6.S081 学习笔记 - Lab-Traps
RISC-V 知识点
RISC-V 寄存器
从表中可以看到,保存寄存器和临时寄存器的编号不是连续的。这是为了支持另一个只有 16 个寄存器的 RISC-V 变种 RV32E。
保存寄存器和栈指针在函数调用前后保持不变,它们的值由被调用者保存和恢复。
临时寄存器、函数参数和返回值在函数调用前后可能会被修改,它们的值由调用者保存和恢复。
关于调用前后是否一致可以这样理解:保存寄存器一般是存一些重要的值,而临时寄存器是存一些不重要的中间结果或临时值。所以被调用者 (Callee) 如果要利用保存寄存器的空间就需要负责在使用后恢复原样,而对临时寄存器无需负责 (因为它认为临时寄存器中的值不重要)。因此如果调用者 (Caller) 在临时寄存器中保存了在函数调用后还需要的值,它就需要自己负责保存,避免被被调用者修改。
32 位和 64 位 RISC-V 的寄存器数量相同,只是寄存器的位宽不同。
RV32I 指令集
指令分类
- R 型:用于寄存器之间的操作
- I 型:用于短立即数和寄存器之间的操作
- S 型:用于存储操作
- B 型:用于条件分支操作
- U 型:用于长立即数的操作
- J 型:用于无条件跳转操作
指令列表
整数计算指令
指令名称 | 指令格式 | 描述 |
---|---|---|
add | add rd, rs1, rs2 |
将 x[rs2] 和 x[rs1] 相加,结果存入 x[rd] |
addi | addi rd, rs1, imm |
对 imm 符号扩展后与 x[rs1] 相加,结果存入 x[rd] |
sub | sub rd, rs1, rs2 |
将 x[rs1] 减去 x[rs2] ,结果存入 x[rd] |
and | and rd, rs1, rs2 |
将 x[rs1] 和 x[rs2] 按位与,结果存入 x[rd] |
andi | andi rd, rs1, imm |
对 imm 符号扩展后和 x[rs1] 按位与,结果存入 x[rd] |
or | or rd, rs1, rs2 |
将 x[rs1] 和 x[rs2] 按位或,结果存入 x[rd] |
ori | ori rd, rs1, imm |
对 imm 符号扩展后和 x[rs1] 按位或,结果存入 x[rd] |
xor | xor rd, rs1, rs2 |
将 x[rs1] 和 x[rs2] 按位异或,结果存入 x[rd] |
xori | xori rd, rs1, imm |
对 imm 符号扩展后和 x[rs1] 按位异或,结果存入 x[rd] |
sll | sll rd, rs1, rs2 |
将 x[rs1] 逻辑左移 x[rs2] 位,结果存入 x[rd] 。x[rs2] 的低 5 位是移位位数,高位忽略 |
slli | slli rd, rs1, shamt |
将 x[rs1] 逻辑左移 shamt 位,结果存入 x[rd] 。仅当 shamt[5]=0 时指令合法 |
srl | srl rd, rs1, rs2 |
将 x[rs1] 逻辑右移 x[rs2] 位,结果存入 x[rd] 。x[rs2] 的低 5 位是移位位数,高位忽略 |
srli | srli rd, rs1, shamt |
将 x[rs1] 逻辑右移 shamt 位,结果存入 x[rd] 。仅当 shamt[5]=0 时指令合法 |
sra | sra rd, rs1, rs2 |
将 x[rs1] 算术右移 x[rs2] 位,结果存入 x[rd] 。x[rs2] 的低 5 位是移位位数,高位忽略 |
srai | srai rd, rs1, shamt |
将 x[rs1] 算术右移 shamt 位,结果存入 x[rd] 。仅当 shamt[5]=0 时指令合法 |
lui | lui rd, imm |
将 20 位 imm 符号扩展后左移 12 位,低 12 位置 0,结果存入 x[rd] |
auipc | auipc rd, imm |
将 20 位 imm 符号扩展后左移 12 位,加上 pc ,结果存入 x[rd] |
slt | slt rd, rs1, rs2 |
如果 x[rs1] 小于 x[rs2] ,则 x[rd]=1 ,否则 x[rd]=0 |
slti | slti rd, rs1, imm |
如果 x[rs1] 小于符号扩展后的 imm ,则 x[rd]=1 ,否则 x[rd]=0 |
sltiu | sltiu rd, rs1, imm |
如果 x[rs1] 小于无符号扩展后的 imm (视为无符号数),则 x[rd]=1 ,否则 x[rd]=0 |
控制转移指令
指令名称 | 指令格式 | 描述 |
---|---|---|
beq | beq rs1, rs2, offset |
如果 x[rs1] 等于 x[rs2] ,则将 pc 设为当前值加上符号扩展后的 offset |
bne | bne rs1, rs2, offset |
如果 x[rs1] 不等于 x[rs2] ,则将 pc 设为当前值加上符号扩展后的 offset |
bge | bge rs1, rs2, offset |
如果 x[rs1] 大于等于 x[rs2] ,则将 pc 设为当前值加上符号扩展后的 offset |
bgeu | bgeu rs1, rs2, offset |
如果 x[rs1] 大于等于 x[rs2] (视为无符号数),则将 pc 设为当前值加上符号扩展后的 offset |
blt | blt rs1, rs2, offset |
如果 x[rs1] 小于 x[rs2] ,则将 pc 设为当前值加上符号扩展后的 offset |
bltu | bltu rs1, rs2, offset |
如果 x[rs1] 小于 x[rs2] (视为无符号数),则将 pc 设为当前值加上符号扩展后的 offset |
jal | jal rd, offset |
将下一条指令的地址 (pc+4 ) 写入 x[rd] ,然后将 pc 设为当前值加上符号扩展后的 offset 。若省略 rd ,则默认为 x1 |
jalr | jalr rd, rs1, imm |
将 pc 设为 x[rs1]+sign-extend(offset) ,将跳转地址的最低位清零,并将原 pc+4 写入 x[rd] 。若省略 rd ,则默认为 x1 |
装载存储指令
指令名称 | 指令格式 | 描述 |
---|---|---|
lb | lb rd, offset(rs1) |
从 x[rs1]+sign-extend(offset) 读取一个字节,符号扩展后存入 x[rd] |
lbu | lbu rd, offset(rs1) |
从 x[rs1]+sign-extend(offset) 读取一个字节,零扩展后存入 x[rd] |
lh | lh rd, offset(rs1) |
从 x[rs1]+sign-extend(offset) 读取两个字节,符号扩展后存入 x[rd] |
lhu | lhu rd, offset(rs1) |
从 x[rs1]+sign-extend(offset) 读取两个字节,零扩展后存入 x[rd] |
lw | lw rd, offset(rs1) |
从 x[rs1]+sign-extend(offset) 读取四个字节,符号扩展后存入 x[rd] |
sb | sb rs2, offset(rs1) |
将 x[rs2] 的最低字节存入内存地址 x[rs1]+sign-extend(offset) |
sh | sh rs2, offset(rs1) |
将 x[rs2] 的最低 2 字节存入内存地址 x[rs1]+sign-extend(offset) |
sw | sw rs2, offset(rs1) |
将 x[rs2] 的最低 4 字节存入内存地址 x[rs1]+sign-extend(offset) |
其他指令
指令名称 | 指令格式 | 描述 |
---|---|---|
fence | fence pred, succ |
内存屏障,保证内存操作的顺序性 |
fence.i | fence.i |
指令屏障,保证指令的顺序性 |
ebreak | ebreak |
通过抛出断点异常调用调试器 |
ecall | ecall |
通过抛出环境调用异常调用执行环境 |
csrrc | csrrc rd, csr, rs1 |
记控制状态寄存器 csr 的值为 t 。将 x[rs1] 的反码和 t 按位与,结果写入 csr ,再将 t 写入 x[rd] |
csrrci | csrrci rd, csr, zimm[4:0] |
记控制状态寄存器 csr 的值为 t 。将 5 位立即数 zimm 零扩展后的反码和 t 按位与,结果写入 csr ,再将 t 写入 x[rd] |
csrrs | csrrs rd, csr, rs1 |
记控制状态寄存器 csr 的值为 t 。将 x[rs1] 的值和 t 按位或,结果写入 csr ,再将 t 写入 x[rd] |
csrrsi | csrrsi rd, csr, zimm[4:0] |
记控制状态寄存器 csr 的值为 t 。将 5 位立即数 zimm 零扩展后的值和 t 按位或,结果写入 csr ,再将 t 写入 x[rd] |
csrrw | csrrw rd, csr, rs1 |
记控制状态寄存器 csr 的值为 t 。将 x[rs1] 的值写入 csr ,再将 t 写入 x[rd] |
csrrwi | csrrwi rd, csr, zimm[4:0] |
将控制状态寄存器的值复制到 x[rd] ,再将 5 位立即数 zimm 零扩展后的值写入 csr |
RV64I 指令集
在 RV32I 的基础上,RV64I 增加了图中红色的指令,主要是对字长的扩展。
RV32/RV64 特权架构
特权模式下的异常处理
重要寄存器:
sstatus
(Supervisor Status):维护各种状态,其中SIE
位控制设置中断使能,SPP
位存储异常发生的特权模式sip
(Supervisor Interrupt Pending):记录当前的中断请求sie
(Supervisor Interrupt Enable):维护处理器的中断使能状态scause
(Supervisor Exception Cause):指示发生了何种异常stvec
(Supervisor Trap Vector):指向异常处理程序的入口地址stval
(Supervisor Trap Value):存放当前自陷的额外信息sepc
(Supervisor Exception Program Counter):指向发生异常的指令地址sscratch
(Supervisor Scratch):向异常处理程序提供一个字的临时存储
处理流程:
- 将发生异常的指令 PC 存入
sepc
, 并将 PC 设为stvec
- 将异常原因写入
scause
,并将故障地址或其他异常相关信息字写入stval
- 将
sstatus.SIE
置零以屏蔽中断,并将SIE
的旧值存放在SPIE
中 - 将异常发生前的特权模式存放在
sstatus.SPP
,并将当前特权模式设为S
sret
指令将spec
的值复制到 PC
RISC-V 汇编器指示符
不用中间变量交换两个整数的值
1 |
|
异或运算的性质:
- 交换律:\(a \oplus b = b \oplus a\)
- 结合律:\((a \oplus b) \oplus c = a \oplus (b \oplus c)\)
- 逆元:\(a \oplus a = 0\)
- 单位元:\(a \oplus 0 = a\)
证明:
将 (1) 代入 (2):\(b = (a \oplus b) \oplus b = a \oplus (b \oplus b) = a \oplus 0 = a\)
将 (1) 和 (2) 代入 (3):\(a = (a \oplus b) \oplus a = b \oplus (a \oplus a) = b \oplus 0 = b\)
参考资料
《RISC-V 开放架构设计之道》
6.S081 学习笔记 - Lab-Traps
http://blog.qzink.me/posts/6.S081学习笔记-Lab-Traps/