Floorplanning
Before a single one of your million standard cells is placed,
someone has to decide the shape of the world they will live in. That is
floorplanning — the city planning of chip design. How big is the die, and what
aspect ratio? Where do the roads (routing resources) run? Where do the big immovable buildings go?
Which districts talk to which, and should they be neighbours?
It is the highest-leverage step in the entire back-end, and the least automatable. A good floorplan
makes every later stage — placement, clock trees, routing, timing closure — merely difficult. A bad
floorplan makes them impossible, and here is the brutal part: you usually find out weeks
later, when routing fails, and the only fix is to come all the way back and start again.
A bad floorplan cannot be routed out of.
The pieces of a floorplan
- Die size and aspect ratio — the outline itself. Near-square dies are usually
preferred: routing demand spreads evenly in both directions, and packages like them. Sometimes the
package or the pad count dictates otherwise.
- The IO ring — pads and their driver circuits around the periphery: the chip's
only doors to the outside. Pad positions are often frozen early (the package substrate is designed
against them), so they become fixed constraints on everything inside.
- Macros — the big pre-built blocks: SRAMs, PLLs, third-party IP. They are
boulders: rectangles of hundreds of thousands of µm² that the placer cannot bend, split or
shrink, only route around. They get placed first, by hand or semi-automatically.
- The core area — everything inside the IO ring not occupied by macros, striped
into standard-cell rows.
- Power planning — reserving space for the power grid's rings and straps before
logic claims it (the details are a coming lesson).
A floorplan, step by step
Here is the whole discipline in one picture — watch the order: outline, doors, boulders, rows, flow.
Utilization: why you must not fill the box
The core utilization is the fraction of the core area actually covered by
standard cells:
\text{utilization} = \frac{\text{total cell area}}{\text{core area}}.
Targets sit around 70–80%, and the missing 20–30% is not waste — it is
breathing room. Routing needs empty space to drop vias and jog wires; the clock tree will
insert thousands of buffers that do not exist yet; timing fixes will upsize cells; engineering
changes will add logic late. Push utilization to 95% and placement still succeeds — then routing
jams, like a city that paved over every park and wonders why traffic cannot move. Dense regions also
concentrate power draw, which the power grid must survive.
Two macros placed close together create a channel — a corridor whose width caps how
many wires can cross between them (width ÷ track pitch = tracks). Too narrow a channel is a routing
dam. The alternative is abutment: push the macros flush against each other and
route around the pair entirely — a deliberate choice that no wires shall cross there.
Try it: utilization and a greedy macro placer
Floorplanning tools score candidate macro positions by (among much else) the total wirelength implied
by how strongly each macro talks to its neighbours. Here is a toy version: a utilization check, then
a greedy placer that drops three macros onto a grid, each minimising connectivity-weighted Manhattan
wirelength to what is already placed:
// ── Utilization check ──
const coreArea = 4.0; // mm²
const cellArea = 3.1; // mm² of standard cells
const util = (cellArea / coreArea) * 100;
console.log(`Utilization: ${util.toFixed(0)}% ` +
(util > 85 ? "→ routing will jam!" : "→ healthy, room to route"));
// ── Greedy macro placement on a 10×10 grid ──
// The IO sits at (0,5). Weights = how much traffic each pair exchanges.
interface Macro { name: string; wires: [string, number][]; }
const placed: { [name: string]: [number, number] } = { IO: [0, 5] };
const macros: Macro[] = [
{ name: "CPU", wires: [["IO", 2]] },
{ name: "RAM0", wires: [["CPU", 8]] }, // talks heavily to CPU
{ name: "DMA", wires: [["IO", 5], ["RAM0", 3]] },
];
const dist = (a: [number, number], b: [number, number]) =>
Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]);
for (const m of macros) {
let best: [number, number] = [0, 0];
let bestCost = Infinity;
for (let x = 0; x < 10; x++) {
for (let y = 0; y < 10; y++) {
const spot: [number, number] = [x, y];
if (Object.values(placed).some((p) => dist(p, spot) === 0)) continue;
let cost = 0;
for (const [other, w] of m.wires) cost += w * dist(placed[other], spot);
if (cost < bestCost) { bestCost = cost; best = spot; }
}
}
placed[m.name] = best;
console.log(`${m.name.padEnd(4)} → (${best[0]},${best[1]}) weighted wirelength ${bestCost}`);
}
console.log("Heavy talkers end up adjacent — that is the whole game.");
Real floorplanners search far more cleverly (and juggle timing, power and routability at once), but
the objective survives intact: blocks that talk a lot go near each other. The IO
logic hugs its pads; a cache hugs its CPU; and the wire bill falls before routing even begins.
- the floorplan fixes the die outline, IO ring, macro positions and core rows
before any cell is placed;
- macros go first — they are immovable boulders that everything else must route
around, best pushed to edges and corners with pins facing the logic;
- target utilization ≈ 70–80%: the empty fraction is routing, clock-tree and
fix-up breathing room, not waste;
- place communicating blocks near each other — pin positions and data flow set
the wirelength bill for the whole design;
- every downstream stage inherits the floorplan's mistakes: you cannot route your way
out of a bad one.
If routing is jammed and utilization is high, surely the fix is a few more square millimetres of
silicon? Sometimes yes — and it is one of the most expensive sentences a designer can utter. Die cost
rises faster than area: you get fewer dice per wafer, and a larger die is more
likely to catch a killer defect, so yield falls too — a double penalty that a
later
lesson quantifies with a merciless exponential. At volume, one square millimetre can be
worth millions of dollars a year. This is why floorplanning is a negotiation: the physical designer
wants space, the product manager wants the die small, and the floorplan is the treaty they sign.
The classic rookie floorplan puts a big SRAM macro dead centre — it looks tidy, like a courtyard
building. It is a disaster. Routing flows across the core like a river system, and a central macro is
a dam: every east–west and north–south net in its shadow must detour around it,
piling congestion onto the corridors along its edges. The standard discipline is the opposite:
macros go to the edges and corners, backs against the wall, pins facing
inward toward the logic that uses them — keeping the centre of the core an open, routable
sea. (Like most rules it can be broken knowingly — but never accidentally.)