Summary
.reg(step, init = ...) crashes the compiler when the value's width comes from a design parameter. The same design with a literal width is fine, and so is the equivalent declared-register form at the same parameterised width.
Reproduction
import dfhdl.*
class RegZ(val WQ: Int <> CONST = 9) extends RTDesign:
val d_in = Bits(WQ) <> IN
val d_out = Bits(WQ) <> OUT
d_out <> d_in.reg(1, init = all(0))
sbt "runMain RegZ compile"
java.util.NoSuchElementException: Missing member of reference "TR_f18cc5c3_0_10":
Func(DFBits("TR_f18cc5c3_0_10"),repeat,
List("TW_f18cc5c3_0_21", "TW_f18cc5c3_0_22"),"OW_f18cc5c3_0_23",
Meta(None,RegZ.scala:6:29 - 6:35,None,List()),Map())
The source position is the all(0), and the dangling Func is the repeat it lowers to.
What does and does not trigger it
| form |
width |
result |
d_out <> d_in.reg(2, init = all(0)) |
literal Bits(8) |
OK |
d_out <> d_in.reg(1, init = all(0)) |
parameter Bits(WQ) |
crash |
d_out <> d_in.reg(2, init = all(0)) |
parameter Bits(WQ) |
crash |
d_out <> d_in.reg(1, init = ?) |
parameter Bits(WQ) |
crash |
val d_out = Bits(WQ) <> OUT.REG init all(0) + d_out.din := d_in |
parameter Bits(WQ) |
OK |
So it is the parameter-dependent width combined with .reg's init argument, not the step count, and not all(0) specifically (init = ? fails identically). The last row is the workaround: declaring the register with its init and assigning .din produces the intended hardware.
The reference id is stable across differently-named reproductions and survives clearDFHDL, so it is not a stale elaboration cache.
Context
VeeR-EH1's rvsyncss is a width-parameterised two-flop synchronizer, which is exactly din.reg(2, init = all(0)). Falling back to the declared-register chain works but spells out two named registers where the design has none.
Environment
DFHDL v0.22.0+118-fac67942-SNAPSHOT, Scala 3.8.4.
Summary
.reg(step, init = ...)crashes the compiler when the value's width comes from a design parameter. The same design with a literal width is fine, and so is the equivalent declared-register form at the same parameterised width.Reproduction
sbt "runMain RegZ compile"The source position is the
all(0), and the danglingFuncis therepeatit lowers to.What does and does not trigger it
d_out <> d_in.reg(2, init = all(0))Bits(8)d_out <> d_in.reg(1, init = all(0))Bits(WQ)d_out <> d_in.reg(2, init = all(0))Bits(WQ)d_out <> d_in.reg(1, init = ?)Bits(WQ)val d_out = Bits(WQ) <> OUT.REG init all(0)+d_out.din := d_inBits(WQ)So it is the parameter-dependent width combined with
.reg'sinitargument, not the step count, and notall(0)specifically (init = ?fails identically). The last row is the workaround: declaring the register with itsinitand assigning.dinproduces the intended hardware.The reference id is stable across differently-named reproductions and survives
clearDFHDL, so it is not a stale elaboration cache.Context
VeeR-EH1's
rvsyncssis a width-parameterised two-flop synchronizer, which is exactlydin.reg(2, init = all(0)). Falling back to the declared-register chain works but spells out two named registers where the design has none.Environment
DFHDL v0.22.0+118-fac67942-SNAPSHOT, Scala 3.8.4.