; Build/run from examples/: ; ../utils/mcpu-as -o frame-pointer.o frame-pointer.s ; ../utils/mcpu-ld --stack-size=512 -o frame-pointer frame-pointer.o ; ../utils/mcpu-run --int-reg=r64@0x00008 frame-pointer ; ; Expected output: 42 ; ; LibCPU optional frame-pointer and dynamic STACK allocation example. ; ; demo(5) builds a fixed frame, creates a 24-byte dynamic object below it, ; accesses a fixed local through FP while SP is moving, and returns 42 in ; the canonical r64 return register. .text _start_life: LDI r64@0x00000, 5 ADJSP -16 ; 16-byte ABI argument block STSP 0, r64@0x00000 CALL demo ADJSP 16 MOV r64@0x00008, r64@0x7fff8 HALT demo: PUSHFP SETFP ADJSP -16 ; First explicit argument. With FP in use the layout is: ; FP+0 saved caller FP ; FP+8 return PC ; FP+16 first explicit argument LDFP r64@0x00100, 16 ; Fixed local at FP-8. STFP -8, r64@0x00100 LEAFP r64@0x00108, -8 ; Save the current stack top as a dynamic-scope mark. LEASP r64@0x00110, 0 ; Dynamically reserve 24 bytes: new_SP = old_SP - 24. LDI r64@0x00118, 24 PSUB r64@0x00120, r64@0x00110, r64@0x00118 SETSP r64@0x00120 ; Put 37 in the dynamic object at current SP. LDI r64@0x00128, 37 LEASP r64@0x00130, 0 STOREP r64@0x00130, r64@0x00128 ; FP-relative access is stable although SP moved dynamically. LDFP r64@0x00138, -8 LOADP r64@0x00140, r64@0x00130 IADD r64@0x7fff8, r64@0x00138, r64@0x00140 ; Restore the nested dynamic scope explicitly. SETSP r64@0x00110 ; Destroy the complete frame below FP, restore caller FP and return. RESTSP POPFP RET