文章目錄
- 其他文章
- 計算機指令
- CPU如何執行指令
- CPU 内部處理過程
- CPU 是一系列寄存器的集合體
- 程式計數器
- 條件分支和循環機制
- 函數調用機制
- CPU 指令執行過程
- 記憶體
- 記憶體的實體結構
- 記憶體的讀寫過程
- 記憶體的現實模型
- 記憶體的使用
- 指針
- 數組是記憶體的實作
- 磁盤
- 磁盤的實體結構
- 磁盤緩存
- 虛拟記憶體
- 總線
- 位址總線
- 資料總線
- 控制總線
- 輸入輸出裝置
- CPU如何控制I/O裝置
- 程式直接控制和中斷控制方式
- DMA存取方式
- 通道控制方式
- 信号和位址
- CPU 和 I/O 裝置之間的通信
計算機指令
如果我們從軟體工程師的角度來講,CPU 就是一個執行各種計算機指令(Instruction Code)的邏輯機器。這裡的計算機指令,就好比一門 CPU 能夠聽得懂的語言,我們也可以把它叫作機器語言(Machine Language)。
不同的 CPU 能夠聽懂的語言不太一樣。比如,我們的個人電腦用的是 Intel 的 CPU,蘋果手機用的是 ARM 的 CPU。這兩者能聽懂的語言就不太一樣。類似這樣兩種 CPU 各自支援的語言,就是兩組不同的計算機指令集,英文叫 Instruction Set。這裡面的“Set”,其實就是數學上的集合,代表不同的單詞、文法。
不同的 CPU 有不同的指令集,也就對應着不同的彙編語言和不同的機器碼。為了友善你快速了解這個機器碼的計算方式,我們選用最簡單的 MIPS 指令集,來看看機器碼是如何生成的。
MIPS 是一組由 MIPS 技術公司在 80 年代中期設計出來的 CPU 指令集。就在最近,MIPS 公司把整個指令集和晶片架構都完全開源了。

MIPS 的指令是一個 32 位的整數,高 6 位叫操作碼(Opcode),也就是代表這條指令具體是一條什麼樣的指令,剩下的 26 位有三種格式,分别是 R、I 和 J。
R 指令是一般用來做算術和邏輯操作,裡面有讀取和寫入資料的寄存器的位址。如果是邏輯位移操作,後面還有位移操作的位移量,而最後的功能碼,則是在前面的操作碼不夠的時候,擴充操作碼表示對應的具體指令的。
I 指令,則通常是用在資料傳輸、條件分支,以及在運算的時候使用的并非變量還是常數的時候。這個時候,沒有了位移量和操作碼,也沒有了第三個寄存器,而是把這三部分直接合并成了一個位址值或者一個常數。
J 指令就是一個跳轉指令,高 6 位之外的 26 位都是一個跳轉後的位址。
// test.c int main() { int a = 1; int b = 2; a = a + b; }
要讓這段在一個 Linux 作業系統上跑起來,我們需要把整個程式翻譯成一個彙編語言(ASM,Assembly Language)的程式,這個過程我們一般叫編譯(Compile)成彙編代碼。
針對彙編代碼,我們可以再用彙編器(Assembler)翻譯成機器碼(Machine Code)。這些機器碼由“0”和“1”組成的機器語言表示。這一條條機器碼,就是一條條的計算機指令。這樣一串串的 16 進制數字,就是我們 CPU 能夠真正認識的計算機指令。
因為彙編代碼其實就是“給程式員看的機器碼”,也正因為這樣,機器碼和彙編代碼是一一對應的。我們人類很容易記住 add、mov 這些用英文表示的指令,而 8b 45 f8 這樣的指令,由于很難一下子看明白是在幹什麼,是以會非常難以記憶。
從進階語言到彙編代碼,再到機器碼,就是一個日常開發程式,最終變成了 CPU 可以執行的計算機指令的過程。
CPU如何執行指令
CPU 内部處理過程
下圖展示了一般程式的運作流程(以 C 語言為例),可以說了解程式的運作流程是掌握程式運作機制的基礎和前提。
在這個流程中,CPU 負責的就是解釋和運作最終轉換成機器語言的内容。
CPU 主要由兩部分構成:控制單元 和 算術邏輯單元(ALU)
- 控制單元:從記憶體中提取指令并解碼執行
- 算數邏輯單元(ALU):處理算數和邏輯運算
CPU 是計算機的心髒和大腦,它和記憶體都是由許多半導體組成的電子部件。它接收資料輸入,執行指令并處理資訊。它與輸入/輸出(I / O)裝置進行通信,這些裝置向 CPU 發送資料和從 CPU 接收資料。
從功能來看,CPU 的内部由寄存器、控制器、運算器和時鐘四部分組成,各部分之間通過電信号連通。
- 寄存器是中央處理器内的組成部分。它們可以用來暫存指令、資料和位址。可以将其看作是記憶體的一種。根據種類的不同,一個 CPU 内部會有 20 – 100個寄存器。
- 控制器負責把記憶體上的指令、資料讀入寄存器,并根據指令的結果控制計算機
- 運算器負責運算從記憶體中讀入寄存器的資料
- 時鐘 負責發出 CPU 開始計時的時鐘信号
也可以說它包括三個部分,運算單元、資料單元和控制單元。
運算單元隻管算,例如做加法、做位移等等。但是,它不知道應該算哪些資料,運算結果應該放在哪裡。
運算單元計算的資料如果每次都要經過總線,到記憶體裡面現拿,這樣就太慢了,是以就有了資料單元。資料單元包括 CPU 内部的緩存和寄存器組,空間很小,但是速度飛快,可以暫時存放資料和運算結果。
有了放資料的地方,也有了算的地方,還需要有個指揮到底做什麼運算的地方,這就是控制單元。控制單元是一個統一的指揮中心,它可以獲得下一條指令,然後執行這條指令。這個指令會指導運算單元取出資料單元中的某幾個資料,計算出個結果,然後放在資料單元的某個地方。
CPU 的控制單元裡面,有一個指令指針寄存器,它裡面存放的是下一條指令在記憶體中的位址。控制單元會不停地将代碼段的指令拿進來,先放入指令寄存器。
目前的指令分兩部分,一部分是做什麼操作,例如是加法還是位移;一部分是操作哪些資料。
要執行這條指令,就要把第一部分交給運算單元,第二部分交給資料單元。
資料單元根據資料的位址,從資料段裡讀到資料寄存器裡,就可以參與運算了。運算單元做完運算,産生的結果會暫存在資料單元的資料寄存器裡。最終,會有指令将資料寫回記憶體中的資料段。
你可能會問,上面算來算去執行的都是程序 A 裡的指令,那程序 B 呢?CPU 裡有兩個寄存器,專門儲存目前處理程序的代碼段的起始位址,以及資料段的起始位址。這裡面寫的都是程序 A,那目前執行的就是程序 A 的指令,等切換成程序 B,就會執行 B 的指令了,這個過程叫作程序切換(Process Switch)。
到這裡,你會發現,CPU 和記憶體來來回回傳資料,靠的都是總線。其實總線上主要有兩類資料,一個是位址資料,也就是我想拿記憶體中哪個位置的資料,這類總線叫位址總線(Address Bus);另一類是真正的資料,這類總線叫資料總線(Data Bus)。
位址總線的位數,決定了能通路的位址範圍到底有多廣。例如隻有兩位,那 CPU 就隻能認 00,01,10,11 四個位置,超過四個位置,就區分不出來了。位數越多,能夠通路的位置就越多,能管理的記憶體的範圍也就越廣。
而資料總線的位數,決定了一次能拿多少個資料進來。例如隻有兩位,那 CPU 一次隻能從記憶體拿兩位數。要想拿八位,就要拿四次。位數越多,一次拿的資料就越多,通路速度也就越快。
CPU 是一系列寄存器的集合體
拿我們用的 Intel CPU 來說,裡面差不多有幾百億個半導體。我們先不管幾百億的半導體的背後是怎麼通過電路運轉起來的,邏輯上,我們可以認為,CPU 其實就是由一堆寄存器組成的。而寄存器就是 CPU 内部,由多個觸發器(Flip-Flop)或者鎖存器(Latches)組成的簡單電路。
觸發器和鎖存器,其實就是兩種不同原理的數字電路組成的邏輯門。
一個 CPU 裡面會有很多種不同功能的寄存器。我這裡給你介紹三種比較特殊的。
一個是PC 寄存器(Program Counter Register),我們也叫指令位址寄存器(Instruction Address Register)。顧名思義,它就是用來存放下一條需要執行的計算機指令的記憶體位址。
第二個是指令寄存器(Instruction Register),用來存放目前正在執行的指令。
第三個是條件碼寄存器(Status Register),用裡面的一個一個标記位(Flag),存放 CPU 進行算術或者邏輯計算的結果。
除了這些特殊的寄存器,CPU 裡面還有更多用來存儲資料和記憶體位址的寄存器。這樣的寄存器通常一類裡面不止一個。我們通常根據存放的資料内容來給它們取名字,比如整數寄存器、浮點數寄存器、向量寄存器和位址寄存器等等。有些寄存器既可以存放資料,又能存放位址,我們就叫它通用寄存器。
程式計數器
程式計數器(Program Counter)是用來存儲下一條指令所在單元的位址。
程式執行時,PC的初值為程式第一條指令的位址,在順序執行程式時,控制器首先按程式計數器所指出的指令位址從記憶體中取出一條指令,然後分析和執行該指令,同時将PC的值加1指向下一條要執行的指令。
我們還是以一個事例為準來詳細的看一下程式計數器的執行過程
這是一段進行相加的操作,程式啟動,在經過編譯解析後會由作業系統把硬碟中的程式複制到記憶體中,示例中的程式是将 123 和 456 執行相加操作,并将結果輸出到顯示器上。
位址 0100 是程式運作的起始位置。Windows 等作業系統把程式從硬碟複制到記憶體後,會将程式計數器作為設定為起始位置 0100,然後執行程式,每執行一條指令後,程式計數器的數值會增加1(或者直接指向下一條指令的位址),然後,CPU 就會根據程式計數器的數值,從記憶體中讀取指令并執行,也就是說,程式計數器控制着程式的流程。
條件分支和循環機制
進階語言中的條件控制流程主要分為三種:順序執行、條件分支、循環判斷三種,順序執行是按照位址的内容順序的執行指令。條件分支是根據條件執行任意位址的指令。循環是重複執行同一位址的指令。
- 順序執行的情況比較簡單,每執行一條指令程式計數器的值就是 + 1。
- 條件和循環分支會使程式計數器的值指向任意的位址,這樣一來,程式便可以傳回到上一個位址來重複執行同一個指令,或者跳轉到任意指令。
下面以條件分支為例來說明程式的執行過程(循環也很相似)
條件和循環分支會使用到 jump(跳轉指令)
程式的開始過程和順序流程是一樣的,CPU 從0100處開始執行指令,在0100和0101都是順序執行,PC 的值順序+1,執行到0102位址的指令時,判斷0106寄存器的數值大于0,跳轉(jump)到0104位址的指令,将數值輸出到顯示器中,然後結束程式,0103 的指令被跳過了,這就和我們程式中的 if() 判斷是一樣的,在不滿足條件的情況下,指令會直接跳過。是以 PC 的執行過程也就沒有直接+1,而是下一條指令的位址。
函數調用機制
接下來,我們繼續介紹函數調用機制,哪怕是進階語言編寫的程式,函數調用處理也是通過把程式計數器的值設定成函數的存儲位址來實作的。函數執行跳轉指令後,必須進行傳回處理,單純的指令跳轉沒有意義,下面是一個實作函數跳轉的例子
函數的調用和傳回很重要的兩個指令是 call 和 return 指令,再将函數的入口位址設定到程式計數器之前,call 指令會把調用函數後要執行的指令位址存儲在名為棧的主存内。函數處理完畢後,再通過函數的出口來執行 return 指令。return 指令的功能是把儲存在棧中的位址設定到程式計數器。MyFun 函數在被調用之前,0154 位址儲存在棧中,MyFun 函數處理完成後,會把 0154 的位址儲存在程式計數器中。
CPU 指令執行過程
幾乎所有的馮·諾伊曼型計算機的CPU,其工作都可以分為5個階段:取指令、指令譯碼、執行指令、訪存取數、結果寫回。
- 取指令階段是将記憶體中的指令讀取到 CPU 中寄存器的過程,程式寄存器用于存儲下一條指令所在的位址
- 指令譯碼階段,在取指令完成後,立馬進入指令譯碼階段,在指令譯碼階段,指令譯碼器按照預定的指令格式,對取回的指令進行拆分和解釋,識别區分出不同的指令類别以及各種擷取操作數的方法。
- 執行指令階段,譯碼完成後,就需要執行這一條指令了,此階段的任務是完成指令所規定的各種操作,具體實作指令的功能。
- 通路取數階段,根據指令的需要,有可能需要從記憶體中提取資料,此階段的任務是:根據指令位址碼,得到操作數在主存中的位址,并從主存中讀取該操作數用于運算。
- 結果寫回階段,作為最後一個階段,結果寫回(Write Back,WB)階段把執行指令階段的運作結果資料“寫回”到某種存儲形式:結果資料經常被寫到CPU的内部寄存器中,以便被後續的指令快速地存取;
記憶體
CPU 和 記憶體就像是一堆不可分割的戀人一樣,是無法拆散的一對兒,沒有記憶體,CPU 無法執行程式指令,那麼計算機也就失去了意義;隻有記憶體,無法執行指令,那麼計算機照樣無法運作。
記憶體和 CPU 如何進行互動?下面就來介紹一下
記憶體的實體結構
在了解一個事物之前,你首先得先需要見過它,你才會有印象,才會有想要了解的興趣,是以我們首先需要先看一下什麼是記憶體以及它的實體結構是怎樣的。
記憶體的内部是由各種 IC 電路組成的,它的種類很龐大,但是其主要分為三種存儲器
- 随機存儲器(RAM):記憶體中最重要的一種,表示既可以從中讀取資料,也可以寫入資料。當機器關閉時,記憶體中的資訊會 丢失。
- 隻讀存儲器(ROM):ROM 一般隻能用于資料的讀取,不能寫入資料,但是當機器停電時,這些資料不會丢失。
- 高速緩存(Cache):Cache 也是我們經常見到的,它分為一級緩存(L1 Cache)、二級緩存(L2 Cache)、三級緩存(L3 Cache)這些資料,它位于記憶體和 CPU 之間,是一個讀寫速度比記憶體更快的存儲器。當 CPU 向記憶體寫入資料時,這些資料也會被寫入高速緩存中。當 CPU 需要讀取資料時,會直接從高速緩存中直接讀取,當然,如需要的資料在Cache中沒有,CPU會再去讀取記憶體中的資料。
記憶體 IC 是一個完整的結構,它内部也有電源、位址信号、資料信号、控制信号和用于尋址的 IC 引腳來進行資料的讀寫。下面是一個虛拟的 IC 引腳示意圖
圖中 VCC 和 GND 表示電源,A0 – A9 是位址信号的引腳,D0 – D7 表示的是控制信号、RD 和 WR 都是好控制信号,我用不同的顔色進行了區分,将電源連接配接到 VCC 和 GND 後,就可以對其他引腳傳遞 0 和 1 的信号,大多數情況下,+5V 表示1,0V 表示 0。
我們都知道記憶體是用來存儲資料,那麼這個記憶體 IC 中能存儲多少資料呢?D0 – D7 表示的是資料信号,也就是說,一次可以輸入輸出 8 bit = 1 byte 的資料。A0 – A9 是位址信号共十個,表示可以指定 00000 00000 – 11111 11111 共 2 的 10次方 = 1024個位址。每個位址都會存放 1 byte 的資料,是以我們可以得出記憶體 IC 的容量就是 1 KB。
記憶體的讀寫過程
讓我們把關注點放在記憶體 IC 對資料的讀寫過程上來吧!我們來看一個對記憶體IC 進行資料寫入和讀取的模型
來較長的描述一下這個過程,假設我們要向記憶體 IC 中寫入 1byte 的資料的話,它的過程是這樣的:
- 首先給 VCC 接通 +5V 的電源,給 GND 接通 0V 的電源,使用 A0 - A9 來指定資料的存儲場所,然後再把資料的值輸入給 D0 - D7 的資料信号,并把 WR(write)的值置為 1,執行完這些操作後,即可以向記憶體 IC 寫入資料
- 讀出資料時,隻需要通過 A0 – A9 的位址信号指定資料的存儲場所,然後再将 RD 的值置為 1 即可。
- 圖中的 RD 和 WR 又被稱為控制信号。其中當WR 和 RD 都為 0 時,無法進行寫入和讀取操作。
記憶體的現實模型
為了便于記憶,我們把記憶體模型映射成為我們現實世界的模型,在現實世界中,記憶體的模型很想我們生活的樓房。在這個樓房中,1層可以存儲一個位元組的資料,樓層号就是位址,下面是記憶體和樓層整合的模型圖
我們知道,程式中的資料不僅隻有數值,還有資料類型的概念,從記憶體上來看,就是占用記憶體大小(占用樓層數)的意思。即使實體上強制以 1 個位元組為機關來逐一讀寫資料的記憶體,在程式中,通過指定其資料類型,也能實作以特定位元組數為機關來進行讀寫。
下面是一個以特定位元組數為例來讀寫指令位元組的程式的示例
// 定義變量 char a; short b; long c; // 變量指派 a = 123; b = 123; c = 123;
我們分别聲明了三個變量 a,b,c ,并給每個變量賦上了相同的 123,這三個變量表示記憶體的特定區域。通過變量,即使不指定實體位址,也可以直接完成讀寫操作,作業系統會自動為變量配置設定記憶體位址。
這三個變量分别表示 1 個位元組長度的 char,2 個位元組長度的 short,表示4 個位元組的 long。是以,雖然資料都表示的是 123,但是其存儲時所占的記憶體大小是不一樣的。如下所示
這裡的 123 都沒有超過每個類型的最大長度,是以 short 和 long 類型為所占用的其他記憶體空間配置設定的數值是0,這裡我們采用的是低位元組序列的方式存儲
低位元組序列:将資料低位存儲在記憶體低位位址。
高位元組序列:将資料的高位存儲在記憶體地位的方式稱為高位元組序列。
記憶體的使用
指針
指針是 C 語言非常重要的特征,指針也是一種變量,隻不過它所表示的不是資料的值,而是記憶體的位址。通過使用指針,可以對任意記憶體位址的資料進行讀寫。
在了解指針讀寫的過程前,我們先需要了解如何定義一個指針,和普通的變量不同,在定義指針時,我們通常會在變量名前加一個 * 号。例如我們可以用指針定義如下的變量
char *d; // char類型的指針 d 定義 short *e; // short類型的指針 e 定義 long *f; // long類型的指針 f 定義
我們以32位計算機為例,32位計算機的記憶體位址是 4 位元組,在這種情況下,指針的長度也是 32 位。然而,變量 d e f 卻代表了不同的位元組長度,這是為什麼呢?
實際上,這些資料表示的是從記憶體中一次讀取的位元組數,比如 d e f 的值都為 100,那麼使用 char 類型時就能夠從記憶體中讀寫 1 byte 的資料,使用 short 類型就能夠從記憶體讀寫 2 位元組的資料, 使用 long 就能夠讀寫 4 位元組的資料,下面是一個完整的類型位元組表
類型 | 32位 | 64位 |
char | 1 | 1 |
short int | 2 | 2 |
int | 4 | 4 |
unsigned int | 4 | 4 |
float | 4 | 4 |
double | 8 | 8 |
long | 4 | 8 |
long long | 8 | 8 |
unsigned long | 4 | 8 |
我們可以用圖來描述一下這個讀寫過程
數組是記憶體的實作
數組是指多個相同的資料類型在記憶體中連續排列的一種形式。作為數組元素的各個資料會通過下标編号來區分,這個編号也叫做索引,如此一來,就可以對指定索引的元素進行讀寫操作。
首先先來認識一下數組,我們還是用 char、short、long 三種元素來定義數組,數組的元素用[value] 擴起來,裡面的值代表的是數組的長度,就像下面的定義
char g[100]; short h[100]; long i[100];
數組定義的資料類型,也表示一次能夠讀寫的記憶體大小,char 、short 、long 分别以 1 、2 、4 個位元組為例進行記憶體的讀寫。
數組是記憶體的實作,數組和記憶體的實體結構完全一緻,尤其是在讀寫1個位元組的時候,當位元組數超過 1 時,隻能通過逐個位元組來讀取,下面是記憶體的讀寫過程
數組是我們學習的第一個資料結構,我們都知道數組的檢索效率是比較快的,至于數組的檢索效率為什麼這麼快并不是我們這篇文章讨論的重點。
磁盤
磁盤的實體結構
之前我們介紹了CPU、記憶體的實體結構,現在我們來介紹一下磁盤的實體結構。磁盤的實體結構指的是磁盤存儲資料的形式。
一塊機械硬碟是由盤面、磁頭和懸臂三個部件組成的。
把磁盤表面分成若幹個同心圓的空間就是 磁道,把磁道按照固定大小的存儲空間劃分而成的就是 扇區
扇區是對磁盤進行實體讀寫的最小機關。Windows 中使用的磁盤,一般是一個扇區 512 個位元組。不過,Windows 在邏輯方面對磁盤進行讀寫的機關是扇區整數倍簇。根據磁盤容量不同功能,1簇可以是 512 位元組(1 簇 = 1扇區)、1KB(1簇 = 2扇區)、2KB、4KB、8KB、16KB、32KB( 1 簇 = 64 扇區)。簇和扇區的大小是相等的。
硬碟的基本存儲機關為扇區(Sector),每個扇區一般為512位元組。一個硬碟往往有多個磁片,每面按照同心圓劃分若幹個磁道,每個磁道劃分為若幹個扇區。
通常,我們的一個盤面上會有兩個磁頭,分别在盤面的正反面。盤面在正反兩面都有對應的磁性塗層來存儲資料,而且一塊硬碟也不是隻有一個盤面,而是上下堆疊了很多個盤面,各個盤面之間是平行的。每個盤面的正反兩面都有對應的磁頭。
我們的資料并不能直接從盤面傳輸到總線上,而是通過磁頭,從盤面上讀取到,然後再通過電路信号傳輸給控制電路、接口,再到總線上的。
讀取資料,其實就是兩個步驟。一個步驟,就是把盤面旋轉到某一個位置。在這個位置上,我們的懸臂可以定位到整個盤面的某一個子區間。這個子區間的形狀有點兒像一塊披薩餅,我們一般把這個區間叫作幾何扇區(Geometrical Sector),意思是,在“幾何位置上”,所有這些扇區都可以被懸臂通路到。另一個步驟,就是把我們的懸臂移動到特定磁道的特定扇區,也就在這個“幾何扇區”裡面,找到我們實際的扇區。找到之後,我們的磁頭會落下,就可以讀取到正對着扇區的資料。
磁盤緩存
我們上面提到,磁盤往往和記憶體是互利共生的關系,互相協作,彼此持有良好的合作關系。每次記憶體都需要從磁盤中讀取資料,必然會讀到相同的内容,是以一定會有一個角色負責存儲我們經常需要讀到的内容。我們大家做軟體的時候經常會用到緩存技術,那麼硬體層面也不例外,磁盤也有緩存,磁盤的緩存叫做磁盤緩存。
磁盤緩存指的是把從磁盤中讀出的資料存儲到記憶體的方式,這樣一來,當接下來需要讀取相同的内容時,就不會再通過實際的磁盤,而是通過磁盤緩存來讀取。某一種技術或者架構的出現勢必要解決某種問題的,那麼磁盤緩存就大大改善了磁盤通路的速度。
虛拟記憶體
虛拟記憶體是記憶體和磁盤互動的第二個媒介。虛拟記憶體是指把磁盤的一部分作為假想記憶體來使用。這與磁盤緩存是假想的磁盤(實際上是記憶體)相對,虛拟記憶體是假想的記憶體(實際上是磁盤)。
虛拟記憶體是計算機系統記憶體管理的一種技術。它使得應用程式認為它擁有連續可用的記憶體(一個完整的位址空間),但是實際上,它通常被分割成多個實體碎片,還有部分存儲在外部磁盤管理器上,必要時進行資料交換。
通過借助虛拟記憶體,在記憶體不足時仍然可以運作程式。例如,在隻剩 5MB 記憶體空間的情況下仍然可以運作 10MB 的程式。由于 CPU 隻能執行加載到記憶體中的程式,是以,虛拟記憶體的空間就需要和記憶體中的空間進行置換(swap),然後運作程式。
虛拟記憶體的方法有分頁式 和 分段式 兩種。Windows 采用的是分頁式。該方式是指在不考慮程式構造的情況下,把運作的程式按照一定大小的頁進行分割,并以頁為機關進行置換。在分頁式中,我們把磁盤的内容讀到記憶體中稱為 Page In,把記憶體的内容寫入磁盤稱為 Page Out。Windows 計算機的頁大小為 4KB ,也就是說,需要把應用程式按照 4KB 的頁來進行切分,以頁(page)為機關放到磁盤中,然後進行置換。
為了實作記憶體功能,Windows 在磁盤上提供了虛拟記憶體使用的檔案(page file,頁檔案)。該檔案由 Windows 生成和管理,檔案的大小和虛拟記憶體大小相同,通常大小是記憶體的 1 – 2 倍。
總線
計算機是由五大部件組成的:運算器、存儲器、控制器、輸入裝置和輸出裝置,這個概念比較抽象,簡單一點來說就是 CPU 包含運算器和控制器,存儲器也就指的是記憶體,而輸入輸出裝置分别指的是鍵盤和顯示器。計算機這幾個部件之間是需要共同協作完成資訊處理的,那麼,這幾大部件之間如何進行通信呢?靠的是總線
現代的 Intel CPU 的體系結構裡面,通常有好幾條總線。
首先,CPU 和記憶體以及高速緩存通信的總線,這裡面通常有兩種總線。這種方式,我們稱之為雙獨立總線(Dual Independent Bus,縮寫為 DIB)。CPU 裡,有一個快速的本地總線(Local Bus),以及一個速度相對較慢的前端總線(Front-side Bus)。
我們在前面幾講剛剛講過,現代的 CPU 裡,通常有專門的高速緩存晶片。這裡的高速本地總線,就是用來和高速緩存通信的。而前端總線,則是用來和主記憶體以及輸入輸出裝置通信的。有時候,我們會把本地總線也叫作後端總線(Back-side Bus),和前面的前端總線對應起來。而前端總線也有很多其他名字,比如處理器總線(Processor Bus)、記憶體總線(Memory Bus)。
除了前端總線呢,我們常常還會聽到 PCI 總線、I/O 總線或者系統總線(System Bus)。看到這麼多總線的名字,你是不是已經有點暈了。這些名詞确實容易混為一談。其實各種總線的命名一直都很混亂,我們不如直接來看一看CPU 的硬體架構圖。對照圖來看,一切問題就都清楚了。
CPU 裡面的北橋晶片,把我們上面說的前端總線,一分為二,變成了三個總線。
我們的前端總線,其實就是系統總線。CPU 裡面的記憶體接口,直接和系統總線通信,然後系統總線再接入一個 I/O 橋接器(I/O Bridge)。這個 I/O 橋接器,一邊接入了我們的記憶體總線,使得我們的 CPU 和記憶體通信;另一邊呢,又接入了一個 I/O 總線,用來連接配接 I/O 裝置。
事實上,真實的計算機裡,這個總線層面拆分得更細。根據不同的裝置,還會分成獨立的 PCI 總線、ISA 總線等等。
在實體層面,其實我們完全可以把總線看作一組“電線”。不過呢,這些電線之間也是有分工的,我們通常有三類線路。
- 資料線(Data Bus),用來傳輸實際的資料資訊,也就是實際上了公共汽車的“人”。
- 位址線(Address Bus),用來确定到底把資料傳輸到哪裡去,是記憶體的某個位置,還是某一個 I/O 裝置。這個其實就相當于拿了個紙條,寫下了上面的人要下車的站點。
- 控制線(Control Bus),用來控制對于總線的通路。雖然我們把總線比喻成了一輛公共汽車。那麼有人想要做公共汽車的時候,需要告訴公共汽車司機,這個就是我們的控制信号。
位址總線
位址總線主要用于傳輸源資料或者目的資料在主存單元中的位址。
CPU 通過位址總線來指定存儲單元的位置的,位址總線上能傳送多少資訊,CPU 就可以對多少個存儲單元進行尋址。
上圖中 CPU 和記憶體中間資訊交換通過了 10 條位址總線,每一條線能夠傳遞的資料都是 0 或 1 ,是以上圖一次 CPU 和記憶體傳遞的資料是 2 的十次方。
是以,如果 CPU 有 N 條位址總線,那麼可以說這個位址總線的寬度是 N 。這樣 CPU 可以尋找 2 的 N 次方個記憶體單元。
資料總線
資料線顧名思義就是一次傳遞資料的位數,資料總線的位數就是資料總線寬度。
CPU 與記憶體或其他部件之間的資料傳送是由資料總線來完成的。資料總線的寬度決定了 CPU 和外界的資料傳輸速度。8 根資料總線可以一次傳送一個 8 位二進制資料(即一個位元組)。16 根資料總線一次可以傳輸兩個位元組,32 根資料總線可以一次傳輸四個位元組。。。。。。
控制總線
控制總線是在總線上發出控制信号的傳輸線,常見的控制信号有:時鐘(同步操作)、複位(初始化操作)、中斷請求/響應、存儲器讀寫、IO 讀寫等。
CPU 與其他部件之間的控制是通過 控制總線 來完成的。有多少根控制總線,就意味着 CPU 提供了對外部器件的多少種控制。是以,控制總線的寬度決定了 CPU 對外部部件的控制能力。
輸入輸出裝置
CPU如何控制I/O裝置
程式直接控制和中斷控制方式
- 首先是資料寄存器(Data Register)。CPU 向 I/O 裝置寫入需要傳輸的資料,比如要列印的内容是“GeekTime”,我們就要先發送一個“G”給到對應的 I/O 裝置。
- 然後是指令寄存器(Command Register)。CPU 發送一個指令,告訴列印機,要進行列印工作。這個時候,列印機裡面的控制電路會做兩個動作。第一個,是去設定我們的狀态寄存器裡面的狀态,把狀态設定成 not-ready。第二個,就是實際操作列印機進行列印。
- 而狀态寄存器(Status Register),就是告訴了我們的 CPU,現在裝置已經在工作了,是以這個時候,CPU 你再發送資料或者指令過來,都是沒有用的。直到前面的動作已經完成,狀态寄存器重新變成了 ready 狀态,我們的 CPU 才能發送下一個字元和指令。
對于快速的I/O裝置,如“磁盤”,每準備好一個字就給CPU發送一次中斷請求,會導緻什麼問題?
答:CPU需要花大量的時間來進行中斷服務程式,CPU使用率嚴重下降。
DMA存取方式
通道控制方式
信号和位址
搞清楚了實際的 I/O 裝置和接口之間的關系,一個新的問題就來了。那就是,我們的 CPU 到底要往總線上發送一個什麼樣的指令,才能和 I/O 接口上的裝置通信呢?
CPU 和 I/O 裝置的通信,一樣是通過 CPU 支援的機器指令來執行的。
為了讓已經足夠複雜的 CPU 盡可能簡單,計算機會把 I/O 裝置的各個寄存器,以及 I/O 裝置内部的記憶體位址,都映射到主記憶體位址空間裡來。主記憶體的位址空間裡,會給不同的 I/O 裝置預留一段一段的記憶體位址。CPU 想要和這些 I/O 裝置通信的時候呢,就往這些位址發送資料。
而我們的 I/O 裝置呢,就會監控位址線,并且在 CPU 往自己位址發送資料的時候,把對應的資料線裡面傳輸過來的資料,接入到對應的裝置裡面的寄存器和記憶體裡面來。CPU 無論是向 I/O 裝置發送指令、查詢狀态還是傳輸資料,都可以通過這樣的方式。這種方式呢,叫作記憶體映射IO(Memory-Mapped I/O,簡稱 MMIO)。
CPU 和 I/O 裝置之間的通信
在計算機系統裡面,CPU 和 I/O 裝置之間的通信,是這麼來解決的。
首先,在 I/O 裝置這一側,我們把 I/O 裝置拆分成,能和 CPU 通信的接口電路,以及實際的 I/O 裝置本身。==接口電路裡面有對應的狀态寄存器、指令寄存器、資料寄存器、資料緩沖區和裝置記憶體等等。==接口電路通過總線和 CPU 通信,接收來自 CPU 的指令和資料。而接口電路中的控制電路,再解碼接收到的指令,實際去操作對應的硬體裝置。