前言
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
//测试定时中断
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
等待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
中断异常指令设计
参考:教学资料
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
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
测试定时中断时需要使用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
等待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
附录
其余与上篇一样
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
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
祝大家逢考必过
点赞收藏关注哦文章来源地址https://www.toymoban.com/news/detail-489225.html
到了这里,关于4实现中断异常相关指令-2【FPGA模型机课程设计】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!