mirror of
https://github.com/verilator/verilator.git
synced 2025-01-05 22:27:35 +00:00
80b08b71aa
For NBAs that might execute a dynamic number of times in a single evaluation (specifically: those that assign to array elements inside loops), we introduce a new run-time VlNBACommitQueue data-structure (currently a vector), which stores all pending updates and the necessary info to reconstruct the LHS reference of the AstAssignDly at run-time. All variables needing a commit queue has their corresponding unique commit queue. All NBAs to a variable that requires a commit queue go through the commit queue. This is necessary to preserve update order in sequential code, e.g.: a[7] <= 10 for (int i = 1 ; i < 10; ++i) a[i] <= i; a[2] <= 10 needs to end with array elements 1..9 being 1, 10, 3, 4, 5, 6, 7, 8, 9. This enables supporting common forms of NBAs to arrays on the left hand side of <= in non-suspendable/non-fork code. (Suspendable/fork implementation is unclear to me so I left it unchanged, see #5084). Any NBA that does not need a commit queue (i.e.: those that were supported before), use the same scheme as before, and this patch should have no effect on the generated code for those NBAs.
301 lines
12 KiB
Systemverilog
301 lines
12 KiB
Systemverilog
// DESCRIPTION: Verilator: Verilog Test module
|
|
//
|
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
|
// any use, without warranty, 2024 by Wilson Snyder.
|
|
// SPDX-License-Identifier: CC0-1.0
|
|
|
|
`define stop $stop
|
|
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0)
|
|
`define checkr(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
|
`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
|
|
|
|
|
|
|
module t(clk);
|
|
input clk;
|
|
|
|
logic [31:0] cyc = 0;
|
|
always @(posedge clk) begin
|
|
cyc <= cyc + 1;
|
|
if (cyc == 99) begin
|
|
$write("*-* All Finished *-*\n");
|
|
$finish;
|
|
end
|
|
end
|
|
|
|
reg [63:0] crc = 64'h5aef0c8d_d70a4497;
|
|
always @ (posedge clk) crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]};
|
|
|
|
`define at_posedge_clk_on_cycle(n) always @(posedge clk) if (cyc == n)
|
|
|
|
// Case 1: narrow packed variable, whole element updates only - 1D
|
|
typedef logic [31:0] elem1_t;
|
|
typedef elem1_t array1_t[128];
|
|
array1_t array1;
|
|
`at_posedge_clk_on_cycle(0) begin
|
|
for (int i = 0 ; i < 128; ++i) array1[i] = 0;
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array1[i], 0);
|
|
end
|
|
`at_posedge_clk_on_cycle(1) begin
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array1[i], 0);
|
|
for (int i = 0 ; i < 128; ++i) array1[i] <= i;
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array1[i], 0);
|
|
end
|
|
`at_posedge_clk_on_cycle(2) begin
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array1[i], i);
|
|
for (int i = 0 ; i < 128; ++i) array1[i] <= ~i;
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array1[i], i);
|
|
end
|
|
`at_posedge_clk_on_cycle(3) begin
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array1[i], ~i);
|
|
for (int i = 0 ; i < 128; ++i) array1[i] <= -1;
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array1[i], ~i);
|
|
end
|
|
`at_posedge_clk_on_cycle(4) begin
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array1[i], -1);
|
|
end
|
|
|
|
// Case 2: wide packed variable, whole element updates only - 1D
|
|
typedef logic [127:0] elem2_t;
|
|
typedef elem2_t array2_t[128];
|
|
array2_t array2;
|
|
`at_posedge_clk_on_cycle(0) begin
|
|
for (int i = 0 ; i < 128; ++i) array2[i] = 0;
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array2[i], 0);
|
|
end
|
|
`at_posedge_clk_on_cycle(1) begin
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array2[i], 0);
|
|
for (int i = 0 ; i < 128; ++i) array2[i] <= {4{i}};
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array2[i], 0);
|
|
end
|
|
`at_posedge_clk_on_cycle(2) begin
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array2[i], {4{i}});
|
|
for (int i = 0 ; i < 128; ++i) array2[i] <= {4{~i}};
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array2[i], {4{i}});
|
|
end
|
|
`at_posedge_clk_on_cycle(3) begin
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array2[i], {4{~i}});
|
|
for (int i = 0 ; i < 128; ++i) array2[i] <= '1;
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array2[i], {4{~i}});
|
|
end
|
|
`at_posedge_clk_on_cycle(4) begin
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array2[i], ~128'b0);
|
|
end
|
|
|
|
|
|
// Case 3: wide packed variable, whole element updates only - 2D
|
|
typedef logic [127:0] elem3_t;
|
|
typedef elem3_t array3sub_t[512];
|
|
typedef array3sub_t array3_t[128];
|
|
array3_t array3;
|
|
`at_posedge_clk_on_cycle(0) begin
|
|
for (int i = 0 ; i < 128; ++i) for (int j = 0 ; j < 512; ++j) array3[i][j] = 0;
|
|
for (int i = 0 ; i < 128; ++i) for (int j = 0 ; j < 512; ++j) `checkh(array3[i][j], 0);
|
|
end
|
|
`at_posedge_clk_on_cycle(1) begin
|
|
for (int i = 0 ; i < 128; ++i) for (int j = 0 ; j < 512; ++j) `checkh(array3[i][j], 0);
|
|
for (int i = 0 ; i < 128; ++i) for (int j = 0 ; j < 512; ++j) array3[i][j] <= {4{i}};
|
|
for (int i = 0 ; i < 128; ++i) for (int j = 0 ; j < 512; ++j) `checkh(array3[i][j], 0);
|
|
end
|
|
`at_posedge_clk_on_cycle(2) begin
|
|
for (int i = 0 ; i < 128; ++i) for (int j = 0 ; j < 512; ++j) `checkh(array3[i][j], {4{i}});
|
|
for (int i = 0 ; i < 128; ++i) for (int j = 0 ; j < 512; ++j) array3[i][j] <= {4{~i}};
|
|
for (int i = 0 ; i < 128; ++i) for (int j = 0 ; j < 512; ++j) `checkh(array3[i][j], {4{i}});
|
|
end
|
|
`at_posedge_clk_on_cycle(3) begin
|
|
for (int i = 0 ; i < 128; ++i) for (int j = 0 ; j < 512; ++j) `checkh(array3[i][j], {4{~i}});
|
|
for (int i = 0 ; i < 128; ++i) for (int j = 0 ; j < 512; ++j) array3[i][j] <= '1;
|
|
for (int i = 0 ; i < 128; ++i) for (int j = 0 ; j < 512; ++j) `checkh(array3[i][j], {4{~i}});
|
|
end
|
|
`at_posedge_clk_on_cycle(4) begin
|
|
for (int i = 0 ; i < 128; ++i) for (int j = 0 ; j < 512; ++j) `checkh(array3[i][j], ~128'b0);
|
|
end
|
|
|
|
// Case 4: real
|
|
typedef real elem4_t;
|
|
typedef elem4_t array4_t[128];
|
|
array4_t array4;
|
|
`at_posedge_clk_on_cycle(0) begin
|
|
for (int i = 0 ; i < 128; ++i) array4[i] = 1e-5;
|
|
for (int i = 0 ; i < 128; ++i) `checkr(array4[i], 1e-5);
|
|
end
|
|
`at_posedge_clk_on_cycle(1) begin
|
|
for (int i = 0 ; i < 128; ++i) `checkr(array4[i], 1e-5);
|
|
for (int i = 0 ; i < 128; ++i) array4[i] <= 3.14*real'(i);
|
|
for (int i = 0 ; i < 128; ++i) `checkr(array4[i], 1e-5);
|
|
end
|
|
`at_posedge_clk_on_cycle(2) begin
|
|
for (int i = 0 ; i < 128; ++i) `checkr(array4[i], 3.14*real'(i));
|
|
for (int i = 0 ; i < 128; ++i) array4[i] <= 2.78*real'(i);
|
|
for (int i = 0 ; i < 128; ++i) `checkr(array4[i], 3.14*real'(i));
|
|
end
|
|
`at_posedge_clk_on_cycle(3) begin
|
|
for (int i = 0 ; i < 128; ++i) `checkr(array4[i], 2.78*real'(i));
|
|
for (int i = 0 ; i < 128; ++i) array4[i] <= 1e50;
|
|
for (int i = 0 ; i < 128; ++i) `checkr(array4[i], 2.78*real'(i));
|
|
end
|
|
`at_posedge_clk_on_cycle(4) begin
|
|
for (int i = 0 ; i < 128; ++i) `checkr(array4[i], 1e50);
|
|
end
|
|
|
|
// Case 5: narrow packed variable, partial element updates - 1D
|
|
typedef logic [31:0] elem5_t;
|
|
typedef elem5_t array5_t[128];
|
|
array5_t array5;
|
|
`at_posedge_clk_on_cycle(0) begin
|
|
for (int i = 0 ; i < 128; ++i) array5[i] = -1;
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array5[i], -1);
|
|
end
|
|
`at_posedge_clk_on_cycle(1) begin
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array5[i], -1);
|
|
for (int i = 0 ; i < 128; ++i) array5[i][0] <= 1'b0;
|
|
for (int i = 0 ; i < 128; ++i) array5[i][1] <= 1'b0;
|
|
for (int i = 0 ; i < 128; ++i) array5[i][2] <= 1'b0;
|
|
for (int i = 0 ; i < 128; ++i) array5[i][1] <= 1'b1;
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array5[i], -1);
|
|
end
|
|
`at_posedge_clk_on_cycle(2) begin
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array5[i], 32'hffff_fffa);
|
|
for (int i = 0 ; i < 128; ++i) array5[i][18:16] <= i[3:1];
|
|
for (int i = 0 ; i < 128; ++i) array5[i][19:17] <= ~i[2:0];
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array5[i], 32'hffff_fffa);
|
|
end
|
|
`at_posedge_clk_on_cycle(3) begin
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array5[i], {12'hfff, ~i[2:0], i[1], 16'hfffa});
|
|
for (int i = 0 ; i < 128; ++i) array5[i] <= -1;
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array5[i], {12'hfff, ~i[2:0], i[1], 16'hfffa});
|
|
end
|
|
`at_posedge_clk_on_cycle(4) begin
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array5[i], -1);
|
|
end
|
|
|
|
// Case 6: wide packed variable, partial element updates - 1D
|
|
typedef logic [99:0] elem6_t;
|
|
typedef elem6_t array6_t[128];
|
|
array6_t array6;
|
|
`at_posedge_clk_on_cycle(0) begin
|
|
for (int i = 0 ; i < 128; ++i) array6[i] = -1;
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array6[i], -1);
|
|
end
|
|
`at_posedge_clk_on_cycle(1) begin
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array6[i], -1);
|
|
for (int i = 0 ; i < 128; ++i) array6[i][80] <= 1'b0;
|
|
for (int i = 0 ; i < 128; ++i) array6[i][81] <= 1'b0;
|
|
for (int i = 0 ; i < 128; ++i) array6[i][82] <= 1'b0;
|
|
for (int i = 0 ; i < 128; ++i) array6[i][81] <= 1'b1;
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array6[i], -1);
|
|
end
|
|
`at_posedge_clk_on_cycle(2) begin
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array6[i], 100'hf_fffa_ffff_ffff_ffff_ffff_ffff);
|
|
for (int i = 0 ; i < 128; ++i) array6[i][86:84] <= ~i[3:1];
|
|
for (int i = 0 ; i < 128; ++i) array6[i][87:85] <= i[2:0];
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array6[i], 100'hf_fffa_ffff_ffff_ffff_ffff_ffff);
|
|
end
|
|
`at_posedge_clk_on_cycle(3) begin
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array6[i], {12'hfff, i[2:0], ~i[1], 84'ha_ffff_ffff_ffff_ffff_ffff});
|
|
for (int i = 0 ; i < 128; ++i) array6[i] <= -1;
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array6[i], {12'hfff, i[2:0], ~i[1], 84'ha_ffff_ffff_ffff_ffff_ffff});
|
|
end
|
|
`at_posedge_clk_on_cycle(4) begin
|
|
for (int i = 0 ; i < 128; ++i) `checkh(array6[i], -1);
|
|
end
|
|
|
|
// Case 7: variable partial updates
|
|
typedef logic [99:0] elem7_t;
|
|
typedef elem7_t array7sub_t[256];
|
|
typedef array7sub_t array7_t[128];
|
|
array7_t array7_nba;
|
|
array7_t array7_ref;
|
|
always @(posedge clk) begin
|
|
if (cyc == 0) begin
|
|
for (int i = 0 ; i < 128; ++i) for (int j = 0 ; j < 256; ++j) array7_nba[i][j] = 100'b0;
|
|
for (int i = 0 ; i < 128; ++i) for (int j = 0 ; j < 256; ++j) array7_ref[i][j] = ~100'b0;
|
|
end else begin
|
|
for (int i = 0 ; i < 128; ++i) for (int j = 0 ; j < 256; ++j) `checkh(array7_nba[i][j], ~array7_ref[i][j]);
|
|
for (int i = 0 ; i < 128; ++i) begin
|
|
for (int j = 0 ; j < 256; ++j) begin
|
|
array7_nba[i[6:0] ^ crc[30+:7]][j[7:0] ^ crc[10+:8]][7'((crc % 10) * 5) +: 5] <= ~crc[4+:5];
|
|
array7_ref[i[6:0] ^ crc[30+:7]][j[7:0] ^ crc[10+:8]][7'((crc % 10) * 5) +: 5] = crc[4+:5];
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
// Case 8: Mixed dynamic/non-dynamic
|
|
typedef longint elem8_t;
|
|
typedef elem8_t array8_t[4];
|
|
array8_t array8;
|
|
`at_posedge_clk_on_cycle(0) begin
|
|
array8[0] <= 0;
|
|
array8[1] <= 0;
|
|
array8[2] <= 0;
|
|
array8[3] <= 0;
|
|
end
|
|
`at_posedge_clk_on_cycle(1) begin
|
|
`checkh(array8[0], 0);
|
|
`checkh(array8[1], 0);
|
|
`checkh(array8[2], 0);
|
|
`checkh(array8[3], 0);
|
|
array8[1] <= 42;
|
|
array8[3] <= 63;
|
|
for (int i = 1 ; i < 3 ; ++i) array8[i] <= 2*i + 7;
|
|
array8[1] <= 74;
|
|
end
|
|
`at_posedge_clk_on_cycle(3) begin
|
|
`checkh(array8[0], 0);
|
|
`checkh(array8[1], 74);
|
|
`checkh(array8[2], 11);
|
|
`checkh(array8[3], 63);
|
|
end
|
|
|
|
// Case 9: string
|
|
typedef string elem9_t;
|
|
typedef elem9_t array9_t[10];
|
|
array9_t array9;
|
|
`at_posedge_clk_on_cycle(0) begin
|
|
for (int i = 0 ; i < 10; ++i) array9[i] = "squid";
|
|
for (int i = 0 ; i < 10; ++i) `checks(array9[i], "squid");
|
|
end
|
|
`at_posedge_clk_on_cycle(1) begin
|
|
for (int i = 0 ; i < 10; ++i) `checks(array9[i], "squid");
|
|
for (int i = 0 ; i < 10; ++i) array9[i] <= "octopus";
|
|
for (int i = 0 ; i < 10; ++i) `checks(array9[i], "squid");
|
|
end
|
|
`at_posedge_clk_on_cycle(2) begin
|
|
for (int i = 0 ; i < 10; ++i) `checks(array9[i], "octopus");
|
|
for (int i = 1 ; i < 9; ++i) begin
|
|
string tmp;
|
|
$sformat(tmp, "%0d-legged-cephalopod", i);
|
|
array9[i] <= tmp;
|
|
end
|
|
for (int i = 0 ; i < 10; ++i) `checks(array9[i], "octopus");
|
|
end
|
|
`at_posedge_clk_on_cycle(3) begin
|
|
`checks(array9[0], "octopus");
|
|
`checks(array9[1], "1-legged-cephalopod");
|
|
`checks(array9[2], "2-legged-cephalopod");
|
|
`checks(array9[3], "3-legged-cephalopod");
|
|
`checks(array9[4], "4-legged-cephalopod");
|
|
`checks(array9[5], "5-legged-cephalopod");
|
|
`checks(array9[6], "6-legged-cephalopod");
|
|
`checks(array9[7], "7-legged-cephalopod");
|
|
`checks(array9[8], "8-legged-cephalopod");
|
|
`checks(array9[9], "octopus");
|
|
for (int i = 0 ; i < 10; ++i) array9[i] <= "cuttlefish";
|
|
`checks(array9[0], "octopus");
|
|
`checks(array9[1], "1-legged-cephalopod");
|
|
`checks(array9[2], "2-legged-cephalopod");
|
|
`checks(array9[3], "3-legged-cephalopod");
|
|
`checks(array9[4], "4-legged-cephalopod");
|
|
`checks(array9[5], "5-legged-cephalopod");
|
|
`checks(array9[6], "6-legged-cephalopod");
|
|
`checks(array9[7], "7-legged-cephalopod");
|
|
`checks(array9[8], "8-legged-cephalopod");
|
|
`checks(array9[9], "octopus");
|
|
end
|
|
`at_posedge_clk_on_cycle(4) begin
|
|
for (int i = 0 ; i < 10; ++i) `checks(array9[i], "cuttlefish");
|
|
end
|
|
|
|
endmodule
|