The cold-boot generator: $FB3A in 2.23, $DB6E in 2.20 — and the device-code 6 branch only 2.23 has
Detail for Part 6 — The BIOS Factory.
Continuing past the static-vs-generated-handlers finding. 2.23 doesn’t have static device-handler code in BIOS; the handlers must be written into the trap-marker pages at boot. So where is the writer?
Disassembling 2.23 page 0 past the dispatch table (which ends at $FB29) lands on a routine at $FB3A:
$FB3A: 11 07 00 LD DE,0007 ; counter E = 7
$FB3D: 21 B8 F3 LD HL,F3B8 ; HL = slot-info table base
$FB40: 19 ADD HL,DE ; HL = F3B8 + E
$FB41: 7E LD A,(HL) ; A = device code at slot E
$FB42: D6 03 SUB 03 ; if A == 3...
$FB44: 20 07 JR NZ,FB4D
$FB46: CD 81 FE CALL FE81 ; ...init handler for device code 3
$FB49: 36 03 LD (HL),03 ; (and rewrite slot byte)
$FB4B: 36 15 LD (HL),15
$FB4D: 3D DEC A ; if A == 4...
$FB4E: 20 0B JR NZ,FB5B
$FB50: CD 83 FD CALL FD83 ; ...init handler for device code 4 (Pascal 1.0)
$FB53: 21 00 C8 LD HL,C800
$FB56: CD 45 FB CALL FB45 ; helper that loads expansion ROM area
$FB59: 18 0A JR FB65
$FB5B: FE 02 CP 02 ; if A == 6 (i.e., subtract-3-then-dec gave 2)...
$FB5D: 20 06 JR NZ,FB65
$FB5F: 21 D0 0D LD HL,0DD0 ; ...init handler for device code 6 (Pascal 1.1)
$FB62: CD B0 FD CALL FDB0 ; ← THE PASCAL 1.1 BRANCH
$FB65: 1D DEC E ; next slot
$FB66: 20 D5 JR NZ,FB3D
$FB68: C9 RET
This is the cold-boot generator. It iterates through slots 7→1 in the slot-info table at $F3B8+E (built by the 6502 boot loader’s slot scanner) and for each detected device code, calls a specific init routine that writes handler bytes into the BIOS trap-marker pages.
The branch decoding works through subtractive comparisons:
- After
SUB 03,A == 0means the original was 3. - After the subsequent
DEC A(which always runs),A == 0means original was 4. - Falling further to
CP 02comparesA(= original − 4) against 2; equality means original was 6.
So 2.23 dispatches on device codes 3, 4, and 6.
2.20 has the same scan loop, in the same structural shape, at $DB6E:
$DB6E: 11 07 00 LD DE,0007 ; counter E = 7
$DB71: 21 B8 F3 LD HL,F3B8 ; HL = slot-info table base
$DB74: 19 ADD HL,DE
$DB75: 7E LD A,(HL)
$DB76: D6 03 SUB 03 ; if A == 3...
$DB78: 20 07 JR NZ,DB81
$DB7A: CD 60 DD CALL DD60 ; ...init handler for device 3
$DB7D: 36 03 LD (HL),03
$DB7F: 36 15 LD (HL),15
$DB81: 3D DEC A ; if A == 4...
$DB82: 20 09 JR NZ,DB8D
$DB84: CD EE DC CALL DCEE ; ...init handler for device 4 (Pascal 1.0)
$DB87: 21 00 C8 LD HL,C800
$DB8A: CD 3B DB CALL DB3B ; helper
$DB8D: 1D DEC E
$DB8E: 20 E1 JR NZ,DB71
$DB90: C9 RET
Same prologue, same loop, same handlers for codes 3 and 4 — and no branch for device code 6. After the device-4 path’s JR $DB8D (or its fall-through), the loop just decrements E and continues. There’s no Pascal 1.1 case.
So the version difference is 20 bytes of additional handler-dispatch code in 2.23’s generator (the FE 02 / 20 06 / 21 D0 0D / CD B0 FD / JR FB65 sequence between the device-4 path and the loop’s bottom).
Combined with the 11-byte slot-scanner delta on the 6502 side, the entire Videx fix in 2.23 is roughly 31 bytes of code, in two coordinated changes:
- 6502 side (boot loader): 11-byte branch that detects Pascal 1.1 by reading
$Cn0Band tags the slot with device code$06instead of$04. - Z-80 side (BIOS cold-boot generator): ~20-byte branch that dispatches device code
$06to a Pascal 1.1 init routine at$FDB0(with handler-code parameters at$0DD0).
That’s the entire story. Microsoft’s CP/M 2.23 release fixed Videx (and any other Pascal 1.1 card) by adding detection of a third firmware-protocol byte plus a corresponding handler-init path in the BIOS factory.
The Pascal 1.1 init at $FDB0 is the next thing to disassemble — that routine writes the actual Pascal-1.1-aware handler code into the trap-marker pages, where the BIOS’s static device-scan dispatch jumps to it. Reading $FDB0 will tell us what code 2.23 generates for a Pascal 1.1 card. That’ll close the loop on the original “what does 2.23 actually do for a Videx?” question.
Status: generator located in both versions; per-device-code dispatch identified; the missing Pascal 1.1 branch in 2.20 confirmed as the BIOS-side half of the fix. Combined with the 6502-side detection delta, the full Videx-recognition path in 2.23 is now visible end-to-end. Next: disassemble $FDB0 (the Pascal 1.1 handler init in 2.23) and write Part 5 of the article series, “The BIOS Factory.”