Mercurial > hg > index.cgi
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/keyb.s Sun Aug 06 00:12:29 2023 -0600 @@ -0,0 +1,255 @@ + *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