Skip to main content

NMOS 6510 illegal-opcode toolkit: a standalone 6510 -> raw-P-Code lifter + pure-Python P-Code VM, and a 6510 Ghidra/pypcode SLEIGH processor module.

Project description

deity-informant

A 6510 illegal-opcode toolkit: a standalone 6510 -> raw-P-Code lifter + pure-Python P-Code VM, and a 6510 Ghidra/pypcode SLEIGH processor module. All 105 documented NMOS 6510 illegal opcodes are first-class. No runtime dependency on py65 or Ghidra.

Why

Working on C64 code requires the NMOS 6510 illegal opcodes, and no existing backend handles them correctly:

  • Real playroutines/demos use illegals as load-bearing instructions (A Mind Is Born runs SRE; Automatas runs SBX/SAX/LAX/ANC/ALR).
  • Stock Ghidra's 6502 SLEIGH spec (and pypcode, which vendors it verbatim) defines zero illegals and has no catch-all — every illegal is a BadDataError, so it cannot even disassemble such code, let alone decompile it.
  • Ghidra's decompiler only consumes P-Code from a compiled SLEIGH spec, so Python-generated P-Code cannot be injected — a SLEIGH language extension is the only way to make the decompiler illegal-aware.
  • py65 is not a valid execution reference: it stubs the RMW illegals (SLO/RLA/SRE/RRA/DCP/ISC, LAS/ANE/SH*) as inst_not_implemented — a 2-byte, 0-cycle skip, silently wrong on real code.
  • The known community 6510 Ghidra fork adds illegal disassembly only, with uncertain P-Code semantics — not trustworthy for decompilation or execution.
  • deity-informant supplies both missing pieces: a compiled 6510 SLEIGH module (illegal-aware Ghidra/pypcode decompilation) and a hardware-validated lifter + VM (byte-exact vs sidplayfp) executing all 105 illegals.

Two products

  • standalone lifter + VMlift (6510 -> raw P-Code), the PcodeVM interpreter, and the run_sub/run_irq/run_irq_driven drivers. Pure Python, no Ghidra, no py65.
  • 6510 SLEIGH module (ghidra/6510/) — stock 6502 legal spec + generated 6510_illegal.sinc that makes Ghidra's disassembler and decompiler, and pypcode, illegal-aware. Language id 6510:LE:16:default.

Install

pip install deity-informant            # core, no deps
pip install deity-informant[oracle]    # + py65 (legal-opcode differential oracle)
pip install deity-informant[ghidra]    # + pypcode (SLEIGH build / lift backend)
pip install deity-informant[dev]       # test + lint tooling

CLI

Console script deity-informant:

deity-informant disasm IMAGE [--org ADDR] [--start ADDR] [--count N]  # 6510 disassembly (illegal-aware)
deity-informant pcode  IMAGE --at ADDR [--org ADDR]                   # raw P-Code for one instruction
deity-informant run    IMAGE --init ADDR [--play ADDR --frames N]     # execute in PcodeVM, dump $D400.. grid
deity-informant emit-sleigh [-o DIR] [--magic 0xEE]                   # build/install the 6510 SLEIGH module

Python API

from deity_informant import lift, PcodeVM, run_sub
insn = lift(mem, pc)                 # {"ops", "len", "cyc", "pen", "ctrl"}
vm = PcodeVM(mem); run_sub(vm, entry, {}, lift)   # execute a subroutine to its RTS

Use with Ghidra

python ghidra/6510/build.py --install "$GHIDRA_INSTALL_DIR/Ghidra/Processors/6510/data/languages"

Compiles 6510.sla, resolving the stock 6502.slaspec + SLEIGH compiler from $GHIDRA_INSTALL_DIR (or a pypcode install). Restart Ghidra, import the C64 image as Raw Binary language 6510:LE:16:default at base $0000; illegals now decode instead of BadData. Full steps: docs/ghidra.md.

Example / demo

python examples/hello_world.py prints HELLO, WORLD! from a self-contained 33-byte C64 program that uses two load-bearing illegal opcodes (LAX, ISC) and genuine self-modifying code (ISC's INC rewrites the STA operand each pass). CI verifies both the VM output and that the LAX/ISC bytes decode through the 6510 SLEIGH engine (where stock 6502 throws BadDataError). Walkthrough: docs/hello-world.md.

Decompiled to P-Code

The two illegal opcodes through Ghidra's decompiler engine (6510:LE:16:default, libsla — same engine as pypcode.Context(...).translate(...)). Stock 6502 raises BadDataError on both bytes; the 6510 module emits real P-Code:

$1002  BF 13 10   LAX $1013,Y      ; illegal — one instruction loads A and X and sets Z
  unique[11b00:2] = zext(Y)                 # Y widened to 16-bit index
  unique[11d00:2] = 0x1013 + unique[11b00:2]# effective address $1013 + Y
  A = *[RAM]unique[11d00:2]                  # A <- data[Y]
  X = A                                      #   ...and X too (the "LAX" fork)
  Z = A == 0x0                               # Z flag the BEQ terminator rides on
  N = A s< 0x0                               # N flag

$100C  EF 0A 10   ISC $100A        ; illegal RMW — INC $100A then SBC (discarded)
  unique[f400:1] = RAM[100a:1] + 0x1         # INC the byte at $100A ...
  RAM[100a:1]    = unique[f400:1]            #   ...= the STA operand -> self-modification
  unique[f500:1] = A - unique[f400:1]        # SBC A,mem: borrow-chain subtract ...
  unique[f800:1] = unique[f500:1] - !C       #   ...minus carry-complement
  ... V/N/Z/C flag algebra elided ...
  A = unique[f800:1]                         # SBC result -> A (overwritten by next LAX)

RAM[100a:1] = ... is Ghidra rendering a store into code space — the self-modification made visible in P-Code. The full instruction-by-instruction dump (and how CI asserts it under headless Ghidra) is in docs/hello-world.md.

Illegal opcodes

All 105 documented NMOS 6510 illegals lifted as genuine P-Code (not stubs), semantics/cycles per "No More Secrets — NMOS 6510 Unintended Opcodes" (V1.0, 24 Dec 2025) (csdb.dk/release/?id=258111), independently validated byte-exact against the sidplayfp hardware oracle. Full table: docs/illegal-opcodes.md.

Docs

Project details


Download files

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

Source Distribution

deity_informant-0.2.0.tar.gz (30.5 kB view details)

Uploaded Source

Built Distribution

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

deity_informant-0.2.0-py3-none-any.whl (21.2 kB view details)

Uploaded Python 3

File details

Details for the file deity_informant-0.2.0.tar.gz.

File metadata

  • Download URL: deity_informant-0.2.0.tar.gz
  • Upload date:
  • Size: 30.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for deity_informant-0.2.0.tar.gz
Algorithm Hash digest
SHA256 7bbe0d05db57e5b6d85c952d181e79990e67ed140fc44408d555b1a733ba1b72
MD5 8ed914cc1776ab640b907aae5ea3c891
BLAKE2b-256 3669fb15d60feeda7cb88959d86b4eed2287a29442dd40ed60f0bcac138a857f

See more details on using hashes here.

Provenance

The following attestation bundles were made for deity_informant-0.2.0.tar.gz:

Publisher: publish.yml on anarkiwi/deity-informant

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file deity_informant-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: deity_informant-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 21.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for deity_informant-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a3695d3e4061092686610877cb3621edf1506f5329fa8c42db9a321801122fd6
MD5 15646ba4d594c54244a84eb661ae667e
BLAKE2b-256 235db214247679b6f3a4cbc330857f71a7a6f7f0ddc693f10994e2ca6e3576a6

See more details on using hashes here.

Provenance

The following attestation bundles were made for deity_informant-0.2.0-py3-none-any.whl:

Publisher: publish.yml on anarkiwi/deity-informant

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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