RISC-V RV32I Base Instruction Set
转载自 https://www.cnblogs.com/mikewolf2002/p/11196680.html
RV32I是32位基础整数指令集,它支持32位寻址空间,支持字节地址访问,仅支持小端格式(little-endian,高地址高位,低地址地位),寄存器也是32位整数寄存器。RV32I指令集的目的是尽量简化硬件的实施设计,所以它只有40条指令(备注,之前是47条指令,在最新的规范中,一些csr指令被放在扩展指令集中)。这40条指令几乎能够模拟其它任何扩展指令(除了A扩展指令,因为原子指令需要硬件支持)。如果用更简单的实现方式,比如对于ECALL和EBREAK指令,调用时候,系统总是自陷(trap),以及用NOP指令模拟Fence指令,则RV32I甚至可以减少到38条指令(备注:在RISC V中,NOP指令是伪代码,其实就是addi, x0,x0,0)。
实际上要实现机器模式的RiscV特权架构,还需要6条csr指令,之前这些指令都是在RV32I中的,现在被放在扩展指令集 Zicsr中了。所以说要实现一个完整的RiscV系统,至少要实现RV32I+Zicsr指令集。
在RV32I指令集架构中,包括32个通用目的寄存器,其中x0被预留为常数0,其它31个寄存器(x1-x31)是普通的通用整数寄存器。在Risc-V汇编语言中,每个通用寄存器都有一个对应的ABI名字,也就是说在汇编语言中,x1等价于ra,它们都会汇编成相同的机器码。对于RV32I,通用寄存器是32位的寄存器,xlen=32;对于RV64I,通用寄存器是64位寄存器,xlen=64。
在Risc-V架构中,要得到当前指令pc(指令在存储器中的位置,instruction program counter),可以通过AUIPC指令,把它读入到一个通用寄存器中。
寄存器 | ABI名字 | 注释 | Saver |
x0 | zero | Hard-wired zero,常数0 | |
x1 | ra | Return address | caller,调用函数的指令pc |
x2 | sp | Stack pointer | callee,被调用的函数指令pc |
x3 | gp | Global pointer | |
x4 | tp | Thread pointer | |
x5 | t0 | Temporary/alternate link register | caller |
x6 | t1 | Temporaries | caller |
x7 | t2 | Temporaries | caller |
x8 | s0/fp | Saved register/frame pointer | caller |
x9 | s1 | Saved register | caller |
x10 | a0 | Function arguments/return values | caller |
x11 | a1 | Function arguments/return values | caller |
x12 | a2 | Function arguments | caller |
x13 | a3 | Function arguments | caller |
x14 | a4 | Function arguments | caller |
x15 | a5 | Function arguments | caller |
x16 | a6 | Function arguments | caller |
x17 | a7 | Function arguments | caller |
x18 | s2 | Saved registers | caller |
x19 | s3 | Saved registers | caller |
x20 | s4 | Saved registers | caller |
x21 | s5 | Saved registers | caller |
x22 | s6 | Saved registers | caller |
x23 | s7 | Saved registers | caller |
x24 | s8 | Saved registers | caller |
x25 | s9 | Saved registers | caller |
x26 | s10 | Saved registers | caller |
x27 | s11 | Saved registers | caller |
x28 | t3 | Temporaries | caller |
x29 | t4 | Temporaries | caller |
x30 | t5 | Temporaries | caller |
x31 | t6 | Temporaries | caller |
Base指令格式:
RV32I指令格式包括以下6种,每种指令格式都是固定的32位指令,所以指令在内存中必须4字节对齐。比如一个分支跳转指令,当条件判定是跳转的时候,而目的地址不是4字节对齐,则产生指令地址不对齐异常。无条件跳转指令也是如此,目的地址不是4字节对齐,则产生指令地址不对齐异常。备注:但在实际应用中,很难会产生这种错误,因为在汇编语言中,我们用label作为跳转目的,汇编器会自动帮我们产生字节对齐的偏移地址。
其中rd表示目的寄存器,rs1是源操作数寄存器1,rs2是源操作数寄存器2。
imm表示指令中的立即数,比如imm[11:0],表示一个12位的立即数,它的高20位会符号位扩展,也就是用最左边的位imm[11]来进行扩展。imm[31:12]表示一个32位的立即数,它的低12位会补0。备注: csr指令中的5位立即数不需要符号位扩展。
下图是各种指令格式扩展后的32位立即数。
分支指令(B 类型)的立即数字段在 S 类型的基础上旋转了 1 位。跳转指令(J类型)的直接字段在 U 类型的基础上旋转了 12 位。因此,RISC-V 实际上只有四种基本格式,但我们可以保守地认为它有六种格式。
RV32I整数指令集
RV32I整数指令集分为几个种类:
1.Load和store指令
RV32I是一个load /store架构,所有的memory访问都是通过load/store指令,其它指令都是在寄存器之间或者寄存器和立即数之间进行运算,比如加法指令,减法指令等等。注意,装入目的寄存器如果为x0,将会产生一个异常。Load/Store指令在memory和寄存器之间传输数据,Load指令编码为I型,store指令编码为S型。计算memory地址时候,imm都会符号扩展成32位,然后和rs1相加,得到memory地址。为了提高性能,load/store指令应该尽量对齐地址,比如lw指令,访问地址应该4字节对齐,lh访问地址应该双字节对齐。根据微架构实现的不同,不对齐地址的访问可能会比较慢,而且地址对齐访问,能够确保是原子操作,不对齐的话为了读取和存储数据正确,还要进行额外的同步操作。
lb
lb rd, offset(rs1) //x[rd] = sext(M[x[rs1] + sext(offset)][7:0])
字节加载 (Load Byte). I-type, RV32I and RV64I.
从地址 x[rs1] + sign-extend(offset)读取一个字节,经符号位扩展后写入x[rd]。
imm(offset) | |||||||||||||||||||||||||||||||||
11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | rs1 | func3 | rd | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
lb | I | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
例子:
Disassembly of section .text:
00000000 <.text>:
0: 00510503 lb x10,5(x2)
4: fec18283 lb x5,-20(x3)
注:立即数为补码表示
lh
lh rd, offset(rs1) //x[rd] = sext(M[x[rs1] + sext(offset)][15:0])
半字加载 (Load Halfword). I-type, RV32I and RV64I.
从地址 x[rs1] + sign-extend(offset)读取两个字节,经符号位扩展后写入 x[rd]。
imm(offset) | |||||||||||||||||||||||||||||||||
11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | rs1 | func3 | rd | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
lh | I | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
例子:
0: 00511503 lh x10,5(x2)
lw
lw rd, offset(rs1) //x[rd] = sext(M[x[rs1] + sext(offset)][31:0])
字加载 (Load Word). I-type, RV32I and RV64I.
从地址 x[rs1] + sign-extend(offset)读取四个字节,写入 x[rd]。对于 RV64I,结果要进行符号位扩展。
压缩形式: c.lwsp rd, offset; c.lw rd, offset(rs1)
imm(offset) | ||||||||||||||||||||||||||||||||||
11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | rs1 | func3 | rd | opcode | |||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | RV32I |
lw | I | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | √ |
例子:
0: 00512503 lw x10,5(x2)
lbu
lbu rd, offset(rs1) //x[rd] = M[x[rs1] + sext(offset)][7:0]
无符号字节加载 (Load Byte, Unsigned). I-type, RV32I and RV64I.
从地址 x[rs1] + sign-extend(offset)读取一个字节,经零扩展后写入 x[rd]。
imm(offset) | |||||||||||||||||||||||||||||||||
11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | rs1 | func3 | rd | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
lbu | I | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
例子:
0: 00514503 lbu x10,5(x2)
lhu
lhu rd, offset(rs1) //x[rd] = M[x[rs1] + sext(offset)][15:0]无符号半字加载 (Load Halfword, Unsigned). I-type, RV32I and RV64I.
从地址 x[rs1] + sign-extend(offset)读取两个字节,经零扩展后写入 x[rd]。
imm(offset) | |||||||||||||||||||||||||||||||||
11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | rs1 | func3 | rd | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
lhu | I | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
例子:
0: 00515503 lhu x10,5(x2)
sb
sb rs2, offset(rs1) //M[x[rs1] + sext(offset)] = x[rs2][7: 0]存字节(Store Byte). S-type, RV32I and RV64I.
将 x[rs2]的低位字节存入内存地址 x[rs1]+sign-extend(offset)。
imm(offset) | imm(offset) | ||||||||||||||||||||||||||||||||
11 | 10 | 9 | 8 | 7 | 6 | 5 | rs2 | rs1 | func3 | 4 | 3 | 2 | 1 | 0 | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
sb | S | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 |
例子:
0: 00520123 sb x5,2(x4) # 0x2
sh
sh rs2, offset(rs1) //M[x[rs1] + sext(offset) = x[rs2][15: 0]
存半字(Store Halfword). S-type, RV32I and RV64I.
将 x[rs2]的低位 2 个字节存入内存地址 x[rs1]+sign-extend(offset)。
imm(offset) | imm(offset) | ||||||||||||||||||||||||||||||||
11 | 10 | 9 | 8 | 7 | 6 | 5 | rs2 | rs1 | func3 | 4 | 3 | 2 | 1 | 0 | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
sh | S | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 1 |
例子:
4: 00521123 sh x5,2(x4) # 0x2
sw
sw rs2, offset(rs1) //M[x[rs1] + sext(offset) = x[rs2][31: 0]
存字(Store Word). S-type, RV32I and RV64I.
将 x[rs2]的低位 4 个字节存入内存地址 x[rs1]+sign-extend(offset)。
压缩形式: c.swsp rs2, offset; c.sw rs2, offset(rs1)
imm(offset) | imm(offset) | ||||||||||||||||||||||||||||||||
11 | 10 | 9 | 8 | 7 | 6 | 5 | rs2 | rs1 | func3 | 4 | 3 | 2 | 1 | 0 | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
sw | S | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 |
例子:
8: 00522123 sw x5,2(x4) # 0x2
2.整数计算指令(算术,逻辑指令,比较指令以及移位指令)
计算指令在寄存器和寄存器之间,或者在寄存器和立即数之间进行算术或逻辑运算。指令格式为I,R,U。
整数计算指令不会产生异常,但我们可以通过分支指令增加溢出(overflow)检测,比如对于无符号数加法:
add t0, t1, t2; bltu t0, t1, overflow; //如果t0<t1,则跳转到溢出处理
对于有符号数,如果知道符号位,则可以用下面代码:
addi t0, t1, +imm; blt t0, t1, overflow; //t0<t1,则跳转到溢出处理,因为imm为正数
对于通用有符号数加法,可以用下面的指令:
add t0, t1, t2; slti t3, t2, 0; //如果t2<0, t3=1 slt t4, t0, t1; //如果t0<t1, t4=1 bne t3, t4, overflow; //如果t3!=t4, 跳转到溢出程序处理
算术指令:
add
add rd, rs1, rs2 //x[rd] = x[rs1] + x[rs2]
把寄存器 x[rs2]加到寄存器 x[rs1]上,结果写入 x[rd]。忽略算术溢出。
加 (Add). R-type, RV32I and RV64I
压缩形式: c.add rd, rs2; c.mv rd, rs2
func7 | rs2 | rs1 | func3 | rd | opcode | ||||||||||||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
add | R | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
例子:
0: 00a48433 add x8,x9,x10
addi
addi rd, rs1, immediate //x[rd] = x[rs1] + sext(immediate)
加立即数(Add Immediate). I-type, RV32I and RV64I.
把符号位扩展的立即数加到寄存器 x[rs1]上,结果写入 x[rd]。忽略算术溢出。
压缩形式: c.li rd, imm; c.addi rd, imm; c.addi16sp imm; c.addi4spn rd, imm
imm | |||||||||||||||||||||||||||||||||
11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | rs1 | func3 | rd | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
addi | I | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 |
我们可以用addi指令实现move指令, addi rd, rs1, 0 <=>mv rd,rs1 //x[rd]=x[rs1]
例子:
0: 01430513 addi x10,x6,20
sub
sub rd, rs1, rs2 //x[rd] = x[rs1] - x[rs2]
减(Substract). R-type, RV32I and RV64I.
x[rs1]减去 x[rs2],结果写入 x[rd]。忽略算术溢出。
压缩形式: c.sub rd, rs2
func7 | rs2 | rs1 | func3 | rd | opcode | ||||||||||||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
sub | R | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
例子:
0: 40a48433 sub x8,x9,x10
lui
lui rd, immediate //x[rd] = sext(immediate[31:12] << 12)
高位立即数加载 (Load Upper Immediate). U-type, RV32I and RV64I.
20 位立即数 immediate 左移 12 位, 并将低 12 位置零, 写入 x[rd]中。
压缩形式: c.lui rd, imm
imm | |||||||||||||||||||||||||||||||||
19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | rd | opcode | ||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
lui | U | 0 | 1 | 1 | 0 | 1 | 1 | 1 |
例子:
0: 00003237 lui x4,0x3
4: 000141b7 lui x3,0x14
8: 000102b7 lui x5,0x10
lui x5,-0x10 注意:立即数不能为负,范围是0..1048575。
mm.s: Assembler messages:
mm.s:1: Error: lui expression not in range 0..1048575,
auipc
auipc rd, immediate //x[rd] = pc + sext(immediate[31:12] << 12)
PC 加立即数 (Add Upper Immediate to PC). U-type, RV32I and RV64I.
把符号位扩展的 20 位(左移 12 位)立即数加到 pc 上,结果写入 x[rd]。
imm | |||||||||||||||||||||||||||||||||
19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | rd | opcode | ||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
auipc | U | 0 | 0 | 1 | 0 | 1 | 1 | 1 |
例子:
0: 0000a297 auipc x5,0xa
用 auipc x5,0 我们能得到当前的pc值。
逻辑指令:
xor
xor rd, rs1, rs2 //x[rd] = x[rs1] ^ x[rs2]
异或(Exclusive-OR). R-type, RV32I and RV64I.
x[rs1]和 x[rs2]按位异或,结果写入 x[rd]。
压缩形式: c.xor rd, rs2
func7 | rs2 | rs1 | func3 | rd | opcode | ||||||||||||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
xor | R | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
例子:
c: 00a4c433 xor x8,x9,x10
xori
xori rd, rs1, immediate //x[rd] = x[rs1] ^ sext(immediate)
立即数异或(Exclusive-OR Immediate). I-type, RV32I and RV64I.
x[rs1]和有符号扩展的 immediate 按位异或,结果写入 x[rd]。
压缩形式: c.xor rd, rs2
imm | |||||||||||||||||||||||||||||||||
11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | rs1 | func3 | rd | opcode | ||||||||||||||||||
xori | I | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 |
例子:
0: 00224293 xori x5,x4,2
or
or rd, rs1, rs2 //x[rd] = x[rs1] | x[rs2]
取或(OR). R-type, RV32I and RV64I.
把寄存器 x[rs1]和寄存器 x[rs2]按位取或,结果写入 x[rd]。
压缩形式: c.or rd, rs2
func7 | rs2 | rs1 | func3 | rd | opcode | ||||||||||||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
or | R | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
例子:
18: 00a4e433 or x8,x9,x10
ori
ori rd, rs1, immediate //x[rd] = x[rs1] | sext(immediate)
立即数取或(OR Immediate). R-type, RV32I and RV64I.
把寄存器 x[rs1]和有符号扩展的立即数 immediate 按位取或,结果写入 x[rd]。
压缩形式: c.or rd, rs2
imm | |||||||||||||||||||||||||||||||||
11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | rs1 | func3 | rd | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
ori | I | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 |
例子:
0: 00226293 ori x5,x4,2
and
and rd, rs1, rs2 //x[rd] = x[rs1] & x[rs2]
与 (And). R-type, RV32I and RV64I.
将寄存器 x[rs1]和寄存器 x[rs2]位与的结果写入 x[rd]。
压缩形式: c.and rd, rs2
func7 | rs2 | rs1 | func3 | rd | opcode | ||||||||||||||||||||||||||||
and | R | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
例子:
1c: 00a4f433 and x8,x9,x10
andi
andi rd, rs1, immediate //x[rd] = x[rs1] & sext(immediate)
与立即数 (And Immediate). I-type, RV32I and RV64I.
把符号位扩展的立即数和寄存器 x[rs1]上的值进行位与,结果写入 x[rd]。
压缩形式: c.andi rd, imm
imm | |||||||||||||||||||||||||||||||||
11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | rs1 | func3 | rd | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
andi | I | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 1 |
例子:
0: 00227293 andi x5,x4,2
移位指令:
sll
sll rd, rs1, rs2 //x[rd] = x[rs1] ≪ x[rs2]
逻辑左移(Shift Left Logical). R-type, RV32I and RV64I.
把寄存器 x[rs1]左移 x[rs2]位,空出的位置填入 0,结果写入 x[rd]。 x[rs2]的低 5 位(如果是RV64I 则是低 6 位)代表移动位数,其高位则被忽略。
func7 | rs2 | rs1 | func3 | rd | opcode | ||||||||||||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
sll | R | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
例子:
0: 00a49433 sll x8,x9,x10
slli
slli rd, rs1, shamt //x[rd] = x[rs1] ≪ shamt
立即数逻辑左移(Shift Left Logical Immediate). I-type, RV32I and RV64I.
把寄存器 x[rs1]左移 shamt位,空出的位置填入 0,结果写入 x[rd]。对于 RV32I,仅当 shamt[5]=0
时,指令才是有效的。
压缩形式: c.slli rd, shamt
shamt | |||||||||||||||||||||||||||||||||
5 | 4 | 3 | 2 | 1 | 0 | rs1 | func3 | rd | opcode | ||||||||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
slli | I | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 1 |
例子:
0: 00511513 slli x10,x2,0x5
srl
srl rd, rs1, rs2 //x[rd] = (x[rs1] ≫u x[rs2])
逻辑右移(Shift Right Logical). R-type, RV32I and RV64I.
把寄存器 x[rs1]右移 x[rs2]位,空出的位置填入 0,结果写入 x[rd]。 x[rs2]的低 5 位(如果是 RV64I 则是低 6 位)代表移动位数,其高位则被忽略。
func7 | rs2 | rs1 | func3 | rd | opcode | ||||||||||||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
srl | R | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
例子:
10: 00a4d433 srl x8,x9,x10
srli
srli rd, rs1, shamt //x[rd] = (x[rs1] ≫u shamt)
立即数逻辑右移(Shift Right Logical Immediate). I-type, RV32I and RV64I.
把寄存器 x[rs1]右移 shamt位,空出的位置填入 0,结果写入 x[rd]。对于 RV32I,仅当 shamt[5]=0 时,指令才是有效的。
压缩形式: c.srli rd, shamt
shamt | |||||||||||||||||||||||||||||||||
5 | 4 | 3 | 2 | 1 | 0 | rs1 | func3 | rd | opcode | ||||||||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
srli | I | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 1 |
例子:
0: 00515513 srli x10,x2,0x5
sra
sra rd, rs1, rs2 //x[rd] = (x[rs1] ≫s x[rs2])
算术右移(Shift Right Arithmetic). R-type, RV32I and RV64I.
把寄存器 x[rs1]右移 x[rs2]位,空位用 x[rs1]的最高位填充,结果写入 x[rd]。 x[rs2]的低 5 位 (如果是 RV64I 则是低 6 位)为移动位数,高位则被忽略。
func7 | rs2 | rs1 | func3 | rd | opcode | ||||||||||||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
sra | R | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
例子:
14: 40a4d433 sra x8,x9,x10
srai
srai rd, rs1, shamt //x[rd] = (x[rs1] ≫s shamt)
立即数算术右移(Shift Right Arithmetic Immediate). I-type, RV32I and RV64I.
把寄存器 x[rs1]右移 shamt 位,空位用 x[rs1]的最高位填充,结果写入 x[rd]。对于 RV32I, 仅当 shamt[5]=0 时指令有效。
压缩形式: c.srai rd, shamt
shamt | |||||||||||||||||||||||||||||||||
5 | 4 | 3 | 2 | 1 | 0 | rs1 | func3 | rd | opcode | ||||||||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
srai | I | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 1 |
例子:
0: 40515513 srai x10,x2,0x5
比较指令:
slt
slt rd, rs1, rs2 //x[rd] = (x[rs1] <s x[rs2])
小于则置位(Set if Less Than). R-type, RV32I and RV64I.
比较 x[rs1]和 x[rs2]中的数,如果 x[rs1]更小,向 x[rd]写入 1,否则写入 0。
func7 | rs2 | rs1 | func3 | rd | opcode | ||||||||||||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
slt | R | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
例子:
4: 00a4a433 slt x8,x9,x10
slti
slti rd, rs1, immediate //x[rd] = (x[rs1] <s sext(immediate))
小于立即数则置位(Set if Less Than Immediate). I-type, RV32I and RV64I.
比较 x[rs1]和有符号扩展的 immediate,如果 x[rs1]更小,向 x[rd]写入 1,否则写入 0。
imm | |||||||||||||||||||||||||||||||||
11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | rs1 | func3 | rd | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
slti | I | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 |
例子:
0: 00222293 slti x5,x4,2
sltu
sltu rd, rs1, rs2 //x[rd] = (x[rs1] <u x[rs2])
无符号小于则置位(Set if Less Than, Unsigned). R-type, RV32I and RV64I.
比较 x[rs1]和 x[rs2],比较时视为无符号数。如果 x[rs1]更小,向 x[rd]写入 1,否则写入 0。
func7 | rs2 | rs1 | func3 | rd | opcode | ||||||||||||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
sltu | R | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
例子:
8: 00a4b433 sltu x8,x9,x10
sltiu
sltiu rd, rs1, immediate //x[rd] = (x[rs1] <u sext(immediate))
无符号小于立即数则置位(Set if Less Than Immediate, Unsigned). I-type, RV32I and RV64I.
比较 x[rs1]和有符号扩展的 immediate,比较时视为无符号数。如果 x[rs1]更小,向 x[rd]写入 1,否则写入 0
imm | |||||||||||||||||||||||||||||||||
11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | rs1 | func3 | rd | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
sltiu | I | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 1 |
例子:
0: 00223293 sltiu x5,x4,2
3. 控制指令,包括无条件跳转指令和条件跳转指令
beq
beq rs1, rs2, offset //if (rs1 == rs2) pc += sext(offset)
相等时分支跳转 (Branch if Equal). B-type, RV32I and RV64I.
若寄存器 x[rs1]和寄存器 x[rs2]的值相等,把 pc 的值设为当前值加上符号位扩展的偏移 offset。
压缩形式: c.beqz rs1, offset
imm | imm | ||||||||||||||||||||||||||||||||
12 | 10 | 9 | 8 | 7 | 6 | 5 | rs2 | rs1 | func3 | 4 | 3 | 2 | 1 | 11 | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
beq | B | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 1 |
例子:
00000000 <label-0x8>:
0: 00628463 beq x5,x6,8 <label>
4: 00a48433 add x8,x9,x10
00000008 <label>:
8: 00d605b3 add x11,x12,x13
bne
bne rs1, rs2, offset //if (rs1 ≠ rs2) pc += sext(offset)
不相等时分支跳转 (Branch if Not Equal). B-type, RV32I and RV64I.
若寄存器 x[rs1]和寄存器 x[rs2]的值不相等,把 pc 的值设为当前值加上符号位扩展的偏移offset。
压缩形式: c.bnez rs1, offset
imm | imm | ||||||||||||||||||||||||||||||||
12 | 10 | 9 | 8 | 7 | 6 | 5 | rs2 | rs1 | func3 | 4 | 3 | 2 | 1 | 11 | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
bne | B | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 1 |
例子:
00000000 <label-0x8>:
0: 00629463 bne x5,x6,8 <label>
4: 00a48433 add x8,x9,x10
00000008 <label>:
8: 00d605b3 add x11,x12,x13
blt
blt rs1, rs2, offset //if (rs1 <s rs2) pc += sext(offset)
小于时分支跳转 (Branch if Less Than). B-type, RV32I and RV64I.
若寄存器 x[rs1]的值小于寄存器 x[rs2]的值(均视为二进制补码),把 pc 的值设为当前值加上符号位扩展的偏移 offset。
imm | imm | ||||||||||||||||||||||||||||||||
12 | 10 | 9 | 8 | 7 | 6 | 5 | rs2 | rs1 | func3 | 4 | 3 | 2 | 1 | 11 | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
blt | B | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 1 |
例子:
00000000 <label-0x8>:
0: 0062c463 blt x5,x6,8 <label>
4: 00a48433 add x8,x9,x10
00000008 <label>:
8: 00d605b3 add x11,x12,x13
bge
bge rs1, rs2, offset //if (rs1 ≥s rs2) pc += sext(offset)
大于等于时分支 跳转(Branch if Greater Than or Equal). B-type, RV32I and RV64I.
若寄存器 x[rs1]的值大于等于寄存器 x[rs2]的值(均视为二进制补码),把 pc 的值设为当前值加上符号位扩展的偏移 offset。
imm | imm | ||||||||||||||||||||||||||||||||
12 | 10 | 9 | 8 | 7 | 6 | 5 | rs2 | rs1 | func3 | 4 | 3 | 2 | 1 | 11 | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
bge | B | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 1 |
例子:
00000000 <label-0x8>:
0: 0062d463 bge x5,x6,8 <label>
4: 00a48433 add x8,x9,x10
00000008 <label>:
8: 00d605b3 add x11,x12,x13
bltu
bltu rs1, rs2, offset //if (rs1 <u rs2) pc += sext(offset)
无符号小于时分支跳转 (Branch if Less Than, Unsigned). B-type, RV32I and RV64I.
若寄存器 x[rs1]的值小于寄存器 x[rs2]的值(均视为无符号数),把 pc 的值设为当前值加上
符号位扩展的偏移 offset。
imm | imm | ||||||||||||||||||||||||||||||||
12 | 10 | 9 | 8 | 7 | 6 | 5 | rs2 | rs1 | func3 | 4 | 3 | 2 | 1 | 11 | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
bltu | B | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 1 |
例子:
00000000 <label-0x8>:
0: 0062e463 bltu x5,x6,8 <label>
4: 00a48433 add x8,x9,x10
00000008 <label>:
8: 00d605b3 add x11,x12,x13
bgeu
bgeu rs1, rs2, offset //if (rs1 ≥u rs2) pc += sext(offset)
无符号大于等于时分支跳转 (Branch if Greater Than or Equal, Unsigned). B-type, RV32I and RV64I.
若寄存器 x[rs1]的值大于等于寄存器 x[rs2]的值(均视为无符号数),把 pc 的值设为当前值加上符号位扩展的偏移 offset。
imm | imm | ||||||||||||||||||||||||||||||||
12 | 10 | 9 | 8 | 7 | 6 | 5 | rs2 | rs1 | func3 | 4 | 3 | 2 | 1 | 11 | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
bgeu | B | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 1 |
例子:
00000000 <label-0x8>:
0: 0062f463 bgeu x5,x6,8 <label>
4: 00a48433 add x8,x9,x10
00000008 <label>:
8: 00d605b3 add x11,x12,x13
jal
jal rd, offset //x[rd] = pc+4; pc += sext(offset)
跳转并链接 (Jump and Link). J-type, RV32I and RV64I.
把下一条指令的地址(pc+4)保存到目的寄存器,然后把 pc 设置为当前值加上符号位扩展的offset。rd 默认为 x1。
压缩形式: c.j offset; c.jal offset
imm | |||||||||||||||||||||||||||||||||
20 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 11 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | rd | opcode | ||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
jal | J | 1 | 1 | 0 | 1 | 1 | 1 | 1 |
例子:
00000000 <label-0x1c>:
0: 01430513 addi x10,x6,20
4: 01430593 addi x11,x6,20
8: 01430513 addi x10,x6,20
c: 01430513 addi x10,x6,20
10: 00c000ef jal x1,1c <label>
14: 01430613 addi x12,x6,20
18: 01430613 addi x12,x6,20
0000001c <label>:
1c: 01430613 addi x12,x6,20
20: 01430613 addi x12,x6,20
24: 01430613 addi x12,x6,20
注意:汇编和spec有点不一样,汇编里面jal的立即数是绝对地址,但指令编码是对的,偏移了12个字节,所以imm[3:1]=110,imm[0]默认为0。
00000004 <label>:
4: 01430593 addi x11,x6,20
8: 01430513 addi x10,x6,20
c: 01430513 addi x10,x6,20
10: ff5ff0ef jal x1,4 <label>
14: 01430613 addi x12,x6,20
18: 01430613 addi x12,x6,20
偏移 为-12,补码表示
jalr
jalr rd, offset(rs1) // t =pc+4; pc=(x[rs1]+sext(offset))&~1; x[rd]=t
跳转并寄存器链接 (Jump and Link Register). I-type, RV32I and RV64I.
把 pc 设置为 x[rs1] + sign-extend(offset),把计算出的地址的最低有效位设为 0,并将原 pc+4的值写入 f[rd]。 rd 默认为 x1。
压缩形式: c.jr rs1; c.jalr rs1
imm | |||||||||||||||||||||||||||||||||
11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | rs1 | func3 | rd | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
jalr | I | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 1 |
例子:
00000000 <label-0x4>:
0: 01430513 addi x10,x6,20
00000004 <label>:
4: 01430593 addi x11,x6,20
8: 01430513 addi x10,x6,20
c: 01430513 addi x10,x6,20
10: ffc082e7 jalr x5,-4(x1)
14: 01430613 addi x12,x6,20
18: 01430613 addi x12,x6,20
00000000 <label-0x4>:
0: 01430513 addi x10,x6,20
00000004 <label>:
4: 01430593 addi x11,x6,20
8: 01430513 addi x10,x6,20
c: 01430513 addi x10,x6,20
10: 004082e7 jalr x5,4(x1)
14: 01430613 addi x12,x6,20
18: 01430613 addi x12,x6,20
4. 同步指令
fence
fence pred, succ //Fence(pred, succ)
同步内存和 I/O(Fence Memory and I/O). I-type, RV32I and RV64I.
在后续指令中的内存和 I/O 访问对外部(例如其他线程)可见之前,使这条指令之前的内存及 I/O 访问对外部可见。比特中的第 3,2,1 和 0 位分别对应于设备输入,设备输出,内存读写。例如 fence r, rw,将前面读取与后面的读取和写入排序,使用 pred = 0010 和 succ = 0011进行编码。如果省略了参数,则表示 fence iorw, iorw,即对所有访存请求进行排序。
pred | succ | rs1 | func3 | rd | opcode | ||||||||||||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
fence | I | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
例子:
0: 0ff0000f fence iorw,iorw
Risc-V在多个hart(硬件线程)之间使用的是松散一致性模型,所以需要存储器fence指令。
fence指令能够保证存储器访问的执行顺序。在fence指令之前的所有存储器访问指令,比该fence之后的所有数据存储器访问指令先执行。
Risc-V架构将数据存储器的地址空间分为设备IO(device IO)和普通存储器空间,因此其读写访问分为四种类型:
I:设备读(device-input)
O:设备写(device-ouput)
R:存储器读(memory-reads)
W:存储器写(memory-writes)
PI/PO/PR/PW,分别表示fence指令之前的四种读写访问类型,SI/SO/SR/SW分别表示fence指令之后的四种读写访问类型。
6.环境调用和断点指令
这两条指令能够产生环境调用异常和生成断点异常,产生异常时候,当前指令的pc值被写入mepc寄存器。
这两条指令在调试代码时候有用。
ecall
ecall //RaiseException(EnvironmentCall)
环境调用 (Environment Call). I-type, RV32I and RV64I.
通过引发环境调用异常来请求执行环境。
imm | |||||||||||||||||||||||||||||||||
11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | rs1 | func3 | rd | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
ecall | I | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | 1 |
例子:
0: 00000073 ecall
ebreak
Ebreak //RaiseException(Breakpoint)
环境断点 (Environment Breakpoint). I-type, RV32I and RV64I.
通过抛出断点异常的方式请求调试器。
imm | |||||||||||||||||||||||||||||||||
11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | rs1 | func3 | rd | opcode | ||||||||||||||||||
name | type | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
ebreak | I | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | 1 |
例子:
0: 00100073 ebreak