计算机系统结构:指令的动态调度-记分牌算法

记分牌算法和Tomasulo算法是两种比较典型的动态调度算法。记分牌算法历史现在仍在某些地方根据需求被使用。Tomasulo算法已经比计分牌算法改进了许多,是一种更强的算法。许多开发指令级并行的现代处理机都采用了Tomasulo算法或其变形。本文讨论记分牌算法。

基本思想

目标是在没有结构冲突的时候,尽可能早地执行没有数据冲突的指令。如果某条指令被暂停,而后面的指令与流水线中正在执行或被暂停的指令都不相关,那么这些指令就可以跨越它们,继续流出和执行下去。也就是说,指令可以按序流出,可以乱序执行和乱序完成。

记分牌全面负责和管理这些指令的流出和执行,当然也包括检测所有的冲突。

算法

我用一个采用记分牌的处理器的简单例子来说明计分牌的算法:
在这里插入图片描述
每条指令都要经过记分牌。
记分牌负责检测相关,控制指令的流出和执行。
如果指令不能马上执行,记分牌可以检测硬件中信息的每一个变化,一旦所需的操作数就绪,就立即启动该指令的执行。那么记分牌记录的信息有哪些才能做到这一点呢?它记录的信息由三部分构成:
用容易记忆的话说就是“三张表”
(1)指令状态表:记录正在执行的各条指令已经进入到了哪一段。
(2)功能部件状态表:记录各个功能部件的状态。每个功能部件有一项,每一项由以下9个字段组成。
Busy:指出功能部件是否忙,初值为no;
Op:该功能部件正在执行或将要执行的操作;
Fi:目的寄存器编号;
Fj, Fk:源寄存器编号;
Qj, Qk:指出向源寄存器Fj、Fk写数据的功能部件(即Fj、Fk中的数据将由它们产生);
Rj,Rk:标志位,yes表示Fj,Fk中的操作数就绪且还未被取走,否则就被置为no。
(3)结果寄存器状态表Result:每个寄存器在该表中有一项,用于指出哪个功能部件(编号)将把结果写入该寄存器。如果当前正在运行的指令都不以它为目的寄存器,则其相应项置为no。Result 各项的初值为 no(全零)。
在这里插入图片描述
通过这三张表,记分牌就可以控制指令的执行。

每条指令的执行过程分为4段:
流出、读操作数、执行、写结果
1)流出
如果当前流出指令所需的功能部件空闲(检测结构相关),并且所有其它正在执行的指令的目的寄存器与该指令不同(检测WAW冲突),记分牌就向功能部件流出该指令,并修改记分牌内部的记录表。

2)读操作数
对于给定寄存器来说,如果前面已流出且还在执行的执行都不对该寄存器进行写操作,则该寄存器的数据可用(解决RAW冲突)

3)执行
执行产生结果后,就通知记分牌它已经完成执行。

4)写结果
记分牌一旦知道执行部件完成了执行,就检测是否存在WAR冲突。没有WAR冲突再写结果

为了描述问题,对一些符号做如下约定:

FU:当前指令所要用的功能部件
D:目的寄存器
S1、S2:源操作数寄存器
Op:要进行的操作
Fj[FU]:功能部件FU的Fj字段(其它字段以此类推)
Result[D]:结果寄存器状态表中寄存器D所对的项,存放的是将写入寄存器D的功能部件

具体控制过程如下:

1)指令流出阶段
注意指令必须按序流出:
(1)进入条件:
not Busy[FU] & not Result[D]; // 功能部件空闲且没有WAW冲突
(2)记分牌内容修改
Busy[FU] ← \leftarrow yes; // 把当前指令所要用的功能部件是否占用改为yes;
Op[FU] ← \leftarrow Op; // 记录操作码
Fi[FU] ← \leftarrow D; // 记录目的寄存器
Fj[FU] ← \leftarrow S1; // 记录第一个源寄存器
Fk[Fu] ← \leftarrow S2; // 记录第二个源寄存器
Qj[FU] ← \leftarrow Result[S1]; // 将产生第一个源操作数的部件
Qk[FU] ← \leftarrow Result[S2]; // 将产生第二个源操作数的部件
Rj[FU] ← \leftarrow not Qj[FU]; // 第一个源操作数是否可用,如果Qj[FU]为no就表示没有部件要写S1,数据可用
Rk[FU] ← \leftarrow not Qk[FU]; // 第二个源操作数是否可用,如果Qk[FU]为no就表示没有部件要写S2,数据可用
Result[D] ← \leftarrow FU; // 结果寄存器状态表的D项改为该条指令要使用的部件

2)读操作数
(1)进入条件
Rj[FU] ← \leftarrow $ Rk[FU]; //两个源操作数都已就绪
(2)记分牌内容修改
Rj[FU] ← \leftarrow no; // 已经读走了就绪的第一个源操作数
Rk[FU] ← \leftarrow no; // 已经读走了就绪的第二个源操作数

3)执行
(1)结束条件
功能部件操作结束

4)写结果
(1)进入条件
∀ \forall f: ( Fj[f] ≠ Fi[FU] or Rj[f] = no ) & (Fk[f] ≠ Fi[FU] or Rk[f] = no);// 不存在 WAR 冲突
(2)r记分牌内容修改
∀ \forall f: (if Qj[f]=FU then Rj[f] ← \leftarrow yes ,Qj[f] ← \leftarrow 0 ) ;// 如果有部件的第一个源操作数在等待该结果,则将其Rj操作数就绪置为yes,将Qj等待其它部件置为0;
∀ \forall f: (if Qk[f]=FU then Rk[f] ← \leftarrow yes ,Qj[f] ← \leftarrow 0 ) ;// 如果有部件的第一个源操作数在等待该结果,则将其Rj操作数就绪置为yes,将Qj等待其它部件置为0;
Result(Fi[FU]) ← \leftarrow ;// 释放部件的目的寄存器
Busy[FU]=no;// 释放功能部件

实例

举个实际的例子:
假设浮点流水线中各部件的延迟如下:
加法需要2个时钟周期;
乘法需要10个时钟周期;
除法需要40个时钟周期。
请给出MULT.D和DIV.D准备写结果之前的记分牌状态和写结果时的周期。
在这里插入图片描述
分析:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
回顾一下发射顺序和完成顺序:
在这里插入图片描述
在这里插入图片描述
之前提的问题是:请给出MULT.D和DIV.D准备写结果之前的记分牌状态和写结果时的周期。
查找得知MULT.D写结果的周期是20,之前记分牌的状态为:
在这里插入图片描述
DIV.D写结果的周期是62,之前记分牌的状态为:
在这里插入图片描述

  • 4
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值