【使用verilog、五级流水和MIPS指令集设计CPU】

内容

  • 大概描述
    • 设计思想
    • 设计内容
    • 设计处理器的结构和方法
    • 处理器的操作过程
    • 代码
    • 测试部分
    • 总结
    • 参考文献
    • 备注

大概描述

参考《自己动手写CPU》这本书,这本书算是手把手教学写CPU,比较适合初学者。这里完成五级流水结构的处理器,实现70条左右的指令,基本实现全部整数指令,开发工具是Vivado。

设计思想

设计的处理器是五级流水处理器,取指,译码,执行,访存,回写。
(1)取指: 取出指令存储器中的指令,PC值递增,准备取下一条指令。
(2)译码:对指令进行译码,依据译码结果,从32个通用寄存器中取出源操作数,有的 指令要求两个源操作数都是寄存器的值,比如or指令,有的指令要求其中一 个源操作数是指令中立即数的扩展,比如ori指令,所以这里有两个复用器, 用于依据指令要求,确定参与运算的操作数,最终确定的两个操作数会送到执 行阶段。
(3)执行:依据译码阶段送入的源操作数、操作码,进行运算,对于ori指令而言, 就是进行逻辑“或”运算,运算结果传递到访存阶段。
(4)访存:对于ori指令,在访存阶段没有任何操作,直接将运算结果向下传递到回写阶 段。
(5)回写:将运算结果保存到目的寄存器。
指令执行周期

指令类别 指令名 周期
除法指令 div,divu 36
乘累加指令 madd,maddu 2
乘累减指令 msub,msubu 2
其余指令 1

设计内容

【使用verilog、五级流水和MIPS指令集设计CPU】_第1张图片

(1)取指阶段
PC模块;给出指令地址,其中实现指令指针寄存器PC,该寄存器的值就是指令地址,
对应 pc_reg.v文件。
IF/ID模块:实现取指与译码阶段之间的寄存器,将取指阶段的结果(取得的指令、 指令地址等信息)在下一个时钟传递到译码阶段,对应if_id.v文件。
(2)译码阶段
ID模块:对指令进行译码,译码结果包括运算类型、运算所需的源操作数、要 写入的目的寄存器地址等,对应 idv文件。
Regfile模块:实现了32个32位通用整数寄存器,可以同时进行两个寄存器的读操 作和一个寄存器的写操作,对应Regfile.v文件。
ID/EX模块:实现译码与执行阶段之间的寄存器,将译码阶段的结果在下一个时钟周 期传递到执行阶段,对应 id_ex.v。
(3)执行阶段
EX模块:依据译码阶段的结果,进行指定的运算,给出运算结果。对应.ex.v文件。 DIV模块:进行除法运算的模块,对应 div.v文件。
EX/MEM 模块:实现执行与访存阶段之间的寄存器,将执行阶段的结果在下一个时 钟周期传递到访存阶段,对应 ex_mem.v文件。
(4)访存阶段
MEM模块:如果是加载、存储指令,那么会对数据存储器进行访问。此外,还会在 该模块进行异常判断。对应mem.v文件。
MEM/WB模块:实现访存与回写阶段之间的寄存器,将访存阶段的结果在下一个时 钟周期传递到回写阶段,对应mem_wb.v文件。
(5)回写阶段
HILO模块:实现寄存器 HI、LO,在乘法、除法指令的处理过程中会使用到这两个 寄存器。

设计处理器的结构和方法

1.ctrl 模块定义
【使用verilog、五级流水和MIPS指令集设计CPU】_第2张图片
2.data_ram模块定义
【使用verilog、五级流水和MIPS指令集设计CPU】_第3张图片
3.div模块定义
【使用verilog、五级流水和MIPS指令集设计CPU】_第4张图片
【使用verilog、五级流水和MIPS指令集设计CPU】_第5张图片
4.ex模块定义
【使用verilog、五级流水和MIPS指令集设计CPU】_第6张图片
【使用verilog、五级流水和MIPS指令集设计CPU】_第7张图片
5.ex_mem模块定义
【使用verilog、五级流水和MIPS指令集设计CPU】_第8张图片
6.hilo_reg模块定义
【使用verilog、五级流水和MIPS指令集设计CPU】_第9张图片
7.id模块定义
【使用verilog、五级流水和MIPS指令集设计CPU】_第10张图片
【使用verilog、五级流水和MIPS指令集设计CPU】_第11张图片
8.id_ex模块定义
【使用verilog、五级流水和MIPS指令集设计CPU】_第12张图片
【使用verilog、五级流水和MIPS指令集设计CPU】_第13张图片
9.if_id模块定义
【使用verilog、五级流水和MIPS指令集设计CPU】_第14张图片
10.inst_rom模块定义
【使用verilog、五级流水和MIPS指令集设计CPU】_第15张图片
11.mem模块定义
【使用verilog、五级流水和MIPS指令集设计CPU】_第16张图片
12.mem_wb模块定义
【使用verilog、五级流水和MIPS指令集设计CPU】_第17张图片
13.openmips模块定义
【使用verilog、五级流水和MIPS指令集设计CPU】_第18张图片
14.openmips_min_sopc模块定义
【使用verilog、五级流水和MIPS指令集设计CPU】_第19张图片
15.pc_reg模块定义
【使用verilog、五级流水和MIPS指令集设计CPU】_第20张图片
16.Regfile模块定义
【使用verilog、五级流水和MIPS指令集设计CPU】_第21张图片

处理器的操作过程

  1. 逻辑以及移位指令操作过程
    【使用verilog、五级流水和MIPS指令集设计CPU】_第22张图片
    逻辑以及移位指令结构图

    【使用verilog、五级流水和MIPS指令集设计CPU】_第23张图片
    逻辑以及移位指令数据流图

  2. 移动指令操作过程
    【使用verilog、五级流水和MIPS指令集设计CPU】_第24张图片
    移动指令结构图

【使用verilog、五级流水和MIPS指令集设计CPU】_第25张图片
移动指令数据流图

  1. 算术指令操作过程

【使用verilog、五级流水和MIPS指令集设计CPU】_第26张图片

算术指令数据流图

【使用verilog、五级流水和MIPS指令集设计CPU】_第27张图片

除法状态转换图

【使用verilog、五级流水和MIPS指令集设计CPU】_第28张图片

试除法流程图

【使用verilog、五级流水和MIPS指令集设计CPU】_第29张图片

暂停流水结构图
  1. 转移指令操作过程
    【使用verilog、五级流水和MIPS指令集设计CPU】_第30张图片

    转移指令结构图

【使用verilog、五级流水和MIPS指令集设计CPU】_第31张图片

转移指令数据流图 
  1. 加载存储指令

【使用verilog、五级流水和MIPS指令集设计CPU】_第32张图片

加载存储指令结构图 

【使用verilog、五级流水和MIPS指令集设计CPU】_第33张图片

加载存储指令数据流图 

代码

  1. pc_reg 模块
`include"defines.v"
module pc_reg(
input wire  clk,
input wire  rst,
input wire[5:0] stall,//来自控制模块的ctrl
input wire  branch_flag_i,
input wire[`RegBus]  branch_target_address_i,
output  reg[`InstAddrBus] pc,
output  reg ce
    );
    always @ (posedge clk)begin
        if (rst == `RstEnable)begin
            ce <= `ChipDisable;
        end else begin
            ce <= `ChipEnable;
        end
    end
    always @ (posedge clk) begin
        if (ce == `ChipDisable) begin
            pc <= 32'h0;//
        end else if(stall[0] == `NoStop) begin
            if(branch_flag_i == `Branch)begin
                pc <= branch_target_address_i;
             end else begin
                  pc <= pc + 4'h4;
              end
        end
    end
endmodule
  1. if_id 模块
`include"defines.v"
module if_id(
input  wire clk,
input  wire rst,
input wire[5:0] stall,
// 来自取指阶段的信号,其中宏定义InstBus表示指令宽度,为32
input wire[`InstAddrBus] if_pc,
input wire[`InstBus]     if_inst,
//对应译码阶段的信号
output reg[`InstAddrBus] id_pc,
output reg[`InstBus]     id_inst
    );
    always @ (posedge clk)begin
        if(rst == `RstEnable) begin
            id_pc <= `ZeroWord; // 复位的时候pc为0
            id_inst <= `ZeroWord;// 复位的时候指令也为0.实际就是空指令
        end else if(stall[1] == `Stop && stall[2] == `NoStop) begin
             id_pc <= `ZeroWord; 
            id_inst <= `ZeroWord;
        end else if(stall[1] == `NoStop) begin
            id_pc <= if_pc;     //其余时刻向下传递取指令阶段的值
            id_inst <= if_inst;
        end
    end
endmodule
  1. Regfile 模块
`include"defines.v"
module Regfile(
    input wire clk,
    input wire  rst,
    //写端口
    input wire              we,
    input wire[`RegAddrBus] waddr,
    input wire[`RegBus]     wdata,
    //读端口
    input wire              re1,
    input wire[`RegAddrBus]raddr1,
    output reg[`RegBus]    rdata1,
    //读端口
    input wire              re2,
    input wire[`RegAddrBus] raddr2,
    output  reg[`RegBus]    rdata2
    );
    
    /**********************************************  第一段  : 定义32个32位寄存器       *************************/
    reg[`RegBus] regs[0:`RegNum-1];
    /**********************************************  第二段 : 写操作                    *************************/
    always @ (posedge clk) begin
        if (rst == `RstDisable)begin
            if((we == `WriteEnable) && (waddr != `RegNumLog2'h0))begin
                regs[waddr] <= wdata;
            end
        end
    end
    /********************************************** 第三段 : 读端口1的读操作           **************************/
    always @ (*) begin
        if(rst == `RstEnable)begin
            rdata1 <= `ZeroWord;
        end else if(raddr1 == `RegNumLog2'h0)begin
            rdata1 <= `ZeroWord;
        end else if((raddr1 == waddr) && (we == `WriteEnable) && (re1 == `ReadEnable)) begin
            rdata1 <= wdata;
        end else if(re1 == `ReadEnable)begin
            rdata1 <= regs[raddr1];
        end else begin
            rdata1 <= `ZeroWord;
        end
    end
    /********************************************** 第四段 : 读端口2的读操作             ***************************/
    always @ (*) begin
        if(rst == `RstEnable) begin
            rdata2 <= `ZeroWord;
        end else if(raddr2 == `RegNumLog2'h0)begin
            rdata2 <= `ZeroWord;
        end else if((raddr2 == waddr) && (we == `WriteEnable) && (re2 == `ReadEnable))begin
            rdata2 <= wdata;
        end else if(re2 == `ReadEnable)begin
            rdata2 <= regs[raddr2];
        end else begin
            rdata2 <= `ZeroWord;
        end
     end
endmodule
  1. if_id 模块
include"defines.v"
module if_id(
input  wire clk,
input  wire rst,
input wire[5:0] stall,
// 来自取指阶段的信号,其中宏定义InstBus表示指令宽度,为32
input wire[`InstAddrBus] if_pc,
input wire[`InstBus]     if_inst,
//对应译码阶段的信号
output reg[`InstAddrBus] id_pc,
output reg[`InstBus]     id_inst
    );
    always @ (posedge clk)begin
        if(rst == `RstEnable) begin
            id_pc <= `ZeroWord; // 复位的时候pc为0
            id_inst <= `ZeroWord;// 复位的时候指令也为0.实际就是空指令
        end else if(stall[1] == `Stop && stall[2] == `NoStop) begin
             id_pc <= `ZeroWord; 
            id_inst <= `ZeroWord;
        end else if(stall[1] == `NoStop) begin
            id_pc <= if_pc;     //其余时刻向下传递取指令阶段的值
            id_inst <= if_inst;
        end
    end
endmodule
  1. id 模块
`include"defines.v"
 module id(
    input   wire    rst,
    input   wire[`InstAddrBus]  pc_i,
    input   wire[`InstBus]  inst_i,
    // 时延
    input   wire        is_in_delayslot_i,
    
    // 读取的RegFile的值
    input wire[`RegBus] reg1_data_i,
    input wire[`RegBus] reg2_data_i,
    //输出到Regfile的信息
    output reg          reg1_read_0,
    output reg          reg2_read_0,
    output reg[`RegAddrBus] reg1_addr_0,
    output reg[`RegAddrBus] reg2_addr_0,
    
    //处于执行阶段的指令的运算结果
    input wire ex_wreg_i,
    input wire[`RegBus] ex_wdata_i,
    input wire[`RegAddrBus] ex_wd_i,
    
    //处于访存阶段的指令的运算结果
    input wire  mem_wreg_i,
    input wire[`RegBus]  mem_wdata_i,
    input wire[`RegAddrBus]  mem_wd_i,
    // 分支时延
    output  reg             next_inst_in_delayslot_0,
    
    output  reg             branch_flag_0,
    output  reg[`RegBus]    branch_target_address_0,
    output  reg[`RegBus]    link_addr_0,
    output  reg             is_in_delayslot_0,
    
    //送到执行阶段的信息
    output  reg[`AluOpBus] aluop_0,
    output  reg[`AluSelBus] alusel_0,
    output  reg[`RegBus]    reg1_0,
    output  reg[`RegBus]    reg2_0,
    output  reg[`RegAddrBus]wd_0,
    output  reg             wreg_0,

    output wire              stallreq,
    output wire[`RegBus]    inst_0
    );
    //取指令的指令码,功能码
    wire[5:0] op = inst_i[31:26];
    wire[4:0] op2 = inst_i[10:6];
    wire[5:0] op3 = inst_i[5:0];
    wire[4:0] op4 = inst_i[20:16];
    
    
    wire[`RegBus]   pc_plus_8;
    wire[`RegBus]   pc_plus_4;
    
    wire[`RegBus]   imm_sll2_signedext;
    //指示指令是否有效
    reg instvalid;
    //保存指令执行需要的立即数
    reg[`RegBus] imm;
    assign  pc_plus_8 =  pc_i + 8;
    assign  pc_plus_4 =  pc_i + 4;
    //对应分支指令中的offset左移两位,再符号拓展到32位
    assign  imm_sll2_signedext = {{14{inst_i[15]}}, inst_i[15:0],2'b00};
    
    assign stallreq = `NoStop;
    
    assign  inst_0  = inst_i; // inst_0的值就是译码阶段的指令
    /************************** 第一段: 对指令进行译码   **************************************/
    always @ (*) begin
        if(rst == `RstEnable) begin
            aluop_0 <= `EXE_NOP_OP;
            alusel_0 <= `EXE_RES_NOP;
            wd_0 <= `NOPRegAddr;
            wreg_0 <= `WriteDisable;
            instvalid <= `InstValid;
            reg1_read_0 <= 1'b0;
            reg2_read_0 <= 1'b0;
            reg1_addr_0 <= `NOPRegAddr;
            reg2_addr_0 <= `NOPRegAddr;
            imm <= 32'h0;
            link_addr_0 <=  `ZeroWord;
            branch_target_address_0 <= `ZeroWord;
            branch_flag_0   <=  `NotBranch;
            next_inst_in_delayslot_0    <= `NotInDelaySlot;
       end else begin
            aluop_0 <= `EXE_NOP_OP;
            alusel_0 <= `EXE_RES_NOP;
            wd_0 <= inst_i[15:11];
            wreg_0 <= `WriteDisable;
            instvalid <= `InstInvalid;
            reg1_read_0 <= 1'b0;
            reg2_read_0 <= 1'b0;
            reg1_addr_0 <= inst_i[25:21];  // 默认通过 Regfile 读端口1读取的寄存器地址
            reg2_addr_0 <= inst_i[20:16];  // 默认通过 Regfile 读端口2读取的寄存器地址
            imm <= `ZeroWord;
            link_addr_0 <=  `ZeroWord;
            branch_target_address_0 <= `ZeroWord;
            branch_flag_0   <=  `NotBranch;
            next_inst_in_delayslot_0    <= `NotInDelaySlot;
            case(op)
                `EXE_SPECIAL_INST:begin
                    case(op2)
                        5'b00000:begin
                            case(op3)
                                `EXE_OR:begin
                                    wreg_0 <= `WriteEnable;
                                    aluop_0 <= `EXE_OR_OP;
                                    alusel_0 <= `EXE_RES_LOGIC;
                                    reg1_read_0 <= 1'b1;
                                    reg2_read_0 <= 1'b1;
                                    instvalid <= `InstValid;
                                    end
                                    `EXE_AND:begin
                                    wreg_0 <= `WriteEnable;
                                    aluop_0 <= `EXE_AND_OP;
                                    alusel_0 <= `EXE_RES_LOGIC;
                                    reg1_read_0 <= 1'b1;
                                    reg2_read_0 <= 1'b1;
                                    instvalid <= `InstValid;
                                    end
                                    `EXE_XOR:begin
                                     wreg_0 <= `WriteEnable;
                                     aluop_0 <= `EXE_XOR_OP;
                                     alusel_0 <= `EXE_RES_LOGIC;
                                     reg1_read_0 <= 1'b1;
                                     reg2_read_0 <= 1'b1;
                                     instvalid <= `InstValid;
                                     end
                                     `EXE_NOR:begin
                                     wreg_0 <= `WriteEnable;
                                     aluop_0 <= `EXE_NOR_OP;
                                     alusel_0 <= `EXE_RES_LOGIC;
                                     reg1_read_0 <= 1'b1;
                                     reg2_read_0 <= 1'b1;
                                     instvalid <= `InstValid;
                                     end
                                     `EXE_DIV:begin
                                     wreg_0 <= `WriteDisable;
                                     aluop_0 <= `EXE_DIV_OP;
                                     reg1_read_0 <= 1'b1;
                                     reg2_read_0 <= 1'b1;
                                     instvalid  <= `InstValid;
                                     end
                                     `EXE_DIVU:begin
                                      wreg_0 <= `WriteDisable;
                                     aluop_0 <= `EXE_DIVU_OP;
                                     reg1_read_0 <= 1'b1;
                                     reg2_read_0 <= 1'b1;
                                     instvalid  <= `InstValid;
                                     end
                                     `EXE_JR:begin
                                     wreg_0     <=  `WriteDisable;
                                     aluop_0    <=  `EXE_JR_OP;
                                     alusel_0   <=  `EXE_RES_JUMP_BRANCH;
                                     reg1_read_0  <=    1'b1;
                                     reg2_read_0  <=    1'b0;
                                     link_addr_0    <=  `ZeroWord;
                                     branch_target_address_0    <= reg1_0;
                                     branch_flag_0  <= `Branch;
                                     next_inst_in_delayslot_0   <= `InDelaySlot;
                                     instvalid         <=   `InstValid;
                                     end
                                     `EXE_JALR:begin
                                     wreg_0     <=  `WriteEnable;
                                     aluop_0    <=  `EXE_JALR_OP;
                                     alusel_0   <=  `EXE_RES_JUMP_BRANCH;
                                     reg1_read_0  <=    1'b1;
                                     reg2_read_0  <=    1'b0;
                                     wd_0         <=    inst_i[15:11];
                                     link_addr_0    <=  pc_plus_8;
                                     branch_target_address_0    <= reg1_0;
                                     branch_flag_0  <= `Branch;
                                     next_inst_in_delayslot_0   <= `InDelaySlot;
                                     instvalid         <=   `InstValid;
                                     end
                                     `EXE_SLLV:begin
                                     wreg_0 <= `WriteEnable;
                                     aluop_0 <= `EXE_SLL_OP;
                                     alusel_0 <= `EXE_RES_SHIFT;
                                     reg1_read_0 <= 1'b1;
                                     reg2_read_0 <= 1'b1;
                                     instvalid <= `InstValid;
                                     end
                                    `EXE_SRLV:begin
                                     wreg_0 <= `WriteEnable;
                                     aluop_0 <= `EXE_SRL_OP;
                                     alusel_0 <= `EXE_RES_SHIFT;
                                     reg1_read_0 <= 1'b1;
                                     reg2_read_0 <= 1'b1;
                                     instvalid <= `InstValid;
                                     end
                                     `EXE_SRAV:begin
                                     wreg_0 <= `WriteEnable;
                                     aluop_0 <= `EXE_SRA_OP;
                                     alusel_0 <= `EXE_RES_SHIFT;
                                     reg1_read_0 <= 1'b1;
                                     reg2_read_0 <= 1'b1;
                                     instvalid <= `InstValid;
                                     end
                                     `EXE_SYNC:begin
                                     wreg_0 <= `WriteEnable;
                                     aluop_0 <= `EXE_NOP_OP;
                                     alusel_0 <= `EXE_RES_NOP;
                                     reg1_read_0 <= 1'b0;
                                     reg2_read_0 <= 1'b1;
                                     instvalid <= `InstValid;
                                     end
                                     `EXE_MFHI:begin
                                     wreg_0 <= `WriteEnable;
                                     aluop_0 <= `EXE_MFHI_OP;
                                     alusel_0 <= `EXE_RES_MOVE;
                                     reg1_read_0 <= 1'b0;
                                     reg2_read_0 <= 1'b0;
                                     instvalid <= `InstValid;
                                     end
                                     `EXE_MFLO:begin
                                     wreg_0 <= `WriteEnable;
                                     aluop_0 <= `EXE_MFLO_OP;
                                     alusel_0 <= `EXE_RES_MOVE;
                                     reg1_read_0 <= 1'b0;
                                     reg2_read_0 <= 1'b0;
                                     instvalid <= `InstValid;                                     
                                     end
                                     `EXE_MTHI:begin
                                     wreg_0 <= `WriteEnable;
                                     aluop_0 <= `EXE_MTHI_OP;
                                     reg1_read_0 <= 1'b1;
                                     reg2_read_0 <= 1'b0;
                                     instvalid <= `InstValid;                                     
                                     end
                                     `EXE_MTLO:begin
                                     wreg_0 <= `WriteEnable;
                                     aluop_0 <= `EXE_MTLO_OP;
                                     reg1_read_0 <= 1'b1;
                                     reg2_read_0 <= 1'b0;
                                     instvalid <= `InstValid;                                    
                                     end
                                     `EXE_MOVN:begin
                                     aluop_0 <= `EXE_MOVN_OP;
                                     alusel_0 <= `EXE_RES_MOVE;
                                     reg1_read_0 <= 1'b1;
                                     reg2_read_0 <= 1'b1;
                                     instvalid <= `InstValid;
                                     if(reg2_0!=`ZeroWord)begin
                                        wreg_0 <= `WriteEnable;
                                     end else begin
                                        wreg_0 <= `WriteDisable;
                                        end
                                     end
                                     `EXE_MOVZ:begin
                                     aluop_0 <= `EXE_MOVZ_OP;
                                     alusel_0 <= `EXE_RES_MOVE;
                                     reg1_read_0 <= 1'b1;
                                     reg2_read_0 <= 1'b1;
                                     instvalid <= `InstValid; 
                                     if(reg2_0==`ZeroWord)begin
                                        wreg_0 <= `WriteEnable;
                                     end else begin
                                        wreg_0 <= `WriteDisable;
                                        end                                                                         
                                     end
                                     `EXE_SLT:begin
                                        wreg_0 <= `WriteEnable;
                                        aluop_0 <= `EXE_SLT_OP;
                                        alusel_0 <= `EXE_RES_ARITHMETIC;
                                        reg1_read_0 <= 1'b1;
                                        reg2_read_0 <= 1'b1;
                                        instvalid <= `InstValid;
                                     end
                                     `EXE_SLTU:begin
                                        wreg_0 <= `WriteEnable;
                                        aluop_0 <= `EXE_SLTU_OP;
                                        alusel_0 <= `EXE_RES_ARITHMETIC;
                                        reg1_read_0 <= 1'b1;
                                        reg2_read_0 <= 1'b1;
                                        instvalid <= `InstValid;
                                     end
                                     `EXE_ADD:begin
                                        wreg_0 <= `WriteEnable;
                                        aluop_0 <= `EXE_ADD_OP;
                                        alusel_0 <= `EXE_RES_ARITHMETIC;
                                        reg1_read_0 <= 1'b1;
                                        reg2_read_0 <= 1'b1;
                                        instvalid <= `InstValid;
                                     end
                                     `EXE_ADDU:begin
                                        wreg_0 <= `WriteEnable;
                                        aluop_0 <= `EXE_ADDU_OP;
                                        alusel_0 <= `EXE_RES_ARITHMETIC;
                                        reg1_read_0 <= 1'b1;
                                        reg2_read_0 <= 1'b1;
                                        instvalid <= `InstValid;
                                     end
                                     `EXE_SUB:begin
                                        wreg_0 <= `WriteEnable;
                                        aluop_0 <= `EXE_SUB_OP;
                                        alusel_0 <= `EXE_RES_ARITHMETIC;
                                        reg1_read_0 <= 1'b1;
                                        reg2_read_0 <= 1'b1;
                                        instvalid <= `InstValid;
                                     end
                                     `EXE_SUBU:begin
                                        wreg_0 <= `WriteEnable;
                                        aluop_0 <= `EXE_SUBU_OP;
                                        alusel_0 <= `EXE_RES_ARITHMETIC;
                                        reg1_read_0 <= 1'b1;
                                        reg2_read_0 <= 1'b1;
                                        instvalid <= `InstValid;
                                     end
                                     `EXE_MULT:begin
                                        wreg_0 <= `WriteEnable;
                                        aluop_0 <= `EXE_MULT_OP;
                                        reg1_read_0 <= 1'b1;
                                        reg2_read_0 <= 1'b1;
                                        instvalid <= `InstValid;
                                     end
                                     `EXE_MULTU:begin
                                        wreg_0 <= `WriteEnable;
                                        aluop_0 <= `EXE_MULTU_OP;
                                        reg1_read_0 <= 1'b1;
                                        reg2_read_0 <= 1'b1;
                                        instvalid <= `InstValid;
                                     end
                                     default:begin
                                     end
                                  endcase
                                end
                          default:begin
                          end
                  endcase
                end
                `EXE_J:begin
                    wreg_0  <=  `WriteDisable;
                    aluop_0  <= `EXE_J_OP;
                    alusel_0    <= `EXE_RES_JUMP_BRANCH;
                    reg1_read_0 <=  1'b0;
                    reg2_read_0 <=  1'b0;
                    link_addr_0 <=  `ZeroWord;
                    branch_flag_0  <=   `Branch;
                    next_inst_in_delayslot_0 <= `InDelaySlot;
                    instvalid       <=  `InstValid;
                    branch_target_address_0 <= {pc_plus_4[31:28],inst_i[25:0],2'b00};
                end
                `EXE_JAL:begin
                    wreg_0  <=  `WriteEnable;
                    aluop_0  <= `EXE_JAL_OP;
                    alusel_0    <= `EXE_RES_JUMP_BRANCH;
                    reg1_read_0 <=  1'b0;
                    reg2_read_0 <=  1'b0;
                    wd_0        <=  5'b11111;
                    link_addr_0 <=  pc_plus_8;
                    branch_flag_0  <=   `Branch;
                    next_inst_in_delayslot_0 <= `InDelaySlot;
                    instvalid       <=  `InstValid;
                    branch_target_address_0 <= {pc_plus_4[31:28],inst_i[25:0],2'b00};
                end
                `EXE_BEQ:begin
                    wreg_0  <=  `WriteDisable;
                    aluop_0  <= `EXE_BEQ_OP;
                    alusel_0    <= `EXE_RES_JUMP_BRANCH;
                    reg1_read_0 <=  1'b1;
                    reg2_read_0 <=  1'b1;
                    instvalid       <=  `InstValid;
                    if(reg1_0 == reg2_0)begin
                        branch_target_address_0     <=  pc_plus_4 + imm_sll2_signedext;
                        branch_flag_0   <=  `Branch;
                        next_inst_in_delayslot_0 <= `InDelaySlot;
                    end
                end
                `EXE_BGTZ:begin
                    wreg_0  <=  `WriteDisable;
                    aluop_0  <= `EXE_BGTZ_OP;
                    alusel_0    <= `EXE_RES_JUMP_BRANCH;
                    reg1_read_0 <=  1'b1;
                    reg2_read_0 <=  1'b0;
                    instvalid       <=  `InstValid;
                    if((reg1_0[31] == 1'b0) && (reg1_0 != `ZeroWord))begin
                        branch_target_address_0     <=  pc_plus_4 + imm_sll2_signedext;
                        branch_flag_0   <=  `Branch;
                        next_inst_in_delayslot_0 <= `InDelaySlot;
                    end
                end
                `EXE_BLEZ:begin
                    wreg_0  <=  `WriteDisable;
                    aluop_0  <= `EXE_BLEZ_OP;
                    alusel_0    <= `EXE_RES_JUMP_BRANCH;
                    reg1_read_0 <=  1'b1;
                    reg2_read_0 <=  1'b0;
                    instvalid       <=  `InstValid;
                    if((reg1_0[31] == 1'b1) || (reg1_0 == `ZeroWord))begin
                        branch_target_address_0     <=  pc_plus_4 + imm_sll2_signedext;
                        branch_flag_0   <=  `Branch;
                        next_inst_in_delayslot_0 <= `InDelaySlot;
                    end
                end
                `EXE_BNE:begin
                    wreg_0  <=  `WriteDisable;
                    aluop_0  <= `EXE_BLEZ_OP;
                    alusel_0    <= `EXE_RES_JUMP_BRANCH;
                    reg1_read_0 <=  1'b1;
                    reg2_read_0 <=  1'b1;
                    instvalid       <=  `InstValid;
                    if(reg1_0 != reg2_0)begin
                        branch_target_address_0     <=  pc_plus_4 + imm_sll2_signedext;
                        branch_flag_0   <=  `Branch;
                        next_inst_in_delayslot_0 <= `InDelaySlot;
                    end
                end
                `EXE_REGIMM_INST:begin
                    case(op4)
                    `EXE_BGEZ:begin
                        wreg_0  <=  `WriteDisable;
                        aluop_0  <= `EXE_BGEZ_OP;
                        alusel_0    <= `EXE_RES_JUMP_BRANCH;
                        reg1_read_0 <=  1'b1;
                        reg2_read_0 <=  1'b0;
                        instvalid       <=  `InstValid;
                        if(reg1_0[31] == 1'b0)begin
                            branch_target_address_0     <=  pc_plus_4 + imm_sll2_signedext;
                            branch_flag_0   <=  `Branch;
                            next_inst_in_delayslot_0 <= `InDelaySlot;
                        end
                    end
                    `EXE_BGEZAL:begin
                        wreg_0  <=  `WriteEnable;
                        aluop_0  <= `EXE_BGEZAL_OP;
                        alusel_0    <= `EXE_RES_JUMP_BRANCH;
                        reg1_read_0 <=  1'b1;
                        reg2_read_0 <=  1'b0;
                        link_addr_0 <=  pc_plus_8;
                        wd_0    <=  5'b11111;
                        instvalid       <=  `InstValid;
                        if(reg1_0[31] == 1'b0)begin
                            branch_target_address_0     <=  pc_plus_4 + imm_sll2_signedext;
                            branch_flag_0   <=  `Branch;
                            next_inst_in_delayslot_0 <= `InDelaySlot;
                        end
                    end
                    `EXE_BLTZ:begin
                        wreg_0  <=  `WriteDisable;
                        aluop_0  <= `EXE_BGEZAL_OP;
                        alusel_0    <= `EXE_RES_JUMP_BRANCH;
                        reg1_read_0 <=  1'b1;
                        reg2_read_0 <=  1'b0;
                        instvalid       <=  `InstValid;
                        if(reg1_0[31] == 1'b1)begin
                            branch_target_address_0     <=  pc_plus_4 + imm_sll2_signedext;
                            branch_flag_0   <=  `Branch;
                            next_inst_in_delayslot_0 <= `InDelaySlot;
                        end
                    end
                    `EXE_BLTZAL:begin
                        wreg_0  <=  `WriteEnable;
                        aluop_0  <= `EXE_BGEZAL_OP;
                        alusel_0    <= `EXE_RES_JUMP_BRANCH;
                        reg1_read_0 <=  1'b1;
                        reg2_read_0 <=  1'b0;
                        link_addr_0 <=  pc_plus_8;
                        wd_0    <=  5'b11111;
                        instvalid       <=  `InstValid;
                        if(reg1_0[31] == 1'b1)begin
                            branch_target_address_0     <=  pc_plus_4 + imm_sll2_signedext;
                            branch_flag_0   <=  `Branch;
                            next_inst_in_delayslot_0 <= `InDelaySlot;
                        end
                     end
                     default:begin
                     end
                    endcase
                end
                `EXE_LB: begin
                 wreg_0 <=  `WriteEnable;
                 aluop_0    <=  `EXE_LB_OP;
                 alusel_0   <=  `EXE_RES_LOAD_STORE;
                 reg1_read_0 <= 1'b1;
                 reg2_read_0 <= 1'b0;
                 wd_0   <=  inst_i[20:16];
                 instvalid  <=   `InstValid;
                end
                `EXE_LBU:begin
                 wreg_0 <=  `WriteEnable;
                 aluop_0    <=  `EXE_LBU_OP;
                 alusel_0   <=  `EXE_RES_LOAD_STORE;
                 reg1_read_0 <= 1'b1;
                 reg2_read_0 <= 1'b0;
                 wd_0   <=  inst_i[20:16];
                 instvalid  <=   `InstValid;
                end
                `EXE_LH:begin
                 wreg_0 <=  `WriteEnable;
                 aluop_0    <=  `EXE_LH_OP;
                 alusel_0   <=  `EXE_RES_LOAD_STORE;
                 reg1_read_0 <= 1'b1;
                 reg2_read_0 <= 1'b0;
                 wd_0   <=  inst_i[20:16];
                 instvalid  <=   `InstValid;
                end
                `EXE_LHU:begin
                 wreg_0 <=  `WriteEnable;
                 aluop_0    <=  `EXE_LHU_OP;
                 alusel_0   <=  `EXE_RES_LOAD_STORE;
                 reg1_read_0 <= 1'b1;
                 reg2_read_0 <= 1'b0;
                 wd_0   <=  inst_i[20:16];
                 instvalid  <=   `InstValid;
                end
                `EXE_LW:begin
                 wreg_0 <=  `WriteEnable;
                 aluop_0    <=  `EXE_LW_OP;
                 alusel_0   <=  `EXE_RES_LOAD_STORE;
                 reg1_read_0 <= 1'b1;
                 reg2_read_0 <= 1'b0;
                 wd_0   <=  inst_i[20:16];
                 instvalid  <=   `InstValid;
                end
                `EXE_LWL:begin
                 wreg_0 <=  `WriteEnable;
                 aluop_0    <=  `EXE_LWL_OP;
                 alusel_0   <=  `EXE_RES_LOAD_STORE;
                 reg1_read_0 <= 1'b1;
                 reg2_read_0 <= 1'b1;
                 wd_0   <=  inst_i[20:16];
                 instvalid  <=   `InstValid;
                end
                `EXE_LWR:begin
                 wreg_0 <=  `WriteEnable;
                 aluop_0    <=  `EXE_LWR_OP;
                 alusel_0   <=  `EXE_RES_LOAD_STORE;
                 reg1_read_0 <= 1'b1;
                 reg2_read_0 <= 1'b1;
                 wd_0   <=  inst_i[20:16];
                 instvalid  <=   `InstValid;
                end
                `EXE_SB:begin
                 wreg_0 <=  `WriteDisable;
                 aluop_0    <=  `EXE_SB_OP;
                 alusel_0   <=  `EXE_RES_LOAD_STORE;
                 reg1_read_0 <= 1'b1;
                 reg2_read_0 <= 1'b1;
                 instvalid  <=   `InstValid;
                end
                `EXE_SH:begin
                 wreg_0 <=  `WriteDisable;
                 aluop_0    <=  `EXE_SH_OP;
                 alusel_0   <=  `EXE_RES_LOAD_STORE;
                 reg1_read_0 <= 1'b1;
                 reg2_read_0 <= 1'b1;
                 instvalid  <=   `InstValid;
                end
                `EXE_SW:begin
                 wreg_0 <=  `WriteDisable;
                 aluop_0    <=  `EXE_SW_OP;
                 alusel_0   <=  `EXE_RES_LOAD_STORE;
                 reg1_read_0 <= 1'b1;
                 reg2_read_0 <= 1'b1;
                 instvalid  <=   `InstValid;
                end
                `EXE_SWL:begin
                 wreg_0 <=  `WriteDisable;
                 aluop_0    <=  `EXE_SWL_OP;
                 alusel_0   <=  `EXE_RES_LOAD_STORE;
                 reg1_read_0 <= 1'b1;
                 reg2_read_0 <= 1'b1;
                 instvalid  <=   `InstValid;
                end
                `EXE_SWR:begin
                 wreg_0 <=  `WriteDisable;
                 aluop_0    <=  `EXE_SWR_OP;
                 alusel_0   <=  `EXE_RES_LOAD_STORE;
                 reg1_read_0 <= 1'b1;
                 reg2_read_0 <= 1'b1;
                 instvalid  <=   `InstValid;
                end
                `EXE_ORI:begin 
                wreg_0 <=`WriteEnable;
                aluop_0 <=`EXE_OR_OP;
                alusel_0 <=`EXE_RES_LOGIC;
                reg1_read_0 <= 1'b1;
                reg2_read_0 <= 1'b0;
                imm <= {16'h0,inst_i[15:0]};
                wd_0 <= inst_i[20:16];
                instvalid <= `InstValid;
                end
                `EXE_ANDI:begin
                wreg_0 <=`WriteEnable;
                aluop_0 <=`EXE_AND_OP;
                alusel_0 <=`EXE_RES_LOGIC;
                reg1_read_0 <= 1'b1;
                reg2_read_0 <= 1'b0;
                imm <= {16'h0,inst_i[15:0]};
                wd_0 <= inst_i[20:16];
                instvalid <= `InstValid;    
                end
                `EXE_XORI:begin
                wreg_0 <=`WriteEnable;
                aluop_0 <=`EXE_XOR_OP;
                alusel_0 <=`EXE_RES_LOGIC;
                reg1_read_0 <= 1'b1;
                reg2_read_0 <= 1'b0;
                imm <= {16'h0,inst_i[15:0]};
                wd_0 <= inst_i[20:16];
                instvalid <= `InstValid;    
                end
                `EXE_LUI:begin
                wreg_0 <=`WriteEnable;
                aluop_0 <=`EXE_OR_OP;
                alusel_0 <=`EXE_RES_LOGIC;
                reg1_read_0 <= 1'b1;
                reg2_read_0 <= 1'b0;
                imm <= {inst_i[15:0],16'h0};
                wd_0 <= inst_i[20:16];
                instvalid <= `InstValid;    
                end
                `EXE_PREF:begin
                wreg_0 <=`WriteEnable;
                aluop_0 <=`EXE_NOP_OP;
                alusel_0 <=`EXE_RES_NOP;
                reg1_read_0 <= 1'b0;
                reg2_read_0 <= 1'b0;
                instvalid <= `InstValid;    
                end
                `EXE_SLTI:begin
                 wreg_0 <= `WriteEnable;
                 aluop_0 <= `EXE_SLT_OP;
                 alusel_0 <= `EXE_RES_ARITHMETIC;
                 reg1_read_0 <= 1'b1;
                 reg2_read_0 <= 1'b0;
                 imm        <= {{16{inst_i[15]}},inst_i[15:0]};
                 wd_0       <= inst_i[20:16];
                 instvalid <= `InstValid;
                end
                `EXE_SLTIU:begin
                 wreg_0 <= `WriteEnable;
                 aluop_0 <= `EXE_SLTU_OP;
                 alusel_0 <= `EXE_RES_ARITHMETIC;
                 reg1_read_0 <= 1'b1;
                 reg2_read_0 <= 1'b0;
                 imm         <= {{16{inst_i[15]}},inst_i[15:0]};
                 wd_0        <= inst_i[20:16];
                 instvalid <= `InstValid;
                end
                `EXE_ADDI:begin
                 wreg_0 <= `WriteEnable;
                 aluop_0 <= `EXE_ADDI_OP;
                 alusel_0 <= `EXE_RES_ARITHMETIC;
                 reg1_read_0 <= 1'b1;
                 reg2_read_0 <= 1'b0;
                 imm         <= {{16{inst_i[15]}},inst_i[15:0]};
                 wd_0        <= inst_i[20:16];
                 instvalid <= `InstValid;
                end
                `EXE_ADDIU:begin
                 wreg_0 <= `WriteEnable;
                 aluop_0 <= `EXE_ADDIU_OP;
                 alusel_0 <= `EXE_RES_ARITHMETIC;
                 reg1_read_0 <= 1'b1;
                 reg2_read_0 <= 1'b0;
                 imm         <= {{16{inst_i[15]}},inst_i[15:0]};
                 wd_0        <= inst_i[20:16];
                 instvalid <= `InstValid;
                end
                `EXE_SPECIAL2_INST:begin
                    case(op3)
                      `EXE_CLZ:begin
                       wreg_0 <= `WriteEnable;
                       aluop_0 <= `EXE_CLZ_OP;
                       alusel_0 <= `EXE_RES_ARITHMETIC;
                       reg1_read_0 <= 1'b1;
                       reg2_read_0 <= 1'b0;
                       instvalid <= `InstValid;
                       end
                      `EXE_CLO:begin
                       wreg_0 <= `WriteEnable;
                       aluop_0 <= `EXE_CLO_OP;
                       alusel_0 <= `EXE_RES_ARITHMETIC;
                       reg1_read_0 <= 1'b1;
                       reg2_read_0 <= 1'b0;
                       instvalid <= `InstValid;
                      end
                      `EXE_MUL:begin
                       wreg_0 <= `WriteEnable;
                       aluop_0 <= `EXE_MUL_OP;
                       alusel_0 <= `EXE_RES_MUL;
                       reg1_read_0 <= 1'b1;
                       reg2_read_0 <= 1'b1;
                       instvalid <= `InstValid;
                      end
                      `EXE_MADD:begin
                        wreg_0 <= `WriteDisable;
                        aluop_0 <= `EXE_MADD_OP;
                        alusel_0 <= `EXE_RES_MUL;
                        reg1_read_0 <= 1'b1;
                        reg2_read_0 <= 1'b1;
                        instvalid <= `InstValid;
                      end
                      `EXE_MADDU:begin
                        wreg_0 <= `WriteDisable;
                        aluop_0 <= `EXE_MADDU_OP;
                        alusel_0 <= `EXE_RES_MUL;
                        reg1_read_0 <= 1'b1;
                        reg2_read_0 <= 1'b1;
                        instvalid <= `InstValid;
                      end
                      `EXE_MSUB:begin
                        wreg_0 <= `WriteDisable;
                        aluop_0 <= `EXE_MSUB_OP;
                        alusel_0 <= `EXE_RES_MUL;
                        reg1_read_0 <= 1'b1;
                        reg2_read_0 <= 1'b1;
                        instvalid <= `InstValid;
                      end
                      `EXE_MSUBU:begin
                        wreg_0 <= `WriteDisable;
                        aluop_0 <= `EXE_MSUBU_OP;
                        alusel_0 <= `EXE_RES_MUL;
                        reg1_read_0 <= 1'b1;
                        reg2_read_0 <= 1'b1;
                        instvalid <= `InstValid;
                      end
                    default:begin
                    end
                 endcase
                end                
                default:begin
                end  
            endcase
              if(inst_i[31:21] == 11'b00000000000)begin
                if(op3 == `EXE_SLL)begin
                    wreg_0 <=`WriteEnable;
                    aluop_0 <=`EXE_SLL_OP;
                    alusel_0 <=`EXE_RES_SHIFT;
                    reg1_read_0 <= 1'b0;
                    reg2_read_0 <= 1'b1;
                    imm[4:0] <= inst_i[10:6];
                    wd_0 <= inst_i[15:11];
                    instvalid <= `InstValid;    
                end else if(op3 == `EXE_SRL) begin
                    wreg_0 <=`WriteEnable;
                    aluop_0 <=`EXE_SRL_OP;
                    alusel_0 <=`EXE_RES_SHIFT;
                    reg1_read_0 <= 1'b0;
                    reg2_read_0 <= 1'b1;
                    imm[4:0] <= inst_i[10:6];
                    wd_0 <= inst_i[15:11];
                    instvalid <= `InstValid;                  
                end else if(op3 == `EXE_SRA) begin
                    wreg_0 <=`WriteEnable;
                    aluop_0 <=`EXE_SRA_OP;
                    alusel_0 <=`EXE_RES_SHIFT;
                    reg1_read_0 <= 1'b0;
                    reg2_read_0 <= 1'b1;
                    imm[4:0] <= inst_i[10:6];
                    wd_0 <= inst_i[15:11];
                    instvalid <= `InstValid;
                    end
                 end                
            end
          end
          /**************************** 第二段: 确定进行运算的源操作数 1**************************/
          always @ (*) begin
            if(rst == `RstEnable) begin
                reg1_0 <= `ZeroWord;
            end else if((reg1_read_0 == 1'b1) && (ex_wreg_i == 1'b1) && (ex_wd_i == reg1_addr_0))begin
                reg1_0 <= ex_wdata_i;
            end else if((reg1_read_0 == 1'b1) && (mem_wreg_i == 1'b1) && (mem_wd_i == reg1_addr_0))begin
                reg1_0 <= mem_wdata_i;
            end else if(reg1_read_0 == 1'b1) begin
                reg1_0 <= reg1_data_i; //Regfile 读端口1的输出值
            end else if(reg1_read_0 == 1'b0) begin
                reg1_0 <= imm;
            end else begin
                reg1_0 <= `ZeroWord;
            end
          end
          /************************** 第三段:确定进行运算的源操作数2 ***********************************/
          always @ (*) begin
            if(rst == `RstEnable)begin
                reg2_0 <= `ZeroWord;
            end else if((reg2_read_0 == 1'b1) && (ex_wreg_i == 1'b1) && (ex_wd_i == reg2_addr_0))begin
                reg2_0 <= ex_wdata_i;
            end else if((reg2_read_0 == 1'b1) && (mem_wreg_i == 1'b1) && (mem_wd_i == reg2_addr_0))begin
                reg2_0 <= mem_wdata_i;
            end else if(reg2_read_0 == 1'b1) begin
                reg2_0 <= reg2_data_i;//Regfile 读端口2的输出值
            end else if(reg2_read_0 == 1'b0) begin
                reg2_0 <= imm;
            end else begin
                reg2_0 <= `ZeroWord;
            end
          end
          always @ (*) begin
            if(rst == `RstEnable)begin
                is_in_delayslot_0   <= `NotInDelaySlot;
             end else begin
                is_in_delayslot_0 <= is_in_delayslot_i;
              end
           end
Endmodule
  1. id_ex模块
include"defines.v"
module id_ex(
    input wire clk,
    input wire rst,
    
    input wire[5:0] stall,
    
    //从译码阶段传递过来的信息
    input wire[`AluOpBus]   id_aluop,
    input wire[`AluSelBus]  id_alusel,
    input wire[`RegBus]     id_reg1,
    input wire[`RegBus]     id_reg2,
    input wire[`RegAddrBus] id_wd,
    input wire              id_wreg,
    
    //跳转时延
    input wire[`RegBus]     id_link_address,
    input                    id_is_in_delayslot,
    input wire              next_inst_in_delayslot_i,
    //load
    input wire[`RegBus]     id_inst,
    //传递到执行阶段的信息
    output reg[`AluOpBus]   ex_aluop,
    output reg[`AluSelBus]  ex_alusel,
    output reg[`RegBus]     ex_reg1,
    output reg[`RegBus]     ex_reg2,
    output reg[`RegAddrBus] ex_wd,
    output reg              ex_wreg , 
    //跳转时延
    output  reg[`RegBus]    ex_link_address,
    output  reg             ex_is_in_delayslot,
    output  reg             is_in_delayslot_0,
    //load
    output  reg[`RegBus]    ex_inst
    );  
    
    always @ (posedge clk) begin
        if(rst == `RstEnable) begin
            ex_aluop <= `EXE_NOP_OP;
            ex_alusel <= `EXE_RES_NOP;
            ex_reg1 <= `ZeroWord;
            ex_reg2 <= `ZeroWord;
            ex_wd <= `NOPRegAddr;
            ex_wreg <= `WriteDisable;
            ex_link_address <= `ZeroWord;
            ex_is_in_delayslot <= `NotInDelaySlot;
            is_in_delayslot_0   <=`NotInDelaySlot;
            ex_inst <=  `ZeroWord;
         end else if(stall[2] == `Stop && stall[3] == `NoStop) begin
            ex_aluop <= `EXE_NOP_OP;
            ex_alusel <= `EXE_RES_NOP;
            ex_reg1 <= `ZeroWord;
            ex_reg2 <= `ZeroWord;
            ex_wd <= `NOPRegAddr;
            ex_wreg <= `WriteDisable;
             ex_link_address <= `ZeroWord;
            ex_is_in_delayslot <= `NotInDelaySlot;
            ex_inst <=  `ZeroWord;
         end else if(stall[2] == `NoStop)begin
            ex_aluop <= id_aluop;
            ex_alusel <= id_alusel;
            ex_reg1 <= id_reg1;
            ex_reg2 <= id_reg2;
            ex_wd <= id_wd;
            ex_wreg <= id_wreg;
            ex_link_address <= id_link_address;
            ex_is_in_delayslot <= id_is_in_delayslot;
            is_in_delayslot_0   <= next_inst_in_delayslot_i;
            ex_inst <=  id_inst;
         end
      end
Endmodule
  1. ex模块
`include"defines.v"
module ex(
    input wire rst,
    // 译码阶段送到执行阶段的信息
    input wire[`AluOpBus]  aluop_i,
    input wire[`AluSelBus] alusel_i,
    input wire[`RegBus]    reg1_i,
    input wire[`RegBus]    reg2_i,
    input wire[`RegAddrBus] wd_i,
    input wire              wreg_i,
    // 执行的结果
    output reg[`RegAddrBus]  wd_0,
    output reg              wreg_0,
    output reg[`RegBus]     wdata_0,
    // HILO 模块给出的HI,LO 寄存器的值
    input wire[`RegBus]     hi_i,
    input wire[`RegBus]     lo_i,
    // 回写阶段的指令是否要写HI,LO,用于检测HI,LO寄存器带来的数据相关问题
    input wire[`RegBus]     wb_hi_i,
    input wire[`RegBus]     wb_lo_i,
    input wire              wb_whilo_i,
    //访存阶段的指令是否要写 HI,LO,用于检测HI,LO寄存器带来的数据相关问题
    input wire[`RegBus]     mem_hi_i,
    input wire[`RegBus]     mem_lo_i,
    input wire              mem_whilo_i,
    
    input wire[`DoubleRegBus]   hilo_temp_i,
    input wire[1:0]             cnt_i,
    //来自除法模块的输入
    input wire[`DoubleRegBus]   div_result_i,
    input wire                  div_ready_i,
    
    //tiaozhuan
    input wire[`RegBus]  link_address_i,
    input wire           is_in_delayslot_i,
    
    //load
    input wire[`RegBus]     inst_i,
    
    output reg[`DoubleRegBus]   hilo_temp_0,
    output reg[1:0]             cnt_0,
    
    //处于执行阶段的指令对HI,LO寄存器的写操作请求
    output reg[`RegBus]     hi_0,
    output reg[`RegBus]     lo_0,
    output reg              whilo_0,
    
    //到除法模块的输出
    output reg[`RegBus]     div_opdata1_0,
    output reg[`RegBus]     div_opdata2_0,
    output reg              div_start_0,
    output reg              signed_div_0,
    
    output reg              stallreq,
    //load
    output wire[`AluOpBus]  aluop_0,
    output wire[`RegBus]    mem_addr_0,
    output wire[`RegBus]    reg2_0
    );
    //保存逻辑运算的结果
    reg[`RegBus]  logicout;
    //保存移位运算结果
    reg[`RegBus]  shiftres;
    //移动操作的结果
    reg[`RegBus]  moveres;
    //保存HI寄存器的最新值
    reg[`RegBus] HI;
    //保存LO寄存器的最新值
    reg[`RegBus] LO;
    //送到访存阶段
    wire   ov_sum;   //保存溢出情况
    wire   reg1_eq_reg2;//第一个操作数是否等于第二个操作数
    wire   reg1_lt_reg2;//第一个操作数是否小于第二个操作数
    reg[`RegBus]   arithmeticres;//保存算术运算的结果
    wire[`RegBus]  reg2_i_mux;//保存输入的第二个操作数reg2_i的补码
    wire[`RegBus]  reg1_i_not;//保存输入的第一个操作数reg1_i取反后的值
    wire[`RegBus]  result_sum;//保存加法结果
    wire[`RegBus]  opdata1_mult;//乘法操作中的被乘数
    wire[`RegBus]  opdata2_mult;//乘法操作中的乘数
    wire[`DoubleRegBus] hilo_temp; // 临时保存乘法结果,宽度为64位
    reg[`DoubleRegBus]  hilo_temp1;
    reg[`DoubleRegBus] mulres;//保存乘法结果,宽度为64位
    reg stallreq_for_madd_msub;
    reg stallreq_for_div;//是否由于除法运算导致流水线暂停
   
    assign  aluop_0 = aluop_i;
    assign  mem_addr_0 = reg1_i + {{16{inst_i[15]}},inst_i[15:0]};
    assign reg2_0   = reg2_i;
    assign  reg2_i_mux = ((aluop_i == `EXE_SUB_OP) || (aluop_i == `EXE_SUBU_OP) || (aluop_i == `EXE_SLT_OP)) ? (~reg2_i) + 1 : reg2_i;
    
    assign result_sum = reg1_i + reg2_i_mux;
    
    assign ov_sum = ((!reg1_i[31] && !reg2_i_mux[31]) && result_sum[31])||((reg1_i[31] && reg2_i_mux[31]) && (!result_sum[31]));
    
    assign reg1_it_reg2 = ((aluop_i == `EXE_SLT_OP))?((reg1_i[31] && !reg2_i[31]) || (!reg1_i[31] && !reg2_i[31] && result_sum[31]) || (reg1_i[31] && reg2_i[31] && result_sum[31])):(reg1_i < reg2_i);
    
    assign reg1_i_not = ~reg1_i;
    
    always @ (*) begin
        if(rst == `RstEnable) begin
            arithmeticres <= `ZeroWord;
        end else begin
            case(aluop_i)
                `EXE_SLT_OP,`EXE_SLTU_OP:begin
                    arithmeticres <= reg1_it_reg2;
                 end
                 `EXE_ADD_OP,`EXE_ADDU_OP,`EXE_ADDI_OP,`EXE_ADDIU_OP:begin
                    arithmeticres<=result_sum;
                 end
                 `EXE_SUB_OP,`EXE_SUBU_OP:begin
                    arithmeticres <= result_sum;
                 end
                 `EXE_CLZ_OP:begin
                    arithmeticres <= reg1_i[31] ? 0:reg1_i[30] ? 1: 
                                     reg1_i[29] ? 2:reg1_i[28] ? 3: 
                                     reg1_i[27] ? 4:reg1_i[26] ? 5: 
                                     reg1_i[25] ? 6:reg1_i[24] ? 7: 
                                     reg1_i[23] ? 8:reg1_i[22] ? 9: 
                                     reg1_i[21] ? 10:reg1_i[20] ? 11: 
                                     reg1_i[19] ? 12:reg1_i[18] ? 13: 
                                     reg1_i[17] ? 14:reg1_i[16] ? 15: 
                                     reg1_i[15] ? 16:reg1_i[14] ? 17: 
                                     reg1_i[13] ? 18:reg1_i[12] ? 19: 
                                     reg1_i[11] ? 20:reg1_i[10] ? 21: 
                                     reg1_i[9] ? 22:reg1_i[8] ? 23: 
                                     reg1_i[7] ? 24:reg1_i[6] ? 25: 
                                     reg1_i[5] ? 26:reg1_i[4] ? 27: 
                                     reg1_i[3] ? 28:reg1_i[2] ? 29: 
                                     reg1_i[1] ? 30:reg1_i[0] ? 31: 32;
                  end
                  `EXE_CLO_OP:begin
                     arithmeticres <= (reg1_i_not[31] ? 0:reg1_i_not[30] ? 1: 
                                     reg1_i_not[29] ? 2:reg1_i_not[28] ? 3: 
                                     reg1_i_not[27] ? 4:reg1_i_not[26] ? 5: 
                                     reg1_i_not[25] ? 6:reg1_i_not[24] ? 7: 
                                     reg1_i_not[23] ? 8:reg1_i_not[22] ? 9: 
                                     reg1_i_not[21] ? 10:reg1_i_not[20] ? 11: 
                                     reg1_i_not[19] ? 12:reg1_i_not[18] ? 13: 
                                     reg1_i_not[17] ? 14:reg1_i_not[16] ? 15: 
                                     reg1_i_not[15] ? 16:reg1_i_not[14] ? 17: 
                                     reg1_i_not[13] ? 18:reg1_i_not[12] ? 19: 
                                     reg1_i_not[11] ? 20:reg1_i_not[10] ? 21: 
                                     reg1_i_not[9] ? 22:reg1_i_not[8] ? 23: 
                                     reg1_i_not[7] ? 24:reg1_i_not[6] ? 25: 
                                     reg1_i_not[5] ? 26:reg1_i_not[4] ? 27: 
                                     reg1_i_not[3] ? 28:reg1_i_not[2] ? 29: 
                                     reg1_i_not[1] ? 30:reg1_i_not[0] ? 31: 32);
                              end
                           default:begin
                                arithmeticres <= `ZeroWord;
                           end
                       endcase
                     end
                  end
   
    //乘法运算
    assign opdata1_mult = (((aluop_i == `EXE_MUL_OP) || (aluop_i == `EXE_MULT_OP)||(aluop_i == `EXE_MADD_OP) || (aluop_i == `EXE_MSUB_OP)) && (reg1_i[31] == 1'b1)) ? (~reg1_i + 1) : reg1_i;
    
    assign opdata2_mult = (((aluop_i == `EXE_MUL_OP) || (aluop_i == `EXE_MULT_OP)||(aluop_i == `EXE_MADD_OP) || (aluop_i == `EXE_MSUB_OP)) && (reg2_i[31] == 1'b1)) ? (~reg2_i + 1) : reg2_i;
    
    assign hilo_temp = opdata1_mult * opdata2_mult;
    
    always @ (*) begin
        if(rst == `RstEnable) begin
            mulres <= {`ZeroWord,`ZeroWord};
        end else if ((aluop_i == `EXE_MULT_OP) || (aluop_i ==`EXE_MUL_OP)||(aluop_i == `EXE_MADD_OP) || (aluop_i == `EXE_MSUB_OP)) begin
            if(reg1_i[31]^reg2_i[31] == 1'b1) begin
             mulres <= ~hilo_temp + 1;
            end else begin
            mulres <= hilo_temp;
            end 
         end else begin
            mulres <= hilo_temp;
         end 
      end
    
    always @ (*) begin
        if(rst == `RstEnable)begin
            {HI,LO} <= {`ZeroWord,`ZeroWord};
        end else if(mem_whilo_i == `WriteEnable) begin
            {HI,LO} <= {mem_hi_i,mem_lo_i};
        end else if(wb_whilo_i == `WriteEnable) begin
            {HI,LO} <= {wb_hi_i,wb_lo_i};
        end else begin
            {HI,LO} <= {hi_i,lo_i};
        end
     end
     
     always @ (*) begin
        if(rst == `RstEnable) begin
            moveres <= `ZeroWord;
        end else begin
            moveres <= `ZeroWord;
            case(aluop_i)
                `EXE_MFHI_OP:begin
                    moveres <= HI;
                 end
                 `EXE_MFLO_OP:begin
                    moveres <= LO;
                 end
                 `EXE_MOVZ_OP:begin
                    moveres <= reg1_i;
                 end
                 `EXE_MOVN_OP:begin
                    moveres <= reg1_i;                 
                 end
                 default:begin
                 end
              endcase
            end
          end
          
    /********************************** 第一段:依据aluop_i指示的运算子类型进行运算   **************************************/
    always @ (*) begin
        if(rst ==  `RstEnable)begin
            logicout <= `ZeroWord;
        end else begin
            case (aluop_i)
                `EXE_OR_OP:begin
                    logicout <= reg1_i | reg2_i;
                 end
                 `EXE_AND_OP:begin
                    logicout <= reg1_i & reg2_i;
                 end
                 `EXE_NOR_OP:begin
                    logicout <= ~(reg1_i | reg2_i);
                 end
                 `EXE_XOR_OP:begin
                    logicout <= reg1_i ^ reg2_i;
                 end
                 default:begin
                    logicout <= `ZeroWord;
                end
              endcase
             end
          end
       // 进行移位运算
       always @ (*) begin
        if(rst == `RstEnable) begin
            shiftres <= `ZeroWord;
        end else begin
            case (aluop_i)
                `EXE_SLL_OP:begin
                    shiftres <= reg2_i << reg1_i[4:0];
                 end
                 `EXE_SRL_OP:begin
                    shiftres <= reg2_i >> reg1_i[4:0];
                 end
                 `EXE_SRA_OP:begin
                    shiftres <= ({32{reg2_i[31]}} << (6'd32 - {1'b0,reg1_i[4:0]})) | reg2_i >> reg1_i[4:0];
                 end
                 default:begin
                    shiftres <= `ZeroWord;
                 end
              endcase
           end
        end
       /******************************************  第二段 :依据aluse1_i指示的运算类型,选择一个运算结果作为最终结果   *************/
      
       always @ (*) begin
            wd_0  <= wd_i;  // wd_0 等于wd_i,要写的目的寄存器地址
        if(((aluop_i == `EXE_ADD_OP) || (aluop_i==`EXE_ADDI_OP) || (aluop_i == `EXE_SUB_OP)) && (ov_sum == 1'b1)) begin
            wreg_0 <= `WriteDisable;
            end else begin
                    wreg_0 <= wreg_i;
             end
            case(alusel_i)
                `EXE_RES_LOGIC: begin
                    wdata_0 <= logicout;   // wdata_0中存放运算结果
                  end
                `EXE_RES_SHIFT:begin
                    wdata_0 <= shiftres;
                  end
                 `EXE_RES_MOVE:begin
                    wdata_0 <= moveres;
                 end
                 `EXE_RES_ARITHMETIC:begin
                    wdata_0 <= arithmeticres;
                 end
                 `EXE_RES_MUL:begin
                    wdata_0 <= mulres[31:0];
                 end
                 `EXE_RES_JUMP_BRANCH:begin
                    wdata_0<= link_address_i;
                 end
                  default: begin
                     wdata_0 <= `ZeroWord;
                   end
                 endcase
               end
       always @ (*) begin
            if( rst == `RstEnable)begin
                hilo_temp_0 <= {`ZeroWord,`ZeroWord};
                cnt_0 <= 2'b00;
                stallreq_for_madd_msub <= `NoStop;
              end else begin
                 case (aluop_i)
                 `EXE_MADD_OP,`EXE_MADDU_OP:begin
                    if(cnt_i == 2'b00) begin
                        hilo_temp_0 <= mulres;
                        cnt_0 <= 2'b01;
                        hilo_temp1 <= {`ZeroWord,`ZeroWord};
                        stallreq_for_madd_msub <= `Stop;
                      end else if(cnt_i == 2'b01)begin
                        hilo_temp_0 <= {`ZeroWord,`ZeroWord};
                        cnt_0 <= 2'b10;
                        hilo_temp1 <= hilo_temp_i + {HI,LO};
                        stallreq_for_madd_msub<= `NoStop;
                       end
                     end
                     `EXE_MSUB_OP,`EXE_MSUBU_OP:begin
                        if(cnt_i == 2'b00)begin
                            hilo_temp_0 <= ~mulres + 1;
                            cnt_0       <= 2'b01;
                            stallreq_for_madd_msub <= `Stop;
                          end else if(cnt_i == 2'b01)begin
                            hilo_temp_0 <= {`ZeroWord,`ZeroWord};
                            cnt_0 <= 2'b10;
                            hilo_temp1 <= hilo_temp_i + {HI,LO};
                            stallreq_for_madd_msub <= `NoStop;
                           end
                          end
                        default:begin
                            hilo_temp_0 <= {`ZeroWord,`ZeroWord};
                            cnt_0 <= 2'b00;
                            stallreq_for_madd_msub <= `NoStop;
                          end
                        endcase
                       end
                      end
  //除法运算
    always @ (*)begin
        if(rst == `RstEnable)begin
            stallreq_for_div <= `NoStop;
            div_opdata1_0   <= `ZeroWord;
            div_opdata2_0   <= `ZeroWord;
            div_start_0     <= `DivStop;
            signed_div_0    <= 1'b0;//singed_div_0
          end else begin
            stallreq_for_div <= `NoStop;
            div_opdata1_0   <= `ZeroWord;
            div_opdata2_0   <= `ZeroWord;
            div_start_0     <= `DivStop;
            signed_div_0    <= 1'b0;
            case(aluop_i)
            `EXE_DIV_OP:begin
                if(div_ready_i == `DivResultNotReady) begin
                    div_opdata1_0 <= reg1_i;
                    div_opdata2_0 <= reg2_i;
                    div_start_0   <= `DivStart;
                    signed_div_0   <= 1'b1;
                    stallreq_for_div <= `Stop;
                 end else if(div_ready_i == `DivResultReady) begin
                    div_opdata1_0   <= reg1_i;
                    div_opdata2_0   <= reg2_i;
                    div_start_0     <= `DivStop;
                    signed_div_0    <=  1'b1;
                    stallreq_for_div <= `NoStop;
                 end else begin
                    div_opdata1_0   <= `ZeroWord;
                    div_opdata2_0   <= `ZeroWord;
                    div_start_0     <= `DivStop;
                    signed_div_0    <=  1'b0;
                    stallreq_for_div <= `NoStop;
                end
               end
               `EXE_DIVU_OP:begin
                    if(div_ready_i == `DivResultNotReady)begin
                        div_opdata1_0   <=  reg1_i;
                        div_opdata2_0   <=  reg2_i;
                        div_start_0     <= `DivStart;
                        signed_div_0    <= 1'b0;
                        stallreq_for_div    <= `Stop;
                      end else if(div_ready_i == `DivResultReady)begin
                        div_opdata1_0   <=  reg1_i;
                        div_opdata2_0   <=  reg2_i;
                        div_start_0     <= `DivStop;
                        signed_div_0    <= 1'b0;
                        stallreq_for_div    <= `NoStop;
                      end else begin
                        div_opdata1_0   <= `ZeroWord;
                        div_opdata2_0   <= `ZeroWord;
                        div_start_0     <= `DivStop;
                        signed_div_0    <=  1'b0;
                        stallreq_for_div <= `NoStop;
                      end
                    end
                  default:begin
                  end
                endcase
              end
           end
            
       //暂停流水线               
       always @ (*) begin
            stallreq = stallreq_for_madd_msub || stallreq_for_div;
            end
                        
       always @ (*) begin
            if(rst == `RstEnable) begin
                whilo_0 <= `WriteDisable;
                hi_0 <= `ZeroWord;
                lo_0 <= `ZeroWord;
           end else if((aluop_i == `EXE_MSUB_OP) || (aluop_i == `EXE_MSUBU_OP))begin
                whilo_0 <= `WriteEnable;
                hi_0 <= hilo_temp1[63:32];
                lo_0 <= hilo_temp1[31:0];
            end else if((aluop_i == `EXE_MADD_OP) || (aluop_i == `EXE_MADDU_OP))begin
                whilo_0 <= `WriteEnable;
                hi_0 <= hilo_temp1[63:32];
                lo_0 <= hilo_temp1[31:0];
            end else if((aluop_i == `EXE_DIV_OP)||(aluop_i == `EXE_DIVU_OP))begin
                whilo_0 <= `WriteEnable;
                hi_0 <= div_result_i[63:32];
                lo_0 <= div_result_i[31:0];
            end else if((aluop_i == `EXE_MULT_OP) || (aluop_i == `EXE_MULTU_OP)) begin
                whilo_0<=`WriteEnable;
                hi_0 <= mulres[63:32];
                lo_0 <= mulres[31:0];
            end else if(aluop_i == `EXE_MTHI_OP)begin
                whilo_0 <= `WriteEnable;
                hi_0 <= reg1_i;
                lo_0 <= LO;
            end else if(aluop_i == `EXE_MTLO_OP)begin
                whilo_0 <= `WriteEnable;
                hi_0 <= HI;
                lo_0 <= reg1_i;            
            end else begin
                whilo_0 <= `WriteDisable;
                hi_0 <= `ZeroWord;
                lo_0 <= `ZeroWord;           
            end
          end
endmodule
  1. div模块
module div(
    input   wire    clk,
    input   wire    rst,
    input   wire    signed_div_i,
    input   wire[31:0]  opdata1_i,
    input   wire[31:0]  opdata2_i,
    input   wire        start_i,
    input   wire        annul_i,
    output  reg[63:0]   result_0,
    output  reg         ready_0
    );
    wire[32:0] div_temp;
    reg[5:0]    cnt;//记录试商法进行了几轮,当等于32时,表示试商法结束
    reg[64:0]   dividend;
    reg[1:0]    state;
    reg[31:0]   divisor;
    reg[31:0]   temp_op1;
    reg[31:0]   temp_op2;
    assign  div_temp = {1'b0,dividend[63:32]} - {1'b0,divisor};
    always @ (posedge clk)begin
        if(rst == `RstEnable) begin
            state <= `DivFree;
            ready_0 <= `DivResultNotReady;
            result_0 <= {`ZeroWord,`ZeroWord};
         end else begin
            case(state)
                `DivFree:begin
                   if(start_i == `DivStart && annul_i == 1'b0)begin
                    if(opdata2_i == `ZeroWord)begin
                        state <= `DivByZero;
                     end else begin
                        state <= `DivOn;
                        cnt <= 6'b000000;
                        if(signed_div_i == 1'b1 && opdata1_i[31] == 1'b1)begin
                            temp_op1 = ~opdata1_i + 1;
                         end else begin
                            temp_op1 = opdata1_i;
                         end
                         if(signed_div_i == 1'b1 && opdata2_i[31] == 1'b1)begin
                            temp_op2 = ~opdata2_i + 1;
                         end else begin
                            temp_op2 = opdata2_i;
                         end
                         dividend <= {`ZeroWord,`ZeroWord};
                         dividend[32:1] <= temp_op1;
                         divisor <= temp_op2;
                         end
                       end else begin
                          ready_0 <= `DivResultNotReady;
                          result_0 <= {`ZeroWord,`ZeroWord};
                        end
                       end
                    `DivByZero:begin
                        dividend <= {`ZeroWord,`ZeroWord};
                        state <= `DivEnd;
                     end
                     `DivOn:begin
                        if(annul_i == 1'b0)begin
                            if(cnt  != 6'b100000 )begin
                                if(div_temp[32] == 1'b1) begin
                                    dividend <= {dividend[63:0],1'b0};
                                 end else begin
                                    dividend <= {div_temp[31:0],dividend[31:0],1'b1};
                                 end
                                 cnt <= cnt+1;
                              end else begin
                                if((signed_div_i == 1'b1) && ((opdata1_i[31] ^ opdata2_i[31]) == 1'b1)) begin
                                    dividend[31:0] <= (~dividend[31:0] + 1);
                                 end
                                 if((signed_div_i == 1'b1) && ((opdata1_i[31] ^ dividend[64]) == 1'b1)) begin
                                    dividend[64:33] <= (~dividend[64:33] + 1);
                                 end
                                 state <= `DivEnd;
                                 cnt<=6'b000000;
                                 end
                              end else begin
                                  state <= `DivFree;
                              end
                           end
                        `DivEnd:begin
                            result_0 <= {dividend[64:33],dividend[31:0]};
                            ready_0 <= `DivResultReady;
                            if(start_i == `DivStop) begin
                                state <= `DivFree;
                                ready_0 <= `DivResultNotReady;
                                result_0 <= {`ZeroWord,`ZeroWord};
                             end
                           end
                         endcase
                       end
                     end 
endmodule
  1. ex_mem模块
include"defines.v"
module ex_mem(
    input wire  clk,
    input wire  rst,
    input wire[5:0]             stall,
    // 来自执行阶段的信息
    input wire[`RegAddrBus] ex_wd,
    input wire              ex_wreg,
    input wire[`RegBus]     ex_wdata,
    input wire[`RegBus]     ex_hi,
    input wire[`RegBus]     ex_lo,
    input wire              ex_whilo,
    input wire[`DoubleRegBus] hilo_i,
    input wire[1:0]           cnt_i,
    //load
    input wire[`AluOpBus]   ex_aluop,
    input wire[`RegBus]     ex_mem_addr,
    input wire[`RegBus]     ex_reg2,
    output  reg[`AluOpBus]  mem_aluop,
    output  reg[`RegBus]    mem_mem_addr,
    output  reg[`RegBus]    mem_reg2,
    output reg[`DoubleRegBus] hilo_0,
    output reg[1:0]           cnt_0,
    //送到访存阶段的信息
    output reg[`RegAddrBus] mem_wd,
    output reg              mem_wreg,
    output reg[`RegBus]     mem_wdata,
    output reg[`RegBus]     mem_hi,
    output reg[`RegBus]     mem_lo,
    output reg              mem_whilo
    );
    always @ (posedge clk) begin
        if(rst == `RstEnable) begin
            mem_wd <= `NOPRegAddr;
            mem_wreg <= `WriteDisable;
            mem_wdata<= `ZeroWord;
            mem_hi <= `ZeroWord;
            mem_lo <= `ZeroWord;
            mem_whilo <= `WriteDisable;
            hilo_0 <= {`ZeroWord,`ZeroWord};
            cnt_0  <= 2'b00;
            mem_aluop <=  `EXE_NOP_OP;
            mem_mem_addr <= `ZeroWord;
            mem_reg2    <=  `ZeroWord;
         end else if(stall[3] == `Stop && stall[4] == `NoStop)begin
            mem_wd <= `NOPRegAddr;
            mem_wreg <= `WriteDisable;
            mem_wdata<= `ZeroWord;
            mem_hi <= `ZeroWord;
            mem_lo <= `ZeroWord;
            mem_whilo <= `WriteDisable;
            hilo_0 <= hilo_i;
            cnt_0  <= cnt_i;
            mem_aluop <=  `EXE_NOP_OP;
            mem_mem_addr <= `ZeroWord;
            mem_reg2    <=  `ZeroWord;
         end else if(stall[3] == `NoStop) begin
            mem_wd <= ex_wd;
            mem_wreg <= ex_wreg;
            mem_wdata <= ex_wdata;
            mem_hi <=  ex_hi;
            mem_lo <=  ex_lo;
            mem_whilo <= ex_whilo;
            hilo_0 <= {`ZeroWord,`ZeroWord};
            cnt_0  <= 2'b00;
            mem_aluop <=  ex_aluop;
            mem_mem_addr <= ex_mem_addr;
            mem_reg2    <=  ex_reg2;
         end else begin
             hilo_0 <= hilo_i;
             cnt_0  <= cnt_i;
         end
       end
endmodule
  1. mem模块
`include"defines.v"
module mem(
    input wire rst,
    // 来自执行阶段的信息
    input wire[`RegAddrBus]     wd_i,
    input wire                  wreg_i,
    input wire[`RegBus]         wdata_i,
    input wire[`RegBus]         hi_i,      
    input wire[`RegBus]         lo_i,
    input wire                  whilo_i,
    //load
    input   wire[`AluOpBus]     aluop_i,
    input   wire[`RegBus]       mem_addr_i,
    input   wire[`RegBus]       reg2_i,
    // ram
    input   wire[`RegBus]       mem_data_i,
    //送到RAM的信息
    output reg[`RegBus]         mem_addr_0,
    output wire                 mem_we_0,
    output reg[3:0]             mem_sel_0,
    output  reg[`RegBus]        mem_data_0,
    output  reg                 mem_ce_0,
    //访存阶段的结构
    output reg[`RegAddrBus]     wd_0,
    output reg                  wreg_0,
    output reg[`RegBus]         wdata_0,
    output reg[`RegBus]         hi_0,
    output reg[`RegBus]         lo_0,
    output reg                  whilo_0
    );
    wire[`RegBus]   zero32;
    reg mem_we;
    assign  mem_we_0 = mem_we;
    assign  zer032 = `ZeroWord;
    
    always @ (*) begin
        if(rst == `RstEnable) begin
            wd_0 <= `NOPRegAddr;
            wreg_0 <= `WriteDisable;
            wdata_0 <= `ZeroWord;
            hi_0    <=  `ZeroWord;
            lo_0    <=   `ZeroWord;
            whilo_0 <= `WriteDisable;
            mem_addr_0  <= `ZeroWord;
            mem_we  <=  `WriteDisable;
            mem_sel_0 <= 4'b0000;
            mem_data_0  <= `ZeroWord;
            mem_ce_0    <= `ChipDisable;
         end else begin
            wd_0 <= wd_i;
            wreg_0 <= wreg_i;
            wdata_0 <= wdata_i;
             hi_0    <=  hi_i;
            lo_0    <=   lo_i;
            whilo_0 <=  whilo_i;
            mem_addr_0  <= `ZeroWord;
            mem_we  <=  `WriteDisable;
            mem_sel_0 <= 4'b1111;
            mem_ce_0    <= `ChipDisable;
            case(aluop_i)
            `EXE_LB_OP:begin
                mem_addr_0  <= mem_addr_i;
                mem_we  <=  `WriteDisable;
                mem_ce_0    <=  `ChipEnable;
                case(mem_addr_i[1:0])
                    2'b00:begin
                        wdata_0 <= {{24{mem_data_i[31]}},mem_data_i[31:24]};
                        mem_sel_0   <= 4'b1000;
                    end
                    2'b01:begin
                        wdata_0 <= {{24{mem_data_i[23]}},mem_data_i[23:16]};
                        mem_sel_0   <= 4'b0100;
                    end
                    2'b10:begin
                        wdata_0 <= {{24{mem_data_i[15]}},mem_data_i[15:8]};
                        mem_sel_0   <= 4'b0010;
                    end
                    2'b11:begin
                        wdata_0 <= {{24{mem_data_i[7]}},mem_data_i[7:0]};
                        mem_sel_0   <= 4'b0001;
                    end
                    default:begin
                        wdata_0 <= `ZeroWord;
                    end
                    endcase
            end
            `EXE_LBU_OP:begin
                mem_addr_0  <= mem_addr_i;
                mem_we  <=  `WriteDisable;
                mem_ce_0    <=  `ChipEnable;
                case(mem_addr_i[1:0])
                    2'b00:begin
                        wdata_0 <= {{24{1'b0}},mem_data_i[31:24]};
                        mem_sel_0   <= 4'b1000;
                    end
                    2'b01:begin
                        wdata_0 <= {{24{1'b0}},mem_data_i[23:16]};
                        mem_sel_0   <= 4'b0100;
                    end
                    2'b10:begin
                        wdata_0 <= {{24{1'b0}},mem_data_i[15:8]};
                        mem_sel_0   <= 4'b0010;
                    end
                    2'b11:begin
                        wdata_0 <= {{24{1'b0}},mem_data_i[7:0]};
                        mem_sel_0   <= 4'b0001;
                    end
                    default:begin
                        wdata_0 <= `ZeroWord;
                    end
                    endcase
            end
            `EXE_LH_OP:begin
                mem_addr_0  <= mem_addr_i;
                mem_we  <=  `WriteDisable;
                mem_ce_0    <=  `ChipEnable;
                case(mem_addr_i[1:0])
                    2'b00:begin
                        wdata_0 <= {{16{mem_data_i[31]}},mem_data_i[31:16]};
                        mem_sel_0   <= 4'b1100;
                    end
                    2'b10:begin
                        wdata_0 <= {{16{mem_data_i[15]}},mem_data_i[15:0]};
                        mem_sel_0   <= 4'b0011;
                    end
                    default:begin
                        wdata_0 <= `ZeroWord;
                    end
                    endcase
            end
            `EXE_LHU_OP:begin
                mem_addr_0  <= mem_addr_i;
                mem_we  <=  `WriteDisable;
                mem_ce_0    <=  `ChipEnable;
                case(mem_addr_i[1:0])
                    2'b00:begin
                        wdata_0 <= {{16{1'b0}},mem_data_i[31:16]};
                        mem_sel_0   <= 4'b1100;
                    end
                    2'b10:begin
                        wdata_0 <= {{16{1'b0}},mem_data_i[15:0]};
                        mem_sel_0   <= 4'b0011;
                    end
                    default:begin
                        wdata_0 <= `ZeroWord;
                    end
                    endcase
            end
            `EXE_LW_OP:begin
                mem_addr_0 <= mem_addr_i;
                mem_we  <=  `WriteDisable;
                wdata_0 <=  mem_data_i;
                mem_sel_0   <= 4'b1111;
                mem_ce_0 <= `ChipEnable;
            end
            `EXE_LWL_OP:begin
                mem_addr_0  <= {mem_addr_i[31:2],2'b00};
                mem_we  <=  `WriteDisable;
                mem_sel_0   <= 4'b1111;
                mem_ce_0    <=  `ChipEnable;
                case(mem_addr_i[1:0])
                    2'b00:begin
                        wdata_0 <= mem_data_i[31:0]; 
                    end
                    2'b01:begin
                        wdata_0 <= {mem_data_i[23:0],reg2_i[7:0]};
                    end
                    2'b10:begin
                        wdata_0 <= {mem_data_i[15:0],reg2_i[15:0]};
                    end
                    2'b11:begin
                         wdata_0 <= {mem_data_i[7:0],reg2_i[23:0]};
                    end
                    default:begin
                        wdata_0 <= `ZeroWord;
                    end
                    endcase
            end
            `EXE_LWR_OP:begin
                mem_addr_0  <= {mem_addr_i[31:2],2'b00};
                mem_we  <=  `WriteDisable;
                mem_sel_0   <= 4'b1111;
                mem_ce_0    <=  `ChipEnable;
                case(mem_addr_i[1:0])
                    2'b00:begin
                        wdata_0 <= {reg2_i[31:8],mem_data_i[31:24]}; 
                    end
                    2'b01:begin
                        wdata_0 <= {reg2_i[31:16],mem_data_i[31:16]};
                    end
                    2'b10:begin
                       wdata_0 <= {reg2_i[31:24],mem_data_i[31:8]};
                    end
                    2'b11:begin
                        wdata_0 <= mem_data_i;
                    end
                    default:begin
                        wdata_0 <= `ZeroWord;
                    end
                    endcase
            end
            `EXE_SB_OP:begin
                mem_addr_0  <= mem_addr_i;
                mem_we  <=  `WriteEnable;
                mem_data_0  <= {reg2_i[7:0],reg2_i[7:0],reg2_i[7:0],reg2_i[7:0]};
                mem_ce_0    <=  `ChipEnable;
                case(mem_addr_i[1:0])
                    2'b00:begin
                        mem_sel_0   <= 4'b1000;
                    end
                    2'b01:begin
                        mem_sel_0   <= 4'b0100;
                    end
                    2'b10:begin
                       mem_sel_0   <= 4'b0010;
                    end
                    2'b11:begin
                        mem_sel_0   <= 4'b0001;
                    end
                    default:begin
                        mem_sel_0   <= 4'b0000;
                    end
                    endcase
            end
            `EXE_SH_OP:begin
                mem_addr_0  <= mem_addr_i;
                mem_we  <=  `WriteEnable;
                mem_data_0  <= {reg2_i[15:0],reg2_i[15:0]};
                mem_ce_0    <=  `ChipEnable;
                case(mem_addr_i[1:0])
                    2'b00:begin
                        mem_sel_0   <= 4'b1100;
                    end
                    2'b10:begin
                       mem_sel_0   <= 4'b0011;
                    end
                    default:begin
                        mem_sel_0   <= 4'b0000;
                    end
                    endcase
            end
            `EXE_SW_OP:begin
                mem_addr_0  <=  mem_addr_i;
                mem_we      <=  `WriteEnable;
                mem_data_0  <=  reg2_i;
                mem_sel_0   <=  4'b1111;
                mem_ce_0    <= `ChipEnable;
            end
            `EXE_SWL_OP:begin
                mem_addr_0  <= {mem_addr_i[31:2],2'b00};
                mem_we  <=  `WriteEnable;
                mem_ce_0    <=  `ChipEnable;
                case(mem_addr_i[1:0])
                    2'b00:begin
                        mem_sel_0   <= 4'b1111;
                        mem_data_0  <= reg2_i;
                    end
                    2'b01:begin
                        mem_sel_0   <= 4'b0111;
                        mem_data_0 <= {zero32[7:0],reg2_i[31:8]};
                    end
                    2'b10:begin
                       mem_sel_0   <= 4'b0011;
                       mem_data_0 <= {zero32[15:0],reg2_i[31:16]};
                    end
                    2'b11:begin
                        mem_sel_0   <= 4'b0001;
                        mem_data_0 <= {zero32[23:0],reg2_i[31:24]};
                    end
                    default:begin
                        mem_sel_0   <= 4'b0000;
                    end
                    endcase
            end
            `EXE_SWR_OP:begin
                mem_addr_0  <= {mem_addr_i[31:2],2'b00};
                mem_we  <=  `WriteEnable;
                mem_ce_0    <=  `ChipEnable;
                case(mem_addr_i[1:0])
                    2'b00:begin
                        mem_sel_0   <= 4'b1000;
                        mem_data_0  <= {reg2_i[7:0],zero32[23:0]};
                    end
                    2'b01:begin
                        mem_sel_0   <= 4'b1100;
                        mem_data_0  <= {reg2_i[15:0],zero32[15:0]};
                    end
                    2'b10:begin
                       mem_sel_0   <= 4'b1110;
                        mem_data_0  <= {reg2_i[23:0],zero32[7:0]};
                    end
                    2'b11:begin
                        mem_sel_0   <= 4'b1111;
                        mem_data_0  <= reg2_i[31:0];
                    end
                    default:begin
                        mem_sel_0   <= 4'b0000;
                    end
                    endcase
            end
            default:begin
            end
            endcase
          end
        end
Endmodule
  1. mem_wb模块
`include"defines.v"
module mem_wb(
    input wire clk,
    input wire rst,
    input wire[5:0]     stall,
    //访存阶段的结果
    input wire[`RegAddrBus]  mem_wd,
    input wire               mem_wreg,
    input wire[`RegBus]      mem_wdata,
    input wire[`RegBus]      mem_hi,
    input wire[`RegBus]      mem_lo,
    input wire               mem_whilo,
    //送到回写阶段的信息
    output reg[`RegAddrBus]   wb_wd,
    output reg                wb_wreg,
    output reg[`RegBus]       wb_wdata,
    output reg[`RegBus]       wb_hi,
    output reg[`RegBus]       wb_lo,
    output reg               wb_whilo
    );
    always @ (posedge clk)begin
        if(rst == `RstEnable) begin
            wb_wd <= `NOPRegAddr;
            wb_wreg <= `WriteDisable;
            wb_wdata <= `ZeroWord;
            wb_hi   <= `ZeroWord;
            wb_lo   <=`ZeroWord;
            wb_whilo <=`WriteDisable;
        end else if(stall[4] == `Stop && stall[5] == `NoStop) begin
            wb_wd <= `NOPRegAddr;
            wb_wreg <= `WriteDisable;
            wb_wdata <= `ZeroWord;
            wb_hi   <= `ZeroWord;
            wb_lo   <=`ZeroWord;
            wb_whilo <=`WriteDisable;
        end else if (stall[4] == `NoStop) begin
            wb_wd <= mem_wd;
            wb_wreg <= mem_wreg;
            wb_wdata <= mem_wdata;
             wb_hi   <= mem_hi;
            wb_lo   <= mem_lo;
            wb_whilo <= mem_whilo;
        end
     end 
endmodule
  1. hilo_reg模块
`include"defines.v"
module hilo_reg(
        input wire clk,
        input wire rst,

        // 写端口
        input wire  we,
        input wire[`RegBus] hi_i,
        input wire[`RegBus] lo_i,
        //读端口
        
        output reg[`RegBus] hi_0,
        output reg[`RegBus] lo_0
    );
    always @ (posedge clk) begin
        if (rst == `RstEnable)begin
                hi_0 <= `ZeroWord;
                lo_0 <= `ZeroWord;
        end else if((we == `WriteEnable)) begin
                hi_0 <= hi_i;
                lo_0 <= lo_i;
        end
    end
Endmodule
  1. openmips模块
include"defines.v"
module openmips(
    input wire clk,
    input wire rst,
    input wire[`RegBus]   rom_data_i,
    output wire[`RegBus]  rom_addr_0,
    
    input  wire[`RegBus]  ram_data_i,
    output wire[`RegBus]  ram_addr_0,
    output wire[`RegBus]  ram_data_0,
    output wire           ram_we_0,
    output wire[3:0]      ram_sel_0,
    output wire           ram_ce_0,
    
    output wire           rom_ce_0
 
    );
   

    //连接IF/ID模块与译码阶段ID 模块的变量
    wire [`InstAddrBus] pc;
    wire [`InstAddrBus] id_pc_i;
    wire [`InstBus] id_inst_i;
    
    //连接译码阶段ID模块输出与 ID / EX 模块的输入变量
    wire[`AluOpBus]  id_aluop_0;
    wire[`AluSelBus] id_alusel_0;
    wire[`RegBus]    id_reg1_0;
    wire[`RegBus]    id_reg2_0;
    wire             id_wreg_0;
    wire[`RegAddrBus]id_wd_0;
    wire    is_in_delayslot_0;
    wire[`RegBus]    link_addr_0;
    wire    next_inst_in_delayslot_0;
    wire[`RegBus]    inst_0;
    //送到pc_reg
    wire[`RegBus]    branch_target_address_0;
    wire    branch_flag_0;
    // 连接ID / EX 模块输出与执行阶段 EX 模块的输入的变量
    wire[`AluOpBus]  ex_aluop_i;
    wire[`AluSelBus] ex_alusel_i;
    wire[`RegBus]    ex_reg1_i;
    wire[`RegBus]    ex_reg2_i;
    wire             ex_wreg_i;
    wire[`RegAddrBus]ex_wd_i;
    wire             ex_is_in_delayslot_i;
    wire[`RegBus]    ex_link_address_i;
    
    wire[`RegBus]   ex_inst_i;
    //送到pc
    wire             ex_is_in_delayslot_0;
    //连接执行阶段EX 模块的输出与EX/MEM 模块的输入的变量
    wire             ex_wreg_0;
    wire[`RegAddrBus]ex_wd_0;
    wire[`RegBus]    ex_wdata_0;
    wire[`RegBus]    ex_hi_0;
    wire[`RegBus]    ex_lo_0;
    wire             ex_whilo_0;
    
    wire[7:0]         ex_aluop_0;
    wire[`RegBus]     ex_mem_addr_0;
    wire[`RegBus]     ex_reg2_0;
    
    //连接EX/MEM 模块的输出与访存阶段MEM模块的输入的变量
    wire             mem_wreg_i;
    wire[`RegAddrBus]mem_wd_i;
    wire[`RegBus]    mem_wdata_i;
    wire             mem_whilo_i;
    wire[`RegBus]    mem_hi_i;
    wire[`RegBus]    mem_lo_i;
    
    wire[7:0]        mem_aluop;
    wire[`RegBus]    mem_mem_addr;
    wire[`RegBus]    mem_reg2;
    //连接访存阶段MEM模块的输出与MEM/WB模块的输入的变量
    wire             mem_wreg_0;
    wire[`RegAddrBus] mem_wd_0;
    wire[`RegBus]    mem_wdata_0;
    wire             mem_whilo_0;
    wire[`RegBus]    mem_hi_0;
    wire[`RegBus]    mem_lo_0;
    //mem -> ram
    wire[`RegBus]            mem_addr_0;
    wire                     mem_we_0;
    wire[3:0]                mem_sel_0;
    wire[`RegBus]            mem_data_0;
    wire                     mem_ce_0;           
    //连接MEM/WB模块的输出与回写阶段的输入的变量
    wire             wb_wreg_i;
    wire[`RegAddrBus]wb_wd_i;
    wire[`RegBus]    wb_wdata_i;
    wire             wb_whilo_i;
    wire[`RegBus]    wb_hi_i;
    wire[`RegBus]    wb_lo_i; 
    //连接译码阶段ID模块与通用寄存器Regfile模块的变量
    wire             reg1_read;
    wire             reg2_read;
    wire[`RegBus]    reg1_data;
    wire[`RegBus]    reg2_data;
    wire[`RegAddrBus]reg1_addr;
    wire[`RegAddrBus]reg2_addr;
    //HILO
    wire[`RegBus] hi_0;
    wire[`RegBus] lo_0;
    
    //ctrl
    wire[5:0]   stall;
    wire        stallreq_id;
    wire        stallreq_ex;
    //乘累加和乘累减
    wire[1:0] ex_cnt_0;
    wire[`DoubleRegBus]ex_hilo_0;
    wire[1:0] ex_mem_cnt_0;
    wire[`DoubleRegBus]ex_mem_hilo_0;
    //DIV
    wire signed_div;
    wire[31:0] div_opdata1;
    wire[31:0] div_opdata2;
    wire div_start;
    wire[63:0] div_result;
    wire div_ready;
    
    //pc_reg 例化
    pc_reg pc_reg0(.clk(clk),.rst(rst),.stall(stall),.branch_flag_i(branch_flag_0),.branch_target_address_i(branch_target_address_0),.pc(pc),.ce(rom_ce_0));
    
    assign rom_addr_0 = pc;//指令存储器的输入地址就是pc的值
    //  if/id 模块例化
    
    if_id if_id0(.clk(clk),.rst(rst),.stall(stall),.if_pc(pc),.if_inst(rom_data_i),.id_pc(id_pc_i),.id_inst(id_inst_i));
    
    //译码阶段的例化
    
    id id0(.rst(rst),.pc_i(id_pc_i),.inst_i(id_inst_i),
    .is_in_delayslot_i(ex_is_in_delayslot_0),
    //来自Regfile模块的输入
    .reg1_data_i(reg1_data),.reg2_data_i(reg2_data),
    
    //送到regfile模块的信息
    
    .reg1_read_0(reg1_read),.reg2_read_0(reg2_read),
    .reg1_addr_0(reg1_addr),.reg2_addr_0(reg2_addr),
    
     .ex_wreg_i(ex_wreg_0),
     .ex_wdata_i(ex_wdata_0),
     .ex_wd_i(ex_wd_0),
     .mem_wreg_i(mem_wreg_0),
     .mem_wdata_i(mem_wdata_0),
     .mem_wd_i(mem_wd_0),
     //yanshifenzi
      .next_inst_in_delayslot_0(next_inst_in_delayslot_0),
      .branch_flag_0(branch_flag_0),
      .branch_target_address_0(branch_target_address_0),
      .link_addr_0(link_addr_0),
      .is_in_delayslot_0(is_in_delayslot_0),
    //送到ID/EX模块的信息
    .aluop_0(id_aluop_0),.alusel_0(id_alusel_0),
    .reg1_0(id_reg1_0),.reg2_0(id_reg2_0),
    .wd_0(id_wd_0),.wreg_0(id_wreg_0),
    .stallreq(stallreq_id),
    .inst_0(inst_0)
    );
    
    //通用寄存器Regfile模块例化
    Regfile regfile1(
    .clk(clk),                      .rst(rst),
    .we(wb_wreg_i),                 .waddr(wb_wd_i),
    .wdata(wb_wdata_i),             .re1(reg1_read),
    .raddr1(reg1_addr),             .rdata1(reg1_data),
    .re2(reg2_read),                .raddr2(reg2_addr),
    .rdata2(reg2_data)
    );
    
    //ID/EX模块例化
    id_ex id_ex0(
        .clk(clk),      .rst(rst),.stall(stall),
        //从译码阶段 ID 模块传递过来的信息
        .id_aluop(id_aluop_0),     .id_alusel(id_alusel_0),
        .id_reg1(id_reg1_0),       .id_reg2(id_reg2_0),
        .id_wd(id_wd_0),           .id_wreg(id_wreg_0),
         //跳转时延
         .id_link_address(link_addr_0),
         .id_is_in_delayslot(is_in_delayslot_0),
         .next_inst_in_delayslot_i(next_inst_in_delayslot_0),
         .id_inst(inst_0),
        //传递到执行阶段EX模块的信息
        .ex_aluop(ex_aluop_i),  .ex_alusel(ex_alusel_i),
        .ex_reg1(ex_reg1_i),    .ex_reg2(ex_reg2_i),
        .ex_wd(ex_wd_i),        .ex_wreg(ex_wreg_i),
        //跳转时延
        .ex_link_address(ex_link_address_i),
        .ex_is_in_delayslot(ex_is_in_delayslot_i),
        .is_in_delayslot_0(ex_is_in_delayslot_0),
        .ex_inst(ex_inst_i)
    );
    
    //EX 模块例化
    ex ex0(
    .rst(rst),
    
    // 从ID/EX 模块传递过来的信息
    .aluop_i(ex_aluop_i),       .alusel_i(ex_alusel_i),
    .reg1_i(ex_reg1_i),         .reg2_i(ex_reg2_i),
    .wd_i(ex_wd_i),             .wreg_i(ex_wreg_i),
  
    //输出到EX/MEM模块的信息
    .wd_0(ex_wd_0),             .wreg_0(ex_wreg_0),
    .wdata_0(ex_wdata_0),
    
    //hilo传递过来的值
    .hi_i(hi_0),    .lo_i(lo_0),
    .wb_hi_i(wb_hi_i),
    .wb_lo_i(wb_lo_i),
    .wb_whilo_i(wb_whilo_i),
  
    .mem_hi_i(mem_hi_0),
    .mem_lo_i(mem_lo_0),
    .mem_whilo_i(mem_whilo_0),
    
    .inst_i(ex_inst_i),
    
    .cnt_i(ex_mem_cnt_0),      
    .hilo_temp_i(ex_mem_hilo_0),   
    
    .div_result_i(div_result),            .div_ready_i(div_ready),
    .link_address_i(ex_link_address_i),
    .is_in_delayslot_i(ex_is_in_delayslot_i),
    
    .cnt_0(ex_cnt_0),           .hilo_temp_0(ex_hilo_0),
    
    .hi_0(ex_hi_0),
    .lo_0(ex_lo_0),
    .whilo_0(ex_whilo_0),
    
    .div_start_0(div_start),             .div_opdata2_0(div_opdata2),
    .div_opdata1_0(div_opdata1),           .signed_div_0(signed_div),
    .stallreq(stallreq_ex),
    .aluop_0(ex_aluop_0),
    .mem_addr_0(ex_mem_addr_0),
    .reg2_0(ex_reg2_0)
    );
    
    // EX/MEM 模块例化
    ex_mem ex_mem0(
    .clk(clk),          .rst(rst),
    .stall(stall),
    // 来自执行阶段EX模块的信息
    .ex_wd(ex_wd_0),    .ex_wreg(ex_wreg_0),
    .ex_wdata(ex_wdata_0),
    .ex_whilo(ex_whilo_0),        .ex_hi(ex_hi_0),
    .ex_lo(ex_lo_0),
    
    .cnt_i(ex_cnt_0),               .hilo_i(ex_hilo_0),
    .cnt_0(ex_mem_cnt_0),           .hilo_0(ex_mem_hilo_0),
    
    .ex_aluop(ex_aluop_0),
    .ex_mem_addr(ex_mem_addr_0),
    .ex_reg2(ex_reg2_0),
    // 送到访存阶MEM 模块的信息
    .mem_wd(mem_wd_i),  .mem_wreg(mem_wreg_i),
    .mem_wdata(mem_wdata_i),
    
    .mem_whilo(mem_whilo_i),
    .mem_hi(mem_hi_i),
    .mem_lo(mem_lo_i),
    .mem_aluop(mem_aluop),
    .mem_mem_addr(mem_mem_addr),
    .mem_reg2(mem_reg2)
    );
    
    // MEM模块例化
    mem mem0(
        .rst(rst),
        //来自EX/MEM 模块的信息
        .wd_i(mem_wd_i),     .wreg_i(mem_wreg_i),
        .wdata_i(mem_wdata_i),
        .whilo_i(mem_whilo_i),             .hi_i(mem_hi_i),
        .lo_i(mem_lo_i),
        
        .mem_data_i(ram_data_i),
        
        .aluop_i(mem_aluop),
        .mem_addr_i(mem_mem_addr),
        .reg2_i(mem_reg2),
        
        .mem_addr_0(mem_addr_0),
        .mem_we_0(mem_we_0),
        .mem_sel_0(mem_sel_0),
        .mem_data_0(mem_data_0),
        .mem_ce_0(mem_ce_0),        
        // 送到MEM/WB模块的信息
        .wd_0(mem_wd_0),        .wreg_0(mem_wreg_0),
        .wdata_0(mem_wdata_0),
        .whilo_0(mem_whilo_0),  .hi_0(mem_hi_0),
        .lo_0(mem_lo_0)
    );
    
    assign ram_addr_0 = mem_addr_0 ;
    assign  ram_data_0 = mem_data_0;
    assign ram_we_0 = mem_we_0;
    assign  ram_sel_0 = mem_sel_0;
    assign ram_ce_0 = mem_ce_0;
    //MEM/WB 模块例化
    mem_wb mem_wb0(
    .clk(clk),      .rst(rst),
    .stall(stall),
    //来自访存阶段MEM模块的信息
    .mem_wd(mem_wd_0),          .mem_wreg(mem_wreg_0),
    .mem_wdata(mem_wdata_0),
    .mem_whilo(mem_whilo_0),               .mem_hi(mem_hi_0),
    .mem_lo(mem_lo_0),
    //送到回写阶段的信息
    .wb_wd(wb_wd_i),            .wb_wreg(wb_wreg_i),
    .wb_wdata(wb_wdata_i),
    .wb_whilo(wb_whilo_i),                .wb_hi(wb_hi_i),
    .wb_lo(wb_lo_i)
    );
    hilo_reg hilo_reg0(.clk(clk),.rst(rst),.we(wb_whilo_i),.hi_i(wb_hi_i),.lo_i(wb_lo_i),.hi_0(hi_0),.lo_0(lo_0));
    ctrl ctrl0(.rst(rst),.stallreq_from_id(stallreq_id),.stallreq_from_ex(stallreq_ex),.stall(stall));
    div div0(.clk(clk),.rst(rst),.signed_div_i(signed_div),.opdata1_i(div_opdata1),.opdata2_i(div_opdata2),.start_i(div_start),
    .annul_i(1'b0),.result_0(div_result),.ready_0(div_ready));
endmodule
  1. openmips_min_sopc模块
include"defines.v"
module openmips_min_sopc(
    input   wire        clk,
    input   wire        rst
    );
    //连接指令存储器
    wire[`InstAddrBus] inst_addr;
    wire[`InstBus]     inst;
    wire               rom_ce;
    //连接ram
    wire[`RegBus]       ram_addr;
    wire[`RegBus]       ram_data_i;
    wire[`RegBus]       ram_data_o;
    wire[3:0]           ram_sel;
    wire                ram_we;
    wire                ram_ce;
    //例化处理器 OpenMIPS
    openmips openmips0(
        .clk(clk),         
        .rst(rst),  
        .rom_addr_0(inst_addr), 
        .rom_data_i(inst),
       .ram_data_i(ram_data_o),
       .ram_addr_0(ram_addr),
       .ram_data_0(ram_data_i),
       .ram_we_0(ram_we),
       .ram_sel_0(ram_sel),
       .ram_ce_0(ram_ce),
        .rom_ce_0(rom_ce)
    );
    // 例化指令存储器 ROM
    inst_rom inst_rom0(
    .ce(rom_ce),
    .addr(inst_addr),   .inst(inst)
    );
    data_ram data_ram0(.clk(clk),.addr(ram_addr),.data_i(ram_data_i),.sel(ram_sel),.we(ram_we),.ce(ram_ce),.data_0(ram_data_o));
endmodule
  1. data_ram模块
include"defines.v"
module data_ram(
    input wire clk,
    input wire  ce,
    input wire we,
    input  wire[`DataAddrBus] addr,
    input   wire[3:0]       sel,
    input   wire[`DataBus]  data_i,
    output  reg[`DataBus]   data_0
    );
    reg[`ByteWidth] data_mem0[0:`DataMemNum-1];
    reg[`ByteWidth] data_mem1[0:`DataMemNum-1];
    reg[`ByteWidth] data_mem2[0:`DataMemNum-1];
    reg[`ByteWidth] data_mem3[0:`DataMemNum-1];
    //写
    always @(posedge clk)begin
        if(ce == `ChipDisable)begin
            //data_0 <= `ZeroWord;
        end else if(we == `WriteEnable) begin
            if(sel[3] == 1'b1) begin
                data_mem3[addr[`DataMemNumLog2+1:2]] <= data_i[31:24];
            end
            if(sel[2] == 1'b1)begin
                data_mem2[addr[`DataMemNumLog2+1:2]] <= data_i[23:16];
            end
            if(sel[1] == 1'b1)begin
                data_mem1[addr[`DataMemNumLog2+1:2]] <= data_i[15:8];
            end
            if(sel[0] == 1'b1)begin
                data_mem0[addr[`DataMemNumLog2+1:2]] <= data_i[7:0];
            end
        end
    end
    //读
    always @ (*) begin
        if(ce == `ChipDisable)begin
            data_0 <= `ZeroWord;
        end else if( we == `WriteDisable)begin
            data_0 <= {data_mem3[addr[`DataMemNumLog2+1:2]],
                       data_mem2[addr[`DataMemNumLog2+1:2]],
                       data_mem1[addr[`DataMemNumLog2+1:2]],
                       data_mem0[addr[`DataMemNumLog2+1:2]]};
         end else begin
            data_0 <= `ZeroWord;
         end
        end
endmodule
  1. inst_rom模块
`include"defines.v"
module inst_rom(
    input   wire        ce,
    input   wire[`InstAddrBus] addr,
    output  reg[`InstBus]       inst
    );
    
    //定义一个数组,大小是InstMenNum,元素宽度是InstBus
   reg[`InstBus] inst_mem[0:`InstMemNum-1];
  initial $readmemh("C:\\Users\\86183\\Desktop\\mips\\inst_rom.txt",inst_mem);
  /*initial begin
    inst_mem[0] = 32'h34011100;
    inst_mem[1] = 32'h34020020;
    inst_mem[2] = 32'h3403ff00;
    inst_mem[3] = 32'h3404ffff;
  end*/
  //当复位信号无效时,依据输入的地址,给出指令存储器ROM对应的元素
  always @ (*) begin
       if(ce == `ChipDisable) begin
                inst <= `ZeroWord;
        end else begin
                inst <= inst_mem[addr[`InstMemNumLog2 +1:2]];
        end
     end  
endmodule
  1. defines 模块
define RstEnable       1'b1    //复位有效信号
`define RstDisable      1'b0        //复位信号无效
`define ZeroWord        32'h00000000    //32位的数值0
`define WriteEnable     1'b1        //使能写
`define WriteDisable    1'b0        //禁止写
`define ReadEnable      1'b1        //使能读
`define ReadDisable     1'b0       //禁止读
`define AluOpBus        7:0       // 译码阶段的输出 aluop_o的宽度
`define AluSelBus       2:0       // 译码阶段的输出 alusel_o的宽度
`define InstValid       1'b0      //指令有效
`define InstInvalid     1'b1      //指令无效    
`define True_v          1'b1      //逻辑“真”
`define False_v         1'b0      //逻辑“假” 
`define ChipEnable      1'b1      //芯片使能
`define ChipDisable     1'b0      //芯片禁止

//*******************************与具体指令有关的宏定义************************************//
`define  EXE_NOP        6'b000000
`define  EXE_AND        6'b100100    // and
`define  EXE_OR         6'b100101   //or
`define  EXE_XOR        6'b100110   //xor
`define  EXE_NOR        6'b100111   //nor
`define  EXE_ANDI       6'b001100   //andi
`define  EXE_ORI        6'b001101   //ori
`define  EXE_XORI       6'b001110   //xori
`define  EXE_LUI        6'b001111   //lui
`define  EXE_SLL        6'b000000   //sll
`define  EXE_SLLV       6'b000100   //sllv
`define  EXE_SRL        6'b000010   //sra
`define  EXE_SRLV       6'b000110   //srlv
`define  EXE_SRA        6'b000011   //sra
`define  EXE_SRAV       6'b000111   //srav
`define  EXE_SYNC       6'b001111   //sync
`define  EXE_PREF       6'b110011   //pref
`define  EXE_SPECIAL_INST   6'b000000 //special
`define  EXE_MOVZ       6'b001010   // movz
`define  EXE_MOVN       6'b001011  //  movn
`define  EXE_MFHI       6'b010000   // mfhi
`define  EXE_MTHI       6'b010001   // mthi
`define  EXE_MFLO       6'b010010   // mflo
`define  EXE_MTLO       6'b010011   // mtlo
`define  EXE_SLT        6'b101010
`define  EXE_SLTU       6'b101011
`define  EXE_SLTI       6'b001010
`define  EXE_SLTIU      6'b001011
`define  EXE_ADD        6'b100000
`define  EXE_ADDU       6'b100001
`define  EXE_SUB        6'b100010
`define  EXE_SUBU       6'b100011
`define  EXE_ADDI       6'b001000
`define  EXE_ADDIU      6'b001001
`define  EXE_CLZ        6'b100000
`define  EXE_CLO        6'b100001
`define  EXE_MULT       6'b011000
`define  EXE_MULTU      6'b011001
`define  EXE_MUL        6'b000010
`define  EXE_MADD       6'b000000
`define  EXE_MADDU      6'b000001
`define  EXE_MSUB       6'b000100
`define  EXE_MSUBU      6'b000101
`define  EXE_DIV        6'b011010
`define  EXE_DIVU       6'b011011
`define  EXE_J          6'b000010
`define  EXE_JAL        6'b000011
`define  EXE_JALR       6'b001001
`define  EXE_JR         6'b001000
`define  EXE_BEQ        6'b000100
`define  EXE_BGEZ       5'b00001
`define  EXE_BGEZAL     5'b10001
`define  EXE_BGTZ       6'b000111
`define  EXE_BLEZ       6'b000110
`define  EXE_BLTZ       5'b00000
`define  EXE_BLTZAL     5'b10000
`define  EXE_BNE        6'b000101
`define  EXE_LB         6'b100000
`define  EXE_LBU        6'b100100
`define  EXE_LH         6'b100001
`define  EXE_LHU        6'b100101
`define  EXE_LW         6'b100011
`define  EXE_LWL        6'b100010
`define  EXE_LWR        6'b100110
`define  EXE_SB         6'b101000
`define  EXE_SH         6'b101001
`define  EXE_SW         6'b101011
`define  EXE_SWL        6'b101010
`define  EXE_SWR        6'b101110
`define  EXE_REGIMM_INST    6'b000001 
`define  EXE_SPECIAL2_INST  6'b011100


//AluOp
`define EXE_NOP_OP      8'b00000000
`define  EXE_AND_OP     8'b00000001    // and
`define  EXE_OR_OP      8'b00000010   //or
`define  EXE_XOR_OP     8'b00000011   //xor
`define  EXE_NOR_OP     8'b00000100   //nor
`define  EXE_ANDI_OP    8'b00000101   //andi
`define  EXE_ORI_OP     8'b00000110   //ori
`define  EXE_XORI_OP    8'b00000111   //xori
`define  EXE_LUI_OP     8'b00001000   //lui
`define  EXE_SLL_OP     8'b00001001   //sll
`define  EXE_SLLV_OP    8'b00001010   //sllv
`define  EXE_SRL_OP     8'b00001011   //sra
`define  EXE_SRLV_OP    8'b00001100   //srlv
`define  EXE_SRA_OP     8'b00001101   //sra
`define  EXE_SRAV_OP    8'b00001110   //srav
`define  EXE_SYNC_OP    8'b00001111   //sync
`define  EXE_PREF_OP    8'b00010000   //pref
`define  EXE_SPECIAL_INST_OP    8'b00010001 //special
`define  EXE_MFHI_OP    8'b00010010
`define  EXE_MFLO_OP    8'b00010011
`define  EXE_MTHI_OP    8'b00010100
`define  EXE_MTLO_OP    8'b00010101
`define  EXE_MOVN_OP    8'b00010110
`define  EXE_MOVZ_OP    8'b00010111
`define  EXE_SLT_OP     8'b00011000
`define  EXE_SLTU_OP    8'b00011001
`define  EXE_SLTI_OP    8'b00011010
`define  EXE_SLTIU_OP   8'b00011011
`define  EXE_ADD_OP     8'b00011100
`define  EXE_ADDU_OP    8'b00011101
`define  EXE_SUB_OP     8'b00011110
`define  EXE_SUBU_OP    8'b00011111
`define  EXE_ADDI_OP    8'b00100000
`define  EXE_ADDIU_OP   8'b00100001
`define  EXE_CLZ_OP     8'b00100010
`define  EXE_CLO_OP     8'b00100011
`define  EXE_MULT_OP    8'b00100100
`define  EXE_MULTU_OP   8'b00100101
`define  EXE_MUL_OP     8'b00100110
`define  EXE_MADD_OP    8'b00100111
`define  EXE_MADDU_OP   8'b00101000
`define  EXE_MSUB_OP    8'b00101001
`define  EXE_MSUBU_OP   8'b00101010
`define  EXE_DIV_OP     8'b00101011
`define  EXE_DIVU_OP    8'b00101100
`define  EXE_J_OP       8'b00101101
`define  EXE_JAL_OP     8'b00101110
`define  EXE_JALR_OP    8'b00101111
`define  EXE_JR_OP      8'b00110000
`define  EXE_BEQ_OP     8'b00110001
`define  EXE_BGEZ_OP    8'b00110010
`define  EXE_BGEZAL_OP  8'b00110011
`define  EXE_BGTZ_OP    8'b00110100
`define  EXE_BLEZ_OP    8'b00110101
`define  EXE_BLTZ_OP    8'b00110110
`define  EXE_BLTZAL_OP  8'b00110111
`define  EXE_BNE_OP     8'b00111000
`define  EXE_LB_OP      8'b00111001
`define  EXE_LBU_OP     8'b00111010
`define  EXE_LH_OP      8'b00111011
`define  EXE_LHU_OP     8'b00111100
`define  EXE_LW_OP      8'b00111101
`define  EXE_LWL_OP     8'b00111110
`define  EXE_LWR_OP     8'b00111111
`define  EXE_SB_OP      8'b01000000
`define  EXE_SH_OP      8'b01000001
`define  EXE_SW_OP      8'b01000010
`define  EXE_SWL_OP     8'b01000011
`define  EXE_SWR_OP     8'b01000100
//AluSel
`define EXE_RES_LOGIC   3'b001
`define EXE_RES_SHIFT   3'b010
`define EXE_RES_NOP     3'b000
`define EXE_RES_MOVE    3'b011
`define EXE_RES_ARITHMETIC  3'b100
`define EXE_RES_MUL      3'b101
`define EXE_RES_JUMP_BRANCH 3'b110
`define EXE_RES_LOAD_STORE 3'b111
//**********************************与指令存储器ROM有关的宏定义***************************************//
`define InstAddrBus     31:0        //ROM的地址总线宽度
`define InstBus         31:0        //ROM的数据总线宽度
`define InstMemNum      131071      //ROM的实际大小为128KB
`define InstMemNumLog2  17          //ROM实际使用的地址线宽度
//**********************************与通用寄存器Regffile有关的宏定义****************************************//
`define RegAddrBus      4:0         //Regfile模块的地址线宽度
`define RegBus          31:0        //Regfile模块的数据线宽度
`define RegWidth        32          //通用寄存器的宽度
`define DoubleRegWidth  64          //两倍的通用寄存器的宽度
`define DoubleRegBus    63:0        //两倍的通用寄存器的数据线宽度
`define RegNum          32          //通用寄存器数量
`define RegNumLog2      5           //寻址通用寄存器使用的地址位数
`define NOPRegAddr      5'b00000    //

/************************              暂停阶段                ***/
`define Stop    1'b1
`define NoStop  1'b0

/************************               除法                   ****/
`define DivFree 2'b00
`define DivByZero   2'b01
`define DivOn   2'b10
`define DivEnd  2'b11
`define DivResultReady  1'b1
`define DivResultNotReady   1'b0
`define DivStart    1'b1
/*************************      转移     **************/
`define Branch  1'b1     //转移
`define NotBranch   1'b0 // 不转移
`define InDelaySlot 1'b1
`define NotInDelaySlot  1'b0
/*****************************   ram ******************************/
`define DataAddrBus    31:0
`define DataBus         31:0
`define DataMemNum      131071
`define DataMemNumLog2  17
`define ByteWidth   7:0
`define DivStop     1'b0


测试部分

1 逻辑指令仿真测试
1.1 MIPS 汇编代码以及对应机器码
#机器码 # 汇编代码 #运算结果
3c010101 lui $1,0x0101 #$1 = 0x01010000
34210101 ori $1,$1,0x0101 # $1 = 0x01010101
34221100 ori $2,$1,0x1100 # $2 = 0x01011101
00220825 or $1,$1,$2 # $1 = 0x01011101
302300fe andi$3,$1,0x00fe # $3 = 0x00000000
00610824 and $1,$3,$1 # $1 = 0x00000000
3824ff00 xori$4,$1,0xff00 # $4 = 0x0000ff00
00810826 xor $1,$4,$1 # $1 = 0x0000ff00
00810827 nor $1,$4,$1 # $1 = ffff00ff
1.2 仿真波形图
在这里插入图片描述

逻辑指令仿真总览图 1
【使用verilog、五级流水和MIPS指令集设计CPU】_第34张图片

逻辑指令仿真局部放大图 2

1.3 结果分析
在这里插入图片描述
MARS最终运行情况图 3
在MARS中得到的结果在7.1.1中的运算结果中有展示,图3为最终结果,对比仿真结果与MARS中得到的结果可以得知二者完全吻合,仿真波形图也符合五级流水的规则。
2 移位与空指令仿真测试
2.1 MIPS 汇编代码以及对应机器码
#机器码 #汇编代码 #运算结果
3c020404 lui $2,0x0404 #$2 = 0x04040000
34420404 ori $2,$2,0x0404#$2 = 0x04040404
34070007 ori $7,$0,0x7
34050005 ori $5,$0,0x5
34080008 ori $8,$0,0x8
00000000 nop
#################### 第一段####################
00021200 sll $2,$2,8 #$2 = 0x04040400
00e21004 sllv$2,$2,$7 #$2 = 0x02020000
00021202 srl $2,$2,8 #$2 = 0x00020200
00a21006 srlv$2,$2,$5 #$2 = 0x00001010
00000000 nop
################## 第二段 ######################
000214c0 sll $2,$2,19 #$2 = 0x80800000
00021403 sra $2,$2,16 #$2 = 0xffff8080
01021007 srav$2,$2,$8 #$2 = 0xffffff80
################## 第三段 ######################
2.2 仿真波形图
在这里插入图片描述

移位与空指令仿真总览图 4

在这里插入图片描述

移位与空指令第一段仿真图 5
在这里插入图片描述

移位与空指令第二段仿真图 6
在这里插入图片描述

移位与空指令第三段仿真图 7
2.3 结果分析
在MARS中得到的结果在7.2.1中的运算结果中有展示,对比仿真结果与MARS中得到的结果可以得知二者完全吻合,仿真波形图也符合五级流水的规则。

3 移动指令仿真测试
3.1 MIPS 汇编代码以及对应机器码
#机器码 #汇编代码 #运算结果
3c010000 lui $1,0x0000 # $1 = 0x00000000
3c02ffff lui $2,0xffff # $2 = 0xffff0000
3c030505 lui $3,0x0505 # $3 = 0x05050000
3c040000 lui $4,0x0000 # $4 = 0x00000000
0041200a movz $4,$2,$1 # $4 = 0xffff0000
0061200b movn $4,$3,$1 # $4 = 0xffff0000
0062200b movn $4,$3,$2 # $4 = 0x05050000
0043200a movz $4,$2,$3 # $4 = 0x05050000
00000011 mthi $0 # hi = 0x00000000
00400011 mthi $2 # hi = 0xffff0000
00600011 mthi $3 # hi = 0x05050000
00600013 mtlo $3 # lo = 0x05050000
00400013 mtlo $2 # lo = 0xffff0000
00200013 mtlo $1 # lo = 0x00000000
3.2 仿真波形图
【使用verilog、五级流水和MIPS指令集设计CPU】_第35张图片

移动指令仿真第一部分图
【使用verilog、五级流水和MIPS指令集设计CPU】_第36张图片

移动指令仿真第二部分图

3.3 结果分析
移动指令与8086的mov 很类似,不过mips指令的移动指令内容更加丰富,然后结果也与预期相同
4 算术指令仿真测试
4.1 MIPS 汇编代码以及对应机器码
#机器码 #汇编代码 #运算结果
34018000 ori $1,$0,0x8000 # $1 = 0x00008000
00010c00 sll $1,$1,16 # $1 = 0x80000000
34210010 ori $1,$1,0x0010 # $1 = 0x80000010
34028000 ori $2,$0,0x8000 # $2 = 0x00008000
00021400 sll $2,$2,16 # $2 = 0x80000000
34420001 ori $2,$2,0x0001 # $2 = 0x80000001
34030000 ori $3,$0,0x0000 # $3 = 0x00000000
00411821 addu $3,$2,$1 # $3 = 0x00000011
34030000 ori $3,$0,0x0000 # $3 = 0x00000000
00411820 add $3,$2,$1 # $2 + $1,有符号加法,结果溢出# $3 = 0x00000000
00231822 sub $3,$1,$3 # $3 = 0x80000010
00621823 subu $3,$3,$2 # $3 = 0xf
20630002 addi $3,$3,2 # $3 = 0x11
34030000 ori $3,$0,0x0000 # $3 = 0x00000000
24638000 addiu $3,$3,0x8000 # $3 = 0xffff8000
3401ffff or $1,$0,0xffff # $1 = 0x0000ffff
00010c00 sll $1,$1,16 # $1 = 0xffff0000
0020102a slt $2,$1,$0 # $2 = 1
0020102b sltu $2,$1,$0 # $2 = 0
28228000 slti $2,$1,0x8000 # $2 = 1
2c228000 sltiu $2,$1,0x8000 # $2 = 1
3c010000 lui $1,0x0000 # $1 = 0x00000000
70201021 clo $2,$1 # $2 = 0x00000000
70201020 clz $2,$1 # $2 = 0x00000020
3c01ffff lui $1,0xffff # $1 = 0xffff0000
3421ffff ori $1,$1,0xffff # $1 = 0xffffffff
70201020 clz $2,$1 # $2 = 0x00000000
70201021 clo $2,$1 # $2 = 0x00000020
3c01a100 lui $1,0xa100 # $1 = 0xa1000000
70201020 clz $2,$1 # $2 = 0x00000000
70201021 clo $2,$1 # $2 = 0x00000000
3c011100 lui $1,0x1100 # $1 = 0x11000000
70201020 clz $2,$1 # $2 = 0x00000003
70201021 clo $2,$1 # $2 = 0x00000000
3401ffff ori $1,$0,0xffff
00010c00 sll $1,$1,16
3421fffb ori $1,$1,0xfffb # $1 = -5
34020006 ori $2,$0,6 # $2 = 6
70221802 mul $3,$1,$2 # $3 = -30 = 0xffffffe2
00220018 mult $1,$2 # HI = 0xffffffff LO = 0xffffffe2
00220019 multu $1,$2 # HI = 0x5 LO = 0xffffffe2
00000000 nop
00000000 nop

4.2 仿真波形图
【使用verilog、五级流水和MIPS指令集设计CPU】_第37张图片

算术指令第一部分图
在这里插入图片描述

算术指令第二部分图
在这里插入图片描述

算术指令第三部分图
【使用verilog、五级流水和MIPS指令集设计CPU】_第38张图片

算术指令第四部分图
4.3 结果分析
与预期结果相符合,与运算结果相符合
5 乘累加乘累减指令仿真测试
5.1 MIPS 汇编代码以及对应机器码
#机器码 #汇编代码 #运算结果
3401ffff ori $1,$0,0xffff
00010c00 sll $1,$1,16
3421fffb ori $1,$1,0xfffb
34020006 ori $2,$0,6
00220018 mult $1,$2 # hi = 0xffffffff lo = 0xffffffe2
70220000 madd $1,$2 # hi = 0xffffffff lo = 0xffffffc4
70220001 maddu $1,$2 # hi = 0x5 lo = 0xffffffa6
70220004 msub $1,$2 # hi = 0x5 lo = 0xffffffc4
70360005 msubu $1,$22 # hi = 0xffffffff lo = 0xffffffe2
5.2 仿真波形图
在这里插入图片描述

乘累加,乘累减仿真图
5.3 结果分析
与5.1的预算结果完全吻合,且与MARS结果完全吻合
6 除法指令仿真测试
6.1 MIPS 汇编代码以及对应机器码
#机器码 #汇编代码 #运行结果
3402ffff ori $2,$0,0xffff
00021400 sll $2,$2,16
3442fff1 ori $2,$2,0xfff1 # $2 = -15
34030011 ori $3,$0,0x11 # $3 = 17
0043001a div $zero,$2,$3 # hi = 0xfffffff1 lo = 0x0
0043001b divu $zero,$2,$3 # hi = 0x00000003 lo = 0x0f0f0f0e
0062001a div $zero,$3,$2 # hi = 2 lo = 0xffffffff
00000000 nop

6.2 仿真波形图
在这里插入图片描述

除法指令仿真图
6.3 结果分析
除法指令执行周期长,因为采用的是试除法,而被除数与除数的长度都为32位,因此需要至少32个周期,如果出现除数为0的情况,div模块的状态机中也有对应状态表示该情况
7 分支指令仿真测试
7.1 MIPS 汇编代码以及对应机器码、
#机械指令 #汇编代码 #运行结果
34038000 ori $3,$0,0x8000
00031c00 sll $3,$3,16 # 设置$3 =0x80000000
34010001 ori $1,$0,0x0001 # $1 =0x1
10000003 beq $0,$0,s1 # 转移到s1处
34010002 ori $1,$0,0x0002 # $1 =0x2,这是延迟槽指令
t1:
34011111 ori $1,$0,0x1111
34011100 ori $1,$0,0x1100
s1:
34010003 ori $1,$0, 0x0003 # $1 =0x3
04110007 bgezal $0,s2 # 转移到s2处,
#同时设置$31为0×2c
03e1001a div $zero,$31,$1 # 此时$31 =0x2c, $1=0x3,
#所以除法结果为# HI =0x2,
#Lo =Oxe,这是延迟槽指令
34011100 ori $1,$0,0x1100
34011111 ori $1,$0,0x1111
1420000e bne $1, $0,s3
00000000 nop
34011100 ori $1,$0,0x1100
34011111 ori $1,$0,0x1111
s2:
34010004 ori $1,$0,0x0004 # $1=0x4
10630009 beq $3,$3,s3 # $3等于$3,所以会发生转移,
#目的地址是s3
03e00825 or $1,$31,$0 # $1= Ox2c,这是延迟槽指令
34011111 ori $1,$0,0x1111
34011100 ori $1, $0,0x1100
t2:
34010007 ori $1,$0,0x0007 # $1 =0x7
34010008 ori $1,$0,0x0008 # $1 = 0x8
1c200008 bgtz $1,s4 # 此时$1为0×8,大于0,
#所以转移至标号s4处
34010009 ori $1,$0,0x0009 # $1 =0x9,这是延迟槽指令
34011111 ori $1,$0,0x1111
34011100 ori $1,$0,0x1100

s3:
34010005 ori $1,$0,0x0005 # $1 = 0x5
0421fff8 bgez $1,t2 # 此时$1为0×5,大于0,
#所以转移至前面的标号2处
34010006 ori $1,$0,0x0006 # $1= 0x6,这是延迟槽指令
34011111 ori $1,$0,0x1111
34011100 ori $1,$0,0x1100

s4:
3401000a ori $1,$0,0x000a # $1= 0xa
0471fff9 bgezal $3,s3 # 此时$3为0x80000000,
#小于0,所以不发生转移
001f0825 or $1, $0,$31 # $1=0×10c
3401000b ori $1,$0,0x000b # $1=0xb
3401000c ori $1, $0, 0x000c # $1=0xc
3401000d ori $1, $0, 0x000d # $1 = 0xd
3401000e ori $1,$0,0x000e # $1 = Oxe
04600002 bltz $3,s5 # 此时$3为0x80000000,小于0, # 所以发生转移,转移至s5处
3401000f ori $1,$0,0x000f # $1 =0xf,这是延迟槽指令
34011100 ori $1,$0,0x1100
s5:
34010010 ori $1,$0,0x0010 # $1 = 0x10
1820ffe9 blez $1,t2 # 此时$1为0x10,大于0,
#所以不发生转移
34010011 ori $1,$0,0x0011 # $1 = 0x11
34010012 ori $1,$0,0x0012 # $1 = 0x12
34010013 ori $1,$0,0x0013 # $1 = 0x13
04700002 bltzal $3,s6 # 此时$3为0x80000000,小于0, # 所以发生转移,转移到s6处
001f0825 or $1,$0,$31 # $1 = 0x14c,这是延迟槽指令
34011100 ori $1,$0,0x1100
s6:
34010014 ori $1,$0,0x0014 # $1 = 0x14
00000000 nop

7.2 仿真波形图

在这里插入图片描述

分支指令仿真第一部分图
在这里插入图片描述

分支指令仿真第二部分图
在这里插入图片描述

分支指令仿真第三部分图

在这里插入图片描述

分支指令仿真第四部分图
在这里插入图片描述

分支指令仿真第五部分图
7.3 结果分析
分支有别于跳转,分支跳转时跳转的位置是相对于当前执行的指令的地址的下一条指令地址
7.8 跳转指令仿真测试
7.8.1 MIPS 汇编代码以及对应机器码
#机器码   #汇编代码 #运算结果
34010001 ori $1,$0,0x0001 # $1 = 0x1
08000005 j $1 # 转移到$1处
34010002 ori $1,$0,0x0002 # $1 =0x2,这是延迟槽指令
34011111 ori $1,$0,0x1111
34011100 ori $1,$0,0x1100
s1:
34010003 ori $1,$0,0x0003 # $1 =0x3
0c00000d jal s2   # 转移到$2处
#同时设置$31为0x2c
03e1001a div $zero,$31,$1 # 此时$31 =0x20, $1 =0x3,
#所以得到除法结果
#HI =0x2,LO =0xa,这是延迟槽指令
00000000 nop
34010005 ori $1,$0,0x0005 # $1=0x5
34010006 ori $1,$0,0x0006 # $1=0x6
08000013 j s3 # 转移到s3处
00000000 nop
s2:
03e01009 jalr $2,$31   # 此时$31为0x20,
#所以转移到0×20,同时设置
#$20x3c
00400825 or $1,$2,$0 # $1=0x3c,这是延迟槽指令
34010009 ori $1,$0,0x0009 # $1 =0x9
3401000a ori $1,$0,0x000a # $1 =Oxa
08000019 j s4 # 转移到s4处
00000000 nop
s3:
34010007 ori $1,$0,0x0007 # $1 = 0x7
00400008 jr $2 # 此时$2为0x3c,
#所以转移到0x3c处
34010008 ori $1,$0,0x0008 # $1 = 0x8,这是延迟槽指令
34011111 ori $1,$0,0x1111
34011100 ori $1,$0,0x1100
s4:
00000000 nop
8.2 仿真波形图
在这里插入图片描述
【使用verilog、五级流水和MIPS指令集设计CPU】_第39张图片

跳转指令仿真第一部分图
【使用verilog、五级流水和MIPS指令集设计CPU】_第40张图片

跳转指令仿真第二部分图
【使用verilog、五级流水和MIPS指令集设计CPU】_第41张图片

跳转指令仿真第三部分图
8.3 结果分析
因为跳转指令在执行时,不会立马跳转而是先执行指令槽指令,就是跳转指令下一条指令,然后在跳转,仿真结果正确,与MARS运行结果不同,因为起始地址从0x00003000开始的,而本MIPSCPU初始地址是从0x00000000开始的,但是将对应位置更改过后,能正常运行
9. 存储加载指令仿真测试
9.1 MIPS 汇编代码以及对应机器码
#机器码 #汇编代码 #运算结果
#####################第一段:测试sb、 lb、lbu指令############
3403eeff ori $3,$0,0xeeff # $3 =0x0000eeff
a0030003 sb $3,0x3($0) # 向RAM地址0x3处存储0xff,
#[0x3] = 0xff
00031a02 srl $3,$3,8 # 逻辑右移8位,$3 = 0x000000ee
a0030002 sb $3,0x2($0) # 向RAM地址0x2处存储0xee,
#[0x2] = 0xee
3403ccdd ori $3,$0,0xccdd # $3 =0x0000ccdd
a0030001 sb $3,0x1($0) # 向RAM地址0x1处存储0xdd,
#[0x1] = 0xdd
00031a02 srl $3,$3,8 # 逻辑右移8位,$3 =0x000000cc
a0030000 sb $3,0x0($0) # 向RAM地址0x0处存储0xcc,
#[0x0] = 0xcc
80010003 lb $1,0x3($0) # 加载0x3处的字节并作符号扩展,
#$1 =0xffffffff
90010002 lbu $1,0x2($0) # 并加载0×2处的字节并作无符号扩展,
#$1 = 0x000000ee
###################第二段:测试sh、lh、 lhu指令##########
3403aabb ori $3,$0,0xaabb # $3=0x0000aabb
a4030004 sh $3,0x4($0) # 向RAM地址0x4处存储0xaabb,
# [0x4]=0xaa, [0x5] = 0xbb
94010004 lhu $1,0x4($0) # 加载0x4处的半字并作无符号扩展,
#$1 = 0x0000aabb
84010004 lh $1,0x4($0) # 加载0x4处的半字并作符号扩展,
#$1 = 0xffffaabb
34038899 ori $3,$0,0x8899 # $3 = 0x00008899
a4030006 sh $3,0x6($0) # 向RAM地址0x6处存储0x8899,
#[0x6] = 0x88,
#[0x7] = 0x99
84010006 lh $1,0x6($0) # 加载0x6处的半字并作符号扩展,
#$1 = 0xffff8899
94010006 lhu $1,0x6($0) # 加载0x6处的半字并作无符号扩展,
#$1 = 0x00008899
##################第三段:测试sw、lw、lwl、 lwr##############
# 经过上面指令的执行,此时RAM的内容如下
# [0x0] = 0xcc, [0x1] = 0xdd
# [0x2] = 0xee, [0x3] = 0xff
# [0x4] = 0xaa, [0x5] = 0xbb
# [0x6] = 0x88, [0x7] = 0x99
34034455 ori $3,$0,0x4455
00031c00 sll $3,$3,0x10
34636677 ori $3,$3,0x6677 # $3 = 0x44556677
ac030008 sw $3,0x8 ($0) # 向RAM地址0x8处存储0x44556677,
# [0x8]= 0x44,[0x9] =0x55,
# [0xa] = 0x66,[0xb]= 0x77
8c010008 lw $1,0x8($0) # 加载0x8处的字,$1 =0x44556677
88010005 lwl $1,0x5($0) # 非对齐加载指令1wl,执行后使得
#$1 =0xbb889977
98010008 lwr $1,0x8($0) # 非对齐加载指令1wr,
#执行后使得$1 = 0xbb889900
00000000 nop
############## 第四段:测试swl、swr指令###############
b8010002 swr $1,0x2($0) # 非对齐存储指令swr,执行效果如下
# [0x0]=0x88, [0x1] =0x99,
# [0x2]=0x44,[0x3]= 0xff
a8010007 swl $1,0x7($0) # 非对齐存储指令swl,执行效果如下
# [0x4]=0xaa,[0x5] = 0xbb,
# [0x6]=0x88,[0x7] = 0xbb
8c010000 lw $1,0x0($0) # 加载RAM地址0x0处的字,
#$1= 0x000044ff,
# 验证swr指令的执行效果
8c010004 lw $1,0x4($0) # 加载RAM地址0x4处的字,
#$1 = 0xaabb8800,
9.2 仿真波形图
【使用verilog、五级流水和MIPS指令集设计CPU】_第42张图片

存储加载指令仿真第一部分图
【使用verilog、五级流水和MIPS指令集设计CPU】_第43张图片

存储加载指令仿真第二部分图
【使用verilog、五级流水和MIPS指令集设计CPU】_第44张图片

存储加载指令仿真第三部分图

9.3 结果分析

结果与MARS不太一样因为我这写的是大端法存储,Mars是小端法,所以数据不同

总结

  1. 数据冲突解决方式
    流水线结构紧密,每一条指令基本上参与绝大部分的模块,执行效率很高,不过也有一些问题,因为流水线每一个周期在正常情况下都会读取一个指令,然后很容易出现相邻指令共用同一个寄存器的现象,比如 ori $1,$2,0x12,和 ori $3,$1,0x15,因为前一个指令最后需要把值存入$1寄存器中,但是因为第二条指令访问$1寄存器的时候,第一条指令还未将结果写回,
    间隔相邻指令之间也存在这样的情况。
    在这里插入图片描述
    在这里插入图片描述

    我采用了这样的方式规避间隔相邻指令数据冲突的问题,这是一个判断,如果发现当前要读取的寄存 器和下一个时钟上升沿要写入的数据相同则可以把该数据赋值给输出数据。
    而相邻情况总共有三种解决方法:1.插入暂停周期,2.编译器调度,3.数据前推
    我采用的是比较简单的第三种方式数据前推的方式来解决该方法,不过这样该方法需要一个前提就是 新的寄存器的值可以在执行阶段计算出来,然而加载指令不满足,因为加载指令是在访存阶段执行的。解决方法在第五部分也是有体现的,就是将ex模块传入ex_mem的wdata_0 以及 wd_0、wreg_0 回传到id模块,MEM模块也是如此将送到mem_wb模块的
    wdata_0 以及 wd_0、wreg_0 回传到id模块,在id模块中添加一些新的判断,如果待读取的内容和上面二者之一符合就将这其数据送到对应的输出数据中去。

  2. 暂停流水线模块小结
    为了执行div,divu,madd,maddu,msub,msubu这些指令需要添加暂停流水线模块ctrl模块
    该模块在前面第三部分有描述,当在执行阶段执行上述指令时ex模块会发出通向ctrl模块的请求暂停信号,然后计算完成过后就会恢复流水线的流通,该内容的实现过程如下描述:
    首先以madd为例,madd是将{HO,LO}<- rs * rt + {HO,LO},当执行阶段读取到该指令是madd时,因为ex模块内敏感参数列表是全部输入信号,意思是当ex_mem模块有回传的信号和数据,或者id_ex有送来的信号和数据,只要导致了输入端的信号或者数据发生了变化ex模块就会执行,首先送来的数据有两个操作数,这两个操作数是从rs和rt寄存器中读取的数据,这两个操作数会最先被转换为补码,然后直接进行乘法运算,该内容在ex模块中有十分详细的介绍,进行乘法运算过后(极短时间内完成),就会执行
    1.{HI,LO}<=从mem,mem_wb,hilo 这三个模块回写的hi,lo的值,2.
    2.然后进入了madd的开始阶段,mulres赋值给hilo_temp_0,设置st allreq_for_madd_msub = 1,初始化hilo_temp1并且将cnt_0的值改变为2’b01;
    3.因为stallreq_for_madd_msub = 1,所以导致stallreq的值为1,因此改变了ctrl模块 的值,让ctrl输出了stall对应的信号,stall = 6’b001111
    然后下一个周期的时钟上升沿到来时,送到ex_mem的cnt_0,和hilo_temp_0回送到ex模块,然后此时stall的信号已经暂停了取指,译码,执行三阶段的进行,访存和回写继续进行,这导致从前面模块过来的大部分数据是保持不变的,比如指令的值,pc的值,这样的话进入ex模块的信号还是madd的信号,因此上面的三个步骤又会执行一次,HI,LO的值就绪,因为 cnt_i = 2’b01所以进入了第二阶段,完成了计算,并且向ctrl模块传达了取消暂停的信号,当下一个周期到来时,流水线又恢复了正常 ,div等也是这样

  3. 其他情况说明
    因为mars 通过任务书的要求得到是指令存储地址从 0x00003000开始的一些列机器码,所以针对这种情况有两种解决方法
    1.配合mars的起始地址,更改处理器的初始地址
    2.更改生成的机器码
    第一种方式难度较大,因为目前无办法让从txt文本读取的指令从0x00003000开始存,有一些比较小道的方法就是只取pc前10位来取指令,这样造成的问题就是指令条数不能超过256条,否则会出现错误,所以权衡下我还是使用第二种方法,第二种方法其实需要更改的内容不多,因为只要j指令会用到具体的指令存储地址,分支指令用的是相对偏移地址,所以真正需要修改的内容不多。
    其次就是mars采用的小端法存储数据,而这里采用的是大端法存储数据,因为写得太早已经成型,后期无时间修改

参考文献

雷思磊.自己动手写CPU. 北京: 电子工业出版社.2014.9

备注

代码仍然存在部分bug,分支指令和其他指令进行了较为复杂的搭配时会出现一些费解的bug,在短暂的课设期间没有查明原因,现在暂时没有时间进行debug,需要工程文件和测试用的机器指令可以留言。

你可能感兴趣的:(嵌入式相关,fpga开发)