;	BACKUP - DISK BACKUP UTILITY FOR CP/M
;
	ORG	0100H
	JMP	BACKUP
;
SINGLE	EQU	1
;
;	ONE OF THE FOLLOWING LINES SHOULD BE COMMENTED OUT
;
DRIVES	DB	1		;SINGLE DRIVE VERSION
;DRIVES	DB	2		;MULTI DRIVE VERSION
;
	DB	'(C) 1980 - N D H HAMMOND'
PRGNAME	DB	'BACKUP VSN 1.1 OF 20JUL80',0DH,0AH,'$'
;
;	VSN 1.0 12JAN80
;	VSN 1.1 MODIFIED FOR DUAL DRIVE OPTION
;
;
	;CONSTANTS
TRUE	EQU	0FFH
LF	EQU	0AH
CR	EQU	0DH
EOM	EQU	'$'
;
	;SYSTEM VALUES
BOOT	EQU	0000H		;REBOOT ADDRESS
FSIZE	EQU	TRUE		;8IN DISK
MINI	EQU	NOT(FSIZE)	;5IN DISK
	IF	FSIZE
NSCTRS	EQU	1AH		;SECTRS PER TRK 
NTRKS	EQU	4DH		;TRACKS PER DISK
	ENDIF
	IF	MINI
NSCTRS	EQU	12H
NTRKS	EQU	23H
	ENDIF
;
;	MAIN PROGRAM
;
BACKUP	LXI	SP,STACK
	LXI	D,PRGNAME
	CALL	WRITESTRING
COPYLP	LDA	DRIVES
	CPI	SINGLE
	JZ	SDRV
	LXI	D,DRVMSG
	CALL	WRITESTRING
	CALL	WAIT
SDRV	CALL	INITVAR
	CALL	HOME
REPEAT	CALL	SOURCEDISK
	CALL	LOADBUF
	CALL	DESTDISK
	CALL	DUMPBUF
	LDA	FINISH
	CPI	TRUE
	JNZ	REPEAT
	LXI	D,TERMSG
	CALL	WRITESTRING
ENDCOPY	CALL	CHKMORE
	LDA	MULTI
	CPI	TRUE
	JZ	COPYLP
	CALL	HOME
	JMP	BOOT
;
;	SUBROUTINBS
;
INITVAR		;INITIALIZE VARIABLES
	XRA	A
	STA	FINISH	;FINISH:=FÁLSE
	STA	TRK	;TRK:=0
	INR	A
	STA	SEC	;SEC:=1
	LHLD	BOOT+1
	MVI	L,0
	SHLD	EXTENT	;EXTENT:=^CBIOS
	RET
;
;
LOADBUF		;LOAD BUFFER FROM SOURCE DISK
	LDA	TRK		;SAVE TRK AND SEC
	STA	TRKSAVE
	LDA	SEC
	STA	SECSAVE
	LXI	H,BUFFER	;INITIALIZE BUFFPT
	SHLD	BUFFPT
LOADLP	PUSH	H
	POP	B
	CALL	SETDMA		;SETUP FOR READ
	LDA	TRK
	MOV	C,A
	CALL	SETTRK
	LDA	SEC
	MOV	C,A
	CALL	SETSEC
	CALL	READ
	JNZ	READERR
	CALL	INCTS		;UPDATE TRK & SEC
	RZ			;LAST TRACK READ
	LHLD	BUFFPT		;UPDATE BUFFPT
	LXI	B,80H
	DAD	B
	SHLD	BUFFPT
	LXI	B,EXTENT
	CALL	COMPARE		;CHECK FOR FULL BUFFER
	JNZ	LOADLP
	RET
;
;
DUMPBUF		;DUMP BUFFER TO DEST DISK
	LDA	TRKSAVE		;RESTORE TRK & SEC
	STA	TRK
	LDA	SECSAVE
	STA	SEC
	LXI	H,BUFFER	;INITIALIZE BUFFPT
	SHLD	BUFFPT
DUMPLP	PUSH	H
	POP	B
	CALL	SETDMA		;SETUP FOR WRITE
	LDA	TRK
	MOV	C,A
	CALL	SETTRK
	LDA	SEC
	MOV	C,A
	CALL	SETSEC
	CALL	WRITE
	JNZ	WRITERR
	CALL	INCTS		;UPDATE TRK & SeC
	JNZ	DMPMORE
	MVI	A,TRUE		;LAST TRACK WRITTEN
	STA	FINISH
	RET
DMPMORE	LHLD	BUFFPT		;UPDATE BUFFPT
	LXI	B,80H
	DAD	B
	SHLD	BUFFPT
	LXI	B,EXTENT
	CALL	COMPARE		;CHECK FOR FULL BUFFER
	JNZ	DUMPLP
	RET
;
;
CHKMORE		;CHECK FOR ANOTHER DISK
	MVI	A,TRUE
	STA	MULTI
	CALL	CONIN
	CPI	'Y'
	RZ
	CPI	'Y'+20H
	RZ
	;IF NOT, REBOOT CP/M
	XRA	A
	STA	MULTI
	LXI	D,RBMSG
	CALL	WRITESTRING
	CALL	WAIT
	RET
;
;
COMPARE		;COMPARE BC^ AND HL - SET FLAGS
	INX	B
	LDAX	B
	DCX	B
	CMP	H
	RNZ
	LDAX	B
	CMP	L
	RET
;
;
SOURCEDISK	;SELECT OR PROMPT FOR SOURCE DISK
	LDA	DRIVES
	CPI	SINGLE
	JZ	SDPROMPT
	MVI	C,1
	CALL	SELDRV
	RET
SDPROMPT	;ADVISE OPERATOR, WAIT FOR RESPONSE,
	LXI	D,SDMSG
	CALL	WRITESTRING
	CALL	WAIT
	RET
;
;
DESTDISK	;SELECT OR PROMPT FOR DEST DISK
	LDA	DRIVES
	CPI	SINGLE
	JZ	DDPROMPT
	MVI	C,0
	CALL	SELDRV
	RET
DDPROMPT	;ADVISE OPERATOR, WAIT FOR RESPONSE,
	LXI	D,DDMSG
	CALL	WRITESTRING
	CALL	WAIT
	RET
;
;
WAIT		;WAIT FOR OPERATOR TO TYPE RETURN
	CALL	CONIN
	CPI	03H
	JZ	BOOT
	CPI	CR
	JNZ	WAIT
	RET
;
;
WRITESTRING	;WRITE STRING AT DE^ ON CONSOLE
	LDAX	D
	INX	D
	CPI	EOM
	RZ
	PUSH	D
	MOV	C,A
	CALL	CONOUT
	POP	D
	JMP	WRITESTRING
;
;
INCTS	;INCREMENT TRACK AND SECTOR ADDRESS
	;RETURN WITH Z RESET IF ADDRESS VALID
	LDA	SEC
	INR	A
	CPI	NSCTRS+1
	JZ	NEWTRK
	STA	SEC
	RET
NEWTRK	MVI	A,1
	STA	SEC
	LDA	TRK
	INR	A
	CPI	NTRKS
	RZ			;PAST LAST TRACK
	STA	TRK
	RET
;
;
READERR	;DISK ERROR ON READ
	LXI	SP,STACK
	LXI	D,REMSG
	CALL	WRITESTRING
	JMP	ENDCOPY
;
;
WRITERR	;DISK ERROR ON WRITE
	LXI	SP,STACK
	LXI	D,WEMSG
	CALL	WRITESTRING
	JMP	ENDCOPY
;
;	I/O ROUTINES
;
;	WARNING - THESE ARE LOW LEVEL ROUTINES
;	WHICH DIRECTLY ACCESS THE CP/M CBIOS.  THEY
;	MAY REQUIRE MODIFICATION WITH NON STANDARD
;	SYSTEMS.
;
;
CONIN	;READ CHAR FROM CONSOLE (A-REG)
	LHLD	BOOT+1
	MVI	L,09H
	PCHL
;
;
CONOUT	;WRITE CHAR TO CONSOLE (C-REG)
	LHLD	BOOT+1
	MVI	L,0CH
	PCHL
;
;
HOME	;HOME DISK TO TRACK 00
	LHLD	BOOT+1
	MVI	L,18H
	PCHL
;
;
SELDRV	;SET DRIVE (C-REG)
	LHLD	BOOT+1
	MVI	L,1BH
	PCHL
;
;
SETTRK	;SET TRACK (C-REG)
	LHLD	BOOT+1
	MVI	L,1EH
	PCHL
;
;
SETSEC	;SET SECTOR (C-REG)
	LHLD	BOOT+1
	MVI	L,21H
	PCHL
;
;
SETDMA	;SET TRANSFER ADDRESS (BC-REG)
	LHLD	BOOT+1
	MVI	L,24H
	PCHL
;
;
READ	;READ SECTOR TO DMA ADDRESS
	LHLD	BOOT+1
	MVI	L,27H
	PCHL
;
;
WRITE	;WRITE A SECTOR FROM DMA ADDRESS
	LHLD	BOOT+1
	MVI	L,2AH
	PCHL
;
;
;	DATA AREA
;
EXTENT	DS	2	;EXTENT OF COPY BUFFER
MULTI	DS	1	;MULTIPLE COPY MODE FLAG
BUFFPT	DS	2	;BUFFER POINTER
FINISH	DS	1	;LAST BUFFER FLAG
TRK	DS	1	;CURRENT TRACK
SEC	DS	1	;CURRENT SECTOR
TRKSAVE	DS	1	;TRACK TO START DUMP
SECSAVE	DS	1	;SECTOR TO START DUMP
DRVMSG	DB	'INSERT SOURCE DISK IN DRIVE B'
	DB	' AND BACKUP DISK IN DRIVE A',CR,LF
	DB	'<CR> TO CONTINUE',CR,LF,EOM
SDMSG	DB	CR,LF
	DB	'INSERT SOURCE DISK, <CR> TO CONTINUE'
	DB	CR,LF,EOM
DDMSG	DB	'INSERT DEST DISK, <CR> TO CONTINUE'
	DB	CR,LF,EOM
TERMSG	DB	'COPY COMPLETE',CR,LF
	DB	'ANY MORE DISKS TO BACKUP?',CR,LF,EOM
RBMSG	DB	CR,LF,'<CR> TO REBOOT CP/M',CR,LF,EOM
REMSG	DB	'READ ERROR ON DRIVE A',CR,LF,EOM
WEMSG	DB	'WRITE ERROR ON DRIVE B',CR,LF,EOM
	DS	20H	;MINIMUM STACK SPACE
	;SET START OF BUFFER TO MULTIPLE OF SECTOR SIZE
	ORG	(($ + 7FH) / 80H) * 80H
STACK	EQU	$	;GROWS DOWN
BUFFER	EQU	$	;FILLS REST OF MEMORY TO CBIOS
	END
