问题引入
......
lw $1,0x0($0) //从数据存储器地址0x0处加载字 保存到通用寄存器$1
beq $1,$2,Label1 //比较通用寄存器$1与$2 如果相等 那么转移到Label1处
......
lw在访存阶段从ram读取数据,即在访存
阶段才能写入$1的值,此值就是$1的最新值。紧接着的转移指令beq处于执行阶段,beq在上一周期译码阶段时,就已经对$1,$2的值进行了比较,并判断是否发生转移。判断时$1的值并不是lw指令加载得到的值,所以程序执行的结果是错误的
。
如果使用之前解决数据相关问题的数据前推,将访存阶段加载到的数据前推,解决不了问题。因为,数据加载时,beq指令处于执行阶段,已经进行了比较这种情况称为load相关。
解决方法
在id阶段检查当前指令和上一条指令是否存在load相关,如果存在load相关,那么就让流水线的译码,取指阶段暂停,执行,访存,回写阶段继续,相当于插入一个空指令,这样处于执行阶段的加载指令就会继续执行。当其运行到访存阶段时,将加载的带的数据前推到译码阶段,然后流水线可以继续运行。
系统结构的修改
id.v(修改)
`include "define.v"
module id(
input wire rst,
input wire[`InstAddrBus] pc_i,
input wire[`InstBus] inst_i,
input wire[`RegBus] reg1_data_i,
input wire[`RegBus] reg2_data_i,
input wire is_in_delayslot_i,//是否位于延迟槽指令
//送到regfile的信息
output reg reg1_read_o,
output reg reg2_read_o,
output reg[`RegAddrBus] reg1_addr_o,
output reg[`RegAddrBus] reg2_addr_o,
//送到执行阶段的信息
output reg[`AluOpBus] aluop_o,
output reg[`AluSelBus] alusel_o,
output reg[`RegBus] reg1_o,
output reg[`RegBus] reg2_o,
output reg[`RegAddrBus] wd_o,
output reg wreg_o,
//处于执行阶段的指令的运算结果
input wire ex_wreg_i,
input wire[`RegBus] ex_wdata_i,
input wire[`RegAddrBus] ex_wd_i,
input wire[`AluOpBus] ex_aluop_i,
//处于访存阶段的指令的运算结果
input wire mem_wreg_i,
input wire[`RegBus] mem_wdata_i,
input wire[`RegAddrBus] mem_wd_i,
output wire stallreq,
output reg next_inst_in_delayslot_o,//下条指令是否是延迟槽
output reg branch_flag_o,//是否发生转移
output reg[`RegBus] branch_target_address_o,//转移到的目标地址
output reg[`RegBus] link_addr_o,//转移指令要保存的返回地址
output reg is_in_delayslot_o,//当前处于译码指令是否位于延迟槽
output wire[`RegBus] inst_o //新增加的输出接口
//input wire[`AluOpBus] ex_aluop_i,
//output wire stallreq
);
wire[5:0] op = inst_i[31:26];
wire[4:0] op2 = inst_i[10:6];
wire[5:0] op3 = inst_i[5:0];
wire[4:0] op4 = inst_i[20:16];
wire[`RegBus] pc_plus_8;//保存当前译码阶段指令后面第二条指令的地址
wire[`RegBus] pc_plus_4;//保存当前译码阶段指令后面紧接着的指令地址
wire[`RegBus] imm_sll2_signedext;//对应分支指令中offset左移两位,再符号扩展至32位的值
reg[`RegBus] imm;
reg instvalid;
assign stallreq = `NoStop;//在实现加载、存储指令时会给该信号赋值
assign imm_sll2_signedext = {{14{inst_i[15]}},inst_i[15:0],2'b00};
//imm_sll2_signedext对应分支指令中的offset左移两位,再符号扩展至32位的值
assign pc_plus_8 = pc_i+8;
assign pc_plus_4 = pc_i+4;
assign stallreq = `NoStop;
assign inst_o = inst_i;//译码阶段的指令
//新定义一个变量 表示要读取的寄存器1是否与上一条指令存在load相关
reg stallreq_for_reg1_loadrelate;
//新定义一个变量 表示要读取的寄存器2是否与上一条指令存在load相关
reg stallreq_for_reg2_loadrelate;
//新定义一个变量 表示上一条指令是否是加载指令
wire pre_inst_is_load;
//依据输入信号ex_aluop_i值 判断上一条指令是否是加载指令
//如果是加载指令 那么置pre_inst_is_load为1 反之置0
assign pre_inst_is_load = ((ex_aluop_i == `EXE_LB_OP)||
(ex_aluop_i == `EXE_LBU_OP)||
(ex_aluop_i == `EXE_LH_OP)||
(ex_aluop_i==`EXE_LHU)||
(ex_aluop_i==`EXE_LW_OP)||
(ex_aluop_i==`EXE_LWR_OP)||
(ex_aluop_i==`EXE_LWL_OP)||
(ex_aluop_i==`EXE_LL_OP)||
(ex_aluop_i==`EXE_SC_OP)) ? 1'b1 : 1'b0;
/*如果上一条指令是加载指令 且该加载指令要加载到目的寄存器就是当前指令
要通过Regfile模块读取端口1读取的通用寄存器,那么表示存在load相关*/
//设置stallreq_for_reg1_loadrelate为Stop
always @(*)begin
stallreq_for_reg1_loadrelate <= `NoStop;
if(rst == `RstEnable)begin
reg1_o <= `ZeroWord;
end else if(pre_inst_is_load == 1'b1 && ex_wd_i == reg1_addr_o && reg1_read_o == 1'b1)begin
stallreq_for_reg1_loadrelate <= `Stop;//存在load相关 Stop
end
end
//reg2与reg1同理
always @(*)begin
stallreq_for_reg2_loadrelate <= `NoStop;
if(rst == `RstEnable)begin
reg2_o <= `ZeroWord;
end else if(pre_inst_is_load == 1'b1 && ex_wd_i == reg2_addr_o && reg2_read_o == 1'b1)begin
stallreq_for_reg2_loadrelate <= `Stop;//存在load相关 Stop
end
end
assign stallreq = stallreq_for_reg1_loadrelate | stallreq_for_reg2_loadrelate;
always @ (*) begin
if (rst == `RstEnable) begin
aluop_o <= `EXE_NOP_OP;
alusel_o <= `EXE_RES_NOP;//nop
wd_o <= `NOPRegAddr;
wreg_o <= `WriteDisable;
instvalid <= `InstValid;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
reg1_addr_o <= `NOPRegAddr;
reg2_addr_o <= `NOPRegAddr;
imm <= 32'h0;
link_addr_o <= `ZeroWord;//转移指令要保存的返回地址
branch_target_address_o <= `ZeroWord;//转移到的目标地址
branch_flag_o <= `NotBranch;//不发生转移
next_inst_in_delayslot_o <= `NotInDelaySlot;//下一条指令是否位于延迟槽
end else begin //先初始化
aluop_o <= `EXE_NOP_OP;
alusel_o <= `EXE_RES_NOP;
wd_o <= inst_i[15:11];
wreg_o <= `WriteDisable;
instvalid <= `InstInvalid;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
reg1_addr_o <= inst_i[25:21];//rs
reg2_addr_o <= inst_i[20:16];//rt
imm <= `ZeroWord;
link_addr_o <= `ZeroWord;
branch_target_address_o <= `ZeroWord;
branch_flag_o <= `NotBranch;
next_inst_in_delayslot_o <= `NotInDelaySlot;
case (op)//指令码
`EXE_SPECIAL_INST: begin //指令码是SPECIAL
case(op2)//功能码
5'b00000: begin
case(op3) //依据功能码判断是哪一个指令
`EXE_OR: begin //or R型指令 rs|rt -> rd
wreg_o <= `WriteEnable;
aluop_o <= `EXE_OR_OP;
alusel_o <= `EXE_RES_LOGIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_AND:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_AND_OP;//R rs&rt ->rd
alusel_o <= `EXE_RES_LOGIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_XOR:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_XOR_OP;// R rs^rt ->rd
alusel_o <= `EXE_RES_LOGIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_NOR:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_NOR_OP;// R rs~|rt ->rd
alusel_o <= `EXE_RES_LOGIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SLLV:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SLL_OP;
alusel_o <= `EXE_RES_SHIFT;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SRLV:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SRLV_OP;
alusel_o <= `EXE_RES_SHIFT;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SRAV:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SRAV_OP;
alusel_o <= `EXE_RES_SHIFT;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SYNC:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_NOP_OP;
alusel_o <= `EXE_RES_NOP;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MFHI:begin//将特殊寄存器hi的值赋给地址为rd的寄存器
wreg_o <= `WriteEnable;
aluop_o <= `EXE_MFHI_OP;
alusel_o <= `EXE_RES_MOVE;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MFLO:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_MFLO_OP;
alusel_o <= `EXE_RES_MOVE;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MTHI:begin//hi<-rs 写特殊寄存器
wreg_o <= `WriteEnable;
aluop_o <= `EXE_MTHI_OP;
alusel_o <= `EXE_RES_MOVE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MTLO:begin //lo<-rs 写特殊寄存器
wreg_o <= `WriteEnable;
aluop_o <= `EXE_MTLO_OP;
reg1_read_o <= 1'b1;//rs
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MOVN:begin//判断rt寄存器的值 如果不为0 将rs的值赋给rd 反之rd值不变
//wreg_o <= `WriteEnable;
aluop_o <= `EXE_MOVN_OP;
alusel_o <= `EXE_RES_MOVE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
//reg2_o的值就是地址为rt的寄存器的值
if(reg2_o != `ZeroWord)begin
wreg_o <= `WriteEnable;
end else begin
wreg_o <= `WriteDisable;
end
end
`EXE_MOVZ:begin //判断rt寄存器的值 如果是0 将rs的值赋给rd 反之rd值不变
aluop_o <= `EXE_MOVZ_OP;
alusel_o <= `EXE_RES_MOVE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
if(reg2_o == `ZeroWord)begin
wreg_o <= `WriteEnable;
end else begin
wreg_o <= `WriteDisable;
end
end
`EXE_SLT:begin//slt指令 rd<-(rs<rt)
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SLT_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SLTU:begin //sltu指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SLTU_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_ADD:begin//rd<-rs+rt
wreg_o <= `WriteEnable;
aluop_o <= `EXE_ADD_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_ADDU:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_ADDU_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SUB:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SUB_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SUBU:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SUBU_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MULT:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_MULT_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MULTU:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_MULTU_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_DIV:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_DIV_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_DIVU:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_DIVU_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_JR:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_JR_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;//rs寄存器需要被使用
reg2_read_o <= 1'b0;
wd_o <= inst_i[15:11];
link_addr_o <= pc_plus_8;//返回地址
branch_target_address_o <= reg1_o;//转移到的目标地址
branch_flag_o <= `Branch;//是否发生转移
next_inst_in_delayslot_o <= `InDelaySlot;//下一条指令不位于延迟槽
instvalid <= `InstValid;
end
`EXE_JALR:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_JALR_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
wd_o <= inst_i[15:11];
link_addr_o <= pc_plus_8;
branch_target_address_o <= reg1_o;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
instvalid <= `InstValid;
end
default:begin
end
endcase
end
default:begin
//aluop_o <= `EXE_NOP_OP;
//alusel_o <= `EXE_RES_OP;
//wd_o <= `NOPRegAddr;
//wreg_o <= `WriteDisable;
//instvalid <= `InstValid;
//reg1_read_o <= `ReadDisable;
//reg2_read_o <= `ReadDisable;
//reg1_addr_o <= inst_i[25:21];
//reg2_addr_o <= inst_i[20:16];
end
endcase//op3
end // 5'b00000
`EXE_J:begin
wreg_o <= `WriteDisable;//译码阶段是否要写入目的寄存器
aluop_o <= `EXE_J_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
link_addr_o <= `ZeroWord;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
instvalid <= `InstValid;
branch_target_address_o <= {pc_plus_4[31:28],inst_i[25:0],2'b00};//转移目的的地址
end
`EXE_JAL:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_JAL_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
wd_o <= 5'b11111;//要写入的目的寄存器的地址 寄存器$1
link_addr_o <= pc_plus_8;//转移指令要保存的返回地址
branch_flag_o <= `Branch;//转移发生的标志
next_inst_in_delayslot_o <= `InDelaySlot;
instvalid <= `InstValid;
branch_target_address_o <= {pc_plus_4[31:28],inst_i[25:0],2'b00};
end
`EXE_BEQ:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_BEQ_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;//需要比较rs与rt
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
if(reg1_o == reg2_o)begin //如果rs的值reg1_o与rd的值reg2_o相等 发生转移
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_BGTZ:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_BGTZ_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;//rs
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
if((reg1_o[31] == 1'b0)&&(reg1_o != `ZeroWord))begin
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_BLEZ:begin
wreg_o <= `WriteDisable;//译码阶段是否要写入目的寄存器
aluop_o <= `EXE_BLEZ_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
if((reg1_o[31] == 1'b1)&&(reg1_o != `ZeroWord))begin
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_BNE:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_BNE_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
if(reg1_o != reg2_o)begin
branch_target_address_o <= pc_plus_4+imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_REGIMM_INST:begin
case(op4)
`EXE_BLTZAL:begin//bltzal
wreg_o <= `WriteEnable;
aluop_o <= `EXE_BGEZAL_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
link_addr_o <= pc_plus_8;
wd_o <= 5'b11111;
instvalid <= `InstValid;
if(reg1_o[31] == 1'b1) begin//reg1_o<0
branch_target_address_o <= pc_plus_4+imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_BLTZ:begin//bltz
wreg_o <= `WriteDisable;
aluop_o <= `EXE_BGEZAL_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
if(reg1_o[31] == 1'b1)begin
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_BGEZ:begin//bgez
wreg_o <= `WriteDisable;
aluop_o <= `EXE_BGEZ_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
if(reg1_o[31] == 1'b0)begin//rs的值大于等于0
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_BGEZAL:begin//bgezal
wreg_o <= `WriteEnable;
aluop_o <= `EXE_BGEZAL_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
link_addr_o <= pc_plus_8;
wd_o <= 5'b11111;
instvalid <= `InstValid;
if(reg1_o[31] == 1'b0)begin
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
default:begin
end
endcase // op2
end
`EXE_ORI:begin //ORI指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_OR_OP;
alusel_o <= `EXE_RES_LOGIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {16'h0, inst_i[15:0]}; //立即数0扩展
wd_o <= inst_i[20:16]; // 读取rt地址
instvalid <= `InstValid;
end
`EXE_ANDI:begin //andi
wreg_o <= `WriteEnable;
aluop_o <= `EXE_AND_OP;
alusel_o <= `EXE_RES_LOGIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {16'h0,inst_i[15:0]};
wd_o <= inst_i[20:16];//rt
instvalid = `InstValid;
end
`EXE_XORI:begin//xori
wreg_o <= `WriteEnable;
aluop_o <= `EXE_XOR_OP;
alusel_o <= `EXE_RES_LOGIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {16'h0,inst_i[15:0]};
wd_o <= inst_i[20:16];
instvalid = `InstValid;
end
`EXE_LUI:begin//lui
wreg_o <= `WriteEnable;//注意书上的打印错误 无语了
aluop_o <= `EXE_OR_OP;
alusel_o <= `EXE_RES_LOGIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {inst_i[15:0],16'h0};
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
/*`EXE_PREF: begin//pref
wreg_o <= `WriteDisable;
aluop_o <= `EXE_NOP_OP;
alusel_o <= `EXE_RES_NOP;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end */
`EXE_SLTI:begin //slti rt <- (rs < (sign_extended)immediate)
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SLT_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}},inst_i[15:0]};
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_SLTIU:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SLTU_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}},inst_i[15:0]};
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_ADDI:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_ADDI_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}},inst_i[15:0]};
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_ADDIU:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_ADDIU_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}},inst_i[15:0]};
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_LB:begin//将加载结果写入目的寄存器
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LB_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;//计算加载目标地址需要使用地址为base的寄存器值
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16];//目的寄存器地址
instvalid <= `InstValid;
end
`EXE_LBU:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LBU_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_LH:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LH_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_LHU:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LHU_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_LW:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LW_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_LWL:begin//向左加载 加载结果需要写入目的寄存器 [20:16]
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LWL_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_LWR:begin//向右加载
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LWR_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_SB:begin //不需要写通用寄存器 计算存储目标地址需要使用的地址为base的寄存器的值
wreg_o <= `WriteDisable;
aluop_o <= `EXE_SB_OP;
reg1_read_o <= 1'b1; //[25:21] reg1_addr_o ======> base
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
`EXE_SH:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_SH_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
`EXE_SW:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_SW_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
`EXE_SWL:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_SWL_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
`EXE_SWR:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_SWR_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
`EXE_LL:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_LL_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_SC:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SC_OP;
alusel_o <= `EXE_RES_LOAD_STORE;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_SPECIAL2_INST:begin//(op)
case(op3)
`EXE_CLZ:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_CLZ_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_CLO:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_CLO_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MUL:begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_MUL_OP;
alusel_o <= `EXE_RES_MUL;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MADD:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_MADD_OP;
alusel_o <= `EXE_RES_MUL;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MADDU:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_MADDU_OP;
alusel_o <= `EXE_RES_MUL;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MSUB:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_MSUB_OP;
alusel_o <= `EXE_RES_MUL;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MSUBU:begin
wreg_o <= `WriteDisable;
aluop_o <= `EXE_MSUBU_OP;
alusel_o <= `EXE_RES_MUL;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
default:begin
end
endcase //EXE_SPECIAL_INST2 case
end
default:begin
end
endcase //case op
if(inst_i[31:21] == 11'b00000000000)begin //sll,srl,sra
if(op3 == `EXE_SLL) begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SLL_OP;
alusel_o <= `EXE_RES_SHIFT;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b1;
imm[4:0] <= inst_i[10:6];
wd_o <= inst_i[15:11];
instvalid <= `InstValid;
end else if(op3 == `EXE_SRL)begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SRL_OP;
alusel_o <= `EXE_RES_SHIFT;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b1;
imm[4:0] <= inst_i[10:6];
wd_o <= inst_i[15:11];
instvalid <= `InstValid;
end else if(op3 == `EXE_SRA) begin
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SRA_OP;
alusel_o <= `EXE_RES_SHIFT;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b1;
imm[4:0] <= inst_i[10:6];
wd_o <= inst_i[15:11];
instvalid <= `InstValid;
end
//endcase
//end
end //if
end
end //always
/* 数据前推
给reg1_o赋值过程增加了两种情况
1:如果Regfile模块读端口1要读取的寄存器就是执行阶段要写的目的寄存器,那么直接把执行阶段的结果ex_wdata_i作为reg1_o的值
2:如果Regfile模块读端口1要读取的寄存器就是访存阶段要写的目的寄存器,那么直接把访存阶段的结果mem_wdata_i作为reg1_o的值*/
always @ (*) begin
if(rst == `RstEnable) begin
reg1_o <= `ZeroWord;
end else if((reg1_read_o == 1'b1) && (ex_wreg_i == 1'b1)
&& (ex_wd_i == reg1_addr_o)) begin
reg1_o <= ex_wdata_i;
end else if((reg1_read_o == 1'b1) && (mem_wreg_i == 1'b1)
&& (mem_wd_i == reg1_addr_o)) begin
reg1_o <= mem_wdata_i;
end else if(reg1_read_o == 1'b1) begin
reg1_o <= reg1_data_i;
end else if(reg1_read_o == 1'b0) begin
reg1_o <= imm;
end else begin
reg1_o <= `ZeroWord;
end
end
always @ (*) begin
if(rst == `RstEnable) begin
reg2_o <= `ZeroWord;
end else if((reg2_read_o == 1'b1) && (ex_wreg_i == 1'b1)
&& (ex_wd_i == reg2_addr_o)) begin
reg2_o <= ex_wdata_i;
end else if((reg2_read_o == 1'b1) && (mem_wreg_i == 1'b1)
&& (mem_wd_i == reg2_addr_o)) begin
reg2_o <= mem_wdata_i;
end else if(reg2_read_o == 1'b1) begin
reg2_o <= reg2_data_i;
end else if(reg2_read_o == 1'b0) begin
reg2_o <= imm;
end else begin
reg2_o <= `ZeroWord;
end
end
//输出变量is_in_delayslot_o表示当前译码阶段指令是否是延迟槽指令
always @ (*)begin
if(rst == `RstEnable)begin
is_in_delayslot_o <= `NotInDelaySlot;
end else begin
//直接等于is_in_delayslot_i
is_in_delayslot_o <= is_in_delayslot_i;
end
end
endmodule
inst_rom.S
.org 0x0
.set noat
.set noreorder
.set nomacro
.global _start
_start:
ori $1,$0,0x1234 # $1 = 0x00001234
sw $1,0x0($0) # [0x0] = 0x00001234
ori $2,$0,0x1234 # $2 = 0x00001234
ori $1,$0,0x0 # $1 = 0x0
lw $1,0x0($0) # $1 = 0x00001234
beq $1,$2,Label
nop
ori $1,$0,0x4567
nop
Label:
ori $1,$0,0x89ab # $1 = 0x000089ab
nop
_loop:
j _loop
nop
inst_rom.data
34011234
ac010000
34021234
34010000
8c010000
10220003
00000000
34014567
00000000
340189ab
00000000
0800000b
00000000