
A keyboard looks like 70-odd separate switches, and a computer has nowhere near 70 spare input lines. This section shows how the Einstein manages with sixteen, why those sixteen belong to the sound chip, and how the MOS turns a switch closing into the letter Q.
The keys are wired in a grid: 8 rows by 8 columns. Each key sits where one row wire crosses one column wire, and pressing it connects the two.
To read the grid, you energise one row at a time and look at all 8 columns at once. If a column reads differently, the key at that row and column is down. Eight rows, eight readings - 64 keys from 16 wires.
On the Einstein the signals are active low: you select a row by setting its line to 0 and the others to 1, and a held key pulls its column bit to 0. With nothing held, every column reads 1: FFh.
The rows and their keys, bit 7 to bit 0:
| Row | bit 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| 0 | ESC | SPACE | ENTER | CAPS | F7 | F0 | - | BREAK |
| 1 | 0 @ | ½ ‖ | DOWN | - £ | LEFT | P | O | I |
| 2 | F5 | 9 ) | TAB | RIGHT | : * | ; + | L | K |
| 3 | F4 | UP | = - | DELETE | 8 ( | / ? | . > | , < |
| 4 | F3 | 1 ! | 2 " | 3 # | 4 $ | 5 % | 6 & | 7 ' |
| 5 | F2 | Q | W | E | R | T | Y | U |
| 6 | F1 | A | S | D | F | G | H | J |
| 7 | F6 | Z | X | C | V | B | N | M |
SHIFT, CTRL and GRPH are not in the grid.
Sixteen lines still means two 8-bit ports. The AY-3-8910 sound chip happens to have exactly that built in - two general-purpose 8-bit ports, reached as its registers 14 and 15 - and the Einstein wires the keyboard to them. One chip makes the sound and reads the keys. On a board where every chip costs money and space, that is a good bargain.
To use a register of the AY, you write its number to port 2, then write its value to port 3 or read it from port 2.
Here are the MOS's two smallest keyboard routines, with their original names:
PSGOUT:
ld a,00eh ;0f99
out (002h),a ;0f9b
ld a,e ;0f9d
cpl ;0f9e
out (003h),a ;0f9f
ret ;0fa1
PSGOI:
call PSGOUT ;0fa2
PSGIN:
ld a,00fh ;0fa5
out (002h),a ;0fa7
in a,(002h) ;0fa9
cpl ;0fab
or a ;0fac
ret ;0fad
PSGOUT selects register 14 and writes E to it, inverted by CPL - so the rest of the MOS can think in "1 means this row", and the inversion makes it the active-low pattern the hardware wants. PSGIN selects register 15, reads the columns and inverts them too, so a held key comes back as a 1. OR A sets the zero flag if nothing is held. PSGOI does both: select rows, read columns.
When call 181 scans the keyboard, the rows it writes to register 14 are FEh, FDh, FBh, F7h, EFh, DFh, BFh, 7Fh - a single 0 walking from bit 0 to bit 7 - and then 00h, every row at once.
Knowing that the key at row 5, bit 6 is down does not yet give the code for Q. That comes from a table: KTAB, at 10C5h. Look at the bytes at 1125h:
defb 034h,033h,032h,031h,083h,075h,079h,074h ;1120 4321.uyt
defb 072h,065h,077h,071h,082h,055h,059h,054h ;1128 rewq.UYT
From 1125h: u y t r e w q and 82h. Compare row 5 of the grid, bit 0 to bit 7: U, Y, T, R, E, W, Q, F2. The table lists each row's keys in bit order, and the byte at 112Bh is the character for Q. Straight after it comes the same row again in capitals.
You can show that the MOS takes the Q key's character from 112Bh by changing that one byte. In your copy of mos12.asm, on the line for 1128h, change the fourth byte, 071h (q), to 02ah (*). Rebuild and boot the ROM (S5), and at the prompt type q and then Q.
What you should see
>**
With the original ROM you get >QQ: the Einstein hands back letters as capitals whichever you type. With your change, the Q key gives * both times.
The keys form an 8 x 8 grid read one row at a time, active low, through the AY's spare ports: register 14 selects rows, register 15 returns the columns. The MOS's PSGOUT, PSGIN and PSGOI do that, inverting so that 1 means "key down". A key's character comes from KTAB at 10C5h, laid out row by row in bit order: the Q key's is the byte at 112Bh.
S12: something else happens while the keyboard is being scanned - once a second the MOS stops whatever it is doing to keep time.
This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.