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 --version

cargo 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 init

init 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.asm

You get a fantasm.toml:

[project]
name = "hello"
version = "0.1.0"
main = "main.asm"
output = "out.nex"

[assembler]
device = "zxnext"
format = "nex"
verbose = true

and 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 main

The Build

fantasm build
Info: 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.nex

On 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
    endtest

Then:

fantasm build --test

The 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.toml can 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.

Documentation