ZHCAEQ3 November 2024 F29H850TU , F29H859TU-Q1
传统上,分支 (Branch)、调用 (Call) 和返回 (Return) 操作由于指令流水线的存在会导致开销。在流水线的 Decode-2 阶段,CPU 解析并确定需要执行分支、调用或返回操作。此时,流水线已经填充了后续指令,这些指令需要被清除,然后从不连续目标位置重新抓取指令。清除指令会产生开销。
C29 CPU 具有 9 级流水线,不连续性决策同样发生在 Decode-2 (D2) 阶段。因此,在流水线中,不连续性指令后续的三条指令(Fetch-1、Fetch-2 和 Decode-1 阶段)已经进入执行阶段。除了传统的分支、调用和返回指令外,C29 ISA 还支持延迟 分支、调用和返回指令(在指令后添加后缀 D,如 CALLD、RETD)。使用延迟指令时,无论不连续性是否发生(如条件分支),其后的三条指令始终会被执行。这三条指令称为延迟时隙。C29 编译器在使用延迟指令时,会将适当的指令插入延迟时隙中,从而将原本的三周期不连续开销降低为零周期。
以下两个示例说明了编译器这种结构的使用原理。
@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 = 4funcA: 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 编译器如何使用延迟时隙的模型。实际上,延迟时隙不仅仅用于函数实参传递、寄存器恢复和堆栈释放,通常还包含用于实现用户代码的实际功能的指令。