home *** CD-ROM | disk | FTP | other *** search
- ; Disk Copy Utility from CPM Users Group
- ; Modified for CDOS by Trevor Marshall
- ; Elec Eng Dept
- ; Uni W.A.
- ; Jan 1980
- ;
- ; Rewritten for 2.36 CDOS (Double Density)
- ; Automatic disk label checking,
- ; Sept 1980, Trevor Marshall
- ;
- ;
- ORG 100H
- JP COPY
- ; BIOS FUNCTION CALLING TABLE
- WBOOT: CALL BIOSGO
- CONST: CALL BIOSGO
- CONIN: CALL BIOSGO
- CONOUT: CALL BIOSGO
- LIST: CALL BIOSGO
- PUNCH: CALL BIOSGO
- READER: CALL BIOSGO
- HOME: CALL BIOSGO
- SELDSK: CALL BIOSGO
- SETTRK: CALL BIOSGO
- SETSEC: CALL BIOSGO
- SETDMA: CALL BIOSGO
- READ: CALL BIOSGO
- WRITE: CALL BIOSGO
- BIOSGO: EX (SP),HL ; Get call addr in HL, save HL on stack
- PUSH DE ; Save DE
- EX DE,HL ; Move call addr to DE
- LD HL,(1) ; Get BIOS entry address
- ADD HL,DE ; Add call addr to entry addr
- LD DE,[WBOOT+3]; Get start of table
- ; Subtract DE from HL in 8080 code (for compatibility)
- LD A,E
- CPL
- LD E,A
- LD A,D
- CPL
- LD D,A ;Now have 1s compl of DE
- INC DE ;2s compl
- ADD HL,DE ;Done!
- POP DE ; Restore DE
- EX (SP),HL ; Restore HL, put jump addr on stack
- RET ; Jump to BIOS routine
- ; Original coding by:
- ; L.E. HUGHES 8080SDC 77/10/29
- ;
- ; Modified by Trevor Marshall
- ; E.E.Dept
- ; Uni W.A.
- ;
- ; to work with any sized CDOS system
- ; and to prompt for drives
- ;
-
- ; MISC SYMBOLS
-
- LF EQU 0AH ;LINE FEED
- CR EQU 0DH ;CARRIAGE RETURN
-
- ITRK EQU 0 ;INITIAL TRACK TO COPY
- LTRK EQU 76 ;LAST TRACK TO COPY
-
- BDOS: EQU 5
- ;
- COPY: LD HL,0
- ADD HL,SP
- LD (OLDSP),HL
- LD SP,STACK+64
- ;
- ; ALLOW USER TO MOUNT DISK(S) BEFORE PROCEEDING
-
- AGAIN: LD C,96H ;Turn drive motors off
- CALL BDOS
- ;
- LD HL,CRLF
- CALL WASC
- LD HL,STR1 ;PRINT 'Source Disk Drive,etc'
- CALL WASC
- CALL RACC
- CP 3 ;CTL-C ABORT
- JP Z,EXIT1
- CALL WACC
- SUB 'A'
- JP C,AGAIN ;Invalid entry
- CP 3
- JP NC,AGAIN
- LD (SOURCE),A
- LD HL,CRLF
- CALL WASC
- ; Now prompt for destination
- LD HL,STR1A
- CALL WASC
- CALL RACC
- CALL WACC
- SUB 'A'
- JP C,AGAIN
- CP 3
- JP NC,AGAIN
- LD (DEST),A
- LD HL,SOURCE
- LD C,(HL)
- CP A,C
- JP Z,AGAIN
- LD HL,CRLF
- CALL WASC
-
-
- ; Now we must determine whether single or double
- ; density disks are in use, and check that we
- ; are not trying to copy between incompatible formats
- ;
- ; We will use the CDOS 1BH cal (Get disk allocation vec)
- ; as the disk labels are read before this call returns.
- ; This call returns the number of clusters in DE
- ;
- ;
- LD C,0DH ;Reset CDOS
- CALL BDOS
- ;
- LD A,(SOURCE) ;Select Source drive
- LD E,A
- LD C,0EH
- CALL BDOS
- ;
- LD C,1BH ;Get CLUSTER.SIZE size map
- CALL BDOS ;for first disk
- LD (ACLUSTERS),DE
- ;
- LD A,(DEST) ;Select Dest. drive
- LD E,A
- LD C,0EH
- CALL BDOS
- ;
- LD C,1BH ;Get cluster size map
- CALL BDOS ;for second disk
- LD (BCLUSTERS),DE ;save it
- LD HL,(ACLUSTERS) ;get it again
- XOR A
- SBC HL,DE ;to compare them
- LD A,L
- OR A,L ;see if HL is zero
- JP NZ,SEND.DIFF.ERROR ;no
- ; Now display the disks in use and branch to copy S/R
- LD A,E ;LSB of # clusters
- CP A,0FEH ;D/D S/S?
- JP Z,SEND.DD.MSG
- CP A,060H ;D/D D/S
- JP Z,SEND.DS.MSG
- CP A,0F3H ;S/D S/S
- JR Z,SEND.SD.MSG
- CP A,0F7H ;S/D D/S
- JP Z,SEND.DS.MSG ;Dont use this often,
- ;I wont bother to tidy it up
- JP SEND.NON.STANDARD.MSG
- ;
- SEND.SD.MSG: LD DE,SD.MSG
- LD C,9
- CALL BDOS ;Print it
- LD A,1BH ;Max sectors/trk+1
- LD (SECTORS.PER.TRACK),A
- LD HL,80H ;The sector size for S/D
- LD (DMA.INCR),HL
- LD HL,SDMAP-1 ;Point to sector map
- LD (SECTOR.MAP.ADDRESS),HL
- JR MAIN
- ;
- SEND.DIFF.ERROR: LD DE,DIFF.ERROR.MSG
- L5: LD C,9
- CALL BDOS
- JP AGAIN
- SEND.NON.STANDARD.MSG: LD DE,NON.STANDARD.ERROR.MSG
- JR L5
- ;
- ; BEGIN SINGLE DENSITY LOOP
-
- MAIN: LD DE,MSG1 ;Finish disk msg
- LD C,9
- CALL BDOS
- ;
- LD HL,STR4 ;PRINT HEADER
- CALL WASC
- LD HL,STR5
- CALL WASC
- ;
- LD A,ITRK ;INITIAL TRACK NUMBER
- LD (TRKNO),A
- COPY2:
- ; Check for CTL-C abort
- CALL CONST
- CP 0
- JP Z,FT1
- CALL CONIN
- AND 5FH
- CP 3 ;CTL-C
- JP Z,COPYX
- FT1: LD A,(SOURCE) ;Select Source Disk
- LD C,A
- CALL SELDSK
- LD A,(TRKNO) ;SET TRACK NUMBER
- LD C,A
- CALL SETTRK
- LD HL,TBUF ;SET INITIAL DMA ADDRESS
- LD (DMAPTR),HL
- LD A,1 ;INITIAL SECTOR NUMBER
- LD (SECNO),A
- COPY3: LD A,(SECNO) ;SET SECTOR NUMBER
- LD HL,(SECTOR.MAP.ADDRESS)
- LD D,0
- LD E,A
- ADD HL,DE
- LD C,(HL)
- CALL SETSEC
- LD HL,(DMAPTR) ;SET DMA ADDRESS
- LD B,H
- LD C,L
- CALL SETDMA
- CALL READ ;READ SECTOR
- LD HL,(DMAPTR) ;ADD INCR TO DMA PTR
- PUSH DE
- LD DE,(DMA.INCR)
- ADD HL,DE
- POP DE
- LD (DMAPTR),HL
- LD HL,SECNO ;ADD 1 TO SECTOR NUMBER
- INC (HL)
- LD A,(HL)
- LD HL,SECTORS.PER.TRACK
- CP A,(HL) ;LOOP THRU ENTIRE TRACK
- JP C,COPY3
-
- ; WRITE TBUF TO CURRENT TRACK ON DISK C
-
- LD A,(DEST) ;Select dest dsk
- LD C,A
- CALL SELDSK
- LD A,(TRKNO) ;SET TRACK NUMBER
- LD C,A
- CALL SETTRK
- LD HL,TBUF ;SET DMA ADDRESS
- LD (DMAPTR),HL
- LD A,1 ;SET INITIAL SECTOR NUMBER
- LD (SECNO),A
- COPY4: LD A,(SECNO) ;SET SECTOR NUMBER
- LD HL,(SECTOR.MAP.ADDRESS)
- LD D,0
- LD E,A
- ADD HL,DE
- LD C,(HL)
- CALL SETSEC
- LD HL,(DMAPTR) ;SET DMA ADDRESS
- LD B,H
- LD C,L
- CALL SETDMA
- CALL WRITE ;WRITE SECTOR
- LD HL,(DMAPTR) ;ADD INCR TO DMAPTR
- PUSH DE
- LD DE,(DMA.INCR)
- ADD HL,DE
- POP DE
- LD (DMAPTR),HL
- LD HL,SECNO ;ADD 1 TO SECTOR NUMBER
- INC (HL)
- LD A,(HL)
- LD HL,SECTORS.PER.TRACK
- CP A,(HL) ;LOOP THRU ENTIRE TRACK
- JP C,COPY4
-
- ; ADVANCE TO NEXT TRACK
-
- LD A,'*'
- CALL WACC
- LD HL,TRKNO
- INC (HL)
- LD A,(HL)
- CP LTRK+1 ;LOOP THRU ENTIRE DISK
- JP C,COPY2
-
- ; ALL DONE SINGLE DENSITY
-
- COPY5: LD HL,STR2 ;PRINT 'COPY COMPLETE'
- JP COPY6
- COPYX: LD HL,STR3 ;PRINT 'COPY ABORTED'
- COPY6: CALL WASC
- JP COPY
- EXIT1: LD HL,(OLDSP) ;EXIT TO CP/M
- LD SP,HL
- JP 0
-
- ; WASC - WRITE ASCII STRING TO CONSOLE
-
- WASC: LD A,(HL)
- OR A
- RET Z
- CALL WACC
- INC HL
- JP WASC
-
- ; WACC - WRITE ASCII CHARACTER TO CONSOLE
-
- WACC: PUSH HL
- PUSH DE
- PUSH BC
- PUSH AF
- LD C,A
- CALL CONOUT
- POP AF
- POP BC
- POP DE
- POP HL
- RET
-
- ; RACC - READ ASCII CHARACTER FROM CONSOLE
-
- RACC: PUSH HL
- PUSH DE
- PUSH BC
- CALL CONIN
- AND 5FH ;Make LC=UC
- POP BC
- POP DE
- POP HL
- RET
-
- SEND.DS.MSG: LD A,2
- LD (SIZE.FLAG),A
- LD DE,DS.MSG
- JR V1
- SEND.DD.MSG: LD A,1
- LD (SIZE.FLAG),A
- LD DE,DD.MSG
- V1: LD C,9
- CALL BDOS
- ;
- ;Calculate the 2's complement of the block capacity of disk
- LD HL,(ACLUSTERS) ;Get # on disk
- ADD HL,HL ; x2 (16 blocks per cluster)
- ADD HL,HL ; x4
- ADD HL,HL ; x8
- ADD HL,HL ; x16
- EX DE,HL ;into DE
- SCF ;add 1 to block capacity
- LD HL,0
- SBC HL,DE ;have 2's complement
- LD (BLOCK.CAPACITY),HL
- ; We cannot use the same approach for D/D disks
- ; as for S/D, so we will use a LOGICAL BLOCK
- ; approach. Each block is 128 Bytes, I have
- ; ~32K free RAM, so will read ~28K at a time
- ; (160h, 352d blocks).
- ;
- DOUBLE: LD DE,MSG1 ;Finish disk msg
- LD C,9
- CALL BDOS
- ;
- LD A,(SIZE.FLAG) ;Is it D/D or D/S ?
- CP 1 ;D/D only?
- JR NZ,JJ1 ;No, D/S D/D
- LD HL,STR6 ;PRINT D/D HEADER
- CALL WASC
- LD HL,STR7
- CALL WASC
- JR JJ2
- ;
- JJ1: LD HL,STR8 ;PRINT D/S HEADER
- CALL WASC
- LD HL,STR9
- CALL WASC
- ;
- JJ2: LD HL,0 ;INITIAL BLOCK NUMBER
- LD (BLKNO),HL
- ;
- ; Begin the main (fill buffer) loop
- DCOPY2: LD HL,TBUF-80H
- LD (DMAPTR),HL ;Initialize DMA ptr
- LD DE,(BLKNO) ;Block # to DE
- LD (FIRSTBLK),DE ;Save first blocK #
- ;
- ; Check for CTL-C abort
- CALL CONST
- CP 0
- JP Z,DFT1
- CALL CONIN
- AND 5FH
- CP 3 ;CTL-C
- JP Z,COPYX ;and abort
- ;
- ; Get enough blocks to fill buffer, one at a time
- DFT1: LD HL,(DMAPTR) ;ADD INCR TO DMA PTR
- LD DE,80H ;Block size is 128 bytes
- ADD HL,DE
- LD (DMAPTR),HL
- ; Are we at end of Buffer,
- LD DE,-8000H
- ADD HL,DE ;C means .LT. 8000H
- JR C,DCOPY6 ;If so write the buffer
- ;Set DMA for DOS
- LD DE,(DMAPTR)
- LD C,1AH
- CALL BDOS
- ; Is this block beyond the end of disk?
- LD DE,(BLOCK.CAPACITY)
- LD HL,(BLKNO)
- ADD HL,DE ;see if DE & HL are .EQ.
- LD A,L
- OR A,H
- JP Z,COPY5 ;Z = done copy
- ; Read the block
- LD DE,(BLKNO) ;Block # to DE
- LD C,83H
- LD HL,SOURCE
- LD B,(HL) ;disk # to B
- INC B ;For BDOS
- SET 7,B ;Set interleaved read
- CALL BDOS
- ; Handle error status
- CP A,1 ;I/O error
- JP Z,COPYX
- CP A,2 ;Illegal request
- JP Z,COPYX
- CP A,3 ;Illegal Block
- JP EQ,COPYX
- ; Now incr the block #
- LD HL,(BLKNO)
- INC HL
- LD (BLKNO),HL
- ; Is this beyond the end of disk?
- LD DE,(BLOCK.CAPACITY)
- ADD HL,DE ;see if DE & HL are .EQ.
- LD A,L
- OR A,H
- JR NZ,DFT1 ;Z = done read
- ; Must decr last BLKNO so write does not overrun
- DCOPY6: LD HL,(BLKNO)
- DEC HL
- LD (BLKNO),HL
- ;
- ;Write the buffer if full
- DCOPY3:
- ; Begin the main (empty buffer) loop
- SENDSTAR: LD A,'*'
- CALL WACC
- ;
- LD HL,TBUF-80H
- LD (DMAPTR),HL ;Initialize DMA ptr
- ; Save last BLK # and get first #
- LD HL,(BLKNO)
- LD (LASTBLK),HL
- ;
- LD DE,(FIRSTBLK) ;First Block # to DE
- LD (BLKNO),DE ;Save blocK #
- ;
- ; Put enough blocks to empty buffer, one at a time
- DFT2: LD HL,(DMAPTR) ;ADD INCR TO DMA PTR
- LD DE,80H ;Block size is 128 bytes
- ADD HL,DE
- LD (DMAPTR),HL
- ; Is this beyond the end of disk?
- ; LD DE,(BLOCK.CAPACITY)
- ; LD HL,(BLKNO) ;get the block #
- ; ADD HL,DE ;see if DE & HL are .EQ.
- ; LD A,L
- ; OR A,H
- ; JP Z,COPY5 ;Z = done copy
- ; Have we written too many blocks
- LD HL,(LASTBLK)
- LD DE,(BLKNO)
- XOR A
- SBC HL,DE
- JP C,DCOPY2 ;C if BLKNO > LASTBLK
- ; On exit BLKNO will be LASTBLK + 1
- ; Which is OK for next read loop
- ;Set DMA for DOS
- LD DE,(DMAPTR)
- LD C,1AH
- CALL BDOS
- ;
- ; Write the block
- LD DE,(BLKNO) ;Block # to DE
- LD C,84H
- LD HL,DEST
- LD B,(HL) ;disk # to B
- INC B ;for BDOS
- SET 7,B ;Set interleaved read
- CALL BDOS
- ; Handle error status
- CP A,1 ;I/O error
- JP Z,COPYX
- CP A,2 ;Illegal request
- JP Z,COPYX
- CP A,3 ;Illegal Block,done
- JP EQ,COPYX
- ; Now incr the block #
- LD HL,(BLKNO)
- INC HL
- LD (BLKNO),HL
- ;
- JR DFT2 ;Loop for more blocks
- ;
- ;
- ; OUTPUT STRINGS
-
- STR1: DEFB 'Source disk drive (A to D) ?',CR,LF
- DB 'Type <CR> if you make an error --- ',0
- CRLF: DB cr,lf,0
- STR1A: db 'Ensure you mount the disks before'
- db 'typing the : ',cr,lf
- DB 'Destination drive (A to D) ? --- ',0
- STR2: DEFB CR,LF,'Copy completed',CR,LF,0
- STR3: DEFB '***** Copy aborted *****',CR,LF,0
- STR4: DEFB 0DH,0AH,0AH
- DB ' 1 2 3 4'
- DEFB ' 5 6 7',CR,LF,0
- STR5: DEFB '01234567890123456789012345678901234567890'
- DEFB '123456789012345678901234567890123456',CR,LF,0
- STR6: DB 0DH,0AH,0AH
- DB ' 1',CR,LF,0
- STR7: DB '01234567890123456',CR,LF,0
- STR8: DB 0DH,0AH,0AH
- DB ' 1 2 3 4',CR,LF,0
- STR9: DB '01234567890123456789012345678901234567890',CR,LF,0
- ;
- DD.MSG: DB 0DH,0AH,'Double Density$'
- SD.MSG: DB 0DH,0AH,'Single Density$'
- DS.MSG: DB 0DH,0AH,'Double sided Double Density$'
- MSG1: DB ' disks mounted.$'
- DIFF.ERR.MSG: DB 0DH,0AH,'**** DISK LABEL ERROR ***$'
- NON.STANDARD.ERROR.MSG: DB 0DH,0AH,'**** DISKS ARE NON STANDARD ****$'
- ;
- ; SECTOR MAP
-
- SDMAP: DB 1,7,0DH,13H,19H,5,0BH,11H,17H,3,9,0FH,15H,2
- DB 8,0EH,14H,1AH,6,0CH,12H,18H,4,0AH,10H,16H
- ;DDMAP: DB 1,0CH,7,2,0DH,8,3,0EH,9,4,0FH,0AH,5,10H,0BH,6
- ;
- OLDSP: DEFS 2
- STACK: DEFS 64
- ACLUSTERS: DS 2 ;Clusters on DSK 1
- BCLUSTERS: DS 2 ;Clusters on DSK 2
- BLOCK.CAPACITY: DS 2 ;Blocks on the disk
- SIZE.FLAG: DS 1 ;D/D OR D/S ?
- SECTORS.PER.TRACK: DS 1
- DMA.INCR: DS 2
- SECTOR.MAP.ADDRESS: DS 2
- SOURCE: DS 1 ;SOURCE DRIVE #
- DEST: DS 1 ;DEST DRIVE #
-
- TRKNO: DEFS 1 ;TRACK NUMBER
- SECNO: DEFS 1 ;SECTOR NUMBER
- DMAPTR: DEFS 2 ;DMA POINTER
- BLKNO: DS 2
- FIRSTBLK: DS 2
- LASTBLK: DS 2
- ;
- ; THe buffer for D/D is assumed 45 K long
- TBUF: DEFS 26*128 ;TRACK BUFFER
-
- END 100H
-