07_dos: - file_io.md: 108→240+ lines — buffered I/O (FRead/FWrite/SetVBuf), access mode comparison, FileHandle struct with offsets, standard handles, Printf %ld warning, FileInfoBlock, practical patterns (copy file, get size, load to RAM), error code table - filesystem.md: 91→270+ lines — full disk geometry (ADF/HDF), all 8 DOS\x filesystem IDs, root block byte-level layout, file header layout with reverse-order pointer quirk, OFS vs FFS data blocks with efficiency numbers, bitmap blocks, extension blocks, checksum algorithm, Python ADF reader - locks_examine.md: 113→270+ lines — lock semantics diagram, FileLock struct with handler discovery, ExAll bulk scan, practical patterns (atomic write, path resolution, volume info), 4 antipatterns (leaked locks, exclusive too long, unchecked IoErr, DupLock), pattern matching 10_devices: - audio.md: 73→240+ lines — hardware architecture diagram, channel registers with offsets, period/frequency table, priority allocation, double-buffering, audio interrupts, AM/PM modulation, direct HW - timer.md: 80→230+ lines — CIA timer hardware, all 5 units with decision flowchart, non-blocking delays, signal-based waiting, time arithmetic, ReadEClock, periodic game loop pattern, pitfalls - trackdisk.md: 82→210+ lines — MFM encoding, track format, disk geometry, read/write/motor, change notification, track caching, direct hardware access, FPGA timing implications - keyboard.md: 58→220+ lines — CIA-A serial handshake protocol with sequence diagram, bit rotation quirk, complete key code map, key matrix bitmap, reset sequence, FPGA notes
5.8 KiB
keyboard.device — Keyboard Hardware and Raw Key Codes
Overview
keyboard.device provides access to the Amiga keyboard via the CIA-A serial port handshake protocol. The keyboard controller (a dedicated 6500/1 or 68HC05 microcontroller inside the keyboard) transmits raw key codes as serial data through CIA-A. Understanding this protocol is essential for FPGA core implementation.
Hardware Protocol
sequenceDiagram
participant KB as Keyboard MCU
participant CIA as CIA-A (SP/CNT pins)
participant CPU as 68000 (interrupt)
KB->>CIA: Serial data (8 bits, MSB first)
Note over CIA: CIA-A SP register latches byte
CIA->>CPU: CIA-A ICR bit 3 (SP interrupt)
CPU->>CIA: Read $BFEC01 (SP data register)
CPU->>CIA: Pulse KDAT line low for ~85µs
Note over CIA: Handshake acknowledges receipt
KB->>KB: Ready for next key
CIA-A Registers Used
| Register | Address | Bit | Function |
|---|---|---|---|
CIASDR |
$BFEC01 |
7:0 | Serial data register — receives raw key code |
CIACRA |
$BFEE01 |
6 | SP direction: 0=input (keyboard), 1=output |
CIAICR |
$BFED01 |
3 | SP interrupt flag — set when byte received |
Raw Key Code Format
The keyboard sends an 8-bit value where:
- Bit 7 = key state: 0 = pressed, 1 = released
- Bits 6:0 = key code (0–127)
/* Decode a raw key event: */
UBYTE raw = ~(cia->ciaSDR); /* invert (active low) */
raw = (raw >> 1) | (raw << 7); /* rotate right 1 bit */
UBYTE keycode = raw & 0x7F;
BOOL keyup = raw & 0x80;
Bit rotation: The keyboard transmits bits in a rotated format. The software must rotate the received byte right by 1 bit to get the actual key code. This is a hardware design quirk.
Handshake Timing
After reading the key code, the CPU must acknowledge by pulsing the KDAT line:
; Acknowledge key reception:
OR.B #$40, $BFEE01 ; CIACRA — set SP to output
; Wait at least 85 µs
MOVE.B #0, $BFEC01 ; drive KDAT low
; (timer or loop delay ~85 µs)
AND.B #~$40, $BFEE01 ; CIACRA — set SP back to input
; Keyboard is now ready to send next key
FPGA note: If the handshake acknowledgement is too fast (<75µs) or too slow (>200ms), the keyboard MCU will resend the key code or initiate a reset sequence.
Raw Key Code Map
Main Keys
| Code | Key | Code | Key | Code | Key |
|---|---|---|---|---|---|
| $00 | ` (backtick) |
$01 | 1 |
$02 | 2 |
| $03 | 3 |
$04 | 4 |
$05 | 5 |
| $06 | 6 |
$07 | 7 |
$08 | 8 |
| $09 | 9 |
$0A | 0 |
$0B | - |
| $0C | = |
$0D | \ |
$10 | Q |
| $11 | W |
$12 | E |
$13 | R |
| $14 | T |
$15 | Y |
$16 | U |
| $17 | I |
$18 | O |
$19 | P |
| $1A | [ |
$1B | ] |
$20 | A |
| $21 | S |
$22 | D |
$23 | F |
| $24 | G |
$25 | H |
$26 | J |
| $27 | K |
$28 | L |
$29 | ; |
| $2A | ' |
$31 | Z |
$32 | X |
| $33 | C |
$34 | V |
$35 | B |
| $36 | N |
$37 | M |
$38 | , |
| $39 | . |
$3A | / |
$40 | Space |
| $41 | Backspace |
$42 | Tab |
$43 | Numpad Enter |
| $44 | Return |
$45 | Escape |
$46 | Delete |
Modifier and Special Keys
| Code | Key | Code | Key |
|---|---|---|---|
| $60 | Left Shift |
$61 | Right Shift |
| $62 | Caps Lock |
$63 | Ctrl |
| $64 | Left Alt |
$65 | Right Alt |
| $66 | Left Amiga |
$67 | Right Amiga |
Cursor and Function Keys
| Code | Key | Code | Key |
|---|---|---|---|
| $4C | Cursor Up |
$4D | Cursor Down |
| $4E | Cursor Right |
$4F | Cursor Left |
| $50–$59 | F1–F10 |
$5F | Help |
Special Codes
| Code | Meaning |
|---|---|
| $78 | Reset warning — Ctrl+Amiga+Amiga pressed (keyboard sends this before resetting) |
| $F9 | Last key code was bad (parity error) — resend |
| $FA | Keyboard buffer overflow |
| $FC | Keyboard self-test failed |
| $FD | Initiate power-up key stream |
| $FE | Terminate power-up key stream |
Using keyboard.device (OS Level)
Most applications receive key events through Intuition IDCMP (see idcmp.md). Direct keyboard.device use is for system-level software:
struct MsgPort *kbPort = CreateMsgPort();
struct IOStdReq *kbReq = (struct IOStdReq *)
CreateIORequest(kbPort, sizeof(struct IOStdReq));
OpenDevice("keyboard.device", 0, (struct IORequest *)kbReq, 0);
/* Read raw key events: */
struct InputEvent ie;
kbReq->io_Command = KBD_READMATRIX;
kbReq->io_Data = &keyMatrix; /* 16-byte key matrix bitmap */
kbReq->io_Length = 16;
DoIO((struct IORequest *)kbReq);
/* keyMatrix bit N = 1 if key code N is currently held down */
/* Reset keyboard (force self-test): */
kbReq->io_Command = KBD_RESETHANDLER;
DoIO((struct IORequest *)kbReq);
Key Matrix
The KBD_READMATRIX command returns a 16-byte (128-bit) bitmap where each bit corresponds to a raw key code:
UBYTE keyMatrix[16];
/* Bit test: is key $45 (Escape) pressed? */
BOOL escPressed = keyMatrix[0x45 / 8] & (1 << (0x45 % 8));
Keyboard Reset Sequence
The Ctrl+Amiga+Amiga three-key combination triggers a hardware reset:
- User presses Ctrl+Left Amiga+Right Amiga
- Keyboard MCU detects the combo
- Sends raw code
$78(reset warning) — gives software ~10 seconds to clean up - Pulls KBRST line low → triggers 68000 reset via RESET pin
FPGA: The core must implement this reset path. The
$78warning code allows software (e.g., debuggers) to save state before reset.