92 lines
6 KiB
Markdown
92 lines
6 KiB
Markdown
# Modem Wars (Commodore 64, 1988) - annotated disassembly
|
|
|
|
A complete, reassemblable, commented disassembly of Dan Bunten's *Modem Wars* (Ozark Softscape /
|
|
Electronic Arts, 1988) produced from the disk image `Modem_Wars_1988_Electronic_Arts_b4.d64`.
|
|
|
|
* `docs/overview.md` - how the disk is organised, how the game boots, the fast-loader protocol, the
|
|
sector cipher, the run-time memory map and the overlay system. Start here.
|
|
* `docs/knowledgeBase.md` - every routine and data block with its purpose (generated from the
|
|
survey pass of the annotation work).
|
|
* `docs/titleScreen.png`, `docs/screenshots/` - the loader's title picture decoded straight from the
|
|
disk bytes, and screenshots taken by driving the game in VICE
|
|
(`extracted/vice/playSession.py` boots it on a private X display and feeds it real key events).
|
|
* `docs/track1_DanBuntenLetter.txt` - the letter to pirates that is hidden in plain text on track 1.
|
|
* `disassembly/` - the sources:
|
|
* `boot/` - the two directory files (`ea`, `load`), the C128 boot sector and its CBM80 stub, and
|
|
the title-picture data;
|
|
* `drive/` - the code that runs inside the 1541 (bootstrap sector and fast loader / cipher);
|
|
* `game/` - the game itself: main program, every overlay variant, data blocks;
|
|
* `c64.inc`, `kernal.inc`, `drive1541.inc`, `zeropage.inc`, `drive_zp.inc` - symbol files;
|
|
* `XREF.txt` - cross reference (callers, readers, writers) for every label and zero-page location;
|
|
* `INDEX.txt` - one line per source file with its address range;
|
|
* `verify.sh` - reassembles every file with `ca65`/`ld65` and compares it byte for byte with the
|
|
bytes extracted from the disk.
|
|
* `extracted/` - raw and decrypted sectors, the directory files, the reconstructed memory images and
|
|
the VICE automation used to validate them.
|
|
* `annotations/` - the comment/label database (JSON) that `tools/build.py` merges into the sources.
|
|
* `tools/` - the disassembler pipeline:
|
|
* `build.py` - rebuilds the whole of `disassembly/` from the decrypted sectors plus `annotations/`;
|
|
* `m6502.py` / `discover.py` - instruction decoder, recursive-descent tracer, and the discovery
|
|
pass that follows interrupt vectors and self-modified jump tables into code the tracer alone
|
|
cannot reach;
|
|
* `render.py` - turns a traced memory image into annotated ca65 source (bit art for graphics,
|
|
grids for tables, per-file table of contents);
|
|
* `findStrings.py` - finds the bit-7-terminated message strings still sitting in data areas;
|
|
* `chunks.py`, `mergeSurvey.py`, `extractAssets.py`, `hwSymbols.py` - supporting tools;
|
|
* `phase2_annotate.js`, `phase3_finish.js` - the multi-agent passes that produced the comments.
|
|
|
|
The listing is never edited by hand. Everything a human contributed lives in `annotations/*.json`
|
|
(labels, comments, data types, zero-page names) and `tools/build.py` regenerates `disassembly/` from
|
|
the decrypted sectors plus those annotations, so the sources can always be reproduced from the disk.
|
|
|
|
## What is in the disassembly
|
|
|
|
24 source files, 56,000 lines, covering 74,741 bytes: the C128 boot sector and its C64 cartridge
|
|
stub, both directory files, the code that runs inside the 1541 drive, the main program, every
|
|
overlay variant, and all of the data. About 65% of those bytes are code and the rest data.
|
|
|
|
* **Every one of the 21,627 instructions carries a comment** explaining what it is for, not what the
|
|
mnemonic does.
|
|
* Every routine has a header giving its purpose, its inputs, its outputs and its callers, and every
|
|
source file opens with a table of contents.
|
|
* All 164 zero-page locations the game uses are named and described, as are the work-RAM variables,
|
|
the unit record arrays and the hardware registers.
|
|
* Data is rendered as what it is: character and sprite graphics as bit art, tables as rows of the
|
|
right width, strings as text, jump tables as address lists.
|
|
* `verify.sh` reassembles all 24 files with `ca65`/`ld65` and compares each against the bytes taken
|
|
off the disk. All 24 match exactly, so nothing in the listing is guesswork about the bytes.
|
|
|
|
## Rebuilding and verifying
|
|
|
|
```
|
|
python3 tools/build.py # regenerate disassembly/ from extracted/ + annotations/
|
|
./disassembly/verify.sh # reassemble everything and compare with the original bytes
|
|
```
|
|
|
|
Requires Python 3 and the cc65 tool chain (`ca65`, `ld65`).
|
|
|
|
## Conventions used in the listings
|
|
|
|
* Every instruction line ends with `; XXXX` - its address - followed by the comment.
|
|
* Labels are camelCase; `sub_XXXX` / `L_XXXX` / `D_XXXX` are auto-generated names for code and data
|
|
that has not (yet) been given a meaningful name.
|
|
* Labels are scoped to a source file. The `$6F00-$87FF` and `$E000-$EFFF` regions exist in two
|
|
variants each; when code in one file calls into such a region the name of the variant that really
|
|
contains code at that address is used, and the other variant's name is mentioned in the comment.
|
|
* Strings end with a character whose bit 7 is set and are written as `.byte "TEXT",'T'|$80`.
|
|
* Hardware registers use the names from `c64.inc` (`VIC_*`, `SID_*`, `CIA1_*`, `CIA2_*`).
|
|
|
|
## SwiftLink driver
|
|
|
|
`swiftlink/` holds an alternate opponent module that drives a **SwiftLink cartridge** (a 6551 ACIA on
|
|
the expansion port) instead of the shipped module's bit-banged user-port UART, so the game can play
|
|
over a modem or a null-modem cable at up to 38400 baud instead of 300/1200. The shipped module is
|
|
layered and only its bottom layer is hardware specific, so the packet layer, the ARQ frame layer, the
|
|
ring buffers and the link state machine are left byte-for-byte alone: 434 of the module's 4096 bytes
|
|
changed, every routine kept its address, and a SwiftLink player and a stock-driver player can still
|
|
play each other at a shared rate.
|
|
|
|
`./swiftlink/build.sh` assembles the module and writes `Modem_Wars_SwiftLink.d64`, a copy of the game
|
|
disk that differs from the original in four sectors. See `swiftlink/README.md` for the hardware it
|
|
expects, the baud and hot-key tables, the direct-connect mode, the address-by-address map of what
|
|
changed, and an honest account of what the VICE testing did and did not prove.
|