八條指令,全部 R 型(opcode=0110011,funct7=0000001):

指令 funct3 語意
mul 000 rd = (rs1 \(\times\) rs2)[31:0](低 32 位;帶號/無號同)
mulh 001 rd = (帶號\(\times\)帶號)[63:32]
mulhsu 010 rd = (帶號\(\times\)無號)[63:32]
mulhu 011 rd = (無號\(\times\)無號)[63:32]
div 100 rd = rs1 \(\div\) rs2(帶號,向零截斷)
divu 101 rd = rs1 \(\div\) rs2(無號)
rem 110 rd = 帶號餘數(符號同被除數)
remu 111 rd = 無號餘數

定義行為(不設陷阱)

情況 餘數
除以零 全 1(\(-1\) / \(2^{32}-1\)) 被除數
帶號溢位(\(-2^{31} \div -1\)) \(-2^{31}\) 0

RISC-V 不因除零觸發例外——語言運行期(如 C 的 UB、Java 的 ArithmeticException)自行檢查。硬體簡單、語意可移植。

mulh t1, a0, a1     # 高 32 位 (必須先發!)
mul  t0, a0, a1     # 低 32 位
# 微結構提示: 規格建議把 mulh/mul 相鄰成對,
# 硬體可融合為一次乘法 (macro-op fusion)。

硬體實作光譜

  • 迭代式:移位—加法(第 9 章 Booth),32 週期,面積極小——微控制器;

  • 陣列/華萊士樹:單週期或 2–4 級管線化乘法器——應用處理器;

  • 除法幾乎都是迭代(每週期 1–2 位),或以牛頓法用乘法器逼近。

C 擴展:壓縮指令

C 擴展提供 16 位元編碼的常用指令別名:c.addic.lwc.mvc.j……。設計要點:

  • 每條 c.* 都能一對一展開為 32 位元指令——組譯器/解碼器前端做展開,後端資料路徑完全不變;

  • 常用的 8 個暫存器(x8–x15)用 3 位元欄位編碼;立即值/位移縮短;

  • 指令流成為 16/32 位元混合:程式大小平均縮小 25–30%,I-cache 命中率上升;

  • 代價:提取對齊複雜化(32 位元指令可能跨字邊界)、解碼器前端多一級展開;jalr 目標因此只強制 2 位元組對齊(第 18 章)。

嵌入式市場幾乎必選 C(Arm 的 Thumb-2 證明過這條路);高效能核也普遍支援。

A 擴展:原子操作概覽

多 hart 同步需要「讀—改—寫」不可分割:

  • lr.w rd,(rs1) / sc.w rd,rs2,(rs1):載入保留/條件儲存——sc 僅在保留未被打破時成功(回傳 0),否則失敗(非 0)。以重試迴圈實作任意原子操作(CAS、自旋鎖)。

  • amoadd.wamoswap.wamoand/or/xor/min/max:單指令原子讀改寫,適合計數器、佇列指標。

  • 記憶體序修飾位 aq/rl(acquire/release)配合 RVWMO(第 16 章)。

lock:
    li   t0, 1
retry:
    lr.w t1, (a0)        # 讀鎖
    bnez t1, retry       # 已被持有 -> 忙等
    sc.w t1, t0, (a0)    # 嘗試寫 1
    bnez t1, retry       # sc 失敗 -> 重試
    ret
unlock:
    sw   x0, 0(a0)       # 寫 0 釋放 (配合 fence)
    ret

工程取捨:選哪些擴展?

應用 典型組合
極簡控制核(FSM 替代品) RV32E 或 RV32I
微控制器(本教材實作級) RV32I 或 RV32IM(C 視程式記憶體壓力)
RTOS 級嵌入式 RV32IMAC + Zicsr
Linux 應用處理器 RV64GC(+H 虛擬化、V 向量視需求)

模組化的威力:驗證與面積成本只花在用得到的功能上。我們的 Verilog 實作選擇純 RV32I——最小可教學集;讀者可把 M 擴展當作第一個自我挑戰(第 26 章習題)。

本章重點回顧

  • RV32M 八條:mul/mulh 家族取低/高 32 位;div/rem 除零與溢位有定義結果、不陷阱。

  • C 擴展=常用指令的 16 位元別名,前端展開、後端不變;省 25–30% 程式空間。

  • A 擴展:lr/sc 與 amo* 支撐鎖與無鎖結構。

  • 擴展選配是成本工程:RV32I → RV32IMC → RV64GC 隨應用升級。

複習問題

  1. 為什麼 mul 不分帶號/無號,mulh 卻要分三種?

  2. 計算 div/rem\((-7) \div 2\) 的結果;RISC-V 的截斷方向是什麼?

  3. C 擴展為何能「後端不變」?這對驗證成本意味著什麼?

  4. 以 lr/sc 寫出原子的 fetch-and-add。

  5. 你要設計一顆電池供電感測器 SoC 的控制核,選哪些擴展?說明理由。

9 RISC-V International, ISA Manual Vol. I, ver. 20260120: “M”、“C”、“A” chapters. A. Waterman, Design of the RISC-V ISA, UCB PhD thesis, 2016(C 擴展的定量依據).