MIPS多周期CPU设计实现(40条指令)

无异常指令(共40条)

1.算术指令

  1. ADDIU
  2. ADDU
  3. SUBU
  4. MULU
  5. DIVU
  6. MUL
  7. DIV

2.逻辑指令

  1. AND
  2. ANDI
  3. NOR
  4. OR
  5. ORI
  6. XOR
  7. XORI
  8. LUI

3.移位指令

  1. SLLV
  2. SLL
  3. SRAV
  4. SRA
  5. SLT
  6. SLTI
  7. SLTIU
  8. SLTU
  9. SRL
  10. SRLV

4.分支跳转指令

  1. J
  2. JAL
  3. JR
  4. BEQ
  5. BNE
  6. BGEZ
  7. BGTZ
  8. BLEZ
  9. BLTZ

5.读写指令

  1. LW
  2. SW

6.数据移动

1.MFLO
2.MFHI
3.MTLO
4.MTHI

包括的模块

  1. mips模块是一个CPU,只含有复位信号rst和时钟信号clk,内部由PC、NPC、DM、IM、EXT、ALU、IR、Ctrl等模块以及一些多路选择器和缓冲器组成。
  2. PC(程序计数器):PC是指令计数器,主要功能是完成输出当前指令地址并保存下一条指令地址。复位后,PC指向0x0000_3000,此处为第一条指令的地址。
  3. NPC(NextPC计算单元):NPC是下条指令计数器,主要功能是计算下一条指令地址,NPCOp[1:0]决定如何计算NPC。
  4. Regfile(通用寄存器组,也称为寄存器文件、寄存器堆):RF主要功能是保存寄存器文件,并支持对通用寄存器的访问。
  5. ALU(算术逻辑单元):ALU主要功能是完成对输入数据的算数逻辑计算,包括加法、减法、按位或运算以及判断两个操作数是否相等。
  6. EXT(扩展单元):EXT主要功能是将16位的数据扩展为32位数据。
  7. IMEM(指令存储器):IM是指令存储器,主要功能是根据读控制信号DMWr,读写对应addr地址的32位数据。
  8. IR(指令寄存器):IR主要功能是完成对来自IM的指令的缓冲。
  9. DMEM(数据存储器):DM是数据存储器,主要功能是根据读写控制信号DMWr,读写对应addr地址的32位数据。
  10. MUX(数据选择器):主要功能是多路选择器。mux.v文件包含二选一、四选一、八选一、十六选一4中多路选择器。实例化多路选择器时,可使用#(XXX),实例化位宽为XXX的多路选择器。
  11. ICUT:主要功能是将32位指令分割为几个部分,传到不同的地方。
  12. MDU:进行乘除运算的单元
  13. define:对所有的名字进行宏定义。

模块

1.PC

端口说明

信号名 方向 描述
Clk I 时钟信号
Rst I 复位信号
1:将PC置为初始值
0:无效
PCwr I PC读写使能端信号
1:可以写
0:不可写
PCin[31:0] I 下一条指令的地址
PCout[31:0] O 当前指令的地址(映射)

功能定义

序号 功能 描述
1 复位 将PC置为初始值
2 计数 当PCWR有效并且时钟上升沿,PC就更新为NPC的输出

2.IMEM

端口说明

信号名 方向 描述
Addr I 当前指令的地址
Iout O 当前指令

功能定义

序号 功能 描述
1 取指令 输出Addr地址所代表的当前指令

3.IR

端口说明

信号名 方向 描述
clk I 时钟信号
IRin I 来自IMEM的指令
IRwr I 控制指令寄存器的读写
1:可以写
0:不可写
IRout O 当前指令

功能定义

序号 功能 描述
1 缓冲 对来自IMEM的指令进行缓冲

4.Regfile

端口说明

信号名 方向 描述
Clk I 时钟信号
rst I 重置信号
Ra[4:0] I 5位地址输入信号,将寄存器中的内容读出到Raout
Rb[4:0] I 5位地址输入信号,将寄存器中的内容读出到Rbout
Rw[4:0] I 5位地址输入信号,将寄存器作为目标寄存器
Wd[31:0] I 32位数据输入信号
IRwr I 控制IR读写
1:可写
0:不可写
Raout O 输出Raout所指定的寄存器中的32位数据
Rbout O 输出Rbout所指定的寄存器中的32位数据

功能定义

序号 功能 描述
1 读数据 读出Ra,Rb地址所对应寄存器中1的数据到Raout,Rbout
2 写数据 当RFwr有效且时钟上升沿来临,将Wd中的数据写入Rw所对应的寄存器中

5.ALU

端口说明

信号名 方向 描述
A[31:0] I 操作数A
B[31:0] I 操作数B
ALUop[3:0] I 详见功能表
Out[31:0] O ALU输出结果为32位数据

功能定义

序号 功能 描述
1 加运算 0000:Out = A + B
2 减运算 0001:Out = A - B
3 与运算 0010:Out = A & B
4 或非运算 0011:Out = ~(A | B)
5 异或运算 0100:Out = A ^ B
6 或运算 0101:Out = A | B
7 逻辑左移 0110:Out = B << A[10:6]
8 逻辑右移 0111:Out = B >> A[10:6]
9 算术右移 1000:Out = Signed(B) >>> A[10:6]
10 小于置1(有符号) 1001:Out = Signed(A) < Signed(B) ? 1 : 0
11 小于置1(无符号) 1010:Out = A < B ? 1 : 0
12 将A操作数左移16位(LUI) 1011:Out = A << 16

6.DMEM

端口说明

信号名 方向 描述
DMwr I 数据存储器写使能信号
1:可写
0:无效
Addr[31:0] I 32位地址输入,指定读出或写入地址数据
Imm[31:0] I 经过拓展的32位立即数,用于计算地址
Din[31:0] I 32为数据输入
Dout[31:0] O 32为数据输出,由计算后的地址指定

功能定义

序号 功能 描述
1 读数据 读出Addr所指定的数据到Dout
2 计算地址 计算出由Addr和立即数相加的地址
3 写数据 当DMwr有效且时钟上升到来时,将输入的数据Din写到计算结果所指定的地址

7.EXT

端口说明

信号名 方向 描述
EXTin I 16位输入数据
EXTop I 扩展方式选择信号
0:符号扩展
1:零扩展
EXTout O 扩展到32位后的输出数据

功能定义

序号 功能 描述
1 符号扩展 将16位的输入数据进行符号扩展,输出32位数据
2 零扩展 将16位的输入数据进行零扩展,输出32位数据

8.NPC

端口说明

信号名 方向 描述
Immj[25:0] I 跳转指令目的地址中间26位
ImmB[31:0] I 分支指令的偏移00量(分支选择时加上)
PC[31:0] I 分支指令基地址
CmpA I 分支指令第一个比较数,指令为Jump时当做地址使用
CmpB I 分支指令第二个比较数
is_JR I 单独判断是不是JR指令
NPCop[2:0] I 详见功能表
JORB I 对Jump和Branch选择
0:Jump
1:Branch
NPCout[31:0] O 从Jump和Branch里选出来的下一条指令地址
NextPC O 常规情况下PC + 4

功能定义

序号 功能 描述
1 计算分支地址 先拓展立即数,根据比较结果来计算分支地址:
000:BEQ
001:BNE
010:BLEZ
011:BGTZ
100:BLTZ
101:BGEZ
2 计算跳转地址 通过位拼接来计算得到跳转地址

9.MDU

端口说明

信号名 方向 描述
clk I 时钟信号
rst I 重置信号
MDUressel I 读寄存器选择信号
0:读LO寄存器
1:读HI寄存器
A[31:0] I 参与计算的第一个值
B[31:0] I 参与计算的第二个值
MDUcoac I MDU使能端
MDUop[2:0] I MDU功能选择信号
000:{HI, LO} = $signed(A) * $signed(B)
001:{HI, LO} = A * B
010:LO = A / B, HI = A % B
011:LO = $signed(A) / $signed(B, HI = $signed(A) % $signed(B)
100:LO = A
101:HI = A
MDUout[31:0] O 将计算结果输出

功能定义

序号 功能 描述
1 无符号乘 {HI, LO} = A * B
2 有符号乘 {HI, LO} = $signed(A) * $signed(B)
3 无符号除 LO = A / B, HI = A % B
4 有符号除 LO = $signed(A) / $signed(B, HI = $signed(A) % $signed(B)
5 写LO寄存器 LO = A
6 读LO寄存器 MDUout = LO
7 写HI寄存器 HI = A
8 读HI寄存器 MDUout = HI

10.ICUT

端口说明

信号名 方向 描述
Ins[31:0] I 传入的32位指令
op[5:0] O rs寄存器
rt[4:0] O rt寄存器
rd[4:0] O rd寄存器
rs[4:0] O 操作码
sa[4:0] O 位移量
Imm[15:0] O 立即数
Addr[25:0] O J指令地址片段
Insout[31:0] O 传给control的32位指令

功能定义

序号 功能 描述
1 分割 将32位指令分割成片段,传到各个的端口中去

11.Control

端口说明

信号名 方向 描述
Rst I 重置
Clk I 时钟信号
Ins I 32位指令,用来译码
PCwr O 控制PC是否可写
0:不可写
1:可写
IRwr O 控制IR是否可写
0:不可写
1:可写
Regin[1:0] O 选择写入Regfile的地址
00:写到rt寄存器
01:写到rd寄存器
10:写到1F寄存器
RFwr O 控制是否可以写入Regfile
0:不可写
1:可写
SEL_A O 选择A操作数
0:从Regfile中来
1:从EXT来
SEL_B O 选择B操作数
0:从Regfile中来
1:从EXT来
ALUop[3:0] O 控制ALU选择哪种运算,详见ALU功能描述
JORB O 控制NPCout选择Jump还是Branch
0:Jump
1:Branch
NPCop[2:0] O 选择Branch的种类, 详见NPC功能描述
MDUressel O 读寄存器选择信号
0:读LO寄存器
1:读HI寄存器
MDUop[2:0] O 选择MDU的功能,详见功能描述
DMwr O 控制DM是否可写
0:不可写
1:可写
EXTop[1:0] O 控制扩展方式,详见功能表
WBsel[1:0] O 选择写回寄存器的数据从哪里来
NPCOsel O 选择正常执行下一条还是跳转分支
is_JR O 判断是不是将CMPA作为JR的地址使用
MDUcoac O MDU使能信号
1:可以进行计算
0:不可以进行计算

CPU数据数据通路图

MIPS多周期CPU设计实现(40条指令)

状态对应信号

MIPS多周期CPU设计实现(40条指令)
MIPS多周期CPU设计实现(40条指令)
MIPS多周期CPU设计实现(40条指令)
MIPS多周期CPU设计实现(40条指令)
MIPS多周期CPU设计实现(40条指令)
MIPS多周期CPU设计实现(40条指令)

模块代码实现

1.ALU

module ALU(
    input [31:0]A,          // 操作数A
    input [31:0]B,          // 操作数B
    input [3:0]ALUop,       // 选择功能
    output reg [31:0]Out        // 输出结果
);

    always @(*) begin
        case(ALUop)
            4'b0000: Out = A + B;
            4'b0001: Out = A - B;
            4'b0010: Out = A & B;
            4'b0011: Out = A | B;
            4'b0100: Out = A ^ B;                               // XOR
            4'b0101: Out = ~(A | B);                            // NOR
            4'b0110: Out = B << A[10:6];                        // SLL
            4'b0111: Out = B >> A[10:6];                        // SRL
            4'b1000: Out = $signed(B) >>> A[10:6];              // SRA
            4'b1001: Out = ($signed(A) < $signed(B)) ? 1 : 0;   // SLT和SLTI
            4'b1010: Out = (A < B) ? 1 : 0;                     // SLTU和SLTIU
            4'b1011: Out = A << 16;                             // LUI
        endcase 
    end

endmodule

2.Control

`include "define.v"

module Control(
    input clk,                  // 时钟信号
    input rst,                  // 重置信号
    input [31:0]Ins,            // 传入的32位指令
    output reg PCwr,                // 控制PC是否能写入
    output reg IRwr,                // 控制IR是否能写入
    output reg[1:0]Regin,       // 进入Regfile的选择
    output reg RFwr,                // 控制Regfile是否能写入
    output reg SEL_A,               // 选入ALU的A操作数
    output reg SEL_B,               // 选入ALU的B操作数
    output reg[3:0]ALUop,          // ALU的操作
    output reg JORB,                // 判断是Jump还是Branch
    output reg[2:0]NPCop,          // 判断是哪种Branch
    output reg MDUressel,           // 选择是HI还是LO
    output reg[2:0]MDUop,          // MDU的操作
    output reg DMwr,                // DM使能信号
    output reg[1:0]EXTop,          // 是哪一种扩展
    output reg[1:0]WBsel,          // 写回的数据从哪里来
    output reg NPCOsel,             // 对NPC出来的结果进行选择(跳或者常态)
    output reg is_JR,               // 判断是不是JR, 需要将CmpA作为地址
    output reg Dtype,               // 判断DM是读还是写
    output reg MDUcoac              // MDU使能信号
);

    parameter  IF = 3'b000;    // 取指
    parameter  ID = 3'b001;    // 译码
    parameter  EXE = 3'b010;   // 执行
    parameter  MEM = 3'b011;   // 读取
    parameter  WB = 3'b100;    // 写回


    reg[2:0] CurrentState;     // 当前状态
    reg[2:0] NextState;        // 下一状态

    reg[5:0] Op;
    /*时序逻辑*/
    always @(posedge clk,posedge rst) begin
        if(rst) 
            CurrentState <= IF;
        else
            CurrentState <= NextState;
    end
    
    always @(*) begin
        case(CurrentState)
            IF: begin
                NextState = ID;
                PCwr = 1'b0;
                IRwr = 1'b1;
                RFwr = 1'b0;
                DMwr = 1'b0;
                NPCOsel = 1'b0;
            end

            ID: begin
                JORB = ~(Ins[`op] == `OP_J || Ins[`op] == `OP_JAL || (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_JR));
                NPCOsel = (Ins[`op] == `OP_J || Ins[`op] == `OP_JAL || (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_JR));
                //$display("NPCOsel = %8X", NPCOsel);
                is_JR = (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_JR) ? 1'b1 : 1'b0;

                case(Ins[`op])
                    `OP_J: begin
                        NextState = IF;
                        PCwr = 1'b1;
                        IRwr = 1'b0;
                        RFwr = 1'b0;
                        DMwr = 1'b0;
                    end 

                    `OP_BEQ,`OP_BGEZ,`OP_BGTZ,
                    `OP_BLEZ,`OP_BLTZ,`OP_BNE: begin
                        NextState = EXE;
                        PCwr = 1'b0;
                        RFwr = 1'b0;
                        DMwr = 1'b0;
                        IRwr = 1'b0;
                    end

                    `OP_JAL: begin
                        NextState = IF;
                        PCwr = 1'b1;
                        IRwr = 1'b0;
                        RFwr = 1'b1;
                        DMwr = 1'b0;
                        Regin = 2'b10;
                        WBsel = 2'b11;
                    end

                    `OP_R:
                        case(Ins[`funct])
                            `FUNCT_JR: begin
                                NextState = IF;
                                PCwr = 1'b1;
                                IRwr = 1'b0;
                                RFwr = 1'b0;
                                DMwr = 1'b0;
                            end
                            default: begin
                                NextState = EXE;
                                PCwr = 1'b1;       // 为了每次让PC + 4
                                RFwr = 1'b0;
                                DMwr = 1'b0;
                                IRwr = 1'b0;
                                MDUcoac = 1'b0; 
                            end
                        endcase
                    default: begin
                        NextState = EXE;
                        PCwr = 1'b1;
                        RFwr = 1'b0;
                        DMwr = 1'b0;
                        IRwr = 1'b0;
                    end
                endcase
            end

            EXE: begin
                is_JR = 1'b0;

                Regin = 
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_DIV) ? 2'b00 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_DIVU) ? 2'b00 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MULT) ? 2'b00 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MULTU) ? 2'b00 :
                2'b01;

                SEL_A = 
                (Ins[`op] == `OP_LUI) ? 1'b1 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SLL) ? 1'b1 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SRL) ? 1'b1 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SRA) ? 1'b1 :
                1'b0;

                SEL_B = 
                (Ins[`op] == `OP_ADDIU || Ins[`op] == `OP_ANDI || Ins[`op] == `OP_ORI
                || Ins[`op] == `OP_XORI || Ins[`op] == `OP_SLTI || Ins[`op] == `OP_SLTIU);

                ALUop = 
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_ADDU) ? 4'b0000 :
                (Ins[`op] == `OP_ADDIU) ? 4'b0000 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_AND) ? 4'b0010 :
                (Ins[`op] == `OP_ANDI) ? 4'b0010 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_OR) ? 4'b0011 :
                (Ins[`op] == `OP_ORI) ? 4'b0011 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_XOR) ? 4'b0100 :
                (Ins[`op] == `OP_XORI) ? 4'b0100 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SLL) ? 4'b0110 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SLLV) ? 4'b0110 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SRA) ? 4'b1000 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SRAV) ? 4'b1000 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SLT) ? 4'b1001 :
                (Ins[`op] == `OP_SLTI) ? 4'b1001 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SLTU) ? 4'b1010 :
                (Ins[`op] == `OP_SLTIU) ? 4'b1010 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SRL) ? 4'b0111 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SRLV) ? 4'b0111 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SUBU) ? 4'b0001 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_NOR) ? 4'b0101 :
                (Ins[`op] == `OP_LUI) ? 4'b1011 :
                4'b1111;

                JORB = 
                (Ins[`op] == `OP_BEQ) ? 1'b1 :
                (Ins[`op] == `OP_BNE) ? 1'b1 :
                (Ins[`op] == `OP_BLEZ && Ins[`rt] == `RT_BLEZ) ? 1'b1 :
                (Ins[`op] == `OP_BGTZ && Ins[`rt] == `RT_BGTZ) ? 1'b1 :
                (Ins[`op] == `OP_BLTZ && Ins[`rt] == `RT_BLTZ) ? 1'b1 :
                (Ins[`op] == `OP_BGEZ && Ins[`rt] == `RT_BGEZ) ? 1'b1 :
                1'b0;

                NPCop = 
                (Ins[`op] == `OP_BEQ) ? 3'b000 :
                (Ins[`op] == `OP_BNE) ? 3'b001 :
                (Ins[`op] == `OP_BLEZ && Ins[`rt] == `RT_BLEZ) ? 3'b010 :
                (Ins[`op] == `OP_BGTZ && Ins[`rt] == `RT_BGTZ) ? 3'b011 :
                (Ins[`op] == `OP_BLTZ && Ins[`rt] == `RT_BLTZ) ? 3'b100 :
                (Ins[`op] == `OP_BGEZ && Ins[`rt] == `RT_BGEZ) ? 3'b101 :
                3'b111;

                MDUop = 
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MULT) ? 3'b000 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MULTU) ? 3'b001 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_DIV) ? 3'b011 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_DIVU) ? 3'b010 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MTLO) ? 3'b100 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MTHI) ? 3'b101 :
                3'b111;

                EXTop = 
                (Ins[`op] == `OP_ADDIU) ? 2'b00 :
                (Ins[`op] == `OP_ANDI) ? 2'b01 :
                (Ins[`op] == `OP_ORI) ? 2'b01 :
                (Ins[`op] == `OP_XORI) ? 2'b01 :
                (Ins[`op] == `OP_LUI) ? 2'b01 :
                2'b00;

                NPCOsel = 
                (Ins[`op] == `OP_BEQ) ? 1'b1 :
                (Ins[`op] == `OP_BNE) ? 1'b1 :
                (Ins[`op] == `OP_BLEZ && Ins[`rt] == `RT_BLEZ) ? 1'b1 :
                (Ins[`op] == `OP_BGTZ && Ins[`rt] == `RT_BGTZ) ? 1'b1 :
                (Ins[`op] == `OP_BLTZ && Ins[`rt] == `RT_BLTZ) ? 1'b1 :
                (Ins[`op] == `OP_BGEZ && Ins[`rt] == `RT_BGEZ) ? 1'b1 :
                1'b0;

                MDUcoac = 
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_DIV) ? 1'b1 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_DIVU) ? 1'b1 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MULT) ? 1'b1 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MULTU) ? 1'b1 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MTLO) ? 1'b1 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MTHI) ? 1'b1 :
                1'b0;

                case(Ins[`op])
                    `OP_R,`OP_ADDI,`OP_ADDIU,
                    `OP_ANDI,`OP_ORI,`OP_XORI,`OP_SLTI,`OP_SLTIU,`OP_LUI: begin
                        
                        if (Ins[`funct] == `FUNCT_DIV || Ins[`funct] == `FUNCT_DIVU || 
                            Ins[`funct] == `FUNCT_MULT || Ins[`funct] == `FUNCT_MULTU ||
                            Ins[`funct] == `FUNCT_MTLO || Ins[`funct] == `FUNCT_MTHI) begin
                            NextState = IF;
                            PCwr = 1'b0;
                            RFwr = 1'b0;
                            DMwr = 1'b0;
                            IRwr = 1'b0;
                        end
                        else begin
                            NextState = WB;
                            PCwr = 1'b0;
                            RFwr = 1'b0;
                            DMwr = 1'b0;
                            IRwr = 1'b0;
                        end
                    end

                    `OP_BEQ,`OP_BGEZ,`OP_BGTZ,
                    `OP_BLEZ,`OP_BLTZ,`OP_BNE: begin
                        NextState = IF;
                        PCwr = 1'b1;
                        RFwr = 1'b0;
                        DMwr = 1'b0;
                        IRwr = 1'b0;
                    end

                    default: begin
                        NextState = MEM;
                        PCwr = 1'b0;
                        RFwr = 1'b0;
                        DMwr = 1'b0;
                        IRwr = 1'b0;
                    end
                endcase
            end

            MEM: begin
                case(Ins[`op])
                    `OP_LW: begin
                        NextState = WB;
                        PCwr = 1'b0;
                        RFwr = 1'b1;
                        DMwr = 1'b0;
                        IRwr = 1'b0;
                        //Dtype = 1'b0;
                    end

                    default: begin
                        NextState = IF;
                        PCwr = 1'b0;
                        RFwr = 1'b0;
                        DMwr = 1'b1;
                        IRwr = 1'b0;
                        //Dtype = 1'b1;
                    end
                endcase
            end

            WB: begin
                Regin = 
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_ADDU) ? 2'b01 : 
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SUBU) ? 2'b01 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_AND) ? 2'b01 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_OR) ? 2'b01 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_XOR) ? 2'b01 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_NOR) ? 2'b01 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SLL) ? 2'b01 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SLLV) ? 2'b01 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SRL) ? 2'b01 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SRLV) ? 2'b01 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SRA) ? 2'b01 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SRAV) ? 2'b01 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SLT) ? 2'b01 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SLTU) ? 2'b01 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MFLO) ? 2'b01 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MFHI) ? 2'b01 :
                (Ins[`op] == `OP_ADDIU) ? 2'b00 :
                (Ins[`op] == `OP_ANDI) ? 2'b00 :
                (Ins[`op] == `OP_ORI) ? 2'b00 :
                (Ins[`op] == `OP_XORI) ? 2'b00 :
                (Ins[`op] == `OP_LUI) ? 2'b00 :
                (Ins[`op] == `OP_SLTI) ? 2'b00 :
                (Ins[`op] == `OP_SLTIU) ? 2'b00 :
                (Ins[`op] == `OP_LW) ? 2'b00 :
                0;


                MDUressel = (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MFHI) ? 1'b1 : 1'b0;

                WBsel = 
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MFLO) ? 2'b01 :
                (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MFHI) ? 2'b01 :
                (Ins[`op] == `OP_LW) ? 2'b10 :
                2'b00;

                NextState = IF;
                PCwr = 1'b0;
                RFwr = 1'b1;
                DMwr = 1'b0;
                IRwr = 1'b0;
            end
        endcase
    end

endmodule

3.define

/*指令分段*/
`define op 31:26
`define funct 5:0
`define imm26 25:0
`define imm16 15:0
`define rs 25:21
`define rt 20:16
`define rd 15:11
`define s 10:6

/*ALU操作*/
`define ALUop_ADD     4'b0000
`define ALUop_SUB     4'b0001
`define ALUop_AND     4'b0010
`define ALUop_OR      4'b0011
`define ALUop_XOR     4'b0100
`define ALUop_NOR     4'b0101
`define ALUop_SLL     4'b0110
`define ALUop_SRL     4'b0111
`define ALUop_SRA     4'b1000
`define ALUop_SLT     4'b1001
`define ALUop_SLTU    4'b1010
`define ALUop_LUI     4'b1011

/*EXTop*/
`define EXT_SIGN      2'b00
`define EXT_ZERO      2'b01

/******* OP 操作码 *******/
`define OP_R    6'b000000
/******* 存储读取指令 *******/
`define OP_LW   6'b100011
`define OP_LUI  6'b001111
`define OP_SW   6'b101011
/*******     I TYPE      *******/
`define OP_ADDI 6'b001000
`define OP_ADDIU 6'b001001
`define OP_ANDI 6'b001100
`define OP_ORI  6'b001101
`define OP_SLTI 6'b001010
`define OP_SLTIU 6'b001011
`define OP_XORI 6'b001110
/*******   BRANCH TYPE   *******/
`define OP_BEQ  6'b000100
`define OP_BGEZ 6'b000001
`define OP_BGTZ 6'b000111
`define OP_BLEZ 6'b000110
`define OP_BLTZ 6'b000001
`define OP_BNE  6'b000101
/*******     J TYPE      *******/
`define OP_J    6'b000010
`define OP_JAL  6'b000011


//功能码
`define FUNCT_ADD     6'b100000
`define FUNCT_SUB     6'b100010
`define FUNCT_ADDU    6'b100001
`define FUNCT_SUBU    6'b100011
`define FUNCT_AND     6'b100100
`define FUNCT_OR      6'b100101
`define FUNCT_NOR     6'b100111
`define FUNCT_XOR     6'b100110
`define FUNCT_SLL     6'b000000
`define FUNCT_SLLV    6'b000100
`define FUNCT_SRL     6'b000010
`define FUNCT_SRLV    6'b000110
`define FUNCT_SRA     6'b000011
`define FUNCT_SRAV    6'b000111
`define FUNCT_SLT     6'b101010
`define FUNCT_SLTU    6'b101011
`define FUNCT_JALR    6'b001001
`define FUNCT_JR      6'b001000
`define FUNCT_MULT    6'b011000
`define FUNCT_MULTU   6'b011001
`define FUNCT_DIV     6'b011010
`define FUNCT_DIVU    6'b011011
`define FUNCT_MFHI    6'b010000
`define FUNCT_MFLO    6'b010010
`define FUNCT_MTHI    6'b010001
`define FUNCT_MTLO    6'b010011
//B_type_opcode
`define RT_BGEZ    5'b00001
`define RT_BGTZ    5'b00000
`define RT_BLEZ    5'b00000
`define RT_BLTZ    5'b00000

4.DMEM

module DMEM(
    input clk,                  // 时钟信号
    input DMwr,                 // DM写使能信号
    input [31:0]Din,            // 要写入DM的数据
    input [31:0]Imm,            // 用来计算地址的,扩展过的立即数
    input [31:0]Addr,           // 用来计算地址的rs中的内容
    output reg[31:0]Dout        // 从DM中输出的数据
);

    reg [31:0] RAM[1023:0];

    integer i;

    initial begin  // 初始时将所有内存单元初始化
        for (i = 0; i < 1023; i = i + 1) RAM[i] = 32'b0;
    end

    always @(posedge clk) begin
        if (DMwr) begin
            RAM[Imm + Addr[11:2]] = Din;  // 利用映射地址写入
            //$display("%H",RAM[Addr[11:2]]);
        end
        else begin
            Dout = RAM[Imm + Addr[11:2]];  // 利用映射地址读出
            //$display("%H",RAM[Addr[11:2]]);
        end
    end

endmodule

5.EXT

module EXT(
    input [15:0] EXTin,    // 需要扩展的16位立即数
    input EXTop,           // 操作
    output reg[31:0]EXTout    // 扩展后的32位输出
);

    always @(*) begin
        if (EXTop) begin       // 零扩展
            EXTout = EXTin;
        end
        else EXTout = $signed(EXTin);    // 符号扩展
    end

endmodule

6.ICUT

module ICUT(
    input [31:0]Ins,
    output reg[4:0]rs,          // 传入rs端口
    output reg[4:0]rt,          // 传入rt端口
    output reg[4:0]rd,          // 传入rd端口
    output reg[15:0]Imm,        // Imm传入EXT中拓展
    output reg[25:0]Addr,       // 地址片段传入NPC中
    output reg[31:0]Insout      // 不分割,直接送入Control进行译码
);

    initial begin
        rs = 5'b00000;
        rt = 5'b00000;
        rd = 5'b00000;
    end

    always @(Ins) begin
        rs = Ins[25:21];
        rt = Ins[20:16];
        rd = Ins[15:11];
        Imm = Ins[15:0];
        Addr = Ins[25:0];
        Insout = Ins;
    end

endmodule

7.IMEM

module IMEM(
    input [31:0]Addr,
    output reg [31:0]Iout
);

    reg [31:0] IM [1023:0];

    initial
        $readmemh("F:/MIPS_MULTI_CYCLE_CPU/test_app/test_12.txt", IM);

    always@(*) begin
        Iout <= IM[Addr[11:2]];
    end

endmodule

8.IR

module IR(
    input clk,
    input IRwr,
    input [31:0]IRin,
    output reg [31:0]IRout
);

    initial
        IRout = 0;

    always @(posedge clk) begin
        if (IRwr) begin
            IRout <= IRin;
        end
    end

endmodule

9.MDU

module MDU(
    input clk,              // 时钟信号
    input rst,              // 重置信号
    input [31:0]A,          // 操作数A
    input [31:0]B,          // 操作数B
    input MDUressel,        // 结果选择(HI/LO)
    input MDUcoac,          // MUD使能端
    input [2:0]MDUop,       // 操作选择
    output [31:0]MDUout     // 输出结果
);

    reg [31:0]HI;
    reg [31:0]LO;

    assign MDUout = (MDUressel == 0) ? LO : HI;

    always @(posedge clk) begin
        if (rst) begin
            HI = 0;
            LO = 0;
        end
        else begin
            if (MDUcoac) begin
                case(MDUop)
                    3'b000:  {HI,LO} = $signed(A) * $signed(B);
                    3'b001:  {HI,LO} = A * B;
                    3'b010:  if(B != 0) begin
                        LO = $signed(A) / $signed(B);
                        HI = $signed(A) % $signed(B);
                    end
                    3'b011:  if(B != 0) begin
                        LO = A / B;
                        HI = A % B;
                    end
                    3'b100: begin 
                        LO = A;
                    end
                    3'b101: begin
                        HI = A;
                    end 
                endcase
            end
        end
    end

endmodule

10.mips

`timescale 1ns / 1ps
`include "define.v"
//
// Company: 
// Engineer: 
// 
// Create Date: 2021/07/02 14:26:18
// Design Name: 
// Module Name: mips
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module mips(
    input clk,
    input rst
);
    //线网部分
    // PC模块
    wire PCwr;
    wire [31:0]PCin;
    wire [31:0]PCout;

    // IMEM模块
    wire [31:0]Iout;

    // 拓展器模块
    wire EXTop;

    // IR模块
    wire [31:0]IRout;
    wire IRwr;

    // ICUT模块
    wire [4:0]rs;
    wire [4:0]rt;
    wire [4:0]rd;
    wire [15:0]Imm;
    wire [25:0]OutAddr;
    wire [31:0]Insout;

    // ICUT和RF之间的数据选择器
    wire [1:0]Regin;
    wire [4:0]CUT_MUX_RF_out;

    // Regfile模块
    wire [31:0]Wd;
    wire RFwr;
    wire [31:0]Raout;
    wire [31:0]Rbout;

    // NPC模块
    wire JORB;
    wire is_JR;
    wire [2:0]NPCop;
    wire [31:0]NextPC;
    wire [31:0]NPCout;

    // NPC和PC之间的数据选择器
    wire NPCOsel;

    // 操作数A选择器
    wire [31:0]SEL_A_out;
    wire [31:0]EXTout;
    wire Sel_A;

    // 操作数B选择器
    wire [31:0]SEL_B_out;
    wire Sel_B;

    // ALU模块
    wire [3:0]ALUop;
    wire [31:0]ALUout;

    //  数据存储器模块
    wire DMwr;
    wire Dtype;
    wire [31:0]Dout;

    // 乘除器单元
    wire MDUressel;
    wire MDUcoac;
    wire [2:0]MDUop;
    wire [31:0]MDUout;

    // 写回寄存器的选择器
    wire [1:0]WBsel;

    

    // 模块实例化
    PC U_PC(.clk(clk), .rst(rst), .PCwr(PCwr), .PCin(PCin), .PCout(PCout));
    IMEM U_IMEM(.Addr(PCout), .Iout(Iout));
    EXT U_EXT(.EXTin(Imm), .EXTop(EXTop), .EXTout(EXTout));
    IR U_IR(.clk(clk), .IRwr(IRwr), .IRin(Iout), .IRout(IRout));
    ICUT U_ICUT(.Ins(IRout), .rs(rs), .rt(rt), .rd(rd), .Imm(Imm), .Addr(OutAddr), .Insout(Insout));
    MUX4#(5) CUT_MUX_RF(.In0(rt), .In1(rd), .In2(31), .Op(Regin), .Out(CUT_MUX_RF_out));
    Regfile U_Regfile(.clk(clk), .rst(rst), .Ra(rs), .Rb(rt), .Rw(CUT_MUX_RF_out), .Wd(Wd), .RFwr(RFwr), .Raout(Raout), .Rbout(Rbout));
    NPC U_NPC(.Immj(OutAddr), .ImmB(EXTout), .PC(PCout), .CmpA(Raout), .CmpB(Rbout), .is_JR(is_JR), .NPCop(NPCop), .JORB(JORB), .NPCout(NPCout), .NextPC(NextPC));
    MUX2 NPC_TO_PC(.In0(NextPC), .In1(NPCout), .Op(NPCOsel), .Out(PCin));
    MUX2 SEL_A(.In0(Raout), .In1(EXTout), .Op(Sel_A), .Out(SEL_A_out));
    MUX2 SEL_B(.In0(Rbout), .In1(EXTout), .Op(Sel_B), .Out(SEL_B_out));
    ALU U_ALU(.A(SEL_A_out), .B(SEL_B_out), .ALUop(ALUop), .Out(ALUout));
    DMEM U_DMEM(.clk(clk), .DMwr(DMwr), .Din(Rbout), .Imm(EXTout), .Addr(Raout), .Dout(Dout));
    MDU U_MDU(.clk(clk), .rst(rst), .A(Raout), .B(Rbout), .MDUressel(MDUressel), .MDUcoac(MDUcoac), .MDUop(MDUop), .MDUout(MDUout));
    MUX4 WB_MUX(.In0(ALUout), .In1(MDUout), .In2(Dout), .In3(NextPC), .Op(WBsel), .Out(Wd));
    Control U_Control(.clk(clk), .rst(rst), .Ins(Insout), .PCwr(PCwr), .IRwr(IRwr), .Regin(Regin), .RFwr(RFwr),
                      .SEL_A(Sel_A), .SEL_B(Sel_B), .ALUop(ALUop), .JORB(JORB), .NPCop(NPCop), .MDUressel(MDUressel), 
                      .MDUop(MDUop), .DMwr(DMwr), .EXTop(EXTop), .WBsel(WBsel), .NPCOsel(NPCOsel), .is_JR(is_JR), 
                      .Dtype(Dtype), .MDUcoac(MDUcoac));
endmodule

11.MUX

module MUX2
#(parameter width = 32)(
    input [width-1:0] In0,
    input [width-1:0] In1,
    input Op,
    output reg [width-1:0] Out
    );
    
    

    always @(*) begin
        case (Op)
            1'b0: Out = In0;
            1'b1: Out = In1;
        endcase
    end

endmodule


module MUX4
#(parameter width = 32)(
    input [width-1:0] In0,
    input [width-1:0] In1,
    input [width-1:0] In2,
    input [width-1:0] In3,
    input [1:0] Op,
    output reg [width-1:0] Out
    );
    
    

    always @(*) begin
        case (Op)
            2'b00: Out = In0;
            2'b01: Out = In1;
            2'b10: Out = In2;
            2'b11: Out = In3;
        endcase
    end

endmodule


module MUX8
#(parameter width = 32)(
    input [width-1:0] In0,
    input [width-1:0] In1,
    input [width-1:0] In2,
    input [width-1:0] In3,
    input [width-1:0] In4,
    input [width-1:0] In5,
    input [width-1:0] In6,
    input [width-1:0] In7,
    input [2:0] Op,
    output reg [width-1:0] Out
    );
    

    always @(*) begin
        case (Op)
            3'b000: Out = In0;
            3'b001: Out = In1;
            3'b010: Out = In2;
            3'b011: Out = In3;
            3'b100: Out = In4;
            3'b101: Out = In5;
            3'b110: Out = In6;
            3'b111: Out = In7;
        endcase
    end

endmodule

12.NPC

module NPC(
    input [25:0]Immj,           // 分支指令立即数
    input [31:0]ImmB,           // 跳转指令立即数(偏移量)
    input [31:0]PC,             // 基地址
    input [31:0]CmpA,           // 分支比较数A
    input [31:0]CmpB,           // 分支比较数B
    input [2:0]NPCop,           // 选择分支
    input is_JR,                // 单独判断是不是JR
    input JORB,                 // 选择输出是Jump还是Branch
    output reg [31:0]NPCout,    // Jump和Branch选出的下一条指令地址
    output [31:0]NextPC         // 常态下PC + 4
);

    assign NextPC = PC + 4;

    always @(*) begin
        if (JORB) begin  // JORB是1执行Branch
            case(NPCop)
                3'b000: NPCout = ($signed(CmpA) == $signed(CmpB)) ? (PC + (ImmB << 2) + 4) : (PC + 4);       // BEQ
                3'b001: NPCout = ($signed(CmpA) != $signed(CmpB)) ? (PC + (ImmB << 2) + 4) : (PC + 4);       // BNE
                3'b010: NPCout = ($signed(CmpA) <= 0) ? (PC + (ImmB << 2) + 4) : (PC + 4);                   // BLEZ
                3'b011: NPCout = ($signed(CmpA) > 0) ? (PC + (ImmB << 2) + 4) : (PC + 4);                    // BGTZ
                3'b100: NPCout = ($signed(CmpA) < 0) ? (PC + (ImmB << 2) + 4) : (PC + 4);                    // BLTZ
                3'b101: NPCout = ($signed(CmpA) >= 0) ? (PC + (ImmB << 2) + 4) : (PC + 4);                   // BGEZ
            endcase
        end
        else begin  // JORB是0执行Jump
            if (is_JR) begin
                NPCout = CmpA;
            end
            else NPCout = {PC[31:28], Immj, 2'b00};
        end
    end

endmodule

13.PC

module PC(
	input clk,					// 时钟信号
	input rst,					// 重置信号
	input PCwr,					// PC写使能信号
	input [31:0]PCin,			// PC输入端口
	output reg [31:0]PCout		// PC 输出端口
);

	always @(posedge clk or rst) begin
		if (rst) begin
			PCout <= 32'h0000_0000;
		end
		else if (PCwr) begin
			PCout <= PCin;
		end
	end

endmodule

14.Regfile

module Regfile(
    input clk,                  // 时钟信号
    input rst,                  // 重置信号
    input [4:0]Ra,              // rs寄存器读入
    input [4:0]Rb,              // rt寄存器读入
    input [4:0]Rw,              // rd/rt寄存器读入
    input [31:0]Wd,             // 写入寄存器的数据
    input RFwr,                 // 写寄存器使能信号
    output reg [31:0]Raout,         // 从rs中读出来的内容
    output reg [31:0]Rbout          // 从rt中读出来的内容
);

    initial begin
        Raout = 0;
        Rbout = 0;
    end

    // 寄存器堆
    reg [31:0] RF[31:0];
    integer i;
    initial begin
        for (i = 0; i < 32; i = i + 1) RF[i] = 32'b0;
    end

    always@(Ra or Rb) begin
        Raout <= RF[Ra];
        Rbout <= RF[Rb];
    end

    always @(posedge clk) begin
        if (rst) begin
            for (i = 0; i < 32; i = i + 1) RF[i] = 32'b0;
        end

        else if (RFwr && Rw != 0) begin
            RF[Rw] <= Wd;
            //$display("Wd = %8X", Wd);
            //$display("R[00-07]= %8X, %8X, %8X, %8X, %8X, %8X, %8X, %8X", 0, RF[1], RF[2], RF[3], RF[4], RF[5], RF[6], RF[7]);
            //$display("R[08-15]= %8X, %8X, %8X, %8X, %8X, %8X, %8X, %8X", RF[8], RF[9], RF[10], RF[11], RF[12], RF[13], RF[14], RF[15]);
            //$display("R[16-23]= %8X, %8X, %8X, %8X, %8X, %8X, %8X, %8X", RF[16], RF[17], RF[18], RF[19], RF[20], RF[21], RF[22], RF[23]);
            //$display("R[24-31]= %8X, %8X, %8X, %8X, %8X, %8X, %8X, %8X", RF[24], RF[25], RF[26], RF[27], RF[28], RF[29], RF[30], RF[31]);
        end
    end

endmodule
上一篇:MIPS体系结构学习笔记


下一篇:mips架构汇编指令