微處理器設計/計算機體系結構
在計算機科學的早期,計算機程式是硬連線的,只使用記憶體來儲存資料。重新程式設計計算機涉及手動更改硬體開關,這需要花費大量的時間,並且有很高的程式碼錯誤可能性。為了解決這些問題,數學家和計算機科學家 約翰·馮·諾依曼 提出了現在被稱為 馮·諾依曼體系結構 的體系結構,該體系結構將程式儲存在記憶體中,從而避免了將它們硬連線的需要。
在馮·諾依曼體系結構中,一個稱為 微處理器 的電路用於處理程式指令並執行它們。為了執行程式,微處理器首先從記憶體中獲取程式的指令以及執行這些指令所需的資料。然後,微處理器解碼和分離指令和資料,並激活執行程式所需的必要元件和通路。最後,微處理器執行程式,遍歷指令,操作資料並存儲結果。
這個獲取、解碼和執行的三步過程通常用兩個硬體元件實現:控制單元和資料通路。如果資料被認為是水,那麼資料通路就像一條有很多分支的運河,而控制單元就像一系列水閘。控制單元讀取從記憶體中獲取的指令,並使用它們來指導資料在資料通路中的流動方向。在此過程中,資料通路的不同分支將包含不同的機制來修改和轉換流經它的資料。這些機制被稱為 算術邏輯單元 (ALU)(稍後將更深入地討論),它們對流經資料通路的 data 執行算術運算(如加法、減法、移位和求反)和邏輯運算(如 AND 和 OR)。
對控制單元和資料通路更細緻的討論將在後面一節中進行,該節的標題很方便,稱為 控制和資料通路。
在 **哈佛體系結構** 機器中,計算機系統的記憶體被分成兩個獨立的部分:資料和指令。在純哈佛系統中,這兩個不同的記憶體佔用獨立的記憶體模組,並且指令只能從指令記憶體中執行。
許多 DSP 是修改後的哈佛體系結構,設計為同時訪問三個不同的記憶體區域:程式指令、訊號資料樣本和濾波器係數(通常稱為 P、X 和 Y 記憶體)。
理論上,這種三路哈佛體系結構可以比馮·諾依曼體系結構快三倍,後者必須一次讀取指令、資料樣本和濾波器係數。
現代臺式計算機,尤其是基於英特爾 x86 ISA 的計算機,不是哈佛計算機,儘管較新的變體具有“哈佛式”的特性。所有資訊、程式指令和資料都儲存在同一個 RAM 區域中。但是,現代稱為“分頁”的功能允許物理記憶體被分割成稱為“頁面”的大塊記憶體。每個記憶體頁面可以是指令或資料,但不能兩者兼而有之。
然而,現代嵌入式計算機通常基於哈佛體系結構。指令儲存在與資料不同的可定址記憶體塊中,微處理器無法互換資料和指令。
從歷史上看,第一種型別的 ISA(指令集體系結構)是 **複雜指令集計算機** (CISC),第二種型別是 **精簡指令集計算機** (RISC)。一個常見的誤解是 RISC 系統通常具有較小的 ISA(更少的指令),但用更快的硬體彌補了這一點。RISC 系統實際上具有“精簡指令”,因為每條指令的功能很少,以至於執行起來只需要很少的時間。一個常見的誤解是 CISC 系統有更多的指令,但通常會為增加的靈活性付出很高的效能代價。CISC 系統實際上具有“複雜指令”,因為至少有一條指令需要很長時間才能執行,例如,“雙重間接”定址模式本質上需要兩個記憶體週期才能執行,而一些 CPU 具有“字串複製”指令,這可能需要數百個記憶體週期才能執行。MIPS 和 SPARC 是 RISC 計算機的例子。英特爾 x86 是 CISC 計算機的一個例子。
有些人將堆疊機與 RISC 機歸為一類;另一些人 [1] 將堆疊機與 CISC 機歸為一類;有些人 [2],[3] 將堆疊機描述為既不是 RISC 也不是 CISC。
其他 ISA 型別包括 DSP、堆疊機、VLIW 機、MISC 機、TTA 體系結構、大規模並行處理器陣列等。
我們將在 稍後 更詳細地討論這些術語和概念。
微處理器的一些常見元件是
- 控制單元
- I/O 單元
- 算術邏輯單元 (ALU)
- 暫存器
- 快取
下面簡要介紹這些元件。
如上所述,控制處理單元讀取指令並生成操作其他元件所需的數字訊號。例如,將兩個數字加在一起的指令將導致控制單元啟用加法模組。
處理器需要能夠與計算機系統的其他部分進行通訊。這種通訊透過 I/O 埠進行。I/O 埠將與系統記憶體 (RAM) 以及計算機的其他外設介面。
算術邏輯單元 (ALU) 是微處理器執行算術運算的部分。ALU 通常可以執行兩個數字的加、減、除、乘以及邏輯運算(與、或、非、異或等)。
ALU will be discussed in far more detail in a later chapter, ALU.
有不同型別的暫存器。從上下文中可以很容易地看出我們指的是哪種型別的暫存器。
最一般的含義是“硬體暫存器”:任何可以用來儲存資訊位的器件,並且所有位可以同時寫入或讀出。由於 CPU 外部的暫存器也超出了本書的範圍,因此本書只討論處理器暫存器,它們是硬體暫存器,恰好位於 CPU 內部。但通常我們會參考更具體的暫存器型別。
暫存器在後面的一章暫存器檔案中會有更詳細的介紹。
程式設計師可見暫存器,也稱為使用者可訪問暫存器,也稱為架構暫存器,通常簡稱為“暫存器”,是指直接作為指令集中至少一條指令的一部分編碼的暫存器。
暫存器是最快的可訪問記憶體位置,因為它們非常快,所以通常數量很少。在大多數處理器中,暫存器的數量不到 32 個。暫存器的大小定義了計算機的大小。例如,一個“32 位計算機”的暫存器長度為 32 位。暫存器的長度被稱為計算機的字長。
限制暫存器數量的因素有很多,包括:
- 對於一個新的 CPU,與舊 CPU 的軟體相容性非常重要。這要求新晶片的程式設計師可見暫存器數量與舊晶片完全相同。
- 將通用暫存器的數量翻倍,需要為每條指令新增一個額外的位,用於選擇特定的暫存器。每個三運算元指令(指定兩個源運算元和一個目標運算元)將擴充套件 3 位。現代晶片製造工藝可以在一個晶片上放置一百萬個暫存器;這將使每個三運算元指令都需要 60 位來選擇暫存器,不包括指定對這些運算元執行什麼操作所需的位。
- 新增更多暫存器會為關鍵路徑新增更多線,增加電容,從而降低 CPU 的最大時鐘速度。
- 從歷史上看,CPU 的設計暫存器數量很少,因為每個額外的暫存器都會大幅增加 CPU 的成本。但現在,現代晶片製造工藝可以在單個商品 CPU 晶片上放置數千萬個儲存位,所以這已經不再是一個問題。
微處理器通常包含大量的暫存器,但只有少數暫存器可供程式設計師訪問。程式設計師可以用來根據需要儲存任意資料的暫存器稱為通用暫存器。程式設計師無法直接訪問的暫存器稱為保留暫存器[需要引用]。
有些計算機有高度專門化的暫存器——記憶體地址總是來自程式計數器或“該”索引暫存器或“該”堆疊指標;一個 ALU 輸入總是連線到來自記憶體的資料,另一個 ALU 輸入總是連線到“該”累加器;等等。
其他計算機有更多通用的暫存器——任何訪問記憶體的指令都可以使用任何地址暫存器作為索引暫存器或堆疊指標;任何使用 ALU 的指令都可以使用任何資料暫存器。
其他計算機具有完全通用的暫存器——任何暫存器都可以用作任何指令中的資料或地址,不受限制。
除了程式設計師可見暫存器,所有 CPU 都有其他程式設計師不可見的暫存器,稱為“微架構暫存器”或“物理暫存器”。
這些暫存器包括:
- 記憶體地址暫存器
- 記憶體資料暫存器
- 指令暫存器
- 微指令暫存器
- 微程式計數器
- 流水線暫存器
- 支援暫存器重新命名的額外物理暫存器
- 預取輸入佇列
- 可寫控制儲存器(我們將在微處理器設計/控制單元和微處理器設計/微程式碼中討論控制儲存器)
- 有些人認為片上快取是微架構暫存器的一部分;而另一些人則認為它位於 CPU “外部”。
實現任何一種指令集的方法有很多。絕大多數這些微架構暫存器在技術上並非“必需”。設計人員可以選擇設計一個幾乎沒有物理暫存器(除了程式設計師可見暫存器)的 CPU。然而,許多設計人員選擇設計一個包含大量物理暫存器的 CPU,以利用這些暫存器以比沒有這些暫存器的 CPU 更快的速度執行相同的指令集。
大多數製造的 CPU 都沒有快取。
快取是指位於晶片上的記憶體,但並不被視為暫存器。快取的使用是因為讀取外部記憶體速度非常慢(與處理器的速度相比),而讀取本地快取速度快得多。在現代處理器中,快取可能佔晶片總面積的 50% 或更多。下表顯示了不同型別記憶體之間的關係
| 最小 | 最大 | |
| 暫存器 | 快取 | RAM |
| 最快 | 最慢 |
快取通常有 2 或 3 個“級別”,具體取決於晶片。級別 1 (L1) 快取比級別 2 (L2) 快取更小更快,而級別 2 (L2) 快取更大更慢。有些晶片也有級別 3 (L3) 快取,它比 L2 快取更大(儘管 L3 快取仍然比外部 RAM 快得多)。
我們將在後面的章節快取中更詳細地討論快取。
不同的計算機以不同的方式在 RAM 中排列其多位元組資料字(即 16 位、32 位或 64 位字)。多位元組字中的每個單獨位元組仍然是可單獨定址的。一些計算機以最高有效位元組在最低地址的方式排列資料,而另一些計算機以最高有效位元組在最高地址的方式排列資料。兩種方法都有其背後的邏輯,這曾經是激烈爭論的話題。
這種區別被稱為位元組序。以最低有效位元組在最低地址的方式排列資料的計算機被稱為“小端”,而以最高有效位元組在最低地址的方式排列資料的計算機被稱為“大端”。對於人類(通常是程式設計師)來說,如果以大端方式排列多字資料並將其轉儲到螢幕上,以逐位元組的方式顯示資料會更容易。但是對於其他人來說,將 LS 資料儲存在 LS 地址更有意義。
在使用計算機時,這種區別通常是透明的;也就是說使用者無法區分使用不同格式的計算機。但是,當不同型別的計算機嘗試透過網路相互通訊時,就會出現問題。
對於使用大端 68K 的機器來說,
address increases > ------ >
data : 74 65 73 74 00 00 00 05
字串“test”後跟 32 位整數 5。小端序 x86 類機器會將最後部分解釋為整數 0x0500_0000。
在由大端序和和小端序機器組成的網路上通訊時,網路硬體(應該)應用地址不變性原則,以避免文字混亂(避免 NUXI 問題)。高階軟體(應該)將要傳輸到網路的資料包格式化為網路位元組序。高階軟體(應該)編寫為“端序無關” - 始終將 16 位整數讀取和寫入為完整的 16 位整數,將 32 位整數讀取和寫入為完整的 32 位整數等 - 因此,無需更改即可為大端序或小端序機器重新編譯。不是“端序無關”的軟體 - 寫入整數,然後將其讀出為 8 位位元組或其他長度的整數的軟體 - 通常在為另一臺計算機重新編譯時會失敗。
一些計算機 - 包括幾乎所有 DSP - 是“非端序”的。它們始終讀取和寫入完整對齊的字,並且沒有處理單個位元組的硬體。在這些計算機上構建的系統通常*確實*具有特定的端序 - 但這種端序是寫入軟體中的,可以透過重新編譯以相反的端序來切換。
堆疊是一塊用作草稿區的記憶體。堆疊是一組連續的記憶體位置,設定為充當 LIFO(後進先出)緩衝區。資料透過“壓入”操作新增到堆疊頂部,而頂部資料項在“彈出”操作期間從堆疊中刪除。大多數計算機體系結構至少包含一個通常為堆疊指標保留的暫存器。
一些微處理器在 CPU 中包含一個獨立於 RAM 的小型硬體堆疊。
有些人聲稱處理器必須具有硬體堆疊才能執行 C 程式。[1]
大多數計算機體系結構在其 組合語言 中對遞迴“呼叫”指令提供硬體支援。一些體系結構(如 ARM、Freescale RS08 等)以這種方式實現“呼叫”
- “呼叫”指令將返回地址壓入連結暫存器並跳轉到子程式。子程式開頭附近的單獨指令將連結暫存器的內容壓入主記憶體中的堆疊,以釋放連結暫存器,以便子程式可以遞迴呼叫其他子程式。
一些體系結構(如 6502、x86 等)以這種方式實現“呼叫”
- “呼叫”指令將返回地址壓入主記憶體中的堆疊並跳轉到子程式。
一些體系結構(如 PIC16、RISC I 處理器、Novix NC4016、許多 LISP 機器等)以這種方式實現“呼叫”
- “呼叫”指令將返回地址壓入一個專用的返回堆疊(獨立於主記憶體)並跳轉到子程式。