Six Layers, 1,536 Balls: Why the Escape Router Ran Out of Room at Ring 3

Reading Time: 15 minutes
3,014 words

16 min read


13 parts, 59 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.

Update: Doubling the Layers, Confirming the Theory

The invariant said trace surface is where the gain lives, not via load. That prediction was testable, so it got tested. The interposer’s stackup was rebuilt with twelve signal layers instead of six — from twelve total copper to eighteen — and the router ran again against the fresh grid.

Metric 6 signal layers (v1) 12 signal layers (v2)
Total copper layers 12 18
Signal balls per layer, invariant 146.2 73.1
Signal balls per layer, measured 92 / 87 / 86 / 83 / 78 / 80 73 / 73 / 73 / 73 / 73 / 73 / 73 / 73 / 73 / 73 / 73 / 72
Escape routed 506 of 960 (52.7%) 720 of 960 (75.0%)
DRC routing-quality violations 0 0

The measured layer load matched the invariant prediction to a single ball. 877 signal balls that needed routing, twelve layers to spread them across, and A* placed 73 or 72 on each layer with no manual tuning of the load-balancing heuristic. The theorem does not care what the router thinks it is doing.

Escape coverage jumped by 214 balls — a 42% improvement in what actually reaches the BGA. DRC came back clean the first time the re-route finished, once 274 stray traces from the old routing had been swept off physical layer IDs that got renamed to plane layers during the stackup change. Those are the standard hazards of a stackup rewrite, not routing errors.

What the invariant does and does not fix

Layer choice cancels for via congestion (the derivation earlier in this post). Moving from six to twelve signal layers dropped per-layer via keepouts from 1,120 to 1,040 — a 7% improvement, exactly what the algebra predicted, and irrelevant next to the real constraint. The real gain was that trace surface per layer halved. Same 960 signal balls, twelve layers instead of six, means 80 balls of trace traffic per layer instead of 160. Half the trace congestion, same via congestion. The 214 balls of extra coverage came out of that trace headroom.

Cost of the extra layers on a small (94 × 62 mm) HDI substrate: around $300 per piece at typical per-square-inch HDI rates. Not a factor at the substrate’s list price.

The general lesson

The point of deriving the bound was to know which knob to turn. The invariant answered “not layer assignment, not netclass clearance, not routing effort.” That left “more signal layers” as the last remaining knob, and turning it produced exactly the improvement the algebra said it would.

The interposer on the store now ships with the 12-signal-layer stackup and 720/960 routed. The ESCAPE-THEORY.md document that goes with the source bundle is the same document as last week: the invariant does not change — only the choice of N does.

Update Two: 24 Layers, 815 of 960

The N=12 result begged the same question a second time. If doubling signal layers from six to twelve added 214 balls of coverage, what does going from twelve to eighteen do? The invariant already predicted the answer: less. Trace load per layer scales as 1/N, so each doubling helps by a smaller fraction than the last. Twelve to eighteen is not a doubling — it is a 1.5× — so the gain should be smaller still.

Ran the experiment: 24-layer stackup, 18 signal layers between four planes, same router, same lessons.

Metric 6 signal (v1) 12 signal (v2) 18 signal (v3)
Total copper layers 12 18 24
Balls per layer, invariant 146.2 73.1 53.1
Balls per layer, measured 92/87/86/83/78/80 73/73/73/73/73/73/73/73/73/73/73/72 54/54/53×16
Escape routed 506 (52.7%) 720 (75.0%) 815 (84.9%)
Delta from previous +214 balls (+42%) +95 balls (+13%)
DRC routing violations 0 0 0

Third time the layer balance matched the invariant to a single ball. Two of the eighteen layers took 54; the other sixteen took 53. 956 ÷ 18 = 53.11. The two extra balls are the round-off.

Coverage improvement decelerated exactly as predicted. 6 → 12 signal layers bought +42%. 12 → 18 bought +13% on top. Extrapolate the same shape and 24 signal layers would buy another few percent and then flatten as the geometric limit (the 240 pads at the die-BGA grid collision distance) becomes binding rather than trace surface.

Same Design, Three Tiers

Because each stackup change is a fabrication cost knob rather than a design change — same pin map, same die, same escape routing algorithm — the three versions ship as three product tiers on the store. Same substrate design, different HDI process class, different price.

Tier Stackup Escape coverage Fab class Price
Access 12 layers, 6 signal 506 of 960 (52.7%) Standard HDI $400,000
Standard 18 layers, 12 signal 720 of 960 (75.0%) Advanced HDI $760,000
Premium 24 layers, 18 signal 815 of 960 (84.9%) Premium HDI $1,200,000

Every tier ships the same package structure: editable KiCad source with libraries and 3D models, plus a fabrication package with gerbers, drill, IPC-2581, BOM and pick-and-place (CPL). Every tier also ships the same ESCAPE-THEORY.md document, because the invariant does not change — only the choice of N does.

The Access tier makes sense for buyers who can live with 506 signals routed on a lower-cost HDI process. The Standard tier is the middle: current mainstream HDI, 720 signals, the invariant analysis published a week ago. Premium runs at the process class where a single die substrate approaches full-density fan-out on this pad geometry.

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.