SystemVerilog: $ urandom_range дает значения вне диапазона - PullRequest
0 голосов
/ 14 апреля 2020

Я получаю странную проблему в ModelSim, где я устанавливаю входную переменную в случайное значение в диапазоне, но по какой-то причине я получаю значение вне диапазона. Весь мой код приведен ниже, но основная строка:

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

В ModelSim ему присваивается значение 0, когда это не нужно (как показано в форме сигнала; выделенный сигнал) ...

enter image description here

Меня смущает то, что я никогда не устанавливаю адрес записи равным нулю , за исключением когда я устанавливаю начальные сигналы в блоке INITIAL_VECTOR_VALUES. Я изменяю переменную только с помощью функции $urandom_range с диапазоном, явно исключающим число ноль.

Основные блоки кода, в которые я записываю эту переменную, находятся здесь:

    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

1 Ответ

2 голосов
/ 14 апреля 2020

Проблема в том, что $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);

Вот полный пример, демонстрирующий проблему:

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

Проблема, которую вы видите, не указана c для ModelSim; Я могу видеть это на 2 других симуляторах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...