TITLE "MORROW DESIGNS PIVOT - KEYBOARD PROCESSOR FIRMWARE" SBTTL "REVISION 8/8/85 1:00 PM 6.04" WIDTH 96 ;************************************************ ;* * ;* Morrow Designs Pivot * ;* Keyboard Processor Firmware * ;* * ;* Author: Michael Stolowitz * ;* Revision: 6.04 * ;* Date: 7/24/85 * ;* Time: 17:00 * ;* * ;************************************************ ; ; Revision History: ;============================================================================== ; Release 6.00 (14_Jul_85) ;========================= ; 6/14 ROM DISK - To read the disk, request an NMI ; with an ofset of 20H added to the sector ; number. Once the NMI has been returned, ; data bytes may be fetched from the MODE ; register. The address will auto-increment. ; This function may be aborted after any ; number of bytes have been transferred by ; acknowledging the NMI. ; ; ALT ICON FUNCTIONS - Added new NMI codes ; for ALT versions of Icon Keys. ; ; ROM REVISION - The value defined in the ; equate ROM.REV will be returned as the ; NMI status in the initial fetch which ; is used to enable NMIs. ; ; ARROW KEYS - Select shifted function on ; RS only. Release RS and/or NUM LOCK ; before sending scan code and remake ; after. On a key break, send the make ; code with the break bit set independent ; of the current state of RS. Do not ; interrupt RS or NUM LOCK on the break ; code. Also used for INSERT/DELETE. ; ; ARROW KEYS - Revised to send NUM LOCK ; make/break pulse before and after key ; code if required. ; ; BREAK NUM LOCK FOR + AND - ; ; Create two bytes of ram by chopping ; off the start of the FIFO. ; ; Extend MACROES by above two bytes. Adjust ; lengths of MACROES and FIFO everywhere. ; ; Write new key type MATH sharing parts ; of arrow to implement macroes. ; ; Add cursor NMI disable based on cursor style. ; No cursor on BP = 01, R10 > 7 or R10 > R11. ; ;============================================================================== ; Release 6.02 (7_Jul_85) ;======================== ; 7/5 SETEL routine added, which sets both bytes of ; the EL time out counter to the initial values. ; The initial values are dependent upon AC-ON. ; All places that used to set this counter now ; use this routine. ; ; Incorrect mask values in the cursor on - off ; routines were corrected. ; ; Changes were made in the SENDSCAN and SCANCODE ; routines to swallow the first typed character ; when the EL is off. ; ; The EL time out counters were changed to count ; in 1/2 minute incrememnts. ; ;============================================================================== ; Release 6.04 (8_Aug_85) ;======================== ; 7/17 Added register 27 to accept a keyboard ; state from the host processor. Revised ; internal state byte to correspond to bit ; structure of system keyboard state byte. ; ; 7/24 Added 1 frame time delay between macro characters. ; ; .HF 7/29 Keep BLINK bit active, even if blink is disabled. ; ; .DB 8/1 Changed RSTAT to feed back all 4 possible combinations ; of Display Enable and Sync. The pattern cycles every ; four reads. ; ; .DB 8/5 Added seperate power fail interrupt for LoBat1 if on ; AC. Changed keys (Row.Col) 6.6, 8.6, and 9.7 to be ; conditional on NumLock State. ; ; .DB 8/6 Added the SCROLL/NUM LOCK key to the macro handler. ; ; .JZ 8/7 Changed Rom.Rev from 2 to 3 ; ;************************************************ ;* * ;* Program Structure: * ;* * ;* COLD Code Executed On Reset * ;* MAIN Main Loop ( See MAIN: ) * ;* STALL Interrupt ( See STALL: ) * ;* TIMER Interrupt ( See TIMER: ) * ;* * ;************************************************ ; ;************************************************ ;* * ;* Other References: * ;* * ;* KBHRD.DOC Hardware Description * ;* KB.DOC Functional Description * ;* KBSCAN.DOC Keyboard Description * ;* * ;************************************************ ; ; BANK 0 REGISTER UTILIZATION ; ; KB RED DELTA CODE SEND ; -------------------------------------------------------------- ; R0 ; R1 KEY-ARRAY KEY-ARRAY KEY-ARRAY KEY-ARRAY ; R2 ROW CNT ROW CNT ROW CNT ROW-CNT ; R3 DELTA DELTA ; R4 ROTATE ROTATE ; R5 PWR-STAT PWR-STAT PWR-STAT PWR-STAT ; R6 BIT-CNT BIT-CNT ; R7 KEYSTATE KEYSTATE KEYSTATE KEYSTATE ; ; BANK 1 REGISTER UTILIZATION ; ; R0 WORKING INDEX REGISTER ; R1 6845 ADDRESS REGISTER ; R2 FIFO INPUT POINTER ; R3 FIFO OUTPUT POINTER ; R4 NMI STATUS ; R5 DISPLAY STATUS ; Bit 0 Display Enable ; Bit 1 FDC-OFF ; Bit 2 EL Timeout Inhibit ; Bit 3 Vertical Sync ; Bit 4 Drive Off 0 ; Bit 5 Drive Off 1 ; Bit 6 Attribute Enable Static ; Bit 7 Curser Updated ; R6 SAVED ACCUMULATOR ; R7 DISP CTL SHADOW ; ; F0 NO CURSOR UPDATE ; F1 NOT END-FRAME ; ; PORT 1 KEYBOARD SCAN CODES TO 8255 ; PORT 2 STROBE OUTPUT PORT ; ; ; PORT 2 BIT ASSIGNMENTS ; KBDAV.N: EQU 10000000B ;SET DAV LATCH PACK.P: EQU 01000000B ;PROCESSOR ACKNOWLEDGE NMIRQ.P: EQU 00100000B ;ASSERT PROCESSOR NMI ATENA.P: EQU 00010000B ;ATTRIBUTE ENABLE ; ; DATA BUS 8084 LOCAL BUS FACILITIES ; KB.STB EQU 00H ;Key Board Strobe PD.STB EQU 01H ;Processor Data Strobe FDC.STB EQU 02H ;Floppy Disk Enable DS.STB EQU 03H ;Display Strobe KB.ENA EQU 00H ;Key Board Enable PD.ENA EQU 01H ;Processor Data Enable AUX.ENA EQU 02H ;Extra Port Enable PA.ENA EQU 03H ;Processor Address Enable ; ; ROM.REV EQU 03H ;INITIAL NMI STATUS ; DSP.DFLT EQU 0C4H ;DEFAULT DISPLAY CONTROL ; ; RAM BASED DATA STRUCTURES ; ; CRT.REG : Array[0..17] Of 6845 Registers Absolute 20H ; CRT.REG: EQU 20H ;START OF 6845 REGISTERS ; ; Single Byte Variables: ; ELTIME0: EQU 32H ;EL PANEL TIMEOUT LSB ELTIME1: EQU 33H ;EL PANLE TIMEOUT MSB NMIREQ: EQU 34H ;NMI REQUEST PAGE: EQU 35H ;ROM DISK SECTOR REGISTER SAVE1: EQU 36H ;OP SYS ADDR SAVE SAVE2: EQU 37H ;NMI ADDR SAVE BLINK: EQU 38H ;BLINK COUNTER BOUNCE: EQU 39H ;DEBOUNCE VARIABLE REPEAT: EQU 3AH ;REPEAT REGISTER SWBRK: EQU 3BH ;BREAK TO SWALLOW ;---------------------------------------------------------- ; KARRAY : Array[Row1..Row12] of [NewData,OldData] ; KARRAY: EQU 3CH ;KB DATA ARRAY ;---------------------------------------------------------- ; MACROES : Array[1..8] Of MACRO ; MACRO : Record ; Control, ScanCode : Byte ; CONTROL { By Precidence } ; B6 Send NMLK Make ; B5 Send NMLK Break ; B1 Send RS Break ; B2 Send Data ; B0 Send RS Make ; B4 Send NMLK Make ; B3 Send NMLK Break ; NUMMACRO EQU 8 ;NUMBER OF MACROES MACROES EQU 54H ;FIRST MACRO ;---------------------------------------------------------- ; FIFO : Array[0..30] Of ScanCode Absolute 61H ; ; E1 is used so that overflow will set CRY ; FIFO: EQU 0E4H ;FIFO - 1CH BYTES TO END RAM ; ;BUF.LEN: EQU 1CH ;FIFO LENGTH ; ;CUR.REG EQU 0EH ;CURSOR REGISTER PAIR ;DISPLAY BLINK CONSTANTS K.BLINK: EQU 37 ;75/74 CYCLES PER SECOND BLINK.B: EQU 20H ;BLINK BIT OF DISP CTL ;DISPLAY EL PANEL TIMEOUT CONSTANTS EL.K0 EQU -60 ;60 BLINK PERIODS = 1/2 MIN EL.K10 EQU -20 ;10 MINUTES EL.K1 EQU -3 ;1.5 MINUTE EL.B EQU 04H ;EL ENABLE BIT OF DISP CTL ;DEBOUNCE CONSTANTS KBDB.S: EQU 2H ;SHORT - 2 FRAME TIMES KBDB.L: EQU 8H ;LONG - 8 FRAME TIMES ;NMI STATUS CODES LOBAT1$: EQU 2 ;LO BATT 1 CURSOR$: EQU 4 ;CURSOR UPDATED LOBAT2$: EQU 6 ;LO BATT 2 CHANGED IACALC$: EQU 8 ;ALT-CALC ICON ICLOCK$: EQU 10 ;CLOCK ICON IPHONE$: EQU 12 ;PHONE ICON IDISK$: EQU 14 ;DISK ICON ICALC$: EQU 16 ;CALC ICON ACCHG$: EQU 18 ;AC CHANGED ; IACLOCK$: EQU 22 ;ALT-CLOCK ICON IAPHONE$: EQU 24 ;ALT-PHONE ICON IADISK$: EQU 26 ;ALT-DISK ICON CUROFF$: EQU 28 ;CURSOR OFF BADAC$ EQU 30 ;LOBAT1 ON AC ROM.ORG: EQU 00H ;FOR SIMULATION ORG ROM.ORG ;RESET ADDRESS ; ; RESET - The 80C39 vectors here following a reset. ; RESET: JMP COLD ;RESET ENTRY NOP JMP STALL ;INT INTERRUPT NOP NOP JMP TIMER ;TIMER INTERRUPT ; ; COLD - Code executed one time at reset. ; COLD: ;STROBES OFF MOV A,#KBDAV.N ;ALL STROBES OFF OUTL P2,A ;TO STROBE PORT ;INITIALIZE DISPLAY SEL RB1 ;BANK 1 REGISTERS MOV A,#DSP.DFLT ;DEFAULT DISP CTL MOV R0,#DS.STB ;SET NDX TO DISP MOVX @R0,A ;AND SET THE PORT MOV R7,A ;COPY TO SHADOW REG ; SEL RB0 ;BANK 0 REGISTERS ; ; ; ;INITIALIZE KEYBOARD DATA ARRAY MOV R0,#KARRAY ;SET NDX TO ARRAY MOV R1,#24 ;LENGTH OF ARRAY CLR A ;KEYS OPEN COLD1: MOV @R0,A ;CLEAR BYTE INC R0 ;BUMP INDEX DJNZ R1,COLD1 ;DCR CNT UNTIL ZERO ;INITIALIZE BANK 0 REGISTERS MOV R0,A ;WORKING MOV R1,A ;KEY ARRAY POINTER MOV R2,A ;ROW CNT MOV R3,A ;DELTA DATA MOV R4,A ;ROTATED DATA MOV R5,A ;PWR-STATUS MOV R6,A ;BIT COUNT MOV R7,A ;KB STATE ;INITIALIZE BLINK MOV R0,#BLINK ;SET NDX TO CNTR MOV @R0,#K.BLINK ;AND LOAD INIT VALUE ;INITIALIZE EL PANEL TIMEOUT CALL SETEL ;INITIALIZE NMI REQUEST MOV R0,#NMIREQ ;SET NDX TO REGISTER MOV @R0,#0 ;AND CLEAR REQUEST ;INITIALIZE SWALLOW BREAK MOV R0,#SWBRK ;SET NDX TO REGISTER MOV @R0,#0 ;AND CLEAR ;INITIALIZE BANK 1 REGISTERS CALL KBINIT ;INITIALIZE THE KB (SELECTS BANK 1) ;INITIALIZE NMI STATUS MOV R4,#80H ;SET NMI STATUS ;OTHER BANK 1 REGISTERS CLR A ;ZERO MOV R1,A ;6845 ADDR REG MOV R5,A ;DISP STATUS MOV R6,A ;ACCUM SAVE ;SETUP THE FLAGS CPL F1 ;CLR END OF FRAME CPL F0 ;CLR CURSOR UPDATE ;SETUP THE EVENT COUNTER MOV A,#0FFH ;OVFL LESS ONE MOV T,A ;TO EVENT CNTR STRT CNT ;ENABLE CNTR ;ENABLE INTERRUPTS EN TCNTI ;ENABLE TIMER INT EN I ;ENABLE STALL INT ; ; THE MAIN LOOP ; ; WHILE NOT END OF FRAME ; 1. SEND OUT scan codes in FIFO ; 2. Process Drive Off ; 3. Poll power status port ; Process Lo Batt 1 if set ; Check for AC-ON rising ; 4. Poll NMI request register ; ; AT END OF FRAME: ; 1. Clear end of frame flag. ; 2. Send NMI if cursor updated ; 3. Update blink counter. On overflow: ; Update display blink if enabled ; Pulse attribute if mode enabled ; Update EL panel timeout if enabled ; Send Lo Batt 2 NMI if true and AC-OFF ; 4. Scan keyboard ; Skip if in debounce FRAME3 ; If FIFO is not full FRAME35 ; If MACRO is active ; Send Next Macro Code ; Else ; Read keyboard FRAME4 ; Process Changes ; 5. Auto Repeat ; ; MAIN: JF1 SENDOUT ;SKIP IF NOT END FRAME CPL F1 ;CLR END FRAME FLAG JMP FRAME1 ;EXECUTE END FRAME CODE ; ; SEND OUT - If the 8255 is not already busy, and if the FIFO ; is not empty, the next scan code in the buffer is sent to ; the 8255, the keyboard data available latch is set, and the ; output pointer is advanced. If the end of the FIFO is reached, ; the address is wraped forming a ring buffer. If either the ; FIFO is empty, or the 8255 is busy, this routine simply returns. ; ; Bank 1 Register Usage: ; R2 = FIFO Input Pointer ; R3 = FIFO Output Pointer - Updated ; Bank 0 Register Usage: ; R0 = Data is lost ; SENDOUT: JT0 DRVOFF ;IF 8255 BUSY SEL RB1 ;BANK 1 REGISTERS MOV A,R3 ;FETCH FIFO-OUT XRL A,R2 ;CMPR FIFO-IN JZ DRVOFF ;SKIP IF FIFO EMPTY MOV A,R3 ;FETCH IT AGAIN INC A ;AND BUMP IT JNZ SENDOUT1 ;SKIP IF NO OVFL MOV A,#FIFO ;WRAP THE FIFO SENDOUT1: MOV R3,A ;RESTORE THE PTR SEL RB0 ;BANK ZERO MOV R0,A ;TO NDX VIA A MOV A,@R0 ;READ BUF TO A OUTL P1,A ;AND THEN TO 8255 ANL P2,#NOT KBDAV.N ;ASSERT CPU INT1 ORL P2,#KBDAV.N ;NEGATE STROBES ; ; DRIVE OFF FUNCTION ; DRVOFF: SEL RB0 ;BANK 0 REGISTERS ;READ CURRENT STATE OF FDC MOV R0,#AUX.ENA ;SET NDX TO AUX PORT MOVX A,@R0 ;READ PORT TO A ANL A,#40H ;MASK TO FDC ON MOV R0,A ;HOLD IN R0 ;READ DRIVE AND FDC OFF FROM DISP-STAT, CLR IN STAT SEL RB1 ;BANK 1 REGISTERS DIS I ;BLOCK INTERRUPTS MOV A,R5 ;COPY DISPLAY STATUS ANL A,#0CDH ;CLR DRIVE OFF BITS XCH A,R5 ;SWAP WITH ORIGINAL EN I ;ENABLE INTERRUPTS SEL RB0 ;BANK 0 REGISTERS XRL A,#32H ;CMPL THE OFF BITS ;PROCESS FDC-OFF JB1 DRVOFF0 ;SKIP IF NOT FDC OFF MOV R0,#00H ;CLR FDC STATE DRVOFF0: MOVX @R0,A ;PULSE NEW FDC STATE ;PROCESS DRIVE OFF 0 XCH A,R0 ;SWAP FOR ADDR ADD A,#34H ;OFFSET TO ROW 13 XCH A,R0 ;SWAP BACK JB4 DRVOFF1 ;SKIP IF NOT DRV 0 MOVX @R0,A ;PULSE DRV OFF 0 ;PROCESS DRIVE OFF 1 DRVOFF1: XCH A,R0 ;SWAP WITH ADDR ADD A,#4 ;OFFSET TO ROW 14 XCH A,R0 ;SWAP BACK JB5 PWRFAIL ;SKIP IF NOT DRV 1 MOVX @R0,A ;PULSE DRV OFF 1 ; ; POWER FAIL - Test the extra port for Low Batt 1. ; If true, send an NMI 2 and once acknowledged, ; hang forever. Save the new power status. If AC-ON ; has just set, send an NMI 18. ; PWRFAIL: SEL RB0 ;BANK 0 REGISTERS MOV R0,#AUX.ENA ;SET NDX TO EXTRA PORT MOVX A,@R0 ;READ IN THE PORT JB2 PWRFAIL1 ;SKIP IF LOW BATT 1 XCH A,R5 ;NEW VALUES TO PWR STAT ;CHECK FOR AC-ON RISING JB0 NMIRQ ;SKIP IF AC WAS ON MOV A,R5 ;RECALL NEW STATE JB0 PWRFAIL3 ;AC-ON NOW SET JMP NMIRQ ;ELSE DONE ;LO BATT 1 PWRFAIL1: JB0 PWRFAIL2 ;IF ON AC, THEN LOAD AC BAD CODE MOV A,#LOBAT1$ ;LOAD BATTERY NMI CODE JMP PWRFAIL4 PWRFAIL2: MOV A,#BADAC$ ;LOAD AC NMI CODE PWRFAIL4: CALL NMI ;SET STATUS AND PULSE NMI DIS I ;DISABLE EXT INTERRUPT DIS TCNTI ;DISABLE CNTR INTERRUPT MOV A,#0 MOV R0,#00H ;CLR FDC STATE MOVX @R0,A ;PULSE NEW FDC STATE MOV R0,#DS.STB ;SET NDX TO DISP CTL MOV A,#(EL.B OR 90H) ;A = ELEN,40 COL & CURE OFF MOVX @R0,A ;AND THE DISP CTL PORT DB 1H ;IDLE OP-CODE HANG FOREVER ;AC-ON RISING PWRFAIL3: MOV A,#ACCHG$ ;NMI CODE OF AC-ON CALL NMI ;NMI TO CPU ; ; NMI REQUEST - Test the NMIREQ variable. If it is ; non-zero, send the content to the NMI routine and ; clear the variable. ; NMIRQ: SEL RB0 ;BANK 0 REGISTERS MOV R0,#NMIREQ ;SET NDX TO NMI REQ MOV A,@R0 ;AND READ THE VARIABLE JNZ NMIRQ1 ;SKIP IF CODE PRESENT JMP MAIN ;OTHERWISE DONE NMIRQ1: MOV @R0,#00H ;CLEAR THE VARIABLE CALL NMI ;SET THE CODE SEL RB0 ;RESTORE BANK JMP MAIN ;AND DONE ; ; ; TIMER INTERRUPT - A sync pulse has been received from ; the LCD display causing the event counter to overflow ; and generate an interrupt. Reset the counter to -1 ; and re-arm the timer interrupt. Clear F1 to indicate ; that end of frame has been reached. ; ; F1 Cleared ; TIMER: ;TIMER INT CLR F1 ;ENABLE END OF FRAME SEL RB1 ;FOR CORRECT R6 MOV R6,A ;SAVE A IN R6 MOV A,#0FFH ;ONE SHORT OF OVFL MOV T,A ;TO RE-ARM THE TIMER MOV A,R6 ;RESTORE A RETR ;AND DONE ; ; AUTO REPEAT - SENDSCAN clears REPEAT. This ; routine will increment repeat. Once bit 7 ; is set, it latches 6 & 7. Based on the MSBs: ; 00 Delay - No Output ; 01 Repeat - 5 cps ; 10 Repeat - 10 cps ; 11 Repeat - 15 cps ; The output rate is controlled by the LSBs: ; 0000 5 cps ; d000 10 cps ; dd00 20 cps ; The character at FIFO-IN is sent unless ; it is a break code. ; FRAME4: SEL RB0 ;BANK 0 REGISTERS MOV R0,#REPEAT ;SET NDX TO CNTR MOV A,@R0 ;AND FETCH IT JB7 RPT2 ;SPEED 2 OR 3 JB6 RPT1 ;SPEED 1 INC A ;DELAYING MOV @R0,A ;RESTORE JMP MAIN ;DONE FOR NOW ;SPEED 1 RPT1: MOV R6,#07H ;FOR 10 CPS JMP RPT4 ; RPT2: JB6 RPT3 ;IF SPEED 3 ;SPEED 2 MOV R6,#03H ;FOR 20 CPS JMP RPT4 ; ;SPEED 3 RPT3: MOV R6,#01H ;FOR 40 CPS INC A ;BUMP ORL A,#0F0H ;LATCH HI BITS JMP RPT5 ;CONT RPT4: INC A ;BUMP RPT5: MOV @R0,A ;RESTORE ANL A,R6 ;MASK LSBS JNZ RPT6 ;NOT TIME YET SEL RB1 ;TO FIFO BANK MOV A,R2 ;FETCH FIFO-OUT SEL RB0 ;RESTORE BANK MOV R0,A ;ADDR TO NDX MOV A,@R0 ;LAST SCAN CODE JB7 RPT6 ;EXIT IF BREAK CALL SENDSCAN ;DATA TO FIFO RPT6: JMP MAIN ;AND DONE PAGE ; ; START OF SECOND PAGE ; ORG ROM.ORG+100H ; ; STALL INTERRUPT - This interrupt is invoked whenever the ; CPU accesses an I/O port in the range reserved for the ; IBM Color / Graphics adapter. The hardware features of ; these boards which will be emulated by this code inlcude ; the 6845, the MODE register, and the STATUS register. ; Accesses of the SELECT register and the light pen latch ; will be ignored. The interrupt response time must be ; minimized as the CPU is held in a wait state inhibiting ; refresh cycles until it is released. The interrupt ; response time for a port write operation is 18 cycles. ; ; ; THE PORT TABLE: ; The least significant four bits of the CPU address ; and the state of the IORS (I/O Read Status) line are ; read through a port and a 32 entry table is then used ; to call potentially unique routines for reading or ; writing any of the sixteen port addresses associated ; with the color graphics boars. ; ; Processor Address Port: A2 /IOR A3 A1 A0 ; ; The table will dispatch the code to: ; EXIT Illegal or Ignored Access ; WCRTADDR Write 6845 address register ; RCRTDATA Read 6845 data register ; WCRTDATA Write 6845 data register ; WMODE Write MODE register ; RSTAT Read STATUS register ; PORT.TBL: DB EXIT ;R0 READ 6845 ADDR DB RCRTDATA ;R1 READ 6845 DATA DB EXIT ;R2 READ 6845 ADDR DB RCRTDATA ;R3 READ 6845 DATA DB RCRTADDR ;R4 READ 6845 ADDR DB RCRTDATA ;R5 READ 6845 DATA DB EXIT ;R6 READ 6845 ADDR DB RCRTDATA ;R7 READ 6845 DATA DB RMODE ;R8 READ MODE REG DB EXIT ;R9 READ SELECT DB RSTAT ;RA READ STATUS DB EXIT ;RB LIGHT PEN CLEAR DB EXIT ;RC READ MODE REG DB EXIT ;RD READ SELECT DB EXIT ;RE READ STATUS DB EXIT ;RF LIGHT PEN CLEAR DB WCRTADDR ;W0 WRITE 6845 ADDR DB WCRTDATA ;W1 WRITE 6845 DATA DB WCRTADDR ;W2 WRITE 6845 ADDR DB WCRTDATA ;W3 WRITE 6845 DATA DB WCRTADDR ;W4 WRITE 6845 ADDR DB WCRTDATA ;W5 WRITE 6845 DATA DB WCRTADDR ;W6 WRITE 6845 ADDR DB WCRTDATA ;W7 WRITE 6845 DATA DB WMODE ;W8 WRITE MODE REG DB EXIT ;W9 WRITE COLOR SELECT DB EXIT ;WA WRITE STATUS DB EXIT ;WB LIGHT PEN CLEAR DB EXIT ;WC LIGHT PEN SET DB EXIT ;WD NOT USED DB EXIT ;WE NOT USED DB EXIT ;WF NOT USED ; ; 6845 ADDRESS TABLE: ; The 6845 requires only two addresses in its ; interface while its internal structure proivides ; eighteen bytes of registers. The first accessable ; address is a pointer register used to select which ; of the internal registers is to be accessable through ; the second. This table is used to dispatch on the ; data which the CPU is attempting to write to the ; 6845's address register. ; ; A number of hardware features unique to the PIVOT have ; been concealed in registers added to the emulated 6845. ; Since these features may be accessed by the operating ; system or within an NMI, and the accesses requires a ; pair of cycles (one to set the address register and ; one to access the data register), mechanisms are ; provided for preserving address pointers of lower ; levels as higher levels are accessed. ; ; This table will dispatch to: ; WADDR Load Addres ; EXIT Ignore Address - Illegal ; NMIADR Push to SAVE2 - Load ; TRANADR Push to SAVE1 - Load ; ADDR.TBL: DB WADDR ;A0 DB WADDR ;A1 DB WADDR ;A2 DB WADDR ;A3 DB WADDR ;A4 DB WADDR ;A5 DB WADDR ;A6 DB WADDR ;A7 DB WADDR ;A8 DB WADDR ;A9 DB WADDR ;A10 DB WADDR ;A11 DB WADDR ;A12 DB WADDR ;A13 DB WADDR ;A14 DB WADDR ;A15 DB WADDR ;A16 DB WADDR ;A17 DB NMIADR ;A18 DB EXIT ;A19 DB TRANADR ;A20 DB TRANADR ;A21 DB TRANADR ;A22 DB TRANADR ;A23 DB TRANADR ;A24 DB TRANADR ;A25 DB TRANADR ;A26 DB TRANADR ;A27 DB EXIT ;A28 DB EXIT ;A29 DB EXIT ;A30 DB EXIT ;A31 ; ; 6845 DATA REGISTER TABLE: ; The routines which this table passed execution to ; will normally read or write the 6845 register ; indicated by the current value in the address ; register. ; ; There are two types of accesses permitted to the ; added registers. Operating system accesses of ; registers 19-21 make transient use of the address ; register in that its value prior to selection of ; one of these registers is restored (from SAVE1) ; following the next data register access. Setting ; the address register to R18 indicates the start ; of an NMI routine causing the current state of ; the address register to be saved in SAVE2. Any ; write to R18 will clear the NMI state and restore ; the address register from SAVE2. Within an NMI, ; any number of other address or data accesses may ; be made. ; ; This table will dispatch to: ; RD.REG Read Register ; EXIT Return FFh - Illegal ; RD.18 Return NMI status code ; RD.20 Display Control Shadow ; RD.21 Return Extra, Pop SAVE1* ; ; * SAVE1 is popped only if NMI is off ; RD.TBL DB RD.REG ;R0 DB RD.REG ;R1 DB RD.REG ;R2 DB RD.REG ;R3 DB RD.REG ;R4 DB RD.REG ;R5 DB RD.REG ;R6 DB RD.REG ;R7 DB RD.REG ;R8 DB RD.REG ;R9 DB RD.REG ;R10 DB RD.REG ;R11 DB RD.REG ;R12 DB RD.REG ;R13 DB RD.REG ;R14 DB RD.REG ;R15 DB RD.REG ;R16 DB RD.REG ;R17 DB RD.18 ;R18 DB EXIT ;R19 DB RD.20 ;R20 DB RD.21 ;R21 DB EXIT ;R22 DB EXIT ;R23 DB EXIT ;R24 DB EXIT ;R25 DB EXIT ;R26 DB EXIT ;R27 DB EXIT ;R28 DB EXIT ;R29 DB EXIT ;R30 DB EXIT ;R31 STALL: SEL RB1 ;BANK 1 REGISTERS MOV R6,A ;SAVE A IN R6 MOV R0,#PA.ENA ;PROC ADDR TO NDX MOVX A,@R0 ;ADDR TO A ANL A,#1FH ;MASK TO 5 BITS ; ADD A,#PORT.TBL AND 0FFH ;TABLE ADDR IS ZERO JMPP @A ;JUMP THROUGH TABLE EXIT: ORL P2,#PACK.P ;RELEASE HOST PROC ANL P2,#NOT PACK.P ;NEGATE STROBE EXIT1: CALL SETEL ;INITIALIZE EL TIME OUT COUNTER MOV A,R6 ;RESTORE A RETR ;AND RETURN WDATA: MOV R0,#PD.ENA ;DATA ADDR TO NDX MOVX A,@R0 ;DATA TO ACC ORL P2,#PACK.P ;RELEASE HOST PROC ANL P2,#NOT PACK.P ;NEGATE STROBE RET WMODE: CALL WDATA ;ACCEPT THE DATA ADD A,#20H ;BLINK ENA TO B6 MOV R0,A ;COPY TO R0 XRL A,#01H ;CMPL BIT 0 JB1 WMODE1 ;SKIP IF GRAPHIC JB0 WMODE2 ;SKIP IF 40X25 ALPHA CLR A ;80X25 ALPHA JMP WMODE3 ;CLR HI-RES WMODE1: JB4 WMODE2 ;SKIP IF 640X200 CLR A ;320X200 GRAPHIC JMP WMODE3 ;CLR HI-RES WMODE2: MOV A,#10H ;SET HI-RES WMODE3: XCH A,R0 ;SWAP WITH MODE ANL A,#01000010B ;KEEP BITS 1 & 6 ORL A,R0 ;ADD HI-RES, BIT 4 MOV R0,A ;HOLD IN R0 MOV A,R7 ;FETCH SHADOW ANL A,#10101101B ;KEEP THE REST ORL A,R0 ;MERGE NEW BITS MOV R7,A ;UPDATE SHADOW MOV R0,#DS.STB ;SET NDX TO DISP MOVX @R0,A ;UPDATE DISP CTL REG JMP EXIT1 ;AND EXIT RMODE: MOV A,R4 ;FETCH NMI STATUS JB7 RMODE1 ;SKIP IF NMI ACTIVE JMP EXIT ;NOT ALLOWED RMODE1: JMP ROM.DSK ;FETCH A BYTE RSTAT: MOV A,R5 ;STATUS REG TO A JB3 RSTAT1 ;IF BIT 3 NOT SET THEN... XRL A,#08H ; THEN SET IT JMP RSTAT2 ; AND RESTORE STATUS REGISTER RSTAT1: XRL A,#09H ;TGL SYNC & ENABLE RSTAT2: MOV R5,A ;RESTORE STATUS ANL A,#09H ;MASK TO ENA & SYNC CALL RDATA ;REL CPU WITH DATA JMP EXIT1 ;AND EXIT RDATA: MOV R0,#PD.STB ;SET NDX TO CPU DATA MOVX @R0,A ;AND OUTPUT THE DATA ORL P2,#PACK.P ;RELEASE HOST PROC ANL P2,#NOT PACK.P ;NEGATE STROBE RET WCRTADDR: CALL WDATA ;FETCH THE CPU DATA ANL A,#1FH ;MASK TO FIVE BITS MOV R0,A ;HOLD COPY IN R0 ADD A,#ADDR.TBL AND 0FFH ;OFST TO TABLE BASE JMPP @A ;JMP INDIRECT WADDR: MOV A,R0 ;MOVE VIA A MOV R1,A ;TO R1 JMP EXIT1 ;AND EXIT NMIADR: MOV A,R4 ;FETCH NMI STATUS JB7 WADDR ;SKIP IF NMI SET JMP NMIADR1 ;SKIP NEXT PAGE TRANADR: MOV A,R4 ;FETCH NMI STATUS JB7 WADDR ;SKIP IF NMI SET MOV A,R0 ;RECALL NEW ADDR XCH A,R1 ;SWAP OLD WITH NEW MOV R0,#SAVE1 ;SET NDX TO SAVE1 TRANADR1: MOV @R0,A ;PUSH OLD R1 MOV A,R6 ;RESORE A RETR ;AND DONE RCRTADDR: JMP RADDR ;SKIP TO NEXT PAGE WCRTDATA: JMP WCRTDAT1 ;CHANGE PAGES RCRTDATA: MOV A,R1 ;FETCH THE ADDR ADD A,#RD.TBL AND 0FFH ;READ DATA TABLE JMPP @A ;INDIRECT THRU TABLE RD.REG: MOV A,R1 ;FETCH REG NUMBER ADD A,#CRT.REG ;ADD RAM OFST MOV R0,A ;COPY TO NDX MOV A,@R0 ;AND READ DATA CALL RDATA ;SEND DATA AND REL CPU MOV A,R4 ;FETCH NMI STATUS JB7 RD.REG1 ;SKIP IF ACTIVE JMP EXIT1 ;ELSE DONE RD.REG1: INC R1 ;BUMP ADDR REG JMP EXIT1 ;AND END INTERRUPT RD.18: MOV A,R4 ;FETCH NMI STATUS ANL A,#7FH ;MASK ACTIVE FLAG CALL RDATA ;RETURN DATA MOV A,R6 ;RESTORE A RETR ;AND DONE RD.20: MOV A,R7 ;COPY SHADOW TO A CALL RDATA ;RETURN DATA MOV A,R6 ;RESTORE A RETR ;AND DONE RD.21: MOV R0,#AUX.ENA ;SET NDX TO AUX PORT MOVX A,@R0 ;AND READ PORT CALL RDATA ;DATA TO CPU MOV A,R6 ;RESTORE A RETR ;AND DONE PAGE ; ; START OF THIRD PAGE OF ROM ; ORG ROM.ORG+200H ; ; 6845 DATA REGISTER TABLE: ; The routines which this table passed execution to ; will normally read or write the 6845 register ; indicated by the current value in the address ; register. ; ; There are two types of accesses permitted to the ; added registers. Operating system accesses of ; registers 19-21 make transient use of the address ; register in that its value prior to selection of ; one of these registers is restored (from SAVE1) ; following the next data register access. Setting ; the address register to R18 indicates the start ; of an NMI routine causing the current state of ; the address register to be saved in SAVE2. Any ; write to R18 will clear the NMI state and restore ; the address register from SAVE2. Within an NMI, ; any number of other address or data accesses may ; be made. ; ; This table will dispatch to: ; WR.REG Write Register ; WEXIT Return FFh - Illegal ; WR.18 End NMI, Pop SAVE2 ; ; WR.20 Write Display, Pop SAVE1* ; WR.21 Write FDC ON, Pop SAVE1* ; WR.22 Set NMI request, Pop SAVE1* ; WR.23 Set EL Timer Disable, Pop SAVE1* ; WR.24 Set Attribute State, Pop SAVE1* ; WR.25 Drive Power Off, Pop SAVE1* ; WR.26 Keyboard Reset ; WR.27 Keyboard State ; ; * SAVE1 is popped only if NMI is off ; WR.TBL DB WR.REG ;W0 DB WR.REG ;W1 DB WR.REG ;W2 DB WR.REG ;W3 DB WR.REG ;W4 DB WR.REG ;W5 DB WR.REG ;W6 DB WR.REG ;W7 DB WR.REG ;W8 DB WR.REG ;W9 DB WR.STYL ;W10 DB WR.STYL ;W11 DB WR.REG ;W12 DB WR.REG ;W13 DB WR.CUR ;W14 DB WR.CUR ;W15 DB WR.REG ;W16 DB WR.REG ;W17 DB WR.18 ;W18 DB WEXIT ;W19 DB WR.20 ;W20 DB WR.21 ;W21 DB WR.22 ;W22 DB WR.23 ;W23 DB WR.24 ;W24 DB WR.25 ;W25 DB WR.26 ;W26 DB WR.27 ;W27 DB WEXIT ;W28 DB WEXIT ;W29 DB WEXIT ;W30 DB WEXIT ;W31 WEXIT: ORL P2,#PACK.P ;RELEASE HOST PROC ANL P2,#NOT PACK.P ;NEGATE STROBE WEXIT1: CALL SETEL ;INITIALIZE EL TIME OUT COUNTER MOV A,R6 ;RESTORE A RETR ;AND RETURN WCRTDAT1: MOV R0,#PD.ENA ;DATA ADDR TO NDX MOVX A,@R0 ;DATA TO ACC ORL P2,#PACK.P ;RELEASE HOST PROC ANL P2,#NOT PACK.P ;NEGATE STROBE MOV R0,A ;HOLD IN R0 MOV A,R1 ;FETCH THE ADDR ; ADD A,#WR.TBL AND 0FFH ;WRITE DATA TABLE JMPP @A ;INDIRECT THRU TABLE WR.STYL: MOV A,R0 ;FETCH DATA ORL A,#80H ;SET UPDATE FLAG MOV R0,A ;REPLACE IN R0 JMP WR.REG ;AND USE WRITE REG WR.CUR: MOV A,R5 ;FETCH DISPLAY STATUS ORL A,#80H ;TURN ON CURSOR UPDATE MOV R5,A ;RESTORE DISP STAT WR.REG: MOV A,R1 ;FETCH REG NUMBER ADD A,#CRT.REG ;ADD BASE ADDR XCH A,R0 ;SWAP ADDR & DATA MOV @R0,A ;STORE DATA TO ADDR JMP WEXIT1 ;AND EXIT ;WRITE NMI STATUS REGISTER WR.18: MOV R4,#0 ;CLR NMI STATUS MOV R0,#SAVE2 ;SET NDX TO SAVE2 MOV A,@R0 ;AND RESTORE MOV R1,A ;VIA A MOV A,R6 ;RESTORE A RETR ;AND DONE ;WRITE DISPLAY CONTROL PORT WR.20: MOV A,#10001001B ;NEW BIT MASK ANL A,R0 ;ON NEW DATA XRL A,#80H ;TOGGLE CUR ENA MOV R0,A ;BACK ON HOLD MOV A,#01110110B ;OLD BIT MASK ANL A,R7 ;ON OLD DATA ORL A,R0 ;MERGE BITS MOV R7,A ;UPDATE SHADOW MOV R0,#DS.STB ;SET NDX TO DISP MOVX @R0,A ;AND UPDATE DISP JMP WR.EXIT ;TRANSIENT EXIT ;WRITE FDC-ON WR.21: MOV A,R0 ;RECALL NEW DATA JB6 WR.EXIT ;SKIP IF FDC-ON MOV A,#02H ;FDC OFF BIT ORL A,R5 ;MERGE DISP STAT MOV R5,A ;RESTORE STAT JMP WR.EXIT ;TRANSIENT EXIT ;WRITE NMI REQUEST WR.22: MOV A,R0 ;RECALL NEW DATA MOV R0,#NMIREQ ;SET NDX TO NMI REQ MOV @R0,A ;AND STORE DATA JMP WR.EXIT ;TRANSIENT EXIT ;WRITE DISPLAY TIMEOUT WR.23: MOV A,R5 ;FETCH DISP STAT ANL A,#0FBH ;MASK KEEPERS MOV R5,A ;BACK ON HOLD MOV A,R0 ;FETCH NEW DATA ANL A,#04H ;BIT 2 ONLY ORL A,R5 ;MERGE KEEPERS MOV R5,A ;AND RESTORE JB2 WR.231 ;SKIP IF TIME INH JMP WR.EXIT ;OTHERWISE EXIT WR.231: MOV A,R7 ;FETCH SHADOW ANL A,#0FBH ;MASK OUT EL PANEL XCH A,R0 ;SWAP WITH NEW DATA RL A ;SHIFT UP BIT 1 ANL A,#04H ;MASK TO BIT 2 ORL A,R0 ;MERGE OLD DATA MOV R7,A ;AND RESTORE SHADOW JMP WR.EXIT ;AND DONE ;WRITE DISPLAY CONTROL PORT WR.24: JB0 WR1.24 ;STATE TO HIGH ANL P2,#NOT ATENA.P ;CLEAR ATENA JMP WR2.24 ;AND CONT WR1.24: ORL P2,#ATENA.P ;SET ATENA WR2.24: MOV A,#01000000B ;MASK TO PULSE MODE ANL A,R0 ;INHIBIT ON NEW DATA MOV R0,A ;HOLD IN R0 MOV A,R5 ;FETCH DISP STATUS ANL A,#10111111B ;OLD BIT MASK ORL A,R0 ;MERGE WITH NEW MOV R5,A ;AND RESTORE STATUS JMP WR.EXIT ;TRANSIENT EXIT ;WRITE DRIVE OFF BITS OF DISPLAY STATUS REGISTER WR.25: MOV A,R0 ;FETCH NEW DATA ANL A,#32H ;MASK DRV OFF BITS MOV R0,A ;HOLD IN R0 MOV A,R5 ;FETCH DISP STATUS ANL A,#0CDH ;MASK OLD BITS ORL A,R0 ;MERGE NEW BITS MOV R5,A ;RESTORE STATUS JMP WR.EXIT ;TRANSIENT EXIT ;SOFTWARE RESET OF KEYBOARD WR.26: CALL KBINIT ;RESET KEYBOARD JMP WR.EXIT ;TRANSIENT EXIT ;WRITE KEYBOARD STATE WR.27: MOV A,R0 ;FETCH NEW DATA ANL A,#2FH ;MASK TO SIG BITS SEL RB0 ;TO REG BANK 0 MOV R7,A ;AND SET STATE SEL RB1 ;BANK IN BANK 1 JMP WR.EXIT ;TRANSIENT EXIT ;NMIADR from last page NMIADR1: ORL A,#80H ;IF NOT, SET IT MOV R4,A ;RESTORE NMI STATUS ANL P2,#NOT NMIRQ.P ;NEGATE THE NMI REQ MOV A,R0 ;RECALL NEW ADDR XCH A,R1 ;SWAP WITH OLD MOV R0,#SAVE2 ;SET NDX TO SAVE2 MOV @R0,A ;PUSH OLD R1 MOV A,R6 ;RESTORE A RETR ;AND DONE ;RCRTADDR from previous page. RADDR: MOV A,R4 ;FETCH NMI STATUS JB7 ENDNMI ;SKIP IF NMI ACTIVE JNZ RADDR1 ;IF (NO NMI REQUEST) MOV A,#0 CALL RDATA ; ACKNOWLEDGE JMP WR.EXIT1 ; RETURN RADDR1: ANL P2,#NOT NMIRQ.P ;NEGATE THE NMI REQUEST CALL RDATA ;RETURN VALUE TO HOST ORL A,#80H ;ASSERT ACTIVE MOV R4,A ;TO STATUS REGISTER MOV R0,#SAVE2 ;SET NDX TO SAVE2 MOV A,R1 ;PUSH R1 TO MOV @R0,A ;SAVE2 VIA A MOV A,R4 ;RECALL NMI CODE JB5 RADDR2 ;SKIP IF ROM DISK XRL A,#CURSOR$+80H ;CURSOR UPDATE ? JNZ WR.EXIT1 ;QUIT IF NOT MOV R1,#0EH ;SET ADDR TO CUR REG MOV A,R7 ;FETCH DISP SHADOW ANL A,#7FH ;ENABLE CURSOR RAM MOV R0,#DS.STB ;SET NDX TO DISP CTL MOVX @R0,A ;AND WRITE DISP REG JMP WR.EXIT1 ;DONE FOR NOW ; RADDR2: JMP ROM.DSK2 ;ACCESS THE DISK ; ENDNMI: MOV A,R7 ;FETCH DISP SHADOW ORL A,#80H ;DISABLE CURSOR RAM MOV R0,#DS.STB ;SET NDX TO DISP CTL MOVX @R0,A ;AND WRITE DISP REG MOV A,#ROM.REV ;A:= CURRENT ROM REVISION CALL RDATA ;VALUE TO HOST CLR A ;CLEAR ACC MOV R4,A ;AND TO NMI STATUS MOV R0,#SAVE2 ;SET NDX TO SAVE2 MOV A,@R0 ;AND POP SAVED MOV R1,A ;VALUE OF R1 VIA A JMP WR.EXIT1 ;AND DONE ;TRANSIENT EXIT WR.EXIT: MOV A,R4 ;FETCH NMI STATUS JB7 WR.EXIT1 ;SKIP IF NMI SET MOV R0,#SAVE1 ;SET NDX TO SAVE1 MOV A,@R0 ;AND RESTORE R1 MOV R1,A ;VIA A ;NORMAL EXIT WR.EXIT1: MOV A,R6 ;RESTORE A RETR ;AND DONE PAGE ; ; START OF FOURTH PAGE OF ROM ; ; ; LOOKUP SCAN CODE - A scan code is looked up for each ; bit set in the accumulator assuming that R1 indicates ; the matrix row from which the data was obtained. If ; bit 7 is set in the located code, an NMI is generated ; using the balance of the code as a status. Otherwise, ; 80H is added to the locaed code if F0 was set and the ; result is placed in the FIFO. ; ; Bank 0 Register Usage: ; A = Image of Changed Keys ; R2 = 13 - Matrix Row Number ; F0 = Generate Break Codes ; ; A = Scan Code or NMI Status ; R4 = Save Rotated Delta ; R6 = Save Bit Counter ; R7 = Current Keyboard State ; ORG ROM.ORG+300H ;TABLE AT X00 ; BIT 0 1 2 3 4 5 6 7 SCANTBL: DB 3BH,3DH,3FH,42H,44H,X09,X08,00H ;ROW12 DB 3CH,3EH,40H,41H,43H,X0A,X07,00H ;ROW11 DB 0EH,X1C,X05,X12,X0F,X0C,X13,X14 ;ROW10 DB X06,1CH,X0D,X11,X0E,X0B,X10,X1E ;ROW9 DB 1AH,00H,X15,07H,15H,23H,X1F,31H ;ROW8 DB X03,2BH,X16,06H,14H,22H,X17,30H ;ROW7 DB 0FH,X19,0CH,04H,12H,20H,X20,2EH ;ROW6 DB X04,1BH,X1B,03H,11H,1FH,X18,2DH ;ROW5 DB 3AH,X00,00H,05H,13H,21H,39H,2FH ;ROW4 DB 01H,00H,X01,02H,10H,1EH,X1A,2CH ;ROW3 DB 00H,00H,00H,00H,00H,00H,00H,X02 ;ROW2 DB 00H,00H,00H,00H,00H,00H,00H,X1D ;ROW1 SCANCODE: MOV R6,#8 ;INITIATE CNT SC1: RLC A ;NEXT BIT TO CRY JNC SC8 ;SKIP IF NOT SET MOV R4,A ;SAVE ROTATED DELTA MOV A,R2 ;GET ROW INDEX DEC A ;ADJUST TO 11-0 RL A ;AND SHIFT UP - 1 RL A ; - 2 RL A ; - 3 ADD A,R6 ;MERGE THE BIT NUMBER DEC A ;DECR FOR 8-1 TO 7-0 MOVP A,@A ;AND FETCH THE CODE JB7 SC.CONV ;SKIP IF EXEC CODE JF0 SC.BRK ;SKIP IF BREAK CALL SENDSCAN ;DATA TO FIFO SC5: MOV R0,#BOUNCE ;SET NDX TO BOUNCE MOV A,R2 ;GET ROW NUMBER ADD A,#-3 ;LOOP CNT > 2 ? JNC SC6 ;YES, USE SHORT DLY MOV @R0,#KBDB.S ;LOAD SHORT DELAY JMP SC7 ;AND CONT SC6: MOV @R0,#KBDB.L ;LOAD LONG DELAY SC7: MOV A,R4 ;RESTORE ROTATED DATA SC8: DJNZ R6,SC1 ;REPEAT FOR 8 BITS CALL SETEL ;INITIALIZE EL TIME OUT COUNTER MOV R0,#REPEAT ;SET NDX TO RERPEAT MOV @R0,#0 ;AND RESET IT RET ;AND DONE SC.CONV: CALL CONVERT ;SKIP TO NEXT PAGE JF0 SC7 ;NO DEBOUNCE ON BREAK JMP SC5 ;SET DEBOUNCE SC.BRK: ORL A,#80H ;ADD BREAK BIT MOV R0,#SWBRK ;SET NDX TO SWALLOW BREAK XCH A,@R0 ;SWAP DATA JZ SC9 ;JUMP IF NO BREAK TO SWALLOW XRL A,@R0 ;SEE IF THE SAME JZ SC10 ;JUMP IF MATCH XRL A,@R0 ;RESTORE DATA SC9: XCH A,@R0 ;SWAP BACK CALL SENDSCAN ;DATA TO FIFO JMP SC7 ;NO DEBOUNCE SC10: MOV @R0,A ;CLEAR SWBRK JMP SC7 ;CONTINUE ; ; SEND SCAN - This routine will return the address of ; the next available FIFO-IN location. If the FIFO is ; full, this location will be the same as the previous ; location and the pointer will not be incremented. ; ; Called By SCANCODE and REPEAT, Returns in RB0 ; ; Bank 1 Register Usage: ; R2 = FIFO Input Pointer - Updated ; R3 = FIFO Output Pointer ; Bank 0 Register Usage: ; SENDSCAN: MOV R0,A ;HOLD IN R0 SEL RB1 ;BANK 1 REGISTERS MOV A,R7 ;GET DISP CTL SHADOW JB2 SNDSCAN0 ;SKIP IF EL ON DIS I ;LOCK OUT INTERRUPTS ORL A,#EL.B ;SET EL ON BIT MOV R7,A ;UPDATE SHADOW MOV R0,#DS.STB ;SET NDX TO DISP CTL MOVX @R0,A ;AND UPDATE PORT EN I ;UNLOCK INTERRUPTS SEL RB0 ;BANK 0 REGISTERS MOV A,R0 ;GET SCAN CODE ORL A,#80H ;MAKE BREAK CODE MOV R0,#SWBRK ;SET NDX TO MEM MOV @R0,A ;SAVE BREAK CODE RET SNDSCAN0: MOV A,R2 ;FETCH FIFO-IN INC A ;BUMP PTR JNZ SNDSCAN1 ;SKIP IF NOT OVFL MOV A,#FIFO ;WRAP THE FIFO SNDSCAN1: XRL A,R3 ;CMP FIFO-OUT JZ SNDSCAN2 ;SKIP IF BUF FULL XRL A,R3 ;RESTORE ADDR MOV R2,A ;UPDATE FIFO-IN SEL RB0 ;RESTORE BANK XCH A,R0 ;SWAP ADDR & DATA MOV @R0,A ;SEND DATA TO FIFO RET ;AND DONE SNDSCAN2: MOV A,R2 ;FETCH OLD VALUE SEL RB0 ;RESTORE BANK XCH A,R0 ;SWAP ADDR & DATA MOV @R0,A ;SEND DATA TO FIFO RET ; ; NMI - If NMI is not already set, the status code from ; A is place in the NMI status register and the CPU's ; NMI request line is set. The routine then waits for ; the status register to be cleared through the STALL ; interrupt routine and then exits with A clear. If ; NMI is already active on entry, exit the routine ; immediately with the new code in A. ; ; A = NMI Status Code ; NMI: SEL RB1 ;IN REGISTER BANK 0 XCH A,R4 ;SWAP NEW & OLD JB7 NMI2 ;IF ALREADY NMI ON ORL P2,#NMIRQ.P ;ASSERT NMI REQUEST NMI1: MOV A,R4 ;FETCH NMI STATUS JNZ NMI1 ;LOOP UNTIL CLEARED RET NMI2: XCH A,R4 ;RESTORE OLD CODE RET ; ; KB INIT - Initialize the keyboard ; KBINIT: SEL RB0 ;BANK 0 REGISTERS MOV R7,#0 ;CLEAR KB STATE SEL RB1 ;BANK 1 REGISTERS ;Clear all outstanding macroes CLR A ;CLEAR ACCUM MOV R2,#NUMMACRO*2 ;LENGTH IN BYTE MOV R0,#MACROES ;START OF STRUCTURE KBINIT1: MOV @R0,A ; CLEAR A BYTE INC R0 ; BUMP ADDR DJNZ R2,KBINIT1 ; FOR COUNT ; MOV R2,#FIFO ;CLR FIFO-IN MOV R3,#FIFO ;CLR FIFO-OUT MOV R0,#FIFO ;SET NDX TO FIFO-OUT MOV @R0,#80H ;STUFF A BREAK CODE RET ;THAT'S IT ; ; SETEL - Check the status of AC-ON and initialize the ; EL time out counter. ; SETEL: MOV R0,#AUX.ENA ;SET NDX TO EXTRA PORT MOVX A,@R0 ;READ IN THE PORT MOV R0,#ELTIME1 ;SET NDX TO EL TIMER MSB JB0 SETEL1 ;CHECK AC-ON MOV @R0,#EL.K1 ;SET TO BATTERY VALUE JMP SETEL2 SETEL1: MOV @R0,#EL.K10 ;SET TO AC VALUE SETEL2: DEC R0 ;SET NDX TO EL TIMER LSB MOV @R0,#EL.K0 ;AND RESET IT RET ; ; START OF FIFTH PAGE OF ROM ; ; ; CONVERT - The SCANCODE routine will convert keyboard ; column/row information to either a PC equivalent scan ; code or to a special conversion code which will be ; indicated by bit 7 being a 1. This routine will ; further decode this information. ; ; A = Output of scan code table with B7 = 1 ; ; F0 = 1 for break, 0 for make. ; ; The keyboard state is held in R7 of bank 0: ; ; ORG ROM.ORG+400H ;TABLE AT X00 ; NL.B EQU 20H ;NUM LOCK SET SCRL.B EQU 10H ;SCROLL LOCK SENT ALT.B EQU 08H ;ALT DOWN CTL.B EQU 04H ;CTL DOWN LS.B EQU 02H ;LS DOWN RS.B EQU 01H ;RS DOWN CONVERT: MOV R0,A ;HOLD ENTRY IN R0 JMPP @A ;INDIRECT THRU TBL ; ; STATE KEYS - This routine will maintain the states ; of LS, RS, CTL and NUM LOCK. ; CONV.LS: MOV A,R7 ;FETCH STATE JF0 CONV.LS1 ;SKIP IF BREAK ORL A,#LS.B ;SET LS BIT MOV R7,A ;RESTORE STATE JMP ARG1 ;AND SEND FIRST ARG CONV.LS1: ANL A,#NOT LS.B ;CLR LS BIT MOV R7,A ;RESTORE STATE JMP ARG1 ;AND SEND FIRST ARG CONV.RS: MOV A,R7 ;FETCH STATE JF0 CONV.RS1 ;SKIP IF BREAK ORL A,#RS.B ;SET RS BIT MOV R7,A ;RESTORE STATE JMP ARG1 ;AND SEND FIRST ARG CONV.RS1: ANL A,#NOT RS.B ;CLR RS BIT MOV R7,A ;RESTORE STATE JMP ARG1 ;AND SEND FIRST ARG CONV.CTL: MOV A,R7 ;FETCH STATE JF0 CNV.CTL1 ;SKIP IF BREAK ORL A,#CTL.B ;SET CTL BIT MOV R7,A ;RESTOEE STATE JMP ARG1 ;AND SEND FIRST ARG CNV.CTL1: ANL A,#NOT CTL.B ;CLR CTL BIT MOV R7,A ;RESTORE STATE JMP ARG1 ;AND SEND FIRST ARG CONV.LCK: MOV A,R7 ;FETCH STATE JF0 CNV.LCK2 ;SKIP IF BREAK JB0 CNV.LCK1 ;SKIP IF RS JB2 ARG1 ;SND NUM LOCK IF CTL XRL A,#NL.B ;TOGGLE NUM LOCK MOV R7,A ;RESTORE STATE JMP ARG1 ;SEND NUM LOCK CNV.LCK1: ORL A,#SCRL.B ;SET SCROLL BIT MOV R7,A ;RESTORE STATE JMP ARROW ;SEND SCROLL CNV.LCK2: JB4 CNV.LCK3 ;BREAK SCROLL LOCK JMP ARG1 ;BREAK NUM LOCK CNV.LCK3: ANL A,#NOT SCRL.B ;CLR SCROLL BIT MOV R7,A ;RESTORE STATE JMP ARROW ;BREAK SCROLL LOCK CONV.ALT: MOV A,R7 ;FETCH STATE JF0 CNV.ALT1 ;SKIP IF BREAK ORL A,#ALT.B ;SET ALT BIT MOV R7,A ;RESTORE STATE JMP ARG1 ;AND SEND FIRST ARG CNV.ALT1: ANL A,#NOT ALT.B ;CLR CTL BIT MOV R7,A ;RESTORE STATE JMP ARG1 ;AND SEND FIRST ARG ; ; CONTROL FUNCTIONS - This routine handles "Prt On" ; which will send a CTL-P, and "Break" which will send a ; CTL-SCROLL LOCK. "Pause" is handled by CONV.LOCK: ; CTLKEYS: MOV A,R7 ;FETCH STATE JB2 ARG2 ;SKP IF CTL TO 2ND ARG JMP ARG1 ;JMP TO FIRST ARG ; ; NUMERIC KEYPAD - Keys in the range of the numeric ; keypad will come through here. If NUM LOCK is false ; the normal key function will be transmitted. If NUM LOCK ; is true, the numeric keypad equivalent will be transmitted. ; NUMPAD: MOV A,R7 ;FETCH STATE JB5 ARG2 ;SKIP IF NUM LOCK JMP ARG1 ;SEND FIRST ARG ARG2: INC R0 ;BUMP ONE ARG ARG1: INC R0 ;BUMP ONE ARG MOV A,R0 ;RECALL ADDR ARGS: MOVP A,@A ;FETCH THE ARG JF0 ARGS2 ;SKIP IF KEY BREAK JMP ARGS3 ; ARGS2: ADD A,#80H ;ADD BREAK BIT ARGS3: JMP SENDSCAN ;SEND THE BREAK ; ; ARROW KEYS - From the rom table in this page, select an ; fetch a scan code based on the state of RS. Fetch ; argument three which is the macro address for the key. ; With this data in registers, depart to another ; page with more space to resolve this situation. ; ARROW: INC R0 ;BUMP TO ARG1 MOV A,R7 ;FETCH STATE JB0 ARROW1 ;SKIP IF RS MOV A,R0 ;ADDR BACK TO A MOVP A,@A ;FETCH ARG1 XCH A,R0 ;SWAP DATA & ADDR INC A ;TO ARG2 JMP ARROW2 ;AND CONTINUE ARROW1: INC R0 ;TO ARG2 MOV A,R0 ;RECALL ADDR MOVP A,@A ;FETCH ARG2 XCH A,R0 ;SWAP DATA & ADDR ARROW2: INC A ;DUMP TO ARG3 MOVP A,@A ;FETCH ARG3 JMP MACSET ;SETUP MACRO, NEW PAGE ; ; ICON KEYS - Icon keys will execute this code. If ; processing a key make, unique NMI status codes are ; generated for ALT and non-ALT versions of the key. ; No Scan Codes are placed in the FIFO. ; ICONS: JF0 ICONS3 ;SKIP IF BREAK MOV A,R7 ;FETCH STATE JB3 ICONS1 ;SKIP IF ALT MOV A,R0 ;RECALL ADDR INC A ;FIRST ARG JMP ICONS2 ;AND FETCH ICONS1: MOV A,R0 ;RECALL ADDR INC A ;SKIP FIRST ARG INC A ;USE SECOND ARG ICONS2: MOVP A,@A ;FETCH NMI STATUS CALL NMI ;SEND THE CODE SEL RB0 ;RESTORE REG BANK ICONS3: RET ;AND DONE ; ; MATH KEYS - Send alpha-key first argument if NUM LOCK ; if off. Otherwise fetch the second argument and depart ; to another page to setup a macro. ; MATH: MOV A,R7 ;RECALL STATE JB5 MATH1 ;SKIP IF NUM LOCK JMP ARG1 ;USE ALPHA KEY MATH1: INC R0 ;T0 ARG1 JMP ARROW1 ;TO FINISH UP X00: DB CONV.LS ;LEFT SHIFT KEY, 4.1 DB 02AH X01: DB CONV.RS ;RIGHT SHIFT KEY, 3.2 DB 036H X02: DB CONV.CTL ;CONTROL KEY, 2.7 DB 01DH X03: DB CONV.LCK ;LOCK KEY, 7.0 DB 045H ;NUM LOCK DB 046H ;SCROLL LOCK DB MACROES+15 ;Macro-8,Data X04: DB ARROW ;DELETE KEY, 5.0 DB 053H ;DELETE DB 052H ;INSERT DB MACROES+9 ;Macro-5,Data X05: DB CTLKEYS ;BREAK, 4.4 DB 00DH ;= DB 046H ;SCROLL LOCK X06: DB CTLKEYS ;PRINTER ON, 9.0 DB 028H ;' DB 019H ;^P X07: DB ICONS ;CLOCK ICON, 11.6 DB ICLOCK$ ;NMI STATUS CODE DB IACLOCK$ ;ALT-CLOCK X08: DB ICONS ;PHONE ICON, 12.6 DB IPHONE$ ;NMI STATUS CODE DB IAPHONE$ ;ALT-PHONE X09: DB ICONS ;DISK ICON, 12.5 DB IDISK$ ;NMI STATUS CODE DB IADISK$ ;ALT-DISK X0A: DB ICONS ;CALCULATOR ICON, 11.5 DB ICALC$ ;CALC DB IACALC$ ;ALT-CALC X0B: DB NUMPAD ;FUNCTION OF NUM LOCK, 9.5 DB 024H ;J - Alpha Key Board DB 04FH ;1 - Numeric Key Pad X0C: DB NUMPAD ; 10.5 DB 025H ;K DB 050H ;2 X0D: DB NUMPAD ; 9.2 DB 026H ;L DB 051H ;3 X0E: DB NUMPAD ; 9.4 DB 016H ;U DB 04BH ;4 X0F: DB NUMPAD ; 10.4 DB 017H ;I DB 04CH ;5 X10: DB NUMPAD ; 9.6 DB 018H ;O DB 04DH ;6 X11: DB NUMPAD ; 9.3 DB 008H ;7 DB 047H ;7 X12: DB NUMPAD ; 10.3 DB 009H ;8 DB 048H ;8 X13: DB NUMPAD ; 10.6 DB 00AH ;9 DB 049H ;9 X14: DB NUMPAD ; 10.7 DB 033H ;, DB 052H ;0 X15: DB MATH ; 8.2 DB 035H ;/ DB 04EH ;+ DB MACROES+11 ;Macro-6,Data X16: DB MATH ; 7.2 DB 027H ;; DB 04AH ;- DB MACROES+13 ;Macro-7,Data X17: DB NUMPAD ; 7.6 DB 34H ;. DB 53H ;. X18: DB ARROW ;FUNCTION OF SHIFT, 5.6 DB 4BH ;< DB 47H ;Home DB MACROES+3 ;Macro-2,Data X19: DB ARROW ; 6.1 DB 4DH ;> DB 4FH ;End DB MACROES+1 ;Macro-1,Data X1A: DB ARROW ; 3.6 DB 48H ;^ DB 49H ;Page Up DB MACROES+7 ;Macro-4,Data X1B: DB ARROW ; 5.2 DB 50H ;V DB 51H ;Page Down DB MACROES+5 ;Macro-3,Data X1C: DB CTLKEYS ;Print Screen, 10.1 DB 29H ;` DB 37H ;* X1D: DB CONV.ALT ;ALTKEY, 1.7 DB 38H ; X1E: DB NUMPAD ;9.7 DB 32H ;M DB 0DH ;= X1F: DB NUMPAD ;8.6 DB 19H ;P DB 37H ;* / PRTSCR SCAN CODE X20: DB NUMPAD ;6.6 DB 0BH ;0 DB 35H ;/ ; ; START OF SIXTH PAGE OF ROM ; ; FRAME - This page of the rom contains all of the ; routines which execute at the end of each frame ; time of the display. These include the cursor ; update NMI, blink and EL timeouts, keyboard ; debouncing and keyboard scanning. ; ORG ROM.ORG+500H ;TABLE AT X00 ; ; FRAME1 - Generate CPU NMI if cursor register has ; been updated since the last end of frame. ; FRAME1: MOV R0,#CRT.REG+11 ;NDX TO 6845 REG 11 MOV A,@R0 ; AND FETCH JB7 STYL1 ;SKIP IF UPDATED DEC R0 ;BUMP NDX TO R10 MOV A,@R0 ; AND FETCH JB7 STYL1 ;SKIP IF UPDATED JB6 FRAME17 ;CURSOR IS ON JMP FRAME2 ;CURSOR IS OFF ;r10 or r11 changed STYL1: MOV R0,#CRT.REG+11 ;NDX TO 6845 REG 11 MOV A,@R0 ; AND FETCH ANL A,#1FH ;MASK TO FIVE BITS MOV @R0,A ;AND RESTORE DEC R0 ;NDX TO REG 10 MOV A,@R0 ;FETCH REG ANL A,#1FH ;MASK TO FIVE BITS XCH A,@R0 ;AND RESTORE JB6 STYL2 ;SKIP IF BLINK JB5 STYL3 ;CURSOR OFF STYL2: JB4 STYL3 ;=>16 JB3 STYL3 ;=>8 ANL A,#07H ;MASK TO THREE BITS INC R0 ;NDX TO R11 MOV R2,A ; SAVE CRT.R10 IN R2 MOV A,@R0 ; FETCH R11 CPL A ; COMPLEMENT ADD A,R2 ; AND ADD JC STYL3 ;R10>R11 ;Cursor is on, generate cursor update NMI DEC R0 ;BACK TO R10 MOV A,@R0 ;FETCH REG ORL A,#40H ;SET BIT 6 MOV @R0,A ;AND RESTORE JMP FRAME18 ;Cursor is now off, generate cursor off NMI STYL3: MOV A,#CUROFF$ JMP FRAME19 ;End of frame test if r10 and r11 unchanged FRAME17: SEL RB1 ;BANK1 REGISTERS DIS I ;BLOCK INTERRUPTS MOV A,R5 ;FETCH DISPLAY STATUS ANL A,#7FH ;CLEAR UPDATE FLAG XCH A,R5 ;SWAP WITH ORIGINAL EN I ;ENABLE INTERRUPTS XRL A,#80H ;INVERT UPDATE FLAG JB7 FRAME2 ;SKIP IF NOT UPDATED FRAME18: MOV A,#CURSOR$ ;LOAD NMI STATUS CODE FRAME19: CALL NMI ;AND SEND NMI ; ; BLINK - Increment the BLINK variable. If no overflow, ; go on to FRAME3. Otherwise, re-initialize the counter. ; If blink is enabled, toggle the blink bit in the display ; control shadow register, otherwise, turn off the blink ; bit in the shadow register. If attribute enable pulsing ; mode is enabled in the display status register, pulse ; attribute enable. Increment the EL panel ; least significant byte. If overflow, reset and increment ; the EL panel most significant byte. If it overflows, ; set it back to -1 so that it will overflow next time and ; clear the EL panel enable bit in the shadow. ; Copy the shadow to the control register. ; FRAME2: SEL RB0 ;BANK 0 REGISTERS MOV R0,#BLINK ;SET NDX TO BLINK INC @R0 ;BUMP IT MOV A,@R0 ;FETCH NEW VALUE JNZ FRAME20 ;SKIP IF NOT ZERO JMP FRAME200 FRAME20: JMP FRAME3 ;RE-INITIALIZE BLINK TIMER FRAME200: MOV @R0,#-K.BLINK ;RE-INIT THE CNTR ;PULSE ATTRIBUTE ENABLE IS MODE ACTIVE SEL RB1 ;IN BANK 1 MOV A,R5 ;FETCH DISP STATUS JB6 FRAME21 ;SKIP IF INHIBITED ANL P2,#NOT ATENA.P ;PULSE LOW ORL P2,#ATENA.P ;AND THEN HIGH ;PROCESS EL TIMEOUT FRAME21: XRL A,#04H ;TOGGLE TIMEOUT DISABLE JB2 FRAME22 ;SKIP IF NOT DISABLED MOV A,R7 ;FETCH CURRENT VALUE ANL A,#EL.B ;MASK TO EL BIT SEL RB0 ;IN BANK 0 MOV R0,A ;HOLD OLD VALUE IN R0 JMP FRAME25 ;SKIP TO BLINK FRAME22: SEL RB0 ;IN BANK 0 MOV R0,#ELTIME1 ;SET NDX TO TIMER MSB MOV A,@R0 ;FETCH CURRENT VALUE JZ FRAME23 ;DISPLAY OFF DEC R0 ;SET NDX TO LSB INC @R0 ;BUMP THE COUNT MOV A,@R0 ;FETCH NEW VALUE JNZ FRAME24 ;DISPLAY ON MOV @R0,#EL.K0 ;SET TO ONE MINUTE INC R0 ;SET NDX TO MSB INC @R0 ;BUMP THE COUNT JMP FRAME24 ;DISPLAY ON ;TURN EL PANEL OFF FRAME23: MOV R0,#0 ;NEW VALUE TO R0 JMP FRAME25 ; ;TURN EL PANEL ON FRAME24: MOV R0,#EL.B ;NEW VALUE IN R0 JMP FRAME25 ; ;PROCESS BLINK CONTROL FRAME25: SEL RB1 ;BANK 1 REGISTERS MOV A,R7 ;FETCH DISPLAY CTL SEL RB0 ;BANK 0 REGISTERS XRL A,#BLINK.B ;INVERT BLINK ANL A,#BLINK.B ;MASK TOGGLED BLINK ORL A,R0 ;MERGE NEW EL BIT ;UPDATE SHADOW AND CONTROL PORT WITH DATA IN R0 FRAME27: SEL RB1 ;IN BANK 1 DIS I ;LOCK OUT INTERRUPTS XCH A,R7 ;SWAP NEW WITH SHADOW ANL A,#NOT(EL.B+BLINK.B) ;MASK TO KEEPERS ORL A,R7 ;MERGE NEW BITS MOV R7,A ;UPDATE SHADOW EN I ;UNBLOCK INTERRUPTS SEL RB0 ;IN BANK 0 MOV R0,#DS.STB ;SET NDX TO DISP CTL MOVX @R0,A ;AND UPDATE PORT ;PROCESS LO BATT 2 NMI MOV A,R5 ;FETCH PWR STAT JB0 FRAME20 ;SKIP IF AC-ON JB1 FRAME28 ;SKIP IF LO BAT 2 JMP FRAME3 ;ELSE DONE FRAME28: MOV A,#LOBAT2$ ;LOAD NMI CODE CALL NMI ;AND SEND TO CPU JMP FRAME3 ;SKIP TO NEXT PAGE ; ; START OF SEVENTH PAGE OF ROM ; ORG ROM.ORG+600H ;********************************************************** ;* KEYBOARD SCAN - The following code sequence will ;* scan the key matrix for changes once per frame ;* time of the LCD display. Key operations are ;* translated into scan codes and loaded into the ;* FIFO for tranmission to the CPU. ICON keys ;* assert NMI and present status codes. Detection ;* of the simultaneous assertion of CTL, ALT and DEL ;* will result in a RESET of the CPU. ;********************************************************** FRAME3: ; ; DEBOUNCE - If there is debounce time remaining, ; decrement the time and skip reading the keyboard ; for this frame time of the display. ; SEL RB0 ;BANK ZERO REGISTERS MOV R0,#BOUNCE ;SET NDX TO BOUNCE MOV A,@R0 ;FETCH DEBOUNCE JZ FRAME35 ;SKIP IF ZERO DEC A ;DECR BALANCE MOV @R0,A ;AND RESTORE JMP MAIN ;TILL NEXT FRAME FRAME35: ; ; MACRO EXECUTION - These routines will poll the eight ; macroes, executing any active macroes in place of ; normal keyboard scanning. This routine will poll for ; active macroes and transmit scan codes as required. ; RS EQU 036H ;SCAN CODE RS RSBRK EQU 0B6H ;SCAN CODE RS BREAK NMLK EQU 045H ;SCAN CODE NUM LOCK NMLKBRK EQU 0C5H ;SCAN CODE NMLK BREAK ;Don't bother to scan macroes or keyboard if FIFO is full. SEL RB1 ;BANK 1 REGISTERS MOV A,R2 ;FETCH FIFO-IN INC A ;BUMP PTR JNZ MACX0 ;SKIP IF NOT OVFL MOV A,#FIFO ;WRAP THE FIFO MACX0: XRL A,R3 ;CMP FIFO-OUT SEL RB0 ;BACK TO BANK 0 JNZ MACX1 ;IF NOT FULL JMP MAIN ;IF FIFO IS FULL ;Scan for active macroes MACX1: MOV R0,#MACROES ;SET NDX TO MACROES MOV R1,#NUMMACRO ;FOR NUMBER MACROES MACX2: MOV A,@R0 ;FETCH CTL BYTE JZ MACX12 ;SKIP IF INACTIVE ;Play it again, Sam: JB6 MACX4 ;NMLK JB5 MACX5 ;NMLK BREAK JB1 MACX6 ;RS BREAK JB2 MACX7 ;DATA JB0 MACX8 ;RS MAKE JB4 MACX9 ;NUM LOCK MAKE ; JB3 MACX10 ;NUM LOCK BREAK ;Send Num Lock Break MACX3: ANL A,#0F7H ;CLEAR 3 BIT MOV @R0,A ; TO CTL BYTE MOV A,#NMLKBRK ; JMP MACX11 ;Send Num Lock Make MACX4: ANL A,#0BFH ;CLEAR BIT 6 MOV @R0,A ;TO CTL BYTE MOV A,#NMLK ; JMP MACX11 ;Send Num Lock Break MACX5: ANL A,#0DFH ;MASK BIT 5 MOV @R0,A ;TO CTL BYTE MOV A,#NMLKBRK ; JMP MACX11 ;Send RS Up MACX6: ANL A,#0FDH ;CLEAR BIT 1 MOV @R0,A ;TO CTL BYTE MOV A,#RSBRK ;LOAD RS BRK JMP MACX11 ;SEND SCANCODE ;Send Data MACX7: ANL A,#0FBH ;CLEAR BIT 2 MOV @R0,A ;TO CTL BYTE INC R0 ;BUMP TO DATA MOV A,@R0 ;FETCH JMP MACX11 ; AND SEND ;Send RS MACX8: ANL A,#0FEH ;CLEAR BIT 0 MOV @R0,A ;TO CTL BYTE MOV A,#RS ;LOAD RS JMP MACX11 ;SEND SCANCODE ;Send NMLK Make MACX9: ANL A,#0EFH ;CLEAR BIT 4 MOV @R0,A ;TO CTL BYTE MOV A,#NMLK ;LOAD NMLK MACX11: CALL SENDSCAN ;SEND SCANCODE ;***** MOV R0,#BOUNCE ;DELAY 1 FRAME PER CHARACTER EXPANSION MOV @R0,#1 JMP MAIN ;AND DONE ;Loop for five macroes MACX12: INC R0 ;BUMP ADDR TO DATA INC R0 ;BUMP ADDR TO NEXT CTL DJNZ R1,MACX2 ;LOOP FOR EIGHT MACROES ; ; READ KEY MATRIX - The twelve rows of the key matrix ; are read into the corresponding even byte locations ; in the 24 byte structure KEY-ARRAY. The current state ; of FDC-ENA which is controlled by PAD6 must be main- ; tained. Turn off the KB decoder when done. ; KBSCAN1: MOV R0,#AUX.ENA ;SET NDX TO AUX PORT MOVX A,@R0 ;READ PORT TO A ANL A,#40H ;MASK TO FDC-ON ADD A,#04 ;ADD FIRST KB ROW MOV R0,A ;AND MOVE TO NDX MOV R1,#KARRAY ;FIRST KEY ARRAY BYTE MOV R2,#12 ;FOR TWELVE ROWS KBSCAN2: MOVX @R0,A ;SELECT KB ROW MOV R3,#8 ;A COUNT OF 8 KBSCAN21: DJNZ R3,KBSCAN21 ;WASTE 16 CYCLES MOVX A,@R0 ;READ KB ROW DATA MOV @R1,A ;AND SAVE IN ARRAY INC R0 ;ADVANCE KB ROW INC R0 ;BY FOUR TO INC R0 ;NEXT KB INC R0 ;COLUMN INC R1 ;ADVANCE ARRAY NDX BY INC R1 ;TWO TO NEXT ENTRY DJNZ R2,KBSCAN2 ;DECR ROW CNT MOV A,R0 ;COPY R0 TO A ANL A,#40H ;MASK FDC ON MOV R0,A ;AND REPLACE MOVX @R0,A ;KB OFF, KEEP FDC ; ; LOCATE CHANGED KEYS - The current state of the ; key matrix is compared with the previous state. ; Changes are processed. The new data for rows ; eleven and twelve is ignored if more than one ; key is active between the two rows. ; KBSCAN3: MOV R1,#KARRAY+20 ;NDX TO ROW 11 MOV A,@R1 ;FETCH NEW DATA JNZ KBSFN2 ;SKIP IF R11 KEYS MOV R1,#KARRAY+22 ;NDX TO ROW 12 MOV A,@R1 ;FETCH NEW DATA JZ KBSFN4 ;SKIP IF NO KEYS KBSFN5: CLR C ;CLEAR FOR ROTATE KBSFN1: RLC A ;ROTATE LEFT JNC KBSFN1 ;UNTIL FIRST BIT FOUND JZ KBSFN4 ;PROCESS 12 IF UNIQUE JMP KBSFN3 ;ELSE USE ONLY 10 ROWS KBSFN2: MOV R4,A ;HOLD R11 DATA IN R4 MOV R1,#KARRAY+22 ;NDX TO ROW 12 MOV A,@R1 ;FETCH NEW DATA JNZ KBSFN3 ;SKIP IF R11 AND R12 KEYS MOV A,R4 ;RECALL R11 DATA JMP KBSFN5 ;AND CHECK FOR MULTI ;USE ONLY 10 ROWS OF NEW DATA KBSFN3: MOV R2,#10 ;PROCESS ONLY 10 ROWS JMP KBSFN6 ;THIS SCAN ;USE ALL 12 ROWS OF NEW DATA KBSFN4: MOV R2,#12 ;PROCESS TWELVE ROWS KBSFN6: MOV R1,#KARRAY ;START OF KARRAY KBSCAN4: MOV A,@R1 ;FETCH NEW DATA INC R1 ;NDX TO OLD DATA XCH A,@R1 ;XCHG NEW WITH OLD XRL A,@R1 ;LOCATE CHANGES JZ KBSCAN6 ;SKIP IF NONE CLR F0 ;SET KEY MAKE MOV R3,A ;SAVE A COPY ANL A,@R1 ;FIND THE MAKES JZ KBSCAN5 ;SKIP IF NONE CALL SCANCODE ;PROCESS MAKES KBSCAN5: MOV A,@R1 ;XOR COMPLEMENT CPL A ;OF NEW DATA WITH ANL A,R3 ;WITH CHANGES TO JZ KBSCAN6 ;FIND BREAKS - ANY? CPL F0 ;INDICATE BREAKS CALL SCANCODE ;PROCESS BREAKS KBSCAN6: INC R1 ;BUMP TO NEXT NEW DJNZ R2,KBSCAN4 ;LOOP FOR ALL ROWS JMP FRAME4 ;TO CHANGE PAGE ; ; START OF EIGHTH PAGE OF ROM ; ORG ROM.ORG+700H ; ROM DISK - The following code is used to upload 'sectors' ; of the keyboard processors rom to the host. The host processor ; requests a sector by writing the sector number with an ofset ; of 32 as an NMI Request. When the processor responds to the ; NMI, the sector number will be translated to a pointer into ; the following rom page table. This pointer will be held in ; the variable PAGE between accesses. The data is obtained by ; reading the Mode register. The first byte obtained will be ; byte 2 of the sector in order to skip the header. Each ; access will auto-increment the byte offset so that the entire ; sector may be read Subsequent ; ; In RADDR, test for a RAM DISK access after testing for cursor ; update access. If found, set R0 to 2* (NMI - 32) and place ; a 2 in register R1. ; ; Add a RMODE in which, if NMI is active, a byte of ROM DISK ; data is returned. ; ; The RMODE function will be disabled by the NMI acknowledge, ; i.e. reading RADDR again. ; ; PAGE.TBL - This table has one entry for each page ; of a bank of rom. Each entry copies the contents ; of R1 which is the target ofset within the page. ; The is followed by the incrementing of R1 which ; brings the entry size up to four bytes. The entry ; ends with a "long jump" to the destination in the ; new bank. ; PAGE.TBL: DB PG0 - PAGE.TBL DB PG1 - PAGE.TBL DB PG2 - PAGE.TBL DB PG3 - PAGE.TBL DB PG4 - PAGE.TBL DB PG5 - PAGE.TBL DB PG6 - PAGE.TBL DB PG7 - PAGE.TBL PG0: MOV A,R1 ;COPY OFST FROM R1 INC R1 ;BUMP OFST JMP 0 ;IN BANK 1 PG1: MOV A,R1 ;COPY OFST FROM R1 INC R1 ;BUMP OFST JMP 100H ;IN BANK 1 PG2: MOV A,R1 ;COPY OFST FROM R1 INC R1 ;BUMP OFST JMP 200H ;IN BANK 1 PG3: MOV A,R1 ;COPY OFST FROM R1 INC R1 ;BUMP OFST JMP 300H ;IN BANK 1 PG4: MOV A,R1 ;COPY OFST FROM R1 INC R1 ;BUMP OFST JMP 400H ;IN BANK 1 PG5: MOV A,R1 ;COPY OFST FROM R1 INC R1 ;BUMP OFST JMP 500H ;IN BANK 1 PG6: MOV A,R1 ;COPY OFST FROM R1 INC R1 ;BUMP OFST JMP 600H ;IN BANK 1 PG7: MOV A,R1 ;COPY OFST FROM R1 INC R1 ;BUMP OFST JMP 700H ;IN BANK 1 ; ; ROM DISK is called for each data fetch of the rom disk. ; ROM.DSK: MOV R0,#PAGE ;SET NDX TO PAGE MOV A,@R0 ;AND RECALL PAGE DIS I DIS TCNTI CALL ROM.DSK3 ;ENABLE BANK 1 SELECT CALL ROM.DSK1 ;FETCH THE DATA SEL MB0 ;RESELECT ROM BANK 1 CALL RDATA ;SEND TO HOST MOV A,R6 ;RESTORE A FROM R6 EN TCNTI EN I RETR ;AND DONE ; ROM.DSK1: SEL MB1 ;IN ROM BANK 1 JMPP @A ;INDIRECT VIA PAGE TBL ; ROM.DSK2: MOV R0,#PAGE ;SET NDX TO PAGE MOV A,R4 ;FETCH NMI STATUS ANL A,#1FH ;CLR ACTIVE AND DISK MOV @R0,A ;AND STORE IN PAGE MOV R1,#2 ;BYTE OFST TO 2 MOV A,R6 ;RESTORE A RETR ;AND DONE ROM.DSK3: RETR ;ALLOW BANK 1 TO BE SELECTED ; ; Each Sector of the Rom Disk must be formatted with the ; following header: ; ; MOVP A,@A ;FETCH DATA ; RET ;AND RETURN ; ; ; MACRO SETUP - Hold the data in the macro while determining ; the break status. Then offset data as required. Build the ; control byte and store it in the macro. Note that normal ; arrow key usage will result in a single key invocation of ; the macro. Exit back to SCANCODE to debounce and to ; restore the keyboard scan state. ; MACSET: XCH A,R0 ;SWAP ADDR TO R0 JF0 MACSET1 ;SKIP IF BREAK JMP MACSET2 ;USE NEW DATA MACSET1: MOV A,#80H ;ADD BREAK BIT TO ORL A,@R0 ; PREV MAKE CODE MACSET2: MOV @R0,A ;STORE THE DATA ;Setup Macro Control Word CLR A ;CLEAR ACCUM JF0 MACSET4 ;SKIP IF BREAK MOV A,R7 ;RECALL STATE ANL A,#21H ;KEEP RS & NUM JB0 MACSET5 ;SKIP IF RS MACSET3: JB5 MACSET6 ;SKIP IF NMLK MACSET4: ADD A,#04H ;SET DATA DEC R0 ;BUMP ADDR TO CTL MOV @R0,A ;AND STORE BYTE RET ;BACK TO KEYSCAN MACSET5: XRL A,#02H ;CLR RS, SET 0 & 1 JMP MACSET3 ;AND CONTINUE MACSET6: XRL A,#58H ;CLR NUM, SET 6, 5, 4, & 3 JMP MACSET4 ;AND CONTINUE ORG 7FFH ; DB 0H ; END