20世紀90年代末,RISC和CISC爆發(fā)了一場大戰(zhàn),自那以后,大家都說RISC和CISC的區(qū)別沒那么重要了。許多人表示,指令集也就那么回事,對CPU沒什么太大的影響。但其實不然,指令集決定了我們可以輕松為微處理器做哪些優(yōu)化。
本文將介紹RISC-V處理器是如何設計指令集的,這樣的設計具有什么好處。
我最近一直在了解有關RISC-V指令集架構 (ISA) 的更多信息,說起來,關于RISC-V ISA有幾件事給我留下了非常深刻的印象: ◆ 它是一種RISC指令集,體積小,易于學 習 。 不管是任何人,只要有興趣學習微處理器,選它準沒錯。 ◆ 它在大學數(shù)字化設計教學中占據(jù)重要地位:為什么大學要學RISC-V。 ◆ 經過巧妙地設計,它允許CPU設計生產者使用RISC-V ISA打造高性能微處理器。 ◆ 無需授權費,且被設計成允許簡單的硬件實現(xiàn),按道理,專業(yè)愛好者可以在合理的時間內完成他自己的RISC-V CPU設計。 ◆ 易于修改和使用的開源設計:The Berkely Out-of-Order(BOOM)RISC-V處理器。
01
RISC的復仇
當我開始更深入地理解RISC-V時,意識到RISC-V是一種根本性的轉變,它回到了許多人認為已經過時的計算時代。在設計方面,RISC-V就像乘著時光機穿越回了上世紀八九十年代的經典RISC時代。近年來,許多人指出RISC和CISC的區(qū)別不再重要,因為像ARM這樣的 RISC CPU已經添加了太多的指令,很多指令相當復雜,以至于它現(xiàn)在更像是一個混合的RISC CPU,而不是純粹的RISC CPU。而那些RISC CPU也是如此,比如PowerPC。 相比之下,RISC-V是RISC CPU真正的硬核。事實上,如果你在網上看過大家就RISC-V的討論,會發(fā)現(xiàn)有人聲稱RISC-V出自一些老學究式的RISC激進分子之手,他們拒絕與時俱進。 前ARM工程師Erin Shepherd幾年前就RISC-V寫過一篇評論,內容很有意思: RISC-V ISA過分追求極簡主義。它非常強調最小化指令數(shù)、規(guī)范化編碼這些事。這種對極簡主義的追求導致了錯誤的正交性(例如針對分支、調用和返回重用同一條指令)和對冗余指令的需求,這在指令大小和數(shù)量這兩個方面影響了代碼密度。 我向大家簡單介紹一下背景。讓代碼更小對性能有好處,因為這樣就可以更容易將正在運行的代碼保存在高速CPU緩存中。 本文在此批評的是,RISC-V設計者太過于追求擁有小的指令集。盡管,這是RISC最初的目標之一。然而,這樣做的弊端是,實際上程序在完成工作時將需要更多的指令,從而消耗更多的內存空間。多年來,人們普遍認為RISC處理器應該增加更多的指令,變得更像CISC。其理論依據(jù)是,更專門化的指令可以替代對多個通用指令的使用。
02
壓縮指令和宏融合
然而,在CPU設計中有兩項特別的創(chuàng)新,這些創(chuàng)新從許多方面使添加更多復雜指令的策略變得多余:◆ 壓縮指令——在內存中壓縮指令,并在CPU的第一階段進行解壓。 ◆ 宏融合——將兩個或兩個以上由CPU讀取的簡單指令融合成一個復雜指令。 實際上ARM已經采用了這兩種策略,而x86 CPU則采用了后者,所以這不能算是RISC-V的新招術。 然而,關鍵是RISC-V從這些策略中獲得了更大的優(yōu)勢,這里面有兩個重要原因: ◆ 它從一開始就添加了壓縮指令。 在 ARM 上使用的是 Thumb2 壓縮指令格式,這就必須將其作為一個單獨的ISA來添加以完成改造,這需要一個內部模 式切換和單獨的解碼器來進行處理。 RISC-V壓縮指令可以添加到具有400個額外邏輯門 (AND、OR、NOR、NAND 門) 的CPU上。 ◆ RISC執(zhí)著地控制獨特指令的數(shù)量得到了回報,如此就有了更多的空間來容納壓縮指令。
03
指令編碼
這一部分需要進行一些解釋。指令在RISC體系結構上通常是32位(即比特)寬的。這些比特需要用來編碼不同的信息。例如,下面這樣一條指令: ADD x1, x4, x8 # x1 ← x4 + x8
這條指令將累加寄存器x4和x8的內容,然后將結果存儲在x1中。我們需要多少比特來編碼,這取決于我們有多少寄存器。RISC-V和ARM64有32個寄存器。可以用5比特表示數(shù)字32:
2? = 32
因為我們需要指定3個不同的寄存器,所以我們需要總共15比特 (3×5) 來編碼操作數(shù) (累加操作的輸入)。 因此,我們想要在指令集中支持的東西越多,那么就會消耗掉那32比特中更多的比特。當然,我們可以使用64位指令,但是這會消耗太多的內存,從而降低性能。 通過刻意壓低指令的數(shù)量,RISC-V節(jié)省下更多的空間來添加表示我們正在使用的壓縮指令的比特。如果CPU看到指令中的某些位被設置為1,它就知道這條指令應該作為一條壓縮指令來進行解釋。 04
壓縮指令——二到一
這表示,我們可以將兩條16位寬的指令裝入一個32位字,而不是一個32位字只裝入一條指令。當然,并不是所有的RISC-V指令都可以用16位格式表示。因此,32位指令的子集是根據(jù)它們的效用和使用頻率來挑選的。未壓縮指令可以接受3個操作數(shù) (輸入),而壓縮指令只能接受2個操作數(shù)。因此,壓縮后的ADD指令應該如下所示:(# 號后為注釋)
C.ADD x4, x8 # x4 ← x4 + x8
RISC-V匯編程序使用前綴 c. 來指示一條指令應該被匯編程序轉換成一個壓縮指令。但實際上你不需要去寫它。RISC-V匯編程序將能夠在適當?shù)臅r候選擇是壓縮指令還是非壓縮指令。 基本上,壓縮指令減少了操作數(shù)的數(shù)量。三個寄存器操作數(shù)將消耗15比特,而留給我們指定操作的就只剩下1比特了!因此,將操作數(shù)減少到兩個,我們就能剩下6比特來指定操作碼 (要執(zhí)行的操作)。 這實際上接近于x86匯編的工作方式,在x86匯編中沒有足夠的比特來保留3個寄存器操作數(shù)。取而代之的是,x86使用一些比特來允許像ADD這樣的指令從內存和寄存器中讀取輸入。 05
宏融合——一到二
但是,當我們將指令壓縮與宏融合結合起來看時,才能發(fā)現(xiàn)真正的收益。你看,如果CPU得到一個包含有兩個16比特的壓縮指令的32比特的字,它可以把這些合并成一條單一的復雜指令。這聽起來很荒謬,我們不是又回到原點了嗎?我們是不是又回到CISC風格的CPU,這不正是我們試圖要避免的嗎? 不是的,因為我們避免用大量復雜的指令、x86和ARM策略填充ISA規(guī)范。相反,我們基本上是通過各種簡單指令的組合來間接地表達一整套復雜指令。 在正常情況下,宏融合存在一個問題:雖然兩條指令可以被一條指令替換,但它們仍然會消耗兩倍的內存空間。但是使用指令壓縮,我們不會消耗更多的空間。我們做到了兩全其美。 讓我們來看看艾琳·謝潑德的一個例子。在她批評RISC-V ISA時,展示了一個簡單的C函數(shù)。為了解釋起來更清楚一些,我把它重新寫了下來,內容如下:
int get_index(int *array, int i) {
return array[i];
}
在x86上編譯成:
mov eax, [rdi+rsi*4]
ret
當你在編程語言中調用函數(shù)時,參數(shù)通常會根據(jù)既定的約定傳遞給寄存器中的函數(shù),這將取決于你所使用的指令集。在x86上,第一個參數(shù)放在寄存器 rdi 中,第二個放在 rsi 中。按照慣例,返回值必須放在寄存器eax中。 第一條指令將 rsi 的內容乘以4。它包含了變量 i。為什么乘?因為數(shù)組是由整數(shù)元素組成的,所以它們之間的間距為4個字節(jié)。因此,數(shù)組中的第三個元素的字節(jié)偏移量實際上是3×4=12。 然后,我們把它添加到rdi,它包含數(shù)組的基址。于是,我們得到了數(shù)組第 i 個元素的最終地址。我們讀取該地址的存儲單元的內容,并將其存儲在 eax 中:大功告成。 在ARM上與之很相似:
LDR r0, [r0, r1, lsl #2]
BX lr ; return
這里我們不是乘以4,而是將寄存器r1向左平移2位,這就相當于乘以 4。這也可能是更本真地表示了x86代碼中所發(fā)生的情況。在x86上,你只能乘以2、4、8,所有這些其實都可以通過左移1、2、3位來實現(xiàn)。 我想,x86描述中的剩余內容你肯定都能猜得到了?,F(xiàn)在讓我們進入 RISC-V,真正有趣的內容開始嘍!(# 號后為注釋)
SLLI a1, a1, 2 # a1 ← a1 << 2 ADD a0, a0, a1 # a0 ← a0 + a1 LW a0, a0, 0 # a0 ← [a0 + 0] RET
RISC-V上的寄存器a0和a1只是x10和x11的別名。它們是放置函數(shù)調用的第一個和第二個參數(shù)的地方。RET是一條偽指令(簡寫):
JALR x0, 0(ra) # sp ← 0 + ra
# x0 ← sp + 4 ignoring result
JALR 跳轉到 ra 引用返回地址的地址。ra 是 x1 的別名。 不管怎樣看,這似乎都很糟糕,對吧?對于像在表中執(zhí)行基于索引的查找并返回結果這樣簡單而常見的操作,需要兩倍的指令。 看上去確實很糟糕。這就是為什么艾琳·謝潑德強烈批評了 RISC-V 的設計選擇。她寫道: RISC-V 的簡化使解碼器 (即 CPU 前端) 更簡單,但代價是執(zhí)行更多的指令。然而,真正棘手的問題是擴展流水線的寬度,而稍稍不規(guī)則甚至很不規(guī)則的指令其解碼都不會有太大的問題,主要難點是確定指令的長度,尤其是 x86,因為它有很多前綴。 然而,多虧了有指令壓縮和宏融合,我們可以扳回這一程。
C.SLLI a1, 2 # a1 ← a1 << 2 C.ADD a0, a1 # a0 ← a0 + a1 C.LW a0, a0, 0 # a0 ← [a0 + 0] C.JR ra
現(xiàn)在,這和 ARM 的例子中所占用的內存空間是完全相同的。 好吧,接下來讓我們做一些 宏融合! 在 RISC-V 中允許將多個操作融合為一個的規(guī)則之一是,目標寄存器得是相同的。ADD 和 LW(加載字) 指令就屬于這種情況。因此,中央處理器將把這些轉換成一條指令。 如果 SLLI 也是這樣的話,我們就可以把這三條指令融合成一條了。因此,CPU 會看到一些類似于更復雜的 ARM 指令的東西:
LDR r0, [r0, r1, lsl #2]
06
為何不能在代碼中直接編寫此宏操作
因為我們的 ISA 不包含對它的支持!記住,可用的比特數(shù)是有限的。為什么不把說明寫長一點呢?不行,那樣會消耗太多的內存,并且會更快填滿寶貴的 CPU 緩存。然而,如果我們在 CPU 內部制造這些半復雜的長指令,也沒有什么可擔心的。CPU 在任何時候所面對的指令最多也不過幾百條。所以在每條指令上浪費個 128 比特不是什么大問題。每個人都有足夠的硅。 因此,當解碼器得到一條正常指令時,它通常會把它轉換成一個或多個“微”操作。這些“微”操作是 CPU 實際要處理的指令。它們可以非常地“寬廣”,包含很多額外的有用信息。稱之為“微”似乎有些諷刺,因為它們其實很“廣”。然而事實上“微”指的是它們做的任務數(shù)量有限。
07
指令的復雜性
宏融合將解碼器的工作做了一點改變:不再是將一條指令轉換成多個微操作,而是將多個操作轉換成一個微操作。因此,在現(xiàn)代 CPU 中發(fā)生的事情看起來相當奇怪:
-
首先,它通過壓縮將兩條指令合并為一條指令。
-
然后借助解壓把它分成兩部分。
-
通過宏融合將它們合并到一個操作中。
-
不能太復雜,否則無法在為每條指令分配的數(shù)量固定的時鐘周期內完成。
-
不能太簡單,因為那純粹就是浪費CPU資源。執(zhí)行兩個微操作的時間是執(zhí)行一個微操作的時間的兩倍。
08
RISC的好處
好了,以上解釋了很多細節(jié),也許你很難一下子弄清楚重點是什么。為什么要進行壓縮和融合?聽起來有很多額外的工作要做。首先,指令壓縮和zip壓縮完全不同。“壓縮”這個詞其實有點用詞不當,因為立即解壓一條已壓縮的指令非常簡單。做這件事并不浪費時間。記住,對于RISC-V來說這很簡單。只需400個邏輯門,就可以完成解壓。 宏融合也是如此。雖然這看起來很復雜,但這些方法已經在現(xiàn)代微處理器中得到了應用。因此,這種復雜性的學費早就已經交過了。 然而,與ARM、MIPS和x86設計者不同的是,RISC-V設計者在開始設計ISA時就了解指令壓縮和宏融合。或者更準確地說,當他們最初的ISA被設計出來的時候,那些競爭對手們并不知道這一點。當設計64位版本的 x86 和 ARM 指令集時,他們可能已經考慮到了這一點。那么,為什么他們沒有這樣做呢,我們只能揣測??赡苁沁@些公司制作新的ISA時,不喜歡過多地偏離早期版本吧。通常它更著重于消除以往明顯的錯誤,而不是顛覆之前的理論基礎。 通過對第一個最小指令集展開各種測試,RISC-V的設計者有了兩個重要的發(fā)現(xiàn):
-
通常RISC-V程序占用的內存空間接近或少于任何其他CPU體系結構,包括x86,鑒于x86是CISC ISA,所以被公認是最節(jié)省空間的。
-
它需要執(zhí)行的微操作數(shù)比其他ISA更少。
09
RISC-V設計策
RISC-V利用了我們當今對現(xiàn)代CPU的了解,并用這些知識指導了他們在設計時的選擇。例如,我們知道:-
如今,CPU內核會提前做分支預測。它們的預測正確率超過90%。
-
CPU內核是超標量體系結構的,這意味著它們在并行執(zhí)行多條指令。
-
使用無序執(zhí)行做到超標量體系結構。
-
它們是流水線式的。
10
業(yè)界有什么說法?
好吧,從理論上這聽起來可能很好,但在現(xiàn)實世界中也果真如此嗎?科技公司對此有什么看法?他們是否認為RISC-V ISA比商業(yè)ISA(如ARM)提供了實實在在的好處? RISC-V甚至不在備選的采購清單上,但隨著Esperanto的工程師們對它越來越多的研究,他們漸漸意識到它不僅僅是一個玩具或者是一個教學工具?!拔覀冋J為RISC-V(相對于Arm或MIPS或SPARC)可能會損失30%到40%的編譯效率,因為它太簡單了?!盌itzel說。“但我們的編譯器專業(yè)人員對它進行了基準測試,難以置信的是只有1%左右?!?/span> Esperanto Technologies現(xiàn)在只是一家小公司。像英偉達這樣擁有大量經驗豐富的芯片設計師和資源的大公司呢?英偉達在他們的板卡上使用了一種叫做“獵鷹”的通用處理器。在評估備選方案時,RISC-V名列前茅。免責聲明:本文內容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!