2016-05-03 160 views
1

我正在學習MIPS指令,這個問題讓我有些困惑,因爲MIPS文檔似乎在說一些與提供的答案不同的東西。這裏是問題和答案:跳轉和鏈接寄存器MIPS

什麼寄存器引用和/或改變在這個指令在位置0x5000

0x5000 : 0x0140F809 

答案:

操作碼= 0x00,R型,功能= 0×09(jalr),RS = 10($t2

跳躍$t2

提出0x5004解決在$ra

但是,從文檔中可以看出,在寄存器31($ra)中,它將PC + 4置位。因此,由於指令在地址0x5000處執行,PC應該是0x5004嗎?那麼JALR指令不應該將0x5004 + 4或0x5008放入PC而不是0x5004?

對我來說它是有道理的,它應該跳回到0x5004,因爲這在技術上是跳轉後的下一條指令,但文檔明確地說R [31] = PC + 4,所以它讓我困惑一點,將是x5008。謝謝!

回答

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,執行單元執行該指令在週期N-1(例如5000)中取出的指令,指令預取單元被提取的下一個指令(在5004)。它們與一個循環延遲重疊。在週期N + 1中,執行單元正在執行預取指令(在5004)並且預取單元預取下一個指令(在5008)。

這很有效,直到遇到控制指令的條件傳輸。

如果沒有延遲槽,處理器將不得不停止,並且執行與分支相同的週期預取的分支之後的指令將被浪費浪費。通過執行延遲插槽,通常可以使用一些有用的東西來填充插槽,所以不需要浪費預取。

但是,它確實使事情變得更加複雜。