《自己动手写CPU》11.异常相关指令实现

1.实现的六种异常介绍

MIPS32有不同的异常类型及其优先级,OpenMIPS只实现了六种异常情况的处理:

●硬件复位(复位后所有信号清零)

●中断(软件中断,硬件中断)

●syscall系统调用(在用户模式下执行内核模式下的某些操作)

●无效指令(OpenMIPS未定义的指令)

●整数溢出(算术操作指令add,addi,sub运算溢出)

●自陷指令(不是很理解他的作用)

2.解决异常方法:精确异常

①精确异常:异常发生时,处理器转移到异常处理例程,异常处理结束后返回原程序继续执行,不破坏原程序的正常执行。且异常发生时,会记住流水线未执行完的指令。

异常发生时,会产生发生异常的指令,该指令前所有的指令都正常执行到流水线的最后一个阶段,该指令之后的指令信号都被清除。

②潜在问题:异常发生顺序与指令顺序不一定相同

例如bd6a1dd035634abbaa5bc88454a4b43b.png

 加载指令lw发生地址未对齐异常(访存阶段检测到),下一条指令发生无效异常(译码阶段检测到)。这样,指令顺序是先加载再无效,而异常发生顺序却是先无效再加载。

③解决方法:发生异常时,先将异常事件标记,在访存(因为发生异常的情况在译码执行保存段都有可能发生,可能还有别的原因吧)阶段专门处理异常(异常指令之后的清除信号,异常指令之前的正常执行)。

3.要添加的异常指令

①自陷指令

不含立即数的自陷指令:

ceed1c28e645461e8df00cfbaeedb9d8.png

teq  rs,rt  ifGPR[rs]=GPR[rt] then trap

tge  rs,rt ifGPR[rs]≥GPR[rt] then trap有符号比较

tgeu  rs,rt ifGPR[rs]≥GPR[rt] then trap无符号比较

tlt  rs,rt ifGPR[rs]<GPR[rt] then trap有符号比较

tltu  rs,rt ifGPR[rs]<GPR[rt] then trap无符号比较

tne  rs,rt ifGPR[rs]≠GPR[rt] then trap

含立即数的自陷指令:3ae04a3d42854718bc072f058b926c78.png

teqi  rs,immediate ifGPR[rs]=sign_extended(immediate)then trap

tgei  rs,immediate ifGPR[rs]≥sign_extended(immediate)then trap有符号比较

tgeiu  rs,immediate ifGPR[rs]≥sign_extended(immediate)then trap无符号比较

tlti  rs,immediate ifGPR[rs]<sign_extended(immediate)then trap有符号比较

tltiu  rs,immediate ifGPR[rs]<sign_extended(immediate)then trap无符号比较

tnei  rs,immediate ifGPR[rs]≠sign_extended(immediate)then trap

②系统调用指令26f1e3749eef428183013361f43694ef.png

使用户模式下可以执行内核模式的操作,OpenMIPS不区分用户模式,内核模式,但为了兼容MIPS32指令集架构,还是实现

③异常返回指令783266e7d03743e7a912841fae2e1f9f.png

 在处理完异常后执行该指令。使epc寄存器的值成为新的取指地址,好继续执行原程序。同时设置cp0.status[1]为0,表示不再处于异常级。

4.异常处理过程

[1]译码阶段判断是否是系统调用指令、异常返回指令、无效指令,将这些信息通过excepttype_o传递到执行阶段,同时指令地址通过current_inst_addr_o传递到执行阶段。

异常类型excepttype_o={19'b0,excepttype_is_eret,ovassert,trapassert,instvaild,excepttype_is_syscall,8'b0}

异常指令地址current_inst_addr_o:异常处理完成后需不影响原来程序执行,所以需要记住异常指定地址,在异常完成后继续这个地址的指令,所以最终回到PC模块。如果是延迟槽指令,应是这条指令的前一条指令地址。

[2]执行判断是否为自陷异常,溢出异常,这些信息融合到译码阶段的excepttype传递至访存阶段,current_inst_addr也一同传递。同时判断出是否会延迟槽指令,通过is_in_delayslot传递。

[3]访存阶段会接收excepttype、cause寄存器最新值、status寄存器最新值,epc寄存器最新值,综合判断是否需要处理异常。当然is_in_delayslot和current_inst_addr也会继续传递。

[4]如果需要处理异常,既要Cp0修改寄存器信息,又要清除流水线上除回写阶段外所有寄存器的值。cp0修改过程为bdddecbc6cd042ca8d4af413e32925cc.png

 EXL为cp0.status[1]表是否处于异常级,处于异常时处理器会进入内核模式下工作,并且禁止中断。

上图中的“转移到相应的异常处理历程入口地址”,由control模块输出至PC模块完成。异常处理历程入口就是处理异常这个过程的入口,从这个地址进入就开始处理异常,这个地址是定义的,在完成这个异常处理后就返回异常,按原来指定地址进行。fd874796ea864fbdb2c9fda88225f75c.png

再次强调,如果异常指令处延迟槽中,那么异常处理后重新执行的指令地址为延迟槽指令的前一个地址。

除回写阶段的流水线信号清除工作由Control模块发出flush信号控制完成。

5.数据流图7faff2ff329a4cfebb29154a346f4efd.png

6.代码

defines

//全局
`define RstEnable 1'b1
`define RstDisable 1'b0
`define ZeroWord 32'h00000000
`define WriteEnable 1'b1
`define WriteDisable 1'b0
`define ReadEnable 1'b1
`define ReadDisable 1'b0
`define AluOpBus 7:0
`define AluSelBus 2:0
`define InstValid 1'b0
`define InstInvalid 1'b1
`define Stop 1'b1
`define NoStop 1'b0
`define InDelaySlot 1'b1
`define NotInDelaySlot 1'b0
`define Branch 1'b1
`define NotBranch 1'b0
`define InterruptAssert 1'b1
`define InterruptNotAssert 1'b0
`define TrapAssert 1'b1
`define TrapNotAssert 1'b0
`define True_v 1'b1
`define False_v 1'b0
`define ChipEnable 1'b1
`define ChipDisable 1'b0


//指令
`define EXE_AND  6'b100100
`define EXE_OR   6'b100101
`define EXE_XOR 6'b100110
`define EXE_NOR 6'b100111
`define EXE_ANDI 6'b001100
`define EXE_ORI  6'b001101
`define EXE_XORI 6'b001110
`define EXE_LUI 6'b001111

`define EXE_SLL  6'b000000
`define EXE_SLLV  6'b000100
`define EXE_SRL  6'b000010
`define EXE_SRLV  6'b000110
`define EXE_SRA  6'b000011
`define EXE_SRAV  6'b000111
`define EXE_SYNC  6'b001111
`define EXE_PREF  6'b110011

`define EXE_MOVZ  6'b001010
`define EXE_MOVN  6'b001011
`define EXE_MFHI  6'b010000
`define EXE_MTHI  6'b010001
`define EXE_MFLO  6'b010010
`define EXE_MTLO  6'b010011

`define EXE_SLT  6'b101010
`define EXE_SLTU  6'b101011
`define EXE_SLTI  6'b001010
`define EXE_SLTIU  6'b001011   
`define EXE_ADD  6'b100000
`define EXE_ADDU  6'b100001
`define EXE_SUB  6'b100010
`define EXE_SUBU  6'b100011
`define EXE_ADDI  6'b001000
`define EXE_ADDIU  6'b001001
`define EXE_CLZ  6'b100000
`define EXE_CLO  6'b100001

`define EXE_MULT  6'b011000
`define EXE_MULTU  6'b011001
`define EXE_MUL  6'b000010
`define EXE_MADD  6'b000000
`define EXE_MADDU  6'b000001
`define EXE_MSUB  6'b000100
`define EXE_MSUBU  6'b000101

`define EXE_DIV  6'b011010
`define EXE_DIVU  6'b011011

`define EXE_J  6'b000010
`define EXE_JAL  6'b000011
`define EXE_JALR  6'b001001
`define EXE_JR  6'b001000
`define EXE_BEQ  6'b000100
`define EXE_BGEZ  5'b00001
`define EXE_BGEZAL  5'b10001
`define EXE_BGTZ  6'b000111
`define EXE_BLEZ  6'b000110
`define EXE_BLTZ  5'b00000
`define EXE_BLTZAL  5'b10000
`define EXE_BNE  6'b000101

`define EXE_LB  6'b100000
`define EXE_LBU  6'b100100
`define EXE_LH  6'b100001
`define EXE_LHU  6'b100101
`define EXE_LL  6'b110000
`define EXE_LW  6'b100011
`define EXE_LWL  6'b100010
`define EXE_LWR  6'b100110
`define EXE_SB  6'b101000
`define EXE_SC  6'b111000
`define EXE_SH  6'b101001
`define EXE_SW  6'b101011
`define EXE_SWL  6'b101010
`define EXE_SWR  6'b101110

`define EXE_SYSCALL 6'b001100
   
`define EXE_TEQ 6'b110100
`define EXE_TEQI 5'b01100
`define EXE_TGE 6'b110000
`define EXE_TGEI 5'b01000
`define EXE_TGEIU 5'b01001
`define EXE_TGEU 6'b110001
`define EXE_TLT 6'b110010
`define EXE_TLTI 5'b01010
`define EXE_TLTIU 5'b01011
`define EXE_TLTU 6'b110011
`define EXE_TNE 6'b110110
`define EXE_TNEI 5'b01110
   
`define EXE_ERET 32'b01000010000000000000000000011000

`define EXE_NOP 6'b000000
`define SSNOP 32'b00000000000000000000000001000000

`define EXE_SPECIAL_INST 6'b000000
`define EXE_REGIMM_INST 6'b000001
`define EXE_SPECIAL2_INST 6'b011100

//AluOp
`define EXE_AND_OP   8'b00100100
`define EXE_OR_OP    8'b00100101
`define EXE_XOR_OP  8'b00100110
`define EXE_NOR_OP  8'b00100111
`define EXE_ANDI_OP  8'b01011001
`define EXE_ORI_OP  8'b01011010
`define EXE_XORI_OP  8'b01011011
`define EXE_LUI_OP  8'b01011100   

`define EXE_SLL_OP  8'b01111100
`define EXE_SLLV_OP  8'b00000100
`define EXE_SRL_OP  8'b00000010
`define EXE_SRLV_OP  8'b00000110
`define EXE_SRA_OP  8'b00000011
`define EXE_SRAV_OP  8'b00000111

`define EXE_MOVZ_OP  8'b00001010
`define EXE_MOVN_OP  8'b00001011
`define EXE_MFHI_OP  8'b00010000
`define EXE_MTHI_OP  8'b00010001
`define EXE_MFLO_OP  8'b00010010
`define EXE_MTLO_OP  8'b00010011

`define EXE_SLT_OP  8'b00101010
`define EXE_SLTU_OP  8'b00101011
`define EXE_SLTI_OP  8'b01010111
`define EXE_SLTIU_OP  8'b01011000   
`define EXE_ADD_OP  8'b00100000
`define EXE_ADDU_OP  8'b00100001
`define EXE_SUB_OP  8'b00100010
`define EXE_SUBU_OP  8'b00100011
`define EXE_ADDI_OP  8'b01010101
`define EXE_ADDIU_OP  8'b01010110
`define EXE_CLZ_OP  8'b10110000
`define EXE_CLO_OP  8'b10110001

`define EXE_MULT_OP  8'b00011000
`define EXE_MULTU_OP  8'b00011001
`define EXE_MUL_OP  8'b10101001
`define EXE_MADD_OP  8'b10100110
`define EXE_MADDU_OP  8'b10101000
`define EXE_MSUB_OP  8'b10101010
`define EXE_MSUBU_OP  8'b10101011

`define EXE_DIV_OP  8'b00011010
`define EXE_DIVU_OP  8'b00011011

`define EXE_J_OP  8'b01001111
`define EXE_JAL_OP  8'b01010000
`define EXE_JALR_OP  8'b00001001
`define EXE_JR_OP  8'b00001000
`define EXE_BEQ_OP  8'b01010001
`define EXE_BGEZ_OP  8'b01000001
`define EXE_BGEZAL_OP  8'b01001011
`define EXE_BGTZ_OP  8'b01010100
`define EXE_BLEZ_OP  8'b01010011
`define EXE_BLTZ_OP  8'b01000000
`define EXE_BLTZAL_OP  8'b01001010
`define EXE_BNE_OP  8'b01010010

`define EXE_LB_OP  8'b11100000
`define EXE_LBU_OP  8'b11100100
`define EXE_LH_OP  8'b11100001
`define EXE_LHU_OP  8'b11100101
`define EXE_LL_OP  8'b11110000
`define EXE_LW_OP  8'b11100011
`define EXE_LWL_OP  8'b11100010
`define EXE_LWR_OP  8'b11100110
`define EXE_PREF_OP  8'b11110011
`define EXE_SB_OP  8'b11101000
`define EXE_SC_OP  8'b11111000
`define EXE_SH_OP  8'b11101001
`define EXE_SW_OP  8'b11101011
`define EXE_SWL_OP  8'b11101010
`define EXE_SWR_OP  8'b11101110
`define EXE_SYNC_OP  8'b00001111

`define EXE_MFC0_OP 8'b01011101
`define EXE_MTC0_OP 8'b01100000

`define EXE_SYSCALL_OP 8'b00001100

`define EXE_TEQ_OP 8'b00110100
`define EXE_TEQI_OP 8'b01001000
`define EXE_TGE_OP 8'b00110000
`define EXE_TGEI_OP 8'b01000100
`define EXE_TGEIU_OP 8'b01000101
`define EXE_TGEU_OP 8'b00110001
`define EXE_TLT_OP 8'b00110010
`define EXE_TLTI_OP 8'b01000110
`define EXE_TLTIU_OP 8'b01000111
`define EXE_TLTU_OP 8'b00110011
`define EXE_TNE_OP 8'b00110110
`define EXE_TNEI_OP 8'b01001001
   
`define EXE_ERET_OP 8'b01101011

`define EXE_NOP_OP    8'b00000000

//AluSel
`define EXE_RES_LOGIC 3'b001
`define EXE_RES_SHIFT 3'b010
`define EXE_RES_MOVE 3'b011	
`define EXE_RES_ARITHMETIC 3'b100	
`define EXE_RES_MUL 3'b101
`define EXE_RES_JUMP_BRANCH 3'b110
`define EXE_RES_LOAD_STORE 3'b111	

`define EXE_RES_NOP 3'b000


//指令存储器inst_rom
`define InstAddrBus 31:0
`define InstBus 31:0
`define InstMemNum 131071
`define InstMemNumLog2 17

//数据存储器data_ram
`define DataAddrBus 31:0
`define DataBus 31:0
`define DataMemNum 131071
`define DataMemNumLog2 17
`define ByteWidth 7:0

//通用寄存器regfile
`define RegAddrBus 4:0
`define RegBus 31:0
`define RegWidth 32
`define DoubleRegWidth 64
`define DoubleRegBus 63:0
`define RegNum 32
`define RegNumLog2 5
`define NOPRegAddr 5'b00000

//除法div
`define DivFree 2'b00
`define DivByZero 2'b01
`define DivOn 2'b10
`define DivEnd 2'b11
`define DivResultReady 1'b1
`define DivResultNotReady 1'b0
`define DivStart 1'b1
`define DivStop 1'b0

//CP0寄存器地址
`define CP0_REG_COUNT    5'b01001        //可读写
`define CP0_REG_COMPARE    5'b01011      //可读写
`define CP0_REG_STATUS    5'b01100       //可读写
`define CP0_REG_CAUSE    5'b01101        //只读
`define CP0_REG_EPC    5'b01110          //可读写
`define CP0_REG_PrId    5'b01111         //只读
`define CP0_REG_CONFIG    5'b10000       //只读

pc模块

`include "defines.v"
`timescale 1ns/1ps
module pc_reg(

	input	wire			clk,
	input wire				rst,
	//来自控制模块的信息
	input wire[5:0]               stall,    //流水线暂停控制
	input wire					  flush,	//清除信号
	input wire[`RegBus]			  new_pc,	//异常处理例程入口地址
	//来自译码阶段的信息
	input wire                    branch_flag_i,    //是否转移
	input wire[`RegBus]           branch_target_address_i,  //转移目标地址
	
	output reg[`InstAddrBus]	  pc,
	output reg                    ce
	
);

	always @ (posedge clk) begin
		if (ce == `ChipDisable) begin        //复位清零
			pc <= 32'h00000000;
		end else if(flush == 1'b1) begin		//else与if间添加begin,最后加end
				    pc <= new_pc;	//异常时进入异常处理例程
				end else if(stall[0] == `NoStop) begin    //流水线不暂停
							if(branch_flag_i == `Branch) begin    
								pc <= branch_target_address_i;    //转移条件满足给出转移地址
							end else begin
								 pc <= pc + 4'h4;        //转移条件不满足正常按顺序读下一条指令地址
								end
						end
	end
	
	always @ (posedge clk) begin
		if (rst == `RstEnable) begin
			ce <= `ChipDisable;        //模块禁用
		end else begin
			ce <= `ChipEnable;        //模块可用
		end
	end

endmodule
//PC:复位清零;
//	   是否清除信号
//    	流水线不暂停|判断是转移指令,读转移指令地址。否,读下一条指令
//                  |正常读下一条指令

if/id模块

`include "defines.v"
`timescale 1ns/1ps
module if_id(

	input	wire				clk,
	input   wire				rst,

	//来自控制模块的信息
	input wire[5:0]               stall,	//流水线暂停
	input wire					  flush,	//清除信号
	
	input wire[`InstAddrBus]	  if_pc,
	input wire[`InstBus]          if_inst,
	output reg[`InstAddrBus]      id_pc,
	output reg[`InstBus]          id_inst  
	
);

	always @ (posedge clk) begin
		if (rst == `RstEnable) begin
			id_pc <= `ZeroWord;
			id_inst <= `ZeroWord;
		end else if(flush == 1'b1) begin	//与上一起写或
					id_pc <= `ZeroWord;
					id_inst <= `ZeroWord;
				 end else if(stall[1] == `Stop && stall[2] == `NoStop) begin
							id_pc <= `ZeroWord;
							id_inst <= `ZeroWord;	
							end else if(stall[1] == `NoStop) begin
										id_pc <= if_pc;
										id_inst <= if_inst;
									end
	end

endmodule

id模块

`include "defines.v"
`timescale 1ns/1ps
module id(

	input wire						rst,
	input wire[`InstAddrBus]		pc_i,
	input wire[`InstBus]          inst_i,
	//来自regfile模块的读取数据
	input wire[`RegBus]           reg1_data_i,
	input wire[`RegBus]           reg2_data_i,
	
	//处于执行阶段的指令要写入的目的寄存器信息
	input wire					ex_wreg_i,        //数据前推,解决数据相关
	input wire[`RegBus]			ex_wdata_i,
	input wire[`RegAddrBus]     ex_wd_i,	
	//处于访存阶段的指令要写入的目的寄存器信息
	input wire					mem_wreg_i,
	input wire[`RegBus]			mem_wdata_i,
	input wire[`RegAddrBus]       mem_wd_i,
	//来自EX阶段的前一指令的子运算类型
	input wire[`AluOpBus]		ex_aluop_i,		//判断load相关

	//如果上一条指令是转移指令,那么下一条指令在译码的时候is_in_delayslot为true
	input wire                    is_in_delayslot_i,    //来于ID/EX

	//送到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,  //操作数1(rs)地址
	output reg[`RegBus]           reg2_o,
	output reg[`RegAddrBus]       wd_o,  //要写入的地址
	output reg                    wreg_o,
	
	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                   stallreq,	        //流水线暂停请求	
	
	output wire[`RegBus]		 inst_o,	//指令地址传入EX,EX执行段读offset值计算加载存储地址
	
	output wire[31:0]			  excepttype_o,  //异常信息(是否返回异常eret,是否无效指令,是否系统调用,是否中断)
	output wire[`RegBus]		  current_inst_address_o  //当前指令地址 EPC存储异常地址
);

	  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];//rt
	  reg[`RegBus]		imm;
	  reg 				instvalid;
	  
	  reg 				stallreq_for_reg1_loadrelate;	//读取的第一个寄存器与上条指令load相关
	  reg 				stallreq_for_reg2_loadrelate;	//读取的第二个寄存器与上条指令load相关
	  wire 				pre_inst_is_load;	//前一指令是否为加载指令
	  //跳转指令
	  wire[`RegBus] 	pc_plus_8;    //指令后面第二条指令地址
	  wire[`RegBus] 	pc_plus_4;    //指令后面第一条指令地址
	  wire[`RegBus] 	imm_sll2_signedext;
	  
	  reg excepttype_is_syscall;
	  reg excepttype_is_eret;
	  
	  assign pc_plus_8 = pc_i + 8;
	  assign pc_plus_4 = pc_i +4;
	  assign imm_sll2_signedext = {{14{inst_i[15]}}, inst_i[15:0], 2'b00 };  //offset左移2位并做符号扩展
	  
	  //加载存储指令
	  assign inst_o = inst_i; //指令传递,读offset值算存储加载地址
	  assign stallreq = stallreq_for_reg1_loadrelate | stallreq_for_reg2_loadrelate;	//load相关,流水线暂停请求
	  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_OP)||
								(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;	//前一指令为加载指令
	  //异常信息设定
	  assign excepttype_o = {19'b0,excepttype_is_eret,2'b0,instvalid,excepttype_is_syscall,8'b0};//异常信息(是否返回异常eret,是否无效指令,是否系统调用,是否中断)
	  assign current_inst_address_o = pc_i;
	always @ (*) begin	
		if (rst == `RstEnable) begin
			aluop_o <= `EXE_NOP_OP;        //复位清零
			alusel_o <= `EXE_RES_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;	
			excepttype_is_syscall <= `False_v;
			excepttype_is_eret <= `False_v;				
	  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; 
			excepttype_is_syscall <= `False_v;
			excepttype_is_eret <= `False_v;				
		  case (op)
		    `EXE_SPECIAL_INST:		begin
		    	case (op2)
		    		5'b00000:			begin
		    			case (op3)
		    				`EXE_OR:	begin            //或 rd<-rs OR rt 
		    					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            //与 rd<-rs AND rt
		    					wreg_o <= `WriteEnable;		
                                aluop_o <= `EXE_AND_OP;
		  						alusel_o <= `EXE_RES_LOGIC;	  
                                reg1_read_o <= 1'b1;	
                                reg2_read_o <= 1'b1;	
		  						instvalid <= `InstValid;	
								end  	
		    				`EXE_XOR:	begin            //异或 rd<-rs XOR rt
		    					wreg_o <= `WriteEnable;		
                                aluop_o <= `EXE_XOR_OP;
		  						alusel_o <= `EXE_RES_LOGIC;		
                                reg1_read_o <= 1'b1;	
                                reg2_read_o <= 1'b1;	
		  						instvalid <= `InstValid;	
								end  				
		    				`EXE_NOR:	begin            //或非 rd<-rs NOR rt
		    					wreg_o <= `WriteEnable;		
                                aluop_o <= `EXE_NOR_OP;
		  						alusel_o <= `EXE_RES_LOGIC;		
                                reg1_read_o <= 1'b1;	
                                reg2_read_o <= 1'b1;	
		  						instvalid <= `InstValid;	
								end 
							`EXE_SLLV: begin        //逻辑左移 rd<-rt<<rs[4:0](logic)
								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        //逻辑右移 rd<-rt>>rs[4:0](logic)
								wreg_o <= `WriteEnable;		
                                aluop_o <= `EXE_SRL_OP;
		  						alusel_o <= `EXE_RES_SHIFT;		
                                reg1_read_o <= 1'b1;	
                                reg2_read_o <= 1'b1;
		  						instvalid <= `InstValid;	
								end 					
							`EXE_SRAV: begin       //算术右移 rd<-rt>>rs[4:0](arithmetic)
								wreg_o <= `WriteEnable;		
                                aluop_o <= `EXE_SRA_OP;
		  						alusel_o <= `EXE_RES_SHIFT;		
                                reg1_read_o <= 1'b1;	
                                reg2_read_o <= 1'b1;
		  						instvalid <= `InstValid;			
		  					    end
							`EXE_MFHI: begin        //移动 rd<-hi
								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        //移动 rd<-lo
								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 <= `WriteDisable;   //写HI寄存器,非通用寄存器.写无效	
                                aluop_o <= `EXE_MTHI_OP;
		  						reg1_read_o <= 1'b1;	
                                reg2_read_o <= 1'b0; 
                                instvalid <= `InstValid;	
								end
							`EXE_MTLO: begin        //移动 lo<-rs
								wreg_o <= `WriteDisable;	
                            	aluop_o <= `EXE_MTLO_OP;
		  						reg1_read_o <= 1'b1;
                               	reg2_read_o <= 1'b0; 
                                instvalid <= `InstValid;	
								end
							`EXE_MOVN: begin        //移动 if rt≠0 then rd<-rs
								aluop_o <= `EXE_MOVN_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_MOVZ: begin        //移动 if rt=0 then rd<-rs
								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        //算术 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        //算术 rd<-(rs<rt) 无符号比较
								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        //算术 rd<-rs+rt 溢出保存
								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        //算术 rd<-rs-rt 溢出不保存
								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        //算术 rd<-rs-rt 溢出保存
								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        //算术 {hi,lo}<-rs×rd 有符号乘
								wreg_o <= `WriteDisable;
                        		aluop_o <= `EXE_MULT_OP;
		  						reg1_read_o <= 1'b1;
                            	reg2_read_o <= 1'b1;
                                instvalid <= `InstValid;	
								end
							`EXE_MULTU: begin        //算术 {hi,lo}<-rs×rd 无符号乘
								wreg_o <= `WriteDisable;
                        		aluop_o <= `EXE_MULTU_OP;
		  						reg1_read_o <= 1'b1;
                            	reg2_read_o <= 1'b1; 
                                instvalid <= `InstValid;	
								end
							`EXE_DIV: begin        //算术 {HI,LO}<-rs/rt 有符号除
								wreg_o <= `WriteDisable;	
                            	aluop_o <= `EXE_DIV_OP;
		  						reg1_read_o <= 1'b1;	
                                reg2_read_o <= 1'b1; 
                                instvalid <= `InstValid;	
								end
							`EXE_DIVU: begin        //算术 {HI,LO}<-rs/rt 无符号除
								wreg_o <= `WriteDisable;	
                            	aluop_o <= `EXE_DIVU_OP;
		  						reg1_read_o <= 1'b1;	
                                reg2_read_o <= 1'b1; 
                                instvalid <= `InstValid;	
								end			
							`EXE_JR: begin        //转移 pc<-rs
								wreg_o <= `WriteDisable;	
                            	aluop_o <= `EXE_JR_OP;
		  						alusel_o <= `EXE_RES_JUMP_BRANCH;  
                                reg1_read_o <= 1'b1;	
                                reg2_read_o <= 1'b0;
		  						link_addr_o <= `ZeroWord;     //不返回地址	  						
			                	branch_target_address_o <= reg1_o; //rs的值为要转移的地址
			                	branch_flag_o <= `Branch;		           
			                    next_inst_in_delayslot_o <= `InDelaySlot; //下一指令为延迟槽指令
			                    instvalid <= `InstValid;	
								end
							`EXE_JALR: begin        //转移 rd<-return_address,pc<-rs
								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
						end
					endcase	
				case (op3)
					`EXE_TEQ: begin		//不含立即数的自陷指令,if GPR[rs]=GPR[rt]then trap
						wreg_o <= `WriteDisable;//不写通用寄存器
						aluop_o <= `EXE_TEQ_OP;
		  				alusel_o <= `EXE_RES_NOP;
						reg1_read_o <= 1'b1;
						reg2_read_o <= 1'b1;
		  				instvalid <= `InstValid;
		  			end
		  			`EXE_TGE: begin		//不含立即数的自陷指令,if GPR[rs]≥GPR[rt]then trap,有符号比较
						wreg_o <= `WriteDisable;
						aluop_o <= `EXE_TGE_OP;
	  					alusel_o <= `EXE_RES_NOP;
						reg1_read_o <= 1'b1;
						reg2_read_o <= 1'b1;
		  				instvalid <= `InstValid;
		  			end		
		  			`EXE_TGEU: begin	//不含立即数的自陷指令,if GPR[rs]≥GPR[rt]then trap,无符号比较
						wreg_o <= `WriteDisable;
						aluop_o <= `EXE_TGEU_OP;
  						alusel_o <= `EXE_RES_NOP; 
						reg1_read_o <= 1'b1;	
						reg2_read_o <= 1'b1;
						instvalid <= `InstValid;
		  			end	
		  			`EXE_TLT: begin		//不含立即数的自陷指令,if GPR[rs]<GPR[rt]then trap,有符号比较
						wreg_o <= `WriteDisable;
						aluop_o <= `EXE_TLT_OP;
		  				alusel_o <= `EXE_RES_NOP;
						reg1_read_o <= 1'b1;
						reg2_read_o <= 1'b1;
		  				instvalid <= `InstValid;
		  			end
		  			`EXE_TLTU: begin	//不含立即数的自陷指令,if GPR[rs]<GPR[rt]then trap,无符号比较
						wreg_o <= `WriteDisable;	
						aluop_o <= `EXE_TLTU_OP;
		  				alusel_o <= `EXE_RES_NOP;
						reg1_read_o <= 1'b1;	
						reg2_read_o <= 1'b1;
		  				instvalid <= `InstValid;
		  			end	
		  			`EXE_TNE: begin		//不含立即数的自陷指令,if GPR[rs]≠GPR[rt]then trap
						wreg_o <= `WriteDisable;
						aluop_o <= `EXE_TNE_OP;
						alusel_o <= `EXE_RES_NOP;
						reg1_read_o <= 1'b1;	
						reg2_read_o <= 1'b1;
		  				instvalid <= `InstValid;
		  			end
		  			`EXE_SYSCALL: begin		//系统自陷
						wreg_o <= `WriteDisable;	
						aluop_o <= `EXE_SYSCALL_OP;
  						alusel_o <= `EXE_RES_NOP;  
						reg1_read_o <= 1'b0;	
						reg2_read_o <= 1'b0;
						instvalid <= `InstValid; 
						excepttype_is_syscall<= `True_v;
					end							 																					
					default:	begin
						end	
				endcase									
			end		//end special_inst						 
		 						  
		  	`EXE_ORI:			begin  //ORI指令 逻辑或 rt<-rs OR zero_extended(immediate)
		  		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]};
           		wd_o <= inst_i[20:16];
				instvalid <= `InstValid;	
		      	end
		  	`EXE_ANDI:			begin        //逻辑与 rt<-rs AND zero_extended(immediate)
		  		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]}; //源操作数2与默认rt无关.源操作数2经计算赋给立即数
            	wd_o <= inst_i[20:16];	  //写的是rt非默认	  	
				instvalid <= `InstValid;	
				end	 	
		  	`EXE_XORI:			begin       //逻辑异或 rt<-rs XOR zero_extended(immediate)
		  		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        //逻辑 rt<-immediate || 0^16
		  		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_SLTI:			begin        //算术 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        //算术 rt<-(rs<(sign_extended)immediate) 无符号比较
		  		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        //算术 rt<-rs+((sign_extended)immediate) 溢出不保存
		  		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        //算术 rt<-rs+((sign_extended)immediate) 溢出保存
		  		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_J:			begin        //转移 pc<-(pc+4)[31,28]||target||'00'
		  		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_target_address_o <= {pc_plus_4[31:28], inst_i[25:0], 2'b00};
			    branch_flag_o <= `Branch;
			    next_inst_in_delayslot_o <= `InDelaySlot;		  	
			    instvalid <= `InstValid;	
				end
			`EXE_JAL:		begin        //转移 pc<-(pc+4)[31,28]||target||'00',后面第二条指令地址作返回地址存入$31
		  		wreg_o <= `WriteEnable;	//返回地址存入通用寄存器31,写使能
            	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;	//存入$31寄存器,地址为5’b11111。非默认地址,此处修改写地址
		  		link_addr_o <= pc_plus_8 ;
			    branch_target_address_o <= {pc_plus_4[31:28], inst_i[25:0], 2'b00};
			    branch_flag_o <= `Branch;
			    next_inst_in_delayslot_o <= `InDelaySlot;		  	
			    instvalid <= `InstValid;	
				end
			`EXE_BEQ:			begin    //转移 if rs=rt then branch
		  		wreg_o <= `WriteDisable;		
                aluop_o <= `EXE_BEQ_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_BGTZ:			begin    //转移 if rs>0 then branch
		  		wreg_o <= `WriteDisable;		
                aluop_o <= `EXE_BGTZ_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) && (reg1_o != `ZeroWord)) begin  //注意不能为0
			    	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    //转移 if rs≤0 then branch
		  		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    //转移 if rs≠rt then branch
		  		wreg_o <= `WriteDisable;		
                aluop_o <= `EXE_BLEZ_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_BGEZ:	begin    //转移 if rs≥0 then branch 
							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
			    		    	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    //转移 if rs≥0 then branch 后面第二条指令地址作返回地址保存到$31寄存器
							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
					    `EXE_BLTZ:		begin    //转移 if rs<0 then branch
						    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_BLTZAL:		begin    //转移 if rs<0 then branch 后面第二条指令地址作返回地址保存到$31寄存器
							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
			    			    branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
			    		    	branch_flag_o <= `Branch;
			    			    next_inst_in_delayslot_o <= `InDelaySlot;
			   		        	end
						    end
						`EXE_TEQI:			begin	//含立即数的自陷指令,if GPR[rs]=sign_extended(immediate)then trap
							wreg_o <= `WriteDisable;	
							aluop_o <= `EXE_TEQI_OP;
							alusel_o <= `EXE_RES_NOP; 
							reg1_read_o <= 1'b1;	
							reg2_read_o <= 1'b0;	  	
							imm <= {{16{inst_i[15]}}, inst_i[15:0]};		  	
							instvalid <= `InstValid;	
						end
						`EXE_TGEI:			begin	//含立即数的自陷指令,if GPR[rs]≥sign_extended(immediate)then trap,有符号比较
							wreg_o <= `WriteDisable;
							aluop_o <= `EXE_TGEI_OP;
							alusel_o <= `EXE_RES_NOP; 
							reg1_read_o <= 1'b1;	
							reg2_read_o <= 1'b0;	  	
							imm <= {{16{inst_i[15]}}, inst_i[15:0]};		  	
							instvalid <= `InstValid;	
						end
						`EXE_TGEIU:			begin	//含立即数的自陷指令,if GPR[rs]≥sign_extended(immediate)then trap,无符号比较
							wreg_o <= `WriteDisable;
							aluop_o <= `EXE_TGEIU_OP;
							alusel_o <= `EXE_RES_NOP; 
							reg1_read_o <= 1'b1;	
							reg2_read_o <= 1'b0;	  	
							imm <= {{16{inst_i[15]}}, inst_i[15:0]};		  	
							instvalid <= `InstValid;	
						end
						`EXE_TLTI:			begin	//含立即数的自陷指令,if GPR[rs]<sign_extended(immediate)then trap,有符号比较
							wreg_o <= `WriteDisable;
							aluop_o <= `EXE_TLTI_OP;
							alusel_o <= `EXE_RES_NOP; 
							reg1_read_o <= 1'b1;	
							reg2_read_o <= 1'b0;	  	
							imm <= {{16{inst_i[15]}}, inst_i[15:0]};		  	
							instvalid <= `InstValid;	
						end
						`EXE_TLTIU:			begin	//含立即数的自陷指令,if GPR[rs]<sign_extended(immediate)then trap,无符号比较
							wreg_o <= `WriteDisable;
							aluop_o <= `EXE_TLTIU_OP;
							alusel_o <= `EXE_RES_NOP;
							reg1_read_o <= 1'b1;	
							reg2_read_o <= 1'b0;	  	
							imm <= {{16{inst_i[15]}}, inst_i[15:0]};		  	
							instvalid <= `InstValid;	
						end
						`EXE_TNEI:			begin	//含立即数的自陷指令,if GPR[rs]≠sign_extended(immediate)then trap
							wreg_o <= `WriteDisable;
							aluop_o <= `EXE_TNEI_OP;
							alusel_o <= `EXE_RES_NOP; 
							reg1_read_o <= 1'b1;	
							reg2_read_o <= 1'b0;	  	
							imm <= {{16{inst_i[15]}}, inst_i[15:0]};		  	
							instvalid <= `InstValid;	
						end						
						default:	begin
						end
					endcase
				end								
				`EXE_SPECIAL2_INST:		begin
					case ( op3 )
						`EXE_CLZ:		begin    //算术 rd<-coun_leading_zeros rs
							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    //算术 rd<-coun_leading_ones rs
							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    //算术 rd<-rs×rt 有符号乘
							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    //算术 {HI,LO}<-{HI,LO}+rs×rt 有符号乘累加
							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    //算术 {HI,LO}<-{HI,LO}+rs×rt 无符号乘累加
							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   //算术 {HI,LO}<-{HI,LO}-rs×rt 有符号乘累减
							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    //算术 {HI,LO}<-{HI,LO}-rs×rt 无符号乘累减
							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																		  	
		    `EXE_LB:	begin //加载
				wreg_o <= `WriteEnable; //加载结果写入rt通用寄存器
				aluop_o <= `EXE_LB_OP;
				alusel_o <= `EXE_RES_LOAD_STORE;
				reg1_read_o <= 1'b1; //base值
				reg2_read_o <= 1'b0;	//符号扩展32位写入rt
				wd_o <= inst_i[20:16]; //写入rt寄存器
				instvalid <= `InstValid;
				end
			`EXE_LBU:	begin
				wreg_o <= `WriteEnable; //加载结果写入rt通用寄存器
				aluop_o <= `EXE_LBU_OP;
				alusel_o <= `EXE_RES_LOAD_STORE;
				reg1_read_o <= 1'b1; //base值
				reg2_read_o <= 1'b0;
				wd_o <= inst_i[20:16]; //写入rt寄存器
				instvalid <= `InstValid;
				end
			`EXE_LH: 	begin
				wreg_o <= `WriteEnable; //加载结果写入rt通用寄存器
				aluop_o <= `EXE_LH_OP;
				alusel_o <= `EXE_RES_LOAD_STORE;
				reg1_read_o <= 1'b1; //base值
				reg2_read_o <= 1'b0;
				wd_o <= inst_i[20:16]; //写入rt寄存器
				instvalid <= `InstValid;
				end
			`EXE_LHU: 	begin
				wreg_o <= `WriteEnable; //加载结果写入rt通用寄存器
				aluop_o <= `EXE_LHU_OP;
				alusel_o <= `EXE_RES_LOAD_STORE;
				reg1_read_o <= 1'b1; //base值
				reg2_read_o <= 1'b0;
				wd_o <= inst_i[20:16]; //写入rt寄存器
				instvalid <= `InstValid;
				end
			`EXE_LW:	begin
				wreg_o <= `WriteEnable; //加载结果写入rt通用寄存器
				aluop_o <= `EXE_LW_OP;
				alusel_o <= `EXE_RES_LOAD_STORE;
				reg1_read_o <= 1'b1; //base值
				reg2_read_o <= 1'b0;
				wd_o <= inst_i[20:16]; //写入rt寄存器
				instvalid <= `InstValid;
				end
			`EXE_LWL:	begin
				wreg_o <= `WriteEnable; //加载结果写入rt通用寄存器
				aluop_o <= `EXE_LWL_OP;
				alusel_o <= `EXE_RES_LOAD_STORE;
				reg1_read_o <= 1'b1; //base值
				reg2_read_o <= 1'b1;	//rt部分值被修改,需要读rt值
				wd_o <= inst_i[20:16]; //写入rt寄存器
				instvalid <= `InstValid;
				end
			`EXE_LWR:	begin
				wreg_o <= `WriteEnable; //加载结果写入rt通用寄存器
				aluop_o <= `EXE_LWR_OP;
				alusel_o <= `EXE_RES_LOAD_STORE;
				reg1_read_o <= 1'b1; //base值
				reg2_read_o <= 1'b1;	//rt部分值被修改,需要读rt值
				wd_o <= inst_i[20:16]; //写入rt寄存器
				instvalid <= `InstValid;
				end
			`EXE_SB:	begin
				wreg_o <= `WriteDisable; //存储,不写通用寄存器
				aluop_o <= `EXE_SB_OP;
				alusel_o <= `EXE_RES_LOAD_STORE;
				reg1_read_o <= 1'b1; //base值
				reg2_read_o <= 1'b1;	//存储rt部分值
				instvalid <= `InstValid;
				end
			`EXE_SH:	begin
				wreg_o <= `WriteDisable; //存储,不写通用寄存器
				aluop_o <= `EXE_SH_OP;
				alusel_o <= `EXE_RES_LOAD_STORE;
				reg1_read_o <= 1'b1; //base值
				reg2_read_o <= 1'b1;	//存储rt部分值
				instvalid <= `InstValid;
				end
			`EXE_SW:	begin
				wreg_o <= `WriteDisable; //存储,不写通用寄存器
				aluop_o <= `EXE_SW_OP;
				alusel_o <= `EXE_RES_LOAD_STORE;
				reg1_read_o <= 1'b1; //base值
				reg2_read_o <= 1'b1;	//存储rt值
				instvalid <= `InstValid;
				end
			`EXE_SWL:	begin
				wreg_o <= `WriteDisable; //存储,不写通用寄存器
				aluop_o <= `EXE_SWL_OP;
				alusel_o <= `EXE_RES_LOAD_STORE;
				reg1_read_o <= 1'b1; //base值
				reg2_read_o <= 1'b1;	//存储rt部分值
				instvalid <= `InstValid;
				end
			`EXE_SWR:	begin
				wreg_o <= `WriteDisable; //存储,不写通用寄存器
				aluop_o <= `EXE_SWR_OP;
				alusel_o <= `EXE_RES_LOAD_STORE;
				reg1_read_o <= 1'b1; //base值
				reg2_read_o <= 1'b1;	//存储rt部分值
				instvalid <= `InstValid;
				end
			`EXE_LL:	begin
				wreg_o <= `WriteEnable;//写rt
				aluop_o <= `EXE_LL_OP;
		  		alusel_o <= `EXE_RES_LOAD_STORE; 
				reg1_read_o <= 1'b1;	//base值
				reg2_read_o <= 1'b0;	//rt值全改写,无需读	  	
				wd_o <= inst_i[20:16]; 	//写地址为rt通用寄存器
				instvalid <= `InstValid;	
			end
			`EXE_SC:	begin
		  		wreg_o <= `WriteEnable;//写rt
				aluop_o <= `EXE_SC_OP;
		  		alusel_o <= `EXE_RES_LOAD_STORE; 
				reg1_read_o <= 1'b1;	//base值
				reg2_read_o <= 1'b1;	//改写rt值。存储成功rt置1,失败置0	  	
				wd_o <= inst_i[20:16]; 	//写地址为rt通用寄存器
				instvalid <= `InstValid;	
			end
			default:			begin
		    end
		  endcase		  //case op
		  
		  if (inst_i[31:21] == 11'b00000000000) begin
		  	if (op3 == `EXE_SLL) begin    //逻辑左移 rd<-rt<<sa(logic)
		  		wreg_o <= `WriteEnable;		
                aluop_o <= `EXE_SLL_OP;
		  		alusel_o <= `EXE_RES_SHIFT; 
                reg1_read_o <= 1'b0;	
                reg2_read_o <= 1'b1;  //rt	  	
				imm[4:0] <= inst_i[10:6]; //sa 移位数
        		wd_o <= inst_i[15:11];  //rd
			    instvalid <= `InstValid;	
				end 
              else if ( op3 == `EXE_SRL ) begin    //逻辑右移 rd<-rt>>sa(logic)
		  		     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  //算术右移 rd<-rt>>sa(arithmetic)
		  		          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		//else  		  
	
		if(inst_i == `EXE_ERET) begin	//返回异常指令
			wreg_o <= `WriteDisable;	
			aluop_o <= `EXE_ERET_OP;
		  	alusel_o <= `EXE_RES_NOP;  
			reg1_read_o <= 1'b0;	
			reg2_read_o <= 1'b0;
		  	instvalid <= `InstValid; 
			excepttype_is_eret<= `True_v;				
		end else if(inst_i[31:21] == 11'b01000000000 && inst_i[10:0] == 11'b00000000000) begin	//协处理器访问mfc0 GPR[rt]<-CPR[0,rd] 读数
					aluop_o <= `EXE_MFC0_OP;
					alusel_o <= `EXE_RES_MOVE;
					wd_o <= inst_i[20:16];//rt
					wreg_o <= `WriteEnable;
					instvalid <= `InstValid;
					reg1_read_o <= 1'b0;
					reg2_read_o <= 1'b0;		
				end else if(inst_i[31:21] == 11'b01000000100 && inst_i[10:0] == 11'b00000000000) begin	//协处理器访问mtc0 CPR[0,rd]<-GPR[rt] 改数
							aluop_o <= `EXE_MTC0_OP;
							alusel_o <= `EXE_RES_NOP;
							wreg_o <= `WriteDisable;
							instvalid <= `InstValid;	   
							reg1_read_o <= 1'b1;
							reg1_addr_o <= inst_i[20:16];//rt
							reg2_read_o <= 1'b0;					
						 end				  
	end         //always
	end
	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;		//前一指令为加载指令,第一个读取的寄存器值为前一加载指令加载值					
				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;    //立即数有值即利用,无值默认0
													   end else begin
															 reg1_o <= `ZeroWord;
														   end
	    end     //always
	
	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;			
				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

	always @ (*) begin
		if(rst == `RstEnable) begin
			is_in_delayslot_o <= `NotInDelaySlot;
		end else begin
		  is_in_delayslot_o <= is_in_delayslot_i;	//延迟指令传递	
	  end
	end

endmodule
//指令是否返回异常,是否有效,是否系统调用,是否中断->异常信息
//译出运算类型及其子类型
//是否读,读的地址 (确保读到准确数,解决数据相关)
//是否写通用寄存器/保存转移指令返回地址/写加载地址,写的地址
//是否转移指令|译出转移地址
//            |设定下一指令为延迟槽指令next_inst_in_delayslot、当前是否为延迟槽指令is_in_delayslot_o
//            |译出要保存到通用寄存器的返回地址,无设为0,有写使能
//判断前一指令与当前指令是否存在load相关
//异常信息判断设定

 id/ex

`include "defines.v"
`timescale 1ns/1ps
module id_ex(

	input	wire				clk,
	input   wire				rst,

	//来自控制模块的信息
	input wire[5:0]				stall,	//流水线暂停
	input wire					flush,	//信号清除
	//从译码阶段传递的信息
	input wire[`AluOpBus]         id_aluop,
	input wire[`AluSelBus]        id_alusel,
	input wire[`RegBus]           id_reg1,
	input wire[`RegBus]           id_reg2,
	input wire[`RegAddrBus]       id_wd,
	input wire                    id_wreg,
	input wire[`RegBus]           id_link_address,
	input wire                    id_is_in_delayslot,
	input wire                    next_inst_in_delayslot_i,
	input wire[`RegBus]			  id_inst,  //传递至EX,读offset值
	input wire[31:0]              id_excepttype,
	input wire[`RegBus]           id_current_inst_address,
	
	//传递到执行阶段的信息
	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,读offset
	output reg[31:0]              ex_excepttype,
	output reg[`RegBus]           ex_current_inst_address
);

	always @ (posedge clk) begin
		if (rst == `RstEnable) begin	//复位清零
			ex_aluop <= `EXE_NOP_OP;
			ex_alusel <= `EXE_RES_NOP;
			ex_reg1 <= `ZeroWord;
			ex_reg2 <= `ZeroWord;
			ex_wd <= `NOPRegAddr;
			ex_wreg <= `WriteDisable;
			ex_link_address <= `ZeroWord;
			ex_is_in_delayslot <= `NotInDelaySlot;
			is_in_delayslot_o <= `NotInDelaySlot;	
			ex_inst <= `ZeroWord;
			ex_excepttype <= `ZeroWord;
			ex_current_inst_address <= `ZeroWord;
		end else if(flush == 1'b1 ) begin	//信号清除
					ex_aluop <= `EXE_NOP_OP;
					ex_alusel <= `EXE_RES_NOP;
					ex_reg1 <= `ZeroWord;
					ex_reg2 <= `ZeroWord;
					ex_wd <= `NOPRegAddr;
					ex_wreg <= `WriteDisable;
					ex_excepttype <= `ZeroWord;
					ex_link_address <= `ZeroWord;
					ex_inst <= `ZeroWord;
					ex_is_in_delayslot <= `NotInDelaySlot;
					ex_current_inst_address <= `ZeroWord;	
					is_in_delayslot_o <= `NotInDelaySlot;	
			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;		
						ex_excepttype <= `ZeroWord;
						ex_current_inst_address <= `ZeroWord;	
				end else if(stall[2] == `NoStop) begin		//正常传递
							ex_aluop <= id_aluop;
							ex_alusel <= id_alusel;
							ex_reg1 <= id_reg1;
							ex_reg2 <= id_reg2;
							ex_wd <= id_wd;
							ex_wreg <= id_wreg;		
							ex_link_address <= id_link_address;
							ex_is_in_delayslot <= id_is_in_delayslot;
							is_in_delayslot_o <= next_inst_in_delayslot_i;		
							ex_inst <= id_inst;
							ex_excepttype <= id_excepttype;
							ex_current_inst_address <= id_current_inst_address;	
						 end
	end
	
endmodule

ex

`include "defines.v"
`timescale 1ns/1ps
module ex(

	input wire			          rst,
	
	//ID模块送到执行阶段的信息
	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[31:0]              excepttype_i,
	input wire[`RegBus]           current_inst_address_i,
	//HI、LO、CP0寄存器送入的值
	input wire[`RegBus]           hi_i,    //移动操作指令,读取HI,LO值
	input wire[`RegBus]           lo_i,
	//CP0寄存器送入的值
	input wire[`RegBus]			  cp0_reg_data_i,
	//回写阶段的指令是否要写HI、LO,用于检测HI、LO的数据相关;要改写HI、LO值,将改写后的准确值读入
	input wire[`RegBus]           wb_hi_i,
	input wire[`RegBus]           wb_lo_i,
	input wire                    wb_whilo_i,
	//回写阶段的指令是否要写cp0中寄存器,避免数据相关
	input wire					  wb_cp0_reg_we,
	input wire[4:0]				  wb_cp0_reg_write_addr,
	input wire[`RegBus]			  wb_cp0_reg_data,
	//访存阶段的指令是否要写HI、LO,用于检测HI、LO的数据相关
	input wire[`RegBus]           mem_hi_i,
	input wire[`RegBus]           mem_lo_i,
	input wire                    mem_whilo_i,
	//访存阶段的指令是否要写cp0中寄存器,避免数据相关
	input wire					  mem_cp0_reg_we,
	input wire[4:0]				  mem_cp0_reg_write_addr,
	input wire[`RegBus]			  mem_cp0_reg_data,
	
	input wire[`DoubleRegBus]     hilo_temp_i,//从EX/MEM得到第一个执行周期的乘法结果
	input wire[1:0]               cnt_i,      //当前处于第几个周期

	//与除法模块相连
	input wire[`DoubleRegBus]     div_result_i,  //除法运算结果
	input wire                    div_ready_i,  //除法运算是否结束(开始)
	//是否转移、以及link address
	input wire[`RegBus]           link_address_i,    //保存返回地址
	input wire                    is_in_delayslot_i,
	
	//存储加载指令地址接收。读offset
	input wire[`RegBus]			  inst_i,
	//送入MEM
	output reg[`RegAddrBus]       wd_o,
	output reg                    wreg_o,
	output reg[`RegBus]			  wdata_o,
	output reg[`RegBus]           hi_o,  //改写HI,LO值
	output reg[`RegBus]           lo_o,
	output reg                    whilo_o,
	output reg					  cp0_reg_we_o,//写cp0
	output reg[4:0]				  cp0_reg_write_addr_o,
	output reg[`RegBus]			  cp0_reg_data_o,
		
	output reg[`DoubleRegBus]     hilo_temp_o,  //将第一个执行周期的乘法结果送EX/MEM
	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 wire[`AluOpBus]		  aluop_o,	//送入MEM,MEM据子运算类型看加载/存储作执行操作
	output wire[`RegBus]		  mem_addr_o,//加载存储地址
	output wire[`RegBus]		  reg2_o,	//部分存储指令改写部分rt值,rt不改写值读取保留
	
	output wire[31:0]             excepttype_o, //异常信息
	output wire                   is_in_delayslot_o,
	output wire[`RegBus]          current_inst_address_o,	
	//送入CP0  /要读的cp0中某寄存器地址(与18行应)
	output reg[4:0]				  cp0_reg_read_addr_o,
	
	output reg					  stallreq       //是否请求暂停流水线			
	
);

	reg[`RegBus] logicout;
	reg[`RegBus] shiftres;
	reg[`RegBus] moveres;
	reg[`RegBus] arithmeticres;
	reg[`DoubleRegBus] mulres;	//第一次乘结果,且作符号调整。第一个时钟周期后给EX/MEM
	reg[`RegBus] HI;
	reg[`RegBus] LO;
	//算术指令
	wire[`RegBus] reg2_i_mux; //操作数2的补码
	wire[`RegBus] reg1_i_not; //操作数1取反
	wire[`RegBus] result_sum; //加法结果
	wire ov_sum;    //溢出情况
	wire reg1_eq_reg2; //操作数1是否 = 操作数2
	wire reg1_lt_reg2; //操作数1是否 < 操作数2
	wire[`RegBus] opdata1_mult; //被乘数
	wire[`RegBus] opdata2_mult; //乘数
	wire[`DoubleRegBus] hilo_temp; //第一次乘结果,未作符号调整
	reg[`DoubleRegBus] hilo_temp1; //最终乘累加、累减结果。第二个时钟周期可给EX/MEM
	reg stallreq_for_madd_msub;			
	reg stallreq_for_div;
	reg trapassert;		//是否自陷异常
	reg ovassert;		//是否溢出异常
	//加载存储指令
	assign aluop_o = aluop_i; 		//运算子类型正常传递至MEM
	assign mem_addr_o = reg1_i + {{16{inst_i[15]}},inst_i[15:0]};	//加载存储地址=offset符号扩展至32位与base加
	assign reg2_o = reg2_i;		//部分存储指令改写部分rt值,rt不改写值读取保留。送至访存段,访存RAM
	//异常信息译码阶段异常信息添加(是否返回异常eret,是否溢出,是否自陷,是否无效指令,是否系统调用,是否中断)
	assign excepttype_o = {excepttype_i[31:12],ovassert,trapassert,excepttype_i[9:8],8'h00};
	assign is_in_delayslot_o = is_in_delayslot_i;
	assign current_inst_address_o = current_inst_address_i;
	always @ (*) begin
		if(rst == `RstEnable) begin
			logicout <= `ZeroWord;        //逻辑
		end else begin
			case (aluop_i)
				`EXE_OR_OP:			begin
					logicout <= reg1_i | reg2_i;
				end
				`EXE_AND_OP:		begin
					logicout <= reg1_i & reg2_i;
				end
				`EXE_NOR_OP:		begin
					logicout <= ~(reg1_i |reg2_i);
				end
				`EXE_XOR_OP:		begin
					logicout <= reg1_i ^ reg2_i;
				end
				default:				begin
					logicout <= `ZeroWord;
				end
			endcase
		end    //if
	end      //always

	always @ (*) begin    //移位
		if(rst == `RstEnable) begin
			shiftres <= `ZeroWord;
		end else begin
			case (aluop_i)
				`EXE_SLL_OP:			begin
					shiftres <= reg2_i << reg1_i[4:0] ;
				end
				`EXE_SRL_OP:		begin
					shiftres <= reg2_i >> reg1_i[4:0];
				end
				`EXE_SRA_OP:		begin
					shiftres <= ({32{reg2_i[31]}} << (6'd32-{1'b0, reg1_i[4:0]})) | reg2_i >> reg1_i[4:0];//这步很妙
				end
				default:				begin
					shiftres <= `ZeroWord;
				end
			endcase
		end    //if
	end      //always

    //减法 或 有符号比较运算 或 有符号自陷,对源操作数2取补码,否则源操作数2不变
	assign reg2_i_mux = ((aluop_i == `EXE_SUB_OP) || (aluop_i == `EXE_SUBU_OP) 
						|| (aluop_i == `EXE_SLT_OP)
						|| (aluop_i == `EXE_TLT_OP) || (aluop_i == `EXE_TLTI_OP) || (aluop_i == `EXE_TGE_OP) || (aluop_i == `EXE_TGEI_OP)) ? (~reg2_i)+1 : reg2_i;

	assign result_sum = reg1_i + reg2_i_mux;//算和。加 减 有符号比较 有符号自陷适用										 

	assign ov_sum = ((!reg1_i[31] && !reg2_i_mux[31]) && result_sum[31]) ||((reg1_i[31] && reg2_i_mux[31]) && (!result_sum[31]));  //溢出情况
	//比较指令,自陷指令 操作数比较结果								
	assign reg1_lt_reg2 = ((aluop_i == `EXE_SLT_OP)
						|| (aluop_i == `EXE_TLT_OP) || (aluop_i == `EXE_TLTI_OP) || (aluop_i == `EXE_TGE_OP) || (aluop_i == `EXE_TGEI_OP))?((reg1_i[31] && !reg2_i[31])||(!reg1_i[31] && !reg2_i[31] && result_sum[31])||(reg1_i[31] && reg2_i[31] && result_sum[31])):(reg1_i < reg2_i); //比较运算情况
  
  assign reg1_i_not = ~reg1_i;//源操作数1取反
							
	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_ADDIU_OP,`EXE_SUB_OP, `EXE_SUBU_OP:		begin    //加减
					arithmeticres <= result_sum; 
				end	
				`EXE_ADDI_OP:	begin
					arithmeticres <= result_sum; 
				end
				`EXE_CLZ_OP:		begin    //计0
					arithmeticres <= reg1_i[31] ? 0 : reg1_i[30] ? 1 : reg1_i[29] ? 2 :
													 reg1_i[28] ? 3 : reg1_i[27] ? 4 : reg1_i[26] ? 5 :
													 reg1_i[25] ? 6 : reg1_i[24] ? 7 : reg1_i[23] ? 8 : 
													 reg1_i[22] ? 9 : reg1_i[21] ? 10 : reg1_i[20] ? 11 :
													 reg1_i[19] ? 12 : reg1_i[18] ? 13 : reg1_i[17] ? 14 : 
													 reg1_i[16] ? 15 : reg1_i[15] ? 16 : reg1_i[14] ? 17 : 
													 reg1_i[13] ? 18 : reg1_i[12] ? 19 : reg1_i[11] ? 20 :
													 reg1_i[10] ? 21 : reg1_i[9] ? 22 : reg1_i[8] ? 23 : 
													 reg1_i[7] ? 24 : reg1_i[6] ? 25 : reg1_i[5] ? 26 : 
													 reg1_i[4] ? 27 : reg1_i[3] ? 28 : reg1_i[2] ? 29 : 
													 reg1_i[1] ? 30 : reg1_i[0] ? 31 : 32 ;
				end    //从左向右依次找0
				`EXE_CLO_OP:		begin    //计数1
					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    //从左向右依次找1
				default:				begin
					arithmeticres <= `ZeroWord;
				end
			endcase
		end
	end

  //取得乘法操作的操作数,如果是有符号除法且操作数是负数,那么取反加一
  assign opdata1_mult = (((aluop_i == `EXE_MUL_OP) || (aluop_i == `EXE_MULT_OP) ||(aluop_i == `EXE_MADD_OP) || (aluop_i == `EXE_MSUB_OP))&& (reg1_i[31] == 1'b1)) ? (~reg1_i + 1) : reg1_i;

  assign opdata2_mult = (((aluop_i == `EXE_MUL_OP) || (aluop_i == `EXE_MULT_OP) ||(aluop_i == `EXE_MADD_OP) || (aluop_i == `EXE_MSUB_OP))&& (reg2_i[31] == 1'b1)) ? (~reg2_i + 1) : reg2_i;	

  assign hilo_temp = opdata1_mult * opdata2_mult;																				

	always @ (*) begin		//乘
		if(rst == `RstEnable) begin
			mulres <= {`ZeroWord,`ZeroWord};
		end else if ((aluop_i == `EXE_MULT_OP) || (aluop_i == `EXE_MUL_OP) ||(aluop_i == `EXE_MADD_OP) || (aluop_i == `EXE_MSUB_OP))begin
					if(reg1_i[31] ^ reg2_i[31] == 1'b1) begin
						mulres <= ~hilo_temp + 1;  //有符号乘,结果为负取补码,正数补码是本身
					end else begin
					  mulres <= hilo_temp;  //无符号乘,直接做结果
					end
				 end else begin
					mulres <= hilo_temp;
				 end
	end

  //得到最新的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};
		         end else if(wb_whilo_i == `WriteEnable) begin
			                {HI,LO} <= {wb_hi_i,wb_lo_i};
		                  end else begin
		                	{HI,LO} <= {hi_i,lo_i};			
		                    end
	  end	

  always @ (*) begin  //乘累加乘累减除法的流水线暂停请求
    stallreq = stallreq_for_madd_msub || stallreq_for_div;
  end

  //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  //第一个时钟周期,给出乘法结果,设定下一进行下一时钟周期,流水线暂停,结果为0
						hilo_temp_o <= mulres;
						cnt_o <= 2'b01;
						stallreq_for_madd_msub <= `Stop;
						hilo_temp1 <= {`ZeroWord,`ZeroWord};
					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
				`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、DIVU指令	
	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;//除法开始,div模块工作
						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	

	//MFHI、MFLO、MOVN、MOVZ移动指令
	always @ (*) begin		//移动指令
		if(rst == `RstEnable) begin
	  	    moveres <= `ZeroWord;
	    end else begin
	        moveres <= `ZeroWord;
	        case (aluop_i)
	   	       `EXE_MFHI_OP:		begin
	   		        moveres <= HI;
	   	          end
	           	`EXE_MFLO_OP:		begin
	   	        	moveres <= LO;
	              end
	   	        `EXE_MOVZ_OP:		begin
	   		        moveres <= reg1_i;
	   	          end
	   	        `EXE_MOVN_OP:		begin
	   		        moveres <= reg1_i;
	   	          end
				`EXE_MFC0_OP:		begin
					cp0_reg_read_addr_o <= inst_i[15:11];	//读CPR[0,rd]
					moveres <= cp0_reg_data_i; 
					//访存段、回写段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 //else
	end	 //always
	
	always @ (*) begin		//自陷指令
		if(rst == `RstEnable) begin
			trapassert <= `TrapNotAssert;
		end else begin
			trapassert <= `TrapNotAssert;
			case (aluop_i)
				`EXE_TEQ_OP, `EXE_TEQI_OP:  begin
					if( reg1_i == reg2_i ) begin
						trapassert <= `TrapAssert;
					end
				end
				`EXE_TGE_OP, `EXE_TGEI_OP, `EXE_TGEIU_OP, `EXE_TGEU_OP:	begin
					if( ~reg1_lt_reg2 ) begin
						trapassert <= `TrapAssert;
					end
				end
				`EXE_TLT_OP, `EXE_TLTI_OP, `EXE_TLTIU_OP, `EXE_TLTU_OP:	begin
					if( reg1_lt_reg2 ) begin
						trapassert <= `TrapAssert;
					end
				end
				`EXE_TNE_OP, `EXE_TNEI_OP:	begin
					if( reg1_i != reg2_i ) begin
						trapassert <= `TrapAssert;
					end
				end
				default: begin
					trapassert <= `TrapNotAssert;
				end
			endcase
		end
	end

 always @ (*) begin //要写入通用寄存器的数据确定,溢出写是否使能
	 wd_o <= wd_i;	 	 	 	
	 if(((aluop_i == `EXE_ADD_OP) || (aluop_i == `EXE_ADDI_OP) || (aluop_i == `EXE_SUB_OP)) && (ov_sum == 1'b1)) begin
	 	wreg_o <= `WriteDisable; //溢出不保存,写无效
		ovassert <= 1'b1;	//溢出异常
	 end else begin
	     wreg_o <= wreg_i; 
		 ovassert <= 1'b0;	//未溢出异常
	     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
	 		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 @ (*) begin //要写入HI,LO数据的确定
		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//乘结果写入HI,LO寄存器
			        whilo_o <= `WriteEnable;
			        hi_o <= mulres[63:32];
			        lo_o <= mulres[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_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_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 if(aluop_i == `EXE_MTHI_OP) begin
			                                        whilo_o <= `WriteEnable;
			                                        hi_o <= reg1_i;
			                                        lo_o <= 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		
	always @ (*) begin	//对cp0中寄存器修改信息送入MEM,传递至后面模块
		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
					cp0_reg_write_addr_o <= inst_i[15:11]; //改rd值
					cp0_reg_we_o <= `WriteEnable; //修改使能
					cp0_reg_data_o <= 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
//两源操作数运算,计算写结果
//                        加法直接相加,减法用源操作数1加源操作数2补码。溢出情况选中后设定是否写
//                        比较:有符号看差正负
//                        乘法:源操作数取补,结果据有符号乘和无符号乘看正负
//                        除:DIV模块实现
//						  自陷:比较结果加工
//通用寄存器写结果转移确定,HI,LO寄存器写结果转移确定,CP0中寄存器值确定
//访存回写段数据相关问题的解决
//乘累加乘累减除法流水线暂停请求
//计算加载存储指令地址。要存储的数据或要部分修改的原数据
//异常信息添加

 ex/mem

`include "defines.v"
`timescale 1ns/1ps
module ex_mem(

	input wire				    clk,
	input wire					rst,

	//来自控制模块的信息
	input wire[5:0]				stall,	
	input wire                   flush,
	//来自执行阶段的信息	
	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					  ex_cp0_reg_we,
	input wire[4:0]				  ex_cp0_reg_write_addr,
	input wire[`RegBus]			  ex_cp0_reg_data,
	input wire[31:0]              ex_excepttype,
	input wire                    ex_is_in_delayslot,
	input wire[`RegBus]           ex_current_inst_address,
	
	input wire[`DoubleRegBus]     hilo_i,	
	input wire[1:0]               cnt_i,
	//存储加载指令
	input wire[`AluOpBus]		  ex_aluop,	//送入MEM,MEM据子运算类型看加载/存储作执行操作
	input wire[`RegBus]		  	  ex_mem_addr,//加载存储地址
	input wire[`RegBus]		   	  ex_reg2,	//部分存储指令改写部分rt值,rt不改写值读取保留
	
	//送到访存阶段的信息
	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					 mem_cp0_reg_we,
	output reg[4:0]				 mem_cp0_reg_write_addr,
	output reg[`RegBus]			 mem_cp0_reg_data,
	output reg[31:0]             mem_excepttype,
    output reg                   mem_is_in_delayslot,
	output reg[`RegBus]          mem_current_inst_address,
	
	output reg[`DoubleRegBus]    hilo_o,
	output reg[1:0]              cnt_o,
	//存储加载指令
	output reg[`AluOpBus]		 mem_aluop,	//送入MEM,MEM据子运算类型看加载/存储作执行操作
	output reg[`RegBus]		     mem_mem_addr,//加载存储地址
	output reg[`RegBus]		     mem_reg2	//部分存储指令改写部分rt值,rt不改写值读取保留
		
);


	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;
			mem_excepttype <= `ZeroWord;
			mem_is_in_delayslot <= `NotInDelaySlot;
			mem_current_inst_address <= `ZeroWord;
		end else if(flush == 1'b1 ) begin
					mem_wd <= `NOPRegAddr;
					mem_wreg <= `WriteDisable;
					mem_wdata <= `ZeroWord;
					mem_hi <= `ZeroWord;
					mem_lo <= `ZeroWord;
					mem_whilo <= `WriteDisable;
					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;
					mem_excepttype <= `ZeroWord;
					mem_is_in_delayslot <= `NotInDelaySlot;
					mem_current_inst_address <= `ZeroWord;
					hilo_o <= {`ZeroWord, `ZeroWord};
					cnt_o <= 2'b00;	    	    				
			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;
						mem_excepttype <= `ZeroWord;
						mem_is_in_delayslot <= `NotInDelaySlot;
						mem_current_inst_address <= `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据子运算类型看加载/存储作执行操作
								mem_mem_addr <= ex_mem_addr;	//加载存储地址
								mem_reg2 <= ex_reg2;			//部分存储指令改写部分rt值,rt不改写值读取保留
								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;
								mem_excepttype <= ex_excepttype;
								mem_is_in_delayslot <= ex_is_in_delayslot;
								mem_current_inst_address <= ex_current_inst_address;						
							end else begin
									hilo_o <= hilo_i;
									cnt_o <= cnt_i;											
								end    
	end      //always
			

endmodule

mem

`include "defines.v"
`timescale 1ns/1ps
module mem(

	input wire					rst,
	
	//来自执行阶段的信息	
	input wire[`RegAddrBus]       wd_i,
	input wire                    wreg_i,
	input wire[`RegBus]			  wdata_i,
	input wire					  cp0_reg_we_i,
	input wire[4:0]				  cp0_reg_write_addr_i,
	input wire[`RegBus]			  cp0_reg_data_i,
	input wire[`RegBus]           hi_i,
	input wire[`RegBus]           lo_i,
	input wire                    whilo_i,
	input wire[31:0]              excepttype_i,
	input wire                    is_in_delayslot_i,
	input wire[`RegBus]           current_inst_address_i,	
		//存储加载指令
	input wire[`AluOpBus]		  aluop_i,	//送入MEM,MEM据子运算类型看加载/存储作执行操作
	input wire[`RegBus]		  	  mem_addr_i,//加载存储地址
	input wire[`RegBus]		   	  reg2_i,	//部分存储指令改写部分rt值,rt不改写值读取保留
	//来自RAM数据存储器
	input wire[`RegBus]			mem_data_i,
	//来自LLbit寄存器
	input wire                  LLbit_i,//来自LLbit寄存器
	input wire                  wb_LLbit_we_i,
	input wire                  wb_LLbit_value_i,//来自MEM/WB,数据前推解决数据相关
	//来自CP0,访存段据cp0内寄存器值判断异常种类,需cp0寄存器最新值
	input wire[`RegBus]          cp0_status_i,
	input wire[`RegBus]          cp0_cause_i,
		//来自CP0,送至crtl,作异常返回指令的异常处理例程入口地址
	input wire[`RegBus]          cp0_epc_i,
	//来自MEM/WB,回写阶段的指令是否要写CP0,用来检测数据相关
	input wire                    wb_cp0_reg_we,
	input wire[4:0]               wb_cp0_reg_write_addr,
	input wire[`RegBus]           wb_cp0_reg_data,
	//送到回写阶段的信息
	output reg[`RegAddrBus]      wd_o,
	output reg                   wreg_o,
	output reg[`RegBus]			 wdata_o,
	output reg					 cp0_reg_we_o,
	output reg[4:0]				 cp0_reg_write_addr_o,
	output reg[`RegBus]			 cp0_reg_data_o,
	output reg[`RegBus]          hi_o,
	output reg[`RegBus]          lo_o,
	output reg                   whilo_o,	
	//送到RAM数据存储器
	output reg					 mem_ce_o, //RAM使能
	output reg[`RegBus]			 mem_addr_o, //加载存储地址
	output wire					 mem_we_o, //是否写RAM
	output reg[3:0]				 mem_sel_o, //存储/加载不同字节位置的选择(一个字节8bit,4×8=32bit)
	output reg[`RegBus]			 mem_data_o, //写RAM值
	//最终送至LLbit
	output reg                   LLbit_we_o,
	output reg                   LLbit_value_o,
	
	output reg[31:0]             excepttype_o,	//送至cp0据此异常信息修改各寄存器值
	output wire[`RegBus]         cp0_epc_o,		//送至crtl,作异常返回指令的异常处理例程入口地址
	output wire                  is_in_delayslot_o,//送至cp0据是否为延迟指令判断异常指令地址
	
	output wire[`RegBus]         current_inst_address_o	//送至cp0,修改epc寄存器值。因为可能为延迟槽指令,需前一指令,要减4
);
	wire[`RegBus]		  zero32;
	reg			   		  mem_we;
	reg					  LLbit;
	reg[`RegBus]          cp0_status;
	reg[`RegBus]          cp0_cause;
	reg[`RegBus]          cp0_epc;
	//assign				  mem_we_o = mem_we;//输出为网线型(左),设置时为寄存器型(右)
	assign mem_we_o = mem_we & (~(|excepttype_o));//异常取消写
	assign				  zero32 = `ZeroWord;
	assign is_in_delayslot_o = is_in_delayslot_i;
	assign current_inst_address_o = current_inst_address_i;
	assign cp0_epc_o = cp0_epc;
	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_ce_o <= `ChipDisable;
			mem_addr_o <= `ZeroWord;
			mem_we <= `WriteDisable;
			mem_sel_o <= 4'b0000;
			mem_data_o <= `ZeroWord;
			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;
			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;
			hi_o <= hi_i;
			lo_o <= lo_i;
			whilo_o <= whilo_i;		
			mem_ce_o <= `ChipDisable;
			mem_addr_o <= `ZeroWord;
			mem_we <= `WriteDisable;
			mem_sel_o <= 4'b1111;
			LLbit_we_o <= 1'b0;
			LLbit_value_o <= 1'b0;
			case(aluop_i)
				`EXE_LB_OP:		begin		//有符号加载字节指令
					mem_addr_o <= mem_addr_i;  
					mem_we <= `WriteDisable; //加载指令不改写RAM中值
					mem_ce_o <= `ChipEnable; //RAM使能
					case(mem_addr_i[1:0])	//参考加载地址后2位给字节选择赋值,添加Wishbone总线接口容易
						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; //加载指令不改写RAM中值
					mem_ce_o <= `ChipEnable; //RAM使能
					case(mem_addr_i[1:0])	//参考加载地址后2位给字节选择赋值,添加Wishbone总线接口容易
						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字节16bit)
					mem_addr_o <= mem_addr_i;  
					mem_we <= `WriteDisable; //加载指令不改写RAM中值
					mem_ce_o <= `ChipEnable; //RAM使能
					case(mem_addr_i[1:0])	//参考加载地址后2位给字节选择赋值,添加Wishbone总线接口容易
						2'b00:	begin
							wdata_o <= {{16{mem_data_i[31]}},mem_data_i[31:16]};
							mem_sel_o <= 4'b1100;
						end
						2'b01: 	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		//无符号加载半字指令(一个字2字节16bit)
					mem_addr_o <= mem_addr_i;  
					mem_we <= `WriteDisable; //加载指令不改写RAM中值
					mem_ce_o <= `ChipEnable; //RAM使能
					case(mem_addr_i[1:0])	//参考加载地址后2位给字节选择赋值,添加Wishbone总线接口容易
						2'b00:	begin
							wdata_o <= {{16{1'b0}},mem_data_i[31:16]};
							mem_sel_o <= 4'b1100;
						end
						2'b01: 	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_ce_o <= `ChipEnable; //RAM使能
					mem_we <= `WriteDisable; //加载指令不改写RAM中值
					wdata_o <= mem_data_i;  //写入通用寄存器的加载值
					mem_sel_o <=4'b1111;   //全加载
				end
				`EXE_LWL_OP:	begin
					mem_addr_o <= {mem_addr_i[31:2], 2'b00};	//从loadaddr_align加载字节
					mem_we <= `WriteDisable; //加载指令不改写RAM中值
					mem_sel_o <= 4'b1111;
					mem_ce_o <= `ChipEnable;
					case (mem_addr_i[1:0])	//参考加载地址后2位给字节选择赋值
						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]};	//少一个字节的加载值低位存入rt高位
						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};	//从loadaddr_align加载字节
					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]};  //0+1位加载值的高位存入rt的低位
						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_SB_OP:		begin
					mem_addr_o <= mem_addr_i;	
					mem_we <= `WriteEnable;		//存储指令,向RAM中存储数据,要写入
					mem_data_o <= {reg2_i[7:0],reg2_i[7:0],reg2_i[7:0],reg2_i[7:0]};  //rt值低字节写入
					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]}; //rt值低两个字节写入
					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;	//rt值全存入
					mem_ce_o <= `ChipEnable;		
				end
				`EXE_SWL_OP:		begin
					mem_addr_o <= {mem_addr_i[31:2], 2'b00};	//从storaddr_align存储字节
					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;	//存4-storaddr[1:0]个rt高字节至存储低字节
						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};	//从storaddr_align存储字节
					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]};	//存1+storaddr[1: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_LL_OP:		begin
					mem_ce_o <= `ChipEnable;						
					mem_addr_o <= mem_addr_i;
					mem_we <= `WriteDisable;
					wdata_o <= mem_data_i;	//加载至通用寄存器rt
					LLbit_we_o <= 1'b1;
					LLbit_value_o <= 1'b1;//无异常,LLbit置1
					mem_sel_o <= 4'b1111;							
				end				
				`EXE_SC_OP:		begin
					if(LLbit == 1'b1) begin
						LLbit_we_o <= 1'b1;
						LLbit_value_o <= 1'b0;//LLbit为1,未发生异常,执行sc后LLbit置0
						mem_ce_o <= `ChipEnable;
						mem_addr_o <= mem_addr_i;
						mem_we <= `WriteEnable;
						mem_data_o <= reg2_i;
						wdata_o <= 32'b1;//sc指令成功执行,rt置1
						mem_sel_o <= 4'b1111;												
					end else begin
						wdata_o <= 32'b0;//sc指令执行失败,rt置0
					end
				end				
				default:		begin
					//什么也不做
				end
			endcase							
		end    //else
	end      //always
			
	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;//LLbit最新值
				end else begin
					LLbit <= LLbit_i;
				end
		end
	end
	always @ (*) begin	//得到status最新值
		if(rst == `RstEnable) begin
			cp0_status <= `ZeroWord;
		end else if((wb_cp0_reg_we == `WriteEnable) && (wb_cp0_reg_write_addr == `CP0_REG_STATUS ))begin
					cp0_status <= wb_cp0_reg_data;	//来自于MEM/WB输出.访存段未执行,则(若)上一条修改cp0,cp0寄存器修改未执行,MEM/WB输出的是最新值
				end else begin
						cp0_status <= cp0_status_i;	//来自cp0输出。上一条非修改cp0寄存器,cp0值后面作异常信息设定的判断
					end
	end
	always @ (*) begin	//得到epc最新值
		if(rst == `RstEnable) begin
			cp0_epc <= `ZeroWord;
		end else if((wb_cp0_reg_we == `WriteEnable) && (wb_cp0_reg_write_addr == `CP0_REG_EPC ))begin
					cp0_epc <= wb_cp0_reg_data;
				end else begin
						cp0_epc <= cp0_epc_i;
					end
	end

  always @ (*) begin	//得到cause最新值
		if(rst == `RstEnable) begin
			cp0_cause <= `ZeroWord;
		end else if((wb_cp0_reg_we == `WriteEnable) && (wb_cp0_reg_write_addr == `CP0_REG_CAUSE ))begin
					cp0_cause[9:8] <= wb_cp0_reg_data[9:8];//IP[1:0]软件中断
					cp0_cause[22] <= wb_cp0_reg_data[22];//WP 处理器处于异常模式
					cp0_cause[23] <= wb_cp0_reg_data[23];//IV 中断异常向量
				end else begin
						cp0_cause <= cp0_cause_i;
					end
	end
	always @ (*) begin
		if(rst == `RstEnable) begin
			excepttype_o <= `ZeroWord;
		end else begin
			excepttype_o <= `ZeroWord;			
			if(current_inst_address_i != `ZeroWord) begin
				if(((cp0_cause[15:8] & (cp0_status[15:8])) != 8'h00) && (cp0_status[1] == 1'b0) && (cp0_status[0] == 1'b1)) begin
					excepttype_o <= 32'h00000001;        //interrupt 不屏蔽中断且中断且不禁止中断且中断使能
				end else if(excepttype_i[8] == 1'b1) begin
							excepttype_o <= 32'h00000008;        //syscall 系统调用
					end else if(excepttype_i[9] == 1'b1) begin
								excepttype_o <= 32'h0000000a;        //inst_invalid 指令无效
						end else if(excepttype_i[10] ==1'b1) begin
									excepttype_o <= 32'h0000000d;        //trap 自陷
							end else if(excepttype_i[11] == 1'b1) begin  
										excepttype_o <= 32'h0000000c;		//ov 溢出
								end else if(excepttype_i[12] == 1'b1) begin  
											excepttype_o <= 32'h0000000e;	//eret 异常返回指令
								end
			end
		end
	end		
endmodule
//传递运算结果,写入通用寄存器
//与RAM数据存储器相连,从RAM中获得加载数据,或向RAM中存储数据
//据MEM/WB,CP0送来的cp0寄存器最新数据,判断设定异常类型,
//												送至cp0修改寄存器数据(如处理器是否可用,异常种类)
//												送至crtl,再发出异常清除信号及异常处理例程入口地址
//

mem/wb

`include "defines.v"
`timescale 1ns/1ps
module mem_wb(

	input wire					clk,
	input wire					rst,

  //来自控制模块的信息
	input wire[5:0]               stall,	
	input wire                    flush,
	//来自访存阶段的信息	
	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_cp0_reg_we,
	input wire[4:0]				  mem_cp0_reg_write_addr,
	input wire[`RegBus]			  mem_cp0_reg_data,
	input wire                    mem_LLbit_we,
	input wire                    mem_LLbit_value,	

	//送到回写阶段的信息
	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_cp0_reg_we,
	output reg[4:0]				 wb_cp0_reg_write_addr,
	output reg[`RegBus]			 wb_cp0_reg_data,

	output reg                   wb_LLbit_we,
	output reg                   wb_LLbit_value
	
);


	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(flush == 1'b1 ) 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_cp0_reg_we <= `WriteDisable;
						wb_cp0_reg_write_addr <= 5'b00000;
						wb_cp0_reg_data <= `ZeroWord;
						wb_hi <= `ZeroWord;
						wb_lo <= `ZeroWord;
						wb_whilo <= `WriteDisable;
						wb_LLbit_we <= 1'b0;
						wb_LLbit_value <= 1'b0;
					end else if(stall[4] == `NoStop) begin	//流水线正常
								wb_wd <= mem_wd;
								wb_wreg <= mem_wreg;
								wb_wdata <= mem_wdata;
								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;
								wb_hi <= mem_hi;
								wb_lo <= mem_lo;
								wb_whilo <= mem_whilo;
								wb_LLbit_we <= mem_LLbit_we;
								wb_LLbit_value <= mem_LLbit_value;
							end    
		end      
			
endmodule

regfile

`include "defines.v"
`timescale 1ns/1ps
module regfile(

	input	wire										clk,
	input wire										rst,
	
	//写端口
	input wire										we,
	input wire[`RegAddrBus]				waddr,
	input wire[`RegBus]						wdata,
	
	//读端口1
	input wire										re1,
	input wire[`RegAddrBus]			  raddr1,
	output reg[`RegBus]           rdata1,
	
	//读端口2
	input wire										re2,
	input wire[`RegAddrBus]			  raddr2,
	output reg[`RegBus]           rdata2
	
);

	reg[`RegBus]  regs[0:`RegNum-1];

	always @ (posedge clk) begin
		if (rst == `RstDisable) begin
			if((we == `WriteEnable) && (waddr != `RegNumLog2'h0)) begin
				regs[waddr] <= wdata;
			end
		end
	end
	
	always @ (*) begin
		if(rst == `RstEnable) begin
			  rdata1 <= `ZeroWord;
	  end else if(raddr1 == `RegNumLog2'h0) begin
	  		rdata1 <= `ZeroWord;
	  end else if((raddr1 == waddr) && (we == `WriteEnable) 
	  	            && (re1 == `ReadEnable)) begin
	  	  rdata1 <= wdata;
	  end else if(re1 == `ReadEnable) begin
	      rdata1 <= regs[raddr1];
	  end else begin
	      rdata1 <= `ZeroWord;
	  end
	end

	always @ (*) begin
		if(rst == `RstEnable) begin
			  rdata2 <= `ZeroWord;
	  end else if(raddr2 == `RegNumLog2'h0) begin
	  		rdata2 <= `ZeroWord;
	  end else if((raddr2 == waddr) && (we == `WriteEnable) 
	  	            && (re2 == `ReadEnable)) begin
	  	  rdata2 <= wdata;
	  end else if(re2 == `ReadEnable) begin
	      rdata2 <= regs[raddr2];
	  end else begin
	      rdata2 <= `ZeroWord;
	  end
	end

endmodule

ram

`include "defines.v"
`timescale 1ns/1ps
module data_ram(

	input wire						clk,
	input wire						ce,     //RAM是否使能
	input wire						we,     //RAM是否存储
	input wire[`DataAddrBus]		addr,   //加载存储地址
	input wire[3:0]					sel,    //字节选择
	input wire[`DataBus]			data_i, //存储数据
	output reg[`DataBus]			data_o //加载数据
	
);
//定义4个1字节数组
	reg[`ByteWidth]  data_mem0[0:`DataMemNum-1];
	reg[`ByteWidth]  data_mem1[0:`DataMemNum-1];
	reg[`ByteWidth]  data_mem2[0:`DataMemNum-1];
	reg[`ByteWidth]  data_mem3[0:`DataMemNum-1];
//读
	always @ (posedge clk) begin
		if (ce == `ChipDisable) begin
			//data_o <= ZeroWord;
		end else if(we == `WriteEnable) begin
			  if (sel[3] == 1'b1) begin
		      data_mem3[addr[`DataMemNumLog2+1:2]] <= data_i[31:24];//据sel值修改存储器对应字节,低两位不使用
		    end
			  if (sel[2] == 1'b1) begin
		      data_mem2[addr[`DataMemNumLog2+1:2]] <= data_i[23:16];
		    end
		    if (sel[1] == 1'b1) begin
		      data_mem1[addr[`DataMemNumLog2+1:2]] <= data_i[15:8];
		    end
			  if (sel[0] == 1'b1) begin
		      data_mem0[addr[`DataMemNumLog2+1:2]] <= data_i[7:0];
		    end			   	    
		end
	end
/是否合并
	//写
	always @ (*) begin
		if (ce == `ChipDisable) begin
			data_o <= `ZeroWord;
	  end else if(we == `WriteDisable) begin
		    data_o <= {data_mem3[addr[`DataMemNumLog2+1:2]],
		               data_mem2[addr[`DataMemNumLog2+1:2]],
		               data_mem1[addr[`DataMemNumLog2+1:2]],
		               data_mem0[addr[`DataMemNumLog2+1:2]]};
		end else begin
				data_o <= `ZeroWord;
		end
	end		

endmodule

hilo

`include "defines.v"
`timescale 1ns/1ps
module hilo_reg(

	input	wire										clk,
	input wire										rst,
	
	//写端口
	input wire										we,
	input wire[`RegBus]				    hi_i,
	input wire[`RegBus]						lo_i,
	
	//读端口1
	output reg[`RegBus]           hi_o,
	output reg[`RegBus]           lo_o
	
);

	always @ (posedge clk) begin
		if (rst == `RstEnable) begin
					hi_o <= `ZeroWord;
					lo_o <= `ZeroWord;
		end else if((we == `WriteEnable)) begin
					hi_o <= hi_i;
					lo_o <= lo_i;
		end
	end

endmodule

div

`include "defines.v"
`timescale 1ns/1ps
module div(

	input	wire										clk,
	input wire										rst,
	
	input wire                    signed_div_i,
	input wire[31:0]              opdata1_i,
	input wire[31:0]		   				opdata2_i,
	input wire                    start_i,
	input wire                    annul_i,
	
	output reg[63:0]             result_o,
	output reg			             ready_o
);

	wire[32:0] div_temp;
	reg[5:0] cnt;
	reg[64:0] dividend;
	reg[1:0] state;
	reg[31:0] divisor;	 
	reg[31:0] temp_op1;
	reg[31:0] temp_op2;
	
	assign div_temp = {1'b0,dividend[63:32]} - {1'b0,divisor};

	always @ (posedge clk) begin
		if (rst == `RstEnable) begin
			state <= `DivFree;
			ready_o <= `DivResultNotReady;
			result_o <= {`ZeroWord,`ZeroWord};
		end else begin
		  case (state)
		  	`DivFree:			begin               //DivFree状态
		  		if(start_i == `DivStart && annul_i == 1'b0) begin
		  			if(opdata2_i == `ZeroWord) begin
		  				state <= `DivByZero;
		  			end else begin
		  				state <= `DivOn;
		  				cnt <= 6'b000000;
		  				if(signed_div_i == 1'b1 && opdata1_i[31] == 1'b1 ) begin
		  					temp_op1 = ~opdata1_i + 1;
		  				end else begin
		  					temp_op1 = opdata1_i;
		  				end
		  				if(signed_div_i == 1'b1 && opdata2_i[31] == 1'b1 ) begin
		  					temp_op2 = ~opdata2_i + 1;
		  				end else begin
		  					temp_op2 = opdata2_i;
		  				end
		  				dividend <= {`ZeroWord,`ZeroWord};
              dividend[32:1] <= temp_op1;
              divisor <= temp_op2;
             end
          end else begin
						ready_o <= `DivResultNotReady;
						result_o <= {`ZeroWord,`ZeroWord};
				  end          	
		  	end
		  	`DivByZero:		begin               //DivByZero状态
         	dividend <= {`ZeroWord,`ZeroWord};
          state <= `DivEnd;		 		
		  	end
		  	`DivOn:				begin               //DivOn状态
		  		if(annul_i == 1'b0) begin
		  			if(cnt != 6'b100000) begin
               if(div_temp[32] == 1'b1) begin
                  dividend <= {dividend[63:0] , 1'b0};
               end else begin
                  dividend <= {div_temp[31:0] , dividend[31:0] , 1'b1};
               end
               cnt <= cnt + 1;
             end else begin
               if((signed_div_i == 1'b1) && ((opdata1_i[31] ^ opdata2_i[31]) == 1'b1)) begin
                  dividend[31:0] <= (~dividend[31:0] + 1);
               end
               if((signed_div_i == 1'b1) && ((opdata1_i[31] ^ dividend[64]) == 1'b1)) begin              
                  dividend[64:33] <= (~dividend[64:33] + 1);
               end
               state <= `DivEnd;
               cnt <= 6'b000000;            	
             end
		  		end else begin
		  			state <= `DivFree;
		  		end	
		  	end
		  	`DivEnd:			begin               //DivEnd状态
        	result_o <= {dividend[64:33], dividend[31:0]};  
          ready_o <= `DivResultReady;
          if(start_i == `DivStop) begin
          	state <= `DivFree;
						ready_o <= `DivResultNotReady;
						result_o <= {`ZeroWord,`ZeroWord};       	
          end		  	
		  	end
		  endcase
		end
	end

endmodule

cp0

`include "defines.v"
`timescale 1ns/1ps
module cp0_reg(

	input	wire				 clk,
	input   wire				 rst,
	//是否写,写的地址,写的数据	
	input wire                    we_i,
	input wire[4:0]               waddr_i,
	input wire[`RegBus]           data_i,
	
	input wire[4:0]               raddr_i,//读的地址	
	input wire[5:0]               int_i,	//6个外硬件中断输入
 	
	input wire[31:0]              excepttype_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    
	
);
//cp0内寄存器值更新
	always @ (posedge clk) begin
		if(rst == `RstEnable) begin
			count_o <= `ZeroWord;
			compare_o <= `ZeroWord;			
			status_o <= 32'b00010000000000000000000000000000;//status寄存器的CU为0001,表示协处理器CP0存在
			cause_o <= `ZeroWord;
			epc_o <= `ZeroWord;			
			config_o <= 32'b00000000000000001000000000000000;//config寄存器的BE为1,表示Big-Endian;MT为00,表示没有MMU		
			prid_o <= 32'b00000000010011000000000100000010;//制作者是L,对应的是0x48,类型是0x1,基本类型,版本号是1.0
			timer_int_o <= `InterruptNotAssert;//未定时中断
		end else begin
					count_o <= count_o + 1 ;	//计数加1
					cause_o[15:10] <= int_i;	//cause寄存器15-10位表示外硬件中断情况		
					if(compare_o != `ZeroWord && count_o == compare_o) begin
						timer_int_o <= `InterruptAssert;	//compare值与count值相同,定时中断
					end						
					if(we_i == `WriteEnable) begin	//cp0内寄存器值写入
						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 <= `InterruptNotAssert;
							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	
							default: 	begin
							end		
						endcase  //case addr_i
					end	
					case (excepttype_i)
						32'h00000001:		begin	//外部中断
							if(is_in_delayslot_i == `InDelaySlot ) begin
								epc_o <= current_inst_addr_i - 4 ;
								cause_o[31] <= 1'b1;    //异常在延迟槽
							end else begin
								  epc_o <= current_inst_addr_i;
								  cause_o[31] <= 1'b0;  //异常不在延迟槽
							end
							status_o[1] <= 1'b1;		//处于异常级进入内核模式禁止中断
							cause_o[6:2] <= 5'b00000;	//异常原因:中断			
						end
						32'h00000008:		begin	//系统调用
							if(status_o[1] == 1'b0) begin //未处于异常级
								if(is_in_delayslot_i == `InDelaySlot ) begin
									epc_o <= current_inst_addr_i - 4 ;
									cause_o[31] <= 1'b1;			//异常在延迟槽
								end else begin
									epc_o <= current_inst_addr_i;
									cause_o[31] <= 1'b0;		//异常不在延迟槽
									end
								end
							status_o[1] <= 1'b1;		//处于异常级
							cause_o[6:2] <= 5'b01000;	//异常原因:系统调用		
						end
						32'h0000000a:		begin		//指令无效
							if(status_o[1] == 1'b0) begin
								if(is_in_delayslot_i == `InDelaySlot ) begin
									epc_o <= current_inst_addr_i - 4 ;
									cause_o[31] <= 1'b1;
								end else begin
									epc_o <= current_inst_addr_i;
									cause_o[31] <= 1'b0;
									end
								end
							status_o[1] <= 1'b1;
							cause_o[6:2] <= 5'b01010;		//异常原因:指令未定义			
						end
						32'h0000000d:		begin		//自陷异常
							if(status_o[1] == 1'b0) begin
								if(is_in_delayslot_i == `InDelaySlot ) begin
									epc_o <= current_inst_addr_i - 4 ;
									cause_o[31] <= 1'b1;
								end else begin
									epc_o <= current_inst_addr_i;
									cause_o[31] <= 1'b0;
								end
							end
							status_o[1] <= 1'b1;
							cause_o[6:2] <= 5'b01101;		//异常原因:自陷指令			
						end
						32'h0000000c:		begin		//溢出异常
							if(status_o[1] == 1'b0) begin
								if(is_in_delayslot_i == `InDelaySlot ) begin
									epc_o <= current_inst_addr_i - 4 ;
									cause_o[31] <= 1'b1;
								end else begin
									epc_o <= current_inst_addr_i;
									cause_o[31] <= 1'b0;
								end
							end
							status_o[1] <= 1'b1;
							cause_o[6:2] <= 5'b01100;		//异常原因:整数溢出	
						end				
						32'h0000000e:   begin	//异常返回
							status_o[1] <= 1'b0;//不禁止中断
						end
						default:		begin
						end
					endcase			
			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

ctrl

`include "defines.v"
`timescale 1ns/1ps
module ctrl(

	input wire					 rst,
	//暂停请求
	input wire                   stallreq_from_id,
	input wire                   stallreq_from_ex,
	//来自MEM异常信息
	input wire[31:0]             excepttype_i,
	input wire[`RegBus]          cp0_epc_i,//异常返回eret时作异常处理例程入口地址。因为要返回异常发生前状态执行
	
	output reg[5:0]              stall,
	
	output reg                   flush,//清除信号
	output reg[`RegBus]          new_pc//异常入口地址
	
);


	always @ (*) begin
		if(rst == `RstEnable) begin
			stall <= 6'b000000;
			flush <= 1'b0;
			new_pc <= `ZeroWord;
		end else flush <= 1'b0;
				if(excepttype_i != `ZeroWord) begin  //异常信息不为0,发生异常
				flush <= 1'b1;
				stall <= 6'b000000;
				case (excepttype_i)
					32'h00000001:		begin   //interrupt中断
						new_pc <= 32'h00000020;
					end
					32'h00000008:		begin   //syscall系统调用
						new_pc <= 32'h00000040;
					end
					32'h0000000a:		begin   //inst_invalid指令无效
						new_pc <= 32'h00000040;
					end
					32'h0000000d:		begin   //trap自陷
						new_pc <= 32'h00000040;
					end
					32'h0000000c:		begin   //ov溢出
						new_pc <= 32'h00000040;
					end
					32'h0000000e:		begin   //eret异常返回
						new_pc <= cp0_epc_i;  //要返回异常发生前状态继续执行
					end
					default	: begin
					end
				endcase 		
			end else if(stallreq_from_ex == `Stop) begin
					stall <= 6'b001111;
				end else if(stallreq_from_id == `Stop) begin
						stall <= 6'b000111;			
					end else begin
							stall <= 6'b000000;
					end    //if
	end      //always
			

endmodule

inst_rom.v

`include "defines.v"
`timescale 1ns/1ps
module inst_rom(

//	input	wire						clk,
	input wire							ce,
	input wire[`InstAddrBus]			addr,
	output reg[`InstBus]				inst
	
);

	reg[`InstBus]  inst_mem[0:`InstMemNum-1];

	initial $readmemh ( "E:/ma/chap10/inst_rom_chap11_3.data", inst_mem );

	always @ (*) begin
		if (ce == `ChipDisable) begin
			inst <= `ZeroWord;
	  end else begin
		  inst <= inst_mem[addr[`InstMemNumLog2+1:2]];
		end
	end

endmodule

指令测试程序

系统调用

d4d3c290626e4452998fc133e0d3b894.png

自陷指令821b992023d948179de46ea37dc4c82a.png

 14f27ae2a5e04b41b5cebb53bfacbae8.png

 

中断

68bd944156e947d5b59b30b2048e7bf4.png

 

7.仿真波形

仿真波形我一共截了9张图,太多了,就放个书上的吧a1bce9cbba6a4a918e846a1bb6c31ac7.png

2f966b66b207498eae17f89f8f4d107e.png

12e282db1a2d4e859a4068fee94a0c16.png

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值