Glossary
Every one of the 105 terms this book defines, from 9 chapters — each with an ordinary-words meaning and the precise architectural one, and a link to the section where it is first used. Both meanings are always shown: meeting a term in its formal form alone is what makes this material hard to read in the first place.
- Instructionfirst used in §1.1 →
One order for the CPU, stored as one 32-bit number in memory. The CPU reads it, does what it says, and moves to the next one.
Precisely: A 32-bit word in one of the three MIPS formats (R, I, J); its opcode and sub-fields select an operation, and its register and immediate fields name the operands.
See also: Instruction set architecture (ISA), Word
- Instruction set architecture (ISA)first used in §1.1 →
The list of everything a program may ask the CPU to do: the instructions, the registers, and how memory is named. It is a contract between software and hardware.
Precisely: The programmer-visible definition of a processor family — instruction encodings and semantics, architectural registers, memory model, reset behaviour — independent of any particular implementation.
See also: Instruction, RISC
- RISCfirst used in §1.1 →
A style of instruction set with few, simple, same-size instructions, where only loads and stores touch memory.
Precisely: Reduced Instruction Set Computer: fixed-length encodings, a load/store architecture, and simple operations designed for pipelining; MIPS (1985) and RISC-V (2010) are both RISC designs.
See also: Instruction set architecture (ISA)
- Wordfirst used in §1.1 →
Four bytes together — 32 bits. Every MIPS instruction is one word, and most values are one word.
Precisely: The 32-bit unit of MIPS32: instruction size, register width, and the size `lw`/`sw` move.
See also: Hexadecimal
- Hexadecimalfirst used in §1.1 →
Base-16 writing of a number. One hex digit is exactly four bits, so a 32-bit word is eight hex digits.
Precisely: The `0x…` notation used for words, addresses and masks throughout; digits 0–9 and a–f.
See also: Word
- Registerfirst used in §1.2 →
One of 32 small boxes inside the CPU that each hold a 32-bit value. Instructions work on registers, not directly on memory.
Precisely: One of the 32 general-purpose registers `$0`–`$31`; `$0` reads as zero and ignores writes.
See also: Program counter (PC)
- Program counter (PC)first used in §1.1 →
The address of the instruction the CPU is running right now. After each instruction it moves 4 bytes forward, unless a branch or jump changes it.
Precisely: The architectural PC; not a general register (no instruction names it directly); advanced by 4 per instruction; set by branches, jumps and reset (to 0xBFC00000).
See also: Register, Delay slot
- Memory-mapped I/Ofirst used in §1.2 →
A few special addresses that are not memory. Writing to one prints a character, prints a number, or stops the machine.
Precisely: The test machine's three "doors" at the top of the data region (putchar, putint, exit), read by the simulation harness from the store port; a convention of the reader's project, not of MIPS.
See also: Word
- Immediatefirst used in §1.2 →
A number written inside the instruction itself, so the CPU does not need to fetch it from anywhere.
Precisely: The 16-bit `imm16` field of an I-format instruction (or the 26-bit index of a J-format one), extended to 32 bits by the rule of the instruction — sign-extended for `addiu`, `slti`, loads and stores; zero-extended for `andi`, `ori`, `xori`; shifted for `lui` and branches.
See also: I-format
- Delay slotfirst used in §1.2 →
The instruction right after a branch or jump. On MIPS it always runs, even when the branch is taken.
Precisely: The architecturally defined branch delay slot: the instruction at branch+4 executes before control transfers; the branch target is computed relative to branch+4; `jal` links branch+8.
See also: Branch, Pipeline, Squash, Program counter (PC)
- Opcodefirst used in §1.3 →
The top six bits of a word. They say what kind of instruction it is.
Precisely: Bits 31..26. Opcode 0 (SPECIAL), 1 (REGIMM), 28 (SPECIAL2) and 31 (SPECIAL3) are families whose member is chosen by a second field.
See also: Function code (funct), R-format
- Function code (funct)first used in §1.3 →
The bottom six bits of a register-only instruction. When the opcode is 0, this field picks the operation.
Precisely: Bits 5..0 of an R-format word; e.g. 32 = `add`, 33 = `addu`, 24 = `mult`, 8 = `jr`.
See also: Opcode
- R-formatfirst used in §1.3 →
The layout for instructions that use only registers: opcode, three register numbers, a shift amount, and a function code.
Precisely: `opcode(31..26) rs(25..21) rt(20..16) rd(15..11) sa(10..6) funct(5..0)`; opcode 0 for the SPECIAL family.
- I-formatfirst used in §1.3 →
The layout for instructions that carry a 16-bit number: opcode, two register numbers, and the number.
Precisely: `opcode(31..26) rs(25..21) rt(20..16) imm16(15..0)`; used by arithmetic-with-immediate, loads, stores and branches.
- J-formatfirst used in §1.3 →
The layout for `j` and `jal`: an opcode and one big 26-bit number that says where to jump.
Precisely: `opcode(31..26) index(25..0)`; the target is the top four bits of PC+4 followed by `index << 2`.
- Zero register ($zero)first used in §2.1 →
Register 0. It always holds 0. If an instruction tries to write it, the write is thrown away.
Precisely: `$0`; reads return 0 and writes are discarded by the hardware. Carolyne declares it `const_regs={0: 0}`. `nop`, `move`, `li` and `beqz` are all built on it.
See also: Register, Calling convention (o32 ABI)
- HI and LOfirst used in §2.1 →
Two extra 32-bit registers next to the 32 general ones. A multiply fills both with its 64-bit answer; a divide puts the quotient in LO and the remainder in HI.
Precisely: The multiply/divide accumulator pair; written by `mult`, `multu`, `div`, `divu`, `mthi`, `mtlo`; read only by `mfhi` and `mflo`. Carolyne models them as two one-register classes `hi` and `lo`.
See also: Register, Zero register ($zero)
- Calling convention (o32 ABI)first used in §2.2 →
The agreement between compilers about which register does which job: where arguments go, where a result comes back, which registers a function may overwrite. The CPU does not know about it.
Precisely: The MIPS o32 application binary interface (ABI): `$a0`–`$a3` arguments, `$v0`–`$v1` results, `$t0`–`$t9` caller-saved, `$s0`–`$s7` callee-saved, `$sp`/`$fp`/`$gp`/`$ra` pointers, `$at` and `$k0`/`$k1` reserved. Selected by `-mabi=32`.
See also: Caller-saved register, Callee-saved register, Return address register ($ra)
- Argument register ($a0–$a3)first used in §2.2 →
The four registers a function's first four arguments arrive in.
Precisely: `$4`–`$7`. Further arguments go on the stack (§6.1). Not preserved across a call.
See also: Calling convention (o32 ABI), Return-value register ($v0, $v1)
- Return-value register ($v0, $v1)first used in §2.2 →
Where a function leaves its answer for the caller.
Precisely: `$2` and `$3`; a 32-bit result is in `$v0`, a 64-bit one in the pair. Not preserved across a call.
See also: Argument register ($a0–$a3)
- Caller-saved registerfirst used in §2.2 →
A register a called function is allowed to overwrite. If the caller still needs the value afterwards, the caller must save it first.
Precisely: `$t0`–`$t9`, `$a0`–`$a3`, `$v0`–`$v1`, `$at`, `$ra` (and HI/LO): their values are undefined after a `jal` returns.
See also: Callee-saved register, Calling convention (o32 ABI)
- Callee-saved registerfirst used in §2.2 →
A register a called function must leave exactly as it found it. If it wants to use one, it saves the old value first and restores it before returning.
Precisely: `$s0`–`$s7`, `$fp`/`s8`, `$gp`, `$sp`: preserved across every call by the callee's prologue and epilogue (§6.2).
See also: Caller-saved register
- Return address register ($ra)first used in §2.2 →
Register 31. When a function is called with `jal`, the address to come back to is put here.
Precisely: `$31`; `jal` and `bltzal`/`bgezal` write PC + 8 into it (the instruction after the delay slot); `jr $ra` returns. The one register besides `$zero` the hardware treats specially.
See also: Calling convention (o32 ABI), Program counter (PC)
- Stack pointer ($sp)first used in §2.2 →
Register 29. It holds the address of the top of the stack, the memory area where functions keep their local values.
Precisely: `$29`; always a multiple of 8 in o32; moved down by a function's prologue and back up by its epilogue (§4.4, §6.3).
See also: Frame pointer ($fp / s8), Callee-saved register
- Global pointer ($gp)first used in §2.2 →
Register 28. It holds a fixed address near the program's data, so a single load or store can reach small global variables.
Precisely: `$28`; set once by crt0 to `_gp`; in this book's builds (`-G0`) nothing is placed in the small-data area, so `$gp` is set and then unused.
See also: Stack pointer ($sp)
- Frame pointer ($fp / s8)first used in §2.2 →
Register 30. At -O0 the compiler uses it as a fixed base for the current function's local values. objdump prints it as `s8`.
Precisely: `$30`; callee-saved; `-O2` code usually does not use it and treats it as `$s8`.
See also: Stack pointer ($sp)
- Assembler temporary ($at)first used in §2.2 →
Register 1. The assembler is allowed to use it while expanding a pseudo-instruction, so your own code should not rely on it.
Precisely: `$1`; used by `la`, `li` with 32-bit values, and branch pseudo-instructions (§9.1); `.set noat` forbids the assembler from touching it.
See also: Calling convention (o32 ABI)
- Kernel registers ($k0, $k1)first used in §2.2 →
Registers 26 and 27. They are set aside for the operating system's exception handler; a normal program never uses them.
Precisely: `$26`, `$27`; may change at any moment when an exception is taken, so no user code may hold a value in them.
See also: Calling convention (o32 ABI)
- Two's complementfirst used in §3.1 →
The way negative numbers are stored. To get −x, flip every bit of x and add one. Bit 31 tells you the sign: 1 means negative.
Precisely: A 32-bit pattern b read as signed is b − 2³² when bit 31 is set; −1 is 0xFFFFFFFF and the range is −2³¹ … 2³¹ − 1. Addition and subtraction use the same circuit for signed and unsigned values.
See also: Signed overflow, Sign extension
- Signed overflowfirst used in §3.1 →
The true answer of an add or subtract does not fit in 32 signed bits. Two positive numbers give a negative, or two negatives give a positive.
Precisely: The carry into bit 31 differs from the carry out of bit 31. `add`, `addi` and `sub` trap on it; `addu`, `addiu` and `subu` keep the wrapped 32 bits.
See also: Two's complement, Trap (exception), Wrap-around
- Trap (exception)first used in §3.1 →
The CPU stops the program and jumps to an error handler. In this book's test machine there is no handler, so the run simply halts.
Precisely: An exception raised by the instruction itself: integer overflow (`add`, `addi`, `sub`), an address error (a misaligned `lw`/`sw`), a reserved instruction. Carolyne's MIPS description has no trap policy yet, so its `add` wraps like `addu` (a recorded LIMIT).
See also: Signed overflow
- Wrap-aroundfirst used in §3.1 →
Keeping only the low 32 bits of a result and throwing the rest away, like a car's odometer rolling over.
Precisely: Arithmetic modulo 2³²: `addu`, `addiu`, `subu` and every shift and logic instruction behave this way; 0x7FFFFFFF + 1 = 0x80000000.
See also: Signed overflow
- Sign extensionfirst used in §3.2 →
Making a short number longer by copying its top bit into all the new bits. A negative stays negative.
Precisely: Bits 31–16 receive copies of bit 15 (for a 16-bit immediate); used by `addi`, `addiu`, `slti`, `sltiu` and every load/store offset; `lb`/`lh`/`seb`/`seh` do it for 8 and 16 bits.
See also: Zero extension, Immediate
- Zero extensionfirst used in §3.2 →
Making a short number longer by filling the new bits with zeros. The value is read as a plain count.
Precisely: Bits 31–16 become 0; used by `andi`, `ori`, `xori`; `lbu`/`lhu` do it for loaded bytes and halfwords.
See also: Sign extension
- %hi / %lofirst used in §3.2 →
The assembler's way of splitting a 32-bit constant into the half `lui` loads and the half `addiu` adds. When the low half looks negative, the high half is one bigger to compensate.
Precisely: `%lo(x)` = the low 16 bits of x, read signed; `%hi(x)` = `(x − %lo(x)) >> 16`, so that `lui %hi(x)` + `addiu %lo(x)` = x. With `ori` (zero-extended) no correction is needed.
See also: Sign extension, Pseudo-instruction
- Pseudo-instructionfirst used in §3.1 →
A mnemonic the assembler accepts but the CPU does not have. The assembler replaces it with one or more real instructions.
Precisely: `li`, `la`, `move`, `not`, `neg`, `negu`, `b`, `beqz`, `bnez`, `nop` and others; `la` and a 32-bit `li` become two words; some expansions use `$at`.
See also: Assembler temporary ($at), %hi / %lo
- Bit maskfirst used in §3.3 →
A constant with 1s where you want to keep bits and 0s where you want to clear them, used with `and`.
Precisely: `andi rt,rs,0xff` keeps the low byte; `and` with a `lui`-built mask keeps any field; `or` with a mask sets bits, `xor` flips them.
See also: Logical shift
- Logical shiftfirst used in §3.3 →
Sliding all the bits left or right and filling the empty places with zeros.
Precisely: `sll`/`sllv` (left) and `srl`/`srlv` (right, zero fill); a left shift by n multiplies by 2ⁿ, a logical right shift divides an unsigned value by 2ⁿ.
See also: Arithmetic shift, Rotate
- Arithmetic shiftfirst used in §3.3 →
A right shift that fills the empty top bits with copies of the sign bit, so a negative number stays negative.
Precisely: `sra`/`srav`; divides a signed value by 2ⁿ, rounding toward −∞ (−7 >> 1 = −4).
See also: Logical shift
- Rotatefirst used in §3.3 →
A shift where the bits that fall off one end come back in at the other end. Nothing is lost.
Precisely: `rotr rd,rt,sa` and `rotrv rd,rt,rs` (release 2); encoded like `srl`/`srlv` with the `rs` or `sa` field set to 1.
See also: Logical shift
- Set on less thanfirst used in §3.4 →
MIPS has no flags. To compare, an instruction writes 1 into a register if the first value is smaller, else 0. A branch then tests that register.
Precisely: `slt`/`slti` (signed), `sltu`/`sltiu` (unsigned; the immediate is still sign-extended first). Greater-than, ≤ and ≥ are made by swapping operands or `xori rd,rd,1`.
See also: Two's complement, Zero register ($zero)
- Addressfirst used in §4.1 →
The number of one byte in memory. Memory is a very long row of bytes, numbered from 0, and an address is a position in that row.
Precisely: A 32-bit unsigned value; MIPS32 memory is byte-addressed, so consecutive addresses name consecutive bytes. Always written in this book as 8 hex digits.
- Bytefirst used in §4.1 →
Eight bits. The smallest piece of memory that has its own address.
Precisely: The unit `lb`, `lbu` and `sb` move; values 0–255 unsigned or −128–127 signed.
- Halfwordfirst used in §4.1 →
Two bytes, 16 bits. Half of a word.
Precisely: The unit `lh`, `lhu` and `sh` move; its address must be even.
- Little-endianfirst used in §4.1 →
The lowest byte of a word is stored at the lowest address. Written out, the bytes look reversed compared with the number.
Precisely: The byte order of `mipsel`, which the reader's toolchain and core use: `0x12345678` at address A is `78` at A, `56` at A+1, `34` at A+2, `12` at A+3. MIPS also exists big-endian (`mips`).
- Alignmentfirst used in §4.1 →
A word must start at an address that is a multiple of 4, a halfword at a multiple of 2. Such addresses are "aligned".
Precisely: The natural-alignment rule of MIPS32 loads and stores; the low two (or one) bits of the address must be zero. Bytes have no alignment rule.
See also: Address error, Word
- Address errorfirst used in §4.1 →
What happens when a load or store uses an address that is not aligned: on real MIPS the program stops with an exception.
Precisely: The AdEL / AdES exceptions raised by a misaligned `lw`, `lh`, `lhu`, `sw` or `sh`. GCC never emits one. Carolyne's core does not check and would read the wrong word — a recorded open item.
See also: Alignment, Trap (exception)
- Base + offsetfirst used in §4.2 →
The one way MIPS names a memory location: take a register, add a small constant. `16($sp)` means "16 bytes above where $sp points".
Precisely: `rt, offset(rs)`: address = `rs` + sign-extended 16-bit offset, so a base reaches −32768…+32767 bytes around itself. MIPS has no other addressing mode; arrays scale the index with `sll` and add.
See also: Load, Store, Sign extension
- Loadfirst used in §4.2 →
Copy a value from memory into a register. The register changes; memory does not.
Precisely: `lw` (word), `lh`/`lhu` (halfword, sign-/zero-extended), `lb`/`lbu` (byte, sign-/zero-extended); the only instructions that read memory.
See also: Store, Base + offset
- Storefirst used in §4.2 →
Copy a register's value into memory. Memory changes; the register does not. In the assembly the register comes first and the address second.
Precisely: `sw` (word), `sh` (low halfword of rt), `sb` (low byte of rt); the only instructions that write memory. The three doors are reached with `sw`.
See also: Load, Memory-mapped I/O
- Sub-word accessfirst used in §4.3 →
Reading or writing one byte or one halfword instead of a whole word. The other bytes of the word are left exactly as they were.
Precisely: `lb`/`lbu`/`lh`/`lhu`/`sb`/`sh`; a sub-word store is implemented as a read-modify-write of the containing word in the reader's LS unit.
See also: Byte, Halfword, Sign extension
- Memory mapfirst used in §4.1 →
The plan of where things live in memory: the program in one region, the data in another, the stack inside the data region, the doors at its top.
Precisely: For this book's test machine: code from `0xBFC00000` (the reset vector), data from `0x10000000`, the stack starting at `0x10003FF0` and growing down, the doors at `0x10003FF0`/`FF4`/`FF8` (16 KB data) or `0x10000FF0`… (4 KB).
See also: Stack, Memory-mapped I/O
- Stackfirst used in §4.4 →
The part of memory where functions keep their local values and the registers they must not destroy. It grows toward lower addresses: pushing means $sp gets smaller.
Precisely: The region below `$sp`'s starting value; a function claims N bytes with `addiu sp,sp,-N` and releases them with `addiu sp,sp,N`; o32 keeps `$sp` a multiple of 8. There is no `push` or `pop` instruction.
See also: Stack pointer ($sp), Stack frame
- Stack framefirst used in §4.4 →
The slice of the stack that one running function owns: its saved registers and its local variables, from $sp up to where the caller's slice begins.
Precisely: Built by the prologue (`addiu sp,sp,-N`, `sw` of `$ra`, `$fp`, `$s*`) and torn down by the epilogue in reverse; `print_char`'s frame is 8 bytes, `main`'s 32.
See also: Stack, Callee-saved register, Frame pointer ($fp / s8)
- Branchfirst used in §5.1 →
An instruction that tests something and, if the test holds, makes the program continue somewhere else. If not, the program goes on to the next instruction.
Precisely: `beq`, `bne` (two registers), `blez`, `bgtz`, `bltz`, `bgez` (one register against zero), and the link forms; the target is PC-relative, and the instruction after the branch always executes.
See also: Branch target, Taken / not taken, Delay slot
- Taken / not takenfirst used in §5.1 →
A branch is "taken" when its test is true and the PC moves to the target. It is "not taken" when the test is false and the program simply continues.
Precisely: Either way the delay slot executes first; a not-taken branch then continues at branch + 8.
See also: Branch, Delay slot
- Branch offsetfirst used in §5.1 →
The 16-bit number inside a branch. It is not an address; it is how many instructions forward or backward the target is, counted from the delay slot.
Precisely: imm16, sign-extended and multiplied by 4; range −32768…+32767 instructions (±128 KB).
See also: Branch target, Sign extension
- Branch targetfirst used in §5.1 →
The address a taken branch goes to.
Precisely: (address of the branch + 4) + (offset × 4). The +4 is the delay slot's address; branches are relative to it, not to themselves.
See also: Branch offset, Program counter (PC)
- Compare-with-zero branchfirst used in §5.2 →
The four branches that test one register against zero: less or equal, greater, less, greater or equal. There is no second register to compare with.
Precisely: `blez`, `bgtz` (opcodes 6, 7) and `bltz`, `bgez` (REGIMM: opcode 1 with rt = 0 or 1). `beqz`/`bnez` are `beq`/`bne` with `$zero`.
See also: Branch, Set on less than
- Branch and linkfirst used in §5.2 →
A branch that also remembers where it came from, by writing the return address into $ra. Used for calling a nearby function.
Precisely: `bltzal`, `bgezal` (REGIMM rt = 16, 17); `bal` is `bgezal $zero`; $ra = branch address + 8. `beq`/`bne` have no link forms.
See also: Link, Return address register ($ra)
- Jumpfirst used in §5.3 →
Go somewhere with no test. `j` and `jal` name the place with a 26-bit number; `jr` and `jalr` go to the address in a register.
Precisely: J-format `j`/`jal` (target = region : index : 00), R-format `jr rs` / `jalr rd,rs`; all four have a delay slot.
See also: Jump region, Link, Return
- Jump regionfirst used in §5.3 →
The 256 MB block of memory a `j` or `jal` can reach: the one the instruction after the jump is in. To go further you put the address in a register and use `jr`.
Precisely: The top 4 bits of PC + 4 are kept; the 26-bit index × 4 supplies the low 28 bits.
- Linkfirst used in §5.3 →
Saving the address to come back to. `jal` writes it into $ra just before jumping, so the called function knows the way home.
Precisely: $ra (or rd for `jalr`) = address of the jump + 8, the instruction after the delay slot.
See also: Return address register ($ra), Return, Delay slot
- Returnfirst used in §5.3 →
Going back to the caller: `jr $ra` jumps to the address `jal` saved.
Precisely: `jr ra` (funct 8) with its delay slot; the epilogue restores $ra from the stack first if the function made any calls.
See also: Link, Stack frame
- Pipelinefirst used in §5.4 →
The way a CPU works on several instructions at once, like an assembly line: while one is being executed, the next is being decoded and the one after is being fetched.
Precisely: The classic MIPS pipeline has five stages; one instruction enters and one leaves every cycle when nothing stalls.
See also: Pipeline stage, Delay slot, Squash
- Pipeline stagefirst used in §5.4 →
One step of the assembly line. MIPS's classic five: fetch the word, decode it and read registers, execute, access memory, write the result back.
Precisely: IF, ID, EX, MEM, WB; a branch is decided in ID or EX, after the next instruction has already been fetched.
See also: Pipeline
- Squashfirst used in §5.4 →
Throwing away an instruction that the CPU had already started but must not finish. A CPU without delay slots squashes the instruction after a taken branch.
Precisely: Killing an in-flight instruction before it writes any state; the reader's out-of-order core squashes everything younger than a mispredicted branch, which is why its MIPS slots must be `nop` until the engine learns the slot (phase B).
See also: Pipeline, Delay slot
- .set noreorderfirst used in §5.4 →
A note to the assembler: "do not move my instructions around or add nops; I have written every delay slot myself."
Precisely: GAS directive; without it (`.set reorder`, the default) the assembler fills delay slots by moving instructions or inserting `nop`. crt0 uses it; GCC's `-fno-delayed-branch` output has explicit `nop`s.
See also: Delay slot, Pseudo-instruction
- Callfirst used in §6.1 →
Asking another function to do a job and come back. Put the arguments in $a0–$a3, jal to the function, and expect the answer in $v0.
Precisely: `jal f` (or `jalr`, `bal`) with the o32 register assignments; the callee returns with `jr ra` and the result in `$v0` (`$v1` for a second word).
See also: Link, Return, Argument register ($a0–$a3), Return-value register ($v0, $v1)
- Leaf functionfirst used in §6.1 →
A function that calls no other function. Nothing overwrites its $ra, so it can return with jr ra without saving anything.
Precisely: A function containing no `jal`/`jalr`/`bal`; at -O2 it usually needs no stack frame at all, at -O0 GCC still builds a small `$fp` frame (`print_char`, `print_int`).
See also: Non-leaf function, Return address register ($ra)
- Non-leaf functionfirst used in §6.1 →
A function that calls other functions. Its own jal would destroy $ra, so it must save $ra on the stack first and restore it before returning.
Precisely: Any function with a call inside; its prologue stores `$ra` (`outchar`: `sw ra,20(sp)`) and its epilogue reloads it.
See also: Leaf function, Prologue, Epilogue
- Prologuefirst used in §6.1 →
The few instructions at the start of a function that make its stack frame and save the registers it will need to give back.
Precisely: `addiu sp,sp,-N`, `sw` of `$ra` (non-leaf), `$fp` and any `$s` registers, `move s8,sp` at -O0, then spills of arguments into the caller's argument area.
See also: Epilogue, Stack frame
- Epiloguefirst used in §6.1 →
The mirror image at the end of a function: put the saved registers back, release the frame, jump to $ra.
Precisely: `move sp,s8` (at -O0), `lw` of what the prologue stored, `addiu sp,sp,N`, `jr ra`, a delay slot.
- Clobberfirst used in §6.2 →
To destroy a register's value by writing something else into it. A call clobbers every caller-saved register: after jal returns, $t0 may hold anything.
Precisely: The o32 promise is only that callee-saved registers survive a call; `$t0–$t9`, `$a0–$a3`, `$v0–$v1`, `$at` and `$ra` have no guaranteed value afterwards.
See also: Caller-saved register, Callee-saved register
- Argument areafirst used in §6.3 →
Sixteen bytes at the bottom of every function's frame that the function reserves for the functions it calls, so they have a place to store their first four arguments.
Precisely: o32 requires the caller to reserve 4 × 4 bytes at `0(sp)…12(sp)` before a call; the callee may spill `$a0–$a3` there (`fib`: `sw a0,32(s8)`, which is 0 from the caller's `$sp`).
See also: Stack frame, Argument register ($a0–$a3)
- Activationfirst used in §6.3 →
One running instance of a function. Each call creates a new activation with its own frame, even when it is the same function again.
Precisely: The frame plus the register state belonging to one call; `fib(3)` has three activations alive at its deepest point, each with its own saved `$ra` and argument.
See also: Recursion, Stack frame
- Recursionfirst used in §6.3 →
A function that calls itself. It works because every call gets a fresh frame on the stack, so the outer calls' values are not disturbed.
Precisely: No hardware support beyond the stack discipline; `fib` at -O0 uses 32 bytes per activation and saves `$ra`, `$s8`, `$s0` in each.
See also: Activation, Stack
- Multiply into HI:LOfirst used in §7.1 →
mult and multu multiply two registers and put the whole 64-bit answer into the pair HI and LO. The instruction names no destination register.
Precisely: `mult rs,rt` (signed) and `multu rs,rt` (unsigned), R-format with rd = 0; HI = bits 63–32 of the product, LO = bits 31–0.
See also: HI and LO, Product high word, Move from / to HI and LO
- Product high wordfirst used in §7.1 →
The top half of a 64-bit product. It is the only part where multiplying "as signed" and "as unsigned" give different answers; the low half is always the same bits.
Precisely: HI after `mult` versus `multu`; for 0xFFFFFFFF × 2, HI is 0xFFFFFFFF (signed: −2) or 0x00000001 (unsigned: 8589934590), LO is 0xFFFFFFFE either way.
See also: Multiply into HI:LO, Two's complement
- Move from / to HI and LOfirst used in §7.1 →
The only four instructions that can reach HI and LO: mfhi and mflo copy them into a normal register, mthi and mtlo copy a normal register into them.
Precisely: `mfhi rd`, `mflo rd`, `mthi rs`, `mtlo rs`; in Carolyne they read or write a one-register class through an operand that carries no index.
See also: HI and LO, Multiply into HI:LO
- Quotientfirst used in §7.2 →
How many times the divisor fits into the dividend. div and divu put it in LO; mflo fetches it.
Precisely: LO after `div`/`divu`; truncated toward zero for `div`; INT_MIN / −1 gives INT_MIN with no trap.
See also: Remainder, Truncation toward zero
- Remainderfirst used in §7.2 →
What is left over after the division. div and divu put it in HI; mfhi fetches it. It has the same sign as the dividend.
Precisely: HI after `div`/`divu`, defined by dividend = quotient × divisor + remainder; −7 / 2 gives quotient −3, remainder −1.
See also: Quotient
- Truncation toward zerofirst used in §7.2 →
div rounds its quotient toward zero, not downward: −7 / 2 is −3, not −4. This matches C.
Precisely: The rounding rule of `div` (and of C's `/` and `%` on MIPS); `sra` rounds toward −∞ instead, which is why a compiler adjusts before using a shift for a signed divide.
See also: Quotient, Arithmetic shift
- Unpredictablefirst used in §7.2 →
The MIPS manual's word for "we do not say what happens". A divide by zero leaves HI and LO unpredictable: any value, and a program must not depend on it.
Precisely: UNPREDICTABLE results in the MIPS32 architecture; GCC guards `/` with a `teq` trap unless `-mno-check-zero-division`; the site's simulator returns LO = −1, HI = the dividend and flags the tick.
See also: Trap (exception)
- Release-2 mulfirst used in §7.2 →
mul rd,rs,rt multiplies and writes the low 32 bits straight into a normal register, like an add. It is what the compiler uses for int × int.
Precisely: SPECIAL2 (opcode 28), funct 2; HI and LO are UNPREDICTABLE afterwards; `mult` + `mflo` gives the same low word in two instructions.
See also: Multiply into HI:LO, HI and LO
- Conditional movefirst used in §8.1 →
Copy one register into another only if a third register is zero (movz) or not zero (movn). If the test fails, the destination keeps its old value. It replaces a small branch.
Precisely: `movz rd,rs,rt`: if rt == 0 then rd = rs; `movn rd,rs,rt`: if rt != 0 then rd = rs. Three sources matter (rs, rt, the old rd); Carolyne lists rd as a third source. SPECIAL funct 10 / 11.
See also: Branch, Delay slot
- Sign-extend in a registerfirst used in §8.1 →
seb and seh take a byte or a halfword that is already in a register and stretch it to 32 bits by copying its top bit upward, exactly what lb and lh do when they load.
Precisely: `seb rd,rt` copies bit 7 of rt into bits 31–8; `seh rd,rt` copies bit 15 into bits 31–16. SPECIAL3 funct 32 with sa = 16 / 24. Replaces `sll 24; sra 24` (or 16).
See also: Sign extension, Sub-word access
- Bit fieldfirst used in §8.2 →
A run of bits inside a word, named by where it starts (pos) and how long it is (size). C's `struct { unsigned x : 4; }` is one.
Precisely: Bits pos+size−1 .. pos of a 32-bit word, with 0 ≤ pos, 1 ≤ size, pos + size ≤ 32.
See also: Field extract, Field insert, Bit mask
- Field extractfirst used in §8.2 →
ext pulls a bit field out of a register, slides it down so it starts at bit 0, and fills the rest with zeros. One instruction instead of a shift and a mask.
Precisely: `ext rt,rs,pos,size`: rt = (rs >> pos) & (2^size − 1). SPECIAL3 funct 0; the word stores sa = pos and rd = size − 1.
See also: Bit field, Field insert
- Field insertfirst used in §8.2 →
ins puts the low bits of one register into a chosen field of another register, and leaves all the other bits of that register exactly as they were.
Precisely: `ins rt,rs,pos,size`: bits pos+size−1..pos of rt = the low size bits of rs; rt is both read and written. SPECIAL3 funct 4; the word stores sa = pos and rd = pos + size − 1.
See also: Bit field, Field extract
- Count leading zerosfirst used in §8.2 →
clz counts how many zero bits a word starts with, from bit 31 down to the first 1. clo does the same for ones. For a word that is all zeros, clz gives 32.
Precisely: `clz rd,rs`, `clo rd,rs`: SPECIAL2 funct 32 / 33 (the encoding also sets rt = rd). Used for `__builtin_clz`, normalisation and integer log2.
See also: Bit field, Logical shift
- Toolchainfirst used in §9.1 →
The set of programs that turn your C file into words in memory and let you read those words back: the compiler, the assembler, the linker and the disassembler.
Precisely: `mipsel-linux-gnu-gcc` (with `-S` for assembly), `as`, `ld` with the project's linker script, `objdump -d`; driven by `examples/compile_tool` in the reader's project.
See also: Assembler, Linker, Disassembly
- Assemblerfirst used in §9.1 →
The tool that turns assembly text into 32-bit words. It also expands pseudo-instructions and works out every branch offset from its label.
Precisely: GNU `as` for MIPS: honours `.set noreorder` / `.set noat`, expands `li`, `la`, `move`, `b`, `nop`, and may use `$at` as scratch.
See also: Pseudo-instruction, Assembler temporary ($at), Branch offset
- Linkerfirst used in §9.1 →
The tool that joins the compiled pieces into one program, decides the address of every section and every label, and writes the ELF file.
Precisely: GNU `ld`, driven by the project's linker script; resolves `jal main`, `_gp`, `__stack_top` and `%hi`/`%lo` pairs to final addresses.
See also: Linker script, ELF
- Linker scriptfirst used in §9.1 →
A small text file that tells the linker where each part of the program goes in memory: the code at the reset vector, the data at the data memory, the stack at its top.
Precisely: `link.ld` generated per target: `.text` at 0xBFC00000, `.data`/`.rodata` at 0x10000000, `_gp`, `__stack_top` and the door addresses as symbols.
See also: Linker, Memory map
- ELFfirst used in §9.1 →
The file the linker produces: the program's words, grouped into sections, each with the address where it must be loaded, plus the entry point.
Precisely: Executable and Linkable Format; the compile tool reads its sections to build the two memory images and checks the entry equals the reset vector.
See also: Linker, Reset vector
- Disassemblyfirst used in §9.1 →
The words of a program printed back as instructions, one line each: address, hex word, mnemonic, operands. The dump files in this book are disassemblies.
Precisely: `objdump -d` output; register names without `$`, `s8` for `$30`, branch and jump targets printed as resolved addresses with `<symbol+offset>`.
See also: Toolchain, Pseudo-instruction
- Reset vectorfirst used in §9.2 →
The address the CPU starts executing from when it is switched on or reset. On MIPS it is always 0xBFC00000.
Precisely: Fixed by the MIPS architecture; stated in Carolyne's description as `RESET_PC` and used by the linker script for `_start`. RISC-V leaves it to the implementation (the reader's RV32IM uses 0).
See also: Program counter (PC), crt0
- crt0first used in §9.2 →
The few dozen instructions that run before main: they clear the registers, set up $gp and $sp, call main, and hand main's return value to the exit door.
Precisely: `crt0_mips.S`, assembled with `.set noreorder` and every delay slot written out; 42 words at 0xBFC00000–0xBFC000A4 in every build.
See also: Reset vector, Stack pointer ($sp), Global pointer ($gp)
- Optimisation levelfirst used in §9.3 →
How hard the compiler works to make the code fast. -O0: every variable lives in memory and each statement is translated on its own. -O2: values stay in registers, small functions are copied inline, loops are rewritten, constants are computed ahead of time.
Precisely: GCC's `-O0` and `-O2`; the reader's census builds every program at both.
See also: Inlining, Loop unrolling, Constant folding
- Inliningfirst used in §9.3 →
Copying the body of a small function into the place that calls it, so there is no call, no return and no frame.
Precisely: What -O2 did to `print_str`, `print_int` and `print_char` in `hello.c`: `main` at -O2 contains their stores to the doors directly.
See also: Optimisation level, Call
- Loop unrollingfirst used in §9.3 →
Writing out a loop's iterations one after another instead of looping, so the counter and the back-branch disappear.
Precisely: What -O2 did to `for (i = 0; i < 5; i++)` in `hello.c`: five copies of the body, no `slti`/`bnez`.
See also: Optimisation level, Branch
- Constant foldingfirst used in §9.3 →
When the compiler can compute a value itself, it writes the answer into the program instead of the instructions that would compute it.
Precisely: `i * i` for i = 0…4 became the constants 0, 1, 4, 9, 16 in `hello_o2.dump`; no `mul` remains.
See also: Optimisation level, Release-2 mul
- Cycles versus instructionsfirst used in §9.3 →
An instruction count says how much work the program asks for; a cycle count says how long the core took. Branches, loads and the machine's width make the two differ.
Precisely: The census counts instructions in the ELF; the sweep counts cycles to the exit door on the reader's core: `hello` 128 instructions / 1023 cycles at -O0, 72 / 264 at -O2.
See also: Pipeline, Delay slot
- ISA descriptionfirst used in §9.4 →
The package that tells Carolyne's engine what the MIPS words mean: which register classes exist, the 63 operations, how to recognise each word, how to widen each immediate, which unit runs what.
Precisely: `carolyne/isa/mips/`: `reg.py`, `field_match.py`, `imm.py`, `operand.py`, `uop.py`, `mop.py`, `exec_unit*.py`, `mips32.py`; the same file set as `riscv/`.
See also: Instruction set architecture (ISA), HI and LO