当前位置:   article > 正文

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条指令

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

在这里插入图片描述

测试与结果

		//测试中断指令
		
		//测试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


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在这里插入图片描述

		//测试定时中断
		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


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

0-6
在这里插入图片描述

等待count== compare
在这里插入图片描述
然后执行中断程序
执行完成异常返回
在这里插入图片描述
继续等待count== compare
在这里插入图片描述

测试原子指令-失败案例

在原有的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


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

在这里插入图片描述

中断异常指令设计

参考:教学资料

4.5 异常与中断处理

4.5.1 异常与中断的概念

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

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

在这里插入图片描述
断点即返回地址,MIPS 处理器对异常和中断所保存的“返回地址”有所不同,异常发生时,返回地址是当前指令的下一条指令地址(NPC),因为引发异常的指令已经被响应过了,不需要再重复执行。而外部中断发生时,返回地址是当前指令地址(PC),因为当前指令的执行被打断,中断返回后需重新执行。

在这里插入图片描述
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]字段是可写的,其余字段只可读。

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

如图 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 所示。

在这里插入图片描述

其中,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 异常和中断的设计实现

在这里插入图片描述

如图 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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

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;


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100

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;


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79

在代码设计中,选用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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

MEM

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

				`Eret:
					begin
						//LLbit<-0
						wbit=`Valid;
						wLLbit = `ClearFlag;
					end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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)
	);


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75

SOC

系统封装

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


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

		.intr(intr),//中断
		.intimer(intr[0])//中断
    );	
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在这里插入图片描述
测试定时中断时需要使用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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

0-6
在这里插入图片描述

等待count== compare
在这里插入图片描述
然后执行中断程序
执行完成异常返回
在这里插入图片描述
继续等待count== compare
在这里插入图片描述

另外,对于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


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

在这里插入图片描述

附录

其余与上篇一样

0 框架

顶层设计
在这里插入图片描述

代码框架

在这里插入图片描述

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

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


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540
  • 541
  • 542
  • 543
  • 544
  • 545
  • 546
  • 547
  • 548
  • 549
  • 550
  • 551
  • 552
  • 553
  • 554
  • 555
  • 556
  • 557
  • 558
  • 559
  • 560
  • 561
  • 562
  • 563
  • 564
  • 565
  • 566
  • 567
  • 568
  • 569
  • 570
  • 571
  • 572
  • 573
  • 574
  • 575
  • 576
  • 577
  • 578
  • 579
  • 580
  • 581
  • 582
  • 583
  • 584
  • 585
  • 586
  • 587
  • 588
  • 589
  • 590
  • 591
  • 592
  • 593
  • 594
  • 595
  • 596
  • 597
  • 598
  • 599
  • 600
  • 601
  • 602
  • 603
  • 604
  • 605
  • 606
  • 607
  • 608
  • 609
  • 610
  • 611
  • 612
  • 613
  • 614
  • 615
  • 616
  • 617
  • 618
  • 619
  • 620
  • 621
  • 622
  • 623
  • 624
  • 625
  • 626
  • 627
  • 628
  • 629
  • 630
  • 631
  • 632
  • 633
  • 634
  • 635
  • 636
  • 637
  • 638
  • 639
  • 640
  • 641
  • 642
  • 643
  • 644
  • 645
  • 646
  • 647
  • 648
  • 649
  • 650
  • 651
  • 652
  • 653
  • 654
  • 655
  • 656
  • 657
  • 658
  • 659
  • 660
  • 661
  • 662
  • 663
  • 664
  • 665
  • 666
  • 667

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208

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



  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

最后

2023-5-24 21:44:39

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

祝大家逢考必过
点赞收藏关注哦

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/749549
推荐阅读
相关标签
  

闽ICP备14008679号