;	DTC LOADER
;
TBASE:	EQU	100H
	ORG	TBASE
BOOT:	EQU	0
BDOS:	EQU	5
MEMTOP:	EQU	BDOS+1	;TOP OF AVAILABLE MEMORY
;	BDOS FUNCTIONS
CONOUT:	EQU	9	;CONSOLE OUTPUT
CONIN:	EQU	10	;CONSOLE INPUT
OPENF:	EQU	15	;OPEN FILE
CLOSEF:	EQU	16	;CLOSE FILE
SEARCF: EQU	17	;SEARCH FIRST
READF:	EQU	20	;READ SECTOR
INTDSK:	EQU	25	;INTERROGATE DISK
;
TFCB:	EQU	05CH	;DEFAULT FILE CONTROL BLOCK
TET:	EQU	TFCB	;ENTRY TYPE
TFN:	EQU	TET+1	;FILE NAME
TFT:	EQU	TFN+8	;FILE TYPE
TEX:	EQU	TFT+3	;FILE EXTENT
TRC:	EQU	TEX+3	;RECORD COUNT
TDM:	EQU	TRC+1	;DISK ALLOCATION MAP
TNR:	EQU	TDM+16	;NEXT RECORD NUMBER
;
TBUFF:	EQU	080H	;DEFAULT BUFFER
;
SECSIZ:	EQU	128	;SECTOR SIZE
;
CR:	EQU	0DH
LF:	EQU	0AH
;
;
LOAD:	LXI	H,0		;SAVE CP/M STACK POINTER
	DAD	SP
	SHLD	SAVESP
	LXI	SP,STACK	;SET STACK POINTER
	CALL	INIT		;INITIALIZE FILE PARAMETERS
;
	MVI	C,0		;CLEAR BUFFER COUNT
LOAD1:	CALL	GETCHR		;SCAN TO BEGIN OF LINE
	CPI	':'
	JNZ	LOAD1
	LXI	D,COUNT		;GET LOAD COUNT
	CALL	HEXBYT
	LDA	COUNT		;DONE?
	ORA	A
	JZ	EXIT
	LXI	D,LADDR		;GET LOAD ADDRESS
	CALL	GETADR
	PUSH	H		;ADD OFFSET
	LHLD	LADDR
	XCHG
	LHLD	OFFSET
	DAD	D
	LXI	D,LOW		;IS ADDRESS IN LOADER?
	CALL	COMPAR
	XCHG
	JP	LOAD2
	LXI	D,ERMES		;YES
	MVI	C,CONOUT
	CALL	BDOS
	JMP	EXIT
ERMES:	DB	'LOAD ADDRESS WITHIN LOADER.',CR,LF,'$'
;
LOAD2:	POP	H		;RESTORE BUFFER POINTER
	CALL	GETCHR		;SKIP SEPARATOR BYTE
	CALL	GETCHR
LOAD3:	CALL	HEXBYT		;LOAD DATA
	PUSH	H
	LXI	H,COUNT		;DECREMENT COUNT
	DCR	M
	POP	H
	JNZ	LOAD3
	JMP	LOAD1		;END OF LINE
;
;
;
;	GET CHARACTER FROM RECORD
;	IN - HL=BUFFER POINTER
;	      C=BUFFER COUNT
;	OUT-A=CHARACTER
;
GETCHR:	XRA	A	;BUFFER EMPTY?
	CMP	C
	JNZ	GETCH2
	MVI	C,READF	;YES. GET NEXT RECORD
	PUSH	B
	PUSH	D
	CALL	FILEOP
	POP	D
	POP	B
	JZ	GETCH1
EXIT:	CALL	CLOSE
	MVI	C,0	;RESTORE LOGGED DRIVE
DRIVE:	EQU	$-1
	CALL	$
SELDSK:	EQU	$-2
	LHLD	SAVESP	;RESTORE CP/M STACK POINTER
	SPHL
	RET
;
GETCH1:	LXI	H,TBUFF
	MVI	C,SECSIZ
GETCH2:	MOV	A,M
	INX	H
	DCR	C
	RET
;
;
;
;
CLOSE:	MVI	C,CLOSEF
FILEOP:	LXI	D,TFCB
	CALL	BDOS
	CPI	0
	RET
;	GET ADDRESS
;	IN - HL=4 DIGIT ASCII HEX ADDRESS
;	     DE=ADDRESS OF RESULT
;
GETADR:	INX	D	;POINT TO MOST SIGN. BYTE
	CALL	HEXBYT
	DCX	D
	DCX	D
	CALL	HEXBYT
	INX	D
	XRA	A
	RET
HEXBYT:	CALL	ASCHEX
	RLC
	RLC
	RLC
	RLC
	MOV	B,A
	CALL	ASCHEX
	ADD	B
	STAX	D
	INX	D
	RET
ASCHEX:	CALL	GETCHR
	SUI	'0'
	CPI	10
	RM
	SUI	7
	RET
;	COMPARE HL & DE
;	OUT - FLAGS ARE SET TO RESULT OF HL - DE
;
COMPAR:	MOV	A,H
	CMP	D
	RNZ
	MOV	A,L
	CMP	E
	RET
;
;
;	VARIABLES
LADDR:	DW	0	;LOAD ADDRESS
OFFSET:	DW	0	;LOAD OFFSET
SAVESP:	DW	0	;CP/M STACK POINTER
COUNT:	DW	0	;LOAD COUNT OF LINE
	DS	26
STACK:
LOW:	EQU	$	;LOW LOAD ADDRESS
;
;
INIT:	MVI	C,INTDSK	;SAVE CURRENTLY LOGGED DISK
	CALL	BDOS
	STA	DRIVE
	LHLD	BOOT+1		;GET SELECT DISK ADDRESS
	MVI	L,3*9
	SHLD	SELDSK
	SHLD	INISEL
	LXI	H,0		;CLEAR OFFSET
	SHLD	OFFSET
	MVI	B,22		;SET MAX CHAR SCAN
	LDA	TFN		;WAS FILE SPECIFIED?
	CPI	' '
	JNZ	INIT1
	MVI	A,20		;NO. SET MAX BUFFER LENGTH
	STA	TBUFF
INIT0:	LXI	D,FNMES		;OUTPUT FILENAME MESSAGE
	MVI	C,CONOUT
	CALL	BDOS
	LXI	D,TBUFF		;INPUT FILE NAME
	MVI	C,CONIN
	CALL	BDOS
	CALL	CRLF
	LDA	TBUFF+1		;# CHARS IN BUFFER
	CPI	0
	JZ	INIT0
	MOV	B,A		;B:=# CHARS IN BUFFER
INIT1:	LXI	H,TBUFF+1
	LDA	TBUFF+3		;DRIVE SPECIFIED?
	CPI	':'
	JNZ	INITD3
	INX	H
	MOV	A,M
	SUI	'A'		;YES. LEGAL DRIVE #
	JM	INITD1
	CPI	16
	JM	INITD2
INITD1:	LXI	D,DRVMES	;NO
	MVI	C,CONOUT
	CALL	BDOS
	JMP	EXIT
DRVMES:	DB	'INVALID DRIVE.',CR,LF,'$'
INITD2:	PUSH	B
	MOV	C,A		;SELECT DRIVE
	CALL	$
INISEL:	EQU	$-2
	POP	B
	LXI	H,TBUFF+3
INITD3:
	LXI	D,TFCB
INIT2:	INX	H
	INX	D
	MOV	A,M
	CPI	'.'		;END OF NAME?
	JZ	INIT4
	CPI	' '
	JZ	INIT7
	CPI	CR
	JZ	INIT9
	CPI	060H		;NO. LOWER CASE?
	JC	INIT3
	SUI	020H		;YES. CONVERT TO UPPER CASE
INIT3:	STAX	D
	DCR	B
	JNZ	INIT2
	JMP	INIT9
INIT4:	LXI	D,TFT-1		;GET FILE TYPE
INIT5:	INX	H
	INX	D
	MOV	A,M
	CPI	' '
	JZ	INIT7
	CPI	CR
	JZ	INIT9
	CPI	060H
	JC	INIT6
	SUI	020H
INIT6:	STAX	D
	DCR	B
	JNZ	INIT5
	JP	INIT9
INIT7:	INX	H		;SCAN FOR OFFSET
	MOV	A,M
	CPI	'='
	JZ	INIT8
	CPI	CR
	JZ	INIT9
	DCR	B
	JNZ	INIT7
	JMP	INIT9
INIT8:	INX	H		;GET OFFSET
	LXI	D,OFFSET
	CALL	GETADR
INIT9:
	LDA	TFT		;WAS FILE TYPE SPECIFIED?
	CPI	' '
	JNZ	INIT11
	LXI	H,HEXMES	;SET FILE TYPE TO HEX
	LXI	D,TFT
	MVI	B,3
INIT10:	MOV	A,M
	STAX	D
	INX	H
	INX	D
	DCR	B
	JNZ	INIT10
INIT11:
	LXI	D,TEX		;CLEAR EXTENT AND
	MVI	B,4		; RECORD COUNT
	XRA	A
INIT12:	STAX	D
	INX	D
	DCR	B
	JNZ	INIT12
	LXI	D,TNR		;CLEAR NEXT RECORD NUMBER
	STAX	D
	MVI	C,SEARCF
	CALL	FILEOP		;LOOKUP HEX FILE
	CPI	0FFH
	JNZ	INIT13
	LXI	D,EXIMES	;OUTPUT ERROR MESSAGE
	MVI	C,CONOUT
	CALL	BDOS
	JMP	EXIT
EXIMES:	DB	'HEX FILE DOES NOT EXIST.',CR,LF,'$'
INIT13:
	MVI	C,OPENF		;OPEN HEX FILE
	CALL	FILEOP
	RET
;
;
CRLF:	LXI	D,CRLFM
	MVI	C,CONOUT
	CALL	BDOS
	RET
CRLFM:	DB	 CR,LF,'$'
FNMES:	DB	'FILENAME ... $'
HEXMES:	DB	'HEX'
	END
