;====================================================================== ; NABU KEYBOARD DRIVER ; ; CREATED BY: LES BIRD ; ;====================================================================== ; ; NABU KEYBOARD CODES: ; ; $00-$7F STANDARD ASCII CODES ; $80-$8F JOYSTICK PREFIXES ($80 = JS1, $81 = JS2) ; $90-$9F KEYBOARD ERROR CODES ; $A0-$BF JOYSTICK DATA ; $C0-$DF UNUSED ; $E0-$EF SPECIAL KEYS ; ; NOTE THAT THE ERROR CODE $94 IS A WATCHDOG TIMER THAT WILL BE ; SENT BY THE KEYBOARD EVERY 3.7 SECONDS. ; ; THE CODE BELOW WILL IGNORE (SWALLOW) THE ERROR CODES ($90-$9F) AND ; WILL TRANSLATE SPECIAL KEYS ($E0-$FF) TO ROMWBW EQUIVALENTS. ALL ; OTHER KEYS WILL BE PASSED THROUGH AS IS. ; NABUKB_IODAT .EQU $90 ; KEYBOARD DATA (READ) NABUKB_IOSTAT .EQU $91 ; STATUS (READ), CMD (WRITE) ; ; NABUKB_BUFSZ .EQU 16 ; RECEIVE RING BUFFER SIZE ; DEVECHO "NABUKB: IO=" DEVECHO NABUKB_IODAT DEVECHO "\n" ; ; INITIALZIZE THE KEYBOARD CONTROLLER. ; NABUKB_INIT: CALL NEWLINE PRTS("NABUKB: IO=0x$") LD A,NABUKB_IODAT CALL PRTHEXBYTE ; XOR A CALL NABUKB_PUT CALL NABUKB_PUT CALL NABUKB_PUT CALL NABUKB_PUT CALL NABUKB_PUT LD A,$40 ; RESET 8251 CALL NABUKB_PUT LD A,$4E ; 1 STOP BIT, 8 BITS, 64X CLK CALL NABUKB_PUT LD A,$04 ; ENABLE RECV CALL NABUKB_PUT ; #IF (INTMODE == 1) ; ADD TO INTERRUPT CHAIN LD HL,NABUKB_INT CALL HB_ADDIM1 ; ADD TO IM1 CALL LIST #ENDIF ; #IF (INTMODE == 2) ; INSTALL VECTOR LD HL,NABUKB_INT LD (IVT(INT_NABUKB)),HL ; IVT INDEX #ENDIF ; #IF (INTMODE > 0) ; ENABLE KEYBOARD INTERRUPTS ON NABU INTERRUPT CONTROLLER LD A,14 ; PSG R14 (PORT A DATA) OUT (NABU_RSEL),A ; SELECT IT LD A,(NABU_CTLVAL) ; GET NABU CTL PORT SHADOW REG SET 5,A ; ENABLE VDP INTERRUPTS LD (NABU_CTLVAL),A ; UPDATE SHADOW REG OUT (NABU_RDAT),A ; WRITE TO HARDWARE #ENDIF ; XOR A RET ; #IF (INTMODE > 0) ; ; INTERRUPT HANDLER FOR NABU KEYBOARD. HANDLES INTERRUPTS FOR EITHER ; INT MODE 1 OR INT MODE 2. THE KEYBOARD BUFFER IS JUST A SINGLE CHAR ; AT THIS POINT. NEW CHARACTERS ARRIVING WHEN THE BUFFER IS FULL WILL ; BE DISCARDED. ; NABUKB_INT: IN A,(NABUKB_IOSTAT) ; GET KBD STATUS AND $02 ; CHECK DATA RDY BIT RET Z ; ABORT W/ Z (INT NOT HANDLED) ; ;CALL PC_LT ; *DEBUG* IN A,(NABUKB_IODAT) ; GET THE KEY ;CALL PRTHEXBYTE ; *DEBUG* ;CALL PC_COMMA ; *DEBUG* CALL NABUKB_XB ; TRANSLATE THE KEY ;CALL PRTHEXBYTE ; *DEBUG* ;CALL PC_GT ; *DEBUG* JR C,NABUKB_INTRCV4 ; ABORT IF UNUSABLE KEY LD B,A ; SAVE BYTE READ LD HL,NABUKB_RCVBUF ; SET HL TO START OF BUF STRUCT LD A,(HL) ; GET COUNT CP NABUKB_BUFSZ ; COMPARE TO BUFFER SIZE JR Z,NABUKB_INTRCV4 ; BAIL OUT IF BUFFER FULL, RCV BYTE DISCARDED INC A ; INCREMENT THE COUNT LD (HL),A ; AND SAVE IT INC HL ; HL NOW HAS ADR OF HEAD PTR PUSH HL ; SAVE ADR OF HEAD PTR LD A,(HL) ; DEREFERENCE HL INC HL LD H,(HL) LD L,A ; HL IS NOW ACTUAL HEAD PTR LD (HL),B ; SAVE CHARACTER RECEIVED IN BUFFER AT HEAD INC HL ; BUMP HEAD POINTER POP DE ; RECOVER ADR OF HEAD PTR LD A,L ; GET LOW BYTE OF HEAD PTR SUB NABUKB_BUFSZ+4 ; SUBTRACT SIZE OF BUFFER AND POINTER CP E ; IF EQUAL TO START, HEAD PTR IS PAST BUF END JR NZ,NABUKB_INTRCV3 ; IF NOT, BYPASS LD H,D ; SET HL TO LD L,E ; ... HEAD PTR ADR INC HL ; BUMP PAST HEAD PTR INC HL INC HL INC HL ; ... SO HL NOW HAS ADR OF ACTUAL BUFFER START NABUKB_INTRCV3: EX DE,HL ; DE := HEAD PTR VAL, HL := ADR OF HEAD PTR LD (HL),E ; SAVE UPDATED HEAD PTR INC HL LD (HL),D NABUKB_INTRCV4: OR $FF ; NZ SET TO INDICATE INT HANDLED RET ; AND RETURN ; #ENDIF ; ; NORMAL HBIOS CHAR INPUT STATUS. IF INTERRUPTS ARE NOT ACTIVE, THEN ; KEYBOARD POLLING IS IMPLEMENTED HERE. ; #IF (INTMODE == 0) NABUKB_STAT: LD A,(NABUKB_KSTAT) ; GET KEY WAITING STATUS OR A ; SET FLAGS RET NZ ; KEY WAITING, ALL SET IN A,(NABUKB_IOSTAT) ; GET KBD STATUS AND $02 ; CHECK DATA RDY BIT JR Z,NABUKB_STATX ; BAIL OUT W/ Z (NO KEY) IN A,(NABUKB_IODAT) ; GET THE KEY CALL NABUKB_XB ; TRANSLATE/FILTER JR C,NABUKB_STATX ; IF CF SET, IGNORE LD (NABUKB_KEY),A ; BUFFER IT LD A,1 ; SIGNAL KEY WAITING LD (NABUKB_KSTAT),A ; SAVE IT OR A ; SET FLAGS RET ; DONE ; NABUKB_STATX: XOR A ; SIGNAL NO CHAR READY JP CIO_IDLE ; RETURN VIA IDLE PROCESSOR ; #ELSE NABUKB_STAT: LD A,(NABUKB_BUFCNT) ; GET BUFFER UTILIZATION COUNT OR A ; SET FLAGS JP Z,CIO_IDLE ; NOT READY, RETURN VIA IDLE PROCESSING RET ; DONE #ENDIF ; ; ROUTINE TO FILTER AND TRANSLATE INCOMING NABU KEYBOARD KEYCODES ; ENTER WITH RAW KEY CODE IN A ; RESULT IN A, CF SET IF THE KEY SHOULD BE DISCARDED ; NABUKB_XB: ; $00 - $7F ARE NORMAL ASCII CHARS (PASS THROUGH) BIT 7,A ; HIGH BIT IS SPECIAL CHAR JR Z,NABUKB_XB2 ; IF NORMAL CHAR, RETURN W/ CF CLEAR ; $80-$8F ARE JOSYSTICK PREFIXES (PASS THESE THROUGH) CP $90 ; END OF JOYSTICK PREFIXES JR C,NABUKB_XB2 ; IF JOY PRE, RETURN W/ CF CLEAR ; $90-$9F ARE KEYBOARD ERROR CODES (IGNORE THESE) CP $A0 ; END OF ERR CODES JR C,NABUKB_XB1 ; IF ERR CODE, RETURN W/ CF SET ; $A0-$BF ARE JOYSTICK DATA (PASS THESE THROUGH) CP $C0 ; END OF JOYSTICK DATA JR C,NABUKB_XB2 ; IF JOY DATA, RETURN W/ CF CLEAR ; $C0-$DF ARE UNUSED CODES (IGNORE THESE) CP $E0 ; END OF UNUSED CODES JR C,NABUKB_XB1 ; IF UNUSED CODE, RETURN W/ CF SET ; NABU KEYBOARD USES $E0-$FF FOR SPECIAL KEYS ; HERE WE TRANSLATE TO ROMWBW SPECIAL KEYS AS BEST WE CAN SUB $E0 ; ZERO OFFSET LD HL,NABUKB_XTBL ; POINT TO XLAT TABLE CALL ADDHLA ; OFFSET BY SPECIAL KEY VAL LD A,(HL) ; GET TRANSLATED VALUE OR A ; CHECK FOR N/A (0) RET NZ ; XLAT OK, RET W/ CF CLEAR NABUKB_XB1: ; RETURN W/ CF SET (DISCARD RESULT) SCF ; ELSE SIGNAL INVALID RET ; DONE NABUKB_XB2: ; RETURN W/ CF CLEAR (KEEP RESULT) OR A ; CLEAR CF RET ; RETURN, CF CLEAR ; ; FLUSH KEYBOARD BUFFER ; NABUKB_FLUSH: #IF (INTMODE == 0) XOR A LD (NABUKB_KSTAT),A #ELSE ; RESET THE RECEIVE BUFFER LD DE,NABUKB_RCVBUF ; DE := CNT XOR A ; A := 0 LD (DE),A ; _CNT = 0 INC DE ; DE := ADR OF _HD PUSH DE ; SAVE IT INC DE INC DE INC DE INC DE ; DE := ADR OF _BUF POP HL ; HL := ADR OF _HD LD (HL),E INC HL LD (HL),D ; _HD := _BUF INC HL LD (HL),E INC HL LD (HL),D ; _TL := _BUF #ENDIF RET ; ; WAIT FOR A KEY TO BE READY AND RETURN IT. ; #IF (INTMODE == 0) NABUKB_READ: CALL NABUKB_STAT ; CHECK FOR KEY READY JR Z,NABUKB_READ ; LOOP TIL ONE IS READY LD A,(NABUKB_KEY) ; GET THE BUFFERED KEY LD E,A ; PUT IN E FOR RETURN XOR A ; ZERO TO ACCUM LD C,A ; NO SCANCODE LD D,A ; NO KEYSTATE LD (NABUKB_KSTAT),A ; CLEAR KEY WAITING STATUS RET ; AND RETURN #ELSE ; NABUKB_READ: CALL NABUKB_STAT ; SEE IF CHAR AVAILABLE JR Z,NABUKB_READ ; LOOP UNTIL SO HB_DI ; AVOID COLLISION WITH INT HANDLER LD HL,NABUKB_RCVBUF ; SET HL TO START OF BUF STRUCT LD A,(HL) ; GET COUNT DEC A ; DECREMENT COUNT LD (HL),A ; SAVE UPDATED COUNT INC HL ; HL := ADR OF TAIL PTR INC HL ; " INC HL ; " PUSH HL ; SAVE ADR OF TAIL PTR LD A,(HL) ; DEREFERENCE HL INC HL LD H,(HL) LD L,A ; HL IS NOW ACTUAL TAIL PTR LD C,(HL) ; C := CHAR TO BE RETURNED INC HL ; BUMP TAIL PTR POP DE ; RECOVER ADR OF TAIL PTR LD A,L ; GET LOW BYTE OF TAIL PTR SUB NABUKB_BUFSZ+2 ; SUBTRACT SIZE OF BUFFER AND POINTER CP E ; IF EQUAL TO START, TAIL PTR IS PAST BUF END JR NZ,NABUKB_READ2 ; IF NOT, BYPASS LD H,D ; SET HL TO LD L,E ; ... TAIL PTR ADR INC HL ; BUMP PAST TAIL PTR INC HL ; ... SO HL NOW HAS ADR OF ACTUAL BUFFER START NABUKB_READ2: EX DE,HL ; DE := TAIL PTR VAL, HL := ADR OF TAIL PTR LD (HL),E ; SAVE UPDATED TAIL PTR INC HL ; " LD (HL),D ; " LD E,C ; MOVE CHAR TO RETURN TO E HB_EI ; INTERRUPTS OK AGAIN XOR A ; SIGNAL SUCCESS RET ; AND DONE ; #ENDIF ; ; HELPER ROUTINE TO WRITE ; NABUKB_PUT: OUT (NABUKB_IOSTAT),A NOP NOP NOP NOP NOP RET ; ; ; #IF (INTMODE == 0) NABUKB_KSTAT .DB 0 ; KEY STATUS NABUKB_KEY .DB 0 ; KEY BUFFER #ELSE ; ; RECEIVE BUFFER ; NABUKB_RCVBUF: NABUKB_BUFCNT .DB 0 ; CHARACTERS IN RING BUFFER NABUKB_HD .DW NABUKB_BUF ; BUFFER HEAD POINTER NABUKB_TL .DW NABUKB_BUF ; BUFFER TAIL POINTER NABUKB_BUF .FILL NABUKB_BUFSZ,0 ; RECEIVE RING BUFFER NABUKB_BUFEND .EQU $ ; END OF BUFFER #ENDIF ; ; THIS TABLE TRANSLATES THE NABU KEYBOARD SPECIAL CHARS INTO ; ANALOGOUS ROMWBW STANDARD SPECIAL CHARACTERS. THE TABLE STARTS WITH ; NABU KEY CODE $E0 AND HANDLES $20 POSSIBLE VALUES ($E0-$FF) ; THE SPECIAL KEYS SEND A SPECIFIC KEYCODE TO INDICATE DOWN (KEY ; PRESSED) AND UP (KEY RELEASED). WE WILL ARBITRARILY CHOOSE TO ; RESPOND TO KEY PRESSED. a TRANSLATION VALUE OF $00 MEANS THAT THE ; KEY CODE SHOULD BE DISCARDED. ; NABUKB_XTBL: .DB $F9 ; $E0, RIGHT ARROW (DN) -> RIGHT ARROW .DB $F8 ; $E1, LEFT ARROW (DN) -> LEFT ARROW .DB $F6 ; $E2, UP ARROW (DN) -> UP ARROW .DB $F7 ; $E3, DOWN ARROW (DN) -> DOWN ARROW .DB $F5 ; $E4, PAGE RIGHT (DN) -> PAGE DOWN .DB $F4 ; $E5, PAGE LEFT (DN) -> PAGE UP .DB $F3 ; $E6, NO (DN) -> END .DB $F2 ; $E7, YES (DN) -> HOME .DB $EE ; $E8, SYM (DN) -> SYSRQ .DB $EF ; $E9, PAUSE (DN) -> PAUSE .DB $00 ; $EA, TV/NABU (DN) -> APP .DB $00 ; $EB, N/A .DB $00 ; $EC, N/A .DB $00 ; $ED, N/A .DB $00 ; $EE, N/A .DB $00 ; $EF, N/A .DB $00 ; $F0, RIGHT ARROW (UP) .DB $00 ; $F1, LEFT ARROW (UP) .DB $00 ; $F2, UP ARROW (UP) .DB $00 ; $F3, DOWN ARROW (UP) .DB $00 ; $F4, PAGE RIGHT (UP) .DB $00 ; $F5, PAGE LEFT (UP) .DB $00 ; $F6, NO (UP) .DB $00 ; $F7, YES (UP) .DB $00 ; $F8, SYM (UP) .DB $00 ; $F9, PAUSE (UP) .DB $00 ; $FA, TV/NABU (UP) .DB $00 ; $FB, N/A .DB $00 ; $FC, N/A .DB $00 ; $FD, N/A .DB $00 ; $FE, N/A .DB $00 ; $FF, N/A