类MIPS指令集无旁路五级流水线分支延迟槽执行问题咨询
Hey there, let's unpack this branch delay slot scenario for your 5-stage MIPS-like pipeline—since you're prepping for this, I'll break down the core mechanics clearly, especially focusing on the branch-not-taken case and your ADDI in the delay slot.
First, let's lock in the ground rules for your pipeline: it's a classic 5-stage (IF → ID → EX → MEM → WB) RISC design, no forwarding, no dynamic scheduling, and includes a branch delay slot. The non-negotiable hardware rule here is: the delay slot instruction ALWAYS executes—regardless of whether the branch is taken or not. That's the foundation of how this pipeline handles branch latency.
Let's use a concrete instruction sequence to walk through the flow, matching your mention of an ADDI in the delay slot:
; 假设分支指令位于地址0x100 BNEZ $t0, target ; 分支未选取($t0 == 0) ADDI $t1, $t1, 1 ; 分支延迟槽指令 LW $t2, 0($t3) ; 分支未选取时,下一条要执行的指令
流水线时序拆解
Here's a table to visualize how each instruction moves through pipeline cycles:
| 周期 | IF阶段指令 | ID阶段指令 | EX阶段指令 | MEM阶段指令 | WB阶段指令 |
|---|---|---|---|---|---|
| 1 | BNEZ (0x100) | — | — | — | — |
| 2 | ADDI (0x104) | BNEZ | — | — | — |
| 3 | LW (0x108) | ADDI | BNEZ | — | — |
| 4 | — | LW | ADDI | BNEZ | — |
| 5 | — | — | LW | ADDI | BNEZ |
| 6 | — | — | — | LW | ADDI |
| 7 | — | — | — | — | LW |
关键周期解释
- 周期1:取指阶段获取分支指令
BNEZ。 - 周期2:流水线推进,
BNEZ进入译码阶段(读取寄存器$t0),同时取指阶段自动获取下一条指令——也就是延迟槽里的ADDI。此时我们还不知道分支是否会被选取(分支判断要到执行阶段才完成)。 - 周期3:
BNEZ进入执行阶段,计算得出分支未选取(因为$t0等于0)。由于分支不跳转,取指阶段会获取延迟槽之后的指令LW。同时ADDI进入译码阶段,继续推进——记住,延迟槽指令已经进入流水线,必须完整执行完毕。 - 周期4-7:所有指令走完各自的流水线阶段。
BNEZ会经过访存和写回,但因为分支未选取,这两个阶段不会修改任何寄存器(仅确认PC更新到0x108)。ADDI完成全部阶段,在写回阶段更新$t1的值,LW则紧随其后作为顺序指令执行。
针对你场景的核心要点
- 无旁路/无动态调度的影响:如果延迟槽的
ADDI和之前的指令存在数据冒险,你需要用NOP或者指令重排来处理,但如果是无冒险的情况,就会像上面的时序一样顺畅执行。 - 延迟槽的存在意义:在五级流水线中,分支决策要到执行阶段才能确定,此时取指阶段已经获取了下一条指令。硬件不选择 stall 浪费周期,而是将这条已获取的指令设为延迟槽,强制执行——以此隐藏分支决策的延迟。
- 分支未选取vs选取的差异:如果分支被选取,周期3的取指阶段会获取
target地址的指令,但延迟槽的ADDI依然会完整执行,这一点不会改变。
如果你的官方流水线图和这个时序匹配(ADDI与BNEZ重叠流水线阶段并走完所有5个阶段),那你的理解完全正确——延迟槽里的ADDI确实会执行!
内容的提问来源于stack exchange,提问作者J. Doe




