目标

修改之前一直做测试的sopc,为其添加数据RAM,测试一般加载指令的实现,加入特殊加载存储指令。
探讨由于加载指令引起的load相关问题,给出OpenMIPS的解决方法,验证解决效果。

加载存储指令说明

31-26 25-21 20-16 15-0 useage function
LB(100000) base rt offset lb rt,offset(base) 从内存中指定的地址处,读取一个字节,然后符号扩展至32位,保存到地址为rt的通用寄存器中
LBU(100100) base rt offset lbu rt,offset(base) 同上,有符号改为无符号
LH(100001) base rt offset lh rt,offset(base) 从内存中指定的加载地址处读取一个半字,然后符号扩展到32位,保存到地址为rt的通用寄存器中。该指令有地址对齐要求,要求加载地址的最低位为0
LHU(100101) base rt offset lhu rt,offset(base) 同上,有符号改为无符号
LW(100011) base rt offset lw rt,offset(base) 从内存中指定的加载地址处,读取一个字,保存到地址为rt的通用寄存器中,该指令有地址对齐要求,要求加载地址的最低两位为00

加载地址 = signed_extended(offset) + GPR[base]
先将16位的offset符号扩展至32位,然后与地址为base的通用寄存器的值相加,即可得到加载地址

存储指令说明

31-26 25-21 20-16 15-0 useage function
SB(101000) base rt offset sb rt,offset(base) 将地址为rt的通用寄存器的最低字节存储到内存中的指定地址
SH(101001) base rt offset sh rt,offset(base) 将地址为rt的通用寄存器的 最低两个字节存储 到内存中的指定地址。 该指令有地址对齐要求,要求计算出来的存储地址的最低位为0
SW(101011) base rt offset sw rt,offset(base) 将地址为rt的通用寄存器的值存储到内存中的指定地址。该指令有地址对齐要求,要求计算出来的存储地址的最低两位为00

存储地址 = signed_extended(offset) + GPR[base]
先将16位的offset符号扩展至32位,然后与地址为base的通用寄存器的值相加,即可得到存储地址

加载存储指令用法示例

按字节寻址,在大端模式下,数据的高位保存在存储器的低地址中,数据的低位保存在存储器的高地址中。
使用sb指令在0x50处存储0x81数据的高位保存在存储器的低地址中。

使用sh指令在0x54处存储0x8281。数据的低位保存在高地址中。

使用sw指令在0x58处存储0x84838281

下面使用加载指令

  • 使用lbu在0x58处加载一个字节。读出的字节为0x84,无符号扩展到32位0x00000084。
  • 使用lb从0x58处加载一个字节。读出的字节为0x84,有符号扩展到32位0xffffff84。
  • 使用lhu从0x58处加载一个半字。读出的字节为半字是(32位Cpu中,一个字是4个字节,半字就是2个字节)。读出的字节为0x8483。无符号扩展到32位为0x00008483
  • 使用lh从0x5a处加载一个半字,读取2个字节,读出的字节是0x8281,该指令有地址对齐要求,要求加载地址的最低为位0,此时是1,不符合要求。

加载指令lwl,lwr说明

31-26 25-21 20-16 15-0 useage function
LWL(100010) base rt offset lwl rt,offset(base) 从内存指定的加载地址处,加载一个字的最高有效部分,没有地址对齐要求。
LWR(100110) base rt offset lwr rt,offset(base) 从内存中指定的加载地址处,加载一个字的最低有效部分,没有地址对齐要求。

lwl计算方法:

此处是大端模式下的效果
加载地址loadaddr = signed_extended(offset)+GPR[base]
n = loadaddr[1:0]
loadaddr_align = loadaddr - n;

lwl指令作用是从地址为loadaddr_align处加载一个字,4个字节,将这个字的最低4-n个字节保存到地址为rt的通用寄存器的高位,保持低位不变。
lwl $1,5($0) rt = $1

lwr计算方法:

加载地址loadaddr = signed_extended(offset)+GPR[base]
n = loadaddr[1:0]
loaddr_align =loadaddr - n;

lwr指令作用是从地址为loadaddr_align处加载一个字,4个字节,将这个字的最高n+1个字节保存到地址为rt的通用寄存器的低位,保持高位不变。

lwl,lwr指令配合可以实现一个非对齐地址加载一个字,而且只需要使用2条指令

存储指令的说明

31-26 25-21 20-16 15-0 useage function
SWL(101010) base rt offset swl rt,offset(base) 将地址为rt的通用寄存器的高位部分存储到内存中指定的地址,存储地址最后两位确定了要存储的rt通用寄存器的哪几个字节,swl指令对存储指令没有对齐要求(将地址为rt的通用寄存器的最高4-n个字节存储到storeaddr)
SWR(101110) base rt offset swr rt,offset(base) 非对齐指令,向右存储。将地址为rt的通用寄存器的低位部分存储到内存中的指定地址, 存储地址的最后两位确定了要存储rt通用寄存器的哪几个字节(将地址为rt的通用寄存器的最低n+1字节存储到storeaddr)
***storeaddr =signed_extended(offset) + GPR[base]
n=storeaddr[1:0]
storeaddr_align=storeaddr-n***
除了将加载改为存储外,其他都一样。

加载存储指令实现思路

加载指令在译码阶段译码,得到运算类型和子运算类型,以及要存储的数据。将这些信息传输到执行阶段,然后送到访存阶段,访存阶段根据这些信息,设置对数据存储器RAM的访问信号。从RAM读取回来的数据需要按照加载指令的类型、加载地址进行对齐调整,调整后的结果作为最终结果写入目的寄存器

数据流图的修改

与之前相比,在访存阶段加了对数据存储器RAM的访问。同时由于写入的目的寄存器的数据可能是执行阶段的结果,也可能是访存阶段从RAM中加载得出的数据。所以在访存阶段增加一个选择器,就进行选择。

系统结构的修改

代码模块的修改

译码阶段

id.v

译码阶段ID增加输出信号inst_o 译码阶段的指令,该值会传递到执行阶段,在ex模块利用该信号的值(译码阶段的指令),计算加载、存储地址mem_addr_o。

`include "define.v"
module id(input wire                                        rst,input wire[`InstAddrBus]           pc_i,input wire[`InstBus]          inst_i,input wire[`RegBus]           reg1_data_i,input wire[`RegBus]           reg2_data_i,input wire is_in_delayslot_i,//是否位于延迟槽指令//送到regfile的信息output reg                    reg1_read_o,output reg                    reg2_read_o,     output reg[`RegAddrBus]       reg1_addr_o,output reg[`RegAddrBus]       reg2_addr_o,        //送到执行阶段的信息output reg[`AluOpBus]         aluop_o,output reg[`AluSelBus]        alusel_o,output reg[`RegBus]           reg1_o,output reg[`RegBus]           reg2_o,output reg[`RegAddrBus]       wd_o,output reg                    wreg_o,//处于执行阶段的指令的运算结果input wire ex_wreg_i,input wire[`RegBus] ex_wdata_i,input wire[`RegAddrBus] ex_wd_i,input wire[`AluOpBus] ex_aluop_i,//处于访存阶段的指令的运算结果input wire mem_wreg_i,input wire[`RegBus] mem_wdata_i,input wire[`RegAddrBus] mem_wd_i,output wire stallreq,output reg next_inst_in_delayslot_o,//下条指令是否是延迟槽output reg branch_flag_o,//是否发生转移output reg[`RegBus] branch_target_address_o,//转移到的目标地址output reg[`RegBus] link_addr_o,//转移指令要保存的返回地址output reg is_in_delayslot_o,//当前处于译码指令是否位于延迟槽output wire[`RegBus] inst_o //新增加的输出接口
);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;//对应分支指令中offset左移两位,再符号扩展至32位的值reg[`RegBus]   imm;reg instvalid;assign stallreq = `NoStop;//在实现加载、存储指令时会给该信号赋值assign imm_sll2_signedext = {{14{inst_i[15]}},inst_i[15:0],2'b00};//imm_sll2_signedext对应分支指令中的offset左移两位,再符号扩展至32位的值assign pc_plus_8 = pc_i+8;assign pc_plus_4 = pc_i+4;assign stallreq = `NoStop;assign inst_o = inst_i;//译码阶段的指令always @ (*) begin if (rst == `RstEnable) beginaluop_o <= `EXE_NOP_OP;alusel_o <= `EXE_RES_NOP;//nopwd_o <= `NOPRegAddr;wreg_o <= `WriteDisable;instvalid <= `InstValid;reg1_read_o <= 1'b0;reg2_read_o <= 1'b0;reg1_addr_o <= `NOPRegAddr;reg2_addr_o <= `NOPRegAddr;imm <= 32'h0;       link_addr_o <= `ZeroWord;//转移指令要保存的返回地址branch_target_address_o <= `ZeroWord;//转移到的目标地址branch_flag_o <= `NotBranch;//不发生转移next_inst_in_delayslot_o <= `NotInDelaySlot;//下一条指令是否位于延迟槽 end else begin //先初始化aluop_o <= `EXE_NOP_OP;alusel_o <= `EXE_RES_NOP;wd_o <= inst_i[15:11];wreg_o <= `WriteDisable;instvalid <= `InstInvalid;      reg1_read_o <= 1'b0;reg2_read_o <= 1'b0;reg1_addr_o <= inst_i[25:21];//rsreg2_addr_o <= inst_i[20:16];//rtimm <= `ZeroWord;       link_addr_o <= `ZeroWord;branch_target_address_o <= `ZeroWord;branch_flag_o <= `NotBranch;next_inst_in_delayslot_o <= `NotInDelaySlot;  case (op)//指令码`EXE_SPECIAL_INST: begin //指令码是SPECIALcase(op2)//功能码5'b00000: begincase(op3) //依据功能码判断是哪一个指令`EXE_OR: begin //or R型指令 rs|rt -> rdwreg_o <= `WriteEnable;aluop_o <= `EXE_OR_OP;alusel_o <= `EXE_RES_LOGIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_AND:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_AND_OP;//R rs&rt ->rdalusel_o <=  `EXE_RES_LOGIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_XOR:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_XOR_OP;// R rs^rt ->rdalusel_o <= `EXE_RES_LOGIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_NOR:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_NOR_OP;// R rs~|rt ->rdalusel_o <= `EXE_RES_LOGIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_SLLV:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_SLL_OP; alusel_o <= `EXE_RES_SHIFT;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_SRLV:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_SRLV_OP;alusel_o <= `EXE_RES_SHIFT;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_SRAV:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_SRAV_OP;alusel_o <= `EXE_RES_SHIFT;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_SYNC:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_NOP_OP;alusel_o <= `EXE_RES_NOP;reg1_read_o <= 1'b0;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_MFHI:begin//将特殊寄存器hi的值赋给地址为rd的寄存器wreg_o <= `WriteEnable;aluop_o <= `EXE_MFHI_OP;alusel_o <= `EXE_RES_MOVE;reg1_read_o <= 1'b0;reg2_read_o <= 1'b0;instvalid <= `InstValid;end`EXE_MFLO:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_MFLO_OP;alusel_o <= `EXE_RES_MOVE;reg1_read_o <= 1'b0;reg2_read_o <= 1'b0;instvalid <= `InstValid;end`EXE_MTHI:begin//hi<-rs 写特殊寄存器wreg_o <= `WriteEnable;aluop_o <= `EXE_MTHI_OP;alusel_o <= `EXE_RES_MOVE;reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;instvalid <= `InstValid;end`EXE_MTLO:begin //lo<-rs 写特殊寄存器wreg_o <= `WriteEnable;aluop_o <= `EXE_MTLO_OP;reg1_read_o <= 1'b1;//rsreg2_read_o <= 1'b0;instvalid <= `InstValid;end`EXE_MOVN:begin//判断rt寄存器的值 如果不为0 将rs的值赋给rd 反之rd值不变//wreg_o <= `WriteEnable;aluop_o <= `EXE_MOVN_OP;alusel_o <= `EXE_RES_MOVE;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;//reg2_o的值就是地址为rt的寄存器的值if(reg2_o != `ZeroWord)beginwreg_o <= `WriteEnable;end else beginwreg_o <= `WriteDisable;endend`EXE_MOVZ:begin //判断rt寄存器的值 如果是0 将rs的值赋给rd 反之rd值不变aluop_o <= `EXE_MOVZ_OP;alusel_o <= `EXE_RES_MOVE;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;if(reg2_o == `ZeroWord)beginwreg_o <= `WriteEnable;end else beginwreg_o <= `WriteDisable;end end`EXE_SLT:begin//slt指令 rd<-(rs<rt)wreg_o <= `WriteEnable;aluop_o <= `EXE_SLT_OP;alusel_o <= `EXE_RES_ARITHMETIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_SLTU:begin //sltu指令wreg_o <= `WriteEnable;aluop_o <= `EXE_SLTU_OP;alusel_o <= `EXE_RES_ARITHMETIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_ADD:begin//rd<-rs+rtwreg_o <= `WriteEnable;aluop_o <= `EXE_ADD_OP;alusel_o <= `EXE_RES_ARITHMETIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_ADDU:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_ADDU_OP;alusel_o <= `EXE_RES_ARITHMETIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_SUB:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_SUB_OP;alusel_o <= `EXE_RES_ARITHMETIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_SUBU:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_SUBU_OP;alusel_o <= `EXE_RES_ARITHMETIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_MULT:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_MULT_OP;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_MULTU:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_MULTU_OP;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end   `EXE_DIV:beginwreg_o <= `WriteDisable;aluop_o <= `EXE_DIV_OP;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_DIVU:beginwreg_o <= `WriteDisable;aluop_o <= `EXE_DIVU_OP;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_JR:beginwreg_o <= `WriteDisable;aluop_o <= `EXE_JR_OP;alusel_o <= `EXE_RES_JUMP_BRANCH;reg1_read_o <= 1'b1;//rs寄存器需要被使用reg2_read_o <= 1'b0;wd_o <= inst_i[15:11];link_addr_o <= pc_plus_8;//返回地址branch_target_address_o <= reg1_o;//转移到的目标地址branch_flag_o <= `Branch;//是否发生转移next_inst_in_delayslot_o <= `InDelaySlot;//下一条指令不位于延迟槽instvalid <= `InstValid;end`EXE_JALR:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_JALR_OP;alusel_o <= `EXE_RES_JUMP_BRANCH;reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;wd_o <= inst_i[15:11];link_addr_o <= pc_plus_8;branch_target_address_o <= reg1_o;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot;instvalid <= `InstValid;enddefault:beginendendcaseenddefault:begin//aluop_o <= `EXE_NOP_OP;//alusel_o <= `EXE_RES_OP;//wd_o <= `NOPRegAddr;//wreg_o <= `WriteDisable;//instvalid <= `InstValid;//reg1_read_o <= `ReadDisable;//reg2_read_o <= `ReadDisable;//reg1_addr_o <= inst_i[25:21];//reg2_addr_o <= inst_i[20:16];endendcase//op3end // 5'b00000`EXE_J:beginwreg_o <= `WriteDisable;//译码阶段是否要写入目的寄存器aluop_o <= `EXE_J_OP;alusel_o <= `EXE_RES_JUMP_BRANCH;reg1_read_o <= 1'b0;reg2_read_o <= 1'b0;link_addr_o <= `ZeroWord;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot;instvalid <= `InstValid;branch_target_address_o <= {pc_plus_4[31:28],inst_i[25:0],2'b00};//转移目的的地址end`EXE_JAL:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_JAL_OP;alusel_o <= `EXE_RES_JUMP_BRANCH;reg1_read_o <= 1'b0;reg2_read_o <= 1'b0;wd_o <= 5'b11111;//要写入的目的寄存器的地址 寄存器$1link_addr_o <= pc_plus_8;//转移指令要保存的返回地址branch_flag_o <= `Branch;//转移发生的标志next_inst_in_delayslot_o <= `InDelaySlot;instvalid <= `InstValid;branch_target_address_o <= {pc_plus_4[31:28],inst_i[25:0],2'b00};end`EXE_BEQ:beginwreg_o <= `WriteDisable;aluop_o <= `EXE_BEQ_OP;alusel_o <= `EXE_RES_JUMP_BRANCH;reg1_read_o <= 1'b1;//需要比较rs与rt reg2_read_o <= 1'b1;instvalid <= `InstValid;if(reg1_o == reg2_o)begin //如果rs的值reg1_o与rd的值reg2_o相等 发生转移branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot;endend`EXE_BGTZ:beginwreg_o <= `WriteDisable;aluop_o <= `EXE_BGTZ_OP;alusel_o <= `EXE_RES_JUMP_BRANCH;reg1_read_o <= 1'b1;//rsreg2_read_o <= 1'b0;instvalid <= `InstValid;if((reg1_o[31] == 1'b0)&&(reg1_o != `ZeroWord))beginbranch_target_address_o <= pc_plus_4 + imm_sll2_signedext;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot;endend`EXE_BLEZ:beginwreg_o <= `WriteDisable;//译码阶段是否要写入目的寄存器aluop_o <= `EXE_BLEZ_OP;alusel_o <= `EXE_RES_JUMP_BRANCH;reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;instvalid <= `InstValid;if((reg1_o[31] == 1'b1)&&(reg1_o != `ZeroWord))beginbranch_target_address_o <= pc_plus_4 + imm_sll2_signedext;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot;endend`EXE_BNE:beginwreg_o <= `WriteDisable;aluop_o <= `EXE_BNE_OP;alusel_o <= `EXE_RES_JUMP_BRANCH;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;if(reg1_o != reg2_o)beginbranch_target_address_o <= pc_plus_4+imm_sll2_signedext;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot;endend`EXE_REGIMM_INST:begincase(op4)`EXE_BLTZAL:begin//bltzalwreg_o <= `WriteEnable;aluop_o <= `EXE_BGEZAL_OP;alusel_o <= `EXE_RES_JUMP_BRANCH;reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;link_addr_o <= pc_plus_8;wd_o <= 5'b11111;instvalid <= `InstValid;if(reg1_o[31] == 1'b1) begin//reg1_o<0branch_target_address_o <= pc_plus_4+imm_sll2_signedext;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot;endend`EXE_BLTZ:begin//bltzwreg_o <= `WriteDisable;aluop_o <= `EXE_BGEZAL_OP;alusel_o <= `EXE_RES_JUMP_BRANCH;reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;instvalid <= `InstValid;if(reg1_o[31] == 1'b1)beginbranch_target_address_o <= pc_plus_4 + imm_sll2_signedext;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot;endend`EXE_BGEZ:begin//bgezwreg_o <= `WriteDisable;aluop_o <= `EXE_BGEZ_OP;alusel_o <= `EXE_RES_JUMP_BRANCH;reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;instvalid <= `InstValid;if(reg1_o[31] == 1'b0)begin//rs的值大于等于0branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot;endend`EXE_BGEZAL:begin//bgezalwreg_o <= `WriteEnable;aluop_o <= `EXE_BGEZAL_OP;alusel_o <= `EXE_RES_JUMP_BRANCH;reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;link_addr_o <= pc_plus_8;wd_o <= 5'b11111;instvalid <= `InstValid;if(reg1_o[31] == 1'b0)beginbranch_target_address_o <= pc_plus_4 + imm_sll2_signedext;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot;endenddefault:beginendendcase      // op2  end `EXE_ORI:begin                        //ORI指令wreg_o <= `WriteEnable;      aluop_o <= `EXE_OR_OP;alusel_o <= `EXE_RES_LOGIC; reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;      imm <= {16'h0, inst_i[15:0]};  //立即数0扩展wd_o <= inst_i[20:16]; // 读取rt地址instvalid <= `InstValid;   end `EXE_ANDI:begin //andiwreg_o <= `WriteEnable;aluop_o <= `EXE_AND_OP;alusel_o <= `EXE_RES_LOGIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;imm <= {16'h0,inst_i[15:0]};wd_o <= inst_i[20:16];//rtinstvalid = `InstValid;end`EXE_XORI:begin//xoriwreg_o <= `WriteEnable;aluop_o <= `EXE_XOR_OP;alusel_o <= `EXE_RES_LOGIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;imm <= {16'h0,inst_i[15:0]};wd_o <= inst_i[20:16];instvalid = `InstValid;        end`EXE_LUI:begin//luiwreg_o <= `WriteEnable;//注意书上的打印错误 无语了aluop_o <= `EXE_OR_OP;alusel_o <= `EXE_RES_LOGIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;imm <= {inst_i[15:0],16'h0};    wd_o <= inst_i[20:16];instvalid <= `InstValid;end/*`EXE_PREF: begin//prefwreg_o <= `WriteDisable;aluop_o <= `EXE_NOP_OP;alusel_o <= `EXE_RES_NOP;reg1_read_o <= 1'b0;reg2_read_o <= 1'b0;instvalid <=    `InstValid;end */  `EXE_SLTI:begin //slti   rt <- (rs < (sign_extended)immediate)wreg_o <= `WriteEnable;aluop_o <= `EXE_SLT_OP;alusel_o <= `EXE_RES_ARITHMETIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;imm <= {{16{inst_i[15]}},inst_i[15:0]};wd_o <= inst_i[20:16];instvalid <= `InstValid;end`EXE_SLTIU:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_SLTU_OP;alusel_o <= `EXE_RES_ARITHMETIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;imm <= {{16{inst_i[15]}},inst_i[15:0]};wd_o <= inst_i[20:16];instvalid <= `InstValid;end`EXE_ADDI:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_ADDI_OP;alusel_o <= `EXE_RES_ARITHMETIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;imm <= {{16{inst_i[15]}},inst_i[15:0]};wd_o <= inst_i[20:16];instvalid <= `InstValid;end`EXE_ADDIU:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_ADDIU_OP;alusel_o <= `EXE_RES_ARITHMETIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;imm <= {{16{inst_i[15]}},inst_i[15:0]};wd_o <= inst_i[20:16];instvalid <= `InstValid;end     `EXE_LB:begin//将加载结果写入目的寄存器wreg_o <= `WriteEnable;aluop_o <= `EXE_LB_OP;alusel_o <= `EXE_RES_LOAD_STORE;reg1_read_o <= 1'b1;//计算加载目标地址需要使用地址为base的寄存器值reg2_read_o <= 1'b0;wd_o <= inst_i[20:16];//目的寄存器地址instvalid <= `InstValid;end`EXE_LBU:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_LBU_OP;alusel_o <= `EXE_RES_LOAD_STORE;reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;wd_o <= inst_i[20:16];instvalid <= `InstValid;end`EXE_LH:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_LH_OP;alusel_o <= `EXE_RES_LOAD_STORE;reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;wd_o <= inst_i[20:16];instvalid <= `InstValid;end`EXE_LHU:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_LHU_OP;alusel_o <= `EXE_RES_LOAD_STORE;reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;wd_o <= inst_i[20:16];instvalid <= `InstValid;end`EXE_LW:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_LW_OP;alusel_o <= `EXE_RES_LOAD_STORE;reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;wd_o <= inst_i[20:16];instvalid <= `InstValid;end`EXE_LWL:begin//向左加载 加载结果需要写入目的寄存器 [20:16]wreg_o <= `WriteEnable;aluop_o <= `EXE_LWL_OP;alusel_o <= `EXE_RES_LOAD_STORE;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;wd_o <= inst_i[20:16];instvalid <= `InstValid;end`EXE_LWR:begin//向右加载wreg_o <= `WriteEnable;aluop_o <= `EXE_LWR_OP;alusel_o <= `EXE_RES_LOAD_STORE;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;wd_o <= inst_i[20:16];instvalid <= `InstValid;end`EXE_SB:begin //不需要写通用寄存器 计算存储目标地址需要使用的地址为base的寄存器的值wreg_o <= `WriteDisable;aluop_o <= `EXE_SB_OP;reg1_read_o <= 1'b1; //[25:21] reg1_addr_o ======> basereg2_read_o <= 1'b1;instvalid <= `InstValid;alusel_o <= `EXE_RES_LOAD_STORE;end`EXE_SH:beginwreg_o <= `WriteDisable;aluop_o <= `EXE_SH_OP;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;alusel_o <= `EXE_RES_LOAD_STORE;end`EXE_SW:beginwreg_o <= `WriteDisable;aluop_o <= `EXE_SW_OP;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;alusel_o <= `EXE_RES_LOAD_STORE;end`EXE_SWL:beginwreg_o <= `WriteDisable;aluop_o <= `EXE_SWL_OP;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;alusel_o <= `EXE_RES_LOAD_STORE;end`EXE_SWR:beginwreg_o <= `WriteDisable;aluop_o <= `EXE_SWR_OP;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;alusel_o <= `EXE_RES_LOAD_STORE;end`EXE_SPECIAL2_INST:begin//(op)case(op3)`EXE_CLZ:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_CLZ_OP;alusel_o <= `EXE_RES_ARITHMETIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;instvalid <= `InstValid;end`EXE_CLO:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_CLO_OP;alusel_o <= `EXE_RES_ARITHMETIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b0;instvalid <= `InstValid;end`EXE_MUL:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_MUL_OP;alusel_o <= `EXE_RES_MUL;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_MADD:begin wreg_o <= `WriteDisable;aluop_o <= `EXE_MADD_OP;alusel_o <= `EXE_RES_MUL;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_MADDU:beginwreg_o <= `WriteDisable;aluop_o <= `EXE_MADDU_OP;alusel_o <= `EXE_RES_MUL;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_MSUB:beginwreg_o <= `WriteDisable;aluop_o <= `EXE_MSUB_OP;alusel_o <= `EXE_RES_MUL;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_MSUBU:beginwreg_o <= `WriteDisable;aluop_o <= `EXE_MSUBU_OP;alusel_o <= `EXE_RES_MUL;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;enddefault:beginendendcase //EXE_SPECIAL_INST2 caseend                 default:beginendendcase          //case op     if(inst_i[31:21] == 11'b00000000000)begin //sll,srl,sraif(op3 == `EXE_SLL) beginwreg_o <= `WriteEnable;aluop_o <= `EXE_SLL_OP;alusel_o <= `EXE_RES_SHIFT;reg1_read_o <= 1'b0;reg2_read_o <= 1'b1;imm[4:0] <= inst_i[10:6];wd_o <= inst_i[15:11];instvalid <= `InstValid;end else if(op3 == `EXE_SRL)beginwreg_o <= `WriteEnable;aluop_o <= `EXE_SRL_OP;alusel_o <= `EXE_RES_SHIFT;reg1_read_o <= 1'b0;reg2_read_o <= 1'b1;imm[4:0] <= inst_i[10:6];wd_o <= inst_i[15:11];instvalid <= `InstValid;end else if(op3 == `EXE_SRA) beginwreg_o <= `WriteEnable;aluop_o <= `EXE_SRA_OP;alusel_o <= `EXE_RES_SHIFT;reg1_read_o <= 1'b0;reg2_read_o <= 1'b1;imm[4:0] <= inst_i[10:6];wd_o <= inst_i[15:11];instvalid <= `InstValid;end
//endcase//endend       //ifend
end        //always/*       数据前推
给reg1_o赋值过程增加了两种情况
1:如果Regfile模块读端口1要读取的寄存器就是执行阶段要写的目的寄存器,那么直接把执行阶段的结果ex_wdata_i作为reg1_o的值
2:如果Regfile模块读端口1要读取的寄存器就是访存阶段要写的目的寄存器,那么直接把访存阶段的结果mem_wdata_i作为reg1_o的值*/always @ (*) beginif(rst == `RstEnable) beginreg1_o <= `ZeroWord;     end else if((reg1_read_o == 1'b1) && (ex_wreg_i == 1'b1) && (ex_wd_i == reg1_addr_o)) beginreg1_o <= ex_wdata_i; end else if((reg1_read_o == 1'b1) && (mem_wreg_i == 1'b1) && (mem_wd_i == reg1_addr_o)) beginreg1_o <= mem_wdata_i;            end else if(reg1_read_o == 1'b1) beginreg1_o <= reg1_data_i;end else if(reg1_read_o == 1'b0) beginreg1_o <= imm;end else beginreg1_o <= `ZeroWord;endendalways @ (*) beginif(rst == `RstEnable) beginreg2_o <= `ZeroWord;end else if((reg2_read_o == 1'b1) && (ex_wreg_i == 1'b1) && (ex_wd_i == reg2_addr_o)) beginreg2_o <= ex_wdata_i; end else if((reg2_read_o == 1'b1) && (mem_wreg_i == 1'b1) && (mem_wd_i == reg2_addr_o)) beginreg2_o <= mem_wdata_i;           end else if(reg2_read_o == 1'b1) beginreg2_o <= reg2_data_i;end else if(reg2_read_o == 1'b0) beginreg2_o <= imm;end else beginreg2_o <= `ZeroWord;endend//输出变量is_in_delayslot_o表示当前译码阶段指令是否是延迟槽指令
always @ (*)beginif(rst == `RstEnable)beginis_in_delayslot_o <= `NotInDelaySlot;end else begin//直接等于is_in_delayslot_iis_in_delayslot_o <= is_in_delayslot_i;end
endendmodule

id_ex.v

`include "define.v"
//在时钟周期的上升沿,将译码阶段的结果传递到执行阶段*/
module id_ex(input  wire                                        clk,input wire                                      rst,//从译码阶段传递的信息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[5:0] stall  ,input wire[`RegBus] id_link_address,input wire id_is_in_delayslot,input wire next_inst_in_delayslot_i,input wire[`RegBus] id_inst, //来自id模块的信号 当前处于译码阶段的指令//传递到执行阶段的信息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_o,output reg[`RegBus] ex_inst //传递到ex模块 当前处于执行阶段的指令);always @ (posedge clk) beginif (rst == `RstEnable) beginex_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] == `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;ex_inst <= id_inst;is_in_delayslot_o <= next_inst_in_delayslot_i;/*end else 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;        end*/endendendmodule

执行模块

ex.v

`include "define.v"
//ex.v 执行模块
module ex(
//译码阶段送到执行阶段的信息
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,
input wire rst,
//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,//处于执行阶段的转移指令要保存的返回地址
input wire[`RegBus] link_address_i,//当前执行阶段指令是否处于延迟槽
input wire is_in_delayslot_i,//新增输入端口inst_i,其值就是当前处于执行阶段的指令
input wire[`RegBus] inst_i,//当前处于执行阶段的指令//处于执行阶段指令对LO,HI寄存器的写操作请求
output reg[`RegBus] hi_o,
output reg[`RegBus] lo_o,
output reg whilo_o,//执行的结果
output reg[`RegAddrBus] wd_o,
output reg wreg_o,
output reg[`RegBus] wdata_o,
output reg stallreq,output reg[`DoubleRegBus] hilo_temp_o,
output reg[1:0] cnt_o,//新增到除法模块的输出
output reg[`RegBus] div_opdata1_o,
output reg[`RegBus] div_opdata2_o,
output reg div_start_o,
output reg signed_div_o,//output reg is_in_delayslot_o,
//下面新增的几个输出接口是为 加载、 存储指令准备的
output wire[`AluOpBus] aluop_o, //执行阶段要进行运算的子类型
output wire[`RegBus] mem_addr_o,//加载存储指令对应的存储器地址
output wire[`RegBus] reg2_o//存储指令要存储的数据,或者lwl,lwr指令要加载到的目的寄存器的地址
);
//保存逻辑运算的结果
reg[`RegBus] logicout;
//保存移位运算的结果
reg[`RegBus] shiftres;
//保存移动操作的结果
reg[`RegBus] moveres;
//保存HI,LO寄存器的最新值
reg[`RegBus] HI;
reg[`RegBus] LO;
//是否由于除法运算导致流水线暂停
reg stallreq_for_div;
/***********************第七章新定义一些变量***********************/
wire ov_sum;//保存溢出情况
wire reg1_eq_reg2;//第一个操作数是否等于第二个操作数
wire reg1_lt_reg2;//第一个操作数是否小于第二个操作数
reg[`RegBus] arithmeticres;//保存算术运算的结果
reg[`DoubleRegBus] mulres;//保存乘法运算的结果
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 stallreq_for_madd_msub;
//aluop_o会传递到访存阶段,届时将利用其确定加载、存储类型
assign aluop_o = aluop_i;
//mem_addr_o会传递到访存阶段,是加载、存储指令对应的存储器地址,此处reg1_i就是加载、存储指令中地址为base的通用寄存器的值
//通过计算mem_addr_o,了解为何要在译码阶段ID模块新增输出接口inst_o
assign mem_addr_o = reg1_i + {{16{inst_i[15]}},inst_i[15:0]};
//reg2_i是存储指令要存储的数据,或者是lwl,lwr指令要加载到的目的寄存器的原始值,该值通过reg2_o接口传递到访存阶段
assign reg2_o = reg2_i;
/*******************************************************************
**            第一段:依据aluop_i指示的运算子类型进行运算          **
*******************************************************************/
always @ (*)
begin//1if(rst == `RstEnable)begin//2logicout <= `ZeroWord;end//2elsebegin//3case(aluop_i)//4`EXE_OR_OP:begin//5 逻辑或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;enddefault:begin//6logicout <= `ZeroWord;end//6endcase//4end//3
end//1
always @ (*) beginif(rst == `RstEnable)beginshiftres <= `ZeroWord;end else begincase(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//算术右移1shiftres <= ({32{reg2_i[31]}}<<(6'd32-{1'b0,reg1_i[4:0]})) |/*rt向右移sa位*/ reg2_i>>reg1_i[4:0];enddefault:beginshiftres <= `ZeroWord;endendcase
end
end/******************************************************************
****第三段:得到最新的HI,LO寄存器的值,此处要解决数据相关的问题****
******************************************************************/
always @ (*)beginif(rst == `RstEnable) begin{HI,LO} <= {`ZeroWord,`ZeroWord};end else if(mem_whilo_i == `WriteEnable)begin{HI,LO} <= {mem_hi_i,mem_lo_i};//访存阶段的指令要写HI,LO寄存器end else if(wb_whilo_i == `WriteEnable)begin{HI,LO} <= {wb_hi_i,wb_lo_i};//回写阶段的指令要写HI,LO寄存器
end
end
/*******************************************************************
******************第四段:MFHI,MFLO,MOVN,MOVZ指令********************
*******************************************************************/
always @ (*) beginif(rst == `RstEnable) beginmoveres <= `ZeroWord;end else beginmoveres <= `ZeroWord;case(aluop_i)`EXE_MFHI_OP:begin//rd<-himoveres <= HI;//HI的值是移动操作的结果end`EXE_MFLO_OP:begin//rd<-lomoveres <= LO;end`EXE_MOVN_OP:begin//rd<-rsmoveres <= reg1_i;end`EXE_MOVZ_OP:begin//rd<-rsmoveres <= reg1_i;enddefault:beginendendcaseend
end
/***************************************************************
*******如果是MTHI,MTLO指令,需要给出whilo_o,hi_o,lo_o的值*******
***************************************************************/
always @ (*)beginif(rst == `RstEnable) beginwhilo_o <= `WriteDisable;hi_o <= `ZeroWord;lo_o <= `ZeroWord;end else if(aluop_i == `EXE_MTHI_OP)beginwhilo_o <= `WriteEnable;hi_o <= reg1_i;lo_o <= LO;//写HI寄存器所以LO保持不变end else if(aluop_i == `EXE_MTLO_OP)beginwhilo_o <= `WriteEnable;hi_o <= HI;lo_o <= reg1_i;end else beginwhilo_o <= `WriteDisable;hi_o <= `ZeroWord;lo_o <= `ZeroWord;end
end
//end
//endmodule
/*************************************************************
******************第五段:计算以下5个变量的值******************
*************************************************************/
/*(1)如果是减法或者是有符号比较运算,那么reg2_i_mux等于第二个操作数reg2_i的补码,
否则reg2_i_mux就等于第二个操作数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;
/*(2)分三种情况:
A:如果是加法运算,此时reg2_i_mux就是第二个操作数reg2_i,所以result_sum就是加法运算结果
B:如果是减法运算,此时reg2_i_mux就是第二个操作数reg2_i的补码,所以result_sum就是减法运算的结果
C:如果是有符号的比较运算,此时reg2_i_mux也就是第二个操作数reg2_i的补码,所以result_sum也就是减法
运算的结果,可以通过判断减法的结果是否小于0,进而判断第一个操作数reg1_i是否小于第二个操作数reg2_i*/
assign result_sum = reg1_i + reg2_i_mux;
/*(3)计算是否溢出,加法指令add和addi,减法指令sub执行的时候,需要判断是否溢出,满足以下两种情况之一的时候
A:reg1_i为正数,reg2_i_mux为正数,但两者之和为负数
B:reg1_i为负数,reg2_i_mux为负数,但是两者之和为正数*/
//这个我不理解 艹    2022.3.10理解了
assign ov_sum = ((!reg1_i[31] && !reg2_i_mux[31]) && result_sum[31])||((reg1_i[31] && reg2_i_mux[31])&&(!result_sum[31]));
/*(4)计算操作数1是否小于操作数2,分两种情况:
A:aluop_i为EXE_SLT_OP表示有符号比较运算
1.reg1_i为负数、reg2_i为正数,显然reg1_i小于reg2_i
2.reg1_i为正数、reg2_i为正数,并且reg1_i减去reg2_i的值小于0(result_sum为负)此时reg1_i小于reg2_i
3.reg1_i为负数、reg2_i为负数,并且reg1_i减去reg2_i的值小于0(result_sum为负)此时reg1_i小于reg2_i
B:无符号数比较运算的时候,直接使用比较运算符比较reg1_i和reg2_i*/
assign reg1_lt_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);
//(5)对操作数1逐位取反 赋值给reg1_i_not
assign reg1_i_not = ~reg1_i;
/*****************************************************************
*****第六段:依据不同的算术运算类型,给arithmeticres变量赋值*******
*****************************************************************/
always @ (*) beginif(rst == `RstEnable)beginarithmeticres <= `ZeroWord;end else begincase(aluop_i) //选择运算类型`EXE_SLT_OP,`EXE_SLTU_OP:beginarithmeticres <= reg1_lt_reg2;//比较运算end`EXE_ADD_OP,`EXE_ADDU_OP,`EXE_ADDI_OP,`EXE_ADDIU_OP:beginarithmeticres <= result_sum;//加法运算end`EXE_SUB_OP,`EXE_SUBU_OP:beginarithmeticres <= result_sum;//减法运算end`EXE_CLZ_OP:begin //计数运算clz 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]?20:reg1_i[0]?31:32;end`EXE_CLO_OP:begin //计数运算cloarithmeticres <= (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);enddefault:beginarithmeticres <= `ZeroWord;endendcaseendend
/*****************************************************************
************************第七段:进行乘法运算***********************
*****************************************************************/
/*(1)取得乘法运算的被乘数 指令 madd,msub都是有符号乘法,如果第一个操作数reg1_i是负数
那么取reg1_i的补码为被乘数,反之直接使用reg1_i作为被乘数 如果是有符号乘法且被乘数是负数 那么取补码*/
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;
//(2)取得乘法运算的乘数 如果是有符号乘法且乘数是负数 那么取补码
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;
//(3)得到临时乘法结果 保存在变量hilo_temp中
assign hilo_temp = opdata1_mult * opdata2_mult;
/*(4)对临时乘法结果进行修正 最终的乘法结果保存在变量mulres中 主要有以下两点
A:如果是有符号乘法指令mult、mul,那么需要修正临时乘法结果,如下:
A1:如果被乘数与乘数两者为一正一负,那么需要对临时乘法结果hilo_temp求补码,作为最终乘法结果,赋给mulres
A2:如果被乘数与乘数同号,那么hilo_temp的值就作为最终的乘法结果,赋给变量mulres
B:如果是无符号乘法指令multu,那么hilo_temp的值就作为最终的乘法结果,赋给变量mulres
*/
always @ (*) begin//1if(rst == `RstEnable) begin//2mulres <= {`ZeroWord,`ZeroWord};end/*2*/ else if((aluop_i == `EXE_MULT_OP)||(aluop_i == `EXE_MUL_OP)||(aluop_i == `EXE_MADD_OP)||(aluop_i == `EXE_MSUB_OP))begin//3if(reg1_i[31]^reg2_i[31] == 1'b1)begin//4 被乘数和乘数一正一负mulres <= ~hilo_temp+1;end/*4*/ else begin//5 被乘数和乘数同号mulres <= hilo_temp;end//5end/*3*/ else begin//6 无符号乘法mulres <= hilo_temp;end//6end//1
/*****************************************************************
****************第八段:确定要写入目的寄存器的数据*****************
*****************************************************************/
always @ (*)beginwd_o <= wd_i;//如果是add,addi,sub,subi指令,且发生溢出,那么设置wreg_o为WriteEnable 表示不写目的寄存器if(((aluop_i == `EXE_ADD_OP)||(aluop_i == `EXE_ADDI_OP)||(aluop_i == `EXE_SUB_OP))&&(ov_sum == 1'b1))beginwreg_o <= `WriteDisable;end else beginwreg_o <= wreg_i;endcase(alusel_i)`EXE_RES_LOGIC:beginwdata_o <= logicout;end`EXE_RES_SHIFT:beginwdata_o <= shiftres;end`EXE_RES_MOVE:beginwdata_o <= moveres;end`EXE_RES_ARITHMETIC:begin//除乘法外的简单算术操作指令wdata_o <= arithmeticres;end`EXE_RES_MUL:begin//乘法指令mulwdata_o <= mulres[31:0];end`EXE_RES_JUMP_BRANCH:beginwdata_o <= link_address_i;enddefault:beginwdata_o <= `ZeroWord;endendcase
end//always/****************************************************************
********************第十段:乘累加、乘累减************************
****************************************************************/
//MADD MADDU MSUB MSUBU指令
always @ (*) beginif(rst == `RstEnable) beginhilo_temp_o <= {`ZeroWord,`ZeroWord};cnt_o <= 2'b00;stallreq_for_madd_msub <= `NoStop;end else begincase(aluop_i)`EXE_MADD_OP,`EXE_MADDU_OP:beginif(cnt_i == 2'b00) begin //执行第一个时钟周期hilo_temp_o <= mulres;//此时将乘法结果mulres通过接口hilo_temp_o输出到EX/MEM模块 以便在下一个时钟周期使用cnt_o <= 2'b01;hilo_temp1 <= {`ZeroWord,`ZeroWord};stallreq_for_madd_msub <= `Stop;//乘累加指令请求流水线暂停end else if(cnt_i == 2'b01) begin//执行第二个时钟周期hilo_temp_o <= {`ZeroWord,`ZeroWord};cnt_o <= 2'b10;hilo_temp1 <= hilo_temp_i+{HI,LO}; //hilo_temp_i是上一个时钟周期得到的乘法结果stallreq_for_madd_msub <= `NoStop;//乘累加指令执行结束 不再请求流水线暂停endend`EXE_MSUB_OP,`EXE_MSUBU_OP:beginif(cnt_i == 2'b00) beginhilo_temp_o <= ~mulres+1;cnt_o <= 2'b01;stallreq_for_madd_msub <= `Stop;end else if(cnt_i == 2'b01) beginhilo_temp_o <= {`ZeroWord,`ZeroWord};cnt_o <= 2'b10;hilo_temp1 <= hilo_temp_i +{HI,LO};stallreq_for_madd_msub <= `NoStop;endenddefault:beginhilo_temp_o <= {`ZeroWord,`ZeroWord};cnt_o <= 2'b00;stallreq_for_madd_msub <= `NoStop;endendcaseend
end
/****************************************************************
******第十二段:输出DIV模块控制信息,获取DIV模块给出的结果*********
****************************************************************/
always @ (*) beginif(rst == `RstEnable)beginstallreq_for_div <= `NoStop;div_opdata1_o <= `ZeroWord;div_opdata2_o <= `ZeroWord;div_start_o <= `DivStop;signed_div_o <= 1'b0;end else beginstallreq_for_div <= `NoStop;div_opdata1_o <= `ZeroWord;div_opdata2_o <= `ZeroWord;div_start_o <= `DivStop;signed_div_o <= 1'b0;case(aluop_i)`EXE_DIV_OP:beginif(div_ready_i == `DivResultNotReady) begindiv_opdata1_o <= reg1_i;//被除数div_opdata2_o <= reg2_i;//除数div_start_o <= `DivStart;//开始除法运算signed_div_o <= 1'b1;//有符号除法stallreq_for_div <= `Stop;//请求流水线暂停end else if(div_ready_i == `DivResultReady) begindiv_opdata1_o <= reg1_i;div_opdata2_o <= reg2_i;div_start_o <= `DivStop;//结束除法运算signed_div_o <= 1'b1;stallreq_for_div <= `NoStop;//不再请求流水线暂停end else begindiv_opdata1_o <= `ZeroWord;div_opdata2_o <= `ZeroWord;div_start_o <= `DivStop;signed_div_o <= 1'b0;stallreq_for_div <= `NoStop;endend`EXE_DIVU_OP:beginif(div_ready_i == `DivResultNotReady) begindiv_opdata1_o <= reg1_i;div_opdata2_o <= reg2_i;div_start_o <= `DivStart;signed_div_o <= 1'b0;//无符号除法stallreq_for_div <= `Stop;end else if(div_ready_i == `DivResultReady) begindiv_opdata1_o <= reg1_i;div_opdata2_o <= reg2_i;div_start_o <= `DivStop;signed_div_o <= 1'b0;stallreq_for_div <= `NoStop;end else begindiv_opdata1_o <= `ZeroWord;div_opdata2_o <= `ZeroWord;div_start_o <= `DivStop;signed_div_o <= 1'b0;stallreq_for_div <= `NoStop;endenddefault:beginendendcaseend
end/****************************************************************
*********************第十一段:暂停流水线*************************
****************************************************************/
//目前只有乘累加和乘累减指令会导致流水线暂停,所以stallreq=stallreq_for_madd_msub
always @ (*) beginstallreq = stallreq_for_madd_msub || stallreq_for_div;
end
/****************************************************************
****************第九段:确定(修改)对HI,LO寄存器的操作信息*********
****************************************************************/
always @ (*)beginif(rst == `RstEnable) beginwhilo_o <= `WriteDisable;hi_o <= `ZeroWord;lo_o <= `ZeroWord;end else if((aluop_i == `EXE_MULT_OP)||(aluop_i == `EXE_MULTU_OP))begin //mult,multu指令whilo_o <= `WriteEnable;hi_o <= mulres[63:32];lo_o <= mulres[31:0];end else if(aluop_i == `EXE_MTHI_OP)beginwhilo_o <= `WriteEnable;hi_o <= reg1_i;lo_o <= LO;//写HI寄存器所以LO保持不变end else if(aluop_i == `EXE_MTLO_OP)beginwhilo_o <= `WriteEnable;hi_o <= HI;lo_o <= reg1_i;end else if((aluop_i == `EXE_MSUB_OP)||(aluop_i == `EXE_MSUBU_OP))beginwhilo_o <= `WriteEnable;hi_o <= hilo_temp1[63:32];lo_o <= hilo_temp1[31:0];end else if((aluop_i == `EXE_MADD_OP)||(aluop_i == `EXE_MADDU_OP))beginwhilo_o <= `WriteEnable;hi_o <= hilo_temp1[63:32];lo_o <= hilo_temp1[31:0];end else if((aluop_i == `EXE_DIV_OP)||(aluop_i == `EXE_DIVU_OP))beginwhilo_o <= `WriteEnable;hi_o <= div_result_i[63:32];lo_o <= div_result_i[31:0];end else beginwhilo_o <= `WriteDisable;hi_o <= `ZeroWord;lo_o <= `ZeroWord;end endendmodule

ex_mem.v

`include "define.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[`AluOpBus] ex_aluop, //执行阶段要进行运算的子类型input wire[`RegBus] ex_mem_addr,//执行阶段的加载、存储指令对应的存储器地址input wire[`RegBus] ex_reg2,//执行阶段存储指令要存储的数据,或者lwl,lwr指令要写入的目的寄存器的原始值//增加的输入接口input wire[`DoubleRegBus] hilo_i,input wire[1:0] cnt_i,//input wire[5:0] stall,//送到访存阶段的信息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 ,//增加的输出端口output reg[`DoubleRegBus] hilo_o,output reg[1:0] cnt_o,//为实现加载、存储指令而增加的输出接口output reg[`AluOpBus] mem_aluop,//访存阶段的指令要进行运算的子类型output reg[`RegBus] mem_mem_addr,//访存阶段的加载、存储指令对应的存储器地址output reg[`RegBus] mem_reg2//访存阶段存储指令要存储的数据,或者lwl,lwr要写入的目的寄存器原始值);/*在流水线执行阶段暂停的时候,将输入信号hilo_i通过输出接口hilo_o送出,
输入信号cnt_i通过输出接口cnt_o送出。其余时刻,hilo_o为0,cnt_o也为0。*/always @ (posedge clk) beginif(rst == `RstEnable) beginmem_wd <= `NOPRegAddr;mem_wreg <= `WriteDisable;mem_wdata <= `ZeroWord;    mem_hi <= `ZeroWord;mem_lo <= `ZeroWord;mem_whilo <= `WriteDisable;  hilo_o <= {`ZeroWord,`ZeroWord};cnt_o <= 2'b00;    mem_aluop <= `EXE_NOP_OP;mem_mem_addr <= `ZeroWord;mem_reg2 <= `ZeroWord;end else if(stall[3] == `Stop && stall[4] == `NoStop)beginmem_wd <= `NOPRegAddr;mem_wreg <= `WriteDisable;mem_wdata <= `ZeroWord;mem_hi <= `ZeroWord;mem_lo <= `ZeroWord;mem_whilo <= `WriteDisable;hilo_o <= hilo_i;cnt_o <= cnt_i;mem_aluop <= `EXE_NOP_OP;mem_mem_addr <= `ZeroWord;mem_reg2 <= `ZeroWord;end else if(stall[3] == `NoStop)beginmem_wd <= ex_wd;mem_wreg <= ex_wreg;mem_wdata <= ex_wdata;    mem_hi <= ex_hi;mem_lo <= ex_lo;mem_whilo <= ex_whilo;  hilo_o <= {`ZeroWord,`ZeroWord};cnt_o <= 2'b00;mem_aluop <= ex_aluop;mem_mem_addr <= ex_mem_addr;mem_reg2 <= ex_reg2;end else beginhilo_o <= hilo_i;cnt_o <= cnt_i;              end    //ifend      //alwaysendmodule

访存模块

mem.v

`include "define.v"
//mem.v 访存
//将输入的执行阶段的结果直接作为输出
module mem(
input wire rst,
input wire clk,
//来自执行阶段的信息
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,//新增接口,来自访存阶段的信息,添加对数据存储器RAM的访问接口
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[`RegAddrBus] wd_o,
output reg wreg_o,
output reg[`RegBus] wdata_o,
output reg[`RegBus] hi_o,
output reg[`RegBus] lo_o,
output reg whilo_o,//新增接口,送到外部数据存储器RAM的信息
output reg[`RegBus] mem_addr_o,//要访问的ram地址
output wire mem_we_o,//是否为写操作 为1是写操作
output reg[3:0] mem_sel_o,//字节选择信号
output reg[`RegBus] mem_data_o,//要写入数据存储器的地址
output reg mem_ce_o//数据存储器使能信号
);
wire[`RegBus] zero32;
reg mem_we;
assign mem_we_o = mem_we;//外部数据存储器ram的读、写信号
assign zero32 = `ZeroWord;
always @ (*)
beginif(rst == `RstEnable)beginwd_o <= `NOPRegAddr;wreg_o <= `WriteDisable;wdata_o <= `ZeroWord;hi_o <= `ZeroWord;lo_o <= `ZeroWord;whilo_o <= `WriteDisable;mem_addr_o <= `ZeroWord;mem_we <= `WriteDisable;mem_sel_o <= 4'b0000;mem_data_o <= `ZeroWord;mem_ce_o <= `ChipDisable;
end
else
beginwd_o <= wd_i;wreg_o <= wreg_i;wdata_o <= wdata_i;hi_o <= hi_i;lo_o <= lo_i;whilo_o <= whilo_i;mem_we <= `WriteDisable;mem_addr_o <= `ZeroWord;mem_sel_o <= 4'b1111;mem_ce_o <= `ChipDisable;case(aluop_i)//访存阶段要执行运算的子类型`EXE_LB_OP:begin //读取一个字节,无符号扩展到32位 保存到地址为rt的寄存器中mem_addr_o <= mem_addr_i;mem_we <= `WriteDisable;mem_ce_o <= `ChipEnable;case(mem_addr_i[1:0])//要访问的ram地址的最后两位2'b00:begin //读取数据存储器ram在0x mem_addr_i[1:0]处的字节wdata_o <={{24{mem_data_i[31]}},mem_data_i[31:24]}; //最高位mem_sel_o <= 4'b1000;//0x0end2'b01:beginwdata_o <= {{24{mem_data_i[23]}},mem_data_i[23:16]};//次高位mem_sel_o <= 4'b0100;//0x1end2'b10:beginwdata_o <= {{24{mem_data_i[15]}},mem_data_i[15:8]};mem_sel_o <= 4'b0010;//0x2end2'b11:beginwdata_o <= {{24{mem_data_i[7]}},mem_data_i[7:0]};mem_sel_o <= 4'b0001; //0x3enddefault:beginwdata_o <= `ZeroWord;endendcaseend`EXE_LBU_OP:beginmem_addr_o <= mem_addr_i;mem_we <= `WriteDisable;mem_ce_o <= `ChipEnable;case(mem_addr_i[1:0])2'b00:beginwdata_o <= {{24{1'b0}},mem_data_i[31:24]};mem_sel_o <= 4'b1000;end2'b01:beginwdata_o <= {{24{1'b0}},mem_data_i[23:16]};mem_sel_o <= 4'b0100;end2'b10:beginwdata_o <= {{24{1'b0}},mem_data_i[15:8]};mem_sel_o <= 4'b0010;end2'b11:beginwdata_o <= {{24{1'b0}},mem_data_i[7:0]};mem_sel_o <= 4'b0001;enddefault:beginwdata_o <= `ZeroWord;endendcaseend`EXE_LH_OP:begin //读取半字 2个字节mem_addr_o <= mem_addr_i;mem_we <= `WriteDisable;mem_ce_o <= `ChipEnable;case(mem_addr_i[1:0])2'b00:beginwdata_o <= {{16{mem_data_i[31]}},mem_data_i[31:16]};//读取最低8位mem_sel_o <= 4'b1100;//从0x0开始读取2个字节end2'b10:beginwdata_o <= {{16{mem_data_i[15]}},mem_data_i[15:0]};mem_sel_o <= 0011;enddefault:beginwdata_o <= `ZeroWord;endendcaseend`EXE_LHU_OP:beginmem_addr_o <= mem_addr_i;mem_we <= `WriteDisable;mem_ce_o <= `ChipEnable;case(mem_addr_i[1:0])2'b00:beginwdata_o <= {{16{1'b0}},mem_data_i[31:16]};mem_sel_o <= 4'b1100;end2'b10:beginwdata_o <= {{16{1'b0}},mem_data_i[15:0]};mem_sel_o <= 4'b0011;enddefault:beginwdata_o <= `ZeroWord;endendcaseend`EXE_LW_OP:begin //加载一个字mem_addr_o <= {mem_addr_i[31:2],2'b00};mem_we <= `WriteDisable;mem_sel_o <= 4'b1111;mem_ce_o <= `ChipEnable;wdata_o <= mem_data_i;end`EXE_LWL_OP:begin //从内存指定地址处 加载一个字的最高有效部分 允许非对齐加载mem_addr_o <= {mem_addr_i[31:2],2'b00};mem_we <= `WriteDisable;mem_sel_o <= 4'b1111;mem_ce_o <= `ChipEnable;case(mem_addr_i[1:0])//从地址为mem_addr_o处加载一个字 将这个字的最低4-n个字节保存到rt寄存器的高位 低位不变2'b00:beginwdata_o <= mem_data_i[31:0];//32位 (4-0)*8end2'b01:beginwdata_o <= {mem_data_i[23:0],reg2_i[7:0]};//24位 (4-1)*8end2'b10:beginwdata_o <= {mem_data_i[15:0],reg2_i[15:0]};//16位 (4-2)*8end2'b11:beginwdata_o <= {mem_data_i[7:0],reg2_i[23:0]};//8位 (4-3)*8enddefault:beginwdata_o <= `ZeroWord;endendcaseend`EXE_LWR_OP:beginmem_addr_o <= {mem_addr_i[31:2],2'b00};mem_we <= `WriteDisable;mem_sel_o <= 4'b1111;mem_ce_o <= `ChipEnable;case(mem_addr_i[1:0])2'b00:beginwdata_o <= {reg2_i[31:8],mem_data_i[31:24]};//低位保存8位end2'b01:beginwdata_o <= {reg2_i[31:16],mem_data_i[31:16]};//低位保存16位end2'b10:beginwdata_o <= {reg2_i[31:24],mem_data_i[31:8]};//低位保存高24位end2'b11:beginwdata_o <= mem_data_i;enddefault:beginwdata_o <= `ZeroWord;endendcaseend`EXE_SB_OP:begin//将地址为rt的通用寄存器的最低字节存储到内存中的指定地址mem_addr_o <= mem_addr_i;mem_we <= `WriteEnable;mem_data_o <= {reg2_i[7:0],reg2_i[7:0],reg2_i[7:0],reg2_i[7:0]};mem_ce_o <= `ChipEnable;case(mem_addr_i[1:0])//数据的高位保存在存储器的低地址中2'b00:beginmem_sel_o <= 4'b1000;end2'b01:beginmem_sel_o <= 4'b0100;end2'b10:beginmem_sel_o <= 4'b0010;end2'b11:beginmem_sel_o <= 4'b0001;enddefault:beginmem_sel_o <= 4'b0000;endendcaseend`EXE_SH_OP:begin//将地址为rt的通用寄存器的 最低两个字节存储 低位2保存到高地址mem_addr_o <= mem_addr_i;mem_we <= `WriteEnable;mem_data_o <= {reg2_i[15:0],reg2_i[15:0]};mem_ce_o <= `ChipEnable;case(mem_addr_i[1:0])2'b00:beginmem_sel_o <= 4'b1100;end2'b10:beginmem_sel_o <= 4'b0011;enddefault:beginmem_sel_o <= `ZeroWord;endendcaseend`EXE_SW_OP:beginmem_addr_o <= mem_addr_i;mem_we <= `WriteEnable;mem_ce_o <= `ChipEnable;mem_sel_o <= 4'b1111;end/*将地址为rt的通用寄存器的高位部分存储到内存中指定的地址,存储地址最后两位确定了要存储的rt通用寄存器的哪几个字节,swl指令对存储指令没有对齐要求将地址为rt的通用寄存器的最高4-n个字节存储到storeaddr*/`EXE_SWL_OP:begin//非对齐存储指令 向左存储 将地址为rt的通用寄存器的高位部分存储到内存的指定地址处//存储地址的最后两位确定了要存储rt通用寄存器的哪几个字节mem_addr_o <= {mem_addr_i[31:2],2'b00};mem_we <= `WriteEnable;mem_ce_o <= `ChipEnable;case(mem_addr_i[1:0])//确定了存储rt通用寄存器的哪几个字节2'b00:beginmem_sel_o <= 4'b1111;mem_data_o <= reg2_i;end2'b01:beginmem_sel_o <= 4'b0111;mem_data_o <= {zero32[7:0],reg2_i[31:8]};//将最高4-1个字节(24bits) 存储到storeaddrend2'b10:beginmem_sel_o <= 4'b0011;//16bits mem_data_o <= {zero32[15:0],reg2_i[31:16]};end2'b11:beginmem_sel_o <= 4'b0001;mem_data_o <= {zero32[23:0],reg2_i[31:24]};enddefault:beginmem_sel_o <= 4'b000;endendcaseend`EXE_SWR_OP:beginmem_addr_o <= {mem_addr_i[31:2],2'b00};mem_we <= `WriteEnable;mem_ce_o <= `ChipEnable;case(mem_addr_i[1:0])2'b00:beginmem_sel_o <= 4'b1000;mem_data_o <= {reg2_i[7:0],zero32[23:0]};end2'b01:beginmem_sel_o <= 4'b1100;mem_data_o <= {reg2_i[15:0],zero32[15:0]};end2'b10:beginmem_sel_o <= 4'b1110;mem_data_o <= {reg2_i[23:0],zero32[7:0]};end2'b11:beginmem_sel_o <= 4'b1111;mem_data_o <= reg2_i[31:0];enddefault:beginmem_sel_o <= `ZeroWord;endendcaseenddefault:beginend
endcaseend
end
endmodule

例化(每次必错!!!)

openmips.v

`include "define.v"module openmips(input  wire                                        clk,input wire                                      rst,input wire[`RegBus]           rom_data_i,output wire[`RegBus]           rom_addr_o,output wire                    rom_ce_o,//连接数据存储器data_raminput wire[`RegBus]           ram_data_i,output wire[`RegBus]           ram_addr_o,output wire[`RegBus]           ram_data_o,output wire                    ram_we_o,output wire[3:0]               ram_sel_o,output wire[3:0]               ram_ce_o);wire[`InstAddrBus] pc;wire[`InstAddrBus] id_pc_i;wire[`InstBus] id_inst_i;//连接译码阶段ID模块的输出与ID/EX模块的输入wire[`AluOpBus] id_aluop_o;wire[`AluSelBus] id_alusel_o;wire[`RegBus] id_reg1_o;wire[`RegBus] id_reg2_o;wire id_wreg_o;wire[`RegAddrBus] id_wd_o;wire id_is_in_delayslot_o;wire[`RegBus] id_link_address_o;    wire[`RegBus] id_inst_o;//连接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;//连接执行阶段EX模块的输出与EX/MEM模块的输入wire ex_wreg_o;wire[`RegAddrBus] ex_wd_o;wire[`RegBus] ex_wdata_o;wire[`RegBus] ex_hi_o;wire[`RegBus] ex_lo_o;wire ex_whilo_o;wire[`AluOpBus] ex_aluop_o;wire[`RegBus] ex_mem_addr_o;wire[`RegBus] ex_reg1_o;wire[`RegBus] ex_reg2_o;   //连接EX/MEM模块的输出与访存阶段MEM模块的输入wire mem_wreg_i;wire[`RegAddrBus] mem_wd_i;wire[`RegBus] mem_wdata_i;wire[`RegBus] mem_hi_i;wire[`RegBus] mem_lo_i;wire mem_whilo_i;        wire[`AluOpBus] mem_aluop_i;wire[`RegBus] mem_mem_addr_i;wire[`RegBus] mem_reg1_i;wire[`RegBus] mem_reg2_i;     //连接访存阶段MEM模块的输出与MEM/WB模块的输入wire mem_wreg_o;wire[`RegAddrBus] mem_wd_o;wire[`RegBus] mem_wdata_o;wire[`RegBus] mem_hi_o;wire[`RegBus] mem_lo_o;wire mem_whilo_o;        //连接MEM/WB模块的输出与回写阶段的输入 wire wb_wreg_i;wire[`RegAddrBus] wb_wd_i;wire[`RegBus] wb_wdata_i;wire[`RegBus] wb_hi_i;wire[`RegBus] wb_lo_i;wire wb_whilo_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模块的输出,读取HI、LO寄存器wire[`RegBus]     hi;wire[`RegBus]   lo;//连接执行阶段与ex_reg模块,用于多周期的MADD、MADDU、MSUB、MSUBU指令wire[`DoubleRegBus] hilo_temp_o;wire[1:0] cnt_o;wire[`DoubleRegBus] hilo_temp_i;wire[1:0] cnt_i;wire[`DoubleRegBus] div_result;wire div_ready;wire[`RegBus] div_opdata1;wire[`RegBus] div_opdata2;wire div_start;wire div_annul;wire signed_div;wire is_in_delayslot_i;wire is_in_delayslot_o;wire next_inst_in_delayslot_o;wire id_branch_flag_o;wire[`RegBus] branch_target_address;wire[5:0] stall;wire stallreq_from_id; wire stallreq_from_ex;//pc_reg例化pc_reg pc_reg0(.clk(clk),.rst(rst),.stall(stall),.branch_flag_i(id_branch_flag_o),.branch_target_address_i(branch_target_address),      .pc(pc),.ce(rom_ce_o)       );assign rom_addr_o = 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模块id id0(.rst(rst),.pc_i(id_pc_i),.inst_i(id_inst_i),.ex_aluop_i(ex_aluop_o),.reg1_data_i(reg1_data),.reg2_data_i(reg2_data),//处于执行阶段的指令要写入的目的寄存器信息.ex_wreg_i(ex_wreg_o),.ex_wdata_i(ex_wdata_o),.ex_wd_i(ex_wd_o),//处于访存阶段的指令要写入的目的寄存器信息.mem_wreg_i(mem_wreg_o),.mem_wdata_i(mem_wdata_o),.mem_wd_i(mem_wd_o),.is_in_delayslot_i(is_in_delayslot_i),//送到regfile的信息.reg1_read_o(reg1_read),.reg2_read_o(reg2_read),     .reg1_addr_o(reg1_addr),.reg2_addr_o(reg2_addr), //送到ID/EX模块的信息.aluop_o(id_aluop_o),.alusel_o(id_alusel_o),.reg1_o(id_reg1_o),.reg2_o(id_reg2_o),.wd_o(id_wd_o),.wreg_o(id_wreg_o),.inst_o(id_inst_o),.next_inst_in_delayslot_o(next_inst_in_delayslot_o),    .branch_flag_o(id_branch_flag_o),.branch_target_address_o(branch_target_address),       .link_addr_o(id_link_address_o),.is_in_delayslot_o(id_is_in_delayslot_o),.stallreq(stallreq_from_id)        );//通用寄存器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_o),.id_alusel(id_alusel_o),.id_reg1(id_reg1_o),.id_reg2(id_reg2_o),.id_wd(id_wd_o),.id_wreg(id_wreg_o),.id_link_address(id_link_address_o),.id_is_in_delayslot(id_is_in_delayslot_o),.next_inst_in_delayslot_i(next_inst_in_delayslot_o),        .id_inst(id_inst_o),        //传递到执行阶段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_o(is_in_delayslot_i),.ex_inst(ex_inst_i)       );      //EX模块ex ex0(.rst(rst),//送到执行阶段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),.hi_i(hi),.lo_i(lo),.inst_i(ex_inst_i),.wb_hi_i(wb_hi_i),.wb_lo_i(wb_lo_i),.wb_whilo_i(wb_whilo_i),.mem_hi_i(mem_hi_o),.mem_lo_i(mem_lo_o),.mem_whilo_i(mem_whilo_o),.hilo_temp_i(hilo_temp_i),.cnt_i(cnt_i),.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),    //EX模块的输出到EX/MEM模块信息.wd_o(ex_wd_o),.wreg_o(ex_wreg_o),.wdata_o(ex_wdata_o),.hi_o(ex_hi_o),.lo_o(ex_lo_o),.whilo_o(ex_whilo_o),.hilo_temp_o(hilo_temp_o),.cnt_o(cnt_o),.div_opdata1_o(div_opdata1),.div_opdata2_o(div_opdata2),.div_start_o(div_start),.signed_div_o(signed_div),  .aluop_o(ex_aluop_o),.mem_addr_o(ex_mem_addr_o),.reg2_o(ex_reg2_o),.stallreq(stallreq_from_ex)                  );//EX/MEM模块ex_mem ex_mem0(.clk(clk),.rst(rst),.stall(stall),//来自执行阶段EX模块的信息    .ex_wd(ex_wd_o),.ex_wreg(ex_wreg_o),.ex_wdata(ex_wdata_o),.ex_hi(ex_hi_o),.ex_lo(ex_lo_o),.ex_whilo(ex_whilo_o),        .ex_aluop(ex_aluop_o),.ex_mem_addr(ex_mem_addr_o),.ex_reg2(ex_reg2_o),          .hilo_i(hilo_temp_o),.cnt_i(cnt_o), //送到访存阶段MEM模块的信息.mem_wd(mem_wd_i),.mem_wreg(mem_wreg_i),.mem_wdata(mem_wdata_i),.mem_hi(mem_hi_i),.mem_lo(mem_lo_i),.mem_whilo(mem_whilo_i),.mem_aluop(mem_aluop_i),.mem_mem_addr(mem_mem_addr_i),.mem_reg2(mem_reg2_i),.hilo_o(hilo_temp_i),.cnt_o(cnt_i));//MEM模块例化mem mem0(.rst(rst),//来自EX/MEM模块的信息 .wd_i(mem_wd_i),.wreg_i(mem_wreg_i),.wdata_i(mem_wdata_i),.hi_i(mem_hi_i),.lo_i(mem_lo_i),.whilo_i(mem_whilo_i),        .aluop_i(mem_aluop_i),.mem_addr_i(mem_mem_addr_i),.reg2_i(mem_reg2_i),//来自memory的信息.mem_data_i(ram_data_i),//送到MEM/WB模块的信息.wd_o(mem_wd_o),.wreg_o(mem_wreg_o),.wdata_o(mem_wdata_o),.hi_o(mem_hi_o),.lo_o(mem_lo_o),.whilo_o(mem_whilo_o),//送到memory的信息.mem_addr_o(ram_addr_o),.mem_we_o(ram_we_o),.mem_sel_o(ram_sel_o),.mem_data_o(ram_data_o),.mem_ce_o(ram_ce_o)        );//MEM/WB模块mem_wb mem_wb0(.clk(clk),.rst(rst),.stall(stall),//来自访存阶段MEM模块的信息   .mem_wd(mem_wd_o),.mem_wreg(mem_wreg_o),.mem_wdata(mem_wdata_o),.mem_hi(mem_hi_o),.mem_lo(mem_lo_o),.mem_whilo(mem_whilo_o),        //送到回写阶段的信息.wb_wd(wb_wd_i),.wb_wreg(wb_wreg_i),.wb_wdata(wb_wdata_i),.wb_hi(wb_hi_i),.wb_lo(wb_lo_i),.wb_whilo(wb_whilo_i)      );hilo_reg hilo_reg0(.clk(clk),.rst(rst),//写端口.we(wb_whilo_i),.hi_i(wb_hi_i),.lo_i(wb_lo_i),//读端口1.hi_o(hi),.lo_o(lo)   );ctrl ctrl0(.rst(rst),.stallreq_from_id(stallreq_from_id),//来自执行阶段的暂停请求.stallreq_from_ex(stallreq_from_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_o(div_result),.ready_o(div_ready));endmodule

openmips_min_sopc.v

`include "define.v"
//openmips_min_sopc.v
module openmips_min_sopc(
input wire clk,
input wire rst
);
//连接指令存储器
wire[`InstAddrBus] inst_addr;
wire[`InstBus] inst;
wire rom_ce;
//连接外部数据存储器
wire mem_we_i;
wire [`RegBus]mem_addr_i;
wire [`RegBus]mem_data_i;
wire [`RegBus]mem_data_o;
wire[3:0] mem_sel_i;
wire mem_ce_i;
//例化处理器
openmips openmips0(.clk(clk),.rst(rst),.rom_addr_o(inst_addr),.rom_data_i(inst),.rom_ce_o(rom_ce),.ram_we_o(mem_we_i),.ram_addr_o(mem_addr_i),.ram_sel_o(mem_sel_i),.ram_data_o(mem_data_i),.ram_data_i(mem_data_o),.ram_ce_o(mem_ce_i)     );
//例化指令存储器
inst_rom inst_rom0(.ce(rom_ce), .inst(inst), .addr(inst_addr)
);
//例化外部数据存储器RAM
data_ram data_ram0(.clk(clk),.we(mem_we_i),.addr(mem_addr_i),.sel(mem_sel_i),.data_i(mem_data_i),.data_o(mem_data_o),.ce(mem_ce_i)
);
endmodule

测试数据

inst_rom.S

   .org 0x0.set noat.set noreorder.set nomacro.global _start
_start:ori  $3,$0,0xeeffsb   $3,0x3($0)       # [0x3] = 0xffsrl  $3,$3,8sb   $3,0x2($0)       # [0x2] = 0xeeori  $3,$0,0xccddsb   $3,0x1($0)       # [0x1] = 0xddsrl  $3,$3,8sb   $3,0x0($0)       # [0x0] = 0xcclb   $1,0x3($0)       # $1 = 0xfffffffflbu  $1,0x2($0)       # $1 = 0x000000eenopori  $3,$0,0xaabbsh   $3,0x4($0)       # [0x4] = 0xaa, [0x5] = 0xbblhu  $1,0x4($0)       # $1 = 0x0000aabblh   $1,0x4($0)       # $1 = 0xffffaabbori  $3,$0,0x8899sh   $3,0x6($0)       # [0x6] = 0x88, [0x7] = 0x99lh   $1,0x6($0)       # $1 = 0xffff8899lhu  $1,0x6($0)       # $1 = 0x00008899ori  $3,$0,0x4455sll  $3,$3,0x10ori  $3,$3,0x6677     sw   $3,0x8($0)       # [0x8] = 0x44, [0x9]= 0x55, [0xa]= 0x66, [0xb] = 0x77lw   $1,0x8($0)       # $1 = 0x44556677lwl  $1, 0x5($0)      # $1 = 0xbb889977lwr  $1, 0x8($0)      # $1 = 0xbb889944nopswr  $1, 0x2($0)      # [0x0] = 0x88, [0x1] = 0x99, [0x2]= 0x44, [0x3] = 0xffswl  $1, 0x7($0)      # [0x4] = 0xaa, [0x5] = 0xbb, [0x6] = 0x88, [0x7] = 0x44lw   $1, 0x0($0)      # $1 = 0x889944fflw   $1, 0x4($0)      # $1 = 0xaabb8844_loop:j _loopnop

inst_rom.data

3403eeff
a0030003
00031a02
a0030002
3403ccdd
a0030001
00031a02
a0030000
80010003
90010002
00000000
3403aabb
a4030004
94010004
84010004
34038899
a4030006
84010006
94010006
34034455
00031c00
34636677
ac030008
8c010008
88010005
98010008
00000000
b8010002
a8010007
8c010000
8c010004
0800001f
00000000

结果(reg1和reg3的变化)$1和$3



仿真结果是错的 因为lw指令 define部分写错了 懒得在这里改了
详细设计可能会另开一篇。。。

【自己动手写CPU】加载存储指令的实现相关推荐

  1. 自己动手写CPU(8)加载存储指令的实现

    自己动手写CPU(8)加载存储指令的实现 好久没更新blog了,暑假提前放了.现在收假也该收收心了,继续捡起之前的CPU,自己开的坑不管咋样把它填完吧. 指令介绍 1.加载指令 2.存储指令 修改系统 ...

  2. 自己动手写CPU之第九阶段(2)——加载存储指令说明2(lwl、lwr)

    将陆续上传新书<自己动手写CPU>,今天是第38篇,我尽量每周四篇,但是最近已经很久没有实现这个目标了,一直都有事,不好意思哈. 开展晒书评送书活动,在亚马逊.京东.当当三大图书网站上,发 ...

  3. 自己动手写CPU(11)——加载存储指令说明

    加载存储指令说明 加载指令(7) lb.lbu.lh.lhu.lw.lwl.lwr 存储指令(5) sb.sh.sw.swl.swr 补充 加载指令(7) lb.lbu.lh.lhu.lw.lwl.l ...

  4. 【五级流水线CPU】—— 6. 加载存储指令(14)

    文章目录 1. 初步 12条 1.1 分析 1.2 添加数据存储器RAM 1.3 修改最小SOPC 2.3 测试9 加载存储指令 2. load-use数据冒险 测试10 load-use数据冒险的解 ...

  5. 【自己动手写CPU】异常相关指令的实现

    MIPS架构中定义的异常类型 MIPS32架构中,有些事情打断程序的正常的执行流程,这些事情称为中断.陷阱.系统调用以及其他打断程序执行流程的情况,统称为异常. 此处的OpenMIPS处理器只实现了其 ...

  6. ARM多寄存器加载/存储指令

    ARM中如何实现跳转? a. 直接向PC 寄存器赋值实现跳转 MOV PC ,R14 b.使用分支指令直接跳转 分支指令种类 1.B:分支指令 2.BL:带链接的分支指令(可返回) 3.BX:带状态切 ...

  7. 【自己动手写CPU】第一条指令ori的实现

    验证过程 实现ori指令->建立最小SOPC->验证ori指令是否正确 ori指令说明 ori是进行逻辑"或"的运算指令 ori指令的指令码是6'b001101.处理器 ...

  8. 自己动手写CPU(5)简单算术操作指令实现_1

    自己动手写CPU(5)简单算数操作指令实现_1 指令介绍 MIPS32指令集架构定义的所有算术操作指令,共有21条 共有三类,分别是: 简单算术指令 乘累加.乘累减指令 除法指令 算术指令操作介绍 一 ...

  9. ARM的批量加载/存储指令

    批量加载/存储指令格式: LDMXX|STMXX{条件符}{寻址模式}Rb{!},{寄存器列表} 其中XX表示IA/IB/DA/DB. LDMIA/STMIA    访问/存储后地址递增(Increm ...

最新文章

  1. 反正我不信!马斯克谈元宇宙:没人愿意把屏幕贴脸上
  2. php数据采集类,一个数据采集类
  3. 计算机应用基础形成性考核册答案,2019年最新(电大秋)计算机应用基础形成性考核册题目及答案.doc...
  4. React Native开发环境搭建
  5. [2017-2018上 网络工程] 面向对象预习任务
  6. Java黑皮书课后题第3章:**3.4(随机月份)编写一个随机产生1和12之间整数的程序,并根据数组1,2,3...显示对应的月份
  7. java ee程序设计师_软件设计师:Java EE开发四大常用框架[1]
  8. 图形的花样翻转(洛谷P1205题题解,Java语言描述)
  9. Day9-HTML body属性
  10. data-ajax=“false“
  11. java随机生成字母用三元运算符,【代码笔记】Java常识性基础补充(一)——赋值运算符、逻辑运算符、三元运算符、Scanner类、键盘输入、Random类、随机数...
  12. 什么是人工神经网络模型,人工神经网络模型定义
  13. 负载均衡性能参数如何测评?
  14. Windows Git 多用户多仓库配置
  15. 电脑android模拟器哪个好用,安卓模拟器哪个好用
  16. C语言实现死循环的方式
  17. P语言: 为异步、容错和不确定性而生的编程语言
  18. 用python构建机器学习模型分析空气质量
  19. 暗影精灵5风扇怎么调_惠普暗影精灵5super散热改装
  20. 数据分析在金融行业中的应用

热门文章

  1. 任意模数ntt_【知识总结】多项式全家桶(三)(任意模数NTT)
  2. 计划任务以及日志管理
  3. 2021 年全国职业院校技能大赛(中职组) 网络安全竞赛 A 模块评分标准
  4. Mac磁盘格式化与系统重装
  5. 将Navicat右键表【对象信息】-【DDL】的内容转换为JavaBean
  6. 面试算法题:1 到 1000 之间有多少个 7?
  7. android自带的icon矢量图
  8. 1999-2021地级市GDP及一二三产业GDP数据
  9. 华为总裁任正非新年致辞:没什么能阻挡前进
  10. 计算机无法找到实达打印机,无法安装打印机