Skip to content

Latest commit

 

History

History
274 lines (212 loc) · 12 KB

File metadata and controls

274 lines (212 loc) · 12 KB

The code: three executables, two build epochs, and a debugger that shipped

The address convention, fixed before any address is quoted — step 25

Every address in this repository is one of three kinds and is always labelled:

  • file offset — a byte position in the file as pressed. Written 0x0C6FB8 with no qualifier, and this is the default in this repository;
  • hunk offset — a position within a named hunk, written hunk 3 +0x1A1C0. The absolute constants inside an AmigaDOS hunk executable are hunk offsets that LoadSeg relocates, and the same numbers read as file offsets point somewhere else entirely;
  • resident offset — a position inside an unpacked piece, using this pipeline's <file>+s<off> and <file>+gap<off> naming. alfred+s775100 means the stream found at byte 775,100 of alfred.

No runtime address is quoted anywhere in this repository, because nothing on this disc copies itself to a fixed address the way Myth's loader does.

A constant not covered by a relocation entry is a literal; one that is covered is a pointer, proved (tools/relocs.py --at).

What the three executables are

alf — a 13,736-byte C launcher, shipped with its debug symbols

measure value
hunks 2 (CODE 5,508 B, DATA 344 B)
relocations 8 over 5,508 code bytes = 1.49 per KB
plus DEBUG hunks of 52, 6,332 and 60 bytes, and two SYMBOL hunks

6,444 bytes of the file — 46.9 % of it — are debug information, and it was pressed onto the master. What is in it:

  • HEADDBGV01 and ver6.00 — the SAS/C 6.00 debug format;
  • SRC6 and LINE records naming the source file alf.c, with a full line-number table;
  • the compiler's entire type dictionary: size_t, va_list, fpos_t, __iobuf, wchar_t, ldiv_t, LONGBITS, STRPTR, USHORT, clock_t, ln_Succ, ln_Pred, tc_Node, tc_Flags, tc_IDNestCnt, mlh_TailPred and dozens more — the Amiga includes, as seen by the compiler;
  • function symbols: _strncpy, @stccpy, ___write, _findpath, __XCEXIT, __OSERR, ___iob, __ONEXIT, ___fmask, ___stdiowin, __SIGFPE.

What it does is four bytes of the file: the strings intro and alfred sit in its data, with con:10/10/320/80/ and /auto/close/wait — the SAS/C standard-I/O window. alf runs the intro and then the game.

The relocation density of 1.49/KB would look like "data in a CODE hunk" by the step 36 test. It is not. It is a small C program whose file is half debug information, and the tell is that the debug hunks are declared as such in the hunk structure rather than the low density having to be explained. Worth adding to the step 36 notes: check for DEBUG/SYMBOL hunks before reading a low density.

intro — 255,376 bytes, built from 1992 source, carrying a hardware debugger

hunk type size relocs mem
0 CODE 10,276 18 any
1 DATA 220,316 3 CHIP
2 CODE 6,944 289 any
3 DATA 14,796 404 any

714 relocations over 17,220 code bytes = 42.46 per KB. That is squarely in the "real program" bin, next to SuperFrogCD at 43.6. A 220 KB CHIP DATA hunk with three relocations is the artwork.

Its RCS keyword dates its source to 1992-09-29 — fourteen months before alfred's.

alfred — 816,616 bytes, and three quarters of its CODE hunk is not code

hunk type size relocs mem
0 CODE 7,772 24 any
1 BSS 4 any
2 DATA 336,112 1,057 CHIP
3 CODE 441,780 6,102 any
4 BSS 2,568 CHIP
5 DATA 8 any
6 CODE 212 24 any
7 DATA 1,460 24 any

Whole-file: 7,231 relocations over 449,764 code bytes = 16.46 per KB, which sits between the "real program" and "data in a CODE hunk" bins and would be uninformative on its own.

The relocation spans are what make it informative:

hunk size relocation span share of hunk covered
3 (CODE) 441,780 0x0C .. 0x1A1C0 24.2 %
2 (DATA, CHIP) 336,112 0x380EA .. 0x510AA last 30.8 % only

So hunk 3 is ~107 KB of real code followed by ~335 KB of data in a CODE hunk — the TUNNELDEMO shape, at a much larger scale. Measured against the code part alone the density is about 57 relocations per KB, above every entry in the set's table.

And hunk 2 is the mirror image: the first 229,610 bytes of the CHIP DATA hunk carry no relocations at all (planar artwork) and the relocations are confined to its last third (pointer tables into that artwork).

This is why the step 36 test is a ratio over a span and not a single number. The whole-file figure, 16.46/KB, is the average of a program and a picture.

The four RNC streams inside alfred

alfred is the third container shape: a concatenation of streams and raw gaps.

piece bytes what it is
alfred+gap0 663,294 code, artwork, tables
alfred+s663294 7,516 → 35,840 tile bank (280 tiles)
alfred+gap670810 20,480
alfred+s691290 3,798 → 12,800 tile bank (100 tiles)
alfred+gap695088 64,972
alfred+s760060 9,919 → 29,440 the title screen — byte-identical to frontend.pak
alfred+gap769979 5,121
alfred+s775100 15,051 → 56,320 tile bank (440 tiles), rock and platform texture
alfred+gap790151 26,465 strings, library names, format strings, the RCS keyword

Six gaps, 780,333 bytes. The gaps are not padding — the largest is the program itself.

The debugger that shipped, and only in the older build

intro contains a complete Amiga hardware monitor. alfred contains none of it.

The register name table

47 descriptive strings, 1,533 bytes, verbatim Commodore comment text from hardware/custom.i:

read vert most signif. bit (and frame flop)
read vert and horiz. position of beam
disk data early read (dummy address)
collision data (read and clear)
audio, disk control register read
pot counter pair 0 data (vert,horiz)
disk pointer (high 3 bits)          disk pointer (low 15 bits)
disk length                          disk DMA data write
disk sync pattern for disk read      audio, disk, UART control
blitter first word mask for source A blitter last word mask for source A
blitter pointer to source A/B/C/D (high 3 bits / low 15 bits)
blitter modulo for source A/B/C/D    blitter source A/B/C data
sprite 0..7 image data register A/B
...

Beside them, a table of the register addresses — which is the source of the 00B80038 byte-pattern hit that docs/07-graphics.md catalogues as a false positive.

copdis — a copper list disassembler

0x03DC38  vpos=%d,hpos=%d
0x03DC48  instruction %x, %x\n
0x03DC5C  ,vcomp=%d,hcomp=%d\n
0x03DC70  UNKNOWN_OPCODE
0x03DC88  \tmove\t%x,%s
0x03DC9C  copdis: copper list pointer is null\n

A working copper disassembler, with a null-pointer guard and an unknown-opcode path, printing register names from the table above. Pressed onto a commercial CD32 disc.

What it says, put together

intro is built from source checked out 1992-09-29 and ships with a hardware debugger. alfred is built from source checked out 1993-11-19 and ships without one — no register table, no copdis, no UNKNOWN_OPCODE.

Two builds of one code base, fourteen months apart, and the debug scaffolding was removed between them but the older executable was shipped anyway. The intro was finished in 1992, put aside, and pressed in 1993 in whatever state it had been left in.

This is the single best archaeological find on the disc, and it exists only because intro was never rebuilt.

The four-owner assignment, filled in

Open question 14 asks that every artefact be assigned to the step that produced it. This is the first disc where all four steps have an observable owner and all four slots are filled:

step owner evidence on the disc
game build Twilight $Header: Hard0:alfred/rcs/amiga.c,v … JJS, SAS/C 6.00 debug records, alf.c, alf2:%s, the copdis debugger, the label's copyright and trademark
label Mindscape PVD publisher field Mindscape, artwork
premastering / ISO image Abersoft PVD data preparer Abersoft - ISOCD 1.04 by Pantaray, Inc. USA -, the 32-sector final run, the root directory record, the .TM block placement
glass master and pressing Nimbus matrix ring MASTERED BY NIMBUS, CDD2971, absence of any SID

And the timestamps separate them without needing the inference (see docs/05-timestamps.md): the asset copy is a nine-second block on 1993-11-30, /alfred is written alone on 1993-12-06 after 21 hours of silence, and the master is cut four minutes later.

The cross-test that this makes possible

The packer is RNC ProPack, written by Rob Northen Computing. The premastering is Abersoft. On Myth it was the other way round — the premastering was Rob Northen Computing and the packer was Bytekiller.

Two discs, the two roles swapped, and in neither case does the mastering house's tool appear in the master it cut. The packing step belongs to the game build; the mastering step does not touch it. That is what open question 14 was trying to establish, and this pair establishes it.

Abersoft appears zero times anywhere on the disc outside the PVD field — the same grep that returned zero for Northen on Myth.

A script interpreter — open question 25

tools/dispatch.py, both executables:

alfred : dispatch tables 0, opcodes total 0
intro  : dispatch tables 0, opcodes total 0

No VM, which is the predicted answer for a 2D platformer and is reported with the count rather than as an assumption.

What there is instead: two runs of consecutive bra.w in alfred, found structurally rather than from the code that jumps into them.

table entries distinct handlers largest target's share
alfred 0x0007AB68 6 6 16.7 %
alfred 0x00092CA0 7 7 14.3 %

100 % distinct in both. That is the Myth pattern (the CD backend's 16 of 16, the device API's 12 of 12) and not the Superfrog one, where four fifths of a 320-slot table was a shared default. The useful measurement is the ratio, and here it says these are small hand-written branch tables with no default arm at all.

Executable format summary — step 36

file CODE bytes relocs per KB classification
intro 17,220 714 42.46 real program
alfred, hunk 3 code portion ~107,000 6,102 ~57 real program
alfred, whole file 449,764 7,231 16.46 average of a program and a picture — do not use
c/setpatch 12,104 246 20.81 real program (Commodore)
libs/lowlevel.library 6,812 14 2.10 a library, a different structure
alf 5,508 8 1.49 a small C program that is 47 % debug records
c/assign 3,184 0 0.00 pure PC-relative, residentable (Commodore)
c/execute 4,396 0 0.00 pure PC-relative, residentable (Commodore)

Two new notes for the step 36 table:

  • zero relocations is not one thing. Myth's /myth had zero because it is self-relocating and copies itself to a fixed address. c/assign and c/execute have zero because AmigaOS 2.0 commands are written entirely PC-relative so they can be made resident. tools/relocs.py FILE --list returns an empty list in both cases; what distinguishes them is whether the code starts by copying itself, and these two do not;
  • check for DEBUG and SYMBOL hunks before reading a low density. alf's 1.49/KB is an artefact of 6,444 bytes of debug records inflating the denominator's file, and the hunk walk says so directly.

Capstone

tools/dis68k.py recomputes branch targets from the encoding. No immediate, displacement or absolute address in this repository was taken from a Capstone M68K listing without being re-read from the raw bytes, per the standing warning.