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.

It is not a Z80 tutorial. A working knowledge of the instruction set and of the machine is assumed, and no attempt is made to teach either; what an instruction does to the flags and how long it takes is measured in Bizmuth’s reference rather than restated here.

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 — Pass Structure is the one exception, and says so.

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.

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.

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.

Virtual Origins

!virtual, for a routine that runs somewhere other than where it is loaded: assembling it for the address it will run at while its bytes stay inline, so a copied routine keeps its symbols instead of arriving as an incbin’ed blob. Covers $ inside a block, the page argument a debugger needs, what a sweep does with it, and the six things a block refuses.

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.

Building in Pieces

-f obj, for assembling one part of a program on its own and joining the parts with fantasm link. What separate compilation buys, section with its flags and placement options, extern as the other half of global, why an object has no origin, what an object build refuses, and the archive an ar makes. A call across pages is left as it was written, paging the target in being yours.

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.

Pass Structure

The same three passes for someone reading the crate: what each may still change, how a diagnostic raised after the reader has gone gets a position at all, why errors are sorted and warnings are not, and what line -1 means.

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.