制作多周期CPU(代码)

来源:互联网 发布:数据侠客行txt网盘 编辑:程序博客网 时间:2024/06/16 05:38

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          endendmodule

ALU_For_Next

module ALU_For_Next( CurPC, PC4 );    input [31:0] CurPC;    output reg [31:0] PC4;    always@( CurPC ) begin        PC4 = CurPC + 4;    endendmodule

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;    endendmodule

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    endendmodule

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);    endendmodule

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    endendmodule

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 };    endendmodule

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    endendmodule

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;    endendmodule

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 };    endendmodule

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    endendmodule

DR

module DR( CLK, DataIn, DataOut );    input CLK;    input [31:0] DataIn;    output reg [31:0] DataOut;    always@( negedge CLK ) begin        DataOut <= DataIn;    endendmodule

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进行扩展   endendmodule

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    endendmodule

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    endendmodule

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   endendmodule
原创粉丝点击