RV32I:RISC-V 基础整数指令集
目錄
- RV32I指令
- 指令格式
- RV32I寄存器
- RV32I 整數(shù)計算
- RV32I load 和 Store
- 條件分支
- 無條件跳轉(zhuǎn)
- RV32I 雜項
- RV32I特性
- 一個例子
- 參考
提升計算性能并且讓用戶能切實享受到性能提升的唯一方法是同時設(shè)計編譯器和計算機。這樣軟件用不 到的特性將不會被實現(xiàn)在硬件上…
——Frances Elizabeth “Fran” Allen, 1981
RV32I指令
??圖 2.1 是 RV32I 基礎(chǔ)指令集的一頁圖形表示。對于每幅圖,將有下劃線的字母從左到 右連接起來,即可組成完整的 RV32I 指令集。對于每一個圖,集合標(biāo)志{}內(nèi)列舉了指令的 所有變體,變體用加下劃線的字母或下劃線字符_表示。特別的,下劃線字符_表示對于此 指令變體不需用字符表示。。例如,下圖表示了這四個 RV32I 指令:slt,slti,sltu,sltiu:
指令格式
??六種基本指令格式,分別是:
- 用于寄存器-寄存器操作的 R 類型指令
- 用 于短立即數(shù)和訪存 load 操作的 I 型指令
- 用于訪存 store 操作的 S 型指令
- 用于條件跳轉(zhuǎn)操作的 B 類型指令
- 用于長立即數(shù)的 U 型指令
- 用于無條件跳轉(zhuǎn)的 J 型指令
??即使是指令格式也能從一些方面說明 RISC-V 更簡潔的 ISA 設(shè)計能提高性能功耗比。 首先,指令只有六種格式,并且所有的指令都是 32 位長,這簡化了指令解碼。ARM-32, 還有更典型的 x86-32 都有許多不同的指令格式,使得解碼部件在低端實現(xiàn)中偏昂貴,在中高端處理器設(shè)計中容易帶來性能挑戰(zhàn)。第二,RISC-V 指令提供三個寄存器操作數(shù),而不是 像 x86-32 一樣,讓源操作數(shù)和目的操作數(shù)共享一個字段。當(dāng)一個操作天然就需要有三個不 同的操作數(shù),但是 ISA 只提供了兩個操作數(shù)時,編譯器或者匯編程序程序員就需要多使用 一條 move(搬運)指令,來保存目的寄存器的值。第三,在 RISC-V 中對于所有指令,要讀寫的寄存器的標(biāo)識符總是在同一位置,意味著在解碼指令之前,就可以先開始訪問寄存 器。在許多其他的 ISA 中,某些指令字段在部分指令中被重用作為源目的地,在其他指令 中又被作為目的操作數(shù)(例如,ARM-32 和 MIPS-32)。因此,為了取出正確的指令字 段,我們需要時序本就可能緊張的解碼路徑上添加額外的解碼邏輯,使得解碼路徑的時序 更為緊張。第四,這些格式的立即數(shù)字段總是符號擴展,符號位總是在指令中最高位。這 意味著可能成為關(guān)鍵路徑的立即數(shù)符號擴展,可以在指令解碼之前進行。
??為了給 ISA 擴展留出足夠的空間,最基礎(chǔ)的 RV32I 指令集只使用了 32 位指令字中的 編碼空間的不到八分之一。架構(gòu)師們也仔細(xì)挑選了 RV32I 操作碼,使擁有共同數(shù)據(jù)通路的 指令的操作碼位有盡可能多的位的值是一樣的,這簡化了控制邏輯。最后,當(dāng)我們看到,B 和 J 格式的分支和跳轉(zhuǎn)地址必須向左移動 1 位以將地址乘以 2,從而給予分支和跳轉(zhuǎn)指令 更大的跳轉(zhuǎn)范圍。RISC-V 將立即數(shù)中的位從自然排布進行了一些移位輪換,將指令信號的 扇出和立即數(shù)多路復(fù)用的成本降低了近兩倍,這也簡化了低端實現(xiàn)中的數(shù)據(jù)通路邏輯。
RV32I寄存器
??圖 4 列出了 RV32I 寄存器以及由 RISC-V 應(yīng)用程序二進制接口(ABI)所定義的寄存 器名稱。為了滿足匯編 語言程序員和編譯器編寫者,RV32I 有 31 寄存器加上一個值恒為 0 的 x0 寄存器。為常量 0 單獨分配一個寄存器是 RISC-V ISA 能如此簡單的一個很 大的因素。
RV32I 整數(shù)計算
??簡單的算術(shù)指令(add, sub)、邏輯指令(and, or, xor),以及圖 2.1 中的移位指令 (sll, srl, sra)和其他 ISA 差不多。他們從寄存器讀取兩個 32 位的值,并將 32 位結(jié)果寫 入目標(biāo)寄存器。RV32I 還提供了這些指令的立即數(shù)版本。和 ARM-32 不同,立即數(shù)總是進 行符號擴展,這樣子如果需要,我們可以用立即數(shù)表示負(fù)數(shù),正因為如此,我們并不需要 一個立即數(shù)版本的 sub。
??程序可以根據(jù)比較結(jié)果生成布爾值。為應(yīng)對這種使用場景下,RV32I 提供一個當(dāng)小于 時置位的指令。如果第一個操作數(shù)小于第二個操作數(shù),它將目標(biāo)寄存器設(shè)置為 1,否則為 0。不出所料,對這個指令,有一個有符號版本(slt)和無符號版本(sltu),分別用于處 理有符號和無符號整數(shù)比較。相應(yīng)的,上述兩條指令也有立即數(shù)版本的(slti,sltiu)。
??1 剩下的兩條整數(shù)計算指令主要用于構(gòu)造大的常量數(shù)值和鏈接。加載立即數(shù)到高 位(lui)將 20 位常量加載到寄存器的高 20 位。接著便可以使用標(biāo)準(zhǔn)的立即指令來創(chuàng)建 32 位常量。這樣子,僅使用 2 條 32 位 RV32I 指令,便可構(gòu)造一個 32 位常量。向 PC 高位加 上立即數(shù)(auipc)讓我們僅用兩條指令,便可以基于當(dāng)前 PC 以任意偏移量轉(zhuǎn)移控制流或 者訪問數(shù)據(jù)。將 auipc 中的 20 位立即數(shù)與 jalr(參見下面)中 12 位立即數(shù)的組合,我們 可以將執(zhí)行流轉(zhuǎn)移到任何 32 位 PC 相對地址。而 auipc 加上普通加載或存儲指令中的 12 位立即數(shù)偏移量,使我們可以訪問任何 32 位 PC 相對地址的數(shù)據(jù)。
??,RISC-V 中沒有字節(jié)或半字寬度的整數(shù)計算操作。操作始終 是以完整的寄存器寬度。RV32I 不包含乘法和除法,它們包含在可選的 RV32M 擴展。
RV32I load 和 Store
??除了提供 32 位字(lw,sw)的加載和存儲外,圖 2.1 中說明,RV32I 支持加載有符 號和無符號字節(jié)和半字(lb,lbu,lh,lhu)和存儲字節(jié)和半字(sb,sh)。有符號字節(jié) 和半字符號擴展為 32 位再寫入目的寄存器。在文本和無符號整數(shù) 中常用的無符號字節(jié)和半字,在寫入目標(biāo)寄存器之前都被無符號擴展到 32 位。
??加載和存儲的支持的唯一尋址模式是符號擴展 12 位立即數(shù)到基地址寄存器,這在 x86-32 中被稱為位偏移尋址模式。
??RV32I 省略了 ARM-32 和 x86-32 的復(fù)雜尋址模式。另外,ARM-32 提供的尋址模式并非適用于所有數(shù)據(jù)類型,但 RV32I 尋址不會歧視任何數(shù)據(jù)類型。RISCV 可以模仿某些 x86 尋址模式。例如,將立即數(shù)字段設(shè)置為 0 即與 x86 中的寄存器間接尋 址效果相同。與 x86-32 不同,RISC-V 沒有特殊的堆棧指令。將 31 個寄存器中的某一個作 為堆棧指針(見圖 2.4),標(biāo)準(zhǔn)尋址模式使用起來和壓棧(push)和出棧(pop)類似,并 且不增加 ISA 的復(fù)雜性。與 MIPS-32 不同,RISC-V 不支持延遲加載(delayed load)。
??雖然 ARM-32 和 MIPS-32 要求存儲在內(nèi)存中的數(shù)據(jù),要按照數(shù)據(jù)的自然大小進行邊界 對齊,但是 RISC-V 沒有這個要求。
條件分支
??RV32I 可以比較兩個寄存器并根據(jù)比較結(jié)果上進行分支跳轉(zhuǎn)。比較可以是:相等 (beq),不相等 (bne),大于等于(bge),或小于(blt)。最后兩種比較有符號比 較,RV32I 也提供相應(yīng)的無符號版本比較的:bgeu 和 bltu。剩下的兩個比較關(guān)系(大于和 小于等于)可以通過簡單地交換兩個操作數(shù),即可完成比較。
??由于 RISC-V 指令長度必須是兩個字節(jié)的倍數(shù)。分支指令的尋址方式是 12 位的立即數(shù)乘以 2,符號擴展它,然后將得到值加到 PC 上作為分支的跳轉(zhuǎn)地址。PC 相對尋址可用于位置無關(guān)的代碼,簡化了鏈接器和加載器 的工作。
??對于條件分支,它還沒有像 ARM-32 和 x86-32 那樣使用條件 碼。條件碼的存在使得大多數(shù)指令都需要隱式設(shè)置一些額外狀態(tài),這使亂序執(zhí)行的依賴計 算復(fù)雜化。最后,它省略了 x86-32 中的循環(huán)指令:loop,loope,loopz,loopne, loopnz。
無條件跳轉(zhuǎn)
??圖 2.1 中的跳轉(zhuǎn)并鏈接指令(jal)具有雙重功能。若將下一條指令 PC + 4 的地址保存 到目標(biāo)寄存器中,通常是返回地址寄存器 ra(見圖 2.4),便可以用它來實現(xiàn)過程調(diào)用。 如果使用零寄存器(x0)替換 ra 作為目標(biāo)寄存器,則可以實現(xiàn)無條件跳轉(zhuǎn),因為 x0 不能 更改。像分支一樣,jal 將其 20 位分支地址乘以 2,進行符號擴展后再添加到 PC 上,便得 到了跳轉(zhuǎn)地址。
??跳轉(zhuǎn)和鏈接指令的寄存器版本(jalr)同樣是多用途的。它可以調(diào)用地址是動態(tài)計算 出來的函數(shù),或者也可以實現(xiàn)調(diào)用返回(只需 ra 作為源寄存器,零寄存器(x0)作為目的 寄存器)。Switch 和 case 語句的地址跳轉(zhuǎn),也可以使用 jalr 指令,目的寄存器設(shè)為 x0。
??RV32I 避開了錯綜復(fù)雜的程序調(diào)用指令。
RV32I 雜項
??圖 2.1 中的控制狀態(tài)寄存器指令 (csrrc、csrrs、csrrw、csrrci、csrrsi、csrrwi), 使我們可以輕松地訪問一些程序性能計數(shù)器。對于這些 64 位計數(shù)器, 我們一次可以讀取 32 位。這些計數(shù)器包括了系統(tǒng)時間, 時鐘周期以及執(zhí)行的指令數(shù)目。
??在 RISC-V 指令集中,ecall 指令用于向運行時環(huán)境發(fā)出請求,例如系統(tǒng)調(diào)用。調(diào)試器 使用 ebreak 指令將控制轉(zhuǎn)移到調(diào)試環(huán)境。
??fence 指令對外部可見的訪存請求,如設(shè)備 I / O 和內(nèi)存訪問等進行串行化。外部可見 指對處理器的其他核心、線程,外部設(shè)備或協(xié)處理器可見。fence.i 指令同步指令和數(shù)據(jù) 流。在執(zhí)行 fence.i 指令之前,對于同一個硬件線程,RISC-V 不保證用存儲指令寫到內(nèi)存 指令區(qū)的數(shù)據(jù)可以被取指令取到。
?&ems;RISC-V 使用內(nèi)存映射 I / O 。為支持字符串處理,RISC-V 實現(xiàn)了 字節(jié)存取。
RV32I特性
??圖 2.7 使用七個 ISA 設(shè)計指標(biāo)來組織前面提到的一些過去的指令集中學(xué)習(xí) 到的經(jīng)驗教訓(xùn),并說明了這些經(jīng)驗教訓(xùn)對 RV32I 設(shè)計的積極影響。
- 32 位字節(jié)可尋址的地址空間
- 所有指令均為 32 位長
- 31 個寄存器,全部 32 位寬,寄存器 0 硬連線為零
- 所有操作都在寄存器之間(沒有寄存器到內(nèi)存的操作)
- 加載/存儲字加上有符號和無符號加載/存儲字節(jié)和半字
- 所有算術(shù),邏輯和移位指令都有立即數(shù)版本的指令
- 立即數(shù)總是符號擴展
- 僅提供一種數(shù)據(jù)尋址模式(寄存器+立即數(shù))和 PC 相對分支
- 無乘法或除法指令
- 一個指令,用于將大立即數(shù)加載到寄存器的高位,這樣加載 32 位常量到寄存器只需要兩條指令
一個例子
??冒泡排序算法的C實現(xiàn)如下:
??編譯成RV32I匯編語言之后如下:
參考
RISC-V 手冊 第二章
總結(jié)
以上是生活随笔為你收集整理的RV32I:RISC-V 基础整数指令集的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hive 正则表达式验证电话号码
- 下一篇: DNA存储技术—让信息保存万年