MIPS流水线数据冒险识别与带转发机制停顿问题求解
MIPS流水线冒险与转发机制习题解答
给定测试代码
slti $t1, $t2, 24 add $t4, $t1, $t3 sub $t5, $t4, $t1 sw $t1, 150($t4) subi $t3, $t5, 1 lw $t1, 30($t2)
第一问:三类数据冒险判定校验
首先明确三类数据冒险的核心判定规则:
- RAW(写后读,真数据相关):后序指令需要读取的源寄存器,是前序指令的目标写寄存器,且前序指令还未完成写回时后序就要读,会读到旧值。
- WAW(写后写,输出相关):两条指令存在相同的目标写寄存器,若后序指令先完成写回,会导致寄存器最终值不符合程序顺序预期。
- WAR(读后写,反相关):前序指令需要读取某源寄存器,后序指令写同一个寄存器,若后序指令先完成写回,会导致前序指令读到错误的新值。
原判定结果的错误修正
- RAW冒险部分:原列表漏了2组RAW,完整列表为:
- slti → add:slti写$t1,add源操作数读$t1
- slti → sub:slti写$t1,sub源操作数读$t1
- slti → sw:slti写$t1,sw待存储的源操作数是$t1
- add → sub:add写$t4,sub源操作数读$t4
- add → sw:add写$t4,sw计算访存地址时读基址寄存器$t4
- sub → subi:sub写$t5,subi源操作数读$t5
- WAW冒险部分:原判定的
add-swWAW完全不成立。sw是存储指令,功能是将寄存器值写入内存,不存在通用寄存器写回操作,没有写寄存器的行为,不可能和写$t4的add构成写后写冲突。在标准按序执行、按序写回的5级MIPS流水线上,这组代码不存在WAW冒险:仅slti和lw两条指令写同一个寄存器$t1,二者按程序顺序分别在第5、第10周期完成写回,顺序完全正确。 - WAR冒险部分:原判定「无WAR冒险」的结论是正确的。
这组代码不存在WAR的核心原因是:所有写寄存器的操作,对应前序读同寄存器的指令,都在写操作完成前就结束了寄存器读阶段(MIPS 5级流水线的寄存器读在D译码阶段完成,早于所有后续指令的W写回阶段),不可能出现后序写先于前序读完成的情况。
WAR冒险具体示例
WAR冒险基本只在乱序执行、支持长延迟指令乱序写回的流水线中出现,例如下列代码:
div $t0, $t1, $t2 # 除法是长延迟指令,执行需要10个周期 addi $t1, $t3, 1 # 加法是单周期短指令
如果流水线允许乱序执行,addi会远早于div完成执行并写回$t1,而div原本需要读取addi执行前的旧$t1值,此时就会读到addi写入的新值,触发WAR冒险,一般通过寄存器重命名机制解决。
第二问:支持转发的5级流水线时序校验
首先明确转发机制的适用规则:
- 算术/逻辑运算指令的结果在E执行阶段结束就已生成,可以从E/M、M/W流水寄存器直接转发给后续指令的ALU输入端,不需要等写回阶段。
- 唯一的转发例外是
lw加载指令:加载的结果需要到M访存阶段结束才能从内存读出,如果lw的直接下一条指令需要用lw的目标寄存器值,无法通过转发覆盖,必须插入1个周期的停顿(即load-use冒险)。
回到题目给出的时序:
SLTI F D E M W ADD F D E M W SUB F D E M W SW F D E M W SUBI F D E M W LW F D E M W
这个时序是完全正确的,不需要插入任何停顿:
- 所有算术指令的RAW相关都可以通过转发解决:相邻指令的操作数从E/M寄存器转发,隔一条指令的操作数从M/W寄存器转发,没有时序缺口。
- sw指令需要的基址$t4、待存值$t1,都可以通过转发路径在E(地址计算)、M(内存写入)阶段拿到正确值,不需要停顿。
- 最后一条lw指令后面没有其他指令,不存在load-use冒险,不需要停顿。
内容的提问来源于stack exchange,提问作者Luca Pedersoli
相关产品推荐
相关产品推荐

