Methods, initial blocks, FSM cycle fusion, DFacsimile - #414
Merged
Conversation
Introduce `dfhdl.options.ToolOptions.Location` (dftools|local), threaded through the linter/simulator/builder/programmer options following the existing OnError pattern, and exposed as the `--tools-location` CLI flag. When set to `dftools`, `Tool.exec` runs the bare tool inside the pinned DFTools Apptainer image (resolved/cached by the new `DFToolsImage` via Scalapptainer) instead of resolving it on the host PATH; `local` keeps the existing PATH-based behavior. Default is `local` until a DFTools image release is published. Adds the scalapptainer dependency to the lib subproject. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rework DFToolsImage from one combined image to a per-cluster image set (synth-verilog, synth-vhdl, pnr, sim-llvm, sim-verilator, sim-iverilog, wavegen, program). `imageFor(exec, vhdl)` maps each in-image executable to its image (yosys resolves by backend dialect; ghdl-as-simulator -> sim-llvm). Images are resolved/cached independently, with a per-image dev/test override `-Ddfhdl.dftools.sif.<image>=<path>`. Tool.exec now selects the image per executable before spawning the apptainer argv. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When running a tool inside a DFTools image, the command runs on Linux, so backslash path separators in the relative source/include arguments must be converted to forward slashes (otherwise e.g. iverilog sees a literal "hdl\rotWord.v" and fails to find the file). Validated end-to-end: the AES CipherSim simulation now runs to $finish through the sim-iverilog image (verilator/iverilog on Windows via WSL2 apptainer exec). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…inary name - Tool.exec: a produced artifact (path with a separator, e.g. verilator's obj_dir/V<top>) runs by its relative ./path inside the mounted cwd, with the Linux name (forward slashes, .exe stripped), in its producing tool's image. - Verilator: use the `verilator` wrapper inside the image (not the Windows verilator_bin), and report the verilated binary as obj_dir/V<top> (no .exe) under DFTools so producedFiles/run resolve the actual Linux artifact. Validated: AES CipherSim simulates to $finish through both the sim-iverilog and sim-verilator images (verilate -> compile C++ with g++/make in-image -> run produced binary). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DFHDL now runs the external EDA tools via the pinned DFTools images by default; pass --tools-location local to use tools on PATH instead. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tool version/availability detection scanned only the host PATH (installedVersion), so in dftools mode tools that look up their version before running — Verilator's lint config (getInstalledVersion) and NVC's produced-file naming — failed with "<tool> could not be found" even though the tool lives in the image. This made the DFTools CI gate's `test` run fail on issues.IssuesSpec i142/i147 (Verilog linting). Add DFToolsImage.probe and a memoized dftoolsInstalledVersion that runs the tool's versionCmd inside its image and parses it with the same extractVersion. getInstalledVersion now uses it in dftools mode; NVC reads the version via getInstalledVersion instead of the host-only installedVersion. Verified locally: IssuesSpec Verilog-linting tests pass in dftools mode against the locally built sifs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DFToolsImage.version was hardcoded. Define the targeted DFTools release as `dftoolsVersion` in build.sbt and surface it through the generated version.properties resource (alongside the DFHDL version), read by DFToolsImage the same way hdl.dfhdlVersion reads its version. Bumping the DFTools release is now a one-line build.sbt change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Use Apptainer.pull (apptainer's native https:// SIF transport, with cache-reuse) to fetch the release asset, replacing the manual curl download. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the dependency versions out of the `dependencies` object and the inlined scalapptainer version out of `lib` into a single VERSIONS block at the top, alongside compilerVersion and dftoolsVersion. The dependencies object and lib now reference these names. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Source-compatible; lib compiles and the DFTools image pull/exec/version-probe path works end-to-end (i142 verilator lint passes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tool objects are singletons accessed concurrently; the previous memoization used an unsynchronized `var` (a data race). Replace it with a parameterless `lazy val` (the `using ToolOptions` was unused), which initializes once and publishes safely across threads — matching the existing `installedVersion` lazy val. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add `isToolInWindows = osIsWindows && !usesDFTools` (the tool runs as a Windows
binary only on a Windows host AND outside the Linux DFTools image) plus a matching
`toolSeparatorChar`. Key the tool-facing launcher name, the produced-binary name,
`vvp`/`osExe` siblings, and path conversion off these instead of the raw host
`osIsWindows`. In dftools mode the tool then naturally resolves to its plain Linux
`binExec` with `/`-separated paths, so the bespoke container handling is removed:
- `containerExec` (and Verilator's override) — runExec is already the in-image name
- the produced-artifact `.exe`-drop / backslash rewrite in `Tool.exec`
- the blanket `cmd.replace('\','/')` — source paths convert via `!isToolInWindows`
- `verilatedBinary`'s `usesDFTools` special case
The local PATH lookup uses a dedicated `hostExec`; local behaviour is unchanged
(there `isToolInWindows == osIsWindows`). Verified Windows->container: verilator
lint, iverilog v2001 sim, and verilator sim all pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Under `sbtn` an external tool that floods stdout (e.g. a runaway verilator simulation) could not be stopped with Ctrl+C: the run executes in the detached sbt server JVM and the cancel is forwarded by the client, but the output flood saturates the client<->server channel so the client never gets to deliver it. Cap forwarded console output continuously (~500 lines/s) so the channel stays idle most of each window, leaving headroom for the cancel to arrive promptly. A burst/adaptive cap does not work — a flood re-saturates the channel instantly — so the rate must be capped continuously. Output below the cap is untouched and nothing is dropped. Also drop the post-kill backlog silently (`aborted`) so a cancelled run ends promptly instead of trickling the buffered backlog out at the throttled rate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When an external tool floods stdout while running inside the DFTools image on Windows + WSL2, Ctrl+C could not stop it. Two launcher-specific causes: - scala-cli (and similar) hide the Ctrl+C from the app JVM entirely — no SIGINT, no thread-interrupt, no shutdown. The console Ctrl+C does reach the in-VM process as SIGINT, but killing the in-VM tool alone doesn't stop the flood: the host wsl.exe relay keeps draining its buffered output. Only killing wsl.exe does. Run the tool inside the VM through a signal-trapping bash wrapper that, on INT/TERM/HUP, kills our host wsl.exe via WSL->Windows interop (`wmic ... parentprocessid=<jvmPid> call terminate`) — dropping the relay buffer and unblocking the JVM's waitFor — then force-kills the in-VM tool subtree and drops a `.dfhdl-cancel` marker. The wrapper is installed via `tee` (stdin) and invoked by path so it survives wsl.exe arg re-quoting; the JVM passes its own pid. JVM side: a daemon marker watcher (fallback kill + clean-interrupt detection) and a single post-waitFor marker check, so the run unwinds as a clean ToolInterruptedException rather than reading the killed launcher's exit code as an error. Normal runs pay no latency. This complements the output throttle (committed separately) that fixes the sbtn channel-saturation case. Confirmed working for local & dftools tools under both sbtn and scala-cli. Design notes in docs/dev/ctrl-c-cancellation.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A no-throttle experiment showed the output throttle does two jobs under an sbtn flood, not one: besides keeping the client<->server channel idle enough to deliver the Ctrl+C, it back-pressures the tool so the flood backlog stays upstream (in wsl.exe, where killing the launcher drops it) instead of being slurped into JVM / sbt-server memory at full speed (observed multi-GB), where killing the launcher no longer stops the flood. Comment-only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The generated-file cache keyed artifacts by the design-content hash only (getDataHash), which is identical across toolchains since it depends solely on the source. Local and DFTools builds therefore shared one cache slot and clobbered each other, e.g. iverilog failing with "VVP input file 14.0 can not be run with run time version 13.0" after a switch. Key gen-files by keyHash too, which folds in otherDeps (tool, version, location, backend), so each toolchain gets its own artifact slot. Some tools also keep cache-unmanaged build intermediates in the sandbox that the analyzer/builder updates in place; these survive a switch and break the next run. Add a shared Tool.staleToolArtifacts + purgeStaleToolArtifactsOnSwitch fingerprint-stamp mechanism (purges only on a toolchain switch, so same-toolchain runs stay incremental): - Verilator: purge obj_dir (stale *.d/*.o embed the other toolchain's verilated.cpp include path -> make fails with "No rule to make target" / "multiple target patterns"). - GHDL: purge work-obj*.cf (records per-unit source paths; the / vs \ difference makes GHDL report duplicate definitions, -Wlibrary). NVC needs nothing: its producedFiles already enumerates every WORK.* unit. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Switch the documentation engine from MkDocs to ProperDocs (a maintained fork of MkDocs 1.6.1), keeping the Material for MkDocs 9.7.6 theme so the rendered site is byte-for-byte identical to before. - rename mkdocs.yml -> properdocs.yml (ProperDocs' native config name; the mkdocs.yml fallback is deprecated and warns) - requirements.txt: mkdocs -> properdocs - CI dfdocs.yml: `mkdocs build` -> `properdocs build` - workflows: update path triggers mkdocs.yml -> properdocs.yml - CLAUDE.md: document the new config file and build command requirements.txt also carries pre-existing docs dependency bumps (pymdown-extensions, mkdocs-drawio, schemdraw) that were already in the working tree. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The docs/dev/ notes are internal and were never part of the site nav. Relocating them to a top-level devdocs/ keeps them out of the built site and the docs CI path triggers. - docs/dev/ctrl-c-cancellation.md -> devdocs/ (fix relative link depth: ../../lib -> ../lib) - add devdocs/interfaces-views-plan.md Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
With the default tools-location=dftools, running a proprietary tool that has no DFTools image (Questa, Vivado, Quartus, Diamond, Gowin) failed with e.g. "no DFTools image for tool 'vlog'". Make such tools transparently run from the local PATH instead of erroring. Split DFToolsImage.imageFor into an Option-returning imageForOpt (the single source of truth for the tool->image mapping) plus the throwing imageFor, and gate Tool.usesDFTools on a new supportsDFTools (= imageForOpt(binExec).isDefined). An unsupported tool now always resolves to local regardless of the option, which also keeps the version-probe and exec paths from ever hitting imageFor for it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…p_` prefix) The plugin previously synthesized a separate `top_<Design>` object extending `DFApp` to host the generated `main`. Replace this with a `main` injected directly into the design's companion object, so the companion (e.g. `Foo`) is itself the runnable entry point — improving the run/runMain UX. - `DFApp` becomes a class without `main` (renamed to `run`); `setInitials`/ `setDsn`/`getDsnArg` are made public so the injected `main` can drive an instance. `appCompileTime` is derived from a `topClass` passed to `setInitials` (falling back to `this.getClass` for `ManualDFApp`). - `TopAnnotPhase` injects `main` into the companion module class, instantiating `DFApp`, priming it, and rerouting argv to `run`. The design `__dfc` is still wired by `MetaContextPlacerPhase` from the `@top` annotation. - `PreTyperPhase` synthesizes an empty (non-Synthetic) companion before the typer when a `@top` class lacks one, so the namer establishes real companion linkage (a post-typer module would not link, causing a clashing mirror class). Non-Synthetic lets `mergeCompanionDefs` fold in the desugared default-getter companion for designs with default args. - Update downstream references: `testApps` (`util.EmptyDesign`, `dfhdl.AES.CipherSim`), the reflective CLI test helper, docs, and the new-stage skill. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Capture the per-invocation latency the DFTools (Apptainer-in-WSL) path adds vs local execution on Windows+WSL2: ~160ms fixed overhead per tool process launch (~100ms wsl.exe spawn + ~60ms apptainer container start), constant across tools/images, and per-launch rather than per-sim-step. Includes the apptainer-instance vs exec-<sif> comparison (~110ms/exec win) and a Git Bash/MSYS2 timing gotcha to avoid when re-measuring. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…mePos mutation) Class metadata (name/position/doc/annotations) was previously applied by a plugin-injected `setClsNamePos` call that mutated the elaborated design block (`getSet.replace`). Replace this with a declarative inheritance chain that the container reads to construct the design block correctly at creation — no mutation. - `HasClsMetaArgs` now exposes `__clsMetaArgs: List[ClsMetaArgs]`. The compiler plugin injects, per DFHDL class, an override `newClsMetaArgs :: super.__clsMetaArgs`, so the leaf's `__clsMetaArgs` yields the full chain (most-derived first; only concrete classes appear). For the override to take effect via virtual dispatch, `MetaContextPlacerPhase` is now an `IdentityDenotTransformer` with `changesMembers = true` and enters the override symbol with `enteredAfter(this)`, copying the inherited symbol's flags/info for an exact signature match. - `Design`/`Interface` build their block directly in `initOwner` from the chain: the leaf (head) names the design/interface; for a blackbox IP the base-most concrete class in the chain names the IP `typeName`. The former `setClsNamePos` implementations and the global-tag side effects move here. - `ResourceContext` derives `resourceType` and constraint annotations from the chain instead of via `setClsNamePos`. - `EDBlackBox.source` becomes a `def` (was a constructor-param field) so `mkInstMode` is safe to evaluate during construction, allowing the block's final `instMode` to be set at creation. - `CoreSpec.PluginSpec` reads `__clsMetaArgs` instead of `setClsNamePos`. Verified: compiler_stages 437/437 (incl. qsys blackbox), core 74/74, and the IDTop elaborate printout is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…. advantages not worth the instability.
… streams Fixes the intermittent Windows AccessDenied on version.properties during copyResources, from two compounding causes: - The core resourceGenerator rewrote version.properties unconditionally every build, bumping its mtime and forcing copyResources to re-copy it each run; it now writes only when the content actually changes. - Both readers (hdl.dfhdlVersion and DFToolsImage.version) left getResourceAsStream open, holding a Windows file lock that blocks the rename; both now close the stream. DFToolsImage now reads its own lib-owned dftools.properties rather than sharing core's version.properties, so the dfhdl version and the dftools version are decoupled. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Values of width <= 32 now compute as int over int-typed state: 32-bit adds wrap for free with no mask AND, and 32-bit rotate patterns compile to a single ror instruction. Measurements showed the int form only pays with int-typed storage (computing in int over the long signal array loses more to the per-access truncate/widen boundary than the arithmetic saves), so registers and spilled comb values move into width-typed kernel fields and the shared signal array is made coherent only at kernel entry (registers load, pokes land) and exit (registers and spills store; peeks, scheduler wait bounds, and text-output arguments read after the call returns) - legal under the bulk-run contract, with the sync cost amortized over each call's cycles and the state-checkpoint invariant preserved at call boundaries. runWatch is specialized on the generation-time watch node (new watchNode parameter on Codegen.compile, runtime argument cross-checked). SHA farm n=32: 2.16 -> 2.69 Mcycles/s (above single-threaded Verilator's 2.48); n=8: 10.7 -> 13.6; small designs unchanged-to-better. States stay bit-identical to the interpreter tier everywhere. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Move chains of eight or more int-typed moves (shift registers, delay pipelines) now keep their registers in a shared chain array and commit as overlapping 8-lane Vector API moves instead of scalar field-to-field copies, which profiling showed to be ~38% of large-design cycle time. All lanes load before any lane stores, preserving the same read-before-overwrite guarantee the consumer-first commit order gives the scalar form. Chain registers are read by constant index everywhere else; all remaining state stays in width-typed fields, which measure faster for compute than array-backed state. The vector path engages only when the host JVM resolves jdk.incubator.vector (JPMS forbids resolving a boot-loader incubator module into a running JVM, so it must be a launch flag); otherwise the commit silently stays scalar. The repo .jvmopts adds the flag so sbt server sims vectorize out of the box. New sysprops: -Ddfhdl.sim.codegen.dumpSource=true prints the generated kernel Java, -Ddfhdl.sim.codegen.noVector=true forces the scalar commit. SHAFarm throughput (forked JDK 25, bit-identical aggregates): n=32 2.82 -> 3.79 Mcycles/s, n=64 1.33 -> 1.68 - ahead of single-threaded Verilator at both sizes (2.52 / 1.50). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A reg alias reading a dcl that the proper-alias mechanism replaces with a REG dcl created its din chain against the removed dcl, leaving a dangling reference. The reg-group din chain now resolves its rel val through the proper-alias replacement map to reference the new REG dcl directly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The DFiantHDL/benchmarks repository joins the build as the `benchmarks` submodule: a never-published sbt module depending on lib (Apache 2.0, per-derived-work licensing documented in that repo), with every top-level work folder auto-discovered as a source directory. The benchmark sources previously kept uncommitted under compiler_stages test scope (dfhdl.sim.bench) live there now, peeking state through the public typed simulation API. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A single-arg FuncOp.|/&/^ is a bit reduction (Bits/UInt -> Bit), but buildFunc routed it through the binary-op cases, where rdAt(_, resW = 1) truncated the operand to bit 0 instead of reducing it. Found by the SERV benchmark port: `cnt_en := cnt_lsb.|` read only bit 0 of the ring counter, parking the CPU after its first instruction fetch. Reductions now lower explicitly: or-reduce compares against zero, and-reduce against all-ones, and xor-reduce folds the 64-bit-normalized lane xor down to bit 0. Regression coverage in WideSimSpec exercises all three on single-lane (4-bit) and multi-lane (100-bit) operands on both kernel tiers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New .claude/commands/verilog-to-dfhdl.md skill capturing the Verilog-to-DFHDL porting workflow, the clock/reset magnet wiring across a hierarchy, initFile memory handling and the memory-vs-reset gap, CONST params, and emitter gotchas; it defers all language basics to the user guide (from-verilog, design-domains, type-system). Bumps the benchmarks submodule to the serv baseline-port-names and clock/reset-magnet rework. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A related domain shares the target's clock by default and also its reset. `@timing.related(target, includeReset = false)` keeps the shared clock but drops the reset: the domain's registers/memories are excluded from reset initialization and rely on their init values instead. - IR/frontend: add `includeReset: Boolean = true` to Timing.Related / related - reset resolution: new `resolvedRstAnnot` chain-walk helper severs the reset on an includeReset=false link; wired into hasResolvedRstCfg and ToED's two reset reads (clock keeps resolving through the full chain) - tests: ToEDSpec (init-instead-of-reset lowering) + PrintCodeStringSpec (codeString round-trip) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Related Domains section: explain that includeReset = false keeps the shared clock but drops the reset, so the domain's registers/memories rely on their init values instead of a reset-initialization block. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Support the nested RTDomain that keeps servant_ram's initFile memory out of the reset. DFacsimile's minimum builder now walks a @timing.related RT DomainBlock's members inline (new isRelatedRTDomain predicate: RT domain with a Timing.Related annotation and no own Timing.Clock), sharing the parent's clock; nested clock-owning or ED domains stay unsupported. It also binds an explicitly-declared Clk/Rst magnet input to its deasserted-low constant (active-high) instead of leaving an unpatched MOV, so a design that reads its reset combinationally (serv_state's `!i_rst.actual`) simulates. Verified: the mini Servant top is bit-exact against the reference on both the Interpreter and Codegen tiers; all dfhdl.sim.* tests pass. Also updates the verilog-to-dfhdl skill (memory-vs-reset pattern and the String CONST / DFacsimile note) and bumps the benchmarks submodule. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A DFVector register accessed only cell-wise (every referrer an ApplyIdx into it, cell width <= 64) now lowers to a long[]-backed memory instead of a wide register: an async MEMRD node (O(1) read) plus ordered synchronous write ports, if (we) mem[addr] = (mem[addr] & ~mask) | ((data << pos) & mask), the guard being the enclosing path condition so byte enables and branch guards fold into we. Anything not cleanly cell-wise (a whole-vector read/connection, a wider cell) falls back to the wide model, so no design regresses. This replaces the packed-bits lowering where each dynamic index expanded into a barrel-shift network over the whole vector -- O(memory-size) nodes evaluated and committed every cycle -- which made 32 KiB RAM un-runnable and even the 256 B mini about 10x slower than Verilator. Now the mini Codegen tier runs at ~6 Mcycles/s (about Verilator's speed, up from 0.59) and the 32 KiB SERV tops run at ~5.7, all bit-exact against Verilator. Memory-less designs are untouched: the Codegen write-commit emission is gated on memWrites, and the Interpreter guards its commit with a hasMem flag, so the generated code and per-cycle path are identical to before (A/B on sha_farm/protocol_engine stayed within run-to-run noise on both tiers). Adds ByteMemDut (a byte-enable RAM, the Servant firmware-RAM shape) to CompositeSimSpec, verified on both tiers alongside the existing RegFileDut. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rays) Replace the memory node's isReg gate with an access-pattern classifier vecRepr(dcl): Ram | CombArray | Wide. A DFVector accessed only cell-wise (every referrer an ApplyIdx into it, cell <= 64) lowers by storage class: a register to the RAM node as before, a combinational VAR wire to a sweep-local scratch array instead of a barrel-shift network. Anything not cleanly cell-wise stays the wide model (const vectors already lower to a ROM node at their use site). The comb array is a kernel-owned long[] cleared each sweep, with three version-threaded ops so the combinational scheduler orders writes before same-sweep reads: ANEW (clear + version-0), ALOAD (arr[addr]), ASTORE (arr[addr] = data). A guarded/partial cell write folds to store(i, mux(we, insert(load(i), part, pos), load(i))); DFacsimile threads the current version node through the body walk (no env/mux merge, like the RAM). Fixes a latent unrollCombFor bug the comb array exposed: the index of v(i) is a cached value read, stale across unroll iterations, so every write hit address 0. unrollCombFor now drops per-iteration cache entries (procOverlay in a process, else nodeOf) so iterator-dependent reads rebuild against the new binding. Adds CombVecDut (a combinational cell-wise wire vector) to CompositeSimSpec, verified on both tiers. Memory/comb-less designs are unchanged: the Codegen emission is gated so their generated code is identical (sha_farm and protocol_engine A/B outputs identical, throughput within noise). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Profiling the SERV bit-serial core (control-dominated, ~1400 one-bit ops per cycle) showed the Codegen path is memory/field-access bound, so these three passes cut field traffic and node count with no observable change. - CSE (value numbering) in the netlist builder: pure combinational ops are hash-consed on (op, width, inputs), collapsing the repeated bit extracts a bit-serial decoder emits at many sites (~18% fewer comb ops). Side-effecting / order-sensitive nodes (MOV, ROM, memory, comb arrays) never enter the cache. - Copy propagation: pure-alias MOV nodes (hierarchy port connections, wire renames) are forwarded so consumers, register-nexts, memory-write operands, and peek observers read the source directly. Post-commit observers (text-output snaps, scheduler wait bounds, the watch aggregate) are pinned and preserved. Also rescues shift-register move-chain detection when a reg-to-reg move hops through an alias. - Dead-code elimination in Codegen: run/settle/stepDirty emit only the backward cone from registers, memory writes, the observed set, and the watch node, so the forwarded alias MOVs drop out of every method. SERV steady-state Codegen throughput (bit-exact vs Verilator, no regression on sha_farm / protocol_engine): hello-mini 5.98 -> 7.38 Mcps (+23%) hello-32k 5.89 -> 7.32 Mcps (+24%) phil-32k 5.46 -> 7.06 Mcps (+29%) 727 compiler_stages + 144 sim tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add `derives CanEqual` to the PCont enum in DFacsimile so the strictEquality match on the parameterless PCont.Wrap case compiles (compiler_stages was failing to compile). - Pin svgdom to 0.1.23 in the DFDocs workflow. svgdom 0.1.24+ tightened ensureXMLSerializableName, which throws on the hdelk-generated SVG for user-guide/connectivity; 0.1.23 is the last version the docs built cleanly on. Unrelated to this PR's code (also broke unrelated branches). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… sbt.version to 1.12.14, and sbt-ci-release to 1.12.0
The foreign-IP DPI flags were built as a single `-LDFLAGS "<multi word>"` string, but the tool exec layer tokenizes the command with a plain split-on-space that does not honor quotes, so verilator received the inner tokens (e.g. `-l:libinteractive_dpi.so`) as stray top-level options and aborted with "Invalid option". Emit each linker token under its own `-LDFLAGS` (verilator concatenates repeated occurrences in order), so no space-containing value has to survive the split. Same behavior on host Linux, dftools, macOS, and Windows. This first surfaced with the interactive foreign IP, the first to link a DPI library into the verilated binary. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DFToolsImage.isAvailable caught every Throwable and returned false, so a real resolve failure (no container runtime, blocked unprivileged user namespaces, a corrupt or absent asset) was indistinguishable from an image that is simply not configured. The only downstream symptom was the misleading "could not be found in its DFTools image". Print the caught exception before returning false so the actual cause shows up in the log. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Build runs the test suite in the committed `dftools` location, executing each EDA tool inside a rootless Apptainer image. Ubuntu 24.04 blocks the unprivileged user namespace Apptainer's rootless engine needs (kernel.apparmor_restrict_unprivileged_userns=1), which the previous commit surfaced as scalapptainer.UserNamespaceException. Clear the AppArmor sysctl so the images can run. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DFToolsImage passed an explicit `dest` to Apptainer.pull, but scalapptainer
0.5.3 only creates the images cache dir on the derived-name path, not for an
explicit dest, so apptainer's pull failed ("could not open temporary file for
copy: ... no such file or directory") on a fresh runner. Pull by `name` (the
asset minus .sif), which routes through the dir-creating path and lands the SIF
at the same <imagesDir>/<asset>. Root cause also fixed upstream in scalapptainer.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Drop the pull-by-name workaround in DFToolsImage: scalapptainer 0.5.4 creates the parent dir for an explicit `dest` in pull/build, so pass `dest` directly again. Bump scalapptainerVersion 0.5.3 -> 0.5.4. - Bump interactiveSimVersion 0.4.1 -> 0.4.2 to pick up the claim_heartbeat WIDTHTRUNC fix, clearing the verilator -Wall warnings on the IP wrappers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pull in dfhdl-ips 98d519b: the vga/interactive viewer os.proc(...).spawn() calls now pass destroyOnExit=false, so a missing viewer executable no longer throws uncaught on os-lib's shutdown-hook/monitor threads (nor leaves a JVM shutdown hook that re-throws the launch failure at exit). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
scalapptainer stores pulled SIFs under ~/.scalapptainer/images by content-addressed name, and both DFHDL and scalapptainer short-circuit the pull when the SIF is already present. Cache that folder so the per-run `[dftools] downloading image ...` pulls are skipped. Keyed on dftoolsVersion (which pins the exact image set via the bundled dftools.lock.json); the prefix restore-key lets a version bump reuse every unchanged, content-addressed image. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.