MIPS架构中定义的异常类型
MIPS32架构中,有些事情打断程序的正常的执行流程,这些事情称为中断、陷阱、系统调用以及其他打断程序执行流程的情况,统称为异常
。
此处的OpenMIPS处理器只实现了其中6中异常情况的处理:
- 硬件复位
- 中断(软中断、硬中断)
- syscall系统调用
- 无效指令
- 溢出
- 自陷指令引发的异常
异常发生后,进入异常处理例程进行具体处理,处理结束后,返回到异常发生前的状态继续执行。`硬件复位是一种特殊的异常,在于不用从异常处理例程返回,不需要保护现场,不用保存返回地址,此处的处理方法简单粗暴:全部寄存器清零,从地址0x0处取指执行,即复位。所以此处置详细论述其他5种异常的处理过程。
精确异常
当一个异常发生时,系统的顺序执行会被中断,此时,若干条指令处于流水线上的不同阶段,处理器会转到异常处理例程,异常处理结束后返回原程序继续执行。当异常发生时,因为不希望异常处理例程破坏原程序的正常执行,对于没有执行完的指令,必须记住它处于流水线的哪个阶段,以便异常处理结束后能恢复执行,这就是精确异常
当异常发生时,被异常打断的指令称为异常受害者
,该指令前面的所有指令都要被执行到流水线的最后一个阶段,即正常完成。但是该指令及该指令之后的指令都要被取消。
for example
e.g.1
第二条指令add执行阶段发生溢出异常,在这种情况下,指令1ori指令会顺利完成,指令2,3,4都会被取消。为了实现精确异常,必须要求异常发生的顺序与指令的顺序相同。流水线处理器上,异常会在流水线的不同阶段发生,带来问题。
e.g.2
加载指令lw会在流水线的访存阶段发生地址未对齐的异常
,该异常会在第四
个时钟周期发生,后一条指令di是无效指令mips32架构并没有这条指令,所以是无效的
,在流水线阶段引发无效指令异常,也就是第三
个周期,此时上一条加载指令lw还处于执行阶段,没有进入访存阶段,所以先发生的异常是无效指令异常。
从而不满足异常发生的顺序与指令的顺序相同
这一要求。
为了避免
上述情况,先发生的异常并不立即处理
,异常事件只是被标记,并继续运行流水线
,大多数处理器中,会设计一个特殊的流水线阶段
,专门用于处理异常
,如果某一条指令的异常事件达到流水线的这个阶段
,就会被进行异常处理
,并且当前处于流水线其余阶段的指令的异常事件都会被忽略
。
以上图为例,假设处理器会在访存阶段处理异常情况
,那么di指令虽然在第三个周期发生异常
,但并不处理
,只是一个保存一个异常标记
,等到了第五个时钟周期该指令进入访存阶段时再处理
。但是在第四个时钟周期
,上一条指令lw进入访存阶段
,并发生地址未对齐异常
,因为已经处于访存阶段
,所以会处理该异常
,包括无效指令异常在内的流水线其余阶段的异常都被忽略
。
通过上述方法,实现在流水线处理器中实现按指令执行的顺序处理异常,而不是按异常发生的顺序处理异常处理
。
异常处理过程
EXL为1,表示当前已经处于异常处理过程,如果当前发生的异常类型是中断,那么不处理,忽略,因为异常处理过程中会禁止中断。如果当前发生的异常类型不是中断,那么将异常原因保存到CP0中的Cause寄存器的ExCode字段
如果EXL为0
,那么将异常原因保存到CP0中的Cause寄存器的ExCode字段
,进入步骤二
检查发生异常的指令是否在延迟槽中
,如果在延迟槽中,那么设置EPC寄存器的值为该指令的地址减4,同时设置Cause寄存器的BD字段为1
,反之,设置EPC寄存器的值就位该指令的地址,同时设置Cause寄存器的BD字段为0
。
设置Status寄存器EXL字段为1
,表示进入异常处理过程
,禁止中断
处理器转移到事先定义好的一个地址
,在那个地址中往往有异常处理例程
,在其中进行异常处理,这个地址称为异常处理例程入口地址
OpenMIPS定义的异常处理例程入口地址表如下。此处对系统调用、无效指令、溢出、自陷这四类异常都设置为相同的处理例程入口地址,也可以设置为不同的地址。
在异常处理例程中会进行具体的异常处理,处理结束后,需要返回到异常发生前的状态继续执行。异常返回指令eret来完成此项工作,eret指令既要清除Status寄存器的EXL字段,从而使能中断,还要将EPC寄存器保存的地址恢复到PC中,从而返回到异常发生处继续执行
引延迟槽后,处理器执行转移指令的顺序:
转移指令->延迟槽指令->转移目标指令地址
流程图(我懒得画)
异常相关指令介绍
自陷指令
按照指令中是否包含立即数,分为2类
不包含立即数的自陷指令
31-26 | 25-21 | 20-16 | 15-6 | 5-0 | useage | function |
---|---|---|---|---|---|---|
SPECIAL(000000) | rs | rt | code | TEQ(110100) | teq rs,rt | if GPR[rs]=GPR[rt] then trap将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值比较,如果两者相等,发生自陷异常 |
SPECIAL(000000) | rs | rt | code | TGE(110000) | tge rs,rt | if GPR[rs] >= GPR[rt] then trap将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值作为有符号数比较,如果前者大于后者,那么引发自陷异常 |
SPECIAL(000000) | rs | rt | code | TGEU(110001) | tgeu rs,rt | if GPR[rs] >= GPR[rt] then trap将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值作为无 符号数比较,如果前者大于后者,那么引发自陷异常 |
SPECIAL(000000) | rs | rt | code | TLT(110010) | tlt rs,rt | if GPR[rs] < GPR[rt] then trap将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值作为有符号数比较,如果前者小 于后者,那么引发自陷异常 |
SPECIAL(000000) | rs | rt | code | TLTU(110011) | tltu rs,rt | if GPR[rs] >= GPR[rt] then trap将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值作无· 符号数比较,如果前者小 于后者,那么引发自陷异常 |
SPECIAL(000000) | rs | rt | code | TNE(110110) | tne rs,rt | if GPR[rs] != GPR[rt] then trap将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值比较,如果两者不相等,那么引发自陷异常 |
包含立即数的自陷指令
31-26 | 25-21 | 20-16 | 15-0 | useage | function |
---|---|---|---|---|---|
REGIMM(000001) | rs | TEQI(01100) | immediate | teqi rs ,immediate | if GPR[rs]=sign_extended(immediate) then trap 将地址为rs 的通用寄存器的值与指令中16位立即数符号扩展至32位 后的值比较,如果两者相等,那引发自陷异常 |
REGIMM(000001) | rs | TGEI(01000) | immediate | tgei rs ,immediate | if GPR[rs]=sign>=extended(immediate) then trap 将地址为rs 的通用寄存器的值与指令中16位立即数符号扩展至32位 后的值比较,如果前者大于等于后者,那么引发自陷异常 |
REGIMM(000001) | rs | TGEIU(01001) | immediate | tgeiu rs ,immediate | if GPR[rs]>=sign_extended(immediate) then trap 将地址为rs 的通用寄存器的值与指令中16位立即数符号扩展至32位后的值作为无符号数进行比较 ,如果前者大于等于后者,那么引发自陷异常 |
REGIMM(000001) | rs | TLTI(01010) | immediate | tlti rs ,immediate | if GPR[rs]<sign_extended(immediate) then trap 将地址为rs 的通用寄存器的值与指令中16位立即数符号扩展至32位后的值作为有符号数进行比较 ,如果前者小于后者,那么引发自陷异常、REGIMM(000001) |
REGIMM(000001) | rs | TNEI(01110) | immediate | tnei rs ,immediate | if GPR[rs]!=sign_extended(immediate) then trap 将地址为rs 的通用寄存器的值与指令中16位立即数符号扩展至32位后的值进行比较 ,如果两者不相等,那么引发自陷异常 |
异常返回指令eret
31-26 | 25 | 24-6 | 5-0 | useage | function |
---|---|---|---|---|---|
COP0(010000) | CO(1) | 0000 0000 0000 0000 000 | ERET(011000) | eret | 从异常处理例程返回,执行该指令(1)是EPC寄存器的值称为新的取指地址(2)设置Status寄存器的EXL字段为0,表示不再处于异常级 |
系统调用指令syscall
31-26 | 25-6 | 5-0 | useage | function |
---|---|---|---|---|
SPECIAL(000000) | code | SYSCALL(001100) | syscall | 引发系统调用异常。用户模式下的程序为了执行一些在内核模式下才能进行的操作,可以调用syscall指令,引发系统调用异常,进入异常处理例程,从而进入内核模式 |
实现思路
在流水线各个阶段手机异常信息,并传递到流水线访存阶段,在访存阶段同一处理异常信息。流水线各个阶段需要收集的异常信息:
译码
判断是否系统调用异常、是否返回指令、无效指令
执行
判断是否有自陷异常、溢出异常
访存
检查是否有中断发生。访存阶段,处理器结合CP0中相关寄存器的值,判断异常是否需要处理,如果需要处理,那么转移到该异常对应的处理例程入口地址,清除流水线上除回写阶段外的全部信息,同时修改协处理器CP0中相关寄存器的值
。eret指令,转移到EPC寄存器保存的地址处,同时清除流水线上除回写阶段外的全部信息,修改协处理器CP0中相关寄存器的值。所谓清除流水线上某个阶段的信息,其实就是将该阶段中所有寄存器设置为初始值即可
数据流图的修改
确定自陷指令、syscall指令、eret指令的过程
id
系统结构的修改
id
id模块判断是否调用指令syscall,异常返回指令eret,无效指令,将这些信息通过excepttype_o
接口传递到ex模块,同时将指令地址通过current_inst_addr_o
接口传递到执行阶段。
ex
ex模块进一步判断是否有自陷异常,或溢出异常。这些信息会融合到id模块的异常信息中,excepttype_i
传入,通过excepttype_o
传递到mem模块。同时current_inst_addr_o
接口将指令地址传递到mem模块,通过is_delayslot_o
指出指令是否位于延迟槽中,该信息也会传入mem模块。
mem
mem模块依据传递来的异常类型excepttype_i
,Cause寄存器的值cp0_cause_i
,Status寄存器的值cp0_status_i
,综合判断是否需要处理异常,如果需要处理,最终的异常类型会跳过excepttype_o
接口送入到CTRL
模块,CTRL模块据此给出异常处理的入口地址new_pc
传递到PC。
cp0_reg
处理异常时,需要修改CP0中的EPC,Status,Cause等寄存器的值,所以mem模块给出的最终的异常类型还要通过excepttype_o
接口送入CP0模块,同时送入的异常指令是否在延迟槽中is_in_delayslot_i
接口送入,发生异常指令的地址current_inst_address_o
接口送入。CP0模块根据这些信息修改相应寄存器的值。
CTRL
如果要处理异常,需要清除流水线上除回写阶段
外寄存器的值,CTRL模块通过送出flush
实现。flush
模块送到PC,IF/ID,ID/EX,EX/MEM,MEM/WB
等模块,将这些模块中的寄存器置为初始值。
LLbit
ll执行时设置LLbit为1,sc执行时,检测该寄存器是否为1,如果为1就正常运行,如果为0,说明出现了干扰,不进行存储操作。出现干扰的原因之一就是ll,sc指令之间产生了异常,所以在异常处理过程中会多进行一步操作,将LLbit寄存器设置为0
。
代码
因为这是自己动手写cpu基础版的最后一章了,所以把完整的代码放上来。
pc_reg.v
`include "define.v"
module pc_reg(
input wire clk,
input wire rst,
//来自控制模块的信息
input wire[5:0] stall,
input wire flush,
input wire[`RegBus] new_pc,
//来自译码阶段的信息
input wire branch_flag_i,
input wire[`RegBus] branch_target_address_i,
output reg[`InstAddrBus] pc,
output reg ce
);
always @ (posedge clk) begin
if (rst == `RstEnable) begin
ce <= `ChipDisable;
end else begin
ce <= `ChipEnable;
end
end
/*always @ (posedge clk) begin
if (ce == `ChipDisable) begin
pc <= 32'h00000000;
end else if(stall[0] == `NoStop)begin
if(branch_flag_i == `Branch)begin//如果发生转移
pc <= branch_target_address_i;//给出转移到的目标地址
end else begin
pc <= pc + 4'h4;
end
end
end*/
always @ (posedge clk)begin
if(ce == `ChipDisable)begin
pc <= 32'h00000000;
end else begin
if(flush == 1'b1)begin
//flush==1表示异常发生 将从CTRL模块给出的异常处理
//例程入口地址 new_pc处取指执行
pc <= new_pc;
end else if(stall[0] == `NoStop)begin
end
end
end
end
endmodule
inst_rom.v
`include "define.v"
//inst_rom.v
module inst_rom(
input wire ce,
input wire[`InstAddrBus] addr,
output reg[`InstBus] inst
);
//定义一个数组,大小是InstMemNum,元素宽度是InstBus
reg[`InstBus] inst_mem[0:`InstMemNum-1];
//使用文件inst_rom.data 初始化指令存储器
initial $readmemh ("D:/test_2/inst_rom_11_3.data",inst_mem);
always @ (*)
begin
if(ce == `ChipDisable)//当复位信号无效时,依据输入的地址,给出指令存储器ROM中对应的元素
begin
inst <= `ZeroWord;
end
else begin
inst <= inst_mem[addr[`InstMemNumLog2+1:2]];
end
end
endmodule
if_id.v
`include "define.v"
module if_id(
input wire clk,
input wire rst,
input wire[`InstAddrBus] if_pc,
input wire[`InstBus] if_inst,
input wire[5:0] stall, //来自控制模块的信息
input wire flush,
output reg[`InstAddrBus] id_pc,
output reg[`InstBus] id_inst
);
/**************************说明******************************
*****stall[0]表示取指地址PC是否保持不变,为1表示保持不变*****
*******stall[1]表示流水线取指阶段是否暂停,为1表示暂停*******
*******stall[2]表示流水线译码阶段是否暂停,为1表示暂停*******
*******stall[3]表示流水线执行阶段是否暂停,为1表示暂停*******
*******stall[4]表示流水线访存阶段是否暂停,为1表示暂停*******
*******stall[5]表示流水线回写阶段是否暂停,为1表示暂停*******
(1)stall[1]为Stop,stall[5]为NoStop,表示取指阶段暂停,译码阶段
继续,所以使用空指令作为下一个周期进入译码阶段的指令
(2)stall[1]为NoStop,取指阶段继续,取得的指令进入译码阶段
(3)其余情况下,保持译码阶段的寄存器id_pc,id_inst不变
************************************************************/
always @ (posedge clk) begin
if (rst == `RstEnable) begin
id_pc <= `ZeroWord;
id_inst <= `ZeroWord;
end else if(flush== 1'b1)begin
//异常发生 清除流水线 所以要复位id_pc id_inst寄存器的值
id_pc <= `ZeroWord;
id_inst <= `ZeroWord;
end else if(stall[1] == `Stop && stall[2] == `NoStop)begin
id_pc <= `ZeroWord;
id_inst <= `ZeroWord;
end else if(stall[1] == `NoStop)begin
id_pc <= if_pc;
id_inst <= if_inst;
end
end
endmodule
ctrl.v
//ctrl.v
`include "define.v"
module ctrl(
input wire rst,
input wire stallreq_from_id,
input wire stallreq_from_ex,
input wire[31:0] excepttype_i,
input wire[`RegBus] cp0_epc_i,
output reg[5:0] stall,
output reg[`RegBus] new_pc,
output reg flush
);
/**************************说明******************************
*****stall[0]表示取指地址PC是否保持不变,为1表示保持不变*****
*******stall[1]表示流水线取指阶段是否暂停,为1表示暂停*******
*******stall[2]表示流水线译码阶段是否暂停,为1表示暂停*******
*******stall[3]表示流水线执行阶段是否暂停,为1表示暂停*******
*******stall[4]表示流水线访存阶段是否暂停,为1表示暂停*******
*******stall[5]表示流水线回写阶段是否暂停,为1表示暂停*******
************************************************************/
always @ (*) begin
if(rst == `RstEnable) begin
stall <= 6'b000000;
flush <= 1'b0;
new_pc <= `ZeroWord;
end else if(excepttype_i != `ZeroWord) begin
flush <= 1'b1;
stall <= 6'b000000;
case (excepttype_i)
32'h00000001: begin //interrupt
new_pc <= 32'h00000020;
end
32'h00000008: begin //syscall
new_pc <= 32'h00000040;
end
32'h0000000a: begin //inst_invalid
new_pc <= 32'h00000040;
end
32'h0000000d: begin //trap
new_pc <= 32'h00000040;
end
32'h0000000c: begin //ov
new_pc <= 32'h00000040;
end
32'h0000000e: begin //eret
new_pc <= cp0_epc_i;
end
default : begin
end
endcase
end else if(stallreq_from_ex == `Stop) begin
stall <= 6'b001111;
flush <= 1'b0;
end else if(stallreq_from_id == `Stop) begin
stall <= 6'b000111;
flush <= 1'b0;
end else begin
stall <= 6'b000000;
flush <= 1'b0;
new_pc <= `ZeroWord;
end //if
end //always
endmodule
data_ram.v
`include "define.v"
module data_ram(
input wire clk,
input wire ce,//数据存储器使能信号
input wire we,//是否为写操作 写1
input wire[`DataAddrBus] addr,//要访问的地址
input wire[3:0] sel,//字节选择信号
input wire[`DataBus] data_i,//要写入的数据
output reg[`DataBus] data_o//读出的数据
);
//定义四个字节数组
reg[`ByteWidth] data_mem0[0:`DataMemNum-1];
reg[`ByteWidth] data_mem1[0:`DataMemNum-1];
reg[`ByteWidth] data_mem2[0:`DataMemNum-1];
reg[`ByteWidth] data_mem3[0:`DataMemNum-1];
//写操作
always @ (posedge clk)begin
if(ce == `ChipDisable) begin
end else if(we == `WriteEnable)begin
if(sel[3] == 1'b1)begin
data_mem3[addr[`DataMemNumLog2+1:2]] <= data_i[31:24];
end
if(sel[2] == 1'b1)begin
data_mem2[addr[`DataMemNumLog2+1:2]] <= data_i[23:16];
end
if(sel[1] == 1'b1)begin
data_mem1[addr[`DataMemNumLog2+1:2]] <= data_i[15:8];
end
if(sel[0 == 1'b1])begin
data_mem0[addr[`DataMemNumLog2+1:2]] <= data_i[7:0];
end
end
end
//读操作
always @ (*) begin
if(ce == `ChipDisable)begin
data_o <= `ZeroWord;
end else if(we == `WriteDisable)begin
data_o <= {data_mem3[addr[`DataMemNumLog2+1:2]],data_mem2[addr[`DataMemNumLog2+1:2]],data_mem1[addr[`DataMemNumLog2+1:2]],data_mem0[addr[`DataMemNumLog2+1:2]]};
end else begin
data_o <= `ZeroWord;
end
end
endmodule
define.v
//全局
`define RstEnable 1'b1
`define RstDisable 1'b0
`define ZeroWord 32'h00000000
`define WriteEnable 1'b1
`define WriteDisable 1'b0
`define ReadEnable 1'b1
`define ReadDisable 1'b0
`define AluOpBus 7:0
`define AluSelBus 2:0
`define InstValid 1'b0
`define InstInvalid 1'b1
`define Stop 1'b1
`define NoStop 1'b0
`define InDelaySlot 1'b1
`define NotInDelaySlot 1'b0
`define Branch 1'b1
`define NotBranch 1'b0
`define InterruputAssert 1'b1
`define InterruputNotAssert 1'b0
`define TrapAssert 1'b1
`define TrapNotAssert 1'b0
`define True_v 1'b1
`define False_v 1'b0
`define ChipEnable 1'b1
`define ChipDisable 1'b0
//指令
`define EXE_AND 6'b100100
`define EXE_OR 6'b100101
`define EXE_XOR 6'b100110
`define EXE_NOR 6'b100111
`define EXE_ANDI 6'b001100
`define EXE_ORI 6'b001101
`define EXE_XORI 6'b001110
`define EXE_LUI 6'b001111
`define EXE_SLL 6'b000000
`define EXE_SLLV 6'b000100
`define EXE_SRL 6'b000010
`define EXE_SRLV 6'b000110
`define EXE_SRA 6'b000011
`define EXE_SRAV 6'b000111
`define EXE_SYNC 6'b001111
`define EXE_PREF 6'b110011
`define EXE_MOVZ 6'b001010
`define EXE_MOVN 6'b001011
`define EXE_MFHI 6'b010000
`define EXE_MTHI 6'b010001
`define EXE_MFLO 6'b010010
`define EXE_MTLO 6'b010011
`define EXE_SLT 6'b101010
`define EXE_SLTU 6'b101011
`define EXE_SLTI 6'b001010
`define EXE_SLTIU 6'b001011
`define EXE_ADD 6'b100000
`define EXE_ADDU 6'b100001
`define EXE_SUB 6'b100010
`define EXE_SUBU 6'b100011
`define EXE_ADDI 6'b001000
`define EXE_ADDIU 6'b001001
`define EXE_CLZ 6'b100000
`define EXE_CLO 6'b100001
`define EXE_MULT 6'b011000
`define EXE_MULTU 6'b011001
`define EXE_MUL 6'b000010
`define EXE_MADD 6'b000000
`define EXE_MADDU 6'b000001
`define EXE_MSUB 6'b000100
`define EXE_MSUBU 6'b000101
`define EXE_DIV 6'b011010
`define EXE_DIVU 6'b011011
`define EXE_J 6'b000010
`define EXE_JAL 6'b000011
`define EXE_JALR 6'b001001
`define EXE_JR 6'b001000
`define EXE_BEQ 6'b000100
`define EXE_BGEZ 5'b00001
`define EXE_BGEZAL 5'b10001
`define EXE_BGTZ 6'b000111
`define EXE_BLEZ 6'b000110
`define EXE_BLTZ 5'b00000
`define EXE_BLTZAL 5'b10000
`define EXE_BNE 6'b000101
`define EXE_LB 6'b100000
`define EXE_LBU 6'b100100
`define EXE_LH 6'b100001
`define EXE_LHU 6'b100101
`define EXE_LL 6'b110000
`define EXE_LW 6'b100011
`define EXE_LWL 6'b100010
`define EXE_LWR 6'b100110
`define EXE_SB 6'b101000
`define EXE_SC 6'b111000
`define EXE_SH 6'b101001
`define EXE_SW 6'b101011
`define EXE_SWL 6'b101010
`define EXE_SWR 6'b101110
`define EXE_SYSCALL 6'b001100
`define EXE_TEQ 6'b110100
`define EXE_TEQI 5'b01100
`define EXE_TGE 6'b110000
`define EXE_TGEI 5'b01000
`define EXE_TGEIU 5'b01001
`define EXE_TGEU 6'b110001
`define EXE_TLT 6'b110010
`define EXE_TLTI 5'b01010
`define EXE_TLTIU 5'b01011
`define EXE_TLTU 6'b110011
`define EXE_TNE 6'b110110
`define EXE_TNEI 5'b01110
`define EXE_ERET 32'b01000010000000000000000000011000
`define EXE_NOP 6'b000000
`define SSNOP 32'b00000000000000000000000001000000
`define EXE_SPECIAL_INST 6'b000000
`define EXE_REGIMM_INST 6'b000001
`define EXE_SPECIAL2_INST 6'b011100
//AluOp
`define EXE_AND_OP 8'b00100100
`define EXE_OR_OP 8'b00100101
`define EXE_XOR_OP 8'b00100110
`define EXE_NOR_OP 8'b00100111
`define EXE_ANDI_OP 8'b01011001
`define EXE_ORI_OP 8'b01011010
`define EXE_XORI_OP 8'b01011011
`define EXE_LUI_OP 8'b01011100
`define EXE_SLL_OP 8'b01111100
`define EXE_SLLV_OP 8'b00000100
`define EXE_SRL_OP 8'b00000010
`define EXE_SRLV_OP 8'b00000110
`define EXE_SRA_OP 8'b00000011
`define EXE_SRAV_OP 8'b00000111
`define EXE_MOVZ_OP 8'b00001010
`define EXE_MOVN_OP 8'b00001011
`define EXE_MFHI_OP 8'b00010000
`define EXE_MTHI_OP 8'b00010001
`define EXE_MFLO_OP 8'b00010010
`define EXE_MTLO_OP 8'b00010011
`define EXE_SLT_OP 8'b00101010
`define EXE_SLTU_OP 8'b00101011
`define EXE_SLTI_OP 8'b01010111
`define EXE_SLTIU_OP 8'b01011000
`define EXE_ADD_OP 8'b00100000
`define EXE_ADDU_OP 8'b00100001
`define EXE_SUB_OP 8'b00100010
`define EXE_SUBU_OP 8'b00100011
`define EXE_ADDI_OP 8'b01010101
`define EXE_ADDIU_OP 8'b01010110
`define EXE_CLZ_OP 8'b10110000
`define EXE_CLO_OP 8'b10110001
`define EXE_MULT_OP 8'b00011000
`define EXE_MULTU_OP 8'b00011001
`define EXE_MUL_OP 8'b10101001
`define EXE_MADD_OP 8'b10100110
`define EXE_MADDU_OP 8'b10101000
`define EXE_MSUB_OP 8'b10101010
`define EXE_MSUBU_OP 8'b10101011
`define EXE_DIV_OP 8'b00011010
`define EXE_DIVU_OP 8'b00011011
`define EXE_J_OP 8'b01001111
`define EXE_JAL_OP 8'b01010000
`define EXE_JALR_OP 8'b00001001
`define EXE_JR_OP 8'b00001000
`define EXE_BEQ_OP 8'b01010001
`define EXE_BGEZ_OP 8'b01000001
`define EXE_BGEZAL_OP 8'b01001011
`define EXE_BGTZ_OP 8'b01010100
`define EXE_BLEZ_OP 8'b01010011
`define EXE_BLTZ_OP 8'b01000000
`define EXE_BLTZAL_OP 8'b01001010
`define EXE_BNE_OP 8'b01010010
`define EXE_LB_OP 8'b11100000
`define EXE_LBU_OP 8'b11100100
`define EXE_LH_OP 8'b11100001
`define EXE_LHU_OP 8'b11100101
`define EXE_LL_OP 8'b11110000
`define EXE_LW_OP 8'b11100011
`define EXE_LWL_OP 8'b11100010
`define EXE_LWR_OP 8'b11100110
`define EXE_PREF_OP 8'b11110011
`define EXE_SB_OP 8'b11101000
`define EXE_SC_OP 8'b11111000
`define EXE_SH_OP 8'b11101001
`define EXE_SW_OP 8'b11101011
`define EXE_SWL_OP 8'b11101010
`define EXE_SWR_OP 8'b11101110
`define EXE_SYNC_OP 8'b00001111
`define EXE_MFC0_OP 8'b01011101
`define EXE_MTC0_OP 8'b01100000
`define EXE_SYSCALL_OP 8'b00001100
`define EXE_TEQ_OP 8'b00110100
`define EXE_TEQI_OP 8'b01001000
`define EXE_TGE_OP 8'b00110000
`define EXE_TGEI_OP 8'b01000100
`define EXE_TGEIU_OP 8'b01000101
`define EXE_TGEU_OP 8'b00110001
`define EXE_TLT_OP 8'b00110010
`define EXE_TLTI_OP 8'b01000110
`define EXE_TLTIU_OP 8'b01000111
`define EXE_TLTU_OP 8'b00110011
`define EXE_TNE_OP 8'b00110110
`define EXE_TNEI_OP 8'b01001001
`define EXE_ERET_OP 8'b01101011
`define EXE_NOP_OP 8'b00000000
//AluSel
`define EXE_RES_LOGIC 3'b001
`define EXE_RES_SHIFT 3'b010
`define EXE_RES_MOVE 3'b011
`define EXE_RES_ARITHMETIC 3'b100
`define EXE_RES_MUL 3'b101
`define EXE_RES_JUMP_BRANCH 3'b110
`define EXE_RES_LOAD_STORE 3'b111
`define EXE_RES_NOP 3'b000
//指令存储器inst_rom
`define InstAddrBus 31:0
`define InstBus 31:0
`define InstMemNum 131071
`define InstMemNumLog2 17
//数据存储器data_ram
`define DataAddrBus 31:0
`define DataBus 31:0
`define DataMemNum 131071
`define DataMemNumLog2 17
`define ByteWidth 7:0
//通用寄存器regfile
`define RegAddrBus 4:0
`define RegBus 31:0
`define RegWidth 32
`define DoubleRegWidth 64
`define DoubleRegBus 63:0
`define RegNum 32
`define RegNumLog2 5
`define NOPRegAddr 5'b00000
//除法div
`define DivFree 2'b00
`define DivByZero 2'b01
`define DivOn 2'b10
`define DivEnd 2'b11
`define DivResultReady 1'b1
`define DivResultNotReady 1'b0
`define DivStart 1'b1
`define DivStop 1'b0
//CP0寄存器地址
`define CP0_REG_COUNT 5'b01001 //可读写
`define CP0_REG_COMPARE 5'b01011 //可读写
`define CP0_REG_STATUS 5'b01100 //可读写
`define CP0_REG_CAUSE 5'b01101 //只读
`define CP0_REG_EPC 5'b01110 //可读写
`define CP0_REG_PrId 5'b01111 //只读
`define CP0_REG_CONFIG 5'b10000 //只读
div.v
`include "define.v"
module div(
input wire clk,
input wire rst,
input wire signed_div_i,
input wire[31:0] opdata1_i,
input wire[31:0] opdata2_i,
input wire start_i,
input wire annul_i,
output reg[63:0] result_o,
output reg ready_o
);
wire[32:0] div_temp;
reg[5:0] cnt;
reg[64:0] dividend;
reg[1:0] state;
reg[31:0] divisor;
reg[31:0] temp_op1;
reg[31:0] temp_op2;
assign div_temp = {1'b0,dividend[63:32]} - {1'b0,divisor};
always @ (posedge clk) begin
if (rst == `RstEnable) begin
state <= `DivFree;
ready_o <= `DivResultNotReady;
result_o <= {`ZeroWord,`ZeroWord};
end else begin
case (state)
`DivFree: begin //DivFree״̬
if(start_i == `DivStart && annul_i == 1'b0) begin
if(opdata2_i == `ZeroWord) begin
state <= `DivByZero;
end else begin
state <= `DivOn;
cnt <= 6'b000000;
if(signed_div_i == 1'b1 && opdata1_i[31] == 1'b1 ) begin
temp_op1 = ~opdata1_i + 1;
end else begin
temp_op1 = opdata1_i;
end
if(signed_div_i == 1'b1 && opdata2_i[31] == 1'b1 ) begin
temp_op2 = ~opdata2_i + 1;
end else begin
temp_op2 = opdata2_i;
end
dividend <= {`ZeroWord,`ZeroWord};
dividend[32:1] <= temp_op1;
divisor <= temp_op2;
end
end else begin
ready_o <= `DivResultNotReady;
result_o <= {`ZeroWord,`ZeroWord};
end
end
`DivByZero: begin //DivByZero״̬
dividend <= {`ZeroWord,`ZeroWord};
state <= `DivEnd;
end
`DivOn: begin //DivOn״̬
if(annul_i == 1'b0) begin
if(cnt != 6'b100000) begin
if(div_temp[32] == 1'b1) begin
dividend <= {dividend[63:0] , 1'b0};
end else begin
dividend <= {div_temp[31:0] , dividend[31:0] , 1'b1};
end
cnt <= cnt + 1;
end else begin
if((signed_div_i == 1'b1) && ((opdata1_i[31] ^ opdata2_i[31]) == 1'b1)) begin
dividend[31:0] <= (~dividend[31:0] + 1);
end
if((signed_div_i == 1'b1) && ((opdata1_i[31] ^ dividend[64]) == 1'b1)) begin
dividend[64:33] <= (~dividend[64:33] + 1);
end
state <= `DivEnd;
cnt <= 6'b000000;
end
end else begin
state <= `DivFree;
end
end
`DivEnd: begin //DivEnd״̬
result_o <= {dividend[64:33], dividend[31:0]};
ready_o <= `DivResultReady;
if(start_i == `DivStop) begin
state <= `DivFree;
ready_o <= `DivResultNotReady;
result_o <= {`ZeroWord,`ZeroWord};
end
end
endcase
end
end
endmodule
id.v
`include "define.v"
module id(
input wire rst,
input wire[`InstAddrBus] pc_i,
input wire[`InstBus] inst_i,
input wire[`RegBus] reg1_data_i,
input wire[`RegBus] reg2_data_i,
input wire is_in_delayslot_i,//是否位于延迟槽指令
//送到regfile的信息
output reg reg1_read_o,
output reg reg2_read_o,
output reg[`RegAddrBus] reg1_addr_o,
output reg[`RegAddrBus] reg2_addr_o,
//送到执行阶段的信息
output reg[`AluOpBus] aluop_o,
output reg[`AluSelBus] alusel_o,
output reg[`RegBus] reg1_o,
output reg[`RegBus] reg2_o,
output reg[`RegAddrBus] wd_o,
output reg wreg_o,
//处于执行阶段的指令的运算结果
input wire ex_wreg_i,
input wire[`RegBus] ex_wdata_i,
input wire[`RegAddrBus] ex_wd_i,
input wire[`AluOpBus] ex_aluop_i,
//处于访存阶段的指令的运算结果
input wire mem_wreg_i,
input wire[`RegBus] mem_wdata_i,
input wire[`RegAddrBus] mem_wd_i,
output wire stallreq,
output reg next_inst_in_delayslot_o,//下条指令是否是延迟槽
output reg branch_flag_o,//是否发生转移
output reg[`RegBus] branch_target_address_o,//转移到的目标地址
output reg[`RegBus] link_addr_o,//转移指令要保存的返回地址
output reg is_in_delayslot_o,//当前处于译码指令是否位于延迟槽
output wire[`RegBus] inst_o ,//新增加的输出接口
//input wire[`AluOpBus] ex_aluop_i,
//output wire stallreq
output wire[31:0] excepttype_o,//收集的异常信息
output wire[`RegBus] current_inst_address_o//译码阶段指令的地址
);
wire[5:0] op = inst_i[31:26];
wire[4:0] op2 = inst_i[10:6];
wire[5:0] op3 = inst_i[5:0];
wire[4:0] op4 = inst_i[20:16];
wire[`RegBus] pc_plus_8;//保存当前译码阶段指令后面第二条指令的地址
wire[`RegBus] pc_plus_4;//保存当前译码阶段指令后面紧接着的指令地址
wire[`RegBus] imm_sll2_signedext;//对应分支指令中offset左移两位,再符号扩展至32位的值
reg[`RegBus] imm;
reg instvalid;
reg excepttype_is_syscall;//是否是系统调用异常syscall
reg excepttype_is_eret;//是否是异常返回指令
/*excepttype_o的低八位留给外部中断,第八位表示是否是syscall指令引起的
系统调用异常,第九位表示是否是无效指令引起的异常,第十二位表示是否是eret指令
eret指令可以认为是一种特殊的异常--返回异常*/
assign excepttype_o = {19'b0,excepttype_is_eret,2'b0,instvalid,excepttype_is_syscall,8'b0};
//输入信号pc_i就是当前处于译码阶段指令的地址
assign current_inst_address_o = pc_i;
assign stallreq = `NoStop;//在实现加载、存储指令时会给该信号赋值
assign imm_sll2_signedext = {{14{inst_i[15]}},inst_i[15:0],2'b00};
//imm_sll2_signedext对应分支指令中的offset左移两位,再符号扩展至32位的值
assign pc_plus_8 = pc_i+8;
assign pc_plus_4 = pc_i+4;
assign stallreq = `NoStop;
assign inst_o = inst_i;//译码阶段的指令
//新定义一个变量 表示要读取的寄存器1是否与上一条指令存在load相关
reg stallreq_for_reg1_loadrelate;
//新定义一个变量 表示要读取的寄存器2是否与上一条指令存在load相关
reg stallreq_for_reg2_loadrelate;
//新定义一个变量 表示上一条指令是否是加载指令
wire pre_inst_is_load;
//依据输入信号ex_aluop_i值 判断上一条指令是否是加载指令
//如果是加载指令 那么置pre_inst_is_load为1 反之置0
assign pre_inst_is_load = ((ex_aluop_i == `EXE_LB_OP)||
(ex_aluop_i == `EXE_LBU_OP)||
(ex_aluop_i == `EXE_LH_OP)||
(ex_aluop_i==`EXE_LHU)||
(ex_aluop_i==`EXE_LW_OP)||
(ex_aluop_i==`EXE_LWR_OP)||
(ex_aluop_i==`EXE_LWL_OP)||
(ex_aluop_i==`EXE_LL_OP)||
(ex_aluop_i==`EXE_SC_OP)) ? 1'b1 : 1'b0;
/*如果上一条指令是加载指令 且该加载指令要加载到目的寄存器就是当前指令
要通过Regfile模块读取端口1读取的通用寄存器,那么表示存在load相关*/
//设置stallreq_for_reg1_loadrelate为Stop
always @(*)begin
stallreq_for_reg1_loadrelate <= `NoStop;
if(rst == `RstEnable)begin
reg1_o <= `ZeroWord;
end else if(pre_inst_is_load == 1'b1 && ex_wd_i == reg1_addr_o && reg1_read_o == 1'b1)begin
stallreq_for_reg1_loadrelate <= `Stop;//存在load相关 Stop
end
end
//reg2与reg1同理
always @(*)begin
stallreq_for_reg2_loadrelate <= `NoStop;
if(rst == `RstEnable)begin
reg2_o <= `ZeroWord;
end else if(pre_inst_is_load == 1'b1 && ex_wd_i == reg2_addr_o && reg2_read_o == 1'b1)begin
stallreq_for_reg2_loadrelate <= `Stop;//存在load相关 Stop
end
end
assign stallreq = stallreq_for_reg1_loadrelate | stallreq_for_reg2_loadrelate;
always @ (*) begin
if (rst == `RstEnable) begin
aluop_o <= `EXE_NOP_OP;
alusel_o <= `EXE_RES_NOP;//nop
wd_o <= `NOPRegAddr;
wreg_o <= `WriteDisable;
instvalid <= `InstValid;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
reg1_addr_o <= `NOPRegAddr;
reg2_addr_o <= `NOPRegAddr;
imm <= 32'h0;
link_addr_o <= `ZeroWord;//转移指令要保存的返回地址
branch_target_address_o <= `ZeroWord;//转移到的目标地址
branch_flag_o <= `NotBranch;//不发生转移
next_inst_in_delayslot_o <= `NotInDelaySlot;//下一条指令是否位于延迟槽
end else begin //先初始化
aluop_o <= `EXE_NOP_OP;
alusel_o <= `EXE_RES_NOP;
wd_o <= inst_i[15:11];
wreg_o <= `WriteDisable;
instvalid <= `InstInvalid;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
reg1_addr_o <= inst_i[25:21];//rs
reg2_addr_o <= inst_i[20:16];//rt
imm <= `ZeroWord;
link_addr_o <= `ZeroWord;
branch_target_address_o <= `ZeroWord;
branch_flag_o <= `NotBranch;
next_inst_in_delayslot_o <= `NotInDelaySlot;
excepttype_is_syscall <= `False_v;//默认没有系统调用异常
excepttype_is_eret <= `False_v;//默认不是eret指令
instvalid <= `InstInvalid;//默认无效指令
case (op)//指令码
`EXE_SPECIAL_INST: begin //指令码是SPECIAL
case(op2)//功能码
5'b00000: begin
case(op3) //依据功能码判断是哪一个指令
`EXE_OR: begin //or R型指令 rs|rt -> rd
wreg_o <= `WriteEnable;
aluop_o <= `EXE_OR_OP;
alusel_o <= `EXE_RES_LOGIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_AND:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_AND_OP;//R rs&rt ->rd
alusel_o <= `EXE_RES_LOGIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_XOR:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_XOR_OP;// R rs^rt ->rd
alusel_o <= `EXE_RES_LOGIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_NOR:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_NOR_OP;// R rs~|rt ->rd
alusel_o <= `EXE_RES_LOGIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SLLV:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SLL_OP;
alusel_o <= `EXE_RES_SHIFT;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SRLV:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SRLV_OP;
alusel_o <= `EXE_RES_SHIFT;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SRAV:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SRAV_OP;
alusel_o <= `EXE_RES_SHIFT;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SYNC:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_NOP_OP;
alusel_o <= `EXE_RES_NOP;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MFHI:begin//将特殊寄存器hi的值赋给地址为rd的寄存器
wreg_o <= `WriteEnable;
aluop_o <= `EXE_MFHI_OP;
alusel_o <= `EXE_RES_MOVE;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MFLO:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_MFLO_OP;
alusel_o <= `EXE_RES_MOVE;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MTHI:begin//hi<-rs 写特殊寄存器
wreg_o <= `WriteEnable;
aluop_o <= `EXE_MTHI_OP;
alusel_o <= `EXE_RES_MOVE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MTLO:begin //lo<-rs 写特殊寄存器
wreg_o <= `WriteEnable;
aluop_o <= `EXE_MTLO_OP;
reg1_read_o <= 1'b1;//rs
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MOVN:begin//判断rt寄存器的值 如果不为0 将rs的值赋给rd 反之rd值不变
//wreg_o <= `WriteEnable;
aluop_o <= `EXE_MOVN_OP;
alusel_o <= `EXE_RES_MOVE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
//reg2_o的值就是地址为rt的寄存器的值
if(reg2_o != `ZeroWord)begin
wreg_o <= `WriteEnable;
end else begin
wreg_o <= `WriteDisable;
end
end
`EXE_MOVZ:begin //判断rt寄存器的值 如果是0 将rs的值赋给rd 反之rd值不变
aluop_o <= `EXE_MOVZ_OP;
alusel_o <= `EXE_RES_MOVE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
if(reg2_o == `ZeroWord)begin
wreg_o <= `WriteEnable;
end else begin
wreg_o <= `WriteDisable;
end
end
`EXE_SLT:begin//slt指令 rd<-(rs<rt)
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SLT_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SLTU:begin //sltu指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SLTU_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_ADD:begin//rd<-rs+rt
wreg_o <= `WriteEnable;
aluop_o <= `EXE_ADD_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_ADDU:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_ADDU_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SUB:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SUB_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SUBU:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SUBU_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MULT:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_MULT_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MULTU:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_MULTU_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_DIV:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_DIV_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_DIVU:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_DIVU_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_JR:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_JR_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;//rs寄存器需要被使用
reg2_read_o <= 1'b0;
wd_o <= inst_i[15:11];
link_addr_o <= pc_plus_8;//返回地址
branch_target_address_o <= reg1_o;//转移到的目标地址
branch_flag_o <= `Branch;//是否发生转移
next_inst_in_delayslot_o <= `InDelaySlot;//下一条指令不位于延迟槽
instvalid <= `InstValid;
end
`EXE_JALR:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_JALR_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
wd_o <= inst_i[15:11];
link_addr_o <= pc_plus_8;
branch_target_address_o <= reg1_o;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
instvalid <= `InstValid;
end
`EXE_TEQ:begin//teq
wreg_o <= `WriteDisable;
aluop_o <= `EXE_SYSCALL_OP;
alusel_o <= `EXE_RES_NOP;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_TGE:begin//tge
wreg_o <= `WriteDisable;
aluop_o <= `EXE_TGE_OP;
alusel_o <= `EXE_RES_NOP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_TGEU:begin//tgeu
wreg_o <= `WriteDisable;
aluop_o <= `EXE_TGEU_OP;
alusel_o <= `EXE_RES_NOP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_TLT:begin//tlt
wreg_o <= `WriteDisable;
aluop_o <= `EXE_TLT_OP;
alusel_o <= `EXE_RES_NOP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_TLTU:begin//tltu
wreg_o <= `WriteDisable;
aluop_o <= `EXE_TLTU_OP;
alusel_o <= `EXE_RES_NOP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_TNE:begin//tne
wreg_o <= `WriteDisable;
aluop_o <= `EXE_TNE_OP;
alusel_o <= `EXE_RES_NOP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SYSCALL:begin//syscall
wreg_o <= `WriteDisable;
aluop_o <= `EXE_SYSCALL_OP;
alusel_o <= `EXE_RES_NOP;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
excepttype_is_syscall <= `True_v;
end
default:begin
end
endcase
end
default:begin
//aluop_o <= `EXE_NOP_OP;
//alusel_o <= `EXE_RES_OP;
//wd_o <= `NOPRegAddr;
//wreg_o <= `WriteDisable;
//instvalid <= `InstValid;
//reg1_read_o <= `ReadDisable;
//reg2_read_o <= `ReadDisable;
//reg1_addr_o <= inst_i[25:21];
//reg2_addr_o <= inst_i[20:16];
end
endcase//op3
end // 5'b00000
`EXE_J:begin
wreg_o <= `WriteDisable;//译码阶段是否要写入目的寄存器
aluop_o <= `EXE_J_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
link_addr_o <= `ZeroWord;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
instvalid <= `InstValid;
branch_target_address_o <= {pc_plus_4[31:28],inst_i[25:0],2'b00};//转移目的的地址
end
`EXE_JAL:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_JAL_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
wd_o <= 5'b11111;//要写入的目的寄存器的地址 寄存器$1
link_addr_o <= pc_plus_8;//转移指令要保存的返回地址
branch_flag_o <= `Branch;//转移发生的标志
next_inst_in_delayslot_o <= `InDelaySlot;
instvalid <= `InstValid;
branch_target_address_o <= {pc_plus_4[31:28],inst_i[25:0],2'b00};
end
`EXE_BEQ:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_BEQ_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;//需要比较rs与rt
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
if(reg1_o == reg2_o)begin //如果rs的值reg1_o与rd的值reg2_o相等 发生转移
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_BGTZ:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_BGTZ_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;//rs
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
if((reg1_o[31] == 1'b0)&&(reg1_o != `ZeroWord))begin
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_BLEZ:begin
wreg_o <= `WriteDisable;//译码阶段是否要写入目的寄存器
aluop_o <= `EXE_BLEZ_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
if((reg1_o[31] == 1'b1)&&(reg1_o != `ZeroWord))begin
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_BNE:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_BNE_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
if(reg1_o != reg2_o)begin
branch_target_address_o <= pc_plus_4+imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_REGIMM_INST:begin
case(op4)
`EXE_BLTZAL:begin//bltzal
wreg_o <= `WriteEnable;
aluop_o <= `EXE_BGEZAL_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
link_addr_o <= pc_plus_8;
wd_o <= 5'b11111;
instvalid <= `InstValid;
if(reg1_o[31] == 1'b1) begin//reg1_o<0
branch_target_address_o <= pc_plus_4+imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_BLTZ:begin//bltz
wreg_o <= `WriteDisable;
aluop_o <= `EXE_BGEZAL_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
if(reg1_o[31] == 1'b1)begin
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_BGEZ:begin//bgez
wreg_o <= `WriteDisable;
aluop_o <= `EXE_BGEZ_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
if(reg1_o[31] == 1'b0)begin//rs的值大于等于0
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_BGEZAL:begin//bgezal
wreg_o <= `WriteEnable;
aluop_o <= `EXE_BGEZAL_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
link_addr_o <= pc_plus_8;
wd_o <= 5'b11111;
instvalid <= `InstValid;
if(reg1_o[31] == 1'b0)begin
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
//将地址为rs的通用寄存器的值与指令中16位立即数符号扩展至32位后的值比较,如果两者相等,那引发自陷异常
`EXE_TEQI:begin //teqi
wreg_o <= `WriteDisable;
aluop_o <= `EXE_TEQI_OP;
alusel_o <= `EXE_RES_NOP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}},inst_i[15:0]};
instvalid <= `InstValid;
end
`EXE_TGEI:begin //tegi
wreg_o <= `WriteDisable;
aluop_o <= `EXE_TGEI_OP;
alusel_o <= `EXE_RES_NOP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}},inst_i[15:0]};
instvalid <= `InstValid;
end
`EXE_TGEIU:begin //teqi
wreg_o <= `WriteDisable;
aluop_o <= `EXE_TGEIU_OP;
alusel_o <= `EXE_RES_NOP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}},inst_i[15:0]};
instvalid <= `InstValid;
end
`EXE_TLTI:begin //teqi
wreg_o <= `WriteDisable;
aluop_o <= `EXE_TLTI_OP;
alusel_o <= `EXE_RES_NOP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}},inst_i[15:0]};
instvalid <= `InstValid;
end
`EXE_TLTIU:begin //teqi
wreg_o <= `WriteDisable;
aluop_o <= `EXE_TLTIU_OP;
alusel_o <= `EXE_RES_NOP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}},inst_i[15:0]};
instvalid <= `InstValid;
end
`EXE_TNEI:begin //teqi
wreg_o <= `WriteDisable;
aluop_o <= `EXE_TNEI_OP;
alusel_o <= `EXE_RES_NOP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}},inst_i[15:0]};
instvalid <= `InstValid;
end
default:begin
end
endcase // op2
end
`EXE_ORI:begin //ORI指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_OR_OP;
alusel_o <= `EXE_RES_LOGIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {16'h0, inst_i[15:0]}; //立即数0扩展
wd_o <= inst_i[20:16]; // 读取rt地址
instvalid <= `InstValid;
end
`EXE_ANDI:begin //andi
wreg_o <= `WriteEnable;
aluop_o <= `EXE_AND_OP;
alusel_o <= `EXE_RES_LOGIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {16'h0,inst_i[15:0]};
wd_o <= inst_i[20:16];//rt
instvalid = `InstValid;
end
`EXE_XORI:begin//xori
wreg_o <= `WriteEnable;
aluop_o <= `EXE_XOR_OP;
alusel_o <= `EXE_RES_LOGIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {16'h0,inst_i[15:0]};
wd_o <= inst_i[20:16];
instvalid = `InstValid;
end
`EXE_LUI:begin//lui
wreg_o <= `WriteEnable;//注意书上的打印错误 无语了
aluop_o <= `EXE_OR_OP;
alusel_o <= `EXE_RES_LOGIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {inst_i[15:0],16'h0};
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
/*`EXE_PREF: begin//pref
wreg_o <= `WriteDisable;
aluop_o <= `EXE_NOP_OP;
alusel_o <= `EXE_RES_NOP;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end */
`EXE_SLTI:begin //slti rt <- (rs < (sign_extended)immediate)
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SLT_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}},inst_i[15:0]};
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_SLTIU:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SLTU_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}},inst_i[15:0]};
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_ADDI:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_ADDI_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}},inst_i[15:0]};
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_ADDIU:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_ADDIU_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}},inst_i[15:0]};
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_LB:begin//将加载结果写入目的寄存器
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LB_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;//计算加载目标地址需要使用地址为base的寄存器值
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16];//目的寄存器地址
instvalid <= `InstValid;
end
`EXE_LBU:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LBU_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_LH:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LH_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_LHU:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LHU_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_LW:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LW_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_LWL:begin//向左加载 加载结果需要写入目的寄存器 [20:16]
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LWL_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_LWR:begin//向右加载
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LWR_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_SB:begin //不需要写通用寄存器 计算存储目标地址需要使用的地址为base的寄存器的值
wreg_o <= `WriteDisable;
aluop_o <= `EXE_SB_OP;
reg1_read_o <= 1'b1; //[25:21] reg1_addr_o ======> base
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
`EXE_SH:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_SH_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
`EXE_SW:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_SW_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
`EXE_SWL:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_SWL_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
`EXE_SWR:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_SWR_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
`EXE_LL:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LL_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_SC:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SC_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_SPECIAL2_INST:begin//(op)
case(op3)
`EXE_CLZ:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_CLZ_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_CLO:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_CLO_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MUL:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_MUL_OP;
alusel_o <= `EXE_RES_MUL;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MADD:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_MADD_OP;
alusel_o <= `EXE_RES_MUL;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MADDU:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_MADDU_OP;
alusel_o <= `EXE_RES_MUL;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MSUB:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_MSUB_OP;
alusel_o <= `EXE_RES_MUL;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MSUBU:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_MSUBU_OP;
alusel_o <= `EXE_RES_MUL;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
default:begin
end
endcase //EXE_SPECIAL_INST2 case
end
default:begin
end
endcase //case op
if(inst_i == `EXE_ERET)begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_ERET_OP;
alusel_o <= `EXE_RES_NOP;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
excepttype_is_eret <= `True_v;
end
if(inst_i[31:21] == 11'b00000000000)begin //sll,srl,sra
if(op3 == `EXE_SLL) begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SLL_OP;
alusel_o <= `EXE_RES_SHIFT;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b1;
imm[4:0] <= inst_i[10:6];
wd_o <= inst_i[15:11];
instvalid <= `InstValid;
end else if(op3 == `EXE_SRL)begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SRL_OP;
alusel_o <= `EXE_RES_SHIFT;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b1;
imm[4:0] <= inst_i[10:6];
wd_o <= inst_i[15:11];
instvalid <= `InstValid;
end else if(op3 == `EXE_SRA) begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SRA_OP;
alusel_o <= `EXE_RES_SHIFT;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b1;
imm[4:0] <= inst_i[10:6];
wd_o <= inst_i[15:11];
instvalid <= `InstValid;
end
end
//endcase
//end
// end else begin //if
if(inst_i[31:21]==11'b010_0000_0000&&inst_i[10:0]==11'b000_0000_0000)//mfc0指令
begin
aluop_o <= `EXE_MFC0_OP;
alusel_o <= `EXE_RES_MOVE;//一种移动运算
wd_o <= inst_i[20:16];//rt 要写的目的寄存器是指令中rt的值
wreg_o <= `WriteEnable;//需要读取CP0中的寄存器的值写入目的寄存器,要写通用寄存器
instvalid <= `InstValid;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
end else if(inst_i[31:21]==11'b010_0000_0100&&inst_i[10:0]==11'b00000000000)//mtc0指令
begin
aluop_o <= `EXE_MTC0_OP;
alusel_o <= `EXE_RES_MOVE;
wreg_o <= `WriteDisable;//不需要写通用寄存器
instvalid <= `InstValid;
reg1_read_o <= 1'b1;//需要读取通用寄存器 通过Regfile1端口读取数据
reg1_addr_o <= inst_i[20:16];//读取地址是指令中16-20位 是rt的值
reg2_read_o <= 1'b0;
end
end //if
end //always
/* 数据前推
给reg1_o赋值过程增加了两种情况
1:如果Regfile模块读端口1要读取的寄存器就是执行阶段要写的目的寄存器,那么直接把执行阶段的结果ex_wdata_i作为reg1_o的值
2:如果Regfile模块读端口1要读取的寄存器就是访存阶段要写的目的寄存器,那么直接把访存阶段的结果mem_wdata_i作为reg1_o的值*/
always @ (*) begin
if(rst == `RstEnable) begin
reg1_o <= `ZeroWord;
end else if((reg1_read_o == 1'b1) && (ex_wreg_i == 1'b1)
&& (ex_wd_i == reg1_addr_o)) begin
reg1_o <= ex_wdata_i;
end else if((reg1_read_o == 1'b1) && (mem_wreg_i == 1'b1)
&& (mem_wd_i == reg1_addr_o)) begin
reg1_o <= mem_wdata_i;
end else if(reg1_read_o == 1'b1) begin
reg1_o <= reg1_data_i;
end else if(reg1_read_o == 1'b0) begin
reg1_o <= imm;
end else begin
reg1_o <= `ZeroWord;
end
end
always @ (*) begin
if(rst == `RstEnable) begin
reg2_o <= `ZeroWord;
end else if((reg2_read_o == 1'b1) && (ex_wreg_i == 1'b1)
&& (ex_wd_i == reg2_addr_o)) begin
reg2_o <= ex_wdata_i;
end else if((reg2_read_o == 1'b1) && (mem_wreg_i == 1'b1)
&& (mem_wd_i == reg2_addr_o)) begin
reg2_o <= mem_wdata_i;
end else if(reg2_read_o == 1'b1) begin
reg2_o <= reg2_data_i;
end else if(reg2_read_o == 1'b0) begin
reg2_o <= imm;
end else begin
reg2_o <= `ZeroWord;
end
end
//输出变量is_in_delayslot_o表示当前译码阶段指令是否是延迟槽指令
always @ (*)begin
if(rst == `RstEnable)begin
is_in_delayslot_o <= `NotInDelaySlot;
end else begin
//直接等于is_in_delayslot_i
is_in_delayslot_o <= is_in_delayslot_i;
end
end
endmodule
id_ex.v
`include "define.v"
//在时钟周期的上升沿,将译码阶段的结果传递到执行阶段*/
module id_ex(
input wire clk,
input wire rst,
input wire flush,
//最后一章,从译码阶段传递过来的信号
input wire[`RegBus] id_current_inst_address,
input wire[31:0] id_excepttype,
//从译码阶段传递的信息
input wire[`AluOpBus] id_aluop,
input wire[`AluSelBus] id_alusel,
input wire[`RegBus] id_reg1,
input wire[`RegBus] id_reg2,
input wire[`RegAddrBus] id_wd,
input wire id_wreg,
//来自控制模块的信息
input wire[5:0] stall ,
input wire[`RegBus] id_link_address,
input wire id_is_in_delayslot,
input wire next_inst_in_delayslot_i,
input wire[`RegBus] id_inst, //来自id模块的信号 当前处于译码阶段的指令
//传递到执行阶段的信息
output reg[`AluOpBus] ex_aluop,
output reg[`AluSelBus] ex_alusel,
output reg[`RegBus] ex_reg1,
output reg[`RegBus] ex_reg2,
output reg[`RegAddrBus] ex_wd,
output reg ex_wreg,
output reg[`RegBus] ex_link_address,
output reg ex_is_in_delayslot,
output reg is_in_delayslot_o,
output reg[`RegBus] ex_inst ,//传递到ex模块 当前处于执行阶段的指令
//最后一章 新增接口 传递到执行阶段的信号
output reg[`RegBus] ex_current_inst_address,
output reg[31:0] ex_excepttype
);
always @ (posedge clk) begin
if (rst == `RstEnable) begin
ex_aluop <= `EXE_NOP_OP;
ex_alusel <= `EXE_RES_NOP;
ex_reg1 <= `ZeroWord;
ex_reg2 <= `ZeroWord;
ex_wd <= `NOPRegAddr;
ex_wreg <= `WriteDisable;
ex_link_address <= `ZeroWord;
ex_is_in_delayslot <= `NotInDelaySlot;
ex_inst <= `ZeroWord;
ex_excepttype <= `ZeroWord;
ex_current_inst_address <= `ZeroWord;
end else if(flush == 1'b1) begin//清除流水线
ex_aluop <= `EXE_NOP_OP;
ex_alusel <= `EXE_RES_NOP;
ex_reg1 <= `ZeroWord;
ex_reg2 <= `ZeroWord;
ex_wd <= `NOPRegAddr;
ex_wreg <= `WriteDisable;
ex_excepttype <= `ZeroWord;
ex_link_address <= `ZeroWord;
ex_inst <= `ZeroWord;
ex_is_in_delayslot <= `NotInDelaySlot;
is_in_delayslot_o <= `NotInDelaySlot;
ex_current_inst_address <= `ZeroWord;
end else if(stall[2] == `Stop && stall[3] == `NoStop)begin//执行停止访存继续
ex_aluop <= `EXE_NOP_OP;
ex_alusel <= `EXE_RES_NOP;
ex_reg1 <= `ZeroWord;
ex_reg2 <= `ZeroWord;
ex_wd <= `NOPRegAddr;
ex_wreg <= `WriteDisable;
ex_link_address <= `ZeroWord;
ex_is_in_delayslot <= `NotInDelaySlot;
ex_inst <= `ZeroWord;
ex_excepttype <= `ZeroWord;
ex_current_inst_address <= `ZeroWord;
end else if(stall[2] == `NoStop)begin//执行继续
ex_aluop <= id_aluop;
ex_alusel <= id_alusel;
ex_reg1 <= id_reg1;
ex_reg2 <= id_reg2;
ex_wd <= id_wd;
ex_wreg <= id_wreg;
ex_link_address <= id_link_address;
ex_is_in_delayslot <= id_is_in_delayslot;
ex_inst <= id_inst;
is_in_delayslot_o <= next_inst_in_delayslot_i;
ex_excepttype <= id_excepttype;
ex_current_inst_address <= id_current_inst_address;
/*end else begin
ex_aluop <= id_aluop;
ex_alusel <= id_alusel;
ex_reg1 <= id_reg1;
ex_reg2 <= id_reg2;
ex_wd <= id_wd;
ex_wreg <= id_wreg;
end*/
end
end
endmodule
ex.v
`include "define.v"
//ex.v 执行模块
module ex(
//译码阶段送到执行阶段的信息
input wire[`AluOpBus] aluop_i,
input wire[`AluSelBus] alusel_i,
input wire[`RegBus] reg1_i,
input wire[`RegBus] reg2_i,
input wire[`RegAddrBus] wd_i,
input wire wreg_i,
input wire rst,
//HILO模块给出HI,LO寄存器的值
input wire[`RegBus] hi_i,
input wire[`RegBus] lo_i,
//回写阶段的指令是否要写HI,LO,用于检测HI,LO寄存器带来的数据相关的问题
input wire[`RegBus] wb_hi_i,
input wire[`RegBus] wb_lo_i,
input wire wb_whilo_i,
//访存阶段的指令是否要写HI,LO,用于检测HI,LO寄存器带来的数据相关的问题
input wire[`RegBus] mem_hi_i,
input wire[`RegBus] mem_lo_i,
input wire mem_whilo_i,
//增加的输入端口
input wire[`DoubleRegBus] hilo_temp_i,//保存乘法结果
input wire[1:0] cnt_i,//处于执行阶段的第几个周期
//新增来自除法模块的输入
input wire[`DoubleRegBus] div_result_i,
input wire div_ready_i,
//处于执行阶段的转移指令要保存的返回地址
input wire[`RegBus] link_address_i,
//当前执行阶段指令是否处于延迟槽
input wire is_in_delayslot_i,
//新增输入端口inst_i,其值就是当前处于执行阶段的指令
input wire[`RegBus] inst_i,//当前处于执行阶段的指令
//访存阶段的指令是否要写CP0中的寄存器 用来检测数据相关
input wire mem_cp0_reg_we,
input wire[4:0] mem_cp0_reg_write_addr,
input wire[`RegBus] mem_cp0_reg_data,
//回写阶段的指令是否要写CP0中的寄存器 也是用来检测数据相关
input wire wb_cp0_reg_we,
input wire[4:0] wb_cp0_reg_write_addr,
input wire[`RegBus] wb_cp0_reg_data,
//与CP0直接相连 用于读取其中指定寄存器的值
input wire[`RegBus] cp0_reg_data_i,
//最后一章新增的输入接口
input wire[31:0] excepttype_i,
input wire[`RegBus] current_inst_address_i,
output reg[4:0] cp0_reg_read_addr_o,
//向流水线下一级传递 用于写CP0的指定寄存器的值
output reg cp0_reg_we_o,
output reg[4:0] cp0_reg_write_addr_o,
output reg[`RegBus] cp0_reg_data_o,
//处于执行阶段指令对LO,HI寄存器的写操作请求
output reg[`RegBus] hi_o,
output reg[`RegBus] lo_o,
output reg whilo_o,
//执行的结果
output reg[`RegAddrBus] wd_o,
output reg wreg_o,
output reg[`RegBus] wdata_o,
output reg stallreq,
output reg[`DoubleRegBus] hilo_temp_o,
output reg[1:0] cnt_o,
//新增到除法模块的输出
output reg[`RegBus] div_opdata1_o,
output reg[`RegBus] div_opdata2_o,
output reg div_start_o,
output reg signed_div_o,
//output reg is_in_delayslot_o,
//下面新增的几个输出接口是为 加载、 存储指令准备的
output wire[`AluOpBus] aluop_o, //执行阶段要进行运算的子类型
output wire[`RegBus] mem_addr_o,//加载存储指令对应的存储器地址
output wire[`RegBus] reg2_o,//存储指令要存储的数据,或者lwl,lwr指令要加载到的目的寄存器的地址
//最后一章新增的输出端口
output wire[31:0] excepttype_o,
output wire[`RegBus] current_inst_address_o,
output wire is_in_delayslot_o
);
//保存逻辑运算的结果
reg[`RegBus] logicout;
//保存移位运算的结果
reg[`RegBus] shiftres;
//保存移动操作的结果
reg[`RegBus] moveres;
//保存HI,LO寄存器的最新值
reg[`RegBus] HI;
reg[`RegBus] LO;
//是否由于除法运算导致流水线暂停
reg stallreq_for_div;
/***********************第七章新定义一些变量***********************/
wire ov_sum;//保存溢出情况
wire reg1_eq_reg2;//第一个操作数是否等于第二个操作数
wire reg1_lt_reg2;//第一个操作数是否小于第二个操作数
reg[`RegBus] arithmeticres;//保存算术运算的结果
reg[`DoubleRegBus] mulres;//保存乘法运算的结果
wire[`RegBus] reg2_i_mux;//保存输入的第二个操作数reg2_i的补码
wire[`RegBus] reg1_i_not;//保存输入的第一个操作数reg1_i取反后的值
wire[`RegBus] result_sum;//保存加法结果
wire[`RegBus] opdata1_mult;//乘法操作中的被乘数
wire[`RegBus] opdata2_mult;//乘法操作中的乘数
wire[`DoubleRegBus] hilo_temp;//临时保存乘法结果,宽度为64位
reg [`DoubleRegBus] hilo_temp1;
reg stallreq_for_madd_msub;
reg trapassert;//表示是否有自陷异常
reg ovassert;//表示是否有溢出异常
//aluop_o会传递到访存阶段,届时将利用其确定加载、存储类型
assign aluop_o = aluop_i;
//mem_addr_o会传递到访存阶段,是加载、存储指令对应的存储器地址,此处reg1_i就是加载、存储指令中地址为base的通用寄存器的值
//通过计算mem_addr_o,了解为何要在译码阶段ID模块新增输出接口inst_o
assign mem_addr_o = reg1_i + {{16{inst_i[15]}},inst_i[15:0]};
//reg2_i是存储指令要存储的数据,或者是lwl,lwr指令要加载到的目的寄存器的原始值,该值通过reg2_o接口传递到访存阶段
assign reg2_o = reg2_i;
assign excepttype_o={excepttype_i[31:12],ovassert,trapassert,excepttype_i[9:8],8'h00};
//is_in_delayslot_i表示当前指令是否在延迟槽中
assign is_in_delayslot_o = is_in_delayslot_i;
//当前 处于执行指令的地址
assign current_inst_address_o = current_inst_address_i;
/*******************************************************************
** 第一段:依据aluop_i指示的运算子类型进行运算 **
*******************************************************************/
always @ (*)
begin//1
if(rst == `RstEnable)
begin//2
logicout <= `ZeroWord;
end//2
else
begin//3
case(aluop_i)//4
`EXE_OR_OP:begin//5 逻辑或
logicout <= reg1_i|reg2_i;
end
`EXE_AND_OP: begin //逻辑与
logicout <= reg1_i®2_i;
end
`EXE_NOR_OP:begin //逻辑或非
logicout <= ~(reg1_i|reg2_i);
end
`EXE_XOR_OP:begin //逻辑异或
logicout <= reg1_i^reg2_i;
end
default:begin//6
logicout <= `ZeroWord;
end//6
endcase//4
end//3
end//1
always @ (*) begin
if(rst == `RstEnable)begin
shiftres <= `ZeroWord;
end else begin
case(aluop_i)
`EXE_SLL_OP:begin //逻辑左移
shiftres <= reg2_i << reg1_i[4:0];
end
`EXE_SRL_OP:begin //逻辑右移
shiftres <= reg2_i >> reg1_i[4:0];
end
`EXE_SRA_OP:begin//算术右移1
shiftres <= ({32{reg2_i[31]}}<<(6'd32-{1'b0,reg1_i[4:0]})) |/*rt向右移sa位*/ reg2_i>>reg1_i[4:0];
end
default:begin
shiftres <= `ZeroWord;
end
endcase
end
end
/******************************************************************
****第三段:得到最新的HI,LO寄存器的值,此处要解决数据相关的问题****
******************************************************************/
always @ (*)begin
if(rst == `RstEnable) begin
{HI,LO} <= {`ZeroWord,`ZeroWord};
end else if(mem_whilo_i == `WriteEnable)begin
{HI,LO} <= {mem_hi_i,mem_lo_i};//访存阶段的指令要写HI,LO寄存器
end else if(wb_whilo_i == `WriteEnable)begin
{HI,LO} <= {wb_hi_i,wb_lo_i};//回写阶段的指令要写HI,LO寄存器
end
end
/*******************************************************************
******************第四段:MFHI,MFLO,MOVN,MOVZ指令********************
*******************************************************************/
always @ (*) begin
if(rst == `RstEnable) begin
moveres <= `ZeroWord;
end else begin
moveres <= `ZeroWord;
case(aluop_i)
`EXE_MFHI_OP:begin
//rd<-hi
moveres <= HI;//HI的值是移动操作的结果
end
`EXE_MFLO_OP:begin
//rd<-lo
moveres <= LO;
end
`EXE_MOVN_OP:begin
//rd<-rs
moveres <= reg1_i;
end
`EXE_MOVZ_OP:begin
//rd<-rs
moveres <= reg1_i;
end
`EXE_MFC0_OP:begin
//要从CP0中读取寄存器的地址
cp0_reg_read_addr_o <= inst_i[15:11];//通过cp0_reg_read_addr_o向CP0模块送出要读取的CP0中寄存器地址
//读取到的CP0中指定寄存器的值
moveres <= cp0_reg_data_i;//通过cp0_reg_data_i接口送入ex 赋值给变量moveres
//判断是否存在数据相关 此时moveres并不一定是CP0中寄存器的最新值
if(mem_cp0_reg_we == `WriteEnable && mem_cp0_reg_write_addr == inst_i[15:11])
begin
moveres <= mem_cp0_reg_data;//与访存阶段存在数据相关
end else if(wb_cp0_reg_we == `WriteEnable && wb_cp0_reg_write_addr == inst_i[15:11])
begin
moveres <= wb_cp0_reg_data;//与回写阶段存在数据相关
end
end
default:begin
end
endcase
end
end
/***************************************************************
*******如果是MTHI,MTLO指令,需要给出whilo_o,hi_o,lo_o的值*******
***************************************************************/
always @ (*)begin
if(rst == `RstEnable) begin
whilo_o <= `WriteDisable;
hi_o <= `ZeroWord;
lo_o <= `ZeroWord;
end else if(aluop_i == `EXE_MTHI_OP)begin
whilo_o <= `WriteEnable;
hi_o <= reg1_i;
lo_o <= LO;//写HI寄存器所以LO保持不变
end else if(aluop_i == `EXE_MTLO_OP)begin
whilo_o <= `WriteEnable;
hi_o <= HI;
lo_o <= reg1_i;
end else begin
whilo_o <= `WriteDisable;
hi_o <= `ZeroWord;
lo_o <= `ZeroWord;
end
end
//end
//endmodule
/*************************************************************
******************第五段:计算以下5个变量的值******************
*************************************************************/
/*(1)如果是减法或者是有符号比较运算,那么reg2_i_mux等于第二个操作数reg2_i的补码,
否则reg2_i_mux就等于第二个操作数reg2_i*/
assign reg2_i_mux = ((aluop_i == `EXE_SUB_OP)||(aluop_i == `EXE_SUBU_OP)||(aluop_i == `EXE_SLT_OP)||
(aluop_i == `EXE_TLT_OP)||(aluop_i == `EXE_TLTI_OP)||(aluop_i == `EXE_TGE_OP)||(aluop_i == `EXE_TGE_OP)||(aluop_i == `EXE_TGEI_OP))?(~reg2_i)+1:reg2_i;
/*(2)分三种情况:
A:如果是加法运算,此时reg2_i_mux就是第二个操作数reg2_i,所以result_sum就是加法运算结果
B:如果是减法运算,此时reg2_i_mux就是第二个操作数reg2_i的补码,所以result_sum就是减法运算的结果
C:如果是有符号的比较运算,此时reg2_i_mux也就是第二个操作数reg2_i的补码,所以result_sum也就是减法
运算的结果,可以通过判断减法的结果是否小于0,进而判断第一个操作数reg1_i是否小于第二个操作数reg2_i*/
assign result_sum = reg1_i + reg2_i_mux;
/*(3)计算是否溢出,加法指令add和addi,减法指令sub执行的时候,需要判断是否溢出,满足以下两种情况之一的时候
A:reg1_i为正数,reg2_i_mux为正数,但两者之和为负数
B:reg1_i为负数,reg2_i_mux为负数,但是两者之和为正数*/
//这个我不理解 艹 2022.3.10理解了
assign ov_sum = ((!reg1_i[31] && !reg2_i_mux[31]) && result_sum[31])||((reg1_i[31] && reg2_i_mux[31])&&(!result_sum[31]));
/*(4)计算操作数1是否小于操作数2,分两种情况:
A:aluop_i为EXE_SLT_OP表示有符号比较运算
1.reg1_i为负数、reg2_i为正数,显然reg1_i小于reg2_i
2.reg1_i为正数、reg2_i为正数,并且reg1_i减去reg2_i的值小于0(result_sum为负)此时reg1_i小于reg2_i
3.reg1_i为负数、reg2_i为负数,并且reg1_i减去reg2_i的值小于0(result_sum为负)此时reg1_i小于reg2_i
B:无符号数比较运算的时候,直接使用比较运算符比较reg1_i和reg2_i*/
assign reg1_lt_reg2 = ((aluop_i == `EXE_SLT_OP)
||(aluop_i == `EXE_TLT_OP)||
(aluop_i == `EXE_TLTI_OP)||
(aluop_i == `EXE_TGE_OP)||
(aluop_i == `EXE_TGEI_OP))?((reg1_i[31]&&!reg2_i[31])||(!reg1_i[31]&&!reg2_i[31]&&result_sum[31])||(reg1_i[31]&®2_i[31]&&result_sum[31])):(reg1_i<reg2_i);
//(5)对操作数1逐位取反 赋值给reg1_i_not
assign reg1_i_not = ~reg1_i;
/*****************************************************************
*****第六段:依据不同的算术运算类型,给arithmeticres变量赋值*******
*****************************************************************/
always @ (*) begin
if(rst == `RstEnable)begin
arithmeticres <= `ZeroWord;
end else begin
case(aluop_i) //选择运算类型
`EXE_SLT_OP,`EXE_SLTU_OP:begin
arithmeticres <= reg1_lt_reg2;//比较运算
end
`EXE_ADD_OP,`EXE_ADDU_OP,`EXE_ADDI_OP,`EXE_ADDIU_OP:begin
arithmeticres <= result_sum;//加法运算
end
`EXE_SUB_OP,`EXE_SUBU_OP:begin
arithmeticres <= result_sum;//减法运算
end
`EXE_CLZ_OP:begin //计数运算clz
arithmeticres <= reg1_i[31]?0:reg1_i[30]?1:
reg1_i[29]?2:reg1_i[28]?3:
reg1_i[27]?4:reg1_i[26]?5:
reg1_i[25]?6:reg1_i[24]?7:
reg1_i[23]?8:reg1_i[22]?9:
reg1_i[21]?10:reg1_i[20]?11:
reg1_i[19]?12:reg1_i[18]?13:
reg1_i[17]?14:reg1_i[16]?15:
reg1_i[15]?16:reg1_i[14]?17:
reg1_i[13]?18:reg1_i[12]?19:
reg1_i[11]?20:reg1_i[10]?21:
reg1_i[9]?22:reg1_i[8]?23:
reg1_i[7]?24:reg1_i[6]?25:
reg1_i[5]?26:reg1_i[4]?27:
reg1_i[3]?28:reg1_i[2]?29:
reg1_i[1]?20:reg1_i[0]?31:32;
end
`EXE_CLO_OP:begin //计数运算clo
arithmeticres <= (reg1_i_not[31]?0:
reg1_i_not[30]?1:
reg1_i_not[29]?2:
reg1_i_not[28]?3:
reg1_i_not[27]?4:
reg1_i_not[26]?5:
reg1_i_not[25]?6:
reg1_i_not[24]?7:
reg1_i_not[23]?8:
reg1_i_not[22]?9:
reg1_i_not[21]?10:
reg1_i_not[20]?11:
reg1_i_not[19]?12:
reg1_i_not[18]?13:
reg1_i_not[17]?14:
reg1_i_not[16]?15:
reg1_i_not[15]?16:
reg1_i_not[14]?17:
reg1_i_not[13]?18:
reg1_i_not[12]?19:
reg1_i_not[11]?20:
reg1_i_not[10]?21:
reg1_i_not[9]?22:
reg1_i_not[8]?23:
reg1_i_not[7]?24:
reg1_i_not[6]?25:
reg1_i_not[5]?26:
reg1_i_not[4]?27:
reg1_i_not[3]?28:
reg1_i_not[2]?29:
reg1_i_not[1]?30:
reg1_i_not[0]?31:32);
end
default:begin
arithmeticres <= `ZeroWord;
end
endcase
end
end
/*****************************************************************
************************第七段:进行乘法运算***********************
*****************************************************************/
/*(1)取得乘法运算的被乘数 指令 madd,msub都是有符号乘法,如果第一个操作数reg1_i是负数
那么取reg1_i的补码为被乘数,反之直接使用reg1_i作为被乘数 如果是有符号乘法且被乘数是负数 那么取补码*/
assign opdata1_mult = (((aluop_i == `EXE_MUL_OP)||(aluop_i == `EXE_MULT_OP)||(aluop_i == `EXE_MADD_OP)||(aluop_i == `EXE_MSUB_OP))&&(reg1_i[31] == 1'b1)) ? (~reg1_i+1):reg1_i;
//(2)取得乘法运算的乘数 如果是有符号乘法且乘数是负数 那么取补码
assign opdata2_mult = (((aluop_i == `EXE_MUL_OP)||(aluop_i == `EXE_MULT_OP)||(aluop_i == `EXE_MADD_OP)||(aluop_i == `EXE_MSUB_OP))&&(reg2_i[31] == 1'b1)) ? (~reg2_i+1):reg2_i;
//(3)得到临时乘法结果 保存在变量hilo_temp中
assign hilo_temp = opdata1_mult * opdata2_mult;
/*(4)对临时乘法结果进行修正 最终的乘法结果保存在变量mulres中 主要有以下两点
A:如果是有符号乘法指令mult、mul,那么需要修正临时乘法结果,如下:
A1:如果被乘数与乘数两者为一正一负,那么需要对临时乘法结果hilo_temp求补码,作为最终乘法结果,赋给mulres
A2:如果被乘数与乘数同号,那么hilo_temp的值就作为最终的乘法结果,赋给变量mulres
B:如果是无符号乘法指令multu,那么hilo_temp的值就作为最终的乘法结果,赋给变量mulres
*/
always @ (*) begin//1
if(rst == `RstEnable) begin//2
mulres <= {`ZeroWord,`ZeroWord};
end/*2*/ else if((aluop_i == `EXE_MULT_OP)||(aluop_i == `EXE_MUL_OP)||(aluop_i == `EXE_MADD_OP)||(aluop_i == `EXE_MSUB_OP))begin//3
if(reg1_i[31]^reg2_i[31] == 1'b1)begin//4 被乘数和乘数一正一负
mulres <= ~hilo_temp+1;
end/*4*/ else begin//5 被乘数和乘数同号
mulres <= hilo_temp;
end//5
end/*3*/ else begin//6 无符号乘法
mulres <= hilo_temp;
end//6
end//1
/*****************************************************************
****************第八段:确定要写入目的寄存器的数据*****************
*****************************************************************/
always @ (*)begin
wd_o <= wd_i;
//如果是add,addi,sub,subi指令,且发生溢出,那么设置wreg_o为WriteEnable 表示不写目的寄存器
if(((aluop_i == `EXE_ADD_OP)||(aluop_i == `EXE_ADDI_OP)||(aluop_i == `EXE_SUB_OP))&&(ov_sum == 1'b1))begin
wreg_o <= `WriteDisable;
ovassert <= 1'b1;
end else begin
wreg_o <= wreg_i;
ovassert <= 1'b0;
end
case(alusel_i)
`EXE_RES_LOGIC:begin
wdata_o <= logicout;
end
`EXE_RES_SHIFT:begin
wdata_o <= shiftres;
end
`EXE_RES_MOVE:begin
wdata_o <= moveres;
end
`EXE_RES_ARITHMETIC:begin//除乘法外的简单算术操作指令
wdata_o <= arithmeticres;
end
`EXE_RES_MUL:begin//乘法指令mul
wdata_o <= mulres[31:0];
end
`EXE_RES_JUMP_BRANCH:begin
wdata_o <= link_address_i;
end
default:begin
wdata_o <= `ZeroWord;
end
endcase
end//always
/****************************************************************
********************第十段:乘累加、乘累减************************
****************************************************************/
//MADD MADDU MSUB MSUBU指令
always @ (*) begin
if(rst == `RstEnable) begin
hilo_temp_o <= {`ZeroWord,`ZeroWord};
cnt_o <= 2'b00;
stallreq_for_madd_msub <= `NoStop;
end else begin
case(aluop_i)
`EXE_MADD_OP,`EXE_MADDU_OP:begin
if(cnt_i == 2'b00) begin //执行第一个时钟周期
hilo_temp_o <= mulres;//此时将乘法结果mulres通过接口hilo_temp_o输出到EX/MEM模块 以便在下一个时钟周期使用
cnt_o <= 2'b01;
hilo_temp1 <= {`ZeroWord,`ZeroWord};
stallreq_for_madd_msub <= `Stop;//乘累加指令请求流水线暂停
end else if(cnt_i == 2'b01) begin//执行第二个时钟周期
hilo_temp_o <= {`ZeroWord,`ZeroWord};
cnt_o <= 2'b10;
hilo_temp1 <= hilo_temp_i+{HI,LO}; //hilo_temp_i是上一个时钟周期得到的乘法结果
stallreq_for_madd_msub <= `NoStop;//乘累加指令执行结束 不再请求流水线暂停
end
end
`EXE_MSUB_OP,`EXE_MSUBU_OP:begin
if(cnt_i == 2'b00) begin
hilo_temp_o <= ~mulres+1;
cnt_o <= 2'b01;
stallreq_for_madd_msub <= `Stop;
end else if(cnt_i == 2'b01) begin
hilo_temp_o <= {`ZeroWord,`ZeroWord};
cnt_o <= 2'b10;
hilo_temp1 <= hilo_temp_i +{HI,LO};
stallreq_for_madd_msub <= `NoStop;
end
end
default:begin
hilo_temp_o <= {`ZeroWord,`ZeroWord};
cnt_o <= 2'b00;
stallreq_for_madd_msub <= `NoStop;
end
endcase
end
end
/****************************************************************
******第十二段:输出DIV模块控制信息,获取DIV模块给出的结果*********
****************************************************************/
always @ (*) begin
if(rst == `RstEnable)begin
stallreq_for_div <= `NoStop;
div_opdata1_o <= `ZeroWord;
div_opdata2_o <= `ZeroWord;
div_start_o <= `DivStop;
signed_div_o <= 1'b0;
end else begin
stallreq_for_div <= `NoStop;
div_opdata1_o <= `ZeroWord;
div_opdata2_o <= `ZeroWord;
div_start_o <= `DivStop;
signed_div_o <= 1'b0;
case(aluop_i)
`EXE_DIV_OP:begin
if(div_ready_i == `DivResultNotReady) begin
div_opdata1_o <= reg1_i;//被除数
div_opdata2_o <= reg2_i;//除数
div_start_o <= `DivStart;//开始除法运算
signed_div_o <= 1'b1;//有符号除法
stallreq_for_div <= `Stop;//请求流水线暂停
end else if(div_ready_i == `DivResultReady) begin
div_opdata1_o <= reg1_i;
div_opdata2_o <= reg2_i;
div_start_o <= `DivStop;//结束除法运算
signed_div_o <= 1'b1;
stallreq_for_div <= `NoStop;//不再请求流水线暂停
end else begin
div_opdata1_o <= `ZeroWord;
div_opdata2_o <= `ZeroWord;
div_start_o <= `DivStop;
signed_div_o <= 1'b0;
stallreq_for_div <= `NoStop;
end
end
`EXE_DIVU_OP:begin
if(div_ready_i == `DivResultNotReady) begin
div_opdata1_o <= reg1_i;
div_opdata2_o <= reg2_i;
div_start_o <= `DivStart;
signed_div_o <= 1'b0;//无符号除法
stallreq_for_div <= `Stop;
end else if(div_ready_i == `DivResultReady) begin
div_opdata1_o <= reg1_i;
div_opdata2_o <= reg2_i;
div_start_o <= `DivStop;
signed_div_o <= 1'b0;
stallreq_for_div <= `NoStop;
end else begin
div_opdata1_o <= `ZeroWord;
div_opdata2_o <= `ZeroWord;
div_start_o <= `DivStop;
signed_div_o <= 1'b0;
stallreq_for_div <= `NoStop;
end
end
default:begin
end
endcase
end
end
/****************************************************************
*********************第十一段:暂停流水线*************************
****************************************************************/
//目前只有乘累加和乘累减指令会导致流水线暂停,所以stallreq=stallreq_for_madd_msub
always @ (*) begin
stallreq = stallreq_for_madd_msub || stallreq_for_div;
end
/****************************************************************
****************第九段:确定(修改)对HI,LO寄存器的操作信息*********
****************************************************************/
always @ (*)begin
if(rst == `RstEnable) begin
whilo_o <= `WriteDisable;
hi_o <= `ZeroWord;
lo_o <= `ZeroWord;
end else if((aluop_i == `EXE_MULT_OP)||(aluop_i == `EXE_MULTU_OP))begin //mult,multu指令
whilo_o <= `WriteEnable;
hi_o <= mulres[63:32];
lo_o <= mulres[31:0];
end else if(aluop_i == `EXE_MTHI_OP)begin
whilo_o <= `WriteEnable;
hi_o <= reg1_i;
lo_o <= LO;//写HI寄存器所以LO保持不变
end else if(aluop_i == `EXE_MTLO_OP)begin
whilo_o <= `WriteEnable;
hi_o <= HI;
lo_o <= reg1_i;
end else if((aluop_i == `EXE_MSUB_OP)||(aluop_i == `EXE_MSUBU_OP))begin
whilo_o <= `WriteEnable;
hi_o <= hilo_temp1[63:32];
lo_o <= hilo_temp1[31:0];
end else if((aluop_i == `EXE_MADD_OP)||(aluop_i == `EXE_MADDU_OP))begin
whilo_o <= `WriteEnable;
hi_o <= hilo_temp1[63:32];
lo_o <= hilo_temp1[31:0];
end else if((aluop_i == `EXE_DIV_OP)||(aluop_i == `EXE_DIVU_OP))begin
whilo_o <= `WriteEnable;
hi_o <= div_result_i[63:32];
lo_o <= div_result_i[31:0];
end else begin
whilo_o <= `WriteDisable;
hi_o <= `ZeroWord;
lo_o <= `ZeroWord;
end
end
/*********************************************************************
******************第十三段:给出mtc0指令执行的结果*********************
*********************************************************************/
always @ (*) begin
if(rst == `RstEnable)begin
cp0_reg_write_addr_o <= 5'b00000;
cp0_reg_we_o <= `WriteDisable;
cp0_reg_data_o <= `ZeroWord;
end else if(aluop_i == `EXE_MTC0_OP)begin//如果是mtc0指令
cp0_reg_write_addr_o <= inst_i[15:11];//写入地址为指令中第11-15为的值
cp0_reg_we_o <= `WriteEnable;//设置写操作信号cp0_reg_we_o为可写
cp0_reg_data_o <= reg1_i;//写入的值就是译码阶段传递来的reg1_i的值 正是rt通用寄存器的值
end else begin
cp0_reg_write_addr_o <= 5'b00000;
cp0_reg_we_o <= `WriteDisable;
cp0_reg_data_o <= `ZeroWord;
end
end
/************************************************************************
******************第十四段:判断是否发生自陷异常**************************
************************************************************************/
always @ (*) begin
if(rst == `RstEnable)begin
trapassert <= `TrapNotAssert;
end else begin
trapassert <= `TrapNotAssert;//默认没有自陷异常
case(aluop_i)
//teg teqi指令
`EXE_TEQ_OP,`EXE_TEQI_OP:begin
if(reg1_i == reg2_i)begin
trapassert <= `TrapAssert;
end
end
//tge tgei tgeiu tgeu指令
`EXE_TGE_OP,`EXE_TGEI_OP,`EXE_TGEIU_OP,`EXE_TGEU_OP:
begin
if(~reg1_lt_reg2)begin
trapassert <= `TrapAssert;
end
end
//tlt tlti tltiu tltu指令
`EXE_TLT_OP,`EXE_TLTI_OP,`EXE_TLTIU_OP,`EXE_TLTU_OP:
begin
if(reg1_lt_reg2)begin
trapassert <= `TrapAssert;
end
end
//tne tnei指令
`EXE_TNE_OP,`EXE_TNEI_OP:begin
if(reg1_i!=reg2_i)begin
trapassert <= `TrapAssert;
end
end
default:begin
trapassert <= `TrapNotAssert;
end
endcase
end
end
endmodule
ex_mem.v
`include "define.v"
module ex_mem(
input wire clk,
input wire rst,
//来自控制模块的信息
input wire[5:0] stall,
input wire flush,
//来自执行阶段的信息
input wire[`RegAddrBus] ex_wd,
input wire ex_wreg,
input wire[`RegBus] ex_wdata,
input wire[`RegBus] ex_hi,
input wire[`RegBus] ex_lo,
input wire ex_whilo,
//为实现加载、访存指令而添加
input wire[`AluOpBus] ex_aluop,
input wire[`RegBus] ex_mem_addr,
input wire[`RegBus] ex_reg2,
input wire[`DoubleRegBus] hilo_i,
input wire[1:0] cnt_i,
input wire ex_cp0_reg_we,
input wire[4:0] ex_cp0_reg_write_addr,
input wire[`RegBus] ex_cp0_reg_data,
//最后一章 新增的输入模块
input wire[31:0] ex_excepttype,//译码、执行阶段手机到的异常信息
input wire ex_is_in_delayslot,//执行阶段的指令是否是延迟槽指令
input wire[`RegBus] ex_current_inst_address,//执行阶段指令的地址
//送到访存阶段的信息
output reg[`RegAddrBus] mem_wd,
output reg mem_wreg,
output reg[`RegBus] mem_wdata,
output reg[`RegBus] mem_hi,
output reg[`RegBus] mem_lo,
output reg mem_whilo,
//为实现加载、访存指令而添加
output reg[`AluOpBus] mem_aluop,
output reg[`RegBus] mem_mem_addr,
output reg[`RegBus] mem_reg2,
output reg mem_cp0_reg_we,
output reg[4:0] mem_cp0_reg_write_addr,
output reg[`RegBus] mem_cp0_reg_data,
output reg[`DoubleRegBus] hilo_o,
output reg[1:0] cnt_o ,
//最后一章 新增的输出模块
output reg[31:0] mem_excepttype,//译码、执行阶段收集到的异常信息
output reg mem_is_in_delayslot,//访存阶段的指令是否是延迟槽指令
output reg[`RegBus] mem_current_inst_address
);
always @ (posedge clk) begin
if(rst == `RstEnable) begin
mem_wd <= `NOPRegAddr;
mem_wreg <= `WriteDisable;
mem_wdata <= `ZeroWord;
mem_hi <= `ZeroWord;
mem_lo <= `ZeroWord;
mem_whilo <= `WriteDisable;
hilo_o <= {`ZeroWord, `ZeroWord};
cnt_o <= 2'b00;
mem_aluop <= `EXE_NOP_OP;
mem_mem_addr <= `ZeroWord;
mem_reg2 <= `ZeroWord;
mem_cp0_reg_we <= `WriteDisable;
mem_cp0_reg_write_addr <= 5'b00000;
mem_cp0_reg_data <= `ZeroWord;
mem_excepttype <= `ZeroWord;
mem_is_in_delayslot <= `NotInDelaySlot;
mem_current_inst_address <= `ZeroWord;
end else if(flush == 1'b1)begin
mem_wd <= `NOPRegAddr;
mem_wreg <= `WriteDisable;
mem_wdata <= `ZeroWord;
mem_hi <= `ZeroWord;
mem_lo <= `ZeroWord;
mem_whilo <= `WriteDisable;
mem_aluop <= `EXE_NOP_OP;
mem_mem_addr <= `ZeroWord;
mem_reg2 <= `ZeroWord;
mem_cp0_reg_we <= `WriteDisable;
mem_cp0_reg_write_addr <= 5'b00000;
mem_cp0_reg_data <= `ZeroWord;
mem_excepttype <= `ZeroWord;
mem_is_in_delayslot <= `NotInDelaySlot;
mem_current_inst_address <= `ZeroWord;
hilo_o <= {`ZeroWord,`ZeroWord};
cnt_o <= 2'b00;
end else if(stall[3] == `Stop && stall[4] == `NoStop) begin//执行阶段暂停 访存阶段没有暂停
mem_wd <= `NOPRegAddr;
mem_wreg <= `WriteDisable;
mem_wdata <= `ZeroWord;
mem_hi <= `ZeroWord;
mem_lo <= `ZeroWord;
mem_whilo <= `WriteDisable;
hilo_o <= hilo_i;
cnt_o <= cnt_i;
mem_aluop <= `EXE_NOP_OP;
mem_mem_addr <= `ZeroWord;
mem_reg2 <= `ZeroWord;
mem_cp0_reg_we <= `WriteDisable;
mem_cp0_reg_write_addr <= 5'b00000;
mem_cp0_reg_data <= `ZeroWord;
mem_excepttype <= `ZeroWord;
mem_is_in_delayslot <= `NotInDelaySlot;
mem_current_inst_address <= `ZeroWord;
end else if(stall[3] == `NoStop) begin//执行阶段没有暂停
mem_wd <= ex_wd;
mem_wreg <= ex_wreg;
mem_wdata <= ex_wdata;
mem_hi <= ex_hi;
mem_lo <= ex_lo;
mem_whilo <= ex_whilo;
hilo_o <= {`ZeroWord, `ZeroWord};
cnt_o <= 2'b00;
mem_aluop <= ex_aluop;
mem_mem_addr <= ex_mem_addr;
mem_reg2 <= ex_reg2;
mem_cp0_reg_we <= ex_cp0_reg_we;
mem_cp0_reg_write_addr <= ex_cp0_reg_write_addr;
mem_cp0_reg_data <= ex_cp0_reg_data;
mem_excepttype <= ex_excepttype;
mem_is_in_delayslot <= ex_is_in_delayslot;
mem_current_inst_address <= ex_current_inst_address;
end else begin
hilo_o <= hilo_i;
cnt_o <= cnt_i;
end //if
end //always
endmodule
mem.v
`include "define.v"
module mem(
input wire rst,
//来自执行阶段的信息
input wire[`RegAddrBus] wd_i,
input wire wreg_i,
input wire[`RegBus] wdata_i,
input wire[`RegBus] hi_i,
input wire[`RegBus] lo_i,
input wire whilo_i,
input wire[`AluOpBus] aluop_i,
input wire[`RegBus] mem_addr_i,
input wire[`RegBus] reg2_i,
//来自memory的信息
input wire[`RegBus] mem_data_i,
//LLbit_i是LLbit寄存器的值
input wire LLbit_i,
//但不一定是最新值,回写阶段可能要写LLbit,所以还要进一步判断
input wire wb_LLbit_we_i,
input wire wb_LLbit_value_i,
//协处理器CP0的写信号
input wire cp0_reg_we_i,
input wire[4:0] cp0_reg_write_addr_i,
input wire[`RegBus] cp0_reg_data_i,
input wire[31:0] excepttype_i,
input wire is_in_delayslot_i,
input wire[`RegBus] current_inst_address_i,
//CP0的各个寄存器的值,但不一定是最新的值,要防止回写阶段指令写CP0
input wire[`RegBus] cp0_status_i,
input wire[`RegBus] cp0_cause_i,
input wire[`RegBus] cp0_epc_i,
//回写阶段的指令是否要写CP0,用来检测数据相关
input wire wb_cp0_reg_we,
input wire[4:0] wb_cp0_reg_write_addr,
input wire[`RegBus] wb_cp0_reg_data,
//送到回写阶段的信息
output reg[`RegAddrBus] wd_o,
output reg wreg_o,
output reg[`RegBus] wdata_o,
output reg[`RegBus] hi_o,
output reg[`RegBus] lo_o,
output reg whilo_o,
output reg LLbit_we_o,
output reg LLbit_value_o,
output reg cp0_reg_we_o,
output reg[4:0] cp0_reg_write_addr_o,
output reg[`RegBus] cp0_reg_data_o,
//送到memory的信息
output reg[`RegBus] mem_addr_o,
output wire mem_we_o,
output reg[3:0] mem_sel_o,
output reg[`RegBus] mem_data_o,
output reg mem_ce_o,
output reg[31:0] excepttype_o,
output wire[`RegBus] cp0_epc_o,
output wire is_in_delayslot_o,
output wire[`RegBus] current_inst_address_o
);
reg LLbit;
wire[`RegBus] zero32;
reg[`RegBus] cp0_status;
reg[`RegBus] cp0_cause;
reg[`RegBus] cp0_epc;
reg mem_we;
assign mem_we_o = mem_we & (~(|excepttype_o));
assign zero32 = `ZeroWord;
assign is_in_delayslot_o = is_in_delayslot_i;
assign current_inst_address_o = current_inst_address_i;
assign cp0_epc_o = cp0_epc;
//获取最新的LLbit的值
always @ (*) begin
if(rst == `RstEnable) begin
LLbit <= 1'b0;
end else begin
if(wb_LLbit_we_i == 1'b1) begin
LLbit <= wb_LLbit_value_i;
end else begin
LLbit <= LLbit_i;
end
end
end
always @ (*) begin
if(rst == `RstEnable) begin
wd_o <= `NOPRegAddr;
wreg_o <= `WriteDisable;
wdata_o <= `ZeroWord;
hi_o <= `ZeroWord;
lo_o <= `ZeroWord;
whilo_o <= `WriteDisable;
mem_addr_o <= `ZeroWord;
mem_we <= `WriteDisable;
mem_sel_o <= 4'b0000;
mem_data_o <= `ZeroWord;
mem_ce_o <= `ChipDisable;
LLbit_we_o <= 1'b0;
LLbit_value_o <= 1'b0;
cp0_reg_we_o <= `WriteDisable;
cp0_reg_write_addr_o <= 5'b00000;
cp0_reg_data_o <= `ZeroWord;
end else begin
wd_o <= wd_i;
wreg_o <= wreg_i;
wdata_o <= wdata_i;
hi_o <= hi_i;
lo_o <= lo_i;
whilo_o <= whilo_i;
mem_we <= `WriteDisable;
mem_addr_o <= `ZeroWord;
mem_sel_o <= 4'b1111;
mem_ce_o <= `ChipDisable;
LLbit_we_o <= 1'b0;
LLbit_value_o <= 1'b0;
cp0_reg_we_o <= cp0_reg_we_i;
cp0_reg_write_addr_o <= cp0_reg_write_addr_i;
cp0_reg_data_o <= cp0_reg_data_i;
case (aluop_i)
`EXE_LB_OP: begin
mem_addr_o <= mem_addr_i;
mem_we <= `WriteDisable;
mem_ce_o <= `ChipEnable;
case (mem_addr_i[1:0])
2'b00: begin
wdata_o <= {{24{mem_data_i[31]}},mem_data_i[31:24]};
mem_sel_o <= 4'b1000;
end
2'b01: begin
wdata_o <= {{24{mem_data_i[23]}},mem_data_i[23:16]};
mem_sel_o <= 4'b0100;
end
2'b10: begin
wdata_o <= {{24{mem_data_i[15]}},mem_data_i[15:8]};
mem_sel_o <= 4'b0010;
end
2'b11: begin
wdata_o <= {{24{mem_data_i[7]}},mem_data_i[7:0]};
mem_sel_o <= 4'b0001;
end
default: begin
wdata_o <= `ZeroWord;
end
endcase
end
`EXE_LBU_OP: begin
mem_addr_o <= mem_addr_i;
mem_we <= `WriteDisable;
mem_ce_o <= `ChipEnable;
case (mem_addr_i[1:0])
2'b00: begin
wdata_o <= {{24{1'b0}},mem_data_i[31:24]};
mem_sel_o <= 4'b1000;
end
2'b01: begin
wdata_o <= {{24{1'b0}},mem_data_i[23:16]};
mem_sel_o <= 4'b0100;
end
2'b10: begin
wdata_o <= {{24{1'b0}},mem_data_i[15:8]};
mem_sel_o <= 4'b0010;
end
2'b11: begin
wdata_o <= {{24{1'b0}},mem_data_i[7:0]};
mem_sel_o <= 4'b0001;
end
default: begin
wdata_o <= `ZeroWord;
end
endcase
end
`EXE_LH_OP: begin
mem_addr_o <= mem_addr_i;
mem_we <= `WriteDisable;
mem_ce_o <= `ChipEnable;
case (mem_addr_i[1:0])
2'b00: begin
wdata_o <= {{16{mem_data_i[31]}},mem_data_i[31:16]};
mem_sel_o <= 4'b1100;
end
2'b10: begin
wdata_o <= {{16{mem_data_i[15]}},mem_data_i[15:0]};
mem_sel_o <= 4'b0011;
end
default: begin
wdata_o <= `ZeroWord;
end
endcase
end
`EXE_LHU_OP: begin
mem_addr_o <= mem_addr_i;
mem_we <= `WriteDisable;
mem_ce_o <= `ChipEnable;
case (mem_addr_i[1:0])
2'b00: begin
wdata_o <= {{16{1'b0}},mem_data_i[31:16]};
mem_sel_o <= 4'b1100;
end
2'b10: begin
wdata_o <= {{16{1'b0}},mem_data_i[15:0]};
mem_sel_o <= 4'b0011;
end
default: begin
wdata_o <= `ZeroWord;
end
endcase
end
`EXE_LW_OP: begin
mem_addr_o <= mem_addr_i;
mem_we <= `WriteDisable;
wdata_o <= mem_data_i;
mem_sel_o <= 4'b1111;
mem_ce_o <= `ChipEnable;
end
`EXE_LWL_OP: begin
mem_addr_o <= {mem_addr_i[31:2], 2'b00};
mem_we <= `WriteDisable;
mem_sel_o <= 4'b1111;
mem_ce_o <= `ChipEnable;
case (mem_addr_i[1:0])
2'b00: begin
wdata_o <= mem_data_i[31:0];
end
2'b01: begin
wdata_o <= {mem_data_i[23:0],reg2_i[7:0]};
end
2'b10: begin
wdata_o <= {mem_data_i[15:0],reg2_i[15:0]};
end
2'b11: begin
wdata_o <= {mem_data_i[7:0],reg2_i[23:0]};
end
default: begin
wdata_o <= `ZeroWord;
end
endcase
end
`EXE_LWR_OP: begin
mem_addr_o <= {mem_addr_i[31:2], 2'b00};
mem_we <= `WriteDisable;
mem_sel_o <= 4'b1111;
mem_ce_o <= `ChipEnable;
case (mem_addr_i[1:0])
2'b00: begin
wdata_o <= {reg2_i[31:8],mem_data_i[31:24]};
end
2'b01: begin
wdata_o <= {reg2_i[31:16],mem_data_i[31:16]};
end
2'b10: begin
wdata_o <= {reg2_i[31:24],mem_data_i[31:8]};
end
2'b11: begin
wdata_o <= mem_data_i;
end
default: begin
wdata_o <= `ZeroWord;
end
endcase
end
`EXE_LL_OP: begin
mem_addr_o <= mem_addr_i;
mem_we <= `WriteDisable;
wdata_o <= mem_data_i;
LLbit_we_o <= 1'b1;
LLbit_value_o <= 1'b1;
mem_sel_o <= 4'b1111;
mem_ce_o <= `ChipEnable;
end
`EXE_SB_OP: begin
mem_addr_o <= mem_addr_i;
mem_we <= `WriteEnable;
mem_data_o <= {reg2_i[7:0],reg2_i[7:0],reg2_i[7:0],reg2_i[7:0]};
mem_ce_o <= `ChipEnable;
case (mem_addr_i[1:0])
2'b00: begin
mem_sel_o <= 4'b1000;
end
2'b01: begin
mem_sel_o <= 4'b0100;
end
2'b10: begin
mem_sel_o <= 4'b0010;
end
2'b11: begin
mem_sel_o <= 4'b0001;
end
default: begin
mem_sel_o <= 4'b0000;
end
endcase
end
`EXE_SH_OP: begin
mem_addr_o <= mem_addr_i;
mem_we <= `WriteEnable;
mem_data_o <= {reg2_i[15:0],reg2_i[15:0]};
mem_ce_o <= `ChipEnable;
case (mem_addr_i[1:0])
2'b00: begin
mem_sel_o <= 4'b1100;
end
2'b10: begin
mem_sel_o <= 4'b0011;
end
default: begin
mem_sel_o <= 4'b0000;
end
endcase
end
`EXE_SW_OP: begin
mem_addr_o <= mem_addr_i;
mem_we <= `WriteEnable;
mem_data_o <= reg2_i;
mem_sel_o <= 4'b1111;
mem_ce_o <= `ChipEnable;
end
`EXE_SWL_OP: begin
mem_addr_o <= {mem_addr_i[31:2], 2'b00};
mem_we <= `WriteEnable;
mem_ce_o <= `ChipEnable;
case (mem_addr_i[1:0])
2'b00: begin
mem_sel_o <= 4'b1111;
mem_data_o <= reg2_i;
end
2'b01: begin
mem_sel_o <= 4'b0111;
mem_data_o <= {zero32[7:0],reg2_i[31:8]};
end
2'b10: begin
mem_sel_o <= 4'b0011;
mem_data_o <= {zero32[15:0],reg2_i[31:16]};
end
2'b11: begin
mem_sel_o <= 4'b0001;
mem_data_o <= {zero32[23:0],reg2_i[31:24]};
end
default: begin
mem_sel_o <= 4'b0000;
end
endcase
end
`EXE_SWR_OP: begin
mem_addr_o <= {mem_addr_i[31:2], 2'b00};
mem_we <= `WriteEnable;
mem_ce_o <= `ChipEnable;
case (mem_addr_i[1:0])
2'b00: begin
mem_sel_o <= 4'b1000;
mem_data_o <= {reg2_i[7:0],zero32[23:0]};
end
2'b01: begin
mem_sel_o <= 4'b1100;
mem_data_o <= {reg2_i[15:0],zero32[15:0]};
end
2'b10: begin
mem_sel_o <= 4'b1110;
mem_data_o <= {reg2_i[23:0],zero32[7:0]};
end
2'b11: begin
mem_sel_o <= 4'b1111;
mem_data_o <= reg2_i[31:0];
end
default: begin
mem_sel_o <= 4'b0000;
end
endcase
end
`EXE_SC_OP: begin
if(LLbit == 1'b1) begin
LLbit_we_o <= 1'b1;
LLbit_value_o <= 1'b0;
mem_addr_o <= mem_addr_i;
mem_we <= `WriteEnable;
mem_data_o <= reg2_i;
wdata_o <= 32'b1;
mem_sel_o <= 4'b1111;
mem_ce_o <= `ChipEnable;
end else begin
wdata_o <= 32'b0;
end
end
default: begin
//什么也不做
end
endcase
end //if
end //always
always @ (*) begin
if(rst == `RstEnable) begin
cp0_status <= `ZeroWord;
end else if((wb_cp0_reg_we == `WriteEnable) &&
(wb_cp0_reg_write_addr == `CP0_REG_STATUS ))begin
cp0_status <= wb_cp0_reg_data;
end else begin
cp0_status <= cp0_status_i;
end
end
always @ (*) begin
if(rst == `RstEnable) begin
cp0_epc <= `ZeroWord;
end else if((wb_cp0_reg_we == `WriteEnable) &&
(wb_cp0_reg_write_addr == `CP0_REG_EPC ))begin
cp0_epc <= wb_cp0_reg_data;
end else begin
cp0_epc <= cp0_epc_i;
end
end
always @ (*) begin
if(rst == `RstEnable) begin
cp0_cause <= `ZeroWord;
end else if((wb_cp0_reg_we == `WriteEnable) &&
(wb_cp0_reg_write_addr == `CP0_REG_CAUSE ))begin
cp0_cause[9:8] <= wb_cp0_reg_data[9:8];
cp0_cause[22] <= wb_cp0_reg_data[22];
cp0_cause[23] <= wb_cp0_reg_data[23];
end else begin
cp0_cause <= cp0_cause_i;
end
end
always @ (*) begin
if(rst == `RstEnable) begin
excepttype_o <= `ZeroWord;
end else begin
excepttype_o <= `ZeroWord;
if(current_inst_address_i != `ZeroWord) begin
if(((cp0_cause[15:8] & (cp0_status[15:8])) != 8'h00) && (cp0_status[1] == 1'b0) &&
(cp0_status[0] == 1'b1)) begin
excepttype_o <= 32'h00000001; //interrupt
end else if(excepttype_i[8] == 1'b1) begin
excepttype_o <= 32'h00000008; //syscall
end else if(excepttype_i[9] == 1'b1) begin
excepttype_o <= 32'h0000000a; //inst_invalid
end else if(excepttype_i[10] ==1'b1) begin
excepttype_o <= 32'h0000000d; //trap
end else if(excepttype_i[11] == 1'b1) begin //ov
excepttype_o <= 32'h0000000c;
end else if(excepttype_i[12] == 1'b1) begin //返回指令
excepttype_o <= 32'h0000000e;
end
end
end
end
endmodule
mem_wb.v
`include "define.v"
module mem_wb(
input wire clk,
input wire rst,
//来自控制模块的信息
input wire[5:0] stall,
input wire flush,
//来自访存阶段的信息
input wire[`RegAddrBus] mem_wd,
input wire mem_wreg,
input wire[`RegBus] mem_wdata,
input wire[`RegBus] mem_hi,
input wire[`RegBus] mem_lo,
input wire mem_whilo,
input wire mem_LLbit_we,
input wire mem_LLbit_value,
input wire mem_cp0_reg_we,
input wire[4:0] mem_cp0_reg_write_addr,
input wire[`RegBus] mem_cp0_reg_data,
//送到回写阶段的信息
output reg[`RegAddrBus] wb_wd,
output reg wb_wreg,
output reg[`RegBus] wb_wdata,
output reg[`RegBus] wb_hi,
output reg[`RegBus] wb_lo,
output reg wb_whilo,
output reg wb_LLbit_we,
output reg wb_LLbit_value,
output reg wb_cp0_reg_we,
output reg[4:0] wb_cp0_reg_write_addr,
output reg[`RegBus] wb_cp0_reg_data
);
always @ (posedge clk) begin
if(rst == `RstEnable) begin
wb_wd <= `NOPRegAddr;
wb_wreg <= `WriteDisable;
wb_wdata <= `ZeroWord;
wb_hi <= `ZeroWord;
wb_lo <= `ZeroWord;
wb_whilo <= `WriteDisable;
wb_LLbit_we <= 1'b0;
wb_LLbit_value <= 1'b0;
wb_cp0_reg_we <= `WriteDisable;
wb_cp0_reg_write_addr <= 5'b00000;
wb_cp0_reg_data <= `ZeroWord;
end else if(flush == 1'b1 ) begin
wb_wd <= `NOPRegAddr;
wb_wreg <= `WriteDisable;
wb_wdata <= `ZeroWord;
wb_hi <= `ZeroWord;
wb_lo <= `ZeroWord;
wb_whilo <= `WriteDisable;
wb_LLbit_we <= 1'b0;
wb_LLbit_value <= 1'b0;
wb_cp0_reg_we <= `WriteDisable;
wb_cp0_reg_write_addr <= 5'b00000;
wb_cp0_reg_data <= `ZeroWord;
end else if(stall[4] == `Stop && stall[5] == `NoStop) begin
wb_wd <= `NOPRegAddr;
wb_wreg <= `WriteDisable;
wb_wdata <= `ZeroWord;
wb_hi <= `ZeroWord;
wb_lo <= `ZeroWord;
wb_whilo <= `WriteDisable;
wb_LLbit_we <= 1'b0;
wb_LLbit_value <= 1'b0;
wb_cp0_reg_we <= `WriteDisable;
wb_cp0_reg_write_addr <= 5'b00000;
wb_cp0_reg_data <= `ZeroWord;
end else if(stall[4] == `NoStop) begin
wb_wd <= mem_wd;
wb_wreg <= mem_wreg;
wb_wdata <= mem_wdata;
wb_hi <= mem_hi;
wb_lo <= mem_lo;
wb_whilo <= mem_whilo;
wb_LLbit_we <= mem_LLbit_we;
wb_LLbit_value <= mem_LLbit_value;
wb_cp0_reg_we <= mem_cp0_reg_we;
wb_cp0_reg_write_addr <= mem_cp0_reg_write_addr;
wb_cp0_reg_data <= mem_cp0_reg_data;
end //if
end //always
endmodule
regfile.v
`include "define.v"
//回写阶段的实现实际上是在Regfile模块中实现的
//Regfile模块 寄存器堆
module regfile(
input wire clk,//时钟信号
input wire rst,//复位信号,高电平有效
//写端口
input wire we,//写使能信号
input wire[`RegAddrBus] waddr,//要写入的寄存器地址
input wire[`RegBus] wdata,//要写入的数据
//读端口1
input wire re1,//第一个读寄存器端口读使能信号
input wire[`RegAddrBus] raddr1,//第一个读寄存器端口要读取的寄存器的地址
output reg[`RegBus] rdata1,//第一个读寄存器端口输出寄存器的值
//读端口2
input wire re2,//第二个读寄存器端口读使能信号
input wire[`RegAddrBus] raddr2,//第二个读寄存器端口要读取的寄存器地址
output reg[`RegBus] rdata2//第二个读寄存器端口要输出的寄存器的值
);
/*******第一段: 定义32个32位寄存器*******/
/*******第二段:写操作******************/
/*******第三段:读端口1的读操作********/
/*******第四段:读端口2的读操作*******/
//第一段:定义32个32位寄存器
reg[`RegBus] regs[0:`RegNum-1];
//第二段:实现写寄存器操作
always @ (posedge clk)
begin
if(rst==`RstDisable)//rst==1,复位信号无效
begin
if((we==`WriteEnable)&&(waddr!=`RegNumLog2'h0))//写使能信号we有效 且 写操作目的寄存器不等于0的情况下
begin//MIPS32架构规定 $0的值只能为0 所以不需要写入
regs[waddr]<=wdata;//将写输入数据保存到目的寄存器
end
end
end
//第三段:读端口1的读操作 实现第一个读寄存器端口
always @(*)
begin
if(rst==`RstEnable)//当复位信号有效时
begin
rdata1 <= `ZeroWord;//第一个读寄存器端口的输出始终为0
end
else if(raddr1==`RegNumLog2'h0)//当复位信号无效时 如果读取的是$0
begin
rdata1<=`ZeroWord;//直接给出0
end
else if((raddr1==waddr)&&(we==`WriteEnable)&&(re1==`ReadEnable))//如果第一个读寄存器端口要读取的目标寄存器与要写入的目的寄存器是同一个
begin
rdata1<=wdata;//直接将要写入的值作为第一个寄存器端口的输出
end
else if(re1==`ReadEnable)//上述情况都不满足时
begin
rdata1<=regs[raddr1];//给出第一个读寄存器端口要读取的目标寄存器地址对应寄存器的值
end
else//当第一个寄存器端口不能使用时
begin
rdata1<=`ZeroWord;//直接输出0
end
end
//第四段 读端口2的操作 实现第二个寄存器端口 具体过程和第三段相似 注意地址的变化
always @ (*)
begin
if(rst==`RstEnable)
begin
rdata2<=`ZeroWord;
end
else if(raddr2==`RegNumLog2'h0)
begin
rdata2<=`ZeroWord;
end
else if((raddr2==waddr)&&(we==`WriteEnable)&&(re2==`ReadEnable))
begin
rdata2<=wdata;
end
else if(re2==`ReadEnable)
begin
rdata2<=regs[raddr2];
end
else
begin
rdata2<=`ZeroWord;
end
end
endmodule
cp_reg.v
`include "define.v"
module cp0_reg(
input wire clk,
input wire rst,
input wire we_i,
input wire[4:0] waddr_i,
input wire[4:0] raddr_i,
input wire[`RegBus] data_i,
input wire[31:0] excepttype_i,
input wire[5:0] int_i,
input wire[`RegBus] current_inst_addr_i,
input wire is_in_delayslot_i,
output reg[`RegBus] data_o,
output reg[`RegBus] count_o,
output reg[`RegBus] compare_o,
output reg[`RegBus] status_o,
output reg[`RegBus] cause_o,
output reg[`RegBus] epc_o,
output reg[`RegBus] config_o,
output reg[`RegBus] prid_o,
output reg timer_int_o
);
always @ (posedge clk) begin
if(rst == `RstEnable) begin
count_o <= `ZeroWord;
compare_o <= `ZeroWord;
//status寄存器的CU为0001,表示协处理器CP0存在
status_o <= 32'b00010000000000000000000000000000;
cause_o <= `ZeroWord;
epc_o <= `ZeroWord;
//config寄存器的BE为1,表示Big-Endian;MT为00,表示没有MMU
config_o <= 32'b00000000000000001000000000000000;
//制作者是L,对应的是0x48,类型是0x1,基本类型,版本号是1.0
prid_o <= 32'b00000000010011000000000100000010;
timer_int_o <= `InterruputNotAssert;
end else begin
count_o <= count_o + 1 ;
cause_o[15:10] <= int_i;
if(compare_o != `ZeroWord && count_o == compare_o) begin
timer_int_o <= `InterruputAssert;
end
if(we_i == `WriteEnable) begin
case (waddr_i)
`CP0_REG_COUNT: begin
count_o <= data_i;
end
`CP0_REG_COMPARE: begin
compare_o <= data_i;
//count_o <= `ZeroWord;
timer_int_o <= `InterruputNotAssert;
end
`CP0_REG_STATUS: begin
status_o <= data_i;
end
`CP0_REG_EPC: begin
epc_o <= data_i;
end
`CP0_REG_CAUSE: begin
//cause寄存器只有IP[1:0]、IV、WP字段是可写的
cause_o[9:8] <= data_i[9:8];
cause_o[23] <= data_i[23];
cause_o[22] <= data_i[22];
end
endcase //case addr_i
end
case (excepttype_i)
32'h00000001: begin
if(is_in_delayslot_i == `InDelaySlot ) begin
epc_o <= current_inst_addr_i - 4 ;
cause_o[31] <= 1'b1;
end else begin
epc_o <= current_inst_addr_i;
cause_o[31] <= 1'b0;
end
status_o[1] <= 1'b1;
cause_o[6:2] <= 5'b00000;
end
32'h00000008: begin
if(status_o[1] == 1'b0) begin
if(is_in_delayslot_i == `InDelaySlot ) begin
epc_o <= current_inst_addr_i - 4 ;
cause_o[31] <= 1'b1;
end else begin
epc_o <= current_inst_addr_i;
cause_o[31] <= 1'b0;
end
end
status_o[1] <= 1'b1;
cause_o[6:2] <= 5'b01000;
end
32'h0000000a: begin
if(status_o[1] == 1'b0) begin
if(is_in_delayslot_i == `InDelaySlot ) begin
epc_o <= current_inst_addr_i - 4 ;
cause_o[31] <= 1'b1;
end else begin
epc_o <= current_inst_addr_i;
cause_o[31] <= 1'b0;
end
end
status_o[1] <= 1'b1;
cause_o[6:2] <= 5'b01010;
end
32'h0000000d: begin
if(status_o[1] == 1'b0) begin
if(is_in_delayslot_i == `InDelaySlot ) begin
epc_o <= current_inst_addr_i - 4 ;
cause_o[31] <= 1'b1;
end else begin
epc_o <= current_inst_addr_i;
cause_o[31] <= 1'b0;
end
end
status_o[1] <= 1'b1;
cause_o[6:2] <= 5'b01101;
end
32'h0000000c: begin
if(status_o[1] == 1'b0) begin
if(is_in_delayslot_i == `InDelaySlot ) begin
epc_o <= current_inst_addr_i - 4 ;
cause_o[31] <= 1'b1;
end else begin
epc_o <= current_inst_addr_i;
cause_o[31] <= 1'b0;
end
end
status_o[1] <= 1'b1;
cause_o[6:2] <= 5'b01100;
end
32'h0000000e: begin
status_o[1] <= 1'b0;
end
default: begin
end
endcase
end //if
end //always
always @ (*) begin
if(rst == `RstEnable) begin
data_o <= `ZeroWord;
end else begin
case (raddr_i)
`CP0_REG_COUNT: begin
data_o <= count_o ;
end
`CP0_REG_COMPARE: begin
data_o <= compare_o ;
end
`CP0_REG_STATUS: begin
data_o <= status_o ;
end
`CP0_REG_CAUSE: begin
data_o <= cause_o ;
end
`CP0_REG_EPC: begin
data_o <= epc_o ;
end
`CP0_REG_PrId: begin
data_o <= prid_o ;
end
`CP0_REG_CONFIG: begin
data_o <= config_o ;
end
default: begin
end
endcase //case addr_i
end //if
end //always
endmodule
LLbit_reg.v
`include "define.v"
module LLbit_reg(
input wire clk,
input wire rst,
//异常是否发生 为1表示异常发生 为0表示没有异常
input wire flush,
//写操作
input wire LLbit_i,
input wire we,
//LLbit寄存器的值
output reg LLbit_o
);
always @ (posedge clk) begin
if(rst == `RstEnable)begin
LLbit_o <= 1'b0;
end else if((flush == 1'b1))begin//如果异常发生 那么设置LLbit_o为0
LLbit_o <= 1'b0;
end else if((we == `WriteEnable))begin
LLbit_o <= LLbit_i;
end
end
endmodule
openmips.v
`include "define.v"
module openmips(
input wire clk,
input wire rst,
input wire[5:0] int_i,
input wire[`RegBus] rom_data_i,
output wire[`RegBus] rom_addr_o,
output wire rom_ce_o,
//连接数据存储器data_ram
input wire[`RegBus] ram_data_i,
output wire[`RegBus] ram_addr_o,
output wire[`RegBus] ram_data_o,
output wire ram_we_o,
output wire[3:0] ram_sel_o,
output wire[3:0] ram_ce_o,
output wire timer_int_o
);
wire[`InstAddrBus] pc;
wire[`InstAddrBus] id_pc_i;
wire[`InstBus] id_inst_i;
//连接译码阶段ID模块的输出与ID/EX模块的输入
wire[`AluOpBus] id_aluop_o;
wire[`AluSelBus] id_alusel_o;
wire[`RegBus] id_reg1_o;
wire[`RegBus] id_reg2_o;
wire id_wreg_o;
wire[`RegAddrBus] id_wd_o;
wire id_is_in_delayslot_o;
wire[`RegBus] id_link_address_o;
wire[`RegBus] id_inst_o;
wire[31:0] id_excepttype_o;
wire[`RegBus] id_current_inst_address_o;
//连接ID/EX模块的输出与执行阶段EX模块的输入
wire[`AluOpBus] ex_aluop_i;
wire[`AluSelBus] ex_alusel_i;
wire[`RegBus] ex_reg1_i;
wire[`RegBus] ex_reg2_i;
wire ex_wreg_i;
wire[`RegAddrBus] ex_wd_i;
wire ex_is_in_delayslot_i;
wire[`RegBus] ex_link_address_i;
wire[`RegBus] ex_inst_i;
wire[31:0] ex_excepttype_i;
wire[`RegBus] ex_current_inst_address_i;
//连接执行阶段EX模块的输出与EX/MEM模块的输入
wire ex_wreg_o;
wire[`RegAddrBus] ex_wd_o;
wire[`RegBus] ex_wdata_o;
wire[`RegBus] ex_hi_o;
wire[`RegBus] ex_lo_o;
wire ex_whilo_o;
wire[`AluOpBus] ex_aluop_o;
wire[`RegBus] ex_mem_addr_o;
wire[`RegBus] ex_reg2_o;
wire ex_cp0_reg_we_o;
wire[4:0] ex_cp0_reg_write_addr_o;
wire[`RegBus] ex_cp0_reg_data_o;
wire[31:0] ex_excepttype_o;
wire[`RegBus] ex_current_inst_address_o;
wire ex_is_in_delayslot_o;
//连接EX/MEM模块的输出与访存阶段MEM模块的输入
wire mem_wreg_i;
wire[`RegAddrBus] mem_wd_i;
wire[`RegBus] mem_wdata_i;
wire[`RegBus] mem_hi_i;
wire[`RegBus] mem_lo_i;
wire mem_whilo_i;
wire[`AluOpBus] mem_aluop_i;
wire[`RegBus] mem_mem_addr_i;
wire[`RegBus] mem_reg2_i;
wire mem_cp0_reg_we_i;
wire[4:0] mem_cp0_reg_write_addr_i;
wire[`RegBus] mem_cp0_reg_data_i;
wire[31:0] mem_excepttype_i;
wire mem_is_in_delayslot_i;
wire[`RegBus] mem_current_inst_address_i;
//连接访存阶段MEM模块的输出与MEM/WB模块的输入
wire mem_wreg_o;
wire[`RegAddrBus] mem_wd_o;
wire[`RegBus] mem_wdata_o;
wire[`RegBus] mem_hi_o;
wire[`RegBus] mem_lo_o;
wire mem_whilo_o;
wire mem_LLbit_value_o;
wire mem_LLbit_we_o;
wire mem_cp0_reg_we_o;
wire[4:0] mem_cp0_reg_write_addr_o;
wire[`RegBus] mem_cp0_reg_data_o;
wire[31:0] mem_excepttype_o;
wire mem_is_in_delayslot_o;
wire[`RegBus] mem_current_inst_address_o;
//连接MEM/WB模块的输出与回写阶段的输入
wire wb_wreg_i;
wire[`RegAddrBus] wb_wd_i;
wire[`RegBus] wb_wdata_i;
wire[`RegBus] wb_hi_i;
wire[`RegBus] wb_lo_i;
wire wb_whilo_i;
wire wb_LLbit_value_i;
wire wb_LLbit_we_i;
wire wb_cp0_reg_we_i;
wire[4:0] wb_cp0_reg_write_addr_i;
wire[`RegBus] wb_cp0_reg_data_i;
wire[31:0] wb_excepttype_i;
wire wb_is_in_delayslot_i;
wire[`RegBus] wb_current_inst_address_i;
//连接译码阶段ID模块与通用寄存器Regfile模块
wire reg1_read;
wire reg2_read;
wire[`RegBus] reg1_data;
wire[`RegBus] reg2_data;
wire[`RegAddrBus] reg1_addr;
wire[`RegAddrBus] reg2_addr;
//连接执行阶段与hilo模块的输出,读取HI、LO寄存器
wire[`RegBus] hi;
wire[`RegBus] lo;
//连接执行阶段与ex_reg模块,用于多周期的MADD、MADDU、MSUB、MSUBU指令
wire[`DoubleRegBus] hilo_temp_o;
wire[1:0] cnt_o;
wire[`DoubleRegBus] hilo_temp_i;
wire[1:0] cnt_i;
wire[`DoubleRegBus] div_result;
wire div_ready;
wire[`RegBus] div_opdata1;
wire[`RegBus] div_opdata2;
wire div_start;
wire div_annul;
wire signed_div;
wire is_in_delayslot_i;
wire is_in_delayslot_o;
wire next_inst_in_delayslot_o;
wire id_branch_flag_o;
wire[`RegBus] branch_target_address;
wire[5:0] stall;
wire stallreq_from_id;
wire stallreq_from_ex;
wire LLbit_o;
wire[`RegBus] cp0_data_o;
wire[4:0] cp0_raddr_i;
wire flush;
wire[`RegBus] new_pc;
wire[`RegBus] cp0_count;
wire[`RegBus] cp0_compare;
wire[`RegBus] cp0_status;
wire[`RegBus] cp0_cause;
wire[`RegBus] cp0_epc;
wire[`RegBus] cp0_config;
wire[`RegBus] cp0_prid;
wire[`RegBus] latest_epc;
//pc_reg例化
pc_reg pc_reg0(
.clk(clk),
.rst(rst),
.stall(stall),
.flush(flush),
.new_pc(new_pc),
.branch_flag_i(id_branch_flag_o),
.branch_target_address_i(branch_target_address),
.pc(pc),
.ce(rom_ce_o)
);
assign rom_addr_o = pc;
//IF/ID模块例化
if_id if_id0(
.clk(clk),
.rst(rst),
.stall(stall),
.flush(flush),
.if_pc(pc),
.if_inst(rom_data_i),
.id_pc(id_pc_i),
.id_inst(id_inst_i)
);
//译码阶段ID模块
id id0(
.rst(rst),
.pc_i(id_pc_i),
.inst_i(id_inst_i),
.ex_aluop_i(ex_aluop_o),
.reg1_data_i(reg1_data),
.reg2_data_i(reg2_data),
//处于执行阶段的指令要写入的目的寄存器信息
.ex_wreg_i(ex_wreg_o),
.ex_wdata_i(ex_wdata_o),
.ex_wd_i(ex_wd_o),
//处于访存阶段的指令要写入的目的寄存器信息
.mem_wreg_i(mem_wreg_o),
.mem_wdata_i(mem_wdata_o),
.mem_wd_i(mem_wd_o),
.is_in_delayslot_i(is_in_delayslot_i),
//送到regfile的信息
.reg1_read_o(reg1_read),
.reg2_read_o(reg2_read),
.reg1_addr_o(reg1_addr),
.reg2_addr_o(reg2_addr),
//送到ID/EX模块的信息
.aluop_o(id_aluop_o),
.alusel_o(id_alusel_o),
.reg1_o(id_reg1_o),
.reg2_o(id_reg2_o),
.wd_o(id_wd_o),
.wreg_o(id_wreg_o),
.excepttype_o(id_excepttype_o),
.inst_o(id_inst_o),
.next_inst_in_delayslot_o(next_inst_in_delayslot_o),
.branch_flag_o(id_branch_flag_o),
.branch_target_address_o(branch_target_address),
.link_addr_o(id_link_address_o),
.is_in_delayslot_o(id_is_in_delayslot_o),
.current_inst_address_o(id_current_inst_address_o),
.stallreq(stallreq_from_id)
);
//通用寄存器Regfile例化
regfile regfile1(
.clk (clk),
.rst (rst),
.we (wb_wreg_i),
.waddr (wb_wd_i),
.wdata (wb_wdata_i),
.re1 (reg1_read),
.raddr1 (reg1_addr),
.rdata1 (reg1_data),
.re2 (reg2_read),
.raddr2 (reg2_addr),
.rdata2 (reg2_data)
);
//ID/EX模块
id_ex id_ex0(
.clk(clk),
.rst(rst),
.stall(stall),
.flush(flush),
//从译码阶段ID模块传递的信息
.id_aluop(id_aluop_o),
.id_alusel(id_alusel_o),
.id_reg1(id_reg1_o),
.id_reg2(id_reg2_o),
.id_wd(id_wd_o),
.id_wreg(id_wreg_o),
.id_link_address(id_link_address_o),
.id_is_in_delayslot(id_is_in_delayslot_o),
.next_inst_in_delayslot_i(next_inst_in_delayslot_o),
.id_inst(id_inst_o),
.id_excepttype(id_excepttype_o),
.id_current_inst_address(id_current_inst_address_o),
//传递到执行阶段EX模块的信息
.ex_aluop(ex_aluop_i),
.ex_alusel(ex_alusel_i),
.ex_reg1(ex_reg1_i),
.ex_reg2(ex_reg2_i),
.ex_wd(ex_wd_i),
.ex_wreg(ex_wreg_i),
.ex_link_address(ex_link_address_i),
.ex_is_in_delayslot(ex_is_in_delayslot_i),
.is_in_delayslot_o(is_in_delayslot_i),
.ex_inst(ex_inst_i),
.ex_excepttype(ex_excepttype_i),
.ex_current_inst_address(ex_current_inst_address_i)
);
//EX模块
ex ex0(
.rst(rst),
//送到执行阶段EX模块的信息
.aluop_i(ex_aluop_i),
.alusel_i(ex_alusel_i),
.reg1_i(ex_reg1_i),
.reg2_i(ex_reg2_i),
.wd_i(ex_wd_i),
.wreg_i(ex_wreg_i),
.hi_i(hi),
.lo_i(lo),
.inst_i(ex_inst_i),
.wb_hi_i(wb_hi_i),
.wb_lo_i(wb_lo_i),
.wb_whilo_i(wb_whilo_i),
.mem_hi_i(mem_hi_o),
.mem_lo_i(mem_lo_o),
.mem_whilo_i(mem_whilo_o),
.hilo_temp_i(hilo_temp_i),
.cnt_i(cnt_i),
.div_result_i(div_result),
.div_ready_i(div_ready),
.link_address_i(ex_link_address_i),
.is_in_delayslot_i(ex_is_in_delayslot_i),
.excepttype_i(ex_excepttype_i),
.current_inst_address_i(ex_current_inst_address_i),
//访存阶段的指令是否要写CP0,用来检测数据相关
.mem_cp0_reg_we(mem_cp0_reg_we_o),
.mem_cp0_reg_write_addr(mem_cp0_reg_write_addr_o),
.mem_cp0_reg_data(mem_cp0_reg_data_o),
//回写阶段的指令是否要写CP0,用来检测数据相关
.wb_cp0_reg_we(wb_cp0_reg_we_i),
.wb_cp0_reg_write_addr(wb_cp0_reg_write_addr_i),
.wb_cp0_reg_data(wb_cp0_reg_data_i),
.cp0_reg_data_i(cp0_data_o),
.cp0_reg_read_addr_o(cp0_raddr_i),
//向下一流水级传递,用于写CP0中的寄存器
.cp0_reg_we_o(ex_cp0_reg_we_o),
.cp0_reg_write_addr_o(ex_cp0_reg_write_addr_o),
.cp0_reg_data_o(ex_cp0_reg_data_o),
//EX模块的输出到EX/MEM模块信息
.wd_o(ex_wd_o),
.wreg_o(ex_wreg_o),
.wdata_o(ex_wdata_o),
.hi_o(ex_hi_o),
.lo_o(ex_lo_o),
.whilo_o(ex_whilo_o),
.hilo_temp_o(hilo_temp_o),
.cnt_o(cnt_o),
.div_opdata1_o(div_opdata1),
.div_opdata2_o(div_opdata2),
.div_start_o(div_start),
.signed_div_o(signed_div),
.aluop_o(ex_aluop_o),
.mem_addr_o(ex_mem_addr_o),
.reg2_o(ex_reg2_o),
.excepttype_o(ex_excepttype_o),
.is_in_delayslot_o(ex_is_in_delayslot_o),
.current_inst_address_o(ex_current_inst_address_o),
.stallreq(stallreq_from_ex)
);
//EX/MEM模块
ex_mem ex_mem0(
.clk(clk),
.rst(rst),
.stall(stall),
.flush(flush),
//来自执行阶段EX模块的信息
.ex_wd(ex_wd_o),
.ex_wreg(ex_wreg_o),
.ex_wdata(ex_wdata_o),
.ex_hi(ex_hi_o),
.ex_lo(ex_lo_o),
.ex_whilo(ex_whilo_o),
.ex_aluop(ex_aluop_o),
.ex_mem_addr(ex_mem_addr_o),
.ex_reg2(ex_reg2_o),
.ex_cp0_reg_we(ex_cp0_reg_we_o),
.ex_cp0_reg_write_addr(ex_cp0_reg_write_addr_o),
.ex_cp0_reg_data(ex_cp0_reg_data_o),
.ex_excepttype(ex_excepttype_o),
.ex_is_in_delayslot(ex_is_in_delayslot_o),
.ex_current_inst_address(ex_current_inst_address_o),
.hilo_i(hilo_temp_o),
.cnt_i(cnt_o),
//送到访存阶段MEM模块的信息
.mem_wd(mem_wd_i),
.mem_wreg(mem_wreg_i),
.mem_wdata(mem_wdata_i),
.mem_hi(mem_hi_i),
.mem_lo(mem_lo_i),
.mem_whilo(mem_whilo_i),
.mem_cp0_reg_we(mem_cp0_reg_we_i),
.mem_cp0_reg_write_addr(mem_cp0_reg_write_addr_i),
.mem_cp0_reg_data(mem_cp0_reg_data_i),
.mem_aluop(mem_aluop_i),
.mem_mem_addr(mem_mem_addr_i),
.mem_reg2(mem_reg2_i),
.mem_excepttype(mem_excepttype_i),
.mem_is_in_delayslot(mem_is_in_delayslot_i),
.mem_current_inst_address(mem_current_inst_address_i),
.hilo_o(hilo_temp_i),
.cnt_o(cnt_i)
);
//MEM模块例化
mem mem0(
.rst(rst),
//来自EX/MEM模块的信息
.wd_i(mem_wd_i),
.wreg_i(mem_wreg_i),
.wdata_i(mem_wdata_i),
.hi_i(mem_hi_i),
.lo_i(mem_lo_i),
.whilo_i(mem_whilo_i),
.aluop_i(mem_aluop_i),
.mem_addr_i(mem_mem_addr_i),
.reg2_i(mem_reg2_i),
//来自memory的信息
.mem_data_i(ram_data_i),
//LLbit_i是LLbit寄存器的值
.LLbit_i(LLbit_o),
//但不一定是最新值,回写阶段可能要写LLbit,所以还要进一步判断
.wb_LLbit_we_i(wb_LLbit_we_i),
.wb_LLbit_value_i(wb_LLbit_value_i),
.cp0_reg_we_i(mem_cp0_reg_we_i),
.cp0_reg_write_addr_i(mem_cp0_reg_write_addr_i),
.cp0_reg_data_i(mem_cp0_reg_data_i),
.excepttype_i(mem_excepttype_i),
.is_in_delayslot_i(mem_is_in_delayslot_i),
.current_inst_address_i(mem_current_inst_address_i),
.cp0_status_i(cp0_status),
.cp0_cause_i(cp0_cause),
.cp0_epc_i(cp0_epc),
//回写阶段的指令是否要写CP0,用来检测数据相关
.wb_cp0_reg_we(wb_cp0_reg_we_i),
.wb_cp0_reg_write_addr(wb_cp0_reg_write_addr_i),
.wb_cp0_reg_data(wb_cp0_reg_data_i),
.LLbit_we_o(mem_LLbit_we_o),
.LLbit_value_o(mem_LLbit_value_o),
.cp0_reg_we_o(mem_cp0_reg_we_o),
.cp0_reg_write_addr_o(mem_cp0_reg_write_addr_o),
.cp0_reg_data_o(mem_cp0_reg_data_o),
//送到MEM/WB模块的信息
.wd_o(mem_wd_o),
.wreg_o(mem_wreg_o),
.wdata_o(mem_wdata_o),
.hi_o(mem_hi_o),
.lo_o(mem_lo_o),
.whilo_o(mem_whilo_o),
//送到memory的信息
.mem_addr_o(ram_addr_o),
.mem_we_o(ram_we_o),
.mem_sel_o(ram_sel_o),
.mem_data_o(ram_data_o),
.mem_ce_o(ram_ce_o),
.excepttype_o(mem_excepttype_o),
.cp0_epc_o(latest_epc),
.is_in_delayslot_o(mem_is_in_delayslot_o),
.current_inst_address_o(mem_current_inst_address_o)
);
//MEM/WB模块
mem_wb mem_wb0(
.clk(clk),
.rst(rst),
.stall(stall),
.flush(flush),
//来自访存阶段MEM模块的信息
.mem_wd(mem_wd_o),
.mem_wreg(mem_wreg_o),
.mem_wdata(mem_wdata_o),
.mem_hi(mem_hi_o),
.mem_lo(mem_lo_o),
.mem_whilo(mem_whilo_o),
.mem_LLbit_we(mem_LLbit_we_o),
.mem_LLbit_value(mem_LLbit_value_o),
.mem_cp0_reg_we(mem_cp0_reg_we_o),
.mem_cp0_reg_write_addr(mem_cp0_reg_write_addr_o),
.mem_cp0_reg_data(mem_cp0_reg_data_o),
//送到回写阶段的信息
.wb_wd(wb_wd_i),
.wb_wreg(wb_wreg_i),
.wb_wdata(wb_wdata_i),
.wb_hi(wb_hi_i),
.wb_lo(wb_lo_i),
.wb_whilo(wb_whilo_i),
.wb_LLbit_we(wb_LLbit_we_i),
.wb_LLbit_value(wb_LLbit_value_i),
.wb_cp0_reg_we(wb_cp0_reg_we_i),
.wb_cp0_reg_write_addr(wb_cp0_reg_write_addr_i),
.wb_cp0_reg_data(wb_cp0_reg_data_i)
);
hilo_reg hilo_reg0(
.clk(clk),
.rst(rst),
//写端口
.we(wb_whilo_i),
.hi_i(wb_hi_i),
.lo_i(wb_lo_i),
//读端口1
.hi_o(hi),
.lo_o(lo)
);
ctrl ctrl0(
.rst(rst),
.excepttype_i(mem_excepttype_o),
.cp0_epc_i(latest_epc),
.stallreq_from_id(stallreq_from_id),
//来自执行阶段的暂停请求
.stallreq_from_ex(stallreq_from_ex),
.new_pc(new_pc),
.flush(flush),
.stall(stall)
);
div div0(
.clk(clk),
.rst(rst),
.signed_div_i(signed_div),
.opdata1_i(div_opdata1),
.opdata2_i(div_opdata2),
.start_i(div_start),
.annul_i(flush),
.result_o(div_result),
.ready_o(div_ready)
);
LLbit_reg LLbit_reg0(
.clk(clk),
.rst(rst),
.flush(flush),
//写端口
.LLbit_i(wb_LLbit_value_i),
.we(wb_LLbit_we_i),
//读端口1
.LLbit_o(LLbit_o)
);
cp0_reg cp0_reg0(
.clk(clk),
.rst(rst),
.we_i(wb_cp0_reg_we_i),
.waddr_i(wb_cp0_reg_write_addr_i),
.raddr_i(cp0_raddr_i),
.data_i(wb_cp0_reg_data_i),
.excepttype_i(mem_excepttype_o),
.int_i(int_i),
.current_inst_addr_i(mem_current_inst_address_o),
.is_in_delayslot_i(mem_is_in_delayslot_o),
.data_o(cp0_data_o),
.count_o(cp0_count),
.compare_o(cp0_compare),
.status_o(cp0_status),
.cause_o(cp0_cause),
.epc_o(cp0_epc),
.config_o(cp0_config),
.prid_o(cp0_prid),
.timer_int_o(timer_int_o)
);
endmodule
openmips_min_sopc.v
`include "define.v"
module openmips(
input wire clk,
input wire rst,
input wire[5:0] int_i,
input wire[`RegBus] rom_data_i,
output wire[`RegBus] rom_addr_o,
output wire rom_ce_o,
//连接数据存储器data_ram
input wire[`RegBus] ram_data_i,
output wire[`RegBus] ram_addr_o,
output wire[`RegBus] ram_data_o,
output wire ram_we_o,
output wire[3:0] ram_sel_o,
output wire[3:0] ram_ce_o,
output wire timer_int_o
);
wire[`InstAddrBus] pc;
wire[`InstAddrBus] id_pc_i;
wire[`InstBus] id_inst_i;
//连接译码阶段ID模块的输出与ID/EX模块的输入
wire[`AluOpBus] id_aluop_o;
wire[`AluSelBus] id_alusel_o;
wire[`RegBus] id_reg1_o;
wire[`RegBus] id_reg2_o;
wire id_wreg_o;
wire[`RegAddrBus] id_wd_o;
wire id_is_in_delayslot_o;
wire[`RegBus] id_link_address_o;
wire[`RegBus] id_inst_o;
wire[31:0] id_excepttype_o;
wire[`RegBus] id_current_inst_address_o;
//连接ID/EX模块的输出与执行阶段EX模块的输入
wire[`AluOpBus] ex_aluop_i;
wire[`AluSelBus] ex_alusel_i;
wire[`RegBus] ex_reg1_i;
wire[`RegBus] ex_reg2_i;
wire ex_wreg_i;
wire[`RegAddrBus] ex_wd_i;
wire ex_is_in_delayslot_i;
wire[`RegBus] ex_link_address_i;
wire[`RegBus] ex_inst_i;
wire[31:0] ex_excepttype_i;
wire[`RegBus] ex_current_inst_address_i;
//连接执行阶段EX模块的输出与EX/MEM模块的输入
wire ex_wreg_o;
wire[`RegAddrBus] ex_wd_o;
wire[`RegBus] ex_wdata_o;
wire[`RegBus] ex_hi_o;
wire[`RegBus] ex_lo_o;
wire ex_whilo_o;
wire[`AluOpBus] ex_aluop_o;
wire[`RegBus] ex_mem_addr_o;
wire[`RegBus] ex_reg2_o;
wire ex_cp0_reg_we_o;
wire[4:0] ex_cp0_reg_write_addr_o;
wire[`RegBus] ex_cp0_reg_data_o;
wire[31:0] ex_excepttype_o;
wire[`RegBus] ex_current_inst_address_o;
wire ex_is_in_delayslot_o;
//连接EX/MEM模块的输出与访存阶段MEM模块的输入
wire mem_wreg_i;
wire[`RegAddrBus] mem_wd_i;
wire[`RegBus] mem_wdata_i;
wire[`RegBus] mem_hi_i;
wire[`RegBus] mem_lo_i;
wire mem_whilo_i;
wire[`AluOpBus] mem_aluop_i;
wire[`RegBus] mem_mem_addr_i;
wire[`RegBus] mem_reg2_i;
wire mem_cp0_reg_we_i;
wire[4:0] mem_cp0_reg_write_addr_i;
wire[`RegBus] mem_cp0_reg_data_i;
wire[31:0] mem_excepttype_i;
wire mem_is_in_delayslot_i;
wire[`RegBus] mem_current_inst_address_i;
//连接访存阶段MEM模块的输出与MEM/WB模块的输入
wire mem_wreg_o;
wire[`RegAddrBus] mem_wd_o;
wire[`RegBus] mem_wdata_o;
wire[`RegBus] mem_hi_o;
wire[`RegBus] mem_lo_o;
wire mem_whilo_o;
wire mem_LLbit_value_o;
wire mem_LLbit_we_o;
wire mem_cp0_reg_we_o;
wire[4:0] mem_cp0_reg_write_addr_o;
wire[`RegBus] mem_cp0_reg_data_o;
wire[31:0] mem_excepttype_o;
wire mem_is_in_delayslot_o;
wire[`RegBus] mem_current_inst_address_o;
//连接MEM/WB模块的输出与回写阶段的输入
wire wb_wreg_i;
wire[`RegAddrBus] wb_wd_i;
wire[`RegBus] wb_wdata_i;
wire[`RegBus] wb_hi_i;
wire[`RegBus] wb_lo_i;
wire wb_whilo_i;
wire wb_LLbit_value_i;
wire wb_LLbit_we_i;
wire wb_cp0_reg_we_i;
wire[4:0] wb_cp0_reg_write_addr_i;
wire[`RegBus] wb_cp0_reg_data_i;
wire[31:0] wb_excepttype_i;
wire wb_is_in_delayslot_i;
wire[`RegBus] wb_current_inst_address_i;
//连接译码阶段ID模块与通用寄存器Regfile模块
wire reg1_read;
wire reg2_read;
wire[`RegBus] reg1_data;
wire[`RegBus] reg2_data;
wire[`RegAddrBus] reg1_addr;
wire[`RegAddrBus] reg2_addr;
//连接执行阶段与hilo模块的输出,读取HI、LO寄存器
wire[`RegBus] hi;
wire[`RegBus] lo;
//连接执行阶段与ex_reg模块,用于多周期的MADD、MADDU、MSUB、MSUBU指令
wire[`DoubleRegBus] hilo_temp_o;
wire[1:0] cnt_o;
wire[`DoubleRegBus] hilo_temp_i;
wire[1:0] cnt_i;
wire[`DoubleRegBus] div_result;
wire div_ready;
wire[`RegBus] div_opdata1;
wire[`RegBus] div_opdata2;
wire div_start;
wire div_annul;
wire signed_div;
wire is_in_delayslot_i;
wire is_in_delayslot_o;
wire next_inst_in_delayslot_o;
wire id_branch_flag_o;
wire[`RegBus] branch_target_address;
wire[5:0] stall;
wire stallreq_from_id;
wire stallreq_from_ex;
wire LLbit_o;
wire[`RegBus] cp0_data_o;
wire[4:0] cp0_raddr_i;
wire flush;
wire[`RegBus] new_pc;
wire[`RegBus] cp0_count;
wire[`RegBus] cp0_compare;
wire[`RegBus] cp0_status;
wire[`RegBus] cp0_cause;
wire[`RegBus] cp0_epc;
wire[`RegBus] cp0_config;
wire[`RegBus] cp0_prid;
wire[`RegBus] latest_epc;
//pc_reg例化
pc_reg pc_reg0(
.clk(clk),
.rst(rst),
.stall(stall),
.flush(flush),
.new_pc(new_pc),
.branch_flag_i(id_branch_flag_o),
.branch_target_address_i(branch_target_address),
.pc(pc),
.ce(rom_ce_o)
);
assign rom_addr_o = pc;
//IF/ID模块例化
if_id if_id0(
.clk(clk),
.rst(rst),
.stall(stall),
.flush(flush),
.if_pc(pc),
.if_inst(rom_data_i),
.id_pc(id_pc_i),
.id_inst(id_inst_i)
);
//译码阶段ID模块
id id0(
.rst(rst),
.pc_i(id_pc_i),
.inst_i(id_inst_i),
.ex_aluop_i(ex_aluop_o),
.reg1_data_i(reg1_data),
.reg2_data_i(reg2_data),
//处于执行阶段的指令要写入的目的寄存器信息
.ex_wreg_i(ex_wreg_o),
.ex_wdata_i(ex_wdata_o),
.ex_wd_i(ex_wd_o),
//处于访存阶段的指令要写入的目的寄存器信息
.mem_wreg_i(mem_wreg_o),
.mem_wdata_i(mem_wdata_o),
.mem_wd_i(mem_wd_o),
.is_in_delayslot_i(is_in_delayslot_i),
//送到regfile的信息
.reg1_read_o(reg1_read),
.reg2_read_o(reg2_read),
.reg1_addr_o(reg1_addr),
.reg2_addr_o(reg2_addr),
//送到ID/EX模块的信息
.aluop_o(id_aluop_o),
.alusel_o(id_alusel_o),
.reg1_o(id_reg1_o),
.reg2_o(id_reg2_o),
.wd_o(id_wd_o),
.wreg_o(id_wreg_o),
.excepttype_o(id_excepttype_o),
.inst_o(id_inst_o),
.next_inst_in_delayslot_o(next_inst_in_delayslot_o),
.branch_flag_o(id_branch_flag_o),
.branch_target_address_o(branch_target_address),
.link_addr_o(id_link_address_o),
.is_in_delayslot_o(id_is_in_delayslot_o),
.current_inst_address_o(id_current_inst_address_o),
.stallreq(stallreq_from_id)
);
//通用寄存器Regfile例化
regfile regfile1(
.clk (clk),
.rst (rst),
.we (wb_wreg_i),
.waddr (wb_wd_i),
.wdata (wb_wdata_i),
.re1 (reg1_read),
.raddr1 (reg1_addr),
.rdata1 (reg1_data),
.re2 (reg2_read),
.raddr2 (reg2_addr),
.rdata2 (reg2_data)
);
//ID/EX模块
id_ex id_ex0(
.clk(clk),
.rst(rst),
.stall(stall),
.flush(flush),
//从译码阶段ID模块传递的信息
.id_aluop(id_aluop_o),
.id_alusel(id_alusel_o),
.id_reg1(id_reg1_o),
.id_reg2(id_reg2_o),
.id_wd(id_wd_o),
.id_wreg(id_wreg_o),
.id_link_address(id_link_address_o),
.id_is_in_delayslot(id_is_in_delayslot_o),
.next_inst_in_delayslot_i(next_inst_in_delayslot_o),
.id_inst(id_inst_o),
.id_excepttype(id_excepttype_o),
.id_current_inst_address(id_current_inst_address_o),
//传递到执行阶段EX模块的信息
.ex_aluop(ex_aluop_i),
.ex_alusel(ex_alusel_i),
.ex_reg1(ex_reg1_i),
.ex_reg2(ex_reg2_i),
.ex_wd(ex_wd_i),
.ex_wreg(ex_wreg_i),
.ex_link_address(ex_link_address_i),
.ex_is_in_delayslot(ex_is_in_delayslot_i),
.is_in_delayslot_o(is_in_delayslot_i),
.ex_inst(ex_inst_i),
.ex_excepttype(ex_excepttype_i),
.ex_current_inst_address(ex_current_inst_address_i)
);
//EX模块
ex ex0(
.rst(rst),
//送到执行阶段EX模块的信息
.aluop_i(ex_aluop_i),
.alusel_i(ex_alusel_i),
.reg1_i(ex_reg1_i),
.reg2_i(ex_reg2_i),
.wd_i(ex_wd_i),
.wreg_i(ex_wreg_i),
.hi_i(hi),
.lo_i(lo),
.inst_i(ex_inst_i),
.wb_hi_i(wb_hi_i),
.wb_lo_i(wb_lo_i),
.wb_whilo_i(wb_whilo_i),
.mem_hi_i(mem_hi_o),
.mem_lo_i(mem_lo_o),
.mem_whilo_i(mem_whilo_o),
.hilo_temp_i(hilo_temp_i),
.cnt_i(cnt_i),
.div_result_i(div_result),
.div_ready_i(div_ready),
.link_address_i(ex_link_address_i),
.is_in_delayslot_i(ex_is_in_delayslot_i),
.excepttype_i(ex_excepttype_i),
.current_inst_address_i(ex_current_inst_address_i),
//访存阶段的指令是否要写CP0,用来检测数据相关
.mem_cp0_reg_we(mem_cp0_reg_we_o),
.mem_cp0_reg_write_addr(mem_cp0_reg_write_addr_o),
.mem_cp0_reg_data(mem_cp0_reg_data_o),
//回写阶段的指令是否要写CP0,用来检测数据相关
.wb_cp0_reg_we(wb_cp0_reg_we_i),
.wb_cp0_reg_write_addr(wb_cp0_reg_write_addr_i),
.wb_cp0_reg_data(wb_cp0_reg_data_i),
.cp0_reg_data_i(cp0_data_o),
.cp0_reg_read_addr_o(cp0_raddr_i),
//向下一流水级传递,用于写CP0中的寄存器
.cp0_reg_we_o(ex_cp0_reg_we_o),
.cp0_reg_write_addr_o(ex_cp0_reg_write_addr_o),
.cp0_reg_data_o(ex_cp0_reg_data_o),
//EX模块的输出到EX/MEM模块信息
.wd_o(ex_wd_o),
.wreg_o(ex_wreg_o),
.wdata_o(ex_wdata_o),
.hi_o(ex_hi_o),
.lo_o(ex_lo_o),
.whilo_o(ex_whilo_o),
.hilo_temp_o(hilo_temp_o),
.cnt_o(cnt_o),
.div_opdata1_o(div_opdata1),
.div_opdata2_o(div_opdata2),
.div_start_o(div_start),
.signed_div_o(signed_div),
.aluop_o(ex_aluop_o),
.mem_addr_o(ex_mem_addr_o),
.reg2_o(ex_reg2_o),
.excepttype_o(ex_excepttype_o),
.is_in_delayslot_o(ex_is_in_delayslot_o),
.current_inst_address_o(ex_current_inst_address_o),
.stallreq(stallreq_from_ex)
);
//EX/MEM模块
ex_mem ex_mem0(
.clk(clk),
.rst(rst),
.stall(stall),
.flush(flush),
//来自执行阶段EX模块的信息
.ex_wd(ex_wd_o),
.ex_wreg(ex_wreg_o),
.ex_wdata(ex_wdata_o),
.ex_hi(ex_hi_o),
.ex_lo(ex_lo_o),
.ex_whilo(ex_whilo_o),
.ex_aluop(ex_aluop_o),
.ex_mem_addr(ex_mem_addr_o),
.ex_reg2(ex_reg2_o),
.ex_cp0_reg_we(ex_cp0_reg_we_o),
.ex_cp0_reg_write_addr(ex_cp0_reg_write_addr_o),
.ex_cp0_reg_data(ex_cp0_reg_data_o),
.ex_excepttype(ex_excepttype_o),
.ex_is_in_delayslot(ex_is_in_delayslot_o),
.ex_current_inst_address(ex_current_inst_address_o),
.hilo_i(hilo_temp_o),
.cnt_i(cnt_o),
//送到访存阶段MEM模块的信息
.mem_wd(mem_wd_i),
.mem_wreg(mem_wreg_i),
.mem_wdata(mem_wdata_i),
.mem_hi(mem_hi_i),
.mem_lo(mem_lo_i),
.mem_whilo(mem_whilo_i),
.mem_cp0_reg_we(mem_cp0_reg_we_i),
.mem_cp0_reg_write_addr(mem_cp0_reg_write_addr_i),
.mem_cp0_reg_data(mem_cp0_reg_data_i),
.mem_aluop(mem_aluop_i),
.mem_mem_addr(mem_mem_addr_i),
.mem_reg2(mem_reg2_i),
.mem_excepttype(mem_excepttype_i),
.mem_is_in_delayslot(mem_is_in_delayslot_i),
.mem_current_inst_address(mem_current_inst_address_i),
.hilo_o(hilo_temp_i),
.cnt_o(cnt_i)
);
//MEM模块例化
mem mem0(
.rst(rst),
//来自EX/MEM模块的信息
.wd_i(mem_wd_i),
.wreg_i(mem_wreg_i),
.wdata_i(mem_wdata_i),
.hi_i(mem_hi_i),
.lo_i(mem_lo_i),
.whilo_i(mem_whilo_i),
.aluop_i(mem_aluop_i),
.mem_addr_i(mem_mem_addr_i),
.reg2_i(mem_reg2_i),
//来自memory的信息
.mem_data_i(ram_data_i),
//LLbit_i是LLbit寄存器的值
.LLbit_i(LLbit_o),
//但不一定是最新值,回写阶段可能要写LLbit,所以还要进一步判断
.wb_LLbit_we_i(wb_LLbit_we_i),
.wb_LLbit_value_i(wb_LLbit_value_i),
.cp0_reg_we_i(mem_cp0_reg_we_i),
.cp0_reg_write_addr_i(mem_cp0_reg_write_addr_i),
.cp0_reg_data_i(mem_cp0_reg_data_i),
.excepttype_i(mem_excepttype_i),
.is_in_delayslot_i(mem_is_in_delayslot_i),
.current_inst_address_i(mem_current_inst_address_i),
.cp0_status_i(cp0_status),
.cp0_cause_i(cp0_cause),
.cp0_epc_i(cp0_epc),
//回写阶段的指令是否要写CP0,用来检测数据相关
.wb_cp0_reg_we(wb_cp0_reg_we_i),
.wb_cp0_reg_write_addr(wb_cp0_reg_write_addr_i),
.wb_cp0_reg_data(wb_cp0_reg_data_i),
.LLbit_we_o(mem_LLbit_we_o),
.LLbit_value_o(mem_LLbit_value_o),
.cp0_reg_we_o(mem_cp0_reg_we_o),
.cp0_reg_write_addr_o(mem_cp0_reg_write_addr_o),
.cp0_reg_data_o(mem_cp0_reg_data_o),
//送到MEM/WB模块的信息
.wd_o(mem_wd_o),
.wreg_o(mem_wreg_o),
.wdata_o(mem_wdata_o),
.hi_o(mem_hi_o),
.lo_o(mem_lo_o),
.whilo_o(mem_whilo_o),
//送到memory的信息
.mem_addr_o(ram_addr_o),
.mem_we_o(ram_we_o),
.mem_sel_o(ram_sel_o),
.mem_data_o(ram_data_o),
.mem_ce_o(ram_ce_o),
.excepttype_o(mem_excepttype_o),
.cp0_epc_o(latest_epc),
.is_in_delayslot_o(mem_is_in_delayslot_o),
.current_inst_address_o(mem_current_inst_address_o)
);
//MEM/WB模块
mem_wb mem_wb0(
.clk(clk),
.rst(rst),
.stall(stall),
.flush(flush),
//来自访存阶段MEM模块的信息
.mem_wd(mem_wd_o),
.mem_wreg(mem_wreg_o),
.mem_wdata(mem_wdata_o),
.mem_hi(mem_hi_o),
.mem_lo(mem_lo_o),
.mem_whilo(mem_whilo_o),
.mem_LLbit_we(mem_LLbit_we_o),
.mem_LLbit_value(mem_LLbit_value_o),
.mem_cp0_reg_we(mem_cp0_reg_we_o),
.mem_cp0_reg_write_addr(mem_cp0_reg_write_addr_o),
.mem_cp0_reg_data(mem_cp0_reg_data_o),
//送到回写阶段的信息
.wb_wd(wb_wd_i),
.wb_wreg(wb_wreg_i),
.wb_wdata(wb_wdata_i),
.wb_hi(wb_hi_i),
.wb_lo(wb_lo_i),
.wb_whilo(wb_whilo_i),
.wb_LLbit_we(wb_LLbit_we_i),
.wb_LLbit_value(wb_LLbit_value_i),
.wb_cp0_reg_we(wb_cp0_reg_we_i),
.wb_cp0_reg_write_addr(wb_cp0_reg_write_addr_i),
.wb_cp0_reg_data(wb_cp0_reg_data_i)
);
hilo_reg hilo_reg0(
.clk(clk),
.rst(rst),
//写端口
.we(wb_whilo_i),
.hi_i(wb_hi_i),
.lo_i(wb_lo_i),
//读端口1
.hi_o(hi),
.lo_o(lo)
);
ctrl ctrl0(
.rst(rst),
.excepttype_i(mem_excepttype_o),
.cp0_epc_i(latest_epc),
.stallreq_from_id(stallreq_from_id),
//来自执行阶段的暂停请求
.stallreq_from_ex(stallreq_from_ex),
.new_pc(new_pc),
.flush(flush),
.stall(stall)
);
div div0(
.clk(clk),
.rst(rst),
.signed_div_i(signed_div),
.opdata1_i(div_opdata1),
.opdata2_i(div_opdata2),
.start_i(div_start),
.annul_i(flush),
.result_o(div_result),
.ready_o(div_ready)
);
LLbit_reg LLbit_reg0(
.clk(clk),
.rst(rst),
.flush(flush),
//写端口
.LLbit_i(wb_LLbit_value_i),
.we(wb_LLbit_we_i),
//读端口1
.LLbit_o(LLbit_o)
);
cp0_reg cp0_reg0(
.clk(clk),
.rst(rst),
.we_i(wb_cp0_reg_we_i),
.waddr_i(wb_cp0_reg_write_addr_i),
.raddr_i(cp0_raddr_i),
.data_i(wb_cp0_reg_data_i),
.excepttype_i(mem_excepttype_o),
.int_i(int_i),
.current_inst_addr_i(mem_current_inst_address_o),
.is_in_delayslot_i(mem_is_in_delayslot_o),
.data_o(cp0_data_o),
.count_o(cp0_count),
.compare_o(cp0_compare),
.status_o(cp0_status),
.cause_o(cp0_cause),
.epc_o(cp0_epc),
.config_o(cp0_config),
.prid_o(cp0_prid),
.timer_int_o(timer_int_o)
);
endmodule
opemmips_min_sopc_tb.v
`include "define.v"
//·*//建立TestBench文件
//时间单位是1ns,精度是1ps
`timescale 1ns/1ps
module openmips_min_sopc_tb();
reg CLOCK_50;
reg rst;
//每隔10ns,CLOCK_50信号翻转一次,所以下一个时钟周期是20ns,对应50MHz
initial begin
CLOCK_50 = 1'b0;
forever #10 CLOCK_50 = ~CLOCK_50;
end
//最初时刻,复位信号有效,在第195ns复位信号无效 最小SOPC开始运行
//运行1000ns后,暂停仿真
initial begin
rst = `RstEnable;
#195 rst = `RstDisable;
#1000 $stop;
end
//例化最小SOPC
openmips_min_sopc openmips_min_sopc0(
.clk(CLOCK_50),
.rst(rst)
);
endmodule
测试文件和结果
测试文件分为3个,分别对系统调用异常
,自陷异常
,时钟和中断
进行测试,结果就是看各个寄存器的值是否和指令中的相符。测试文件和结果就不放出来了。
完结撒花