Minimal reproduction (verified against v0.22.0+72-ec89141c-SNAPSHOT)
import dfhdl.*
class Probe extends EDDesign:
val clk, rst = Bit <> IN
val cnt = UInt(1) <> VAR
process(clk.rising, rst.rising):
if (rst)
cnt :== 0
else
cnt :== cnt + 1
Compiled with:
scala run src/ --scala 3.8.4 \
--dep "io.github.dfianthdl::dfhdl::0.22.0+72-ec89141c-SNAPSHOT" \
--compiler-plugin "io.github.dfianthdl:::dfhdl-plugin::0.22.0+72-ec89141c-SNAPSHOT" \
-O -deprecation -M Probe -- --nocache commit
Expected behavior
Per the docs (user-guide/type-system/index.md, Wildcard Int Values section), a Scala Int literal such as 1 acts as a wildcard that adapts to the bit-accurate operand's width — 1 fits comfortably inside UInt[1] (max representable value in 1 bit is exactly 1), so cnt + 1 should elaborate as an ordinary (modular) 1-bit increment, exactly as buff_cnt <= buff_cnt + 'd1; does in Verilog for a 1-bit reg.
Actual behavior
DFiant HDL elaboration error!
Position: src/Probe.scala:9:7 - 9:22
Hierarchy: Probe
Operation: `apply`
Message: Signed value width must be larger than 1, but found: 1
Nothing in the source uses a signed type — cnt is UInt(1), and the literal 1 on the RHS is the only other operand. The message names an internal constraint ("Signed value width must be larger than 1") that has no counterpart in the code the user wrote, suggesting the compiler's internal handling of the wildcard-Int-to-bit-accurate-value adaptation path constructs an invalid SInt[1] somewhere along the way (perhaps while computing a signed representation of the literal to check the addition's sign/width rules) rather than a message about cnt's own type.
Where I hit this in practice
This surfaced while translating a Verilog line buffer's shift-register FIFO controller (kernel_shiftreg), which declares a small counter as reg [BUFF_SIZE-1:0] buff_cnt; where BUFF_SIZE = $clog2(BLOCK_WIDTH). For BLOCK_WIDTH == 2, $clog2(2) == 1, giving a 1-bit buff_cnt, incremented with buff_cnt <= buff_cnt + 'd1;. Translating this literally as UInt.until(BLOCK_WIDTH) <> VAR (also 1 bit wide) with buff_cnt :== buff_cnt + 1 hits exactly this error. Any UInt.until/UInt.to-derived width-1 counter incremented by a plain 1 will hit it — this is not a contrived case, it's the natural output of the documented .until/.to counter-width idiom (user-guide/type-system/index.md, "Avoid using clog2 directly for widths") whenever the counter happens to land on exactly 1 bit.
Workaround used
For a 1-bit counter, a modular +1 increment is mathematically identical to a bit toggle, so cnt :== ~cnt sidesteps the bug with unchanged semantics. This is a workaround, not a fix — it only works because the specific width is 1; the underlying UInt[1] + <literal fitting in 1 bit> path itself appears broken.
Version
0.22.0+72-ec89141c-SNAPSHOT (per ~/.dfhdl_version in the training environment on 2026-08-10).
Minimal reproduction (verified against v0.22.0+72-ec89141c-SNAPSHOT)
Compiled with:
Expected behavior
Per the docs (
user-guide/type-system/index.md, WildcardIntValues section), a ScalaIntliteral such as1acts as a wildcard that adapts to the bit-accurate operand's width —1fits comfortably insideUInt[1](max representable value in 1 bit is exactly 1), socnt + 1should elaborate as an ordinary (modular) 1-bit increment, exactly asbuff_cnt <= buff_cnt + 'd1;does in Verilog for a 1-bitreg.Actual behavior
Nothing in the source uses a signed type —
cntisUInt(1), and the literal1on the RHS is the only other operand. The message names an internal constraint ("Signed value width must be larger than 1") that has no counterpart in the code the user wrote, suggesting the compiler's internal handling of the wildcard-Int-to-bit-accurate-value adaptation path constructs an invalidSInt[1]somewhere along the way (perhaps while computing a signed representation of the literal to check the addition's sign/width rules) rather than a message aboutcnt's own type.Where I hit this in practice
This surfaced while translating a Verilog line buffer's shift-register FIFO controller (
kernel_shiftreg), which declares a small counter asreg [BUFF_SIZE-1:0] buff_cnt;whereBUFF_SIZE = $clog2(BLOCK_WIDTH). ForBLOCK_WIDTH == 2,$clog2(2) == 1, giving a 1-bitbuff_cnt, incremented withbuff_cnt <= buff_cnt + 'd1;. Translating this literally asUInt.until(BLOCK_WIDTH) <> VAR(also 1 bit wide) withbuff_cnt :== buff_cnt + 1hits exactly this error. AnyUInt.until/UInt.to-derived width-1 counter incremented by a plain1will hit it — this is not a contrived case, it's the natural output of the documented.until/.tocounter-width idiom (user-guide/type-system/index.md, "Avoid using clog2 directly for widths") whenever the counter happens to land on exactly 1 bit.Workaround used
For a 1-bit counter, a modular
+1increment is mathematically identical to a bit toggle, socnt :== ~cntsidesteps the bug with unchanged semantics. This is a workaround, not a fix — it only works because the specific width is 1; the underlyingUInt[1] + <literal fitting in 1 bit>path itself appears broken.Version
0.22.0+72-ec89141c-SNAPSHOT(per~/.dfhdl_versionin the training environment on 2026-08-10).