RISC-V 架構簡介

最後更新: 2023-01-29 16:47:11 +0800 +0800
原文以英文撰寫。您正在閱讀AI翻譯版本。

RISC-V 是一種開放的指令集架構,由基礎整數 ISA 和分別進行版本管理的擴充組成。ISA 定義指令行為和特權執行;平台設定檔、ABI 以及執行環境則補充執行可互通軟體所需的要求。

基礎整數 ISA 與暫存器慣例 #

RV32I 和 RV64I 分別提供 32 位元和 64 位元整數暫存器。兩者都定義了從 x0 到 x31 的 32 個通用暫存器。x0 永遠讀取為零,並捨棄寫入。程式計數器透過控制流程效果在架構上可見,而不是作為通用暫存器存在。

RISC-V 採用載入—儲存設計。整數算術讀取暫存器運算元並寫入暫存器;載入和儲存會在暫存器與記憶體之間移動值。基礎 ISA 使用固定的 32 位元編碼。RV64I 增加了 64 位元暫存器和運算,以及對低 32 位元值執行符號延伸的 *W 運算;因此,它並非只是位址較寬的 RV32I。

標準整數呼叫慣例分配以下 ABI 名稱和角色:

RegistersABI namesRole
x0zero常數零
x1ra返回位址
x2sp堆疊指標
x5-x7, x28-x31t0-t6caller-saved 暫存暫存器
x8-x9, x18-x27s0-s11callee-saved 暫存器
x10-x17a0-a7引數和返回值

浮點和向量呼叫慣例還會增加各自的規則。與編譯程式碼互通的組合語言必須遵循完整的 psABI,包括堆疊對齊、需保留的狀態、重定位以及程式碼模型。

擴充、ISA 字串和設定檔 #

單字母標準擴充包括:表示整數乘除法的 M,表示原子操作的 A,表示浮點的 F 和 D,表示壓縮指令的 C,以及表示向量的 V。多字母擴充涵蓋範圍更窄的功能,並在 ISA 字串語法要求時使用底線分隔。擴充版本很重要,因為批准程序和後續修訂可能會改變精確的契約。

歷史上的 G 縮寫表示以 IMAFD 為核心並包含所需相依項的通用擴充集合。rv64gc 這樣的字串很方便,但無法表達所有平台功能、ABI 或特權功能。工具鏈會規範化擴充順序並展開相依關係;不要自行建構有歧義的字串,而應使用工具鏈的 -march 診斷。

C 擴充為常用操作提供 16 位元編碼,從而提高程式碼密度。壓縮指令按照其定義操作的語義執行,並且可以與較長的編碼交錯使用。指令對齊和分支目標必須遵循目標實作的擴充。

RISC-V 設定檔為某類系統選擇一組命名的必要和選用 ISA 功能。實作也可以公開自訂擴充。可攜式軟體應針對硬體和執行環境共同支援的設定檔或明確擴充集合,而不應假定每個 RV64 處理器都實作相同的 ISA。

特權模式、CSR 和例外 #

特權架構定義機器模式(M)、監督者模式(S)和使用者模式(U)。M-mode 是必要的,用於控制機器。S-mode 支援作業系統和虛擬記憶體,U-mode 支援應用程式。選用的虛擬化功能會增加由虛擬機器管理程式控制的變體以及兩階段位址轉換。

控制與狀態暫存器(CSR)保存例外狀態、中斷啟用、位址轉換控制、計數器以及擴充特定狀態。CSR 位址編碼了存取限制和特權限制。缺少權限的指令會觸發例外,而不是無提示地存取特權級別更高的暫存器。

例外會記錄原因、例外 PC 和選取的狀態,然後轉移到設定的例外向量。委派暫存器可以將選取的例外從 M-mode 路由到 S-mode。ECALL 向執行環境請求服務,MRET 或 SRET 執行從特權處理常式經過檢查的返回。

監督者軟體不應依賴供應商特定的 M-mode 韌體呼叫。Supervisor Binary Interface(SBI)為計時器程式設計、處理器間中斷、hart 管理、系統重設以及韌體輔助的效能監控等服務定義可攜式介面。SBI 是執行環境介面,而不是指令集擴充。

虛擬記憶體和轉換柵欄 #

S-mode 轉換方案包括面向 RV32 的 Sv32,以及面向 RV64 的 Sv39、Sv48 和 Sv57 等方案。頁表項目攜帶有效、讀取/寫入/執行、使用者、已存取、髒以及其他屬性。作用中的方案和根由 satp 選取。

頁表寫入不會自動使所有快取的轉換保持一致。SFENCE.VMA 會對相關頁表更新進行排序,並使其指定作用域內的位址轉換快取項目失效。多處理器 shootdown 還需要與遠端 hart 協調,通常透過 SBI 或平台特定的處理器間中斷路徑完成。

記憶體排序、柵欄和原子操作 #

基礎 RISC-V 弱記憶體模型允許在相依關係或同步未禁止的情況下,觀測結果不同於程式順序。FENCE 會對選取的前驅類別和後繼類別進行排序,而 FENCE.I 則在執行該指令的 hart 上協調資料寫入與後續指令擷取。

A 擴充提供載入保留/條件儲存操作和原子記憶體操作。取得(aq)位元和釋放(rl)位元為原子操作增加排序;aqrl 同時提供兩個方向。原子性和排序解決的是不同問題:不可分割的計數器更新不會發布不相關的資料,除非同時存在所需的排序。

在 C、C++ 和 Rust 中,應優先使用語言層級原子操作,因為編譯器會將其記憶體模型對映到可用的 RISC-V 序列。手寫組合語言必須考慮擴充集合、記憶體和 I/O 網域、保留失敗以及前進保證規則。

主要參考資料 #

評論

在 GitHub 上閱讀或評論(發表評論需要登入)