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

  1. Registers & Conventions
  2. Instruction Formats
  3. Arithmetic Instructions
  4. Logical Instructions
  5. Shift Instructions
  6. Comparison (Set) Instructions
  7. Branch Instructions
  8. Jump Instructions
  9. Load Instructions
  10. Store Instructions
  11. Data Movement Instructions
  12. Floating-Point Instructions
  13. System & Exception Instructions
  14. Pseudo Instructions
  15. MARS System Calls
  16. Complete Example Programs
  17. 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

2. Instruction Formats

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.

I-Type (Immediate)

┌────────┬───────┬───────┬──────────────────────┐
│ 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.


3.3 ADDI — Add Immediate (with overflow trap)

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.


3.4 ADDIU — Add Immediate Unsigned (no overflow trap)

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

4.2 ANDI — Bitwise AND Immediate

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

4.4 ORI — Bitwise OR Immediate

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

4.6 XORI — Bitwise XOR Immediate

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)

6.3 SLTI — Set on Less Than Immediate (signed)

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

6.4 SLTIU — Set on Less Than Immediate Unsigned

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:

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

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.


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

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.


9.6 LUI — Load Upper Immediate

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, 00x00000000
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