{"id":47752113,"url":"https://github.com/c0rner/ghidra_wpc_loader","last_synced_at":"2026-06-06T09:01:04.821Z","repository":{"id":346437866,"uuid":"1189972130","full_name":"c0rner/ghidra_wpc_loader","owner":"c0rner","description":"Loader for Williams Pinball Controller (WPC) game ROMs","archived":false,"fork":false,"pushed_at":"2026-05-28T22:34:52.000Z","size":43,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-29T00:10:25.431Z","etag":null,"topics":["6809","ghidra","pinball","reverse-engineering","romhacking"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/c0rner.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-23T21:05:55.000Z","updated_at":"2026-05-28T22:33:42.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/c0rner/ghidra_wpc_loader","commit_stats":null,"previous_names":["c0rner/ghidra_wpc_loader"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/c0rner/ghidra_wpc_loader","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c0rner%2Fghidra_wpc_loader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c0rner%2Fghidra_wpc_loader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c0rner%2Fghidra_wpc_loader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c0rner%2Fghidra_wpc_loader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/c0rner","download_url":"https://codeload.github.com/c0rner/ghidra_wpc_loader/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c0rner%2Fghidra_wpc_loader/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33975476,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-06T02:00:07.033Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["6809","ghidra","pinball","reverse-engineering","romhacking"],"created_at":"2026-04-03T03:23:39.916Z","updated_at":"2026-06-06T09:01:04.812Z","avatar_url":"https://github.com/c0rner.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WPC Loader — Ghidra ROM Loader for Williams Pinball Controller\n\nA [Ghidra](https://ghidra-sre.org/) extension that loads Williams Pinball Controller (WPC)\ngame ROMs and builds a complete, navigable memory map — including banked ROM overlays,\nASIC I/O registers, interrupt vectors, and OS-level RAM symbols.\n\n---\n\n## Overview\n\nWPC pinball machines (1990–1999) use a **Motorola 68B09E** CPU running at 2 MHz with a\n64 KB address space. Game ROMs come in four sizes: 128 KiB, 256 KiB, 512 KiB, or 1 MiB,\ndivided into 16 KiB pages that are bank-switched into the CPU window at `0x4000–0x7FFF`\nvia the `WPC_ROM_BANK` hardware register (`0x3FFC`).\n\nThe loader covers all six WPC hardware generations:\n\n| Generation | Years | Key hardware |\n|---|---|---|\n| WPC Alphanumeric | 1990–1991 | 14-segment displays, separate sound board |\n| WPC DMD | 1991–1993 | 128×32 dot-matrix display |\n| WPC Fliptronic | 1993–1994 | Dedicated flipper board |\n| WPC DCS | 1993–1995 | High-fidelity DCS audio board |\n| WPC Security | 1994–1996 | Security PIC chip in switch matrix path |\n| WPC-95 | 1995–1999 | FPGA-consolidated boards, extra RAM bank-switching |\n\n---\n\n## Memory Map\n\nThe loader creates the following Ghidra memory blocks:\n\n| Block | Address range | Size | Permissions | Volatile | Description |\n|---|---|---|---|---|---|\n| `RAM` | `0x0000–0x1FFF` | 8 KiB | R/W | No | Battery-backed SRAM |\n| `RAM_EXT` | `0x2000–0x2FFF` | 4 KiB | R/W | No | Extra RAM — DCS / WPC-95 *(optional)* |\n| `DMD` | `0x3000–0x3BFF` | 3 KiB | R/W | **No** | DMD display SRAM windows — see note |\n| `IO` | `0x3C00–0x3FFF` | 1 KiB | R/W | **Yes** | WPC ASIC hardware registers |\n| `ROM_PAGE_XX` | `0x4000–0x7FFF` | 16 KiB | R/W/X | No | Banked ROM overlay — see note |\n| `ROM_SYSTEM` | `0x8000–0xFFFF` | 32 KiB | R/W/X | No | Fixed system ROM — see note |\n\n### Block notes\n\n**`DMD` — R/W, non-volatile**\n\nThe DMD controller board has 8 KiB of SRAM holding up to 16 bit-planes (512 bytes each).\nThe CPU maps up to two pages at a time into the `0x3000–0x3BFF` window and has full R/W\naccess to them. Critically, the DMD controller **cannot autonomously write** to these RAM\npages — it only reads from them to refresh the display. This means the block is *not*\nvolatile from Ghidra's perspective: the CPU is the sole writer, and a value written will\nread back unchanged until the CPU changes it again.\n\n**`ROM_PAGE_XX` — R/W/X, non-volatile overlays**\n\nThe WPC ASIC does not physically write-protect the ROM window. The CPU can and does write\nto `0x4000–0x7FFF`, typically to patch self-modifying trampolines or update code vectors\nin-place. However, these writes affect only the currently mapped page in the ASIC's bus\nlogic — they are **not persisted to the ROM chip**. When a different page is banked in and\nthe original page is later restored, all writes are gone. Each Ghidra overlay block models\na single bank-in snapshot; cross-bank write effects are not represented.\n\n**`ROM_SYSTEM` — R/W/X**\n\nThe system ROM at `0x8000–0xFFFF` mirrors the behaviour of the hardware: the WPC ASIC\ndoes not enforce read-only protection on the fixed ROM window, so the CPU can issue write\ncycles to this region. In practice the writes have no lasting effect (the ROM chip ignores\nthem), but marking the block writable prevents Ghidra from flagging legitimate write\ninstructions as analysis errors.\n\n### Banked ROM page numbering\n\nWPC hardware page numbers are counted from the **top** of the address space downward.\nThe last two pages (`0x3E`, `0x3F`) are permanently visible in the system ROM window\n(`0x8000–0xFFFF`) and are not overlaid. For a ROM of *N* total 16 KiB pages, banked\npage index *b* gets hardware page number `0x3F − (N − 1 − b)`:\n\n| ROM size | Total pages | Banked overlay range |\n|---|---|---|\n| 128 KiB | 8 | `ROM_PAGE_38` – `ROM_PAGE_3D` (6 pages) |\n| 256 KiB | 16 | `ROM_PAGE_30` – `ROM_PAGE_3D` (14 pages) |\n| 512 KiB | 32 | `ROM_PAGE_20` – `ROM_PAGE_3D` (30 pages) |\n| 1 MiB | 64 | `ROM_PAGE_00` – `ROM_PAGE_3D` (62 pages) |\n\n---\n\n## Labels Applied\n\n### I/O registers (`0x3FB8–0x3FFF`)\n\nAll documented WPC ASIC and peripheral registers are labelled, including:\n\n- `WPC_ROM_BANK` — bank-switch register\n- `WPC_ZEROCROSS_IRQ_CLEAR` — IRQ source / watchdog kick\n- `WPC_LEDS` — diagnostic LED\n- `WPC_SOL_*` — solenoid driver outputs\n- `WPC_LAMP_*` — lamp matrix row/column\n- `WPC_SW_*` / `WPCS_PIC_*` — switch matrix inputs (pre-Security / WPC-S)\n- `WPC_DMD_*` — DMD page select and scanline registers\n- `WPC_SHIFTADDR` / `WPC_SHIFTBIT` — hardware bit-shifter\n- `WPC_RAM_LOCK` / `WPC_RAM_LOCKSIZE` — RAM write-protect\n- `WPC_CLK_*` — real-time clock\n- `WPCS_DATA` / `WPCS_CONTROL_STATUS` — sound board\n- `WPC_FLIPTRONIC_PORT_A` — flipper coil/switch I/O\n- `WPC95_FLIPPER_*` — WPC-95 flipper registers\n- `WPC_ROM_CHECKSUM` / `WPC_ROM_CHECKSUM_DELTA` — checksum fields\n\n### Interrupt vectors (`0xFFF0–0xFFFE`)\n\nEach 6809 vector slot is typed as a `Pointer16`, labelled (`VEC_RESET`, `VEC_NMI`,\n`VEC_SWI`, `VEC_IRQ`, `VEC_FIRQ`, `VEC_SWI2`, `VEC_SWI3`, `VEC_RESERVED`), and a\nGhidra function (`\u003cname\u003e_ISR`) is created at its target address.\n\nThe reset vector target is also registered as the program **entry point**.\n\n### RAM symbols (`0x0000–0x03FF`)\n\nAround 50 OS-level symbols from WPC reverse-engineering work, including threading\nvariables, lamp matrix buffers, solenoid enable shadows, IRQ counters, and DMD ISR state.\n\n---\n\n## Loader Options\n\nTwo options appear in Ghidra's import dialog:\n\n| Option | Default | Description |\n|---|---|---|\n| **Create banked ROM overlays** | ✅ On | Creates one `ROM_PAGE_XX` overlay block per banked page |\n| **Create extended RAM block (DCS/WPC-95)** | ✅ On | Creates the 4 KiB `RAM_EXT` block at `0x2000` |\n\nDisable the overlays for a quick analysis pass on the fixed ROM only.\n\n---\n\n## ROM Validity\n\nThe loader accepts files whose size is exactly one of the four valid WPC ROM sizes\n(128 KiB, 256 KiB, 512 KiB, 1 MiB). After loading, the message log reports the ROM\nversion number (decoded from the low byte of the checksum word at `0xFFEE`) and\nwhether the checksum is disabled (`delta = 0x00FF`, development mode).\n\n---\n\n## Requirements\n\n| Requirement | Version |\n|---|---|\n| [Ghidra](https://ghidra-sre.org/) | **12.0.4** |\n| Java | 21 (bundled with Ghidra) |\n\n---\n\n## Building\n\nUse gradle that is bundled with Ghidra\n\n**1. Set your Ghidra installation path**\n```bash\nexport GHIDRA_INSTALL_DIR=/path/to/ghidra_12.0.4_PUBLIC\n```\n\n**2. Compile:**\n\n```bash\n/path/to/ghidra_12.0.4_PUBLIC/support/gradle/gradlew\n# → dist/ghidra_12.0.4_PUBLIC_\u003cdate\u003e_WPCLoader.zip\n```\n\n**3. Install in Ghidra:**\n\nIn Ghidra's project manager: *File → Install Extensions* → select the zip from `dist/`.\nRestart Ghidra when prompted.\n\n---\n\n## Usage\n\n1. Open Ghidra and create or open a project.\n2. Drag a WPC ROM file (`.bin`, `.rom`, or any extension) onto the project window,\n   or use *File → Import File*.\n3. Ghidra will auto-detect the WPC format via the file size check and propose\n   **WPC ROM Loader** with `6809:BE:16:default` (Motorola 6809, big-endian).\n4. Adjust the import options (overlays, extended RAM) as needed, then click **OK**.\n5. Open the imported program in the CodeBrowser and run **Auto Analyze** to disassemble\n   the system ROM. Each banked overlay can be analysed separately.\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc0rner%2Fghidra_wpc_loader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fc0rner%2Fghidra_wpc_loader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc0rner%2Fghidra_wpc_loader/lists"}