基于MIPS的五級流水線微處理器CPU設(shè)計,verilog編寫,modelsim和vivado仿真通過

摘 ?要
本設(shè)計為一個五級流水線CPU,此CPU結(jié)構(gòu)為MIPS結(jié)構(gòu)。流水線CPU與單周期和多周期CPU相比較,提高了指令的執(zhí)行速度,改善了CPU的整體吞吐率,提高了CPU的性能。流水線CPU相對單周期CPU和多周期CPU,硬件設(shè)計上也更復(fù)雜,并且還有許多使流水線斷流的因素。在設(shè)計中,重點(diǎn)解決影響流水線的數(shù)據(jù)相關(guān)、結(jié)構(gòu)相關(guān)、控制相關(guān),做到充分流水。

獲取程序verilog源碼 設(shè)計文檔 聯(lián)系企鵝號?3270516346
一、流水線概述
1、設(shè)計內(nèi)容
????本設(shè)計為一個五級流水線CPU,采用MIPS結(jié)構(gòu)。此CPU支持多種指令集,能夠滿足基本的功能需求。在此設(shè)計中,編寫了一個求平均數(shù)和實(shí)現(xiàn)位反轉(zhuǎn)的程序,以驗證CPU功能的正確性以及是否充分流水。
2、流水線原理
???cpu流水線技術(shù)是一種將指令分解為多步,并讓不同指令的各步操作重疊,從而實(shí)現(xiàn)幾條指令并行處理,以加速程序運(yùn)行過程的技術(shù)。指令的每步有各自獨(dú)立的電路來處理,每完成一步,就進(jìn)到下一步,而前一步則處理后續(xù)指令。

3、指令執(zhí)行階段
??取指令(IF)、譯碼(ID)、執(zhí)行(EX)、訪存(MEM)、回寫(WB)
二、指令系統(tǒng)設(shè)計
??1、指令格式
①?R型指令:寄存器操作

op: 操作碼
rs、rt :源操作數(shù)
rd :目的操作數(shù)
funct : 使用操作碼告訴計算機(jī)執(zhí)行什么操作
shamt:位移指令的位移量,不是位移指令就為0
②I型指令:立即數(shù)型

op : 操作碼
??rs : 源操作數(shù)
??rt : 目的操作數(shù)
??imm: 立即數(shù)
③J型指令:跳轉(zhuǎn)類型

?op : 操作數(shù)
addr: 立即數(shù),跳轉(zhuǎn)地址
2、CPU寄存器
MIPS架構(gòu)的CPU擁有32個通用寄存器和32個浮點(diǎn)寄存器,每個寄存器的編號、代號以及用途如下:

3、設(shè)計的指令及功能
add: ?R-R型,寄存器相加運(yùn)算

sub : R-R型,寄存器相減運(yùn)算

and :R-R型,寄存器與運(yùn)算

div :R-R型,寄存器相除

addi : R-I型,立即數(shù)與寄存器相加運(yùn)算

j :跳轉(zhuǎn)指令

lw : R-I型指令 ?,加載存儲字

sw : R-I型指令 ?,存儲字

ben :R-I型,相等時轉(zhuǎn)移
?

4、10個數(shù)累加并求平均數(shù)的指令設(shè)計
使用了S0到S5這六個寄存器

對應(yīng)的二進(jìn)制代碼為:

三、模塊詳細(xì)設(shè)計
???1、寄存器模塊設(shè)計
????①程序計數(shù)器設(shè)計(PC)
程序計數(shù)器為一個32位的寄存器,它決定下一條將要執(zhí)行的命令的地址。PC有一個輸入端輸入下一地址,一個輸出端決定當(dāng)前程序執(zhí)行地址,在此PC中還加入了一個使能位,以配合流水線CPU的控制。
???②次地址計算單元(NPC)
???次地址計算單元的功能為計算下一地址,當(dāng)指令不是轉(zhuǎn)移類指令時,它就是加4,次地址為連續(xù)的下一地址單元。
?? ?③指令寄存器(IM)
?? IM用于存儲指令,為只讀存儲器。它有兩個端口,一個為地址輸入,另一個為指定地址處的數(shù)據(jù)輸出。

④寄存器堆(RF)
?? 寄存器堆為CPU中指令執(zhí)行時所用到的寄存器,在該寄存器堆設(shè)計中,用兩個讀取數(shù)據(jù)端,對應(yīng)指令中兩個源操作數(shù),一個數(shù)據(jù)寫入段,用于對數(shù)據(jù)的寫入。

?、輸?shù)據(jù)存儲器(DM)
? ?DM為RAM型存儲器,它有一個讀寫控制端,讀寫控制端為低電平時,對DM讀操作,高電平時,對DM讀操作。

?2、算數(shù)邏輯單元(ALU)
? ?ALU的功能為對輸入的數(shù)據(jù)進(jìn)行加減等算數(shù)運(yùn)算,ALU有一個控制端F,根據(jù)輸入F的不同,對輸入的數(shù)據(jù)進(jìn)行不同的運(yùn)算。

?3、數(shù)據(jù)擴(kuò)展模塊(EXT)
?? 對于立即數(shù)類的指令,立即數(shù)為16位數(shù)據(jù),立即數(shù)要與RF輸出的32位數(shù)據(jù)進(jìn)行運(yùn)算。為了在運(yùn)算時對數(shù)據(jù)進(jìn)行匹配,需要將立即數(shù)擴(kuò)展為32位,對輸入的立即數(shù)進(jìn)行補(bǔ)碼擴(kuò)展。

4、主控制器(CU)
控制器的職責(zé)為根據(jù)指令的操作碼和funct域計算出每條指令在執(zhí)行時控制信號應(yīng)取何值。
控制器首先判斷OP位是否為零(即指令是否為寄存器型指令),當(dāng)OP為為零時,CU則根據(jù)funct位輸出相應(yīng)的控制信號,否則則根據(jù)OP位輸出相應(yīng)的控制信號。
CU有7種輸出控制信號:cs為NPC的控制位,決定NPC如何計算下一地址;rf_wr為寄存器堆讀寫控制信號;dm_wr為數(shù)據(jù)存儲器控制信號;ALUop為ALU的控制信號,決定ALU做怎樣的運(yùn)算;m1sel、m2sel、m3sel為三個MUX的選擇控制信號。
四、流水線的數(shù)據(jù)通路
1、在流水線的兩級之間插入寄存器用于數(shù)據(jù)的暫存,各級之間插入的寄存器
IF_ID:取指令與指令譯碼之間的寄存器,為配合流水線相關(guān)控制,該寄存器有使能端和異步復(fù)位端。
ID_EX:指令譯碼與指令執(zhí)行階段之間的寄存器,該寄存器有異步復(fù)位端。該寄存器除要傳輸數(shù)據(jù)外,還需要傳輸控制信號以及指令的信息。
EX_MEM:執(zhí)行階段與讀存儲器階段之間的寄存器,需要傳遞控制信號與相應(yīng)的指令信息。
MEM_WB:讀存儲器與回寫階段之間的寄存器,需要傳遞控制信號與相應(yīng)的指令信息。

2、CPU的數(shù)據(jù)通通路
五級流水線CPU的數(shù)據(jù)通路為在單周期CPU的數(shù)據(jù)通路中插入四個流水線寄存器實(shí)現(xiàn)。并且要注意在指令執(zhí)行過程中,指令的相關(guān)信息必須沿流水線傳遞到數(shù)據(jù)執(zhí)行結(jié)束。
五、流水線相關(guān)性的解決
1、相關(guān)控制器
為了使設(shè)計更加簡潔,構(gòu)造了一個相關(guān)控制器專門用于檢測相關(guān)并進(jìn)行處理。在相關(guān)控制器中分為檢測機(jī)構(gòu)與執(zhí)行機(jī)構(gòu),檢測機(jī)構(gòu)用于檢測相關(guān)性,執(zhí)行機(jī)構(gòu)用于檢測到相關(guān)時如何進(jìn)行處理。

2、結(jié)構(gòu)相關(guān)
結(jié)構(gòu)相關(guān)是由于?多條指令需要同時爭用同一個功能部件引起的沖突。在次CPU設(shè)計中,采用了IM與DM分離的設(shè)計,故流水線可以支持讀指令與讀寫數(shù)據(jù)的并行執(zhí)行,不存在存儲器爭用問題。對于同時出現(xiàn)的寄存器堆讀寫操作來說,雖然寄存器堆只有一個,但其結(jié)構(gòu)采用了讀寫雙端口設(shè)計,這樣就能同時支持對寄存器堆的讀寫兩個操作,不存在寄存器堆的資源沖突。所以在此設(shè)計的CPU中,不存在結(jié)構(gòu)相關(guān)。
?3、數(shù)據(jù)相關(guān)
????數(shù)據(jù)相關(guān)是因為后進(jìn)入流水線的指令需要引用先期進(jìn)入流水線正在執(zhí)行的指令計算結(jié)果而引起的沖突。相應(yīng)的解決方案有數(shù)據(jù)轉(zhuǎn)發(fā)和數(shù)據(jù)暫停機(jī)制。
①數(shù)據(jù)轉(zhuǎn)發(fā):對于數(shù)據(jù)相關(guān),如果寄存器新值已經(jīng)出現(xiàn)在流水線中的某級寄存器了,則可以將這個數(shù)據(jù)從該寄存器直接輸入致需要使用該寄存器值的功能部件,這種技術(shù)成為轉(zhuǎn)發(fā)(或旁路)。
為了實(shí)現(xiàn)轉(zhuǎn)發(fā),首先需要分析目的寄存器的新值會出現(xiàn)在那些流水線寄存器中,其次對于一條指令來說,要分析它真正使用新值的地方。
②數(shù)據(jù)暫停:當(dāng)出現(xiàn)lw等指令時,如果下一條指令需要lw的執(zhí)行結(jié)果,但lw的執(zhí)行結(jié)果最早也要在其第四個時鐘周期才出現(xiàn),轉(zhuǎn)發(fā)無法解決這一問題,辦法只有暫停后續(xù)指令的執(zhí)行。

暫停包括兩個環(huán)節(jié)。首先暫停取指令,必須禁止PC繼續(xù)執(zhí)行+4計數(shù)(PC寄存器的使能端置零)。其次向后級流水線注入空操作,將后級流水線清空(使能寄存器的異步清楚操作)。
4、控制相關(guān)
因為在程序中存在分支、函數(shù)調(diào)用等,所以在指令執(zhí)行過程中會存在導(dǎo)致指令執(zhí)行方向改變的相關(guān)指令。控制相關(guān)就是指指令執(zhí)行方向改變,但流水線在取下一條指令時卻不知道該從那個方向取指令。如下例所示如果流水線不對執(zhí)行過程中做任何處理,那么本不該執(zhí)行的add與sub均會被錯誤的執(zhí)行??梢酝ㄟ^縮短分支延時解決。

縮短分支延時:流水線中,盡早完成分支的決策,可以減少性能損失。(以beq指令為例)假設(shè)圖中分支目標(biāo)地址的輸出階段從MEM級前移到EX級,那么圖中(下圖)的指令序列只需要被阻塞2個時鐘周期就能解決控制冒險因為正確的目標(biāo)地址在EX級形成,EX級結(jié)束時就更新了PC寄存器。
六、設(shè)計結(jié)果
??采用Modelsim進(jìn)行仿真,對頂層模塊外加時鐘信號和復(fù)位信號,仿真波形如下:

從使用的寄存器值的變化可以看出指令執(zhí)行過程正確,最終的的結(jié)果正確(圖中y0~y5代表寄存器s0~s5,y為最終存放結(jié)果的存儲器)。

圖中為PC的使能信號與流水線寄存器的使能和控制信號,可見在指令執(zhí)行過程中,當(dāng)出現(xiàn)控制相關(guān)時,這些控制信號在不斷變化,證明當(dāng)存在指令的控制相關(guān)時,這些控制信號在不斷解決這些相關(guān)。
圖中為在相關(guān)控制器中解決數(shù)據(jù)相關(guān)的控制信號,在指令執(zhí)行過程中,在出現(xiàn)數(shù)據(jù)相關(guān)的位置,控制信號不斷變化,可以證明解決了數(shù)據(jù)相關(guān)的問題。

參考文獻(xiàn)
[1] 唐朔飛. 計算機(jī)組成原理.第?2 版. 高等教育出版社, 2020.
[2] 高小鵬. 計算機(jī)組成與實(shí)現(xiàn).第1版. 高等教育出版社, 2018.
附錄
1、完整流水線CPU結(jié)構(gòu)圖:

2、頂層文件代碼(部分)
module cpu_top(
???????????????input clk,
???????????????input reset,
???????????????);
wire [31:0] pc,npc,ext,exte;
wire m1sel,m2sel,m3sel,rf_wr,dm_wr,zero;
wire m1sele,m2sele,m3sele,dm_wre,rf_wre,m2selw,m2selm;
wire [4:0] rsD,rtD,rdD,rsE,rtE,rdE,dstE,dstM,dstW;
?
?wire [31:0] RDs,RD_o ; ???????????
?wire [2:0] ALUop,ALUope; ?
?wire [31:0] RD1o,RD2o;
?
wire PCEnD,FlushD,FlushE,FrsD,FrtD,EnD;
wire [1:0] FrsE,FrtE;
???????????????
PC ????PC_inst(
???????????????.clk(clk),
???????????????.reset(reset),
???????????????.di(npc),
???????????????.do(pc),
???????????????.PCEnD(PCEnD)??????????
???????????????);
wire [31:0] ID;
assign rsD=ID[25:21];
assign rtD=ID[20:16];
assign rdD=ID[15:11];
?
wire [31:0] ALU_out,ALU_outm,ALU_outw,A,B,Bs,Bs_o;
?
?wire [31:0] WD,RD1,RD2,RD1_o,RD2_o;
?wire [4:0] A3;
?assign RD1_o=(FrsD==1'b0)? RD1:ALU_outm;
?assign RD2_o=(FrtD==1'b0)? RD2:ALU_outm;
?
?assign A3=dstW;
?assign WD=(m2selw==1'b0)?ALU_outw:RD_o; ???
?assign zero=(RD1_o==RD2_o)?1'b1:1'b0; ???
RF ??RF_Inst(
?????????????.clk(clk),
?????????????.wr(rf_wrw),
?????????????.A1(ID[25:21]),
?????????????.A2(ID[20:16]),
?????????????.A3(A3),
?????????????.WD(WD),
?????????????.RD1(RD1),
?????????????.RD2(RD2),
?????????????); ?????????
wire [2:0] cs;
NPC ??NPC_inst(
????????????????.pc(pc),
????????????????.cs(cs),
????????????????.ra(RD1_o),
????????????????.imm(ID[25:0]),
????????????????.npc(npc),
????????????????.zero(zero)
???????????????);
?wire [31:0] RD; ?????????????
IM ?IM_inst(
????????????.A(pc),
????????????.D(RD)
?????????????);
IF_ID ?IF_ID_inst(
??????????????????.clk(clk),
??????????????????.FlushD(FlushD),
??????????????????.EnD(EnD),
??????????????????.IF(RD),
??????????????????.ID(ID) ????
??????????????????); ?????
EXT ?EXT_inst(
??????????????.in16(ID[15:0]),
??????????????.out32(ext)
??????????????); ???????
ID_EX ????ID_EX_inst(
??????????????.clk(clk),
??????????????.s(FlushE),
??????????????.rf_wr(rf_wr),
??????????????.dm_wr(dm_wr),
??????????????.m1sel(m1sel),
??????????????.m2sel(m2sel),
??????????????.m3sel(m3sel),
??????????????.ext(ext),
??????????????.ALUop(ALUop),
??????????????.rsD(rsD),
??????????????.rtD(rtD),
??????????????.rdD(rdD),
??????????????.RD1(RD1_o),
??????????????.RD2(RD2_o),
??????????????.rf_wre(rf_wre),
??????????????.dm_wre(dm_wre),
??????????????.m1sele(m1sele),
??????????????.m2sele(m2sele),
??????????????.m3sele(m3sele),
??????????????.ALUope(ALUope),
??????????????.exte(exte),
??????????????.rsE(rsE),
??????????????.rtE(rtE),
??????????????.rdE(rdE),
??????????????.RD1o(RD1o),
??????????????.RD2o(RD2o)
??????????????); ????????????
??????????????
assign A=(FrsE==2'b00)? RD1o: ((FrsE==2'b01)?WD:ALU_outm); ?
assign Bs=(FrtE==2'b00)? RD2o: ((FrtE==2'b01)?WD:ALU_outm); ?
assign B=(m3sele==1'b0)? Bs:exte; ????
ALU ?ALU_inst(
??????????????.A(A),
??????????????.B(B),
??????????????.F(ALUope),
??????????????.Y(ALU_out)
?????????????);
assign dstE=(m1sele==1'b0)?rtE:rdE;
EX_MEM ???EX_MEM_inst(
??????????????.clk(clk),
??????????????.rf_wre(rf_wre),
??????????????.m2sele(m2sele),
??????????????.dm_wre(dm_wre),
??????????????.ALU_out(ALU_out),
??????????????.wd_i(Bs),
??????????????.dste(dstE),
??????????????.rf_wrm(rf_wrm),
??????????????.m2selm(m2selm),
??????????????.dm_wrm(dm_wrm),
??????????????.ALU_outm(ALU_outm),
??????????????.wd_o(Bs_o),
??????????????.dstm(dstM)
??????????????);
DM ??DM_inst(
?????????????.A(ALU_outm),
?????????????.WD(Bs_o),
?????????????.wr(dm_wrm),
?????????????.clk(clk),
?????????????.RD(RDs),
?????????????);
MEM_WB ????MEM_WB_inst(
???????????????.clk(clk),
???????????????.rf_wrm(rf_wrm),
???????????????.m2selm(m2selm),
???????????????.ALU_outm(ALU_outm),
???????????????.RD_i(RDs),
???????????????.dstm(dstM),
???????????????.rf_wrw(rf_wrw),
???????????????.m2selw(m2selw),
???????????????.ALU_outw(ALU_outw),
???????????????.RD_o(RD_o),
???????????????.dstw(dstW)
????????????????????); ???????????
CU ??CU_inst(
?????????????.op(ID[31:26]),
?????????????.fun(ID[5:0]),
?????????????.cs(cs),
?????????????.rf_wr(rf_wr),
?????????????.dm_wr(dm_wr),
?????????????.m1sel(m1sel),
?????????????.m2sel(m2sel),
?????????????.m3sel(m3sel),
?????????????.ALUop(ALUop)
?????????????);
?????????????
CUm ????CUM_inst(
????????????.rsD(rsD),
????????????.rtD(rtD),
????????????.rsE(rsE),
????????????.rtE(rtE),
????????????.dstE(dstE),
????????????.dstM(dstM),
????????????.dstW(dstW),
????????????.rf_wre(rf_wre),
????????????.rf_wrm(rf_wrm),
????????????.rf_wrw(rf_wrw),
????????????.dm_wre(dm_wre),
????????????.dm_wrm(dm_wrm),
????????????.cs(cs),
????????????.zero(zero),
????????????.PCEnD(PCEnD),
????????????.FlushD(FlushD),
????????????.FlushE(FlushE),
????????????.EnD(EnD),
????????????.FrsD(FrsD),
????????????.FrtD(FrtD),
????????????.FrsE(FrsE),
????????????.FrtE(FrtE),
????????????.m2sele(m2sele)
???????????);
endmodule