Files
VRIO/PlasmaNew/FIRMWARE.md
T
CydandClaude Opus 4.8 49e88fbe20 vPLASMA: fold in the real ROM fonts and firmware-confirmed commands
Replaces the guessed font/cursor model with what the firmware dump proved:

- The 8 real Babcock ROM fonts, extracted from tms27pc512.BIN into
  PlasmaFonts.cs (6x8, 6x10, 7x10, 12x16, 12x20). Drops the public-domain
  5x7 stand-in and PlasmaFont.cs.
- Pixel-addressed cursor with the real positioning commands: ESC Q (row Y,
  0-31) and ESC R (column X, 0-127), matching the firmware's range checks.
  Cursor motion (BS/HT/LF/VT/CR) now moves by font pixels, not cells.
- ESC K selects fonts 0-7 (out-of-range ignored, per firmware); ESC H
  attributes are the low 4 bits (half/underline/reverse/flash).

Deferred (documented in FIRMWARE.md): the 10 double-buffered pages
(ESC I/i) and vector-graphics primitives (ESC A-F); vPLASMA keeps a
single-page model for now.

Verified: 24 unit tests pass; the three self-test pages render the real
glyphs (big font 4 banner, full charset in font 0, graphics). Next: begin
the modern-parts hardware replica, with this as the reference firmware.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 17:39:07 -05:00

7.2 KiB
Raw Blame History

PD01D221 firmware analysis (tms27pc512.BIN)

Reverse-engineering notes for the dumped controller firmware — the 64 KB TI TMS27PC512 EPROM (U3) from the Babcock PD01D221. This is the authoritative source for the display's command set, and it feeds both vPLASMA and the planned hardware replica.

Dump: tms27pc512.BIN, 65,536 bytes, MD5 b775427806857f60ca4a4cc501f4b5cc. Analysis tooling: hc11dis.py (a purpose-built 68HC11 disassembler — the toolchain has no m68hc11 target).

Memory map

  • CPU $8000$FFFF = EPROM upper 32 KB, 1:1 (the HC11 vector table lands at ROM offset $FFC0$FFFF and is valid, which pins the mapping). The EPROM's lower 32 KB is unused (all $00) — only A15-high is decoded to the ROM.
  • Code: $9000$B8xx. Data/tables: $8000$8FFF (demo), $98AC+ (dispatch tables), $BC03+ (font descriptors), $C000$DFFF (glyph bitmaps + graphics).
  • RAM (Mosel MS62256, 32 KB) at low addresses: HC11 registers on page 0 ($00$3F; SCSR=$2E, SCDR=$2F), zero-page variables $40$FF, RX ring buffer at $0228, and ten 128×32 screen buffers from $0F6D up.

Vectors

Vector Target Notes
RESET $9059 Init: registers, stack $0227, then main loop
SCI (serial rx) $B85C Interrupt-driven receive → ring buffer
COP watchdog $905E (re-inits)
others $9059 default → reset

Architecture

  1. SCI RX ISR ($B85C) — on RDRF, reads SCSR/SCDR, stores the byte to a ring buffer at $0228 (write ptr $0228, count $022C). No parsing here.
  2. Main-loop parser ($B7E0$B859) — pulls buffered bytes and runs an ESC-state machine (flag $AF: bit $10 = ESC seen, bit $20 = operand pending). Dispatch is table-driven (below). Printable chars in the current font's [first,last] range ($62/$63) go to the character renderer ($9648), which enqueues a glyph to a deferred rasterizer.
  3. Ten double-buffered screens — descriptor table at $A4E0 (10 × 6 bytes): each screen has a draw pointer ($BE) and a display pointer ($BC) into SRAM, 1 KB apart. ESC I sets the draw target, ESC i sets what's scanned to the glass → page-flipping / double-buffering.

Command dispatch

Two jump tables, indexed by byte:

  • ESC + letter → command table at $98AC. Valid letters 0x300x7E; index = letter 0x30; null entry = ignored. 58 commands populated.
  • Control bytes 0x080x14 → table at $994C. index = byte 0x08.

Most command handlers share a prologue: first sighting of the letter sets the "operand pending" flag and returns; the next byte is the 1-byte operand (in $C6). Multi-operand commands (ESC P/X/Y) collect into a parameter block at $0070.

Control characters ($994C)

Byte Handler Meaning
0x08 BS $99AF cursor left
0x09 HT $9966 tab
0x0A LF $99F3 line feed
0x0B VT $9A30 vertical tab
0x0D CR $9A55 carriage return
0x110x14 DC1DC4 $9A5C/$9B34/$9C09/$9CFC device controls (TBD)
0x0C FF, 0x0E0x10 no handler

ESC commands ($98AC) — confirmed semantics

Cmd Handler Meaning
ESC @ $9F26 Clear the active draw buffer (512 bytes = 128×32÷8)
ESC G n $A42B Cursor mode, low nibble of $B4 (n = 07)
ESC H n $A44C Text attributes, low 4 bits of $B1 (intensity/underline/reverse/flash)
ESC K n $A3EA Font select (n = 09; 8 real fonts)
ESC L $A556 Home cursor (X=0, Y=0)
ESC Q n $A51C Set cursor row Y (range-checked 031)
ESC R n $A539 Set cursor column X (range-checked 0127)
ESC I n $A473 Select DRAW page 09 (sets $BE from $A4E0 table)
ESC i n $A4A2 Select DISPLAY page 09 (page-flip; sets $BC)
ESC P … $AAF1 Graphics bitmap write (multi-operand: screen,y,x,w,h,data)
ESC AESC F $9FB6$A13C Vector/graphics primitives (line/point/move; pen state $B6, coords $58/$59, line routine $A16C)
ESC X n $A748 Set graphics pen X (multi-op, 0127)
ESC Y n $A644 Set graphics pen Y (multi-op)
ESC J $A4D4 Toggle mode bit $B7.7 (orientation/display — TBD)

ESC commands — populated but not yet decoded

ESC 09 ($9E27+, set continuations — likely custom-char / numeric entry), ESC : ; = , ESC < > W w _ (cluster $AEBA$AF00), ESC B C D E F variants, ESC M N O ($A5BD/$A5C5/$A5E0), ESC Z ^ z ~ (cluster $AC73$ACA1), ESC af, ESC h l n p q r x. ~30 handlers remain to label — full list with addresses is dumped by the tooling below.

Fonts

Font-pointer table at $BC03 (10 slots) → 12-byte descriptors. 8 real fonts (slots 89 are junk pointers, matching the demo's "8 STORED CHARACTER FONTS"):

Font FirstLast W×H Notes
0 0x200xFF 6×8 base font, full range
1 0x400x7F 6×8 uppercase-only
2 0x200xFF 6×10
3 0x400x7F 6×10
4 0x200x7F 12×16 large
5 0x200x7F 12×20 largest
6 0x200xFF 7×10
7 0x400x7F 7×10

Glyph bitmaps live in ROM (~$C000$DFFF). Exact glyph base + encoding pending — the renderer at $9648 enqueues to a deferred rasterizer; tracing that (or brute-forcing the 'A' pattern at the known stride) will extract the real glyphs to replace vPLASMA's public-domain 5×7 stand-in.

Demo program

Enabled by jumper 6 (PD3) — confirms the JP1 map. A 10-screen scripted demo; the script at $8028+ is literal command usage (pointer table at $8000). It's how the new ESC R/I/Q/i/K commands were first spotted, e.g. 1B 47 00 (ESC G 0) 1B 40 (ESC @) 1B 4C (ESC L) 1B 52 04 (ESC R 4) …

What this means

For vPLASMA (folded in 2026-07-16): the recovered spec replaced the guessed behavior. vPLASMA now uses the 8 real ROM fonts (extracted to src/VPlasma.Core/Device/PlasmaFonts.cs), a pixel-addressed cursor with the real ESC Q (row) / ESC R (column) positioning, ESC K 07 font select, and ESC H attributes as the low 4 bits. Verified: 24 unit tests + the three self-test pages render the real glyphs. Still deferred (documented, single-page model retained): the 10 double-buffered pages (ESC I/ESC i) and the vector-graphics primitives (ESC AF).

For the replica: this is the spec. The firmware confirms a clean model — a byte-stream command parser, a 512-byte-per-page frame buffer, 10 pages with page-flip, 8 fonts, text attributes as 4 flags, plus vector graphics. All of it ports directly onto a modern MCU. The one artifact still to extract is the glyph bitmaps.

Reproduce

python hc11dis.py <hexaddr> <count>      # disassemble from a CPU address
# e.g. python hc11dis.py B7E0 70         # the command parser

Command/control tables are at $98AC / $994C; font table $BC03; screen table $A4E0.