计算机体系结构:记分牌算法(完全弄懂!)

前言:最近在计算机结构体系这门课程的指令级并行一章中学习了记分牌算法,笔者在开始接触这个算法时觉得非常复杂,并且在CSDN和B站等网站上也缺乏很好的教程。于是我通过多方面的学习和相关资料对这个算法进行了较为细致的总结和归纳,希望能够帮助到更多的人。

记分牌算法,其实说白了就是计算机为了通过动态调度指令以提高计算机运行效率而采用的一种填表方法,其核心也就在于填什么表,如何进行填表,掌握了这一部分,这个算法也就学习得差不多了。
自行练习记分牌算法的内容可以使用如下的Excel模板:

链接:https://pan.baidu.com/s/1FCGXVr3QxG1NIxfgAj1Ijg?pwd=hm76 提取码:hm76

1.明白记分牌算法中指令执行的四个阶段

与一般MIPS指令将指令周期分为取指令、指令译码、执行指令、存储器访问和分支完成以及写回五个周期不同,记分牌算法中将所有指令都划分分为如下的四个阶段:

1.1.流出阶段

首先我们来考虑指令执行的前提条件。如果你已经了解了结构冲突和写后写冲突,则可以跳过接下来的两段。
如果一条指令需要执行,那就必须得有一个空闲的部件能够执行这条指令吧?比如如果想要执行一条加法指令,那么就需要有一个空余的加法器来执行;如果加法器被其他加法指令占用,那么这条指令就得等到之前的加法指令执行完成后释放加法器才能继续执行。用体系结构的术语来说,这样做称为避免了结构冲突。
其次,我们考虑这样一种情况。如果一条指令C2和之前的一条指令C1都要修改某一个相同的寄存器中的数据,那么在乱序执行的情况下,就有可能发生C2的指令先将指令执行的结果数据写入了这个寄存器,之后C1才将自己的执行结果写入该寄存器,那么这样就出错了。因为正确的执行顺序下,最后这个寄存器中应该是存放着C2指令的结果的。从体系结构的术语来说,这种情况就称为写后写冲突。
那么,如果指令之间可以实现正确的乱序执行,就必须避免结构冲突和写后写冲突,记分牌算法就可以在流出阶段避免结构冲突和写后写冲突
流出过程可以概述如下:如果本条指令所需要的功能部件空闲,并且其他正在执行的指令使用的目的寄存器与本指令的不同,记分牌就向本指令所需要的功能部件流出指令,并修改记分牌内部的数据记录。
如何理解这段话呢?其实流出过程的前两句就是分别避免了结构冲突和写后写冲突;而具体怎么写记分牌,这个我们放在后面讨论。
总之,可以把流出阶段视为一个过滤器,只有不会产生结构冲突和写后写冲突的指令才会被放进来,然后修改记分牌。

1.2.读操作数阶段

如果把指令视为一个挂号看病的病人,那么经过了流出阶段,那么就相当于这个病人已经经过了门口保安(负责检验无结构冲突和写后写冲突)的检验进入门诊大楼了,并且这个病人的信息已经被放入了候诊名单(记分牌)中,但是他能直接去看病吗?他还是不能。因为可能他挂号的科室之前还有先来的人排着队呢!因此指令在流出后还需要等待满足一定的条件才能正式执行指令。
那么应该满足什么条件呢?考虑这样一种情况:如果指令C1的运行结果是修改某一个寄存器的值,而其后的另一条指令C2需要读取这个寄存器中的值。在乱序执行的情况下,可能C1还来不及修改寄存器中的值,C2已经对寄存器进行了读取,这样就导致了冲突。用体系结构的术语来说,这种情况就称为写后读冲突。
记分牌算法在读操作数阶段可以避免写后读冲突。记分牌会进行如下的监测:如果在当前指令之前且正在运行的那些指令不对当前指令的源操作数寄存器进行写操作,又或者已经完成了写操作,当前指令才可以取操作数并开始执行
因此,读操作数阶段又避免了一种冲突,也就是写后读冲突。

1.3.执行阶段

执行阶段是这四个阶段里面最简单的阶段了,就是直接执行即可。
顺便说一下,执行阶段可能需要若干个周期,但是流出阶段和读操作数阶段都只需要一个周期

1.4.写结果阶段

执行完指令可以直接把结果写到寄存器中吗?不好意思,还不可以哦!
考虑下面这种情况:如果C1指令需要读取寄存器中的数据,而其后的指令C2执行结果需要放到这个寄存器中。在乱序执行的情况下,可能C2的执行结果先放到寄存器里,而C1在这之后才读到寄存器,这样就发生了冲突。用体系结构的术语来说,这种情况就称为读后写冲突。
记分牌算法在写结果阶段会避免读后写冲突。方法很简单:当前指令一直进行等待,直到排在前面的所有指令都不需要对当前指令的目的寄存器进行读操作,这时才对目标寄存器进行回写

综上所述,记分牌算法整个执行过程中避免了全部的三种数据冲突,同时还避免了结构冲突,并且还实现了乱序执行。了解了记分牌算法的基本思想,那么我们接下来就开始考虑具体如果填写记分牌这张“表”。

2.看懂记分牌的表格结构

记分牌其实不只是一张表,而是由指令状态表、功能部件状态表和结果寄存器状态表三张表共同组成。
这一部分的内容是为了让大家在遇到记分牌表格时能够看懂,暂时还不需要学会填写。
注意:记分牌都是针对某一个时刻而言的,而不是针对某一段指令。因此,随着时间的变化记分牌的三张表也会发生变化。

2.1.指令状态表

指令状态表的格式如下:
在这里插入图片描述
①表格的最左边一列表示指令序列,一段程序有多少条指令,指令状态表就有多少行。
②指令状态表表示了某一个时刻程序中各条指令的执行阶段。如上图中,第一条LD指令已经完全执行完成;第二条LD指令已经完成了第三步的执行阶段,但是还没有完成结果写回阶段。以此类推。

2.2.功能部件状态表

功能部件状态表是三张表格中最重要的同时也是最复杂的,其结构如下所示:
在这里插入图片描述
①功能部件状态表最左边一列列出了所有的功能部件。某种功能部件可能有不只一个(如上图中的乘法部件)。
②Busy域:Busy一列表示对应行的部件是否在工作(被占用)。上图中,除了乘法2部件,其他所有部件都处于被占用的状态。
③OP域:OP一列表示某一部件正在执行的操作种类。如上图中的整数部件正在执行的操作位装载浮点数(LD);乘法1部件正在执行的操作是浮点乘法(MULTD)。
④Fi Fj和Fk域:Fi表示当前指令的目的寄存器;Fj和Fk分别表示两个源操作数寄存器(对于一些指令,可能只有一个或没有源操作数,此时Fj和Fk域为空)。如上图中第一行的LD指令的目的寄存器是F2,只有一个源操作数寄存器R3。
⑤Qj和Qk域:Qj和Qk域表示源操作数来自于当前哪一个操作部件的运行结果,如果源操作数不来自于当前任意一个操作部件那么该域为空。如上图,第二行MULTD指令的第一个源操作数寄存器中的值来自于当前整数操作部件的运算结果。
⑥Rj和Rk域:Rj和Rk域用于源操作数寄存器是否已经准备被读取。如果是no则表示没有就绪,是yes则表示已经就绪。另外,如果数据已经读取完成,则也用no进行表示。如上图第一行LD指令中已经读源操作寄存器完成,因此Rj为no(没有Rk是因为LD指令只有一个源操作数);第二行MULTD指令的Rj为no且Rk为yes,说明Fj寄存器还未就绪,而Fk寄存器已经就绪。

在Rj和Rk域都是no的情况下如何区分指令是还未读取操作数还是已经读取完成?通过Qj和Qk域进行判断。如果Qj和Qk域都是空,则说明是读取完成,否则是还未就绪。

2.3.结果寄存器状态表

结果寄存器状态表的结构如下图所示:
在这里插入图片描述
结果寄存器状态表的每一列表示一个结果寄存器。如果这个结果寄存器在等待某一个运算部件的运算结果,则将该运算部件填入对应的列中。如上图所示:寄存器F0在等待部件乘法1的运算结果;寄存器F2在等待部件整数的运算结果。以此类推。

3.会填写记分牌

3.1填写记分牌的通用算法

3.1.1.流出阶段算法

1.1.如果当前指令所需的部件空闲 and 记分牌中已经存在的指令不对当前指令的目的寄存器进行写操作,进入步骤1.2.
(判断方式:通过查看功能部件状态表的Busy列判断是否有部件空闲;通过查看结果寄存器表并找出当前指令对应的结果寄存器,看是否不为空来判断是否存在先前的指令对当前指令的目的寄存器进行写操作)
1.2.向功能部件状态表中填写以下内容
①将当前指令所需使用的部件的Busy域设置为yes;
②将对应部件列的OP域设置为当前执行的指令名称;
③根据指令的源操作数寄存器和目的操作数寄存器填写Fi Fj和Fk。
④判断源操作数寄存器中的内容是否来自于当前记分牌中某些指令的执行结果,如果是则将Qj和Qk域中写入相应的部件名称。判断的过程通过查看结果寄存器状态表来定。
⑤判断源操作数寄存器是否就绪,填入相应的yes或no。
1.3.向结果寄存器状态表中填写以下内容:找出当前指令目的寄存器所对应的列,在列中填入执行当前指令的部件名称。

3.1.2.读操作数阶段算法

2.1.判断是否满足读操作数条件:如果Rj和Rk两个域的值都是yes,那么可以进行读操作数,进入步骤2.2。
2.2.将记分牌中Rj和Rk重新设置为no。
2.3.将记分牌中Qj和Qk域重新设置为空。
(也可以把后面两步放在执行阶段做)

3.1.3.执行阶段算法

执行阶段不用执行任何算法,因此我们可以直接考虑写结果阶段。(欣慰.jpg)

3.1.4.写结果阶段算法

4.1.进行进入条件检验:在功能部件状态表中的每一条指令进行逐一查看,如果不存在任意一条指令的源操作数寄存器与当前指令的目的操作数寄存器相同且对应的寄存器处于读就绪状态,则转到步骤4.2。
4.2.修改记分牌内容
①逐一检验功能部件状态表中的每一条指令的Qj和Qk域,如果存在一条指令以当前指令的结果作为源操作数,则将那一条指令对应的Rj或Rk域设置为yes。
②将结果状态寄存器表中当前指令对应的结果寄存器列设置为空。
③将功能部件状态表中对应的部件的Busy域设置为no。

3.2.记分牌实例分析

假设需要执行的程序包含如下的指令序列,求出指令序列执行各个周期的记分牌。
(这里借用一下学校的PPT帮助讲解)
在这里插入图片描述

第一周期

在这里插入图片描述
首先,第一条指令LD指令进行取指令周期。在最上面的表中记录,该表中第i行第j列的元素表示的是第i条指令完成第j个周期的总时钟周期周期数
接着判断是否可以可以进入记分牌。根据流出算法步骤,首先判断LD指令所需要的部件是否被占用:由于LD指令对整数进行操作,因此使用Integer整数操作部件,此时未被占用;接着判断记分牌中是否存在指令对LD指令的目的操作数寄存器写:由于记分牌中还不存在指令,因此LD指令可以进行流出。
流出需要填写功能部件状态表:将Integer部件的Busy域设置为yes,OP域赋值为Load,Fi目的寄存器为R6,源操作数寄存器只有一个,因此将Fk域填写R2。由于该过程的两个源操作数一个是立即数,另一个直接来源于寄存器R2中现有的值,因此不需要填写Qj和Qk域,同时对Rk赋值为yes。
最后,在结果寄存器状态表中F6域下填写Integer,表示寄存器F6在等待部件Integer的运算结果。
综上,是否可以流出取决于两个条件,流出后填写表格需要参考此时的结果寄存器状态表。

第二周期

在这里插入图片描述
上一条LD指令在经过了流出后进入读操作数周期。由于第一条LD指令只有一个操作数来自于寄存器,并且由于Rk为yes说明源操作数寄存器已经就绪,因此可以进行读操作数。
另外,下一条Load指令可不可以进来呢?根据流出条件判断。由于第二条LD指令同样需要使用整数部件Integer,而此时Integer被第一条LD指令占用,因此第二条LD指令还不可以流出,其后续的指令也都停住。

第三周期

在这里插入图片描述
第一条LD指令进入执行阶段。此时由于读操作数已经完成,因此需要将Rk域置为no;且由于Qj和Qk域本身就是空的,因此不作操作。
此时由于Integer部件仍然被占用,因此第二条LD指令还是不能流出。

第四周期

在这里插入图片描述
第一条LD指令开始准备执行写回操作。
首先判断是否可以进行写回:由于当前记分牌中只存在这一条指令,因此不存在读后写冲突,可以进行写回。
由于当前记分牌中没有其他指令,因此也不存在其他指令以当前指令的结果作为操作数,不需要修改Rj和Rk域的内容。
将功能部件状态表中Integer对应的一行清空,Busy域标注为No,同时将结果寄存器中F6域清空。
另外,由于Integer部件在这个周期之后才被释放,因此第二条LD指令还不能流出。

第五周期

在这里插入图片描述
由于第一条指令已经释放Integer部件,因此第二条LD指令可以流出。流出后修改功能部件状态表和结果寄存器状态表。

第六周期

在这里插入图片描述
第二条LD指令由于只有一个源操作数寄存器且对应的Rk为yes,因此开始读操作数。
由于乘法部件未被占用,且当前记分牌中的指令不写F0,因此MULTD指令流出。流出后修改功能部件状态表和结果寄存器表。注意由于MULTD指令的一个源操作数寄存器F2可以由结果状态寄存器表看出处于等待结果状态,因此将Qj域填写Integer。

第七周期

在这里插入图片描述
第二条LD指令进入执行阶段,将对应的Rk域设置为No。
判断MULTD指令是否可以取操作数:由于Rj域为No,因此不可以取操作数,继续等待。
下一条指令SUBD,由于加法器未被占用,且当前不存在指令写寄存器F8,因此可以流出,填写功能部件状态表和结果寄存器状态表。

第八周期

在这里插入图片描述
第二条指令LD已经完成执行,进入结果写回检验,检验通过。由于MULT1部件的源操作数寄存器与LD指令的目的寄存器相同,因此将MULT1部件的Fj域设置为Yes同时把Qj域清空,对SUBD指令执行类似的操作。接着清空Integer部件对应的行,以及结果寄存器状态表中F2对应的列。
MULTD指令和SUBD等到了源操作数,将在下一个周期开始执行。
另外,DIVD指令满足流出条件,进行流出并填写相应的表格内容。

第九周期

在这里插入图片描述
MULTD指令和SUBD指令由于数据都就绪,因此都可以完成读操作数周期。
DIVD指令中,Qj表示该指令需要等待Mult1的执行结果,操作数未就绪,还不能读操作数。
ADDD指令想要流出,但是SUBD指令占用了ADD部件,因此还不能进行流出。

后续的过程就是类似的了,只要掌握和熟悉了算法的过程,后面的过程也可以比较容易地写出来。

4.记分牌算法学习总结

关于记分牌算法的学习,笔者建议按照三步进行:首先能够懂得表格的含义,接着能够看懂一个具体的记分牌,最后能自行写出记分牌。如果能够自行完成像上面所给出的例题,那么你的记分牌算法至少应付考试就可以了(doge)。

  • 47
    点赞
  • 155
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值