问题引入

......
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 反之置0assign 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为Stopalways @(*)beginstallreq_for_reg1_loadrelate <= `NoStop;if(rst == `RstEnable)beginreg1_o <= `ZeroWord;end else if(pre_inst_is_load == 1'b1 && ex_wd_i == reg1_addr_o && reg1_read_o == 1'b1)beginstallreq_for_reg1_loadrelate <= `Stop;//存在load相关 Stopend
end
//reg2与reg1同理
always @(*)beginstallreq_for_reg2_loadrelate <= `NoStop;if(rst == `RstEnable)beginreg2_o <= `ZeroWord;end else if(pre_inst_is_load == 1'b1 && ex_wd_i == reg2_addr_o && reg2_read_o == 1'b1)beginstallreq_for_reg2_loadrelate <= `Stop;//存在load相关 Stopend
end
assign stallreq = stallreq_for_reg1_loadrelate | stallreq_for_reg2_loadrelate;always @ (*) begin  if (rst == `RstEnable) beginaluop_o <= `EXE_NOP_OP;alusel_o <= `EXE_RES_NOP;//nopwd_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];//rsreg2_addr_o <= inst_i[20:16];//rtimm <= `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 //指令码是SPECIALcase(op2)//功能码5'b00000: begincase(op3) //依据功能码判断是哪一个指令`EXE_OR: begin //or R型指令 rs|rt -> rdwreg_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:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_AND_OP;//R rs&rt ->rdalusel_o <=  `EXE_RES_LOGIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_XOR:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_XOR_OP;// R rs^rt ->rdalusel_o <= `EXE_RES_LOGIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_NOR:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_NOR_OP;// R rs~|rt ->rdalusel_o <= `EXE_RES_LOGIC;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_SLLV:beginwreg_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:beginwreg_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:beginwreg_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:beginwreg_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:beginwreg_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;//rsreg2_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)beginwreg_o <= `WriteEnable;end else beginwreg_o <= `WriteDisable;endend`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)beginwreg_o <= `WriteEnable;end else beginwreg_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+rtwreg_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:beginwreg_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:beginwreg_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:beginwreg_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:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_MULT_OP;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_MULTU:beginwreg_o <= `WriteEnable;aluop_o <= `EXE_MULTU_OP;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end   `EXE_DIV:beginwreg_o <= `WriteDisable;aluop_o <= `EXE_DIV_OP;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_DIVU:beginwreg_o <= `WriteDisable;aluop_o <= `EXE_DIVU_OP;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;end`EXE_JR:beginwreg_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:beginwreg_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;enddefault:beginendendcaseenddefault: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];endendcase//op3end // 5'b00000`EXE_J:beginwreg_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:beginwreg_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;//要写入的目的寄存器的地址 寄存器$1link_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:beginwreg_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;endend`EXE_BGTZ:beginwreg_o <= `WriteDisable;aluop_o <= `EXE_BGTZ_OP;alusel_o <= `EXE_RES_JUMP_BRANCH;reg1_read_o <= 1'b1;//rsreg2_read_o <= 1'b0;instvalid <= `InstValid;if((reg1_o[31] == 1'b0)&&(reg1_o != `ZeroWord))beginbranch_target_address_o <= pc_plus_4 + imm_sll2_signedext;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot;endend`EXE_BLEZ:beginwreg_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))beginbranch_target_address_o <= pc_plus_4 + imm_sll2_signedext;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot;endend`EXE_BNE:beginwreg_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)beginbranch_target_address_o <= pc_plus_4+imm_sll2_signedext;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot;endend`EXE_REGIMM_INST:begincase(op4)`EXE_BLTZAL:begin//bltzalwreg_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<0branch_target_address_o <= pc_plus_4+imm_sll2_signedext;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot;endend`EXE_BLTZ:begin//bltzwreg_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)beginbranch_target_address_o <= pc_plus_4 + imm_sll2_signedext;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot;endend`EXE_BGEZ:begin//bgezwreg_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的值大于等于0branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot;endend`EXE_BGEZAL:begin//bgezalwreg_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)beginbranch_target_address_o <= pc_plus_4 + imm_sll2_signedext;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot;endenddefault:beginendendcase      // 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 //andiwreg_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];//rtinstvalid = `InstValid;end`EXE_XORI:begin//xoriwreg_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//luiwreg_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//prefwreg_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:beginwreg_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:beginwreg_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:beginwreg_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:beginwreg_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:beginwreg_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:beginwreg_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:beginwreg_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 ======> basereg2_read_o <= 1'b1;instvalid <= `InstValid;alusel_o <= `EXE_RES_LOAD_STORE;end`EXE_SH:beginwreg_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:beginwreg_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:beginwreg_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:beginwreg_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:beginwreg_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:beginwreg_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:beginwreg_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:beginwreg_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:beginwreg_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:beginwreg_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:beginwreg_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:beginwreg_o <= `WriteDisable;aluop_o <= `EXE_MSUBU_OP;alusel_o <= `EXE_RES_MUL;reg1_read_o <= 1'b1;reg2_read_o <= 1'b1;instvalid <= `InstValid;enddefault:beginendendcase //EXE_SPECIAL_INST2 caseend               default:beginendendcase          //case op     if(inst_i[31:21] == 11'b00000000000)begin //sll,srl,sraif(op3 == `EXE_SLL) beginwreg_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)beginwreg_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) beginwreg_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//endend       //ifend
end        //always/*       数据前推
给reg1_o赋值过程增加了两种情况
1:如果Regfile模块读端口1要读取的寄存器就是执行阶段要写的目的寄存器,那么直接把执行阶段的结果ex_wdata_i作为reg1_o的值
2:如果Regfile模块读端口1要读取的寄存器就是访存阶段要写的目的寄存器,那么直接把访存阶段的结果mem_wdata_i作为reg1_o的值*/always @ (*) beginif(rst == `RstEnable) beginreg1_o <= `ZeroWord;     end else if((reg1_read_o == 1'b1) && (ex_wreg_i == 1'b1) && (ex_wd_i == reg1_addr_o)) beginreg1_o <= ex_wdata_i; end else if((reg1_read_o == 1'b1) && (mem_wreg_i == 1'b1) && (mem_wd_i == reg1_addr_o)) beginreg1_o <= mem_wdata_i;            end else if(reg1_read_o == 1'b1) beginreg1_o <= reg1_data_i;end else if(reg1_read_o == 1'b0) beginreg1_o <= imm;end else beginreg1_o <= `ZeroWord;endendalways @ (*) beginif(rst == `RstEnable) beginreg2_o <= `ZeroWord;end else if((reg2_read_o == 1'b1) && (ex_wreg_i == 1'b1) && (ex_wd_i == reg2_addr_o)) beginreg2_o <= ex_wdata_i; end else if((reg2_read_o == 1'b1) && (mem_wreg_i == 1'b1) && (mem_wd_i == reg2_addr_o)) beginreg2_o <= mem_wdata_i;           end else if(reg2_read_o == 1'b1) beginreg2_o <= reg2_data_i;end else if(reg2_read_o == 1'b0) beginreg2_o <= imm;end else beginreg2_o <= `ZeroWord;endend//输出变量is_in_delayslot_o表示当前译码阶段指令是否是延迟槽指令
always @ (*)beginif(rst == `RstEnable)beginis_in_delayslot_o <= `NotInDelaySlot;end else begin//直接等于is_in_delayslot_iis_in_delayslot_o <= is_in_delayslot_i;end
endendmodule

inst_rom.S

   .org 0x0.set noat.set noreorder.set nomacro.global _start
_start:ori $1,$0,0x1234    # $1 = 0x00001234sw  $1,0x0($0)      # [0x0] = 0x00001234ori $2,$0,0x1234    # $2 = 0x00001234ori $1,$0,0x0       # $1 = 0x0lw  $1,0x0($0)      # $1 = 0x00001234beq $1,$2,Label     nopori $1,$0,0x4567    nopLabel:ori $1,$0,0x89ab    # $1 = 0x000089ab    nop            _loop:j _loopnop

inst_rom.data

34011234
ac010000
34021234
34010000
8c010000
10220003
00000000
34014567
00000000
340189ab
00000000
0800000b
00000000

result(reg1)

【自己动手写CPU】load相关问题相关推荐

  1. 自己动手写CPU之第五阶段(1)——流水线数据相关问题

    将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第15篇,我尽量每周四篇 上一章建立了原始的OpenMIPS五级流水线结构,可是仅仅实现了一条ori指令,从本章開始,将逐步完 ...

  2. 【自己动手写CPU】异常相关指令的实现

    MIPS架构中定义的异常类型 MIPS32架构中,有些事情打断程序的正常的执行流程,这些事情称为中断.陷阱.系统调用以及其他打断程序执行流程的情况,统称为异常. 此处的OpenMIPS处理器只实现了其 ...

  3. 自己动手写CPU(2)流水线数据相关问题

    自己动手写CPU(2)流水线数据相关问题 问题定义 流水线中经常有一些被称为"相关"的情况发生,它使得指令序列中下一条指令无法按照设计的时钟周期执行,这些"相关" ...

  4. 自己动手写CPU(8)加载存储指令的实现

    自己动手写CPU(8)加载存储指令的实现 好久没更新blog了,暑假提前放了.现在收假也该收收心了,继续捡起之前的CPU,自己开的坑不管咋样把它填完吧. 指令介绍 1.加载指令 2.存储指令 修改系统 ...

  5. 自己动手写CPU(5)简单算术操作指令实现_1

    自己动手写CPU(5)简单算数操作指令实现_1 指令介绍 MIPS32指令集架构定义的所有算术操作指令,共有21条 共有三类,分别是: 简单算术指令 乘累加.乘累减指令 除法指令 算术指令操作介绍 一 ...

  6. 自己动手写CPU(4)移动操作指令的实现

    自己动手写CPU(4)移动操作指令的实现 指令说明 MIPS32指令集架构中定义的移动操作指令共有6条: movn.movz.mfhi.mthi.mflo.mtlo,后4条指令涉及对特殊寄存器HI.L ...

  7. 自己动手写CPU(2)第一条ori指令

    本博客内容基于<自己动手写CPU>这本书 上一篇文章介绍了一下流水线思想.设计流程等,下面我们可以实操一下实现第一条ori指令. 其实实现一条ori指令不难,我目前对这一条指令的理解简单来 ...

  8. 【自己动手写CPU】第一条指令ori的实现

    验证过程 实现ori指令->建立最小SOPC->验证ori指令是否正确 ori指令说明 ori是进行逻辑"或"的运算指令 ori指令的指令码是6'b001101.处理器 ...

  9. 自己动手写CPU之第七阶段(5)——流水线暂停机制的设计与实现

    将陆续上传本人写的新书<自己动手写CPU>,今天是第28篇.我尽量每周四篇 China-pub的预售地址例如以下(有文件夹.内容简单介绍.前言): http://product.china ...

  10. 自己动手写CPU(7)转移指令的实现

    自己动手写CPU(7)转移指令的实现 分支延迟槽 在MIPS五级流水线中,一条指令被分成了五个阶段:取指.译指.执行.仿存.回写.当第一条指令的执行阶段结束时,第二条指令的译指阶段也已经结束了. 那么 ...

最新文章

  1. firewalled centos7
  2. 工作方法及总结(给自己的忠告)
  3. 如何理解Generator
  4. Jar/War/Ear等包的作用与区别详解
  5. UltraEdit正则表达式介绍及实例
  6. Angular jasmine fixture.detectChanges如何触发directive的set方法
  7. DateTime.Now.Ticks.ToString()说明
  8. 信号与系统 chapter10 系统的初值问题与系数匹配法
  9. 现代偏微分方程第1章预备知识复习题
  10. 关于 Linux 操作
  11. CQOI2015 解题报告
  12. 深入理解HashMap
  13. 训练faster rcnn报错:KeyError:‘max_overlaps’
  14. kubeadm搭建k8s集群
  15. C语言如何求最大值和最小值
  16. php 百度天气接口api接口,PHP调用百度天气接口API实现查询实时天气
  17. 商用厨房设备公司利邦国际申请纳斯达克IPO上市,募资2500万美元
  18. 中冠百年|年轻人收入低如何理财
  19. iphone导出视频 无法连接到设备_管理各种iOS设备文件的管理软件
  20. HT单片机笔记1-时钟配置(2022/2/20)

热门文章

  1. ubuntu-20.04-desktop-amd64.iso巧方法(起别名)设置python命令指向python3.8
  2. HTML 基础【2】 -- 表格标签 / 表单标签
  3. fit和transform和fit_transform的区别
  4. html引入css js,html中如何调用css和js?
  5. 博德之门2增强版存档_博德|博德之门2:增强版存档修改方法_234游戏网
  6. 【爱生活之咖啡】咖啡入坑记--冲泡篇
  7. layui分页 加下拉选择
  8. keras中构造loss曲线图像
  9. Unity换脸插件OpenCVForUnity实现换脸
  10. 为什么和平精英显示服务器未开放,《和平精英》为什么一直不开放“淘汰回放”,真的是技术原因吗?...