在流水线的提交(Commit)阶段,之所以能够将乱序执行的指令变回程序中指定的顺序状态,主要是通过重排序缓存(Reorder Buffer, ROB)来实现的
- ROB本质上是一个FIFO
- 在它当中存储了一条指令的相关信息,例如这条指令的类型、结果、目的寄存器和异常的类型等
- ROB 的容量决定了流水线中最多可以同时执行的指令个数
- complete
- 当前指令已经执行完毕;
- Areg
- 指令在原始程序中指定的源寄存器,放的是逻辑寄存器的编号;
- Preg
- 源寄存器,重命名后,对应的物理寄存器编号;
- OPreg
- 该寄存器之前对应的旧的Preg;
- PC
- 指令对应的PC值,
- Exception
- 保存的是异常的类型,指令retire时,根据异常类型做相应的处理;
- Type
- 指令的类型,retire时,根据不同的类型,做不同的操作;例如store指令要写D-Cache、分支指令要释放Checkpoint资源等 ;
- complete
- 指令一旦在流水线的分发阶段占据了ROB中的一个表项,这个表项的编号会一直随着这条指令在流水线中流动,这样指令在之后的任何时刻,都可以知道如何在 ROB中找到自己。
- 一条指令一旦变为 ROB 中最旧的指令并且它的 complete状态位也为1,就表示这条指令已经具备退休(retire)的条件了。
- 如果这条指令在之前没有发生过异常,也就是它在ROB中对应的exception部分为0,则这条指令可以顺利地离开流水线,它的结果可以对处理器的状态进行更新;
- 如果这条指令发生过异常,那么就要启动异常的处理过程;
通过如下的例子,来说明ROB的执行情况
- i1是除法,i2使用i1的结果,所有这两条指令的执行时间会很长;
- 因为乱序的存在,i3/i4会先执行;
- 但是i3/i4执行完成后,不能将结果写入寄存器;
- 下图中,显示了ROB在三个时间点的情况:
- i1~i3重命名后,申请对应的ROB entry, 并将相应的信息写入ROB, 包括逻辑寄存器,重命名后的物理寄存器;
- 经过一段时间,i3/i4结果已经计算出来,标记为complete状态;
- 因为i3/i4不是ROB中最老的指令,因此虽然标记为complete,仍然不能retire;
- 当i1变为complete时,因为其是最老的指令,因此,可以retire, ROB的head 指针往下移动;
一般情况下,在流水线的分发(Dispatch)阶段,每周期最多可以进入ROB的指令个数会等于ROB每周期最多可以退休的指令个数,这样可以保持流水线的畅通;