指令集并行与开发
Tomasulo算法
1. 概念
Tomasulo 方法是一种用于在超标量处理器中执行指令并处理数据相关(数据相关性)的方法。它主要通过对指令进行乱序执行和动态调度来提高指令级并行性。
可以通过寄存器重命名消除 WAR 和 WAW 相关(通过保留站号间接实现重命名)
也可以通过总线结构在写回寄存器之前将值送入需要的指令中,消除RAW相关
乱序的能力和有关队列大小紧密相关
2.各种阻塞
WAR 读后写(先读后写)冲突(Write After Read)是指一个指令在另一个指令读取相同寄存器之后试图写入该寄存器的情况。这种情况可能会导致结果不正确或者不确定,比如有两个指令,指令1将地址a中的数据写入寄存器b,指令2将寄存器b中的内容写回地址a中,此时如果指令2提前执行了,那么就会有不确定的内容被写入地址a,导致寄存器b的内容也会错误,但是如果必须顺序执行就会发生阻塞降低执行效率
WAW 写后写冲突(Write After Write )指的是两条指令都对一个寄存器进行了写,但是有可能第一条指令的结果被其他指令依赖,但是写入以后还没读的时候就被第二条指令的结果覆盖了,这样可能造成错误结果。如果必须顺序执行,可能会专门等待依赖第一条指令的所有指令执行完才能执行第二条指令,这样效率会下降。
RAW 写后读(先写后读)冲突(Read After Write)是数据相关性的一种类型,指的是在流水线处理器中,当前指令要读取一个在之前指令写入的寄存器的数值的情况。这种数据相关性可能会导致问题,因为如果当前指令在前一条指令写入数据之前就需要读取这个数据,那么可能会读取到错误的数据或者数据尚未更新。为了解决 RAW 相关性,流水线处理器通常采用数据前推(Data Forwarding)或者暂停(Stalling)的方式来处理;暂停就是等一会,阻塞一会,数据前推即在数据计算完成后,将数据直接传递给需要使用它的指令,而不用等到写入寄存器后再读取。这样可以避免等待写入寄存器的延迟。
WAR和WAW很明显可以通过寄存器重命名解决,RAW的解决依赖于总线, 因为总线直接将值广播到了保留站,这样就能直接完成数据前推操作,缓解RAW冲突。
3. 算法结构
整个算法的执行区域与所需结构,如图2-12所示,其中保留站内容:
1)Busy:忙位
2)Op:操作码
3)Vj, Vk:源操作数的值
4)Qj, Qk:保存没有准备好的源操作数保留站号( 0 表示操作数已经准备好)。
基础算法中的经典站位为 Op - Qj Vj , Qk Vk,如果Vj Vk都准备好了,Qj Qk就都为0。同时寄存器增加一个域(结果状态域)空表示寄存器可用,否则保存产生寄存器结果依赖的保留站号(这个域的意思就是,如果是空的,可以直接去寄存器取所需的操作数;否则,就要等某一条保留站内的指令执行完毕后采用其结果,这个结果后边也是要写到对应寄存器的)。
其中结果总线除了要送回结果外,还要送回对应操作的保留站号,毕竟还有其他操作等待此保留站的指令执行完毕,要通过此保留站号来检测是否是自己所等待的内容。

图2-12 整个算法执行结构
4. 算法流程
1)发射:把操作队列的指令根据操作类型送到保留站(如果保留站有空),发射过程中读寄存器的值和结果状态域
2)执行: 如果所需的操作数都准备好, 则执行, 否则侦听结果总线并接收结果总线的值。
3)写回: 把结果送到结果总线, 释放保留站
5. 例1:基础算法
第一个例子是基础算法,后边还有加上重排序缓存的流水线,如图2-13所示。
在指令队列中有四个指令,以指令 DIV F0 F1 F2 为例,这个指令的含义为,从浮点寄存器1 2取出两个数F1 F2,对他们执行除法操作,结果保存在F0中,即F0 = F1 / F2,其他指令类似此解释。

图2-13 基础重排序算法准备阶段
1)首先发射DIV指令(F1和F2的浮点寄存器标志位都为空,所以他们都可以访问,所在乘法保留站中两个1.0都对应0,表示他们无需等待保留站结果),将指令放入乘法保留站,保留站号为3,所以浮点寄存器0中标志位置为3,表示在等待乘法保留站3中的结果写入,如图2-14所示。

图2-14 DIV发射并计算
2) 接下来发射MUL1,即第一个乘法运算,第一个操作数是F0,需要等保留站3的结果,第二个操作数F2可以直接访问,无需等结果,所以第一个操作数保留站号置为3值置为空,第二个操作数保留站置为0值置为1(保留站号为0表示无需等待),如图2-15所示。

图2-15 发射乘法运算
3) 此时第三个加法指令进入,F1,F2均已准备就绪,所以加法保留站可以填入数值,两个操作数的保留站号都置为0,如图2-16所示。

图2-16 增加加法指令
4) 发射最后一个指令MUL2,他需要F0 F2其中F0需要等待上一条的ADD操作,即等待保留站号为6的结果,而F2不需要等待,所以在保留站中其F0操作数对应的保留站号为6值置为空,F2对应为0并将值置为1,如图2-17所示。

图2-17 增加第二个乘法运算
5) 接下来,开始依次执行保留站内的指令,首先执行加法保留站内的6号指令,并将执行结果与自身的保留站号通过总线广播出去,乘法保留站1号得到结果并将其写入,寄存器0也得到结果并写入(这两个操作均通过保留站号进行判断是否是自己所需的值),如图2-18所示。

图2-18 依次执行保留站内的指令
6) 执行DIV写回,并将结果写入保留站号2内(因为他在寄存器的写入操作被ADD覆盖了,所以就不用重新写回寄存器,此时只有他在原始队列中的下一条指令MUL1需要他的结果,这也是消除 写后写WAW 的方法,以往都是通过寄存器重命名解决的,这里用保留站号代替了重命名),如图2-19所示。

图2-19 执行DIV写回
7) 后边只需要执行保留号为1的指令,并将其结果放入浮点寄存器即可,对于2号保留站,因为其他保留站内的指令都对他没有依赖,并且浮点寄存器也无需其结果,所以是无效运行(这点看指令队列也能看出来)。