Skip to content

Fk sc/uhdi pool#2

Open
fkhaidari wants to merge 12 commits into
fk-sc/debug-infofrom
fk-sc/uhdi-pool
Open

Fk sc/uhdi pool#2
fkhaidari wants to merge 12 commits into
fk-sc/debug-infofrom
fk-sc/uhdi-pool

Conversation

@fkhaidari

Copy link
Copy Markdown
Owner

No description provided.

fkhaidari added 10 commits May 22, 2026 02:45
…d honor enum width

Accept circt_debug_subfield leaves whose 'parent' is rooted at the var via
'.' or '[' separators, so nested bundles emitted by the frontend (e.g. leaves
of 'io.in' under a debug_var of 'io.in') still attach to their owning var.

Read an optional 'width' param on circt_debug_enumdef and size variant
IntegerAttrs accordingly; fall back to i64 when absent so pre-existing
hand-written tests keep working.
Introduce dbg.expression (compound expression handle), dbg.rootblock /
dbg.subblock (statement tree that survives ExpandWhens), and
dbg.connect_stmt / dbg.decl_stmt for recording source-level connects and
declarations. Add ExpressionType and the uhdi.stable_id / uhdi.repr_entry
attribute names consumed by EmitUHDI.

verifyUhdiStatementRefs walks each dbg.rootblock and reports varRef /
valueRef / guardRef strings that don't resolve to a sibling dbg.variable;
exposed as a free function rather than a verifier hook because the
statement tree intentionally permits literal-string fallbacks (mem-port
subfields, XMR refs, synthesized capture-when names).
Register test-verify-uhdi-refs so lit suites can exercise the
statement-tree ref checker without depending on a verifier hook.
…dies

Extend the inliner's region-containing op allowlist with debug::RootBlockOp
and debug::SubBlockOp so the captured when/connect tree gets cloned under
the caller's scope alongside the inlined ops.
UhdiCaptureWhen records each module's when/connect tree into a dbg.rootblock
region before ExpandWhens flattens it. firrtl.when becomes dbg.subblock,
firrtl.connect becomes dbg.connect_stmt with bp.enableRef carrying the
AND-reduced guard stack. StringAttr refs decouple the captured structure
from the FIRRTL IR.

UhdiInit stamps uhdi.stable_id onto every dbg.* op using a deterministic
fingerprint over kind + owning module + name/type/opcode (walk position
excluded so unrelated inserts upstream don't perturb sibling IDs).
Idempotent on re-runs.
VerilogName.h centralises post-PrettifyVerilog name lookup (port aliases,
hw.verilogName, sv.wire / read_inout chains) so emitters and snapshot
passes share one resolver.

UhdiVerilogSnapshot attaches uhdi.repr_entry dicts onto every dbg.* op
stamped by UhdiInit, recording the op's final Verilog-level signal name
for EmitUHDI to surface as representations.verilog.name. Must run after
PrettifyVerilogNames and before EmitUHDI.
Move findLocations / findBestLocation out of EmitHGLDD.cpp into a
LocationUtils translation unit so a follow-up EmitUHDI can reuse the
loc-tree walk. Pure refactor -- EmitHGLDD now calls
circt::debuginfo::bestLocation with the same arguments.
Add the pool-based UHDI JSON emitter and register it as the `emit-uhdi`
MLIR translation. EmitUHDIOptions mirrors the HGLDD options struct.
EmitUHDI consumes uhdi.stable_id / uhdi.repr_entry stamped by
firrtl-uhdi-init and hw-uhdi-verilog-snapshot, unwraps dbg.subfield
wrappers before name resolution, and walks port-alias names through
the post-ExportVerilog sv.read_inout / sv.wire / port chain.
Add `--emit-uhdi`, `--uhdi-output-file`, `--uhdi-source-prefix`,
`--uhdi-output-prefix`, `--uhdi-only-existing-file-locs` CLI flags on
firtool. When enabled, the firtool pipeline runs UhdiInit +
UhdiCaptureWhen before ExpandWhens, a second UhdiInit after Inliner,
UhdiVerilogSnapshot after PrettifyVerilog, and writes UHDI JSON via
EmitUHDIPass during prepare-for-export-verilog.
dbg.subfield previously carried its enum linkage only as an SSA reference to a
dbg.enumdef in the same module. Enums shared across modules keep their
dbg.enumdef in a single module, so a subfield leaf in any other module had no
in-module enumdef to bind to and lost its enum type; EmitUHDI could then not
resolve the enum type-pool entry.

Add optional enumTypeName / enumFqn string attributes on dbg.subfield that
mirror the linkage by FQN. FIRRTLIntrinsics stamps them from the source
intrinsic's enumFqn / enumTypeName params and no longer warns when no
same-module dbg.enumdef exists, since that is expected for shared enums.
EmitUHDI falls back to the FQN string to locate the enum pool entry across
module boundaries.
fkhaidari added 2 commits May 22, 2026 22:44
…terializeExpression

Chisel compiles `when(expr)` into a `firrtl.node` wrapping the actual
primop. `materializeExpression` called `firrtlOpcode` on the node op,
got an empty string, and fell back to the `<complex>` sentinel even
when the underlying op (e.g. `firrtl.gt`, `firrtl.eq`) was already in
the whitelist.

Fix: peel through `firrtl.node` chains before dispatching to
`firrtlOpcode`. This eliminates all `<complex>` occurrences in GCD
(verified: `grep -c '<complex>' gcd.uhdi.json` = 0).

Also allow `firrtl::ConstantOp` through `findModuleBodyProxy`
regardless of which block it was defined in. Constants are pure and
control-flow-free; after lowering they become `hw::ConstantOp`, which
`EmitUHDI::ExpressionPool::operandFor` already handles via
`renderConstant`. This covers the case where `when(x === 0.U)`
generates a constant inside a nested region.
…ions

renderConstant() gains an includeWidth parameter (default false).
When true, adds "width" key alongside "constant"/"bitVector" -- needed
for expression-context constants where no typeRef provides the width.

Enable for hw::ConstantOp in ExpressionPool::operandFor() and for the
ReplicateOp multiplier operand.  The Python converter already handles
the "width" field (convert.py:266); no converter change needed.
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