FantASM

The documentation for FantASM, a Z80 and Z80N assembler for the ZX Spectrum and the Spectrum Next. It writes raw binaries, Intel HEX, .sna snapshots and .nex executables, runs unit tests against an emulated CPU, and ships a language server. What it assembles runs under Bizmuth.

The repository’s own docs/ is the terse reference that travels with the source. These pages are the longer form, written for people using the assembler rather than working on it.

Getting Started

Getting Started

Installing, a first project, building it, writing a test that runs on an emulated CPU, and where to go from there.

The Language

Writing Source

The syntax underneath everything else: labels and local labels, constants, every number format, strings and escapes, and what may go in an expression.

Instructions

What FantASM accepts and what has to be turned on: the undocumented instructions that need no flag, the three ways to enable Z80N, the CSpect pseudo-ops, and how an operand may be written. Flags and timings are measured in Bizmuth’s reference rather than restated here.

Directives

Every directive, grouped by what it does: placing code, laying down data, including files, conditional assembly, macros, enums and structs. Includes the ones whose syntax surprises — #define makes a macro rather than a constant, and enum takes its name after the directive.

Libraries

Writing a library as a file: !library and the guard it brings, includes scoped by where they sit, types and macros belonging to the library that declares them, an INTERFACE saying what is public, and --gc-libraries for paying only for what you call.

Modules

MODULE — the legacy way to namespace, and the way to place bytes at the end of a file. Carries the scope rules both forms share: the three ways to reach across a boundary, local labels, GLOBAL as export rather than visibility, and --gc-modules with KEEP.

Memory and Banking

What each machine’s memory looks like, selecting a page with bank and page, knowing where you are with _page/_bank/_slot, and using --ram to make a build fail at your desk rather than on someone else’s hardware.

The Build

Command Line

Every option, what it does, and the ones that surprise people — -u turning on one sweep rather than all warnings, the machine being a device rather than a target, and the --no- forms that exist because a project file could otherwise only turn a setting on. Also init, the environment variables and the exit status.

The Project File

fantasm.toml: getting one, what each table does, and what happens when the command line and the file disagree. Covers [project], [assembler], [defines], [lint], [artifacts] and [tasks], the precedence rules, and how a project keeps settings of its own in the same file without being told they are misspelt.

Output Formats

bin, hex, sna and nex — what each one is, which of the three places naming a format wins, and how to get code into a bank of a .nex so it is still there when the program runs. Also --reloc, for running a bin at an address it was not assembled for.

Building Several Images

[[target]], for a program that is more than one file: a payload and the loader that incbins it, or a release and a debug variant. Declaring targets, depends and build order, --only and --all, what happens when one fails, per-target recipes and per-target test counts.

Further Topics

Testing

Unit tests that run your routines on an emulated CPU at build time. The shape of a !test block, what init_reg and assert_reg actually are, cycle budgets, and how to read a failure.

The Language Server

Errors as you type, go-to-definition, hover showing a label’s value or an instruction’s T-states, completion over your own names, project-wide rename, call hierarchy and quick fixes. How to point an editor at it, which file answered for the one you have open, and the one case where it can still disagree with a real build.

Rhai Scripting

Computing things at build time instead of typing them. The three forms a script takes, everything ctx offers, why an expression call cannot change state, the sandbox and its limits, and what a script fault looks like.

Using It as a Library

For Rust developers rather than Z80 programmers: assembling in-process and getting bytes and structured diagnostics back as values. Where the diagnostics actually live, why warnings is not only warnings, and what the crate promises about staying still.

Troubleshooting

Debugging a Build

The two files a debugger reads — --sld for source lines and -e for exported symbols — what is in each, and how the 0x1DE extension drives an assemble-and-run cycle under Bizmuth.

How Assembly Works

Gather, decide, emit — and why nearly every surprising behaviour is one of the three showing through: which names may be used before they are defined, where a MODULE body really lands, and why some warnings name a line long after you wrote it.

Diagnostics

How to read a message, what the level and the code mean, which warnings you have to ask for, the ones you will actually meet, the reserved words that cause the most confusing failures, and a table of every code FantASM can print.