首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >SystemVerilog:$urandom_range给出超出范围的值

SystemVerilog:$urandom_range给出超出范围的值
EN

Stack Overflow用户
提问于 2020-04-13 21:15:24
回答 1查看 728关注 0票数 0

在ModelSim中,我遇到了一个奇怪的问题,我将输入变量设置为一个范围内的随机值,但出于某种原因,我得到了一个超出范围的值。我的所有代码都包含在下面,但基本行是:

write_addrs[i] = $urandom_range(1,NUM_ARCH_REGS);

在ModelSim中,当它不应该被分配给0时(如波形所示;突出显示的信号).

让我困惑的是,除了在write_adresses块中设置初始信号时,除了之外,我从来没有将INITIAL_VECTOR_VALUES设置为零。我只使用显式排除数字0的范围的$urandom_range函数来修改变量。

我写入该变量的主要代码块如下:

代码语言:javascript
运行
复制
    initial begin : INITIAL_VECTOR_VALUES
        advance = 0;
        checkpoint = 0;
        recover = 0;
        write_before_checkpoint = 0;
        for (int i = 0; i < NUM_READ_PORTS; i++)
            read_addrs[i]  = 0;
        for (int i = 0; i < NUM_WRITE_PORTS; i++) begin
            write_addrs[i] = 0;         //<--------------------- HERE!!!
            wr_en[i] = 0;
            write_data[i] = 0;
            commit_en[i] = 0;
            commit_data[i] = 0;
            commit_addrs[i]= 0;
        end
    end

..。在这里:

代码语言:javascript
运行
复制
    task random_operations(int repeat_num);
        //local vars
        int operation_select, num_write, num_commit;
        int current_checkpoints;
        int loop_idx;
        ##5;

        current_checkpoints = 0; //initialize
        $display("Begin Random Operations @ %0t", $time());
        while (loop_idx < repeat_num) begin
            ... other stuff ...
            //operand select (sets the stimulus inputs)

            for (int k = 0; k < num_write; k++) begin
                write_addrs[k] = $urandom_range(1,NUM_ARCH_REGS); //<--------------------- HERE!!!
                $display("%0t: num_write = %0d",$time(), num_write);
                $display("%0t: write_addrs[%0d] = %0d", $time(), k, write_addrs[k]);
                write_data[k] = $urandom_range(1,128);
                wr_en[k] = 1;
            end
            ...
            loop_idx++;
            ##1;

            //reset signals (reset stimulus inputs)
            ...
        end : end_while
    endtask : random_operations

有人知道为什么会发生这种事吗?

参考码

代码语言:javascript
运行
复制
`timescale 1ns/1ns

module testbench;

localparam int NUM_CHECKPOINTS = 8;
localparam int NUM_ARCH_REGS = 32; 
localparam int NUM_READ_PORTS = 4; 
localparam int NUM_WRITE_PORTS = 2;

logic clk;
logic rst;
initial begin : CLOCK_INIT
    clk = 1'b0;
    forever #5 clk = ~clk;
end
default clocking tb_clk @(posedge clk); endclocking


logic [$clog2(32)-1:0] read_addrs [4];
logic [$clog2(32)-1:0] write_addrs [2];
logic wr_en [2];
logic advance;      //moves tail pointer forward
logic checkpoint;       //moves head pointer forward
logic recover;      //moves head pointer backward (to tail)
logic write_before_checkpoint;
logic [$clog2(32)-1:0] commit_addrs [2];
logic [$clog2(128)-1:0] commit_data [2];
logic commit_en [2];
logic [$clog2(128)-1:0] write_data [2];
logic [$clog2(128)-1:0] read_data [4]; 
logic [$clog2(128)-1:0] write_evict_data [2];
logic enable_assertions;

cfc_rat dut(.*);
shadow_rat rat_monitor(.*);

initial begin : INITIAL_VECTOR_VALUES
    advance = 0;
    checkpoint = 0;
    recover = 0;
    write_before_checkpoint = 0;
    for (int i = 0; i < NUM_READ_PORTS; i++)
        read_addrs[i]  = 0;
    for (int i = 0; i < NUM_WRITE_PORTS; i++) begin
        write_addrs[i] = 0;
        wr_en[i] = 0;
        write_data[i] = 0;
        commit_en[i] = 0;
        commit_data[i] = 0;
        commit_addrs[i]= 0;
    end
end

task reset();
    rst = 1;
    ##2;
    rst = 0;
    ##1;
endtask : reset


task random_operations(int repeat_num);
    //local vars
    int operation_select, num_write, num_commit;
    int current_checkpoints;
    int loop_idx;

    ##5;

    current_checkpoints = 0; //initialize

    $display("Begin Random Operations @ %0t", $time());
    while (loop_idx < repeat_num) begin

        operation_select = (loop_idx < 5) ? 1 : ((dut.dfa.chkpt_empty) ? $urandom_range(0,1) : ((dut.dfa.chkpt_full) ? 1 : $urandom_range(0,2)));
        num_write = $urandom_range(0,NUM_WRITE_PORTS);
        num_commit = $urandom_range(0,NUM_WRITE_PORTS);

        case (operation_select)
            0: begin //checkpoint
                if (current_checkpoints+1 < NUM_CHECKPOINTS) begin
                    $display("Checkpoint @ %0t", $time());
                    write_before_checkpoint = $urandom_range(0,1);
                    checkpoint = 1;
                    current_checkpoints++;
                end
                else begin
                    loop_idx--;
                    continue;
                end
            end
            1: $display("Normal RW @ %0t",$time()); //no operation, only read and write
            2: begin //advance
                if (current_checkpoints > 0) begin 
                    advance = 1;
                    $display("Advance @ %0t", $time());
                    current_checkpoints--;
                end
                else begin
                    loop_idx--;
                    continue;
                end
            end
            3: begin //recover
                $display("Recover @ %0t", $time());
                recover = 1;
                current_checkpoints = 0;
            end
            default:;
        endcase // operation_select

        //operand select (sets the stimulus inputs)
        for (int k = 0; k < NUM_READ_PORTS; k++)
            read_addrs[k]  = $urandom_range(0,NUM_ARCH_REGS);

        for (int k = 0; k < num_write; k++) begin
            write_addrs[k] = $urandom_range(1,NUM_ARCH_REGS);
            $display("%0t: num_write = %0d",$time(), num_write);
            $display("%0t: write_addrs[%0d] = %0d", $time(), k, write_addrs[k]);
            write_data[k] = $urandom_range(1,128);
            wr_en[k] = 1;
        end
        for (int k = 0; k < num_commit; k++) begin
            commit_addrs[k] = $urandom_range(1,NUM_ARCH_REGS);
            commit_data[k] = $urandom_range(1,128); 
            commit_en[k] = 1;
        end
        loop_idx++;
        ##1;

        //reset signals (reset stimulus inputs)
        checkpoint = 0;
        recover = 0;
        advance = 0;
        write_before_checkpoint = 0;
        for (int i = 0; i < NUM_WRITE_PORTS; i++) begin
            write_data[i] = 0;
            wr_en[i] = 0;
        end
        for (int i = 0; i < NUM_READ_PORTS; i++)
            read_addrs[i] = 0;
        for (int i = 0; i < NUM_WRITE_PORTS; i++) begin
            commit_en[i] = 0;
            commit_data[i] = 0; 
        end
    end : end_repeat
endtask : random_operations




initial begin : TEST_VECTORS
    enable_assertions = 1; //for testing the monitor

    reset();
    random_operations(5000);

    ##10;
    $display("Finished Successfuly! @ %0t",$time());
    $finish;
end

endmodule
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-04-13 21:58:03

问题是$urandom_range(1, NUM_ARCH_REGS)将值从1返回到32。但是,write_addrs被声明为logic [4:0],这意味着它只能接受0到31之间的值。当$urandom_range返回32 (与6'b10_000相同)时,代码中的赋值将其截断为5位,删除MSB,5'b0_0000存储在write_addrs中。

要解决这个问题,只允许随机值达到31。

更改:

代码语言:javascript
运行
复制
        write_addrs[k] = $urandom_range(1, NUM_ARCH_REGS);

至:

代码语言:javascript
运行
复制
        write_addrs[k] = $urandom_range(1, NUM_ARCH_REGS-1);

下面是一个演示这个问题的完整示例:

代码语言:javascript
运行
复制
module tb;

localparam int NUM_ARCH_REGS = 32; 
logic [$clog2(32)-1:0] write_addrs [2];

initial begin
    repeat (100) begin
        for (int k=0; k<2; k++) begin
            write_addrs[k] = $urandom_range(1, NUM_ARCH_REGS);
            $write("write_addrs[%0d]=%02d ", k, write_addrs[k]);
        end
        $display;
    end
end
endmodule

您看到的问题并不是ModelSim特有的;我可以在另外两个模拟器上看到它。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61196905

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档