Getting started

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.

What you need

The ROM goes in the root, as mahjong.rom. It is exactly 32768 bytes:

sha256  24cb5bda5f55dcd5ab1343fb61ebac67e8c292f9714ee7a492431e33188b9b40

make comprueba checks it.

The commands

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

What is in each folder

src/mahjong.entriesthe entry points, each with its justification
src/mahjong.nocodethe ranges the tracer must not read as code
src/mahjong.notesthe only file edited by hand: every annotation
src/mahjong.asmthe 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

How to read the listing

The annotations are anchored to an address, so they survive a retrace. The directives follow theNestruo's guidelines:

La label and what the routine does
Ca comment on that line
Ba block header before that address
Da data range, with its name and its explanation
Fthe 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.

How it was done

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.

So that it can be repeated

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.