流水线设计

20世纪80年代,流水线技术成为RISC处理器设计方法中最基本的技术之一,RISC的设计多以高流水为目标设计。

而后流水线技术也被应用到CISC处理器

在流水线的发展史上主要有两种流水线,算术流水线和指令流水线。

首先通过算术流水线的例子,介绍流水线理想假设。

流水线意味着将系统分割为许多段,段与段之间增加合适的缓冲,这样每隔D/K个时间单位就可以启动新的任务,而不是每隔D个时间单位。

流水线并不能被无限制的增加下去,因为时钟的限制(setup time/clock uncertainty),流水线的划分有一个物理局限。

流水线深度的权衡:

一个k级流水线的价格:C = G + k *L,原来非流水的价格+流水线段数×增加一级流水价格;

流水系统的性能:1/(T/k + S),T非流水系统的延时,S引入流水新加的延时,k级流水。

通过微分求解:可以得到一个流水线的最佳深度

                       

K<Kopt:不够完全流水化,可以进一步增加流水,性能的提升比价格的提高更明显;

K>Kopt:过度流水化,增加流水,价格的提升比性能的提升更明显;

流水线操作中的硬件要求:

1):每一段进行控制和完成数据操作的逻辑;

2):支持多个流水段同时访问的寄存器文件接口;

3):支持多个流水段访问的存储器接口;

随着流水线深度的增加,流水线的硬件资源会显著的增加,最突出的是寄存器文件和存储器端口数目的增加。

目前流水线处理器的设计趋势是向着更高的流水程度和更深的流水深度发展,这样流水线级颗粒更小,时钟频率更高,目前超过10级的流水线很常见,

还有一个趋势是多条级数不等的流水线。

流水化的理想假设:只有在理想情况下,流水线的吞吐量才能得到K倍;

1):一致的运算分量,要完成的整个运算量均匀的分成延迟一致的若干分量。

由于流水线的时钟周期取决于延迟最长的那一段,所以各个流水段最好做平,来减少”内部碎片”,

并且,流水段之间的缓冲不会带来额外的延迟(setup time),时钟也不会引入额外的延迟(clock uncertainty)

2):重复的运算,输入数据有大量相同的,重复的运算。

不同的功能流水段中,可能不需要一些特定的流水段,这些空闲的流水段”外部碎片”

各个流水段只有完全流水阶段,不存在流水线填充阶段。

3):独立的运算,所有相同的运算之间没有相关性。

后面的运算可能会用到之前运算的结果,当这两条命令都在流水线中时,会产生等待状态,”流水线停顿(pipeline stall)”

指令流水化设计:

一条指令的处理过程,流水化的运算,被划分为多个一致的子运算,获得尽可能均衡的流水线。

处理一条指令的时间延迟:

指令周期-------体系结构原语,由指令集体系结构定义。

机器周期-------流水线的时钟周期,机器原语,由处理器的微体系结构定义。

指令流水线设计的主要任务,将逻辑指令周期映射到物理机器周期,将指令周期合理的分割为一个子运算的序列,需要考虑:

1):一致的运算分量,量化流水段,尽可能的减少内部碎片,流水线越均衡,内部碎片越少。

2):重复的运算,指令流水线天生就是多功能流水线,对应的子运算序列不同,硬件资源不同,

            连接或者整合不同指令类型对不同资源的需求。尽量减少无效或者空闲的机器周期。

3):独立的运算,尽量减少流水线停顿。

指令集体系结构对流水线的影响:

1):一致的运算分量,在流水线设计中,关键分量是对存储器的访问,采用cache访问。典型6级流水设计

2):重复的计算,RISC体系结构的主要目的之一,降低指令类型的复杂性和多样性,可以降低整理不同指令类型的难度。主要分为三种指令类型

3):寄存器相关比较容易检测,可以由编译器静态完成,或者运行时硬件动态完成,存储器相关比较难判断。

保持流水段均衡:

一个典型的指令周期,可以划分为:

1):取指(IF,Instruction Fetch)

2):译码(ID,Instruction Decode)

3):取操作数(OF,Operand Fetch)

4):执行(EX,Instruction execution)

5):存储(OS,Operand Store)

分割指令周期的很自然的方法是按5个基本运算分量来划分,得到一个5级指令流水线,称为基本指令流水线GNR(generic)流水线。

其中逻辑指令周期映射到5个物理机器周期中,这个值反映了流水化的程度和颗粒。

在量化流水线中,可以根据实际分量的大小,进行合并和再分解。从而增大流水度和减小流水度。或者可以将合并与分解结合使用。

不管在哪种情况下,目的都是为了减小内部碎片。

统一指令类型:

指令流水线需要满足不同的需求,必须提供所有指令类型所需要的所有运算分量。

对于单独一种指令类型,不需要的流水段将成为某种形式的失效和开销,称为外部碎片。

要完成一次运算,计算机必须完成三个基本任务:

1):算术操作,ALU部分,执行算术和逻辑运算

2):数据移动,将操作数和结果在存储地址之间进行移动

3):指令定序,由指令自身来确定

CISC指令集多采用,一条指令都能完成一条以上的基本任务。

在现代RISC体系结构中,指令集采用一种专门的指令类型来完成三个基本任务中的一个,定长正交指令,load/store体系结构和简单寻址模式。

其中指令可以分为三种类型:(包括无条件跳转指令和条件跳转指令,定点指令和浮点指令)

ALU:算术和逻辑运算

Load/Store:数据在寄存器和存储器间移动,选择简单寻址模式,带偏移的寄存器间接寻址模式。

分支指令:控制指令执行的顺序,寻址模式支持PC相对寻址。

Load/Store之间也有微小区别:load指令,OF可以新分为读寄存器得基址,有效地址生成,存储器访问

                           Store指令,OS可以分为有效地址生成,寄存器操作数写入存储器

资源需求的整合:

尽量提高流水线中所有资源的利用率,合理分配各个流水段的资源,减少各个指令类型带来的空闲周期。

针对四种指令(ALU, Load/Store, jump)进行功能划分:

1):所有四种指令有相同的IF和ID分量,完成取指和译码操作;

2):所有四种指令的OF分量都要读寄存器文件,ALU访问寄存器操作数,load得到基地址,store得到操作数和基地址,jump访问PC寄存器

RD段从寄存器文件中读取最多两个寄存器操作数,所以寄存器文件在每个时钟都必须支持两个独立的并行读操作。

3):ALU完成算术逻辑运算,load/store/jump完成有效地址生成。

4):Load/store访问存储器,流水线第五段,MEM

5):ALU和load都要向寄存器文件写入结果,为了统一,在ALU执行完后,不直接向寄存器写入,和load一样在流水线第六段写入。

ALU在MEM段后,产生一个空闲周期,外部碎片

6):对于条件分支指令,必须在更新程序计数器之前,确定分支条件,所以最早能用分支目标地址更新程序计数器的段是MEM

以上是一个TYP的指令流水线,ALU有一个空闲周期(MEM),store和jump没有WB段,只有load指令用了其中6个流水段,这是一条效率比较高的流水线了。

在这个指令流水线的实现过程中,每个时钟周期最多有6条指令会驻留在流水线中,所以一个机器时钟,I-Cache需要支持一次读操作,D-cache需要支持一次读操作

和一次写操作。

减少流水线停顿。

两条指令之间的关系可以分为:数据相关和控制相关,数据相关分为;

数据相关即可以发生在存储器中也可以发生在寄存器中。

1):先写后读,(RAW,read after write),后一指令的操作数是该指令的结果。该指令的结果被后指令使用。真相关。

2):先读后写,(WAR,write after read),反相关,防止后一指令的结果对上一指令的操作数产生影响。

3):写后写,(WAW,write after write),两条指令的顺序不能改变。输出相关。

4):读后读,(RAR,read after read),无影响。

在以上的TYP的6级流水线中,可以发生的数据相关,是RAW相关。

要化解RAW相关,就要阻止后续的指令进入读相关寄存器的流水段中。知道前面的指令通过了相关寄存器的流水段。

除了停止执行发生相关的指令,还有一些更加有效的方法:

1):采用定向路径。前面的指令i与后面的指令j存在相关,对于RAW相关,指令j需要指令i的结果,则在指令i结束ALU之后,

ALU的输出可以通过一段物理的定向路径(Forwarding path)到达ALU的输入端,这样j指令执行时,可以直接使用,而不用等到i指令到达WB。

              如果指令i是load指令,指令j需要的数据需要在MEM段,也可以再增加一条定向路径。

ALU指令引起的RAW相关,称为ALU开销。Load指令的开销称为load开销。从MEM段和WB段到ALU的输入的路径称为定向路径。

2):流水线互锁实现。检测出所有的流水线相关,并保证所有的相关得到满足。包括停止流水线的某一段,以及,数据在定向路径中的传输控制。

RAW相关的检测是通过比较器,连续比较连续两条指令的寄存器标识来实现的。如果检测到数据的相关性,则使能相关的定向路径。

如果没有相关的定向路径,则停止流水线的某段。

流水线的互锁硬件还必须处理控制相关引起的流水线相关。

流水线处理器性能的主要障碍是指令相关引起的流水线停顿,其中控制相关引起的分支开销是最重要的部分。

动态分支预测能减少这一部分的开销,预测成功时,流水线没有停顿。在检测到预测失败时,必须清空流水线。

减少从取指段到完成分支指令段的距离也可以减少分支指令引起的开销。

在流水线处理器设计中,不仅仅数据通道被流水化了,连控制通道也被流水化了,传统的数据通道和控制通道被合并到同一条流水线。

标量流水线的局限性:

1):标量流水线的最大吞吐率不会超过每周期一条指令。

2):将不同类型的指令放在同一条流水线中处理,效率低下。

3):为了保证流水线的步调一致而插入停顿,使流水线产生很多气泡。

为了提高处理器的IPC,需要同一周期启动多条指令执行的方案,需要增加流水线的宽度,称为并行流水线

在典型的TYP6级流水中,IF,ID,RD执行相同的指令,但是ALU和MEM端却不尽相同。如浮点指令和部分定点指令,访存指令的延时等,

不同指令需要的资源和硬件性能都不同,使得流水线的执行阶段更难统一,为了解决这一局限性,在流水线的执行阶段,为不同的指令提供了不同的执行部件,

这样的流水线叫做多配置流水线

标量流水线是严格按顺序执行的,所有指令同步流动,且不会打断指令的原始顺序,某段的停顿会导致它之后所有段的停顿。如果多条指令可以绕过停顿的流水段,

则可以减少多个周期的开销,这种允许后续指令绕过停顿指令的技术称为指令的乱序执行。支持指令乱序的并行流水线称为动态流水线

并行流水线,同一时刻可以同时处理的最大指令数来衡量,程度相同的时间并行和空间并行理论上可以获得相同的加速比,

但是时间并行更加节省硬件,空间并行需要重复配置多个处理单元。如下的流水线,需要双端口的寄存器,双端口的cache,两套ALU。

多配置流水线,并行流水线在执行段配置了多个功能部件,并形成了多条流水线。多配置流水线,每条流水线只执行一种指令,

进行专门的优化设计并采用高效的硬件,来提高流水线效率,在进入分派之前就可以解决所有不同类型的指令相关,

这样可以把相关控制的复杂度控制在各条流水线中。

超标量流水线,如增加浮点流水线,乘法,除法,图形图像,信号处理的操作。

动态流水线

如图是一个发射宽度是3的动态多配置并行流水线,执行部分的4个流水化功能部件,前后各有一个再定序多记录缓冲。第一个缓冲称为分派缓冲,指令进入是顺序的,

流出是乱序的。后一个再定序缓冲,按程序的原始顺序将指令提交给写回段。

TEM模板的超标量流水线结构,TEM的6级流水线是指取指(Fetch),译码(Decode),分派(Dispatch),执行(Execution),完成(Complete),提交(Retire)

取指段:设计目标,增大取指段的宽度。取指段能够维持的吞吐率直接影响整个超标量流水线的吞吐率。

            主要障碍,读取的S条指令没有对齐,和指令cache的物理组织有关。

                          每个时钟周期,取指段用PC索引,将PC指向的指令连同后续的s-1条指令,一同取出。如果S条指令在一个cache的存储阵列中,

                          该行可以一次取出。如果S条指令跨越了阵列边界,S条指令就不能在一个周期内读出。

            解决方法:编译时的静态技术,将指令合理的放置在存储器中,保证每个分支目标的指令都放在Cache一行开始的位置。

                          硬件保证,即使指令跨越了阵列边界,也能一个周期内读出。

指令译码段:包括指令的识别以及指令之间相关性的检测。译码的复杂度,主要由ISA(指令体系结构)和并行流水线的宽度来决定。

            同时译码多条RISC指令,并确定指令间的相关性,以及确定分支指令的分支方向,译码段常成为超标量流水线中的关键路径。CISC会更加复杂。

指令分派:在指令译码和执行之间,还需要对指令进行临时的缓冲,某些操作数还没有准备好的指令可以放入一个单独的缓冲区内。在所有的操作数都就绪后,

              从缓冲区中读取指令到功能部件执行。这个临时的指令缓冲称为保留站。保留站将指令译码和执行加以分离,消除了译码段不必要的停顿。

              分派段后使用一个统一的缓冲,称为集中保留站。分派段后使用分离的缓冲,称为分布保留站。

指令执行:当前超标量设计的趋势是向着大规模并行和多条流水线的方向发展,配置了越来越多,越来越专用的功能部件。在超标量流水线中,

          各种部件的数量比例也是一个有趣的问题,一般由应用领域来决定,40%ALU指令,20%分支指令以及40%load/store指令。

          在实际的超标量流水线设计中,功能部件的数量大于并行流水线的宽度。由于超标量流水线的宽度是由每周期取指,译码,已完成的指令数来确定的,

          每次发射的指令类型都不同,不一定和功能部件类型匹配。同时为了避免结构相关带来的停顿,功能部件的数目必须大于流水线的宽度,

          才不会使执行段称为流水段的瓶颈。

中断和异常,经常会打断程序的执行,动态流水线的超标量处理器存在指令的乱序执行,所以在发生中断或异常时,

                 一种实现方案是停止取指段读取新指令,完成当前流水线中执行的执行,记录机器当前的状态,中断处理后,恢复机器状态,程序继续执行。

原文地址:https://www.cnblogs.com/-9-8/p/6129250.html