不清楚概念的话,先看王道书,或者看这篇:
计算机组成原理(11)----指令流水线_store指令的时空图-CSDN博客
结构冒险:
对于结构冒险,通常采用指令Cache和数据Cache分离的方法就能解决。
数据冒险:
在学习的指令中,Load指令和运算类指令会写寄存器,如果在没有写回寄存器之前,其他指令就尝试读这一指令,那么就会发生数据冒险。
控制冒险:
在学习的指令中,只有转移类指令可能会更改PC值,那么下一条要执行的指令就不是流水线中的下一条指令,则引起控制冒险。
判断是否存在数据冒险:
从第一条指令开始,结合注释,观察该指令"写"了某个寄存器,并观察后续相邻的3条指令是否"读"了同一个寄存器。若发现此类情况,则存在数据冒险。为什么只用看后面3条,看下面的图就懂了。
例题1:
I1写的是R1,观察后面3条指令,没有读R1,I1与其他3条指令不存在数据冒险;第二条指令写了R5,观察后续3条指令有没有读R5,I3读了R5,所以I2与I3存在数据冒险。
数据冒险的解决方法:
① 硬件阻塞 ② 转发(旁路)技术,转发旁路技术能解决大部分数据冒险,不能解决由 Load 指令写寄存器引起的 Load-use数据冒险(后面讲)
用硬件阻塞的方法解决如下:
由于阻塞期间I2一直占用IF段的硬件资源,所以只有I2段进入到了ID,下一段才能进入IF
例题2:
答案为C,自己分析一遍,以下为解决方法:
分析是否存在控制冒险:
只有转移类指令的执行才会引发控制冒险。因此只需观察指令序列中是否包含"转移类指令"即可。
解决方法:将转移类指令后一条指令的IF段硬件阻塞3个时钟。 这样就能保证后一条指令取指的操作,在转移类指令的第4段(M)之后在开始,这样才能保证后一条指令取指,取的是修改完PC后正确地址的指令。
例题:
第1条指令写了R4,而后面的2,3条指令都读了R4,所以需要确保第2条和第3条指令的ID段在第1条指令的WB段之后:
第2条指令与第3条指令之间也会产生数据冒险:
其余同理分析,会由于数据相关而产生阻塞的是2,3,4,6
很显然,第6条指令是转移类指令,所以会产生控制冒险。
为什么第1条指令和第5条指令存在数据相关?不是只有与后面3条指令才可以产生数据相关吗?
这是因为第6条指令是一条转移类指令,如果执行I6指令后,跳转到I1继续执行,那么I5和I1就有可能产生数据相关。
I5指令需要写R2,而I1需要读R2,所以I1的ID段需要在I5的WB段之后:
由于题目给了,分支指令的执行均引起3个时钟周期的阻塞,也就是后一个指令的IF段会推后3个时钟。看到下图,I1段的ID已经在WB段后面很多了,所以即使有数据相关,但是因为有3个时钟周期的阻塞,所以I1和I5不会因为数据相关而阻塞。
总结:关于数据冒险:后一条指令的ID段要在前一条指令的WB段之后
判断是否会产生数据冒险,则看该条指令的后3条指令有没有读 该条指令写的寄存器
关于控制冒险:后一条指令的IF段要在前一条指令的M段之后
转发技术处理数据冒险:
以 I1 举例,在通常的指令流水线中,执行(EX)阶段得到的结果,需要到WB阶段才能写回,而采用转发技术,可以直接将I1的EX的结果(放到EX/MEM流水段寄存器的结果)从流水段寄存器中取出,直接送到第2条指令的ALU输入端。
也就是说,即使I2的ID段取得数据是错误的,但是EX执行操作阶段,使用的数据是正确的,所以ID不需要进行阻塞3个时钟周期的操作。
为什么转发技术不能解决由 Load 指令写寄存器引起的 Load-use数据冒险
Load-use:Load指令将数据加载到寄存器中,下一条指令就需要使用寄存器中的值。例如下图的I2,I3指令:
Load指令会在M段结束后,才能在内存中获得最终的数据,然后在WB段才写回R[s3]
而下一条指令要在EX段就使用Load指令读出来的数据。
所以必须要让EX段阻塞一个时钟,阻塞一个时钟之后就可以使用转发技术将上一条指令M段的数据转发到下一条指令的EX段
由于I3指令阻塞了一个时钟,那么后一条指令I4,就必须阻塞4个时钟周期,使得后一条指令的IF段在前一条指令的M段之后:
完整解答:
总结:
① 对于控制冒险,如果采用硬件阻塞的方法,就要确保后一条指令的IF段在前一条指令的M段(修改PC值)之后。
② 对于数据冒险,可以使用硬件阻塞,也可以使用转发技术。如果采用转发技术,就不需要进行任何阻塞。但是转发技术不能解决由 Load 指令写寄存器引起的 Load-use数据冒险。对于Load-use指令,需要在EX段前进行一个时钟周期的阻塞。