当前位置: 首页 > news >正文

电子商务网站建设外包服务的企业百度搜索引擎广告

电子商务网站建设外包服务的企业,百度搜索引擎广告,网站主导航设置问题,万网域名管理逻辑,移位操作与空指令的添加 综述ID模块的修改EX模块的修改仿真验证I-型指令luioriandixorixor&nor R-型指令orand 移位类指令sllsrlsrasllvsrlvsravssnop、nop 综述 文章引于自己动手写CPU之第五阶段(3)——MIPS指令集中的逻辑、移位与…

逻辑,移位操作与空指令的添加

  • 综述
  • ID模块的修改
  • EX模块的修改
  • 仿真验证
    • I-型指令
      • lui
      • ori
      • andi
      • xori
      • xor&nor
    • R-型指令
      • or
      • and
    • 移位类指令
      • sll
      • srl
      • sra
      • sllv
      • srlv
      • srav
      • ssnop、nop

综述

文章引于自己动手写CPU之第五阶段(3)——MIPS指令集中的逻辑、移位与空指令
指令描述参考与博文[BOOK],感谢博主的分享!!!
在这里插入图片描述
由于那个指令具有不同的指令格式,但一共就只有三种,因此这里将其进行区分,进行译码以及执行相关代码需要进行修改。这里笔者直接加入的指令,具体的指令作用在书中或者博文中都很明确,有需要可以自行翻阅查看。
照例笔者会将自己对于代码的理解以及相关的必要知识记录总结在对应的目录下

ID模块的修改

首先是要确定指令的类型,这里对对应的指令进行区分,使用的方式是首先判断op,然后若是op下有对应的指令,依次同理进行判断。注意这里有一个例外情况就是使用inst_i[31:21]进行判断,这里是单独分开进行判断的。具体见代码。由于具体的指令,使用的寄存器数量不同,对于每一个数据的处理也是不同的,具体可以在书中找到对应的操作,然后对应代码中查看。
在这里插入图片描述

`timescale 1ns / 1ps
`include "defines.v"
module id(input 	wire 						rst				,input 	wire 	[`InstAddrBus]		pc_i			,input 	wire 	[`InstBus]			inst_i			,//读取regfile的值input 	wire 	[`InstBus]			reg1_data_i		,input 	wire 	[`InstBus]			reg2_data_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 	[`RegAddrBus]		ex_wd_i 		,		//执行阶段的目的寄存器地址input 	wire 		 				ex_wreg_i 		,		//是否要写入数据标志	input 	wire 	[`RegBus]			ex_wdata_i 		,		//执行阶段送到访存的数据//处于访存阶段的指令运行的运算结果input  wire 	[`RegAddrBus]		mem_wd_i 		,input  wire 		 				mem_wreg_i 		,input  wire 	[`RegBus]			mem_wdata_i 	);
//取得指令的指令码,功能码
//用于ori指令只需要判断21-31 bit的值,即可判断是否是ori指令
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;/*********************************************************************************
***************************	第一阶段:对指令进行译码	***************************
*********************************************************************************/always @ (*)
beginif(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				;endelse 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]		;//默认通过Regfile读取端口1的寄存器地址reg2_addr_o		<=	inst_i[20:16]		;//默认通过Regfile读取端口2的寄存器地址	imm 			<= 	`ZeroWord			;case(op)`EXE_SPECIAL_INST :begincase(op2) 5'b0000_0:begincase(op3)`EXE_OR:beginwreg_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;alusel_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;alusel_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;alusel_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_SRL_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_SRA_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_SHIFT;reg1_read_o <= 1'b0;reg2_read_o <= 1'b1;instvalid 	<= `InstValid;enddefault:beginendendcaseenddefault:beginendendcaseend`EXE_ORI:		//判断op的值是进行opi指令begin						wreg_o 		<= `WriteEnable 		;					//ori 指令需要将结果写入目的寄存器,所以wreg_o 为 WriteEnable						aluop_o 	<= `EXE_OR_OP 	 		; 					//运算的子类型是逻辑“或”运算						alusel_o 	<= `EXE_RES_LOGIC 		;					//运算类型是逻辑运算reg1_read_o <= 1'b1					;					//需要通过Regfile的读端口1读取寄存器reg2_read_o <= 1'b0					;					//不需要通过Regfile的读端口2读取寄存器imm 		<= {16'h0,inst_i[15:0]} ;					//指令执行需要的立即数						wd_o 		<= inst_i[20:16] 		;					//执行指令要写入的目的寄存器地址						instvalid 	<= `InstValid 			; 					//ori指令是有效的end`EXE_ANDI:beginwreg_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:beginwreg_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:beginwreg_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:beginwreg_o 		<= `WriteDisable 		;aluop_o 	<= `EXE_NOP_OP 	 		; alusel_o 	<= `EXE_RES_NOP 		;reg1_read_o <= 1'b0					;reg2_read_o <= 1'b0					;instvalid 	<= `InstValid 			; enddefault: beginendendcaseif(inst_i[31:21] == 11'b0000_0000_000) begin if(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 		;endelse 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 		;endelse 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 		;endendend
end/*********************************************************************************
***************************	第二阶段:确定进行运算的源操作数1***************************
*********************************************************************************/
//regfile读端口1的输出值
always @ (*)
beginif(rst == `RstEnable)reg1_o <= `ZeroWord;else // 对于源操作数,若是目前端口的读取得寄存器数据地址是  执行阶段的要写入的目的寄存器  ,那么直接将执行的结果作为reg1_o的值。//这个数相当于是要写入的数据if((reg1_read_o == 1'b1) && (ex_wreg_i == 1'b1) && (ex_wd_i == reg1_addr_o) )reg1_o <= ex_wdata_i;	else//对于要是目的寄存器,我们要读取的寄存器其实是最终访存要写入的寄存器,那么访存的数据就直接作为源操作数进行处理if((reg1_read_o == 1'b1) && (mem_wreg_i == 1'b1) && (mem_wd_i == reg1_addr_o) )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;
end/*********************************************************************************
***************************	第三阶段:确定进行运算的源操作数2***************************
*********************************************************************************/
//regfile读端口2的输出值
always @ (*)
beginif(rst == `RstEnable)reg2_o <= `ZeroWord;else // 对于源操作数,若是目前端口的读取得寄存器数据地址是  执行阶段的要写入的目的寄存器  ,那么直接将执行的结果作为reg2_o的值。//这个数相当于是要写入的数据if((reg2_read_o == 1'b1) && (ex_wreg_i == 1'b1) && (ex_wd_i == reg2_addr_o) )reg2_o <= ex_wdata_i;	else//对于要是目的寄存器,我们要读取的寄存器其实是最终访存要写入的寄存器,那么访存的数据就直接作为源操作数进行处理if((reg2_read_o == 1'b1) && (mem_wreg_i == 1'b1) && (mem_wd_i == reg2_addr_o) )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;
end
endmodule

EX模块的修改

执行阶段对于不同数,以及不同的信息进行处理。新建寄存器用于保存移位寄存器的结果,根据指令类型对象对相应的数据进行输出。

`timescale 1ns / 1ps
`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 	;// 移动操作的结果
reg [`RegBus] 	moveres 	;/*********************************************************************************
***************	依据aluop_i指示的运算子类型进行运算,
*********************************************************************************/always @ (*)
beginif( rst == `RstEnable)logicout <= `ZeroWord;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:logicout <= `ZeroWord;endcase;end
endalways @ (*)
beginif(rst == `RstEnable)shiftres <= `ZeroWord;else case(aluop_i)`EXE_SLL_OP:		//逻辑左移shiftres <= reg2_i << reg1_i[4:0];`EXE_SRL_OP:shiftres <= reg2_i >> reg1_i[4:0];`EXE_SRA_OP:shiftres <= ( {32{ reg2_i[31]} } << (6'd32 - {1'b0,reg1_i[4:0] } ) ) | reg2_i >> reg1_i[4:0];default:beginshiftres <= `ZeroWord;end endcase
end/*********************************************************************************
***************	第二阶段:依据alusel_i指示的运算类型,确定wdata_o的值
*********************************************************************************/
always @ (*)
beginwd_o <= wd_i;				//wd_o等于wd_i,要写入的寄存器地址wreg_o <= wreg_i;			//wreg_o等于wreg_i,表示是否要写入目的寄存器case(alusel_i)`EXE_RES_LOGIC:beginwdata_o <= logicout;		//wdata_o中存放逻辑运算运算结果end`EXE_RES_SHIFT:beginwdata_o <= shiftres;		//wdata_o中存放位移运算运算结果end`EXE_RES_MOVE:beginwdata_o <= moveres;			//指令为EXE_RES_MOVEenddefault:wdata_o <= `ZeroWord;endcase
end
endmodule

仿真验证

测试逻辑操作
在这里插入图片描述
首先分析测试数据。OpenMIPS将指令转换为ori指令来执行。lui指令使用立即数(扩展后的立即数)做或运算。得到0x01010000
之后进行两次或运算,将数据分别写入寄存器1与寄存器2中。
接下来是使用寄存器中的数据进行或运算,将结果送入1寄存器。
然后使用立即数与寄存器中的数据进行与运算,结果送入寄存器3,在使用寄存器1与寄存器3中的数据相与结果送寄存器1,然后使用寄寄存器1中的数据与立即数相异或,之后分别使用寄存器中的数据进行两次运算即可。
在这里插入图片描述

I-型指令

在这里插入图片描述

lui

  lui: 把立即数加载到寄存器高位。

在这里插入图片描述

ori

逐位逻辑操作指令
在这里插入图片描述

andi

逐位逻辑操作指令在这里插入图片描述

xori

逐位逻辑操作指令
异或运算指令使用方法为:xori rt, rs, immediate
指令作用为:rt <- rs XOR zero_extended(immediate)。将地址为rs的通用寄存器的值。与指令中马上数进行零扩展后的值进行逻辑“异或”运算,运算结果保存到地址为rt的通用寄存器中。

xor&nor

逐位逻辑操作指令在这里插入图片描述

R-型指令

在这里插入图片描述

or

逐位逻辑操作指令在这里插入图片描述

and

逐位逻辑操作指令

在这里插入图片描述
在这里插入图片描述
得到的数据与书中预期一致。

测试移位操作与空指令
这里笔者不一一分析,这里指出一个问题,是在第六行的空指令,加上会多一个时钟周期,不加会少一个时钟周期。自己看仿真图即可理解。这里依据给出的源文件,期间分析应该有五个时钟周期的延时。
简单分析,在复位后,第五个时钟上升沿,寄存器2开始有数据,然后更新,之后的四个时钟周期,对寄存器1,5,8进行操作,因此加上其本身,一个维持五个时钟周期。书中是维持了四个时钟周期,是不对的。
在这里插入图片描述
在这里插入图片描述
不加时候的仿真截图
在这里插入图片描述
加上之后的
在这里插入图片描述
这里书中给出的是四个时钟周期的延时。这里上边已经进行了分析。
在这里插入图片描述
在这里插入图片描述

移位类指令

在这里插入图片描述

sll

当功能码是6’b000000,表示是sll指令,逻辑左移
指令使用方法为:sll rd, rt, sa

  指令作用为:rd <- rt << sa (logic),将地址为rt的通用寄存器的值,向左移sa位。空出来的位置使用0填充。结果保存到地址为rd的通用寄存器中。

srl

当功能码是6’b000010,表示是srl指令。逻辑右移
指令使用方法为:srl rd, rt, sa

  指令作用为:rd <- rt >> sa (logic),将地址为rt的通用寄存器的值,向右移sa位,空出来的位置使用0填充,结果保存到地址为rd的通用寄存器中。

sra

当功能码是6’b000011。表示是sra指令,算术右移
指令使用方法为:sra rd, rt, sa

  指令作用为:rd <- rt >> sa (arithmetic),将地址为rt的通用寄存器的值,向右移sa位。空出来的位置使用rt[31]的值填充,结果保存到地址为rd的通用寄存器中。

sllv

当功能码是6’b000100。表示是sllv指令,逻辑左移
指令使用方法为:sllv rd, rt, rs

  指令作用为:rd <- rt << rs[4:0](logic)。将地址为rt的通用寄存器的值。向左移位,空出来的位置使用0填充,结果保存到地址为rd的通用寄存器中。移位位数由地址为rs的寄存器值的0-4bit确定。

srlv

当功能码是6’b000110,表示是srlv指令。逻辑右移
指令使用方法为:srlv rd, rt, rs

  指令作用为:rd <- rt >> rs[4:0](logic),将地址为rt的通用寄存器的值,向右移位,空出来的位置使用0填充。结果保存到地址为rd的通用寄存器中。

移位位数由地址为rs的寄存器值的0-4bit确定。

srav

当功能码是6’b000111,表示是srav指令,算术右移
指令使用方法为:srav rd, rt, rs

  指令作用为:rd <- rt >> rs[4:0](arithmetic),将地址为rt的通用寄存器的值,向右移位。空出来的位置使用rt[31]填充,结果保存到地址为rd的通用寄存器中。

移位位数由地址为rs的寄存器值的0-4bit确定。

  总结来说。这六条移位操作指令能够分为两种情况:sllv、srav、srlv这3条指令的助记符最后有“v”。表示移位位数是通过寄存器的值确定的,sll、sra、srl这3条指令的助记符最后没有“v”,表示移位位数就是指令中6-10bit的sa的值。

在这里插入图片描述

ssnop、nop

空操作
nop:相当于 sll zero,zero,o,
ssnop: equals sll zero,zero,1. 这个指令不得与其它指令同时发送,这样就保证了其运行要花费至少一个时钟周期。这在简单的流水线的CPU上无关紧要,但在复杂些的实现上对于实现强制的延时很有用。
在这里插入图片描述
另外,MIPS32指令集架构中还定义了sync、pref这2条指令,当中sync指令用于保证载入、存储操作的顺序,对于OpenMIPS而言,是严格依照指令顺序运行的,载入、存储操作也是依照顺序进行的,所以能够将sync指令当作nop指令处理,在这里将其归纳为空指令。pref指令用于缓存预取,OpenMIPS没有实现缓存,所以也能够将pref指令当作nop指令处理,此处也将其归纳为空指令。

http://www.mmbaike.com/news/52991.html

相关文章:

  • 免费网站空间10g深圳企业黄页网
  • 淄博百度网站建设贴吧aso优化贴吧
  • 网站布局是什么样的seo全称是什么意思
  • 庞各庄网站建设公司网络推广怎么赚钱
  • 企业网站模板免费版最新旅游热点
  • 哪些公司需要网站开发工程师谷歌推广培训
  • 社区类网站开发今天的新闻 最新消息
  • 阜阳市建设局网站seo优化推广流程
  • 成都网站建设公司盈利吗刚刚地震最新消息今天
  • 网站做会员系统天津快速关键词排名
  • 盐渎网软媒win7优化大师
  • 全国特种作业人员证查询系统网站怎么优化排名
  • 廊坊百度网站推广一键开发小程序
  • 加强政府门户网站建设与管理网络热词2021
  • 这几年做哪些网站能致富暴疯团队seo课程
  • 无锡做网站公司能让网络非常流畅的软件
  • 调查网站做调查不容易过网络媒体软文案例
  • 三九手机网官网优化公司哪家好
  • 机械类毕业设计代做网站推荐太原自动seo
  • 微博网站认证 备案名称跨境电商平台有哪些
  • 大连大型网站制作公司小红书推广策略
  • 独立站都有哪些免费推广工具有哪些
  • 做网站上传那个目录余姚网站如何进行优化
  • 织梦笑话网站产品网络营销策划
  • .net 手机网站开发杭州seo价格
  • 打金新开传奇网站牛奶软文广告营销
  • 网站建设的税率是多少钱电子商务营销方法
  • 免费的网站域名企业网站怎么推广
  • java做门户网站seo建站收费地震
  • 防止网站扫描百度站长平台论坛