Skip to content

OpenROAD-SYN status: asap7 Bazel syn_test suite, QoR/runtime/clock-period graphs, opt-in LEC#4363

Closed
oharboe wants to merge 12 commits into
The-OpenROAD-Project:masterfrom
oharboe:openroad-syn-status
Closed

OpenROAD-SYN status: asap7 Bazel syn_test suite, QoR/runtime/clock-period graphs, opt-in LEC#4363
oharboe wants to merge 12 commits into
The-OpenROAD-Project:masterfrom
oharboe:openroad-syn-status

Conversation

@oharboe

@oharboe oharboe commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Status report for OpenROAD-SYN (SYNTH_USE_SYN=1) across the asap7 design suite, now wired into Bazel via the config.mk DSL.

What this adds

  • SYNTH_USE_SYN is first-class in the Bazel DSL: both synthesis engines are supported, and a design's config.mk value selects its regular flow's engine (gcd's local_arguments workaround is gone). Carried as four git_override patches on the pinned bazel-orfs commit (patches/bazel-orfs/), to be upstreamed when churn settles.
  • bazelisk test //flow/designs/asap7:syn_test — synthesis-only OpenROAD-SYN QoR gates for 14 designs, failing designs included by design: this is a status suite. The gate checks the synthesis-stage subset of the design's regular rules-base.json (checkMetadata.py --only-prefix), so no per-variant rules files are committed; the generated synthesis rules snapshot (<name>_syn_update_rules) feeds the clock-period plot instead.
  • Status graphs as plain bazelisk build targets (matplotlib from the pip hub, no host deps), checked into flow/docs/images/:
    • //flow/designs/asap7:syn_qor_png — QoR deltas + runtime A/B, failed designs rendered as hatched columns via best-effort _qor targets
    • //flow/designs/asap7:clock_period_png — effective clock period across stages from the checked-in rules-*.json alone
  • Opt-in RTL-vs-netlist LEC (SYNTH_LEC_CHECK=1, make-side): kepler-formal compares the input RTL (experimental slang frontend) against the new always-written 1_synth.v.
  • Fixes surfaced along the way: the Bazel synth stage never declared logs/1_synth.json, so metadata-check could not see any synth__* metrics (broke every Bazel <design>_test with synth rules); bazelisk run <design>_update was broken by a two-source cp; genMetrics.py now tolerates synthesis-only trees.

Where OpenROAD-SYN stands on asap7

QoR

Runtime A/B

Clock period across stages

design OpenROAD-SYN synthesis notes
gcd, gcd-ccs ✅ pass 1.7% less area, 12% fewer instances than yosys
uart ✅ pass yosys baseline itself is broken in Bazel today (read_slang plugin fails to load; pre-existing)
aes, aes_lvt, aes-mbff ✅ pass ~9% less area, ~22% fewer instances; up to 68% faster synthesis
jpeg, jpeg_lvt ✅ pass slightly more area (+3–5%), fewer instances, positive WS
ethmac, ethmac_lvt ✅ pass area parity, ~90% slower than yosys
aes-block ❌ QoR gate fail hierarchical BLOCKS; synthesizes, but +157% area blows past the yosys-derived rules-base gate
mock-alu ❌ fail SDC references yosys-style register names (*io_out_REG*) absent from the SYN netlist
riscv32i ❌ fail slang rejects procedural assignment to nets (dmem.v)
mock-cpu ❌ fail slang rejects endianness-mismatched part-select (wptr_full.v)
ibex ⏱ excluded synthesis completes in seconds; report_metrics STA spins >2h on 48 threads
cva6 ⏱ excluded synthesize takes 73s but repair_design -pre_placement still running after 10+ min when cut off
swerv_wrapper, riscv32i-mock-sram ⏱ excluded large/hierarchical; not yet run to completion

Excluded designs are documented in SYN_SLOW_DESIGNS (flow/designs/asap7/BUILD); their manual per-design targets remain for reproduction.

LEC status (kepler-formal)

The wiring works end-to-end (flist generation, YAML config, verdict grep), but kepler-formal's experimental SystemVerilog frontend cannot yet lower even gcd's RegEn sequential block ("fallback currently supports only multi-LHS reset branches"), so SYNTH_LEC_CHECK is a separate opt-in from LEC_CHECK — otherwise installing kepler-formal would break make synth for every SYN design. Hermetic Bazel-built kepler-formal was investigated and parked: its naja cmake superbuild needs system Boost/CapnProto/TBB and -lstdc++, which cannot work under the zero-sysroot hermetic toolchain (the deps.bzl @@//Label() fix and a BCR onetbb dependency get kepler's own sources compiling and are worth upstreaming to keplertech/kepler-formal).

Refreshing the graphs

bazelisk build //flow/designs/asap7:syn_qor_png //flow/designs/asap7:clock_period_png
cp -f bazel-bin/flow/designs/asap7/openroad-syn-*.png flow/docs/images/

🤖 Generated with Claude Code

oharboe and others added 9 commits July 16, 2026 19:28
genMetrics.py: fall back to 1_synth.sdc for clock extraction when
2_floorplan.sdc is absent (synthesis-only trees, e.g. FLOW_VARIANT=syn);
guard the 5_1_grt.log/6_finish.rpt extractions so stages that never ran
do not pollute metadata with ERR values; treat empty netlist files like
missing ones when hashing (Bazel placeholder files hash like a make run
that never wrote the file).

genRuleFile.py: add synth instance count (padding) and synth setup
WS/TNS (period padding) so rules-syn.json QoR gates cover the metrics
synth_syn.tcl reports. Note base-variant update_rules runs will now pick
these up too.

utils.mk: metadata-synth convenience target (synth + metadata-generate +
metadata-check) for make-side smoke runs of the syn variant.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
synth_syn.tcl now always writes a gate-level 1_synth.v (via
write_lec_verilog: physical-only masters removed, LEC_AUX_VERILOG_FILES
honored) — the Bazel synthesis action declares it as an output and it is
the post-synthesis side of LEC.

lec_check.tcl: factor the kepler-formal run/verdict out of run_lec_test
into run_lec_config, and add an RTL-vs-netlist synthesis LEC
(run_synth_lec_test): the input RTL goes through kepler-formal's
experimental slang/SystemVerilog frontend via a generated flist
(VERILOG_FILES, +incdir+, defines, -G top params, SYNTH_SLANG_ARGS) and
is compared against 1_synth.v + LIB_FILES.

Gated by a new SYNTH_LEC_CHECK variable (default 0) rather than
LEC_CHECK: LEC_CHECK auto-enables when kepler-formal is installed
(flow/settings.mk), and kepler's SV frontend does not yet support all
RTL constructs — e.g. gcd's RegEn sequential block fails lowering
('fallback currently supports only multi-LHS reset branches') — so
riding the auto-enable would break make synth for every SYNTH_USE_SYN
design on developer machines. CTS-stage LEC is unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
plotSynQoR.py renders the syn-vs-yosys synthesis QoR comparison from
per-design best-effort qor.json pairs: percent-delta panels (std-cell
area, instance count, runtime) plus an absolute SYN worst-slack panel,
with failed designs drawn as hatched FAIL columns instead of omitted.
--runtime-output adds an absolute runtime A/B grouped-bar chart (log
scale) from the same inputs.

plotClockPeriod.py renders effective clock period (target - gated worst
slack) across synth/cts/globalroute/finish, one series per design, from
the checked-in rules-*.json files alone — the OpenROAD-SYN synthesis
point overlays the regular flow's trajectory, no flow runs needed.

genMetrics.py gains a scalar constraints__clocks__period metric (rule
files cannot carry the details list) and genRuleFile.py propagates it as
a direct == rule, so regenerated rules files feed the clock-period plot.

Both scripts are matplotlib py_binaries fed from the @orfs-pip hub, so
bazelisk build needs no host python packages; output is deterministic
(Agg, fixed geometry, no timestamps) for meaningful PNG diffs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
Four patches on the pinned BAZEL_ORFS_COMMIT, to be upstreamed once the
status-suite churn settles:

- 0001: SYNTH_USE_SYN engine selection in the synth stage rule; declare
  logs/1_synth.json in both engine modes (generate_metadata previously
  never saw synth__* metrics in bazel); orfs_test honors its cmd attr.
- 0002: synthesis-only flows (last_stage="synth") get the same
  metadata/test/update_rules/update chain as full flows, gated on
  RULES_JSON — with FLOW_VARIANT=syn this selects rules-syn.json.
- 0003: orfs_update copies only rules.json (cp of the stage's whole
  DefaultInfo broke bazelisk run <design>_update for everyone).
- 0004: orfs_design(extra=) caller hook so ORFS's config.mk DSL layer
  owns the OpenROAD-SYN status policy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
Every design now gets manual OpenROAD-SYN status targets via the
orfs_design extra hook (flow/designs/design.bzl): a synthesis-only
variant "syn" flow with SYNTH_USE_SYN=1 forced (<name>_syn_synth, and
with a rules-syn.json also <name>_syn_test / <name>_syn_update) plus a
best-effort <name>_syn_qor / <name>_yosys_qor pair (flow/designs/qor.bzl)
that always builds, emitting metadata or a failure marker for the QoR
comparison graph.

flow/designs/asap7/BUILD aggregates them: bazelisk test
//flow/designs/asap7:syn_test (17 designs, failing ones included — it is
a status suite) and the graph genrules syn_qor_png / clock_period_png.
ibex is excluded as a documented runaway: its OpenROAD-SYN synthesis
completes but report_metrics STA spins for hours.

gcd's SYNTH_USE_SYN local_arguments workaround is gone — the DSL now
routes the variable natively, so gcd's regular flow uses OpenROAD-SYN
like make does. The single-process comparison keeps a dedicated
yosys-engine flow variant since single_flow.tcl seeds from the yosys
netlist.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
Real gates (from <design>_syn_update runs: std-cell area/count with
padding, period-padded setup WS/TNS, clock count and period, warning-
level netlist hashes) for the 11 designs whose OpenROAD-SYN synthesis
passes: gcd, uart, aes, aes_lvt, aes-mbff, aes-block, jpeg, jpeg_lvt,
ethmac, ethmac_lvt, gcd-ccs.

Minimal stubs (instance count > 0) for designs that fail today, so
their <name>_syn_test targets exist and fail honestly at the synth
stage: mock-alu (SDC references yosys-style register names), riscv32i
(slang rejects procedural assignment to nets), mock-cpu (slang rejects
endianness-mismatched part-select), and the slow/excluded set (ibex,
cva6, swerv_wrapper, riscv32i-mock-sram).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
Generated by:
  bazelisk build //flow/designs/asap7:syn_qor_png
  bazelisk build //flow/designs/asap7:clock_period_png
  cp -f bazel-bin/flow/designs/asap7/openroad-syn-*.png flow/docs/images/

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
… targets

Move cva6, swerv_wrapper and riscv32i-mock-sram next to ibex in
SYN_SLOW_DESIGNS: their OpenROAD-SYN runs are too slow (or unfinished)
for the aggregators, so they are excluded from syn_test and the QoR
graph while their per-design manual targets remain for reproduction.
Make the best-effort qor targets public so the platform-level genrules
can consume them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
@oharboe

oharboe commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator Author

@povik @maliberty I took OpenROAD SYN for a spin.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request integrates OpenROAD-SYN support into the design flow, enabling a synthesis-only variant and a best-effort synthesis QoR reporting suite for asap7 designs. Key changes include adding Bazel patches for bazel-orfs, implementing new QoR reporting targets and plotting utilities, and integrating formal equivalence checking (LEC) for synthesis. The build configuration was updated to support these status targets, and a minor improvement was suggested to refactor a dictionary comprehension in design.bzl for better readability and efficiency.

Comment thread flow/designs/design.bzl
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@oharboe
oharboe force-pushed the openroad-syn-status branch from 40ed76f to d9edaaa Compare July 16, 2026 17:32
Compute the RULES_JSON-stripped sources dict once per design instead of
once per qor variant, per gemini-code-assist review on the status PR.

Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>

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

oharboe commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator Author

@povik It is enormously much further along than the first time I tried it. 🤠

… files

The synthesis-only QoR gate now checks the synthesis-stage subset of the
design's regular rules-base.json (checkMetadata.py --only-prefix via the
new metadata-check-synth target, bazel-orfs patch 0005) instead of a
committed per-variant rules file, so the 18 rules-syn.json files are
gone from git. This also makes the gate meaningful: aes-block's SYN run
now fails its gate because its area blows past the yosys-derived
reference (+157%), which the self-referential rules-syn.json had masked.

The clock-period plot consumes the generated synthesis rules snapshot
(the syn variant's update_rules stage output) through per-design
filegroups instead of checked-in files; designs whose SYN synthesis
fails outright are excluded via SYN_FAILING_DESIGNS. <name>_syn_update
is no longer emitted — it would have overwritten rules-base.json with
synthesis-only rules.

Suite status: 10 pass, 1 QoR-gate fail (aes-block), 3 fail to
synthesize (mock-alu, riscv32i, mock-cpu).

Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>

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

oharboe commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator Author

Closing this in favor of a narrower follow-up PR that carries only the immediate concern: a local Bazel counterpart of the Jenkins QoR signal (https://dashboard.precisioninno.com/), so OpenROAD-SYN can be iterated on locally with fast, targeted feedback — on any design, including designs not yet officially switched to SYN, with a forced-yosys comparison still available after a switch.

The rest of this PR is parked, not abandoned:

  • SYNTH_LEC_CHECK (opt-in RTL-vs-netlist LEC) waits for kepler-formal's experimental SystemVerilog frontend to become more capable (today it cannot lower even gcd's RegEn block).
  • Hermetic Bazel deployment of kepler-formal needs upstream work in its naja cmake superbuild (system Boost/CapnProto/TBB).
  • The QoR/runtime/clock-period status graphs are superseded by the dashboard.

Everything here remains in this closed PR / the openroad-syn-status branch and can be revived when those pieces mature.

@oharboe

oharboe commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator Author

The narrower follow-up PR is #4365 (bazel-orfs side merged as The-OpenROAD-Project/bazel-orfs#771).

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