有了前兩節對于RISC-V匯編、寄存器、匯編語法等的認識,本節開始介紹RISC-V指令集和偽指令。
前面說了RISC-V的模塊化特點,是以RV32I為作為ISA的核心模塊,其他都是要基于此為基礎,可以這樣認為:RISC-V ISA = 基本整數指令集+多個可選擴展指令集
;另外RISC-V的ISA spec上是從指令類型和指令格式開始介紹指令的;但從一個嵌入式軟件開發人員的角度來說,不是特別適合學習和記憶,所以我這里簡單羅列下,不多講解,感興趣可以參考spec。
1 指令類型
1.1 組成格式
所有RISC-V指令都是固定長度的32位,這有助于簡化指令解碼過程。每個指令都由以下幾個關鍵部分組成:
- opcode:這是7位的操作碼,用來標識指令的基本類型。
- funct3:這是一個3位的功能碼,與opcode一起使用以進一步細化指令的類別。
- funct7:某些指令使用額外的7位功能碼來更精確地定義指令的行為。
- rs1/rs2/rd:這些是5位的寄存器地址,分別代表源寄存器1、源寄存器2和目的寄存器。
- imm:立即數字段,其大小和位置根據指令類型的不同而變化。
1.2 類型
RISC-V定義了幾種基本的指令格式,每一種都針對特定類型的運算或操作。這些格式包括:R型、I型、S型、B型、U型、J型。
-
R型(Register)
用于寄存器間的算術/邏輯運算(如ADD x1, x2, x3)
字段:opcode確定操作類型,funct3和funct7進一步指定具體操作(如區分ADD與SUB) -
I型(Immediate)
用于立即數操作(如ADDI x1, x2, 42)或加載指令(如LW x1, 100(x2))
立即數:12位符號擴展,直接嵌入指令中 -
S型(Store)
存儲數據到內存(如SW x3, 200(x4))
立即數:12位拆分為imm[11:5]和imm[4:0],組合后作為偏移地址。 -
B型(Branch)
條件分支(如BEQ x1, x2, label)
立即數:13位(符號擴展后左移1位),拆分為imm[12|10:5|4:1|11],支持更大跳轉范圍 -
U型(Upper Immediate)
加載高20位立即數(如LUI x1, 0x12345)或構造地址(如AUIPC)
立即數:20位直接嵌入高位,低12位由后續指令補充 -
J型(Jump)
長距離無條件跳轉(如JAL x1, label)
立即數:20位符號擴展后左移1位,支持±1MB跳轉范圍
但在實際應用中,我們也很難記住這么匯編指令機器碼,一般情況下也不會有錯,具體可以參考spec。
2 指令命名
下圖是RV32I基礎指令集的??圖形表示,將有下劃線的字?從左到右連接起來,即可組成完整的RV32I指令集。集合標志{}內列舉了指令的所有變體,變體?加下劃線的字?或下劃線字符_表示,特別的,下劃線字符_表示對于此指令變體不需?字符表示
以slt指令為例,如下示意圖:大括號{ }內列舉了每組指令的所有變體,這些變體通過帶下滑線的字母(單獨的下劃線_表示空字段),從左到右連接帶下滑線的字母即可組成完整的指令集,比如slt意思是set less than,相當于是一種縮寫,完整語句方便我們快速清晰的理解指令的作用。
上圖可以表示:slt、slti、sltu、sltiu 這4條RVI指令。
下面將列舉以下RISC-V指令集:
- RVI(包括RV32I與RV64I)
- RVM(包括RV32M與RV64M)
- RVFD(包括RV32FD與RV64FD)
- RVA(包括RV32A與RV64A)
3 RVI指令集
RVI是 RISC-V 指令集架構的基礎部分,它定義了32位整數運算的核心指令集。RVI 包括 RV32I(32位整數指令集)和 RV64I(64位整數指令集),它們為處理器提供了執行基本計算任務的能力;包括:內存操作指令、邏輯指令、分支和跳轉指令、算術指令等等,下面就一一列舉。
3.1 內存操作指令
在RISC-V中,內存操作主要通過加載(Load)和存儲(Store)兩類指令來實現。這些指令允許程序從內存讀取數據到寄存器(Load),或將寄存器中的數據寫入內存(Store)
指令 | 格式 | 功能描述 | 操作(偽代碼) | 指令集 |
---|---|---|---|---|
LB | lb rd, offset(rs1) | 加載字節(符號擴展) | rd = SignExt(Mem[rs1 + offset][7:0]) | RV32I / RV64I |
LBU | lbu rd, offset(rs1) | 加載字節(無符號擴展) | rd = ZeroExt(Mem[rs1 + offset][7:0]) | RV32I / RV64I |
LH | lh rd, offset(rs1) | 加載半字(符號擴展) | rd = SignExt(Mem[rs1 + offset][15:0]) | RV32I / RV64I |
LHU | lhu rd, offset(rs1) | 加載半字(無符號擴展) | rd = ZeroExt(Mem[rs1 + offset][15:0]) | RV32I / RV64I |
LW | lw rd, offset(rs1) | 加載字(RV32I:32位;RV64I:符號擴展至64位) | RV32I: rd = Mem[rs1 + offset][31:0] RV64I: rd = SignExt(Mem[rs1 + offset][31:0]) | RV32I / RV64I |
LWU | lwu rd, offset(rs1) | 加載字(無符號擴展至64位) | rd = ZeroExt(Mem[rs1 + offset][31:0]) | RV64I |
LD | ld rd, offset(rs1) | 加載雙字(64位) | rd = Mem[rs1 + offset][63:0] | RV64I |
SB | sb rs2, offset(rs1) | 存儲字節 | Mem[rs1 + offset] = rs2[7:0] | RV32I / RV64I |
SH | sh rs2, offset(rs1) | 存儲半字 | Mem[rs1 + offset] = rs2[15:0] | RV32I / RV64I |
SW | sw rs2, offset(rs1) | 存儲字 | Mem[rs1 + offset] = rs2[31:0] | RV32I / RV64I |
SD | sd rs2, offset(rs1) | 存儲雙字 | Mem[rs1 + offset] = rs2[63:0] | RV64I |
3.2 算術指令
算術指令狹義定義:僅包含加法、減法及其直接相關的操作,用于寄存器或寄存器與立即數之間的數值運算。
指令 | 格式 | 功能描述 | 操作(偽代碼) | 指令集 |
---|---|---|---|---|
基礎加減指令 | ||||
ADD | add rd, rs1, rs2 | 加法(忽略溢出) | rd = rs1 + rs2 | RV32I / RV64I |
SUB | sub rd, rs1, rs2 | 減法(忽略溢出) | rd = rs1 - rs2 | RV32I / RV64I |
ADDI | addi rd, rs1, imm | 立即數加法(符號擴展立即數) | rd = rs1 + SignExt(imm) | RV32I / RV64I |
RV64I 擴展加減指令 | ||||
ADDIW | addiw rd, rs1, imm | 立即數加法(32位,符號擴展至64位) | rd = SignExt((rs1 + SignExt(imm))[31:0]) | RV64I |
ADDW | addw rd, rs1, rs2 | 加法(32位,符號擴展至64位) | rd = SignExt((rs1 + rs2)[31:0]) | RV64I |
SUBW | subw rd, rs1, rs2 | 減法(32位,符號擴展至64位) | rd = SignExt((rs1 - rs2)[31:0]) | RV64I |
高位立即數構建指令 | ||||
LUI | lui rd, imm | 加載高位立即數(imm[31:12]) | rd = imm << 12 | RV32I / RV64I |
AUIPC | auipc rd, imm | 將高位立即數與 PC 相加 | rd = PC + (imm << 12) | RV32I / RV64I |
偽指令表格:
偽指令 | 格式 | 功能描述 | 實際轉換(基礎指令) | 適用指令集 |
---|---|---|---|---|
寄存器操作 | ||||
MV | mv rd, rs | 寄存器間移動值 | addi rd, rs, 0 | RV32I / RV64I |
NEG | neg rd, rs | 取負值(rd = -rs) | sub rd, x0, rs | RV32I / RV64I |
NEGW | negw rd, rs | 取負值(32位操作,符號擴展) | subw rd, x0, rs | RV64I |
立即數操作 | ||||
LI | li rd, imm | 加載任意立即數到寄存器 | 若 imm 在 12 位有符號范圍內:addi rd, x0, imm 否則: lui rd, imm[31:12] + addi rd, rd, imm[11:0] | RV32I / RV64I |
地址加載 | ||||
LA | la rd, symbol | 加載絕對地址(鏈接時解析) | auipc rd, offset_hi + addi rd, rd, offset_lo 或 lui rd, offset_hi + addi rd, rd, offset_lo | RV32I / RV64I |
LLA | lla rd, symbol | 加載本地地址(PC相對,位置無關) | auipc rd, offset_hi + addi rd, rd, offset_lo | RV32I / RV64I |
符號擴展 | ||||
SEXT.W | sext.w rd, rs | 將低32位符號擴展至64位(RV64I) | addiw rd, rs, 0 | RV64I |
空操作 | ||||
NOP | nop | 空操作(無實際效果) | addi x0, x0, 0 | RV32I / RV64I |
3.3 移位指令
移位指令用于對寄存器中的數據進行位級左移或右移,分為以下兩類:
-
- 寄存器移位:移位位數由另一個寄存器的低 5 位(RV32I)或低 6 位(RV64I)指定。
-
- 立即數移位:移位位數由指令中的立即數字段直接指定。
- 立即數移位:移位位數由指令中的立即數字段直接指定。
指令 | 格式 | 功能描述 | 操作(偽代碼) | 指令集 |
---|---|---|---|---|
邏輯左移 | ||||
SLL | sll rd, rs1, rs2 | 邏輯左移(低位補零) | rd = rs1 << (rs2[4:0]) (RV32I,取低5位)rd = rs1 << (rs2[5:0]) (RV64I,取低6位) | RV32I / RV64I |
SLLI | slli rd, rs1, shamt | 立即數邏輯左移 | rd = rs1 << shamt (shamt范圍:RV32I為 0–31,RV64I為 0–63) | RV32I / RV64I |
SLLW | sllw rd, rs1, rs2 | 32位邏輯左移(RV64I,低32位操作) | rd = SignExt((rs1[31:0] << rs2[4:0])) | RV64I |
SLLIW | slliw rd, rs1, shamt | 32位立即數邏輯左移(RV64I) | rd = SignExt((rs1[31:0] << shamt)[31:0]) (shamt范圍:0–31) | RV64I |
邏輯右移 | ||||
SRL | srl rd, rs1, rs2 | 邏輯右移(高位補零) | rd = rs1 >> (rs2[4:0]) (RV32I)rd = rs1 >> (rs2[5:0]) (RV64I) | RV32I / RV64I |
SRLI | srli rd, rs1, shamt | 立即數邏輯右移 | rd = rs1 >> shamt | RV32I / RV64I |
SRLW | srlw rd, rs1, rs2 | 32位邏輯右移(RV64I,低32位操作) | rd = SignExt((rs1[31:0] >> rs2[4:0])) | RV64I |
SRLIW | srliw rd, rs1, shamt | 32位立即數邏輯右移(RV64I) | rd = SignExt((rs1[31:0] >> shamt)[31:0]) (shamt范圍:0–31) | RV64I |
算術右移 | ||||
SRA | sra rd, rs1, rs2 | 算術右移(高位補符號位) | rd = rs1 >>> (rs2[4:0]) (RV32I)rd = rs1 >>> (rs2[5:0]) (RV64I) | RV32I / RV64I |
SRAI | srai rd, rs1, shamt | 立即數算術右移 | rd = rs1 >>> shamt | RV32I / RV64I |
SRAW | sraw rd, rs1, rs2 | 32位算術右移(RV64I,低32位操作) | rd = SignExt((rs1[31:0] >>> rs2[4:0])) | RV64I |
SRAIW | sraiw rd, rs1, shamt | 32位立即數算術右移(RV64I) | rd = SignExt((rs1[31:0] >>> shamt)[31:0]) (shamt范圍:0–31) | RV64I |
3.4 邏輯指令
邏輯指令用于對寄存器中的數據進行按位操作,分為以下兩類:
- 1.寄存器-寄存器操作:兩個寄存器之間的按位運算。
- 2.寄存器-立即數操作:寄存器與符號擴展后的立即數進行按位運算。
指令 | 格式 | 功能描述 | 操作(偽代碼) | 指令集 |
---|---|---|---|---|
按位與操作 | ||||
AND | and rd, rs1, rs2 | 按位與 | rd = rs1 & rs2 | RV32I / RV64Ity-reference |
ANDI | andi rd, rs1, imm | 立即數按位與(符號擴展立即數) | rd = rs1 & SignExt(imm) | RV32I / RV64Ity-reference |
按位或操作 | ||||
OR | or rd, rs1, rs2 | 按位或 | `rd = rs1 | rs2` |
ORI | ori rd, rs1, imm | 立即數按位或(符號擴展立即數) | `rd = rs1 | SignExt(imm)` |
按位異或操作 | ||||
XOR | xor rd, rs1, rs2 | 按位異或 | rd = rs1 ^ rs2 | RV32I / RV64Ity-reference |
XORI | xori rd, rs1, imm | 立即數按位異或(符號擴展立即數) | rd = rs1 ^ SignExt(imm) | RV32I / RV64Ity-reference |
偽指令:
偽指令 | 格式 | 功能描述 | 實際轉換(基礎指令) | 適用指令集 |
---|---|---|---|---|
NOT | not rd, rs | 按位取反(rd = ~rs) | xori rd, rs, -1 | RV32I / RV64I |
3.5 比較-置位指令
指令根據兩個操作數的比較結果設置目標寄存器的值為 1 或 0,用于條件判斷和邏輯控制,支持有符號和無符號比較。
指令 | 格式 | 功能描述 | 操作(偽代碼) | 指令集 |
---|---|---|---|---|
有符號比較 | ||||
SLT | slt rd, rs1, rs2 | 有符號比較:若 rs1 < rs2,則 rd = 1,否則 rd = 0 | rd = (rs1 < rs2) ? 1 : 0 (有符號比較) | RV32I / RV64Ity-reference |
SLTI | slti rd, rs1, imm | 有符號立即數比較:若 rs1 < SignExt(imm),則 rd = 1 | rd = (rs1 < SignExt(imm)) ? 1 : 0 | RV32I / RV64Ity-reference |
無符號比較 | ||||
SLTU | sltu rd, rs1, rs2 | 無符號比較:若 rs1 < rs2,則 rd = 1 | rd = (rs1 < rs2) ? 1 : 0 (無符號比較) | RV32I / RV64Ity-reference |
SLTIU | sltiu rd, rs1, imm | 無符號立即數比較(立即數符號擴展后按無符號比較):若 rs1 < SignExt(imm),則 rd = 1 | rd = (rs1 < SignExt(imm)) ? 1 : 0 (無符號比較) | RV32I / RV64Ity-reference |
偽指令:
偽指令 | 格式 | 功能描述 | 實際轉換(基礎指令) | 適用指令集 |
---|---|---|---|---|
零值判斷 | ||||
SEQZ | seqz rd, rs | 若 rs == 0,則 rd = 1,否則 0 | sltiu rd, rs, 1 | RV32I / RV64I |
SNEZ | snez rd, rs | 若 rs ≠ 0,則 rd = 1,否則 0 | sltu rd, x0, rs | RV32I / RV64I |
符號判斷 | ||||
SLTZ | sltz rd, rs | 若 rs < 0(有符號),則 rd = 1 | slt rd, rs, x0 | RV32I / RV64I |
SGTZ | sgtz rd, rs | 若 rs > 0(有符號),則 rd = 1 | slt rd, x0, rs | RV32I / RV64I |
非零符號判斷 | ||||
SLEZ | slez rd, rs | 若 rs ≤ 0(有符號),則 rd = 1 | slt rd, x0, rs → xori rd, rd, 1 | RV32I / RV64I |
SGEZ | sgez rd, rs | 若 rs ≥ 0(有符號),則 rd = 1 | slt rd, rs, x0 → xori rd, rd, 1 | RV32I / RV64I |
3.6 分支指令
分支指令用于控制程序流程,根據條件或地址跳轉執行目標代碼,均為 B-Type 或 J-Type 格式。
條件分支指令
指令 | 格式 | 功能描述 | 操作(偽代碼) | 指令集 |
---|---|---|---|---|
BEQ | beq rs1, rs2, offset | 若 rs1 == rs2,跳轉到 PC + offset | if (rs1 == rs2) PC += SignExt(offset << 1) | RV32I / RV64I |
BNE | bne rs1, rs2, offset | 若 rs1 ≠ rs2,跳轉到 PC + offset | if (rs1 != rs2) PC += SignExt(offset << 1) | RV32I / RV64I |
BLT | blt rs1, rs2, offset | 若 rs1 < rs2(有符號),跳轉 | if (rs1 < rs2) PC += SignExt(offset << 1) | RV32I / RV64I |
BGE | bge rs1, rs2, offset | 若 rs1 ≥ rs2(有符號),跳轉 | if (rs1 >= rs2) PC += SignExt(offset << 1) | RV32I / RV64I |
BLTU | bltu rs1, rs2, offset | 若 rs1 < rs2(無符號),跳轉 | if (rs1 < rs2) PC += SignExt(offset << 1) | RV32I / RV64I |
BGEU | bgeu rs1, rs2, offset | 若 rs1 ≥ rs2(無符號),跳轉 | if (rs1 >= rs2) PC += SignExt(offset << 1) | RV32I / RV64I |
條件分支偽指令
偽指令 | 格式 | 功能描述 | 實際轉換(基礎指令) | 適用指令集 |
---|---|---|---|---|
BEQZ | beqz rs, offset | 若 rs == 0,跳轉到 offset | beq rs, x0, offset | RV32I / RV64I |
BNEZ | bnez rs, offset | 若 rs ≠ 0,跳轉到 offset | bne rs, x0, offset | RV32I / RV64I |
BGT | bgt rs1, rs2, offset | 若 rs1 > rs2(有符號),跳轉 | blt rs2, rs1, offset | RV32I / RV64I |
BGTU | bgtu rs1, rs2, offset | 若 rs1 > rs2(無符號),跳轉 | bltu rs2, rs1, offset | RV32I / RV64I |
BLE | ble rs1, rs2, offset | 若 rs1 ≤ rs2(有符號),跳轉 | bge rs2, rs1, offset | RV32I / RV64I |
BLEU | bleu rs1, rs2, offset | 若 rs1 ≤ rs2(無符號),跳轉 | bgeu rs2, rs1, offset | RV32I / RV64I |
3.7 跳轉指令
跳轉指令用于改變程序的執行流程,使程序能夠跳轉到代碼中的其他位置執行
無條件跳轉指令
指令 | 格式 | 功能描述 | 操作(偽代碼) | 指令集 |
---|---|---|---|---|
JAL | jal rd, offset | 跳轉到 PC + offset,并將返回地址存入 rd | rd = PC + 4; PC += SignExt(offset << 1) | RV32I / RV64I |
JALR | jalr rd, offset(rs1) | 跳轉到 rs1 + offset,存入返回地址 | rd = PC + 4; PC = (rs1 + SignExt(offset)) & ~1 | RV32I / RV64I |
無條件跳轉偽指令
偽指令 | 格式 | 功能描述 | 實際轉換(基礎指令) | 適用指令集 |
---|---|---|---|---|
J | j offset | 無條件跳轉到 offset | jal x0, offset | RV32I / RV64I |
JR | jr rs | 跳轉到 rs 指向的地址 | jalr x0, 0(rs) | RV32I / RV64I |
RET | ret | 從函數返回(跳轉到 ra 地址) | jalr x0, 0(ra) | RV32I / RV64I |
3.8 同步指令
同步指令用于處理內存訪問順序控制,確保數據一致性和并發安全。
內存屏障指令
指令 | 格式 | 功能描述 | 操作(偽代碼) | 適用指令集 |
---|---|---|---|---|
FENCE | fence pred, succ | 內存屏障(控制訪存順序) | 確保 pred 操作在 succ 操作前完成 (pred/succ 可以為 r(讀)、w(寫)、i(指令流)) | RV32I / RV64I |
FENCE.I | fence.i | 指令流同步屏障 | 確保后續指令看到此前所有指令的修改(用于自修改代碼) | RV32I / RV64I) |
3.9 環境指令
環境指令用于系統調用、調試、中斷處理等特權級操作,通常需在特定權限模式下執行。
系統調用與異常處理指令
指令 | 格式 | 功能描述 | 操作(偽代碼) | 適用指令集 |
---|---|---|---|---|
ECALL | ecall | 觸發環境調用(系統調用/異常) | 根據當前模式跳轉到異常處理程序 | RV32I / RV64I |
EBREAK | ebreak | 觸發斷點異常(用于調試) | 進入調試模式或觸發異常處理 | RV32I / RV64I |
中斷返回指令
指令 | 格式 | 功能描述 | 操作(偽代碼) | 適用指令集 |
---|---|---|---|---|
MRET | mret | 從機器模式異常返回 | PC = MEPC; Privilege = MPP | RV32I / RV64I |
SRET | sret | 從監管者模式異常返回 | PC = SEPC; Privilege = SPP | RV32I / RV64I |
URET | uret | 從用戶模式異常返回 | PC = UEPC | RV32I / RV64I |
等待與暫停指令
指令 | 格式 | 功能描述 | 操作(偽代碼) | 適用指令集 |
---|---|---|---|---|
WFI | wfi | 等待中斷(暫停執行直至中斷發生) | 暫停 CPU 直至中斷或事件喚醒 | RV32I / RV64I ) |
3.10 控制狀態寄存器指令
指令用于讀寫處理器的控制狀態寄存器(如中斷配置、計數器、特權模式設置等),支持原子操作和位操作,適用于系統編程和特權級管理。
CSR 讀寫指令
指令 | 格式 | 功能描述 | 操作(偽代碼) | 適用指令集 |
---|---|---|---|---|
CSRRW | csrrw rd, csr, rs1 | 將 rs1 寫入 CSR,原值存入 rd | t = CSR[csr]; CSR[csr] = rs1; rd = t | RV32I / RV64I |
CSRRS | csrrs rd, csr, rs1 | 將 rs1 對應位設為 1,原值存入 rd | `t = CSR[csr]; CSR[csr] | = rs1; rd = t` |
CSRRC | csrrc rd, csr, rs1 | 將 rs1 對應位清 0,原值存入 rd | t = CSR[csr]; CSR[csr] &= ~rs1; rd = t | RV32I / RV64I |
CSRRWI | csrrwi rd, csr, imm | 將 5 位立即數寫入 CSR | t = CSR[csr]; CSR[csr] = imm; rd = t | RV32I / RV64I |
CSRRSI | csrrsi rd, csr, imm | 將立即數對應位置 1 | `t = CSR[csr]; CSR[csr] | = imm; rd = t` |
CSRRCI | csrrci rd, csr, imm | 將立即數對應位清 0 | t = CSR[csr]; CSR[csr] &= ~imm; rd = t | RV32I / RV64I |
CSR 偽指令
偽指令 | 格式 | 功能描述 | 實際轉換(基礎指令) | 適用指令集 |
---|---|---|---|---|
CSRR | csrr rd, csr | 讀取 CSR 的值到寄存器 | csrrs rd, csr, x0 (讀 CSR,不修改) | RV32I / RV64I |
CSRW | csrw csr, rs | 將寄存器的值寫入 CSR | csrrw x0, csr, rs (丟棄原值,僅寫入) | RV32I / RV64I |
CSRS | csrs csr, rs | 設置 CSR 中由 rs 指定的位 | csrrs x0, csr, rs (按位或,不保存結果) | RV32I / RV64I |
CSRC | csrc csr, rs | 清除 CSR 中由 rs 指定的位 | csrrc x0, csr, rs (按位與取反,不保存結果) | RV32I / RV64I |
CSRWI | csrwi csr, imm | 將 5 位立即數寫入 CSR | csrrwi x0, csr, imm | RV32I / RV64I |
CSRSI | csrsi csr, imm | 設置 CSR 中由立即數指定的位 | csrrsi x0, csr, imm | RV32I / RV64I |
CSRCI | csrci csr, imm | 清除 CSR 中由立即數指定的位 | csrrci x0, csr, imm | RV32I / RV64I |
4 RVM指令集
RVM 擴展指令分為 乘法指令 和 除法/取余指令,支持有符號和無符號操作,并區分 RV32 和 RV64 的差異。
乘法指令
指令 | 格式 | 功能描述 | 操作(偽代碼) | 適用指令集 |
---|---|---|---|---|
MUL | mul rd, rs1, rs2 | 乘法(低32/64位結果) | rd = (rs1 * rs2)[31:0] (RV32)rd = rs1 * rs2 (RV64) | RV32M / RV64M |
MULH | mulh rd, rs1, rs2 | 有符號乘法(高32/64位結果) | rd = (rs1 * rs2)[63:32] (RV32)rd = (rs1 * rs2)[127:64] (RV64) | RV32M / RV64M |
MULHU | mulhu rd, rs1, rs2 | 無符號乘法(高32/64位結果) | 同上,操作數為無符號數 | RV32M / RV64M |
MULHSU | mulhsu rd, rs1, rs2 | 有符號-無符號乘法(高32/64位結果) | rs1 有符號,rs2 無符號 | RV32M / RV64M |
MULW | mulw rd, rs1, rs2 | 32位乘法(結果符號擴展至64位) | rd = SignExt((rs1[31:0] * rs2[31:0])) | RV64M |
除法/取余指令
指令 | 格式 | 功能描述 | 操作(偽代碼) | 適用指令集 |
---|---|---|---|---|
DIV | div rd, rs1, rs2 | 有符號除法(商) | rd = rs1 / rs2 (向零舍入) | RV32M / RV64M |
DIVU | divu rd, rs1, rs2 | 無符號除法(商) | rd = rs1 / rs2 | RV32M / RV64M |
REM | rem rd, rs1, rs2 | 有符號取余(余數) | rd = rs1 % rs2 (符號與 rs1 相同) | RV32M / RV64M |
REMU | remu rd, rs1, rs2 | 無符號取余(余數) | rd = rs1 % rs2 | RV32M / RV64M |
DIVW | divw rd, rs1, rs2 | 32位有符號除法(符號擴展至64位) | rd = SignExt((rs1[31:0] / rs2[31:0])) | RV64M |
DIVUW | divuw rd, rs1, rs2 | 32位無符號除法(零擴展至64位) | rd = ZeroExt((rs1[31:0] / rs2[31:0])) | RV64M |
REMW | remw rd, rs1, rs2 | 32位有符號取余(符號擴展至64位) | rd = SignExt((rs1[31:0] % rs2[31:0])) | RV64M |
REMUW | remuw rd, rs1, rs2 | 32位無符號取余(零擴展至64位) | rd = ZeroExt((rs1[31:0] % rs2[31:0])) | RV64M |
5 RVFD指令集
5.1 訪存指令
指令用于在內存和浮點寄存器(f0-f31)之間傳輸單精度(F 擴展)或雙精度(D 擴展)浮點數據:
浮點加載和存儲指令
指令 | 格式 | 功能描述 | 操作(偽代碼) | 適用指令集 |
---|---|---|---|---|
FLW | flw fd, offset(rs1) | 從內存加載單精度浮點數到浮點寄存器 | fd = F32(Mem[rs1 + offset]) | RV32F / RV64F |
FSW | fsw fs, offset(rs1) | 將單精度浮點數從浮點寄存器存入內存 | Mem[rs1 + offset] = F32(fs) | RV32F / RV64F |
FLD | fld fd, offset(rs1) | 從內存加載雙精度浮點數到浮點寄存器 | fd = F64(Mem[rs1 + offset]) | RV64D |
FSD | fsd fs, offset(rs1) | 將雙精度浮點數從浮點寄存器存入內存 | Mem[rs1 + offset] = F64(fs) | RV64D |
5.2 算術指令
算術指令用于執行各種數學運算,如加法、減法、乘法、除法等。當涉及到浮點數時,這些操作變得更為復雜,因為它們需要處理指數和尾數部分
基本算術指令
指令類型 | 指令 | 格式 | 功能描述 | 操作(偽代碼) | 適用指令集 |
---|---|---|---|---|---|
加法 | FADD.S | fadd.s fd, fs1, fs2 | 單精度浮點加法 | fd = fs1 + fs2 | RV32F / RV64F |
FADD.D | fadd.d fd, fs1, fs2 | 雙精度浮點加法 | fd = fs1 + fs2 | RV64D | |
減法 | FSUB.S | fsub.s fd, fs1, fs2 | 單精度浮點減法 | fd = fs1 - fs2 | RV32F / RV64F |
FSUB.D | fsub.d fd, fs1, fs2 | 雙精度浮點減法 | fd = fs1 - fs2 | RV64D | |
乘法 | FMUL.S | fmul.s fd, fs1, fs2 | 單精度浮點乘法 | fd = fs1 * fs2 | RV32F / RV64F |
FMUL.D | fmul.d fd, fs1, fs2 | 雙精度浮點乘法 | fd = fs1 * fs2 | RV64D | |
除法 | FDIV.S | fdiv.s fd, fs1, fs2 | 單精度浮點除法 | fd = fs1 / fs2 | RV32F / RV64F |
FDIV.D | fdiv.d fd, fs1, fs2 | 雙精度浮點除法 | fd = fs1 / fs2 | RV64D | |
平方根 | FSQRT.S | fsqrt.s fd, fs1 | 單精度浮點平方根 | fd = sqrt(fs1) | RV32F / RV64F |
FSQRT.D | fsqrt.d fd, fs1 | 雙精度浮點平方根 | fd = sqrt(fs1) | RV64D | |
最小值 | FMIN.S | fmin.s fd, fs1, fs2 | 單精度浮點最小值 | fd = min(fs1, fs2) | RV32F / RV64F |
FMIN.D | fmin.d fd, fs1, fs2 | 雙精度浮點最小值 | fd = min(fs1, fs2) | RV64D | |
最大值 | FMAX.S | fmax.s fd, fs1, fs2 | 單精度浮點最大值 | fd = max(fs1, fs2) | RV32F / RV64F |
FMAX.D | fmax.d fd, fs1, fs2 | 雙精度浮點最大值 | fd = max(fs1, fs2) | RV64D |
5.3 RVFD 乘加指令
指令用于執行 乘加融合運算(Fused Multiply-Add, FMA),即在一個操作中完成乘法和加法,通常具有更高的精度和性能
指令類型 | 指令 | 格式 | 功能描述 | 操作(偽代碼) | 適用指令集 |
---|---|---|---|---|---|
單精度乘加 | FMADD.S | fmadd.s fd, fs1, fs2, fs3 | 單精度浮點乘加 | fd = (fs1 * fs2) + fs3 | RV32F / RV64F |
單精度乘減 | FMSUB.S | fmsub.s fd, fs1, fs2, fs3 | 單精度浮點乘減 | fd = (fs1 * fs2) - fs3 | RV32F / RV64F |
單精度負乘加 | FNMADD.S | fnmadd.s fd, fs1, fs2, fs3 | 單精度浮點負乘加 | fd = -((fs1 * fs2) + fs3) | RV32F / RV64F |
單精度負乘減 | FNMSUB.S | fnmsub.s fd, fs1, fs2, fs3 | 單精度浮點負乘減 | fd = -((fs1 * fs2) - fs3) | RV32F / RV64F |
雙精度乘加 | FMADD.D | fmadd.d fd, fs1, fs2, fs3 | 雙精度浮點乘加 | fd = (fs1 * fs2) + fs3 | RV64D |
雙精度乘減 | FMSUB.D | fmsub.d fd, fs1, fs2, fs3 | 雙精度浮點乘減 | fd = (fs1 * fs2) - fs3 | RV64D |
雙精度負乘加 | FNMADD.D | fnmadd.d fd, fs1, fs2, fs3 | 雙精度浮點負乘加 | fd = -((fs1 * fs2) + fs3) | RV64D |
雙精度負乘減 | FNMSUB.D | fnmsub.d fd, fs1, fs2, fs3 | 雙精度浮點負乘減 | fd = -((fs1 * fs2) - fs3) | RV64D |
5.4 RVFD傳送指令
指令用于在 浮點寄存器 和 整數寄存器 之間傳輸數據,或在不同浮點寄存器之間復制數據
指令類型 | 指令 | 格式 | 功能描述 | 操作(偽代碼) | 適用指令集 |
---|---|---|---|---|---|
浮點到整數 | FMV.X.S | fmv.x.s rd, fs1 | 將單精度浮點數轉為整數表示 | rd = fs1 (按位復制) | RV32F / RV64F |
浮點到整數 | FMV.X.D | fmv.x.d rd, fs1 | 將雙精度浮點數轉為整數表示 | rd = fs1 (按位復制) | RV64D |
整數到浮點 | FMV.S.X | fmv.s.x fd, rs1 | 將整數表示轉為單精度浮點數 | fd = rs1 (按位復制) | RV32F / RV64F |
整數到浮點 | FMV.D.X | fmv.d.x fd, rs1 | 將整數表示轉為雙精度浮點數 | fd = rs1 (按位復制) | RV64D |
5.5 RVFD 轉換指令
分兩類歸納:浮點寄存器間傳送 和 浮點與整數寄存器間傳送,涵蓋符號操作、位模式復制及特殊值處理
浮點與整數之間的轉換
指令類型 | 指令 | 格式 | 功能描述 | 操作(偽代碼) | 適用指令集 |
---|---|---|---|---|---|
浮點 → 整數 | FCVT.W.S | fcvt.w.s rd, fs1 | 單精度浮點轉為 32 位有符號整數 | rd = (int32_t)fs1 | RV32F / RV64F |
FCVT.WU.S | fcvt.wu.s rd, fs1 | 單精度浮點轉為 32 位無符號整數 | rd = (uint32_t)fs1 | RV32F / RV64F | |
FCVT.L.S | fcvt.l.s rd, fs1 | 單精度浮點轉為 64 位有符號整數 | rd = (int64_t)fs1 | RV64F | |
FCVT.LU.S | fcvt.lu.s rd, fs1 | 單精度浮點轉為 64 位無符號整數 | rd = (uint64_t)fs1 | RV64F | |
FCVT.W.D | fcvt.w.d rd, fs1 | 雙精度浮點轉為 32 位有符號整數 | rd = (int32_t)fs1 | RV64D | |
FCVT.WU.D | fcvt.wu.d rd, fs1 | 雙精度浮點轉為 32 位無符號整數 | rd = (uint32_t)fs1 | RV64D | |
FCVT.L.D | fcvt.l.d rd, fs1 | 雙精度浮點轉為 64 位有符號整數 | rd = (int64_t)fs1 | RV64D | |
FCVT.LU.D | fcvt.lu.d rd, fs1 | 雙精度浮點轉為 64 位無符號整數 | rd = (uint64_t)fs1 | RV64D | |
整數 → 浮點 | FCVT.S.W | fcvt.s.w fd, rs1 | 32 位有符號整數轉為單精度浮點 | fd = (float)rs1 | RV32F / RV64F |
FCVT.S.WU | fcvt.s.wu fd, rs1 | 32 位無符號整數轉為單精度浮點 | fd = (float)rs1 | RV32F / RV64F | |
FCVT.S.L | fcvt.s.l fd, rs1 | 64 位有符號整數轉為單精度浮點 | fd = (float)rs1 | RV64F | |
FCVT.S.LU | fcvt.s.lu fd, rs1 | 64 位無符號整數轉為單精度浮點 | fd = (float)rs1 | RV64F | |
FCVT.D.W | fcvt.d.w fd, rs1 | 32 位有符號整數轉為雙精度浮點 | fd = (double)rs1 | RV64D | |
FCVT.D.WU | fcvt.d.wu fd, rs1 | 32 位無符號整數轉為雙精度浮點 | fd = (double)rs1 | RV64D | |
FCVT.D.L | fcvt.d.l fd, rs1 | 64 位有符號整數轉為雙精度浮點 | fd = (double)rs1 | RV64D | |
FCVT.D.LU | fcvt.d.lu fd, rs1 | 64 位無符號整數轉為雙精度浮點 | fd = (double)rs1 | RV64D |
浮點精度之間的轉換
指令類型 | 指令 | 格式 | 功能描述 | 操作(偽代碼) | 適用指令集 |
---|---|---|---|---|---|
單精度 ? 雙精度 | FCVT.S.D | fcvt.s.d fd, fs1 | 雙精度浮點轉為單精度浮點 | fd = (float)fs1 | RV64D |
單精度 ? 雙精度 | FCVT.D.S | fcvt.d.s fd, fs1 | 單精度浮點轉為雙精度浮點 | fd = (double)fs1 | RV64D |
5.6 RVFD 符號注入指令
指令用于將 整數立即數 或 整數寄存器值 注入到浮點寄存器中,通常用于快速構造浮點常數或特殊值(如 NaN、無窮大)
單精度浮點注入指令
指令類型 | 指令 | 格式 | 功能描述 | 操作(偽代碼) | 適用指令集 |
---|---|---|---|---|---|
符號復制 | FSGNJ.S | fsgnj.s fd, fs1, fs2 | 復制數值,符號位取自 fs2 | fd = {fs2[31], fs1[30:0]} | RV32F / RV64F |
符號取反 | FSGNJN.S | fsgnjn.s fd, fs1, fs2 | 復制數值,符號位取反自 fs2 | fd = {~fs2[31], fs1[30:0]} | RV32F / RV64F |
符號取絕對值 | FSGNJX.S | fsgnjx.s fd, fs1, fs2 | 復制數值,符號位異或(取絕對值) | fd = {fs1[31] ^ fs2[31], fs1[30:0]} | RV32F / RV64F |
雙精度浮點注入指令
指令類型 | 指令 | 格式 | 功能描述 | 操作(偽代碼) | 適用指令集 |
---|---|---|---|---|---|
符號復制 | FSGNJ.D | fsgnj.d fd, fs1, fs2 | 復制數值,符號位取自 fs2 | fd = {fs2[63], fs1[62:0]} | RV64D |
符號取反 | FSGNJN.D | fsgnjn.d fd, fs1, fs2 | 復制數值,符號位取反自 fs2 | fd = {~fs2[63], fs1[62:0]} | RV64D |
符號取絕對值 | FSGNJX.D | fsgnjx.d fd, fs1, fs2 | 復制數值,符號位異或(取絕對值) | fd = {fs1[63] ^ fs2[63], fs1[62:0]} | RV64D |
偽指令
指令類型 | 偽指令 | 格式 | 功能描述 | 實際轉換(基礎指令) | 適用指令集 |
---|---|---|---|---|---|
單精度浮點注入 | FABS.S | fabs.s fd, fs | 單精度浮點取絕對值 | fsgnjx.s fd, fs, fs | RV32F / RV64F |
FMV.S | fmv.s fd, fs | 單精度浮點復制 | fsgnj.s fd, fs, fs | RV32F / RV64F | |
FNEG.S | fneg.s fd, fs | 單精度浮點取反 | fsgnjn.s fd, fs, fs | RV32F / RV64F |
指令類型 | 偽指令 | 格式 | 功能描述 | 實際轉換(基礎指令) | 適用指令集 |
---|---|---|---|---|---|
雙精度浮點注入 | FABS.D | fabs.d fd, fs | 雙精度浮點取絕對值 | fsgnjx.d fd, fs, fs | RV64D |
FMV.D | fmv.d fd, fs | 雙精度浮點復制 | fsgnj.d fd, fs, fs | RV64D | |
FNEG.D | fneg.d fd, fs | 雙精度浮點取反 | fsgnjn.d fd, fs, fs | RV64D |
5.7 RVFD 比較指令
指令用于比較兩個浮點數的值,并將比較結果寫入整數寄存器,支持 相等、小于 和 小于等于 三種比較操作
指令類型 | 指令 | 格式 | 功能描述 | 操作(偽代碼) | 適用指令集 |
---|---|---|---|---|---|
相等比較 | FEQ.S | feq.s rd, fs1, fs2 | 單精度浮點相等比較 | rd = (fs1 == fs2) ? 1 : 0 | RV32F / RV64F |
FEQ.D | feq.d rd, fs1, fs2 | 雙精度浮點相等比較 | rd = (fs1 == fs2) ? 1 : 0 | RV64D | |
小于比較 | FLT.S | flt.s rd, fs1, fs2 | 單精度浮點小于比較 | rd = (fs1 < fs2) ? 1 : 0 | RV32F / RV64F |
FLT.D | flt.d rd, fs1, fs2 | 雙精度浮點小于比較 | rd = (fs1 < fs2) ? 1 : 0 | RV64D | |
小于等于比較 | FLE.S | fle.s rd, fs1, fs2 | 單精度浮點小于等于比較 | rd = (fs1 <= fs2) ? 1 : 0 | RV32F / RV64F |
FLE.D | fle.d rd, fs1, fs2 | 雙精度浮點小于等于比較 | rd = (fs1 <= fs2) ? 1 : 0 | RV64D |
5.8 RVFD 分類指令
指令用于檢查浮點數的類別(如正無窮、負零、NaN 等),并將結果寫入整數寄存器,適用于浮點數的異常處理和特殊值檢測
指令類型 | 指令 | 格式 | 功能描述 | 操作(偽代碼) | 適用指令集 |
---|---|---|---|---|---|
浮點分類 | 單精度分類 | fclass.s rd, fs1 | 單精度浮點分類 | rd = classify(fs1) | RV32F / RV64F |
浮點分類 | 雙精度分類 | fclass.d rd, fs1 | 雙精度浮點分類 | rd = classify(fs1) | RV64D |
5.9 RVFD 配置指令
指令用于配置和管理浮點單元的狀態,包括 舍入模式、異常標志 和 浮點控制狀態寄存器(fcsr) 的操作
指令類型 | 指令 | 格式 | 功能描述 | 操作(偽代碼) | 適用指令集 |
---|---|---|---|---|---|
浮點控制狀態寄存器(fcsr)操作 | |||||
讀取 fcsr | FRCSR | frcsr rd | 讀取 fcsr 的值到整數寄存器 | rd = fcsr | RV32F / RV64F |
寫入 fcsr | FSCSR | fscsr rd, rs | 將整數寄存器的值寫入 fcsr | fcsr = rs | RV32F / RV64F |
交換 fcsr | FSRCS | fscsr rd, rs | 交換 fcsr 和整數寄存器的值 | t = fcsr; fcsr = rs; rd = t | RV32F / RV64F |
舍入模式配置 | |||||
讀取舍入模式 | FRRM | frrm rd | 讀取舍入模式到整數寄存器 | rd = fcsr[7:5] | RV32F / RV64F |
寫入舍入模式 | FSRM | fsrm rd, rs | 將整數寄存器的值寫入舍入模式 | fcsr[7:5] = rs[2:0] | RV32F / RV64F |
交換舍入模式 | FSRRM | fsrrm rd, rs | 交換舍入模式和整數寄存器的值 | t = fcsr[7:5]; fcsr[7:5] = rs[2:0]; rd = t | RV32F / RV64F |
異常標志操作 | |||||
讀取異常標志 | FFLAGS | fflags rd | 讀取異常標志到整數寄存器 | rd = fcsr[4:0] | RV32F / RV64F |
寫入異常標志 | FSFLAGS | fsflags rd, rs | 將整數寄存器的值寫入異常標志 | fcsr[4:0] = rs[4:0] | RV32F / RV64F |
交換異常標志 | FSRFLAGS | fsrflags rd, rs | 交換異常標志和整數寄存器的值 | t = fcsr[4:0]; fcsr[4:0] = rs[4:0]; rd = t | RV32F / RV64F |
6 RVA指令集
RVA(Atomic Operations)擴展為 RISC-V 提供了硬件支持的原子操作指令,用于在多線程或多核環境中實現 原子內存訪問 和 同步操作,確保數據一致性和并發安全。
加載保留與條件存儲指令
指令類型 | 指令 | 格式 | 功能描述 | 操作(偽代碼) | 適用指令集 |
---|---|---|---|---|---|
加載保留 | LR.W | lr.w rd, (rs1) | 加載保留(原子加載字,標記內存地址) | rd = Mem[rs1]; Reserve rs1 | RV32A / RV64A |
LR.D | lr.d rd, (rs1) | 加載保留(原子加載雙字) | rd = Mem[rs1]; Reserve rs1 | RV64A | |
條件存儲 | SC.W | sc.w rd, rs2, (rs1) | 條件存儲(若地址未被修改,存儲字) | if (Reserve rs1 still valid) { Mem[rs1] = rs2; rd = 0 } else { rd = 1 } | RV32A / RV64A |
SC.D | sc.d rd, rs2, (rs1) | 條件存儲(若地址未被修改,存儲雙字) | if (Reserve rs1 still valid) { Mem[rs1] = rs2; rd = 0 } else { rd = 1 } | RV64A |
原子內存操作指令
指令類型 | 指令 | 格式 | 功能描述 | 操作(偽代碼) | 適用指令集 |
---|---|---|---|---|---|
原子加 | AMOADD.W | amoadd.w rd, rs2, (rs1) | 原子加并返回原值 | rd = Mem[rs1]; Mem[rs1] += rs2 | RV32A / RV64A |
AMOADD.D | amoadd.d rd, rs2, (rs1) | 原子加并返回原值(雙字) | rd = Mem[rs1]; Mem[rs1] += rs2 | RV64A | |
原子交換 | AMOSWAP.W | amoswap.w rd, rs2, (rs1) | 原子交換并返回原值 | rd = Mem[rs1]; Mem[rs1] = rs2 | RV32A / RV64A |
AMOSWAP.D | amoswap.d rd, rs2, (rs1) | 原子交換并返回原值(雙字) | rd = Mem[rs1]; Mem[rs1] = rs2 | RV64A | |
原子按位與 | AMOAND.W | amoand.w rd, rs2, (rs1) | 原子按位與并返回原值 | rd = Mem[rs1]; Mem[rs1] &= rs2 | RV32A / RV64A |
AMOAND.D | amoand.d rd, rs2, (rs1) | 原子按位與并返回原值(雙字) | rd = Mem[rs1]; Mem[rs1] &= rs2 | RV64A | |
原子按位或 | AMOOR.W | amoor.w rd, rs2, (rs1) | 原子按位或并返回原值 | `rd = Mem[rs1]; Mem[rs1] | = rs2` |
AMOOR.D | amoor.d rd, rs2, (rs1) | 原子按位或并返回原值(雙字) | `rd = Mem[rs1]; Mem[rs1] | = rs2` | |
原子按位異或 | AMOXOR.W | amoxor.w rd, rs2, (rs1) | 原子按位異或并返回原值 | rd = Mem[rs1]; Mem[rs1] ^= rs2 | RV32A / RV64A |
AMOXOR.D | amoxor.d rd, rs2, (rs1) | 原子按位異或并返回原值(雙字) | rd = Mem[rs1]; Mem[rs1] ^= rs2 | RV64A | |
原子最大值 | AMOMAX.W | amomax.w rd, rs2, (rs1) | 原子有符號最大值并返回原值 | rd = Mem[rs1]; Mem[rs1] = max(rd, rs2) | RV32A / RV64A |
AMOMAX.D | amomax.d rd, rs2, (rs1) | 原子有符號最大值并返回原值(雙字) | rd = Mem[rs1]; Mem[rs1] = max(rd, rs2) | RV64A | |
原子無符號最大值 | AMOMAXU.W | amomaxu.w rd, rs2, (rs1) | 原子無符號最大值并返回原值 | rd = Mem[rs1]; Mem[rs1] = maxu(rd, rs2) | RV32A / RV64A |
AMOMAXU.D | amomaxu.d rd, rs2, (rs1) | 原子無符號最大值并返回原值(雙字) | rd = Mem[rs1]; Mem[rs1] = maxu(rd, rs2) | RV64A | |
原子最小值 | AMOMIN.W | amomin.w rd, rs2, (rs1) | 原子有符號最小值并返回原值 | rd = Mem[rs1]; Mem[rs1] = min(rd, rs2) | RV32A / RV64A |
AMOMIN.D | amomin.d rd, rs2, (rs1) | 原子有符號最小值并返回原值(雙字) | rd = Mem[rs1]; Mem[rs1] = min(rd, rs2) | RV64A | |
原子無符號最小值 | AMOMINU.W | amominu.w rd, rs2, (rs1) | 原子無符號最小值并返回原值 | rd = Mem[rs1]; Mem[rs1] = minu(rd, rs2) | RV32A / RV64A |
AMOMINU.D | amominu.d rd, rs2, (rs1) | 原子無符號最小值并返回原值(雙字) | rd = Mem[rs1]; Mem[rs1] = minu(rd, rs2) | RV64A |
上面列舉了RISC-V指令集,但實際上上面列舉的指令集我很多也沒用過,是按照spec總結了下,如有錯誤或者遺漏,還請各位大佬評論區指出。
參考
riscv-spec-20240411.pdf
一起學RISC-V匯編第5講之常用指令及偽指令列表
RISC-V 常用匯編指令