1.我们知道流水线有取指、译码、执行、访存、回写五个阶段,转移指令即按顺序正常进行流水线时,突然不按顺序进行,而转移执行别的指令。
2.转移指令会造成控制相关。
控制相关是指流水线中的转移指令或者其他需要改写PC的指令造成的相关。
比如:执行阶段判断是否方式转移指令,若发生则PC将不按顺序取下一指令地址,PC将取转移的指令地址。那么未取转移指令地址前,处在‘取指、译码’阶段的按顺序指令将无效,需要重新取指,就会浪费两个时钟周期。
3.为减少时钟周期的损失,引入延迟槽,且使转移指令在译码阶段进行判断、转移地址在译码阶段给出。转移指令发生时执行延迟槽指令(个人理解这个指令就是PC按顺序取指 在延迟槽指令后紧的跟下一条指令)。延迟槽指令总会发生,不管是否达到转移指令条件。
4.转移指令分为跳转指令和分支指令两种。
跳转指令:jr, jalr, j, jal .属绝对转移
分支指令:b, bal, beq, bgez, bgtz, blez, bltz, bltzal, bne。 属相对转移
(1)跳转指令:
jr:pc<-rs 将地址为rs通用寄存器的值赋给PC作新指令地址
jalr:rd<-return_address,pc<-rs 将将地址为rs通用寄存器的值赋给PC作新指令地址,跳转指令后面按顺序的第二条指令地址作返回地址保存至rd寄存器中。如果指令中未指明rd,则保存到$31寄存器中
j:pc<- (pc+4)[31:28] || target || '00' 转移新指令地址给PC,新指令地址低28位为指令inst_index左移两位值,高4位为延迟槽地址的高4位
jal:pc <- (pc+4)[31:28] || target || '00' 转移新指令地址给PC,新指令地址低28位为指令inst_index左移两位值,高4位为延迟槽地址的高4位。但还要将跳转指令后第二条指令地址作返回地址保存到$31寄存器中
(2)分支指令:
首先介绍一下转移目标地址。所有分支指令的0~15位为offset,offset左移两位,并符号扩展至32位,再与延迟槽指令地址相加,相加结果就为转移目的地址。
转移目标地址=(signed_extend)(offset || '00') + (pc+4)
beq:if rs=rt then branch 如果rs与rt寄存器值相等就发生转移,给PC转移目标地址
b: 无条件转移。是beq的特殊情况,rs rt都为0时为b指令,无需特殊实现
bgtz:if rs > 0 then branch 如果rs的值大于0,那么发生转移。
blez:if rs<=0 then branch 如果rs的值小于等于0,则发生转移。
bne:if rs rt then branch 如果rs寄存器值不等于rt寄存器值,则转移
bltz:if rs<0 then branch 如果rs寄存器值小于0,则转移
bltzal:if rs<0 then branch 如果rs寄存器值小于0,则转移,并且将转移指令后面第二条指令地址作返回地址保存到$31。
begz:if rs>=0 then branch 如果rs值大于等于0,则转移
bgezal:if rs>=0 then branch 如果rs值等于等于0,则转移,且将转移指令后第二条指令地址作返回地址保存至$31
bal:无条件转移,且将转移指令后面第二条指令作返回地址保存至$31。此指令是bgezal的特殊情况(rs=0),无需特殊实现
5.系统结构修改
(1)对于ID模块
[1.] 首先判断是否满足发生转移指令的条件,若满足,则给出发生转移指令标志信号(branch_flag_o)和转移目标地址(branch_target_address_o),送至PC模块
[2.] 同时,设置(next_inst_in_delayslot_o)给ID/EX模块,表下一指令是延迟槽指令。此信号一个时钟周期后ID/EX将is_in_delayslot_o送到ID,ID模块可据此判断当前译码阶段是否是延迟槽指令【这话好迷,我不理解】
[3.] 同时,如果转移指令要保存返回地址(返回地址写入寄存器,写使能),那么ID要送出返回地址(link_addr_o)至ID/EX模块
6.代码实现
PC模块
`include "defines.v"
`timescale 1ns/1ps
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,output reg ce);always @ (posedge clk) beginif (ce == `ChipDisable) begin //复位清零pc <= 32'h00000000;end else if(stall[0] == `NoStop) begin //流水线不暂停if(branch_flag_i == `Branch) begin pc <= branch_target_address_i; //转移条件满足给出转移地址end else beginpc <= pc + 4'h4; //转移条件不满足正常按顺序读下一条指令地址endendendalways @ (posedge clk) beginif (rst == `RstEnable) begince <= `ChipDisable; //模块禁用end else begince <= `ChipEnable; //模块可用endendendmodule
//PC:复位清零;
// 流水线不暂停|正常读下一条指令
// |判断是转移指令,读转移指令地址。否,读下一条指令
ID模块
`include "defines.v"
`timescale 1ns/1ps
module id(input wire rst,input wire[`InstAddrBus] pc_i,input wire[`InstBus] inst_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,input wire[`RegBus] reg1_data_i,input wire[`RegBus] reg2_data_i,//如果上一条指令是转移指令,那么下一条指令在译码的时候is_in_delayslot为trueinput 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 //流水线暂停请求
);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];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;assign pc_plus_4 = pc_i +4;assign imm_sll2_signedext = {{14{inst_i[15]}}, inst_i[15:0], 2'b00 }; //offset左移2位并做符号扩展assign stallreq = `NoStop;always @ (*) begin if (rst == `RstEnable) beginaluop_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; end else beginaluop_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];reg2_addr_o <= inst_i[20:16]; 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: begincase (op2)5'b00000: begincase (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 rtwreg_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 rtwreg_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 rtwreg_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<-hiwreg_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<-lowreg_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<-rswreg_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<-rswreg_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<-rsaluop_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) beginwreg_o <= `WriteEnable;end else beginwreg_o <= `WriteDisable;endend`EXE_MOVZ: begin //移动 if rt=0 then rd<-rsaluop_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 //算术 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<-rswreg_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<-rswreg_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: beginendendcaseenddefault: beginendendcase end `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^16wreg_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',后面第二条指令地址作返回地址存入$31wreg_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 branchwreg_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) beginbranch_target_address_o <= pc_plus_4 + imm_sll2_signedext; //转移目标地址branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot; endend`EXE_BGTZ: begin //转移 if rs>0 then branchwreg_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 //注意不能为0branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot; endend`EXE_BLEZ: begin //转移 if rs≤0 then branchwreg_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: begin //转移 if rs≠rt then branchwreg_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) 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_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) beginbranch_target_address_o <= pc_plus_4 + imm_sll2_signedext;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot; endend`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) beginbranch_target_address_o <= pc_plus_4 + imm_sll2_signedext;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot;endend`EXE_BLTZ: begin //转移 if rs<0 then branchwreg_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_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) beginbranch_target_address_o <= pc_plus_4 + imm_sll2_signedext;branch_flag_o <= `Branch;next_inst_in_delayslot_o <= `InDelaySlot;endenddefault: beginendendcaseend `EXE_SPECIAL2_INST: begincase ( op3 )`EXE_CLZ: begin //算术 rd<-coun_leading_zeros rswreg_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 rswreg_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: beginendendcase //EXE_SPECIAL_INST2 caseend default: beginendendcase //case opif (inst_i[31:21] == 11'b00000000000) beginif (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]; //rdinstvalid <= `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; endend //if end //else (默认赋值)end //alwaysalways @ (*) 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; //立即数有值即利用,无值默认0end else beginreg1_o <= `ZeroWord;endend //alwaysalways @ (*) begin //操作数2 同上if(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;endendalways @ (*) beginif(rst == `RstEnable) beginis_in_delayslot_o <= `NotInDelaySlot;end else beginis_in_delayslot_o <= is_in_delayslot_i; //延迟指令传递 endendendmodule
//指令是否有效
//译出运算类型及其子类型
//是否读,读的地址 (确保读到准确数,解决数据相关)
//是否写通用寄存器,写的地址
// |译出转移地址
//是否转移指令|设定下一指令为延迟槽指令next_inst_in_delayslot、当前是否为延迟槽指令is_in_delayslot_o
// |译出要保存到通用寄存器的返回地址,无设为0,有写使能
EX模块
`include "defines.v"
`timescale 1ns/1ps
module ex(input wire rst,//送到执行阶段的信息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,//HI、LO寄存器的值input wire[`RegBus] hi_i, //移动操作指令,读取HI,LO值input wire[`RegBus] lo_i,//回写阶段的指令是否要写HI、LO,用于检测HI、LO的数据相关;要改写HI、LO值,将改写后的准确值读入input wire[`RegBus] wb_hi_i,input wire[`RegBus] wb_lo_i,input wire wb_whilo_i,//访存阶段的指令是否要写HI、LO,用于检测HI、LO的数据相关input wire[`RegBus] mem_hi_i,input wire[`RegBus] mem_lo_i,input wire mem_whilo_i,input wire[`DoubleRegBus] hilo_temp_i,//从EX/MEM得到第一个执行周期的乘法结果input wire[1:0] cnt_i, //当前处于第几个周期//与除法模块相连input wire[`DoubleRegBus] div_result_i, //除法运算结果input wire div_ready_i, //除法运算是否结束(开始)//是否转移、以及link addressinput wire[`RegBus] link_address_i, //保存返回地址input wire is_in_delayslot_i, 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[`DoubleRegBus] hilo_temp_o, //将第一个执行周期的乘法结果送EX/MEMoutput reg[1:0] cnt_o, //下一时钟周期是第几个output reg[`RegBus] div_opdata1_o, //被除数output reg[`RegBus] div_opdata2_o, //除数output reg div_start_o, //是否开始除法output reg signed_div_o, //判断是否为有符号除法output reg stallreq //是否请求暂停流水线 );reg[`RegBus] logicout;reg[`RegBus] shiftres;reg[`RegBus] moveres;reg[`RegBus] arithmeticres;reg[`DoubleRegBus] mulres; //第一次乘结果,且作符号调整。第一个时钟周期后给EX/MEMreg[`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是否 = 操作数2wire reg1_lt_reg2; //操作数1是否 < 操作数2wire[`RegBus] opdata1_mult; //被乘数wire[`RegBus] opdata2_mult; //乘数wire[`DoubleRegBus] hilo_temp; //第一次乘结果,未作符号调整reg[`DoubleRegBus] hilo_temp1; //最终乘累加、累减结果。第二个时钟周期可给EX/MEMreg stallreq_for_madd_msub; reg stallreq_for_div;always @ (*) beginif(rst == `RstEnable) beginlogicout <= `ZeroWord; //逻辑end else begincase (aluop_i)`EXE_OR_OP: beginlogicout <= reg1_i | reg2_i;end`EXE_AND_OP: beginlogicout <= reg1_i & reg2_i;end`EXE_NOR_OP: beginlogicout <= ~(reg1_i |reg2_i);end`EXE_XOR_OP: beginlogicout <= reg1_i ^ reg2_i;enddefault: beginlogicout <= `ZeroWord;endendcaseend //ifend //alwaysalways @ (*) begin //移位if(rst == `RstEnable) beginshiftres <= `ZeroWord;end else begincase (aluop_i)`EXE_SLL_OP: beginshiftres <= reg2_i << reg1_i[4:0] ;end`EXE_SRL_OP: beginshiftres <= reg2_i >> reg1_i[4:0];end`EXE_SRA_OP: beginshiftres <= ({32{reg2_i[31]}} << (6'd32-{1'b0, reg1_i[4:0]})) | reg2_i >> reg1_i[4:0];//这步很妙enddefault: beginshiftres <= `ZeroWord;endendcaseend //ifend //always//减法或有符号比较运算,对源操作数2取补码,否则源操作数2不变assign reg2_i_mux = ((aluop_i == `EXE_SUB_OP) || (aluop_i == `EXE_SUBU_OP) ||(aluop_i == `EXE_SLT_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)) ?((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 @ (*) beginif(rst == `RstEnable) beginarithmeticres <= `ZeroWord;end else begincase (aluop_i)`EXE_SLT_OP, `EXE_SLTU_OP: begin //比较arithmeticres <= reg1_lt_reg2 ;end`EXE_ADD_OP, `EXE_ADDU_OP, `EXE_ADDI_OP, `EXE_ADDIU_OP,`EXE_SUB_OP, `EXE_SUBU_OP: begin //加减arithmeticres <= result_sum; end `EXE_CLZ_OP: begin //计0arithmeticres <= 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 //计数1arithmeticres <= (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 //从左向右依次找1default: beginarithmeticres <= `ZeroWord;endendcaseendend//取得乘法操作的操作数,如果是有符号除法且操作数是负数,那么取反加一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 @ (*) beginif(rst == `RstEnable) beginmulres <= {`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))beginif(reg1_i[31] ^ reg2_i[31] == 1'b1) beginmulres <= ~hilo_temp + 1; //有符号乘,结果为负取补码,正数补码是本身end else beginmulres <= hilo_temp; //无符号乘,直接做结果endend else beginmulres <= hilo_temp;endend//得到最新的HI、LO寄存器的值,此处要解决指令数据相关问题always @ (*) beginif(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}; endend always @ (*) begin //乘累加乘累减除法的流水线暂停请求stallreq = stallreq_for_madd_msub || stallreq_for_div;end//MADD、MADDU、MSUB、MSUBU指令always @ (*) beginif(rst == `RstEnable) beginhilo_temp_o <= {`ZeroWord,`ZeroWord};cnt_o <= 2'b00;stallreq_for_madd_msub <= `NoStop;end else begincase (aluop_i) `EXE_MADD_OP, `EXE_MADDU_OP: beginif(cnt_i == 2'b00) begin //第一个时钟周期,给出乘法结果,设定下一进行下一时钟周期,流水线暂停,结果为0hilo_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;endend`EXE_MSUB_OP, `EXE_MSUBU_OP: begin//同乘累加实现if(cnt_i == 2'b00) beginhilo_temp_o <= ~mulres + 1 ;cnt_o <= 2'b01;stallreq_for_madd_msub <= `Stop;end else if(cnt_i == 2'b01)beginhilo_temp_o <= {`ZeroWord,`ZeroWord}; cnt_o <= 2'b10;hilo_temp1 <= hilo_temp_i + {HI,LO};stallreq_for_madd_msub <= `NoStop;end enddefault: beginhilo_temp_o <= {`ZeroWord,`ZeroWord};cnt_o <= 2'b00;stallreq_for_madd_msub <= `NoStop; endendcaseendend //DIV、DIVU指令 always @ (*) beginif(rst == `RstEnable) beginstallreq_for_div <= `NoStop;div_opdata1_o <= `ZeroWord;div_opdata2_o <= `ZeroWord;div_start_o <= `DivStop;signed_div_o <= 1'b0;end else beginstallreq_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: beginif(div_ready_i == `DivResultNotReady) begindiv_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) begindiv_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 enddefault: beginendendcaseendend //MFHI、MFLO、MOVN、MOVZ移动指令always @ (*) beginif(rst == `RstEnable) beginmoveres <= `ZeroWord;end else beginmoveres <= `ZeroWord;case (aluop_i)`EXE_MFHI_OP: beginmoveres <= HI;end`EXE_MFLO_OP: beginmoveres <= LO;end`EXE_MOVZ_OP: beginmoveres <= reg1_i;end`EXE_MOVN_OP: beginmoveres <= reg1_i;enddefault : beginendendcaseend //elseend //alwaysalways @ (*) 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)) beginwreg_o <= `WriteDisable; //溢出不保存,写无效end else beginwreg_o <= wreg_i; end case ( alusel_i ) `EXE_RES_LOGIC: beginwdata_o <= logicout;end`EXE_RES_SHIFT: beginwdata_o <= shiftres;end `EXE_RES_MOVE: beginwdata_o <= moveres;end `EXE_RES_ARITHMETIC: beginwdata_o <= arithmeticres;end`EXE_RES_MUL: beginwdata_o <= mulres[31:0];end `EXE_RES_JUMP_BRANCH: beginwdata_o <= link_address_i;end default: beginwdata_o <= `ZeroWord;endendcaseend always @ (*) begin //要写入HI,LO数据的确定if(rst == `RstEnable) beginwhilo_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)) beginwhilo_o <= `WriteEnable;hi_o <= div_result_i[63:32];lo_o <= div_result_i[31:0]; end else if(aluop_i == `EXE_MTHI_OP) beginwhilo_o <= `WriteEnable;hi_o <= reg1_i;lo_o <= LO;end else if(aluop_i == `EXE_MTLO_OP) beginwhilo_o <= `WriteEnable;hi_o <= HI;lo_o <= reg1_i;end else beginwhilo_o <= `WriteDisable;hi_o <= `ZeroWord;lo_o <= `ZeroWord;end end endmodule
//两源操作数运算,计算写结果
// 加法直接相加,减法用源操作数1加源操作数2补码。溢出情况选中后设定是否写
// 比较:有符号看差正负
// 乘法:源操作数取补,结果据有符号乘和无符号乘看正负
// 除:DIV模块实现
//通用寄存器写结果转移确定,HI,LO寄存器写结果转移确定
//访存回写段数据相关问题的解决
//乘累加乘累减除法流水线暂停请求
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[`RegBus] hi_i,input wire[`RegBus] lo_i,input wire whilo_i, //送到回写阶段的信息output reg[`RegAddrBus] wd_o,output reg wreg_o,output reg[`RegBus] wdata_o,output reg[`RegBus] hi_o,output reg[`RegBus] lo_o,output reg whilo_o );always @ (*) beginif(rst == `RstEnable) beginwd_o <= `NOPRegAddr;wreg_o <= `WriteDisable;wdata_o <= `ZeroWord;hi_o <= `ZeroWord;lo_o <= `ZeroWord;whilo_o <= `WriteDisable; end else beginwd_o <= wd_i;wreg_o <= wreg_i;wdata_o <= wdata_i;hi_o <= hi_i;lo_o <= lo_i;whilo_o <= whilo_i; end //ifend //alwaysendmodule
仿真波形:板子型号xc7z010clg400-1
本文发布于:2024-02-05 07:41:11,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170727613464588.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |