自己动手写CPU之第五阶段(2)——OpenMIPS对数据相关问题的解决措施

将陆续上传本人写的新书《自己动手写CPU》(尚未出版)。今天是第16篇。我尽量每周四篇


5.2 OpenMIPS对数据相关问题的解决措施

      OpenMIPS处理器採用数据前推的方法来解决流水线数据相关问题。

通过补充完好图4-4原始的数据流图,加入部分信号使得能够完毕数据前推的工作,如图5-7所看到的。主要是将运行阶段的结果、訪存阶段的结果前推到译码阶段。參与译码阶段选择运算源操作数的过程。


      图5-8给出了为实现数据前推而对OpenMIPS系统结构所做的改动。有两个方面。

      (1)将处于流水线运行阶段的指令的运算结果,包含:是否要写目的寄存器wreg_o、要写的目的寄存器地址wd_o、要写入目的寄存器的数据wdata_o等信息送到译码阶段,如图5-8中虚线所看到的。

      (2)将处于流水线訪存阶段的指令的运算结果。包含:是否要写目的寄存器wreg_o、要写的目的寄存器地址wd_o、要写入目的寄存器的数据wdata_o等信息送到译码阶段。


      为此。译码阶段的ID模块要添加如表5-1所看到的的接口。


      译码阶段的ID模块会根据送入的信息。进行综合推断。解决数据相关,给出最后要參与运算的操作数。

ID模块的代码要做例如以下改动,当中主要改动部分使用加粗、斜体表示。改动后的代码位于本书光盘的CodeChapter5_1文件夹下的id.v文件。

module id(

	......

	//处于运行阶段的指令的运算结果
	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,
	
...... 	      
	
	//送到运行阶段的源操作数1、源操作数2
	output reg[`RegBus]           reg1_o,
	output reg[`RegBus]           reg2_o,
	......
);

       ......

       //给reg1_o赋值的过程添加了两种情况:
       //1、假设Regfile模块读port1要读取的寄存器就是运行阶段要写的目的寄存器。
       //   那么直接把运行阶段的结果ex_wdata_i作为reg1_o的值;
       //2、假设Regfile模块读port1要读取的寄存器就是訪存阶段要写的目的寄存器,
       //   那么直接把訪存阶段的结果mem_wdata_i作为reg1_o的值;
    	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模块读port2要读取的寄存器就是运行阶段要写的目的寄存器,
       //   那么直接把运行阶段的结果ex_wdata_i作为reg2_o的值;
       //2、假设Regfile模块读port2要读取的寄存器就是訪存阶段要写的目的寄存器,
       //   那么直接把訪存阶段的结果mem_wdata_i作为reg2_o的值;
	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

      除了改动译码阶段ID模块的代码,还要改动顶层模块OpenMIPS相应的代码,在当中添加图5-8所看到的的连接关系。详细改动过程不在书中列出,读者能够參考本书附带光盘的CodeChapter5_1文件夹下的openmips.v文件。

(代码会在稍后上传)

5.3 測试数据相关问题解决效果

      測试程序例如以下,当中存在5.1节讨论的RAW相关的三种情况,源文件是本书附带光盘CodeChapter5_1AsmTest文件夹下的inst_rom.S文件。

.org 0x0
.global _start
.set noat
_start:
   ori $1,$0,0x1100        # $1 = $0 | 0x1100 = 0x1100
   ori $1,$1,0x0020        # $1 = $1 | 0x0020 = 0x1120
   ori $1,$1,0x4400        # $1 = $1 | 0x4400 = 0x5520
   ori $1,$1,0x0044        # $1 = $1 | 0x0044 = 0x5564

      指令的凝视给出了预期运行效果。

将上述inst_rom.S文件,与第4章实现的Bin2Mem.exeMakefileram.ld这三个文件复制到Ubuntu虚拟机中的同一个文件夹下,打开终端,使用cd命令进入该文件夹,然后输入make  all,就可以得到可以用于ModelSim仿真的inst_rom.data文件。

      在ModelSim中新建一个project。加入本书附带光盘CodeChapter5_1文件夹下的全部.v文件。然后能够编译。再复制上面得到的inst_rom.data文件到ModelSimproject的文件夹下,就能够进行仿真了。ModelSim中新建project、仿真的具体步骤能够參考第2章。

      执行仿真,观察寄存器$1值的变化,如图5-9所看到的。$1的变化符合预期,所以改动后的OpenMIPS正确攻克了数据相关问题。



下一步将实现逻辑、移位、空指令,敬请关注!


原文地址:https://www.cnblogs.com/lytwajue/p/6772715.html