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

目标

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

加载存储指令说明

31-2625-2120-1615-0useagefunction
LB(100000)basertoffsetlb rt,offset(base)从内存中指定的地址处,读取一个字节,然后符号扩展至32位,保存到地址为rt的通用寄存器中
LBU(100100)basertoffsetlbu rt,offset(base)同上,有符号改为无符号
LH(100001)basertoffsetlh rt,offset(base)从内存中指定的加载地址处读取一个半字,然后符号扩展到32位,保存到地址为rt的通用寄存器中。该指令有地址对齐要求,要求加载地址的最低位为0
LHU(100101)basertoffsetlhu rt,offset(base)同上,有符号改为无符号
LW(100011)basertoffsetlw rt,offset(base)从内存中指定的加载地址处,读取一个字,保存到地址为rt的通用寄存器中,该指令有地址对齐要求,要求加载地址的最低两位为00

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

存储指令说明

31-2625-2120-1615-0useagefunction
SB(101000)basertoffsetsb rt,offset(base)将地址为rt的通用寄存器的最低字节存储到内存中的指定地址
SH(101001)basertoffsetsh rt,offset(base)将地址为rt的通用寄存器的 最低两个字节存储 到内存中的指定地址。 该指令有地址对齐要求,要求计算出来的存储地址的最低位为0
SW(101011)basertoffsetsw 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-2625-2120-1615-0useagefunction
LWL(100010)basertoffsetlwl rt,offset(base)从内存指定的加载地址处,加载一个字的最高有效部分,没有地址对齐要求。
LWR(100110)basertoffsetlwr 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-2625-2120-1615-0useagefunction
SWL(101010)basertoffsetswl rt,offset(base)将地址为rt的通用寄存器的高位部分存储到内存中指定的地址,存储地址最后两位确定了要存储的rt通用寄存器的哪几个字节,swl指令对存储指令没有对齐要求(将地址为rt的通用寄存器的最高4-n个字节存储到storeaddr)
SWR(101110)basertoffsetswr 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) begin
			aluop_o <= `EXE_NOP_OP;
			alusel_o <= `EXE_RES_NOP;//nop
			wd_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];//rs
			reg2_addr_o <= inst_i[20:16];//rt
			imm <= `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 //指令码是SPECIAL
		  		case(op2)//功能码
		  			5'b00000: begin
		  				case(op3) //依据功能码判断是哪一个指令
								`EXE_OR: begin //or R型指令 rs|rt -> rd
									wreg_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:begin
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_AND_OP;//R rs&rt ->rd
									alusel_o <=  `EXE_RES_LOGIC;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_XOR:begin
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_XOR_OP;// R rs^rt ->rd
									alusel_o <= `EXE_RES_LOGIC;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_NOR:begin
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_NOR_OP;// R rs~|rt ->rd
									alusel_o <= `EXE_RES_LOGIC;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_SLLV:begin
									wreg_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:begin
									wreg_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:begin
									wreg_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:begin
									wreg_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:begin
									wreg_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;//rs
									reg2_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)begin
									wreg_o <= `WriteEnable;
									end else begin
									wreg_o <= `WriteDisable;
									end
								end
								`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)begin
									wreg_o <= `WriteEnable;
									end else begin
									wreg_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+rt
									wreg_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:begin
									wreg_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:begin
									wreg_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:begin
									wreg_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:begin
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_MULT_OP;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_MULTU:begin
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_MULTU_OP;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end 	
								`EXE_DIV:begin
									wreg_o <= `WriteDisable;
									aluop_o <= `EXE_DIV_OP;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_DIVU:begin
									wreg_o <= `WriteDisable;
									aluop_o <= `EXE_DIVU_OP;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_JR:begin
									wreg_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:begin
									wreg_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;
								end
								default:begin
								end
								endcase
								end
								
								
								
		  					default: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];
		  					end
		  				endcase//op3
		  			end	// 5'b00000
					`EXE_J:begin
						wreg_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:begin
						wreg_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;//要写入的目的寄存器的地址 寄存器$1
						link_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:begin
						wreg_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;
						end
					end
					`EXE_BGTZ:begin
						wreg_o <= `WriteDisable;
						aluop_o <= `EXE_BGTZ_OP;
						alusel_o <= `EXE_RES_JUMP_BRANCH;
						reg1_read_o <= 1'b1;//rs
						reg2_read_o <= 1'b0;
						instvalid <= `InstValid;
						if((reg1_o[31] == 1'b0)&&(reg1_o != `ZeroWord))begin
							branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
							branch_flag_o <= `Branch;
							next_inst_in_delayslot_o <= `InDelaySlot;
						end
					end
					`EXE_BLEZ:begin
						wreg_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))begin
							branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
							branch_flag_o <= `Branch;
							next_inst_in_delayslot_o <= `InDelaySlot;
						end
					end
					`EXE_BNE:begin
						wreg_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)begin
							branch_target_address_o <= pc_plus_4+imm_sll2_signedext;
							branch_flag_o <= `Branch;
							next_inst_in_delayslot_o <= `InDelaySlot;
						end
					end
					`EXE_REGIMM_INST:begin
						case(op4)
							`EXE_BLTZAL:begin//bltzal
								wreg_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<0
									branch_target_address_o <= pc_plus_4+imm_sll2_signedext;
									branch_flag_o <= `Branch;
									next_inst_in_delayslot_o <= `InDelaySlot;
								end
							end
							`EXE_BLTZ:begin//bltz
								wreg_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)begin
									branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
									branch_flag_o <= `Branch;
									next_inst_in_delayslot_o <= `InDelaySlot;
								end
							end
							`EXE_BGEZ:begin//bgez
								wreg_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的值大于等于0
									branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
									branch_flag_o <= `Branch;
									next_inst_in_delayslot_o <= `InDelaySlot;
								end
							end
							`EXE_BGEZAL:begin//bgezal
								wreg_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)begin
									branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
									branch_flag_o <= `Branch;
									next_inst_in_delayslot_o <= `InDelaySlot;
								end
							end
					default:begin
				end
				endcase		// 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 //andi
		  		wreg_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];//rt
		  		instvalid = `InstValid;
		  	end
		  	`EXE_XORI:begin//xori
		  		wreg_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//lui
		  		wreg_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//pref
		  		wreg_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:begin
		  		wreg_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:begin
		  		wreg_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:begin
		  		wreg_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:begin
		  		wreg_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:begin
		  		wreg_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:begin
		  		wreg_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:begin
		  		wreg_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 ======> base
		  		reg2_read_o <= 1'b1;
		  		instvalid <= `InstValid;
		  		alusel_o <= `EXE_RES_LOAD_STORE;
		  	end
		  	`EXE_SH:begin
		  		wreg_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:begin
		  		wreg_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:begin
		  		wreg_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:begin
		  		wreg_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:begin
		  				wreg_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:begin
		  				wreg_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:begin
		  				wreg_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:begin
		  				wreg_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:begin
		  				wreg_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:begin
		  				wreg_o <= `WriteDisable;
		  				aluop_o <= `EXE_MSUBU_OP;
		  				alusel_o <= `EXE_RES_MUL;
		  				reg1_read_o <= 1'b1;
		  				reg2_read_o <= 1'b1;
		  				instvalid <= `InstValid;
		  			end
					default:begin
					 end
				endcase //EXE_SPECIAL_INST2 case
			end				 
		    default:begin
		    end
		endcase		  //case op		
		if(inst_i[31:21] == 11'b00000000000)begin //sll,srl,sra
		  	if(op3 == `EXE_SLL) begin
		  		wreg_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)begin
		  		wreg_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) begin
		  		wreg_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
		  	//end
		end       //if
	end 
end        //always
	
/*       数据前推
给reg1_o赋值过程增加了两种情况
1:如果Regfile模块读端口1要读取的寄存器就是执行阶段要写的目的寄存器,那么直接把执行阶段的结果ex_wdata_i作为reg1_o的值
2:如果Regfile模块读端口1要读取的寄存器就是访存阶段要写的目的寄存器,那么直接把访存阶段的结果mem_wdata_i作为reg1_o的值*/
	always @ (*) begin
		if(rst == `RstEnable) begin
			reg1_o <= `ZeroWord;		
		end else if((reg1_read_o == 1'b1) && (ex_wreg_i == 1'b1) 
								&& (ex_wd_i == reg1_addr_o)) begin
			reg1_o <= ex_wdata_i; 
		end else if((reg1_read_o == 1'b1) && (mem_wreg_i == 1'b1) 
								&& (mem_wd_i == reg1_addr_o)) begin
			reg1_o <= mem_wdata_i; 			
	  end else if(reg1_read_o == 1'b1) begin
	  	reg1_o <= reg1_data_i;
	  end else if(reg1_read_o == 1'b0) begin
	  	reg1_o <= imm;
	  end else begin
	    reg1_o <= `ZeroWord;
	  end
	end
	
	always @ (*) begin
		if(rst == `RstEnable) begin
			reg2_o <= `ZeroWord;
		end else if((reg2_read_o == 1'b1) && (ex_wreg_i == 1'b1) 
								&& (ex_wd_i == reg2_addr_o)) begin
			reg2_o <= ex_wdata_i; 
		end else if((reg2_read_o == 1'b1) && (mem_wreg_i == 1'b1) 
								&& (mem_wd_i == reg2_addr_o)) begin
			reg2_o <= mem_wdata_i;			
	  end else if(reg2_read_o == 1'b1) begin
	  	reg2_o <= reg2_data_i;
	  end else if(reg2_read_o == 1'b0) begin
	  	reg2_o <= imm;
	  end else begin
	    reg2_o <= `ZeroWord;
	  end
	end


//输出变量is_in_delayslot_o表示当前译码阶段指令是否是延迟槽指令
always @ (*)begin
	if(rst == `RstEnable)begin
		is_in_delayslot_o <= `NotInDelaySlot;
	end else begin
		//直接等于is_in_delayslot_i
		is_in_delayslot_o <= is_in_delayslot_i;
	end
end

endmodule


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) 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;
			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*/
	end
	end
	
endmodule
	

执行模块

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//1
	if(rst == `RstEnable)
	begin//2
		logicout <= `ZeroWord;
	end//2
	else
	begin//3
		case(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;
			end
			default:begin//6
				logicout <= `ZeroWord;
			end//6
		endcase//4
	end//3
end//1
always @ (*) begin
	if(rst == `RstEnable)begin
		shiftres <= `ZeroWord;
	end else begin
		case(aluop_i)
			`EXE_SLL_OP:begin //逻辑左移
				shiftres <= reg2_i << reg1_i[4:0];
			end
			`EXE_SRL_OP:begin //逻辑右移
				shiftres <= reg2_i >> reg1_i[4:0];
			end
			`EXE_SRA_OP:begin//算术右移1
				shiftres <= ({32{reg2_i[31]}}<<(6'd32-{1'b0,reg1_i[4:0]})) |/*rt向右移sa位*/ reg2_i>>reg1_i[4:0];
			end
			default:begin
			 shiftres <= `ZeroWord;
		end
	endcase
end
end
	
/******************************************************************
****第三段:得到最新的HI,LO寄存器的值,此处要解决数据相关的问题****
******************************************************************/
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};//访存阶段的指令要写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 @ (*) begin
	if(rst == `RstEnable) begin
		moveres <= `ZeroWord;
	end else begin
		moveres <= `ZeroWord;
		case(aluop_i)
			`EXE_MFHI_OP:begin
				//rd<-hi
				moveres <= HI;//HI的值是移动操作的结果
			end
			`EXE_MFLO_OP:begin
				//rd<-lo
				moveres <= LO;
			end
			`EXE_MOVN_OP:begin
				//rd<-rs
				moveres <= reg1_i;
			end
			`EXE_MOVZ_OP:begin
				//rd<-rs
				moveres <= reg1_i;
			end
			default:begin
			end
		endcase
	end
end
/***************************************************************
*******如果是MTHI,MTLO指令,需要给出whilo_o,hi_o,lo_o的值*******
***************************************************************/                 
always @ (*)begin
	if(rst == `RstEnable) begin
		whilo_o <= `WriteDisable;
		hi_o <= `ZeroWord;
		lo_o <= `ZeroWord;
	end else if(aluop_i == `EXE_MTHI_OP)begin
		whilo_o <= `WriteEnable;
		hi_o <= reg1_i;
		lo_o <= LO;//写HI寄存器所以LO保持不变
	end else if(aluop_i == `EXE_MTLO_OP)begin
		whilo_o <= `WriteEnable;
		hi_o <= HI;
		lo_o <= reg1_i;
	end else begin
		whilo_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 @ (*) begin
	if(rst == `RstEnable)begin
		arithmeticres <= `ZeroWord;
	end else begin
		case(aluop_i) //选择运算类型
			`EXE_SLT_OP,`EXE_SLTU_OP:begin
				arithmeticres <= reg1_lt_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 //计数运算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 //计数运算clo
				arithmeticres <= (reg1_i_not[31]?0:
													reg1_i_not[30]?1:
													reg1_i_not[29]?2:
													reg1_i_not[28]?3:
													reg1_i_not[27]?4:
													reg1_i_not[26]?5:
													reg1_i_not[25]?6:
													reg1_i_not[24]?7:
													reg1_i_not[23]?8:
													reg1_i_not[22]?9:
													reg1_i_not[21]?10:
													reg1_i_not[20]?11:
													reg1_i_not[19]?12:
													reg1_i_not[18]?13:
													reg1_i_not[17]?14:
													reg1_i_not[16]?15:
													reg1_i_not[15]?16:
													reg1_i_not[14]?17:
													reg1_i_not[13]?18:
													reg1_i_not[12]?19:
													reg1_i_not[11]?20:
													reg1_i_not[10]?21:
													reg1_i_not[9]?22:
													reg1_i_not[8]?23:
													reg1_i_not[7]?24:
													reg1_i_not[6]?25:
													reg1_i_not[5]?26:
													reg1_i_not[4]?27:
													reg1_i_not[3]?28:
													reg1_i_not[2]?29:
													reg1_i_not[1]?30:
													reg1_i_not[0]?31:32);
												end
												default:begin
													arithmeticres <= `ZeroWord;
												end
											endcase
										end
									end 
/*****************************************************************
************************第七段:进行乘法运算***********************
*****************************************************************/
/*(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//1
	if(rst == `RstEnable) begin//2
		mulres <= {`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//3
		if(reg1_i[31]^reg2_i[31] == 1'b1)begin//4 被乘数和乘数一正一负
			mulres <= ~hilo_temp+1;
		end/*4*/ else begin//5 被乘数和乘数同号
			mulres <= hilo_temp;
		end//5
		end/*3*/ else begin//6 无符号乘法
			mulres <= hilo_temp;
		end//6
	end//1
/*****************************************************************
****************第八段:确定要写入目的寄存器的数据*****************
*****************************************************************/
always @ (*)begin
	wd_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))begin
		wreg_o <= `WriteDisable;
	end else begin
		wreg_o <= wreg_i;
	end
	case(alusel_i)
		`EXE_RES_LOGIC:begin
			wdata_o <= logicout;
		end
		`EXE_RES_SHIFT:begin
			wdata_o <= shiftres;
		end
		`EXE_RES_MOVE:begin
			wdata_o <= moveres;
		end
		`EXE_RES_ARITHMETIC:begin//除乘法外的简单算术操作指令
			wdata_o <= arithmeticres;
		end
		`EXE_RES_MUL:begin//乘法指令mul
			wdata_o <= mulres[31:0];
		end
		`EXE_RES_JUMP_BRANCH:begin
			wdata_o <= link_address_i;
		end
		default:begin
			wdata_o <= `ZeroWord;
		end
	endcase
end//always

/****************************************************************
********************第十段:乘累加、乘累减************************
****************************************************************/
//MADD MADDU MSUB MSUBU指令
always @ (*) begin
	if(rst == `RstEnable) begin
		hilo_temp_o <= {`ZeroWord,`ZeroWord};
		cnt_o <= 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_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;//乘累加指令执行结束 不再请求流水线暂停
				end
			end
			`EXE_MSUB_OP,`EXE_MSUBU_OP:begin
				if(cnt_i == 2'b00) begin
					hilo_temp_o <= ~mulres+1;
					cnt_o <= 2'b01;
					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};
					stallreq_for_madd_msub <= `NoStop;
				end
			end
			default:begin
				hilo_temp_o <= {`ZeroWord,`ZeroWord};
				cnt_o <= 2'b00;
				stallreq_for_madd_msub <= `NoStop;
			end
		endcase
	end
end
/****************************************************************
******第十二段:输出DIV模块控制信息,获取DIV模块给出的结果*********
****************************************************************/
always @ (*) begin
	if(rst == `RstEnable)begin
		stallreq_for_div <= `NoStop;
		div_opdata1_o <= `ZeroWord;
		div_opdata2_o <= `ZeroWord;
		div_start_o <= `DivStop;
		signed_div_o <= 1'b0;
	end else begin
		stallreq_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:begin
				if(div_ready_i == `DivResultNotReady) begin
					div_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) begin
					div_opdata1_o <= reg1_i;
					div_opdata2_o <= reg2_i;
					div_start_o <= `DivStop;//结束除法运算
					signed_div_o <= 1'b1;
					stallreq_for_div <= `NoStop;//不再请求流水线暂停
				end else begin
					div_opdata1_o <= `ZeroWord;
					div_opdata2_o <= `ZeroWord;
					div_start_o <= `DivStop;
					signed_div_o <= 1'b0;
					stallreq_for_div <= `NoStop;
				end
			end
			`EXE_DIVU_OP:begin
				if(div_ready_i == `DivResultNotReady) begin
					div_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) begin
					div_opdata1_o <= reg1_i;
					div_opdata2_o <= reg2_i;
					div_start_o <= `DivStop;
					signed_div_o <= 1'b0;
					stallreq_for_div <= `NoStop;
				end else begin
					div_opdata1_o <= `ZeroWord;
					div_opdata2_o <= `ZeroWord;
					div_start_o <= `DivStop;
					signed_div_o <= 1'b0;
					stallreq_for_div <= `NoStop;
				end
			end
			default:begin
			end
		endcase
	end
end
			
/****************************************************************
*********************第十一段:暂停流水线*************************
****************************************************************/
//目前只有乘累加和乘累减指令会导致流水线暂停,所以stallreq=stallreq_for_madd_msub
always @ (*) begin
	stallreq = stallreq_for_madd_msub || stallreq_for_div;
end
/****************************************************************
****************第九段:确定(修改)对HI,LO寄存器的操作信息*********
****************************************************************/
always @ (*)begin
	if(rst == `RstEnable) begin
		whilo_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)begin
		whilo_o <= `WriteEnable;
		hi_o <= reg1_i;
		lo_o <= LO;//写HI寄存器所以LO保持不变
	end else if(aluop_i == `EXE_MTLO_OP)begin
		whilo_o <= `WriteEnable;
		hi_o <= HI;
		lo_o <= reg1_i;
	end else if((aluop_i == `EXE_MSUB_OP)||(aluop_i == `EXE_MSUBU_OP))begin
		whilo_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))begin
		whilo_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))begin
		whilo_o <= `WriteEnable;
		hi_o <= div_result_i[63:32];
		lo_o <= div_result_i[31:0];
	end else begin
		whilo_o <= `WriteDisable;
		hi_o <= `ZeroWord;
		lo_o <= `ZeroWord;
	end 
		
end

endmodule

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) begin
		if(rst == `RstEnable) begin
			mem_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)begin
			mem_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)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_o <= {`ZeroWord,`ZeroWord};
			cnt_o <= 2'b00;
			mem_aluop <= ex_aluop;
			mem_mem_addr <= ex_mem_addr;
			mem_reg2 <= ex_reg2;
		end else begin
			hilo_o <= hilo_i;
			cnt_o <= cnt_i;				
		end    //if
	end      //always
			

endmodule

访存模块

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 @ (*)
begin
	if(rst == `RstEnable)
	begin
	wd_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 
begin
	wd_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;//0x0
				end
				2'b01:begin
					wdata_o <= {{24{mem_data_i[23]}},mem_data_i[23:16]};//次高位
					mem_sel_o <= 4'b0100;//0x1
				end
				2'b10:begin
					wdata_o <= {{24{mem_data_i[15]}},mem_data_i[15:8]};
					mem_sel_o <= 4'b0010;//0x2
				end
				2'b11:begin
					wdata_o <= {{24{mem_data_i[7]}},mem_data_i[7:0]};
					mem_sel_o <= 4'b0001; //0x3
				end
				default:begin
					wdata_o <= `ZeroWord;
				end
			endcase
		end
		`EXE_LBU_OP:begin
			mem_addr_o <= mem_addr_i;
			mem_we <= `WriteDisable;
			mem_ce_o <= `ChipEnable;
			case(mem_addr_i[1:0])
				2'b00:begin
					wdata_o <= {{24{1'b0}},mem_data_i[31:24]};
					mem_sel_o <= 4'b1000;
				end
				2'b01:begin
					wdata_o <= {{24{1'b0}},mem_data_i[23:16]};
					mem_sel_o <= 4'b0100;
				end
				2'b10:begin
					wdata_o <= {{24{1'b0}},mem_data_i[15:8]};
					mem_sel_o <= 4'b0010;
				end
				2'b11:begin
					wdata_o <= {{24{1'b0}},mem_data_i[7:0]};
					mem_sel_o <= 4'b0001;
				end
				default:begin
					wdata_o <= `ZeroWord;
				end
			endcase
		end
		`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:begin
					wdata_o <= {{16{mem_data_i[31]}},mem_data_i[31:16]};//读取最低8位
					mem_sel_o <= 4'b1100;//从0x0开始读取2个字节
				end
				2'b10:begin
					wdata_o <= {{16{mem_data_i[15]}},mem_data_i[15:0]};
					mem_sel_o <= 0011;
				end
				default:begin
					wdata_o <= `ZeroWord;
				end
			endcase
		end
		`EXE_LHU_OP:begin
			mem_addr_o <= mem_addr_i;
			mem_we <= `WriteDisable;
			mem_ce_o <= `ChipEnable;
			case(mem_addr_i[1:0])
				2'b00:begin
					wdata_o <= {{16{1'b0}},mem_data_i[31:16]};
					mem_sel_o <= 4'b1100;
				end
				2'b10:begin
					wdata_o <= {{16{1'b0}},mem_data_i[15:0]};
					mem_sel_o <= 4'b0011;
				end
				default:begin
				wdata_o <= `ZeroWord;
			end
		endcase
	end
	`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:begin
				wdata_o <= mem_data_i[31:0];//32位 (4-0)*8
			end
			2'b01:begin
				wdata_o <= {mem_data_i[23:0],reg2_i[7:0]};//24位 (4-1)*8
			end
			2'b10:begin
				wdata_o <= {mem_data_i[15:0],reg2_i[15:0]};//16位 (4-2)*8
			end
			2'b11:begin
				wdata_o <= {mem_data_i[7:0],reg2_i[23:0]};//8位 (4-3)*8
			end
			default:begin
				wdata_o <= `ZeroWord;
			end
		endcase
	end
	`EXE_LWR_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])
			2'b00:begin
				wdata_o <= {reg2_i[31:8],mem_data_i[31:24]};//低位保存8位
			end
			2'b01:begin
				wdata_o <= {reg2_i[31:16],mem_data_i[31:16]};//低位保存16位
			end
			2'b10:begin
				wdata_o <= {reg2_i[31:24],mem_data_i[31:8]};//低位保存高24位
			end
			2'b11:begin
				wdata_o <= mem_data_i;
			end
			default:begin
				wdata_o <= `ZeroWord;
			end
		endcase
	end
	`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:begin
				mem_sel_o <= 4'b1000;
			end
			2'b01:begin
				mem_sel_o <= 4'b0100;
			end
			2'b10:begin
				mem_sel_o <= 4'b0010;
			end
			2'b11:begin
				mem_sel_o <= 4'b0001;
			end
			default:begin
				mem_sel_o <= 4'b0000;
			end
		endcase
	end
	`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:begin
				mem_sel_o <= 4'b1100;
			end
			2'b10:begin
				mem_sel_o <= 4'b0011;
			end
			default:begin
				mem_sel_o <= `ZeroWord;
			end
		endcase
	end
	`EXE_SW_OP:begin
		mem_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:begin
				mem_sel_o <= 4'b1111;
				mem_data_o <= reg2_i;
			end
			2'b01:begin
				mem_sel_o <= 4'b0111;
				mem_data_o <= {zero32[7:0],reg2_i[31:8]};//将最高4-1个字节(24bits) 存储到storeaddr
			end
			2'b10:begin
				mem_sel_o <= 4'b0011;//16bits 
				mem_data_o <= {zero32[15:0],reg2_i[31:16]};
			end
			2'b11:begin
				mem_sel_o <= 4'b0001;
				mem_data_o <= {zero32[23:0],reg2_i[31:24]};
			end
			default:begin
				mem_sel_o <= 4'b000;
			end
		endcase
	end
	`EXE_SWR_OP:begin
		mem_addr_o <= {mem_addr_i[31:2],2'b00};
		mem_we <= `WriteEnable;
		mem_ce_o <= `ChipEnable;
		case(mem_addr_i[1:0])
			2'b00:begin
				mem_sel_o <= 4'b1000;
				mem_data_o <= {reg2_i[7:0],zero32[23:0]};
			end
			2'b01:begin
				mem_sel_o <= 4'b1100;
				mem_data_o <= {reg2_i[15:0],zero32[15:0]};
			end
			2'b10:begin
				mem_sel_o <= 4'b1110;
				mem_data_o <= {reg2_i[23:0],zero32[7:0]};
			end
			2'b11:begin
				mem_sel_o <= 4'b1111;
				mem_data_o <= reg2_i[31:0];
			end
			default:begin
				mem_sel_o <= `ZeroWord;
			end
		endcase
	end
	default:begin
	end
endcase

end
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_ram
	input 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,0xeeff
   sb   $3,0x3($0)       # [0x3] = 0xff
   srl  $3,$3,8
   sb   $3,0x2($0)       # [0x2] = 0xee
   ori  $3,$0,0xccdd
   sb   $3,0x1($0)       # [0x1] = 0xdd
   srl  $3,$3,8
   sb   $3,0x0($0)       # [0x0] = 0xcc
   lb   $1,0x3($0)       # $1 = 0xffffffff
   lbu  $1,0x2($0)       # $1 = 0x000000ee
   nop

   ori  $3,$0,0xaabb
   sh   $3,0x4($0)       # [0x4] = 0xaa, [0x5] = 0xbb
   lhu  $1,0x4($0)       # $1 = 0x0000aabb
   lh   $1,0x4($0)       # $1 = 0xffffaabb
 
   ori  $3,$0,0x8899
   sh   $3,0x6($0)       # [0x6] = 0x88, [0x7] = 0x99
   lh   $1,0x6($0)       # $1 = 0xffff8899
   lhu  $1,0x6($0)       # $1 = 0x00008899

   ori  $3,$0,0x4455
   sll  $3,$3,0x10
   ori  $3,$3,0x6677     
   sw   $3,0x8($0)       # [0x8] = 0x44, [0x9]= 0x55, [0xa]= 0x66, [0xb] = 0x77
   lw   $1,0x8($0)       # $1 = 0x44556677

   lwl  $1, 0x5($0)      # $1 = 0xbb889977
   lwr  $1, 0x8($0)      # $1 = 0xbb889944

   nop
   swr  $1, 0x2($0)      # [0x0] = 0x88, [0x1] = 0x99, [0x2]= 0x44, [0x3] = 0xff
   swl  $1, 0x7($0)      # [0x4] = 0xaa, [0x5] = 0xbb, [0x6] = 0x88, [0x7] = 0x44

   lw   $1, 0x0($0)      # $1 = 0x889944ff
   lw   $1, 0x4($0)      # $1 = 0xaabb8844
    
_loop:
   j _loop
   nop

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部分写错了 懒得在这里改了
详细设计可能会另开一篇。。。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值