1. 程式人生 > >深入理解計算機系統----第四章處理器體系結構

深入理解計算機系統----第四章處理器體系結構

https://www.jianshu.com/p/15210eb3870d?open_source=weibo_search 原文地址

目錄

學習事物是怎樣工作的有其內在價值:處理器是如何工作的對於我們普通人來說一直是個祕密,我們將從零開始構建一個流水線處理器,為了實現這一處理器的軟硬體,我們有大量的前提知識要學習,包括:指令系統、硬體設計背景知識(hcl)、以及流水線的通用原理。學習完這些內容以後我們才開始YY一個我們自己的86處理器。

本章內容


※ YY一個指令集Y86:各種狀態、指令集、編碼、程式設計規範、異常處理;

※數字硬體設計背景:處理器的基本構件,如何連線操作,介紹hcl語言;

※流水線原理,如何實現高效的五個步驟;如何處理冒險與衝突;

※開始實現我們自己的Y86;

筆記


一、基礎知識部分

1、介紹一個精簡的Y86指令集


①狀態碼

狀態碼指明程式是否正常,程式可以訪問和修改:程式暫存器、條件碼、PC和儲存器

②所支援的指令

長度:1-6位元組,一條普通的指令包含:指令指示符+暫存器指示符+四位元組常數

說明:

        1] 欄位 fn 指明是某個整數操作:OPL、資料移動條件:cmovXX、分支條件:jXX;

        2] 圖中最後的pushl、popl指明不需要訪問任何暫存器0xF表示;

        3] xxmovl中:i代表立即數,r代表暫存器,m代表儲存器;

        4] OPL代表的是:add sub and xor;jXX代表:jmp、jle、jl、je、jne、jge、jg。

【疑惑:不允許:儲存器——儲存器 ;立即數——儲存器 為什麼?】

③一條普通指令的編碼:

OPL指令有相同的code編碼6,不同功能編碼function區別不同操作

其他具體的編碼如下:

整數、分支和資料傳送操作

根據功能進行最優化的儲存方式,比如rrmovl與條件傳送有相同的code編碼,這是因為其行為相當於無條件傳送。

!我們還需要訪問暫存器,為了訪問的便利我們給暫存器編號,統一存放在CPU的一個暫存器檔案中。就如學生時代的學號一樣,唯一、明確,也像收監的犯罪嫌疑人,你從入獄的那一天起將沒有名字,沒有身份,只是一個簡化的號碼。

暫存器編號:esp4號,ebp5號,F代表無暫存器

舉例說明:rmmovl %esp ,   0x12345(%edx)

                rmmovl ——>4  0

                esp|edx—③—>4 2

                0x12345——>00,01,23,45(小端法儲存)

合成到最後的指令就是:[40] [42] [45] [23] [01] [00]

任何一個指令序列都是一個唯一的編碼

④異常

描述整體狀態

狀態碼如下:

我們簡單的在異常條件下停止執行

⑤我們寫一段程式碼試一試

c程式碼

翻譯成x86和y86彙編形式,基本上沒什麼不同

(特別注意:pushl 將棧指標esp減去4,並將內容寫入儲存器中。當我們執行push esp時,我們約定:首先雅鹿esp的原始值,然後壓入減去4的esp的值)

2、邏輯設計和硬體控制語言


我們將會學到:計算對位進行組合的邏輯;儲存位的儲存原理和更新時鐘訊號三部分內容。

① 對單個為進行操作:邏輯閘

與門,或門,非門

② 組合邏輯用HCL表示:一個邏輯閘肯定實現不了很多功能,我們來組合一下

用於檢測兩個Bit是否相等:

eq = (a && b) || (!a && !b)

當 a = b = 0時:上與邏輯為0,下與邏輯為1 或邏輯輸出eq為1;

當a = b = 1時:上與邏輯為1,下與邏輯為0 或邏輯輸出eq為1;

多路複用器:根據s的值選擇是輸出a或者b

out = (s && a) || (!s && b);

當 s = 0時,上與為b, 下與為0,或邏輯輸出out = b;

當 s = 1時, 上與為0, 下與為a,或邏輯輸入out = a;

四路複用器:

根據s1和s0組合,選擇abcd其中一個

hcl表示圖

字級組合電路:單個的bit位並沒太大用途

字級組合電路:用32個Equal電路組合而成

多路複用組合電路:使用32個MUX組合而成,只是非門是統一的一個

多路複用組合電路

算術邏輯單元:ALU

根據輸入設定會執行不同的邏輯運算中的一種

 

③ 集合關係

在處理器設計中,很多時候需要將一個訊號與許多可能匹配的訊號做比較,以此來檢驗正在處理的訊號是否屬於某一類指令程式碼;

判斷是否在集合中

結果在2,3中s1 = 1,結果在1,3中s0 = 1

④ 儲存器和時鐘:儲存原理(組合電路本身不能儲存資訊,只是一個時間序列電路)

更新週期將值放入儲存器中

分類:

1] 時鐘儲存器(暫存器):儲存單個位或字;

2] 隨機訪問儲存器(儲存器):儲存多個字;(虛擬儲存系統,暫存器檔案,)

硬體暫存器和程式暫存器的區別:

      硬體暫存器:在硬體中暫存器直接將輸入和輸出連線到電路的其他部分;

      程式暫存器:CPU中位數不多的可定址的暫存器,地址就是暫存器ID。

a.硬體暫存器:當時鍾訊號處於高頻上升階段時,才將輸入的訊號載入

硬體暫存器:儲存cc、pc、stat值

b.暫存器檔案

暫存器檔案

有兩個讀:A、B埠,和一個寫:W埠。允許同時進行多個讀寫操作,可以同時讀兩個暫存器和寫一個暫存器的值。srcX、desW代表地址,valX、valW代表要資料。如我們要訪問3號暫存器ebx的值,就將srcA=3,然後valA就是要訪問的資料。

c.隨機訪問儲存器

隨機訪問儲存器

假如我們要訪問一個地址address上的資料,就將該地址傳入address中,同時設定write=0,那麼在data out上的資料就是我們要訪問的值了。

3 流水線通用原理


以自動化洗車裝置為例,車子需要按照一定的速度通過流水線,增加了一部分處理量。也就是不用等前面的車子洗完,就可以開入另一輛車子了;但這個系統有時候也會增加延遲,比如你只需要給車子打蠟,但也必須要經過噴水、抹乾階段。

①未加入流水線的系統:

組合邏輯花了:300ps,處理卻只有20ps

②加入流水線的:

分成三個階段,當指令I1進入B的時候,I2就可以進入A以此類推

通過將指令分成了3個階段,我經過一個120ps週期,每條指令就行進下一個階段

③流水線操作詳細說明:

三個階段流水線時序

說明:詳細說明240-360的時鐘週期的故事

1] 點①時鐘開始上升之前(239):階段A中計算的指令I2已經到達第一個流水線暫存器的輸入,圖中藍色區域表示。但是該流水線暫存器Reg的值仍然是I1中的深灰色區域;指令I1在階段B中計算的值已經到達第二個流水線流水線暫存器的輸入Comb logic B,深灰色表示;

2] 點②時鐘開始進入上升階段(241):兩個組合邏輯輸入:A和B,將結果放入到流水線暫存器中,形成圖2的形式。藍色Reg和深灰色Reg,並將組合邏輯A設定成發起指令I3計算;

3] 點 ③階段訊號開始傳播,訊號通過不同的速率通過各個不同的部分;

4] 點④360來到之前,指令I3完成組合邏輯A處的載入,形成淺灰色區域。

 

流水線操作的一個時鐘週期

④流水線的侷限性:

1] 不一致的劃分:由於階段的延遲並不一樣,這樣空閒的空間就增加了延遲;

2] 流水線過深,收益下降;

⑤帶反饋的流水線系統:許多指令前後相關,如何建立帶反饋的指令

二、從零開始構建我們的Y86處理器


1、一個Y86的順序實現(簡易方式)

為了要實現一個通用的框架,我們通常要找到這個框架的層次結構,使得許多不同的指令可以共享相同的硬體,這是降低複雜度的一個有效的方法。

通用框架結構

①跟蹤一塊指令序列的執行:

Y86指令序列

②以 subl %edx, %ebx為例:

③SEQ硬體結構圖:

seq抽象檢視

(注:為什麼是逆序從下往上寫的?我們以後講流水線的時候再講解。)

④SEQ的時間和執行順序:

一條重要的原則是:處理器從來不需要為了完成一條指令的執行而去讀該指令更新了的狀態。

比如我們之前講到的push %esp指令,如果是分步執行,先將esp-4,然後將更新後的值作為寫地址效率就太低了。我們的做法是在執行階段計算出valE的值,然後在訪存和寫會階段同時完成更新暫存器和儲存器的操作。

push指令的三個階段

我們再來看一段程式碼:

講解SEQ時序

我們重點來看一下,第3和第4條指令的執行:

執行序列

我們來簡單的講解一下執行的過程:

1] 在時鐘週期3開始的時候點①狀態元素儲存的是週期2執行irmovl時的更新後的狀態,用淺灰色表示。點②:隨著時鐘週期開始上升時,地址0x00c載入pc中,這樣就取出了addl指令,值沿著Combinational Logic流動,充滿了淺藍色區域。在這個時候ebx就是加了以後的0x300新值,以及pc的新值0x00e。但是指令的狀態仍然保留的是irmovl指令設定的值。

2] 時鐘週期4:點③開始的時候,會更新程式計數器、暫存器檔案、和條件碼暫存器。也就是addl更新的狀態。同樣的會取出je指令,用深灰表示,ZF=0不會選擇分支。在④的時候,pc產生新值0x013,Combinational Logic已經被更新過,但是狀態還是保持的是addl指令的設定的值。

我們再重申一下原則:通過時鐘週期來控制元素的更新,通過組合邏輯來傳播,每次時鐘週期由低到高時,處理器開始執行一條新指令。處理器從來不需要為了完成一條指令的執行而去讀該指令更新了的狀態。

⑤Seq階段的實現:

1] 取指階段

以PC為起始地址,從指令儲存器中讀出6個位元組

說明:第一個位元組為Split,位元組0標號為:icode和ifun;1-5位元組為Align:暫存器指示符和常數字的組合。

2] 譯碼和寫回階段:這兩個階段都需要訪問暫存器檔案

seq的譯碼和寫回階段

同時支援兩個讀,A、B;和兩個寫:E、M;

3] 執行階段

執行階段:根據ALU的值設定條件碼暫存器,檢測條件碼的值判斷是否選擇分支

根據ALU fun訊號設定是否進行,加減乘除操作。ALU的輸出就是valE

4] 訪存階段

訪存階段:讀或寫儲存器

5] 更新PC階段

根據指令程式碼和分支標誌,從valC valM和valP中選出下一個pc的值

2.Y86的流水線實現


我們說過,我們的目的是建立一個流水線化的處理器Y86,學了這麼久的基礎知識,也建立了一個簡化的Seq模型,我們終於可以開始我們的內容了,首先我們來優化一下簡易設計中的seq,我們稱之為seq+:

①SEQ+:重新安排計算pc階段

SEQ+中沒有單獨的硬體暫存器來存放pc,而是通過pIconde、pCnd等暫存器計算pc的值。

設計原則:只要處理器能夠正確的執行機器語言,我們不需要程式猿可見狀態進行編碼,只要能產生正確的值就可以了。

將pc移動到最開始的階段

詳細的seq+圖如下:

將pc從時鐘週期結束移動到了開始,這樣更適合於流水線

②插入流水線暫存器的pipe-處理器結構:

pipe-硬體結構,我們建立了5階段流水線

說明:圖中以深藍色區域表示的就是我們加入的5個流水線暫存器,白色方塊代表不同的欄位;

F : 儲存pc預測值;

D :位於取指和譯碼之間,儲存最新的指令資訊,即將由譯碼階段處理;

E :位於譯碼和執行之間,儲存最新譯碼指令和從暫存器讀出的值,即將由執行階段處理;

M :位於執行和訪存之間,儲存最新執行指令的結果,條件分支和分支目標,即將由訪存處理;

W :位於訪存和反饋之間,提供給暫存器檔案寫,完成ret指令,向pc提供返回地址。

③ 對訊號進行重新排列和標號

在pipe-中有4個標號為stat的白色區域,就是不同指令的狀態碼:D_stat、E_stat、M_stat、W_stat來區分。而小寫的:f、d、e、m、w指的是流水階段。

④ 預測一下一個pc:除了分支和ret指令外,我們基本上能夠用valC和valP的值來預測下一條指令的地址,這樣就可以通過之前學到的流水線技術使得每個週期執行一條指令。

⑤ 流水線的冒險和處理方法

什麼是流水線的冒險?一條指令更新後面指令會用到的值。

資料冒險

當irmovl $3, %eax在第六個時鐘週期的時候,寫回階段eax還未得到正確的值3,而流水線的系統中,addl %edx, %eax已經需要使用eax的值,這時侯得到的就是錯誤的值。

冒險的分類:1)資料冒險;2)控制冒險;3)載入\使用資料冒險

我們之前講到流水線的反饋中,提到過如果兩條相鄰資料存在關聯該如何處理成為了一個問題。特別是在使用流水線技術的情況下,如果一條指令要修改一個暫存器的內容,而下一條指令又剛剛需要引用該處的內容。如何使得兩條指令執行正確。

方法一:暫停    

將指令阻滯在譯碼階段,相當於加入一條nop指令,直到獲得正確的值,才讓其他指令繼續執行。優點是實現容易,缺點是效能不佳

方法二:轉發

通過使用狀態碼儲存的值,實現旁路的轉發

圖中可以看出,我們不是在被動的等待irmovl執行完畢,而是在addl指令需要用到eax值的時候,我們將irmovl的W階段的中間值,W_valE=3轉發到addl指令中去,賦值給eax。

5個用作源的有:e_valE、m_valM、M_valE、W_valM、W_valE;兩個目的:valA、valB

有一類比較特殊的資料冒險:載入\使用資料冒險,我們特別講一下?

Load 、 Use 資料冒險

上面的兩條指令,我們具體來看一下流水線的執行過程:

載入使用資料冒險

我們執行0x018指令,要在第八個時鐘週期的時候才能獲得eax的值,而0x01e指令在第七個時鐘週期就需要這個eax,我們不可能將這個值從第八個週期傳回第七個週期。就像不能穿越時間線回到過去一樣。遇到這種情況我們的處理方式是:使用暫停和轉發相結合的方法,確切的講就是暫停addl執行的一個時鐘週期,使得在週期8的時候實現轉發。

⑥ 異常處理

異常分為:halt指令、有非法指令和功能碼組合的指令、訪問非法地址

處理方法:有多條指令引起異常,由流水線最深的指令優先順序最高

                 多條分支中有異常,取消預測指令

                 出現異常,根據狀態碼的stat值,禁止其他指令更新程式狀態

⑦ PIPE各個階段的實現:

1] PC選擇和取指階段

選擇和取指邏輯

PC選擇器必須要選擇出正確的pc值,一般來說有三種方式可選:當預測錯誤分支進入訪存,選擇M_valA中的valP;當ret指令進入寫回階段時,選擇W _valM;其他情況下選擇F_predPC。

2] 譯碼和寫回階段:

譯碼寫回

疑問:對於轉發邏輯和不同的轉發源還不明白;對Sel+Fwn的具體功能不明確

3] 執行階段:

同SEQ中相似

4] 訪存階段

⑧ 流水線控制邏輯

1]特殊情況的處理

ret指令實際的處理過程是在取指階段反覆的取出ret指令後面的指令,在譯碼階段插入氣泡;

當分支結果還未計算出來的時候,保持預測指令執行在FD階段,這樣可以防止,如果預測錯誤,預測指令不會修改程式狀態。如果決定不執行分支,取消指令的執行不會帶來錯誤的影響;實現的方法是根據stat的值:禁止執行階段中的指令設定條件碼;向儲存階段插入氣魄,以禁止寫入;當寫回階段有異常的時候,暫停寫回。

2]流水線的控制機制:加入氣泡和暫停

加入stall、bubble

當暫停stall=1的時候,狀態保持先前的值不變;

當bubble=1的時候,用nop覆蓋當前的狀態

3]控制條件的組合

兩種特殊情況的組合

我們需要處理的情況為組合B:載入指令設定暫存器esp的值,而ret指令將esp用作源運算元,因為它必須從棧中彈出返回地址,流水線控制應將ret指令阻滯在譯碼階段。

(注:系統分析的重要性,僅僅執行正確其實並不可靠)

4]最終控制模型:

控制邏輯全