我理解的是5级流水线中的转移指令前级被跳过
`include "defines.v"
module pc_reg(
input wire clk,
input wire rst,
//来自控制模块的信息
input wire[5:0] stall,
//来自译码阶段的信息
input wire branch_flag_i,
input wire[`RegBus] branch_target_address_i,
output reg [`InstAddrBus] pc, //InstAddrBus为宏定义 31:0 代表ROM的地址总线宽度 输出给ROM的addr
output reg ce //给到ROM的使能
);
//如果复位,则使能信号ce拉0,否则置1
always @ (posedge clk) begin
if (rst == `RstEnable) begin //复位信号有效 1'b1
ce <= `ChipDisable;
end
else begin
ce <= `ChipEnable;
end
end
//如果使能信号为低,则指令地址拉0;使能有效,则指令地址自加4'h4
always @ (posedge clk) begin
if (ce == `ChipDisable) begin //芯片禁止宏定义 1'b0
pc <= 32'h00000000;
end
else if(stall[0] == `NoStop)begin
if(branch_flag_i == `Branch) begin
pc <= branch_target_address_i;
end
else
pc <= pc + 4'h4; //自加4 字节寻址
end
end
endmodule
module id(
input wire rst,
input wire[`InstAddrBus] pc_i, //[31:0]
input wire[`InstBus] inst_i, //[31:0] 接收IF/ID模块给的指令
//从regfile里输入的
input wire[`RegBus] reg1_data_i, //[31:0]
input wire[`RegBus] reg2_data_i, //[31:0]
//处于执行阶段的指令要写入的目的寄存器信息
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,
//如果上一条指令是转移指令,那么下一条指令在译码的时候
//is_in_delayslot为true表示是延迟槽指令,反之为false
input wire is_in_delayslot_i,
//送到regfile的信息
output reg reg1_read_o, //使能
output reg reg2_read_o, //使能
output reg[`RegAddrBus] reg1_addr_o, //[4:0]
output reg[`RegAddrBus] reg2_addr_o, //[4:0]
//送到执行阶段的信息
output reg[`AluOpBus] aluop_o, //译码阶段的输出aluop_o的宽度 7:0 运算子类型
output reg[`AluSelBus] alusel_o, //译码阶段的输出alusel_o的宽度 2:0 运算类型
//结果写入寄存器
output reg[`RegAddrBus] wd_o, //[4:0] 要写入的目的寄存器地址
output reg wreg_o, //是否有要写入的目的寄存器
//这两个是最终输出的操作数
output reg[`RegBus] reg1_o, //[31:0] 源操作数1
output reg[`RegBus] reg2_o, //[31:0] 源操作数2
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
);
//取得指令的指令码,功能码 即分解帧格式
//对于ori指令只需通过判断第26-31bit的值,即可判断是否是ori指令;对应I类型指令
wire[5:0] op = inst_i[31:26]; //op指令段
wire[4:0] op2 = inst_i[10:6];
wire[5:0] op3 = inst_i[5:0];
wire[4:0] op4 = inst_i[20:16];
//保存指令执行需要的立即数[31:0]
reg[`RegBus] imm;
//指示指令是否有效
reg instvalid;
wire[`RegBus] pc_plus_8;
wire[`RegBus] pc_plus_4;
wire[`RegBus] imm_sll2_signedext;
assign pc_plus_8 = pc_i + 8; //保存当前译码阶段指令后面第2条指令的地址
assign pc_plus_4 = pc_i +4; //保存当前译码阶段指令后面第1条指令的地址
//对应分支指令中的左移两位,并符号扩展至32位
assign imm_sll2_signedext = {{14{inst_i[15]}}, inst_i[15:0], 2'b00 };
assign stallreq = `NoStop;
//译码操作 组合逻辑实时译码
//确定要读取的寄存器情况、要执行的运算、要写的目的寄存器
//主要内容:大小运算类型、两个读口、指令有无效、是否要写、写地址、imm
always @ (*)
if (rst == `RstEnable) begin
aluop_o <= `EXE_NOP_OP; //8'b0000_0000
alusel_o <= `EXE_RES_NOP; //3'b000
wd_o <= `NOPRegAddr; //5'b00000
wreg_o <= `WriteDisable;
instvalid <= `InstValid; //指令有效
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
reg1_addr_o <= `NOPRegAddr; //5'b00000
reg2_addr_o <= `NOPRegAddr; //5'b00000
imm <= `ZeroWord;
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; //8'b0000_0000
alusel_o <= `EXE_RES_NOP; //3'b000
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;
case (op)
`EXE_SPECIAL_INST: begin //op为special 去判断op2
case (op2)
5'b00000: begin //5-2阶段非0无效 继续判断op3功能码 以此可跟sll区别
case (op3) //功能码 操作均是:类型与子类型,写使能、两个读使能、有无效(这几个操作要写入的寄存器就是默认的rd!)
`EXE_OR: begin
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;
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;
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;
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_SRL_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_SRA_OP;
alusel_o <= `EXE_RES_SHIFT;
reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SYNC: begin
wreg_o <= `WriteDisable; 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 //NEW
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
wreg_o <= `WriteDisable; aluop_o <= `EXE_MTHI_OP;
reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MTLO: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_MTLO_OP;
reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MOVN: begin
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 //NEW
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
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
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
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 <= `WriteDisable; aluop_o <= `EXE_MULT_OP;
reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MULTU: begin
wreg_o <= `WriteDisable; 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; reg2_read_o <= 1'b0;
link_addr_o <= `ZeroWord;
branch_target_address_o <= reg1_o; //这个会返给PC
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
default: begin
end
endcase
end
default: begin
end
endcase
end
//这几个写入的寄存器不同,所以单独赋值wd_o
`EXE_ORI: begin //ORI指令 用立即数和rs计算后写入rt
alusel_o <= `EXE_RES_LOGIC;
aluop_o <= `EXE_OR_OP;
wreg_o <= `WriteEnable;
wd_o <= inst_i[20:16]; //立即数与rs的结果写入rt
imm <= {16'h0,inst_i[15:0]};
reg1_read_o <= 1'b1; //要去读一个rs
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_ANDI: begin
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];
instvalid <= `InstValid;
end
`EXE_XORI: begin
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
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
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
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_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_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
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; //$31
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
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
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
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_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
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
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
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
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
default: begin
end
endcase
end
`EXE_SPECIAL2_INST: begin
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:;
endcase //EXE_SPECIAL_INST2 case
end
default:;
endcase
//sll、srl、sra 把移位数给到imm,作为1个源操作数
if(inst_i[31:21] == 11'b00000000000) begin //新的位段判断指令
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
end
//确定2个源操作数
always@(*)
if(rst == `RstEnable)
reg1_o <= `ZeroWord;
else if((reg1_read_o == 1'b1)&&(ex_wreg_i == 1'b1)&&(reg1_addr_o == ex_wd_i))//前堆
reg1_o <= ex_wdata_i;
else if((reg1_read_o == 1'b1)&&(mem_wreg_i == 1'b1)&&(reg1_addr_o == mem_wd_i))//前堆
reg1_o <= mem_wdata_i;
else if(reg1_read_o == 1'b1)
reg1_o <= reg1_data_i;
else if(reg1_read_o == 1'b0)
reg1_o <= imm;
else
reg1_o <= `ZeroWord;
always@(*)
if(rst == `RstEnable)
reg2_o <= `ZeroWord;
else if((reg2_read_o == 1'b1)&&(ex_wreg_i == 1'b1)&&(reg2_addr_o == ex_wd_i))//前堆
reg2_o <= ex_wdata_i;
else if((reg2_read_o == 1'b1)&&(mem_wreg_i == 1'b1)&&(reg2_addr_o == mem_wd_i))//前堆
reg2_o <= mem_wdata_i;
else if(reg2_read_o == 1'b1)
reg2_o <= reg2_data_i;
else if(reg2_read_o == 1'b0)
reg2_o <= imm;
else
reg2_o <= `ZeroWord;
endmodule
`include "defines.v"
module id_ex(
input wire clk,
input wire rst,
//从译码阶段传递的信息
input wire[`AluOpBus] id_aluop, //[7:0]
input wire[`AluSelBus] id_alusel, //[2:0]
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[5:0] stall,
//传递到执行阶段的
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 //当前译码阶段的指令是否位于延迟槽
);
//打一拍传过去
//1.当stall[2]为stop,stall[3]为nostop,表示译码阶段暂停,执行阶段继续
// 使用空指令作为下一个周期进入执行阶段的指令
//2.当stall[2]为nostop,译码阶段继续,译码后的指令进入执行阶段
//3.其余情况,保持不变
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;
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;
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;
end
end
endmodule