lgbtasm

A Game Boy assembler and disassembler provided as a standalone Lua module. The syntax is strict and the command language is minimal; in particular, there are no macros and there are no global labels, although global labels may be implemented on top of lgbtasm using defs.

lgbtasm is known to work with Lua 5.1 and LuaJIT. Other Lua versions will probably need minimal adaptation. All code examples provided here assume a LuaJIT interpreter in order to embed hexadecimal values in string literals.

lgbtasm is used in the original Oracles Randomizer, as well as in some of my ROM hacks.

Downloads: single file (lua, 28K), archive (zip, 12K)

Syntax

This module uses bgb/no$gmb syntax and enforces a strict style: numbers are undecorated (no $, etc.) and hexadecimal, a, is required in mnemonics that feature it, spaces do not appear after ,s, parens are used for "dereferencing" memory, and all keywords are lower-case. User-defined symbols such as labels are case-sensitive. A label and instruction cannot appear on the same line.

The characters in ;*# all begin inline comments, although instruction delimiter status overrides comment character status in the compile() function.

"Local" labels (the only kind) start with a . and can be referenced by relative jumps. Decompilation automatically generates labels for relative jump destinations.

Functions

compile(block, opts)

Parses a series of instructions and returns the equivalent machine code as a byte string. Generates an error if an instruction does not match any mnemonic, or if an invalid argument is given to an instruction. The optional opts table can have the fields:

> lgbtasm = require 'lgbtasm'
> return lgbtasm.compile('cp b; ret', {delims = ';'}) == '\xb8\xc9'
true
> return lgbtasm.compile('ld (x),a', {defs = {x = 0xc6c5}}) == '\xea\xc5\xc6'
true

decompile(block, opts)

Converts a string of machine code into an asm string. Generates an error if an opcode is invalid, or if not enough bytes remain in the string to satisfy an instruction's argument. The optional opts table can have the fields:

> lgbtasm = require 'lgbtasm'
> return lgbtasm.decompile('\xb8\xc9', {delim = '; '})
cp b; ret
> return lgbtasm.decompile('\xfa\xc5\xc6', {defs = {x = 0xc6c5}})
ld a,(x)

Commands

db d8{,d8}

Creates a sequence of literal bytes.

> lgbtasm = require 'lgbtasm'
> return lgbtasm.compile('db 01,02,03') == '\x01\x02\x03'
true

dw d16{,d16}

Creates a sequence of little-endian words.

> lgbtasm = require 'lgbtasm'
> return lgbtasm.compile('dw 0201,0403') == '\x01\x02\x03\x04'
true

define symbol,value

Associates a symbol with a constant numeric value. Redefining a symbol is not an error.

> lgbtasm = require 'lgbtasm'
> return lgbtasm.compile('define x,01; ld a,x', {delims = ';'}) == '\x3e\x01'
true