4.1.5Computer Architecture (Deep)

Registers — general purpose, special (PC, SP, LR, CPSR)

2,529 words11 min readdifficulty · medium

WHY do registers exist at all?

WHAT is a register, precisely?

HOW many bits? A register holding WW bits can store 2W2^W distinct values.

  • 32-bit register → 2324.29×1092^{32} \approx 4.29\times10^9 values.
  • 64-bit register → 2641.84×10192^{64} \approx 1.84\times10^{19} values.

The two families

1. General-Purpose Registers (GPRs)

WHY general? Flexibility — the compiler decides what each holds, so it can keep your hottest variables in registers (this is register allocation).

2. Special-Purpose Registers

These have hardware-defined meaning. The CPU itself reads/updates them.

Reg Name What it holds Why it's special
PC Program Counter address of the next instruction to fetch Hardware auto-increments it every fetch; branches overwrite it
SP Stack Pointer address of the top of the stack Hardware (push/pop, call/ret) bumps it
LR Link Register return address of a function call BL writes it so the callee knows where to go back
CPSR Current Program Status Register condition flags + mode bits ALU sets flags; branches read them
Figure — Registers — general purpose, special (PC, SP, LR, CPSR)

PC — the Program Counter (deriving the fetch loop)

Deriving the increment from first principles. Suppose instructions are fixed width LL bytes (ARM: L=4L=4). After fetching the instruction at address PCPC, the default next instruction sits at: PCnext=PC+LPC_{\text{next}} = PC + L The hardware performs this before executing the current instruction, so by the time the instruction runs, PC already points to the following one. This is why on classic ARM PC reads as current + 8 (pipeline: fetch is two stages ahead) — a famous gotcha.

A branch to target TT simply does PCTPC \leftarrow T. A relative branch with signed offset oo (in instructions) computes: PCPCref+LoPC \leftarrow PC_{\text{ref}} + L\cdot o


SP — the Stack Pointer (deriving push/pop)

Most CPUs use a full-descending stack: the stack grows toward lower addresses, and SP points to the last item pushed (the occupied top).

Derive PUSH of value vv (full-descending, word = 4 bytes):

  1. Make room by moving the top down: SPSP4SP \leftarrow SP - 4. Why first? So we don't overwrite the current top item.
  2. Store: Mem[SP]v\text{Mem}[SP] \leftarrow v.

Derive POP into register rr:

  1. Read current top: rMem[SP]r \leftarrow \text{Mem}[SP].
  2. Free the slot: SPSP+4SP \leftarrow SP + 4. Why after? The data must be read before we declare the slot free.

A function call BL target (Branch with Link) does two things atomically: LRPCnextPCtargetLR \leftarrow PC_{\text{next}} \qquad PC \leftarrow target Why save PC_next not PC? Because we want to resume at the instruction after the call, not re-run the call (infinite loop!).

To return: BX LR does PCLRPC \leftarrow LR.


CPSR — the flags (deriving conditional branches)

WHY do flags exist? Branches need to ask "was the result zero? negative?" without re-computing. The compare instruction CMP a, b computes aba-b, throws away the result, but keeps the flags. Then BEQ (branch if equal) just tests ZZ.

Derive BEQ after CMP a,b:

  • CMP computes aba-b. If a=ba=b then ab=0a-b=0Z=1Z=1.
  • BEQ branches iff Z=1Z=1 → branches iff a=ba=b. ✔ first-principles correct.

Deriving V (signed overflow) from first principles. For addition r=a+br = a+b with nn-bit signed numbers, signed overflow occurs iff both operands share a sign but the result has the opposite sign: V=(signa=signb)  (signrsigna)V = (\text{sign}_a = \text{sign}_b)\ \wedge\ (\text{sign}_r \ne \text{sign}_a) Why? Two positives can't legitimately sum to a negative within range; if the bit pattern says they did, the true sum overflowed the representable range [2n1,2n11][-2^{n-1},\,2^{n-1}-1].


Recall Feynman: explain to a 12-year-old (click to reveal)

The CPU is a super-fast cook. Registers are the few bowls right next to the chopping board — the cook grabs ingredients from them instantly. RAM is the big fridge across the kitchen: lots of room, but slow to walk to. A few bowls are special: one bowl (PC) holds a sticky note saying "next step number." Another (SP) marks the top of a stack of dirty plates. Another (LR) is a note saying "after this errand, come back here." And CPSR is a little scoreboard: was the last result zero? negative? did it spill over the edge? The cook checks that scoreboard to decide whether to skip ahead in the recipe.


Common mistakes


Flashcards

Why are registers faster than RAM?
They are physically on the CPU die, wired directly to the ALU; no off-chip memory bus latency (~1 cycle vs ~100+ cycles).
What distinguishes a general-purpose register from a special one?
A GPR has no hardware-imposed meaning (compiler chooses its use); a special register (PC/SP/LR/CPSR) has a fixed role the hardware itself reads/updates.
What does the PC hold and how does it change each cycle?
The address of the next instruction; hardware does PCPC+LPC \leftarrow PC + L (LL=instruction length) each fetch, and branches overwrite it with the target.
In a full-descending stack, what does PUSH do?
SPSP4SP \leftarrow SP-4 then Mem[SP]v\text{Mem}[SP]\leftarrow v (decrement first, then store).
In a full-descending stack, what does POP do?
rMem[SP]r\leftarrow \text{Mem}[SP] then SPSP+4SP\leftarrow SP+4 (read first, then free).
What two actions does BL target perform?
LRPCnextLR \leftarrow PC_{next} (save return address) and PCtargetPC \leftarrow target (jump).
Why must a non-leaf function save LR?
A nested BL overwrites LR, destroying the caller's return address; saving LR on the stack allows unlimited nesting.
What are the four CPSR condition flags?
N (negative, MSB=1), Z (zero result), C (carry/borrow, unsigned), V (signed overflow).
Give the rule for the V (signed overflow) flag on addition.
V=1 iff both operands have the same sign but the result has the opposite sign.
After CMP a, b, which flag does BEQ test and why?
It tests Z; CMP computes aba-b, so Z=1Z=1 exactly when a=ba=b.
For 8-bit signed 0x7F + 0x01, what are N,Z,C,V?
N=1, Z=0, C=0, V=1 (127+1 overflows signed range to −128).
On ARM, which instructions update the flags?
Only S-suffixed ops (ADDS, SUBS, …) and CMP/CMN/TST/TEQ; plain ADD does not.

Connections

Concept Map

motivates

width W stores

splits into

splits into

enables

keeps

includes

includes

includes

includes

auto-increment by L then

sets

read by

overwrite

set by BL for

Speed gap ALU vs RAM

Register tiny CPU cell

2 to the W values

General-Purpose Regs

Special-Purpose Regs

Register allocation

Hottest variables fast

PC next instr address

SP top of stack

LR return address

CPSR flags plus mode

Fetch loop

ALU operations

Branches

Function call return

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Dekho, register ek tiny storage cell hai jo CPU ke andar hota hai — ekdum ALU ke paas. RAM bahut bada hai par door hai (100+ cycles lagte hain ek word laane mein), jabki register se data ek hi cycle mein milta hai. Isliye CPU apna "abhi-ka-kaam" wala data registers mein rakhta hai. General-purpose registers (R0–R12) compiler jaise chahe waise use kar sakta hai — koi fixed matlab nahi. Par kuch special registers ka kaam hardware ne fix kar rakha hai.

Chaar special yaad rakho: PC (Program Counter) — agle instruction ka address; har fetch pe automatic PC = PC + 4 ho jaata hai, aur branch hone pe yeh overwrite ho jaata hai. SP (Stack Pointer) — stack ke top ka address; PUSH karte waqt pehle SP -= 4 phir store, POP mein pehle read phir SP += 4 (full-descending stack, niche ki taraf badhta hai). LR (Link Register) — jab BL function chalta hai to LR mein return address save hota hai taaki kaam khatam hone ke baad BX LR se wapas aa sako.

Sabse important gotcha: agar function A, function B ko call kare, to B ka BL LR ko overwrite kar dega — A ka return address gaya! Isliye non-leaf function ko entry pe PUSH {LR} aur exit pe POP {PC} karna padta hai. Stack unlimited nesting deta hai, LR sirf current frame ke liye fast shortcut hai.

Aur CPSR — yeh ek chhota scoreboard hai jisme N Z C V flags hote hain. ALU har S-suffix operation ke baad inhe set karta hai. CMP a, b actually a - b compute karta hai par result phenk deta hai, sirf flags rakhta hai — phir BEQ Z flag check karke decide karta hai equal the ya nahi. Yaad rakho: plain ADD flags update nahi karta, sirf ADDS karta hai — yeh ek common bug ka source hai.

Go deeper — visual, from zero

Test yourself — Computer Architecture (Deep)

Connections