Debugging a Build
FantASM writes two files a debugger can use: --sld, which maps source lines to addresses, and -e, a plain list of exported symbols. Neither changes the image; both are written alongside it.
With the SLD file you get breakpoints on source lines and a call stack naming your labels. Without it, a debugger has addresses and nothing else.
Producing the files
fantasm build main.asm game.nex -t zxnext --sld game.sld -e game.labelsor, so nobody has to remember the flags:
[artifacts]
sld = "dist/game.sld"
labels = "dist/game.labels"Both paths in fantasm.toml resolve against the directory holding it. With several images, each [[target]] can name its own — see Building Several Images.
What --sld contains
sjasmplus-style SLD v1, which is a text format one record per line:
|SLD.data.version|1
t.asm|1||0|-1|-1|Z|pages.size:8192,pages.count:224,slots.count:8,slots.adr:0,8192,…
t.asm|15||0|4|32768|T|
t.asm|14||0|4|32768|L|,main,
t.asm|3||0|20|32777|L|Lib,First,,+used
t.asm|6||0|-1|16384|L|,SCREEN,,+equZdescribes the machine’s paging, so a debugger knows the slot layout.Tmaps a source line to an address. Breakpoints and the stack are built from these.Lis a symbol: module, name, and traits —+equfor a constant,+moduleand+endmodfor boundaries,+usedfor something referenced.
Records are page-aware: each carries a physical page as well as the Z80 address, so a debugger can tell two banked routines at the same address apart.
What -e contains
main = 0x8000
Lib.First = 0x8009⛔ Only GLOBAL symbols appear. The file is empty until something is exported, which is working correctly rather than failing. A constant holding text is written as NAME = "text". Module labels are written with their qualified name.
This is for a loader or a script that needs one address, not for source-level debugging — the SLD file is what a debugger reads. See Modules for what GLOBAL does and does not do.
Debugging under Bizmuth
The 0x1DE extension (The Language Server) drives the whole cycle from the editor. Its Assemble task runs
fantasm build <source> <source>.nex -t <target> --sld <source>.sldso the debug info is always beside the image and always current. Run on Bizmuth then launches the emulator and attaches.
A launch configuration takes program, host, port and stopOnEntry; attaching to an already-running Bizmuth takes host and port. The defaults are 127.0.0.1 and port 11001.
The SLD file is found from the program name — game.nex looks for game.sld — or you can name one explicitly. Without it the session still runs, but at address level only: stack frames show $PC rather than a source line, and breakpoints do not verify.
Two limitations worth knowing before you start
⛔ A breakpoint inside a MODULE does not work. Trace records for a module body carry the address the body was read at rather than where it was placed, so a breakpoint on one resolves into ROM and never hits. Stepping into a module stops in the right place but highlights the wrong line — usually the caller’s. The label records are correct, so Lib.First in a watch or a jump-to-symbol is fine. Only line-level debugging inside a module is affected.
⛔ A !test block is not debuggable. Tests run inside the assembler on its own simulator (Testing) and never reach the image, so there is nothing for an emulator to attach to. -v and assert_cycles are the tools there.
What next
- The Language Server — the editor side, and the rest of what 0x1DE provides.
- Testing — catching it at build time instead, which needs no debugger at all.
- Modules —
GLOBAL, and what ends up in the labels file.