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 mainThe 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.nexOn a Machine
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.
Note 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.