Z80 CPU REFERENCE

Zilog Z80 Microprocessor Emulator

Phone: 555-4355

Introduction

Welcome to the SLP-Z80 emulator, a faithful implementation of the legendary Zilog Z80 microprocessor for the Emulator.ca modem network. The Z80 stands as one of the most influential processors in computing history, and this manual will guide you through its architecture, instruction set, and the unique features of this implementation.

The Z80 Legacy

In 1976, Federico Faggin founded Zilog and released the Z80---a processor that would shape the personal computing revolution. The Z80 was software-compatible with the Intel 8080 but added numerous enhancements: additional registers, more powerful instructions, a simpler clock design, and a built-in DRAM refresh circuit.

The Z80 powered an extraordinary range of systems:

The Z80's elegant design and powerful instruction set made it the processor of choice for an entire generation of programmers. When you program the Z80, you're connecting with a heritage that spans gaming, business computing, scientific applications, and industrial control.

This Z80 emulator implements the complete documented instruction set plus many undocumented instructions. It provides 64KB of memory, configurable ROM protection, UART I/O, and timer peripherals with interrupt support.

About This Implementation

The SLP-Z80 provides:

Whether you're learning assembly language, exploring vintage computing, or developing embedded software, this emulator provides an authentic Z80 experience through your modem connection.

Getting Connected

To access the SLP-Z80 system, configure your modem and dial:

ATDT555-4355

Upon successful connection, you'll see the system banner:

CODE_FENCE_0

This simple demonstration loads a pre-compiled "Hello World" program, executes it on the Z80 emulator, and displays the output via the emulated UART. The program then halts, demonstrating basic BIOS functionality.

Terminal Settings

Configure your terminal software as follows:

Modem Signals

The Z80 emulator participates in RS-232 handshaking:

Signal Direction Function
DTR DTE->DCE Asserted when emulator ready; dropped to disconnect
RTS DTE->DCE Asserted when emulator can accept data
CTS DCE->DTE When low, output is paused (flow control)
DCD DCE->DTE Carrier detect - connection active

This service runs a pre-compiled hello world program to demonstrate Z80 emulation. The program executes automatically upon connection and the line disconnects after completion. For interactive Z80 programming, see the Z80 Snake games (555-7635 and 555-9807).

Architecture Overview

The Z80 is an 8-bit microprocessor with a 16-bit address bus, providing access to 64 kilobytes of memory. It features a rich register set, powerful addressing modes, and a comprehensive instruction set that made it the most popular 8-bit processor of its era.

Memory Map

    +------------------+ 0xFFFF (65535)
    |                  |
    |       RAM        |
    |    (56 KB)       |
    |                  |
    +------------------+ 0x2000 (8192)
    |                  |
    |       ROM        |
    |    (8 KB)        |
    |                  |
    +------------------+ 0x0000 (0)

The default configuration provides:

ROM protection prevents accidental overwrites of system code. The ROM size is configurable.

I/O Space

The Z80 has a separate 256-port I/O address space. This implementation provides:

Port Function
0x00 UART Data (read: receive, write: transmit)
0x01 UART Status (bit 0: RX ready, bit 1: TX ready)
0x10 Timer Control
0x11 Timer Reload Low
0x12 Timer Reload High

Block Diagram

                          +---------------------------+
                          |          Z80 CPU          |
                          |                           |
    +----------+          |  +-----+      +-------+   |
    |          |=========]|  | ALU |=====]| Regs  |   |
    |  Memory  |  16-bit  |  +-----+      +-------+   |
    |  64 KB   |  Address |                           |
    |          |=========]|  +-----+      +-------+   |
    +----------+   8-bit  |  | IR  |      | Flags |   |
                   Data   |  +-----+      +-------+   |
                          |                           |
    +----------+          |  +-----+      +-------+   |
    |   I/O    |=========]|  | PC  |      |  SP   |   |
    | Devices  |  8-bit   |  +-----+      +-------+   |
    +----------+   I/O    |                           |
                          +---------------------------+

The Register Set

The Z80's register set is one of its most distinctive features. In addition to the basic 8080-compatible registers, it provides alternate registers, index registers, and specialized registers for interrupt handling.

Main Registers

The primary working registers are organised as 8-bit registers that can be paired into 16-bit register pairs:

    8-bit       16-bit pair
    +---+---+   
    | A | F |   AF - Accumulator and Flags
    +---+---+
    | B | C |   BC - General purpose / Counter
    +---+---+
    | D | E |   DE - General purpose / Destination
    +---+---+
    | H | L |   HL - General purpose / Memory pointer
    +---+---+

A (Accumulator): The primary register for arithmetic and logical operations. Most ALU operations use A as one operand and store the result back in A.

F (Flags): Contains the condition flags that reflect the results of operations. See the Flag Register section for details.

BC, DE, HL: General-purpose register pairs. HL is particularly important as it serves as the primary memory pointer---many instructions use (HL) to address memory.

Alternate Registers

The Z80 provides a complete set of alternate registers:

    Main Set        Alternate Set
    +---+---+       +---+---+
    | A | F |       | A'| F'|
    +---+---+       +---+---+
    | B | C |       | B'| C'|
    +---+---+       +---+---+
    | D | E |       | D'| E'|
    +---+---+       +---+---+
    | H | L |       | H'| L'|
    +---+---+       +---+---+

The EX AF,AF' instruction exchanges AF with AF'. The EXX instruction exchanges BC, DE, and HL with their alternates simultaneously. This allows fast context switching---an interrupt handler can preserve the main registers with a single instruction.

Index Registers

    +-------+
    |   IX  |   Index Register X (16-bit)
    +-------+
    |   IY  |   Index Register Y (16-bit)
    +-------+

IX and IY provide indexed addressing: you can access memory at IX+d or IY+d where d is a signed 8-bit displacement (-128 to +127). This is invaluable for accessing data structures, stack frames, and arrays.

Special Registers

    +-------+
    |   SP  |   Stack Pointer (16-bit)
    +-------+
    |   PC  |   Program Counter (16-bit)
    +-------+
    +---+
    | I |       Interrupt Vector Register (8-bit)
    +---+
    | R |       Memory Refresh Register (8-bit)
    +---+

SP (Stack Pointer): Points to the top of the stack. The stack grows downward (toward lower addresses). PUSH decrements SP by 2 then writes; POP reads then increments SP by 2.

PC (Program Counter): Contains the address of the next instruction to execute. Modified by jumps, calls, and returns.

I (Interrupt Vector): In Interrupt Mode 2, I provides the high byte of the interrupt vector table address. Combined with a byte from the interrupting device, it forms the address of the interrupt service routine.

R (Refresh Register): Automatically incremented after each instruction fetch. Originally designed to refresh dynamic RAM, it's useful for pseudo-random number generation.

Use HL for memory pointers (many instructions implicitly use it). Use BC as a counter in loops. Use DE as a secondary pointer or for block operations. Reserve IX and IY for complex data structures where indexed addressing is beneficial.

The Flag Register

The F register contains six status flags that reflect the results of operations. Two additional bits (X and Y) are undocumented but are set by the hardware.

    Bit:  7   6   5   4   3   2   1   0
        +---+---+---+---+---+---+---+---+
        | S | Z | Y | H | X |P/V| N | C |
        +---+---+---+---+---+---+---+---+

Flag Descriptions

Flag Bit Name Description
S 7 Sign Set if result is negative (bit 7 = 1)
Z 6 Zero Set if result is zero
Y 5 (Undocumented) Copy of bit 5 of result
H 4 Half Carry Carry from bit 3 to bit 4 (BCD operations)
X 3 (Undocumented) Copy of bit 3 of result
P/V 2 Parity/Overflow Parity (logical ops) or Overflow (arithmetic)
N 1 Add/Subtract Set if last operation was subtraction
C 0 Carry Carry out of bit 7 (or borrow)

Sign Flag (S)

The Sign flag reflects bit 7 of the result. In signed arithmetic, this indicates whether the result is negative:

    LD A, 50        ; A = 50, S = 0 (positive)
    ADD A, 100      ; A = 150, S = 1 (negative in signed)

For signed bytes: 0-127 are positive, 128-255 represent -128 to -1.

Zero Flag (Z)

Set when the result of an operation is zero:

    LD A, 5
    DEC A           ; A = 4, Z = 0
    DEC A           ; A = 3, Z = 0
    ...
    DEC A           ; A = 0, Z = 1

Essential for loops and comparisons:

    CP 10           ; Compare A with 10
    JR Z, equal     ; Jump if A equals 10

Half Carry Flag (H)

Set when there's a carry from bit 3 to bit 4. This is essential for BCD (Binary-Coded Decimal) arithmetic:

    LD A, 0x09      ; A = 9 (BCD)
    ADD A, 0x01     ; A = 0x0A, H = 0
                    ; (no carry from bit 3)
    
    LD A, 0x0F      ; A = 15
    ADD A, 0x01     ; A = 0x10, H = 1
                    ; (carry from bit 3 to bit 4)

The DAA instruction uses H to correct BCD results.

Parity/Overflow Flag (P/V)

This flag serves two purposes depending on the operation:

Parity (logical operations): Set if the result has an even number of 1 bits:

    LD A, 0b00001111    ; 4 ones = even parity
    OR A                ; P = 1
    
    LD A, 0b00000111    ; 3 ones = odd parity
    OR A                ; P = 0

Overflow (arithmetic operations): Set if signed overflow occurred:

    LD A, 127           ; Maximum positive signed byte
    ADD A, 1            ; Result = 128 = -128 signed
                        ; V = 1 (overflow!)

Add/Subtract Flag (N)

Set after subtraction operations, cleared after additions. Used by DAA to determine the correct BCD adjustment:

    ADD A, B            ; N = 0
    SUB C               ; N = 1
    DAA                 ; Uses N to adjust correctly

Carry Flag (C)

Set when an operation produces a carry out of bit 7 (addition) or a borrow (subtraction):

    LD A, 200
    ADD A, 100          ; 300 > 255, C = 1, A = 44
    
    LD A, 50
    SUB 100             ; 50 - 100 = -50, C = 1 (borrow)

Used for multi-byte arithmetic with ADC and SBC:

    ; Add 16-bit numbers: HL = HL + DE
    ADD HL, DE          ; Adds with carry into H

Undocumented Flags (X and Y)

Bits 3 and 5 of the F register are copies of bits 3 and 5 of the result (or operand, depending on the instruction). While not officially documented, this emulator faithfully replicates this behavior for compatibility with software that relies on it.

Addressing Modes

The Z80 supports multiple addressing modes, providing flexibility in how instructions access data.

Immediate

The operand is contained in the instruction itself:

    LD A, 42            ; Load 42 into A
    LD BC, 0x1234       ; Load 0x1234 into BC
    ADD A, 5            ; Add 5 to A

Register

The operand is in a register:

    LD A, B             ; Copy B to A
    ADD A, C            ; Add C to A
    INC D               ; Increment D

Register Indirect

The register contains an address; the operand is in memory at that address:

    LD A, (HL)          ; Load byte at address HL into A
    LD (BC), A          ; Store A at address BC
    INC (HL)            ; Increment byte at address HL

Extended (Direct)

The instruction contains a 16-bit address:

    LD A, (0x4000)      ; Load byte at 0x4000 into A
    LD (0x5000), A      ; Store A at 0x5000
    LD HL, (0x6000)     ; Load 16-bit value at 0x6000 into HL
    JP 0x8000           ; Jump to 0x8000

Indexed

The address is formed by adding a signed displacement to IX or IY:

    LD A, (IX+5)        ; Load byte at IX+5 into A
    LD (IY-3), B        ; Store B at IY-3
    INC (IX+0)          ; Increment byte at address IX

The displacement ranges from -128 to +127, making indexed addressing ideal for accessing structure fields and array elements.

Relative

Used only by JR (Jump Relative) and DJNZ. The target address is PC plus a signed 8-bit displacement:

    JR loop             ; Jump relative to 'loop'
    DJNZ back           ; Decrement B, jump if not zero

Relative jumps save memory (2 bytes vs 3) and produce position-independent code.

Bit Addressing

BIT, SET, and RES instructions address individual bits within a byte:

    BIT 3, A            ; Test bit 3 of A
    SET 7, (HL)         ; Set bit 7 of byte at (HL)
    RES 0, B            ; Clear bit 0 of B

Implicit

Some instructions have implicit operands:

    DAA                 ; Decimal adjust A (A is implicit)
    CPL                 ; Complement A
    RLA                 ; Rotate A left through carry

Instruction Set Reference

The Z80 instruction set comprises over 700 opcodes (including duplicates and undocumented variations). This section organises them by function.

Data Transfer Instructions

8-Bit Loads

Instruction Operation Flags
LD r, r' r ← r' -
LD r, n r ← n -
LD r, (HL) r ← (HL) -
LD (HL), r (HL) ← r -
LD (HL), n (HL) ← n -
LD A, (BC) A ← (BC) -
LD A, (DE) A ← (DE) -
LD A, (nn) A ← (nn) -
LD (BC), A (BC) ← A -
LD (DE), A (DE) ← A -
LD (nn), A (nn) ← A -
LD A, I A ← I S Z - H:0 - P:IFF2 N:0 -
LD A, R A ← R S Z - H:0 - P:IFF2 N:0 -
LD I, A I ← A -
LD R, A R ← A -

16-Bit Loads

Instruction Operation Flags
LD dd, nn dd ← nn -
LD HL, (nn) HL ← (nn) -
LD dd, (nn) dd ← (nn) -
LD (nn), HL (nn) ← HL -
LD (nn), dd (nn) ← dd -
LD SP, HL SP ← HL -
LD SP, IX SP ← IX -
LD SP, IY SP ← IY -

Stack Operations

Instruction Operation Flags
PUSH qq (SP-1) ← qqH, (SP-2) ← qqL, SP ← SP-2 -
POP qq qqL ← (SP), qqH ← (SP+1), SP ← SP+2 AF: all flags

Exchange Instructions

Instruction Operation Flags
EX DE, HL DE ↔ HL -
EX AF, AF' AF ↔ AF' All flags from AF'
EXX BC↔BC', DE↔DE', HL↔HL' -
EX (SP), HL (SP) ↔ L, (SP+1) ↔ H -
EX (SP), IX (SP) ↔ IXL, (SP+1) ↔ IXH -
EX (SP), IY (SP) ↔ IYL, (SP+1) ↔ IYH -

Arithmetic Instructions

8-Bit Addition

Instruction Operation Flags
ADD A, r A ← A + r S Z - H - V N:0 C
ADD A, n A ← A + n S Z - H - V N:0 C
ADD A, (HL) A ← A + (HL) S Z - H - V N:0 C
ADD A, (IX+d) A ← A + (IX+d) S Z - H - V N:0 C
ADD A, (IY+d) A ← A + (IY+d) S Z - H - V N:0 C
ADC A, s A ← A + s + C S Z - H - V N:0 C

8-Bit Subtraction

Instruction Operation Flags
SUB r A ← A - r S Z - H - V N:1 C
SUB n A ← A - n S Z - H - V N:1 C
SUB (HL) A ← A - (HL) S Z - H - V N:1 C
SBC A, s A ← A - s - C S Z - H - V N:1 C
CP r A - r (flags only) S Z - H - V N:1 C
CP n A - n (flags only) S Z - H - V N:1 C

Increment and Decrement

Instruction Operation Flags
INC r r ← r + 1 S Z - H - V N:0 -
INC (HL) (HL) ← (HL) + 1 S Z - H - V N:0 -
DEC r r ← r - 1 S Z - H - V N:1 -
DEC (HL) (HL) ← (HL) - 1 S Z - H - V N:1 -

16-Bit Arithmetic

Instruction Operation Flags
ADD HL, ss HL ← HL + ss - - - H - - N:0 C
ADC HL, ss HL ← HL + ss + C S Z - H - V N:0 C
SBC HL, ss HL ← HL - ss - C S Z - H - V N:1 C
ADD IX, pp IX ← IX + pp - - - H - - N:0 C
ADD IY, rr IY ← IY + rr - - - H - - N:0 C
INC ss ss ← ss + 1 -
DEC ss ss ← ss - 1 -

Special Arithmetic

Instruction Operation Flags
DAA Decimal adjust A S Z - H - P N C
CPL A ← NOT A - - - H:1 - - N:1 -
NEG A ← 0 - A S Z - H - V N:1 C

Logical Instructions

Instruction Operation Flags
AND r A ← A AND r S Z - H:1 - P N:0 C:0
AND n A ← A AND n S Z - H:1 - P N:0 C:0
AND (HL) A ← A AND (HL) S Z - H:1 - P N:0 C:0
OR r A ← A OR r S Z - H:0 - P N:0 C:0
OR n A ← A OR n S Z - H:0 - P N:0 C:0
OR (HL) A ← A OR (HL) S Z - H:0 - P N:0 C:0
XOR r A ← A XOR r S Z - H:0 - P N:0 C:0
XOR n A ← A XOR n S Z - H:0 - P N:0 C:0
XOR (HL) A ← A XOR (HL) S Z - H:0 - P N:0 C:0

Bit Manipulation Instructions

Bit Test, Set, and Reset

Instruction Operation Flags
BIT b, r Test bit b of r - Z - H:1 - P:~Z N:0 -
BIT b, (HL) Test bit b of (HL) - Z - H:1 - P:~Z N:0 -
SET b, r Set bit b of r -
SET b, (HL) Set bit b of (HL) -
RES b, r Reset bit b of r -
RES b, (HL) Reset bit b of (HL) -

Where b = 0-7 specifies the bit position.

Rotate and Shift Instructions

Rotate Accumulator

Instruction Operation Flags
RLCA Rotate A left circular - - - H:0 - - N:0 C
RLA Rotate A left through carry - - - H:0 - - N:0 C
RRCA Rotate A right circular - - - H:0 - - N:0 C
RRA Rotate A right through carry - - - H:0 - - N:0 C

Rotate Register/Memory

Instruction Operation Flags
RLC r Rotate left circular S Z - H:0 - P N:0 C
RL r Rotate left through carry S Z - H:0 - P N:0 C
RRC r Rotate right circular S Z - H:0 - P N:0 C
RR r Rotate right through carry S Z - H:0 - P N:0 C

Shift Instructions

Instruction Operation Flags
SLA r Shift left arithmetic S Z - H:0 - P N:0 C
SRA r Shift right arithmetic S Z - H:0 - P N:0 C
SRL r Shift right logical S Z - H:0 - P N:0 C
    Rotate and Shift Operations:
    
    RLCA/RLC    [C] ← [7 ← 0] ←+
                       +----------+
    
    RLA/RL      [C] ← [7 ← 0] ← [C]
    
    RRCA/RRC    +-> [7 -> 0] -> [C]
                +----------+
    
    RRA/RR      [C] -> [7 -> 0] -> [C]
    
    SLA         [C] ← [7 ← 0] ← 0
    
    SRA         [7] -> [7 -> 0] -> [C]
                (sign preserved)
    
    SRL         0 -> [7 -> 0] -> [C]

Rotate Digit Instructions

Instruction Operation Flags
RLD Rotate left digit (A and (HL)) S Z - H:0 - P N:0 -
RRD Rotate right digit (A and (HL)) S Z - H:0 - P N:0 -

These unusual instructions rotate the lower nibble of A with both nibbles of (HL), useful for BCD manipulation.

Branch Instructions

Unconditional Jumps

Instruction Operation Bytes Cycles
JP nn PC ← nn 3 10
JP (HL) PC ← HL 1 4
JP (IX) PC ← IX 2 8
JP (IY) PC ← IY 2 8
JR e PC ← PC + e 2 12

Conditional Jumps

Instruction Condition Branch if
JP NZ, nn Z = 0 Not zero
JP Z, nn Z = 1 Zero
JP NC, nn C = 0 No carry
JP C, nn C = 1 Carry
JP PO, nn P/V = 0 Parity odd / No overflow
JP PE, nn P/V = 1 Parity even / Overflow
JP P, nn S = 0 Positive
JP M, nn S = 1 Minus (negative)

The same conditions apply to JR, except JR only supports NZ, Z, NC, and C.

Subroutine Calls and Returns

Instruction Operation
CALL nn (SP-1) ← PCH, (SP-2) ← PCL, SP ← SP-2, PC ← nn
CALL cc, nn If condition cc true, CALL nn
RET PCL ← (SP), PCH ← (SP+1), SP ← SP+2
RET cc If condition cc true, RET
RETI Return from interrupt
RETN Return from NMI

Special Branches

Instruction Operation
DJNZ e B ← B - 1; if B != 0, PC ← PC + e
RST p CALL to address p (p = 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38)

Block Instructions

The Z80's block instructions are among its most powerful features, allowing memory-to-memory and I/O operations with automatic incrementing or decrementing and repeat capability.

Block Transfer

Instruction Operation
LDI (DE) ← (HL), DE++, HL++, BC--
LDIR LDI repeated until BC = 0
LDD (DE) ← (HL), DE--, HL--, BC--
LDDR LDD repeated until BC = 0

Block Compare

Instruction Operation
CPI A - (HL), HL++, BC--
CPIR CPI repeated until BC = 0 or A = (HL)
CPD A - (HL), HL--, BC--
CPDR CPD repeated until BC = 0 or A = (HL)

Block I/O

Instruction Operation
INI (HL) ← IN(C), HL++, B--
INIR INI repeated until B = 0
IND (HL) ← IN(C), HL--, B--
INDR IND repeated until B = 0
OUTI OUT(C) ← (HL), HL++, B--
OTIR OUTI repeated until B = 0
OUTD OUT(C) ← (HL), HL--, B--
OTDR OUTD repeated until B = 0

I/O Instructions

Instruction Operation Flags
IN A, (n) A ← port n -
IN r, (C) r ← port C S Z - H:0 - P N:0 -
OUT (n), A port n ← A -
OUT (C), r port C ← r -

Control Instructions

Instruction Operation
NOP No operation
HALT Halt until interrupt
DI Disable interrupts (IFF1=IFF2=0)
EI Enable interrupts (IFF1=IFF2=1)
IM 0 Set interrupt mode 0
IM 1 Set interrupt mode 1
IM 2 Set interrupt mode 2

Undocumented Instructions

The Z80 contains several undocumented instructions that work reliably and are used by some software. This implementation supports them for compatibility.

SLL (Shift Left Logical)

Opcode: CB 30+r

Similar to SLA but shifts a 1 into bit 0 instead of 0:

    SLL A       ; Shift A left, bit 0 becomes 1
                ; Equivalent to: SLA A : OR 1

IX/IY Half-Register Operations

The DD and FD prefixes allow access to the high and low bytes of IX and IY:

Register Encoding
IXH DD with H encoding
IXL DD with L encoding
IYH FD with H encoding
IYL FD with L encoding

Examples:

    LD A, IXH       ; DD 7C - Load high byte of IX into A
    LD IXL, 0x42    ; DD 2E 42 - Load 0x42 into low byte of IX
    INC IYH         ; FD 24 - Increment high byte of IY

DDCB/FDCB Autocopy

When using indexed bit/rotate/shift instructions (DDCB or FDCB prefixed), the result is automatically copied to a register if the final byte encodes a register:

    ; Standard: RLC (IX+5)
    ; With autocopy: result also goes to specified register
    
    ; DD CB 05 00 - RLC (IX+5),B - rotate and copy to B
    ; DD CB 05 01 - RLC (IX+5),C - rotate and copy to C
    ; DD CB 05 06 - RLC (IX+5)   - standard (no copy)

This behavior, while undocumented, is relied upon by some Z80 software.

Interrupts

The Z80 supports two types of interrupts: maskable (INT) and non-maskable (NMI).

Non-Maskable Interrupt (NMI)

The NMI is edge-triggered and cannot be disabled. When an NMI occurs:

  1. Current PC is pushed onto the stack
  2. IFF1 is copied to IFF2, then IFF1 is cleared
  3. PC is set to 0x0066

The interrupt handler should end with RETN, which restores IFF1 from IFF2.

Maskable Interrupt (INT)

The maskable interrupt can be enabled (EI) or disabled (DI). The response depends on the current interrupt mode.

Interrupt Mode 0

The interrupting device places an instruction (typically RST) on the data bus. The Z80 executes this instruction. This mode is 8080-compatible.

Interrupt Mode 1

The simplest mode. When an INT occurs with IFF1 set:

  1. IFF1 and IFF2 are cleared
  2. Current PC is pushed onto the stack
  3. PC is set to 0x0038

This is the most commonly used mode on many systems.

Interrupt Mode 2

The most powerful mode. When an INT occurs:

  1. IFF1 and IFF2 are cleared
  2. Current PC is pushed onto the stack
  3. The device provides an 8-bit vector
  4. This vector is combined with I to form: (I * 256 + vector)
  5. PC is loaded from the 16-bit value at that address

This allows up to 128 different interrupt vectors.

Interrupt State Registers

IFF1: Controls whether maskable interrupts are accepted. IFF2: Temporary storage of IFF1 during NMI processing.

    ; Typical interrupt handler structure
    
    ORG 0x0038          ; IM 1 vector
    PUSH AF
    PUSH BC
    PUSH DE
    PUSH HL
    
    ; ... handle interrupt ...
    
    POP HL
    POP DE
    POP BC
    POP AF
    EI
    RETI

After EI, interrupts are not enabled until after the following instruction. This allows EI followed by RETI to complete atomically.

Programming Examples

Hello World

A simple program to output a string via UART:

    ORG 0x2000
    
START:
    LD HL, MESSAGE      ; Point to message
    
LOOP:
    LD A, (HL)          ; Get character
    OR A                ; Check for null terminator
    JR Z, DONE          ; Exit if zero
    
    CALL PUTCHAR        ; Output character
    INC HL              ; Next character
    JR LOOP
    
DONE:
    HALT
    
PUTCHAR:
    PUSH AF
WAIT:
    IN A, (0x01)        ; Check UART status
    BIT 1, A            ; TX ready?
    JR Z, WAIT          ; Wait if not
    POP AF
    OUT (0x00), A       ; Send character
    RET
    
MESSAGE:
    DB "Hello, World!", 0x0D, 0x0A, 0

16-Bit Addition

Add two 16-bit numbers:

    ; HL = HL + DE
    ADD HL, DE          ; Simple case
    
    ; For numbers in memory:
    ; Add (NUM1) to (NUM2), store in (RESULT)
    
    LD HL, (NUM1)
    LD DE, (NUM2)
    ADD HL, DE
    LD (RESULT), HL

Memory Fill

Fill a block of memory with a value:

    ; Fill 256 bytes at 0x4000 with 0xFF
    
    LD HL, 0x4000       ; Start address
    LD BC, 0x0100       ; Count (256 bytes)
    LD A, 0xFF          ; Fill value
    
FILL:
    LD (HL), A
    INC HL
    DEC BC
    LD A, B
    OR C
    JR NZ, FILL

Or using block instructions:

    LD HL, 0x4000       ; Start address
    LD DE, 0x4001       ; Destination (start + 1)
    LD BC, 0x00FF       ; Count - 1
    LD (HL), 0xFF       ; Set first byte
    LDIR                ; Copy to fill

Delay Loop

Create a delay using register counting:

    ; Delay approximately (BC * 13) T-states
    
DELAY:
    LD BC, 0xFFFF       ; Maximum count
DELAY_LOOP:
    DEC BC              ; 6 T-states
    LD A, B             ; 4 T-states
    OR C                ; 4 T-states
    JR NZ, DELAY_LOOP   ; 12/7 T-states
    RET

Simple UART Echo

Echo received characters back to the sender:

    ORG 0x2000
    
ECHO:
    IN A, (0x01)        ; Check UART status
    BIT 0, A            ; RX data available?
    JR Z, ECHO          ; Keep waiting
    
    IN A, (0x00)        ; Read received byte
    
WAIT_TX:
    PUSH AF
    IN A, (0x01)        ; Check TX status
    BIT 1, A            ; TX ready?
    JR Z, WAIT_TX       ; Keep waiting
    POP AF
    
    OUT (0x00), A       ; Echo the byte
    JR ECHO             ; Continue

Quick Reference Tables

Condition Codes

Code Flag Test True When
NZ Z = 0 Not zero
Z Z = 1 Zero
NC C = 0 No carry
C C = 1 Carry
PO P/V = 0 Parity odd / No overflow
PE P/V = 1 Parity even / Overflow
P S = 0 Positive
M S = 1 Minus (negative)

Register Codes

8-Bit Registers (r)

Code Register
000 B
001 C
010 D
011 E
100 H
101 L
110 (HL)
111 A

16-Bit Register Pairs

dd ss qq pp
BC BC BC BC
DE DE DE DE
HL HL HL IX/IY
SP SP AF SP

Common Opcode Prefixes

Prefix Effect
CB Bit/Rotate/Shift instructions
DD IX register instead of HL
ED Extended instructions
FD IY register instead of HL

Instruction Timing (Selected)

Instruction T-States
NOP 4
LD r, r' 4
LD r, n 7
LD r, (HL) 7
LD (HL), r 7
LD r, (IX+d) 19
ADD A, r 4
ADD HL, ss 11
INC r 4
JP nn 10
JP cc, nn 10
JR e 12
JR cc, e 12/7
CALL nn 17
RET 10
PUSH qq 11
POP qq 10
LDIR 21/16

Troubleshooting

Common Problems

Program Won't Run

Symptom: Code loads but doesn't execute as expected.

Possible Causes:

  1. Code loaded into ROM area (write-protected)
  2. Stack pointer not initialized
  3. Interrupts disabled when interrupt-driven

Solutions:

Garbled Output

Symptom: UART output appears corrupted.

Possible Causes:

  1. Not waiting for TX ready before sending
  2. Baud rate mismatch
  3. Flow control issues

Solutions:

Infinite Loop

Symptom: Program appears stuck.

Possible Causes:

  1. Condition never met for loop exit
  2. Missing or incorrect jump target
  3. Interrupt handler not returning

Solutions:

Stack Overflow/Underflow

Symptom: Erratic behavior, wrong return addresses.

Possible Causes:

  1. SP initialized too low
  2. Unbalanced PUSH/POP
  3. Deep recursion

Solutions:

See Also