RISC-V指令集2
RISC-V指令集提供了丰富的移位和位操作指令。移位指令包括逻辑左移(sll)、逻辑右移(srl)、算术右移(sra)及其立即数版本(slli/srli/srai),主要用于乘除法运算和位操作。RV64还专有32位移位指令(sllw/srlw/sraw等)。位操作指令包含与(and)、或(or)、异或(xor)运算及其立即数版本。异或操作具有特殊性质,可用于位翻转、变量交换和寄存器清零等操作。这些
1. 移位指令
移位指令是RISC-V指令集中用于对数据进行位移操作的重要指令类型。移位操作在计算机中广泛用于乘法、除法、位操作等场景。
1.1 逻辑左移指令 (sll)
sll: 逻辑左移 (Shift Left Logical) 指令
- 功能: 将操作数向左移动指定的位数
- 特点: 最高位会被丢弃,最低位补0
- 用途: 常用于实现乘法运算(左移1位相当于乘以2)
指令格式
sll rd, rs1, rs2
操作说明
rd
: 目标寄存器,存储移位结果rs1
: 源寄存器,包含要移位的操作数rs2
: 移位量寄存器,指定左移的位数
1.2 逻辑右移指令 (srl)
srl: 逻辑右移 (Shift Right Logical) 指令
- 功能: 将操作数向右移动指定的位数
- 特点: 最高位补0,最低位会被丢弃
- 用途: 常用于实现除法运算(右移1位相当于除以2)
指令格式
srl rd, rs1, rs2
操作说明
rd
: 目标寄存器,存储移位结果rs1
: 源寄存器,包含要移位的操作数rs2
: 移位量寄存器,指定右移的位数
1.3 算术右移指令 (sra)
sra: 算术右移 (Shift Right Arithmetic) 指令
- 功能: 将操作数向右移动指定的位数
- 特点: 最低位会被丢弃,最高位会按照符号进行扩展
- 用途: 用于有符号数的除法运算,保持符号位不变
指令格式
sra rd, rs1, rs2
操作说明
rd
: 目标寄存器,存储移位结果rs1
: 源寄存器,包含要移位的操作数rs2
: 移位量寄存器,指定右移的位数- 符号扩展: 如果原数的最高位是1(负数),则右移时高位补1;如果最高位是0(正数),则右移时高位补0
1.4 带立即数的移位指令
带立即数的移位指令是移位指令的扩展形式,它们使用立即数作为移位量,而不是从寄存器中读取。这种设计提高了指令执行效率,因为移位量直接编码在指令中。
1.4.1 立即数逻辑左移指令 (slli)
slli: 立即数逻辑左移 (Shift Left Logical Immediate) 指令
- 功能: 将操作数向左移动指定的立即数位数
- 特点: 最高位会被丢弃,最低位补0
- 优势: 移位量直接编码在指令中,执行效率更高
指令格式
slli rd, rs1, shamt
操作说明
rd
: 目标寄存器,存储移位结果rs1
: 源寄存器,包含要移位的操作数shamt
: 移位量,为6位无符号立即数(0-63)- 操作:
rd = rs1 << shamt
1.4.2 立即数逻辑右移指令 (srli)
srli: 立即数逻辑右移 (Shift Right Logical Immediate) 指令
- 功能: 将操作数向右移动指定的立即数位数
- 特点: 最高位补0,最低位会被丢弃
- 优势: 移位量直接编码在指令中,执行效率更高
指令格式
srli rd, rs1, shamt
操作说明
rd
: 目标寄存器,存储移位结果rs1
: 源寄存器,包含要移位的操作数shamt
: 移位量,为6位无符号立即数(0-63)- 操作:
rd = rs1 >> shamt
1.4.3 立即数算术右移指令 (srai)
srai: 立即数算术右移 (Shift Right Arithmetic Immediate) 指令
- 功能: 将操作数向右移动指定的立即数位数
- 特点: 最低位会被丢弃,最高位会按照符号进行扩展
- 优势: 移位量直接编码在指令中,执行效率更高
指令格式
srai rd, rs1, shamt
操作说明
rd
: 目标寄存器,存储移位结果rs1
: 源寄存器,包含要移位的操作数shamt
: 移位量,为6位无符号立即数(0-63)- 操作:
tmp = rs1 >> shamt
rd = Signed_with_rs1(tmp)
- 符号扩展: 根据rs1的符号位进行符号扩展
1.5 32位移位指令 (RV64专用)
32位移位指令是RISC-V 64位架构(RV64)的专用指令,用于处理32位数据的移位操作。这些指令只对操作数的低32位进行移位,然后将结果符号扩展到64位。
32位移位指令对比表
指令助记符 | 中文描述 | 指令格式 | 操作说明 |
---|---|---|---|
sllw | 逻辑左移 (低32位版本) | sllw rd, rs1, rs2 |
tmp = rs1[31:0] << rs2[4:0] tmp = tmp[31:0] rd = signed(tmp) 其中 rs2 只取最低 5 位数值 |
srlw | 逻辑右移 (低32位版本) | srlw rd, rs1, rs2 |
tmp = rs1[31:0] >> rs2[4:0] rd = signed(tmp) 其中 rs2 只取最低 5 位数值 |
sraw | 算术右移 (低32位版本) | sraw rd, rs1, rs2 |
tmp = rs1[31:0] >> rs2[4:0] rd = Signed_with_rs1(tmp) 其中 rs2 只取最低 5 位数值, 另外结果需要以 rs1 的 Bit[31] 为符号位来做符号扩展 |
slliw | 立即数逻辑左移 (低32位版本) | slliw rd, rs1, shamt |
tmp = rs1[31:0] << shamt tmp = tmp[31:0] rd = signed(tmp) 其中 shamt 为 6 位无符号数 |
srliw | 立即数逻辑右移 (低32位版本) | srliw rd, rs1, shamt |
tmp = rs1[31:0] >> shamt tmp = tmp[31:0] rd = signed(tmp) 其中 shamt 为 6 位无符号数 |
sraiw | 立即数算术右移 (低32位版本) | sraiw rd, rs1, shamt |
tmp = rs1[31:0] >> shamt tmp = tmp[31:0] rd = Signed_with_rs1(tmp) 其中 shamt 为 6 位无符号数, 另外结果需要以 rs1 的 Bit[31] 为符号位来做符号扩展 |
.global shift_test
shift_test:
li t0, 0x8000008a00000000
srai a1, t0, 1 # 0xC000004500000000
srli t1, t0, 1 # 0x4000004500000000
li t0, 0x128000008a # 0x128000008a
sraiw a2, t0, 1 # 0xffffffffC0000045
srliw t1, t0, 1 # 0x40000045
slliw a3, t0, 1 # 0x114
li t0, 0x124000008a
sraiw a2, t0, 1 # 0x20000045
srliw t1, t0, 1 # 0x20000045
slliw a4, t0, 1 # 0xffffffff80000114
2. 位操作指令
2.1 寄存器到寄存器位操作指令
RV64指令集提供与(and)、或(or)以及异或(xor)三种位操作指令
指令助记符 | 中文描述 | 指令格式 | 操作说明 |
---|---|---|---|
and | 与操作 | and rd, rs1, rs2 |
rd = rs1 & rs2 |
xor | 异或操作 | xor rd, rs1, rs2 |
rd = rs1 ^ rs2 |
or | 或操作 | or rd, rs1, rs2 |
rd = rs1 | rs2 |
2.2 立即数位操作指令
• 立即数位操作指令
指令助记符 | 中文描述 | 指令格式 | 操作说明 |
---|---|---|---|
xori | 立即数异或操作 | xori rd, rs1, imm |
rd = rs1 ^ imm 其中 imm 为 12 位有符号数 |
ori | 立即数或操作 | ori rd, rs1, imm |
rd = rs1 | imm 其中 imm 为 12 位有符号数 |
andi | 立即数与操作 | andi rd, rs1, imm |
rd = rs1 & imm 其中 imm 为 12 位有符号数 |
异或操作的妙用
异或的3个小特点
(1) 0异或任何数=任何数
0^0=0
0^1=1
0异或任何数=任何数
(2) 1异或任何数 = 任何数取反
1^0=1
1^1=0
1异或任何数 = 任何数取反
(3) 任何数异或自己 = 把自己置0
任何数异或自己 = 把自己置0
异或的几个小妙用
(1) 使某些特定的位翻转
说明: 要使数字10100001
的第1位和第2位翻转,可以将其与00000110
进行异或运算。
示例: 10100001 ^ 00000110 = 10100111
(2) 交换两个数
说明: 演示如何在不使用临时变量的情况下交换两个整数a
和b
。
示例: 对于a=10100001
和b=00000110
,交换过程如下:
a = a^b; // a变成 10100111
b = b^a; // b变成 10100001 (原来的a)
a = a^b; // a变成 00000110 (原来的b)
(3) 在汇编里让变量设置为0,例如x1寄存器
示例: 汇编指令xor x1, x1, x1
将x1
寄存器设置为0。
(4) 判断两个是否相等
说明: 如果两个数a
和b
相等,它们的异或结果将为0。
示例: return ((a^ b) == 0)
3. 算术运算指令
RV64I指令集只提供最基础的加法和减法指令
指令助记符 | 中文描述 | 指令格式 | 操作说明 |
---|---|---|---|
add | 加法指令 | add rd, rs1, rs2 |
rd = rs1 + rs2 |
sub | 减法指令 | sub rd, rs1, rs2 |
rd = rs1 - rs2 |
addi | 立即数加法 | addi rd, rs1, imm |
rd = rs1 + imm 其中 imm 为 12 位有符号数 |
addiw | 立即数加法 (低32位版本) | addi rd, rs1, imm |
tmp = rs1[31:0] + imm tmp = tmp[31:0] rd = signed (tmp) 其中 imm 为 12 位有符号数 |
addw | 加法 (低32位版本) | addw rd, rs1, rs2 |
tmp = rs1[31:0] + rs2[31:0] tmp = tmp[31:0] rd = signed (tmp) |
subw | 减法 (低32位版本) | subw rd, rs1, rs2 |
tmp = rs1[31:0] - rs2[31:0] tmp = tmp[31:0] rd = signed (tmp) |
3.1 addi指令立即数操作数示例
例子:合法与非法指令识别
问题: 下面两条指令哪一条是非法指令?
addi a1, t0, 0x800
addi a1, t0, 0xfffffffffffff800
答案: 第一条指令为非法指令
汇编器错误信息:
src/asm_test.S: Assembler messages:
src/asm_test.S:12: Error: illegal operands 'addi a1,t0,0x800'
解释:
在GNU AS汇编中,0x800
被看作是一个数值为2048的无符号数,而不是12位宽的带符号扩展的立即数。如果想表示"-2048"立即数,我们需要使用0xfffffffffffff800
。
关键要点:
addi
指令在RISC-V中期望一个12位有符号立即数- GNU AS将
0x800
解释为正无符号值(2048),这超出了12位有符号立即数的范围(-2048到2047) - 要表示负立即数值如-2048,必须使用完整的64位符号扩展表示
0xfffffffffffff800
- 这个值在截断为12位时是
0x800
,在12位二进制补码中确实是-2048
4. 比较指令
比较指令是RISC-V指令集中用于进行数值比较的重要指令类型,支持有符号和无符号数的比较操作。
4.1 RV64I指令集提供的比较指令
RV64I指令集提供4条比较指令
指令类型/描述 | 指令格式 | 操作说明 | 附加说明 |
---|---|---|---|
slt 小于比较指令 | slt rd, rs1, rs2 |
rd = (rs1 < rs2) ? 1 : 0 |
其中 rs1 和 rs2 为有符号数 |
sltu 小于比较指令 | sltu rd, rs1, rs2 |
rd = (rs1 < rs2) ? 1 : 0 |
其中 rs1 和 rs2 为无符号数 |
slti 小于比较指令 | slti rd, rs1, imm |
rd = (rs1 < imm) ? 1 : 0 |
其中 imm 为 12 位有符号数, rs1 为有符号数 |
sltiu 立即数小于比较 | sltiu rd, rs1, imm |
rd = (rs1 < imm) ? 1 : 0 |
其中 imm 为 12 位有符号数, rs1 为无符号数 |
4.2 RV64I指令集提供的比较伪指令
RV64I指令集提供比较伪指令
伪指令 | 伪指令格式 | 说明 |
---|---|---|
sltz | sltz rd, rs1 |
小于0则置位指令。如果rs1的值小于0,向rd寄存器写入1,否则写入0。 |
snez | snez rd, rs1 |
不等于0则置位指令。如果rs1寄存器的值不等于0,向rd寄存器写入1,否则写入0。 |
seqz | seqz rd, rs1 |
等于0则置位指令。如果rs1寄存器的值等于0,向rd寄存器写入1,否则写入0。 |
sgtz | sgtz rd, rs1 |
大于0则置位指令。如果rs1的值大于0,向rd寄存器写入1,否则写入0。 |
5. 无条件跳转指令
无条件跳转指令是RISC-V指令集中用于控制程序流程的重要指令类型,支持函数调用和程序跳转操作。
5.1 RV64I指令集提供的无条件跳转指令
RV64I指令集提供2条无条件跳转指令
指令类型/描述 | 指令格式 | 操作说明 | 附加说明 |
---|---|---|---|
JAL 跳转并链接指令 | jal rd, label |
PC = PC + offset 和 rd = PC + 4 |
其中 offset 为 21 位有符号数, 2 字节对齐 (最低位为 0)。其值表示 label 地址与当前 PC 值的偏移量 |
JALR 使用寄存器跳转并链接指令 | jalr rd, offset(rs1) |
PC = rs1 + offset 和 rd = PC + 4 |
其中 offset 为 12 位有符号数 |
5.2 JAL指令详细说明
JAL指令特点
- JAL (jump and link) 指令使用 J-type 指令编码
- 其操作数
offset[20:1]
由指令编码的[31:12]
位组成 - 默认为 2 的倍数,即其跳转范围约为当前 PC 值的 ±1 MB
- 返回地址(即
PC + 4
)存储在rd
寄存器中 - 如果返回地址存储在
ra
(return address)寄存器中,则可以实现函数返回
5.3 JALR指令详细说明
JALR指令特点
- JALR (jump and link register) 指令使用 I-type 指令编码
- 跳转目标地址由寄存器
rs1
的值加上 12 位有符号立即数offset
计算得出 - 返回地址(即
PC + 4
)存储在rd
寄存器中 - 常用于间接跳转和函数指针调用
应用场景
- 函数调用:
jal ra, function_name
- 调用函数并将返回地址存储在ra寄存器 - 间接跳转:
jalr t0, 0(t1)
- 跳转到t1寄存器指向的地址 - 函数返回:
jalr zero, 0(ra)
- 返回到ra寄存器存储的地址
5.4 RV64I指令集提供的无条件跳转伪指令
无条件跳转伪指令是RISC-V指令集中基于基础跳转指令构建的高级指令,提供了更简洁和易用的编程接口。
伪指令 | 指令组合 | 说明 |
---|---|---|
j label | jal x0, offset |
跳转到label标签处,不带返回地址 |
jal label | jal ra, offset |
跳转到label标签处,返回地址存储在ra寄存器中 |
jr rs | jalr x0, 0(rs) |
跳转到rs寄存器地址处,不带返回地址 |
jalr rs | jalr ra, 0(rs) |
跳转到rs寄存器地址处,返回地址存储在ra寄存器中 |
ret | jalr x0, 0(ra) |
从ra寄存器中获取返回地址,并返回。常用于子函数返回 |
call func | auipc ra, offset[31:12]+offset[11] jalr ra, offset[11:0](ra) |
调用子函数func,返回地址保存到ra寄存器中 |
tail func | auipc x6, offset[31:12]+offset[11] jalr x0, offset[11:0](x6) |
调用子函数func,不保存返回地址 |
6. 条件跳转指令
条件跳转指令是RISC-V指令集中用于实现程序控制流的重要指令类型,根据比较结果决定是否跳转到指定位置。
6.1 RV64I指令集提供的条件跳转指令
RV64I指令集提供多条条件跳转指令
指令 | 指令格式 | 说明 |
---|---|---|
beq | beq rs1, rs2, label |
如果rs1和rs2寄存器的值相等,则跳转到label标签处 |
bne | bne rs1, rs2, label |
如果rs1和rs2寄存器的值不相等,则跳转到label标签处 |
blt | blt rs1, rs2, label |
如果rs1寄存器的值小于rs2,则跳转到label标签处 |
bltu | bltu rs1, rs2, label |
与blt指令类似,只不过rs1和rs2的值为无符号数 |
bgt | bgt rs1, rs2, label |
如果rs1寄存器的值大于rs2,则跳转到label标签处 |
bgtu | bgtu rs1, rs2, label |
与bgt指令类似,只不过rs1和rs2的值为无符号数 |
bge | bge rs1, rs2, label |
如果rs1寄存器的值大于等于rs2,则跳转到label标签处 |
bgeu | bgeu rs1, rs2, label |
与bge指令类似,只不过rs1和rs2的值为无符号数 |
6.2 跳转范围
跳转范围:
- offset表示label标签地址基于当前PC地址的偏移量。
- offset是13位有符号立即数,其中offset[12:1]由指令编码的Bit[31:25]以及Bit[11:7]共同构成,offset[0]为0,它默认是2的倍数,因此它最大寻址范围是[-4KB ~ 4KB]
- 跳转到当前PC地址±4KB的范围
6.3 条件跳转伪指令
条件跳转伪指令是RISC-V指令集中基于基础条件跳转指令构建的高级指令,提供了更简洁和易用的编程接口。这些伪指令通过组合基础指令来实现更直观的比较操作。
伪指令 | 指令组合 | 判断条件 |
---|---|---|
beqz | beq rs, x0, label |
rs == 0 |
bnez | bne rs, x0, label |
rs != 0 |
blez | bge x0, rs, label |
rs <= 0 |
bgez | bge rs, x0, label |
rs >= 0 |
bltz | blt rs, x0, label |
rs < 0 |
bgtz | blt x0, rs, label |
rs > 0 |
bgt | blt rt, rs, label |
rs > rt |
ble | bge rt, rs, label |
rs <= rt |
bgtu | bltu rt, rs, label |
rs > rt (无符号数比较) |
bleu | bgeu rt, rs, label |
rs <= rt (无符号数比较) |
7. CSR指令
CSR(Control and Status Register)指令是RISC-V指令集中用于访问和控制状态寄存器的重要指令类型。这些指令允许程序读取和修改处理器的控制状态寄存器,实现系统级操作。
7.1 CSR指令格式
CSR指令使用I-type指令格式,具有以下字段结构:
31-20: csr字段 (12位) - 用于索引CSR寄存器
19-15: rs1字段 (5位) - 源寄存器或立即数
14-12: funct3字段 (3位) - 指令功能码
11-7: rd字段 (5位) - 目标寄存器
6-0: opcode字段 (7位) - 操作码
7.2 CSR指令详细说明
CSR指令 | 指令格式 | 说明 |
---|---|---|
csrrw | csrrw rd, csr, rs1 |
原子地交换CSR和rs1寄存器的值。读取在CSR的旧值,将其零扩展到64位,然后写入rd寄存器中,与此同时,rs1寄存器的旧值将被写入CSR中。 |
csrrs | csrrs rd, csr, rs1 |
原子地读CSR寄存器的值并且设置CSR寄存器中相应的位。指令读取CSR寄存器的旧值,将其零扩展到64位,然后写入rd寄存器中。与此同时,把rs1寄存器的值做作为掩码,设置CSR寄存器相应的位。 |
csrrc | csrrc rd, csr, rs1 |
原子地读CSR寄存器的值并且清CSR寄存器中相应的位。指令读取CSR寄存器的旧值,将其零扩展到64位,然后写入rd寄存器中。与此同时,把rs1寄存器的值做作为掩码,清CSR寄存器相应的位。 |
csrrwi | csrrwi rd, csr, uimm |
作用与csrrw指令类似,区别在于使用5位无符号立即数替代rs1。 |
csrrsi | csrrsi rd, csr, uimm |
作用与csrrs指令类似,区别在于使用5位无符号立即数替代rs1。 |
csrrci | csrrci rd, csr, uimm |
作用与csrrc指令类似,区别在于使用5位无符号立即数替代rs1。 |
7.3 RV64I指令集基于CSR的伪指令
RV64I指令集提供了基于CSR指令的伪指令,这些伪指令通过组合基础CSR指令来实现更简洁和易用的编程接口。
伪指令 | 指令组合 | 说明 |
---|---|---|
csrr | csrrs rd, csr, x0 |
读取CSR寄存器的值 |
csrw | csrrw x0, csr, rs |
写CSR寄存器的值 |
csrs | csrrs x0, csr, rs |
设置CSR寄存器的字段 (`csr |
csrc | csrrc x0, csr, rs |
清CSR寄存器的字段 (csr &= ~rs ) |
csrwi | csrrwi x0, csr, imm |
把立即数imm写入CSR寄存器中 |
csrsi | csrrsi x0, csr, imm |
设置CSR寄存器的字段 (`csr |
csrci | csrrci x0, csr, imm |
清CSR寄存器的字段 (csr &= ~imm ) |
更多推荐
所有评论(0)