mirror of https://github.com/wwarthen/RomWBW.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
655 lines
20 KiB
655 lines
20 KiB
;__________________________________________________________________________________________________
|
|
;
|
|
; PARALLEL PORT KEYBOARD DRIVER FOR N8VEM
|
|
; SUPPORT KEYBOARD/MOUSE ON VDU AND N8
|
|
;
|
|
; ORIGINAL CODE BY DR JAMES MOXHAM
|
|
; ROMWBW ADAPTATION BY WAYNE WARTHEN
|
|
;__________________________________________________________________________________________________
|
|
;
|
|
;__________________________________________________________________________________________________
|
|
; DATA CONSTANTS
|
|
;__________________________________________________________________________________________________
|
|
;
|
|
#IF (PLATFORM == PLT_N8)
|
|
PPK_PPI .EQU 084H ; PPI PORT BASE FOR N8
|
|
#ELSE
|
|
PPK_PPI .EQU 0F4H ; PPI PORT BASE FOR VDU
|
|
#ENDIF
|
|
|
|
PPK_PPIA .EQU PPK_PPI + 0 ; KEYBOARD PPI PORT A
|
|
PPK_PPIB .EQU PPK_PPI + 1 ; KEYBOARD PPI PORT B
|
|
PPK_PPIC .EQU PPK_PPI + 2 ; KEYBOARD PPI PORT C
|
|
PPK_PPIX .EQU PPK_PPI + 3 ; KEYBOARD PPI CONTROL PORT
|
|
|
|
PPK_DAT .EQU 01111000B ; PPIX MASK TO MANAGE DATA LINE (C:4)
|
|
PPK_CLK .EQU 01111010B ; PPIX MASK TO MANAGE CLOCK LINE (C:5)
|
|
|
|
PPK_WAITTO .EQU 50 * CPUFREQ ; TUNE!!! WANT SMALL AS POSSIBLE W/O ERRORS
|
|
PPK_WAITRDY .EQU 10 * CPUFREQ ; TUNE!!! 100US LOOP DELAY TO ENSURE DEVICE READY
|
|
;
|
|
;__________________________________________________________________________________________________
|
|
; KEYBOARD INITIALIZATION
|
|
;__________________________________________________________________________________________________
|
|
;
|
|
PPK_INIT:
|
|
CALL PPK_INITPORT ; SETS PORT C SO CAN INPUT AND OUTPUT
|
|
CALL PPK_RESET ; RESET TO THE KEYBOARD
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
;
|
|
;__________________________________________________________________________________________________
|
|
; KEYBOARD STATUS
|
|
;__________________________________________________________________________________________________
|
|
;
|
|
; CHECKING THE KEYBOARD REQUIRES "WAITING" FOR A KEY TO BE SENT AND USING A TIMEOUT
|
|
; TO DETECT THAT NO KEY IS READY. MANY APPS CALL STATUS REPEATEDLY. IN ORDER TO AVOID
|
|
; SLOWING THEM DOWN, WE IGNORE 1/256 OF THE CALLS.
|
|
;
|
|
PPK_STAT:
|
|
LD A,(PPK_STATUS) ; GET STATUS
|
|
AND PPK_KEYRDY ; ISOLATE READ BIT
|
|
JR NZ,PPK_STAT3 ; KEY READY, DONE
|
|
|
|
PPK_STAT1:
|
|
LD A,(PPK_IDLE) ; GET IDLE COUNT
|
|
DEC A ; DECREMENT IT
|
|
LD (PPK_IDLE),A ; SAVE IT
|
|
JR Z,PPK_STAT2 ; ZERO? OK, DO A REAL KEY CHECK
|
|
XOR A ; RETURN KEY NOT READY
|
|
RET
|
|
|
|
PPK_STAT2:
|
|
CALL Z,PPK_DECODE ; NOT READY, RUN THE DECODING ENGINE
|
|
LD A,(PPK_STATUS) ; GET STATUS
|
|
AND PPK_KEYRDY ; ISOLATE READ BIT
|
|
|
|
PPK_STAT3:
|
|
RLCA ; ROTATE READY BIT TO LOW ORDER BIT
|
|
RET
|
|
;
|
|
;__________________________________________________________________________________________________
|
|
; KEYBOARD READ
|
|
;__________________________________________________________________________________________________
|
|
;
|
|
PPK_READ:
|
|
; CALL PPK_STAT ; CHECK TO SEE IF KEY READY
|
|
LD A,(PPK_STATUS) ; GET STATUS
|
|
AND PPK_KEYRDY ; ISOLIATE KEY READY BIT
|
|
JR NZ,PPK_READ1 ; READY, GO GET THE KEY AND RETURN
|
|
CALL PPK_DECODE ; TRY TO GET A KEY
|
|
JR PPK_READ ; AND LOOP
|
|
;
|
|
PPK_READ1:
|
|
LD A,(PPK_KEYCODE) ; GET KEYCODE
|
|
LD E,A ; SAVE IT IN E
|
|
LD A,(PPK_STATE) ; GET STATE FLAGS
|
|
LD D,A ; SAVE THEM IN D
|
|
XOR A ; SIGNAL SUCCESS
|
|
LD (PPK_STATUS),A ; CLEAR STATE TO INDICATE BYTE RECEIVED
|
|
RET
|
|
;
|
|
;__________________________________________________________________________________________________
|
|
; KEYBOARD FLUSH
|
|
;__________________________________________________________________________________________________
|
|
;
|
|
PPK_FLUSH:
|
|
XOR A ; A = 0
|
|
LD (PPK_STATE),A ; CLEAR STATE
|
|
RET
|
|
;
|
|
;__________________________________________________________________________________________________
|
|
; HARDWARE INTERFACE
|
|
;__________________________________________________________________________________________________
|
|
;
|
|
;__________________________________________________________________________________________________
|
|
PPK_GETBYTE:
|
|
;
|
|
; GET RAW BYTE FROM KEYBOARD INTERFACE INTO A
|
|
; IF TIMEOUT, RETURN WITH A=0 AND Z SET
|
|
;
|
|
; ALL REGISTERS ARE DESTROYED
|
|
;
|
|
CALL PPK_CLKHI ; ALLOW KEYBOARD TO XMIT
|
|
CALL PPK_WTCLKLO ; WAIT FOR CLOCK LINE TO GO LOW
|
|
JP NZ,PPK_GETBYTE1 ; IF IT WENT LOW, READ THE BYTE
|
|
CALL PPK_CLKLO ; SUPPRESS KEYBOARD XMIT
|
|
XOR A ; SIGNAL TIMEOUT
|
|
RET
|
|
|
|
PPK_GETBYTE1:
|
|
CALL PPK_WTCLKHI ; WAIT FOR END OF START BIT
|
|
LD B,8 ; SAMPLE 8 TIMES
|
|
LD E,0 ; START WITH E=0
|
|
|
|
PPK_GETBYTE2:
|
|
CALL PPK_WTCLKLO ; WAIT TILL CLOCK GOES LOW
|
|
IN A,(PPK_PPIB) ; SAMPLE THE DATA LINE
|
|
RRA ; MOVE THE DATA BIT INTO THE CARRY REGISTER
|
|
LD A,E ; GET THE BYTE WE ARE BUILDING IN E
|
|
RRA ; MOVE THE CARRY BIT INTO BIT 7 AND SHIFT RIGHT
|
|
LD E,A ; STORE IT BACK AFTER 8 CYCLES 1ST BIT READ WILL BE IN B0
|
|
CALL PPK_WTCLKHI ; WAIT TILL GOES HIGH
|
|
DJNZ PPK_GETBYTE2 ; DO THIS 8 TIMES
|
|
CALL PPK_WTCLKLO ; GET THE PARITY BIT
|
|
CALL PPK_WTCLKHI
|
|
CALL PPK_WTCLKLO ; GET THE STOP BIT
|
|
CALL PPK_WTCLKHI
|
|
CALL PPK_CLKLO ; SUPPRESS KEYBOARD XMIT
|
|
LD A,E ; RETURN WITH RAW SCANCODE BYTE IN A
|
|
|
|
; ; *DEBUG*
|
|
; CALL PC_SPACE
|
|
; CALL PC_LT
|
|
; CALL PRTHEXBYTE
|
|
|
|
OR A
|
|
RET
|
|
;
|
|
;__________________________________________________________________________________________________
|
|
PPK_PUTBYTE:
|
|
;
|
|
; PUT A RAW BYTE FROM A TO THE KEYBOARD INTERFACE
|
|
;
|
|
; ALL REGISTERS ARE DESTROYED
|
|
;
|
|
LD E,A ; STASH INCOMING BYTE VALUE IN E
|
|
|
|
; ; *DEBUG*
|
|
; CALL PC_SPACE
|
|
; CALL PC_GT
|
|
; CALL PRTHEXBYTE
|
|
|
|
; START WITH DATA HI AND CLOCK LOW
|
|
CALL PPK_DATHI
|
|
CALL PPK_CLKLO ; NEED CLOCK LOW TO GET DEVICE ATTENTION
|
|
|
|
; WAIT 100US TO MAKE SURE DEVICE IS READY TO RECEIVE
|
|
LD B,PPK_WAITRDY ; WAIT 100US
|
|
DJNZ $ ; SPIN
|
|
|
|
; SEND START BIT
|
|
CALL PPK_DATLO ; SET DATA LOW - REQUEST TO SEND/START BIT
|
|
CALL PPK_CLKHI ; RELEASE THE CLOCK LINE
|
|
CALL PPK_WTCLKLO ; DEVICE HAS RECEIVED THE START BIT
|
|
|
|
; SEND DATA BITS
|
|
LD B,8 ; 8 DATA BITS
|
|
PPK_PUTBYTE1:
|
|
RRC E ; ROTATE LOW BIT OF E TO CARRY (NEXT BIT TO SEND)
|
|
LD A,PPK_DAT >> 1 ; INIT A WITH DATA MASK SHIFTED RIGHT BY ONE BIT
|
|
RLA ; SHIFT CARRY INTO LOW BIT OF A
|
|
OUT (PPK_PPIX),A ; SET/RESET DATA LINE FOR NEXT BIT VALUE
|
|
CALL PPK_WTCLKHI ; WAIT FOR CLOCK TO TRANSTION HI
|
|
CALL PPK_WTCLKLO ; THEN LO, BIT HAS NOW BEEN RECEIVED BY DEVICE
|
|
DJNZ PPK_PUTBYTE1 ; LOOP TO SEND 8 DATA BITS
|
|
|
|
; SEND PARITY BIT
|
|
XOR A ; CLEAR A
|
|
OR E ; OR WITH SENT VALUE, SETS PARITY FLAG!
|
|
LD A,PPK_DAT ; PREPARE A WITH DATA MASK
|
|
JP PO,PPK_PUTBYTE2 ; PARITY IS ALREADY ODD, LEAVE A ALONE
|
|
INC A ; SET PARITY BIT BY INCREMENTING A
|
|
PPK_PUTBYTE2:
|
|
OUT (PPK_PPIX),A ; SET THE DATA LINE
|
|
CALL PPK_WTCLKHI ; WAIT FOR CLOCK TO TRANSITION HI
|
|
CALL PPK_WTCLKLO ; THEN LO, BIT HAS NOW BEEN RECEIVED BY DEVICE
|
|
|
|
; SEND STOP BIT, NO NEED TO WATCH CLOCK, JUST WAIT FOR START OF DEVICE ACK
|
|
CALL PPK_DATHI ; STOP BIT IS 1 (HI)
|
|
|
|
; HANDLE DEVICE ACK
|
|
CALL PPK_WTDATLO ; WAIT FOR DEVICE TO START ACK
|
|
CALL PPK_WTCLKLO ; WAIT FOR CLOCK TO TRANSITION LO
|
|
CALL PPK_WTCLKHI ; THEN HI
|
|
CALL PPK_WTDATHI ; FINALLY WAIT FOR DEVICE TO RELEASE DATA LINE
|
|
|
|
; ASSERT CLOCK TO INHIBIT DEVICE FROM SENDING US ANYTHING UNTIL WE ARE READY
|
|
CALL PPK_CLKLO ; SET CLOCK LOW
|
|
|
|
RET
|
|
;
|
|
;__________________________________________________________________________________________________
|
|
PPK_INITPORT:
|
|
;
|
|
; INITIALIZE PPI
|
|
;
|
|
LD A,10000010B ; A=OUT B=IN, C HIGH=OUT, CLOW=OUT
|
|
OUT (PPK_PPIX),A ; SET PPI CONTROL PORT
|
|
XOR A ; A=0
|
|
OUT (PPK_PPIA),A ; PPI PORT A TO ZERO (REQUIRED FOR PAR PRINTER)
|
|
CALL PPK_DATHI ; KBD DATA LINE HI (IDLE)
|
|
CALL PPK_CLKHI ; KBD CLOCK LINE HI (IDLE)
|
|
RET
|
|
;
|
|
;__________________________________________________________________________________________________
|
|
;
|
|
; BIT TESTING (PORT B)
|
|
;
|
|
; B:0 = KBD DATA LINE (INPUT)
|
|
; B:1 = KBD CLOCK LINE (INPUT)
|
|
;
|
|
; TEST PPI PORT B BIT(S) DESIGNATED BY BITMASK IN D AFTER XOR WITH E
|
|
; WAIT FOR ANY OF THE DESIGNATED BITS TO BE SET, THEN RETURN
|
|
; IF TIMEOUT, RETURN WITH A=0 AND Z SET
|
|
; HL IS DESTROYED, A IS OVERWRITTEN WITH RETURN VALUE
|
|
;
|
|
PPK_WTCLKLO: ; WAIT FOR CLOCK LINE TO BE LOW
|
|
PUSH DE
|
|
LD DE,0202H ; TEST BIT 1 AFTER INVERTING
|
|
JR PPK_WAIT
|
|
;
|
|
PPK_WTCLKHI: ; WAIT FOR CLOCK LINE TO BE HIGH
|
|
PUSH DE
|
|
LD DE,0200H ; TEST BIT 1
|
|
JR PPK_WAIT
|
|
;
|
|
PPK_WTDATLO: ; WAIT FOR DATA LINE TO BE LOW
|
|
PUSH DE
|
|
LD DE,0101H ; TEST BIT 0 AFTER INVERTING
|
|
JR PPK_WAIT
|
|
;
|
|
PPK_WTDATHI: ; WAIT FOR DATA LINE TO BE HIGH
|
|
PUSH DE
|
|
LD DE,0100H ; TEST BIT 0
|
|
JR PPK_WAIT
|
|
;
|
|
PPK_WAIT: ; COMPLETE THE WAIT PROCESSING
|
|
LD HL,PPK_WAITTO
|
|
PPK_WAIT1:
|
|
IN A,(PPK_PPIB) ; GET BYTE FROM PORT B
|
|
XOR E
|
|
AND D
|
|
JR NZ,PPK_WAIT2 ; EXIT IF ANY BIT IS SET
|
|
DEC HL
|
|
LD A,H
|
|
OR L
|
|
JR NZ,PPK_WAIT1
|
|
PPK_WAIT2:
|
|
POP DE
|
|
RET
|
|
;
|
|
;__________________________________________________________________________________________________
|
|
;
|
|
; BIT MANAGEMENT (PORT C)
|
|
;
|
|
; C:4 = KBD DATA LINE (LATCHED OUTPUT)
|
|
; C:5 = KBD CLOCK LINE (LATCHED OUTPUT)
|
|
;
|
|
; A IS DESTROYED (OVERWRITTEN WITH PORT OUTPUT VALUE)
|
|
;
|
|
PPK_DATHI:
|
|
LD A,PPK_DAT + 1
|
|
JR PPK_SETBIT
|
|
PPK_DATLO:
|
|
LD A,PPK_DAT
|
|
JR PPK_SETBIT
|
|
PPK_CLKHI:
|
|
LD A,PPK_CLK + 1
|
|
JR PPK_SETBIT
|
|
PPK_CLKLO:
|
|
LD A,PPK_CLK
|
|
JR PPK_SETBIT
|
|
PPK_SETBIT:
|
|
OUT (PPK_PPIX),A
|
|
RET
|
|
;
|
|
;__________________________________________________________________________________________________
|
|
; RESET KEYBOARD
|
|
;__________________________________________________________________________________________________
|
|
;
|
|
PPK_RESET:
|
|
LD A,$FF ; RESET COMMAND
|
|
CALL PPK_PUTBYTE ; SEND IT
|
|
CALL PPK_GETBYTE ; GET THE ACK
|
|
LD B,0 ; SETUP LOOP COUNTER
|
|
PPK_RESET0:
|
|
PUSH BC ; PRESERVE LOOP COUNTER
|
|
CALL DELAY ; DELAY 25MS
|
|
CALL PPK_GETBYTE ; TRY TO GET $AA
|
|
POP BC ; RESTORE LOOP COUNTER
|
|
JR NZ,PPK_RESET1 ; GOT A BYTE? IF SO, DONE (WE IGNORE RESPONSE CODE VALUE)
|
|
DJNZ PPK_RESET0 ; KEEP TRYING UNTIL COUNTER EXPIRES
|
|
PPK_RESET1:
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET ; DONE
|
|
;
|
|
;__________________________________________________________________________________________________
|
|
; DECODING ENGINE
|
|
;__________________________________________________________________________________________________
|
|
;
|
|
; STATUS BITS (FOR PPK_STATUS)
|
|
;
|
|
PPK_EXT .EQU 01H ; BIT 0, EXTENDED SCANCODE ACTIVE
|
|
PPK_BREAK .EQU 02H ; BIT 1, THIS IS A KEY UP (BREAK) EVENT
|
|
PPK_KEYRDY .EQU 80H ; BIT 7, INDICATES A DECODED KEYCODE IS READY
|
|
;
|
|
; STATE BITS (FOR PPK_STATE, PPK_LSTATE, PPK_RSTATE)
|
|
;
|
|
PPK_SHIFT .EQU 01H ; BIT 0, SHIFT ACTIVE (PRESSED)
|
|
PPK_CTRL .EQU 02H ; BIT 1, CONTROL ACTIVE (PRESSED)
|
|
PPK_ALT .EQU 04H ; BIT 2, ALT ACTIVE (PRESSED)
|
|
PPK_WIN .EQU 08H ; BIT 3, WIN ACTIVE (PRESSED)
|
|
PPK_SCRLCK .EQU 10H ; BIT 4, CAPS LOCK ACTIVE (TOGGLED ON)
|
|
PPK_NUMLCK .EQU 20H ; BIT 5, NUM LOCK ACTIVE (TOGGLED ON)
|
|
PPK_CAPSLCK .EQU 40H ; BIT 6, SCROLL LOCK ACTIVE (TOGGLED ON)
|
|
PPK_NUMPAD .EQU 80H ; BIT 7, NUM PAD KEY (KEY PRESSED IS ON NUM PAD)
|
|
;
|
|
PPK_SCANCODE .DB 0 ; RAW SCANCODE
|
|
PPK_KEYCODE .DB 0 ; RESULTANT KEYCODE AFTER DECODING
|
|
PPK_STATE .DB 0 ; STATE BITS (SEE ABOVE)
|
|
PPK_LSTATE .DB 0 ; STATE BITS FOR "LEFT" KEYS
|
|
PPK_RSTATE .DB 0 ; STATE BITS FOR "RIGHT" KEYS
|
|
PPK_STATUS .DB 0 ; CURRENT STATUS BITS (SEE ABOVE)
|
|
PPK_IDLE .DB 0 ; IDLE COUNT
|
|
;
|
|
;__________________________________________________________________________________________________
|
|
PPK_DECODE:
|
|
;
|
|
; RUN THE DECODING ENGINE UNTIL EITHER: 1) A TIMEOUT OCCURS TRYING TO GET SCANCODES
|
|
; FROM THE KEYBOARD, OR 2) A DECODED KEY VALUE IS AVAILABLE
|
|
;
|
|
; RETURNS A=0 AND Z SET IF TIMEOUT, OTHERWISE A DECODED KEY VALUE IS AVAILABLE.
|
|
; THE DECODED KEY VALUE AND KEY STATE IS STORED IN PPK_KEYCODE AND PPK_STATE.
|
|
;
|
|
; PPK_KEYCODE AND PPK_STATUS ARE CLEARED AT START. IF IS THE CALLER'S RESPONSIBILITY
|
|
; TO RETRIEVE ANY PRIOR VALUE BEFORE CALLING THIS FUNCTION AGAIN.
|
|
;
|
|
XOR A ; A = ZERO
|
|
LD (PPK_STATUS),A ; CLEAR STATUS
|
|
DEC A ; A = $FF
|
|
LD (PPK_KEYCODE),A ; CLEAR KEYCODE
|
|
|
|
PPK_DECODENEXT: ; PROCESS NEXT SCANCODE
|
|
CALL PPK_GETBYTE ; GET A SCANCODE
|
|
RET Z ; TIMEOUT, RETURN WITH A=0, Z SET
|
|
LD (PPK_SCANCODE),A ; SAVE SCANCODE
|
|
|
|
PPK_DECODE1: ; HANDLE BREAK (KEYUP) F0 PREFIX
|
|
CP $F0 ; BREAK (KEY UP) PREFIX?
|
|
JR NZ,PPK_DECODE2 ; NOPE MOVE ON
|
|
LD A,(PPK_STATUS) ; GET STATUS
|
|
OR PPK_BREAK ; SET BREAK BIT
|
|
LD (PPK_STATUS),A ; SAVE STATUS
|
|
JR PPK_DECODENEXT ; LOOP TO DO NEXT SCANCODE
|
|
|
|
PPK_DECODE2: ; HANDLE EXTENDED KEY E0 PREFIX
|
|
CP $E0 ; EXTENDED KEY PREFIX?
|
|
JR NZ,PPK_DECODE3 ; NOPE MOVE ON
|
|
LD A,(PPK_STATUS) ; GET STATUS
|
|
OR PPK_EXT ; SET EXTENDED BIT
|
|
LD (PPK_STATUS),A ; SAVE STATUS
|
|
JR PPK_DECODENEXT ; LOOP TO DO NEXT SCANCODE
|
|
|
|
PPK_DECODE3: ; HANDLE SPECIAL EXTENDED KEY E1 PREFIX
|
|
; TODO: HANDLE PAUSE KEY HERE...
|
|
|
|
PPK_DECODE4: ; PERFORM EXTENDED MAPPING
|
|
LD A,(PPK_STATUS) ; GET STATUS
|
|
AND PPK_EXT ; EXTENDED BIT SET?
|
|
JR Z,PPK_DECODE5 ; NOPE, MOVE ON
|
|
LD A,(PPK_SCANCODE) ; GET SCANCODE
|
|
LD E,A ; STASH IT IN E
|
|
LD HL,PPK_MAPEXT ; POINT TO START OF EXT MAP TABLE
|
|
PPK_DECODE4A:
|
|
LD A,(HL) ; GET FIRST BYTE OF PAIR
|
|
CP $00 ; END OF TABLE?
|
|
JP Z,PPK_DECODE ; UNKNOWN OR BOGUS, START OVER
|
|
INC HL ; INC HL FOR FUTURE
|
|
CP E ; DOES MATCH BYTE EQUAL SCANCODE?
|
|
JR Z,PPK_DECODE4B ; YES! JUMP OUT
|
|
INC HL ; BUMP TO START OF NEXT PAIR
|
|
JR PPK_DECODE4A ; LOOP TO CHECK NEXT TABLE ENTRY
|
|
PPK_DECODE4B:
|
|
LD A,(HL) ; GET THE KEYCODE VIA MAPPING TABLE
|
|
LD (PPK_KEYCODE),A ; SAVE IT
|
|
JR PPK_DECODE6
|
|
|
|
PPK_DECODE5: ; PERFORM SHIFTED/UNSHIFTED MAPPING
|
|
LD A,(PPK_SCANCODE) ; GET THE SCANCODE
|
|
CP $85 ; PAST END OF TABLE?
|
|
JR NC,PPK_DECODE6 ; YES, SKIP OVER LOOKUP
|
|
|
|
LD A,(PPK_STATE) ; GET STATE
|
|
AND PPK_SHIFT ; SHIFT ACTIVE?
|
|
LD HL,PPK_MAPSTD ; LOAD ADDRESS OF NON-SHIFTED MAPPING TABLE
|
|
JR Z,PPK_DECODE5A ; NON-SHIFTED, MOVE ON
|
|
LD HL,PPK_MAPSHIFT ; LOAD ADDRESS OF SHIFTED MAPPING TABLE
|
|
PPK_DECODE5A:
|
|
LD A,(PPK_SCANCODE) ; GET THE SCANCODE
|
|
LD E,A ; SCANCODE TO E FOR TABLE OFFSET
|
|
LD D,0 ; D -> 0
|
|
ADD HL,DE ; COMMIT THE TABLE OFFSET TO HL
|
|
LD A,(HL) ; GET THE KEYCODE VIA MAPPING TABLE
|
|
LD (PPK_KEYCODE),A ; SAVE IT
|
|
|
|
PPK_DECODE6: ; HANDLE MODIFIER KEY MAKE/BREAK EVENTS
|
|
LD A,(PPK_KEYCODE) ; MAKE SURE WE HAVE KEYCODE
|
|
CP $B8 ; END OF MODIFIER KEYS
|
|
JR NC,PPK_DECODE13 ; BYPASS MODIFIER KEY CHECKING
|
|
CP $B0 ; START OF MODIFIER KEYS
|
|
JR C,PPK_DECODE13 ; BYPASS MODIFIER KEY CHECKING
|
|
|
|
; TODO: STUFF BELOW COULD BE A LOOP
|
|
|
|
; HANDLE L/R SHIFT KEYS
|
|
LD E,PPK_SHIFT ; SETUP TO SET/CLEAR SHIFT BIT
|
|
SUB $B0 ; L-SHIFT?
|
|
JR Z,PPK_DECODE7 ; YES, HANDLE L-SHIFT MAKE/BREAK
|
|
DEC A ; R-SHIFT?
|
|
JR Z,PPK_DECODE8 ; YES, HANDLE R-SHIFT MAKE/BREAK
|
|
|
|
; HANDLE L/R CONTROL KEYS
|
|
LD E,PPK_CTRL ; SETUP TO SET/CLEAR CONTROL BIT
|
|
DEC A ; L-CONTROL?
|
|
JR Z,PPK_DECODE7 ; YES, HANDLE L-CONTROL MAKE/BREAK
|
|
DEC A ; R-CONTROL?
|
|
JR Z,PPK_DECODE8 ; YES, HANDLE R-CONTROL MAKE/BREAK
|
|
|
|
; HANDLE L/R ALT KEYS
|
|
LD E,PPK_ALT ; SETUP TO SET/CLEAR ALT BIT
|
|
DEC A ; L-ALT?
|
|
JR Z,PPK_DECODE7 ; YES, HANDLE L-ALT MAKE/BREAK
|
|
DEC A ; R-ALT?
|
|
JR Z,PPK_DECODE8 ; YES, HANDLE R-ALT MAKE/BREAK
|
|
|
|
; HANDLE L/R WIN KEYS
|
|
LD E,PPK_WIN ; SETUP TO SET/CLEAR WIN BIT
|
|
DEC A ; L-WIN?
|
|
JR Z,PPK_DECODE7 ; YES, HANDLE L-WIN MAKE/BREAK
|
|
DEC A ; R-WIN?
|
|
JR Z,PPK_DECODE8 ; YES, HANDLE R-WIN MAKE/BREAK
|
|
|
|
PPK_DECODE7: ; LEFT STATE KEY MAKE/BREAK (STATE BIT TO SET/CLEAR IN E)
|
|
LD HL,PPK_LSTATE
|
|
JR PPK_DECODE9
|
|
|
|
PPK_DECODE8: ; RIGHT STATE KEY MAKE/BREAK (STATE BIT TO SET/CLEAR IN E)
|
|
LD HL,PPK_RSTATE
|
|
JR PPK_DECODE9
|
|
|
|
PPK_DECODE9: ; BRANCH BASED ON WHETHER THIS IS A MAKE OR BREAK EVENT
|
|
LD A,(PPK_STATUS) ; GET STATUS FLAGS
|
|
AND PPK_BREAK ; BREAK EVENT?
|
|
JR Z,PPK_DECODE10 ; NO, HANDLE A MODIFIER KEY MAKE EVENT
|
|
JR PPK_DECODE11 ; YES, HANDLE A MODIFIER BREAK EVENT
|
|
|
|
PPK_DECODE10: ; HANDLE STATE KEY MAKE EVENT
|
|
LD A,E
|
|
OR (HL)
|
|
LD (HL),A
|
|
JR PPK_DECODE12
|
|
|
|
PPK_DECODE11: ; HANDLE STATE KEY BREAK EVENT
|
|
LD A,E
|
|
XOR $FF
|
|
AND (HL)
|
|
LD (HL),A
|
|
JR PPK_DECODE12
|
|
|
|
PPK_DECODE12: ; COALESCE L/R STATE FLAGS
|
|
LD A,(PPK_STATE) ; GET EXISTING STATE BITS
|
|
AND $F0 ; GET RID OF OLD MODIFIER BITS
|
|
LD DE,(PPK_LSTATE) ; LOAD BOTH L/R STATE BYTES IN D/E
|
|
OR E ; MERGE IN LEFT STATE BITS
|
|
OR D ; MERGE IN RIGHT STATE BITS
|
|
LD (PPK_STATE),A ; SAVE IT
|
|
JP PPK_DECODE ; DONE WITH CURRENT KEYSTROKE
|
|
|
|
PPK_DECODE13: ; NO MORE BREAK KEY PROCESSING!
|
|
LD A,(PPK_STATUS)
|
|
AND PPK_BREAK
|
|
JP NZ,PPK_DECODE
|
|
|
|
PPK_DECODE14: ; TOGGLE KEY PROCESSING
|
|
LD A,(PPK_KEYCODE)
|
|
LD E,PPK_CAPSLCK
|
|
CP $BC
|
|
JR Z,PPK_DECODE15
|
|
LD E,PPK_NUMLCK
|
|
CP $BD
|
|
JR Z,PPK_DECODE15
|
|
LD E,PPK_SCRLCK
|
|
CP $BE
|
|
JR Z,PPK_DECODE15
|
|
JR PPK_DECODE16
|
|
|
|
PPK_DECODE15: ; RECORD THE TOGGLE
|
|
LD A,(PPK_STATE)
|
|
XOR E
|
|
LD (PPK_STATE),A
|
|
|
|
LD A,$ED ; SET/RESET LED'S COMMAND
|
|
CALL PPK_PUTBYTE
|
|
CALL PPK_GETBYTE
|
|
CP $FA ; MAKE SURE WE GET ACK
|
|
JP NZ,PPK_DECODE ; ABORT IF NO ACK
|
|
LD A,(PPK_STATE)
|
|
RRCA
|
|
RRCA
|
|
RRCA
|
|
RRCA
|
|
AND $07
|
|
CALL PPK_PUTBYTE ; SEND THE LED DATA
|
|
CALL PPK_GETBYTE ; READ THE ACK
|
|
|
|
JP PPK_DECODE ; DONE WITH CURRENT KEYSTROKE
|
|
|
|
PPK_DECODE16: ; CONTROL KEY PROCESSING
|
|
LD A,(PPK_STATE)
|
|
AND PPK_CTRL
|
|
JR Z,PPK_DECODE18 ; CONTROL KEY NOT PRESSED, MOVE ON
|
|
LD A,(PPK_KEYCODE)
|
|
CP 'a'
|
|
JR C,PPK_DECODE17
|
|
CP 'z' + 1
|
|
JR NC,PPK_DECODE17
|
|
RES 5,A ; CLEAR BIT 5 TO MAP LOWERCASE A-Z TO UPPERCASE
|
|
PPK_DECODE17:
|
|
CP '@'
|
|
JR C,PPK_DECODE18
|
|
CP '_' + 1
|
|
JR NC,PPK_DECODE18
|
|
RES 6,A
|
|
LD (PPK_KEYCODE),A ; UPDATE KEYCODE TO CONTROL VALUE
|
|
|
|
PPK_DECODE18: ; CAPS LOCK KEY PROCESSING
|
|
LD A,(PPK_STATE)
|
|
AND PPK_CAPSLCK
|
|
JR Z,PPK_DECODE21 ; CAPS LOCK NOT ACTIVE, MOVE ON
|
|
LD A,(PPK_KEYCODE)
|
|
CP 'a'
|
|
JR C,PPK_DECODE19
|
|
CP 'z' + 1
|
|
JR NC,PPK_DECODE19
|
|
JR PPK_DECODE20
|
|
PPK_DECODE19:
|
|
CP 'A'
|
|
JR C,PPK_DECODE21
|
|
CP 'Z' + 1
|
|
JR NC,PPK_DECODE21
|
|
JR PPK_DECODE20
|
|
PPK_DECODE20:
|
|
LD A,(PPK_KEYCODE)
|
|
XOR $20
|
|
LD (PPK_KEYCODE),A
|
|
|
|
PPK_DECODE21: ; NUM PAD PROCESSING
|
|
LD A,(PPK_STATE)
|
|
AND ~PPK_NUMPAD
|
|
LD (PPK_STATE),A ; ASSUME NOT A NUMPAD KEY
|
|
|
|
LD A,(PPK_KEYCODE)
|
|
AND 11100000B ; ISOLATE TOP 3 BITS
|
|
CP 11000000B ; IS NUMPAD RANGE?
|
|
JR NZ,PPK_DECODEX ; NOPE, GET OUT
|
|
|
|
LD A,(PPK_STATE)
|
|
OR PPK_NUMPAD
|
|
LD (PPK_STATE),A ; SET NUMPAD BIT IN STATE
|
|
|
|
AND PPK_NUMLCK
|
|
JR Z,PPK_DECODE22 ; SKIP NUMLOCK PROCESSING
|
|
LD A,(PPK_KEYCODE)
|
|
XOR $10 ; FLIP FOR NUMLOCK
|
|
LD (PPK_KEYCODE),A ; SAVE IT
|
|
|
|
PPK_DECODE22: ; DO NUMPAD MAPPING
|
|
LD A,(PPK_KEYCODE)
|
|
LD HL,PPK_MAPNUMPAD
|
|
SUB $C0
|
|
LD E,A
|
|
LD D,0
|
|
ADD HL,DE
|
|
LD A,(HL)
|
|
LD (PPK_KEYCODE),A
|
|
|
|
PPK_DECODEX:
|
|
LD A,(PPK_KEYCODE) ; GET THE FINAL KEYCODE
|
|
CP $FF ; IS IT $FF (UNKNOWN/INVALID)
|
|
JP Z,PPK_DECODE ; IF SO, JUST RESTART THE ENGINE
|
|
|
|
LD A,(PPK_STATUS) ; GET CURRENT STATUS
|
|
OR PPK_KEYRDY ; SET KEY READY BIT
|
|
LD (PPK_STATUS),A ; SAVE IT
|
|
XOR A ; A=0
|
|
INC A ; SIGNAL SUCCESS WITH A=1
|
|
RET
|
|
;
|
|
;__________________________________________________________________________________________________
|
|
; MAPPING TABLES
|
|
;__________________________________________________________________________________________________
|
|
;
|
|
PPK_MAPSTD: ; SCANCODE IS INDEX INTO TABLE TO RESULTANT LOOKUP KEYCODE
|
|
.DB $FF,$E8,$FF,$E4,$E2,$E0,$E1,$EB,$FF,$E9,$E7,$E5,$E3,$09,'`',$FF
|
|
.DB $FF,$B4,$B0,$FF,$B2,'q','1',$FF,$FF,$FF,'z','s','a','w','2',$FF
|
|
.DB $FF,'c','x','d','e','4','3',$FF,$FF,' ','v','f','t','r','5',$FF
|
|
.DB $FF,'n','b','h','g','y','6',$FF,$FF,$FF,'m','j','u','7','8',$FF
|
|
.DB $FF,',','k','i','o','0','9',$FF,$FF,'.','/','l',';','p','-',$FF
|
|
.DB $FF,$FF,$27,$FF,'[','=',$FF,$FF,$BC,$B1,$0D,']',$FF,'\',$FF,$FF
|
|
.DB $FF,$FF,$FF,$FF,$FF,$FF,$08,$FF,$FF,$C0,$FF,$C3,$C6,$FF,$FF,$FF
|
|
.DB $C9,$CA,$C1,$C4,$C5,$C7,$1B,$BD,$FA,$CE,$C2,$CD,$CC,$C8,$BE,$FF
|
|
.DB $FF,$FF,$FF,$E6,$EC
|
|
;
|
|
PPK_MAPSHIFT: ; SCANCODE IS INDEX INTO TABLE TO RESULTANT LOOKUP KEYCODE WHEN SHIFT ACTIVE
|
|
.DB $FF,$E8,$FF,$E4,$E2,$E0,$E1,$EB,$FF,$E9,$E7,$E5,$E3,$09,'~',$FF
|
|
.DB $FF,$B4,$B0,$FF,$B2,'Q','!',$FF,$FF,$FF,'Z','S','A','W','@',$FF
|
|
.DB $FF,'C','X','D','E','$','#',$FF,$FF,' ','V','F','T','R','%',$FF
|
|
.DB $FF,'N','B','H','G','Y','^',$FF,$FF,$FF,'M','J','U','&','*',$FF
|
|
.DB $FF,'<','K','I','O',')',')',$FF,$FF,'>','?','L',':','P','_',$FF
|
|
.DB $FF,$FF,$22,$FF,'{','+',$FF,$FF,$BC,$B1,$0D,'}',$FF,'|',$FF,$FF
|
|
.DB $FF,$FF,$FF,$FF,$FF,$FF,$08,$FF,$FF,$D0,$FF,$D3,$D6,$FF,$FF,$FF
|
|
.DB $D9,$DA,$D1,$D4,$D5,$D7,$1B,$BD,$FA,$DE,$D2,$DD,$DC,$D8,$BE,$FF
|
|
.DB $FF,$FF,$FF,$E6,$EC
|
|
;
|
|
PPK_MAPEXT: ; PAIRS ARE [SCANCODE,KEYCODE] FOR EXTENDED SCANCODES
|
|
.DB $11,$B5, $14,$B3, $1F,$B6, $27,$B7
|
|
.DB $2F,$EF, $37,$FA, $3F,$FB, $4A,$CB
|
|
.DB $5A,$CF, $5E,$FC, $69,$F3, $6B,$F8
|
|
.DB $6C,$F2, $70,$F0, $71,$F1, $72,$F7
|
|
.DB $74,$F9, $75,$F6, $7A,$F5, $7C,$ED
|
|
.DB $7D,$F4, $7E,$FD, $00,$00
|
|
;
|
|
PPK_MAPNUMPAD: ; KEYCODE TRANSLATION FROM NUMPAD RANGE TO STD ASCII/KEYCODES
|
|
.DB $F3,$F7,$F5,$F8,$FF,$F9,$F2,$F6,$F4,$F0,$F1,$2F,$2A,$2D,$2B,$0D
|
|
.DB $31,$32,$33,$34,$35,$36,$37,$38,$39,$30,$2E,$2F,$2A,$2D,$2B,$0D
|
|
|