19. 流水线的冒险

流水线本质是提高了时间并行性,这样可能会带来一些错误。

1. 什么是冒险hazard

阻止下一条指令在下一个时钟周期开始执行的情况。

2. 冒险的分类

2.1 结构冒险

所需的硬件正在为之前的指令工作。

2.2 数据冒险

需要等待之前的指令完成数据的读写。

2.3 控制冒险

需要根据之前指令的结果决定下一步的行为。

3. 结构冒险举例

3.1 结构冒险举例1

如下图所示,我们之前的笔记用各个阶段的缩写表示,现在我们用每个阶段用到的部件来表示。如果这个数据通路的指令存储器和数据存储器是同一个存储器,那么第一条lw指令和第四条指令就会发生结构冒险,lw指令访存的同时第四条指令同时也要使用存储器,而存储器同一时刻只可以接受一个读操作。

结构冒险举例1

这个结构冒险的第一种解决方案,就是插入空泡bubble,让流水线停顿stall一个周期,如下图所示,

插入bubble解决流水线结构冒险问题

插入空泡就是设置各个控制信号为不影响流水线状态的信号。

插入空泡是最简单也是最容易实现的方法,但是非常影响流水线的效率。那么这里解决这个访存结构冒险的第二个方案就是采用哈佛结构,指令存储器和数据存储器单独设置。注意这里是指令高速缓存和数据高速缓存是哈佛结构,内存等其他存储器仍然是冯诺依曼结构。

3.2 结构冒险举例2

再看一个结构冒险的例子。如下图所示,

结构冒险举例2

第5个时钟周期发生了结构冒险,有两条指令同时使用Reg。解决方案很简单,因为设计之初就考虑了这种结构冒险情况,寄存器堆的读写较快,我们前半个时钟周期写,后半个时钟周期读,并且独立设置读写口,就避免了这样的结构冒险。

4. 数据冒险

如下图所示,第一条sub指令的结构在第5个时钟周期写回寄存器t0,而第2条add指令第3个周期译码阶段就要读取t0的值,也就是sub的运算结果。这里就发生了数据冒险。

如果不做任何处理,那么add指令读回的t0的值肯定是错误的,因为此时sub指令的结果还没有写回。

数据冒险举例

解决方案可是使用那个万能解决方案,即插入bubble,stall流水线,如下图所示,

使用stall流水线的方法解决数据冒险

5. 控制冒险

如下图所示,就是一个控制冒险的例子,第一条指令是一个beq指令,第二条指令要在第2个时钟周期取指,但是取哪条指令要等到beq判断完成才可以知道,也就是beq的ALU计算完成后才可以知道下一条指令应该取哪一条,这里就发生了控制冒险。

控制冒险举例

解决方法也可以是那个万能方法,插入bubble,stall流水线,等到beq判断出下一条指令,如下图所示,

插入bubble解决控制冒险

总之,你可以使用stall流水线的方法解决流水线冒险,但这样设计出来的流水线就没有价值了。

你可能感兴趣的:(19. 流水线的冒险)