计算机体系结构——指令的执行和流水线技术

指令流水线把一条指令的执行划分为若干阶段来减少每个时钟周期的工作量,从而提高主频;并允许多条指令的不同阶段重叠执行实现并行处理。
这样虽然一条指令的执行时间不变,但处理器再单位时间内处理的指令数增加了。

1. 常用的流水线技术

  1. 转移预测技术
    典型的程序平均5~10条指令中就有一条转移指令,而转移指令的后续指令需要等转移执行完成后才能取值,造成流水线效率降低。
    在转移指令的取指或 译码阶段预测该转移指令的跳转方向和目的地址并进行后续指令的取指,而在转移指令执行后,根据已确定的目的地址修正预测结果;若预测错误,需要取消流水线中后续的指令。
  2. 乱序执行技术
    通过动态调度允许指令i后面的源操作数准备好的指令越过指令i执行,以提高效率
  3. 超标量技术(多发射)
    允许流水线的每一阶段可以处理多条指令。发射的概念见第4大点动态调度部分。

2. 以5级流水线为例

可以先借助多周期处理器理解CPU指令执行流程,再过渡到流水线处理器

  • (1)5级分别为取指,译码,执行,访存,写回五个操作
  1. 取指(IF):
    根据PC读出指令地址,根据地址从指令存储器中取出指令,随后PC+4准备下一次取指。
     
  2. 译码(ID):从指令中解析出相关控制信号,并读取通用寄存器堆
  3. 执行(EX):运算器对通用寄存器堆读出的操作数进行计算
  4. 访存(MEM):

    将执行结果读取或者写入到存储器

    在CISC中,CPU可以对内存直接进行读取和写入操作;但在RISC中,CPU需要通过寄存器对内存操作,而寄存器与内存间的通信则需要LSU来完成。load store unit为加载存储单元,管理所有load, store操作。

  5. 写回(WB):将结果写回到通用寄存器堆
  • (2)多周期处理器

该处理器通过使用分频时钟,确保在同一指令后几个时钟周期执行时,控制逻辑因没有就受到下一时钟沿所以不会发生变化。


如上图所示:
在第一个时钟周期,通过PC取出指令,在第二个时钟上升沿锁存到指令码触发器R1;
在第二个时钟周期,将R1译码并生成控制逻辑,读取通用寄存器,读出结果在第三个时钟上升沿锁存到R2;
在第三个时钟周期,使用控制逻辑和R2进行ALU运算。

在指令执行过程中,寄存器虽时钟的变化如图所示,以指令add x1, x2,x3为例:
计算机体系结构——指令的执行和流水线技术_第1张图片

  • (3)流水线处理器

该处理器通过在每级流水的触发器旁再添加一批用于存储控制逻辑的触发器。指令的控制逻辑借由这些触发器沿着流水线逐级传递下去,从而保证各阶段执行时使用的控制逻辑都是属于该指令的。

从上图虚线可见,运算器进行计算的信息来源于控制逻辑2,即锁存过一次的控制逻辑,刚好与R2中存储的运算之同属一条指令。同时图中取消了R3阶段写通用寄存器的通路,而将R3的内容锁存一个时钟周期,统一使用控制逻辑4和R4来写。
计算机体系结构——指令的执行和流水线技术_第2张图片
如上图流水线时空图,如当某一条指令译码时,下一条指令开始取指,上一条指令开始执行。

3. 流水线冲突

可根据产生冲突的指令的相关分为3类:数据相关,控制相关和结构相关

  1. 数据相关
    在程序中,若两条指令访问同一寄存器或内存单元,且至少有一条是写入操作,则是数据相关冲突。

    解决办法1:采用阻塞方式
    即将被组设流水线所在的寄存器保持原值不变,同时向被阻塞流水线的下一级流水线输入指令无效信号,用流水线空泡填充
    解决办法2:流水线前递技术
    即上一条指令在执行阶段完成后即从寄存器中取出供下一条指令使用,不必等上条指令一级一级执行完后读取
  2. 控制相关
    若转移指令执行尚未完成,下一条指令与上一条指令相同操作数的程序计数器PC已经开始取指了,从而取出了错误的值,造成控制相关冲突,其本质是对程序计数器PC的冲突访问引起的。

    解决办法1:在取指阶段引入2拍的流水线阻塞
    解决办法2:采用转移指令的延迟槽技术
    在定义指令系统的时候就明确转移指令延迟槽指令的执行不依赖于转移指令的结果
  3. 结构相关
    两条指令要同时访问流水线中的同一功能部件

4. 提高流水线效率的技术

  • (1)动态调度

即把相关的解决尽量往后拖延,同时前面指令的等待不影响后面指令继续前进。

例如:DIV    $3, $2, $1
           ADD  $5, $4, $3
           SUB  $8, $7, $6
SUB指令的操作数与前面的指令没有关系,可以在前面指令间的相关引起阻塞而空闲的时候“见缝插针”地提前执行。

  1. 要完成上述操作,需要对原流水线作一些改动:
    首先,将原译码阶段拆分成“发射”和“读操作数阶段”。发射阶段进行指令译码并检查结构相关,随后在读操作数阶段则一直等待直到操作数可以读取。

    处于等待状态的指令将会被存放在保留站中,也称为发射队列,这也是动态调度中的核心部件。保留站的作用是记录下描绘指令间相关关系的信息,控制存放的指令执行时间,同时监测每条指令的执行状态。保留站会在每个时钟周期选择一条没有被阻塞的指令,送往执行逻辑,并退出保留站,该动作称为发射。
  2. 消除WAR和WAW在动态调度时产生的冲突:
    记分板办法:保留站判断出未发射的指令与前面尚未执行完毕的指令存在WAR和WAW相关,就阻塞其发射,直至冲突解决。

    Tomasulo算法:通过硬件寄存器重命名,将出现冲突指令的相关关系记录下来,有相关的等待,不相关的今早送到功能部件执行。
  3. 精确异常问题
    异常的来源包括:外部事件、指令执行中的错误,数据完整性问题、地址转换异常、系统调用等。精确异常要求处理器处理完异常后,回到产生异常的地方,还能处理正确。

    在动态调度中,原先指令执行的先后被打乱,当异常来临时,指令该如何先后执行?发生异常后面的指令都不能修改机器状态,万一这些指令越过发生异常的指令提前执行了,该如何避免?
    解决办法是在流水线中添加一个重排序缓冲(ROB),用来维护指令的有序结束,同时在流水线中增加一个“提交”阶段,用来对已经完成的指令做最后处理,更新某些寄存器状态。如上图所示。
    ROB是一个先进先出的有序队列,所有指令在译码后按程序顺序进入队列尾部,所有执行完毕的指令从队列头部按序提交;提交时一旦发现有指令发生异常,则在ROB中将该指令及其后面的指令全部清空,也无法提交,也就不会修改机器状态;发生异常的指令出现在ROB头部时,这条指令前面的指令已经从ROB头部提交并退出了,这些指令对机器状态的修改都生效了;
  4. 总结完整的调度流程
    取指:不变

    译码:先译码后发射
    正常译码后,把操作队列的指令根据操作类型送至保留站,前提是保留站和ROB都有空,并在ROB中指定一项作为临时保存该指令的结果;发射时读寄存器的值和结果状态域,如果结果状态域指出结果寄存器已被命名到ROB,则读ROB

    执行:准备好操作数则执行,否则根据结果ROB号侦听结果并接收结果总线值

    写回:把结果送至结果总线,释放保留站;ROB根据结果总线修改相应项

    提交:如果队列中第一条指令的结果已经写回且没有发生异常,把该指令的结果从ROB中写回到寄存器或存储器,释放ROB相应项;若队列头的指令发生异常,队列和ROB清空。
  • (2)多发射数据通路

增加发射通路,让每级流水线都可以同时处理更多的指令
可大幅度降低CPI(每条指令执行的周期数),但是要解决多条指令相关冲突,还要core中的各种资源翻倍,实际效率是要大打折扣的

  • (3)转移预测

上述解决控制相关冲突的解决办法并不普世,现代处理器普遍采用硬件转移预测机制来解决转移指令引起的控制相关阻塞。其基本思路是在转移指令的取指或译码阶段预测出转移指令的方向和目标地址,并从该地址继续取指令执行,这样在猜对的情况下无需阻塞流水线
实现分为两步:预测和确认
预测:在取指或译码阶段预测转移指令是否跳转以及转移的目标地址,并根据预测结果进行后续指令的取指
确认:在转移指令执行完成后,比较最终确定的转移条件或转移目标与之前预测的结果是否相同,如果不同则需要取消预测后的指令执行,并从正确的目标重新取指执行。

你可能感兴趣的:(计算机结构)