ITADN

Verilog backend struggles with multidimensional array indices into array dimensions from Verific frontend that are non-PoT and/or don't start from zero

#5878Opencpearce 创建于 2026-05-12
bug
C
cpearcecommented
### Version 0.64. Note this is Google's internal build of Yosys which includes Verific support. ### On which OS did this happen? Linux ### Reproduction Steps When the minimized testcase is parsed with Yosys's Verific parser, the output SV has flattened mutli-dimensional arrays from the input which are indexed out of bounds. The arrays have one dimension with a non-zero starting index. I suspect that this bug is happening in Yosys' Verific frontend, as the netlist that Verific produces when run on the testcase below looks correct to me. Minimized testcase `/tmp/repro.sv`: ``` module repro( input logic clk, input logic [2:0] data_in [1:0][0:0], // Unique enables force discrete loop unrolling input logic enable [1:0][0:0][3:1], output logic out ); // Multi-dimensional unpacked array with a 1-indexed dimension logic [2:0] my_array [1:0][0:0][3:1]; always_ff @(posedge clk) begin foreach (my_array[sch, disp, src]) begin if (enable[sch][disp][src]) begin my_array[sch][disp][src] <= data_in[sch][disp]; end end end // Prevent DCE by reducing the entire array logic out_tmp; always_comb begin out_tmp = 1'b0; foreach (my_array[sch, disp, src]) begin out_tmp ^= ^my_array[sch][disp][src]; end end assign out = out_tmp; endmodule ``` Repro with Yosys: ``` yosys -p "verific -sv /tmp/repro.sv; verific -import repro; write_verilog /tmp/repro.out.sv" ``` I work at Google. This testcase was reduced by Gemini from a production use case inside Google. ### Expected Behavior I believe the `always_ff @(posedge clk) begin` block should resolve equivalent to: ``` // sch=0, src=1 -> index 0 if (\enable[0][0] [1]) my_array[3'h0] <= _24_; // sch=0, src=2 -> index 1 if (\enable[0][0] [2]) my_array[3'h1] <= _24_; // sch=0, src=3 -> index 2 if (\enable[0][0] [3]) my_array[3'h2] <= _24_; // sch=1, src=1 -> index 3 if (\enable[1][0] [1]) my_array[3'h3] <= _25_; // sch=1, src=2 -> index 4 if (\enable[1][0] [2]) my_array[3'h4] <= _25_; // sch=1, src=3 -> index 5 if (\enable[1][0] [3]) my_array[3'h5] <= _25_; ``` ### Actual Behavior The contents of `/tmp/repro.out.sv` resolves to: ``` /* Generated by 0.64 */ (* \library = "work" *) (* hdlname = "repro" *) (* src = "/tmp/repro.sv:1.8-1.13" *) module repro(clk, \data_in[1][0] , \data_in[0][0] , \enable[1][0] , \enable[0][0] , out); (* src = "/tmp/repro.sv:2.17-2.20" *) input clk; wire clk; (* src = "/tmp/repro.sv:3.23-3.30" *) input [2:0] \data_in[1][0] ; wire [2:0] \data_in[1][0] ; (* src = "/tmp/repro.sv:3.23-3.30" *) input [2:0] \data_in[0][0] ; wire [2:0] \data_in[0][0] ; (* src = "/tmp/repro.sv:5.17-5.23" *) input [3:1] \enable[1][0] ; wire [3:1] \enable[1][0] ; (* src = "/tmp/repro.sv:5.17-5.23" *) input [3:1] \enable[0][0] ; wire [3:1] \enable[0][0] ; (* src = "/tmp/repro.sv:6.18-6.21" *) output out; wire out; wire _00_; wire [2:0] _01_; wire _02_; wire _03_; wire [2:0] _04_; wire _05_; wire _06_; wire _07_; wire [2:0] _08_; wire _09_; wire _10_; wire _11_; wire [2:0] _12_; wire _13_; wire _14_; wire _15_; wire [2:0] _16_; wire _17_; wire _18_; wire _19_; wire [2:0] _20_; wire _21_; wire _22_; wire _23_; wire [2:0] _24_; wire [2:0] _25_; (* src = "/tmp/repro.sv:23.32-23.36" *) wire [31:0] disp; (* src = "/tmp/repro.sv:12.32-12.36" *) wire [31:0] disp_2; (* src = "/tmp/repro.sv:20.11-20.18" *) wire out_tmp; (* src = "/tmp/repro.sv:23.27-23.30" *) wire [31:0] sch; (* src = "/tmp/repro.sv:12.27-12.30" *) wire [31:0] sch_2; (* src = "/tmp/repro.sv:23.38-23.41" *) wire [31:0] src; (* src = "/tmp/repro.sv:12.38-12.41" *) wire [31:0] src_2; (* ORIG_DEPTH = 32'd2 *) (* ORIG_WIDTH = 32'd9 *) (* src = "/tmp/repro.sv:9.17-9.25" *) reg [2:0] my_array [5:0]; always @(posedge clk) begin if (\enable[0][0] [3]) my_array[4'h3] <= _24_; if (\enable[1][0] [1]) my_array[4'h9] <= _25_; if (\enable[0][0] [1]) my_array[4'h1] <= _24_; if (\enable[0][0] [2]) my_array[4'h2] <= _24_; if (\enable[1][0] [2]) my_array[4'ha] <= _25_; if (\enable[1][0] [3]) my_array[4'hb] <= _25_; end assign _20_ = my_array[4'h1]; assign _16_ = my_array[4'h2]; assign _12_ = my_array[4'h3]; assign _08_ = my_array[4'h9]; assign _04_ = my_array[4'ha]; assign _01_ = my_array[4'hb]; assign _24_ = + (* src = "/tmp/repro.sv:14.17-14.64" *) \data_in[0][0] ; assign _25_ = + (* src = "/tmp/repro.sv:14.17-14.64" *) \data_in[1][0] ; assign _03_ = _02_; assign _06_ = _03_ ^ (* src = "/tmp/repro.sv:24.13-24.50" *) _05_; assign _07_ = _06_; assign _10_ = _07_ ^ (* src = "/tmp/repro.sv:24.13-24.50" *) _09_; assign _11_ = _10_; assign _14_ = _11_ ^ (* src = "/tmp/repro.sv:24.13-24.50" *) _13_; assign _15_ = _14_; assign _18_ = _15_ ^ (* src = "/tmp/repro.sv:24.13-24.50" *) _17_; assign _19_ = _18_; assign _22_ = _19_ ^ (* src = "/tmp/repro.sv:24.13-24.50" *) _21_; assign out_tmp = _22_; assign out = out_tmp; assign _02_ = ^ (* src = "/tmp/repro.sv:24.24-24.49" *) _01_; assign _05_ = ^ (* src = "/tmp/repro.sv:24.24-24.49" *) _04_; assign _09_ = ^ (* src = "/tmp/repro.sv:24.24-24.49" *) _08_; assign _13_ = ^ (* src = "/tmp/repro.sv:24.24-24.49" *) _12_; assign _17_ = ^ (* src = "/tmp/repro.sv:24.24-24.49" *) _16_; assign _21_ = ^ (* src = "/tmp/repro.sv:24.24-24.49" *) _20_; assign _00_ = 1'h0; assign _23_ = 1'h1; endmodule ``` The problem is the `always_ff @(posedge clk) begin` block: ``` reg [2:0] my_array [5:0]; always @(posedge clk) begin if (\enable[0][0] [3]) my_array[4'h3] <= _24_; if (\enable[1][0] [1]) my_array[4'h9] <= _25_; if (\enable[0][0] [1]) my_array[4'h1] <= _24_; if (\enable[0][0] [2]) my_array[4'h2] <= _24_; if (\enable[1][0] [2]) my_array[4'ha] <= _25_; if (\enable[1][0] [3]) my_array[4'hb] <= _25_; end ``` Here `my_array` is length 6, but we're indexing at 9, 10, 11 (`my_array[4'h9]`, `my_array[4'ha]`, `my_array[4'hb]` respectively, which is out of bounds.
14 条评论