> 文档中心 > 【使用verilog、五级流水和MIPS指令集设计CPU】

【使用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

设计内容

(https://img-blog.csdnimg.cn/3cbf7c79007041608ff7df4a93824ad2.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAZGVhcnpjcw==,size_20,color_FFFFFF,t_70,g_se,x_16)

(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 模块定义
在这里插入图片描述
2.data_ram模块定义
在这里插入图片描述
3.div模块定义
在这里插入图片描述
【使用verilog、五级流水和MIPS指令集设计CPU】
4.ex模块定义
在这里插入图片描述
在这里插入图片描述
5.ex_mem模块定义
在这里插入图片描述
6.hilo_reg模块定义
在这里插入图片描述
7.id模块定义
在这里插入图片描述
【使用verilog、五级流水和MIPS指令集设计CPU】
8.id_ex模块定义
在这里插入图片描述
【使用verilog、五级流水和MIPS指令集设计CPU】
9.if_id模块定义
在这里插入图片描述
10.inst_rom模块定义
在这里插入图片描述
11.mem模块定义
在这里插入图片描述
12.mem_wb模块定义
在这里插入图片描述
13.openmips模块定义
在这里插入图片描述
14.openmips_min_sopc模块定义
在这里插入图片描述
15.pc_reg模块定义
在这里插入图片描述
16.Regfile模块定义
在这里插入图片描述

处理器的操作过程

  1. 逻辑以及移位指令操作过程
    在这里插入图片描述
    逻辑以及移位指令结构图

    在这里插入图片描述
    逻辑以及移位指令数据流图

  2. 移动指令操作过程
    在这里插入图片描述
    移动指令结构图

在这里插入图片描述
移动指令数据流图

  1. 算术指令操作过程

在这里插入图片描述

算术指令数据流图

在这里插入图片描述

除法状态转换图

在这里插入图片描述

试除法流程图

在这里插入图片描述

暂停流水结构图
  1. 转移指令操作过程
    在这里插入图片描述

    转移指令结构图

在这里插入图片描述

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

在这里插入图片描述

加载存储指令结构图 

在这里插入图片描述

加载存储指令数据流图 

代码

  1. pc_reg 模块
`include"defines.v"module pc_reg(input wire  clk,input wire  rst,input wire[5:0] stall,//来自控制模块的ctrlinput 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    endendmodule
  1. if_id 模块
`include"defines.v"module if_id(input  wire clk,input  wire rst,input wire[5:0] stall,// 来自取指阶段的信号,其中宏定义InstBus表示指令宽度,为32input 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    endendmodule
  1. Regfile 模块
`include"defines.v"module Regfile(    input wire clk,    input wire  rst,    //写端口    input wirewe,    input wire[`RegAddrBus] waddr,    input wire[`RegBus]     wdata,    //读端口    input wirere1,    input wire[`RegAddrBus]raddr1,    output reg[`RegBus]    rdata1,    //读端口    input wirere2,    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     endendmodule
  1. if_id 模块
include"defines.v"module if_id(input  wire clk,input  wire rst,input wire[5:0] stall,// 来自取指阶段的信号,其中宏定义InstBus表示指令宽度,为32input 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    endendmodule
  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 wirestallreq,    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:begincase(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)beginbranch_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)beginbranch_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)beginbranch_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)beginbranch_target_address_0     <=  pc_plus_4 + imm_sll2_signedext;branch_flag_0   <=  `Branch;next_inst_in_delayslot_0 <= `InDelaySlot;   endenddefault:beginend      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  endendcaseif(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   endend   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    endEndmodule
  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 wireid_wreg, //跳转时延    input wire[`RegBus]     id_link_address,    input      id_is_in_delayslot,    input wirenext_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 regex_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      endEndmodule
  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 wirewreg_i,    // 执行的结果    output reg[`RegAddrBus]  wd_0,    output regwreg_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 wirewb_whilo_i,    //访存阶段的指令是否要写 HI,LO,用于检测HI,LO寄存器带来的数据相关问题    input wire[`RegBus]     mem_hi_i,    input wire[`RegBus]     mem_lo_i,    input wiremem_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 regwhilo_0, //到除法模块的输出    output reg[`RegBus]     div_opdata1_0,    output reg[`RegBus]     div_opdata2_0,    output regdiv_start_0,    output regsigned_div_0, output regstallreq,    //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:beginarithmeticres <= (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  endcaseend    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;  endend 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   endendcase     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;  endendcase      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 > reg1_i[4:0];   end   `EXE_SRA_OP:begin      shiftres <= ({32{reg2_i[31]}} <> reg1_i[4:0];   end   default:begin      shiftres <= `ZeroWord;   endendcase    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: beginwdata_0 <= `ZeroWord;     end   endcase endalways @ (*) 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;  endend`EXE_MSUB_OP,`EXE_MSUBU_OP:begin   if(cnt_i == 2'b00)beginhilo_temp_0 <= ~mulres + 1;cnt_0<= 2'b01;stallreq_for_madd_msub <= `Stop;     end else if(cnt_i == 2'b01)beginhilo_temp_0 <= {`ZeroWord,`ZeroWord};cnt_0 <= 2'b10;hilo_temp1 <= hilo_temp_i + {HI,LO};stallreq_for_madd_msub <= `NoStop;      end     end   default:beginhilo_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  endcaseend    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   endendmodule
  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)begintemp_op1 = ~opdata1_i + 1;    end else begintemp_op1 = opdata1_i;    end    if(signed_div_i == 1'b1 && opdata2_i[31] == 1'b1)begintemp_op2 = ~opdata2_i + 1;    end else begintemp_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)beginif(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:beginresult_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  endend 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 wireex_wreg,    input wire[`RegBus]     ex_wdata,    input wire[`RegBus]     ex_hi,    input wire[`RegBus]     ex_lo,    input wireex_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 regmem_wreg,    output reg[`RegBus]     mem_wdata,    output reg[`RegBus]     mem_hi,    output reg[`RegBus]     mem_lo,    output regmem_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;  endendendmodule
  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 endEndmodule
  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    endEndmodule
  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;    wiremem_we_0;    wire[3:0]  mem_sel_0;    wire[`RegBus]     mem_data_0;    wiremem_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 endendmodule
  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 @ (*) beginif(ce == `ChipDisable) begin  inst <= `ZeroWord; end else begin  inst <= inst_mem[addr[`InstMemNumLog2 +1:2]]; end     end  endmodule
  1. defines 模块
define RstEnable1'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 AluSelBus2:0// 译码阶段的输出 alusel_o的宽度`define InstValid1'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_ANDI6'b001100   //andi`define  EXE_ORI 6'b001101   //ori`define  EXE_XORI6'b001110   //xori`define  EXE_LUI 6'b001111   //lui`define  EXE_SLL 6'b000000   //sll`define  EXE_SLLV6'b000100   //sllv`define  EXE_SRL 6'b000010   //sra`define  EXE_SRLV6'b000110   //srlv`define  EXE_SRA 6'b000011   //sra`define  EXE_SRAV6'b000111   //srav`define  EXE_SYNC6'b001111   //sync`define  EXE_PREF6'b110011   //pref`define  EXE_SPECIAL_INST   6'b000000 //special`define  EXE_MOVZ6'b001010   // movz`define  EXE_MOVN6'b001011  //  movn`define  EXE_MFHI6'b010000   // mfhi`define  EXE_MTHI6'b010001   // mthi`define  EXE_MFLO6'b010010   // mflo`define  EXE_MTLO6'b010011   // mtlo`define  EXE_SLT 6'b101010`define  EXE_SLTU6'b101011`define  EXE_SLTI6'b001010`define  EXE_SLTIU      6'b001011`define  EXE_ADD 6'b100000`define  EXE_ADDU6'b100001`define  EXE_SUB 6'b100010`define  EXE_SUBU6'b100011`define  EXE_ADDI6'b001000`define  EXE_ADDIU      6'b001001`define  EXE_CLZ 6'b100000`define  EXE_CLO 6'b100001`define  EXE_MULT6'b011000`define  EXE_MULTU      6'b011001`define  EXE_MUL 6'b000010`define  EXE_MADD6'b000000`define  EXE_MADDU      6'b000001`define  EXE_MSUB6'b000100`define  EXE_MSUBU      6'b000101`define  EXE_DIV 6'b011010`define  EXE_DIVU6'b011011`define  EXE_J   6'b000010`define  EXE_JAL 6'b000011`define  EXE_JALR6'b001001`define  EXE_JR  6'b001000`define  EXE_BEQ 6'b000100`define  EXE_BGEZ5'b00001`define  EXE_BGEZAL     5'b10001`define  EXE_BGTZ6'b000111`define  EXE_BLEZ6'b000110`define  EXE_BLTZ5'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_OP8'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 仿真波形图
【使用verilog、五级流水和MIPS指令集设计CPU】

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

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

1.3 结果分析
【使用verilog、五级流水和MIPS指令集设计CPU】
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 仿真波形图
【使用verilog、五级流水和MIPS指令集设计CPU】

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

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

移位与空指令第一段仿真图 5
【使用verilog、五级流水和MIPS指令集设计CPU】

移位与空指令第二段仿真图 6
【使用verilog、五级流水和MIPS指令集设计CPU】

移位与空指令第三段仿真图 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】

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

移动指令仿真第二部分图

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】

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

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

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

算术指令第四部分图
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 仿真波形图
【使用verilog、五级流水和MIPS指令集设计CPU】

乘累加,乘累减仿真图
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 仿真波形图
【使用verilog、五级流水和MIPS指令集设计CPU】

除法指令仿真图
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 仿真波形图

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

分支指令仿真第一部分图
【使用verilog、五级流水和MIPS指令集设计CPU】

分支指令仿真第二部分图
【使用verilog、五级流水和MIPS指令集设计CPU】

分支指令仿真第三部分图

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

分支指令仿真第四部分图
【使用verilog、五级流水和MIPS指令集设计CPU】

分支指令仿真第五部分图
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】

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

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

跳转指令仿真第三部分图
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】

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

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

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

9.3 结果分析

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

创建一个表格

一个简单的表格是这么创建的:

项目 Value
电脑 $1600
手机 $12
导管 $1

总结

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

    我采用了这样的方式规避间隔相邻指令数据冲突的问题,这是一个判断,如果发现当前要读取的寄存 器和下一个时钟上升沿要写入的数据相同则可以把该数据赋值给输出数据。
    而相邻情况总共有三种解决方法: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,需要工程文件和测试用的机器指令可以留言。