IMD 1.15: 16/05/2007 8:23:12 ROM V1.21 1 OF 2 مممممممممممممممROM5 MAC€ ROM5 MAC9ROM0 MAC€ !"#$%&'()ROM0 MACb*+,-./0123456RAMS10 MAC 78RAMSMON MAC@9:;<=>?@LISTROM MACAممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممم SUBTTL 'DISK DRIVERS' ; ********************************************************* ; * * ; * DISK DRIVERS * ; * * ; ********************************************************* ; ; MODULE 5 --ROM5-- ENTRY POINTS ; ; DISK ROUTINES ; ; RDRV: RESET DRIVE ; RSEC: READ SECTOR ; WSEC: WRITE SECTOR ; R_WSEC: PERFORM READ OR WRITE OF SECTOR ; SENDEN: DETERMINE DENSITY AND NUMBER OF SECTORS/TRACK ; HOME: HOME DRIVE (TRACK 0) ; SEEK: SEEK TO GIVEN TRACK ; STEP: STEP ONE TRACK ; STEPIN: STEP IN ONE TRACK (TRACK = TRACK + 1) ; STEPOUT: STEP OUT ONE TRACK (TRACK = TRACK - 1) ; PSECC: PERFORM SEEK-TYPE COMMAND ; READ: READ GIVEN NUMBER OF SECTORS ; WRITE: WRITE GIVEN NUMBER OF SECTORS ; RD_WRT: PERFORM READ OR WRITE OF SECTOR(S) ; RADR: READ ADDRESS INFORMATION ; ROMREAD: FAST DMA READ (USED BY RADR) ; FMTTRK: FORMAT ONE TRACK ; FORINT: INTERRUPT DISK CONTROLLER ; FDSK: FUNCTION DISK ; SELDRV: SELECT DRIVE ; WBUSY: WAIT FOR BUSY TO CLEAR ; FORMAT: FORMAT TRACK IN IBM 3740 FORMAT ; DELAY: DELAY 'N' MILLISECONDS 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 DMARD,DMAWRT,BANKMOVE ; PUBLIC RDRV,RSEC,WSEC,SENDEN,HOME,SEEK,STEP,STEPIN,STEPOUT,READ,WRITE ; PUBLIC RADR,FMTTRK,FORINT,SELDRV,FORMAT,D.FINT CSEG PAGE ; ; +-----------------------------------------------+ ; | DISK ROUTINES | ; +-----------------------------------------------+ RDRV: ;RESET DRIVE ;THIS ROUTINE WILL HOME THE DRIVE, IF THERE IS AN ERROR, A RECALIBATION IS PREFORMED ; ;ENTRY ;NONE ;EXIT ;ZBIT = RESET IF ERROR LD A,(NRETRY) LD (RTRY),A XJ134: CALL SELDRV ;SELECT DRIVE CALL STEPIN ;MAKE SURE HEAD IS NOT PAST TRACK 0 CALL HOME ;HOME DRIVE JR NC,XJ135 ;IF GOOD XJ136: LD A,(RTRY) DEC A LD (RTRY),A JR NZ,XJ134 ;& TRY AGAIN INC A ;MAKE NOT ZERO SCF ;INDICATE ERROR RET XJ135: XOR A RET PAGE RSEC: ;READ SECTOR ;*NOTE* ; NO RETRIES ARE PREFORMED AT THIS LEVEL ;ENTRY ;B = NUMBER OF SECTORS ;EXIT ;HL = LAST DMA ADDRESS PLUS ONE IF GOOD TRANSFER ;ZBIT = RESET IF ERROR ;A = 0 IF NO ERROR, 1 IF HARD ERROR ;B = FDC STATUS IF ERROR LD A,D.RDS LD (R_WCOM),A JR R_WSEC PAGE WSEC: ;WRITE A SECTOR ;*NOTE* ; NO RETRIES ARE PREFORMED AT THIS LEVEL ;ENTRY ;B = NUMBER OF SECTORS ;EXIT ;HL = LAST DMA ADDRESS PLUS ONE IF GOOD TRANSFER ;ZBIT = RESET IF ERROR ;A = 0 IF NO ERROR, 1 IF HARD ERROR, 2 IF WRITE PROTECTED ;B = FDC STATUS IF ERROR LD A,D.WRTS LD (R_WCOM),A ;FALLS THROUGH TO "R_WSEC" PAGE R_WSEC: ;READ OR WRITE SEGMENT ;ENTRY ;B = NUMBER OF SECTORS TO READ OR WRITE ;R_WCOM = D.RDS OR D.WRTS ;RDFLAG = 0 FOR READ, NON-ZERO FOR WRITE (FOR HYSTERESIS) ;EXIT ;HL = LAST DMA ADDRESS PLUS ONE IF GOOD TRANSFER ;ZBIT = RESET IF ERROR ;A = 0 IF GOOD, 1 IF HARD ERROR, 2 IF WRITE PROTECTED ;B = FDC STATUS IF ERROR LD A,B ;PUT SECTOR COUNT IN A LD (NUMSEC),A ;AND SAVE IT LD A,(NRETRY) LD (RTRY),A ;SET RETRY NUMBER SRL A ;A=A/2 LD (RDFLAG),A ;SAVE VALUE FOR RECALIBRATION ;SELECT DRIVE CALL SELDRV ;TURN DRIVE ON JR Z,XJ138 ;IF DRIVE ON DON'T READ ADDRESS ;SET "DSK_TRK" TO HEAD POSITION XJ139: CALL RADR ;READ ADDRESS AND SET CONTROLLER LD B,A ;SAVE FDC STATUS JR C,XJ140 ;ERROR ?- YES, RETRY ;SEEK XJ138: CALL SEEK ;SEEK TO TRACK LD B,A ;SAVE FDC STATUS JR C,XJ140 ;ERROR ?- YES, RETRY ;READ OR WRITE LD A,(NUMSEC) ;RESTORE # SECTORS TO R/W LD B,A ;TO B CALL RD_WRT ;READ/WRITE PER R_WCOM JR NC,XJ141 ;IF GOOD, RETURN CP 02H ;IS WRITE PROTECTED ? JR Z,XJ141 ;YES- XJ140: LD HL,RTRY ;GET RETRY COUNT LD A,(RDFLAG) ;GET RECALIBRATION ERROR NUMBER CP (HL) JR NZ,XJ142 ;NOT TIME TO RECALIBRATE LD A,(HL) ;SAVE RETRY COUNT PUSH AF ;& PUSH HL ;RTRY ADDRESS CALL RDRV ;RECALIBATE TO TRACK 0 POP HL ;RESTORE VALUES POP AF LD (HL),A XJ142: DEC (HL) JP NZ,XJ139 ;YES-RETRYS XJ143: LD A,1 ;INDICATE HARD ERROR XJ141: OR A RET PAGE SENDEN: ;DETERMINE THE DENSITY, # AND SIZE OF SECTORS PER TRACK & # OF SIDES ON THIS DISKETTE ; ;ENTRY NONE ;EXIT ;B = NUMBER OF SECTORS ON ONE TRACK ;ZBIT = RESET IF ERROR ;SAVTYP IS SET WITH DENSITY, SECTOR SIZE & # OF SIDES ; ;SAVTYPE +---+---+---+---++---+---+---+---+ ; | 7 | 6 | 5 | 4 || 3 | 2 | 1 | 0 | ; +---+---+---+---++---+---+---+---+ ; | | | | | | | | ; Unchanged (undefined bits) <---+---+---+---+ | | | | ; Bytes/sector <----------------------------------+---+ | | ; 0 = 128, 1 = 256 | | ; 2 = 512, 3 = 1024 | | ; Side ( 0 = SS, 1 = DS ) <-------------------------------+ | ; Density ( 0 = DD, 1 = SD ) <--------------------------------+ ; ;Test side 0 first LD HL,SAVTYP LD A,(HL) AND 11110001b ;Reset side bit & clear sector length LD (HL),A LD A,(NRETRY) ;Get retry count into C-reg LD C,A ;DENSITY LOOP(CHECK PRESENT DENSITY FIRST) XJ144: LD B,2 ;CHECK BOTH DENSITYS XJ145: PUSH BC ;Save retry counts PUSH HL ;Save SAVTYP address ;CHECK THIS DENSTIY CALL SELDRV ;SELECT DRIVE CALL RADR ;READ ADDRESS POP HL POP BC ;Restore retry counts JR NC,XJ146 ;IF GOOD ;IF DENSITY ERROR CHANGE DENSITY AND LOOP TO :RL2: LD A,(HL) ;PRESENT DENSITY XOR 1 ;CHANGE DENSITY BIT LD (HL),A ;NEW DENSITY DJNZ XJ145 ;DENSITY LOOP ;IF BOTH DENSITYS FAIL HOME DRIVE AND TRY AGAIN DEC C JR Z,XJ147 ;END IF SECOND TIME THROUGH PUSH BC PUSH HL CALL HOME ;HOME DRIVE POP HL POP BC JR XJ144 ;TRY AGAIN ;SET "SAVTYP" XJ146: LD A,(DSTSB+3) ;SECTOR LENTGH STATUS BYTE AND 00000011B ;0-3 SLA A SLA A ;NOW IS 0000_XX00B WAS 0000_00XXB OR (HL) ;Or sector length with SAVTYP LD (HL),A ;And save it ;READ ADDRESS AND SET NUMBER OF SECTORS AND RETURN LD A,(DSTSB+2) ;SECTOR JUST READ LD D,A ;RETRY LOOP LD A,(NRETRY) ;SET RETRYS LD E,A ;READ HEADER LOOP XJ149: PUSH DE ;SAVE LAST SECTOR ADDR & retry count PUSH HL CALL RADR ;READ ADDRESS POP HL POP DE JR C,XJ150 ;IF ERROR IN RADR ;CHECK FOR LAST HEADER LD A,(DSTSB+2) LD B,A ;B=PRESENT SECTOR LD A,D ;A=LAST SECTOR SUB B ;LAST SECTOR - PRESENT SECTOR JR Z,XJ149 ;IF THE LAST SECTOR = THE PRESENT SECTOR(THIS SHOULD HAPPEN ONLY ON ERROR RETRY) JR NC,XJ151 ;IF THE VALUE IN A WAS THE LAST SECTOR OF THE TRACK LD D,B ;D=LAST SECTOR READ JR XJ149 ;LOOP TILL YOU FIND THE LAST TRACK ;SET NUMBER OF SECTORS PER TRACK XJ151: INC A ;A=NUMBER OF SECTORS PER TRACK LD B,A ;REMOVE THESE TWO STATEMENTS TO IMPLEMENT DOUBLE-SIDED xor a ret ;clear z-flag and ret ;and remove the ";" before each of the following executable statements ;Determine # of sides ; PUSH BC ;Try side 1 ; SET 1,(HL) ;Select side 1 in SAVTYP ;Now try to read the sector header ; CALL RADR ; JR NC,CONT ;Continue if no error ; CALL RADR ;Try again if error ; JR C,SSDD ;Error again, must be single sided diskette ;CONT: LD A,(DSTSB+1) ;Get side from header ; OR A ;A=0 on single sided drive, 1 on double sided drive ; JR NZ,DSDD ;If A=1 must be double sided ;SSDD: LD HL,SAVTYP ; RES 1,(HL) ;Clear side bit ;DSDD: POP BC ;Restore # of sectors ; XOR A ;RESET CFLAG ; JR XJ152 ;GOOD RETURN ;IF NUMB. SEC. ERROR MAKE LAST SECTOR READ ZERO AND RETRY TO :LOOP1 XJ150: LD D,0 DEC E JR NZ,XJ149 ;RETRY XJ147: LD A,1 OR A ;CFLAG TO NONZERO XJ152: RET PAGE HOME: ;HOME DISK DRIVE ;DRIVE IS ALREADY SELECTED AND READY ;IF "SEKDEL" HAS THE VERIFY BIT SET THIS PROC WILL CHECK FOR SEEK AND CRC ERRORS ;ENTRY ;SDISK = DRIVE ;EXIT ;CBIT = SET IF ERROR ;A = FDC STATUS IF ERROR  LD A,(SEKDEL) ;GET SEEK DELAY AND 00000111B ;SPEAD & VERIFY BITS ONLY DI CALL FDSK ;FUNCTION DISK JR C,XJ153 ;IF ERROR CALL WBUSY ;WAIT FOR BUSY TO DROP JR C,XJ153 IN A,(DSK_STS) BIT 2,A JR Z,XJ154 ;IF NOT ON TRACK ZERO LD A,(SEKDEL) AND 00000100B ;VERIFY? JR Z,XJ153 ;NO VERIFY GOOD RETURN IN A,(DSK_STS) LD B,A ;SAVE FDC STATUS AND 00011000B ;TEST SEEK AND CRC LD A,B ;RESTORE FDC STATUS JR Z,XJ153 ;GOOD RETURN XJ154: SCF ;IF ERROR XJ153: EI RET PAGE SEEK: ;SEEK TO TRACK DEFINED BY SAVTRK ;TRACK REG UPDATED AND VERIFIED ;ENTRY ;SAVTRK SET TO DESIRED TRACK ;EXIT ;CBIT = SET IF ERROR ;A = FDC STATUS IF ERROR ; IF NO ERROR CONTROLLER TRACK = SAVTRK LD HL,SAVTRK IN A,(DSK_TRK) CP (HL) RET Z ;RETURN LD A,(HL) OUT (DSK_DAT),A ;SET TRACK WANTED LD B,D.SEK JR PSEKC ;PERFORM SEEK COMMAND PAGE STEP: ;STEP ONE TRACK ;SAVTRK IS NOT USED IN THIS PROC ;CONTROLLER TRK REG IS UPDATED ;VERIFY IS PREFORMED ;ENTRY ;NONE ;EXIT ;CBIT = SET IF ERROR ;A = FDC STATUS IF ERROR ; IF NO ERROR CONTROLER TRACK = TRACK +/- 1 LD B,D.STP JR PSEKC ;PERFORM STEP COMMAND PAGE STEPIN: ;STEP IN ONE TRACK ;SAVTRK IS NOT USED IN THIS PROC ;CONTROLLER TRK REG IS UPDATED ;ENTRY ;NONE ;EXIT ;CBIT = SET IF ERROR ;A = FDC STATUS IF ERROR ; IF NO ERROR CONTROLER TRACK = TRACK + 1 LD B,D.STPI JR PSEKC ;PERFORM STEP-IN COMMAND PAGE STEPOUT: ;STEP OUT ONE TRACK ;SAVTRK IS NOT USED IN THIS PROC ;CONTROLER TRK REG IS UPDATED ;VERIFY IS PERFORMED ;ENTRY ;NONE ;EXIT ;CBIT = SET IF ERROR ;A = FDC STATUS IF ERROR ; IF NO ERROR CONTROLER TRACK = TRACK - 1 LD B,D.STPO JR PSEKC ;PERFORM STEP-OUT COMMAND PAGE PSEKC: ;OR IN SEKDEL AND PERFORM SEEK TYPE COMMAND ;ENTRY ;B = SEEK TYPE COMMAND ;EXIT ;CBIT = SET IF ERROR ;A = FDC STATUS IF ERROR LD A,(SEKDEL) AND 00010111B ;UPDATE, VERIFY, & STEP RATE OR B ;OR IN ACTUAL COMMAND DI CALL FDSK ;FUNCTION DISK JR C,XJ155 ;IF ERROR CALL WBUSY ;WAIT FOR BUSY TO DROP JR C,XJ155 ;RETURN IF TIME OUT ERROR ;HEAD SETTLE TIME LD A,20 ;Head settle time of 20ms CALL DELAY ;CHECK FOR ERRORS LD A,(SEKDEL) AND 00000100B ;VERIFY? JR Z,XJ155 ;NO VERIFY GOOD RETURN IN A,(DSK_STS) LD B,A ;SAVE FDC STATUS AND 00011000B ;TEST SEEK AND CRC JR Z,XJ155 ;GOOD RETURN LD A,B ;RESTORE FDC STATUS SCF ;IF ERROR XJ155: EI RET PAGE READ: ;ENTRY ;B = NUMB OF SECTORS TO READ ;EXIT ;HL = LAST DMA ADDRESS PLUS ONE IF GOOD TRANSFER ;CBIT = SET IF ERROR ;B = FDC STATUS IF ERROR LD A,D.RDS LD (R_WCOM),A JR RD_WRT ;JMP AND RETURN TO CALLING PROC PAGE WRITE: ;ENTRY ;B = NUMB OF SECTORS TO WRITE ;EXIT ;HL = LAST DMA ADDRESS PLUS ONE IF GOOD TRANSFER ;CBIT = SET IF ERROR ;B = FDC STATUS IF ERROR LD A,D.WRTS LD (R_WCOM),A ;FALLS THROUGH TO RD_WRT PAGE RD_WRT: ;READ OR WRITE A SECTOR ; THIS ROUTINE ASSUMES THAT IX IS NOT CHANGED BY ANY CALLED ; ROUTINE (FDSK, ETC). ;ENTRY ;B = NUMB OF SECTORS TO READ OR WRITE ;R_WCOM = D.RDS OR D.WRTS ;EXIT ;HL = LAST DMA ADDRESS PLUS ONE IF GOOD TRANSFER ;CBIT = SET IF ERROR ;A = 0 IF NO ERROR, 1 IF HARD ERROR, 2 IF WRITE PROTECTED ;B = FDC STATUS IF ERROR ;SET SECTOR REG LD A,(SAVSEC) OUT (DSK_SEC),A PUSH BC ;SAVE NUMBER OF SECTORS TO R/W ;LOCATE ADDRESS OF DMA TRANSFER ROUTINE LD A,(R_WCOM) ;GET D.RDS OR D.WRTS CP D.RDS ;IS COMMAND IN A A READ? LD IX,DMARD JR Z,XJ156 ;IF READ LD IX,DMAWRT ;IF WRITE ;SET DE TO NUMBER OF BYTES IN ONE SECTOR XJ156: LD HL,128 LD A,(SAVTYP) ;DISK TYPE SRL A ;DUMP TWO BITS SRL A AND 00000011B ;SIZE ONLY OR A ;SET CFLAG JR Z,XJ157 ;IF 128 LD B,A XJ158: ADD HL,HL ;SHIFT LEFT ONE BIT DJNZ XJ158 XJ157: EX DE,HL ;DE=NUMBER OF BYTES IN ONE SECTOR POP BC ;RESTORE NUMBER OF SECTORS TO R/W PUSH BC ;SAVE ;GET COMMAND AND CHECK FOR MULTI-SECTOR LD A,B ;GET NUMBER OF SECTORS LD C,0 ;MAKE NONMULTI-SECTOR CP 2 JR C,XJ159 ;IF LESS THAN TWO SECTORS LD C,10H ;MAKE MULTI-SECTOR XJ159: LD A,(R_WCOM) ;GET D.RDS OR D.WRTS OR C ;MAKE MULTI-SECTOR OR NONMULTI-SECTOR ;A = COMMAND FOR FDSK ;SET HL TO NUMBER OF BYTES TO TRANSFER LD HL,0 XJ160: ADD HL,DE DJNZ XJ160 PUSH HL ;SAVE LENTH ;GIVE COMMAND DI CALL SSEL ;Form command with correct side CALL FDSK JR NC,XJ161 ;IF GOOD ;IF ABORT BEFORE DMA EI LD B,A POP DE ;RESTORE STACK POP DE JR XJ162 ;RETURN IF ERROR IN FDSK ;SET RETURN FROM DMA, DMA ADDR AND NUMBER OF BYTES TO TRANSFER XJ161: POP BC ;RESTORE LENGTH LD HL,(DMADR) ;HL = DMA ADDRESS LD DE,XJ163 PUSH DE ;FOR RETURN JP (IX) ;CALL DMA TRANSFER RTN ;RETURN FROM DMA AND CHECK FOR BUSY AND RESET XJ163: POP BC ;RESTORE NUMBER OF SECTORS IN A,(DSK_STS) ;GET STATUS BIT 0,A JR Z,XJ164 ;IF NOT BUSY LD DE,XJ165 PUSH DE ;FOR RETURN DEC B ;SUBTRACT ONE FROM THE NUMBER OF SECTORS AND SET THE ZERO FLAG JP Z,WBUSY ;IF NON MULTI-SECTOR R/W WAIT FOR BUSY TO DROP JP FORINT ;CLEAR BUSY XJ165: IN A,(DSK_STS) ;RETURN AND GET STATUS ;CHECK FOR ERRORS XJ164: EI LD B,A AND 01011100B ;TEST WRITE PROTECT, RNF, CRC, AND LOST DATA RET Z ;IF GOOD (CBIT RESET WITH ANI INSTRUCTION) ;FDC ERROR AND 01000000B ;IS WRITE PROTECTED ? LD A,2 JR NZ,XJ166 ;YES XJ162: LD A,1 ;HARD ERROR XJ166: SCF RET ;RETURN PAGE RADR: ;READ ADDRESS INFO. ;READS SIX BYTES INTO "DSTSB" ;ENTRY ;NONE ;EXIT ;A = FDC STATUS IF ERROR ;CBIT = SET IF ERROR ;DSK_TRK = HEAD POSITION ;NOTE* ; SETS TRACK REG IN CONTROLLER IF GOOD LD A,D.RDA DI CALL SSEL CALL FDSK ;FUNCTION DISK JR C,XJ168 ;WAIT FOR FIRST DRQ OR TIME OUT ;SET REGESTERS FOR DMA TRANSFER LD B,5 ;SIX BYTES TO READ LD HL,DSTSB ;FBA FOR DMA ;WAIT FOR 1/2 OF A TRACK (100MS) OR DRQ LD DE,7273 XJ169: IN A,(DSK_STS) ;(11+2) GET STATUS RRA ;(4) RRA ;(4) JP C,XJ170 ;(10) GOT DRQ DEC DE ;(6) LD A,D ;(4) OR E ;(4) JP NZ,XJ169 ;(10) ;INDICATE TIME OUT ERROR CALL FORINT ;CLEAR BUSY JR XJ171 ;INDICATE A TIME OUT ERROR ;TRANSFER FIRST BYTE AND CALL DMARD FOR LAST FIVE BYTES XJ170: IN A,(DSK_DAT) ;(11+2) GET BYTE LD (HL),A ;(7) STORE BYTE INC HL ;(6) ;BC = 5 CALL ROMREAD ;(17) CALL ROM RESIDENT DMA READ ROUTINE (NO BANK SWITCHING) ;RETURN FROM DMARD AND WAIT FOR BUSY TO BE RESET CALL WBUSY JR C,XJ168 ;IF TIME OUT ERROR IN A,(DSK_STS) ;GET STATUS LD B,A ;CHECK FOR ERRORS AND 00011100B ;TEST RNF, CRC AND DATA LOST LD A,B JR NZ,XJ171 ;IF ERROR ;SET TRACK REGISTER IN A,(DSK_SEC) ;GET TRACK OUT (DSK_TRK),A ;SET TRACK XOR A ;RESET CARRY JR XJ168 XJ171: SCF ;SET CBIT XJ168: EI RET PAGE ROMREAD: ;DMA READ ROUTINE USED BY RADR. RADR NEEDS A VERY QUICK ;DMA ROUTINE SINCE IT HAS ALREADY READ ONE BYTE AND MUST GET ;TO THE NEXT BYTE IN TIME. THE NORMAL DMA ROUTINE SPENDS TOO ;MUCH TIME DOING BANK SWITCHING ;ENTRY ;B = NUMBER OF BYTES TO TRANSFER ;HL = FWA OF BUFFER ;EXIT ;HL = NEXT ADDRESS ;DO DMA XJ172: IN A,(DSK_STS) ;(13) GET STATUS RRA ;(4) RET NC ;(5) RETURN IF NO BUSY RRA ;(4) JP NC,XJ172 ;(10) IF NO DRQ IN A,(DSK_DAT) ;(13) GET BYTE LD (HL),A ;(7) STORE BYTE INC HL ;(6) DJNZ XJ172 ;(13) ON JUMP RET PAGE FMTTRK: ;FORMAT ONE TRACK ;ENTRY ;BC = LENTH ;DMADR = FWA OF BUFFER ;DMABANK = BUFFER'S BANK ;EXIT ;CBIT = SET IF ERROR ;A = FDC STATUS IF ERROR ;TEST DENSITY AND SET REG D TO 04EH OR 0FFH LD A,(SAVTYP) LD D,04EH ;DOUBLE RRCA JR NC,XJ173 ;IF DOUBLE LD D,0FFH ;SINGLE ;GIVE COMMAND XJ173: LD A,D.WRTT PUSH DE ;FILL BYTE PUSH BC ;LENTH DI CALL SSEL CALL FDSK POP BC ;LENTH POP DE ;FILL BYTE JR C,XJ174 ;IF ERROR ;DO DMA PUSH DE ;FILL BYTE LD HL,(DMADR) CALL DMAWRT ;PAD REST OF TRACK POP BC ;B = FILL BYTE XJ175: IN A,(DSK_STS) ;GET STATUS RRA JR NC,XJ176 ;FINISHED IF NO BUSY RRA JR NC,XJ175 ;IF NO DRQ LD A,B OUT (DSK_DAT),A ;STORE BYTE JR XJ175 PAGE ;CHECK FOR ERROR XJ176: IN A,(DSK_STS) ;GET STATUS LD B,A ;SAVE AND 01000100B ;TEST WRITE PROTECT, AND DATA LOST LD A,B JR Z,XJ177 ;IF GOOD XJ174: SCF XJ177: EI RET PAGE SSEL: ;SIDE SELECT, selects appropriate side using SAVTYP bit 1 ; ;ENTRY ; A = FDC Command ; SAVTYP = Side bit set to appropriate value ; ;EXIT ; A = FDC Command with side bit modified ; LD B,A ;Save command LD A,(SAVTYP) AND 00000010B ;Just get side bit OR B ;And form new command RET PAGE FORINT: ;INTERRUPT DISK CONTROLLER ;IF ANY APPLICATION PROGRAM CALLS THIS ROUTINE, THAT PROGRAM SHOULD ;DISABLE AND ENABLE THE INTERRUPT FOR FORINT ROUTINE. ;ENTRY ;NONE ;EXIT ;BUSY CLEARED. ;CBIT = SET IF ERROR ;A = FDC STATUS IF ERROR LD A,D.FINT OUT (DSK_CMD),A ;WAIT FOR AT LEAST 24 MICROSECONDS FOR SINGLE DENSITY ; 12 MICROSECONDS FOR DOUBLE DENSITY TO READ BUSY STATUS ; FOR 1 MHZ CLOCK LD A,(SAVTYP) ;(13)DISK TYPE RRCA ;(4) LD B,1 ;(7) JR NC,XJ178 ;(12) OR (7) - DOUBLE DENSITY LD B,4 ;(7) XJ178: DJNZ XJ178 ;(13) OR (8) ;CHECK FOR BUSY DROP CALL WBUSY ;(17) RET PAGE FDSK: ;FUNCTION DISK ROUTINE ;THIS IS THE ONLY ROUTINE THAT WRITES TO THE COMMAND REGESTER OF THE CONTROLER CHIP ;THIS ROUTINE HAS A BUILT IN DELAY OF AT LEAST 28 MICRO SEC. BEFORE READING THE STATUS ON THE CHIP ;ENTRY ;A = FUNCTION CODE ;EXIT ;A = 0 IF NO ERROR, FDC STATUS IF ERROR ;CBIT = SET IF ERROR LD B,A ;SAVE FUNCTION CODE IN B IN A,(DSK_STS) ;STATUS REGISTER RRCA LD A,B JR NC,XJ179 ;IF NOT BUSY CALL FORINT ;RESET BUSY XJ179: OUT (DSK_CMD),A ;FUNCTION DRIVE(WRITE COMMAND TO CONTROLER) ;WAIT FOR 56 SINGLE AND 28 DOUBLE(MICRO SEC.) LD A,(SAVTYP) ;(13) DISK TYPE LD B,5 ;(7) RRCA ;(4) JR NC,XJ180 ;(10) IF DOUBLE DENSITY LD B,13 ;(7) XJ180: DJNZ XJ180 ;(13) WAIT ;WAIT FOR BUSY TO BE SET LD B,0FFH ;(7) 256 LOOPS XJ181: IN A,(DSK_STS) ;TEST BUSY BIT BIT 0,A JR NZ,XJ182 ;IF CHIP WENT BUSY DJNZ XJ181 ;IF NOT TIME-OUT SCF ;IF ERROR A=FDC STATUS AND CBIT = SET RET XJ182: OR 0FFH LD (DACTVE),A ;SET DRIVE ACTIVE COUNTER XOR A ;NO ERROR A=0 AND CBIT=RESET RET PAGE SELDRV: ;SELECT DRIVE ;ENTRY ;SDISK = DRIVE TO SELECT ;EXIT ;ZBIT = SET IF DRIVE ALREADY SELECTED ;ZBIT = RESET IF DRIVE NOT ALREADY SELECTED DI ;DISABLE INTERRUPTS WHILE USING SYSTEM PIA ;(TO PREVENT INTERRUPT FROM TURNING DRIVE OFF) ;SELECT DENSITY IN A,(SYS_DTB) ;GET CURRENT REG VALUE AND 11111110B ;CLEAR BIT 0 LD C,A ;SET DENSITY BIT LD A,(SAVTYP) ;GET DISK TYPE INFO RRCA ;CBIT <= BIT 0 JR NC,XJ183 ;IF "SAVTYP" BIT0 IS 0  SET 0,C ;SET BIT 0 OF REG C XJ183: LD A,C OUT (SYS_DTB),A ;FUNCTION PIA ;SET DRIVE ACTIVE COUNTER LD HL,DACTVE LD (HL),0FFH ;SET DRIVE ACTIVE COUNTER ;GET DRIVE TO SELECT LD A,(SDISK) LD HL,DSKSWP ;DISK DRIVE SWAP CELL XOR (HL) ;SWAP A FOR B IF DSKSWP=1 AND 1 ;CAN ONLY BE 0 OR 1 CP 1 JR Z,XJ184 ;IF DRIVE 1 LD A,2 ;IF DRIVE 0 XJ184: SLA A ;POSITION BITS (DR 0 = 0000_0100, DR 1 = 0000_0010) LD C,A IN A,(SYS_DTB) LD B,A AND 00000110B ;GET DRIVE BITS ONLY CP C JR NZ,XJ185 ;IF DRIVE ISN'T ALREADY SELECTED EI RET ;RETURN IF DRIVE ALREADY SELECTED PAGE ;SELECT DRIVE ;TURN DRIVE ON XJ185: IN A,(SYS_DTB) ;GET SETTINGS AND 11111001B ;SET DRIVE BITS TO 0 OR C ;ADD NEW DRIVE BITS OUT (SYS_DTB),A ;SAVE NEW SETTING LD A,25 LD (DCHK_FLG),A ;DON'T CHECK FOR DISK CHANGE EI ;& DON'T LEAVE INTERRUPTS DISABLED WHILE DAB12/13 ;MOTOR SPINS UP. ;SPIN UP LD A,250 CALL DELAY ;WAIT FOR MOTOR SPIN UP LD A,250 CALL DELAY ;2ND DELAY OR 0FFH ;INDICATED DRIVE WAS NOT ALREADY SELECTED ;CLEAR ZBIT RET PAGE WBUSY: ;WAIT FOR BUSY TO CLEAR ;THIS ROUTINE MUST WAIT FOR 2 SECONDS ;2 SECONDS IS THE TIME IT TAKES FOR THE CHIP TO SEEK 39 TRACKS AND HAVE FIVE INDEX HOLES GO BY. ;ENTRY ;NONE ;EXIT ;A = FDC STATUS IF ERROR ;CBIT = SET " " " " LD BC,0 XJ186: IN A,(DSK_STS) ;(11) LD D,A ;SAVE STATUS RRCA ;(4) DS.BSY (CBIT RESET WITH ANI INSTRUCTION) JR NC,XJ187 ;(7) GOOD RETURN EX (SP),HL ;(19) DELAY EX (SP),HL ;(19) DELAY EX (SP),HL ;(19) DELAY EX (SP),HL ;(19) DELAY DEC BC ;(6) LD A,B ;(4) OR C ;(4) JR NZ,XJ186 ;(12) IF NOT TIME-OUT SET 7,D ;TIME OUT ERROR (NOT READY BIT) LD A,D ;FDC STATUS IS IN A SCF ;SET ERROR XJ187: RET PAGE FORMAT: ; THIS PROC WILL FORMAT THE NEXT TRACK IN IBM 3740 FORMAT CONSISTING OF 40 TRACKS, WITH EACH ;TRACK CONTAINING 10 SECTORS. ;ENTRY ;SAVTRK = THE TRACK TO BE FORMATED ;EXIT ;Z = 0 IF ERROR, 1 IF NO ERROR ;A = 0 IF NO ERROR, FDC STATUS IF ERROR ;SELECT DRIVE CALL SELDRV ;TEST FOR STEP OR NO-STEP LD HL,SAVTRK IN A,(DSK_TRK) ;TRACK REG CP (HL) JR Z,XJ188 ;IF SAVTRK AND TRACK REG ARE THE SAME SKIP THE STEP ;STEP IN ONE TRACK LD A,(SEKDEL) OR 00010000B ;UPDATE LD (SEKDEL),A ;SET UP SEKDEL CALL STEPIN PUSH AF ;SAVE CFLAG LD A,(SEKDEL) XOR 00010000B ;TOGGLE UPDATE BIT LD (SEKDEL),A ;RESET SEKDEL POP AF ;RESTORE JR C,XJ189 PAGE ;SET "DMADR" ;MOVE THE LENGTH BYTES TO A SPOT WHERE THEY CAN BE READ XJ188: LD HL,(DMADR) ;HL = SOURCE ADDRESS LD DE,HIBUFF ;DE = DESTINATION LD A,(DMABANK) LD (SRCBANK),A ;SOURCE BANK LD A,ROM_BANK ;DESTINATION BANK LD (DESTBANK),A LD BC,2 ;MOVE 2 BYTES CALL BANKMOVE ;SAVE DMADR LD (DMADR),HL ;BANKMOVE RETURNS WITH ;HL = NEXT ADDRESS IN SOURCE STRING ;GET LENGTH LD HL,HIBUFF LD C,(HL) INC HL LD B,(HL) ;BC = LENGTH OF FORMAT DATA ;FORMAT TRACK CALL FMTTRK JR C,XJ189 XOR A RET XJ189: ;A = FDC STATUS OR A RET PAGE DELAY: ;'N' MILLISECONDS ;ENTRY ;A = NUMBER OF MILLISECONDS TO DELAY ;SCLFRE = (FREQ/1000)/(# OF TICS IN LOOP) ;EXIT ;NONE LD C,A XJ190: LD A,SCLFRE XJ191: DEC A ;(4 TICS) LD B,B ;(4 TICS) LD C,C ;(4 TICS) JR NZ,XJ191 ;(10 TICS) IF 1 MS NOT ELAPSED DEC C JR NZ,XJ190 ;IF REQUESTED MSEC NOT DONE RET PAGE ; ********************************************************* ; * * ; * DISK EQUATES * ; * * ; ********************************************************* D.SEK EQU 010H ;SEEK D.STP EQU 020H ;STEP D.STPI EQU 040H ;STEP IN D.STPO EQU 060H ;STEP OUT D.RDS EQU 088H ;READ SECTOR D.WRTS EQU 0A8H ;WRITE SECTOR D.RDA EQU 0C0H ;READ ADDRESS D.RDT EQU 0E0H ;READ TRACK D.WRTT EQU 0F0H ;WRITE TRACK D.FINT EQU 0D0H ;FORCE INTERRUPT DRV_A EQU 04H ;SELECT DRIVE A DRV_B EQU 02H ;SELECT DRIVE B T PAGE DELAY: ;'N' MILLISECONDS ;ENTRY ;A = NUMBER OF MILLISECONDS TO DELAY ;SCLFRE = (FREQ/1000)/(# OF TICS IN LOOP) ;EXIT ;NONE LD C,A XJ190: LD A,SCLFRE XJ191: DEC A ;(4 TICS) LD B,B ;(4 TICS) LD C,C ;(4 TICS) JR NZ,XJ191 ;(10 TICS) IF 1 MS NOT ELAPSED DEC C JR NZ,XJ190 ;IF REQUESTED MSEC NOT DONE RET PAGE ; ********************************************************* ; * * ; * DISK EQUATES * ; * * ; ********************************************************* D.SEK EQU 010H ;SEEK D.STP EQU 020H ;STEP D.STPI EQU 040H ;STEP IN D.STPO EQU 060H ;STEP OUT D.RDS EQU 088H ;READ SECTOR D.WRTS EQU 0A8H ;WRITE SECTOR D.RDA EQU 0C0H ;READ ADDRESS D.RDT EQU 0E0H ;READ TRACK D.WRTT EQU 0F0H ;WRITE TRACK D.FINT EQU 0D0H ;FORCE INTERRUPT DRV_A EQU 04H ;SELECT DRIVE A DRV_B EQU  ;.LAST MODIFIED: ROGER W. CHAPMAN REV 1.21 (4.030) ;.TITLE: EXECUTIVE MONITOR ROM ;.COMMENTS: ; ; +-------------------------------+ ; | | ; | EXECUTIVE MONITOR | ; | COPYRIGHT 1984 | ; | BY | ; | OSBORNE COMPUTER CORPORATION | ; | 26538 DANTI COURT | ; | HAYWARD, CA 94545 | ; | | ; | CREATED BY | ; | ROGER W. CHAPMAN | ; | WENDY JAMES | ; | DAVID BERG | ; | CHRIS MAYER | ; | | ; +-------------------------------+ PAGE ;------------------------------------------------------------------------------- ; REVISION HISTORY ; ; 03/24/83: ; A. MODIFIED RADR ROUTINE TO USE 100 MS TIME OUT INSTEAD OF 60 MS. THIS ; CHANGE WAS NECESSARY BECAUSE OF THE DISK CHANGE DETECT ALGORITHM, ; WHICH COULD CAUSE THE CONTROLLER TO LOSE SYNC AND POTENTIALLY MISS THE ; NEXT ADDRESS MARK. ; ; B. MODIFIED SIGN-ON TO REFLECT CURRENT RELEASE VERSION NUMBER V1.2 ; ; 06/27/83: ; A. ALL SOURCE CODE CONVERTED FROM ACT TO M80 ; ; B. ROM SOURCE SPLIT INTO EIGHT MODULES ; ; 07/11/83: ; A. MODIFIED BUFFER ROUTINES (IN ROM7.MAC) TO FIX BUFFER ALLOCATION ; PROBLEM. ; ; 07/25/83: ; A. MODIFIED DISK ROUTINES (IN ROM5.MAC) TO SUPPORT DOUBLE SIDED DISK ; DRIVES ; ; 08/01/83: ; A. CORRECTED PARAMETER PASSING PROBLEM IN IEEE ROUTINES (ROM4.MAC) ; ; B. MODIFIED SIGN-ON TO REFLECT CURRENT STATE OF ROM CODE X1.3 ; ; 01/30/84: ; A. Removed double-sided support from SENDEN (ROM5.MAC) ; ; B. Changed interrupt handler to push all register on stack instead of ; using alternate regs ; ; C. Modified sign-on to reflect current version # V1.21 ; (double-sided support was removed, bug fix was implemented) ;-------------------------------------------------------------------------------- PAGE ; MODULE 0 --ROM0.MAC-- ENTRY POINTS ; ; BOOT AND INITIALIZE SYSTEM ; ; ; START: START OF ROM ; AUTOBOOT: BOOT THE SYSTEM ; INITIALIZE: INITIALIZES (INIT.) MEMORY AND SYSTEM PIA ; CBOOT: INIT. (STACK/MEMORY/INTERRUPTS) AND LOADS BOOT STRAP ; BOOT: LOADS BOOT STRAP LOADER ; RES_SIO: RESETS THE SIO ; INIT_INT: INIT. THE SIO AND INTERRUPT STATE ; SYSINIT: INIT. SYSTEM AND PARALLEL PIA ; INIT_POLL: INIT. BANK AND ADDRESS OF INTERRUPT POLLING ROUTINE ; KB_INIT: INIT. KEYBOARD TABLE POINTERS AND SCAN MASKS ; CONINIT: INIT. ALL NON-ZERO VALUES FOR CONSOLE ; SETCHAR: FILLS CHARACTER FONT RAM WITH CHARACTER SET ; SETJMP: INIT. HIGH RAM JUMP VECTORS ; OSTR: OUTPUTS STRING TO THE CONSOLE ; ; NOTE............THE ROM JUMP TABLE ALSO RESIDES IN THIS MODULE 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 ; PAGE ; EXT SET_INT,CON_IN,STINT,INT_HL,LENINT,R_INT_TBL,R_I_TBL_LEN ; EXT IN_AL_BF,SKEY,COUT,SAI_STAT,SBI_STAT,SAO_STAT,SBO_STAT,SERAIN ; EXT SERBIN,SERAOUT,SERBOUT,SETBAUD,IE.CO,IE.SI,IE.GTS,IE.TC,IE.OIM ; EXT IE.ODM,IE.IDM,IE.PP,IEINSTAT,IEOSTAT,IEINP,IEOUT,PISTAT,POSTAT ; EXT PARINP,PAROUT,RDRV,RSEC,WSEC,SENDEN,FORMAT,SELDRV,STEP,STEPIN ; EXT STEPOUT,SEEK,HOME,FORINT,FMTTRK,DMAWRT,DMARD,READ,WRITE,RADR ; EXT SETDMA,CTC_INIT,SIOINIT,INT_POLL,BANKJMP,BANKCALL,BANKMOVE ; EXT CTBLPTRS,LENCTBL,PODIAG,L_PWR_UP,DIAG_INIT ; PUBLIC AL_T_SZ,INIT_INT,OSTR,AUTOBOOT,INITIALIZE PAGE ASEG ORG 0 ;START THE LOC COUNTER AT LO MEM .PHASE 0H ; ********************************************************* ; * * ; * START OF ROM * ; * * ; ********************************************************* START: ;INITIALIZE ALL DEPENDENT HARDWARE. LD SP,ROMSTK ;SET STACK CALL INITIALIZE ;INITIALIZE MEMORY AND SYSTEM PIA XOR A LD (RSTHLD),A ;CLEAR RSTHLD, THE RESET INTERRUPT ROUTINE ; WILL SET RSTHLD IF RESET IS BEING PRESSED LD B,A LD C,A ;BC = 0 CALL SET_INT ;INDIVIDUALLY DISABLE ALL INTERRUPTS EXCEPT RESET ;(SIO HAS NOT BEEN INITIALIZED AT THIS POINT) ;RESET SIO TO KEEP IT FROM INT ERRUPTING AND CONFUSING THE RESET/POWER ON ISSUE CALL RES_SIO ;INITIALIZE SIO AND NORMAL INTERRUPT STATE CALL INIT_INT ;INITIALIZE SIO AND REENABLE ALL INTERRUPTS ;(RESET SHOULD HAVE HAD TIME TO INTERRUPT AT THIS POINT) ;CHECK FOR RESET LD A,(RSTHLD) ;CHECK FOR RESET INT OR A JP NZ,AUTOBOOT ;IF RESET PRESSED, BOOT ;FALL THROUGH TO PWRUP IF RESET NOT PRESSED CALL PODIAG PAGE AUTOBOOT: ;SIGN ON PROMPT LD DE,IMSG CALL OSTR ;OUTPUT INITIAL MESSAGE EI ;ENABLE INTERUPTS ;BOOT XJ000: CALL CON_IN ;READ IN NEXT CHAR CP CR LD B,0 ;IF BOOT FROM DRIVE A JR Z,XJ001 ;IF COLD BOOT OFF OF A, TRY TO BOOT INC B ;SWAP DRIVES: A=B, B=A CP 'I'-40H JR Z,XJ001 ;IF NOT DRIVE B, TRY AGAIN CP 'T' JP Z,L_PWR_UP ;LOOP POWER UP TEST JR XJ000 XJ001: LD A,B ;A = 0 FOR DRIVE A, 1 FOR DRIVE B Jذ BOOش PAGE INITIALIZE: ;INITIALIZES MEMORY AND SYSTEM PIA ;ENTRY ;NONE ;EXIT ;SYSTEM INITIALIZED ;INITIALIZE MEMORY  ;CLEAR ALL LD HL,MONRAM ;START LD DE,MONRAM+1 LD BC,RSTMODE-MONRAM-1 ;LENGTH LD (HL),0 LDIR LD HL,MRAM LD DE,MRAM+1 LD BC,EMRAM-MRAM LD (HL),0 LDIR ;SET VALUES OF ONE LD A,1 ;A = ONE LD (KEYLCK),A ;INDICATE NOT LOCKED ;SET VALUES OF TWO INC A ;A = TWO LD (SEKDEL),A ;SET SEEK STEP RATE FOR SEMIENS ;SET DISK RETRY NUMBER LD A,10 LD (NRETRY),A ; INITIALIZE DISK CHANGE DETECT VARIABLE LD HL,WP_STS LD (MEDIA),HL LD (A_DRIVE),HL LD (B_DRIVE),HL ;INITIALIZE KEY CODE TABLE POINTERS CALL KB_INIT ;INITIALIZE REAL TIME CLOCK POINTER LD HL,ROMCLK LD (CLK_PTR),HL ;POINT TO SPOT IN ROM ;INITIALIZE CONSOLE VALUES CALL CONINIT ;INITIALIZE HIGH RAM JUMP VECTORS CALL SETJMP ;INITIALIZE JUMP VECTORS FOR HIGH RAM ROUTINES ;(BANKMOVE, BANKJMP, BANKCALL, DMA READ AND WRITE) ;INITIALIZE CHARACTER FONT RAM LD DE,CHRFONT ;INIT MAIN SET CALL SETCHAR ; LD DE,CHRFONT+800H ;INIT ALTERNATE SET CALL SETCHAR PAGE ;SET INTERRUPTS ;SET MODE 2 INTERUPTS IM 2 ;SET INTERRUPT REGISTER LD A,HIGH SIO_I_TBL LD I,A ;MOVE INTERRUPT ROUTINES TO HIGH RAM ; (MUST DO THIS BEFORE INITIALIZING INTERRUPT JUMP TABLE) LD HL,STINT ;START ADDRESS IN ROM LD DE,INT_HL ;DESTINATION IN HIGH RAM LD BC,LENINT ;LENGTH LDIR ;INITIALIZE SIO INTERRUPT JUMP VECTORS LD B,8 ;LOAD B WITH NUMBER OF ENTRIES TO INIT LD HL,SIO_I_TBL ;POINT HL TO LOCATION TO INIT LD DE,INT_HL ;LOAD DE WITH ADDRESS OF INTERRUPT HANDLER XJ002: LD (HL),E ;SAVE LOW BYTE OF INTERRUPT HANDLER ADDRESS INC HL ;BUMP PTR TO NEXT CELL LD (HL),D ;SAVE HI BYTE INC HL ;BUMP PTR TO NEXT CELL DJNZ XJ002 ;IF MORE ENTRIES ;INITIALIZE OTHER INTERRUPT VECTOR LD HL,INTVEC ;LOCATION TO INITIALIZE LD (HL),E INC HL LD (HL),D ;INITIALIZE INTERRUPT TABLE LD HL,R_INT_TBL LD DE,INT_TBL LD BC,R_I_TBL_LEN LDIR ;INITIALIZE I/O BUFFERS CALL IN_AL_BF ;INITIALIZE CHARACTER I/O BUFFERS ;INITIALIZE POLLING ROUTINE ADDRESS AND BANK CALL INIT_POLL ;INITIALIZE SYSTEM PIA JP SYSINIT ;SYSINIT WILL RETURN PAGE ;ROM VERSION NUMBER IF $ GT 0FCH .PRINTX 'PAGE 0 OVERFLOW ' ENDIF .DEPHASE ORG 0FCH .PHASE 0FCH VERSION: DB 2 ;PRODUCT CODE (EXECUTIVE = OCC 2) DB 0 ;OPTIONS CODE (0 = BASE MACHINE) DW 4030H ;VERSION NUMBER .DEPHASE CSEG PAGE ;START OF ROM JUMP TABLE ; ********************************************************* ; * * ; * ROM JUMP TABLE * ; * * ; ********************************************************* ; CBIOS = JMPS USED MAINLY BY CBIOS JP CBOOT ;CBIOS COLD BOOT ; CONSOLE I/O JP SKEY ;CBIOS KEYBOARD STATUS JP CON_IN ;CBIOS KEYBOARD INPUT JP COUT ;CBIOS CONSOLE OUTPUT ; SERIAL I/O JP SAI_STAT ; SERIAL PORT A INPUT STATUS JP SBI_STAT ;CBIOS SERIAL PORT B INPUT STATUS JP SAO_STAT ; SERIAL PORT A OUTPUT STATUS JP SBO_STAT ;CBIOS SERIAL PORT B OUTPUT STATUS JP SERAIN ;CBIOS SERIAL PORT A INPUT (READER INPUT) JP SERBIN ; SERIAL PORT B INPUT JP SERAOUT ;CBIOS SERIAL PORT A OUTPUT (PUNCH OUTPUT) JP SERBOUT ;CBIOS SERIAL PORT B OUTPUT (LIST OUTPUT) JP SETBAUD ;CBIOS SIO SET BAUD RATE ; IEEE JP IE.CO ;CBIOS IEEE CONTROL OUT JP IE.SI ;CBIOS STATUS IN JP IE.GTS ;CBIOS GO TO STANDBY JP IE.TC ;CBIOS TAKE CONTROL JP IE.OIM ;CBIOS OUTPUT INTERFACE MESSAGE JP IE.ODM ;CBIOS OUTPUT DEVICE MESSAGE JP IE.IDM ;CBIOS INPUT DEVICE MESSAGE JP IE.PP ;CBIOS PARALLEL POLL JP IEINSTAT ;CBIOS IEEE JP IEOSTAT ;CBIOS IEEE JP IEINP ;CBIOS IEEE JP IEOUT ;CBIOS IEEE JP PISTAT ;CBIOS IEEE JP POSTAT ;CBIOS IEEE JP PARINP ;CBIOS IEEE JP PAROUT ;CBIOS IEEE PAGE ; DISK I/O JP RDRV ;CBIOS HOME JP RSEC ;CBIOS DISK SECTOR READ JP WSEC ;CBIOS DISK SECTOR WRITE JP SENDEN ;CBIOS SENSE THE DENSITY OF DRIVE JP FORMAT ;CBIOS FORMATING ROUTINE JP SELDRV ; SELECT DRIVE JP STEP ; STEP SAME DIRECTION JP STEPOUT ; STEP O UT JP STEPIN ; STEP IN JP SEEK ; SEEK TO TRACK JP HOME ; HOME DISK DRIVE JP FORINT ; FORCE INTERUPT JP FMTTRK ; FORMAT ONE TRACK JP DMAWRT ; DMA WRITE TO CONTROLER JP DMARD ; DMA READ FROM CONTROLER ; DIAGNOSTIC ENTRY POINTS JP OSTR ; OUTPUT STRING TO CONSOLE JP DIAG_INIT ;INITIALIZE SYSTEM FOR DIAGNOSTIC JP READ ;READ SECTOR (DIAG ONLY!!) JP WRITE ;WRITE SECTOR (DIAG ONLY!!) JP RADR ;READ ADDRESS PAGE ; ********************************************************* ; * * ; * BOOT ROUTINES * ; * * ; ********************************************************* CBOOT: ;INITIALIZE STACK, MEMORY, I/O PORTS, INTERRUPTS ;LOAD BOOT STRAP LOADER ;ENTRY ;A = DRIVE TO BOOT FROM ;EXIT ;NONE DI ;DISABLE INTERRUPTS WHILE WE ;INIT EVERYTHING. LD SP,ROMSTK ;SET STACK POINTER PUSH AF ;SAVE DRIVE TO BOOT FROM CALL INITIALIZE ;INITIALIZE MEMORY AND PIA CALL INIT_INT ;INITIALIZE SIO AND INTERRUPT STATE POP AF ;GET DRIVE TO BOOT FROM ; JMP BOOT ;FALL THROUGH TO BOOT PAGE BOOT: ;LOAD BOOTSTRAP ;ENTRY A = DRIVE TO BOOT FROM LD (DSKSWP),A ;SET DRIVE TO BOOT FROM OR A ;CHECK DRIVE TO SET DRIVE MASK LD HL,DRV_MSK LD B,2 JR NZ,XJ012 LD B,4 XJ012: LD (HL),B ;SAVE DRIVE MASK ;LOAD BOOT STRAP LOADER (ONE PHYSICAL SECTOR) ;READ SECTOR XJ013: LD DE,LD_MSG ;POINT AT MESSAGE CALL OSTR ;DISPLAY IT CALL RDRV ;HOME DRIVE ;SET "SAVTYP" CALL SENDEN ;DETERMINE DENSITY JR NZ,XJ014 ;IF BAD... LD HL,BOOTADDR LD A,BOOTBANK LD (JMPBANK),A ;SET BANK # TO JUMP TO CALL SETDMA XOR A LD (SAVTRK),A ;TRACK 0 INC A LD (SAVSEC),A ;SECTOR 1 LD B,A ;READ 1 SECTOR LD A,(SAVTYP) ;SAVE SAVTYP STATUS PUSH AF RES 1,A ;SET SAVTYP TO READ SIDE 0 LD (SAVTYP),A CALL RSEC POP DE ;RESTORE SAVTYP STATUS LD A,D LD (SAVTYP),A JR NZ,XJ014 ;IF UNSUCCESSFUL SECTOR READ LD A,(BOOTADDR) ;LOAD FIRST BYTE OF BOOT SECTOR OR A ;IS IT ZERO? JR NZ,XJ015 ;NO...  ; ;YES. IS PRODUCT CODE CORRECT? LD A,(BOOTADDR+4) ;LOAD PRODUCT CODE CP PROD_CODE ;IS IT CORRECT? JR NZ,XJ015 ;NO... LD HL,BOOTADDR ;RETURN WITH HL = P-SYSTEM ENTRY ADDRESS LD (JMPADDR),HL ;SET ADDRESS TO JUMP TO CALL BANKJMP ;JUMP TO SYSTEM XJ014: ;HARD READ ERROR LD DE,EB_MSG ;DISPLAY MESSAGE CALL OSTR JP XJ016 ;AND WAIT FOR USER TO ENTER ;CARRIAGE RETURN XJ015: ;INVALID SYSTEM DISK LD DE,BD_MSG ;DISPLAY ERROR CALL OSTR XJ016: ;DISPLAY MESSAGE TRAILER AND LD DE,WT_CR_MSG CALL OSTR XJ017: CALL CON_IN ;WAIT FOR USER TO ENTER CARRIAGE CP CR ;RETURN JP NZ,XJ017 ;NOT CR, GET ANOTHER CHAR ; JP XJ013 ;USER ENTERED CR, TRY TO BOOT AGAIN. PAGE ; ********************************************************* ; * * ; * INITIALIZATION ROUTINES * ; * * ; ********************************************************* RES_SIO: ; RESET THE SIO BY SENDING CHANNEL RESETS TO BOTH CHANNELS. ; THIS KEEPS THE SIO FROM INTERRUPTING WHILE WE'RE CHECKING FOR ; SYSTEM RESET/POWER ON. ; ; ENTRY: ; NONE. ; EXIT: ; NONE. ; LD A,00011000B ;SIO CHANNEL RESET COMMAND OUT (SIO_CNA),A ;SEND TO CHANNEL A OUT (SIO_CNA),A ;TWICE OUT (SIO_CNB),A ;SEND TO CHANNEL B OUT (SIO_CNB),A ;TWICE RET PAGE INIT_INT: ;INITIALIZE SIO AND INTERRUPT STATE. ; ;INIT_INT CALLS SET_INT, WHICH ENABLES INTERRUPTS. ; ;ENTRY ;NONE ;EXIT ;NONE ;INITIALIZE THE CLOCK-TIMER CHIP CALL CTC_INIT ;INITIALIZE SERIAL PORTS LD C,SIO_CNB ;PORT B CALL SIOINIT LD C,SIO_CNA ;PORT A CALL SIOINIT ;INITIALIZE BAUD RATES TO 1200 LD C,BD1200 XOR A ;PORT A CALL SETBAUD LD C,BD1200 ;PORT B LD A,1 CALL SETBAUD ;INITIALIZE INTERRUPT STATE LD BC,0F800H CALL SET_INT ;INITIALIZE INTERRUPT STATES RET PAGE SYSINIT: ;INITIALIZE SYSTEM AND PARALLEL PIA ;ENTRY ;NONE ;EXIT ;NONE ;INITIALIZE A CHANNEL OF SYSTEM PIA IN A,(SYS_CNA) ; OR C_DAT ;ENABLE DATA REG OUT (SYS_CNA),A ;CONTROL A LD A,DATA_INIT ;INITIALIZE -- ENABLE ROM OUT (SYS_DTA),A IN A,(SYS_CNA) ; AND C_DIR ;ENABLE DIRECTION REG OUT (SYS_CNA),A ;CONTROL A LD A,DIRA_INIT ;INITIALIZE DIRECTION -- ALL OUTPUTS OUT (SYS_DTA),A IN A,(SYS_CNA) ; OR C_DAT ;ENABLE DATA REG AND C_DMA ;SET DMA INTERRUPT AND C_I_KBD ;SET INTELLIGENT KEYBOARD INTERRUPT OUT (SYS_CNA),A ;CONTROL A ;INITIALIZE B CHANNEL OF SYSTEM PIA IN A,(SYS_CNB) ; OR C_DAT ;ENABLE DATA REG OUT (SYS_CNB),A ;CONTROL B LD A,DATB_INIT ;INITIALIZE -- SINGLE DENSITY, DESELECT DRIVES ;SPKR OFF OUT (SYS_DTB),A IN A,(SYS_CNB) ; AND C_DIR ;ENABLE DIRECTION REG OUT (SYS_CNB),A ;CONTROL B LD A,DIRB_INIT ;INITIALIZE DIRECTION -- RI AND DSR INPUTS, OTHERS OUTPUTS OUT (SYS_DTB),A IN A,(SYS_CNB) ; OR C_DAT ;ENABLE DATA REG OR C_60_HZ_O ;SET 60 HZ AND C_60_HZ_A ; OR C_RTC ;SET REAL TIME CLOCK INTERRUPT OUT (SYS_CNB),A ;CONTROL B PAGE ;INITIALIZE A CHANNEL OF PARALLEL PIA IN A,(PA R_CNA) ; OR C_PAR ;SET PARALLEL INTERRUPT OUT (PAR_CNA),A ; LD C,1 CALL IE.CO ;INITIALIZE B CHANNEL OF PARALLEL PIA IN A,(PAR_CNB) ; OR C_FDC ;SET FDC INTERRUPT OUT (PAR_CNB),A ; RET PAGE INIT_POLL: ; INITIALIZE BANK AND ADDRESS OF INTERRUPT POLLING ROUTINE ; ; ENTRY: ; NONE. ; EXIT: ; NONE. ; LD A,ROM_BANK ;INTERRUPT POLL RTN IS IN ROM LD (I_POL_BANK),A LD HL,INT_POLL ;SAVE ADDRESS LD (I_POL_ADR),HL RET PAGE KB_INIT: ; INITIALIZES ALL KEYBOARD TABLE POINTERS TO POINT TO THE ALPHA ; LOCK TABLE. ALL KEYSTROKES WILL BE TRANSLATED TO THEIR ALPHA LOCK ; EQUIVALENTS REGARDLESS OF THE STATE OF THE SHIFT, CTRL AND ALPHA LOCK ; KEYS. ; ; ALSO INITIALIZES KEYBOARD SCAN MASKS AND LOCATIONS OF SHIFT-TYPE ; KEYS. ; ; ALL OTHER KEY DECODE TABLES HAVE BEEN REMOVED FROM THE ROM FOR SPACE ; CONSIDERATIONS. ; ; ; THE COLD BOOT ROUTINE OF ANY OS WILL HAVE TO INITIALIZE THE TABLES AND POINTERS ; TO THEM IN ROM'S RAM. ; LD HL,R_K_IN_TB ;COPY KEY MASK INTO RAM LD DE,K_MSK_TBL LD BC,K_TB_SZ LDIR LD B,5 ;COPY KEYBOARD TABLE LD DE,KEYS ;TO XJ003: PUSH BC ;SAVE LD BC,AL_T_SZ ;ALPA LOCK TABLE SIZE LD HL,AL_TB ;(FROM)INITIALIZE KEYBOARD TABLE LDIR POP BC DJNZ XJ003 RET PAGE CONINIT: ;INITIALIZE ALL NON-0 VALUES FOR CONSOLE ; (THIS ROUTINE ASSUMES 0 VALUES HAVE ALREADY BEEN INITIALIZED) ;ENTRY ;NONE ;EXIT ;CONSOLE VARIABLES INITIALIZED ;INITIALIZE POINTERS TO CONSOLE TABLE LD HL,CONTBLS ;POINT TO CONSOLE TABLES LD (ROMCON),HL ; SYSTEM POINTER ;INITIALIZE POINTERS IN THE SYSTEM CONSOLE TABLE LD HL,CTBLPTRS ;MOVE TABLE POINTERS FROM ROM LD DE,CONTBLS ;TO RAM LD BC,LENCTBL LDIR ;INITIALIZE OTHER MEMORY LOCATIONS LD HL,FWAVM LD (CURPOS),HL ;POSITION CURSOR TO TOP OF SCREEN LD (FWAWIND),HL ;INITIALIZE WINDOW TO FULL SCREEN LD A,VMCOLS LD (WINDCOLS),A ;FULL 80 COLUMNS LD A,VMROWS LD (WINDROWS),A ;FULL 24 ROWS LD A,20H LD (OFFSET),A ;X-Y POSITIONING OFFSET = 20H ;INITIALIZE ALL WINDOW DEFINITIONS TO FULL SCREEN LD B,16 ;NUMBER OF WINDOWS LD DE,WINDDEFS ;DESTINATION XJ004: PUSH BC ;INITIALIZE A WINDOW LD HL,FWAWIND LD BC,4 LDIR POP BC DJNZ XJ004 ;IF MORE WINDOWS RET PAGE PAGE SETCHAR: ;FILL CHARACTER FONT RAM WITH CHARACTER SET ;ENTRY ;DE = FONT RAM ADDRESS LD HL,FONT_TABLE ;POINT AT FONT TABLE IN ROM LD A,FONT_ROWS ;A = # ROWS TO TRANSFER XJ005: LD BC,ROW_LEخ ;BC = # BYTES / ROW LDIR ;TRANSFER A ROW LD BC,6 ;BUMP PTR TO FONT RAM TO START OF NEXT EX DE,HL ;RAM ROW ADD HL,BC ; EX DE,HL DEC A ;IS THIS THE LAST ROW? JP NZ,XJ005 ;NO, CONTINUE... ;YES... RET ;RETURN PAGE SETJMP: ;INITIALIZE HIGH RAM JUMP VECTORS ; (VECTORS TO BANKJMP, BANKCALL, BANKMOVE, DMA READ, AND DMA WRITE) ;ENTRY ;NONE ;EXIT ;NONE LD HL,STJMP ;START OF ROM COPY OF JUMP VECTORS LD DE,COMJMP ;DESTINATION IN HIGH RAM LD BC,LENJMP ;LENGTH OF TABLE LDIR RET STJMP: ;HIGH RAM JUMP VECTORS DW BANKJMP DW BANKCALL DW BANKMOVE DW DMARD DW DMAWRT LENJMP EQU $-STJMP PAGE ; ********************************************************* ; * * ; * MISCELLANEOUS ROUTINES * ; * * ; ********************************************************* OSTR: ;OUTPUT STRING TO CONSOLE ;NOTE: OSTR RECOGNIZES 7F AS AN ESCAPE SEQUENCE TO REPEAT CHAR N TIMES. ; FORMAT IS: 7F, REPEAT COUNT, CHAR ;ENTRY ;DE = FWA OF SOURCE ;EXIT ;NONE LD A,(DE) OR A PUSH AF AND 07FH CP 07FH LD C,A JR NZ,XJ192 ;IF NOT REPEAT INC DE LD A,(DE) DEC A LD B,A ;REPEAT COUNT INC DE LD A,(DE) ;GET REPEAT CHAR LD C,A PUSH DE ;SAVE DE XJ193: PUSH BC CALL COUT ;OUTPUT CHAR POP BC DJNZ XJ193 ;IF NOT DONE POP DE XJ192: PUSH DE CALL COUT ;OUTPUT IT POP DE INC DE POP AF JP P,OSTR ;IF NOT DONE OUT (1CH),A ;ENABLE VIDEO OUTPUT RET PAGE ; ********************************************************* ; * * ; * SYSTEM PIA INITIALIZATION EQUATES * ; * * ; ********************************************************* ;MASKS: C_DAT EQU 00000100B ;ORED WITH SYS PIA CONTROL TO ENABLE DATA REGISTER C_DIR EQU 11111011B ;ANDED WITH SYS PIA CONTROL TO ENABLE DIRECTION REG C_60_HZ_O EQU 00110000B ;ORED WITH SYS PIA CONTROL B TO SET 60 HZ C_60_HZ_A EQU 11110111B ;ANDED WITH SYS PIA CONTROL B TO SET 60 HZ C_I_KBD EQU 11001111B ;ANDED WITH SYS PIA CONTROL A TO SET INTELLIGENT ;KEYBOARD TO INTERRUPT ON A HIGH TO LOW ;TRANSITION OF CA2 C_DMA EQU 11111101B ;ANDED WITH SYS PIA CONTROL A TO SET DMA TO ;INTERRUPT ON A HIGH TO LOW TRANSITION ;OF CA1 C_RTC EQU 00000010B ;ORED WITH SYS PIA CONTROL B TO SET RTC TO ;INTERRUPT ON A LOW TO HIGH TRANSITION ;OF CB1 C_PAR EQU 00000010B ;ORED WITH PARALLEL PIA CONTROL A TO SET ;PARALLEL PORT TO INTERRUPT ON A LOW TO HIGH ;TRANSITION OF CA1 (AS PER IE.CO ROUTINE). C_ FDC EQU 00000010B ;ORED WITH PARALLEL PIA CONTROL B TO SET FDC ;TO INTERRUPT ON A LOW TO HIGH TRANSITION OF ;CB1 PAGE ; ********************************************************* ; * * ; * BOOT MESSAGES * ; * * ; ********************************************************* LD_MSG: DB ESC,VDELL ;DELETE CURRENT LINE DB 7FH, 32, 20H ;21 SPACES DB 'LOADING SYSTEM' DC '.' ;SET HI BIT ON LAST CHAR EB_MSG: DB ESC,VDELL ;DELETE CURRENT LINE DB 7FH, 21, 20H ;21 SPACES DB 'BOOT ERROR' DC '.' ;SET HI BIT ON LAST CHAR BD_MSG: DB ESC,VDELL ;DELETE CURRENT LINE DB 7FH, 10, 20H ;21 SPACES DB 'DISK IS NOT A VALID SYSTEM DISK' DC '.' ;SET HI BIT ON LAST CHAR WT_CR_MSG: DB ' PRESS RETURN TO TRY AGAIN' DC '.' PAGE ; ********************************************************* ; * * ; * LOG ON MESSAGE * ; * * ; ********************************************************* IMSG: DB ESC,'.0' ;DISABLE CURSOR DB 'Z'-40H,LF,LF DB 07FH, 21, 20H DB ESC,VSGH DB 'Q'-40H DB 07FH, 37, 'W'-40H DB 'E'-40H DB ESC,VEGH DB CRLF DB 07FH, 21, 20H DB ESC,VSGH,1, ESC,VEGH DB 07FH,14,20H DB 'EXECUTIVE' DB 07FH,14,20H DB ESC,VSGH,4, ESC,VEGH DB CRLF DB 07FH, 21, 20H DB ESC,VSGH DB 'A'-40H DB ESC,VEGH DB 7FH, 16, 20H DB ESC,VSHI DB 'V1.21' DB ESC,VEHI DB 7FH, 16, 20H DB ESC,VSGH DB 'D'-40H DB ESC,VEGH DB CRLF DB 07FH, 21, 20H DB ESC,VSGH DB 'A'-40H DB 07FH,37, 20H DB 'D'-40H DB ESC,VEGH DB CRLF DB 07FH,21,20H DB ESC,VSGH DB 'A'-40H DB ESC,VEGH DB 20H DB ESC,VSGH DB 'S'-40H DB ESC,VEGH DB ' 1984 OSBORNE COMPUTER CORPORATION ' DB ESC,VSGH DB 'D'-40H DB ESC,VEGH DB CRLF DB 07FH,21,20H DB ESC,VSGH DB 'A'-40H DB ESC,VEGH DB 7FH, 10, 20H DB '26538 DANTI COURT' DB 7FH, 10, 20H DB ESC,VSGH DB 'D'-40H DB ESC,VEGH DB CRLF DB 07FH,21,20H DB ESC,VSGH DB 'A'-40H DB ESC,VEGH DB 7FH, 10, 20H DB 'HAYWARD, CA 94545' DB 7FH, 10, 20H DB ESC,VSGH DB 'D'-40H DB ESC,VEGH DB CRLF DB 07FH, 21, 20H DB ESC,VSGH DB 'Z'-40H DB 07FH, 37, 'X'-40H DB 'C'-40H DB ESC,VEGH DB CRLF,LF,LF DB 07FH, 21, 20H DB ESC,'.2' ;ENABLE BLOCK CURSOR DB 'INSERT DISK IN DRIVE ' DB ESC,VSUL DB 'A' DB ESC,VEUL DB ' AND PRESS RETURN' DC '.' PAGE ; ********************************************************* ; * * ; * INITIALIZATION VALUES * ; * * ; ********************************************************* ; KEYBOARD TABLE COPIED INTO ROM'S RAM AT INIT TIME: R_K_IN_TB: ; ; MASKS FOR REMOVING INVALID KEYS FROM SCAN: ; (INVALID KEYS ARE SHIFT, CTRL, ALPHA LOCK AND THE DISABLED RETURN ; KEY.) ; DB 11100011B ;MASK FOR ROW 0: STRIP OFF CTRL, ALPHA AND SHIFT DB 11111111B ;FOR ROWS 1-6, STRIP OFF NOTHING DB 11111111B DB 11111111B DB 11111111B DB 11111111B DB 11111111B DB 00000000B ;FOR ROW 7, STRIP OFF ALL CHARS ; ; FOLLOWING ARE THE KEYBOARD MATRIX LOCATIONS FOR CTRL, ALPHA AND SHIFT: ; DB 000010B ;CTRL: ROW 0, COL 2 DB 111011B ;ALPHA: ROW 7, COL 3 DB 000100B ;SHIFT: ROW 0, COL 4 ; ; KEY CLICK INITIALIZATION VALUE: ; DB 0 K_TB_SZ EQU $ - R_K_IN_TB PAGE ; ********************************************************* ; * * ; * ALPHA LOCK TABLE * ; * * ; ********************************************************* AL_TB: ;ALPHA LOCK TABLE DB ESC, TAB, BAD, BAD, BAD, CR, '''', '[' DB '1', '2', '3', '4', '5', '6', '7', '8' DB 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I' DB 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K' DB 'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',' DB 8AH, 8DH, '0', ' ', '.', 'P', 'O', '9' DB 8BH, 8CH, '-', '/', ';', '\', 'L', '=' DB BAD, BAD, BAD, BAD, CR, BAD, BAD, BAD AL_T_SZ EQU $-AL_TB PAGE ; ********************************************************* ; * * ; * CHARACTER FONT VALUES * ; * * ; ********************************************************* ;CHARACTER FONT FONT_TABLE: DB 0FFH,0C3H,0C3H,0C3H,0C3H,0C3H,0C3H,0C3H,0C3H,0FFH DB 0F0H,0F0H,0F0H,0F0H,0F0H,0F0H,0F0H,0F0H,0F0H,0F0H DB 00FH,00FH,00FH,00FH,00FH,0F0H,0F0H,0F0H,0F0H,0F0H DB 00FH,00FH,00FH,00FH,00FH,0FFH,0FFH,0FFH,0FFH,0FFH DB 00FH,00FH,00FH,00FH,00FH,00FH,00FH,00FH,00FH,00FH DB 0FFH,0FFH,0FFH,0FFH,0FFH,00FH,00FH,00FH,00FH,00FH DB 000H,000H,000H,000H,000H,0F0H,0F0H,0F0H,0F0H,0F0H DB 000H,000H,000H,000H,000H,00FH,00FH,00FH,00FH,00FH DB 080H,0C0H,0E0H,0F0H,0F0H,0F8H,0F8H,0FCH,0FEH,0FFH DB 000H,000H,000H,03FH,03FH,03FH,03FH,03CH,03CH,03CH DB 001H,003H,007H,00FH,00FH,01FH,01FH,03FH,07FH,0FFH DB 03CH,03CH,03CH,03CH,03CH,03CH,03CH,03CH,03CH,03CH DB 03CH,03CH,03CH,0FFH,0FFH,0FFH,0FFH,03CH,03CH,03CH DB 000H,000H,03CH,07EH,07EH,07EH,07EH,03CH,000H,000H DB 0F0H,0F0H,0F0H,0F0H,0F0H,00FH,00FH,00FH,00FH,00FH DB 000H,000H,00 0H,0FFH,0FFH,0FFH,0FFH,03CH,03CH,03CH DB 000H,000H,000H,0FCH,0FCH,0FCH,0FCH,03CH,03CH,03CH DB 0FFH,0FFH,0FFH,0FFH,0FFH,0F0H,0F0H,0F0H,0F0H,0F0H DB 0F0H,0F0H,0F0H,0F0H,0F0H,000H,000H,000H,000H,000H DB 000H,038H,044H,09AH,0A2H,0A2H,09AH,044H,038H,000H DB 00FH,00FH,00FH,00FH,00FH,000H,000H,000H,000H,000H DB 0FFH,07FH,03FH,01FH,01FH,00FH,00FH,007H,003H,001H DB 0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH DB 0FFH,0FFH,0FFH,0FFH,0FFH,000H,000H,000H,000H,000H DB 000H,000H,000H,000H,000H,0FFH,0FFH,0FFH,0FFH,0FFH DB 0FFH,0FEH,0FCH,0F8H,0F8H,0F0H,0F0H,0E0H,0C0H,080H DB 0F0H,0F0H,0F0H,0F0H,0F0H,0FFH,0FFH,0FFH,0FFH,0FFH DB 000H,000H,000H,0FFH,0FFH,0FFH,0FFH,000H,000H,000H DB 03CH,03CH,03CH,03FH,03FH,03FH,03FH,000H,000H,000H DB 0C0H,0C6H,0CCH,0D8H,030H,06EH,0C3H,006H,018H,03FH DB 03CH,03CH,03CH,0FFH,0FFH,0FFH,0FFH,000H,000H,000H DB 03CH,03CH,03CH,0FCH,0FCH,0FCH,0FCH,000H,000H,000H DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H DB 000H,018H,03CH,03CH,018H,018H,000H,018H,000H,000H DB 000H,066H,066H,000H,000H,000H,000H,000H,000H,000H DB 000H,024H,024H,07EH,024H,07EH,024H,024H,000H,000H DB 000H,018H,03EH,058H,038H,01AH,07CH,018H,000H,000H DB 000H,026H,076H,02CH,018H,034H,06EH,064H,000H,000H DB 000H,038H,06CH,06CH,038H,06DH,066H,03FH,003H,000H DB 000H,006H,006H,00CH,000H,000H,000H,000H,000H,000H DB 000H,00CH,018H,030H,030H,030H,018H,00CH,000H,000H DB 000H,030H,018H,00CH,00CH,00CH,018H,030H,000H,000H DB 000H,010H,054H,038H,07CH,038H,054H,010H,000H,000H DB 000H,000H,000H,018H,018H,07EH,018H,018H,000H,000H DB 000H,000H,000H,000H,000H,000H,01CH,01CH,00CH,018H DB 000H,000H,000H,000H,07EH,07EH,000H,000H,000H,000H DB 000H,000H,000H,000H,000H,000H,018H,018H,000H,000H DB 000H,002H,006H,00CH,018H,030H,060H,040H,000H,000H DB 000H,03CH,066H,066H,06EH,076H,066H,03CH,000H,000H DB 000H,018H,038H,018H,018H,018H,018H,03CH,000H,000H DB 000H,03CH,066H,00CH,038H,060H,060H,07EH,000H,000H DB 000H,03CH,066H,006H,01CH,006H,066H,03CH,000H,000H DB 000H,00CH,06CH,06CH,06CH,07EH,00CH,00CH,000H,000H DB 000H,07EH,060H,060H,07CH,006H,066H,03CH,000H,000H DB 000H,03CH,066H,060H,07CH,066H,066H,03CH,000H,000H DB 000H,07EH,006H,00CH,018H,030H,030H,030H,000H,000H DB 000H,03CH,066H,066H,03CH,066H,066H,03CH,000H,000H DB 000H,03CH,066H,066H,03EH,006H,066H,03CH,000H,000H DB 000H,000H,000H,01CH,01CH,000H,01CH,01CH,000H,000H DB 000H,000H,000H,038H,038H,000H,038H,038H,018H,030H DB 000H,00CH,018H,030H,060H,030H,018H,00CH,000H,000H DB 000H,000H,000H,000H,07EH,000H,07EH,000H,000H,000H DB 000H,030H,018H,00CH,006H,00CH,018H,030H,000H,000H DB 000H,03CH,066H,006H,00CH,018H,000H,018H,000H,000H DB 000H,03CH,042H,04EH,056H,05CH,040H,03CH,000H,000H DB 000H,03CH,066H,066H,07EH,066H,066H,066H,000H,000H DB 000H,07CH,066H,066H,07CH,066H,066H,07CH,000H,000H DB 000H,03CH,066H,060H,060H,060H,066H,03CH,000H,000H DB 000H,07CH,066H,066H,066H,066H,066H,07CH,000H,000H DB 000H,07EH,060H,060H,078H,060H,060H,07EH,000H,000H DB 000H,07EH,060H,060H,078H,060H,060H,060H,000H,000H DB 000H,03CH,066H,060H,06EH,066H,066H,03CH,000H,000H DB 000H,066H,066H,066H,07EH,066H,066H,066H,000H,000H DB 000H,03CH,018H,018H,018H,018H,018H,03CH,000H,000H DB 000H,006H,006H,006H,006H,006H,066H,03CH,000H,000H DB 000H,066H,06CH,078H,070H,078H,06CH,066H,000H,000H DB 000H,060H,060H,060H,060H,060H,060H,07EH,000H,000H DB 000H,063H,077H,07FH,06BH,06BH,063H,063H,000H,000H DB 000H,066H,066H,076H,07EH,06EH,066H,066H,000H,000H DB 000H,03CH,066H,066H,066H,066H,066H,03CH,000H,000H DB 000H,07CH,066H,066H,07CH,060H,060H,060H,000H,000H DB 000H,03CH,066H,066H,066H,066H,076H,03CH,00CH,006H DB 000H,07CH,066H,066H,07CH,066H,066H,066H,000H,000H DB 000H,03CH,066H,060H,03CH,006H,066H,03CH,000H,000H DB 000H,07EH,018H,018H,018H,018H,018H,018H,000H,000H DB 000H,066H,066H,066H,066H,066H,066H,03CH,000H,000H DB 000H,066H,066H,066H,066H,03CH,03CH,018H,000H,000H DB 000H,063H,063H,06BH,06BH,07FH,07FH,036H,000H,000H DB 000H,066H,066H,03CH,018H,03CH,066H,066H,000H,000H DB 000H,066H,066H,066H,03CH,018H,018H,018H,000H,000H DB 000H,07EH,046H,00CH,018H,030H,062H,07EH,000H,000H FONTLEN EQU $-FONT_TABLE ROW_LEN EQU 10 FONT_ROWS EQU FONTLEN / ROW_LEN 3CH,000H,000H DB 000H,066H,06CH,078H,070H,078H,06CH,066H,000H,000H DB 000H,060H,060H,060H,060H,060H,060H,07EH,000H,000H DB 000H,063H,077H,07FH,06BH,06BH,063H,063H,000H,000H DB 000H,066H,066H,076H,07EH,06EH,066H,066H,000H,000H DB 000H,03CH,066H,066H,066H,066H,066H,03CH,000H,000H DB 000H,07CH,066H,066H,07CH,060H,060H,060H,000H,000H DB 000H,03CH,066H,066H,066H,066H,076H,03CH,00CH,006H DB 000H,07CH,066H,066H,07CH,066H,066H,066H,000H,000H DB 000H,03CH,066H,060H,03CH,006H,066H,03CH,000H,000H DB 000H,07EH,018H,018H,018H,018H,018H,018H,000H,000H DB 000H,066H,066H,066H,066H,066H,066H,03CH,000H,000H DB 000H,066H,066H,066H,066H,03CH,03CH,018H,000H,000H DB 000H,063H,063H,06BH,06BH,07FH,07FH,036H,000H,000H DB 000H,066H,066H,03CH, ; ********************************************************* ; * * ; * RAMS10.MAC -- STORAGE DECLARATIONS * ; * * ; ********************************************************* ; RAMS10.MAC ; Used to assemble ROM resident and CBIOS SUBTTL 'COMMON RAM STORAGE DECLARATIONS' ; Disk operation temps and control DMABANK EQU MRAM ;Bank for read/write disk DMADR EQU DMABANK+1 ;Address for read/write disk ; Note order of xxxSEC,xxxTRK,xxxDSK must be maintained ; along with length (1,2,1). SAVSEC EQU DMADR+2 ;last sector requested SAVTRK EQU SAVSEC+1 ;last track requested SDISK EQU SAVTRK+2 ;selected disk drive (0,1) SAVTYP EQU SDISK+1 ;SELECTED TYPE (sector size) IE_ADR EQU SAVTYP+1 CURPOS EQU IE_ADR+1 ;Current cursor position ; VARIABLES FOR HIGH RAM ROUTINES TEMSAV EQU CURPOS+2 ;Used by jump bank routine SRCBANK EQU TEMSAV+1 ;Source bank for block move DESTBANK EQU SRCBANK+1 ;Destination bank for block move ;JMPSPOT and JMPADDR must stay next to each other JMPSPOT EQU DESTBANK+1 ;To be filled in with a JMP instruction by the ROM JMPADDR EQU JMPSPOT+1 ;Address to jump to for BANKJMP and BANKCALL JMPBANK EQU JMPADDR+2 ;Bank to jump to for BANKJMP and BANKCALL EMRAM EQU JMPBANK+1 ; INTERRUPT VARIABLES USR_BNK EQU JMPBANK+1 ;User's bank on interrupt bank switch I_POL_BANK EQU USR_BNK+3 I_POL_ADR EQU I_POL_BANK+1 USR_STK EQU I_POL_ADR+2 ;save current stk ptr ; Interrupt stack ISTK EQU USR_STK+30*2+2 ; ROM and BIOS stack ROMSTK EQU ISTK+30*2 BIOSTK EQU ROMSTK HIBUFF EQU ROMSTK  ;selected disk drive (0,1) SAVTYP EQU SDISK+1 ;SELECTED TYPE (sector size) IE_ADR EQU SAVTYP+1 CURPOS EQU IE_ADR+1 ;Current cursor position ; VARIABLES FOR HIGH RAM ROUTINES TEMSAV EQU CURPOS+2 ;Used by jump bank routine SRCBANK EQU TEMSAV+1 ;Source bank for block move DESTBANK EQU SRCBANK+1 ;Destination bank for block move ;JMPSPOT and JMPADDR mu; ********************************************************* ; * * ; * MONITOR'S RAM STORAGE DEFINITION * ; * * ; ********************************************************* ;RAMSMON.ASM SUBTTL 'MONITOR RAM STORAGE.' ; BIOS POINTERS ;RTC POINTER CLK_PTR EQU MONRAM ;POINTER TO CURRENT TIME ;DISK CHANGE FLAG POINTER MEDIA EQU CLK_PTR + 2 ;ADDR FOR DISK CHANGE FLAG A_DRIVE EQU MEDIA + 2 ;ADDR FOR DRIVE A DISK CHANGE FLAG B_DRIVE EQU A_DRIVE + 2 ;ADDR FOR DRIVE B DISK CHANGE FLAG ;PROTOCOL HANDLING VARIABLES: ;PROTOCOL MODE FOR SIO CHANNEL A. ;0 = NO PROTOCOL, ;1 = XON/XOFF PROTOCOL AND ;2 = ETX/ACK PROTOCOL. A_PROTCL EQU B_DRIVE + 2 ;PROTOCOL MODE FOR SIO CHANNEL B. ;0 = NO PROTOCOL, ;1 = XON/XOFF PROTOCOL AND ;2 = ETX/ACK PROTOCOL. B_PROTCL EQU A_PROTCL + 1 ; KEYBOARD MASKS: K_MSK_TBL EQU B_PROTCL + 1 ; INITIAL VALUES -- ; 11100011B ;ROW 0 -- STRIP CTRL/ALPHA/SHIFT ; 11111111B ;ROWS 1-6 -- STRIP NOTHING ; 11111111B ; 11111111B ; 11111111B ; 11111111B ; 11111111B ; 11010111B ;ROW 7 -- STRIP ALPHA/INVALID RET ; ; SPECIAL KEY LOCATIONS: ; CT_KEY EQU K_MSK_TBL + 8 ;000_101B ;CTRL: ROW 0, COL 2 AL_KEY EQU CT_KEY + 1 ;111_011B ;ALPHA: ROW 7, COL 3 SH_KEY EQU AL_KEY + 1 ;000_100B ;SHIFT: ROW 0, COL 4 KEYS EQU SH_KEY + 1 ;1ST 64BYTE-NORMAL, 2ND 64-SHIFT ;3RD 64-CONTROL, 4TH 64-ALPA ;5TH 64-CONTROL SHIFT TABLE ; FUNCTION KEY TABLES FKEY_ADR EQU KEYS + 320 ;SPACE RESVERED FOR FUNCTION KEYS ;CONSOLE POINTERS HERTZ EQU FKEY_ADR + 200H ;HERTZ RATE (50 OR 60) CURTYPE EQU HERTZ + 1 ;CURSOR TYPE (3 MSB'S) -- ; (BLOCK, UNDERLINE, BLINK) BACKGND EQU CURTYPE + 1 ;BACKGROUND ATTRIBUTE FLAG KCLICK EQU BACKGND + 1 ;KEY CLICK FLAG ROMCON EQU KCLICK + 1 ;POINTER TO ROM CONSOLE STRUCTURE PAGE ;NON-CONFIGURABLE PORTION ;CONSOLE ;ROM'S CONSOLE TABLE STRUCTURE CONTBLS EQU ROMCON + 2 ;CURRENT TABLE ADDRESS CTBLADDR EQU ROMCON + 2 ;CURRENT TABLE TO BE SEARCHED ;POINTERS TO TABLES ; CTBLADDR + 2 ; BASE TABLE POINTER ; CTBLADDR + 4 ; ESCAPE TABLE POINTER ; CTBLADDR + 6 ; CONTROL TABLE POINTER ; CTBLADDR + 8 ; Y COORDINATE TABLE POINTER ; CTBLADDR + 10 ; X COORDINATE TABLE POINTER ; CTBLADDR + 12 ; WINDOW DEFINE TABLE POINTER ; CTBLADDR + 14 ; FIRST ROW OF WINDOW TABLE POINTER ; CTBLADDR + 16 ; FIRST COLUMN OF WINDOW TABLE POINTER ; CTBLADDR + 18 ; LAST ROW OF WINDOW TABLE POINTER ; CTBLADDR + 20 ; LAST COLUMN OF WINDOW TABLE POINTER ; CTBLADDR + 22 ; WINDOW SET TABLE POINTER ; CTBLADDR + 24 ; CURSOR TYPE TABLE POINTER ; CTBLADDR + 26 ; X-Y OFFSET TABLE POINTER ; CTBLADDR + 28 ; BACKGROUND ATTRIBUTE POINTER ; ;CONSOLE VARIABLES OFFSET EQU CTBLADDR + 30 ;OFFSET FOR X-Y COORDINATES CFLAG EQU OFFSET + 1 ;CONSOLE FLAG CURWIND EQU CFLAG + 1  ;CURRENT WINDOW DEFINITION ;(THESE BYTES MUST STAY TOGETHER) FWAWIND EQU CFLAG + 1 ;FIRST WORD ADDRESS OF WINDOW WINDROWS EQU FWAWIND + 2 ;NUMBER OF ROWS IN WINDOW WINDCOLS EQU WINDROWS + 1 ;NUMBER OF COLUMNS IN WINDOW TEMP EQU WINDCOLS + 1 ;TEMPORARY USED BY SCROLL ROUTINE ;WHILE WINDOW IS BEING DEFINED -- WINDNUM EQU TEMP + 1 ; NUMBER OF WINDOW TEMPFWA EQU WINDNUM + 1 ; NEW FWA TEMPROWS EQU TEMPFWA + 2 ; NEW NUMBER OF ROWS FSTROW EQU TEMPROWS + 1 ; FIRST ROW NUMBER FSTCOL EQU FSTROW + 1 ; FIRST COLUMN NUMBER SCRL_UPF EQU FSTCOL + 1 ;0= SCROL_DOWN, 0FFH= SCROL_UP WINDDEFS EQU SCRL_UPF + 1 ;ALL 16 WINDOW DEFINITIONS PAGE ;MONITOR VARIABLES ;SINCE CP/M CANNOT BOOT OFF B:, THIS CELL IS USED ;TO INVERT THE NAMES OF THE 2 DRIVES: ; =0, ALL NORMAL, A=A:, B=B: ; =1, ALL INVERTED, A=B:, B=A: DSKSWP EQU WINDDEFS + 64 ;DISK VARIABLES RTRY EQU DSKSWP + 1 ;RETRY COUNTER DSTSB EQU RTRY + 1  ;DISK STATUS BYTES NUMSEC EQU DSTSB + 6 ;(1) # OF SECTORS TO R/W R_WCOM EQU NUMSEC + 1 ;(1) # OF SECTORS TO R/W NRETRY EQU R_WCOM + 1 ;INITIAL RETRY COUNTER WP_STS EQU NRETRY + 1 ;WRITE PROTECT STATUS DRV_MSK EQU WP_STS + 1 ;INTERRUPT VARIABLES CUR_I_ST EQU DRV_MSK + 1 ;CELL TO SAVE CURRENT INTERRUPT ;STATE I_POL_BNK EQU CUR_I_ST + 2 ;CELL TO SAVE INTERRUPT POLLING ;ROUTINE'S BANK MASK S_A_FLG EQU I_POL_BNK + 1 ;FLAG SET IF -- ; CH. A TX BUFF EMPTY INT OCCURS ;AND NO CHARS READY S_B_FLG EQU S_A_FLG + 1 ;FLAG SET IF -- ; CH. B TX BUFF EMPTY INT OCCURS ;FUNCTION KEY TABLE POINTERS FKEYFLAG EQU S_B_FLG + 1 ;FLAG TO INDICATE -- ; WHICH TRANSLATION TABLE TO USE ;AND NO CHARS READY ;PARALLEL PORT VARIABLES PIACTL EQU FKEYFLAG + 1 PP.MODE EQU PIACTL + 1 ;IEEE 488 VARIABLES: IE_CHAR EQU PP.MODE + 1 ;KEYBOARD SCAN VARIABLES KEYLCK EQU IE_CHAR + 1 ;ZERO IF LOCKED KEYBOARD  KEYLST EQU KEYLCK + 1 FIRSTKEY EQU KEYLST SECONDKEY EQU FIRSTKEY + 2 LASTKEY EQU KEYLST + 4 ;FUNCTION KEY TRANSLATION VARIABLES COUNT EQU KEYLST + 6 ;NUMBER OF KEYS LEFT TO TRANSLATE FPNTR EQU COUNT + 1 ;PNTR TO CURRENT POS IN TRANX TABLE ;RTC VARIABLES LAST_TCK EQU FPNTR + 2 ;LAST VALUE READ FROM -- ; TICK OVERFLOW COUNTER DCHK_FLG EQU LAST_TCK + 1 ;# OF TICKS LEFT BEFORE -- ; DISK CHANGE IS SERVICED SYS_TICKS EQU DCHK_FLG + 1 ;SYSTEM TICK COUNT ;DIAGNOSTICS VARIABLES ERRFLG EQU SYS_TICKS + 1 ;ERROR FLAG PAGE ;REAL TIME CLOCK VARIABLES ;4 BYTES FOR -- ;DAYS (# OF DAYS SINCE JAN 1, 1979) ;HOURS ;MINUTES ROMCLK EQU ERRFLG + 5 ;SECONDS SEKDEL EQU ROMCLK + 1 ;SET FOR SEEK-RESTORE COMMAND IN ROM ;LOWEST 2 BITS ARE SPEED. SIEMENS = 3H, MPI = 0H RDFLAG EQU SEKDEL + 1 ;READ FLAG ; USED TO DESELECT DRIVE WHEN THERE IS NO ACTIVITY ; ON DRIVE FOR N SECONDS. SEE FDSK ROUTINE DACTVE EQU RDFLAG + 1 ;=0 BY FDSK, USED BY UPTIM ;INTERRUPT TABLE INT_TBL EQU DACTVE + 1 ;INTERRUPT HANDLER TABLE ;DMA ;PARALLEL ;SIO TX CHANNEL B ;SIO EXTERNAL/STATUS CHANNEL B ;SIO RX CHANNEL B ;SIO RX CHANNEL B SPECIAL CONDITION ;SIO TX CHANNEL A ;SIO EXTERNAL/STATUS CHANNEL A ;SIO RX CHANNEL A ;SIO RX CHANNEL A SPECIAL CONDITION ;INTELLIGENT KEYBOARD ;REAL TIME CLOCK (TICK) INTERRUPT ;FLOPPY DISK CONTROLLER ;SYSTEM RESET ;------------------------------------------------------------------------------ ; DATA AREAS ;------------------------------------------------------------------------------ ;RESERVE STORAGE FOR DEVICE BUFFER LIST ROOTS ; ** REPT D_RT_LEN*NO_DEVS ;INITIALIZE ALL POINTERS TO 0 D_RT_TBL EQU INT_TBL + 42 ; ** ENDM ; ; FRE_ADDR EQU D_RT_TBL + (D_RT_LEN*NO_DEVS) ;(2 BYTES) FREE LIST ROOT. ; POINTER TO FIRST FREE BUFFER ; IS INITIALIZED TO POINT TO FIRST BUFFER ;(1 BYTE) FREE BUFFER COUNT.  ; IS INITIALIZED TO NUMBER OF BUFFERS. ;------------------------------------------------------------------------------ ; BUFFERS FOLLOW. THE FIRST ENTRY IN EACH IS INITIALIZED TO POINT TO ; THE NEXT SO THAT ALL ARE IN THE FREE LIST. ;------------------------------------------------------------------------------ BUFF_ST EQU FRE_ADDR + 3 ;PROTOCOL HANDLING VARIABLES: ;TRANSMIT DISABLE FLAG FOR CHANNEL A. ;000H = TRANSMIT ENABLED AND ;0FFH = TRANSMIT DISABLED BECAUSE OF PROTOCOL A_XMT_OFF EQU BUFF_ST + ((MX_CH_BF + BF_OV_HD) * NO_BUFS) ;TRANSMIT DISABLE FLAG FOR CHANNEL B. ;000H = TRANSMIT ENABLED AND ;0FFH = TRANSMIT DISABLED BECAUSE OF PROTOCOL B_XMT_OFF EQU A_XMT_OFF + 1 ;RESET VARIABLES RSTHLD EQU B_XMT_OFF + 1 ;SET BY INTERRUPT ROUTINE IF -- ; RESET BUTTON IS HELD DOWN. RSTMODE EQU RSTHLD + 1 ;RESET MODE -- ; 0 = BOOT AFTER RESET ; NOT 0 = SYSTEM AFTER RESET  .Z80 TITLE 'EXECUTIVE ROM MONITOR' ; .XLIST INCLUDE SYSS1.MAC ;SYSTEST FILE PAGE INCLUDE RAMS10.MAC ;RAM MEMORY LOCATIONS AND CONSTANTS PAGE INCLUDE RAMSMON.MAC ;MONITOR RAM MEMORY LOCATIONS ; .LIST PAGE INCLUDE ROM0 ;BOOT AND INITIALIZATION ROUTINES PAGE INCLUDE ROM1 ;POWER ON DIAGNOSTICS PAGE INCLUDE ROM2 ;CONSOLE ROUTINES PAGE INCLUDE ROM3 ;KEYBOARD ROUTINES PAGE INCLUDE ROM4 ;I/O ROUTINES PAGE INCLUDE ROM5 ;DISK ROUTINES PAGE INCLUDE ROM6 ;INTERUPT HANDLING ROUTINES PAGE INCLUDE ROM7 ;BUFFERING ROUTINES PAGE INCLUDE ROM8 ;HIGH RAM ROUTINES (BANK SWITCHING) END ممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممممم ممممم!ممممم"ممممم#ممممم$ممممم%ممممم&ممممم'ممممم