Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cdi-merlinsapprentice-doc

Reverse-engineering notes on Merlin's Apprentice (Philips Interactive Media of America, 1995) — a CD-i puzzle game designed and directed by Cliff Johnson, the author of The Fool's Errand, and the only CD-i title he made.

This repository documents the European pressing: one CDI/2352 track of 131,610 sectors, 29:14, 39.5 % of a CD, holding eighteen files in a flat root — and, in among them, the linker's symbol file for the shipping build.

Documentation only. No game assets, no extracted images, no audio, no executable code is committed here. The tools in tools/ reproduce every figure, table and claim in these pages from your own legally obtained copy.

What is documented

Doc Contents
00-overview.md The release, the disc, and where 309 MB goes
01-disc-image.md The track, and 5.2 MB of speech in front of the file system that a 1995 disc shares byte for byte with two 1993 ones
02-filesystem.md Green Book descriptor, eighteen entries, SCCS keywords, and a 39-person credit roll
03-executable.md cdi_merlin: one CRC-clean module whose first instruction proves the symbol file
04-symbol-table.md cdi_merlin.stb — 887 named symbols, shipped by accident
05-bolt-library.md BOLT: 129 groups, 7,703 members, mapped to the byte, and a compressor that barely compresses
06-realtime-files.md Eight streams, 89 animations, and the 472-byte table that indexes them
07-audio.md Level B ADPCM, an eight-channel jukebox the code calls a jukebox, and the one stereo animation
08-game-architecture.md Eight engines, 27 named puzzles, three potions, the save format, and a cheat flag
09-leftovers.md The archaeology: a symbol table, a Traffic Cop, a Kludge, and fourteen diagnostics that shipped
10-open-questions.md What is measured, what is inferred, and what did not resolve
notes/file-inventory.md All eighteen entries, the sector budget, and all 89 animations
notes/symbol-inventory.md All 887 symbols in address order, by section
notes/bolt-inventory.md The BOLT header, all 129 groups, all 49 member ids
notes/string-inventory.md Every readable string in the executable, grouped
cdi-platformnotes-doc Platform checklist — what to look for on any CD-i disc. Shared by every CD-i pipeline; this repo links it rather than forking it

Highlights

The Microware linker's symbol file is on the retail disc. cdi_merlin.stb, 19,752 bytes in the root, is an OS-9 Data module holding the complete global symbol table of the shipping build: 887 symbols with their source-level names, covering the game, BOLT, the Microware C library and the OS-9 system-call library. Nothing on the disc references it and the program never opens it. The timestamps say it was not an oversight from an earlier build — it is one second older than the executable and two seconds older than the volume descriptor:

1995-01-31 13:57:18   cdi_merlin.stb
1995-01-31 13:57:19   cdi_merlin
1995-01-31 13:57:20   the volume descriptor

The address model is addr = (hi << 16) | value, and three independent checks settle it: btext0x00000000, etext0x0002196a which is M$Size to the byte, and _cstart0x00000054 which is M$Exec to the byte. Of the 576 code symbols, 452 land on a C-compiler prologue.

The whole game falls out of it. Intersecting symbol addresses with string offsets recovers eight puzzle engines and every puzzle in each:

engine puzzles
SoundChallEngine Pond, Flasks, Stalac(tite)
FragChallEngine Mirror, Plaque, Octagon, Tile
ArcadeChallEngine Seeds, Leaves, Bubbles, Snowflak(e), Gems, Demons
CodeChallEngine Grave, Parch(ment), Tablet
MorphChallEngine Window, Star
AlignChallEngine Planet, Door, Sphere
JumbleChallEngine Raven, Leaf, Snake, Skeltn, Spider, Quartz
PotionChallEngine Forest, Labrat, Cavern

27 puzzles and 3 potions — exactly what the disc's own abstract.txt promises. There is also a BOSS_GetCheatMode / BOSS_SetCheatMode pair, built with the same verbs as BOSS_GetDiffLevel / BOSS_SetDiffLevel.

The engine names itself three times over. BOLT in ASCII at byte 0 of boltlib0.blt; InitBOLT, OpenBOLTLib, GetBOLTGroup, BOLTAllocType, Decompress in the symbol table; and in bibliography.txt, BOLT Engineering Support: David Todd, Ken Jordon. The container is mapped here — 129 groups, 7,703 members — and the map closes:

groups 129, members 7703, chain breaks 0
last group end 8007558  (header says 8007558)

Its compressor recovers 1.172 : 1 across 4.7 MB, which is 8 % of the library, on a disc using 39.5 % of a CD. The codec itself is not identified; what constrains it is written down in 10-open-questions.md.

"TC" is Traffic Cop. Forty symbols carry the prefix and nothing expands it — until you read the error strings, which say Traffic Cop Could Not Open Animation:%d. It is the streaming scheduler, and it reads a 472-byte table called tcanim.toc whose every byte is accounted for:

python tools/cditoc.py check
89 of 89 entries land on a channel-31 EOR sector

help.rtf is a jukebox, and the code says so. Eight audio channels whose first sectors are 24, 23, 22, 21, 20, 19, 18, 17 — a perfect round-robin, so switching between them costs no seek — carrying 25.2 minutes of narration in 43 records, of which the game plays one channel. The API is TC_Open_Jukebox, TC_Play_Jukebox_Selection, TC_Is_Jukebox_Playing. Link's disc does the same thing with the same channel count; there it had to be inferred from sector arithmetic, and here it has a name.

A 1993 artefact on a 1995 disc. Descramble the 2,250 sectors in front of the file system and the 5,229,000 bytes hash to a0ed87f2e98b43f91281d16390fb178b — byte-identical to the same region on Origami (Netherlands, 1993) and Link: The Faces of Evil (USA, 1993). Three discs, two continents, three unrelated development houses, and now two years apart. It is an artefact of the CD-i authoring chain, and nobody can hear it.

A libgcc-to-Microware thunk table. Five BRA.W instructions, four bytes apart, at 0x1d452:

__mulsi3    -> _T$UMul / _T$LMul      __umodsi3  -> _T$UMod
__udivsi3   -> _T$UDiv                __modsi3   -> _T$LMod
__divsi3    -> _T$LDiv

Every branch target is exactly the symbol its name calls for. Something in this build was compiled by a GCC-family compiler and shimmed onto the Microware runtime's arithmetic helpers rather than linked against libgcc.

Fourteen developer diagnostics shipped, including one that was column-aligned for a terminal that is not there:

BOSS_Init:  NumBitsPerVar = %d.  Should be 1,2,4, or 8.            -- using 8.

and a global named after the fact that the code around it is a kludge: KludgeTwoControllers.

One animation out of 89 is in stereo. Exactly 149 sectors on the disc carry coding 0x01; they are every fourth sector of one 7.9-second sequence in anims.rtf, which contains no mono audio at all. Everything else on the disc is Level B mono.

And the disc is unusually clean. No dangling path references, no all-zero files, no unused sectors between the path table and the tail, no MPEG, no abandoned localisation, and no personal data. What was cut from Merlin's Apprentice was cut before the final link.

Tools

Platform-general, carried between CD-i pipelines and unchanged here:

tool what it does
cdilib.py sector, subheader and directory primitives
cdifs.py list / map / extract the Green Book file system
cdihead.py the pre-file-system region: map, check, wav
os9mod.py OS-9/68000 module headers, parity and CRC
cdistrings.py filtered strings out of an executable
cdiaudio.py Green Book ADPCM decode

Written for this disc:

tool what it does
cdistb.py parse a Microware .stb symbol module — stats, list, groups
cdibolt.py parse a BOLT library — header, groups, members, ids, check
cditoc.py parse tcanim.toclist, and check it against the disc
cdirtf.py real-time census — census, records, sizes

cdistb.py should work unmodified on any Microware .stb; the other three carry this title's tables and are worth reading rather than running elsewhere.

Point them at your own dump:

export CDI_BIN="/path/to/Merlin's Apprentice (Europe).bin"
python tools/cdifs.py list
python tools/cdifs.py extract _work/files
python tools/cdistb.py list
python tools/cditoc.py check
python tools/cdibolt.py check
python tools/cdirtf.py census

cdilib.py defaults to Merlin's Apprentice (Europe).bin in the repository root; CDI_BIN overrides it.

Related

About

Reverse-engineering notes on Merlin's Apprentice (Philips CD-i, 1995): the linker symbol file that shipped on the retail disc, the BOLT asset container mapped to the byte, and the 27 named puzzles it gives up.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages