Skip to content

syn: reject combinational loops in synthesize - #11618

Merged
maliberty merged 2 commits into
The-OpenROAD-Project:masterfrom
The-OpenROAD-Project-staging:syn-comb-loop-check
Oct 3, 2026
Merged

maliberty merged 2 commits into
The-OpenROAD-Project:masterfrom
The-OpenROAD-Project-staging:syn-comb-loop-check

Conversation

@maliberty

Copy link
Copy Markdown
Member

Summary

The elaborator lowers latches (e.g. a latch-based clock gate) to feedback muxes. syn cuts such a loop with a loop_breaker and then optimizes it as combinational logic, which does not preserve the state the loop holds. On nangate45/ibex the enable of prim_clock_gating dropped out entirely, leaving AND2(clk_i, clk) -> clk. CTS's LatencyBalancer::computeSinkArrivalRecur then recursed around that loop until the stack overflowed (a segfault in 4_1_cts).

synthesize now checks for combinational loops after the full bitblast and fails with SYN-0080, naming nets on each loop (SYN-0079), instead of silently producing a wrong netlist.

  • Loops are found as strongly connected components of a per-pin dependency graph, so word-level false loops (e.g. feedback through an adder) are not reported.
  • A liberty cell output depends only on the inputs in its function/three_state expression or with a combinational/tristate timing arc to it. An output with neither (such as a fakeram read port) breaks the loop, matching how Yosys treats such cells as opaque.
  • New comb_loop regression test covers a word-level false loop, a loop through a RAM macro, a multi-output cell with independent paths (all accepted), and a loop through one pin of a partially opaque cell and a latch clock gate (both rejected).

Running the check across all ORFS designs: every design that uses syn upstream (SYNTH_USE_SYN = 1) still passes. Designs containing real latches now fail at synthesis rather than producing a broken netlist: ibex (all platforms), picorv32 ((* full_case *) is not honored by the elaborator), bp_quad and mempool_group. None of these use syn upstream.

The elaborator lowers latches (e.g. a latch-based clock gate) to feedback
muxes. syn cuts such a loop with a loop_breaker and optimizes it as
combinational logic, which does not preserve the state the loop holds.
For ibex's prim_clock_gating the enable dropped out entirely, leaving
AND2(clk_i, clk) -> clk; CTS then recursed around that loop until the
stack overflowed.

synthesize now checks for combinational loops after the full bitblast
and fails with SYN-0080, naming nets on each loop (SYN-0079). Loops are
found as strongly connected components of a per-pin dependency graph:
a liberty cell output depends only on the inputs in its function or
three_state expression, or with a combinational or tristate timing arc
to it. An output with neither, such as a RAM read port, breaks the loop.

Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
@maliberty maliberty self-assigned this Oct 3, 2026
@github-actions github-actions Bot added the size/L label Oct 3, 2026

@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 a combinational loop detection mechanism (checkCombinationalLoops) to the synthesis flow, which identifies and rejects designs containing combinational loops (such as inferred latches) using Tarjan's strongly connected components algorithm. Feedback on the implementation suggests fixing the net name indexing for vectors declared in descending order to prevent incorrect names in warnings, and falling back to printing net IDs for unnamed nets to improve debuggability.

Comment thread src/syn/src/flow/loop_check.cc
Comment thread src/syn/src/flow/loop_check.cc
Unnamed nets on a reported loop print as %<id>, which dump_fanin_cone
accepts, instead of being dropped; unnamed loop-breaker aliases are
skipped. Vector bit names use the same from/to mapping as resolveNetRef.

Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
@maliberty
maliberty marked this pull request as ready for review October 3, 2026 02:18
@maliberty
maliberty requested a review from a team as a code owner October 3, 2026 02:18
@maliberty

Copy link
Copy Markdown
Member Author

@povik FYI

@maliberty
maliberty merged commit 2d645dd into The-OpenROAD-Project:master Oct 3, 2026
20 checks passed
@maliberty
maliberty deleted the syn-comb-loop-check branch October 3, 2026 03:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant