Neon816: PS/2 keyboard working

This commit is contained in:
mgcaret 2020-03-23 20:25:28 -07:00
parent 8078f8cf21
commit 367ec0d98d
2 changed files with 275 additions and 137 deletions

View File

@ -0,0 +1,111 @@
# -
Updated: 2020-03-23 20:21:18 -0700
## $KBDRESET
_( -- )_ send reset command to PS/2 keyboard
## DUMPEDID
_( -- )_ dump display EDID data, first 256 bytes.
## GETRTC
_( -- day hour minutes seconds ms us )_ get RTC
## I2C2!
_( byte -- )_ write byte to I2C2.
## I2C2@
_( -- byte )_ receive byte from I2C2, do not send ack.
## I2C2@+
_( -- byte )_ receive byte from I2C2, send ack.
## I2C2START
_( -- )_ start I2C2 communication.
## I2C2STOP
_( -- )_ stop I2C2 communication.
## PS2K!
_( byte -- )_ write byte to PS/2 keyboard port.
## PS2K?
_( -- f )_ f is true if data waiting at PS/2 keyboard port.
## PS2K@
_( -- byte )_ read byte from PS/2 keyboard port.
## PS2KEY
_( -- c )_ wait for keypress on PS/2 port, c is the character typed.
## PS2M!
_( byte -- )_ write byte to PS/2 mouse port.
## PS2M?
_( -- f )_ f is true if data waiting at PS/2 mouse port.
## PS2M@
_( -- byte )_ read byte from PS/2 keyboard port.
## PS2RAW
_( -- code f )_ read raw keycode from PS/2 port.
code is keycode, either xx or E0xx, f is true if break.
## SETRTC
_( day hour minutes seconds ms us -- )_ set RTC
## SPI2!
_( byte -- )_ write byte to SPI2.
## SPI2@
_( -- byte )_ fetch byte from SPI2.
## SPI2INIT
_( -- )_ initialize SPI2.
## SPI2START
_( -- )_ start SPI2 communication.
## SPI2STOP
_( -- )_ stop SPI2 communication.
## VDC!
_( offset word -- )_ write word to VDC at offset
## VDCC!
_( offset byte -- )_ write byte to VDC at offset
## VDCC@
_( offset -- byte )_ read byte from VDC at offset
## VIDSTART
## VIDSTOP
## VMODELINE

View File

@ -24,55 +24,53 @@ KEYMODS = PLATF_DP ; keyboard modifiers, 16 bits
dstart "neon816" dstart "neon816"
dchain H_FORTH ; Make branch off the word FORTH dchain H_FORTH ; Make branch off the word FORTH
; H: ( byte -- ) write byte to PS/2 keyboard port.
dword PS2K_STORE,"PS2K!" dword PS2K_STORE,"PS2K!"
jsr _popay jsr _popay
tya tya
sep #SHORT_A jsr ps2k_write
.a8
sta f:PS2Kio
: lda f:PS2Kstat
bit #$08
bne :-
rep #SHORT_A
.a16
NEXT NEXT
eword eword
; H: ( -- f ) f is true if data waiting at PS/2 keyboard port.
dword PS2K_QUERY,"PS2K?" dword PS2K_QUERY,"PS2K?"
jsr ps2k_ready
ldy #$0000 ldy #$0000
sep #SHORT_A
.a8
lda f:PS2Kstat
ror
rep #SHORT_A
.a16
bcc :+ bcc :+
dey dey
: tya : tya
PUSHNEXT PUSHNEXT
eword eword
; H: ( -- byte ) read byte from PS/2 keyboard port.
dword PS2K_FETCH,"PS2K@" dword PS2K_FETCH,"PS2K@"
sep #SHORT_A jsr ps2k_read
.a8
: lda f:PS2Kstat
ror
bcc :-
lda f:PS2Kio
rep #SHORT_A
.a16
and #$00FF
jsr _pusha jsr _pusha
NEXT NEXT
eword eword
; H: ( -- c ) wait for keypress on PS/2 port, c is the character typed.
dword PS2KEY,"PS2KEY" dword PS2KEY,"PS2KEY"
: jsr ps2_keyin jsr ps2_keyin
bcc :-
jsr _pusha jsr _pusha
NEXT NEXT
eword eword
; H: ( -- code f ) read raw keycode from PS/2 port.
; H: code is keycode, either xx or E0xx, f is true if break.
dword PS2RAW,"PS2RAW"
jsr ps2_readcode
php
jsr _pusha
ldy #$00
plp
bcc :+
dey
: tya
PUSHNEXT
eword
; H: ( byte -- ) write byte to PS/2 mouse port.
dword PS2M_STORE,"PS2M!" dword PS2M_STORE,"PS2M!"
jsr _popay jsr _popay
tya tya
@ -87,6 +85,7 @@ dword PS2M_STORE,"PS2M!"
NEXT NEXT
eword eword
; H: ( -- f ) f is true if data waiting at PS/2 mouse port.
dword PS2M_QUERY,"PS2M?" dword PS2M_QUERY,"PS2M?"
ldy #$0000 ldy #$0000
sep #SHORT_A sep #SHORT_A
@ -101,6 +100,7 @@ dword PS2M_QUERY,"PS2M?"
PUSHNEXT PUSHNEXT
eword eword
; H: ( -- byte ) read byte from PS/2 keyboard port.
dword PS2M_FETCH,"PS2M@" dword PS2M_FETCH,"PS2M@"
sep #SHORT_A sep #SHORT_A
.a8 .a8
@ -115,6 +115,7 @@ dword PS2M_FETCH,"PS2M@"
NEXT NEXT
eword eword
; H: ( -- ) send reset command to PS/2 keyboard
dword dKBDRESET,"$KBDRESET" dword dKBDRESET,"$KBDRESET"
ENTER ENTER
ONLIT $FF ONLIT $FF
@ -122,6 +123,7 @@ dword dKBDRESET,"$KBDRESET"
EXIT EXIT
eword eword
; H: ( day hour minutes seconds ms us -- ) set RTC
; this probably isn't fast enough to reliably set micro and milliseconds ; this probably isn't fast enough to reliably set micro and milliseconds
dword SETRTC,"SETRTC" dword SETRTC,"SETRTC"
ENTER ENTER
@ -140,6 +142,7 @@ dword SETRTC,"SETRTC"
EXIT EXIT
eword eword
; H: ( -- day hour minutes seconds ms us ) get RTC
dword GETRTC,"GETRTC" dword GETRTC,"GETRTC"
ENTER ENTER
ONLIT RTCday ONLIT RTCday
@ -169,6 +172,7 @@ nosep:
.a16 .a16
.endproc .endproc
; H: ( -- ) start I2C2 communication.
dword I2C2START,"I2C2START" dword I2C2START,"I2C2START"
jsr I2C2_busy_wait jsr I2C2_busy_wait
.a8 .a8
@ -179,6 +183,7 @@ dword I2C2START,"I2C2START"
NEXT NEXT
eword eword
; H: ( -- ) stop I2C2 communication.
dword I2C2STOP,"I2C2STOP" dword I2C2STOP,"I2C2STOP"
jsr I2C2_busy_wait jsr I2C2_busy_wait
.a8 .a8
@ -189,6 +194,7 @@ dword I2C2STOP,"I2C2STOP"
NEXT NEXT
eword eword
; H: ( byte -- ) write byte to I2C2.
dword I2C2_STORE,"I2C2!" dword I2C2_STORE,"I2C2!"
jsr _popay jsr _popay
jsr I2C2_busy_wait jsr I2C2_busy_wait
@ -202,6 +208,7 @@ dword I2C2_STORE,"I2C2!"
NEXT NEXT
eword eword
; H: ( -- byte ) receive byte from I2C2, send ack.
dword I2C2_FETCH_ACK,"I2C2@+" dword I2C2_FETCH_ACK,"I2C2@+"
jsr I2C2_busy_wait jsr I2C2_busy_wait
.a8 .a8
@ -216,7 +223,8 @@ dofetch: sta f:I2C2ctrl
NEXT NEXT
eword eword
dword I2C2_FETCH,"I2C2@+" ; H: ( -- byte ) receive byte from I2C2, do not send ack.
dword I2C2_FETCH,"I2C2@"
jsr I2C2_busy_wait jsr I2C2_busy_wait
.a8 .a8
lda #$04 lda #$04
@ -224,6 +232,7 @@ dword I2C2_FETCH,"I2C2@+"
.a16 .a16
eword eword
; H: ( offset byte -- ) write byte to VDC at offset
dword VDC_C_STORE,"VDCC!" dword VDC_C_STORE,"VDCC!"
jsr _popay ; pop offset jsr _popay ; pop offset
phy ; save low word phy ; save low word
@ -241,6 +250,7 @@ dword VDC_C_STORE,"VDCC!"
NEXT NEXT
eword eword
; H: ( offset -- byte ) read byte from VDC at offset
dword VDC_C_FETCH,"VDCC@" dword VDC_C_FETCH,"VDCC@"
jsr _popay ; pop offet jsr _popay ; pop offet
phx ; save SP phx ; save SP
@ -257,6 +267,7 @@ dword VDC_C_FETCH,"VDCC@"
NEXT NEXT
eword eword
; H: ( offset word -- ) write word to VDC at offset
dword VDC_STORE,"VDC!" dword VDC_STORE,"VDC!"
jsr _popay ; again! again! again! jsr _popay ; again! again! again!
phy phy
@ -363,6 +374,7 @@ dword VIDSTOP,"VIDSTOP"
EXIT EXIT
eword eword
; H: ( -- ) dump display EDID data, first 256 bytes.
dword DUMPEDID,"DUMPEDID" dword DUMPEDID,"DUMPEDID"
dump_size = $0100 dump_size = $0100
ENTER ENTER
@ -398,6 +410,7 @@ dump_size = $0100
EXIT EXIT
eword eword
; H: ( -- ) initialize SPI2.
dword SPI2INIT,"SPI2INIT" dword SPI2INIT,"SPI2INIT"
sep #SHORT_A sep #SHORT_A
.a8 .a8
@ -411,6 +424,7 @@ dword SPI2INIT,"SPI2INIT"
NEXT NEXT
eword eword
; H: ( -- ) start SPI2 communication.
dword SPI2START,"SPI2START" dword SPI2START,"SPI2START"
sep #SHORT_A sep #SHORT_A
.a8 .a8
@ -421,6 +435,7 @@ dword SPI2START,"SPI2START"
NEXT NEXT
eword eword
; H: ( -- ) stop SPI2 communication.
dword SPI2STOP,"SPI2STOP" dword SPI2STOP,"SPI2STOP"
sep #SHORT_A sep #SHORT_A
.a8 .a8
@ -445,6 +460,7 @@ nosep:
.a16 .a16
.endproc .endproc
; H: ( byte -- ) write byte to SPI2.
dword SPI2_STORE,"SPI2!" dword SPI2_STORE,"SPI2!"
jsr _popay jsr _popay
jsr SPI2_busy_wait jsr SPI2_busy_wait
@ -456,6 +472,7 @@ dword SPI2_STORE,"SPI2!"
NEXT NEXT
eword eword
; H: ( -- byte ) fetch byte from SPI2.
dword SPI2_FETCH,"SPI2@" dword SPI2_FETCH,"SPI2@"
jsr SPI2_busy_wait jsr SPI2_busy_wait
.a8 .a8
@ -527,6 +544,7 @@ table: .addr _sf_pre_init
.proc _sf_post_init .proc _sf_post_init
plx plx
stz KEYMODS
; Here we make a vocabulary definition for the neon816 dictionary ; Here we make a vocabulary definition for the neon816 dictionary
; that we defined at the beginning of this file. ; that we defined at the beginning of this file.
ENTER ENTER
@ -662,6 +680,13 @@ list:
rts rts
.endproc .endproc
.proc ps2k_command
jsr ps2k_write
jsr ps2k_read
cmp #$00FA
rts
.endproc
; Keyboard translate tables ; Keyboard translate tables
; unshifted and shifted codes ; unshifted and shifted codes
; if high bit set, jump to special handler routine ; if high bit set, jump to special handler routine
@ -767,7 +792,6 @@ list:
.byte $00,$00 ; none .byte $00,$00 ; none
.byte $00,$00 ; none .byte $00,$00 ; none
; $58 ; $58
.byte $00,$00 ; none
.byte $84,$84 ; caps lock .byte $84,$84 ; caps lock
.byte $82,$82 ; right shift .byte $82,$82 ; right shift
.byte $0D,$0D ; enter .byte $0D,$0D ; enter
@ -775,6 +799,7 @@ list:
.byte $00,$00 ; none .byte $00,$00 ; none
.byte '\','|' .byte '\','|'
.byte $00,$00 ; none .byte $00,$00 ; none
.byte $00,$00 ; none
; $60 ; $60
.byte $00,$00 ; none .byte $00,$00 ; none
.byte $00,$00 ; none .byte $00,$00 ; none
@ -977,7 +1002,7 @@ list:
.addr bk_lshift-1 ; $80 .addr bk_lshift-1 ; $80
.addr bk_rshift-1 ; $82 .addr bk_rshift-1 ; $82
.addr bk_caps-1 ; $84 .addr bk_caps-1 ; $84
.addr bk_lctrl-1 ; $88 .addr bk_lctrl-1 ; $86
.addr bk_rctrl-1 ; $88 .addr bk_rctrl-1 ; $88
.endproc .endproc
@ -992,17 +1017,19 @@ list:
.endproc .endproc
.proc mk_caps .proc mk_caps
lda #%0000000000000001 lda KEYMODS
jsr makemod eor #%1
sta KEYMODS
; fall-through to ps2_setLEDs ; fall-through to ps2_setLEDs
.endproc .endproc
.proc ps2_setleds .proc ps2_setleds
lda #$ED ; set LEDs command lda #$ED ; set LEDs command
jsr ps2k_write jsr ps2k_command
lda KEYMODS lda KEYMODS
jsr ps2k_write and #%111
bra nokey jsr ps2k_command
rts
.endproc .endproc
.proc mk_lctrl .proc mk_lctrl
@ -1017,12 +1044,6 @@ list:
.proc makemod .proc makemod
tsb KEYMODS tsb KEYMODS
; fall through to nokey
.endproc
.proc nokey
lda #$0000
clc
rts rts
.endproc .endproc
@ -1037,9 +1058,7 @@ list:
.endproc .endproc
.proc bk_caps .proc bk_caps
lda #%0000000000000001 rts
jsr breakmod
bra ps2_setleds
.endproc .endproc
.proc bk_lctrl .proc bk_lctrl
@ -1054,116 +1073,124 @@ list:
.proc breakmod .proc breakmod
trb KEYMODS trb KEYMODS
bra nokey rts
.endproc .endproc
; expects a 'make' code, either 00xx or E0xx ; Read a code from the keyboard, return carry set if it was 'break' and clear
.proc ps2_keydn ; if it was 'make'
lda #%1100000000000000 ; shift keys .proc ps2_readcode
bit KEYMODS phy ; save Y
php ; save result (Z=1 if no shift) ldy #$0000 ; flag for break
ora #$0000 ; if high bit is set we will treat as $E0 phy ; space for extended code byte
php : jsr ps2k_read
cmp #$E1 ; pause/break annoyance
beq pausebrk
cmp #$E0 ; extended code?
bne :+
xba
sta 1,s ; yes, put in upper byte on stack
bra :- ; back to read
: cmp #$F0 ; break code?
bne :+
iny ; yes, flag
bra :-- ; back to read
: ora 1,s ; if none of those, put in lower byte
sta 1,s ; inefficient but it works
pla ; and get it off the stack
done: cpy #$01 ; set carry if break
ply ; restore Y
rts
pausebrk: pla
ldy #7
: jsr ps2k_read ; drop 7 bytes
dey
bne :-
lda #$E000 ; bogus scan code
bra done
.endproc
; get code from translate table for key code in A, return in A
; destroys y, returns 0000 if there is no translation
.proc ps2_keytran
pha
and #$00FF and #$00FF
asl asl
tay 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 pla
bcc nocaps ; if no caps lock and #$FF00
cmp #'a' cmp #$E000
bcc nocaps beq ext
cmp #'z'+1 cpy #.sizeof(mktab)
bcs nocaps bcs bad
and #$DF ; make caps lda mktab,y
nocaps: pha ; save on stack bra done
lda #%0000000011000000 ; ctrl keys ext: cpy #.sizeof(ektab)
bit KEYMODS bcs bad
beq :+ ; if no ctrl lda ektab,y
bra done
bad: lda #$0000
done: cmp #$0001
rts
.endproc
; take translated code in A, apply keyboard modifiers, and return result in A
; if special, return carry set
.proc ps2_keymod
pha ; work with it on stack
lda KEYMODS
and #%1100000000000000 ; shift keys
beq :+
lda 1,s lda 1,s
and #%0000000000011111 ; make ctrl xba
sta 1,s
: lda 1,s
and #$0080
bne :++ ; shortcut special
lda KEYMODS
ror ; caps into carry
bcc :+
lda 1,s
and #$00FF
cmp #'a'
bcc :+
cmp #'z'+1
bcs :+
and #$DF
sta 1,s
: lda KEYMODS
and #%0000000011000000 ; ctrl keys
beq :+
lda 1,s
and #%11111 ; make ctrl char
sta 1,s sta 1,s
: pla : 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 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 cmp #$0080
bcs special
lda #$0000
clc
rts
special: and #$7f
tay
lda kbktbl,y
pha
rts rts
.endproc .endproc
; Wait for a valid key, when we get one, decode and return ; Wait for a valid key, when we get one, decode and return
.proc ps2_keyin .proc ps2_keyin
: jsr ps2k_read : php
cmp #$F0 : plp
beq break jsr ps2_readcode
cmp #$FE php
beq extended jsr ps2_keytran
cmp #$AA ; diags passed bcc :- ; carry is clear if no value for key
beq :- jsr ps2_keymod
cmp #$FC ; diags failed bcs special
beq :- ; prob shouldn't do this plp
cmp #$FA ; ACK bcs :-- ; break code, wait for another
beq :- rts
jmp ps2_keydn ; see if we can decode it special: and #$007F
break: jsr ps2k_read tay
bra ps2_keyup lda kmktbl,y
extended: jsr ps2k_read plp
cmp #$F0 bcc :+ ; if make
beq :+ ; extended break lda kbktbl,y
ora #$E000 : jsr :+
jmp ps2_keydn bra :--- ; for special, we go back to waiting
: jsr ps2k_read : pha ; do RTS trick
ora #$E000 rts
bra ps2_keyup
.endproc .endproc