Skip to content

synth: SYNTH_ABC_PARTITION, one abc call per register group - #4731

Draft
dvanblerkom wants to merge 2 commits into
The-OpenROAD-Project:masterfrom
dvanblerkom:synth-abc-partition
Draft

dvanblerkom wants to merge 2 commits into
The-OpenROAD-Project:masterfrom
dvanblerkom:synth-abc-partition

Conversation

@dvanblerkom

@dvanblerkom dvanblerkom commented Oct 24, 2026 •

Copy link
Copy Markdown

TL;DR: ABC sees no SDC: no clocks, no false paths, and no arrival times at cells mapped before it, such as extract_fa's adders. It maps each run against that run's own critical path and area-recovers every cone that is faster. When that critical path is the wrong one, the real cones are rebuilt smaller and slower, and repair_timing can resize and buffer them but not restructure them. SYNTH_ABC_PARTITION=<n> maps the top module with one abc call per register group, so a wrong critical path only affects one group. It is a workaround, not a fix, and it is off by default (0).

Why the critical path ABC sees can be wrong

  • Pre-mapped cells. On sky130hd/jpeg the critical paths are the MAC multipliers: four fa cells and an ha, then a final adder built by ABC. ABC sees the adder-cell outputs as arriving at t=0. In one run its critical delay is 2.2 ns, while the real path is 6.6 ns, so the final adder looks non-critical and is mapped 9 gates deep. With one call per group it is 6 gates deep.
  • False paths and multicycle paths. A path the SDC excludes can set ABC's target. In a test case (one register fed by a compare cone, plus an unrelated 16x16 multiply; sky130hd, ADDER_MAP_FILE=, OpenSTA without wires, 4 ns clock), declaring the multiply a 2-cycle path makes it pass in both netlists. The cone then has −0.61 ns slack with stock synthesis and +2.01 ns with SYNTH_ABC_PARTITION=20.
  • Not the cell delay model. That is a separate issue, handled by ABC_LIBERTY_ARGS="-a -G 250" (synth: ABC_LIBERTY_ARGS, extra arguments for ABC's read_lib #4730). On sky130hd/aes nearly all of the gain comes from synth: ABC_LIBERTY_ARGS, extra arguments for ABC's read_lib #4730 and little from this PR. On jpeg it is the other way round.

With one shared clock and no exceptions the effect is smaller: there, the path ABC relaxes against usually does set the period. Test case and scripts: https://github.com/dvanblerkom/yosys-abc-partition.

How it works

synth_abc_partition.tcl, called in place of log_cmd abc {*}$abc_args, works in four steps:

  • It groups the flops by name, with bit indices and the $_DFF... suffix removed. These are liberty cells after dfflibmap.
  • It selects each group's still-unmapped combinational fan-in with %ci1 %cie* t:$_* %i.
  • It maps the groups largest cone first, with one abc call each. Logic shared by several groups goes to the first group that reaches it.
  • One final abc call maps whatever is left.

abc maps only the selected cells, so there are no hierarchy changes.

Results

Setup WNS / TNS in ns at CTS, area relative to master. One run per configuration.

design master SYNTH_ABC_PARTITION=50
sky130hd/jpeg -0.516 / -71.0 -0.024 / -0.02 (+4.3% area)
sky130hd/riscv32i -0.634 / -49.2 -0.676 / -32.2 (+1.3%)
nangate45/picorv32 -0.304 / -34.5 -0.319 / -33.2 (+1.5%)
nangate45/ibex +0.000 / 0 +0.008 / 0 (+3.1%)
nangate45/jpeg (ABC_AREA=1) -0.106 / -40.3 -0.069 / -32.2 (+17%)
nangate45/gcd (ABC_AREA=1) -0.157 / -7.0 -0.180 / -7.9

The large gain on sky130hd/jpeg comes from the pre-mapped adders described above. The CPUs are roughly neutral, and the option costs area with the area script.

Combined with ABC_LIBERTY_ARGS="-a -G 250" (#4730), sky130hd/riscv32i reaches -0.070 / -0.21 (+3.3%) and sky130hd/jpeg -0.049 / -0.05 (+9.4%).

Limitations

  • Only the top module is partitioned; kept submodules go to the final call. It is meant for SYNTH_HIERARCHICAL=0.
  • It is ignored on the abc_new path (SWAP_ARITH_OPERATORS, SYNTH_WRAPPED_OPERATORS), like ABC_SCRIPT.
  • Grouping by name is a heuristic. Shared logic is not duplicated, so a path that crosses two groups spans two ABC runs.
  • There is one ABC start-up per group: jpeg has 186 groups at n=50, which adds about a minute.

Status

This is a draft. ABC already accepts per-input arrival and per-output required times (read_constr -n), and &nf uses the input arrivals, but Yosys's abc -constr passes only the driving cell and the load. If Yosys gains a way to pass that timing context, that is the better fix, and this PR would become a stopgap or be closed.

How this was tested

Testing was the same as in #4730: make synth used this branch's scripts on master cca3a71, with the Yosys from openroad/orfs:26Q4-102-gef421749a. Floorplan to CTS ran in that image's ORFS on the netlist via SYNTH_NETLIST_FILES.

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Daniel Van Blerkom <vanblerkom@gmail.com>

@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 introduces the SYNTH_ABC_PARTITION feature, which allows mapping the top module with one ABC call per register group to optimize each group against its own critical delay. This is implemented via a new Tcl script synth_abc_partition.tcl and integrated into the synthesis flow, with corresponding updates to documentation and variable configurations. The review feedback suggests making the Tcl script more robust by normalizing cell names to handle leading backslashes, initializing variables n and left before regexp calls to prevent stale values, and explicitly defining the variable type as an integer in both the JSON and YAML configuration files.

Comment on lines +17 to +20
set top $::env(DESIGN_NAME)
set groups [dict create]
foreach cell [tee -q -s result.string select -list "$top/t:*" "$top/t:\$*" %d] {
set name [string range $cell [string length "$top/"] end]

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.

medium

Normalizing $top and $cell by stripping any leading backslash before computing the substring range makes the cell name extraction much more robust against different naming formats in Yosys/RTLIL.

  set top $::env(DESIGN_NAME)
  regsub {^\\} $top {} top_norm
  set groups [dict create]
  foreach cell [tee -q -s result.string select -list "$top/t:*" "$top/t:\\$*" %d] {
    regsub {^\\} $cell {} cell_norm
    set name [string range $cell_norm [string length "$top_norm/"] end]

Comment on lines +41 to +42
regexp {[0-9]+} [tee -q -s result.string select -count \
@abc_partition_group %ci1 %cie* "$top/t:\$_*" %i] n

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.

medium

Initializing n to 0 before running regexp ensures that n is always defined and does not retain a stale value if the regular expression fails to match.

    set n 0
    regexp {[0-9]+} [tee -q -s result.string select -count \
      @abc_partition_group %ci1 %cie* "$top/t:\\$_*" %i] n

select -set abc_partition_group {*}$sel
select -set abc_partition_cone \
@abc_partition_group %ci1 %cie* "$top/t:\$_*" %i
regexp {[0-9]+} [tee -q -s result.string select -count @abc_partition_cone] left

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.

medium

Initializing left to 0 before running regexp prevents it from retaining a stale value from a previous iteration of the loop if the regular expression fails to match.

    set left 0
    regexp {[0-9]+} [tee -q -s result.string select -count @abc_partition_cone] left

Comment thread flow/scripts/variables.json Outdated
Comment on lines +1292 to +1294
"stages": [
"synth"
]

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.

medium

Adding "type": "int" to the variable definition ensures proper type validation and consistent documentation generation.

    "stages": [
      "synth"
    ],
    "type": "int"

Comment on lines +1082 to +1084
stages:
- synth
default: 0

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.

medium

Adding type: int to the variable definition ensures proper type validation and consistent documentation generation.

  stages:
    - synth
  default: 0
  type: int

- Initialize n and left before regexp, so a failed match cannot reuse
  the previous group's count.
- Declare the variable as type int.
- Explain the effect as ABC lacking timing context (no SDC, no arrival
  times at cells mapped before it, such as extract_fa's adders), which
  can make the critical path it maps against the wrong one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Daniel Van Blerkom <vanblerkom@gmail.com>
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