Skip to content

Getting Started ​

Installing ​

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

bash
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:

csharp
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 ​

csharp
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 ​

DirectivePurpose
ORG addressSet the assembly location.
EQU valueDefine 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 boundaryAdvance 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:

asm
        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:

OperatorsMeaning
- ~ (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, for example, 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.