2_指令集、体系架构、微架构
指令集、體系架構(gòu)、微架構(gòu) [轉(zhuǎn)]
轉(zhuǎn)載自《操作系統(tǒng)真相還原》
指令集是什么?表面上看它是一套指令的集合。集合的意思顯而易見,那咱們說說什么是指令。
在計(jì)算機(jī)中,CPU只能識(shí)別0、1這兩個(gè)數(shù),甚至它都不知道數(shù)是什么,它只知道要么“是”,要么“不是”,恰好用0、1來表示這兩種狀態(tài)而已。
人發(fā)明的東西逃不出人的思維,所以,先看看我們?nèi)祟惖恼Z言是怎么回事。
不同的語言對(duì)同一種事物有不同的名字,這個(gè)名字其實(shí)就是代碼。比如說人類的好朋友:狗,咱們?cè)谥形睦锓Q之為狗,但在英文中它被稱為dog,雖然用了兩種語言,但其描述的都是這種會(huì)汪汪叫、對(duì)人類無比忠誠的動(dòng)物。人是怎樣識(shí)別小狗的呢?識(shí)別信息來自聽覺、視覺等,這是因?yàn)槿颂焐邆涮幚砺曇艉蛨D像的能力,能夠識(shí)別出各種不同的聲音和顏色不同的圖像。可是計(jì)算機(jī)只能處理0、1這兩個(gè)數(shù),所以讓計(jì)算機(jī)識(shí)別某個(gè)事物,只有用01這兩個(gè)數(shù)來定義。也就是說,要用0、1來為各種事物編碼。
為了更好地說明指令集,咱們這里不再用現(xiàn)有的語言舉例子,當(dāng)然也不是要自創(chuàng)指令集。下面舉個(gè)簡單的例子來演示指令集的模型。
咱們拿表達(dá)式A=B+C 為例。假設(shè)A 、B 、C 都是內(nèi)存變量的值,它們的地址分別是Ox3000 、Ox3004 、Ox3008 。在此用Ra 表示寄存器A, Rb 表示寄存器B, Re 表示寄存器c.
完成這個(gè)加法的步驟是先將B 和C 載入到Ra 和Rb 寄存器中,再將兩個(gè)寄存器的值相加后送入寄存器Ra,之后再將寄存器Ra 的值寫入到地址為Ox3000 的內(nèi)存中。
步驟有了,咱們?cè)僭O(shè)計(jì)完成這些步驟的指令。
步驟1 :將內(nèi)存中的數(shù)據(jù)載入到寄存器,咱們假設(shè)它的指令名為load 。?
步驟2:兩個(gè)寄存器的加法指令,假設(shè)指令名為add。
步驟3 :將寄存器中的內(nèi)容存儲(chǔ)到內(nèi)存,假設(shè)指令名為store。
以上指令名都是假設(shè)的,名字可以任意取,因?yàn)镃PU 不識(shí)別指令名。指令名是編譯器用來給人看的,為的是方便人來編程, CPU 它只認(rèn)編碼。目前CPU 中的指令,無論是哪種指令集,都由操作碼和操作數(shù)兩部分組成(有些指令即使指令格式中沒有列出操作數(shù),也會(huì)有隱含的操作數(shù))。咱們也采用這種操作碼+操作數(shù)的思路,分別為這兩部分編碼。
咱們先為操作碼設(shè)計(jì)編碼。
接下來為操作數(shù)編碼,操作數(shù)一般是立即數(shù)、寄存器、內(nèi)存等,咱們這里主要是為寄存器編碼。
好啦,操作碼和操作數(shù)都有了,其實(shí)指令集己經(jīng)完成了。不過在一長串的二進(jìn)制01 中,哪些是操作碼,哪些是操作數(shù)呢?這就是指令格式的由來啦。我們?nèi)藶橐?guī)定個(gè)格式,規(guī)定操作碼和操作數(shù)的大小及位置,然后在CPU 硬件電路中寫死這些規(guī)則,讓CPU 在硬件一級(jí)上識(shí)別這些格式,從而能識(shí)別出操作碼和操作數(shù)。
假設(shè)我們的指令格式最大支持三個(gè)寄存器參數(shù)和一個(gè)立即數(shù)參數(shù)。其中操作碼和各寄存器操作數(shù)各占1字節(jié),立即數(shù)部分占4 字節(jié)。各條指令并不是完全按照此格式填充,不同的指令有不同的參數(shù),只有操作碼部分是固定的,其他操作數(shù)部分是可選的。當(dāng)CPU 在譯碼階段識(shí)別出操作碼后,CPU自然知道該指令需要什么樣的操作數(shù),這是寫死在硬件電路中的,所以不同的指令其機(jī)器碼長度很可能不一致。
為了演示指令集模型,我們?cè)谏厦婕僭O(shè)了寄存器名、指令名、格式。按理說這對(duì)于指令集來說已經(jīng)全了,不過,為方便咱們了解編譯器,不如咱們?cè)偌僭O(shè)個(gè)指令的語法吧,咱們這里學(xué)習(xí)Intel 的語法格式:“指令目的操作數(shù),源操作數(shù)飛目的操作數(shù)在左,源操作數(shù)在右,此賦值順序比較直觀。Intel 想表達(dá)的是a=b這種語序,如a=b ,便是mov a, b。
以上三個(gè)步驟的機(jī)器碼按照十六進(jìn)制表示為:
以上自定義的指令便是按照咱們假設(shè)的語法來生成的。對(duì)于機(jī)器碼的大小,由于指令不同,需要的操作數(shù)也不同,所以機(jī)器碼大小也不同。另外,機(jī)器碼中的立即數(shù)是按照x86 架構(gòu)的小端字節(jié)序?qū)懙?#xff0c;這一點(diǎn)大家要注意。小端字節(jié)序是數(shù)值中的低位在低地址,高位在高地址,數(shù)位以字節(jié)為單位。
步驟2 的機(jī)器碼為01000110。操作碼占1 字節(jié), CPU 識(shí)別出第1 字節(jié)的二進(jìn)制01 是add 指令,知道此指令的操作數(shù)是3 個(gè)寄存器,并且第1 個(gè)寄存器操作數(shù)是目的寄存器,另外兩個(gè)寄存器是源操作數(shù)(這都是我們假定的,并且是寫死在硬件中的規(guī)則,不同的指令有不同的規(guī)則,您也可以創(chuàng)造出內(nèi)存和寄存器混合作為操作數(shù)的加法指令)。于是到第2 宇節(jié)去讀取寄存器編碼,發(fā)現(xiàn)其值為二進(jìn)制00 ,就是寄存器Ra 對(duì)應(yīng)的編碼。接著到下一個(gè)字節(jié)處繼續(xù)讀出寄存器編碼,發(fā)現(xiàn)是二進(jìn)制01 ,也就是寄存器Rb, Re 同理。于是將寄存器Rb 和Re 的值相加后存入到寄存器b。
步驟3 中,機(jī)器碼為10 00 0c300000, CPU 讀取機(jī)器碼的第1 字節(jié)發(fā)現(xiàn)其為二進(jìn)制10 ,知道其為指令store,于是便確定了,目的操作數(shù)是個(gè)立即數(shù)形式的內(nèi)存地址,源操作數(shù)是個(gè)寄存器。接著到指令格式中的寄存器操作數(shù)1 的位置去讀取寄存器編碼,發(fā)現(xiàn)其值為00 ,這就是寄存器Ra 的編碼。機(jī)器碼中剩下的部分便作為立即數(shù),這樣便將寄存器Ra 的值寫入到內(nèi)存0x0000300c 中了。
以上指令集的模型,確實(shí)太過于簡單了,也許稱之為模型都非常勉強(qiáng)。現(xiàn)實(shí)中的指令格式要遠(yuǎn)遠(yuǎn)復(fù)雜得多。下面我們看看目前世面上的指令集有哪些。
最早的指令集是CISC (Complex Instruction Set Computer ),意為復(fù)雜指令集計(jì)算機(jī)。從名字上看,這套指令集相當(dāng)復(fù)雜,當(dāng)初這套指令集問世的時(shí)候,它的研發(fā)者們都沒想過要給它起名,只是因?yàn)楹髞沓霈F(xiàn)了相對(duì)精簡高效的指令集,所以人們?yōu)榱思右詤^(qū)分,才將最初的這套相對(duì)復(fù)雜的指令集命名為CISC ,而后來精簡高效的指令集稱為RISC (Reduced Instruction Set Computer )。
CISC 和RISC 并不是具體的指令集,而是兩種不同的指令體系,相當(dāng)于指令集中的門派,是指令的設(shè)計(jì)思想。舉個(gè)例子,就像中醫(yī)與西醫(yī),中醫(yī)講究從整體上調(diào)理身體,西醫(yī)則更多的是偏向局部。這就是兩種不同的醫(yī)療思路,類似于CISC 和陽SC 這兩種指令體系。那什么是指令集呢?拿中醫(yī)舉例,像華倫、張仲景這兩位醫(yī)圣,他們雖然都是基于中醫(yī)的思想治病,但醫(yī)術(shù)各有特色,水平也不盡相同,這就相當(dāng)于不同的指令集。一會(huì)兒咱們會(huì)介紹具體的指令集。
為什么說CISC 復(fù)雜呢?
首先,因?yàn)樗亲钤绲闹噶罴?#xff0c;當(dāng)初都是摸著石頭過河,肯定有一些瑕疵在里面。其次,當(dāng)初的程序員都是用匯編語言開發(fā)程序,他們當(dāng)然希望匯編語言強(qiáng)大啦,盡量多一些指令,盡量一個(gè)指令能多干幾件事,所以指令集中的指令越來越多,越來越復(fù)雜。不過這樣的好處是程序員同學(xué)很爽。最后,CISC是Intel使用的指令集,Intel公司在兼容性方面做得最好,指令集在發(fā)展的過程中,還要兼容過去有瑕疵的古董,以至于最后的指令集變得有點(diǎn)“奇形怪狀”了。
作為后起之秀的RISC ,借鑒了前輩CISC 的經(jīng)驗(yàn),取其精華,棄其糟柏,當(dāng)然要更好更輕量啦。它是怎么來的呢?
CISC 不是做得很全很強(qiáng)嗎,可是很多時(shí)候,程序員并不會(huì)用到那些復(fù)雜的指令和尋址方式,即使用到了,編譯器有時(shí)候?yàn)榱藘?yōu)化,未必“全”將其編譯為復(fù)雜的形式。這就導(dǎo)致了CPU 中的復(fù)雜的指令和尋址方式無用武之地。根據(jù)二八定律,指令集中20%的簡單指令占了程序的80% ,而指令集中80% 的復(fù)雜指令占了程序的20% 。根據(jù)這個(gè)特性,處理器及指令集被重新設(shè)計(jì),保留了那些基本常用的指令,減少了硬件電路的復(fù)雜性。這樣,大部分指令部能在一個(gè)時(shí)鐘周期內(nèi)完成,更有利于提升流水線的效率。而且,指令采用了定長編碼,這樣譯碼工作更容易了。由于其太優(yōu)秀了,后來的處理器,如MIPS, ARM, Power都采用RISC 指令體系,做得最好的就是MIPS 處理器,它嚴(yán)格遵守RISC 思想,業(yè)界公認(rèn)其優(yōu)雅。
我們常用的CPU 是Intel 和AMD 公司的產(chǎn)品,它們用的指令集便是基于CISC 思想的x86.。 AMD 的x86指令架構(gòu)是Intel 授權(quán)給他們的,為區(qū)別于此, Intel 在官方手冊(cè)上稱自己的指令集為IA32。
雖然AMD 采用的也是x86 指令集,但I(xiàn)ntel 可沒把硬件實(shí)現(xiàn)方法也告訴AMD ,否則AMD 的CPU 和Intel 的CPU 不就完全一樣了嗎,人家Intel 也不肯呢。指令集是一套約定,里面規(guī)定的是有哪些指令、指令的二進(jìn)制編碼、指令格式等,如何實(shí)現(xiàn)這套約定,這是硬件自己的事。打個(gè)比方,這就像和朋友約好了在某餐廳吃飯,咱是坐車去,還是走著去,這是咱們的事,與吃飯是無關(guān)的。說白了,在Intel 的CPU 上運(yùn)行的軟件也能夠在AMD 的CPU 上運(yùn)行,原因就是它們共用了同用一套指令集,也就是對(duì)二進(jìn)制編碼達(dá)成了共識(shí)。它們面對(duì)相同的需求,可能采取了不同的行動(dòng),但都完成了任務(wù)。比如機(jī)器碼是b80000, Intel的CPU 經(jīng)過譯碼,知道這是將0 賦值給寄存器ax,相當(dāng)于匯編語言mov ax, 0 。AMD 的CPU 在譯碼時(shí),也得將此機(jī)器碼認(rèn)為是將0 賦值給寄存器ax。至于它們?cè)谖锢砩鲜窃趺磳? 傳入寄存器ax 中的,這是它們各自實(shí)現(xiàn)的方式,與指令集無關(guān)。它們各自實(shí)現(xiàn)的方式,就叫微架構(gòu)。
總結(jié)一下,指令集是具體的一套指令編碼,微架構(gòu)是指令集的物理實(shí)現(xiàn)方式。
發(fā)展到后來, x86 指令集越來越復(fù)雜。它本屬于CISC 體系,但由于效率低下,最終在其內(nèi)部實(shí)現(xiàn)上采取了RISC 內(nèi)核,即一條CISC 指令在譯碼時(shí),分解成多條RISC 指令,這樣其執(zhí)行效率便可與RISC 媲美啦。
目前市面上常見的指令集有五種,除x86 是CISC 指令體系外, ARM、MIPS 、Power、C6000 都是RISC 指令體系的指令集。
CPU 與指令集是對(duì)應(yīng)的,一種CPU 只能識(shí)別一種指令集,所以很多CPU 都以其支持的指令集來稱呼。比如ARM 、MIPS,它們本身是CPU名稱,又是指令集名稱。
ARM 主要用在手機(jī)中,作為手機(jī)的處理器。Power 是IBM 用于服務(wù)器上的處理器。C6000 是數(shù)字信號(hào)處理器,廣泛用于視頻處理。而MIPS 雖然本身很優(yōu)秀,但其在各領(lǐng)域起步都較晚,并沒有廣泛應(yīng)用的領(lǐng)域。
由于MIPS 本身的優(yōu)越性,龍芯用的就是mips 指令集,有沒有人問,為什么咱們自主研發(fā)的CPU 還要用人家國外的指令集?就不能也研發(fā)出一套指令集嗎?能倒是能,不過語言不通用。就像我自己可以發(fā)明一門語言,語言本身沒什么問題,問題是我用自己發(fā)明的語言和別人交流,誰昕得懂呢,誰又愿意去學(xué)這門語言呢?大家都很忙,不通用的東西沒人愿意花精力去學(xué)。如果龍芯也自立門戶創(chuàng)造新的指令集,那有誰愿意給它寫編譯器呢?即使有了編譯器,操作系統(tǒng)也要重新編譯發(fā)布,應(yīng)用程序也要重新編譯發(fā)布,指令集背后不僅是個(gè)計(jì)算機(jī)生態(tài)鏈,更重要的是全球經(jīng)濟(jì)鏈。
平時(shí)所說的編程語言,雖然其上層表現(xiàn)各異,歸根結(jié)底是要在具體的CPU 上運(yùn)行的,所以必須由編譯器按照該CPU 的指奪集,翻譯成符合該CPU 的指令。說到這,不得不說一下交叉編譯,本質(zhì)上交叉編譯就是用在A平臺(tái)上運(yùn)行的編譯器,編譯出符合B 平臺(tái)CPU 指令集的程序,編譯出的程序直接能在B平臺(tái)上運(yùn)行啦。這里的平臺(tái)指的就是CPU 指令體系結(jié)構(gòu)。
鏈接:https://www.jianshu.com/p/39325938a73a
來源:簡書
總結(jié)
以上是生活随笔為你收集整理的2_指令集、体系架构、微架构的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数字电路可控门电路原理(三态/同相/反相
- 下一篇: STM32的8种GPIO输入输出模式深入