总览
RISC-V 的6种指令格式:
- R-format: 寄存器-寄存器数学指令
- I-format: 寄存器-立即数指令以及加载指令
- S-format: 存储指令
- B-format: 分支指令
- U-format: 上半立即数指令
- J-format: 跳转指令
R-format
指令布局:
字段说明:
opcode(7 bits): 操作码,指示指令类型。对于 R-format 指令,opcode通常为0110011。rd(5 bits): 目的寄存器地址funct3(3 bits): 功能码,指示具体操作rs1(5 bits): 源寄存器1地址rs2(5 bits): 源寄存器2地址funct7(7 bits): 功能码,进一步指示具体操作
指令示例:
add x18, x19, x20
所有R-format指令:
funct7 | rs2 | rs1 | funct3 | rd | opcode | 指令名 |
|---|---|---|---|---|---|---|
0000000 | rs2 | rs1 | 000 | rd | 0110011 | add |
0100000 | rs2 | rs1 | 000 | rd | 0110011 | sub |
0000000 | rs2 | rs1 | 001 | rd | 0110011 | sll |
0000000 | rs2 | rs1 | 010 | rd | 0110011 | slt |
0000000 | rs2 | rs1 | 011 | rd | 0110011 | sltu |
0000000 | rs2 | rs1 | 100 | rd | 0110011 | xor |
0000000 | rs2 | rs1 | 101 | rd | 0110011 | srl |
0100000 | rs2 | rs1 | 101 | rd | 0110011 | sra |
0000000 | rs2 | rs1 | 110 | rd | 0110011 | or |
0000000 | rs2 | rs1 | 111 | rd | 0110011 | and |
I-format
立即数指令
指令布局:
字段说明:
- I-format指令的字段与R-format指令的区别只在于
rs2和funct7被替换成了一个12位的立即数imm。 opcode(7 bits): 操作码,指示指令类型。对于 I-format 立即数指令,opcode通常为0010011(算术立即数指令)或0000011(加载指令)。rd(5 bits): 目的寄存器地址funct3(3 bits): 功能码,指示具体操作rs1(5 bits): 源寄存器地址imm(12 bits): 立即数,直接编码在指令中。在数学立即数指令中,imm是一个有符号数,可以表示 -2048 到 2047 之间的值,在使用之前一直符号扩展为 32 位。
指令示例:
addi x15, x1, -50
所有I-format立即数指令:
| `imm[11:0]` | `funct3` | `rd` | `opcode` | 指令 |
|---|---|---|---|---|
| `imm[11:0]` | `000` | `rd` | `0010011` | `addi` |
| `imm[11:0]` | `010` | `rd` | `0010011` | `slti` |
| `imm[11:0]` | `011` | `rd` | `0010011` | `sltiu` |
| `imm[11:0]` | `100` | `rd` | `0010011` | `xori` |
| `imm[11:0]` | `110` | `rd` | `0010011` | `ori` |
| `imm[11:0]` | `111` | `rd` | `0010011` | `andi` |
| `0000000` / `shamt` | `001` | `rd` | `0010011` | `slli` |
| `0000000` / `shamt` | `101` | `rd` | `0010011` | `srli` |
| `0100000` / `shamt` | `101` | `rd` | `0010011` | `srai` |
加载指令
指令布局:
字段说明:
- I-format指令中,存储指令字段与立即数指令相同,区别在于
opcode不同以及imm的使用方式不同。 opcode(7 bits): 操作码,指示指令类型。对于 I-format 加载指令,opcode通常为0000011。rd(5 bits): 目的寄存器地址funct3(3 bits): 功能码,指示具体加载类型rs1(5 bits): 基址寄存器地址imm(12 bits): 立即数,表示内存地址的偏移
指令示例:
lw x14, 8(x2)
所有I-format加载指令:
imm[11:0] | rs1 | funct3 | rd | opcode | 指令 |
|---|---|---|---|---|---|
imm[11:0] | rs1 | 000 | rd | 0000011 | lb |
imm[11:0] | rs1 | 001 | rd | 0000011 | lh |
imm[11:0] | rs1 | 010 | rd | 0000011 | lw |
imm[11:0] | rs1 | 100 | rd | 0000011 | lbu |
imm[11:0] | rs1 | 101 | rd | 0000011 | lhu |
S-format
指令布局:
字段说明:
opcode(7 bits): 操作码,指示指令类型。对于 S-format 存储指令,opcode通常为0100011。funct3(3 bits): 功能码,指示具体存储类型rs1(5 bits): 基址寄存器地址rs2(5 bits): 源寄存器地址,存储指令中rs2寄存器的值将被存储到内存中imm(12 bits): 立即数,表示内存地址的偏移。
指令示例:
sw x14, 8(x2)
所有S-format存储指令:
imm[11:5] | rs2 | rs1 | funct3 | imm[4:0] | opcode | 指令 |
|---|---|---|---|---|---|---|
imm[11:5] | rs2 | rs1 | 000 | imm[4:0] | 0100011 | sb |
imm[11:5] | rs2 | rs1 | 001 | imm[4:0] | 0100011 | sh |
imm[11:5] | rs2 | rs1 | 010 | imm[4:0] | 0100011 | sw |
B-format
说明:
- 如何表示Label? Label是跳转的指令地址,可以通过与当前指令的地址的差值来表示。这个差值就是一个立即数,直接编码在指令中。
- Label一定要存偏移量的每一位吗? 不需要,立即数的每一位不需要存储在指令中。因为指令地址是对齐的。 (注意:只省略了偏移量的最后一位)
指令布局:
字段说明:
opcode(7 bits): 操作码,指示指令类型。对于 B-format 分支指令,opcode通常为1100011。funct3(3 bits): 功能码,指示具体分支类型rs1(5 bits): 源寄存器1地址rs2(5 bits): 源寄存器2地址imm(13 bits): 立即数,表示跳转的偏移量。由于指令地址是对齐的,所以立即数的最后一位被省略了。
指令示例:
Loop:
beq x19, x10, End
add x18, x18, x10
addi x19, x19, -1
j Loop
End:
立即数扩展: 下面的图片演示了I/S/B-format指令中立即数的扩展方式
所有B-format分支指令:
imm[12] | imm[10:5] | rs2 | rs1 | funct3 | imm[4:1] | imm[11] | opcode | 指令 |
|---|---|---|---|---|---|---|---|---|
imm[12] | imm[10:5] | rs2 | rs1 | 000 | imm[4:1] | imm[11] | 1100011 | beq |
imm[12] | imm[10:5] | rs2 | rs1 | 001 | imm[4:1] | imm[11] | 1100011 | bne |
imm[12] | imm[10:5] | rs2 | rs1 | 100 | imm[4:1] | imm[11] | 1100011 | blt |
imm[12] | imm[10:5] | rs2 | rs1 | 101 | imm[4:1] | imm[11] | 1100011 | bge |
imm[12] | imm[10:5] | rs2 | rs1 | 110 | imm[4:1] | imm[11] | 1100011 | bltu |
imm[12] | imm[10:5] | rs2 | rs1 | 111 | imm[4:1] | imm[11] | 1100011 | bgeu |
U-format
lui/auipc
指令含义:
lui(load upper immediate): 将20位立即数左移12位加载到寄存器中,低12位填0。auipc(add upper immediate to pc): 将20位立即数左移12位加上当前指令地址(pc),并将结果存储在寄存器中。
典型用途:
# 加载一个32位立即数到寄存器中
lui rd, imm20
addi rd, rd, imm12# 加载相对PC地址偏移量的指令地址到寄存器中
auipc rd, imm20
lw rd, imm12(rd)# 实现32位立即数宽度的长跳转
auipc rd, imm20
jalr rd, imm12(rd)指令结构
J-format
总结