changeset 11:b2212c9de7b7

Initial implementation of keyboard scan and setup This implements the keyboard scanning routine, including decoding into the keyboard ring buffer. Also include resetting the state on reset. It is not, however, active yet.
author William Astle <lost@l-w.ca>
date Sun, 06 Nov 2022 00:27:04 -0600
parents 8d4c0ffa2308
children 981a5ed51a4d
files src/lwbasic.s
diffstat 1 files changed, 214 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/lwbasic.s	Fri Nov 04 18:40:47 2022 -0600
+++ b/src/lwbasic.s	Sun Nov 06 00:27:04 2022 -0600
@@ -31,6 +31,13 @@
                 *pragmapop list
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ; Various constants
+keyb_bufflen    equ 64                          ; keyboard ring buffer length
+keyb_repdeli    equ 15                          ; ticks before initial repeat
+keyb_repdelr    equ 5
+keyb_caps       equ 0x80                        ; capslock enabled
+keyb_alt        equ 0x04                        ; alt pressed
+keyb_ctrl       equ 0x02                        ; ctrl pressed
+keyb_shift      equ 0x01                        ; shift pressed
                 ifdef COCO3
 ; GIME INIT0
 GIME_COCO       equ 0x80                        ; Set for coco2 compatible mode (video display)
@@ -189,6 +196,12 @@
 RSTFLG          rmb 1                           ; 0x55 if RSTVEC is valid
 RSTVEC          rmb 2                           ; points to warm start routine (must start with NOP)
 console_curptr  rmb 2                           ; current cursor pointer for console driver
+keyb_flags      rmb 1                           ; shift flags for the keyboard
+keyb_joystate   rmb 1                           ; joystick button state
+keyb_repdel     rmb 1                           ; repeat delay
+keyb_curscan    rmb 1                           ; current repeating scan code
+keyb_buffw      rmb 2                           ; keyboard ring buffer write pointer
+keyb_buffr      rmb 2                           ; keyboard ring buffer read pointer
                 rmb 0x100-*                     ; make sure the stuff that isn't direct page is outside of it
 SW3VEC          rmb 3                           ; SWI3 vector (for compatibility)
 SW2VEC          rmb 3                           ; SWI2 vector (for compatibility)
@@ -196,7 +209,9 @@
 NMIVEC          rmb 3                           ; NMI vector (for compatibility)
 IRQVEC          rmb 3                           ; IRQ vector (for compatibility)
 FRQVEC          rmb 3                           ; FIRQ vector (for compatibility)
-                rmb 0xee                        ; unused
+keyb_state      rmb 8                           ; rollover table state
+keyb_buff       rmb keyb_bufflen                ; the keyboard ring buffer
+                rmb 0x200-*                     ; unused
 textscreen      rmb 0x200                       ; the actual text screen (must be on 512 byte alignment)
                 org 0x8000                      ; the hardware puts the ROMs here; it's not negotiable
 START           orcc #0x50                      ; make sure interrupts are disabled if we come here in an unusual way
@@ -398,7 +413,8 @@
                 else
 warmstart       nop                             ; flag warm start routine as valid
                 endc
-                jsr console_clear                ; clear screen
+                jsr console_clear               ; clear screen
+                jsr keyb_reset                  ; reset the keyboard
                 bra *
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ; System startup message
@@ -408,7 +424,202 @@
                 fcc 'WIZARD ENTERPRISES INC.\r\n'
                 fcn '\n'
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Console output driver
+; Console keyboard input driver
+;
+; Reset the keyboard state, which means clearing the buffer and state flags
+keyb_reset      ldx #keyb_buff                  ; point to start of keyboard ring buffer
+                stx keyb_buffw                  ; set write point there
+                stx keyb_buffr                  ; set read point there (pointers equal means empty buffer)
+                clr keyb_flags                  ; reset keyboard state flags
+                clr keyb_joystate               ; clear joystick button state
+                clr keyb_curscan                ; stop any keyboard repeating
+                rts
+; The PIA reading loop is specifically set up to NOT read PIA0.DB to avoid prematurely clearing the VSYNC interrupt flag
+; since that could lead to missing interrupts. Reading PIA0.DA will clear the HSYNC interrupt flag but that's less of a
+; problem because that interrupt is basically useless.
+;
+; As a note, doing the PIA read in a loop ends up using an extra 27 CPU cycles for the BCS instruction. However, it
+; saves 70 code bytes. The trade off seems worth it in this case.
+;
+; Once keyboard state is read, we do the following:
+;
+; * update the state of SHIFT, CTRL, ALT
+; * decode all other keys in a loop
+keyb_read       leas -9,s                       ; make temporary buffer
+                leay 1,s                        ; point to temporary state buffer
+                clra                            ;* set to 0xff with C clear; start by strobing no columns for joystick
+                deca                            ;* then rotate the 0 bit through to do the actual keyboard columns
+                ldu #keyb_state                 ; point to end of keyboard state buffer
+                sta PIA0.DB                     ; strobe no columns
+                ldb PIA0.DA                     ; get joystick button state
+                stb keyb_joystate               ; save it for later when needed
+                andb #0x7f                      ; mask off comparator (pretend "button" down)
+                stb ,s                          ; save button/comparator state mask
+                rola                            ; set up for first column
+keyb_read0      sta PIA0.DB                     ; set column strobe
+                ldb PIA0.DA                     ; read row data
+                eorb ,u+                        ; set bits if state changed
+                andb ,s                         ; mask off comparator and active buttons
+                stb ,y+                         ; save state change information
+                rola                            ; shift to next column
+                bcs keyb_read0                  ; brif we haven't done the last column
+                lda -1,y                        ; get row data for SHIFT
+                anda #0x40                      ; did it change state?
+                beq keyb_read1                  ; brif not
+                eora -1,y                       ; remove it from the state change records
+                sta -1,y
+                ldb #keyb_shift                 ; flip the shift flag
+                eorb keyb_flags
+                stb keyb_flags
+keyb_read1      lda -4,y                        ; get row data for CTRL
+                anda #0x40                      ; did it change state?
+                beq keyb_read2                  ; brif not
+                eora -4,y                       ; clear from state change records
+                sta -4,y
+                ldb #keyb_ctrl                  ; flip the ctrl flag
+                eorb keyb_flags
+                stb keyb_flags
+keyb_read2      lda -5,y                        ; get row data for ALT
+                anda #0x40                      ; did it change state?
+                beq keyb_read3                  ; brif not
+                eora -5,y                       ; clear from state change records
+                sta -5,y
+                ldb #keyb_alt                   ; flip the ALT flag
+                eorb keyb_flags
+                stb keyb_flags
+keyb_read3      ldd #0x3701                     ; initialize bit probe and counter
+keyb_read4      leay -1,y                       ; move pointers to next byte
+                leau -1,u
+keyb_read5      bitb ,y                         ; did this key change state?
+                bne keyb_read7                  ; brif so
+keyb_read6      lslb                            ; shift bit probe
+                suba #8                         ; adjust scan code
+                bpl keyb_read5                  ; brif we haven't done all bits
+                ldb ,y                          ; update state flags for this byte
+                eorb ,u
+                stb ,u
+                ldb #1                          ; reset bit probe
+                deca                            ; adjust for next column
+                adda #0x38                      ; reset scan code
+                cmpa #0x30                      ; done all bytes?
+                bhs keyb_read4                  ; brif not - do another
+                leas 9,s                        ; clean up stack
+                ldb keyb_curscan                ; is key repeating?
+                bne keyb_read9                  ; brif so
+keyb_reada      rts
+keyb_read7      bitb ,u                         ; get current state
+                beq keyb_read8                  ; brif key pressed (make)
+                cmpa keyb_curscan               ; is it the currently repeating key?
+                bne keyb_read6                  ; brif not - don't need to do anything
+                clr keyb_curscan                ; clear the current repeat
+                bra keyb_read6
+keyb_read8      clr ,s                          ; flag keyboard as not idle
+                sta keyb_curscan                ; save current scan code as the repeating one
+                pshs d                          ; save current bit probe and scan code
+                ldb #keyb_repdeli               ; intialize repeat delay
+                stb keyb_repdel
+                bsr keyb_tobuff                 ; decode key to buffer
+                puls d                          ; restore scan code and bit probe
+                bra keyb_read6                  ; go handle the next bit
+keyb_read9      dec keyb_repdel                 ; is it time to repeat it?
+                bne keyb_reada                  ; brif not
+                ldb #keyb_repdelr               ; reset repeat delay
+                stb keyb_repdel
+                lda keyb_curscan                ; get current scan code
+keyb_tobuff     tsta                            ; @?
+                beq keyb_tobuff7                ; brif so
+                cmpa #26                        ; is it alpha or @?
+                bhi keyb_tobuff6                ; brif not
+                ldb keyb_flags                  ; get shift flags
+                bitb #keyb_ctrl|keyb_alt        ; ALT or CTRL?
+                beq keyb_tobuff4                ; brif not
+                ora #0x60                       ; make lower case
+                bitb #keyb_caps                 ; capslock enabled?
+                beq keyb_tobuff0                ; brif not
+                eora #0x20                      ; flip to upper case
+keyb_tobuff0    bitb #keyb_shift                ; shifted?
+                beq keyb_tobuff1                ; brif not
+                eora #0x20                      ; flip case if shifted
+keyb_tobuff1    ldx keyb_buffw                  ; get write pointer for keyboard buffer
+                sta ,x+                         ; put it in the buffer
+                cmpx #keyb_buff+keyb_bufflen    ; end of buffer?
+                blo keyb_tobuff2                ; brif not
+                ldx #keyb_buff                  ; reset pointer to start
+keyb_tobuff2    cmpx keyb_buffr                 ; did we run into the read pointer?
+                bne keyb_tobuff3                ; brif not - there was room
+                stx keyb_buffw                  ; update the write pointer
+keyb_tobuff3    rts
+keyb_tobuff4    bitb #keyb_alt                  ; is ALT?
+                beq keyb_tobuff1                ; brif not - scan code is CTRL-<letter> code
+                ora #0x80                       ; set bit 7 for "ALT" codes
+                bitb #keyb_shift                ; shifted?
+                beq keyb_tobuff5                ; brif not
+                ora #0x20                       ; set bit 5
+keyb_tobuff5    bitb #keyb_ctrl                 ; ctrl?
+                beq keyb_tobuff1                ; brif not - stash it in the buffer
+                ora #0x40                       ; set bit 6 for "ctrl
+                bra keyb_tobuff1                ; stash it the buffer
+keyb_tobuff6    suba #26                        ; codes above 26 down to 1; @ will be 0
+keyb_tobuff7    cmpa #6                         ; is it "0"?
+                bne keyb_tobuff8                ; brif not
+                ldb keyb_flags                  ; get shift flags
+                bitb #keyb_shift|keyb_ctrl      ; CTRL-0 or SHIFT-0?
+                beq keyb_tobuff8                ; brif not - not "capslock"
+                eorb #keyb_caps                 ; flip the capslock state
+                stb keyb_flags
+keyb_tobuffa    rts                             ; and don't put it in the buffer
+keyb_tobuff8    cmpa #25                        ; is it at or above ALT?
+                blo keyb_tobuff9                ; brif not
+                suba #2                         ; close gap for ALT/CTRL
+keyb_tobuff9    ldb #8                          ;* 8 codes; multiply by 8 and move to B
+                mul                             ;*
+                ldx #keyb_codetab               ; point to special code table
+                abx                             ; now X points to the base entry in the table
+                ldb keyb_flags                  ; get shift flags
+                andb #keyb_shift|keyb_ctrl|keyb_alt ; keep only shift/ctrl/alt
+                lda b,x                         ; fetch key code
+                beq keyb_tobuffa                ; brif no code to return
+                bra keyb_tobuff1                ; go stash it in the buffer
+; This is the keyboard code table; there are 8 bytes per entry in the following order:
+; 0: unmodified
+; 1: shift
+; 2: ctrl
+; 3: ctrl-shift
+; 4: alt
+; 5: alt-shift
+; 6: alt-ctrl
+; 7: alt-ctrl-shift
+;
+; No entries for ALT, CTRL, SHIFT, or letters
+keyb_codetab    fcb 0x40,0x13,0x40,0x40,0x80,0xa0,0xc0,0xe0     ; @
+                fcb 0x5e,0x5f,0x00,0x00,0x00,0x00,0x00,0x00     ; <UP>
+                fcb 0x0a,0x5b,0x00,0x00,0x00,0x00,0x00,0x00     ; <DOWN>
+                fcb 0x08,0x15,0x00,0x00,0x00,0x00,0x00,0x00     ; <LEFT>
+                fcb 0x09,0x5d,0x00,0x00,0x00,0x00,0x00,0x00     ; <RIGHT>
+                fcb 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20     ; <SPACE>
+                fcb 0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00     ; 0 (shift/ctrl variants shadowed above)
+                fcb 0x31,0x21,0x00,0x00,0x00,0x00,0x00,0x00     ; 1 !
+                fcb 0x32,0x22,0x00,0x00,0x00,0x00,0x00,0x00     ; 2 "
+                fcb 0x33,0x23,0x00,0x00,0x00,0x00,0x00,0x00     ; 3 #
+                fcb 0x34,0x24,0x00,0x00,0x00,0x00,0x00,0x00     ; 4 $
+                fcb 0x35,0x25,0x00,0x00,0x00,0x00,0x00,0x00     ; 5 %
+                fcb 0x36,0x26,0x00,0x00,0x00,0x00,0x00,0x00     ; 6 &
+                fcb 0x37,0x27,0x00,0x00,0x00,0x00,0x00,0x00     ; 7 '
+                fcb 0x38,0x28,0x00,0x00,0x00,0x00,0x00,0x00     ; 8 (
+                fcb 0x39,0x29,0x00,0x00,0x00,0x00,0x00,0x00     ; 9 )
+                fcb 0x3a,0x2a,0x00,0x00,0x00,0x00,0x00,0x00     ; : *
+                fcb 0x3b,0x2b,0x00,0x00,0x00,0x00,0x00,0x00     ; ; +
+                fcb 0x2c,0x3c,0x00,0x00,0x00,0x00,0x00,0x00     ; , <
+                fcb 0x2d,0x3d,0x00,0x00,0x00,0x00,0x00,0x00     ; - =
+                fcb 0x2e,0x3e,0x00,0x00,0x00,0x00,0x00,0x00     ; . >
+                fcb 0x2f,0x3f,0x00,0x00,0x00,0x00,0x00,0x00     ; / ?
+                fcb 0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d     ; <ENTER>
+                fcb 0x0c,0x5c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c     ; <CLEAR>
+                fcb 0x03,0x03,0x1b,0x1b,0x9b,0xbb,0xdb,0xfb     ; <BREAK>
+                fcb 0x1c,0x1d,0x1c,0x1d,0x00,0x00,0x00,0x00     ; <F1>
+                fcb 0x1e,0x1f,0x1e,0x1f,0x00,0x00,0x00,0x00     ; <F2>
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Console screen output driver
 ;
 ; Clear screen
 console_clear   ldb #0x60                       ; VDG space character