簡單的多週期MIPS I CPU設計(二)—— 指令執行階段
通常我們將RISC CPU的指令的執行過程分為5個步驟,分別是取指令(IF)、解碼(ID)、執行(EX)、記憶體讀寫(MEM)、暫存器寫(WB)。我們要實現CPU,可以將5個步驟做成5個子模組分別設計,這樣可以大大降低我們的開發複雜度。
取指令(IF)
CPU在取指令階段(IF階段)時,先向一級指令快取要指令,要到指令後我們將程式計數器(PC)自增1(1表示移動一條指令的寬度,如果資料單位是32位,那麼就自增1,如果資料單位是8位1位元組,那麼就自增4)。這樣我們在下次取指令的時候就能取到下一條指令了。同時如果你實現了分支預測,那麼在這裡則需要做另外的處理。
那麼我們的取指令模組fetch_unit.v
的埠如下:
埠種類 | 埠名 | 埠意義 |
---|---|---|
input | clk | 時鐘訊號 |
input | rst_n | 復位訊號 |
input | stall | 阻塞訊號 |
input | rw | 讀寫狀態 |
input | write | 跳轉到的地址 |
output | pc | 程式計數器 |
當不阻塞時,寫狀態則將pc置為write,否則自增。很簡單的邏輯。
always @(posedge clk, negedge rst_n)
if (!rst_n)
pc <= 0; // 復位
else
if (!stall) // 如果未被阻塞(和流水線有關)
if (rw == `MEM_WRITE) // 寫狀態,二選一的資料選擇器
pc <= write; // 預置端
else // 預設狀態
pc <= pc + 1; // 一個加法單元,其中一個運算元固定為1
解碼(ID)
注意到我們有這些指令對:add和addi,addu和addui,or和ori等,這些指令對的功能是一樣的,只是取運算元的方式不一樣,如果我們能用某種方式統一這些指令對,那麼我們在實現這些指令的執行將會變得更簡單,因為對於同一類的指令我們能做同一個操作。解碼器就是做這個事情的。我們要實現的解碼器將會把指令的資訊分成如下的幾條:
資訊代號 | 資訊描述 |
---|---|
rs | 左運算元暫存器代號 |
nop、lui、j、jal、mflo、mfhi不需要 | |
rs_enable | 是否有左運算元 |
nop、lui、j、jal、mflo、mfhi指令該項為false | |
rt | 右運算元暫存器代號 |
對於所有有立即數(imm和shamt)和只需要讀取一個暫存器的指令都不需要 | |
rt_enable | 是否有右運算元/右運算元是否從暫存器中提取 |
對於所有有立即數(imm和shamt)和只需要讀取一個暫存器的指令該項為false | |
rd | 結果存放的暫存器代號 |
對於所有有立即數(imm)的指令,和指令中的rt部分相等 | |
imm | 32位立即數(如果指令有立即數imm,需要擴充套件至32位 |
算術運算(無論是有符號還是無符號)均為有符號擴充套件,邏輯與地址運算均為無符號擴充套件 | |
alu_op | ALU的微指令碼 |
需要和ALU一致 | |
addr | 跳轉指令要跳轉到的地址 |
對於j類指令,addr為立即數;對於b類指令,由傳入的pc和立即數運算得到 | |
ex_src | 執行階段使用ALU、浮點運算單元、還是整數乘除單元 |
\makecell{mul、mulu、div、divu採用整數乘除單元;浮點運算採用FPU;\\算術邏輯地址運算使用ALU;否則交由外部裝置執行 | |
b_ctrl | 控制右運算元使用立即數代替還是從暫存器中取數 |
有立即數的指令均為真,否則為假 | |
mem_width | 讀寫記憶體的時候是位元組模式、半字模式還是字模式 |
lb、lbu、sb、sbu為位元組模式;lh、lhu、sh、shu為半字模式;lw、sw為字模式 | |
mem_rw | 寫記憶體還是讀記憶體 |
l類指令為讀記憶體(低電平);s類指令為寫記憶體(高電平) | |
mem_enable | 指令是否要操作記憶體 |
比如lb, sb之類的指令需要操作記憶體 | |
sign_extend | 記憶體操作時是否進行符號擴充套件 |
\makecell{lb、lh、lbu、sb、sh之類的指令不足一個字,而暫存器為1個字長\\u類指令需要零擴充套件,非u類指令為符號擴充套件 | |
wb_src | WB階段寫入暫存器的資料從ALU拿還是從記憶體拿 |
運算類指令從ALU拿,l類指令從記憶體拿 | |
wb_reg | WB階段是否需要將資料寫回到暫存器 |
跳轉、儲存、浮點運算、整數乘除都不需要將資料寫回 | |
jump | 跳轉到的地址在暫存器中儲存還是從指令中的地址碼拿 |
jr和jalr需要,j和jal不需要 | |
branch | 是否是跳轉指令 |
j類指令和b類指令為真 |
CPU在解碼階段(ID階段)時還需要根據解碼器得到的運算元暫存器的編號,從相應的暫存器中取出ALU所需要的運算元,因此我們也將暫存器歸到解碼階段中。
執行(EX)
執行階段(EX階段)是我們呼叫ALU進行真正的計算過程。由於乘法和除法的速度比較慢,如果1個週期能完成加法的計算,那麼乘法和除法就需要超過1個週期的時間,也就是說乘法器和除法器在多週期CPU裡是多週期的。同時,所有的浮點運算也都是多週期的,比如浮點加是4個週期(另外在浮點運算單元中同樣存在流水線,把浮點加法分成4個階段計算)。
同時對於syscall
指令,我們也要在執行階段完成操作。
因此執行階段CPU一共會有以下執行模組,分別是ALU、整數的乘除運算單元、浮點運算單元(內部仍存在流水線,而且加減法和乘除法可以並行執行)和其他的一些處理電路。
ALU
ALU在執行階段將會按照給定的ALU的微指令,對兩個運算元進行運算(無論是加減運算、位運算、比較運算以及跳轉指令需要的比較運算),並得到結果輸出(輸出包括運算結果、是否跳轉等資訊)。對於記憶體操作的指令,我們也需要ALU計算出我們要讀取的記憶體的真實地址(因為指令規範中給定的是某個暫存器的偏移,或者當前指令的偏移)。
當解碼階段得到的ALU使能訊號為真時,ALU計算結果。目前我們要支援的運算如下:
代號 | 描述 | 代號 | 描述 | 代號 | 描述 | 代號 | 描述 |
---|---|---|---|---|---|---|---|
sll | 邏輯左移 | srl | 邏輯右移 | sra | 算術右移 | lu | 左移16位 |
mfhi | 載入乘除法的高32位 | mflo | 載入乘除法的低32位 | ||||
add | 加法 | sub | 減法 | and | 邏輯與 | or | 邏輯或 |
xor | 異或 | nor | 同或 | slt | 算術比較 | sltu | 無符號算術比較 |
beq | 相等跳轉 | bne | 不相等跳轉 | bltz | 小於零跳轉 | bgez | 大於等於零跳轉 |
blez | 小於等於零跳轉 | bgtz | 大於零跳轉 |
ALU的埠如下:
埠種類 | 埠名 | 埠意義 |
---|---|---|
input | stall | 阻塞訊號 |
input | en | 使能訊號 |
input | op | 微指令 |
input | rs | 運算元 |
input | rt | 運算元 |
output | rd | 運算結果 |
output | branch | 是否跳轉 |
output | test_state | 執行測試用指令結果 |
那麼實現一個ALU就是一個大的無條件always語句以及case語句了。
電路方面就是多路選擇器。
記憶體讀寫(MEM)
對於lb
、lbu
、lh
、lhu
、lw
、sb
、sbu
、sh
、shu
、sw
等記憶體操作的指令,這個階段將被啟用。這個階段將會與一級的資料快取互動。
暫存器寫(WB)
這個階段(WB階段)有結果的指令將會把資料存到對應的暫存器裡。
相關文章
- Mips單週期CPU設計(logisim實現)
- 手寫一個簡易的多週期 MIPS CPU
- react 學習--元件的生命週期(二)執行階段React元件
- MIPS單週期處理器設計
- MIPS指令的CPU實現:ALU設計
- 單週期cpu設計程式碼解讀
- Vivado實戰—單週期CPU指令分析
- JAVA面試題 執行緒的生命週期包括哪幾個階段?Java面試題執行緒
- Java多執行緒程式設計——進階篇二Java執行緒程式設計
- 執行緒的生命週期,真的沒那麼簡單執行緒
- 【Java】【多執行緒】執行緒的生命週期Java執行緒
- Java多執行緒設計模式(6)兩階段終止模式Java執行緒設計模式
- 設定週期性自動執行備份指令碼指令碼
- 多執行緒-執行緒生命週期圖解執行緒圖解
- <react學習筆記(4)>元件的生命週期(執行階段和銷燬階段)以及事件處理函式React筆記元件事件函式
- Solidity的生命週期包含哪些階段?Solid
- 這麼理解執行緒生命週期,是不是很簡單?執行緒
- 深入React的生命週期(上):出生階段(Mount)React
- 簡單的執行緒池(二)執行緒
- Python多執行緒程式設計(二)Python執行緒程式設計
- 【計組5.2】指令週期
- 多執行緒程式設計基礎(二)-- 執行緒池的使用執行緒程式設計
- wxWidgets簡單的多執行緒執行緒
- Java多執行緒學習(1)建立執行緒與執行緒的生命週期Java執行緒
- Spring Bean各階段生命週期的介紹SpringBean
- React 元件的生命週期可以分為哪些階段React元件
- 執行緒的【生命週期】和【執行緒的同步】(多視窗售票例子)執行緒
- 啃碎併發(二):Java執行緒的生命週期Java執行緒
- Java多執行緒程式設計——進階篇一Java執行緒程式設計
- Java指定週期執行執行緒Java執行緒
- 【原創】Java多執行緒初學者指南(4):執行緒的生命週期Java執行緒
- javascript引擎執行的過程的理解--執行階段JavaScript
- react 學習--元件的生命週期(三)銷燬階段React元件
- IOS高階程式設計之三:IOS 多執行緒程式設計iOS程式設計執行緒
- Java執行緒的生命週期Java執行緒
- 【多執行緒高併發程式設計】二 實現多執行緒的幾種方式執行緒程式設計
- 時鐘週期,機器週期,指令週期
- 簡簡單單的Vue2(簡單語法,生命週期,元件)Vue元件