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 >> shamtrd = 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] << shamttmp = tmp[31:0]rd = signed(tmp)其中 shamt 为 6 位无符号数 |
| srliw | 立即数逻辑右移 (低32位版本) | srliw rd, rs1, shamt |
tmp = rs1[31:0] >> shamttmp = tmp[31:0]rd = signed(tmp)其中 shamt 为 6 位无符号数 |
| sraiw | 立即数算术右移 (低32位版本) | sraiw rd, rs1, shamt |
tmp = rs1[31:0] >> shamttmp = 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=00^1=10异或任何数=任何数
(2) 1异或任何数 = 任何数取反
1^0=11^1=01异或任何数 = 任何数取反
(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] + immtmp = 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)