5.1.6 · D5Instruction Set Architecture (ISA)
Question bank — ARM architecture overview
Before we start, three words we lean on constantly — earn them once so the reveals make sense:
True or false — justify
Every answer must give the reason, not just T/F.
T/F: In ARM, an ADD instruction can read one operand straight from memory.
False. ARM is a load-store architecture: only
LDR/STR touch memory, so ADD operands must already sit in registers. You'd need a separate LDR first.T/F: Fixed 32-bit instruction width means ARM programs are always smaller than x86 programs.
False. Fixed width simplifies decoding, but a simple
MOV r0,#1 still eats a full 32 bits even though it barely needs any — this is exactly why Thumb exists to shrink code.T/F: Conditional execution (ADDGT) removes the branch, so it is always faster than a branch.
False. A skipped conditional instruction still occupies its slot as a NOP (1 cycle). If a branch would have jumped over many instructions, the branch wins; conditional execution only pays off for very short skips.
T/F: ADDGT r1, r1, #1 does nothing to the CPU state when the condition fails.
True (for the result), but subtle. When the condition is false the instruction becomes a NOP — it still occupies a cycle and is fetched/decoded, but no register or flag is written.
T/F: ARMv8 (AArch64) dropped conditional execution because it was a bad idea.
False. It was a good trade for its era; modern out-of-order cores with >95% branch prediction find per-instruction conditions harder to schedule than a well-predicted branch, so removing them simplified the hardware.
T/F: A deeper pipeline (more stages) always makes a processor faster.
False. More stages allow a higher clock, but a mispredicted branch now flushes more stages, so the branch penalty grows — deep pipelines only win when prediction is good and work is streaming.
T/F: The x31 register in AArch64 is just "another general register."
False.
x31 is context-dependent: in most instructions it reads as the zero register (always 0, writes ignored), but in stack-relative contexts it is the stack pointer. It is never an ordinary storage register.T/F: The Program Counter is register r15 in both ARMv7 and AArch64.
False. In ARMv7 the PC is
r15 and directly readable/writable. In AArch64 the PC is not a general register — you change it only through branches.T/F: Banked registers mean the FIQ handler runs with more total registers than user code.
False. It has the same register names but private physical copies of some (e.g. r8–r12), so the handler needn't save/restore them — faster entry, not more registers.
Spot the error
Each snippet or claim has one flaw. Name it.
Error? LDR r0, [r1] then immediately ADD r2, r0, #5 on a simple ARM7.
Data hazard. The load result for
r0 isn't ready when ADD wants it, so the pipeline must stall (or forward) one cycle — the ADD reads a stale/not-yet-loaded value otherwise.Error? "Thumb code is faster because 16-bit instructions execute in half the cycles."
Wrong reason. Thumb instructions don't execute faster per-op; they win by making code smaller, which raises the instruction-cache hit rate and cuts fetch energy.
Error? "In Thumb you can freely use all 16 registers just like in ARM."
Wrong. Base Thumb has 3-bit register fields, so most instructions reach only r0–r7. Full register access needs 32-bit (Thumb-2 or ARM) encodings.
Error? "ADD [mem], reg is a normal ARM instruction."
Not ARM. That memory-destination arithmetic is an x86 style (5.1.10-x86-architecture); ARM forbids it because of the load-store rule.
Error? "16 registers were chosen because programmers rarely need more."
Wrong driver. The choice is an encoding trade-off: fits a register in 4 bits, leaving room in the fixed 32-bit word — not a claim about programmer need.
Error? "The condition field lives in bits 24–21 of a data-processing instruction."
Wrong bits. The condition code is bits 31–28; bits 24–21 hold the opcode. Mixing them up breaks the whole point of parallel decode.
Error? "Because ARM is RISC, every instruction always finishes in exactly one cycle."
Overstated. RISC aims for simple, predictable timing, but loads, stores, and multi-cycle ops take more than one cycle — "one cycle each" is an idealization.
Why questions
Answer the reason, not the fact.
Why does a load-store design help power, not just speed?
Memory I/O costs roughly 10–100× the energy of a register op, so keeping data in registers between memory touches directly cuts energy/instruction — relevant to 7.1.05-power-optimization.
Why can ARM decode the condition and the opcode at the same time?
Because fields sit at fixed bit positions in every 32-bit instruction, separate hardware blocks can read bits 31–28 and 24–21 in parallel — no need to first learn the length like x86's serial decode (5.1.07-ARM-instruction-encoding).
Why is fixed-width instruction fetch so simple?
Every instruction is exactly 4 bytes, so "next instruction" is just — no variable-length parsing to find where one instruction ends and the next begins.
Why does conditional execution complicate out-of-order cores?
An instruction with a condition doesn't know whether it will actually commit until its flags resolve late in the pipeline, which makes scheduling and speculation harder than a cleanly predicted branch (5.2.03-pipelining).
Why did the original ARM7 use only a 3-stage pipeline?
Fewer stages give lower per-instruction latency and a tiny branch penalty, which suits real-time embedded systems where predictable, short response beats peak clock speed.
Why does a smaller code footprint indirectly raise speed?
More instructions fit in the instruction cache, so fewer fetches reach slow DRAM — cache hits are fast and cheap, DRAM fetches are slow and power-hungry.
Why does ARM's licensing model produce such varied chips (Apple M-series, AWS Graviton)?
ARM licenses the architecture/IP rather than selling finished chips, so each vendor fabricates and tunes a design for its exact workload instead of using one fixed part.
Edge cases
The scenarios the rules almost forget.
What happens to MOVLE r2, #0 when the compared value made "Less-or-Equal" false?
It becomes a NOP — fetched and decoded, consuming one cycle, but writing nothing to
r2 and touching no flags.CMP uses subtraction internally but never writes a result — where does its "output" go?
Into the condition flags (N, Z, C, V in CPSR/PSTATE).
CMP exists purely to set flags for a following conditional instruction; the numeric difference is discarded.If a branch's prediction accuracy were 0% (always wrong), which style wins — branches or conditional execution?
Conditional execution, decisively — every branch would flush the pipeline, whereas conditionals only ever cost their 1-cycle NOP, so the plausible-mispredict math flips entirely in their favor.
What does writing to the AArch64 zero register actually do?
Nothing — writes are silently discarded, which is handy as a "throw-away" destination when you need an instruction's side effects (like flag setting) but not its result.
In a 3-stage pipeline, how many instructions are "in flight" once it's full, and why does that bound the flush cost?
Three (one per stage), so a mispredicted branch can waste at most a couple of cycles — the flush cost is bounded by pipeline depth, which is exactly why deep modern pipelines hurt more on a miss.
Can a Thumb MOVS instruction leave the condition flags unchanged?
No by design — the trailing
S means it updates flags; base Thumb data-processing ops set flags automatically (a difference from ARM, where the S suffix is optional).Recall One-line summary of the traps
Load-store confusion, "fixed-width = smaller code", "conditional always beats branch", zero-register/PC-register special cases, and deeper-pipeline-is-always-faster are the five ideas that catch almost everyone.