home *** CD-ROM | disk | FTP | other *** search
- ;
- ; COPYFAST October 1980 version
- ;
- ; Written by Chuck Weingart, after the
- ; public domain Tarbell disk copy program
- ; (does not require a Tarbell controller)
- ;
- ; This program will copy the data area of one CP/M disk to
- ; another (thats tracks 2 - 76), as fast as possible. All data
- ; written is read back to verify that the write was successful,
- ; and multiple tracks are copied in one pass, for speed. The
- ; version as supplied assumes that the controller CRC checking is
- ; sufficient for verification, but an assembly option allows
- ; complete byte-by-byte comparison on the read back.
- ;
- ; The program as supplied copies 12 tracks per pass, and must run
- ; in a 42K or greater version of CP/M. The number of track
- ; buffers, and hence the minimum size, can be changed to suit
- ; your system. If re-assembled, it can copy four tracks at a pass
- ; in a minimum (16K) system, and 18 tracks at a pass in a max-
- ; imum system (64K). Only CP/M standard CBIOS calls are
- ; used to access the disk. No BDOS calls are used, so the BDOS
- ; and CCP can be overlaid by the track buffers. No other CP/M
- ; functions are assumed. N* CP/M or UCSD Pascal users should be
- ; able to modify this program easily to run on their systems.
- ;
- ; COPYFAST will allow a disk to be copied on a one-drive system,
- ; as an assembly option. A version with 18 buffers (64K) will
- ; require only 5 complete swaps.
- ;
- ; To invoke, just type: COPYFAST The program will then request
- ; the source and destination disks, (drives A - F) and give you a
- ; chance to put in the correct disks in the drives before
- ; continuing (or quit by entering CTRL-C). When done, the program
- ; will ask if another pair of disks is to be copied, and the
- ; process repeated.
- ;
- ; COPYFAST runs on an 8080 or similar cpu, CP/M 1.3, 1.4 or 2.2,
- ; or Cromemco (any) disk operating systems as supplied, and does
- ; not use any particular type of controller or disk hardware,
- ; other than the "standard" 77 track, 26 sector-per-track disk.
- ; The latter two numbers can be easily changed in the source.
- ;
- ; The program currently assumes that the disk controller can read
- ; the disk in one revolution, but requires two revolutions to
- ; write. This means that an entire track can be written and
- ; checked in three revolutions. One alternate interleave table
- ; is included in the source if this is not possible with your
- ; hardware, and any sector interleave can be used by changing the
- ; table. An assembly option is available to allow interleaved
- ; reads, if your disk controller cannot keep up with the program.
- ;
- ; This source can be assembled with the CP/M ASM or MAC.
- ;
- ; This program has been run unaltered on a Micromation Doubler
- ; disk controller with Shugart drives, a Tarbell single density
- ; controller board, and a Cromemco 4FDC board (the latter two
- ; use a WD 1771 chip) with Persci drives, and the worst copy
- ; time was 122 seconds. Faster hardware means faster copies.
- ;
- ; The only bad feedback I have gotten about this program so
- ; far was a case where it didn't work on a CP/M 2.2 system
- ; using 256 byte sectors. This turned out to be faulty logic in
- ; the sample deblocking routine Digital Research is supplying!
- ;
- ORG 0100H
- ;
- ; **************
- ;
- ; Equates
- ;
- FALSE EQU 0
- TRUE EQU NOT FALSE
- DUMYAD EQU 0
- EXITCP EQU 0 ; warm start return to CP/M
- CR EQU 13
- LF EQU 10
- CTRLC EQU 3
- ;
- ; **************
- ;
- SINGLE EQU FALSE ; TRUE for single-drive copy program
- RSKEW EQU FALSE ; TRUE if read interleaving needed
- DOCOMP EQU FALSE ; TRUE if byte-by-byte comparison
- ; ; desired on read-after-write check
- NUMERR EQU 10 ; number of error retries done
- ;
- ; **************
- ;
- BUFFNU EQU 12-(DOCOMP AND 1) ; the number of full track buffers
- ; that will fit in your system. With the current specification
- ; of 26 sectors per track, the program will require at least
- ; 39K for buffers alone, an so should run in a 42K system minimum.
- ; (12 * 128 * 26 = 39936. plus 3K for CBIOS and program)
- FIRSTRK EQU 2 ; the first track copied
- ; ; Note: UCSD Pascal users should
- ; ; begin copying at track 1
- LASTRK EQU 77 ; the last track copied plus one
- SDLAST EQU 26 ; the number of 128 byte sectors per track
- ;
- ; **************
- ; 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 DUMYAD ; not used
- CONST:
- JMP DUMYAD ; not used
- CONIN:
- JMP DUMYAD
- CONOUT:
- JMP DUMYAD
- LIST:
- JMP DUMYAD ; not used
- PUNCH:
- JMP DUMYAD ; not used
- READER:
- JMP DUMYAD ; not used
- HOME:
- JMP DUMYAD
- SELDIS:
- JMP DUMYAD
- SETTRK:
- JMP DUMYAD
- SETSCT:
- JMP DUMYAD
- SETDMA:
- JMP DUMYAD
- READ:
- JMP DUMYAD
- WRITE:
- JMP DUMYAD
- ;
- ; **************
- ; initialize and put in copy limits
- ;
- BUFMSR:
- LXI SP,STKTOP
- MVI L,FIRSTRK ; first track copied
- MVI H,LASTRK ; last track + 1 copied
- SHLD TRKSRT
- ;
- ; **************
- ; 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,INIT
- CALL PRINT ; start prompt sequence here
- LXI D,SOURCE
- CALL PRINT ; ask for source drive
- SRCELU:
- CALL CONIN ; read response (upper case)
- CPI CTRLC
- JZ EXITCP ; 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
- IF NOT SINGLE
- LXI D,CRLF
- CALL PRINT
- LXI D,OBJECT ; prompt for destination disk
- CALL PRINT
- OBJLUP: ; read response
- CALL CONIN
- CPI CTRLC ; CTRL-C means abort
- JZ EXITCP
- 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
- LXI D,SIGNON
- CALL PRINT ; now give chance to change disks
- ; ; or give up
- AGIN:
- CALL CONIN ; read response from keyboard
- CPI CTRLC
- JZ EXITCP ; 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 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
- STA TRK ; start with first track
- MOV C,A
- CALL SETTRK ; move to that 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
- TRYAGA:
- LXI D,TRKM ; print the current starting track
- CALL PRINT ; being copied
- LDA TRKSAV
- CALL PRTHEX
- 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
- JNZ LOOP1 ; if not all tracks read, loop back
- LDA ERR1
- ORA A
- JZ LOOP1 ; if any read errors, dont bother writing
- ;
- ; write loop
- ;
- 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 TRK ; and set next track
- INR A ; past track in error
- SUI BUFFNU
- STA TRKSAV
- ;
- ; copied all tracks correctly (or NUMERR errors)
- ;
- SKIP:
- LDA TRKSAV ; bump up track counter
- ADI BUFFNU
- 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
- PUSH PSW
- CALL PRINT ; now give chance to change disks
- ; ; or give up
- AGIN:
- CALL CONIN ; read response from keyboard
- CPI CTRLC
- JZ EXITCP ; ctrl-C means quit
- CPI CR
- JNZ AGIN ; CR means go. Ignore anything else
- POP PSW
- ENDIF
- MOV C,A ; select the disk first
- CALL SELDSK
- LXI H,BUF0 ; load address of first buffer
- SHLD BUF0SA
- MVI A,10H ; reset error flag
- STA ERR1
- MVI A,BUFFNU ; load number of buffers
- STA BUFFCO
- LDA TRKSAV ; load first track copied
- STA TRK
- MOV C,A
- JMP SETTRK ; and set the track
- ;
- ; **************
- ; 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
- JMP ENDLUP
- ;
- ; **************
- ; read the full track now, no interleaving
- ;
- READT:
- MVI A,10H ; reset error flag so all tracks get read
- STA ERR1 ; before trying to write
- IF (NOT RSKEW)
- LHLD BUF0SA ; first, get beginning of buffer
- SHLD DMAAD
- ENDIF
- MVI C,0
- MVI B,SDLAST ; initialize sector count
- RT3:
- INR C ; increment sector counter
- PUSH B
- IF RSKEW
- LXI H,READTAB ; 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
- DAD H
- DAD H
- 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)
- CALL SETSEC ; set the sector
- LHLD DMAAD
- CALL DMASET ; set the DMA
- LXI H,128
- 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
- JMP ENDLUP ; return with complete track read
- ;
- ; **************
- ; write the full track, with interleaving, and then
- ; check it by reading it all back in
- ;
- WRITET:
- 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
- DAD H
- DAD H
- XCHG
- LHLD DMAAD ; and then adding to the buffer start
- DAD D
- CALL DMASET ; set the DMA and do the write
- 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 ; 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
- 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,128
- 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,128*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
- STA TRK
- MOV C,A ; move to the next track
- CALL SETTRK
- LXI H,BUFFCO ; decrement buffer counter
- DCR M
- RZ ; return if all buffers full/empty
- LXI D,128*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
- CALL SELDIS ; now select the disk
- RET
- ;
- ; **************
- ; all messages here for convenience in disassembling
- ;
- DONMSG:
- DB CR,LF,CR,LF,'******** '
- DB ' COPY COMPLETE ********$'
- DRIVE:
- DB ' DRIVE $'
- ERM:
- DB CR,LF,'+ ERROR ON TRACK $'
- MESGB:
- DB '(HEX) SECTOR (HEX)$'
- MESGC:
- DB CR,LF,'********** PERMANENT '
- DB ' **********$'
- 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 CR,LF,'+OBJECT ON '
- OBJMES:
- DB 0 ; will be filled in later
- ENDIF
- SINOFF:
- DB CR,LF,'+TYPE <RET>$'
- IF SINGLE
- OBJMSG:
- DB CR,LF,'+OBJECT ON '
- OBJMES:
- DB 0 ; will be filled in later
- DB CR,LF,'+TYPE <RET>$'
- ENDIF
- REPMES:
- DB CR,LF,'TYPE RETURN (OR R TO REPEAT)$'
- CRLF:
- DB CR,LF,'$'
- INIT:
- DB CR,LF,'COPY PROGRAM FOR '
- DB 'CP/M$'
- SOURCE:
- DB CR,LF,'SOURCE DRIVE? A,B,C,D,E,F$'
- IF NOT SINGLE
- OBJECT:
- DB CR,LF,'OBJECT DRIVE? A,B,C,D,E,F$'
- ENDIF
- TRKM:
- DB CR,LF,'COPYING TRACK $'
- ;
- IF DOCOMP
- MESGA:
- DB CR,LF,'+ MEMORY COMPARE ERROR ON TRACK $'
- MEM:
- DB CR,LF,'MEMORY ADDRESS $'
- DATAM:
- DB ' DATA $'
- ENDIF
- ;
- ; **************
- ;
- ; This is the sector interleave table. If you want the
- ; program to work, all sector numbers must be here
- ; somewhere. The sectors are listed in the order they
- ; will be written to disk.
- ; NOTE: the peculiar ordering is due to the fact that
- ; some disk controllers cannot switch between writing
- ; sector 26 and reading sector 1 in time - so the table
- ; begins with 25, proceed up every other sector, and
- ; ends with number 24. While the head is passing sectors
- ; 25 and 26, the program will be switching to read back
- ; the entire track. There is generally no problem
- ; starting with sector 25, because simply moving the
- ; head after the previous read on most drives will take
- ; about one half revolution. This table was determined em-
- ; perically using Shugart drives and doing actual tests
- ; with two different types of controller boards, and it
- ; is the fastest variation found. Change at your own risk.
- ;
- ;
- WRITAB:
- DB 25,1,3,5,7,9,11,13,15,17,19,21,23
- DB 26,2,4,6,8,10,12,14,16,18,20,22,24
- ;
- ; the following table is recommended for those whose controllers
- ; cannot write even every other sector:
- ; There is no peculiar starting sector here because the inter-
- ; leave ends on sector 24, and that is the same as the table
- ; above. This might be a better choice for a "universal" table.
- ;
- ; DB 1,4,7,10,13,16,19,22,25
- ; DB 2,5,8,11,14,17,20,23,26
- ; DB 3,6,9,12,15,18,21,24
- ;
- 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. (Are you listening, Digital Research?)
- ;
- 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 one-time code to initialize the branch table
- ; to the CBIOS vectors. Only those vectors used are
- ; initialized. This routine occupies the lowest area
- ; of the stack, and may be clobbered by the stack during
- ; operation, but it is used only once, so who cares.
- ;
- VECTOR:
- LHLD 1 ; get warm boot address
- SPHL ; and save it in SP for DAD
- 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 SETTRK+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
- ;
- LXI SP,STKTOP
- LXI H,BUFMSR
- SHLD START+1
- PCHL
- ;
- ; **************
- ;
- STK: ; stack
- DS 32
- STKTOP:
- DB 0
- TRKSRT: ; first and last+1 track numbers
- DB 0,0
- 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
- ;
- ; **************
- ; the track buffers. BUFEND must not overlay the BIOS !
- ;
- ; BUF0 is where all input tracks are read
- ;
- BUF0: DS 128*SDLAST*BUFFNU
- ;
- ; BUF1 is where the read-after-write is performed
- ;
- IF DOCOMP
- DATA1:
- DS 1 ; used in compare
- DATA2:
- DS 1
- BUF1:
- DS 128*SDLAST ; space for a full track read
- ENDIF
- IF NOT DOCOMP
- BUF1:
- DS 128 ; just one sector for CRC only
- ENDIF
- BUFEND: DS 1
- ;
- END
-