risc-V学习日记(4):RV32I指令集
这一期我们重新回到RISC-V的内容说明。
文章目录
- 基本指令集
- 指令格式
- 指令集功能分类
- 指令集总览
- 指令详细说明
- 1. 高位立即数与地址构造
- LUI 代码演示
- 2. 控制转移指令
- 无条件跳转
- JALR代码演示
- 条件分支
- BNE代码演示
- 3. 内存访问指令
- 加载指令
- 存储指令
- 4. 整数运算指令
- 立即数运算
- ADDI代码演示
- 移位运算
- SLLI代码演示
- 寄存器-寄存器运算
- ADD代码演示
- 5. 系统与同步指令
- 结语
- 感谢大伙观看,别忘了三连支持一下
- 大家也可以关注一下我的其它专栏,同样精彩喔~
- 下期见咯~
基本指令集
指令格式
在基本ISA中,有四种核心指令格式(R/I/S/U),如图 2.2所示。所有的指令都是固定32位长度的,并且在存储器中必须在4字节边界对齐。当发生一个条件分支或者无条件转移而且目标地址不是对齐到4字节时, 将会产生一个指令地址不对齐的异常。 如果条件分支没有发生(not taken),那么将不会产生一个取指不对齐异常。
基于立即数处理,还有额外两种指令格式变种(SB/UJ)
指令集功能分类
RV32I指令集按照指令功能可以分为5类。
- Integer Computational Instructions【整数计算指令,下称使用中文】
- Loads and Store Instructions【访存指令】
- Control Transfer Instructions【控制转移指令】
- Memory Ordering Instructions【内存顺序指令】
- Environment Call and Breakpoints【环境调用和断点】
这5类指令包括了一种或多种指令格式,下面分类给出各部分指令的简要功能介绍。
指令集总览
RV32I 基本指令集有47条指令,如下图:
是不是很多,这里给大伙提供一个网站,可以在线直接查看 Risc-V的指令功能 —— 跳转链接
指令详细说明
1. 高位立即数与地址构造
指令 | 格式 | 功能描述 | 示例 |
---|---|---|---|
LUI | lui rd, imm | 将 20 位立即数 imm 左移 12 位,写入 rd 的高位,低位补 0。 | lui x5, 0x12345 → x5 = 0x12345000 |
AUIPC | auipc rd, imm | 将 PC 当前值 + (imm << 12),结果写入 rd,用于构造全局地址或远跳转。 | auipc x6 |
LUI 代码演示
.text # Define beginning of text section.global _start # Define entry _start_start:lui x5, 0x12345 # int x5 = 0x12345 << 12addi x5, x5, 0x678 # x5 = x5 + 0x678
stop:j stop # Infinite loop to stop execution.end # End of file
2. 控制转移指令
无条件跳转
指令 | 格式 | 功能描述 | 示例 |
---|---|---|---|
JAL | jal rd, offset | 跳转到 PC + offset,并将返回地址 PC+4 存入 rd(通常 rd=x1)。 | jal x1, func → 调用函数 func |
JALR | jalr rd, rs1, imm | 跳转到 rs1 + imm(地址最低位强制为 0),返回地址 PC+4 存入 rd。 | jalr x0, x1, 0 → 跳转到 x1 并返回 |
JALR代码演示
.text # Define beginning of text section.global _start # Define entry _start_start:li x6, 1li x7, 2jal x5, sum # call sum, return address is saved in x5stop:j stop # Infinite loop to stop executionsum:add x6, x6, x7 # x6 = x6 + x7jalr x0, 0(x5) # return.end # End of file
条件分支
指令 | 格式 | 功能描述 | 示例 |
---|---|---|---|
BEQ | beq rs1, rs2, offset | 若 rs1 == rs2,跳转到 PC + offset。 | beq x5, x6, loop → 相等则循环 |
BNE | bne rs1, rs2, offset | 若 rs1 != rs2,跳转。 | bne x5, x0, exit → 非零则退出 |
BLT | blt rs1, rs2, offset | 若 rs1 < rs2(有符号比较),跳转。 | blt x5, x6, less |
BGE | bge rs1, rs2, offset | 若 rs1 >= rs2(有符号比较),跳转。 | bge x5, x6, greater_eq |
BLTU | bltu rs1, rs2, offset | 若 rs1 < rs2(无符号比较),跳转。 | bltu x5, x6, uless |
BGEU | bgeu rs1, rs2, offset | 若 rs1 >= rs2(无符号比较),跳转。 | bgeu x5, x6, ugreater_eq |
BNE代码演示
.text # Define beginning of text section.global _start # Define entry _start_start:# i = 0# while (i < 5) i++;li x5, 0li x6, 5
loop:addi x5, x5, 1bne x5, x6, loopstop:j stop # Infinite loop to stop execution.end # End of file
在这里插入图片描述
3. 内存访问指令
加载指令
指令 | 格式 | 功能描述 | 示例 |
---|---|---|---|
LB | lb rd, offset(rs1) | 从 rs1 + offset 加载字节(符号扩展后写入 rd)。 | lb x5, 4(x6) → 加载字节到 x5 |
LH | lh rd, offset(rs1) | 加载半字(符号扩展)。 | lh x5, -8(x6) |
LW | lw rd, offset(rs1) | 加载字(32 位数据)。 | lw x5, 0(x6) |
LBU | lbu rd, offset(rs1) | 加载无符号字节(高位补 0)。 | lbu x5, 3(x6) |
LHU | lhu rd, offset(rs1) | 加载无符号半字(高位补 0)。 | lhu x5, 2(x6) |
存储指令
指令 | 格式 | 功能描述 | 示例 |
---|---|---|---|
SB | sb rs2, offset(rs1) | 将 rs2 的低 8 位存储到 rs1 + offset。 | sb x5, 10(x6) → 存储字节 |
SH | sh rs2, offset(rs1) | 存储低 16 位。 | sh x5, -4(x6) |
SW | sw rs2, offset(rs1) | 存储 32 位。 | sw x5, 0(x6) |
4. 整数运算指令
立即数运算
指令 | 格式 | 功能描述 | 示例 |
---|---|---|---|
ADDI | addi rd, rs1, imm | rs1 + 符号扩展的12位立即数,结果写入 rd。 | addi x5, x6, -5 → x5 = x6 -5 |
SLTI | slti rd, rs1, imm | 若 rs1 < imm(有符号比较),则 rd=1,否则 rd=0。 | slti x5, x6, 10 → 检查是否小于 10 |
SLTIU | sltiu rd, rs1, imm | 无符号比较 rs1 < imm,结果写入 rd。 | sltiu x5, x6, 0xFFF |
XORI | xori rd, rs1, imm | rs1 ^ 符号扩展的立即数。 | xori x5, x6, 0xFFFF → 按位取反 |
ORI | ori rd, rs1, imm | rs1 | 符号扩展的立即数。 |
ANDI | andi rd, rs1, imm | rs1 & 符号扩展的立即数。 | andi x5, x6, 0xFF → 取低8位 |
ADDI代码演示
.text # Define beginning of text section.global _start # Define entry _start_start:li x6, 2 # x6 = 2addi x5, x6, 1 # x5 = x6 + 1stop:j stop # Infinite loop to stop execution.end # End of file
移位运算
指令 | 格式 | 功能描述 | 示例 |
---|---|---|---|
SLLI | slli rd, rs1, shamt | 逻辑左移 rs1,移位数为 shamt(0-31),结果写入 rd。 | slli x5, x6, 2 → x5 = x6 << 2 |
SRLI | srli rd, rs1, shamt | 逻辑右移(高位补 0)。 | srli x5, x6, 3 |
SRAI | srai rd, rs1, shamt | 算术右移(高位补符号位)。 | srai x5, x6, 4 |
SLLI代码演示
.text # Define beginning of text section.global _start # Define entry _start_start:li x6, 1 # x6 = 1slli x5, x6, 3 # x5 = x6 << 3stop:j stop # Infinite loop to stop execution.end # End of file
寄存器-寄存器运算
指令 | 格式 | 功能描述 | 示例 |
---|---|---|---|
ADD | add rd, rs1, rs2 | rs1 + rs2,结果写入 rd。 | add x5, x6, x7 |
SUB | sub rd, rs1, rs2 | rs1 - rs2。 | sub x5, x6, x7 |
SLL | sll rd, rs1, rs2 | 逻辑左移 rs1,移位数为 rs2 的低 5 位。 | sll x5, x6, x7 |
SLT | slt rd, rs1, rs2 | 若 rs1 < rs2 | (有符号比较),则 rd=1,否则 rd=0。 |
SLTU | sltu rd, rs1, rs2 | 无符号比较 rs1 < rs2,结果写入 rd。 | sltu x5, x6, x7 |
XOR | xor rd, rs1, rs2 | 按位异或。 | xor x5, x6, x7 → x5 = x6 ^ x7 |
SRL | srl rd, rs1, rs2 | 逻辑右移(高位补 0)。 | srl x5, x6, x7 |
SRA | sra rd, rs1, rs2 | 算术右移(高位补符号位)。 | sra x5, x6, x7 |
OR | or rd, rs1, rs2 | 按位或。 | or x5, x6, x7 → x5 = x6 |
AND | and rd, rs1, rs2 | 按位与。 | and x5, x6, x7 → x5 = x6 & x7 |
ADD代码演示
.text # Define beginning of text section.global _start # Define entry _start_start:li x6, 1 # x6 = 1li x7, 2 # x7 = 2add x5, x6, x7 # x5 = x6 + x7stop:j stop # Infinite loop to stop execution.end # End of file
5. 系统与同步指令
指令 | 格式 | 功能描述 | 示例 |
---|---|---|---|
FENCE | fence 内存屏障,确保其前后的内存访问顺序。 | fence → 保证访存顺序 | |
ECALL | ecall 触发环境调用(如系统调用或切换到更高权限模式)。 | ecall → 执行系统调用 | |
EBREAK | ebreak 触发调试断点,通常用于调试器介入。 | ebreak → 进入调试模式 |
结语
这一期讲了RV32I的所有指令集,下一期我们来看看指令在CPU中是经过了那些过程才最终实现出来的。