本文為《RISC-V CPU設(shè)計(jì)》專(zhuān)欄和《RISC-V嵌入式軟件開(kāi)發(fā)》專(zhuān)欄系列文章之一。
注:本文節(jié)選自“硅農(nóng)亞歷山大”所著國(guó)內(nèi)第一本系統(tǒng)介紹CPU與RISC-V設(shè)計(jì)的中文書(shū)籍《手把手教你設(shè)計(jì)CPU:RISC-V處理器篇》(預(yù)計(jì)將于2018年3~4月上市)。
“大道至簡(jiǎn)——RISC-V架構(gòu)之魂”——分成上中下三篇,本文是中篇。關(guān)注文末公眾號(hào)后可查詢(xún)上中下三篇的內(nèi)容。
本文上接《大道至簡(jiǎn)——RISC-V架構(gòu)之魂(上)》
2.3 規(guī)整的指令編碼
在流水線(xiàn)中能夠盡早盡快的讀取通用寄存器組,往往是處理器流水線(xiàn)設(shè)計(jì)的期望之一,這樣可以提高處理器性能和優(yōu)化時(shí)序。這個(gè)看似簡(jiǎn)單的道理在很多現(xiàn)存的商用RISC架構(gòu)中都難以實(shí)現(xiàn),因?yàn)榻?jīng)過(guò)多年反復(fù)修改不斷添加新指令后,其指令編碼中的寄存器索引位置變得非常的凌亂,給譯碼器造成了負(fù)擔(dān)。
得益于后發(fā)優(yōu)勢(shì)和總結(jié)了多年來(lái)處理器發(fā)展的教訓(xùn),RISC-V的指令集編碼非常的規(guī)整,指令所需的通用寄存器的索引(Index)都被放在固定的位置,如圖2所示。因此指令譯碼器(Instruction Decoder)可以非常便捷的譯碼出寄存器索引然后讀取通用寄存器組(Register File,Regfile)。
圖2 RV32I規(guī)整的指令編碼格式
2.4 簡(jiǎn)潔的存儲(chǔ)器訪問(wèn)指令
與所有的RISC處理器架構(gòu)一樣,RISC-V架構(gòu)使用專(zhuān)用的存儲(chǔ)器讀(Load)指令和存儲(chǔ)器寫(xiě)(Store)指令訪問(wèn)存儲(chǔ)器(Memory),其他的普通指令無(wú)法訪問(wèn)存儲(chǔ)器,這種架構(gòu)是RISC架構(gòu)的常用的一個(gè)基本策略,這種策略使得處理器核的硬件設(shè)計(jì)變得簡(jiǎn)單。
存儲(chǔ)器訪問(wèn)的基本單位是字節(jié)(Byte)。RISC-V的存儲(chǔ)器讀和存儲(chǔ)器寫(xiě)指令支持一個(gè)字節(jié)(8位),半字(16位),單字(32位)為單位的存儲(chǔ)器讀寫(xiě)操作,如果是64位架構(gòu)還可以支持一個(gè)雙字(64位)為單位的存儲(chǔ)器讀寫(xiě)操作。
RISC-V架構(gòu)的存儲(chǔ)器訪問(wèn)指令還有如下顯著特點(diǎn):
為了提高存儲(chǔ)器讀寫(xiě)的性能,RISC-V架構(gòu)推薦使用地址對(duì)齊的存儲(chǔ)器讀寫(xiě)操作,但是地址非對(duì)齊的存儲(chǔ)器操作RISC-V架構(gòu)也支持,處理器可以選擇用硬件來(lái)支持,也可以選擇用軟件來(lái)支持。
由于現(xiàn)在的主流應(yīng)用是小端格式(Little-Endian),RISC-V架構(gòu)僅支持小端格式。有關(guān)小端格式和大端格式的定義和區(qū)別,本文在此不做過(guò)多介紹,若對(duì)此不甚了解的初學(xué)者可以自行查閱學(xué)習(xí)。
很多的RISC處理器都支持地址自增或者自減模式,這種自增或者自減的模式雖然能夠提高處理器訪問(wèn)連續(xù)存儲(chǔ)器地址區(qū)間的性能,但是也增加了設(shè)計(jì)處理器的難度。RISC-V架構(gòu)的存儲(chǔ)器讀和存儲(chǔ)器寫(xiě)指令不支持地址自增自減的模式。
RISC-V架構(gòu)采用松散存儲(chǔ)器模型(Relaxed Memory Model),松散存儲(chǔ)器模型對(duì)于訪問(wèn)不同地址的存儲(chǔ)器讀寫(xiě)指令的執(zhí)行順序不作要求,除非使用明確的存儲(chǔ)器屏障(Fence)指令加以屏蔽。
這些選擇都清楚地反映了RISC-V架構(gòu)力圖簡(jiǎn)化基本指令集,從而簡(jiǎn)化硬件設(shè)計(jì)的哲學(xué)。RISC-V架構(gòu)如此定義非常合理,能夠達(dá)到能屈能伸的效果。譬如:對(duì)于低功耗的簡(jiǎn)單CPU,可以使用非常簡(jiǎn)單的硬件電路即可完成設(shè)計(jì);而對(duì)于追求高性能的超標(biāo)量處理器則可以通過(guò)復(fù)雜設(shè)計(jì)的動(dòng)態(tài)硬件調(diào)度能力來(lái)提高性能。
2.5 高效的分支跳轉(zhuǎn)指令
RISC-V架構(gòu)有兩條無(wú)條件跳轉(zhuǎn)指令(Unconditional Jump),jal與jalr指令。跳轉(zhuǎn)鏈接(Jump and Link)指令jal可用于進(jìn)行子程序調(diào)用,同時(shí)將子程序返回地址存在鏈接寄存器(Link Register:由某一個(gè)通用整數(shù)寄存器擔(dān)任)中。跳轉(zhuǎn)鏈接寄存器(Jump and Link-Register)指令jalr指令能夠用于子程序返回指令,通過(guò)將jal指令(跳轉(zhuǎn)進(jìn)入子程序)保存的鏈接寄存器用于jalr指令的基地址寄存器,則可以從子程序返回。
RISC-V架構(gòu)有6條帶條件跳轉(zhuǎn)指令(Conditional Branch),這種帶條件的跳轉(zhuǎn)指令跟普通的運(yùn)算指令一樣直接使用2個(gè)整數(shù)操作數(shù),然后對(duì)其進(jìn)行比較,如果比較的條件滿(mǎn)足時(shí),則進(jìn)行跳轉(zhuǎn)。因此,此類(lèi)指令將比較與跳轉(zhuǎn)兩個(gè)操作放到了一條指令里完成。
作為比較,很多的其他RISC架構(gòu)的處理器需要使用兩條獨(dú)立的指令。第一條指令先使用比較指令,比較的結(jié)果被保存到狀態(tài)寄存器之中;第二條指令使用跳轉(zhuǎn)指令,判斷前一條指令保存在狀態(tài)寄存器當(dāng)中的比較結(jié)果為真時(shí)則進(jìn)行跳轉(zhuǎn)。相比而言RISC-V的這種帶條件跳轉(zhuǎn)指令不僅減少了指令的條數(shù),同時(shí)硬件設(shè)計(jì)上更加簡(jiǎn)單。
對(duì)于沒(méi)有配備硬件分支預(yù)測(cè)器的低端CPU,為了保證其性能,RISC-V的架構(gòu)明確要求其采用默認(rèn)的靜態(tài)分支預(yù)測(cè)機(jī)制,即:如果是向后跳轉(zhuǎn)的條件跳轉(zhuǎn)指令,則預(yù)測(cè)為“跳”;如果是向前跳轉(zhuǎn)的條件跳轉(zhuǎn)指令,則預(yù)測(cè)為“不跳”,并且RISC-V架構(gòu)要求編譯器也按照這種默認(rèn)的靜態(tài)分支預(yù)測(cè)機(jī)制來(lái)編譯生成匯編代碼,從而讓低端的CPU也能得到不錯(cuò)的性能。
為了使硬件設(shè)計(jì)盡量簡(jiǎn)單,RISC-V架構(gòu)特地定義了所有的帶條件跳轉(zhuǎn)指令跳轉(zhuǎn)目標(biāo)的偏移量(相對(duì)于當(dāng)前指令的地址)都是有符號(hào)數(shù),并且其符號(hào)位被編碼在固定的位置。因此,這種靜態(tài)預(yù)測(cè)機(jī)制在硬件上非常容易實(shí)現(xiàn),硬件譯碼器可以輕松的找到這個(gè)固定的位置,并判斷其是0還是1來(lái)判斷其是正數(shù)還是負(fù)數(shù),如果是負(fù)數(shù)則表示跳轉(zhuǎn)的目標(biāo)地址為當(dāng)前地址減去偏移量,也就是向后跳轉(zhuǎn),則預(yù)測(cè)為“跳”。當(dāng)然對(duì)于配備有硬件分支預(yù)測(cè)器的高端CPU,則可以采用高級(jí)的動(dòng)態(tài)分支預(yù)測(cè)機(jī)制來(lái)保證性能。
2.6 簡(jiǎn)潔的子程序調(diào)用
為了理解此節(jié),需先對(duì)一般RISC架構(gòu)中程序調(diào)用子函數(shù)的過(guò)程予以介紹,其過(guò)程如下:
進(jìn)入子函數(shù)之后需要用存儲(chǔ)器寫(xiě)(Store)指令來(lái)將當(dāng)前的上下文(通用寄存器等的值)保存到系統(tǒng)存儲(chǔ)器的堆棧區(qū)內(nèi),這個(gè)過(guò)程通常稱(chēng)為“保存現(xiàn)場(chǎng)”。
在退出子程序之時(shí),需要用存儲(chǔ)器讀(Load)指令來(lái)將之前保存的上下文(通用寄存器等的值)從系統(tǒng)存儲(chǔ)器的堆棧區(qū)讀出來(lái),這個(gè)過(guò)程通常稱(chēng)為“恢復(fù)現(xiàn)場(chǎng)”。
“保存現(xiàn)場(chǎng)”和“恢復(fù)現(xiàn)場(chǎng)”的過(guò)程通常由編譯器編譯生成的指令來(lái)完成,使用高層語(yǔ)言(譬如C或者C++)開(kāi)發(fā)的開(kāi)發(fā)者對(duì)此可以不用太關(guān)心。高層語(yǔ)言的程序中直接寫(xiě)上一個(gè)子函數(shù)調(diào)用即可,但是這個(gè)底層發(fā)生的“保存現(xiàn)場(chǎng)”和“恢復(fù)現(xiàn)場(chǎng)”的過(guò)程卻是實(shí)實(shí)在在地發(fā)生著(可以從編譯出的匯編語(yǔ)言里面看到那些“保存現(xiàn)場(chǎng)”和“恢復(fù)現(xiàn)場(chǎng)”的匯編指令),并且還需要消耗若干的CPU執(zhí)行時(shí)間。
為了加速這個(gè)“保存現(xiàn)場(chǎng)”和“恢復(fù)現(xiàn)場(chǎng)”的過(guò)程,有的RISC架構(gòu)發(fā)明了一次寫(xiě)多個(gè)寄存器到存儲(chǔ)器中(Store Multiple),或者一次從存儲(chǔ)器中讀多個(gè)寄存器出來(lái)(Load Multiple)的指令,此類(lèi)指令的好處是一條指令就可以完成很多事情,從而減少匯編指令的代碼量,節(jié)省代碼的空間大小。但是此種“Load Multiple”和“Store Multiple”的弊端是會(huì)讓CPU的硬件設(shè)計(jì)變得復(fù)雜,增加硬件的開(kāi)銷(xiāo),也可能損傷時(shí)序使得CPU的主頻無(wú)法提高,筆者在曾經(jīng)設(shè)計(jì)此類(lèi)處理器時(shí)便深受其苦。
RISC-V架構(gòu)則放棄使用這種“Load Multiple”和“Store Multiple”指令。并解釋?zhuān)绻械膱?chǎng)合比較介意這種“保存現(xiàn)場(chǎng)”和“恢復(fù)現(xiàn)場(chǎng)”的指令條數(shù),那么可以使用公用的程序庫(kù)(專(zhuān)門(mén)用于保存和恢復(fù)現(xiàn)場(chǎng))來(lái)進(jìn)行,這樣就可以省掉在每個(gè)子函數(shù)調(diào)用的過(guò)程中都放置數(shù)目不等的“保存現(xiàn)場(chǎng)”和“恢復(fù)現(xiàn)場(chǎng)”的指令。
此選擇再次印證了RISC-V追求硬件簡(jiǎn)單的哲學(xué),因?yàn)榉艞墶癓oad Multiple”和“Store Multiple”指令可以大幅簡(jiǎn)化CPU的硬件設(shè)計(jì),對(duì)于低功耗小面積的CPU可以選擇非常簡(jiǎn)單的電路進(jìn)行實(shí)現(xiàn),而高性能超標(biāo)量處理器由于硬件動(dòng)態(tài)調(diào)度能力很強(qiáng),可以有強(qiáng)大的分支預(yù)測(cè)電路保證CPU能夠快速的跳轉(zhuǎn)執(zhí)行,從而可以選擇使用公用的程序庫(kù)(專(zhuān)門(mén)用于保存和恢復(fù)現(xiàn)場(chǎng))的方式減少代碼量,但是同時(shí)達(dá)到高性能。
12下一頁(yè)>(免責(zé)聲明:本網(wǎng)站內(nèi)容主要來(lái)自原創(chuàng)、合作伙伴供稿和第三方自媒體作者投稿,凡在本網(wǎng)站出現(xiàn)的信息,均僅供參考。本網(wǎng)站將盡力確保所提供信息的準(zhǔn)確性及可靠性,但不保證有關(guān)資料的準(zhǔn)確性及可靠性,讀者在使用前請(qǐng)進(jìn)一步核實(shí),并對(duì)任何自主決定的行為負(fù)責(zé)。本網(wǎng)站對(duì)有關(guān)資料所引致的錯(cuò)誤、不確或遺漏,概不負(fù)任何法律責(zé)任。
任何單位或個(gè)人認(rèn)為本網(wǎng)站中的網(wǎng)頁(yè)或鏈接內(nèi)容可能涉嫌侵犯其知識(shí)產(chǎn)權(quán)或存在不實(shí)內(nèi)容時(shí),應(yīng)及時(shí)向本網(wǎng)站提出書(shū)面權(quán)利通知或不實(shí)情況說(shuō)明,并提供身份證明、權(quán)屬證明及詳細(xì)侵權(quán)或不實(shí)情況證明。本網(wǎng)站在收到上述法律文件后,將會(huì)依法盡快聯(lián)系相關(guān)文章源頭核實(shí),溝通刪除相關(guān)內(nèi)容或斷開(kāi)相關(guān)鏈接。 )