微處理器設計/指令集架構
指令集或指令集架構 (ISA) 是處理器理解的基本指令集。指令集是構成架構的一部分。
歷史上,指令集的最初兩種哲學是:簡化 (RISC) 和複雜 (CISC)。兩種哲學的優點和爭論的效能優勢一直受到深入的討論。
複雜指令集計算機 (CISC) 來源於計算的歷史。最初沒有編譯器,程式必須手動逐條指令編碼。為了簡化程式設計,增加了越來越多的指令。其中許多指令是複雜的組合指令,例如迴圈。一般來說,更復雜或更專門的指令在硬體中效率低下,在典型的 CISC 架構中,可以使用 ISA 中最簡單的指令才能獲得最佳效能。
最知名/商品化的 CISC ISA 是 Motorola 68k 和 Intel x86 架構。
精簡指令集計算機 (RISC) 是由 IBM 在 1970 年代後期實現的。研究人員發現,大多數程式都沒有利用所有可用於指令的各種定址模式。透過減少定址模式的數量並將多週期指令分解為多個單週期指令,可以實現以下幾個優勢
- 編譯器更容易編寫(更容易最佳化)。
- 對於執行簡單操作的程式,效能得到提升。
- 由於最小迴圈時間由執行時間最長的指令決定,因此可以提高時鐘頻率。
最知名/商品化的 RISC ISA 是 PowerPC、ARM、MIPS 和 SPARC 架構。
我們將在後面的章節中討論VLIW 處理器。
我們將在後面的章節中討論向量處理器。
計算 RAM (C-RAM) 是將處理器整合到設計的半導體隨機存取儲存器,用於構建廉價的大規模平行計算機。
指令通常在記憶體中按順序排列。每個指令佔用 1 個或多個計算機字。程式計數器 (PC) 是微處理器內部的一個暫存器,它包含當前指令的地址。[1] 在取指週期中,從程式計數器指示的地址讀取記憶體中的指令到指令暫存器 (IR) 中,程式計數器增加 n,其中 n 是機器的字長(以位元組為單位)。
除了可執行指令的取指之外,許多(但不是全部)指令還會從記憶體中取指資料值(“載入”)到資料暫存器,或者將資料值從資料暫存器寫入記憶體(“儲存”)。在這樣的載入或儲存指令中訪問的特定記憶體字的地址稱為“有效地址”。在最簡單的指令集中,有效地址始終包含在某個地址暫存器中。其他指令集具有更復雜的“有效地址”計算 - 我們將在後面討論這些“定址模式”。
移動指令導致將一個暫存器中的資料移動或複製到另一個暫存器。載入指令將資料從外部源(例如記憶體)放入暫存器。儲存指令將資料從暫存器移動到外部目標。
將資料從一個地方移動(或複製)到另一個地方的指令是大多數程式中使用頻率最高的指令。[2]
分支和跳轉是將 PC 暫存器載入到一個新的地址的能力,這個地址不是下一個順序地址。通常,"跳轉"或"呼叫"無條件發生,而"分支"在給定條件下發生。在這本書中,我們將一般地將兩者都稱為分支,其中“跳轉”是無條件分支。
“呼叫”指令是分支指令,其額外作用是將當前地址儲存到特定位置(例如將其壓入堆疊),以便於輕鬆返回以繼續執行。“呼叫”指令通常與“返回”指令匹配,該指令檢索儲存的地址並恢復執行。
“中斷”指令是呼叫預設位置的指令,通常是某種方式編碼在指令本身中的指令。這通常用於訪問常用的資源,例如作業系統。通常,透過中斷指令進入的例程透過中斷返回指令退出,該指令與返回指令類似,它檢索儲存的地址並恢復執行。
在許多程式中,“呼叫”是第二常用的指令(僅次於“移動”)。[2]
算術邏輯單元 (ALU) 用於執行算術和邏輯指令。ALU 的功能通常隨著更高階的中央處理器而增強,但 RISC 機器的 ALU 故意保持簡單,因此只具有一些功能。ALU 至少會執行加法、減法、非、與、或和異或,通常也會執行單位元旋轉和移位。許多 CISC 機器 ALU 還可以執行多位元旋轉和移位(使用桶形移位器)以及整數乘法和除法。雖然許多現代 CPU 也可以執行浮點數學運算,但這些通常由 FPU 處理,FPU 是機器的不同部分。我們在ALU 設計章節中更詳細地描述了 ALU。
輸入指令從指定的輸入埠獲取資料,而輸出指令將資料傳送到指定的輸出埠。輸入/輸出空間和記憶體空間之間的區別很小,微處理器提供一個地址,然後從資料匯流排接收資料或向資料匯流排傳送資料,但是輸入/輸出空間中可用的操作型別通常比記憶體空間中可用的操作型別更有限。
NOP,是“無操作”的縮寫,是一種不產生結果也不產生副作用的指令。NOP 在計時和防止危險方面很有用。
人們平衡各種指令長度的各種優缺點,有幾種不同的方法。

對於 CPU 來說,固定長度指令比可變寬度指令更容易處理,原因有以下幾點,因此在一定程度上更容易最佳化速度。例如:具有可變長度指令的 CPU 必須檢查每個指令是否跨越快取行或虛擬記憶體頁邊界;具有固定長度指令的 CPU 可以跳過所有這些。[3]
在 16 位指令中,沒有足夠的位來容納 32 個通用暫存器,而且還做“Ra = Rb (op) Rc”Template:Snd,即獨立地從 32 個通用暫存器組中選擇 2 個源暫存器和 1 個目標暫存器,並獨立地選擇幾種 ALU 操作之一。
因此,設計指令集的人員必須做出以下一項或多項折衷
- 犧牲程式碼密度,使用更長的固定寬度指令,通常為 32 位,例如 MIPS、DLX 和 ARM。
- 犧牲固定寬度指令,需要更復雜的解碼器來處理短的 16 位指令和更長的 3 運算元指令,例如 ARM Thumb。
- 犧牲 3 運算元,在所有指令中使用不超過 2 個運算元,例如 Atmel AVR。3 運算元指令可以更好地重用資料;[3]沒有 3 運算元指令,程式偶爾需要額外的複製指令,當某些 ALU 操作的兩個可變輸入運算元都需要為某些後面的指令保留時。
- 犧牲暫存器,因此只有 16 或 8 個程式設計師可見的暫存器。
- 犧牲通用暫存器的概念——也許只有 16 或 8 個“資料暫存器”對 3 運算元 ALU 指令可見,就像在 68000 中一樣,或者目標暫存器僅限於一個或兩個“累加器”,但其他暫存器(例如“地址暫存器”)對其他指令可見。
對於任何一個特定的 CPU,任何一個特定的機器語言指令通常可以細分為欄位。例如,在“ADD”指令中的某些位指示操作——這實際上是一個“ADD”而不是一個“XOR”或“減法”指令。其他位指示哪個暫存器是源暫存器,其他位指示哪個暫存器是目標暫存器,等等。
一些處理器不僅具有固定的指令寬度,而且還具有單一指令格式——一組固定的欄位,對於每個指令都是相同的。
許多處理器具有固定的指令寬度,但具有多種指令格式。儲存在特定固定位置“指令型別”欄位中的實際位(該欄位在該 CPU 的每個指令中都位於相同的位置)指示該特定指令使用哪種指令格式——該指令使用哪種特定欄位佈局。例如,MIPS 處理器具有 R 型、I 型、J 型、FR 型和 FI 型指令格式。[4] 例如,J1 處理器具有 3 種指令格式:Literal、Branch 和 ALU。[5] 例如,Microchip PIC 中檔具有 4 種指令格式:位元組定向暫存器操作、位定向暫存器操作、8 位字面量操作和具有 11 位字面量的分支指令。[6]
偶爾,一些新的 CPU 會與其他 CPU 具有不同的指令集格式,使其與其他 CPU“不相容”。但是,有時可以設計這種新的 CPU 使其與其他 CPU 具有“原始碼向後相容性”——它與為其他 CPU 編寫的程式“相容組合語言,但不相容二進位制”。(例如,8080 與 8008 原始碼相容,但不相容二進位制,或者 8086 與為 8085、8080 和 8008 編寫的程式原始碼相容,但不相容二進位制 [需要引用])。
- ↑ 實際上,所有現代 CPU 都保持程式計數器順序遍歷程式碼一次執行一條指令的假象。但是,一些複雜的現代 CPU 在內部同時執行多個指令(超標量),或亂序執行指令,甚至推測性地預執行“錯誤”路徑上的指令,然後備份並採取正確的路徑。在設計和測試這種內部結構時,“PC”的概念有點模糊。一些處理器架構,例如 CDP1802,沒有單個程式計數器;相反,通用暫存器之一用作程式計數器,而哪個暫存器可以由程式控制更改。
- ↑ a b Peter Kankowski。 "x86 機器碼統計"
- ↑ a b IBM 的 RISC 技術發展——IBM 研究與開發雜誌,第 44 卷,第 1/2 期,第 48 頁 (2000)
- ↑ MIPS 彙編/指令格式
- ↑ Victor Yurkovsky。 "自制 CPU:使用 J1 胡鬧"
- ↑ "PICmicro 中檔 MCU 系列:第 29 節 指令集" 第 29.2 節 指令格式。