CPU 進(jìn)化論:復(fù)雜指令集 CISC
英國(guó)生物學(xué)家達(dá)爾文于 1859 年出版了震動(dòng)整個(gè)學(xué)術(shù)界和宗教界的《物種起源》,達(dá)爾文在這本書(shū)里提出了生物進(jìn)化論學(xué)說(shuō),認(rèn)為生命在不斷演變進(jìn)化,物競(jìng)天擇適者生存。
沒(méi)有歷史的計(jì)算機(jī)
生命是這樣,實(shí)際上計(jì)算機(jī)技術(shù)也是如此。
計(jì)算機(jī)技術(shù)也和生命體一樣在不斷演變進(jìn)化,在討論一項(xiàng)技術(shù)時(shí),如果不了解其演變過(guò)程而僅僅著眼于當(dāng)下就會(huì)讓人疑惑,不巧的是這正是當(dāng)前計(jì)算機(jī)教育的現(xiàn)狀——沒(méi)有歷史。
因此,在這里我將嘗試從歷史的角度來(lái)講講 CPU,以及 CPU 的發(fā)展歷程。
本篇主要關(guān)注CPU與復(fù)雜指令集CISC。
首先來(lái)看下什么是CPU。
什么是CPU?
我們都是程序員,那么從程序員的角度來(lái)看,CPU的工作其實(shí)是很簡(jiǎn)單的。
我們編寫(xiě)的所有程序,不管是簡(jiǎn)單的Hello World,還是復(fù)雜的比如PhotoShop之類(lèi)大型App,最終都會(huì)被編譯器轉(zhuǎn)為一條條簡(jiǎn)單的機(jī)器指令,因此在CPU看來(lái)所有程序是沒(méi)有什么本質(zhì)區(qū)別的,無(wú)非就是一個(gè)包含的指令多,一個(gè)包含的指令少,這些指令就保存在可執(zhí)行文件中,程序運(yùn)行時(shí)被加載到內(nèi)存開(kāi)始被CPU執(zhí)行。
管你是簡(jiǎn)單程序還是復(fù)雜程序,CPU才不關(guān)心這些,它只需要簡(jiǎn)單一條一條的執(zhí)行就可以了,因此,在程序員眼里 CPU 是一個(gè)很簡(jiǎn)單的家伙。
有很多同學(xué)可能會(huì)好奇CPU是怎么構(gòu)造出來(lái),你可以參考《你管這破玩意叫CPU》。
接下來(lái)我們的視角就可以進(jìn)一步聚焦了,CPU執(zhí)行的是什么機(jī)器指令呢?
CPU的能力圈:指令集
我們?cè)撛鯓用枋鲆粋€(gè)人的能力呢?寫(xiě)過(guò)簡(jiǎn)歷的同學(xué)肯定都知道,就像這樣:
會(huì)寫(xiě)代碼
- 會(huì)炒菜
- 會(huì)唱歌
- 會(huì)跳舞
- 會(huì)炒股
- 。。。
巴菲特有一個(gè)詞用的很好,這叫能力圈,如果一個(gè)人會(huì)“寫(xiě)代碼”,那么你命令這個(gè)人“寫(xiě)代碼”,他就能寫(xiě)出代碼來(lái)(現(xiàn)實(shí)情況下你讓他寫(xiě)代碼他可能會(huì)過(guò)來(lái)打你)。
CPU也是同樣的道理,每種類(lèi)型的CPU都要自己的能力圈,只不過(guò)CPU的能力圈有一個(gè)特殊的名字,叫做 Instruction Set Architecture ,ISA,也就是指令集,指令集中包含各種各樣的指令:
- 會(huì)加法
- 會(huì)從內(nèi)存把數(shù)據(jù)搬運(yùn)到寄存器
- 會(huì)跳轉(zhuǎn)
- 會(huì)比較大小
- 。。。
指令集告訴我們一個(gè)CPU可以干嘛。
你從ISA中找一條指令發(fā)給CPU,CPU就是完成這條指令所代表的任務(wù)。
ISA有什么用呢,當(dāng)然是程序員用來(lái)編程啦!
沒(méi)錯(cuò),最初的程序都是面向CPU直接用匯編來(lái)寫(xiě)程序,這一時(shí)期也非常的樸實(shí)無(wú)華,沒(méi)有那么多花哨的概念,什么面向?qū)ο罄玻裁丛O(shè)計(jì)模式啦,統(tǒng)統(tǒng)沒(méi)有,總之這個(gè)時(shí)期的程序員寫(xiě)代碼只需要看看ISA就可以了。
這就是指令集的概念,注意,指令集是CPU告訴程序員該怎么讓自己工作的。
不同的CPU會(huì)有不同類(lèi)型的指令集,指令集的類(lèi)型除了影響程序員寫(xiě)匯編程序之外還會(huì)影響CPU的硬件設(shè)計(jì),到底CPU該采用什么類(lèi)型的指令集,CPU該如何設(shè)計(jì),這一論戰(zhàn)持續(xù)至今,并且愈發(fā)精彩。
接下來(lái)我們看一下第一種也是最先誕生的指令集類(lèi)型:復(fù)雜指令集,Complex Instruction Set Computer,簡(jiǎn)稱(chēng)CISC。當(dāng)今普遍存在于桌面PC以及服務(wù)器端的x86架構(gòu)就是基于復(fù)雜指令集CISC,生產(chǎn)x86處理器的廠(chǎng)商就是我們熟悉的“等,等等等等”英特爾以及AMD。
抽象:少就是多
直到1970s年代,這一時(shí)期編譯器還非常菜,不像現(xiàn)在這么智能,沒(méi)多少人信得過(guò)編譯器,大部分程序還是用匯編語(yǔ)言純手工編寫(xiě) (這一點(diǎn)極為重要,對(duì)于接下來(lái)理解復(fù)雜指令集非常關(guān)鍵),這對(duì)現(xiàn)代程序員來(lái)說(shuō)是無(wú)法想象的,不要說(shuō)手寫(xiě)匯編語(yǔ)言,就是看懂匯編語(yǔ)言的程序員都不會(huì)很多。
當(dāng)然,現(xiàn)代編譯器已經(jīng)足夠強(qiáng)大足夠智能,編譯器生成的匯編語(yǔ)言已經(jīng)足夠優(yōu)秀,因此當(dāng)今程序員,除了編寫(xiě)操作系統(tǒng)以及部分驅(qū)動(dòng)的那幫家伙,剩下的幾乎已經(jīng)意識(shí)不到匯編語(yǔ)言的存在了,不要覺(jué)得可惜,這是生產(chǎn)力進(jìn)步的表現(xiàn),用高級(jí)語(yǔ)言編寫(xiě)程序的效率可是匯編語(yǔ)言望塵莫及的。
題外話(huà)說(shuō)的有點(diǎn)多,總之,這一時(shí)期的大部分程序都是直接通過(guò)匯編語(yǔ)言編寫(xiě)的,因此大家普遍認(rèn)為指令集應(yīng)該更加豐富一些、指令本身功能更強(qiáng)大一些,程序員常用的操作最好都有對(duì)應(yīng)的特定指令,畢竟大家都在直接用匯編語(yǔ)言來(lái)寫(xiě)程序,如果指令集很少或者指令本身功能單一,那么程序員用匯編指令寫(xiě)起程序會(huì)會(huì)非常繁瑣,很不方便,如果你在這個(gè)時(shí)期用匯編寫(xiě)程序你也會(huì)這樣想。
這就是這個(gè)時(shí)期一些計(jì)算機(jī)科學(xué)家所謂的抹平差異,semantic gap,抹平什么差異呢?
大家認(rèn)為高級(jí)語(yǔ)言中的一些概念比如函數(shù)調(diào)用、循環(huán)控制、復(fù)雜的尋址模式、數(shù)據(jù)結(jié)構(gòu)和數(shù)組的訪(fǎng)問(wèn)等都應(yīng)該直接有對(duì)應(yīng)的機(jī)器指令,這些就是現(xiàn)代大家認(rèn)為的復(fù)雜指令集CISC非常鮮明的特點(diǎn)。
除了更方便的使用匯編語(yǔ)言寫(xiě)程序,另一點(diǎn)需要考慮就是存儲(chǔ)。
物種起源
當(dāng)今的計(jì)算機(jī)都遵從馮諾依曼架構(gòu),該架構(gòu)的核心思想之一是“程序應(yīng)該和數(shù)據(jù)一樣都作為比特保存在計(jì)算機(jī)存儲(chǔ)設(shè)備中”,下面這張圖是所有計(jì)算設(shè)備的鼻祖,你現(xiàn)在看這篇文章用計(jì)算設(shè)備,不管是智能手機(jī)或者iPad、PC,亦或是存放這篇文章的微信數(shù)據(jù)中心服務(wù)器,其本質(zhì)都是下面這張簡(jiǎn)單的圖,這張圖是一切計(jì)算設(shè)備的起源。
代碼也是要占存儲(chǔ)空間的
從馮諾依曼結(jié)構(gòu)中我們就能知道為什么當(dāng)今可執(zhí)行程序中,比如Windows下的EXE或者Linux下的ELF文件,即包含機(jī)器指令也包含數(shù)據(jù),對(duì)于程序員來(lái)說(shuō)我們可以簡(jiǎn)單的認(rèn)為可執(zhí)行程序中有兩部分內(nèi)容:數(shù)據(jù)段以及代碼段:
由此可見(jiàn),程序員寫(xiě)的代碼是要占據(jù)存儲(chǔ)空間的,要知道在1970s年代,內(nèi)存大小僅僅數(shù)KB到數(shù)十KB,這是當(dāng)今程序員不可想象的,因?yàn)楝F(xiàn)在(2021年)的智能手機(jī)內(nèi)存都已經(jīng)數(shù)GB。如圖所示是1974年發(fā)布的Intel 1103內(nèi)存芯片:
大小只有 1KB 的英特爾1103存儲(chǔ)芯片的于1974年發(fā)布,這標(biāo)志著計(jì)算機(jī)工業(yè)界開(kāi)始進(jìn)入動(dòng)態(tài)隨機(jī)存儲(chǔ)DRAM時(shí)代,DRAM也就是我們熟知的內(nèi)存。
大家可以思考一下,幾KB的內(nèi)存,可謂寸土寸金,這么小的內(nèi)存要想裝入更多的程序就必須仔細(xì)的設(shè)計(jì)機(jī)器指令以節(jié)省程序占據(jù)的空間,這就要求:
- 一條機(jī)器指令盡可能完成更多的任務(wù),這很容易理解,就像在《你管這破玩意叫編程語(yǔ)言》這篇中的例子一樣,你更希望有一條“給我端杯水”的指令,而不是自己去寫(xiě)“邁出左腳;停住;邁出右腳;直到飲水機(jī);伸出右手;拿起水杯;接水。。。”等等這樣的匯編代碼
- 機(jī)器指令長(zhǎng)度不固定,也就是變長(zhǎng)機(jī)器指令,簡(jiǎn)單的指令占據(jù)更少的空間
- 機(jī)器指令高度編碼(encoded),提高代碼密度,節(jié)省空間
復(fù)雜指令集誕生的必然
基于對(duì)程序員方便編寫(xiě)匯編語(yǔ)言以及節(jié)省代碼存儲(chǔ)空間的需要,直接促成了復(fù)雜指令集的設(shè)計(jì),因此我們可以看到復(fù)雜指令集是這一時(shí)期必然的選擇,該指令集就這樣誕生了并開(kāi)始成為主流。
就這樣經(jīng)過(guò)一段時(shí)間后,人們發(fā)現(xiàn)了新的問(wèn)題,由于單條指令比較復(fù)雜,設(shè)計(jì)解碼機(jī)器指令的硬件(CPU的一部分)成了一件非常麻煩的事情,該怎樣解決這一問(wèn)題呢?
CPU真的在直接執(zhí)行機(jī)器指令嗎?
作為程序員,我們知道,對(duì)于重復(fù)使用的代碼其實(shí)是沒(méi)有必要一遍遍編寫(xiě)的,你可以把這些代碼封裝到函數(shù)中,這樣每次使用時(shí)只需要調(diào)用這個(gè)函數(shù)就好了,這個(gè)思路可以解決上述問(wèn)題。
對(duì)于指令集中的每一條機(jī)器指令都有一小段對(duì)應(yīng)的程序,這些程序存儲(chǔ)在CPU中,這些程序都是由更簡(jiǎn)單的指令組成,這些指令就是所謂的微代碼,Microcode。
就這樣CPU的指令集可以添加更多的指令,代價(jià)僅僅是再多一些簡(jiǎn)單的微代碼而已,是不是很天才的設(shè)計(jì)。
在這里也可以看到,一般我們認(rèn)為CPU直接執(zhí)行機(jī)器指令,嚴(yán)格來(lái)說(shuō)這是不正確的,對(duì)于含有微代碼設(shè)計(jì)的CPU來(lái)說(shuō),CPU直接執(zhí)行的并不是機(jī)器指令,而是微代碼,微代碼是CPU以及機(jī)器指令的中間層,機(jī)器指令相對(duì)于微代碼來(lái)說(shuō)是“更高級(jí)的語(yǔ)言”,機(jī)器指令對(duì)程序員來(lái)說(shuō)可見(jiàn),但微代碼對(duì)程序員來(lái)說(shuō)不可見(jiàn),程序員無(wú)法直接使用微代碼來(lái)控制CPU。
而在這一時(shí)期,這些微代碼普遍存放在ROM中,Read-Only Memory,而ROM普遍要比內(nèi)存便宜,因此依靠存儲(chǔ)在ROM中的微代碼來(lái)設(shè)計(jì)更多復(fù)雜指令進(jìn)而減少程序本身對(duì)內(nèi)存的占用是非常劃算的。
新的問(wèn)題
一切看上去都很好,有了復(fù)雜指令集,程序員可以更方便的編寫(xiě)匯編程序,這些程序也不需要占用很多存儲(chǔ)空間,代價(jià)就是CPU中需要有微代碼來(lái)簡(jiǎn)化CPU設(shè)計(jì)。
然而這一設(shè)計(jì)隨著時(shí)間的推移又出現(xiàn)了新的問(wèn)題。
作為程序員我們知道代碼難免會(huì)有bug,微代碼也不會(huì)有例外。但修復(fù)微代碼的bug要比修復(fù)普通程序的bug困難的多,你無(wú)法像普通程序那樣來(lái)測(cè)試、調(diào)試微代碼,這一切都太復(fù)雜了。
而且微代碼設(shè)計(jì)非常消耗晶體管,1979年代的Motorola 68000 處理器就采用該設(shè)計(jì),其中三分之一的晶體管都用在了微代碼上。
同年,計(jì)算機(jī)科學(xué)家Dave Patterson被委以重任來(lái)改善微代碼設(shè)計(jì),為此他還專(zhuān)門(mén)發(fā)表了論文,但他后來(lái)又推翻了自己想法,認(rèn)為微代碼設(shè)計(jì)的復(fù)雜性問(wèn)題很難解決,有問(wèn)題的是微代碼這種設(shè)計(jì)本身。。
因此,有人開(kāi)始反思,是不是還會(huì)有更好的設(shè)計(jì)。。。
預(yù)知后事如何請(qǐng)聽(tīng)下回分解。
總結(jié)
CPU是整個(gè)計(jì)算機(jī)系統(tǒng)的核心,CPU指令集ISA更是核心中的核心。
本文從歷史的角度講述了復(fù)雜指令集出現(xiàn)的必然,復(fù)雜指令集對(duì)于那些直接使用匯編語(yǔ)言進(jìn)行編程的程序員來(lái)說(shuō)是很方便的,同時(shí)復(fù)雜指令集的指令密度更高,相同的存儲(chǔ)空間可以存儲(chǔ)更多程序,這一切都推動(dòng)了復(fù)雜指令集的發(fā)展。
然而任何事物都有其必然性以及局限性,復(fù)雜指令集也不例外,隨著時(shí)間的推移采用復(fù)雜指令集的CPU設(shè)計(jì)出現(xiàn)各種各樣的問(wèn)題,面對(duì)這些問(wèn)題一部分人開(kāi)始重新思考指令集到底該如何設(shè)計(jì),我們將在下篇文章中繼續(xù)講述這一話(huà)題。
希望本篇對(duì)大家理解復(fù)雜指令集有所幫助。
本文轉(zhuǎn)載自微信公眾號(hào)「碼農(nóng)的荒島求生」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系碼農(nóng)的荒島求生公眾號(hào)。