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.