【自己动手写CPU】协处理器访问指令的实现

协处理器介绍

MIPS32架构定义的协处理器及其作用

协处理器作用
CP0系统控制
CP1FPU(浮点数处理单元)
CP2特定实现
CP3FPU(浮点数处理单元)

CP0负责的主要工作

  • 配置CPU工作状态:通过读写一些个内部寄存器来改变一些很根本的CPU特性
  • 高速缓存控制:集成缓存控制器,来控制、读、写缓存
  • 异常控制:异常发生时的检测和处理都由CP0中的一些控制寄存器来定义和控制
  • 存储管理单元控制:对系统的存储区域进行合理的控制、管理和分配,主要是对MMU,TLB的一些配置、管理、访问
  • 其他:当要把额外功能集成在CPU中,但又不方便当作外设访问时,常常在CP0中增加一些模块来实现这些功能。(例如:时钟、时间计数器、奇偶校验错误检测等)

CP0中寄存器描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

重要寄存器

Count寄存器

不停计数的32位寄存器,计数频率一般与CPU时钟频率相同,当计数达到32位无符号数上限时,从0开始计数。Count寄存器可读可写
Count寄存器的字段

Bit31-0
标志名Count

Compare寄存器

32位寄存器,与Count寄存器一起完成定时中断的功能。当Count寄存器中的值和Compare寄存器中的值一样时,会产生定时中断,这个中断会一直保持,直到有数据被写入Compare寄存器,Compare寄存器可读可写
Compare寄存器的字段

Bit31-0
标志名Compare

Status寄存器

32位可读可写寄存器,用来控制处理器的操作模式、中断使能以及诊断状态

Status寄存器的各个字段

Bit31-2827262524-2322212019
标志名CU3-CU0RPRRE0BEVTSSRNMI
Bit18-1615-87-543210
标志名0IM7-IM0RUMRERLEXLIE

标识为R是保留字段

  • CU3-CU0表示协处理器是否可用,分别控制协处理器CP3,CP2,CP1,CP0。为0时,表示相应的协处理器不可用,为1时,表示相应的协处理器可用。此处只有协处理器CP0,所以设置本字段为4'b0001
  • SR表示是否软重启,为1表示重启异常是有软重启引起的
  • NMI表示是否不可屏蔽中断,为1表示重启异常是由不可屏蔽中断引起的
  • IM7-IM0表示是否屏蔽相应中断,0表示屏蔽,1表示不屏蔽,MIPS处理器有8个中断源,对应IM字段的8位,其中6个中断源是处理器外部硬件中断,另外2个是软件中断,中断是都能被处理器响应是由Status寄存器和Cause寄存器共同决定的,如果Status寄存器的IM字段与Cause寄存器的IP字段的相应位都为1,而且Status寄存器的IE字段也为1时,处理器才相应中断
  • EXL表示手处于异常级,当异常发生时,会设置本字段为1,表示处理器处于异常级,此时,处理器会进入内核模式下工作,并且禁止中断
  • IE表示是否使能中断,这是全局中断使能标志位,为1表示中断使能,为0表示中断禁止

Cause寄存器

在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述

EPC寄存器和PRId寄存器

在这里插入图片描述

Config寄存器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

CP0的实现

在这里插入图片描述

`include "define.v"
module cp0_reg(
input wire clk,
input rst,

input wire we_i,//是否要写CP0中的寄存器
input wire[4:0] waddr_i,//要写的CP0中的寄存器地址
input wire[4:0] raddr_i,//要读取的CP0中寄存器的地址
input wire[`RegBus] wdata_i,//要写入CP0中寄存器的数据
input wire[5:0] int_i,//6个外部硬件中断输入

output reg[`RegBus] data_o,//读出CP0中某个寄存器的值
output reg[`RegBus] count_o,//Count寄存器的值
output reg[`RegBus] compare_o,//Compare寄存器的值
output reg[`RegBus] status_o,//Status寄存器的值
output reg[`RegBus] cause_o,//Cause寄存器的值
output reg[`RegBus] epc_o,//EPC寄存器的值
output reg[`RegBus] config_o,//Config寄存器的值
output reg[`RegBus] prid_o,//PRId寄存器的值

output reg timer_int_o//是否有定时中断产生
);
//第一段:对CP0中寄存器的写操作
always @(posedge clk)begin
	if(rst == `RstEnable)begin
		count_o <= `ZeroWord;//Count寄存器的初始值为0
		compare_o <= `ZeroWord;//Compare寄存器的初始值为0
		status_o <= 32'b0001_0000_0000_0000_0000_0000_0000_0000;//CU字段为0001表示协处理器CP0存在
		cause_o <= `ZeroWord;//Cause寄存器的初始值为0
		epc_o <= `ZeroWord;
		config_o <= 32'b0000_0000_0000_0000_1000_0000_0000_0000;//BE字段为1 表示工作在大端模式
		prid_o <= 32'b0000_0000_0100_1100_0000_0001_0000_0010;//制作者L 对应0x48 类型0x1 表示是基本类型 版本号1.0
		timer_int_o <= `InterrputNotAssert;
	end else begin
		count_o <= count_o+1;//Count寄存器的值在每个时钟周期都加1
		cause_o[15:0] <= int_i;//Cause的第10到15bit保存外部中断声明
		//当Compare不为0且Count寄存器的值等于Compare寄存器的值时,将输出信号timer_int_o置为1 表示时钟中断发生
		if(compare_o != `ZeroWord && count_o == compare_o) begin
			timer_int_o <= `InterrputNotAssert;
		end
		if(we_i == `WriteEnable)begin
			case(waddr_i)
				`CP0_REG_COUNT:begin
					count_o <= data_i;//写Count寄存器
				end
				`CP0_REG_COMPARE:begin
					compare_o <= data_i;//写Compare寄存器
				end 
				`CP0_REG_STATUS:begin
					status_o <= data_i;
				end
				`CP0_REG_EPC:begin
					epc_o <= data_i;
				end 
				`CP0_REG_CAUSE:begin
					//Cause寄存器只有IP[1:0] IV WP字段是可写的
					cause_o[9:8] <= data_i[9:8];
					case_o[23] <= data_i[23];
					case_o[22] <= data_i[22];
				end 
			endcase
		end 
	end 
end 
//第二段:对CP0中寄存器的读操作
always @ (*) begin
	if(rst == `RstEnable)begin
		data_o <= `ZeroWord;
	end else begin
		case(raddr_i)
			`CP0_REG_COUNT:begin
				data_o <= count_o;
			end 
			`CP0_REG_COMPARE:begin
				data_o <= compare_o;
			end 
			`CP0_REG_STATUS:begin
				data_o <= status_o;
			end 
			`CP0_REG_CAUSE:begin
				data_o <= cause_o;
			end 
			`CP0_REG_EPC:begin
				data_o <= epc_o;
			end 
			`CP0_REG_PRId:begin
				data_o <= prid_o;
			end 
			`CP0_REG_CONFIG:begin
				data_o <= config_o;
			end 
			default:begin
			end 
		endcase 
	end 
end 
endmodule
	

CP0访问指令说明

31-2625-2120-1615-1110-32-0useagefunction
COP0(010000)MT(00100)rtrd00000000selmtc0 rt,rdCPR[0,rd]<-GPR[rt]将地址为rt的通用寄存器的值赋给协处理器CP0中地址为rd的寄存器
COP0(010000)MF(00000)rtrd00000000selmfc0 rt,rdGPR[rt]<-CPR[0,rd]读出协处理器CP0中地址为rd的通用寄存器,并赋值给地址为rt的通用寄存器

实现思路

mtc0

  • 译码阶段依据指令,读出地址为rt的通用寄存器
  • 执行阶段确定要写入CP0寄存器中的值,即译码阶段读出的地址为rt的通用寄存器的值,将这些信息传递到访存阶段
  • 访存阶段再将这些信息传递到回写阶段
  • 回写阶段依据这些信息修改CP0中地址为rd的寄存器

mfc0

  • 执行阶段获取CP0中指定寄存器的值,作为要写入的通用寄存器的数据,并将这些信息传递到访存阶段
  • 访存阶段将这些信息传递到回写阶段
  • 回写阶段依据这些信息修改地址为rt的通用寄存器

数据流图的修改

在这里插入图片描述

在回写阶段增加了CP0模块,并在CP0模块的输出数据传递到执行阶段,用于确定最后参与运算的操作数,如:mfc0指令在执行阶段就会选择从CP0传递来的数据,作为运算结果,写入目的寄存器

代码的修改

我不想写代码了,我只想把这个流程记住并理解。。。。

id.v

之前id模块diamante写错了,之后有空具体写一期如何改bug。

`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 //新增加的输出接口
	//input wire[`AluOpBus] ex_aluop_i,
	//output wire stallreq
);

  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;//译码阶段的指令
 //新定义一个变量 表示要读取的寄存器1是否与上一条指令存在load相关
 reg stallreq_for_reg1_loadrelate;
 //新定义一个变量 表示要读取的寄存器2是否与上一条指令存在load相关
 reg stallreq_for_reg2_loadrelate;
 //新定义一个变量 表示上一条指令是否是加载指令
 wire pre_inst_is_load;
 //依据输入信号ex_aluop_i值 判断上一条指令是否是加载指令
 //如果是加载指令 那么置pre_inst_is_load为1 反之置0
 assign pre_inst_is_load = ((ex_aluop_i == `EXE_LB_OP)||
(ex_aluop_i == `EXE_LBU_OP)||
(ex_aluop_i == `EXE_LH_OP)||
(ex_aluop_i==`EXE_LHU)||
(ex_aluop_i==`EXE_LW_OP)||
 (ex_aluop_i==`EXE_LWR_OP)||
 (ex_aluop_i==`EXE_LWL_OP)||
 (ex_aluop_i==`EXE_LL_OP)||
 (ex_aluop_i==`EXE_SC_OP)) ? 1'b1 : 1'b0;
 /*如果上一条指令是加载指令 且该加载指令要加载到目的寄存器就是当前指令
 要通过Regfile模块读取端口1读取的通用寄存器,那么表示存在load相关*/
 //设置stallreq_for_reg1_loadrelate为Stop
 always @(*)begin
 	stallreq_for_reg1_loadrelate <= `NoStop;
 	if(rst == `RstEnable)begin
 		reg1_o <= `ZeroWord;
 	end else if(pre_inst_is_load == 1'b1 && ex_wd_i == reg1_addr_o && reg1_read_o == 1'b1)begin
 		stallreq_for_reg1_loadrelate <= `Stop;//存在load相关 Stop
 	end  
end 
//reg2与reg1同理
always @(*)begin
 	stallreq_for_reg2_loadrelate <= `NoStop;
 	if(rst == `RstEnable)begin
 		reg2_o <= `ZeroWord;
 	end else if(pre_inst_is_load == 1'b1 && ex_wd_i == reg2_addr_o && reg2_read_o == 1'b1)begin
 		stallreq_for_reg2_loadrelate <= `Stop;//存在load相关 Stop
 	end  
end 
assign stallreq = stallreq_for_reg1_loadrelate | stallreq_for_reg2_loadrelate;
	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_LL:begin
		  		wreg_o <= `WriteEnable;
		  		aluop_o <= `EXE_LL_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_SC:begin
		  		wreg_o <= `WriteEnable;
		  		aluop_o <= `EXE_SC_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_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 
		  end 
//endcase
		  	//end
		// end else begin     //if
			if(inst_i[31:21]==11'b010_0000_0000&&inst_i[10:0]==11'b000_0000_0000)//mfc0指令
			begin
				aluop_o <= `EXE_MFC0_OP;
				alusel_o <= `EXE_RES_MOVE;//一种移动运算
				wd_o <= inst_i[20:16];//rt 要写的目的寄存器是指令中rt的值
				wreg_o <= `WriteEnable;//需要读取CP0中的寄存器的值写入目的寄存器,要写通用寄存器
				instvalid <= `InstValid;
				reg1_read_o <= 1'b0;
				reg2_read_o <= 1'b0;
			end else if(inst_i[31:21]==11'b010_0000_0100&&inst_i[10:0]==11'b00000000000)//mtc0指令
			begin
				aluop_o <= `EXE_MTC0_OP;
				alusel_o <= `EXE_RES_MOVE;
				wreg_o <= `WriteDisable;//不需要写通用寄存器
				instvalid <= `InstValid;
				reg1_read_o <= 1'b1;//需要读取通用寄存器 通过Regfile1端口读取数据
				reg1_addr_o <= inst_i[20:16];//读取地址是指令中16-20位 是rt的值
				reg2_read_o <= 1'b0;
			end 
	end //if
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

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,//当前处于执行阶段的指令

//访存阶段的指令是否要写CP0中的寄存器 用来检测数据相关
input wire mem_cp0_reg_we,
input wire[4:0] mem_cp0_reg_write_addr,
input wire[`RegBus] mem_cp0_reg_data,
//回写阶段的指令是否要写CP0中的寄存器 也是用来检测数据相关
input wire wb_cp0_reg_we,
input wire[4:0] wb_cp0_reg_write_addr,
input wire[`RegBus] wb_cp0_reg_data,
//与CP0直接相连 用于读取其中指定寄存器的值
input wire[`RegBus] cp0_reg_data_i,
output reg[4:0] cp0_reg_read_addr_o,
//向流水线下一级传递 用于写CP0的指定寄存器的值
output reg cp0_reg_we_o,
output reg[4:0] cp0_reg_write_addr_o,
output reg[`RegBus] cp0_reg_data_o,
//处于执行阶段指令对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
			`EXE_MFC0_OP:begin
				//要从CP0中读取寄存器的地址
				cp0_reg_read_addr_o <= inst_i[15:11];//通过cp0_reg_read_addr_o向CP0模块送出要读取的CP0中寄存器地址
				//读取到的CP0中指定寄存器的值
				moveres <= cp0_reg_data_i;//通过cp0_reg_data_i接口送入ex 赋值给变量moveres
				//判断是否存在数据相关 此时moveres并不一定是CP0中寄存器的最新值
				if(mem_cp0_reg_we == `WriteEnable && mem_cp0_reg_write_addr == inst_i[15:11])
				begin
					moveres <= mem_cp0_reg_data;//与访存阶段存在数据相关
				end else if(wb_cp0_reg_we == `WriteEnable && wb_cp0_reg_write_addr == inst_i[15:11])
				begin
					moveres <= wb_cp0_reg_data;//与回写阶段存在数据相关
				end 
			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
/*********************************************************************
******************第十三段:给出mtc0指令执行的结果*********************
*********************************************************************/
always @ (*) begin
	if(rst == `RstEnable)begin
		cp0_reg_write_addr_o <= 5'b00000;
		cp0_reg_we_o <= `WriteDisable;
		cp0_reg_data_o <= `ZeroWord;
	end else if(aluop_i == `EXE_MTC0_OP)begin//如果是mtc0指令
		cp0_reg_write_addr_o <= inst_i[15:11];//写入地址为指令中第11-15为的值
		cp0_reg_we_o <= `WriteEnable;//设置写操作信号cp0_reg_we_o为可写
		cp0_reg_data_o <= reg1_i;//写入的值就是译码阶段传递来的reg1_i的值 正是rt通用寄存器的值
	end else begin
		cp0_reg_write_addr_o <= 5'b00000;
		cp0_reg_we_o <= `WriteDisable;
		cp0_reg_data_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,

	input wire[`DoubleRegBus]     hilo_i,	
	input wire[1:0]               cnt_i,	

	input wire                   ex_cp0_reg_we,
	input wire[4:0]              ex_cp0_reg_write_addr,
	input wire[`RegBus]          ex_cp0_reg_data,	
	
	//送到访存阶段的信息
	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[`AluOpBus]        mem_aluop,
	output reg[`RegBus]          mem_mem_addr,
	output reg[`RegBus]          mem_reg2,
	
	output reg                   mem_cp0_reg_we,
	output reg[4:0]              mem_cp0_reg_write_addr,
	output reg[`RegBus]          mem_cp0_reg_data,
		
	output reg[`DoubleRegBus]    hilo_o,
	output reg[1:0]              cnt_o	
	
	
);


	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;	
			mem_cp0_reg_we <= `WriteDisable;
			mem_cp0_reg_write_addr <= 5'b00000;
			mem_cp0_reg_data <= `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;		
			mem_cp0_reg_we <= `WriteDisable;
			mem_cp0_reg_write_addr <= 5'b00000;
			mem_cp0_reg_data <= `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;
			mem_cp0_reg_we <= ex_cp0_reg_we;
			mem_cp0_reg_write_addr <= ex_cp0_reg_write_addr;
			mem_cp0_reg_data <= ex_cp0_reg_data;						
		end else begin
	    hilo_o <= hilo_i;
			cnt_o <= cnt_i;											
		end    //if
	end      //always
			

endmodule

mem.v

`include "define.v"
module mem(

	input wire										rst,
	
	//来自执行阶段的信息	
	input wire[`RegAddrBus]       wd_i,
	input wire                    wreg_i,
	input wire[`RegBus]					  wdata_i,
	input wire[`RegBus]           hi_i,
	input wire[`RegBus]           lo_i,
	input wire                    whilo_i,	

  input wire[`AluOpBus]        aluop_i,
	input wire[`RegBus]          mem_addr_i,
	input wire[`RegBus]          reg2_i,
	
	//来自memory的信息
	input wire[`RegBus]          mem_data_i,

	//LLbit_i是LLbit寄存器的值
	input wire                  LLbit_i,
	//但不一定是最新值,回写阶段可能要写LLbit,所以还要进一步判断
	input wire                  wb_LLbit_we_i,
	input wire                  wb_LLbit_value_i,

	//协处理器CP0的写信号
	input wire                   cp0_reg_we_i,
	input wire[4:0]              cp0_reg_write_addr_i,
	input wire[`RegBus]          cp0_reg_data_i,
	
	//送到回写阶段的信息
	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,

	output reg                   LLbit_we_o,
	output reg                   LLbit_value_o,

	output reg                   cp0_reg_we_o,
	output reg[4:0]              cp0_reg_write_addr_o,
	output reg[`RegBus]          cp0_reg_data_o,
	
	//送到memory的信息
	output reg[`RegBus]          mem_addr_o,
	output wire									 mem_we_o,
	output reg[3:0]              mem_sel_o,
	output reg[`RegBus]          mem_data_o,
	output reg                   mem_ce_o	
	
);

  reg LLbit;
	wire[`RegBus] zero32;
	reg                   mem_we;

	assign mem_we_o = mem_we ;
	assign zero32 = `ZeroWord;

  //获取最新的LLbit的值
	always @ (*) begin
		if(rst == `RstEnable) begin
			LLbit <= 1'b0;
		end else begin
			if(wb_LLbit_we_i == 1'b1) begin
				LLbit <= wb_LLbit_value_i;
			end else begin
				LLbit <= LLbit_i;
			end
		end
	end
	
	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;	
		  LLbit_we_o <= 1'b0;
		  LLbit_value_o <= 1'b0;		
		  cp0_reg_we_o <= `WriteDisable;
		  cp0_reg_write_addr_o <= 5'b00000;
		  cp0_reg_data_o <= `ZeroWord;		        
		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;
		  LLbit_we_o <= 1'b0;
		  LLbit_value_o <= 1'b0;		
		  cp0_reg_we_o <= cp0_reg_we_i;
		  cp0_reg_write_addr_o <= cp0_reg_write_addr_i;
		  cp0_reg_data_o <= cp0_reg_data_i;		 		  	
			case (aluop_i)
				`EXE_LB_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{mem_data_i[31]}},mem_data_i[31:24]};
							mem_sel_o <= 4'b1000;
						end
						2'b01:	begin
							wdata_o <= {{24{mem_data_i[23]}},mem_data_i[23:16]};
							mem_sel_o <= 4'b0100;
						end
						2'b10:	begin
							wdata_o <= {{24{mem_data_i[15]}},mem_data_i[15:8]};
							mem_sel_o <= 4'b0010;
						end
						2'b11:	begin
							wdata_o <= {{24{mem_data_i[7]}},mem_data_i[7:0]};
							mem_sel_o <= 4'b0001;
						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
					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]};
							mem_sel_o <= 4'b1100;
						end
						2'b10:	begin
							wdata_o <= {{16{mem_data_i[15]}},mem_data_i[15:0]};
							mem_sel_o <= 4'b0011;
						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;
					mem_we <= `WriteDisable;
					wdata_o <= mem_data_i;
					mem_sel_o <= 4'b1111;		
					mem_ce_o <= `ChipEnable;
				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])
						2'b00:	begin
							wdata_o <= mem_data_i[31:0];
						end
						2'b01:	begin
							wdata_o <= {mem_data_i[23:0],reg2_i[7:0]};
						end
						2'b10:	begin
							wdata_o <= {mem_data_i[15:0],reg2_i[15:0]};
						end
						2'b11:	begin
							wdata_o <= {mem_data_i[7:0],reg2_i[23:0]};	
						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]};
						end
						2'b01:	begin
							wdata_o <= {reg2_i[31:16],mem_data_i[31:16]};
						end
						2'b10:	begin
							wdata_o <= {reg2_i[31:24],mem_data_i[31:8]};
						end
						2'b11:	begin
							wdata_o <= mem_data_i;	
						end
						default:	begin
							wdata_o <= `ZeroWord;
						end
					endcase					
				end
				`EXE_LL_OP:		begin
					mem_addr_o <= mem_addr_i;
					mem_we <= `WriteDisable;
					wdata_o <= mem_data_i;	
		  		LLbit_we_o <= 1'b1;
		  		LLbit_value_o <= 1'b1;
		  		mem_sel_o <= 4'b1111;			
		  		mem_ce_o <= `ChipEnable;						
				end				
				`EXE_SB_OP:		begin
					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
					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 <= 4'b0000;
						end
					endcase						
				end
				`EXE_SW_OP:		begin
					mem_addr_o <= mem_addr_i;
					mem_we <= `WriteEnable;
					mem_data_o <= reg2_i;
					mem_sel_o <= 4'b1111;			
					mem_ce_o <= `ChipEnable;
				end
				`EXE_SWL_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'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]};
						end
						2'b10:	begin
							mem_sel_o <= 4'b0011;
							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'b0000;
						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 <= 4'b0000;
						end
					endcase											
				end 
				`EXE_SC_OP:		begin
					if(LLbit == 1'b1) begin
						LLbit_we_o <= 1'b1;
						LLbit_value_o <= 1'b0;
						mem_addr_o <= mem_addr_i;
						mem_we <= `WriteEnable;
						mem_data_o <= reg2_i;
						wdata_o <= 32'b1;
						mem_sel_o <= 4'b1111;	
						mem_ce_o <= `ChipEnable;					
					end else begin
						wdata_o <= 32'b0;
					end
				end				
				default:		begin
          //什么也不做
				end
			endcase							
		end    //if
	end      //always

endmodule

mem_wb.v

`include "define.v"
module mem_wb(

	input	wire										clk,
	input wire										rst,

  //来自控制模块的信息
	input wire[5:0]               stall,	

	//来自访存阶段的信息	
	input wire[`RegAddrBus]       mem_wd,
	input wire                    mem_wreg,
	input wire[`RegBus]					 mem_wdata,
	input wire[`RegBus]           mem_hi,
	input wire[`RegBus]           mem_lo,
	input wire                    mem_whilo,	
	
	input wire                  mem_LLbit_we,
	input wire                  mem_LLbit_value,	

	input wire                   mem_cp0_reg_we,
	input wire[4:0]              mem_cp0_reg_write_addr,
	input wire[`RegBus]          mem_cp0_reg_data,			

	//送到回写阶段的信息
	output reg[`RegAddrBus]      wb_wd,
	output reg                   wb_wreg,
	output reg[`RegBus]					 wb_wdata,
	output reg[`RegBus]          wb_hi,
	output reg[`RegBus]          wb_lo,
	output reg                   wb_whilo,

	output reg                  wb_LLbit_we,
	output reg                  wb_LLbit_value,

	output reg                   wb_cp0_reg_we,
	output reg[4:0]              wb_cp0_reg_write_addr,
	output reg[`RegBus]          wb_cp0_reg_data								       
	
);


	always @ (posedge clk) begin
		if(rst == `RstEnable) begin
			wb_wd <= `NOPRegAddr;
			wb_wreg <= `WriteDisable;
		  wb_wdata <= `ZeroWord;	
		  wb_hi <= `ZeroWord;
		  wb_lo <= `ZeroWord;
		  wb_whilo <= `WriteDisable;
		  wb_LLbit_we <= 1'b0;
		  wb_LLbit_value <= 1'b0;		
			wb_cp0_reg_we <= `WriteDisable;
			wb_cp0_reg_write_addr <= 5'b00000;
			wb_cp0_reg_data <= `ZeroWord;				  	  	
		end else if(stall[4] == `Stop && stall[5] == `NoStop) begin
			wb_wd <= `NOPRegAddr;
			wb_wreg <= `WriteDisable;
		  wb_wdata <= `ZeroWord;
		  wb_hi <= `ZeroWord;
		  wb_lo <= `ZeroWord;
		  wb_whilo <= `WriteDisable;	
		  wb_LLbit_we <= 1'b0;
		  wb_LLbit_value <= 1'b0;	
			wb_cp0_reg_we <= `WriteDisable;
			wb_cp0_reg_write_addr <= 5'b00000;
			wb_cp0_reg_data <= `ZeroWord;					  		  	  	  
		end else if(stall[4] == `NoStop) begin
			wb_wd <= mem_wd;
			wb_wreg <= mem_wreg;
			wb_wdata <= mem_wdata;
			wb_hi <= mem_hi;
			wb_lo <= mem_lo;
			wb_whilo <= mem_whilo;		
		  wb_LLbit_we <= mem_LLbit_we;
		  wb_LLbit_value <= mem_LLbit_value;		
			wb_cp0_reg_we <= mem_cp0_reg_we;
			wb_cp0_reg_write_addr <= mem_cp0_reg_write_addr;
			wb_cp0_reg_data <= mem_cp0_reg_data;			  		
		end    //if
	end      //always
			

endmodule

cp0_reg.v

`include "define.v"
module cp0_reg(

	input	wire										clk,
	input wire										rst,
	
	
	input wire                    we_i,
	input wire[4:0]               waddr_i,
	input wire[4:0]               raddr_i,
	input wire[`RegBus]           data_i,
	
//	input wire[31:0]              excepttype_i,
	input wire[5:0]               int_i,
//	input wire[`RegBus]           current_inst_addr_i,
//	input wire                    is_in_delayslot_i,
	
	output reg[`RegBus]           data_o,
	output reg[`RegBus]           count_o,
	output reg[`RegBus]           compare_o,
	output reg[`RegBus]           status_o,
	output reg[`RegBus]           cause_o,
	output reg[`RegBus]           epc_o,
	output reg[`RegBus]           config_o,
	output reg[`RegBus]           prid_o,
	
	output reg                   timer_int_o    
	
);

	always @ (posedge clk) begin
		if(rst == `RstEnable) begin
			count_o <= `ZeroWord;
			compare_o <= `ZeroWord;
			//status寄存器的CU为0001,表示协处理器CP0存在
			status_o <= 32'b00010000000000000000000000000000;
			cause_o <= `ZeroWord;
			epc_o <= `ZeroWord;
			//config寄存器的BE为1,表示Big-Endian;MT为00,表示没有MMU
			config_o <= 32'b00000000000000001000000000000000;
			//制作者是L,对应的是0x48,类型是0x1,基本类型,版本号是1.0
			prid_o <= 32'b00000000010011000000000100000010;
      timer_int_o <= `InterruputNotAssert;
		end else begin
		  count_o <= count_o + 1 ;
		  cause_o[15:10] <= int_i;
		
			if(compare_o != `ZeroWord && count_o == compare_o) begin
				timer_int_o <= `InterruputAssert;
			end
					
			if(we_i == `WriteEnable) begin
				case (waddr_i) 
					`CP0_REG_COUNT:		begin
						count_o <= data_i;
					end
					`CP0_REG_COMPARE:	begin
						compare_o <= data_i;
						//count_o <= `ZeroWord;
            timer_int_o <= `InterruputNotAssert;
					end
					`CP0_REG_STATUS:	begin
						status_o <= data_i;
					end
					`CP0_REG_EPC:	begin
						epc_o <= data_i;
					end
					`CP0_REG_CAUSE:	begin
					  //cause寄存器只有IP[1:0]、IV、WP字段是可写的
						cause_o[9:8] <= data_i[9:8];
						cause_o[23] <= data_i[23];
						cause_o[22] <= data_i[22];
					end					
				endcase  //case addr_i
			end
			
			
		end    //if
	end      //always
			
	always @ (*) begin
		if(rst == `RstEnable) begin
			data_o <= `ZeroWord;
		end else begin
				case (raddr_i) 
					`CP0_REG_COUNT:		begin
						data_o <= count_o ;
					end
					`CP0_REG_COMPARE:	begin
						data_o <= compare_o ;
					end
					`CP0_REG_STATUS:	begin
						data_o <= status_o ;
					end
					`CP0_REG_CAUSE:	begin
						data_o <= cause_o ;
					end
					`CP0_REG_EPC:	begin
						data_o <= epc_o ;
					end
					`CP0_REG_PrId:	begin
						data_o <= prid_o ;
					end
					`CP0_REG_CONFIG:	begin
						data_o <= config_o ;
					end	
					default: 	begin
					end			
				endcase  //case addr_i			
		end    //if
	end      //always

endmodule

openmips.v也要修改 就是改一下例化 增加连线和一个cp0_reg模块

inst_rom.data

3401000f
40815800
3c011000
34210401
40816000
40026000
08000006
00000000

inst_rom.S

   .org 0x0
   .set noat
   .set noreorder
   .set nomacro
   .global _start
_start:
   ori $1,$0,0xf
   mtc0 $1,$11,0x0  #写compare寄存器,开始计时
   lui $1,0x1000
   ori $1,$1,0x401
   mtc0 $1,$12,0x0  #将0x401写如status寄存器
   mfc0 $2,$12,0x0  #读status寄存器,$2=0x401

_loop:
   j _loop
   nop

仿真结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《自己动手CPU(含CD光盘1张)》使用Verilog HDL 设计实现了一款兼容MIPS32指令集架构的处理器——OpenMIPS。OpenMIPS 处理器具有两个版本,分别是教学版和实践版。教学版的主要设计思想是尽量简单,处理器的运行情况比较理想化,与教科书相似,便于使用其进行教学、学术研究和讨论,也有助于学生理解课堂上讲授的知识。实践版的设计目标是能完成特定功能,发挥实际作用。《自己动手CPU(含CD光盘1张)》分为三篇。第一篇是理论篇,介绍了指令集架构、Verilog HDL的相关知识。第二篇是基础篇,采用增量模型,实现了教学版OpenMIPS处理器。首先实现了仅能执行一条指令的处理器,从这个最简单的情况出发,通过依次添加,实现逻辑操作指令、移位操作指令、空指令、移动操作指令、算术操作指令、转移指令、加载存储指令协处理器访问指令、异常相关指令,最终实现了教学版OpenMIPS处理器。第三篇是进阶篇,通过为教学版OpenMIPS添加Wishbone总线接口,从而实现了实践版OpenMIPS处理器,并与SDRAM控制器、GPIO模块、Flash控制器、UART控制器、Wishbone总线互联矩阵等模块组成一个小型SOPC,然后下载到FPGA芯片以验证实现效果,最后为实践版OpenMIPS处理器移植了嵌入式实时操作系统μC/OS-II。 《自己动手CPU(含CD光盘1张)》适合计算机专业的学生、FPGA开发人员、处理器设计者、嵌入式系统应用开发工程师、MIPS平台开发人员以及对处理器内部的实现感兴趣的读者阅读,也可以作为高等院校计算机原理、计算机体系结构等课程的实践参考书。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值