RV32I基础整数指令集

      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 zeroHard-wired zero,常数0 
x1raReturn addresscaller,调用函数的指令pc
x2spStack pointercallee,被调用的函数指令pc
x3gpGlobal pointer 
x4tpThread pointer 
x5t0Temporary/alternate link registercaller
x6t1Temporariescaller
x7t2Temporariescaller
x8s0/fpSaved register/frame pointercaller
x9s1Saved registercaller
x10a0Function arguments/return valuescaller
x11a1Function arguments/return valuescaller
x12a2Function argumentscaller
x13a3Function argumentscaller
x14a4Function argumentscaller
x15a5Function argumentscaller
x16a6Function argumentscaller
x17a7Function argumentscaller
x18s2Saved registerscaller
x19s3Saved registerscaller
x20s4Saved registerscaller
x21s5Saved registerscaller
x22s6Saved registerscaller
x23s7Saved registerscaller
x24s8Saved registerscaller
x25s9Saved registerscaller
x26s10Saved registerscaller
x27s11Saved registerscaller
x28t3Temporariescaller
x29t4Temporariescaller
x30t5Temporariescaller
x31t6Temporariescaller


Base指令格式:

      RV32I指令格式包括以下6种,每种指令格式都是固定的32位指令,所以指令在内存中必须4字节对齐。比如一个分支跳转指令,当条件判定是跳转的时候,而目的地址不是4字节对齐,则产生指令地址不对齐异常。无条件跳转指令也是如此,目的地址不是4字节对齐,则产生指令地址不对齐异常。备注:但在实际应用中,很难会产生这种错误,因为在汇编语言中,我们用label作为跳转目的,汇编器会自动帮我们产生字节对齐的偏移地址

      其中rd表示目的寄存器,rs1是源操作数寄存器1,rs2是源操作数寄存器2。

image

      imm表示指令中的立即数,比如imm[11:0],表示一个12位的立即数,它的高20位会符号位扩展,也就是用最左边的位imm[11]来进行扩展。imm[31:12]表示一个32位的立即数,它的低12位会补0。备注: csr指令中的5位立即数不需要符号位扩展

下图是各种指令格式扩展后的32位立即数。

image

      分支指令(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)             
  11109876543210rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
lbI                 000     0000011

例子:

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)             
  11109876543210rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
lhI                 001     0000011

例子:

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)              
  11109876543210rs1func3rdopcode 
nametype313029282726252423222120191817161514131211109876543210RV32I
lwI                 010     0000011

例子:

  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)             
  11109876543210rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
lbuI                 100     0000011

例子:

   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)             
  11109876543210rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
lhuI                 101     0000011

例子:

   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)        
  111098765rs2rs1func343210opcode
nametype313029282726252423222120191817161514131211109876543210
sbS                 000     0100011

例子:

   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)        
  111098765rs2rs1func343210opcode
nametype313029282726252423222120191817161514131211109876543210
shS                 001     0100011

例子:

  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)        
  111098765rs2rs1func343210opcode
nametype313029282726252423222120191817161514131211109876543210
swS                 010     0100011

例子:

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

  func7rs2rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
addR0000000          000     0110011

例子:

      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             
  11109876543210rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
addiI                 000     0010011

我们可以用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

  func7rs2rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
subR0100000          000     0110011

例子:

   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            
  191817161514131211109876543210rdopcode
nametype313029282726252423222120191817161514131211109876543210
luiU                         0110111

例子:

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            
  191817161514131211109876543210rdopcode
nametype313029282726252423222120191817161514131211109876543210
auipcU                         0010111

例子:

   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

  func7rs2rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
xorR0000000          100     0110011

例子:

   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             
  11109876543210rs1func3rdopcode
xoriI                 100     0010011

例子:

   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

  func7rs2rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
orR0000000          110     0110011

例子:

  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             
  11109876543210rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
oriI                 110     0010011

例子:

   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

  func7rs2rs1func3rdopcode
andR0000000          111     0110011

例子:

  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             
  11109876543210rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
andiI                 111     0010011

例子:

  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 位)代表移动位数,其高位则被忽略。

                
  func7rs2rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
sllR0000000          001     0110011

例子:

   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             
        543210rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
slliI000000           001     0010011

例子:

   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 位)代表移动位数,其高位则被忽略。

                
  func7rs2rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
srlR0000000          101     0110011

例子:

  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             
        543210rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
srliI000000           101     0010011

例子:

   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 位)为移动位数,高位则被忽略。

  func7rs2rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
sraR0100000          101     0110011

例子:

  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             
        543210rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
sraiI010000           101     0010011

例子:

   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。

  func7rs2rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
sltR0000000          010     0110011

例子:

   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             
  11109876543210rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
sltiI                 010     0010011

例子:

   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。

                
  func7rs2rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
sltuR0000000          011     0110011

例子:

   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             
  11109876543210rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
sltiuI                 011     0010011

例子:

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 
  121098765rs2rs1func3432111opcode
nametype313029282726252423222120191817161514131211109876543210
beqB                 000     1100011

例子:

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 
  121098765rs2rs1func3432111opcode
nametype313029282726252423222120191817161514131211109876543210
bneB                 001     1100011


例子:

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 
  121098765rs2rs1func3432111opcode
nametype313029282726252423222120191817161514131211109876543210
bltB                 100     1100011


例子:

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 
  121098765rs2rs1func3432111opcode
nametype313029282726252423222120191817161514131211109876543210
bgeB                 101     1100011



例子:

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 
  121098765rs2rs1func3432111opcode
nametype313029282726252423222120191817161514131211109876543210
bltuB                 110     1100011


例子:

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 
  121098765rs2rs1func3432111opcode
nametype313029282726252423222120191817161514131211109876543210
bgeuB                 111     1100011


例子:

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            
  2010987654321111918171615141312rdopcode
nametype313029282726252423222120191817161514131211109876543210
jalJ                         1101111

例子:

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             
  11109876543210rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
jalrI                 000     1100111

例子:

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,即对所有访存请求进行排序


                
      predsuccrs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
fenceI00000000000000000000000000001111

例子:

  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指令之后的四种读写访问类型。

image


6.环境调用和断点指令


这两条指令能够产生环境调用异常和生成断点异常,产生异常时候,当前指令的pc值被写入mepc寄存器。

这两条指令在调试代码时候有用。


ecall

ecall     //RaiseException(EnvironmentCall)
环境调用 (Environment Call). I-type, RV32I and RV64I.
通过引发环境调用异常来请求执行环境。

  imm             
  11109876543210rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
ecallI00000000000000000000000001110011

例子:

   0:   00000073                ecall


ebreak

Ebreak     //RaiseException(Breakpoint)
环境断点 (Environment Breakpoint). I-type, RV32I and RV64I.
通过抛出断点异常的方式请求调试器

  imm             
  11109876543210rs1func3rdopcode
nametype313029282726252423222120191817161514131211109876543210
ebreakI00000000000100000000000001110011

例子:

   0:   00100073                ebreak








原文地址:https://www.cnblogs.com/mikewolf2002/p/11196680.html