1. 程式人生 > >使用logisim搭建單週期CPU與新增指令

使用logisim搭建單週期CPU與新增指令

# 使用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} ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201127114114561.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1NTUxOTMw,size_16,color_FFFFFF,t_70#pic_center) 下面分模組逐個分析 ### PC 本質上就是一個32位的暫存器,這裡採用的是非同步復位,所以直接把reset訊號連在clear口。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/2020112711421427.png#pic_center) ### NPC 由於我的CPU支援beq、jal、jr,所以NPCOp有2位,如下表所示 | NPCOp | 功能 | | :---: | :------------------: | | 00 | 計算順序地址(PC+4) | | 01 | 計算beq地址 | | 10 | 計算jal地址 | | 11 | 計算jr地址 | ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201127114252628.png#pic_center) 其中PC4是用來把PC+4輸出至RF以完成jal指令 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201127114313844.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1NTUxOTMw,size_16,color_FFFFFF,t_70#pic_center) ### IM 這個就更簡單了,直接一個ROM搞定,注意把PC的2~6位引出作為IM的地址。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201127114405272.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1NTUxOTMw,size_16,color_FFFFFF,t_70#pic_center) ### RF 這個比較耗時間,聽說用vscode開啟.circ檔案就可以寫程式碼去搭建這玩意,開啟後發現3k行程式碼,直接反手關掉vscode繼續手動連線。連完應該差不多這個樣子。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201127114423896.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1NTUxOTMw,size_16,color_FFFFFF,t_70#pic_center) 外部看起來是這樣子的,RD1輸出A1對應暫存器的值,RD2輸出A2對應暫存器的值,當寫使能訊號WE3有效時,將在時鐘上升沿把WD3寫入A3對應的暫存器。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201127114438256.png#pic_center) ### EXT 將imm16擴充套件後輸出。由於我的lui是使用的EXT載入到高位(好像說其實應該用ALU實現?),因此我的EXT有3個功能分別是無符號擴充套件、符號擴充套件、左移16位。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201127114451728.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1NTUxOTMw,size_16,color_FFFFFF,t_70#pic_center) ### ALU 根據ALUOp進行不同的運算即可,這裡加法和減法用的一個加法器(A-B=A+~B+1),但是好像這樣不太好擴充套件(?) ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201127114510507.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1NTUxOTMw,size_16,color_FFFFFF,t_70#pic_center) ### DM 本來是一個非常簡單的RAM,但是由於做了lb、sb、lh、sh,就得對DM前後加上組合邏輯以保證不改變其他位的資料。這裡用兩個控制訊號,SSel控制store時的位寬,LSel控制Load時的位寬。(其實用一個控制訊號就可以,當時做的時候傻了一下用了兩個) 使用一個譯碼器,選擇被替換的那一段,如sb時,A的0~1位為01,那麼就會將DM中的對應地址的32位資料中的8~15位替換成WD的低8位,再存入DM,這樣就保證了僅讀入一個位元組而對其他位不改變,即實現了sb。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201127114528367.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1NTUxOTMw,size_16,color_FFFFFF,t_70#pic_center) ### Controller 使用了最簡樸的方法,搭建時可以先用小手把opcode和funct點成要新增的指令,然後再連接出該指令。如果opcode是000000,那麼再與funct得出的訊號並起來,即得到該指令,如圖中的addu和subu。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/202011271145575.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1NTUxOTMw,size_16,color_FFFFFF,t_70#pic_center) 得到指令後,再根據列的真值表,把在真值表中是1的連上 如對於NPCOp[1:0],只有beq時為01,只有jal時為10,只有jr時為11,也就是NPCOp[0]僅在beq和jr時取1,NPCOp[1]僅在jal和jr時取1,所以把他們連線起來即可,如下圖。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201127114615212.png#pic_center) 對於每一個控制訊號都如此連線,即可完成CPU的搭建。 ## 新增指令 ### 注意事項 - 在改變與門或者或門的輸入資料個數時,建議從奇數個到奇數個,否則可能出現這樣的情況:如我有一個5input的或門,如下 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201127114630930.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1NTUxOTMw,size_16,color_FFFFFF,t_70#pic_center) 現在要新增第6個input,如果直接改成6input,那麼如圖所示 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201127114645404.png#pic_center) 發現中間的空掉了 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201127114658778.png#pic_center) 而如果遵循奇數個改奇數個的原則就不會出錯,如將number of input改成7就如下圖所示,中間的連上了。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201127114709644.png#pic_center) ### eg:新增addiu #### 首先分析資料通路 判斷是否需要增加新的通路以實現該指令,可以看出其需要的功能我的CPU都有了,因此直接修改控制訊號即可 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201127114722838.png#pic_center) #### 確定控制訊號 對於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點成該指令 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201127114735674.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1NTUxOTMw,size_16,color_FFFFFF,t_70#pic_center) 然後再連接出addiu ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201127114747992.png#pic_center) 這時候由於opcode即addiu指令,應該只有addiu是亮的。 #### 修改控制訊號 得到addiu訊號後,僅需要在addiu控制訊號為1的對應位置連線即可,如addiu只有RFWr、EXTOp[0]、WRSel[0]、BSel為1,所以只需要將他們的或門新增一根線與addiu訊號連線。連線完成後,應檢查一遍此時的控制訊號是否與之前分析的一樣。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201127114924744.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1NTUxOTMw,size_16,color_FFFFFF,t_70#pic_center) ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201127114930634.png#pic_center) 可以看到與之前分析的完全一樣,至此addiu的新增