From 465a6979522b110bfa99b5ce2e1a295c70dce117 Mon Sep 17 00:00:00 2001 From: mgcaret Date: Sun, 22 Mar 2020 21:25:23 -0700 Subject: [PATCH] neon816 - experimental PS/2 keyboard decoder --- platforms/Neon816/platform-lib.s | 564 ++++++++++++++++++++++++++++++- 1 file changed, 563 insertions(+), 1 deletion(-) diff --git a/platforms/Neon816/platform-lib.s b/platforms/Neon816/platform-lib.s index 868205d..ddae91e 100644 --- a/platforms/Neon816/platform-lib.s +++ b/platforms/Neon816/platform-lib.s @@ -2,6 +2,17 @@ ; .include "./Neon816-hw.inc" +PLATF_DP = DP_END +KEYMODS = PLATF_DP ; keyboard modifiers, 16 bits + ; b15 = left shift + ; b14 = right shift + ; b7 = left ctrl + ; b6 = right ctrl + ; these 3 are same position as set LED command: + ; b2 = scroll lock (reserved) + ; b1 = num lock (reserved) + ; b0 = caps lock + ; Neon816 dictionary, a bit of a different approach than the other ports ; This will get set up by the post init function of the system interface ; The system interface functions are after this dictionary. @@ -11,7 +22,7 @@ ; Lenore Byron places on them. dstart "neon816" -dchain H_FORTH ; Make branch off the word FORTH +dchain H_FORTH ; Make branch off the word FORTH dword PS2K_STORE,"PS2K!" jsr _popay @@ -55,6 +66,12 @@ dword PS2K_FETCH,"PS2K@" NEXT eword +dword PS2KEY,"PS2KEY" + jsr ps2_keyin + jsr _pusha + NEXT +eword + dword PS2M_STORE,"PS2M!" jsr _popay tya @@ -604,3 +621,548 @@ list: jmp _sf_fail .endproc +; return carry set if data waiting at PS/2 keyboard port, clear otherwise +; destroys A +.proc ps2k_ready + sep #SHORT_A + .a8 + lda f:PS2Kstat + ror + rep #SHORT_A + .a16 + rts +.endproc + +; read data from PS/2 keyboard port, blocking +; returns byte in A +.proc ps2k_read + sep #SHORT_A + .a8 +: lda f:PS2Kstat + ror + bcc :- + lda f:PS2Kio + rep #SHORT_A + .a16 + and #$00FF + rts +.endproc + +; write data byte in A to PS/2 keyboard port +.proc ps2k_write + sep #SHORT_A + .a8 + sta f:PS2Kio +: lda f:PS2Kstat + bit #$08 + bne :- + rep #SHORT_A + .a16 + rts +.endproc + +; Keyboard translate tables +; unshifted and shifted codes +; if high bit set, jump to special handler routine + +.proc mktab ; 'main' scan codes' + ; $00 + .byte $00,$00 ; none + .byte $00,$00 ; F9 + .byte $00,$00 ; none + .byte $00,$00 ; F5 + .byte $00,$00 ; F3 + .byte $00,$00 ; F1 + .byte $00,$00 ; F2 + .byte $00,$00 ; F12 + ; $08 + .byte $00,$00 ; none + .byte $00,$00 ; F10 + .byte $00,$00 ; F8 + .byte $00,$00 ; F6 + .byte $00,$00 ; F4 + .byte $09,$09 ; Tab + .byte '`','~' + .byte $00,$00 ; none + ; $10 + .byte $00,$00 ; none + .byte $00,$00 ; left alt + .byte $80,$80 ; left shift + .byte $00,$00 ; none + .byte $86,$86 ; left control + .byte 'q','Q' + .byte '1','!' + .byte $00,$00 ; none + ; $18 + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte 'z','Z' + .byte 's','S' + .byte 'a','A' + .byte 'w','W' + .byte '2','@' + .byte $00,$00 ; none + ; $20 + .byte $00,$00 ; none + .byte 'c','C' + .byte 'x','X' + .byte 'd','D' + .byte 'e','E' + .byte '4','$' + .byte '3','#' + .byte $00,$00 ; none + ; $28 + .byte $00,$00 ; none + .byte ' ',' ' + .byte 'v','V' + .byte 'f','F' + .byte 't','T' + .byte 'r','R' + .byte '5','S' + .byte $00,$00 ; none + ; $30 + .byte $00,$00 ; none + .byte 'n','N' + .byte 'b','B' + .byte 'h','H' + .byte 'g','G' + .byte 'y','Y' + .byte '6','^' + .byte $00,$00 ; none + ; $38 + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte 'm','M' + .byte 'j','J' + .byte 'u','U' + .byte '7','&' + .byte '8','*' + .byte $00,$00 ; none + ; $40 + .byte $00,$00 ; none + .byte ',','<' + .byte 'k','K' + .byte 'i','I' + .byte 'o','O' + .byte '0',')' + .byte '9','(' + .byte $00,$00 ; none + ; $48 + .byte $00,$00 ; none + .byte '.','>' + .byte '/','?' + .byte 'l','L' + .byte ';',':' + .byte 'p','P' + .byte '-','_' + .byte $00,$00 ; none + ; $50 + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $27,'"' + .byte $00,$00 ; none + .byte '[','{' + .byte '=','+' + .byte $00,$00 ; none + .byte $00,$00 ; none + ; $58 + .byte $00,$00 ; none + .byte $84,$84 ; caps lock + .byte $82,$82 ; right shift + .byte $0D,$0D ; enter + .byte ']','}' + .byte $00,$00 ; none + .byte '\','|' + .byte $00,$00 ; none + ; $60 + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $08,$7F ; backspace + .byte $00,$00 ; none + ; $68 + .byte $00,$00 ; none + .byte '1','1' ; keypad + .byte $00,$00 ; none + .byte '4','4' ; keypad + .byte '7','7' ; keypad + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + ; $70 + .byte '0','0' ; keypad + .byte '.','.' ; keypad + .byte '2','2' ; keypad + .byte '5','5' ; keypad + .byte '6','6' ; keypad + .byte '8','8' ; keypad + .byte $1B,$1B ; escape + .byte $00,$00 ; num lock + ; $78 + .byte $00,$00 ; F11 + .byte '+','+' ; keypad + .byte '3','3' ; keypad + .byte '-','-' ; keypad + .byte '*','*' ; keypad + .byte '9','9' ; keypad + .byte $00,$00 ; scroll lock + .byte $00,$00 ; none + ; $80 + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; F7 + .endproc + +.proc ektab ; E0 scan codes + ; $00 + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + ; $08 + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + ; $10 + .byte $00,$00 ; MM WWW search + .byte $00,$00 ; right alt + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $88,$88 ; right control + .byte $00,$00 ; MM prev track + .byte $00,$00 ; none + .byte $00,$00 ; none + ; $18 + .byte $00,$00 ; MM WWW favorites + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; left GUI + ; $20 + .byte $00,$00 ; MM WWW refresh + .byte $00,$00 ; MM vol down + .byte $00,$00 ; MM mute + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; right GUI + ; $28 + .byte $00,$00 ; MM WWW stop + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; MM calculator + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; 'apps' + ; $30 + .byte $00,$00 ; MM WWW forward + .byte $00,$00 ; none + .byte $00,$00 ; MM vol up + .byte $00,$00 ; none + .byte $00,$00 ; MM play/pause + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; ACPI power + ; $38 + .byte $00,$00 ; MM WWW back + .byte $00,$00 ; none + .byte $00,$00 ; MM WWW home + .byte $00,$00 ; MM stop + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; ACPI sleep + ; $40 + .byte $00,$00 ; MM my computer + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + ; $48 + .byte $00,$00 ; MM email + .byte $00,$00 ; none + .byte '/','/' ; keypad + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; MM next track + .byte $00,$00 ; none + .byte $00,$00 ; none + ; $50 + .byte $00,$00 ; MM select + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + ; $58 + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $0D,$0D ; keypad 'enter' + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; ACPI wake + .byte $00,$00 ; none + ; $60 + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + ; $68 + .byte $00,$00 ; none + .byte $00,$00 ; end + .byte $00,$00 ; none + .byte $08,$08 ; cursor left + .byte $00,$00 ; home + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; none + ; $70 + .byte $00,$00 ; insert + .byte $7F,$7F ; delete + .byte $0A,$0A ; cursor down + .byte $00,$00 ; none + .byte $15,$15 ; cursor right + .byte $0B,$0B ; cursor up + .byte $00,$00 ; none + .byte $00,$00 ; none + ; $78 + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; page down + .byte $00,$00 ; none + .byte $00,$00 ; none + .byte $00,$00 ; page up +.endproc + +; Tables of routines for special make/break of keys (values > $80) +; kmktbl and kbktbl must match up. +.proc kmktbl + .addr mk_lshift-1 ; $80 + .addr mk_rshift-1 ; $82 + .addr mk_caps-1 ; $84 + .addr mk_lctrl-1 ; $86 + .addr mk_rctrl-1 ; $88 +.endproc + +.proc kbktbl + .addr bk_lshift-1 ; $80 + .addr bk_rshift-1 ; $82 + .addr bk_caps-1 ; $84 + .addr bk_lctrl-1 ; $88 + .addr bk_rctrl-1 ; $88 +.endproc + +.proc mk_lshift + lda #%1000000000000000 + bra makemod +.endproc + +.proc mk_rshift + lda #%0100000000000000 + bra makemod +.endproc + +.proc mk_caps + lda #%0000000000000001 + jsr makemod + ; fall-through to ps2_setLEDs +.endproc + +.proc ps2_setleds + lda #$ED ; set LEDs command + jsr ps2k_write + lda KEYMODS + jsr ps2k_write + bra nokey +.endproc + +.proc mk_lctrl + lda #%0000000010000000 + bra makemod +.endproc + +.proc mk_rctrl + lda #%0000000001000000 + ;bra makemod +.endproc + +.proc makemod + tsb KEYMODS + ; fall through to nokey +.endproc + +.proc nokey + lda #$0000 + clc + rts +.endproc + +.proc bk_lshift + lda #%1000000000000000 + bra breakmod +.endproc + +.proc bk_rshift + lda #%0100000000000000 + bra breakmod +.endproc + +.proc bk_caps + lda #%0000000000000001 + jsr breakmod + bra ps2_setleds +.endproc + +.proc bk_lctrl + lda #%0000000010000000 + bra breakmod +.endproc + +.proc bk_rctrl + lda #%0000000001000000 + ;bra breakmod +.endproc + +.proc breakmod + trb KEYMODS + bra nokey +.endproc + +; expects a 'make' code, either 00xx or E0xx +.proc ps2_keydn + lda #%1100000000000000 ; shift keys + bit KEYMODS + php ; save result (Z=1 if no shift) + ora #$0000 ; if high bit is set we will treat as $E0 + php + and #$00FF + asl + tay + lda #$0000 ; anticipate failure of cpy + plp + bmi :+ + cpy .sizeof(mktab)/2 + bcs :++ ; bad value + lda mktab,y + bra :++ +: cpy .sizeof(ektab)/2 + bcs :+ ; bad value + lda ektab,y +: plp + beq :+ ; unshifted + xba +: and #$00FF + cmp #$0080 + bcs special + pha + lda KEYMODS + ror ; caps lock into carry + pla + bcc nocaps ; if no caps lock + cmp #'a' + bcc nocaps + cmp #'z'+1 + bcs nocaps + and #$DF ; make caps +nocaps: pha ; save on stack + lda #%0000000011000000 ; ctrl keys + bit KEYMODS + beq :+ ; if no ctrl + lda 1,s + and #%0000000000011111 ; make ctrl + sta 1,s +: pla + cmp #$01 ; set carry if >= 1 + rts +special: and #$7f + tay + lda kmktbl,y + pha + rts +.endproc + +; for the break we only care about modifiers, we aren't keeping track of anything else +; so we also ignore shifted values +; expects a 'make'-like code, either 00xx or E0xx +.proc ps2_keyup + ora #$0000 + php + and #$00FF + asl + tay + plp + bmi :+ + cpy .sizeof(mktab)/2 + bcs :++ + lda mktab,y + bra :++ +: cpy .sizeof(ektab)/2 + bcs :+ + lda ektab,y +: and #$00FF + cmp #$0080 + bcs special + lda #$0000 + clc + rts +special: and #$7f + tay + lda kbktbl,y + pha + rts +.endproc + +; Wait for a valid key, when we get one, decode and return +.proc ps2_keyin +: jsr ps2k_read + cmp #$F0 + beq break + cmp #$FE + beq extended + cmp #$AA ; diags passed + beq :- + cmp #$FC ; diags failed + beq :- ; prob shouldn't do this + cmp #$FA ; ACK + beq :- + jmp ps2_keydn ; see if we can decode it +break: jsr ps2k_read + bra ps2_keyup +extended: jsr ps2k_read + cmp #$F0 + beq :+ ; extended break + ora #$E000 + jmp ps2_keydn +: jsr ps2k_read + ora #$E000 + bra ps2_keyup +.endproc +