A MOS 6502 toolchain written in Zig.
mostools is a linker-based toolchain for 6502 development, modeled after the classic binutils workflow: sources are assembled into relocatable object files, and a separate linker places them into their final memory layout. This enables true multi-file projects with cross-file symbols, named segments, and target-specific memory configurations for systems such as the Commodore 64 and the NES.
Status: pre-alpha. The toolchain is under active initial development and is not yet usable. Interfaces, the object format, and the assembler dialect are all subject to change without notice. See TODO.md for the development plan and current progress.
| Tool | Purpose |
|---|---|
mosasm |
Assembler. Translates 6502 assembly into relocatable objects. |
mosld |
Linker. Places objects into a final binary via a memory config. |
mosdump |
Inspector. Dumps and disassembles objects and binaries. |
mosar |
Archiver. Bundles objects into static libraries. |
All four tools are thin front ends over a shared core module containing the
object format codec, the instruction tables, the expression evaluator, and the
layout engine. The core is pure (no file I/O, no process state), which keeps
every piece of real logic unit-testable in memory.
- Relocatable objects. mosasm emits a compact custom object format rather
than flat binaries. Relocations are restricted to
symbol + addendwith five fixup types (16-bit absolute, zeropage, low byte, high byte, and relative branch). The format is specified in docs/OBJECT_FORMAT.md, which is authoritative: format changes land in the document before they land in code. - Declared zeropage semantics. Whether an imported symbol is zeropage is declared at the import site. Instruction sizing is therefore fully determined at assembly time; the linker never resizes code.
- Sections everywhere. Code is always assembled into named segments, even in single-file projects. Assembling directly to a runnable binary is supported as a convenience and is implemented as an in-process link against a default configuration, not as a separate code path.
- Data-driven ISA. A single declarative CPU description generates both the assembler's encoding tables and the disassembler's decoding tables at compile time, so the two cannot disagree. CPU variants (undocumented opcodes, 65C02) are additions to the data, not to the code.
- Diagnostics as values. Errors carry source locations and accumulate; a run reports every problem it finds rather than stopping at the first.
Requires Zig 0.16.0.
zig build
zig build test
Binaries are installed to zig-out/bin/.
The interface sketched below reflects the intended design and will change during development.
Assemble and link a multi-file project:
mosasm main.s -o main.o
mosasm sprites.s -o sprites.o
mosld -C c64.cfg main.o sprites.o -o game.prg
Assemble a single file directly to a binary:
mosasm demo.s -o demo.bin
Inspect an object:
mosdump main.o
Planned output formats: flat binary, Commodore 64 .prg, and iNES .nes.
Memory layouts are described by a linker configuration file defining memory
areas and the assignment of segments to them, following the model established
by cc65.
Link-time code relaxation, expression trees in relocations, and 65816 support are explicitly out of scope for the initial release. The object format reserves space for future extensions.
The project is not yet accepting contributions while the core design settles. Issues and discussion are welcome.
Apache-2.0