使用logisim搭建單周期CPU與添加指令
搭建
總設計
借用高老板的圖,我們只需要分別做出PC、NPC、IM、RF、EXT、ALU、DM、Controller模塊即可,再按圖連線,最后進行控制信號的處理,一個CPU就差不多搭完了。目前支持的指令集為{addu、subu、ori、lw、sw、beq、jal、jr、nop、lui、sb、lb、sh、lh}
下面分模塊逐個分析
PC
本質上就是一個32位的寄存器,這里采用的是異步復位,所以直接把reset信號連在clear口。
NPC
由於我的CPU支持beq、jal、jr,所以NPCOp有2位,如下表所示
NPCOp | 功能 |
---|---|
00 | 計算順序地址(PC+4) |
01 | 計算beq地址 |
10 | 計算jal地址 |
11 | 計算jr地址 |
其中PC4是用來把PC+4輸出至RF以完成jal指令
IM
這個就更簡單了,直接一個ROM搞定,注意把PC的2~6位引出作為IM的地址。
RF
這個比較耗時間,聽說用vscode打開.circ文件就可以寫代碼去搭建這玩意,打開后發現3k行代碼,直接反手關掉vscode繼續手動連線。連完應該差不多這個樣子。
外部看起來是這樣子的,RD1輸出A1對應寄存器的值,RD2輸出A2對應寄存器的值,當寫使能信號WE3有效時,將在時鍾上升沿把WD3寫入A3對應的寄存器。
EXT
將imm16擴展后輸出。由於我的lui是使用的EXT加載到高位(好像說其實應該用ALU實現?),因此我的EXT有3個功能分別是無符號擴展、符號擴展、左移16位。
ALU
根據ALUOp進行不同的運算即可,這里加法和減法用的一個加法器(A-B=A+~B+1),但是好像這樣不太好擴展(?)
DM
本來是一個非常簡單的RAM,但是由於做了lb、sb、lh、sh,就得對DM前后加上組合邏輯以保證不改變其他位的數據。這里用兩個控制信號,SSel控制store時的位寬,LSel控制Load時的位寬。(其實用一個控制信號就可以,當時做的時候傻了一下用了兩個)
使用一個譯碼器,選擇被替換的那一段,如sb時,A的01位為01,那么就會將DM中的對應地址的32位數據中的815位替換成WD的低8位,再存入DM,這樣就保證了僅讀入一個字節而對其他位不改變,即實現了sb。
Controller
使用了最簡朴的方法,搭建時可以先用小手把opcode和funct點成要添加的指令,然后再連接出該指令。如果opcode是000000,那么再與funct得出的信號並起來,即得到該指令,如圖中的addu和subu。
得到指令后,再根據列的真值表,把在真值表中是1的連上
如對於NPCOp[1:0],只有beq時為01,只有jal時為10,只有jr時為11,也就是NPCOp[0]僅在beq和jr時取1,NPCOp[1]僅在jal和jr時取1,所以把他們連接起來即可,如下圖。
對於每一個控制信號都如此連接,即可完成CPU的搭建。
添加指令
注意事項
- 在改變與門或者或門的輸入數據個數時,建議從奇數個到奇數個,否則可能出現這樣的情況:如我有一個5input的或門,如下
現在要添加第6個input,如果直接改成6input,那么如圖所示
發現中間的空掉了
而如果遵循奇數個改奇數個的原則就不會出錯,如將number of input改成7就如下圖所示,中間的連上了。
eg:添加addiu
首先分析數據通路
判斷是否需要增加新的通路以實現該指令,可以看出其需要的功能我的CPU都有了,因此直接修改控制信號即可
確定控制信號
對於NPCOp,這不是一個跳轉指令,因此NPCOp取00
對於RFWr,要回寫到R[rt],因此RFWr為1
對於EXTOp,要進行符號擴展,所以取01
對於ALUOp,加法,所以取00
對於DMWr,不用寫入DM,所以取0
對於WRSel,由於寫入的是R[rt],所以取01
對於WDSel,由於寫入的數據來自ALU的計算結果,所以取00
對於BSel,由於參與ALU計算的第二個數來自EXT,所以取1
對於SSel和LSel,由於不涉及半字或字節,都取00
添加指令信號
首先將opcode點成該指令
然后再連接出addiu
這時候由於opcode即addiu指令,應該只有addiu是亮的。
修改控制信號
得到addiu信號后,僅需要在addiu控制信號為1的對應位置連線即可,如addiu只有RFWr、EXTOp[0]、WRSel[0]、BSel為1,所以只需要將他們的或門添加一根線與addiu信號連接。連接完成后,應檢查一遍此時的控制信號是否與之前分析的一樣。
可以看到與之前分析的完全一樣,至此addiu的添加完成。