实验设计的是五段式流水线 CPU,分别为 IF(取指),ID(指令译码),EX(执行),MEM(访存),WB(写回)五个阶段,并且时钟周期由所有指令耗时最长的阶段决定。流水线 CPU 是在 单周期 CPU 基础上,让各个部件都处理当前对应阶段的指令,使得资源的利用率得到大大提高,并且也缩短了时钟周期。其主要改变在于,需要在各个阶段之间加入流水段寄存器,来存储该指令在当前阶段所需要使用的所有信息,包括PC值,控制信号,寄存器数据,访存数据等等。同时还有一个比较关键的在于需要解决结构冒险(寄存器可能同时需要读、写),控制冒险(跳转指令可能会改变指令顺序,但流水线读取每次是先读取静态 PC, 即 PC + 4),以及数据冒险(在本实验中是 RAW,即还未写回就以及需要进行读取)以上这些问题需要通过设计转发单元,以及阻塞冲刷信号等等来实现。
顶层模块设计:
1. PipelineCPU_top
1.1 PipelineCPU
1.1.1 ForwardUnit(数据转发单元)
1.1.2 IF(即IF阶段所进行的操作)
1.1.3 ID(即ID阶段所进行的操作以及 IF -> ID 流水段寄存器)
1.1.3.1 CtrSignal(指令对应控制信号生成模块 / 控制信号 Memop 有修改)
1.1.3.2 InstrImm(立即数生成模块)
1.1.3,3 Regfiles(寄存器堆)
1.1.4 EX(即EX阶段所进行的操作以及 ID -> EX 流水段寄存器)
1.1.4.1 ALU 算术逻辑单元
1.1.4.2 NextAddr(跳转地址计算模块)
1.1.4.3 JumpCtr(跳转信号生成模块)
1.1.5 MEM(即MEM阶段所进行的操作以及 EX -> MEM 流水段寄存器)
1.1.6 WB(即WB阶段所进行的操作以及 MEM -> WB 流水段寄存器)
2. testmem(Instruction Memory)
3. testdmem(Data Memory)
4. seg7todecimal(数码管模块)
Source Code:
`timescale 1ns / 1ps
module PipelineCPU_top(
input CLK100MHZ,
input reset,
output [6:0] seg,
output [7:0] an,
output [15:0] a_out
);
wire [31:0] iaddr,idataout;
wire iclk;
wire [31:0] daddr,ddataout,ddatain;
wire drdclk, dwrclk, dwe;
wire [2:0] dop;
wire [15:0] cpudbgdata;
wire done;
rv32ip pipeline_cpu(
.clk(CLK100MHZ),
.rst(reset),
.imemaddr(iaddr), //imem的地址
.imemdataout(idataout), //imem读取到的数据
.imemclk(iclk), //imem的时钟
.dmemaddr(daddr), //dmem的地址
.dmemdataout(ddataout), //dmem读取到的数据
.dmemdatain(ddatain), //需要写入dmem的数据
.dmemrdclk(drdclk), //dmem读口时钟
.dmemwrclk(dwrclk), //dmem写口时钟
.dmemop(dop), //3'b000:sb 3'b001:sh 3'b010://sw
.dmemwe(dwe), //dmem写有效
.dbg_data(cpudbgdata), //当前完成的指令的PC
.done(done) //读取到Instr为0xdead10cc时认为程序结束
);
// instrucation memory
testmem instructions(.address(iaddr[17:2]), .clock(iclk), .data(32'b0), .wren(1'b0), .q(idataout));
//data memory
dmem mydatamem_top(.dataout(ddataout), .rdclk(drdclk), .wrclk(dwrclk), .we(dwe), .memop(dop), .datain(ddatain),.addr(daddr));
seg7decimal seg7decimal(.x({16'h0000, a_out}), .clk(CLK100MHZ), .seg(seg), .an(an), .dp(1'b0));
endmodule
module rv32ip(
input clk,
input rst,
output [31:0] imemaddr, //imem的地址
input [31:0] imemdataout, //imem读取到的数据
output imemclk, //imem的时钟
output [31:0] dmemaddr, //dmem的地址
input [31:0] dmemdataout, //dmem读取到的数据
output [31:0] dmemdatain, //需要写入dmem的数据
output dmemrdclk, //dmem读口时钟
output dmemwrclk, //dmem写口时钟
output [2:0] dmemop, //3'b000:sb 3'b001:sh 3'b010://sw
output dmemwe, //dmem写有效
output [31:0] dbg_data, //当前完成的指令的PC
output done, //读取到Instr为0xdead10cc时认为程序结束
output wb, //当前周期是否有指令完成
output [31:0] reg00, reg01, reg02, reg03, reg04, reg05, reg06, reg07,
reg08, reg09, reg10, reg11, reg12, reg13, reg14, reg15,
reg16, reg17, reg18, reg19, reg20, reg21, reg22, reg23,
reg24, reg25, reg26, reg27, reg28, reg29, reg30, reg31
);
// Instruction Fetching
wire [31:0] IF_PC, IF_snPC, IF_instr, inputPC;
wire flushIF;
wire stallIF;
// Instruction Decoding
wire [31:0] ID_PC, ID_imm;
wire [2:0] ID_Branch;
wire [1:0] ID_ALUBSrc;
wire [3:0] ID_ALUctr;
wire [2:0] ID_MemOp;
wire ID_RegWr, ID_MemtoReg, ID_ALUASrc, ID_MemWr;
wire [31:0] ID_busa, ID_busb;
wire [4:0] ID_rw;
wire [4:0] ID_rs1, ID_rs2;
wire ID_done;
wire flushID;
wire stallID;
// Executing
wire EX_done;
wire [31:0] EX_busb;
wire [31:0] EX_PC;
wire [31:0] EX_nextPC;
wire [31:0] EX_result;
wire [4:0] EX_rw;
wire [2:0] EX_MemOp, EX_Branch;
wire EX_RegWr, EX_MemtoReg;
wire EX_MemWr;
wire flush;
wire PCselect;
wire flushEX;
wire stallEX;
wire [31:0] EX_data1, EX_data2;
// Memory
wire M_done;
wire M_MemtoReg, M_RegWr;
wire [31:0] M_result;
wire [4:0] M_rw;
wire [31:0] M_Do;
wire [31:0] M_PC;
// Writing Back
wire W_RegWr;
wire [31:0] W_busw;
wire [4:0] W_rw;
assign flushID = flush;
assign flushIF = flush;
// ForwardUnit
wire Forwardrs1, Forwardrs2;
wire [31:0] ForwardData1, ForwardData2;
ForwardUnit Forward_Unit(
.EX_rs1(ID_rs1),
.EX_rs2(ID_rs2),
.WB_rd(M_rw),
.M_rd(EX_rw),
.WB_RegWr(M_RegWr),
.WB_MemtoReg(M_MemtoReg),
.M_RegWr(EX_RegWr),
.M_MemtoReg(EX_MemtoReg),
.WB_ALUResult(M_result),
.WB_Memout(M_Do),
.M_ALUResult(EX_result),
.M_Memout(dmemdataout),
.Forwardrs1(Forwardrs1), .Forwardrs2(Forwardrs2),
.ForwardData1(ForwardData1), .ForwardData2(ForwardData2),
.stallIF(stallIF),
.stallID(stallID),
.stallEX(stallEX),
.flushEX(flushEX)
);
IF IF(
.clk(clk), .rst(rst), .flush(flushIF), .block(stallIF),
.inputPC(inputPC), .done(done),
.imemaddr(imemaddr), .imemclk(imemclk), .imemdataout(imemdataout),
.currentPC(IF_PC), .snPC(IF_snPC), .currentInstr(IF_instr)
);
assign dbg_data = IF_PC;
assign inputPC = PCselect ? EX_nextPC : IF_snPC;
ID ID(
.clk(clk), .flush(flushID), .block(stallID), .rst(rst),
.in_instr(IF_instr), .in_PC(IF_PC),
.in_RegWr(W_RegWr), .in_busw(W_busw), .in_rw(W_rw),
.currentPC(ID_PC),
.imm(ID_imm),
.Branch(ID_Branch),
.ALUBSrc(ID_ALUBSrc),
.ALUctr(ID_ALUctr),
.MemOp(ID_MemOp),
.RegWr(ID_RegWr),
.MemtoReg(ID_MemtoReg),
.ALUASrc(ID_ALUASrc),
.MemWr(ID_MemWr),
.busa(ID_busa),
.busb(ID_busb),
.rw(ID_rw),
.rs1(ID_rs1),
.rs2(ID_rs2),
.done(ID_done),
.reg00(reg00), .reg01(reg01), .reg02(reg02), .reg03(reg03), .reg04(reg04), .reg05(reg05), .reg06(reg06), .reg07(reg07),
.reg08(reg08), .reg09(reg09), .reg10(reg10), .reg11(reg11), .reg12(reg12), .reg13(reg13), .reg14(reg14), .reg15(reg15),
.reg16(reg16), .reg17(reg17), .reg18(reg18), .reg19(reg19), .reg20(reg20), .reg21(reg21), .reg22(reg22), .reg23(reg23),
.reg24(reg24), .reg25(reg25), .reg26(reg26), .reg27(reg27), .reg28(reg28), .reg29(reg29), .reg30(reg30), .reg31(reg31)
);
assign EX_data1 = (Forwardrs1 == 1 ? ForwardData1 : ID_busa);
assign EX_data2 = (Forwardrs2 == 1 ? ForwardData2 : ID_busb);
EX EX(
.clk(clk), .flush(flushEX), .block(stallEX), .rst(rst),
.in_busa(EX_data1),
.in_busb(EX_data2),
.in_rw(ID_rw),
.in_PC(ID_PC),
.in_imm(ID_imm),
.in_Branch(ID_Branch),
.in_ALUBSrc(ID_ALUBSrc),
.in_ALUctr(ID_ALUctr),
.in_MemOp(ID_MemOp),
.in_RegWr(ID_RegWr),
.in_MemtoReg(ID_MemtoReg),
.in_ALUASrc(ID_ALUASrc),
.in_MemWr(ID_MemWr),
.in_done(ID_done),
.flush_o(flush),
.PCselect(PCselect),
.busb(EX_busb),
.result(EX_result),
.currentPC(EX_PC),
.Branch(EX_Branch),
.MemOp(EX_MemOp),
.RegWr(EX_RegWr),
.MemtoReg(EX_MemtoReg),
.MemWr(EX_MemWr),
.rw(EX_rw),
.done(EX_done),
.nextPC(EX_nextPC)
,.nextPC_da(nextPC_da),
.nextPC_db(nextPC_db)
);
M M(
.clk(clk), .rst(rst),
.MemWr(EX_MemWr),
.MemOp(EX_MemOp),
.Di(EX_busb),
.ALUout(EX_result),
.currentPC(EX_PC),
.MemtoReg(EX_MemtoReg),
.RegWr(EX_RegWr),
.Rd(EX_rw),
.done(EX_done),
.MemtoReg_o(M_MemtoReg),
.RegWr_o(M_RegWr),
.Rd_o(M_rw),
.ALUout_o(M_result),
.Do(M_Do),
.done_o(M_done),
.PC_o(M_PC),
.dmemaddr(dmemaddr),
.dmemdataout(dmemdataout),
.dmemdatain(dmemdatain),
.dmemrdclk(dmemrdclk),
.dmemwrclk(dmemwrclk),
.dmemop(dmemop),
.dmemwe(dmemwe)
);
WB WB(
.clk(clk), .rst(rst), .flush(flush),
.currentPC(M_PC),
.MemtoReg(M_MemtoReg),
.RegWr(M_RegWr),
.done(M_done),
.Rd(M_rw),
.Do(M_Do),
.ALUout(M_result),
.Di(W_busw),
.WE(W_RegWr),
.Rw(W_rw),
.wb(wb),
.done_o(done)
);
endmodule
`timescale 1ns / 1ps
module ForwardUnit(
// input clk, rst,
input [4: 0]EX_rs1,
input [4: 0]EX_rs2,
input [4: 0]WB_rd,
input [4: 0]M_rd,
input WB_RegWr,
input WB_MemtoReg,
input M_RegWr,
input M_MemtoReg,
input [31:0]WB_Memout,
input [31:0]WB_ALUResult,
input [31:0]M_ALUResult,
input [31:0]M_Memout,
output reg Forwardrs1, Forwardrs2,
output reg [31:0]ForwardData1, ForwardData2,
output reg stallIF,
output reg stallID,
output reg stallEX,
output reg flushEX
);
always @ (*) begin
if (M_MemtoReg && M_rd != 5'b00000 && (EX_rs1 == M_rd || EX_rs2 == M_rd)) begin stallIF = 1; stallID = 1; stallEX = 1; flushEX = 1; end
else begin stallIF = 0; stallID = 0; stallEX = 0; flushEX = 0; end
ForwardData1 = 32'h00000000;
ForwardData2 = 32'h00000000;
Forwardrs1 = 0;
Forwardrs2 = 0;
if(WB_RegWr && WB_rd != 5'b00000 && (EX_rs1 == WB_rd || EX_rs2 == WB_rd)) begin
if(EX_rs1 == WB_rd) begin ForwardData1 =(WB_MemtoReg == 1 ? WB_Memout : WB_ALUResult); Forwardrs1 = 1; end
if(EX_rs2 == WB_rd) begin ForwardData2 =(WB_MemtoReg == 1 ? WB_Memout : WB_ALUResult); Forwardrs2 = 1; end
end
if(M_RegWr && M_rd != 5'b00000 && (EX_rs1 == M_rd || EX_rs2 == M_rd)) begin
if(EX_rs1 == M_rd) begin ForwardData1 = (M_MemtoReg == 1 ? M_Memout : M_ALUResult); Forwardrs1 = 1; end
if(EX_rs2 == M_rd) begin ForwardData2 = (M_MemtoReg == 1 ? M_Memout : M_ALUResult); Forwardrs2 = 1; end
end
end
endmodule
module IF(
input clk, rst, flush, block,
input [31:0] inputPC,
input done,
output [31:0] imemaddr,
output imemclk,
input [31:0] imemdataout,
output [31:0] currentPC,
output [31:0] snPC,
output [31:0] currentInstr
);
reg [31:0] PC;
always @(negedge clk or posedge rst) begin
if (rst)
PC <= 0;
else if (done)
PC <= PC;
else if (block)
PC <= PC;
else if(!block && !done)
PC <= inputPC;
end
assign snPC = PC + 32'h00000004;
assign imemaddr = PC;
assign imemclk = clk;
assign currentPC = PC;
assign currentInstr = imemdataout;
endmodule
module ID(
input clk, flush, block, rst,
input [31:0] in_instr,
input [31:0] in_PC,
input in_RegWr,
input [31:0] in_busw,
input [4:0] in_rw,
input [31:0] a,
output [4:0] rs1,
output [4:0] rs2,
output [31:0] currentPC,
output [31:0] imm,
output [2:0] Branch,
output [1:0] ALUBSrc,
output [3:0] ALUctr,
output [2:0] MemOp,
output RegWr, MemtoReg, ALUASrc, MemWr,
output [31:0] busa, busb,
output [4:0] rw,
//output blk,
output done,
output [31:0] reg00,
output [31:0] reg01,
output [31:0] reg02,
output [31:0] reg03,
output [31:0] reg04,
output [31:0] reg05,
output [31:0] reg06,
output [31:0] reg07,
output [31:0] reg08,
output [31:0] reg09,
output [31:0] reg10,
output [31:0] reg11,
output [31:0] reg12,
output [31:0] reg13,
output [31:0] reg14,
output [31:0] reg15,
output [31:0] reg16,
output [31:0] reg17,
output [31:0] reg18,
output [31:0] reg19,
output [31:0] reg20,
output [31:0] reg21,
output [31:0] reg22,
output [31:0] reg23,
output [31:0] reg24,
output [31:0] reg25,
output [31:0] reg26,
output [31:0] reg27,
output [31:0] reg28,
output [31:0] reg29,
output [31:0] reg30,
output [31:0] reg31
);
reg [31:0] reg_instr, reg_PC;
always @(negedge clk or posedge rst) begin
if (rst) begin
reg_instr <= 32'h00000000;
reg_PC <= 32'h00000000;
end
else if (block) begin
reg_instr <= reg_instr;
reg_PC <= reg_PC;
end
else if (flush) begin
reg_instr <= 32'h00000000;
reg_PC <= 32'h00000000;
end
else if(!block) begin
reg_instr <= in_instr;
reg_PC <= in_PC;
end
end
wire [2:0] ExtOp;
wire reada, readb, protect;
wire ban;
assign ban = flush | done | (reg_instr == 32'h00000013); // 判断 nop 指令
CtrSignal CtrSignal(
.op(reg_instr[6:2]),
.func3(reg_instr[14:12]),
.func7(reg_instr[30]),
.ban(ban),
.ExtOp(ExtOp),
.Branch(Branch),
.ALUBSrc(ALUBSrc),
.ALUctr(ALUctr),
.RegWr(RegWr),
.MemtoReg(MemtoReg),
.MemOp(MemOp),
.ALUASrc(ALUASrc),
.MemWr(MemWr)
);
InstrToImm InstrToImm(
.instr(reg_instr),
.ExtOp(ExtOp),
.imm(imm),
.reada(reada),
.readb(readb),
.protect(protect)
);
Regfiles Regfiles(
.clk(clk), .flush(flush), .rst(rst),
.reada(reada), .readb(readb),
.ra(reg_instr[19:15]),
.rb(reg_instr[24:20]),
.we(in_RegWr),
.busw(in_busw),
.rw(in_rw),
.protect(protect),
.protectw(reg_instr[11:7]),
.done(done),
.busa(busa), .busb(busb),
.x0(reg00),
.x1(reg01),
.x2(reg02),
.x3(reg03),
.x4(reg04),
.x5(reg05),
.x6(reg06),
.x7(reg07),
.x8(reg08),
.x9(reg09),
.x10(reg10),
.x11(reg11),
.x12(reg12),
.x13(reg13),
.x14(reg14),
.x15(reg15),
.x16(reg16),
.x17(reg17),
.x18(reg18),
.x19(reg19),
.x20(reg20),
.x21(reg21),
.x22(reg22),
.x23(reg23),
.x24(reg24),
.x25(reg25),
.x26(reg26),
.x27(reg27),
.x28(reg28),
.x29(reg29),
.x30(reg30),
.x31(reg31)
);
assign rs1 = reg_instr[19:15];
assign rs2 = reg_instr[24:20];
assign currentPC = reg_PC;
assign rw = reg_instr[11:7];
assign done = (rst == 1'b1 ? 0 : (reg_instr == 32'hdead10cc) ? 1 : 0);
endmodule
`timescale 1ns / 1ps
module CtrSignal(
input [4:0] op,
input [2:0] func3,
input func7,
input ban,
output reg [2:0] ExtOp,
output reg [2:0] Branch,
output reg [1:0] ALUBSrc,
output reg [3:0] ALUctr,
output reg [2:0] MemOp,
output reg RegWr, MemtoReg, ALUASrc, MemWr
);
always @(*) begin
if (ban) begin
ExtOp = 3'b000;
Branch = 3'b000;
ALUBSrc = 2'b00;
ALUctr = 4'b0000;
MemOp = 3'b000;
RegWr = 0;
MemtoReg = 0;
ALUASrc = 0;
MemWr = 0;
end
else begin
case (op)
5'b01101: begin
ExtOp = 3'b001; RegWr = 1; MemtoReg = 0; MemWr = 0; ALUASrc = 0; ALUBSrc = 2'b01;
Branch = 3'b000; MemOp = 3'b000; ALUctr = 4'b1111;
end
5'b00101: begin
ExtOp = 3'b001; RegWr = 1; MemtoReg = 0; MemWr = 0; ALUASrc = 1; ALUBSrc = 2'b01;
Branch = 3'b000; MemOp = 3'b000; ALUctr = 4'b0000;
end
5'b00100: begin
ExtOp = 3'b000; RegWr = 1; MemtoReg = 0; MemWr = 0; ALUASrc = 0; ALUBSrc = 2'b01;
Branch = 3'b000; MemOp = 3'b000;
if (func3 != 3'b101) ALUctr = {1'b0, func3}; else ALUctr = {func7, func3};
end
5'b01100: begin
ExtOp = 3'b101; RegWr = 1; MemtoReg = 0; MemWr = 0; ALUASrc = 0; ALUBSrc = 2'b00;
Branch = 3'b000; MemOp = 3'b000; ALUctr = {func7, func3};
end
5'b11011: begin
ExtOp = 3'b100; RegWr = 1; MemtoReg = 0; MemWr = 0; ALUASrc = 1; ALUBSrc = 2'b10;
Branch = 3'b001; MemOp = 3'b000; ALUctr = 4'b0000;
end
5'b11001: begin
ExtOp = 3'b000; RegWr = 1; MemtoReg = 0; MemWr = 0; ALUASrc = 1; ALUBSrc = 2'b10;
Branch = 3'b010; MemOp = 3'b000; ALUctr = 4'b0000;
end
5'b11000: begin
ExtOp = 3'b011; RegWr = 1'b0; ALUASrc = 1'b0; ALUBSrc = 2'b00; MemOp = 3'b000;
if(func3 == 3'b000)begin ALUctr = 4'b0010; Branch = 3'b100;MemtoReg = 1'b0;MemWr=1'b0; end
else if(func3 == 3'b001)begin ALUctr = 4'b0010; Branch = 3'b101;MemtoReg = 1'b0;MemWr=1'b0;end
else if(func3 == 3'b100)begin ALUctr = 4'b0010;Branch = 3'b110;MemtoReg = 1'b0;MemWr=1'b0;end
else if(func3 == 3'b101)begin ALUctr = 4'b0010;Branch = 3'b111;MemtoReg = 1'b0;MemWr=1'b0;end
else if(func3 == 3'b110)begin ALUctr = 4'b0011;Branch = 3'b110;MemtoReg = 1'b0;MemWr=1'b0;end
else if(func3 == 3'b111)begin ALUctr = 4'b0011;Branch = 3'b111;MemtoReg = 1'b0;MemWr=1'b0;end
end
5'b00000: begin
ExtOp = 3'b000; RegWr = 1; MemtoReg = 1; MemWr = 0; ALUASrc = 0; ALUBSrc = 2'b01;
Branch = 3'b000;
MemOp = func3;
ALUctr = 4'b0000;
end
5'b01000: begin
ExtOp = 3'b010; RegWr = 0; MemtoReg = 0; MemWr = 1; ALUASrc = 0; ALUBSrc = 2'b01;
Branch = 3'b000;
MemOp = func3;
ALUctr = 4'b0000;
end
endcase
end
end
endmodule
`timescale 1ns / 1ps
module InstrToImm(
input [31:0] instr,
input [2:0] ExtOp,
output reg [31:0] imm
);
always @(*) begin
case(ExtOp)
0: begin // I-type
imm = {{20{instr[31]}}, instr[31:20]};
end
1: begin // U-type
imm = {instr[31:12], 12'b0};
end
2: begin // S-type
imm = {{20{instr[31]}}, instr[31:25], instr[11:7]};
end
3: begin // B-type
imm = {{20{instr[31]}}, instr[7], instr[30:25], instr[11:8],1'b0};
end
4: begin // J-type
imm = {{12{instr[31]}}, instr[19:12], instr[20], instr[30:21],1'b0};
end
5: begin // R-type
imm = 0;
end
endcase
end
endmodule
`timescale 1ns / 1ps
module Regfiles(
input clk, flush, rst,
input reada, readb,
input [4:0] ra,
input [4:0] rb,
input we,
input [4:0] rw,
input [31:0] busw,
input protect,
input [4:0] protectw,
input done,
output reg [31:0] busa,
output reg [31:0] busb,
output reg conflict,
output [31:0] x0 , x1 , x2 , x3 , x4 , x5 , x6 , x7,
output [31:0] x8 , x9 , x10, x11, x12, x13, x14, x15,
output [31:0] x16, x17, x18, x19, x20, x21, x22, x23,
output [31:0] x24, x25, x26, x27, x28, x29, x30, x31
);
reg [31:0] registers[31:0]; integer i;
initial begin
for (i = 0; i <= 31; i = i + 1) begin
registers[i] = 0;
end
end
always @(*) begin
busa = registers[ra];
busb = registers[rb];
end
wire write;
assign write = (we == 1'b1 && rw != 5'b00000 && !done);
always @(posedge clk or posedge rst) begin
if (rst) begin
for (i = 0; i <= 31; i = i + 1) begin
registers[i] <= 0;
end
end
else if (write && !done) begin
registers[rw] <= busw;
end
end
assign x0 = registers[0]; assign x1 = registers[1]; assign x2 = registers[2]; assign x3 = registers[3];
assign x4 = registers[4]; assign x5 = registers[5]; assign x6 = registers[6]; assign x7 = registers[7];
assign x8 = registers[8]; assign x9 = registers[9]; assign x10 = registers[10]; assign x11 = registers[11];
assign x12 = registers[12]; assign x13 = registers[13]; assign x14 = registers[14]; assign x15 = registers[15];
assign x16 = registers[16]; assign x17 = registers[17]; assign x18 = registers[18]; assign x19 = registers[19];
assign x20 = registers[20]; assign x21 = registers[21]; assign x22 = registers[22]; assign x23 = registers[23];
assign x24 = registers[24]; assign x25 = registers[25]; assign x26 = registers[26]; assign x27 = registers[27];
assign x28 = registers[28]; assign x29 = registers[29]; assign x30 = registers[30]; assign x31 = registers[31];
endmodule
module EX (
input clk, flush, block, rst,
input [31:0] in_busa, in_busb,
input [4:0] in_rw,
input [31:0] in_PC,
input [31:0] in_imm,
input [2:0] in_Branch,
input [1:0] in_ALUBSrc,
input [3:0] in_ALUctr,
input [2:0] in_MemOp,
input in_RegWr, in_MemtoReg, in_ALUASrc, in_MemWr,
input in_done,
output PCselect,
output [31:0] result,
output [31:0] currentPC,
output [31:0] busb,
output [4:0] rw,
output [2:0] MemOp,
output RegWr, MemtoReg, MemWr,
output done,
output flush_o,
output [2:0] Branch,
output [31:0] nextPC,
output [31:0] nextPC_da, nextPC_db
);
reg [31:0] reg_PC, reg_imm, reg_busa, reg_busb;
reg [4:0] reg_rw;
reg [2:0] reg_Branch;
reg [1:0] reg_ALUBSrc;
reg [3:0] reg_ALUctr;
reg [2:0] reg_MemOp;
reg reg_RegWr, reg_MemtoReg, reg_ALUASrc, reg_MemWr;
reg reg_done;
wire zero;
wire [31:0] imm, busa;
always @(negedge clk) begin
if (rst) begin
reg_PC <= 32'h00000000;
reg_imm <= 32'h00000000;
reg_busa <= 32'h00000000;
reg_busb <= 32'h00000000;
reg_rw <= 5'b00000;
reg_Branch <= 3'b000;
reg_ALUBSrc <= 2'b00;
reg_ALUctr <= 4'b0000;
reg_MemOp <= 3'b000;
reg_RegWr <= 1'b0;
reg_MemtoReg <= 1'b0;
reg_ALUASrc <= 1'b0;
reg_MemWr <= 1'b0;
reg_done <= 1'b0;
end
else if (!block) begin
reg_PC <= in_PC;
reg_imm <= in_imm;
reg_busa <= in_busa;
reg_busb <= in_busb;
reg_rw <= in_rw;
reg_Branch <= in_Branch;
reg_ALUBSrc <= in_ALUBSrc;
reg_ALUctr <= in_ALUctr;
reg_MemOp <= in_MemOp;
reg_RegWr <= in_RegWr;
reg_MemtoReg <= in_MemtoReg;
reg_ALUASrc <= in_ALUASrc;
reg_MemWr <= in_MemWr;
reg_done <= in_done;
end
else if(flush) begin
reg_PC <= 32'h00000000;
reg_imm <= 32'h00000000;
reg_busa <= 32'h00000000;
reg_busb <= 32'h00000000;
reg_rw <= 5'b00000;
reg_Branch <= 3'b000;
reg_ALUBSrc <= 2'b00;
reg_ALUctr <= 4'b0000;
reg_MemOp <= 3'b000;
reg_RegWr <= 1'b0;
reg_MemtoReg <= 1'b0;
reg_ALUASrc <= 1'b0;
reg_MemWr <= 1'b0;
reg_done <= 1'b0;
end
end
wire [31:0] ALUa, ALUb;
assign ALUa = (reg_ALUASrc == 1 ? reg_PC : reg_busa);
assign ALUb = (reg_ALUBSrc == 2'b00) ? reg_busb : ((reg_ALUBSrc == 2'b01) ? reg_imm : 32'h00000004);
assign flush_o = PCselect;
ALU32 ALU(
.dataa(ALUa),
.datab(ALUb),
.aluctr(reg_ALUctr),
.result(result),
.zero(zero)
);
NextAddr NextAddr (
.zero(zero),
.rst(flush),
.result0(result[0]),
.Branch(Branch),
.imm(imm),
.currentPC(currentPC),
.busa(busa),
.nextPC(nextPC)
,.da(nextPC_da),
.db(nextPC_db)
);
assign PCselect = (Branch != 3'b0 && nextPC != currentPC + 32'h00000004);
assign currentPC = reg_PC;
assign Branch = reg_Branch;
assign MemOp = reg_MemOp;
assign RegWr = reg_RegWr;
assign MemtoReg = reg_MemtoReg;
assign MemWr = reg_MemWr;
assign imm = reg_imm;
assign busa = reg_busa;
assign busb = reg_busb;
assign rw = reg_rw;
assign done = reg_done;
endmodule
`timescale 1ns / 1ps
module ALU32(
output reg [31:0] result, //32位运算结果
output reg zero, //结果为0标志位
input [31:0] dataa, //32位数据输入,送到ALU端口A
input [31:0] datab, //32位数据输入,送到ALU端口B
input [3:0] aluctr //4位ALU操作控制信号
);
//add your code here
reg SUBctr,SIGctr,ALctr,SFTctr; reg[2:0]OPctr;
wire [31:0]f;wire[31:0] dout;
wire OF,SF,ZF,CF,cout;
Adder32 my_adder(.f(f),.OF(OF),.SF(SF),.ZF(ZF),.CF(CF),.cout(cout),.x(dataa),.y(datab),.sub(SUBctr));
barrelsft32 my_barrel(.dout(dout),.din(dataa),.shamt(datab[4:0]),.LR(SFTctr),.AL(ALctr));
always@(*)begin
case(aluctr)
4'b0000: begin SUBctr = 0; OPctr = 3'b000; end
4'b0001: begin ALctr = 0; SFTctr = 1; OPctr = 3'b100; end
4'b0010: begin SUBctr = 1;SIGctr=1;OPctr = 3'b110; end
4'b0011: begin SUBctr = 1;SIGctr=0;OPctr=3'b110;end
4'b0100: begin OPctr = 3'b011; end
4'b0101: begin ALctr = 0; SFTctr = 0; OPctr = 3'b100; end
4'b0110: begin OPctr = 3'b010; end
4'b0111: begin OPctr = 3'b001; end
4'b1000: begin SUBctr = 1; OPctr = 3'b000; end
4'b1101: begin ALctr = 1; SFTctr = 0;OPctr = 3'b100; end
4'b1111: begin OPctr = 3'b101; end
default;
endcase
case(OPctr)
3'b000: begin result = f;end
3'b001: begin result = dataa & datab; end
3'b010: begin result = dataa | datab; end
3'b011: begin result = dataa ^ datab; end
3'b100: begin result = dout; end
3'b101: begin result = datab; end
3'b110: begin
result = {31'b0,(SIGctr == 1)? (OF ^ SF) : CF};
end
default;
endcase
zero = ZF;
end
endmodule
`timescale 1ns / 1ps
module Adder32(
output [31:0] f,
output OF, SF, ZF, CF,
output cout,
input [31:0] x, y,
input sub
);
wire [31:0] new_y;
assign new_y = (sub) ? ~y : y;
wire c16;
CLA_16 add1(.f(f[15:0]),.cout(c16),.x(x[15:0]),.y(new_y[15:0]),.cin(sub));
CLA_16 add2(.f(f[31:16]),.cout(cout),.x(x[31:16]),.y(new_y[31:16]),.cin(c16));
assign ZF = (f == 0);
assign SF = f[31];
assign CF = cout ^ sub;
assign OF = (~x[31] & ~new_y[31] & f[31]) | (x[31] & new_y[31] & ~f[31]);
endmodule
module CLA_16(
output wire [15:0] f,
output wire cout,
input [15:0] x, y,
input cin
);
wire [3:0] Pi,Gi; // 4位组间进位传递因子和生成因子
wire [4:0] c; // 4位组间进位和整体进位
assign c[0] = cin;
CLA_group cla0(f[3:0],Pi[0],Gi[0],x[3:0],y[3:0],c[0]);
CLA_group cla1(f[7:4],Pi[1],Gi[1],x[7:4],y[7:4],c[1]);
CLA_group cla2(f[11:8],Pi[2],Gi[2],x[11:8],y[11:8],c[2]);
CLA_group cla3(f[15:12],Pi[3],Gi[3],x[15:12],y[15:12],c[3]);
CLU clu(c[4:1],Pi,Gi, c[0]);
assign cout = c[4];
endmodule
module CLA_group (
output [3:0] f,
output pg,gg,
input [3:0] x, y,
input cin
);
wire [4:0] c;
wire [4:1] p, g;
assign c[0] = cin;
FA_PG fa0(f[0], p[1], g[1],x[0], y[0], c[0]);
FA_PG fa1(f[1], p[2], g[2],x[1], y[1], c[1]);
FA_PG fa2(f[2], p[3], g[3],x[2], y[2], c[2]);
FA_PG fa3(f[3], p[4], g[4],x[3], y[3], c[3]);
CLU clu(c[4:1],p, g, c[0]);
// assign cout = c[4];
assign pg=p[1] & p[2] & p[3] & p[4];
assign gg= g[4] | (p[4] & g[3]) | (p[4] & p[3] & g[2]) | (p[4] & p[3] & p[2] & g[1]);
endmodule
module CLU (
output [4:1] c,
input [4:1] p, g,
input c0
);
assign c[1] = g[1] | (p[1] & c0);
assign c[2] = g[2] | (p[2] & g[1]) | (p[2] & p[1] & c0);
// 以下两个表达式使用了位拼接运算和归约运算
assign c[3] = g[3] | (p[3] & g[2]) | (&{p[3:2], g[1]}) | (&{p[3:1], c0});
assign c[4] = g[4] | (p[4] & g[3]) | (&{p[4:3], g[2]}) | (&{p[4:2], g[1]}) | (&{p[4:1], c0});
endmodule
module FA_PG (
output f, p, g,
input x, y, cin
);
assign f = x ^ y ^ cin;
assign p = x | y;
assign g = x & y;
endmodule
`timescale 1ns / 1ps
module WB(
input clk, rst, flush,
input MemtoReg,
input RegWr,
input done,
input [4:0] Rd,
input [31:0] Do,
input [31:0] ALUout,
input [31:0] currentPC,
output reg [31:0] Di,
output reg WE,
output reg [4:0] Rw,
output reg wb,
output reg done_o,
output reg [31:0] PC_o
);
always @(negedge clk or posedge rst) begin
if (rst) begin
Di <= 0;
WE <= 0;
Rw <= 0;
wb <= 0;
done_o <= 0;
PC_o <= 0;
end
else begin
Di <= (MemtoReg) ? Do : ALUout;
WE <= RegWr & (~done);
Rw <= Rd;
wb <= 1'b1;
done_o <= done;
PC_o <= currentPC;
end
end
endmodule
module testmem(
address,
clock,
data,
wren,
q);
input [15:0] address;
input clock;
input [31:0] data;
input wren;
output reg [31:0] q;
reg [31:0] ram [65535:0];
initial begin
$readmemh("add.txt",ram); // 需要在这里输入指令
end
always@(posedge clock)
q <= ram[address];
endmodule
module dmem(addr, dataout, datain, rdclk, wrclk, memop, we);
input [31:0] addr;
output reg [31:0] dataout;
input [31:0] datain;
input rdclk;
input wrclk;
input [2:0] memop;
input we;
wire [31:0] memin;
reg [3:0] wmask;
wire [7:0] byteout;
wire [15:0] wordout;
wire [31:0] dwordout;
assign memin = (memop[1:0]==2'b00)?{4{datain[7:0]}}:((memop[1:0]==2'b10)?datain:{2{datain[15:0]}}) ; //lb: same for all four, lh:copy twice; lw:copy
//four memory chips
testdmem mymem(.wea(wmask),.dina(memin), .addrb(addr[16:2]), .clkb(rdclk), .addra(addr[16:2]), .clka(wrclk), .ena(we), .doutb(dwordout),.enb(1'b1) );
//datamem mymem(.wea(wmask),.dina(memin), .addrb(addr[16:2]), .clkb(rdclk), .addra(addr[16:2]), .clka(wrclk), .ena(we), .doutb(dwordout),.enb(1'b1) );
//wmask,addr[16:2]
assign wordout = (addr[1]==1'b1)? dwordout[31:16]:dwordout[15:0];
assign byteout = (addr[1]==1'b1)? ((addr[0]==1'b1)? dwordout[31:24]:dwordout[23:16]):((addr[0]==1'b1)? dwordout[15:8]:dwordout[7:0]);
always @(*)
begin
case(memop)
3'b000: //lb
dataout = { {24{byteout[7]}}, byteout};
3'b001: //lh
dataout = { {16{wordout[15]}}, wordout};
3'b010: //lw
dataout = dwordout;
3'b100: //lbu
dataout = { 24'b0, byteout};
3'b101: //lhu
dataout = { 16'b0, wordout};
default:
dataout = dwordout;
endcase
end
always@(*)
begin
if(we==1'b1)
begin
case(memop)
3'b000://sb
begin
wmask[0]=(addr[1:0]==2'b00)?1'b1:1'b0;
wmask[1]=(addr[1:0]==2'b01)?1'b1:1'b0;
wmask[2]=(addr[1:0]==2'b10)?1'b1:1'b0;
wmask[3]=(addr[1:0]==2'b11)?1'b1:1'b0;
end
3'b001://sh
begin
wmask[0]=(addr[1]==1'b0)?1'b1:1'b0;
wmask[1]=(addr[1]==1'b0)?1'b1:1'b0;
wmask[2]=(addr[1]==1'b1)?1'b1:1'b0;
wmask[3]=(addr[1]==1'b1)?1'b1:1'b0;
end
3'b010://sw
begin
wmask=4'b1111;
end
default:
begin
wmask=4'b0000;
end
endcase
end
else
begin
wmask=4'b0000;
end
end
endmodule
`timescale 1ns / 1ps
module seg7decimal(
input [31:0] x,
input clk,
output reg [6:0] seg,
output reg [7:0] an,
output wire dp
);
wire [2:0] s;
reg [3:0] digit;
wire [7:0] aen;
reg [19:0] clkdiv;
assign dp = 1;
assign s = clkdiv[19:17];
assign aen = 8'b11111111; // all turned off initially
// quad 4to1 MUX.
always @(posedge clk)// or posedge clr)
case(s)
0:digit = x[3:0]; // s is 00 -->0 ; digit gets assigned 4 bit value assigned to x[3:0]
1:digit = x[7:4]; // s is 01 -->1 ; digit gets assigned 4 bit value assigned to x[7:4]
2:digit = x[11:8]; // s is 10 -->2 ; digit gets assigned 4 bit value assigned to x[11:8
3:digit = x[15:12]; // s is 11 -->3 ; digit gets assigned 4 bit value assigned to x[15:12]
4:digit = x[19:16]; // s is 00 -->0 ; digit gets assigned 4 bit value assigned to x[3:0]
5:digit = x[23:20]; // s is 01 -->1 ; digit gets assigned 4 bit value assigned to x[7:4]
6:digit = x[27:24]; // s is 10 -->2 ; digit gets assigned 4 bit value assigned to x[11:8
7:digit = x[31:28]; // s is 11 -->3 ; digit gets assigned 4 bit value assigned to x[15:12]
default:digit = x[3:0];
endcase
//decoder or truth-table for 7seg display values
always @(*)
case(digit)
//<---MSB-LSB<---
//gfedcba a
0:seg = 7'b1000000;0000 __
1:seg = 7'b1111001;0001 f/ /b
2:seg = 7'b0100100;0010 g
// __
3:seg = 7'b0110000;0011 e / /c
4:seg = 7'b0011001;0100 __
5:seg = 7'b0010010;0101 d
6:seg = 7'b0000010;0110
7:seg = 7'b1111000;0111
8:seg = 7'b0000000;1000
9:seg = 7'b0010000;1001
'hA:seg = 7'b0001000;
'hB:seg = 7'b0000011;
'hC:seg = 7'b1000110;
'hD:seg = 7'b0100001;
'hE:seg = 7'b0000110;
'hF:seg = 7'b0001110;
default: seg = 7'b0000000; // U
endcase
always @(*)begin
an=8'b11111111;
if(aen[s] == 1)
an[s] = 0;
end
//clkdiv
always @(posedge clk) begin
clkdiv <= clkdiv+1;
end
endmodule