Structural documentation of the Amiga CD32 release of Superfrog, a 2D platform game published by Team 17 — and of the two playable demos and the bespoke front-end menu that share the master with it.
Documentation only. No game code, artwork, audio, text or other asset is
committed here — the tools in tools/ reproduce every figure and
table in these documents from a disc image you supply. The manual scripts are
described by their grammar and never reproduced as prose.
This is the sixteenth disc in a running Amiga CD32 / CDTV series. The shared checklist those discs feed is cd32-platformnotes-doc.
CATALOG 5022358170384 (a real EAN-13)
TRACK 01 MODE1/2048 4,164 sectors declared, 4,194 in the image
no audio track, nothing else in the cue sheet
221 files, 22 directories, 8,589,312 bytes — 1.26 % of a CD, and with no Red Book audio the occupancy figure is the content.
volume identifier SuperFrog_AGA
publisher identifier Team 17
data preparer Kenny Grant - ISOCD 1.04 by Pantaray, Inc. USA -
application identifier s/startup-sequence
system identifier CDTV
creation date 1994-08-24 12:17:15 +0
Version T17MENU 39.1 Kenny G (23.07.94), from the front end's $VER: — the
game engine has no $VER: and no bare build banner. The disc names exactly one
person, Kenny Grant, and names him twice: in the ISO preparer field and as
the author of the menu program. Nobody who wrote the game is credited anywhere
in the filesystem.
All of that read off the disc, none of it taken on trust.
It is not one game. Superfrog is 50.5 % of the bytes; a Super Stardust demo is 39.6 %, an Arcade Pool demo 7.4 %, and the system tree 2.5 %. That matters for every size figure in these documents and it is why the band question below has an answer at all.
The band's ceiling breaks — on one of its two readings, and not the other. Superfrog alone is 4,102,748 bytes on disc and 13,336,690 resident after every container is expanded at every depth. That is 84,993 bytes and 0.64 % above Marvin's 13,251,697, which had been the maximum across fifteen discs. Read on disc it is 4.10 MB and sits comfortably inside the 2.25–13.3 MB band. So the two readings now return different verdicts about the same disc for the first time. The checklist already says the band is coherent only as an on-disc measurement; this is the disc where obeying that rule changes the answer instead of merely tidying it. Both figures are kept, neither is averaged. → docs/05-compression.md
The cruncher follows the label; the mastering tool does not — and the disc
supplies the mechanism. Two predictions were written before either was
measured, deliberately pointing opposite ways. Superfrog packs with the
Imploder, like The Speris Legacy, the other Team 17 disc — and the
decruncher transcribed from Speris's own shipped 68000 routine, reused here
unmodified, decodes all 96 files exactly. But Superfrog's .TM block is
byte-identical to the twelve discs cut with the same tool and not to Speris's.
Both predictions came out as written. The mechanism is on the disc: the preparer
field names Kenny Grant and s/T17Menu's $VER: names Kenny G as the menu's
author, so the person who cut the master and the people who wrote the game are
demonstrably different hands — which is why the artefacts they each produce
can disagree. Open item 14's question had the wrong shape: build practice has no
single owner, and the owner is readable per artefact.
→ docs/11-label-comparison.md
The 1993 floppy release, recovered byte-exact from the CD binary.
SuperFrogCD carries four parallel vocabularies of the same 85 asset names —
SDDISK1:, DF0:, DF1:, DF2:. The union of the three floppy devices is
exactly the SDDISK1 set, zero difference in both directions, so the
disk-to-asset assignment of the earlier release is readable from the shipped CD
executable: disk 1 common, disk 2 worlds 1–3, disk 3 worlds 4–6 — with L1FX on
all three disks and L6ET/L6LP/L6MU on two, the floppy-era trick of
duplicating a small shared asset to avoid a swap. The disc never asks for a
floppy; it just still knows which one everything was on.
→ docs/10-floppy-ancestry.md
A fifth home for the music, and a M.K. scan cannot see it. Zero ProTracker
modules, zero OctaMED. 37 modules in The Player's own replayer format —
26 × P41A (Superfrog, Arcade Pool) and 11 × P40B (Super Stardust). The
format's four-byte magic is its version string, so it matches neither a tracker
scan nor a cruncher scan. The disc confirms the reading itself: a file named
P40.INGAME1 begins P40B. Eight of the 26 are one-to-four-sample modules
inside INTROC — sound effects written as tiny tracker tunes. Separately, 27 IFF
8SVX samples exist on this disc and all 27 are inside a binary, invisible
to a census over files.
→ docs/08-audio.md
A markup language, shipped in source with its comments. The four manual
files are not data — they are scripts for an in-house viewer, T17Man, in a
language with eleven directives, # comment banners, named asset bindings and a
font table. All twelve asset references resolve to files on the disc. And in
one language only, the English original, @SCREEN Money and its comment
banner are pasted twice: 13 @SCREEN against 12 @ENDSCREEN, so the file
runs one nesting level deep from line 160 to the end. French, German and
Italian are balanced. Four complete languages in correct ISO 8859-1 — every
accent right, nothing stripped or remapped.
→ docs/09-text.md
A build-machine assign in 26 shipped files. Every level map carries
@SDIFF:<level>-IFF at resident offset 0xAF, naming the IFF artwork it was
built from. SDIFF: is created by no script on this disc and none of the eight
targets shipped. The assign is spelled three ways across its 52 occurrences —
SDIFF 32, sdiff 10, Sdiff 10 — sometimes differently for the same target.
Two builds a byte diff calls unrelated. MAINDEMO1 and MAINDEMO2 share
zero end-aligned bytes and diverge at code offset 0x24. Mask the relocated
longwords and they agree for 6,083 bytes, then differ by one immediate:
#$0001 against #$0002. Method note for open item 23: mask the relocations
before diffing two builds. Separately, T17Man and T17Man.lace are both
24,172 bytes and differ in ten bytes across two runs — the $VER: date, and
one byte turning SA_DisplayID from $00029000 (PAL:HighRes) into $00029004
(PAL:HighRes-Interlaced). Neither is NTSC.
→ docs/06-executables.md
A ninth container format. Nine files begin PaCK. The 14-byte header is
proven on 9 of 9 — 14 + packed == filesize every time — and on the four with a
sibling in RAW/ the declared unpacked size equals that sibling's byte count
exactly. The codec is not decoded, so the honest claim is a ninth container,
not a ninth cruncher.
Step 36 has a second instance, on a different studio. TUNNELDEMO is
1,475,712 bytes of CODE hunk with 904 relocations — 0.63 per KB, seventy
times below this disc's own densest program, and all 904 fall in the first
2.51 % of the hunk. The remaining 1.44 MB is data in a code hunk, confirmed
independently by the 27 8SVX samples embedded in it. The diagnostic is the
ratio, not the magic.
Six planes with KILLEHB clear, on a volume named _AGA. Superfrog's own
display is 320×256 PAL, five bitplanes, 32 colours, with BPLCON3 written
only to safe defaults and FMODE never written in any validated copper list —
a display an ECS machine can show. The one six-plane list has BPLCON2 bit 9
clear, which makes it Extra-Half-Brite, i.e. ECS. The disc's actual AGA content
is next door: Arcade Pool has BPLCON0 $0210, which reads as zero
bitplanes to any scan that ignores BPU3 in bit 4 and is an eight-plane
256-colour screen — the third instance of that trap in the set.
→ docs/07-graphics.md
The root directory record is dated seven days before every file it indexes.
1994-08-17 16:41:45, stored identically in the PVD, in the extent's . entry
and in its .. entry, against an earliest file of 1994-08-22 12:13:39. All 21
subdirectories are dated with the files; only the root is old. The PVD itself is
25m22s newer than the newest file, so the usual comparison is normal. No disc
in the set has had this particular field checked, so there is no baseline — it
is open question 1 and it is now step 37.
→ docs/03-timestamps.md
- No Akiko. Zero pointer loads of
$00B80000,$00B80030,$00B80038,$00B8003C; zero$C0DE0000. All eightleaand all eightmovea.lencodings scanned. - No C2P. The six constants appear 42,017 times as data and 37 times as an immediate — and four of the six have zero immediates. What the 37 are is a two-bit interleave, shared code between Arcade Pool and Superfrog's loader.
- No save system.
nonvolatile.libraryships and no game binary opens it; no binary touches the EEPROM port either. Two independent measurements. - No bytecode VM. Instead a 64-way type dispatch over object records: five tables, 320 slots, 24 distinct handlers, one default taking 82.8 % of the slots.
- No little-endian IFF. 20
FORMs, all big-endian — a fair test, not a vacuous one. - No MS-DOS epoch. Zero 1980 and zero 1978 records. Two calendar days total.
- No empty directories, no byte-identical duplicate files, and no
.infofile shared with any disc in the set. - No disk-swap prompt, no installer, no
.bak. Unlike Gunship, the CD build removed every user-visible trace of the floppy release while keeping the internal path table intact.
| 00-overview.md | What the disc is, the offset convention, the document map |
| 01-disc-and-filesystem.md | PVD field by field, sector map, the 32-sector run, the third preparer pattern |
| 02-tm-block.md | The .TM block, and tool versus label |
| 03-timestamps.md | Two calendar days, three bursts, a root directory a week early |
| 04-boot-chain.md | All five scripts in full; the menu that writes its own script |
| 05-compression.md | 158 Imploder streams, depth 2, a ninth container, the band |
| 06-executables.md | Hunk structure, relocation density, the dispatch table, diffing two builds properly |
| 07-graphics.md | The display, stored copper lists, blitter geometry, tile layout, no C2P |
| 08-audio.md | No Red Book; 37 modules in a format the checklist had not seen |
| 09-text.md | Two denominators, four languages, a shipped markup language and a paste bug |
| 10-floppy-ancestry.md | The 1993 three-floppy layout, recovered exactly |
| 11-label-comparison.md | Superfrog against The Speris Legacy, row by row |
| 12-open-questions.md | Ten open items with measurements, and the predictions scorecard |
Stated in 00-overview.md and used throughout. Briefly:
- File offset — a position in a file as it sits in the ISO 9660 volume.
- Resident offset — a position inside a file after every container in it
is expanded. Resident pieces are named
<file>+s<offset>for a stream found at that offset and<file>+gap<offset>for raw bytes between streams, so an address is always attached to one named piece. - Hunk offset — a position relative to a hunk's image, which is what
LoadSegrelocates against. An absolute constant in a hunk executable is a hunk offset if a relocation covers it and a literal if not (tools/relocs.py --at).
Addresses are labelled where the kind is not obvious from context.
Every figure and table above is reproduced by these. Nothing is hand-counted.
| tool | what it does |
|---|---|
packscan2.py |
Codec-agnostic magic scan at every offset, validated by running the decompressor; reports nesting by depth and lists magic-shaped hits that did not decode |
band.py |
The three figures — on disc, resident at all depths, used — attributed per title, with the per-file slack breakdown |
unpackall.py |
Materialises the resident corpus, one file per resident piece, gaps kept |
census.py |
Size, SHA-1, magic, entropy; first-longword histogram; duplicates by content and same-name-different-content |
packheader.py |
The PaCK header, validated against RAW/ siblings |
embedscan.py |
Tracker / OctaMED / IFF magics at every offset with per-format validation |
playerscan.py |
Finds and validates The Player P41A / P40B modules |
c2pscan.py |
C2P constants counted as data and as instruction immediates, with mask-table hits classified out |
blitgeom.py |
Section 4's three questions; derives bitmap width from BLTSIZE + modulo |
copperscan.py |
Strict stored-copper-list finder; requires bitplane pointers, and reports how many candidates it rejected |
display.py |
BPLCON0 with the BPU3 bit; KILLEHB; AGA register census |
hunkinfo.py |
Hunk walk and relocation density per KB of code (step 36) |
jumptable.py |
Reads a bra.w run as a jump table; counts distinct targets and the default's share |
libscan.py |
Library and device names found by walking backwards from the NUL, with the rts low-byte stripped by an exact test |
strs.py |
Printable-run dump that documents and handles the 4E 75 = Nu trap |
textcensus.py |
Prose against both denominators, with the definition stated; byte-value encoding census |
manscript.py |
The T17Man script grammar, and whether every reference resolves |
levelhdr.py |
The SDIFF: build references and their letter case |
devpaths.py |
Device-qualified path census, grouped by device |
floppymap.py |
Recovers the floppy layout; diffs the device sets both ways |
speris_imp.py (the Imploder decruncher, from
cd32-thesperislegacy-doc —
transcribed there from Speris's own shipped routine and reused here with no
changes, decoding all 96 files exactly), isodump.py, akiko2.py,
relocs.py, dis68k.py, timeline.py, geomguess.py, iffle.py,
blitscan.py, lvoscan.py, dispatch.py, strdump.py, copperpal.py,
planar.py, picture.py, and the rest of the shared set.
The checklist's most expensive trap, and it fired again. Recorded so the next disc does not pay for it:
| tool | what it reports here | why it is wrong |
|---|---|---|
containers.py, unpackall.py (Universe versions) |
zero streams | they decode RNC method 1 only; this disc has no RNC at all and 158 Imploder streams. Not used. |
crm.py (from cd32-gloom-doc) |
0 decrunched, 2 failed |
its CrM! branch is the literal line raise NotImplementedError("CrM! stream: no file on the disc uses it") — true of Gloom, false here. Open question 2. |
display.py in copper-word mode, and any loose copper scanner |
179 BPLCON0 "copper writes" in SuperFrogCD, including $4E75 and $4EB9 |
those are rts and jsr. None of it is claimed. copperscan.py was written to replace it and accepts 35 lists where the loose scan finds thousands. |
| any printable-run dump | Nucd.device, ufreeanim.library, N]Nuscsi.device |
4E 75 is rts and reads Nu. libscan.py and strs.py handle it by an exact byte test, not a heuristic. |
ISO="Superfrog (1994)(Team 17)[!].iso"
python3 tools/isodump.py "$ISO" --extract _work/iso --json _work/iso.json
python3 tools/census.py _work/iso --csv _work/census.csv
python3 tools/packscan2.py _work/iso --depth 3
python3 tools/unpackall.py _work/iso _work/resident
python3 tools/band.py _work/iso --per-file
python3 tools/floppymap.py "_work/resident/SuperFrog_SuperFrogCD+gap0.bin"
python3 tools/copperscan.py _work/resident/*.bin --minlen 16
python3 tools/playerscan.py _work/resident
python3 tools/textcensus.py _work/iso --label "on-disc corpus"Generated output is committed under notes/ so the documents can be
checked without running anything.
Analysis and documentation only. Superfrog, Super Stardust, Arcade Pool and all their content are © their respective rights holders. Nothing from the disc is redistributed here — no code, no artwork, no audio, no level data, and no manual text beyond the short structural excerpts needed to describe the script grammar.