有人预言,RISC-V或将是继Intel和Arm之后的第三大主流处理器体系。欢迎访问全球首家只专注于RISC-V单片机行业应用的中文网站
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
本帖最后由 皋陶 于 2021-3-6 12:32 编辑
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) 注:立即数为补码表示
lhlh 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)
lwlw 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)
lbulbu 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)
lhulhu 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)
sbsb 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
shsh 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
swsw 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, 跳转到溢出程序处理
复制代码 算术指令: addadd 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 addiaddi 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
subsub 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
luilui 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,
auipcauipc 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值。
逻辑指令: xorxor 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
xorixori 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
oror 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
oriori 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
andand 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
andiandi 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
移位指令:sllsll 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
sllislli 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
srlsrl 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
srlisrli 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
srasra 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
sraisrai 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
比较指令:
sltslt 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
sltislti 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
sltusltu 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
sltiusltiu 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. 控制指令,包括无条件跳转指令和条件跳转指令beqbeq 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
bnebne 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
bltblt 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
bltubltu 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
bgeubgeu 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
jaljal 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寄存器。 这两条指令在调试代码时候有用。
ecallecall //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
ebreakEbreak //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
完
|