一、指令集
圖片來源:互聯(lián)網(wǎng)
依據(jù)指令長度的不同,指令系統(tǒng)可分為復(fù)雜指令系統(tǒng)(Complex Instruction Set Computer,簡稱CISC )、精簡指令系統(tǒng)(Reduced Instruction Set Computer,簡稱 RISC)和超長指令字(Very Long Instruction Word,簡稱VLIW)指令集三種。
CISC中的指令長度可變;RISC中的指令長度比較固定;VLIW本質(zhì)上來講是多條同時執(zhí)行的指令的組合,其“同時執(zhí)行”的特征由編譯器指定,無須硬件進(jìn)行判斷。超標(biāo)量處理器是動態(tài)調(diào)度,由硬件發(fā)現(xiàn)指令級并行機(jī)會并負(fù)責(zé)正確調(diào)度,VLIW是靜態(tài)調(diào)度,由編譯器發(fā)現(xiàn)指令級并行機(jī)會并負(fù)責(zé)正確調(diào)度。
VLIW結(jié)構(gòu)的最初思想是最大限度利用指令級并行(Instruction Level Parallelism,簡稱ILP),VLIW的一個超長指令字由多個互相不存在相關(guān)性(控制相關(guān)、數(shù)據(jù)相關(guān)等)的指令組成,可并行進(jìn)行處理。VLIW可顯著簡化硬件實(shí)現(xiàn),但增加了編譯器的設(shè)計難度。由于AI和DSP領(lǐng)域,數(shù)據(jù)基本上是數(shù)據(jù)流,沒有跳轉(zhuǎn),因此特別適合靜態(tài)的VLIW,近期有不少AI芯片使用VLIW架構(gòu)。
圖片來源:互聯(lián)網(wǎng)
早期的CPU都采用CISC結(jié)構(gòu),如IBM的System360、Intel的8080和8086系列、Motorola的68000系列等。這與當(dāng)時的時代特點(diǎn)有關(guān),早期處理器設(shè)備昂貴且處理速度慢,設(shè)計者不得不加入越來越多的復(fù)雜指令來提高執(zhí)行效率,部分復(fù)雜指令甚至可與高級語言中的操作直接對應(yīng)。這種設(shè)計簡化了軟件和編譯器的設(shè)計,但也顯著提高了硬件的復(fù)雜性。
當(dāng)硬件復(fù)雜度逐漸提高時,CISC結(jié)構(gòu)出現(xiàn)了一系列問題。大量復(fù)雜指令在實(shí)際中很少用到,典型程序所使用的80%的指令只占指令集總指令數(shù)的20%,消耗大量精力的復(fù)雜設(shè)計只有很少的回報。同時,復(fù)雜的微代碼翻譯也會增加流水線設(shè)計難度,并降低頻繁使用的簡單指令的執(zhí)行效率。針對CISC結(jié)構(gòu)的缺點(diǎn),RISC遵循簡化的核心思路。
RISC簡化了指令功能,單個指令執(zhí)行周期短;簡化了指令編碼,使得譯碼簡單;簡化了訪存類型,訪存只能通過load/store指令實(shí)現(xiàn)。RISC指令的設(shè)計精髓是簡化了指令間的關(guān)系,有利于實(shí)現(xiàn)高效的流水線、多發(fā)射等技術(shù),從而提高主頻和效率。
RISC指令系統(tǒng)的最本質(zhì)特征是通過load/store結(jié)構(gòu)簡化了指令間關(guān)系,即所有運(yùn)算指令都是對寄存器運(yùn)算,所有訪存都通過專用的訪存指令(load/store)進(jìn)行。這樣,CPU只要通過寄存器的比較就能判斷運(yùn)算指令之間以及運(yùn)算指令和訪存指令之間有沒有數(shù)據(jù)相關(guān)性,而較復(fù)雜的訪存指令相關(guān)判斷(需要對訪存的物理地址進(jìn)行比較)則只在執(zhí)行l(wèi)oad/store指令的訪存部件上進(jìn)行,從而大大簡化了指令間相關(guān)性判斷的復(fù)雜度,有利于CPU采用指令流水線、多發(fā)射、亂序執(zhí)行等提高性能。因此,RISC不僅是一種指令系統(tǒng)類型,同時也是一種提高CPU性能的技術(shù)。X86處理器中將 CISC指令譯碼為類RISC的內(nèi)部操作,然后對這些內(nèi)部操作使用諸如超流水、亂序執(zhí)行、多發(fā)射等高效實(shí)現(xiàn)手段。而以PowerPC為例的RISC處理器則包含了許多功能強(qiáng)大的指令。
RISC的設(shè)計初衷針對CISC CPU復(fù)雜的弊端,選擇一些可以在單個CPU周期完成的指令,以降低CPU的復(fù)雜度,將復(fù)雜性交給編譯器。舉個例子,CISC提供的乘法指令,調(diào)用時可完成內(nèi)存a和內(nèi)存b中的兩個數(shù)相乘,結(jié)果存入內(nèi)存a,需要多個CPU周期才可以完成;而RISC不提供“一站式”的乘法指令,需調(diào)用四條單CPU周期指令完成兩數(shù)相乘:內(nèi)存a加載到寄存器,內(nèi)存b加載到寄存器,兩個寄存器中數(shù)相乘,寄存器結(jié)果存入內(nèi)存a。按此思路,早期設(shè)計出的RISC指令集,指令數(shù)是比CISC少些,但后來,很多RISC的指令集中指令數(shù)反超了CISC,因此,引用指令的復(fù)雜度而非數(shù)量來區(qū)分兩種指令集。
CISC指令的格式長短不一,執(zhí)行時的周期次數(shù)也不統(tǒng)一,而RISC結(jié)構(gòu)剛好相反,它是定長的,故適合采用管線處理架構(gòu)的設(shè)計,進(jìn)而可以達(dá)到平均一周期完成一指令的方向努力。顯然,在設(shè)計上RISC較CISC簡單,同時因?yàn)镃ISC的執(zhí)行步驟過多,閑置的單元電路等待時間增長,不利于平行處理的設(shè)計,所以就效能而言RISC較CISC還是站了上風(fēng),但RISC因指令精簡化后造成應(yīng)用程式碼變大,需要較大的程式存儲空間,且存在指令種類較多等等的缺點(diǎn)。
對CPU內(nèi)核結(jié)構(gòu)的影響X86指令集早期通常只有8個通用寄存器。所以,CISC的CPU執(zhí)行是大多數(shù)時間是在訪問存儲器中的數(shù)據(jù),而不是寄存器中的。這就拖慢了整個系統(tǒng)的速度。RISC系統(tǒng)往往具有非常多的通用寄存器,早期多是27個,并采用了重疊寄存器窗口和寄存器堆等技術(shù)使寄存器資源得到充分的利用。
大部分情況下(90%)的時間內(nèi)處理器都在運(yùn)行少數(shù)的指令,其余的時間則運(yùn)行各式各樣的復(fù)雜指令(復(fù)雜就意味著較長的運(yùn)行時間),RISC就是將這些復(fù)雜的指令剔除掉,只留下最經(jīng)常運(yùn)行的指令(所謂的精簡指令集),然而被剔除掉的那些指令雖然實(shí)現(xiàn)起來比較麻煩,卻在某些領(lǐng)域確實(shí)有其價值,RISC的做法就是將這些麻煩都交給軟件,CISC的做法則是像現(xiàn)在這樣: 由硬件設(shè)計完成。因此RISC指令集對編譯器要求很高,而CISC則很簡單。對編程人員的要求也類似。
因此x86架構(gòu)通常只需要一個復(fù)雜解碼器,簡單解碼器可以將一條x86指令(包括大部分SSE指令在內(nèi))翻譯為一條微指令(uop),而復(fù)雜解碼器則將一些特別的(單條)x86指令翻譯為1~4 條uops——在極少數(shù)的情況下,某些指令需通過額外的可編程microcode解碼器解碼為更多的uops (有時候甚至可達(dá)幾百個,因?yàn)橐恍㊣A指令很復(fù)雜,并且可以帶有很多的前綴/修改量,當(dāng)然這種情況很少見)。
二、運(yùn)算架構(gòu)
馮諾伊曼架構(gòu)與哈佛架構(gòu)
圖片來源:互聯(lián)網(wǎng)
馮諾伊曼架構(gòu)與哈佛架構(gòu)最大區(qū)別是存儲總線,馮諾依曼架構(gòu)的指令和數(shù)據(jù)是共用一條總線,也就是說,不能同時讀取指令和數(shù)據(jù),必須在時間序列上分開。哈佛架構(gòu)是指令和數(shù)據(jù)用不同的總線,可以同時讀取指令和數(shù)據(jù)。
早期的計算機(jī)設(shè)計中,程序和數(shù)據(jù)是倆個截然不同的概念,數(shù)據(jù)放在存儲器中,而程序作為控制器的一部分,這樣的計算機(jī)計算效率低,靈活性較差。馮.諾依曼結(jié)構(gòu)中,將程序和數(shù)據(jù)一樣看待,將程序編碼為數(shù)據(jù),然后與數(shù)據(jù)一同存放在存儲器中,這樣計算機(jī)就可以調(diào)用存儲器中的程序來處理數(shù)據(jù)了。這意味著無論什么程序,最終都是會轉(zhuǎn)換為數(shù)據(jù)的形式存儲在存儲器中,要執(zhí)行相應(yīng)的程序只需要從存儲器中依次取出指令、執(zhí)行,而無需再從控制器中取出,馮.諾依曼結(jié)構(gòu)的靈魂所在正是這里:這種設(shè)計思想導(dǎo)致了硬件和軟件的分離,即硬件設(shè)計和程序設(shè)計可以分開執(zhí)行。
現(xiàn)代計算架構(gòu)中,整個計算架構(gòu)通常都采用馮諾依曼架構(gòu),在CPU內(nèi)部采用類哈佛架構(gòu),在現(xiàn)代CPU內(nèi)部的一級緩存中,指令和數(shù)據(jù)是分開存儲的,但指令和數(shù)據(jù)的尋址空間address space還是共享的,這不能算嚴(yán)格的哈佛架構(gòu),但思路是哈佛架構(gòu)的思路。
馮諾依曼詳細(xì)架構(gòu)
圖片來源:互聯(lián)網(wǎng)
虛線框內(nèi)再加上多級緩存就是現(xiàn)代意義上的CPU,鼠標(biāo)鍵盤是輸入設(shè)備、顯示器是輸出設(shè)備;手機(jī)觸摸屏既是輸入設(shè)備又是輸出設(shè)備;服務(wù)器中網(wǎng)卡既是輸入設(shè)備又是輸出設(shè)備;所有的計算機(jī)程序都可以抽象為輸入設(shè)備讀取信息,通過CPU來執(zhí)行存儲在存儲器中的程序,結(jié)果通過輸出設(shè)備反饋給用戶。
算術(shù)邏輯單元(Arithmetic Logic Unit,ALU)。ALU的主要功能就是在控制信號的作用下,完成加、減、乘、除等算術(shù)運(yùn)算以及與、或、非、異或等邏輯運(yùn)算以及移位、補(bǔ)位等運(yùn)算??刂茊卧–ontrol Unit),是計算機(jī)的神經(jīng)中樞和指揮中心,只有在控制器的控制下,整個計算機(jī)才能有條不紊地工作、自動執(zhí)行程序。
控制器的工作流程為:從內(nèi)存中取指令、翻譯指令、分析指令,然后根據(jù)指令的內(nèi)存向有關(guān)部件發(fā)送控制命令,控制相關(guān)部件執(zhí)行指令所包含的操作。 計算機(jī)內(nèi)部,程序和數(shù)據(jù)都是以二進(jìn)制代碼的形式存儲的,均以字節(jié)為單位(8位)存儲在存儲器中,一個字節(jié)占用一個存儲單元,且每個存儲單元都有唯一的地址號。
CPU可以直接使用指令對內(nèi)部存儲器按照地址進(jìn)行讀寫兩種操作,讀:將內(nèi)存中某個存儲單元的內(nèi)容讀出,送入CPU的某個寄存器中;寫:在控制器的控制下,將CPU中某寄存器內(nèi)容傳到某個存儲單元中。要注意,內(nèi)存中的數(shù)據(jù)和地址碼都是二進(jìn)制數(shù),但是倆者是不同的,一個地址碼可以指向一個存儲單元,地址是存儲單元的位置,數(shù)據(jù)是存儲單元的內(nèi)容。地址碼的長度由內(nèi)存單元的個數(shù)確定。
內(nèi)存的存取速度會直接影響計算機(jī)的運(yùn)算速度,由于CPU是高速器件,但是CPU的速度是受制于內(nèi)存的存取速度的,所以為解決CPU與內(nèi)存速度不匹配的問題,在CPU和內(nèi)存直接設(shè)置了一種高速緩沖存儲器Cache。Cache是計算機(jī)中的一個高速小容量存儲器,其中存放的是CPU近期要執(zhí)行的指令和數(shù)據(jù),其存取速度可以和CPU的速度匹配,一般采用靜態(tài)RAM充當(dāng)Cache即緩存。
內(nèi)存按工作方式的不同又可以分為倆部分:RAM:隨機(jī)存儲器,可以被CPU隨機(jī)讀取,一般存放CPU將要執(zhí)行的程序、數(shù)據(jù),斷電丟失數(shù)據(jù)。ROM:只讀存儲器,只能被CPU讀,不能輕易被CPU寫,用來存放永久性的程序和數(shù)據(jù),比如:系統(tǒng)引導(dǎo)程序、監(jiān)控程序等。具有掉電非易失性。
哈佛架構(gòu)
圖片來源:互聯(lián)網(wǎng)
通常哈佛架構(gòu)有四條總線,處理器與存儲器之間有兩條總線,一條是尋址,一條是數(shù)據(jù),哈佛架構(gòu)的指令(即編程Program)和數(shù)據(jù)分開存儲,也就是四條總線。
典型的哈佛架構(gòu)是DSP,通常我們把馮諾依曼架構(gòu)的處理器叫GPP,即通用型處理器。DSP是為單一密集計算任務(wù)如視頻編解碼、FIR濾波器,這些任務(wù)拆解到底層通常是乘法或乘積累加。DSP為了進(jìn)行這些密集計算任務(wù),添加了一些固定算法指令,比如單周期乘加指令、逆序加減指令(FFT時特別有用,不是ARM的那種逆序),塊重復(fù)指令(減少跳轉(zhuǎn)延時)等等,甚至將很多常用的由幾個操作組成的一個序列專門設(shè)計一個指令可以一周期完成(比如一指令作一個乘法,把結(jié)果累加,同時將操作數(shù)地址逆序加1),極大地提高了信號處理的速度。
由于數(shù)字處理的讀數(shù)、回寫量非常大,為了提高速度,采用指令、數(shù)據(jù)空間分開的方式,以兩條總線來分別訪問兩個空間,同時,一般在DSP內(nèi)部有高速RAM,數(shù)據(jù)和程序要先加載到高速片內(nèi)RAM中才能運(yùn)行。DSP為提高數(shù)字計算效率,犧牲了存儲器管理的方便性,對多任務(wù)的支持要差的多,所以DSP不適合于作多任務(wù)控制作用。
像乘積累加計算,早期GPP(通用處理器)處理一般是用加法代替乘法,要n多CPU周期,盡管CPU主頻很快,但還是要相當(dāng)時間,所以早期CPU會特設(shè)一個乘法器專門做乘法。乘法都如此麻煩,乘積累加就更麻煩,通常做一次乘法會發(fā)生4次存儲器訪問,用掉至少四個指令周期。再做加法,再用掉兩個指令周期,而DSP只需要一個指令周期。
現(xiàn)在典型的高性能GPP實(shí)際上已包含兩個片內(nèi)高速緩存,一個是數(shù)據(jù),一個是指令,它們直接連接到處理器核,以加快運(yùn)行時的訪問速度。從物理上說,這種片內(nèi)的雙存儲器和總線的結(jié)構(gòu)幾乎與哈佛結(jié)構(gòu)的一樣了。然而從邏輯上講,兩者還是有重要的區(qū)別。GPP使用控制邏輯來決定哪些數(shù)據(jù)和指令字存儲在片內(nèi)的高速緩存里,其程序員并不加以指定(也可能根本不知道)。
與此相反,DSP使用多個片內(nèi)存儲器和多組總線來保證每個指令周期內(nèi)存儲器的多次訪問。在使用DSP時,程序員要明確地控制哪些數(shù)據(jù)和指令要存儲在片內(nèi)存儲器中,哪些要放在片外。也就是說GPP的數(shù)據(jù)和指令程序員無法修改,有時可能出現(xiàn)錯誤,也會導(dǎo)致效率的下降,不過由于在一個尋址空間內(nèi),即便出現(xiàn)錯誤,帶來的后果也只是延遲,效率降低。而DSP不同,它是非常靈活的,可以保證任何狀況下效率都是最高,當(dāng)然缺點(diǎn)是萬一數(shù)據(jù)和指令錯誤,可能會出現(xiàn)中斷乃至系統(tǒng)崩潰,因此DSP只能執(zhí)行比較簡單純粹的任務(wù)。
程序員在寫程序時,必須保證處理器能夠有效地使用其雙總線。此外,DSP處理器幾乎都不具備數(shù)據(jù)高速緩存。這是因?yàn)镈SP的典型數(shù)據(jù)是數(shù)據(jù)流。也就是說,DSP處理器對每個數(shù)據(jù)樣本做計算后,就丟棄了,幾乎不再重復(fù)使用。 DSP算法的一個共同的特點(diǎn),即大多數(shù)的處理時間是花在執(zhí)行較小的循環(huán)上,也就容易理解,為什么大多數(shù)的DSP都有專門的硬件,用于零開銷循環(huán)。所謂零開銷循環(huán)是指處理器在執(zhí)行循環(huán)時,不用花時間去檢查循環(huán)計數(shù)器的值、條件轉(zhuǎn)移到循環(huán)的頂部、將循環(huán)計數(shù)器減1。
與此相反,GPP的循環(huán)使用軟件來實(shí)現(xiàn)。某些高性能的GPP使用轉(zhuǎn)移預(yù)報硬件,幾乎達(dá)到與硬件支持的零開銷循環(huán)同樣的效果。 GPP的程序通常并不在意處理器的指令集是否容易使用,因?yàn)樗麄円话闶褂孟馛或C++等高級語言。而對于DSP的程序員來說,不幸的是主要的DSP應(yīng)用程序都是用匯編語言寫的(至少部分是匯編語言優(yōu)化的)。
這里有兩個理由:首先,大多數(shù)廣泛使用的高級語言,例如C,并不適合于描述典型的DSP算法。其次,DSP結(jié)構(gòu)的復(fù)雜性,如多存儲器空間、多總線、不規(guī)則的指令集、高度專門化的硬件等,使得難于為其編寫高效率的編譯器。即便用編譯器將C源代碼編譯成為DSP的匯編代碼,優(yōu)化的任務(wù)仍然很重。典型的DSP應(yīng)用都具有大量計算的要求,并有嚴(yán)格的開銷限制,使得程序的優(yōu)化必不可少(至少是對程序的最關(guān)鍵部分)。因此,考慮選用DSP的一個關(guān)鍵因素是,是否存在足夠的能夠較好地適應(yīng)DSP處理器指令集的程序員。
除DSP外,MCU一般也是哈佛架構(gòu),因?yàn)镸CU所需要的數(shù)據(jù)和指令體積都很小,分開存儲也不會增加多少成本。MCU的運(yùn)算能力一般較弱,運(yùn)行頻率較低,一般只有幾十MHz到300MHz,因此運(yùn)算需要高效率,馮諾依曼架構(gòu)不適合。再有就是MCU一般是嵌入式系統(tǒng),電池供電,對功耗要求高,需要低功耗,需要高效率的哈佛架構(gòu)。
三、FPGA
大部分FPGA器件采用了查找表(Look Up Table,LUT)結(jié)構(gòu)。查找表的原理類似于ROM,其物理結(jié)構(gòu)是靜態(tài)存儲器(SRAM),N個輸入項(xiàng)的邏輯函數(shù)能夠由一個2^N位容量的SRAM實(shí)現(xiàn), 函數(shù)值存放在SRAM中,SRAM的地址線起輸入線的作用,地址即輸入變量值,SRAM的輸出為邏輯函數(shù)值。由連線開關(guān)實(shí)現(xiàn)與其它功能塊的連接。
RAM基本的作用就是存儲代碼和數(shù)據(jù)供CPU在需要的時候調(diào)用??墒沁@些數(shù)據(jù)并非像用袋子盛米那么簡單。更像是圖書館中用有格子的書架存放書籍一樣。不但要放進(jìn)去還要可以在需要的時候準(zhǔn)確地調(diào)用出來。盡管都是書可是每本書是不同的。對于RAM等存儲器來說也是一樣的,盡管存儲的都是代表0和1的代碼,可是不同的組合就是不同的數(shù)據(jù)。讓我們又一次回到書和書架上來,假設(shè)有一個書架上有10行和10列格子(每行和每列都有0-9的編號),有100本書要存放在里面,那么我們使用一個行的編號+一個列的編號就能確定某一本書的位置。假設(shè)已知這本書的編號87,那么我們首先鎖定第8行。然后找到第7列就能準(zhǔn)確的找到這本書了。
在RAM存儲器中也是利用了相似的原理。如今讓我們回到RAM存儲器上,對于RAM存儲器而言數(shù)據(jù)總線是用來傳入數(shù)據(jù)或者傳出數(shù)據(jù)的。由于存儲器中的存儲空間是假設(shè)前面提到的存放圖書的書架一樣通過一定的規(guī)則定義的,所以我們能夠通過這個規(guī)則來把數(shù)據(jù)存放到存儲器上相應(yīng)的位置。而進(jìn)行這樣的定位的工作就要依靠地址總線來實(shí)現(xiàn)了。對于CPU來說,RAM就像是一條長長的有非常多空格的細(xì)線。每一個空格都有一個唯一的地址與之相應(yīng)。假設(shè)CPU想要從RAM中調(diào)用數(shù)據(jù),首先需要給地址總線發(fā)送地址數(shù)據(jù)定位要存取的數(shù)據(jù),然后等待若干個時鐘周期之后,數(shù)據(jù)總線就會把傳輸數(shù)據(jù)給CPU。
FPGA是基于邏輯門和觸發(fā)器的,它是并行執(zhí)行方式,沒有取指到執(zhí)行這種操作。簡單而言,就是通過燒寫文件去配置查找表的內(nèi)容,從而在相同的電路情況下實(shí)現(xiàn)了不同的邏輯功能,數(shù)字電路中所有邏輯門和觸發(fā)器均可以實(shí)現(xiàn),適合真正意義上的并行任務(wù)處理。FPGA程序在編譯后實(shí)際上是轉(zhuǎn)換為內(nèi)部的連線表,相當(dāng)于FPGA內(nèi)部提供了大量的與非門、或非門、觸發(fā)器等基本數(shù)字邏輯器件,編程決定了有多少器件被使用以及它們之間的連接方式。
通過編程,用戶可對FPGA內(nèi)部的邏輯模塊和I/O模塊重新配置,以實(shí)現(xiàn)用戶的邏輯。它還具有靜態(tài)可重復(fù)編程和動態(tài)在系統(tǒng)重新配置的特性,使得硬件的功能可以像軟件一樣通過編程來修改。只要FPGA規(guī)模夠大,這些數(shù)字器件理論上能形成一切數(shù)字系統(tǒng),包括MCU,甚至CPU。因FPGA是純數(shù)字電路,在抗干擾和速度性能上有很大優(yōu)勢。 FPGA沒有取指到執(zhí)行這種操作,效率極高,功耗很低,又是天生的并行計算結(jié)構(gòu)。
但是FPGA采用的是統(tǒng)計型連線結(jié)構(gòu)。這類器件具有較復(fù)雜的可編程布線資源,內(nèi)部包含多種長度的金屬連線,從而使片內(nèi)互連十分靈活。因此每次編程后的連線可不盡相同。但是這些布線資源消耗了很大一部分芯片面積,而ASIC只需要選用最短長度的布線即可,面積大大縮小,同樣密度,ASIC大約可以縮小40%的面積,這就意味著FPGA比ASIC要貴40%左右,F(xiàn)PGA的算力達(dá)到一定程度后,再增加算力,價格會飛速增長。