指令周期和指令流水线
指令周期
指令周期:处理单个指令的时间,简单分为取址周期和执行周期
状态图:
并非所有指令的周期都一样
带中断的指令周期
如果中断允许,那么会在执行指令结束后,检查有无中断及处理中断
状态图:
间址周期
间接寻址,在取操作数时需要额外的存储器访问
间址周期:把间接地址的读取看成一个额外的指令子空间
状态图:
取操作数发生了两次:根据地址取有效地址,再根据有效地址取操作数
CPU的任务
- 取指令
- 解释指令
- 取数据
- 处理数据
- 写数据
CPU需求:寄存器:
- 1个存储地址寄存器:MAR
- 1个存储缓冲寄存器:MBR/存储数据寄存器:MDR(这两者并没有太大的区别)
- 一个程序计数器:PC
- 一个指令寄存器:IR
数据流:取值周期
1、控制器下达指令:取址周期的开始
2、通过MAR讲PC中的地址传入地址总线,同时控制器通过控制线通知存储器地址就绪,然后存储器读取地址。
3、存储器通过数据总线讲数据发送给MBR。如果是异步总线,存储器提供反馈
4、指令取回来后,PC+“1”(往后一个地址)
数据流:间址周期
1、将MBR中的地址引用送入MAR,MAR将地址传入地址总线,控制器通过控制总线通知存储器取地址
2、存储器通过数据总线将有效地址发送给MBR
数据流:中断周期
1、处理中断前,将下一条指令放到MBR中,再放到数据总线上
2、控制器将下一条指令的取值地址通过MAR放到地址总线上
3、控制器通知存储器获得数据,存储器从地址线获得地址,存储器从数据线获得数据,并将数据写入到获得的地址
指令流水线
一条指令的处理过程被分成若干个阶段,每个阶段由相应的功能部件完成
两阶段方法:将指令处理分成两个阶段:取指令和执行指令
- 在当前指令的执行期间取下一条指令
存在的问题:
- 执行时间一般要长于取指时间
- 主存访问冲突(同时有多个指令要访问主存)
- 条件分支指令使得待取的下一条指令的地址是未知的(也许是按顺序执行,也许会跳转到其他的指令处)
六阶段方法:
- 取指令(FI)
- 译码指令(DI)
- 计算操作数(CO)(计算每个原操作数的有效地址)
- 取操作数(FO)
- 执行指令(EI)
- 写操作数(WO)
各个阶段所需要的时间几乎是相等的
存在的问题:
- 不是所有指令都包含6个阶段(LOAD指令不需要WO阶段)
- 不是所有的阶段都能并行完成(FI/FO/WO都涉及到存储器访问)
- 六个阶段不全是相等时间时会在各个流水阶段设计某种等待
- 条件转移指令使得若干指令的读取变为无效
- 中断:提前处理到一半的过程都需要被清除
超流水线
- 将六级流水线细分为更多的阶段,增加流水线的深度
- 提升时钟频率,从而提高指令吞吐率(但是可能会导致指令的级数增加)
流水线性能
假设:
- :流水线第i段的电路延迟时间
- :最大段延迟(通过耗时最长段的延迟)
- :指令流水线段数
- :锁存延时(数据和信号从上一段送到下一段所需的段间锁存接收时间)
可以得出:
- 周期时间(进行完一次指令中的一段的时间):
- k阶段流水线执行完n条指令的时间:(理想情况)
- 加速比(不使用流水线与使用流水线情况下的执行n条指令所画时间之比):
并非流水线中的阶段数越多,执行速度越快(每个阶段都存在锁存延时等开销,同时控制逻辑数量也会急剧增加)
超标量流水线
具有两条或两条以上并行工作的流水线结构
单周期->标量流水线:时间并行性的优化,主要是对现有硬件的分段
标量流水线->超标量流水线:空间并行性的优化, 需成倍增加硬件资源
冒险
在某些情况下,指令流水线会阻塞或停顿(stall),导致后续指令无法正确执行
类型:
- 结构冒险(不同指令同时使用相同的硬件资源,比如访存)
- 数据冒险(有些数据要等前序计算完成)
- 控制冒险(比如条件转移)
结构冒险
已进入流水线的不同指令在同一时刻访问相同的硬件资源
解决方法:
1、在指令之间插入空泡(等待一个时钟周期再开始执行下一条指令)
2、使用不同用途的多个存储器(例如:指令和数据放在不同的Cache中)(分开访问不同存储器)
3、同一个存储器提供分时处理(例如:寄存器时钟上升沿写,时钟下降沿读)
数据冒险
未生成指令所需要的数据(例如:一条指令需要使用之前指令的运算结果,但是结果还没有写回)
解决方法:
1、插入nop指令(软件)(表示这个指令什么都不做,来确保需要用到的数据在之前的指令更新后再取出)
2、插入bubble(硬件)(也是什么都不做,但是会导致效率低下,流水线失去意义)
3、前递(forwarding) / 旁路(bypassing)(分别表示直接从一个执行单元将数据传递给另一个执行单元、以及传递给需要这个数据的指令)(无法解决:一条指令需要使用之前指令的访存结果)
4、交换指令顺序(将一些与之前的操作没有关联的指令先行执行,来增加有关联的指令之间的时间间隔,避免冲突)
控制冒险
指令的执行顺序被更改,导致先前流水线执行的指令作废
解决方法:
1、取多条指令(多个指令流(使用两个指令流),预取分支目标(取分支指令之后的指令的同时也取分支目标处的指令),循环缓冲器(维护一个小高速存储器,含有n条最近顺序取来的指令))
2、分支预测(静态预测(规则不变,如预测绝不跳转或总是跳转),或动态预测(规则变化,如预测发生/不发生转移、以及转移历史表))
- 发生/不发生切换
仅在连续两次发生错误时改变状态
- 转移历史表(记录过去遇到的分支时的情况,每次进行分支时查询该表)
3、提前判断
- 直接无条件转移:例如 j Target,在取指阶段即可获得转移目标地址(流水线不停顿)
- 间接无条件转移:例如 jr $r1,在译码阶段才能获得转移目标地址(流水线停顿1周期)
- 直接有条件转移:例如 beq $r1, $r2, Target,在执行阶段才能获得转移目标地址(流水线停顿2周期),在寄存器堆输出端增加额外的比较电路(流水线停顿1周期)
4、交换指令顺序(提前执行判断指令,将与判断指令无关的在判断之前的指令放到判断指令后面)