4实现中断异常相关指令-2【FPGA模型机课程设计】

这篇具有很好参考价值的文章主要介绍了4实现中断异常相关指令-2【FPGA模型机课程设计】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

2023-5-23 16:43:50

以下内容源自《【FPGA模型机课程设计】》
仅供学习交流使用

修改

2023-6-3 17:24:24

系统调用和异常返回的功能 不完善

需要在Mem中添加对LLbit<-0的代码

并且新增测试
对原子指令的失败测试

推荐

0集中实践环节计划书【FPGA模型机课程设计】

4实现中断异常相关指令-2

安排

第一周周四:

选择MIPS与中断异常相关的6条指令,继续将完整模型机的指令进行实现。学生将在Modelsim里仿真验证通过的模型机程序,并编写具体测试指令,能够通过简单的中断异常机器指令对中断异常等功能进行测试。

表3 MIPS 与中断异常相关6条指令

上篇文章实现原子指令(前两条指令)
本篇文章实现中断异常指令(后四条指令)

4实现中断异常相关指令-2【FPGA模型机课程设计】

测试与结果

		//测试中断指令
		
		//测试syscall
		instmem[6]=32'h0000000c;//syscall instruction

		instmem[7]=32'h3407ffff;//ori
		instmem[8]=32'h3408ffff;//ori

		instmem [16]=32'h340affff;//syscall except program
		instmem [17]=32'h340bffff;//ori
		instmem [18]=32'h42000018;//eret inatruction


4实现中断异常相关指令-2【FPGA模型机课程设计】

		//测试定时中断
		instmem[0] =32'h34020000; 	//ori $2, $0,0
		instmem[1]= 32'h34010014; 	//ori $1, $0,20
		instmem[2]= 32'h40815800; 	//mtc0 $1,$11 set compare=20
		instmem[3]=32'h3c011000;	//lui $1, 0x1000
		instmem[4]=32'h34210401;	//ori $1, $1,0x0401
		instmem[5]= 32'h40816000; 	//mtc0 $1,$12 set status,enable int
		instmem[6]= 32'h08000006; 	//lpt: j lpt
		//interproc first addr Ox0050
		instmem[20]= 32'h34030001; 	//ORI $3,$0,1
		instmem[21]= 32'h34040014;	//ORI S4, $0,20
		instmem[22]= 32'h00431020;	//ADD $2,$2,$3
		instmem[23]= 32'h40015800;	//MFC $1,$11 read compare
		instmem[24]=32'h00240820; 	//ADD $1,$1,$4
		instmem[25]= 32'h40815800;	//MTC0 s1,$11 set compare
		instmem[26]= 32'h42000018;	//eret


0-6
4实现中断异常相关指令-2【FPGA模型机课程设计】

等待count== compare
4实现中断异常相关指令-2【FPGA模型机课程设计】
然后执行中断程序
执行完成异常返回
4实现中断异常相关指令-2【FPGA模型机课程设计】
继续等待count== compare
4实现中断异常相关指令-2【FPGA模型机课程设计】

测试原子指令-失败案例

在原有的sc指令的前面添加系统调用指令
把LLbit<-0
导致sc把r7<-0

		//测试原子功能--失败测试
		//R1=00001100 R2=00000020 
		//Lpt: 	LL r7,0x20(r1)		//读取程序里的信号量,LLibt=1
		//ll r7,0x20(r2) --(r7)=mem[72]=0
		instmem [6] = 32'b110000_00001_00111_0000_0000_0010_0000;//ll r7,0x20(r1)
		//if(r7 == clearFlag)	//判断信号是否被占用,为clearFlag表示没占用
		//pc=jaddr=npc+S14 offset(16) 00(2)
		//bne,r7,r0,else(+4)
		instmem [7] = 32'b000101_00111_00000_0000_0000_0000_0100;//bne,r7,r0,else(+4)
		//{
		//	MOV r7, setFlag			//设置本程序的占用标志
		//ori R7,ffff -- R7 --0000ffff
        instmem [8] = 32'h3407ffff;	//ori  R7 ffff

		//系统调用 把LLbit<-0
		instmem[9]=32'h0000000c;//syscall instruction
		//	SC r7, 0x20(r1)			//设置到信号量里  设置失败因为LLbit=0
		instmem [10] = 32'b111000_00001_00111_0000_0000_0010_0000;//sc r7,0x20(r1)
		//	if(r7 == 1) goto Success//如果信号量设置成功,r1就会为1
		//pc=jaddr=npc+S14 offset(16) 00(2)
		//bne,r1,r0,Success(+2)
		instmem [11] = 32'b000101_00111_00000_0000_0000_0000_0010;//bne,r7,r0,Success(+2)
		//	//如果信号量没有设置成功,重新读信号量,即重新执行LL指令
		//	else goto Lpt
		//j Lpt(6)
		//pc=jaddr=npc(4) offset(26) 00(2)	
		instmem [12] = 32'h08000006;//j Lpt(6) 编码000010  pc=0018 
		//}
		//else goto Lpt
		//j Lpt(6)
		//pc=jaddr=npc(4) offset(26) 00(2)	
		instmem [13] =  32'h08000006;//j Lpt(6) 编码000010  pc=0018 
		//Success:
		//	访问指定的存储区域
		//	set r7,clearFlag
		//andi R7,0000 -- R7 --00000000
        instmem [14] = 32'h30070000;	//andi R7,0000
		//	lw r7,(0x20)r1
		instmem[15]=32'b100011_00001_00111_0000_0000_0010_0000; //lw r7,0x20(r1)

		//系统调用程序
		instmem [16]=32'h340affff;//syscall except program
		instmem [17]=32'h340bffff;//ori
		instmem [18]=32'h42000018;//eret inatruction


4实现中断异常相关指令-2【FPGA模型机课程设计】

中断异常指令设计

参考:教学资料

4.5 异常与中断处理

4.5.1 异常与中断的概念

异常(exception)和中断(interruput)都是不可预知事件,会打扰程序的正常执行。广义上讲异常包括中断,即所有处理器外部和内部突发事件都可以归为异常。狭义上讲异常是指由指令执行引发的,可以说是处理器内部产生的,例如除法运算时除数为 0;而中断是外部事件,可以理解为是外部硬件事件触发的,例如键盘输入。本书所指异常一般为处理器内部引发,即指令执行所引发,当异常指所有突发事件(包括中断)时会加以说明。本书所指中断是由处理器外部事件触发。

当一个异常或中断发生时,CPU 应该停止当前程序的执行,转去执行异常或中断服务程序。当异常或中断服务程序执行结束后,应返回断点,继续执行主程序。这个过程称为异常或中断处理过程。

4实现中断异常相关指令-2【FPGA模型机课程设计】
断点即返回地址,MIPS 处理器对异常和中断所保存的“返回地址”有所不同,异常发生时,返回地址是当前指令的下一条指令地址(NPC),因为引发异常的指令已经被响应过了,不需要再重复执行。而外部中断发生时,返回地址是当前指令地址(PC),因为当前指令的执行被打断,中断返回后需重新执行。

4实现中断异常相关指令-2【FPGA模型机课程设计】
MIPS 处理器使用 EPC 保存断点,即异常或中断返回地址都由 EPC 保存,没有使用堆栈。本书设计中断和异常处理都为单级,即不允许中断或异常嵌套。

4.5.2 协处理器 CP0

MIPS 处理器设计了协处理器 CP0 专门用于异常和中断处理。首先介绍 CP0 中有 32 个 32 位寄存器。本书中所需要用到的寄存器有:Cause、Status、Count、Compare、EPC 这 5 个寄存器。
(1) Cause 寄存器(十进制寄存器地址 13)
Cause 寄存器主要用于记录当前异常和中断的信息。如图 4.5.2-1 所示,只列出了与本书中异常和中断有关的位。另外,Cause[9:8]和 Cause[23:22]字段是可写的,其余字段只可读。

4实现中断异常相关指令-2【FPGA模型机课程设计】

其中,ExcCode 用来记录当前发生的是何种异常(广义的异常,包含中断)。ExcCode 对应的编码表,本书中仅涉及到中断和系统调用异常 Syscall。如表所示:

4实现中断异常相关指令-2【FPGA模型机课程设计】

如果是中断,则根据 IP[7:0]来确定是哪一个中断。对应的位为 1 表示发生中断,为 0 则未发生相应中断。

4实现中断异常相关指令-2【FPGA模型机课程设计】

(2) Status 寄存器(十进制寄存器地址 12)
Status 寄存器用记录异常或中断的状态,并可以控制异常和中断是否响应。如图所示,只列出与本书中异常和中断有关的位:

4实现中断异常相关指令-2【FPGA模型机课程设计】

如图 4.5.2-2 所示,EXL 表示当前是否处于异常(广义的异常,包含中断)处理中,为 1 表示处于异常处理中,为 0 表示未处于异常处理中。IE 是中断允许标识,IE 为 1 表示允许对中断请求进行处理,为 0 则对中断请求不处理。IM[7:0]是中断屏蔽位,对应 Cause 寄存器的中断源 IP[7:0]。IM[7:0]的某位为 0 表示屏蔽对应的中断源的中断请求,为 1 则表示不屏蔽对应的中断源的中断请求。由于本书中采用单级中断处理方式,因此当有异常或中断发生时,首先检测Status 寄存器的 EXL 位,若为 1 则表示当前正处在异常(广义)处理中,则本次异常或中断不予响应。若 EXL 为 0,则表示当前没有异常(广义)处理,则本次异常可以得到相应。若是本次是中断请求,则还需检测 IE 位,若 IE 为 0,则中断请求不处理。若 IE 为 1,则还有检测 IM[7:0]对应的位,若为 0,则中断屏蔽;若为 1 则中断不屏蔽,此时才会响应中断请求。
(3) Count 寄存器(十进制寄存器地址 9)
Count 寄存器是一个 32 位计数器,计数频率与处理器频率一样。当计数值达到 32 位无符号数最大值时,又会从 0 开始重新计数。Count 寄存器可读可写。
(4) Compare 寄存器(十进制寄存器地址 11)
Compare 寄存器是一个 32 位寄存器,与 Count 寄存器一起完成定时中断的功能。当 Count 寄存器计数值不为 0 且与 Compare 寄存器中数值相同时,会产生定时中断,这个中断会一直保持,直到有新的数据被写入 Compare 寄存器。同样 Compare 寄存器也可读可写。
(5) EPC 寄存器(十进制寄存器地址 14)
EPC 寄存器是一个 32 位寄存器,用来保存异常或中断服务程序的返回地址。

4.5.3 中断与异常相关指令

本书中与中断和异常相关的指令,包括 syscall(system call),eret(exception
return)、mfc0(move from coprocessor0)和 mtc0(move to coprocessor0)指令,如图
4.5.3-1 所示。

4实现中断异常相关指令-2【FPGA模型机课程设计】

其中,syscall 是系统调用指令,引发系统调用异常,eret 指令是异常或中断处理程序最后一条返回指令。syscall 和 eret 指令因为指令格式固定,也没有操作数,因此可以译码时可以将所有位进行译码。

mfc0 和 mtc0 指令是完成 MIPS 处理器的 32 个通用寄存器和 CP0 中 32 个寄存器进行数据交换的功能。mfc0 和 mtc0 指令的高 6 位为 010000,通过次高6 位进行区分,因此也需要二次译码。

28:00

5.8 异常与中断设计

5.8.1 异常或中断处理过程

异常或中断处理过程如下:
(1)ID 模块根据译码结果,通过 excptype 收集 Syscall 和 Eret 指令,检测是否有对应的异常发生。
(2)EX 模块根据 Cause 寄存器的 IP[7:2],通过 excptype 收集 intimer,检测是否发生定时中断。

  • a.若为 Eret 异常,则将对应的 excptype 和 epc 送至 Ctrl 模块,Ctrl 模块进行地址转移(中断异常返回);将 excptype 送至 CP0 模块,CP0 模块将 Status 中EXL 位清 0。
  • b.若为 Syscall 异常,则首先检查 Status 中 EXL 位,若 EXL== 1,说明此时有异常或中断正在处理,则忽略此异常,即该指令不再执行,其后指令正常取指执行。若此时 Status 的 EXL==0,说明此时没有异常或中断处理,则处理该异常。将对应的 exceptype 送至 Ctrl 模块。Ctrl 模块进行转移;将 pc 和 excptype 送至 CP0 模块。CP0 模块根据 excptype 将 pc+4 送至 Epc 寄存器中保存,并且将Status 中的 EXL 位置 1,并设置 Cause 中的 ExcCode 字段,设置为 8。
  • c.若为 intimer 定时中断,则执行模块 EX 首先检查 Status 寄存器中 EXL 位,若 EXL==1,说明此时有异常或中断正在处理,则忽略此中断,即当前指令继续正常执行。若此时 Status 寄存器中 EXL 位为 0,则说明此时没有异常或中断,则此时需继续检测 Status 中 IE 位是否为 1,若不为 1 则说明中断不允许;若为 1,则继续检查对应的 Status 寄存器的 IM[7:2]位中对应位是否为 1,若对应位不为 1则说明中断被屏蔽。若此时 IM[7:2]位为 1,则说明满足条件可以响应中断。注意Status 寄存器中的 IE 和 IM 位需在主程序中通过 mtc0 指令提前设置。
    将对应的 excptype 送至 Ctrl 模块。Ctrl 模块进行转移;将 pc 和 excptype 送至 CP0 模块。CP0 模块根据 excptype 将 pc 送至 EPC 寄存器中保存,并且将 Status寄存器中 EXL 位置 1,并设置 Cause 寄存器中的 ExcCode 字段,数值为 0。
    若以上异常或中断发生,传给访存模块所有信号皆置为无效。若以上异常或中断未发生,则继续向访存模块正常传递信号。
    (3)定时中断的产生
    将 Count 和 Compare 寄存器进行比较,若 Count 不为 0,且与 Compare 值相同时,则产生该定时中断。重新给 Compare 寄存器赋值,则此时定时中断取消。将此定时中断输出接入 CP0 模块的输入端,送入 Cause 寄存器的 IP[7:2]中某一位,作为中断输入信号。

5.8.2 异常和中断的设计实现

4实现中断异常相关指令-2【FPGA模型机课程设计】

如图 5.8.2-1 所示,要实现异常和中断的设计,需要在处理器中增加协处理器 CP0模块和控制 Ctrl 模块。本书处理的中断包括:硬件定时中断,系统调用指令 Syscall。另外,异常或中断返回指令 Eret 虽然不会引发异常或中断,但处理的方式很类似与异常或中断。

代码设计

define

//中断编码
`define ZeroWord 32'h0000_0000
`define IntrOccur 1'b1
`define IntrNotOccur 1'b0
//cp0中各寄存器地址
`define CP0_count 5'd9
`define CP0_compare 5'd11
`define CP0_status 5'd12
`define CP0_epc 5'd14
`define CP0_cause 5'd13


//MIPS 扩展整数指令集

//表3 MIPS与中断异常相关6条指令

`define Inst_syscall 32'b000000_00000_000000000000000_001100//全译码
`define Inst_eret 32'b010000_10000_000000000000000_011000//全译码
`define Inst_cp0  6'b010000	
`define Inst_mfc0 5'b00000	 //010000扩展编码
`define Inst_mtc0 5'b00100	 //010000扩展编码

//内部供EX的编码

`define Syscall 6'b011101
`define Eret 6'b011110
`define Mfc0 6'b011111
`define Mtc0 6'b100001

IF

(1)取值F模块设计

	//增加引脚
	input wire[31:0] ejpc,	//异常或中断转移地址
	input wire excpt		//异常或中断有效信号

    //程序执行 pc+=4
	//中断-修改
    always@(posedge clk)
        if(ce == `RomDisable)
            pc = `Zero;
		else if(excpt == 1'b1)
			pc <=ejpc;//异常或中断的转移地址更新pc
 		else if(jCe == `Valid)//J型
            pc = jAddr;

        else
            pc = pc + 4;


ID

(2)译码ID模块设计
系统调用指令syscall 和异常中断返回指令eret指令编码固定,因此采用全译码方式。而mfc0和mtc0指令采用二次译码方式。


`include "define.v";


//	input wire [31:0] pc,	//J型

	input wire [31:0] pc_i,//将原来输入pc变为pc_i
	output wire[31:0] pc,//新增输出pc
	output wire[31:0] excptype//异常信息记录


	//中断
	reg is_syscall;
	reg is_eret;
	assign pc = pc_i;
	assign excptype= {22'b0, is_eret, is_syscall,8'b0};


    always@(*)
        if(rst == `RstEnable)
          	 begin   
          	   
				is_eret = `Invalid;//中断
				is_syscall = `Invalid;//中断
          	 end
		else if(inst == `Inst_eret)
			 begin
				op =`Eret;
				regaRead = `Invalid;
				regbRead = `Invalid;
				regcWrite= `Invalid;
				regaAddr = `Zero;
				regbAddr = `Zero;
				regcAddr = `Zero;
				imm= `Zero;
				jCe=`Invalid;
				jAddr=`Zero;
				is_eret = `Valid;
				is_syscall = `Invalid;
			  end
		else if(inst == `Inst_syscall)
			  begin
				op = `Syscall;
				regaRead = `Invalid;
				regbRead= `Invalid;
				regcWrite = `Invalid;
				regaAddr = `Zero;
				regbAddr = `Zero;
				regcAddr = `Zero;
				imm= `Zero;
				jCe=`Invalid;
				jAddr=`Zero;
				is_eret = `Invalid;
				is_syscall = `Valid;
			  end

		else 
			begin//后面的end

				is_eret = `Invalid;//中断
				is_syscall = `Invalid;//中断

	          	case(inst_op)
					`Inst_cp0:
						case(inst[25:21])
							`Inst_mfc0:
								begin
									op = `Mfc0;
									regaRead = `Invalid;
									regbRead = `Invalid;
									regcWrite = `Valid;
									regaAddr = `Zero;
									regbAddr = `Zero;
									regcAddr = inst[20:16];
									imm= {27'h0, inst[15:11]};
								end
							`Inst_mtc0:
								begin
									op =`Mtc0;
									regaRead = `Invalid;
									regbRead = `Valid;
									regcWrite = `Invalid;
									regaAddr = `Zero;
									regbAddr = inst[20:16];
									regcAddr = `Zero;
									imm= {27'h0, inst[15:11]};
								end
								
							default:
								begin
									op= `Nop;
									regaRead = `Invalid;
									regbRead = `Invalid;
									regcWrite = `Invalid;
									regaAddr = `Zero;
									regbAddr = `Zero;
									regcAddr = `Zero;
									imm= `Zero;
								end
						endcase

EX

		output reg cp0we,			//CPO寄存器的写信号
		output reg [4:0] cp0Addr,	//CPO寄存器的地址信号
		output reg [31:0] cp0wData,	//CPO寄存器的写入数据
		input wire[31:0] cp0rData,	//CPO寄存器的读出数据
		input wire[31:0] pc_i,		//当前指令地址
		input wire [31:0] excptype_i,//输入的异常或中断信息记录
		output reg [31:0] excptype,	//输出的异常或中断信息记录
		output wire [31:0] epc,		//输出的epc值,用于eret 指令
		output wire [31:0] pc,		//输出的pc值,用于异常或中断响应
		input wire [31:0] cause,	//输入的cause寄存器值
		input wire [31:0] status	//输入的status寄存器值

	//中断
	assign pc = pc_i;
	//还是需要给MEM传送指令的 LLbit<-0
//	assign op = (excptype == `ZeroWord) ?
//				 op_i : `Nop;
	assign regcWrite =(excptype == `ZeroWord) ?
				 regcWrite_i : `Invalid;



        if(rst == `RstEnable)
			begin
              	regcData = `Zero;
				whi=`Invalid;
				wlo=`Invalid;
			  	wHiData=`Zero;
			  	wLoData=`Zero;
				cp0we=`Invalid;
				cpOwData= `Zero;
				cp0Addr =`CP0_epc;
			end
        else
          begin
            regcData = `Zero;
       		wHiData=`Zero;
			wLoData=`Zero;
			cp0we=`Invalid;
			cpOwData= `Zero;
			cp0Addr =`CP0_epc;   
            //case(op)
            case(op_i)
				//中断
				`MfcO:
					begin
						cp0Addr = regaData[4:0];
						regcData = cp0rData;
					end
				`MtcO:
					begin
						regcData= `Zero;
						cp0we = `Valid;
						cp0Addr = regaData[4:0];
						cp0wData = regbData;
					end
			endcase
		  end
	/*增加关于中断查询和响应的代码*/
	//tips:cp0rData默认读出的是epc的地址
	assign epc = (excptype == 32'h0000_0200) ? cp0rData : `Zero;

	always@(*)
		if(rst ==`RstEnable)
			excptype = `Zero;
			//Cause's IP[2] Status's IM[2]; Status EXL, IE
		else if(cause[10]&& status[10]== 1'b1 && status[1:0] == 2'b01)
			//timerInt
			excptype = 32'h0000_0004;
		else if(excptype_i[8] == 1'b1 && status[1] == 1'b0)
			//Syscall
			excptype = 32'h00000100;
		else if(excptype_i[9]== 1'b1)
			//Eret
			excptype = 32'h0000_0200;
		else
			excptype = `Zero;


在代码设计中,选用Cause寄存器的IP[2]对应的0号硬件中断,即定时中断intimer输出到IP[2]上,然后在执行EX模块检测IP[2]这位是否为1,并且是否允许中断,从而确定定时中断是否有效。若异常或中断有效,则当前指令不会被继续执行,后面的操作都设为无效。

CP0

(4)协处理器CPO模块
访存MEM模块和寄存器文件 RegFile模块与上一节对应部分相同,另外,新增加了协处理器CPO模块。具体设计如下:

`include "define.v"
//协处理器模块
module CP0(
	input wire clk,		//时钟信号
	input wire rst,		//复位信号
	input wire cp0we,	//CP0寄存器的写信号
	input wire[4:0] cp0Addr,	//CP0寄存器的地址信号
	input wire[31:0] cp0wData,	//CP0寄存器的写入数据
	output reg[31:0] cp0rData,	//CP0寄存器的读出数据
	input wire[5:0] intr,		//输入硬件中断
	output reg intimer,			//输出定时中断
	input wire[31:0] excptype,//异常和中断的记录信息
	input wire[31:0] pc,		//当前指令地址
	output wire[31:0] cause,	//寄存器Cause的输出值
	output wire[31:0] status	//寄存器Status的输出值
);
	reg[31:0] Count;
	reg[31:0] Compare;
	reg[31:0] Status;
	reg[31:0] Cause;
	reg[31:0] Epc;
	
	assign cause = Cause;
	assign status = Status;

	always@(*)
		Cause[15:10]= intr;//对应IP[7:2]

	always@(posedge clk)
		if(rst == `RstEnable)
			begin
				Count= `Zero;
				Compare = `Zero;
				Status= 32'h10000000;
				Cause = `ZeroWord;
				Epc = `Zero;
				intimer = `IntrNotOccur;
			end
		else
			begin
				Count = Count + 1;
				if(Compare != `Zero && Count == Compare)
					intimer = `IntrOccur;
				if(cp0we == `Valid)
					case(cp0Addr)
						`CP0_count:
							Count = cp0wData;
						`CP0_compare:
							begin
								Compare = cp0wData;
								intimer = `IntrNotOccur;
							end
						`CP0_status:
							Status = cp0wData;
						`CP0_epc:
							Epc = cp0wData;
						`CP0_cause:
							begin
								Cause[9:8]=cp0wData[9:8];
								Cause[23:22]= cp0wData[23:22];
							end
						default: ;
					endcase
				case(excptype)
					//timerInt
					32'h0000_0004:
						begin
							//interupt instruction
							Epc = pc;
							//Status's Ex1
							Status[1]=1'b1;
							//Cause's ExcCode
							Cause[6:2]= 5'b00000;
						end
					//Syscall
					32'h0000_0100:
						begin
							Epc = pc+ 4;
							Status[1]= 1'b1;
							Cause[6:2]= 5'b01000;
						end
					//Eret
					32'h0000_0200:
						Status[1]=1'b0;
					default : ;
				endcase
			end

	always@(*)
		if(rst==`RstEnable)
			cp0rData= `Zero;
		else
			case(cp0Addr)
				`CP0_count:
					cp0rData = Count ;
				`CP0_compare:
					cp0rData = Compare;
				`CP0_status:
					cp0rData = Status;
				`CP0_epc:
					cp0rData = Epc;
				`CP0_cause:
					cp0rData= Cause;
				default:
					cp0rData= `Zero;
			endcase
endmodule

Ctrl

(5)控制Ctrl模块
控制Ctrl模块为新增加模块,主要是在查询方式下,提供异常或中断服务程序的首地址。

`include "define.v"
//控制模块
module Ctrl(
	input wire rst,				//复位信号
	input wire[31:0] excptype,	//异常或中断信息记录
	input wire [31:0] epc,		//输入epc的值,用于eret 指令
	output reg [31:0] ejpc,		//输出ejpc的值
	output reg excpt			//中断或异常有效信号
);
	always@(*)
		if(rst == `RstEnable)
			begin
				excpt = `Invalid;
				ejpc = `Zero;
			end
		else
			begin
				excpt = `Valid;
				case(excptype)
					//timerInt
					32'h0000_0004:
						ejpc = 32'h00000050;//自己指定:中断服务地址 50h右移2位(即除以4)=20 instMem
					//Syscall
					32'h0000_0100:
						ejpc= 32'h00000040;//自己指定:中断服务地址 40h右移2位(即除以4)=16 instMem
					//Eret
					32'h0000_0200:
						ejpc = epc;
					default:
						begin
							ejpc= `Zero;
							excpt = `Invalid;
						end
				endcase
			end
endmodule

MEM

				`Syscall:
					begin
						//LLbit<-0
						wbit=`Valid;
						wLLbit = `ClearFlag;
					end

				`Eret:
					begin
						//LLbit<-0
						wbit=`Valid;
						wLLbit = `ClearFlag;
					end

MIPS

(6)MIPS处理器顶层模块
根据异常和中断指令设计修改MIPS处理器顶层模块:

    //增加引脚
	input wire[5:0] intr,	//硬件中断的输入信号
	output wire intimer		//定时中断的输出信号

	//中断
	wire cp0we;
	wire[4:0] cp0Addr;
	wire[31:0] cp0wData;
	wire[31:0] cp0rData;
	wire[31:0] epc_ex , ejpc;
	wire[31:0] excptype_id,excptype_ex;
	wire[31:0] cause, status;
	wire[31:0] pc_id, pc_ex;


	//中断修改
    IF if0(

		.ejpc(ejpc),//异常或中断转移地址
		.excpt(excpt)//异常或中断信号
    );
    
	//中断修改
    ID id0(
//       .pc(instAddr),//J型

		.pc_i(instAddr),//pc的输入信号
		.pc(pc_id),	//pc的输出信号
		.excptype(excptype_id)//中断或异常的记录信息
    );


    //乘除md-修改EX实例化
	//中断修改
    EX ex0(

		.cp0we(cp0we),//CPO的写信号
		.cp0Addr(cp0Addr),//CPO的地址信息
		.cp0wData(cp0wData),//CPO的写入数据
		.cp0rData(cp0rData),//CPO的读出数据
		.pc_i(pc_id),//pc的输入值
		.excptype_i(excptype_id),//异常或中断的记录信息输入值
		.excptype(excptype_ex),//异常或中断的记录信息输出值
		.epc(epc_ex),//epc的输出值
		.pc(pc_ex),//pc的输出值
		.cause(cause),//cause的输入值
		.status(status)//status的输入值
    ); 
       
	//中断-新增加模块
	CP0 cp0(
		.clk(clk),
		.rst(rst),
		.cp0we(cp0we),
		.cp0wData(cp0wData),
		.cp0Addr(cp0Addr),
		.cp0rData(cp0rData),
		.intr(intr),
		.intimer(intimer),
		.pc(pc_ex),
		.excptype(excptype_ex),
		.cause(cause),
		.status(status)
	);
	
	//中断-新增加模块
	Ctrl ctrl0(
		.rst(rst),
		.ejpc(ejpc),
		.excpt(excpt),
		.excptype(excptype_ex),
		.epc(epc_ex)
	);


SOC

系统封装

	//中断
	wire[5:0] intr;
	wire initimer;
	assign intr={5'b0,intimer};


	//修改MIPS实例
	//中断-修改
    MIPS mips0(

		.intr(intr),//中断
		.intimer(intr[0])//中断
    );	

InstMem

(8)系统测试设计
分别编写一段代码,测试Syscall 指令和定时中断,注意Syscall系统调用异常和定时中断各自对应的异常/中断服务程序入口地址,编写异常/中断服务程序最后一条指令应是Eret 指令,实现返回断点。

例如:测试syscall指令的简单指令代码:

		//测试中断指令
		instmem[6]=32'h0000000c;//syscall instruction

		instmem[7]=32'h3407ffff;//ori
		instmem[8]=32'h3408ffff;//ori

		instmem [16]=32'h340affff;//syscall except program
		instmem [17]=32'h340bffff;//ori
		instmem [18]=32'h42000018;//eret inatruction


4实现中断异常相关指令-2【FPGA模型机课程设计】
测试定时中断时需要使用mtc指令设置Status寄存器的IM相应和E位。例如,测试定时中断的程序代码:

		instmem[0] =32'h34020000; 	//ori $2, $0,0
		instmem[1]= 32'h34010014; 	//ori $1, $0,20
		instmem[2]= 32'h40815800; 	//mtc0 $1,$11 set compare=20
		instmem[3]=32'h3c011000;	//lui $1, 0x1000
		instmem[4]=32'h34210401;	//ori $1, $1,0x0401
		instmem[5]= 32'h40816000; 	//mtc0 $1,$12 set status,enable int
		instmem[6]= 32'h08000006; 	//lpt: j lpt
		//interproc first addr Ox0050
		instmem[20]= 32'h34030001; 	//ORI $3,$0,1
		instmem[21]= 32'h34040014;	//ORI S4, $0,20
		instmem[22]= 32'h00431020;	//ADD $2,$2,$3
		instmem[23]= 32'h40015800;	//MFC $1,$11 read compare
		instmem[24]=32'h00240820; 	//ADD $1,$1,$4
		instmem[25]= 32'h40815800;	//MTC0 s1,$11 set compare
		instmem[26]= 32'h42000018;	//eret

0-6
4实现中断异常相关指令-2【FPGA模型机课程设计】

等待count== compare
4实现中断异常相关指令-2【FPGA模型机课程设计】
然后执行中断程序
执行完成异常返回
4实现中断异常相关指令-2【FPGA模型机课程设计】
继续等待count== compare
4实现中断异常相关指令-2【FPGA模型机课程设计】

另外,对于LL和SC指令的异常或中断情况下的处理,也可以进行测试。

测试原子指令-失败案例

在原有的sc指令的前面添加系统调用指令
把LLbit<-0
导致sc把r7<-0

		//测试原子功能--失败测试
		//R1=00001100 R2=00000020 
		//Lpt: 	LL r7,0x20(r1)		//读取程序里的信号量,LLibt=1
		//ll r7,0x20(r2) --(r7)=mem[72]=0
		instmem [6] = 32'b110000_00001_00111_0000_0000_0010_0000;//ll r7,0x20(r1)
		//if(r7 == clearFlag)	//判断信号是否被占用,为clearFlag表示没占用
		//pc=jaddr=npc+S14 offset(16) 00(2)
		//bne,r7,r0,else(+4)
		instmem [7] = 32'b000101_00111_00000_0000_0000_0000_0100;//bne,r7,r0,else(+4)
		//{
		//	MOV r7, setFlag			//设置本程序的占用标志
		//ori R7,ffff -- R7 --0000ffff
        instmem [8] = 32'h3407ffff;	//ori  R7 ffff

		//系统调用 把LLbit<-0
		instmem[9]=32'h0000000c;//syscall instruction
		//	SC r7, 0x20(r1)			//设置到信号量里  设置失败因为LLbit=0
		instmem [10] = 32'b111000_00001_00111_0000_0000_0010_0000;//sc r7,0x20(r1)
		//	if(r7 == 1) goto Success//如果信号量设置成功,r1就会为1
		//pc=jaddr=npc+S14 offset(16) 00(2)
		//bne,r1,r0,Success(+2)
		instmem [11] = 32'b000101_00111_00000_0000_0000_0000_0010;//bne,r7,r0,Success(+2)
		//	//如果信号量没有设置成功,重新读信号量,即重新执行LL指令
		//	else goto Lpt
		//j Lpt(6)
		//pc=jaddr=npc(4) offset(26) 00(2)	
		instmem [12] = 32'h08000006;//j Lpt(6) 编码000010  pc=0018 
		//}
		//else goto Lpt
		//j Lpt(6)
		//pc=jaddr=npc(4) offset(26) 00(2)	
		instmem [13] =  32'h08000006;//j Lpt(6) 编码000010  pc=0018 
		//Success:
		//	访问指定的存储区域
		//	set r7,clearFlag
		//andi R7,0000 -- R7 --00000000
        instmem [14] = 32'h30070000;	//andi R7,0000
		//	lw r7,(0x20)r1
		instmem[15]=32'b100011_00001_00111_0000_0000_0010_0000; //lw r7,0x20(r1)

		//系统调用程序
		instmem [16]=32'h340affff;//syscall except program
		instmem [17]=32'h340bffff;//ori
		instmem [18]=32'h42000018;//eret inatruction


4实现中断异常相关指令-2【FPGA模型机课程设计】

附录

其余与上篇一样

0 框架

顶层设计
4实现中断异常相关指令-2【FPGA模型机课程设计】

代码框架

4实现中断异常相关指令-2【FPGA模型机课程设计】

1 define 编码

//0、宏定义文件
`define RstEnable 1'b1
`define RstDisable 1'b0
`define RomEnable 1'b1
`define RomDisable 1'b0
`define Zero 0
`define Valid 1'b1
`define Invalid 1'b0
`define SetFlag 1'b1 	//检查LLbit的值,控制信号,不是数据信号
`define ClearFlag 1'b0	//检查LLbit的值,控制信号,不是数据信号

//MEM宏编译
`define RamWrite 1'b1
`define RamUnWrite 1'b0
`define RamEnable 1'b1
`define RamDisable 1'b0

//中断编码
`define ZeroWord 32'h0000_0000
`define IntrOccur 1'b1
`define IntrNotOccur 1'b0
//cp0中各寄存器地址
`define CP0_count 5'd9
`define CP0_compare 5'd11
`define CP0_status 5'd12
`define CP0_epc 5'd14
`define CP0_cause 5'd13


//指令外部编码

//MIPS 基本整数指令集
//表1 20条MIPS整数指令

//R型编码
`define Inst_reg 6'b000000

`define Inst_add 6'b100000
`define Inst_sub 6'b100010
`define Inst_and 6'b100100
`define Inst_or  6'b100101
`define Inst_xor 6'b100110
`define Inst_sll 6'b000000
`define Inst_srl 6'b000010
`define Inst_sra 6'b000011
`define Inst_jr  6'b001000

//I型编码
`define Inst_addi 6'b001000
`define Inst_andi 6'b001100
`define Inst_ori  6'b001101
`define Inst_xori 6'b001110
`define Inst_lw 6'b100011
`define Inst_sw 6'b101011
`define Inst_beq  6'b000100	
`define Inst_bne  6'b000101	
`define Inst_lui  6'b001111

//J型编码
`define Inst_j 	 6'b000010	
`define Inst_jal 6'b000011	


//MIPS 扩展整数指令集
//表2 MIPS 12条整数指令
`define Inst_slt 6'b101010
`define Inst_bgtz 6'b000111	//j i	
`define Inst_bltz 6'b000001	//j i 	
`define Inst_jalr 6'b001001	//r 
`define Inst_mult 6'b011000	 //r 
`define Inst_multu 6'b011001 //r 
`define Inst_div 6'b011010	 //r 
`define Inst_divu 6'b011011 //r 
`define Inst_mfhi 6'b010000	 //r 
`define Inst_mflo 6'b010010	 //r 
`define Inst_mthi 6'b010001	 //r 
`define Inst_mtlo 6'b010011	 //r 

//表3 MIPS与中断异常相关6条指令
`define Inst_ll 6'b110000	 //i
`define Inst_sc 6'b111000	 //i


`define Inst_syscall 32'b000000_00000_000000000000000_001100//全译码
`define Inst_eret 32'b010000_10000_000000000000000_011000//全译码
`define Inst_cp0  6'b010000	
`define Inst_mfc0 5'b00000	 //010000扩展编码
`define Inst_mtc0 5'b00100	 //010000扩展编码


//另外
//`define Inst_subi 6'b001001	//i


//内部供EX的编码
`define Nop 6'b000000
`define Or  6'b000001
`define And 6'b000010
`define Xor 6'b000011
`define Add 6'b000100
`define Sub 6'b000101
`define Lui 6'b100000 
`define Sll 6'b000110
`define Srl 6'b000111
`define Sra 6'b001000


`define J   6'b001001
`define Jal 6'b001010
`define Jr  6'b001011
`define Beq 6'b001100
`define Bne 6'b001101
`define Bgtz 6'b001110
`define Bltz 6'b001111

`define Lw  6'b010000
`define Sw  6'b010001

`define Slt  6'b010010
`define Mult 6'b010011
`define Multu 6'b010100
`define Div 6'b010101
`define Divu 6'b010110

`define Mfhi 6'b010111
`define Mflo 6'b011000
`define Mthi 6'b011001
`define Mtlo 6'b011010
`define Ll 6'b011011
`define Sc 6'b011100

`define Syscall 6'b011101
`define Eret 6'b011110
`define Mfc0 6'b011111
`define Mtc0 6'b100001

2 IF 取值

`include "define.v";
//IF 取指模块
//1、控制PC,程序计数器

module IF(
    input wire clk,
    input wire rst, 
    input wire [31:0] jAddr,//J型
    input wire jCe,//J型
    output reg ce, 
    output reg [31:0] pc,
	input wire[31:0] ejpc,	//异常或中断转移地址
	input wire excpt		//异常或中断有效信号
);
    always@(*)
        if(rst == `RstEnable)
            ce = `RomDisable;
        else
            ce = `RomEnable;

    //程序执行 pc+=4
	//中断-修改
    always@(posedge clk)
        if(ce == `RomDisable)
            pc = `Zero;
		else if(excpt == 1'b1)
			pc <=ejpc;//异常或中断的转移地址更新pc
 		else if(jCe == `Valid)//J型
            pc = jAddr;

        else
            pc = pc + 4;

endmodule

3 ID 译码

`include "define.v";

//ID 译码模块
//2、为操作数做准备

module  ID (
    input wire rst,    
//	input wire [31:0] pc,	//J型
    input wire [31:0] inst,
    input wire [31:0] regaData_i,
    input wire [31:0] regbData_i,
    output reg [5:0] op,    
    output reg [31:0] regaData,
    output reg [31:0] regbData,
    output reg regaRead,
    output reg regbRead,
    output reg regcWrite,
    output reg [4:0] regaAddr,
    output reg [4:0] regbAddr,    
    output reg [4:0] regcAddr,
	output reg [31:0] jAddr,	//J型
    output reg jCe,//J型
	input wire [31:0] pc_i,//将原来输入pc变为pc_i
	output wire[31:0] pc,//新增输出pc
	output wire[31:0] excptype//异常信息记录
);

    //操作指令
    wire [5:0] inst_op = inst[31:26];   
    //扩展的立即数 
    reg [31:0] imm;
	//用于R型指令
    wire[5:0] func = inst[5:0]; 
	//用于J型指令
	wire [31:0] npc = pc + 4;
	//中断
	reg is_syscall;
	reg is_eret;
	assign pc = pc_i;
	assign excptype= {22'b0, is_eret, is_syscall,8'b0};


    always@(*)
        if(rst == `RstEnable)
          	 begin
            	op = `Nop;            
	            regaRead = `Invalid;
	            regbRead = `Invalid;
	            regcWrite = `Invalid;
	            regaAddr = `Zero;
	            regbAddr = `Zero;
	            regcAddr = `Zero;
	            imm    = `Zero;
				jCe = `Invalid;//J型
	            jAddr = `Zero;//J型
				is_eret = `Invalid;//中断
				is_syscall = `Invalid;//中断

          	 end
		else if(inst == `Inst_eret)
			 begin
				op =`Eret;
				regaRead = `Invalid;
				regbRead = `Invalid;
				regcWrite= `Invalid;
				regaAddr = `Zero;
				regbAddr = `Zero;
				regcAddr = `Zero;
				imm= `Zero;
				jCe=`Invalid;
				jAddr=`Zero;
				is_eret = `Valid;
				is_syscall = `Invalid;
			  end
		else if(inst == `Inst_syscall)
			  begin
				op = `Syscall;
				regaRead = `Invalid;
				regbRead= `Invalid;
				regcWrite = `Invalid;
				regaAddr = `Zero;
				regbAddr = `Zero;
				regcAddr = `Zero;
				imm= `Zero;
				jCe=`Invalid;
				jAddr=`Zero;
				is_eret = `Invalid;
				is_syscall = `Valid;
			  end


		else 
			begin//后面的end
			    jCe = `Invalid;//J型
		        jAddr = `Zero;//J型
				is_eret = `Invalid;//中断
				is_syscall = `Invalid;//中断

	          	case(inst_op)
					`Inst_cp0:
						case(inst[25:21])
							`Inst_mfc0:
								begin
									op = `Mfc0;
									regaRead = `Invalid;
									regbRead = `Invalid;
									regcWrite = `Valid;
									regaAddr = `Zero;
									regbAddr = `Zero;
									regcAddr = inst[20:16];
									imm= {27'h0, inst[15:11]};
								end
							`Inst_mtc0:
								begin
									op =`Mtc0;
									regaRead = `Invalid;
									regbRead = `Valid;
									regcWrite = `Invalid;
									regaAddr = `Zero;
									regbAddr = inst[20:16];
									regcAddr = `Zero;
									imm= {27'h0, inst[15:11]};
								end
								
							default:
								begin
									op= `Nop;
									regaRead = `Invalid;
									regbRead = `Invalid;
									regcWrite = `Invalid;
									regaAddr = `Zero;
									regbAddr = `Zero;
									regcAddr = `Zero;
									imm= `Zero;
								end
						endcase

	               	`Inst_ori:
	                 	begin
		                    op = `Or;                    
		                    regaRead = `Valid;
		                    regbRead = `Invalid;
		                    regcWrite = `Valid;
		                    regaAddr = inst[25:21];
		                    regbAddr = `Zero;
		                    regcAddr = inst[20:16];
		                    imm = {16'h0, inst[15:0]};
	                  	end
				    `Inst_andi:
			  		  	begin
		                    op = `And;                    
		                    regaRead = `Valid;
		                    regbRead = `Invalid;
		                    regcWrite = `Valid;
		                    regaAddr = inst[25:21];
		                    regbAddr = `Zero;
		                    regcAddr = inst[20:16];
		                    imm = {16'h0, inst[15:0]};
		                end
					`Inst_xori:
			 			begin
		                    op = `Xor;                    
		                    regaRead = `Valid;
		                    regbRead = `Invalid;
		                    regcWrite = `Valid;
		                    regaAddr = inst[25:21];
		                    regbAddr = `Zero;
		                    regcAddr = inst[20:16];
		                    imm = {16'h0, inst[15:0]};
	                  	end
	
					`Inst_addi:
				  		begin
		                    op = `Add;                    
		                    regaRead = `Valid;
		                    regbRead = `Invalid;
		                    regcWrite = `Valid;
		                    regaAddr = inst[25:21];
		                    regbAddr = `Zero;
		                    regcAddr = inst[20:16];
		                    imm = {{16{inst[15]}}, inst[15:0]};
		                end
//					`Inst_subi:
//					 	begin
//		                    op = `Sub;                    
//		                    regaRead = `Valid;
//		                    regbRead = `Invalid;
//		                    regcWrite = `Valid;
//		                    regaAddr = inst[25:21];
//		                    regbAddr = `Zero;
//		                    regcAddr = inst[20:16];
//		                    imm = {{16{inst[15]}}, inst[15:0]};
//	                    end
					`Inst_lui:
					  	begin
		                    op = `Lui;                    
		                    regaRead = `Valid;
		                    regbRead = `Invalid;
		                    regcWrite = `Valid;
		                    regaAddr = inst[25:21];
		                    regbAddr = `Zero;
		                    regcAddr = inst[20:16];
		                    imm = {inst[15:0],16'h0};
	                  	end
					`Inst_reg:
	        		    case(func)
		                	`Inst_add:
			                    begin
			                        op = `Add;  
				                    regaRead = `Valid;
				                    regbRead = `Valid;
				                    regcWrite = `Valid;
				                    regaAddr = inst[25:21];
				                    regbAddr = inst[20:16];
								    regcAddr = inst[15:11];
				                    imm = `Zero;
			                    end
	
							`Inst_or:
								begin
								    op = `Or;
								    regaRead = `Valid;
								    regbRead = `Valid;
								    regcWrite = `Valid;
								    regaAddr = inst[25:21];
								            regbAddr = inst[20:16];
								            regcAddr = inst[15:11];
								            imm = `Zero;
								        end
	
								`Inst_sub:
								        begin
								            op = `Sub;
								            regaRead = `Valid;
								            regbRead = `Valid;
								            regcWrite = `Valid;
								            regaAddr = inst[25:21];
								            regbAddr = inst[20:16];
								            regcAddr = inst[15:11];
								            imm = `Zero;
								        end
	
								`Inst_and:
								        begin
								            op = `And;
								            regaRead = `Valid;
								            regbRead = `Valid;
								            regcWrite = `Valid;
								            regaAddr = inst[25:21];
								            regbAddr = inst[20:16];
								            regcAddr = inst[15:11];
								            imm = `Zero;
								        end
	
	
								`Inst_xor:
								        begin
								            op = `Xor;
								            regaRead = `Valid;
								            regbRead = `Valid;
								            regcWrite = `Valid;
								            regaAddr = inst[25:21];
								            regbAddr = inst[20:16];
								            regcAddr = inst[15:11];
								            imm = `Zero;
								        end
	
	
								`Inst_sll:
								        begin
								            op = `Sll;
								            regaRead = `Invalid;
								            regbRead = `Valid;
								            regcWrite = `Valid;
								            regaAddr = `Zero;
								            regbAddr = inst[20:16];
								            regcAddr = inst[15:11];
								            imm = {27'b0,inst[10:6]};//移位复用imm
								        end
	
								`Inst_srl:
								        begin
								            op = `Srl;
								            regaRead = `Invalid;
								            regbRead = `Valid;
								            regcWrite = `Valid;
								            regaAddr = `Zero;
								            regbAddr = inst[20:16];
								            regcAddr = inst[15:11];
								            imm = {27'b0,inst[10:6]};//移位复用imm
								        end
	
								`Inst_sra:
								        begin
								            op = `Sra;
								            regaRead = `Invalid;
								            regbRead = `Valid;
								            regcWrite = `Valid;
								            regaAddr = `Zero;
								            regbAddr = inst[20:16];
								            regcAddr = inst[15:11];
								            imm = {27'b0,inst[10:6]};//移位复用imm
								        end
	
	
								//JR型指令
								`Inst_jr:
					 					begin
					   						op = `J;
					   						regaRead = `Valid;//需要读rs
					   						regbRead = `Invalid;
					   						regcWrite = `Invalid;
				   							regaAddr = inst[25:21];
					  	 					regbAddr = `Zero;
					 	 					regcAddr = `Zero;
				   							jAddr = regaData;//regaData=(regaAddr)
			        	        			jCe = `Valid;
				   							imm = `Zero;
				 						end
	
								`Inst_jalr:
					 					begin
					   						op = `Jal;
					   						regaRead = `Valid;
					   						regbRead = `Invalid;
					   						regcWrite = `Valid;
				   							regaAddr = inst[25:21];
					   						regbAddr = `Zero;
					  						regcAddr = 5'b11111;
				   							jAddr = regaData;
			                				jCe = `Valid;
				   							imm = npc;//regbData中存imm npc
				 						end
						
									//12条整数指令
									`Inst_slt:
						 				begin
							 				op = `Slt;
						      				regaRead = `Valid;
							  				regbRead = `Valid;
							  				regcWrite = `Valid;
							  				regaAddr = inst[25:21];
							  				regbAddr = inst[20:16];
							  				regcAddr = inst[15:11];
							  				imm = `Zero;
						 				end		
									//乘除指令
									`Inst_mult:
						 				begin
							 				op = `Mult;
						      				regaRead = `Valid;
							  				regbRead = `Valid;
							  				regcWrite = `Invalid;//写到HILO寄存器中,而不是通用寄存器中
							  				regaAddr = inst[25:21];
							  				regbAddr = inst[20:16];
							  				regcAddr = `Zero;
							  				imm = `Zero;
						 				end		
									`Inst_multu:
						 				begin
							 				op = `Multu;
						      				regaRead = `Valid;
							  				regbRead = `Valid;
							  				regcWrite = `Invalid;//写到HILO寄存器中,而不是通用寄存器中
							  				regaAddr = inst[25:21];
							  				regbAddr = inst[20:16];
							  				regcAddr = `Zero;
							  				imm = `Zero;
						 				end		
									`Inst_div:
						 				begin
							 				op = `Div;
						      				regaRead = `Valid;
							  				regbRead = `Valid;
							  				regcWrite = `Invalid;//写到HILO寄存器中,而不是通用寄存器中
							  				regaAddr = inst[25:21];
							  				regbAddr = inst[20:16];
							  				regcAddr = `Zero;
							  				imm = `Zero;
						 				end		
									`Inst_divu:
						 				begin
							 				op = `Divu;
						      				regaRead = `Valid;
							  				regbRead = `Valid;
							  				regcWrite = `Invalid;//写到HILO寄存器中,而不是通用寄存器中
							  				regaAddr = inst[25:21];
							  				regbAddr = inst[20:16];
							  				regcAddr = `Zero;
							  				imm = `Zero;
						 				end		
									//后4条指令
									`Inst_mfhi:
						 				begin
							 				op = `Mfhi;
						      				regaRead = `Invalid;
							  				regbRead = `Invalid;
							  				regcWrite = `Valid;//从HILO寄存器中,写到通用寄存器中
							  				regaAddr = `Zero;
							  				regbAddr = `Zero;
							  				regcAddr = inst[15:11];
							  				imm = `Zero;//HiLo的数据在EX中得到
						 				end		
									`Inst_mflo:
						 				begin
							 				op = `Mflo;
						      				regaRead = `Invalid;
							  				regbRead = `Invalid;
							  				regcWrite = `Valid;//从HILO寄存器中,写到通用寄存器中
							  				regaAddr = `Zero;
							  				regbAddr = `Zero;
							  				regcAddr = inst[15:11];
							  				imm = `Zero;//HiLo的数据在EX中得到
						 				end		
									`Inst_mthi:
						 				begin
							 				op = `Mthi;
						      				regaRead = `Valid;//从通用寄存器读出
							  				regbRead = `Invalid;
							  				regcWrite = `Invalid;//写到HILO寄存器中,而不是通用寄存器中
							  				regaAddr = inst[25:21];	
							  				regbAddr = `Zero;
							  				regcAddr = `Zero;
							  				imm = `Zero;
						 				end		
									`Inst_mtlo:
						 				begin
							 				op = `Mtlo;
						      				regaRead = `Valid;//从通用寄存器读出
							  				regbRead = `Invalid;
							  				regcWrite = `Invalid;//写到HILO寄存器中,而不是通用寄存器中			
							  				regaAddr = inst[25:21];
							  				regbAddr = `Zero;
							  				regcAddr = `Zero;
							  				imm = `Zero;
						 				end		
								default:
								        begin
								            regaRead = `Invalid;
								            regbRead = `Invalid;
								            regcWrite = `Invalid;
								            regaAddr = `Zero;
								            regbAddr = `Zero;
								 		    regcAddr = `Zero;
								            imm = `Zero;
											
								        end
							endcase
	
					//J型指令
					`Inst_j:
						begin
					   		op = `J;
					   		regaRead = `Invalid;
					   		regbRead = `Invalid;
					   		regcWrite = `Invalid;//不需要写
				   			regaAddr = `Zero;
					   		regbAddr = `Zero;
					  		regcAddr = `Zero;
				   			jAddr = {npc[31:28], inst[25:0], 2'b00};
			                jCe = `Valid;
				   			imm = `Zero;
				 		end				
					`Inst_jal:
					 	begin
					   		op = `Jal;
					   		regaRead = `Invalid;
					   		regbRead = `Invalid;
					   		regcWrite = `Valid;//需要把npc写入R31中
				   			regaAddr = `Zero;
					   		regbAddr = `Zero;
					  		regcAddr = 5'b11111;
				   			jAddr = {npc[31:28], inst[25:0], 2'b00};
			               	jCe = `Valid;
				   			imm = npc;
				 			end
					//J+型指令	
					`Inst_beq:
						begin
							op = `Beq;
							regaRead = `Valid;
							regbRead = `Valid;
							regcWrite = `Invalid;
						   	regaAddr = inst[25:21];
							regbAddr = inst[20:16];
							regcAddr = `Zero;
						   	jAddr = npc+{{14{inst[15]}},inst[15:0], 2'b00};
										
							if(regaData==regbData)
					            jCe = `Valid;//等于有效
							else
								jCe = `Invalid;
						   	imm = `Zero;
					 	end		
					`Inst_bne:
						begin
						   	op = `Beq;
						   	regaRead = `Valid;
						   	regbRead = `Valid;
						   	regcWrite = `Invalid;
					   		regaAddr = inst[25:21];
						   	regbAddr = inst[20:16];
						  	regcAddr = `Zero;
					   		jAddr = npc+{{14{inst[15]}},inst[15:0], 2'b00};
									
							if(regaData!=regbData)
				                jCe = `Valid;//等于有效
							else
								jCe = `Invalid;
					   		imm = `Zero;
					 	end		
					`Inst_bltz:
						begin
						   	op = `Bltz;
						   	regaRead = `Valid;
						   	regbRead = `Valid;//若regbRead无效,则regbData=imm=0
						   	regcWrite = `Invalid;
					   		regaAddr = inst[25:21];
						   	regbAddr = inst[20:16];
						  	regcAddr = `Zero;
					   		jAddr = npc+{{14{inst[15]}},inst[15:0], 2'b00};
									
							if(regaData<regbData)
				                jCe = `Valid;//小于有效
							else
								jCe = `Invalid;
					   		imm = 32'b0;
					 	end		
		
					`Inst_bgtz:
						begin
						   	op = `Bgtz;
						   	regaRead = `Valid;
						   	//regbRead = `Valid;//若regbRead有效,则regbData=(regbAddr)
							regbRead = `Invalid;//若regbRead无效,则regbData=imm=0
						   	regcWrite = `Invalid;
					   		regaAddr = inst[25:21];
						   	regbAddr = inst[20:16];
						  	regcAddr = `Zero;
					   		jAddr = npc+{{14{inst[15]}},inst[15:0], 2'b00};
									
							if(regaData>regbData)
				               	jCe = `Valid;//大于有效
							else
								jCe = `Invalid;
					   		imm = 32'b0;
					 	end		
				 	//Load Store指令
				    `Inst_lw:
				        begin
						    op = `Lw;
						    regaRead = `Valid;
						    regbRead = `Invalid;
						    regcWrite = `Valid;
						    regaAddr = inst[25:21];
						    regbAddr = `Zero;
						    regcAddr = inst[20:16];
						    imm = {{16{inst[15]}},inst[15:0]};
						 end
					
				    `Inst_sw:
						 begin
							 op = `Sw;
						      regaRead = `Valid;
							  regbRead = `Valid;
							  regcWrite = `Invalid;
							  regaAddr = inst[25:21];
							  regbAddr = inst[20:16];
							  regcAddr = `Zero;
							  imm = {{16{inst[15]}},inst[15:0]};
						end		

					//ll sc
				    `Inst_ll:
						 begin
							  op = `Ll;
						      regaRead = `Valid;
							  regbRead = `Invalid;
							  regcWrite = `Valid;
							  regaAddr = inst[25:21];
							  regbAddr = `Zero;
							  regcAddr = inst[20:16];
							  imm = {{16{inst[15]}},inst[15:0]};
						end						

				    `Inst_sc:
						 begin
							 op = `Sc;
						      regaRead = `Valid;
							  regbRead = `Valid;
							  regcWrite = `Valid;//还需给rt赋值为1
							  regaAddr = inst[25:21];
							  regbAddr = inst[20:16];
							  regcAddr = inst[20:16];//还需给rt赋值为1
							  imm = {{16{inst[15]}},inst[15:0]};
						end		


					default:
	                  	begin
		                    op = `Nop;                    
		                    regaRead = `Invalid;
		                    regbRead = `Invalid;
		                    regcWrite = `Invalid;
		                    regaAddr = `Zero;
		                    regbAddr = `Zero;
		                    regcAddr = `Zero;
		                    imm = `Zero;
		                end
            	endcase 
			end
   
	/*
	//二选一 regaData= regaData_i : imm
	always@(*)
      if(rst == `RstEnable)
          regaData = `Zero;
      else if(regaRead == `Valid)
          regaData = regaData_i;
      else	
          regaData = imm;
	
   //二选一 regbData= regbData_i : imm
    always@(*)
      if(rst == `RstEnable)
          regbData = `Zero;      
      else if(regbRead == `Valid)
          regbData = regbData_i;
      else
          regbData = imm; 
	*/	

	/*
	always@(*)      
	    if(rst == `RstEnable)          
	        regaData = `Zero;      
	    else if(op == `Lw || op == `Sw)               
	        regaData = regaData_i + imm;      
	    else if(regaRead == `Valid)          
	        regaData = regaData_i;      
	    else          
	        regaData = imm;    
	*/

	//原子-修改
	always@(*)      
	    if(rst == `RstEnable)          
	        regaData = `Zero;      
	    else if(op == `Lw || op == `Sw || op==`Ll || op==`Sc)               
	        regaData = regaData_i + imm;      
	    else if(regaRead == `Valid)          
	        regaData = regaData_i;      
	    else          
	        regaData = imm;    


	always@(*)      
	    if(rst == `RstEnable)          
	        regbData = `Zero;      
	    else if(regbRead == `Valid)          
	        regbData = regbData_i;      
	    else          
	    	regbData = imm;
	
endmodule


4 EX 执行

`include "define.v";
//3、执行指令模块

module EX (
        input wire rst,
        //input wire [5:0] op,   
		input wire [5:0] op_i,      
        input wire [31:0] regaData,
        input wire [31:0] regbData,
        input wire regcWrite_i,
        input wire [4:0] regcAddr_i,
        input wire [31:0] rHiData,//乘除 读hi数据
        input wire [31:0] rLoData,//乘除 读hi数据
        output reg [31:0] regcData,
        output wire regcWrite,
        output wire [4:0] regcAddr,
		output wire [5:0] op,
    	output wire [31:0] memAddr,
    	output wire [31:0] memData,
    	output reg whi,	//乘除 写hi使能
   		output reg wlo,	//乘除 写lo使能
   		output reg [31:0] wHiData,	//乘除 写hi数据
   		output reg [31:0] wLoData,  //乘除 写lo数据
		output reg cp0we,			//CPO寄存器的写信号
		output reg [4:0] cp0Addr,	//CPO寄存器的地址信号
		output reg [31:0] cp0wData,	//CPO寄存器的写入数据
		input wire[31:0] cp0rData,	//CPO寄存器的读出数据
		input wire[31:0] pc_i,		//当前指令地址
		input wire [31:0] excptype_i,//输入的异常或中断信息记录
		output reg [31:0] excptype,	//输出的异常或中断信息记录
		output wire [31:0] epc,		//输出的epc值,用于eret 指令
		output wire [31:0] pc,		//输出的pc值,用于异常或中断响应
		input wire [31:0] cause,	//输入的cause寄存器值
		input wire [31:0] status	//输入的status寄存器值
    );    

	assign op = op_i;
    assign memAddr = regaData;
    assign memData = regbData;

	//中断
	assign pc = pc_i;
	//还是需要给MEM传送指令的 LLbit<-0
//	assign op = (excptype == `ZeroWord) ?
//				 op_i : `Nop;
	assign regcWrite =(excptype == `ZeroWord) ?
				 regcWrite_i : `Invalid;




	always@(*)
        if(rst == `RstEnable)
			begin
              	regcData = `Zero;
				whi=`Invalid;
				wlo=`Invalid;
			  	wHiData=`Zero;
			  	wLoData=`Zero;

			end
        else
		  begin
            regcData = `Zero;
       		wHiData=`Zero;
			wLoData=`Zero;
			cp0we=`Invalid;
			cp0wData= `Zero;
			cp0Addr =`CP0_epc;  
            //case(op)
            case(op_i)
                `Or:
                    regcData = regaData | regbData;
				`And:
		    		regcData = regaData & regbData;
				`Xor:
		    		regcData = regaData ^ regbData;
				`Add:
		    		regcData = regaData + regbData;
				`Sub:
		    		regcData = regaData - regbData;
				`Lui:
					begin
		    			regcData = regaData | regbData;
					end
      
             	`Sll:
                	regcData = regbData << regaData;
              	`Srl:
                	regcData = regbData >> regaData;
				`Sra:
					regcData = ($signed(regbData)) >>> regaData;
				
				//J- JR型
				`J:
					regcData = `Zero;
				`Jal:
                    regcData = regbData;//regaData有其他用处  jr给pc=jaddr=(rs)

				//J+型
				`Beq:
					regcData = `Zero;
				`Bne:
					regcData = `Zero;
				`Bltz:
					regcData = `Zero;
				`Bgtz:
					regcData = `Zero;
				//12条整数指令
				`Slt:
					begin
						if($signed(regaData)<$signed(regbData))
							regcData={{31{0}},1};
						else
							regcData={32{0}};
					end
				//乘除指令
				`Mult:
					begin
						whi=`Valid;
						wlo=`Valid;
						{wHiData,wLoData}=
							$signed(regaData)*$signed(regbData);
					end
				`Multu:
					begin
						whi=`Valid;
						wlo=`Valid;
						{wHiData,wLoData}=regaData*regbData;
					end
				`Div:
					begin
						whi=`Valid;
						wlo=`Valid;
						wHiData=$signed(regaData)%$signed(regbData);
						wLoData=$signed(regaData)/$signed(regbData);
					end
				`Divu:
					begin
						whi=`Valid;
						wlo=`Valid;
						wHiData=regaData%regbData;
						wLoData=regaData/regbData;
					end
				//剩余4条指令
				`Mfhi:				
					regcData = rHiData;
				`Mflo:				
					regcData = rLoData;
				`Mthi:		
					begin		
						whi=`Valid;
						wHiData = regaData;
					end
				`Mtlo:		
					begin		
						wlo=`Valid;		
						wLoData = regaData;
					end

				//原子
//				`Sc:
//					regcData = 32'b1;

				//中断
				`Mfc0:
					begin
						cp0Addr = regaData[4:0];
						regcData = cp0rData;
					end
				`Mtc0:
					begin
						regcData= `Zero;
						cp0we = `Valid;
						cp0Addr = regaData[4:0];
						cp0wData = regbData;
					end
                default:
                    regcData = `Zero;
            endcase    
		  end
	/*增加关于中断查询和响应的代码*/
	//tips:cp0rData默认读出的是epc的地址
	assign epc = (excptype == 32'h0000_0200) ? cp0rData : `Zero;

	always@(*)
		if(rst ==`RstEnable)
			excptype = `Zero;
			//Cause's IP[2] Status's IM[2]; Status EXL, IE
		else if(cause[10]&& status[10]== 1'b1 && status[1:0] == 2'b01)
			//timerInt
			excptype = 32'h0000_0004;
		else if(excptype_i[8] == 1'b1 && status[1] == 1'b0)
			//Syscall
			excptype = 32'h00000100;
		else if(excptype_i[9]== 1'b1)
			//Eret
			excptype = 32'h0000_0200;
		else
			excptype = `Zero;
  
	assign regcWrite = regcWrite_i;
	assign regcAddr = regcAddr_i;




endmodule

5 MEM 访存

`include "define.v";
//访存(mem)模块设计
module MEM(
	input wire rst,		
	input wire [5:0] op,
	input wire [31:0] regcData,
	input wire [4:0] regcAddr,
	input wire regcWr,
	input wire [31:0] memAddr_i,
	input wire [31:0] memData,	
	input  wire [31:0] rdData,
	input wire rLLbit,		//llsc
	output wire [4:0]  regAddr,
	output wire regWr,
	output wire [31:0] regData,	
	output wire [31:0] memAddr,
	output reg [31:0] wtData,
	output reg memWr,	
	output reg memCe,
	output reg wbit,		//llsc
	output reg wLLbit		//llsc
);

	assign regAddr = regcAddr;    
	assign regWr = regcWr;    
//	assign regData = (op == `Lw) ? rdData : regcData;    

	//因为regData是wire型的,所以为了不修改原来的代码,就不使用always
	//而是修改regcData的值,来传到regData


	//二选一,选出Sc指令的rt<-1或rt<0
	wire [31:0]regDataLL= (rLLbit==`SetFlag) ? 32'b1 : 32'b0; 
	//二选一,存往regFile的值 sc指令存的值regcDataLL 还是  寄存器传入的值regcData
	wire [31:0]regcDataLL=  (op == `Sc ) ? regDataLL : regcData;
	//二选一,存往regFile的值 lw取得的值rdData 还是 寄存器传入的值regcData
    assign regData = (op == `Lw) ? rdData : regcDataLL;  

	assign memAddr = memAddr_i;
	




	always @ (*)        
	    if(rst == `RstEnable)          
	      begin            
	          wtData = `Zero;            
	          memWr = `RamUnWrite;            
	          memCe = `RamDisable;  
			  wbit=	`Invalid;
   			  wLLbit=`ClearFlag;
	      end        
		else
		  begin
	        wtData = `Zero;            
	        memWr = `RamUnWrite;            
	        memCe = `RamDisable;  
			wbit=	`Invalid;
   			wLLbit=`ClearFlag;

			case(op)                
			    `Lw:                  
			      begin                    
			         wtData = `Zero;                        
			         memWr = `RamUnWrite;                     
			         memCe = `RamEnable;                    
			      end                
			    `Sw:                  
			      begin                    
			         wtData = memData;                    
			         memWr = `RamWrite;                      
			         memCe = `RamEnable;                   
			     end

				//Ll Sc
				`Ll:
					begin		
						//rt<-datamem[addr]
						//不需要写到DataMem中
			         	wtData = `Zero;                  
			         	memWr = `RamUnWrite;                     
			         	memCe = `RamEnable; 
    					//LLbit<-1
						wbit=`Valid;
						wLLbit = `SetFlag;
					end
				`Sc:
					begin	
						if(rLLbit==`SetFlag)
							begin	
								//datamem[addr]<-rt
			         			wtData = memData;                    
			         			memWr = `RamWrite;                      
			        			memCe = `RamEnable;    
								//rt<-1
								//在EX中实现
								//LLbit<-0
								wbit=`Valid;
								wLLbit = `ClearFlag;
							end
						else
							begin
								//把rt<-0
								//在Mem前面对regcData处理来实现
							end
					end

				`Syscall:
					begin
						//LLbit<-0
						wbit=`Valid;
						wLLbit = `ClearFlag;
					end

				`Eret:
					begin
						//LLbit<-0
						wbit=`Valid;
						wLLbit = `ClearFlag;
					end

				default:                  
				    begin                    
				        wtData = `Zero;                    
				        memWr = `RamUnWrite;                    
				        memCe = `RamDisable;  
				 		wbit=	`Invalid;
	   			  		wLLbit=`ClearFlag;                
				    end             
			endcase
		  end
endmodule



CP0 协处理器

`include "define.v"
//协处理器模块
module CP0(
	input wire clk,		//时钟信号
	input wire rst,		//复位信号
	input wire cp0we,	//CP0寄存器的写信号
	input wire[4:0] cp0Addr,	//CP0寄存器的地址信号
	input wire[31:0] cp0wData,	//CP0寄存器的写入数据
	output reg[31:0] cp0rData,	//CP0寄存器的读出数据
	input wire[5:0] intr,		//输入硬件中断
	output reg intimer,			//输出定时中断
	input wire[31:0] excptype,//异常和中断的记录信息
	input wire[31:0] pc,		//当前指令地址
	output wire[31:0] cause,	//寄存器Cause的输出值
	output wire[31:0] status	//寄存器Status的输出值
);
	reg[31:0] Count;
	reg[31:0] Compare;
	reg[31:0] Status;
	reg[31:0] Cause;
	reg[31:0] Epc;
	
	assign cause = Cause;
	assign status = Status;

	always@(*)
		Cause[15:10]= intr;//对应IP[7:2]

	always@(posedge clk)
		if(rst == `RstEnable)
			begin
				Count= `Zero;
				Compare = `Zero;
				Status= 32'h10000000;
				Cause = `ZeroWord;
				Epc = `Zero;
				intimer = `IntrNotOccur;
			end
		else
			begin
				Count = Count + 1;
				if(Compare != `Zero && Count == Compare)
					intimer = `IntrOccur;
				if(cp0we == `Valid)
					case(cp0Addr)
						`CP0_count:
							Count = cp0wData;
						`CP0_compare:
							begin
								Compare = cp0wData;
								intimer = `IntrNotOccur;
							end
						`CP0_status:
							Status = cp0wData;
						`CP0_epc:
							Epc = cp0wData;
						`CP0_cause:
							begin
								Cause[9:8]=cp0wData[9:8];
								Cause[23:22]= cp0wData[23:22];
							end
						default: ;
					endcase
				case(excptype)
					//timerInt
					32'h0000_0004:
						begin
							//interupt instruction
							Epc = pc;
							//Status's Ex1
							Status[1]=1'b1;
							//Cause's ExcCode
							Cause[6:2]= 5'b00000;
						end
					//Syscall
					32'h0000_0100:
						begin
							Epc = pc+ 4;
							Status[1]= 1'b1;
							Cause[6:2]= 5'b01000;
						end
					//Eret
					32'h0000_0200:
						Status[1]=1'b0;
					default : ;
				endcase
			end

	always@(*)
		if(rst==`RstEnable)
			cp0rData= `Zero;
		else
			case(cp0Addr)
				`CP0_count:
					cp0rData = Count ;
				`CP0_compare:
					cp0rData = Compare;
				`CP0_status:
					cp0rData = Status;
				`CP0_epc:
					cp0rData = Epc;
				`CP0_cause:
					cp0rData= Cause;
				default:
					cp0rData= `Zero;
			endcase
endmodule

Ctrl 控制模块

`include "define.v"
//控制模块
module Ctrl(
	input wire rst,				//复位信号
	input wire[31:0] excptype,	//异常或中断信息记录
	input wire [31:0] epc,		//输入epc的值,用于eret 指令
	output reg [31:0] ejpc,		//输出ejpc的值
	output reg excpt			//中断或异常有效信号
);
	always@(*)
		if(rst == `RstEnable)
			begin
				excpt = `Invalid;
				ejpc = `Zero;
			end
		else
			begin
				excpt = `Valid;
				case(excptype)
					//timerInt
					32'h0000_0004:
						ejpc = 32'h00000050;//自己指定:中断服务地址 50h右移2位(即除以4)=20 instMem
					//Syscall
					32'h0000_0100:
						ejpc= 32'h00000040;//自己指定:中断服务地址 40h右移2位(即除以4)=16 instMem
					//Eret
					32'h0000_0200:
						ejpc = epc;
					default:
						begin
							ejpc= `Zero;
							excpt = `Invalid;
						end
				endcase
			end
endmodule

8 MIPS 封装

`include "define.v";
//5、MIPS封装
//修改EX实例化,新增Mem实例化

//新增端口rdData wtData memAddr memCe memWr
//原op变为op_i
//新增ls内部变量
module MIPS(
    input wire clk,
    input wire rst,
    input wire [31:0] instruction,
    input wire [31:0] rdData,//ls
	output wire romCe,
	output wire [31:0] instAddr,
	output wire [31:0] wtData,//ls
	output wire [31:0] memAddr,//ls
	output wire memCe,//ls
	output wire memWr,//ls
	input wire[5:0] intr,	//硬件中断的输入信号
	output wire intimer		//定时中断的输出信号
);
    wire [31:0] regaData_regFile, regbData_regFile;
    wire [31:0] regaData_id, regbData_id; 
    wire [31:0] regcData_ex;
    //wire [5:0] op; 
    wire [5:0] op_id; //ls  
    wire regaRead, regbRead;
    wire [4:0] regaAddr, regbAddr;
    wire regcWrite_id, regcWrite_ex;
    wire [4:0] regcAddr_id, regcAddr_ex;

	//J型
	wire [31:0] jAddr;
    wire jCe;

	//ls
	wire [5:0] op_ex;
	wire[31:0] memAddr_ex,memData_ex;
	wire [5:0] regAddr_mem;
	wire [31:0] regData_mem;
	wire regWr_mem;

	//md-hl
	wire [31:0] wHiData_ex;
	wire [31:0] wLoData_ex;
	wire whi;
	wire wlo;
	wire [31:0] rHiData_ex;
	wire [31:0] rLoData_ex;

	//llsc
	wire excpt;
	wire wbit;
	wire wLLbit;
	wire rLLbit;

	//中断
	wire cp0we;
	wire[4:0] cp0Addr;
	wire[31:0] cp0wData;
	wire[31:0] cp0rData;
	wire[31:0] epc_ex , ejpc;
	wire[31:0] excptype_id,excptype_ex;
	wire[31:0] cause, status;
	wire[31:0] pc_id, pc_ex;

	//中断修改
    IF if0(
        .clk(clk),
        .rst(rst),
		.jAddr(jAddr),//J型
		.jCe(jCe),//J型
        .ce(romCe), 
        .pc(instAddr),
		.ejpc(ejpc),//异常或中断转移地址
		.excpt(excpt)//异常或中断信号
    );

	//中断修改
    ID id0(
        .rst(rst), 
//       .pc(instAddr),//J型
        .inst(instruction),
        .regaData_i(regaData_regFile),
        .regbData_i(regbData_regFile),
        //.op(op),
		.op(op_id),//ls
        .regaData(regaData_id),
        .regbData(regbData_id),
        .regaRead(regaRead),
        .regbRead(regbRead),
        .regaAddr(regaAddr),
        .regbAddr(regbAddr),
        .regcWrite(regcWrite_id),
        .regcAddr(regcAddr_id),
		.jAddr(jAddr),//J型
		.jCe(jCe),//J型
		.pc_i(instAddr),//pc的输入信号
		.pc(pc_id),	//pc的输出信号
		.excptype(excptype_id)//中断或异常的记录信息
    );

    //乘除md-修改EX实例化
	//中断修改
    EX ex0(
        .rst(rst),
        //.op(op),    
		.op_i(op_id),    
        .regaData(regaData_id),
        .regbData(regbData_id),
        .regcWrite_i(regcWrite_id),
        .regcAddr_i(regcAddr_id),
		.rHiData(rHiData_ex),//md
		.rLoData(rLoData_ex),//md
        .regcData(regcData_ex),
        .regcWrite(regcWrite_ex),
        .regcAddr(regcAddr_ex),
		.op(op_ex),//ls
		.memAddr(memAddr_ex),//ls
		.memData(memData_ex),//ls
		.whi(whi_ex),//md
		.wlo(wlo_ex),//md
		.wHiData(wHiData_ex),//md
		.wLoData(wLoData_ex),//md
		.cp0we(cp0we),//CPO的写信号
		.cp0Addr(cp0Addr),//CPO的地址信息
		.cp0wData(cp0wData),//CPO的写入数据
		.cp0rData(cp0rData),//CPO的读出数据
		.pc_i(pc_id),//pc的输入值
		.excptype_i(excptype_id),//异常或中断的记录信息输入值
		.excptype(excptype_ex),//异常或中断的记录信息输出值
		.epc(epc_ex),//epc的输出值
		.pc(pc_ex),//pc的输出值
		.cause(cause),//cause的输入值
		.status(status)//status的输入值
    );    

	//新增HiLo寄存器
	HiLo hilo0(
		.rst(rst),
		.clk(clk),
		.wHiData(wHiData_ex),
		.wLoData(wLoData_ex),
		.whi(whi_ex),
		.wlo(wlo_ex),
		.rHiData(rHiData_ex),
		.rLoData(rLoData_ex)
	);

	//新增Mem实例化
	//修改Mem实例化 llsc
	MEM mem0(
        .rst(rst),		
	    .op(op_ex),
	 	.regcData(regcData_ex),
		.regcAddr(regcAddr_ex),
		.regcWr(regcWrite_ex),
		.memAddr_i(memAddr_ex),
		.memData(memData_ex),	
		.rdData(rdData),
		.rLLbit(rLLbit),//llsc
		.regAddr(regAddr_mem),
		.regWr(regWr_mem),
		.regData(regData_mem),	
		.memAddr(memAddr),
		.wtData(wtData),
		.memWr(memWr),	
		.memCe(memCe),
		.wbit(wbit),   //llsc
		.wLLbit(wLLbit)//llsc
	);

	//新增LLbit实例化 llsc
	LLbit llbit0(
		.clk(clk),
		.rst(rst),
		.excpt(excpt),
		.wbit(wbit), 	
		.wLLbit(wLLbit),	
		.rLLbit(rLLbit)
	);

	

	//修改RegFile实例化
    RegFile regfile0(
        .clk(clk),
        .rst(rst),
        //.we(regcWrite_ex),
		.we(regWr_mem),
        //.waddr(regcAddr_ex),
		.waddr(regAddr_mem),
        //.wdata(regcData_ex),
		.wdata(regData_mem),
        .regaRead(regaRead),
        .regbRead(regbRead),
        .regaAddr(regaAddr),
        .regbAddr(regbAddr),
        .regaData(regaData_regFile),
        .regbData(regbData_regFile)
    );

	//中断-新增加模块
	CP0 cp0(
		.clk(clk),
		.rst(rst),
		.cp0we(cp0we),
		.cp0wData(cp0wData),
		.cp0Addr(cp0Addr),
		.cp0rData(cp0rData),
		.intr(intr),
		.intimer(intimer),
		.pc(pc_ex),
		.excptype(excptype_ex),
		.cause(cause),
		.status(status)
	);

	//中断-新增加模块
	Ctrl ctrl0(
		.rst(rst),
		.ejpc(ejpc),
		.excpt(excpt),
		.excptype(excptype_ex),
		.epc(epc_ex)
	);

endmodule

9 InstMem 指令存储器

`include "define.v";
//6、指令存储器
module InstMem(
    input wire ce,
    input wire [31:0] addr,
    output reg [31:0] data
);
    reg [31:0] instmem [1023 : 0];    
    always@(*)      
        if(ce == `RomDisable)
          data = `Zero;
        else
          data = instmem[addr[11 : 2]];   
    initial
      begin


		//指令测试

/*
		//初始化数据
		//ori R0,1100 -- R1 --00001100
        instmem [0] = 32'h34011100;
		//ori R0,0020 -- R2 --00000020
        instmem [1] = 32'h34020020;
		//ori R0,ff00 -- R3 --0000ff00
        instmem [2] = 32'h3403ff00;
		//ori R0,ffff -- R4 --0000ffff
        instmem [3] = 32'h3404ffff;
*/
		
		//I型指令测试
/*
		//andi R0,ffff --R5 --00000000
		instmem [4] = 32'h3005ffff;
		//xori R0,ffff --R6 --0000ffff
		instmem [5] = 32'h3806ffff;
		//addi R0,ffff --R7 --ffffffff
		instmem [6] = 32'h2007ffff;
//		//subi R0,ffff --R8 --00000001
//		instmem [7] = 32'h2408ffff;
		//lui  R0,ffff --R9 --ffff0000
		instmem [8] = 32'h3C09ffff;
*/

/*		
		//R1=00001100 R2=00000020
		instmem [4] = 32'b000000_00001_00010_00101_00000_100000;//add,R5,R1,R2  00001120
		instmem [5] = 32'b000000_00001_00010_00110_00000_100101;//or,R6,R1,R2   00001120
*/
		//R型指令测试
/*
		instmem [6] = 32'b000000_00001_00010_00111_00000_100010;//sub,R7,R1,R2  000010e0
		instmem [7] = 32'b000000_00001_00010_01000_00000_100100;//and,R8,R1,R2  00000000
		instmem [8] = 32'b000000_00001_00010_01001_00000_100110;//xor,R9,R1,R2  00001120

		//lui  R0,ffff --R10 --ffff0000
		instmem [9] = 32'h3C0Affff;

		
		//R11=fffe0000 R12=7fff8000  R13=ffff8000
		// Ra=sa={25'b0,imm[10:6]}
		instmem [10] = 32'b000000_00000_01010_01011_00001_000000;//sll,R11,Ra,R10
		instmem [11] = 32'b000000_00000_01010_01100_00001_000010;//srl,R12,Ra,R10  		
		instmem [12] = 32'b000000_00000_01010_01101_00001_000011;//sra,R13,Ra,R10
*/

		//J- JR型指令测试
/*
		//pc=jaddr=npc(4) offset(26) 00(2)
		//instmem [6] = 32'h08000001;  	//j 1		编码000010  pc=0004 	
		instmem [6] = 32'h0C000002; 	//jal 2		编码000011  pc=0008	r31=npc001c
*/

/*
		//pc=jaddr=(rs)
		instmem [6] = 32'h3407000C;//ori,R7,000C
		//instmem [7] = 32'b000000_00111_00000_00000_00000_001000; //jr R7		编码001000 pc=0000000C
		instmem [7] = 32'b000000_00111_00000_00000_00000_001001; //jalr R7 编码001001 pc=0000000C R31=00000020
*/

/*
		//J+型指令测试
		//pc=jaddr=npc+S14 offset(16) 00(2)
		//R1=00001100 R2=00000020 R3=000000ff R4=0000ffff R5=00001120 R6=00001120
		//instmem [6] = 32'b000100_00101_00110_0000_0000_0000_0000;  //beq r5,r6,0 		编码000100  pc=001C 
		//instmem [6] = 32'b000100_00101_00110_0000_0000_0000_0001;  //beq r5,r6,1 		编码000100  pc=0020 
		//instmem [6] = 32'b000101_00001_00110_1111_1111_1111_1110;  //bne r5,r6,-2 		编码000101  pc=0014 
				
		//instmem [6] = 32'b000001_00010_00000_0000_0000_0000_0001;  //bltz r2,r0,1 		编码000001 pc=0020 
		instmem [6] = 32'b000111_00001_00000_1111_1111_1111_1110;  //bgtz r1,r0,-2 		编码010011 pc=0014 		

		//ori R7,0001 -- R7 --00000001
        instmem [7] = 32'h34070001;	//ori  R7 1
		//ori R8,0001 -- R8 --00000001
        instmem [8] = 32'h34080001;	//ori  R8 1
*/

/*
		//(r1)=0000 1100
		//    +0000 0018
		//addr=0000 1118  
		//    =1000100011000 字节地址
		//    =100 0100 0110 字地址
		//	  =446H	         只有1K空间
		//    =46H		     丢掉了高位的1位
		//    =70
		//mem[70]=(r6)
		instmem[6]=32'b101011_00001_00110_0000_0000_0001_1000; //sw r6,0x18(r1)
		//(r7)=mem[70]
		instmem[7]=32'b100011_00001_00111_0000_0000_0001_1000; //lw r7,0x18(r1)
*/


		//测试12条MIPS指令

/*
		//测试slt
		//R1=00001100 R2=00000020
	  	instmem [6] = 32'b000000_00001_00010_00111_00000_101010;//slt,R7,R1,R2   00000000
		//lui  R0,ffff --R8 --ffff0000
		instmem [7] = 32'h3C08ffff;
		//ori R8,ffff --R8 --ffffffff
		instmem [8] = 32'b001101_01000_01000_1111_1111_1111_1111;
		//lui  R0,ffff --R9 --ffff0000
		instmem [9] = 32'h3C09ffff;
		//ori R9,ffff --R9 --fffffffe
		instmem [10] = 32'b001101_01001_01001_1111_1111_1111_1110;
		//R8=ffffffff(-1) R9=fffffffe(-2)
	  	instmem [11] = 32'b000000_01001_01000_01010_00000_101010;//slt,R10,R9,R8   00000001
*/

/*
		//测试乘除
		//R1=00001100 R2=00000020 
		//multu,R1,R2 0_22000
		instmem [6] = 32'b000000_00001_00010_00111_00000_011001;//multu,R1,R2
		//ori R7,ffff -- R7 --0000ffff
        instmem [7] = 32'h3407ffff;	//ori  R7 ffff
		//sll R7,R7,10h -- R7 --ffff0000
        instmem [8] = 32'b000000_00000_00111_00111_10000_000000;//sll R7,R7,10h
		//mult R7,R2  	ffffffff_ffe00000
        instmem [9] = 32'b000000_00111_00010_00000_00000_011000;//mult R7,R2
		//divu r1,r2	88_0
        instmem [10] = 32'b000000_00001_00010_00000_00000_011011;//divu r1,r2
		//div r3,r2 	fffff800_0
        instmem [11] = 32'b000000_00111_00010_00000_00000_011010;//div r7,r2
*/

/*
		//测试剩余4条指令
		//R1=00001100 R2=00000020 
		//mthi,R1--hi=00001100
		instmem [6] = 32'b000000_00001_00000_00000_00000_010001;//mthi,R1
		//mtlo,R2--lo=00000020 
		instmem [7] = 32'b000000_00010_00000_00000_00000_010011;//mtlo,R2
		//mfhi,R7--R7=00001100
		instmem [8] = 32'b000000_00000_00000_00111_00000_010000;//mfhi,R7
		//mflo,R8--R8=00000020 
		instmem [9] = 32'b000000_00000_00000_01000_00000_010010;//mflo,R8
*/

/*
		//测试原子指令

		//计算地址说明
		//(r1)=0000 1100
		//    +0000 0020
		//addr=0000 1120  
		//    =1000100100000 字节地址
		//    =100 0100 1000 字地址
		//	  =448H	         只有1K空间
		//    =48H		     丢掉了高位的1位
		//    =72
		//mem[72]<-->(r7)



		//测试功能
		//R1=00001100 R2=00000020 
		//Lpt: 	LL r7,0x20(r1)		//读取程序里的信号量,LLibt=1
		//ll r7,0x20(r2) --(r7)=mem[72]=0
		instmem [6] = 32'b110000_00001_00111_0000_0000_0010_0000;//ll r7,0x20(r1)
		//if(r7 == clearFlag)	//判断信号是否被占用,为clearFlag表示没占用
		//pc=jaddr=npc+S14 offset(16) 00(2)
		//bne,r7,r0,else(+4)
		instmem [7] = 32'b000101_00111_00000_0000_0000_0000_0100;//bne,r7,r0,else(+4)
		//{
		//	MOV r7, setFlag			//设置本程序的占用标志
		//ori R7,ffff -- R7 --0000ffff
        instmem [8] = 32'h3407ffff;	//ori  R7 ffff
		//	SC r7, 0x20(r1)			//设置到信号量里
		instmem [9] = 32'b111000_00001_00111_0000_0000_0010_0000;//sc r7,0x20(r1)
		//	if(r7 == 1) goto Success//如果信号量设置成功,r1就会为1
		//pc=jaddr=npc+S14 offset(16) 00(2)
		//bne,r1,r0,Success(+2)
		instmem [10] = 32'b000101_00111_00000_0000_0000_0000_0010;//bne,r7,r0,Success(+2)
		//	//如果信号量没有设置成功,重新读信号量,即重新执行LL指令
		//	else goto Lpt
		//j Lpt(6)
		//pc=jaddr=npc(4) offset(26) 00(2)	
		instmem [11] = 32'h08000006;//j Lpt(6) 编码000010  pc=0018 
		//}
		//else goto Lpt
		//j Lpt(6)
		//pc=jaddr=npc(4) offset(26) 00(2)	
		instmem [12] =  32'h08000006;//j Lpt(6) 编码000010  pc=0018 
		//Success:
		//	访问指定的存储区域
		//	set r7,clearFlag
		//andi R7,0000 -- R7 --00000000
        instmem [13] = 32'h30070000;	//andi R7,0000
		//	lw r7,(0x20)r1
		instmem[14]=32'b100011_00001_00111_0000_0000_0010_0000; //lw r7,0x20(r1)
*/



		//测试中断指令

/*	
		//测试syscall
		instmem[6]=32'h0000000c;//syscall instruction

		instmem[7]=32'h3407ffff;//ori
		instmem[8]=32'h3408ffff;//ori

		instmem [16]=32'h340affff;//syscall except program
		instmem [17]=32'h340bffff;//ori
		instmem [18]=32'h42000018;//eret inatruction
*/

		//测试定时中断
		instmem[0] =32'h34020000; 	//ori $2, $0,0
		instmem[1]= 32'h34010014; 	//ori $1, $0,20
		instmem[2]= 32'h40815800; 	//mtc0 $1,$11 set compare=20
		instmem[3]=32'h3c011000;	//lui $1, 0x1000
		instmem[4]=32'h34210401;	//ori $1, $1,0x0401
		instmem[5]= 32'h40816000; 	//mtc0 $1,$12 set status,enable int
		instmem[6]= 32'h08000006; 	//lpt: j lpt
		//interproc first addr Ox0050
		instmem[20]= 32'h34030001; 	//ORI $3,$0,1
		instmem[21]= 32'h34040014;	//ORI S4, $0,20
		instmem[22]= 32'h00431020;	//ADD $2,$2,$3
		instmem[23]= 32'h40015800;	//MFC $1,$11 read compare
		instmem[24]=32'h00240820; 	//ADD $1,$1,$4
		instmem[25]= 32'h40815800;	//MTC0 s1,$11 set compare
		instmem[26]= 32'h42000018;	//eret



      end
endmodule

10 SOC 顶层

//7、系统封装
//整合MIPS DataMem InstMem
//端口信号只需clk rst,其余信号在MIPS中增加,并且新增使用内部信号连线
module SoC(
    input wire clk,
    input wire rst
);
    wire [31:0] instAddr;
    wire [31:0] instruction;
    wire romCe;

	//ls
    wire memCe, memWr;    
    wire [31:0] memAddr;
    wire [31:0] rdData;
    wire [31:0] wtData;

	//中断
	wire[5:0] intr;
	wire intimer;
	assign intr={5'b0,intimer};

	//修改MIPS实例
	//中断-修改
    MIPS mips0(
        .clk(clk),
        .rst(rst),
        .instruction(instruction),
        .instAddr(instAddr),
        .romCe(romCe),
		.rdData(rdData),        
    	.wtData(wtData),        
    	.memAddr(memAddr),        
    	.memCe(memCe),        
    	.memWr(memWr),
		.intr(intr),//中断
		.intimer(intr[0])//中断
    );	
    
    InstMem instrom0(
        .ce(romCe),
        .addr(instAddr),
        .data(instruction)
    );

	//新增DataMem实例化
	DataMem datamem0(       
    	.ce(memCe),        
    	.clk(clk),        
    	.we(memWr),        
    	.addr(memAddr),        
    	.wtData(wtData),        
    	.rdData(rdData)  
	);
endmodule

最后

2023-5-24 21:44:39

你对我百般注视,
并不能构成万分之一的我,
却是一览无余的你。

祝大家逢考必过
点赞收藏关注哦文章来源地址https://www.toymoban.com/news/detail-489225.html

到了这里,关于4实现中断异常相关指令-2【FPGA模型机课程设计】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 6设计指令流水线-1【FPGA模型机课程设计】

    2023-5-25 09:25:05 以下内容源自《【FPGA模型机课程设计】》 仅供学习交流使用 0集中实践环节计划书【FPGA模型机课程设计】 2023-5-30 16:03:03 添加MEM_WB模块 2023-5-30 19:00:25 IF模块添加stall 2023-5-30 21:08:26 修改stall相关的处理 在id ctrl 流水寄存器中修改 因为原来没有理解stall[5:0]是什么

    2024年02月08日
    浏览(42)
  • 5模型机整体的联调【FPGA模型机课程设计】

    2023-5-25 08:15:05 以下内容源自《【FPGA模型机课程设计】》 仅供学习交流使用 0集中实践环节计划书【FPGA模型机课程设计】 第一周周五: 模型机整体的联调。完成模型机指令系统实现。学生根据设计好的指令系统实现方案,在Modelsim上进行功能仿真。要求将所有设计的机器指令

    2024年02月08日
    浏览(29)
  • 2模型计算机各功能电路设计【FPGA模型机课程设计】

    2023-5-22 10:18:30 以下内容源自《【FPGA模型机课程设计】》 仅供学习交流使用 0集中实践环节计划书【FPGA模型机课程设计】 简单的指令设计 MIPS CPU 设计【计算机组成原理】 详细的指令设计 MIPS CPU 设计+【计算机组成原理】 测试结果具体分析可以查看: 实验三+ I型指令设计实验

    2024年02月07日
    浏览(29)
  • 单周期-开发过程【FPGA模型机课程设计】

    2023-5-25 08:24:28 以下内容源自《【FPGA模型机课程设计】》 仅供学习交流使用 0集中实践环节计划书【FPGA模型机课程设计】 工程迭代过程 README.txt 1FPGA模型计算机整体方案设计【FPGA模型机课程设计】 2模型计算机各功能电路设计【FPGA模型机课程设计】 实现基本20条指令 3模型机

    2024年02月09日
    浏览(31)
  • 电子技术课程设计基于FPGA的音乐硬件演奏电路的设计与实现

    【ChatGPT】前些天发现了一个巨牛的人工智能学习电子书,通俗易懂,风趣幽默,无广告,忍不住分享一下给大家。(点击查看学习资料) wx供重浩:创享日记 对话框发送:乐曲电路 免费获取完整无水印论文报告(包含电路图) 1、课程设计题目 设计一个乐曲演奏电路,能够

    2024年02月05日
    浏览(43)
  • ARMv8-A 与异常相关的指令

    最近一直在学习 ARMv8-A 的东西,记录一下与异常相关的指令。下面的内容基于AArch64讨论,暂不考虑 AArch32。 与异常生成相关的指令如下所示。下面主要学习 SVC 和 HVC 。 1. SVC SVC (Supervisor Call) 产生一个路由到 EL1 的异常,可以调用系统服务这些。此时, ESR_ELx.EC = 0x15 。 2. HVC

    2024年02月21日
    浏览(36)
  • LLMs:ColossalChat相关的开源训练数据集简介(SFT指令微调数据集+奖励模型排序数据集+RLHF数据集)、RLHF算法实现的三个阶段(监督指令微调→训练奖励模型→RLHF训练模型→​​​

    LLMs:ColossalChat相关的开源训练数据集简介(SFT指令微调数据集+奖励模型排序数据集+RLHF数据集)、RLHF算法实现的三个阶段(监督指令微调→训练奖励模型→RLHF训练模型→推理量化和服务)   目录 ColossalChat的使用方法 1、ColossalChat相关的开源训练数据集 (1)、SFT指令微调数据集

    2024年02月14日
    浏览(36)
  • FPGA课程设计--电子门锁的设计

      这是一个关于FPGA的课程设计【只是一个简单的课程设计,并没有涉及很深的FPGA技术知识】,实物测试结果可以参考 FPGA课程设计-电子门锁   视频中使用的板子是睿智助学的开发板,芯片型号为 EP4CE6E22C8 。大家如果用的是其他开发板也可以参考本文章。除了芯片的资源

    2024年02月04日
    浏览(25)
  • 【FPGA】课程设计:简单计时器闹钟

    本文是EDA实验的课程设计 完整源码文件获取方式见文末 少废话,先看东西。 EDA实验-闹钟演示视频 设计一个电子闹钟。要求电路上电后自动计时,到达预置的闹响时刻后,由蜂鸣器发出音乐报警。闹响时刻可利用按键设置,设置范围0~999999。 此次实验除了满足上述基本功能

    2024年02月04日
    浏览(32)
  • 数字系统设计(FPGA)课程设计: 多功能数字钟

    一、目的: 实现多功能数字钟,具备下列功能: 1、数字钟:能计时,实现小时、分钟、秒的显示; 2、数字跑表:精度至0.01秒 比如显示12.97秒; 3、闹钟: 可以设定闹钟,用试验箱上的蜂鸣器作为闹铃; 4、调时:可以对时间进行设定; 5、日期设定:能设定日期并显示当前

    2023年04月18日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包