Skip to content
Contents

Reference

MIPS32 cheat sheet

The whole book on one page: the three instruction formats, the 32 registers with their o32 jobs, every one of the 63 instructions your core runs with what it does, and the 26 things that catch a RISC-V reader. Every row links to the section that explains it.

Instruction formats

Every instruction is one 32-bit word, bit 31 on the left. The opcode (bits 31..26) picks the format; opcode 0 means "look at funct". §1.3

R-typeregister–register: add, and, sll, jr, mult, mfhi, movz, seb, ext …

add $t0,$t1,$t2 = 0x012a40a0
  • opcode — opcode 0 (SPECIAL), 28 (SPECIAL2), 31 (SPECIAL3)
  • rs — rs: first source register
  • rt — rt: second source, or the destination of an I-type
  • rd — rd: destination register
  • sa — sa: shift amount (0 when unused)
  • funct — funct: which SPECIAL instruction

I-typeregister + 16-bit immediate: addiu, ori, lui, lw, sw, beq, slti, bgez …

addiu $t1,$zero,72 = 0x24090048
  • opcode — opcode: which instruction (0 = SPECIAL: see funct)
  • rs — rs: first source register
  • rt — rt: the destination, or the second register of beq/bne, or the REGIMM sub-opcode
  • imm16 — imm: 16-bit constant, offset, or upper half

J-typejump to an absolute target: j, jal

jal 0xbfc0018c = 0x0ff00063
  • opcode — opcode 2 (j) or 3 (jal)
  • index26 — index: 26 bits, ×4, under the top 4 bits of PC+4

Opcodes that need a second look

  • op 0 SPECIAL — funct picks: arithmetic, logic, shifts, slt, jr/jalr, movz/movn, mult/div, mfhi/mflo/mthi/mtlo
  • op 1 REGIMM — the rt field picks: bltz 0, bgez 1, bltzal 16, bgezal 17
  • op 28 SPECIAL2 — funct: mul 2, clz 32, clo 33
  • op 31 SPECIAL3 — funct: ext 0, ins 4, seb/seh 32 (sa 16 / 24)

Same funct, different field

  • srl and rotr are both funct 2: rs = 0 shifts, rs = 1 rotates
  • srlv and rotrv are both funct 6: sa = 0 shifts, sa = 1 rotates
  • seb and seh are both SPECIAL3 funct 32: sa = 16 byte, sa = 24 half
  • nop is the all-zero word: sll $zero,$zero,0

The register file (o32 names)

32 general registers of 32 bits, plus HI, LO and the PC. The names are a convention between compilers; the hardware knows only $0 (always zero) and $31 (where jal writes the link). §2.2

numbernamejob (o32)after a call, the value is…
$0 $zero always 0 (hardware) always 0
$1 $at assembler temporary gone (the assembler may use it)
$2 $v0 return value gone (holds the result)
$3 $v1 return value, second word gone
$4 $a0 argument 1 gone
$5 $a1 argument 2 gone
$6 $a2 argument 3 gone
$7 $a3 argument 4 gone
$8 $t0 temporary gone (caller-saved)
$9 $t1 temporary gone (caller-saved)
$10 $t2 temporary gone (caller-saved)
$11 $t3 temporary gone (caller-saved)
$12 $t4 temporary gone (caller-saved)
$13 $t5 temporary gone (caller-saved)
$14 $t6 temporary gone (caller-saved)
$15 $t7 temporary gone (caller-saved)
$16 $s0 saved kept (callee-saved)
$17 $s1 saved kept (callee-saved)
$18 $s2 saved kept (callee-saved)
$19 $s3 saved kept (callee-saved)
$20 $s4 saved kept (callee-saved)
$21 $s5 saved kept (callee-saved)
$22 $s6 saved kept (callee-saved)
$23 $s7 saved kept (callee-saved)
$24 $t8 temporary gone (caller-saved)
$25 $t9 temporary gone (caller-saved)
$26 $k0 reserved for the operating system never use
$27 $k1 reserved for the operating system never use
$28 $gp global pointer kept
$29 $sp stack pointer kept
$30 $fp frame pointer (objdump: s8) kept (callee-saved)
$31 $ra return address (written by jal, hardware) gone (jal overwrites it)
— HI high word of mult/multu; remainder of div/divu; read with mfhi, written with mthi gone (caller-saved)
— LO low word of mult/multu; quotient of div/divu; read with mflo, written with mtlo gone (caller-saved)
— PC address of the current instruction; not a register: only branches and jumps set it, jal/jalr/bgezal read it (+8) the return address is in $ra
  • special: $zero $at $k0 $k1
  • arguments and results: $a0–$a3 $v0 $v1
  • temporaries, not saved: $t0–$t9
  • saved across calls: $s0–$s7 $fp
  • pointers: $gp $sp $ra

Every instruction

The 63 MIPS32 release-2 user-mode integer instructions your core runs, in the order the book teaches them. Register operands are named as in the assembler syntax; rd is written, rs and rt are read unless the syntax says otherwise.

Arithmetic

add/sub trap on signed overflow; the u forms wrap. GCC uses the u forms.
instruction what it does encoding · immediate example §
add rd, rs, rt rd = rs + rt; traps on signed overflow R · op 0 · funct 32 add $t0,$t1,$t2
= 0x012a40a0
§3.1
addu rd, rs, rt rd = rs + rt; wraps, never traps (what C uses) R · op 0 · funct 33 addu $t0,$t1,$t2
= 0x012a40a1
§3.1
sub rd, rs, rt rd = rs − rt; traps on signed overflow R · op 0 · funct 34 sub $t0,$t1,$t2
= 0x012a40a2
§3.1
subu rd, rs, rt rd = rs − rt; wraps, never traps R · op 0 · funct 35 subu $t0,$t1,$t2
= 0x012a40a3
§3.1
addi rt, rs, imm rt = rs + sign-extended imm; traps on overflow I · op 8
imm16, sign-extended
addi $t2,$t1,16
= 0x212a0010
§3.2
addiu rt, rs, imm rt = rs + sign-extended imm; wraps (what C uses) I · op 9
imm16, sign-extended
addiu $t2,$t1,16
= 0x252a0010
§3.2
lui rt, imm rt = imm << 16 (the top half; low half zero) I · op 15
imm16 → bits 31..16
lui $t2,0x10
= 0x3d2a0010
§3.2

Logic

The immediate forms zero-extend their 16 bits.
instruction what it does encoding · immediate example §
and rd, rs, rt rd = rs AND rt, bit by bit R · op 0 · funct 36 and $t0,$t1,$t2
= 0x012a40a4
§3.3
or rd, rs, rt rd = rs OR rt, bit by bit (move is or rd,rs,$zero) R · op 0 · funct 37 or $t0,$t1,$t2
= 0x012a40a5
§3.3
xor rd, rs, rt rd = rs XOR rt, bit by bit R · op 0 · funct 38 xor $t0,$t1,$t2
= 0x012a40a6
§3.3
nor rd, rs, rt rd = NOT (rs OR rt); not rd,rs is nor rd,rs,$zero R · op 0 · funct 39 nor $t0,$t1,$t2
= 0x012a40a7
§3.3
andi rt, rs, imm rt = rs AND zero-extended imm I · op 12
imm16, zero-extended
andi $t2,$t1,0x10
= 0x312a0010
§3.3
ori rt, rs, imm rt = rs OR zero-extended imm I · op 13
imm16, zero-extended
ori $t2,$t1,0x10
= 0x352a0010
§3.3
xori rt, rs, imm rt = rs XOR zero-extended imm I · op 14
imm16, zero-extended
xori $t2,$t1,0x10
= 0x392a0010
§3.3

Compare

Only "less than". Other comparisons swap operands or add xori (§3.4).
instruction what it does encoding · immediate example §
slt rd, rs, rt rd = 1 if rs < rt (signed), else 0 R · op 0 · funct 42 slt $t0,$t1,$t2
= 0x012a40aa
§3.4
sltu rd, rs, rt rd = 1 if rs < rt (unsigned), else 0 R · op 0 · funct 43 sltu $t0,$t1,$t2
= 0x012a40ab
§3.4
slti rt, rs, imm rt = 1 if rs < sign-extended imm (signed) I · op 10
imm16, sign-extended
slti $t2,$t1,16
= 0x292a0010
§3.4
sltiu rt, rs, imm rt = 1 if rs < sign-extended imm, compared unsigned I · op 11
imm16, sign-extended
sltiu $t2,$t1,16
= 0x2d2a0010
§3.4

Shifts and rotates

The value is rt; the count is sa (5 bits) or the low 5 bits of rs.
instruction what it does encoding · immediate example §
sll rd, rt, sa rd = rt << sa; sll $zero,$zero,0 is nop R · op 0 · funct 0
sa: 0–31
sll $t0,$t2,2
= 0x012a4080
§3.3
srl rd, rt, sa rd = rt >> sa, filling with zeros (logical) R · op 0 · funct 2 · rs 0
sa: 0–31
srl $t0,$t2,2
= 0x000a4082
§3.3
sra rd, rt, sa rd = rt >> sa, filling with the sign bit (arithmetic) R · op 0 · funct 3
sa: 0–31
sra $t0,$t2,2
= 0x012a4083
§3.3
rotr rd, rt, sa r2 rd = rt rotated right by sa R · op 0 · funct 2 · rs 1
sa: 0–31
rotr $t0,$t2,2
= 0x002a4082
§8.2
sllv rd, rt, rs rd = rt << (rs & 31) R · op 0 · funct 4 sllv $t0,$t2,$t1
= 0x012a4084
§3.3
srlv rd, rt, rs rd = rt >> (rs & 31), logical R · op 0 · funct 6 · sa 0 srlv $t0,$t2,$t1
= 0x012a4006
§3.3
srav rd, rt, rs rd = rt >> (rs & 31), arithmetic R · op 0 · funct 7 srav $t0,$t2,$t1
= 0x012a4087
§3.3
rotrv rd, rt, rs r2 rd = rt rotated right by (rs & 31) R · op 0 · funct 6 · sa 1 rotrv $t0,$t2,$t1
= 0x012a4046
§8.2

Loads

Address = rs + signed 16-bit offset. Byte and half loads choose sign or zero extension.
instruction what it does encoding · immediate example §
lb rt, off(rs) rt = one byte at rs+off, sign-extended I · op 32
imm16, sign-extended
lb $t2,16($t1)
= 0x812a0010
§4.3
lh rt, off(rs) rt = one halfword at rs+off, sign-extended I · op 33
imm16, sign-extended
lh $t2,16($t1)
= 0x852a0010
§4.3
lw rt, off(rs) rt = the word at rs+off I · op 35
imm16, sign-extended
lw $t2,16($t1)
= 0x8d2a0010
§4.2
lbu rt, off(rs) rt = one byte at rs+off, zero-extended I · op 36
imm16, sign-extended
lbu $t2,16($t1)
= 0x912a0010
§4.3
lhu rt, off(rs) rt = one halfword at rs+off, zero-extended I · op 37
imm16, sign-extended
lhu $t2,16($t1)
= 0x952a0010
§4.3

Stores

Store the low byte, half or word of rt.
instruction what it does encoding · immediate example §
sb rt, off(rs) the low byte of rt → memory at rs+off I · op 40
imm16, sign-extended
sb $t2,16($t1)
= 0xa12a0010
§4.3
sh rt, off(rs) the low halfword of rt → memory at rs+off I · op 41
imm16, sign-extended
sh $t2,16($t1)
= 0xa52a0010
§4.3
sw rt, off(rs) rt → the word at rs+off I · op 43
imm16, sign-extended
sw $t2,16($t1)
= 0xad2a0010
§4.2

Branches

Target = PC+4 + offset×4. The instruction after the branch always runs (delay slot).
instruction what it does encoding · immediate example §
beq rs, rt, label slot if rs == rt go to label (after the delay slot) I · op 4
offset16 × 4, signed
beq $t1,$t2,0x00000044
= 0x112a0010
§5.1
bne rs, rt, label slot if rs != rt go to label I · op 5
offset16 × 4, signed
bne $t1,$t2,0x00000044
= 0x152a0010
§5.1
blez rs, label slot if rs <= 0 go to label I · op 6
offset16 × 4, signed
blez $t1,0x00000044
= 0x192a0010
§5.2
bgtz rs, label slot if rs > 0 go to label I · op 7
offset16 × 4, signed
bgtz $t1,0x00000044
= 0x1d2a0010
§5.2
bltz rs, label slot if rs < 0 go to label I · op 1 · rt 0
offset16 × 4, signed
bltz $t1,0x00000044
= 0x05200010
§5.2
bgez rs, label slot if rs >= 0 go to label I · op 1 · rt 1
offset16 × 4, signed
bgez $t1,0x00000044
= 0x05210010
§5.2
bltzal rs, label slot links $ra = PC+8; if rs < 0 go to label I · op 1 · rt 16
offset16 × 4, signed
bltzal $t1,0x00000044
= 0x05300010
§5.3
bgezal rs, label slot links $ra = PC+8; if rs >= 0 go to label (bal is bgezal $zero) I · op 1 · rt 17
offset16 × 4, signed
bgezal $t1,0x00000044
= 0x05310010
§5.3

Jumps

j/jal keep the top 4 bits of PC+4; jr/jalr take an address from a register.
instruction what it does encoding · immediate example §
j target slot go to target (same 256 MB region) J · op 2
index26 × 4
j 0x03c0018c
= 0x08f00063
§5.3
jal target slot links $ra = PC+8; go to target — the function call J · op 3
index26 × 4
jal 0x03c0018c
= 0x0cf00063
§5.3
jr rs slot go to the address in rs — the function return R · op 0 · funct 8 jr $t1
= 0x012a4088
§5.3
jalr rd, rs slot links rd = PC+8 (default $ra); go to the address in rs R · op 0 · funct 9 jalr $t0,$t1
= 0x012a4089
§5.3

Multiply and divide

mult/div write HI and LO; mul writes rd with the low word.
instruction what it does encoding · immediate example §
mult rs, rt HI:LO = rs × rt, signed 64-bit product R · op 0 · funct 24 mult $t1,$t2
= 0x012a4098
§7.1
multu rs, rt HI:LO = rs × rt, unsigned 64-bit product R · op 0 · funct 25 multu $t1,$t2
= 0x012a4099
§7.1
div rs, rt LO = rs ÷ rt, HI = rs mod rt (signed) R · op 0 · funct 26 div $t1,$t2
= 0x012a409a
§7.2
divu rs, rt LO = rs ÷ rt, HI = rs mod rt (unsigned) R · op 0 · funct 27 divu $t1,$t2
= 0x012a409b
§7.2
mul rd, rs, rt rd = low 32 bits of rs × rt; HI/LO become undefined R · op 28 · funct 2 mul $t0,$t1,$t2
= 0x712a4082
§7.2
mfhi rd rd = HI R · op 0 · funct 16 mfhi $t0
= 0x012a4090
§7.1
mflo rd rd = LO R · op 0 · funct 18 mflo $t0
= 0x012a4092
§7.1
mthi rs HI = rs R · op 0 · funct 17 mthi $t1
= 0x012a4091
§7.1
mtlo rs LO = rs R · op 0 · funct 19 mtlo $t1
= 0x012a4093
§7.1

Release-2 extras

Conditional moves, sign-extend, bit fields, count leading zeros.
instruction what it does encoding · immediate example §
movz rd, rs, rt if rt == 0 then rd = rs (else rd unchanged) R · op 0 · funct 10 movz $t0,$t1,$t2
= 0x012a408a
§8.1
movn rd, rs, rt if rt != 0 then rd = rs (else rd unchanged) R · op 0 · funct 11 movn $t0,$t1,$t2
= 0x012a408b
§8.1
clz rd, rs rd = number of leading zero bits in rs (32 for zero) R · op 28 · funct 32 clz $t0,$t1
= 0x712a40a0
§8.2
clo rd, rs rd = number of leading one bits in rs R · op 28 · funct 33 clo $t0,$t1
= 0x712a40a1
§8.2
seb rd, rt r2 rd = the low byte of rt, sign-extended to 32 bits R · op 31 · funct 32 · sa 16 seb $t0,$t2
= 0x7d2a4420
§8.1
seh rd, rt r2 rd = the low halfword of rt, sign-extended to 32 bits R · op 31 · funct 32 · sa 24 seh $t0,$t2
= 0x7d2a4620
§8.1
ext rt, rs, pos, size r2 rt = bits pos+size-1..pos of rs, zero-extended R · op 31 · funct 0
pos, size (in sa, rd)
ext $t2,$t1,2,9
= 0x7d2a4080
§8.2
ins rt, rs, pos, size r2 replace bits pos+size-1..pos of rt with the low size bits of rs R · op 31 · funct 4
pos, size (in sa, rd)
ins $t2,$t1,3,6
= 0x7d2a40c4
§8.2

What to keep in mind

The rules a RISC-V reader trips over, each with the section that shows it running.

The delay slot

§5.4

The instruction after every branch and jump runs whether or not the branch is taken. Your core squashes it today, so GCC fills every slot with nop (-fno-delayed-branch).

Link = PC + 8

§5.3

jal, jalr, bgezal and bltzal write the address after the delay slot, not the next word. jr $ra therefore returns past the slot.

bgezal / bltzal link even when not taken

§5.3

$ra is written before the condition is tested. bal label is bgezal $zero,label.

Branch target arithmetic

§5.1

target = (address of the slot) + offset × 4, offset signed 16 bits: about ±128 KB. Relative to PC+4, not to the branch itself.

Jump target arithmetic

§5.3

j and jal: target = top 4 bits of PC+4, then index × 4. A jump cannot leave its 256 MB region; jr/jalr can.

Only equality compares two registers

§5.2

beq and bne are the only two-register branches. blez, bgtz, bltz, bgez compare with zero. a < b needs slt then bnez.

slt is the only compare

§3.4

For >, >=, <= swap the operands or add xori rd,rd,1. sltiu rd,rs,1 tests rs == 0.

$zero is really zero

§2.1

Reads give 0 and every write is dropped. nop is sll $zero,$zero,0; move rd,rs is or rd,rs,$zero (some assemblers: addu).

add traps, addu wraps

§3.1

add, addi and sub trap on signed overflow; addu, addiu, subu wrap silently. GCC emits only the u forms. Your core does not implement the trap.

Three immediate extensions

§3.2

addi, addiu, slti, sltiu and every load/store offset sign-extend. andi, ori, xori zero-extend. lui puts the 16 bits in the upper half and zeros the rest.

The %hi/%lo +1 rule

§3.2

lui + addiu builds a 32-bit address. If bit 15 of the low half is set, addiu subtracts, so the linker adds 1 to the upper half.

li and la are not instructions

§9.1

li is addiu (fits 16 signed) or ori (fits 16 unsigned) or lui + ori. la is lui + addiu with %hi/%lo. The dump shows the real words.

Shift counts

§3.3

sll/srl/sra/rotr take the count from sa, the variable forms from the low 5 bits of rs. The value is always rt. srl and rotr share funct 2 and differ in the rs field (0/1); srlv and rotrv differ in sa.

Loads choose the extension

§4.3

lb and lh sign-extend, lbu and lhu zero-extend. lw needs a 4-byte aligned address and lh/sh a 2-byte one; misaligned is an address error on real hardware and silently wrong on your core.

Little-endian

§4.1

The byte at the lowest address is bits 7..0 of the word. sb stores the low byte of rt.

The stack grows down

§4.4

Push is addiu $sp,$sp,-N then sw; $sp stays 8-byte aligned in o32. $fp is register 30, which objdump prints as s8.

o32 calling convention

§6.2

Arguments in $a0–$a3 plus a 16-byte argument area the caller always reserves; results in $v0/$v1; $t* and $a* are clobbered by a call; $s*, $sp, $fp, $gp survive it.

HI and LO

§7.1

mult/multu write the 64-bit product to HI:LO; div/divu put the quotient in LO and the remainder in HI. mul rd,rs,rt writes only the low 32 bits to rd. Divide by zero is undefined.

movz/movn read rd

§8.1

The old value of rd is a third source: movz rd,rs,rt means rd = (rt == 0) ? rs : rd.

ext and ins fields

§8.2

ext rt,rs,pos,size encodes size−1 in the rd field and pos in sa. ins rt,rs,pos,size encodes pos+size−1 in rd and pos in sa. seb/seh keep funct 32 and differ in sa (16/24).

clz of zero is 32

§8.2

clz rd,rs counts leading zero bits; clo counts leading ones. Both are SPECIAL2 (opcode 28).

jalr rd,rs

§5.3

The default rd is $ra. rs and rd must differ. jr and jalr targets must be 4-byte aligned.

Reserved registers

§2.2

$at is the assembler’s scratch register (pseudo-instructions may use it). $k0/$k1 belong to the kernel. $gp is set by crt0 but unused with -G0.

Reset vector 0xBFC00000

§9.2

Fixed by the architecture. crt0 is placed there by the linker script; it clears the registers, sets $gp and $sp, calls main and stores $v0 to the exit door.

The test machine’s doors

§4.1

Stores to 0x10003FF0 print a character, 0x10003FF4 an integer, 0x10003FF8 ends the run with an exit code. They are the top 16 bytes of the 16 KB data memory (the 4 KB scenarios use 0x10000FF0…).

What a dump shows

§9.1

objdump prints register names without $, s8 for $30, resolved branch targets with <symbol+offset>, and the aliases move, li, b, nop, beqz, bnez. Only the address and the word are in memory.

Generated from data/instructions/mips32.json, the table the book's opcode figures read, which was produced from the Carolyne MIPS32 description; every example word was assembled by the site's own assembler and decoded back. The register table is §2.2's. Print this page: the sidebar is left out.