;**********************************************************************
;	SINGLE DENSITY DISK COPY PROGRAM FOR TARBELL DD CONTROLLER
;**********************************************************************
;
;	THIS PROGRAM IS USED TO COPY SINGLE DENSITY DISKS FROM
;	DRIVE A: TO DRIVE B:. THE BIOS PRIMITIVES ARE ACCESSED
;	DIRECTLY FOR SPEED. COMMANDS ACCEPTED BY THIS PROGRAM
;	AND THE TRACKS CORRESPONDINGLY  COPIED ARE AS FOLLOWS:
;
;		COPY ALL		TRACKS 00 TO 76
;		COPY SYSTEM		TRACKS 00 TO 01
;		COPY DATA		TRACKS 02 TO 76
;
;		================
;		MICHAEL J. KARAS
;		MICRO RESOURCES
;		These days Mike can be reached at mkaras@carousel-design.com” (March 23, 2009)
;		==============
;
;
;**********************************************************************

DCOM	EQU	0F8H	;DISK COMMAND PORT
WAIT	EQU	0FCH	;WAIT COMMAND


	ORG	100H
;
;
	JMP	VECTOR
;
;
;
HOME:	JMP	DUMYADR
SELDSK:	JMP	DUMYADR
SETTRK:	JMP	DUMYADR
SETSEC:	JMP	DUMYADR
SETDMA:	JMP	DUMYADR
READ:	JMP	DUMYADR
WRITE:	JMP	DUMYADR
;
;EQUATES
;
EXITCPM	EQU	0
LASTSEC	EQU	26
BDOS	EQU	5
;
MSG:	DB	0DH,0AH,'MICRO RESOURCES SINGLE DENSITY DISKETTE COPY PROGRAM'
	DB	0DH,0AH,'$'
MESGA:	DB	0DH,0AH,'COMPARE ERROR ON TRACK $'
MESGB:	DB	'(HEX) SECTOR $'
MESGC:	DB	'PERMANENT $'
MESGD:	DB	'PERMANENT SOURCE DISK ERROR EXIT $'
MESGE:	DB	'PERMANENT DESTINATION DISK ERROR EXIT $'
SIGNON:	DB	0DH,0AH,'INSERT DISK SOURCE IN DRIVE A,'
	DB	'AND DISK DESTINATION IN DRIVE B'
SINOFF:	DB	0DH,0AH
	DB	0DH,0AH,'COPY OR QUIT (C OR Q) ? $'
CRLF:	DB	0DH,0AH,'$'
;
;
PRTHEX:	PUSH	PSW	;SAVE FOR LSN
	RAR		;SHIFT MSNIBLE TO LSN
	RAR
	RAR
	RAR
	CALL	PRTNBL	;PRINT IT
	POP	PSW	;NOW FOR LSN
PRTNBL:	ANI	0FH
	ADI	30H	;SHIFT TO ASCII VALUE
	CPI	3AH	;OVER 9?
	JC	SML
	ADI	7	;SHIFT TO ALPHA
SML:
	MOV	E,A	;FOR BDOS CALL
	MVI	C,2	;WRITE CONSOLE FUNCTION
	CALL	BDOS
	RET
;
;
COPY:	MVI	C,0
	CALL	SELDSK	;SELECT DISK A
	LDA	TRKSRT	;FIRST TRACK TO MOVE
	STA	TRK	;MAKE CURRENT
	MOV	C,A
	CALL	SETTRK	;AND SELECT IT ON DISK A
	MVI	C,1
	CALL	SELDSK	;ALSO B
	LDA	TRKSRT	;FIRST TRACK TO MOVE
	MOV	C,A
	CALL	SETTRK	;AND SELECT IT ON DISK B
RDLOOP:	MVI	C,0
	XRA	A
	STA	CMPERR
	CALL	SELDSK
	LDA	TRK	;GET TRACK
	MOV	C,A
	CALL	READT	;READ ENTIRE TRACK
RETRYW:
	MVI	C,1
	CALL	SELDSK
	LDA	TRK
	MOV	C,A
	CALL	WRITET	;WRITE TRACK
	LDA	TRK
	MOV	C,A
	CALL	COMPT	;REREAD AND COMPARE
	JNZ	RETRYW	;RETRY IF ERR
	LDA	TRK
	INR	A
	STA	TRK
	LXI	H,TRKSRT+1	;POINT TO LAST TRACK+1 STORAGE
	CMP	M	;ARE WE DONE?
	JNZ	RDLOOP	;LOOP IF NOT
	RET
;
;
COMPT:	LXI	H,BUF1
	CALL	RT2	;REREAD INTO BUF1
	LXI	H,BUF0
	LXI	D,BUF1
	LXI	B,128*LASTSEC
CMPLP:	LDAX	D
	CMP	M
	JNZ	CERR
	INX	H
	INX	D
	DCR	C
	JNZ	CMPLP
	DCR	B	;ARE WE AT END OF BUFFER?
	JNZ	CMPLP
	RET
CERR:	PUSH	B
	LXI	D,MESGA
	MVI	C,9	;BDOS PRINT BUFFER FUNCTION CALL
	CALL	BDOS
	LDA	TRK
	CALL	PRTHEX
	LXI	D,MESGB
	MVI	C,9	;BDOS PRINT BUFFER FUNCTION CALL
	CALL	BDOS
	POP	H	;PUSHED FROM B
	DAD	H	;COMPUTE SECTOR IN ERROR
	LXI	D,0FF00H
	DAD	D
	MVI	A,27
	SUB	H
	CALL	PRTHEX	;PRINT SECTOR
	LDA	CMPERR
	INR	A
	STA	CMPERR	;INCREMENT ERROR COUNT
	CPI	10
	RNZ
	MVI	C,9	;BDOS PRINT BUFFER FUNCTION CALL
	LXI	D,MESGC
	CALL	BDOS
	XRA	A
	RET
;
DMASET:	PUSH	B
	MOV	C,L
	MOV	B,H
	CALL	SETDMA
	POP	B
	RET
;
;
READT:	LXI	H,BUF0	;TRACK # IN C
RT2:	SHLD	DMAAD
	CALL	DMASET
	CALL	SETTRK
	MVI	C,1
	PUSH	B
	CALL	SETSEC
	CALL	READ
	JMP	RT4
RT3:	PUSH	B
	CALL	SETSEC
	CALL	READ
RT4:	RAR		;WAS A BIT 0 SET BY DISK ERROR?
	CC	FAILR
	LHLD	DMAAD
	LXI	D,128
	DAD	D
	SHLD	DMAAD
	CALL	DMASET
	POP	B
	MVI	A,LASTSEC
	CMP	C
	RZ
	INR	C
	JMP	RT3
;
;
WRITET:	LXI	H,BUF0	;TRACK # IN C
WT2:	SHLD	DMAAD
	CALL	DMASET
	CALL	SETTRK
	MVI	C,1
	PUSH	B
	CALL	SETSEC
	CALL	WRITE
	JMP	WT4
WT3:	PUSH	B
	CALL	SETSEC
	CALL	WRITE
WT4:	RAR		;WAS A BIT 0 SET BY DISK ERROR?
	CC	FAILW
	LHLD	DMAAD
	LXI	D,128
	DAD	D
	SHLD	DMAAD
	CALL	DMASET
	POP	B
	MVI	A,LASTSEC
	CMP	C
	RZ
	INR	C
	JMP	WT3
CMPERR:	DB	0	;NUMBER OF COMPARE ERRORS
TRK:	DB	0
DMAAD:	DS	2
STK:	DS	32
STKTOP:	DB	0
;
;
;
BUF0:	DS	128*LASTSEC
BUF1:	DS	128*LASTSEC
;
;
;
VECTOR:	MVI	C,9
	LXI	D,MSG
	CALL	BDOS
;
;
;
;SET UP JUMP VECTORS FOR  ACCESS TO BIOS PRIMITIVES
;
BASE	EQU	0	;FIND WBOOT JMP ADDRESS AT RST0
DUMYADR	EQU	0	;WHO CARES?
;
	LHLD	BASE+1	;GET WBOOT ADDRESS
	SPHL		;SAVE IT IN SP FOR DAD
;
	LXI	H,15H
	DAD	SP
	SHLD	HOME+1
;
	LXI	H,18H
	DAD	SP
	SHLD	SELDSK+1
;
	LXI	H,1BH
	DAD	SP
	SHLD	SETTRK+1
;
	LXI	H,1EH
	DAD	SP
	SHLD	SETSEC+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
;
RUNTYP:	JMP	BUFMSR
;
;
;
;THIS ROUTINE SETS UP THE PARAMETERS FOR THE COPY ROUTINE.
;COPY CAN BE USED TO TRANSFER:	SYS	TRACKS  0- 1
;				DAT	TRACKS  2-76
;				ALL	TRACKS	0-76
;THE ROUTINE SEARCHES THE DEFAULT BUFFER AT 80H FOR THE
;RUN PARAMETER TO BE USED
;ROUTINE EQUATES
TBUFF	EQU	80H
;DATA TABLES
SYSMSG:	DB	'YSTEM$'	;SYSTEM MESSAGE
DATMSG:	DB	'ATA$'		;DATA MESSAGE
ALLMSG:	DB	'LL$'		;ALL MESSAGE
TRKSRT:	DW	0		;STORAGE FOR FIRST AND LAST+1 TRACK NUMBERS
CMDER1:	DB	'COMMAND "COPY$'
CMDER2:	DB	'" HAS SYNTAX ERROR',0DH,0AH,'$'
CMDINF:	DB	'THIS PROGRAM IS INITIATED WITH THE COMMAND',0DH,0AH
	DB	'"COPY SYSTEM", "COPY DATA" OR "COPY ALL"$'
DONMSG:	DB	0DH,0AH,'COPY COMPLETE$'
;FIRST WE MEASURE THE INPUT BUFFER MESSAGE
;AND DELIMIT IT WITH A $ PER BDOS CALL 9
BUFMSR:	LXI	H,TBUFF
	XRA	A		;CLEAR ACC.
	ADD	M		;GET MESSAGE SIZE
	JZ	NOMSG		;NONE FOUND
	INX	H		;ADD FOR ADDR. PAST MESSAGE
	MVI	B,0		;EMPTY FOR DAD
	MOV	C,A
	DAD	B		;ADD CHARACTER COUNT TO HL
	MVI	M,'$'		;END BUFFER CHARACTER
;NEXT IS A TEST FOR WHICH MESSAGE IS PRESENT
	LDA	TBUFF+2		;FIRST CHARACTER ADDRESS
	CPI	'S'
	JZ	SYSSET
	CPI	'D'
	JZ	DATSET
	CPI	'A'
	JZ	ALLSET
	JMP	BADMSG		;FIRST CHARACTER NOT ONE OF 3 PERMITTED
SYSSET:
	LXI	D,SYSMSG
	MVI	C,6
	CALL	MSGTST
	MVI	L,0		;FIRST TRACK TO TRANSFER
	MVI	H,2		;LAST TRACK PLUS ONE
	JMP	PUTPAR
DATSET:
	LXI	D,DATMSG
	MVI	C,4
	CALL	MSGTST
	MVI	L,2		;FIRST TRACK TO TRANSFER
	MVI	H,77		;LAST TRACK PLUS ONE
	JMP	PUTPAR
ALLSET:
	LXI	D,ALLMSG
	MVI	C,3
	CALL	MSGTST
	MVI	L,0		;FIRST TRACK TO TRANSFER
	MVI	H,77		;LAST TRACK PLUS ONE
PUTPAR:	SHLD	TRKSRT		;PUT PARAMETERS IN TRKSRT AND TRKSRT+1
	LXI	D,SIGNON
AGIN:	MVI	C,9
	CALL	BDOS
	MVI	C,1
	CALL	BDOS
	CPI	'Q'
	MVI	C,0		;SELECT DISK 0 IF DONE
	PUSH	PSW
	CZ	SELDSK
	POP	PSW
	JZ	EXITCPM
	CPI	'C'
	JNZ	AGIN1
	LXI	D,CRLF
	MVI	C,9
	CALL	BDOS
	CALL	COPY		;MAIN ROUTINE
	LXI	D,DONMSG	;SAY WE'RE DONE
	MVI	C,9
	CALL	BDOS
	CALL	RESTORE		;RESTORE THE DRIVES TO TRACK ZERO
AGIN1:	LXI	D,SINOFF	;GIVE THEM THE COPY OR QUIT MESSAGE
	JMP	AGIN		;WANT TO TRY AGAIN?
MSGTST:	LXI	H,TBUFF+3
	LDAX	D
	CMP	M		;SAME AS MESSAGE?
	JNZ	BADMSG
	INX	H
	INX	D
	DCR	C		;REDUCE CHARACTER COUNTER
	RZ			;FINISHED OK
	JMP	MSGTST+3	;CHECK OUT NEXT CHARACTER
BADMSG:	LXI	D,CMDER1
	MVI	C,9
	CALL	BDOS
	LXI	D,TBUFF+1		;PRINT ERRONEOUS COMMAND
	MVI	C,9
	CALL	BDOS
	LXI	D,CMDER2
	MVI	C,9
	CALL	BDOS
NOMSG:	LXI	D,CMDINF
	MVI	C,9
	CALL	BDOS
	JMP	EXITCPM
FAILR:	LXI	D,MESGD
	JMP	DIE
FAILW:	LXI	D,MESGE
	MVI	C,9		;BDOS PRINT BUFFER FUNCTION CALL
DIE:	CALL	BDOS
	CALL	RESTORE
	JMP	EXITCPM
;
;
;
RESTORE:	MVI	A,0B2H	;RESTORE DRIVE A
	CALL	TRK00
	MVI	A,0A2H	;RESTORE DRIVE B
	CALL	TRK00
	RET
;
;
;
TRK00:	OUT	WAIT
	MVI	A,0F2H
	OUT	DCOM
	IN	WAIT
	RET
;
;
;
	END

