WACCI 138 Index - Home Page www.wacci.org.uk


01 - Thanx & Stuff 02 - Fair Comment 03 - A to Z of the CPC 04 - From the Archives
05 - Twenty Questions 06 - Keyboard Scanning 07 - Meet the Relatives 08 - Programmers' Patch
09 - Genesis 10 - Famous Last Words

img_138_06_01.gif - 17,556 bytes

Keyboard Scanning

James Hoskisson explains the CPC's rather arcane method of interpreting what you type on the keyboard

Hi folks - it's been a while! Seeing as I'm currently averaging about one article every year I can't quite remember where I got up to with this series. I think some research may be in order...
  Ah yes (he says, whilst reading his previous article). I remember now: keyboard scanning. I sincerely hope one of the other articles was about the PPI, or this article will be totally incomprehensible - not that that's anything new!

To the point

Anyway, keyboard scanning. It's really easy to do but the way that the CPC designers implemented it makes it a pain in the posterior to carry out. Anyone who has had to scan the keyboard directly will agree with me. It certainly makes you appreciate why some games designers chose such silly combinations of keys to move the sprites around the screen!
  But now I've finally managed to declare keyboard scanning to be simultaneously simple and awkward, I'd better explain how you might do it. (As an aside on keyboards, if you notice any semicolons in this article instead of apostrophes that would be because I've almost exclusively used PCs to write anything lengthy over the last few years, so I'm still not fully 're-used' to the CPC keyboard. Of course you could just put it down to bad editing... But with Richard being the consumate professional (bwah-ha-ha - Richard) I'm sure he'd have a good reason for it, should such an inexcusable thing occur!)

Go through the PPI and take a left...

The reason that keyboard scanning is so damn inconvenient is that there is no way to get at the keyboard directly from the CPU. The design of the CPC means that you have to go through the PPI and the PSG before you can actually get at the keyboard.
  Those of you who were paying attention in the last issue would know that the PSG is designed to generate sound. The rather obvious question is "Why does this chip have anything to do with keyboard scanning?". The obvious answer, of course, is "It's the CPC - since when has any of it been logical?".
  The slightly more helpful answer is probably that the PSG has an I/O port on it, which is just what is needed to check the state of the keyboard. So the designers of the CPC decided to use this, rather than jack up the cost by adding more chips.
  The real puzzler in this, though, is why there are so many trivial functions (such as checking the circuit board links to see what makers name should be displayed on start up etc.) connected to the much superior PPI chip, when the keyboard scanning, which is carried out much more often, is connected to the PSG, which is slower and more cumbersome to use.
  My theory is that the designers of our beloved CPC fixed everything up and forgot about the keyboard; so they just stuck it on the PSG port, rather than having to mess about rearranging everything!

Don't forget your keys

The keyboard isn't very complicated, from a hardware point of view. Basically all it is is a set of switches that return a 0 if they are depressed (no, not that sort of depressed) and a 1 if they are up. This counter-intuitive way of representing whether a key is held down or not is a consequence of the electronics, in order to save the need for extra components, and therefore saving money.
  Since there are around 74 keys on the CPC keyboard (he says, after counting them) this is a lot of inputs. The way they are arranged is to split them up into 10 lines of 8 bits, where each bit represents the state of one of the keys. This is very convenient since each line can now be represented as one byte, and there are even 7 bits left over to check the state of the joystick port. Now that is convenient.

Runb, daddy, runb

One thing that I should also mention at this juncture is the dreaded 'Keyboard Clash'. You may already have noticed this effect when you've been using the keyboard. I know I have, because I always get a 'b' on the end of a 'run' command when I type it too fast.
  The problem is that when certain sets of three keys are held down, a fourth 'ghost' key appears. The 'ghost' key for any other three keys can be figured out by looking at the keyboard line allocation table.
  The easiest way to figure it out is to pick two keys that are either horizontally or vertically adjacent. If you then imagine a straight line going from one of the keys to the other, you can draw two other lines at 90 degrees, which go through the two adjacent keys. These two parallel lines then tell you which keys will be 'ghosted'.
  If you pick a key on one of the lines and hold it down in conjunction with the two keys that you originally selected then the key on the adjacent line will be ghosted. This is why you will get a 'b' if you hold down 'r, 'u', 'n', and an 'r' if you hold down 'b', 'u', 'n'...
  I've just realised that the keyboard clash is harder to explain than I thought. Unfortunately I think that's the best I can do!
  There is, basically, no solution to the keyboard clash problem. The only thing you can do is to choose keys that won't clash when your writing your high speed pure assembler super game. I don't think it would cause a problem in most situations, since it is quite unlikely that anyone would want to hold down three keys (perhaps that's why they abandoned Streetfighter II - Richard), but I suppose it's best to err on the side of caution.

Down to the nitty gritty

I've already mentioned that you need to go through the PSG to get at the keyboard, which entails setting up the PPI to output values to the PSG so that it will select the I/O register (register 14).
  Once this is done you need to tell the PSG to read from the I/O register, which is achieved by setting bit 6 of register 7 (the PSG mixer register). Now we set PPI port A back to input mode and we're away. I won't bother going into detail on how to do all this, since it was explained in the last couple of articles. I know Richard wanted articles but I don't think he would appreciate a treatise on the CPC hardware!
  Right, so we've got the PSG I/O port and port A of the PPI set up in input mode. Now all we need to do is select which keys we want to check. This is easily achieved (fortunately) using port C of the PPI. This port has 4 bits set aside for selecting which keyboard line you want to select. This allows a maximum of 16 different lines to be selected, but only the first 10 numbers will actually do anything. All the other lines will return &FF if you check the PSG I/O port, so it's pretty pointless selecting them.
  The keys are laid out as shown in the table on this page. You can see that the number of the line that you select alters the keys that output to the PSG I/O port. The bit number gives the state of the respective key, so if you selected line 7, for example, the byte returned from the PSG I/O port would give the state of the X, C, D, S, W, E, 3, and 4 keys.
  The directions on line 9 are for the first joystick ('Joy 0'). All of the Joy 1 inputs are mapped over line 6, in exactly the same order. This means that line 6 has a dual function and the CPC sees a movement on the second joystick as being identical to a key press.
  'Spare' refers to the pin on the joystick port that doesn't do anything, in case you were wondering. It was used for the middle button of the AMX mouse, as I recall, but I don't know of anything else that used it.
  That's basically all there is to accessing the keyboard. Once you've got the correct byte from the PSG it's just a matter of decoding it so that you test the bit that corresponds to the key that you want. I suppose it's worth mentioning that the byte returned from the PSG I/O port is the instantaneous state of the respective keys on the keyboard. There's none of this fancy interrupt genereation or anything on the CPC! It's just a matter of polling the keyboard at reasonably short intervals. The CPC hardware may be slow by today's standards, but I don't think anybody can type faster than 1.5 million characters per minute!
  We've got to the stage where I do a bit of an example. It's off the top of my head I'm afraid because I'm currently assemblerless, so if you spot anything that doesn't look quite right it's probably because it's not!
  All that remains is to tell you about the Centronics Port Latch, since that will have to go in somewhere.

Printing stuff

The Centronics Port latch is incredibly simple. All you have to do is figure out the byte you want to send to the printer and then OUT it to &EF00. This byte is then output to the printer, except for bit 7 being inverted on the way.
  The byte you send is split up into the data for the printer and the strobe line. The strobe line is bit 7 with bits 0-6 being the data you want to send to the printer. The CPC only has a 7 bit printer port, so the high order data bit is always set to 0.
  The strobe line is just used to tell the printer that you are sending it data. It should be set high when you are sending data in the other 7 bits of the byte.
  The only other line that is concerned with the printer is the busy line, which is mapped to PPI port B, and should be checked before you try to send anything. If the printer is busy when you try to send something then it will probably just ignore it. I should probably mention that the busy line is high when the printer is busy and low if it isn't, so a simple BIT instruction can be used to determine this.
  See, wasn't that simple? That just about wraps up everything I wanted to say. I currently can't think of anything to write for another issue, but you never know...

The CPC keyboard grid

Keyboard			           Bit number
line	7	6	5	4	3	2	1	0

0	f.	ENTER	f3	f6	f9	Down	Right	Up
1	f0	f2	f1	f5	f8	f7	COPY	Left
2	CTRL	\	SHIFT	f4	]	RETURN	[	CLR
3	.	/	:	;	P	@	-	^
4	,	M	K	L	I	O	9	0
5	SPACE	N	J	H	Y	U	7	8
6	V	B	F	G	T	R	5	6
7	X	C	D	S	W	E	3	4
8	Z	CAPS	A	TAB	Q	ESC	2	1
9	DEL	Spare	Fire 1	Fire 2	Right	Left	Down	Up
		Row 9, bits 6-0: joystick controls
; Keyboard Scanning Routine

;; Initialise PSG and PPI

DI
; Disable the interrupts so the firmware won't butt in.
LD BC,&F40E	;Select PSG register 14
OUT (C),C 	;(assuming PPI port A is in output mode to start with!)
LD BC,&F6C0	;Tell PSG that we're trying to get it to select a register.
OUT (C),C
XOR A		;Tell the PSG to go to sleep once it's done that.
OUT (C),A
LD BC,&F792	;Set PPI port A to output.
OUT (C),C

;; Get keyboard line from PSG I/O port.
LD BC,&F645	;Tell PSG that we want to read from its port, while
OUT (C),C	;simultaneously selecting keyboard line 5.
LD B,&F4	;Read I/O port value in from PSG.

.loop
IN A,(C)	;Stick the byte we read from the keyboard in A.
RLCA 		;If bit 7 is set then carry will be set.
JR C, loop	;Keep looping until SPACE has been pressed.

LD BC,&F782  	;Now return the PPI to the way we found it.
OUT (C),C
LD BC,&F600	;Tell PSG to go to sleep.
OUT (C),C
RET		;Return to BASIC and hope for the best!

Okay, so that program is breathtakingly unimaginative in that it doesn't do anything until you press SPACE... and then it doesn't do anything. But you get the gist. If you're lucky it may even work directly from BASIC - now that would be fun, wouldn't it? - James


01 - Thanx & Stuff 02 - Fair Comment 03 - A to Z of the CPC 04 - From the Archives
05 - Twenty Questions 06 - Keyboard Scanning 07 - Meet the Relatives 08 - Programmers' Patch
09 - Genesis 10 - Famous Last Words

WACCI 138 Index - Home Page www.wacci.org.uk