Reverse-engineering notes on Microcosm (Psygnosis, 1994) for the
Amiga CD32 — a game that spends 92 % of its data track on a single file,
streams 30,707 frames of video off the CD with the console's own CD_READXL
mode, checksums every one of them to the ASCII string 'COSM', and decodes them
straight into eight AGA bitplanes without a chunky pixel anywhere in the
pipeline.
This repository documents the Psygnosis release: one MODE1/2048 track of
255,552 sectors and one 203-second Red Book audio track that nothing on the
disc ever plays; 34 files; a five-byte boot script; and an executable that
still carries the names of all 77 of its assembler source files.
Documentation only. No game asset, no extracted art, no audio, no
executable code is committed here. The tools in tools/ reproduce
every figure and table in these pages from your own legally obtained copy.
| Doc | Contents |
|---|---|
| 00-overview.md | The disc in one table, and what is actually on it |
| 01-disc-and-filesystem.md | A retail disc whose volume is called CDTV_TEST, and 15,000 sectors of nothing |
| 02-timestamps.md | A master stamped 1978 over files stamped 1994, and a 66-second build log |
| 03-boot-and-loader.md | Five bytes of boot script, AmigaDOS used exactly once, and two assets marked absent |
| 04-source-map.md | 77 source file names recovered from the debug hunks |
| 05-cbmbuild-container.md | 483 MB, 30,707 frames, 261 movies, and a checksum that spells COSM |
| 06-video-codec.md | Twelve opcodes, three sub-streams, and a decoder that alternates scan direction |
| 07-akiko.md | AKIKO measured to zero, and the mechanical reason why |
| 08-graphics-aga.md | 24-bit AGA palettes loaded entirely from the copper, and no graphics.library call after LoadView(NULL) |
| 09-audio.md | Thirteen tracker modules, four IFF files that name their own tool, and an unused CD track |
| 10-input-and-saves.md | All seven pad buttons, and ten bytes of NVRAM under MCOSM/core |
| 11-archaeology.md | The archaeology |
| 12-open-questions.md | Eleven things unresolved, with the measurement beside each |
| notes/file-inventory.md | All 36 directory records with LBA, size, timestamp and SHA-1 |
| cd32-platformnotes-doc | Platform checklist — what to look for on any CD32 or CDTV disc. Shared by every Amiga CD pipeline; this repo does not keep a copy |
Raw tool output — the ISO listing, the entropy census, the sector map, the
timestamp log, the module map, the container scan, the 261-movie table, the
copper lists, the CDXL cost comparison, the game text, the module and sample
names — is in notes/.
The volume identifier on this retail disc is CDTV_TEST. Every other
free-text field in the primary volume descriptor is empty, including the data
preparer, which on the other discs in this pipeline names a person. Nothing
noticed, because nothing needs it: the boot script names cosm with no path and
cosm reaches every file through cd0:, the device, not the volume.
The 483 MB video file is called cbmbuild. CBM is Commodore Business
Machines. The credits screen thanks COMMODORE and, one line above it,
SILICON GRAPHICS — which is the only trace on the disc of where 30,707 frames
of pre-rendered flight came from.
The loader carries two assets that do not exist and knows they do not.
cd0:briefing.code/.data and cd0:eolb4.code/.data sit in the shipped file
table with a presence flag of 0, and the loader tests the flag and skips the
Lock. There is no fourth end-of-level boss — the disc has eolb1, eolb2,
eolb3 and eolb5 — but cosm still contains LEVELS/EOLBDIE4.S,
LEVELS/EOLBTWEEN4.S and LEVELS/EOLBKILLYOU4.S with real code in them. And
the build log shows no pause where eolb4 would have been written: it was never
built, not built and dropped.
Every frame header on the disc sums to 'COSM'. CDCODE/CDXLINT.S — the
interrupt cd.device calls at each streaming block boundary — does
d0 = 'COSM' and seventeen sub.l (a0)+,d0, and rejects the block unless the
result is zero. Each chunk header gets the same treatment, and so does a prefix
of each chunk's payload. Verified across all 30,707 frames: zero failures.
AKIKO is not touched, and the reason is structural. Zero occurrences of
$00B80038 in 9.5 MB of code across 33 executables and overlays. The decoder in
DECRUNCH/DECRUNCHER.S writes planar bitplanes directly — ten unrolled
move.l (a3)+,(a0)+ per row, a 40-byte stride, and +0x1680 = 5,760 = 40 × 144
at the end of each plane. There is no chunky pixel in the pipeline to convert:
the conversion happened once, offline, on the Silicon Graphics machines that
rendered the film.
Commodore shipped a format for this and it would not have fitted. CDXL is uncompressed, so a frame costs the same whatever is in it: these 30,707 frames at 320 x 144 in 256 colours come to 1,349 MB, more than two CDs, and cap out at 6.67 fps on a 2x drive against the in-house codec's 19.57. Even the geometry Prey CD32's real CDXL stream used — 240 x 96 at 7 planes — is 590 MB for this much footage. The reason the in-house codec wins is variance rather than cleverness: 9.1 % of frames cost under 5,000 bytes and the smallest is 364, while the worst costs 40,224 — 87.3 % of raw, a ratio of 1.15:1. A fixed-size container cannot spend its budget where the picture is.
The executable still has its whole source tree in it. 77 HUNK_DEBUG
blocks name every assembler file and where its code starts:
CDCODE/CDXLINT.S, FRAMEHANDLERS/INTERACTIVE256.S,
COPPER/DOUBLEEBITCOPPERLIST.S, MAIN/PT_RBFINTERRUPT.S,
LEVELS/EOLBKILLYOU5.S, and 72 more. The largest of them,
CDCODE/FILELIST.S, is a 3,444-line generated table occupying 56.6 % of all
the code in the program, and its generator's two stub files —
/filelist.i and /filelist.s, eleven bytes each, containing their own names —
are still in the disc's root.
The retail build ships its debug console, and it is the only error message the
game has. DEBUG/PRINT.S, DEBUG/NUM.S, DEBUG/DEBUGCOPPERLIST.S and
TASKS/CONSOLETASK.S are all linked in; the one-bitplane debug copper list is
the one cosm installs at start-up; and the string internal hardware error
appears 195 times across the executable and the overlays. A missing library,
a drive that will not report double speed, a short read, a bad checksum — all of
them print those three words in a debug font and stop.
freeanim.library is opened and closed four instructions apart, with nothing
in between. That open/close pair is the documented CD32 way to dismiss the boot
animation — the open starts the fade, the close waits for it — and the interval
between them is where a title is supposed to initialise. Microcosm has already
finished initialising by the time it gets there, so the boot animation is given
no time at all.
A 203-second Red Book music track that nothing plays. It is finished music —
continuous to 195 s, then a clean fade — and no CD_PLAYTRACK, CD_PLAYMSF or
CD_PLAYLSN is issued anywhere on the disc. A CD32 has one mechanism and
Microcosm streams video off it essentially all the time.
The palette test comes back "neither", and the copper answers instead. There
is no LoadRGB4 and no LoadRGB32 call in the program — after LoadView(NULL)
and two WaitTOF()s, graphics.library is never used again.
COPPER/COLOURCOPPERLIST.S writes 256 colour registers twice, cycling
BPLCON3 through all eight banks with LOCT clear and then set: a genuine
24-bit AGA palette, 512 copper MOVEs, loaded without the OS.
Two development tools named themselves in the shipped data. Four sound
effects were embedded as complete IFF 8SVX files rather than as raw samples, so
their ANNO chunks survived: carpast3.raw and exec10b.raw say
AudioMasterIV, and redalert.iff and alarmlo.iff say Audio Engineer.
A cheat page with its own threat. waystat.code contains a fifth
mission-overview screen numbered zero: "SO YOU FOUND THE CHEAT MODE DID YOU.
WELL DONE BUT I'M AFRAID IF YOU WANT TO CHEAT THEN I'M GOING TO SUCK THE COLOUR
FROM THE NICE GRAPHICS." The 256-colour frame handler has 32-, 64- and
128-colour siblings and the palette handler has a blanking flag, so it is
probably not a bluff.
The disc answers the pipeline's standing question about disc occupancy, and the answer is not the obvious one. Microcosm spends 86 % of the whole disc on video — but the game, code and data and boot script together, is 9.1 MB, which sits squarely inside the 2.7–13.3 MB band every other CD32 disc in this series occupies. The band held for an eighth disc. What is different is that the thing filling the disc is the content the player is playing through rather than a soundtrack laid beside it.
Python 3, no dependencies except capstone for the disassembler helper.
| Tool | What it does |
|---|---|
isolist.py |
Walks the ISO 9660 tree, prints the PVD, writes _work/tree.json |
isoextract.py |
Extracts every file with its SHA-1 |
inventory.py |
Writes notes/file-inventory.md |
census.py |
Entropy, first longword vs file size, last non-zero byte |
sectormap.py |
Sector map against the declared volume, and the occupancy split |
timestamps.py |
The directory sorted by time, as a build log |
strs.py |
Printable runs with file offsets (no strings needed) |
hunk.py |
AmigaDOS hunk reader; lists the HUNK_DEBUG blocks |
modmap.py |
Decodes the HCLN line tables into the 77-module source map |
m68k.py |
Capstone M68K disassembly with the raw bytes beside every line |
copper.py |
Decodes a copper list out of the chip DATA hunk |
animwalk.py |
Walks the chunk stream of cbmbuild from a given offset |
animscan.py |
Full structural scan: frames, chunk vocabulary, size distribution |
animseq.py |
Segments cbmbuild into its 261 movies |
cosmsum.py |
Verifies the 'COSM' header checksum over every frame |
datalumps.py |
Reads the lump directory of each .data overlay, detects modules |
iffscan.py |
Finds embedded IFF 8SVX headers and their NAME/ANNO chunks |
cdxlcost.py |
What the same footage would have cost in CDXL |
gametext.py |
Pulls the readable game text out of the overlays |
platsweep.py |
Checklist step 15: traces of the game's other releases |
Run them from the directory holding the disc image:
python tools/isolist.py .
python tools/isoextract.py .
python tools/census.py .
python tools/animscan.py
A note on the disassembly: Capstone's M68K backend prints plausible but wrong
constants on this code. Every immediate, displacement and absolute address
quoted in these documents was re-read from the raw bytes, which is why
tools/m68k.py prints the instruction bytes beside every line.