|
指令集是處理器體系架構(gòu)的重要組成部分。指令集有兩個(gè)發(fā)展方面,包括以X86為代表的CISC(復(fù)雜指令集)和以ARM、MIPS為代表的RISC(精簡(jiǎn)指令集)。CISC的目標(biāo)是盡可能將常用的功能用最少甚至一條指令來(lái)實(shí)現(xiàn),因此該指令對(duì)應(yīng)的執(zhí)行電路往往是復(fù)雜的,其側(cè)重的是硬件功能的實(shí)現(xiàn);RISC則相反,其是將復(fù)雜的執(zhí)行電路進(jìn)行分解,即用盡可能簡(jiǎn)單的多指令去描述該功能,以軟件來(lái)降低硬件的復(fù)雜度,因此RISC對(duì)編譯器的要求比較高。CISC的指令長(zhǎng)度是可變的,執(zhí)行周期也不固定,而RISC則是定長(zhǎng)的、往往都是單周期執(zhí)行。寄存器多也是RISC的特點(diǎn)。 本文的重點(diǎn)不在于詳細(xì)比較RISC和CISC,而是介紹CPU指令的編碼和譯碼。我們都知道CPU的流水線執(zhí)行過(guò)程有取指、譯碼、執(zhí)行、訪存和回寫(參看博文: CPU指令的流水線執(zhí)行),但很多人對(duì)于這些步驟的理解都僅僅在概念層面上的,有必要對(duì)其進(jìn)行詳細(xì)闡述,理解CPU指令的設(shè)計(jì)和實(shí)現(xiàn)。
我們都知道C語(yǔ)言是對(duì)現(xiàn)實(shí)問(wèn)題的解決方法和過(guò)程的高度抽象,其語(yǔ)法主要包括數(shù)值、邏輯運(yùn)算和分支控制轉(zhuǎn)移。數(shù)值運(yùn)算就是加減乘除(比較也是減法),邏輯運(yùn)算就是與、或、非、異或等,分支控制轉(zhuǎn)移包括if/else、for、while等語(yǔ)法。匯編語(yǔ)言是在機(jī)器層面上對(duì)C語(yǔ)言的理解和建構(gòu),其指令同樣也包括數(shù)值、邏輯運(yùn)算、分支控制轉(zhuǎn)移,但是一行C語(yǔ)言可能需要多條匯編指令才能實(shí)現(xiàn)。同時(shí)由于指令在內(nèi)存上,而CPU訪問(wèn)寄存器要比訪問(wèn)內(nèi)存要快得多,所以CPU的運(yùn)算一般都在寄存器中進(jìn)行,因此匯編語(yǔ)言一般都需要增加內(nèi)存和寄存器直接的數(shù)據(jù)加載/存儲(chǔ)指令。CPU只認(rèn)識(shí)二進(jìn)制輸入,所以可以把匯編語(yǔ)言當(dāng)次硬件層面上的偽代碼,其便于開(kāi)發(fā)人員熟記,同樣是低級(jí)語(yǔ)言。
指令的編碼就是實(shí)現(xiàn)匯編語(yǔ)言到二進(jìn)制機(jī)器碼的過(guò)程,其是匯編器實(shí)現(xiàn)的(編譯器是將C語(yǔ)言轉(zhuǎn)為匯編語(yǔ)言)。 現(xiàn)在假設(shè)某種簡(jiǎn)單的CPU只支持4種功能: 包括
1)加法 ADD Rd,Rs,Rn , 結(jié)果是Rd=Rs+Rn
2)減法 SUB Rd,Rs,Rn ,結(jié)果是Rd=Rs-Rn
3)數(shù)據(jù)傳送 MOV Rd,Rs,結(jié)果是Rd=Rs
4)數(shù)據(jù)加載 LDR Rd,[Rs],結(jié)構(gòu)是將內(nèi)存中以Rs寄存器的值為地址取值賦給Rd
如何進(jìn)行編碼呢?
1)首先將指令分為操作碼+操作數(shù)兩個(gè)部分,操作碼即代表指令功能,如ADD、SUB等,其在CPU中就代表某種具體的電路,如ADD就代表加法電路,SUB代表減法電路;操作數(shù)即是代表功能的輸入和輸出,對(duì)應(yīng)電路的輸入和輸出。
2)現(xiàn)在共有4種功能,那至少需要2個(gè)比特來(lái)進(jìn)行編碼,如00代表ADD,01代表SUB,10代表MOV,11代表LDR;
3)操作數(shù)的編碼,假設(shè)寄存器共有8個(gè),Rd,Rs,Rn都是其中的一個(gè),即d,s,n的范圍是0到7,那至少需要3個(gè)比特來(lái)編碼,如000代表R0,001代表R1,以此類推,111代表R7.
那要實(shí)現(xiàn)以上四種功能指令,總共需要2+3+3+3=11個(gè)比特進(jìn)行編碼。如SUBR6,R1,R2,即R1減去R2的值賦給R7,那其編碼就是01 110 001 010.
理解完指令的編碼,那指令的譯碼應(yīng)該是比較好理解的。取指就是根據(jù)當(dāng)前程序計(jì)數(shù)寄存器PC(假設(shè)硬件電路規(guī)定R7就是寄存器PC)的值從內(nèi)存中取出機(jī)器碼指令,該機(jī)器碼的值是01 110 001010。接下來(lái)的過(guò)程就是譯碼,即根據(jù)最先的兩個(gè)比特01送入譯碼器,選擇為減法電路;110即譯碼選擇為R6,001譯碼選擇R1,010譯碼選擇R2.再接著的就是指令的執(zhí)行了,執(zhí)行就是減法單元電路對(duì)兩個(gè)輸入(R1,R2)進(jìn)行運(yùn)算,將結(jié)果賦給R6.
取指和譯碼都是CPU的 控制單元(CU)完成的,執(zhí)行是ALU(邏輯運(yùn)算單元)完成,可以將ALU看出是很多種電路的集合。CPU指令的設(shè)計(jì)和指令編碼息息相關(guān)。
ARM和MIPSCPU都是32位字長(zhǎng),因此指令編碼是32比特,能夠支持和表達(dá)更多的功能(操作碼)和寄存器(操作數(shù))。如ARM體系是r0到r15,因此需要4個(gè)比特來(lái)表示,當(dāng)然ARM的寄存器還有組的概念,即CPU在不同的工作模式時(shí)看到的寄存器可能是不同的,如r13,r14等。這些譯碼時(shí)不僅需要指令操作數(shù)作為輸入,還需要當(dāng)前狀態(tài)寄存器的值作為輸入。
16位指令集是因?yàn)槭裁串a(chǎn)生的呢?是因?yàn)橥瑯拥囊欢蜟語(yǔ)言代碼,用16位指令進(jìn)行編碼比32位編碼能夠節(jié)省30%的代碼量,代碼量越少,那占用的內(nèi)存就越少,自然成本越低。在MCU領(lǐng)域,一般都是成本敏感的,所以16為指令在MCU領(lǐng)域有非常廣泛的使用。
ARM和MIPS的指令設(shè)計(jì)是以32位為基礎(chǔ)進(jìn)行設(shè)計(jì),其執(zhí)行也是32作為輸入的,那如何在32位指令集中實(shí)現(xiàn)16位呢?我們都知道二八原理,即20%的指令的使用率會(huì)達(dá)到80%,所以我們對(duì)這20%的指令(其是32位指令的一個(gè)子集)進(jìn)行編碼,自然可以用較少的比特?cái)?shù)來(lái)進(jìn)行編碼,而在16位指令使用時(shí),我們可以強(qiáng)制要求其只使用一部分寄存器,那自然可以以更少的比特?cái)?shù)來(lái)進(jìn)行寄存器的編碼?梢詫16位指令集看成是32位指令集的一個(gè)子集,CPU在譯碼階段先將16為指令轉(zhuǎn)化為對(duì)應(yīng)的32位指令,再進(jìn)行譯碼、執(zhí)行。
ARM的16位指令集為thumb指令集,MIPS的16為指令集為MIPS16指令集。至于32位指令集和16位指令集之間的無(wú)縫切換,請(qǐng)參看另一篇博文:32位和16位指令集模式自動(dòng)切換機(jī)制。
|
|