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

问题描述 投票:0回答:1

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

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

在ModelSim中,不应将其分配为0(如波形所示;突出显示的信号)...enter image description here

令我困惑的是,当我在INITIAL_VECTOR_VALUES块中设置初始信号时,我从未将write_adresses设置为零except。我仅通过使用$ urandom_range函数(带有明确排除数字0的范围)来修改变量。

我在其中写入此变量的主要代码块在这里:

    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

...和这里:

    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

有人知道为什么会这样吗?

如果代码难以阅读,请提前道歉。另外,如果这不是张贴此邮件的正确位置,有人会重定向我到正确的堆栈交换吗?谢谢〜

参考代码

`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
system-verilog hdl
1个回答
0
投票

问题是$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的随机值。

更改:

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

至:

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

您看到的问题并非特定于ModelSim;我可以在其他2个模拟器上看到它。

© www.soinside.com 2019 - 2024. All rights reserved.