为什么这两种索引模式之一给我一个 "index out of bounds" 错误?

Why does one of these two indexing patterns give me an "index out of bounds" error?

使用 ncsim 时,以下代码会引发错误:

Bit-select or part-select index out of declared bounds.

但是,执行完全相同操作的注释掉的代码却没有。是我遗漏了什么还是编译器弄错了?

   module pd__test;

    genvar i, j;

    reg [10-1:0] assign_from_reg;
    reg [256:0] assign_to_reg;

    generate
        for (i=0; i<2; i=i+1) begin
            for (j=0; j<13; j=j+1) begin
                always @* begin
                    if (i+2*j < 25) begin

                        // gives me an index out of bounds error
                        assign_to_reg[10*(i+2*j)+9 : 10*(i+2*j)] =  assign_from_reg;

                        // gives me no such error, however the indices are the same
                        // assign_to_reg[10*(i+2*j)+9 -: 10] =  assign_from_reg;
                    end else begin
                       // do something else
                    end
                end
            end
        end
    endgenerate

endmodule

我运行一个python脚本来打印索引以仔细检查:

for i in range(2):
    for j in range(13):
        if (i+(2*j) < 25):
            print("[",  10*(i+(2*j))+9, ":", 10*(i+(2*j)), "]")

打印:

[ 9 : 0 ]
[ 29 : 20 ]
[ 49 : 40 ]
[ 69 : 60 ]
[ 89 : 80 ]
[ 109 : 100 ]
[ 129 : 120 ]
[ 149 : 140 ]
[ 169 : 160 ]
[ 189 : 180 ]
[ 209 : 200 ]
[ 229 : 220 ]
[ 249 : 240 ]
[ 19 : 10 ]
[ 39 : 30 ]
[ 59 : 50 ]
[ 79 : 70 ]
[ 99 : 90 ]
[ 119 : 110 ]
[ 139 : 130 ]
[ 159 : 150 ]
[ 179 : 170 ]
[ 199 : 190 ]
[ 219 : 210 ]
[ 239 : 230 ]

将条件 if (i+2*j < 25) 移到 always 块之外:

module pd__test;

    genvar i, j;

    reg [10-1:0] assign_from_reg;
    reg [256:0] assign_to_reg;

    generate
        for (i=0; i<2; i=i+1) begin
            for (j=0; j<13; j=j+1) begin
                if (i+2*j < 25) begin
                    always @* begin
                        //assign_to_reg[10*(i+2*j)+9 : 10*(i+2*j)] =  assign_from_reg;
                        assign_to_reg[10*(i+2*j)+9 -: 10] =  assign_from_reg;
                    end
                end
            end
        end
    endgenerate

endmodule

对我来说,这两个作业编译时没有警告或错误。

你要求 verilog 编译器在 always 块中编译这段代码

assign_to_reg[10*(i+2*j)+9 -: 10]

其中 i == 1j == 12 由生成块生成为:

 assign_to_reg[259 : 250]

以上显然超出了声明的范围[256:0]。

将 'if' 移动到生成块中,正如@toolic 所建议的那样,将导致 verilog not 根本不生成最后一个 always 块,因此,它不会已编译,不会生成 warning/error。

因此,生成块的另一个解决方案是将您的assign_to_reg声明为[259:0]

但最好的解决方案是一起摆脱 generate 块,并将 all 循环移动到 single always 中区块:

  always @* begin
      for (int i=0; i<2; i=i+1) begin
        for (int j=0; j<13; j=j+1) begin
            if (i+2*j < 25) begin
                assign_to_reg[10*(i+2*j)+9 -: 10] =  assign_from_reg;            
            end
        end
    end
end

这应该让编译器在 运行 时计算索引,并且也不会导致越界访问。