The BIOS that wouldn't byte-diff

5 min read
apple-iiz80cpmsoftcardoperating-systemsretrocomputingreverse-engineeringcpm-videx-series

Detail for Part 5 — The BIOS That Half-Exists.

CP/M 2.x BIOS starts with a string of JMP instructions — C3 lo hi repeated, one per device entry point. Searched both disk images for any run of 8 or more consecutive C3 ?? ?? triples whose targets cluster in a small address range.

Found two separate occurrences in each image (a primary copy and a backup). 2.23 has 15-jump runs targeting $FAB8..$FED1. 2.20 has 15-jump runs targeting $DACC..$DEA8. 15 entries, not 17 — SoftCard CP/M is CP/M 2.0-style without LISTST or SECTRAN, even on the 2.23 build dated 1982.

Two findings from the addresses:

  • 2.23 BIOS lives at Z-80 $FAB8. 2.20 lives at $DACC. That’s an 8 KB shift up, which means 2.23 has reorganized memory to give the Transient Program Area 8 KB more room.
  • The CCP+BDOS portion of CP/M is supplied unchanged by Digital Research and should be byte-identical between Microsoft builds. Only the BIOS varies. The relocation alone explains why a naive whole-disk diff would show massive differences without indicating real semantic change.

Tried to align the two BIOSes by jump-table base and diff the routines. 1982 of 2048 bytes differ in the first 2 KB after the table — close to 100%. Every absolute address moves by $2000, which dirties two bytes per JMP/CALL/LD imm16 instruction; subsequent re-assembly shifts everything that follows. The aligned diff is not informative.

Tried to extract just the BIOS bytes and disassemble them. Hit a deeper problem: the bytes at the jump-table targets in the reconstructed file image do not decode as plausible Z-80 code. They look like address tables, not routines. The on-disk layout the boot loader reads from doesn’t equal the layout that ends up in Z-80 memory — the SoftCard loader presumably reads sectors in some skew order and scatters them across non-contiguous addresses. Reconstructing that mapping requires understanding the loader.

So the loader is what needs to be understood first anyway. Z-80 BIOS extraction is on hold.

Status: Z-80 BIOS load addresses identified ($FAB8 in 2.23, $DACC in 2.20). Direct BIOS extraction blocked by unknown sector-to-Z-80-memory mapping. The 6502 stage-2 loader, which already lives in the 3 KB at $0800-$13FF after the boot stub completes, is the next thing to disassemble.