Prove the three pattern detectors work on unseen inputs, not just the RTL
they were derived from. Because detection is functional (ConstEval
fingerprinting over the reachable input space), correctness is established
per case with equiv_opt -assert (full) or a SAT miter clamped to the
reachable range (non-power-of-two), and detection is confirmed with a
w:*tag* probe.
opt_priokey:
D1-D3 spelling variants (explicit shift-or set, compound derived guard,
accumulator also exported) -- all fire and prove equivalent.
E1-E2 parameter sweep P=2..8, S=4..32.
E3 non-power-of-two S=12 reachable-range equivalence via SAT miter.
E4 same shape under -strict declines to rewrite (formal-flow safety).
F1-F2 near-miss negatives (clear accumulator, multi-hot set) -> no rewrite.
opt_prienc (round-robin):
RR4-RR5 DEPTH sweep 8/32, full sequential equivalence.
RR6 non-power-of-two DEPTH=7 reachable-range equivalence (SAT miter).
RR7 an entirely different spelling (upward wrap-scan, first-hit) of the
same arbiter -- fires and proves equivalent.
RR8 fixed-priority (no rotating pointer) negative.
opt_first_fit_alloc (coalesce):
H1 inline same-category compare (no precomputed matrix) spelling.
H2 different slot/field shape (N=8, NB=8, W=3).
All new cases pass locally; they avoid brittle exact cell-count asserts so
they are robust to upstream optimization drift.
Co-authored-by: Cursor <cursoragent@cursor.com>
The round-robin detector fed sigmap(wire) signals straight into
ConstEval::set() while sweeping test vectors. On real designs a candidate
bus can have bits tied to constants, repeated bits, or a req/start pair
that alias to the same net after sigmap. ConstEval::set() asserts
(current_val[i].wire != NULL || current_val[i] == value[i]) when asked to
re-pin such a bit to a conflicting value, crashing the pass
(consteval.h:83) on designs like veer/picorv32/murax/raygentop under
formal synthesis.
Add clean_set_signals() and reject any fingerprint candidate whose
set-signals contain constant bits, repeated bits, or overlap each other,
in both the priority-encoder and round-robin paths. Skipping an unclean
candidate only forgoes a possible rewrite; it never produces an incorrect
one. Clean candidates (the intended patterns) are unaffected.
Co-authored-by: Cursor <cursoragent@cursor.com>
The max_pairs budget was a single running counter shared across all
req_wire iterations, so once a start-candidate-heavy first req size
exhausted it, every later req size broke on its first start candidate and
was silently skipped. Reset the budget per req_wire so all req sizes get
a fair chance. (Completeness only; fingerprint_rr still validates every
match, so this never affected correctness.)
Co-authored-by: Cursor <cursoragent@cursor.com>
Extend two existing opt passes and add one new pass to collapse
serial/dynamic-index structures that were leaving high logic depth:
- opt_first_fit_alloc: recognize the "coalesce-matrix" first-fit
allocator variant (same_cat[i][k] coalescing gated on the leader's
enable, driven from a raw input enable). Rewrite both the lane_slot
allocation and the xbar field gather from one shared log-depth scan.
- opt_prienc: detect round-robin / rotated-priority scans (req scanned
from idx_last downward with wraparound) and rewrite the depth-N
idx--/req[idx] mux chain to rotate -> log-depth priority-encode ->
unrotate.
- opt_priokey (new): recognize priority-by-key one-hot accumulators and
replace each dynamic taken[key] read ($shiftx/$bmux) with the
equivalent pairwise-key-compare reduction, dropping the wide dynamic
indexing. Supports -strict for full-key-range formal validation.
Each includes self-contained tests (equiv_opt / sat -prove-asserts,
mux-bound and negative cases) in tests/opt/.
Co-authored-by: Cursor <cursoragent@cursor.com>
Fix the failing regression test: the single-fanout passthrough removal was
shorting out a cone's only real gate (e.g. a lone $_NOT_ driving an output),
replacing it with a bare wire. That drops the gate entirely (nothing left to
characterize) and, for an inverter, silently drops the inversion, making the
carved cell inequivalent to the RTL. Only short a redundant re-driver whose
input is driven by another in-cone cell; keep a passthrough that reads a
primary input (the cell-under-test's boundary gate).
Also address Greptile review comments:
- fix swapped log_warning arguments in the split-boundary-port diagnostic.
- error out (instead of silently overwriting) when two cell groups rename to
the same carved module name (e.g. slow_<enc> and fast_<enc> -> <enc>).
- derive pq_speed from the explicit "fast_" base prefix.
Co-authored-by: Cursor <cursoragent@cursor.com>