.title	"Copy Floppy Disks using a HD"
        .sbttl  "FDHDCOPY"
version	==	1 
revision==	1
patch	==	'C'
	.pabs
	.phex
	.loc	100h		;beginning of TPA
;
»	Tablå oæ contentó foò FDHDCOPY
;
;  Table of contents				 1
;  Program Description				 2
;  Update History				 3
;  Equates					 4
;  Compute BIOS Addresses			 5
;  Ask user for source drive			 6
;  Ask user for destination drive		 7
;  Ask user for source density and what to copy  8
;  Set up copy variables			 9
;  Read the floppy disk to the hard disk	10
;  Reinit counter for copy back to FD		11
;  Read from HD, Write to FD and verify		12
;  End the Read-Write Process			15
;  Beginning of Subroutines			16
;  Hard Disk Subroutines			16
;  Floppy disk Subroutines			18
;  CRT I/O Subroutines				23
;  Define Storage				24
;  CRT Messages					26
;
.page
.sbttl 	' Program Descripition'
;
; DMS DSC 3/4 Copy floppy diskettes using a harddisk.
; By D. Brentlinger with assistance of D. Stein. 1/82
;
; User selects single or double density.
; System(0-1), Data(2-76), or All tracks can be copied.
;
; The user must have a separate partition on the 
; harddisk to use this program.  The partition name 
; must be 'SCRATCH'.  If it is not, an error message
; is printed.  If you do not have a partition named
; 'SCRATCH', use ALLOC to create it, with a size of 2.
;
; It is recommended that the user have a separate user
; table entry.  The format should be:
;
;     Name   copy
; password   You may want to control access.
; Defaults   A:d0
;	     B:scratch
;	     C:work partition - FDHDCOPY is here.
;	     D:u:   unassigned
;
; The user loads FDHDCOPY from drive C, the source
; drive is 0 and destination drive is B.
;
; First, 4 DD tracks or 8 SD tracks are read to the 
; buffer.  The  buffer is then written to the harddisk.
; This continues until the specified tracks are written
; to the harddisk.
;
; Next, 4 DD tracks or 8 SD tracks are read from the 
; harddisk to the buffer and  written to the floppy
; disk. The data is then read off the floppy disk into
; buf5 for verification.  If subroutine compare finds 
; two bytes that are not equal, an error message is  
; sent to the user and the program is restarted.
;
; The user can do multiple copies of a floppy disk.
; When the program has completed your first copy, it
; will ask if you want to repeat this copy.  A 'Y'
; will result in a repeat of the copy, using data
; already written to the harddisk.
;
; Program loops indefinitely until aborted by a ^C.
.page
.sbttl 'Update History'
;
;LAST REVISED 25MAY82 DRB
;
; Version 1.01
; 20MAY82MdG	Corrected an error in the computation
;		of buffer addresses.  Bufbegin was
;		being added to the buffer length 
;		instead of bufbase.
; Version 1.01A
; 20MAY82MdG	Updated the code to agree with the
;		new cpmMAP routine.
;
; 'B' 5/25/82	The original drive was not restored
;		correctly.  Problem fixed.
; 'C' 07/26/82  Add a table of contents, reorganize
;		and document the subroutines
;		correct a problem in the copy routine
;		that caused program to read a second
;		floppy disk incorrectly.
.page
.sbttl 'Equates'
;------------------
;  Data and Address constants
;
cr	==      0Dh
lf	==	0Ah
CTRLB	==      2h
CTRLC	==      3h	;I/O controls
wboot	==	0	;base address
sectbyt ==	128	
BDOS	==	05h	;Common CP/M entry point
conslin ==	01h	;CP/M 1,  Console Input
conout	==	2h	;CP/M 2,  Console Out
prtstrg == 	09h	;CP/M 9,  Print String
constat	==	0Bh	;CP/M 11, Get Console Status
setdsk  ==	0Dh	;CP/M 13, Reset Disk System
logdsk	==	0Eh	;CP/M 14, Select Disk nu
open	==	0Fh	;CP/M 15, Open File
close	==	10h	;CP/M 16, Close File
CPMread	==	14h	;CP/M 20, Read Sequential
dma	==	1Ah	;CP/M 26, Set DMA Address
EOF	==	1Ah	;end marker for file & buf I/O
usernum ==	47h	;network user number
locknet ==	19h	;network code
lockack ==	0h	;lock acknowledge
lockloc ==	4Ah	;loc of lock strg in high mem
lockstat==	49h	;lock status returned by BIOS
DDbyt	==	1<5	;Double density BIOS code
SDbyt	==	0<5	;Single density BIOS code
trk0bytes ==   	sectbyt*26   ;# of bytes in track 0
bufbase	==	1000h	; Beginning of copy buffer
NRtrks	==	4	; # of trks copied at a time
trklen	== sectbytes*52
buflen	== trklen*NRtrks
bufend  == bufbase+buflen	; end of rd buffer
buf5	== bufend+1	;beginning of verify buffer
bufsize == trklen*(NRtrks+1) ;size of rd buffer
secttrk	== 	128	;sectors per track on HD
lastread== 	104	;control harddisk seek if less
lasttim ==	4Bh	;than 2 floppy tracks left
;
.page
.sbttl 'Compute BIOS Addresses'
;
	lxi	sp,stack    ;Fresh stack
	lhld	wboot + 1    ;get the WBOOT address
	mov	D,H
	mov	E,L	    ;DE = HL
	lxi	H,15h
	dad	D
	shld	home +1	    ;BIOS jump for home
	lxi	H,18h
	dad	D
	shld	seldsk + 1  ;BIOS jump for seldsk
	lxi	H,1Bh
	dad	D
	shld	settrk + 1  ;BIOS jump for settrk
	lxi	H,1Eh
	dad	D
	shld	setsect + 1 ;BIOS jump for setsect
	lxi	H,21h
	dad	D
	shld	setdma + 1  ;BIOS jump for setdma
	lxi	H,24h
	dad	D
	shld	read + 1    ;BIOS jump for read
	lxi	H,27h
	dad	D
	shld	write + 1   ;BIOS jump for write
	lxi	H,5Dh
	dad	D
	shld	netlock + 1 ;BIOS jump for netlock
	lxi	H,60h
	dad	D
	shld	CPMmap + 1  ;BIOS jump for CPMmap
	lxi	H,63h
	dad	D
	shld	netunlock + 1 ;BIOS jump for netunlock
	lxi	H,66h
	dad	D
	shld	setbyt + 1  ;BIOS jump for setbyt
 	lxi	H,6Ch
	dad	D
	shld	sendnet	+ 1 ;BIOS jump for sendnet
	lxi	H,6Fh
	dad	D
	shld	recnet + 1  ;BIOS jump for recnet
	lxi	H,72h
	dad	D
	shld	nackpoll + 1 ;BIOS jump for nackpoll
	lxi	H,75h
	dad	D
	shld	ackpoll + 1 ;BIOS jump for ackpoll
.page
.sbttl	'Ask User for Source Drive'
;
	lxi	D,login	  ;print version number
	call	prtmsg	
	call	stoMAPbyt ;save users current map byte
	lda	usernum	  ;if user number = FFh, don't
	cpi	0FFh	  ;need lock string
	jrz	asksrc	  ;so continue
	lxi	H,lockmsg
	shld	lockloc	  ;loc of lock strg in memory
	call	netlock	  ;send lock using BIOS
	lda	lockstat  ;in first byte
	cpi	lockack	  ;if master says ok,
	jrz	asksrc	  ;continue
	lxi	D,nolock
	call	prtmsg	  ;else, tell user no
	jmp	abort
asksrc:			  ;ask for source disk
	lxi	D,query1  ;load source query
	call	prtmsg
	call	conin	  ;char returned in reg A
	cpi	CTRLC		
	jz	abort	  ;abort if ^C
	cpi	CTRLB		
	jrz	asksrc	  ;erroneous response
	sui	'0'       ;Make ascii chr numerical
	cpi	08	  ;maximum drives is 7
	jrc	..2	  ;no, store the source disk
	lxi	D,error2  ;yes, so
	call	prtmsg	  ;print err message and
	jmpr	asksrc    ;start this over
..2:	sta	srcedsk	  ;and save it.
.page
.sbttl	'Ask User for Destination Drive'
;
askdest:		  ;ask for destination disk
	lxi	D,query2  ;load destin message
	call	prtmsg
	call	conin	  ;get char. from accum
	cpi	CTRLB
	jrz	asksrc	  ;backstep if ^B
	cpi	CTRLC
	jz	abort     ;abort if ^C
	ani	0DFh	  ;make sure it is uppercase
	sui	'A'	  ;make ascii numeric
	cpi	04	  ;Out of range?
	jrc	..1	  ;no, so store dest disk 
	lxi	D,error2  ;yes, so print error msg
	call	prtmsg
	jmpr	askdest   ;and try again.
..1:	sta	destdsk   ;and save it.
	mov 	C,A	
	call	seldsk
	call	cpmmap	  ;need to make sure user is
			  ;assign to scratch on HD
	dcx	H	  ; Point at media type
	dcx	H	  ; Point at HD #
	dcx	H	  ; Point at last letter
			  ; in partition name
	lxi	D,litsch+7  ;we can see the 8 letter
	mvi	B,8	  ;parition name
..2:	ldax	D	  ;get first byte
	cmp	m	  ;should say SCRATCH
	jrnz	..err	  ;does not, start over
	dcx	D
	dcx	H	  ;next character
	djnz	..2
	jmpr	askdens	  ;it was right, continue
..err:	lxi	D,error4  ;wrong, print message and
	call	prtmsg	  
	jmpr	askdest	  ;start over
.page
.sbttl	'Ask User for source density and what to copy'
;
askdens:		  ;ask for density
	lxi	D,instr3  ;load dens question
	call	prtmsg
	call	conin     ;Get chr from console
	cpi	CTRLC
	jz	abort     ;abort if ^C
	cpi	CTRLB
	jrz	askdest   ;backstep if ^B
	ani	0DFh	  ;Make it UPPER CASE
	cpi	'S'	  ;S is single density
	mvi	C,SDbyt	  ;load sing dens code
	mvi	B,26 	  ;SD bytes per sector
	lxi	H,SDscttbl;load SD table address
	jrz	..1	  ;store if SD
	cpi	'D'	  ;D is double density
	mvi	C,DDbyt	  ;load doub dens code
	mvi	B,52 	  ;DD bytes per sector
	lxi	H,DDscttbl;load DD table address
	jrz	..1	  ;if neither,
        lxi	D,error3  ;Load dens err msg
	call	prtmsg
	jmpr	askdens   ;and ask again.
..1:    mov	A,C       ;get dens code in A
	sta	DENSbyt	  ;Save dens code.
	mov	A,B
	sta	numsect   ;Save num of sectors
	shld	tablstrt  ;Save sect tabl addr
;---------------
asktrk:			  ;ask user how many tracks
	lxi	D,query4  ;get copy message
	call	prtmsg
	call	conin	  ;get char from CRT
	ani	0DFh	  ;Make it UPPER CASE
	cpi	'S'
	jrz	..sys
	cpi	'D'
	jrz	..data
	cpi	'A'
	jrz	..all
        cpi	CTRLB
	jz	askdens   ;backstep if ^B
	cpi	CTRLC
	jz	abort     ;abort if ^C
	lxi	D,error5  ;all tests failed so load
	call	prtmsg	  ;and print err message
	jmpr	asktrk	  ;and start this over
.page
.sbttl  'Set up Copy Variables'
;
;Variables used for copying the operating system.
..sys:	mvi	A,0
	sta	fsttrk
	mvi	A,1
	jmpr    ..1       ;ready to copy floppy
;
;Variables used for copying the disk data.
..data:	mvi	A,2	  ;first track to copy 
	sta	fsttrk	  
	mvi	A,76	  ;last track to copy
	jmpr    ..1       ;ready to copy floppy
;
;Variables used for copying all tracks.
..all:	mvi	A,0
	sta	fsttrk
	mvi	A,76
..1:	sta	lasttrk	  ;last track to copy stored
	lxi	D,instr4  ;ready to copy message
	call	prtmsg	  ;print it
        call	conin
	cpi	CTRLB     
	jrz	asktrk    ;backstep if ^B
	cpi	CTRLC     ;if request is ^C,
	jz	abort	  ;abort the program
	lda	srcedsk   ;source disk
	call	chaMAPbyt ;Select source disk
	call	HOME	  ;and set to track 0
	lxi	D,crlf  
	call	prtmsg	  ;skip a line
	lda	fsttrk    ;first track to read
	sta	floptrk	  ;incremented track number
	call	getcomp	  ;# of compares for SD or DD
;--------------
; set up the floppy disk read-write buffer
;
	lda     densbyt   ;get density code 
	cpi	DDbyt	  ;if we have double density,
	mvi	A,NRtrks  ;# of DD tracks to fill buff
	jrz	..2	  ;else, more tracks for buff 
	add	A	  ;Double it for # of SD tracks
..2:	sta	maxtrk	  ;stored in maximum tracks
	call	calcsect  ;calculate sectors to HD
	shld	sectwrt	  ;used to reinit sector cntr
	shld	totsectcntr ;buffer is same for all
	lda	fsttrk	  ;if first track is 2, 
	cpi	2	  ;don't subract sectors
	jrz	readflop  ;for track 0
	lda	densbyt	  ;get density code
	cpi	SDbyt	  ;check if SD
	jrz	readflop  ;so don't sub for track 0
	lxi	B,-26	  ;else, sectors for track 0
	dad	B	  ;subtracted from totsectcntr
	shld	totsectcntr ;and stored in counter
.page
.sbttl	'Read FD to the HD'
;
readflop:
	sub	A	  ;reiniô counter for # of
	sta	trkcntr	  ;floppy tracks to read
	lda	srcedsk   ;get source disk
	call	chaMAPbyt ;and select it.
	lhld	bufbegin
	shld	bufloc   ;for dma addressing
	lda	floptrk	 ;current track
	ora	A	 ;trk0? if not, then go
	jrnz	..1      ;read sect. by sect.
	call	setrk0	 ;set trk0 ready to
	call	read	 ;be read
	call    prttrk   ;print track written to buff
	lxi	b,sectbyt ;reset # of bytes to
	call	setbyt	 ;128 for next i/o
	lded	bufloc   ;increment buffer addr
	lxi	h,trk0bytes ;by the # of bytes in
	dad	d	 ;track 0
	shld	bufloc   ;track 0 read finished
	lxi	H,trkcntr ;counts tracks read
	inr	m	  ;increment for track 0
	lxi	H,floptrk ;addr of counter
	inr	m	  ;increment to track 1
..1:    call	readtrk   ;read next track
	call    prttrk    ;print track written to buff
	lxi	H,floptrk ;addr of counter
	inr	m	  ;and add one to it
	lda	lasttrk	 ;last track we need to write
	cmp	m	 ;if not =, do it again, else,
	lxi	H,trkcntr 
	inr	m	 ;increment tracks read 
	jrc	..2      ;dump the read buffer
	lda	maxtrk	 ;if track counter = max track
	cmp	m	 ;write buffer to HD
	jrnz	..1	 ;else, read next trk to buff
	call    wrttoHD  ;write the buffer to HD and
	jmpr	readflop ;reinit the disk and buffer
;---------------
; Successful floppy read so dump the buffer.
;
..2:	cpi	1	  ;if this is a system copy,
	jrz	..3	  ;use initial totsectcntr
	lda	trkcntr   ;else use final track count
	sta	maxtrk	  ;for final write from buffer
	call    calcsect  ;to the harddisk
	shld	totsectcntr 
..3:	call	wrttoHD	  ;write to harddisk
.page
.sbttl	'Reinit counters for copy of FD'
;
; Start of copy to the floppy disk
;
	lxi	D,crlflf  ;double linefeed
	call	prtmsg
	lxi	D,insrtms ;floppy copied to harddisk
	call	prtmsg	  ;insert new floppy msg
repeat:	call	waitCR	  ;wait for new floppy disk
	lxi	D,contmsg ;do you want to continue
	call	prtmsg	  
	call    conin	  ;get users response
	ani	0DFh	  ;make sure it is upper case
	cpi	'Y'
	jrz	..4	  ;yes, read harddisk
	lxi	D,abortms ;else, ask user if this
	call	prtmsg	  ;response is incorrect
	call	conin
	ani	0DFh	  ;make sure it is upper case
	cpi	'Y'	  ;if user responds yes, abort
	jz	abort	  ;the copy, else, continue
..4:	lxi	D,crlf	  
	call	prtmsg	  ;space one line extra
	mvi	A,1	  ;reinit sector counter
	sta     cursec	  ;for the harddisk
	lxi     H,0	  ;reinit track counter
	shld	hardtrk   ;for the harddisk
	lda	fsttrk	  ;reint beginning track # for
	sta	floptrk	  ;reinit current track
	lda     densbyt   ;get density code 
	cpi	DDbyt	  ;if we have double density,
	mvi	A,NRtrks  ;# of DD tracks to fill buff
	jrz	..5	  ;else, more tracks for buff 
	add	A	  ;Double # of trks for SD
..5:	sta	maxtrk	  ;stored in maximum tracks
	call	calcsect  ;calculate # of sectors 
	shld	sectwrt	  ;used to reinit sector cntr
	shld	totsectcntr ;buffer is same for all
	lda	fsttrk	  ;if first track is 2, 
	cpi	2	  ;so don't subract sectors
	jrz	readHD	  ;for track 0
	lda	densbyt	  ;get density code
	cpi	SDbyt	  ;Check if SD
	jrz	readHD	  ;so don't sub for track 0
	lxi	B,-26	  ;else, sectors for track 0
	dad	B	  ;subtracted from totsectcntr
	shld	totsectcntr ;and stored in counter
.page
.sbttl	'Read from HD, write to FD, then verify'
;
; Read from harddisk to memory
;
readHD:
	lda	floptrk	  ;if this is the last floppy
	cpé	lasttim   ;disë write¬ reaä less
	jrc	..1	  ;sectors from the HD
	lxi	H,lastread  ;number of sectors to read
	shld	totsectcntr ;stored in sector counter
..1:	lda	destdsk   ;destination disk is source
	sta	curdsk	  ;disk for floppy copy
	lhld	bufbegin  ;beginning addr of buffer
	shld	curdma	  ;in current DMA address
..2:	call	SETUP
	call	READ
	call	NEXTSEC	   
	lbcd	totsectcntr ;total sectors in buffer
	dcx	B	    ;decremented for each write
	sbcd	totsectcntr ;and stored
	moö	A,B
	ora	C
	jrnz	..2	   ;start write on next track
        lbcd	sectwrt	   ;sectors to write to HD
	sbcd	totsectcntr ;in the counter
	mvi	A,0	   ;zero track counter for 
	sta	trkcntr	   ;next write and verify
;---------------
; write, read and verify the track written to floppy
;
	lda	srcedsk   ;source disk is the
	call	chaMAPbyt ;destination disk
	lhld	bufbegin  ;get buffer address
	shld	bufloc    ;save for dma
	shld	cmpbuf    ;add where verify start
	lda 	floptrk   
	cpi	0	  ;is it trk0 ?
	jrnz	wrttrk    ;if not, regular write
	call	setrk0	  ;else set trk0
	call 	write	  ;go write it
	lxi	b,sectbyt ;reset # of bytes to 
	call 	setbyt	  ;128 for next i/o
	lded	bufloc    
	lxi	h,trk0bytes ;increment buffer by
	dad	d	  ;# of bytes inn trk0
	shld	bufloc  
	jmpr	read1	  ;go read back & verify
.page
;---------------
wrttrk:
	call	setdisk	  ;set up disk for read
	lda	sectontrk ;get num of sec on
	mov	B,A	  ;this track in B.
..1:	push	B
	call	getsect	  ;Get next sector
	mov	C,A		
	call	setsect	  ;and select it.
	lbcd	bufloc	
	call	setdma	  ;Set DMA
	call	write	  ;write one sector
	lded	bufloc
	lxi	H,sectbyt ;bytes per sector
	dad	D	  ;increment buffer to
	shld	bufloc    ;write the next track
	pop	B
	djnz	..1	  ;Do all sectors
	shld	tmpbuf    ;save it
;---------------
; read back track just copied and verify it
read1:
	lda	floptrk	  ;if trk0 then read
	cpi	0	  ;whole track. if not
	jrnz	..1	  ;read 1 sect. at a time
	mvi	c,1	  ;first sector
	call	setsect	  ;set it for read
	lxi	b,buf5	  ;buffer location for compare
	call	setdma	  ;trk to be verified
	lxi	b,trk0bytes ;# of bytes in trk0
	call 	setbyt	 
	call	read	
	lxi	b,sectbyt ;reset # of bytes to
	call 	setbyt	  ;128 for next i/o
	jmpr    verify	  ;go verify track copied
..1:	lxi	h,buf5	  ;parameter passing to
	shld	bufloc	  ;subroutine readtrk
	call  	readtrk   ;read one track
	lhld	tmpbuf    ;restore init. value
	shld	bufloc    ;of buffer and verify copy
.page
;---------------
VERIFY: 
	lda	floptrk	  
	lxi	h,lasttrk	
	cmp	m		
	jrz	theend	  ;end of copy
	cpi	0	  ;is it track 0 ?
	jrnz	..1		
	lxi	h,trk0bytes ;# of comp for trk0
	shld	noofcomp  
	jmpr	..2	
..1:	lhld	cmpned	  ;# of comp for 
	shld	noofcomp  ;other tracks
..2:	call	compare	  ;go verify copied trk
	cpi	'/'	  ;if accum = '/', we have
	jrz	badcopy	  ;badcopy so print message
	lxi	H,floptrk ;increment the track #
	inr	m	  
	lxi	h,trkcntr ;have we written and
	inr	m	  ;verified the 4 tracks
	lda	maxtrk    ;if not, verify
	cmp	m	  ;the next track.
	jz	readHD    ;Else, load the buffer again
	lhld	bufloc    ;reset next loc in buffer
	shld	cmpbuf    ;where verify will start
	jmp     wrttrk
.page
.sbttl	'End of R/W Process'
;
abort:			  ;didn't do it right
	call	resMAPbyt ;restore org assmt	
	lxi	D,instr7  ;load complete message
	call	prtmsg	  ;print message
	lda	usernum	  ;if user number = FFh, don't
	cpi	0FFh	  ;need lock string
	jrz	..2	  ;so continue
	lxi	H,lockmsg
	shld	lockloc	  ;loc of lock strg in memory
	call	netunlock ;send unlock using BIOS
..2:	jmp	wboot	  ;wboot
;--------------- 
theend:	
        lhld	cmpned	  ;# of comp. needed
	shld	noofcomp  
	call 	compare	  
	cpi	'/'	  ;if accum = '/', we have
	jrz	badcopy	  ;badcopy so print message
	lxi	D,crlf	  
	call	prtmsg	  ;double space
	lxi	D,askrept ;does the user want to 
	call	prtmsg	  ;make another copy?
	call	conin	  ;user's response
	ani	0DFh	  ;make it upper case
        cpi	'N'
	jrz     ..3       ;if no, don't repeat copy
	lxi	D,repetms ;else,insert formatted
	call 	prtmsg	  ;diskette and
	jmp	repeat    ;start HD read over
..3:	mvi	A,1	  ;reinit sector counter
	sta     cursec	  ;for the harddisk
	lxi     H,0	  ;reinit track counter
	shld	hardtrk   ;for the harddisk
	lxi	D,instr7  ;job completed msg
	call	prtmsg	  ;print msg
	lxi	D,crlflf
	call	prtmsg	  ;Double line feed
	jmp	asksrc    ;and start over.
;---------------
badcopy:
	call	prttrk	  ;print bad track 
	lxi	d,error6  ;print 
	call	prtmsg	  ;copy error message
	lxi	d,crlflf  
	call	prtmsg	
	jmp	asksrc	  ;retry again
.page
.sbttl 'Hard disk Subroutines'
;
; Subroutine wrttoHD: write memory buffer to harddisk
; Reg in:  None
; Reg out: None
; Destroyed: A,BC,HL
;	
wrttoHD:
	lda	destdsk	   ;destination disk is
	sta	curdsk	   ;current disk
	lhld	bufbegin   ;beginning addr of buffer
	shld	curdma	   ;in current DMA address
..2:	
        call	SETUP
	call	WRITE
	call	NEXTSEC	   
	lbcd	totsectcntr ;total sectors in buffer
	dcx	B	    ;decremented for each write
	sbcd	totsectcntr ;and stored
	moö	A,B
	ora	C
	jrnz	..2	   ;start write on next track
        lbcd	sectwrt	   ;sectors to write to HD
	sbcd	totsectcntr ;in the counter
	ret		   ;and return
;--------------
; Subroutine Setup:  Setup a CP/M disk read or write
; Reg in:  None
; Reg out: None
; Destroyed: A,BC,HL
;
SETUP:
	lda	curdsk
	mov	C,A
	call	SELDSK	;set disk number
	lbcd	hardtrk
	call	SETTRK	;set track number
	lda	cursec
	mov	C,A
	call	SETSEC	;set sector number
	lbcd	curdma
	call	SETDMA	;set DMA address
	ret
.page
; Subroutine Nextsec:  Advance to next HD sector.  If
;  		sector is full, advance to next track.
; Reg in:  None
; Reg out: None
; Destroyed: A,DE,HL
;
NEXTSEC:
	lda	cursec
	cpi	128
	jrnz	..1
	lhld	hardtrk
	inx	H
	shld	hardtrk	;increment track counter
	mvi	A,0	;reinit sector counter
..1:	inr	A	;increment sector counter
	sta	cursec  ;store sector counter
	lhld	curdma
	lxi	D,128
	dad	D
	shld	curdma	;increment DMA address
	ret
.page
.sbttl  'Floppy disk Subroutines'
;
; Subroutine calcsect: calculate number of sectors to
;		       write to the harddisk
; Reg in:  None
; Reg out: None
; Destroyed: All
;
calcsect:
	lda	numsect   ;sectors in SD or DD diskette
	mov	C,A
	mvi	B,0	  ;now it is 2 bytes long
	lda	maxtrk	  ;# of tracks read 
	lxi	H,0	  ;nothing in reg
..loop:
        dcr	A
	dad	B	  ;numsect added to HL
	jrnz	..loop	  ;do it for all tracks
	ret
;---------------
; Subroutine setrk0: special read of track 0
;
; Reg in:  None
; Reg out: None
; Destroyed: All
setrk0:	
        mov	c,a	  ;argument for settrk
	call	settrk		
	mvi	c,1	  ;argument for setsect
	call	setsect	  ;set first sector
	lxi	b,trk0bytes ;# of bytes read
	call	setbyt		
	lbcd	bufloc    ;dma addr.
	call	setdma		
	ret			
;---------------
; Subroutine getcomp: calculate # of  compares needed 
;                     for SD or DD floppy disk
; regs in : none
; regs out : none
; destroyed : hl,bc
getcomp:
	lxi	h,numsect ;# of sectors per track
	mov	a,m	  ;is it single density ?
	cpi	26	  ;if not, goto double
	jrnz	..52sect  ;density routine
	lxi	d,trk0bytes ;get # of SD comparisons
	sded	cmpned	  ;save compares needed
	ret
..52sect:
	lxi	d,52*sectbyt ;# of comp. for DD disk
	sded	cmpned	  ;save compares needed
	ret
.page
;---------------  
; Subroutine readtrk: read a track on the floppy
; Regs in:	none
; Regs out:	none
; Destroyed:	all
readtrk:
	call	setdisk	  ;set up disk for read
	lda	sectontrk ;Get the num of secs
	mov	B,A	  ;on this track in B.
..1:	push	B	  ;Use it as a counter.
	call	getsect
	mov	C,A
	call	setsect
	lbcd	bufloc	
	call	setdma
	call	read	  ;read one sector
	lded	bufloc	  ;location of buffer
	lxi	H,128	  ;bytes per sector 
	dad	D	  ;increment the buffer
	shld	bufloc    ;to read the next track
	pop	B	  ;Restore the counter
	djnz	..1	  ;Do all sectors
	ret
;---------------
; Subroutine setdisk: set number of sectors on track.
; Regs  in:	none
; Regs out:	none
; Select next track.
; Reset sector table address.
; Abort if ^C is received from the console.
;
setdisk:
	lda	floptrk
        mov	C,A	  ;get current track
	mvi	B,0	  ;zero second byte
	call	settrk    ;and select it
	lda	numsect
	sta	sectontrk ;# of sect on track
	lhld	tablstrt  ;Get sect tabl addr
	shld	tabladdr  ;to start the start
	mvi	C,constat ;CP/M 11, Get Console Status
	call	BDOS
	ora	A	  ;Reset carry flag.
	rrc		  ;Set carry if console
			  ;chr is ready.
	rnc		  ;Return. No chr ready.
  	call	conin	  ;Read con chr
	cpi	CTRLC
	jz	abort	  ;abort if ^C
	ret		  ;otherwise return
.page
;---------------
; Subroutine getsect: get next sector from table
; Regs  in:	none
; Regs out:	A = next sector in sector table
; Destroyed:	HL
; Increment to next address in table
;
getsect:
	lhld	tabladdr  ;get spot in sect tabl
	mov	A,M	  ;get sector value
	cpi	0FFh	  ;End of table?
	jrz	..1       ;Yes. abort.
	inx	H	  ;get to next table addr
	shld	tabladdr  ;and save it.
	ret		  
..1:			  ;fatal error
	lxi	D,error1  ;Print sector fall-
	call	prtmsg	  ;thru message.
	jmp	abort	  ;Fatal error. Abort.
;---------------
; Subroutine compare: compare the track just copied 
; with the same track read 
; regs in: none		
; regs out: none
; destroyed: all
;
compare:
	lxi	d,0	  ;initialize counter
	sded	compcntr  ;save it
	lhld	cmpbuf    ;where trk from source
	push	h	  ;is stored; save it
	lxi	b,buf5	  ;where dest. track is
..1:    pop	h	  ;get one byte
	mov	d,m	  ;from source
	ldax	b	  ;get one byte from dest
	cmp	d	  ;compare the two bytes
	jrnz	..exit	  ;copy error!!
	inx	h	  ;else get next byte 
	inx 	b	  ;from source & dest.
	push	h	 
	lded	compcntr  ;get current count
	inx	d	  ;increment it
	sded	compcntr  ;save it
	lhld	noofcomp  ;max # of comp. needed
	ora	a	  ;clear carry bit
	dsbc	d	  ;done? if not,
	jrnz	..1	  ;keep comparing
	pop	h	  ;pop junk
	call	prttrk 	  ;print track copied
	ret		  ;else return to caller
..exit: mvi	A,'/'     ;we have copy error so
	ret		  ;return with flag in accum
.page
;---------------
;Subroutine stoMAPbyt: save current disk assignment
; Regs  in:	none
; Regs out:	none
;Destroyed:	all registers
;
stoMAPbyt: 
	call	CPMmap	; get current assignment
	shld	origdrv ; used to restore drive
	sta	UNITno	; save current unit #
	dcx	H	; Point at media type
	mov	A,M	; Get media type
	sta	DEVtype	; save it
	ret		; and return.
;---------------
;Subroutine chaMAPbyt:  Change the map byte
; Regs  in:	A = unit number to assign to
; Regs out:	none
;Destroyed:	all registers
;
; Change the assignment to the floppy disk of
; the unit number received in the accumulator.
;
chaMAPbyt:
	push	PSW	  ;Save unit number
	mov	C,A
	call	seldsk
	pop     PSW	  ;need accum but need to
	push	PSW	  ;save it
	call	CPMmap	  ;get current MAPbyte byte addr
	pop	B	  ;Restore unit number in B
	mov	M,B	; Set new unit #
	lda	DENSbyt	  ;Get floppy density code
	dcx	H	; Point at media type in RAM
	mov	M,A	  ;Store it in the BIOS
	ret
;---------------
; Subroutine  resMAPbyt: restore original disk 
; Regs  in:	none
; Regs out:	none
;Destroyed:	all registers
;
resMAPbyt:
	lhld	origdrv ; get BIOS addr
	lda	UNITno	; original unit number
	mov	M,A	; Put it back in RAM
	lda	DEVtype	; Original media type
	dcx	H	; Point at media byte
	mov	M,A	; And store it,
	ret		; and return.
.page
.sbttl  'CRT I/O Subroutines'
;
; Subroutine prttrk:  print track number we processed
;
prttrk:
	lda	floptrk
	mov	C,A	;save for low bit
	rrc
	rrc
	rrc
	rrc
	ani	0Fh
	adi	30h
	cpi	3Ah
	jrc	..1
	adi	'A'-':'
..1:	sta	trkmsg	;for display of track number
	mov	A,C
	ani	0Fh
	adi	30h
	cpi	3Ah	;10 or greater?
	jrc	..2	;skip if not
	adi	'A'-':'
..2:	sta	trkmsg + 1
	lxi	D,disptrk ;load track number copied
	call	prtmsg	;print it
	ret
;---------------
; Subroutine prtmsg:  send string output to the CRT.
;
prtmsg:	
	mvi	C,prtstrg ;CP/M 9, Print String
	call	BDOS	
	ret			
;---------------
; Subroutine conin:  get character input from the CRT.
;
conin:		
	mvi	C,conslin ;CP/M 1, Console Input
	call	BDOS
	ret
;---------------
; Wait for a CR (carriage return) to be typed
;
waitCR:
..loop: call	conin
	cpi	cr
	jrnz	..loop
	ret
.page
.sbttl	'Define Storage'
;
; Floppy disk constants
;
trkcntr:.byte   0       ;counts # of tracks read
srcedsk:.byte	0	;source disk
destdsk:.byte	0	;Destination disk.  HD part
litsch: .ascii 'SCRATCH ' ;name must be SCRATCH
bufloc:	.word 	00	;current DMA location
fsttrk:	.byte 	0	;first track to copy
lasttrk:.byte	0	;last track to copy
floptrk:.byte	0	;current track for R/W
maxtrk: .byte   0	;max tracks to fill buffer
numsect:.byte	0	;sectors per track (26 or 52)
sectontrk:
	.byte   0	;sectors on current track
tablstrt:.word	00	;start addr of sector table
tabladdr:.word	00	;current address in sect tabl
DENSbyt:.byte	0	;Holds BIOS density code
DEVtype:.byte	0	;Used by chaMAPbyt, etc.
UNITno:	.byte	0	;Used by chaMAPbyt, etc.
origdrv:.word	0	;Used by chaMAPbyt,stoMAPbyt
;
;constants for floppy write compare
;
bufbegin:.word  1000h	;read from floppy to memory 
compcntr:.word  0	; counter for # of compares
noofcomp:.word  0	; # of compares (SD or DD)
cmpbuf:.word	0	;location where verify starts
tmpbuf:.word    0	;temporary storage for compare
cmpned:.word	0	;number of compares for 1 trk
;---------------
;Staggered sector tables for optimized Reads/Writes
;
DDscttbl:	; Double Density staggered sector table
	.byte 01,02,03,04,05,06,07,08,09,10,11,12,13,14
	.byte 15,16,17,18,19,20,21,22,23,24,25,26,27,28
	.byte 29,30,31,32,33,34,35,36,37,38,39,40,41,42
	.byte 43,44,45,46,47,48,49,50,51,52,0FFh
;
SDscttbl:   ; Single Density staggered sector table
    .byte 01,03,05,07,09,11,13,15,17,19,21,23,25
    .byte 02,04,06,08,10,12,14,16,18,20,22,24,26,0FFh
.page
home:	  jmp	0  	;BIOS addresses are filled in
seldsk:	  jmp	0	;during the first part of the
settrk:	  jmp	0	;MAIN  execution.
setsect:  jmp	0
setdma:	  jmp	0
read:	  jmp	0
write:	  jmp	0
netlock:  jmp	0
CPMmap:	  jmp	0
netunlock:jmp	0
setbyt:	  jmp	0
sendnet:  jmp	0
recnet:   jmp	0
nackpoll: jmp	0
ackpoll:  jmp   0
; File Control Block. See CP/M users guide for details.
;
FCBaddr:.word	0000h	; address of FCB (here or 5Ch)
FCB:	.byte	00h
filnam:	.byte	20h,20h,20h,20h,20h,20h
	.byte	20h,20h,20h,20h,20h
	.byte	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	.byte	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DMAaddr:.word	00h	;addr (in file buffer) for DMA
FCBcnt:	.byte	00h	;Counter of FCB bytes tranfered
sectred:.byte	00h	;Number of sectors read by CP/M
bufaddr:.word	00h	;Addrs of current FCB location
sectwrt:.word   00h	;# of sectors  to write to HD
totsectcntr:		;sectors written
	.word   00h	;to HD counter
sectcntr:.byte  00h	;count sectors written to HD
;
; Constants for harddisk write/read
;
dstdsk:	.byte	0	; destination disk (0-3)
srcdsk:	.byte	0	; source disk (0-3)
numtrk:	.word	0	; CP/M tracks on disk (16-512)
curdsk:	.byte	0	; current disk (0-3)
hardtrk:.word	0	; current track (0-511)
cursec:	.byte	1	; current sector (1-128)
curdma:	.word	0	; current DMA address
.page
.sbttl 'CRT Messages'
;---------------
; Messages to the operator
;
login:	.ascii	[cr][lf]'Copy Floppy Disks Using a HD,'
	.ascii		' version '
	.byte	version+'0','.'
	.byte	revision/10+'0',revision@10+'0'
	.byte	patch
crlf:	.ascii  [cr][lf] '$'
lockmsg:.byte	9h
	.ascii  	'FDHDCOPY'
nolock: .ascii	[cr][lf]'FDHDCOPY is in use, please '
	.ascii		'try again later.$'
instr3:	.ascii	[cr][lf]'Density? (S/D) $'
instr4:	.ascii	[cr][lf]'Hit return when ready$'
instr7:	.ascii	[cr][lf][lf]'**  JOB COMPLETED $'
instr8:	.ascii	[cr][lf][lf]'**  JOB TERMINATED $'
query1:	.ascii	[cr][lf]'Source disk (0-7) :$'
query2:	.ascii	[cr][lf]'Destination disk '
        .ascii          '(A,B,C, or D)$'
query4:	.ascii	[cr][lf]'COPY: System tracks, Data'
	.ascii	        ' tracks, or '
	.ascii	[cr][lf]'      All tracks? '
	.ascii	        ' (S,D, or A)? $'
error1:	.ascii	[cr][lf]'FELL THROUGH SECTOR TABLE$'
error2:	.ascii	[cr][lf]'IMPROPER DISK SELECTION$'
error3:	.ascii	[cr][lf]'IMPROPER DENSITY SELECTION$'
error4:	.ascii	[cr][lf]'IMPROPER HARDDISK DRIVE '
	.ascii		'SELECTION '
	.ascii	[cr][lf]'Harddisk partition name '
	.ascii		'must be SCRATCH.$'
error5: .ascii	[cr][lf]'IMPROPER COPY COMMAND$'
error6: .ascii  [cr][lf]'** BAD TRACK HERE ! retry-$'
disptrk:.ascii	[cr]    'Track ' 
trkmsg:	.ascii	        '00h'
	.ascii	        ' processed'[cr]	
	.ascii	        '$'
insrtms:.ascii	[cr][lf]'Remove diskette you read '
	.ascii		'from.'
repetms:.ascii  [cr][lf]'Insert a formatted diskette.'
       	.ascii  [cr][lf]'Then hit RETURN to continue.$'
contmsg:.ascii  [cr][lf]'Do you want to continue the '
	.ascii		'copy? (Y or N) $'
askrept:.ascii  [cr][lf]'Do you want to repeat this '
	.ascii		'copy? (Y or N) $'
abortms:.ascii  [cr][lf]'Do you want to abort the '
	.ascii          'copy? (Y or N) $'
crlflf:	.ascii	[cr][lf][lf]'$'
;----------
; Stack room
	.blkb	30
stack:
;
.end
