Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cd32-guardian-doc

Reverse-engineering notes on Guardian (Acid Software, 1994) for the Amiga CD32 — a third-person polygonal shooter, mastered 1994-08-04, that fills its triangles with one Blitter cookie-cut per scanline straight into four interleaved bitplanes, drives a 24-bit per-scanline sky from a 7,144-byte copper list, reads all seven pad buttons on both ports with no lowlevel.library, and touches Akiko not at all.

This repository documents a 1,193-sector volume — 0.40 % of a CD, with 41.3 % given to twelve Red Book tracks — holding 61 files, none of them compressed; a 72-byte freeanim that is the smallest wrapper on the format; a startup-sequence.info and a setpatch that are byte-identical to Gloom's; a twelfth zone's worth of assets the shipped zone table cannot reach; and an A1200 floppy release 24 of whose data files are byte-identical to this disc's.

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

What is documented

Doc Contents
00-overview.md The disc in one table, and the hunk/file offset convention
01-disc-and-filesystem.md ISOCD 1.04, an empty preparer, the ninth identical .TM block, and no front gap
02-timestamps-and-dating.md A seven-second copy of 60 files, and one file from the MS-DOS epoch
03-boot-chain.md Three lines in the root, a .bak that names sw, and an icon shared with Gloom
04-executable.md 3 hunks, 5,113 relocations, nothing compressed — and nine RLE images inside the program
05-display-and-akiko.md Akiko measured to zero, eleventh of eleven; a six-plane panel over a four-plane 3D view
06-the-3d-engine.md One Blitter cookie-cut per polygon scanline, all four planes at once
07-data-formats.md The zone table, dither sheets, 4,096-entry 24-bit skies, sprite banks
08-audio.md Twelve Red Book tracks, every one reachable, played out of the disc's own TOC
09-input-and-saves.md Seven buttons, two ports, no lowlevel.library; a save that stores 8 and reads 80
10-two-releases.md 24 files byte-identical inside the A1200 data floppy, and what that says about compression
11-archaeology.md PIRATES FUCK OFF, a live hElP canary, a paint file, and a zone nobody can load
12-open-questions.md Twelve things unresolved, with the measurement beside each
notes/file-inventory.md All 61 files with LBA, size, timestamp, entropy, SHA-1 and A1200 match
cd32-platformnotes-doc Platform checklist — what to look for on any CD32 or CDTV disc. Shared by every Amiga CD pipeline in this series; this repository does not keep a copy

Raw tool output — the ISO listing, the sector map, the entropy census, the hunk and relocation tables, the register and LVO histograms, the copper list, the Akiko scan, the audio-track measurements, the floppy listings, the cross-release diff and the string dumps — is in notes/. The predictions written before any measurement are in notes/predictions.md, and doc 12 scores them.

Highlights

Akiko is zero, for the eleventh time — and this was the disc that should have used it

This pipeline writes its predictions down before it measures, and for the first time in eleven discs the prediction was positive: Guardian is CD32-first, it has a genuine real-time polygon renderer, and the argument that killed every earlier candidate ("the same binary has to run on an A1200") did not apply when the code was written.

                       $00B80038  $00B8003C  $C0DE0000  pointer loads
raw image                      0          0          0              0
all 61 extracted files         0          0          0              0

The prediction was wrong, and the reason is the interesting part. The question that matters is not "does it touch $B80000" but where does the frame end up — and here the frame is already bitplanes. There is no chunky buffer anywhere in the program, no bset/bclr plotter, and no BLTCON1 write of any kind. A chunky-to-planar converter would have nothing to convert.

One Blitter cookie-cut per polygon scanline

The rasteriser is set up once per polygon and then issues one Blitter operation per scanline, which paints all four bitplanes at the same time because the bitmap is interleaved:

BLTCON0 = $07CA      USEB|USEC|USED, minterm D = (A AND B) OR (NOT A AND C)
BLTADAT = $FFFF      A is a constant; only BLTAFWM/BLTALWM modulate it
BLTBPT  = the dither pattern for this face's shade
BLTCPT  = BLTDPT = the screen
BLTBMOD = BLTCMOD = BLTDMOD = 40 - width
BLTSIZE height = 4   <- the four interleaved planes of one row

BLTAFWM and BLTALWM come out of a 43,520-byte lookup table indexed by the span's ends, so the inner loop turns an X coordinate into a Blitter set-up with four table reads and no shifts. The routine steals a7 to hold that table's base, saving the stack pointer to a variable first, and runs with no usable stack at all.

Two details worth carrying. Every face has two colour bytes, one per facing — the winding test does not discard the back face, it does sge.b and then picks the other byte, and a colour byte of zero means "do not draw this side". And the dither pattern pointer advances by ±160 bytes per scanline, which is exactly the row stride, so the dither is screen-aligned rather than polygon-aligned and two adjacent faces of the same shade tile without a seam.

Two screens stacked, and the arithmetic closes on the raster line

raster 48 – 86    39 lines   the HUD panel:  320 x 38,  SIX bitplanes, interleaved
raster 87 – 286  200 lines   the 3D view:    320 x 200, FOUR bitplanes, interleaved
                 239 lines = DIWSTOP 287 - DIWSTRT 48

Four independent witnesses agree on the 3D view's geometry: BPL1MOD = 200, a bitplane-pointer loop with moveq #3 and a 40-byte step, a mulu.w #$a0 in the rasteriser, and a 32,000-byte buffer size. The panel's is moveq #5, a 40-byte step and a 9,120-byte stored image whose own header reads 320, 38, 6.

The colour is genuine 24-bit AGA and it never touches registers 0–127: BPLCON4's BPLAM = $80 XORs the six-plane index into the range 128–191, which is exactly the two BPLCON3 banks the copper list writes, each twice with LOCT toggled. LoadRGB4 and LoadRGB32 are both never called — the third zero-zero disc in this series.

The sky is 4,096 twenty-four-bit colours per zone

Each data/splits/splitNN is exactly 16,384 bytes: 4,096 entries of two big-endian words — an AGA LOCT pair. Read as 12-bit $0RGB they are noise; read as LOCT pairs they are gradients that change by one low nibble at a time, which is the whole reason for the 24-bit path. The copper list pours them out at two colours per scanline over roughly 205 lines, from a ~205-instance template of a 28-byte unit the game patches every frame.

Nothing on the disc is compressed — and the other SKU proves why

files at entropy >= 7.0:  0 of 61
RNC / IMP! / ATN! / PP20 / XPKF / CrM2 / LZX / SQSH:  0 hits in 2.75 MB
MMD0..3 / M.K. / 8SVX:  0 hits.   FORM: one, and it is an artist's paint file

The prediction — Guardian is the first title here whose floppy SKU exists but arrives later, so at master time there was no floppy loader to inherit and the rule predicts no compression — is confirmed. And the A1200 release turns the correlation into a controlled experiment: 24 of this disc's data files are byte-identical inside the A1200 data floppy, laid out in eleven 24,832-byte groups, while the sprite banks — 1.35 MB that will not fit on 880 KB — are packed into the floppy's second half at entropy 7.9. One data set, two media, packed on one and raw on the other.

The split files appear on the floppy in the order 1, 2, 4, 9, 8, 5, 11, 3, 6, 7, 10, which is exactly the permutation in the CD32 disc's own zone table. Two files, two build steps, two media, agreeing on an arbitrary eleven-element permutation.

sw, and what the disc can and cannot date

s/startup-sequence.bak — the previous boot script, pressed beside the live one — runs sw m1 f where the live one runs game m1 f. The A1200 release's executable is called sw. So a build called sw existed before 1994-08-04 and had already been renamed here.

That is as far as the disc goes, and this repository says so. There is no $VER: anywhere in /game, the executable's own file record carries the MS-DOS epoch, and the only A1200 images available are a cracked December 1994 release whose dates are the cracker's. Which SKU shipped first is item 1 of 12-open-questions.md.

Two files that belong to another disc

SHA-1  8b6cf0011d6a55754c8b762eec1e808576e6c246   10,964 B  /setpatch  40.3 (10.5.93)
SHA-1  6bb943b7dac227070ce10d44f82a9ed85f51a74e      396 B  /s/startup-sequence.info

Both are byte-identical to Gloom's — Black Magic Software / Guildhall, ten months later — and the setpatch is also byte-identical to the one on Guardian's own A1200 floppy. The icon is a Workbench project icon on the boot script with DefaultTool = blitz2:blitz2: two unrelated studios shipping the same Blitz Basic 2 project icon, byte for byte. On Gloom the credits name Blitz; on Guardian this icon is the only evidence it was in the build chain at all.

And what shipped that should not have

  • (C) 1994 ACID SOFTWARE immediately followed by PIRATES FUCK OFF, at the very top of the code hunk, referenced by nothing.
  • hElP$68456c50 — written at the last longword of seven chip allocations, and verified at run time by seven cmpi.l sites. A working buffer-overrun canary, still armed in the retail build.
  • A twelfth zone's worth of assets nobody can load: split12, spr12 (the largest sprite bank on the disc), sprhead12 and map12, plus map00, map99, dither00 and dither98179,796 bytes, 8.0 % of the disc, against a zone table with eleven records.
  • dither99.iff — the artist's Deluxe Paint working file for the dither sheet, with its GRAB hot-spot and six CRNG colour-cycle ranges intact, pressed beside the stripped binary the game actually reads. It is the only FORM on the disc.
  • WAS and GON — four printable bytes each, sitting immediately in front of the two strings the save code does address, and addressed by nothing.
  • A title screen that draws (C)1994 ACID SOFTWARE in pixels and, across a planet, a hand-lettered signature ending in 94 — the only personal mark on a disc with an empty preparer field, no credits screen and no name in any string.

Reproducing this

python tools/isoread.py    <track01.iso> -x _work/files    # extract the volume
python tools/sectormap.py  <track01.iso>                   # the 32-sector run
python tools/census.py     _work/files                     # entropy, zlib, magic
python tools/akiko.py      <track01.iso> _work/files/*     # the headline measurement
python tools/relocs.py     _work/files/game --at 0x2580    # hunk/file offsets
python tools/regscan.py    _work/files/game                # both register scans
python tools/copperdump.py _work/files/game 0x63674        # the copper list
python tools/rleimg.py     _work/files/game --scan         # the nine images
python tools/rleimg.py     _work/files/game 0x55ebe t.png    # decode and render one
python tools/planarimg.py  _work/files/game 0x53fce t.png    # the four raw ones
python tools/strdump.py    _work/files/game 5               # strings with offsets
python tools/adfread.py    <disk1.adf> -x _work/a1200      # the other release
python tools/audiotracks.py *.wav                          # the twelve tracks

Every tool is plain Python 3 with no dependencies except capstone, which only m68kdis.py needs. The Capstone M68K backend prints wrong-but-plausible immediates on this code; every constant quoted in these pages was re-read from the raw byte column, and tools/relocs.py --at was used to decide which hunk each address belongs to.

About

Reverse-engineering notes on Guardian (Acid Software, 1994) for the Amiga CD32: a polygon engine that fills every scanline with one Blitter cookie-cut into four interleaved bitplanes, a 24-bit per-scanline copper sky, and Akiko measured to zero for the eleventh time

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages