本文是介紹SEQCPU(Sequential CPU)的實現的第一篇,着重介紹如何將Y86的指令組織成階段.
Y86/SEQ CPU
————
"設計一個簡易的處理器"的第一篇中,我介紹了一個簡易的指令集系統Y86,這裏的SEQ CPU使用的就是Y86指令集.
指令集詳見(http://blog.csdn.net/dennis_fan/article/details/8226311).
需要指出的是, CPU是一個數字電路,由組合電路和時序電路組成.我們知道,組合電路沒有狀態,而時序電路是有狀態的.特別的是,程序員的可見狀態在硬件實現上就是一個一個的時序電路來完成的.
SEQ CPU的狀態(時序電路):
- 程序計數器(Program counter register, PC)
- 條件碼寄存器(Conditon code register, CC)
- 寄存器文件(Register File)
- 存儲器(Memory)
這些時序電路隨着時鐘上升而更新.
SEQ CPU的組合電路:
- 算術邏輯單元(ALU)
- 控制邏輯(Control logic)
- 讀存儲器(Memory reads):讀指令寄存器,讀寄存器文件,讀數據寄存器.
指令處理階段
————
爲了降低實現的複雜性,採用統一的框架,這樣可以共用一些部件.我們將Y86的指令處理組織成如下幾個階段:
- 取指(Fetch):從指令寄存器讀取指令.
- 譯碼(Decode):讀取程序寄存器.
- 執行(Execute): ALU計算結果(分爲兩種一種是計算值(用於更新程序寄存器),一種是計算存儲器引用的有效地址).
- 訪存(Memory):讀寫存儲器.
- 寫回(Write Back):寫回寄存器文件.
- 更新PC(PC update):將PC設置成下一條指令的地址.
先大家只需要瞭解一下一條指令執行的要經歷的階段,後面會分析Y86的具體指令的執行過程.
需要注意的兩點:
1.在統一框架下,每條指令都會經歷以上所有階段.
2.在SEQ/SEQ+裏,各個階段是順序進行的,但一個階段內的內容基本上(有例外,稍後再說)是並行執行的.
Y86指令的執行
————
Y86的指令及其編碼可以參看我以前的blog.
下面是各種指令處理的各個階段,大家可以一掃而過,看我的分析結果,再對照着圖就很容易理解.
看到上面的指令處理的各個階段是不是天花亂墜啊.其實一點不復雜,因爲使用的是統一的框架.總結起來就如下幾點:
(1).首先要看指令到底要幹啥,它的操作數是啥,明確數據流的方向.
比如opl, rrmovl, irmovl, cmovXX都不涉及到存儲器,都是將Execute階段中的執行結果valE給某個程序寄存器.(數據流方向: valE->程序寄存器).
比如mrmovl, popl的數據流方向是:存儲器->程序寄存器.以爲這肯定要從存儲器中取出valM,再給這個程序寄存器.
比如rmmovl的數據流方向是:程序寄存器->存儲器,肯定會寫入存儲器.
(2).寫入程序寄存器的數據有兩種來源,一種是valE(opl,rrmovl, irmovl, pushl, popl, call, ret,cmovXX),一種是valM(mrmovl, popl).
(3). pushl, popl, call, ret都涉及了"棧"(存儲器),都會更新%esp(%esp+/-4:在執行階段計算出來valE).將valE寫回%esp.
(4). opl在執行階段會設置CC, cmovXX, jXX在執行階段會有一個判斷邏輯.
(5).只有rmmovl, pushl和call需要寫回存儲器.
(6).統一處理的原則:在excute階段,valA儘量不參與運算,使用valB參與運算;在memory階段,都是valA參與運算(爲了使得pushl和rmmovl統一處理).
(7).總結
階段名 |
信號 |
註釋 |
Fetch |
icode:ifun rA, rB valC valP |
Read instruction byte Read register byte Read constant D or V Compute next PC |
Decode |
valA valB |
Read operand A Read operand B |
Execute |
valE Cond code |
Perform ALU operation Set/Test Condition code register |
Memory |
valM |
Memery read/write |
Write back |
dstE dstM |
Write back ALU result |
PC update |
PC |
Update PC |
疑點
————
1. rrmovl的execute階段本不需要運算,爲什麼要執行"valE = 0+valA"?
答:使用的是統一的框架,每條指令都必須通過每個階段.這樣做還有一個好處,減少信號傳遞的數量.寫回都是通過valE和valM的,而不需要valA.
2.爲什麼是mrmovl D(rB), rA而不是 mrmovl D(rA), rB?
答:統一處理 mrmvol和rmmovl.這樣保證了"execute階段, valA儘量不參與運算,使用valB參與運算".
3. popl rA的Write back階段需要寫兩個寄存器.這兩個寫應該是有次序的啊?
答:是的.爲了保證"popl%esp"的語義同IA32一致,"R[%esp]<-valE"必須在"R[rA]<-valM"之前,這意味着按照只能在上升沿update的規則,就需要2個cycles來執行(違反了原則)。
4. pushl rA怎麼沒有問題?
答:由於在SEQ CPU中.因爲讀取的值在某根信號線(指的是valA信號)上存在着.即便是"pushl %esp", %esp的值已經在valA信號線上了,只需要將valA的值寫回存儲器即可.
reference: