Real Z-80 code at trk2:physA — past where LOAD_CPM reads
Detail for Part 7 — From the Reset Vector to the Device Scan.
Investigating the disk-to-memory pipeline more carefully turned up a structural surprise. The 2.23 BIOS at $FAB8-$FFFF is 1352 bytes. The extract_bios.py script grabs 8 contiguous physical sectors (2048 bytes) starting at trk2:phys4 — overshooting the BIOS by 696 bytes.
What’s in the overshoot?
trk2:phys4-7 (4 sectors, 1024 bytes) — first 4 BIOS pages ($FAB8-$FEB7)
trk2:phys8 (1 sector, 256 bytes) — BIOS page 4 ($FEB8-$FFB7)
— first ~85 bytes are zero (NOP slide)
— real code (device-scan) at byte 86 onwards
trk2:phys9 (1 sector, 256 bytes) — BIOS page 5 trap markers + wrap-zone
trk2:physA (1 sector, 256 bytes) — REAL Z-80 CODE (not BIOS — see below)
trk2:physB (1 sector, 256 bytes) — trap markers
trk2:physA is the surprise. Its bytes are real Z-80 instructions:
trk2:physA: 04 21 DD F3 AE 32 45 F0 21 F0 FD C3 80 FD CD 81 FE C6 8F CB 4E 28 FC ...
Decoding the start:
INC B
LD HL,$F3DD ; slot info area
XOR (HL)
LD ($F045),A ; write to TPA-area state byte
LD HL,$FDF0 ; (in BIOS page 3 marker zone — runtime-generated)
JP $FD80 ; (in BIOS code page 2 — real BIOS code)
CALL $FE81 ; ← calls BIOS device-3 init address
ADD A,$8F
...
This is functioning Z-80 code. It references BIOS routines ($FE81, $FB45, $FD80, $FD7C, $FBF4, $FBC1). So at runtime it’s intended to execute as part of the system, with BIOS fully loaded and addressable.
But — and this is the discovery — these bytes are not in staging_223.bin. The staging file is the full LOAD_CPM result (29 sectors that the 6502 boot loader reads from disk). I searched the full 7424 bytes of staging for the first 32 bytes of trk2:physA. No match. Same for newdisk_223.bin (the post-PREP_HANDOFF Z-80 callbacks + BIOS first 1 KB).
So this code is physically on the disk but not loaded by LOAD_CPM. Yet it makes BIOS calls — so it has to reach Z-80 memory by some later step.
Three candidate mechanisms:
(a) The Z-80 cold-boot loads additional sectors via the BIOS disk callbacks. Once the Z-80 is running and the disk callbacks at $1A00 are wired up, the cold-boot could read more sectors and install them into trap-marker pages or low-memory areas. This would be an extension of the LOAD_CPM model — initial 6502 load gets the static BIOS, and Z-80-side cold-boot finishes the loading.
(b) An undiscovered second-stage 6502 load. The 6502 loader might have a code path I haven’t traced that reads additional sectors before triggering the CPU switch. Worth re-examining the PREP_HANDOFF follow-on code at Apple $03C0 for any disk-call references.
(c) The bytes are unreferenced disk content. Maybe trk2:physA is just leftover code from a different build or version, never loaded at runtime. The BIOS calls would then be coincidentally-valid disassembly.
(c) feels unlikely given the consistency of the BIOS call addresses with the 2.23 BIOS structure. (a) and (b) are both plausible mechanisms.
The 2.20 disk image presumably has analogous bytes at corresponding sectors. Comparing them might illuminate what gets loaded vs not.
What this means for the BIOS factory model: the cold-boot generator at $FB3A calls per-device init routines at $FE81/$FD83/$FDB0. $FE81 is in a trap-marker page on disk — there’s no way the bytes at $FE81 are runtime-correct unless something writes them. The bytes at trk2:physA could be the source of those writes. If the Z-80 cold-boot reads trk2:physA and copies its 256 bytes into the trap-marker page at $FBB8-$FCB7 or $FDB8-$FEB7, then the BIOS calls that previously seemed to land in trap markers would actually land in real handler code.
That’s the working hypothesis going forward. Confirming it requires either (a) tracing the Z-80 cold-boot path further to find the disk reads, or (b) running the system in an emulator and observing what’s at $FE81 post-boot.
Status: real Z-80 code located on disk past the LOAD_CPM range. Not yet linked to a specific runtime address; mechanism for getting it into Z-80 memory is open. Consistent with the BIOS factory hypothesis but not yet proof.