R-type指令是指令集中的一种类型,它们的操作码字段是固定的,而剩余的字段则根据指令的具体功能而变化。R-type指令通常用于执行算术运算和逻辑运算等操作;R-type指令的格式如下所示:
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
funct7 |
rs2 |
rs1 |
funct3 |
rd |
opcode |
rd = rs1 op rs2
,有时候rs1
,rs2
,又称为rs
,rt
R-type指令
Instruction |
Name |
Meaning |
ADD |
Addition |
Adds two values and stores the result in the destination register. |
SUB |
Subtraction |
Subtracts the second value from the first and stores the result in the destination register. |
SLT |
Set Less Than |
Sets the destination register to 1 if the first value is less than the second (signed), otherwise sets to 0. |
SLTU |
Set Less Than Unsigned |
Sets the destination register to 1 if the first value is less than the second (unsigned), otherwise sets to 0. |
AND |
Logical AND |
Performs a bitwise AND operation between two values and stores the result in the destination register. |
OR |
Logical OR |
Performs a bitwise OR operation between two values and stores the result in the destination register. |
XOR |
Logical XOR |
Performs a bitwise XOR (exclusive OR) operation between two values and stores the result. |
SLL |
Shift Left Logical |
Shifts the bits of the first value to the left by the number of positions specified by the second value, filling with zeros. |
SRL |
Shift Right Logical |
Shifts the bits of the first value to the right by the number of positions specified, filling with zeros. |
SRA |
Shift Right Arithmetic |
Shifts the bits of the first value to the right by the number of positions specified, maintaining the sign bit. |
常见的R-type指令
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
0000000 |
rs2 |
rs1 |
000 |
rd |
0110011 |
- 使用格式
ADD rd,rs1,rs2
rd = rs1 + rs2
- 溢出将会被忽略
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
0100000 |
rs2 |
rs1 |
000 |
rd |
0110011 |
- 使用格式
SUB rd,rs1,rs2
rd = rs1 - rs2
- 溢出将会被忽略
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
0000000 |
rs2 |
rs1 |
010 |
rd |
0110011 |
- 使用格式
SLT rd,rs1,rs2
rd = ($signed(rs1) < $signed(rs2)) ? 1 : 0
- 有符号数的比较
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
0000000 |
rs2 |
rs1 |
011 |
rd |
0110011 |
- 使用格式
SLTU rd,rs1,rs2
rd = (rs1 < rs2) ? 1 : 0
- 进行无符号数的比较
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
0000000 |
rs2 |
rs1 |
111 |
rd |
0110011 |
- 使用格式
AND rd,rs1,rs2
rd = rs1 & rs2
- 按位的与操作
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
0000000 |
rs2 |
rs1 |
110 |
rd |
0110011 |
- 使用格式
OR rd,rs1,rs2
rd = rs1 | rs2
- 执行按位或操作
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
0000000 |
rs2 |
rs1 |
100 |
rd |
0110011 |
- 使用格式
XOR rd,rs1,rs2
rd = rs1 ^ rs2
- 执行按位异或操作
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
0000000 |
rs2 |
rs1 |
001 |
rd |
0110011 |
- 使用格式
SLL rd,rs1,rs2
rd = rs1 << rs2[4:0]
- 逻辑左移
- 取
rs2
的低五位进行运算
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
0000000 |
rs2 |
rs1 |
101 |
rd |
0110011 |
- 指令格式:
srl rd,rs1,rs2
,rd=rs1>>rs2[4:0]
- 取
rs2
的低5位
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
0100000 |
rs2 |
rs1 |
101 |
rd |
0110011 |
- 指令格式
sra rd,rs1,rs2
;rd = $signed(rs1) >>> rs2[4:0]
- 算数右移,高位补符号位(为什么没有算数左移,因为没意义)
使用寄存器和立即数进行数字逻辑运算,以及 load 类指令等的指令格式如下:
31 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[11:0] |
rs1 |
funct3 |
rd |
opcode |
立即数为
imm={{20{inst[31]}}, inst[31:20]}
即将立即数的最高位符号位进行扩展到32位
常见的I-type指令
31 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[11:0] |
rs1 |
000 |
rd |
0010011 |
- 指令格式:
addi rd, rs1, imm
rd = rs1 + imm
imm
范围为12位有符号数字-2048~2047
31 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[11:0] |
rs1 |
010 |
rd |
0010011 |
- 使用格式
slti rd,rs1,imm
rd = ($signed(rs1) < $signed(imm)) ? 1 : 0
- 有符号数的比较
31 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[11:0] |
rs1 |
011 |
rd |
0010011 |
- 使用格式
sltiu rd,rs1,imm
rd = (rs1 < imm) ? 1 : 0
- 进行无符号数的比较,
rs1
和imm
都是无符号数
31 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[11:0] |
rs1 |
111 |
rd |
0010011 |
- 使用格式
andi rd,rs1,imm
rd = rs1 & imm
imm
范围在-2048~2047,位数不够时会扩展符号位
31 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[11:0] |
rs1 |
110 |
rd |
0010011 |
- 使用格式
ori rd,rs1,imm
rd = rs1 | imm
imm
范围在-2048~2047,位数不够时会扩展符号位
31 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[11:0] |
rs1 |
100 |
rd |
0010011 |
- 使用格式
xori rd,rs1,imm
rd = rs1 ^ imm
imm
范围在-2048~2047,位数不够时会扩展符号位
- 需要注意的是
xori rd,rs1,-1
等价于与全1异或:rd=~rs1
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
0000000 |
shamt |
rs1 |
001 |
rd |
0010011 |
- 使用格式
slli rd,rs1,shamt
rd = rs1 << shamt
- 逻辑左移
shmat
在原来rs2
的位置上,为五位立即数;此时空出来相当于原来的func7
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
0000000 |
shamt |
rs1 |
101 |
rd |
0010011 |
- 使用格式
srli rd,rs1,shamt
rd = rs1 >> shamt
- 逻辑右移
shmat
在原来rs2
的位置上,为五位立即数;此时空出来相当于原来的func7
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
0100000 |
shamt |
rs1 |
101 |
rd |
0010011 |
- 使用格式
srai rd,rs1,shamt
rd = $signed(rs1) >>> shamt
- 算数右移,高位补符号位
31 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[11:0] |
rs1 |
000 |
rd |
1100111 |
- 使用格式
jalr rd,rs1,imm
rd = pc+4; pc = (rs1 + imm) & ~1
,即最低位为0
- 可以实现任意位置的跳转
31 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[11:0] |
rs1 |
000 |
rd |
0000011 |
- 使用格式
lb rd,imm(rs1)
rd = {{24M[rs1+imm][7]},M[rs1 + imm][7:0]}
- 从内存的
rs1+imm
地址处读取一个字节的数据,符号扩展到32位,存到rd
中
31 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[11:0] |
rs1 |
001 |
rd |
0000011 |
-
使用格式 lh rd,imm(rs1)
rd = {{16M[rs1+imm][15]},M[rs1 + imm][15:0]}
-
从内存的rs1+imm
地址处读取一个半字的数据,存到rd
的低16位,符号扩展到32位
31 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[11:0] |
rs1 |
010 |
rd |
0000011 |
- 使用格式
lw rd,imm(rs1)
rd = M[rs1 + imm]
- 从内存的
rs1+imm
地址处读取一个字的数据,存到rd
中
31 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[11:0] |
rs1 |
100 |
rd |
0000011 |
- 使用格式
lbu rd,imm(rs1)
`rd = M[rs1 + imm][7:0]
- 从内存的
rs1+imm
地址处读取一个字节的数据,零扩展到32位,存到rd
中(高位全0)
31 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[11:0] |
rs1 |
101 |
rd |
0000011 |
- 使用格式
lhu rd,imm(rs1)
rd = M[rs1 + imm][15:0]
- 从内存的
rs1+imm
地址处读取一个半字的数据,零扩展到32位,存到rd
中(高位全0)
31 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
000000000000 |
00000 |
000 |
00000 |
1110011 |
- 使用格式
ecall
系统调用
31 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
000000000001 |
00000 |
000 |
00000 |
1110011 |
- 使用格式
ebreak
,将控制流转到调试环境
store 类指令,将寄存器中的数据存储到内存中,存储的大小由func3
决定,没有rd
寄存器
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[11:5] |
rs2 |
rs1 |
funct3 |
imm[4:0] |
opcode |
立即数为
imm = {{20{inst[31]}}, inst[31:25], inst[11:7]}
将
rd
的5位和
func7
的7位一共12位组合成一个立即数
在RISC-V指令集中,B型(B-type)指令用于条件分支,根据比较结果决定是否跳转到指定的偏移地址。B型指令通常包含两个寄存器进行比较以及一个立即数偏移量(表示跳转的距离)。
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[12,10:5] |
rs2 |
rs1 |
funct3 |
imm[4:1,11] |
opcode |
立即数为
imm={{19{inst[31]}}, inst[31], inst[7], inst[30:25], inst[11:8], 1'b0}
最低位为0,不存;扩展到imm[12]位;将13位拼接完后,剩下高19位用
inst[31]
符号位填充,此时imm[11]可以不是符号位;imm[12]是符号位
常用的B-type指令
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[12,10:5] |
rs2 |
rs1 |
000 |
imm[4:1,11] |
1100011 |
- 使用格式:
beq rs1,rs2,imm
if(rs1 == rs2) pc = pc + imm
- 可以跳转到\(\pm 2^{12}Byte\)的位置,即\(\pm 4KiB\)
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[12,10:5] |
rs2 |
rs1 |
001 |
imm[4:1,11] |
1100011 |
- 使用格式:
bne rs1,rs2,imm
if(rs1 != rs2) pc = pc + imm
- 可以跳转到\(\pm 2^{12}Byte\)的位置,即\(\pm 4KiB\)
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[12,10:5] |
rs2 |
rs1 |
100 |
imm[4:1,11] |
1100011 |
- 使用格式:
blt rs1,rs2,imm
if($signed(rs1) < $signed(rs2)) pc = pc + imm
- 有符号数
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[12,10:5] |
rs2 |
rs1 |
101 |
imm[4:1,11] |
1100011 |
- 使用格式:
bge rs1,rs2,imm
if($signed(rs1) >= $signed(rs2)) pc = pc + imm
- 有符号数
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[12,10:5] |
rs2 |
rs1 |
110 |
imm[4:1,11] |
1100011 |
- 使用格式:
bltu rs1,rs2,imm
if(rs1 < rs2) pc = pc + imm
- 无符号数比较
31 |
|
25 |
24 |
|
20 |
19 |
|
15 |
14 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[12,10:5] |
rs2 |
rs1 |
111 |
imm[4:1,11] |
1100011 |
- 使用格式:
bgeu rs1,rs2,imm
if(rs1 >= rs2) pc = pc + imm
- 无符号数比较
31 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[31:12] |
rd |
opcode |
没有源操作数,只有目的操作数,立即数为
31 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[20,10:1,11,19:12] |
rd |
opcode |
立即数为
imm={{11{inst[31]}}, inst[31], inst[19:12], inst[20], inst[30:21], 1'b0}
imm
最低位0不存,此时
imm[20]
是符号位,
imm
相当于21位有符号数
,跳转范围是
\(\pm 2^{20}\)
JAL指令
31 |
|
12 |
11 |
|
7 |
6 |
|
0 |
imm[20,10:1,11,19:12] |
rd |
1101111 |
- 使用格式
jal rd,imm
rd = pc + 4; pc = pc + imm
- 将
pc+4
存入rd
,然后跳转到pc+imm
处
- Jal指令的跳转范围是\(\pm 2^{20}Byte\),即\(\pm 1MiB\)