Registers — general purpose, special (PC, SP, LR, CPSR)
WHY do registers exist at all?
WHAT is a register, precisely?
HOW many bits? A register holding bits can store distinct values.
- 32-bit register → values.
- 64-bit register → 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 |

PC — the Program Counter (deriving the fetch loop)
Deriving the increment from first principles. Suppose instructions are fixed width bytes (ARM: ). After fetching the instruction at address , the default next instruction sits at:
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 simply does . A relative branch with signed offset (in instructions) computes:
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 (full-descending, word = 4 bytes):
- Make room by moving the top down: . Why first? So we don't overwrite the current top item.
- Store: .
Derive POP into register :
- Read current top: .
- Free the slot: . Why after? The data must be read before we declare the slot free.
LR — the Link Register (deriving call/return)
A function call BL target (Branch with Link) does two things atomically:
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 .
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 , throws away the result, but keeps the flags. Then BEQ (branch if equal) just tests .
Derive BEQ after CMP a,b:
CMPcomputes . If then → .BEQbranches iff → branches iff . ✔ first-principles correct.
Deriving V (signed overflow) from first principles. For addition with -bit signed numbers, signed overflow occurs iff both operands share a sign but the result has the opposite sign: 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 .
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?
What distinguishes a general-purpose register from a special one?
What does the PC hold and how does it change each cycle?
In a full-descending stack, what does PUSH do?
In a full-descending stack, what does POP do?
What two actions does BL target perform?
Why must a non-leaf function save LR?
BL overwrites LR, destroying the caller's return address; saving LR on the stack allows unlimited nesting.What are the four CPSR condition flags?
Give the rule for the V (signed overflow) flag on addition.
After CMP a, b, which flag does BEQ test and why?
For 8-bit signed 0x7F + 0x01, what are N,Z,C,V?
On ARM, which instructions update the flags?
Connections
- Instruction Cycle (Fetch-Decode-Execute) — PC drives the fetch stage.
- The Stack and Function Calls (Calling Conventions) — SP & LR implement call/return frames.
- Pipelining — explains the classic ARM "PC = current + 8" offset.
- Two's Complement Arithmetic — defines how N/C/V flags are computed.
- Addressing Modes — registers as operands vs memory operands.
- Cache Memory Hierarchy — registers are the fastest tier above L1.
Concept Map
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.