home *** CD-ROM | disk | FTP | other *** search
- ; COPYFAST.ASM Version 3.5
- ; (See the DOC file for change history)
- ;
- ORG 0100H
- ;
- ;
- ; Equates
- ;
- FALSE EQU 0 ; define false
- TRUE EQU NOT FALSE; define true
- ;
- EXITCP EQU 0 ; warm start return to CP/M
- FCB EQU 5CH ; default FCB address
- ;
- CR EQU 0DH ; ASCII Carriage return
- LF EQU 0AH ; ASCII line feed
- CTRLC EQU 3 ; ASCII control-C
- ;
- ; User-modifiable switches
- ;
- SINGLE EQU FALSE ; TRUE for single drive copy program
- RSKEW EQU FALSE ; TRUE if read interleaving needed
- ; ; Note: change READTAB if TRUE
- DOCOMP EQU TRUE ; TRUE if byte-by-byte comparison
- ; ; desired on read-after-write check
- TRSKW EQU TRUE ; TRUE if track skewing is wanted
- ; ; on non-interleaved reads
- ; ; (RSKEW MUST be false)
- WRSWCH EQU FALSE ; TRUE if CP/M 2.2 block/deblock
- ; ; routines need various values in
- ; ; reg. C during writes. See WRTAB
- ;
- NUMERR EQU 4 ; number of error retries done
- ;
- BUFFNU EQU 0 ; the number of full track buffers
- ; that will fit in your system. This figure includes
- ; the space used by the read-back buffers, if used
- ; (minimum 2). If zero, the number of buffers will
- ; be automatically computed at execution.
- ;
- TSKEW EQU 6 ; Amount of track-to-track skew
- ; ; (if TRSKW is TRUE and RSKEW is FALSE)
- ; ; Should be less than SDLAST
- ;
- ; The next two values specify the copy range, and the program
- ; can be run in other ways by the parameter (first character
- ; of the first filename) given when COPYFAST is first invoked:
- ;
- ; All 0-(Lastrk-1) Entire disk
- ; Data Firstrk-(Lastrk-1) CP/M data area
- ; First Firstrk CP/M directory track
- ; Last (Lastrk-1) Last track on disk
- ; One 1 Track one, UCSD directory
- ; Pascal 1-(Lastrk-1) UCSD Pascal data area
- ; System 0-(Firstrk-1) CP/M bootstrap
- ; Zero 0 Track zero, UCSD bootstrap
- ; (Note: only complete tracks are copied)
- ; The default range, currently Firstrk to Lastrk-1, is given
- ; in the two values at TRKSRT.
- ;
- FIRSTRK EQU 2 ; the first data track copied.
- ; ; The bootstrap is assumed to be
- ; ; on tracks 0 to Firstrk-1
- LASTRK EQU 77 ; the last track copied plus one
- ;
- DIFFTRK EQU 0 ; difference between first source
- ; ; track and the first object track.
- ; ; (applies only when default range
- ; ; is used)
- ;
- SDLAST EQU 26 ; the number of sectors per track
- ; ; Also determines the lengths of
- ; ; WRTAB, READTAB, and WRITAB
- ;
- SECSIZ EQU 128 ; number of bytes per sector.
- ;
- WRCODE EQU 2 ; value passed to sector write rtn
- ; ; in reg. C if WRSWCH is FALSE
- IF TRSKW AND RSKEW
- TRSKW SET FALSE ; option is wrong
- ENDIF
- ;
- ; A set of dummy branch points to the CBIOS that are
- ; filled in by the VECTOR routine.
- ;
- START:
- JMP VECTOR ; go initialize the branches
- WBOOT:
- JMP $-$ ; not used
- CONST:
- JMP $-$
- CONIN:
- JMP $-$
- CONOUT:
- JMP $-$
- LIST:
- JMP $-$ ; not used
- PUNCH:
- JMP $-$ ; not used
- READER:
- JMP $-$ ; not used
- HOME:
- JMP $-$
- SELDIS:
- JMP $-$
- SETRAK:
- JMP $-$
- SETSCT:
- JMP $-$
- SETDMA:
- JMP $-$
- READ:
- JMP $-$
- WRITE:
- JMP $-$
- ;
- ; Useful constants placed here for finding easily
- ; These can be changed using DDT to alter some of
- ; the characteristics of the program to suit your
- ; taste.
- ;
- TRKSRT: ; default first and last+1 track numbers
- ; ; Can be changed at run time
- DB FIRSTRK
- DB LASTRK
- BUFFNMB: ; max. number of buffers
- DB BUFFNU
- SRCTRAK: ; source track - object track
- DB DIFFTRK
- ;
- ; This is the point where the program returns to repeat the
- ; copy. Everything is re-initialized.
- ;
- REPEAT:
- LXI SP,STKTOP ; re-initialize stack
- LXI D,SOURCE
- CALL PRINT ; ask for source drive
- SRCELU:
- CALL CONIN ; read response (upper case)
- CPI CTRLC
- JZ EXIT ; CTRL-C means abort
- ANI 5FH
- CPI 'A' ;41H
- JC SRCELU ; bad value - less than A
- CPI 'F' ;46H
- JZ SETSOU
- JC SETSOU
- JMP SRCELU ; bad value - greater than F
- SETSOU:
- STA SRCEME ; save the source drive
- IF SINGLE
- STA OBJMES
- ENDIF
- SUI 'A' ;41H
- STA SRCEDR ; convert value to CP/M number
- LDA SRCEME
- CALL CONOUT ; echo value to console
- IF NOT SINGLE
- LXI D,OBJECT ; prompt for destination disk
- CALL PRINT
- OBJLUP: ; read response
- CALL CONIN
- CPI CTRLC ; CTRL-C means abort
- JZ EXIT
- ANI 5FH ; convert to upper case
- CPI 'A' ;41H
- JC OBJLUP ; bad value - less than A
- CPI 'F' ;46H
- JZ SETOBJ
- JC SETOBJ
- JMP OBJLUP ; bad value - greater than F
- SETOBJ:
- LXI H,SRCEME ; Cannot have a one drive copy
- CMP M
- JZ OBJLUP
- STA OBJMES ; save the destination drive
- SUI 'A' ;41H
- STA OBJDRI ; convert value to CP/M number
- LDA OBJMES
- CALL CONOUT ; echo object drive
- LXI D,SIGNON
- CALL PRINT ; now give chance to change disks
- ; ; or give up
- AGIN:
- CALL CONIN ; read response from keyboard
- CPI CTRLC
- JZ EXIT ; ctrl-C means quit
- CPI CR
- JNZ AGIN ; CR means go. Ignore anything else
- ENDIF
- ;
- ; now go do it !
- ;
- LXI D,CRLF
- CALL PRINT ; now start actual copy
- CALL COPY
- LXI D,DONMSG
- CALL PRINT ; copy is now done, say so
- ;
- ; end of this copy
- ;
- EXIT:
- LXI SP,STKTOP ; re-initialize stack
- LDA SRCEDR ; first, select source drive
- MOV C,A
- CALL SELDSK
- CALL HOME ; home the disk in case
- IF NOT SINGLE
- LDA OBJDRI
- MOV C,A ; now, select destination drive
- CALL SELDSK
- CALL HOME ; and home that disk, in case
- ENDIF
- LXI D,REPMES ; ask if another copy is desired
- CALL PRINT
- CALL CONIN ; read response, upper case
- ANI 5FH
- CPI 'R' ; R means repeat
- JZ REPEAT
- CPI CR ; carriage return means back to CP/M
- JNZ EXIT
- MVI C,0 ; set default disk back to A
- CALL SELDSK
- JMP EXITCP ; and warmstart back to CP/M
- ;
- ; convert value in A reg. to ASCII hex and print it
- ;
- PRTHEX:
- PUSH PSW ; save for LSN
- RAR
- RAR ; shift MSN nibble to LSN
- RAR
- RAR
- CALL PRTNBL ; now print it
- POP PSW ; and then do LSN
- PRTNBL:
- ANI 0FH
- ADI '0' ;convert to ASCII value
- CPI '0'+10 ; over 9 ?
- JC SML
- ADI 7 ; convert 10 to A, etc.
- SML:
- MOV C,A ; move to C for BDOS call
- CALL CONOUT
- RET
- ;
- ;
- ; this is the main copy routine
- ;
- COPY:
- LDA SRCEDR ; first, select source drive
- MOV C,A
- CALL SELDSK
- CALL HOME ; home the disk first, in case
- ; ; the controller requires it.
- ; ; (this might be the first time
- ; ; the drive has been used)
- LDA TRKSRT
- CALL SETTRK ; now start with first track
- IF NOT SINGLE
- LDA OBJDRI
- MOV C,A ; now, select destination drive
- CALL SELDSK
- CALL HOME ; and home that disk, in case
- ENDIF
- ;
- ; return here to continue copy
- ;
- RDLOOP:
- LDA TRK ; note current track
- STA TRKSAV
- XRA A ; reset error counter
- STA CMPERR
- LXI D,TRKM ; print the current starting track
- CALL PRINT ; being copied
- LDA TRKSAV
- CALL PRTHEX
- TRYRDA:
- IF SINGLE
- LXI D,SIGNON ; now give operator chance to change disk
- ENDIF
- LDA SRCEDR ; select source drive
- ;
- ; read loop
- ;
- CALL STARTL ; start the copy loop (reading source)
- LOOP1:
- CALL READT ; read one track
- JZ LOOP4 ; if all tracks read, go check errors
- LDA ERR1
- ORA A ; not all done, but see if error already
- JNZ LOOP1 ; and go try another track
- ;
- ; now see if any errors in the previous operations
- ;
- LOOP4:
- LDA ERR1 ; now check if any errors
- ORA A
- JNZ RDSKIP ; jump if no errors at all
- MVI A,10H
- STA ERR1 ; reset error flag
- ;
- ; allow NUMERR errors before giving up
- ;
- LDA CMPERR ; check the retry counter
- INR A
- STA CMPERR
- CPI NUMERR ; normally ten retries max
- JNZ LOOP1 ; WAS TRYRDA
- LXI D,MESGC ; if maximum error count,
- CALL PRINT ; print message
- XRA A
- STA CMPERR ; full track error, reset error counter
- CALL ENDLUP
- JNZ LOOP1 ; now bump up track and see if done
- ;
- ; write loop
- ;
- RDSKIP:
- XRA A ; reset error counter
- STA CMPERR
- TRYAGA:
- IF SINGLE
- LXI D,OBJMSG ; give chance to put in object disk
- ENDIF
- LDA OBJDRI ; now select destination disk
- CALL STARTL ; start the write loop
- LOOP2:
- CALL WRITET ; write one track (and readback check)
- JZ LOOP3 ; if all tracks written, go check errors
- LDA ERR1
- ORA A ; not all done, but see if error already
- JNZ LOOP2
- ;
- ; now see if any errors in the previous operations
- ;
- LOOP3:
- LDA ERR1 ; now check if any errors
- ORA A
- JNZ SKIP ; jump if no errors at all
- ;
- ; allow NUMERR errors before giving up
- ;
- LDA CMPERR ; check the retry counter
- INR A
- STA CMPERR
- CPI NUMERR ; normally ten retries max
- JNZ TRYAGA
- LXI D,MESGC ; if maximum error count,
- CALL PRINT ; print message
- LDA BUFFNMB
- MOV H,A
- LDA TRK ; and set next track
- INR A ; past track in error
- SUB H
- STA TRKSAV
- ;
- ; copied all tracks correctly (or NUMERR errors)
- ;
- SKIP:
- LDA BUFFNMB ; get number of buffers
- MOV H,A
- LDA TRKSAV ; bump up track counter
- ADD H
- STA TRK
- LXI H,TRKSRT+1 ; see if copy operation is done
- CMP M
- RNC
- JNZ RDLOOP ; go back and do more
- RET
- ;
- ; This routine selects the disk, and initializes the buffer
- ; address, buffer counter, and track counter,and seeks to the
- ; right track.
- ;
- STARTL:
- IF SINGLE
- CALL HOME ; Home the disk for a deblocking CBIOS
- ; ; to get a chance to flush the buffer
- CALL PRINT ; now give chance to change disks
- ; ; or give up
- AGIN:
- CALL CONIN ; read response from keyboard
- CPI CTRLC
- JZ EXIT ; CTRL-C means quit
- CPI CR
- JNZ AGIN ; CR means go. Ignore anything else
- ENDIF
- IF NOT SINGLE
- MOV C,A ; select the disk first
- CALL SELDSK
- ENDIF
- IF TRSKW
- XRA A ; zero out track sector skew
- STA TSECT
- STA TBUFF ; zero out coresponding buffer addr
- STA TBUFF+1
- ENDIF
- LXI H,BUF0 ; load address of first buffer
- SHLD BUF0SA
- MVI A,10H ; reset error flag
- STA ERR1
- LDA BUFFNMB ; load number of buffers
- STA BUFFCO
- LDA TRKSAV ; load first track copied
- ;
- ; set the track to be used, and add offset if source
- ; drive. Save track number for error routine.
- ;
- SETTRK:
- STA TRK ; save current track
- IF (NOT SINGLE)
- LDA CURRDI ; check drive
- MOV C,A
- LDA SRCEDR ; is it source
- CMP C
- LDA TRK ; if object, skip
- JNZ SETTR0
- MOV C,A ; now get difference
- LDA SRCTRAK
- ADD C ; and do correction
- SETTR0:
- ENDIF
- MOV C,A ; now go set track
- JMP SETRAK
- ;
- ; set the DMA address (in HL)
- ;
- DMASET:
- MOV C,L ; move HL to BC
- MOV B,H
- PUSH B ; save result and call CBIOS
- CALL SETDMA
- POP B
- RET
- ;
- ; these are the disk error handling routines
- ;
- FAILR:
- LXI D,MESGD ; read error message
- JMP DIE
- FAILW:
- LXI D,MESGE ; write error message
- DIE:
- CALL PRINT ; print the main error message
- LXI D,ERM
- CALL PRINT
- LDA TRK ; print the track number
- CALL PRTHEX
- LXI D,MESGB ; print sector message
- CALL PRINT
- LDA SECTOR ; and print sector
- CALL PRTHEX
- LXI D,DRIVE ; print drive message
- CALL PRINT
- LDA CURRDI
- ADI 'A' ; convert drive number to ASCII
- MOV C,A
- CALL CONOUT ; and finally print drive
- XRA A
- STA ERR1 ; note the error so this track is retried
- CALL CONST
- ORA A ; see if any console input present
- JZ ENDLUP
- CALL CONIN ; yes, see if aborting
- CPI CTRLC
- JZ EXIT ; die if CTRL-C was hit
- JMP ENDLUP
- ;
- ; read the full track now, no interleaving
- ;
- READT:
- CALL CONST
- ORA A ; see if any console input present
- JZ READT0
- CALL CONIN ; yes, see if aborting
- CPI CTRLC
- JZ EXIT ; die if CTRL-C was hit
- READT0:
- IF (NOT RSKEW) AND (NOT TRSKW)
- LHLD BUF0SA ; first, get beginning of buffer
- SHLD DMAAD
- ENDIF
- IF TRSKW
- LHLD BUF0SA ; first, get beginning of buffer
- XCHG
- LHLD TBUFF ; and correct for skew
- DAD D
- SHLD DMAAD
- LDA TSECT ; initialize first sector
- MOV C,A
- ENDIF
- IF (NOT TRSKW)
- MVI C,0 ; initialize first sector
- ENDIF
- MVI B,SDLAST ; initialize sector count
- RT3:
- IF TRSKW
- MOV A,C ; check for skew too big
- CPI SDLAST
- JC RT4 ; jump if sector within range
- XRA A
- MOV C,A ; out of range, back to sector 1
- LHLD BUF0SA
- SHLD DMAAD
- RT4:
- ENDIF
- IF RSKEW
- INR C ; increment sector counter
- PUSH B
- LXI H,READTAB-1 ; find the interleaved sector number
- MVI B,0
- DAD B ; using the READTAB
- MOV C,M
- CALL SETSEC ; and set the sector
- MVI H,0
- DCR C ; now compute the buffer location
- MOV L,C
- ;
- DAD H ; corresponding to that sector
- DAD H
- DAD H ; by multiplying by 128
- DAD H
- DAD H ; The number of DAD H instructions
- DAD H ; MUST correspond to the buffer size
- DAD H ; i.e. 7 DADs means 128 byte (2^7)
- ;
- XCHG
- LHLD BUF0SA ; and then adding to the buffer start
- DAD D
- CALL DMASET ; set the DMA and do the read
- ENDIF
- IF (NOT RSKEW)
- INR C ; increment sector counter
- PUSH B
- CALL SETSEC ; set the sector
- LHLD DMAAD
- CALL DMASET ; set the DMA
- LXI H,SECSIZ
- DAD B ; bump up the DMA for next time
- SHLD DMAAD
- ENDIF
- CALL READ ; now read one sector
- RAR
- CC FAILR ; if returned 01, read error
- POP B
- DCR B ; see if all sectors read
- JNZ RT3
- IF TRSKW
- LHLD TBUFF ; bump up skewed buffer
- LXI D,SECSIZ*TSKEW
- DAD D ; add the skew
- SHLD TBUFF
- LDA TSECT ; now bump starting sector
- ADI TSKEW
- STA TSECT ; and put it back
- SBI SDLAST
- JC ENDLUP ; jump if sector within range
- STA TSECT
- LHLD TBUFF
- LXI D,-SDLAST*SECSIZ; correct sector start and
- DAD D
- SHLD TBUFF ; buffer skew address
- ENDIF
- JMP ENDLUP ; return with complete track read
- ;
- ; Write the full track, with interleaving, and then check it
- ; by reading it all back in.
- ;
- WRITET:
- CALL CONST
- ORA A ; see if any console input present
- JZ WRITE0
- CALL CONIN ; yes, see if aborting
- CPI CTRLC
- JZ EXIT ; die if CTRL-C was hit
- WRITE0:
- LHLD BUF0SA ; first, get the beginning of buffer
- SHLD DMAAD
- MVI C,0
- MVI B,SDLAST ; initialize sector counter
- WT3:
- PUSH B
- LXI H,WRITAB ; find the interleaved sector number
- MVI B,0
- DAD B ; using the WRITAB
- MOV C,M
- CALL SETSEC ; and set the sector
- MVI H,0
- DCR C ; now compute the buffer location
- MOV L,C
- ;
- DAD H ; corresponding to that sector
- DAD H
- DAD H ; by multiplying by 128
- DAD H
- DAD H ; NOTE: see comments in RT3 for
- DAD H ; changing this code for other
- DAD H ; than 128 byte sectors
- ;
- XCHG
- LHLD DMAAD ; and then adding to the buffer start
- DAD D
- CALL DMASET ; set the DMA and do the write
- IF NOT WRSWCH
- MVI C,WRCODE ; value for CP/M 2.2 routine
- ENDIF
- IF WRSWCH
- POP B ; get sector number
- PUSH B
- LXI H,WRTAB-1 ; find the C reg. value for this
- MVI B,0
- DAD B ; sector using the WRTAB
- MOV C,M
- ENDIF
- CALL WRITE
- RAR ; if 01 returned, write error
- CC FAILW
- POP B
- INR C ; increment sector count
- DCR B
- JNZ WT3 ; and loop back if not done
- IF DOCOMP AND (NOT RSKEW)
- LXI H,BUF1 ; first, get beginning of buffer
- SHLD DMAAD
- ENDIF
- MVI C,0
- MVI B,SDLAST ; reinitialize sector counts for read
- WT4:
- INR C ; bump up sector counter
- PUSH B
- IF RSKEW
- LXI H,READTAB-1 ; find the interleaved sector number
- MVI B,0
- DAD B ; using the READTAB
- MOV C,M
- CALL SETSEC ; and set the sector
- ENDIF
- IF RSKEW AND DOCOMP
- MVI H,0
- DCR C ; now compute the buffer location
- MOV L,C
- DAD H ; corresponding to that sector
- DAD H
- DAD H ; by multiplying by 128
- DAD H
- DAD H ; (2 ^ 7 = 128)
- DAD H
- DAD H
- XCHG
- LXI H,BUF1 ; and then adding to the buffer start
- DAD D
- CALL DMASET ; now set the read buffer
- ENDIF
- IF (NOT RSKEW) AND DOCOMP
- CALL SETSEC ; set the sector
- LHLD DMAAD
- CALL DMASET ; set the DMA
- LXI H,SECSIZ
- DAD B ; bump up the DMA for next time
- SHLD DMAAD
- ENDIF
- IF RSKEW AND (NOT DOCOMP)
- LXI H,BUF1 ; load the buffer address
- CALL DMASET ; and set the read buffer
- ENDIF
- IF (NOT RSKEW) AND (NOT DOCOMP)
- CALL SETSEC ; now set the sector
- LXI H,BUF1
- CALL DMASET ; and set the read buffer
- ENDIF
- CALL READ
- RAR ; was bit 0 set by disk error?
- CC FAILR
- POP B ; no error, see if all sectors read
- DCR B
- JNZ WT4 ; if not all done, go back
- IF DOCOMP
- LXI B,SECSIZ*SDLAST ; now, compare the track read in
- LHLD BUF0SA
- LXI D,BUF1
- CMPLP: LDAX D ; get read data
- CMP M
- JNZ CERR ; and if not what was written, error
- INX H
- INX D ; bump counters
- DCX B
- MOV A,C ; and count BC down to zero
- ORA B
- JNZ CMPLP ; if all done, return
- JMP ENDLUP
- ;
- ; print read verify compare error
- ;
- CERR: PUSH H ; save the goodies
- PUSH D
- PUSH B
- LXI D,MESGA ; start the error message
- CALL PRINT
- LDA TRK ; print the track number
- CALL PRTHEX
- LXI D,MESGB ; print more
- CALL PRINT
- POP H ; pop the down counter
- DCX H
- DAD H ; multiply by 2 to get sectors left
- MVI A,SDLAST
- SUB H ; subtract from total number of sectors
- CALL PRTHEX ; to get sector number, and print it
- LXI D,MEM
- CALL PRINT ; print second line
- POP H
- MOV A,M ; get byte read
- STA DATA1 ; and save it
- PUSH H
- MOV A,H ; print high order byte of address
- CALL PRTHEX
- POP H
- MOV A,L ; print low order byte of address
- CALL PRTHEX
- MVI C,','
- CALL CONOUT ; comma
- POP H
- MOV A,M ; get byte written
- STA DATA2 ; and save it
- PUSH H
- MOV A,H ; print high order byte of address
- CALL PRTHEX
- POP H
- MOV A,L ; print low order byte of address
- CALL PRTHEX
- LXI D,DATAM ; print data header
- CALL PRINT
- LDA DATA1 ; print byte read
- CALL PRTHEX
- MVI C,',' ; comma
- CALL CONOUT
- LDA DATA2 ; print byte written
- CALL PRTHEX
- XRA A
- STA ERR1 ; note the error so this track is retried
- ENDIF
- ;
- ; This routine is used to check if another track is to be
- ; read/written: it increments buffer address and track
- ; counter, and decrements the buffer counter. Then, it
- ; terminates the loop if all buffers are full or the last
- ; track has been processed (Z flag set).
- ;
- ENDLUP:
- LDA ERR1 ; now check if any errors
- ORA A ; and return if so
- RZ
- LDA TRK ; increment track
- INR A
- LXI H,TRKSRT+1 ; check if last track
- CMP M
- RZ ; return if last track
- CALL SETTRK
- LXI H,BUFFCO ; decrement buffer counter
- DCR M
- RZ ; return if all buffers full/empty
- LXI D,SECSIZ*SDLAST
- LHLD BUF0SA ; increment buffer address
- DAD D
- SHLD BUF0SA
- ORI 255 ; non-zero to indicate more
- RET
- ;
- ; this routine writes messages to the console. Message
- ; address is in DE, and terminates on a $. The BDOS call is
- ; not used here because BDOS may be destroyed by the track
- ; buffers
- ;
- PRINT:
- LDAX D ; get the character
- CPI '$' ;24H
- RZ ; quit if $
- PUSH D
- MOV C,A ; send it to the console
- CALL CONOUT
- POP D ; go check next character
- INX D
- JMP PRINT
- ;
- ; set the next sector to be used, and save that
- ; number for the error routine, in case
- ;
- SETSEC:
- MOV A,C ; save the sector number
- STA SECTOR
- PUSH B ; save regs, in case
- CALL SETSCT ; now go set the sector
- POP B
- RET
- ;
- ; set the disk to be used, and save that
- ; for the error routine, in case
- ;
- SELDSK:
- MOV A,C ; save the disk number
- STA CURRDI
- JMP SELDIS ; now select the disk
- ;
- ; all messages here for convenience in disassembling
- ;
- DONMSG:
- DB CR,LF,'*** COPY COMPLETE ***$'
- DRIVE:
- DB ', DRIVE $'
- ERM:
- DB CR,LF,'+ ERROR ON TRACK (HEX)$'
- MESGB:
- DB ' SECTOR (HEX)$'
- MESGC:
- DB CR,LF,'++PERMANENT $'
- MESGD:
- DB CR,LF,'+ READ ERROR $'
- MESGE:
- DB CR,LF,'+ WRITE ERROR $'
- SIGNON:
- DB CR,LF,'SOURCE ON '
- SRCEME:
- DB 0 ; will be filled in later
- IF NOT SINGLE
- DB ': OBJECT ON '
- OBJMES:
- DB 0 ; will be filled in later
- DB ':'
- ENDIF
- SINOFF:
- DB CR,LF,'TYPE <RET> TO CONTINUE, OR CONTROL-C TO EXIT: $'
- IF SINGLE
- OBJMSG:
- DB CR,LF,'OBJECT ON '
- OBJMES:
- DB 0 ; will be filled in later
- DB ':'
- DB CR,LF,'TYPE <RET> TO CONTINUE, OR CONTROL-C TO EXIT: $'
- ENDIF
- REPMES:
- DB CR,LF,'TYPE <RET> OR "R", TO REPEAT COPY: $'
- CRLF:
- DB CR,LF,'$'
- SOURCE:
- DB CR,LF,'SOURCE DRIVE (A THRU F): $'
- IF NOT SINGLE
- OBJECT:
- DB CR,LF,'OBJECT DRIVE (A THRU F): $'
- ENDIF
- TRKM:
- DB CR,LF,'COPYING TRACK $'
- ;
- IF DOCOMP
- MESGA:
- DB CR,LF,'+ MEMORY COMPARE ERROR ON TRACK (HEX)$'
- MEM:
- DB CR,LF,'+ MEMORY ADDRESS $'
- DATAM:
- DB ' (OBJ,SRC) DATA $'
- ENDIF
- ;
- ; This is the sector interleave table. If you want the
- ; program to work, all sector numbers must be here somewhere.
- ;
- WRITAB:
- ;
- ; Interleave table for very fast controllers
- ;
- DB 25,26,1,2,3,4,5,6,7,8,9,10,11,12
- DB 13,14,15,16,17,18,19,20,21,22,23,24
- ;
- ;
- IF WRSWCH
- ;
- ; This is the write switch table. The values in this table
- ; are passed to the sector write routine of CP/M 2.2 in
- ; reg. C when each write occurs. This table is modified if
- ; and only if some particular pattern is needed for your
- ; blocking routine to work as fast or as well as possible.
- ; Refer to the CP/M 2.2 Alteration Guide for more details.
- ;
- WRTAB:
- DB 2,2,2,2,2,2,2,2,2,2,2,2,2
- DB 2,2,2,2,2,2,2,2,2,2,2,2,2
- ENDIF
- ;
- IF RSKEW
- ;
- ; This is the read skew table, if needed. The same general
- ; considerations as the write skew table apply here also, but
- ; the table should start with sector 1. Both the read and the
- ; read-after write use this table. As you can see, the write
- ; and read interleaving doesn't have to be the same.
- ;
- READTAB:
- DB 1,3,5,7,9,11,13,15,17,19,21,23,25
- DB 2,4,6,8,10,12,14,16,18,20,22,24,26
- ENDIF
- ;
- ; This is the initialization code, and occupies the lowest area
- ; of the stack, and may be clobbered by the stack during operation,
- ; but it is used only once. (The stack is about 32 bytes long)
- ;
- VECTOR:
- LHLD 1 ; get bottom of CBIOS
- MOV B,H
- LXI D,SECSIZ*SDLAST ; get size of buffers
- LXI H,BUF0 ; start checking where buffer starts
- VECT0:
- DAD D ; add buffer size to buffer addr
- MOV A,H
- CMP B ; check hi order byte if high
- JZ VECT1 ; or equal
- JNC VECT1
- LDA BUFTMP ; buffer fits, add one to count
- INR A
- STA BUFTMP ; and store
- JMP VECT0
- ;
- ; the stack
- ;
- DS 8
- STKTOP:
- DB 0
- ;
- ; variables
- ;
- BUF0SA: ; buffer address
- DB 0,0
- TRKSAV: ; track save area during read and write
- DB 0
- BUFFCO: ; buffer counter
- DB 0
- CMPERR: ; number of disk errors
- DB 0
- TRK: ; current track
- DB 0
- SRCEDR: ; source drive
- IF NOT SINGLE
- DB 0
- ENDIF
- OBJDRI: ; destination drive
- DB 0
- CURRDI: ; drive for current operation
- DB 0
- DMAAD: ; DMA address for current operation
- DB 0,0
- ERR1: ; error flag (0 = error)
- DB 0
- SECTOR: ; sector number for current operation
- DB 0
- ;
- IF TRSKW
- TSECT:
- DB 0 ; skewed sector start for track
- TBUFF:
- DB 0,0 ; skewed buffer address
- ENDIF
- ;
- ; the track buffers. BUFEND must not overlay the BIOS !
- ;
- ; BUF1 is where the read-after-write is performed
- ;
- IF DOCOMP
- DATA1:
- DS 1 ; used in compare
- DATA2:
- DS 1
- BUF1:
- DS SECSIZ*SDLAST ; space for a full track read
- ENDIF
- ;
- IF NOT DOCOMP
- BUF1:
- DS SECSIZ ; just one sector for CRC only
- ENDIF
- ;
- ; BUF0 is where all input tracks are read
- ; Tho space for only one track is allocated here,
- ; the program will use BUFFNU track buffers, or
- ; up to the CBIOS, whichever is smaller
- ;
- BUF0: DS SECSIZ*SDLAST
- ;
- ORG BUF1
- ;
- ; This is one-time code to initialize the branch table to
- ; the CBIOS vectors. Only those vectors used are initialized.
- ; Placed here so that it wont get clobbered by the stack
- ;
- VECT1:
- LHLD 1 ; get warm boot address
- SPHL ; and save it in SP for DAD
- LXI H,3
- DAD SP
- SHLD CONST+1
- ;
- LXI H,6
- DAD SP
- SHLD CONIN+1
- ;
- LXI H,9
- DAD SP
- SHLD CONOUT+1
- ;
- LXI H,15H
- DAD SP
- SHLD HOME+1
- ;
- LXI H,18H
- DAD SP
- SHLD SELDIS+1
- ;
- LXI H,1BH
- DAD SP
- SHLD SETRAK+1
- ;
- LXI H,1EH
- DAD SP
- SHLD SETSCT+1
- ;
- LXI H,21H
- DAD SP
- SHLD SETDMA+1
- ;
- LXI H,24H
- DAD SP
- SHLD READ+1
- ;
- LXI H,27H
- DAD SP
- SHLD WRITE+1
- ;
- ; Now check what kind of copy is wanted
- ;
- LXI SP,STKTOP ; initial stack
- LXI D,INIT
- CALL PRINT ; start program
- LHLD TRKSRT
- LDA FCB+1 ; get character of parameter
- ANI 5FH
- CPI 0 ; check for default
- JZ COPYDEF
- MOV B,A
- XRA A ; no track shift
- STA SRCTRAK
- MOV A,B
- CPI 'A' ; check for All
- JZ COPYALL
- CPI 'D' ; check for Data
- JZ COPYDAT
- CPI 'F' ; check for First
- JZ COPYFIR
- CPI 'L' ; check for Last
- JZ COPYLAS
- CPI 'O' ; check for One
- JZ COPYONE
- CPI 'P' ; check for Pascal
- JZ COPYPAS
- CPI 'S' ; check for System
- JZ COPYSYS
- CPI 'Z' ; check for Zero
- JZ COPYZER
- LXI D,CALLERR ; got a bad value
- CALL PRINT
- JMP EXITCP
- COPYALL:
- MVI H,LASTRK ; All
- MVI L,0
- JMP COPYDEF
- COPYDAT:
- MVI H,LASTRK ; Data
- MVI L,FIRSTRK
- JMP COPYDEF
- COPYFIR:
- MVI H,FIRSTRK+1 ; First
- MVI L,FIRSTRK
- JMP COPYDEF
- COPYLAS:
- MVI H,LASTRK ; Last
- MVI L,LASTRK-1
- JMP COPYDEF
- COPYONE:
- MVI H,2 ; One
- MVI L,1
- JMP COPYDEF
- COPYPAS:
- MVI H,LASTRK ; Pascal
- MVI L,1
- JMP COPYDEF
- COPYSYS:
- MVI H,FIRSTRK ; System
- MVI L,0
- JMP COPYDEF
- COPYZER:
- MVI H,1 ; Zero
- MVI L,0
- ;
- ; The one time finish - up routine
- ;
- COPYDEF:
- SHLD TRKSRT
- LXI D,BGMES1 ; Now print message giving copy range
- CALL PRINT
- LDA TRKSRT
- CALL PRTHEX ; print first track
- LXI D,BGMES2
- CALL PRINT
- LDA TRKSRT+1 ; print last track
- DCR A
- CALL PRTHEX
- LDA BUFFNMB ; load desired buffer number
- ORA A
- JZ VECT3 ; if no autosize, put in
- IF DOCOMP
- DCR A ; subtract one for compare buffer
- STA BUFFNMB
- ENDIF
- LXI H,BUFTMP
- CMP M ; compare against number found
- JZ VECT2
- JC VECT2 ; branch if smaller
- LXI D,BUFERR
- CALL PRINT ; print out error msg
- LDA BUFTMP
- CALL PRTHEX ; print out buffer number
- VECT3:
- LDA BUFTMP
- STA BUFFNMB ; put in smaller buffer number
- VECT2:
- LXI H,REPEAT ; go to mainline code now
- SHLD START+1
- PCHL
- ;
- BUFTMP: DB 0 ; temporary storage for buffer counter
- INIT:
- DB CR,LF,'FAST DISKETTE COPY PROGRAM, VER. 3.5$'
- BUFERR:
- DB CR,LF,'CP/M IS TOO SMALL - BUFFER SPACE REDUCED: $'
- CALLERR:
- DB CR,LF,'INVALID PARAMETER .. VALID COPYFAST PARAMETERS ARE'
- DB CR,LF,'ALL, DATA, FIRST, LAST, ONE, PASCAL, SYSTEM, ZERO$'
- BGMES1:
- DB CR,LF,'COPYING FROM TRACK $'
- BGMES2:
- DB ' TO TRACK $'
- ;
- ;
- END
-