Assembler Directives: Structuring Your Code

Assembler directives are commands that are read and acted upon by the assembler program, not the Z80 CPU. They organize code, reserve memory, and define data.

Directive Action Purpose
ORG NNNNH Sets the origin (starting address) where the following code should be placed in memory. Essential for defining where your program loads.
EQU symbol, value Equates a symbolic name to a numerical value. Defines constants like port addresses or screen dimensions (SCREEN_WIDTH EQU 32).
DB val1, val2, ... Define Byte: Reserves memory and places 8-bit data bytes (numbers or ASCII characters). Used to define text strings or data tables.
DW val1, val2, ... Define Word: Reserves memory and places 16-bit words (often addresses). Used for jump tables or storing address pointers.
DEFS N Define Space: Reserves N bytes of uninitialized memory. Used for buffers, variables, or the stack area.

Example: Data Definition

    ORG  8000H         ; Program starts at address 8000H

TEXT_START:
    DB   'Z80 ROCKS!', 0
    
BUFFER:
    DEFS 256           ; Reserve 256 bytes for a temporary buffer

Debugging and Testing Techniques

Since you are writing low-level code, effective debugging is critical.

1. The NOP Slide: The NOP (No Operation) instruction does nothing but take up one byte and one clock cycle. If your program is crashing or skipping a specific instruction, you can temporarily replace the suspect instruction with a sequence of NOPs to bypass it and test the program flow.

2. Breakpoints and Watchpoints: In an emulator or debugger, a breakpoint stops the CPU when execution reaches a specific address. A watchpoint stops the CPU when a specific memory address or register value changes.

3. Using the Beeper (Hardware Trace): In retro systems like the ZX Spectrum, a common debugging trick is to strategically place code to turn the machine’s internal beeper on and off. If you hear the tone during a crash, you know the code reached