《自己动手写CPU》8.转移指令

阅读: 评论:0

《自己动手写CPU》8.转移指令

《自己动手写CPU》8.转移指令

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小时内删除。

标签:自己动手   指令   CPU
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23