PS/2 Card¶

The board as routed in KiCad (3D render; top view).
Theory of operation: p8x-ps2-card-theory.md — the receiver architecture, register semantics, and the 5 V / no-level-shift reasoning.
Status: designed and routed in KiCad (rev A, 2026-09-19); not fabricated yet. The board is in
kicad/(280 × 140 mm, 4-layer, Gerbers + renders; bespoke placement bykicad/gen_ps2.py). This is the standalone TTL card that realises the PS/2 window the emulator already models andlib_ps2already decodes. The first proposal (2026-09-17) was a pure-TTL receiver; the routed board uses an ATmega1284P instead (see below). The alternative FPGA-fabric path (PS/2 ports off the Tang Nano 20K graphics card, TXS0102 level-shifted) is a separate design — seefpga/tang-nano-20k/PS2-INTERFACE.md.
A human-input card: two dumb PS/2 receivers, port A for a keyboard and port B
for a mouse. Each channel takes in the device's 11-bit frames and latches every
byte with a ready flag — nothing more. All meaning (Set-2 scan codes → ASCII,
3-byte mouse packets → dx/dy/buttons, the host→device transmit dance) lives in
software (lib_ps2, man ps2), which is why the card is small and the emulator's
golden model matches it byte-for-byte.
| Address | Register | Access | Port |
|---|---|---|---|
$FF58 |
PSADAT |
read | A (keyboard) data byte; ready clears on read |
$FF59 |
PSAST |
r/w | A status (r: ready/overrun/parity; w: CLK/DATA low) |
$FF5A |
PSBDAT |
read | B (mouse) data byte |
$FF5B |
PSBST |
r/w | B status |
$FF5C |
PSLINE |
read | live CLK/DATA line states (for bit-banged TX) |
$FF5E |
PSID |
read | 'K' presence probe (absent floats $FF) |
$FF5D / $FF5F are unallocated.
Why a standalone card¶
The P8X backplane is one card per function (six core cards + the planned IRQ card). PS/2
input is its own card so it drops into a free slot without touching the I/O card,
which already fills its $FF00-$FF0F decode. PS/2 is native 5 V TTL
open-drain, and the backplane data bus is 5 V, so this card needs no level
translation anywhere — the one real difference from the FPGA-fabric option,
whose 3.3 V GPIO forces a TXS0102 per port.
Chip family¶
An ATmega1284P (U13, PDIP-40, 5 V) runs both PS/2 ports in firmware: framing,
parity, ready and overrun. An MCU cannot meet the bus's read timing directly, so a
latch bridge sits between it and the backplane: four 74HCT374 read latches
(PSADAT/PSAST/PSBDAT/PSBST) that the MCU keeps loaded, a 74HCT244 for
PSLINE and another driving the constant 'K' for PSID. The decode is local:
a 7430 page detector, 74138s for DOE/DLD and the per-register strobes, and a
74688 window compare. Four status LEDs (power, keyboard read, mouse read,
keystroke available) and an AVR ICSP header; the MCU's reset follows the bus
-RES through a 470 Ω isolation resistor. Through-hole, with the house per-IC
100 nF decoupling caps. The full description is §0 of the
theory of operation; the original pure-TTL proposal
(74HC164 / 74HC161 / 74HC574 / 7407 per channel) is kept there as the fallback.
Presence¶
PSID reads 'K' ($4B) when the card is fitted — the same probe convention as
the GL port ('G') and MDU ('M'). ps2_present() checks it.
The netlist is
CARDS["ps2-card"]ingenerators/gen_eagle.py. The addresses are single-sourced ingenerators/gen_memmap.py; the bus pins are in p8x-bus-definition.md. See p8x-system-design.md for the machine overview andBACKLOG.md(the "PS/2 keyboard + mouse card" item) for status.