	TITLE	'CP/M "DCOPY" FUNCTION 1/78'
;
;	DISK COPY FUNCTION, COPIES FROM DISK A TO DISK B UNTIL 0E5H'S
;
;	COPYRIGHT (C) 1977, 1978
;	DIGITAL RESEARCH
;	BOX 579 PACIFIC GROVE
;	CALIFORNIA, 93950
;
	ORG	100H
	JMP	START
	DB	'COPYRIGHT (C) 1978, DIGITAL RESEARCH '
;
;	GLOBAL EQUATES
BOOT	EQU	0000H
BDOS	EQU	0005H
;
SPT	EQU	58	;SECTORS PER TRACK
BPS	EQU	128	;BYTES PER SECTOR
BPT	EQU	BPS*SPT	;BYTES PER TRACK
TPD	EQU	77	;TRACKS PER DISK
OSTRKS	EQU	2	;TRACKS FOR OS
;
CONIN	EQU	1	;READ CONSOLE DEVICE
RDBUFF	EQU	10	;READ BUFFER
PBUFF	EQU	9	;PRINT BUFFER
CR	EQU	0DH
LF	EQU	0AH
;
READTRK	EQU	$
WRITTRK	EQU	$+3
REREAD	EQU	$+6
	JMP	READ$DISK
	JMP	WRITE$DISK
	JMP	RE$READ$DISK
TRACK:	DS	1	;SET TO TRACK TO READ/WRITE
BUFFA:	DS	2	;SET TO BUFFER ADDRESS TO READ/WRITE
IOF:	DS	1	;IO FUNCTION 0 = READ, 1 = WRITE
;
READ$DISK:
	;READ DISK DRIVE A, FROM TRACK 'TRACK'
	;INTO THE ADDRESS GIVEN BY 'BUFFA'
	XRA A! CALL SEL ;SELECT DRIVE A
	JMP READ$D
;
;
WRITE$DISK:
	;WRITE TO DISK DRIVE B, TO TRACK 'TRACK'
	;FROM THE ADDRESS GIVEN BY 'BUFFA'
	MVI A,1! STA IOF ;SET IOFUNCTION TO WRITE
	CALL SEL ;SELECT DRIVE B
	JMP RW$DISK
;
RE$READ$DISK:
	;READ FROM DISK DRIVE B, FROM TRACK 'TRACK'
	;TO THE ADDRESS GIVEN BY 'BUFFA'
	MVI A,1! CALL SEL ;DRIVE B SELECTED
	READ$D: XRA A! STA IOF ;SET TO READ FUNCTION
	RW$DISK: ;READ OR WRITE DISK
		LXI H,TRACK! MOV C,M ;GET TRACK NUMBER
		CALL TRK ;TRACK SELECTED
		LHLD BUFFA ;GET DMA ADDRESS
		LXI D,spt ;D = 0, E = spt
		RW$LOOP: ;READ/WRITE LOOP
			INR D ;TO NEXT SECTOR
			PUSH D! PUSH H
			mov c,d! mvi b,0
			lxi h,skewtbl-1! dad b
			MOV C,m! CALL SEC ;SECTOR SET
			POP B! PUSH B ;GET DMA ADDRESS
			CALL DMA ;DMA ADDRESS SET
			;PERFORM IO FUNCTION
			LDA IOF! ORA A ;SET FLAGS, 0=READ, 1=WRITE
			JNZ WRITEFUNC
				;READ DISK
				CALL DREAD
				JMP RWCOMPLETE
			WRITEFUNC:
				;WRITE DISK
				CALL DWRITE
			RWCOMPLETE: ;FUNCTION COMPLETE
				POP H ;RECALL DMA ADDRESS
				LXI D,80H! DAD D ;TO NEXT DMA
				POP D ;RECALL SECTOR AND COUNT
			; CHECK ERROR CONDITIONS
			ORA A! RNZ ;RETURN WITH NON ZERO FLAG SET
			DCR E ;COUNT = COUNT - 1
			JNZ RW$LOOP ;FOR ANOTHER SECTOR
			RET ;WITH ZERO FLAG SET FOR IO COMPLETE
;
;
;
;	UTILITY SUBROUTINES FOR DIRECT DISK IO
WBOOT	EQU	1	;WARM BOOT ADDRESS
SELDSK	EQU	24	;SELECT DISK
SETTRK	EQU	27	;SET TRACK
SETSEC	EQU	30	;SET SECTOR
SETDMA	EQU	33	;SET DMA ADDRESS
READF	EQU	36	;READ DISK
WRITF	EQU	39	;WRITE DISK
;
SEL:	;SELECT DRIVE GIVEN BY REGISTER A
	MOV C,A! LHLD WBOOT! LXI D,SELDSK! DAD D! PCHL
;
TRK:	;SET TRACK GIVEN BY C
	LHLD WBOOT! LXI D,SETTRK! DAD D! PCHL
;
SEC:	;SET SECTOR GIVEN BY C
	LHLD WBOOT! LXI D,SETSEC! DAD D! PCHL
;
DMA:	;SET DMA ADDRESS TO VALUE OF B,C
	LHLD WBOOT! LXI D,SETDMA! DAD D! PCHL
;
DREAD:	;PERFORM READ OPERATION
	LHLD WBOOT! LXI D,READF! DAD D! PCHL
;
DWRITE:	;PERFORM WRITE OPERATION
	LHLD WBOOT! LXI D,WRITF! DAD D! PCHL
;
START:
	LXI	SP,STACK
RDDSK:	;PRINT PROMPT AND WAIT FOR RESPONSE TO CONTINUE
	CALL INSMSG! CALL CI ;WAIT FOR RESPONSE
	cpi 03! jz boot! cpi 0dh! jnz rddsk
;
	;NEW DISK IS READY, TRY THE COPY OPERATION
	LXI H,TRACK! MVI M,ostrks ;CLEAR THE TRACK NUMBER
	LXI H,TRCOUNT! MVI M,'0'! INX H! MVI M,'0'
;
RDTRK:	;READ THE NEXT SOURCE TRACK, COMPARE WITH 0E5H FOR END
	LXI H,IBUFF! SHLD BUFFA! CALL READTRK
		JZ READOK! CALL READ0MSG! JMP RDDSK
	READOK:
		LDA TRACK! CPI OSTRKS! JC WRTRK ;MAY BE DATA DISK
		;TRACK IN MEMORY, CHECK FOR LAST TRACK
		LXI H,IBUFF! LXI B,TRLEN
		TRCOMP:	MVI A,0E5H! CMP M! JNZ WRTRK
			INX H! DCX B! MOV A,C! ORA B! JNZ TRCOMP
		;END OF COPY, ALL 0E5H'S
		JMP ENDCOPY	;TERMINATE COPY AND RETURN
	;
	;NOT END OF COPY, WRITE TRACK TO DISK FROM IBUFF
	WRTRK:	CALL WRITTRK
		JZ WROK! CALL WRITE0MSG! JMP RDDSK
	WROK:
		;WRITTEN TO DISK, NOW READ IT BACK AND COMPARE
		LXI H,OBUFF! SHLD BUFFA! CALL REREAD
			JZ READ1OK! CALL READ1MSG! JMP RDDSK
		READ1OK:
		LXI H,IBUFF! LXI D,OBUFF! LXI B,TRLEN
		WRCOMP: LDAX D! CMP M! JNZ WRERR
			INX H! INX D! DCX B! MOV A,C! ORA B
			JNZ WRCOMP
		;COMPARE WENT OK, INCREMENT TRACK COUNT AND CYCLE
		LXI H,TRACK! INR M
		MOV A,M! CPI TPD! JNC ENDCOPY ;TERMINATE BY END OF DISK
		LXI H,TRCOUNT+1! INR M! MOV A,M! CPI '9'+1
		JC RDTRK ;OVERFLOW TO HIGH ORDER TRACK NUMBER
		MVI M,'0'! DCX H! INR M! JMP RDTRK
		;
	WRERR:	;VERIFY ERROR
		CALL VERERR! JMP RDDSK
;
;
ENDCOPY:
;	ARRIVE HERE AT END OF COPY TO PRINT FINAL MESSAGE AND BOOT
	LXI D,TRMSG! CALL PRMSG ;NUMBER OF TRACKS
	JMP RDDSK
;
;
;
;	UTILITY SUBROUTINES
CI:	MVI C,CONIN! JMP BDOS ;READ A CHARACTER
;
PRMSG:	MVI C,PBUFF! JMP BDOS ;PRINT A BUFFER
;
;
;
;	PRINT STRINGS
INSMSG:
	LXI D,$+6! JMP PRMSG
	db cr,lf,'DCS-2 Double Density'
	DB CR,LF,'INSERT SOURCE DISK IN A, NEW DISK IN B, TYPE RETURN$'
;
;
VERERR:
	LXI D,$+6! JMP PRMSG
	DB CR,LF,'VERIFICATION ERROR, BAD DISK$'
;
READ0MSG:
	LXI D,$+6! JMP PRMSG
	DB CR,LF,'ERROR ON SOURCE DISK, REPLACE$'
;
WRITE0MSG:
	LXI D,$+6! JMP PRMSG
	DB CR,LF,'CANNOT WRITE NEW DISK, REPLACE$'
;
READ1MSG:
	LXI D,$+6! JMP PRMSG
	DB CR,LF,'CANNOT RE-READ NEW DISK, REPLACE$'
;
;
;	MISCELLANEOUS DATA AREAS
;
TRMSG:	DB	CR,LF
TRCOUNT:
	DB	'00 TRACKS VERIFIED$'
;
SKEWTBL:
	DB	1,19,37,55
	DB	15,33,51,11
	DB	29,47,7,25
	DB	43,3,21,39
	DB	57,17,35,53
	DB	13,31,49,9
	DB	27,45,5,23
	DB	41,10,28,46
	DB	6,24,42,2
	DB	20,38,56,16
	DB	34,52,12,30
	DB	48,8,26,44
	DB	4,22,40,58
	DB	18,36,54,14
	DB	32,50

	DS	32	;STACK
STACK:
TRLEN	EQU	SPT*BPS	;BUFFER SIZE
IBUFF:	DS	TRLEN
OBUFF:	DS	TRLEN

	END	100H
