RISC-V 流水线 CPU 设计 Verilog

发布时间:2023年12月20日

实验设计的是五段式流水线 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

文章来源:https://blog.csdn.net/weixin_69763109/article/details/134956618
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。