Back to Final Review Hub 返回期末复习中心
Day 2 - Final Review Day 2 - 期末复习

⚡ MIPS Architecture ⚡ MIPS 架构

The Ultimate Guide to MIPS Assembly MIPS 汇编终极指南

1. Registers Guide 1. 寄存器详解

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 指令会自动设置。

⚠️ Critical Rule: ⚠️ 关键规则:

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(并保存它)。

2. Core Instructions 2. 核心指令速查

Data Transfer 数据传输

  • li $t0, 100: Load Immediate (constants only)
  • move $t0, $t1: $t0 = $t1 (Copy)
  • la $t0, label: Load Address (for arrays/strings)

Arithmetic 算术运算

  • add $t0, $t1, $t2: $t0 = $t1 + $t2
  • addi $t0, $t1, 10: $t0 = $t1 + 10
  • sub $t0, $t1, $t2: $t0 = $t1 - $t2
  • mul $t0, $t1, $t2: $t0 = $t1 * $t2

Logical 逻辑运算

  • and $t0, $t1, $t2: Bitwise AND
  • or $t0, $t1, $t2: Bitwise OR
  • xor $t0, $t1, $t2: Bitwise XOR
  • not $t0, $t1: Bitwise NOT

Shift Operations 移位运算

  • sll $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 / 第三个操作数必须是数字)

3. Loops & Control Flow 3. 循环与条件分支

Instr Meaning C Equivalent
beq $t0, $t1, LBranch Equalif (t0 == t1) goto L
bne $t0, $t1, LBranch Not Equalif (t0 != t1) goto L
bgt $t0, $t1, LBranch Greaterif (t0 > t1) goto L
bge $t0, $t1, LBranch >=if (t0 >= t1) goto L
blt $t0, $t1, LBranch Lessif (t0 < t1) goto L
ble $t0, $t1, LBranch <=if (t0 <= t1) goto L
j LJumpgoto L

Standard Loop Template (While/For) 标准循环模板 (While/For)

C Code

int i = 0;
while (i < 10) {
    // body
    i++;
}

MIPS Template

    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:

Visual: Dynamic Instruction Pipeline 可视化:指令动态执行管线

Watch how a single instruction travels through the MIPS datapath. The active stage pops up and glows to show current execution. 观察一条指令如何穿过 MIPS 数据通路。 当前执行阶段会弹起并高亮,模拟真实执行过程。

1

Fetch 取指

PC provides address. Instruction is fetched from memory. PC 提供地址,从指令内存中读取指令。

2

Decode 解码

Read registers $s/$t. Control signals generated. 读取寄存器 $s/$t。生成控制信号。

3

Execute 执行

ALU calculates result (add/sub) or memory address. ALU 计算结果(加减)或计算内存地址。

4

Write Back 写回

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 阶段(使用了未初始化的寄存器)。

4. Array Operations 4. 数组操作 (必考)

Accessing array[i] requires explicit memory calculation. This is where most students lose marks! 访问 array[i] 需要显式的内存地址计算。这是最容易失分的地方!

Address = Base + (Index × ElementSize)
1. Get Base Address: la $s0, array (Do this OUTSIDE loop) 1. 获取基地址: la $s0, array (在循环外执行)
2. Calculate Offset: mul $t1, $t0, 4 (Index * 4 for int) 2. 计算偏移量: mul $t1, $t0, 4 (int 索引 * 4)
3. Add Base + Offset: add $t1, $s0, $t1 3. 基址 + 偏移: add $t1, $s0, $t1
4. Access Memory: lw $t2, 0($t1) or sw $t2, 0($t1) 4. 访问内存: lw $t2, 0($t1)sw $t2, 0($t1)
# Example: Sum of Array # int numbers[5] = {1, 2, 3, 4, 5}; # int sum = 0; li $t0, 0 # i = 0 li $s0, 0 # sum = 0 la $s1, numbers # Base address (Outside loop!) loop: bge $t0, 5, end # if i >= 5, break mul $t1, $t0, 4 # offset = i * 4 add $t1, $s1, $t1 # addr = base + offset lw $t2, 0($t1) # t2 = numbers[i] add $s0, $s0, $t2 # sum += numbers[i] addi $t0, $t0, 1 # i++ j loop end:

5. Bitwise Operations 5. 位操作技巧

Check if ith bit is 1 (检查第 i 位)

li   $t1, 1
sllv $t1, $t1, $t0   # mask = 1 << i
and  $t2, $s0, $t1   # result = val & mask
bne  $t2, 0, is_one

Extract nth Byte (提取第 n 字节)

# (value >> (n * 8)) & 0xFF
srl  $t1, $s0, 8     # shift right 8
andi $t1, $t1, 0xFF  # mask low 8 bits

6. Stack & Functions 6. 栈与函数 (难点)

Standard template for functions. You MUST save $s registers and $ra if you call other functions. 函数的标准模板。如果调用其他函数,必须保存 $s 寄存器和 $ra

my_function: # 1. PROLOGUE: Save registers (序言:保存寄存器) addi $sp, $sp, -12 # Allocate stack space (4 bytes * 3 items) sw $ra, 8($sp) # Save Return Address (Critical!) sw $s0, 4($sp) # Save $s0 sw $s1, 0($sp) # Save $s1 # --- Function Body --- # You can now safely modify $s0, $s1 # jal other_func # Return value goes in $v0 # 2. EPILOGUE: Restore registers (结语:恢复寄存器) lw $s1, 0($sp) # Restore $s1 lw $s0, 4($sp) # Restore $s0 lw $ra, 8($sp) # Restore Return Address addi $sp, $sp, 12 # Deallocate stack space jr $ra # Return

7. Real Exam Cases 7. 真题实战解析

Case 1: Longest Increasing Subsequence 案例 1:最长递增子序列 (22T2 Final Q4)

Task: Read 10 numbers, find length of longest increasing run. 任务: 读取10个数,找出最长连续递增序列的长度。

Logic: Compare curr vs prev.
  • If curr > prev: length++
  • Else: length = 1
  • Update max_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...

Case 2: Bit Reversal 案例 2:位反转 (22T2 Q3)

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

8. Debugging & Checklist 8. 调试与检查清单

Before submitting, run through this checklist: 提交前,请过一遍此清单:

Did you use addi only with numbers as 3rd arg? addi 第三个参数必须是数字。
Is array offset multiplied by 4? 数组访问是否乘以了 4?
Did you save $ra in functions that call others? 调用其他函数的函数是否保存了 $ra
Are loops guaranteed to terminate? 循环是否保证能终止(跳转逻辑对吗)?

Debugging Tip 调试技巧

Insert syscall 1 (print_int) to check register values at critical steps. 插入 syscall 1 来打印关键步骤的寄存器值。