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。

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

image

 

 

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

 

 

 

 

 

 

 

 

posted @ 2022-11-26 11:35  Jerx2y  阅读(306)  评论(0编辑  收藏  举报