IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 【自己动手写CPU】异常相关指令的实现 -> 正文阅读

[嵌入式]【自己动手写CPU】异常相关指令的实现

MIPS架构中定义的异常类型

MIPS32架构中,有些事情打断程序的正常的执行流程,这些事情称为中断、陷阱、系统调用以及其他打断程序执行流程的情况,统称为异常
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

此处的OpenMIPS处理器只实现了其中6中异常情况的处理:

  • 硬件复位
  • 中断(软中断、硬中断)
  • syscall系统调用
  • 无效指令
  • 溢出
  • 自陷指令引发的异常
    异常发生后,进入异常处理例程进行具体处理,处理结束后,返回到异常发生前的状态继续执行。`硬件复位是一种特殊的异常,在于不用从异常处理例程返回,不需要保护现场,不用保存返回地址,此处的处理方法简单粗暴:全部寄存器清零,从地址0x0处取指执行,即复位。所以此处置详细论述其他5种异常的处理过程。

精确异常

当一个异常发生时,系统的顺序执行会被中断,此时,若干条指令处于流水线上的不同阶段,处理器会转到异常处理例程,异常处理结束后返回原程序继续执行。当异常发生时,因为不希望异常处理例程破坏原程序的正常执行,对于没有执行完的指令,必须记住它处于流水线的哪个阶段,以便异常处理结束后能恢复执行,这就是精确异常
当异常发生时,被异常打断的指令称为异常受害者,该指令前面的所有指令都要被执行到流水线的最后一个阶段,即正常完成。但是该指令及该指令之后的指令都要被取消。

for example

e.g.1

在这里插入图片描述

第二条指令add执行阶段发生溢出异常,在这种情况下,指令1ori指令会顺利完成,指令2,3,4都会被取消。为了实现精确异常,必须要求异常发生的顺序与指令的顺序相同。流水线处理器上,异常会在流水线的不同阶段发生,带来问题。

e.g.2

在这里插入图片描述

加载指令lw会在流水线的访存阶段发生地址未对齐的异常,该异常会在第个时钟周期发生,后一条指令di是无效指令mips32架构并没有这条指令,所以是无效的,在流水线阶段引发无效指令异常,也就是第个周期,此时上一条加载指令lw还处于执行阶段,没有进入访存阶段,所以先发生的异常是无效指令异常。从而不满足异常发生的顺序与指令的顺序相同这一要求。

为了避免上述情况,先发生的异常并不立即处理异常事件只是被标记,并继续运行流水线,大多数处理器中,会设计一个特殊的流水线阶段专门用于处理异常,如果某一条指令的异常事件达到流水线的这个阶段,就会被进行异常处理,并且当前处于流水线其余阶段的指令的异常事件都会被忽略

以上图为例,假设处理器会在访存阶段处理异常情况,那么di指令虽然在第三个周期发生异常,但并不处理,只是一个保存一个异常标记,等到了第五个时钟周期该指令进入访存阶段时再处理。但是在第四个时钟周期上一条指令lw进入访存阶段,并发生地址未对齐异常,因为已经处于访存阶段,所以会处理该异常,包括无效指令异常在内的流水线其余阶段的异常都被忽略

通过上述方法,实现在流水线处理器中实现按指令执行的顺序处理异常,而不是按异常发生的顺序处理异常处理

异常处理过程

  • 步骤一

EXL为1,表示当前已经处于异常处理过程,如果当前发生的异常类型是中断,那么不处理,忽略,因为异常处理过程中会禁止中断。如果当前发生的异常类型不是中断,那么将异常原因保存到CP0中的Cause寄存器的ExCode字段
如果EXL为0,那么将异常原因保存到CP0中的Cause寄存器的ExCode字段,进入步骤二

  • 步骤二

检查发生异常的指令是否在延迟槽中如果在延迟槽中,那么设置EPC寄存器的值为该指令的地址减4,同时设置Cause寄存器的BD字段为1,反之,设置EPC寄存器的值就位该指令的地址,同时设置Cause寄存器的BD字段为0

  • 步骤三

设置Status寄存器EXL字段为1,表示进入异常处理过程禁止中断

  • 步骤四

处理器转移到事先定义好的一个地址,在那个地址中往往有异常处理例程,在其中进行异常处理,这个地址称为异常处理例程入口地址OpenMIPS定义的异常处理例程入口地址表如下。此处对系统调用、无效指令、溢出、自陷这四类异常都设置为相同的处理例程入口地址,也可以设置为不同的地址。

在异常处理例程中会进行具体的异常处理,处理结束后,需要返回到异常发生前的状态继续执行。异常返回指令eret来完成此项工作,eret指令既要清除Status寄存器的EXL字段,从而使能中断,还要将EPC寄存器保存的地址恢复到PC中,从而返回到异常发生处继续执行

在这里插入图片描述

引延迟槽后,处理器执行转移指令的顺序:
转移指令->延迟槽指令->转移目标指令地址

流程图(我懒得画)

在这里插入图片描述

异常相关指令介绍

自陷指令

按照指令中是否包含立即数,分为2类

不包含立即数的自陷指令

31-2625-2120-1615-65-0useagefunction
SPECIAL(000000)rsrtcodeTEQ(110100)teq rs,rtif GPR[rs]=GPR[rt] then trap将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值比较,如果两者相等,发生自陷异常
SPECIAL(000000)rsrtcodeTGE(110000)tge rs,rtif GPR[rs] >= GPR[rt] then trap将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值作为有符号数比较,如果前者大于后者,那么引发自陷异常
SPECIAL(000000)rsrtcodeTGEU(110001)tgeu rs,rtif GPR[rs] >= GPR[rt] then trap将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值作为符号数比较,如果前者大于后者,那么引发自陷异常
SPECIAL(000000)rsrtcodeTLT(110010)tlt rs,rtif GPR[rs] < GPR[rt] then trap将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值作为有符号数比较,如果前者于后者,那么引发自陷异常
SPECIAL(000000)rsrtcodeTLTU(110011)tltu rs,rtif GPR[rs] >= GPR[rt] then trap将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值作无·符号数比较,如果前者于后者,那么引发自陷异常
SPECIAL(000000)rsrtcodeTNE(110110)tne rs,rtif GPR[rs] != GPR[rt] then trap将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值比较,如果两者不相等,那么引发自陷异常

包含立即数的自陷指令

31-2625-2120-1615-0useagefunction
REGIMM(000001)rsTEQI(01100)immediateteqi rs ,immediateif GPR[rs]=sign_extended(immediate) then trap 将地址为rs的通用寄存器的值与指令中16位立即数符号扩展至32位后的值比较,如果两者相等,那引发自陷异常
REGIMM(000001)rsTGEI(01000)immediatetgei rs ,immediateif GPR[rs]=sign>=extended(immediate) then trap 将地址为rs的通用寄存器的值与指令中16位立即数符号扩展至32位后的值比较,如果前者大于等于后者,那么引发自陷异常
REGIMM(000001)rsTGEIU(01001)immediatetgeiu rs ,immediateif GPR[rs]>=sign_extended(immediate) then trap 将地址为rs的通用寄存器的值与指令中16位立即数符号扩展至32位后的值作为无符号数进行比较,如果前者大于等于后者,那么引发自陷异常
REGIMM(000001)rsTLTI(01010)immediatetlti rs ,immediateif GPR[rs]<sign_extended(immediate) then trap 将地址为rs的通用寄存器的值与指令中16位立即数符号扩展至32位后的值作为有符号数进行比较,如果前者小于后者,那么引发自陷异常、REGIMM(000001)
REGIMM(000001)rsTNEI(01110)immediatetnei rs ,immediateif GPR[rs]!=sign_extended(immediate) then trap 将地址为rs的通用寄存器的值与指令中16位立即数符号扩展至32位后的值进行比较,如果两者不相等,那么引发自陷异常

异常返回指令eret

31-262524-65-0useagefunction
COP0(010000)CO(1)0000 0000 0000 0000 000ERET(011000)eret从异常处理例程返回,执行该指令(1)是EPC寄存器的值称为新的取指地址(2)设置Status寄存器的EXL字段为0,表示不再处于异常级

系统调用指令syscall

31-2625-65-0useagefunction
SPECIAL(000000)codeSYSCALL(001100)syscall引发系统调用异常。用户模式下的程序为了执行一些在内核模式下才能进行的操作,可以调用syscall指令,引发系统调用异常,进入异常处理例程,从而进入内核模式

实现思路

在流水线各个阶段手机异常信息,并传递到流水线访存阶段,在访存阶段同一处理异常信息。流水线各个阶段需要收集的异常信息:

译码

判断是否系统调用异常、是否返回指令、无效指令

执行

判断是否有自陷异常、溢出异常

访存

检查是否有中断发生。访存阶段,处理器结合CP0中相关寄存器的值,判断异常是否需要处理,如果需要处理,那么转移到该异常对应的处理例程入口地址,清除流水线上除回写阶段外的全部信息,同时修改协处理器CP0中相关寄存器的值。eret指令,转移到EPC寄存器保存的地址处,同时清除流水线上除回写阶段外的全部信息,修改协处理器CP0中相关寄存器的值。所谓清除流水线上某个阶段的信息,其实就是将该阶段中所有寄存器设置为初始值即可

数据流图的修改

在这里插入图片描述

确定自陷指令、syscall质量、eret指令的过程

id在这里插入图片描述

系统结构的修改

id

id模块判断是否调用指令syscall,异常返回指令eret,无效指令,将这些信息通过excepttype_o接口传递到ex模块,同时将指令地址通过current_inst_addr_o接口传递到执行阶段。

ex

ex模块进一步判断是否有自陷异常,或溢出异常。这些信息会融合到id模块的异常信息中,excepttype_i传入,通过excepttype_o传递到mem模块。同时current_inst_addr_o接口将指令地址传递到mem模块,通过is_delayslot_o指出指令是否位于延迟槽中,该信息也会传入mem模块。

mem

mem模块依据传递来的异常类型excepttype_iCause寄存器的值cp0_cause_iStatus寄存器的值cp0_status_i,综合判断是否需要处理异常,如果需要处理,最终的异常类型会跳过excepttype_o接口送入到CTRL模块,CTRL模块据此给出异常处理的入口地址new_pc传递到PC。

cp0_reg

处理异常时,需要修改CP0中的EPC,Status,Cause等寄存器的值,所以mem模块给出的最终的异常类型还要通过excepttype_o接口送入CP0模块,同时送入的异常指令是否在延迟槽中is_in_delayslot_i接口送入,发生异常指令的地址current_inst_address_o接口送入。CP0模块根据这些信息修改相应寄存器的值。

CTRL

如果要处理异常,需要清除流水线上除回写阶段外寄存器的值,CTRL模块通过送出flush实现。flush模块送到PC,IF/ID,ID/EX,EX/MEM,MEM/WB等模块,将这些模块中的寄存器置为初始值。

LLbit

ll执行时设置LLbit为1,sc执行时,检测该寄存器是否为1,如果为1就正常运行,如果为0,说明出现了干扰,不进行存储操作。出现干扰的原因之一就是ll,sc指令之间产生了异常,所以在异常处理过程中会多进行一步操作,将LLbit寄存器设置为0

代码

因为这是自己动手写cpu基础版的最后一章了,所以把完整的代码放上来。

pc_reg.v

`include "define.v"
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 (rst == `RstEnable) begin
			ce <= `ChipDisable;
		end else begin
			ce <= `ChipEnable;
		end
	end


	/*always @ (posedge clk) begin
		if (ce == `ChipDisable) begin
			pc <= 32'h00000000;
		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(ce == `ChipDisable)begin
		pc <= 32'h00000000;
	end else begin
		if(flush == 1'b1)begin
			//flush==1表示异常发生 将从CTRL模块给出的异常处理
			//例程入口地址 new_pc处取指执行
			pc <= new_pc;
		end else if(stall[0] == `NoStop)begin
			
			end 
		end 
	end 
end 
endmodule

inst_rom.v

`include "define.v"
//inst_rom.v
module inst_rom(
input wire ce,
input wire[`InstAddrBus] addr,
output reg[`InstBus] inst
);
//定义一个数组,大小是InstMemNum,元素宽度是InstBus
reg[`InstBus] inst_mem[0:`InstMemNum-1]; 
//使用文件inst_rom.data 初始化指令存储器
initial $readmemh ("D:/test_2/inst_rom_11_3.data",inst_mem);
always @ (*)
begin
if(ce == `ChipDisable)//当复位信号无效时,依据输入的地址,给出指令存储器ROM中对应的元素
begin
	inst <= `ZeroWord;
end
else begin
	inst <= inst_mem[addr[`InstMemNumLog2+1:2]];
end
end
endmodule

if_id.v

`include "define.v"
module if_id(

	input	wire										clk,
	input wire										rst,
	

	input wire[`InstAddrBus]			if_pc,
	input wire[`InstBus]          if_inst,
	input wire[5:0] stall, //来自控制模块的信息
	input wire flush,
	output reg[`InstAddrBus]      id_pc,
	output reg[`InstBus]          id_inst  
	
);
/**************************说明******************************
*****stall[0]表示取指地址PC是否保持不变,为1表示保持不变*****
*******stall[1]表示流水线取指阶段是否暂停,为1表示暂停*******
*******stall[2]表示流水线译码阶段是否暂停,为1表示暂停*******
*******stall[3]表示流水线执行阶段是否暂停,为1表示暂停*******
*******stall[4]表示流水线访存阶段是否暂停,为1表示暂停*******
*******stall[5]表示流水线回写阶段是否暂停,为1表示暂停*******
(1)stall[1]为Stop,stall[5]为NoStop,表示取指阶段暂停,译码阶段
继续,所以使用空指令作为下一个周期进入译码阶段的指令
(2)stall[1]为NoStop,取指阶段继续,取得的指令进入译码阶段
(3)其余情况下,保持译码阶段的寄存器id_pc,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 id_inst寄存器的值
			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

ctrl.v

//ctrl.v
`include "define.v"
module ctrl(
input wire rst,
input wire stallreq_from_id,
input wire stallreq_from_ex,
input wire[31:0] excepttype_i,
input wire[`RegBus] cp0_epc_i,
output reg[5:0] stall,
output reg[`RegBus] new_pc,
output reg flush
);
/**************************说明******************************
*****stall[0]表示取指地址PC是否保持不变,为1表示保持不变*****
*******stall[1]表示流水线取指阶段是否暂停,为1表示暂停*******
*******stall[2]表示流水线译码阶段是否暂停,为1表示暂停*******
*******stall[3]表示流水线执行阶段是否暂停,为1表示暂停*******
*******stall[4]表示流水线访存阶段是否暂停,为1表示暂停*******
*******stall[5]表示流水线回写阶段是否暂停,为1表示暂停*******
************************************************************/
always @ (*) begin
		if(rst == `RstEnable) begin
			stall <= 6'b000000;
			flush <= 1'b0;
			new_pc <= `ZeroWord;
		end else if(excepttype_i != `ZeroWord) begin
		  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;
			flush <= 1'b0;		
		end else if(stallreq_from_id == `Stop) begin
			stall <= 6'b000111;	
			flush <= 1'b0;		
		end else begin
			stall <= 6'b000000;
			flush <= 1'b0;
			new_pc <= `ZeroWord;		
		end    //if
	end      //always
			

endmodule

data_ram.v

`include "define.v"
module data_ram(
input wire clk,
input wire ce,//数据存储器使能信号
input wire we,//是否为写操作 写1 
input wire[`DataAddrBus] addr,//要访问的地址
input wire[3:0] sel,//字节选择信号
input wire[`DataBus] data_i,//要写入的数据
output reg[`DataBus] data_o//读出的数据
);


//定义四个字节数组
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
	end else if(we == `WriteEnable)begin
		if(sel[3] == 1'b1)begin
			data_mem3[addr[`DataMemNumLog2+1:2]] <= data_i[31:24];
		end 
		if(sel[2] == 1'b1)begin
			data_mem2[addr[`DataMemNumLog2+1:2]] <= data_i[23:16];
		end 
		if(sel[1] == 1'b1)begin
			data_mem1[addr[`DataMemNumLog2+1:2]] <= data_i[15:8];
		end 
		if(sel[0 == 1'b1])begin
			data_mem0[addr[`DataMemNumLog2+1:2]] <= data_i[7:0];
		end
	end 
end 

//读操作
always @ (*) begin
	if(ce == `ChipDisable)begin
		data_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

define.v

//全局
`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 InterruputAssert 1'b1
`define InterruputNotAssert 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       //只读

div.v

`include "define.v"
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

id.v

`include "define.v"
module id(

	input wire										rst,
	input wire[`InstAddrBus]			pc_i,
	input wire[`InstBus]          inst_i,

	input wire[`RegBus]           reg1_data_i,
	input wire[`RegBus]           reg2_data_i,
	input wire is_in_delayslot_i,//是否位于延迟槽指令

	//送到regfile的信息
	output reg                    reg1_read_o,
	output reg                    reg2_read_o,     
	output reg[`RegAddrBus]       reg1_addr_o,
	output reg[`RegAddrBus]       reg2_addr_o, 	      
	
	//送到执行阶段的信息
	output reg[`AluOpBus]         aluop_o,
	output reg[`AluSelBus]        alusel_o,
	output reg[`RegBus]           reg1_o,
	output reg[`RegBus]           reg2_o,
	output reg[`RegAddrBus]       wd_o,
	output reg                    wreg_o,
	
	
	//处于执行阶段的指令的运算结果
	input wire ex_wreg_i,
  input wire[`RegBus] ex_wdata_i,
	input wire[`RegAddrBus] ex_wd_i,
	input wire[`AluOpBus] ex_aluop_i,
	//处于访存阶段的指令的运算结果
	input wire mem_wreg_i,
	input wire[`RegBus] mem_wdata_i,
	input wire[`RegAddrBus] mem_wd_i,
	output wire stallreq,
	output reg next_inst_in_delayslot_o,//下条指令是否是延迟槽
	
	output reg branch_flag_o,//是否发生转移
	output reg[`RegBus] branch_target_address_o,//转移到的目标地址
	output reg[`RegBus] link_addr_o,//转移指令要保存的返回地址
	output reg is_in_delayslot_o,//当前处于译码指令是否位于延迟槽
	output wire[`RegBus] inst_o ,//新增加的输出接口
	//input wire[`AluOpBus] ex_aluop_i,
	//output wire stallreq
	output wire[31:0] excepttype_o,//收集的异常信息
	output wire[`RegBus] current_inst_address_o//译码阶段指令的地址
);

  wire[5:0] op = inst_i[31:26];
  wire[4:0] op2 = inst_i[10:6];
  wire[5:0] op3 = inst_i[5:0];
  wire[4:0] op4 = inst_i[20:16];
  
  wire[`RegBus] pc_plus_8;//保存当前译码阶段指令后面第二条指令的地址
  wire[`RegBus] pc_plus_4;//保存当前译码阶段指令后面紧接着的指令地址
  
  wire[`RegBus] imm_sll2_signedext;//对应分支指令中offset左移两位,再符号扩展至32位的值
  
  
  reg[`RegBus]	imm;
  reg instvalid;
  reg excepttype_is_syscall;//是否是系统调用异常syscall
  reg excepttype_is_eret;//是否是异常返回指令
  
  /*excepttype_o的低八位留给外部中断,第八位表示是否是syscall指令引起的
  系统调用异常,第九位表示是否是无效指令引起的异常,第十二位表示是否是eret指令
  eret指令可以认为是一种特殊的异常--返回异常*/
  assign excepttype_o = {19'b0,excepttype_is_eret,2'b0,instvalid,excepttype_is_syscall,8'b0};
  //输入信号pc_i就是当前处于译码阶段指令的地址
  assign current_inst_address_o = pc_i;
  
  assign stallreq = `NoStop;//在实现加载、存储指令时会给该信号赋值
  
  assign imm_sll2_signedext = {{14{inst_i[15]}},inst_i[15:0],2'b00};
  //imm_sll2_signedext对应分支指令中的offset左移两位,再符号扩展至32位的值
  
 assign pc_plus_8 = pc_i+8;
 assign pc_plus_4 = pc_i+4;
 
 assign stallreq = `NoStop;
 assign inst_o = inst_i;//译码阶段的指令
 //新定义一个变量 表示要读取的寄存器1是否与上一条指令存在load相关
 reg stallreq_for_reg1_loadrelate;
 //新定义一个变量 表示要读取的寄存器2是否与上一条指令存在load相关
 reg stallreq_for_reg2_loadrelate;
 //新定义一个变量 表示上一条指令是否是加载指令
 wire pre_inst_is_load;
 //依据输入信号ex_aluop_i值 判断上一条指令是否是加载指令
 //如果是加载指令 那么置pre_inst_is_load为1 反之置0
 assign pre_inst_is_load = ((ex_aluop_i == `EXE_LB_OP)||
(ex_aluop_i == `EXE_LBU_OP)||
(ex_aluop_i == `EXE_LH_OP)||
(ex_aluop_i==`EXE_LHU)||
(ex_aluop_i==`EXE_LW_OP)||
 (ex_aluop_i==`EXE_LWR_OP)||
 (ex_aluop_i==`EXE_LWL_OP)||
 (ex_aluop_i==`EXE_LL_OP)||
 (ex_aluop_i==`EXE_SC_OP)) ? 1'b1 : 1'b0;
 /*如果上一条指令是加载指令 且该加载指令要加载到目的寄存器就是当前指令
 要通过Regfile模块读取端口1读取的通用寄存器,那么表示存在load相关*/
 //设置stallreq_for_reg1_loadrelate为Stop
 always @(*)begin
 	stallreq_for_reg1_loadrelate <= `NoStop;
 	if(rst == `RstEnable)begin
 		reg1_o <= `ZeroWord;
 	end else if(pre_inst_is_load == 1'b1 && ex_wd_i == reg1_addr_o && reg1_read_o == 1'b1)begin
 		stallreq_for_reg1_loadrelate <= `Stop;//存在load相关 Stop
 	end  
end 
//reg2与reg1同理
always @(*)begin
 	stallreq_for_reg2_loadrelate <= `NoStop;
 	if(rst == `RstEnable)begin
 		reg2_o <= `ZeroWord;
 	end else if(pre_inst_is_load == 1'b1 && ex_wd_i == reg2_addr_o && reg2_read_o == 1'b1)begin
 		stallreq_for_reg2_loadrelate <= `Stop;//存在load相关 Stop
 	end  
end 
assign stallreq = stallreq_for_reg1_loadrelate | stallreq_for_reg2_loadrelate;
	always @ (*) begin	
		if (rst == `RstEnable) begin
			aluop_o <= `EXE_NOP_OP;
			alusel_o <= `EXE_RES_NOP;//nop
			wd_o <= `NOPRegAddr;
			wreg_o <= `WriteDisable;
			instvalid <= `InstValid;
			reg1_read_o <= 1'b0;
			reg2_read_o <= 1'b0;
			reg1_addr_o <= `NOPRegAddr;
			reg2_addr_o <= `NOPRegAddr;
			imm <= 32'h0;		
			link_addr_o <= `ZeroWord;//转移指令要保存的返回地址
			branch_target_address_o <= `ZeroWord;//转移到的目标地址
			branch_flag_o <= `NotBranch;//不发生转移
			next_inst_in_delayslot_o <= `NotInDelaySlot;//下一条指令是否位于延迟槽	
	  end else begin //先初始化
			aluop_o <= `EXE_NOP_OP;
			alusel_o <= `EXE_RES_NOP;
			wd_o <= inst_i[15:11];
			wreg_o <= `WriteDisable;
			instvalid <= `InstInvalid;	   
			reg1_read_o <= 1'b0;
			reg2_read_o <= 1'b0;
			reg1_addr_o <= inst_i[25:21];//rs
			reg2_addr_o <= inst_i[20:16];//rt
			imm <= `ZeroWord;		
			link_addr_o <= `ZeroWord;
			branch_target_address_o <= `ZeroWord;
			branch_flag_o <= `NotBranch;
			next_inst_in_delayslot_o <= `NotInDelaySlot; 	
			excepttype_is_syscall <= `False_v;//默认没有系统调用异常
			excepttype_is_eret <= `False_v;//默认不是eret指令
			instvalid <= `InstInvalid;//默认无效指令
		case (op)//指令码
		  	`EXE_SPECIAL_INST: begin //指令码是SPECIAL
		  		case(op2)//功能码
		  			5'b00000: begin
		  				case(op3) //依据功能码判断是哪一个指令
								`EXE_OR: begin //or R型指令 rs|rt -> rd
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_OR_OP;
									alusel_o <= `EXE_RES_LOGIC;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_AND:begin
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_AND_OP;//R rs&rt ->rd
									alusel_o <=  `EXE_RES_LOGIC;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_XOR:begin
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_XOR_OP;// R rs^rt ->rd
									alusel_o <= `EXE_RES_LOGIC;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_NOR:begin
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_NOR_OP;// R rs~|rt ->rd
									alusel_o <= `EXE_RES_LOGIC;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_SLLV:begin
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_SLL_OP; 
									alusel_o <= `EXE_RES_SHIFT;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_SRLV:begin
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_SRLV_OP;
									alusel_o <= `EXE_RES_SHIFT;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_SRAV:begin
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_SRAV_OP;
									alusel_o <= `EXE_RES_SHIFT;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_SYNC:begin
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_NOP_OP;
									alusel_o <= `EXE_RES_NOP;
									reg1_read_o <= 1'b0;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_MFHI:begin//将特殊寄存器hi的值赋给地址为rd的寄存器
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_MFHI_OP;
									alusel_o <= `EXE_RES_MOVE;
									reg1_read_o <= 1'b0;
									reg2_read_o <= 1'b0;
									instvalid <= `InstValid;
								end
								`EXE_MFLO:begin
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_MFLO_OP;
									alusel_o <= `EXE_RES_MOVE;
									reg1_read_o <= 1'b0;
									reg2_read_o <= 1'b0;
									instvalid <= `InstValid;
								end
								`EXE_MTHI:begin//hi<-rs 写特殊寄存器
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_MTHI_OP;
									alusel_o <= `EXE_RES_MOVE;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b0;
									instvalid <= `InstValid;
								end
								`EXE_MTLO:begin //lo<-rs 写特殊寄存器
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_MTLO_OP;
									reg1_read_o <= 1'b1;//rs
									reg2_read_o <= 1'b0;
									instvalid <= `InstValid;
								end
								`EXE_MOVN:begin//判断rt寄存器的值 如果不为0 将rs的值赋给rd 反之rd值不变
									//wreg_o <= `WriteEnable;
									aluop_o <= `EXE_MOVN_OP;
									alusel_o <= `EXE_RES_MOVE;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
									//reg2_o的值就是地址为rt的寄存器的值
									if(reg2_o != `ZeroWord)begin
									wreg_o <= `WriteEnable;
									end else begin
									wreg_o <= `WriteDisable;
									end
								end
								`EXE_MOVZ:begin //判断rt寄存器的值 如果是0 将rs的值赋给rd 反之rd值不变
									aluop_o <= `EXE_MOVZ_OP;
									alusel_o <= `EXE_RES_MOVE;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
									if(reg2_o == `ZeroWord)begin
									wreg_o <= `WriteEnable;
									end else begin
									wreg_o <= `WriteDisable;
									end 
								end
								`EXE_SLT:begin//slt指令 rd<-(rs<rt)
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_SLT_OP;
									alusel_o <= `EXE_RES_ARITHMETIC;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_SLTU:begin //sltu指令
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_SLTU_OP;
									alusel_o <= `EXE_RES_ARITHMETIC;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_ADD:begin//rd<-rs+rt
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_ADD_OP;
									alusel_o <= `EXE_RES_ARITHMETIC;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_ADDU:begin
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_ADDU_OP;
									alusel_o <= `EXE_RES_ARITHMETIC;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_SUB:begin
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_SUB_OP;
									alusel_o <= `EXE_RES_ARITHMETIC;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_SUBU:begin
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_SUBU_OP;
									alusel_o <= `EXE_RES_ARITHMETIC;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_MULT:begin
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_MULT_OP;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_MULTU:begin
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_MULTU_OP;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end 	
								`EXE_DIV:begin
									wreg_o <= `WriteDisable;
									aluop_o <= `EXE_DIV_OP;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_DIVU:begin
									wreg_o <= `WriteDisable;
									aluop_o <= `EXE_DIVU_OP;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b1;
									instvalid <= `InstValid;
								end
								`EXE_JR:begin
									wreg_o <= `WriteDisable;
									aluop_o <= `EXE_JR_OP;
									alusel_o <= `EXE_RES_JUMP_BRANCH;
									reg1_read_o <= 1'b1;//rs寄存器需要被使用
									reg2_read_o <= 1'b0;
									wd_o <= inst_i[15:11];
									link_addr_o <= pc_plus_8;//返回地址
									branch_target_address_o <= reg1_o;//转移到的目标地址
									branch_flag_o <= `Branch;//是否发生转移
									next_inst_in_delayslot_o <= `InDelaySlot;//下一条指令不位于延迟槽
									instvalid <= `InstValid;
								end
								`EXE_JALR:begin
									wreg_o <= `WriteEnable;
									aluop_o <= `EXE_JALR_OP;
									alusel_o <= `EXE_RES_JUMP_BRANCH;
									reg1_read_o <= 1'b1;
									reg2_read_o <= 1'b0;
									wd_o <= inst_i[15:11];
									link_addr_o <= pc_plus_8;
									branch_target_address_o <= reg1_o;
									branch_flag_o <= `Branch;
									next_inst_in_delayslot_o <= `InDelaySlot;
									instvalid <= `InstValid;
								end
								`EXE_TEQ:begin//teq
									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;
								end 
								`EXE_TGE:begin//tge
									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//tgeu
									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//tlt
									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//tltu
									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//tne
									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//syscall
									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
								
								
								
		  					default:begin
									//aluop_o <= `EXE_NOP_OP;
									//alusel_o <= `EXE_RES_OP;
									//wd_o <= `NOPRegAddr;
									//wreg_o <= `WriteDisable;
									//instvalid <= `InstValid;
									//reg1_read_o <= `ReadDisable;
									//reg2_read_o <= `ReadDisable;
									//reg1_addr_o <= inst_i[25:21];
									//reg2_addr_o <= inst_i[20:16];
		  					end
		  				endcase//op3
		  			end	// 5'b00000
					`EXE_J:begin
						wreg_o <= `WriteDisable;//译码阶段是否要写入目的寄存器
						aluop_o <= `EXE_J_OP;
						alusel_o <= `EXE_RES_JUMP_BRANCH;
						reg1_read_o <= 1'b0;
						reg2_read_o <= 1'b0;
						link_addr_o <= `ZeroWord;
						branch_flag_o <= `Branch;
						next_inst_in_delayslot_o <= `InDelaySlot;
						instvalid <= `InstValid;
						branch_target_address_o <= {pc_plus_4[31:28],inst_i[25:0],2'b00};//转移目的的地址
					end
					`EXE_JAL:begin
						wreg_o <= `WriteEnable;
						aluop_o <= `EXE_JAL_OP;
						alusel_o <= `EXE_RES_JUMP_BRANCH;
						reg1_read_o <= 1'b0;
						reg2_read_o <= 1'b0;
						wd_o <= 5'b11111;//要写入的目的寄存器的地址 寄存器$1
						link_addr_o <= pc_plus_8;//转移指令要保存的返回地址
						branch_flag_o <= `Branch;//转移发生的标志
						next_inst_in_delayslot_o <= `InDelaySlot;
						instvalid <= `InstValid;
						branch_target_address_o <= {pc_plus_4[31:28],inst_i[25:0],2'b00};
					end
					`EXE_BEQ:begin
						wreg_o <= `WriteDisable;
						aluop_o <= `EXE_BEQ_OP;
						alusel_o <= `EXE_RES_JUMP_BRANCH;
						reg1_read_o <= 1'b1;//需要比较rs与rt 
						reg2_read_o <= 1'b1;
						instvalid <= `InstValid;
						if(reg1_o == reg2_o)begin //如果rs的值reg1_o与rd的值reg2_o相等 发生转移
							branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
							branch_flag_o <= `Branch;
							next_inst_in_delayslot_o <= `InDelaySlot;
						end
					end
					`EXE_BGTZ:begin
						wreg_o <= `WriteDisable;
						aluop_o <= `EXE_BGTZ_OP;
						alusel_o <= `EXE_RES_JUMP_BRANCH;
						reg1_read_o <= 1'b1;//rs
						reg2_read_o <= 1'b0;
						instvalid <= `InstValid;
						if((reg1_o[31] == 1'b0)&&(reg1_o != `ZeroWord))begin
							branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
							branch_flag_o <= `Branch;
							next_inst_in_delayslot_o <= `InDelaySlot;
						end
					end
					`EXE_BLEZ:begin
						wreg_o <= `WriteDisable;//译码阶段是否要写入目的寄存器
						aluop_o <= `EXE_BLEZ_OP;
						alusel_o <= `EXE_RES_JUMP_BRANCH;
						reg1_read_o <= 1'b1;
						reg2_read_o <= 1'b0;
						instvalid <= `InstValid;
						if((reg1_o[31] == 1'b1)&&(reg1_o != `ZeroWord))begin
							branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
							branch_flag_o <= `Branch;
							next_inst_in_delayslot_o <= `InDelaySlot;
						end
					end
					`EXE_BNE:begin
						wreg_o <= `WriteDisable;
						aluop_o <= `EXE_BNE_OP;
						alusel_o <= `EXE_RES_JUMP_BRANCH;
						reg1_read_o <= 1'b1;
						reg2_read_o <= 1'b1;
						instvalid <= `InstValid;
						if(reg1_o != reg2_o)begin
							branch_target_address_o <= pc_plus_4+imm_sll2_signedext;
							branch_flag_o <= `Branch;
							next_inst_in_delayslot_o <= `InDelaySlot;
						end
					end
					`EXE_REGIMM_INST:begin
						case(op4)
							`EXE_BLTZAL:begin//bltzal
								wreg_o <= `WriteEnable;
								aluop_o <= `EXE_BGEZAL_OP;
								alusel_o <= `EXE_RES_JUMP_BRANCH;
								reg1_read_o <= 1'b1;
								reg2_read_o <= 1'b0;
								link_addr_o <= pc_plus_8;
								wd_o <= 5'b11111;
								instvalid <= `InstValid;
								if(reg1_o[31] == 1'b1) begin//reg1_o<0
									branch_target_address_o <= pc_plus_4+imm_sll2_signedext;
									branch_flag_o <= `Branch;
									next_inst_in_delayslot_o <= `InDelaySlot;
								end
							end
							`EXE_BLTZ:begin//bltz
								wreg_o <= `WriteDisable;
								aluop_o <= `EXE_BGEZAL_OP;
								alusel_o <= `EXE_RES_JUMP_BRANCH;
								reg1_read_o <= 1'b1;
								reg2_read_o <= 1'b0;
								instvalid <= `InstValid;
								if(reg1_o[31] == 1'b1)begin
									branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
									branch_flag_o <= `Branch;
									next_inst_in_delayslot_o <= `InDelaySlot;
								end
							end
							`EXE_BGEZ:begin//bgez
								wreg_o <= `WriteDisable;
								aluop_o <= `EXE_BGEZ_OP;
								alusel_o <= `EXE_RES_JUMP_BRANCH;
								reg1_read_o <= 1'b1;
								reg2_read_o <= 1'b0;
								instvalid <= `InstValid;
								if(reg1_o[31] == 1'b0)begin//rs的值大于等于0
									branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
									branch_flag_o <= `Branch;
									next_inst_in_delayslot_o <= `InDelaySlot;
								end
							end
							`EXE_BGEZAL:begin//bgezal
								wreg_o <= `WriteEnable;
								aluop_o <= `EXE_BGEZAL_OP;
								alusel_o <= `EXE_RES_JUMP_BRANCH;
								reg1_read_o <= 1'b1;
								reg2_read_o <= 1'b0;
								link_addr_o <= pc_plus_8;
								wd_o <= 5'b11111;
								instvalid <= `InstValid;
								if(reg1_o[31] == 1'b0)begin
									branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
									branch_flag_o <= `Branch;
									next_inst_in_delayslot_o <= `InDelaySlot;
								end
							end
							//将地址为rs的通用寄存器的值与指令中16位立即数符号扩展至32位后的值比较,如果两者相等,那引发自陷异常
							`EXE_TEQI:begin //teqi 
								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 //tegi 
								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 //teqi 
								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 //teqi 
								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 //teqi 
								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 //teqi 
								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		// op2	
			end	
		  	`EXE_ORI:begin                        //ORI指令
		  		wreg_o <= `WriteEnable;		
		  		aluop_o <= `EXE_OR_OP;
		  		alusel_o <= `EXE_RES_LOGIC; 
		  		reg1_read_o <= 1'b1;
		  		reg2_read_o <= 1'b0;	  	
					imm <= {16'h0, inst_i[15:0]};	//立即数0扩展
					wd_o <= inst_i[20:16]; // 读取rt地址
					instvalid <= `InstValid;	
		  	end 
		  	`EXE_ANDI:begin //andi
		  		wreg_o <= `WriteEnable;
		  		aluop_o <= `EXE_AND_OP;
		  		alusel_o <= `EXE_RES_LOGIC;
		  		reg1_read_o <= 1'b1;
		  		reg2_read_o <= 1'b0;
		  		imm <= {16'h0,inst_i[15:0]};
		  		wd_o <= inst_i[20:16];//rt
		  		instvalid = `InstValid;
		  	end
		  	`EXE_XORI:begin//xori
		  		wreg_o <= `WriteEnable;
		  		aluop_o <= `EXE_XOR_OP;
		  		alusel_o <= `EXE_RES_LOGIC;
		  		reg1_read_o <= 1'b1;
		  		reg2_read_o <= 1'b0;
		  		imm <= {16'h0,inst_i[15:0]};
		  		wd_o <= inst_i[20:16];
		  		instvalid = `InstValid;		
		  	end
		  	`EXE_LUI:begin//lui
		  		wreg_o <= `WriteEnable;//注意书上的打印错误 无语了
		  		aluop_o <= `EXE_OR_OP;
		  		alusel_o <= `EXE_RES_LOGIC;
		  		reg1_read_o <= 1'b1;
		  		reg2_read_o <= 1'b0;
		  		imm <= {inst_i[15:0],16'h0};	
		  		wd_o <= inst_i[20:16];
		  		instvalid <= `InstValid;
		  	end
		  	/*`EXE_PREF:	begin//pref
		  		wreg_o <= `WriteDisable;
		  		aluop_o <= `EXE_NOP_OP;
		  		alusel_o <= `EXE_RES_NOP;
		  		reg1_read_o <= 1'b0;
		  		reg2_read_o <= 1'b0;
		  		instvalid <= 	`InstValid;
		  	end	*/	
		  	`EXE_SLTI:begin //slti   rt <- (rs < (sign_extended)immediate)
		  		wreg_o <= `WriteEnable;
		  		aluop_o <= `EXE_SLT_OP;
		  		alusel_o <= `EXE_RES_ARITHMETIC;
		  		reg1_read_o <= 1'b1;
		  		reg2_read_o <= 1'b0;
		  		imm <= {{16{inst_i[15]}},inst_i[15:0]};
		  		wd_o <= inst_i[20:16];
		  		instvalid <= `InstValid;
		  	end
		  	`EXE_SLTIU:begin
		  		wreg_o <= `WriteEnable;
		  		aluop_o <= `EXE_SLTU_OP;
		  		alusel_o <= `EXE_RES_ARITHMETIC;
		  		reg1_read_o <= 1'b1;
		  		reg2_read_o <= 1'b0;
		  		imm <= {{16{inst_i[15]}},inst_i[15:0]};
		  		wd_o <= inst_i[20:16];
		  		instvalid <= `InstValid;
		  	end
		  	`EXE_ADDI:begin
		  		wreg_o <= `WriteEnable;
		  		aluop_o <= `EXE_ADDI_OP;
		  		alusel_o <= `EXE_RES_ARITHMETIC;
		  		reg1_read_o <= 1'b1;
		  		reg2_read_o <= 1'b0;
		  		imm <= {{16{inst_i[15]}},inst_i[15:0]};
		  		wd_o <= inst_i[20:16];
		  		instvalid <= `InstValid;
		  	end
		  	`EXE_ADDIU:begin
		  		wreg_o <= `WriteEnable;
		  		aluop_o <= `EXE_ADDIU_OP;
		  		alusel_o <= `EXE_RES_ARITHMETIC;
		  		reg1_read_o <= 1'b1;
		  		reg2_read_o <= 1'b0;
		  		imm <= {{16{inst_i[15]}},inst_i[15:0]};
		  		wd_o <= inst_i[20:16];
		  		instvalid <= `InstValid;
		  	end		
		  	`EXE_LB:begin//将加载结果写入目的寄存器
		  		wreg_o <= `WriteEnable;
		  		aluop_o <= `EXE_LB_OP;
		  		alusel_o <= `EXE_RES_LOAD_STORE;
		  		reg1_read_o <= 1'b1;//计算加载目标地址需要使用地址为base的寄存器值
		  		reg2_read_o <= 1'b0;
		  		wd_o <= inst_i[20:16];//目的寄存器地址
		  		instvalid <= `InstValid;
		  	end
		  	`EXE_LBU:begin
		  		wreg_o <= `WriteEnable;
		  		aluop_o <= `EXE_LBU_OP;
		  		alusel_o <= `EXE_RES_LOAD_STORE;
		  		reg1_read_o <= 1'b1;
		  		reg2_read_o <= 1'b0;
		  		wd_o <= inst_i[20:16];
		  		instvalid <= `InstValid;
		  	end
		  	`EXE_LH:begin
		  		wreg_o <= `WriteEnable;
		  		aluop_o <= `EXE_LH_OP;
		  		alusel_o <= `EXE_RES_LOAD_STORE;
		  		reg1_read_o <= 1'b1;
		  		reg2_read_o <= 1'b0;
		  		wd_o <= inst_i[20:16];
		  		instvalid <= `InstValid;
		  	end
		  	`EXE_LHU:begin
		  		wreg_o <= `WriteEnable;
		  		aluop_o <= `EXE_LHU_OP;
		  		alusel_o <= `EXE_RES_LOAD_STORE;
		  		reg1_read_o <= 1'b1;
		  		reg2_read_o <= 1'b0;
		  		wd_o <= inst_i[20:16];
		  		instvalid <= `InstValid;
		  	end
		  	`EXE_LW:begin
		  		wreg_o <= `WriteEnable;
		  		aluop_o <= `EXE_LW_OP;
		  		alusel_o <= `EXE_RES_LOAD_STORE;
		  		reg1_read_o <= 1'b1;
		  		reg2_read_o <= 1'b0;
		  		wd_o <= inst_i[20:16];
		  		instvalid <= `InstValid;
		  	end
		  	`EXE_LWL:begin//向左加载 加载结果需要写入目的寄存器 [20:16]
		  		wreg_o <= `WriteEnable;
		  		aluop_o <= `EXE_LWL_OP;
		  		alusel_o <= `EXE_RES_LOAD_STORE;
		  		reg1_read_o <= 1'b1;
		  		reg2_read_o <= 1'b1;
		  		wd_o <= inst_i[20:16];
		  		instvalid <= `InstValid;
		  	end
		  	`EXE_LWR:begin//向右加载
		  		wreg_o <= `WriteEnable;
		  		aluop_o <= `EXE_LWR_OP;
		  		alusel_o <= `EXE_RES_LOAD_STORE;
		  		reg1_read_o <= 1'b1;
		  		reg2_read_o <= 1'b1;
		  		wd_o <= inst_i[20:16];
		  		instvalid <= `InstValid;
		  	end
		  	`EXE_SB:begin //不需要写通用寄存器 计算存储目标地址需要使用的地址为base的寄存器的值
		  		wreg_o <= `WriteDisable;
		  		aluop_o <= `EXE_SB_OP;
		  		reg1_read_o <= 1'b1; //[25:21] reg1_addr_o ======> base
		  		reg2_read_o <= 1'b1;
		  		instvalid <= `InstValid;
		  		alusel_o <= `EXE_RES_LOAD_STORE;
		  	end
		  	`EXE_SH:begin
		  		wreg_o <= `WriteDisable;
		  		aluop_o <= `EXE_SH_OP;
		  		reg1_read_o <= 1'b1;
		  		reg2_read_o <= 1'b1;
		  		instvalid <= `InstValid;
		  		alusel_o <= `EXE_RES_LOAD_STORE;
		  	end
		  	`EXE_SW:begin
		  		wreg_o <= `WriteDisable;
		  		aluop_o <= `EXE_SW_OP;
		  		reg1_read_o <= 1'b1;
		  		reg2_read_o <= 1'b1;
		  		instvalid <= `InstValid;
		  		alusel_o <= `EXE_RES_LOAD_STORE;
		  	end
		  	`EXE_SWL:begin
		  		wreg_o <= `WriteDisable;
		  		aluop_o <= `EXE_SWL_OP;
		  		reg1_read_o <= 1'b1;
		  		reg2_read_o <= 1'b1;
		  		instvalid <= `InstValid;
		  		alusel_o <= `EXE_RES_LOAD_STORE;
		  	end
		  	`EXE_SWR:begin
		  		wreg_o <= `WriteDisable;
		  		aluop_o <= `EXE_SWR_OP;
		  		reg1_read_o <= 1'b1;
		  		reg2_read_o <= 1'b1;
		  		instvalid <= `InstValid;
		  		alusel_o <= `EXE_RES_LOAD_STORE;
		  	end
		  	`EXE_LL:begin
		  		wreg_o <= `WriteEnable;
		  		aluop_o <= `EXE_LL_OP;
		  		alusel_o <= `EXE_RES_LOAD_STORE;
		  		reg1_read_o <= 1'b1;
		  		reg2_read_o <= 1'b0;
		  		wd_o <= inst_i[20:16];
		  		instvalid <= `InstValid;
		  	end 
		  	`EXE_SC:begin
		  		wreg_o <= `WriteEnable;
		  		aluop_o <= `EXE_SC_OP;
		  		alusel_o <= `EXE_RES_LOAD_STORE;
		  		reg1_read_o <= 1'b1;
		  		reg2_read_o <= 1'b1;
		  		wd_o <= inst_i[20:16];
		  		instvalid <= `InstValid;
		  	end 
		  	`EXE_SPECIAL2_INST:begin//(op)
				case(op3)
					`EXE_CLZ:begin
		  				wreg_o <= `WriteEnable;
		  				aluop_o <= `EXE_CLZ_OP;
		  				alusel_o <= `EXE_RES_ARITHMETIC;
		  				reg1_read_o <= 1'b1;
		  				reg2_read_o <= 1'b0;
		  				instvalid <= `InstValid;
		  			end
					`EXE_CLO:begin
		  				wreg_o <= `WriteEnable;
		  				aluop_o <= `EXE_CLO_OP;
		  				alusel_o <= `EXE_RES_ARITHMETIC;
		  				reg1_read_o <= 1'b1;
		  				reg2_read_o <= 1'b0;
		  				instvalid <= `InstValid;
		  			end
					`EXE_MUL:begin
		  				wreg_o <= `WriteEnable;
		  				aluop_o <= `EXE_MUL_OP;
		  				alusel_o <= `EXE_RES_MUL;
		  				reg1_read_o <= 1'b1;
		  				reg2_read_o <= 1'b1;
		  				instvalid <= `InstValid;
		  			end
					`EXE_MADD:begin 
		  				wreg_o <= `WriteDisable;
		  				aluop_o <= `EXE_MADD_OP;
		  				alusel_o <= `EXE_RES_MUL;
		  				reg1_read_o <= 1'b1;
		  				reg2_read_o <= 1'b1;
		  				instvalid <= `InstValid;
		  			end
					`EXE_MADDU:begin
		  				wreg_o <= `WriteDisable;
		  				aluop_o <= `EXE_MADDU_OP;
		  			  alusel_o <= `EXE_RES_MUL;
		  				reg1_read_o <= 1'b1;
		  				reg2_read_o <= 1'b1;
		  				instvalid <= `InstValid;
		  			end
					`EXE_MSUB:begin
		  				wreg_o <= `WriteDisable;
		  				aluop_o <= `EXE_MSUB_OP;
		  				alusel_o <= `EXE_RES_MUL;
		  				reg1_read_o <= 1'b1;
		  				reg2_read_o <= 1'b1;
		  				instvalid <= `InstValid;
		  			end
					`EXE_MSUBU:begin
		  				wreg_o <= `WriteDisable;
		  				aluop_o <= `EXE_MSUBU_OP;
		  				alusel_o <= `EXE_RES_MUL;
		  				reg1_read_o <= 1'b1;
		  				reg2_read_o <= 1'b1;
		  				instvalid <= `InstValid;
		  			end
					default:begin
					 end
				endcase //EXE_SPECIAL_INST2 case
			end				 
		    default:begin
		    end
		endcase		  //case op	
		if(inst_i == `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 	
		if(inst_i[31:21] == 11'b00000000000)begin //sll,srl,sra
		  	if(op3 == `EXE_SLL) begin
		  		wreg_o <= `WriteEnable;
		  		aluop_o <= `EXE_SLL_OP;
		  		alusel_o <= `EXE_RES_SHIFT;
		  		reg1_read_o <= 1'b0;
		  		reg2_read_o <= 1'b1;
		  		imm[4:0] <= inst_i[10:6];
		  		wd_o <= inst_i[15:11];
		  		instvalid <= `InstValid;
		  	end else if(op3 == `EXE_SRL)begin
		  		wreg_o <= `WriteEnable;
		  		aluop_o <= `EXE_SRL_OP;
		  		alusel_o <= `EXE_RES_SHIFT;
		  		reg1_read_o <= 1'b0;
		  		reg2_read_o <= 1'b1;
		  		imm[4:0] <= inst_i[10:6];
		  		wd_o <= inst_i[15:11];
		  		instvalid <= `InstValid;
		  	end else if(op3 == `EXE_SRA) begin
		  		wreg_o <= `WriteEnable;
		  		aluop_o <= `EXE_SRA_OP;
		  		alusel_o <= `EXE_RES_SHIFT;
		  		reg1_read_o <= 1'b0;
		  		reg2_read_o <= 1'b1;
		  		imm[4:0] <= inst_i[10:6];
		  		wd_o <= inst_i[15:11];
		  		instvalid <= `InstValid;
		  	end 
		  end 
//endcase
		  	//end
		// end else begin     //if
			if(inst_i[31:21]==11'b010_0000_0000&&inst_i[10:0]==11'b000_0000_0000)//mfc0指令
			begin
				aluop_o <= `EXE_MFC0_OP;
				alusel_o <= `EXE_RES_MOVE;//一种移动运算
				wd_o <= inst_i[20:16];//rt 要写的目的寄存器是指令中rt的值
				wreg_o <= `WriteEnable;//需要读取CP0中的寄存器的值写入目的寄存器,要写通用寄存器
				instvalid <= `InstValid;
				reg1_read_o <= 1'b0;
				reg2_read_o <= 1'b0;
			end else if(inst_i[31:21]==11'b010_0000_0100&&inst_i[10:0]==11'b00000000000)//mtc0指令
			begin
				aluop_o <= `EXE_MTC0_OP;
				alusel_o <= `EXE_RES_MOVE;
				wreg_o <= `WriteDisable;//不需要写通用寄存器
				instvalid <= `InstValid;
				reg1_read_o <= 1'b1;//需要读取通用寄存器 通过Regfile1端口读取数据
				reg1_addr_o <= inst_i[20:16];//读取地址是指令中16-20位 是rt的值
				reg2_read_o <= 1'b0;
			end 
	end //if
end        //always
	
/*       数据前推
给reg1_o赋值过程增加了两种情况
1:如果Regfile模块读端口1要读取的寄存器就是执行阶段要写的目的寄存器,那么直接把执行阶段的结果ex_wdata_i作为reg1_o的值
2:如果Regfile模块读端口1要读取的寄存器就是访存阶段要写的目的寄存器,那么直接把访存阶段的结果mem_wdata_i作为reg1_o的值*/
	always @ (*) begin
		if(rst == `RstEnable) begin
			reg1_o <= `ZeroWord;		
		end else if((reg1_read_o == 1'b1) && (ex_wreg_i == 1'b1) 
								&& (ex_wd_i == reg1_addr_o)) begin
			reg1_o <= ex_wdata_i; 
		end else if((reg1_read_o == 1'b1) && (mem_wreg_i == 1'b1) 
								&& (mem_wd_i == reg1_addr_o)) begin
			reg1_o <= mem_wdata_i; 			
	  end else if(reg1_read_o == 1'b1) begin
	  	reg1_o <= reg1_data_i;
	  end else if(reg1_read_o == 1'b0) begin
	  	reg1_o <= imm;
	  end else begin
	    reg1_o <= `ZeroWord;
	  end
	end
	
	always @ (*) begin
		if(rst == `RstEnable) begin
			reg2_o <= `ZeroWord;
		end else if((reg2_read_o == 1'b1) && (ex_wreg_i == 1'b1) 
								&& (ex_wd_i == reg2_addr_o)) begin
			reg2_o <= ex_wdata_i; 
		end else if((reg2_read_o == 1'b1) && (mem_wreg_i == 1'b1) 
								&& (mem_wd_i == reg2_addr_o)) begin
			reg2_o <= mem_wdata_i;			
	  end else if(reg2_read_o == 1'b1) begin
	  	reg2_o <= reg2_data_i;
	  end else if(reg2_read_o == 1'b0) begin
	  	reg2_o <= imm;
	  end else begin
	    reg2_o <= `ZeroWord;
	  end
	end


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

endmodule

id_ex.v

`include "define.v"
//在时钟周期的上升沿,将译码阶段的结果传递到执行阶段*/
module id_ex(

	input	wire										clk,
	input wire										rst,
	input wire flush,
	//最后一章,从译码阶段传递过来的信号
	input wire[`RegBus] id_current_inst_address,
	input wire[31:0] id_excepttype,

	
	//从译码阶段传递的信息
	input wire[`AluOpBus]         id_aluop,
	input wire[`AluSelBus]        id_alusel,
	input wire[`RegBus]           id_reg1,
	input wire[`RegBus]           id_reg2,
	input wire[`RegAddrBus]       id_wd,
	input wire                    id_wreg,
	
	//来自控制模块的信息
	input wire[5:0] stall	,
	input wire[`RegBus] id_link_address,
	input wire id_is_in_delayslot,
	input wire next_inst_in_delayslot_i,
	
	input wire[`RegBus] id_inst, //来自id模块的信号 当前处于译码阶段的指令
	
	
	
	
	//传递到执行阶段的信息
	output reg[`AluOpBus]         ex_aluop,
	output reg[`AluSelBus]        ex_alusel,
	output reg[`RegBus]           ex_reg1,
	output reg[`RegBus]           ex_reg2,
	output reg[`RegAddrBus]       ex_wd,
	output reg                    ex_wreg,
	
	output reg[`RegBus] ex_link_address,
	output reg ex_is_in_delayslot,
	output reg is_in_delayslot_o,
	output reg[`RegBus] ex_inst ,//传递到ex模块 当前处于执行阶段的指令
	
	//最后一章 新增接口 传递到执行阶段的信号
	output reg[`RegBus] ex_current_inst_address,
	output reg[31:0] ex_excepttype
	
);


	always @ (posedge clk) begin
		if (rst == `RstEnable) begin
			ex_aluop <= `EXE_NOP_OP;
			ex_alusel <= `EXE_RES_NOP;
			ex_reg1 <= `ZeroWord;
			ex_reg2 <= `ZeroWord;
			ex_wd <= `NOPRegAddr;
			ex_wreg <= `WriteDisable;
			ex_link_address <= `ZeroWord;
			ex_is_in_delayslot <= `NotInDelaySlot;
			ex_inst <= `ZeroWord;
			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;
			is_in_delayslot_o <= `NotInDelaySlot;
			ex_current_inst_address <= `ZeroWord;
		end else if(stall[2] == `Stop && stall[3] == `NoStop)begin//执行停止访存继续
			ex_aluop <= `EXE_NOP_OP;
			ex_alusel <= `EXE_RES_NOP;
			ex_reg1 <= `ZeroWord;
			ex_reg2 <= `ZeroWord;
			ex_wd <= `NOPRegAddr;
			ex_wreg <= `WriteDisable;
			ex_link_address <= `ZeroWord;
			ex_is_in_delayslot <= `NotInDelaySlot;
			ex_inst <= `ZeroWord;
			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;
			ex_inst <= id_inst;
			is_in_delayslot_o <= next_inst_in_delayslot_i;
			ex_excepttype <= id_excepttype;
			ex_current_inst_address <= id_current_inst_address;
		/*end else begin		
			ex_aluop <= id_aluop;
			ex_alusel <= id_alusel;
			ex_reg1 <= id_reg1;
			ex_reg2 <= id_reg2;
			ex_wd <= id_wd;
			ex_wreg <= id_wreg;		
		end*/
	end
	end
	
endmodule
	

ex.v

`include "define.v"
//ex.v 执行模块
module ex(
//译码阶段送到执行阶段的信息
input wire[`AluOpBus] aluop_i,
input wire[`AluSelBus] alusel_i,
input wire[`RegBus] reg1_i,
input wire[`RegBus] reg2_i,
input wire[`RegAddrBus] wd_i,
input wire wreg_i,
input wire rst,
//HILO模块给出HI,LO寄存器的值
input wire[`RegBus] hi_i,
input wire[`RegBus] lo_i,
//回写阶段的指令是否要写HI,LO,用于检测HI,LO寄存器带来的数据相关的问题
input wire[`RegBus] wb_hi_i,
input wire[`RegBus] wb_lo_i,
input wire wb_whilo_i,
//访存阶段的指令是否要写HI,LO,用于检测HI,LO寄存器带来的数据相关的问题
input wire[`RegBus] mem_hi_i,
input wire[`RegBus] mem_lo_i,
input wire mem_whilo_i,

//增加的输入端口
input wire[`DoubleRegBus] hilo_temp_i,//保存乘法结果
input wire[1:0] cnt_i,//处于执行阶段的第几个周期

//新增来自除法模块的输入
input wire[`DoubleRegBus] div_result_i,
input wire div_ready_i,

//处于执行阶段的转移指令要保存的返回地址
input wire[`RegBus] link_address_i,

//当前执行阶段指令是否处于延迟槽
input wire is_in_delayslot_i,

//新增输入端口inst_i,其值就是当前处于执行阶段的指令
input wire[`RegBus] inst_i,//当前处于执行阶段的指令

//访存阶段的指令是否要写CP0中的寄存器 用来检测数据相关
input wire mem_cp0_reg_we,
input wire[4:0] mem_cp0_reg_write_addr,
input wire[`RegBus] mem_cp0_reg_data,
//回写阶段的指令是否要写CP0中的寄存器 也是用来检测数据相关
input wire wb_cp0_reg_we,
input wire[4:0] wb_cp0_reg_write_addr,
input wire[`RegBus] wb_cp0_reg_data,
//与CP0直接相连 用于读取其中指定寄存器的值
input wire[`RegBus] cp0_reg_data_i,

//最后一章新增的输入接口
input wire[31:0] excepttype_i,
input wire[`RegBus] current_inst_address_i,


output reg[4:0] cp0_reg_read_addr_o,
//向流水线下一级传递 用于写CP0的指定寄存器的值
output reg cp0_reg_we_o,
output reg[4:0] cp0_reg_write_addr_o,
output reg[`RegBus] cp0_reg_data_o,
//处于执行阶段指令对LO,HI寄存器的写操作请求
output reg[`RegBus] hi_o,
output reg[`RegBus] lo_o,
output reg whilo_o,

//执行的结果
output reg[`RegAddrBus] wd_o,
output reg wreg_o,
output reg[`RegBus] wdata_o,
output reg stallreq,

output reg[`DoubleRegBus] hilo_temp_o,
output reg[1:0] cnt_o,

//新增到除法模块的输出
output reg[`RegBus] div_opdata1_o,
output reg[`RegBus] div_opdata2_o,
output reg div_start_o,
output reg signed_div_o,


//output reg is_in_delayslot_o,
//下面新增的几个输出接口是为 加载、 存储指令准备的
output wire[`AluOpBus] aluop_o, //执行阶段要进行运算的子类型
output wire[`RegBus] mem_addr_o,//加载存储指令对应的存储器地址
output wire[`RegBus] reg2_o,//存储指令要存储的数据,或者lwl,lwr指令要加载到的目的寄存器的地址

//最后一章新增的输出端口
output wire[31:0] excepttype_o,
output wire[`RegBus] current_inst_address_o,
output wire is_in_delayslot_o
);
//保存逻辑运算的结果
reg[`RegBus] logicout;
//保存移位运算的结果
reg[`RegBus] shiftres;
//保存移动操作的结果
reg[`RegBus] moveres;
//保存HI,LO寄存器的最新值
reg[`RegBus] HI;
reg[`RegBus] LO;
//是否由于除法运算导致流水线暂停
reg stallreq_for_div;
/***********************第七章新定义一些变量***********************/
wire ov_sum;//保存溢出情况
wire reg1_eq_reg2;//第一个操作数是否等于第二个操作数
wire reg1_lt_reg2;//第一个操作数是否小于第二个操作数
reg[`RegBus] arithmeticres;//保存算术运算的结果
reg[`DoubleRegBus] mulres;//保存乘法运算的结果
wire[`RegBus] reg2_i_mux;//保存输入的第二个操作数reg2_i的补码
wire[`RegBus] reg1_i_not;//保存输入的第一个操作数reg1_i取反后的值
wire[`RegBus] result_sum;//保存加法结果
wire[`RegBus] opdata1_mult;//乘法操作中的被乘数
wire[`RegBus] opdata2_mult;//乘法操作中的乘数
wire[`DoubleRegBus] hilo_temp;//临时保存乘法结果,宽度为64位
reg [`DoubleRegBus] hilo_temp1;
reg stallreq_for_madd_msub;
reg trapassert;//表示是否有自陷异常
reg ovassert;//表示是否有溢出异常
//aluop_o会传递到访存阶段,届时将利用其确定加载、存储类型
assign aluop_o = aluop_i;
//mem_addr_o会传递到访存阶段,是加载、存储指令对应的存储器地址,此处reg1_i就是加载、存储指令中地址为base的通用寄存器的值
//通过计算mem_addr_o,了解为何要在译码阶段ID模块新增输出接口inst_o
assign mem_addr_o = reg1_i + {{16{inst_i[15]}},inst_i[15:0]};
//reg2_i是存储指令要存储的数据,或者是lwl,lwr指令要加载到的目的寄存器的原始值,该值通过reg2_o接口传递到访存阶段
assign reg2_o = reg2_i;

assign excepttype_o={excepttype_i[31:12],ovassert,trapassert,excepttype_i[9:8],8'h00};

//is_in_delayslot_i表示当前指令是否在延迟槽中
assign is_in_delayslot_o = is_in_delayslot_i;
//当前 处于执行指令的地址
assign current_inst_address_o = current_inst_address_i;
/*******************************************************************
**            第一段:依据aluop_i指示的运算子类型进行运算          **
*******************************************************************/
always @ (*) 
begin//1
	if(rst == `RstEnable)
	begin//2
		logicout <= `ZeroWord;
	end//2
	else
	begin//3
		case(aluop_i)//4
			`EXE_OR_OP:begin//5 逻辑或
				logicout <= reg1_i|reg2_i;
			end 
			`EXE_AND_OP: begin //逻辑与
				logicout <= reg1_i&reg2_i;
			end
			`EXE_NOR_OP:begin //逻辑或非
				logicout <= ~(reg1_i|reg2_i);
			end
			`EXE_XOR_OP:begin //逻辑异或
				logicout <= reg1_i^reg2_i;
			end
			default:begin//6
				logicout <= `ZeroWord;
			end//6
		endcase//4
	end//3
end//1
always @ (*) begin
	if(rst == `RstEnable)begin
		shiftres <= `ZeroWord;
	end else begin
		case(aluop_i)
			`EXE_SLL_OP:begin //逻辑左移
				shiftres <= reg2_i << reg1_i[4:0];
			end
			`EXE_SRL_OP:begin //逻辑右移
				shiftres <= reg2_i >> reg1_i[4:0];
			end
			`EXE_SRA_OP:begin//算术右移1
				shiftres <= ({32{reg2_i[31]}}<<(6'd32-{1'b0,reg1_i[4:0]})) |/*rt向右移sa位*/ reg2_i>>reg1_i[4:0];
			end
			default:begin
			 shiftres <= `ZeroWord;
		end
	endcase
end
end
	
/******************************************************************
****第三段:得到最新的HI,LO寄存器的值,此处要解决数据相关的问题****
******************************************************************/
always @ (*)begin
	if(rst == `RstEnable) begin
		{HI,LO} <= {`ZeroWord,`ZeroWord};
	end else if(mem_whilo_i == `WriteEnable)begin
		{HI,LO} <= {mem_hi_i,mem_lo_i};//访存阶段的指令要写HI,LO寄存器
	end else if(wb_whilo_i == `WriteEnable)begin
		{HI,LO} <= {wb_hi_i,wb_lo_i};//回写阶段的指令要写HI,LO寄存器
end
end
/*******************************************************************
******************第四段:MFHI,MFLO,MOVN,MOVZ指令********************
*******************************************************************/
always @ (*) begin
	if(rst == `RstEnable) begin
		moveres <= `ZeroWord;
	end else begin
		moveres <= `ZeroWord;
		case(aluop_i)
			`EXE_MFHI_OP:begin
				//rd<-hi
				moveres <= HI;//HI的值是移动操作的结果
			end
			`EXE_MFLO_OP:begin
				//rd<-lo
				moveres <= LO;
			end
			`EXE_MOVN_OP:begin
				//rd<-rs
				moveres <= reg1_i;
			end
			`EXE_MOVZ_OP:begin
				//rd<-rs
				moveres <= reg1_i;
			end
			`EXE_MFC0_OP:begin
				//要从CP0中读取寄存器的地址
				cp0_reg_read_addr_o <= inst_i[15:11];//通过cp0_reg_read_addr_o向CP0模块送出要读取的CP0中寄存器地址
				//读取到的CP0中指定寄存器的值
				moveres <= cp0_reg_data_i;//通过cp0_reg_data_i接口送入ex 赋值给变量moveres
				//判断是否存在数据相关 此时moveres并不一定是CP0中寄存器的最新值
				if(mem_cp0_reg_we == `WriteEnable && mem_cp0_reg_write_addr == inst_i[15:11])
				begin
					moveres <= mem_cp0_reg_data;//与访存阶段存在数据相关
				end else if(wb_cp0_reg_we == `WriteEnable && wb_cp0_reg_write_addr == inst_i[15:11])
				begin
					moveres <= wb_cp0_reg_data;//与回写阶段存在数据相关
				end 
			end 
			default:begin
			end
		endcase
	end
end
/***************************************************************
*******如果是MTHI,MTLO指令,需要给出whilo_o,hi_o,lo_o的值*******
***************************************************************/                 
always @ (*)begin
	if(rst == `RstEnable) begin
		whilo_o <= `WriteDisable;
		hi_o <= `ZeroWord;
		lo_o <= `ZeroWord;
	end else if(aluop_i == `EXE_MTHI_OP)begin
		whilo_o <= `WriteEnable;
		hi_o <= reg1_i;
		lo_o <= LO;//写HI寄存器所以LO保持不变
	end else if(aluop_i == `EXE_MTLO_OP)begin
		whilo_o <= `WriteEnable;
		hi_o <= HI;
		lo_o <= reg1_i;
	end else begin
		whilo_o <= `WriteDisable;
		hi_o <= `ZeroWord;
		lo_o <= `ZeroWord;
	end
end
//end
//endmodule
/*************************************************************
******************第五段:计算以下5个变量的值******************
*************************************************************/
/*(1)如果是减法或者是有符号比较运算,那么reg2_i_mux等于第二个操作数reg2_i的补码,
否则reg2_i_mux就等于第二个操作数reg2_i*/
assign reg2_i_mux = ((aluop_i == `EXE_SUB_OP)||(aluop_i == `EXE_SUBU_OP)||(aluop_i == `EXE_SLT_OP)||
(aluop_i == `EXE_TLT_OP)||(aluop_i == `EXE_TLTI_OP)||(aluop_i ==  `EXE_TGE_OP)||(aluop_i == `EXE_TGE_OP)||(aluop_i == `EXE_TGEI_OP))?(~reg2_i)+1:reg2_i;
/*(2)分三种情况:
A:如果是加法运算,此时reg2_i_mux就是第二个操作数reg2_i,所以result_sum就是加法运算结果
B:如果是减法运算,此时reg2_i_mux就是第二个操作数reg2_i的补码,所以result_sum就是减法运算的结果
C:如果是有符号的比较运算,此时reg2_i_mux也就是第二个操作数reg2_i的补码,所以result_sum也就是减法
运算的结果,可以通过判断减法的结果是否小于0,进而判断第一个操作数reg1_i是否小于第二个操作数reg2_i*/
assign result_sum = reg1_i + reg2_i_mux;
/*(3)计算是否溢出,加法指令add和addi,减法指令sub执行的时候,需要判断是否溢出,满足以下两种情况之一的时候
A:reg1_i为正数,reg2_i_mux为正数,但两者之和为负数
B:reg1_i为负数,reg2_i_mux为负数,但是两者之和为正数*/
//这个我不理解 艹    2022.3.10理解了
assign ov_sum = ((!reg1_i[31] && !reg2_i_mux[31]) && result_sum[31])||((reg1_i[31] && reg2_i_mux[31])&&(!result_sum[31]));
/*(4)计算操作数1是否小于操作数2,分两种情况:
A:aluop_i为EXE_SLT_OP表示有符号比较运算
1.reg1_i为负数、reg2_i为正数,显然reg1_i小于reg2_i
2.reg1_i为正数、reg2_i为正数,并且reg1_i减去reg2_i的值小于0(result_sum为负)此时reg1_i小于reg2_i
3.reg1_i为负数、reg2_i为负数,并且reg1_i减去reg2_i的值小于0(result_sum为负)此时reg1_i小于reg2_i
B:无符号数比较运算的时候,直接使用比较运算符比较reg1_i和reg2_i*/
assign reg1_lt_reg2 = ((aluop_i == `EXE_SLT_OP)
||(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);
//(5)对操作数1逐位取反 赋值给reg1_i_not
assign reg1_i_not = ~reg1_i;
/*****************************************************************
*****第六段:依据不同的算术运算类型,给arithmeticres变量赋值*******
*****************************************************************/
always @ (*) begin
	if(rst == `RstEnable)begin
		arithmeticres <= `ZeroWord;
	end else begin
		case(aluop_i) //选择运算类型
			`EXE_SLT_OP,`EXE_SLTU_OP:begin
				arithmeticres <= reg1_lt_reg2;//比较运算
			end
			`EXE_ADD_OP,`EXE_ADDU_OP,`EXE_ADDI_OP,`EXE_ADDIU_OP:begin
				arithmeticres <= result_sum;//加法运算
			end
			`EXE_SUB_OP,`EXE_SUBU_OP:begin
				arithmeticres <= result_sum;//减法运算
			end
			`EXE_CLZ_OP:begin //计数运算clz 
				arithmeticres <= reg1_i[31]?0:reg1_i[30]?1:
												 reg1_i[29]?2:reg1_i[28]?3:
												 reg1_i[27]?4:reg1_i[26]?5:
												 reg1_i[25]?6:reg1_i[24]?7:
												 reg1_i[23]?8:reg1_i[22]?9:
												 reg1_i[21]?10:reg1_i[20]?11:
												 reg1_i[19]?12:reg1_i[18]?13:
												 reg1_i[17]?14:reg1_i[16]?15:
												 reg1_i[15]?16:reg1_i[14]?17:
												 reg1_i[13]?18:reg1_i[12]?19:
												 reg1_i[11]?20:reg1_i[10]?21:
												 reg1_i[9]?22:reg1_i[8]?23:
												 reg1_i[7]?24:reg1_i[6]?25:
												 reg1_i[5]?26:reg1_i[4]?27:
												 reg1_i[3]?28:reg1_i[2]?29:
												 reg1_i[1]?20:reg1_i[0]?31:32;
												end
			`EXE_CLO_OP:begin //计数运算clo
				arithmeticres <= (reg1_i_not[31]?0:
													reg1_i_not[30]?1:
													reg1_i_not[29]?2:
													reg1_i_not[28]?3:
													reg1_i_not[27]?4:
													reg1_i_not[26]?5:
													reg1_i_not[25]?6:
													reg1_i_not[24]?7:
													reg1_i_not[23]?8:
													reg1_i_not[22]?9:
													reg1_i_not[21]?10:
													reg1_i_not[20]?11:
													reg1_i_not[19]?12:
													reg1_i_not[18]?13:
													reg1_i_not[17]?14:
													reg1_i_not[16]?15:
													reg1_i_not[15]?16:
													reg1_i_not[14]?17:
													reg1_i_not[13]?18:
													reg1_i_not[12]?19:
													reg1_i_not[11]?20:
													reg1_i_not[10]?21:
													reg1_i_not[9]?22:
													reg1_i_not[8]?23:
													reg1_i_not[7]?24:
													reg1_i_not[6]?25:
													reg1_i_not[5]?26:
													reg1_i_not[4]?27:
													reg1_i_not[3]?28:
													reg1_i_not[2]?29:
													reg1_i_not[1]?30:
													reg1_i_not[0]?31:32);
												end
												default:begin
													arithmeticres <= `ZeroWord;
												end
											endcase
										end
									end 
/*****************************************************************
************************第七段:进行乘法运算***********************
*****************************************************************/
/*(1)取得乘法运算的被乘数 指令 madd,msub都是有符号乘法,如果第一个操作数reg1_i是负数
那么取reg1_i的补码为被乘数,反之直接使用reg1_i作为被乘数 如果是有符号乘法且被乘数是负数 那么取补码*/
assign opdata1_mult = (((aluop_i == `EXE_MUL_OP)||(aluop_i == `EXE_MULT_OP)||(aluop_i == `EXE_MADD_OP)||(aluop_i == `EXE_MSUB_OP))&&(reg1_i[31] == 1'b1)) ? (~reg1_i+1):reg1_i;
//(2)取得乘法运算的乘数 如果是有符号乘法且乘数是负数 那么取补码
assign opdata2_mult = (((aluop_i == `EXE_MUL_OP)||(aluop_i == `EXE_MULT_OP)||(aluop_i == `EXE_MADD_OP)||(aluop_i == `EXE_MSUB_OP))&&(reg2_i[31] == 1'b1)) ? (~reg2_i+1):reg2_i;
//(3)得到临时乘法结果 保存在变量hilo_temp中
assign hilo_temp = opdata1_mult * opdata2_mult;
/*(4)对临时乘法结果进行修正 最终的乘法结果保存在变量mulres中 主要有以下两点
A:如果是有符号乘法指令mult、mul,那么需要修正临时乘法结果,如下:
A1:如果被乘数与乘数两者为一正一负,那么需要对临时乘法结果hilo_temp求补码,作为最终乘法结果,赋给mulres
A2:如果被乘数与乘数同号,那么hilo_temp的值就作为最终的乘法结果,赋给变量mulres
B:如果是无符号乘法指令multu,那么hilo_temp的值就作为最终的乘法结果,赋给变量mulres
*/
always @ (*) begin//1
	if(rst == `RstEnable) begin//2
		mulres <= {`ZeroWord,`ZeroWord};
	end/*2*/ else if((aluop_i == `EXE_MULT_OP)||(aluop_i == `EXE_MUL_OP)||(aluop_i == `EXE_MADD_OP)||(aluop_i == `EXE_MSUB_OP))begin//3
		if(reg1_i[31]^reg2_i[31] == 1'b1)begin//4 被乘数和乘数一正一负
			mulres <= ~hilo_temp+1;
		end/*4*/ else begin//5 被乘数和乘数同号
			mulres <= hilo_temp;
		end//5
		end/*3*/ else begin//6 无符号乘法
			mulres <= hilo_temp;
		end//6
	end//1
/*****************************************************************
****************第八段:确定要写入目的寄存器的数据*****************
*****************************************************************/
always @ (*)begin
	wd_o <= wd_i;
	//如果是add,addi,sub,subi指令,且发生溢出,那么设置wreg_o为WriteEnable 表示不写目的寄存器
	if(((aluop_i == `EXE_ADD_OP)||(aluop_i == `EXE_ADDI_OP)||(aluop_i == `EXE_SUB_OP))&&(ov_sum == 1'b1))begin
		wreg_o <= `WriteDisable;
		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//乘法指令mul
			wdata_o <= mulres[31:0];
		end
		`EXE_RES_JUMP_BRANCH:begin
			wdata_o <= link_address_i;
		end
		default:begin
			wdata_o <= `ZeroWord;
		end
	endcase
end//always

/****************************************************************
********************第十段:乘累加、乘累减************************
****************************************************************/
//MADD MADDU MSUB MSUBU指令
always @ (*) begin
	if(rst == `RstEnable) begin
		hilo_temp_o <= {`ZeroWord,`ZeroWord};
		cnt_o <= 2'b00;
		stallreq_for_madd_msub <= `NoStop;
	end else begin
		case(aluop_i)
			`EXE_MADD_OP,`EXE_MADDU_OP:begin
				if(cnt_i == 2'b00) begin //执行第一个时钟周期
					hilo_temp_o <= mulres;//此时将乘法结果mulres通过接口hilo_temp_o输出到EX/MEM模块 以便在下一个时钟周期使用
					cnt_o <= 2'b01;
					hilo_temp1 <= {`ZeroWord,`ZeroWord};
					stallreq_for_madd_msub <= `Stop;//乘累加指令请求流水线暂停
					
				end else if(cnt_i == 2'b01) begin//执行第二个时钟周期
					hilo_temp_o <= {`ZeroWord,`ZeroWord};
					cnt_o <= 2'b10;
					hilo_temp1 <= hilo_temp_i+{HI,LO}; //hilo_temp_i是上一个时钟周期得到的乘法结果
					stallreq_for_madd_msub <= `NoStop;//乘累加指令执行结束 不再请求流水线暂停
				end
			end
			`EXE_MSUB_OP,`EXE_MSUBU_OP:begin
				if(cnt_i == 2'b00) begin
					hilo_temp_o <= ~mulres+1;
					cnt_o <= 2'b01;
					stallreq_for_madd_msub <= `Stop;
				end else if(cnt_i == 2'b01) begin
					hilo_temp_o <= {`ZeroWord,`ZeroWord};
					cnt_o <= 2'b10;
					hilo_temp1 <= hilo_temp_i +{HI,LO};
					stallreq_for_madd_msub <= `NoStop;
				end
			end
			default:begin
				hilo_temp_o <= {`ZeroWord,`ZeroWord};
				cnt_o <= 2'b00;
				stallreq_for_madd_msub <= `NoStop;
			end
		endcase
	end
end
/****************************************************************
******第十二段:输出DIV模块控制信息,获取DIV模块给出的结果*********
****************************************************************/
always @ (*) begin
	if(rst == `RstEnable)begin
		stallreq_for_div <= `NoStop;
		div_opdata1_o <= `ZeroWord;
		div_opdata2_o <= `ZeroWord;
		div_start_o <= `DivStop;
		signed_div_o <= 1'b0;
	end else begin
		stallreq_for_div <= `NoStop;
		div_opdata1_o <= `ZeroWord;
		div_opdata2_o <= `ZeroWord;
		div_start_o <= `DivStop;
		signed_div_o <= 1'b0;
		case(aluop_i)
			`EXE_DIV_OP:begin
				if(div_ready_i == `DivResultNotReady) begin
					div_opdata1_o <= reg1_i;//被除数
					div_opdata2_o <= reg2_i;//除数
					div_start_o <= `DivStart;//开始除法运算
					signed_div_o <= 1'b1;//有符号除法
					stallreq_for_div <= `Stop;//请求流水线暂停
				end else if(div_ready_i == `DivResultReady) begin
					div_opdata1_o <= reg1_i;
					div_opdata2_o <= reg2_i;
					div_start_o <= `DivStop;//结束除法运算
					signed_div_o <= 1'b1;
					stallreq_for_div <= `NoStop;//不再请求流水线暂停
				end else begin
					div_opdata1_o <= `ZeroWord;
					div_opdata2_o <= `ZeroWord;
					div_start_o <= `DivStop;
					signed_div_o <= 1'b0;
					stallreq_for_div <= `NoStop;
				end
			end
			`EXE_DIVU_OP:begin
				if(div_ready_i == `DivResultNotReady) begin
					div_opdata1_o <= reg1_i;
					div_opdata2_o <= reg2_i;
					div_start_o <= `DivStart;
					signed_div_o <= 1'b0;//无符号除法
					stallreq_for_div <= `Stop;
				end else if(div_ready_i == `DivResultReady) begin
					div_opdata1_o <= reg1_i;
					div_opdata2_o <= reg2_i;
					div_start_o <= `DivStop;
					signed_div_o <= 1'b0;
					stallreq_for_div <= `NoStop;
				end else begin
					div_opdata1_o <= `ZeroWord;
					div_opdata2_o <= `ZeroWord;
					div_start_o <= `DivStop;
					signed_div_o <= 1'b0;
					stallreq_for_div <= `NoStop;
				end
			end
			default:begin
			end
		endcase
	end
end
			
/****************************************************************
*********************第十一段:暂停流水线*************************
****************************************************************/
//目前只有乘累加和乘累减指令会导致流水线暂停,所以stallreq=stallreq_for_madd_msub
always @ (*) begin
	stallreq = stallreq_for_madd_msub || stallreq_for_div;
end
/****************************************************************
****************第九段:确定(修改)对HI,LO寄存器的操作信息*********
****************************************************************/
always @ (*)begin
	if(rst == `RstEnable) begin
		whilo_o <= `WriteDisable;
		hi_o <= `ZeroWord;
		lo_o <= `ZeroWord;
	end else if((aluop_i == `EXE_MULT_OP)||(aluop_i == `EXE_MULTU_OP))begin //mult,multu指令
		whilo_o <= `WriteEnable;
		hi_o <= mulres[63:32];
		lo_o <= mulres[31:0];
	end else if(aluop_i == `EXE_MTHI_OP)begin
		whilo_o <= `WriteEnable;
		hi_o <= reg1_i;
		lo_o <= LO;//写HI寄存器所以LO保持不变
	end else if(aluop_i == `EXE_MTLO_OP)begin
		whilo_o <= `WriteEnable;
		hi_o <= HI;
		lo_o <= reg1_i;
	end else if((aluop_i == `EXE_MSUB_OP)||(aluop_i == `EXE_MSUBU_OP))begin
		whilo_o <= `WriteEnable;
		hi_o <= hilo_temp1[63:32];
		lo_o <= hilo_temp1[31:0];
	end else if((aluop_i == `EXE_MADD_OP)||(aluop_i == `EXE_MADDU_OP))begin
		whilo_o <= `WriteEnable;
		hi_o <= hilo_temp1[63:32];
		lo_o <= hilo_temp1[31:0];
	end else if((aluop_i == `EXE_DIV_OP)||(aluop_i == `EXE_DIVU_OP))begin
		whilo_o <= `WriteEnable;
		hi_o <= div_result_i[63:32];
		lo_o <= div_result_i[31:0];
	end else begin
		whilo_o <= `WriteDisable;
		hi_o <= `ZeroWord;
		lo_o <= `ZeroWord;
	end 
		
end
/*********************************************************************
******************第十三段:给出mtc0指令执行的结果*********************
*********************************************************************/
always @ (*) begin
	if(rst == `RstEnable)begin
		cp0_reg_write_addr_o <= 5'b00000;
		cp0_reg_we_o <= `WriteDisable;
		cp0_reg_data_o <= `ZeroWord;
	end else if(aluop_i == `EXE_MTC0_OP)begin//如果是mtc0指令
		cp0_reg_write_addr_o <= inst_i[15:11];//写入地址为指令中第11-15为的值
		cp0_reg_we_o <= `WriteEnable;//设置写操作信号cp0_reg_we_o为可写
		cp0_reg_data_o <= reg1_i;//写入的值就是译码阶段传递来的reg1_i的值 正是rt通用寄存器的值
	end else begin
		cp0_reg_write_addr_o <= 5'b00000;
		cp0_reg_we_o <= `WriteDisable;
		cp0_reg_data_o <= `ZeroWord;
	end 
end 

/************************************************************************
******************第十四段:判断是否发生自陷异常**************************
************************************************************************/
always @ (*) begin
	if(rst == `RstEnable)begin
		trapassert <= `TrapNotAssert;
	end else begin
		trapassert <= `TrapNotAssert;//默认没有自陷异常
		case(aluop_i)
			//teg teqi指令
			`EXE_TEQ_OP,`EXE_TEQI_OP:begin
				if(reg1_i == reg2_i)begin
					trapassert <= `TrapAssert;
				end 
			end 
			//tge tgei tgeiu tgeu指令
			`EXE_TGE_OP,`EXE_TGEI_OP,`EXE_TGEIU_OP,`EXE_TGEU_OP:
			begin
				if(~reg1_lt_reg2)begin
					trapassert <= `TrapAssert;
				end 
			end 
			//tlt tlti tltiu tltu指令
			`EXE_TLT_OP,`EXE_TLTI_OP,`EXE_TLTIU_OP,`EXE_TLTU_OP:
			begin
				if(reg1_lt_reg2)begin
					trapassert <= `TrapAssert;
				end 
			end 
			//tne tnei指令
			`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 
endmodule		

ex_mem.v

`include "define.v"
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[`AluOpBus]        ex_aluop,
	input wire[`RegBus]          ex_mem_addr,
	input wire[`RegBus]          ex_reg2,

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

	input wire                   ex_cp0_reg_we,
	input wire[4:0]              ex_cp0_reg_write_addr,
	input wire[`RegBus]          ex_cp0_reg_data,	
	
	//最后一章 新增的输入模块
	input wire[31:0] ex_excepttype,//译码、执行阶段手机到的异常信息
	input wire ex_is_in_delayslot,//执行阶段的指令是否是延迟槽指令
	input wire[`RegBus] ex_current_inst_address,//执行阶段指令的地址
	
	//送到访存阶段的信息
	output reg[`RegAddrBus]      mem_wd,
	output reg                   mem_wreg,
	output reg[`RegBus]					 mem_wdata,
	output reg[`RegBus]          mem_hi,
	output reg[`RegBus]          mem_lo,
	output reg                   mem_whilo,

  //为实现加载、访存指令而添加
  output reg[`AluOpBus]        mem_aluop,
	output reg[`RegBus]          mem_mem_addr,
	output reg[`RegBus]          mem_reg2,
	
	output reg                   mem_cp0_reg_we,
	output reg[4:0]              mem_cp0_reg_write_addr,
	output reg[`RegBus]          mem_cp0_reg_data,
		
	output reg[`DoubleRegBus]    hilo_o,
	output reg[1:0]              cnt_o	,
	
	//最后一章 新增的输出模块
	output reg[31:0] mem_excepttype,//译码、执行阶段收集到的异常信息
	output reg mem_is_in_delayslot,//访存阶段的指令是否是延迟槽指令
	output reg[`RegBus] mem_current_inst_address	
	
);


	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_addr <= ex_mem_addr;
			mem_reg2 <= ex_reg2;
			mem_cp0_reg_we <= ex_cp0_reg_we;
			mem_cp0_reg_write_addr <= ex_cp0_reg_write_addr;
			mem_cp0_reg_data <= ex_cp0_reg_data;
			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    //if
	end      //always
			

endmodule

mem.v



`include "define.v"

module mem(

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

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

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

	//协处理器CP0的写信号
	input wire                   cp0_reg_we_i,
	input wire[4:0]              cp0_reg_write_addr_i,
	input wire[`RegBus]          cp0_reg_data_i,
	
	input wire[31:0]             excepttype_i,
	input wire                   is_in_delayslot_i,
	input wire[`RegBus]          current_inst_address_i,	
	
	//CP0的各个寄存器的值,但不一定是最新的值,要防止回写阶段指令写CP0
	input wire[`RegBus]          cp0_status_i,
	input wire[`RegBus]          cp0_cause_i,
	input wire[`RegBus]          cp0_epc_i,

	//回写阶段的指令是否要写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[`RegBus]          hi_o,
	output reg[`RegBus]          lo_o,
	output reg                   whilo_o,

	output reg                   LLbit_we_o,
	output reg                   LLbit_value_o,

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

  reg LLbit;
	wire[`RegBus] zero32;
	reg[`RegBus]          cp0_status;
	reg[`RegBus]          cp0_cause;
	reg[`RegBus]          cp0_epc;	
	reg                   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;

  //获取最新的LLbit的值
	always @ (*) begin
		if(rst == `RstEnable) begin
			LLbit <= 1'b0;
		end else begin
			if(wb_LLbit_we_i == 1'b1) begin
				LLbit <= wb_LLbit_value_i;
			end else begin
				LLbit <= LLbit_i;
			end
		end
	end
	
	always @ (*) begin
		if(rst == `RstEnable) begin
			wd_o <= `NOPRegAddr;
			wreg_o <= `WriteDisable;
		  wdata_o <= `ZeroWord;
		  hi_o <= `ZeroWord;
		  lo_o <= `ZeroWord;
		  whilo_o <= `WriteDisable;		
		  mem_addr_o <= `ZeroWord;
		  mem_we <= `WriteDisable;
		  mem_sel_o <= 4'b0000;
		  mem_data_o <= `ZeroWord;		
		  mem_ce_o <= `ChipDisable;
		  LLbit_we_o <= 1'b0;
		  LLbit_value_o <= 1'b0;		
		  cp0_reg_we_o <= `WriteDisable;
		  cp0_reg_write_addr_o <= 5'b00000;
		  cp0_reg_data_o <= `ZeroWord;		        
		end else begin
		  wd_o <= wd_i;
			wreg_o <= wreg_i;
			wdata_o <= wdata_i;
			hi_o <= hi_i;
			lo_o <= lo_i;
			whilo_o <= whilo_i;		
			mem_we <= `WriteDisable;
			mem_addr_o <= `ZeroWord;
			mem_sel_o <= 4'b1111;
			mem_ce_o <= `ChipDisable;
		  LLbit_we_o <= 1'b0;
		  LLbit_value_o <= 1'b0;		
		  cp0_reg_we_o <= cp0_reg_we_i;
		  cp0_reg_write_addr_o <= cp0_reg_write_addr_i;
		  cp0_reg_data_o <= cp0_reg_data_i;		 		  	
			case (aluop_i)
				`EXE_LB_OP:		begin
					mem_addr_o <= mem_addr_i;
					mem_we <= `WriteDisable;
					mem_ce_o <= `ChipEnable;
					case (mem_addr_i[1:0])
						2'b00:	begin
							wdata_o <= {{24{mem_data_i[31]}},mem_data_i[31:24]};
							mem_sel_o <= 4'b1000;
						end
						2'b01:	begin
							wdata_o <= {{24{mem_data_i[23]}},mem_data_i[23:16]};
							mem_sel_o <= 4'b0100;
						end
						2'b10:	begin
							wdata_o <= {{24{mem_data_i[15]}},mem_data_i[15:8]};
							mem_sel_o <= 4'b0010;
						end
						2'b11:	begin
							wdata_o <= {{24{mem_data_i[7]}},mem_data_i[7:0]};
							mem_sel_o <= 4'b0001;
						end
						default:	begin
							wdata_o <= `ZeroWord;
						end
					endcase
				end
				`EXE_LBU_OP:		begin
					mem_addr_o <= mem_addr_i;
					mem_we <= `WriteDisable;
					mem_ce_o <= `ChipEnable;
					case (mem_addr_i[1:0])
						2'b00:	begin
							wdata_o <= {{24{1'b0}},mem_data_i[31:24]};
							mem_sel_o <= 4'b1000;
						end
						2'b01:	begin
							wdata_o <= {{24{1'b0}},mem_data_i[23:16]};
							mem_sel_o <= 4'b0100;
						end
						2'b10:	begin
							wdata_o <= {{24{1'b0}},mem_data_i[15:8]};
							mem_sel_o <= 4'b0010;
						end
						2'b11:	begin
							wdata_o <= {{24{1'b0}},mem_data_i[7:0]};
							mem_sel_o <= 4'b0001;
						end
						default:	begin
							wdata_o <= `ZeroWord;
						end
					endcase				
				end
				`EXE_LH_OP:		begin
					mem_addr_o <= mem_addr_i;
					mem_we <= `WriteDisable;
					mem_ce_o <= `ChipEnable;
					case (mem_addr_i[1:0])
						2'b00:	begin
							wdata_o <= {{16{mem_data_i[31]}},mem_data_i[31:16]};
							mem_sel_o <= 4'b1100;
						end
						2'b10:	begin
							wdata_o <= {{16{mem_data_i[15]}},mem_data_i[15:0]};
							mem_sel_o <= 4'b0011;
						end
						default:	begin
							wdata_o <= `ZeroWord;
						end
					endcase					
				end
				`EXE_LHU_OP:		begin
					mem_addr_o <= mem_addr_i;
					mem_we <= `WriteDisable;
					mem_ce_o <= `ChipEnable;
					case (mem_addr_i[1:0])
						2'b00:	begin
							wdata_o <= {{16{1'b0}},mem_data_i[31:16]};
							mem_sel_o <= 4'b1100;
						end
						2'b10:	begin
							wdata_o <= {{16{1'b0}},mem_data_i[15:0]};
							mem_sel_o <= 4'b0011;
						end
						default:	begin
							wdata_o <= `ZeroWord;
						end
					endcase				
				end
				`EXE_LW_OP:		begin
					mem_addr_o <= mem_addr_i;
					mem_we <= `WriteDisable;
					wdata_o <= mem_data_i;
					mem_sel_o <= 4'b1111;		
					mem_ce_o <= `ChipEnable;
				end
				`EXE_LWL_OP:		begin
					mem_addr_o <= {mem_addr_i[31:2], 2'b00};
					mem_we <= `WriteDisable;
					mem_sel_o <= 4'b1111;
					mem_ce_o <= `ChipEnable;
					case (mem_addr_i[1:0])
						2'b00:	begin
							wdata_o <= mem_data_i[31:0];
						end
						2'b01:	begin
							wdata_o <= {mem_data_i[23:0],reg2_i[7:0]};
						end
						2'b10:	begin
							wdata_o <= {mem_data_i[15:0],reg2_i[15:0]};
						end
						2'b11:	begin
							wdata_o <= {mem_data_i[7:0],reg2_i[23:0]};	
						end
						default:	begin
							wdata_o <= `ZeroWord;
						end
					endcase				
				end
				`EXE_LWR_OP:		begin
					mem_addr_o <= {mem_addr_i[31:2], 2'b00};
					mem_we <= `WriteDisable;
					mem_sel_o <= 4'b1111;
					mem_ce_o <= `ChipEnable;
					case (mem_addr_i[1:0])
						2'b00:	begin
							wdata_o <= {reg2_i[31:8],mem_data_i[31:24]};
						end
						2'b01:	begin
							wdata_o <= {reg2_i[31:16],mem_data_i[31:16]};
						end
						2'b10:	begin
							wdata_o <= {reg2_i[31:24],mem_data_i[31:8]};
						end
						2'b11:	begin
							wdata_o <= mem_data_i;	
						end
						default:	begin
							wdata_o <= `ZeroWord;
						end
					endcase					
				end
				`EXE_LL_OP:		begin
					mem_addr_o <= mem_addr_i;
					mem_we <= `WriteDisable;
					wdata_o <= mem_data_i;	
		  		LLbit_we_o <= 1'b1;
		  		LLbit_value_o <= 1'b1;
		  		mem_sel_o <= 4'b1111;					
		  		mem_ce_o <= `ChipEnable;				
				end				
				`EXE_SB_OP:		begin
					mem_addr_o <= mem_addr_i;
					mem_we <= `WriteEnable;
					mem_data_o <= {reg2_i[7:0],reg2_i[7:0],reg2_i[7:0],reg2_i[7:0]};
					mem_ce_o <= `ChipEnable;
					case (mem_addr_i[1:0])
						2'b00:	begin
							mem_sel_o <= 4'b1000;
						end
						2'b01:	begin
							mem_sel_o <= 4'b0100;
						end
						2'b10:	begin
							mem_sel_o <= 4'b0010;
						end
						2'b11:	begin
							mem_sel_o <= 4'b0001;	
						end
						default:	begin
							mem_sel_o <= 4'b0000;
						end
					endcase				
				end
				`EXE_SH_OP:		begin
					mem_addr_o <= mem_addr_i;
					mem_we <= `WriteEnable;
					mem_data_o <= {reg2_i[15:0],reg2_i[15:0]};
					mem_ce_o <= `ChipEnable;
					case (mem_addr_i[1:0])
						2'b00:	begin
							mem_sel_o <= 4'b1100;
						end
						2'b10:	begin
							mem_sel_o <= 4'b0011;
						end
						default:	begin
							mem_sel_o <= 4'b0000;
						end
					endcase						
				end
				`EXE_SW_OP:		begin
					mem_addr_o <= mem_addr_i;
					mem_we <= `WriteEnable;
					mem_data_o <= reg2_i;
					mem_sel_o <= 4'b1111;			
					mem_ce_o <= `ChipEnable;
				end
				`EXE_SWL_OP:		begin
					mem_addr_o <= {mem_addr_i[31:2], 2'b00};
					mem_we <= `WriteEnable;
					mem_ce_o <= `ChipEnable;
					case (mem_addr_i[1:0])
						2'b00:	begin						  
							mem_sel_o <= 4'b1111;
							mem_data_o <= reg2_i;
						end
						2'b01:	begin
							mem_sel_o <= 4'b0111;
							mem_data_o <= {zero32[7:0],reg2_i[31:8]};
						end
						2'b10:	begin
							mem_sel_o <= 4'b0011;
							mem_data_o <= {zero32[15:0],reg2_i[31:16]};
						end
						2'b11:	begin
							mem_sel_o <= 4'b0001;	
							mem_data_o <= {zero32[23:0],reg2_i[31:24]};
						end
						default:	begin
							mem_sel_o <= 4'b0000;
						end
					endcase							
				end
				`EXE_SWR_OP:		begin
					mem_addr_o <= {mem_addr_i[31:2], 2'b00};
					mem_we <= `WriteEnable;
					mem_ce_o <= `ChipEnable;
					case (mem_addr_i[1:0])
						2'b00:	begin						  
							mem_sel_o <= 4'b1000;
							mem_data_o <= {reg2_i[7:0],zero32[23:0]};
						end
						2'b01:	begin
							mem_sel_o <= 4'b1100;
							mem_data_o <= {reg2_i[15:0],zero32[15:0]};
						end
						2'b10:	begin
							mem_sel_o <= 4'b1110;
							mem_data_o <= {reg2_i[23:0],zero32[7:0]};
						end
						2'b11:	begin
							mem_sel_o <= 4'b1111;	
							mem_data_o <= reg2_i[31:0];
						end
						default:	begin
							mem_sel_o <= 4'b0000;
						end
					endcase											
				end 
				`EXE_SC_OP:		begin
					if(LLbit == 1'b1) begin
						LLbit_we_o <= 1'b1;
						LLbit_value_o <= 1'b0;
						mem_addr_o <= mem_addr_i;
						mem_we <= `WriteEnable;
						mem_data_o <= reg2_i;
						wdata_o <= 32'b1;
						mem_sel_o <= 4'b1111;		
						mem_ce_o <= `ChipEnable;				
					end else begin
						wdata_o <= 32'b0;
					end
				end				
				default:		begin
          //什么也不做
				end
			endcase							
		end    //if
	end      //always

	always @ (*) begin
		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;
		end else begin
		  cp0_status <= cp0_status_i;
		end
	end
	
	always @ (*) begin
		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
		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];
			cp0_cause[22] <= wb_cp0_reg_data[22];
			cp0_cause[23] <= wb_cp0_reg_data[23];
		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  //ov
					excepttype_o <= 32'h0000000c;
				end else if(excepttype_i[12] == 1'b1) begin  //返回指令
					excepttype_o <= 32'h0000000e;
				end
			end
				
		end
	end			

endmodule

mem_wb.v

`include "define.v"
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_LLbit_we,
	input wire                  mem_LLbit_value,	

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

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

	output reg                  wb_LLbit_we,
	output reg                  wb_LLbit_value,

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


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

endmodule

regfile.v

`include "define.v"
//回写阶段的实现实际上是在Regfile模块中实现的
//Regfile模块 寄存器堆
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//第二个读寄存器端口要输出的寄存器的值
);
/*******第一段: 定义32个32位寄存器*******/
/*******第二段:写操作******************/
/*******第三段:读端口1的读操作********/
/*******第四段:读端口2的读操作*******/



//第一段:定义32个32位寄存器

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

//第二段:实现写寄存器操作
always @ (posedge clk)
begin
	if(rst==`RstDisable)//rst==1,复位信号无效
	begin
		if((we==`WriteEnable)&&(waddr!=`RegNumLog2'h0))//写使能信号we有效 且 写操作目的寄存器不等于0的情况下
		begin//MIPS32架构规定 $0的值只能为0 所以不需要写入	
			regs[waddr]<=wdata;//将写输入数据保存到目的寄存器
		end
	end
end


//第三段:读端口1的读操作 实现第一个读寄存器端口
always @(*) 
begin 
	if(rst==`RstEnable)//当复位信号有效时
	begin
		rdata1 <= `ZeroWord;//第一个读寄存器端口的输出始终为0
	end
	else if(raddr1==`RegNumLog2'h0)//当复位信号无效时 如果读取的是$0 
	begin
		rdata1<=`ZeroWord;//直接给出0
	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;//直接输出0
	end
end
//第四段 读端口2的操作 实现第二个寄存器端口 具体过程和第三段相似 注意地址的变化
always @ (*)
begin
	if(rst==`RstEnable)
	begin
		rdata2<=`ZeroWord;
	end
	else if(raddr2==`RegNumLog2'h0)
	begin
		rdata2<=`ZeroWord;
	end
	else if((raddr2==waddr)&&(we==`WriteEnable)&&(re2==`ReadEnable))
	begin
		rdata2<=wdata;
	end
	else if(re2==`ReadEnable)
	begin
		rdata2<=regs[raddr2];
	end
	else
	begin
		rdata2<=`ZeroWord;
	end
end
endmodule

cp_reg.v

`include "define.v"

module cp0_reg(

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

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

			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    //if
	end      //always
			
	always @ (*) begin
		if(rst == `RstEnable) begin
			data_o <= `ZeroWord;
		end else begin
				case (raddr_i) 
					`CP0_REG_COUNT:		begin
						data_o <= count_o ;
					end
					`CP0_REG_COMPARE:	begin
						data_o <= compare_o ;
					end
					`CP0_REG_STATUS:	begin
						data_o <= status_o ;
					end
					`CP0_REG_CAUSE:	begin
						data_o <= cause_o ;
					end
					`CP0_REG_EPC:	begin
						data_o <= epc_o ;
					end
					`CP0_REG_PrId:	begin
						data_o <= prid_o ;
					end
					`CP0_REG_CONFIG:	begin
						data_o <= config_o ;
					end	
					default: 	begin
					end			
				endcase  //case addr_i			
		end    //if
	end      //always
endmodule

LLbit_reg.v

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

//异常是否发生 为1表示异常发生 为0表示没有异常
input wire flush,

//写操作
input wire LLbit_i,
input wire we,

//LLbit寄存器的值
output reg LLbit_o
);
always @ (posedge clk) begin
	if(rst == `RstEnable)begin
		LLbit_o <= 1'b0;
	end else if((flush == 1'b1))begin//如果异常发生 那么设置LLbit_o为0
		LLbit_o <= 1'b0;
	end else if((we == `WriteEnable))begin
		LLbit_o <= LLbit_i;
	end
end
endmodule
		

openmips.v

`include "define.v"

module openmips(

	input	wire										clk,
	input wire										rst,
	
  input wire[5:0]                int_i,
  
	input wire[`RegBus]           rom_data_i,
	output wire[`RegBus]           rom_addr_o,
	output wire                    rom_ce_o,
	
  //连接数据存储器data_ram
	input wire[`RegBus]           ram_data_i,
	output wire[`RegBus]           ram_addr_o,
	output wire[`RegBus]           ram_data_o,
	output wire                    ram_we_o,
	output wire[3:0]               ram_sel_o,
	output wire[3:0]               ram_ce_o,
	
	output wire                    timer_int_o
	
);

	wire[`InstAddrBus] pc;
	wire[`InstAddrBus] id_pc_i;
	wire[`InstBus] id_inst_i;
	
	//连接译码阶段ID模块的输出与ID/EX模块的输入
	wire[`AluOpBus] id_aluop_o;
	wire[`AluSelBus] id_alusel_o;
	wire[`RegBus] id_reg1_o;
	wire[`RegBus] id_reg2_o;
	wire id_wreg_o;
	wire[`RegAddrBus] id_wd_o;
	wire id_is_in_delayslot_o;
  wire[`RegBus] id_link_address_o;	
  wire[`RegBus] id_inst_o;
  wire[31:0] id_excepttype_o;
  wire[`RegBus] id_current_inst_address_o;
	
	//连接ID/EX模块的输出与执行阶段EX模块的输入
	wire[`AluOpBus] ex_aluop_i;
	wire[`AluSelBus] ex_alusel_i;
	wire[`RegBus] ex_reg1_i;
	wire[`RegBus] ex_reg2_i;
	wire ex_wreg_i;
	wire[`RegAddrBus] ex_wd_i;
	wire ex_is_in_delayslot_i;	
  wire[`RegBus] ex_link_address_i;	
  wire[`RegBus] ex_inst_i;
  wire[31:0] ex_excepttype_i;	
  wire[`RegBus] ex_current_inst_address_i;	
	
	//连接执行阶段EX模块的输出与EX/MEM模块的输入
	wire ex_wreg_o;
	wire[`RegAddrBus] ex_wd_o;
	wire[`RegBus] ex_wdata_o;
	wire[`RegBus] ex_hi_o;
	wire[`RegBus] ex_lo_o;
	wire ex_whilo_o;
	wire[`AluOpBus] ex_aluop_o;
	wire[`RegBus] ex_mem_addr_o;
	wire[`RegBus] ex_reg2_o;
	wire ex_cp0_reg_we_o;
	wire[4:0] ex_cp0_reg_write_addr_o;
	wire[`RegBus] ex_cp0_reg_data_o; 	
	wire[31:0] ex_excepttype_o;
	wire[`RegBus] ex_current_inst_address_o;
	wire ex_is_in_delayslot_o;

	//连接EX/MEM模块的输出与访存阶段MEM模块的输入
	wire mem_wreg_i;
	wire[`RegAddrBus] mem_wd_i;
	wire[`RegBus] mem_wdata_i;
	wire[`RegBus] mem_hi_i;
	wire[`RegBus] mem_lo_i;
	wire mem_whilo_i;		
	wire[`AluOpBus] mem_aluop_i;
	wire[`RegBus] mem_mem_addr_i;
	wire[`RegBus] mem_reg2_i;		
	wire mem_cp0_reg_we_i;
	wire[4:0] mem_cp0_reg_write_addr_i;
	wire[`RegBus] mem_cp0_reg_data_i;	
	wire[31:0] mem_excepttype_i;	
	wire mem_is_in_delayslot_i;
	wire[`RegBus] mem_current_inst_address_i;	

	//连接访存阶段MEM模块的输出与MEM/WB模块的输入
	wire mem_wreg_o;
	wire[`RegAddrBus] mem_wd_o;
	wire[`RegBus] mem_wdata_o;
	wire[`RegBus] mem_hi_o;
	wire[`RegBus] mem_lo_o;
	wire mem_whilo_o;	
	wire mem_LLbit_value_o;
	wire mem_LLbit_we_o;
	wire mem_cp0_reg_we_o;
	wire[4:0] mem_cp0_reg_write_addr_o;
	wire[`RegBus] mem_cp0_reg_data_o;	
	wire[31:0] mem_excepttype_o;
	wire mem_is_in_delayslot_o;
	wire[`RegBus] mem_current_inst_address_o;			
	
	//连接MEM/WB模块的输出与回写阶段的输入	
	wire wb_wreg_i;
	wire[`RegAddrBus] wb_wd_i;
	wire[`RegBus] wb_wdata_i;
	wire[`RegBus] wb_hi_i;
	wire[`RegBus] wb_lo_i;
	wire wb_whilo_i;	
	wire wb_LLbit_value_i;
	wire wb_LLbit_we_i;	
	wire wb_cp0_reg_we_i;
	wire[4:0] wb_cp0_reg_write_addr_i;
	wire[`RegBus] wb_cp0_reg_data_i;		
	wire[31:0] wb_excepttype_i;
	wire wb_is_in_delayslot_i;
	wire[`RegBus] wb_current_inst_address_i;
	
	//连接译码阶段ID模块与通用寄存器Regfile模块
  wire reg1_read;
  wire reg2_read;
  wire[`RegBus] reg1_data;
  wire[`RegBus] reg2_data;
  wire[`RegAddrBus] reg1_addr;
  wire[`RegAddrBus] reg2_addr;

	//连接执行阶段与hilo模块的输出,读取HI、LO寄存器
	wire[`RegBus] 	hi;
	wire[`RegBus]   lo;

  //连接执行阶段与ex_reg模块,用于多周期的MADD、MADDU、MSUB、MSUBU指令
	wire[`DoubleRegBus] hilo_temp_o;
	wire[1:0] cnt_o;
	
	wire[`DoubleRegBus] hilo_temp_i;
	wire[1:0] cnt_i;

	wire[`DoubleRegBus] div_result;
	wire div_ready;
	wire[`RegBus] div_opdata1;
	wire[`RegBus] div_opdata2;
	wire div_start;
	wire div_annul;
	wire signed_div;

	wire is_in_delayslot_i;
	wire is_in_delayslot_o;
	wire next_inst_in_delayslot_o;
	wire id_branch_flag_o;
	wire[`RegBus] branch_target_address;

	wire[5:0] stall;
	wire stallreq_from_id;	
	wire stallreq_from_ex;

	wire LLbit_o;

  wire[`RegBus] cp0_data_o;
  wire[4:0] cp0_raddr_i;
 
  wire flush;
  wire[`RegBus] new_pc;

	wire[`RegBus] cp0_count;
	wire[`RegBus]	cp0_compare;
	wire[`RegBus]	cp0_status;
	wire[`RegBus]	cp0_cause;
	wire[`RegBus]	cp0_epc;
	wire[`RegBus]	cp0_config;
	wire[`RegBus]	cp0_prid; 

  wire[`RegBus] latest_epc;
  
  //pc_reg例化
	pc_reg pc_reg0(
		.clk(clk),
		.rst(rst),
		.stall(stall),
		.flush(flush),
	  .new_pc(new_pc),
		.branch_flag_i(id_branch_flag_o),
		.branch_target_address_i(branch_target_address),		
		.pc(pc),
		.ce(rom_ce_o)	
			
	);
	
  assign rom_addr_o = pc;

  //IF/ID模块例化
	if_id if_id0(
		.clk(clk),
		.rst(rst),
		.stall(stall),
		.flush(flush),
		.if_pc(pc),
		.if_inst(rom_data_i),
		.id_pc(id_pc_i),
		.id_inst(id_inst_i)      	
	);
	
	//译码阶段ID模块
	id id0(
		.rst(rst),
		.pc_i(id_pc_i),
		.inst_i(id_inst_i),

  	.ex_aluop_i(ex_aluop_o),

		.reg1_data_i(reg1_data),
		.reg2_data_i(reg2_data),

	  //处于执行阶段的指令要写入的目的寄存器信息
		.ex_wreg_i(ex_wreg_o),
		.ex_wdata_i(ex_wdata_o),
		.ex_wd_i(ex_wd_o),

	  //处于访存阶段的指令要写入的目的寄存器信息
		.mem_wreg_i(mem_wreg_o),
		.mem_wdata_i(mem_wdata_o),
		.mem_wd_i(mem_wd_o),

	  .is_in_delayslot_i(is_in_delayslot_i),

		//送到regfile的信息
		.reg1_read_o(reg1_read),
		.reg2_read_o(reg2_read), 	  

		.reg1_addr_o(reg1_addr),
		.reg2_addr_o(reg2_addr), 
	  
		//送到ID/EX模块的信息
		.aluop_o(id_aluop_o),
		.alusel_o(id_alusel_o),
		.reg1_o(id_reg1_o),
		.reg2_o(id_reg2_o),
		.wd_o(id_wd_o),
		.wreg_o(id_wreg_o),
		.excepttype_o(id_excepttype_o),
		.inst_o(id_inst_o),

	 	.next_inst_in_delayslot_o(next_inst_in_delayslot_o),	
		.branch_flag_o(id_branch_flag_o),
		.branch_target_address_o(branch_target_address),       
		.link_addr_o(id_link_address_o),
		
		.is_in_delayslot_o(id_is_in_delayslot_o),
		.current_inst_address_o(id_current_inst_address_o),
		
		.stallreq(stallreq_from_id)		
	);

  //通用寄存器Regfile例化
	regfile regfile1(
		.clk (clk),
		.rst (rst),
		.we	(wb_wreg_i),
		.waddr (wb_wd_i),
		.wdata (wb_wdata_i),
		.re1 (reg1_read),
		.raddr1 (reg1_addr),
		.rdata1 (reg1_data),
		.re2 (reg2_read),
		.raddr2 (reg2_addr),
		.rdata2 (reg2_data)
	);

	//ID/EX模块
	id_ex id_ex0(
		.clk(clk),
		.rst(rst),
		
		.stall(stall),
		.flush(flush),
		
		//从译码阶段ID模块传递的信息
		.id_aluop(id_aluop_o),
		.id_alusel(id_alusel_o),
		.id_reg1(id_reg1_o),
		.id_reg2(id_reg2_o),
		.id_wd(id_wd_o),
		.id_wreg(id_wreg_o),
		.id_link_address(id_link_address_o),
		.id_is_in_delayslot(id_is_in_delayslot_o),
		.next_inst_in_delayslot_i(next_inst_in_delayslot_o),		
		.id_inst(id_inst_o),		
		.id_excepttype(id_excepttype_o),
		.id_current_inst_address(id_current_inst_address_o),
	
		//传递到执行阶段EX模块的信息
		.ex_aluop(ex_aluop_i),
		.ex_alusel(ex_alusel_i),
		.ex_reg1(ex_reg1_i),
		.ex_reg2(ex_reg2_i),
		.ex_wd(ex_wd_i),
		.ex_wreg(ex_wreg_i),
		.ex_link_address(ex_link_address_i),
  	.ex_is_in_delayslot(ex_is_in_delayslot_i),
		.is_in_delayslot_o(is_in_delayslot_i),
		.ex_inst(ex_inst_i),
		.ex_excepttype(ex_excepttype_i),
		.ex_current_inst_address(ex_current_inst_address_i)		
	);		
	
	//EX模块
	ex ex0(
		.rst(rst),
	
		//送到执行阶段EX模块的信息
		.aluop_i(ex_aluop_i),
		.alusel_i(ex_alusel_i),
		.reg1_i(ex_reg1_i),
		.reg2_i(ex_reg2_i),
		.wd_i(ex_wd_i),
		.wreg_i(ex_wreg_i),
		.hi_i(hi),
		.lo_i(lo),
		.inst_i(ex_inst_i),

	  .wb_hi_i(wb_hi_i),
	  .wb_lo_i(wb_lo_i),
	  .wb_whilo_i(wb_whilo_i),
	  .mem_hi_i(mem_hi_o),
	  .mem_lo_i(mem_lo_o),
	  .mem_whilo_i(mem_whilo_o),

	  .hilo_temp_i(hilo_temp_i),
	  .cnt_i(cnt_i),

		.div_result_i(div_result),
		.div_ready_i(div_ready), 

	  .link_address_i(ex_link_address_i),
		.is_in_delayslot_i(ex_is_in_delayslot_i),	  
		
		.excepttype_i(ex_excepttype_i),
		.current_inst_address_i(ex_current_inst_address_i),

		//访存阶段的指令是否要写CP0,用来检测数据相关
  	.mem_cp0_reg_we(mem_cp0_reg_we_o),
		.mem_cp0_reg_write_addr(mem_cp0_reg_write_addr_o),
		.mem_cp0_reg_data(mem_cp0_reg_data_o),
	
		//回写阶段的指令是否要写CP0,用来检测数据相关
  	.wb_cp0_reg_we(wb_cp0_reg_we_i),
		.wb_cp0_reg_write_addr(wb_cp0_reg_write_addr_i),
		.wb_cp0_reg_data(wb_cp0_reg_data_i),

		.cp0_reg_data_i(cp0_data_o),
		.cp0_reg_read_addr_o(cp0_raddr_i),
		
		//向下一流水级传递,用于写CP0中的寄存器
		.cp0_reg_we_o(ex_cp0_reg_we_o),
		.cp0_reg_write_addr_o(ex_cp0_reg_write_addr_o),
		.cp0_reg_data_o(ex_cp0_reg_data_o),	  
			  
	  //EX模块的输出到EX/MEM模块信息
		.wd_o(ex_wd_o),
		.wreg_o(ex_wreg_o),
		.wdata_o(ex_wdata_o),

		.hi_o(ex_hi_o),
		.lo_o(ex_lo_o),
		.whilo_o(ex_whilo_o),

		.hilo_temp_o(hilo_temp_o),
		.cnt_o(cnt_o),

		.div_opdata1_o(div_opdata1),
		.div_opdata2_o(div_opdata2),
		.div_start_o(div_start),
		.signed_div_o(signed_div),	

		.aluop_o(ex_aluop_o),
		.mem_addr_o(ex_mem_addr_o),
		.reg2_o(ex_reg2_o),
		
		.excepttype_o(ex_excepttype_o),
		.is_in_delayslot_o(ex_is_in_delayslot_o),
		.current_inst_address_o(ex_current_inst_address_o),	
		
		.stallreq(stallreq_from_ex)     				
		
	);

  //EX/MEM模块
  ex_mem ex_mem0(
		.clk(clk),
		.rst(rst),
	  
	  .stall(stall),
	  .flush(flush),
	  
		//来自执行阶段EX模块的信息	
		.ex_wd(ex_wd_o),
		.ex_wreg(ex_wreg_o),
		.ex_wdata(ex_wdata_o),
		.ex_hi(ex_hi_o),
		.ex_lo(ex_lo_o),
		.ex_whilo(ex_whilo_o),		

  	.ex_aluop(ex_aluop_o),
		.ex_mem_addr(ex_mem_addr_o),
		.ex_reg2(ex_reg2_o),			
	
		.ex_cp0_reg_we(ex_cp0_reg_we_o),
		.ex_cp0_reg_write_addr(ex_cp0_reg_write_addr_o),
		.ex_cp0_reg_data(ex_cp0_reg_data_o),	

    .ex_excepttype(ex_excepttype_o),
		.ex_is_in_delayslot(ex_is_in_delayslot_o),
		.ex_current_inst_address(ex_current_inst_address_o),	

		.hilo_i(hilo_temp_o),
		.cnt_i(cnt_o),	

		//送到访存阶段MEM模块的信息
		.mem_wd(mem_wd_i),
		.mem_wreg(mem_wreg_i),
		.mem_wdata(mem_wdata_i),
		.mem_hi(mem_hi_i),
		.mem_lo(mem_lo_i),
		.mem_whilo(mem_whilo_i),
	
		.mem_cp0_reg_we(mem_cp0_reg_we_i),
		.mem_cp0_reg_write_addr(mem_cp0_reg_write_addr_i),
		.mem_cp0_reg_data(mem_cp0_reg_data_i),

  	.mem_aluop(mem_aluop_i),
		.mem_mem_addr(mem_mem_addr_i),
		.mem_reg2(mem_reg2_i),
		
		.mem_excepttype(mem_excepttype_i),
  	.mem_is_in_delayslot(mem_is_in_delayslot_i),
		.mem_current_inst_address(mem_current_inst_address_i),
				
		.hilo_o(hilo_temp_i),
		.cnt_o(cnt_i)
						       	
	);
	
  //MEM模块例化
	mem mem0(
		.rst(rst),
	
		//来自EX/MEM模块的信息	
		.wd_i(mem_wd_i),
		.wreg_i(mem_wreg_i),
		.wdata_i(mem_wdata_i),
		.hi_i(mem_hi_i),
		.lo_i(mem_lo_i),
		.whilo_i(mem_whilo_i),		

  	.aluop_i(mem_aluop_i),
		.mem_addr_i(mem_mem_addr_i),
		.reg2_i(mem_reg2_i),
	
		//来自memory的信息
		.mem_data_i(ram_data_i),

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

		.cp0_reg_we_i(mem_cp0_reg_we_i),
		.cp0_reg_write_addr_i(mem_cp0_reg_write_addr_i),
		.cp0_reg_data_i(mem_cp0_reg_data_i),

    .excepttype_i(mem_excepttype_i),
		.is_in_delayslot_i(mem_is_in_delayslot_i),
		.current_inst_address_i(mem_current_inst_address_i),	
		
		.cp0_status_i(cp0_status),
		.cp0_cause_i(cp0_cause),
		.cp0_epc_i(cp0_epc),
		
		//回写阶段的指令是否要写CP0,用来检测数据相关
  	.wb_cp0_reg_we(wb_cp0_reg_we_i),
		.wb_cp0_reg_write_addr(wb_cp0_reg_write_addr_i),
		.wb_cp0_reg_data(wb_cp0_reg_data_i),	  

		.LLbit_we_o(mem_LLbit_we_o),
		.LLbit_value_o(mem_LLbit_value_o),

		.cp0_reg_we_o(mem_cp0_reg_we_o),
		.cp0_reg_write_addr_o(mem_cp0_reg_write_addr_o),
		.cp0_reg_data_o(mem_cp0_reg_data_o),			
	  
		//送到MEM/WB模块的信息
		.wd_o(mem_wd_o),
		.wreg_o(mem_wreg_o),
		.wdata_o(mem_wdata_o),
		.hi_o(mem_hi_o),
		.lo_o(mem_lo_o),
		.whilo_o(mem_whilo_o),
		
		//送到memory的信息
		.mem_addr_o(ram_addr_o),
		.mem_we_o(ram_we_o),
		.mem_sel_o(ram_sel_o),
		.mem_data_o(ram_data_o),
		.mem_ce_o(ram_ce_o),
		
		.excepttype_o(mem_excepttype_o),
		.cp0_epc_o(latest_epc),
		.is_in_delayslot_o(mem_is_in_delayslot_o),
		.current_inst_address_o(mem_current_inst_address_o)		
	);

  //MEM/WB模块
	mem_wb mem_wb0(
		.clk(clk),
		.rst(rst),

    .stall(stall),
    .flush(flush),

		//来自访存阶段MEM模块的信息	
		.mem_wd(mem_wd_o),
		.mem_wreg(mem_wreg_o),
		.mem_wdata(mem_wdata_o),
		.mem_hi(mem_hi_o),
		.mem_lo(mem_lo_o),
		.mem_whilo(mem_whilo_o),		

		.mem_LLbit_we(mem_LLbit_we_o),
		.mem_LLbit_value(mem_LLbit_value_o),	
	
		.mem_cp0_reg_we(mem_cp0_reg_we_o),
		.mem_cp0_reg_write_addr(mem_cp0_reg_write_addr_o),
		.mem_cp0_reg_data(mem_cp0_reg_data_o),					
	
		//送到回写阶段的信息
		.wb_wd(wb_wd_i),
		.wb_wreg(wb_wreg_i),
		.wb_wdata(wb_wdata_i),
		.wb_hi(wb_hi_i),
		.wb_lo(wb_lo_i),
		.wb_whilo(wb_whilo_i),

		.wb_LLbit_we(wb_LLbit_we_i),
		.wb_LLbit_value(wb_LLbit_value_i),
		
		.wb_cp0_reg_we(wb_cp0_reg_we_i),
		.wb_cp0_reg_write_addr(wb_cp0_reg_write_addr_i),
		.wb_cp0_reg_data(wb_cp0_reg_data_i)						
									       	
	);

	hilo_reg hilo_reg0(
		.clk(clk),
		.rst(rst),
	
		//写端口
		.we(wb_whilo_i),
		.hi_i(wb_hi_i),
		.lo_i(wb_lo_i),
	
		//读端口1
		.hi_o(hi),
		.lo_o(lo)	
	);
	
	ctrl ctrl0(
		.rst(rst),
	
	  .excepttype_i(mem_excepttype_o),
	  .cp0_epc_i(latest_epc),
 
		.stallreq_from_id(stallreq_from_id),
	
  	//来自执行阶段的暂停请求
		.stallreq_from_ex(stallreq_from_ex),
	  .new_pc(new_pc),
	  .flush(flush),
		.stall(stall)       	
	);

	div div0(
		.clk(clk),
		.rst(rst),
	
		.signed_div_i(signed_div),
		.opdata1_i(div_opdata1),
		.opdata2_i(div_opdata2),
		.start_i(div_start),
		.annul_i(flush),
	
		.result_o(div_result),
		.ready_o(div_ready)
	);

	LLbit_reg LLbit_reg0(
		.clk(clk),
		.rst(rst),
	  .flush(flush),
	  
		//写端口
		.LLbit_i(wb_LLbit_value_i),
		.we(wb_LLbit_we_i),
	
		//读端口1
		.LLbit_o(LLbit_o)
	
	);

	cp0_reg cp0_reg0(
		.clk(clk),
		.rst(rst),
		
		.we_i(wb_cp0_reg_we_i),
		.waddr_i(wb_cp0_reg_write_addr_i),
		.raddr_i(cp0_raddr_i),
		.data_i(wb_cp0_reg_data_i),
		
		.excepttype_i(mem_excepttype_o),
		.int_i(int_i),
		.current_inst_addr_i(mem_current_inst_address_o),
		.is_in_delayslot_i(mem_is_in_delayslot_o),
		
		.data_o(cp0_data_o),
		.count_o(cp0_count),
		.compare_o(cp0_compare),
		.status_o(cp0_status),
		.cause_o(cp0_cause),
		.epc_o(cp0_epc),
		.config_o(cp0_config),
		.prid_o(cp0_prid),
		
		
		.timer_int_o(timer_int_o)  			
	);
	
endmodule

openmips_min_sopc.v

`include "define.v"

module openmips(

	input	wire										clk,
	input wire										rst,
	
  input wire[5:0]                int_i,
  
	input wire[`RegBus]           rom_data_i,
	output wire[`RegBus]           rom_addr_o,
	output wire                    rom_ce_o,
	
  //连接数据存储器data_ram
	input wire[`RegBus]           ram_data_i,
	output wire[`RegBus]           ram_addr_o,
	output wire[`RegBus]           ram_data_o,
	output wire                    ram_we_o,
	output wire[3:0]               ram_sel_o,
	output wire[3:0]               ram_ce_o,
	
	output wire                    timer_int_o
	
);

	wire[`InstAddrBus] pc;
	wire[`InstAddrBus] id_pc_i;
	wire[`InstBus] id_inst_i;
	
	//连接译码阶段ID模块的输出与ID/EX模块的输入
	wire[`AluOpBus] id_aluop_o;
	wire[`AluSelBus] id_alusel_o;
	wire[`RegBus] id_reg1_o;
	wire[`RegBus] id_reg2_o;
	wire id_wreg_o;
	wire[`RegAddrBus] id_wd_o;
	wire id_is_in_delayslot_o;
  wire[`RegBus] id_link_address_o;	
  wire[`RegBus] id_inst_o;
  wire[31:0] id_excepttype_o;
  wire[`RegBus] id_current_inst_address_o;
	
	//连接ID/EX模块的输出与执行阶段EX模块的输入
	wire[`AluOpBus] ex_aluop_i;
	wire[`AluSelBus] ex_alusel_i;
	wire[`RegBus] ex_reg1_i;
	wire[`RegBus] ex_reg2_i;
	wire ex_wreg_i;
	wire[`RegAddrBus] ex_wd_i;
	wire ex_is_in_delayslot_i;	
  wire[`RegBus] ex_link_address_i;	
  wire[`RegBus] ex_inst_i;
  wire[31:0] ex_excepttype_i;	
  wire[`RegBus] ex_current_inst_address_i;	
	
	//连接执行阶段EX模块的输出与EX/MEM模块的输入
	wire ex_wreg_o;
	wire[`RegAddrBus] ex_wd_o;
	wire[`RegBus] ex_wdata_o;
	wire[`RegBus] ex_hi_o;
	wire[`RegBus] ex_lo_o;
	wire ex_whilo_o;
	wire[`AluOpBus] ex_aluop_o;
	wire[`RegBus] ex_mem_addr_o;
	wire[`RegBus] ex_reg2_o;
	wire ex_cp0_reg_we_o;
	wire[4:0] ex_cp0_reg_write_addr_o;
	wire[`RegBus] ex_cp0_reg_data_o; 	
	wire[31:0] ex_excepttype_o;
	wire[`RegBus] ex_current_inst_address_o;
	wire ex_is_in_delayslot_o;

	//连接EX/MEM模块的输出与访存阶段MEM模块的输入
	wire mem_wreg_i;
	wire[`RegAddrBus] mem_wd_i;
	wire[`RegBus] mem_wdata_i;
	wire[`RegBus] mem_hi_i;
	wire[`RegBus] mem_lo_i;
	wire mem_whilo_i;		
	wire[`AluOpBus] mem_aluop_i;
	wire[`RegBus] mem_mem_addr_i;
	wire[`RegBus] mem_reg2_i;		
	wire mem_cp0_reg_we_i;
	wire[4:0] mem_cp0_reg_write_addr_i;
	wire[`RegBus] mem_cp0_reg_data_i;	
	wire[31:0] mem_excepttype_i;	
	wire mem_is_in_delayslot_i;
	wire[`RegBus] mem_current_inst_address_i;	

	//连接访存阶段MEM模块的输出与MEM/WB模块的输入
	wire mem_wreg_o;
	wire[`RegAddrBus] mem_wd_o;
	wire[`RegBus] mem_wdata_o;
	wire[`RegBus] mem_hi_o;
	wire[`RegBus] mem_lo_o;
	wire mem_whilo_o;	
	wire mem_LLbit_value_o;
	wire mem_LLbit_we_o;
	wire mem_cp0_reg_we_o;
	wire[4:0] mem_cp0_reg_write_addr_o;
	wire[`RegBus] mem_cp0_reg_data_o;	
	wire[31:0] mem_excepttype_o;
	wire mem_is_in_delayslot_o;
	wire[`RegBus] mem_current_inst_address_o;			
	
	//连接MEM/WB模块的输出与回写阶段的输入	
	wire wb_wreg_i;
	wire[`RegAddrBus] wb_wd_i;
	wire[`RegBus] wb_wdata_i;
	wire[`RegBus] wb_hi_i;
	wire[`RegBus] wb_lo_i;
	wire wb_whilo_i;	
	wire wb_LLbit_value_i;
	wire wb_LLbit_we_i;	
	wire wb_cp0_reg_we_i;
	wire[4:0] wb_cp0_reg_write_addr_i;
	wire[`RegBus] wb_cp0_reg_data_i;		
	wire[31:0] wb_excepttype_i;
	wire wb_is_in_delayslot_i;
	wire[`RegBus] wb_current_inst_address_i;
	
	//连接译码阶段ID模块与通用寄存器Regfile模块
  wire reg1_read;
  wire reg2_read;
  wire[`RegBus] reg1_data;
  wire[`RegBus] reg2_data;
  wire[`RegAddrBus] reg1_addr;
  wire[`RegAddrBus] reg2_addr;

	//连接执行阶段与hilo模块的输出,读取HI、LO寄存器
	wire[`RegBus] 	hi;
	wire[`RegBus]   lo;

  //连接执行阶段与ex_reg模块,用于多周期的MADD、MADDU、MSUB、MSUBU指令
	wire[`DoubleRegBus] hilo_temp_o;
	wire[1:0] cnt_o;
	
	wire[`DoubleRegBus] hilo_temp_i;
	wire[1:0] cnt_i;

	wire[`DoubleRegBus] div_result;
	wire div_ready;
	wire[`RegBus] div_opdata1;
	wire[`RegBus] div_opdata2;
	wire div_start;
	wire div_annul;
	wire signed_div;

	wire is_in_delayslot_i;
	wire is_in_delayslot_o;
	wire next_inst_in_delayslot_o;
	wire id_branch_flag_o;
	wire[`RegBus] branch_target_address;

	wire[5:0] stall;
	wire stallreq_from_id;	
	wire stallreq_from_ex;

	wire LLbit_o;

  wire[`RegBus] cp0_data_o;
  wire[4:0] cp0_raddr_i;
 
  wire flush;
  wire[`RegBus] new_pc;

	wire[`RegBus] cp0_count;
	wire[`RegBus]	cp0_compare;
	wire[`RegBus]	cp0_status;
	wire[`RegBus]	cp0_cause;
	wire[`RegBus]	cp0_epc;
	wire[`RegBus]	cp0_config;
	wire[`RegBus]	cp0_prid; 

  wire[`RegBus] latest_epc;
  
  //pc_reg例化
	pc_reg pc_reg0(
		.clk(clk),
		.rst(rst),
		.stall(stall),
		.flush(flush),
	  .new_pc(new_pc),
		.branch_flag_i(id_branch_flag_o),
		.branch_target_address_i(branch_target_address),		
		.pc(pc),
		.ce(rom_ce_o)	
			
	);
	
  assign rom_addr_o = pc;

  //IF/ID模块例化
	if_id if_id0(
		.clk(clk),
		.rst(rst),
		.stall(stall),
		.flush(flush),
		.if_pc(pc),
		.if_inst(rom_data_i),
		.id_pc(id_pc_i),
		.id_inst(id_inst_i)      	
	);
	
	//译码阶段ID模块
	id id0(
		.rst(rst),
		.pc_i(id_pc_i),
		.inst_i(id_inst_i),

  	.ex_aluop_i(ex_aluop_o),

		.reg1_data_i(reg1_data),
		.reg2_data_i(reg2_data),

	  //处于执行阶段的指令要写入的目的寄存器信息
		.ex_wreg_i(ex_wreg_o),
		.ex_wdata_i(ex_wdata_o),
		.ex_wd_i(ex_wd_o),

	  //处于访存阶段的指令要写入的目的寄存器信息
		.mem_wreg_i(mem_wreg_o),
		.mem_wdata_i(mem_wdata_o),
		.mem_wd_i(mem_wd_o),

	  .is_in_delayslot_i(is_in_delayslot_i),

		//送到regfile的信息
		.reg1_read_o(reg1_read),
		.reg2_read_o(reg2_read), 	  

		.reg1_addr_o(reg1_addr),
		.reg2_addr_o(reg2_addr), 
	  
		//送到ID/EX模块的信息
		.aluop_o(id_aluop_o),
		.alusel_o(id_alusel_o),
		.reg1_o(id_reg1_o),
		.reg2_o(id_reg2_o),
		.wd_o(id_wd_o),
		.wreg_o(id_wreg_o),
		.excepttype_o(id_excepttype_o),
		.inst_o(id_inst_o),

	 	.next_inst_in_delayslot_o(next_inst_in_delayslot_o),	
		.branch_flag_o(id_branch_flag_o),
		.branch_target_address_o(branch_target_address),       
		.link_addr_o(id_link_address_o),
		
		.is_in_delayslot_o(id_is_in_delayslot_o),
		.current_inst_address_o(id_current_inst_address_o),
		
		.stallreq(stallreq_from_id)		
	);

  //通用寄存器Regfile例化
	regfile regfile1(
		.clk (clk),
		.rst (rst),
		.we	(wb_wreg_i),
		.waddr (wb_wd_i),
		.wdata (wb_wdata_i),
		.re1 (reg1_read),
		.raddr1 (reg1_addr),
		.rdata1 (reg1_data),
		.re2 (reg2_read),
		.raddr2 (reg2_addr),
		.rdata2 (reg2_data)
	);

	//ID/EX模块
	id_ex id_ex0(
		.clk(clk),
		.rst(rst),
		
		.stall(stall),
		.flush(flush),
		
		//从译码阶段ID模块传递的信息
		.id_aluop(id_aluop_o),
		.id_alusel(id_alusel_o),
		.id_reg1(id_reg1_o),
		.id_reg2(id_reg2_o),
		.id_wd(id_wd_o),
		.id_wreg(id_wreg_o),
		.id_link_address(id_link_address_o),
		.id_is_in_delayslot(id_is_in_delayslot_o),
		.next_inst_in_delayslot_i(next_inst_in_delayslot_o),		
		.id_inst(id_inst_o),		
		.id_excepttype(id_excepttype_o),
		.id_current_inst_address(id_current_inst_address_o),
	
		//传递到执行阶段EX模块的信息
		.ex_aluop(ex_aluop_i),
		.ex_alusel(ex_alusel_i),
		.ex_reg1(ex_reg1_i),
		.ex_reg2(ex_reg2_i),
		.ex_wd(ex_wd_i),
		.ex_wreg(ex_wreg_i),
		.ex_link_address(ex_link_address_i),
  	.ex_is_in_delayslot(ex_is_in_delayslot_i),
		.is_in_delayslot_o(is_in_delayslot_i),
		.ex_inst(ex_inst_i),
		.ex_excepttype(ex_excepttype_i),
		.ex_current_inst_address(ex_current_inst_address_i)		
	);		
	
	//EX模块
	ex ex0(
		.rst(rst),
	
		//送到执行阶段EX模块的信息
		.aluop_i(ex_aluop_i),
		.alusel_i(ex_alusel_i),
		.reg1_i(ex_reg1_i),
		.reg2_i(ex_reg2_i),
		.wd_i(ex_wd_i),
		.wreg_i(ex_wreg_i),
		.hi_i(hi),
		.lo_i(lo),
		.inst_i(ex_inst_i),

	  .wb_hi_i(wb_hi_i),
	  .wb_lo_i(wb_lo_i),
	  .wb_whilo_i(wb_whilo_i),
	  .mem_hi_i(mem_hi_o),
	  .mem_lo_i(mem_lo_o),
	  .mem_whilo_i(mem_whilo_o),

	  .hilo_temp_i(hilo_temp_i),
	  .cnt_i(cnt_i),

		.div_result_i(div_result),
		.div_ready_i(div_ready), 

	  .link_address_i(ex_link_address_i),
		.is_in_delayslot_i(ex_is_in_delayslot_i),	  
		
		.excepttype_i(ex_excepttype_i),
		.current_inst_address_i(ex_current_inst_address_i),

		//访存阶段的指令是否要写CP0,用来检测数据相关
  	.mem_cp0_reg_we(mem_cp0_reg_we_o),
		.mem_cp0_reg_write_addr(mem_cp0_reg_write_addr_o),
		.mem_cp0_reg_data(mem_cp0_reg_data_o),
	
		//回写阶段的指令是否要写CP0,用来检测数据相关
  	.wb_cp0_reg_we(wb_cp0_reg_we_i),
		.wb_cp0_reg_write_addr(wb_cp0_reg_write_addr_i),
		.wb_cp0_reg_data(wb_cp0_reg_data_i),

		.cp0_reg_data_i(cp0_data_o),
		.cp0_reg_read_addr_o(cp0_raddr_i),
		
		//向下一流水级传递,用于写CP0中的寄存器
		.cp0_reg_we_o(ex_cp0_reg_we_o),
		.cp0_reg_write_addr_o(ex_cp0_reg_write_addr_o),
		.cp0_reg_data_o(ex_cp0_reg_data_o),	  
			  
	  //EX模块的输出到EX/MEM模块信息
		.wd_o(ex_wd_o),
		.wreg_o(ex_wreg_o),
		.wdata_o(ex_wdata_o),

		.hi_o(ex_hi_o),
		.lo_o(ex_lo_o),
		.whilo_o(ex_whilo_o),

		.hilo_temp_o(hilo_temp_o),
		.cnt_o(cnt_o),

		.div_opdata1_o(div_opdata1),
		.div_opdata2_o(div_opdata2),
		.div_start_o(div_start),
		.signed_div_o(signed_div),	

		.aluop_o(ex_aluop_o),
		.mem_addr_o(ex_mem_addr_o),
		.reg2_o(ex_reg2_o),
		
		.excepttype_o(ex_excepttype_o),
		.is_in_delayslot_o(ex_is_in_delayslot_o),
		.current_inst_address_o(ex_current_inst_address_o),	
		
		.stallreq(stallreq_from_ex)     				
		
	);

  //EX/MEM模块
  ex_mem ex_mem0(
		.clk(clk),
		.rst(rst),
	  
	  .stall(stall),
	  .flush(flush),
	  
		//来自执行阶段EX模块的信息	
		.ex_wd(ex_wd_o),
		.ex_wreg(ex_wreg_o),
		.ex_wdata(ex_wdata_o),
		.ex_hi(ex_hi_o),
		.ex_lo(ex_lo_o),
		.ex_whilo(ex_whilo_o),		

  	.ex_aluop(ex_aluop_o),
		.ex_mem_addr(ex_mem_addr_o),
		.ex_reg2(ex_reg2_o),			
	
		.ex_cp0_reg_we(ex_cp0_reg_we_o),
		.ex_cp0_reg_write_addr(ex_cp0_reg_write_addr_o),
		.ex_cp0_reg_data(ex_cp0_reg_data_o),	

    .ex_excepttype(ex_excepttype_o),
		.ex_is_in_delayslot(ex_is_in_delayslot_o),
		.ex_current_inst_address(ex_current_inst_address_o),	

		.hilo_i(hilo_temp_o),
		.cnt_i(cnt_o),	

		//送到访存阶段MEM模块的信息
		.mem_wd(mem_wd_i),
		.mem_wreg(mem_wreg_i),
		.mem_wdata(mem_wdata_i),
		.mem_hi(mem_hi_i),
		.mem_lo(mem_lo_i),
		.mem_whilo(mem_whilo_i),
	
		.mem_cp0_reg_we(mem_cp0_reg_we_i),
		.mem_cp0_reg_write_addr(mem_cp0_reg_write_addr_i),
		.mem_cp0_reg_data(mem_cp0_reg_data_i),

  	.mem_aluop(mem_aluop_i),
		.mem_mem_addr(mem_mem_addr_i),
		.mem_reg2(mem_reg2_i),
		
		.mem_excepttype(mem_excepttype_i),
  	.mem_is_in_delayslot(mem_is_in_delayslot_i),
		.mem_current_inst_address(mem_current_inst_address_i),
				
		.hilo_o(hilo_temp_i),
		.cnt_o(cnt_i)
						       	
	);
	
  //MEM模块例化
	mem mem0(
		.rst(rst),
	
		//来自EX/MEM模块的信息	
		.wd_i(mem_wd_i),
		.wreg_i(mem_wreg_i),
		.wdata_i(mem_wdata_i),
		.hi_i(mem_hi_i),
		.lo_i(mem_lo_i),
		.whilo_i(mem_whilo_i),		

  	.aluop_i(mem_aluop_i),
		.mem_addr_i(mem_mem_addr_i),
		.reg2_i(mem_reg2_i),
	
		//来自memory的信息
		.mem_data_i(ram_data_i),

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

		.cp0_reg_we_i(mem_cp0_reg_we_i),
		.cp0_reg_write_addr_i(mem_cp0_reg_write_addr_i),
		.cp0_reg_data_i(mem_cp0_reg_data_i),

    .excepttype_i(mem_excepttype_i),
		.is_in_delayslot_i(mem_is_in_delayslot_i),
		.current_inst_address_i(mem_current_inst_address_i),	
		
		.cp0_status_i(cp0_status),
		.cp0_cause_i(cp0_cause),
		.cp0_epc_i(cp0_epc),
		
		//回写阶段的指令是否要写CP0,用来检测数据相关
  	.wb_cp0_reg_we(wb_cp0_reg_we_i),
		.wb_cp0_reg_write_addr(wb_cp0_reg_write_addr_i),
		.wb_cp0_reg_data(wb_cp0_reg_data_i),	  

		.LLbit_we_o(mem_LLbit_we_o),
		.LLbit_value_o(mem_LLbit_value_o),

		.cp0_reg_we_o(mem_cp0_reg_we_o),
		.cp0_reg_write_addr_o(mem_cp0_reg_write_addr_o),
		.cp0_reg_data_o(mem_cp0_reg_data_o),			
	  
		//送到MEM/WB模块的信息
		.wd_o(mem_wd_o),
		.wreg_o(mem_wreg_o),
		.wdata_o(mem_wdata_o),
		.hi_o(mem_hi_o),
		.lo_o(mem_lo_o),
		.whilo_o(mem_whilo_o),
		
		//送到memory的信息
		.mem_addr_o(ram_addr_o),
		.mem_we_o(ram_we_o),
		.mem_sel_o(ram_sel_o),
		.mem_data_o(ram_data_o),
		.mem_ce_o(ram_ce_o),
		
		.excepttype_o(mem_excepttype_o),
		.cp0_epc_o(latest_epc),
		.is_in_delayslot_o(mem_is_in_delayslot_o),
		.current_inst_address_o(mem_current_inst_address_o)		
	);

  //MEM/WB模块
	mem_wb mem_wb0(
		.clk(clk),
		.rst(rst),

    .stall(stall),
    .flush(flush),

		//来自访存阶段MEM模块的信息	
		.mem_wd(mem_wd_o),
		.mem_wreg(mem_wreg_o),
		.mem_wdata(mem_wdata_o),
		.mem_hi(mem_hi_o),
		.mem_lo(mem_lo_o),
		.mem_whilo(mem_whilo_o),		

		.mem_LLbit_we(mem_LLbit_we_o),
		.mem_LLbit_value(mem_LLbit_value_o),	
	
		.mem_cp0_reg_we(mem_cp0_reg_we_o),
		.mem_cp0_reg_write_addr(mem_cp0_reg_write_addr_o),
		.mem_cp0_reg_data(mem_cp0_reg_data_o),					
	
		//送到回写阶段的信息
		.wb_wd(wb_wd_i),
		.wb_wreg(wb_wreg_i),
		.wb_wdata(wb_wdata_i),
		.wb_hi(wb_hi_i),
		.wb_lo(wb_lo_i),
		.wb_whilo(wb_whilo_i),

		.wb_LLbit_we(wb_LLbit_we_i),
		.wb_LLbit_value(wb_LLbit_value_i),
		
		.wb_cp0_reg_we(wb_cp0_reg_we_i),
		.wb_cp0_reg_write_addr(wb_cp0_reg_write_addr_i),
		.wb_cp0_reg_data(wb_cp0_reg_data_i)						
									       	
	);

	hilo_reg hilo_reg0(
		.clk(clk),
		.rst(rst),
	
		//写端口
		.we(wb_whilo_i),
		.hi_i(wb_hi_i),
		.lo_i(wb_lo_i),
	
		//读端口1
		.hi_o(hi),
		.lo_o(lo)	
	);
	
	ctrl ctrl0(
		.rst(rst),
	
	  .excepttype_i(mem_excepttype_o),
	  .cp0_epc_i(latest_epc),
 
		.stallreq_from_id(stallreq_from_id),
	
  	//来自执行阶段的暂停请求
		.stallreq_from_ex(stallreq_from_ex),
	  .new_pc(new_pc),
	  .flush(flush),
		.stall(stall)       	
	);

	div div0(
		.clk(clk),
		.rst(rst),
	
		.signed_div_i(signed_div),
		.opdata1_i(div_opdata1),
		.opdata2_i(div_opdata2),
		.start_i(div_start),
		.annul_i(flush),
	
		.result_o(div_result),
		.ready_o(div_ready)
	);

	LLbit_reg LLbit_reg0(
		.clk(clk),
		.rst(rst),
	  .flush(flush),
	  
		//写端口
		.LLbit_i(wb_LLbit_value_i),
		.we(wb_LLbit_we_i),
	
		//读端口1
		.LLbit_o(LLbit_o)
	
	);

	cp0_reg cp0_reg0(
		.clk(clk),
		.rst(rst),
		
		.we_i(wb_cp0_reg_we_i),
		.waddr_i(wb_cp0_reg_write_addr_i),
		.raddr_i(cp0_raddr_i),
		.data_i(wb_cp0_reg_data_i),
		
		.excepttype_i(mem_excepttype_o),
		.int_i(int_i),
		.current_inst_addr_i(mem_current_inst_address_o),
		.is_in_delayslot_i(mem_is_in_delayslot_o),
		
		.data_o(cp0_data_o),
		.count_o(cp0_count),
		.compare_o(cp0_compare),
		.status_o(cp0_status),
		.cause_o(cp0_cause),
		.epc_o(cp0_epc),
		.config_o(cp0_config),
		.prid_o(cp0_prid),
		
		
		.timer_int_o(timer_int_o)  			
	);
	
endmodule

opemmips_min_sopc_tb.v

`include "define.v"
//·*//建立TestBench文件
//时间单位是1ns,精度是1ps
`timescale 1ns/1ps
module openmips_min_sopc_tb();
reg CLOCK_50;
reg rst;
//每隔10ns,CLOCK_50信号翻转一次,所以下一个时钟周期是20ns,对应50MHz
initial begin
	CLOCK_50 = 1'b0;
	forever #10 CLOCK_50 = ~CLOCK_50;
end
//最初时刻,复位信号有效,在第195ns复位信号无效 最小SOPC开始运行
//运行1000ns后,暂停仿真
initial begin
	rst = `RstEnable;
	#195 rst = `RstDisable;
	#1000 $stop;
end
//例化最小SOPC
openmips_min_sopc openmips_min_sopc0(
.clk(CLOCK_50),
.rst(rst)
);
endmodule

测试文件和结果

测试文件分为3个,分别对系统调用异常自陷异常,时钟和中断进行测试,结果就是看各个寄存器的值是否和指令中的相符。测试文件和结果就不放出来了。

完结撒花
在这里插入图片描述

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-06-08 19:10:53  更:2022-06-08 19:11:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 1:50:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码