Track Assignment
Global routing tells you a net will cross from GCell (4,7) to GCell (5,7) on met2, a neighbourhood-level answer. But met2 does not have neighbourhoods. It has tracks: a comb of parallel, fixed-pitch lines that the layer’s manufacturing rules and the standard cell grid dictate down to fractions of a micron. A wire on met2 does not get to sit roughly around x = 12.3 um. It sits on a track, at whatever exact coordinate that track occupies, or it is not legal metal. Track assignment takes global routing’s coarse answer and pins it to one of those real tracks, layer by layer, before detailed routing draws the geometry.
Why this needs its own step
You might reasonably ask why global routing does not pick tracks directly, or why detailed routing does not work straight off GCells. Each of the three steps solves a problem at a different resolution, and mixing resolutions makes all of them slower and worse. Global routing needs to reason about the whole design cheaply, so it deliberately ignores tracks. Detailed routing needs to guarantee exact legality, so it cannot also be deciding rough net topology across the whole chip; that search space is too large to do both at once. Track assignment is the practical middle step. For each net, on each layer its global route touches, pick a specific track consistent with the tracks its neighbours are being assigned, so detailed routing inherits an assignment that is already close to legal rather than starting from a blank GCell.
Computing a track index
Every layer’s tracks are defined by two numbers: a pitch, the spacing between adjacent tracks, and an offset, where the first track sits relative to the layer’s origin. Given a rough coordinate from global routing, snapping is straightforward:
$$ \text{track index} = \left\lfloor \frac{x - \text{offset}}{\text{pitch}} + 0.5 \right\rfloor $$
which is “round to the nearest whole number of pitches past the offset”. The track’s real coordinate is then offset plus index times pitch. Every OpenROAD run reads a real per-layer track definition, from the technology LEF, that states exactly this pitch and offset for every routing layer. Track assignment does not guess. The numbers below stand in for that real data so you can see the arithmetic, not to state SKY130’s manufactured pitch as fact.
Suppose a layer’s tracks have pitch 0.46 um with the first track offset 0.23 um from the origin. Global routing puts a net’s rough crossing at x = 12.30 um.
$$ \text{track index} = \left\lfloor \frac{12.30 - 0.23}{0.46} + 0.5 \right\rfloor = \left\lfloor 26.24 + 0.5 \right\rfloor = 26 $$
Track 26 sits at 0.23 + 26 x 0.46 = 12.19 um. The net moves about 0.11 um from its rough guess, small on the scale of the design, but exactly the kind of shift that, multiplied across thousands of nets converging in one region, can turn a GCell that looked fine during global routing into one where two assigned tracks collide.
Track assignment is where global routing’s optimism meets reality in miniature, before detailed routing meets it in full. A GCell edge with enough coarse capacity can still produce a local pile-up once every net inside it is forced onto discrete tracks. If detailed routing keeps failing in the same tight spot even after you have dealt with GCell-level congestion, look at track-level crowding there next.
Practice Exercise
Two nets on the same layer have rough coordinates x = 5.00 um and x = 5.20 um. The layer’s pitch is 0.34 um with offset 0.17 um. Compute each net’s track index. Do they land on the same track, and if they had, what would have to happen before both could exist as legal metal?
Solution
Net 1: floor((5.00 - 0.17) / 0.34 + 0.5) = floor(14.21 + 0.5) = 14. Net 2: floor((5.20 - 0.17) / 0.34 + 0.5) = floor(14.79 + 0.5) = 15.
Adjacent tracks, 14 and 15, not the same one. Close, but legal. Had a third net also rounded to track 14, that would be a real conflict: two nets cannot occupy the same track segment on the same layer at the same place. Track assignment would have to push one to a different track, or, if none was free, a different layer, before handing off, or TritonRoute would immediately report a conflict at that location.
With nets pinned to real tracks, it is time to see what actually draws the wires: TritonRoute, and the design rules it has to satisfy that global routing and track assignment never checked.