Skip to content

Fixing bugs and introduce inlining if - #425

Merged
soronpo merged 20 commits into
mainfrom
training
Jul 29, 2026
Merged

Fixing bugs and introduce inlining if#425
soronpo merged 20 commits into
mainfrom
training

Conversation

@soronpo

@soronpo soronpo commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

Oron Port and others added 20 commits July 25, 2026 03:42
- `COMB_LOOP`/`FALL_THROUGH` are now block wrappers around loops instead of
  statements inside them; the old statement forms are removed. `COMB_LOOP`
  also provides `HasDFRange`, forcing DFHDL for-loop generation under it in
  concurrent RT scope, where ranges now default to ordinary Scala ranges
  (elaboration-time unrolling), even for DFHDL Int arguments.
- The DFHDL printer prints the annotations as wrappers around the outermost
  annotated loop, under RT domains only (post-toED ED processes print plain
  loops).
- plugin fix: `withFilter[FP]` gained a type parameter in 75c9246, so
  `LoopFSMPhase`'s `FilteredRange` pattern missed the TypeApply-wrapped call
  and guarded for-comprehensions escaped to runtime.
- Tests migrated to the wrapper form; RT design-body loops that must stay
  hardware loops are now explicitly wrapped with `COMB_LOOP`.
- Docs: wrapper syntax, RT-domain-only note, and a `Plus1`/`Plus4`
  elaboration-time loop example.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Design doc for native for/if/case-generate emission in the SystemVerilog
and VHDL backends, driven by a frontend `generate:` block (ED domain only).
Records the locked decisions: reuse existing IR members tagged with
GenerateTag, const iterators, and per-dialect native-or-lowered emission.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nside design-body methods

The plugin generated the design-parameter val as a constructor-local value, so a
reference to it from a `def` (or nested class) in the design body could not be
lambda-lifted and crashed the compiler ("Could not find proxy"). The generated
val is now a private synthetic member of the class, making it reachable from any
scope within the design. Capture naming strips the generated `_plugin$N` suffix
so a captured parameter's phantom keeps the original parameter name.

This legalizes both DFHDL methods capturing `<> CONST` class parameters and
plain Scala defs acting as inline hardware generators (the issue's example),
now documented under the methods user guide.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ulus

Decompose parametric int expressions into sum(coeff * base) + offset in a
new shared IR object (IntExprCalc), so IntParamRef.compare now recognizes
c * v == v + v + ... + v (e.g. `2 * W` == `W + W`), general +/- term
cancellation, and max/min between operands that differ only by a constant
offset, in any operand order. SimplifyFunc's MaxMinWithOffset elaboration
folding reuses the same calculus (without design-param resolution, so its
picks hold for any parameter assignment).

Adds a PrintCodeStringSpec test covering the previously false
"argument width (W + W) is different than the receiver width (twoW)"
elaboration error.

Fixes #423 and fixes #418.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`DesignContext.endDesign` merged the ended design's refTable into the
parent context but not its originRefTable, so resolving a ref TARGET
from the parent worked while resolving its ORIGIN threw "Missing ref".
Hit when printing a connection-error message that names a child port's
parametric width: `csRef` on the width TypeRef needs the origin (the
child's port dcl) for its relative naming. Merge originRefTable at
endDesign just like refTable (and like `inject` already does for both).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Flatten products into an overall constant factor and non-constant factor
list in IntExprCalc, carrying the constant in the term coefficient, and
match product bases by their factor multisets in any operand order, so
`v1 * v2` == `v2 * v1` (also across design hierarchy via resolved design
params) and `(W + W) * v` == `2 * W * v`. Other commutative ops (max,
min, &, |, ^) appearing as opaque bases now compare their args as
multisets as well. Extends the PrintCodeStringSpec parametric width
equivalence test accordingly.

Fixes #419 and fixes #420.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
When a DFHDL Boolean condition is a known constant and the scope has no
conditional-statement capability (or the `hw.flag.scalaBoolean` opt-in
is imported), the DFHDL-to-Scala Boolean conversion now reads the
constant via `toScalaBoolean`, so the enclosing Scala `if` is evaluated
at elaboration time instead of becoming a DFHDL conditional.

- `BooleanHack` is now applied through the inline `BooleanHackInline`
  conversion, dispatching on constness and the new `ScalaBooleanFlag`
  against `Scope.HasCondStats`
- the plugin extracts conditions from the inline expansion shapes
  (shared `HackedGuard`), restoring call-site spans and sources so
  member positions stay correct
- the nested plugin-error pipeline now runs inlining faithfully (one
  shared compilation unit; Zinc-free inline expansion), so inline
  expansion errors preempt later plugin diagnostics exactly like a real
  compile; affected test expectations updated accordingly

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Boolean conversion is now transparent and dispatches on the
argument's type (`inline from match` on `DFConstOf`) instead of a
`P =:= CONST` summon, dropping the type parameter entirely. A
transparent conversion with a type parameter expands during type
inference while the parameter is still an uninstantiated type variable,
so the constness summon would instantiate it to CONST and wrongly
select the Scala-Boolean path for every condition.

Expanding at typer means the purity check sees the actually selected
branch with the true call-site scope resolution: a constant guard that
inlines in a design body forces the rooted `<> CONST` parameter's data
and marks it data-impure (joining the design key), while the same guard
inside a process stays a DFHDL conditional, forces nothing, and keeps
the design parametric. Both behaviors are covered by new
ClassDesignKeySpec tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`IntParam.=~` compared two symbolic width constants by calling `=~` on
the constants themselves, but inside the `IntParam` object the opaque
type dealiases to `Int | DFConstInt32`, so the call re-selected the very
same extension method and the self-tail-call compiled into an infinite
loop. The comparison now dispatches to the underlying IR constants, so
elaboration of `.bits.resize(W)` chains with parametric widths
terminates.

With the comparison terminating, the redundant-cast removal in
`DFVal.Alias.AsIs.apply` silently dropped width-changing resizes (for
concrete widths as well): `(0 - x.sint).bits.resize(W).uint` elaborated
to `.unsigned` of the original width. The removal guard only checked
that the intermediate cast preserves its underlying value's width, never
the target width, so a following resize was elided as if redundant. The
guard now also requires the target bits width to match the intermediate
alias width, keeping the removal to true no-op cast round-trips. Adds a
DFBitsSpec regression test covering both parametric and concrete widths.

Fixes #422.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
from-verilog:
* drop the outdated `.toScalaInt` requirement from the generate-for note
  (an `Int <> CONST` range bound is read directly during elaboration)
* replace the fragment with a self-contained inc/inc_bank example
* add a generate-if section covering elaboration-time constant conditions

conditionals:
* document elaboration-time (generate) if resolution at concurrent scope,
  with the generated Verilog and VHDL output shown in tabs
* clarify the concurrent-scope vs process-scope distinction and the one
  genuine difference from Verilog/VHDL generate-if (both branches type-checked)

Fixes DFiantHDL#85
Fixes DFiantHDL#96

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sweep all prose uses of `--` as a dash separator out of docs/, replacing
them with commas, colons, semicolons, or separate sentences. 23 occurrences
across 5 files. Markdown table rules, YAML/card separators, VHDL comment
syntax, and CLI flags are untouched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Ticket #92 found that the naming page's documented fix for a design class
colliding with a DFHDL built-in (`type AbsModule = abs; AbsModule(...)`)
does not work: a Scala 3 type alias lives in the type namespace only, gives
no universal-apply sugar, and DFHDL design classes have no companion apply.

`new DesignName(...)` always resolves to the class constructor and cannot be
shadowed by a value, a port, or a built-in, so it is now the documented house
style for every design instantiation:

- naming: `new` is the primary recommendation, capitalization is secondary;
  the built-in-collision example now uses `new abs(...)`; the redundant type
  alias section is removed.
- design-hierarchy: direct composition syntax template uses `new`, with a
  note on why, and the parameter bullet no longer claims empty parentheses
  are required (they are optional with `new`).
- connectivity, type-system, interfaces: all design instantiations converted.
  Interface instantiation is unchanged (apply form, parentheses required).
- docExamples/ugdemos/demo5/LRShiftDirect.scala: the source rendered by the
  Direct Connection Composition section.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@soronpo
soronpo merged commit 3b36502 into main Jul 29, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant