逻辑、移位操作与空指令的实现

流水线中的三种相关问题
在这里插入图片描述
相邻:即译码和回写差2T
相隔1:差1T
相隔2:同一T读不到(这种回写在regfile里已被同写同读处理掉了)
没有相隔3
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

		//读1地址和写地址相同且均使能有效时,读值直接为写值
	    else if((raddr1 == waddr) && (we == `WriteEnable) && (re1 == `ReadEnable)) begin
	    	  rdata1 <= wdata;
	    end 

三种处理数据相关的方法
在这里插入图片描述
在这里插入图片描述
采取数据前堆。加了两条回传线,把执行和访存的组合逻辑阶段回传到两个mux里
在这里插入图片描述
给译码的ID模块增加6个分别来自执行和访存的输入及相应的逻辑
在这里插入图片描述
在这里插入图片描述

	//……………………………………………………………………………………………………
	//处于执行阶段的指令要写入的目的寄存器信息
	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,
	//……………………………………………………………………………………………………
	

	//……………………………………………………………………………………………………
	//给reg1_o赋值的过程增加了两种情况
	//1.如果regfile模块读端口1要读取的寄存器就是执行阶段要写的目的寄存器
	//  那么直接把执行阶段的结果ex_wdata_i给到reg1_o
	//2.如果regfile模块读端口1要读取的寄存器就是访存阶段要写的目的寄存器
	//  那么直接把访存阶段的结果mem_wdata_i给到reg1_o
	/***************************************
	  *****  第二段:确定进行运算的源操作数1  *****
	***************************************/
	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
	
	
	//给reg2_o赋值的过程增加了两种情况
	//1.如果regfile模块读端口2要读取的寄存器就是执行阶段要写的目的寄存器
	//  那么直接把执行阶段的结果ex_wdata_i给到reg2_o
	//2.如果regfile模块读端口2要读取的寄存器就是访存阶段要写的目的寄存器
	//  那么直接把访存阶段的结果mem_wdata_i给到reg2_o
	/***************************************
	  *****  第三段:确定进行运算的源操作数2  *****
	***************************************/	
	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

endmodule

此外还要修改顶层连接,略。
8条逻辑操作 6条移位 2条空指令
sync和pref当作nop
在这里插入图片描述
四种R指令的逻辑运算:op均为6’b0,靠5:0的func功能码来判断具体操作。均为rs和rt运算后存到rd
在这里插入图片描述
2个I指令的逻辑运算,可通过op直接判断
在这里插入图片描述
lui指令:把16位立即数保存到rt寄存器高16位,低位补0
直接op判断
在这里插入图片描述
6个移位指令都是R指令,OP均为0,通过func判断
在这里插入图片描述
sra是rt右移后用rt[31]来补;
后三个的移位数从sa改为rs[4:0]
在这里插入图片描述
在这里插入图片描述
nop和ssnop处理为sll,向$0保存,直接被置0
在这里插入图片描述
需修改译码ID和执行EX
在这里插入图片描述
给出现阶段的完整宏定义

`define RstEnable 1'b1
`define RstDisable 1'b0
`define ZeroWord 32'h00000000
`define WriteEnable 1'b1
`define WriteDisable 1'b0
`define ReadEnable 1'b1
`define ReadDisable 1'b0
`define AluOpBus 7:0
`define AluSelBus 2:0
`define InstValid 1'b0
`define InstInvalid 1'b1
`define Stop 1'b1
`define NoStop 1'b0
`define InDelaySlot 1'b1
`define NotInDelaySlot 1'b0
`define Branch 1'b1
`define NotBranch 1'b0
`define InterruptAssert 1'b1
`define InterruptNotAssert 1'b0
`define TrapAssert 1'b1
`define TrapNotAssert 1'b0
`define True_v 1'b1
`define False_v 1'b0
`define ChipEnable 1'b1
`define ChipDisable 1'b0


//指令
`define EXE_AND  6'b100100
`define EXE_OR   6'b100101
`define EXE_XOR 6'b100110
`define EXE_NOR 6'b100111
`define EXE_ANDI 6'b001100
`define EXE_ORI  6'b001101
`define EXE_XORI 6'b001110
`define EXE_LUI 6'b001111

`define EXE_SLL  6'b000000
`define EXE_SLLV  6'b000100
`define EXE_SRL  6'b000010
`define EXE_SRLV  6'b000110
`define EXE_SRA  6'b000011
`define EXE_SRAV  6'b000111
`define EXE_SYNC  6'b001111
`define EXE_PREF  6'b110011

`define EXE_NOP 6'b000000
`define SSNOP 32'b00000000000000000000000001000000

`define EXE_SPECIAL_INST 6'b000000
`define EXE_REGIMM_INST 6'b000001
`define EXE_SPECIAL2_INST 6'b011100

//AluOp
`define EXE_AND_OP   8'b00100100
`define EXE_OR_OP    8'b00100101
`define EXE_XOR_OP  8'b00100110
`define EXE_NOR_OP  8'b00100111
`define EXE_ANDI_OP  8'b01011001
`define EXE_ORI_OP  8'b01011010
`define EXE_XORI_OP  8'b01011011
`define EXE_LUI_OP  8'b01011100   

`define EXE_SLL_OP  8'b01111100
`define EXE_SLLV_OP  8'b00000100
`define EXE_SRL_OP  8'b00000010
`define EXE_SRLV_OP  8'b00000110
`define EXE_SRA_OP  8'b00000011
`define EXE_SRAV_OP  8'b00000111

`define EXE_NOP_OP    8'b00000000

//AluSel
`define EXE_RES_LOGIC 3'b001
`define EXE_RES_SHIFT 3'b010

`define EXE_RES_NOP 3'b000


//指令存储器inst_rom
`define InstAddrBus 31:0
`define InstBus 31:0
`define InstMemNum 131071
`define InstMemNumLog2 17


//通用寄存器regfile
`define RegAddrBus 4:0
`define RegBus 31:0
`define RegWidth 32
`define DoubleRegWidth 64
`define DoubleRegBus 63:0
`define RegNum 32
`define RegNumLog2 5
`define NOPRegAddr 5'b00000

sll、srl、sra三条指令需[31:21]均为0
在这里插入图片描述
在这里插入图片描述

module id(
	input wire					      rst,
	input wire[`InstAddrBus]	   pc_i,			//[31:0]
	input wire[`InstBus]          inst_i,		//[31:0] 接收IF/ID模块给的指令
	
	//从regfile里输入的
	input wire[`RegBus]           reg1_data_i,	//[31:0]
	input wire[`RegBus]           reg2_data_i,	//[31:0]

	//处于执行阶段的指令要写入的目的寄存器信息
	input wire					  		ex_wreg_i,		//是否要写
	input wire[`RegBus]			   ex_wdata_i,
	input wire[`RegAddrBus]       ex_wd_i,
	
	//处于访存阶段的指令要写入的目的寄存器信息
	input wire					  		mem_wreg_i,		//是否要写
	input wire[`RegBus]			   mem_wdata_i,
	input wire[`RegAddrBus]       mem_wd_i,
	
	//送到regfile的信息
	output reg                    reg1_read_o,	//使能
	output reg                    reg2_read_o,   //使能  	
	output reg[`RegAddrBus]       reg1_addr_o,	//[4:0]
	output reg[`RegAddrBus]       reg2_addr_o,	//[4:0] 	      
	
	//送到执行阶段的信息
	output reg[`AluOpBus]         aluop_o,		//译码阶段的输出aluop_o的宽度  7:0 运算子类型
	output reg[`AluSelBus]        alusel_o,	//译码阶段的输出alusel_o的宽度 2:0 运算类型
	
	//结果写入寄存器
	output reg[`RegAddrBus]       wd_o,			//[4:0]  要写入的目的寄存器地址
	output reg                    wreg_o,		//是否有要写入的目的寄存器
	
	//这两个是最终输出的操作数
	output reg[`RegBus]           reg1_o,		//[31:0] 源操作数1
	output reg[`RegBus]           reg2_o		//[31:0] 源操作数2
);
	
	//取得指令的指令码,功能码 即分解帧格式
	//对于ori指令只需通过判断第26-31bit的值,即可判断是否是ori指令;对应I类型指令
    wire[5:0] op  = inst_i[31:26];	//op指令段
    wire[4:0] op2 = inst_i[10:6];
    wire[5:0] op3 = inst_i[5:0];
    wire[4:0] op4 = inst_i[20:16];
	 
	//保存指令执行需要的立即数[31:0]
    reg[`RegBus]	imm;
	 
	//指示指令是否有效
    reg instvalid;

	//译码操作 组合逻辑实时译码
	always @ (*) 	
		if (rst == `RstEnable) begin
			aluop_o  <= `EXE_NOP_OP;	//8'b0000_0000
			alusel_o <= `EXE_RES_NOP;	//3'b000
			wd_o   <= `NOPRegAddr;		//5'b00000
			wreg_o <= `WriteDisable;
			instvalid   <= `InstValid;	//指令有效 
			reg1_read_o <= 1'b0;
			reg2_read_o <= 1'b0;
			reg1_addr_o <= `NOPRegAddr; //5'b00000
			reg2_addr_o <= `NOPRegAddr; //5'b00000
			imm <= `ZeroWord;			
	  end 
	  else begin
			//以下是非复位且无法判断指令时的默认情况
			aluop_o  <= `EXE_NOP_OP;	//8'b0000_0000
			alusel_o <= `EXE_RES_NOP;	//3'b000
			wd_o   <= inst_i[15:11];	
			wreg_o <= `WriteDisable;
			instvalid   <= `InstInvalid;	//指令无效  
			reg1_read_o <= 1'b0;
			reg2_read_o <= 1'b0;
			//默认
			reg1_addr_o <= inst_i[25:21];	//rs寄存器	
			reg2_addr_o <= inst_i[20:16];	//rt寄存器
			imm <= `ZeroWord;		
		   case (op)
				`EXE_SPECIAL_INST: begin	//op为special 去判断op2
					case (op2)
						5'b00000:			begin	//5-2阶段非0无效 继续判断op3功能码 以此可跟sll区别
							case (op3)			//功能码	操作均是:类型与子类型,写使能、两个读使能、有无效(这几个操作要写入的寄存器就是默认的rd!)
								`EXE_OR:	begin	
									wreg_o <= `WriteEnable;		aluop_o <= `EXE_OR_OP;
									alusel_o <= `EXE_RES_LOGIC; 	reg1_read_o <= 1'b1;	reg2_read_o <= 1'b1;
									instvalid <= `InstValid;	
								end  
								`EXE_AND:	begin	
									wreg_o <= `WriteEnable;		aluop_o <= `EXE_AND_OP;
									alusel_o <= `EXE_RES_LOGIC;	  reg1_read_o <= 1'b1;	reg2_read_o <= 1'b1;	
									instvalid <= `InstValid;	
								end  	
								`EXE_XOR:	begin	
									wreg_o <= `WriteEnable;		aluop_o <= `EXE_XOR_OP;
									alusel_o <= `EXE_RES_LOGIC;		reg1_read_o <= 1'b1;	reg2_read_o <= 1'b1;	
									instvalid <= `InstValid;	
								end  				
								`EXE_NOR:	begin
									wreg_o <= `WriteEnable;		aluop_o <= `EXE_NOR_OP;
									alusel_o <= `EXE_RES_LOGIC;		reg1_read_o <= 1'b1;	reg2_read_o <= 1'b1;	
									instvalid <= `InstValid;	
								end 
								`EXE_SLLV: begin
										wreg_o <= `WriteEnable;		aluop_o <= `EXE_SLL_OP;
									alusel_o <= `EXE_RES_SHIFT;		reg1_read_o <= 1'b1;	reg2_read_o <= 1'b1;
									instvalid <= `InstValid;	
								end 
								`EXE_SRLV: begin
									wreg_o <= `WriteEnable;		aluop_o <= `EXE_SRL_OP;
									alusel_o <= `EXE_RES_SHIFT;		reg1_read_o <= 1'b1;	reg2_read_o <= 1'b1;
									instvalid <= `InstValid;	
								end 					
								`EXE_SRAV: begin
									wreg_o <= `WriteEnable;		aluop_o <= `EXE_SRA_OP;
									alusel_o <= `EXE_RES_SHIFT;		reg1_read_o <= 1'b1;	reg2_read_o <= 1'b1;
									instvalid <= `InstValid;			
								end			
								`EXE_SYNC: begin
									wreg_o <= `WriteDisable;		aluop_o <= `EXE_NOP_OP;
									alusel_o <= `EXE_RES_NOP;		reg1_read_o <= 1'b0;	reg2_read_o <= 1'b1;
									instvalid <= `InstValid;	
								end								  									
								default:	begin
								end
							endcase
						end
						default: begin
						end
					endcase	
				end
				
				//这几个写入的寄存器不同,所以单独赋值wd_o
				`EXE_ORI:	begin           //ORI指令 用立即数和rs计算后写入rt
					alusel_o    <= `EXE_RES_LOGIC;
					aluop_o 	   <= `EXE_OR_OP;
					wreg_o      <= `WriteEnable;
					wd_o        <= inst_i[20:16];	//立即数与rs的结果写入rt
					imm         <= {16'h0,inst_i[15:0]};
					reg1_read_o <= 1'b1;				//要去读一个rs
					reg2_read_o <= 1'b0;
					instvalid 	<= `InstValid;
				end 

				`EXE_ANDI:			begin
					wreg_o <= `WriteEnable;		aluop_o <= `EXE_AND_OP;
					alusel_o <= `EXE_RES_LOGIC;	reg1_read_o <= 1'b1;	reg2_read_o <= 1'b0;	  	
					imm <= {16'h0, inst_i[15:0]};		wd_o <= inst_i[20:16];		  	
					instvalid <= `InstValid;	
				end
				
				`EXE_XORI:			begin
					wreg_o <= `WriteEnable;		aluop_o <= `EXE_XOR_OP;
					alusel_o <= `EXE_RES_LOGIC;	reg1_read_o <= 1'b1;	reg2_read_o <= 1'b0;	  	
					imm <= {16'h0, inst_i[15:0]};		wd_o <= inst_i[20:16];		  	
					instvalid <= `InstValid;	
				end
				
				`EXE_LUI:			begin
					wreg_o <= `WriteEnable;		aluop_o <= `EXE_OR_OP;
					alusel_o <= `EXE_RES_LOGIC; reg1_read_o <= 1'b1;	reg2_read_o <= 1'b0;	  	
					imm <= {inst_i[15:0], 16'h0};		wd_o <= inst_i[20:16];		  	
					instvalid <= `InstValid;	
				end	
				
				`EXE_PREF:			begin
					wreg_o <= `WriteDisable;		aluop_o <= `EXE_NOP_OP;
					alusel_o <= `EXE_RES_NOP; reg1_read_o <= 1'b0;	reg2_read_o <= 1'b0;	  	  	
					instvalid <= `InstValid;	
				end	
				
				default:;			
		  endcase
		  
		  //sll、srl、sra	把移位数给到imm,作为1个源操作数
		  if(inst_i[31:21] == 11'b00000000000) begin	//新的位段判断指令
				if (op3 == `EXE_SLL) begin
					wreg_o <= `WriteEnable;		aluop_o <= `EXE_SLL_OP;
					alusel_o <= `EXE_RES_SHIFT; reg1_read_o <= 1'b0;	reg2_read_o <= 1'b1;	  	
					imm[4:0] <= inst_i[10:6];		wd_o <= inst_i[15:11];
					instvalid <= `InstValid;	
				end 
				else if ( op3 == `EXE_SRL ) begin
					wreg_o <= `WriteEnable;		aluop_o <= `EXE_SRL_OP;
					alusel_o <= `EXE_RES_SHIFT; reg1_read_o <= 1'b0;	reg2_read_o <= 1'b1;	  	
					imm[4:0] <= inst_i[10:6];		wd_o <= inst_i[15:11];
					instvalid <= `InstValid;	
				end 
				else if ( op3 == `EXE_SRA ) begin
					wreg_o <= `WriteEnable;		aluop_o <= `EXE_SRA_OP;
					alusel_o <= `EXE_RES_SHIFT; reg1_read_o <= 1'b0;	reg2_read_o <= 1'b1;	  	
					imm[4:0] <= inst_i[10:6];		wd_o <= inst_i[15:11];
					instvalid <= `InstValid;	
				end
		  end			  
	  
		end       
	       
	
	//确定2个源操作数
	always@(*)
		if(rst == `RstEnable)
			reg1_o <= `ZeroWord;
		else if((reg1_read_o == 1'b1)&&(ex_wreg_i == 1'b1)&&(reg1_addr_o == ex_wd_i))
			reg1_o <= ex_wdata_i;
		else if((reg1_read_o == 1'b1)&&(mem_wreg_i == 1'b1)&&(reg1_addr_o == mem_wd_i))
			reg1_o <= mem_wdata_i;		
		else if(reg1_read_o == 1'b1)
			reg1_o <= reg1_data_i;
		else if(reg1_read_o == 1'b0)
			reg1_o <= imm;
		else
			reg1_o <= `ZeroWord;
		
	always@(*)
		if(rst == `RstEnable)
			reg2_o <= `ZeroWord;
		else if((reg2_read_o == 1'b1)&&(ex_wreg_i == 1'b1)&&(reg2_addr_o == ex_wd_i))
			reg2_o <= ex_wdata_i;
		else if((reg2_read_o == 1'b1)&&(mem_wreg_i == 1'b1)&&(reg2_addr_o == mem_wd_i))
			reg2_o <= mem_wdata_i;				
		else if(reg2_read_o == 1'b1)
			reg2_o <= reg2_data_i;
		else if(reg2_read_o == 1'b0)
			reg2_o <= imm;
		else
			reg2_o <= `ZeroWord;

endmodule

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
对应修改执行模块EX。EX相比于ID没有那么多项,因为把相同的操作合并了

`include "defines.v"

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,

	//执行结果
	output reg[`RegAddrBus]       wd_o,
	output reg                    wreg_o,
	output reg[`RegBus]			   wdata_o
	
);
	//保存逻辑运算的结果
	reg[`RegBus] logicout;	//保存逻辑运算结果
	reg[`RegBus] shiftres;	//保存移位运算结果
	
	//根据大类型判断输出
   always @ (*) begin
 	   wd_o   <= wd_i;		//传递写目的寄存器地址	 	 	
 	   wreg_o <= wreg_i;		//传递寄存器写使能信号
 	   case ( alusel_i ) 
 	   	`EXE_RES_LOGIC:	begin
 	   		wdata_o <= logicout;
 	   	end
			`EXE_RES_SHIFT:		begin
				wdata_o <= shiftres;
			end	 			
 	   	default: begin
 	   		wdata_o <= `ZeroWord;
 	   	end
 	   endcase
   end	
	
	//根据小类型作逻辑运算
	always @ (*) 
		if(rst == `RstEnable) begin
			logicout <= `ZeroWord;
		end 
		else begin
			case (aluop_i)
				`EXE_OR_OP:			begin
					logicout <= reg1_i | reg2_i;
				end
				`EXE_AND_OP:		begin
					logicout <= reg1_i & reg2_i;
				end
				`EXE_NOR_OP:		begin
					logicout <= ~(reg1_i |reg2_i);
				end
				`EXE_XOR_OP:		begin
					logicout <= reg1_i ^ reg2_i;
				end
				default:			begin
					logicout <= `ZeroWord;
				end
			endcase
		end    
		
	//根据小类型作移位运算
	always @ (*) 
		if(rst == `RstEnable) begin
			shiftres <= `ZeroWord;
		end 
		else begin
			case (aluop_i)
				`EXE_SLL_OP:		begin
					shiftres <= reg2_i << reg1_i[4:0] ;
				end
				`EXE_SRL_OP:		begin
					shiftres <= reg2_i >> reg1_i[4:0];
				end
				`EXE_SRA_OP:		begin	//sra和srav都是这个指令
					shiftres <= ({32{reg2_i[31]}} << (6'd32-{1'b0, reg1_i[4:0]})) 
												| reg2_i >> reg1_i[4:0];
				end
				default:				begin
					shiftres <= `ZeroWord;
				end
			endcase
		end 
			
endmodule

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值