This repository holds a commented disassembly of Konami's Mahjong for the MSX (Konami, 1984, cartridge RC-707). Everything here comes out of the binary and can be generated from it again.
The ROM goes in the root, as mahjong.rom. It is exactly 32768 bytes:
sha256 24cb5bda5f55dcd5ab1343fb61ebac67e8c292f9714ee7a492431e33188b9b40
make comprueba checks it.
make listado # rebuilds src/mahjong.asm from the annotations
make verify # reassembles and compares with the ROM, byte for byte
make sanity # nothing declared as data may come out as code,
# and not one byte may be left unassigned
make notas # no dangling and no duplicated comment
make test # the checks
make densidad # how many instructions carry a comment, routine by routine
make capturas # redoes the web pictures with openMSX
make web # rebuilds this web
src/mahjong.entries | the entry points, each with its justification |
src/mahjong.nocode | the ranges the tracer must not read as code |
src/mahjong.notes | the only file edited by hand: every annotation |
src/mahjong.asm | the listing, generated by tools/mkasm.py |
tools/ | the tracer, the listing generator and the measuring tools |
tests/ | the checks on the listing and the annotations |
docs/ | this web |
The annotations are anchored to an address, so they survive a retrace. The directives follow theNestruo's guidelines:
L | a label and what the routine does |
C | a comment on that line |
B | a block header before that address |
D | a data range, with its name and its explanation |
F | the row width of a data block |
The 340 named routines are named after what they do, not after where they sit, and the 89 data blocks each carry a name, a size and the width of their rows, which is what lets you read them as tables instead of as a run of bytes.
The tracer follows the real flow from the entry points. Whatever cannot be worked out statically is declared by hand in the .entries, with the reason written next to it: the INIT vector from the header, the interrupt hook INIT writes into H.KEYI, and the thirty-two destinations of the dispatcher's five tables, which ends in jp (hl) and cannot be followed through.
That dispatcher also forces the opposite: the tables sit embedded right behind the call that invokes it, so those bytes are data even though they are in the middle of the code. They are declared in the .nocode, and make sanity checks that none of them is read as an instruction.
There is no assumption dressed up as a fact here. What is not known is in Open questions, and it says so.
make verify reassembles the listing and compares the result with the original ROM. It has to come out identical, byte for byte. And make sanity then checks what reassembling cannot catch: that no range declared as data is being read as code, and that not one of the 32768 bytes is left unassigned.
The pictures on this web are not made by hand either. make capturas boots the cartridge in openMSX with nothing being drawn, dumps video memory at fixed instants and builds the PNG from the dump; the first pass does not press a single key, because the demo plays itself.