;	   CARRY.ASM ver 1.2
;	   (revised 6/24/81)
;	by Keith Petersen, W8SDZ
;
;This program runs up in high RAM.  It gets there
;by being moved there when CARRY <program name>
;is typed.
;
;The program in high RAM does the following:
;
;Loads and executes a .COM file named in command line,
;but first waits for the user to change disks.
;Arguements after requested .COM file name are passed
;to the executed program, thus making it possible to
;run ED or Wordmaster.
;
;Why this is useful: Users of single-drive systems
;may not have room for ED, WM, ASM, LOAD, or other
;such programs on their "work" disk.  This program
;makes it possible to change disks, get the editor
;assembler or loader, then change disks again.  CARRY
;must be on the same disk with the COM file it is to
;get.
;
;Command:  CARRY ED MYFILE.ASM
;	(gets ED.COM to edit MYFILE.ASM)
;
;Fixes/updates (in reverse order to minimize reading time):
;
;06/24/81 Added more documentation about ENDMARK. (KBP)
;
;NOTE: If you add improvements or otherwise update
;this program, please modem a copy of the new file
;to "TECHNICAL CBBS" in Dearborn, Michigan - phone
;313-846-6127 (110, 300, 450 or 600 baud).  Use the
;filename CARRYXX.NEW where XX is the new version nr.
;------------------------------------------------
;
;A marker has been placed at the end of this file to
;deliberately print an error message during assembly
;in order to determine the actual ending address of
;the program.  The error message will not affect the
;assembly.  Make sure you have free memory available
;up to the address shown.
;
;Change the following equate to an area in your
;high memory where this program may patch itself in.
;This may be below BDOS, provided that sufficient
;space is available below CARRY to load the requested
;COM file.
;
DEST	EQU	0FA00H	;RUNNING LOCATION OF CODE
;
;------------------------------------------------
;
BASE	EQU	0	;PUT 4200H HERE FOR ALTERNATE CP/M
;
PRINT	EQU	9
OPEN	EQU	15
STDMA	EQU	26
BDOS	EQU	BASE+5
FCB	EQU	BASE+5CH 
FCBEXT	EQU	FCB+12
FCB2	EQU	BASE+6CH
;
CR	EQU	0DH
LF	EQU	0AH
;
	ORG	BASE+100H
;
;Move the program up to high RAM and jump to it.
;
MOVEUP:	LXI	B,PEND-START+1		;NUMBER OF BYTES TO MOVE
	LXI	H,DEST+PEND-START+1	;END OF MOVED CODE
	LXI	D,SOURCE+PEND-START	;END OF SOURCE CODE
;
MVLP:	LDAX	D	;GET BYTE
	DCX	H	;BUMP POINTERS
	MOV	M,A	;NEW HOME
	DCX	D
	DCX	B	;BUMP BYTE COUNT
	MOV	A,B	;CHECK IF ZERO
	ORA	C
	JNZ	MVLP	;IF NOT, DO SOME MORE
	PCHL		;JUMP TO "START"
;
SOURCE	EQU	$	;BOUNDARY MEMORY MARKER
;
OFFSET	EQU	DEST-SOURCE	;RELOC AMOUNT
;-----------------------------------------------;
;	The following code gets moved		;
;	to high RAM located at "DEST",		;
;	    where it is executed.		;
;-----------------------------------------------;
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XX   C A U T I O N :  If modifying anything 	XX
;XX 	in this program from here on: 		XX
;XX  	A-L-L labels must be of the form:	XX
;XX	LABEL	EQU	$+OFFSET		XX
;XX	in order that the relocation to high	XX
;XX	RAM work successfully.  Forgetting to	XX
;XX	specify '$+OFFSET' will cause the pro-	XX
;XX	gram to JMP into whatever is currently	XX
;XX	in low memory, with unpredictable	XX
;XX	results.  Be careful....		XX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;
START	EQU	$+OFFSET
	LXI	SP,STACK ;SET UP LOCAL STACK POINTER
;Move requested file name to our FCB
	LXI	H,FCB	;SOURCE
	LXI	D,MYFCB	;DESTINATION
	MVI	B,9	;LENGTH
	CALL	MOVE	;MOVE THE NAME
;Move arguement to default FCB
	LXI	H,FCB2	;SOURCE
	LXI	D,FCB	;DESTINATION
	MVI	B,13	;LENGTH
	CALL	MOVE	;MOVE THE NAME
;Clear FCB2 and initialize our FCB
	MVI	A,' '
	STA	FCB2+1
	XRA	A
	STA	FCB2
	STA	FCBEXT
	STA	MYFCB+32
;Set DMA address to 80H
	LXI	D,BASE+80H
	MVI	C,STDMA
	CALL	BDOS
;Open the file
	LXI	D,MYFCB
	MVI	C,OPEN
	CALL	BDOS
;Did it exist?
	INR	A	;A=> 0 MEANS "NO"
	JZ	BYERR	;NO FILE, EXIT ERROR MSG
;
OPENOK	EQU	$+OFFSET
	LXI	D,BASE+100H	;POINT TO TPA
;
READLP	EQU	$+OFFSET
	PUSH	D	;SAVE BUFFER ADDRESS
	PUSH	B
	PUSH	H
	MVI	C,STDMA
	CALL	BDOS
;Read a sector
	LXI	D,MYFCB
	MVI	C,20	;READ
	CALL	BDOS
	POP	H
	POP	B
	ORA	A	;OK?
	JNZ	EOF	;NOT OK, MUST BE EOF
	POP	D	;GET DMA ADDR
	LXI	H,80H	;LENGTH OF 1 SECT.
	DAD	D	;CALC NEXT BUFF ADDR
	XCHG		;PUT IT BACK IN DE
	JMP	READLP	;LOOP
;
;Got return code on read, see if error or EOF
;
EOF	EQU	$+OFFSET
	POP	D	;DELETE STACKED BUFFER ADDR
;A has return code from read
	DCR	A	;EOF?
	JZ	RSDMA	;YES, EXIT
;
;Read error - exit with message
BYERR	EQU	$+OFFSET
	CALL	ERXIT	;PRINT:
	DB	CR,LF,'++DISK READ ERROR or FILE NOT FOUND++',CR,LF,'$'
;
;Exit with error message
ERXIT	EQU	$+OFFSET
	POP	D
	MVI	C,9	;PRINT ERROR MESSAGE
	CALL	BDOS
;
ERXIT2	EQU	$+OFFSET
	XRA	A
	STA	BASE+4	;SET DRIVE A:, USER 0
	JMP	BASE
;
;Reset DMA address to normal
RSDMA	EQU	$+OFFSET
	LXI	D,BASE+80H
	MVI	C,STDMA
	CALL	BDOS
;
REASK	EQU	$+OFFSET
	LXI	D,RDYMSG
	MVI	C,9	;PRINT READY MESSAGE
	CALL	BDOS
	MVI	C,1	;GET CONSOLE CHAR.
	CALL	BDOS
	CPI	'C'-40H	;CTL-C?
	JZ	ERXIT2	;YES, EXIT
	CPI	CR	;CARRIAGE RETURN?
	JNZ	REASK
;
	MVI	C,13	;RESET DISK SYSTEM
	CALL	BDOS
;
;Leave warm boot address on stack, them execute file
	LXI	H,BASE+0
	PUSH	H
	JMP	BASE+100H	;EXECUTE PROGRAM
;
;Move (HL) to (DE), length in (B)
;
MOVE	EQU	$+OFFSET
	MOV	A,M	;GET A BYTE
	STAX	D	;PUT AT NEW HOME
	INX	D	;BUMP POINTERS
	INX	H
	DCR	B	;DEC BYTE COUNT
	JNZ	MOVE	;IF MORE, DO IT
	RET		;IF NOT,RETURN
;
RDYMSG	EQU	$+OFFSET
	DB	CR,LF,'CHANGE DISKS THEN PRESS RETURN '
	DB	'TO CONTINUE (CTL-C ABORTS) > $'
;
MYFCB	EQU	$+OFFSET
	DB	0,'        COM',0
;
PEND	EQU	$+OFFSET ;END OF RELOCATED CODE
;
	DS	20	;ROOM FOR OUR FCB
	DS	40	;ROOM FOR OUR STACK
STACK	EQU	$+OFFSET ;LOCAL STACK
;
ENDMARK	EQU	$+OFFSET ;! IGNORE ERROR. THIS MARKS END OF PGM
;
	END
