CS61C Lecture09: RISC-V 位操作与函数调用¶
约 752 个字 47 行代码 预计阅读时间 4 分钟 共被读过 次
一、位操作指令详解¶
1. 位掩码操作¶
Text Only
andi x5, x6, 0xFF # 取最低字节(x5 = x6 & 0x000000FF)
andi x7, x8, 0xFF000000 # 取最高字节(x7 = x8 & 0xFF000000)
掩码应用场景:
- 提取颜色通道(ARGB格式)
- 网络协议头解析
- 字符编码处理
2. 逻辑运算技巧¶
操作 | 实现方式 | 示例 |
---|---|---|
按位取反 | XOR全1掩码 | xori x5, x6, 0xFFFFFFFF |
清除特定位 | AND取反掩码 | andi x5, x6, 0xFFFFF0FF (清除第8-11位) |
设置特定位 | OR置位掩码 | ori x5, x6, 0x00000F00 |
3. 移位指令对比¶
指令 | 格式 | 行为 | 用途 |
---|---|---|---|
sll | sll rd, rs1, rs2 | 逻辑左移(补0) | 快速乘法(2^n倍) |
slli | slli rd, rs1, imm | 立即数逻辑左移 | |
srl | srl rd, rs1, rs2 | 逻辑右移(补0) | 无符号数除法 |
sra | sra rd, rs1, rs2 | 算术右移(符号扩展) | 有符号数除法 |
srai | srai rd, rs1, imm | 立即数算术右移 |
示例:
二、程序控制核心机制¶
1. 程序计数器(PC)¶
- 32位寄存器,存储下一条指令的字节地址
- 默认行为:PC += 4(顺序执行)
- 跳转时:PC = target_address
2. 寄存器别名表¶
物理寄存器 | 符号名称 | 用途 |
---|---|---|
x0 | zero | 常数0 |
x1 | ra | 返回地址 |
x2 | sp | 栈指针 |
x10-x17 | a0-a7 | 参数/返回值 |
x5-x7, x28-x31 | t0-t6 | 临时寄存器 |
三、伪指令解析¶
伪指令 | 实际指令 | 功能 |
---|---|---|
mv rd, rs | addi rd, rs, 0 | 寄存器复制 |
li rd, imm | 组合指令(可能包含lui+addi) | 加载立即数 |
nop | addi x0, x0, 0 | 空操作(用于流水线控制) |
j label | jal x0, label | 无条件跳转 |
ret | jalr x0, 0(x1) | 函数返回 |
nop的三大作用:
1. 填充流水线气泡
2. 对齐指令地址
3. 软件延时(不推荐)
四、函数调用机制¶
1. 函数调用六步曲¶
- 参数传递:a0-a7寄存器(前8个参数)
- 控制转移:jal指令(保存返回地址到ra)
- 栈帧分配:
addi sp, sp, -framesize
- 局部存储:保存被调用者保存寄存器(s0-s11)
- 返回值设置:a0/a1寄存器
- 资源释放:
addi sp, sp, framesize
+ ret
2. 关键跳转指令对比¶
指令 | 格式 | 行为 | 用途 |
---|---|---|---|
j | jal x0, offset | PC = PC + offset | 短距离跳转 |
jal | jal rd, offset | rd=PC+4; PC=PC+offset | 函数调用 |
jalr | jalr rd, offset(rs1) | rd=PC+4; PC=rs1+offset | 间接跳转 |
jr | jalr x0, 0(rs1) | PC = rs1 | 寄存器跳转 |
调用示例:
Text Only
# 调用函数func
addi a0, x0, 5 # 设置参数
jal ra, func # 跳转并保存返回地址
... # 后续代码
func:
addi sp, sp, -16 # 分配栈空间
sw ra, 12(sp) # 保存返回地址
... # 函数体
lw ra, 12(sp) # 恢复返回地址
addi sp, sp, 16 # 释放栈空间
ret # 返回
五、函数调用规范¶
1. 寄存器保存规则¶
寄存器类型 | 保存责任 | 寄存器列表 |
---|---|---|
调用者保存 | 调用者负责保存 | t0-t6, a0-a7 |
被调用者保存 | 被调用者负责保存 | s0-s11, ra |
2. 栈帧结构示例¶
Text Only
High Address
|----------------|
| 保存的s1 | <- sp + 24
|----------------|
| 保存的s0 | <- sp + 20
|----------------|
| 保存的ra | <- sp + 16
|----------------|
| 局部变量2 | <- sp + 12
|----------------|
| 局部变量1 | <- sp + 8
|----------------|
| 参数溢出区 | <- sp + 4
|----------------|
| 当前栈帧 | <- sp
Low Address
六、高级编程技巧¶
1. 尾调用优化¶
Text Only
# 普通递归调用
factorial:
addi sp, sp, -8
sw ra, 4(sp)
...
jal factorial # 产生新栈帧
# 尾递归优化版
factorial_tail:
...
mv a0, t0 # 直接修改参数
j factorial_tail # 复用当前栈帧
2. 多精度运算¶
Text Only
# 64位加法(x5:x4 = x5:x4 + x7:x6)
add x4, x4, x6 # 低32位相加
sltu t0, x4, x6 # 检测进位
add x5, x5, x7 # 高32位相加
add x5, x5, t0 # 加上进位
七、常见错误分析¶
-
栈不平衡:
后果:后续函数调用栈损坏 -
未保存调用者保存寄存器:
正确做法:调用前保存t0到栈中 -
错误使用ra寄存器:
正确做法:嵌套调用前保存ra到栈中