【轉】ARM獲得PC指針爲何PC=PC+8[下](轉)
ARM7的三條流水線,PC=PC+8,很好理解,但是AMR9中,是五級流水線,爲何還是PC=PC+8,而不是
PC
=PC+(5-1)*4
=PC + 16,
呢?
下面就需要好好解釋一番了。
具體解釋之前,先貼上ARM7和ARM9的流水線的區別和聯繫:
圖表 26 ARM7三級流水線 vs ARM9五級流水線
圖表 27 ARM7三級流水線到ARM9五級流水線的映射
下面開始對爲何ARM9也是PC=PC+8進行解釋。
先列出ARM9的五級流水線的示例:
圖表 28 ARM9的五級流水線示例
然後我們以下面uboot中的start.S的最開始的彙編代碼爲例來進行解釋:
- 00000000 <_start>:
- 0: ea000014 b 58 <reset>
- 4: e59ff014 ldr pc, [pc, #20] ; 20 <_undefined_instruction>
- 8: e59ff014 ldr pc, [pc, #20] ; 24 <_software_interrupt>
- c: e59ff014 ldr pc, [pc, #20] ; 28 <_prefetch_abort>
- 10: e59ff014 ldr pc, [pc, #20] ; 2c <_data_abort>
- 14: e59ff014 ldr pc, [pc, #20] ; 30 <_not_used>
- 18: e59ff014 ldr pc, [pc, #20] ; 34 <_irq>
- 1c: e59ff014 ldr pc, [pc, #20] ; 38 <_fiq>
- 00000020 <_undefined_instruction>:
- 20: 00000120 .word 0x00000120
下面對每一個指令週期,CPU做了哪些事情,分別詳細進行闡述:
在看下面具體解釋之前,有一句話要牢記,那就是:
PC不是指向你正在運行的指令,而是
PC始終指向你要取的指令的地址。
認識清楚了這個前提,後面的舉例講解,就容易懂了。
指令週期Cycle1
(1)取指:
PC總是指向將要讀取的指令的地址(即我們常說的,指向下一條指令的地址),而當前PC=4,
所以去取物理地址爲4對對應的指令“ldr pc, [pc, #20]”,其對應二進制代碼爲e59ff014。
此處取指完之後,自動更新PC的值,即PC=PC+4(單個指令佔4字節,所以加4)=4+4=8
指令週期Cycle2
(1)譯指:翻譯指令e59ff014;
(2)同時再去取指:
PC總是指向將要讀取的指令的地址(即我們常說的,指向下一條指令的地址),而當前PC=8,
所以去物理地址爲8所對應的指令“ldr pc, [pc, #20]” 其對應二進制代碼爲e59ff014。
此處取指完之後,自動更新PC的值,即PC=PC+4=8+4=12=0xc
指令週期Cycle3
(1)執行(指令):執行“e59ff014”,即“ldr pc,[pc, #20]”所對錶達的含義,即
PC
= PC + 20
= 12 + 20
= 32
= 0x20
此處,只是計算出待會要賦值給PC的值是0x20,這個0x20還只是放在執行單元中內部的緩衝中。
(2)譯指:翻譯e59ff014。
(3)取指:
此步驟由於是和上面(1)中的執行同步做的,所以,未受到影響,繼續取指,而取指的那一時刻,PC爲上一Cycle
更新後的值,即PC=0xc,所以是去取物理地址爲0xc所對應的指令” ldr pc, [pc, #20]”,對應二進制爲e59ff014。
其實,分析到這裏,大家就可以看出:
在Cycle3的時候,PC的值,剛好已經在Cycle1和Cycle2,分別加了4,所以Cycle3的時候,PC=PC+8,而同樣道理
,對於任何一條指令的,都是在Cycle3,指令的Execute執行階段,如果用到PC的值,那麼PC那一時刻,就是
PC=PC+8。
所以,此處雖然是五級流水線,但是卻不是PC=PC+16,而是PC=PC+8。
進一步地,我們發現,其實PC=PC+N的N,是和指令的執行階段所處於流水線的深度有關,即此處指令的執行
Execute階段,是五級流水線中的第三個,而這個第三階段的Execute和指令的第一個階段的Fetch取指,相差的
值是 3 -1 =2,即兩個CPU的Cycle,而每個Cycle都會導致PC=+PC+4,所以,指令到了Execute階段,纔會發現
,此時PC已經變成PC=PC+8了。
回過頭來反觀ARM7的三級流水線,也是同樣的道理,指令的Execute執行階段,是處於指令的第三個階段,
同理,在指令計算數據的時候,如果用到PC,就會發現此時PC=PC+8。
同理,假如ARM9的五級流水線,把指令的Execute執行階段,設計在了第四個階段,那麼就是
PC=PC+(第4階段-1)*4個字節 = PC= PC+12了。
【總結】
ARM7的三級流水線,PC=PC+8,
ARM9的五級流水線,也是PC=PC+8,
根本的原因是,兩者的流水線設計中,指令的Execute執行階段,都是處於流水線的第三級,
所以使得PC=PC+8。
類似地,可以推導出:
假設,Execute階段處於流水線中的第E階段,每條指令是T個字節,那麼
PC
= PC + N*T
= PC + (E - 1) * T
此處ARM7和ARM9:
Execute階段都是第3階段-> E=3
每條指令是4個字節-> T=4
所以:
PC
=PC + N* T
=PC + (3 -1 ) * 4
= PC + 8
【關於直接改變PC的值,會導致流水線清空的解釋】
把PC的值直接賦值爲0x20。而PC值更改,直接導致流水線的清空,即導致下一個cycle中的,對應的流水線中的
其他幾個步驟,包括接下來的同一個Cycle中的取指的工作被取消。在PC跳轉到0x20的位置之後,流水線重新計算
,重新一步步地按照流水線的邏輯,去一點點執行。當然要保證當前指令的執行完成,即執行之後,
還有兩個cycle,分別做的Memory和Write,會繼續執行完成。