如果僅從“免費(fèi)”或“開放”這兩點(diǎn)來評(píng)判,RISC-V架構(gòu)并不是第一個(gè)做到免費(fèi)或開放的處理器架構(gòu)。
在開始之前,我們先通過論述幾個(gè)具有代表性的開放架構(gòu),來分析RISC-V架構(gòu)的不同之處以及為什么其他開放架構(gòu)沒能取得足夠的成功。
0.1 平民英雄——OpenRISC
OpenRISC是OpenCores組織提供的基于GPL協(xié)議的開放源代碼RISC處理器。
OpenRISC具有以下特點(diǎn):
采用免費(fèi)開放的32/64位 RISC架構(gòu)。
用Verilog HDL(硬件描述語言)實(shí)現(xiàn)了基于該架構(gòu)的處理器源代碼。
具有完整的工具鏈。
OpenRISC被應(yīng)用到很多公司的項(xiàng)目之中??梢哉f,OpenRISC是應(yīng)用非常廣泛的一種開源處理器實(shí)現(xiàn)。
OpenRISC的不足之處在于其側(cè)重于實(shí)現(xiàn)一種開源的CPU Core,而非立足于定義一種開放的指令集架構(gòu),因此其架構(gòu)的發(fā)展不夠完整,指令集的定義也不具備上節(jié)中提到的RISC-V架構(gòu)的優(yōu)點(diǎn),更加沒有上升到成立專門的基金會(huì)組織的高度。OpenRISC更多的時(shí)候被認(rèn)為是一個(gè)開源的Core,而非一種優(yōu)美的指令集架構(gòu)。此外,OpenRISC的許可證為GPL,這意味著所有的指令集改動(dòng)都必須開源(而RISC-V則無此約束)。
0.2 豪門顯貴——SPARC
SPARC架構(gòu)作為經(jīng)典的RISC微處理器架構(gòu)之一,SPARC最早于1985年由Sun電腦所設(shè)計(jì)。SPARC也是SPARC國(guó)際公司的注冊(cè)商標(biāo)之一,這家公司于1989年成立,目的是向外界推廣SPARC架構(gòu)以及為該架構(gòu)進(jìn)行兼容性測(cè)試。該公司為了推廣SPARC的生態(tài)系統(tǒng),SPARC國(guó)際公司將標(biāo)準(zhǔn)開放,并授權(quán)予多家生產(chǎn)商采用,包括德州儀器、Cypress半導(dǎo)體和富士通等。由于SPARC架構(gòu)也對(duì)外完全開放,因此,也出現(xiàn)了完全開放源碼的LEON處理器。不僅如此,Sun公司還于1994年推動(dòng)SPARC v8架構(gòu)成為IEEE標(biāo)準(zhǔn)(IEEE Standard 1754-1994)。
由于SPARC架構(gòu)的初衷是面向服務(wù)器領(lǐng)域而設(shè)計(jì),其最大的特點(diǎn)是擁有一個(gè)大型的寄存器窗口,符合SPARC架構(gòu)的處理器需要實(shí)現(xiàn)從72到640個(gè)之多的通用寄存器,每個(gè)寄存器寬度為64bits,組成一系列的寄存器組,稱之為寄存器窗口。
這種寄存器窗口的架構(gòu),由于可以切換不同的寄存器組快速地響應(yīng)函數(shù)調(diào)用與返回,因此,能夠產(chǎn)生非常高的性能,但是這種架構(gòu)由于功耗面積代價(jià)太大,而并不適用于PC與嵌入式領(lǐng)域處理器。而SPARC架構(gòu)也不具備模塊化的特點(diǎn),使得用戶無法裁剪和選擇。很難作為一種通用的處理器架構(gòu)對(duì)商用的x86和ARM架構(gòu)形成替代。
設(shè)計(jì)這種超大服務(wù)器CPU芯片又非普通公司與個(gè)人所能涉足,而有能力設(shè)計(jì)這種大型CPU的公司也沒有必要投入巨大的成本來挑戰(zhàn)x86的統(tǒng)治地位。隨著Sun公司的衰弱,SPARC架構(gòu)現(xiàn)在基本上退出了人們的視野。感興趣的讀者請(qǐng)?jiān)诰W(wǎng)絡(luò)上自行搜索文章《再見SPARC處理器,再見Sun》
0.3 名校優(yōu)生——RISC-V
關(guān)于RISC-V在伯克利大學(xué)誕生的經(jīng)歷,本節(jié)在此不做重復(fù)贅述。
因?yàn)槎嗄陙碓贑PU領(lǐng)域已經(jīng)出現(xiàn)過多個(gè)免費(fèi)或開放的架構(gòu),很多高校也在科研項(xiàng)目中推出過多種指令集架構(gòu)。因此,當(dāng)筆者第一次聽說RISC-V之時(shí),以為又是一個(gè)玩具,或純粹學(xué)術(shù)性質(zhì)的科研項(xiàng)目而不以為意。
直到筆者親自通讀了一遍RISC-V的架構(gòu)文檔,不禁為其先進(jìn)的設(shè)計(jì)理念所折服。同時(shí),RISC-V架構(gòu)的各種優(yōu)點(diǎn)也得到了眾多專業(yè)人士的青睞好評(píng)和眾多商業(yè)公司的相繼加盟。并且2016年RISC-V基金會(huì)的正式啟動(dòng)在業(yè)界引起了不小的影響。如此種種,使得RISC-V成為至今為止最具備革命性意義的開放處理器架構(gòu)。
1 簡(jiǎn)單就是美——RISC-V架構(gòu)的設(shè)計(jì)哲學(xué)
RISC-V架構(gòu)作為一種指令集架構(gòu),在介紹細(xì)節(jié)之前,讓我們先了解設(shè)計(jì)的哲學(xué)。所謂設(shè)計(jì)的“哲學(xué)”便是其推崇的一種策略,譬如說我們熟知的日本車的設(shè)計(jì)哲學(xué)是經(jīng)濟(jì)省油,美國(guó)車的設(shè)計(jì)哲學(xué)是霸氣外漏等。RISC-V架構(gòu)的設(shè)計(jì)哲學(xué)是什么呢?是“大道至簡(jiǎn)”。
筆者最為推崇的一種設(shè)計(jì)原則便是:簡(jiǎn)單就是美,簡(jiǎn)單便意味著可靠。無數(shù)的實(shí)際案例已經(jīng)佐證了“簡(jiǎn)單即意味著可靠的”真理,反之越復(fù)雜的機(jī)器越則越容易出錯(cuò)。
所謂大道至簡(jiǎn),在IC設(shè)計(jì)的實(shí)際工作中,筆者曾見過最簡(jiǎn)潔的設(shè)計(jì)實(shí)現(xiàn)安全可靠,也曾見過最繁復(fù)的設(shè)計(jì)長(zhǎng)時(shí)間無法穩(wěn)定收斂。最簡(jiǎn)潔的設(shè)計(jì)往往是最可靠的,在大多數(shù)的項(xiàng)目實(shí)踐中一次次的得到檢驗(yàn)。
IC設(shè)計(jì)的工作性質(zhì)非常特殊,其最終的產(chǎn)出是芯片,而一款芯片的設(shè)計(jì)和制造周期均很長(zhǎng),無法像軟件代碼那樣輕易的升級(jí)和打補(bǔ)丁,每一次芯片的改版到交付都需要幾個(gè)月的周期。不僅如此,芯片的一次制造成本費(fèi)用高昂,從幾十萬美金到百千萬美金不等。這些特性都決定了IC設(shè)計(jì)的試錯(cuò)成本極為高昂,因此能夠有效的降低錯(cuò)誤的發(fā)生就顯得非常的重要。
現(xiàn)代的芯片設(shè)計(jì)規(guī)模越來越大,復(fù)雜度越來越高,并不是說要求設(shè)計(jì)者一味的逃避使用復(fù)雜的技術(shù),而是應(yīng)該將好鋼用在刀刃上,將最復(fù)雜的設(shè)計(jì)用在最為關(guān)鍵的場(chǎng)景,在大多數(shù)有選擇的情況下,盡量選擇簡(jiǎn)潔的實(shí)現(xiàn)方案。
筆者在第一次閱讀了RISC-V架構(gòu)文檔之時(shí),不禁擊節(jié)贊嘆,拍案驚奇,因?yàn)镽ISC-V架構(gòu)在其文檔中不斷地明確強(qiáng)調(diào),其設(shè)計(jì)哲學(xué)是“大道至簡(jiǎn)”,力圖通過架構(gòu)的定義使得硬件的實(shí)現(xiàn)足夠簡(jiǎn)單。其簡(jiǎn)單就是美的哲學(xué),可以從幾個(gè)方面容易看出,后續(xù)小節(jié)將一一加以論述。
1.1 無病一身輕——架構(gòu)的篇幅
在處理器領(lǐng)域,目前主流的架構(gòu)為x86與ARM架構(gòu),筆者曾經(jīng)參與設(shè)計(jì)ARM架構(gòu)的應(yīng)用處理器,因此需要閱讀ARM的架構(gòu)文檔,如果對(duì)其熟悉的讀者應(yīng)該了解其篇幅。經(jīng)過幾十年的發(fā)展,現(xiàn)代的x86與ARM架構(gòu)的架構(gòu)文檔長(zhǎng)達(dá)幾百數(shù)千頁(yè)。打印出來能有半個(gè)桌子高,可真是“著作等身”。
之所以現(xiàn)代x86與ARM架構(gòu)的文檔長(zhǎng)達(dá)數(shù)千頁(yè),且版本眾多,一個(gè)主要的原因是因?yàn)槠浼軜?gòu)的發(fā)展的過程也伴隨了現(xiàn)代處理器架構(gòu)技術(shù)的不斷發(fā)展成熟。
并且作為商用的架構(gòu),為了能夠保持架構(gòu)的向后兼容性,其不得不保留許多過時(shí)的定義,或者在定義新的架構(gòu)部分時(shí)為了能夠?qū)⒕鸵呀?jīng)存在的技術(shù)部分而顯得非常的別扭。久而久之就變得極為冗長(zhǎng)。
那么現(xiàn)代成熟的架構(gòu)是否能夠選擇重新開始,重新定義一個(gè)簡(jiǎn)潔的架構(gòu)呢,可以說是幾乎不可能。其中一個(gè)重要的原因便是其無法向前兼容,從而無法得到用戶的接受。試想一下如果我們買了一款新的搭配新的處理器的電腦或者手機(jī)回家,之前所有的軟件都無法運(yùn)行而變磚,那肯定是無法讓人接受的。
而現(xiàn)在才推出的RISC-V架構(gòu),則具備了后發(fā)優(yōu)勢(shì),由于計(jì)算機(jī)體系結(jié)構(gòu)經(jīng)過多年的發(fā)展已經(jīng)成為比較成熟的技術(shù),多年來在不斷成熟的過程中暴露的問題都已經(jīng)被研究透徹,因此新的RISC-V架構(gòu)能夠加以規(guī)避,并且沒有背負(fù)向后兼容的歷史包袱,可以說是無病一身輕。
目前的“RISC-V架構(gòu)文檔”分為“指令集文檔”(riscv-spec-v2.2.pdf)和“特權(quán)架構(gòu)文檔”(riscv-privileged-v1.10.pdf)。“指令集文檔”的篇幅為145頁(yè),而“特權(quán)架構(gòu)文檔”的篇幅也僅為91頁(yè)。熟悉體系結(jié)構(gòu)的工程師僅需一至兩天便可將其通讀,雖然“RISC-V的架構(gòu)文檔”還在不斷地豐富,但是相比“x86的架構(gòu)文檔”與“ARM的架構(gòu)文檔”,RISC-V的篇幅可以說是極其短小精悍。
感興趣的讀者可以在RISC-V基金會(huì)的網(wǎng)站上(https://riscv.org/specifications/)無需注冊(cè)便可免費(fèi)下載其文檔,如圖1所示。
圖1 RISC-V基金會(huì)網(wǎng)站上的架構(gòu)文檔
1.2 能屈能伸——模塊化的指令集
RISC-V架構(gòu)相比其他成熟的商業(yè)架構(gòu)的最大一個(gè)不同還在于它是一個(gè)模塊化的架構(gòu)。因此,RISC-V架構(gòu)不僅短小精悍,而且其不同的部分還能以模塊化的方式組織在一起,從而試圖通過一套統(tǒng)一的架構(gòu)滿足各種不同的應(yīng)用。
這種模塊化是x86與ARM架構(gòu)所不具備的。以ARM的架構(gòu)為例,ARM的架構(gòu)分為A、R和M三個(gè)系列,分別針對(duì)于Application(應(yīng)用操作系統(tǒng))、Real-Time(實(shí)時(shí))和Embedded(嵌入式)三個(gè)領(lǐng)域,彼此之間并不兼容。
但是模塊化的RISC-V架構(gòu)能夠使得用戶能夠靈活選擇不同的模塊組合,以滿足不同的應(yīng)用場(chǎng)景,可以說是“老少咸宜”。譬如針對(duì)于小面積低功耗嵌入式場(chǎng)景,用戶可以選擇RV32IC組合的指令集,僅使用Machine Mode(機(jī)器模式);而高性能應(yīng)用操作系統(tǒng)場(chǎng)景則可以選擇譬如RV32IMFDC的指令集,使用Machine Mode(機(jī)器模式)與User Mode(用戶模式)兩種模式。而他們共同的部分則可以相互兼容。
1.3 濃縮的都是精華——指令的數(shù)量
短小精悍的架構(gòu)以及模塊化的哲學(xué),使得RISC-V架構(gòu)的指令數(shù)目非常的簡(jiǎn)潔。基本的RISC-V指令數(shù)目?jī)H有40多條,加上其他的模塊化擴(kuò)展指令總共幾十條指令。
2 RISC-V指令集架構(gòu)簡(jiǎn)介
本章將對(duì)RISC-V的指令集架構(gòu)多方面的特性進(jìn)行簡(jiǎn)要介紹。
2.1 模塊化的指令子集
RISC-V的指令集使用模塊化的方式進(jìn)行組織,每一個(gè)模塊使用一個(gè)英文字母來表示。RISC-V最基本也是唯一強(qiáng)制要求實(shí)現(xiàn)的指令集部分是由I字母表示的基本整數(shù)指令子集,使用該整數(shù)指令子集,便能夠?qū)崿F(xiàn)完整的軟件編譯器。其他的指令子集部分均為可選的模塊,具有代表性的模塊包括M/A/F/D/C,如表1所示。
表1 RISC-V的模塊化指令集
為了提高代碼密度,RISC-V架構(gòu)也提供可選的“壓縮”指令子集,由英文字母C表示。壓縮指令的指令編碼長(zhǎng)度為16比特,而普通的非壓縮指令的長(zhǎng)度為32比特。以上這些模塊的一個(gè)特定組合“IMAFD”,也被稱為“通用”組合,由英文字母G表示。因此RV32G表示RV32IMAFD,同理RV64G表示RV64IMAFD。
為了進(jìn)一步減少面積,RISC-V架構(gòu)還提供一種“嵌入式”架構(gòu),由英文字母E表示。該架構(gòu)主要用于追求極低面積與功耗的深嵌入式場(chǎng)景。該架構(gòu)僅需要支持16個(gè)通用整數(shù)寄存器,而非嵌入式的普通架構(gòu)則需要支持32個(gè)通用整數(shù)寄存器。
通過以上的模塊化指令集,能夠選擇不同的組合來滿足不同的應(yīng)用。譬如,追求小面積低功耗的嵌入式場(chǎng)景可以選擇使用RV32EC架構(gòu);而大型的64位架構(gòu)則可以選擇RV64G。
除了上述的模塊,還有若干的模塊包括L、B、P、V和T等。這些擴(kuò)展目前大多數(shù)還在不斷完善和定義中,尚未最終確定,因此本文在此不做詳細(xì)論述。
2.2 可配置的通用寄存器組
RISC-V架構(gòu)支持32位或者64位的架構(gòu),32位架構(gòu)由RV32表示,其每個(gè)通用寄存器的寬度為32比特;64位架構(gòu)由RV64表示,其每個(gè)通用寄存器的寬度為64比特。
RISC-V架構(gòu)的整數(shù)通用寄存器組,包含32個(gè)(I架構(gòu))或者16個(gè)(E架構(gòu))通用整數(shù)寄存器,其中整數(shù)寄存器0被預(yù)留為常數(shù)0,其他的31個(gè)(I架構(gòu))或者15個(gè)(E架構(gòu))為普通的通用整數(shù)寄存器。
如果使用了浮點(diǎn)模塊(F或者D),則需要另外一個(gè)獨(dú)立的浮點(diǎn)寄存器組,包含32個(gè)通用浮點(diǎn)寄存器。如果僅使用F模塊的浮點(diǎn)指令子集,則每個(gè)通用浮點(diǎn)寄存器的寬度為32比特;如果使用了D模塊的浮點(diǎn)指令子集,則每個(gè)通用浮點(diǎn)寄存器的寬度為64比特。
2.3 規(guī)整的指令編碼
在流水線中能夠盡早盡快的讀取通用寄存器組,往往是處理器流水線設(shè)計(jì)的期望之一,這樣可以提高處理器性能和優(yōu)化時(shí)序。這個(gè)看似簡(jiǎn)單的道理在很多現(xiàn)存的商用RISC架構(gòu)中都難以實(shí)現(xiàn),因?yàn)榻?jīng)過多年反復(fù)修改不斷添加新指令后,其指令編碼中的寄存器索引位置變得非常的凌亂,給譯碼器造成了負(fù)擔(dān)。
得益于后發(fā)優(yōu)勢(shì)和總結(jié)了多年來處理器發(fā)展的教訓(xùn),RISC-V的指令集編碼非常的規(guī)整,指令所需的通用寄存器的索引(Index)都被放在固定的位置,如圖2所示。因此指令譯碼器(Instruction Decoder)可以非常便捷的譯碼出寄存器索引然后讀取通用寄存器組(Register File,Regfile)。
圖2 RV32I規(guī)整的指令編碼格式
2.4 簡(jiǎn)潔的存儲(chǔ)器訪問指令
與所有的RISC處理器架構(gòu)一樣,RISC-V架構(gòu)使用專用的存儲(chǔ)器讀(Load)指令和存儲(chǔ)器寫(Store)指令訪問存儲(chǔ)器(Memory),其他的普通指令無法訪問存儲(chǔ)器,這種架構(gòu)是RISC架構(gòu)的常用的一個(gè)基本策略,這種策略使得處理器核的硬件設(shè)計(jì)變得簡(jiǎn)單。
存儲(chǔ)器訪問的基本單位是字節(jié)(Byte)。RISC-V的存儲(chǔ)器讀和存儲(chǔ)器寫指令支持一個(gè)字節(jié)(8位),半字(16位),單字(32位)為單位的存儲(chǔ)器讀寫操作,如果是64位架構(gòu)還可以支持一個(gè)雙字(64位)為單位的存儲(chǔ)器讀寫操作。
RISC-V架構(gòu)的存儲(chǔ)器訪問指令還有如下顯著特點(diǎn):
為了提高存儲(chǔ)器讀寫的性能,RISC-V架構(gòu)推薦使用地址對(duì)齊的存儲(chǔ)器讀寫操作,但是地址非對(duì)齊的存儲(chǔ)器操作RISC-V架構(gòu)也支持,處理器可以選擇用硬件來支持,也可以選擇用軟件來支持。
由于現(xiàn)在的主流應(yīng)用是小端格式(Little-Endian),RISC-V架構(gòu)僅支持小端格式。有關(guān)小端格式和大端格式的定義和區(qū)別,本文在此不做過多介紹,若對(duì)此不甚了解的初學(xué)者可以自行查閱學(xué)習(xí)。
很多的RISC處理器都支持地址自增或者自減模式,這種自增或者自減的模式雖然能夠提高處理器訪問連續(xù)存儲(chǔ)器地址區(qū)間的性能,但是也增加了設(shè)計(jì)處理器的難度。RISC-V架構(gòu)的存儲(chǔ)器讀和存儲(chǔ)器寫指令不支持地址自增自減的模式。
RISC-V架構(gòu)采用松散存儲(chǔ)器模型(Relaxed Memory Model),松散存儲(chǔ)器模型對(duì)于訪問不同地址的存儲(chǔ)器讀寫指令的執(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)量處理器則可以通過復(fù)雜設(shè)計(jì)的動(dòng)態(tài)硬件調(diào)度能力來提高性能。
2.5 高效的分支跳轉(zhuǎn)指令
RISC-V架構(gòu)有兩條無條件跳轉(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指令能夠用于子程序返回指令,通過將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)行比較,如果比較的條件滿足時(shí),則進(jìn)行跳轉(zhuǎn)。因此,此類指令將比較與跳轉(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ì)于沒有配備硬件分支預(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ī)制來編譯生成匯編代碼,從而讓低端的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來判斷其是正數(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ī)制來保證性能。
2.6 簡(jiǎn)潔的子程序調(diào)用
為了理解此節(jié),需先對(duì)一般RISC架構(gòu)中程序調(diào)用子函數(shù)的過程予以介紹,其過程如下:
進(jìn)入子函數(shù)之后需要用存儲(chǔ)器寫(Store)指令來將當(dāng)前的上下文(通用寄存器等的值)保存到系統(tǒng)存儲(chǔ)器的堆棧區(qū)內(nèi),這個(gè)過程通常稱為“保存現(xiàn)場(chǎng)”。
在退出子程序之時(shí),需要用存儲(chǔ)器讀(Load)指令來將之前保存的上下文(通用寄存器等的值)從系統(tǒng)存儲(chǔ)器的堆棧區(qū)讀出來,這個(gè)過程通常稱為“恢復(fù)現(xiàn)場(chǎng)”。
“保存現(xiàn)場(chǎng)”和“恢復(fù)現(xiàn)場(chǎng)”的過程通常由編譯器編譯生成的指令來完成,使用高層語言(譬如C或者C++)開發(fā)的開發(fā)者對(duì)此可以不用太關(guān)心。高層語言的程序中直接寫上一個(gè)子函數(shù)調(diào)用即可,但是這個(gè)底層發(fā)生的“保存現(xiàn)場(chǎng)”和“恢復(fù)現(xiàn)場(chǎng)”的過程卻是實(shí)實(shí)在在地發(fā)生著(可以從編譯出的匯編語言里面看到那些“保存現(xiàn)場(chǎng)”和“恢復(fù)現(xiàn)場(chǎng)”的匯編指令),并且還需要消耗若干的CPU執(zhí)行時(shí)間。
為了加速這個(gè)“保存現(xiàn)場(chǎng)”和“恢復(fù)現(xiàn)場(chǎng)”的過程,有的RISC架構(gòu)發(fā)明了一次寫多個(gè)寄存器到存儲(chǔ)器中(Store Multiple),或者一次從存儲(chǔ)器中讀多個(gè)寄存器出來(Load Multiple)的指令,此類指令的好處是一條指令就可以完成很多事情,從而減少匯編指令的代碼量,節(jié)省代碼的空間大小。但是此種“Load Multiple”和“Store Multiple”的弊端是會(huì)讓CPU的硬件設(shè)計(jì)變得復(fù)雜,增加硬件的開銷,也可能損傷時(shí)序使得CPU的主頻無法提高,筆者在曾經(jīng)設(shè)計(jì)此類處理器時(shí)便深受其苦。
RISC-V架構(gòu)則放棄使用這種“Load Multiple”和“Store Multiple”指令。并解釋,如果有的場(chǎng)合比較介意這種“保存現(xiàn)場(chǎng)”和“恢復(fù)現(xiàn)場(chǎng)”的指令條數(shù),那么可以使用公用的程序庫(kù)(專門用于保存和恢復(fù)現(xiàn)場(chǎng))來進(jìn)行,這樣就可以省掉在每個(gè)子函數(shù)調(diào)用的過程中都放置數(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ù)(專門用于保存和恢復(fù)現(xiàn)場(chǎng))的方式減少代碼量,但是同時(shí)達(dá)到高性能。
2.7 無條件碼執(zhí)行
很多早期的RISC架構(gòu)發(fā)明了帶條件碼的指令,譬如在指令編碼的頭幾位表示的是條件碼(Conditional Code),只有該條件碼對(duì)應(yīng)的條件為真時(shí),該指令才被真正執(zhí)行。
這種將條件碼編碼到指令中的形式可以使得編譯器將短小的循環(huán)編譯成帶條件碼的指令,而不用編譯成分支跳轉(zhuǎn)指令。這樣便減少了分支跳轉(zhuǎn)的出現(xiàn),一方面減少了指令的數(shù)目;另一方面也避免了分支跳轉(zhuǎn)帶來的性能損失。然而,這種“條件碼”指令的弊端同樣會(huì)使得CPU的硬件設(shè)計(jì)變得復(fù)雜,增加硬件的開銷,也可能損傷時(shí)序使得CPU的主頻無法提高,筆者在曾經(jīng)設(shè)計(jì)此類處理器時(shí)便深受其苦。
RISC-V架構(gòu)則放棄使用這種帶“條件碼”指令的方式,對(duì)于任何的條件判斷都使用普通的帶條件分支跳轉(zhuǎn)指令。此選擇再次印證了RISC-V追求硬件簡(jiǎn)單的哲學(xué),因?yàn)榉艞墡А皸l件碼”指令的方式可以大幅簡(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í)行達(dá)到高性能。
2.8 無分支延遲槽
很多早期的RISC架構(gòu)均使用了“分支延遲槽(Delay Slot)”,最具有代表性的便是MIPS架構(gòu),在很多經(jīng)典的計(jì)算機(jī)體系結(jié)構(gòu)教材中,均使用MIPS對(duì)分支延遲槽進(jìn)行過介紹。分支延遲槽就是指在每一條分支指令后面緊跟的一條或者若干條指令不受分支跳轉(zhuǎn)的影響,不管分支是否跳轉(zhuǎn),這后面的幾條指令都一定會(huì)被執(zhí)行。
早期的RISC架構(gòu)很多采用了分支延遲槽誕生的原因主要是因?yàn)楫?dāng)時(shí)的處理器流水線比較簡(jiǎn)單,沒有使用高級(jí)的硬件動(dòng)態(tài)分支預(yù)測(cè)器,所以使用分支延遲槽能夠取得可觀的性能效果。然而,這種分支延遲槽使得CPU的硬件設(shè)計(jì)變得極為的別扭,CPU設(shè)計(jì)人員對(duì)此往往苦不堪言。
RISC-V架構(gòu)則放棄了分支延遲槽,再次印證了RISC-V力圖簡(jiǎn)化硬件的哲學(xué),因?yàn)楝F(xiàn)代的高性能處理器的分支預(yù)測(cè)算法精度已經(jīng)非常高,可以有強(qiáng)大的分支預(yù)測(cè)電路保證CPU能夠準(zhǔn)確的預(yù)測(cè)跳轉(zhuǎn)執(zhí)行達(dá)到高性能。而對(duì)于低功耗小面積的CPU,由于無需支持分支延遲槽,硬件得到極大簡(jiǎn)化,也能進(jìn)一步減少功耗和提高時(shí)序。
2.9 無零開銷硬件循環(huán)
很多RISC架構(gòu)還支持零開銷硬件循環(huán)(Zero Overhead Hardware Loop)指令,其思想是通過硬件的直接參與,通過設(shè)置某些循環(huán)次數(shù)寄存器(Loop Count),然后可以讓程序自動(dòng)地進(jìn)行循環(huán),每一次循環(huán)則Loop Count自動(dòng)減1,這樣持續(xù)循環(huán)直到Loop Count的值變成0,則退出循環(huán)。
之所以提出發(fā)明這種硬件協(xié)助的零開銷循環(huán)是因?yàn)樵谲浖a中的for 循環(huán)(for i=0; i
然有得必有失,此類零開銷硬件循環(huán)指令大幅地增加了硬件設(shè)計(jì)的復(fù)雜度。因此,零開銷循環(huán)指令與RISC-V架構(gòu)簡(jiǎn)化硬件的哲學(xué)是完全相反的,在RISC-V架構(gòu)中自然沒有使用此類零開銷硬件循環(huán)指令。
2.10 簡(jiǎn)潔的運(yùn)算指令
在本章第2.1節(jié)中曾經(jīng)提到RISC-V架構(gòu)使用模塊化的方式組織不同的指令子集,最基本的整數(shù)指令子集(I字母表示)支持的運(yùn)算包括加法、減法、移位、按位邏輯操作和比較操作。這些基本的運(yùn)算操作能夠通過組合或者函數(shù)庫(kù)的方式完成更多的復(fù)雜操作(譬如乘除法和浮點(diǎn)操作),從而能夠完成大多數(shù)的軟件操作。
整數(shù)乘除法指令子集(M字母表示)支持的運(yùn)算包括,有符號(hào)或者無符號(hào)的乘法和除法操作。乘法操作能夠支持兩個(gè)32位的整數(shù)相乘得到一個(gè)64位的結(jié)果;除法操作能夠支持兩個(gè)32位的整數(shù)相除得到一個(gè)32位的商與32位的余數(shù)。
單精度浮點(diǎn)指令子集(F字母表示)與雙精度浮點(diǎn)指令子集(D字母表示)支持的運(yùn)算包括浮點(diǎn)加減法,乘除法,乘累加,開平方根和比較等操作,同時(shí)提供整數(shù)與浮點(diǎn),單精度與雙精度浮點(diǎn)彼此之間的格式轉(zhuǎn)換操作。
很多RISC架構(gòu)的處理器在運(yùn)算指令產(chǎn)生錯(cuò)誤之時(shí),譬如上溢(Overflow)、下溢(Underflow)、非規(guī)格化浮點(diǎn)數(shù)(Subnormal)和除零(Divide by Zero),都會(huì)產(chǎn)生軟件異常。RISC-V架構(gòu)的一個(gè)特殊之處是對(duì)任何的運(yùn)算指令錯(cuò)誤(包括整數(shù)與浮點(diǎn)指令)均不產(chǎn)生異常,而是產(chǎn)生某個(gè)特殊的默認(rèn)值,同時(shí),設(shè)置某些狀態(tài)寄存器的狀態(tài)位。RISC-V架構(gòu)推薦軟件通過其他方法來找到這些錯(cuò)誤。再次清楚地反映了RISC-V架構(gòu)力圖簡(jiǎn)化基本的指令集,從而簡(jiǎn)化硬件設(shè)計(jì)的哲學(xué)。
2.11 優(yōu)雅的壓縮指令子集
基本的RISC-V基本整數(shù)指令子集(字母I表示 )規(guī)定的指令長(zhǎng)度均為等長(zhǎng)的32位,這種等長(zhǎng)指令定義使得僅支持整數(shù)指令子集的基本RISC-V CPU非常容易設(shè)計(jì)。但是等長(zhǎng)的32位編碼指令也會(huì)造成代碼體積(Code Size)相對(duì)較大的問題。
為了滿足某些對(duì)于代碼體積要求較高的場(chǎng)景(譬如嵌入式領(lǐng)域),RISC-V定義了一種可選的壓縮(Compressed)指令子集,由字母C表示,也可以由RVC表示。RISC-V具有后發(fā)優(yōu)勢(shì),從一開始便規(guī)劃了壓縮指令,預(yù)留了足夠的編碼空間,16位長(zhǎng)指令與普通的32位長(zhǎng)指令可以無縫自由地交織在一起,處理器也沒有定義額外的狀態(tài)。
RISC-V壓縮指令的另外一個(gè)特別之處是,16位指令的壓縮策略是將一部分普通最常用的的32位指令中的信息進(jìn)行壓縮重排得到(譬如假設(shè)一條指令使用了兩個(gè)同樣的操作數(shù)索引,則可以省去其中一個(gè)索引的編碼空間),因此每一條16位長(zhǎng)的指令都能一一找到其對(duì)應(yīng)的原始32位指令。因此,程序編譯成為壓縮指令僅在匯編器階段就可以完成,極大的簡(jiǎn)化了編譯器工具鏈的負(fù)擔(dān)。
RISC-V架構(gòu)的研究者進(jìn)行了詳細(xì)的代碼體積分析,如圖3所示,通過分析結(jié)果可以看出,RV32C的代碼體積相比RV32的代碼體積減少了百分之四十,并且與ARM,MIPS和x86等架構(gòu)相比都有不錯(cuò)的表現(xiàn)。
圖3 各指令集架構(gòu)的代碼密度比較(數(shù)據(jù)越小越好)
2.12 特權(quán)模式
RISC-V架構(gòu)定義了三種工作模式,又稱特權(quán)模式(Privileged Mode):
Machine Mode:機(jī)器模式,簡(jiǎn)稱M Mode。
Supervisor Mode:監(jiān)督模式,簡(jiǎn)稱S Mode。
User Mode:用戶模式,簡(jiǎn)稱U Mode。
RISC-V架構(gòu)定義M Mode為必選模式,另外兩種為可選模式。通過不同的模式組合可以實(shí)現(xiàn)不同的系統(tǒng)。
RISC-V架構(gòu)也支持幾種不同的存儲(chǔ)器地址管理機(jī)制,包括對(duì)于物理地址和虛擬地址的管理機(jī)制,使得RISC-V架構(gòu)能夠支持從簡(jiǎn)單的嵌入式系統(tǒng)(直接操作物理地址)到復(fù)雜的操作系統(tǒng)(直接操作虛擬地址)的各種系統(tǒng)。
2.13 CSR寄存器
RISC-V架構(gòu)定義了一些控制和狀態(tài)寄存器(Control and Status Register,CSR),用于配置或記錄一些運(yùn)行的狀態(tài)。CSR寄存器是處理器核內(nèi)部的寄存器,使用其自己的地址編碼空間和存儲(chǔ)器尋址的地址區(qū)間完全無關(guān)系。
CSR寄存器的訪問采用專用的CSR指令,包括CSRRW、CSRRS、CSRRC、CSRRWI、CSRRSI以及CSRRCI指令。
2.14 中斷和異常
中斷和異常機(jī)制往往是處理器指令集架構(gòu)中最為復(fù)雜而關(guān)鍵的部分。RISC-V架構(gòu)定義了一套相對(duì)簡(jiǎn)單基本的中斷和異常機(jī)制,但是也允許用戶對(duì)其進(jìn)行定制和擴(kuò)展。
2.15 矢量指令子集
RISC-V架構(gòu)目前雖然還沒有定型矢量(Vector)指令子集,但是從目前的草案中已經(jīng)可以看出,RISC-V矢量指令子集的設(shè)計(jì)理念非常的先進(jìn),由于后發(fā)優(yōu)勢(shì)及借助矢量架構(gòu)多年發(fā)展成熟的結(jié)論,RISC-V架構(gòu)將使用可變長(zhǎng)度的矢量,而不是矢量定長(zhǎng)的SIMD指令集(譬如ARM的NEON和Intel的MMX),從而能夠靈活的支持不同的實(shí)現(xiàn)。追求低功耗小面積的CPU可以選擇使用長(zhǎng)度較短的硬件矢量進(jìn)行實(shí)現(xiàn),而高性能的CPU則可以選擇較長(zhǎng)的硬件矢量進(jìn)行實(shí)現(xiàn),并且同樣的軟件代碼能夠彼此兼容。
2.16 自定制指令擴(kuò)展
除了上述闡述的模塊化指令子集的可擴(kuò)展、可選擇,RISC-V架構(gòu)還有一個(gè)非常重要的特性,那就是支持第三方的擴(kuò)展。用戶可以擴(kuò)展自己的指令子集,RISC-V預(yù)留了大量的指令編碼空間用于用戶的自定義擴(kuò)展,同時(shí),還定義了四條Custom指令可供用戶直接使用,每條Custom指令都有幾個(gè)比特位的子編碼空間預(yù)留,因此,用戶可以直接使用四條Custom指令擴(kuò)展出幾十條自定義的指令。
2.17 總結(jié)與比較
處理器設(shè)計(jì)技術(shù)經(jīng)過幾十年的衍進(jìn),隨著大規(guī)模集成電路設(shè)計(jì)技術(shù)的發(fā)展直至今天,呈現(xiàn)出如下特點(diǎn):
由于高性能處理器的硬件調(diào)度能力已經(jīng)非常強(qiáng)勁且主頻很高,因此,硬件設(shè)計(jì)希望指令集盡可能的規(guī)整、簡(jiǎn)單,從而,使得處理器可以設(shè)計(jì)出更高的主頻與更低的面積。
以IoT應(yīng)用為主的極低功耗處理器更加苛求低功耗與低面積。
存儲(chǔ)器的資源也比早期的RISC處理器更加豐富。
如上種種這些因素,使得很多早期的RISC架構(gòu)設(shè)計(jì)理念(依據(jù)當(dāng)時(shí)技術(shù)背景而誕生),時(shí)至今日不僅不能幫助現(xiàn)代處理器設(shè)計(jì),反而成了負(fù)擔(dān)桎梏。某些早期RISC架構(gòu)定義的特性,一方面使得高性能處理器的硬件設(shè)計(jì)束手束腳;另一方面又使得極低功耗的處理器硬件設(shè)計(jì)背負(fù)不必要的復(fù)雜度。
得益于后發(fā)優(yōu)勢(shì),全新的RISC-V架構(gòu)能夠規(guī)避所有這些已知的負(fù)擔(dān),同時(shí),利用其先進(jìn)的設(shè)計(jì)哲學(xué),設(shè)計(jì)出一套“現(xiàn)代”的指令集。本節(jié)再次將其特點(diǎn)總結(jié)如表2所示。
表2 RISC-V指令集架構(gòu)特點(diǎn)總結(jié)