Verilog backend struggles with multidimensional array indices into array dimensions from Verific frontend that are non-PoT and/or don't start from zero
bug
### 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 条评论