MIPS代码RAW依赖识别与流水线nop插入问题求解
MIPS流水线RAW依赖校验与nop插入方案
原始代码段
(1) Loop : lw $2, 0($1) (2) lw $3, 0($2) # 读取$2 (3) add $4, $3, $2 # 读取$3、$2 (4) sw $4, 4($2) # 读取$4 (5) beq $4, $5, Loop # 读取$4
一、RAW依赖识别结果校验
你的判断完全准确,列出的就是代码中全部的RAW(写后读)真依赖,无遗漏无误判:
- 指令1
lw写入$2,后续指令2访存地址计算、指令3加法操作都需要读取$2,存在两组RAW依赖 - 指令2
lw写入$3,后续指令3加法操作需要读取$3作为源操作数,存在一组RAW依赖 - 指令3
add写入$4,后续指令4存数操作、指令5分支比较操作都需要读取$4,存在两组RAW依赖
代码中不存在额外的RAW依赖,也不存在WAR(读后写)、WAW(写后写)类的假依赖。
二、无硬件冒险检测、全转发场景下的nop插入方案
首先明确给定流水线规则对应的软件插nop判定标准:
- 全转发(旁路)逻辑可将EX、MEM阶段产生的结果直接转发给后续指令的对应执行阶段,仅
lw类加载指令存在特殊的load-use冒险:lw要到MEM阶段结束才能拿到访存结果,若下一条指令的EX阶段直接使用lw写入的寄存器,即使全转发也存在1周期的时间差,必须插入1个nop填补 - 无硬件冒险检测逻辑,所有流水线暂停都需要通过软件插入nop实现,不能依靠硬件自动插入气泡
- 分支指令
beq在ID阶段完成条件判定和目标地址计算,仅存在1周期控制冒险:分支指令取指后,下一个周期会默认按PC+4取指,此时还未完成分支判定,这一条取到的指令是无效的,必须插入1个nop填补 - 分支实际发生跳转,跳转目标为循环起始标签
Loop
逐段排查冒险点后,最终插入nop的代码如下:
Loop: lw $2, 0($1) nop # 填补lw $2与下一条lw的load-use冒险 lw $3, 0($2) nop # 填补lw $3与下一条add的load-use冒险 add $4, $3, $2 sw $4, 4($2) # 全转发可直接拿到add输出的$4,无需插nop beq $4, $5, Loop # 寄存器堆前半周期写、后半周期读,可正常拿到$4,无需插nop nop # 填补ID阶段分支判定带来的1周期控制冒险
插入逻辑说明
- 指令1是
lw加载$2,下一条指令2lw需要直接使用$2计算访存地址,属于load-use场景,插入1个nop后,指令2的EX阶段正好可以通过转发拿到指令1的加载结果 - 指令2是
lw加载$3,下一条指令3add需要直接使用$3作为加法源操作数,同样属于load-use场景,插入1个nop后,指令3的EX阶段可通过转发拿到指令2的加载结果 - 指令3是R型加法指令,结果在EX阶段结束就可生成,后续指令4
sw需要在MEM阶段写入$4对应的值,可通过MEM阶段的转发通路直接拿到$4,不需要插nop - 指令5
beq需要在ID阶段读取$4做比较,此时指令3已经进入WB阶段,寄存器堆支持前半周期写回、后半周期读取,不需要额外插nop即可拿到正确的$4值 beq指令后插入1个nop,填补分支在ID阶段判定带来的1周期控制冒险,避免跳转到Loop前执行错误指令,nop执行不会修改任何寄存器或内存值,跳转后下一个周期将正常取指Loop入口的lw指令,循环可正确运行。
内容的提问来源于stack exchange,提问作者user19336710
相关产品推荐
相关产品推荐

