IMD 1.15: 16/05/2007 8:29:16 OSBORNE EXECUTIVE DS/DD ROM V 1.3 DISK 2 OF 2 AAAROM1 MAC; ROM2 MAC ROM2 MAC !"#$%&'()ROM2 MAC*+,-./0123456789ROM2 MAC:;<ROM3 MAC=>?@ABCDEFGHIJKLROM3 MACMROM4 MACNOPQRSTUVWXYZ[\]ROM4 MACG^_`abcdefROM6 MACghijklmnopqrstuvROM6 MAC~wxyz{|}~ROM7 MACROM7 MAC_ROM8 MAC<ROM1 PRNROM1 HEX SUBTTL 'POWER ON TEST' ; ********************************************************* ; * * ; * POWER ON TEST * ; * * ; ********************************************************* ; ; POTEST.ASM ; FEBRUARY 22TH, 1983 ; BY CHRIS MAYER ; ; MODULE 1 --ROM1-- ENTRY POINTS ; ; POWER ON DIAGNOSTICS ; ; ; PODIAG: START OF DIAGNOSTIC TEST ; MEMORY_TEST: START OF MEMORY TEST ; ROM_TEST: START OF ROM TEST ; LSI_TEST: START OF LSI REGISTERS TEST ; DIAG_INIT: INITIALIZES SYSTEM FOR DIAGNOSTIC PAGE .Z80 ; .XLIST ; INCLUDE SYSS1.MAC ;SYSTEST FILE ; INCLUDE RAMS10.MAC ;RAM MEMORY LOCATIONS AND CONSTANTS ; INCLUDE RAMSMON.MAC ;MONITOR RAM MEMORY LOCATIONS ; .LIST ; ;SYSS1.MAC , RAMSMON.MAC AND RAMS10.MAC INCLUDED ; EXT SET_INT,INITIALIZE,INIT_INT,COUT,AUTOBOOT,OSTR ; PUBLIC PODIAG,L_PWR_UP,DIAG_INIT PAGE PODIAG: LD A,0 PWR_UP: DI EX AF,AF' ;RESET REPEAT FLAG XJ007: CALL MEMORY_TEST MEM_DONE: CALL ROM_TEST CALL LSI_TEST LD A,0FFH EX AF,AF' CP 0FFH ;LOOP FLAG SET ? JP Z,XJ007 CALL DIAG_INIT ;RESTORE INTERRUPTS & STUFF LD C,'G' -040H CALL COUT ;YEA! WE MADE IT LD SP,ROMSTK EI JP AUTOBOOT ;ALL DONE L_PWR_UP: LD A,0FFH JP PWR_UP ;***** MEMORY TEST ***** MEMORY_TEST: LD SP,0BFFFH ;STACK = TPA UNDER VIDEO MEMORY LD A,0C0H ;TEST VIDEO MEMORY OUT (SYS_DTA),A LD HL,0C000H ;SET FIRST ADDRESS POINTER LD BC,4*1024 ;SET BLOCK SIZE LD A,0AAH ;SET TEST PATTERN CALL MEM_TEST LD A,055H CALL MEM_TEST EX AF,AF' PUSH AF ;SAVE LOOP FLAG CALL DIAG_INIT ;RESTORE CONSOLE STUFF LD DE,TEST_MESSAGE ;CLEAR JUNK FROM VIDEO TEST CALL OSTR ; & SHOW TEST MESSAGE DI POP AF EX AF,AF' ;RESTORE LOOP FLAG LD HL,02000H ;TEST ROM'S RAM LD BC,2*1024 LD A,0AAH CALL MEM_TEST LD A,055H CALL MEM_TEST LD SP,027FFH ;STACK = TOP OF ROM'S RAM LD A,080H ;TEST BANK 0 OUT (SYS_DTA),A LD HL,04000H LD BC,48*1024 LD A,0AAH CALL MEM_TEST LD A,055H CALL MEM_TEST LD A,081H ;TEST BANK 1 OUT (SYS_DTA),A LD HL,04000H LD BC,44*1024 LD A,0AAH CALL MEM_TEST LD A,55H CALL MEM_TEST CALL UNIQUE_ADDR JP MEM_DONE ;RET IS FUNNY AFTER A MEM TEST MEM_TEST: PUSH HL PUSH BC ;SAVE REGISTERS FOR NEXT PATTERN PUSH HL PUSH BC ;SAVE REGISTERS FOR CPI# LD E,L LD D,H ;DE <- HL INC DE ;SETTING DE UP FOR LDIR LD (HL),A DEC BC ;FIRST LOAD WAS DONE 'BY HAND' LDIR ;FILL MEMORY POP BC POP HL ;RESTORE REGISTERS FOR CPI# MEM_CHECK: CPI LD IY,' M' ;M = MEMORY ERROR JP NZ,ERROR ;HOPE IT'S THE SAME JP PE,MEM_CHECK ;DONE YET ? POP BC POP HL ;RESTORE REGISTERS FOR NEXT TEST RET UNIQUE_ADDR: LD IY,' U' ;U = UNIQUE ADDRESS TEST ERROR LD A,0 ;DATA WRITTEN LD B,15 LD DE,1 LD HL,08001H ;ADDRESS POINTER XJ008: LD (HL),A ;WRITE DATA INC A ;CHANGE IT ADD HL,DE ;POINT TO NEXT ADDRESS EX DE,HL ADD HL,HL EX DE,HL ;DOUBLE DE DJNZ XJ008 ;15 TIMES LD (08000H),A INC A LD (07FFFH),A LD C,0 LD B,1A5 LD DE,1 LD HL,08001H XJ009: LD A,(HL) ;READ DATA CP C JP NZ,ERROR INC C ADD HL,DE ;POINT TO NEXT ADDRESS EX DE,HL ADD HL,HL EX DE,HL ;DOUBLE DE DJNZ XJ009 LD A,(08000H) CP C JP NZ,ERROR INC C LD A,(07FFFH) CP C ;CHECK LAST ADDRESS JP NZ,ERROR RET ;THE PATTERN IS AS FOLLOWS: ;10000000_00000001B 00 ;10000000_00000010B 01 ;10000000_00000100B 02 ;10000000_00001000B 03 ;10000000_00010000B 04 ;10000000_00100000B 05 ;10000000_01000000B 06 ;10000000_10000000B 07 ;10000001_00000000B 08 ;10000010_00000000B 09 ;10000100_00000000B 0A ;10001000_00000000B 0B ;10010000_00000000B 0C ;10100000_00000000B 0D ;11000000_00000000B 0E ;10000000_00000000B 0F ;01111111_11111111B 10 ;***** ROM CHECK-SUM VERIFICATION ***** ROM_TEST: LD HL,0 ;POINTER TO BYTES TO ADD UP LD IX,0 ;MID & LOW BYTES ACCUMULATOR LD BC,8*(1024)-3 ;# OF BYTES TO ADD UP LD DE,0 LD A,0 ;HIGH BYTE ACCUMULATOR PUSH AF MORE: POP AF ;RESTORE HIGH BYTE OF SUM LD E,(HL) ;GET BYTE INC HL DEC BC ADD IX,DE ADC A,0 ;ADD CARRY TO HIGH BYTE PUSH AF ;SAVE HIGH BYTE OF CHECK-SUM LD A,B OR C JR NZ,MORE ;FINISHED ADDING YET ? POP AF LD HL,8*(1024)-1 CP (HL) ;COMPARE WITH HIGH BYTE LD IY,' R' ;R = ROM ERROR JP NZ,ERROR PUSH IX POP DE DEC HL ;POINT TO MID BYTE LD A,D CP (HL) ;COMPARE WITH MIDDLE BYTE JP NZ,ERROR DEC HL LD A,E CP (HL) ;COMPARE WITH LOW BYTE JP NZ,ERROR RET ;YEA YEA, ROM'S O.K. ! ;***** LSI REGISTERS TEST ***** LSI_TEST: LD IY,' P' ;P = PARALELL CHIP ERROR CALL PIA LD IY,' S' ;S = SIO ERROR CALL SIO ; LK IY,' C' ;C = CTC ERROR ; CALL CTC8253 RET PIA: LD A,03FH ;TOP 2 BITS ARE INTERRUPTS CALL XJ010 ;TEST SYS CONTROL REGISTERS LD A,0 CALL XJ010 LD A,080H ;HIGH BIT KEEPS THE ROM ON CALL XJ011 ;TEST SYS DIR REGISTERS LD A,0FFH CALL XJ011 LD A,04H OUT (SYS_CNA),A OUT (SYS_CNB),A ;ENABLE DATA REGISTERS LD A,010001000B ;HIGH BIT KEEPS THE ROM ON CALL XJ011 ;TEST SYS DATA REGISTERS LD A,011110111B ;THIS PATTERN LEAVES DRIVES & SPEAKER OFF CALL XJ011 RET XJ010: LD B,A OUT (SYS_CNA),A OUT (SYS_CNB),A IN A,(SYS_CNA) AND 00111111B CP B JP NZ,ERROR IN A,(SYS_CNB) AND 00111111B CP B JP NZ,ERROR RET XJ011: LD B,A OUT (SYS_DTA),A OUT (SYS_DTB),A IN A,(SYS_DTA) CP B JP NZ,ERROR IN A,(SYS_DTB) CP B JP NZ,ERROR RET SIO: LD C,0 CALL SIO_TEST LD C,0F1H CALL SIO_TEST RET SIO_TEST: LD A,2 OUT (SIO_CNB),A ;POINT TO WRITE REG 2 LD A,C OUT (SIO_CNB),A ;WRITE PATTERN LD A,2 OUT (SIO_CNB),A ;POINT TO READ REGISTER 2 IN A,(SIO_CNB) ;READ IT BACK AND 011110001B ;REMOVE BITS WHICH MAY CHANGE ;BECAUSE OF STATUS AFFECTS VECTOR ;STATE OF SIO CP C JP NZ,ERROR ;THEY BETTER BE THE SAME ! RET ;CTC8253: LK C,TIM_CT0 ; CALL CTC_TEST ; LK C,TIM_CT1 ; CALL CTC_TEST ; LK A,060H ; OUT TIM_CT2 ; LK A,0 ; OUT TIM_CT2 ;CT2 NEVER GETS INITIALIZED ; LK C,TIM_CT2 ; CALL CTC_TEST ; RET ; ;CTC_TEST: IN,C A ; MOV E,A ; IN,C A ; MOV D,A ;PUT VALUE IN DE ; IN,C A ; MOV L,A ; IN,C A ; MOV H,A ;PUT 'LATER' VALUE IN HL ; OR A ;RESET CARRY FLAG FOR SBC ; SBC HL,DE ; MOV A,H ; OR L ; JZ ERROR ;COUNTER NOT DECREMENTING ! ; RET ;***** COMMON ROUTINES AND MESSAGES ***** ERROR: PUSH IY ;SAVE ERROR CODE CALL INITIALIZE ;RESTORE INTERRUPTS & STUFF LD DE,ERROR_MSG ;OH NOOOOOO ! CALL OSTR LD A,0C0H OUT (SYS_DTA),A POP BC ;RESTORE ERROR CODE LD HL,0C000H LD (HL),C ;SHOW WHICH ERROR JR $ ;SO RESET JUMPS TO BOOT ROUTINE TEST_MESSAGE: DB 'Z'-040H,ESC,'=',32+10,32+30,'PERFORMING SELF-TES' DC 'T' ERROR_MSG: DB ESC,'=',32+10,32+25, 'COMPUTER NOT WORKING PROPERLY' DB ESC,'=',32+11,32+24,'PLEASE CONTACT AN OSBORNE DEALER' DB ESC,'=',32+12,32+28 ,'PROCEED AT YOUR OWN RIS' DC 'K' PAGE ; ********************************************************* ; * * ; * DIAGNOSTIC INITIALIZATION * ; * * ; ********************************************************* ;INITIALIZE SYSTEM FOR DIAGNOSTIC DIAG_INIT: CALL INITIALIZE ;INITIALIZE MEMORY & SYSTEM PIA CALL SET_INT ;INDIVIDUALLY DISABLE ALL INTERRUPTS EXCEPT RESET CALL INIT_INT ;INITIALIZE SIO AND REENABLE ALL THE INTERRUPT RET  ;SAVE ERROR CODE CALL INITIALIZE ;RESTORE INTERRUPTS & STUFF LD DE,ERROR_MSG ;OH NOOOOOO ! CALL OSTR LD A,0C0H OUT (SYS_DTA),A POP BC ;RESTORE ERROR CODE LD HL,0C000H LD (HL),C ;SHOW WHICH ERROR JR $ ;SO RESET JUMPS TO BOOT ROUTINE TEST_MESSAGE: DB 'Z'-040H,ESC,'=',32+10,32+30,'PERFORMING SELF-TES' DC 'T' ERROR_MSG: DB ESC,'=',32+10,32+25, 'COMPUTER NOT WORKING PROPERLY' DB ESC,'=',32+11,32+24,'PLEASE CONTACT AN OSBORNE DEALER' DB ESC,'=',32+12,32+28 ,'PROCEED AT YOUR OWN RIS' DC 'K' PAGE ; ********************************************************* ; * * ; * DIAGNOSTIA SUBTTL 'CONSOLE ROUTINES' ; ********************************************************* ; * * ; * CONSOLE ROUTINES * ; * * ; ********************************************************* ; ; MODULE 2 --ROM2-- ENTRY POINTS ; ; CONSOLE ROUTINES ; ; SKEY: GET STATUS OF KEYBOARD ; CON_IN: GETS A KEYSTROKE ; COUT: GENERAL OUTPUT TO CONSOLE ; LOOKUPB: LOOK UP CHAR. IN TABLE AND BRANCH TO PROPER ROUTINE ; SETTBL: SET TABLE POINTER TO CURRENT TABLE ; PROCNORM: PROCESS 'NORMAL' CHAR. (I.E. NOT LEAD-IN CHAR.) ; CHECKS FOR GRAPHICS OR NORMAL CHAR. AND BRANCH TO ; PROPER ROUTINE ; VGRAPH: PROCESS GRAPHICS CHAR. ; VNORM: PROCESS NORMAL CHAR. ; VOUT: DISPLAY NEW CHAR. AND UPDATE CURSOR ; VC_CR: PERFORM CARRIAGE RETURN ; VC_LF: PERFORM LINE FEED ; VC_NEWLINE: PERFORM CARRIAGE RETURN/LINE FEED ; VC_BKS: MOVE CURSOR LEFT (BACKSPACE) ; VC_MCRT: MOVE CURSOR RIGHT ; VC_MCUP: MOVE CURSOR UP ; VC_MCDOWN: MOVE CURSOR DOWN ; VC_HOME: 'HOME' CURSOR (MOVE TO UPPER LEFT CORNER) ; DO_CR: PROCESS CARRIAGE RETURN ; DO_LF: PROCESS LINE FEED ; EEOL: ERASE TO END OF LINE ; EEOS: ERASE TO END OF SCREEN ; EDELC: DELETE CHAR. ; EINSRT: INSERT CHAR. ; ESCRR: DELETE LINE ; ESCEE: INSERT LINE ; CLR_CHAR: CLEAR CHAR. FOR GIVEN POSSITION ; CLR_EOS: CLEAR TO END OF WINDOW ; VC_CLRS: CLEAR ENTIRE WINDOW ; ESCZZ: CLEAR ENTIRE WINDOW ; SCROL_UP: SCROLL UP ; SCROL_DOWN: SCROLL DOWN ; S_UP_DOWN: PERFORM SCROLLING ; VC_BEL: RING BELL ; ESC_LCK: LOCK KEYBOARD ; ESC_ULK: UNLOCK KEYBOARD ; ESCSAL: ENABLE ALTERNATE CHAR. SET ; ESCSHI: ENABLE HALF INTENSITY ; ESCSGR: ENABLE GRAPHICS ; ESCSRV: ENABLE REVERSE VIDEO ; ESCSUN: ENABLE UNDER LINE ; ESCSBL: ENABLE BLINK ; ESCCAL: DISABLE ALTERNATE CHAR. SET ; ESCCHI: DISABLE HALF INTENSITY ; ESCCGR: DISABLE GRAPHICS ; ESCCRV: DISABLE REVERSE VIDEO ; ESCCUN: DISABLE UNDERLINE ; ESCCBL: DISABLE BLINK ; REVON: SET REVERSE VIDEO BACKGROUND ; REVOFF: CLEAR REVERSE VIDEO BACKGROUND ; NEW_BACK: DEFINE NEW BACKGROUND ; DEFCUR: DEFINE CURSOR TYPE ; SET_ATR: SET SELECTED ATTRIBUTES ; TOG_ATR: TOGGLE SELECTED ATTRIBUTES ; TOG_CUR: TOGGLE CURSOR ; SET_BACK: SET BACKGROUND ; GET__ATR: CONVERT ATTRIBUTES (FROM TV950 TO INTERNAL) ; YCOORD: SET Y COORDINATE FOR CURSOR ; XCOORD: SET X COORDINATE FOR CURSOR ; SETOFF: SET X-Y COORDINATE OFFSET ; ADDROWS: ADD ROWS TO GIVEN ADDRESS ; ABSOLUTE: GET ABSOLUTE VALUE FOR OFFSET ; LASTROW: CHECK IF ADDRESS ON LAST LINE ; GETCOL: GET COLUMN NUMBER OF ADDRESS ; GETROW: GET ROW NUMBER OF ADDRESS ; SETCOL: SET COLUMN NUMBER ; SETROW: SET ROW NUMBER ; DEF_WINDOW: DEFINE AND SET WINDOW ; STARTROW: DEFINE FIRST ROW OF WINDOW ; STARTCOL: DEFINE FIRST COLUMN OF WINDOW ; ENDROW: DEFINE LAST ROW OF WINDOW ; ENDCOL: DEFINE LAST COLUMN OF WINDOW ; SETWIND: SET WINDOW NUMBER ; GETWIND: GET ADDRESS OF WINDOW DEFINITION ; SEQERR: HANDLE UNDEFINED ESC SEQUENCE ; RETPROC: RETURN (USED WHEN NO PROCESSING REQUIRED) ; DISPLAY: DISPLAY CHAR. AT CURRENT POSSITION ; DIST2EOL: CALCULATE DISTANCE TO END OF LINE ; DIST2LASTROW: CALCULATE DISTANCE TO END OF SCREEN ; NOTE: PLAY A MUSICAL NOTE PAGE .Z80 ; .XLIST ; INCLUDE SYSS1.MAC ;SYSTEST FILE ; INCLUDE RAMS10.MAC ;RAM MEMORY LOCATIONS AND CONSTANTS ; INCLUDE RAMSMON.MAC ;MONITOR RAM MEMORY LOCATIONS ; .LIST ; ;SYSS1.MAC , RAMSMON.MAC AND RAMS10.MAC INCLUDED ; EXT RM_C_BF,GET_INT,SET_INT ; PUBLIC SKEY,CON_IN,COUT,ALT_FLG,CTBLPTRS,LENCTBL CSEG PAGE SKEY: ;GET STATUS OF KEYBOARD ;EXIT ;A = 0 IF NO CHARACTER READY ;A = 0FFH IF CHARACTER READY ;ZBIT SET IF NO DATA READY ;CHECK FOR LOCKED KEYBOARD LD A,(KEYLCK) OR A RET Z ;IF LOCKED KEYBOARD ;CHECK FOR PROCESSING FUNCTION KEY LD A,(COUNT) OR A ;IF PROCESSING FUNCTION KEY -- JP NZ,XJ018 ; RETURN ZBIT CLEAR AND A = 0FFH (DATA READY) ;CHECK BUFFER STATUS ; LDK B,KBD_DEV ;KEYBOARD ; CALL RM_CH_ST ;CHECK KEYBOARD BUFFER STATUS LD HL,(D_RT_TBL+D_RT_LEN*KBD_DEV+4) ; LOAD CHAR CNT FROM DEVICE ROOT LD A,H ;IS CHAR COUNT ZERO? OR L ; JR Z,XJ019 ;ZBIT SET IF NO CHARACTER READY XJ018: OR 0FFH ;SET A = 0FFH, CLEAR Z FLAG RET XJ019: XOR A ;A = 0 IF NO CHARACTER RET PAGE CON_IN: ; GETS KEYSTROKE ; FUNCTION KEY TRANSLATION PERFORMED ON CODES 80H TO 8DH DEPENDING ; ON SYSTEM FLAG FKEYFLAG: ; ; FKEYFLAG = 0 --- NO TRANSLATION ; FKEYFLAG = 1 --- TRANSLATION AS PER TABLE ; ; EXIT A = KEY CODE IN ASCII ; ;CHECK IF FUNCTION KEY IS BEING TRANSLATED XJ020: LD A,(COUNT) OR A JR Z,XJ021 ;NO FUNCT. TRANS. -- GET KEY FROM KEYBOARD BUFFER ;FUNCTION KEY NEEDS TRANSLATION ; 'PNTR' = ADDRESS OF NEXT BYTE OF TRANSLATION ; 'COUNT' = # OF BYTES LEFT FOR TRANSLATION LD HL,(FPNTR) LD A,(HL) ;GET NEXT BYTE OF TRANSLATION INC HL LD (FPNTR),HL ;ADVANCE TRANSLATION POINTER LD HL,COUNT DEC (HL) ;REDUCE COUNT OF BYTES LEFT RET ;NO TRANSLATION -- GET KEY FROM KEYBOARD BUFFER ;WAIT FOR KEY READY XJ021: CALL SKEY ;GET STATUAS JR Z,XJ021 ;IF NO DATA, WAIT ;GET KEY LD B,KBD_DEV ;KEYBOARD DI CALL RM_C_BF ;GET CHARACTER FROM KEYBOARD BUFFER LD HL,(D_RT_TBL+D_RT_LEN*KBD_DEV+4) ; DECREMENT CHARACTER COUNT DEC HL LD (D_RT_TBL+D_RT_LEN*KBD_DEV+4),HL ; AND SAVE IT BACK EI ;CHECK IF KEY IS A FUNCTION KEY CP 80H RET C ;RETURN IF KEYSTROKE < 80H (NOT A FUNCTION KEY) CP 8EH RET NC ;RETURN IF KEYSTROKE > 8FH (NOT A FUNCTION KEY) ;IF FUNCTION KEY RETURNED FROM BUFFER ; DETERMINE WHICH TRANSLATION TABLE IS NEEDED LD B,A ;SAVE KEY LD A,(FKEYFLAG) OR A ;SET FLAGS LD A,B ;RESTORE CHARACTER RET Z ;RETURN IF NO TRANSLATION LD HL,FKEY_ADR ;TRANSLATION TABLE ADDRESS ; INITIALIZE FPNTR AND COUNT ;GET FUNCTION KEY NUMBER XJ022: AND 0FH ;GET FUNCTION KEY NUMBER LD B,A ;B = FUNCTION KEY NUMBER JR Z,XJ023 ;IF FUNCTION KEY 0 ;GET FUNCTION KEY'S ADDRESS LD D,0 XJ024: LD E,(HL) ;E = LENGTH OF THIS FUNCTION KEY INC E ;COUNT LENGTH BYTE ADD HL,DE ;HL = ADDRESS OF NEXT FUNCTION KEY DJNZ XJ024 ;IF NOT TO THE RIGHT KEY YET ;INITIALIZE FPNTR AND COUNT XJ023: LD A,(HL) ;GET LENGTH OF THIS FUNCTION KEY LD (COUNT),A INC HL ;POINT TO FIRST BYTE OF TRANSLATION LD (FPNTR),HL JR XJ020 ;RETURN FIRST BYTE OF THIS FUNCTION KEY TRANSLATION PAGE COUT: ;GENERAL OUTPUT ROUTINE TO VIDEO SCREEN ;ENTRY ;C = CHARACTER ;CURPOS = CURSOR ;CFLAG = FLAG+MODE ;CURPOS & CFLAG UPDATED, A=CHARACTER ;(BC, DE, HL PRESERVED) ;BRING IN VIDEO BANK IN A,(SYS_DTA) ;GET CURRENT BANKS PUSH AF ;SAVE CURRENT BANKS OR VID_BANK OUT (SYS_DTA),A ;TURN ON VIDEO BANK ;TURN OFF OLD CURSOR CALL TOG_CUR ;TOGGLE CURSOR ;PROCESS CHARACTER CALL LOOKUPB ;RUN PROCEDURE ADDRESSED IN TABLE ;TURN ON NEW CURSOR CALL TOG_CUR ;BRING BACK OLD BANKS POP AF ;GET OLD BANKS OUT (SYS_DTA),A RET ;RETURN, END OF COUT SUBR. PAGE ; ********************************************************* ; * * ; * TABLE HANDELING ROUTINES * ; * * ; ********************************************************* LOOKUPB: ;LOOK UP CHARACTER IN THE SPECIFIED TABLE AND BRANCH TO PROCESSING PROCEDURE ;IF CHARACTER IS NOT IN THE TABLE, THEN BRANCH TO DEFAULT PROCEDURE. ;ENTRY ;C = CHAR ;*NOTE* ;AFTER GETTBL IS CALLED: ;HL = TABLE ADDRESS ; 1ST BYTE OF TABLE = NUMBER OF (NON-DEFAULT) TABLE ENTRIES ; ENTRIES ARE 4 BYTES LONG: ; 1ST BYTE = MATCH CODE ; 2ND BYTE = NEXT TABLE NUMBER ; 4TH,5TH BYTES = BRANCH ADDRESS ; THE LAST ENTRY IS A 3-BYTE "NO MATCH" DEFAULT NEXT TABLE NUMBER AND BRANCH ADDRESS ;EXIT ;JUMPS TO BRANCH ADDRESS IN TABLE ;C = CHARACTER ;GET CURRENT TABLE LD HL,(ROMCON) ;GET DE = CURRENT TABLE POINTER LD E,(HL) INC HL LD D,(HL) EX DE,HL ;HL = CURRENT TABLE ;FIND CHARACTER IN TABLE LD A,(HL) ;A = NUMBER OF ENTRIES INC HL ;FIRST ENTRY OR A JR Z,XJ025 ;IF NO ENTRIES, DO DEFAULT PROCESSING LD B,A ;B = NUMBER OF ENTRIES LD A,C ;A = CHARACTER XJ026: CP (HL) ;CHECK FOR MATCH INC HL ;(2ND BYTE OF THIS 4 BYTE ENTRY) JR Z,XJ025 ;IF MATCH PROCESS INC HL ;(3RD BYTE OF THIS ENTRY) INC HL ;(4TH BYTE OF THIS ENTRY) INC HL ;1ST BYTE OF NEXT ENTRY DJNZ XJ026 ;CONTINUE THRU BODY OF TABLE ;SET UP NEXT TABLE ADDRESS XJ025: PUSH HL ;SAVE CURRENT POSITION IN TABLE LD A,(HL) ;A = NEXT TABLE NUMBER CALL SETTBL ;SET NEXT TABLE POP HL ;RESTORE ;BRANCH TO PROCESSING PROCEDURE INC HL ;GO TO BRANCH ADDRESS PORTION OF TABLE ENTRY LD A,(HL) ;1ST BYTE (LOW ORDER ADRS) INC HL LD H,(HL) ;2ND BYTE (HIGH ORDER ADRS) LD L,A ;HL=ADRS FROM TABLE LD A,C ;A = CHAR JP (HL) ;ENTER ROUTINE PER TABLE ADRS. PAGE SETTBL: ;SET CURRENT TABLE POINTER TO POINT TO SELECTED TABLE ;ENTRY ;A = TABLE NUMBER ;EXIT ;PRESERVES BC PUSH BC LD DE,(ROMCON) ;GET DE = CURRENT TABLE POINTER ; (BASE ADDRESS FOR TABLE OF TABLE POINTERS) ADD A,A ;A = TABLE NUMBER * 2 LD L,A LD H,0 ;HL = TABLE NUMBER * 2 ADD HL,DE ;[HL] = NEXT TABLE ADDRESS ;DE => TABLE ADDRESS POINTER LDI LDI ;SET TABLE ADDRESS TO NEXT TABLE ADDRESS POP BC RET PAGE ;BASTBL PROCEDURES PROCNORM: ;NORMAL CHARACTER ENTERED (IE NOT A LEAD-IN CHARACTER) ;CHECKS FOR GRAPHICS OR NORMAL CHARACTER AND PASSES CHARACTER ON TO APPROPRIATE ;ROUTINE ;ENTRY ;C = CHARACTER ;EXIT ;JUMPS TO VGRAPH OR VNORM WHICH PROCESS CHARACTER AND UPDATE CURSOR LD A,(CFLAG) ;GET FLAGS XJ027: AND GR_FLG ;CHECK FOR GRAPHICS MODE JR NZ,VGRAPH ;GRAPHICS MODE -- PROCESS CHARACTER JR VNORM ;NORMAL MODE -- PROCESS CHARACTER, SET HL = CURSOR POSITION PAGE VGRAPH: ;GRAPHICS MODE CHARACTER PROCESSING ;CHARACTERS 60H-7FH ARE CONVERTED TO GRAPHICS CHARACTERS (00H-1FH) ;SO THAT BASIC CAN ACCESS ALL GRAPHICS CHARACTERS ;ENTRY ;C = CHAR TO PROCESS LD A,C BIT 5,A JP Z,VOUT BIT 6,A JP Z,VOUT AND 9FH ;CONVERT TO GRAPHICS CHARACTERS JP VOUT VNORM: ;NORMAL MODE CHARACTER PROCESSING. ;ENTRY ;C = CHAAR TO OUTPUT LD A,C CP 20H JP NC,VOUT ;IF NOT CONTROL CHAR, OUTPUT IT ;IF CONTROL CHARACTER LD A,CTLNUM ;SET CURRENT TABLE TO CONTROL TABLE CALL SETTBL JP LOOKUPB ;SCAN TABLE OF VALID CONTROL CHRS AND BRANCH TO APPROPRIATE ROUTINE. PAGE VOUT: ;DISPLAY NEW CHARACTER AND UPDATE CURSOR ;ENTRY ;A = CHAR CALL DISPLAY ;DISPLAY NEW CHARACTER JP VC_MCRT ;MOVE CURSOR RIGHT PAGE ; ********************************************************* ; * * ; * CONTROL CHARACTER CODE PROCESSING * ; * CURSOR MOVEMENTS * ; * * ; ********************************************************* VC_CR: ;CARRIAGE RETURN ;ENTRY ;NONE ;EXIT ;CURPOS = NEW CURSOR POSITION LD HL,(CURPOS) CALL DO_CR LD (CURPOS),HL RET PAGE VC_LF: ;LINE FEED (IF CURSOR IS ON LAST LINE, SCROLL SCREEN AND ADD ; NEW LINE AT BOTTOM) ;ENTRY ;NONE ;EXIT ;CURPOS = NEW CURSOR POSITION LD HL,(CURPOS) CALL DO_LF LD (CURPOS),HL RET PAGE VC_NEWLINE: ;DO CR AND LF ;ENTRY ;NONE ;EXIT ;CURPOS UPDATED CALL VC_CR JP VC_LF PAGE VC_BKS: ;MOVE CURSOR LEFT (BACKSPACE). ;(IF IN 1ST COLUMN THEN WRAP AROUND TO LAST COLUMN OF PREVIOUS LINE) ;(NO EFFECT IF IN 1ST POSITION OF WINDOW) ;ENTRY ;NONE ;EXIT ;CURPOS = NEW CURSOR POSITION ;CHECK IF AT COLUMN 0 LD HL,(CURPOS) CALL GETCOL ;GET CURSOR COLUMN JR Z,XJ028 ;IF MUST WRAP FROM COL 0 TO LAST COL OF PREVIOUS LINE ;IF NOT, BACKSPACE AND RETURN LD HL,(CURPOS) DEC HL JR XJ029 ;IF AT COLUMN 0, CHECK FOR ROW 0 XJ028: CALL GETROW RET Z ;RETURN WITH NO EFFECT IF AT COL 0, ROW 0 ;IF NOT, WRAP AROUND TO PREVIOUS LINE CALL VC_MCUP ;MOVE UP A LINE (HL = NEW ADDRESS) LD HL,(CURPOS) ;MOVE TO END OF LINE CALL DIST2EOL ;BC = DISTANCE FROM CURSOR TO END OF LINE ADD HL,BC ;HL = NEW CURSOR ADDRESS XJ029: LD (CURPOS),HL ;SAVE NEW CURSOR POSITION RET PAGE VC_MCRT: ;MOVE CURSOR RIGHT (IF AT END OF LINE, WRAP AROUND TO NEXT LINE) ;ENTRY ;NONE ;EXIT ;CURPOS = NEW CURSOR POSITION LD HL,(CURPOS) CALL DIST2EOL ;A = # OF BYTES BETWEEN CURSOR AND END OF LINE JR Z,XJ030 ;IF AT LAST COLUMN LD HL,(CURPOS) INC HL ;MOVE CURSOR JR XJ031 ;IF AT LAST COLUMN, WRAP AROUND TO NEXT LINE XJ030: CALL DO_CR ;DO CR... CALL DO_LF ;...AND LF. XJ031: LD (CURPOS),HL ;SAVE NEW CURSOR POSITION RET PAGE VC_MCUP: ;MOVE CURSOR UP. (IF CURSOR IS ON TOP LINE THEN NOTHING HAPPENS) ;ENTRY ;NONE ;EXIT ;CURPOS = NEW CURSOR POSITION ;MOVE UP A LINE LD HL,(CURPOS) OR A ;CLEAR CARRY LD BC,VLL SBC HL,BC ;MOVE UP A LINE ;CHECK IF ABOVE SCREEN PUSH HL ;SAVE CURSOR LD DE,(FWAWIND) SBC HL,DE ;CARRY FLAG SET IF ABOVE SCREEN POP HL JR NC,XJ032 ;DONE IF ON SCREEN ;IF SO, GO BACK TO OLD POSITION ADD HL,BC XJ032: LD (CURPOS),HL RET PAGE VC_MCDOWN: ;MOVE CURSOR DOWN (NO EFFECT IF CURSOR IS ON LAST LINE) ;ENTRY ;NONE ;EXIT ;CURPOS UPDATED ;CHECK IF ON LAST LINE LD HL,(CURPOS) CALL LASTROW ;CHECK IF ON LAST ROW RET Z ;IF ON LAST ROW, DO NOTHING ;IF NOT, MOVE CURSOR DOWN LD DE,VLL ADD HL,DE LD (CURPOS),HL RET PAGE VC_HOME: ;HOME CURSOR ;ENTRY ;NONE ;EXIT ;CURPOS = NEW CURSOR POSITION LD HL,(FWAWIND) ;HOME POSITION LD (CURPOS),HL RET PAGE DO_CR: ;DO CARRIAGE RETURN PROCESSING ;ENTRY ;HL = ADDRESS TO PROCESS ;EXIT ;HL = ADDRESS AFTER CARRIAGE RETURN ;CLEAR COLUMN BITS IN SELECTED ADDRESS LD A,80H AND L LD L,A ;GET FIRST COLUMN OF WINDOW LD DE,(FWAWIND) LD A,E AND 7FH ;GET FIRST WINDOW COLUMN ;SET ADDRESS COLUMN TO FIRST COLUMN OF WINDOW OR L ;OR IN NEW COLUMN LD L,A RET PAGE DO_LF: ;DO LINE FEED PROCESSING (IF ADDRESS IS ON LAST LINE, SCROLL SCREEN AND ADD NEW ;LINE AT BOTTOM) ;ENTRY ;HL = ADDRESS TO PROCESS ;EXIT ;HL = ADDRESS AFTER LINE FEED ;CHECK IF ON LAST LINE CALL LASTROW JR Z,XJ053 ;SCROLL IF ON LAST LINE ;MOVE DOWN ONE LINE LD DE,VLL ;LINE LENGTH ADD HL,DE ;HL = NEW ADDRESS POSITION RET ;IF ON LAST LINE, SCROLL WINDOW UP XJ053: PUSH HL ;SAVE ADDRESS LD HL,(FWAWIND) CALL SCROL_UP ;SCROLL WHOLE WINDOW UP POP HL ;RESTORE ADDRESS RET PAGE ; ********************************************************* ; * * ; * CONTROL CHARACTER CODE PROCESSING * ; * EDITING FUNCTIONS * ; * * ; ********************************************************* EEOL: ;ERASE TO END OF LINE ;ENTRY ;NONE ;EXIT ;CURPOS UNCHANGED LD HL,(CURPOS) JP CLRLN ;CLEAR TO END OF LINE PAGE EEOS: ;ERASE TO END OF SCREEN ;ENTRY ;NONE ;EXIT ;NONE LD HL,(CURPOS) JP CLR_EOS ;CLEAR TO END OF SCREEN PAGE EDELC: ;DELETE CHARACTER ;ENTRY ;NONE ;EXIT ;NONE LD HL,(CURPOS) CALL DIST2EOL ;Z FLAG SET IF AT END OF LINE JR Z,XJ034 ;IF AT END OF LINE PUSH HL POP DE ;DE = CURSOR ADDRESS INC HL ;HL = CURSOR ADDRESS + 1 LDIR ;MOVE CHARACTERS XJ03A4: JP CLR_CHAR ;LAST CHARACTER BECOMES BLANK PAGE EINSRT: ;INSERT CHARACTER ;ENTRY ;NONE LD HL,(CURPOS) CALL DIST2EOL ;BC = DISTANCE TO END OF LINE JR Z,XJ035 ;IF IN LAST COLUMN, JUST BLANK ;CURRENT CHAR ADD HL,BC ;HL = LAST POSITION IN CURSOR LINE PUSH HL POP DE ;DE = LAST POSITION IN LINE DEC HL ;HL = 2ND TO LAST POSITION LDDR ;MOVE LINE OVER XJ035: LD A,20H JP DISPLAY ;PUT A ' ' IN CURSOR POSITION AND SET SELECTED ATTRIBUTES PAGE ESCRR: ;DELETE LINE (SCROLLS LOWER LINES UP AND PUTS CURSOR AT BEGINNING OF LINE) ;ENTRY ;NONE LD HL,(CURPOS) CALL SCROL_UP ;DELETE LINE AND SCROLL LOWER LINES UP JP VC_CR ;PUT CURSOR AT BEGINNING OF LINE PAGE ESCEE: ;INSERT LINE (PUTS CURSOR AT BEGINNING OF INSERTED LINE) ;ENTRY ;NONE ;EXIT ;NONE LD HL,(CURPOS) CALL SCROL_DOWN ;SCROLL LINES FROM CURSOR DOWN, CLEAR CURSOR LINE JP VC_CR CLRLN: ;CLEAR TO END OF LINE ;ENTRY ;HL = START POSITION ;EXIT ;CLEAR TO EOL ; USES ALL. ;CLEAR START POSITION CALL CLR_CHAR ;CLEAR CHARACTER ;FIND NUMBER OF BYTES TO CLEAR CALL DIST2EOL ;BC = DISTANCE TO END OF LINE, Z FLAG SET RET Z ;DONE IF AT END OF LINE PUSH HL POP DE INC DE LDIR ;CLEAR REST OF LINE RET PAGE CLR_CHAR: ;CLEAR CHARACTER FOR GIVEN POSITION ;ENTRY ;HL = ADDRESS ;EXIT ;HL PRESERVED PUSH HL LD A,20H LD (HL),A ;CLEAR CHARACTER LD A,(BACKGND) LD C,A ;C = BACKGROUND ATTRIBUTES CALL SET_ATR ;SET BACKGROUND ATTRIBUTES POP HL RET PAGE CLR_EOS: ;CLEAR TO END OF WINDOW ;ENTRY ;HL = START ADDRESS ;EXIT ;NONE ;GET NUMBER OF ROWS TO CLEAR CALL GETROW ;GET CURRENT ROW LD C,A ;SAVE C = ROW LD A,(WINDROWS) SUB C ;A = NUMBER OF ROWS TO CLEAR ;CLEAR ROWS XJ054: PUSH AF PUSH HL CALL CLRLN ;CLEAR TO END OF LINE POP HL CALL DO_CR ;MAKE SURE ALL LINES AFTER THE 1ST ONE ;START AT THE FIRST COLUMN LD DE,VLL ADD HL,DE ;HL = NEXT LINE'S ADDRESS  POP AF DEC A JR NZ,XJ054 ;IF MORE ROWS RET PAGE VC_CLRS: ESCZZ: ;CLEAR WINDOW ;ENTRY ;NONE ;EXIT ;HL = NEW CURSOR POSITION LD HL,(FWAWIND) ;BEGINNING OF WINDOW LD (CURPOS),HL ;POSITION CURSOR TO BEGINNING OF WINDOW JP CLR_EOS ;CLEAR WINDOW PAGE ; ********************************************************* ; * * ; * CONTROL CODE CHARACTER PROCESSING * ; * SCROLLING * ; * * ; ********************************************************* SCROL_UP: ;SCROLL UP THE LINES FROM SELECTED POSITION TO THE END OF THE WINDOW ;(CLEARS LAST LINE) ;ENTRY ;HL = SELECTED POSITION ;EXIT ;NONE ;POSITION AT BEGINNING OF LINE LD A,0FFH LD (SCRL_UPF),A ;SET SCROL_UP FLAG JP S_UP_DOWN SCROL_DOWN: ;SCROLL WINDOW DOWN FROM SELECTED START LINE TO END OF WINDOW XOR A LD (SCRL_UPF),A ;RESET SCROL_UP FLAG ;FALL THROUGH TO S_UP_DOWN ROUTINE PAGE S_UP_DOWN: ;(CLEARS START LINE) ;ENTRY ;HL = START ADDRESS  ;EXIT ;NONE ;POSITION AT BEGINNING OF LINE CALL DO_CR ;MAKE SURE AT BEGINNING OF LINE ;SCROLL UP OR DOWN CALL DIST2LASTROW ;GET A = NUMBER OF ROWS TO SCROLL JR Z,XJ055 ;IF ON LAST LINE PUSH AF LD A,(SCRL_UPF) ;IS SCROLL UP ? OR A JR NZ,XJ056 ;YES- LD A,(WINDROWS) DEC A CALL SETROW ;HL = LAST ROW'S ADDRESS XJ056: LD A,(WINDCOLS) LD C,A LD B,0 ;BC = NUMBER OF COLUMNS POP AF ;RESTORE A = NUMBER OF ROWS XJ057: LD DE,VLL PUSH AF LD A,(SCRL_UPF) ;IS SCROLL UP ? OR A JR Z,XJ058 ;NO- POP AF EX DE,HL ADD HL,DE JR XJ059 XJ058: POP AF PUSH HL ;SAVE ROW ADDRESS OR A ;CLEAR CARRY SBC HL,DE POP DE ;HL = ROW ABOVE DE XJ059: PUSH BC ;SAVE # CHARS/ROW PUSH HL ;SAVE ROW ADDRESS LDIR POP HL ;RESTORE POP BC DEC A JR NZ,XJ057 ;IF MORE ROWS ;CLEAR START LINE XJ055: CALL CLRLN ;HL = START LINE'S ADDRESS RET PAGE ; ********************************************************* ; * * ; * CONTROL CHARACTER CODE PROCESSING * ; * MISCELLANEOUS * ; * * ; ********************************************************* VC_BEL: ;RING THE BELL ;ENTRY ;NONE ;EXIT ;NONE LD HL,0300H ;FREQUENCY (# MICROSECONDS IN 1/2 PERIOD) LD DE,0100H ;DURATION (# OF WAVES) JP NOTE ;PLAY ONE NOTE PAGE ; ESC SEQUENCE CHARACTER PROCESSING ESC_LCK: ;LOCK KEYBOARD ;ENTRY ;NONE XOR A ;CLEAR A JR XJ033 ESC_ULK: ;UNLOCK KEYBOARD ;ENTRY ;NONE LD A,0FFH XJ033: LD (KEYLCK),A RET PAGE ; ********************************************************* ; * * ; * SET / CLEAR 'CFLAG' ATTRIBUTES * ; * * ; ********************************************************* ;SET ATTRIBUTES ; CFLAG 1 1 1 1 1 1 1 1 ; | | | | | |----- GRAPHICS ; | | | | |------- ALTERNATE CHARACTER SET ; | | | |--------- BLINK ; | | |----------- UNDER LINE ; | |------------- HALF INTENSITY ; |--------------- REVERSE VIDEO ESCSA AL: LD B,ALT_FLG ;START ALTERNATE CHARACTER SET ATTRIBUTE JR XJ036 ESCSHI: LD B,HAF_FLG ;START HALF INTENSITY ATTRIBUTE JR XJ036 ESCSGR: LD B,GR_FLG ;START GRAPHICS ATTRIBUTE JR XJ036 ESCSRV: LD B,REV_FLG JR XJ036 ESCSUN: LD B,UN_FLG JR XJ036 ESCSBL: LD B,BNK_FLG XJ036: LD A,(CFLAG) OR B ;SET BIT JR XJ037 PAGE ;CLEAR ATTRIBUTES ESCCAL: LD B,NOT ALT_FLG ;CLEAR ALTERNATE CHARACTER SET ATTRIBUTE JR XJ038 ESCEHI: LD B,NOT HAF_FLG ;CLEAR HALF INTENSITY ATTRIBUTE JR XJ038 ESCCGR: LD B,NOT GR_FLG ;CLEAR GRAPHICS ATTRIBUTE JR XJ038 ESCCRV: LD B,NOT REV_FLG JR XJ038 ESCCUN: LD B,NOT UN_FLG JR XJ038 ESCCBL: LD B,NOT BNK_FLG XJ038: LD A,(CFLAG) AND B ;CLEAR BIT XJ037: LD (CFLAG),A ;STORE NEW ATTRIBUTE RET PAGE ESCSKK: LD A,1 ;ENABLE KEY CLICK JR XJ039 ESCCKK: XOR A ;DISABLE KEY CLICK XJ039: LD (KCLICK),A RET ESCEFT: LD A,1 ;ENABLE FUNCTION KEY TABLE JR XJ040 ESCDFT: XOR A ;DISABLE FUNCTION KEY TABLE XJ040: LD (FKEYFLAG),A RET PAGE REVON: ;SET REVERSE VIDEO BACKGROUND ;(LEAVES ALL OTHER BACKGROUND BITS ALONE) ;ENTRY ;NONE ;EXIT ;SCREEN SET TO REVERSE VIDEO LD A,(BACKGND) OR REV_FLG ;SET REVERSE VIDEO BIT LD B,A ;B = NEW BACKGROUND ATTRIBUTES JP SET_BACK ;SET NEW BACKGROUND PAGE REVOFF: ;CLEAR REVERSE VIDEO BACKGROUND ATTRIBUTE ;(LEAVES ALL OTHER BACKGROUND BITS ALONE) ;ENTRY ;NONE ;EXIT ;SCREEN SET TO NORMAL VIDEO LD A,(BACKGND) AND NOT REV_FLG ;CLEAR REVERSE VIDEO BIT LD B,A ;B = NEW BACKGROUND ATTRIBUTES JP SET_BACK ;SET NEW BACKGROUND PAGE NEW_BACK: ;DEFINE NEW BACKGROUND ATTRIBUTE BITS ;ENTRY ;C = VIDEO ATTRIBUTE NUMBER (IN ASCII) ;EXIT ;NONE CALL GET_ATR ;GET ATTRIBUTES IN "CFLAG" FORM ;(INTERNAL NUMBERING SYSTEM INSTEAD OF TV950 SYSTEM) JP SET_BACK ;SET NEW BACKGROUND PAGE DEFCUR: ;DEFINE CURSOR TYPE ;(IF SELECTION IS OUT OF RANGE, CURSOR TYPE IS UNCHANGED) ;ENTRY ;C = CURSOR ATTRIBUTE NUMBER (IN ASCII) ; 0 = NO CURSOR DISPLAYED ; 1 = BLINKING BLOCK ; 2 = BLOCK ; 3 = BLINKING UNDERLINE ; 4 = UNDERLINE ; 5 = BLINKING ONLY ;EXIT ;CURTYPE SET LD A,C ;A = CURSOR ATTRIBUTE NUMBER SUB '0' CP 1 JR NC,XJ041 ;IF NOT 0 LD B,0 ;NO CURSOR DISPLAYED JR XJ042 XJ041: JR NZ,XJ043 ;IF NOT 1 LD B,BNK_FLG + REV_FLG ;BLINKING BLOCK JR XJ042 XJ043: CP 3 JR NC,XJ044 ;IF NOT 2 LD B,REV_FLG ;BLOCK JR XJ042 XJ044: JR NZ,XJ045 ;IF NOT 3 LD B,BNK_FLG+UN_FLG ;BLINKING UNDERLINE JR XJ042 XJ045: CP 5 JR NC,XJ046 ;IF NOT 4 LD B,UN_FLG ;UNDERLINE JR XJ042 XJ046: RET NZ ;IF UNDEFINED SELECTION, THEN DON'T CHANGE ANYTHING LD B,BNK_FLG ;BLINKING ONLY XJ042: LD A,B LD (CURTYPE),A ;SAVE NEW CURSOR TYPE RET SET_ATR: ;SET SELECTED ATTRIBUTES IN GIVEN MEMORY LOCATION ;ENTRY ;HL = LOCATION ;C = ATTRIBUTES (BIT 7 = REV, B6 = HF INT, B5 = UND, B4 = BLINK) ;EXIT ;HL PRESERVED PUSH HL LD A,(HL) AND 7FH LD (HL),A ;CLEAR REVERSE VIDEO BIT LD DE,MODEOFF ADD HL,DE ;HL = ATTRIBUTE LOCATION LD A,80H LD (HL),A ;CLEAR ALL ATTRIBUTES POP HL JP TOG_ATR ;SET SELECTED ATTRIBUTES ; (TOGGLING 0'S IS THE SAME AS SETTING 1'S) PAGE TOG_ATR: ;TOGGLE SELECTED ATTRIBUTES IN MEMORY LOCATION ;HL = LOCATION ;C = ATTRIBUTES TO TOGGLE (1 INDICATES TOGGLE, 0 FOR NO TOGGLE) ; (BIT 7 = REVERSE VIDEO, B6 = HF INT, B5 = UND, B4 = BLINK) ;EXIT ;HL PRESERVED PUSH HL LD A,C AND REV_FLG ;GET REVERSE VIDEO BIT XOR (HL) ;IF REVERSE VIDEO IS SELECTED, TOGGLE THAT BIT LD (HL),A LD DE,MODEOFF ADD HL,DE ;HL = ATTRIBUTE LOCATION LD A,C SLA A ;SHIFT TO PROPER POSITION XOR (HL) ;TOGGLE SELECTED BITS LD (HL),A POP HL ;RESTORE ADDRESS RET PAGE TOG_CUR: ;TOGGLE CURSOR ;CURSOR MAY BE ANY COMBINATION OF BLOCK(REV VIDEO), UNDERLINE, AND BLINK ;WHEN THE CURSOR TYPE IS CHANGED, THE FIRST TIME THROUGH THIS ROUTINE WILL ERASE ;THE OLD CURSOR AND THEN SET CURTYP TO THE NEW CURSOR TYPE ;ENTRY ;NONE ;EXIT ;CURSOR INVERTED ;PRESERVES BC PUSH BC ;SAVE ;TOGGLE OLD CURSOR TYPE LD A,(CURTYPE) ;GET CURSOR TYPE LD C,A LD HL,(CURPOS) ;GET CURSOR POSITION CALL TOG_ATR ;TOGGLE ATTRIBUTES POP BC ;RESTORE RET PAGE SET_BACK: ;CHANGE BACKGROUND BITS FOR WINDOW ;ENTRY ;B = NEW BACKGROUND DEFINITION ; (BIT 7 = REV VIDEO, B6 = HF INT, B5 = UND, B4 = BLINK, ) ; B3 = ALTERNATE CHARACTER SET ;EXIT ;NONE ;DECIDE WHICH BITS TO TOGGLE LD A,(BACKGND) XOR B ;TOGGLE NEWLY SELECTED AND DESELECTED BITS LD C,A ;C = BITS TO TOGGLE ;SAVE NEW BACKGND FLAG LD A,B LD (BACKGND),A ;TOGGLE APPROPRIATE BACKGROUND BITS FOR WHOLE WINDOW LD A,(WINDCOLS) LD B,A ;B = # OF COLUMNS/ROW LD HL,(FWAWIND) ;HL = FWA OF WINDOW LD A,(WINDROWS) ;A = # OF ROWS XJ060: PUSH AF ;SAVE ROW NUMBER PUSH BC ;SAVE # OF COLUMNS/ROW PUSH HL ;SAVE ROW ADDRESS XJ061: PUSH BC ;SAVE A  ATTRIBUTE SELECTION CALL TOG_ATR POP BC INC HL DJNZ XJ061 ;GO TO NEXT SPOT IN ROW POP HL ;RESTORE ROW ADDRESS LD DE,VLL ADD HL,DE ;NEXT ROW'S ADDRESS POP BC POP AF DEC A JR NZ,XJ060 ;IF MORE ROWS RET PAGE GET_ATR: ;CONVERT SELECTED ATTRIBUTES FROM TV950 NUMBERING SYSTEM TO INTERNAL ;SYSTEM ; ;TV950: ; (AFTER SUBTRACTING '0') ; ; +---+---+---+---++---+---+---+---+ ; | 7 | 6 | 5 | 4 || 3 | 2 | 1 | 0 | ; +---+---+---+---++---+---+---+---+ ;ALTERNATE CHAR. <----------------------------| | | | | ;UNDERLINE <---------------------------------+ | | | ;REVERSE VIDEO <-------------------------------------+ | | ;BLINKSED <-----------------------------------------+ | ;HALF INTENSITY <---------------------------------------------+ ;INTERNAL: ; +---+---+---+---++---+---+---+---+ ; | 7 | 6 | 5 | 4 || 3 | 2 | 1 | 0 | ; +---+---+---+---++---+---+---+---+ ; | | | | | ;REVERSE VIDEO <------------------+ | | | | ;HALF INTENSITY <---------------------+ | | | ;UNDERLINE <------------------------------+ | | ;ALTERNATE CHAR. <---------------------------------+ ;ENTRY ;C = VIDEO ATTRIBUTE NUMBER (TV950) ;EXIT ;B = INTERNAL CODE LD A,C SUB '0' ;NORMALIZE ATTRIBUTE NUMBER LD C,A LD B,0 ;START WITH NO ATTRIBUTES SET ;CHECK UNDERLINE BIT LD A,UNDBIT ;UNDERLINE BIT IN VIDEO ATTRIBUTE NUMBER AND C ;CHECK IF SET JR Z,XJ062 ;IF NOT UNDERLINE LD A,UN_FLG ;IF UNDERLINE SELECTED LD B,A ;SET UNDERLINE BIT IN B ;CHECK REVERSE BIT XJ062: LD A,REVBIT ;REVERSE BIT IN VIDEO ATTRIBUTE NUMBER AND C ;CHECK IF SET JR Z,XJ063 ;IF NOT REVERSE VIDEO LD A,REV_FLG ;IF REVERSE VIDEO SELECTED OR B LD B,A ;SET REVERSE VIDEO BIT IN B ;CHECK BLINK BIT XJ063: LD A,BLKBIT ;BLINK BIT IN VIDEO ATTRIBUTE NUMBER AND C ;CHECK IF SET JR Z,XJ064 ;IF NOT BLINK LD A,BNK_FLG ;IF BLINK SELECTED OR B LD B,A ;SET BLINK BIT IN B ;CHECK HALF INTENSITY BIT XJ064: LD A,HAFBIT ;HALF INTENSITY BIT IN VIDEO ATTRIBUTE NUMBER AND C ;CHECK IF SET JR Z,XJ065 ;IF NOT HALF INTENSITY LD A,HAF_FLG ;IF HALF INTENSITY SELECTED OR B LD B,A ;SET HALF INTENSITY BIT IN B RET XJ065: LD A,ALTBIT AND C RET Z LD A,ALT_FLG OR B LD B,A RET PAGE ; ********************************************************* ; * * ; * CURSOR COORDINATE PROCESSING * ; * * ; ********************************************************* YCOORD: ;SET UP Y COORDINATE FOR CURSOR ADDRESSSING ;IF COORDINATE IS INVALID, ROW IS SET TO LAST ROW ;ENTRY ;C = CHARACTER (Y COORDINATE + OFFSET) ;EXIT ;CTBLADDR SET UP FOR X COORDINATE CALL ABSOLUTE ;GET ABSOLUTE COORDINATE LD HL,(CURPOS) CALL SETROW ;SET HL TO ROW A LD (CURPOS),HL RET PAGE XCOORD: ;SET UP X COORDINATE. IF COORDINATE IS OUT OF RANGE, POSITION TO COLUMN 0 ;ENTRY ;C = CHARACTER (COORDINATE + OFFSET) ;EXIT ;CTBLADDR RESET TO BASTBL, CURPOS SET TO NEW CURSOR POSITION CALL ABSOLUTE ;GET ABSOLUTE COORDINATE VALUE LD HL,(CURPOS) CALL SETCOL ;SET COLUMN LD (CURPOS),HL RET PAGE SETOFF: ;SET X-Y COORDINATE OFFSET ;ENTRY ;C = OFFSET ;EXIT ;OFFSET UPDATED LD A,C LD (OFFSET),A RET PAGE ADDROWS: ;ADD ROWS TO GIVEN ADDRESS ;ENTRY ;HL = START ADDRESS ;A = NUMBER OF ROWS ;*NOTE* THIS ROUTINE DOES NOT CHECK FOR ADDRESS OUT OF RANGE ; THE CALLING PROCEDURE MUST DO THAT ;EXIT ;HL = NEW ADDRESS ;CHECK FOR ROW 0 OR A ;A = ROW NUMBER RET Z ;DONE IF ROW 0 ;ADD NUMBER OF ROWS TO WINDOW BEGINNING ADDRESS LD DE,VLL ;DISTANCE TO NEXT ROW XJ069: ADD HL,DE ;ADD A ROW DEC A JR NZ,XJ069 ;IF MORE ROWS RET PAGE ABSOLUTE: ;GET ABSOLUTE VALUE FOR OFFSET NUMBER ;ENTRY ;C = NUMBER + OFFSET ;EXIT ;A = ABSOLUTE NUMBER (WITHOUT OFFSET) LD A,(OFFSET) ;GET CURSOR POSITIONING OFFSET NEG ADD A,C ;A = ABSOLUTE CURSOR POSITION  RET PAGE LASTROW: ;CHECK IF GIVEN ADDRESS IS ON LAST LINE ;ENTRY ;HL = ADDRESS ;EXIT ;Z BIT SET IF ON LAST LINE ;HL PRESERVED CALL GETROW ;GET CURRENT ROW LD B,A ;B = CURRENT ROW LD A,(WINDROWS) DEC A ;A = LAST ROW SUB B ;SET Z FLAG IF CURRENT ROW = LAST ROW RET PAGE GETCOL: ;GET COLUMN NUMBER OF SELECTED ADDRESS ;(IF ADDRESS IS OUT OF RANGE AN INVALID NUMBER IS RETURNED) ;ENTRY ;NONE ;EXIT ;A = COLUMN NUMBER ;PRESERVES HL ;GET ACTUAL COLUMN NUMBER FOR FIRST COLUMN OF WINDOW LD DE,(FWAWIND) LD A,E AND 7FH LD C,A ;C = FIRST COLUMN NUMBER ;GET ACTUAL COLUMN NUMBER FOR SELECTED ADDRESS LD A,L ;LOW 7 BITS OF L = COLUMN AND 7FH ;CLEAR HIGH BIT ;GET WINDOW COLUMN NUMBER FOR SELECTED ADDRESS SUB C RET PAGE GETROW: ;GET CURRENT ROW OF SELECTED ADDRESS ;(INVALID NUMBER RETURNED IF ADDRESS IS OUT OF RANGE) ;ENTRY ;HL = ADDRESS ;EXIT ;A = ROW NUMBER ;PRESERVES HL ;GET ACTUAL ROW VALUE OF FIRST ROW IN WINDOW  A PUSH HL LD HL,(FWAWIND) ADD HL,HL ;SHIFT ROW BITS TO H LD A,H AND 1FH ;GET ROW BITS LD C,A POP HL ;GET ACTUAL ROW OF SELECTED ADDRESS PUSH HL ADD HL,HL ;SHIFT ROW BITS TO H LD A,H AND 1FH ;GET ROW BITS POP HL ;GET WINDOW CURSOR ROW SUB C RET PAGE SETCOL: ;SET HL TO GIVEN COLUMN, CURRENT ROW ;(IF COLUMN IS OUT OF RANGE, SET TO COLUMN 0) ;ENTRY ;HL = SELECTED COLUMN ;A = COLUMN NUMBER ;EXIT ;HL = SET TO SELECTED COLUMN ;CHECK FOR VALID COLUMN LD C,A ;SAVE COLUMN LD A,(WINDCOLS) DEC A ;A = LAST COLUMN IN WINDOW CP C ;SET CFLAG IF POSITION OUT OF RANGE LD A,C JR NC,XJ066 ;IF IN RANGE XOR A ;IF OUT OF RANGE ;SET COLUMN ;GET ACTUAL COLUMN VALUE FOR WINDOW'S COLUMN 0 XJ066: LD DE,(FWAWIND) ;START OF WINDOW ADD A,E AND 7FH ;A = ACTUAL COLUMN VALUE LD C,A ;SAVE COLUMN VALUE ;SET COLUMN FOR SELECTED ADDRESS LD A,L AND 80H ;CLEAR COLUMN BITS OR C ;PUT IN NEW COLUMN BITS LD L,A RET PAGE SETROW: ;SET ADDRESS TO GIVEN ROW, CURRENT COLUMN ;(IF ROW IS OUT OF RANGE, ROW SET TO LAST ROW) ;ENTRY ;A = ROW NUMBER ;EXIT ;HL = ADDRESS OF GIVEN ROW, COLUMN 0 ;GET CURRENT COLUMN LD C,A PUSH BC ;SAVE ROW CALL GETCOL POP BC ;RESTORE ROW PUSH AF ;SAVE COLUMN ;CHECK FOR VALID ROW LD A,(WINDROWS) DEC A ;A = LAST VALID ROW NUMBER CP C JR C,XJ067 ;IF INVALID LD A,C ;IF VALID XJ067: LD HL,(FWAWIND) ;START AT TOP OF WINDOW CALL ADDROWS ;AND ADD A ROWS XJ068: POP AF ;RESTORE COLUMN JP SETCOL PAGE ; ********************************************************* ; * * ; * WINDOW PROCESSING * ; * * ; ********************************************************* DEF_WINDOW: ;DEFINE AND SET WINDOW. ;THE DEFINE WINDOW ESCAPE SEQUENCE SPECIFIES A WINDOW NUMBER AND DEFINES THE ;UPPER LEFT AND LOWER RIGHT CORNERS. THEN THE CURSOR IS POSITIONED TO THE HOME ;POSITION OF THE WINDOW. ONCE A WINDOW HAS BEEN DEFINED, IT CAN BE SET AGAIN ;BY JUST USING THE SET WINDOW COMMAND. ;(WINDOW NUMBER CAN BE 1-15. WINDOW 0 IS RESERVED AND IS ALWAYS DEFINED AS THE FULL SCREEN) ;ENTRY ;C = WINDOW NUMBER (IN ASCII) ;EXIT ;WINDNUM = WINDOW NUMBER LD A,C SUB '0' ;NORMALIZE AND 0FH ;GET NUMBER MOD 16 LD (WINDNUM),A ;SAVE WINDOW NUMBER RET PAGE STARTROW: ;DEFINE FIRST ROW OF WINDOW ;(IF ROW IS OUT OR RANGE, SET TO ROW 0) ;ENTRY ;C = ROW NUMBER + OFFSET ;EXIT ;TEMPFWA = ADDRESS SO FAR ;CHECK FOR VALID ROW NUMBER LD A,C CALL ABSOLUTE ;GET ABSOLUTE NUMBER (WITHOUT OFFSET) LD B,VMROWS CP B JR C,XJ047 ;IF VALID ROW, A = SELECTED ROW XOR A ;IF INVALID, A = ROW 0 ;GET ROW ADDRESS XJ047: LD (FSTROW),A ;SAVE ROW NUMBER LD HL,FWAVM ;START OF VIDEO MEMORY CALL ADDROWS ;GET NEW ADDRESS LD (TEMPFWA),HL ;SAVE IN TEMPORARY FWA FOR WINDOW RET PAGE STARTCOL: ;DEFINE FIRST COLUMN OF WINDOW ;(INVALID COLUMNS ARE SET TO COLUMN 0) ;ENTRY ;C = COLUMN NUMBER + OFFSET ;TEMPFWA SET TO SELECTED ROW, COLUMN 0 ;EXIT ;TEMPFWA = FWA FOR WINDOW ;CHECK FOR VALID COLUMN LD A,C ;A = SELECTED COLUMN + OFFSET CALL ABSOLUTE ;A = SELECTED COLUMN LD B,VMCOLS ;B = NUMBER OF COLUMNS IN VIDEO MEMORY CP B JR C,XJ048 ;IF VALID, A = SELECTED COLUMN NUMBER XOR A ;IF INVALID, A = 0 ;SET COLUMN IN TEMPFWA XJ048: LD (FSTCOL),A ;SAVE FIRST COLUMN NUMBER LD HL,(TEMPFWA) ;TEMPFWA = SELECTED ROW, COLUMN 0 LD E,A LD D,0 ADD HL,DE LD (TEMPFWA),HL RET PAGE ENDROW: ;DEFINE LAST ROW OF WINDOW ;(IF INVALID ROW SELECTED, ROW SET TO LAST ROW) ;ENTRY ;C = ROW NUMBER + OFFSET ;EXIT ;TEMPROWS = # OF ROWS IN NEW WINDOW ;CHECK FOR VALID ROW LD A,C ;A = SELECTED ROW + OFFSET CALL ABSOLUTE ;A = SELECTED ROW LD B,VMROWS ;B = NUMBER OF ROWS CP B JR C,XJ049 ;IF VALID, A = SELECTED ROW DEC B LD A,B ;IF INVALID, A = LAST ROW ;CALCULATE NUMBER OF ROWS XJ049: LD HL,FSTROW LD B,(HL) ;B = FIRST ROW NUMBER ;A = LAST ROW NUMBER SUB B JR NC,XJ050 ;IF VALID... ; XOR A ;INVALID, FORCE IT TO 1... XJ050: INC A ;A = NUMBER OF ROWS LD (TEMPROWS),A ;SAVE NUMBER OF ROWS RET PAGE ENDCOL: ;DEFINE LAST COLUMN FOR WINDOW AND SAVE WINDOW DEFINITION ;(IF COLUMN OUT OF RANGE, SET TO LAST COLUMN) ;ENTRY ;C = COLUMN NUMBER + OFFSET ;EXIT ;NEW WINDOW DEFINITIONS SET UP ;CHECK FOR VALID COLUMN LD A,C ;A = SELECTED COLUMN + OFFSET CALL ABSOLUTE ;A = SELECTED COLUMN LD B,VMCOLS ;B = NUMBER OF COLUMNS IN SCREEN CP B JR C,XJ051 ;IF VALID, A = SELECTED COLUMN DEC B LD A,B ;A = LAST COLUMN ;GET NUMBER OF COLUMNS XJ051: LD HL,FSTCOL LD B,(HL) ;B = FIRST COLUMN ;A = LAST COLUMN SUB B JR NC,XJ052 ;IF LAST AFTER FIRST... ; XOR A ;LAST COL IS BEFORE FIRST, ;FORCE TO 1. XJ052: INC A ;A = NUMBER OF COLUMNS ;SAVE NEW WINDOW DEFINITION LD B,A ;SAVE NUMBER OF COLUMNS LD A,(WINDNUM) ;A = WINDOW NUMBER THAT IS BEING DEFINED CP RESERVED RET Z ;DON'T DEFINE THE RESERVED WINDOW  A CALL GETWIND ;GET HL = ADDRESS OF WINDOW DEFINITION LD DE,(TEMPFWA) LD (HL),E ;SAVE NEW FWA INC HL LD (HL),D IN HL LD A,(TEMPROWS) LD (HL),A ;SAVE NEW NUMBER OF ROWS INC HL LD (HL),B ;SAVE NEW NUMBER OF ROWS ;SET WINDOW LD A,(WINDNUM) ADD A,'0' LD C,A ;C = ASCII VALUE FOR WINDOW ;FALL THROUGH TO SETWIND PAGE SETWIND: ;SET WINDOW TO SELECTED WINDOW NUMBER ;ENTRY ;C = WINDOW NUMBER (IN ASCII) ;EXIT ;CURRENT WINDOW SET TO WINDOW NUMBER ;CURSOR POSITIONED TO HOME POSITION OF NEW WINDOW LD A,C SUB '0' AND 0FH ;GET NUMBER MOD 16 CALL GETWIND ;GET HL = ADDRESS OF WINDOW DEFINITION LD DE,CURWIND ;CURRENT WINDOW DEFINITION LD BC,4 LDIR ;MOVE SELECTED WINDOW TO CURRENT WINDOW JP VC_HOME ;INITIALIZE CURSOR TO HOME POSITION OF WINDOW PAGE GETWIND: ;GET ADDRESS OF GIVEN WINDOW DEFINITION ;ENTRY ;A = WINDOW NUMBER ;EXIT ;HL = ADDRESS OF WINDOW DEFINITION ;BC PRESERVED LD HL,WINDDEFS ;START ADDRESS OF WINDOW DEFINITIONS  ADD A,A ;A * 2 ADD A,A ;A * 4 LD E,A LD D,0 ;DE = WINDOW NUMBER * 4 (EACH DEFINITION IS 4 BYTES) ADD HL,DE ;HL = ADDRESS OF WINDOW DEFINITION RET PAGE ; ********************************************************* ; * * ; * MISCELLANEOUS CONSOLE ROUTINES * ; * * ; ********************************************************* SEQERR: ;HANDLE ILLEGAL SEQUENCE (EG UNDEFINED ESC SEQUENCE) ;IGNORE SEQUENCE, SET TABLE ADDRESS BACK TO BASTBL AND PROCESS CURRENT CHARACTER NORMALLY ;ENTRY ;C = CHARACTER ;EXIT ;NONE JP LOOKUPB ;PROCESS CHARACTER NORMALLY RETPROC: ;PROCEDURE WHICH ONLY RETURNS ;USED FOR BRANCH ADDRESSES FOR CONSOLE TABLE ENTRIES WHICH DON'T NEED TO ;DO ANYTHING ;ENTRY ;NONE ;EXIT ;NONE RET PAGE DISPLAY: ;DISPLAY CHARACTER AT CURSOR POSITION ;ENTRY ;A = CHARACTER ;EXIT ;NONE LD HL,(CURPOS) ;HL = CURRENT CURSOR POSITION ;DISPLAY NEW CHARACTER LD (HL),A ;STORE CHARACTER ;GET SELECTED ATTRIBUTES LD A,(BACKGND) ;A = BACKGROUND ATTRIBUTES AND 0F8H ;MAKE SURE ONLY BACKGROUND ATTRIBUTE BITS ARE SET LD C,A ;C = BACKGROUND ATTRIBUTES LD A,(CFLAG) ;A = CURRENT ESC SEQUENCE ATTRIBUTES XOR C ;GET NET ATTRIBUTES LD C,A ;C = SELECTED ATTRIBUTES JP SET_ATR ;STORE ATTRIBUTES PAGE DIST2EOL: ;CALCULATE #CHRS TO BETWEEN GIVEN ADDRESS AND LAST COLUMN IN LINE ;ENTRY ;HL = ADDRESS ;EXIT ;BC = # CHARACTERS BETWEEN ADDRESS AND LAST COLUMN ;A = # CHARACTERS BETWEEN ADDRESS AND LAST COLUMN ;Z BIT SET IF 0 CHARACTERS (IE ADDRESS IS AT END OF LINE) ;HL SAVED PUSH HL CALL GETCOL ;GET COLUMN LD C,A ;C = COLUMN LD A,(WINDCOLS) ;A = LINE LENGTH DEC A ;A = LAST COLUMN IN LINE SUB C ;A = #CHRS BETWEEN ADDRESS AND LAST COLUMN LD C,A LD B,0 ;BC = #CHRS BETWEEN ADDRESS AND LAST COLUMN POP HL RET PAGE DIST2LASTROW: ;CALCULATE NUMBER OF ROWS BETWEEN GIVEN POSITION AND LAST LINE OF VIDEO ;ENTRY ;HL = GIVEN POSITION ;EXIT ;A = # OF ROWS FROM GIVEN POSITION TO BEGINNING OF LAST LINE ;FLAGS SET: Z IF GIVEN POSITION ON LAST LINE ; C IF GIVEN POSITION PAST LAST LINE CALL GETROW LD C,A ;C = CURSOR ROW LD A,(WINDROWS) DEC A ;A = LAST ROW SUB C RET ;A = # OF ROWS BETWEEN CURSOR AND LAST ROW PAGE ; ********************************************************* ; * * ; * MISCELLANEOUS ROUTINES * ; * * ; ********************************************************* NOTE: ;PLAY NOTE ;ENTRY ;HL = FREQUENCY (TIME FOR 1/2 PERIOD (IN MICROSEC)) ;DE = DURATION (NUMBER OF WAVES) ;EXIT ;NOTE PLAYED ;DISABLE 60HZ INTERRUPT CALL GET_INT ;GET INTERRUPT STATE PUSH BC ;SAVE IT LD A,B ;MOVE CURRENT STATE TO A AND 0EFH ;DISABLE 60HZ INTERRUPT LD B,A CALL SET_INT ;DISABLE 60HZ INTERRUPT ;PLAY NOTE LD BC,-6 ;# OF MICROSECONDS IN HI/LOW LOOPS LOOP: IN A,(SYS_DTB) ;[3.75] OR SPEAKER ;[1.75] SET OUTPUT TO +5V OUT (SYS_DTB),A ;[3.50] PUSH HL ;[2.75] SAVE DURATION (# OF MICROSECS IN 1/2 PERIOD) XJ070: ADD HL,BC ;[2.75] SUBTRACT # OF MICROSECS IN LOOP JR C,XJ070 ;[3.00] LOOP AGAIN IF MORE MICROSECS LEFT POP HL ;[2.50] RESTORE DURATION (# OF MICROSECS IN 1/2 PERIOD) IN A,(SYS_DTB) ;[3.75] AND NOT SPEAKER ;[1.75] SET OUTPUT TO 0V OUT (SYS_DTB),A ;[3.50] PUSH HL ;[2.75] SAVE DURATION XJ071: ADD HL,BC ;[2.75] SUBTRACT # OF MICROSECS IN LOOP JR C,XJ071 ;[3.00] LOOP AGAIN IF MORE MICROSECS LEFT POP HL ;[2.50] RESTORE DURATION DEC DE ;[1.50] LD A,D ;[1.00] OR E ;[1.00] JR NZ,LOOP ;[3.00] LOOP IF MORE WAVES ;RESTORE 60HZ INTERRUPT POP BC ;RESTORE OLD INTERRUPT STATE JP SET_INT PAGE ; ********************************************************* ; * * ; * CONSOLE ROUTINES CONSTANTS * ; * * ; ********************************************************* ;BIT DEFINITIONS FOR CFLAG FLAG BYTE ; +---+---+---+---++---+---+---+---+ ; | 7 | 6 | 5 | 4 || 3 | 2 | 1 | 0  A | ; +---+---+---+---++---+---+---+---+ ; | | | | | | | | ;REVERSE VIDEO <------------------+ | | | | | | | ;HALF INTENSITY <---------------------+ | | | | | | ;UNDERLINE <------------------------------+ | | | | | ;BLINK VIDEO <--------------------------------+ | | | | ; | | | | ;ALTERNATE CHARACTER SET <-------------------------+ | | | ;GRAPHICS <--------------------------------------------+ | | ;NOT USED <------------------------------------------------+ | ;NOT USED <----------------------------------------------------+ REV_FLG EQU 80H ;REVERSE VIDEO MODE HAF_FLG EQU 40H ;HALF INTENSITY MODE UN_FLG EQU 20H ;UNDERLINE MODE BNK_FLG EQU 10H ;BLINK VIDEO MODE ALT_FLG EQU 08H ;ALTERNATE CHARACTER SET GR_FLG EQU 04H ;GRAPHICS MODE ATR_MSK EQU 0FCH ;MASK TO GET ATTRIBUTES CLATR_MSK EQU 0FH ;MASK TO CLEAR TOP 4 ATTRIBUTES PAGE ; ********************************************************* ; * * ; * CONSOLE ROUTINES VARIABLES * ; * * ; ********************************************************* ;CONSOLE TABLES BASET: ;BASE TABLE -- USED TO LOOK UP THE FIRST CHARACTER IN A SEQUENCE ;THE TABLE LISTS CHARACTERS AND PROCEDURES TO BRANCH TO TO PROCESS THE CHARACTER ;1ST BYTE OF TABLE IS NUMBER OF ENTRIES ;ENTRIES ARE 4 BYTES LONG: ; 1ST BYTE = MATCH CODE ; 2ND BYTE = NEXT TABLE NUMBER ; 3RD, 4TH BYTES = BRANCH ADDRESS ;THE LAST ENTRY IS A 3-BYTE "NO MATCH" DEFAULT NEXT TABLE AND BRANCH ADDRESS DB BASSIZ ;NUMBER OF ENTRIES IN BASE TABLE ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ DB ESC DB ESCNUM DW RETPROC ;ESC SEQUENCE JX01: DB BASNUM DW PROCNORM ;NO MATCH ;-- PROCESS NORMAL 1 CHARACTER LONG "SEQUENCE" BASSIZ EQU (JX01-BASET + 1)/4 ;NUMBER OF ENTRIES IN BAST PAGE ESCT: ;VALID ESC-SEQUENCE TABLE ;1ST BYTE IS NUMBER OF ENTRIES ;4 BYTES PER ENTRY: ASCII CHAR, NEXT TABLE NUMBER, BRANCH ADDRESS ;FOLLOWING BODY OF TABLE IS 3 BYTE NO-MATCH DEFAULT NEXT TABLE AND BRANCH ADRS DB ESCSIZ ;NUMBER OF BYTES ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ DB VSAL DB BASNUM DW ESCSAL ;SET ALTERNATE CHARACTER SET DB VEAL DB BASNUM DW ESCCAL ;CLEAR ALTERNATE CHARACTER SET DB VSHI DB BASNUM DW ESCSHI ;SET HALF INTENSITY MODE DB VEHI DB BASNUM DW ESCEHI ;CLEAR HALF INTENSITY MODE DB VSGH DB BASNUM DW ESCSGR ;SET GRAPHICS MODE DB VEGH DB BASNUM DW ESCCGR ;CLR GRAPHICS MODE DB VCAD DB YNUM DW RETPROC ;CURSOR ADDRESSING DB 'Z' DB BASNUM DW ESCZZ ;CLEAR SCREEN TO BLANKS DB VINC DB BASNUM DW EINSRT ;INSERT CHAR DB VDELC DB BASNUM DW EDELC ;DELETE CHAR DB VINL  DB BASNUM DW ESCEE ;INSERT LINE DB VDELL DB BASNUM DW ESCRR ;DELETE LINE DB VCEOL DB BASNUM DW EEOL ;CLEAR TO END OF LINE DB VLOCK DB BASNUM DW ESC_LCK ;LOCK KEYBOARD DB VUNLK DB BASNUM DW ESC_ULK ;UNLOCK KEYBOARD DB VCEOS DB BASNUM DW EEOS ;CLEAR TO END OF SCREEN (WINDOW) DB VWDEF DB WDEFNUM DW RETPROC ;DEFINE A WINDOW DB VWSET DB WSETNUM DW RETPROC ;SET WINDOW DB VCTYP DB CTYPNUM DW RETPROC ;DEFINE CURSOR TYPE DB VOFF DB OFFNUM DW RETPROC ;DEFINE X-Y OFFSET DB VRON DB BASNUM DW REVON ;SET REVERSE VIDEO BACKGROUND DB VROFF DB BASNUM DW REVOFF ;SET NORMAL VIDEO BACKGROUND DB VBACK DB BACKNUM DW RETPROC ;DEFINE BACKGROUND ATTRIBUTES DB VSRV DB BASNUM DW ESCSRV ;START REVERSE VIDEO DB VERV DB BASNUM DW ESCCRV ;END REVERSE VIDEO DB VSUL DB BASNUM DW ESCSUN ;START UNDERLINE DB VEUL DB BASNUM DW ESCCUN ;END UNDERLINE DB VSBL DB BASNUM DW ESCSBL ;START BLINK DB VEBL DB BASNUM DW ESCCBL ;END BLINK DB EKC DB BASNUM DW ESCSKK ;ENABLE KEY CLICK DB DKC DB BASNUM DW ESCCKK ;DISABLE KEY CLICK DB EFKT DB BASNUM DW ESCEFT ;ENABLE FUNCTION KEY TRANSLATION DB DFKT DB BASNUM DW ESCDFT ;DISABLE FUNCTION KEY TRANSLATION JX02: DB BASNUM DW SEQERR ;NO MATCH EXIT ESCSIZ EQU (JX02-ESCT+1)/4 ;# OF ENTRIES IN TABLE PAGE CTLT: ;VALID CONTROL CHARACTER TABLE ;1ST BYTE IS NUMBER OF BYTES IN TABLE ;5 BYTES PER ENTRY: ASCII CHAR, NEXT TABLE ADDRESS, BRANCH ADDRESS ;FOLLOWING BODY OF TABLE IS 4 BYTE DEFAULT NEXT TABLE AND BRANCH ADRS DB CTLSIZ ;# ENTRIES IN TABLE ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ DB CR DB BASNUM DW VC_CR ;CARRIAGE RETURN ROUTINE DB LF DB BASNUM  A DW VC_LF ;LINE FEED DB BKS DB BASNUM DW VC_BKS ;BACK SPACE DB MCRIGH DB BASNUM DW VC_MCRT ;MOVE CURSOR RIGHT DB MCUP DB BASNUM DW VC_MCUP ;MOVE CURSOR UP DB VDWN DB BASNUM DW VC_MCDOWN ;MOVE CURSOR DOWN DB CBELL DB BASNUM DW VC_BEL ;RING BELL DB VLIN DB BASNUM DW VC_NEWLINE ;NEW LINE (CR,LF) DB VCLRS DB BASNUM DW VC_CLRS ;CLEAR SCREEN DB VHOME DB BASNUM DW VC_HOME ;CURSOR HOME JX03: DB BASNUM DW RETPROC ;NO MATCH ;--IGNORE UNDEF CONTROL CHAR AND GO ; BACK TO BASE TABLE CTLSIZ EQU (JX03-CTLT+1)/4 ;NUMBER OF VALID ENTRIES PAGE YTAB: ;Y COORDINATE TABLE. ONLY DEFAULT ENTRY SINCE ALL VALUES GO TO THE SAME PROCEDURE DB 0 ;NUMBER OF ENTRIES ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ DB XNUM DW YCOORD ;"NO MATCH" XTAB: ;X COORDINATE TABLE. ONLY DEFAULT ENTRY SINCE ALL VALUES GO TO THE SAME PROCEDURE DB 0 ;NUMBER OF ENTRIES ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ DB BASNUM DW XCOORD ;"NO MATCH" PAGE BACKT: ;BACKGROUND ATTRIBUTE TABLE DB BACKSIZ ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ JX04: DB BASNUM DW NEW_BACK ;SET BACKGROUND ATTRIBUTES BACKSIZ EQU (JX04-BACKT+1)/4 PAGE WDEFT: ;WINDOW DEFINE TABLE ;(THIS LEVEL IN THE WINDOW DEFINITION SEQUENCE GETS THE WINDOW NUMBER TO DEFINE) DB WDEFSIZ ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ JX05: DB FROWNUM DW DEF_WINDOW ;GET WINDOW NUMBER WDEFSIZ EQU (JX05-WDEFT+1)/4 PAGE FROWT: ;DEFINE FIRST ROW OF WINDOW DB FROWSIZ ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ JX06: DB FCOLNUM DW STARTROW ;DEFINE FIRST ROW OF WINDOW FROWSIZ EQU (JX06-FROWT+1)/4 FCOLT: ;DEFINE FIRST COLUMN OF WINDOW DB FCOLSIZ ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ JX07: DB LROWNUM DW STARTCOL ;DEFINE FIRST COLUMN OF WINDOW FCOLSIZ EQU (JX07-FCOLT+1)/4 PAGE LROWT: ;DEFINE LAST ROW OF WINDOW DB LROWSIZ ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ JX08: DB LCOLNUM DW ENDROW ;DEFINE LAST ROW OF WINDOW LROWSIZ EQU (JX08-LROWT+1)/4 LCOLT: ;DEFINE LAST COLUMN OF WINDOW DB LCOLSIZ ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ JX09: DB BASNUM DW ENDCOL ;DEFINE LAST COLUMN OF WINDOW LCOLSIZ EQU (JX09-LCOLT+1)/4 PAGE WSETT: ;WINDOW SET DB WSETSIZ ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ JX10: DB BASNUM DW SETWIND ;SET CURRENT WINDOW ;TO SELECTED NUMBER WSETSIZ EQU (JX10-WSETT+1)/4 PAGE CTYPT: ;CURSOR TYPE DB CTYPSIZ ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ JX11: DB BASNUM DW DEFCUR ;DEFINE CURSOR TYPE CTYPSIZ EQU (JX11-CTYPT+1)/4 PAGE OFFT: ;SET X OFFSET DB OFFSIZ ; +----------------------------------------------+ ; |  CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ JX12: DB BASNUM DW SETOFF ;SET X-Y OFFSET OFFSIZ EQU (JX12-OFFT+1)/4 ;CONSOLE TABLE NUMBERS BASNUM EQU 1 ;BASE TABLE NUMBER ESCNUM EQU 2 ;ESCAPE TABLE NUMBER CTLNUM EQU 3 ;CONTROL TABLE NUMBER YNUM EQU 4 ;Y COORDINATE TABLE NUMBER XNUM EQU 5 ;X COORDINATE TABLE NUMBER WDEFNUM EQU 6 ;WINDOW DEFINITION TABLE NUMBER FROWNUM EQU 7 ; FIRST ROW TABLE NUMBER FCOLNUM EQU 8 ; FIRST COLUMN TABLE NUMBER LROWNUM EQU 9 ; LAST ROW TABLE NUMBER LCOLNUM EQU 10 ; LAST COLUMN TABLE NUMBER WSETNUM EQU 11 ;WINDOW SET TABLE NUMBER CTYPNUM EQU 12 ;CURSOR TYPE TABLE NUMBER OFFNUM EQU 13 ;X OFFSET TABLE NUMBER BACKNUM EQU 14 ;Y OFFSET TABLE NUMBER PAGE ; ********************************************************* ; * * ; * CONSOLE TABLE POINTERS * ; * * ; ********************************************************* ;CONSOLE TABLE POINTERA STRUCTURE CTBLPTRS: DW BASET ;CURRENT TABLE TO BE SEARCHED ;INITIALLY SEARCH THE BASE TABLE ;TABLE POINTERS DW BASET ; BASE TABLE DW ESCT ; ESCAPE TABLE DW CTLT ; CONTROL TABLE DW YTAB ; Y-COORDINATE TABLE DW XTAB ; X-COORDINATE TABLE DW WDEFT ; WINDOW DEFINE TABLE DW FROWT ; FIRST ROW OF WINDOW (FOR WINDOW DEFINE) DW FCOLT ; FIRST COLUMN OF WINDOW DW LROWT ; LAST ROW OF WINDOW DW LCOLT ; LAST COLUMN OF WINDOW DW WSETT ; WINDOW SET TABLE DW CTYPT ; CURSOR TYPE DEFINITION TABLE DW OFFT ; X-Y OFFSET TABLE DW BACKT ; BACKGROUND ATTRIBUTE DEFINITION TABLE LENCTBL EQU $-CTBLPTRS EQU 14 ;Y OFFSET TABLE NUMBER PAGE ; ********************************************************* ; * * ; * CONSOLE TABLE POINTERS * ; * * ; ********************************************************* ;CONSOLE TABLE POINTER SUBTTL 'KEYBOARD ROUTINES' ; ********************************************************* ; * * ; * KEYBOARD ROUTINES * ; * * ; ********************************************************* ; ; MODULE 3 --ROM3-- ENTRY POINTS ; ; KEYBOARD ROUTINES ; ; KBDRVR: DETECT AND PROCESS KEYSTROKES ; REMOVEKEY: REMOVE ENTRY FROM KEYLIST ; CKSERV: CHECK FOR TIME-OUT ON KEYLIST ENTRY ; KBSCAN: SCAN THE KEYBOARD FOR DEPRESSED KEYS ; CHKEY: CHECKS IF KEY NUMBER IS ON ; GTMASK: GENERATES AN 8 BIT MASK WITH 1 BIT SET ; RDROW: READS ROWS OF KEYS ; KBSERV: SERVICE KEYLIST ENTRY ; SAVEKEY: SEND CHAR. FROM KEYBOARD TO BIOS PAGE .Z80 ; .XLIST ; INCLUDE SYSS1.MAC ;SYSTEST FILE ; INCLUDE RAMSMON.MAC ;MONITOR RAM MEMORY LOCATIONS ; INCLUDE RAMS10.MAC ;RAM MEMORY LOCATIONS AND CONSTANTS ; .LIST ; ;SYSS1.MAC , RAMSMON.MAC AND RAMS10.MAC INCLUDED ; EXT AL_T_SZ,FL_B_ST,FL_B_CH,ALT_FLG ; PUBLIC KBDRVR CSEG PAGE KBDRVR: ;DETECTS AND PROCESSES KEYSTROKES. ; MODIFIED TO PROCESS KEY ROLLOVER LIKE THE TELEVIDEO 9XX SERIES. ;ENTRY ;NONE ;EXIT ;LKEY = KEYSTROKE ; ANY VALID KEYSTROKES ARE TRANSLATED BY KBSERV AND SENT TO THE ; BIOS BY SAVEKEY. ; ; CALL KBSCAN ;SCAN KEYBOARD FOR LATCHED KEYS AND ;PLACE KEYS IN KEYLIST ; ; CHECK FOR ANY KEYS IN THE KEY LIST. IF THE FIRST KEYLIST ENTRY ; IS EMPTY, THEN THERE ARE NO KEYS IN LIST ; LD HL,FIRSTKEY ;POINT AT FIRST KEYLIST ENTRY LD A,(HL) ;GET KEY LIST ENTRY BIT KL_USED,A ;SEE IF ENTRY USED BIT IS SET RET Z ;NO...KEYLIST ENTRY: RETURN ; ; NOW SEE IF KEYS IN LIST ARE STILL DOWN ; CKEYSDN: LD B,KL_LEN ;SET LOOP COUNTER TO NUMBER OF KEYS IN ;LIST. HL POINTS TO FIRST ENTRY, A ;CONTAINS FIRST KEY ENTRY CKLP: BIT KL_USED,A ;IS THIS KEYLIST ENTRY IN USE? JR Z,ENDCK ;NO...NO MORE ENTRIES TO CHECK ; ; KEYLIST ENTRY NOT EMPTY: IS THE KEY STILL DOWN? ; PUSH BC ;SAVE LOOP COUNTER OVER CALL TO CHKEY AND KROW_M+KCOL_M ;MASK OFF ALL BITS EXCEPT ROW & COL NO. CALL CHKEY ;CALL CHKEY TO SEE IF KEY IN A IS STILL ;DOWN POP BC ;RESTORE LOOP COUNTER JR NZ,KEYON ;Z SET IF KEY OFF... ; PUSH BC ;SAVE LOOP COUNTER PUSH HL ;SAVE POINTER TO CURRENT LIST ENTRY CALL REMOVEKEY ;REMOVE KEY FROM LIST. NEXT KEY (IF ANY) ;IS NOW IN CURRENT SLOT, SINCE REMOVEKEY ;MOVES EVERYTHING DOWN ONE SLOT. POP HL ;RESTORE PTR TO KEY LIST ENTRY POP BC ;RESTORE LOOP COUNTER LD A,1 ;SET A TO VALUE B SHOULD BE IF THIS IS ;THE LAST ENTRY CP B ;COMPARE A WITH B. IS THIS THE LAST ;ENTRY? JR Z,ENDCK ;YES... ; LD A,(HL) ;NO. MORE TO CHECK. LOAD NEXT KEY, NOW ;IN CURRENT SLOT JR CKLP ;AND CHECK THIS KEY. ; KEYON: ;KEY IS ON: GO TO NEXT KEY, IF ANY. INC HL ;BUMP HL TWICE TO POINT TO NEXT ENTRY INC HL LD A,(HL) ;LOAD KEY POINTED TO BY HL DEC B ;DECREMENT LOOP COUNTER. ARE WE ALL ;DONE? JR NZ,CKLP ;NO... CONTINUE ; ENDCK: ;ALL KEYS IN LIST HAVE BEEN CHECKED TO ;SEE IF THEY'RE STILL DOWN. ; ; NOW SEE IF THERE ARE STILL KEYS IN LIST (I.E., IF THERE ARE ; STILL ANY DOWN. ; LD HL,FIRSTKEY ;POINT TO FIRST KEYLIST ENTRY BIT KL_USED,(HL) ;IS IT IN USE? RET Z ;NO. NO FIRST KEY IMPLIES NO KEYS AT ;ALL. RETURN. ; ; NOW SEE IF THE USER HAS MORE THAN TWO KEYS JAMMED DOWN AT ONCE. ; ALPHA LOCK, CTRL AND SHIFT NOTWITHSTANDING. MORE THAN TWO KEYS ; AND WE DON'T DO ANYTHING, JUST LIKE THE TVIS. ; LD HL,SECONDKEY+2 ;POINT TO KEY AFTER SECOND LD A,(HL) ;GET IT. BIT KL_USED,A ;IS IT IN USE? RET NZ ;YES. MORE THAN TWO KEYS DOWN. RETURN. ; ; ONLY ONE OR TWO KEYS DOWN. SEE IF IT'S TWO. ; LD HL,SECONDKEY ;POINT AT SECOND KEYLIST ENTRY BIT KL_USED,(HL) ;IS THERE A SECOND KEY IN THE LIST? JR Z,CHECK1ST ;NO. CHECK FIRST KEY ; ;TWO KEYS DOWN. SEE IT IT'S TIME TO ;SERVICE THE SECOND KEY. PUSH HL ;SAVE POINTER TO KEYLIST ENTRY AROUND ;CALL CALL CKSERV ;CHECK KEYLIST ENTRY POINTED TO BY HL ;FOR SERVICE TIMEOUT. CARRY SET IF TIME ;TO SERVICE. POP HL ;RESTORE PTR TO ENTRY ; ARET NC ;NOT TIME TO SERVICE KEY. RETURN. ; CALL SERVKEY ;SERVICE KEY POINTED TO BY HL. IF KEY BAD, Z FLAG SET. ; RET NZ ;RETURN IF KEY SENT TO BIOS ; LD HL,FIRSTKEY ;SECOND KEY BAD, SEND FIRST KEY JP SERVKEY ; CHECK1ST: ;AS THERE IS NO SECOND KEY DOWN OR IT IS ;TIMED OUT OR BAD, CHECK FIRST KEY IN LIST. LD HL,FIRSTKEY ;POINT AT FIRST KEYLIST ENTRY PUSH HL ;SAVE PTR CALL CKSERV ;IS IT TIME TO SERVICE? POP HL ;RESTORE PTR RET NC ;NO: CARRY CLEAR, NOT TIME TO SERVICE. ;RETURN... ; SERVKEY: ;SERVICE KEY POINTED TO BY HL CALL KBSERV RET ;AND RETURN PAGE REMOVEKEY: ; REMOVE KEYLIST ENTRY POINTED TO BY HL FROM KEYLIST ;ENTRY: ; HL ==> KEYLIST ENTRY TO DELETE. ; ;EXIT: ; ALL FOLLOWING ENTRIES IN KEYLIST (IF ANY) ARE SHIFTED DOWN ; ONE SLOT. ; IF THERE ARE NO FOLLOWING ENTRIES IN THE KEYLIST, THE ENTRY ; POINTED TO IS SIMPLY ZEROED. ; PUSH HL ;SAVE POINTER TO ENTRY TO DELETE LD DE,LASTKEY ;LOAD ADDRESS OF LAST KEY IN LIST EX DE,HL ;SWAP HL AND DE SO SUBSEQUENT SUBTRACT ;OPERATION WILL RETURN THE NUMBER OF ;CELLS TO MOVE OR ZERO IF CURRENT ENTRY ;IS LAST. SCF ;CLEAR CARRY SO DOUBLE PRECISION CCF ;SUBTRACT WITH CARRY CAN BE USED SBC HL,DE ;SUBTRACT ADDRESS OF ENTRY TO DELETE ;FROM ADDRESS OF LAST ENTRY IN LIST. ;IF ZERO SET THE ENTRY TO DELETE IS THE ;LAST IN THE LIST, ELSE HL CONTAINS THE ;NUMBER OF BYTES TO MOVE. LD B,H ;MOVE RESULT TO BC TO SET UP FOR LDIR LD C,L ; POP DE ;RESTORE POINTER TO DE FOR LDIR JR Z,DELLAST ;IF PREVIOUS SUBTRACT RESULTED IN ZERO, ;ENTRY TO DELETE IS LAST IN LIST AND ;THE ONLY ACTION TO TAKE IS TO DELETE ;THE LAST LIST ENTRY. LD H,D ;COPY POINTER TO ENTRY TO DELETE TO HL LD L,E ; INC HL ;BUMP HL TO POINT TO NEXT ENTRY INC HL ; LDIR ;DO BLOCK MOVE: MOVE ENTRIES FOLLOWING ;ENTRY TO DELETE DOWN INTO ENTRY TO  ;DELETE DELLAST: ;FINALLY, CLEAR LAST LIST ENTRY. LD HL,LASTKEY ;POINT TO LAST KEY LIST ENTRY LD (HL),0 ;CLEAR FIRST BYTE OF ENTRY INC HL ;POINT TO SECOND BYTE LD (HL),0 ;CLEAR IT TO. RET ;AND RETURN PAGE CKSERV: ; ROUTINE TO CHECK FOR TIME OUT ON KEY LIST ENTRY. ;ENTRY: ; HL ==> ENTRY TO CHECK FOR TIME OUT. ; ;EXIT: ; CARRY FLAG SET IF TIME TO SERVICE KEY LIST ENTRY. ; ADDITIONALLY, IF IT IS NOT TIME TO SERVICE THE KEY, THE TIME OUT ; COUNTER OF THE LIST ENTRY IS DECREMENTED. IF IT IS TIME TO ; SERVICE THE KEY, THE COUNTER IS RE-INITIALIZED. THE VALUE ; IT IS SET TO DEPENDS ON WHETHER THE KEY HAS SERVICED ALREADY. ; IF IT HASN'T, THE COUNTER IS SET TO A VALUE WHICH CAUSES A ; SLIGHT DELAY BEFORE THE KEY BEGINS TO REPEAT. ; OTHERWISE, THE KEY HAS ALREADY BEGUN TO REPEAT, SO THE COUNTER ; IS SET TO A SMALLER VALUE ASSOCIATED WITH THE RAPIDITY WITH ; WHICH THE KEY REPEATS. ; HL = VALUE ON ENTRY. ; INC HL ;INCREMENT HL TO POINT TO LIST ENTRY ;REPEAT COUNT DEC (HL) ;DECREMENT REPEAT COUNT DEC HL ;DECREMENT HL TO POINT BACK TO KEY. JR NZ,NOSERV ;REPEAT COUNT NOT ZERO; NOT TIME TO ;SERVICE KEY ; BIT KY_SRVD,(HL) ;KEY READY TO SERVICE. HAS IT BEEN ;SERVICED BEFORE? JR NZ,SRVDLRDY ;YES... ; SET KY_SRVD,(HL) ;NO. SET SERVICED ALREADY BIT FLAG IN ;KEYLIST ENTRY INC HL ;POINT TO KEYLIST ENTRY REPEAT COUNT. LD (HL),IRPTCT ;INITIALIZE REPEAT COUNT TO DELAY BEFORE ;KEY SHOULD START REPEATING JR XJ080 ;AND EXIT WITH CARRY SET AND HL POINTING ;TO LIST ENTRY SRVDLRDY: ;NOT FIRST TIME KEY HAS BEEN SERVED INC HL ;POINT TO ENTRY REPEAT COUNT LD (HL),SRPTCT ;INITIALIZE REPEAT COUNTER TO DELAY ;BEFORE KEY SHOULD REPEAT AGAIN ; XJ080: ;RESTORE HL TO INITIAL ENTRY VALUE AND ;SET CARRY FLAG DENOTING IT IS TIME TO ;SERVICE KEY. DEC HL ;DECREMENT HL TO POINT TO KEY LIST ENTRY SCF ;SET CARRY FLAG RET ;AND RETURN ; NOSERV: ;NOT TIME TO SERVICE KEY. CLEAR CARRY SCF ;TO CLEAR, SET CARRY CCF ;AND COMPLEMENT RET ;AND RETURN PAGE KBSCAN: ; ; ENTRY: ; NONE ; ; EXIT: ; KEYLST = CONTAINS ANY KEYS DETECTED. ; ; REGISTER USAGE: ; ; A = TEMPORARY ; B = KEYBOARD ROW COUNTER ; C = KEYBOARD COLUMN COUNTER ; D = ROW BIT MASK ; E = TEMPORARY ; HL = TEMPORARY POINTER ; LD A,0FFH ;SEE IF ANY KEYS ARE DOWN. CALL RDROW RET Z ;NO KEYS DOWN, RETURN. ; LD HL,K_MSK_TBL ;POINT HL AT TABLE OF KEYBOARD ROW MASK BYTES PUSH HL ;SAVE PTR LD B,TOT_ROW ;INIT ROW COUNTER LD D,1 ;INIT ROW BIT MASK ; XJ081: ;SCAN CURRENT ROW LD A,D ;PUT ROW MASK IN A TO READ ROW CALL RDROW ;READ ROW POP HL ;RESTORE POINTER TO CURRENT ROW MASK AND (HL) ;AND KEY MASK RETURNED BY RDROW WITH TABLE MASK INC HL ;BUMP ROW MASK PTR TO NEXT PUSH HL ;SAVE POINTER ; JP Z,XJ082 ; Z FALAG SET IF NO KEYS DOWN ; LD C,TOT_COL-1 ;INIT COLUMN COUNTER XJ083: ;CHECK FOR KEY DOWN IN CURRENT COLUMN SLA A ;ROTATE MASK IN A INTO CARRY FLAG JP NC,XJ084 ; CARRY SET IF KEY DOWN PAGE ;KEY DOWN. B = ROW, C = COLUMN PUSH DE ;SAVE ROW BIT MASK PUSH AF ;AND COLUMN BIT MASK AROUND KEY SAVE LD A,TOT_ROW ;TRANSFORM ROW & COL # INTO BITS 0-5 OF A SUB B ;GET RELATIVE-0 ROW # TO A RLA ;SHIFT ROW # TO BITS 3, 4 & 5 RLA RLA OR C ;OR COL # INTO BITS 0, 1 & 2 LD D,A ;PUT ROW & COL IN D LD E,KL_LEN ;INIT KEY LIST ENTRY COUNTER LD HL,FIRSTKEY ;POINT HL AT FIRST KEY LIST ENTRY XJ085: ;IS CURRENT KEY LIST ENTRY FREE? BIT 7,(HL) ;CHECK ENTRY IN USE BIT. JP Z,XJ086 ; ; ;THIS ENTRY NOT FREE. ;IS THIS ENTRY SAME AS KEY WE'RE TRYING TO ;SAVE? LD A,(HL) ;GET KEY FROM LIST AND KROW_M+KCOL_M ;STRIP OFF FLAG BITS CP D ;SAME AS ROW/COL # IN D? JP Z,XJ087 ; YES: KEY ALREADY IN LIST ; ;KEY NOT IN THIS LIST ENTRY. CHECK NEXT ENTRY. DEC E ;DECREMENT KEY LIST ENTRY COUNTER JP Z,XJ088 ; IF ZERO, NO FREE LIST ENTRIES ; ;NOT LAST LIST ENTRY. INC HL ;POINT TO NEXT ENTRY INC HL JP XJ085 ;CHECK NEXT ENTRY ; XJ086: ;FREE LIST ENTRY FOUND. SAVE KEY IN ENTRY. ;HL ==> FREE ENTRY. SET KL_USED,D ;SET ENTRY USED FLAG IN ENTRY IN D LD (HL),D ;SAVE ENTRY IN FREE SLOT IN LIST. INC HL ;POINT AT COUNT FIELD OF ENTRY LD (HL),DB_CT ;SAVE DEBOUNCE COUNT. PAGE XJ087: ;KEY ALREADY IN LIST OR JUST SAVED IN LIST. POP AF ;RESTORE COLUMN BIT MASK FOR CURRENT ROW POP DE ;AND ROW BIT MASK IN D XJ084: ;CURRENT KEY NOT DOWN. ;IS THIS THE LAST KEY IN CURRENT ROW? DEC C ;DECREMENT COLUMN COUNTER JP P,XJ083 ;IF NO BORROW (C POSITIVE), NOT DONE WITH ROW. ; ;DONE WITH CURRENT ROW. XJ082: ;CHECK NEXT ROW SLA D ;SHIFT ROW MASK LEFT TO GET MASK FOR NEXT ROW DEC B ;IS THIS THE LAST ROW? JP NZ,XJ081 ;NO... ; JP XJ092 ;YES, END SCAN ; XJ088: ;NO FREE ENTRIES IN LIST. POP AF ;RESTORE COLUMN BIT MASK FOR CURRENT ROW POP DE ;AND ROW MASK... XJ092: ;LAST ROW CHECKED OR NO MORE ENTRIES IN KEY LIST. POP HL ;RESTORE PTR TO MASK TABLE TO BALANCE STACK RET ;AND RETURN. PAGE CHKEY: ;CHECKS IF KEY NUMBER IS ON. ;ENTRY ;A = KEYNUMBER ;EXIT ;Z CLR = KEY IS ON. ;Z SET = KEY IS OFF. PUSH HL ;SAVE CALLERS HL PUSH AF ;SAVE KEYNUMBER RRA RRA RRA ;RIGHT JUSTIFY ROW NUMBER CALL GTMASK POP AF ;GET KEY NUMBER PUSH DE ;SAVE ROW MASK CALL GTMASK ;GET COL MASK (COL NUM IS IN BITS 0..2) POP HL ;MOVE ROW MASK TO L LD A,L ;RDROW EXPECTS MASK IN A CALL RDROW ;GET ROW OF KEYS ADRSED BY L AND E ;Z IND = VALUE OF KEY POP HL RET PAGE GTMASK: ;GENERATES MASK WITH ONE BIT SET. ;ENTRY ;A = BIT NUMBER (0..7) ;EXIT ;E = MASK LD E,1 AND 7 XJ094: RET Z SLA E DEC A JR XJ094 PAGE RDROW: ;READS ROWS OF KEYS ;ENTRY ;A = ROWS TO READ (EACH BIT INDICATES A ROW) ;EXIT ;A = ROW VALUE ; (A BIT IS SET IF THAT BIT (KEY) IS SELECTED IN ANY OF THE CHOSEN ROWS) IN A,(KEYBD) ;READ SELECTED ROW XOR 0FFH ;INVERT VALUES RET PAGE KBSERV: ; ROUTINE TO SERVICE KEY LIST ENTRY. ;ENTRY: ; HL ==> KEY LIST ENTRY TO SERVICE. ;EXIT: ; NONE. ; ; CT_BIT EQU 0 ;TEST SH_BIT EQU 1 ;TEST AL_BIT EQU 2 ;TEST ; LD A,(HL) ;GET KEYLIST ENTRY POINTED TO BY HL. AND KROW_M+KCOL_M ;MASK TO LEAVE ONLY COLUMN AND ROW ;NUMBER BITS. PUSH AF ;SAVE KEY LIST ENTRY ; ; GET STATUS OF CTRL, SHIFT AND ALPHA LOCK KEYS. ; LD L,0 ;CLEAR L. BITS CORRESPONDING TO SHIFT-TYPE KEYS ;WILL BE ACCUMULATED THERE. LD A,(CT_KEY) ;GET LOC OF CTRL KEY CALL CHKEY ;IS IT DOWN? JP Z,XJ095 ;NO... ; SET CT_BIT,L ;YES, SET BIT IN L XJ095: LD A,(SH_KEY) ;GET LOC OF SHIFT KEY. CALL CHKEY ;IS IT DOWN? JP Z,XJ096 ;NO... ; SET SH_BIT,L ;YES, SET BIT IN L XJ096: LD A,(AL_KEY) ;GET LOC OF ALPHA LOCK. CALL CHKEY ;IS IT DOWN? JP Z,XJ097 ;NO... ; SET AL_BIT,L ;YES, SET BIT IN L XJ097: ; ; L NOW CONTAINS SHIFT, CTRL AND ALPHA LOCK. ; THUS WE CAN NOW CHECK FOR THESE KEYS BEING DOWN: ; BIT CT_BIT,L ;IS CTRL DOWN? JR Z,NOCTRL ;NO... ; BIT SH_BIT,L ;YES; IS SHIFT DOWN TOO? JR Z,NOSHCTRL ;NO...ONLY CTRL IS DOWN ; LD DE,4*AL_T_SZ ;CTRL AND SHIFT DOWN. INDICATE THAT ;CURRENT CTRL/SHIFT TABLE IS TO BE USED JR XLATEKEY ;TRANSLATE KEY USING TABLE INDICATED BY ;C ; NOSHCTRL: ;ONLY CTRL DOWN. LD DE,2*AL_T_SZ ;USE CTRL TABLE... JR XLATEKEY ;TO TRANSLATE KEY. ; NOCTRL: ;CTRL NOT DOWN... BIT SH_BIT,L ;IS SHIFT DOWN? JR Z,NOSHIFT ;NO... ; LD DE,1*AL_T_SZ ;YES...USE SHIFT TABLE TO JR XLATEKEY ;TRANSLATE KEY ; NOSHIFT: ;SHIFT NOT DOWN. BIT AL_BIT,L ;IS ALPHA LOCK DOWN? JR Z,NOALPHA ;NO... ; LD DE,3*AL_T_SZ ;YES...USE ALPHA LOCK TABLE TO JR XLATEKEY ;TRANSLATE KEY ; NOALPHA: ;ALPHA LOCAK NOT DOWN. NO 'TRANSLATE' ;KEYS DOWN, SO USE LD DE,0*AL_T_SZ ;'NORMAL' TABLE TO TRANSLATE KEYS ; XLATEKEY: ;TRANSLATE KEYSTROKE ON STACK ACCORDING ;TO THE TABLE WHOSE NUMBER IS IN A ; LD HL,KEYS ;LOAD POINTER TABLE BASE ADD HL,DE ;INDEX TO CORRECT TABLE ENTRY POP AF ;RESTORE KEY NUMBER TO A LD D,0 ;ZERO HI BYTE OF HL TO INDEX INTO ;TRANSLATE TABLE LD E,A ;MOVE KEY NUMBER TO L ADD HL,DE ;ADD BASE ADDRESS OF TABLE TO INDEX LD A,(HL) ;GET TRANSLATED KEYSTROKE FROM TABLE. CP BADKEY ;IS IT AN INVALID KEYSTROKE? (MOST ;LIKELY A BAD CTRL/SHIFT COMBINATION) RET Z ;YES...RETURN WITHOUT SENDING CHAR TO ;BIOS ; CP TOG_ALT_SET ;IS CHAR TOGGLE ALTERNATE CHAR SET COMMAND? JP Z,XJ098 ;YES... ; ;NO, PROCESS AS NORMAL CHAR PUSH AF ;SAVE Z FLAG CALL SAVEKEY ;SEND CHAR TO BIOS POP AF ;RESTORE Z FLAG RET ;AND RETURN PAGE XJ098: ; CHAR RETRIEVED FROM TABLE IS TOGGLE ALTERNATE CHAR SET COMMAND. ; LD A,(CFLAG) ;RETRIEVE CURRENT ATTRIBUTE FLAG BYTE XOR ALT_FLG ;TOGGLE THE ALTERNATE CHAR SET BIT LD (CFLAG),A ;SAVE NEW ATTR BYTE XOR A ;CLEAR Z FLAG TO INDICATE INVALID CHAR RET ;RETURN TO CALLER PAGE SAVEKEY: ; ; ROUTINE TO SEND CHARACTER FROM KEYBOARD TO BIOS. ;ENTRY: ; A = CHAR TO SEND TO BIOS ;EXIT: ; NONE. ; ;TRY TO BUFFER THE CHAR. LD C,A ;PUT CHAR IN C LD B,KBD_DEV ;SPECIFY KEYBOARD DEVICE PUSH BC ;SAVE CALL FL_B_ST ;GET STATUS POP BC RET Z ;IF FULL LD A,(KCLICK) ;IS KEY CLICK FLAG SET? OR A JP Z,XJ099 ;NO... ; ;YES, TOGGLE SPEAKER IN A,(SYS_DTB) ;GET PIA REG WITH SPEAKER TOGGLE OR SPEAKER ;TURN SPEAKER ON OUT (SYS_DTB),A PUSH AF ;SAVE PIA STATE XJ099: CALL FL_B_CH ;PUT CHAR IN LD HL,(D_RT_TBL+D_RT_LEN*KBD_DEV+4) ; BUMP CHAR COUNT INC HL LD (D_RT_TBL+D_RT_LEN*KBD_DEV+4),HL ; AND SAVE IT BACK LD A,(KCLICK) ;IS KEY CLICK FLAG SET? OR A RET Z ;NO...RETURN ; ;YES, TURN SPKR OFF POP AF  ;RESTORE PIA STATE AND NOT SPEAKER ;TURN SPEAKER OFF OUT (SYS_DTB),A RET PAGE ; ********************************************************* ; * * ; * KEYBOARD TABLE EQUATES * ; * * ; ********************************************************* ;KEYBOARD TABLE NUMBERS NM_TB_NO EQU 0 ;NORMAL TABLE NUMBER SH_TB_NO EQU NM_TB_NO + 1 ;SHIFT TABLE NUMBER CT_TB_NO EQU SH_TB_NO + 1 ;CONTROL TABLE NUMBER AL_TB_NO EQU CT_TB_NO + 1 ;ALPHA LOCK TABLE NUMBER CS_TB_NO EQU AL_TB_NO + 1 ;CONTROL SHIFT TABLE NUMBER KTBL_LEN EQU 64 ;LENGTH OF KEYBD XLATE TABLES DTB) ;GET PIA REG WITH SPEAKER TOGGLE OR SPEAKER ;TURN SPEAKER ON OUT (SYS_DTB),A PUSH AF ;SAVE PIA STATE XJ099: CALL FL_B_CH ;PUT CHAR IN LD HL,(D_RT_TBL+D_RT_LEN*KBD_DEV+4) ; BUMP CHAR COUNT INC HL LD (D_RT_TBL+D_RT_LEN*KBD_DEV+4),HL ; AND SAVE IT BACK LD A,(KCLICK) ;IS KEY CLICK FLAG SET? OR A RET Z ;NO...RETURN ; ;YES, TURN SPKR OFF POP AF  SUBTTL 'I/O DRIVERS' ; ; 83-08-01 Fixed parameter passing bug in IE.IDM ; ; ********************************************************* ; * * ; * I / O DRIVERS * ; * * ; ********************************************************* ; ; MODULE 4 --ROM4-- ENTRY POINTS ; ; I / O ROUTINES ; ; IE.CO: CONTROL OUT (BIOS CALL 1) ; IE.SI: STATUS IN (BIOS CALL 2) ; IE.GTS: GO TO STANDBY (BIOS CALL 3) ; IE.TC: TAKE CONTROL (BIOS CALL 4) ; IE.OIM: OUTPUT INTERFACE MESSAGE (BIOS CALL 5) ; IE.ODM: OUTPUT DEVICE MESSAGE (BIOS CALL 6) ; IE.IDM: INPUT DEVICE MESSAGE (BIOS CALL 7) ; IE.PP: PARALLEL POLL (BIOS CALL 8) ; IEINSTAT: GET STATUS OF INPUT DEVICE AT IEEE PORT ; IEINP: INPUT A CHAR. FROM IEEE PORT ; IEOUT: OUTPUT A CHAR. TO IEEE PORT ; CV20P: INITIALIZE TO PARALLEL OUTPUT PORT ; CV2IP: INITIALIZE TO PARALLEL INPUT PORT ; POSTAT: GET STATUS OF OUTPUT DEVICE AT PARALLEL PORT ; PISTAT: GET STATUS OF INPUT DEVICE AT PARALLEL PORT ; PARINP: INPUT A CHAR. FROM PARALLEL PORT ; PAROUT: OUTPUT A CHAR TO PARALLEL PORT ; CTC_INIT: INITIALIZE THE CLOCK-TIMER CHIP ; SIOINIT: INITIALIZE THE SERIAL PORT ; SETBAUD: SET BAUD RATE FOR SERIAL PORT ; SERAIN: INPUT A CHAR. FROM SERIAL PORT A ; SERBIN: INPUT A CHAR. FROM SERIAL PORT B ; SERAOUT: OUTPUT A CHAR. FROM SERIAL PORT A ; SERBOUT: OUTPUT A CHAR. FROM SERIAL PORT B ; SAO_STAT: OUTPUT STATUS FROM SERIAL PORT A ; SAI_STAT: INPUT STATUS FROM SERIAL PORT A ; GET_O_STAT: GET OUTPUT STATUS FROM SERIAL PORT ; GET_I_STAT: GET INPUT STATUS FROM SERIAL PORT ; SETDMA: SET DMA ADDRESS AND BANK PAGE .Z80 ; .XLIST ; INCLUDE SYSS1.MAC ;SYSTEST FILE ; INCLUDE RAMSMON.MAC ;MONITOR RAM MEMORY LOCATIONS ; INCLUDE RAMS10.MAC ;RAM MEMORY LOCATIONS AND CONSTANTS ; .LIST ; ;SYSS1.MAC , RAMSMON.MAC AND RAMS10.MAC INCLUDED ; EXT RM_C_BF,FL_B_CH,FL_B_ST,RM_C_ST ; PUBLIC IE.CO,IE.SI,IE.GTS,IE.TC,IE.OIM,IE.ODM,IE.IDM,IE.PP,IEINSTAT ; PUBLIC IEOSTAT,IEINP,IEOUT,POSTAT,PISTAT,PARINP,PAROUT,CTC_INIT ; PAUBLIC SIOINIT,SETBAUD,SERAIN,SERBIN,SERAOUT,SERBOUT,SAO_STAT,SBO_STAT ; PUBLIC SETDMA,SAI_STAT,SBI_STAT CSEG PAGE ; +---------------------------------------+ ; | ENTERED 05/01/81 FROM TNW XEROX, SEH. | ; +---------------------------------------+ ;LAST EDITED AT 09:29 ON 11 NOV 80 ;THERE ARE FOUR COMMANDS TO THE 6821 ; 00 PERIPHERAL/DIRECTION REGISTER A PAR_DTA ; 01 CONTROL REGISTER A PAR_CNA ; 10 PERIPHERAL/DIRECTION REGISTER B PAR_DTB ; 11 CONTROL REGISTER B PAR_CNB ;BIT 2 OF THE CONTROL REGISTER (A AND B) ALLOWS SELECTION OF EITHER ;A PERIPHERAL INTERFACE REGISTER OR A DATA DIRECTION REGISTER. ;A "1" IN BIT 2 SELECTS THE PERIPHERAL REGISTER. ;THE TWO DATA DIRECTION REGISTERS ALLOW CONTROL OF THE DIRECTION ;OF DATA THROUGH EACH CORRESPONDING PERIPHERAL DATA LINE. ;A DATA DIRECTION REGISTER BIT SET AT "0" CONFIGURES ;THE CORRESPONDING PERIPHERAL DATA LINE AS AN INPUT. ;A RESET AT POWER UP HAS THE EFFECT OF ZEROING ALL PIA REGISTERS. ;THIS WILL SET PA0-PA7, PB0-PB7, CA2, AND CB2 AS INPUTS, ;AND ALL INTERRUPTS DISABLED. ;SIGNALS ATN, REN, AND IFC WILL BE DRIVEN LOW ;UNTIL INITIALIZED BY SOFTWARE. ;DATA DIRECTION IS ALWAYS SET FOR OUTPUT FOR THE DATA REGISTER. ;DATA MUST BE SET TO ALL ONES WHEN INPUTTING. ;THE INTERFACE IS IN SOURCE HANDSHAKE MODE IF DATA ENABLE (PB0) ;IS SET TO "0", AND IN ACCEPTOR HANDSHAKE MODE IF SET TO "1". ;WHEN SWITCHING FROM SOURCE TO ACCEPTOR HANDSHAKE, ;ATN WILL ALWAYS BE LOW. ;TAKE CONTROL CAN ONLY BE CALLED FOLLOWING A GO TO STANDBY. ;AFTER A FATAL ERROR, PERFORM AN IFC RESET. ;STANDARD VALUES USED: ;PAR_CNA 0011(IFC)(DIR)10 ;PAR_CNB 0011(REN)(DIR)00 ;PAR_DTA SOURCE DIRECTION 1111_1111 ; DATA DATA ;PAR_DTA ACCEPTOR DIRECTION 1111_1111 ; DATA 1111_1111 ;PAR_DTB SOURCE DIRECTION 0011_1111 ; DATA 000A_0010 ;A = ATN ;PAR_DTB ACCEPTOR DIRECTION 1101_0111 ; DATA 0100_0101 PAGE ;PIA SIGNAL DEFINITIONS: ;ALL SIGNALS ARE LOW ON THE IEEE BUS WHEN PIA REGISTER CONTAINS "1". ; PA0 DIO 1 ; PA1 DIO 2 ; PA2 DIO 3 ; PA3 DIO 4 ; PA4 DIO 5 ; PA5 DIO 6 ; PA6 DIO 7 ; PA7 DIO 8 ; CA1 SRQ ; CA2 IFC ; PB0 ENABLE DATA OUT (ENABLED WHEN "0") ; PB1 ENABLE NDAC/NRFD (ENABLED WHEN "0") ; PB2 ENABLE EOI/DAV (ENABLED WHEN "0") ; PB3 EOI ; PB4 ATN ; PB5 DAV ; PB6 NDAC ; PB7 NRFD ; CB1 NOT USED ; CB2 REN ;CONTROL WORD FORMAT ;[ 7 ][ 6 ][ 5 ][ 4 ][ 3 ][ 2 ][ 1 ][ 0 ] ;[IRQA1][IRQA2][ CA2 CONTROL ][ DDRA][ CA1 CONTROL] ;[IRQB1][IRQB2][ CB2 CONTROL ][ DDRB][ CB1 CONTROL] ; IRQA1 0 INTERRUPT FLAG SET BY FALL OF SRQ ; IRQA2 0 NOT USED ; CA2 110 SET IFC HIGH ; 111 SET IFC LOW ; DDRA 0 R/W DATA DIRECTION REGISTER A ; 1 R/W PERIPHERAL REGISTER A ; CA1 10 SET IRQA1 HIGH ON RISE OF SRQ ; IRQB1 0 NOT USED ; IRQB2 0 NOT USED ; CB2 110 SET REN HIGH ; 111 SET REN LOW ; DDRB 0 R/W DATA DIRECTION REGISTER B ; 1 R/W PERIPHERAL REGISTER B ; CB1 00 NOT USED PAGE ; ********************************************************* ; * * ; * BIOS CALLS * ; * * ; ********************************************************* ;BIOS CALL 1: CONTROL OUT ; CAN BE CALLED WHILE IN ANY STATE. ; EXITS IN THE CONTROLLER STANDBY STATE (ATN HIGH), ; SOURCE HANDSHAKE MODE ;PARAMETER PASSED IN REGISTER C: ; BIT 0 IF "1", THE IFC SIGNAL IS SET LOW FOR 100 MICRO-SEC ; AND ALL PIA SIGNALS ARE INITIALIZED ; BIT 2 1 ; 0 X NO ACTION ; 1 0 SETS REN HIGH ; 1 1 SETS REN LOW PAGE IE.CO: ; MODIFIED SO AS NOT TO DESTROY THE STATE OF THE PARALLEL PIA ; DAB 11/15/82 ; PUSH AF BIT 0,C ;CHECK IFC SUB-COMMAND JR Z,XJ100 ;INITIALIZE ALL IEEE-488 SIGNALS IN A,(PAR_CNA) OR 00111000B OUT (PAR_CNA),A ;SET IFC-OUT LOW AND ENABLE DIRECTION REG LD A,11111111B ;DIRECT DATA OUT OUT (PAR_DTA),A IN A,(PAR_CNA) OR 00000100B ;ENABLE DATA REG OUT (PAR_CNA),A XOR A OUT (PAR_DTA),A IN A,(PAR_CNB) OR 00110000B ;SET REN-OUT HIGH AND 11110011B ;AND DISABLE DATA DIRECTION REG OUT (PAR_CNB),A LD A,00111111B ;DIRECTION FOR SOURCE HANDSHAKE OUT (PAR_DTB),A IN A,(PAR_CNB) ; OR 00000100B ;ENABLE DATA REG OUT (PAR_CNB),A LD A,00000010B ;VALUES FOR SOURCE HANDSHAKE OUT (PAR_DTB),A ;LEAVE IFC LOW FOR 100 MICRO-SEC LD A,25 ;DELAY 100 MICRO-SEC XJ101: DEC A JR NZ,XJ101 IN A,(PAR_CNA) ; AND 11110111B ;SET IFC HIGH OUT (PAR_CNA),A XJ100: BIT 2,C ;CHECK REN SUB-COMMAND JR Z,XJ102 ;SET/CLEAR REN IN A,(PAR_CNB) O 00110000B AND 11110111B ; BIT 1,C JR Z,XJ103 OR 00001000B XJ103: OUT (PAR_CNB),A XJ102: POP AF RET PAGE IE.SI: ;BIOS CALL 2. STATUS IN ;CAN BE CALLED ONLY WHILE IN SOURCE HANDSHAKE MODE. ;BIT 0 OF REGISTER A SET IF SRQ IS LOW IN A,(PAR_DTA) ;CLEAR IRQA1 IN A,(PAR_DTB) ;PULSE ENABLE NDAC/NRFD RES 1,A OUT (PAR_DTB),A SET 1,A OUT (PAR_DTB),A IN A,(PAR_CNA) ;SET SRQ VALUE IN A AND 10000000B RLCA RET PAGE IE.GTS: ;BIOS CALL 3 GO TAO STANDBY ;CAN BE CALLED ONLY WHILE IN SOURCE HANDSHAKE MODE ;ENTRY ;NONE PUSH AF LD A,00000010B ;SET ATN HIGH OUT (PAR_DTB),A XOR A ;FLOAT DATA BUS OUT (PAR_DTA),A POP AF RET PAGE IE.TC: ;BIOS CALL 4 TAKE CONTROL ;CAN BE CALLED ONLY WHILE IN THE CONTROLLER STANDBY STATE (ATN HIGH). ;EXITS IN THE CONTROLLER ACTIVE STATE (ATN LOW), SOURCE HANDSHAKE MODE. ;BIT 0 OF REGISTER C SET TO TAKE CONTROL ASYNCHRONOUS ;EXIT ;A = ;ERROR CODE PUSH BC BIT 0,C LD C,PAR_DTB JR NZ,XJ104 ;IF ASYNCHRONOUS ;TAKE CONTROL SYNCHRONOUSLY LD B,00000111B OUT (C),B ;DISABLE DRIVERS IN A,(PAR_CNB) RES 2,A OUT (PAR_CNB),A LD B,11010111B OUT (C),B ;DIRECTION REGISTER SET 2,A OUT (PAR_CNB),A LD B,10000101B OUT (C),B ;SET NRFD LOW LD A,12 XJ105: IN B,(C) BIT 5,B JR Z,XJ106 ;DATA VALID HAS DROPPED DEC A JR NZ,XJ105 ;WAIT 100 MICRO-SEC LD A,10000001B ;SET DATA VALID TIMEOUT ERROR JR XJ107 XJ106: LD B,11000101B OUT (C),B ;SET NDAC LOW XJ104: IN B,(C) SET 4,B ;SET ATN LOW OUT (C),B ;SET-UP FOR SOURCE HANDSHAKE IN A,(PAR_CNB) RES 2,A OUT (PAR_CNB),A LD B,00111111B OUT (C),B ;DIRECTION REGISTER SET 2,A OUT (PAR_CNB),A LD B,00010010B OUT (C),B ;CONTROL SIGNAL INITIAL VALUE XOR A ;CLEAR ERROR CODE XJ107: POP BC RET PAGE IE.OIM: ;BIOS CALL 5 OUTPUT INTERFACE MESSAGE ;CAN BE CALLED WHILE IN ANY MODE OR STATE ;EXITS IN THE SOURCE HANDSHAKE MODE WITH ATN LOW. ;ENTRY ;C = MULTI-LINE MESSAGE ;EXIT ;A = ERROR CODE PUSH BC IN A,(PAR_DTB) SET 4,A ;SET ATN LOW OUT (PAR_DTB),A BIT 0,A JR Z,IE.SHK ;SET-UP FOR SOURCE HANDSHAKE LD A,00010111B OUT (PAR_DTB),A ;DISABLE DRIVERS IN A,(PAR_CNB) RES 2,A OUT (PAR_CNB),A LD B,A LD A,00111111B OUT (PAR_DTB),A ;DIRECTION REGISTER LD A,B SET 2,A OUT (PAR_CNB),A ;FLOAT EXTERNAL DATA BUS XOR A OUT (PAR_DTA),A LD A,00010010B OUT (PAR_DTB),A ;CONTROL SIGNAL INITIAL VALUE JR IE.SHK PAGE IE.ODM: ;BIOS CALL 6 OUTPUT DEVICE MESSAGE ;CAN BE CALLED ONLY WHILE IN THE SOURCE HANDSHAKE MODE WITH ATN HIGH OR LOW. ;EXITS IN THE SOURCE HANDSHAKE MODE WITH ATN HIGH. ;ENTRY ;C = MULTI-LINE MESSAGE ;B = EOI REQUEST ;EXIT ;A = ERROR CODE PUSH BC IN A,(PAR_DTB) RES 4,A ;SET ATN HIGH OUT (PAR_DTB),A BIT 0,B ;CHECK IF EOI REQUESTED JR Z,IE.SHK SET 3,A OUT (PAR_DTB),A ;PERFORM SOURCE HANDSHAKE IE.SHK: IN A,(PAR_DTB) BIT 5,A ; JR NZ,XJ108 ;DAC TIMEOUT RE-ENTRY LD A,C OUT (PAR_DTA),A ;PLACE DATA ON BUS ; WAIT FOR READY LD C,10 XJ109: IN A,(PAR_DTB) BIT 7,A JR Z,XJ110 ;READY FOR DATA DEC C JR NZ,XJ109 ;WAIT FOR 100 MICRO-SEC LD A,10000010B ;SET RFD TIMEOUT ERROR JR XJ111 XJ110: IN A,(PAR_DTB) BIT 6,A JR NZ,XJ112 ;DATA ACCEPTED LOW LD A,10000001B ;SET DEVICE NOT PRESENT ERROR JR XJ111 XJ112: SET 5,A ;SET DAV LOW OUT (PAR_DTB),A ; WAIT FOR DATA TO BE ACCEPTED XJ108: LD C,100 PAGE XJ113: IN A,(PAR_DTB) BIT 6,A JR Z,XJ114 ;DATA ACCEPTED DEC C JR NZ,XJ113 ;WAIT 1000 MICRO-SEC LD A,10000100B ;SET DAC TIMEOUT ERROR JR XJ111 XJ114: IN A,(PAR_DTB) RES 5,A ;SET DAV HIGH RES 3,A ;SET EOI HIGH OUT (PAR_DTB),A XOR A ;REMOVE DATA FROM BUS OUT (PAR_DTA),A XJ111: POP BC RET PAGE IE.IDM: ;BIOS CALL 7 INPUT DEVICE MESSAGE ;CAN BE CALLED WHILE IN ANY MODE OR STATE ;EXITS IN THE ACCEPTOR HANDSHAKE MODE WITH ATN HIGH. ;EXIT ;L = ERROR CODE ;A = DEVICE MESSAGE ;H = DEVICE MESSAGE PUSH BC IN A,(PAR_DTB) BIT 0,A JR NZ,XJ115 ;SET-UP FOR ACCEPTOR HANDSHAKE LD B,00010111B LD C,PAR_DTB OUT (C),B ;DISABLE DRIVERS IN A,(PAR_CNB) RES 2,A OUT (PAR_CNB),A LD B,11010111B OUT (C),B ;DIRECTION REGISTER SET 2,A OUT (PAR_CNB),A LD A,11111111B ;FLOAT INTERNAL DATA BUS OUT (PAR_DTA),A LD A,01010101B OUT (PAR_DTB),A ;CONTROL SIGNALS INITIAL VALUE LD A,01000101B ;SET ATN HIGH OUT (PAR_DTB),A ;PERFORM ACCEPTOR HANDSHAKE XJ115: IN A,(PAR_DTB) BIT 6,A JR Z,XJ116 ;DATA INVALID TIMEOUT ERROR RE-ENTRY RES 7,A ;SET NRFD HIGH OUT (PAR_DTB),A LD B,12 XJ117: IN A,(PAR_DTB) BIT 5,A JR NZ,XJ118 ;DATA VALID DJNZ XJ117 ;WAIT 100 MICRO-SEC LD HL,10000010B ;SET DATA VALID TIMEOUT ERROR JR XJ119 PAGE XJ118: SET 7,A ;SET NRFD LOW OUT (PAR_DTB),A IN A,(PAR_DTA) ;READ DATA LD H,A LD L,0 IN A,(PAR_DTB) ;READ EOI BIT 3,A JR Z,XJ120 SET 0,L ;L=1 8/1/83 AOS XJ120: RES 6,A ;SET NDAC HIGH OUT (PAR_DTB),A XJ116: LD B,120 XJ121: IN A,(PAR_DTB) BIT 5,A JR Z,XJ122 ;DATA VALID DROPPED DJNZ XJ121 ;WAIT 1000 MICRO-SEC SET 2,L ;SET DATA INVALID TIMEOUT ERROR SET 7,L JR XJ119 XJ122: SET 6,A ;SET NDAC LOW OUT (PAR_DTB),A XJ119: LD A,H POP BC RET PAGE IE.PP: ;BIOS CALL 8 PARALLEL POLL ;CAN BE CALLED ONLY WHILE IN THE SOUARCE HANDSHAKE MODE WITH ATN HIGH OR LOW. ;EXITS IN THE SOURCE HANDSHAKE MODE WITH ATN LOW. ;EXIT ;A = PARALLEL POLL VALUE LD A,00011011B ;FORM PARALLEL POLL OUT (PAR_DTB),A LD A,11111111B ;FLOAT INTERNAL DATA BUS OUT (PAR_DTA),A IN A,(PAR_DTA) ;READ PARALLEL POLL DATA PUSH AF ;SAVE XOR A OUT (PAR_DTA),A ;RE-STORE SOURCE HANDSHAKE MODE LD A,00010010B OUT (PAR_DTB),A POP AF ;RESTORE PARALLEL POLL VALUE RET PAGE ; ********************************************************* ; * * ; * IEEE DRIVERS * ; * * ; ********************************************************* ;[ ] ;IEEE DRIVERS: ;THE ROUTINES IEINSTAT, IEINP AND IEOUT ARE USED TO ;TRANSFER CHARACTERS TO AND FROM AN IEEE DEVICE ATTACHED TO THE ;OSBORNE IEEE PORT. THE ADDRESS OF THE DEVICE IS SPECIFIED IN ;THE CELL IE_ADRS. ;THE FUNCTION IEINSTAT RETURNS THE STATUS OF THE INPUT DEVICE. ;UNFORTUNATELY THERE IS NO STANDARD WAY BY WHICH AN IEEE DEVICE ;INDICATES THAT IT HAS A CHARACTER. IN ORDER TO DETERMINE THIS, ONE ;HAS TO READ THE CHARACTER DEVICE. AS A CP/M TRANSIENT CAN CALL ;IEINSTAT MANY TIMES BEFORE CALLING IEINP TO READ A CHAR, AND IEINSTAT ;HAS TO READ THE CHAR TO DETERMINE THE STATUS, THE CHARACTER READ HAS TO ;BE BUFFERED UNTIL CALL TO IEINP IS MADE. IEINSTAT READS THE DEVICE ;ONLY WHEN THE BUFFER IS EMPTY. AS ZEROS ARE USED TO INDICATE ;THAT THE BFR IS EMPTY, A NULL CHARACTER CAN NOT BE READ FROM THE ;IEEE DEVICE. PAGE IEINSTAT: ;GETS STATUS OF THE INPUT DEVICE ATTACHED TO IEEE PORT ;IF A CHAR IS PRESENT IN IE_CHAR THEN RETURN WITH 0FFH STATUS ;ELSE ;MAKE DEVICE TALKER ;READ THE DEVICE ;IF CHAR READ THEN ; STORE IN BFR ;MAKE UNTALK ;RETURN WITH STATUS OF BUFFER LD A,(IE_CHAR) OR A JR Z,IEI10 ;IF CHAR PRESENT THEN IEOSTAT: ;RETURNS STATUS OF IEEE ;IEEE ALWAYS APPEARS TO BE READY OR 0FFH ;RETURN WITH 0FFH STATUS RET PAGE IEI10: ;MAKE TALKER LD A,(IE_ADR) ADD A,IE_TALK ;GET PRIMARY ADDRESS LD C,A CALL IE.OIM ;OUTPUT INTERFACE MESSAGE OR A JR NZ,IEI10 ;TRY AGAIN IF ERROR IEI20: ;READ A CHAR. CALL IE.IDM BIT 7,L JR Z,IEI30 ;IF ERROR THEN XOR A ;INICATE NO CHAR RECVD IEI30: LD (IE_CHAR),A ;STOR THE CHAR IEI40: ;MAKE UNTALK LD C,IE_UTLK CALL IE.OIM OR A JR NZ,IEI40 ;RETURN WITH STATUS OF THE CHAR LD A,(IE_CHAR) OR A RET Z OR 0FFH RET PAGE IEINP: ;READS A CHARACTER FROM IEEE PORT CALL IEINSTAT JR Z,IEINP ;WAIT TILL CHAR AVAIL LD HL,IE_CHAR LD A,(HL) LD (HL),0 ;CLEAR THE BUFFER RET PAGE IEOUT: ;OUTPUTS THE CHARACTER IN REG C TO IEEE PORT ;USES ROM RESIDENT PRIMITIVES. PUSH BC ;SAVE THE CHAR ;MAKE LISTENER IEO05: LD A,(IE_ADR) ADD A,IE_LSTN ;GET PRIMARY ADDRESS LD C,A CALL IE.OIM ;OUTPUT INTERFACE MESSAGE OR A JR NZ,IEO05 ;TRY AGAIN IF ERROR POP BC LD B,0 ;DO NOT SEND EOI IEO22: PUSH BC ;SAVE CHAR AGAIN IN CASE OF RETRY CALL IE.ODM POP BC OR A JR NZ,IEO22 ;TRY AGAIN IF ERROR IEO40: ;MAKE UNLISTEN LD C,IE_ULST CALL IE.OIM OR A JR NZ,IEO40 RET PAGE ; ********************************************************* ; * * ; * PARALLEL PORT * ; * * ; ********************************************************* ;THE PARALLEL PORT IS ACTUALLY THE IEEE PORT DRIVEN WITH THE CENTRONIX ;PROTOCOL. THE BIT ASSIGNEMENTS OF THE PIA AND PIB ARE AS FOLLOWS: ;PIA0-7 = DATA BUS ;PIB0 = 0, DATA BUS IS OUTPUT. 1, DATA BUS IS INPUT ;PIB1 = SET TO 1. ;PIB2 = SET TO 0. ;PIB3 = 0 OUTPUT, 1 INPUT ;PIB4 = NOT USED ;PIB5 = OUTPUT STROBE. ACTIVE = 1. ;PIB6 = 0, PRINTER BUSY. 1, PRINTER IS READY. ;PIB7 = NOT USED. ;CA2 = GOING LOW INDICATES TO DEVICE THAT WE ARE BUSY. ;CA1 = LOW TO HIGH TRANSITION GATES INPUT DATA TO PORT A. ;THE PORT IS BIDIRECTIONAL BUT ONLY ONE DIRECTION ;CAN BE ACTIVE AT ANY TIME. THE DIRECTION OF PORT IS DETERMINED ;BY WHICH ROUTINES ARE CALLED. IF POSTAT OR PAROUT ARE ;CALLED, IT IS MADE AN OUTPUT PORT AND AN INPUT PORT IF ;PISTAT OR PARINP ARE CALLED. PAGE CV2OP: ;INITIALIZES THE PORT TO A PARALLEL OUTPUT PORT. LD B,PP.OUT LD E,PA.DRO LD D,PB.DTO JP CV2IOP PAGE CV2IP: ;INITIALIZES THE PORT TO A PARALLEL INPUT PORT. LD B,PP.IN LD E,PA.DRI LD D,PB.DTI ; JMP CV2IOP ; FALL THROUGH CV2IOP: CV2IOP: LD A,(PP.MODE) CP B RET Z ;RETURN WHEN IN CORRECT MODE LD A,PA.CDR OUT (PAR_CNA),A ;SELECT DIRECTION REG LD A,E OUT (PAR_DTA),A ;OUTPUT CONSTANT TO DIR. REG TO PUT A PORT IN INPUT MODE LD A,PA.CDT OUT (PAR_CNA),A ;SELECT PORT A DATA REG. LD A,PB.CDR OUT (PAR_CNB),A ;SELECT PORT B DIRECTION LD A,PB.DR OUT (PAR_DTB),A ;ALL LINES ARE OUTPUT EXCEPT THE OUTPUT BUSY SIGNAL ON BIT 6 LD A,PB.CDT OUT (PAR_CNB),A ;SELECT DATA REGISTER LD A,D OUT (PAR_DTB),A ;INITIALIZE PORT B DATA LD A,B LD (PP.MODE),A RET PAGE POSTAT: ;GETS STATUS OF THE PARALLEL (CENTRONIX) PRINTAER ATTACHED TO THE IEEE PORT CALL CV2OP ;CONVERT TO OUTPUT IN A,(PAR_DTB) ;GET PORT B DATA AND PP.ORDY RET Z OR 0FFH POS10: RET PAGE PISTAT: ;GETS STATUS OF THE INPUT DEVICE ATTACHED TO THE PARALLEL PORT CALL CV2IP LD A,(PIACTL) AND PP.IRDY JR NZ,PIS20 ;IF SAVED STATUS INDICATES THERE IS A CHAR IN THE PIA IN A,(PAR_CNA) LD (PIACTL),A ;THIS IS SAVED AS READING THE ;PIA CLEARS THE STATUS AND PP.IRDY RET Z PIS20: OR 0FFH RET PAGE PARINP: ;INPUTS A CHARACTER FROM PARALLEL PORT. CALL PISTAT JR Z,PARINP ;WAIT TILL CHAR IN PIA XOR A LD (PIACTL),A ;CLEAR SAVED STATUS IN A,(PAR_DTA) CPL ;INVERT DATA LD C,A ;ALSO IN C RET PAGE PAROUT: ;OUTPUTS THE CHARACTER IN C TO THE IEEE PORT TREATING THE PORT AS A PARALLEL PORT. CALL POSTAT JR Z,PAROUT LD A,C CPL ;INVERT DATA OUT (PAR_DTA),A LD A,PB.DTO+STRB OUT (PAR_DTB),A ;SET STROBE LD A,PB.DTO OUT (PAR_DTB),A ;CLEAR STROBE RET PAGE CTC_INIT: ; INITIALIZE THE CLOCK-TIMER CHIP. ; ENTRY: ; NONE ; ; EXIT: ; NONE ; LD A,00110100B ;SET COUNTER 0 TO RATE GENERATOR MODE ;AND TWO BYTE BINARY PROGRAMMING OUT (TIM_CNL),A LD A,01110100B ;SET COUNTER 1 TO RATE GENERATOR MODE ;AND TWO BYTE BINARY PROGRAMMING OUT (TIM_CNL),A LD A,10110110B ;SET COUNTER 2 TO SQUARE WAVE MODE ;AND TWO BYTE BINARY PROGRAMMING OUT (TIM_CNL),A RET PAGE ; ********************************************************* ; * * ; * SERIAL PORT * ; * * ; ********************************************************* SIOINIT: ;INITIALIZE SERIAL PORT ;ENTRY ;C = CONTROL PORT (SIO_CNA OR SIO_CNB) ;EXIT ;NONE DI ;DISABLE INTERRUPTS UNTIL EVERYTHING IS SET UP ;INITIALIZE WRITE REG 4 -- BASIC CONTROL LD A,REG4 ;SELECT WRITE REG 4 FIRST OUT (C),A LD A,BAS_CNL ;BASIC CONTROL -- X16 CLOCK, 1 STOP BIT, NO PARITY OUT (C),A ;INITIALIZE WRITE REG 3 -- RECEIVE CONTROL LD A,REG3 ;SELECT REG 3 OUT (C),A LD A,RCV_CNL ;RECEIVE CONTROL -- 8 BITS/CHAR, AUTO ENABLES ON, RX ENABLE OUT (C),A ;INITIALIZE WRITE REG 5 -- TRANSMIT CONTROL LD A,REG5 ;SELECT REG 5 OUT (C),A ; ; USE MASK CORRESPONDING TO CHANNEL: A HAS RTS LOW, B HAS RTS HIGH ; LD A,SIO_CNA ;ARE WE SETTING CHANNEL A? CP C ; LD A,TX_CNL_A ;LET'S ASSUME WE ARE. JP Z,XJ123 ;AH HA! WE ARE... ; LD A,TX_CNL_B ;NO, NOT A, B. XJ123: OUT (C),A ;OUTPUT CONTROL BYTE. ;INITIALIZE WRITE REG 2 -- INTERRUPT VECTOR LD A,REG2 ; OUT (C),A ;SELECT WR2 LD A,LOW SIO_I_TBL ;SET VECTOR TO LOW BYTE OF SIO INTERRUPT VECTOR TABLE OUT (C),A ; ;INITIALIZE WRITE REG 1 -- INTERRUPT CONTROL LD A,REG1 ;SELECT REG 1 OUT (C),A LD A,SIO_I_IN ;INTERRUPT CONTROL OUT (C),A EI ;REENABLE INTERRUPTS ;SET FLAG LD A,SIO_CNA ;CHECK IF PORT A CP C ;SET Z FLAG IF PORT A LD A,0FFH JR NZ,XJ124 LD (S_A_FLG),A ;IF PORT A RET XJ124: LD (S_B_FLG),A ;IF PORT B RET PAGE SETBAUD: ;SET BAUD RATE FOR SERIAL PORT ;ENTRY ;C = BAUD RATE CODE (0-15) ;A = PORT (0 = PORT A, 1 = PORT B) ;EXIT ;NONE PUSH HL ;SAVE PUSH BC PUS AF ; CHECK FOR VALID CODE ENTRY XJ125: LD A,C CP BTBLLEN ;MAXIMUM CODE VALUE JR C,XJ126 ;IF CODE IS VALID, LOOK UP VALUE POP AF ;RESTORE STACK JR XJ127 ;IF CODE IS INVALID, QUIT ; FIND TABLE ENTRY FOR THE BAUD RATE CODE XJ126: LD HL,BAUDTBL ;HL = BAUD RATE TABLE SLA C ;C = TABLE OFFSET IN BYTES LD B,0 ;BC = TABLE OFFSET IN BYTES ADD HL,BC ;HL = TABLE ENTRY'S ADDRESS ; SET 8253 TIMER TO THE VALUE IN THE TABLE ENTRY POP AF ;DETERMINE WHICH COUNTER TO OR A ;PROGRAM LD C,TIM_CT0 ;ASSUME COUNTER 1 JR Z,XJ128 ;IT IS COUNTER 1 (CHANNEL A) ; ;IT'S NOT COUNTER 1, LD C,TIM_CT1 ;IT'S COUNTER 2 (CHANNEL B) XJ128: LD B,2 ;OUTPUT THE TWO BYTE STRING IN BAUDTBL OTIR ;POINTED TO BY HL XJ127: POP BC ;RESTORE POP HL RET PAGE BAUDTBL: ;TABLE OF COUNT VALUES WHICH MUST BE INPUT TO THE 8253 COUNTER TO GIVE THE SELECTED BAUD RATE ; 23.9619/13 X 10**6= 1.8432MHZ CLK FOR 8253 ; TIME CONSTANT = CLK / (16 * BAUD RATE ) ;EX: 12 = 1,843,200 / (16 * 9600) DW 03 ;38.4 DW 2304 ;50 BAUD DW 1536 ;75 BAUD DW 1047 ;110 BAUD DW 857 ;134.5 BAUD DW 768 ;150 BAUD DW 384 ;300 BAUD DW 192 ;600 BAUD DW 96 ;1200 BAUD DW 64 ;1800 BAUD DW 48 ;2400 BAUD DW 32 ;3600 BAUD DW 24 ;4800 BAUD DW 16 ;7200 BAUD DW 12 ;9600 BAUD DW 6 ;19,200 BAUD BTBLLEN EQU ($ - BAUDTBL)/2 PAGE SERAIN: ;INPUT ONE BYTE FROM SERIAL PORT A ( CP/M PTR: PORT) ;ENTRY ;NONE ;EXIT ;C = CHARACTER READ ;WAIT FOR CHARACTER CALL SAI_STAT JR Z,SERAIN ;IF NO CHARACTER READY ;GET CHARACTER LD B,S_CH_A_I ;SIO CHANNEL A INPUT DI CALL RM_C_BF ;REMOVE CHARACTER FROM BUFFER EI LD C,A ;C = CHARACTER RET PAGE SERBIN: ;INPUT ONE BYTE FROM SERIAL PORT B ( CP/M CRT: POART) ;ENTRY ;NONE ;EXIT ;C = CHARACTER READ ;WAIT FOR CHARACTER CALL SBI_STAT ;GET STATUS JR Z,SERBIN ;IF NO CHARACTER READY ;GET CHARACTER LD B,S_CH_B_I ;SIO CHANNEL B INPUT DI CALL RM_C_BF ;REMOVE CHARACTER FROM BUFFER EI LD C,A ;C = CHARACTER RET PAGE SERAOUT: ;OUTPUT ONE BYTE TO SERIAL PORT A (CP/M PTP: PORT) ;ENTRY ;C = CHARACTER TO OUTPUT ;EXIT ;NONE PUSH BC ;SAVE CHAR ;WAIT TILL READY XJ129: DI ;DISABLE INTERRUPT SO STATUS ;IS VALID CALL SAO_STAT ;GET SERIAL PORT A OUTPUT STATUS JR NZ,XJ130 ;READY... ; EI ;NOT READY. RE-ENABLE AND JR XJ129 ;TO BECOME FREE AND LOOP XJ130: ;SEND CHARACTER POP BC LD B,S_CH_A_O + 40H ;SIO CHANNEL A OUTPUT SERAO1: CALL FL_B_CH ;PUT CHARACTER IN BUFFER EI ;RE-ENABLE INTERRUPTS RET SERBOUT: ;OUTPUT ONE BYTE TO SERIAL PORT B (CP/M CRT: PORT) ;ENTRY ;C = CHARACTER TO OUTPUT ;EXIT ;NONE PUSH BC ;SAVE CHAR ;WAIT TILL READY XJ131: DI  ;DISABLE INTERRUPT SO STATUS ;IS VALID CALL SBO_STAT ;GET SERIAL PORT A OUTPUT STATUS JR NZ,XJ132 ;READY... EI ;NOT READY. RE-ENABLE JR XJ131 ;TO BECOME FREE AND LOOP XJ132: ;SEND CHARACTER POP BC LD B,S_CH_B_O + 40H ;SIO CHANNEL A OUTPUT JP SERAO1 ;PUT CHARACTER IN BUFFER PAGE SAO_STAT: ;OUTPUT STATUS FOR SERIAL PORT A ;ENTRY ;NONE ;EXIT ;A = 0, IF NOT READY ;A = 0FFH IF READY ;ZBIT = SET IF NOT READY FOR OUTPUT LD B,S_CH_A_O ;SIO CHANNEL A OUTPUT SAO_S1: JP GET_O_STAT ;GET STATUS SBO_STAT: ;OUTPUT STATUS FOR SERIAL PORT B ;ENTRY ;NONE ;EXIT ;A = 0, IF NOT READY ;A = 0FFH IF READY ;ZBIT = SET IF NOT READY FOR OUTPUT LD B,S_CH_B_O ;SIO CHANNEL B OUTPUT JP GET_O_STAT ;GET STATUS PAGE SAI_STAT: ;SERIAL PORT A INPUT STATUS ;ENTRY ;NONE ;EXIT ;A = 0 IF NOT READY, 0FFH IF READY ;Z BIT = SET IF NOT READY LD B,S_CH_A_I ;SIO CHANNEL A INPUT JP GET_I_STAT ;GET STATUS SBI_STAT: ;SERIAL PORT B INPUT STATUS ;ENTRY ;NONE ;EXIT ;A = 0 IF NOT READY, 0FFH IF READY ;Z BIT = SET IF NOT READY LD B,S_CH_B_I ;SIO CHANNEL B INPUT JP GET_I_STAT ;GET STATUS PAGE GET_O_STAT: ;SERIAL PORT OUTPUT STATUS ;ENTRY ;B = DEVICE NUMBER ;EXIT ;A = 0 IF NOT READY, 0FFH IF READY ;ZBIT = SET IF NOT READY CALL FL_B_ST ;GET STATUS GET_O_S1: JR Z,XJ133 ;IF NOT READY OR 0FFH ;IF READY RET ;RETURN A = 0FFH XJ133: XOR A ;IF NOT READY RET ;RETURN A = 0 GET_I_STAT: ;SERIAL PORT INPUT STATUS ;ENTRY ;B = DEVICE NUMBER ;EXIT ;A = 0 IF NOT READY, 0FFH IF READY ;ZBIT = SET IF NOT READY CALL RM_C_ST ;GET STATUS JP GET_O_S1 ;IF NOT READY PAGE SETDMA: ;SET DMA ADDRESS AND BANK ;ENTRY ;HL = ADDRESS ;A = BANK ;EXIT ;DMADR SET ;DMABANK SET LD (DMADR),HL LD (DMABANK),A RET  ;Z BIT = SET IF NOT READY LD B,S_CH_A_I ;SIO CHANNEL A INPUT JP GET_I_STAT ;GET STATUS SBI_STAT: ;SERIAL PORT SUBTTL 'INTERRUPT HANDELERS' ; ********************************************************* ; * * ; * INTERRUPT HANDLERS * ; * * ; ********************************************************* ; ; MODULE 6 --ROM6-- ENTRY POINTS ; ; INTERRUPT HANDLING ROUTINES ; ; GET_INT: GET INTERRUPT STATE ; SET_INT: SET INTERRUPT STATE ; INT_POLL: INTERRUPT POLLING ; DMA_INT: DMA INTERRUPT HANDLER ; PAR_INT: PARRALLEL INTERRUPT HANDLER ; INT_KBD: INTELLIGENT KEYBOARD INTERRUPT HANDLER ; FDC_INT: FLOPPY DISK CONTROLLER INTERRUPT HANDLER ; RESET_INT: RESET INTERRUPT HANDLER ; S_R_I_CH_A: SIO PORT (CHANNEL) A RECIEVE INTERRUPT HANDLER ; S_R_I_CH_B: SIO PORT B RECIEVE INTERRUPT HANDLER ; S_T_I_CH_A: SIO PORT A TRANSMIT INTERRUPT HANDLER ; S_T_I_CH_B: SIO PORT B TRANSMIT INTERRUPT HANDLER ; EXT_CH_A: SIO PORT A EXTERNAL/STATUS INTERRUPT HANDLER ; EXT_CH_B: SIO PORT B EXTERNAL/STATUS INTERRUPT HANDLER ; CH_A_SPEC: SIO PORT A SPECIAL RX CONDITION ; CH_B_SPEC: SIO PORT B SBECIAL RX CONDITION ; SPEC_HD: SPECIAL HANDELING ROUTINE FOR BUFFERING ; RTC_INT: REAL TIME CLOCK INTERRUPT HANDLER ; RTC_DRV: REAL TIME CLOCK DRIVER -- ALSO DISK CHANGE DETECT PAGE .Z80 ; .XLIST ; INCLUDE SYSS1.MAC ;SYSTEST FILE ; INCLUDE RAMSMON.MAC ;MONITOR RAM MEMORY LOCATIONS ; INCLUDE RAMS10.MAC ;RAM MEMORY LOCATIONS AND CONSTANTS ; .LIST ; ;SYSS1.MAC , RAMSMON.MAC AND RAMS10.MAC INCLUDED ; EXT INT_HD,FL_B_CH,RM_C_ST,RM_C_BF,D.FINT,KBDRVR ; PUBLIC GET_INT,SET_INT,SPEC_HD,R_INT_TBL,R_I_TBL_LEN,INT_POLL CSEG PAGE ;------------------------------------------------------------------------------ ; SHELLY INTERRUPT STRUCTURE ; BY ; DAVID ANDREW BERG ; 29 OCTOBER 1982 ;------------------------------------------------------------------------------ ; THE FOLLOWING INTERRUPTS WILL BE SUPPORTED: ; ; PIA INTERRUPTS: ; DMA (SYSTEM PIA CA1) ; INTELLIGENT KEYBOARD (SYSTEM PIA CA2) ; REAL TIME CLOCK (SYSTEM PIA CB1) ; IEEE 488 (PARALLEL PIA CA1) ; FLOPPAY DISK CONTROLLER (PARALLEL PIA CB1) ; RESET INTERRUPT ; ; SIO INTERRUPTS (ON EITHER CHANNEL A OR B): ; RX CHARACTER ; RX CHAR W/PARITY ERR ; TX BUFFER EMPTY ; EXTERNAL/STATUS TRANSITION (DCD, CTS, SYNC, BREAK/ABORT, ; OR TRANSMIT UNDERRUN/EOM) ; ; ; THEY WILL BE POLLED IN THE FOLLOWING ORDER TO MINIMIZE INFORMATION ; LOSS AND DUE TO HARDWARE CONSIDERATIONS: ; ; ; DMA ; IEEE-488 ; SIO INTERRUPTS ; INTELLIGENT KEYBOARD ; REAL TIME CLOCK (KEYBOARD SCAN) ; FDC ; ; SIO INTERRUPTS ARE HANDLED BY READING THE INTERRUPT VECTOR FROM ; RR2 ON CHANNEL B AND USING BITS 1-3 AS AN INDEX INTO THE ; INTERRUPT TABLE. BITS 1-3 ARE SET ACCORDING TO THE ; INTERRUPTING CONDITION OF THE SIO, SINCE THE SIO IS SET ; TO STATUS AFFECTS VECTOR IN WR1. ; ; IF NO INTERRUPT HAS OCCURRED, A SYSTEM RESET IS PERFORMED. ; ; DETECTION OF ANY INTERRUPT CAUSES THE SYSTEM TO SWITCH IN THE BANK ; AND JUMP TO THE ADDRESS SPECIFIED BY THE INTERRUPT'S TABLE ENTRY. ; CONTROL IS RETURNED TO THE USER'S PROGRAM BY THE INTERRUPT HANDLER. ; 14 3-BYTE TABLE ENTRIES ARE REQUIRED. ; ; ONCE AN INTERRUPT IS DETECTED IT IS SERVICED AND CONTROL IS RETURNED ; TO THE USER'S PROGRAM. THIS ALLOWS A HIGH PRIORITY INTERRUPT TO BE ; SERVICED BEFORE LOWER PRIORITY INTERRUPTS. PAGE ;------------------------------------------------------------------------------ ; INTERRUPT DETECTION STRATEGY ;------------------------------------------------------------------------------ ; THE FOLLOWING INTERRUPT DETECTION STRATEGY IS IMPLEMENTED IN THE ; INTERRUPT POLLING ROUTINE: ; ; DMA: ; EXAMINE CA1 LINE OF SYS PIA (SYS_CNA BIT 7) ; IF SET, ; SERVICE DMA INT ; ; IEEE 488 RECEIVE INTERRUPT (WHEN IMPLEMENTED) IS DETECTED BY ; EXAMINE THE SRQ LINE ON THE PARALLEL PIA (CA1: BIT 7 ON ; PAR_CNA). ; ; SIO INTERRUPTS ARE DETECTED BY: ; EXAMINING THE INT PENDING BIT (BIT 1) OF RR0 ON CH A (SIO_CNA) ; IF SET, ; LOAD THE SIO INTERRUPT VECTOR (RR2) ; USE BITS 1-3 AS AN INDEX INTO THE INTERRUPT TABLE ;  (SHIFT RIGHT ONCE) ; ; INTELLIGENT KEYBD INTERRUPT IS DETECTED BY ; EXAMINING CA2 LINE OF THE SYSTEM PIA (SYS_CNA BIT 6) ; IF ACTIVE, ; SERVICE INTELLIGENT KEYBD INTERRUPT ; ; RTC: ; EXAMINE CB1 LINE OF THE SYSTEM PIA (PORT SYS_CNB BIT 7) ; IF ACTIVE, ; SERVICE RTC INTERRUPT ; ; FDC: ; EXAMINE THE CB1 LINE ON THE PARALLEL PIA. ; IF ACTIVE, ; SERVICE FDC INT ; ; IF NO INTERRUPTS DETECTED, ; SERVICE RESET INTERRUPT. ; ;------------------------------------------------------------------------------ PAGE GET_INT: ; ROUTINE TO GET INTERRUPT STATE. ; ; CUR_I_ST MUST BE ZEROED AT SYSTEM INITIALIZATION. ; ENTRY: ; NONE ; EXIT: ; INTERRUPT STATE IS RETURNED IN BC. ; THE BIT POSITIONS FOR EACH INTERRUPT ARE: ; ; ;REGISTER B: +---+---+---+---+---+---+---+---+ ; | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ; +---+---+---+---+---+---+---+---+ ; | | | | | | | | ; DMA <-+ | | | | | | | ; PARALLEL PORT <---+ | | | |  | | ; INTELLIGENT KB <------+ | | | | | ; REAL TIME CLOCK<----------+ | | | | ; FLOPPY DISK CON<--------------+ | | | ; UNUSED <------------------+ | | ; UNUSED <----------------------+ | ; UNUSED <--------------------------+ ; ;REGISTER C: +---+---+---+---+---+---+---+---+ ; | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ; +---+---+---+---+---+---+---+---+ ; | | | | | | | | ; UNUSED <-+ | | | | | | | ; UNUSED <---+ | | | | | | ; UNUSED <------+ | | | | | ; UNUSED <----------+ | | | | ; UNUSED <--------------+ | | | ; UNUSED <------------------+ | | ; UNUSED <----------------------+ | ; UNUSED <--------------------------+ ; LD BC,(CUR_I_ST) ;LOAD CURRENT INTERRUPT STATE TO BC RET ;AND RETURN PAGE SET_INT: ; ROUTINE TO SET INTERRUPT STATE. ; ANY PIA INTERRUPTS CAN BE SELECTIVELY ENABLED OR DISABLED. ; ENTRY: ; BC = VECTOR OF INTERRUPTS STATES TO SET. ; A 1 BIT MEANS TO ENABLE AN INTERRUPT, ; 0 MEANS TO DISABLE AN INTERRUPT. ; (SEE GET_INT FOR A DESCRIPTION OF EACH BIT POSITION) ; ; EXIT: ; INTERRUPTS ARE APPROPRIATELY ENABLED OR ; DISABLED. INTERRUPTS ARE ENABLED UPON EXIT. DI ;DISABLE INTERRUPTS TO PREVENT DISRUPTION LD (CUR_I_ST),BC ;SAVE STATE TO SET AS CURRENT ;SET DMA IN A,(SYS_CNA) ;READ SYSTEM PIA CH. A OR 00000001B ;ASSUME DMA ENABLE SLA B ;CHECK DMA BIT. JR C,XJ194 ;IF ENABLE AND 11111110B ;IF DISABLE XJ194: OUT (SYS_CNA),A ;WRITE A TO PIA ;SET PARALLEL PORT IN A,(PAR_CNA) ;READ CHANNEL A OF PARALLEL PIA OR 00000001B ;ASSUME ENABLE INTS SLA B ;IS PARALLEL BIT SET? JR C,XJ196 ;YES, ENABLE PARALLEL INT... AND 11111110B ;NO, DISABLE PARALLEL INT XJ196: OUT (PAR_CNA),A ;SET INTELLIGENT KEYBOARD IN A,(SYS_CNA) ;READ SYSTEM PIA OR 00001000B ;ASSUME ENABLE SLA B ;IS INTELLIGENT KEYBD BIT SET? AJR C,XJ197 ;YES, ENABLE IT AND 11110111B ;NO, DISABLE INT XJ197: OUT (SYS_CNA),A ;SET REAL TIME CLOCK (60HZ) INTERRUPT STATE IN A,(SYS_CNB) ;READ CHANNEL B OF SYSTEM PIA OR 00000001B ;ASSUME ENABLE RTC INT. SET BIT 0. SLA B ;IS RTC BIT SET? JR C,XJ198 ;YES, ENABLE RTC AND 11111110B ;NO, DISABLE XJ198: OUT (SYS_CNB),A ;SET FLOPPY DISK CONTROLLER INTERRUPT STATE IN A,(PAR_CNB) ;READ CHANNEL B OF PARALLEL PIA OR 00000001B ;ASSUME ENABLE SLA B ;IS FDC BIT SET? JR C,XJ199 ;YES, ENABLE IT AND 11111110B ;NO, DISABLE IT XJ199: OUT (PAR_CNB),A ;WRITE FDC STATE EI ;RE-ENABLE INTERRUPTS RET ;AND RETURN PAGE ;------------------------------------------------------------------------------ ; INTERRUPT POLLING ROUTINE ;------------------------------------------------------------------------------ S_INT_PDG EQU 00000010B ;INTERRUPT PENDING MASK FOR SIO RR0 ; IRQ1 EQU 10000000B ;INTERRUPT PENDING MASK FOR PIA IRQ1 IRQ2 EQU 01000000B ;INTERRUPT PENDING MASK FOR PIA IRQ2 ; INT_POLL: ;ENTRY ;NONE ;EXIT ;HL ==> ENTRY IN INTERRUPT TABLE XJ200: ;CHECK FOR DMA INTERRUPT LD E,0 ;FIRST ENTRY IN TABLE (E = ENTRY NUMBER) IN A,(SIO_CNA) ;CHECK FOR SIO INT AND S_INT_PDG ;TEST INTERRUPT PDG BIT (1) JP Z,XJ201 ;:CK_I_KB ;NOT SET...NO SIO INTERRUPT. CHECK INT. KBD ;SIO INTERRUPT PDG: ;READ INTERRUPT VECTOR LD A,2 ;POINT TO RR2 ON CHANNEL B OUT (SIO_CNB),A ; IN A,(SIO_CNB) ;READ RR2: INTERRUPT VECTOR AND 00001110B ;STRIP OFF ALL BITS BUT 1-3 SRA A ;SHIFT RIGHT SO A CONTAINS INDEX INTO TABLE ADD A,E ;A = ENTRY NUMBER LD E,A ;E = ENTRY NUMBER JP XJ202 ;HANDLE INTERRUPT PER TABLE ENTRY XJ201: ;CHECK FOR IEEE-488 (PARALLEL) INT LD A,8 ;BUMP ENTRY NUMBER COUNT PAST SIO VECTORS ADD A,E LD E,A IN A,(SYS_CNB) ; AND IRQ1 ; JP NZ,XJ202 ;HANDLE RTC INTERRUPT PAGE XJ203: ;CHECK SIO INC E ;NEXT ENTRY IN TBL IN A,(PAR_CNA) ;READ PARALLEL PIA CONTROL PORT A AND IRQ1  ;CHECK CA1 (IRQA1) BIT (7): SRQ LINE JP NZ,XJ202 ;NO INTERRUPT PDG...CHECK SIO XJ204: ;CHECK INTELLIGENT KEYBD INC E ;NEXT ENTRY IN TBL IN A,(SYS_CNA) ;READ SYSTEM PIA CONTROL REG AND IRQ2 ;CHECK CA2 (IRQA2) BIT (6) JP NZ,XJ202 ;IT'S SET... XJ205: ;NOT INT. KBD, CHECK RTC INC E ;NEXT ENTRY IN TBL: TICK INTERRUPT IN A,(SYS_CNA) ;CHECK CA1 (IRQ1) BIT (7) ON SYSTEM PIA CH A AND IRQ1 ; JP NZ,XJ202 ;IT'S ACTIVE...SERVICE INT XJ206: ;NOT RTC, CHECK FOR FDC INTERRUPT INC E ;NEXT ENTRY IN TBL IN A,(PAR_CNB) ;CHECK CB1 (IRQ1) LINE OF PARALLEL PIA CH. B AND IRQ1 ; JP NZ,XJ202 ;IT'S ACTIVE...SERVICE INTERRUPT XJ207: ;THIS MUST BE A INTERRUPT GENERATED ;BY PRESSING THE SYSTEM RESET BUTTON INC E ;NEXT ENTRY IN TBL ;NONE...HANDLE SYSTEM RESET INT XJ202: ;POINT TO TABLE ENTRY LD HL,INT_TBL ;POINT HL TO INTERRUPT TBL LD A,E ;E = ENTRY NUMBER ADD A,A ;*2 ADD A,E ;*3 (ENTRY LENGTH = 3) LD E,A LD D,0 ;DE = INDEX INTO TABLE ADD HL,DE ;HL ==> TABLE ENTRY JP INT_HD ;HANDLE INTERRUPT PAGE ;------------------------------------------------------------------------------ ; PIA INTERRUPT HANDLERS ;------------------------------------------------------------------------------ ; THESE HANDLERS ARE FOR INTERRUPTS GENERATED BY THE PIAS. NO REAL ; HANDLING IS DONE. THE INTERRUPT CONDITION IS SIMPLY CLEARED. ; THE REAL TIME CLOCK INTERRUPT IS NOT INCLUDED SINCE IT ALREADY ; EXISTS IN THE ROM. ; DMA_INT: ; DMA INTERRUPT HANDLER IN A,(SYS_DTA) ; RET ; PAR_INT: ; PARALLEL INTERRUPT HANDLER IN A,(PAR_DTA) ; RET ; INT_KBD: ; INTELLIGENT KEYBOARD INTERRUPT HANDLER IN A,(SYS_DTA) ; RET ; FDC_INT: ; FLOPPY DISK CONTROLLER INTERRUPT HANDLER IN A,(PAR_DTB) ; RET ; PAGE ;------------------------------------------------------------------------------ ; RESET INTERRUPT HANDLER ;------------------------------------------------------------------------------ RESET_INT: LD A,0FFH LD (RSTHLD),A ;INDICATE RESET BUTTON PUSHED RET PAGE ;------------------------------------------------------------------------------ ; ; SIO INTERRUPT HANDLERS ; BY ; DAVID ANDREW BERG ; 27 OCTOBER 1982 ; ;------------------------------------------------------------------------------ ; ; SIO CHIP INITIALIZATION PARAMETERS ; ; WR4 IS INITIALIZED TO X16 CLOCK, 1 STOP BIT AND NO PARITY. ; (0100_0100) ; WR3 IS INITIALIZED TO 8 BITS/CHAR, AUTO ENABLES ON AND RX ENABLE. ; (1100_0001) ; WR5 IS INIT'D TO 8 BITS/CHAR, TX ENABLE, RTS AND DTR. ; (1110_1010) ; WR2 IS INIT'D TO THE LOW BYTE OF THE ADDRESS OF THE INTERRUPT ; VECTOR. ; (0FEH) ; ; INTERRUPTS ARE INITIALIZED AS FOLLOWS: ; ; STATUS AFFECTS VECTOR. ; EXTERNAL INTERRUPT IS ENABLED. ; TX INTERRUPT IS ENABLED. ; RX INTERRUPT IS ENABLED TO TRIGGER ON ALL RX CHARS AND PARITY ; AFFECTS VECTOR. ; ; THUS 0001_0111 IS WRITTEN TO WRITE REGISTER 1. ; ; THE I REGISTER IS INITIALIZED BEFORE INIT'ING THE SIO. ; ;--------A---------------------------------------------------------------------- S_R_I_CH_A: ; SIO CHANNEL A RECEIVE INTERRUPT HANDLER ; ; XON/XOFF AND ETX/ACK PROTOCOLS ARE HANDLED WITHIN. ; A_PROTCL INDICATES WHETHER A PROTOCOL IS ENABLED OR NOT: ; ; A_PROTCL = 0 IF NO PROTOCOL IS ENABLED, ; 1 IF XON/XOFF IS ENABLED OR ; 2 IF ETX/ACK IS ENABLED. ; ; IF XON/XOFF IS ENABLED AND XOFF IS RECEIVED, A FLAG IS SET INDICATING TO ; THE TRANSMIT INTERRUPT HANDLER THAT TRANSMITTING IS TO BE STOPPED UNTIL ; XON IS RECEIVED. ; ; WHEN XON IS RECEIVED, THE FLAG IS CLEARED AND IF THE FLAG WAS SET, THE ; TRANSMIT INTERRUPT HANDLER IS CALLED TO RESUME TRANSMISSION. ; ; IF ETX/ACK IS ENABLED AND ACK IS RECEIVED, THE TRANSMIT DISABLE FLAG ; IS RESET AND THE TRANSMIT INTERRUPT HANDLER IS CALLED IF TRANSMISSION ; WAS DISABLED. ; ; IF A PROTOCOL IS ENABLED, ALL PROTOCOL CHARS ARE DISCARDED. ; ; IF NO PROTOCOL IS ENABLED, ALL CHARS ARE BUFFERED. ; ; IN A,(SIO_DTA) ;GET CHARACTER FROM SIO LD C,A ;SAVE IT IN C LD A,(A_PROTCL) ;IS THERE A PROTOCOL ENABLED FOR THIS CHANNEL? OR A ; JP Z,XJ208 ;NO...BUFFER CHAR ; XJ209: ;A PROTOCOL IS ENABLED. DEC A ;IS IT XON/XOFF? JP NZ,XJ210 ;NO, IT MUST BE ETX/ACK. ; ;PROTOCOL IS XON/XOFF. LD A,C ;RESTORE CHAR TO A CP XOFF ;IS IT XOFF? JP NZ,XJ211 ;NO... ; ;YES. DISABLE TRANSMISSION. LD A,0FFH ; LD (A_XMT_OFF),A ;SET XMT DISABLE FLAG RETI ;AND RETURN FROM INTERRUPT. ; XJ211: ;CHAR REC'D IS NOT XOFF. CP XON ;IS IT XON? JP NZ,XJ208 ;NO, BUFFER CHAR AND RETURN FROM INTERRUPT ; ;YES. SEE IF XMT DISABLED. IF IT IS, ENABLE IT ;AND CALL XMT INTERRUPT HANDLER TO RESUME XMT. LD HL,A_XMT_OFF ;POINT AT XMT DISABLE FLAG. XOR A ;CLEAR A CP (HL) ;IS FLAG NOT ZERO? LD (HL),A ;RESET IT REGARDLESS. CALL NZ,S_T_I_CH_A ;IF XMT WAS DISABLED, CALL INTERRUPT HANDLER ;TO RESUME XMT RETI ;AND RETURN FROM INTERRUPT. PAGE XJ210: ;PROTOCOL IS ETX/ACK. LD A,C ;IS CHAR ACK? CP ACK ; JP NZ,XJ208 ;NO. RETURN FROM INTERRUPT AND DISCARD CHAR. ; ;YES. SEE IF XMT DISABLED. IF IT IS, ENABLE IT ;AND CALL XMT INTERRUPT HANDLER TO RESUME XMT. LD HL,A_XMT_OFF ;POINT AT XMT DISABLE FLAG. XOR A ;CLEAR A CP (HL) ;IS FLAG NOT ZERO? LD (HL),A ;RESET IT REGARDLESS. CALL NZ,S_T_I_CH_A ;IF XMT WAS DISABLED, CALL INTERRUPT HANDLER ;TO RESUME XMT RETI ;AND RETURN FROM INTERRUPT. XJ208: ;SAVE CHAR IN C IN BUFFER LD B,S_CH_A_I + HI_PRIOR ; SPECIFY DEVICE AND HIGH PRIORITY CALL FL_B_CH ;BUFFER THE CHAR RETI ;AND RETURN FROM INTERRUPT. PAGE S_R_I_CH_B: ; SIO CHANNEL B RECEIVE INTERRUPT HANDLER ; ; XON/XOFF AND ETX/ACK PROTOCOLS ARE HANDLED WITHIN. ; B_PROTCL INDICATES WHETHER A PROTOCOL IS ENABLED OR NOT: ; ; B_PROTCL = 0 IF NO PROTOCOL IS ENABLED, ; 1 IF XON/XOFF IS ENABLED OR ; 2 IF ETX/ACK IS ENABLED. ; ; IF XON/XOFF IS ENABLED AND XOFF IS RECEIVED, A FLAG IS SET INDICATING TO ; THE TRANSMIT INTERRUPT HANDLER THAT TRANSMITTING IS TO BE STOPPED UNTIL ; XON IS RECEIVED. ; ; WHEN XON IS RECEIVED, THE FLAG IS CLEARED AND IF THE FLAG WAS SET, THE ; TRANSMIT INTERRUPT HANDLER IS CALLED TO RESUME TRANSMISSION. ; ; IF ETX/ACK IS ENABLED AND ACK IS RECEIVED, THE TRANSMIT DISABLE FLAG ; IS RESET AND THE TRANSMIT INTERRUPT HANDLER IS CALLED IF TRANSMISSION ; WAS DISABLED. ; ; IF A PROTOCOL IS ENABLED, ALL PROTOCOL CHARS ARE DISCARDED. ; ; IF NO PROTOCOL IS ENABLED, ALL CHARS ARE BUFFERED. ; ; IN A,(SIO_DTB) ;GET CHARACTER FROM SIO LD C,A ;SAVE IT IN C LD A,(B_PROTCL) ;IS THERE A PROTOCOL ENABLED FOR THIS CHANNEL? OR A ; JP Z,XJ212 ;NO...BUFFER CHAR ; XJ213: ;A PROTOCOL IS ENABLED. DEC A ;IS IT XON/XOFF? JP NZ,XJ214 ;NO, IT MUST BE ETX/ACK. ; ;PROTOCOL IS XON/XOFF. LD A,C ;RESTORE CHAR TO A CP XOFF ;IS IT XOFF? JP NZ,XJ215 ;NO... ; ;YES. DISABLE TRANSMISSION. LD A,0FFH ; LD (B_XMT_OFF),A ;SET XMT DISABLE FLAG RETI ;AND RETURN FROM INTERRUPT. ; XJ215: ;CHAR REC'D IS NOT XOFF. CP XON ;IS IT XON? JP NZ,XJ212 ;NO, BUFFER CHAR AND RETURN FROM INTERRUPT ; ;YES. SEE IF XMT DISABLED. IF IT IS, ENABLE IT ;AND CALL XMT INTERRUPT HANDLER TO RESUME XMT. LD HL,B_XMT_OFF ;POINT AT XMT DISABLE FLAG. XOR A ;CLEAR A CP (HL) ;IS FLAG NOT ZERO? LD (HL),A ;RESET IT REGARDLESS. CALL NZ,S_T_I_CH_B ;IF XMT WAS DISABLED, CALL INTERRUPT HANDLER ;TO RESUME XMT RETI ;AND RETURN FROM INTERRUPT. PAGE XJ214: ;PROTOCOL IS ETX/ACK. LD A,C ;IS CHAR ACK? CP ACK ; JP NZ,XJ212 ;NO. RETURN FROM INTERRUPT AND DISCARD CHAR. ; ;YES. SEE IF XMT DISABLED. IF IT IS, ENABLE IT ;AND CALL XMT INTERRUPT HANDLER TO RESUME XMT. LD HL,B_XMT_OFF ;POINT AT XMT DISABLE FLAG. XOR A ;CLEAR A CP (HL) ;IS FLAG NOT ZERO? LD (HL),A ;RESET IT REGARDLESS. CALL NZ,S_T_I_CH_B ;IF XMT WAS DISABLED, CALL INTERRUPT HANDLER ;TO RESUME XMT RETI ;AND RETURN FROM INTERRUPT. XJ212: ;SAVE CHAR IN C IN BUFFER LD B,S_CH_B_I + HI_PRIOR ; SPECIFY DEVICE AND HIGH PRIORITY CALL FL_B_CH ;BUFFER THE CHAR RETAI ;AND RETURN FROM INTERRUPT. PAGE S_T_I_CH_A: ; SIO CHANNEL A TRANSMIT INTERRUPT HANDLER ; ; XON/XOFF AND ETX/ACK PROTOCOLS ARE HANDLED WITHIN. ; A_PROTCL INDICATES WHETHER A PROTOCOL IS ENABLED OR NOT: ; ; A_PROTCL = 0 IF NO PROTOCOL IS ENABLED, ; 1 IF XON/XOFF IS ENABLED OR ; 2 IF ETX/ACK IS ENABLED. ; ; IF A_XMT_OFF IS SET (0FFH), TRANSMISSION IS DISABLED UNTIL PERMISSION TO ; PROCEED IS RECEIVED. TO DISABLE TRANSMISSION, A RESET TRANSMIT INTERRUPT ; PENDING COMMAND IS GIVEN TO THE SIO. ; ; WHEN THE RECEIVE INTERRUPT HANDLER RECEIVES PERMISSION FROM THE DEVICE TO ; PROCEED (IN THE FORM OF XON OR ACK), IT RESETS THE TRANSMIT DISABLE ; FLAG AND CALLS THIS ROUTINE. ; ; IF ETX/ACK IS ENABLED AND ETX IS TO BE TRANSMITTED, THE TRANSMIT DISABLE FLAG ; IS SET TO PREVENT TRANSMISSION UNTIL ACK IS RECEIVED. ; XJ216 EQU 00101000B ;SIO RESET TRANSMIT INTERRUPT PENDING COMMAND. LD A,(A_XMT_OFF) ;IS XMT DISABLED? OR A ; JP NZ,XJ217 ;YES...RESET TX INTERRUPT ; ;NO. LD B,S_CH_A_O ;ARE THERE CHARS TO SEND? CALL RM_C_ST ; JP Z,XJ218 ;NO...RESET TX INTERRUPT ; ;YES. GET CHAR. LD B,S_CH_A_O ; CALL RM_C_BF ; LD B,A ;SAVE IT IN B LD A,(A_PROTCL) ;IS ETX/ACK PROTOCOL ENABLED? DEC A ;(I.E., A = 2)? DEC A ; LD A,B ;RESTORE CHAR TO A REGARDLESS. JP NZ,XJ219 ;NO ETX... ; ;YES. ETX ENABLED. CP ETX ;IS CHAR ETX? JP NZ,XJ220 ;NO... ; LD A,0FFH ;YES. DISABLE XMT. LD (A_XMT_OFF),A ; LD A,B ;RESTORE CHAR TO REG A FROM B AND SEND IT XJ219: ;ETX/ACK NOT ENABLED XJ220: ;OR ETX NOT SENT ;OR ETX HANDLED, SO SEND CHAR TO SIO OUT (SIO_DTA),A RETI ;AND RETURN FROM INTERRUPT. ; XJ218: LD A,0FFH ;NO CHARS TO SEND. SET FLAG CHECKED BY ;BUFFERING ROUTINE. LD (S_A_FLG),A ;IF FLAG SET, NEXT CHAR BUFFERED IS SENT TO ;SIO IMMEDIATELY TO RESUME TRANSMISSION. ;TRANSMISSION INTERRUPTS ARE NOT REENABLED ;AFTER THE XMT INTERRUPT IS CLEARED UNTIL ;ANOTHER CHARACTER IS SENT TO THE SIO, SO THE ;NEXT CHAR BUFFERED MUST BE SENT TO THE SIO, ;OTHERWISE IT WILL NEVER BE SENT. ;XMT DISABLED BECAUSE OF PROTOCOL. XJ217: LD A,XJ216 ;SEND RESET XMT INT PDG COMMAND OUT (SIO_CNA),A ; OUT (SIO_CNA),A ; RETI ;AND RETURN FROM INTERRUPT. PAGE S_T_I_CH_B: ; SIO CHANNEL B TRANSMIT INTERRUPT HANDLER ; ; XON/XOFF AND ETX/ACK PROTOCOLS ARE HANDLED WITHIN. ; B_PROTCL INDICATES WHETHER A PROTOCOL IS ENABLED OR NOT: ; ; A_PROTCL = 0 IF NO PROTOCOL IS ENABLED, ; 1 IF XON/XOFF IS ENABLED OR ; 2 IF ETX/ACK IS ENABLED. ; ; IF B_XMT_OFF IS SET (0FFH), TRANSMISSION IS DISABLED UNTIL PERMISSION TO ; PROCEED IS RECEIVED. TO DISABLE TRANSMISSION, A RESET TRANSMIT INTERRUPT ; PENDING COMMAND IS GIVEN TO THE SIO. ; ; WHEN THE RECEIVE INTERRUPT HANDLER RECEIVES PERMISSION FROM THE DEVICE TO ; PROCEED (IN THE FORM OF XON OR ACK), IT RESETS THE TRANSMIT DISABLE ; FLAG AND CALLS THIS ROUTINE. ; ; IF ETX/ACK IS ENABLED AND ETX IS TO BE TRANSMITTED, THE TRANSMIT DISABLE FLAG ; IS SET TO PREVENT TRANSMISSION UNTIL ACK IS RECEIVED. ; XJ221 EQU 00101000B ;SIO RESET TRANSMIT INTERRUPT PENDING COMMAND. LD A,(B_XMT_OFF) ;IS XMT DISABLED? OR A ; JP NZ,XJ222 ;YES...RESET TX INTERRUPT ; ;NO. LD B,S_CH_B_O ;ARE THERE CHARS TO SEND? CALL RM_C_ST ; JP Z,XJ223 ;NO...RESET TX INTERRUPT ; ;YES. GET CHAR. LD B,S_CH_B_O ; CALL RM_C_BF ; LD B,A ;SAVE IT IN B LD A,(B_PROTCL) ;IS ETX/ACK PROTOCOL ENABLED? DEC A ;(I.E., A = 2)? DEC A ; LD A,B ;RESTORE CHAR TO A REGARDLESS. JP NZ,XJ224 ;NO ETX... ; ;YES. ETX ENABLED. CP ETX ;IS CHAR ETX? JP NZ,XJ225 ;NO... ; LD A,0FFH ;YES. DISABLE XMT. LD (B_XMT_OFF),A ;AND SEND CHAR... LD A,B ;RESTORE CHAR TO REG A FROM B AND SEND IT XJ224: ;ETX/ACK NOT ENABLED XJ225: ;OR ETX NOT SENT ;OR ETX HANDLED, SO SEND CHAR TO SIO OUT (SIO_DTB),A RETI ;AND RETURN FROM INTERRUPT. ; XJ223: LD A,0FFH ;NO CHARS TO SEND. SET FLAG CHECKED BY ;BUFFERING ROUTINE. LD (S_B_FLG),A ;IF FLAG SET, NEXT CHAR BUFFERED IS SENT TO ;SIO IMMEDIATELY TO RESUME TRANSMISSION. ;TRANSMISSION INTERRUPTS ARE NOT REENABLED ;AFTER THE XMT INTERRUPT IS CLEARED UNTIL ;ANOTHER CHARACTER IS SENT TO THE SIO, SO THE ;NEXT CHAR BUFFERED MUST BE SENT TO THE SIO, ;OTHERWISE IT WILL NEVER BE SENT. ;XMT DISABLED BECAUSE OF PROTOCOL. XJ222: LD A,XJ221 ;SEND RESET XMT INT PDG COMMAND OUT (SIO_CNB),A ; OUT (SIO_CNB),A ; RETI ;AND RETURN FROM INTERRUPT. PAGE ;------------------------------------------------------------------------------ ; OTHER SIO INTERRUPT HANDLERS ;------------------------------------------------------------------------------ ; EXTERNAL/STATUS INTERRUPT HANDLER FOR CHANNEL A ; ; RESET EXT/STATUS INTERRUPT AND RETURN ; EXT_CH_A: XJ226 EQU 010H ;RESET EXT/STATUS INTERRUPT COMMAND LD A,XJ226 ;SEND RESET COMMAND OUT (SIO_CNA),A ;SEND TO SIO OUT (SIO_CNA),A ;TWICE TO ACCOUNT FOR BUG IN CHIP RETI PAGE ;-------------------------------------------------------------------------A----- ; EXTERNAL/STATUS INTERRUPT HANDLER FOR CHANNEL B ; ; RESET EXT/STATUS INTERRUPT AND RETURN ; EXT_CH_B: XJ227 EQU 010H ;RESET EXT/STATUS INTERRUPT COMMAND LD A,XJ227 ;SEND RESET COMMAND OUT (SIO_CNB),A ;SEND TO SIO OUT (SIO_CNB),A ;TWICE TO ACCOUNT FOR BUG IN CHIP RETI PAGE CH_B_SPEC: ; SPECIAL RX CONDITION ON CHANNEL B XJ228 EQU 30H ;ERROR RESET COMMAND LD A,XJ228 ;SEND ERROR RESET OUT (SIO_CNB),A ; OUT (SIO_CNB),A ;TWICE TO ACCOUNT FOR BUG IN CHIP IN A,(SIO_DTB) ;READ CHAR AND DISCARD RETI PAGE CH_A_SPEC: ; SPECIAL RX CONDITION ON CHANNEL A XJ229 EQU 30H ;ERROR RESET COMMAND LD A,XJ229 ;SEND ERROR RESET OUT (SIO_CNA),A ; OUT (SIO_CNA),A ;TWICE TO ACCOUNT FOR BUG IN CHIP IN A,(SIO_DTA) ;READ CHAR AND DISCARD RETI PAGE SPEC_HD: ; SPECIAL HANDLING ROUTINE CALLED BY FILL BUFFER WITH CHAR ROUTINE ; IF SPECIAL HANDLING BIT (6) OF REGISTER B IS SET. ; ; CURRENTLY THIS IS USED TO RE-ENABLE SIO TX INTERRUPTS AFTER THEY ; HAVE BEEN DISABLED BECAUSE THERE WAS NO CHARACTER TO TRANSMIT. ; ; THIS ROUTINE IS CALLED AFTER THE CHARACTER HAS BEEN BUFFERED ; IMMEDIATELY BEFORE RETURNING FROM THE BUFFER FILL ROUTINE. ; ENTRY: ; B = NUMBER OF DEVICE THAT WAS FILLED WITH CHAR. ; C = CHARACTER THAT WAS PUT INTO BUFFER. ; ; EXIT: ; SIO INTERRUPTS RE-ENABLED BY CALLING SIO TX INTERRUPT HANDLER ; IF NECESSARY. ; LD A,B ;PUT DEVICE NO. IN A AND 00111111B ;STRIP OFF PRIORITY AND SPECIAL HANDLING BITS CP S_CH_A_O ;IS DEVICE SIO CHANNEL A OUTPUT? JR NZ,XJ230 ;NO, SEE IF IT IS CHANNEL B DEVICE ; ;YES. SEE IF INTERRUPTS NEED TO BE RE-ENABLED LD A,(S_A_FLG) ;LOAD CHANNEL A FLAG OR A ;IS IT SET? RET Z ;NO, RETURN ; ;YES. XOR A ;RESET FLAG LD (S_A_FLG),A ; CALL S_T_I_CH_A ;AND CALL INTERRUPT HANDLER, WHICH WILL ;TRANSMIT CHAR IN BUFFER, THEREBY RE-ENABLING ;INTERRUPTS. RET ;RETURN TO CALLER ; XJ230: ;DEVICE IS NOT SIO TX CHANNEL A. CP S_CH_B_O ;IS IT CHANNEL B? RET NZ ;NO, RETURN ; LD A,(S_B_FLG) ;YES. IS FLAG SET? OR A ; RET Z ;NO, RETURN. ; XOR A ;YES. CLEAR FLAG LD (S_B_FLG),A ; CALL S_T_I_CH_B ;CALL CH. B INTERRUPT HANDLER. RET ;AND RETURN PAGE ; KEYBOARD HANDLER FOR SHELLY ; INITIAL IMPLEMENTATION FOR USE IN TRESCA ; DAB 9/9/82 V ; RTC_INT: ; ;REAL TIME CLOCK INTERRUPT HANDLER ;ENTRY ;NONE ;EXIT ;KEYBOARD SCAN, RTC MAINTENANCE AND DISK CHANGE DETECT PROCESSING DONE PAGE ;------------------------------------------------------------------------------ ; REAL TIME CLOCK DRIVER BY DAVID ANDREW BERG ;------------------------------------------------------------------------------ RTC_DRV: LD HL,LAST_TCK ; PT TO LAST,DCHK,SYS LD B,(HL) ;LOA LAS TIC OVERFLO VALUE IN A,(RTC_OFL) ;GET CURRENT TICK OVERFLOW VALUE LD (HL),A ;SAVE IT AS LAST SUB B ;COMPUTE DIFFERENCE BETWEEN CURRENT TICK AND: ;LAST: TICKS OCCURRED. LD C,A ;SAVE TICKS OCCURRED ;IS THE TICK RATE 50 OR 60 HZ? INC HL  LD A,(HL) SUB C JR NC,NOTNOW XOR A NOTNOW: LD (HL),A LD B,SIXTY_HZ ;ASSUME IT'S SIXTY. ;CHECK PIA IN A,(SYS_CNB) ; BIT 3,A ;BIT 3 IS 0 IF 60 HZ JP Z,XJ072 ;IT'S 60... ; LD B,FIFTY_HZ ;NO, IT'S 50. XJ072: LD A,C ;RESTORE TICKS OCCURRED ;C = SECONDS TO ADD LD C,0 ;ZERO SECONDS TO ADD XJ073: ;SEE IF WE LOST ANY SECONDS: IS TICKS OCCURRED ;=> TICK RATE? CP B ; JP C,XJ074 ;NO... ; SUB B ;YES. REDUCE TICKS OCCURRED BY TICK RATE INC C ;AND BUMP SECONDS TO ADD JP XJ073 ;LOOP AGAIN TO SEE IF MORE SECONDS LOST ; XJ074: ;A = TICKS OCCURRED MOD TICK RATE (TICKS TO ADD) ;C = SECONDS LOST, LD D,A ;PUT TICKS TO ADD IN D LD A,(SYS_TICKS) ;LOAD LAST SYSTEM TICK COUNT. ADD A,D ;ADD TICKS TO ADD CP B ;IS SYS TICKS => TICK RATE? (I.E, SECOND OVERFLOW?) JP C,XJ075 ;NO... ; SUB B ;YES. REDUCE SYSTICKS BY TICK RATE INC C ;AND BUMP SECONDS TO ADD XJ075: ;A = SYSTICKS, C = SECONDS TO ADD LD (SYS_TICKS),A ;SAVE SYSTEM TICK COUNT XOR A ;CLEAR A TO CHECK FOR 0 SECONDS TO ADD OR C ;IS C (SECONDS TO ADD) 0? JR Z,XJ076 ;NO. RETURN... ; ;YES. GET POINTER TO CLOCK DATA STRUCTURE ;POINTER POINTS TO SECONDS CELL, THE LAST ;ENTRY IN THE STRUCTURE. LD HL,(CLK_PTR) ;LOAD POINTER TO CLOCK TO HL. ;HL ==> SECONDS CELL LD A,(HL) ;GET SYSTEM SECOND COUNT ADD A,C ;ADD SECONDS TO SYS SECONDS DAA ;BCD ADJUST IT. LD (HL),A ;SAVE SYS SECONDS SUB SEC_MIN ;CHECK FOR SECOND OVERFLOW. JR C,XJ076 ;NO OVERFLOW, RETURN ; LD (HL),A ;OVERFLOW. REDUCE SECONDS BY SECONDS/MINUTE ;AND SAVE DEC HL ;POINT TO MINUTES CELL LD A,(HL) ;LOAD SYSTEM MINUTE COUNT INC A ;BUMP IT. DAA ;BCD ADJUST IT LD (HL),A ;SAVE IT CP MIN_HR ;IS IT = MINUTES/HR? JR NZ,XJ076 ;NO, RETURN ; LD (HL),0 ;YES. CLEAR MINUTE DEC HL ;POINT HL TO HOUR CELL LD A,(HL) ;BUMP HOUR INC A ; DAA ; LD (HL),A ;SAVE IT CP HR_DAY ;IS IT = HOURS/DAY? JR NZ,XJ076 ;NO. RETURN ; LD (HL),0 ;YES. CLEAR HOUR A DEC HL ;POINT TO LOW BYTE OF DAY DEC HL ; INC (HL) ;INCREMENT LOW BYTE. ;IS THERE AN OVERFLOW TO HIGH BYTE? JR NZ,XJ076 ;NO, RETURN... ; INC HL ;YES. POINT TO HI BYTE INC (HL) ;BUMP IT PAGE ;--------------------------------------------------------------------------- ; DISK CHANGE DETECT ROUTINE ; BY ROGER W. CHAPMAN & YOUN MOO KIM ; ; THIS ROUTINE CALLS A ROUTINE IN COMMON MEMORY ; IF A DISK CHANGE IS DETECTED WHICH MODIFIES THE ; APPROPRIATE BIOS & BDOS VARIABLES. ; ; VARIABLES USED : ; WP_STS BIT 7 = WRITE PROTECT STATUS A DRIVE ; BIT 6 = WRITE PROTECT STATUS B DRIVE ; ; EXIT PARAMETERS : ; MEDIA FLAG(SCB) = 0FFH IF CHANGE IN STATUS DETECTED ; DRIVE A FLAG = 0FFH IF CHANGE IN A STATUS ; DRIVE B FLAG = 0FFH IF CHANGE IN B STATUS ;--------------------------------------------------------------------------- XJ076: IN A,(DSK_STS) ;GET FDC STATUS RRA ;BUSY ? JR C,XJ077 ;YES- DO NOT ISSUE FORCE INTERRUPT LD A,D.FINT ;ISSUE FORCE INTERRUPT COMMAND FOR DISK CHANGE DETECT OUT (DSK_CMD),A ;SHOULD WAIT 112T BEFORE READ FDC STATUS LD A,(DCHK_FLG) ;(13) IS IT TIME TO CHECK FOR CHANGE? OR A ;(4) JR NZ,XJ077 ;(7) NO, NOT YET LD A,20 ;(7) WAIT 1/3 SEC FOR NEXT CHECK LD (DCHK_FLG),A ;(13) SAVE IT LD HL,WP_STS ;(10) TO GET OLD & SAVE NEW STATUS INFO LD B,(HL) ;(7) GET OLD WRITE PRTECT STATUS LD A,(DRV_MSK) ;(13) GET DRIVE MASK (LOGICAL TO PHYSICAL) LD E,A ;(4) IN A,(SYS_DTB) ;(11) GET CURRRENT SYSTEM PIA STATUS LD C,A ;(4) & SAVE IT FOR LATER AND 0F8H ;(7) SAVE NON-DRIVE BITS OR E ;(4) FIRST EXAMINE DRIVE A STATUS LD E,A ;(4) SAVE FOR LATER OUT (SYS_DTB),A ;(11) SELECT DRIVE & MFM IN A,(DSK_STS) ;READ DRIVE A STATUS LD D,A ;& SAVE IT LD A,E ;NOW EXAMINE DRIVE B STATUS XOR 6 OUT (SYS_DTB),A ;SELECT DRIVE & MFM IN A,(DSK_STS) ;READ DRIVE B STATUS LD E,A ;& SAVE IT LD A,C ;RESTORE SYSTEM PIA OUT (SYS_DTB),A LD A,D ;GET A STATUS RLA ;MOVE BIT 6 TO BIT 7 AND 10000000B ;JUST WANT BIT 7 LD D,A ;SAVE IT LD A,E ;GET B STATUS AND 01000000B ;JUST WANT BIT 6 OR D ;FORM NEW STATUS BYTE LD (HL),A ;& SAVE IT XOR B ;COMPARE WITH OLD STATUS JP Z,XJ077 ;NO CHANGE DETECTED GO TO RTC_DRV LD HL,(MEDIA) ;GET ADDRESS OF MEDIA FLAG LD (HL),0FFH ;& SET IT BIT 7,A ;CHECK DRIVE A STATUS CHANGE JR Z,B_CHNG ;DRIVE A NOT CHANGED LD HL,(A_DRIVE) ;GET ADDRESS OF DRIVE A FLAG LD (HL),0FFH ;& SET IT BIT 6,A ;CHECK DRIVE B STATUS CHANGE JP Z,XJ077 ;NO CHANGE GO TO DONE B_CHNG: LD HL,(B_DRIVE) ;GET ADDRESS OF DRIVE B FLAG LD (HL),0FFH ;& SET IT PAGE ;ROUTINE CHECKS TO SEE IF THE DISK DRIVE MOTOR SHOULD BE TURNED OFF BY UPDATING DACTIVE...ROUTINE ALSO XJ077: LD HL,DACTVE LD A,(HL) OR A JR Z,XJ078 ;IF INACTIVE ;TURN DRIVE OFF IF DACTVE = 1 DEC (HL) ;RESET DELAY JR NZ,XJ078 ;IF DESELECT DRIVE ;DESELECT DRIVE IN A,(SYS_DTB) OR 00000110B ;DESELECT DRIVES OUT (SYS_DTB),A ;READ KEYBOARD XJ078: LD A,(KEYLCK) OR A CALL NZ,KBDRVR ;READ KEYBOARD IF KEYLOCK NOT ACTIVE IN A,(SYS_DTB) ;CLEAR INTERRUPT RET PAGE ; ********************************************************* ; * * ; * INTERRUPT TABLE * ; * * ; ********************************************************* ;------------------------------------------------------------------------------ ; ROM COPY OF INTERRUPT TABLE ;------------------------------------------------------------------------------ ; EACH TABLE ENTRY CONSISTS OF A ONE BYTE BANK SWITCH MASK (IN THIS ; CASE, ALL TO SWITCH IN THE ROM) FOLLOWED BY A TWO BYTE INTERRUPT ; HANDLING ROUTINE ADDRESS. ; ; THE SIO ENTRIES ARE IN THE ORDER CORRESPONDING TO THE BIT PATTERN SET ; IN RR2 ON AN INTERRUPT. ; R_INT_TBL: DB ROM_BANK ;SIO TX CHANNEL B DW S_T_I_CH_B ; DB ROM_BANK ;SIO EXTERNAL/STATUS CHANNEL B DW EXT_CH_B ; DB ROM_BANK ;SIO RX CHANNEL B DW S_R_I_CH_B ; DB ROM_BANK ;SIO RX CHANNEL B SPECIAL CONDITION DW CH_B_SPEC ; DB ROM_BANK ;SIO TX CHANNEL A DW S_T_I_CH_A ; DB ROM_BANK ;SIO EXTERNAL/STATUS CHANNEL A DW EXT_CH_A ; DB ROM_BANK ;SIO RX CHANNEL A DW S_R_I_CH_A ; DB ROM_BANK ;SIO RX CHANNEL A SPECIAL CONDITION DW CH_A_SPEC ; DB ROM_BANK ;REAL TIME CLOCK (TICK) INTERRUPT DW RTC_INT ; DB ROM_BANK ;PARALLEL ENTRY DW PAR_INT ; DB ROM_BANK ;INTELLIGENT KEYBOARD DW INT_KBD ; DB ROM_BANK ;DMA ENTRY DW DMA_INT ; DB ROM_BANK ;FLOPPY DISK CONTROLLER DW FDC_INT ; DB ROM_BANK ;SYSTEM RESET DW RESET_INT ; R_I_TBL_END EQU $ R_I_TBL_LEN EQU R_I_TBL_END - R_INT_TBL  PATTERN SET ; IN RR2 ON AN INTERRUPT. ; R_INT_TBL: DB ROM_BANK ;SIO TX CHANNEL B DW S_T_I_CH_B ; DB ROM_BANK ;SIO EXTERNAL/STATUS CHANNEL B DW EXT_CH_B ; DB ROM_BANK ;SIO RX CHANNEL B DW S_R_I_CH_B ; DB ROM_BANK ;SIO RX CHANNEL B A SUBTTL 'BUFFER HANDLING ROUTINES' ; ; 83-07-18 Fixed the buffer allocation problem in IN_AL_BF and RM_C_BF ; ; ********************************************************* ; * * ; * BUFFERING ROUTINES * ; * * ; ********************************************************* ; ; MODULE 7 --ROM7-- ENTRY POINTS ; ; BUFFERING ROUTINES ; ; IN_AL_BF: INITIALIZE ALL BUFFERS TO NULLS AND PUT ON FREE LIST ; FL_B_ST: RETURNS BUFFER STATUS (BUFFER FULL OR NOT) ; FL_B_CH: INSERT CHAR. IN BUFFER ; RM_C_BF: REMOVE CHAR. FROM BUFFER ; RM_C_ST: RETURNS BUFFER STATUS (BUFFER EMPTY OR NOT) ; FIL_BUF: RETURNS ADDRESS OF CURRENT FILL BUFFER ; RMV_BUF: RETURNS ADDRESS OF CURRENT REMOVE BUFFER ; DEV_ROOT: RETURNS ADDRESS OF DEVICE LIST ROOT ; BUF_INIT: INITIALIZES BUFFER HEADER ; ALC_BUF: ALLOCATE BUFFER IF AVAILABLE ; ALC_ST: CHECKS BUFFER ALLOCATION STATUS ; D_ALC_BF: DEALLOCATE BUFFER--RETURN TO FREE LIST PAGE .Z80 .XLIST ; INCLUDE SYSS1.MAC ;SYSTEST FILE ; INCLUDE RAMSMON.MAC ;MONITOR RAM MEMORY LOCATIONS ; INCLUDE RAMS10.MAC ;RAM MEMORY LOCATIONS AND CONSTANTS .LIST ;SYSS1.MAC , RAMSMON.MAC AND RAMS10.MAC INCLUDED ; EXT SPEC_HD ; PUBLIC IN_AL_BF,FL_B_ST,FL_B_CH,RM_C_BF,RM_C_ST CSEG PAGE ;------------------------------------------------------------------------------ ; ; CHARACTER I/O BUFFERING ROUTINES ; BY ; DAVID ANDREW BERG ; 10/5/82 ; ;------------------------------------------------------------------------------ ; THESE ROUTINES IMPLEMENT A SERIAL I/O BUFFERING SCHEME USING DYNAMIC ; BUFFER ALLOCATION. IN PRACTICE, EACH DEVICE WILL HAVE A LIST OF BUFFERS ; (WHICH MAY BE EMPTY) ASSOCIATED WITH IT. CHARACTERS MAY BE ADDED TO THE ; END OF THE BUFFER LIST AND REMOVED FROM THE BEGINNING. MORE BUFFERS ; ARE DYNAMICALLY ALLOCATED UPON DEMAND. BUFFERS ARE REMOVED FROM THE ; LIST WHEN ALL CHARACTERS HAVE BEEN REMOVED FROM THEM. ; ; ROUTINES ARE ALSO IMPLEMENTED TO OBTAIN THE STATUS OF A DEVICE: WHETHER ; THERE ARE CHARACTERS WAITING TO BE REMOVED AND IF THERE IS ROOM IN ; THE BUFFER FOR MORE CHARACTERS. ; ; IN PRACTICE IF INTERRUPT HANDLERS ALLOCATE BUFFERS, THEN STATUS ; CHECKS WILL BE VALID ONLY IF INTERRUPTS ARE DISABLED. ; ; 11/5/82: DAB: ; A. CHANGED FL_B_CH TO INTERPRET BIT 6 OF THE DEVICE NUMBER ; AS A FLAG INDICATING THAT THE BUFFER FILL NEEDS SPECIAL ; HANDLING. THIS IS IMPLEMENTED PRIMARILY FOR HANDLING SIO ; TRANSMISSION. IF THE SIO INTERRUPTS WITH A TX BUFFER EMPTY ; CONDITION AND THERE ARE NO CHARS READY TO TRANSMIT, THE TX ; BUFFER EMPTY INTERRUPT MUST BE DISABLED, OTHERWISE IT WILL ; CONTINUOUSLY INTERRUPT AND LOCK THE PROCESSOR INTO THE ; INTERRUPT HANDLERS. ; ; ON THE OTHER HAND, IF THIS INTERRUPT IS DISABLED, IT WILL ; NEVER INTERRUPT TO REMOVE CHARS FROM THE BUFFER WHEN THERE ARE ; SOME READY. THUS, THE INTERRUPT HAS TO BE RE-ENABLED WHEN A ; CHARACTER IS PUT INTO THE BUFFER. ; ; THIS FLAG BIT IMPLEMENTATION ALLOWS THIS: WHEN BIOS CALLS ; THE BUFFERING ROUTINE TO BUFFER A CHAR, IT WILL SET THE FLAG. ; THE SPECIAL HANDLING ROUTINE WILL THEN CHECK TO SEE IF ; INTERRUPTS HAVE BEEN DISABLED AND IF SO WILL RE-ENABLE THEM. ; ; B. FIX BUG IN IN_AL_BF. IT CLEARED ONE TOO MANY BYTES OF ; BUFFER SPACE. ; ; 11/4/82: DAB: ; A. CHANGED RM_C_BF TO ALWAYS RETURN A CHARACTER. IT MUST NOT ; BE CALLED UNLESS THERE IS A CHARACTER READY. IN OTHER WORDS, ; RM_C_BF MUST NOT BE CALLED UNLESS RM_C_ST RETURNS ; POSITIVE STATUS. ; ; B. FL_B_ST AND FL_B_CH ARE CHANGED SO THAT THE HIGH BIT OF ; THE DEVICE NUMBER PASSED IN B INDICATES THE PRIORITY OF THE ; DEVICE. IF THE BIT IS SET THE DEVICE HAS HIGH PRIORITY AND ; CAN ALLOCATE BUFFERS BELOW THE SPECIFIED THRESHOLD (SEE BELOW). ; IF THE BIT IS CLEAR, THE DEVICE HAS LOW PRIORITY AND CAN NOT ; ALLOCATE BUFFERS BELOW THE THRESHOLD. THIS IS DONE TO REDUCE ; THE PROBABILITY OF AN INFORMATION LOSS CAUSED BY AN ; INTERRUPTING INPUT DEVICE NOT HAVING A BUFFER IN WHICH TO ; STORE A CHARACTER. INTERRUPTING INPUT DEVICES ARE ASSIGNED ; HIGH PRIORITY AND ALL OTHERS ARE ASSIGNED LOW PRIORITY. ; ; THE THRESHOLD LEVEL IS THE MINIMUM NUMBER OF BUFFERS THAT ; SHOULD BE AVAILABLE FOR HIGH PRIORITY DEVICES ONLY. IT IS AN ; ASSEMBLY TIME PARAMETER CHECKED BY THE BUFFER ALLOCATION AND ; BUFFER ALLOCATION STATUS ROUTINES. ; ;------------------------------------------------------------------------------ PAGE ;------------------------------------------------------------------------------ ; FUNCTIONS: ; ; FILL DEVICE BUFFER WITH CHARACTER ; REMOVE CHARACTER FROM DEVICE BUFFER ; RETURN FILL STATUS OF DEVICE BUFFER (ROOM FOR MORE CHARS?) ; RETURN REMOVE STATUS OF DEVICE BUFFER (CHARS TO REMOVE?) ; RETURN NUMBER OF BYTES AVAILABLE IN DEVICE BUFFER ; RETURN BUFFER ALLOCATION STATUS (ARE THERE BUFFERS AVAILABLE TO ; ALLOCATE) ; ALLOCATE BUFFER ; DE-ALLOCATE BUFFER ; INITIALIZE BUFFERS ;-------------------------------A----------------------------------------------- PAGE ;------------------------------------------------------------------------------ ; DATA STRUCTURES: ; ; EACH DEVICE HAS A BUFFER LIST ROOT: ; ; +-------------------+ ; | POINTER TO FILL | ; | BUFFER | ; +-------------------+ ; | POINTER TO REMOVE | ; | BUFFER | ; +-------------------+ ; ; WHOSE FIRST ENTRY IS A POINTER TO THE DEVICE'S FILL BUFFER, THE BUFFER ; IN WHICH TO PUT CHARACTERS. ; ; THE SECOND ENTRY IS A POINTER TO THE DEVICE'S REMOVE BUFFER, THE ; BUFFER FROM WHICH TO REMOVE CHARACTERS. ; ; EITHER POINTER WILL BE NIL IF THERE IS NO CORRESPONDING BUFFER. ; ; +-------------------+ ; : DEVICE 0 : KEYBOARD ; +-------------------+ ; : DEVICE 1 : RX - SIO CHA ; +-------------------+ ; : DEVICE 2 : RX - SIO CHB ; +-------------------+ ; : DEVICE 3 : TX - SIO CHA ; +-------------------+ ; : DEVICE 4 : TX - SIO CHB ; +-------------------+ ;------------------------------------------------------------------------------ PAGE ;------------------------------------------------------------------------------ ; BUFFER: ; ; A BUFFER HAS ONE OF TWO FORMATS DEPENDING ON WHETHER IT IS ALLOCATED ; OR NOT. ; ; AN ALLOCATED BUFFER HAS THE FOLLOWING FORMAT: ; ; +--------------+ ; | POINTER TO | ; | NEXT REMOVE | ; | BUFFER | ; +--------------+ ; | BUFFER FILL | ; | INDEX | ; +--------------+ ; | BUFFER REMOVE| ; | INDEX | ; +--------------+ ; | BUFFER DATA | ; | AREA | ; +--------------+ ; ; THE FIRST ENTRY POINTS TO THE NEXT REMOVE BUFFER (FROM WHICH TO ; REMOVE CHARACTERS) IN THE LIST. IT IS NIL IF THERE IS NO NEXT. ; ; THE SECOND ENTRY IS AN INDEX TO THE NEXT LOACTION IN THE BUFFER IN ; WHICH TO FILL IN NEW CHARS (I.E., WHERE TO PUT CHARS IN THE BUFFER) ; ; THE THIRD ENTRY IS AN INDEX TO THE NEXT LOCATION FROM WHICH TO REMOVE ; CHARS (I.E., WHERE TO TAKE CHARS FROM BUFFER). ; ; ; AN UNALLOCATED BUFFER (I.E., ONE IN THE FREE LIST) HAS THE FOLLOWING ; FORMAT: ; ; +--------------+ ; | POINTER TO | ; | NEXT FREE | ; | BUFFER | ; +--------------+ ; | UNDEFINED | ; | | ; +--------------+ ; | UNDEFINED | ; | | ; +--------------+ ; | UNDEFINED | ; | | ; +--------------+ ; ; THE FIRST ENTRY IS A POINTER TO THE NEXT FREE BUFFER, IF ANY. IT ; IS UNDEFINED IF THERE IS NO NEXT FREE BUFFER. THE NUMBER OF FREE ; BUFFERS IS TRACKED BY THE COUNT IN THE FREE LIST ROOT. ; ; ALL OTHER ENTRIES IN THE BUFFER ARE UNDEFINED IN A FREE BUFFER. ;------------------------------------------------------------------------------ PAGE ;------------------------------------------------------------------------------ ; FREE LIST ROOT: ; ; THE FREE LIST ROOT IS A DATA STRUCTURE CONTAINING TWO ELEMENTS: ; ; +------------------+ ; | POINTER TO FIRST | ; | FREE BUFFER | ; +------------------+ ; | NUMBER OF FREE | ; | BUFFERS | ; +------------------+ ; ; THE FIRST ENTRY IS A POINTER TO THE FIRST FREE BUFFER. IF THERE ARE ; MORE THAN ONE BUFFER, EACH FREE BUFFER POINTS TO NEXT. SEE BUFFER ; DESCRIPTION ABOVE. ; ; THE SECOND ENTRY IS A COUNT OF THE NUMBER OF BUFFERS IN THE LIST. ;------------------------------------------------------------------------------ PAGE IN_AL_BF: ; INITIALIZES ALL BUFFERS TO NULLS AND PUTS ALL ON FREE LIST. ; ; ENTRY: ; NONE. ; ; EXIT: ; ALL BUFFERS ARE INITIALIZED AND PUT ON FREE LIST ; ; REGISTERS AFFECTED: ; ; GROSS_BF EQU MX_CH_BF + BF_OV_HD ;GROSS BUFFER SIZE (DATA AREA + OVERHEAD) KEY_RT EQU D_RT_TBL+KBD_DEV*D_RT_LEN ;START OF KEYBOARD ROOT TABLE KEY_BF EQU BUFF_ST+KBD_DEV*GROSS_BF ;INITIAL DEDICATED KEYBOARD BUF ; 7/22/AOS ; ASSIGN THE FIRST BUFFER TO THE KEYBOARD ; (I.E. INIT THE KEYBOARD DEVICE ROOT TO POINT TO A BUFFER) ; LD HL,KEY_RT ;GET PNTR TO TOP OF KEYBOARD ROOT TABLE TO HL LD DE,KEY_BF ; AND PNTR TO DEDICATED KEYBOARD BUF IN DE LD (HL),E ;INIT PNTR TO FILL BUF INC HL ; IN KEYBOARD ROOT TABLE LD (HL),D INC HL LD (HL),E ;INIT PNTR TO REMOVE BUF INC HL ; IN KEYBOARD ROOT TABLE LD (HL),D INC HL ;BUMP PNTR TO INIT THE # OF CHARS. ; IN KEYBOARD BUFS AND THE REST ; OF THE ROOT TABLE ; ; INIITIALIZE THE REST OF THE DEVICE ROOTS ; LD D,H ;POINT DE TO 1 BEFORE HL LD E,L ; AND INIT THE COUNT FOR LDIR INC DE LD BC,D_RT_LEN*(NO_DEVS-1)+1 LD (HL),0 LDIR ;COMPUTE SIZE OF AREA TO CLEAR: LD HL,0 ;ZERO HL LD DE,GROSS_BF ;LOAD DE WITH GROSS BUFFER SIZE LD B,NO_BUFS ;LOAD B WITH NO. OF BUFFERS XJ231: ADD HL,DE ;MULTIPLY GROSS BUFFER SIZE TIMES NO_BUFS ;BY ADDING DJNZ XJ231 ;TILL B = 0 LD B,H ;MOVE TOTAL TO BC FOR LDIR LD C,L ; DEC BC ;REDUCE COUNT BY ONE SINCE FIRST CELL GETS 11/5B ;CLEARED DIRECTLY 11/5B LD HL,BUFF_ST ;POINT HL TO FIRST BUFFER START LD DE,BUFF_ST+1 ;AND HL ONE PAST LD (HL),0 ;CLEAR FIRST CELL OF FIRST BUFFER LDIR ;AND ALL THE REST ;POINT EACH BUFFER TO THE NEXT:A  LD DE,BUFF_ST+GROSS_BF ;POINT DE AT FIRST BUFFER 7/22/AOS LD HL,GROSS_BF ;LOAD HL WITH GROSS BUFFER SIZE TO ADD HL,DE ;COMPUTE ADDRESS OF NEXT BUFFER LD B,NO_BUFS-2 ;LOAD B WITH NO. BUFFERS - 2 7/22/AOS XJ232: EX DE,HL ;NOW HL ==> 'CURRENT' BUFFER, DE ==> NEXT ;BUFFER LD (HL),E ;STORE PTR TO NEXT IN CURRENT INC HL ; LD (HL),D ; LD HL,GROSS_BF ;LOAD HL WITH INCREMENT TO NEXT BUFFER ADD HL,DE ;COMPUTE ADDR OF NEXT, DE NOW = CURRENT BUFFER ;HL = NEXT DJNZ XJ232 ;LOOP TILL B = 0: ALL BUFFERS POINT TO NEXT ;EXCEPT THE LAST. ; EX DE,HL ;NOW HL ==> CURRENT LD (HL),0 ;CLEAR PTR (SET TO NIL) INC HL ; LD (HL),0 ; LD HL,BUFF_ST+GROSS_BF ;POINT FREE LIST ROOT TO 7/22/AOS LD (FRE_ADDR),HL ; FIRST FIRST BUFFER LD A,NO_BUFS-1 ;INIT FREE BUFFER COUNT CELL LD (FRE_ADDR+2),A ; TO # OF BUFS - 1(DEDICATED KEYBOARD BUF) RET ;AND RETURN TO CALLER PAGE FL_B_ST: ; RETURNS FILL STATUS FOR DEVICE INDICATED BY B. Z IS SET IF THERE ; IS NO ROOM FOR ANOTHER CHARACTER. ; ; THE HIGH BIT OF B IS SET IF THE DEVICE HAS HIGH PRIORITY. ; ; IF THERE IS NO FILL BUFFER FOR DEVICE B, BUFFER ALLOCATION STATUS ; IS RETURNED. ; ; OTHERWISE IF THE FILL INDEX FOR THE DEVICE'S FILL BUFFER IS NOT ; EQUAL TO THE MAXIMUM CHARS IN A BUFFER, 'GOOD' STATUS IS RETURNED. ; ; OTHERWISE BUFFER ALLOCATION STATUS IS RETURNED (THERE IS NO ROOM IN ; THE CURRENT BUFFER). ; ; ENTRY: ; B = NUMBER OF DEVICE FOR WHICH STATUS IS DESIRED. ; THE HIGH BIT OF B IS SET IF THE DEVICE HAS HIGH PRIORITY. ; HI BIT IS SET IF THE DEVICE IS HIGH PRIORITY. ; HI BIT IS SET IF THE DEVICE IS HIGH PRIORITY. ; ; EXIT: ; Z BIT IS SET IF THERE NO ROOM FOR ANOTHER CHARACTER ('BAD') ; Z BIT IS CLEAR IF THERE IS ROOM. ; ; REGISTERS AFFECTED: ; CALL FIL_BUF ;GET ADDRESS OF DEVICE'S FILL BUFFER TO HL ;RETURNS Z SET IF THERE IS NO BUFFER ;(BC) SHOULD BE SAVED JR Z,XJ233 ;NO FILL BUFFER... ; ; DEVICE HAS A FILL BUFFER. IS THERE ROOM IN IT FOR ANOTHER CHARACTER? ; INC HL ;BUMP PTR TO FILL INDEX ENTRY IN FILL BUFFER INC HL ; LD A,(HL) ;GET FILL INDEX TO A CP MX_CH_BF ;COMPARE IT WITH MAX CHARS IN BUFFER RET NZ ;RETURN IF NOT ZERO WITH Z CLEAR TO INDICATE ;THAT THERE IS ROOM IN BUFFER. ; XJ233: ;EITHER THIS DEVICE HAS NO FILL BUFFER OR ;THERE IS NO ROOM IN THE BUFFER: RETURN ;ALLOCATION STATUS. CALL ALC_ST ;GET ALLOCATION STATUS: Z IS SET IFF THERE ARE ;NO BUFFERS. RET ;RETURN... PAGE FL_B_CH: ; ROUTINE TO FILL_BUFFERWITH_CHAR ; ENTRY: ; B = DEVICE NUMBER ; HI BIT IS SET IF THE DEVICE IS HIGH PRIORITY. ; BIT 6 IS SET IF SPECIAL HANDLING IS REQUIRED. ; ; C = CHARACTER WITH WHICH TO FILL DEVICE ; EXIT: ; DEVICE BUFFER IS FILLED WITH CHAR ; Z BIT SET IF FILL SUCCESSFUL ; Z CLEAR IF UNSUCCESSFUL ; ; REGISTERS AFFECTED: ; A ; BC ; DE ; HL ; CALL FIL_BUF ;GET ADDRESS OF FILL BUFFER TO HL ;RETURNS Z SET IF NO BUFFER ;(BC) SHOULD BE SAVED JR NZ,XJ234 ;NO... ; PUSH BC CALL ALC_BUF ;YES. THERE IS NO FILL BUFFER, SO ALLOCATE ;BUFFER. ADDRESS OF BUFFER IN HL. Z BIT SET ;ON FAILURE POP BC JR Z,XJ235 ;JUMP TO EXIT PT. ; PUSH HL CALL DEV_ROOT ;GET ADDRESS OF DEVICE LIST ROOT TO HL ;(BC) SAVED POP DE ;RESTORE NEW BUFFER ADDR TO HL LD (HL),E ;SAVE NEW BUFFER ADDR IN FILL BUFFER ADDR ENTRY INC HL ;OF DEVICE LIST ROOT LD (HL),D ; INC HL ;AND REMOVE BUFFER ENTRY LD (HL),E ; INC HL ; LD (HL),D ; ; EX DE,HL PUSH HL CALL BUF_INIT ;INITIALIZE BUFFER POP HL ;MOVE NEW BUFFER ADDRESS TO HL ; XJ234: ;HL NOW POINTS TO A BUFFER TO FILL WITH CHAR INC HL ;BUMP HL TO POINT TO FILL INDEX ENTRY INC HL LD A,(HL) ;GET FILL INDEX ENTRY DEC HL DEC HL CP MX_CH_BF ;IS IT EQUAL TO MAX CHARS IN BUFFER? JR NZ,XJ236 ;NO... ; PUSH BC ;YES...NO ROOM IN THIS BUFFER, ALLOCATE NEW PUSH HL ;ONE. SAVE DEVICE NO, CHAR TO SAVE AND ADDR ;OF CURRENT BUFFER CALL ALC_BUF ;ALLOCATE A BUFFER. ADDR IN HL, Z SET IF FAIL POP DE ;RESTORE ADDR OF CURRENT BUFFER TO DE POP BC ;RESTORE DEV NO AND CHAR JR Z,XJ235 ;RETURN IF NO BUFFER AVAILABLE TO ALLOCATE ; EX DE,HL ;SWAP CURRENT BUFFER AND NEW BUFFER ADDR ;SO CURR BUFF ADDR IS IN HL FOR INDEXING LD (HL),E ;SET POINTER TO NEXT REMOVE BUFFER IN ;CURRENT BUFFER HEADER TO POINT TO NEWLY ;ALLOCATED BUFFER. INC HL ;DITTO LD (HL),D ;DITTO ; PUSH DE ;SAVE NEW BUFF ADDR CALL DEV_ROOT ;GET LIST ROOT FOR CURRENT DEVICE TO HL POP DE ;RESTORE NEW BUFF ADDR LD (HL),E ;SET POINTER TO FILL BUFFER IN LIST ROOT TO ;POINT TO NEWLY ALLOCATED BUFFER INC HL ; LD (HL),D ;...HI BYTE... INC HL ; LD A,(HL) ;IS CURRENT REMOVE BUFFER NIL? INC HL ; OR (HL) ; JR NZ,XJ237 ;NO... ; LD (HL),D ;SAVE NEXT BUFFER ADDR AS REMOVE BUFFER DEC HL ; LD (HL),E ; ; XJ237: EX DE,HL ;PUT ADDR OF NEW BUFFER IN HL ; PUSH HL ;SAVE ADDR OF NEW BUFFER CALL BUF_INIT ;INITIALIZE NEW BUFFER, (BC,DE) SAVED POP HL ;RESTORE ADDR OF NEW BUFFER LD A,0 ;L A!OAD A WITH VALUE OF FILL INDEX ; XJ236: ;HL NOW POINTS TO FILL BUFFER ;A = FILL INDEX INC HL ;BUMP HL TO POINT TO BEGINNING OF DATA AREA INC HL ;PAST POINTER TO NEXT REMOVE BUFFER INC (HL) ;BUMP FILL INDEX INC HL ;PAST FILL INDEX INC HL ;PAST REMOVE INDEX ; LD E,A ;MOVE FILL INDEX TO DE TO INDEX INTO BUFFER LD D,0 ;ZERO D FOR DOUBLE ADD ADD HL,DE ;INDEX INTO BUFFER DATA AREA BY FILL INDEX LD (HL),C ;SAVE CHAR IN BUFFER AREA AT FILL INDEXTH BYTE ; BIT 6,B CALL NZ,SPEC_HD ;IF CARRY SET (I.E., BIT 6 OF DEVICE #), CALL 11/5A ;SPECIAL HANDLING ROUTINE. 11/5A ; XOR A ;SET Z BIT TO INDICATE SUCCESS. RET ;AND RETURN ; XJ235: ;A NEW BUFFER COULD NOT BE ALLOCATED XOR A ;CLEAR A DEC A ;AND DECREMENT TO FORCE Z CLEAR RET ;AND RETURN. PAGE RM_C_BF: ; ROUTINE TO REMOVE_CHARACTERFROM_BUFFER ; ; THERE MUST BE A CHARACTER READY TO RETURN, OTHERWISE THE RESULTS 11/4A ; ARE UNPREDICTABLE. 11/4A ; ; ENTRY: ; B = NUMBER OF DEVICE FROM WHICH CHARACTER IS TO BE TAKEN ; EXIT: ; A = CHARACTER FROM DEVICE IN REGISTER B ; ; REGISTERS AFFECTED: ; ; A ; BC ; DE ; HL ; CALL RMV_BUF ;GET ADDR OF REMOVE BUFFER TO ;HL INC HL ;BUMP HL TO POINT TO REMOVE INDEX OF BUFFER INC HL ;PAST PTR TO NEXT REMOVE BUFFER... INC HL ;PAST FILL INDEX LD E,(HL) ;GET REMOVE INDEX INC HL ;BUMP PTR TO DATA AREAI PUSH HL ;SAVE POINTER TO DATA AREA LD D,0 ;ZERO HI BYTE OF DE. DE CONTAINS INDEX TO ;CHAR TO REMOVE IN BUFFER ADD HL,DE ;ADD INDEX TO BASE. HL POINTS TO CHAR TO ;REMOVE LD A,(HL) ;GET CHAR TO A POP HL ;RESTORE PTR TO DATA AREA PUSH AF ;SAVE CHAR ; LD A,E ;MOVE REMOVE INDEX TO A CP MX_CH_BF-1 ;IS LAST CHAR IN BUFFER? JR Z,XJ238 ;YES, DE-ALLOCATE THIS BUFFER AND SET POINTER ;TO POINT NEXT BUFFER ; POP AF ;RESTORE CHARACTER TO RETURN TO A DEC HL ;POINT HL TO REMOVE INDEX ENTRY INC (HL) ;INCREMENT REMOVE INDEX ENTRY RET ;AND RETURN TO CALLER XJ238: ; 7/22/AOS ; THE LAST CHAR WAS REMOVED FROM THE BUFFER SO-- ; DEALLOCATE THE BUFFER UNLESS IT IS THE DEDICATED ; KEYBOARD BUFFER ;THE CHAR TO RETURN IS ON THE STACK, B= DEVICE #, HL= BEGINNING OF DATA AREA DEC HL ;RESTORE HL TO POINT TO BEGINNING DEC HL ; OF BUF TO DEALLOCATE DEC HL DEC HL PUSH HL ;SAVE PNTR TO BUF TO DEALLOCATE CALL DEV_ROOT ;GET ADDR OF DEVICE LIST ROOT TO HL POP DE ;DE=PNTR TO BUF TO DEALLOCATE ;HL=PNTR TO DEVICE LIST ROOT PUSH HL ;SAVE PNTR TO DEVICE LIST ROOT LD A,E CP (HL) ;COMPARE PNTR TO BUF TO DEALLOCATE JR NZ,GT_1_BUF ; WITH PNTR TO DEVICE FILL BUF LD A,D ; TO SEE IF ONLY 1 BUFFER IS INC HL ; ALLOCATED TO THIS DEVICE CP (HL) JR NZ,GT_1_BUF LD A,KBD_DEV ;ONLY 1 BUFFER FOR THIS DEVICE-- CP B ; IS THE DEVICE THE KEYBOARD? JP NZ,NOT_KEYBRD ; NO..SO JUMP EX DE,HL ;KEYBOARD ONLY HAS ONE BUFFER LEFT-- CALL BUF_INIT ; DO NOT DEALLOCATE! -- INIT BUF POP HL ;REMOVE PNTR TO DEVICE LIST ROOT FROM STACK POP AF ;RESTORE CHAR TO RETURN RET ;RETURN TO CALLER  NOT_KEYBRD: ;DE=PNTR TO BUF TO DEALLOCATE ;HL=2ND BYTE OF DEVICE LIST ROOT LD (HL),0 ;CLEAR PNTR TO FILL BUF IN DEVICE LIST DEC HL ; ROOT -- LAST BUF IS BEING DEALLOCATED LD (HL),0 GT_1_BUF: ;DE=PNTR TO BUF TO DEALLOCATE POP HL ;HL=PNTR TO DEVICE LIST ROOT INC HL ;BUMP SO HL POINTS TO LIST ROOT INC HL ; REMOVE PNTR EX DE,HL LD BC,2 ;UPDATE REMOVE PNTR IN DEVICE LIST ROOT LDIR ; TO POINT TO NEXT REMOVE BUFFER ;HL=PNTR TO FILL INDEX OF BUF TO DEALLOCATE DEC HL ;RETURN HL TO TOP OF BUF DEC HL ; TO DEALLOCATE CALL D_ALC_BF ;DEALLOCATE THE BUFFER POP AF ;RESTORE CHAR TO RETURN RET ;RETURN TO CALLER PAGE RM_C_ST: ; RETURNS REMOVE CHARACTER STATUS (ARE THERE CHARS TO REMOVE?) FOR ; DEVICE IN B. ; ; IF THERE IS NO REMOVE BUFFER FOR DEVICE, RETURNS FALSE ; ; IF THERE IS MORE THAN ONE REMOVE BUFFER (I.E., IF THE FIRST POINTS ; TO ANOTHER), THEN THERE ARE CHARS TO REMOVE. ; ; OTHERWISE IF THE REMOVE INDEX OF THE BUFFER IS GREATER THAN OR ; EQUAL TO THE FILL INDEX, THERE ARE NO CHARS IN BUFFER, SO RETURN FALSE, ; ELSE RETURN TRUE. ; ; ENTRY: ; B = NUMBER OF DEVICE FOR WHICH REMOVE STATUS IS DESIRED ; ; EXIT: ; Z BIT IS CLEAR IF THERE ARE CHARS TO REMOVE ; ; Z BIT IS SET IF THERE ARE NO CHARS TO REMOVE ; ; REGISTERS AFFECTED: ; ; CALL RMV_BUF ;GET ADDRESS OF REMOVE BUFFER FOR DEVICE IN B ;TO HL. Z IS SET IF ADDRESS IS NIL (0). RET Z ;RETURN IF Z SET: NO FILL BUFFER. Z SET ;MEANS NO CHARS TO REMOVE. ; LD E,(HL) ;LOAD LO BYTE OF PTR TO NEXT REMOVE BUFFER TO E INC HL ; LD A,(HL) ;LOAD HI BYTE TO A. OR E ;OR HI & LO BYTES TO CHECK FOR ZERO RET NZ ;RETURN IF NOT ZERO WITH Z BIT CLEAR ;TO INDICATE CHARS WAITING ; INC HL ;BUMP PTR TO POINT TO FILL INDEX LD E,(HL) ;GET FILL INDEX TO E INC HL ;BUMP PTR TO REMOVE INDEX LD A,(HL) ;GET REMOVE INDEX TO A CP E ;TEST FOR REMOVE INDEX < FILL INDEX: JR C,XJ241 ;YES... CHARS WTG ; XOR A ;REMOVE INDEX => FILL INDEX: NO CHARS WAITING. ;SET Z !A"RET ;AND RETURN ; XJ241: ;CHARS WAITING... XOR A ;SET Z BIT DEC A ;FORCE Z BIT CLEAR RET ;AND RETURN PAGE ;------------------------------------------------------------------------------ ; UTILITY ROUTINES ;------------------------------------------------------------------------------ FIL_BUF: ; RETURNS ADDRESS OF CURRENT FILL BUFFER FOR DEVICE SELECTED BY REGISTER ; B. Z BIT IS SET IF THERE IS NONE. ; ; RETURNS VALUE LOCATED IN FIRST WORD OF DEVICE LIST ROOT. THIS VALUE ; IS ZERO IF THERE IS NO FILL BUFFER. ; ; ENTRY: ; B = DEVICE NUMBER FOR WHICH CURRENT FILL BUFFER ADDRESS IS DESIRED ; EXIT: ; Z BIT SET IF ADDRESS IS ZERO. ; HL = ADDRESS OF CURRENT FILL BUFFER, IF ANY, ELSE 0. ; ; REGISTERS AFFECTED: ; A ; E ; HL ; Z BIT ; CALL DEV_ROOT ;GET ADDRESS OF DEVICE LIST ROOT TO HL LD E,(HL) ;GET LOW BYTE OF CURRENT FILL BUFFER ;ADDRESS TO E INC HL ;BUMP PTR TO HI BYTE LD D,(HL) ;GET HI BYTE OF SAME TO D LD A,D ;PUT HI BYTE IN A TO OR WITH E OR E ;OR HI AND LO BYTES TO CHECK FOR ZERO EX DE,HL ;PUT ADDR IN HL RET ;AND RETURN TO CALLER. PAGE RMV_BUF: ; RETURNS ADDRESS OF CURRENT REMOVE BUFFER FOR DEVICE SELECTED BY ; REGISTER B. Z BIT IS SET IF THERE IS NONE. ; ; RETURNS VALUE LOCATED IN SECOND WORD OF DEVICE LIST ROOT. THIS VALUE ; IS ZERO IF THERE IS NO FILL BUFFER. ; ; ENTRY: ; B = DEVICE NUMBER FOR WHICH CURRENT REMOVE BUFFER ADDRESS IS DESIRED ; EXIT: ; Z BIT SET IF ADDRESS IS ZERO. ; HL = ADDRESS OF CURRENT REMOVE BUFFER, IF ANY, ELSE 0. ; ; REGISTERS AFFECTED: ; A ; E ; HL ; Z BIT ; CALL DEV_ROOT ;GET ADDRESS OF DEVICE LIST ROOT TO HL INC HL ;BUMP TO POINT TO REMOVE BUFFER ADDR INC HL ;ENTRY LD E,(HL) ;GET LOW BYTE OF CURRENT REMOVE BUFFER ;ADDRESS TO E INC HL ;BUMP PTR TO HI BYTE LD D,(HL) ;GET HI BYTE OF SAME TO LD A,D ;PUT HI BYTE IN A TO OR WITH LO BYTE OR E ;OR HI AND LO BYTES TO CHECK FOR ZERO EX DE,HL ;PUT ADDR IN HL RET ;AND RETURN TO CALLER. PAGE DEV_ROOT: ; RETURNS ADDRESS OF DEVICE LIST ROOT IN HL FOR DEVICE SPECIFIED IN B. ; ; INDEXES INTO LIST ROOT DATA STRUCTURE BY VALUE IN B ; ; THE TWO HIGH ORDER BITS ARE ASSUMED TO BE FLAG BITS AND ARE ; THUS IGNORED. ; ; ENTRY: ; B = DEVICE NUMBER FOR WHICH LIST ROOT IS DESIRED. ; ; EXIT: ; HL = ADDRESS OF LIST ROOT FOR DEVICE. ; ; REGISTERS AFFECTED: ; A ; DE ; HL ; XJ242 EQU 00111111B ;MASK TO STRIP OFF BITS 6 & 7 LD A,B ;MOVE DEVICE NUMBER TO A TO REMOVE HIGH BITS AND XJ242 ;MASK OFF HI BITS RLA ;A = DEV # * 2 (CBIT IS RESET WITH ANI) LD E,A ;E = DEV # * 2 RLA ;A = DEV # * 4 ADD A,E ;A = DEV # * 6 LD E,A ;MOVE A TO DE TO DO DOUBLE ADD LD D,0 ;ZERO HI BYTE OF D LD HL,D_RT_TBL ;POINT HL TO BASE OF DEVICE LIST ROOT TABLE ADD HL,DE ;ADD DEVICE OFFSET TO LIST ROOT RET ;AND RETURN... PAGE BUF_INIT: ; INITIALIZES BUFFER POINTED TO BY HL ; ; CLEARS THE FOLLOWING ENTRIES IN THE BUFFER HEADER: ; POINTER TO NEXT REMOVE BUFFER ; BUFFER FILL INDEX ; BUFFER REMOVE INDEX ; ; ENTRY: ; HL = ADDRESS OF BUFFER TO INITIALIZE ; EXIT: ; BUFFER IS INITIALIZED ; ; REGISTERS AFFECTED: ; A ; LD A,0 ;SET A TO VALUE TO SAVE IN BUFFER HEADER LD (HL),A ;CLEAR LOW BYTE OF NEXT REMOVE BUFFER ADDR INC HL ;POINT TO HI BYTE OF SAME LD (HL),A ;ZERO HI BYTE INC HL ;POINT TO FILL INDEX ENTRY LD (HL),A ;ZERO IT INC HL ;POINT TO REMOVE INDEX ENTRY LD (HL),A ;ZERO IT RET ;AND RETURN PAGE ALC_BUF: ; ALLOCATES A BUFFER IF ONE IS AVAILABLE. IF NONE AVAILABLE Z IS SET. ; ; IF THERE ARE ANY BUFFERS IN THE FREE LIST, THE FIRST IS ALLOCATED. ; THE BUFFER COUNT IN THE FREE LIST IS DECREMENTED. ; ; ENTRY: ; HIGH BIT OF B SET IF DEVICE HAS HIGH PRIORITY. ; ; EXIT: ; HL = ADDRESS OF ALLOCATED BUFFER, IF ANY, ELSE UNDEFINED. ; Z BIT IS SET IF NO BUFFERS ARE AVAILABLE. ; ; REGISTERS AFFECTED: ; ; HL ; CALL ALC_ST ;SEE IF THERE IS A BUFFER TO ALLOCATE. ;HL ==> BUFFER COUNT CELL IN FREE LIST ROOT ;Z SET IF NO BUFFERS AVAILABLE. RET Z ;IF NO BUFFERS AVAILABLE, RETURN. ; DEC (HL) ;DECREMENT BUFFER COUNT ;Z BIT IS SET IF COUNT IS NOW ZERO DEC HL ;DECREMENT HL TO POINT BACK TO FIRST FREE DEC HL ;BUFFER ADDR ENTRY LD E,(HL) ;GET LO BYTE OF FREE BUFFER ADDRESS INC HL ;BUMP HL TO POINT TO HI BYTE LD D,(HL) ;GET HI BYTE JR Z,XJ243 ;IF Z BIT IS SET, THE LAST FREE BUFFER HAS ;BEEN ALLOCATED (I.E., THE COUNT IS NOW ZERO), ;SO THERE IS NO NEED TO UPDATE THE POINTER IN ;THE FREE LIST ROOT TO THE NEXT FREE BUFFER. ;DE CONTAINS ADDRESS OF ALLOCATED BUFFER. ; DEC HL ;DEC HL TO POINT BACK TO NEXT FREE BUFFER PTR ENTRY EX DE,HL ;SWAP ADDRESS OF FREE BUFFER AND FREE BUFFER PTR ;HL NOW POINTS TO CELLS CONTAINING ADDRESS ;OF NEXT FREE BUFFER. LD C,(HL) ;GET ADDRESS OF NEXT FREE BUFFER TO BC INC HL ; LD B,(HL) ;HI BYTE... DEC HL ;DEC HL TO POINT BACK TO NEWLY ALLOCATED BUFFER ; EX DE,HL ;SWAP ADDRESS OF FREE BUFFER AND FREE BUFFER ;PTR AGAIN. LD (HL),C ;CHANGE PTR TO"A# FIRST FREE BUFFER IN FREE LIST INC HL ;ROOT TO POINT TO NEXT BUFFER LD (HL),B ;HI BYTE... ;DE NOW CONTAINS ADDRESS OF ALLOCATED BUFFER ;AND THE FREE LIST HAS BEEN UPDATED ; XJ243: ;DE CONTAINS THE ADDRESS OF ALLOCATED BUFFER ;AND THE FREE LIST HAS BEEN UPDATED IF ;NECESSARY. EX DE,HL ;PUT BUFFER ADDRESS IN HL XOR A ;CLEAR Z BIT TO INDICATE SUCCESSFUL ALLOCATION DEC A ; RET ;AND RETURN. PAGE ALC_ST: ; CHECKS BUFFER ALLOCATION STATUS: ARE THERE ANY BUFFERS TO ALLOCATE. ; ; ENTRY: ; HIGH BIT OF B SET IF ALLOCATING DEVICE HAS HIGH PRIORITY. ; ; EXIT: ; Z IS SET IF THERE ARE NO BUFFERS AVAILABLE. ; HL ==> BUFFER COUNT CELL IN FREE LIST ROOT. ; (THIS IS PASSED TO AVOID ALC_BUF HAVING TO COMPUTE THAT ADDRESS.) ; ; REGISTERS AFFECTED: ; ; A ; B ; HL ; LD HL,FRE_ADDR ;GET ADDRESS OF FREE LIST ROOT TO HL ;DEVICE NUMBER IN B IS PRESERVED INC HL ;BUMP TO POINT TO NUMBER OF BUFFERS ENTRY INC HL ; LD A,(HL) ;GET NUMBER OF BUFFERS TO A OR A ;SET Z FLAG IF ZERO RET Z ;AND RETURN IF NO BUFFERS AVAILABLE ; RLC B ;ROTATE HI BIT OF B INTO CY FLAG JR NC,XJ244 ;IT'S NOT SET: PRIORITY IS LOW... ; ;PRIORITY IS HIGH. OK TO ALLOCATE LAST BUFFER OR A ;SET Z FLAG RET ;AND RETURN ; XJ244: ;DEVICE'S PRIORITY IS NOT HIGH. CHECK TO SEE CP THR_HOLD ;IF NUMBER OF BUFFERS AVAILABLE IS GREATER THAN ;THE PRIORITY THRESHOLD RET Z ;IT'S EQUAL: RETURN WITH Z SET INDICATING ;NO BUFFERS AVAILABLE ; RET NC ;IT'S GREATER: RETURN WITH Z CLEAR INDICATING ;BUFFERS AVAILABLE. ; XOR A ;IT'S LESS THAN: RETURN WITH Z SET INDICATING RET ;NO BUFFERS AVAILABLE PAGE D_ALC_BF: ; DE-ALLOCATES (I.E., PUTS IN THE FREE LIST) THE BUFFER POINTED TO ; BY HL. ; ENTRY: ; HL = ADDRESS OF BUFFER TO PUT IN FREE LIST ; ; EXIT: ; BUFFER POINTED TO BY HL IS PUT IN FREE LIST ; ; REGISTERS AFFECTED: ; ; DE ; HL PUSH HL ;SAVE ADDRESS OF BUFFER TO DE-ALLOCATE LD HL,FRE_ADDR ;GET ADDRESS OF FREE LIST ROOT TO HL LD C,(HL) ;GET POINTER TO FIRST FREE BUFFER INC HL ;TO BC LD B,(HL) ; INC HL ;GET FREE BUFFER COUNT TO A LD A,(HL) ; INC (HL) ;BUMP FREE BUFFER COUNT DEC HL ;POINT HL BACK TO FREE LIST ROOT + 1, HI BYTE ;OF PTR TO FIRST FREE BUFFER ADDR POP DE ;RESTORE ADDRESS OF BUFFER TO DE-ALLOCATE TO DE LD (HL),D ;SET PTR TO FIRST FREE BUFFER TO POINT TO DEC HL ;THIS BUFFER LD (HL),E ; ; OR A ;IS OLD BUFFER COUNT ZERO? (I.E., IS THE ;BUFFER JUST ADDED TO THE LIST THE ONLY ONE IN ;IT? RET Z ;YES, RETURN: THERE IS NO POINT UPDATING PTR ;IN BUFFER TO POINT TO NEXT FREE BUFFER SINCE ;THERE IS NO NEXT FREE BUFFER ; EX DE,HL ;PUT POINTER TO BUFFER ADDRESS IN HL LD (HL),C ;SET POINTER IN BUFFER TO POINT TO NEXT INC HL ;FREE BUFFER LD (HL),B ; RET ;AND RETURN  PUSH HL ;SAVE ADDRESS OF BUFFER TO DE-ALLOCATE LD HL,FRE_ADDR ;GET ADDRESS OF FREE LIST ROOT TO HL LD C,(HL) ;GET POINT SUBTTL 'HIGH RAM ROUTINES' ; ********************************************************* ; * * ; * HIGH RAM ROUTINES * ; * * ; ********************************************************* ; ; MODULE 8 --ROM8-- ENTRY POINTS ; ; HIGH RAM ROUTINES ; ; INT_HL: INTERRUPT HANDELING (CHECK FOR INTERRUPTS) ; INT_HD: INTERRUPT HANDELING (SERVICE INTERRUPTS) ; DMARD: TRANSFER DATA FROM CONTROLLER TO MEMORY ; DMAWRT: TRANSFER DATA FROM MEMORY TO CONTROLLER ; BANKCALL: CALLS AN ADDRESS IN ANY BANK ; BANKJMP: JUMP TO AN ADDRESS IN ANY BANK ; BANKMOVE: MOVE A BLOCK FROM ONE BANK TO ANOTHER ; MOVE: PERFORM A BLOCK MOVE PAGE ; .Z80 ; .XLIST ; INCLUDE SYSS1.MAC ;SYSTEST FILE ; INCLUDE RAMSMON.MAC ;MONITOR RAM MEMORY LOCATIONS ; INCLUDE RAMS10.MAC ;RAM MEMORY LOCATIONS AND CONSTANTS ; .LIST ; ;SYSS1.MAC , RAMSMON.MAC AND RAMS10.MAC INCLUDED PUBLIC STINT,INT_HL,INT_HD,DMARD,DMAWRT,BANKCALL,BANKJMP,BANKMOVE PUBLIC LENINT PAGE ;  +------------------------------------------+ ; | HIGH RAM ROUTINES | ; +------------------------------------------+ ;INTERRUPT HANDLING AND DMA ROUTINES TO BE MOVED TO HIGH RAM ; ; STINT: .PHASE HI_ROUT ; ORG HI_ROUT ;START LOCATION OF HIGH RAM ROUTINES TO BE MOVED TO HIGH RAM ;------------------------------------------------------------------------------ ; INTERRUPT HANDLING ROUTINE ;------------------------------------------------------------------------------ ; SAVES USER STATE, SETS INTERRUPT STATE, CALLS INTERRUPT POLLING ROUTINE ; TO HANDLE INTERRUPT, RESTORES USER STATE. ; ; ENTRY: ; NONE, ; EXIT: ; INTERRUPT HANDLED. ; INT_HL: DI ;PREVENT OTHER INTERRUPTS FROM OCCURRING ;SAVE USER'S STATE LD (USR_STK),SP ;SAVE USER STACK LD SP,ISTK ;SET INTERRUPT STACK ; EX AF,AF' ;SAVE REGISTERS IN ALTERNATES ; EXX PUSH AF PUSH BC PUSH DE PUSH HL PUSH IX ;SAVE IX REGISTER#A$ PUSH IY ;SAVE IY REGISTER IN A,(SYS_DTA) ;GET MEMORY BANK STATE LD (USR_BNK),A ;SAVE IT ;SERVICE INTERRUPT LD A,(I_POL_BANK) ;LOAD BANK MASK FOR INTERRUPT ;POLL ROUTINE OUT (SYS_DTA),A ;SEND TO PIA CONTROL A REG LD HL,(I_POL_ADR) ;LOAD ADDRESS OF INTERRUPT ;POLLING ROUTINE LD DE,XJ245 ;PUSH RETURN ADDRESS ON STACK PUSH DE JP (HL) ;CALL POLLING ROUTINE ;RESTORE USER'S STATE XJ245: LD A,(USR_BNK) ;GET USER BANK STATE OUT (SYS_DTA),A ;SEND IT TO PIA TO RESTORE USER BANK STATE POP IY ;RESTORE REGISTERS POP IX POP HL POP DE POP BC POP AF ; EXX ; EX AF,AF' LD SP,(USR_STK) ;RESTORE USER'S STACK EI ;RE-ENABLE INTERRUPTS RET ;AND RETURN PAGE INT_HD: ; THE INTERRUPT HANDLER ENTRY POINT. ; THE INPUT TO THIS ROUTINE IS A PTR TO A TABLE ENTRY ; INDICATING THE PIA MASK TO SWITCH IN THE BANK IN WHICH THE ; INTERRUPT HANDLER RESIDES AND THE ADDRESS OF THE HANDLER. ; ; THE CURRENT BANK STATE IS SAVED, THE INTERRUPT HANDLER'S ; BANK IS FLAGGED IN AND THE ROUTINE IS CALLED. ; ; SINCE THIS ROUTINE SWITCHES BANKS, IT MUST RESIDE IN HIGH MEMORY. ; ; ENTRY: ; HL ==> TABLE ENTRY ; ; EXIT: ; INTERRUPT HAS BEEN SERVICED. ; IN A,(SYS_DTA) PUSH AF ;SAVE CURRENT BANKS LD A,(HL) ;LOAD INTERRUPT HANDLER BANK STATE FROM TABLE INC HL LD E,(HL) ;LOAD INT. HDLR. ADDR FROM TABLE INC HL ; LD H,(HL) LD L,E ;HL = INTERRUPT HANDLER ADDRESS OUT (SYS_DTA),A ;SET INTERRUPT HANDLER BANK LD DE,XJ246 PUSH DE ;SET RETURN ADDRESS JP (HL) ;"CALL" ROUTINE XJ246: POP AF ;RESTORE CURRENT BANKS OUT (SYS_DTA),A RET PAGE DMARD: ;TRANSFER DATA FROM COMTROLLER TO MEMORY ;ENTRY ;BC = BYTES TO TRANSFER ;HL = FWA OF BUFFER ;DMABANK = BANK ;EXIT ;HL = NEXT ADDRESS ;SAVE CURRENT BANKS AND SWITCH TO DMA BANK IN A,(SYS_DTA) ;(13) GET CURRENT BANKS PUSH AF ;(11) SAVE LD A,(DMABANK) ;(13) OUT (SYS_DTA),A ;(13) SET DMA BANK ;DO DMA XJ247: IN A,(DSK_STS) ;(13) GET STATUS RRA ;(4) JR NC,XJ248 ;(7) RETURN IF NO BUSY RRA ;(4) JR NC,XJ247 ;(10) IF NO DRQ IN A,(DSK_DAT) ;(13) GET BYTE LD (HL),A ;(7) STORE BYTE INC HL ;(6) DEC BC ;(6) LD A,B ;(4) OR C ;(4) JR NZ,XJ247 ;(10) ;RESTORE BANKS XJ248: POP AF OUT (SYS_DTA),A RET PAGE DMAWRT: ;XFER DATA FROM MEMORY TO DISK ;ENTRY ;BC = BYTES TO TRANSFER ;HL = FWA OF BUFFER ;DMABANK = BANK ;EXIT ;HL = NEXT ADDRESS ;SAVE CURRENT BANKS AND SWITCH TO DMA BANK IN A,(SYS_DTA) ;(13) GET CURRENT BANKS PUSH AF ;(11) SAVE LD A,(DMABANK) ;(13) OUT (SYS_DTA),A ;(13) SET DMA BANK ;DO DMA XJ249: IN A,(DSK_STS) ;GET STATUS RRA JR NC,XJ250 ;RETURN IF NO BUSY RRA JR NC,XJ249 ;IF NO DRQ LD A,(HL) ;GET BYTE OUT (DSK_DAT),A ;STORE BYTE INC HL DEC BC LD A,B OR C JR NZ,XJ249 ;RESTORE BANKS XJ250: POP AF OUT (SYS_DTA),A RET PAGE BANKCALL: ;CALLS AN ADDRESS IN ANY BANK ; (SAVES ALL REGISTERS) ;ENTRY ;JMPBANK = BANK ;JMPADDR = ADDRESS ;EXIT ;NONE ;SAVE CURRENT BANKS LD (TEMP),A ;SAVE A IN A,(SYS_DTA) PUSH AF ;SAVE BANKS LD A,(TEMP) ;RESTORE A ;CALL THE ADDRESS CALL BANKJMP ;RESTORE BANKS EX (SP),HL ;SAVE HL ON STACK, GET BANKS IN HL PUSH AF ;SAVE AF PUSH HL ;PUT BANKS ON STACK POP AF ;GET A = BANKS OUT (SYS_DTA),A ;RESTORE BANKS POP AF ;RESTORE AF POP HL ;RESTORE HL RET PAGE BANKJMP: ;JUMP TO AN ADDRESS IN ANY BANK ; *NOTE -- USES A AND HL* ;ENTRY ;JMPBANK = BANK ;JMPADDR = ADDRESS ;EXIT ;ALL REGISTERS SAVED ;SWITCH BANKS LD (TEMSAV),A ;SAVE A LD A,(JMPBANK) OUT (SYS_DTA),A ;SWITCH BANKS ;JUMP TO ADDRESS LD A,0C3H LD (JMPSPOT),A ;SET UP TO JUMP LD A,(TEMSAV) ;RESTORE A JP JMPSPOT PAGE BANKMOVE: ;MOVE A BLOCK (1-10000H BYTES) FROM ONE BANK TO ANOTHER ; (IF BC = 0, 10000H BYTES ARE MOVED) ; THIS ROUTINE USE "5" LEVEL OWN STACK ;ENTRY ;BC = NUMBER OF BYTES TO TRANSFER (0 INDICATES 10000H) ;HL = SOURCE ADDRESS ;DE = DESTINATION ADDRESS ;SRCBANK = SOURCE BANK ;DESTBANK = DESTINATION BANK ;EXIT ;HL = NEXT SOURCE ADDRESS ;DE = NEXT DESTINATION ADDRESS ;SAVE CURRENT BANKS IN A,(SYS_DTA) PUSH AF ;MOVE BLOCK ;MOVE C BYTES LD A,C OR A JR Z,XJ251 ;IF C = 0, ONLY MOVE B * 100H PUSH BC ;SAVE B LD B,0 CALL MOVE ;MOVE C BYTES POP BC ;MOVE B * 100H BYTES LD A,B OR A JR Z,XJ252 ;IF B = 0 XJ251: PUSH BC LD BC,100H CALL MOVE ;MOVE 100H BYTES POP BC DJNZ XJ251 ;IF MORE XJ252: POP AF ;RESTORE ORIGINAL BANK OUT (SYS_DTA),A RET PAGE MOVE: ;MOVE A BLOCK FROM ONE BANK TO ANOTHER (1-256 BYTES) ;*NOTE -- NO ERROR CHECKING DONE AT THIS LEVEL, BC MUST BE BETWEEN 1 AND 256 ;ENTRY ;HL = SOURCE ADDRESS ;DE = DESTINATION ADDRESS ;BC = NUMBER OF BYTES PUSH BC ;SAVE COUNT PUSH DE ;SAVE DESTINATION ADDRESS ;MOVE SOURCE TO HIGH MEMORY LD A,(SRCBANK) OUT (SYS_DTA),A ;SET SOURCE BANK LD DE,$A%HIBUFF ;HIGH RAM BUFFER LDIR ;MOVE BLOCK FROM HIGH MEMORY TO DESTINATION POP DE ;RESTORE DESTINATION POP BC ;RESTORE COUNT PUSH HL ;SAVE NEXT SOURCE ADDRESS LD A,(DESTBANK) OUT (SYS_DTA),A ;SET DESTINATION LD HL,HIBUFF LDIR POP HL ;RESTORE NEXT SOURCE ADDRESS RET IF $ GT 0FFDFH .PRINTX /SIO VECTOR INTERRUPT TABLE CLASHED/ ENDIF LENINT EQU $ - INT_HL ;LENGTH OF INTERRUPT ROUTINES TO BE MOVED TO HIGH RAM .DEPHASE VE ;MOVE 100H BYTES POP BC DJNZ XJ251 ;IF MORE XJ252: POP AF ;RESTORE ORIGINAL BANK OUT (SYS_DTA),A RET PAGE MOVE: ;MOVE A BLOCK FROM ONE BANK TO ANOTHER (1-256 BYTES) ;*NOTE -- NO ERROR CHECKING DONE AT THIS LEVEL, BC MUST BE BETWEEN 1 AND 256 ;ENTRY ;HL = SOURCE ADDRESS ;DE = DESTINATION ADDRESS ;BC = NUMBER OF BYTES PUSH BC ;SAVE COUNT PUSH DE ;SAVE DESTINATION ADDRESS ;MOVE SOURCE TO HIGH MEMORY LD A,(SRCBANK) OUT (SYS_DTA),A ;SET SOURCE BANK LD DE,8U;2ᖟ/H,+',+*8#DM͂*,+*8#DM)Ͳ29*!96:9Ҭ+*9#"9*9)*(9N#F!"8*8:889͒6HҖ+*9#"9*9)*(9N#F!"8[+89͒6©+*9"8+*8"8*8:898͒6H+*8"8ö+:8+!96+!9698͒6i,*8 >ͪ6!7>͟6!7H*8#DM͂*Hc,_'*8#DM)*8 N#F'[1<&06++!96!"t998͒6q-*8 >ͪ6!7>͟6!7H*8#DM͂*Hk-*p9*9&6>~6X-*9*86>~6K-:8+!96!"t998͒6q-*8 >ͪ6!7>͟6!7H*8#DM͂*Hk-*p9*9&6>~6X-*9UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU%A&&A''A