The Atari 800XL Keyboard

Keyboard data are read as 8 rows of 8 columns.
My machine uses two 4051 analogue 1-of-8 multiplexers.
It thus read as one of 64 bits addressed by an output port.
Where a key is pressed at that address, an I/O pin is connected to ground.

Row   Data (read) Pin
                     
    del ins clr ) ( @   ' 1
> < 0 9 8   7
    esc ! " # $ %   & 2
1 2 3 4 5   6
    ret | _ p o i   u 3
= - P O I   U
    tab q w e r t   y 4
Q W E R T   Y
    f2 ^ \ : l k j f1 5
* + ; L K J
    cap a s d f g h   6
A S D F G H
        ? ] [ m sp n 7
/ . , M N
    f4 Zz Xx C V B hlp f3 8
    17 16 15 14 13 12 11 10  
Keyboard XL
F1...4 1200XL only.

Circled numbers are the pins of the keyboard-connector, with the uppermost pin as [1]. The special 'Fn' keys from the 1200XL can be added to any XL model, but may not work when using a replacement OS.
The matrix is not well-ordered with respect to the binary numbers of the ANTIC signals K0 to K5, so I have not worked out the correspondence between them and the keys.
The key contact resistances vary from 47R (most alphanumeric keys) to 120R (HLP). I have not measured them all, there may be other values. I only mention this because if you try and verify the matrix with a continuity buzzer, it may not buzz.

PS/2 Scan code to Atari 800XL Matrix conversion

PC
kbd
--> PS/2
interface
-scan-code-> FIFO -> 800XL Keyboard
Matrix Encoder
<-- 6-bit key addr
--> 2-bit key data
Atari
POKEY
chip
           
<-- <-control-codes-   <-- encoder <-- status for LEDs

The POKEY chip scans the keyboard matrix to detect when keys are pressed.

The Atari OS reads the keyboard as a 6-bit scan code from POKEY, then looks up the keyboard character. If interfacing with a real POKEY chip, then creating a matrix of virtual keys is certainly the way to go.

PS/2 Scan code to Atari 800XL scan code conversion

If implementing the POKEY on VHDL, it is wasteful to create such a matrix and then create the logic for scanning it. In this case, it seems a much better idea to create logic to translate PS/2 scan codes into POKEY scan codes. The scan codes can then be sent to a register inside the VHDL POKEY chip.

The Atari uses a slight variation of ASCII, called ATASCII. This may cause some confusion, so it is worth highlighting the differences, in yellow cells, in the table below.

ASCII IBM ATARI Notes
    US UK        
DEC HEX   KEY CHAR. KEY CHAR.   KEY CHAR.  
34 22 SHIFT ' " 2 " SHIFT 2 " Atari has " in same place as UK kbd
35 23 SHIFT 3 # 3 SHIFT 3 # Atari has no pound sign
39 27   ' '     SHIFT 7 '  
42 2A SHIFT 8 *       * *  
43 2B SHIFT = +       + +  
60 3C SHIFT , <       < <  
62 3E SHIFT . >       > >  
64 40 SHIFT 2 @ ' @ SHIFT 8 @  
91 5B   [ [     SHIFT , [  
92 5C   \ \     SHIFT + \  
93 5D   ] ]     SHIFT . ]  
94 5E SHIFT 6 ^     SHIFT * ^  
96 60   ` `     CTRL . ` Accent grave
123 7B SHIFT [ {     CTRL ; spade Atari has no curly brackets
124 7C SHIFT \ |     SHIFT = | Solid vertical line
125 7D SHIFT ] }     ESC CTRL < left-turn Atari has no curly brackets
126 7E SHIFT ` ~ # ~ ESC BS L pennant  
127 7F   DEL house     ESC TAB R pennant  

The only ATASCII characters that differ from ASCII characters are spade, left-turn and the two pennants. I doubt they were used much, and one might easily redefine the font ROM to match ASCII.

The Atari used three 64-byte look-up tables (for normal, shifted, and control characters), consuming 192 bytes of ROM.

The PS/2 has about 132 key positions, including two shift keys, two control keys and two alt keys. Thus the look-up tables would have twice as many entries, and would also need extra bits to indicate whether the Atari Shift and Control keys need to be pressed. In total, one would need 3 x 128 x 10 = 3840 bits (480 bytes). Memory inside the FPGA is more expensive than standard memory chips.

From the table above, one can see that the shift key only differs from the PS/2 keyboard shift in 12 places, and the control key in only 3 places, so it might be more efficient to implement the Atari shift and control signals in logic rather than a bit in a look-up table. This might reduce the memory requirements to 3 x 128 x 8 = 3072 bits = bytes (384 bytes).

PS/2 keyboard variations

There are a variety of key-top layouts for different countries. The physical key positions remain the same, only the key-top legends and the decoding table change. Most PS/2 info on the web assumes the US layout.

Atari keyboard variations

Atari seem to have used the same QWERTY layout for all regions, apart from the significantly different Arabic version. In theory it should have been quite easy to modify the scan code to character look-up table in ROM, but in practice it would have cost more to manufacture multiple ROMs and keyboards.

I have just implemented US and UK layouts.

One nice thing to note is that once you have a PS/2 scan code to Atari scan code translator, there is less work coping with national keyboard variations so much. For example, a French PS/2 keyboard would have the keys AZERTY instead of QWERTY, but if your Atari 800XL had a ROM expecting a French keyboard then it would translate the scan code appropriately.

Scan codes for both machines seem to spilt into regular and irregular codes. For regular codes, like the A to Z keys, the control and shift keys modify bits 6 and 5 of the ASCII character output, and the Atari control/shift signals are the same as for the PS/2 keyboard.

For irregular codes, like the punctuation keys, the control and shift keys can change all bits of the ASCII character output.

Status is that it appears to be largely working as described above. A test program monitors the status flags, fetches Atari scan codes, and clears the flags as needed. It should be able to use the flags to generate interrupts. Operation is not identical to the real POKEY yet, a few fiddly details remain to be sorted out.