Title: [Bug] Detailed router: regional repair only activates when violations
are <= 100 — inverted condition leaves dense violation fields without joint
repair (DR diverges)
Self checks
ECC version
ecc 1f910c3 (openecos-projects/ecc) + ecc-tools f6ee10a, dreamplace 308dcd35
(frozen M1 toolchain; the buggy line is unchanged on current main).
Affected area
Routing (iRT detailed router)
Environment
- OS: Ubuntu 26.04 LTS, x86_64
- PDK: ICS55 (icsprout55-pdk)
- Design: ~94k-cell SoC with two SRAM macros, util 0.65, MET1-5 routing
Steps to reproduce
- Run the RTL2GDS flow on any block-scale design whose detail-route first
iteration leaves more than 100 violations (e.g. ~116k in our case).
- Observe the per-iteration log line:
setDRIterParam] regional_repair: 0 (violations: 116233, threshold: 100)
- Watch the end-of-iteration violation table across iterations.
Expected behavior
The regional-repair mechanism — iRT's only joint multi-net repair (rip up all
nets overlapping a violation region and re-solve them together, per
routeDRRegionalRepair) — should engage when violations are NUMEROUS, i.e.
whenever violation_num > threshold.
Actual behavior
DetailedRouter.cpp:199:
dr_iter_param.set_regional_repair(iter > 1 && violation_num > threshold); // our fix
// baseline:
// dr_iter_param.set_regional_repair(iter > 1 && 0 < violation_num
// && violation_num <= threshold); // threshold = 100
The baseline comparison is INVERTED: regional repair only activates when
violations are <= 100 (design nearly clean), and NEVER for dense violation
fields — exactly when coordinated repair is needed. All iterations 2-9 on
every run therefore used only the single-net greedy churn path
(updateTaskSchedule selects one net per violation), which in dense pockets
net-ADDS violations:
- old-netlist run k00: end-DRC 554,844 -> 957,592 (+73%) -> 1,126,568 (+18%)
— router diverges, never converges
- safe-netlist run n01: 117,744 -> 178,447 (+52%) -> 242,803 (+36%)
After the one-line flip, regional repair engages from iteration 2
(regional_repair: 1 (violations: 114288, threshold: 100)) and the series
converges:
- n02: 114,288 -> 99,610 (-12.8%) -> 95,753 (-3.9%) -> 94,711 (-1.1%)
- n04 (with layout levers): 106,951 -> 90,669 -> 87,202 -> 86,520
- n10: 100,170 -> 83,781 -> 80,071 -> 78,610 -> 77,604
Suggested fix
Flip the comparison to violation_num > threshold (one line). The threshold
semantics ("activate the expensive joint repair only when there are enough
violations to justify it") match TritonRoute-style repair heuristics.
Related (to file separately)
buildGuidePenaltyMap gate: repair reroutes never follow GRT guides
(guide_ratio <= 0 || !initial_routing || routed_times > 0 returns early
in every reroute) — tested, effect neutral in our runs but semantically
suspect.
updateTaskSchedule selects only ONE net per violation (a break), so
conflict partners are never ripped in the same round; combined with the
rip-then-route-one-net-at-a-time flow in routeDRBox, dense pockets
freeze (measured: 92% of iteration-4 violations already existed at
iteration 1). Proposed two-phase rip-up fix — being validated in a local
build before filing.
Environment notes
- The design also had the floorplan/density issue family (ecc#155,
ecc-dreamplace#31) addressed separately; this bug is independent — it
reproduces with a correct, macro-inclusive die.
Title: [Bug] Detailed router: regional repair only activates when violations
are <= 100 — inverted condition leaves dense violation fields without joint
repair (DR diverges)
Self checks
ECC version
ecc 1f910c3 (openecos-projects/ecc) + ecc-tools f6ee10a, dreamplace 308dcd35
(frozen M1 toolchain; the buggy line is unchanged on current main).
Affected area
Routing (iRT detailed router)
Environment
Steps to reproduce
iteration leaves more than 100 violations (e.g. ~116k in our case).
setDRIterParam] regional_repair: 0 (violations: 116233, threshold: 100)Expected behavior
The regional-repair mechanism — iRT's only joint multi-net repair (rip up all
nets overlapping a violation region and re-solve them together, per
routeDRRegionalRepair) — should engage when violations are NUMEROUS, i.e.whenever
violation_num > threshold.Actual behavior
DetailedRouter.cpp:199:The baseline comparison is INVERTED: regional repair only activates when
violations are <= 100 (design nearly clean), and NEVER for dense violation
fields — exactly when coordinated repair is needed. All iterations 2-9 on
every run therefore used only the single-net greedy churn path
(
updateTaskScheduleselects one net per violation), which in dense pocketsnet-ADDS violations:
— router diverges, never converges
After the one-line flip, regional repair engages from iteration 2
(
regional_repair: 1 (violations: 114288, threshold: 100)) and the seriesconverges:
Suggested fix
Flip the comparison to
violation_num > threshold(one line). The thresholdsemantics ("activate the expensive joint repair only when there are enough
violations to justify it") match TritonRoute-style repair heuristics.
Related (to file separately)
buildGuidePenaltyMapgate: repair reroutes never follow GRT guides(
guide_ratio <= 0 || !initial_routing || routed_times > 0returns earlyin every reroute) — tested, effect neutral in our runs but semantically
suspect.
updateTaskScheduleselects only ONE net per violation (abreak), soconflict partners are never ripped in the same round; combined with the
rip-then-route-one-net-at-a-time flow in
routeDRBox, dense pocketsfreeze (measured: 92% of iteration-4 violations already existed at
iteration 1). Proposed two-phase rip-up fix — being validated in a local
build before filing.
Environment notes
ecc-dreamplace#31) addressed separately; this bug is independent — it
reproduces with a correct, macro-inclusive die.