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
0x0C6FB8with 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 thatLoadSegrelocates, 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+s775100means the stream found at byte 775,100 ofalfred.
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).
| 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:
HEADDBGV01andver6.00— the SAS/C 6.00 debug format;SRC6andLINErecords naming the source filealf.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_TailPredand 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.
| 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.
| 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.
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.
intro contains a complete Amiga hardware monitor. alfred contains none of it.
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.
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.
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.
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 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.
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.
| 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
/mythhad zero because it is self-relocating and copies itself to a fixed address.c/assignandc/executehave zero because AmigaOS 2.0 commands are written entirely PC-relative so they can be made resident.tools/relocs.py FILE --listreturns an empty list in both cases; what distinguishes them is whether the code starts by copying itself, and these two do not; - check for
DEBUGandSYMBOLhunks 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.
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.