制作多周期CPU(代码)

MCPU

module MCPU( CLK, RST, CurPC, instcode );

    input CLK; // 时钟信号
    input RST; // 置零信号
    output [31:0] CurPC; // 当前指令的地址
    output [31:0] instcode; //  指令寄存器中获取的指令码
    wire [5:0] op; // 操作码
    wire [4:0] rs;
    wire [4:0] rt;
    wire [4:0] rd;
    wire [4:0] sa; // 移位指令的移动位数
    wire [15:0] immediate; // I类型指令的立即数(未被扩展)
    wire [25:0] address; // J类型指令跳转的地址(未被扩展)
    wire [31:0] NextPC; // 下一条指令的地址
    wire [31:0] PC4; // PC正常+4后的值,即临近下一个的地址
    wire [31:0] BeqPC; // 对于beq指令成立时要跳转的目标地址
    wire [31:0] JumpPC; // 对于jal、j指令要跳转的目标地址
    wire ExtSel; // 位扩展信号,1为符号扩展,0为0扩展
    wire PCWre; // PC工作信号,0不更改,1更改
    wire InsMemRW; // 指令寄存器信号,0为写,1为读
    wire IRWre; // IR寄存器从指令寄存器中获取指令代码
    wire WrRegDSrc; // 如果是jal指令,此时要选择31号寄存器保存当前PC
    wire [1:0] RegDst; // 指令读取时判断是rt还是rd还是31号寄存器进入寄存器组的写数据端,00为31号,01为rt,10为rd
    wire RegWre; // 寄存器组是否需要写功能,0为无写功能,1为写功能
    wire [2:0] ALUOP; // ALU8种运算功能选择
    wire [1:0] PCSrc; // 选择下一条PC的值,00为正常PC+4,01为beq执行的跳转,10为jr指令跳转到31号寄存器保存的地址,11为j和jal指令
    wire ALUSrcA; // 寄存器组Data1的输出,0为寄存器本身输出,1为指令码的最后16位立即数
    wire ALUSrcB; // 寄存器组Data2的输出,0位本身的输出,1为扩展后的立即数
    wire RD; // 读数据存储器功能,0时读取
    wire WR; // 写数据存储器功能,1时写
    wire DBDataSrc; // 决定将什么数据传入寄存器组Write Data端,0为ALU结果,1为存储器
    wire [4:0] WriteRegAddr; // 寄存器组Write Reg输入端
    wire [31:0] Reg1Out; // 寄存器组rs寄存器的值
    wire [31:0] Reg2Out; // 寄存器组rt寄存器的值,也是存储器的DataIn输入端
    wire [31:0] WriteData; // 寄存器组Write Data输入端的值
    wire [31:0] ALU_Input_A; // ALU的A输入端
    wire [31:0] ALU_Input_B; // ALU的B输入端
    wire [31:0] ALU_Out; // ALU的result输出,也是存储器的地址输入端
    wire zero; // ALU的zero输出
    wire [31:0] MemOut; // 存储器的输出
    wire [31:0] Ext_Imm; // 位扩展后的立即数
    wire [31:0] ADR_Out;
    wire [31:0] BDR_Out;
    wire [31:0] ALUOutDR_Out;
    wire [31:0] DBDR_In;
    wire [31:0] DBDR_Out;
    // PC( CLK, RST, PCWre, NextPC, CurPC )
    PC my_PC( CLK, RST, PCWre, NextPC, CurPC );

    // ALU_For_Next( CurPC, PC4 )
    ALU_For_Next my_ALU_For_Next( CurPC, PC4 );

    // ALU_For_Beq( PC4, Aim, BeqPC )
    ALU_For_Beq my_ALU_For_Beq( PC4, Ext_Imm, BeqPC );

    // Mux_FourToOne_PC( PC4, BeqPC, JrPC, JumpPC, PCSrc, NextPC)
    Mux_FourToOne_PC my_Mux_FourToOne_PC( PC4, BeqPC, Reg1Out, JumpPC, PCSrc, NextPC);

    // InstructionMemory( CurPC, InstMemRW, instcode )
    InstructionMemory my_InstructionMemory( CurPC, InsMemRW, instcode );

    // IR( CLK, instcode, IRWre, op, rs, rt, rd, sa, immediate, address )
    IR my_IR( CLK, instcode, IRWre, op, rs, rt, rd, sa, immediate, address );

    // Extend_For_Address( PC4, Address, JumpPC )
    Extend_For_Address my_Extend_For_Address( PC4, address, JumpPC );

    // Mux_ThreeToOne_WriteReg( rt, rd, RegDst, WriteReg )
    Mux_ThreeToOne_WriteReg my_Mux_ThreeToOne_WriteReg( rt, rd, RegDst, WriteRegAddr );

    // Mux_TwoToOne_Data( Select, DataA, DataB, DataOut )
    Mux_TwoToOne_Data my_MuxTwoToOne_For_WriteData( WrRegDSrc, PC4, DBDR_Out, WriteData );

    // Sign_Zero_Extend( Imm_Number, ExtSel, Result )
    Sign_Zero_Extend my_Sign_Zero_Extend( immediate, ExtSel, Ext_Imm );

    // RegisterFile( RegWre, CLK, Reg1, Reg2, WriteReg, WriteData, DataOut1, DataOut2 )
    RegisterFile my_RegisterFile( RegWre, CLK, rs, rt, WriteRegAddr, WriteData, Reg1Out, Reg2Out );

    // DR( CLK, DataIn, DataOut )
    DR my_ADR( CLK, Reg1Out, ADR_Out );

    // DR( CLK, DataIn, DataOut )
    DR my_BDR( CLK, Reg2Out, BDR_Out );

    // Mux_TwoToOne_For_InputA( ALUSrcA, DataIn, sa, DataOut )
    Mux_TwoToOne_For_InputA my_Mux_TwoToOne_For_InputA( ALUSrcA, ADR_Out, sa, ALU_Input_A );

    // Mux_TwoToOne_Data( Select, DataA, DataB, DataOut )
    Mux_TwoToOne_Data my_Mux_TwoToOne_For_InputB( ALUSrcB, BDR_Out, Ext_Imm, ALU_Input_B );

    // ALU( Reg1, Reg2, ALUOp, result, zero )
    ALU my_ALU( ALU_Input_A, ALU_Input_B, ALUOP, ALU_Out, zero );

    // DR( CLK, DataIn, DataOut )
    DR my_ALUOutDR( CLK, ALU_Out, ALUOutDR_Out );

    // DataMemory( CLK, DAddr, RD, WR, DataIn, DataOut )
    DataMemory my_DataMemory( CLK, ALUOutDR_Out, RD, WR, BDR_Out, MemOut );

    // Mux_TwoToOne_Data( Select, DataA, DataB, DataOut )
    Mux_TwoToOne_Data my_MuxTwoToOne_For_DBDR( DBDataSrc, ALU_Out, MemOut, DBDR_In );

    // DR( CLK, DataIn, DataOut )
    DR my_DBDR( CLK, DBDR_In, DBDR_Out );

    // ControlUnit( CLK, RST, zero, op, DBDataSrc, WR, RD, ALUSrcB, ALUSrcA, ALUOP, RegWre, RegDst, WrRegDSrc, IRWre, InsMemRW, PCWre, ExtSel, PCSrc )
    ControlUnit my_ControlUnit( CLK, RST, zero, op, DBDataSrc, WR, RD, ALUSrcB, ALUSrcA, ALUOP, RegWre, RegDst, WrRegDSrc, IRWre, InsMemRW, PCWre, ExtSel, PCSrc );

endmodule

PC

module PC( CLK, RST, PCWre, NextPC, CurPC );

    input CLK, RST, PCWre;
    input [31:0] NextPC;
    output reg [31:0] CurPC;    

     /*initial begin  
         Address = 0;  
     end*/ 

     always @( negedge CLK or negedge RST )  
         begin
              if (RST == 0) begin
                    CurPC = 0;  
                end  
                else if (PCWre) begin 
                    CurPC = NextPC;
                end
          end

endmodule

ALU_For_Next

module ALU_For_Next( CurPC, PC4 );

    input [31:0] CurPC;
    output reg [31:0] PC4;

    always@( CurPC ) begin
        PC4 = CurPC + 4;
    end

endmodule

ALU_For_Beq

module ALU_For_Beq( PC4, Aim, BeqPC );

    input [31:0] PC4, Aim;
    output reg [31:0] BeqPC;

    always@( PC4 or Aim ) begin
        BeqPC = PC4 + Aim * 4;
    end

endmodule

Mux_FourToOne_PC

module Mux_FourToOne_PC( PC4, BeqPC, JrPC, JumpPC, PCSrc, NextPC );

    input [31:0] PC4, BeqPC, JrPC, JumpPC;
    input [1:0] PCSrc;
    output reg [31:0] NextPC;

    always@( PC4 or BeqPC or JrPC or JumpPC or PCSrc ) begin
        case ( PCSrc )
            2'b00 : NextPC = PC4;
            2'b01 : NextPC = BeqPC;
            2'b10 : NextPC = JrPC;
            2'b11 : NextPC = JumpPC;
        endcase
    end

endmodule

InstructionMemory

module InstructionMemory( CurPC, InstMemRW, instcode );

    input [31:0] CurPC;
    input InstMemRW;
    output reg [31:0] instcode;
    reg [7:0] InstMemory [255:0];

    initial begin
        $readmemb("H:/CPU/Multiple_CPU/instruction.txt", InstMemory);
    end

    always@( CurPC or InstMemRW ) begin
        if (InstMemRW == 1) begin
            instcode = { InstMemory[CurPC], InstMemory[CurPC + 1], InstMemory[CurPC + 2], InstMemory[CurPC + 3] };
        end
        $display("InstMem PC", CurPC, " INST: ", instcode);
    end

endmodule

IR

module IR( CLK, instcode, IRWre, op, rs, rt, rd, sa, immediate, address );

    input CLK;
    input [31:0] instcode;
    input IRWre;
    output reg [5:0] op;
    output reg [4:0] rs, rt, rd, sa;
    output reg [15:0] immediate;
    output reg [25:0] address;

    always@( negedge CLK ) begin
        if (IRWre == 1) begin
            op = instcode[31:26];
            rs = instcode[25:21];
            rt = instcode[20:16];
            rd = instcode[15:11];
            sa = instcode[10:6];
            immediate = instcode[15:0];
            address = instcode[25:0];
        end
    end

endmodule

Extend_For_Address

module Extend_For_Address( PC4, Address, JumpPC );

    input [31:0] PC4;
    input [25:0] Address;
    output reg [31:0] JumpPC;

    always@( PC4 or Address ) begin
        JumpPC = { PC4[31:28], Address[25:0], 2'b00 };
    end

endmodule

Mux_ThreeToOne_WriteReg

module Mux_ThreeToOne_WriteReg( rt, rd, RegDst, WriteReg );

    input [4:0] rt, rd;
    input [1:0] RegDst;
    output reg [4:0] WriteReg;

    always@( rt or rd or RegDst ) begin
        case(RegDst)
            2'b00 : WriteReg = 5'b11111;
            2'b01 : WriteReg = rt;
            2'b10 : WriteReg = rd;
        endcase
    end

endmodule

Mux_TwoToOne_Data

module Mux_TwoToOne_Data( Select, DataA, DataB, DataOut );

    input Select;
    input [31:0] DataA, DataB;
    output reg [31:0] DataOut;

    always@( Select or DataA or DataB ) begin
        if (Select == 0)
            DataOut = DataA;
        else
            DataOut = DataB;
    end

endmodule

Sign_Zero_Extend

module Sign_Zero_Extend( Imm_Number, ExtSel, Result );

    input [15 :0] Imm_Number;
    input ExtSel;
    output reg [31:0] Result;

    always@( Imm_Number or ExtSel) begin
        if (ExtSel == 0 || Imm_Number[15] == 0)
            Result = { 16'b0000000000000000, Imm_Number };
        else
            Result = { 16'b1111111111111111, Imm_Number };
    end

endmodule

RegisterFile

module RegisterFile( RegWre, CLK, Reg1, Reg2, WriteReg, WriteData, DataOut1, DataOut2 );

    input RegWre;
    input CLK;
    input [4:0] Reg1, Reg2;
    input [4:0] WriteReg;
    input [31:0] WriteData;
    output [31:0] DataOut1, DataOut2;
    reg [31:0] registers[1:31];

    assign DataOut1 = ( Reg1 == 0 ) ? 0 : registers[Reg1];
    assign DataOut2 = ( Reg2 == 0 ) ? 0 : registers[Reg2];

    always@( posedge CLK ) begin // 写操作
        $display("RegWre: ", RegWre);
        if (( WriteReg != 0 ) && ( RegWre )) begin
            $display("WriteData: ", WriteData, " WriteReg: ", WriteReg);
            registers[WriteReg] <= WriteData;
        end
    end

endmodule

DR

module DR( CLK, DataIn, DataOut );

    input CLK;
    input [31:0] DataIn;
    output reg [31:0] DataOut;

    always@( negedge CLK ) begin
        DataOut <= DataIn;
    end

endmodule

Mux_TwoToOne_For_InputA

module Mux_TwoToOne_For_InputA( ALUSrcA, DataIn, sa, DataOut );

   input ALUSrcA;
   input [31:0] DataIn;
   input [4:0] sa;
   output reg [31:0] DataOut;

   always@( ALUSrcA or DataIn or sa ) begin
       if ( ALUSrcA == 0 )
           DataOut = DataIn;
       else
           DataOut = { 27'b000000000000000000000000000, sa }; // 对sa进行扩展
   end

endmodule

ALU

module ALU( Reg1, Reg2, ALUOp, result, zero );

    input [31:0] Reg1;
    input [31:0] Reg2;
    input [2:0] ALUOp;
    output reg [31:0] result;
    output zero;

    assign zero = ( result == 0 ) ? 1 : 0;
    always@( ALUOp or Reg1 or Reg2 ) begin
       case (ALUOp)
            3'b000 : result = Reg1 + Reg2; // Y = A + B
            3'b001 : result = Reg1 - Reg2; // Y = A - B
            3'b010 : begin
                         if (Reg1 < Reg2 && ((Reg1[31] == 0 && Reg2[31] == 0) || (Reg1[31] == 1 && Reg2[31] == 1)))
                            result = 1;
                         else if (Reg1[31] == 0 && Reg2[31] == 1)
                            result = 0;
                         else if (Reg1[31] == 1 && Reg2[31] == 0)
                            result = 1;
                         else
                            result = 0;
                     end
            3'b011 : result = (Reg1 < Reg2) ? 1 : 0;  // Y=(A < B)? 1 : 0
            3'b100 : result = Reg2 << Reg1; // Y = B << A
            3'b101 : result = Reg1 | Reg2; // Y = A | B
            3'b110 : result = Reg1 & Reg2; // Y = A & B
            3'b111 : result = Reg1 ^ Reg2; // Y = A ^ B
        endcase
    end

endmodule

DataMemory

module DataMemory( CLK, DAddr, RD, WR, DataIn, DataOut );

    input CLK;
    input [31:0] DAddr;
    input RD;
    input WR;
    input [31:0] DataIn;
    output reg [31:0] DataOut;
    reg [7:0] dataMemory [0:60];

    always@( * ) begin // 读,随时的
        if (RD == 0) begin
            DataOut[7:0] = dataMemory[DAddr + 3];
            DataOut[15:8] = dataMemory[DAddr + 2];
            DataOut[23:16] = dataMemory[DAddr + 1];
            DataOut[31:24] = dataMemory[DAddr];
        end
    end

    always@( posedge CLK ) begin // 写,时钟上升沿触发
        if (WR == 0) begin
            dataMemory[DAddr + 3] <= DataIn[7:0];
            dataMemory[DAddr + 2] <= DataIn[15:8];
            dataMemory[DAddr + 1] <= DataIn[23:16];
            dataMemory[DAddr] <= DataIn[31:24];
        end
    end

endmodule

ControlUnit

module ControlUnit( CLK, RST, zero, op, DBDataSrc, WR, RD, ALUSrcB, ALUSrcA, ALUOP, RegWre, RegDst, WrRegDSrc, IRWre, InsMemRW, PCWre, ExtSel, PCSrc );

    input CLK, RST, zero;
    input [5:0] op;
    output reg DBDataSrc, WR, RD, ALUSrcB, ALUSrcA;
    output reg [2:0] ALUOP;
    output reg RegWre;
    output reg [1:0] RegDst;
    output reg WrRegDSrc, IRWre, InsMemRW, PCWre, ExtSel;
    output reg [1:0] PCSrc;
    reg [2:0] CurState, NextState;

    initial begin
        CurState = 3'b000;
        NextState = 3'b001;
    end

    always@( RST ) begin
        if (RST) begin
            CurState = 3'b000;
            NextState = 3'b001;
        end
    end

    always@( posedge CLK ) begin
        if (RST == 1) begin
            CurState = NextState;
            /*
            * 状态转换阶段
            */
        end
    end

    always@( * ) begin
        if (op == 6'b000000 || op == 6'b000001 || op == 6'b000010 || op == 6'b010000 || op == 6'b010001 || op == 6'b010010 || op == 6'b011000 || op == 6'b100110 || op == 6'b100111) begin
            NextState[2] = CurState[2] ^ CurState[0];
            NextState[1] = CurState[2] ^ CurState[0];
            NextState[0] = ~CurState[0];
        end

        if (op == 6'b110100) begin
            NextState[2] = ~CurState[2] & CurState[0];
            NextState[1] = 0;
            NextState[0] = ~CurState[2];
        end

        if (op == 6'b110001) begin
            NextState[2] = CurState[1] & CurState[0];
            NextState[1] = CurState[1] ^ CurState[0];
            NextState[0] = ~CurState[2] & ~CurState[0];
        end

        if (op == 6'b110000) begin
            NextState[2] = 0;
            NextState[1] = CurState[1] ^ CurState[0];
            NextState[0] = ~CurState[0];
        end

        if (op == 6'b111000 || op == 6'b111010 || op == 6'b111001 || op == 6'b111111) begin
            NextState[2] = 0;
            NextState[1] = 0;
            NextState[0] = ~CurState[0];
        end

    case (CurState)
        3'b000 : begin // IF
                     PCWre = (op == 6'b111111) ? 0 : 1;
                     InsMemRW = 1;
                     IRWre = 0;
                     RD = 1;
                     WR = 1;
                     RegWre = 0;
                 end
        3'b001 : begin // ID
                     PCWre = 0;
                     ExtSel = (op == 6'b010010) ? 0 : 1;
                     IRWre = 1;
                     WrRegDSrc = (op == 6'b111010) ?  0 : 1;
                     if (op == 6'b111010)
                         RegDst = 2'b00;
                     else if (op == 6'b000010 || op == 6'b010010 ||op == 6'b100111 || op == 6'b110001)
                         RegDst = 2'b01;
                     else
                         RegDst = 2'b10;
                     PCSrc[0] = (op == 6'b111010 || op == 6'b111000) ? 1 : 0;
                     PCSrc[1] = (op == 6'b111001 || op == 6'b111010 || op == 6'b111000) ? 1 : 0;
                     RegWre = (op == 6'b111010) ? 1 : 0;
                 end
        3'b110 : begin // EXE for add,sub,addi,or,and,ori,slt,slti,sll
                     IRWre = 0;
                     ALUOP[0] = (op == 6'b000001 || op == 6'b010000 || op == 6'b010010) ? 1 : 0;
                     ALUOP[1] = (op == 6'b010001 || op == 6'b100110 || op == 6'b100111) ? 1 : 0;
                     ALUOP[2] = (op == 6'b010000 || op == 6'b010001 || op == 6'b010010 || op == 6'b011000) ?  1 : 0;
                     ALUSrcA = (op == 6'b011000) ? 1 : 0;
                     ALUSrcB = (op == 6'b000010 || op == 6'b010010 || op == 6'b100111) ? 1 : 0;
                     DBDataSrc = 0;
                 end
        3'b101 : begin // EXE for beq
                     IRWre = 0;
                     ALUOP = 3'b001;
                     ALUSrcA = 0;
                     ALUSrcB = 0;
                     PCSrc = (zero == 1) ? 2'b01 : 2'b00;
                 end
        3'b010 : begin //EXE for sw,lw
                     IRWre = 0;
                     ALUOP = 3'b000;
                     ALUSrcA = 0;
                     ALUSrcB = 1;
                     DBDataSrc = 1;
                 end
        3'b011 : begin // MEM for sw,lw
                     RD = (op == 6'b110001) ? 0 : 1;
                     WR = (op == 6'b110000) ? 0 : 1;
                 end
        3'b111 : begin // WB for add,sub,addi,or,and,ori,slt,slti,sll
                     RD = 1;
                     WR = 1;
                     RegWre = 1;
                 end
        3'b100 : begin // WB for lw
                    RD = 1;
                    WR = 1;
                    RegWre = 1;
                 end
   endcase
   end
endmodule
  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值