1.实现的六种异常介绍
MIPS32有不同的异常类型及其优先级,OpenMIPS只实现了六种异常情况的处理:
●硬件复位(复位后所有信号清零)
●中断(软件中断,硬件中断)
●syscall系统调用(在用户模式下执行内核模式下的某些操作)
●无效指令(OpenMIPS未定义的指令)
●整数溢出(算术操作指令add,addi,sub运算溢出)
●自陷指令(不是很理解他的作用)
2.解决异常方法:精确异常
①精确异常:异常发生时,处理器转移到异常处理例程,异常处理结束后返回原程序继续执行,不破坏原程序的正常执行。且异常发生时,会记住流水线未执行完的指令。
异常发生时,会产生发生异常的指令,该指令前所有的指令都正常执行到流水线的最后一个阶段,该指令之后的指令信号都被清除。
②潜在问题:异常发生顺序与指令顺序不一定相同
例如
加载指令lw发生地址未对齐异常(访存阶段检测到),下一条指令发生无效异常(译码阶段检测到)。这样,指令顺序是先加载再无效,而异常发生顺序却是先无效再加载。
③解决方法:发生异常时,先将异常事件标记,在访存(因为发生异常的情况在译码执行保存段都有可能发生,可能还有别的原因吧)阶段专门处理异常(异常指令之后的清除信号,异常指令之前的正常执行)。
3.要添加的异常指令
①自陷指令
不含立即数的自陷指令:
teq rs,rt ifGPR[rs]=GPR[rt] then trap
tge rs,rt ifGPR[rs]≥GPR[rt] then trap有符号比较
tgeu rs,rt ifGPR[rs]≥GPR[rt] then trap无符号比较
tlt rs,rt ifGPR[rs]<GPR[rt] then trap有符号比较
tltu rs,rt ifGPR[rs]<GPR[rt] then trap无符号比较
tne rs,rt ifGPR[rs]≠GPR[rt] then trap
含立即数的自陷指令:
teqi rs,immediate ifGPR[rs]=sign_extended(immediate)then trap
tgei rs,immediate ifGPR[rs]≥sign_extended(immediate)then trap有符号比较
tgeiu rs,immediate ifGPR[rs]≥sign_extended(immediate)then trap无符号比较
tlti rs,immediate ifGPR[rs]<sign_extended(immediate)then trap有符号比较
tltiu rs,immediate ifGPR[rs]<sign_extended(immediate)then trap无符号比较
tnei rs,immediate ifGPR[rs]≠sign_extended(immediate)then trap
②系统调用指令
使用户模式下可以执行内核模式的操作,OpenMIPS不区分用户模式,内核模式,但为了兼容MIPS32指令集架构,还是实现
③异常返回指令
在处理完异常后执行该指令。使epc寄存器的值成为新的取指地址,好继续执行原程序。同时设置cp0.status[1]为0,表示不再处于异常级。
4.异常处理过程
[1]译码阶段判断是否是系统调用指令、异常返回指令、无效指令,将这些信息通过excepttype_o传递到执行阶段,同时指令地址通过current_inst_addr_o传递到执行阶段。
异常类型excepttype_o={19'b0,excepttype_is_eret,ovassert,trapassert,instvaild,excepttype_is_syscall,8'b0}
异常指令地址current_inst_addr_o:异常处理完成后需不影响原来程序执行,所以需要记住异常指定地址,在异常完成后继续这个地址的指令,所以最终回到PC模块。如果是延迟槽指令,应是这条指令的前一条指令地址。
[2]执行判断是否为自陷异常,溢出异常,这些信息融合到译码阶段的excepttype传递至访存阶段,current_inst_addr也一同传递。同时判断出是否会延迟槽指令,通过is_in_delayslot传递。
[3]访存阶段会接收excepttype、cause寄存器最新值、status寄存器最新值,epc寄存器最新值,综合判断是否需要处理异常。当然is_in_delayslot和current_inst_addr也会继续传递。
[4]如果需要处理异常,既要Cp0修改寄存器信息,又要清除流水线上除回写阶段外所有寄存器的值。cp0修改过程为
EXL为cp0.status[1]表是否处于异常级,处于异常时处理器会进入内核模式下工作,并且禁止中断。
上图中的“转移到相应的异常处理历程入口地址”,由control模块输出至PC模块完成。异常处理历程入口就是处理异常这个过程的入口,从这个地址进入就开始处理异常,这个地址是定义的,在完成这个异常处理后就返回异常,按原来指定地址进行。
再次强调,如果异常指令处延迟槽中,那么异常处理后重新执行的指令地址为延迟槽指令的前一个地址。
除回写阶段的流水线信号清除工作由Control模块发出flush信号控制完成。
5.数据流图
6.代码
defines
//全局
`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 InterruptAssert 1'b1
`define InterruptNotAssert 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 //只读
pc模块
`include "defines.v"
`timescale 1ns/1ps
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 (ce == `ChipDisable) begin //复位清零
pc <= 32'h00000000;
end else if(flush == 1'b1) begin //else与if间添加begin,最后加end
pc <= new_pc; //异常时进入异常处理例程
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 (rst == `RstEnable) begin
ce <= `ChipDisable; //模块禁用
end else begin
ce <= `ChipEnable; //模块可用
end
end
endmodule
//PC:复位清零;
// 是否清除信号
// 流水线不暂停|判断是转移指令,读转移指令地址。否,读下一条指令
// |正常读下一条指令
if/id模块
`include "defines.v"
`timescale 1ns/1ps
module if_id(
input wire clk,
input wire rst,
//来自控制模块的信息
input wire[5:0] stall, //流水线暂停
input wire flush, //清除信号
input wire[`InstAddrBus] if_pc,
input wire[`InstBus] if_inst,
output reg[`InstAddrBus] id_pc,
output reg[`InstBus] 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 <= `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
id模块
`include "defines.v"
`timescale 1ns/1ps
module id(
input wire rst,
input wire[`InstAddrBus] pc_i,
input wire[`InstBus] inst_i,
//来自regfile模块的读取数据
input wire[`RegBus] reg1_data_i,
input wire[`RegBus] reg2_data_i,
//处于执行阶段的指令要写入的目的寄存器信息
input wire ex_wreg_i, //数据前推,解决数据相关
input wire[`RegBus] ex_wdata_i,
input wire[`RegAddrBus] ex_wd_i,
//处于访存阶段的指令要写入的目的寄存器信息
input wire mem_wreg_i,
input wire[`RegBus] mem_wdata_i,
input wire[`RegAddrBus] mem_wd_i,
//来自EX阶段的前一指令的子运算类型
input wire[`AluOpBus] ex_aluop_i, //判断load相关
//如果上一条指令是转移指令,那么下一条指令在译码的时候is_in_delayslot为true
input wire is_in_delayslot_i, //来于ID/EX
//送到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, //操作数1(rs)地址
output reg[`RegBus] reg2_o,
output reg[`RegAddrBus] wd_o, //要写入的地址
output reg wreg_o,
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 stallreq, //流水线暂停请求
output wire[`RegBus] inst_o, //指令地址传入EX,EX执行段读offset值计算加载存储地址
output wire[31:0] excepttype_o, //异常信息(是否返回异常eret,是否无效指令,是否系统调用,是否中断)
output wire[`RegBus] current_inst_address_o //当前指令地址 EPC存储异常地址
);
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];//rt
reg[`RegBus] imm;
reg instvalid;
reg stallreq_for_reg1_loadrelate; //读取的第一个寄存器与上条指令load相关
reg stallreq_for_reg2_loadrelate; //读取的第二个寄存器与上条指令load相关
wire pre_inst_is_load; //前一指令是否为加载指令
//跳转指令
wire[`RegBus] pc_plus_8; //指令后面第二条指令地址
wire[`RegBus] pc_plus_4; //指令后面第一条指令地址
wire[`RegBus] imm_sll2_signedext;
reg excepttype_is_syscall;
reg excepttype_is_eret;
assign pc_plus_8 = pc_i + 8;
assign pc_plus_4 = pc_i +4;
assign imm_sll2_signedext = {{14{inst_i[15]}}, inst_i[15:0], 2'b00 }; //offset左移2位并做符号扩展
//加载存储指令
assign inst_o = inst_i; //指令传递,读offset值算存储加载地址
assign stallreq = stallreq_for_reg1_loadrelate | stallreq_for_reg2_loadrelate; //load相关,流水线暂停请求
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_OP)||
(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; //前一指令为加载指令
//异常信息设定
assign excepttype_o = {19'b0,excepttype_is_eret,2'b0,instvalid,excepttype_is_syscall,8'b0};//异常信息(是否返回异常eret,是否无效指令,是否系统调用,是否中断)
assign current_inst_address_o = pc_i;
always @ (*) begin
if (rst == `RstEnable) begin
aluop_o <= `EXE_NOP_OP; //复位清零
alusel_o <= `EXE_RES_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;
excepttype_is_syscall <= `False_v;
excepttype_is_eret <= `False_v;
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;
case (op)
`EXE_SPECIAL_INST: begin
case (op2)
5'b00000: begin
case (op3)
`EXE_OR: begin //或 rd<-rs OR rt
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 //与 rd<-rs AND rt
wreg_o <= `WriteEnable;
aluop_o <= `EXE_AND_OP;
alusel_o <= `EXE_RES_LOGIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_XOR: begin //异或 rd<-rs XOR rt
wreg_o <= `WriteEnable;
aluop_o <= `EXE_XOR_OP;
alusel_o <= `EXE_RES_LOGIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_NOR: begin //或非 rd<-rs NOR rt
wreg_o <= `WriteEnable;
aluop_o <= `EXE_NOR_OP;
alusel_o <= `EXE_RES_LOGIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SLLV: begin //逻辑左移 rd<-rt<<rs[4:0](logic)
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 //逻辑右移 rd<-rt>>rs[4:0](logic)
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SRL_OP;
alusel_o <= `EXE_RES_SHIFT;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SRAV: begin //算术右移 rd<-rt>>rs[4:0](arithmetic)
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SRA_OP;
alusel_o <= `EXE_RES_SHIFT;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MFHI: begin //移动 rd<-hi
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 //移动 rd<-lo
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 <= `WriteDisable; //写HI寄存器,非通用寄存器.写无效
aluop_o <= `EXE_MTHI_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MTLO: begin //移动 lo<-rs
wreg_o <= `WriteDisable;
aluop_o <= `EXE_MTLO_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MOVN: begin //移动 if rt≠0 then rd<-rs
aluop_o <= `EXE_MOVN_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_MOVZ: begin //移动 if rt=0 then rd<-rs
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 //算术 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 //算术 rd<-(rs<rt) 无符号比较
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 //算术 rd<-rs+rt 溢出保存
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 //算术 rd<-rs-rt 溢出不保存
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 //算术 rd<-rs-rt 溢出保存
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 //算术 {hi,lo}<-rs×rd 有符号乘
wreg_o <= `WriteDisable;
aluop_o <= `EXE_MULT_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MULTU: begin //算术 {hi,lo}<-rs×rd 无符号乘
wreg_o <= `WriteDisable;
aluop_o <= `EXE_MULTU_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_DIV: begin //算术 {HI,LO}<-rs/rt 有符号除
wreg_o <= `WriteDisable;
aluop_o <= `EXE_DIV_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_DIVU: begin //算术 {HI,LO}<-rs/rt 无符号除
wreg_o <= `WriteDisable;
aluop_o <= `EXE_DIVU_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_JR: begin //转移 pc<-rs
wreg_o <= `WriteDisable;
aluop_o <= `EXE_JR_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
link_addr_o <= `ZeroWord; //不返回地址
branch_target_address_o <= reg1_o; //rs的值为要转移的地址
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot; //下一指令为延迟槽指令
instvalid <= `InstValid;
end
`EXE_JALR: begin //转移 rd<-return_address,pc<-rs
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
default: begin
end
endcase
end
default: begin
end
endcase
case (op3)
`EXE_TEQ: begin //不含立即数的自陷指令,if GPR[rs]=GPR[rt]then trap
wreg_o <= `WriteDisable;//不写通用寄存器
aluop_o <= `EXE_TEQ_OP;
alusel_o <= `EXE_RES_NOP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_TGE: begin //不含立即数的自陷指令,if GPR[rs]≥GPR[rt]then trap,有符号比较
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 //不含立即数的自陷指令,if GPR[rs]≥GPR[rt]then trap,无符号比较
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 //不含立即数的自陷指令,if GPR[rs]<GPR[rt]then trap,有符号比较
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 //不含立即数的自陷指令,if GPR[rs]<GPR[rt]then trap,无符号比较
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 //不含立即数的自陷指令,if GPR[rs]≠GPR[rt]then trap
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 //系统自陷
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 //end special_inst
`EXE_ORI: begin //ORI指令 逻辑或 rt<-rs OR zero_extended(immediate)
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]};
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_ANDI: begin //逻辑与 rt<-rs AND zero_extended(immediate)
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]}; //源操作数2与默认rt无关.源操作数2经计算赋给立即数
wd_o <= inst_i[20:16]; //写的是rt非默认
instvalid <= `InstValid;
end
`EXE_XORI: begin //逻辑异或 rt<-rs XOR zero_extended(immediate)
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 //逻辑 rt<-immediate || 0^16
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_SLTI: begin //算术 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 //算术 rt<-(rs<(sign_extended)immediate) 无符号比较
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 //算术 rt<-rs+((sign_extended)immediate) 溢出不保存
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 //算术 rt<-rs+((sign_extended)immediate) 溢出保存
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_J: begin //转移 pc<-(pc+4)[31,28]||target||'00'
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_target_address_o <= {pc_plus_4[31:28], inst_i[25:0], 2'b00};
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
instvalid <= `InstValid;
end
`EXE_JAL: begin //转移 pc<-(pc+4)[31,28]||target||'00',后面第二条指令地址作返回地址存入$31
wreg_o <= `WriteEnable; //返回地址存入通用寄存器31,写使能
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; //存入$31寄存器,地址为5’b11111。非默认地址,此处修改写地址
link_addr_o <= pc_plus_8 ;
branch_target_address_o <= {pc_plus_4[31:28], inst_i[25:0], 2'b00};
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
instvalid <= `InstValid;
end
`EXE_BEQ: begin //转移 if rs=rt then branch
wreg_o <= `WriteDisable;
aluop_o <= `EXE_BEQ_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_BGTZ: begin //转移 if rs>0 then branch
wreg_o <= `WriteDisable;
aluop_o <= `EXE_BGTZ_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) && (reg1_o != `ZeroWord)) begin //注意不能为0
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 //转移 if rs≤0 then branch
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 //转移 if rs≠rt then branch
wreg_o <= `WriteDisable;
aluop_o <= `EXE_BLEZ_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_BGEZ: begin //转移 if rs≥0 then branch
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
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 //转移 if rs≥0 then branch 后面第二条指令地址作返回地址保存到$31寄存器
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
`EXE_BLTZ: begin //转移 if rs<0 then branch
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_BLTZAL: begin //转移 if rs<0 then branch 后面第二条指令地址作返回地址保存到$31寄存器
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
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_TEQI: begin //含立即数的自陷指令,if GPR[rs]=sign_extended(immediate)then trap
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 //含立即数的自陷指令,if GPR[rs]≥sign_extended(immediate)then trap,有符号比较
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 //含立即数的自陷指令,if GPR[rs]≥sign_extended(immediate)then trap,无符号比较
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 //含立即数的自陷指令,if GPR[rs]<sign_extended(immediate)then trap,有符号比较
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 //含立即数的自陷指令,if GPR[rs]<sign_extended(immediate)then trap,无符号比较
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 //含立即数的自陷指令,if GPR[rs]≠sign_extended(immediate)then trap
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
end
`EXE_SPECIAL2_INST: begin
case ( op3 )
`EXE_CLZ: begin //算术 rd<-coun_leading_zeros rs
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 //算术 rd<-coun_leading_ones rs
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 //算术 rd<-rs×rt 有符号乘
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 //算术 {HI,LO}<-{HI,LO}+rs×rt 有符号乘累加
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 //算术 {HI,LO}<-{HI,LO}+rs×rt 无符号乘累加
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 //算术 {HI,LO}<-{HI,LO}-rs×rt 有符号乘累减
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 //算术 {HI,LO}<-{HI,LO}-rs×rt 无符号乘累减
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
`EXE_LB: begin //加载
wreg_o <= `WriteEnable; //加载结果写入rt通用寄存器
aluop_o <= `EXE_LB_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1; //base值
reg2_read_o <= 1'b0; //符号扩展32位写入rt
wd_o <= inst_i[20:16]; //写入rt寄存器
instvalid <= `InstValid;
end
`EXE_LBU: begin
wreg_o <= `WriteEnable; //加载结果写入rt通用寄存器
aluop_o <= `EXE_LBU_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1; //base值
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16]; //写入rt寄存器
instvalid <= `InstValid;
end
`EXE_LH: begin
wreg_o <= `WriteEnable; //加载结果写入rt通用寄存器
aluop_o <= `EXE_LH_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1; //base值
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16]; //写入rt寄存器
instvalid <= `InstValid;
end
`EXE_LHU: begin
wreg_o <= `WriteEnable; //加载结果写入rt通用寄存器
aluop_o <= `EXE_LHU_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1; //base值
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16]; //写入rt寄存器
instvalid <= `InstValid;
end
`EXE_LW: begin
wreg_o <= `WriteEnable; //加载结果写入rt通用寄存器
aluop_o <= `EXE_LW_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1; //base值
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16]; //写入rt寄存器
instvalid <= `InstValid;
end
`EXE_LWL: begin
wreg_o <= `WriteEnable; //加载结果写入rt通用寄存器
aluop_o <= `EXE_LWL_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1; //base值
reg2_read_o <= 1'b1; //rt部分值被修改,需要读rt值
wd_o <= inst_i[20:16]; //写入rt寄存器
instvalid <= `InstValid;
end
`EXE_LWR: begin
wreg_o <= `WriteEnable; //加载结果写入rt通用寄存器
aluop_o <= `EXE_LWR_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1; //base值
reg2_read_o <= 1'b1; //rt部分值被修改,需要读rt值
wd_o <= inst_i[20:16]; //写入rt寄存器
instvalid <= `InstValid;
end
`EXE_SB: begin
wreg_o <= `WriteDisable; //存储,不写通用寄存器
aluop_o <= `EXE_SB_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1; //base值
reg2_read_o <= 1'b1; //存储rt部分值
instvalid <= `InstValid;
end
`EXE_SH: begin
wreg_o <= `WriteDisable; //存储,不写通用寄存器
aluop_o <= `EXE_SH_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1; //base值
reg2_read_o <= 1'b1; //存储rt部分值
instvalid <= `InstValid;
end
`EXE_SW: begin
wreg_o <= `WriteDisable; //存储,不写通用寄存器
aluop_o <= `EXE_SW_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1; //base值
reg2_read_o <= 1'b1; //存储rt值
instvalid <= `InstValid;
end
`EXE_SWL: begin
wreg_o <= `WriteDisable; //存储,不写通用寄存器
aluop_o <= `EXE_SWL_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1; //base值
reg2_read_o <= 1'b1; //存储rt部分值
instvalid <= `InstValid;
end
`EXE_SWR: begin
wreg_o <= `WriteDisable; //存储,不写通用寄存器
aluop_o <= `EXE_SWR_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1; //base值
reg2_read_o <= 1'b1; //存储rt部分值
instvalid <= `InstValid;
end
`EXE_LL: begin
wreg_o <= `WriteEnable;//写rt
aluop_o <= `EXE_LL_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1; //base值
reg2_read_o <= 1'b0; //rt值全改写,无需读
wd_o <= inst_i[20:16]; //写地址为rt通用寄存器
instvalid <= `InstValid;
end
`EXE_SC: begin
wreg_o <= `WriteEnable;//写rt
aluop_o <= `EXE_SC_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1; //base值
reg2_read_o <= 1'b1; //改写rt值。存储成功rt置1,失败置0
wd_o <= inst_i[20:16]; //写地址为rt通用寄存器
instvalid <= `InstValid;
end
default: begin
end
endcase //case op
if (inst_i[31:21] == 11'b00000000000) begin
if (op3 == `EXE_SLL) begin //逻辑左移 rd<-rt<<sa(logic)
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SLL_OP;
alusel_o <= `EXE_RES_SHIFT;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b1; //rt
imm[4:0] <= inst_i[10:6]; //sa 移位数
wd_o <= inst_i[15:11]; //rd
instvalid <= `InstValid;
end
else if ( op3 == `EXE_SRL ) begin //逻辑右移 rd<-rt>>sa(logic)
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 //算术右移 rd<-rt>>sa(arithmetic)
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 //else
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 else if(inst_i[31:21] == 11'b01000000000 && inst_i[10:0] == 11'b00000000000) begin //协处理器访问mfc0 GPR[rt]<-CPR[0,rd] 读数
aluop_o <= `EXE_MFC0_OP;
alusel_o <= `EXE_RES_MOVE;
wd_o <= inst_i[20:16];//rt
wreg_o <= `WriteEnable;
instvalid <= `InstValid;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
end else if(inst_i[31:21] == 11'b01000000100 && inst_i[10:0] == 11'b00000000000) begin //协处理器访问mtc0 CPR[0,rd]<-GPR[rt] 改数
aluop_o <= `EXE_MTC0_OP;
alusel_o <= `EXE_RES_NOP;
wreg_o <= `WriteDisable;
instvalid <= `InstValid;
reg1_read_o <= 1'b1;
reg1_addr_o <= inst_i[20:16];//rt
reg2_read_o <= 1'b0;
end
end //always
end
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; //前一指令为加载指令,第一个读取的寄存器值为前一加载指令加载值
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; //立即数有值即利用,无值默认0
end else begin
reg1_o <= `ZeroWord;
end
end //always
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;
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
always @ (*) begin
if(rst == `RstEnable) begin
is_in_delayslot_o <= `NotInDelaySlot;
end else begin
is_in_delayslot_o <= is_in_delayslot_i; //延迟指令传递
end
end
endmodule
//指令是否返回异常,是否有效,是否系统调用,是否中断->异常信息
//译出运算类型及其子类型
//是否读,读的地址 (确保读到准确数,解决数据相关)
//是否写通用寄存器/保存转移指令返回地址/写加载地址,写的地址
//是否转移指令|译出转移地址
// |设定下一指令为延迟槽指令next_inst_in_delayslot、当前是否为延迟槽指令is_in_delayslot_o
// |译出要保存到通用寄存器的返回地址,无设为0,有写使能
//判断前一指令与当前指令是否存在load相关
//异常信息判断设定
id/ex
`include "defines.v"
`timescale 1ns/1ps
module id_ex(
input wire clk,
input wire rst,
//来自控制模块的信息
input wire[5:0] stall, //流水线暂停
input wire flush, //信号清除
//从译码阶段传递的信息
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[`RegBus] id_link_address,
input wire id_is_in_delayslot,
input wire next_inst_in_delayslot_i,
input wire[`RegBus] id_inst, //传递至EX,读offset值
input wire[31:0] id_excepttype,
input wire[`RegBus] id_current_inst_address,
//传递到执行阶段的信息
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,读offset
output reg[31:0] ex_excepttype,
output reg[`RegBus] ex_current_inst_address
);
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;
is_in_delayslot_o <= `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;
ex_current_inst_address <= `ZeroWord;
is_in_delayslot_o <= `NotInDelaySlot;
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;
is_in_delayslot_o <= next_inst_in_delayslot_i;
ex_inst <= id_inst;
ex_excepttype <= id_excepttype;
ex_current_inst_address <= id_current_inst_address;
end
end
endmodule
ex
`include "defines.v"
`timescale 1ns/1ps
module ex(
input wire rst,
//ID模块送到执行阶段的信息
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[31:0] excepttype_i,
input wire[`RegBus] current_inst_address_i,
//HI、LO、CP0寄存器送入的值
input wire[`RegBus] hi_i, //移动操作指令,读取HI,LO值
input wire[`RegBus] lo_i,
//CP0寄存器送入的值
input wire[`RegBus] cp0_reg_data_i,
//回写阶段的指令是否要写HI、LO,用于检测HI、LO的数据相关;要改写HI、LO值,将改写后的准确值读入
input wire[`RegBus] wb_hi_i,
input wire[`RegBus] wb_lo_i,
input wire wb_whilo_i,
//回写阶段的指令是否要写cp0中寄存器,避免数据相关
input wire wb_cp0_reg_we,
input wire[4:0] wb_cp0_reg_write_addr,
input wire[`RegBus] wb_cp0_reg_data,
//访存阶段的指令是否要写HI、LO,用于检测HI、LO的数据相关
input wire[`RegBus] mem_hi_i,
input wire[`RegBus] mem_lo_i,
input wire mem_whilo_i,
//访存阶段的指令是否要写cp0中寄存器,避免数据相关
input wire mem_cp0_reg_we,
input wire[4:0] mem_cp0_reg_write_addr,
input wire[`RegBus] mem_cp0_reg_data,
input wire[`DoubleRegBus] hilo_temp_i,//从EX/MEM得到第一个执行周期的乘法结果
input wire[1:0] cnt_i, //当前处于第几个周期
//与除法模块相连
input wire[`DoubleRegBus] div_result_i, //除法运算结果
input wire div_ready_i, //除法运算是否结束(开始)
//是否转移、以及link address
input wire[`RegBus] link_address_i, //保存返回地址
input wire is_in_delayslot_i,
//存储加载指令地址接收。读offset
input wire[`RegBus] inst_i,
//送入MEM
output reg[`RegAddrBus] wd_o,
output reg wreg_o,
output reg[`RegBus] wdata_o,
output reg[`RegBus] hi_o, //改写HI,LO值
output reg[`RegBus] lo_o,
output reg whilo_o,
output reg cp0_reg_we_o,//写cp0
output reg[4:0] cp0_reg_write_addr_o,
output reg[`RegBus] cp0_reg_data_o,
output reg[`DoubleRegBus] hilo_temp_o, //将第一个执行周期的乘法结果送EX/MEM
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 wire[`AluOpBus] aluop_o, //送入MEM,MEM据子运算类型看加载/存储作执行操作
output wire[`RegBus] mem_addr_o,//加载存储地址
output wire[`RegBus] reg2_o, //部分存储指令改写部分rt值,rt不改写值读取保留
output wire[31:0] excepttype_o, //异常信息
output wire is_in_delayslot_o,
output wire[`RegBus] current_inst_address_o,
//送入CP0 /要读的cp0中某寄存器地址(与18行应)
output reg[4:0] cp0_reg_read_addr_o,
output reg stallreq //是否请求暂停流水线
);
reg[`RegBus] logicout;
reg[`RegBus] shiftres;
reg[`RegBus] moveres;
reg[`RegBus] arithmeticres;
reg[`DoubleRegBus] mulres; //第一次乘结果,且作符号调整。第一个时钟周期后给EX/MEM
reg[`RegBus] HI;
reg[`RegBus] LO;
//算术指令
wire[`RegBus] reg2_i_mux; //操作数2的补码
wire[`RegBus] reg1_i_not; //操作数1取反
wire[`RegBus] result_sum; //加法结果
wire ov_sum; //溢出情况
wire reg1_eq_reg2; //操作数1是否 = 操作数2
wire reg1_lt_reg2; //操作数1是否 < 操作数2
wire[`RegBus] opdata1_mult; //被乘数
wire[`RegBus] opdata2_mult; //乘数
wire[`DoubleRegBus] hilo_temp; //第一次乘结果,未作符号调整
reg[`DoubleRegBus] hilo_temp1; //最终乘累加、累减结果。第二个时钟周期可给EX/MEM
reg stallreq_for_madd_msub;
reg stallreq_for_div;
reg trapassert; //是否自陷异常
reg ovassert; //是否溢出异常
//加载存储指令
assign aluop_o = aluop_i; //运算子类型正常传递至MEM
assign mem_addr_o = reg1_i + {{16{inst_i[15]}},inst_i[15:0]}; //加载存储地址=offset符号扩展至32位与base加
assign reg2_o = reg2_i; //部分存储指令改写部分rt值,rt不改写值读取保留。送至访存段,访存RAM
//异常信息译码阶段异常信息添加(是否返回异常eret,是否溢出,是否自陷,是否无效指令,是否系统调用,是否中断)
assign excepttype_o = {excepttype_i[31:12],ovassert,trapassert,excepttype_i[9:8],8'h00};
assign is_in_delayslot_o = is_in_delayslot_i;
assign current_inst_address_o = current_inst_address_i;
always @ (*) begin
if(rst == `RstEnable) begin
logicout <= `ZeroWord; //逻辑
end else begin
case (aluop_i)
`EXE_OR_OP: begin
logicout <= reg1_i | reg2_i;
end
`EXE_AND_OP: begin
logicout <= reg1_i & reg2_i;
end
`EXE_NOR_OP: begin
logicout <= ~(reg1_i |reg2_i);
end
`EXE_XOR_OP: begin
logicout <= reg1_i ^ reg2_i;
end
default: begin
logicout <= `ZeroWord;
end
endcase
end //if
end //always
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
shiftres <= ({32{reg2_i[31]}} << (6'd32-{1'b0, reg1_i[4:0]})) | reg2_i >> reg1_i[4:0];//这步很妙
end
default: begin
shiftres <= `ZeroWord;
end
endcase
end //if
end //always
//减法 或 有符号比较运算 或 有符号自陷,对源操作数2取补码,否则源操作数2不变
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_TGEI_OP)) ? (~reg2_i)+1 : reg2_i;
assign result_sum = reg1_i + reg2_i_mux;//算和。加 减 有符号比较 有符号自陷适用
assign ov_sum = ((!reg1_i[31] && !reg2_i_mux[31]) && result_sum[31]) ||((reg1_i[31] && reg2_i_mux[31]) && (!result_sum[31])); //溢出情况
//比较指令,自陷指令 操作数比较结果
assign reg1_lt_reg2 = ((aluop_i == `EXE_SLT_OP)
|| (aluop_i == `EXE_TLT_OP) || (aluop_i == `EXE_TLTI_OP) || (aluop_i == `EXE_TGE_OP) || (aluop_i == `EXE_TGEI_OP))?((reg1_i[31] && !reg2_i[31])||(!reg1_i[31] && !reg2_i[31] && result_sum[31])||(reg1_i[31] && reg2_i[31] && result_sum[31])):(reg1_i < reg2_i); //比较运算情况
assign reg1_i_not = ~reg1_i;//源操作数1取反
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_ADDIU_OP,`EXE_SUB_OP, `EXE_SUBU_OP: begin //加减
arithmeticres <= result_sum;
end
`EXE_ADDI_OP: begin
arithmeticres <= result_sum;
end
`EXE_CLZ_OP: begin //计0
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] ? 30 : reg1_i[0] ? 31 : 32 ;
end //从左向右依次找0
`EXE_CLO_OP: begin //计数1
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 //从左向右依次找1
default: begin
arithmeticres <= `ZeroWord;
end
endcase
end
end
//取得乘法操作的操作数,如果是有符号除法且操作数是负数,那么取反加一
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;
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;
assign hilo_temp = opdata1_mult * opdata2_mult;
always @ (*) begin //乘
if(rst == `RstEnable) begin
mulres <= {`ZeroWord,`ZeroWord};
end else if ((aluop_i == `EXE_MULT_OP) || (aluop_i == `EXE_MUL_OP) ||(aluop_i == `EXE_MADD_OP) || (aluop_i == `EXE_MSUB_OP))begin
if(reg1_i[31] ^ reg2_i[31] == 1'b1) begin
mulres <= ~hilo_temp + 1; //有符号乘,结果为负取补码,正数补码是本身
end else begin
mulres <= hilo_temp; //无符号乘,直接做结果
end
end else begin
mulres <= hilo_temp;
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};
end else if(wb_whilo_i == `WriteEnable) begin
{HI,LO} <= {wb_hi_i,wb_lo_i};
end else begin
{HI,LO} <= {hi_i,lo_i};
end
end
always @ (*) begin //乘累加乘累减除法的流水线暂停请求
stallreq = stallreq_for_madd_msub || stallreq_for_div;
end
//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 //第一个时钟周期,给出乘法结果,设定下一进行下一时钟周期,流水线暂停,结果为0
hilo_temp_o <= mulres;
cnt_o <= 2'b01;
stallreq_for_madd_msub <= `Stop;
hilo_temp1 <= {`ZeroWord,`ZeroWord};
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
`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、DIVU指令
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;//除法开始,div模块工作
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
//MFHI、MFLO、MOVN、MOVZ移动指令
always @ (*) begin //移动指令
if(rst == `RstEnable) begin
moveres <= `ZeroWord;
end else begin
moveres <= `ZeroWord;
case (aluop_i)
`EXE_MFHI_OP: begin
moveres <= HI;
end
`EXE_MFLO_OP: begin
moveres <= LO;
end
`EXE_MOVZ_OP: begin
moveres <= reg1_i;
end
`EXE_MOVN_OP: begin
moveres <= reg1_i;
end
`EXE_MFC0_OP: begin
cp0_reg_read_addr_o <= inst_i[15:11]; //读CPR[0,rd]
moveres <= cp0_reg_data_i;
//访存段、回写段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 //else
end //always
always @ (*) begin //自陷指令
if(rst == `RstEnable) begin
trapassert <= `TrapNotAssert;
end else begin
trapassert <= `TrapNotAssert;
case (aluop_i)
`EXE_TEQ_OP, `EXE_TEQI_OP: begin
if( reg1_i == reg2_i ) begin
trapassert <= `TrapAssert;
end
end
`EXE_TGE_OP, `EXE_TGEI_OP, `EXE_TGEIU_OP, `EXE_TGEU_OP: begin
if( ~reg1_lt_reg2 ) begin
trapassert <= `TrapAssert;
end
end
`EXE_TLT_OP, `EXE_TLTI_OP, `EXE_TLTIU_OP, `EXE_TLTU_OP: begin
if( reg1_lt_reg2 ) begin
trapassert <= `TrapAssert;
end
end
`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
always @ (*) begin //要写入通用寄存器的数据确定,溢出写是否使能
wd_o <= wd_i;
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
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 @ (*) begin //要写入HI,LO数据的确定
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//乘结果写入HI,LO寄存器
whilo_o <= `WriteEnable;
hi_o <= mulres[63:32];
lo_o <= mulres[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_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_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 if(aluop_i == `EXE_MTHI_OP) begin
whilo_o <= `WriteEnable;
hi_o <= reg1_i;
lo_o <= 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
always @ (*) begin //对cp0中寄存器修改信息送入MEM,传递至后面模块
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
cp0_reg_write_addr_o <= inst_i[15:11]; //改rd值
cp0_reg_we_o <= `WriteEnable; //修改使能
cp0_reg_data_o <= 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
endmodule
//两源操作数运算,计算写结果
// 加法直接相加,减法用源操作数1加源操作数2补码。溢出情况选中后设定是否写
// 比较:有符号看差正负
// 乘法:源操作数取补,结果据有符号乘和无符号乘看正负
// 除:DIV模块实现
// 自陷:比较结果加工
//通用寄存器写结果转移确定,HI,LO寄存器写结果转移确定,CP0中寄存器值确定
//访存回写段数据相关问题的解决
//乘累加乘累减除法流水线暂停请求
//计算加载存储指令地址。要存储的数据或要部分修改的原数据
//异常信息添加
ex/mem
`include "defines.v"
`timescale 1ns/1ps
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 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,
input wire[`DoubleRegBus] hilo_i,
input wire[1:0] cnt_i,
//存储加载指令
input wire[`AluOpBus] ex_aluop, //送入MEM,MEM据子运算类型看加载/存储作执行操作
input wire[`RegBus] ex_mem_addr,//加载存储地址
input wire[`RegBus] ex_reg2, //部分存储指令改写部分rt值,rt不改写值读取保留
//送到访存阶段的信息
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 mem_cp0_reg_we,
output reg[4:0] mem_cp0_reg_write_addr,
output reg[`RegBus] mem_cp0_reg_data,
output reg[31:0] mem_excepttype,
output reg mem_is_in_delayslot,
output reg[`RegBus] mem_current_inst_address,
output reg[`DoubleRegBus] hilo_o,
output reg[1:0] cnt_o,
//存储加载指令
output reg[`AluOpBus] mem_aluop, //送入MEM,MEM据子运算类型看加载/存储作执行操作
output reg[`RegBus] mem_mem_addr,//加载存储地址
output reg[`RegBus] mem_reg2 //部分存储指令改写部分rt值,rt不改写值读取保留
);
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据子运算类型看加载/存储作执行操作
mem_mem_addr <= ex_mem_addr; //加载存储地址
mem_reg2 <= ex_reg2; //部分存储指令改写部分rt值,rt不改写值读取保留
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
end //always
endmodule
mem
`include "defines.v"
`timescale 1ns/1ps
module mem(
input wire rst,
//来自执行阶段的信息
input wire[`RegAddrBus] wd_i,
input wire wreg_i,
input wire[`RegBus] wdata_i,
input wire cp0_reg_we_i,
input wire[4:0] cp0_reg_write_addr_i,
input wire[`RegBus] cp0_reg_data_i,
input wire[`RegBus] hi_i,
input wire[`RegBus] lo_i,
input wire whilo_i,
input wire[31:0] excepttype_i,
input wire is_in_delayslot_i,
input wire[`RegBus] current_inst_address_i,
//存储加载指令
input wire[`AluOpBus] aluop_i, //送入MEM,MEM据子运算类型看加载/存储作执行操作
input wire[`RegBus] mem_addr_i,//加载存储地址
input wire[`RegBus] reg2_i, //部分存储指令改写部分rt值,rt不改写值读取保留
//来自RAM数据存储器
input wire[`RegBus] mem_data_i,
//来自LLbit寄存器
input wire LLbit_i,//来自LLbit寄存器
input wire wb_LLbit_we_i,
input wire wb_LLbit_value_i,//来自MEM/WB,数据前推解决数据相关
//来自CP0,访存段据cp0内寄存器值判断异常种类,需cp0寄存器最新值
input wire[`RegBus] cp0_status_i,
input wire[`RegBus] cp0_cause_i,
//来自CP0,送至crtl,作异常返回指令的异常处理例程入口地址
input wire[`RegBus] cp0_epc_i,
//来自MEM/WB,回写阶段的指令是否要写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 cp0_reg_we_o,
output reg[4:0] cp0_reg_write_addr_o,
output reg[`RegBus] cp0_reg_data_o,
output reg[`RegBus] hi_o,
output reg[`RegBus] lo_o,
output reg whilo_o,
//送到RAM数据存储器
output reg mem_ce_o, //RAM使能
output reg[`RegBus] mem_addr_o, //加载存储地址
output wire mem_we_o, //是否写RAM
output reg[3:0] mem_sel_o, //存储/加载不同字节位置的选择(一个字节8bit,4×8=32bit)
output reg[`RegBus] mem_data_o, //写RAM值
//最终送至LLbit
output reg LLbit_we_o,
output reg LLbit_value_o,
output reg[31:0] excepttype_o, //送至cp0据此异常信息修改各寄存器值
output wire[`RegBus] cp0_epc_o, //送至crtl,作异常返回指令的异常处理例程入口地址
output wire is_in_delayslot_o,//送至cp0据是否为延迟指令判断异常指令地址
output wire[`RegBus] current_inst_address_o //送至cp0,修改epc寄存器值。因为可能为延迟槽指令,需前一指令,要减4
);
wire[`RegBus] zero32;
reg mem_we;
reg LLbit;
reg[`RegBus] cp0_status;
reg[`RegBus] cp0_cause;
reg[`RegBus] cp0_epc;
//assign mem_we_o = 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;
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_ce_o <= `ChipDisable;
mem_addr_o <= `ZeroWord;
mem_we <= `WriteDisable;
mem_sel_o <= 4'b0000;
mem_data_o <= `ZeroWord;
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;
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;
hi_o <= hi_i;
lo_o <= lo_i;
whilo_o <= whilo_i;
mem_ce_o <= `ChipDisable;
mem_addr_o <= `ZeroWord;
mem_we <= `WriteDisable;
mem_sel_o <= 4'b1111;
LLbit_we_o <= 1'b0;
LLbit_value_o <= 1'b0;
case(aluop_i)
`EXE_LB_OP: begin //有符号加载字节指令
mem_addr_o <= mem_addr_i;
mem_we <= `WriteDisable; //加载指令不改写RAM中值
mem_ce_o <= `ChipEnable; //RAM使能
case(mem_addr_i[1:0]) //参考加载地址后2位给字节选择赋值,添加Wishbone总线接口容易
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; //加载指令不改写RAM中值
mem_ce_o <= `ChipEnable; //RAM使能
case(mem_addr_i[1:0]) //参考加载地址后2位给字节选择赋值,添加Wishbone总线接口容易
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 //有符号加载半字指令(一个字2字节16bit)
mem_addr_o <= mem_addr_i;
mem_we <= `WriteDisable; //加载指令不改写RAM中值
mem_ce_o <= `ChipEnable; //RAM使能
case(mem_addr_i[1:0]) //参考加载地址后2位给字节选择赋值,添加Wishbone总线接口容易
2'b00: begin
wdata_o <= {{16{mem_data_i[31]}},mem_data_i[31:16]};
mem_sel_o <= 4'b1100;
end
2'b01: 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 //无符号加载半字指令(一个字2字节16bit)
mem_addr_o <= mem_addr_i;
mem_we <= `WriteDisable; //加载指令不改写RAM中值
mem_ce_o <= `ChipEnable; //RAM使能
case(mem_addr_i[1:0]) //参考加载地址后2位给字节选择赋值,添加Wishbone总线接口容易
2'b00: begin
wdata_o <= {{16{1'b0}},mem_data_i[31:16]};
mem_sel_o <= 4'b1100;
end
2'b01: 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_ce_o <= `ChipEnable; //RAM使能
mem_we <= `WriteDisable; //加载指令不改写RAM中值
wdata_o <= mem_data_i; //写入通用寄存器的加载值
mem_sel_o <=4'b1111; //全加载
end
`EXE_LWL_OP: begin
mem_addr_o <= {mem_addr_i[31:2], 2'b00}; //从loadaddr_align加载字节
mem_we <= `WriteDisable; //加载指令不改写RAM中值
mem_sel_o <= 4'b1111;
mem_ce_o <= `ChipEnable;
case (mem_addr_i[1:0]) //参考加载地址后2位给字节选择赋值
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]}; //少一个字节的加载值低位存入rt高位
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}; //从loadaddr_align加载字节
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]}; //0+1位加载值的高位存入rt的低位
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_SB_OP: begin
mem_addr_o <= mem_addr_i;
mem_we <= `WriteEnable; //存储指令,向RAM中存储数据,要写入
mem_data_o <= {reg2_i[7:0],reg2_i[7:0],reg2_i[7:0],reg2_i[7:0]}; //rt值低字节写入
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]}; //rt值低两个字节写入
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; //rt值全存入
mem_ce_o <= `ChipEnable;
end
`EXE_SWL_OP: begin
mem_addr_o <= {mem_addr_i[31:2], 2'b00}; //从storaddr_align存储字节
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; //存4-storaddr[1:0]个rt高字节至存储低字节
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}; //从storaddr_align存储字节
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]}; //存1+storaddr[1: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_LL_OP: begin
mem_ce_o <= `ChipEnable;
mem_addr_o <= mem_addr_i;
mem_we <= `WriteDisable;
wdata_o <= mem_data_i; //加载至通用寄存器rt
LLbit_we_o <= 1'b1;
LLbit_value_o <= 1'b1;//无异常,LLbit置1
mem_sel_o <= 4'b1111;
end
`EXE_SC_OP: begin
if(LLbit == 1'b1) begin
LLbit_we_o <= 1'b1;
LLbit_value_o <= 1'b0;//LLbit为1,未发生异常,执行sc后LLbit置0
mem_ce_o <= `ChipEnable;
mem_addr_o <= mem_addr_i;
mem_we <= `WriteEnable;
mem_data_o <= reg2_i;
wdata_o <= 32'b1;//sc指令成功执行,rt置1
mem_sel_o <= 4'b1111;
end else begin
wdata_o <= 32'b0;//sc指令执行失败,rt置0
end
end
default: begin
//什么也不做
end
endcase
end //else
end //always
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;//LLbit最新值
end else begin
LLbit <= LLbit_i;
end
end
end
always @ (*) begin //得到status最新值
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; //来自于MEM/WB输出.访存段未执行,则(若)上一条修改cp0,cp0寄存器修改未执行,MEM/WB输出的是最新值
end else begin
cp0_status <= cp0_status_i; //来自cp0输出。上一条非修改cp0寄存器,cp0值后面作异常信息设定的判断
end
end
always @ (*) begin //得到epc最新值
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 //得到cause最新值
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];//IP[1:0]软件中断
cp0_cause[22] <= wb_cp0_reg_data[22];//WP 处理器处于异常模式
cp0_cause[23] <= wb_cp0_reg_data[23];//IV 中断异常向量
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
excepttype_o <= 32'h0000000c; //ov 溢出
end else if(excepttype_i[12] == 1'b1) begin
excepttype_o <= 32'h0000000e; //eret 异常返回指令
end
end
end
end
endmodule
//传递运算结果,写入通用寄存器
//与RAM数据存储器相连,从RAM中获得加载数据,或向RAM中存储数据
//据MEM/WB,CP0送来的cp0寄存器最新数据,判断设定异常类型,
// 送至cp0修改寄存器数据(如处理器是否可用,异常种类)
// 送至crtl,再发出异常清除信号及异常处理例程入口地址
//
mem/wb
`include "defines.v"
`timescale 1ns/1ps
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_cp0_reg_we,
input wire[4:0] mem_cp0_reg_write_addr,
input wire[`RegBus] mem_cp0_reg_data,
input wire mem_LLbit_we,
input wire mem_LLbit_value,
//送到回写阶段的信息
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_cp0_reg_we,
output reg[4:0] wb_cp0_reg_write_addr,
output reg[`RegBus] wb_cp0_reg_data,
output reg wb_LLbit_we,
output reg wb_LLbit_value
);
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_cp0_reg_we <= `WriteDisable;
wb_cp0_reg_write_addr <= 5'b00000;
wb_cp0_reg_data <= `ZeroWord;
wb_hi <= `ZeroWord;
wb_lo <= `ZeroWord;
wb_whilo <= `WriteDisable;
wb_LLbit_we <= 1'b0;
wb_LLbit_value <= 1'b0;
end else if(stall[4] == `NoStop) begin //流水线正常
wb_wd <= mem_wd;
wb_wreg <= mem_wreg;
wb_wdata <= mem_wdata;
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;
wb_hi <= mem_hi;
wb_lo <= mem_lo;
wb_whilo <= mem_whilo;
wb_LLbit_we <= mem_LLbit_we;
wb_LLbit_value <= mem_LLbit_value;
end
end
endmodule
regfile
`include "defines.v"
`timescale 1ns/1ps
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
);
reg[`RegBus] regs[0:`RegNum-1];
always @ (posedge clk) begin
if (rst == `RstDisable) begin
if((we == `WriteEnable) && (waddr != `RegNumLog2'h0)) begin
regs[waddr] <= wdata;
end
end
end
always @ (*) begin
if(rst == `RstEnable) begin
rdata1 <= `ZeroWord;
end else if(raddr1 == `RegNumLog2'h0) begin
rdata1 <= `ZeroWord;
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;
end
end
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
ram
`include "defines.v"
`timescale 1ns/1ps
module data_ram(
input wire clk,
input wire ce, //RAM是否使能
input wire we, //RAM是否存储
input wire[`DataAddrBus] addr, //加载存储地址
input wire[3:0] sel, //字节选择
input wire[`DataBus] data_i, //存储数据
output reg[`DataBus] data_o //加载数据
);
//定义4个1字节数组
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
//data_o <= ZeroWord;
end else if(we == `WriteEnable) begin
if (sel[3] == 1'b1) begin
data_mem3[addr[`DataMemNumLog2+1:2]] <= data_i[31:24];//据sel值修改存储器对应字节,低两位不使用
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
hilo
`include "defines.v"
`timescale 1ns/1ps
module hilo_reg(
input wire clk,
input wire rst,
//写端口
input wire we,
input wire[`RegBus] hi_i,
input wire[`RegBus] lo_i,
//读端口1
output reg[`RegBus] hi_o,
output reg[`RegBus] lo_o
);
always @ (posedge clk) begin
if (rst == `RstEnable) begin
hi_o <= `ZeroWord;
lo_o <= `ZeroWord;
end else if((we == `WriteEnable)) begin
hi_o <= hi_i;
lo_o <= lo_i;
end
end
endmodule
div
`include "defines.v"
`timescale 1ns/1ps
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
cp0
`include "defines.v"
`timescale 1ns/1ps
module cp0_reg(
input wire clk,
input wire rst,
//是否写,写的地址,写的数据
input wire we_i,
input wire[4:0] waddr_i,
input wire[`RegBus] data_i,
input wire[4:0] raddr_i,//读的地址
input wire[5:0] int_i, //6个外硬件中断输入
input wire[31:0] excepttype_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
);
//cp0内寄存器值更新
always @ (posedge clk) begin
if(rst == `RstEnable) begin
count_o <= `ZeroWord;
compare_o <= `ZeroWord;
status_o <= 32'b00010000000000000000000000000000;//status寄存器的CU为0001,表示协处理器CP0存在
cause_o <= `ZeroWord;
epc_o <= `ZeroWord;
config_o <= 32'b00000000000000001000000000000000;//config寄存器的BE为1,表示Big-Endian;MT为00,表示没有MMU
prid_o <= 32'b00000000010011000000000100000010;//制作者是L,对应的是0x48,类型是0x1,基本类型,版本号是1.0
timer_int_o <= `InterruptNotAssert;//未定时中断
end else begin
count_o <= count_o + 1 ; //计数加1
cause_o[15:10] <= int_i; //cause寄存器15-10位表示外硬件中断情况
if(compare_o != `ZeroWord && count_o == compare_o) begin
timer_int_o <= `InterruptAssert; //compare值与count值相同,定时中断
end
if(we_i == `WriteEnable) begin //cp0内寄存器值写入
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 <= `InterruptNotAssert;
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
default: begin
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
end
//读cp0 中寄存器值
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
end
end
endmodule
ctrl
`include "defines.v"
`timescale 1ns/1ps
module ctrl(
input wire rst,
//暂停请求
input wire stallreq_from_id,
input wire stallreq_from_ex,
//来自MEM异常信息
input wire[31:0] excepttype_i,
input wire[`RegBus] cp0_epc_i,//异常返回eret时作异常处理例程入口地址。因为要返回异常发生前状态执行
output reg[5:0] stall,
output reg flush,//清除信号
output reg[`RegBus] new_pc//异常入口地址
);
always @ (*) begin
if(rst == `RstEnable) begin
stall <= 6'b000000;
flush <= 1'b0;
new_pc <= `ZeroWord;
end else flush <= 1'b0;
if(excepttype_i != `ZeroWord) begin //异常信息不为0,发生异常
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;
end else if(stallreq_from_id == `Stop) begin
stall <= 6'b000111;
end else begin
stall <= 6'b000000;
end //if
end //always
endmodule
inst_rom.v
`include "defines.v"
`timescale 1ns/1ps
module inst_rom(
// input wire clk,
input wire ce,
input wire[`InstAddrBus] addr,
output reg[`InstBus] inst
);
reg[`InstBus] inst_mem[0:`InstMemNum-1];
initial $readmemh ( "E:/ma/chap10/inst_rom_chap11_3.data", inst_mem );
always @ (*) begin
if (ce == `ChipDisable) begin
inst <= `ZeroWord;
end else begin
inst <= inst_mem[addr[`InstMemNumLog2+1:2]];
end
end
endmodule
指令测试程序
系统调用
自陷指令
中断
7.仿真波形
仿真波形我一共截了9张图,太多了,就放个书上的吧