A comprehensive reference covering every MIPS32 instruction with syntax, description, encoding format, and practical examples. Designed for students using MARS/SPIM simulators.
Table of Contents
- Registers & Conventions
- Instruction Formats
- Arithmetic Instructions
- Logical Instructions
- Shift Instructions
- Comparison (Set) Instructions
- Branch Instructions
- Jump Instructions
- Load Instructions
- Store Instructions
- Data Movement Instructions
- Floating-Point Instructions
- System & Exception Instructions
- Pseudo Instructions
- MARS System Calls
- Complete Example Programs
- Quick Reference Table
1. Registers & Conventions
1.1 General-Purpose Registers
| Register |
Number |
Name |
Purpose |
Preserved across calls? |
$zero |
0 |
— |
Hardwired to 0 |
N/A |
$at |
1 |
— |
Assembler temporary (reserved) |
No |
$v0–$v1 |
2–3 |
Value |
Function return values / syscall |
No |
$a0–$a3 |
4–7 |
Argument |
Function arguments |
No |
$t0–$t7 |
8–15 |
Temporary |
Temporaries (caller-saved) |
No |
$s0–$s7 |
16–23 |
Saved |
Saved values (callee-saved) |
Yes |
$t8–$t9 |
24–25 |
Temporary |
More temporaries |
No |
$k0–$k1 |
26–27 |
Kernel |
OS kernel reserved |
No |
$gp |
28 |
Global Pointer |
Global data access |
Yes |
$sp |
29 |
Stack Pointer |
Top of stack |
Yes |
$fp |
30 |
Frame Pointer |
Stack frame base |
Yes |
$ra |
31 |
Return Address |
Set by jal |
No |
1.2 Special Registers
| Register |
Purpose |
HI |
High 32 bits of multiply result; remainder of divide |
LO |
Low 32 bits of multiply result; quotient of divide |
PC |
Program Counter (not directly accessible) |
1.3 Data Directives
.data # Data segment
.text # Code segment
.globl main # Export symbol
.word 42, 100, -3 # 32-bit integers
.half 1000 # 16-bit half-word
.byte 'A', 0xFF # 8-bit bytes
.ascii "Hello" # String (no null terminator)
.asciiz "Hello" # Null-terminated string
.space 100 # Allocate 100 bytes (zeroed)
.float 3.14 # 32-bit IEEE 754 float
.double 2.71828 # 64-bit IEEE 754 double
.align 2 # Align to 2^2 = 4-byte boundary
All MIPS instructions are exactly 32 bits wide.
R-Type (Register)
┌────────┬───────┬───────┬───────┬───────┬────────┐
│ op (6) │ rs (5)│ rt (5)│ rd (5)│shamt 5│funct(6)│
└────────┴───────┴───────┴───────┴───────┴────────┘
Opcode Src 1 Src 2 Dest Shift Function
= 0x00 amount code
Used by: add, sub, and, or, sll, slt, jr, mult, div, etc.
┌────────┬───────┬───────┬──────────────────────┐
│ op (6) │ rs (5)│ rt (5)│ immediate (16) │
└────────┴───────┴───────┴──────────────────────┘
Opcode Src Dest 16-bit constant or
branch offset
Used by: addi, lw, sw, beq, bne, lui, andi, ori, etc.
J-Type (Jump)
┌────────┬──────────────────────────────────────┐
│ op (6) │ target (26) │
└────────┴──────────────────────────────────────┘
Opcode 26-bit word address (×4 = byte addr)
Used by: j, jal
3. Arithmetic Instructions
3.1 ADD — Add (with overflow trap)
|
Detail |
| Syntax |
add rd, rs, rt |
| Format |
R-Type — op=0x00, funct=0x20 |
| Operation |
rd = rs + rt (signed). Trap on overflow. |
| Flags/Exceptions |
Integer overflow exception if result overflows 32-bit signed range |
add $t2, $t0, $t1 # $t2 = $t0 + $t1
# If $t0 = 5, $t1 = 3 → $t2 = 8
# Overflow causes exception (trap)
3.2 ADDU — Add Unsigned (no overflow trap)
|
Detail |
| Syntax |
addu rd, rs, rt |
| Format |
R-Type — op=0x00, funct=0x21 |
| Operation |
rd = rs + rt. No overflow trap. |
addu $t2, $t0, $t1 # $t2 = $t0 + $t1 (no exception on overflow)
# Common use: pointer arithmetic where overflow trapping is undesirable
addu $sp, $sp, $t0 # Adjust stack pointer
add vs addu: "Unsigned" is misleading — addu works on both signed and unsigned. The only difference is that add triggers an exception on overflow while addu silently wraps around. In practice, addu is used more often.
|
Detail |
| Syntax |
addi rt, rs, imm |
| Format |
I-Type — op=0x08 |
| Operation |
rt = rs + sign_extend(imm). Trap on overflow. |
addi $t1, $t0, 100 # $t1 = $t0 + 100
addi $t0, $t0, -1 # $t0 = $t0 - 1 (decrement)
addi $sp, $sp, -8 # Allocate 8 bytes on stack
The 16-bit immediate is sign-extended to 32 bits. Range: -32768 to +32767.
|
Detail |
| Syntax |
addiu rt, rs, imm |
| Format |
I-Type — op=0x09 |
| Operation |
rt = rs + sign_extend(imm). No overflow trap. |
addiu $sp, $sp, -16 # Standard stack frame allocation
addiu $t0, $zero, 42 # $t0 = 42 (equivalent to li $t0, 42)
3.5 SUB — Subtract (with overflow trap)
|
Detail |
| Syntax |
sub rd, rs, rt |
| Format |
R-Type — op=0x00, funct=0x22 |
| Operation |
rd = rs - rt (signed). Trap on overflow. |
sub $t2, $t0, $t1 # $t2 = $t0 - $t1
# If $t0 = 10, $t1 = 3 → $t2 = 7
3.6 SUBU — Subtract Unsigned (no overflow trap)
|
Detail |
| Syntax |
subu rd, rs, rt |
| Format |
R-Type — op=0x00, funct=0x23 |
| Operation |
rd = rs - rt. No overflow trap. |
subu $t2, $t0, $t1 # $t2 = $t0 - $t1 (no exception on overflow)
There is no subi instruction in MIPS. Use addi with a negative immediate instead: addi $t0, $t0, -5.
3.7 MULT — Multiply (signed)
|
Detail |
| Syntax |
mult rs, rt |
| Format |
R-Type — op=0x00, funct=0x18 |
| Operation |
{HI, LO} = rs × rt (signed 64-bit result) |
# Multiply two 32-bit numbers → 64-bit result
mult $t0, $t1 # {HI, LO} = $t0 × $t1
mflo $t2 # $t2 = low 32 bits (the product if no overflow)
mfhi $t3 # $t3 = high 32 bits
# Example: 7 × 3 = 21
li $t0, 7
li $t1, 3
mult $t0, $t1 # HI = 0, LO = 21
mflo $t2 # $t2 = 21
3.8 MULTU — Multiply Unsigned
|
Detail |
| Syntax |
multu rs, rt |
| Format |
R-Type — op=0x00, funct=0x19 |
| Operation |
{HI, LO} = rs × rt (unsigned 64-bit result) |
multu $t0, $t1 # Unsigned: {HI, LO} = $t0 × $t1
mflo $t2 # $t2 = lower 32 bits
3.9 DIV — Divide (signed)
|
Detail |
| Syntax |
div rs, rt |
| Format |
R-Type — op=0x00, funct=0x1A |
| Operation |
LO = rs ÷ rt (quotient), HI = rs % rt (remainder) |
# 17 ÷ 5 = quotient 3, remainder 2
li $t0, 17
li $t1, 5
div $t0, $t1 # LO = 3, HI = 2
mflo $t2 # $t2 = 3 (quotient)
mfhi $t3 # $t3 = 2 (remainder)
# Division by zero: result is UNDEFINED (no hardware exception in MIPS)
# Programmer must check for zero divisor before calling div
3.10 DIVU — Divide Unsigned
|
Detail |
| Syntax |
divu rs, rt |
| Format |
R-Type — op=0x00, funct=0x1B |
| Operation |
LO = rs ÷ rt (unsigned quotient), HI = rs % rt (unsigned remainder) |
divu $t0, $t1 # Unsigned division
mflo $t2 # Unsigned quotient
mfhi $t3 # Unsigned remainder
4. Logical Instructions
4.1 AND — Bitwise AND
|
Detail |
| Syntax |
and rd, rs, rt |
| Format |
R-Type — op=0x00, funct=0x24 |
| Operation |
rd = rs & rt |
and $t2, $t0, $t1 # $t2 = $t0 AND $t1 (bitwise)
# Mask: extract lower 4 bits
li $t0, 0xAB # $t0 = 1010 1011
li $t1, 0x0F # $t1 = 0000 1111 (mask)
and $t2, $t0, $t1 # $t2 = 0000 1011 = 0x0B
|
Detail |
| Syntax |
andi rt, rs, imm |
| Format |
I-Type — op=0x0C |
| Operation |
rt = rs & zero_extend(imm) |
andi $t1, $t0, 0x00FF # $t1 = lower byte of $t0
andi $t1, $t0, 0x0001 # $t1 = least significant bit of $t0 (even/odd check)
Important: Unlike addi, the immediate in andi is zero-extended (not sign-extended).
4.3 OR — Bitwise OR
|
Detail |
| Syntax |
or rd, rs, rt |
| Format |
R-Type — op=0x00, funct=0x25 |
| Operation |
rd = rs | rt |
or $t2, $t0, $t1 # $t2 = $t0 OR $t1
# Set specific bits
li $t0, 0xA0 # $t0 = 1010 0000
li $t1, 0x05 # $t1 = 0000 0101
or $t2, $t0, $t1 # $t2 = 1010 0101 = 0xA5
|
Detail |
| Syntax |
ori rt, rs, imm |
| Format |
I-Type — op=0x0D |
| Operation |
rt = rs | zero_extend(imm) |
ori $t1, $t0, 0x000F # Set lower 4 bits of $t0
# Load 32-bit constant (assembler technique for lui+ori):
lui $t0, 0x1234 # $t0 = 0x12340000
ori $t0, $t0, 0x5678 # $t0 = 0x12345678
4.5 XOR — Bitwise Exclusive OR
|
Detail |
| Syntax |
xor rd, rs, rt |
| Format |
R-Type — op=0x00, funct=0x26 |
| Operation |
rd = rs ^ rt |
xor $t2, $t0, $t1 # $t2 = $t0 XOR $t1
# Toggle bits
li $t0, 0xFF00
li $t1, 0xFFFF
xor $t2, $t0, $t1 # $t2 = 0x00FF (bits flipped)
# Check equality (result is 0 if equal)
xor $t2, $t0, $t1
beq $t2, $zero, equal # If $t0 == $t1, branch
|
Detail |
| Syntax |
xori rt, rs, imm |
| Format |
I-Type — op=0x0E |
| Operation |
rt = rs ^ zero_extend(imm) |
xori $t1, $t0, 0x00FF # Toggle lower 8 bits of $t0
4.7 NOR — Bitwise NOR
|
Detail |
| Syntax |
nor rd, rs, rt |
| Format |
R-Type — op=0x00, funct=0x27 |
| Operation |
rd = ~(rs | rt) |
nor $t2, $t0, $t1 # $t2 = NOT($t0 OR $t1)
# Bitwise NOT (complement): NOR with $zero
nor $t1, $t0, $zero # $t1 = NOT($t0)
# Since $zero = 0, NOT(x OR 0) = NOT(x)
MIPS has no dedicated NOT instruction. Use nor rd, rs, $zero instead.
5. Shift Instructions
5.1 SLL — Shift Left Logical
|
Detail |
| Syntax |
sll rd, rt, shamt |
| Format |
R-Type — op=0x00, funct=0x00 |
| Operation |
rd = rt << shamt (fill with 0s from right) |
sll $t1, $t0, 2 # $t1 = $t0 << 2 (multiply by 4)
# If $t0 = 3 (0011) → $t1 = 12 (1100)
# Multiply by power of 2 (fast)
sll $t1, $t0, 3 # $t1 = $t0 × 8
# Array index: offset = index × 4 (for word array)
sll $t1, $t0, 2 # $t1 = $t0 × 4 (byte offset for word array)
sll $zero, $zero, 0 encodes as 0x00000000 — this is the NOP instruction.
5.2 SRL — Shift Right Logical
|
Detail |
| Syntax |
srl rd, rt, shamt |
| Format |
R-Type — op=0x00, funct=0x02 |
| Operation |
rd = rt >> shamt (fill with 0s from left, unsigned) |
srl $t1, $t0, 2 # $t1 = $t0 >> 2 (logical, unsigned divide by 4)
# If $t0 = 12 (1100) → $t1 = 3 (0011)
# Extract upper byte
srl $t1, $t0, 24 # $t1 = upper 8 bits of $t0
5.3 SRA — Shift Right Arithmetic
|
Detail |
| Syntax |
sra rd, rt, shamt |
| Format |
R-Type — op=0x00, funct=0x03 |
| Operation |
rd = rt >> shamt (fill with sign bit, signed divide) |
sra $t1, $t0, 2 # $t1 = $t0 >> 2 (arithmetic)
# Preserves the sign bit
# Signed divide by 4:
# If $t0 = -16 (0xFFFFFFF0)
sra $t1, $t0, 2 # $t1 = -4 (0xFFFFFFFC) — sign preserved!
# Compare with SRL:
srl $t1, $t0, 2 # $t1 = 0x3FFFFFFC — positive! (wrong for signed)
5.4 SLLV — Shift Left Logical Variable
|
Detail |
| Syntax |
sllv rd, rt, rs |
| Format |
R-Type — op=0x00, funct=0x04 |
| Operation |
rd = rt << rs[4:0] (shift amount from register) |
li $t0, 1
li $t1, 3
sllv $t2, $t0, $t1 # $t2 = 1 << 3 = 8
# Create bit mask at position n
li $t0, 1
sllv $t1, $t0, $a0 # $t1 = 1 << $a0 (bit mask at position $a0)
5.5 SRLV — Shift Right Logical Variable
|
Detail |
| Syntax |
srlv rd, rt, rs |
| Format |
R-Type — op=0x00, funct=0x06 |
| Operation |
rd = rt >> rs[4:0] (logical, shift amount from register) |
srlv $t2, $t0, $t1 # $t2 = $t0 >> $t1 (unsigned)
5.6 SRAV — Shift Right Arithmetic Variable
|
Detail |
| Syntax |
srav rd, rt, rs |
| Format |
R-Type — op=0x00, funct=0x07 |
| Operation |
rd = rt >> rs[4:0] (arithmetic, sign-preserving) |
srav $t2, $t0, $t1 # $t2 = $t0 >> $t1 (signed, preserves sign bit)
6. Comparison (Set) Instructions
6.1 SLT — Set on Less Than (signed)
|
Detail |
| Syntax |
slt rd, rs, rt |
| Format |
R-Type — op=0x00, funct=0x2A |
| Operation |
rd = (rs < rt) ? 1 : 0 (signed comparison) |
slt $t2, $t0, $t1 # if $t0 < $t1 (signed), $t2 = 1; else $t2 = 0
# Conditional branch: if $t0 < $t1, jump to LESS
slt $t2, $t0, $t1
bne $t2, $zero, LESS # Branch if $t2 == 1 (i.e., $t0 < $t1)
6.2 SLTU — Set on Less Than Unsigned
|
Detail |
| Syntax |
sltu rd, rs, rt |
| Format |
R-Type — op=0x00, funct=0x2B |
| Operation |
rd = (rs < rt) ? 1 : 0 (unsigned comparison) |
# Unsigned comparison
li $t0, 0xFFFFFFFF # As signed: -1. As unsigned: 4,294,967,295
li $t1, 1
slt $t2, $t0, $t1 # $t2 = 1 (signed: -1 < 1 → true)
sltu $t3, $t0, $t1 # $t3 = 0 (unsigned: 4B > 1 → false)
|
Detail |
| Syntax |
slti rt, rs, imm |
| Format |
I-Type — op=0x0A |
| Operation |
rt = (rs < sign_extend(imm)) ? 1 : 0 |
slti $t1, $t0, 100 # if $t0 < 100 (signed), $t1 = 1; else $t1 = 0
# Check if index is in bounds (0 to N-1)
slti $t1, $t0, 10 # $t1 = 1 if $t0 < 10
beq $t1, $zero, OUT_OF_BOUNDS
|
Detail |
| Syntax |
sltiu rt, rs, imm |
| Format |
I-Type — op=0x0B |
| Operation |
rt = (rs < sign_extend(imm)) ? 1 : 0 (unsigned comparison) |
sltiu $t1, $t0, 256 # Unsigned: if $t0 < 256, $t1 = 1
# Trick: test if register is zero
sltiu $t1, $t0, 1 # $t1 = 1 if $t0 == 0 (since 0 < 1 unsigned)
The immediate is still sign-extended before the unsigned comparison. So sltiu $t0, $t1, -1 compares against 0xFFFFFFFF.
7. Branch Instructions
All branch offsets are relative to PC+4 (the instruction after the branch). The 16-bit offset is in words (multiplied by 4 for byte address). The assembler handles this automatically when you use labels.
7.1 BEQ — Branch if Equal
|
Detail |
| Syntax |
beq rs, rt, label |
| Format |
I-Type — op=0x04 |
| Operation |
if (rs == rt) PC = PC + 4 + sign_extend(offset) × 4 |
beq $t0, $t1, EQUAL # if $t0 == $t1, jump to EQUAL
# Loop until counter reaches 10
LOOP:
# ... loop body ...
addi $t0, $t0, 1
li $t1, 10
beq $t0, $t1, DONE # Exit when counter == 10
j LOOP
DONE:
# Compare with zero
beq $t0, $zero, IS_ZERO # if $t0 == 0, branch
7.2 BNE — Branch if Not Equal
|
Detail |
| Syntax |
bne rs, rt, label |
| Format |
I-Type — op=0x05 |
| Operation |
if (rs != rt) PC = PC + 4 + sign_extend(offset) × 4 |
bne $t0, $t1, NOT_EQUAL # if $t0 != $t1, jump to NOT_EQUAL
# Standard counting loop
li $t0, 0 # counter = 0
LOOP:
# ... loop body ...
addi $t0, $t0, 1 # counter++
bne $t0, $t1, LOOP # Loop while counter != limit
7.3 BGTZ — Branch if Greater Than Zero
|
Detail |
| Syntax |
bgtz rs, label |
| Format |
I-Type — op=0x07, rt=0 |
| Operation |
if (rs > 0) branch (signed) |
bgtz $t0, POSITIVE # if $t0 > 0, jump to POSITIVE
7.4 BLEZ — Branch if Less Than or Equal to Zero
|
Detail |
| Syntax |
blez rs, label |
| Format |
I-Type — op=0x06, rt=0 |
| Operation |
if (rs <= 0) branch (signed) |
blez $t0, NON_POSITIVE # if $t0 <= 0, jump
# Countdown loop
li $t0, 10
LOOP:
# ... loop body ...
addi $t0, $t0, -1
bgtz $t0, LOOP # Loop while counter > 0
7.5 BGEZ — Branch if Greater Than or Equal to Zero
|
Detail |
| Syntax |
bgez rs, label |
| Format |
I-Type — op=0x01, rt=0x01 |
| Operation |
if (rs >= 0) branch (signed) |
bgez $t0, NON_NEGATIVE # if $t0 >= 0, jump
7.6 BLTZ — Branch if Less Than Zero
|
Detail |
| Syntax |
bltz rs, label |
| Format |
I-Type — op=0x01, rt=0x00 |
| Operation |
if (rs < 0) branch (signed) |
bltz $t0, NEGATIVE # if $t0 < 0, jump
# Absolute value
bgez $t0, SKIP # if $t0 >= 0, skip negation
sub $t0, $zero, $t0 # $t0 = -$t0
SKIP:
7.7 BGEZAL — Branch if >= 0 and Link
|
Detail |
| Syntax |
bgezal rs, label |
| Format |
I-Type — op=0x01, rt=0x11 |
| Operation |
if (rs >= 0) { $ra = PC + 8; branch } |
bgezal $t0, HANDLER # if $t0 >= 0, call HANDLER (save return addr in $ra)
# Unconditional call (since $zero >= 0 is always true)
bgezal $zero, FUNCTION # Always calls FUNCTION, sets $ra
7.8 BLTZAL — Branch if < 0 and Link
|
Detail |
| Syntax |
bltzal rs, label |
| Format |
I-Type — op=0x01, rt=0x10 |
| Operation |
if (rs < 0) { $ra = PC + 8; branch } |
bltzal $t0, NEG_HANDLER # if $t0 < 0, call NEG_HANDLER
Branch delay slot: In real MIPS hardware, the instruction immediately after a branch is always executed (the "delay slot"). MARS/SPIM simulators disable this by default. Enable with Settings → "Delayed branching."
8. Jump Instructions
8.1 J — Jump
|
Detail |
| Syntax |
j target |
| Format |
J-Type — op=0x02 |
| Operation |
PC = { PC+4[31:28], target, 00 } |
j LOOP # Unconditional jump to LOOP
# Infinite loop
FOREVER:
# ... do something ...
j FOREVER
The 26-bit target is a word address. Combined with the upper 4 bits of PC+4, it can address any location within the current 256 MB region.
8.2 JAL — Jump and Link
|
Detail |
| Syntax |
jal target |
| Format |
J-Type — op=0x03 |
| Operation |
$ra = PC + 4; PC = { PC+4[31:28], target, 00 } |
jal FUNCTION # Call FUNCTION, return address saved in $ra
# Function call sequence:
li $a0, 5 # Argument: n = 5
jal FACTORIAL # Call factorial(5)
move $s0, $v0 # Save result
8.3 JR — Jump Register
|
Detail |
| Syntax |
jr rs |
| Format |
R-Type — op=0x00, funct=0x08 |
| Operation |
PC = rs |
jr $ra # Return from function (standard return)
# Jump table (switch-case implementation)
sll $t0, $a0, 2 # $t0 = case_number × 4
la $t1, JUMP_TABLE
add $t1, $t1, $t0
lw $t1, 0($t1) # Load target address
jr $t1 # Jump to case handler
8.4 JALR — Jump and Link Register
|
Detail |
| Syntax |
jalr rd, rs or jalr rs (rd defaults to $ra) |
| Format |
R-Type — op=0x00, funct=0x09 |
| Operation |
rd = PC + 4; PC = rs |
# Call function via pointer
la $t0, MY_FUNCTION # Load function address
jalr $t0 # Call it, return address in $ra
# Explicit return register
jalr $t9, $t0 # $t9 = return address, jump to $t0
9. Load Instructions
All loads use base + offset addressing: MEM[$rs + sign_extend(offset)].
9.1 LW — Load Word (32-bit)
|
Detail |
| Syntax |
lw rt, offset(rs) |
| Format |
I-Type — op=0x23 |
| Operation |
rt = MEM[rs + sign_extend(offset)] (4 bytes) |
lw $t0, 0($sp) # Load word from top of stack
lw $t1, 4($sp) # Load word from stack + 4
lw $t0, myVar # Load global variable (pseudo: assembler generates lui+lw)
# Array access: A[i]
la $t0, A # $t0 = base address of array A
sll $t1, $s0, 2 # $t1 = i × 4 (word offset)
add $t0, $t0, $t1 # $t0 = &A[i]
lw $t2, 0($t0) # $t2 = A[i]
Alignment: Address must be a multiple of 4. Unaligned access causes an exception.
9.2 LH — Load Halfword (16-bit, sign-extended)
|
Detail |
| Syntax |
lh rt, offset(rs) |
| Format |
I-Type — op=0x21 |
| Operation |
rt = sign_extend(MEM[rs + offset]) (2 bytes → 32 bits) |
lh $t0, 0($s0) # Load 16-bit signed value, sign-extend to 32 bits
# If MEM = 0xFF80, $t0 = 0xFFFFFF80 (-128)
9.3 LHU — Load Halfword Unsigned (16-bit, zero-extended)
|
Detail |
| Syntax |
lhu rt, offset(rs) |
| Format |
I-Type — op=0x25 |
| Operation |
rt = zero_extend(MEM[rs + offset]) (2 bytes → 32 bits) |
lhu $t0, 0($s0) # Load 16-bit value, zero-extend to 32 bits
# If MEM = 0xFF80, $t0 = 0x0000FF80 (65408)
9.4 LB — Load Byte (8-bit, sign-extended)
|
Detail |
| Syntax |
lb rt, offset(rs) |
| Format |
I-Type — op=0x20 |
| Operation |
rt = sign_extend(MEM[rs + offset]) (1 byte → 32 bits) |
lb $t0, 0($s0) # Load byte, sign-extend
# If MEM = 0x80, $t0 = 0xFFFFFF80 (-128)
# String processing: load character
la $s0, myString
lb $t0, 0($s0) # $t0 = first character (sign-extended)
9.5 LBU — Load Byte Unsigned (8-bit, zero-extended)
|
Detail |
| Syntax |
lbu rt, offset(rs) |
| Format |
I-Type — op=0x24 |
| Operation |
rt = zero_extend(MEM[rs + offset]) (1 byte → 32 bits) |
lbu $t0, 0($s0) # Load byte, zero-extend
# If MEM = 0x80, $t0 = 0x00000080 (128)
# ASCII character processing (always use lbu for chars)
la $s0, myString
lbu $t0, 0($s0) # $t0 = first character (0–255)
lbu vs lb: For ASCII characters (0–127), both work. For bytes > 127, lb gives a negative number while lbu gives the correct unsigned value. Always use lbu for character/byte data.
|
Detail |
| Syntax |
lui rt, imm |
| Format |
I-Type — op=0x0F |
| Operation |
rt = imm << 16 (lower 16 bits set to 0) |
lui $t0, 0x1234 # $t0 = 0x12340000
# Build 32-bit constant 0x12345678:
lui $t0, 0x1234 # $t0 = 0x12340000
ori $t0, $t0, 0x5678 # $t0 = 0x12345678
# This is what the pseudo-instruction "li $t0, 0x12345678" expands to
10. Store Instructions
10.1 SW — Store Word (32-bit)
|
Detail |
| Syntax |
sw rt, offset(rs) |
| Format |
I-Type — op=0x2B |
| Operation |
MEM[rs + sign_extend(offset)] = rt (4 bytes) |
sw $t0, 0($sp) # Store $t0 to top of stack
sw $ra, 4($sp) # Save return address to stack
# Array store: A[i] = value
la $t0, A
sll $t1, $s0, 2 # $t1 = i × 4
add $t0, $t0, $t1
sw $t2, 0($t0) # A[i] = $t2
10.2 SH — Store Halfword (lower 16 bits)
|
Detail |
| Syntax |
sh rt, offset(rs) |
| Format |
I-Type — op=0x29 |
| Operation |
MEM[rs + offset] = rt[15:0] (2 bytes) |
sh $t0, 0($s0) # Store lower 16 bits of $t0
10.3 SB — Store Byte (lower 8 bits)
|
Detail |
| Syntax |
sb rt, offset(rs) |
| Format |
I-Type — op=0x28 |
| Operation |
MEM[rs + offset] = rt[7:0] (1 byte) |
sb $t0, 0($s0) # Store lowest byte of $t0
# Store a character
li $t0, 'A' # $t0 = 65 (ASCII 'A')
sb $t0, 0($s0) # Store 'A' to memory
11. Data Movement Instructions
11.1 MFHI — Move From HI
|
Detail |
| Syntax |
mfhi rd |
| Format |
R-Type — op=0x00, funct=0x10 |
| Operation |
rd = HI |
mult $t0, $t1
mfhi $t2 # $t2 = high 32 bits of product
# Or: $t2 = remainder after div
11.2 MFLO — Move From LO
|
Detail |
| Syntax |
mflo rd |
| Format |
R-Type — op=0x00, funct=0x12 |
| Operation |
rd = LO |
mult $t0, $t1
mflo $t2 # $t2 = low 32 bits of product
# Or: $t2 = quotient after div
11.3 MTHI — Move To HI
|
Detail |
| Syntax |
mthi rs |
| Format |
R-Type — op=0x00, funct=0x11 |
| Operation |
HI = rs |
mthi $t0 # HI = $t0
11.4 MTLO — Move To LO
|
Detail |
| Syntax |
mtlo rs |
| Format |
R-Type — op=0x00, funct=0x13 |
| Operation |
LO = rs |
mtlo $t0 # LO = $t0
11.5 MFC0 — Move From Coprocessor 0
|
Detail |
| Syntax |
mfc0 rt, rd |
| Operation |
rt = Coprocessor0[rd] |
mfc0 $t0, $12 # $t0 = Status register (CP0 register 12)
mfc0 $t0, $13 # $t0 = Cause register (CP0 register 13)
mfc0 $t0, $14 # $t0 = EPC (Exception PC, CP0 register 14)
11.6 MTC0 — Move To Coprocessor 0
|
Detail |
| Syntax |
mtc0 rs, rd |
| Operation |
Coprocessor0[rd] = rs |
mtc0 $t0, $12 # Status register = $t0 (enable/disable interrupts)
12. Floating-Point Instructions
MIPS uses Coprocessor 1 for floating-point. It has 32 floating-point registers: $f0–$f31.
12.1 Conventions
| Register |
Purpose |
$f0–$f3 |
Return values |
$f4–$f11 |
Temporaries |
$f12–$f15 |
Arguments |
$f20–$f31 |
Saved (callee-saved) |
For double-precision, register pairs are used: $f0/$f1, $f2/$f3, etc.
12.2 Load / Store
| Instruction |
Syntax |
Operation |
lwc1 |
lwc1 ft, offset(rs) |
Load 32-bit float from memory |
swc1 |
swc1 ft, offset(rs) |
Store 32-bit float to memory |
ldc1 |
ldc1 ft, offset(rs) |
Load 64-bit double from memory |
sdc1 |
sdc1 ft, offset(rs) |
Store 64-bit double to memory |
l.s |
l.s ft, offset(rs) |
Pseudo: load single-precision float |
s.s |
s.s ft, offset(rs) |
Pseudo: store single-precision float |
l.d |
l.d ft, offset(rs) |
Pseudo: load double-precision float |
s.d |
s.d ft, offset(rs) |
Pseudo: store double-precision float |
.data
pi: .float 3.14159
e: .double 2.71828
.text
l.s $f0, pi # Load single float
l.d $f2, e # Load double into $f2/$f3
s.s $f0, result # Store single float
12.3 Arithmetic
| Instruction |
Syntax |
Operation |
add.s |
add.s fd, fs, ft |
fd = fs + ft (single) |
add.d |
add.d fd, fs, ft |
fd = fs + ft (double) |
sub.s |
sub.s fd, fs, ft |
fd = fs - ft (single) |
sub.d |
sub.d fd, fs, ft |
fd = fs - ft (double) |
mul.s |
mul.s fd, fs, ft |
fd = fs × ft (single) |
mul.d |
mul.d fd, fs, ft |
fd = fs × ft (double) |
div.s |
div.s fd, fs, ft |
fd = fs ÷ ft (single) |
div.d |
div.d fd, fs, ft |
fd = fs ÷ ft (double) |
abs.s |
abs.s fd, fs |
fd = |fs| (single) |
abs.d |
abs.d fd, fs |
fd = |fs| (double) |
neg.s |
neg.s fd, fs |
fd = -fs (single) |
neg.d |
neg.d fd, fs |
fd = -fs (double) |
sqrt.s |
sqrt.s fd, fs |
fd = √fs (single) |
sqrt.d |
sqrt.d fd, fs |
fd = √fs (double) |
# Calculate area = π × r²
l.s $f0, pi # $f0 = 3.14159
l.s $f2, radius # $f2 = r
mul.s $f4, $f2, $f2 # $f4 = r × r = r²
mul.s $f6, $f0, $f4 # $f6 = π × r²
s.s $f6, area # Store result
12.4 Comparison & Branch
| Instruction |
Syntax |
Operation |
c.eq.s |
c.eq.s fs, ft |
Set FP flag if fs == ft |
c.lt.s |
c.lt.s fs, ft |
Set FP flag if fs < ft |
c.le.s |
c.le.s fs, ft |
Set FP flag if fs <= ft |
c.eq.d |
c.eq.d fs, ft |
Double-precision version |
c.lt.d |
c.lt.d fs, ft |
Double-precision version |
c.le.d |
c.le.d fs, ft |
Double-precision version |
bc1t |
bc1t label |
Branch if FP flag is true |
bc1f |
bc1f label |
Branch if FP flag is false |
# if (x < y) goto LESS
l.s $f0, x
l.s $f2, y
c.lt.s $f0, $f2 # Compare: is x < y?
bc1t LESS # Branch if true
# if (a == b) goto EQUAL
c.eq.d $f0, $f2 # Double precision compare
bc1t EQUAL
12.5 Conversion
| Instruction |
Syntax |
Operation |
cvt.s.w |
cvt.s.w fd, fs |
Integer → single float |
cvt.d.w |
cvt.d.w fd, fs |
Integer → double float |
cvt.w.s |
cvt.w.s fd, fs |
Single float → integer (truncate) |
cvt.w.d |
cvt.w.d fd, fs |
Double float → integer (truncate) |
cvt.s.d |
cvt.s.d fd, fs |
Double → single |
cvt.d.s |
cvt.d.s fd, fs |
Single → double |
# Convert integer to float
mtc1 $t0, $f0 # Move integer from $t0 to FP register $f0
cvt.s.w $f2, $f0 # Convert integer in $f0 to float in $f2
# Convert float to integer
cvt.w.s $f4, $f2 # Convert float in $f2 to integer in $f4
mfc1 $t1, $f4 # Move result to integer register $t1
12.6 Move Between Integer and FP Registers
| Instruction |
Syntax |
Operation |
mtc1 |
mtc1 rt, fs |
fs = rt (integer → FP register, raw bits) |
mfc1 |
mfc1 rt, fs |
rt = fs (FP register → integer, raw bits) |
mov.s |
mov.s fd, fs |
fd = fs (copy FP register, single) |
mov.d |
mov.d fd, fs |
fd = fs (copy FP register, double) |
mtc1 $t0, $f0 # Copy raw bits from $t0 to $f0
mfc1 $t0, $f0 # Copy raw bits from $f0 to $t0
mov.s $f2, $f0 # $f2 = $f0 (single precision copy)
13. System & Exception Instructions
13.1 SYSCALL — System Call
|
Detail |
| Syntax |
syscall |
| Format |
R-Type — op=0x00, funct=0x0C (special encoding) |
| Operation |
Invoke OS service. Service number in $v0, arguments in $a0–$a3. |
# Print integer
li $v0, 1 # syscall 1 = print integer
li $a0, 42 # integer to print
syscall # prints "42"
# Print string
li $v0, 4 # syscall 4 = print string
la $a0, message # address of null-terminated string
syscall
# Exit program
li $v0, 10 # syscall 10 = exit
syscall
13.2 BREAK — Breakpoint
|
Detail |
| Syntax |
break code |
| Operation |
Cause a breakpoint exception. Used for debugging. |
break 0 # Trigger breakpoint exception
13.3 NOP — No Operation
|
Detail |
| Syntax |
nop |
| Encoding |
sll $zero, $zero, 0 → 0x00000000 |
| Operation |
Does nothing. Advances PC by 4. |
nop # Waste one cycle
# Used in delay slots or for alignment
14. Pseudo Instructions
Pseudo instructions are not real hardware instructions. The assembler translates them into one or more real instructions. They make assembly code more readable.
14.1 Data Loading
| Pseudo Instruction |
Expansion |
Description |
li rd, imm32 |
lui rd, upper16 + ori rd, rd, lower16 |
Load 32-bit immediate |
la rd, label |
lui rd, upper16 + ori rd, rd, lower16 |
Load address of label |
li $t0, 0x12345678 # Expands to:
# lui $t0, 0x1234
# ori $t0, $t0, 0x5678
li $t0, 42 # Small constant, expands to:
# addiu $t0, $zero, 42
la $t0, myArray # Load address of myArray
14.2 Move
| Pseudo Instruction |
Expansion |
Description |
move rd, rs |
addu rd, rs, $zero |
Copy register |
move $t0, $t1 # $t0 = $t1
# Expands to: addu $t0, $t1, $zero
14.3 Branch Comparisons
| Pseudo Instruction |
Expansion |
Description |
blt rs, rt, label |
slt $at, rs, rt + bne $at, $zero, label |
Branch if less than |
bgt rs, rt, label |
slt $at, rt, rs + bne $at, $zero, label |
Branch if greater than |
ble rs, rt, label |
slt $at, rt, rs + beq $at, $zero, label |
Branch if less or equal |
bge rs, rt, label |
slt $at, rs, rt + beq $at, $zero, label |
Branch if greater or equal |
# These are NOT real instructions — assembler expands them
blt $t0, $t1, LESS # if $t0 < $t1, branch
bgt $t0, $t1, GREATER # if $t0 > $t1, branch
ble $t0, $t1, LESS_EQ # if $t0 <= $t1, branch
bge $t0, $t1, GREATER_EQ # if $t0 >= $t1, branch
14.4 Arithmetic
| Pseudo Instruction |
Expansion |
Description |
mul rd, rs, rt |
mult rs, rt + mflo rd |
Multiply (result in rd) |
div rd, rs, rt |
div rs, rt + mflo rd |
Divide (quotient in rd) |
rem rd, rs, rt |
div rs, rt + mfhi rd |
Remainder in rd |
abs rd, rs |
bgez + sub sequence |
Absolute value |
neg rd, rs |
sub rd, $zero, rs |
Negate |
not rd, rs |
nor rd, rs, $zero |
Bitwise NOT |
mul $t2, $t0, $t1 # $t2 = $t0 × $t1
div $t2, $t0, $t1 # $t2 = $t0 / $t1
rem $t2, $t0, $t1 # $t2 = $t0 % $t1
neg $t1, $t0 # $t1 = -$t0
not $t1, $t0 # $t1 = ~$t0
14.5 Set Comparisons
| Pseudo Instruction |
Expansion |
Description |
seq rd, rs, rt |
xor + sltiu + xori sequence |
Set if equal |
sne rd, rs, rt |
xor + sltu sequence |
Set if not equal |
sge rd, rs, rt |
slt + xori sequence |
Set if greater or equal |
sgt rd, rs, rt |
slt rd, rt, rs |
Set if greater than |
sle rd, rs, rt |
slt + xori sequence |
Set if less or equal |
seq $t2, $t0, $t1 # $t2 = ($t0 == $t1) ? 1 : 0
sne $t2, $t0, $t1 # $t2 = ($t0 != $t1) ? 1 : 0
sgt $t2, $t0, $t1 # $t2 = ($t0 > $t1) ? 1 : 0
sge $t2, $t0, $t1 # $t2 = ($t0 >= $t1) ? 1 : 0
sle $t2, $t0, $t1 # $t2 = ($t0 <= $t1) ? 1 : 0
15. MARS System Calls
The MARS simulator provides these services via syscall:
$v0 |
Service |
Arguments |
Result |
| 1 |
Print integer |
$a0 = integer |
Printed to console |
| 2 |
Print float |
$f12 = float |
Printed to console |
| 3 |
Print double |
$f12 = double |
Printed to console |
| 4 |
Print string |
$a0 = address of string |
Printed to console |
| 5 |
Read integer |
— |
$v0 = integer read |
| 6 |
Read float |
— |
$f0 = float read |
| 7 |
Read double |
— |
$f0 = double read |
| 8 |
Read string |
$a0 = buffer addr, $a1 = max length |
String stored at $a0 |
| 9 |
Sbrk (allocate heap) |
$a0 = number of bytes |
$v0 = address of allocated memory |
| 10 |
Exit |
— |
Program terminates |
| 11 |
Print character |
$a0 = character (ASCII) |
Printed to console |
| 12 |
Read character |
— |
$v0 = character read |
| 34 |
Print integer (hex) |
$a0 = integer |
Printed as hex |
| 35 |
Print integer (binary) |
$a0 = integer |
Printed as binary |
| 36 |
Print integer (unsigned) |
$a0 = unsigned int |
Printed as unsigned |
# Read integer from user and print it doubled
li $v0, 5 # syscall: read integer
syscall
move $t0, $v0 # $t0 = input value
add $t0, $t0, $t0 # $t0 = $t0 × 2
li $v0, 1 # syscall: print integer
move $a0, $t0
syscall
# Print newline character
li $v0, 11 # syscall: print char
li $a0, '\n' # newline
syscall
# Allocate 100 bytes of heap memory
li $v0, 9 # syscall: sbrk
li $a0, 100
syscall # $v0 = pointer to allocated block
16. Complete Example Programs
16.1 Hello World
.data
msg: .asciiz "Hello, World!\n"
.text
.globl main
main:
li $v0, 4 # print string
la $a0, msg
syscall
li $v0, 10 # exit
syscall
16.2 Sum of Array
# Calculate sum of an integer array
.data
array: .word 10, 20, 30, 40, 50
size: .word 5
result: .asciiz "Sum = "
.text
.globl main
main:
la $t0, array # $t0 = base address of array
lw $t1, size # $t1 = array size (5)
li $t2, 0 # $t2 = sum = 0
li $t3, 0 # $t3 = index i = 0
loop:
beq $t3, $t1, done # if i == size, exit loop
sll $t4, $t3, 2 # $t4 = i × 4 (byte offset)
add $t4, $t0, $t4 # $t4 = &array[i]
lw $t5, 0($t4) # $t5 = array[i]
add $t2, $t2, $t5 # sum += array[i]
addi $t3, $t3, 1 # i++
j loop
done:
li $v0, 4 # print "Sum = "
la $a0, result
syscall
li $v0, 1 # print integer
move $a0, $t2
syscall
li $v0, 10 # exit
syscall
16.3 Factorial (Recursive Function)
# Recursive factorial: n! = n × (n-1)!
.data
prompt: .asciiz "Enter n: "
result: .asciiz "n! = "
.text
.globl main
main:
li $v0, 4
la $a0, prompt
syscall
li $v0, 5 # Read integer
syscall
move $a0, $v0 # $a0 = n
jal factorial # Call factorial(n)
move $s0, $v0 # $s0 = result
li $v0, 4
la $a0, result
syscall
li $v0, 1
move $a0, $s0
syscall
li $v0, 10
syscall
# int factorial(int n)
# $a0 = n, returns result in $v0
factorial:
addi $sp, $sp, -8 # Allocate stack frame
sw $ra, 4($sp) # Save return address
sw $a0, 0($sp) # Save argument n
slti $t0, $a0, 2 # if n < 2
beq $t0, $zero, recurse
li $v0, 1 # base case: return 1
addi $sp, $sp, 8 # Deallocate stack
jr $ra # Return
recurse:
addi $a0, $a0, -1 # n - 1
jal factorial # factorial(n - 1), result in $v0
lw $a0, 0($sp) # Restore original n
lw $ra, 4($sp) # Restore return address
addi $sp, $sp, 8 # Deallocate stack
mult $a0, $v0 # n × factorial(n-1)
mflo $v0 # $v0 = n!
jr $ra # Return
16.4 Fibonacci (Iterative)
# Print first N Fibonacci numbers
.data
prompt: .asciiz "How many Fibonacci numbers? "
space: .asciiz " "
newline:.asciiz "\n"
.text
.globl main
main:
li $v0, 4
la $a0, prompt
syscall
li $v0, 5 # Read N
syscall
move $s0, $v0 # $s0 = N
li $s1, 0 # $s1 = fib(0) = 0
li $s2, 1 # $s2 = fib(1) = 1
li $s3, 0 # $s3 = counter
fib_loop:
beq $s3, $s0, fib_done # if counter == N, done
li $v0, 1 # Print current fib number
move $a0, $s1
syscall
li $v0, 4 # Print space
la $a0, space
syscall
add $t0, $s1, $s2 # next = fib(n-1) + fib(n-2)
move $s1, $s2 # shift: fib(n-2) = fib(n-1)
move $s2, $t0 # shift: fib(n-1) = next
addi $s3, $s3, 1 # counter++
j fib_loop
fib_done:
li $v0, 4
la $a0, newline
syscall
li $v0, 10
syscall
16.5 String Length Function
# Calculate and print the length of a string
.data
mystr: .asciiz "Hello, MIPS Assembly!"
msg: .asciiz "Length = "
.text
.globl main
main:
la $a0, mystr # $a0 = address of string
jal strlen # Call strlen
move $s0, $v0 # $s0 = length
li $v0, 4
la $a0, msg
syscall
li $v0, 1
move $a0, $s0
syscall
li $v0, 10
syscall
# int strlen(char *s)
# $a0 = pointer to string, returns length in $v0
strlen:
move $t0, $a0 # $t0 = current pointer
li $v0, 0 # $v0 = length = 0
strlen_loop:
lbu $t1, 0($t0) # Load byte (character)
beq $t1, $zero, strlen_done # If null terminator, done
addi $v0, $v0, 1 # length++
addi $t0, $t0, 1 # pointer++
j strlen_loop
strlen_done:
jr $ra # Return length in $v0
16.6 Bubble Sort
# Bubble sort an array of integers
.data
array: .word 64, 25, 12, 22, 11
size: .word 5
before: .asciiz "Before: "
after: .asciiz "After: "
space: .asciiz " "
nl: .asciiz "\n"
.text
.globl main
main:
la $a0, before
li $v0, 4
syscall
la $a0, array
lw $a1, size
jal print_array
la $a0, array # Sort the array
lw $a1, size
jal bubble_sort
la $a0, after
li $v0, 4
syscall
la $a0, array
lw $a1, size
jal print_array
li $v0, 10
syscall
# void bubble_sort(int *arr, int n)
# $a0 = array base, $a1 = size
bubble_sort:
addi $sp, $sp, -4
sw $ra, 0($sp)
addi $t0, $a1, -1 # $t0 = n - 1 (outer loop limit)
outer:
blez $t0, sort_done # if i <= 0, done
li $t1, 0 # $t1 = j (inner index)
li $t6, 0 # $t6 = swapped flag
inner:
bge $t1, $t0, next_pass # if j >= i, next pass
sll $t2, $t1, 2 # $t2 = j × 4
add $t3, $a0, $t2 # $t3 = &arr[j]
lw $t4, 0($t3) # $t4 = arr[j]
lw $t5, 4($t3) # $t5 = arr[j+1]
ble $t4, $t5, no_swap # if arr[j] <= arr[j+1], skip swap
sw $t5, 0($t3) # arr[j] = arr[j+1]
sw $t4, 4($t3) # arr[j+1] = arr[j]
li $t6, 1 # swapped = true
no_swap:
addi $t1, $t1, 1 # j++
j inner
next_pass:
beq $t6, $zero, sort_done # if no swaps, already sorted
addi $t0, $t0, -1 # i--
j outer
sort_done:
lw $ra, 0($sp)
addi $sp, $sp, 4
jr $ra
# void print_array(int *arr, int n)
print_array:
addi $sp, $sp, -12
sw $ra, 8($sp)
sw $s0, 4($sp)
sw $s1, 0($sp)
move $s0, $a0 # $s0 = array base
move $s1, $a1 # $s1 = size
li $t0, 0 # $t0 = index
pa_loop:
beq $t0, $s1, pa_done
sll $t1, $t0, 2
add $t1, $s0, $t1
lw $a0, 0($t1)
li $v0, 1
syscall
li $v0, 4
la $a0, space
syscall
addi $t0, $t0, 1
j pa_loop
pa_done:
li $v0, 4
la $a0, nl
syscall
lw $s1, 0($sp)
lw $s0, 4($sp)
lw $ra, 8($sp)
addi $sp, $sp, 12
jr $ra
17. Quick Reference Table
17.1 All Instructions by Category
| Category |
Instructions |
| Arithmetic |
add, addu, addi, addiu, sub, subu, mult, multu, div, divu |
| Logical |
and, andi, or, ori, xor, xori, nor |
| Shift |
sll, srl, sra, sllv, srlv, srav |
| Comparison |
slt, sltu, slti, sltiu |
| Branch |
beq, bne, bgtz, blez, bgez, bltz, bgezal, bltzal |
| Jump |
j, jal, jr, jalr |
| Load |
lw, lh, lhu, lb, lbu, lui |
| Store |
sw, sh, sb |
| Data Move |
mfhi, mflo, mthi, mtlo, mfc0, mtc0 |
| FP Arith |
add.s/d, sub.s/d, mul.s/d, div.s/d, abs.s/d, neg.s/d, sqrt.s/d |
| FP Compare |
c.eq.s/d, c.lt.s/d, c.le.s/d, bc1t, bc1f |
| FP Move |
mov.s/d, mtc1, mfc1, cvt.*.* |
| FP Load/Store |
lwc1, swc1, ldc1, sdc1, l.s, s.s, l.d, s.d |
| System |
syscall, break, nop |
| Pseudo |
li, la, move, blt, bgt, ble, bge, mul, div(3-op), rem, neg, not, abs, seq, sne, sge, sgt, sle |
17.2 Opcode / Funct Quick Lookup
| Instruction |
Type |
op (hex) |
funct (hex) |
add |
R |
0x00 |
0x20 |
addu |
R |
0x00 |
0x21 |
sub |
R |
0x00 |
0x22 |
subu |
R |
0x00 |
0x23 |
and |
R |
0x00 |
0x24 |
or |
R |
0x00 |
0x25 |
xor |
R |
0x00 |
0x26 |
nor |
R |
0x00 |
0x27 |
slt |
R |
0x00 |
0x2A |
sltu |
R |
0x00 |
0x2B |
sll |
R |
0x00 |
0x00 |
srl |
R |
0x00 |
0x02 |
sra |
R |
0x00 |
0x03 |
sllv |
R |
0x00 |
0x04 |
srlv |
R |
0x00 |
0x06 |
srav |
R |
0x00 |
0x07 |
mult |
R |
0x00 |
0x18 |
multu |
R |
0x00 |
0x19 |
div |
R |
0x00 |
0x1A |
divu |
R |
0x00 |
0x1B |
mfhi |
R |
0x00 |
0x10 |
mflo |
R |
0x00 |
0x12 |
mthi |
R |
0x00 |
0x11 |
mtlo |
R |
0x00 |
0x13 |
jr |
R |
0x00 |
0x08 |
jalr |
R |
0x00 |
0x09 |
syscall |
R |
0x00 |
0x0C |
break |
R |
0x00 |
0x0D |
addi |
I |
0x08 |
— |
addiu |
I |
0x09 |
— |
slti |
I |
0x0A |
— |
sltiu |
I |
0x0B |
— |
andi |
I |
0x0C |
— |
ori |
I |
0x0D |
— |
xori |
I |
0x0E |
— |
lui |
I |
0x0F |
— |
lw |
I |
0x23 |
— |
lh |
I |
0x21 |
— |
lhu |
I |
0x25 |
— |
lb |
I |
0x20 |
— |
lbu |
I |
0x24 |
— |
sw |
I |
0x2B |
— |
sh |
I |
0x29 |
— |
sb |
I |
0x28 |
— |
beq |
I |
0x04 |
— |
bne |
I |
0x05 |
— |
bgtz |
I |
0x07 |
— |
blez |
I |
0x06 |
— |
j |
J |
0x02 |
— |
jal |
J |
0x03 |
— |
17.3 Common Patterns
# ── if-else ──
# if ($s0 == $s1) { A } else { B }
bne $s0, $s1, else_branch
# ... A ...
j end_if
else_branch:
# ... B ...
end_if:
# ── while loop ──
# while ($s0 < $s1) { body; $s0++; }
while:
bge $s0, $s1, end_while # pseudo: if $s0 >= $s1, exit
# ... body ...
addi $s0, $s0, 1
j while
end_while:
# ── for loop ──
# for (i = 0; i < N; i++) { body }
li $t0, 0 # i = 0
for_loop:
bge $t0, $s0, for_done # if i >= N, exit
# ... body ...
addi $t0, $t0, 1 # i++
j for_loop
for_done:
# ── function call convention ──
callee:
addi $sp, $sp, -12 # Allocate frame
sw $ra, 8($sp) # Save return address
sw $s0, 4($sp) # Save callee-saved registers
sw $s1, 0($sp)
# ... function body ...
lw $s1, 0($sp) # Restore callee-saved registers
lw $s0, 4($sp)
lw $ra, 8($sp) # Restore return address
addi $sp, $sp, 12 # Deallocate frame
jr $ra # Return
# ── array access: A[i] ──
la $t0, A # base address
sll $t1, $s0, 2 # offset = i × 4
add $t0, $t0, $t1 # address = base + offset
lw $t2, 0($t0) # load A[i]
sw $t3, 0($t0) # store to A[i]
# ── 2D array: A[i][j] (row-major, N columns) ──
mult $s0, $s2 # i × N
mflo $t0
add $t0, $t0, $s1 # i × N + j
sll $t0, $t0, 2 # × 4 (byte offset)
la $t1, A
add $t1, $t1, $t0
lw $t2, 0($t1) # A[i][j]
# ── swap two registers ──
xor $t0, $t0, $t1 # swap without temporary
xor $t1, $t0, $t1
xor $t0, $t0, $t1