Multi-layer Pathfinder routing was the single major contributor to congestion reduction. All placement-side optimizations were either reverted or marginal.
| Attempted Fix | Target | Congestion Impact |
|---|---|---|
| Hard shell repulsion | QPO placement | Reverted — made QPO worse, pushed components into corners |
| Channel enforcement | QPO placement | Reverted — fought attraction forces every sweep |
| Footprint-aware repulsion | QPO placement | Reverted — broke layout for mixed-size pairs |
| Channel-aware cost term | QPO cost function | Reverted — no visible effect on routing quality |
| Cheap proxy congestion | QPO mid-round refresh | Reverted — inaccurate heatmap, worse than stale |
| Handcrafted positions | Initial placement | Reverted — cascading issues with QPO_MIN conflicts |
| Congestion-aware QPO cost (λ) | QPO cost function | Marginal — ~5% improvement at best |
| Adaptive net reorder | Pathfinder iteration | Marginal — tiebreak role only |
| Route-eval frame selection | QPO→routing bridge | Helpful — picks better QPO frame by actual routing |
| Multi-layer A* with vias | Pathfinder router | 16.0 → 0.8 (95% reduction) |
│ Cong │ Zero% │ Match │ Vias │ WL
────────────────────┼───────┼───────┼────────┼──────┼──────
1-Layer (baseline) │ 16.0 │ 0% │ 59.2% │ 0 │ 698λ
3-Layer M1-pin-only │ 3.3 │ 0% │ 60.4% │ 20 │ 577λ
3-Layer any-layer │ 0.8 │ 50% │ 61.7% │ 18 │ 572λThe A* search space expanded from (x, y) to (x, y, z) where z ∈ {0, 1} represents the metal layer:
Congestion tracking became per-layer: presOcc[z][x][y]. Two nets crossing at the same (x, y) on different layers no longer conflict. This is the key — the old single-layer router counted every crossing as congestion, even when the nets would physically pass over each other on different metal layers.
The original congestion was never a placement problem. We spent 12 iterations trying to fix QPO placement — adjusting repulsion, adding channel enforcement, computing footprint-aware distances, feeding congestion back into the cost function. None of it worked because the fundamental issue was routing dimensionality: 18 nets competing for 4,800 cells when they should have had 9,600 (2 layers × 4,800).
The placement optimizations were trying to spread components apart to create wider routing channels — compensating for a router that couldn't use vertical clearance. With a proper multi-layer router, the original QPO with random scatter and simple repulsion already produces zero-congestion results on 50% of seeds.
When routing fails, fix the router first, not the placer.
Placement quality matters, but only after the router can actually exploit the available routing resources. A perfect placement with a single-layer router will always congest. A mediocre placement with a multi-layer router routes cleanly.