view src/keyb.s @ 125:0607e4e20702

Correct offset error for keyword table lookup
author William Astle <lost@l-w.ca>
date Sun, 07 Jan 2024 20:35:51 -0700
parents 2d52cd154ed1
children
line wrap: on
line source

                *pragmapush list
                *pragma list
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Check for BREAK; this needs to check the keyboard directly instead of just using the usual key fetching routine so
; we don't interfere with keyboard buffering if BREAK isn't pressed. We also need to scan the keyboard directly for this
; so we react even if the keyboard buffer is full. If BREAK is pressed, the keyboard buffer is emptied.
breakcheck      lda #0xfb                       ; strobe column for BREAK
                sta PIA0.DB
                clra                            ; clear carry for no BREAK
                lda PIA0.DA                     ; read rows
                bita #0x40                      ; is BREAK down?
                bne breakcheck0                 ; brif not - check for SHIFT-@
                sync                            ; wait for interrupt to scan keyboard
                bsr keyb_clearbuff              ; reset keyboard buffer
                coma                            ; flag BREAK
breakcheck1     rts
breakcheck0     lda #0x7f                       ; check for SHIFT
                sta PIA0.DB
                lda PIA0.DA
                bita #0x40                      ; shift?
                bne breakcheck1                 ; brif not
                lda #0xfe                       ; check for @
                sta PIA0.DB
                lda PIA0.DA
                bita #1                         ; @?
                bne breakcheck1                 ; brif not
                bsr keyb_clearbuff              ; clear buffer
breakcheck2     sync                            ; wait for keyboard to actually be scanned
                bsr keyb_getkey
                bcs breakcheck2                 ; brif no key down
                bra breakcheck                  ; go do the break/pause check dance again
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Console keyboard input driver
;
; Reset the keyboard state, which means clearing the buffer and state flags
keyb_reset      bsr keyb_clearbuff              ; clear keyboard buffer
                lda keyb_flags                  ; reset keyboard state flags but keep capslock
                anda #keyb_caps
                sta keyb_flags
                clr keyb_joystate               ; clear joystick button state
                clr keyb_curscan                ; stop any keyboard repeating
                ldx #0xffff                     ; mark all key state as "unpressed"
                stx keyb_state
                stx keyb_state+2
                stx keyb_state+4
                stx keyb_state+6
                rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Empty the keyboard buffer
keyb_clearbuff  ldx #keyb_buff                  ; point to start of buffer
                stx keyb_buffr                  ; set both pointers to the start
                stx keyb_buffw
                rts                
; Read character from keyboard ring buffer; return with C set if buffer empty; this doesn't actually need to have
; interrupts disabled because the interrupt only ever updates the write pointer and then only to increase it. As a
; result, worst case is that we don't detect the contents added to the buffer on this call and have to wait for the
; next.
keyb_getkey     pshs x                          ; save register
                ldx keyb_buffr                  ; get read pointer
                cmpx keyb_buffw                 ; same as write pointer?
                bne keyb_getkey0                ; brif not - we have a result
                coma                            ; set carry for empty buffer
                puls x,pc                       ; restore register and return
keyb_getkey0    lda ,x+                         ; get character from buffer
                cmpx #keyb_buff+keyb_bufflen    ; did we run off end of buffer?
                blo keyb_getkey1                ; brif not
                ldx #keyb_buff                  ; reset to start
keyb_getkey1    stx keyb_buffr                  ; save new read pointer
                andcc #0xfe                     ; flag key retrieved
                puls x,pc                       ; restore register and return
; 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_read0a     pshs b                          ; save flag bit
                ldb a,y                         ; get state flag 
                bitb #0x40                      ; did it change state?
                bne keyb_read0d                 ; brif so
                puls b,pc                       ; clean up and return
keyb_read0d     andb #0xbf                      ; flag it as not changed
                stb a,y
                ldb a,u                         ; get current modifier state
                eorb #0x40                      ; flip the state bit
                stb a,u                         ; save new state flags
                bitb #0x40                      ; Z set if not down
                puls b                          ; get back flag bit
                beq keyb_read0b                 ; brif key is pressed
                comb                            ; invert bit flag
                andb keyb_flags                 ; clear bit in flags
                bra keyb_read0c                 ; finish up
keyb_read0b     orb keyb_flags                  ; set the flag
keyb_read0c     stb keyb_flags                  ; update flags
                rts
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
                sta PIA0.DB                     ; reset column strobe to none
                ldd #0xff00|keyb_shift
                bsr keyb_read0a
                ldd #0xfc00|keyb_ctrl
                bsr keyb_read0a
                ldd #0xfb00|keyb_alt
                bsr keyb_read0a
keyb_read3      ldd #0x0701                     ; 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      adda #8                         ; adjust scan code
                lslb                            ; shift bit probe
                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
                anda #0x07                      ; reset scan code
                deca                            ; adjust for next column
                bpl 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
                bne 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      sta keyb_curscan                ; set the current scan code that is repeating
                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?
                bne keyb_tobuff4                ; brif one or both
                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?
                beq keyb_tobuff3                ; brif so - there wasn't room so don't save pointer
                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>
                *pragmapop list