Reading the keyboard by direct hardware access
From Retrosoftware
| Line 11: | Line 11: | ||
== Doing it 'legally' == | == Doing it 'legally' == | ||
| + | The type of keyboard input we're interested in for games is the one of the INKEY(-keycode) variety, i.e. the one which detects multiple depressed keys at once. | ||
| + | |||
| + | I can't imagine the number of times I wrote code like: | ||
| + | |||
| + | <tt> | ||
| + | dx%=INKEY(-98)-INKEY(-67) | ||
| + | dy%=INKEY(-73)-INKEY(-105) | ||
| + | jump%=INKEY(-74) | ||
| + | </tt> | ||
| + | |||
| + | So often did I check for these keys being pressed that their internal codes are forever etched in my brain, just underneath the opcode for NOP, and the address of OSWRCH. | ||
| + | |||
| + | Did you ever wonder what on earth the significance of these strange key codes were? They weren't related to ASCII in any way, and they seemed to be more-or-less randomly chosen. Well, in fact, they were bringing us closer to the hardware than you might have guessed. | ||
| Line 16: | Line 29: | ||
The keyboard is mapped to System VIA port A (accessed through &FE41 or &FE4F for "no handshake", whatever the hell that means...). The bottom 7 bits are used to specify which key you wish to poll, and the top bit returns whether the key is pressed or not. | The keyboard is mapped to System VIA port A (accessed through &FE41 or &FE4F for "no handshake", whatever the hell that means...). The bottom 7 bits are used to specify which key you wish to poll, and the top bit returns whether the key is pressed or not. | ||
| + | |||
So, first we need to set the Data Direction Register A to specify that the bottom 7 bits are outputs, and the top bit is an input. Hence: | So, first we need to set the Data Direction Register A to specify that the bottom 7 bits are outputs, and the top bit is an input. Hence: | ||
| Line 22: | Line 36: | ||
LDA #&7F:STA &FE43 | LDA #&7F:STA &FE43 | ||
</tt> | </tt> | ||
| + | |||
Now, System VIA port A is also shared by the sound chip and the speech chip, so before we can access the keyboard, we need to enable it over the other two possibilities. This is done via the "addressable latch" in System VIA port B. | Now, System VIA port A is also shared by the sound chip and the speech chip, so before we can access the keyboard, we need to enable it over the other two possibilities. This is done via the "addressable latch" in System VIA port B. | ||
| Line 38: | Line 53: | ||
Now, reading a key is simplicity itself! We need the internal key number of the key - either consult the table on AUG page 142, or take the negative INKEY code of the key, make it positive, and subtract 1. (e.g. space (-99) becomes 98). | Now, reading a key is simplicity itself! We need the internal key number of the key - either consult the table on AUG page 142, or take the negative INKEY code of the key, make it positive, and subtract 1. (e.g. space (-99) becomes 98). | ||
| + | |||
Then, write to System VIA port A, and read it back. The top bit will tell you whether the key is pressed or not (set=pressed): | Then, write to System VIA port A, and read it back. The top bit will tell you whether the key is pressed or not (set=pressed): | ||
Revision as of 08:40, 28 June 2008
Sample Code Library > Reading the keyboard by direct hardware access
Reading the keyboard by direct hardware access
This is a topic which is barely, if at all, explained in the AUG, and indeed it was an area which caused some of the biggest problems in the first BBC emulators, mostly because it seemed no-one could find any good documentation on it!
But it turns out that, with some initial setup, reading whether a key is pressed or not by accessing the keyboard hardware directly is extremely trivial on the Beeb.
Doing it 'legally'
The type of keyboard input we're interested in for games is the one of the INKEY(-keycode) variety, i.e. the one which detects multiple depressed keys at once.
I can't imagine the number of times I wrote code like:
dx%=INKEY(-98)-INKEY(-67) dy%=INKEY(-73)-INKEY(-105) jump%=INKEY(-74)
So often did I check for these keys being pressed that their internal codes are forever etched in my brain, just underneath the opcode for NOP, and the address of OSWRCH.
Did you ever wonder what on earth the significance of these strange key codes were? They weren't related to ASCII in any way, and they seemed to be more-or-less randomly chosen. Well, in fact, they were bringing us closer to the hardware than you might have guessed.
Doing it the dirty way
The keyboard is mapped to System VIA port A (accessed through &FE41 or &FE4F for "no handshake", whatever the hell that means...). The bottom 7 bits are used to specify which key you wish to poll, and the top bit returns whether the key is pressed or not.
So, first we need to set the Data Direction Register A to specify that the bottom 7 bits are outputs, and the top bit is an input. Hence:
LDA #&7F:STA &FE43
Now, System VIA port A is also shared by the sound chip and the speech chip, so before we can access the keyboard, we need to enable it over the other two possibilities. This is done via the "addressable latch" in System VIA port B.
The addressable latch controls a miscellany of "stuff" (AUG page 419) - there's a further layer of indirection here: we have to set up the bottom 4 bits of System VIA port B as outputs, and then we write the "bit number" of the addressable latch bit we wish to write in bits 0-2, and the value to write in bit 3.
To enable keyboard we have to pull bit 3 of the addressable latch low, so here's how we do this:
LDA #&0F:STA &FE42 \ allow write to addressable latch LDA #&03:STA &FE40 \ set bit 3 to 0
So, that's all the initialisation we need to do.
Now, reading a key is simplicity itself! We need the internal key number of the key - either consult the table on AUG page 142, or take the negative INKEY code of the key, make it positive, and subtract 1. (e.g. space (-99) becomes 98).
Then, write to System VIA port A, and read it back. The top bit will tell you whether the key is pressed or not (set=pressed):
LDA #97:STA &FE4F:LDA &FE4F \ N flag = whether 'Z' pressed
All of this has to be done either with interrupts disabled, or a custom IRQ handler in place which doesn't let the OS in, otherwise all of the setup will be undone by OS code (because these values are changed to play sounds, for example).
And that's it! How to read a key in 14(ish) clock cycles.