;
;		MOVE.ASM
;		  V2.1
;	   (revised 6/12/80)
;
;USED TO TRANSFER FILES FROM ONE DISK TO ANOTHER
;ON A 1 DISK SYSTEM, BY READING THE FILE INTO MEMORY.
;ISSUES ERROR MSG IF FILE WON'T FIT. ALSO USEFUL FOR
;TRANSFERRING ONE FILE TO MULTIPLE DISKS. WORKS WITH
;ANY DRIVE - A, B, C, OR D.
;
;***************************************************
;* NOTE: CHECK COMMENTS AT LABEL 'EXIT:' REGARDING *
;*	 REBOOT WHEN EXITING THIS PROGRAM.	   *
;***************************************************
;
;07/23/78 ORIGINALLY WRITTEN BY WARD CHRISTENSEN
;10/20/78 MODIFY TO WRITE MULTIPLE TIMES
;	(FOR EXAMPLE TO MOVE STAT.COM TO 5 NEW DISKS)
;02/24/79 MODIFY TO STORE TO EITHER A: OR B:, AS
;	MOVE IS MUCH QUICKER THAN PIP FOR PEOPLE
;	WITH 2 DRIVE SYSTEMS.
;05/27/79 MODIFY TO CHECK FOR NO FILE NAME AND TO
;	ZERO OUT DISK NAME SO IT WON'T OVERULE THIS
;	PROGRAM.  BY KEITH PETERSEN, W8SDZ.
;08/19/79 REMOVE MACROS TO ALLOW ASSEMBLY WITH
;	ASM.COM. ADD CONDITIONAL ASSEMBLY FOR CP/M
;	ON H8 OR TRS-80.  (KBP)
;08/20/79 FIX TEST TO PROTECT BDOS (WAS WRONG WHEN
;	ALTCPM OPTION CHOSEN).  (KBP).
;11/27/79 FIX DMA PROBLEM FOR MULTIPLE WRITES.
;	ELIMINATE EXTRA PUSH-POPS. (KBP).
;12/04/79 FIX ERROR IN RESETTING DMA TO NORMAL
;	(Thanks to Ward Christensen) (KBP)
;04/20/80 MODIFIED TO WORK WITH EITHER CP/M 1.4 OR CP/M-2.
;	EARLIER VERSION COPIED FILE ATTRIBUTES WHICH PREVENTED
;	MOVING R/O FILES AND MADE CP/M-2 FILES INACCESSABLE
;	UNDER 1.4. (KBP)
;06/12/80 MODIFIED TO REMOVE ATTRIBUTES ON ALL 11 CHARACTERS
;	OF FCB NAME. (KBP)
;
STDCPM	EQU	1	;TRUE FOR STANDARD CP/M
ALTCPM	EQU	0	;TRUE FOR H8 OR TRS-80
;
BASE	SET	0
;
	IF	ALTCPM	;H8 OR TRS-80
BASE	SET	4200H
	ENDIF		;ALTCPM
;
CR	EQU	0DH	;CARRIAGE RETURN
LF	EQU	0AH	;LINE FEED
;
	ORG	BASE+100H
;
START	LDA	FCB+1	;SEE IF FILE NAME THERE
	CPI	' '	;NONE?
	RZ		;IF NONE, RETURN TO CP/M
	LXI	SP,STACK
	XRA	A	;ZERO DISK NAME SO IT WON'T
	STA	FCB	;OVERULE COMMANDS IN THIS PGM.
	CALL	ILPRT
	DB	'MOVE.COM V2.1, 6/12/80'
	DB	CR,LF,0
;
SRCMSG	CALL	ILPRT
	DB	'MOUNT SOURCE DISK, TYPE: A, B, C, OR D ',0
	CALL	GETDISK	;GET DISK NAME
	JC	SRCMSG	;INVALID ANSWER, ASK AGAIN
;
;GOT DISK, OPEN THE INPUT FILE
;
	LXI	D,FCB
	MVI	C,OPEN
	CALL	BDOS
	INR	A	;WAS THE OPEN OK?
	JNZ	OPENOK	;YES
;
;OPEN WAS BAD, EXIT WITH ERROR MESSAGE.
;
	CALL	ERXIT
	DB	'++NO SUCH FILE++',CR,LF,'$'
;
OPENOK	LXI	D,BUFF	;POINT TO BUFFER
READLP	PUSH	D	;SAVE BUFFER ADDRESS
	MVI	C,STDMA
	CALL	BDOS
;READ A SECTOR
	LXI	D,FCB
	MVI	C,READ
	CALL	BDOS
	POP	D	;GET DMA ADDR
	ORA	A	;OK?
	JNZ	EOF	;NOT OK, MUST BE EOF
	LHLD	FCT	;LOAD SECTOR COUNT FOR FILE
	INX	H	;BUMP IT
	SHLD	FCT	;SAVE IT BACK
	LXI	H,80H	;LENGTH OF 1 SECT.
	DAD	D	;CALC NEXT BUFF ADDR
	XCHG		;PUT IT BACK IN DE
;OUT OF MEMORY?
	LDA	BASE+7	;GET BDOS PAGE POINTER
	SUI	2	;MAKE SURE
	CMP	D	;ABOUT TO HIT BDOS?
	JNC	READLP	;NO, LOOP
;
;FILE IS TOO BIG - EXIT PRINTING ERROR MSG.
;
	CALL	ERXIT
	DB	'++FILE WON''T FIT IN MEMORY++$'
;
;GOT RETURN CODE ON READ, SEE IF ERROR OR EOF
;
EOF	LHLD	FCT	;GET SECTOR COUNT
	SHLD	SAVEFCT	;SAVE IT FOR MULTIPLE WRITES
;A HAS RETURN CODE FROM READ
	DCR	A	;EOF?
	JZ	DESTMSG	;YES, ASK FOR DEST. DISK
;
;READ ERROR - EXIT WITH MSG
;
	CALL	ERXIT
	DB	'++READ ERROR++$'
;
;FILE READ INTO MEMORY.  ASK FOR DEST. DISK
;
DESTMSG	LXI	D,BASE+80H ;RESET DMA TO NORMAL
	MVI	C,STDMA
	CALL	BDOS
	CALL	ILPRT
	DB	'C/R TO END, ',CR,LF
	DB	'MOUNT DEST.  DISK, TYPE: A, B, C, OR D ',0
	CALL	GETDISK	;GET A OR B
	JC	DESTMSG	;NEITHER, ASK AGAIN
	LHLD	SAVEFCT	;GET SAVED COUNT
	SHLD	FCT	;SAVE FOR DECREMENT
;
;INIT FOR WRITING THE FILE
;
	XRA	A
	STA	FCBEXT	;ZERO EXTENT #
	STA	FCBSNO	;ZERO SECTOR #
;
;REMOVE ALL FILE ATTRIBUTES
	LXI	H,FCB+1	;POINT TO FILE NAME.TYPE
	MVI	B,11	;NUMBER OF CHARACTERS
;
ZFCBLP	MOV	A,M	;GET CHAR
	ANI	7FH	;ZERO OUT ATTRIBUTE
	MOV	M,A	;RESTORE CHAR TO FCB
	INX	H
	DCR	B	;ONE LESS CHARACTER
	JNZ	ZFCBLP
;
;ERASE ANY FILE BY SAME NAME
	LXI	D,FCB
	MVI	C,ERASE
	CALL	BDOS
;
;MAKE THE FILE
	LXI	D,FCB
	MVI	C,MAKE
	CALL	BDOS
	INR	A
	JZ	BADMAKE	;MAYBE DIRECTORY IS FULL?
;
;WRITE THE FILE TO DISK
;
	LXI	H,BUFF	;POINT TO BUFFER
	SHLD	BUFPTR
WRLP	LHLD	BUFPTR
	LXI	D,BASE+80H
	CALL	MOVE128
	SHLD	BUFPTR	;SAVE THE NEW BUF ADDR
;WRITE THE SECTOR
	LXI	D,FCB
	MVI	C,WRITE
	CALL	BDOS
	ORA	A	;WAS THE WRITE SUCCESSFUL?
	JNZ	WRERR	;NO, EXIT W/ERROR MSG
	LHLD	FCT	;GET FILE'S SECTOR COUNT
	DCX	H	;DECREMENT IT
	SHLD	FCT	;SAVE IT BACK
	MOV	A,H
	ORA	L	;ZERO?
	JNZ	WRLP	;NO, LOOP
;CLOSE THE FILE
	LXI	D,FCB
	MVI	C,CLOSE
	CALL	BDOS
	CALL	ILPRT	;PRINT THE FOLLOWING:
	DB	'++DONE++',CR,LF,0
	JMP	DESTMSG
;
;GOT A WRITE ERROR - EXIT W/ERROR MSG.
;
WRERR	CALL	ERXIT
	DB	'++WRITE ERROR$'
;
;COULDN'T MAKE THE FILE, EXIT W/ERROR MSG.
;
BADMAKE	CALL	ERXIT
	DB	'++CAN''T MAKE OUTPUT FILE$'
;
;INLINE PRINT ROUTINE - CALL ILPRT FOLLOWED
;	BY MESSAGE (ENDING IN 0)
;
ILPRT	MVI	A,CR	;CR..
	CALL	TYPE
	MVI	A,LF	;LF FIRST.
	CALL	TYPE
	XTHL		;SAVE HL, GET MSG ADDR
;
ILPLP	MOV	A,M	;GET CHAR OF MSG
	CALL	TYPE	;TYPE IT
	INX	H	;POINT TO NEXT CHAR
	MOV	A,M	;GET IT
	ORA	A	;IS IT END OF MSG?
	JNZ	ILPLP	;NO, LOOP
	INX	H	;SKIP THE 0
	XTHL		;RESTORE HL, STACK RET ADDR
	RET		;..AND RETURN
;
;TYPE CHAR IN A
;
TYPE	PUSH	B
	PUSH	D
	PUSH	H
	MOV	E,A	;FOR TYPE
	MVI	C,WRCON
	CALL	BDOS
	POP	H
	POP	D
	POP	B
	RET
;
;EXIT WITH ERROR MESSAGE
;
ERXIT	MVI	A,CR
	CALL	TYPE
	MVI	A,LF
	CALL	TYPE
	POP	D	;GET MSG ADDR
	MVI	C,PRINT
	CALL	BDOS
;
;EXIT: ASSUMES DISK IN A: MAY NOW BE DIFFERENT
;SYSTEM SIZE, SO WARM BOOT WOULD NOT WORK.
;JUMPS TO COLD BOOT EPROM ENTRY POINT.
;IF SUCH AN ENTRY POINT IS NOT AVAILABLE,
;CHANGE TO JMP 0000.  THIS WILL WORK IF YOU
;ARE WARM-BOOTING THE SAME SIZED SYSTEM AS
;BEFORE.
;
EXIT	CALL	ILPRT
	DB	CR,LF,'RE-BOOTING '
	DB	'VIA "JMP FC00", '	;<------
	DB	'PRESS RETURN',0
	MVI	C,RDCON
	CALL	BDOS	;GET CHAR.
	CPI	CR	;C/R?
	JNZ	EXIT
	JMP	0FC00H	;COLD BOOT ROM ADDRESS <------
;
;MOVE 128 CHARACTERS
;
MOVE128	MVI	B,128	;SET MOVE COUNT
;
;MOVE FROM (HL) TO (DE) LENGTH IN (B)
;
MOVE	MOV	A,M	;GET A CHAR
	STAX	D	;STORE IT
	INX	H	;TO NEXT "FROM"
	INX	D	;TO NEXT "TO"
	DCR	B	;MORE?
	JNZ	MOVE	;..YES, LOOP
	RET		;..NO, RETURN
;
;ROUTINE TO GET DISK NUMBER (A, B, C, D) THEN
;RESET THE DISK AND LOG IN THAT DISK.
;
GETDISK	MVI	C,RDCON
	CALL	BDOS	;GET CHAR.
	CPI	CR	;JUST RETURN?
	JZ	EXIT	;YES, ALL DONE
	PUSH	PSW	;SAVE CHAR
;RESET DISK, KILLING R/O STATUS
	MVI	C,RESETDK
	CALL	BDOS
	POP	PSW	;GET DISK
	ANI	5FH	;MAKE UPPER CASE
	SUI	'A'	;CALC DISK
	MOV	E,A	;SETUP FOR SELECT
	CPI	4	;A-D?
	CMC		;CY ON = BAD
	RC		;ERROR RETURN
;LOG IN THE APPROPRIATE DISK
SELDISK	MVI	C,SELDK
	CALL	BDOS
	ORA	A	;SHOW NO ERROR
	RET
;
FCT	DW	0	;FILE COUNT
SAVEFCT	DW	0	;SAVED FILE COUNT
BUFPTR	DS	2	;BUFFER POINTER FOR WRITE
;
	DS	64	;STACK AREA
STACK	EQU	$
BUFF	EQU	$
;
;BDOS/CBIOS EQUATES
;
RDCON	EQU	1
WRCON	EQU	2
PRINT	EQU	9
RESETDK	EQU	13
SELDK	EQU	14
OPEN	EQU	15
CLOSE	EQU	16
ERASE	EQU	19
READ	EQU	20
WRITE	EQU	21
MAKE	EQU	22
STDMA	EQU	26
BDOS	EQU	BASE+5
FCB	EQU	BASE+5CH 
FCBEXT	EQU	FCB+12
FCBSNO	EQU	FCB+32
;
	END
