Skip to main content

65c816 patching assembler (Super Famicom)

Project description

a816

Another 65c816 assembler.

Targets Super Famicom / SNES ROM hacking and patching. Ships a CLI assembler, an object-file linker, an LSP server, and xdds (a SNES-aware hex dump / disassembler).

Usage

Command line

$ a816 --help
usage: x816 [-h] [--verbose] [-o OUTPUT_FILE] [-f FORMAT] [-m MAPPING]
            [--copier-header] [--dump-symbols] [-c]
            [-D KEY=VALUE [KEY=VALUE ...]] [--no-auto-imports] [-I PATH]
            [--obj-dir OBJ_DIR] [--include-path PATH] [--prelude PRELUDE_FILE]
            input_files [input_files ...]

positional arguments:
  input_files           Input files (asm files or object files for linking)

options:
  -o, --output OUTPUT_FILE
                        Output file
  -f FORMAT             Output format (ips, sfc, obj)
  -m MAPPING            Address mapping (low_rom, low_rom_2, high_rom)
  --copier-header       Adds 0x200 address delta for ips writer.
  --dump-symbols        Dumps symbol table
  -c, --compile-only    Compile to object files without linking.
  -D, --defines KEY=VALUE [KEY=VALUE ...]
                        Defines symbols.
  --no-auto-imports     Disable automatic import resolution.
  -I, --module-path PATH
                        Add directory to module search path.
  --obj-dir OBJ_DIR     Directory for compiled object files (default:
                        build/obj).
  --include-path PATH   Add directory to include search path for .include.
  --prelude PRELUDE_FILE
                        Config file prepended to every module compilation.

Separate compilation

Compile each module to an object file, then link:

$ a816 --compile-only file1.s file2.s   # produces file1.o, file2.o
$ a816 file1.o file2.o -o output.ips    # link to IPS
$ a816 file1.o file2.o -f sfc -o output.sfc
$ a816 file1.s file2.o -o output.ips    # mix sources and objects

From Python

from a816.program import Program

def build_patch(input, output):
    program = Program()
    program.assemble_as_patch(input, output)
    program.resolver.dump_symbol_map()

Supported Syntax

Mnemonics

adc, and, asl, bcc, bcs, beq, bit, bmi, bne, bpl, bra, brk, brl, bvc, bvs, clc, cld, cli, clv, cmp, cop, cpx, cpy, db, dec, dex, dey, eor, inc, inx, iny, jml, jmp, jsl, jsr, lda, ldx, ldy, lsr, mvn, mvp, nop, ora, pea, pei, per, pha, phb, phd, phk, php, phx, phy, pla, plb, pld, plp, plx, ply, rep, rol, ror, rti, rtl, rts, sbc, sec, sed, sei, sep, sta, stp, stx, sty, stz, tax, tay, tcd, tcs, tdc, trb, tsb, tsc, tsx, txa, txs, txy, tya, tyx, wai, xba, xce

Macros

.macro test(var_1, var_2) {
    lda.w var_1 << 16 + var_2
}

test(0x10, 0x10)
; expands to: lda.w 0x10 << 16 + 0x10
; emits:      lda.w 0x1010

Code pointer relocation

*=0x008000
    jsr.l _intro

Scopes

some_address = 0x54
{
    lda.b some_address
    beq no_action
    ; label only visible inside this scope
    no_action:
}

Named scopes

*=0x009000
named_scope {
   addr = 0x1234
   youhou_text:
   .text 'youhou'
   .db 0
   yaha_text:
   .text 'yaha'
   .db 0
}

*=0x019A52
    load_system_menu_text_pointer(named_scope.youhou_text)

*=0x019A80
    load_system_menu_text_pointer(named_scope.yaha_text)

Structs

.struct Name { ... } declares a layout. Each field is one of byte, word, long (24-bit), or dword (32-bit). Field names export as Name.field constants holding the byte offset from the start of the struct, plus Name.__size for the total length.

.struct OAM {
    word x
    byte y
    byte tile
    byte attr
}

emits OAM.x = 0, OAM.y = 2, OAM.tile = 3, OAM.attr = 4, OAM.__size = 5.

Use the offsets against any base address — a hardware register, a WRAM pointer, an array stride:

.struct PPU {
    byte INIDISP
    byte OBSEL
    word OAMADDR
}

*=0x008000
    lda.w 0x2100 + PPU.OAMADDR  ; assembles as LDA $2102

player = 0x7E0010
    lda.b player + OAM.x
    sta.b player + OAM.tile

Structs are layout-only; they don't reserve storage and don't emit bytes. Pair with *= or a memory-map directive to place an instance.

Modules

.import "module" brings symbols from another translation unit; .extern declares cross-module references. See Modules for the full workflow, visibility rules, and constants over externs.

.import "vwf"
.extern external_func

main:
    jsr.l vwf.init
    jsr.w external_func
    rts

Project configuration (a816.toml)

Drop an a816.toml at the project root to declare the entrypoint and search paths. Currently consumed by the LSP server; see LSP.

entrypoint    = "src/main.s"
include-paths = ["src/include"]
module-paths  = ["src/modules"]

LSP

a816-lsp-server ships with the package: diagnostics, goto-definition (including .import targets), and hover info. See LSP for editor setup.

Built-in symbols

  • BUILD_DATE — set automatically to the current date.

.text strings expand ${VAR} references against defined symbols.

xdds

SNES-aware hex dump and disassembler.

$ xdds --help
$ xdds rom.sfc --low-rom -s 0x008000 -l 256
$ xdds rom.sfc --low-rom -d --m16 --x16 -n 32   # disassemble 32 instrs
$ xdds rom.sfc --ips patch.ips -s '$01:FF40'   # apply IPS, dump from SNES addr

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

a816-1.1.0a14-py3-none-any.whl (131.1 kB view details)

Uploaded Python 3

File details

Details for the file a816-1.1.0a14-py3-none-any.whl.

File metadata

  • Download URL: a816-1.1.0a14-py3-none-any.whl
  • Upload date:
  • Size: 131.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: Hatch/1.16.5 cpython/3.12.13 HTTPX/0.28.1

File hashes

Hashes for a816-1.1.0a14-py3-none-any.whl
Algorithm Hash digest
SHA256 df6aa94be2d9da09721440989d36c3131753f10fa4085e6098395cf7d02b0321
MD5 629844459fd527c83e88e3fef951dc6c
BLAKE2b-256 0e82810444efb6e013e765b5bbfff40a5b9a86a59e58a26d2ca92d30e7fed93a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page