;
;		   FROMHARD.ASM ver 1.2
;		 by Keith Petersen, W8SDZ
;	     	     (revised 9/26/80)
;
;This program will transfer files from CP/M on hard disk
;to CP/M on floppy disk.  (It can also be used for transfers
;from 8" floppy to 5-1/4" minifloppy.)
;	
;To do this you must bring up the floppy CP/M as a small
;system (say 24k).  The system location isn't important so
;long as it does not overwrite the larger system in use by
;the hard disk.  It is assumed that the user's system allows
;both disk controller boards to be used without conflict.
;
;
;		USING THIS PROGRAM
;
; 1 - Bring up the hard disk CP/M as a large system (eg. 56k).
; 2 - Cold boot the floppy CP/M.  Log into the drive you will
;     be transferring files to, then run this program.
;
;COMMANDS:
;	FROMHARD filename.type	 ;gets file from default drive
;	FROMHARD B:filename.type ;gets file from B:
;	FROMHARD *.*		 ;gets all files
;	FROMHARD B:*.*		 ;gets all files from B:
;
;All normal ambiguous file names are allowed. Files written to
;the floppy disk will go to the default drive.
;
FALSE	EQU	0
TRUE	EQU	NOT FALSE
;
;CONDITIONAL ASSEMBLY SWITCHES FOR CP/M VERSION
;	(only one should be true)
;
CPM14	EQU	FALSE	;CP/M VERSION 1.4
CPM2	EQU	TRUE	;CP/M VERSION 2.x
;
;OTHER CONDITIONAL ASSEMBLY SWITCHES
;
DJ2D	EQU	FALSE	;TRUE IF BIG SYSTEM IS DISCUS 2D FLOPPY
REPORT	EQU	FALSE	;TRUE TO REPORT READS AND WRITES
			;(nice, but slows down transfers)
;
;EQUATES
;
MSIZE	EQU	56	;PUT BIG SYSTEM MEMORY SIZE HERE
;
	IF	CPM14
BIAS	EQU	(MSIZE-16)*1024
CCP	EQU	BIAS+2900H	;BASE OF CCP
	ENDIF			;CP/M 1.4
;
	IF	CPM2 AND (NOT DJ2D)
BIAS	EQU	(MSIZE-20)*1024
CCP	EQU	BIAS+3400H	;BASE OF CCP
	ENDIF			;STANDARD CP/M 2.x
;
	IF	CPM2 AND DJ2D
BIAS	EQU	(MSIZE-20)*1024
CCP	EQU	BIAS+2D00H	;BASE DISCUS 2D CCP
	ENDIF			;CP/M 2.x ON DISCUS 2D
;
SRC$BDOS EQU	CCP+806H   ;SENDING BDOS VECTOR
;
BELL	EQU	7	;BELL CHARACTER
TAB	EQU	9	;TAB CHARACTER
CR	EQU	0DH	;CARRIAGE RETURN
LF	EQU	0AH	;LINE FEED
;
;BDOS/CBIOS EQUATES
;
WBOOT	EQU	0	;WARM BOOT ENTRY ADRS
WRCON	EQU	2	;WRITE CHARACTER TO CONSOLE
BDOS	EQU	0005H	;THE RECEIVING BDOS VECTOR
PRINT	EQU	9	;PRINT STRING (DE) UNTIL '$'
OPEN	EQU	15	;OPEN FILE
CLOSE	EQU	16	;CLOSE FILE
SRCHF	EQU	17	;SEARCH DIR FOR FIRST OCCUR.
SRCHN	EQU	18	;SEARCH DIR FOR NEXT OCCUR.
DELETE	EQU	19	;ERASE FILE
READ	EQU	20	;READ RECORD
WRITE	EQU	21	;WRITE RECORD
MAKE	EQU	22	;MAKE FILE
STDMA	EQU	26	;SET DMA ADRS
FCB	EQU	5CH	;DEFAULT FILE CONTROL BLOCK
FCBEXT	EQU	FCB+12	;EXTENT BYTE IN FCB
FCBRNO	EQU	FCB+32	;RECORD NUMBER IN FCB
;
NOERR	EQU	0	;NO ERROR
EOF	EQU	1	;END OF FILE
NTFND	EQU	255	;NOT FOUND
NOMAKE	EQU	255	;CAN'T MAKE FILE
BDCLOS	EQU	255	;BAD FILE CLOSE
;
;	THIS IS THE START OF THE PROGRAM.
;
	ORG	100H
;
START	LDA	FCB+1
	CPI	' '	;SEE IF FILENAME THERE
	JNZ	SIGNON
	CALL	ILPRT	;PRINT:
	DB	CR,LF,'++NO FILE NAME SPECIFIED++',0
	RET		;EXIT TO CP/M
;
SIGNON:	LXI	SP,STACK  ;SET STACK POINTER
	CALL	ILPRT	;PRINT:
	DB	CR,LF,'HARD DISK to FLOPPY',CR,LF
	DB	'multiple file transfer program',CR,LF,0

MORE:	CALL	MFNAME	;SEE IF FILE IS IN DIRECTORY
	JNC	MOVNAM	;ANOTHER FILE FOUND, GET IT
	LDA	MFFLG1	;NOTHING FOUND, CHECK...
	ORA	A	;... FIRST TIME FLAG
	JZ	DONE	;AT LEAST ONE WAS FOUND
	CALL	EXIT
	DB	'++FILE NOT FOUND++$'
;
DONE:	CALL	EXIT
	DB	CR,LF,'DONE$'
;
;MOVE FILENAME FROM FCB TO FNAME AND PRINT IT
;
MOVNAM:	LXI	H,FCB+1
	LXI	D,FNAME
	MVI	B,8	;8 CHARS IN FILE NAME
	CALL	MOVER
	LXI	H,FCB+9
	LXI	D,FNAME+9
	MVI	B,3	;3 CHARS IN FILE TYPE
	CALL	MOVER
	CALL	ILPRT	;PRINT:
	DB	CR,LF,'--> FILE: '
FNAME:	DB	'XXXXXXXX.XXX'
	DB	CR,LF,0
;
;SAVE FIRST FCB FOR USE LATER AS DESTINATION FILE NAME
	MVI	B,11	   ;NUMBER OF CHARACTERS TO MOVE
	LXI	H,FCB+1	   ;...FROM FIRST FCB
	LXI	D,NEWFCB+1 ;...TO NEWFCB (USE DEFAULT DRIVE)
	CALL	MOVER
;
;OPEN THE SOURCE FILE
	LXI	D,FCB
	MVI	C,OPEN
	CALL	SRC$BDOS
	CPI	NTFND	;NOT FOUND?
	JNZ	OPENOK
	CALL	EXIT
	DB	BELL
	DB	'++CAN''T OPEN FILE ON SOURCE DISK++$'
;
;OPEN THE DESTINATION FILE
;
OPENOK:	CALL	ILPRT	;PRINT:
	DB	'Opening file on destination disk',0
	LXI	D,NEWFCB
	MVI	C,DELETE	;ERASE ANY OLD FILE
	CALL	BDOS
	LXI	D,NEWFCB
	MVI	C,MAKE		;MAKE THE NEW ONE
	CALL	BDOS
	CPI	NOMAKE
	JNZ	RDLOOP
	CALL	EXIT
	DB	BELL
	DB	'++CANNOT CREATE FILE ON DESTINATION DISK++$'
;
;READ A SECTOR FROM BIG DISK
;
RDLOOP:	EQU	$
;
	IF	REPORT
	CALL	ILPRT	;PRINT:
	DB	TAB,'Reading sector from source disk',0
	ENDIF		;REPORT
;
	LXI	D,80H
	MVI	C,STDMA	;SET DMA TO 80H
	CALL	SRC$BDOS
	LXI	D,FCB
	MVI	C,READ	;READ A RECORD
	CALL	SRC$BDOS
	CPI	NOERR
	JZ	WRLOOP	;NO ERROR, GO WRITE SECTOR
	CPI	EOF
	JZ	TDONE	;END OF FILE, GO CLOSE IT
	CALL	EXIT
	DB	BELL
	DB	'++READ ERROR ON SOURCE DISK++$'
;
;WRITE A SECTOR TO SMALL DISK
;
WRLOOP:	EQU	$
;
	IF	REPORT
	CALL	ILPRT	;PRINT:
	DB	TAB,'Writing sector to destination disk',0
	ENDIF		;REPORT
;
	LXI	D,80H
	MVI	C,STDMA		;SET DMA TO 80H
	CALL	BDOS
	LXI	D,NEWFCB
	MVI	C,WRITE		;WRITE A RECORD
	CALL	BDOS
	CPI	NOERR
	JZ	RDLOOP
	CALL	EXIT
	DB	BELL
	DB	'++WRITE ERROR ON DESTINATION DISK++$'
;
TDONE:	CALL	ILPRT	;PRINT:
	DB	'Closing file on destination disk now',0
	LXI	D,NEWFCB
	MVI	C,CLOSE		;CLOSE DESTINATION FILE
	CALL	BDOS
	CPI	BDCLOS
	JNZ	MORE		;ANOTHER FILE?
	CALL	EXIT
	DB	BELL
	DB	'++BAD CLOSE ON DESTINATION DISK++$'
;
;PRINT MESSAGE THEN EXIT TO CP/M WARM BOOT
;
EXIT:	POP	D
	MVI	C,PRINT
	CALL	BDOS
	JMP	WBOOT
;
;INLINE PRINT ROUTINE
;
ILPRT	XTHL		;SAVE HL, GET MSG
;
ILPLP	MOV	A,M	;GET CHAR
	CALL	TYPE	;OUTPUT IT
	INX	H	;POINT TO NEXT
	MOV	A,M	;TEST
	ORA	A	;..FOR END
	JNZ	ILPLP
	MVI	A,CR	;CARRIAGE RETURN
	CALL	TYPE
	MVI	A,LF	;LINE FEED
	CALL	TYPE
	XTHL		;RESTORE HL, RET ADDR
	RET		;RET PAST MSG
;
TYPE	PUSH	B
	PUSH	D
	PUSH	H
	MOV	E,A	;CHAR TO E FOR CP/M
	MVI	C,WRCON	;WRITE TO CONSOLE
	CALL	BDOS
	POP	H
	POP	D
	POP	B
	RET
;
;MULTI-FILE ACCESS SUBROUTINE.  ALLOWS PROCESSING
;OF MULTIPLE FILES (I.E. *.ASM) FROM DISK.  THIS
;ROUTINE BUILDS THE PROPER NAME IN THE FCB EACH
;TIME IT IS CALLED. CARRY IS SET IF NO MORE NAMES
;CAN BE FOUND. THE ROUTINE IS COMMENTED IN PSEUDO
;CODE, EACH PSEUDO CODE STATEMENT IS IN <<...>>
;
MFNAME:	;<<INIT DMA ADDR, FCB>>
	MVI	C,STDMA
	LXI	D,80H
	CALL	SRC$BDOS
	XRA	A
	STA	FCBEXT
	STA	FCBRNO
;<<IF FIRST TIME>>
	LDA	MFFLG1
	ORA	A
	JZ	MFN01
;<<SAVE THE REQUESTED NAME>>
;SAVE ORIG REQ
	LXI	H,FCB
	LXI	D,MFREQ
	MVI	B,12
	CALL	MOVER
	LDA	FCB
	STA	MFCUR	;SAVE DISK IN CURR FCB
;<<SRCHF REQ NAME>>
	LXI	H,MFREQ
	LXI	D,FCB
	MVI	B,12
	CALL	MOVER
	MVI	C,SRCHF
	LXI	D,FCB
	CALL	SRC$BDOS
;<<ELSE>>
	JMP	MFN02
;
MFN01:	;<<SRCHF CURR NAME>>
	LXI	H,MFCUR
	LXI	D,FCB
	MVI	B,12
	CALL	MOVER
	MVI	C,SRCHF
	LXI	D,FCB
	CALL	SRC$BDOS
;<<SRCHN REQ NAME>>
	LXI	H,MFREQ
	LXI	D,FCB
	MVI	B,12
	CALL	MOVER
	MVI	C,SRCHN
	LXI	D,FCB
	CALL	SRC$BDOS
;<<ENDIF>>
MFN02:	;<<RETURN CARRY IF NOT FOUND>>
	INR	A
	STC
	RZ
;<<MOVE NAME FOUND TO CURR>>
	DCR	A
	ANI	3
	ADD	A
	ADD	A
	ADD	A
	ADD	A
	ADD	A
	ADI	81H
	MOV	L,A
	MVI	H,0
	PUSH	H	;SAVE NAME POINTER
	LXI	D,MFCUR+1
	MVI	B,11
	CALL	MOVER
;<<MOVE NAME FOUND TO FCB>>
	POP	H
	LXI	D,FCB+1
	MVI	B,11
	CALL	MOVER
;<<SETUP FCB>>
	XRA	A
	STA	FCBEXT
	STA	FCBRNO
	STA	NEWFCB
	STA	NEWFCB+12
	STA	NEWFCB+32
	STA	MFFLG1	;TURN OFF 1ST TIME SW
;<<RETURN>>
	RET
;------------------------------------------------
;
;MOVE SUBROUTINE  MOVE (B) BYTES FROM (HL) TO (DE)
;
MOVER	MOV	A,M
	ANI	7FH	;STRIP CP/M 2.x ATTRIBUTES
	STAX	D
	INX	H
	INX	D
	DCR	B
	JNZ	MOVER
	RET
;
;MULTI-FILE ACCESS WORK AREA
;
MFFLG1	DB	1	;1ST TIME SW
MFREQ	DS	12	;REQ NAME
MFCUR	DS	12	;CURR NAME
;
NEWFCB	DS	33
STACK	EQU	$+100
;
	END
