MIPS、流水线和分支延迟槽示例
Example with MIPS, Pipelining and Branch Delay Slot
我正在准备考试,有这样的例子。以下代码:
1: SLL , , 2
2: LW , 1000()
3: BEQL , [=10=], END
4: ADDI , , 1
5: MULT ,
6: MFLO
END:
7: J QUIT
...
QUIT:
100: NOP
在RISC处理器上执行(具有准MIPS指令集)
- 五级流水线
- 无绕过
- 无动态调度
- 分支延迟槽
- 另外我们知道,分支不会被采用
我的任务是了解分支延迟槽在这种情况下的工作原理并构建正确的流水线图。
我有一个官方的解决方案,它给出了下图,没有解释:
1: SLL , , 2 IDEMW
2: LW , 1000() I---DEMW
3: BEQL , [=11=], END I---DEMW
4: ADDI , , 1 IDx
5: MULT , IDEMW
6: MFLO I---DEMW
据我了解,ADDI在Branch Delay Slot中执行并被停止
处理器理解后,那个分支没有被采用,是什么导致我们得到错误的结果。我的问题是
- 我说得对吗?
- 当是时,为什么ADDI是在Branch Delay Slot而不是Jump中执行的?
CPU 一直在按顺序读取指令,即在执行期间(已经获取、解码,现在正在处理剩余的阶段,我不知道你的确切阶段,所以这只是一般描述) beql
它将让管道的另一部分空闲以获取下一条指令,但分支尚未完成,因此 PC
仍指向分支后的下一条指令 -> 那就是 "branch delay slot".
在经典 MIPS 上,这条下一条指令被获取、解码和执行,同时分支可能会或可能不会将 PC 修改为分支目标,因此每次都会执行分支延迟槽指令。仅当未发生分支时才执行它之后的下一条指令,即 PC
在 "branch delay slot" 位置之后顺序继续。如果分支确实修改了 PC
,fetch+decode 将注意并解码来自新目标的下一条指令,因此在经典 MIPS 上,分支延迟槽只有 1 条指令 "big"(我没有想法如果更复杂的 MIPS CPUs 可以有更多的阶段和更多的可用延迟槽,技术上有 5 阶段流水线甚至 5 条指令延迟听起来硬件可能,但它可能很难实际使用并且听起来它会创建问题多于帮助。
BEQL
是更复杂的指令,如果分支条件失败,则在执行中途终止延迟槽指令。
有关 BEQL
的详细说明,请参阅 http://math-atlas.sourceforge.net/devel/assembly/mips-iv.pdf 第 45 页。
所以"NullifyCurrentInstruction()"大概就是图中的那个"x"。图中剩下的东西,我只是猜测,因为我没有研究你的 5 阶段细节,但是在获取和解码后的第二个 LW
(?) 发现它取决于 </code>,所以它等待前一条指令的依赖阶段 <code>W
阶段。等等... ADDI
不依赖于任何东西,所以它几乎与 BEQL
并行执行,并在最后被杀死。
但我不明白为什么每次 "I" 阶段被释放时都没有 "I" 阶段,看起来 "I" 等待什么,最后你喜欢最多同时执行 2 条指令。
无论如何,如果不研究你问题中使用的 CPU 的技术细节,这是非常难以理解的,我不想研究它,我什至不确定 CPU 你有,从哪里得到它的技术文档。
编辑:我也会在这里尝试提取 pdf 的相关部分,使这个答案不是 "just link",但复制 pdf 可能很棘手...
BEQL
MIPS IV 指令文档CPU:
Description:
if (rs
= rt
) then branch_likely
An 18-bit signed offset (the 16-bit offset field shifted left 2 bits) is added to the address of the instruction following the branch (not the branch itself), in the branch delay slot, to form a PC-relative effective target address.
If the contents of GPR rs
and GPR rt
are equal, branch to the target address after the instruction in the delay slot is executed. If the branch is not taken, the instruction in the delay slot is not executed.
Operation:
I:
tgt_offset ← sign_extend(offset || 02)
condition ← (GPR[rs] = GPR[rt])
I+1:
if condition then
PC ← PC + tgt_offset
else
NullifyCurrentInstruction()
endif
我正在准备考试,有这样的例子。以下代码:
1: SLL , , 2
2: LW , 1000()
3: BEQL , [=10=], END
4: ADDI , , 1
5: MULT ,
6: MFLO
END:
7: J QUIT
...
QUIT:
100: NOP
在RISC处理器上执行(具有准MIPS指令集)
- 五级流水线
- 无绕过
- 无动态调度
- 分支延迟槽
- 另外我们知道,分支不会被采用
我的任务是了解分支延迟槽在这种情况下的工作原理并构建正确的流水线图。
我有一个官方的解决方案,它给出了下图,没有解释:
1: SLL , , 2 IDEMW
2: LW , 1000() I---DEMW
3: BEQL , [=11=], END I---DEMW
4: ADDI , , 1 IDx
5: MULT , IDEMW
6: MFLO I---DEMW
据我了解,ADDI在Branch Delay Slot中执行并被停止 处理器理解后,那个分支没有被采用,是什么导致我们得到错误的结果。我的问题是
- 我说得对吗?
- 当是时,为什么ADDI是在Branch Delay Slot而不是Jump中执行的?
CPU 一直在按顺序读取指令,即在执行期间(已经获取、解码,现在正在处理剩余的阶段,我不知道你的确切阶段,所以这只是一般描述) beql
它将让管道的另一部分空闲以获取下一条指令,但分支尚未完成,因此 PC
仍指向分支后的下一条指令 -> 那就是 "branch delay slot".
在经典 MIPS 上,这条下一条指令被获取、解码和执行,同时分支可能会或可能不会将 PC 修改为分支目标,因此每次都会执行分支延迟槽指令。仅当未发生分支时才执行它之后的下一条指令,即 PC
在 "branch delay slot" 位置之后顺序继续。如果分支确实修改了 PC
,fetch+decode 将注意并解码来自新目标的下一条指令,因此在经典 MIPS 上,分支延迟槽只有 1 条指令 "big"(我没有想法如果更复杂的 MIPS CPUs 可以有更多的阶段和更多的可用延迟槽,技术上有 5 阶段流水线甚至 5 条指令延迟听起来硬件可能,但它可能很难实际使用并且听起来它会创建问题多于帮助。
BEQL
是更复杂的指令,如果分支条件失败,则在执行中途终止延迟槽指令。
有关 BEQL
的详细说明,请参阅 http://math-atlas.sourceforge.net/devel/assembly/mips-iv.pdf 第 45 页。
所以"NullifyCurrentInstruction()"大概就是图中的那个"x"。图中剩下的东西,我只是猜测,因为我没有研究你的 5 阶段细节,但是在获取和解码后的第二个 LW
(?) 发现它取决于 </code>,所以它等待前一条指令的依赖阶段 <code>W
阶段。等等... ADDI
不依赖于任何东西,所以它几乎与 BEQL
并行执行,并在最后被杀死。
但我不明白为什么每次 "I" 阶段被释放时都没有 "I" 阶段,看起来 "I" 等待什么,最后你喜欢最多同时执行 2 条指令。
无论如何,如果不研究你问题中使用的 CPU 的技术细节,这是非常难以理解的,我不想研究它,我什至不确定 CPU 你有,从哪里得到它的技术文档。
编辑:我也会在这里尝试提取 pdf 的相关部分,使这个答案不是 "just link",但复制 pdf 可能很棘手...
BEQL
MIPS IV 指令文档CPU:
Description: if (
rs
=rt
) then branch_likely
An 18-bit signed offset (the 16-bit offset field shifted left 2 bits) is added to the address of the instruction following the branch (not the branch itself), in the branch delay slot, to form a PC-relative effective target address.
If the contents of GPRrs
and GPRrt
are equal, branch to the target address after the instruction in the delay slot is executed. If the branch is not taken, the instruction in the delay slot is not executed.Operation:
I:
tgt_offset ← sign_extend(offset || 02)
condition ← (GPR[rs] = GPR[rt])
I+1:
if condition then
PC ← PC + tgt_offset
else
NullifyCurrentInstruction()
endif