TITLE 'MT-70 KEYBOARD FIRMWARE USING 8048 REV. 3.0 4_JUN_84' ;;; MT-70 KEYBOARD FIRMWARE USING 8048 ; REV. 3.0 ; ;; COPYRIGHT 1983 BY ZENITH RADIO CORPORATION ; ; MODIFIED BY GIORA BAR-HAI MARCH 18,1984 ; MODIFIED BY HOWARD FULLMER MAY 16,1984 ; PORT 1 (0-5) RECEIVES THE 6 BIT RESULT FROM THE KEYBOARD SCAN ; PORT 1.6 IS USED AS A CLOCK FOR THE 74LS175 (D-FF) ; PORT 1.7 IS USED TO COMMUNICATE TO THE HOST. (OUTPUT). ; PORT 2 RECEIVES INPUTS FROM CONTROL & SHIFT KEYS (P2.2,P2.3) ; IT OUTPUTS TO CONTROL THE LED INDICATORS & ENABLE THE BELL ; IT ALSO OUTPUTS THE 4 BIT ENCODED VALUE TO SCAN THE KEYBOARD ; (P2.4-P2.7). ; KEYBOARD IDENTIFICATION NUMBER ; IDNUM EQU 10011000B ; FORM OF NUMBER IS 10011xxx ;; MASK WORDS ; CONTM EQU 00000100B ; MASK FOR CONTROL KEY SHFTM EQU 00001000B ; MASK FOR SHIFT KEY OUT0M EQU 01111111B ; MASK OUT GOING DATA LOW OUT1M EQU 10000000B ; MASK OUT GOING DATA HIGH OFFL0M EQU 11011111B ; OFF LINE OUTPUT LOW OFFL1M EQU 00100000B ; OFF LINE OUTPUT HIGH CAPS0M EQU 01111111B ; CAPS LOCKED OUTPUT LOW CAPS1M EQU 10000000B ; CAPS LOCKED OUTPUT HIGH BELL0M EQU 10111111B ; BELL OUTPUT LOW BELL1M EQU 01000000B ; BELL OUTPUT HIGH FFCK0M EQU 10111111B ; D-FF CLK LOW FFCK1M EQU 01000000B ; D-FF CLK HIGH ;; CONSTANTS ; TRUE EQU 0FFH FALSE EQU 00H ;; REPEAT CONSTANTS ; INITDLY EQU 128 ; INITIAL DELAY BEFORE REPEAT MINRPT EQU 34 ; MINIMUM REPEAT SPEED MAXRPT EQU 8 ; MAXIMUM REPEAT SPEED ;; DEBOUNCE CONSTANTS UPBOUNCE EQU 6 ;15ms key release delay DNBOUNCE EQU 3 ;15ms key assert delay ;; DEFINE INTERNAL RAM ; ORG 20H BITMAP: DS 16 ; BITMAP FOR KEYBOARD KBOLD: DS 1 ; LAST KEY PRESSED ON KEYBOARD KBDLY: DS 1 ; DELAY COUNT FOR KEYBOARD KBRLD: DS 1 ; RELOAD VALUE FOR AUTO REPEAT KBTMP: DS 1 ; TEMPORARY VARIABLE FOR KEYBOARD KBENC: DS 1 ; KEYBOARD ENCODED VALUE BNCNT DS 1 ; KEYBOARD DEBOUNCE COUNTER TEMP1: DS 1 ; TEMPORARY #1 TEMP2: DS 1 ; TEMPORARY #2 ROWNUM: DS 1 ; KEYBOARD ROW NUMBER LEDSTA: DS 1 ; LEDs STATUS BELCNT: DS 1 ; BELL DELAY COUNT CAPLKF: DS 1 ; CAPS LOCKED FLAG BELLF: DS 1 ; BELL FLAG TRUE IF RINGING BELL CLICKF: DS 1 ; KEY CLICK FLAG TRUE IF ENABLED REPTF: DS 1 ; AUTO REPEAT FLAG (BITS 0-3) SHFTON: DS 1 ; SHIFT IS DOWN FLAG (BITS 0-3) ORG 3EH LOCKF: DS 1 ; KEYBOARD LOCKED FLAG (BITS 4-7) CNTLON: DS 1 ; CONTROL IS DOWN FLAG (BITS 4-7) ;OFFLNF: DS 1 ; OFF LINE FLAG (NOT USED) ;; FORMAT OF DATA SENT ; ; a = SEVEN BIT ASCII DATA ; s = SHIFT KEY STATUS (1 = DEPRESSED) ; c = CONTROL KEY STATUS (1 = DEPRESSED) ; X = DATA ; B = BINARY ; 0aaaaaaaB ASCII DATA FROM KEYS NULL EQU 00000000B ; NULL BELL EQU 00000111B ; BELL BS EQU 00001000B ; BACKSPACE LF EQU 00001010B ; LINE FEED CR EQU 00001101B ; CARRIAGE RETURN ESC EQU 00011011B ; ESCAPE DEL EQU 01111111B ; DELETE ; ALL KEYS THAT NEED AN ACCESS CODE HAVE BIT 6 SET IN THE MATRIX. ; ALL KEYS NOT TO BE AUTO REPEATED HAVE BIT 5 SET IN THE MATRIX. ; 1scXXXXXB OTHER DATA TO BE DEFINED UPA EQU 10000000B ; UP ARROW DWNA EQU 10000001B ; DOWN ARROW LFTA EQU 10000010B ; LEFT ARROW RGHTA EQU 10000011B ; RIGHT ARROW HOMECLR EQU 10000100B ; HOME CLEAR ERASE EQU 10000101B ; ERASE KEY (NOT USED) HELP EQU 10000110B ; HELP KEY SCROLL EQU 10000111B ; NO SCROLL KEY SETUP EQU 10101000B ; SET UP KEY BREAK EQU 10001001B ; BREAK KEY (NOT USED) CAPLCK EQU 10101010B ; CAPS LOCK KEY TAB EQU 10001011B ; TAB KEY SPACE EQU 10001100B ; SPACE BAR POWERUP EQU 10001111B ; KEYBOARD POWER UP KP0 EQU 10010000B ; KEYPAD 0 KP1 EQU 10010001B ; KEYPAD IL/1 KP2 EQU 10010010B ; KEYPAD 2 KP3 EQU 10010011B ; KEYPAD DL/3 KP4 EQU 10010100B ; KEYPAD 4 KP5 EQU 10010101B ; KEYPAD 5 KP6 EQU 10010110B ; KEYPAD 6 KP7 EQU 10010111B ; KEYPAD IC/7 KP8 EQU 10011000B ; KEYPAD 8 KP9 EQU 10011001B ; KEYPAD DC/9 KPDEC EQU 10011010B ; KEYPAD DECIMAL POINT KPENT EQU 10011011B ; KEYPAD ENTER KPDASH EQU 10011100B ; KEYPAD DASH KPCOM EQU 10011101B ; KEYPAD COMMA ACCESS EQU 10011111B ; ACCESS CODE FN1 EQU 11000000B ; FUNCTION KEY #1 FN2 EQU 11000001B ; FUNCTION KEY #2 FN3 EQU 11000010B ; FUNCTION KEY #3 FN4 EQU 11000011B ; FUNCTION KEY #4 FN5 EQU 11000100B ; FUNCTION KEY #5 FN6 EQU 11000101B ; FUNCTION KEY #6 FN7 EQU 11000110B ; FUNCTION KEY #7 FN8 EQU 11000111B ; FUNCTION KEY #8 FN9 EQU 11001000B ; FUNCTION KEY #9 FN10 EQU 11001001B ; FUNCTION KEY #10 FA EQU 11001010B ; FUNCTION KEY FA FB EQU 11001011B ; FUNCTION KEY FB FC EQU 11001100B ; FUNCTION KEY FC FD EQU 11001101B ; FUNCTION KEY FD ; ; 11011XXXB ID NUMBER (ACTUALLY 10011XXXB) ;; FORMAT OF DATA RECEIVED ; XSNDID EQU 10000000B ; SEND ID NUMBER XRNGBL EQU 10000001B ; RING BELL XENCLK EQU 10000010B ; ENABLE KEY CLICK XDSCLK EQU 10000011B ; DISABLE KEY CLICK XENCAP EQU 10000100B ; ENTER CAPS LOCKED MODE XDSCAP EQU 10000101B ; EXIT CAPS LOCKED MODE XENRPT EQU 10000110B ; ENTER AUTO REPEAT MODE XDSRPT EQU 10000111B ; EXIT AUTO REPEAT MODE XENLCK EQU 10001000B ; ENTER KEYBOARD LOCKED MODE XDSLCK EQU 10001001B ; EXIT KEYBOARD LOCKED MODE XENOFF EQU 10001010B ; ENTER OFF LINE MODE XDSOFF EQU 10001011B ; EXIT OFF LINE MODE ;; POWER UP ROUTINE ; ; THIS SECTION OF CODE IS EXECUTED WHENEVER THE KEYBOARD IS ; POWERED UP OR RESET. THE BELL IS TURNED OFF, ALL LEDS ARE ; TURNED OFF, ALL OF RAM IS CLEARED, ALL FLAGS ARE SET, AND ; THE HOST IS SIGNALED THAT THE KEYBOARD JUST RESET. ORG 0000H POWER: MOV A, #00111111B OUTL P1, A ; INIT PORT 1 FIRST MOST IMPORTANT MOV R0, #LEDSTA ; LED STATUS MOV A, #10111100B MOV @R0, A ; STORE LED STATUS OUTL P2, A ; INIT PORT 2 FOR OUTPUT CALL FFCLK ; PULSE FLIP-FLOP MOV R1, #20 ; DELAY A GOOD 50 MSEC POWER1: MOV R0, #0 POWER2: DJNZ R0, POWER2 DJNZ R1, POWER1 CLR A ; CLEAR ALL OF RAM MOV R0, #32 ; FIRST LOCATION. MOV R1, #32 ; 32 BYTES OF MEMORY. POWER3: INC R0 ; NEXT LOCATION MOV @R0, A ; CLEAR IT DJNZ R1, POWER3 ; UNTIL DONE CALL DISOFF ; DISABLE OFF LINE MODE CALL DISLCK ; DISABLE KEYBOARD LOCK CALL DISCAP ; DISABLE CAPS LOCKED CALL ENCLK ; ENABLE KEY CLICK CALL ENRPT ; ENABLE AUTO REPEAT MOV R0, #TEMP1 MOV @R0, #POWERUP CALL XMT ; SIGNAL POWERUP ;; MAIN SECTION OF CODE ; ; THIS MAIN LOOP CHECKS FOR ANY DATA FROM THE HOST. IF THERE ; IS DATA THEN IT IS PROCESSED. IF THE KEYBOARD IS NOT LOCKED ; THEN IT IS SCANNED DOING ALL N-KEY ROLL OVER, AUTO REPEAT, AND ; ANY OTHER SPECIAL FUNCTIONS. ALL KEYS TO BE TRANSMITTED ARE ; PROCESSED BY THE SCAN ROUTINE. IF THE BELL IS CURRENTLY ; RINGING THEN A CHECK TO STOP THE BELL IS MADE. MAIN: CALL RCV ; RECEIVE ANY MESSAGE FROM HOST JC MAIN1 ; IF DATA THEN CALL DPR ; PROCESS DATA MAIN1: MOV R0, #LOCKF MOV A, @R0 ANL A, #11110000B ; CLEAR BITS 0-3 TO READ 4-7 ONLY JNZ MAIN2 ; IF KEYBOARD NOT LOCKED THEN CALL KBSCAN ; SCAN KEYBOARD AND PROCESS KEYS MAIN2: MOV R0, #BELLF MOV A, @R0 JZ MAIN3 ; IF RINGING THE BELL THEN CALL GOBELL ; DO THE BELL STUFF MAIN3: JMP MAIN ;; DPR - DATA PROCESSOR ; ; *DPR* PROCESSES ALL DATA FROM THE HOST. ; ; ; ENTRY (A) = BYTE FROM HOST ; ; EXIT NONE ; ; USES ALL DPR: MOV R0, #TEMP1 ; SAVE VALUE TO PROCESS MOV @R0, A ADD A, #-(XSNDID) JZ SENDID ; IF SEND ID NUMBER MOV A, @R0 ADD A, #-(XRNGBL) JZ RINGBL ; ELSE IF RING BELL MOV A, @R0 ADD A, #-(XENCLK) JZ ENCLK ; ELSE IF ENABLE KEY CLICK MOV A, @R0 ADD A, #-(XDSCLK) JZ DISCLK ; ELSE IF DISABLE KEY CLICK MOV A, @R0 ADD A, #-(XENCAP) JZ ENCAP ; ELSE IF ENABLE CAPS LOCKED MOV A, @R0 ADD A, #-(XDSCAP) ; ELSE IF DISABLE CAPS LOCKED JZ DISCAP MOV A, @R0 ADD A, #-(XENRPT) JZ ENRPT ; ELSE IF ENABLE REPEAT FUNCTION MOV A, @R0 ADD A, #-(XDSRPT) JZ DISRPT ; ELSE IF DISABLE REPEAT FUNCTION MOV A, @R0 ADD A, #-(XENOFF) JZ ENOFF ; ELSE IF ENABLE OFF LINE MOV A, @R0 ADD A, #-(XDSOFF) JZ DISOFF ; ELSE IF DISABLE OFF LINE MOV A, @R0 ADD A, #-(XENLCK) JZ ENLCK ; ELSE IF ENABLE KEYBOARD LOCK MOV A, @R0 ADD A, #-(XDSLCK) JZ DISLCK ; ELSE IF DISABLE KEYBOARD LOCK RET ; ELSE RETURN ; SENDID - SEND ID NUMBER ; ; *SENDID* SENDS THE ID NUMBER OF THIS KEYBOARD. THIS COULD ; BE USEFUL FOR LATER TERMINALS TO DETERMINE WHAT FUNCTIONS ; ARE AVAILABLE ON THE KEYBOARD. SENDID: MOV R0, #TEMP1 MOV A, #ACCESS MOV @R0, A CALL XMT ; OUTPUT THE ACCESS CODE MOV A, #IDNUM MOV @R0, A JMP XMT ; OUTPUT ID NUMBER AND RETURN ; RINGBL - RING BELL ; ; *RINGBL* STARTS THE BELL RINGING IN BACKGROUND SO THAT ; KEYBOARD SCANNING MAY STILL TAKE PLACE. IT USES THE TIMER ; AND TIMER OVERFLOW FLAG TO DO THIS. RINGBL: MOV A, #BELL1M ; START BELL RINGING CALL FFCLK1 ; PULSE THE FLIP FLOP MOV R0, #BELCNT MOV @R0, #8 ; SET BELL COUNT MOV R0, #BELLF MOV @R0, #TRUE ; FLAG TRUE TO RING THE BELL MOV A, #-255 MOV T, A ; SET TIMER DELAY STRT T ; AND START TIMER RET ; GOBELL - GO RING BELL ; ; *GOBELL* CHECKS THE BELL FROM THE BACKGROUND JOB. IF THE ; TIMER HAS OVERFLOWED THEN IT IS KNOWN THAT THE BELL SHOULD ; BE DONE. GOBELL: JTF GOBEL1 ; IT TIME IS NOT UP THEN RET ; RETURN GOBEL1: MOV A, #-255 ; LOAD NEW DELAY TIME MOV T, A MOV R0, #BELCNT MOV A, @R0 DEC A ; DECREMENT BELL DELAY COUNT MOV @R0, A JNZ GOBRET ; IF DONE RINGING THEN STOP TCNT ; STOP TIMER MOV R0, #BELLF MOV @R0, #FALSE ; FLAG TO STOP BELL MOV A, #BELL0M ; STOP BELL FROM RINGING JMP FFCLK0 ; PULSE THE FF & RETURN GOBRET: RET ; ENCLK - ENABLE KEY CLICK ; ; *ENCLK* ENABLES KEY CLICK BY SETTING A FLAG FOR LATER USE ; BY THE BACKGROUND JOBS. ENCLK: MOV R0, #CLICKF MOV @R0, #TRUE ; FLAG KEY CLICK TRUE RET ; DISCLK - DISABLE KEY CLICK ; ; *DISCLK* DISABLE KEY CLICK BY SETTING A FLAG FOR LATER USE ; BY THE BACKGROUND JOBS. DISCLK: MOV R0, #CLICKF MOV @R0, #FALSE ; FLAG KEY CLICK FALSE RET ; ENCAP - ENABLE CAPS LOCKED ; ; *ENCAP* ENABLES CAPS LOCKED MODE BY SETTING A FLAG FOR LATER ; USE BY THE BACKGROUND JOBS. ENCAP: MOV R0, #CAPLKF MOV @R0, #TRUE ; FLAG CAPS LOCKED TRUE MOV A, #CAPS0M ; LIGHT CAPS LOCKED LED JMP FFCLK0 ; PULSE FLIP-FLOP & RETURN ; DISCAP - DISABLE CAPS LOCKED ; ; *DISCAP* DISABLES CAPS LOCKED MODE BY SETTING A FLAG FOR LATER ; USE BY THE BACKGROUND JOBS. DISCAP: MOV R0, #CAPLKF MOV @R0, #FALSE ; FLAG CAPS LOCKED FALSE MOV A, #CAPS1M ; TURN OFF CAPS LOCKED LED JMP FFCLK1 ; PULSE FLIP-FLOP & RETURN. ; ENRPT - ENABLE AUTO REPEAT ; ; *ENRPT* ENABLES AUTO REPEAT BY SETTING A FLAG FOR LATER ; USE BY THE BACKGROUND JOBS. ENRPT: MOV R0, #REPTF MOV A, @R0 ORL A, #00001111B ; ENABLE AUTO REPEAT FLAG MOV @R0, A RET ; DISRPT - DISABLE AUTO REPEAT ; ; *DISRPT* DISABLES AUTO REPEAT BY SETTING A FLAG FOR LATER ; USE BY THE BACKGROUND JOBS. DISRPT: MOV R0, #REPTF MOV A, @R0 ANL A, #11110000B ; DISABLE AUTO REPEAT FLAG MOV @R0, A RET ; ENOFF - ENABLE OFF LINE LED ; ENOFF: MOV A, #OFFL0M ; TURN ON THE OFF LINE LED JMP FFCLK0 ; PULSE FLIP-FLOP & RETURN. ; DSOFF - DISABLE OFF LINE LED ; ; *DSOFF* TURNS OFF THE OFF LINE LED DISOFF: MOV A, #OFFL1M ; TURN OFF THE OFF LINE LED JMP FFCLK1 ; PULSE FLIP-FLOP & RETURN ; ENLCK - ENABLE KEYBOARD LOCK ; ; *ENLCK* TURNS OFF ANY KEYBOARD SCANNING AND TURNS OFF THE ; KEYBOARD LOCKED LED. ENLCK: MOV R0, #LOCKF MOV A, @R0 ORL A, #11110000B ; FLAG THAT KEYBOARD IS LOCKED MOV @R0, A RET ; DISLCK - DISABLE KEYBOARD LOCK ; ; *DISLCK* TURNS OFF THE KEYBOARD LOCKED FEATURE DISLCK: MOV R0, #LOCKF MOV A, @R0 ANL A, #00001111B ; FLAG KEYBOARD NOT LOCKED MOV @R0, A RET ORG 0100H ; *** NEW PAGE BOUNDRY *** ;; KBSCAN - KEYBOARD SCAN ; ; AUTO REPEAT, AND N-KEY ROLL OVER. IF A KEY SHOULD BE OUTPUTED ; IT IS SENT TO THE HOST ; ; ; REGISTER USAGE ; ; R0 GENERAL WORK POINTER ; R1 POINTER TO KEYBOARD BIT MAP ; R2 SCAN ROW NUMBER ; R3 SCAN COLUMN NUMBER ; R4 TEMPORARY VARIABLE #1 ; R5 TEMPORARY VARIABLE #2 ; R6 FLAG IF ANY KEY IS DOWN ; R7 FLAG IF SAME KEY IS DOWN ; ; ; ENTRY NONE ; ; EXIT NONE ; ; USES ALL ; ; SETUP FOR SCAN LOOP ; KBSCAN: MOV R6, #FALSE ; ASSUME AND SET NO KEY IS DOWN MOV R7, #TRUE ; ASSUME AND SET SAME KEY IS DOWN MOV A, #00001111B ; INITIALIZE SCAN ROW NUMBER OUTL P2,A MOV R0, #ROWNUM MOV @R0, #0 MOVX @R0,A ; WR PULSE TO STROBE 14515 DECODER ; (NOT USED WHEN 74159 IS CONNECTED) MOV R1, #BITMAP ; SET POINTER TO KB BIT MAP ADDRESS MOV R2, #16 ; SET INDEX COUNTER TO 16 COLUMNS ; MAIN KEYBOARD SCAN LOOP ; KBLP1: IN A, P1 ; READ KEYBOARD MATRIX ORL A, #11000000B ; CHECK BITS 0-5 ONLY CPL A MOV R5,A ; SAVE SCAN INFO JZ NOKEY MOV R6, #TRUE ; FLAG THAT A KEY IS DOWN NOKEY: MOV A,@R1 ; GET KB BIT MASK ANL A,#0C0H ; MASK OUT BOUNCE BITS JZ NOUP ; JUMP IF NO BOUNCE BITS CALL INCCNT ; INCREMENT ROW BOUNCE COUNT MOV A, @R1 ; GET OLD KB BIT MAP XRL A,#40H ; INVERT BIT 6 JB6 NODOWN ; JUMP IF NO DOWN BOUNCE MOV A,R4 ; GET BOUNCE COUNT ADD A,#-DNBOUNCE ; SUBTRACT DOWN BOUNCE JNZ NODOWN ; JUMP IF COUNT NOT DOWN YET MOV A,@R1 ; CLEAR DOWN BOUNCE FLAG ANL A,#0BFH MOV @R1,A NODOWN: MOV A,@R1 XRL A,#80H ; INVERT BIT 7 JB7 NOUP ; JUMP IF NO UP BOUNCE MOV A,R4 ; GET BOUNCE COUNT ADD A,#-UPBOUNCE ; SUBTRACT UP BOUNCE JNZ NOUP ; JUMP IF COUNT NOT DONE YET MOV A,R5 ; UPDATE CHANGES ORL A,#01000000B ; AND CLEAR UP BOUNCE FLAG ANL A,@R1 MOV @R1,A NOUP: MOV A,@R1 ; SEE IF ANY CHANGES ANL A,#3FH XRL A,R5 JZ NOCHNG ; JUMP IF NO CHANGES MOV R4,A ; SAVE CHANGES MOV A,@R1 JB6 DNOFF ; JUMP IF DOWN IS OFF MOV A,R4 ; GET CHANGES ANL A,R5 ; LOOK FOR DOWN CHANGES JZ DNOFF ; JUMP IF NO DOWN CHANGES MOV R3,A ; SAVE DOWN CHANGES ORL A,@R1 ; UPDATE KB BIT MAP ORL A,#01000000B ; SET DOWN BOUNCE FLAG MOV @R1,A CALL CLRCNT ; CLEAR BOUNCE COUNT DNOFF: MOV A,@R1 JB7 UPOFF ; JUMP IF UP IS OFF MOV A,R5 ; LOOK FOR UP CHANGES CPL A ANL A,R4 JZ UPOFF CALL CLRCNT MOV A,@R1 ; SET UP BOUNCE FLAG ORL A,#10000000B MOV @R1,A UPOFF: MOV A,R3 JZ NOCHNG ; INNER KEYBOARD SCAN LOOP ; MOV R7,#FALSE MOV R3, #6 ; SET INDEX COUNTER TO 6 BITS KBLP2: RRC A ; ROTATE BIT INTO CARRY JNC KBSKP2 ; IF THIS KEY IS DOWN THEN BEGIN MOV R5, A ; SAVE SHIFTED VALUE TO RESTORE LATER MOV A, R2 SEL RB1 ; SELECT RB #1 TO SAVE REGISTERS MOV R2, A MOV R1, #6 ; TO MULTIPLY BY 6 CALL BMPY ; MULTIPLY R2 BY 6 SEL RB0 ; RETURN TO THE ORIGINAL RB ADD A, R3 ; ADD IN COLUMN OFFSET CLR C ADD A, #-6 ; SUBTRACT BIAS MOV R0, #KBENC MOV @R0, A ; SAVE NUMBER REPRESENTATION OF KEY ORL P2, #(CONTM + SHFTM) MOV R0, #SHFTON MOV A, @R0 ANL A, #11110000B ; SET SHIFT DOWN FLAG FALSE MOV @R0, A IN A, P2 ; READ FOR SHIFT KEY ANL A, #SHFTM ; MASK FOR SHIFT KEY JNZ KBSCN4 ; IF THE SHIFT KEY IS DOWN THEN BEGIN MOV A, @R0 ORL A, #00001111B MOV @R0, A ; SET SHIFT DOWN FLAG TRUE CALL TBSHT ; GET KEY VALUE FROM SHIFT TABLE JMP KBSCN5 KBSCN4: CALL TBLOW ; ELSE GET KEY VALUE FROM REGULAR TABLE KBSCN5: MOV R0, #KBOLD MOV @R0, A ; SAVE KEY VALUE MOV R0, #CAPLKF MOV A, @R0 ; GET CAPS LOCKED FLAG JZ KBSCN6 ; IF CAPS LOCKED THEN BEGIN CALL LOWUP ; CONVERT LOWER CASE TO UPPER CASE MOV R0, #KBOLD MOV @R0, A ; SAVE KEY VALUE KBSCN6: MOV R0, #CNTLON MOV A, @R0 ANL A, #00001111B ; SET CONTROL DOWN FLAG FALSE MOV @R0, A IN A, P2 ; READ FOR CONTROL KEY ANL A, #CONTM ; MASK FOR CONTROL KEY JNZ KBSCN7 ; IF THE CONTROL KEY IS DOWN THEN BEGIN MOV A, @R0 ORL A, #11110000B ; SET CONTROL DOWN FLAG TRUE MOV @R0, A CALL TOCTL ; CONVERT TO CONTROL CODE MOV R0, #KBOLD MOV @R0, A ; SAVE KEY VALUE KBSCN7: MOV R0, #KBDLY MOV @R0, #INITDLY ; SET AUTO REPEAT DELAY COUNT MOV R0, #KBRLD MOV @R0, #MINRPT ; SET REPEAT RELOAD VALUE SEL RB1 ; SELECT RB #1 TO SAVE REGISTERS CALL PROC ; *** PROCESS THE KEY *** SEL RB0 ; RESTORE ORIGINAL REGISTERS MOV A, R5 ; RESTORE SHIFTED VALUE KBSKP2: DJNZ R3, KBLP2 ; UNTIL SCAN COLUMN NUMBER = 0 NOCHNG: MOV R0, #LEDSTA ; LED STATUS MOV A,@R0 MOV R0, #ROWNUM INC @R0 ; INCREMENT ROW NUMBER ANL A, #0FH ; SAVE BITS 0-3 SWAP A ORL A, @R0 SWAP A OUTL P2, A ; BUMP SCAN ROW NUMBER TO NEXT ROW MOVX @R0,A ; WR PULSE TO STROBE 14515 DECODER ; (NOT USED WHEN 74159 IS CONNECTED) INC R1 ; BUMP KB BIT MAP POINTER DJNZ R2, KBLP1 ; UNTIL SCAN ROW NUMBER = 0 ; SCANNING IS ALL DONE NOW, CHECK WHAT HAPPENED ; MOV A, R6 ; GET KEY DOWN FLAG JNZ KBDWN ; IF NO KEY IS DOWN THEN BEGIN KBEXIT: RET ; RETURN KBDWN: MOV A, R7 ; GET SAME KEY DOWN FLAG JZ KBEXIT ; IF SAME KEY IS DOWN THEN BEGIN MOV R0, #KBDLY MOV A, @R0 DEC A MOV @R0, A ; DECREMENT THE DELAY COUNT JNZ KBEXIT ; IF DELAY TIME IS UP THEN BEGIN MOV R0, #KBRLD MOV A, @R0 ; GET RELOAD VALUE ADD A, #-MAXRPT JZ KBDWN1 ; IF OK TO REDUCE DELAY THEN MOV A, @R0 DEC A ; REDUCE DELAY MOV @R0, A ; AND SAVE IT KBDWN1: MOV A, @R0 ; ELSE GET FINAL RELOAD VALUE MOV R0, #KBDLY MOV @R0, A ; RESET THE DELAY COUNT MOV R0, #REPTF MOV A, @R0 ANL A, #00001111B ; CLEAR BITS 4-7 TO READ 0-3 ONLY JZ KBEXIT ; IF AUTO REPEAT ENABLED THEN MOV R0, #KBOLD MOV A, @R0 ; GET KEY VALUE RLC A JNC KBDWN2 ; IF ASCII OR RLC A RLC A JC KBEXIT ; NON-ASCII & AUTO REPEAT ALLOWED THEN KBDWN2: JMP PROC ; *** PROCESS OLD KEY *** ORG 0200H ; *** NEW PAGE BOUNDRY *** ;; XMT - TRANSMIT DATA TO HOST ; ; *XMT* OUTPUTS BYTES TO THE HOST USING A SPECIAL HANDSHAKE. ; ; ; ENTRY (@R0) = BYTE TO OUTPUT ; ; EXIT NONE ; ; USES ALL XMT: ANL P1, #OUT0M ; SET LOW AS SAFETY PRECAUTION MOV A, @R0 ; GET BYTE MOV R1, #8 ; INITIALIZE INDEX FOR 8 BITS ORL P1, #OUT1M ; SET HIGH JT1 XMTRET ; IF REQUEST FROM HOST THEN EXIT ; REQUEST HOST ATTENTION XMT1: JNT1 XMT1 ; WAIT FOR REQUEST DATA SIGNAL RRC A ; ROTATE DATA IN JNC XMT2 ; IF HIGH BIT TO BE SENT THEN ORL P1, #OUT1M ; SET BIT HIGH JMP XMT3 XMT2: ANL P1, #OUT0M ; ELSE SET BIT LOW XMT3: XMT4: JT1 XMT4 ; WAIT FOR DATA RECEIVED SIGNAL DJNZ R1, XMT1 ; UNTIL ALL 8 BITS ARE DONE ANL P1, #OUT0M ; PULL OUTPUT LOW AND RETURN XMTRET: RET ;; RCV - RECEIVE DATA FROM HOST ; ; *RCV* TAKES DATA FROM THE HOST AND PROCESSES IT IF AVAILABLE ; ; ; ENTRY NONE ; ; EXIT (A) = BYTE RECEIVED IF AVAILABLE ; 'C' = SET IF NO DATA, CLEAR OTHERWISE ; ; USES ALL RCV: JT1 RCV1 ; IF NO DATA THEN CLR C CPL C ; SET CARRY AND RETURN RET RCV1: CLR A ; INITIALIZE RECEIVING BYTE MOV R1, #8 ; INDEX COUNTER FOR 8 BITS RCVLP: ORL P1, #OUT1M ; REQUEST DATA BY SETTING HIGH CALL RCVDLY ; DELAY 500 USEC CLR C ; INIT CARRY LOW JT1 RCV2 ; IF INPUT IS LOW THEN CPL C ; SET CARRY RCV2: RRC A ; ROTATE DATA IN ANL P1, #OUT0M ; DATA RECEIVED BY SETTING LOW CALL RCVDLY ; DELAY 500 USEC DJNZ R1, RCVLP ; UNTIL ALL 8 BITS CALL RCVDLY ; WAIT FOR HOST TO FINISH CLR C ; FLAG OK AND RETURN RET RCVDLY: MOV R4, #50 RCVDL1: DJNZ R4, RCVDL1 ; DELAY AT LEAST 500 USEC RET ;; LOWUP - CONVERT FROM LOWER CASE TO UPPER CASE ; ; *LOWUP* CONVERTS THE ASCII CHARACTERS FROM 'a' TO 'z' ; TO THEIR UPPER CASE VALUES. ; ; ; ENTRY (KBOLD) = ASCII VALUE TO CONVERT ; ; EXIT (A) = CONVERTED BYTE IF NEEDED ; ; USES A, R0 LOWUP: MOV R0, #KBOLD MOV A, @R0 ; GET CHARACTER TO CONVERT ADD A, #-('a') JNC LOWUP1 ; IF CHARACTER >= 'a' MOV A, @R0 ADD A, #-('z'+1) JC LOWUP1 ; AND IF CHARACTER <= 'z' THEN MOV A, @R0 ADD A, #-('a'-'A') ; CONVERT TO UPPER CASE RET LOWUP1: MOV A, @R0 ; ELSE USE OLD VALUE RET ;; TOCTL - CONVERT TO CONTROL CHARACTER ; ; *TOCTL* CONVERTS THE ASCII CHARACTER INTO A CONTROL CHARACTER ; ; ; ENTRY (KBOLD) = ASCII VALUE TO CONVERT ; EXIT (A) = CONVERTED BYTE ; ; USES A, R0, TEMP1 TOCTL: CALL LOWUP ; CONVERT TO UPPER CASE MOV R0, #TEMP1 MOV @R0, A ; SAVE CONVERTED UPPER CASE BYTE ADD A, #-('@') JNC TOCTL1 ; IF INSIDE LOWER RANGE MOV A, @R0 ADD A, #-(60H) JC TOCTL1 ; AND INSIDE UPPER RANGE THEN MOV A, @R0 ADD A, #-('@') ; CONVERT TO CONTROL CHARACTER RET TOCTL1: MOV A, @R0 ; ELSE USE OLD VALUE RET ;; PROC - PROCESS KEY ; ; *PROC* TAKES THE ASCII VALUE OR SPECIAL VALUE AND SENDS IT ; TO THE HOST SENDING AN ACCESS CODE IF NEEDED AND MASKING ; IN THE SHIFT AND CONTROL VALUES IF NEEDED. ; ; ; ENTRY (KBOLD) = BYTE TO PROCESS ; ; EXIT NONE ; ; USES ALL PROC: MOV R0, #KBOLD MOV A, @R0 ; GET KEY TO SEND RLC A JNC PROC3 ; IF ASCII CHARACTER THEN SKIP RLC A JNC PROC1 ; IF ACCESS CODE NEEDED THEN BEGIN MOV R0, #TEMP1 MOV @R0, #ACCESS CALL XMT ; OUTPUT ACCESS CODE PROC1: MOV R0, #KBOLD MOV A, @R0 ; GET VALUE TO OUTPUT ANL A, #10011111B ; CLEAR SHIFT/CONTROL AREAS MOV R0, #TEMP1 MOV @R0, A ; SAVE NEW VALUE MOV R1, #SHFTON MOV A, @R1 ANL A, #00001111B ; CLEAR BITS 4-7 TO READ 0-3 ONLY JZ PROC2 ; IF SHIFT KEY DEPRESSED THEN MOV A, @R0 ORL A, #01000000B ; MASK IN SHIFT CODE MOV @R0, A PROC2: MOV R1, #CNTLON MOV A, @R1 ANL A, #11110000B ; CLEAR BITS 0-3 TO READ 4-7 ONLY JZ PROC3 ; IF CONTROL KEY DEPRESSED THEN MOV A, @R0 ORL A, #00100000B ; MASK IN CONTROL CODE MOV @R0, A PROC3: CALL XMT ; OUTPUT CHARACTER POINTED BY @R0 MOV R0, #CLICKF MOV A, @R0 JZ PROC4 ; IF KEY CLICK ENABLED THEN ;; KEYCLK - KEY CLICK ; *KEYCLK* CLICKS THE BELL ON THE KEYBOARD. IF BELL IS ; RINGING THEN THE BELL IS NOT DISTERBED. ; ; ENTRY NONE ; EXIT NONE ; USES A, R0 KEYCLK: MOV R0, #LEDSTA ; READ FOR BELL STATUS MOV A, @R0 ANL A, #BELL1M ; MASK FOR BELL STATUS JNZ KEYCL2 ; IF NO BELL THEN MOV A, #BELL1M ; PULL BELL HIGH CALL FFCLK1 ; PULSE FLIP-FLOP CLOCK MOV R0, #255 KEYCL1: NOP NOP DJNZ R0, KEYCL1 ; DELAY 500 MICROSECONDS MOV A, #BELL0M ; PULL BELL LOW CALL FFCLK0 ; PULSE FLIP-FLOP CLOCK PROC4: KEYCL2: RET ;; BMPY - BINARY MULTIPLY ; ; *BMPY* MULTIPLIES ONE-BYTE MULTIPLIER AND A ONE-BYTE ; MULTIPLICAND. ; ; ; ENTRY - R1-MULTIPLIER ; R2-MULTIPLICAND ; ; EXIT - A -LS BYTE OF RESULT ; R1-MS BYTE OF RESULT ; ; USES - A,R1,R2,R3 (R3 IS A LOOP COUNTER(=8)) ; BMPY: MOV R3, #8 ; SET COUNTER TO 8 CLR A CLR C BMP1: RRC A ; DOUBLE SHIFT RIGHT ACC & R1 XCH A, R1 ; INTO CARRY RRC A XCH A, R1 JNC BMP2 ; IF CARRY=1 ADD, OTHERWISE DON'T ADD A, R2 ; ADD MULTIPLICAND TO ACCUMULATOR BMP2: DJNZ R3, BMP1 ; DEC COUNTER & LOOP IF 0 RRC A ; DO A FINAL RIGHT SHIFT AT THE XCH A, R1 ; END OF THE ROUTINE RRC A RET ; FFCLK0 or FFCLK1 - FLIP-FLOP CLOCK ; ; *FFCLK0/1* TURNS THE LED OM/OFF & PULSES THE FLIP-FLOP CLOCK ; ; ENTRY - A-MASK BYTE ; FFCLK1: MOV R0, #LEDSTA ORL A, @R0 JMP FFCLK01 FFCLK0: MOV R0, #LEDSTA ANL A, @R0 FFCLK01: MOV @R0, A ; SAVE LEDs NEW STATUS OUTL P2, A ; OUTPUT TO PORT 2 FFCLK: ORL P1, #FFCK1M ; CLOCK HIGH ANL P1, #FFCK0M ; CLOCK LOW RET INCCNT: CALL GETCNT JNC NOSWAP0 SWAP A NOSWAP0: INC A MOV R4,A JNC NOSWAP1 SWAP A NOSWAP1: MOV @R0,A MOV A,#0FH ANL A,R4 MOV R4,A RET CLRCNT: CALL GETCNT JNC NOSWAP2 SWAP A NOSWAP2: ANL A,#0F0H JNC NOSWAP3 SWAP A NOSWAP3: MOV @R0,A RET GETCNT: MOV A,R1 CLR C RRC A MOV R0,A MOV A,@R0 RET ORG 0300H ; *** NEW PAGE BOUNDARY *** ;; TBLOW - TABLE LOWER CASE ; ; *TBLOW* DOES THE TABLE LOOKUP FOR THE LOWER CASE LETTERS ; ; ; ENTRY (KBENC) = KEY NUMBER ; ; EXIT (A) = ASCII VALUE OR SPECIAL VALUE ; ; USES A, R0 TBLOW: MOV R0, #KBENC MOV A, #LOW (TBLOWT - 1) ADD A, @R0 ; ADD OFFSET AND CONSTANT INTO TABLE MOVP A, @A ; GET VALUE RET ;; TBSHT - TABLE UPPER CASE ; ; *TBSHT* DOES THE TABLE LOOKUP FOR THE UPPER CASE LETTERS ; ; ; ENTRY (KBENC) = KEY NUMBER ; ; EXIT (A) = ASCII VALUE OR SPECIAL VALUE ; ; USES A, R0 TBSHT: MOV R0, #KBENC MOV A, #LOW (TBSHTT - 1) ADD A, @R0 ; ADD OFFSET AND CONSTANT INTO TABLE MOVP A, @A ; GET VALUE RET ;; TBLOWT - LOWER CASE TABLE ; TBLOWT: DB FC, FD ; S15 BITS 5,4 DB SETUP, NULL, NULL, NULL ; S15 BITS 7,6,5,4 DB FB, FA ; S14 BITS 5,4 DB FN10, FN9, FN8, FN7 ; S14 BITS 7,6,5,4 DB FN6, FN5 ; S13 BITS 5,4 DB FN4, FN3, FN2, FN1 ; S13 BITS 3,2,1,0 DB BS, LF ; S12 BITS 5,4 DB KPDASH, KPENT, CR, SPACE ; S12 BITS 3,2,1,0 DB '/', TAB ; S11 BITS 5,4 DB KPDEC, '.', 'i', 'v' ; S11 BITS 3,2,1,0 DB LFTA, ESC ; S10 BITS 5,4 DB KPCOM, ',', 'u', 'c' ; S10 BITS 3,2,1,0 DB RGHTA, '1' ; S9 DB KP1, '\', 'y', 'x' ; S9 DB DWNA, '2' ; S8 DB KP2, 'o', 't', 'z' ; S8 DB UPA, '3' ; S7 DB KP3, 'p', 'h', 'a' ; S7 DB DEL, '4' ; S6 DB KP4, ''', 'j', 's' ; S6 DB CAPLCK, '5' ; S5 DB KP5, '`', 'k', 'd' ; S5 DB SCROLL, '6' ; S4 DB KP6, '=', 'l', 'f' ; S4 DB NULL, '7' ; S3 DB KP7, '-', 'm', 'r' ; S3 DB HOMECLR,'8' ; S2 DB KP8, '[', 'n', 'e' ; S2 DB HELP, '9' ; S1 DB KP9, ']', 'b', 'w' ; S1 DB ERASE, '0' ; S0 DB KP0, ';', 'g', 'q' ; S0 ;; TBSHTT - UPPER CASE TABLE ; TBSHTT: DB FC, FD ; S15 BITS 5,4 DB SETUP, NULL, NULL, NULL ; S15 BITS 3,2,1,0 DB FB, FA ; S14 BITS 5,4 DB FN10, FN9, FN8, FN7 ; S14 BITS 3,2,1,0 DB FN6, FN5 ; S13 HIGH DB FN4, FN3, FN2, FN1 ; S13 LOW DB BS, LF ; S12 HIGH DB KPDASH, KPENT, CR, SPACE ; S12 LOW DB '?', TAB ; S11 HIGH DB KPDEC, '>', 'I', 'V' ; S11 LOW DB LFTA, ESC ; S10 HIGH DB KPCOM, '<', 'U', 'C' ; S10 LOW DB RGHTA, '!' ; S9 HIGH DB KP1, '|', 'Y', 'X' ; S9 LOW DB DWNA, '@' ; S8 HIGH DB KP2, 'O', 'T', 'Z' ; S8 LOW DB UPA, '#' ; S7 HIGH DB KP3, 'P', 'H', 'A' ; S7 LOW DB DEL, '$' ; S6 HIGH DB KP4, '"', 'J', 'S' ; S6 LOW DB CAPLCK, '%' ; S5 HIGH DB KP5, '~', 'K', 'D' ; S5 LOW DB SCROLL, '^' ; S4 HIGH DB KP6, '+', 'L', 'F' ; S4 LOW DB NULL, '&' ; S3 HIGH DB KP7, '_', 'M', 'R' ; S3 LOW DB HOMECLR,'*' ; S2 HIGH DB KP8, '{', 'N', 'E' ; S2 LOW DB HELP, '(' ; S1 HIGH DB KP9, '}', 'B', 'W' ; S1 LOW DB ERASE, ')' ; S0 HIGH DB KP0, ':', 'G', 'Q' ; S0 LOW END