	title	'Copydisk - updated sysgen program 6/82'
; System generation program
VERS	equ	30		;version x.x for CP/M x.x
;
;**********************************************************
;*							  *
;*							  *
;*		Copysys source code			  *
;*							  *
;*							  *
;**********************************************************
;
FALSE	equ	0
TRUE	equ	not FALSE
;
;
NSECTS	equ	32
;	equ	26		;no. of sectors
NTRKS	equ	80
;	equ	2		;no. of systems tracks
;NDISKS	equ	4		;no. of disks drives
SECSIZ	equ	256
;	equ	128		;size of sector
;
TPA	equ	0100h		;Transient Program Area
LOADP	equ	1000h		;LOAD Point for system
BDOS	equ	05h		;DOS entry point
BOOT	equ	00h		;reboot for system
CONI	equ	1h		;console input function
CONO	equ	2h		;console output function
DRBIOS	equ	50		;Direct BIOS call function
CTLC	equ	'C'-'@'		;ConTroL C
Y	equ	89		;ASCII value of Y
;
MAXTRY	equ	01		;maximum number of tries
CR	equ	0Dh		;Carriage Return
LF	equ	0Ah		;Line Feed
STACKSIZE equ	016h		;size of local stack
;
WBOOT	equ	01		;address of warm boot
;
SELDSK	equ	9		;Bios func #9 SELect DiSK
SETTRK	equ	10		;BIOS func #10 SET TRacK
SETSEC	equ	11		;BIOS func #11 SET SECtor
SETDMA	equ	12		;BIOS func #12 SET DMA address
READF	equ	13		;BIOS func #13 READ selected sector
WRITF	equ	14		;BIOS func #14 WRITe selected sector


	maclib	z80
;
;	org	TPA		;Transient Program Area
;	jmp	START
	db	'COPYRIGHT 1992, '
	db	'by S. Simon '
	db	'011092'
	db	0,0,0,0
	db	'654321'

;
; Utility subroutines
;
MLTBY3:
;multiply the contents of regE to get jmp address
	mov	a,e		;Acc = E
	sui	1
	mov	e,a		;get ready for multiply
	add	e
	add	e
	mov	e,a
	ret			;back at it
;
SEL:
	sta	TEMP
	lda	V3FLG
	cpi	TRUE
	lda	TEMP
	jnz	SEL2
;
	sta	CREG		;CREG = selected register
	lxi	h,0000h
	shld	EREG		;for first time

	mvi	a,SELDSK
	sta	BIOSFC		;store it in func space
	mvi	c,DRBIOS
	lxi	d,BIOSPB
	jmp	BDOS
SEL2:
	mov	c,a
	lhld	WBOOT
	lxi	d,SELDSK
	call	MLTBY3
	dad	d
	pchl
;
TRK:
; Set up track
	sta	TEMP
	lda	V3FLG
	cpi	TRUE
	lda	TEMP
	jnz	TRK2

;
	mvi	a,00h
	sta	BREG		;zero out B register
	mov	a,c		;Acc = track #
	sta	CREG		;set up PB
	mvi	a,SETTRK	;settrk func #
	sta	BIOSFC
	mvi	c,DRBIOS
	lxi	d,BIOSPB
	jmp	BDOS
TRK2:
	lhld	WBOOT
	lxi	d,SETTRK
	call	MLTBY3
	dad	d
	pchl			;gone to set track
;
SEC:
; Set up sector number
	sta	TEMP
	lda	V3FLG
	cpi	TRUE
	lda	TEMP
	jnz	SEC2
;
	mvi	a,00h
	sta	BREG		;zero out BREG
	mov	a,c		; Acc = C
	sta	CREG		;CREG = sector #
	mvi	a,SETSEC
	sta	BIOSFC		;set up bios call
	mvi	c,DRBIOS
	lxi	d,BIOSPB
	jmp	BDOS
SEC2:
	lhld	WBOOT
	lxi	d,SETSEC
	call	MLTBY3
	dad	d
	pchl
;
DMA:
; Set DMA address to value of BC
	sta	TEMP
	lda	V3FLG
	cpi	TRUE
	lda	TEMP
	jnz	DMA2
;
	mov	a,b		;
	sta	BREG		;
	mov	a,c		;Set up the BC
	sta	CREG		;register pair
	mvi	a,SETDMA	;
	sta	BIOSFC		;set up bios #
	mvi	c,DRBIOS
	lxi	d,BIOSPB
	jmp	BDOS
DMA2:
	lhld	WBOOT
	lxi	d,SETDMA
	call	MLTBY3
	dad	d
	pchl
;
READ:
; Perform read operation
	sta	TEMP
	lda	V3FLG
	cpi	TRUE
	lda	TEMP
	jnz	READ2
;
	mvi	a,READF
	sta	BIOSFC
	mvi	c,DRBIOS
	lxi	d,BIOSPB
	jmp	BDOS
READ2:
	lhld	WBOOT
	lxi	d,READF
	call	MLTBY3
	dad	d
	pchl
;
WRITE:
; Perform write operation
	sta	TEMP
	lda	V3FLG
	cpi	TRUE
	lda	TEMP
	jnz	WRITE2
;
	mvi	a,WRITF
	sta	BIOSFC		;set up bios #
	mvi	c,DRBIOS
	lxi	d,BIOSPB
	jmp	BDOS
WRITE2:
	lhld	WBOOT
	lxi	d,WRITF
	call	MLTBY3
	dad	d
	pchl
;
GETCHAR:
; Read console character to rA
	mvi	c,CONI
	call	BDOS
; Convert to upper case
	cpi	'A' or 20h
	rc
	cpi	('Z' or 20h)+1
	rnc
	ani	05Fh
	ret
;
PUTCHAR:
; Write character from rA to console
	mov	e,a
	mvi	c,CONO
	call	BDOS
	ret
;
CRLF:
; Send Carriage Return, Line Feed
	mvi	a,CR
	call	PUTCHAR
	mvi	a,LF
	call	PUTCHAR
	ret
;

CRMSG:
; Print message addressed by the HL until zero with leading CRLF
	push	d
	call	CRLF
	pop	d		;drop through to OUTMSG
OUTMSG:
	mvi	c,9
	jmp	BDOS
;
SOURCE:
	lxi	d,GETPRM	;ask user for source drive
	call	CRMSG
	call	GETCHAR		;obtain response
;	cpi	CR		;is it CR?
;	jz	DFLTDR		;skip if CR only
	cpi	CTLC		;isit ^C?
	jz	REBOOT
;
	sui	'C'
;	sui	'A'		;normalize drive #
	cpi	2
;	cpi	NDISKS		;valid drive?
	jc	GETC		;skip to GETC if so
;
; Invalid drive
	call	BADDISK		;tell user bad drive
	jmp	SOURCE		;try again
;
GETC:
; Select disk given by Acc.
	adi	'C'
;	adi	'A'
	sta	GDISK		;store source disk
	sui	'A'
	mov	e,a		;move disk into E for select func
	call	SEL		;select the disk
	jmp	GETVER
;
;DFLTDR:
	mvi	c,25		;func 25 for current disk
	call	BDOS		;get curdsk
	adi	'A'
	sta	GDISK
	call	CRLF
	lxi	d,VERGET
	call	OUTMSG
	jmp	VERCR
;
GETVER:	
; Getsys set r/w to read and get the system
	call	CRLF
	lxi	d,VERGET	;verify source disk
	call	OUTMSG
VERCR:	call	GETCHAR
	cpi	CR
	jnz	REBOOT		;jmp only if not verified
	call	CRLF
	ret
;
DESTIN:
	lxi	d,PUTPRM	;address of message
	call	CRMSG		;print it
	call	GETCHAR		;get answer
	cpi	CR
	jz	REBOOT		;all done
	sui	'C'
;	sui	'A'
	cpi	2
;	cpi	NDISKS			;valid disk
	jc	PUTC
;
; Invalid drive
	call	BADDISK		;tell user bad drive
	jmp	DESTIN		;to try again
;
PUTC:
; Set disk fron rA
	adi	'C'
;	adi	'A'
	sta	PDISK		;message sent
	sui	'A'
	mov	e,a		;disk # in E
	call	SEL		;select destination drive
; Put system, set r/w to write
	lxi	d,VERPUT	;verify dest prmpt
	call	CRMSG		;print it out
	call	GETCHAR		;retrieve answer
	cpi	CR	
	jnz	REBOOT		;exit to system if error
	call	CRLF
	ret
;
;
GETPUT:
; Get or put CP/M (rw = 0 for read, 1 for write)
; Clear track 00
	mvi	a,-5
	sta	TRACK

; check for last track
ntrack:
	lda	TRACK
	adi	5
	sta	TRACK
	cpi	NTRKS
	jnz	copytrk
	ret			;all done

copytrk:
;read Source
	lda	GDISK
	sui	'A'
	call	SEL
	mvi	a,0
	sta	RW
	call	RWTRK
;write dest
	lda	PDISK
	sui	'A'
	call	SEL
	mvi	a,1
	sta	RW
	call	RWTRK
	jmp	ntrack

; disk is already selected
RWTRK: 
; Read or write next 5 track's
	lxi	h,LOADP		;load point in RAM for DMA address
	shld	DMADDR
	lda	track
	mov	c,a
	mvi	b,5
rwtrk0:
	push	b
	call	rwtrk1
	pop	b
	lda	track
	inr	a
	sta	track	
	djnz	rwtrk0
	mov	a,c
	sta	track
	ret
rwtrk1:
	lda	TRACK
	mov	c,a		;track number
	call	TRK		;set to track
	mvi	a,-1		;counts 0,1,2,...,25
	sta	SECTOR
;
RWSEC:
; Read or write a sector
	lda	SECTOR
	inr	a
	sta	SECTOR
	cpi	NSECTS		;sectors per track
	jnz	RWSECT
	ret			; Track done
;
; Read or write sector to or from current DMA address
RWSECT:
	mov	c,a		;value to C ready for select
	call 	SEC
	lhld	DMADDR		;base DMA
	mov	b,h
	mov	c,l		;to set BC for SEC call
	lxi	d,256
	dad	d
	shld	DMADDR
	call	DMA		;dma address set from BC
	xra	a
	sta	RETRY		;to set zero retries
;
TRYSEC:
; Try to read or write current sector
	lda	RETRY
	cpi	MAXTRY
	jc	TRYOK
;
; Past MAXTRY, message and ignore
	lxi	d,ERRMSG
	call	OUTMSG
	call	GETCHAR
	cpi	CR
	jnz	REBOOT
;
; Typed a CR, ok to ignore
	call	CRLF
	jmp	RWSEC
;
TRYOK:
; Ok to tyr read write
	inr	a
	sta	RETRY	
	lda	RW
	ora	a
	jz	TRYREAD
;
; Must be write
	call	WRITE
	jmp	CHKRW
TRYREAD:
	call	READ
CHKRW:
	ora	a
	jz	RWSEC		;zero flag if read/write ok
;
;Error, retry operation
	jmp	TRYSEC


;*******************
;*
;*	MAIN ROUTINE
;*
;*
;*******************
;
START:

	lxi	sp,STACK
	lxi	d,SIGNON
	call	OUTMSG
;
;get version number to check compatability
	mvi	c,12		;version check
	call	BDOS
	mov	a,l		;version in Acc
	cpi	30h		;version 3 or newer?
	jc	OLDRVR		;
	mvi	a,TRUE
	sta	V3FLG		;
	jmp	CHK
OLDRVR:	
	mvi	a,FALSE
	sta	V3FLG
;

; Check for default
CHK:
GETSYS:
	call	SOURCE		;find out source drive
	call	DESTIN		;get dest drive
;
	lxi	d,drvready
	call	CRMSG		;print it
	call	GETCHAR		;obtain reply
	cpi	Y		;is it yes?
	jnz	REBOOT		;if not exit
				;else
	call	GETPUT		;copy all

	lxi	d,DONE		;end message of get or read func
	call	OUTMSG		;print it out
;
REBOOT:
	jmp	0		; WBOOT
;
BADDISK:
	lxi	d,QDISK
	jmp	CRMSG

;****************************
;*
;*
;*	DATA STRUCTURES     
;*
;*
;****************************
;
BIOSPB:
; BIOS Parameter Block
BIOSFC:	db	0		;BIOS function number
AREG:	db	0		;A register contents
CREG:	db	0		;C register contents
BREG:	db	0		;B register contents
EREG:	db	0		;E register contents
DREG:	db	0		;D register contents
HLREG:	dw	0		;HL register contents
;
;
V3FLG:	db	0		;flag for version #
TEMP:	db	0
SDISK:	ds	1		;selected disk
;DFLAG:	db	0
TRACK:	ds	1		;current track
;CRNREC:	db	0		;current rec count
SECTOR:	ds	1		;current sector
RW:	ds	1		;read if 0 write if 1
DMADDR:	ds	2		;current DMA address
RETRY:	ds	1		;number of tries on this sector
SIGNON:	db	'CP/M 3 COPYDISK - Version '
	db	VERS/10+'0','.',VERS mod 10 +'0'
	db	' fuer 256 Bytes, 80 Spuren, zweiseitig$'
drvready:
	db	'Drives ready (Y/N) ? $'
GETPRM:	db	'Source drive name (or return for default) $'
VERGET:	db	'Source on '
GDISK:	ds	1
	db	' then type return $'
PUTPRM:	db	'Destination drive name (or return to reboot) $'
VERPUT:	db	'Destination on '
PDISK:	ds	1
	db	' then type return $'
;CPYMSG:	db	'Do you wish to copy CPM3.SYS? $'
DONE:	db	'Function complete$'
;
; Error messages......
;
QDISK:	db	'ERROR: Invalid drive name (Use C, or D)$'
;NOFILE:	db	'ERROR: No source file on disk.$'
;NODIR:	db	'ERROR: No directory space.$'
;FSPACE:	db	'ERROR: Out of data space.$'
;WRPROT:	db	'ERROR: Write protected?$'
ERRMSG: db	'ERROR: Possible incompatible disk format.'
	db	CR,LF,' Type return to ignore.$' 
;CLSERR:	db	'ERROR: Close operation failed.$'
;
	ds	STACKSIZE * 3
STACK:
	end	START
