; XEROX REQUIRES 4MHZ ZPU OPERATION EXTRN BINH2 XEROX: ld hl,(6) ld sp,hl LD A,(5CH); CDOS FCB-1 LD (TO),A LD A,(6CH); CDOS FCB-2 LD (FROM),A LD A,(TO) OR A JR NZ,NXT LD C,C.DISK CALL CDOS INC A LD (TO),A NXT: LD A,(FROM) OR A JR NZ,NXT2 LD C,C.DISK CALL CDOS INC A LD (FROM),A NXT2: LD HL,TO CP (HL) JR NZ,NXT2A LD DE,NOTSAME LD C,W.LINE CALL CDOS JP 0 NOTSAME:DB LF,CR,BEL,BEL,BEL,'CANNOT COPY TO SAME FLOPPY',LF,CR,'$' NXT2A: LD A,(TO) ADD 40H LD (DR),A LD DE,QUEST LD C,W.LINE CALL CDOS LD C,R.CHAR CALL CDOS CP 'Y' JR Z,OK CP 'y' JR Z,OK JP 0 QUEST: DB LF,CR,BEL,BEL,BEL,'OK TO DESTROY CURRENT CONTENTS OF FLOPPY ON DRIVE ' DR: DB ' ? $' CRLF: DB LF,CR,'$' FROM: DB 0 TO: DB 0 CURR: DB 0 SAMEDR: DB 0 DENSITY: DB 0 RETRY: DB 0 HLSAVE: DW 0 TRKSINMEM: DB 0 TRKIN: DB 0 TRKOUT: DB 0 TRKCNT: DB 0 ENTRY $MEMRY $MEMRY: DW 0 OK: LD DE,CRLF LD C,W.LINE CALL CDOS LD A,0; TEST IF FLOPPIES ON SAME DUAL DRIVE LD (SAMEDR),A LD A,(FROM) LD B,A LD A,(TO) SUB B JP P,POSA NEG POSA: CP 1 JR NZ,NOTONE; NO LD A,(TO); IF DIFFERENCE IS ONE IT MUST BE A 1,2 OR 3,4 CP B; COMBINATION JP P,AGR LD A,B AGR: RRA; I.E. THE LARGEST MUST BE EVEN JR C,NOTONE; NOT ON SAME DUAL DRIVE LD (SAMEDR),A NOTONE: LD A,(FROM) LD B,A XOR A SCF NXT3: RLA DJNZ NXT3 OR MOTORON+MAXI+DBLDEN LD (FROM),A LD A,(TO) LD B,A XOR A SCF NXT4: RLA DJNZ NXT4 OR MOTORON+MAXI+DBLDEN LD (TO),A MSKINTRP: EQU 03H AUXDSK: EQU 04H; INPUT/OUTPUT PORT FOR FAST SEEK FASTSEEK: EQU 0EFH SEEKCOMP: EQU 40H RESETFST: EQU 0FFH ; DSKSTAT:EQU 30H; INPUT PORT FOR DISK STATUS NOTREADY: EQU 80H PROTECT:EQU 40H HEADDOWN: EQU 20H WRFAULT:EQU 20H NOTFND: EQU 10H CRCERR: EQU 08H LOSTDATA: EQU 04H DRQ: EQU 02H BUSY: EQU 01H ; DSKCMD: EQU 30H; OUTPUT PORT FOR DISK COMMANDS RESTORE:EQU 0CH SEEK: EQU 18H READ: EQU 88H ENBLHOLD: EQU 04H WRITE: EQU 0A8H RESET: EQU 0D0H ; TRKREG: EQU 31H; I/O PORT FOR TRACK REGISTER ; SECREG: EQU 32H; I/O PORT FOR SECTOR REGISTER ; DATAREG:EQU 33H; I/O PORT FOR DATA ; DSKCNTRL:EQU 34H; OUTPUT PORT FOR DISK CONTROL MOTORON:EQU 20H MAXI: EQU 10H DBLDEN: EQU 40H AUTOWAIT: EQU 80H ; DSKFLGS:EQU 34H; INPUT PORT FOR DISK FLAGS HEADLOAD: EQU 20H EOJ: EQU 01H ; CDOS: EQU 5; CDOS CALL ADDRESS ; CDOS CALL CODES C.DISK: EQU 25 R.CHAR: EQU 1 W.LINE: EQU 9 DIVIDE: EQU 138 RES.CDOS: EQU 13 SEL.DISK: EQU 14 ; TTY CONTROL CODES CR: EQU 0DH LF: EQU 0AH BEL: EQU 07H ; DISK CONSTANTS MAXRETRY: EQU 10 ; NUMBER OF RETRIES IF R/W ERROR NRTRKS: EQU 77 NRSECS: EQU 26 ; SINGLE DEN NRSECS2: EQU 16 ; DOUBLE DEN TRKSIZE:EQU NRSECS2*512; SIZE OF A TRACK TRKSIZ1:EQU NRSECS*128 XOR A LD (TRKIN),A LD (TRKOUT),A LD HL,($MEMRY); GET START OF BUFFER EX DE,HL; SAVE IN DE LD HL,(6); GET HIGHEST MEMORY ADDRESS SCF SBC HL,DE; CALCULATE AVAILABLE MEMORY LD DE,TRKSIZE; SIZE OF A TRACK LD C,DIVIDE CALL CDOS LD A,L LD (TRKSINMEM),A; SET MAX. NR OF TRACKS READABLE LD A,(FROM) AND NOT DBLDEN ; DISABLE DOUBLE DENSITY FOR HOME LD (CURR),A OUT DSKCNTRL,A; SELECT INPUT DISK LD D,NOTREADY+NOTFND+CRCERR+BUSY LD A,RESTORE; RESTORE DISK TO TRACK ZERO CALL EXECUTE LD A,(TO) AND NOT DBLDEN LD (CURR),A OUT DSKCNTRL,A LD D,NOTREADY+PROTECT+NOTFND+CRCERR+BUSY LD A,RESTORE CALL EXECUTE ; READ IN FIRST SECTOR TO SEE IF DOUBLE OR SINGLE DENSITY LD HL,($MEMRY) LD A,(FROM) AND NOT DBLDEN LD (CURR),A CALL SETUP ADD READ LD D,NOTREADY+NOTFND+CRCERR+LOSTDATA LD C,SECREG LD E,1 OUT (C),E LD C,DATAREG OUT DSKCMD,A; START READING LOOP2: IN A,DSKFLGS; WAIT FOR DRQ OR EOJ RRA JR C,DENSREADY; EOJ FOUND? INI; PLACE NEXT BYTE AT (HL) AND UPDATE JR LOOP2; GET NEXT BYTE FROM SECTOR DENSREADY: IN A,DSKSTAT; GET STATUS AFTER SECTOR LD B,A AND D JP NZ,ERROR LD IX,($MEMRY) LD A,'L' CP (IX+78H) JR NZ,SINGLE LD A,'G' CP (IX+79H) JR NZ,SINGLE LD A,'S' CP (IX+7AH) JR NZ,SINGLE CP (IX+7BH) JR NZ,SINGLE LD A,'D' CP (IX+7CH) JR NZ,SINGLE CP (IX+7DH) JR NZ,SINGLE LD A,0FFH LD (DENSITY),A LD DE,DOUBLEDEN JR DENMESS SINGLE: XOR A LD (DENSITY),A LD DE,SINGLEDEN DENMESS: LD C,W.LINE CALL CDOS JR RESTART DOUBLEDEN: DB 'Double density transfer.',CR,LF,'$' SINGLEDEN: DB 'Single density transfer.',CR,LF,'$' RESTART: LD HL,($MEMRY) LD A,0 LD (TRKCNT),A LD A,(DENSITY) OR A JR Z,SNGSKP1 IN A,TRKREG OR A ; CHECK FOR TRACK 2 OR GREATER SNGSKP1: LD A,(FROM) JR NZ,DBLSKP1 AND NOT DBLDEN DBLSKP1: LD (CURR),A CALL SETUP; PREPARE DISK FOR COMING OPERATION ADD READ; CONSTRUCT READ COMMAND RDTRACK: LD E,1; SECTOR COUNTER LD D,NOTREADY+NOTFND+CRCERR+LOSTDATA PUSH HL LD HL,RETRY LD (HL),0 POP HL AGAIN: LD (HLSAVE),HL ;SAVE FOR RETRIES LD C,SECREG OUT (C),E LD C,DATAREG OUT DSKCMD,A; START READING AGAIN2: IN A,DSKFLGS; WAIT FOR DRQ OR EOJ RRA JR C,READREADY; EOJ FOUND? INI; PLACE NEXT BYTE AT (HL) AND UPDATE JR AGAIN2; GET NEXT BYTE FROM SECTOR READREADY: IN A,DSKSTAT; GET STATUS AFTER SECTOR LD B,A AND D JP NZ,RERROR LD A,E CP NRSECS JP Z,LSTSEC; LAST SECTOR OF TRACK INPUT LD A,(DENSITY) OR A JR Z,DBLSKP4 IN A,TRKREG ; CHECK FOR DBLDEN OR A JR Z,DBLSKP4 LD A,E CP NRSECS2 JP Z,LSTSEC DBLSKP4: INC E RRETRY: LD A,(DENSITY) OR A JR Z,SNGSKP8 IN A,TRKREG OR A ; CHECK FOR TRACK 2 OR GREATER SNGSKP8: LD A,(FROM) JR NZ,DBLSKP8 AND NOT DBLDEN DBLSKP8: OR AUTOWAIT OUT DSKCNTRL,A LD A,READ JR AGAIN RERROR: LD A,(RETRY) CP MAXRETRY JP Z,ERROR INC A LD (RETRY),A PUSH DE PUSH BC LD A,B LD HL,RSTAT; SET ERROR OR STATUS BITS CALL BINH2 IN A,TRKREG; GET TRACK-NUMBER LD HL,RTRK CALL BINH2 IN A,SECREG; GET SECTOR-NUMBER LD HL,RSEC CALL BINH2 LD DE,MESRETRY LD C,W.LINE CALL CDOS POP BC POP DE LD HL,(HLSAVE) JR RRETRY MESRETRY: DB 'Retry, Status = ' RSTAT: DB ' , Track = ' RTRK: DB ' , Sector = ' RSEC: DB ' .',CR,LF,'$' LSTSEC: LD A,(TRKIN); DO IT FOR 77 TRACKS CP NRTRKS-1 JP Z,WRTHEM INC A LD (TRKIN),A LD B,A DEC A CALL SEEKTRK; GO TO NEXT TRACK LD A,(TRKSINMEM) LD B,A LD A,(TRKCNT) INC A CP B JP Z,WRTHEM LD (TRKCNT),A LD A,(DENSITY) OR A JR Z,SNGSKPA IN A,TRKREG OR A ; CHECK FOR TRACK 2 OR GREATER SNGSKPA: LD A,(FROM) JR NZ,DBLSKPA AND NOT DBLDEN DBLSKPA: OR AUTOWAIT OUT DSKCNTRL,A LD A,READ JP RDTRACK WRTHEM: LD HL,($MEMRY) LD A,0 LD (TRKCNT),A LD A,(SAMEDR); TEST IF ON SAME DUAL DRIVE IS INPUT OR A JR Z,DIFDR; NO LD A,(TRKOUT) LD B,A LD A,(TRKIN) CALL SEEKTRK; SEEK BACK TO WRITING POSITION DIFDR: LD A,(TRKOUT) OUT TRKREG,A LD A,(DENSITY) OR A JR Z,SNGSKP2 IN A,TRKREG OR A ; CHECK FOR TRACK 2 OR GREATER SNGSKP2: LD A,(TO) JR NZ,DBLSKP2 AND NOT DBLDEN DBLSKP2: LD (CURR),A CALL SETUP; PREPARE DISK FOR COMING OPERATION ADD WRITE; CONTRUCT WRITE COMMAND WRTRACK: LD E,1; SECTOR COUNTER LD D,NOTREADY+PROTECT+WRFAULT+NOTFND+CRCERR+LOSTDATA BACK: LD C,SECREG OUT (C),E LD C,DATAREG OUT DSKCMD,A; START WRITING BACK2: IN A,DSKFLGS; WAIT FOR DRQ OR EOJ RRA JR C,WRREADY; EOJ FOUND? OUTI; GET NEXT BYTE FROM (HL) AND UPDATE JR BACK2; WRITE NEXT BYTE TO SECTOR WRREADY: IN A,DSKSTAT; GET STATUS AFTER SECTOR LD B,A AND D JP NZ,ERROR LD A,E; CP NRSECS JR Z,VERIFY; LAST SECTOR OF TRACK WRITTEN LD A,(DENSITY) OR A JR Z,DBLSKP5 IN A,TRKREG ; CHECK FOR DBLDEN OR A JR Z,DBLSKP5 LD A,E CP NRSECS2 JR Z,VERIFY DBLSKP5: INC E LD A,(DENSITY) OR A JR Z,SNGSKP9 IN A,TRKREG OR A ; CHECK FOR TRACK 2 OR GREATER SNGSKP9: LD A,(TO) JR NZ,DBLSKP9 AND NOT DBLDEN DBLSKP9: OR AUTOWAIT OUT DSKCNTRL,A LD A,WRITE JR BACK VERIFY: LD E,1; RESTART AT FIRST SECTOR LD D,NOTREADY+NOTFND+CRCERR+LOSTDATA BACK3: LD A,(DENSITY) OR A JR Z,SNGSKP3 LD A,(TRKOUT) OR A ; CHECK FOR TRACK 2 OR GREATER SNGSKP3: LD A,(TO) JR NZ,DBLSKP3 AND NOT DBLDEN DBLSKP3: OR AUTOWAIT OUT DSKCNTRL,A LD B,0FFH; SET ERROR CODE TO "VERIFY ERROR" LD C,SECREG OUT (C),E LD A,READ OUT DSKCMD,A; START READING BACK4: IN A,DSKFLGS; WAIT FOR DRQ OR EOJ RRA JR C,SECREAD; IF EOJ, SECTOR IS READ IN A,DATAREG; GET BYTE JR BACK4 SECREAD: IN A,DSKSTAT; STATUS AFTER SECTOR READ LD B,A AND D JP NZ,ERROR LD A,E; LAST SECTOR OF TRACK? CP NRSECS JR Z,ENDVERIFY LD A,(DENSITY) OR A JR Z,DBLSKP6 IN A,TRKREG ; CHECK FOR DBLDEN OR A JR Z,DBLSKP6 LD A,E CP NRSECS2 JR Z,ENDVERIFY DBLSKP6: INC E JR BACK3 ENDVERIFY: LD A,(TRKOUT); DO IT FOR 77 TRACKS CP NRTRKS-1 JP Z,TERM INC A LD (TRKOUT),A LD B,A DEC A CALL SEEKTRK; GO TO NEXT TRACK LD A,(TRKSINMEM); CHECK IF END OF MEMORY LD B,A LD A,(TRKCNT) INC A CP B JP Z,RESTART LD (TRKCNT),A LD A,(DENSITY) OR A JR Z,SNGSKPB IN A,TRKREG OR A SNGSKPB: LD A,(TO) JR NZ,DBLSKPB AND NOT DBLDEN DBLSKPB: OR AUTOWAIT OUT DSKCNTRL,A LD A,WRITE JP WRTRACK ; ;THIS SUBROUTINE IS USED AFTER SWITCH TO NEW DRIVE TO PREPARE IT ;FOR A NEW SEQUENCE OF READS OR WRITES ; SETUP: OUT DSKCNTRL,A LD B,A; READ/WRITE FROM FIRST SECTOR ONWARDS LD A,1; OUT SECREG,A IN A,DSKFLGS AND HEADLOAD; HEAD LOADED? LD C,A LD A,B OR A,AUTOWAIT; FOR NEXT COMMANDS USE AUTO WAIT MODE OUT DSKCNTRL,A LD A,C OR A; WAS HEAD LOADED? LD A,4 RET Z; NO XOR A RET ; ;THIS SUBROUTINE EXECUTES "RESTORES" AND "SEEKS" (ERROR MASK IN REG.D) ; EXECUTE: OUT DSKCMD,A WAIT: IN A,DSKFLGS; CHECK IF READY RRA JR NC,WAIT IN A,DSKSTAT LD B,A AND D; COMPARE TO ERROR MASK JR NZ,ERROR RET ; ;THIS ROUTINE EXECUTES A FAST SEEK FROM (A) TO (B) ; SEEKTRK: OUT TRKREG,A; SET TO CURRENT TRACK LD A,B; GET REQUIRED TRACK-NR OUT DATAREG,A; GIVE DESIRED TRACK TO 4FDC LD A,FASTSEEK; SET TO FAST SEEK OUT AUXDSK,A LD A,SEEK; LD D,NOTREADY CALL EXECUTE REDO2: IN A,AUXDSK; SEEK COMPLETED? AND SEEKCOMP JR NZ,REDO2 LD A,RESETFST; RESET FAST SEEK MODE OUT AUXDSK,A RET ; ;THIS HANDLES ANY ERROR AND TERMINATES THE PROGRAM WITH AN APPROPRIATE ;ERROR MESSAGE ; ERROR: PUSH BC; SAVE ERROR STATUS LD A,B LD HL,ERSTAT; SET ERROR OR STATUS BITS CALL BINH2 IN A,TRKREG; GET TRACK-NUMBER LD HL,TRK CALL BINH2 IN A,SECREG; GET SECTOR-NUMBER LD HL,SEC CALL BINH2 LD A,RESET; RESET ANY CURRENT COMMAND OUT DSKCMD,A LD A,(CURR) AND 0FH LD B,1 RRA: RRA ; FIND OUT DEVICE NAME JR C,DEVFND INC B JR RRA DEVFND: LD A,B ADD 40H LD (DEV),A LD DE,ERMSG LD C,W.LINE CALL CDOS POP BC; RESTORE ERROR FLAG LD A,B LD DE,VERFERR CP 0FFH JR Z,ERTERM; ERROR FOUND IN VERIFICATION LD DE,IOERR AND NOTFND+CRCERR JR NZ,ERTERM; REAL READ OR WRITE ERROR LD A,B LD DE,READYERR AND NOTREADY JR NZ,ERTERM; DRIVE IS NOT READY LD A,B LD DE,PROTERR AND PROTECT JR NZ,ERTERM; FLOPPY IS WRITE PROTECTED LD A,B LD DE,WRERR AND WRFAULT JR NZ,ERTERM; I/O ERROR ON WRITING LD DE,UNKNERR; STRANGE ERROR ERTERM: LD C,W.LINE; PREPARE FOR WRITE MESSAGE CALL CDOS LD DE,ERMSG2 CALL CDOS JP TERM2 VERFERR:DB '(DATA READ BACK UNEQUAL TO DATA WRITTEN)$' IOERR: DB '(DATA ERROR WHEN READING OR WRITING)$' READYERR: DB '(DRIVE NOT READY: MAKE READY AND RETRY)$' PROTERR:DB '(FLOPPY IS WRITE PROTECTED)$' WRERR: DB '(DATA ERROR WHEN WRITING: RE-INITIALIZE FLOPPY)$' UNKNERR:DB '(UNIDENTIFIABLE PROBLEM)$' ERMSG: DB BEL,BEL,BEL,'ERROR ',BEL,BEL,'ON DRIVE ',BEL,BEL,BEL DEV: DB ' , AT TRACK ' TRK: DB ' , SECTOR ' SEC: DB ' ,',LF,CR,'STATUS=' ERSTAT: DB ' $' ERMSG2: DB '.',LF,CR,'PROGRAM PREMATURELY TERMINATED.$' TRMMSG: DB 'FAST COPY OPERATION SUCCEEDED. FLOPPY WRITTEN AND VERIFIED.$' ; ;THIS TERMINATES THE PROGRAM AFTER RESTORING THE "CURRENT DISK" SELECTION ; TERM: LD C,W.LINE LD DE,TRMMSG CALL CDOS TERM2: LD C,C.DISK; GET CURRENT DRIVE CALL CDOS LD E,A LD C,RES.CDOS; RESET CDOS AND LOG OFF ALL DISKS CALL CDOS LD C,SEL.DISK; RESTORE CURRENT DISK SELECTION CALL CDOS JP 100H END XEROX