1、指令系統(tǒng)
1.1 x86架構(gòu)
要講CPU,就必須先講一下指令系統(tǒng)。指令系統(tǒng)指的是一個CPU所能夠處理的全部指令的集合,是一個CPU的根本屬性。
我們現(xiàn)在所用的CPU絕大多數(shù)都采用x86架構(gòu),即采用了x86指令集的CPU。這是因為最早的那顆Intel發(fā)展出來的CPU代號稱為8086,后來依此架構(gòu)又開發(fā)出80286, 80386..., 因此這種架構(gòu)的CPU就被稱為x86架構(gòu)了。在2003年以前由Intel所開發(fā)的x86架構(gòu)CPU由8位升級到16、32位,后來AMD依此架構(gòu)修改新一代的CPU為64位,為了區(qū)別兩者的差異,因此64位的個人計算機CPU又被統(tǒng)稱為x86_64架構(gòu)。
之所以說指令系統(tǒng)是一個CPU的 根本屬性,是因為指令系統(tǒng)決定了一個CPU能夠運行什么樣的程序。所有采用高級語言編出的程序,都需要翻譯(編譯或解釋)成為機器語言后才能運行,這些機器語言中所包含的就是一條條的指令。
1.2 指令的格式
一條指令一般包括兩個部分:操作碼和地址碼。

操作碼其實就是指令序列號,用來告訴CPU需要執(zhí)行的是那一條指令。類似于匯編語言里的mov,add,jmp等符號碼。操作數(shù)則復(fù)雜一些,主要包括源操作數(shù)地址、目的地址和下一條指令的地址。在某些指令中,地址碼可以部分或全部省略,比如一條空指令就只有操作碼而沒有地址碼。
舉個例子,某個指令系統(tǒng)的指令長度為32位,操作碼長度為8位,地址長度也為8位,且第一條指令是加,第二條指令是減。當(dāng)它收到一個 “00000010 00000100 00000001 00000110”的指令時,先取出它的前8位操作碼,即00000010,分析得出這是一個減法操作,有3個地址,分別是兩個源操作數(shù)地址和一個目的地址。于是,CPU就到內(nèi)存地址00000100處取出被減數(shù),到00000001處取出減數(shù),送到 ALU中進行減法運算,然后把結(jié)果送到00000110處。
當(dāng)然,這只是一個相當(dāng)簡單化的例子,實際情況要復(fù)雜的多。
1.3 指令的分類與尋址方式
一般說來,現(xiàn)在的指令系統(tǒng)有以下幾種類型的指令:
算術(shù)邏輯運算指令
算術(shù)邏輯運算指令包括加減乘除等算術(shù)運算指令,以及與、或、非、異或等邏輯運算指令?,F(xiàn)在的指令系統(tǒng)還加入了一些十進制運算指令以及字符串運算指令等。浮點運算指令
用于對浮點數(shù)進行運算。浮點運算要大大復(fù)雜于整數(shù)運算,所以CPU中一般還會有專門負(fù)責(zé)浮點運算的浮點運算單元?,F(xiàn)在的浮點指令中一般還加入了向量指令,用于直接對矩陣進行運算,對于現(xiàn)在的多媒體和3D處理很有用。位操作指令
在很多高級語言如C、Java中都有一組位操作語句,相對應(yīng)地,指令系統(tǒng)中也有一組位操作指令,如左移一位、右移一位等。對于計算機內(nèi)部以二進制補碼表示的數(shù)據(jù)來說,這種操作是非常簡單快捷的。其他指令
上面三種都是運算型指令,除此之外還有許多非運算的其他指令。這些指令包括:數(shù)據(jù)傳送指令、堆棧操作指令、轉(zhuǎn)移類指令、輸入輸出指令和一些比較特殊的指令,如特權(quán)指令、多處理器控制指令和等待、停機、空操作等指令。
對于指令中的地址碼,也會有許多不同的尋址(編址)方式,主要有直接尋址,間接尋址,寄存器尋址,基址尋址,變址尋址等,某些復(fù)雜的指令系統(tǒng)會有幾十種甚至更多的尋址方式。
1.4 CISC與RISC
RISC: Reduced Instruction Set Computer,精簡指令系統(tǒng)計算機
CISC:Complex Instruction Set Computer,復(fù)雜指令系統(tǒng)計算機
一開始,計算機的指令系統(tǒng)只有很少一些基本指令,而其他的復(fù)雜指令全靠軟件編譯時通過簡單指令的組合來實現(xiàn)。舉個最簡單的例子,一個a乘以b的操作就可以轉(zhuǎn)換為a個b相加來做,這樣就用不著乘法指令了。當(dāng)然,最早的指令系統(tǒng)就已經(jīng)有乘法指令了,這是為什么呢?因為用硬件實現(xiàn)乘法比加法組合來得快得多。
由于那時的計算機部件相當(dāng)昂貴,而且速度很慢,為了提高速度,越來越多的復(fù)雜指令被加入了指令系統(tǒng)中。但是,很快又有一個問題:一個指令系統(tǒng)的指令數(shù)是受指令操作碼的位數(shù)所限制的,如果操作碼為8位,那么指令數(shù)最多為256條(2的8次方)。
那么怎么辦呢?指令的寬度是很難增加的,聰明的設(shè)計師們又想出了一種方案:操作碼擴展。前面說過,操作碼的后面跟的是地址碼,而有些指令是用不著地址碼或只用少量的地址碼的。那么,就可以把操作碼擴展到這些位置。
舉個簡單的例子,如果一個指令系統(tǒng)的操作碼為2位,那么可以有00、01、10、11四條不同的指令?,F(xiàn)在把11作為保留,把操作碼擴展到4位,那么 就可以有00、01、10、1100、1101、1110、1111七條指令。其中1100、1101、1110、1111這四條指令的地址碼必須少兩位。
然后,為了達到操作碼擴展的先決條件:減少地址碼,設(shè)計師們又動足了腦筋,發(fā)明了各種各樣的尋址方式,如基址尋址、相對尋址等,用以最大限度的壓縮地址碼長度,為操作碼留出空間。
就這樣,慢慢地,CISC指令系統(tǒng)就形成了,大量的復(fù)雜指令、可變的指令長度、多種的尋址方式是CISC的特點,也是CISC的缺點:因為這些都大大增加了解碼的難度,而在現(xiàn)在的高速硬件發(fā)展下,復(fù)雜指令所帶來的速度提升早已不及在解碼上浪費點的時間。除了個人PC市場還在用x86指令集外,服務(wù)器以及更大的系統(tǒng)都早已不用CISC了。x86仍然存在的唯一理由就是為了兼容大量的x86平臺上的軟件。
1975年,IBM的設(shè)計師John Cocke研究了當(dāng)時的IBM370CISC系統(tǒng),發(fā)現(xiàn)其中占總指令數(shù)僅20%的簡單指令卻在程序調(diào)用中占了80%,而占指令數(shù)80%的復(fù)雜指令卻只有20%的機會用到。由此,他提出了RISC的概念。
事實證明,RISC是成功的。80年代末,各公司的RISC CPU如雨后春筍般大量出現(xiàn),占據(jù)了大量的市場。
RISC的最大特點是指令長度固定,指令格式種類少,尋址方式種類少,大多數(shù)是簡單指令且都能在一個時鐘周期內(nèi)完成,易于設(shè)計超標(biāo)量與流水線,寄存器 數(shù)量多,大量操作在寄存器之間進行。
2、CPU內(nèi)核結(jié)構(gòu)
CPU(Central Processing Unit,中央處理器)是一塊超大規(guī)模的集成電路,主要由運算單元、控制單元、存儲單元三部分組成。

2.1 控制單元
控制單元是整個CPU的指揮控制中心,由指令寄存器IR(InstrucTIon Register)、指令譯碼器ID(InstrucTIon Decoder)和操作控制器OC(Operation Controller)等,對協(xié)調(diào)整個電腦有序工作極為重要。它根據(jù)用戶預(yù)先編好的程序,依次從存儲器中取出各條指令,放在指令寄存器IR中,通過指令譯碼(分析)確定應(yīng)該進行什么操作,然后通過操作控制器OC,按確定的時序,向相應(yīng)的部件發(fā)出微操作控制信號。操作控制器OC中主要包括節(jié)拍脈沖發(fā)生器、控制矩陣、時鐘脈沖發(fā)生器、復(fù)位電路和啟停電路等控制邏輯。
2.2 運算單元
運算單元包括算術(shù)邏輯運算單元ALU(Arithmetic and Logic Unit)和浮點運算單元FPU(Floating Point Unit),
ALU主要完成對二進制數(shù)據(jù)的定點算術(shù)運算(加減乘除)、邏輯運算(與或非異或)以及移位操作。在某些CPU中還有專門用于處理移位操作的移位器。
通常ALU由兩個輸入端和一個輸出端。整數(shù)單元有時也稱為IEU(Integer Execution Unit)。我們通常所說的“CPU是XX位的”就是指ALU所能處理的數(shù)據(jù)的位數(shù)。
FPU主要負(fù)責(zé)浮點運算和高精度整數(shù)運算。有些FPU還具有向量運算的功能,另外一些則有專門的向量處理單元。
2.3 存儲單元
存儲單元包括CPU片內(nèi)緩存和寄存器組,是CPU中暫時存放數(shù)據(jù)的地方,里面保存著那些等待處理的數(shù)據(jù),或已經(jīng)處理過的數(shù)據(jù),CPU訪問寄存器所用的時間要比訪問內(nèi)存的時間短。采用寄存器,可以減少CPU訪問內(nèi)存的次數(shù),從而提高了CPU的工作速度。但因為受到芯片面積和集成度所限,寄存器組的容量不可能很大。寄存器組可分為專用寄存器和通用寄存器。
專用寄存器通常是一些狀態(tài)寄存器,不能通過程序改變,由CPU自己控制,表明某種狀態(tài)。
通用寄存器組是一組最快的存儲器,用來保存參加運算的操作數(shù)和中間結(jié)果。用途廣泛并可由程序員規(guī)定其用途,通用寄存器的數(shù)目因微處理器而異。
3、CPU工作原理
CPU的工作過程大體上可分為提取、解碼、執(zhí)行、寫回四步。
3.1 提取
從存儲器或緩存中檢索指令(為數(shù)值或一系列數(shù)值)。由程序計數(shù)器(Program Counter)指定存儲器的位置。(程序計數(shù)器保存供識別程序位置的數(shù)值。換言之,程序計數(shù)器記錄了CPU在程序里的蹤跡。)
3.2 解碼
CPU根據(jù)存儲器提取到的指令來決定其執(zhí)行行為。在解碼階段,指令被拆解為有意義的片段。根據(jù)CPU的指令集定義將數(shù)值解譯為指令。
3.3 執(zhí)行
在提取和解碼階段之后,緊接著進入執(zhí)行階段。該階段中,連接到各種能夠進行所需運算的CPU部件。
例如,要求一個加法運算,算術(shù)邏輯單元ALU將會連接到一組輸入和一組輸出。輸入提供了要相加的數(shù)值,而輸出將含有總和的結(jié)果。ALU內(nèi)含電路系統(tǒng),易于輸出端完成簡單的普通運算和邏輯運算(比如加法和位元運算)。如果加法運算產(chǎn)生一個對該CPU處理而言過大的結(jié)果,在標(biāo)志暫存器里可能會設(shè)置運算溢出(Arithmetic Overflow)標(biāo)志。
3.4 寫回
以一定格式將執(zhí)行階段的結(jié)果簡單的寫回。運算結(jié)果經(jīng)常被寫進CPU內(nèi)部的暫存器,以供隨后指令快速存取。在有些案例中,運算結(jié)果可能寫進速度較慢,但容量較大且較便宜的主記憶體中。某些類型的指令會操作程序計數(shù)器,而不直接產(chǎn)生結(jié)果。這些一般稱作“跳轉(zhuǎn)”(Jumps),并在程式中帶來循環(huán)行為、條件性執(zhí)行(透過條件跳轉(zhuǎn))和函式。許多指令會改變標(biāo)志暫存器的狀態(tài)位元。這些標(biāo)志可用來影響程式行為,緣由于它們時常顯出各種運算結(jié)果。例如,以一個“比較”指令判斷兩個值大小,根據(jù)比較結(jié)果在標(biāo)志暫存器上設(shè)置一個數(shù)值。這個標(biāo)志可藉由隨后跳轉(zhuǎn)指令來決定程式動向。在執(zhí)行指令并寫回結(jié)果之后,程序計數(shù)器值會遞增,反覆整個過程,下一個指令周期正常的提取下一個順序指令。

總結(jié)一下,CPU的運行原理就是:控制單元在時序脈沖的作用下,將指令計數(shù)器里所指向的指令地址(這個地址是在內(nèi)存里的)送到地址總線上去,然后CPU將這個地址里的指令讀到指令寄存器進行譯碼。對于執(zhí)行指令過程中所需要用到的數(shù)據(jù),會將數(shù)據(jù)地址也送到地址總線,然后CPU把數(shù)據(jù)讀到CPU的內(nèi)部存儲單元(就是內(nèi)部寄存器)暫存起來,最后命令運算單元對數(shù)據(jù)進行處理加工。周而復(fù)始,一直這樣執(zhí)行下去,天荒地老,海枯石爛,直到停電。
4、CPU性能
4.1 主頻、外頻與倍頻
CPU的主頻,即CPU內(nèi)核工作的時鐘頻率(CPU Clock Speed)。一個時鐘周期內(nèi)CPU能完成一次最基本的動作,比如某個CPU的主頻為2.7 Ghz,即代表它可以每秒完成2.7*109(27億)次最基本的動作,一條指令一般由多個基本動作組成。
CPU的主頻不代表CPU的速度,但提高主頻對于提高CPU運算速度卻是至關(guān)重要的。
在計算機主板上,以CPU為主,內(nèi)存和各種外圍設(shè)備為輔,有許多設(shè)備要共同在一起工作。這些設(shè)備之間的聯(lián)絡(luò),數(shù)據(jù)的交換,都必須正確無誤,分秒不差。因此,它們必須要有一個固定的時鐘來做時間上的校正,協(xié)調(diào)或者參考。這個時鐘由主板上的時鐘發(fā)生器產(chǎn)生,就是所謂的外頻。
在早期的計算機中,內(nèi)存與主板之間的同步運行的速度等于外頻,在這種方式下,可以理解為CPU外頻直接與內(nèi)存相連通,實現(xiàn)兩者間的同步運行狀態(tài)。由于CPU工作頻率不斷提高,而PC機的一些其他設(shè)備(如插卡、硬盤等)卻受到工藝的限制,不能承受更高的頻率,因此限制了CPU頻率的進一步提高。因此出現(xiàn)了倍頻技術(shù),該技術(shù)能夠使CPU內(nèi)部工作頻率變?yōu)橥獠款l率的倍數(shù),從而通過提升倍頻而達到提升主頻的目的。
倍頻系數(shù)是指CPU主頻與外頻之間的相對比例關(guān)系。它的作用是使系統(tǒng)總線工作在相對較低的頻率上,而CPU速度可以通過倍頻來提升。CPU主頻計算方式為:
主頻=外頻 x 倍頻
4.2 超標(biāo)量
CPU的性能是由什么決定的呢?單純的一個ALU速度在一個CPU中并不起決定性作用,因為ALU的速度都差不多。而一個CPU的性能表現(xiàn)的決定性因素就在于CPU內(nèi)核的設(shè)計。
既然無法大幅提高ALU的速度,有什么替代的方法呢?并行處理的方法又一次產(chǎn)生了強大的作用。所謂的超標(biāo)量CPU,就是指集成了多個ALU、多個FPU、多個譯碼器和多條流水線的CPU,以并行處理的方式來提高性能。這種技術(shù)能夠在相同的CPU主頻下實現(xiàn)更高的CPU吞吐率。
4.3 流水線與超流水線
流水線技術(shù)是一種將每條指令分解為多步,并讓各步操作重疊,從而實現(xiàn)幾條指令并行處理的技術(shù)。程序中的指令仍是一條條順序執(zhí)行,但可以預(yù)先取若干條指令,并在當(dāng)前指令尚未執(zhí)行完時,提前啟動后續(xù)指令的另一些操作步驟。這樣顯然可加速一段程序的運行過程。
對于一條具體的指令執(zhí)行過程,通??梢苑譃槲鍌€部分:取指令,指令譯碼,取操作數(shù),運算(ALU),寫結(jié)果。其中前三步一般由指令控制器完成,后兩步則由運算器完成。按照傳統(tǒng)的方式,所有指令順序執(zhí)行,那么先是指令控制器工作,完成第一條指令的前三步,然后運算器工作,完成后兩步;然后指令控制器工作, 完成第二條指令的前三步,再是運算器,完成第二條指令的后兩部……很明顯,當(dāng)指令控制器工作時運算器基本上在休息,而當(dāng)運算器在工作時指令控制器卻在休息,造成了相當(dāng)大的資源浪費。解決方法很容易想到,當(dāng)指令控制器完成了第一條指令的前三步后,直接開始第二條指令的操作,運算單元也是。這樣就形成了流水線系統(tǒng),這是一條2級流水線。

如果是一個超標(biāo)量系統(tǒng),假設(shè)有三個指令控制單元和兩個運算單元,那么就可以在完成了第一條指令的取址工作后直接開始第二條指令的取址,這時第一條指令在進行譯碼;然后第三條指令取址,第二條指令譯碼,第一條指令取操作數(shù)……這樣就是一個5級流水線。
超流水線以增加流水線級數(shù)的方法來縮短機器周期,相同的時間內(nèi)超級流水線執(zhí)行了更多的機器指令。采用簡單指令以加快執(zhí)行速度是所有流水線的共同特點,但超級流水線配置了多個功能部件和指令譯碼電路,采用多條流水線并行處理,還有多個寄存器端口和總線,可以同時執(zhí)行多個操作,因此比普通流水線執(zhí)行的更快,在一個機器周期內(nèi)可以流出多條指令。
超標(biāo)量是指在CPU中有一條以上的流水線,并且每時鐘周期內(nèi)可以完成一條以上的指令,其實質(zhì)是以空間換取時間。而超流水線是通過細(xì)化流水、提高主頻,使得在一個機器周期內(nèi)完成一個甚至多個操作,其實質(zhì)是以時間換取空間。
流水線系統(tǒng)最大限度地利用了CPU資源,使每個部件在每個時鐘周期都工作,大大提高了效率。但是,流水線有兩個非常大的問題:相關(guān)和轉(zhuǎn)移。
在一個流水線系統(tǒng)中,如果第二條指令需要用到第一條指令的結(jié)果,這種情況叫做相關(guān)。以上面哪個5級流水線為例,當(dāng)?shù)诙l指令需要取操作數(shù)時,第一條指 令的運算還沒有完成,如果這時第二條指令就去取操作數(shù),就會得到錯誤的結(jié)果。所以,這時整條流水線不得不停頓下來,等待第一條指令的完成。這是很討厭的問題,特別是對于比較長的流水線,比如20級,這種停頓通常要損失十幾個時鐘周期。目前解決這個問題的方法是亂序執(zhí)行。亂序執(zhí)行的原理是在兩條相關(guān)指令中插入不相關(guān)的指令,使整條流水線順暢。比如上面的例子中,開始執(zhí)行第一條指令后直接開始執(zhí)行第三條指令(假設(shè)第三條指令不相關(guān)),然后才開始執(zhí)行第二條指令,這樣當(dāng)?shù)诙l指令需要取操作數(shù)時第一條指令剛好完成,而且第三條指令也快要完成了,整條流水線不會停頓。當(dāng)然,流水線的阻塞現(xiàn)象還是不能完全避免的,尤其是當(dāng)相關(guān)指令非常多的時候。
另一個大問題是條件轉(zhuǎn)移。在上面的例子中,如果第一條指令是一個條件轉(zhuǎn)移指令,那么系統(tǒng)就會不清楚下面應(yīng)該執(zhí)行那一條指令?這時就必須等第一條指令的判斷結(jié)果出來才能執(zhí)行第二條指令。條件轉(zhuǎn)移所造成的流水線停頓甚至比相關(guān)還要嚴(yán)重的多。所以,現(xiàn)在采用分支預(yù)測技術(shù)來處理轉(zhuǎn)移問題。雖然我們的程序中充滿著分支,而且哪一條分支都是有可能的,但大多數(shù)情況下總是選擇某一分支。比如一個循環(huán)的末尾是一個分支,除了最后一次我們需要跳出循環(huán)外,其他的時候我們 總是選擇繼續(xù)循環(huán)這條分支。根據(jù)這些原理,分支預(yù)測技術(shù)可以在沒有得到結(jié)果之前預(yù)測下一條指令是什么,并執(zhí)行它。現(xiàn)在的分支預(yù)測技術(shù)能夠達到90%以上的正確率,但是,一旦預(yù)測錯誤,CPU仍然不得不清理整條流水線并回到分支點。這將損失大量的時鐘周期。
越是長的流水線,相關(guān)和轉(zhuǎn)移兩大問題也越嚴(yán)重,所以,流水線并不是越長越好,超標(biāo)量也不是越多越好,找到一個速度與效率的平衡點才是最重要的。
4.4 緩存
說到CPU,不得不說的就是CPU緩存,目前CPU的緩存已經(jīng)成了衡量CPU性能的一個必要指標(biāo),那么CPU緩存到底對CPU性能的影響有多大呢?
我們知道,CPU執(zhí)行指令時,會將執(zhí)行結(jié)果放在一個叫“寄存器”的元件中,由于“寄存器”集成在CPU內(nèi)部,與ALU等構(gòu)成CPU的重要元件,因此寄存器中的指令很快被CPU所訪問,但畢竟寄存器的容量太小,CPU所需的大量指令和數(shù)據(jù)還在內(nèi)存(RAM)當(dāng)中,所以CPU為了完成指令操作,需要頻繁地向內(nèi)存發(fā)送接收指令、數(shù)據(jù)。由于CPU運算速度要比內(nèi)存讀寫速度快很多,這樣會使CPU花費很長時間等待數(shù)據(jù)到來或把數(shù)據(jù)寫入內(nèi)存,所以傳統(tǒng)的系統(tǒng)瓶頸在這里就產(chǎn)生了。
實際工作時,CPU往往需要重復(fù)讀取同樣的數(shù)據(jù)塊,所以人們在CPU內(nèi)部集成了一個比內(nèi)存快許多的“Cache”,這就是最早的“高速緩存”。
按照數(shù)據(jù)讀取順序和與CPU結(jié)合的緊密程度,CPU緩存可以分為一級緩存,二級緩存,部分高端CPU還具有三級緩存。

每一級緩存中所儲存的全部數(shù)據(jù)都是下一級緩存的一部分,這三種緩存的技術(shù)難度和制造成本是相對遞減的,所以其容量也是相對遞增的。當(dāng)CPU要讀取一個數(shù)據(jù)時,首先從一級緩存中查找,如果沒有找到再從二級緩存中查找,如果還是沒有就從三級緩存或內(nèi)存中查找。一般來說,每級緩存的命中率大概都在80%左右,也就是說全部數(shù)據(jù)量的80%都可以在一級緩存中找到,只剩下20%的總數(shù)據(jù)量才需要從二級緩存、三級緩存或內(nèi)存中讀取,由此可見一級緩存是整個CPU緩存架構(gòu)中最為重要的部分。
CPU從不同介質(zhì)讀寫數(shù)據(jù)的對比如下圖所示:

可以發(fā)現(xiàn):1.越往上存儲容量越小,存取速度越快,成本越高,反之亦然;一層存儲器只和下層存儲器打交道,不會跨級訪問,下層作為上層的一個緩存。
CPU要訪問的數(shù)據(jù)的最終一般都經(jīng)過主存,主存可以看做作下層其他設(shè)備的一個緩存,其他設(shè)備的數(shù)據(jù)最終都要進入主存才能被CPU訪問到。比如磁盤文件讀取操作,CPU只發(fā)起操作請求,具體的數(shù)據(jù)操作不需要經(jīng)過CPU,由DMA(Direct Memory Access)來操作IO和主存的交互,當(dāng)操作完成后,IO設(shè)備發(fā)出中斷,通知CPU操作完成。