-1

Recently, I'm coding a testbench for a special circuit. The function of the circuit is to detect whether the input data sequence can be divided by three without remainder. The following code is the interface of the circuit.

module mod3(
input clk,
input rst,
input din,
output dout
);

To be specific, after the rst signal disabled, assuming the din is '1' before the first rising edge of clk, the dout should be '0' after the first rising edge of clk. Before the secend rising edge of clk, assuming din is '1', this time the dout should be '1' after the secend rising edge of clk. The reason is that at the second rising edge of clk, the input data sequence is '11', so the input data can be divided by three without remainder. The following example is the sequence of the input data and the correspond sequence of output data.

input  data: 1101_1001
output data: 0110_1110

For testbench, first I defined a variable logic [0:29] indata; to store the input data sequence to dut, then I defined a variable logic [0:29] outdata; to store the output data sequence from the dut. I use a for loop to send the data into dut and get the data from dut, code slice as shown below.

    for(integer i =0 ;i < 30;i++) begin
        @(negedge clk);
        din = $random;// generate a random value to the dut's input port
        indata[i] = din;// log the input value just before send to dut
        @(posedge clk); //after a rising edge clock, the dut should output whether the input sequence until now can be devided by three without remainder.
        outdata[i] = dout; //log the output result.
    end

After all the input data sent to the dut, then it's time to compare the rusult. I defined a variable logic [0:29] refdata = 0; to generate the true value of the output data from the dut by my own reference model, code slice as shown below.

 for(integer j=2;j<30;j++) begin
        if(indata[0:j]%3 ==0) begin //the indata stored the input data sequence
            refdata[j] = 1;
        end
        else begin
            refdata[j] = 0;
        end
    end
    assert(refdata == outdata) else $display("wrong");

The problem comes from indata[0:j]. The VCS report as shown below.

Error-[IRIPS] Illegal range in part select ./tb.sv, 40

The range of the part select is illegal:

Unknown range in part select.indata[0:j]

I already known this is a syntax error, however, due to the specialness of the question above, I can't figure out another way to code the testbench. Thank you for your patience to read my question.

benjstark
  • 83
  • 4
  • 1
    For the first question, ranges with variable 'widths' are not allowed in verilog, so `[0:j]` constitutes such a range and is illegal. For the second question there is not enough info. If you want a solution for both, you need to post them separately. – Serge Aug 16 '23 at 13:06
  • I find a similar question(link:https://stackoverflow.com/questions/44876888/systemverilog-dynamically-accessing-subarray/44889436#44889436). However, my problem still exist. Since in every loop, I want achieve that the width of 'indata' increase one bit, so I can't use :+ or :- – benjstark Aug 18 '23 at 03:58

2 Answers2

0

I believe that if you will use "generate loop" with genvar this will work. This is because a generate loop iterator is not a "live" variable.

logic [0:29] refdata;

generate
    for(genvar j=2;j<30;j++) begin : gen_ref
        assign refdata[j] = (indata[0:j]%3 == 0); 
    end
endgenerate

assert(refdata == outdata) else $display("wrong");

Basically what it does it duplicates the logic which calculates the %3, for the length of the loop.

Perhaps there is a more pretty solution in UVM.

Note I didn't check it compiles.

EEliaz
  • 155
  • 8
-1

I think below code will work as a stream divided by 3 will have even number of 1's.

for(integer j=2;j<30;j++) begin
        mask_m = (8*(2**(j-2)))-1;  
        data_m = indata & mask_m;
        if($countones(data_m)%2 ==0) begin 
            refdata[j] = 1;
        end
        else begin
            refdata[j] = 0;
        end
end
Parth Pandya
  • 36
  • 1
  • 5