2.20 ships static device handlers in BIOS; 2.23 generates them at runtime
Detail for Part 6 — The BIOS Factory.
Following the device-scan comparison — both BIOSes scan a 9-entry device-code table identically. So if 2.20 had the dispatch logic but couldn’t drive a Videx, the handler code the dispatch jumps to must differ. That’s where to look.
The page-by-page sizes are different. 2.20’s BIOS is 2 KB ($DACC-$E2CB). 2.23’s BIOS is ~1.35 KB ($FAB8-$FFFF). 2.20 has more BIOS — what’s in the extra space?
2.20 BIOS layout (256-byte page interleave, 4 code pages + 4 filler pages = 8 pages × 256 = 2048 bytes):
| Page | Range | Contents |
|---|---|---|
| 0 | $DACC-$DBCB | code: jump table + console/list/punch/reader |
| 1 | $DBCC-$DCCB | $E5 filler |
| 2 | $DCCC-$DDCB | code: SETDMA, READ, WRITE, helpers |
| 3 | $DDCC-$DECB | $E5 filler (BOOT vector $DEA8 lands here) |
| 4 | $DECC-$DFCB | code: cold-boot device-scan loop |
| 5 | $DFCC-$E0CB | $E5 filler |
| 6 | $E0CC-$E1CB | code: static per-device handlers ← extra page 2.23 lacks |
| 7 | $E1CC-$E2CB | $E5 filler |
2.23 BIOS layout (5+ pages = ~1.35 KB):
| Page | Range | Contents |
|---|---|---|
| 0 | $FAB8-$FBB7 | code: jump table + console/list/punch/reader |
| 1 | $FBB8-$FCB7 | FF FF 00 00 / F7 F7 00 00 markers (RST traps) |
| 2 | $FCB8-$FDB7 | code: helpers, dispatch helpers |
| 3 | $FDB8-$FEB7 | trap markers |
| 4 | $FEB8-$FFB7 | code: cold-boot device-scan + NOP slide for BOOT entry |
| 5 | $FFB8-$FFFF | 72 bytes of trap markers (BIOS upper bound) |
Page 6 in 2.20 has no analog in 2.23. Disassembling it reveals static device handlers:
$E0CC: LD B,(HL) ; small return-byte helper
$E0CD: RET P
$E0CE: LD A,(HL)
$E0CF: RET
$E0D0: CALL $DCEA ; per-device output sequence
$E0D3: LD HL,$F678
$E0D6: ADD HL,DE
$E0D7: LD (HL),C
$E0D8: LD HL,$C9AA ; expansion-ROM dispatch?
$E0DB: JP $DB3B ; into CONOUT-style routine
$E0DE: CALL $DD60
$E0E1: LD A,(HL)
$E0E2: RRA
$E0E3: JR NC,$E0E1 ; status-poll loop
$E0E5: INC L
$E0E6: LD A,(HL)
$E0E7: RET
$E0E8: CALL $DCEE
$E0EB: LD HL,$C84D ; another expansion-ROM target
$E0EE: CALL $DB3B
...
$E12C: LD HL,$E08E
$E12F: LD A,E
$E130: ADD A,A ; multiply E by 16
$E131: ADD A,A
$E132: ADD A,A
$E133: ADD A,A ; A = E * 16 = slot offset
$E134: PUSH AF
$E135: ADD A,L ; HL = base + slot offset
$E136: LD L,A
...
$E13F: LD A,($F3B8) ; read slot info byte 0
These routines are device-specific I/O handlers — fixed code that talks to whatever expansion cards 2.20 was designed to support (Pascal 1.0 cards via $Cn07/$Cn05 calling, plus references to $C800-$CFFF shared expansion ROM and direct slot-base address arithmetic via LD A,E; ADD A,A × 4). The handlers are baked into BIOS at compile time. Whatever cards 2.20 knows how to drive, the code lives here.
2.23 doesn’t have this page. The BIOS is shorter by 256 bytes and has no static device-handler code. The equivalent handlers must be runtime-generated — written into the trap-marker pages by the cold-boot generator based on what the slot scanner found.
That’s the architectural shift. 2.20 is dispatch-on-static-handlers; 2.23 is dispatch-on-generated-handlers. And generated handlers can be parameterized per device — same dispatch table consumes them, but the generator can produce a Pascal-1.0-compatible handler for one slot and a Pascal-1.1-compatible handler for another, without needing to ship every variant statically.
This explains why the Videx fix in 2.23 is structurally larger than the 11-byte slot-scanner delta would suggest. The 11 bytes change WHAT the slot scanner detects (Pascal 1.1 → device code $06 instead of $04). But for that detection to be useful, the BIOS has to be able to produce a Pascal-1.1-style handler when it sees device code $06 — and 2.23’s runtime generator can. 2.20’s static handler page didn’t include a Pascal-1.1 handler, so even if 2.20’s slot scanner had detected Pascal 1.1, there’d be no handler to dispatch to.
So the 2.20→2.23 rewrite isn’t one fix. It’s three coordinated changes:
- Slot scanner detects Pascal 1.1 (the 11-byte branch).
- BIOS device-handler architecture switched from static to runtime-generated (the missing 256-byte page).
- Cold-boot generator added (the code that fills the trap-marker pages with handler code based on detected device codes — still being traced).
The 11-byte detection delta is the visible tip of a much larger architectural redesign.
Status: the static-vs-generated distinction is now firm, and the structural reason 2.23 can drive a Videx (when 2.20 cannot) is in view. Next: trace 2.23’s cold-boot generator algorithm — find where it reads $F3A0 device codes and writes handler bytes into $FBB8-$FCB7 and $FDB8-$FEB7.