Summary
The verilog.v2001 backend emits a whole-array assignment when resetting a Vec, which Verilog-2001
has no syntax for. The value is a packed replication ({4{8'h00}}) assigned to an unpacked
array (reg [7:0] mem [0:3]), so the widths do not correspond either.
The SystemVerilog backends are fine: '{default: 8'h00} is legal and synthesizable (Sutherland,
Synthesizing SystemVerilog
§2.5.3, "Array lists are synthesizable"). Only the v95/v2001 lowering is affected, where
literalGroupOpen swaps '{ for { but the default:-shaped repeat-on-DFVector branch has no
Verilog-2001 equivalent to fall back to.
Reproduction
lib/src/test/scala/Playground.scala, then sbt "lib/Test/runMain zzV2001":
import dfhdl.*
class VecReset extends RTDesign:
val din = Bits(8) <> IN
val dout = Bits(8) <> OUT
val mem = Bits(8) X 4 <> VAR.REG init all(all(0))
mem(0).din := din
for (i <- 1 until 4) mem(i).din := mem(i - 1)
dout <> mem(3)
@main def zzV2001(): Unit =
given options.CompilerOptions.Backend = _.verilog.v2001
VecReset().compile
Emitted VecReset.v:
reg [7:0] mem [0:3];
assign dout = mem[3];
always @(posedge clk)
begin
if (rst == 1'b1) mem <= {4{8'h00}}; // <-- 32-bit packed value to a 4x8 unpacked array
else begin
mem[0] <= din;
...
The same design through _.verilog (sv2009) is correct:
logic [7:0] mem [0:3];
if (rst == 1'b1) mem <= '{default: 8'h00};
Three independent tools reject the v2001 output
iverilog -g2001 VecReset.v:15: error: Assignment to an entire array or to an array slice
requires SystemVerilog.
verilator %Error-UNSUPPORTED: Non-1 replication to form 'logic[7:0]$[0:3]' data type
--language
1364-2001 %Error: Assignment pattern missed initializing elements: 1
%Error: Assignment pattern missed initializing elements: 2
%Error: Assignment pattern missed initializing elements: 3
yosys VecReset.v:15: ERROR: Invalid array access.
read_verilog (preceded by: Warning: Replacing memory \mem with list of registers)
Verilator's message is the one worth reading twice: it parses {4{8'h00}} as an assignment pattern
that initializes element 0 only. A tool lenient enough to accept this would reset the first
element and leave the rest un-reset, which is a silent wrong-hardware failure rather than a syntax
error.
Masked at a single-element outer dimension
{1{...}} is a replication of 1, which Verilator accepts, so a Vec whose outer dimension is 1
lints clean and only fails under yosys. Any Vec with two or more elements fails everywhere. This
is why the bug can sit unnoticed in a parameterised design pinned to a single bank/lane.
Suggested fix
An element-wise reset is the construct every Verilog-2001 tool accepts, and it is what a hand-written
model uses for this:
integer i;
...
if (rst == 1'b1) begin for (i = 0; i < 4; i = i + 1) mem[i] <= 8'h00; end
I checked that this parses under yosys's own read_verilog (unlike either current form) and builds
identical hardware to the sv2009 output: same cell count (92 vs 92 on a 31-element test case), same
flop count, same mux/xor counts. A nested loop covers the multi-dimensional Vec case, and the same
form works with SV for (int i = ...) if it is ever preferable to share one lowering.
Found while porting VeeR-EH1's register file, where the module is pinned to one bank and so only
yosys caught it.
Summary
The
verilog.v2001backend emits a whole-array assignment when resetting aVec, which Verilog-2001has no syntax for. The value is a packed replication (
{4{8'h00}}) assigned to an unpackedarray (
reg [7:0] mem [0:3]), so the widths do not correspond either.The SystemVerilog backends are fine:
'{default: 8'h00}is legal and synthesizable (Sutherland,Synthesizing SystemVerilog
§2.5.3, "Array lists are synthesizable"). Only the v95/v2001 lowering is affected, where
literalGroupOpenswaps'{for{but thedefault:-shapedrepeat-on-DFVectorbranch has noVerilog-2001 equivalent to fall back to.
Reproduction
lib/src/test/scala/Playground.scala, thensbt "lib/Test/runMain zzV2001":Emitted
VecReset.v:The same design through
_.verilog(sv2009) is correct:Three independent tools reject the v2001 output
Verilator's message is the one worth reading twice: it parses
{4{8'h00}}as an assignment patternthat initializes element 0 only. A tool lenient enough to accept this would reset the first
element and leave the rest un-reset, which is a silent wrong-hardware failure rather than a syntax
error.
Masked at a single-element outer dimension
{1{...}}is a replication of 1, which Verilator accepts, so aVecwhose outer dimension is 1lints clean and only fails under yosys. Any
Vecwith two or more elements fails everywhere. Thisis why the bug can sit unnoticed in a parameterised design pinned to a single bank/lane.
Suggested fix
An element-wise reset is the construct every Verilog-2001 tool accepts, and it is what a hand-written
model uses for this:
I checked that this parses under yosys's own
read_verilog(unlike either current form) and buildsidentical hardware to the sv2009 output: same cell count (92 vs 92 on a 31-element test case), same
flop count, same mux/xor counts. A nested loop covers the multi-dimensional
Veccase, and the sameform works with SV
for (int i = ...)if it is ever preferable to share one lowering.Found while porting VeeR-EH1's register file, where the module is pinned to one bank and so only
yosys caught it.