Skip to content

verilog.v2001: a Vec reset emits a whole-array assignment, which Verilog-2001 has no syntax for #492

Description

@soronpo

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions