content by LCUS
Six Layers, 1,536 Balls: Why the Escape Router Ran Out of Room at Ring 3
11 min read
10 parts, 45 paragraphs
A 1,536-ball interposer, six signal layers, and a router that ran out of room after four rings. The fix was not more layers. It was noticing that five sixths of every layer was empty.
The AutoPhi V19 interposer has one job: take a die with 1,536 pads on a 0.800 mm grid and fan it out to a BGA with 1,536 pads on a 2.000 mm grid. Same 48 × 32 array on both sides, 2.5× bigger on the way out. Nothing clever. Just 1,536 connections that have to physically exist.
It took three rewrites of the router to get there, and every rewrite started with a wrong assumption that DRC eventually corrected. This is the whole sequence, including the parts that did not work.
The Board
| Die side (U1) | 1,536 pads, 48 × 32, 0.800 mm pitch, 0.35 mm round pads, 37.60 × 24.80 mm |
| Board side (BGA1) | 1,536 pads, 48 × 32, 2.000 mm pitch, 0.9 mm pads, 94.00 × 62.00 mm |
| Stackup | 12 copper: TOP, GND1, SIG1, SIG2, PWR1, SIG3, SIG4, PWR2, SIG5, SIG6, GND2, BOTTOM |
| Signal layers | six — SIG1 through SIG6 |
| Nets | 960 signal balls, 576 on rails (GND, APH_VDD_CORE, 1V0) which drop straight to a plane |
| Geometry | 0.075 mm track, 0.20 mm microvia pad on 0.10 mm drill, 0.40 mm blind via pad on 0.20 mm drill |
Index the array from the outside in and you get sixteen concentric rings. Ring 0 is the outer edge, ring 15 is the four innermost columns. The outer rings are easy — a ball on the edge has open board on three sides. The inner rings are the whole problem, because a ball in the middle has to cross everything outside it to get anywhere.
Attempt One: One Ring, One Layer
The first router gave every ball a private drop lane and every ring its own layer. Ball leaves its die pad, jogs off the pad row, runs horizontally out past the edge of the die pin field, drops down a lane nobody else is using, runs back in to its board pad. Clean, easy to reason about, and provably free of crossings because no two balls ever share a segment.
It got through four rings and stopped:
| Ring | Signal balls | Layers consumed |
| 0 | 90 | SIG1 |
| 1 | 86 | SIG2 |
| 2 | 108 | SIG3 + SIG4 |
| 3 | 100 | SIG5 + SIG6 |
| 4–15 | 576 | none left |
384 balls routed, all six signal layers gone, 576 balls with nowhere to go. Rings 2 and 3 needed two layers each because their left/right traffic and their up/down traffic both want the same corner quadrants, so they had to be split.
An autorouter was the obvious next move. Freerouting ran for hours on the same board and ended its log like this:
java.lang.NullPointerException 2026-07-26 07:26:09.288 ERROR Error during routing passes java.lang.NullPointerException 2026-07-26 07:35:33.143 INFO Saving 'autophi-1536-interposer.ses'...
The file it saved was zero bytes.
The Thing I Had Wrong
The private-lane design was not just conservative. It was answering a question the board does not ask.
The die pads live on TOP. They are 0.35 mm circles on a 0.800 mm grid, and they are dense — that is what makes the die field look impassable. But a signal never routes on TOP. It drops through a microvia to a signal layer, and on that signal layer the die pads do not exist. The only copper there is the 0.20 mm microvia landing belonging to whichever balls were assigned to that particular layer.
Six signal layers, 960 signal balls. Spread evenly, any one signal layer carries about 160 microvia landings across an area of roughly 6,800 mm². The rest is empty. The first router was routing around an obstacle that was on a different layer.
Attempt Two: Measure First
So: model the real obstacles and let a router use the whole plane. A uniform 0.05 mm grid over the board gives 2,000 × 1,360 cells per layer. Mark what a trace centre cannot occupy, then run A* from die pad to board pad, with the direction of travel carried in the search state and a penalty on turns so the paths come out as long rectilinear runs instead of maze scribble.
The first measurement said SIG1 was 64.1% blocked. That did not match the argument above at all, which was the useful part — a number that disagrees with your reasoning is worth more than one that confirms it.
The cause was in my own occupancy code. I was blocking each existing trace by filling its bounding box. That is exact for an axis-aligned segment and catastrophically wrong for a diagonal one. And ring 0 was laid by an even earlier router as single straight diagonals:
| Layer | Tracks | Total length | Average |
| SIG1 | 90 | 2,369.9 mm | 26.3 mm |
| SIG3 | 280 | 1,993.6 mm | 7.1 mm |
Ninety diagonals averaging 26 mm each, every one of them blocking a square roughly 26 mm on a side. Rasterising the actual swept area instead — a vectorised point-to-segment distance over the bounding box — dropped SIG1 from 64.1% to 13.4%. All six layers landed between 9% and 14%.
Four Things DRC Had To Teach Me
The router now produced clean-looking paths that failed DRC. Each round of failures was a real constraint I had not modelled, and each one is the kind of thing that is obvious in hindsight and invisible in advance.
1. A microvia is not a point on its landing layer
Setting a via’s layer pair to TOP–SIG5 does not put copper on SIG5. It puts a barrel through SIG1, SIG2, PWR1, SIG3 and SIG4 on the way down. I had stamped only the landing layer, so inner-ring balls that landed deep punched their barrels straight through the traces of rings 0–3:
[shorting_items]: Items shorting two nets (APH_HSIO_PAIR_238_N and APH_HSIO_PAIR_239_P) @(2.8000 mm, -0.4000 mm): Track [APH_HSIO_PAIR_238_N] on SIG3 @(3.6000 mm, -0.4000 mm): Micro via [APH_HSIO_PAIR_239_P] on TOP - SIG5
This also inverts the cost of a layer choice. A ball landing on SIG1 blocks its die-pad location on one layer. A ball landing on SIG6 blocks it on all six. The die field is the scarce resource, so the router now tries shallow layers first and only goes deep when it has to.
2. The clearance that applies is not the one in the board rules
Board setup says min_clearance: 0.075. The netclass says clearance: 0.2. The netclass wins, and every channel I had sized off 0.075 was too tight by more than a factor of two:
[clearance]: Clearance violation ( clearance 0.2000 mm; actual 0.0625 mm)
The board minimum is a floor for what the fab can build. It is not what your nets are actually being held to.
3. Vias collide on layers the router never draws on
The die grid is 0.800 mm and the board grid is 2.000 mm, both centred on the same origin. Those two grids drift in and out of phase, and in places a die pad ends up 0.283 mm from a board pad. Their barrels then meet on PWR1 — a plane layer, where this router never places a single trace:
[shorting_items]: Items shorting two nets (APH_VDD_CORE and APH_MGMT_GPIO_149) @(-5.0000 mm, 11.0000 mm): Blind via [APH_VDD_CORE] on PWR1 - BOTTOM @(-5.2000 mm, 10.8000 mm): Micro via [APH_MGMT_GPIO_149] on TOP - SIG4
Via feasibility is therefore checked across all twelve copper layers, not the six the router cares about.
4. Moving a via invalidates the antipad that made it legal
Every barrel that crosses a power plane needs the pour to clear a hole around it. Re-point the via and that hole is in the wrong place. Twenty-one hole_clearance violations, all reading actual 0.0000 mm against a zone, disappeared the moment the fills were regenerated before saving.
The Bug That Only a Counter Can Fix
One more, and it is the most interesting of them.
Every ball needs a via at its die pad. Until a ball is routed, nobody knows which layers its barrel will cross — so the router reserves the worst case, TOP down to the deepest signal layer, for every ball still waiting. Otherwise an early ball routes straight across a later ball’s pad and strands it permanently.
But when a ball’s own turn comes, it has to hand that reservation back, or it blocks itself. With a boolean occupancy grid there is no way to do that: if two owners both marked a cell, clearing it for one clears it for both.
So occupancy is a count, not a flag. A ball decrements its worst-case reservation, asks what is reachable, and increments the barrel it actually committed to. Conservative early, exact by the end.
My first attempt at this was a shortcut — a set of cells near each ball’s pads that the search was allowed to treat as passable, on the grounds that a ball must be allowed to sit on its own keepout. It also let the ball sit on everyone else’s copper. Two traces 0.200 mm apart where 0.275 mm was required, for exactly that reason. A “just this once” exception in a constraint checker is a constraint checker with a hole in it.
Where It Stands
All sixteen rings re-routed from scratch: 506 of 960 signal
balls escaped, and DRC came back cleaner than the board had
ever been. Clearance 40 to 0. Shorting 2 to 0. Those forty clearance
violations were the original router’s, and re-laying its work removed
them.
| DRC category | Before | After |
| clearance | 40 | 0 |
| shorting_items | 2 | 0 |
| tracks_crossing | 0 | 0 |
| hole_clearance | 0 | 0 |
Getting there took two more mistakes worth naming. Clearing the traces
does not clear the via layer pairs, so 451 unrouted balls kept
microvias parked as deep as TOP–SIG6 while the occupancy model had
only reserved their guaranteed TOP–SIG1: five layers of copper the
model believed were empty, and 199 shorts. And reserving each waiting
ball’s worst-case barrel rather than its guaranteed one
blocked all six layers at all 1,536 die pads at once, which on a 0.8 mm
grid leaves single-cell channels and stalls the router outright.
Then I Stopped Tuning And Derived The Bound
Three rounds of tuning all landed near 510. When effort stops moving a
number, the number is probably not effort-limited.
A ball landing on signal layer k has a microvia spanning
TOP–k and a blind via spanning k–BOTTOM.
Those cross k and (N − k + 1)
signal layers respectively. Add them:
k + (N - k + 1) = N + 1 for every k
The layer choice cancels. Every ball costs seven
barrel-layer crossings on a six-signal-layer board regardless of where it
lands. 960 balls × 7 = 6,720, over six layers = 1,120 via
keepouts per signal layer, invariant. No assignment strategy
changes it. Load balancing helped — it took failures from 56 to 37
on a 250-ball sample — but only by balancing trace
congestion. It cannot touch the via load, and the via load is what binds.
That prediction was testable, so I tested it. If traces were the
constraint, halving the clearance should help:
| Netclass clearance | Trace pitch | Routed / 250 |
| 0.200 mm | 0.275 mm | 207 |
| 0.100 mm | 0.150 mm | 207 |
Identical. I had expected a clear gain and written the conclusion
before running it. Trace pitch is not the constraint.
What The Constraint Actually Is
The die grid is 0.8 mm and the board grid is 2.0 mm, both on
the same origin. 2.5 is not an integer, so the grids beat against each
other, and 240 board pads end up within 0.50 mm of a die pad. The
closest pair is 0.283 mm — at which a
0.20 mm microvia pad and a 0.40 mm blind via pad physically
overlap. No clearance rule reaches that. I tested 36 translations of the
BGA grid; the design as drawn is already the best of them.
The fix is not a rule and not a router. It is dog-boning
— putting the blind via beside its pad instead of in it. Sweeping
candidate sites around each colliding pad:
dog-bone reach 0.35 mm: 240/240 colliding pads get a legal via site, 0 still stuck
0.35 mm of offset clears every one of them, and a 0.9 mm pad
on a 2.0 mm grid has roughly 0.55 mm of room to give. The ceiling
is removable; it just is not removable by anything the router controls.
What I Would Tell Myself At The Start
Measure the obstacle before designing around it. Four
rings of routing were spent avoiding pads that were on a different layer.
A number that contradicts your reasoning is a gift.
“SIG1 is 64% blocked” was wrong, and chasing why found a bounding-box bug
throwing away four fifths of the board.
Read the DRC entries, do not just count them. Every
count moved in the right direction at least once while the design
underneath was still broken.
Constraint checkers do not get exceptions. Every
special case letting one object ignore the rules is a defect waiting for a
plausible reason to fire.
When tuning stops paying, derive the bound. Three
rounds of increasingly clever heuristics all landed within a few balls of
each other, because they were all optimising a quantity that provably does
not vary.
The AutoPhi V19 blueprints — including this interposer, with its
escape coverage and every DRC entry disclosed on the product page —
are at the store. We ship the
design. You build the board.
Copy one of the formats below: