view src/keyb.s @ 73:2d52cd154ed1

Split some code into separate files for easier management Because the source for lwbasic is so large, split it into several different files to make it easier to navigate and modify. This is part one of the split.
author William Astle <lost@l-w.ca>
date Sun, 06 Aug 2023 00:12:29 -0600
parents
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