計算機原理學習(1)-- 馮諾依曼體系和CPU工作原理
前言
對於我們80後來說,最早接觸計算機應該是在95年左右,那個時候最流行的一個詞語是多媒體。 依舊記得當時在同學家看同學輸入幾個DOS命令就成功的打開了一個遊戲,當時實在是佩服的五體投地。因為對我來說,螢幕上的東西簡直就是天書。有了計算機我們生活發生了巨大的變化,打遊戲,上網,聊天,甚至到現在以此為業。有時無不感嘆計算機的強大。
人類總是聰明的而又懶惰的。即便是1+1這種簡單的計算都不想自己做,1623年Wilhelm Schickard 製作了一個能進行六位以內數加減法,並能通過鈴聲輸出答案的"計算鍾"。通過轉動齒輪來進行操作。 這已經相當高端了,說起計算器,我們5000年文明古國在東漢末年就有記載了---
計算機的發展也是隨著科技的發展經歷了機械計算機、電子計算機、電晶體計算機、小規模積體電路和超大規模積體電路計算機。我們無意討論整個計算機的發展過程,主要還是介紹基於馮諾依曼體系結構的現代計算機。
1. 計算機的發展
計算機的發展包括了硬體和軟體的發展,硬體的發展為計算機提供了更快的處理速度,而軟體的發展為使用者提供了更好的體驗。兩者相輔相成,密不可分。
-
第一階段: 60年代中期以前,是計算機系統發展的早期時代。在這個時期通用硬體已經相當普遍,軟體卻是為每個具體應用而專門編寫的,大多數人認為軟體開發是無需預先計劃的事情。這時的軟體實際上就是規模較小的程式,程式的編寫者和使用者往往是同一個(或同一組)人;
-
第二階段:從60年代中期到70年代中期,是計算機系統發展的第二代。在這10年中計算機技術有了很大進步。多道程式、多使用者系統引入了人機互動的新概念,開創了計算機應用的新境界,使硬體和軟體的配合上了一個新的層次;
-
第三階段:計算機系統發展的第三代從20世紀70年代中期開始,並且跨越了整整10年。在這10年中計算機技術又有了很大進步。分散式系統極大地增加亍計算機系統的複雜性,區域網、廣域網、寬頻數字通訊以及對“即時”資料訪問需求的增加,都對軟體開發者提出了更高的要求;
-
第四階段:在計算機系統發展的第四代已經不再看重單臺計算機和程式,人們感受到的是硬體和軟體的綜合效果。由複雜作業系統控制的強大的桌面機及區域網和廣域網,與先進的應用軟體相配合,已經成為當前的主流。計算機體系結構已迅速地從集中的主機環境轉變成分佈的客戶機/伺服器。
2. 計算機基本原理
Copy了點計算機的發展歷史,現在可以來看看計算機的基本工作原理了。現代計算機,大部分都是基於馮諾依曼體系結構,而我們這裡談論的也是此問前提。馮諾依曼的核心是:儲存程式,順序執行。所以不管計算機如何發展,基本原理是相同的。計算機程式實際上是告訴計算機做什麼。
2.1 馮諾依曼體系結構
馮諾依曼體系結構有以下特點:
- 計算機處理的資料和指令一律用二進位制數表示;
- 指令和資料不加區別混合儲存在同一個儲存器中;
- 順序執行程式的每一條指令;
- 計算機硬體由運算器、控制器、儲存器、輸入裝置和輸出裝置五大部分組成。
馮諾依曼體系結構的計算機必須具有如下功能:
- 把需要的程式和資料送至計算機中;
- 必須具有長期記憶程式、資料、中間結果及最終運算結果的能力;
- 能夠完成各種算術、邏輯運算和資料傳送等資料加工處理的能力;
- 能夠根據需要控制程式走向,並能根據指令控制機器的各部件協調操作;
- 能夠按照要求將處理結果輸出給使用者。
2.2 計算機工作原理
對於我們現代計算機來說,最關鍵的2個部件就是CPU和記憶體。記憶體儲存了要執行的程式指令,而CPU就是用來執行這些指令。CPU首先要知道這些指定存放在儲存器的那個區域,然後才能執行,並且把執行的結果寫入到執行區域。
2.2.1 CPU指令和程式語言
在瞭解CPU和儲存器工作原理之前,先來了解一下CPU指令和我們程式語言之間的一些關係。
2.2.1.1 CPU指令
因為在計算機中指令和資料都用二進位制來表示,也就是說它只認識0和1這樣的數字。最早期的計算機程式通過在紙帶上打洞來人工操操作的方式來模擬0和1,根據不同的組合來完成一些操作。後來直接通過直0和1程式設計程式,這種稱之為機器語言。這裡就會有一個疑問,計算機怎麼知道你這些組合的意思?
於是就出現了CPU指令,我們現在買CPU都會聽到指令集這一說。CPU指令其實就對應了我們這裡說的0和1的一些組合。每款CPU在設計時就規定了一系列與其硬體電路相配合的指令系統。有了CPU指令集的文件你就可以通過這個編寫CPU認識的機器程式碼了。所以對於不同CPU來說可能會有不同的機器碼。比如下面我們就定義了一套我們CPU硬體電路可以完成的CPU指令。
指令 | 格式 | 說明 |
0001 | [address][register] | 讀取儲存取值到暫存器 |
0010 | [register][address] | 寫入暫存器的值到儲存器 |
0011 | [register1][register2] | 加法操作 |
隨著計算機的發展,CPU支援的指令也越來越多,功能也越來越強,上圖就是現在Core I5處理器支援的指令集。
2.2.1.2 組合語言
使用0和1這樣的機器語言好處是CPU認識,可以直接執行,但是對於程式本身來說,沒有可讀性,難以維護,容易出錯。所以就出現了組合語言,它用助記符(代替操作碼指令,用地址符號代替地址碼。實際是對機器語言的一種對映,可讀性高。
指令 | 彙編指令 | 格式 | 說明 |
---|---|---|---|
0001 | READ | [addLable][regLab] | 讀取儲存取值到暫存器 |
0010 | WRITE | [addLable][regLab] | 寫入暫存器的值到儲存器 |
0011 | ADD | [var1][var2] | 加法操作 |
把組合語言轉換為機器語言需要一個叫做彙編器的工具。對於目前的CPU廠商,在推出的CPU指令時都會同時退出新的彙編器。如果你還在使用老版本的彙編器那麼只能使用機器碼來使用新的指令了。
2.2.1.3 高階語言
組合語言的出現大大提高了程式設計效率,但是有一個問題就是不同CPU的指令集可能不同,這樣就需要為不同的CPU編寫不同的彙編程式。於是又出現了高階語言比如C,或者是後來的C++,JAVA,C#。 高階語言把多條彙編指令合成成為了一個表示式,並且去除了許多操作細節(比如堆疊操作,暫存器操作),而是以一種更直觀的方式來編寫程式,而面向物件的語言的出現使得程式編寫更加符合我們的思維方式。我們不必把盡力放到低層的細節上,而更多的關注程式的本身的邏輯的實現。
對於高階語言來說需要一個編譯器來完成高階語言到組合語言的轉換。所以對比不同的CPU結構,只需要有不同編譯器和彙編器就能使得我們的程式在不同CPU上都能運行了。如下圖在VS2010中,我們可以選擇程式編譯的目標平臺,X86,X64,ARM等。當然除了這些編譯類的語言之外還有解釋型別的語言如JS,就不在此討論範圍內。
到這裡有一個疑問:當CPU的指令集更新後高階語言會有什麼影響和變化?對於目前來說,一般出現了新的指令,會有對應的新的彙編器和編譯器。所以編譯器可以把一些高階語言的表示式編譯成新的彙編指令,這樣對於高階來說不會有任何變化; 當然還有一種情況就是高階語言會增加新的語法來對應一些新的組合語言和指令。但是這種情況出現的機率很小。所以如果編譯器不支援新的指令,那麼只有只用彙編會來實現了。
2.2.1.4 小結
從上面的我們可以看出,我們寫的程式最終都將變成機器認識的二進位制可執行程式,然後載入到記憶體順序的執行。 從機器碼到彙編到高階語言,我們可以看到計算機中無處不在的分層,抽象的思想。不光光是軟體,硬體同樣適用。最後留下一個問題在這裡: C#和JAVA程式編譯出來的檔案不是二進位制的機器碼,而是中間語言,那麼他們又是怎麼執行的呢?
2.2.2 CPU工作原理
前面已經瞭解了現代計算機的大致結構,也知道CPU是按照CPU指令來執行操作,那麼就看看CPU的結構和他是如何執行順序操作的。
2.2.2.1 CPU功能
- 指令控制: 指令控制也稱為程式的順序控制,控制程式嚴格按照規定的順序執行。
- 操作控制: 將取出的指令的產生一系列的控制訊號(微指令),分別送往相應的部件,從而控制這些部件按指令的要求進行工作。
- 時間控制: 有些控制訊號在時間上有嚴格的先後順序,如讀取儲存器的資料,只有當地址線訊號穩定以後,才能通過資料線將所需的資料讀出,否則讀出的資料是不正確的資料,這樣計算機才能有條不紊地工作。
- 資料加工: 所謂資料加工,就是對資料進行算術運算和邏輯運算處理。 所謂資料加工,就是對資料進行算術運算和邏輯運算處理
2.2.2.2 CPU基本組成
以前CPU主要由運算器和控制器兩大部分組成,隨著積體電路的發展,目前CPU晶片集成了一些其它邏輯功能部件來擴充CPU的功能,如浮點運算器、記憶體管理單元、cache和MMX等。下面2張圖分別是8086和Pentium CPU的結構圖。
.
對於一個通用的CPU來說,我們只需要關注他的核心部件算數邏輯單元和操作控制單元。
1. 控制器的組成和功能: 控制器由程式計數器、指令暫存器、指令譯碼器、時序產生器和操作控制器組成。它是計算機指揮系統,完成計算機的指揮工作。儘管不同計算機的控制器結構上有很大的區別,當就其基本功能而言,具有如下功能:
- 取指令 從記憶體中取出當前指令,並生成下一條指令在記憶體中的地址。
- 分析指令 指令取出後,控制器還必須具有兩種分析的功能。一是對指令進行譯碼或測試,併產生相應的操作控制訊號,以便啟動規定的動作。比如一次記憶體讀/寫操作,一個算術邏輯運算操作,或一個輸入/輸出操作。二是分析參與這次操作的各運算元所在的地址,即運算元的有效地址。
- 執行指令 控制器還必須具備執行指令的功能,指揮並控制CPU、記憶體和輸入/輸出裝置之間資料流動的方向,完成指令的各種功能。
- 發出各種微操作命令 在指令執行過程中,要求控制器按照操作性質要求,發出各種相應的微操作命令,使相應的部件完成各種功能。
- 改變指令的執行順序 在程式設計過程中,分支結構、迴圈結構等非順序結構的引用可以大大提供程式設計的工作效率。控制器的這種功能可以根據指令執行後的結果,確定下一步是繼續按原程式的順序執行,還是改變原來的執行順序,而轉去執行其它的指令。
- 控制程式和資料的輸入與結果輸出 這實際也是一個人機對話的設計,通過編寫程式,在適當的時候輸入資料和輸出程式的結果。
- 對異常情況和某些請求的處理 當計算機正在執行程式的過程中,發生了一些異常的情況,例如除法出錯、溢位中斷、鍵盤中斷等。
2. 運算器的組成和功能: 運算器由算術邏輯單元(ALU)、累加暫存器、資料緩衝暫存器和狀態條件暫存器組成,它是資料加工處理部件,完成計算機的各種算術和邏輯運算。相對控制器而言,運算器接受控制器的命令而進行動作,即運算器所進行的全部操作都是由控制器發出的控制訊號來指揮的,所以它是執行部件。運算器有兩個主要功能:
- 執行所有的算術運算,如加、減、乘、除等基本運算及附加運算;
- 執行所有的邏輯運算,並進行邏輯測試,如與、或、非、零值測試或兩個值的比較等。
2.2.2.3 CPU工作流程
CPU的基本工作是執行儲存的指令序列,即程式。程式的執行過程實際上是不斷地取出指令、分析指令、執行指令的過程。幾乎所有的馮•諾伊曼型計算機的CPU,其工作都可以分為5個階段:取指令、指令譯碼、執行指令、訪存取數和結果寫回。
2.2.2.4 指令週期
- 指令週期: CPU取出一條指令並執行該指令所需的時間稱為指令週期。指令週期的長短與指令的複雜程度有關。
- CPU週期:從主存讀取一條指令的最短時間來規定CPU週期。指令週期常常用若干個CPU週期數來表示。
- 時鐘週期:時鐘週期是處理操作的最基本時間單位,由機器的主頻決定。一個CPU週期包含有若干個時鐘週期。
從上面的定義可以知道,對於CPU來說取出和執行任何一條指令所需的最短時間為兩個CPU週期。所以頻率越高,那麼時鐘週期越短,這樣CPU週期和指令週期也就越短,理論上程式執行的速度也越快。但是頻率不能無限的提高,而且頻率的提高也帶來了功耗,發熱等問題,所以目前也有超執行緒,流水線等技術來提高CPU執行的速度。
2.2.2.5 時序發生器
- 時序訊號: 在計算機高速執行的過程中,計算機內各部件的每一個動作都必須嚴格遵守時間規定,不能有任何差錯。計算機內各部件的協調動作需要時間標誌,而時間標誌則是用時序訊號來體現的。計算機各部分工作所需的時序訊號,在CPU中統一由時序發生器來產生。
- 時序發生器: 時序訊號發生器是產生指令週期控制時序訊號的部件,當CPU開始取指令並執行指令時,操作控制器利用時序訊號發生器產生的定時脈衝的順序和不同的脈衝間隔,提供計算機各部分工作時所需的各種微操作定時控制訊號,有條理、有節奏地指揮機器各個部件按規定時間動作。
在這裡有一個疑問:指令和資料都存放在記憶體中,那麼CPU怎麼區分是指令還是資料呢?
從時間上來說,取指令事件發生在指令週期的第一個CPU週期中,即發生在“取指令”階段,而取資料事件發生在指令週期的後面幾個CPU週期中,即發生在“執行指令”階段。從空間上來說,如果取出的程式碼是指令,那麼一定送往指令暫存器,如果取出的程式碼是資料,那麼一定送往運算器。
2.2.3 小結
通過以上我們瞭解了CPU的工作過程。簡單來說就是CPU要順序執行一個程式的指令,首先是控制器獲得第一條指令的地址,當CPU取得這個指令並執行後,控制器需要生成下一條要執行的指令的地址。ALU單元負責一些運算操作。下面的FLASH演示了CPU執行一個加法操作的流程。
3 總結
本文主要是簡單介紹了計算機的一些發展歷史和通用CPU的結構以及工作流程。加深了我們對馮諾依曼體系的儲存程式,順序執行的理解。無論硬體是什麼樣子,馮諾依曼計算機的基本原理就是這樣。
當然瞭解了基本原理之後,會產生更多的問題,比如可執行檔案又是如何被裝載到記憶體的?CPU和記憶體之間是如何通訊的呢?是如何根據地址找到指令的呢?記憶體結構又是什麼樣子? CPU如何和記憶體之外的裝置通訊呢?這些問題都會在後面給出答案。