自己动手写CPU之第六阶段(3)——移动操作指令的实现

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

6.3 修改OpenMIPS以实现移动操作指令

6.3.1 HI、LO寄存器的实现

在HILO模块中实现HI、LO寄存器,HILO模块的接口描述如表6-1所示。

HILO模块的代码如下,源文件是本书附带光盘Code\Chapter6目录下的hilo_reg.v。整个代码很简单:在时钟上升沿,如果复位信号无效,那么就判断输入的写使能信号we是否为WriteEnable,如果是WriteEnable,那么就将输入的hi_i、lo_i的值,作为HI、LO寄存器的新值,并通过hi_o、lo_o接口输出。

module hilo_reg(

	input	wire		  clk,
	input  wire		  rst,

	// 写端口
	input wire		  we,
	input wire[`RegBus]	  hi_i,
	input wire[`RegBus]	  lo_i,

	// 读端口
	output reg[`RegBus]   hi_o,
	output reg[`RegBus]   lo_o

);

	always @ (posedge clk) begin
	  if (rst == `RstEnable) begin
		hi_o <= `ZeroWord;
		lo_o <= `ZeroWord;
	  end else if((we == `WriteEnable)) begin
		hi_o <= hi_i;
		lo_o <= lo_i;
	  end
	end

endmodule

6.3.2 修改译码阶段的ID模块

在译码阶段要增加对移动操作指令的分析,根据图6-1给出的移动操作指令格式可知,这6条指令都是SPECIAL类指令,且6-10bit均为0,需要依据0-5bit的功能码确定指令,确定指令的过程如图6-6所示。

其中涉及的宏定义如下,正是图6-1中各个指令的功能码。在本书附带光盘Code\Chapter6目录下的defines.v文件可以找到这些宏定义。

`define EXE_MOVZ  6'b001010
`define EXE_MOVN  6'b001011
`define EXE_MFHI  6'b010000
`define EXE_MTHI  6'b010001
`define EXE_MFLO  6'b010010
`define EXE_MTLO  6'b010011

译码阶段的ID模块主要修改如下。完整代码位于本书附带光盘Code\Chapter6目录下的id.v文件。

module id(
  ......
);

  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];
  ......

always @ (*) begin
......
aluop_o     <= `EXE_NOP_OP;
  alusel_o    <= `EXE_RES_NOP;
  wd_o        <= inst_i[15:11];           // 默认目的寄存器地址wd_o
  wreg_o      <= `WriteDisable;
  instvalid   <= `InstInvalid;
  reg1_read_o <= 1'b0;
  reg2_read_o <= 1'b0;
  reg1_addr_o <= inst_i[25:21];           // 默认的reg1_addr_o
  reg2_addr_o <= inst_i[20:16];           // 默认的reg2_addr_o
  imm         <= `ZeroWord;
  case (op)
    `EXE_SPECIAL_INST:		begin      // 是SPECIAL类指令
        case (op2)
	   5'b00000:			begin      // op2为5'b00000
	     case (op3)
              ......
		`EXE_MFHI: begin               // mfhi指令
                  wreg_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               // mflo指令
                  wreg_o      <= `WriteEnable;
                  aluop_o     <= `EX E_MFLO_OP;
                  alusel_o    <= `EXE_RES_MOVE;
                  reg1_read_o <= 1'b0;
                  reg2_read_o <= 1'b0;
                  instvalid   <= `InstValid;
                end
		`EXE_MTHI: begin               // mthi指令
                  wreg_o      <= `WriteDisable;
                  aluop_o     <= `EXE_MTHI_OP;
                  reg1_read_o <= 1'b1;
                  reg2_read_o <= 1'b0;
                  instvalid   <= `InstValid;
                end
		`EXE_MTLO: begin               // mtlo指令
                  wreg_o      <= `WriteDisable;
                  aluop_o     <= `EXE_MTLO_OP;
                  reg1_read_o <= 1'b1;
                  reg2_read_o <= 1'b0;
                  instvalid   <= `InstValid;
		end
		`EXE_MOVN: begin               // movn指令
                  aluop_o     <= `EXE_MOVN_OP;
                  alusel_o    <= `EXE_RES_MOVE;
                  reg1_read_o <= 1'b1;
                  reg2_read_o <= 1'b1;
                  instvalid   <= `InstValid;
                  //reg2_o的值就是地址为rt的通用寄存器的值
                  if(reg2_o != `ZeroWord) begin
	 	     wreg_o <= `WriteEnable;
	 	  end else begin
                     wreg_o <= `WriteDisable;
	 	  end
		end
		`EXE_MOVZ: begin               // movz指令
                  aluop_o     <= `EXE_MOVZ_OP;
                  alusel_o    <= `EXE_RES_MOVE;
                  reg1_read_o <= 1'b1;
                  reg2_read_o <= 1'b1;
                  instvalid   <= `InstValid;
                  //reg2_o的值就是地址为rt的通用寄存器的值
                  if(reg2_o == `ZeroWord) begin
                     wreg_o <= `WriteEnable;
                  end else begin
                     wreg_o <= `WriteDisable;
                  end
		end		  									......
endmodule

有如下几点说明。

(1)除mthi、mtlo外的其余4条移动操作指令的运算类型alusel_o均为EXE_RES_MOVE。

(2)指令mthi、mtlo需要修改HI、LO寄存器,但是不需要修改通用寄存器,所以在其译码结果中,wreg_o为WriteDisable。另外,设置reg1_read_o为1,表示需要通过Regfile模块读端口1读取通用寄存器的值,默认读取地址就是指令21-25bit的值,正是mthi、mtlo指令中的rs。读出的值作为要写入HI或LO寄存器的数据。

(3)movz指令的译码过程需要读取rs、rt寄存器的值,所以设置reg1_read_o、reg2_read_o均为1。默认通过Regfile模块读端口1读取的寄存器地址reg1_addr_o的值是指令的21-25bit,正是movz指令中的rs,默认通过Regfile模块读端口2读取的寄存器地址reg2_addr_o的值是指令的16-20bit,正是movz指令中的rt。所以,reg2_o的值就是读取到的地址为rt的寄存器的值,如果该值为0,那么设置wreg_o为WriteEnable,表示要将地址为rs的寄存器的值赋给地址为rd的寄存器,反之,wreg_o为WriteDisable,表示不赋值。

(4)movn指令的译码过程与movz指令类似,只是wreg_o为WriteEnable的条件与movz正好相反。

6.3.3 修改执行阶段

1、修改EX模块

译码阶段的结果会传递到执行阶段,执行阶段据此进行计算。考虑到执行阶段需要读写HI、LO寄存器,另外还要解决HI、LO寄存器带来的数据相关问题,所以需要给EX模块增加如表6-2所示的接口。各接口对外连接关系可以参考图6-5。

EX模块的代码修改如下。完整代码位于在本书附带光盘Code\Chapter6目录下的ex.v文件中。

module ex(

	......

	// HILO模块给出的HI、LO寄存器的值
	input wire[`RegBus]           hi_i,
	input wire[`RegBus]           lo_i,

	// 回写阶段的指令是否要写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,

       // 处于执行阶段的指令对HI、LO寄存器的写操作请求
	output reg[`RegBus]           hi_o,
	output reg[`RegBus]           lo_o,
	output reg                    whilo_o,

	......	

);

	reg[`RegBus] logicout;    // 逻辑操作的结果
	reg[`RegBus] shiftres;    // 移位操作的结果
	reg[`RegBus] moveres;     // 移动操作的结果
	reg[`RegBus] HI;          // 保存HI寄存器的最新值
	reg[`RegBus] LO;          // 保存LO寄存器的最新值

	......

/****************************************************************
**    第一段:得到最新的HI、LO寄存器的值,此处要解决数据相关问题    **
*****************************************************************/

	always @ (*) begin
	  if(rst == `RstEnable) begin
	    {HI,LO} <= {`ZeroWord,`ZeroWord};
	  end else if(mem_whilo_i == `WriteEnable) begin
	    {HI,LO} <= {mem_hi_i,mem_lo_i};   // 访存阶段的指令要写HI、LO寄存器
	  end else if(wb_whilo_i == `WriteEnable) begin
	    {HI,LO} <= {wb_hi_i,wb_lo_i};     // 回写阶段的指令要写HI、LO寄存器
	  end else begin
	    {HI,LO} <= {hi_i,lo_i};
	  end
	end	

/****************************************************************
************    第二段:MFHI、MFLO、MOVN、MOVZ指令    *************
*****************************************************************/

	always @ (*) begin
	  if(rst == `RstEnable) begin
	     moveres <= `ZeroWord;
	  end else begin
	     moveres <= `ZeroWord;
	     case (aluop_i)
	   	`EXE_MFHI_OP:	begin
                // 如果是mfhi指令,那么将HI的值作为移动操作的结果
	   	   moveres <= HI;
	   	end
	   	`EXE_MFLO_OP:	begin
                // 如果是mflo指令,那么将LO的值作为移动操作的结果
	   	   moveres <= LO;
	   	end
	   	`EXE_MOVZ_OP:	begin
                // 如果是movz指令,那么将reg1_i的值作为移动操作的结果
	   	   moveres <= reg1_i;
	   	end
	   	`EXE_MOVN_OP:	begin
                // 如果是movn指令,那么将reg1_i的值作为移动操作的结果
	   	   moveres <= reg1_i;
	   	end
	   	default : begin
	   	end
	     endcase
	  end
	end	 

/****************************************************************
***       第三段:依据运算类型alusel_i的值,确定wdata_o的值      ***
*****************************************************************/

       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
	    `EXE_RES_MOVE:	begin  // 移动操作指令的alusel_i为EXE_RES_MOVE
	 	wdata_o <= moveres;
	     end
	     default:		begin
	 	wdata_o <= `ZeroWord;
	     end
	  endcase
       end

/****************************************************************
*  第四段,如果是MTHI、MTLO指令,那么需要给出whilo_o、hi_o、lo_i的值 *
*****************************************************************/

	always @ (*) begin
	  if(rst == `RstEnable) begin
	     whilo_o <= `WriteDisable;
	     hi_o    <= `ZeroWord;
	     lo_o    <= `ZeroWord;
	  end else if(aluop_i == `EXE_MTHI_OP) begin
	     whilo_o <= `WriteEnable;
	     hi_o    <= reg1_i;
	     lo_o    <= LO;         // 写HI寄存器,所以LO保持不变
	  end else if(aluop_i == `EXE_MTLO_OP) begin
	     whilo_o <= `WriteEnable;
	     hi_o    <= HI;         // 写LO寄存器,所以HI保持不变
	     lo_o    <= reg1_i;
          end else begin
	     whilo_o <= `WriteDisable;
	     hi_o    <= `ZeroWord;
	     lo_o    <= `ZeroWord;
	   end
	 end

endmodule

上面修改的代码可以分为四段理解。

(1)第一段代码的作用是得到最新的HI、LO寄存器的值,首先判断当前处于访存阶段的指令是否要写HI、LO寄存器,即mem_whilo_o是否为WriteEnable,如果是,那么访存阶段的指令要写入的值就是HI、LO寄存器的最新值,如果不是,那么再判断当前处于回写阶段的指令是否要写HI、LO寄存器,如果是,那么回写阶段的指令要写入的值就是HI、LO寄存器的最新值,如果不是,那么从HILO模块输入的值hi_i、lo_i就是HI、LO寄存器的最新值。

(2)第二段代码的作用是针对不同的移动操作指令,确定moveres的值,变量moveres存储的是移动操作指令的结果。

(3)第三段代码的作用是依据运算类型alusel_i的值,将不同的运算结果赋给wdata_o,如果是移动操作指令,那么alusel_i为EXE_RES_MOVE,此时将moveres的值赋给wdata_o。

(4)第四段代码的作用是确定是否要写HI、LO寄存器,如果是mthi、mtlo寄存器,那么要写HI、LO寄存器,所以设置输出信号whilo_o为WriteEnable。具体地说,有如下两种情况。

  • 如果是mthi指令,那么表示要写HI寄存器,所以hi_o等于reg1_i的值,参考译码阶段的ID模块可知reg1_i的值就是在译码阶段读出的地址为rs的寄存器的值,另外,LO的值保持不变,所以lo_o等于LO。
  • 如果是mtlo指令,那么表示要写LO寄存器,所以lo_o等于reg1_i的值,参考译码阶段的ID模块可知reg1_i的值就是在译码阶段读出的地址为rs的寄存器的值,另外,HI的值保持不变,所以hi_o等于HI。

    2、修改EX/MEM模块

参考图6-5,EX模块新增加的输出接口whilo_o、hi_o、lo_o连接到EX/MEM模块,需要给EX/MEM模块添加如表6-3所示接口。

EX/MEM模块的代码修改如下。完整代码位于本书附带光盘Code\Chapter6目录下的ex_mem.v文件。主要修改的部分使用加粗、斜体表示,作用是将执行阶段得到的对HI、LO寄存器的写信息传递到访存阶段。

module ex_mem(

	input	wire			   clk,
	input  wire			   rst,

	// 来自执行阶段的信息
	input wire[`RegAddrBus]       ex_wd,
	input wire                    ex_wreg,
	input wire[`RegBus]           ex_wdata,
	input wire[`RegBus]           ex_hi,
	input wire[`RegBus]           ex_lo,
	input wire                    ex_whilo,

	// 送到访存阶段的信息
	output reg[`RegAddrBus]       mem_wd,
	output reg                    mem_wreg,
	output reg[`RegBus]           mem_wdata,
	output reg[`RegBus]           mem_hi,
	output reg[`RegBus]           mem_lo,
	output reg                    mem_whilo

);

	always @ (posedge clk) begin
	  if(rst == `RstEnable) begin
	    mem_wd    <= `NOPRegAddr;
	    mem_wreg  <= `WriteDisable;
	    mem_wdata <= `ZeroWord;
	    mem_hi    <= `ZeroWord;
	    mem_lo    <= `ZeroWord;
	    mem_whilo <= `WriteDisable;
	  end else begin
	    mem_wd    <= ex_wd;
	    mem_wreg  <= ex_wreg;
	    mem_wdata <= ex_wdata;
	    mem_hi    <= ex_hi;
	    mem_lo    <= ex_lo;
	    mem_whilo <= ex_whilo;
	  end
	end 

endmodule

6.3.4 修改访存阶段

  1、修改MEM模块

参考图6-5,EX/MEM模块新增加的输出接口mem_whilo、mem_hi、mem_lo连接到访存阶段的MEM模块,需要给MEM模块添加如表6-4所示接口。

MEM模块的代码修改如下。对应本书附带光盘Code\Chapter6目录下的mem.v文件。主要修改的部分使用加粗、斜体表示,作用是将对HI、LO寄存器的写信息传递到MEM/WB模块,后者会将这些信息传递到回写阶段。

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 @ (*) begin
	   if(rst == `RstEnable) begin
             wd_o    <= `NOPRegAddr;
             wreg_o  <= `WriteDisable;
             wdata_o <= `ZeroWord;
             hi_o    <= `ZeroWord;
             lo_o    <= `ZeroWord;
             whilo_o <= `WriteDisable;
	   end else begin
             wd_o    <= wd_i;
             wreg_o  <= wreg_i;
             wdata_o <= wdata_i;
             hi_o    <= hi_i;
             lo_o    <= lo_i;
             whilo_o <= whilo_i;
	   end
	end

endmodule

  2、修改MEM/WB模块

参考图6-5,MEM模块新增的输出接口whilo_o、hi_o、lo_o连接到MEM/WB模块,需要给MEM/WB模块添加如表6-5所示接口。

MEM/WB模块的代码修改如下。对应本书附带光盘的Code\Chapter6目录下的mem_wb.v文件。主要修改的部分使用加粗、斜体表示,作用是将对HI、LO寄存器的写信息传递到回写阶段。

module mem_wb(

	input	wire			   clk,
	input wire			   rst,

	// 访存阶段的结果
	input wire[`RegAddrBus]       mem_wd,
	input wire                    mem_wreg,
	input wire[`RegBus]           mem_wdata,
	input wire[`RegBus]           mem_hi,
	input wire[`RegBus]           mem_lo,
	input wire                    mem_whilo,

	// 送到回写阶段的信息
	output reg[`RegAddrBus]       wb_wd,
	output reg                    wb_wreg,
	output reg[`RegBus]           wb_wdata,
	output reg[`RegBus]           wb_hi,
	output reg[`RegBus]           wb_lo,
	output reg                    wb_whilo 

);

	always @ (posedge clk) begin
	   if(rst == `RstEnable) begin
             wb_wd    <= `NOPRegAddr;
             wb_wreg  <= `WriteDisable;
             wb_wdata <= `ZeroWord;
             wb_hi    <= `ZeroWord;
             wb_lo    <= `ZeroWord;
             wb_whilo <= `WriteDisable;
	   end else begin
	     wb_wd    <= mem_wd;
             wb_wreg  <= mem_wreg;
             wb_wdata <= mem_wdata;
             wb_hi    <= mem_hi;
             wb_lo    <= mem_lo;
             wb_whilo <= mem_whilo;
	   end
	end

endmodule

6.3.5 修改回写阶段

参考图6-5,MEM/WB模块输出的对HI、LO寄存器的写信息将直接送到HILO模块,包括:wb_whilo、wb_hi、wb_lo,后者据此修改HI、LO寄存器的值。

6.3.6 修改OpenMIPS顶层模块

由于本章增添了HILO模块,而且对流水线中的多个模块都增加了接口,所以需要修改OpenMIPS顶层模块,在其中将各个模块新增加的接口按照图6-5所示的关系连接起来。因为很好理解,所以具体代码不在书中罗列,读者可以参考本书附带光盘Code\Chapter6目录下的openmips.v文件。

自己动手写CPU之第六阶段(3)——移动操作指令的实现

时间: 2024-10-10 03:54:35

自己动手写CPU之第六阶段(3)——移动操作指令的实现的相关文章

自己动手写CPU之第六阶段(2)——移动操作指令实现思路

将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第21篇,我尽量每周四篇 6.2 移动操作指令实现思路 6.2.1 实现思路 这6条移动操作指令可以分为两类:一类是不涉及特殊寄存器HI.LO的指令,包括movn.movz:另一类是涉及特殊寄存器HI.LO的指令,包括mfhi.mflo.mthi.mtlo.前一类很好实现,基本思路与第5章实现逻辑.移位操作指令时类似,只需要修改ID.EX模块即可.后一类涉及到特殊寄存器HI.LO,需要为OpenMIPS添加HI.LO寄存器,以及相应

自己动手写CPU之第六阶段(1)——移动操作指令说明

将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第20篇,我尽量每周四篇 本章将实现移动操作指令,首先在6.1节介绍了MIPS32指令集架构中定义的移动操作指令的格式.作用,接着在6.2节给出移动操作指令实现思路,介绍了修改后的数据流图.新出现的数据相关问题及其解决措施,并给出了修改后的OpenMIPS系统结构图.在6.3节列出了详细的修改过程.本章最后通过一个测试程序验证移动操作指令是否实现正确. 6.1 移动操作指令说明 MIPS32指令集架构中定义的移动操作指令共有6条:m

自己动手写CPU之第六阶段(4)——验证移动操作指令实现效果

将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第23篇,我尽量每周四篇 6.4 测试程序 本节将通过一个测试程序验证为OpenMIPS处理器添加的移动操作指令是否实现正确,测试程序如下,对应本书附带光盘Code\Chapter6\AsmTest目录下的inst_rom.S文件. .org 0x0 .set noat .global _start _start: // 给寄存器$1.$2.$3.$4赋初值 lui $1,0x0000 # $1 = 0x00000000 lui $

自己动手写CPU之第五阶段(3)——MIPS指令集中的逻辑、移位与空指令

将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第17篇,我尽量每周四篇 5.4 逻辑.移位操作与空指令说明 MIPS32指令集架构中定义的逻辑操作指令有8条:and.andi.or.ori.xor.xori.nor.lui,其中ori指令已经实现了,本章要实现其余7条指令. MIPS32指令集架构中定义的移位操作指令有6条:sll.sllv.sra.srav.srl.srlv. MIPS32指令集架构中定义的空指令有2条:nop.ssnop.其中ssnop是一种特殊类型的空操作

自己动手写CPU之第七阶段(2)——简单算术操作指令实现过程

将陆续上传本人写的新书<自己动手写CPU>,今天是第25篇,我尽量每周四篇 亚马逊的预售地址如下,欢迎大家围观呵! http://www.amazon.cn/dp/b00mqkrlg8/ref=cm_sw_r_si_dp_5kq8tb1gyhja4 China-pub的预售地址如下: http://product.china-pub.com/3804025 7.2 简单算术操作指令实现思路 虽然简单算术操作指令的数目比较多,有15条,但实现方式都是相似的,与前几章逻辑.移位操作指令的实现方式也

自己动手写CPU之第七阶段(3)——简单算术操作指令实现过程(续)

将陆续上传本人写的新书<自己动手写CPU>,今天是第26篇,我尽量每周四篇 China-pub的预售地址如下(有目录.内容简介.前言): http://product.china-pub.com/3804025 亚马逊的预售地址如下,欢迎大家围观呵! http://www.amazon.cn/dp/b00mqkrlg8/ref=cm_sw_r_si_dp_5kq8tb1gyhja4 为了实现简单算术指令,需要修改译码阶段的ID模块.执行阶段的EX模块,上一篇博文中已经介绍了对译码阶段ID模块的

自己动手写CPU之第七阶段(1)——简单算术操作指令说明

将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第24篇,我尽量每周四篇 本章将实现MIPS32指令集架构定义的所有算术操作指令,共有21条,按照OpenMIPS实现这些指令的方式,可以分为三类,分别介绍如下. (1)简单算术操作指令 共有15条,包括加法.减法.比较.乘法等指令,这些指令在流水线的执行阶段都只需要一个时钟周期,而且实现思路很直观,与第4章添加逻辑操作指令类似,只需修改译码阶段的ID模块.执行阶段的EX模块,即可实现. (2)乘累加.乘累减指令 共有4条:乘累加m

自己动手写CPU之第五阶段(4)——逻辑、移位与空指令的实现

将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第18篇,我尽量每周四篇 5.5 修改OpenMIPS以实现逻辑.移位操作与空指令 为了实现逻辑.移位操作与空指令(其中nop.ssnop不用特意实现,可以认为是特殊的逻辑左移指令sll),只需要修改OpenMIPS的如下两个模块. 修改译码阶段的ID模块,用以实现对上述指令的译码. 修改执行阶段的EX模块,使其按照译码结果进行运算. 5.5.1 修改译码阶段的ID模块 首先给出如下宏定义,都在文件defines.v中定义,读者可以

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

将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第16篇,我尽量每周四篇 5.2 OpenMIPS对数据相关问题的解决措施 OpenMIPS处理器采用数据前推的方法来解决流水线数据相关问题.通过补充完善图4-4原始的数据流图,添加部分信号使得可以完成数据前推的工作,如图5-7所示.主要是将执行阶段的结果.访存阶段的结果前推到译码阶段,参与译码阶段选择运算源操作数的过程. 图5-8给出了为实现数据前推而对OpenMIPS系统结构所做的修改.有两个方面. (1)将处于流水线执行阶段的