Generating 4-state evaluators for derived signals from slang --ast-json: four fixes to reach bit-exact parity
I generated C++ 4-state evaluators for every combinational signal of a design from slang's elaborated AST, then checked them against a waveform reader's own rebuild. All of them matched bit for bit, but only after four fixes:
1. Run slang --ast-json ... --disable-instance-caching. Without the flag, repeated instance bodies are omitted, and per-instance paths (u_x[3].y) can't be built.
2. Enum-typed variables: take the width from EnumType.baseType (e.g. logic[1:0]). Don't use the members' initializer types; they are often int (32 bits).
3. Output ports driven by always_ff inside a child: the dumper may store only the outermost copy (e.g. tb.done[15:0]) and mark the inner ones (tile.done, cluster.done[t]) as derived.
- A forward cone (inner -> outer) then never reaches a stored leaf.
- Add a "reverse port view": inner = outer lvalue expression of the Out port connection. Use it when the inner driver chain is rooted in a clocked block. It is only exact when the widths are equal.
4. always @* at time 0: it fires at t=0 iff some operand holds a non-x bit once the time-0 settling is done. Otherwise the outputs stay x until the first operand change.
Also worth knowing: hash every rebuilt output stream. In my case 64% of the "computed" signals were exact copies of a stored signal (port alias chains), so an alias pointer replaced their evaluation entirely.