Voltage Scaling and Power Domains
Clock gating attacked \alpha. Now for the heavyweight lever in
P = \alpha C V^2 f: the square on
V. Voltage is the only knob that enters quadratically — and since lowering
frequency permits lowering voltage (gates switch slower at lower V,
so a slower clock tolerates it), the two move together for a compounded, roughly cubic win. This was
the engine of
Dennard
scaling while it lasted; now that it no longer comes free with each process node, chips
do it actively, minute by minute — and carve themselves into independently powered fiefdoms
to do it well.
DVFS: the V² lever, pulled at runtime
Dynamic voltage-frequency scaling lets the operating system slide the chip along a
table of legal (f, V) operating points. The honest arithmetic, for
halving the clock and dropping the supply from 1.0 V to 0.7 V:
\frac{P_{\text{new}}}{P_{\text{old}}} \;=\; \frac{f/2}{f}\cdot\frac{(0.7V)^2}{V^2}
\;=\; 0.5 \times 0.49 \;\approx\; 0.245 \;\approx\; \tfrac{1}{4}.
Half the speed for a quarter of the power — that trade is why your laptop's fan spins down when you
stop compiling. Note what it does to energy per task: time doubles while power quarters, so
the energy for a fixed job scales as V^2 alone — the frequency cancels.
Lower voltage is (dynamically) always more efficient per unit of work… until leakage, which
flows the whole time the chip is powered, changes the verdict. Run the sweep:
// DVFS sweep: dynamic power falls as f·V², but leakage taxes every second of runtime.
const points = [
{ f: 2.0, V: 1.0 }, // GHz, volts
{ f: 1.5, V: 0.85 },
{ f: 1.0, V: 0.7 },
{ f: 0.5, V: 0.55 },
];
const P_LEAK = 0.3; // W, roughly constant while the domain is powered
// Calibrated so 2 GHz @ 1.0 V burns 2 W of dynamic power; task = 1e9 cycles.
const pDyn = (f: number, V: number) => f * V * V;
console.log("f(GHz) V(V) Pdyn(W) time(s) energy(J)");
let bestE = Infinity, bestF = 0;
for (const p of points) {
const t = 1 / p.f; // 1e9 cycles / (f GHz)
const E = (pDyn(p.f, p.V) + P_LEAK) * t;
console.log(" " + p.f.toFixed(1) + " " + p.V.toFixed(2) + " " +
pDyn(p.f, p.V).toFixed(2) + " " + t.toFixed(2) + " " + E.toFixed(2));
if (E < bestE) { bestE = E; bestF = p.f; }
}
console.log("");
console.log("best energy per task: " + bestF.toFixed(1) + " GHz (" + bestE.toFixed(2) + " J)");
console.log("Crawling is NOT optimal: below the sweet spot, leakage x long runtime");
console.log("dominates - often better to 'race to idle' and power-gate the domain.");
The sweep exposes the real shape of the problem: dynamic energy per task falls with
V^2, but leakage energy grows with runtime, so energy-per-task
has a minimum at a middling operating point. Below it, the winning strategy flips to
race to idle: sprint at an efficient point, finish early, then kill the power
entirely. Which raises the question — how do you kill power to only part of a chip?
Power domains: different voltages, switchable islands
A modern SoC is not one circuit at one voltage — it is a federation of voltage
domains: the CPU sprinting at 0.9 V, slow peripherals ambling at 0.6 V, each block given
just enough voltage for its timing. Two kinds of special cells stitch the federation
together, and a third switches parts of it off:
- Level shifters sit on every wire crossing between voltage domains, translating
one domain's logic levels into the other's. Without one, a 0.6 V "high" arriving at a 0.9 V gate
is neither a clean 0 nor 1 — the receiving inverter half-conducts and burns.
- Isolation cells guard the outputs of any domain that can be switched
off, clamping them to a safe constant so the powered neighbours never stare at a floating
wire.
- Power switches (header/footer transistors between a domain and the supply
rails) implement power gating: open the switch and the domain is truly dark —
unlike clock gating, which stops dynamic power but leaves every transistor leaking, power gating
kills leakage too. The price: all state inside evaporates, so anything worth keeping goes
into retention registers (special flops with a tiny always-on shadow latch) or
out to memory first.
Powering down is therefore a ceremony, run by a small always-on power-controller FSM, and
the order is everything: isolate → save → switch off, and on wake-up the mirror
image, switch on → restore → de-isolate. Step through it on the floorplan:
Power intent, and one more voltage trick
Notice that none of this — domains, shifters, isolation, retention — appears in your RTL, which
still describes pure logic. The partitioning lives in a separate power-intent
specification (UPF, or the older CPF): a file declaring the domains, their supply
nets, where isolation and retention are required, and the legal power states. Every tool in the flow
reads it — synthesis inserts the special cells, verification simulates domains actually losing state
(catching the missing-retention bug before silicon), and the back-end wires the switch networks. One
spec, honoured everywhere: the same "say what you mean, let the tools enforce it" pattern as clock
gating, scaled up to the whole chip.
A final, finer-grained voltage lever: libraries ship each cell in several threshold-voltage
(Vt) flavours. Low-Vt cells switch fast but leak hard;
high-Vt cells are slow and thrifty. The tools mix them: low-Vt only on
the critical paths that need the speed, high-Vt everywhere else — buying back the
vast majority of leakage for zero performance cost.
- DVFS: lower f permits lower
V; power falls roughly cubically
(0.5f, 0.7V \Rightarrow \approx \tfrac14 P);
dynamic energy per task scales as V^2, but leakage favours
race-to-idle;
- voltage domains give each block its own supply, with level
shifters at every crossing;
- power gating switches domains off entirely, killing leakage — requires
isolation cells, retention registers, and the ordered ceremony
isolate → save → off, on → restore → de-isolate;
- UPF/CPF captures the power intent as a separate spec the whole flow
honours;
- multi-Vt mixing: low-Vt (fast, leaky) on critical paths
only.
Hundreds — and enumerating them is itself an engineering discipline. A flagship mobile SoC has
dozens of switchable domains (per-core, per-cluster, GPU slices, media blocks, modem pieces), each
with several DVFS points, plus retention-versus-full-off variants for the sleeping ones. The legal
combinations form a state space the power-controller firmware walks all day: your phone crosses
power states thousands of times per second, mostly for milliseconds at a time, and a misordered
transition in even one obscure corner (de-isolating before the supply is stable, say) becomes the
kind of once-a-week freeze that no software patch can fully hide. This is why UPF-aware verification
teams simulate power-state machines, not just logic — and why "low-power methodology
engineer" is a job title with excellent job security.
Open a domain's power switch without isolation cells and its output wires do not politely go to 0 —
they float, drifting toward mid-rail voltages. Every powered gate listening to them
now has an input that is neither 0 nor 1: its pull-up and pull-down networks both half-conduct,
burning crowbar current continuously, while its output flickers with noise —
garbage values marching into live logic. The failure is beautifully perverse: you switched a block
off to save power, and the chip now burns more, while corrupting the blocks that
are still alive. Every switchable domain's outputs must be clamped by isolation cells before
the switch opens — which is exactly why the sequence isolate → save → gate-off is enforced by an FSM
in hardware, not left to polite software convention.