利用流水线提高性能_第1页
利用流水线提高性能_第2页
利用流水线提高性能_第3页
利用流水线提高性能_第4页
利用流水线提高性能_第5页
已阅读5页,还剩90页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第6章 利用流水线提高性能随着时间的推移,每个事物都按固有的规律发展变化,在旧的事物逝去的同时,新的事物又产生了。Robert Herrick在1648年圣诞节前夜庆典上的讲话6.1流水线概述16.2流水线的数据路径176.3流水线的控制286.4数据冒险与转发376.5数据冒险与阻塞496.6分支冒险536.7异常606.8超标量和动态流水线646.9实际资料:PowerPC 64和Pentium Pro的流水线726.10谬误和陷阱756.11结论776.12历史回顾和参考文献796.13重要术语836.14习题856.1流水线概述决不要浪费时间。 -一个美国的谚语。流水线是一种实现多条指

2、令重叠执行的技术。目前,流水线技术是提高处理器处理速度的关键。本节依据上述谚语提供的内涵对流水线的概念及其相关问题进行概述。如果你只是想对流水线技术有一个大概的了解,你可以集中精力看完本节,然后直接跳到6.8节学习流水线的工作方式以及它对程序执行性能的影响。如果你想对基于流水线技术的计算机进行深入的了解,6.2到6.7详细论述了本节涉及到的内容。任何一个经常光顾洗衣店的人都会不自觉的应用流水线技术。非流水线方式的洗衣过程将包括如下几个步骤:1. 把一批脏衣服放入洗衣机里清洗。2. 洗衣机洗完后,把衣服取出放入脱水机中。3. 衣服被甩干后,将之从脱水机中取出,然后将衣服放在桌子上折叠起来。4.

3、衣服折叠好以后,请你的室友帮忙把桌子上的衣服拿走。当你的室友把这批洗干净了的衣服从桌子上全都拿走以后,再开始洗下一批脏衣服。采用流水线的方法将节省大量的时间。如图6.1所示,当把第一批脏衣服从洗衣机里取出放入脱水机之后,你就可以把第二批脏衣服放入洗衣机里进行清洗了。当第一批衣服被甩干之后,就可以将它们折叠起来,同时把洗净的下一批湿衣服放入脱水机中,同时再将下一批脏衣服放入洗衣机里清洗。下一步工作就是让你的室友把第一批衣服从桌子上拿走,而你开始折叠第二批衣服,这时脱水机中放的是第三批衣服,而且你就可以把第四批衣服放入洗衣机清洗了。这样,所有的洗衣步骤(即流水线的步骤)都在同时操作。一旦在每一操作

4、步骤中都有独立的工作单元时,我们就可以采用流水线的方式来快速的完成任务了。流水线的奇妙之处在于,对于单独的一批衣服来说,从它进洗衣机到脱水机,再到折叠、收拾,整个过程的总的处理时间并没有缩短。而在有多批任务时流水线之所以快的原因是所有的工作都是在并行的进行的。因此,单位时间内能够完成的工作量就大大的增加了。如果流水线的所有步骤所花费的时间都相同并且有足够多的工作可以做的话,那么由于采用流水线带来的速度的提高倍数与流水线的步骤的数目相同。一个采用流水线方式工作的洗衣房与非流水线方式工作的相比在速度上提高了四倍:前者洗完20批衣服所需的时间是洗完1批衣服所需时间的4倍,而后者洗完20批衣服所需的时

5、间是洗完一批衣服的20倍。在图6.1中,流水线方式只将处理速度提高了2.3倍的原因是图中只显示了清洗四批衣服的处理过程。图6.1 以洗衣店为例来类比流水线的运作过程。安妮,布朗,凯西和唐每个人都有一些脏衣服要清洗、脱水、折叠及储存。洗衣机、脱水机、折叠机和储存机每个都需要三十分钟来完成各自的任务。顺序的洗衣将花费8个小时的时间洗完四批衣服,而流水线的洗涤方法只需要花费3.5小时。图中采用在这个二维时间轴上显示4道工作的副本的方法来表示同一时间不同的处理步骤对应的流水线步骤,而事实上我们每种洗衣设备都只有一台。同样的原理也可以应用到处理器中,即采用流水线方式执行处理器指令。通常,一个MIPS指令

6、包含如下五个处理步骤:1. 从内存中读取指令。2. 指令解码的同时读取寄存器(MIPS的指令格式允许同时进行指令解码和读寄存器)。3. 执行操作或计算地址。4. 在数据内存中读取操作数。5. 将结果写回寄存器。因此,本章讨论的MIPS流水线具有五个处理步骤。正如流水线能加速洗衣店的工作一样,下面的例子将说明流水线如何加快指令的总体执行时间。单周期指令模型与流水线性能例题:为了使问题具体化,我们首先假设一个流水线结构。在本例以及本章所剩余的部分内容中,我们将只考虑以下的八条指令:load word(lw);store word(sw);add(add);subtract(sub);and(and

7、);or(or);set-less-than(slt)和branch-on-equal(beq)。本实例将比较流水线指令执行与单周期指令执行的平均执行时间,其中在单周期模型中所有指令的执行都花费一个时钟周期。本例中,主要功能单元的操作时间为内存访问:2ns;ALU操作:2ns;寄存器文件的读与写:1ns。(在第五章中我们已经说明在单周期模型中每一条指令都恰恰只花费一个时钟周期,因此,时钟的周期必须延长以满足最慢的指令。)解:八条指令中每一条指令所需要的执行时间如图6.2所示。单周期模型的设计必须考虑到最慢的指令,在图6.2中是 lw,因此,每一条指令所需要的执行时间为8ns。与图6.1类似,图

8、6.3比较了三条load word指令非流水线与流水线的方式的执行过程,其中在非流水线模型中,第一条与第四条指令之间时间的差距是3x8=24ns。指令类别指令预取寄存器读取ALU操作数据访问寄存器写总的执行时间Load word(lw)2ns1ns2ns2ns1ns8nsStore word(lw)2ns1ns2ns2ns7nsR-format(add,sub,and,or,slt)2ns1ns2ns1ns6nsBranch(beq)2ns1ns2ns5ns图6.2由各操作组件计算出来的八条指令总的执行时间。假设乘法器、控制单元、PC访问和信号传递都没有延时。图6.3 单循环、非流水线的指令执

9、行过程(上图) 与 流水线的指令执行过程(下图)。两者采用相同的硬件组件,各组件的处理时间如图6.2 。在此种情况下,指令的执行速度提高了4倍,即从8ns降到了2ns。将本图与图6.1比较。在洗衣服的例子中,我们假设所有的处理过程的完成时间都是相等的。如果脱水机运行得最慢,那么就把抽水的时间设定为各步骤需要的处理时间。计算机的流水线过程处理时间也是受限于最慢的处理资源,即ALU操作和内存访问。同时我们假设对寄存器文件的写操作发生在时钟周期的前半段,对寄存器文件的读操作发生在时钟周期的后半段,并且本章所有内容都遵循这个假设。所有的流水线步骤都只花费一个时钟周期的时间,所以,时钟周期必须能够满足最

10、慢的操作的执行需要。这就象在单周期模型中虽然有些快的指令的执行只需要5ns,但它必须选择在最坏情况下的8ns做为时钟周期一样,流水线执行模型的时钟周期也必须选择最坏情况下的2ns而不是有些步骤可以达到的1ns。流水线能够将性能提高四倍:第一与第四条指令之间的时间差距缩短为3x2=6ns。我们可以把上面讨论的流水线模型能够获得的性能加速比归纳成一个公式。如果流水线各阶段操作平衡,那么在流水线机器上指令执行时间为(在理想情况下):指令执行时间(流水线)=指令执行时间(非流水线)/流水线步骤数即在理想的情况下,流水线所带来的加速比与流水线的执行步骤的数目相同。一个有五个执行步骤的流水线能获得加速比也

11、是五。这个公式说明一个有五个步骤的流水线在8ns的非流水线执行时间或者1.6ns的时钟周期的基础上获得获得五倍的速度提高。然而,在例子中显示,各个步骤间并不是完全的平衡的。另外,流水线中还包括一些常规的额外开销。所以,在流水线机器中每一条指令的执行时间会超过这个最小的可能值,因此流水线能够获得加速比也就小于流水线的步骤数。此外,即使我们在前面的分析中断言能将指令的执行速度提高四倍,但本例子三条指令的执行中并没有反映出来,它实际获得的加速比为24ns/14ns。为什么实际的加速比小了许多呢?如果增加执行指令的数目将会发生什么呢?我们首先将前面的图中的指令增加到1003条,也就是说再在上面的流水线

12、例子中加入一千条指令,每一条指令都将会使整个的执行时间增加2ns,因此,整个的执行时间就变成1000x2ns +14ns,即2014ns。在非流水线的例子中,我们也加入1000条指令,每条指令的执行时间是8ns,因此整个的执行时间为1000x8ns+24ns,即8024ns。在这种理想的条件下,非流水线程序与流水线程序的实际执行时间的比值就非常接近与两者指令执行时间的比值,即为:8024ns/2014ns=3.988ns/2ns流水线所带来的性能的提高是通过增加指令的吞吐率来实现的,而不是减小单条指令的执行实现的。由于实际程序都会执行成千上万条指令,因此,指令的吞吐率是一个很重要的参数。设计流

13、水线指令集尽管上面的例子只是对流水线的最简单的说明,我们也能够通过它讨论如何设计MIPS指令集,即如何设计能以流水线方式执行的指令集。首先,所有的MIPS指令的长度都必须相同。这一限制将简化流水线的第一步预取指令与第二步指令解码。在诸如80x86之类的系统的指令集中,指令的长度并不相同,从byte到17byte不等,这样将会给流水线的执行带来更大的挑战性。第二,MIPS只有很少的几种指令格式,并且每一条指令中的源寄存器的位置都是相同的。这种对称性意味着流水线的第二个步骤在硬件确定提取的指令类型的同时就能够开始读寄存器文件。如果MIPS的指令格式是非对称的,我们就需要将第二个步骤一分为二,从而使

14、得流水线的步骤数变为六(我们不久将看到较长的流水线的缺点)。第三,MIPS中的内存操作数仅出现在load和store操作中。这一限制意味着可以利用执行步骤计算内存地址,就可以接着在下一个步骤访问内存。如果我们可以在内存中操作操作数,就像在80x86中那样,那么步骤与步骤将会扩展为地址步骤,内存步骤,和执行步骤三步。第四,所有操作数必须在内存中排成一列(详情请查阅第三章软硬件界面一节相关内容)。因此,我们不需要担心一个数据传输指令需要两次内存访问的情况,所请求的数据可以在一个的流水线步骤完成在处理器与内存之间传输。流水线冒险(pipeline hazard)流水线有这样一种情况,在下一个时钟周期

15、中下一条指令不能执行。这种情况称为流水线冒险。我们将介绍三种流水线冒险。介绍每种流水线冒险时我们都首先利用前面关于洗衣过程的类比作一简单的描述,然后给出计算机上流水线存在的相应问题及其解决方法。结构冒险第一种冒险叫做结构冒险。即硬件不支持期望的多条指令在同一个时钟周期执行。在洗衣店例子中,如果用洗衣-脱水机代替独立的洗衣机与脱水机,或者如果我的室友正在做其它的事情而不能帮助我将衣服收拾好,都会发生结构冒险。如果发生上述情况,那我们精心构筑起来的流水线就会被破坏。正如我们在上面所说的那样,MIPS的指令集是为流水线设计的。因此,它就要求设计者能够非常容易的在设计流水线时避免结构冒险。假设图6.3

16、的流水线结构只有一个内存而不是两个内存,那么如果有第四个指令的话,我们将会发现,在某一个时钟周期,第一条指令在访问内存的同时第四条指令将会在同一内存中预取指令。如果没有两个内存的话,流水线就会发生结构冒险。控制冒险第二种冒险叫做控制冒险。这种冒险会在下面的情况下出现:决策依赖于一条指令的结果,而正好其他的指令在执行中。假设洗衣店的店员们接到了一个令人高兴的任务:为一个足球队清洗队服。由于衣服非常的脏,我们需要确定清洗剂的用量以及水的温度设置是否能够将衣服清洗干净,但同时要保证不是过大以避免过度的磨损衣物。在洗衣店流水线中,店员只有等到第二步甩干衣服以后才能确定是否需要改变洗衣机的设置。在这种情

17、况应该怎么办呢?有两种办法可以解决洗衣店的控制冒险,同样的方法也可以应用到计算机中。阻塞:在第一批被甩干之前按串行的方式操作,并且重复这一过程直到找到正确的洗衣机设置为止。这种保守的方法当然可以保证正常工作,但它的速度比较慢。计算机中的决策就是分支指令。如果计算机在一个分支前被阻塞,那么流水线就不得不暂停。假设我们可以加入足够多的硬件使得能在流水线的第二阶段测试寄存器、计算分支地址并更新PC(详情参见6.6)。通过这些额外的硬件,包含的条件分支的流水线执行情况如图6.4所示。图中如果分支失败,指令lw在开始执行之前就要被阻塞了额外的2ns的时钟周期。图6.4说明了一个重要的流水线概念:正式的名

18、称叫做流水线阻塞,但是它经常被亲昵的叫做气泡(bubble)。我们经常会在流水线中看到阻塞的发生。阻塞对分支性能的影响例题:评价分支阻塞对单位指令时钟周期数(CPI)的影响。假设其它所有指令的CPI都为1。解:第三章的图3.38显示条件分支占gcc执行指令的17%。由于其它指令的CPI都为1,而分支指令要多一个时钟周期被阻塞,因此平均CPI为1.17。与理想的情况相比,现在的速度下降到了1.17倍(由于图3.38还包括了分支指令slt与slti,而它们并不会阻塞,因此上述CPI只是一个近似值)。图6.4 在每一个条件分支上阻塞是避免流水线控制危险的一种解决方法。本图中在分支后有一步流水线阻塞(

19、或者叫气泡)。如果不能在第二步中解决分支问题(这种情况在较长的流水线中经常发生),那么在分支结构上的阻塞将导致更大的速度下降。对很多的计算机来说,这种阻塞的方法应用代价太大。因此也就产生了另外一种消除控制冒险的方法:预测:如果你确信能正确的设置洗衣设备来洗涤那些队服的话,即你可以预测它的工作,那么就可以在第一批衣服甩干的同时清洗第二批衣服。这种做法在预测正确的时候不会降低流水线的速度,但是一旦预测错误,就不得不将已经洗过的队服重新洗一遍。计算机的确是采用预测的方法来处理分支。一种简单的预测方法就是总预测分支会失败。当你预测正确(即分支失败)的时候,流水线会全速的进行处理。只有当分支成立时流水线

20、才会阻塞。图6.5 给出了这样一个例子。图6.5 预测分支不会执行是一种避免流水线控制冒险的一种解决方法。上图显示的是分支没有执行的流水线,下图显示的是分支发生了的流水线。一种更加成熟的分支预测方法是预测一些分支发生而预测另外一些分支不发生。如在上面的洗衣店的例子中,夜晚和主场比赛的对服使用一个洗衣设备设置而白天或客场比赛的对服则使用另一个设置。举一个计算机的例子,在循环体的底部分支总是会跳回到循环体的顶部。由于分支总是被执行并且总是向前跳转,因此我们可以预测分支会跳转到前面的某一地址上。这种分支预测的方法依赖于一成不变的行为,它没有考虑特定的分支指令的特点。动态硬件预测器与这种方法截然不同,

21、它的预测依赖于每一条指令的行为,并且在整个的程序生命期内可能改变分支的预测。与洗衣店的例子类比,使用动态预测方法,店员将会观察制服的肮脏程度然后在假设一个洗衣设备设置,然后在本次预测的成功的基础上调整下一次的预测行为。计算机中动态预测方法的一种比较普遍的实现方法是保存每次分支的历史纪录,然后利用这个历史纪录来预测未来。这种硬件的方式能够达到90%的正确性(参阅6.6)。当预测错误时,流水线控制必须确保被错误预测了的分支后面的指令不会生效并且必须在正确的分支地址处重新开始启动流水线。如同其它解决控制冒险的方法一样,较长的流水线会恶化预测的性能,它将提高解决错误预测的代价。控制冒险的解决办法在6.

22、6节中将有更加详细的介绍。细节:还有一种解决控制冒险的方法,即延迟决定(delayed decision)。与洗衣店的例子类比,每当要决定如何洗衣服时,就将一批非足球队的衣服放进洗衣机里,同时等待足球队的制服被甩干。只要有足够多不需要决策的脏衣服,这种方法就能够很好的工作。在计算机中这种方法被称为延迟分支,在MIPS系统结构中也得到了实际应用。延迟分支发生分支的下一个顺序的指令,而在一个指令的延迟之后再开始执行分支。由于编译器会自动的排列指令使得分支的行为达到程序员的要求,因此这个过程对MIPS的汇编程序员们是透明的。MIPS软件会在延迟分支指令的后面紧跟着放一条不受该分支影响的指令。发生了的

23、分支会改变这条安全指令之后的指令的地址。在我们的例子中,图6.4中分支前的指令add不影响分支,所以在图6.6中就把它移到了分支之后的延迟分支时间片中。编译器一般只能在大约50%的分支延迟时间片中放入有用的指令。如果流水线比五个步骤长的话,将会有更多的延迟分支时间片,这些时间片将更加难以填满。图6.6推迟分支是避免流水线控制冒险的一种解决方法。流水线气泡被add操作所代替。数据冒险让我们再回到洗衣店的例子。假设你正在折叠一批衣服,而这批衣服的大多数都是短袜。你突然发现你的运气非常的不好。因为在这一批当中的所有短袜的另外一只都在另一批衣服中。而那一批正在洗衣机中洗涤。你无法把手头的这些短袜配对,

24、也就无法对它们进行储存,只有等到那一批衣服也被处理完,因而必须阻塞流水线。这种问题在计算机当中称为数据冒险:即一条指令依赖仍然在流水线当中执行的前一条指令的结果。举个例子来说,假设我们有一条加法指令,它之后紧跟着一条减法指令,而减法指令要使用加法指令的和:Add $s0, $t0,$t1Sub $t2,$s0,$t3在没有干涉的情况下,这一数据冒险会严重的阻碍流水线。加法指令直到第五步才能写出它的结果,这就意味着我们必须在流水线当中加入三个气泡。虽然我们可以试图依靠编译器来避免这种数据冒险的发生,但实际上这种努力是失败的。因为这种相关性的发生过于频繁而且导致的延迟也过于长,因此不可能指望编译器

25、能把我们从这种困境当中解脱出去。一种最基本的解决方法试图不等待指令执行结束来解决数据冒险问题。对于上述的代码序列,一旦ALU生成了加法运算的结果,我们就可以将它用作减法运算的一个输入项。从内部资源中直接提前得到缺少的运算项的过程称为转发(forward)或者旁路(bypassing)。两个指令中的转发例题:对于上述的两条指令说明适用转发如何将流水线步骤连接起来。图6.7描述了流水线的五步的数据路径。图6.1中的洗衣店流水线类似,每条指令的数据路径排成一列。解:图6.8 表示了把add 指令执行后的$s0中的值作为sub指令执行的输入的转发连接。在图6.8中,只有当目标步骤在时间上晚于源步骤时转

26、发的路径才有效。例如,从前一条指令的内存访问的输出至下一条指令的输入的转发路径就不可能有效,因为那样的话将意味着时间的倒流。转发可以工作的非常好,其具体内容将在6.4节中详细介绍。然而它并不能够防止所有的流水线阻塞的发生。例如,假设第一条指令不是add 而是载入$s0寄存器的内容,正如图6.8所描述的那样,由于数据间的依赖,所需要的数据只有在前一条指令流水线的第四步完成之后才能生效,这对于sub指令的第三步输入来说就太迟了。因此,如图6.9所示,即使使用了转发机制,在载入使用的数据冒险中,流水线仍然不得不阻塞一个步骤。在6.5节我们将论述如何通过流水线的硬件解决象这类载入问题。图6.7指令流水

27、线的图形表示。其基本思想与图6.1中的洗衣店流水线类似。在本图以及本章所有内容中,我们使用图形符号来代表流水线执行各阶段使用的物理资源。这些符号在五个流水线步骤中所代表的意义分别是:IF表示指令的预取,其外方框表示指令的内存;ID表示指令的解码或寄存器文件的读取,外边的虚线方框表示要读取的寄存器文件;EX表示指令的执行阶段,外边的图符表示ALU;MEM代表内存访问阶段,包围它的方框代表数据内存;WB代表写回过程,包围它的虚线方框代表被写回的寄存器文件。阴影表示该资源被指令所使用。因此MEM没有阴影,因为add指令在这一步并不读取数据内存。寄存器文件或内存上右半边的阴影表示着它们在此步骤中被读取

28、,左半边的阴影表示它们在此步骤中被写入。因此,由于第二步需要读取寄存器文件,ID的右半边有阴影,而由于第五步中需要写入寄存器文件,WB的左半边有阴影。图6.8 转发的图形表示。图中的连接表示从 add指令的EX操作的输出到sub指令的EX操作的输入的转发路径。,从而替换掉在sub的第二步从寄存器$s0读取的值。图6.9 当一条R型的指令之后紧跟着一条需要使用该数据的load指令时,即使使用了转发机制,仍然会产生一次阻塞。如果不进行一次阻塞的话,从内存访问的输出到执行步骤的输入之间的路径在时间上将是倒着的,这显然是不可能的。重新排列代码以避免流水线的阻塞例题:下面代码是164页图3.2

29、3中的swap过程的一段,请找出其中的数据冒险。#reg$t1has the address of vkLw$t0,0($t1)#reg $t0(temp)= vkLw$t2,4($t1)#reg$t2=vkSw$t2,0($t1)#vk=reg $t2Sw$t0,4($t1)#vk+1=reg $t0 (temp)将这一段指令重新排列以避免流水线阻塞。解:冒险会在第二个lw和第一个sw之间的寄存器$t2上发生。交换两条sw指令的顺序就能排除掉这个冒险:# reg$t1 has the address of vklw$t0,0($t1)# reg$t0 (temp)=vklw$t2,4($t1

30、)# reg$t2 =vk+1sw$t0,4($t1)# vk+1 = reg $t0 (temp)sw$t2,0($t1)# vk = reg $t2注意,由于在lw写寄存器$t0与sw读寄存器$t0之间仍然存在着一条指令,所以这样交换之后不会产生新的冒险。因此,在一台具有转发机制的机器上,执行重新排列的代码段只需要四个时钟周期。软硬件接口 在编译器与硬件的设计复杂性进行折衷的例子中,原始的MIPS处理器通过软件在一条载入指令之后加入一条与之无关的指令的方法来避免阻塞流水线。这样的载入过程叫做延迟载入。除440页所提到的四种情况以外,转发还给MIPS系统结构增加新的约束,即每一个MIPS指令

31、都在指令执行结束时写而且只写一个结果。如果一条指令中需要转发多个结果或者在指令结束以前需要写回多个结果,转发将变得更加困难。例如,在PowerPC的载入指令中就使用了更改寻址机制(参见第三章175页),从而使得处理器必须能够在每一条载入指令中转发两个结果。流水线概述的总结流水线是一种在顺序指令流中利用指令间的并行性的技术,其优势在于,与其它加速技术不同(参见第九章),它对程序员是不可见的。在以下几节中,我们首先使用MIPS的指令子集lw,sw,add,sub,and,or,slt和beq(见第五章)及其简化的流水线方式介绍关于流水线的一些基本概念,然后讨论引入流水线所带来的一些问题以及流水线在

32、一些典型情况下所能够达到的性能。重点:流水线增加了同时执行的指令的数目以及指令开始和结束的比率。流水线并不能够减少单一指令的执行时间。一个五个步骤的流水线仍然需要五个周期来完成一条指令。用第二章56页的术语来描述就是流水线提高了指令的吞吐量而不是减少了单条指令的执行时间。对流水线的设计者们来说指令集即可能将事物简单化,也可能将事物复杂化。流水线设计者必须解决结构冒险、控制冒险和数据冒险。而分支预测、转发和阻塞机制能够在保证得到正确结果的前提下提高计算机的性能。如果你想更快地浏览本章的话,我们相信,在完成了本节的学习以后,你已经具有足够的背景知识,并且可以直接跳到6.8节与6.9节去了解一些先进

33、的流水线概念,如超标量流水线与动态流水线,并且可以去了解流水线在当前的一些微处理器中是如何工作的。如果你想更加深入的了解流水线技术,在读完第五章与本节后,6.2节将介绍为实现流水线数据路径需要做出的改变,6.3节介绍流水线数据路径的控制,6.4节中阐述为实现转发对数据路径及其控制的修改,6.5节介绍解决载入操作数据冒险引起的阻塞及其需要对数据路径和控制机制的修改,6.6节详细介绍分支冒险的解决方法,6.7节讨论异常的处理。细节:转发这个名称来源于将结果从前面的指令直接发送到后面的指令的思想。旁路这个名称来源于把寄存器文件中的结果直接传递到需要的单元中。6.2流水线的数据路径图6.10是摘自第五

34、章的一个单时钟周期的数据路径。将指令划分为五个阶段意味着一个有五个步骤的流水线,也就意味着在任何一个单时钟周期内,最多会有五条指令被执行。因此我们必须把数据路径分为五个部分,每一部分用与它相对应的指令执行阶段来命名。1 IF:指令预取2 ID:指令解码,读寄存器文件3 EX:执行或计算地址4 MEM:数据内存访问5 WB:写回图6.10单周期周期的数据路径(与358页的图5.17类似)。指令的每一步在图中由左至右映射到数据路径上。唯一的例外是PC的更新与写回过程(如图中彩色部分所示),它们发送ALU结果或内存数据到左边的寄存器文件中(通常用彩色线代表控制,而在本图中它们它们都是数据线)。在图6

35、.10中,这五个步骤大致和数据路径相符:指令与数据随着执行的过程从左到右一次在这这五步流过。让我们再一次回到洗衣店那个类比中去,衣服沿着一条工作线依次被清洗、脱水和整理,而不会反过来移动。然而,在这个从左到右的指令流中有两个例外:l 写回阶段,它把结果写回到数据路径中间的寄存器文件中。l 选择PC的下一个值,在PC+1与MEM阶段的分支地址间进行选择。图6.11指令按图6.10中的单时钟周期数据路径执行(假定以流水线的方式执行)。与图6.7到图6.9类似,本图假设每一条指令有它独立的数据路径,并根据使用情况将相应的部分涂上阴影。与这些图不同的是,流水线的每一步都用该步骤使用的实际资源部件标示,

36、分别对应图6.10中数据路径的相应部分。IM表示指令内存与指令预取阶段的PC,Reg表示指令解码/寄存器文件读取阶段(ID)的寄存器文件和信号合成器,依此类推。为了保持正确的时序,这种格式的数据路径把寄存器文件从逻辑上划分为两个部分:寄存器读取(ID)阶段的寄存器读和写回(WB)时的寄存器写。这种双重的应用在图中表示为:在ID阶段当它没有被写入的时候,将没有阴影的寄存器文件的左半部分用虚线表示,而在WB阶段当它没有被读时,则将没有阴影的右边部分用虚线表示。与以前一样,我们假设在时钟周期的前半部分写寄存器文件而在时钟周期的后半部分读寄存器文件。数据从右向左流动并不会影响当前的指令,流水线中只有当

37、前指令以后的指令才会受到这种数据的反向活动的影响。需要注意的是第一个从右向左的箭头会导致数据冒险,而第二个会导致控制冒险。一种表示流水线的数据路径的方法是假定每一条指令都有它独立的数据路径,然后把这些数据路径放在同一时间轴上表示它们之间的关系。图6.11在同一时间轴表示了图6.3中指令执行过程中各自的数据路径,我们仍然使用图6.10中的格式来表示图6.11中的关系。图6.11看起来好像是三条指令需要三条数据路径。在第五章我们增加了保存数据的寄存器,从而使得在指令的执行过程中可以共享部分数据路径。在这里我们使用同样的技术共享多条数据路径。例如,在图6.11中指令内存只在每条指令的五个步骤中的一步

38、中用到,因此我们允许它在其它四步中被其它的指令共享。图6.12 图6.10数据路径的流水线版本。流水线寄存器(图中彩色部分所示)将流水线的各部分分开。他们分别以被分开的各步骤为标志,例如,第一个被标为IF/ID是因为它将指令的预取与指令的解码阶段分开的缘故。为了储存所有穿过它的由线条代表的数据,寄存器的带宽必须足够大。例如,因为IF/ID寄存器必须同时保存32位的从内存中提取出来的指令及32位的PC增量的地址,它的带宽必须是64位。我们将在本章中渐渐增加寄存器的带宽的,目前另外三个流水线寄存器分别包含128位、97位和64位。为了在其它四步中保持指令的各自的值,从指令内存中读出的数据必须保存在

39、寄存器中。同样的方法应用到每个流水线步骤中,我们需要在图6.10中各步骤间有分割线的地方都加入寄存器(这种变化与第五章中在从单时钟周期到多时钟周期变化时增加寄存器的方法类似)。1再回到洗衣店类比例子中,这时我们可以用篮子在两个步骤之间存放下一步的衣服。图6.12描述了流水线的数据路径,其中流水线寄存器用高亮度重点表示。在每个时钟周期中所有指令都会从一个流水线寄存器推进到另一个流水线寄存器中。寄存器以被该寄存器分开的两个阶段来命名,如IF和ID阶段之间的流水线寄存器叫做IF/ID。需要注意的是在写回阶段的后面没有流水线寄存器。所有的指令都会更新机器中的一些状态,如寄存器文件、内存或者是PC等,因

40、此各个流水线寄存器文件对于更新后的状态来说是多余的。例如,一条load指令会把它的结果放入32个寄存器中的某一个中,以后任何需要此数据的指令只需要简单的读取相应的寄存器就可以了(6.4节和6.5节中将详细介绍如何解决流水线指令间存在的数据冒险,在此我们暂时忽略这个问题)。为了描述流水线的工作方式,本章将使用一系列图片来表示这些顺序的操作。这些额外的内容可能需要一定的时间去理解,但千万不要害怕,这些图片实际上比它们看上去要容易理解,因为你可以对比的去观察每一个时钟周期内所发生的变化。图6.13到图6.15表示了一条load 指令在通过流水线的五个执行步骤时数据路径的活动部分,在图中它们都用高亮度

41、重点表示。我们首先讲解load 指令的因为是它在五个步骤中一直是活动的。正如图6.7到图6.12所显示的那样,当寄存器或者是内存被读取时我们用在图中高亮度表示它们的右半部分;而当它们被写入的时候,我们在图中用高亮度来表示其左半部分。我们把每一幅图中活动的流水线步骤用指令的缩写lw标出。这五个步骤的情况如下: 指令的预取:图6.13的上图表示指令使用PC中的地址被从内存中读取数据,然后将数据放入了IF/ID流水线寄存器中(IF/ID流水线寄存器与378页图5.30中的指令寄存器类似)。中的地址加然后存入中为下一个时钟周期做准备。增加后的地址同时也存入了IF/ID流水线寄存器中以备以后的指令使用,

42、如beq。计算机并不知道所预取的类型,所以必须为可能的任何指令作准备,并顺着流水线传递所有可能有用的信息。 指令解码与寄存器文件的读取:图6.13的下图显示的是IF/ID流水线寄存器的指令部分,它提供位的立即数(可扩展为带符号的位数),并读取两个寄存器的寄存器号。这三个值沿着递增的地址存入ID/EX流水线寄存器中。这里我们也必须传递后面的指令可能用到的所有信息。 执行或者地址计算:图6.14表示load指令从ID/EX流水线寄存器中读取寄存器中的内容以及扩展后带符号的立即数,并用将它们相加。加法的和放入了EX/MEM流水线指令寄存器中。 内存访问:图6.15的上图表示load指令使用从EX/M

43、EM流水线寄存器中得到的地址读取数据内存,并将数据载入MEM/WB流水线寄存器当中。 写回:图6.15的下图表示了最后一个步骤,即从MEM/WB流水线寄存器中读取数据并将它写入图中间的寄存器中。图6.13 IF与ID:指令的第一个与第二个流水线步,图6.12的数据路径的活动部分用高亮度表示。图中的表示约定与图6.7中相同。如第五章相同,读写寄存器并不发生冲突是因为寄存器内容的变化只有在时钟周期的边缘发生。虽然load指令只需要第二个步骤中最上面的那个寄存器,但由于处理器并不知道当前是哪一条指令正在被解码,因此它把16位的常量进行符号化扩展,并把两个寄存器中的值都读入ID/EX流水线寄存器中。我

44、们并不需要所有这三个操作数,但是全部保留三个操作数能简化对它们的控制。图6.14 EX:load指令的第三个步,并且用高亮度线条标示出图6.12中的数据路径在这个流水线步的部分。寄存器与经过符号扩展的立即数相加,其和放入EX/MEM流水线寄存器中。图6.15 MEM与WB:load 指令的第四个与第五个流水线步,并且用高亮度线条标示出图6.12中的数据路径在这两个流水线步的部分。利用EX/MEM流水线寄存器中的地址读取数据内存,并将读取的数据放入到MEM/WB流水线寄存器中。然后从MEM/WB流水线寄存器中读取数据并将数据写入数据路径中间的寄存器文件中。对load指令的整个过程的描述表明任何一

45、个将被下一个流水线步骤应用到的数据都必须通过流水线寄存器传输到那个步骤。纵观store指令的执行过程,我们会发现除了要将有用的信息传递到后面的流水线步骤外,指令的执行还有一定的相似性。下面是store指令的五个执行步骤: 指令的预取:利用中的地址从内存中读出指令,然后将指令放入IF/ID流水线寄存器中。这个步骤发生在指令被确认之前,所以图6.13中的上图的内容既适用于load指令也适用于store指令。 指令的解码与寄存器文件的读取:IF/ID流水线寄存器中的指令支持读取两个寄存器的寄存器号和经过符号化扩展的16位立即数。这三个32位的数都存放在ID/EX流水线寄存器中。图6.13中的下图同时

46、也可描述了store指令的第二个流水线步骤。由于此时无法得知要执行的指令的类型,因此这两个步骤在所有的指令执行过程中都会被执行。 指令执行或地址计算:图6.16描述了流水线的第三个步骤,有效地址存放在EX/MEM流水线寄存器中。 内存访问:图6.17的上图描述的是数据写入内存的过程。需要注意的是需要存入寄存器中的数据在较早的流水线步骤中已经读出并存放在ID/EX中。在MEM阶段唯一一种获得这个数据的方法就是把数据放入EX步骤中的EX/MEM流水线寄存器中,这一过程与将有效地址放入EX/MEM中类似。 写回:图6.17中的下图描述了store指令的最后一个流水线步骤。store指令在写回步骤中不

47、做任何事情。由于store指令后的每一条指令都已经进入流水线中,所以我们无法加速这些指令。因此,任何一条指令都必须经过流水线种的每一个步骤,即使在这个步骤中它实际上什么都没有做,这是因为后面的指令已经按照最大的速率在流水线中进行处理。图6.16EX:store指令的第三个流水线步。与图6.14中load指令的第三个流水线步不同的是,第二个寄存器中的数据被载入EX/MEM流水线寄存器中,并被用于下一个步骤。虽然总是将第二个寄存器中的数据载入EX/MEM流水线寄存器中并不会产生什么不良的影响,但为了使流水线更易于理解,我们仍然只在store指令中才写第二个寄存器的内容。图6.17 MEM和WB:s

48、tore指令的第四与第五个流水线步。在第四个步中,为了存储数据将数据写入数据内存中。需要注意的是数据来自于EX/MEM流水线寄存器,并且MEM/WB流水线寄存器并没有改变。一旦数据写入内存,store指令就没有什么可做的了,所以在步骤中store指令并不做任何处理。Store指令再次说明在流水线中为了从前面的步骤向后面的步骤传递信息,就必须将信息放入流水线寄存器中,否则当下一条指令进入该流水线步骤时这些信息将会丢失。在store指令中,我们需要将一个寄存器中的内容在ID步骤中读出然后在MEM步骤放入内存中。这些数据首先放在ID/EX流水线寄存器然后被传送到EX/MEM流水线寄存器中。Load与

49、store的执行过程还表明了另一个重要特性,即数据路径中的每一个逻辑元件,如指令内存、寄存器读取端口、ALU、数据内存以及寄存器写入端口,都只能在一个流水线步骤中使用,否则就会产生结构冒险(请查阅441页)。因此,这些元件以及它们的控制单元都只能与一个流水线步骤相关联。现在我们可以揭示load指令设计中的一个bug了。你发现了这个bug吗?在load指令执行的最后一个阶段有哪一个寄存器内容改变了呢?更确切的说,哪一条指令提供了写寄存器号呢?在IF/ID流水线寄存器中的指令提供了写寄存器号,但是很显然这条指令发生在load指令之后。因此,我们要在load指令中保存目的寄存器号。就像store指令

50、为了MEM步骤使用的需要将寄存器的内容从ID/EX转送到EX/MEM流水线寄存器中去一样,为了WB步骤中的使用的需要,load指令必须把寄存器号从ID/EX经过EX/MEM传送到MEM/WB流水线寄存器中。换一个角度来考虑传输寄存器号的必要性:为了共享流水线的数据路径,我们需要在IF步骤中保存读取的指令,因此,每一个流水线寄存器都要保存当前步骤和以下各流水线步骤所需的部分指令。图6.18描述了正确的数据路径,首先将写寄存器号传送到ID/EX寄存器,然后再送到EX/MEM寄存器,最后送到MEM/WB寄存器。在WB步骤使用寄存器号以确定要写入的寄存器。图6.19是一个正确的简单的数据路径图,图中用

51、高亮度表示了从图6.13到图6.15load指令在所有五个流水线步骤中要使用的硬件(参阅6.6节相关内容了解如何使分支指令按期望的方式工作)。图6.18正确处理load指令的流水线数据路径。写寄存器号与寄存器数据一齐从MEM/WB流水线寄存器中得到。通过在最后的三个流水线寄存器上分别增加了位,寄存器号就能从ID流水线步骤一直传送到MEM/WB流水线寄存器。这条新的数路径如图中彩色部分所示。图6.19图6.18中在load指令所有的五个流水线步中都用到的数据路径部分。图形化表示的流水线流水线技术比较难以理解,因为在每一个时钟周期内同时会有很多指令在一个数据路径中执行。为的帮助理解流水线,有两种基

52、本的表示流水线的图形化方法,即多时钟周期的流水线图(如451中的图6.11所示)和单时钟周期的流水线图(如图6.13到图6.17所示)。下面我们介绍下面这个两指令序列的两种流水线图表示方法:lw$10,20($1)sub$11,$2,$3图6.20表示的是这些指令的多时钟周期流水线图。与437页的图6.1中洗衣店流水线表示方法类似,时间沿着这个图页从左到右前进,指令从上到下前进。沿着指令轴分别表示各流水线步骤,并且分别占据相应的时钟周期。这些格式化的数据路径分别表示流水线中的五个步骤,而用一个小方块写上流水线的名字以清楚的表达流水线。图6.21显示的是一个更加传统的多时钟周期流水线图的表示方法

53、。需要提醒注意的是图6.20中描述的是每个步骤中使用的实际资源,而图6.21描述的则是每个步骤的名字。我们使用多时钟周期流水线图总体描述流水线的情况。单时钟周期流水线图表示的是在一个时钟周期内整个数据路径的状态。而所有五个在流水线中的指令都在各流水线步骤上作相应的标示。这中流水线表示图描述了在每一个时钟周期内流水线中所发生的细节事件。通常,它使用一组单时钟周期流水线图来表示在一系列时钟周期内的流水线的操作。图6.22到图6.24描述了上述两条指令的单周期流水线图。当然,这两种表示流水线的方法是等价的。两种表示方法间有一个容易混淆的方面就是图中的指令顺序:在多时钟周期流水线图中最新的指令总在图的

54、右下方,在单始终周期流水线图最新的指令总在图的左边。从多时钟周期图中抽出一个时钟周期就表示了单时钟周期图中流水线的状态。但从一系列的单时钟周期流水线图转换成一个多时钟周期流水线图就困难一些。由于最新的指令必须放在最底部,因此必须把每一个单时钟周期流水线图逆时针旋转90度,然后再把旋转后的图一个接一个的排列好,相邻的图标志间有一个时钟周期的偏移,从而使得每一条指令的所有五个步骤的数据路径正好排列成占据一个水平线(参见习题6.8)。图6.20两条指令的多时钟周期流水线图。这种类型的流水线图在一幅图中表示了指令集的整个执行过程。指令从上到下按照执行的顺序被排列,时钟周期从左向右前进。与图6.7流水线

55、表示方法不同的是这里画出了每一步骤中的流水线寄存器。图6.21给出了这种图的较为传统的画法。图6.21图6.20中两条指令的传统的多时钟周期流水线图图6.22时钟周期1(上图)与时钟周期2(下图)的单周期流水线图。这种类型的流水线表示方法是每一指令在一个时钟周期内执行的快照。在本例子中只有两条指令,因此在每个时钟周期内至多有两个流水线步骤被标识,而在通常情况下所有五个步骤都会被占据。流水线数据路径中亮度的部分表示在时钟周期中是活动的。在第一个时钟周期Load指令被预取,而在第二个时钟周期Load指令被解码,同时subtract指令被预取。为了使图更容易理解,其它的流水线步骤都是空的,但在通常情

56、况下每一个流水线步骤中都是有指令的。图6.23时钟周期3(上图)与时钟周期4(下图)的单时钟周期流水线图。在上图的第三个时钟周期,lw指令进入了EX阶段,同时sub进入了ID阶段。在下图的第四个时钟周期的数据路径中,lw进入了MEM阶段,使用在第四个时钟周期开始时在EX/MEM中找到的地址来读取内存,同时ALU执行减法并在时钟周期结束时将差值放入EX/MEM中。图6.24时钟周期5(上图)与时钟周期6(下图)的单时钟周期流水线图。在时钟周期5中,lw在把数据放入MEM/WB中的寄存器10后结束,而sub把EX/MEM中的差值放入MEM/WB中。在第六个时钟周期里,sub把MEM/WB中的差值写入寄存器11中。细节:与单指令时不同,由于程序计数器在两条指令之间传递信息,图6.22 这一类的图将PC看作一个外寄存器。在指令预取阶段之前或者在一条指令的写回阶段与下一条指令的预取阶段之间,你可以将PC看成是一个流水线寄存器。因此,和其它的流水线寄存器一样,PC也被画成一个拉长了的长方形。6.3流水线的控制在6600型计算机中,甚至以前所有的计算机中,控制系统都千差万别。James Thornton <<计算机设计:控制数据6600>>,19705.2节介绍了在简

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论