实验目的
本关任务:
1.掌握流水线CPU的原理。
2.具有流水线CPU的设计能力。
3.熟悉 Vivado 的设计流程,具备电路的设计仿真和硬件测试能力。
4.能编写测试程序,测试流水线 CPU 的功能。
实验原理
1.流水线 CPU 实现的指令集
要求实现 20 条 MIPS 整数指令。

2.流水线 CPU 的指令执行过程
流水线技术:不要等一条指令执行完成后再执行下一条指令,而是把一条指令的执行分成若干“级”(Stage),不同的指令的不同的级可以在同一个周期同时执行。
5级流水线CPU把指令执行分成5个阶段,分别是:取指令IF级、指令译码ID级、指令执行EXE级、存储器访问MEM级和结果写回WB级。
流水线CPU设计的难点在于流水线的控制,有三大关键问题需要解决,分别为结构相关、数据相关和控制相关。
3.流水线计算机的总体设计
实现 20 条 MIPS 整数指令的多周期计算机的总体电路设计如图所示,由以下模块构成:PC、IF级的组合电路、IF级与ID级之间的流水线寄存器、ID级的组合电路、ID级与EXE级之间的流水线寄存器、EXE级的组合电路、EXE级与MEM级之间的流水线寄存器、MEM级的组合电路、MEM级与WB级之间的流水线寄存器、WB级的组合电路。

实验内容和要求
根据设计的实验方案,使用 Verilog HDL 编写相应代码。
对编写的代码进行仿真,得到正确的波形图。
将以上设计作为一个单独的模块,设计一个外围模块去调用该模块。
将编写的代码进行综合布局布线,进行硬件测试,做好实验记录,验证此设计的功能。
撰写实验报告,实验报告内容包括:程序设计、仿真分析、硬件测试和实验操作步骤,以及源程序代码、仿真波形图、数据记录和实验结果分析等。
实验步骤
创建工程
新建一个文件夹 pipeline_cpu,然后从中创建本实验的工程。启动 Vivado 软件,选择 “File → Project → New”菜单命令,输入工程名 “pipeline_cpu”,选择工程的文件位置。
模块设计
1)添加源文件
根据 MIPS 指令集设计流水线CPU pipeline_cpu.v。
添加已有 Verilog HDL 文件的方法为:在项目管理区中单击 “Add Sources” ,在弹出的对话框中选中 “Add or create design sources”。
2)添加外围展示模块
按照实验要求,还需要设计外围模块 pipeline_cpu_display.v ,用于调用 pipeline_cpu.v 和触摸屏模块,以便测试实验结果。
功能仿真
1)仿真测试模块
在进行功能仿真时,需要先建立一个测试模块 pipeline_cpu_tb.v。本实验需要产生的输入激励就是时钟信号 clock 和复位信号 resetn。
2)波形仿真
在左侧导航栏中单击 “Run Simulation”,然后选择 “Run Behavioral Simulation”,可以通过观察波形验证流水线 CPU 的功能。

module pipeline_cpu(clock, memclock, resetn, pc, inst, ealu, malu, walu);
input clock, memclock, resetn;
output [31:0] pc, inst, ealu, malu, walu;
wire [31:0] bpc, jpc, npc, pc4, ins;
wire [31:0] dpc4, da, db, dimm;
wire [31:0] epc4, ea, eb, eimm;
wire [31:0] mb, mmo, wmo, wdi;
wire [4:0] drn, ern0, ern, mrn, wrn;
wire [3:0] daluc, ealuc;
wire [1:0] pcsource_raw, pcsource;
wire wpcir;
wire dwreg_raw, dm2reg_raw, dwmem_raw, djal_raw;
wire dwreg, dm2reg, dwmem, daluimm, dshift, djal;
wire ewreg, em2reg, ewmem, ealuimm, eshift, ejal;
wire mwreg, mm2reg, mwmem;
wire wwreg, wm2reg;
reg flushid;
assign pcsource = pcsource_raw;
assign dwreg = dwreg_raw & ~flushid;
assign dm2reg = dm2reg_raw & ~flushid;
assign dwmem = dwmem_raw & ~flushid;
assign djal = djal_raw & ~flushid;
always @(negedge resetn or posedge clock)
if (!resetn)
flushid <= 1'b0;
else if (wpcir)
flushid <= djal_raw;
pipepc prog_cnt(npc, wpcir, clock, resetn, pc);
pipeif if_stage(pcsource, pc, bpc, da, jpc, npc, pc4, ins);
pipeir inst_reg(pc4, ins, wpcir, clock, resetn, dpc4, inst);
pipeid id_stage(mwreg, mrn, ern, ewreg, em2reg, mm2reg, dpc4, inst,
wrn, wdi, ealu, malu, mmo, wwreg, clock, resetn,
bpc, jpc, pcsource_raw, wpcir, dwreg_raw, dm2reg_raw,
dwmem_raw, daluc, daluimm, da, db, dimm, drn, dshift,
djal_raw);
pipedereg de_reg(dwreg, dm2reg, dwmem, daluc, daluimm, da, db, dimm,
drn, dshift, djal, dpc4, clock, resetn, ewreg,
em2reg, ewmem, ealuc, ealuimm, ea, eb, eimm, ern0,
eshift, ejal, epc4);
pipeexe exe_stage(ealuc, ealuimm, ea, eb, eimm, eshift, ern0, epc4,
ejal, ern, ealu);
pipeemreg em_reg(ewreg, em2reg, ewmem, ealu, eb, ern, clock, resetn,
mwreg, mm2reg, mwmem, malu, mb, mrn);
pipemem mem_stage(mwmem, malu, mb, clock, memclock, mmo);
pipemwreg mw_reg(mwreg, mm2reg, mmo, malu, mrn, clock, resetn,
wwreg, wm2reg, wmo, walu, wrn);
mux2x32 wb_stage(walu, wmo, wm2reg, wdi);
endmodule
module pipepc(npc, wpcir, clk, resetn, pc);
input [31:0] npc;
input wpcir, clk, resetn;
output [31:0] pc;
dffe32 program_counter(npc, clk, resetn, wpcir, pc);
endmodule
module pipeif(pcsource, pc, bpc, rpc, jpc, npc, pc4, ins);
input [31:0] pc, bpc, rpc, jpc;
input [1:0] pcsource;
output [31:0] npc, pc4, ins;
mux4x32 next_pc(pc4, bpc, rpc, jpc, pcsource, npc);
assign pc4 = pc + 32'h4;
pipeimem inst_mem(pc, ins);
endmodule
module pipeimem(a, inst);
input [31:0] a;
output [31:0] inst;
reg [31:0] rom [0:31];
initial begin
rom[0] = 32'h3c010000;
rom[1] = 32'h34240050;
rom[2] = 32'h20050004;
rom[3] = 32'h0c000018;
rom[4] = 32'hac820000;
rom[5] = 32'h8c890000;
rom[6] = 32'h01244022;
rom[7] = 32'h20050003;
rom[8] = 32'h20a5ffff;
rom[9] = 32'h34a8ffff;
rom[10] = 32'h39085555;
rom[11] = 32'h2009ffff;
rom[12] = 32'h312affff;
rom[13] = 32'h01493025;
rom[14] = 32'h01494026;
rom[15] = 32'h01463824;
rom[16] = 32'h10a00001;
rom[17] = 32'h08000008;
rom[18] = 32'h2005ffff;
rom[19] = 32'h000543c0;
rom[20] = 32'h00084400;
rom[21] = 32'h00084403;
rom[22] = 32'h000843c2;
rom[23] = 32'h08000017;
rom[24] = 32'h00004020;
rom[25] = 32'h8c890000;
rom[26] = 32'h20840004;
rom[27] = 32'h01094020;
rom[28] = 32'h20a5ffff;
rom[29] = 32'h14a0fffb;
rom[30] = 32'h00081000;
rom[31] = 32'h03e00008;
end
assign inst = rom[a[6:2]];
endmodule
module pipeir(pc4, ins, wpcir, clock, resetn, dpc4, inst);
input [31:0] pc4, ins;
input wpcir, clock, resetn;
output [31:0] dpc4, inst;
dffe32 pc_plus4(pc4, clock, resetn, wpcir, dpc4);
dffe32 instruction(ins, clock, resetn, wpcir, inst);
endmodule
module pipeid(mwreg, mrn, ern, ewreg, em2reg, mm2reg, dpc4, inst,
wrn, wdi, ealu, malu, mmo, wwreg, clock, resetn,
bpc, jpc, pcsource, wpcir, dwreg, dm2reg, dwmem,
daluc, daluimm, da, db, dimm, drn, dshift, djal);
input [31:0] dpc4, inst, wdi, ealu, malu, mmo;
input [4:0] ern, mrn, wrn;
input mwreg, ewreg, em2reg, mm2reg, wwreg;
input clock, resetn;
output [31:0] bpc, jpc, da, db, dimm;
output [4:0] drn;
output [3:0] daluc;
output [1:0] pcsource;
output wpcir, dwreg, dm2reg, dwmem, daluimm, dshift, djal;
wire [5:0] op = inst[31:26];
wire [4:0] rs = inst[25:21];
wire [4:0] rt = inst[20:16];
wire [4:0] rd = inst[15:11];
wire [5:0] func = inst[5:0];
wire [31:0] qa, qb, br_offset;
wire [31:0] da_mux, db_mux;
wire [1:0] fwda, fwdb;
wire regrt, sext, rsrtequ;
wire sign = sext & inst[15];
wire load_rs_hazard = ewreg & em2reg & (ern != 0) & (ern == rs);
wire load_rt_hazard = ewreg & em2reg & (ern != 0) & (ern == rt);
assign dimm = {{16{sign}}, inst[15:0]};
assign br_offset = {dimm[29:0], 2'b00};
assign jpc = {dpc4[31:28], inst[25:0], 2'b00};
assign bpc = dpc4 + br_offset;
assign rsrtequ = ~|(da ^ db);
pipeidcu cu(op, func, rs, rt, mrn, mm2reg, mwreg, ern, em2reg, ewreg,
rsrtequ, pcsource, wpcir, dwreg, dm2reg, dwmem, djal,
daluc, daluimm, dshift, regrt, sext, fwdb, fwda);
regfile rf(rs, rt, wdi, wrn, wwreg, ~clock, resetn, qa, qb);
mux2x5 des_reg_no(rd, rt, regrt, drn);
mux4x32 alu_a(qa, ealu, malu, mmo, fwda, da_mux);
mux4x32 alu_b(qb, ealu, malu, mmo, fwdb, db_mux);
assign da = load_rs_hazard ? 32'h0 : da_mux;
assign db = load_rt_hazard ? 32'h0 : db_mux;
endmodule
module pipeidcu(op, func, rs, rt, mrn, mm2reg, mwreg, ern, em2reg,
ewreg, rsrtequ, pcsource, wpcir, wreg, m2reg, wmem,
jal, aluc, aluimm, shift, regrt, sext, fwdb, fwda);
input [5:0] op, func;
input [4:0] rs, rt, mrn, ern;
input mm2reg, mwreg, em2reg, ewreg, rsrtequ;
output [1:0] pcsource;
output wpcir, wreg, m2reg, wmem, jal, aluimm, shift, regrt, sext;
output [3:0] aluc;
output reg [1:0] fwda, fwdb;
wire r_type = ~|op;
wire i_add = r_type & (func == 6'b100000);
wire i_sub = r_type & (func == 6'b100010);
wire i_and = r_type & (func == 6'b100100);
wire i_or = r_type & (func == 6'b100101);
wire i_xor = r_type & (func == 6'b100110);
wire i_sll = r_type & (func == 6'b000000);
wire i_srl = r_type & (func == 6'b000010);
wire i_sra = r_type & (func == 6'b000011);
wire i_jr = r_type & (func == 6'b001000);
wire i_addi = (op == 6'b001000);
wire i_andi = (op == 6'b001100);
wire i_ori = (op == 6'b001101);
wire i_xori = (op == 6'b001110);
wire i_lw = (op == 6'b100011);
wire i_sw = (op == 6'b101011);
wire i_beq = (op == 6'b000100);
wire i_bne = (op == 6'b000101);
wire i_lui = (op == 6'b001111);
wire i_j = (op == 6'b000010);
wire i_jal = (op == 6'b000011);
wire i_rs = i_add | i_sub | i_and | i_or | i_xor | i_jr | i_addi |
i_andi | i_ori | i_xori | i_lw | i_sw | i_beq | i_bne;
wire i_rt = i_add | i_sub | i_and | i_or | i_xor | i_sll | i_srl |
i_sra | i_sw | i_beq | i_bne;
assign wpcir = ~(ewreg & em2reg & (ern != 0) &
((i_rs & (ern == rs)) | (i_rt & (ern == rt))));
assign wreg = (i_add | i_sub | i_and | i_or | i_xor | i_sll | i_srl |
i_sra | i_addi | i_andi | i_ori | i_xori | i_lw |
i_lui | i_jal) & wpcir;
assign regrt = i_addi | i_andi | i_ori | i_xori | i_lw | i_lui;
assign jal = i_jal;
assign m2reg = i_lw;
assign shift = i_sll | i_srl | i_sra;
assign aluimm = i_addi | i_andi | i_ori | i_xori | i_lw | i_lui | i_sw;
assign sext = i_addi | i_lw | i_sw | i_beq | i_bne;
assign aluc[3] = i_sra;
assign aluc[2] = i_sub | i_or | i_srl | i_sra | i_ori | i_lui;
assign aluc[1] = i_xor | i_sll | i_srl | i_sra | i_xori | i_beq |
i_bne | i_lui;
assign aluc[0] = i_and | i_or | i_sll | i_srl | i_sra | i_andi | i_ori;
assign wmem = i_sw & wpcir;
assign pcsource[1] = i_jr | i_j | i_jal;
assign pcsource[0] = (i_beq & rsrtequ) | (i_bne & ~rsrtequ) | i_j | i_jal;
always @* begin
fwda = 2'b00;
if (ewreg & (ern != 0) & (ern == rs)) begin
if (~em2reg)
fwda = 2'b01;
end else if (mwreg & (mrn != 0) & (mrn == rs) & ~mm2reg)
fwda = 2'b10;
else if (mwreg & (mrn != 0) & (mrn == rs) & mm2reg)
fwda = 2'b11;
fwdb = 2'b00;
if (ewreg & (ern != 0) & (ern == rt)) begin
if (~em2reg)
fwdb = 2'b01;
end else if (mwreg & (mrn != 0) & (mrn == rt) & ~mm2reg)
fwdb = 2'b10;
else if (mwreg & (mrn != 0) & (mrn == rt) & mm2reg)
fwdb = 2'b11;
end
endmodule
module pipedereg(dwreg, dm2reg, dwmem, daluc, daluimm, da, db, dimm,
drn, dshift, djal, dpc4, clock, resetn, ewreg, em2reg,
ewmem, ealuc, ealuimm, ea, eb, eimm, ern0, eshift,
ejal, epc4);
input dwreg, dm2reg, dwmem, daluimm, dshift, djal, clock, resetn;
input [31:0] da, db, dimm, dpc4;
input [3:0] daluc;
input [4:0] drn;
output reg ewreg, em2reg, ewmem, ealuimm, eshift, ejal;
output reg [31:0] ea, eb, eimm, epc4;
output reg [3:0] ealuc;
output reg [4:0] ern0;
always @(negedge resetn or posedge clock)
if (!resetn) begin
ewreg <= 0; em2reg <= 0; ewmem <= 0; ealuimm <= 0;
eshift <= 0; ejal <= 0; ea <= 0; eb <= 0; eimm <= 0;
epc4 <= 0; ealuc <= 0; ern0 <= 0;
end else begin
ewreg <= dwreg; em2reg <= dm2reg; ewmem <= dwmem;
ealuimm <= daluimm; eshift <= dshift; ejal <= djal;
ea <= da; eb <= db; eimm <= dimm; epc4 <= dpc4;
ealuc <= daluc; ern0 <= drn;
end
endmodule
module pipeexe(ealuc, ealuimm, ea, eb, eimm, eshift, ern0, epc4,
ejal, ern, ealu);
input [3:0] ealuc;
input ealuimm, eshift, ejal;
input [31:0] ea, eb, eimm, epc4;
input [4:0] ern0;
output [4:0] ern;
output [31:0] ealu;
wire [31:0] sa, alua, alub, ealu0, epc8;
wire z;
assign sa = {27'b0, eimm[10:6]};
assign epc8 = epc4 + 32'h4;
assign ern = ern0 | {5{ejal}};
mux2x32 alu_ina(ea, sa, eshift, alua);
mux2x32 alu_inb(eb, eimm, ealuimm, alub);
alu al_unit(alua, alub, ealuc, ealu0, z);
mux2x32 save_pc8(ealu0, epc8, ejal, ealu);
endmodule
module pipeemreg(ewreg, em2reg, ewmem, ealu, eb, ern, clk, clrn,
mwreg, mm2reg, mwmem, malu, mb, mrn);
input ewreg, em2reg, ewmem, clk, clrn;
input [31:0] ealu, eb;
input [4:0] ern;
output reg mwreg, mm2reg, mwmem;
output reg [31:0] malu, mb;
output reg [4:0] mrn;
always @(negedge clrn or posedge clk)
if (!clrn) begin
mwreg <= 0; mm2reg <= 0; mwmem <= 0; malu <= 0; mb <= 0; mrn <= 0;
end else begin
mwreg <= ewreg; mm2reg <= em2reg; mwmem <= ewmem;
malu <= ealu; mb <= eb; mrn <= ern;
end
endmodule
module pipemem(we, addr, datain, clk, dmem_clk, dataout);
input we, clk, dmem_clk;
input [31:0] addr, datain;
output [31:0] dataout;
reg [31:0] ram [0:31];
integer i;
initial begin
for (i = 0; i < 32; i = i + 1)
ram[i] = 32'h0;
ram[20] = 32'h000000a3;
ram[21] = 32'h00000027;
ram[22] = 32'h00000079;
ram[23] = 32'h00000115;
end
assign dataout = ram[addr[6:2]];
always @(posedge dmem_clk)
if (we & ~clk)
ram[addr[6:2]] <= datain;
endmodule
module pipemwreg(mwreg, mm2reg, mmo, malu, mrn, clk, clrn,
wwreg, wm2reg, wmo, walu, wrn);
input mwreg, mm2reg, clk, clrn;
input [31:0] mmo, malu;
input [4:0] mrn;
output reg wwreg, wm2reg;
output reg [31:0] wmo, walu;
output reg [4:0] wrn;
always @(negedge clrn or posedge clk)
if (!clrn) begin
wwreg <= 0; wm2reg <= 0; wmo <= 0; walu <= 0; wrn <= 0;
end else begin
wwreg <= mwreg; wm2reg <= mm2reg; wmo <= mmo;
walu <= malu; wrn <= mrn;
end
endmodule
module regfile(rna, rnb, d, wn, we, clk, clrn, qa, qb);
input [4:0] rna, rnb, wn;
input [31:0] d;
input we, clk, clrn;
output [31:0] qa, qb;
reg [31:0] register [1:31];
integer i;
assign qa = (rna == 0) ? 32'h0 : register[rna];
assign qb = (rnb == 0) ? 32'h0 : register[rnb];
always @(posedge clk or negedge clrn)
if (!clrn) begin
for (i = 1; i < 32; i = i + 1)
register[i] <= 32'h0;
end else if (we && (wn != 0)) begin
register[wn] <= d;
end
endmodule
module alu(a, b, aluc, s, z);
input [31:0] a, b;
input [3:0] aluc;
output reg [31:0] s;
output z;
always @*
casex (aluc)
4'bx000: s = a + b;
4'bx100: s = a – b;
4'bx001: s = a & b;
4'bx101: s = a | b;
4'bx010: s = a ^ b;
4'bx110: s = {b[15:0], 16'h0};
4'b0011: s = b << a[4:0];
4'b0111: s = b >> a[4:0];
4'b1111: s = $signed(b) >>> a[4:0];
default: s = 32'h0;
endcase
assign z = ~|s;
endmodule
module mux2x32(a0, a1, s, y);
input [31:0] a0, a1;
input s;
output [31:0] y;
assign y = s ? a1 : a0;
endmodule
module mux2x5(a0, a1, s, y);
input [4:0] a0, a1;
input s;
output [4:0] y;
assign y = s ? a1 : a0;
endmodule
module mux4x32(a0, a1, a2, a3, s, y);
input [31:0] a0, a1, a2, a3;
input [1:0] s;
output reg [31:0] y;
always @*
case (s)
2'b00: y = a0;
2'b01: y = a1;
2'b10: y = a2;
2'b11: y = a3;
endcase
endmodule
module dffe32(d, clk, clrn, e, q);
input [31:0] d;
input clk, clrn, e;
output reg [31:0] q;
always @(negedge clrn or posedge clk)
if (!clrn)
q <= 32'h0;
else if (e)
q <= d;
endmodule



