Files
TeslaRel410/display-board-1408.md
T
CydandClaude Fable 5 6e22e2fdbc Correct 04000000 finding: CheckRequest self-test leftover, not test mode
Bench refutation (display is static under axis movement; version-only
exchanges leave it alone) kills the A-9-E chord theory. Real mechanism:
the CheckRequest handler at $C5A6 runs a full self-test — sets the
test-display flag $2421, brackets itself with TestModeChange 0x8C,
lamp pattern, pod scan, five-channel encoder sweep — and returns
without repainting, leaving the channel-4 frame (04000000) as a stale
cosmetic snapshot. Board fully healthy; no reset needed. PROTOCOL.md
now warns hosts that 0x8C fires around every check. Candidate firmware
fix (repaint cave off $C5E4) noted for a future burn.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 16:04:11 -05:00

148 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Display Board 1408 — outputs, and what the RIO shows on it
Complete definition of the RIO External Display board (P/N 1408 Rev. 1,
`DSP_1408` sheet 7), from the schematic, the board photos, the GAL decode,
and the firmware disassembly (`RIOv4_2.disasm.asm`).
## Outputs: light only — the board is electrically write-only
No signal leaves the board toward the RIO or anything else. J1 has no
readback line, matching the GAL's write-only `DSP_SEL*` decode, and the
PC↔RIO protocol has no display command — only the firmware writes it.
### 1. Eight multiplexed 7-segment digits (U2U9, LTS313A, red, common-cathode)
The ICM7228B (U1) does all driving. `HEX/B/SHD` is strapped high via 2.7 K
(R1): **hexadecimal decode mode, always enabled** — each digit renders 0F
plus a decimal point; no raw-segment access exists as built.
- **Segment bus** — U1 pins 16, 17, 20, 18, 21, 22, 23, 15 drive
`SEGA``SEGG`, `SEGDP`, shared by all digits (digit pins AG, DP =
10, 9, 8, 5, 4, 2, 3, 7). Segments source the multiplexed current
(~20 mA peak).
- **Digit commons** — U1 outputs `DSP1``DSP8` (pins 4, 25, 3, 1, 26, 2,
27, 24) each sink one digit's tied-together commons (CC1+CC2, pins 6+1).
`DSP1`→U2 (leftmost) … `DSP8`→U9 (rightmost).
- Multiplex scanning is internal to the ICM7228; the host only writes
digit registers.
From the 68HC11 the digits are bytes at **`$A000``$A007`** (`AS0-2` =
A0A2, strobed by `DSP_SEL*` = `E & /R/W`-qualified, arriving as the
7228's `/WR` on J1 pin 7). Data format per write: bits 03 = hex value
(`MD[00:03]``ID0-3`), bit 4 = decimal point (`MD[04]``ID7`; DP lights
when the bit is **low** — the firmware always sets it, so the DP is never
used). **`$A000` = leftmost digit (U2), `$A007` = rightmost (U9)**; the
firmware's render buffer (`$2038`, routine `$CB49`) fills right-to-left so
multi-digit hex numbers read naturally.
### 2. Twelve passive monitor LEDs on the "IBM printer port" header (J2) — an input, not an output
J2 (26-pin IDC, standard LPT-ribbon mapping to a DB25) is electrically
isolated from the display circuit; its `DD` nets touch nothing but LEDs
and 1 K resistors referenced to the PC's own ground (`IBM_GND`). With a PC
parallel port plugged in, the LEDs show: **D0D7** = data bits (J2 pins
3, 5, 7, 9, 11, 13, 15, 17), **D8** = `/STROBE` (pin 1), **D9D11** =
`/AUTOFD`, `/INIT`, `/SELECTIN` (pins 2, 6, 8). The LPT status returns are
strapped to ground so a PC streams without waiting. It is a built-in
parallel-port activity monitor / bench tool, powered entirely by the PC.
### 3. Nothing else
J1 (14-pin, from the RIO's EXTERNAL DISPLAY port) is all input:
`MD[00:04]` on pins 2, 4, 6, 8, 10; `AS0-2` on 1, 3, 5; `BF_DSP_SEL*` on
7; GND on 9, 11, 13; VCC on 12, 14.
## What the RIO firmware displays (v4.2)
All display writes go through `$CB49` (buffer render) or five canned
patterns at `$CB7C$CC52`, driven from four contexts: initialization,
the built-in **test mode**, the **serial error/crash displays**, and
the **CheckRequest self-test** (all below). During normal, healthy
gameplay the display is static.
**Normal operation:** `F0000000` — written at cold boot (`$C068`) and warm
re-init (`$C64B`), then left alone.
**Test mode** — entered by typing the keypad sequence **A, 9, E** on a
cockpit keypad (`$C1CB` tracks the sequence at `$20F8`); entry sets flag
`$2421`, shows `F1000000`, and notifies the PC (`TestModeChange`, cmd
`0x8C` — see [PROTOCOL.md](../PROTOCOL.md)). Within test mode the next
keypad digit selects a sub-test; **F** ends a sub-test (back to
`F1000000`), **D** exits test mode (back to `F0000000`).
Display format convention: **left pair = test number, right = value**,
zeros as filler; the decimal points are never used.
| Key | Display | Test |
|-----|---------|------|
| *(entry)* | `F1000000` | test-mode banner |
| `0` | `00000000` | encoder-counter reset: presets the five 16-bit accumulators to `$FAFA` and re-reads all HCTL-2016s (`$C446`) |
| `1` | `0100hhll` | axis test, channel 01 — counter at `$A028/$A038` |
| `2` | `0200hhll` | axis test, channel 02 — `$A020/$A030` |
| `3` | `0300hhll` | axis test, channel 03 — `$A022/$A032` |
| `C` | `0C00hhll` | axis test, channel 0C — `$A024/$A034` |
| `4` | `0400hhll` | axis test, channel 04 — `$A026/$A036` |
| `5` | `050000nn` | button test — `nn` = index of the pressed input (scan at `$D004` over the pod input state at `$2152`), with lamp feedback |
| `6` | `06000003` | lamp test, pattern 3 (`$D34A`) — right digit is the pattern code |
| `7` | `07000001` | lamp test, pattern 1 (`$D370`) |
| `8` | `080000kk` | keypad test — `kk` = keypad status byte `$204B`, refreshed while scanning (`$CC7E`) |
In the axis tests `hhll` is the **live 16-bit quadrature count in hex**
(high:low = `$201D:$201E`, alternating with the raw latched bytes
`$2026:$2025` as the loop runs) — spin the stick/throttle/pedal encoder
and watch the number move. The channel IDs are literally the keypad keys
that start them, which is why the fourth axis reads `0C`.
## The CheckRequest self-test leftover: `04000000`
The host `CheckRequest` (`0x80`) triggers a full self-test in the
handler at `$C5A6`: it sets the same display flag test mode uses
(`$2421`), brackets itself with `TestModeChange 0x8C` notifications,
flashes a lamp pattern, scans the pods, and sweeps the five encoder
channels — rendering each channel's `cc00hhll` frame as it goes. It
clears the flag on exit but **never repaints the display**, so after
every status check the digits are left showing the last frame:
channel 4, usually `04000000` with idle encoders. It is a stale
snapshot (axis movement does not update it — bench-confirmed
2026-07-19), purely cosmetic, and the board keeps operating normally.
Any reset repaints `F0000000`.
## Error displays (the third use)
Two more display writers live in the serial machinery — the display is
also the RIO's **error annunciator**:
- **`E0` serial-diagnostics readout** (`$D5F2`) — `E0xxyyzz` where
`xx` = TX-ring overflow count (`$3187`, outbound byte dropped because
the ring was full, `$D66A`), `yy` = give-up count (`$3184`, `$D96A`
reply cycles whose 5 timeout retransmits all went unACKed), `zz` =
reply-teardown count (`$3185`, `$DA2F` — any reply cycle that needed
at least one retransmission; the counter behind a lone `E0000001`).
Semantics bench-confirmed 2026-07-19: display read `E0000105` after
one give-up + five teardowns. Each increment site immediately re-renders,
so the display live-updates as serial trouble accumulates. If a
cockpit's display reads `E0…` instead of `F0000000`, the serial link
has been dropping or retrying. Note there is **no threshold in stock
firmware** — the first event paints `E0000001` permanently; the
`_e0t5` patched images (`make_patch.py --e0thresh`, see
[RIOv4_2-ANALYSIS.md](../../rio-firmware/RIOv4_2-ANALYSIS.md)) keep
the display quiet until a counter reaches 5.
- **`dEAd` crash screen** (`$DAB8`, loop at `$DAB2`) — the TX-ISR ring
drain (`$D8C2`) looks each outgoing command byte up in an 8-entry
dispatch table at `$3158`; an unmatched byte means internal state
corruption, and the firmware jumps to an infinite loop that renders
`#$DE #$AD`**`dEAd`** followed by RAM bytes `$0000/$0001` (nothing
in this build writes them — vestigial debug data). The board is dead
until reset; there is no watchdog to rescue it (the MAX690's WDI is
not connected to the CPU and no strobe code exists in the firmware).
## Cross-references
- [README.md](README.md) — board family, photos, schematic page map
- [gal/README.md](gal/README.md) — `DSP_SEL*` decode (`$A000-$A00F`,
write-only) recovered from the GAL fuse map
- [`rio-firmware/RIOv4_2.disasm.asm`](../../rio-firmware/RIOv4_2.disasm.asm)
— display routines `$CB20/$CB36/$CB49` (buffer render), `$CB7C` (`F0`),
`$CBA7` (`F1`), `$CBD2`/`$CBFD` (lamp-test banners), `$CC28` (zeros),
test dispatcher `$C241`, entry-sequence tracker `$C1CB`