or1200处理器对数据相关的处理方法

以下内容摘自《步步惊芯——软核处理器内部设计分析》一书


      上文中提到过流水线相关的问题,本节将对流水线相关的问题进行说明。流水线中经常有一些被称为“相关”的情况发生,它使得指令序列中下一条指令无法按照设计的时钟周期执行,这些“相关”会降低流水线的性能。流水线中的相关分为三种类型:

      (1)结构相关:指令在执行的过程中,由于硬件资源满足不了指令执行的要求,发生硬件资源冲突而产生的相关。比如:指令和数据都共享一个存储器,在某个时钟周期内.流水线既要完成某条指令对存储器中数据的访问操作,又要完成后续指令的取指令操作,这样就会发生存储器访问冲突,产生结构相关。

      (2)数据相关:指在流水线中执行的几条指令中,一条指令依赖于前面指令的执行结果。

      (3)控制相关:指流水线中的分支指令或者其他需要改写PC的指令造成的相关。

      结构相关、控制相关将在后续指令分析中讨论。本小节重点讨论流水线数据相关的有关情况,同时介绍OR1200中对数据相关的处理方法。流水线数据相关又分为三种情况:RAW、WAR、WAW。

  •   RAW:Read AfterWrite,假设指令j是指令i后面执行的指令,RAW表示指令i将数据写入寄存器后,指令j才能从这个寄存器读取数据。如果指令j在指令i写入寄存器前尝试读出该寄存器的内容,将得到不正确的数据。
  •   WAR:Write AfterRead,假设指令j是指令i后面执行的指令,WAR表示指令i读出数据后,指令j才能写这个寄存器。
  •   WAW:Write AfterWrite,假设指令j是指令i后面执行的指令,WAW表示指令i将数据写入寄存器后,指令j才能将数据写入这个寄存器。

      对于OR1200处理器而言,这是一个三级流水线的处理器,从前几节对数据处理类指令的分析可知只有在流水线执行阶段才会写寄存器(实际上其余类指令也是一样的),因此不会存在WAW相关,又因为只能在流水线译码阶段读寄存器,所以不存在WAR相关,所以OR1200的流水线只存在RAW相关。在示例代码中就存在RAW相关的问题,如下部分:


……
l.add r4,r2,r3
l.sfeqi r4,0x1234
……

      在指令l.add中会写r4,随后的指令l.sfeqi会读出r4的数据进行比较运算,通过前面的分析知道l.add在执行阶段的时序逻辑中写r4,此时l.sfeqi处于译码阶段的时序逻辑,而在l.sfeqi的译码阶段的组合逻辑中已经得到了r4的值,如果得到的是修改前的值,那么l.sfeqi使用这个r4的值进行比较运算就会出现错误。如图4.5所示。使用ModelSim仿真可以更加清晰地认识到这个问题,如图4.6所示。



图4.5 流水线数据相关的示例



图4.6 ModelSim仿真波形呈现的数据相关问题


      解决这种问题的方法有三种:

      (1)插入暂停周期:当检测到相关时,在流水线中插入一些暂停周期,如图4.7所示。



图4.7 在流水线中插入暂停周期消除数据相关


      (2)编译器调度:编译器检测到相关后,可以改变部分指令的执行顺序,如图4.8所示。此时的流水线情况如图4.9所示。



4.8 编译器通过改变指令执行顺序消除相关



4.9 编译器调度改变指令的执行顺序


      (3)数据前推:将计算结果从其产生处直接送到其他指令需要处或所有有需要的功能单元处,避免流水线暂停。在OR1200中l.add在执行阶段的组合逻辑过程中会得到要写入r4的新值,可以直接将该值送入下一条指令l.sfeqi的译码阶段,从而使得l.sfeqi在译码阶段得到r4的新值,如图4.10所示。



图4.10 数据前推解决流水线相关


      OR1200就是采用数据前推的方法来解决流水线数据相关的问题。通过补充完善图4.3,添加部分信号使得可以完成数据前推的工作,如图4.11所示。主要是将WB_MUX的输出mux_out直接送入OPERAND_MUX模块的输入ex_forw,在OPERAND_MUX模块中参与ALU操作数的选择过程。



图4.11 mux_out输出到OPERAND_MUX的ex_forw实现数据前推


      假设指令j是指令i后面执行的指令,在指令i执行阶段的组合逻辑中,WB_MUX将要写入目的寄存器的值通过mux_out输出到RF的dataw,同时也输出到OPERAND_MUX的ex_forw。

      指令i处于执行阶段的组合逻辑输出的时候,指令j正处于译码阶段的组合逻辑输出,此时在CTRL模块中会判断指令j与其上一条指令i是否存在数据相关。代码如下:


or1200_ctrl.v
//此时的rf_addrw是指令i要写的目的寄存器序号,rfwb_op[0]为1,
//表示要写目的寄存器,反之不写目的寄存器,id_insn[20:16]是
//指令j需要的源寄存器rA的序号,所以此处就是判断rA是否是指
//令i要写入的寄存器

always @(rf_addrw or id_insn or rfwb_op or wbforw_valid or wb_rfaddrw)
	if ((id_insn[20:16] == rf_addrw) && rfwb_op[0])       
		sel_a = `OR1200_SEL_EX_FORW;
	else if ((id_insn[20:16] == wb_rfaddrw) && wbforw_valid)
		sel_a = `OR1200_SEL_WB_FORW;
	else
		sel_a = `OR1200_SEL_RF;


//此时的rf_addrw是指令i要写的目的寄存器序号,rfwb_op[0]为1,
//表示要写目的寄存器,反之不写目的寄存器,id_insn[15:11]是
//指令j需要的源寄存器rB的序号,所以此处就是判断rB是否是指
//令i要写入的寄存器
always @(rf_addrw or sel_imm or id_insn or rfwb_op or wbforw_valid or wb_rfaddrw)
	if (sel_imm)                                         
		sel_b = `OR1200_SEL_IMM;
	else if ((id_insn[15:11] == rf_addrw) && rfwb_op[0])  
		sel_b = `OR1200_SEL_EX_FORW;
	else if ((id_insn[15:11] == wb_rfaddrw) && wbforw_valid)
		sel_b = `OR1200_SEL_WB_FORW;
	else
		sel_b = `OR1200_SEL_RF;

      如果指令i要写目的寄存器,且指令i的目的寄存器就是指令j的源寄存器rA或者rB,则会使得sel_a或者sel_b为OR1200_SEL_EX_FORW,参考图4.11可知sel_a、sel_b都输出到OPERAND_MUX模块,后者会依据sel_a、sel_b的值选择ALU的操作数,代码如下:


or1200_operandmuxes.v
always @(ex_forw or wb_forw or rf_dataa or sel_a) begin
	casez (sel_a)	// synopsys parallel_case              
	  //如果指令j需要读取的寄存器rA正是指令i要写的目的寄存器,
	  //那么就直接把要写入的值赋给muxed_a
		`OR1200_SEL_EX_FORW:   
			  muxed_a = ex_forw;  
		`OR1200_SEL_WB_FORW:
			  muxed_a = wb_forw;
		default:
			  muxed_a = rf_dataa;  //rf_dataa是从RF的rf_a中读出的寄存器值
	endcase
end

//
// Forwarding logic for operand B register
//
always @(simm or ex_forw or wb_forw or rf_datab or sel_b) begin
	casez (sel_b)	// synopsys parallel_case
		`OR1200_SEL_IMM:
			  muxed_b = simm;
		//如果指令j需要读取的寄存器rB正是指令i要写的目的寄存器,
		//那么就直接把要写入的值赋给muxed_b
		`OR1200_SEL_EX_FORW:                     
			  muxed_b = ex_forw;                  
		`OR1200_SEL_WB_FORW:
			  muxed_b = wb_forw;
		default:
			  muxed_b = rf_datab; //rf_datab是从RF的rf_b中读出的寄存器值
	endcase
end

      而此时OPERAND_MUX模块的输入ex_forw正是WB_MUX的输出muxout,也就是指令i要写的目的寄存器的新值。从而实现了数据前推,解决了流水线数据相关问题。图4.12显示的是ModelSim仿真呈现的OR1200处理器数据相关的解决步骤。


开源处理器源代码,学习优秀的代码编写 ////////////////////////////////////////////////////////////////////// //// //// //// OR1200's ALU //// //// //// //// This file is part of the OpenRISC 1200 project //// //// http://www.opencores.org/cores/or1k/ //// //// //// //// Description //// //// ALU //// //// //// //// To Do: //// //// - make it smaller and faster //// //// //// //// Author(s): //// //// - Damjan Lampret, lampret@opencores.org //// //// //// ////////////////////////////////////////////////////////////////////// //// //// //// Copyright (C) 2000 Authors and OPENCORES.ORG //// //// //// //// This source file may be used and distributed without //// //// restriction provided that this copyright statement is not //// //// removed from the file and that any derivative work contains //// //// the original copyright notice and the associated disclaimer. //// //// //// //// This source file is free software; you can redistribute it //// //// and/or modify it under the terms of the GNU Lesser General //// //// Public License as published by the Free Software Foundation; //// //// either version 2.1 of the License, or (at your option) any //// //// later version. //// //// //// //// This source is distributed in the hope that it will be //// //// useful, but WITHOUT ANY WARRANTY; without even the implied //// //// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// //// PURPOSE. See the GNU Lesser General Public License for more //// //// details. //// //// //// //// You should have received a copy of the GNU Lesser General //// //// Public License along with this source; if not, download it //// //// from http://www.opencores.org/lgpl.shtml //// //// //// //////////////////////////////////////////////////////////////////////
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值