The Hardware/Software Contract
An Instruction Set Architecture (ISA) is the contract between hardware and software. It defines the set of instructions a CPU can execute, how operands are specified, the available registers, memory addressing modes, and data types. Any software compiled to an ISA will run on any CPU that implements it, regardless of the microarchitecture underneath.
Instruction encoding
Every machine instruction is encoded as a binary word with two fundamental parts:
- Opcode — identifies the operation (ADD, LOAD, BRANCH, etc.).
- Operands — specify the sources and destination (register numbers, immediate values, memory addresses).
RISC vs CISC
The two dominant design philosophies:
RISC (Reduced Instruction Set Computer):
- Fixed-length instructions (typically 32 bits) — simplifies decoding and pipelining.
- Load-store architecture — only LOAD and STORE access memory; all arithmetic operates on registers.
- Many general-purpose registers (32+) to minimize memory traffic.
- Simple instructions that each execute in roughly one clock cycle.
- Examples: ARM, RISC-V, MIPS.
CISC (Complex Instruction Set Computer):
- Variable-length instructions (x86 instructions range from 1 to 15 bytes).
- Arithmetic instructions can operate directly on memory operands (e.g.,
ADD [mem], reg). - Complex, multi-step instructions (e.g.,
REP MOVSBcopies a block of memory in one instruction). - Fewer registers historically (x86 started with 8 general-purpose registers).
- Examples: x86, x86-64, VAX.
Major ISAs today
- x86 / x86-64 — dominates desktops and servers. Backward compatible to the 8086 (1978). Internally, modern x86 CPUs decode CISC instructions into RISC-like micro-ops for efficient pipelined execution.
- ARM (AArch64) — dominates mobile and is expanding into servers (AWS Graviton, Apple Silicon). Energy-efficient RISC design with conditional execution and a compact Thumb instruction set.
- RISC-V — an open-source ISA from UC Berkeley. Modular design with a minimal base integer set (RV32I/RV64I) plus optional extensions (M for multiply, F/D for floating-point, V for vector). Growing in embedded, academic, and increasingly commercial use.
Addressing modes
How an instruction specifies where its operands come from:
| Mode | Example | Meaning |
|---|---|---|
| Immediate | ADD R1, #5 | Operand is the constant 5 |
| Register | ADD R1, R2 | Operand is the value in R2 |
| Direct | LOAD R1, [0x100] | Operand is at memory address 0x100 |
| Indirect | LOAD R1, [R2] | R2 holds the memory address |
| Indexed | LOAD R1, [R2 + 8] | Base + offset addressing |
The Same Operation, Three ISAs
Adding two registers and storing the result — the same logical operation looks very different across ISAs:
ARM (AArch64):
ADD X2, X0, X1 // X2 = X0 + X1 (fixed 32 bits)
Clean three-operand format. Always 4 bytes. The processor can decode this in a single pipeline stage.
x86-64:
MOV EAX, EDI // EAX = first argument
ADD EAX, ESI // EAX += second argument
x86 ADD is two-operand: it overwrites one source. The encoding varies from 2 to 7+ bytes depending on operand types and prefixes.
RISC-V (RV64I):
add x2, x0, x1 // x2 = x0 + x1 (fixed 32 bits)
Nearly identical to ARM but with 32 integer registers (x0-x31), where x0 is hardwired to zero.
Why this matters in practice: compilers must understand the ISA's constraints. ARM and RISC-V's fixed-width instructions make branch prediction and instruction fetch simpler. x86's variable length means the CPU needs a complex front-end decoder, but gains code density — a single x86 instruction can do the work of 2-3 RISC instructions.