R0KernelPath
module 003 / 262

From Transistors to Gates (CMOS)

Every CPU is billions of tiny switches — here is how electrons, silicon, and geometry conspire to compute anything.

~12h focused study11 concepts

Overview

Before a single line of C, before a system call, before a kernel, there is silicon. A modern CPU is a slab of crystalline silicon about the size of a fingernail, etched with ten billion or more transistors — each one a switch no wider than a few dozen atoms. Understanding how those switches are built and wired is not merely trivia; it is the foundation that explains why computers behave the way they do, why clock speeds stopped climbing around 2004, and why modern chips now scale outward (more cores) instead of upward (faster clocks).

This module traces the full path from physics to logic. We start at the transistor: a three-terminal device that uses a small voltage to control a large current, just like a water valve controls a pipe. We look specifically at the MOSFET — the Metal-Oxide-Semiconductor Field-Effect Transistor — which is the workhorse of every digital chip made in the last forty years. We then see how two flavors of MOSFET, the NMOS and PMOS, are paired in "complementary" (CMOS) circuits to build NOT and NAND gates with astonishing energy efficiency.

From gates we zoom out: thousands of gates form an adder, an adder is part of the ALU, the ALU is one sub-block of a core, and a chip might hold dozens of cores — all realized by the same lithographic printing process that is shrinking transistors toward the physical limits of matter. We close with Moore's Law, Dennard Scaling, and what "process node" means today — knowledge that is essential for understanding every architectural decision in modern CPUs and in the Linux kernel scheduler, power management, and NUMA topology code.

why this matters for the kernel

Linux kernel developers regularly encounter hardware limits that are direct consequences of the physics covered here. The kernel's cpufreq and cpuidle subsystems exist because Dennard Scaling ended — chips can no longer run every transistor at full speed without melting. The kernel's topology-awareness (NUMA, big.LITTLE, P-core/E-core scheduling) exists because process node economics pushed heterogeneous designs. Cache coherence protocols exist because wires across a die are slower than logic. When you read a commit that adds an mwait hint or adjusts a scheduler weight for "efficiency cores," you are reading the software response to the physics you learn here.

More concretely: understanding CMOS explains why a write to an I/O-mapped register has latency, why speculative execution is possible (gates are deterministic and stateless once set), and why low-level performance tuning is about reducing the number of slow operations rather than just algorithmic complexity. A kernel contributor who understands transistors thinks more clearly about cache lines, memory ordering, and power-aware scheduling than one who treats hardware as a black box.

CMOS Inverter and NAND2 Gate Construction

rendering diagram…

Left: the CMOS inverter — one PMOS pull-up and one NMOS pull-down, never both conducting in steady state. Right: NAND2 — PMOS in parallel (either can pull up) and NMOS in series (both must conduct to pull down). This dual-network pattern is the template for every static CMOS gate.

The concepts

01Semiconductors and Doping: The Raw Material

Silicon sits in the middle of the periodic table — it has four valence electrons, so in a perfect crystal it forms four covalent bonds, leaving no free electrons to carry current. Pure silicon is almost an insulator. The trick that makes it useful is doping: deliberately adding tiny amounts of impurity atoms.

N-type doping: add phosphorus (5 valence electrons). The extra electron is weakly bound and becomes a free carrier. The material conducts via electrons (negative).

P-type doping: add boron (3 valence electrons). Each boron atom creates a hole — an absence of an electron that acts like a positive charge carrier moving through the lattice.

The doping concentration is extremely precise, typically 1 in 10^8 atoms, controlled by ion implantation during manufacturing. Everything else in CMOS — junctions, gates, channels — is built by arranging regions of N-type and P-type silicon in specific patterns.

An analogy: think of the crystal lattice as a parking lot. N-type doping adds extra cars (electrons) that can drive around; P-type removes cars and creates empty spaces (holes) that move whenever a neighboring car slides in.

02The MOSFET: A Voltage-Controlled Switch

The Metal-Oxide-Semiconductor Field-Effect Transistor (MOSFET) has four terminals: Gate (G), Drain (D), Source (S), and Body (B). Understanding each:

  • Source and Drain are heavily doped regions of the same type (both N+ in an NMOS, both P+ in a PMOS). They are the two ends of the switch.
  • Gate is a conductor (historically metal, now polysilicon or metal compounds) sitting above the channel region, separated by an insulating layer of silicon dioxide (SiO₂) only a few atomic layers thick.
  • Body is the bulk semiconductor substrate.

How it switches (NMOS case):

  1. The gate and the substrate form a capacitor. Applying a positive voltage V_GS to the gate deposits positive charge on the gate plate.
  2. By electrostatic induction, this repels holes from the P-type substrate beneath the gate and attracts electrons, forming a thin inversion layer of free electrons — the channel.
  3. With the channel present, electrons can flow from source to drain: the switch is ON.
  4. When V_GS drops below the threshold voltage V_th (typically 0.3–0.7 V), the channel vanishes: the switch is OFF.

The gate draws essentially zero DC current because of the oxide insulator — that is why MOSFETs are fantastically energy-efficient in digital logic compared to older bipolar transistors. The gate does have capacitance though, and charging/discharging that capacitance every clock cycle is where most of the dynamic power goes.

PMOS is the complement: it uses P-type source and drain in an N-type body, and turns ON when the gate is pulled LOW (V_GS is sufficiently negative). PMOS carriers (holes) are ~2.5× slower than NMOS electrons, so PMOS transistors are often made wider to balance drive strength.

03CMOS NOT Gate (Inverter): The Simplest Complete Circuit

CMOS stands for Complementary MOS — every function uses a pull-up network of PMOS transistors (connected to V_DD, the positive supply) and a pull-down network of NMOS transistors (connected to GND). They are wired so exactly one network conducts at a time, making the output either firmly HIGH (V_DD) or firmly LOW (GND). No DC current flows in steady state — current only flows briefly during the transition.

Inverter (NOT gate) construction:

       V_DD
        |
       [PMOS]  ← gate = IN
        |
        +------ OUT
        |
       [NMOS]  ← gate = IN
        |
       GND
  • When IN = HIGH (V_DD): NMOS turns ON (N-channel forms), PMOS turns OFF (V_GS = 0, no P-channel). OUT is pulled to GND → LOW.
  • When IN = LOW (GND): NMOS turns OFF, PMOS turns ON (V_GS = V_GS_pmos is negative enough to open P-channel). OUT is pulled to V_DD → HIGH.

This is exactly Boolean NOT: output is the complement of the input. The critical insight is that the PMOS and NMOS are never both fully ON simultaneously (during the brief transition they briefly overlap, causing a small current spike — this is "shoot-through" current and a key concern at high frequencies).

The inverter is the atomic building block. Every other CMOS gate is an extension of this pull-up/pull-down dual-network pattern.

04CMOS NAND Gate: Parallel Pull-Up, Series Pull-Down

NAND (Not-AND) is the most important gate in digital design: you can build any Boolean function from NAND gates alone (it is logically complete). Here is how two-input NAND is realized in CMOS.

NAND2 construction:

  • Pull-UP network: two PMOS in parallel, gates driven by inputs A and B respectively, common drain to OUT.
  • Pull-DOWN network: two NMOS in series (stacked), gates driven by A and B, top drain to OUT, bottom source to GND.

Truth table reasoning:

  • A=0, B=0 → both PMOS ON (A=0 turns P1 on, B=0 turns P2 on), both NMOS OFF → OUT = HIGH ✓
  • A=1, B=0 → P1 OFF, P2 ON (B=0 turns it on), NMOS series chain broken (N1 ON, N2 OFF) → OUT = HIGH ✓
  • A=0, B=1 → P1 ON, P2 OFF, NMOS chain broken → OUT = HIGH ✓
  • A=1, B=1 → both PMOS OFF, both NMOS ON → OUT = LOW ✓ (NAND: only LOW when both inputs are HIGH)

The duality principle makes this systematic: the PMOS pull-up network is always the Boolean dual of the NMOS pull-down network. Series → AND; Parallel → OR. For a NOR gate, the NMOS would be in parallel and PMOS in series.

The series NMOS stack does have a cost: stacked transistors have higher resistance than a single transistor, so NAND is slower than an inverter on the pull-down path. This is why gate sizing (making transistors wider to lower resistance) is a major concern in physical design.

Almost every complex Boolean function in a CPU (adder carry chains, multiplexers, flip-flops) decomposes into trees of NAND and NOR gates, each realized by this same CMOS pattern.

05From Gates to Functional Blocks: Adders, Flip-Flops, Memory

Gates are stateless combinational logic — their output depends only on current inputs. To build anything useful we also need state (memory). The two primitives that appear in every CPU are:

1. The D Flip-Flop (register bit): Built from cross-coupled NAND or NOR gates (forming an SR latch) combined with a clock-gating stage. It samples its D input on the rising edge of the clock and holds the value until the next edge. A 64-bit register is 64 flip-flops. The CPU's register file, pipeline registers, and cache tag arrays are all flip-flop arrays.

2. The Full Adder: Takes three single-bit inputs (A, B, Cin) and produces Sum and Carry-out.

Sum     = A XOR B XOR Cin
Carry   = (A AND B) OR (Cin AND (A XOR B))

Each XOR, AND, OR decomposes to NAND trees. A 64-bit ripple-carry adder chains 64 full adders, with each carry propagating through ~4 gate delays × 64 stages = 256 gate delays. That is too slow for GHz clocks, which is why real CPUs use carry-lookahead or carry-select adders that compute carries in parallel — a tree structure with O(log n) depth instead of O(n).

From blocks to a CPU: An ALU is a collection of adders, shifters, and logic units behind a multiplexer. An instruction decoder is a NAND tree that maps an opcode bit pattern to control signals. A cache is a large SRAM array (six-transistor cells) with address decoders and sense amplifiers. At 5 nm, a single SRAM bit cell is about 35 nm × 120 nm. The entire CPU ISA is just elaborate Boolean logic built from millions of these patterns.

Crucially, all of this is physically instantiated as a flat 2D (layered) pattern of doped silicon regions and metal interconnect, printed by lithography. There is no 'CPU part' and 'memory part' at the atomic level — it is all the same process, the same atoms, arranged differently.

// A 1-bit full adder in C — maps exactly to the gate-level implementation
// Compile with: gcc -O0 -S fa.c  to see the generated assembly
#include <stdint.h>

typedef struct { uint8_t sum; uint8_t carry; } FAOut;

FAOut full_adder(uint8_t a, uint8_t b, uint8_t cin) {
    FAOut r;
    r.sum   = a ^ b ^ cin;          // two XOR gates
    r.carry = (a & b) | (cin & (a ^ b)); // AND + OR
    return r;
}

// 8-bit ripple-carry adder built from eight full adders
uint16_t ripple_add(uint8_t x, uint8_t y) {
    uint8_t carry = 0, result = 0;
    for (int i = 0; i < 8; i++) {
        FAOut fa = full_adder((x >> i) & 1, (y >> i) & 1, carry);
        result |= (fa.sum << i);
        carry = fa.carry;
    }
    return (uint16_t)result | ((uint16_t)carry << 8);
}

06Lithography and Process Nodes: What '3 nm' Actually Means

A process node (also called a technology node) describes a particular generation of semiconductor manufacturing capability. The number — 7 nm, 5 nm, 3 nm — originally referred to the gate length of the smallest MOSFET on the chip: the distance from source to drain along the channel. Shorter gate = faster transistor + lower power + higher density.

The lithography process: Chip manufacturing is photolithography taken to an extreme. A photomask (a pattern of opaque and transparent regions) is illuminated by extremely short-wavelength light (today: extreme ultraviolet, EUV, at 13.5 nm). The light passes through the mask and exposes a photosensitive polymer (photoresist) on the wafer. Chemical etching removes the exposed regions, leaving behind the intended pattern in silicon. Multiple rounds of deposition, doping, lithography, and etching build up the 3D transistor structure layer by layer. A modern chip has 100+ such layers and takes 3–4 months to fabricate.

Why the numbers are marketing now: Below about 20 nm, the industry stopped using actual measured gate lengths as the node name. The '5 nm' node from TSMC in 2020 had transistors with gate lengths around 12–14 nm. The number is now a competitive benchmark label, roughly tracking transistor density. A useful metric is millions of transistors per mm²: Intel 4 delivers ~100 MTr/mm², TSMC N3 delivers ~170 MTr/mm².

FinFETs and Gate-All-Around: At sub-20 nm, the flat planar MOSFET stops working well — the gate cannot fully control the short channel and current leaks even when the gate is OFF. The solution was the FinFET (Fin Field-Effect Transistor): the channel is a thin vertical fin of silicon, and the gate wraps around three sides. This gives the gate much better electrostatic control. At 3 nm and below, even FinFETs struggle, so TSMC and Samsung are moving to Gate-All-Around (GAA) transistors where the gate encircles a horizontal silicon nanosheet on all four sides.

Each process node (roughly every 2 years historically) delivered: ~0.7× linear scaling → ~0.5× area → ~2× density → ~0.7× delay → ~0.5× power for the same frequency. That is the mathematical backbone of Moore's Law.

# Check what process node your CPU uses (Linux)
# /proc/cpuinfo gives the family/model; cross-reference with Intel/AMD ark databases
grep -m1 'model name' /proc/cpuinfo

# For a more detailed hardware view:
lscpu | grep -E 'Model name|CPU MHz|Thread|Core|Socket'

# On macOS (Apple Silicon is TSMC 3nm / 4nm):
sysctl -n machdep.cpu.brand_string

07Moore's Law: The Empirical Doubling Rule

In 1965, Gordon Moore (co-founder of Intel) observed that the number of components on a single integrated circuit had doubled roughly every year since the first IC was made, and predicted this trend would continue. He revised the doubling period to ~24 months in 1975. This became known as Moore's Law.

Moore's Law is NOT a law of physics. It is an empirical observation — and crucially, an industry commitment. Semiconductor companies organized their R&D roadmaps around it through the International Technology Roadmap for Semiconductors (ITRS). It became a self-fulfilling prophecy: because everyone expected the next node in 2 years, everyone invested to make it happen.

The three gifts of scaling (why it mattered):

  1. Speed: Smaller transistors switch faster (shorter channel, less capacitance).
  2. Power: Smaller transistors need less voltage and have less capacitance → quadratic power reduction.
  3. Cost: More chips per wafer, smaller die for the same function → price per transistor plummets.

Is Moore's Law dead? The density doubling continues (barely), but the cadence has slowed from 2 years to 3–4 years per node. More importantly, the performance-per-watt improvements have slowed drastically, because Dennard Scaling (see next concept) ended. The transistor count on a chip still grows (Apple M4 Ultra: 180 billion transistors), but translating that into proportional single-thread performance no longer happens automatically.

For the Linux kernel, this history is written in the source code: NUMA awareness, power governors, heterogeneous core scheduling, and frequency scaling all exist because the free lunch ended.

// Approximate transistor counts at major milestones (for illustration)
// Intel 4004 (1971):       2,300 transistors
// Intel 8086 (1978):      29,000 transistors
// Intel 486  (1989):   1,200,000 transistors (~1.2M)
// Intel Pentium 4 (2000): 42,000,000 (~42M)
// Intel Core i7 (2010):  1,170,000,000 (~1.17B)
// Apple M1 (2020):      16,000,000,000 (~16B)
// Apple M4 Ultra (2025):180,000,000,000 (~180B)
//
// Each step is roughly a 2x increase every ~2 years — Moore's Law in action.
// You can verify current counts at: en.wikipedia.org/wiki/Transistor_count

08Dennard Scaling: Why Clock Speeds Stopped Rising

In 1974, Robert Dennard and colleagues at IBM derived a beautiful result: if you shrink every MOSFET dimension by a factor k (make it k times smaller), and also reduce the supply voltage by k, then:

  • Transistor density increases by k²
  • Circuit delay decreases by k (switches k times faster)
  • Power per transistor decreases by k²
  • Power per unit area stays constant

This is Dennard Scaling, and for 30 years it was the engine of Moore's Law's performance gains. Every node meant transistors that were smaller, faster, AND cooler — you could clock them faster, pack more in, and the chip ran at the same temperature.

Why it broke (~2005):

  1. Leakage current: As gate oxide thinned to a few nanometers, quantum tunneling caused current to flow through the insulator even when the gate said OFF. This static leakage power does not scale away — it is always dissipating heat regardless of clock frequency.
  2. Threshold voltage floor: You cannot reduce V_th below ~0.2–0.3 V or thermal noise (kT) will cause random transistor switching. So V_DD cannot shrink proportionally to area, breaking the power-constant equation.
  3. Wire resistance: Wires do not scale as favorably as transistors. As wires get thinner, their resistance increases (R = ρL/A), eating into the power and delay budget.

The consequences:

  • After ~2004, clock speeds hit a wall around 3–4 GHz (for mainstream silicon at safe temperatures).
  • Intel's "Terahertz transistor" roadmap was cancelled. The industry pivoted to multi-core: put more cores at moderate frequency instead of one core at blistering frequency.
  • Power density became the primary constraint. The Linux cpufreq framework and intel_pstate driver exist precisely to manage this: they dynamically throttle frequency to stay within a thermal design power (TDP) budget.

Dynamic power formula (essential to know):

P_dynamic = α × C × V_DD² × f

where α = activity factor, C = capacitance, V_DD = supply voltage, f = clock frequency. Reducing voltage by 10% cuts power by ~19% (quadratic). This is why DVFS (Dynamic Voltage and Frequency Scaling) is so powerful — and why schedutil, the Linux CPU frequency governor, tries to choose the lowest frequency that satisfies workload demand.

// Observe DVFS in action on Linux:
// Watch CPU frequency change as you apply and remove load

// Terminal 1: watch frequency
// watch -n0.5 'cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq'

// Terminal 2: stress one core, then release
// stress-ng --cpu 1 --timeout 5s

// The kernel (via schedutil or ondemand governor) ramps frequency up under
// load and backs it down at idle — dynamic power management in action.

// Check available governors:
// cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors

// Check current governor:
// cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

09Propagation Delay and the Clock: Timing the Physical World

Every gate takes a finite amount of time to produce a stable output after its inputs change. This is the propagation delay (t_pd), typically measured from when the input crosses 50% of V_DD to when the output reaches 50% of V_DD.

Propagation delay arises from two physical effects:

  1. Channel formation time: The MOSFET inversion layer must form or dissolve — this depends on carrier mobility and gate-oxide capacitance.
  2. Output node capacitance: The output of a gate drives the input capacitances of fan-out gates plus interconnect capacitance. The gate must charge or discharge this capacitance through the channel resistance. Time constant τ = R_on × C_load.

A combinational logic path chains multiple gates: e.g., a 64-bit adder's carry chain might be 20 gate delays long. The maximum clock frequency is:

f_max = 1 / (t_pd_critical_path + t_setup + t_hold)

where t_setup and t_hold are the flip-flop's timing constraints.

This is the physical meaning of 'GHz': a 3 GHz clock means the slowest combinational path in the CPU completes in under 333 ps. Modern high-performance cores are designed with careful timing closure — every wire, every gate, every metal layer is analyzed to ensure no path violates setup time. The Intel or AMD architecture teams spend enormous effort on this.

Pipeline stages exist precisely to chop long combinational paths into shorter segments, each completable within one clock cycle, with flip-flops storing the intermediate result. A 20-stage pipeline runs at 5× the frequency of a 4-stage pipeline for the same logic — at the cost of branch misprediction latency. The Linux kernel's branch prediction hints (likely()/unlikely()) are a software response to this physical constraint.

// Linux kernel's likely/unlikely macros — a direct consequence of pipeline timing
// These expand to __builtin_expect, hinting the compiler to lay out the
// 'likely' path without a branch-induced pipeline flush.

// From <linux/compiler.h>:
#define likely(x)   __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)

// Example usage in kernel code:
void handle_page_fault(unsigned long addr) {
    if (unlikely(addr == 0)) {  // NULL dereference is rare
        // expensive slow path
        send_sigsegv();
        return;
    }
    // common fast path — CPU's branch predictor keeps this in the pipe
    lookup_pte(addr);
}

10Power Dissipation in CMOS: Static vs Dynamic

There are two fundamental sources of power dissipation in CMOS logic, and understanding both is critical for modern CPU design and kernel power management.

1. Dynamic power is consumed only when transistors switch state:

P_dynamic = α × C × V_DD² × f
  • α (activity factor): what fraction of transistors switch each cycle (0 to 1)
  • C: total switching capacitance (sum of all gate + wire capacitances)
  • V_DD²: voltage squared — hence reducing voltage is extremely effective
  • f: clock frequency

This is the dominant power source when the chip is active. Reducing frequency and voltage together (DVFS) gives cubic power reduction (f goes down, V_DD goes down, and lower f allows lower V_DD).

2. Static (leakage) power flows even when the chip is idle:

P_static = I_leak × V_DD

Leakage comes from sub-threshold conduction (transistors that are 'off' but still let a trickle of current through due to the exponential I-V curve), gate oxide tunneling, and junction leakage. At advanced nodes (below 28 nm), static power can exceed 30–40% of total chip power even when idle. This is why modern CPUs have aggressive power gating: entire core complexes are powered off (V_DD = 0) when idle, not just clock-gated.

Thermal design power (TDP): Intel/AMD specify a TDP in watts that represents the sustained power the cooling system must dissipate. A 125 W TDP CPU can briefly boost to 200+ W (Intel's Turbo Boost) but must average ≤125 W over time. The Linux kernel's intel_rapl driver reads the actual instantaneous power via Model-Specific Registers (MSRs), and powercap exposes this to userspace. Thermal throttling — the CPU reducing its own frequency to avoid overheating — is managed by the Platform Controller Hub and reported via /sys/devices/platform/coretemp.*.

# Read instantaneous CPU package power via RAPL (Intel)
# Requires root; reads from MSR 0x611 via the powercap sysfs interface

# Check if RAPL is available:
ls /sys/class/powercap/

# Read package energy counter (in microjoules, monotonically increasing):
cat /sys/class/powercap/intel-rapl/intel-rapl:0/energy_uj

# Measure ~1 second average power (in Watts):
E1=$(cat /sys/class/powercap/intel-rapl/intel-rapl:0/energy_uj)
sleep 1
E2=$(cat /sys/class/powercap/intel-rapl/intel-rapl:0/energy_uj)
echo "Power: $(( (E2 - E1) / 1000000 )) W (approx)"

11Multi-Core and Heterogeneous Designs: The Post-Dennard Response

When Dennard Scaling ended, the semiconductor industry faced a brutal choice: accept flat single-thread performance, or redesign the chip architecture entirely. The dominant response was multi-core: place multiple processor cores on a single die, each running at a modest frequency within the power budget.

The math works like this: if a single-core chip at 3 GHz uses 90 W, two cores at 2 GHz (enabled by the lower frequency allowing lower voltage) might use 60 W each — 120 W total — but deliver twice the throughput for parallelizable work. For server and HPC workloads (databases, web servers, ML training), this is a great trade. For single-threaded workloads, it is irrelevant.

Heterogeneous designs take this further: instead of homogeneous cores, mix core types optimized for different goals:

  • ARM big.LITTLE / DynamIQ: large "big" cores (high IPC, high power) for burst performance + small "LITTLE" cores (low IPC, low power) for background tasks. Apple's M-series and Qualcomm Snapdragon use this extensively.
  • Intel P-core / E-core: Performance cores (P, wider, out-of-order, hyperthreaded) and Efficiency cores (E, simpler, in-order, grouped in clusters) on the same die.
  • Specialized tiles: GPU tiles, NPU tiles, media encode/decode engines, all on the same package interconnect.

Linux kernel implications:

  • The scheduler must know the topology: which CPUs are hyperthreads of the same core, which cores share an L3 cache, which die is attached to which NUMA node. This is exposed via /sys/devices/system/cpu/cpu*/topology/ and read during boot by the kernel's topology_* functions in arch/x86/kernel/cpu/.
  • The SCHED_ITMT (Intel Turbo Boost Max Technology) and EAS (Energy Aware Scheduling) features in the Linux scheduler explicitly model the asymmetric compute capacity of heterogeneous cores to make correct dispatch decisions.
# Inspect CPU topology on Linux — this reads data the kernel parsed from CPUID
# and ACPI/DT firmware tables at boot time.

# Number of physical cores vs logical CPUs (hyperthreads)
nproc --all                          # total logical CPUs
lscpu | grep -E 'Core|Thread|Socket'

# Per-CPU topology (core_id, die_id, cluster_id)
for cpu in /sys/devices/system/cpu/cpu[0-9]*; do
  core=$(cat $cpu/topology/core_id 2>/dev/null)
  die=$(cat $cpu/topology/die_id 2>/dev/null)
  echo "$(basename $cpu): core=$core die=$die"
done | sort -V

# On a big.LITTLE or P/E-core system, check capacity asymmetry:
cat /sys/devices/system/cpu/cpu*/cpu_capacity 2>/dev/null

Key insights

  • ✦A transistor is a voltage-controlled switch: the gate voltage determines whether current flows from drain to source, with essentially zero gate current in steady state.
  • ✦CMOS efficiency comes from complementarity: PMOS and NMOS are always in opposite states in steady state, so no DC current path exists from V_DD to GND — power is only consumed during switching transitions.
  • ✦Process node numbers below ~20 nm are marketing labels, not gate lengths; the real figure that matters is transistors per mm², which continues to double roughly every 2–3 years.
  • ✦Dennard Scaling ended around 2005 because leakage current and threshold voltage cannot be scaled below thermal noise limits — this is why GHz stopped climbing and core counts exploded instead.
  • ✦Dynamic power scales as V² × f: halving voltage cuts power by 4×, which is why DVFS (Dynamic Voltage and Frequency Scaling) is the most powerful energy-saving lever in a CPU.
  • ✦Every architectural decision in the Linux kernel that touches scheduling, power, or NUMA topology is a software response to the physical constraints of CMOS silicon.
  • ✦The critical path through a combinational circuit determines maximum clock frequency: pipelines exist to subdivide long paths, and every pipeline stage costs branch-misprediction latency.

Common pitfalls

  • ⚠Confusing gate current with channel current: the MOSFET gate draws essentially zero DC current (the oxide is an insulator), but the gate capacitance must be charged and discharged each cycle — this is where dynamic power comes from.
  • ⚠Assuming 'process node = gate length': below 20 nm, node names are competitive labels. A '3 nm' process has transistors whose physical gate length is 12–16 nm. Always check transistor density (MTr/mm²) for meaningful comparisons.
  • ⚠Thinking Moore's Law is a physics law: it is an empirical observation and industry commitment. It has slowed significantly and will eventually stop entirely as we approach atomic dimensions.
  • ⚠Equating multi-core scaling with single-thread speedup: doubling cores doubles throughput only for embarrassingly parallel workloads. Amdahl's Law says serialized sections become the bottleneck — the kernel itself must be largely serialized to be correct.
  • ⚠Confusing static and dynamic power: powering down a clock domain (clock gating) stops dynamic power but does NOT eliminate static leakage. Only power gating (removing V_DD) eliminates leakage.
  • ⚠Ignoring interconnect: at advanced nodes, wire resistance and capacitance often dominate over transistor switching delay. The 'speed of light across a die' limit means a 10 mm × 10 mm die at 4 GHz has light-travel time ~3% of one clock cycle — wires are real constraints.
  • ⚠Misreading TDP as peak power: TDP is a sustained thermal envelope, not a peak cap. Modern CPUs routinely burst well above TDP for short periods (Intel Turbo, AMD Precision Boost), and the kernel's RAPL driver manages this budget.

Practice

  1. 01
    easy

    Build a truth-table verifier in C. Write a function `nand2(int a, int b)` that returns the NAND of its inputs using only bitwise operations (no if/else, no subtraction). Then build `not1`, `and2`, `or2`, `xor2`, and `nor2` using only calls to `nand2`. Verify all truth tables with assertions. This directly mirrors how any logic gate can be realized from NAND gates alone.

  2. 02
    easy

    Implement a 32-bit ripple-carry adder in C using only your `full_adder` function from the module example. Verify it against the built-in `+` operator for 10,000 random pairs of 32-bit unsigned integers. Then measure how many nanoseconds a 32-bit addition takes using `clock_gettime(CLOCK_MONOTONIC)` in a tight loop — compare the ripple version to using `+`. What does the difference tell you about hardware adder optimization?

  3. 03
    medium

    Write a shell script that samples your CPU's current frequency, temperature (via `/sys/class/thermal/`), and package power (via `/sys/class/powercap/intel-rapl/` or equivalent) once per second. Run a CPU-bound workload (`yes > /dev/null &`) and observe how frequency, power, and temperature respond. Kill the workload and observe the governor stepping frequency back down. Write a brief explanation of what Dennard Scaling predicts and how well your real chip matches that prediction.

  4. 04
    hard

    Study the Linux kernel source for CPU topology detection. Clone the kernel source (`git clone --depth=1 https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git`). Find `arch/x86/kernel/cpu/topology.c` and `drivers/base/topology.c`. Identify which function reads the CPUID leaf that reports core ID vs thread ID. Write a two-paragraph explanation of how the kernel converts raw CPUID data into the `/sys/devices/system/cpu/cpu*/topology/` sysfs entries you can read from userspace.

  5. 05
    hard

    Implement a gate-level simulation of a 4-bit ripple-carry adder using only NAND gates. First, derive the NAND-only implementation of a full adder (sum and carry) on paper using Boolean algebra and De Morgan's laws. Then implement each NAND gate as a C function and chain them. Count the total number of NAND gates your implementation uses, and compare to the theoretical minimum. Extend to 8-bit and measure the gate count growth.

Resources

📕Digital Design and Computer Architecture (Harris & Harris)
bookpaidMorgan Kaufmann / Elsevier, by David Harris and Sarah Harris. ARM and RISC-V editions available.

The single best undergraduate text covering exactly this module's content: CMOS circuits, gates, adders, FSMs, and CPU microarchitecture — rigorous but very readable.

📕CMOS VLSI Design (Weste & Harris)
bookpaidPearson / Addison-Wesley, by Neil Weste and David Harris. 4th edition.

The graduate-level deep dive into CMOS circuits, timing, power, and physical design. Chapter 1 covers exactly the transistor physics in this module at expert depth.

✎Transistor count — Wikipedia
articlefree

Comprehensive, well-cited table of transistor counts from 1971 to present — makes Moore's Law visceral.

✎MOSFET — Wikipedia
articlefree

Detailed, accurate treatment of MOSFET physics including the I-V curves, threshold voltage derivation, and FinFET evolution. Good reference alongside the Harris textbook.

🔧Compiler Explorer (godbolt.org)
toolfree

Compile C to x86/ARM/RISC-V assembly in the browser. Essential for seeing how the full adder C code maps to real hardware instructions.

📄Linux kernel CPU topology documentation
docsfree

Official kernel documentation on how CPU topology is exposed via sysfs — directly connects the hardware to the kernel code you will eventually contribute to.

📄Intel RAPL (Running Average Power Limit) — kernel docs
docsfree

Explains how the Linux kernel reads CPU power consumption via MSRs and exposes it through the powercap sysfs interface — the software bridge to the physics in this module.

✎Dennard Scaling — Wikipedia
articlefree

Clear explanation of the original 1974 scaling rules and why they broke down, with links to the original Dennard et al. paper.

✎The Free Lunch Is Over — Herb Sutter
articlefree

The canonical 2005 article explaining to software developers why clock speeds stopped and what multi-core means for programming. Short, prescient, still essential reading.

⚡Nand2Tetris (nand2tetris.org)
interactivefree

Build a complete computer from NAND gates up through assembly, OS, and compiler. Directly hands-on with everything in this module. Highly recommended as a companion project.

Checkpoints — you can now…

  • ✓You can explain why a MOSFET gate draws no DC current yet still dissipates power when switching, and give the formula for dynamic power.
  • ✓You can draw the CMOS inverter and NAND2 gate from memory, label every transistor, and trace the current path for each input combination.
  • ✓You can implement any Boolean function using only NAND gates, starting from first principles and De Morgan's laws.
  • ✓You can explain what a process node number means today (transistor density, not gate length) and why the numbers diverged from physical gate lengths around 2005.
  • ✓You can state Dennard Scaling's four predictions and identify which physical mechanisms caused it to break down around 2005.
  • ✓You can read `/sys/devices/system/cpu/` sysfs entries and explain what each topology file represents in terms of physical silicon layout.
  • ✓You can explain why the Linux kernel has a CPU frequency governor, what DVFS is, and connect it directly to the P ∝ V²f power formula.