Keyboard Buffer and Ctrl/Shift/CBM etc

You need an actual VIC.

Moderator: Moderators

SparkyNZ
Vic 20 Enthusiast
Posts: 153
Joined: Tue Jan 18, 2011 2:23 am

Keyboard Buffer and Ctrl/Shift/CBM etc

Post by SparkyNZ »

I've made a rubbish Vic emulator (I have my reasons :-) ) .. I've managed to intercept keys on Windows and place them into the Vic's keyboard buffer at $277 and by setting $c6 to 1 (for 1 keypress). That works great - I can get most keys to work.

The problem I'm having is trying to understand how Ctrl, Shift and CBM work. I'd read that $28d should contain $4 for CTRL, $2 for CBM and $1 for SHIFT.

When I set $28d, $277 and $c6 at the same time, I'm not getting any change in key behaviour. If I press SHIFT + 'A', I put ASCII 65 into the keyboard buffer, set $28d to 1 and I still see 'A' printed on the screen.

What am I missing?
User avatar
javierglez
Vic 20 Hobbyist
Posts: 107
Joined: Sat Jun 03, 2017 3:33 pm

Re: Keyboard Buffer and Ctrl/Shift/CBM etc

Post by javierglez »

I guess your emulator should take care of the via registers (the keyboard matrix) and let the kernal interrupt do the updates of these registers you are talking about. I guess otherwise you are rewriting the rom or designing your own system.
In this case, I guess you should compute the correct ascii code yourself and 653 is of no use. The offset for "lowercase" maybe 32.
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: Keyboard Buffer and Ctrl/Shift/CBM etc

Post by Mike »

What is put into the keyboard buffer by the KERNAL is already the fully decoded result after the modifier keys have been read and the corresponding decoding table has been chosen.

You should note that the routine that does this decoding is vectored (via $028F) so a program is free to remap the keyboard to its liking. This is used for example by MINIPAINT and MG Text Edit: MINIPAINT provides own codes for CBM-1..8 and MG Text Edit remaps the keyboard to a true 7-bit ASCII keyboard. As is, the keyboard entry method in your emulator will break these programs.

(mod: thread moved to Emulation and Cross Development section)
SparkyNZ
Vic 20 Enthusiast
Posts: 153
Joined: Tue Jan 18, 2011 2:23 am

Re: Keyboard Buffer and Ctrl/Shift/CBM etc

Post by SparkyNZ »

Mike wrote: Fri Jan 26, 2024 5:04 am What is put into the keyboard buffer by the KERNAL is already the fully decoded result after the modifier keys have been read and the corresponding decoding table has been chosen.
That makes sense Mike. Cursor Left and Cursor Up I have already got working - and that is really Cursor Right and Cursor Down plus the Shift modifier I suppose.

I'll just need to figure out how to get Ctrl-0 thru 9 etc. I was trying to get RVS ON to work.

For the Shift+Letter graphics, I did try putting char + 64 into the keyboard buffer (such as 'A' + 64). What value would be used for Shift+'A' and CBM+'A'?

I've been using this chart: https://c64os.com/post/Vic20C64SuperChart but I still get confused.
SparkyNZ
Vic 20 Enthusiast
Posts: 153
Joined: Tue Jan 18, 2011 2:23 am

Re: Keyboard Buffer and Ctrl/Shift/CBM etc

Post by SparkyNZ »

javierglez wrote: Fri Jan 26, 2024 2:23 am I guess your emulator should take care of the via registers (the keyboard matrix) and let the kernal interrupt do the updates of these registers you are talking about. I guess otherwise you are rewriting the rom or designing your own system.
In this case, I guess you should compute the correct ascii code yourself and 653 is of no use. The offset for "lowercase" maybe 32.
I did wonder if I should have been doing this at a lower level - mimicking the keyboard matrix as you suggest. I've just been trying to figure this out from various commented ROM disassembly sources (including the C# Hacking texts). I still call the IRQ routine for flashing the cursor etc so I'd be happy to mimick VIA register values there if I have to.

I do have my own 6502 homebrew machine that I'd like to get CBM BASIC running on as well.. so there are quite a few things for me to figure out. I still haven't figured out the separation between the Vic's screen editor and BASIC itself (like where the kernal ends and the BASIC begins from a functional point of view - such as taking the keypresses using the kernal and starting the BASIC token parsing etc). So yeah, I thought a software emulator would be the easiest way to tinker with things.
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: Keyboard Buffer and Ctrl/Shift/CBM etc

Post by Mike »

SparkyNZ wrote:I still haven't figured out the separation between the Vic's screen editor and BASIC itself (like where the kernal ends and the BASIC begins from a functional point of view - such as taking the keypresses using the kernal and starting the BASIC token parsing etc).
There is a clear hierarchy between BASIC and KERNAL: BASIC calls KERNAL functions to perform some of its work, but in turn, the KERNAL never calls routines in the BASIC interpreter - the sole exceptions being BASIC cold start (power on or reset) or warm start (NMI on STOP/RESTORE). In these two cases, the stack is purged and there is no return to the KERNAL except by those calls done by BASIC.

The BASIC interpreter calls CHRIN in the KERNAL to fill the input line buffer from the input. The first call of CHRIN stops the calling program, switches on the cursor and remains in the screen editor until the user enters the line with the RETURN key. Then CHRIN returns with the first character on the line, further calls of CHRIN directly return with all remaining characters until end-of-line is found. CHRIN then returns code 13 (CR) and the next call once again enters the screen editor.
I'll just need to figure out how to get Ctrl-0 thru 9 etc. I was trying to get RVS ON to work.

For the Shift+Letter graphics, I did try putting char + 64 into the keyboard buffer (such as 'A' + 64). What value would be used for Shift+'A' and CBM+'A'?
You could find out these codes by doing a PRINTASC("...") on the VIC-20 itself. The CBM codes actually are quite jumbled (i.e. not in order like the shifted codes) - I once decoded them for my PETSCII printer, see here: "Standards for quoted PETSCII?"

Note there exist 'copies' where different PETSCII codes result in the same screen codes. The 'canonical' correspondence between screen codes and PETSCII (which the screen editor also uses when scanning from the screen to deliver the data for keyboard CHRIN) is:

Code: Select all

with X=0..31:

PETSCII     screen code

   32+X <-> 32+X
   64+X <->    X
  160+X <-> 96+X
  192+X <-> 64+X (_except_ X=30!)
    255 <->   94
(See: Re: Screen values vs PETSCII)

Ultimately, the easiest way to get keyboard input correct will be to mimic the keyboard matrix and VIA registers, and let the KERNAL do all the decoding work. Otherwise you'll get stuck in all sorts of definitions by cases.
SparkyNZ
Vic 20 Enthusiast
Posts: 153
Joined: Tue Jan 18, 2011 2:23 am

Re: Keyboard Buffer and Ctrl/Shift/CBM etc

Post by SparkyNZ »

Mike wrote: Fri Jan 26, 2024 8:58 am Ultimately, the easiest way to get keyboard input correct will be to mimic the keyboard matrix and VIA registers, and let the KERNAL do all the decoding work. Otherwise you'll get stuck in all sorts of definitions by cases.
That is starting to sound like the safest option. I wonder where the best place is to start.. either the ROM disassembly or the schematic itself with the 6522.. or both.

I found this post with a diagram of the matrix: https://www.lemon64.com/forum/viewtopic.php?t=68210

It says "Write to Port B($9120)column, Read from Port A($9121)row".. so I guess the keyboard is read by polling each column to see which key(s) are pressed on the row?

I better go check the ROM disassembly to confirm that thought..

Update: OK, so the ROM disassembly contains this nice matrix chart:

Code: Select all

LAB_9120	= $9120		; VIA 2 DRB, keyboard column drive
LAB_9121	= $9121		; VIA 2 DRA, keyboard row port
					; Vic 20 keyboard matrix layout
					;	c7	c6	c5	c4	c3	c2	c1	c0
					;   +-----------------------------------------------------------------
					; r7|	[F7]	[F5]	[F3]	[F1]	[DN]	[RGT]	[RET]	[DEL]
					; r6|	[Home][UP]  =	[RSH]	/	;	*	£
					; r5|	-	@	:	.	,	L	P	+
					; r4|	0	O	K	M	N	J	I	9
					; r3|	8	U	H	B	V	G	Y	7
					; r2|	6	T	F	C	X	D	R	5
					; r1|	4	E	S	Z	[LSH]	A	W	3
					; r0|	2	Q	[CBM]	[SP]	[RUN]	[CTL]	[LFT]	1
The keyboard read routine would appear to be here:

Code: Select all

LAB_EB1E
	LDA	#$00			; clear A
	STA	LAB_028D		; clear keyboard shift/control/c= flag
	LDY	#$40			; set no key
	STY	LAB_CB		; save which key
	STA	LAB_9120		; clear VIA 2 DRB, keyboard column
	LDX	LAB_9121		; get VIA 2 DRA, keyboard row
	CPX	#$FF			; compare with all bits set
	BEQ	LAB_EB8F		; if no key pressed clear current key and exit (does
					; further BEQ to LAB_EBBA)

	LDA	#$FE			; set column 0 low
	STA	LAB_9120		; set VIA 2 DRB, keyboard column
	LDY	#$00			; clear key count
	LDA	#<LAB_EC5E		; get decode table low byte
	STA	LAB_F5		; set keyboard pointer low byte
	LDA	#>LAB_EC5E		; get decode table high byte
	STA	LAB_F6		; set keyboard pointer high byte
LAB_EB40
	LDX	#$08			; set row count
	LDA	LAB_9121		; get VIA 2 DRA, keyboard row
	CMP	LAB_9121		; compare with itself
	BNE	LAB_EB40		; loop if changing

LAB_EB4A
	LSR				; shift row to Cb
	BCS	LAB_EB63		; if no key closed on this row go do next row?
	PHA				; save row
	LDA	(LAB_F5),Y		; get character from decode table
	CMP	#$05			; compare with $05, there is no $05 key but the control
					; keys are all less than $05
	BCS	LAB_EB60		; if not shift/control/c=/stop go save key count

					; else was shift/control/c=/stop key
	CMP	#$03			; compare with $03, stop
	BEQ	LAB_EB60		; if stop go save key count and continue

					; character is $01 - shift, $02 - c= or $04 - control
	ORA	LAB_028D		; OR keyboard shift/control/c= flag
	STA	LAB_028D		; save keyboard shift/control/c= flag
	BPL	LAB_EB62		; skip save key, branch always

LAB_EB60
	STY	LAB_CB		; save key count
LAB_EB62
	PLA				; restore row
LAB_EB63
	INY				; increment key count
	CPY	#$41			; compare with max+1
	BCS	LAB_EB71		; exit loop if >= max+1

					; else still in matrix
	DEX				; decrement row count
	BNE	LAB_EB4A		; loop if more rows to do

	SEC				; set carry for keyboard column shift
	ROL	LAB_9120		; shift VIA 2 DRB, keyboard column
	BNE	LAB_EB40		; loop for next column, branch always

LAB_EB71
	JMP	(LAB_028F)		; evaluate the SHIFT/CTRL/C= keys, LAB_EBDC	
	
So the matrix appears to be "polled" by masking out the column you want? c2 is bit 2, so the mask would appear to be $FB in the code. Likewise, c3 is bit 3, so we have a mask of $F7 etc

I guess that loop at EB40 is to debounce the key value read?

I'll see if I can implement a matrix of my own and return the various values in $9121 when a read is attempted.. using the column value in $9120. Sounds like fun :-) I was going to try and understand all of what's going on in the above code.. but I may be able to get away with being a little ignorant of the details as long as I provide the correct values in $9121 when asked.
SparkyNZ
Vic 20 Enthusiast
Posts: 153
Joined: Tue Jan 18, 2011 2:23 am

Re: Keyboard Buffer and Ctrl/Shift/CBM etc

Post by SparkyNZ »

Mike wrote: Fri Jan 26, 2024 8:58 am Ultimately, the easiest way to get keyboard input correct will be to mimic the keyboard matrix and VIA registers, and let the KERNAL do all the decoding work. Otherwise you'll get stuck in all sorts of definitions by cases.
Hmmm. I've logged all of the writes to $9120. I'm returning $10 for 'M' when column 4 is requested ($ef previously stored in $9120, read of $9121) but M isn't appearing on the screen.

I'm not an expert using the monitor on Vice so I haven't been able to figure out how to watch the values of $9120/9121 during keypresses.

Any idea what I should be seeing for a keypress of 'M' for those 2 memory addresses?

Code: Select all

LAB_EB40
	LDX	#$08			; set row count
	LDA	LAB_9121		; get VIA 2 DRA, keyboard row
	CMP	LAB_9121		; compare with itself
	BNE	LAB_EB40		; loop if changing

LAB_EB4A
	LSR				; shift row to Cb
	BCS	LAB_EB63		; if no key closed on this row go do next row

	PHA				; save row
	LDA	(LAB_F5),Y		; get character from decode table
	CMP	#$05			; compare with $05, there is no $05 key but the control
					; keys are all less than $05
	BCS	LAB_EB60		; if not shift/control/c=/stop go save key count

					; else was shift/control/c=/stop key
	CMP	#$03			; compare with $03, stop
	BEQ	LAB_EB60		; if stop go save key count and continue

					; character is $01 - shift, $02 - c= or $04 - control
	ORA	LAB_028D		; OR keyboard shift/control/c= flag
	STA	LAB_028D		; save keyboard shift/control/c= flag
	BPL	LAB_EB62		; skip save key, branch always

LAB_EB60
	STY	LAB_CB		; save key count
LAB_EB62
	PLA				; restore row
LAB_EB63
	INY				; increment key count
	CPY	#$41			; compare with max+1
	BCS	LAB_EB71		; exit loop if >= max+1

					; else still in matrix
	DEX				; decrement row count
	BNE	LAB_EB4A		; loop if more rows to do

	SEC				; set carry for keyboard column shift
	ROL	LAB_9120		; shift VIA 2 DRB, keyboard column
	BNE	LAB_EB40		; loop for next column, branch always
SparkyNZ
Vic 20 Enthusiast
Posts: 153
Joined: Tue Jan 18, 2011 2:23 am

Re: Keyboard Buffer and Ctrl/Shift/CBM etc

Post by SparkyNZ »

After reading a few more posts, I thought perhaps I should be returning 0 for keys that are pressed down rather than 1.. So now I'm returning $ef for M in $9121.. but still no keypresses being detected by the VIC. :-(

I must be missing something else?
User avatar
srowe
Vic 20 Scientist
Posts: 1340
Joined: Mon Jun 16, 2014 3:19 pm

Re: Keyboard Buffer and Ctrl/Shift/CBM etc

Post by srowe »

Here's the matrix
keymatrix.png
So 'M' is column 4 (b4), row 'E' (b4).

The KERNEL routine loops over each column setting each bit in turn to be 0 and then reading the row.

Pressing a key causes the row/column combination to shorted. The 6522 pulls inputs high when unconnected so this results in the value 11110111 being returned for column 4.
groepaz
Vic 20 Scientist
Posts: 1187
Joined: Wed Aug 25, 2010 5:30 pm

Re: Keyboard Buffer and Ctrl/Shift/CBM etc

Post by groepaz »

This should be fairly straight forward to implement.... you can ignore all the details about VIA if all you are after is keyboard input (just assume port 1 is all output, port 2 is all input). Then as you noticed, the logic is low-active (you will see that at many other places). One thing to consider is that the kernal takes some time to register a keystroke, and the scanner runs in a timer interrupt that is not in sync with the raster (at least on C64 - it's the same on vic20 i believe), so in the emulator when your keyboard input is processed once per frame, you need to "press" the key for at least two frames to make it work reliable. For a first test, to see if it works at all, use SPACE - since that will give visual feedback even when the key is just pressed and never released.
I'm just a Software Guy who has no Idea how the Hardware works. Don't listen to me.
SparkyNZ
Vic 20 Enthusiast
Posts: 153
Joined: Tue Jan 18, 2011 2:23 am

Re: Keyboard Buffer and Ctrl/Shift/CBM etc

Post by SparkyNZ »

srowe wrote: Sat Jan 27, 2024 3:41 am Pressing a key causes the row/column combination to shorted. The 6522 pulls inputs high when unconnected so this results in the value 11110111 being returned for column 4.
I've tried reversing my bit orders for both column and row. I now return F7 for 'M' but nothing appearing on the screen still. I guess I'll have to turn on my disassembly in the logs again and try figure out why there's no 'M' making it into keyboard buffer.
groepaz wrote: Sat Jan 27, 2024 3:49 am so in the emulator when your keyboard input is processed once per frame, you need to "press" the key for at least two frames to make it work reliable.
If anything, I would have expected too many 'M' keys to be pressed since I should be returning the values when requested until I release the key.

There'll be a stupid bug here - I'm probably returning the wrong value for when no keys are pressed or something.
SparkyNZ
Vic 20 Enthusiast
Posts: 153
Joined: Tue Jan 18, 2011 2:23 am

Re: Keyboard Buffer and Ctrl/Shift/CBM etc

Post by SparkyNZ »

I don't understand what this bit of code is doing:

Code: Select all

LAB_EB1E
	LDA	#$00			; clear A
	STA	LAB_028D		; clear keyboard shift/control/c= flag
	LDY	#$40			; set no key
	STY	LAB_CB		; save which key
	STA	LAB_9120		; clear VIA 2 DRB, keyboard column        ### HERE
	LDX	LAB_9121		; get VIA 2 DRA, keyboard row             ### HERE
	CPX	#$FF			; compare with all bits set
	BEQ	LAB_EB8F		; if no key pressed clear current key and exit (does
					; further BEQ to LAB_EBBA)
I've stored the 'M' keypress in matrix. When 0 is written to $9120 above, what is supposed to be inside $9121? Is $9121 supposed to contain the row index or mask for the last key pressed?? My code is jumping to EB8F thinking that there are no keypresses.

I'm confused about the use of $9121 here because I thought $9121 was only populated once $9120 was written to with a particular column mask?

UPDATE: I have just stored $01 for the first check and that seems to be working better. I've managed to pull out and print M and Q on the screen and then no more keys go through. Likewise, if I press Q first, no more keys go through - something else for me to sort out but at least it does seem to be identifying the correct column/row in my matrix.
User avatar
srowe
Vic 20 Scientist
Posts: 1340
Joined: Mon Jun 16, 2014 3:19 pm

Re: Keyboard Buffer and Ctrl/Shift/CBM etc

Post by srowe »

This initial test is to check if any key in the matrix is down. Remember this function is called from the interrupt handler, it's trying to avoid burning CPU cycles when there's no keyboard input. Setting the column to all zeros mean the read of the row will be the union of all keys that are down.

Your emulator code needs to work the same. Remember the modifier keys (Shift, Ctrl, C=) are just keys in the matrix and therefore it needs to map the OS key into potentially multiple keys down.
SparkyNZ
Vic 20 Enthusiast
Posts: 153
Joined: Tue Jan 18, 2011 2:23 am

Re: Keyboard Buffer and Ctrl/Shift/CBM etc

Post by SparkyNZ »

Well.. I had the wrong value written to my matrix (typo!) so that's why some keypresses wouldn't work. The amount of diassembly debug was also slowing things down that I was missing the key up event.. so I think I have this mostly working now :-)

I haven't implemented colour on the screen yet but that will be my next job.. then I can play with Ctrl+Number keys and the likes.. just like I did when was 9 :-)

My next challenge may well be to see if I can implement my own kernel or at least use the BASIC ROM from my own 80x60 screen editor. Having my "Vic emulator" should help with hooking that up.
Post Reply