ZHCAEQ3 November 2024 F29H850TU , F29H859TU-Q1
傳統(tǒng)上,分支 (Branch)、調(diào)用 (Call) 和返回 (Return) 操作由于指令流水線的存在會導(dǎo)致開銷。在流水線的 Decode-2 階段,CPU 解析并確定需要執(zhí)行分支、調(diào)用或返回操作。此時,流水線已經(jīng)填充了后續(xù)指令,這些指令需要被清除,然后從不連續(xù)目標(biāo)位置重新抓取指令。清除指令會產(chǎn)生開銷。
C29 CPU 具有 9 級流水線,不連續(xù)性決策同樣發(fā)生在 Decode-2 (D2) 階段。因此,在流水線中,不連續(xù)性指令后續(xù)的三條指令(Fetch-1、Fetch-2 和 Decode-1 階段)已經(jīng)進入執(zhí)行階段。除了傳統(tǒng)的分支、調(diào)用和返回指令外,C29 ISA 還支持延遲 分支、調(diào)用和返回指令(在指令后添加后綴 D,如 CALLD、RETD)。使用延遲指令時,無論不連續(xù)性是否發(fā)生(如條件分支),其后的三條指令始終會被執(zhí)行。這三條指令稱為延遲時隙。C29 編譯器在使用延遲指令時,會將適當(dāng)?shù)闹噶畈迦胙舆t時隙中,從而將原本的三周期不連續(xù)開銷降低為零周期。
以下兩個示例說明了編譯器這種結(jié)構(gòu)的使用原理。
@CALLD funcA ; Call funcA
||LD.32 A4,@pointer1 ; Load A4 with pointer1 value from memory
LD.32 A5,@pointer2 ; Load A5 with pointer2 value from memory
||SUB.U16 A6,SP,#34 ; A6 points to value on stack offset -34
MV A7,#ArrayB ; Load A7 with address of ArrayB
||LD.32 D0,@variable1 ; Load D0 with Variable1 from memory
LD.32 D1,@variable2 ; Load D1 with Variable2 from memory
; Total Cycles = 4
funcA: ADD.U16 SP,SP,#24 ; Allocate local stack space
ST.64 *(SP-#24),XM2 ; Save XM2, XM4, XM6 registers on stack
ST.64 *(SP-#16),XM4
ST.64 *(SP-#8),XM6
... user code...
RETD *(SP-#32) ; packet 1:Return and restore RPC from stack
||MV M0,M3 ; Place return value in register M0
LD.64 XM6,*(SP-#8) ; packet 2:Restore XM6 from stack
LD.64 XM4,*(SP-#16) ; packet 3:Restore XM4 from stack
LD.64 XM2,*(SP-#24) ; packet 4:Restore XM2 from stack
||SUB.U16 SP,SP,#32 ; Deallocate local + return stack space
; Total Cycles = 4
以上示例是 C29 編譯器如何使用延遲時隙的模型。實際上,延遲時隙不僅僅用于函數(shù)實參傳遞、寄存器恢復(fù)和堆棧釋放,通常還包含用于實現(xiàn)用戶代碼的實際功能的指令。