簡體   English   中英

為什么ARM PC寄存器指向下一條要執行的指令之后的指令?

[英]Why does the ARM PC register point to the instruction after the next one to be executed?

根據ARM IC。

在ARM狀態下,PC的值是當前指令的地址加上8個字節。

在拇指狀態:

  • 對於 B、BL、CBNZ 和 CBZ 指令,PC 的值是當前指令的地址加上 4 個字節。
  • 對於所有其他使用標簽的指令,PC 的值是當前指令的地址加上 4 個字節,結果的 bit[1] 清零以使其字對齊。

簡單的說,PC寄存器的值指向下一條指令之后的指令。 這是我不明白的事情。 通常(特別是在 x86 上)程序計數器寄存器用於指向要執行的下一條指令的地址。

那么,其背后的前提是什么? 條件執行,也許?

這是一個令人討厭的遺留抽象泄漏。

最初的 ARM 設計有一個 3 級流水線(獲取-解碼-執行)。 為了簡化設計,他們選擇將 PC 讀取為指令提取地址線上的當前值,而不是 2 個周期前當前正在執行的指令的值。 由於大多數與 PC 相關的地址是在鏈接時計算的,因此讓匯編器/鏈接器補償該 2 條指令偏移比設計所有邏輯以“糾正”PC 寄存器更容易。

當然,這一切都堅定地放在“30 年前有意義的事情”這一堆上。 現在想象一下,在當今 15 多個階段、多問題、亂序管道中,如何在該寄存器中保持有意義的值,您可能會理解為什么現在很難找到一個認為將 PC 暴露為注冊是個好主意。

盡管如此,從好的方面來說,至少它不像延遲槽那么可怕。 相反,與您的假設相反,有條件地執行每條指令實際上只是圍繞該預取偏移量的另一種優化。 在圍繞條件代碼進行分支時(或者仍然像瘋子一樣執行管道中剩余的任何內容),您不必總是必須采取管道刷新延遲,您可以完全避免非常短的分支; 管道保持忙碌,當標志不匹配時,解碼的指令可以作為 NOP 執行* 再說一次,現在我們有了有效的分支預測器,它最終成為了一個障礙而不是一個幫助,但在 1985 年它很酷。

* “……地球上 NOP 最多的指令集。”

確實如此...

一個例子如下: C 程序:

int f,g,y;//global variables
int sum(int a, int b){
     return (a+b);
}
int main(void){
    f = 2;
    g = 3;
    y = sum(f, g);
    return y;
}

編譯為匯編:

    00008390 <sum>:
int sum(int a, int b) {
return (a + b);
}
    8390: e0800001 add r0, r0, r1
    8394: e12fff1e bx lr
    00008398 <main>:
int f, g, y; // global variables
int sum(int a, int b);
int main(void) {
    8398: e92d4008 push {r3, lr}
f = 2;
    839c: e3a00002 mov r0, #2
    83a0: e59f301c ldr r3, [pc, #28] ; 83c4 <main+0x2c> 
    83a4: e5830000 str r0, [r3]
g = 3;
    83a8: e3a01003 mov r1, #3
    83ac: e59f3014 ldr r3, [pc, #20] ; 83c8 <main+0x30>
    83b0: e5831000 str r1, [r3]
y = sum(f,g);
    83b4: ebfffff5 bl 8390 <sum>
    83b8: e59f300c ldr r3, [pc, #12] ; 83cc <main+0x34>
    83bc: e5830000 str r0, [r3]
return y;
}
83c0: e8bd8008 pop {r3, pc}
83c4: 00010570 .word 0x00010570
83c8: 00010574 .word 0x00010574
83cc: 00010578 .word 0x00010578

看上面LDR的PC值——這里用來加載變量f,g,y的地址到r3。

    83a0: e59f301c ldr r3, [pc, #28];83c4 main+0x2c
    PC=0x83c4-28=0x83a8-0x1C = 0x83a8

PC 的值就是當前執行指令的下一條指令。 由於ARM使用32位指令,但它使用字節地址,所以+ 8表示8字節,兩條指令的長度。

所以附上 ARM archi 的 5 階段流水線提取、解碼、執行、內存、寫回

ARM 的 5 級流水線

PC寄存器每個時鍾加4,所以當指令冒泡執行時——當前指令,PC寄存器已經2個時鍾過去了! 現在是+8。這實際上意味着:PC 指向“fetch”指令,當前指令表示“execute”指令,因此PC 表示下一個要執行的指令。

BTW:圖片來自 Harris 的 Digital Design and Computer Architecture ARM Edition

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM