2.20 and 2.23 BIOSes have identical device-scan loops
Detail for Part 6 — The BIOS Factory.
After correcting the BIOS jump-table reads, I have proper BOOT-vector targets: $DEA8 for 2.20, $FED1 for 2.23. Both land in runtime-generated regions, but real code resumes shortly after — at $DECC for 2.20 (after $E5 filler) and $FF0E for 2.23 (after a NOP slide).
Side-by-side, the post-runtime-generated code is structurally identical:
2.20 cold-boot scan loop ($DECC-$DEDB):
$DECC: B7 OR A
$DECD: 28 04 JR Z,DED3 ; entry empty → skip
$DECF: AB XOR E
$DED0: B9 CP C
$DED1: 28 05 JR Z,DED8 ; match!
$DED3: 2B DEC HL
$DED4: 10 F5 DJNZ DECB ; loop, B = entries left
$DED6: 18 21 JR DEF9 ; no match
$DED8: 11 0B 00 LD DE,000B
$DEDB: 19 ADD HL,DE
2.23 cold-boot scan loop ($FF2E-$FF3E):
$FF2E: 7E LD A,(HL)
$FF2F: B7 OR A
$FF30: 28 04 JR Z,FF36 ; entry empty → skip
$FF32: AB XOR E
$FF33: B9 CP C
$FF34: 28 05 JR Z,FF3B ; match!
$FF36: 2B DEC HL
$FF37: 10 F5 DJNZ FF2E ; loop, B = entries left
$FF39: 18 21 JR FF5C ; no match
$FF3B: 11 0B 00 LD DE,000B
$FF3E: 19 ADD HL,DE
Same instructions, same encoding, same control flow. The base-table pointer is set up the same way too — LD HL,$F3A0 in 2.23, LD A,($F3A2) in 2.20 (different base byte but same slot-info window in TPA).
The difference is what surrounds the loop. 2.23 has preflight code 2.20 doesn’t:
$FF0E: LD B,A
$FF0F: LD HL,FECD ; state-byte address (in runtime-gen zone)
$FF12: LD A,(HL)
$FF13: LD E,A
$FF14: OR A
$FF15: JR NZ,FF29 ; if state nonzero, skip preflight
$FF17: LD A,(F397) ; read slot info
$FF1A: OR A
$FF1B: JR Z,FF23
$FF1D: CP C
$FF1E: JR NZ,FF23
$FF20: LD (HL),80 ; mark state
$FF22: RET
$FF23: LD A,1F
$FF25: CP C
$FF26: JP C,FCA4 ; jump to FCA4 if C >= 1F
$FF29: LD HL,F3A0 ; (fall-through to scan loop)
$FF2C: LD B,09
So 2.23 prefixes the device-scan with a state-byte check at $FECD (in the runtime-generated zone, so it’s a state slot the generator establishes). If the state byte matches some condition, the scan is skipped. 2.20 has no equivalent — it goes straight to the scan loop.
Two implications.
The device-scan architecture didn’t change between versions. 2.20 was already capable of handling N device codes from a 9-entry table. The fix between 2.20 and 2.23 didn’t add new device-handling capacity to the BIOS — that was already there.
The fix lives in the boot-time slot scanner, not the BIOS. Recall from Part 1: the only material difference between 2.20 and 2.23 in the 6502 boot code was 11 bytes that added a Pascal 1.1 detection branch. That fix changes which device code gets written into the table at $F3A0, but the table consumer (the BIOS device-scan) was already there in 2.20. Pre-2.23, the slot scanner just never wrote the right code for a Videx — so the BIOS scan never matched, and no Videx-aware handler was selected.
That’s a clean refactor pattern: the BIOS was forward-compatible, designed to dispatch on device codes from a configurable table; only the table-population logic needed to change. Microsoft shipped 2.23 by patching detection, not by patching the BIOS.
Status: device-scan loop structurally identical between versions. The 2.23 preflight at $FF0E-$FF28 is new and references a state byte at $FECD in the runtime-generated zone — worth understanding, since it’s the entry point to the scan and may carry the “is this Pascal 1.1?” flag the slot scanner now sets. Next: trace what writes to $FECD and what $FCA4 does (the early-exit target on C >= 1F).