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  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









免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM