Getting Started
From nothing to a running program. Ten minutes, most of it waiting for a compiler.
Installation
FantASM is a Rust program and is built from source. You need a recent stable Rust — the crate is edition 2024 and uses let-chains, so a toolchain more than a year old will not build it. rustup update if in doubt.
git clone https://codeberg.org/twistedraven/fantasm.git
cd fantasm
cargo install --path .That puts fantasm on your $PATH at ~/.cargo/bin. Check it:
fantasm --versioncargo build --release works too and leaves the binary in target/release/fantasm, but then you have to reach it by path.
⚠ cargo install does not track the checkout. After pulling changes, install again or the old binary keeps running. A tool behaving unlike the source you just read is nearly always that.
A First Project
mkdir hello && cd hello
fantasm initinit asks four questions — project name, machine, output format, entry-point filename — and writes two files. Answer them on the command line to skip the prompts:
fantasm init --name hello --device zxnext --format nex --main main.asmYou get a fantasm.toml:
[project]
name = "hello"
version = "0.1.0"
main = "main.asm"
output = "out.nex"
[assembler]
device = "zxnext"
format = "nex"
verbose = trueand a main.asm that turns the border red:
; hello - Generated by FantASM
!device zxnext
ORG $8000
main:
LD A, 2
OUT ($FE), A ; Set border to red
JR mainFirst Build
fantasm buildInfo: assembling `main.asm`
Info: first pass (in-memory)
Info: second pass
Info: assembly complete [0.005s]The project file said where the source is and where the output goes, so nothing had to be repeated on the command line. out.nex is now beside it.
fantasm on its own does not build. With no arguments it prints a usage summary and exits, project file or not; any argument is enough — fantasm build, fantasm -n, fantasm --all — but the bare word is not one.
Without a project file, name the source and let the output be inferred:
fantasm build main.asm # -> main.bin
fantasm build main.asm game.nex # -> game.nexFirst Run
out.nex is a Spectrum Next executable. Load it in Bizmuth or on real hardware; the border should turn red and stay there.
If nothing happens, the usual cause is the entry point. A .nex records where execution starts, and code assembled before any ORG lands at $0000 — see W1069 in Diagnostics.
A First Test
FantASM can run your code on an emulated CPU at build time. Add this below main:
add_one:
inc a
ret
!test "add_one increments"
init_reg a, 1
call add_one
halt
assert_reg a, 2
endtestThen:
fantasm build --testThe test assembles, runs on a simulated Z80, and checks the register afterwards. Nothing about it reaches out.nex — a !test block is build-time only.
Warnings
fantasm build -u-u, or --find-unused, runs the unused-label sweep, which finds labels nothing refers to. It does not complain about labels that are exported, pinned or run into, and it turns on that sweep only — every other warning is shown regardless.
⚠ A routine called only from a !test is currently reported unused. Following the section above and then running -u gives you W1049: unused label add_one, because a reference from inside a test block is not counted as a use. Mark it GLOBAL or KEEP add_one to silence it, and do not read it as the test having failed to reference the routine — the test passes.
Further Reading
- The Project File — everything
fantasm.tomlcan say, and what beats what. - Command Line — every option, and the ones that surprise people.
- Diagnostics — how to read a message, and the reserved words behind the most confusing failures.
- Rhai Scripting — computing tables and constants at build time instead of typing them.
- Building Several Images — when your program becomes a loader and a payload.