Bit wise 'AND' an array of registers in Verilog

4k views Asked by At

I have an array of registers/buses and a single result bus defined as follows.

wire [BW-1:0] bus_array[NUM-1:0];
reg  [BW-1:0] and_result;

where

parameter BW  = 4;
parameter NUM = 8;

I wish to perform a BW-bit AND operation on the elements of the array and assign the result to the register and_result.

I try doing this as follows.

integer l;

generate 
genvar m;
for (m=0; m<BW; m=m+1)
begin : BW_LOOP

    always @ (*)
    begin
      and_result[m] = 1'b1;
      for (l=0; l<NUM; l=l+1)
        and_result[m] = and_result[m] & bus_array[l][m];
    end

end
endgenerate

However when I simulate this in Modelsim 10.1e, I get the following error.

Error: (vsim-3601) Iteration limit reached at time 2 ns

If I do not use the generate loop, and instead have BW instances of the always @ (*) block, the simulation works okay.

I can infer from the error message, that there is a problem with the generate for loop, but I am not able to resolve the problem.

1

There are 1 answers

6
Greg On BEST ANSWER

Most likely a bug with ModelSim. Reproducible on EDAplayground with ModelSim10.1d. Works fine with Riviera2014 (After localizing l inside the generate loop). I'm guessing that and_result[m] is somehow in the @(*) sensitivity list, which it shouldn't be.

l needs to be localized or it will be accessed in parallel with the generated always blocks; creating a potential raise condition.

One workaround is to use SystemVerilog and use always_comb instead of always @(*).

A backwarnd compatable solution is to change and_result[m] = and_result[m] & bus_array[l][m]; to if (bus_array[l][m]==1'b0) and_result[m] = 1'b0; which is equivalent code. This keeps and_result[m] only on as a left hand expression so it cannot be in the sensitivity list.

genvar m;
for (m=0; m<BW; m=m+1)
begin : BW_LOOP
    integer l; // <== 'l' is local to this generate loop

    always @ (*)
    begin
      and_result[m] = 1'b1;
      for (l=0; l<NUM; l=l+1) begin
        if (bus_array[l][m]==1'b0) begin 
          and_result[m] = 1'b0;
        end
    end

end

Working code here