The Ultimate Guide to MIPS Assembly MIPS 汇编终极指南
Understanding registers is the foundation of MIPS. Memorize the difference between temporary ($t) and saved ($s) registers. 理解寄存器是 MIPS 的基础。务必背下临时寄存器 ($t) 和保存寄存器 ($s) 的区别。
| Reg寄存器 | Name编号 | Usage Rule用途与特性 |
|---|---|---|
$zero |
0 | Constant 0. Cannot be changed. Useful for clearing or comparing. 恒为 0。无法修改。常用于清零或比较。 |
$v0-$v1 |
2-3 | Return values & Syscall numbers. Modified after calls. 函数返回值/系统调用号。调用后值会改变。 |
$a0-$a3 |
4-7 | Function arguments. Set before calling a function. 函数参数。调用函数前设置。 |
$t0-$t9 |
8-15, 24-25 | Temporary. Value MAY CHANGE after function call. No need to save. 临时寄存器。调用函数后值可能改变。不需要保存。 |
$s0-$s7 |
16-23 | Saved. Value PRESERVED across calls. Must save to stack if used. 保存寄存器。调用前后值不变。函数内使用前必须保存到栈。 |
$sp |
29 | Stack Pointer. Grows downwards. 栈指针。指向栈顶,向下增长。 |
$ra |
31 |
Return Address. Set automatically by jal.
返回地址。jal 指令会自动设置。
|
If you use $t0 in function A, then call function B, $t0 might be garbage when B returns! Use $s0 (and save it) if you need the value later.
如果你在函数 A 中使用了 $t0,然后调用了函数 B,从 B 返回后 $t0 的值可能已经变了!如果后续还需要用,请使用 $s0(并保存它)。
li $t0, 100: Load Immediate (constants only)move $t0, $t1: $t0 = $t1 (Copy)la $t0, label: Load Address (for arrays/strings)add $t0, $t1, $t2: $t0 = $t1 + $t2addi $t0, $t1, 10: $t0 = $t1 + 10sub $t0, $t1, $t2: $t0 = $t1 - $t2mul $t0, $t1, $t2: $t0 = $t1 * $t2and $t0, $t1, $t2: Bitwise ANDor $t0, $t1, $t2: Bitwise ORxor $t0, $t1, $t2: Bitwise XORnot $t0, $t1: Bitwise NOTsll $t0, $t1, 2: $t0 = $t1 << 2 (x4)srl $t0, $t1, 2: $t0 = $t1 >> 2 (/4)sllv $t0, $t1, $s0: Variable shift amount🚫 Common Mistake: 🚫 常见错误:
addi $t0, $t1, $t2 WRONG!
(3rd operand must be a number / 第三个操作数必须是数字)
| Instr | Meaning | C Equivalent |
|---|---|---|
beq $t0, $t1, L | Branch Equal | if (t0 == t1) goto L |
bne $t0, $t1, L | Branch Not Equal | if (t0 != t1) goto L |
bgt $t0, $t1, L | Branch Greater | if (t0 > t1) goto L |
bge $t0, $t1, L | Branch >= | if (t0 >= t1) goto L |
blt $t0, $t1, L | Branch Less | if (t0 < t1) goto L |
ble $t0, $t1, L | Branch <= | if (t0 <= t1) goto L |
j L | Jump | goto L |
int i = 0;
while (i < 10) {
// body
i++;
}
li $t0, 0 # 1. Init: i = 0
loop:
bge $t0, 10, end # 2. Check: if i >= 10 goto end
# (Invert logic: < becomes >=)
# ... body ... # 3. Body
addi $t0, $t0, 1 # 4. Increment: i++
j loop # 5. Jump back
end:
Watch how a single instruction travels through the MIPS datapath. The active stage pops up and glows to show current execution. 观察一条指令如何穿过 MIPS 数据通路。 当前执行阶段会弹起并高亮,模拟真实执行过程。
PC provides address. Instruction is fetched from memory. PC 提供地址,从指令内存中读取指令。
Read registers $s/$t. Control signals generated.
读取寄存器 $s/$t。生成控制信号。
ALU calculates result (add/sub) or memory address. ALU 计算结果(加减)或计算内存地址。
Result written to register $d or memory.
结果写回寄存器 $d 或存入内存。
💡 Debugging Insight: 💡 调试启示: Most bugs happen in Stage 3 (wrong logic) or Stage 2 (using uninitialized registers). 大多数 Bug 发生在第 3 阶段(逻辑错误)或第 2 阶段(使用了未初始化的寄存器)。
Accessing array[i] requires explicit memory calculation. This is where most students lose marks!
访问 array[i] 需要显式的内存地址计算。这是最容易失分的地方!
la $s0, array (Do this OUTSIDE loop)
1. 获取基地址: la $s0, array (在循环外执行)
mul $t1, $t0, 4 (Index * 4 for int)
2. 计算偏移量: mul $t1, $t0, 4 (int 索引 * 4)
add $t1, $s0, $t1
3. 基址 + 偏移: add $t1, $s0, $t1
lw $t2, 0($t1) or sw $t2, 0($t1)
4. 访问内存: lw $t2, 0($t1) 或 sw $t2, 0($t1)
li $t1, 1 sllv $t1, $t1, $t0 # mask = 1 << i and $t2, $s0, $t1 # result = val & mask bne $t2, 0, is_one
# (value >> (n * 8)) & 0xFF srl $t1, $s0, 8 # shift right 8 andi $t1, $t1, 0xFF # mask low 8 bits
Standard template for functions. You MUST save $s registers and $ra if you call other functions.
函数的标准模板。如果调用其他函数,必须保存 $s 寄存器和 $ra。
Task: Read 10 numbers, find length of longest increasing run. 任务: 读取10个数,找出最长连续递增序列的长度。
curr vs prev.
curr > prev: length++length = 1max_length if needed.
# Checking Logic Snippet
lw $t3, 0($t1) # curr = numbers[i]
lw $t4, -4($t1) # prev = numbers[i-1] (Addr - 4)
ble $t3, $t4, reset # if curr <= prev, reset
addi $t6, $t6, 1 # length++
j update_max
reset:
li $t6, 1 # length = 1
update_max:
# update max logic...
Task: Reverse byte order of a 32-bit integer (0x12345678 -> 0x78563412). 任务: 反转 32 位整数的字节顺序 (0x12345678 -> 0x78563412)。
# Logic: Extract each byte and shift to new position
andi $t0, $a0, 0xFF # Byte 0
sll $t0, $t0, 24 # Move to top
srl $t1, $a0, 8 # Shift down
andi $t1, $t1, 0xFF # Byte 1
sll $t1, $t1, 16 # Move to mid-high
# ... repeat for others ...
or $v0, $t0, $t1 # Combine
Before submitting, run through this checklist: 提交前,请过一遍此清单:
addi only with numbers as 3rd arg?
addi 第三个参数必须是数字。
$ra in functions that call others?
调用其他函数的函数是否保存了 $ra?
Insert syscall 1 (print_int) to check register values at critical steps.
插入 syscall 1 来打印关键步骤的寄存器值。
Test your assembly skills with 30 practice questions covering registers, memory, and control flow. 通过30道练习题测试你的汇编技能,涵盖寄存器、内存和控制流。
✨ First 10 questions FREE | Questions 11-30 require Premium ✨ 前10题免费 | 第11-30题需要 Premium
Start Day 2 Quiz → 开始 Day 2 测验 →