The Value of the Stack in Debugging

When a Z80 program crashes, the CPU registers often hold garbage data. The Stack, however, holds the historical sequence of return addresses created by every CALL instruction. Examining the stack is the primary method to determine how the program arrived at the crash point—the call chain.

The Principle: You read the values on the stack, and these values are the addresses of the instructions immediately following the last few CALL commands.

Reading the Stack After a Crash

Assuming a crash occurs and you enter a debugger or emulator environment:

  1. Check SP: Find the current value of the Stack Pointer (SP) register. This is the memory address where the top of the stack currently resides.
  2. Examine Memory: Look at the memory starting at the address stored in SP.

Stack Contents (LIFO):

Memory Address Content Meaning
SP Low Byte of Return Address 1 Last subroutine called
SP + 1 High Byte of Return Address 1
SP + 2 Low Byte of Return Address 2 Second-to-last subroutine
SP + 3 High Byte of Return Address 2

Locating the Bug: By reading the return addresses and cross-referencing them with your source code’s listing file, you can trace the entire path the CPU took before it failed.

The Register Snapshot

When writing complex programs, it is common to create a Register Snapshot routine that you can call before a potentially buggy section of code.

Routine Goal: Save the state of all CPU registers to a fixed, safe memory location.

Snapshot Routine:

SAVE_STATE:
    LD   HL, SNAPSHOT_RAM_ADDR ; Address where register state will be stored
    
    PUSH AF                    ; Save AF to stack
    POP  (HL)                  ; Move AF from stack to RAM (HL++)
    
    PUSH BC                    ; Save BC
    POP  (HL)                  ; Move BC from stack to RAM (HL++)
    
    ; ... (Repeat for DE and HL)
    
    RET

Usage: If the program crashes later, you can examine the memory starting at SNAPSHOT_RAM_ADDR to see the last known good state of all the registers, which is invaluable for identifying subtle errors.

Common Stack Errors

  1. Stack Overflow: When the stack pointer runs into (and overwrites) valuable program data or code (usually caused by too many nested `CALL′s or not enough reserved stack space).
  2. Stack Underflow: When a routine performs more POP′s than PUSH′s, corrupting the critical return addresses and causing a crash when `RET′ is executed.