Skip to content

Getting Started

Installing

Add the package for the CPU you are targeting; it brings in the core packages:

dotnet add package MrKWatkins.OakAsm.Z80    # Z80
dotnet add package MrKWatkins.OakAsm.Z80N   # ZX Spectrum Next

Building Assembly from C#

The Z80Assembly class has a static builder method for every instruction and directive. Build a Source, assemble it, then write the bytes out:

using MrKWatkins.OakAsm.Ast;
using MrKWatkins.OakAsm.IO;
using MrKWatkins.OakAsm.Z80;
using static MrKWatkins.OakAsm.Z80.Z80Assembly;

var source = new Source(
    ORG(0x6000),
        LD(BC, "STRING"),
    Label("LOOP"),
        LD(A, [BC]),
        CP(0),
        JR(Z, "EXIT"),
        RST10(),               // ZX Spectrum ROM: print the character in A.
        INC(BC),
        JR("LOOP"),
    Label("EXIT"),
        RET(),
    Label("STRING"),
        DEFB("Hello World"),
        DEFB(13, 0));

Z80Assembler.Instance.Assemble(source);

var output = new Output(source);    // output.Regions has the assembled bytes and their locations.

Memory operands use collection expressions — LD(A, [BC]) is LD A, (BC) — and labels are referenced by name, resolved at assembly time.

DEFB and DEFW take any number of values, so generated data can be passed straight through without unpacking it — DEFB(bytes) for a byte[] or span, DEFW(words) for ushorts. Both throw if given nothing to emit.

Parsing Assembly Text

using MrKWatkins.Ast.Position;
using MrKWatkins.OakAsm.Parsing;
using MrKWatkins.OakAsm.Z80;

var source = OakAsmParser.Parse(new TextFile("hello.asm", File.ReadAllText("hello.asm")));

Z80Assembler.Instance.Assemble(source);

if (source.ThisAndDescendentsHaveErrors)
{
    // Inspect source.ThisAndDescendentsWithErrors for details.
}

Supported Directives

Directive Purpose
ORG address Set the assembly location.
EQU value Define a constant for the preceding label.
DEFB value, ... Emit bytes or strings. DEFM is an alias, conventionally used for strings.
DEFW value, ... Emit words.
DEFS length[, fill] Reserve length bytes, filled with fill or zero. DS is an alias.
ALIGN boundary Advance the location to the next multiple of boundary, filling with zeroes.
INCLUDE "file.asm" Splice in another assembly file, relative to the including file. Available when assembling projects.
INCBIN "file.bin" Place the bytes of a binary file in the output as-is, relative to the including file. Available when assembling projects.
END [entry point] End of source, with an optional entry point given as an address or a label. Nothing after END is emitted.

Expressions

Instruction and directive arguments can be expressions over numbers, labels and $, the current location:

        ORG $8000
Start:
        LD HL, Table + 2 * 4
        LD A, 0b00001111 & Mask     ; See operators below.
        JR $                        ; Jump to self.
Finish:
Size:   EQU $ - Start
        DEFW Finish - Start

Operators, highest precedence first:

Operators Meaning
- ~ (unary) Negate, bitwise complement.
* / % Multiply, divide, modulo.
+ - Add, subtract.
<< >> Bit shifts.
& Bitwise AND.
^ Bitwise exclusive OR.
\| Bitwise OR.

Brackets group sub-expressions, but an argument starting with an open bracket is a memory reference — LD A, (Base + 1) reads memory, LD HL, Base + 1 is address arithmetic.

$ evaluates to the location of the containing instruction, so JR $ jumps to itself. Constant expressions for relative jumps, e.g. JR 5, are raw displacements; expressions involving labels or $ are target addresses and the displacement is calculated for you, with an error if the target is out of range.