Mercurial > hg > index.cgi
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