// ARCHITECTURE · WHAT'S UNDERNEATH //
"Stack overflow" is a real place
You've hit "Maximum call stack size exceeded." You know recursion "uses memory" and that local variables live "on the stack." On the Motorola 68000 in your Amiga, the stack isn't a metaphor — it's an address held in a register, walking downward through RAM. Watch it move and three mysteries solve at once.
The stack is a register pointing at memory
The 68000 has eight address registers. A7 is special — it’s the stack pointer, and it holds an address. “The stack” is simply the memory just below it. Calling a subroutine pushes the return address there and jumps:
bsr draw_sprite ; push 4-byte return addr, jump
... ; A7 is now 4 lower
draw_sprite:
...
rts ; pop it back into PC, returnThe stack grows downward — toward lower addresses — which is exactly why “the stack” and “the heap” are always drawn growing toward each other.
Local variables are stack you borrowed
Where do a function’s locals live? The 68000 has one instruction to carve them off the stack — LINK — and one to give them back — UNLK:
func: link a6,#-8 ; reserve 8 bytes of locals
move.l d0,-4(a6) ; a local, addressed off the frame
...
unlk a6 ; hand the 8 bytes back
rts ; return addr is waiting just aboveThat’s what your debugger means by a “frame,” and why a stack trace can exist at all: every return address is sitting in a chain in memory, each frame pointing back at the one that called it. Here it is laid out in RAM:
high addr ┌─────────────────────┐
$40000 │ caller's frame │
├─────────────────────┤
│ return address │ push, by bsr
├─────────────────────┤
│ saved a6 │ ┐ the frame,
│ locals (8 bytes) │ ┘ by link
A7 ─────► └─────────────────────┘
low addr ...grows downward...So overflow is literal
Every level of recursion does the whole dance again: another return address, another link, another few bytes off A7. Nest factorial(n) deep enough and A7 marches straight past the memory the stack was given — on an Amiga, into someone else’s RAM and a Guru Meditation.
“Maximum call stack size exceeded” is just your runtime catching
A7before it walks off the edge. Recursion costs memory because each call is a physical push. Once you’ve watched the pointer move, the error message reads like a description of the hardware — because that’s all it ever was.