跳转和链接寄存器MIPS

时间:2016-05-03 02:56:45

标签: mips

我正在研究MIPS指令,这个问题让我感到困惑,因为MIPS文档似乎说的不同于提供的答案。这是问题和答案:

  

在位置dump处的指令中引用和/或更改了哪些寄存器?

0x5000
     

回答:

     
    

操作码= 0x5000 : 0x0140F809 ,R类型,功能= 0x09(0x00),Rs = 10(jalr

         

跳转到$t2

中的地址          

$t2放入0x5004

  

然而,从文档中可以看出,在寄存器31($ra)中,它将PC + 4放入。因此,由于指令在地址0x5000处执行,因此PC应该是0x5004对吗?所以$ra指令不应该将0x5004 + 4或0x5008放入PC而不是0x5004?

对我而言,它应该跳回到0x5004是有意义的,因为这在技术上是跳转后的下一条指令,但是文档明确地说R [31] = PC + 4所以它让我有点困惑,这会是x5008。谢谢!

1 个答案:

答案 0 :(得分:2)

你必须考虑的是分支延迟时隙

首先让我们处理它们关闭的情况。这是spimmars等模拟器的默认设置。事情很简单:

5000: jalr $10                      # (1) $31 will have 5004
5004: nop                           # (2) this executed upon return

这是大多数架构的工作方式。

但是,mips有[上述]分支延迟时隙。

如果[在模拟器中]或真实硬件启用了延迟,则在每次传输控制指令(例如,分支,跳转,jal,jalr)之后是延迟槽中的单个指令是无条件执行之前分支实际被采取[或]:

5000: jalr $10                      # (1) $31 will have 5008
5004: nop                           # (2) this executed _before_ branch taken
5008: nop                           # (3) this executed upon return

因此,有效执行顺序实际上是(2),(1),(3)。

在一般情况下,您有三个步骤:

5000: beqz $10,foobar               # (1) conditional branch to foobar
5004: nop                           # (2) executed _before_ branch taken
5008: nop                           # (3) executed _after_ if branch _not_ taken

有效执行顺序将再次为(2),(1)。然后,如果分支是,则执行foobar的第一条指令[如果分支是 ],或者5008(3)处的指令将被执行不采取。

好的,你可能会问为什么

在早期的MIPS芯片中,预取了指令。例如,循环N + 1的指令在循环N中被预取[并且可能是预解码的](一个循环延迟)。

因此,在周期N,指令 execution 单元正在执行在周期N-1中取出的指令(例如5000),指令预取单元正在取出下一个指令(在5004)。它们与一个周期延迟重叠。在周期N + 1中,执行单元正在执行预取指令(在5004),并且预取单元正在预取下一条指令(在5008)。

这很有效,直到遇到控制指令的条件转移。

如果没有延迟槽,处理器将不得不停止,并且在执行与分支相同的循环中预取的分支之后的指令将被浪费。使用延迟槽执行时,通常可以使用有用的东西填充插槽,因此不需要浪费预取。

但是,它确实使事情变得更复杂。