Skip to content
Contents

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.

105 of 105
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.

See also: I-format, J-format

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.

See also: R-format, Immediate

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`.

See also: R-format, I-format

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.

See also: Byte, Word, Alignment

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.

See also: Halfword, Word

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.

See also: Byte, Alignment

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`).

See also: Word, Address

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

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.

See also: Jump, J-format

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.

See also: Prologue, Return

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