【Computer Organization笔记14】指令流水中的控制冲突和异常

本次笔记内容:
P27 计算机组成原理(27)
P28 计算机组成原理(28)
P29 计算机组成原理(29):前24分钟

本节课对应幻灯片:

流水线的冲突

  • 结构冲突:是指令在重叠执行的过程中,硬件资源满足不了指令重叠执行的要求而产生的冲突;
  • 数据冲突:是指在同时重叠执行的几条指令中,一条指令依赖于前面指令执行结果数据,但是又在指定的数据源中得不到时发生的冲突;
  • 控制冲突:是指流水线中的分支指令或者其他需要改写PC的指令造成的冲突。

结构冲突和数据冲突

结构冲突:在同一时刻,由于指令重叠执行,不同指令争用同一硬件资源。

  • 暂停流水线(一般不用)
  • 重复设置资源

数据冲突:由于指令重叠执行,造成指令间执行步骤的相对时间发生变化,后续指令无法在预期的位置得到正确的源操作数。

  • 暂停流水线
  • 数据旁路:检测、传送(给出最新鲜的数据)
  • 优化编译器
  • 动态调度

此外,数据冲突还可以使用动态调度

  • 这种方法是由硬件动态调整指令执行顺序以减少暂停的影响,能够简化编译器设计。
  • 动态调度并不能真正消除数据冲突,但它能在出现数据冲突时尽量避免出现处理器暂停。而静态调度方法则是尽量通过分离有冲突问题的指令使它们不会导致冲突,从而减少暂停的影响。
  • 动态调度的主要思想:指令顺序发射——乱序执行——指令乱序流出
  • 动态调度的问题:异常处理的不精确性。在采用动态调度方法的处理机中,在某条指令产生异常情况时,有可能出现其后面的指令已经执行完成的情况,这样异常处理是不精确的。

动态调度的内容将在系统结构中讲解。

控制冲突

流水线的控制冲突是因为程序执行转移类指令而引起的冲突。转移类指令如无条件转移、条件转移、子程序调用、中断等,它们属于分支指令,执行中可能改变程序的方向,从而造成流水线断流。

数据冲突影响到的仅仅是本条指令附近少数几条指令,所以称为局部冲突。而控制冲突影响的范围要大得多,它会引起程序执行方向的改变,使流水线损失更多的性能,所以称为全局冲突

控制冲突会使流水线的连续流动受到破坏。当执行条件转移指令时,有两种可能结果:

  • 如发生转移,将程序计数器PC的内容改变成转移目标地址;
  • 如不发生转移,只将PC加上一个增量,指向下一条指令的地址。

控制冲突

数据冲突:由于寄存器数据的缺失引发。

而相比之下,控制冲突是由于PC的缺失引发的,PC值是由条件转移和无条件转移指令控制的。

控制冲突对性能影响更大。 因为,IF在指令流水的第一个阶段。(多周期CPU情况下,对于JUMP,在第二阶段ID上升沿的情况下可以拿到目的地址PC;对于BEQ,在三个阶段EXE两个源操作数做减法,那这个数去选择地址,才能拿到正确的PC值)


如上,所有指令都要在IF阶段使用PC;对于转移指令,至少要到EXE阶段才能得到正确的PC。需要暂停流水线一个或者两个周期。

控制冲突的处理

暂停流水线:

  • 直到有了正确的转移地址
  • 造成性能的降低

预测分支不成功:

  • 顺序执行下一条指令(赌他不会转移)
  • 预测失败后要清除错误启动的指令(赌错了,转移了)

预测分支成功(赌他会转移)

  • 更复杂一些,因为要计算转移目的地址(这个其实比较难办)
  • 预测失败后要清除错误启动的指令

动态预测:

  • 硬件根据上次分支的结果进行本次预测

编译器处理:

  • 延迟槽用空操作指令loop,防止转移指令后出现控制冲突

暂停流水线

控制冲突简单解决方法:一旦发现分支指令就暂停流水线,即暂停该指令之后的所有指令,直到分支指令达到MEM段确定了新的PC值为止。

暂停几个周期,可以根据操作码知道。


简单方法处理时空图如上。

减少流水线处理分支指令时暂停周期数的方案:

  • 在流水线中尽早判断出分支转移是否成功
  • 尽早计算出分支成功转移时的PC值(如分支的目标地址)。

可能对于上表的情况,将 EX 提前到 ID 时进行,可以减少一个时钟周期的暂停。

支持流水的CPU


如上,从流水线上来看,计算转移的目的地址放在EXE阶段,判断是否能成功转移,也是放在EXE阶段。

对于计算转移的目的地址是有可能提前的。其所需计算值在上一阶段前就出现。但是判断是否能成功转移搬不到前面去。再加一个 ALU 是个办法,但是成本有些高。

对于 BEQ 这条指令,可以做个简单的异或,来进行判断。因此对于 BEQ 加一个异或门。

暂停流水线


如上是原来的流水线。

减少暂停周期数:

  • 在流水线中尽早判断出分支转移是否成功;
  • 尽早计算出分支成功转移时的PC值(如分支目标地址)。
修改后的数据通路

硬件在ID阶段就确定需要的信息,增加:

  • 目标地址加法器
  • 寄存器比较器

例子程序 Branch Taken :

36:  sub  $10, $4, $8
40:  beq  $1,  $3, 7
44:  and  $12, $2, $5
48:  or   $13, $2, $6
52:  add  $14, $4, $2
56:  slt  $15, $6, $7
     ...
72:  lw   $4, 50($7)


上图是 Clock 3 时。

上图是 Clock 4 时,写了一个空泡

与数据冲突的暂停不同的是:要把旧的指令清楚,写空泡

增加的部件

数据通路

  • 增加比较器,完成源操作数的比较
  • 调整加法器到ID段,完成转移地址的计算

控制信号

  • 根据比较结果,若相等则转移
    • PCsrc选择转移目标地址(PC ←目的地址)
    • 清除IF/ID段寄存器的值(IF/ID寄存器←NOP)
    • 当前指令的控制信号为0(ID/EX寄存器←0)
  • 若不等,则顺序执行
    • PCsrc选择顺序执行(PC ← PC+4)
    • 保留IF/ID段寄存器的值(IF/ID寄存器←BEQ的后一条指令)
    • 当前指令的控制信号为0(ID/EX寄存器←0)

r1 与 r2 还有数据冲突怎么办?数据旁路需要大家自己思考。

其实上述过程中已经做了预测(已经预测了分支转移不成功)。

分支预测

减少流水线分支开销的方法:

  • 预测分支转移失败的方法 :译码到一条分支指令指令时,就像分支指令就是一条普通的指令那样,流水线继续取后续的指令,并且允许分支指令后续指令在流水线中正常流动;发现预测错误后,要清除已执行指令的影响。
  • 预测分支转移成功的方法 :一旦完成分支指令的译码并且计算出了分支的目标地址,就假设分支转移成功,并且开始在分支目标地址处取指令执行;发现预测错误后,要清除已执行指令的影响
  • 分支延迟(延迟转移)的方法 :编译器在做。
预测分支转移的方法

预测分支失败
  • 转移不会发生
  • 继续执行下一条指令
  • 如果正确,则不会在性能上有任何损失
  • 如果错误,则要消除影响

控制冲突的动态调度

分支目标缓冲技术(Branch Target Buffer)

  • 缓冲区的每一项内容被用来预测分支转移是否成功,并且根据实际的分支情况对内容进行修改。这种方法是基于如下的考虑:如果本次分支转移成功了,那么预测下一次分支转移也成功,例如一个循环体就是这种情况。
  • 将分支转移成功的分支指令的地址和它的分支目标地址都放到一个缓冲区中保存起来,缓冲区以分支指令的地址作为标志;在取指令阶段,所有的指令地址都与保存的标志作比较,如果相同,就认为本条指令是分支指令,而且认为它分支转移成功,同时它的分支目标(下一条指令)地址就是保存在缓冲区中的分支目标地址。
预测实现的方法


增加分支目的地址存储(Branch Target Buffer)。

首次遇到新的PC,保存它的下一条指令的地址:

Pc+4               alu/lw/sw
Pc+offset        BEQ/J
??                   JR

机理(这种预测方法为什么能起作用):程序的局部性

减少 BTB 容量


只保存转移指令的PC值。

动态预测

  • 统计规律表明,如果上次发生转移,则本次发生转移的概率更大;
  • 反之亦然
  • 提高预测准确率到90%以上。


增加1位BHT位,实现动态预测:BHT: Branch history table

程序设计举例
LI R1 1
LI R2 1
LI R3 40 
SLL R3 R3 0
LI R4 9
SW R3 R1 0
SW R3 R2 1
ADDU R1 R2 R1
ADDU R1 R2 R2
ADDIU R3 2
ADDIU R4 FF
BNEZ R4 F9

静态预测:

  • 顺序执行
  • 准确率:1/10

动态预测:

  • 第1次错误
  • 第2~9次正确
  • 第10次错误
  • 准确率:8/10
动态预测(2位预测位)

  • 连续两次预测错误时才改变预测方向;
  • 对多重循环,可进一步提高预测准确率 。

延迟槽(交给编译器)


无论分支转移成功与否,延迟槽内的指令都要执行。如果分支转移失败,只需要按取来的指令执行;否则,按照分支目标地址的指令执行。

延迟槽指令的选择

选择放到分支延迟槽中的指令必须按照一定的原则经过编译器的调度。对分支延迟的三种调度方法:

延迟槽方式的比较

三种调度方法的所受的限制,以及他们各自的应用场合。

异常

什么是异常?

  • CPU运行时会遇到突发的不正常事件,如:
    • 指令执行过程中发生错误
    • 取指令、指令译码、计算、访存
    • 外部设备提出服务请求
    • 多进程运行时与其他进程发生资源冲突

中断程序正常执行流程的事件:

  • 来自CPU,称为异常
  • 来自外部设备,称为中断

异常响应和处理

很难在程序中进行处理

  • 时间、空间的不确定性

对程序“透明”处理

  • 程序正常运行
  • 由硬件检测发生异常或中断
  • “透明”地自动转换到服务程序进行响应和处理
    • 保存现场
    • 启动服务程序
  • 返回到程序执行
    • 恢复现场

异常处理的实现


增加异常原因寄存器,保存异常的原因:

  • 错误的指令地址、错误的操作码、错误的运算结果、错误的数据地址
  • 外部中断请求编号

发现异常:

  • 增加一个步骤,检查中断寄存器和异常原因寄存器

异常处理的实现

保存现场

  • EPC
  • 当前的状态等(状态寄存器)

转异常处理程序(中断服务)

  • 根据异常原因,寻址处理程序的入口(PC的来源)
  • 跳转到处理程序执行(与转移指令相同)

处理完成后,返回主程序执行。

单周期CPU的异常处理


在启动下条指令之前,来判断是否有异常。

多周期的异常处理


增加一个检查异常(中断)是否发生的步骤。道理与单周期同。

流水线CPU的异常处理


以“溢出”为例。

把前面的指令正常执行完,把后面的指令变成空操作。把写寄存器、写存储等都清空,改成0。

把新PC值赋给PC(根据中断的原因)。

处理要求:

  • 指令流水线中有5条指令正在执行
  • 判断发生异常的位置
  • 保留发生异常的现场
  • 执行异常处理程序

硬件:

  • EPC
  • Cause

大家可以去查 MIPS CP0 的手册,实现之,来完成异常的处理。

精确处理和非精确处理

精确异常处理:

  • EPC中保存有发生异常指令的地址
  • 操作系统处理简单
  • 指令流水情况下实现比较复杂

非精确异常处理:

  • EPC中保存当前PC或者近似的PC
  • 由操作系统处理

小结

冲突问题及解决方案:

  • 结构冲突
  • 数据冲突
  • 控制冲突

控制冲突:

  • 全局冲突
  • 综合解决方案
    • 硬件、编译器
    • 猜测、尝试

异常:

  • 发现和响应
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页