;DCOPY - Diskcopy for version 6.3 ; ; 01/07/87 - Corrected source to include patch #001 TITLE ; CR EQU 13 LF EQU 10 ETX EQU 3 BRK EQU 80H *GET BUILDVER/ASM:3 ;<631> *GET SVCMAC ; ORG 2600H ; DSTERR: LD HL,DSTERR$ DB 0DDH SRCERR: LD HL,SRCERR$ PUSH AF @@LOGOT POP AF ; IOERR: OR 0C0H ;Short error PUSH AF CALL SYSTEM ;Get a system disk in POP AF LD C,A LD H,0 LD L,A @@ERROR LD SP,(SAVSTK) JR EXIT2 ABORT: LD HL,-1 JR EXIT1 EXIT: LD HL,0 EXIT1 LD SP,$-$ SAVSTK EQU $-2 CALL SYSTEM ;Get a system disk EXIT2: @@CKBRKC RET ; NOMEM: LD HL,NOMEM$ ;"Out of memory DB 0DDH NOTCMD: LD HL,NOTCMD$ ;"Not while doing cmndr... DB 0DDH DRVMIS LD HL,DRVMIS$ ;"Missing drive number... DB 0DDH DUPDRV LD HL,DUPDRV$ ;"Dest=Source... DB 0DDH NOTIN LD HL,NOTIN$ @@LOGOT LD HL,-1 LD SP,(SAVSTK) JR EXIT2 ; ILLEG: LD HL,ILLEG$ ;"Illegal drive type... DB 0DDH DRVERR: LD HL,DRVERR$ ;"Drive not ready... DB 0DDH WPERR: LD HL,WPERR$ ;"Dest is WP... DB 0DDH ABORT1: LD HL,ABORT$ @@LOGOT JR ABORT ; ; SIGNON$ DB 'DISKCOPY ' *GET CLIENT:3 ; NOMEM$ DB 'Not enough memory to Diskcopy',CR NOTCMD$ DB 'Diskcopy only valid at DOS level',CR DRVMIS$ DB 'Missing drive number(s)',CR DUPDRV$ DB 'Single drive Diskcopy invalid',CR NOTIN$ DB 'Drive not enabled',CR ABORT$ DB LF,LF,'Diskcopy aborted',CR ILLEG$ DB 'Diskcopy is for 5 inch, double density floppy disks only',CR DRVERR$ DB 'Drive not ready',CR WPERR$ DB 'Destination drive is write protected',CR MOUNT$ DB 'Mount source and destination disks, press' DB ' ENTER when ready ',CR DSTERR$ DB LF,LF,'Destination disk error',CR SRCERR$ DB LF,LF,'Source disk error',CR DONE$ DB LF,LF,'Disk copy complete, copy another (Y/N) ? ',LF,CR SYSTEM$ DB LF,'Mount SYSTEM disk, press ENTER when ready ',CR ; ; BEGIN: @@CKBRKC ;No break down JR Z,BEGINA LD HL,-1 RET BEGINA: LD (SAVSTK),SP ;Save entry stack PUSH HL LD HL,SIGNON$ @@DSPLY @@FLAGS ;Get the flag table LD A,(IY+'C'-'A') ;Get C flag BIT 1,A ;CMNDR? JP NZ,NOTCMD ;Go if it is LD HL,0 ;Get high$ IF @BLD631 LD B,L ;<631>L==0 ELSE LD B,0 ENDIF @@HIGH$ LD DE,ENDLOC ;Get mem needed OR A SBC HL,DE ;See if enuf IF @BLD631 POP HL ;<631>Cmdline ptr JP C,NOMEM ;<631> ELSE JP C,NOMEM POP HL ;Cmdline ptr ENDIF CALL SKPSPC CP ':' ;Got a drive spec? JP NZ,DRVMIS ;Bad if not LD A,(HL) ;Get a drive # INC HL SUB 30H ;Make binary and ck IF @BLD631 ELSE JP C,DRVMIS ; range ENDIF CP 8 JP NC,DRVMIS LD (SRCDRV),A ;Save drive # LD C,A @@GTDCT LD A,(IY) ;Be sure drive is enabled CP 0C9H JP Z,NOTIN CALL SKPSPC CP ':' ;Now get 2nd # JP NZ,DRVMIS LD A,(HL) ;Get drive # SUB 30H IF @BLD631 ELSE JP C,DRVMIS ENDIF CP 8 JP NC,DRVMIS CP C ;Same as source? JP Z,DUPDRV ;No can do LD (DSTDRV),A LD C,A @@GTDCT LD A,(IY) CP 0C9H JP Z,NOTIN CALL GETSYS2 ;Be sure ckdrv is resident ; ; Come here for next disk ; RESTRT: CALL MOUNT ;Have disks mounted LD A,(SRCDRV) ;Now ck drive types LD C,A @@GTDCT ;Get the DCT LD (SRCDCT),IY ;Save source LD A,(IY+3) ;Get dct byte AND 01101000B ;Hard, 8" XOR 40H ;Sden JP NZ,ILLEG ;Was sden, 8", or hard BIT 4,(IY+4) ;Alien? IF @BLD631 NOP ;<631> NOP ;<631> NOP ;<631> ELSE JP NZ,ILLEG ENDIF PUSH IY LD A,(IY+9) ;Read in source GAT LD D,A IF @BLD631 LD HL,GATBUF ;<631> LD E,L ;<631>L==0 ELSE LD E,0 LD HL,GATBUF ENDIF @@RDSSC JP NZ,IOERR LD A,(DSTDRV) LD C,A @@GTDCT LD (DSTDCT),IY ;Save dest dct LD A,(IY+3) ;Save step and delay AND 7 LD B,A ; in B LD A,(IY+4) ;Save select AND 0FH LD C,A ; in C PUSH IY POP DE ;Pt DE to dct+3 INC DE INC DE INC DE POP HL ;Source DCT INC HL INC HL INC HL PUSH BC ;Save dest stuff PUSH DE ;Save dst dct LD BC,7 LDIR POP DE POP BC LD A,(DE) ;Merge in DST stuf AND 078H OR B LD (DE),A INC DE LD A,(DE) IF @BLD631 AND 060H ;<631> ELSE AND 070H ENDIF OR C LD (DE),A ;Now, dst matches src INC DE XOR A ;Always track 0 LD (DE),A ; ; Set to start ; LD IY,(DSTDCT) CALL SETFMT ;Init the format info EXX ;Init alts LD HL,GATBUF ;Used info LD DE,GATBUF+60H ;Lock out table EXX LD A,(SECCYL) LD (RDCNT),A ;Set up sector count LD (WRCNT),A LD (VERCNT),A LD B,4 ;Get cursor posn @@VDCTL LD (CURSOR),HL ;Save for dsply ; MAINLP: CALL BGNFMT ;Format a cyl EXX ;Alts in LD A,(DE) ;Ck for lockout on src LD (WASLOK),A ;Show was locked INC DE ;Next track CP 0FFH ;If it is, then JR NZ,NOLOCK INC HL ;Must skip this also EXX JP DOVER ;Just verify NOLOCK: CP (HL) ;See if in use INC HL EXX JP Z,DOVER ;Go if empty ; ; Not empty or locked, dupe it ; LD HL,RDCYL$ CALL MSGOUT LD A,(SRCDRV) LD C,A ;Drive to C LD D,(IY+5) ;Cyl to D LD E,0 LD B,$-$ RDCNT EQU $-1 LD HL,RDBUF ;Where to put it LD A,(IY+9) ;Ck for dir trk CP D JR Z,RDSYS ;Go if dir RDREG: @@RDSEC JP NZ,SRCERR INC H INC E DJNZ RDREG JR RDDUN RDSYS: @@RDSSC JP NZ,SRCERR INC H INC E DJNZ RDSYS ; RDDUN: LD HL,WRCYL$ CALL MSGOUT LD A,(DSTDRV) LD C,A ;Drive to C LD D,(IY+5) ;Cyl LD E,0 LD B,$-$ ;Sector count WRCNT EQU $-1 LD HL,RDBUF ;Pt to data LD A,(IY+9) ;See if dir. CP D JR Z,WRDIR ;Go if it is WRREG: @@WRSEC JP NZ,DSTERR INC H INC E DJNZ WRREG JR DOVER WRDIR: @@WRSSC JP NZ,DSTERR INC H INC E DJNZ WRDIR ; DOVER: LD HL,VERCYL$ CALL MSGOUT LD A,(DSTDRV) LD C,A LD D,(IY+5) ;Get cyl LD E,0 LD B,$-$ VERCNT EQU $-1 VERLP: @@VRSEC JR Z,VER1 ;Go if ok CP 6 ;Sys sec? JP Z,VER1 ;Is dir, ok LD E,A ;Ok - real error, is src LD A,(WASLOK) ; tracked locked? CP 0FFH LD A,E ;Error code back to A JR Z,VER2 ;If so, error is ok JP DSTERR ;Else abort VER1: INC E ;Next sector DJNZ VERLP ; VER2: LD A,(IY+6) ;See if at end CP (IY+5) ;Are we?? JR Z,ALLDUN ;Go if so RES 4,(IY+3) ;Always start on side 1 CALL STEPIN ;Next track CALL RSELCT ;Wait for FDC JP NZ,IOERR LD BC,3000/15 @@PAUSE JP MAINLP ; ALLDUN: CALL RESTOR ;Restore the drive LD HL,DONE$ ;Show completed @@DSPLY ALLD1: @@KEY ;Get a key CP BRK ;If break, done JP Z,EXIT OR 20H CP 'y' ;Do another? JP Z,RESTRT CP 'n' JR NZ,ALLD1 JP EXIT ; ; ; SKPSPC: LD A,(HL) ;Get a char INC HL CP CR+1 ;End of line? JP C,DRVMIS ;Bad if so CP ' ' JR Z,SKPSPC RET ; ; Check and be sure two disks are mounted ; MOUNT: LD HL,MOUNT$ ;"Mount disks... @@DSPLY MNT1: @@KEY ;Get a key CP 80H JP Z,ABORT1 CP CR JR NZ,MNT1 LD A,$-$ ;Get source drive SRCDRV EQU $-1 LD C,A @@CKDRV IF @BLD631 JR NZ,MOUNT ;<631> ELSE JP NZ,MOUNT ENDIF LD A,$-$ ;Dest. drive # DSTDRV EQU $-1 LD C,A IF @BLD631 LD (SETDRV+1),A ;<631>Save in i/o routine ELSE LD (FMTDRV+1),A ;Save in i/o routine ENDIF @@GTDCT LD A,(IY) ;Drive enabled? CP 0C9H ;Disabled? JP Z,DRVERR BIT 3,(IY+3) ;Hard? JP NZ,ILLEG BIT 4,(IY+4) ;Alien? JP NZ,ILLEG CALL RESTOR ;Restore the drive JP NZ,IOERR CALL RSELCT ;Reselect drive JP NZ,IOERR BIT 7,A JP NZ,DRVERR ;Go if FDC not rdy BIT 2,A JP Z,DRVERR ;Go if not at trk 0 CALL CKDRV ;Be sure disk mounted JR NZ,MOUNT ;Disk not mounted RLCA OR (IY+3) ;Ck for wp AND 80H JP NZ,WPERR ;Go if write prot. LD C,CR ;Bump down a line @@DSP RET ; ; Prompt for a system disk ; SYSTEM: PUSH HL IF @BLD631 JR SYS9 ;<631> ENDIF SYS2: LD HL,SYSTEM$ @@DSPLY ;Show the message SYS1: @@KEY ;Wait for an answer CP CR ;Is it a CR? JR NZ,SYS1 ;Redo if not IF @BLD631 SYS9: ;<631> ENDIF LD HL,BUFF ;Read 0,0 LD DE,0 IF @BLD631 LD C,D ;<631>Drive to C (D==0) ELSE LD C,0 ;Drive to C ENDIF @@CKDRV JR NZ,SYS2 @@RDSEC JR NZ,SYS2 IF @BLD631 LD A,(BUFF+2) ;<631>Get dir cyl ELSE LD A,(BUFF+3) ;Get dir cyl ENDIF LD D,A ;Put in D @@RDSSC ;Read the GAT JR NZ,SYS2 ;Redo on error LD A,(BUFF+0CDH) ;Get the type byte AND 80H ;Is it system? JR NZ,SYS2 ;Redo if not LD C,CR @@DSP POP HL RET ; else all ok, quit ; ; Disk I/O requests ; IF @BLD631 DRVNOP: XOR A ;<631> JR FMTDRV ;<631> SELECT: LD A,1 ;<631> JR FMTDRV ;<631> RESTOR: LD A,4 ;<631> JR FMTDRV ;<631> STEPIN: LD A,5 ;<631> JR FMTDRV ;<631> RSELCT: LD A,7 ;<631> JR FMTDRV ;<631> WRCYL: LD A,15 ;<631> JR FMTDRV ;<631> FMTHD: LD A,12 ;<631> JR FMTDRV ;<631> WRSEC: LD A,13 ;<631> JR FMTDRV ;<631> WRSYS: LD A,14 ;<631> JR FMTDRV ;<631> RDSEC: LD A,9 ;<631> JR FMTDRV ;<631> VERSEC: LD A,10 ;<631> FMTDRV: PUSH BC ;<631> SETDRV: LD C,-1 ;<631>P/u drive # ELSE DRVNOP PUSH BC XOR A JR FMTDRV SELECT PUSH BC LD A,1 JR FMTDRV RESTOR PUSH BC LD A,4 JR FMTDRV STEPIN PUSH BC LD A,5 JR FMTDRV RSELCT PUSH BC LD A,7 JR FMTDRV WRCYL PUSH BC LD A,15 JR FMTDRV FMTHD PUSH BC LD A,12 JR FMTDRV WRSEC PUSH BC LD A,13 JR FMTDRV WRSYS PUSH BC LD A,14 JR FMTDRV RDSEC PUSH BC LD A,9 JR FMTDRV VERSEC PUSH BC LD A,10 FMTDRV LD C,-1 ;P/u drive # ENDIF ADD A,40 ;Adjust SVC # RST 40 POP BC RET ; ; Brief routine to check a drive for availability ; CKDRV LD HL,BUFF @@TIME ;P/u the timer pointer EX DE,HL ;TIME$ to HL DEC HL ;TIMER$ to HL LD A,(HL) ;P/u current timer value ADD A,15 ;Set timeout to 500ms LD D,A ;Save for test later ; ; Test for diskette in drive & rotating ; CKDR1 CALL CKDR6 ;Test index pulse JR NZ,CKDR1 ;Jump on index CKDR2 CALL CKDR6 ;Test index pulse JR Z,CKDR2 ;Jump on no index CKDR2A CALL CKDR6 JR NZ,CKDR2A ;Jump on index RET CKDR6 EI ;Make sure they're ON LD A,(HL) ;P/u latest TIMER$ value SUB D ;500ms passed? JR Z,CKDR7 CALL RSELCT ;Select & wait not busy BIT 1,A ;Test index RET CKDR7 POP DE ;Pop the ret address OR 1 ;Set "Illegal drive # RET ;With NZ ; GETSYS2: LD A,84H ;Load sys2 RST 40 ; ; ;DCOPY1 ; SETFMT: LD DE,D5TBL ;P/u table pointer LD A,(DE) ;P/u # of sectors to fmt INC DE ;Adj for zero offset LD (SECTRK),A LD B,A BIT 5,(IY+4) ;Need twice as many JR Z,$+3 ; if 2-sided drive RLCA LD (SECCYL),A LD A,(DE) ;P/u track skew INC DE LD (TRKSKEW+1),A LD (SECSKEW+1),DE ;Format sector skew ; ; Index past sector info ; INC A ;Add DE -> begin of sec # ADD A,B ;B -> # of sectors/side ADD A,E ; A+1 -> a code byte LD E,A ADC A,D SUB E LD D,A LD HL,BUFF ;Buffer for format data LD BC,HITBUF ;Tempy ptrs to trk,sect info ; ; Create the formatting data without trk,sect info ; FMTDAT LD A,(DE) ;P/u table format byte INC DE ;Bump table ptr CP 0F1H ;Start of cylinder? JR Z,CODF1 CP 0F2H ;Start of track trailer? JR Z,CODF2 CP 0F3H ;Start of track ID info? JR Z,CODF3 CP 0F4H ;End of table parms? JR Z,CODF4 CP 0F5H ;Start of data? PUSH BC JR NZ,CODE1 ;Go if not ; ; Write 2 byte data pattern to format buffer ; LD A,(DE) ;P/u length to write INC DE ;Bump to 1st data byte LD B,A ;Xfer length to B LD A,(DE) ;P/u a data byte INC DE ;Bump again for 2nd byte LD C,A ;Xfer 1st byte LD A,(DE) ;P/u 2nd byte CODF5 LD (HL),C ;Stuff into buf INC HL LD (HL),A INC HL DJNZ CODF5 ;Loop til xfered JR CODRET ; ; Xfer bytes to the format buffer area ; A => count to move ; DE=> data byte to duplicate ; CODE1 LD B,A ;Count to B LD A,(DE) ;P/u data byte to move CODE1A LD (HL),A ;Fill buf with byte INC HL DJNZ CODE1A ;Loop til done CODRET POP BC INC DE ;Bump table ptr JR FMTDAT ;Back for more ; ; Save the current table posn and the number of ; sectors per cylinder on the stack. ; CODF1 LD A,(SECTRK) ;P/u # of sectors/side CODF1A PUSH DE ;Save table pointer PUSH AF ;Save value JR FMTDAT ; ; Done with a sector. Are there more on this cyl? ; CODF2 POP AF ;Count down the # of DEC A ; sectors to format JR Z,CODF2A ;Go if last one done POP DE ;Recover table ptr JR CODF1A ;Loop for more ; CODF2A POP AF ;Clean the stack JR FMTDAT ; and finish off the cyl ; ; Build a table of the location in the format buffer of ; the track and sector ID bytes, to be filled in during ; the actual formatting. ; CODF3 LD A,L ;Stuff pointer to where LD (BC),A ; track & sector info INC BC ; is to be placed LD A,H LD (BC),A INC BC JR FMTDAT ; ; Finished building format cyl info. Terminate the ID table ; with an extra 256 bytes in case of overrun. ; CODF4: XOR A ;Stuff two X'00's to LD (BC),A ; indicate the end INC BC ; of the ID posn table LD (BC),A LD B,0 ;Stuff 256 FF's into the LD A,0FFH ; format buffer LD (HL),A INC HL DJNZ $-2 RET ; ; Begin the formatting ; BGNFMT: LD HL,FMTCYL$ ;"Formatting... CALL MSGOUT SECSKEW LD BC,0 ;Begin of sector table BFMT1 LD HL,HITBUF ;P/u ptr to ID posn table ; BFMT2 @@CKBRKC ;Check for break JP NZ,ABORT1 ;Go if so ; LD E,(HL) ;P/u positions having INC HL ; sector & cylinder LD D,(HL) ; info to be stuffed INC HL ; into format data LD A,D ;Finished? OR E JR Z,BFMT4 LD A,(IY+5) ;P/u cylinder # & stuff LD (DE),A ; into format data INC DE LD A,(IY+3) ;Stuff the side-select AND 10H ; bit RRCA RRCA RRCA RRCA LD (DE),A ; into the format data INC DE LD A,(BC) ;P/u the sector number OR A JP P,BFMT3 ;Go if a good number ADD A,C ; else off the end, LD C,A ; calculate the beginning JR C,BFMT3 ; of the sector table DEC B BFMT3 LD A,(BC) ;P/u the next sector # LD (DE),A ; and stuff in format data INC DE INC BC JR BFMT2 ;Loop until cylinder done ; BFMT4 LD (SECSKEW+1),BC ;Save end of sector table LD D,(IY+5) ;P/u current cylinder LD HL,BUFF ;Pt to format data CALL SELECT ;Drive select JP NZ,IOERR ;Go on error CALL WRCYL ;Cylinder write JP NZ,IOERR BIT 5,(IY+4) ;Double sided? JR Z,BFMT5 BIT 4,(IY+3) ;Flip bit for 2nd side JR NZ,BFMT5 ; if not already on it, SET 4,(IY+3) ; else go to next INC BC ;Bump to start side 2 JR BFMT1 ; at different sector # BFMT5 RES 4,(IY+3) ;Turn off side 2 TRKSKEW LD A,0 ;P/u the track skew byte ADD A,C ;Repoint to beginning LD C,A ; of sector table ADC A,B ;Skew start of next track SUB C LD B,A LD (SECSKEW+1),BC RET ; ; ; Formatting data and tables ; SECCYL DS 1 ;# of sectors per cyl SECTRK DS 1 ;# of sectors per trk ; ; ; Double density 5" format table ; D5TBL DB 18,10 DB 0,9,1,10,2,11,3,12,4 DB 13,5,14,6,15,7,16,8,17 DC 11,-18 DB 32,4EH DB 0F1H,12,0,3,0F5H,1,0FEH DB 0F3H,3,0,1,1,1,0F7H,22,4EH,12,0,3,0F5H DB 1,0FBH,0F5H,128,6DH,0B6H DB 1,0F7H,1,4EH,23,04EH DB 0F2H,182,4EH,0F4H DB 0,1,2,3,4,5,6,7,8,9 DB 10,11,12,13,14,15,16,17 ; ; Routine to convert reg A to 2 decimal digits ; CVDEC LD C,30H ;Init msd to 0 CVD1 SUB 10 ;Sub 10 until underflow JR C,CVD2 INC C ;Inc the count JR CVD1 CVD2 ADD A,3AH ;Add back 10 + '0' LD B,A ;Lsd to B RET ; ; Show what's happening ; MSGOUT: PUSH HL ;Save msg LD HL,$-$ ;Set cursor CURSOR EQU $-2 LD B,3 @@VDCTL POP HL @@DSPLY LD A,(IY+5) ;Get syl # CALL CVDEC @@DSP ;Show cyl # LD C,B @@DSP RET ; ; SRCDCT DW 0 DSTDCT DW 0 WASLOK DB 0 ; FMTCYL$ DB 'Formatting ',3 RDCYL$ DB 'Reading ',3 WRCYL$ DB 'Writing ',3 VERCYL$ DB 'Verifying ',3 ; ORG $<-8+1<8 HITBUF DS 256 GATBUF DS 256 RDBUF DS 36*256 BUFF EQU $ ; ENDLOC EQU $+2B00H ;for free mem check END BEGIN