AZM Book 1 — Z80 Fundamentals
No prior knowledge of computers or programming assumed.
The first two chapters describe the machine and what a program looks like as raw bytes. Chapter 3 introduces assembly language and the AZM program structure. Chapters 4–10 teach raw Z80 programming. Chapters 11–14 introduce AZM-specific features: subroutine conventions and register discipline, AZMDoc register contracts, layout types and op declarations.
Continue with AZM Book 2 — Programming the TEC-1G when you are done, or jump to AZM Book 3 — Algorithms and Data Structures if you want the algorithm track.
Learning arc
Chapters 1 and 2 cover the machine before any code: how the CPU fetches and executes bytes, what a program looks like as raw hex and why raw hex is unmanageable to write by hand. Chapter 3 introduces assembly language and the AZM source format: .org for placing code and data, .equ for named constants, .db/.dw for defining storage and labels as the names for addresses. Chapter 4 extends ld to cover memory access forms and explains how the Z80 represents signed and unsigned values. Chapters 5 through 9 extend the instruction set further — flags and branches, counted loops, data tables, the stack and subroutines, port I/O. By Chapter 9 you can write raw Z80 programs that read hardware and manage memory directly.
Chapter 10 is a capstone: a complete AZM program built from the techniques of Chapters 3–9. It is a real, working program — and it also exposes the practical frictions that grow with any assembly codebase: subroutines whose register usage is undocumented, layouts whose byte offsets have to be counted by hand and short instruction patterns repeated throughout the code. Those frictions are real, and naming them is the point.
Chapters 11 through 14 each address one of those friction points. Chapter 11 covers subroutine calling conventions and the discipline of register ownership — the raw techniques that any serious assembly program needs. Chapter 12 introduces AZMDoc, AZM’s formal register-contract system, which lets you document what goes in, what comes out and what gets clobbered — and have the assembler verify it. Chapter 13 covers AZM’s layout type system — compile-time memory contracts, not hidden data access: scalar types (byte, word, addr), records, unions as alternate views, sizeof and offset, .ds and named-length idioms, layout casts and enums as state/command names. Chapter 14 introduces op declarations, which give a name to a short instruction sequence and expand it inline at every call site.
By Chapter 10 you can read and write any raw Z80 program. By Chapter 14 you can write AZM programs that are self-documenting, where layouts never require hand-counted offsets and repeated instruction patterns have names — while retaining access to every raw instruction when you need it.
Chapter table
| Ch | File | What it covers |
|---|---|---|
| 1 | The Computer | CPU, memory, registers, the fetch-execute cycle |
| 2 | Machine Code | Programs as bytes, decoding a real hex program, why raw machine code is fragile |
| 3 | Assembly Language | AZM program structure, .org, .equ, .db/.dw, labels, ld |
| 4 | Memory Access and Data | (HL), (BC), (DE), direct memory access, LD forms table, signed/unsigned values |
| 5 | Flags, Comparisons, Jumps | Flags register, cp instruction, conditional and unconditional jumps |
| 6 | Counting Loops and DJNZ | djnz instruction, counted loops, loop patterns |
| 7 | Data Tables and Indexed Access | Tables in memory, HL sequential access, IX indexed access, ex de, hl, ldir |
| 8 | Stack and Subroutines | push, pop, call, ret, the system stack, subroutine conventions |
| 9 | I/O and Ports | in, out, port-mapped I/O, TEC-1 hardware examples |
| 10 | A Complete Program | Putting it all together: a real program from start to finish |
| 11 | Subroutine Conventions | Register discipline, calling conventions, push/pop preservation |
| 12 | Register Contracts with AZMDoc | Caller/callee contracts, flags as out, @ entries, .asmi, register-care CLI |
| 13 | Layout Types | byte/word scalars, .type/.union, sizeof/offset, .ds type expressions, layout casts, enums |
| 14 | Op Declarations | op for inline expansion, operand matchers, pseudo-opcodes |
Example files are under examples/ in this directory. Examples 00 and 01 accompany Chapter 3; example 02 accompanies Chapter 4. From 03 onward, each example corresponds to the next chapter: 03_flag_tests_and_jumps.asm goes with Chapter 5, 04_djnz_loops.asm with Chapter 6, and so on. Chapters 1 and 2 have no example files — they cover concepts that precede writing code.
How to assemble the examples
You can assemble from the terminal or from VS Code with Debug80—same .asm source either way.
Terminal (standalone AZM CLI)
azm examples/01_register_moves.asm
From the AZM source tree:
npm run azm -- examples/01_register_moves.asm
VS Code (Debug80)
Install the Debug80 extension, point a debug80.json target at the example .asm and press F5. Debug80 assembles as part of starting the session and writes the usual artifacts (.hex, .lst and related files) under the target’s outputDir. See Debug80 Book 1 — Getting Started for install, project files and platform choice.
Hardware and emulator setup
Target system
This book is platform-agnostic. The programs target a Z80 with ROM starting at $0000 and RAM starting at $8000 — the same memory map described in Chapter 1. They do not rely on any specific hardware beyond that. Port I/O examples in Chapter 9 use TEC-1 port addresses as concrete numbers, but the concepts apply to any Z80 system.
Emulator and debugger (Debug80)
Debug80 is the VS Code debugger extension for this site. It is the preferred way to work through the course: assemble AZM .asm sources on F5, load the program image, map listing lines back to source and debug with normal VS Code controls.
During a session you get:
- Step mode — step into, over and out at source level; continue, pause, restart and stop the emulated CPU.
- Registers — AF, BC, DE, HL, alternate set, index registers, stack pointer and program counter in the Variables view (including flags when a branch looks wrong).
- Memory — inspect and edit RAM through Debug80’s platform panels; confirm results at labels such as
$8000afterhalt. - Breakpoints — set breakpoints in
.asmsource before or during a run; resolved breakpoints map to the generated Z80 addresses. - TEC-1 support — for Chapter 9 port I/O, configure a TEC-1 or Simple target in
debug80.jsonsoin/outexamples see the expected port map; the TEC-1 panel can drive keypad and display behaviour where the chapter references hardware.
Open or create a debug80.json project (Debug80 Book 1 — Getting Started), open your .asm and press F5—no separate terminal azm step is required for editor-based work. Chapters 1–8 and 10–14 need only a plain Z80 memory map; port-accurate behaviour matters mainly in Chapter 9.
The standalone azm CLI (npm install -g @jhlagado/azm) is the same assembler for terminal builds, CI or when you prefer to load .hex into another emulator yourself.
Other emulators
If you prefer a standalone desktop emulator, FUSE and ZEsarUX (both free and cross-platform) also expose registers, memory and step mode. Load the .hex or binary AZM emits and single-step the same way Chapter 3 describes. For TEC-1-specific display and port behaviour outside VS Code, the TEC-1 emulator remains a useful alternative for Chapter 9.
Verifying a program ran correctly
After assembling and loading a program into the emulator:
- Single-step the first several instructions using the emulator’s step mode. Confirm each register holds the value you expect before moving to the next instruction.
- Check memory at the target address after the program halts. For the Chapter 3 example
00_first_program.asm, address$8000should contain$08after the program runs. For the Chapter 4 example02_constants_and_labels.asm,$8000should hold$0A,$8001should hold$34and$8002should hold$12. - Inspect the flags register whenever a jump goes the wrong way. The emulator’s register panel shows each flag bit; compare what you see to what Chapter 5 says the instruction should produce.
If the program does not halt or produces wrong values, the debugging steps in Chapter 3 (“When Your Program Does the Wrong Thing”) give a systematic method for tracing the failure.
Table of contents
- Chapter 1 — The Computer
- Chapter 2 — Machine Code
- Chapter 3 — Assembly Language
- Chapter 4 — Memory Access and Data
- Chapter 5 — Flags, Comparisons and Jumps
- Chapter 6 — Counting Loops and DJNZ
- Chapter 7 — Data Tables and Indexed Access
- Chapter 8 — Stack and Subroutines
- Chapter 9 — I/O and Ports
- Chapter 10 — A Complete Program
- Chapter 11 — Subroutine Conventions
- Chapter 12 — Register Contracts with AZMDoc
- Chapter 13 — Layout Types
- Chapter 14 — Op Declarations