; INTEL HEX LOADER

A0CTRL	EQU	10H	;ACIA 0 CONTROL OUTPUT PORT
A0STAT	EQU	10H	;ACIA 0 STATUS INPUT PORT
A0TDR	EQU	11H	;ACIA 0 TRANSMIT DATA REGISTER
A0RDR	EQU	11H	;ACIA 0 RECEIVE DATA REGISTER
A1CTRL	EQU	12H	;ACIA 1 CONTROL OUTPUT PORT
A1STAT	EQU	12H	;ACIA 1 STATUS INPUT PORT
A1TDR	EQU	13H	;ACIA 1 TRANSMIT DATA REGISTER
A1RDR	EQU	13H	;ACIA 1 RECEIVE DATA REGISTER

; CONTROL REGISTER BITS

ACCDS1	EQU	00000001B	;COUNTER DIVIDE SELECT 1
ACCDS2	EQU	00000010B	;COUNTER DIVIDE SELECT 2
ACWS1	EQU	00000100B	;WORD SELECT 1
ACWS2	EQU	00001000B	;WORD SELECT 2
ACWS3	EQU	00010000B	;WORD SELECT 3
ACTC1	EQU	00100000B	;TRANSMIT CONTROL 1
ACTC2	EQU	01000000B	;TRANSMIT CONTROL 2
ACRXIE	EQU	10000000B	;RECEIVE INTERRRUPT ENABLE

ACRSET	EQU	00000011B	;MASTER RESET

;COMPOUND COMMANDS
AC0INIT	EQU	ACCDS1+ACWS3	;/16 CLOCK, 8 BITS+2 STOP BITS
AC0REN	EQU	AC0INIT+ACTC2	;MAKES RTS ACTIVE
AC1INIT	EQU	ACCDS1+ACWS1+ACWS3 ;/16 CLOCK, 8 BITS+1 STOP BIT
AC1CTS	EQU	AC1INIT+ACTC2	;MAKES RTS INACTIVE
AC0CTS	EQU	AC0INIT+ACTC2	;TURNS OFF TAPE

; STATUS REGISTER BITS

ASRDRF	EQU	00000001B	;RECEIVE DATA REGISTER FULL
ASTDRE	EQU	00000010B	;TRANSMIT DATA REGISTER EMPTY
ASDCD	EQU	00000100B	;DATA CARRIER DETECT
ASCTS	EQU	00001000B	;CLEAR TO SEND
ASFE	EQU	00010000B	;FRAMING ERROR
ASOVRN	EQU	00100000B	;RECEIVER OVERRUN ERROR
ASPE	EQU	01000000B	;PARITY ERROR
ASIRQ	EQU	10000000B	;INTERRUPT REQUEST

CR	EQU	0DH	;ASCII CARRIAGE RETURN
LF	EQU	0AH	;ASCII LINE FEED

ORG	3F00H			;FITS IN 16K SYSTEM

;
; REGISTER USAGE:
; B: RECORD BYTE COUNT
; C: SCRATCH
; D: RECORD CHECKSUM
; E: RECORD TYPE
; HL: MEMORY ADDRESS
;
;
; INITIALIZE ACIA

	MVI	A,ACRSET
	OUT	A0CTRL

RSTART:	MVI	A,AC0INIT
	OUT	A0CTRL

	LXI	SP,STACK

	MVI	C,RDYMSG	;READY MESSAGE
	CALL	PRINTF

; WAIT FOR RECORD START

GETCOL:	CALL	GETCHR
	CPI	':'
	JNZ	GETCOL

; GET BYTE COUNT INTO B

	CALL	GETBYT
	MOV	B,C
	MOV	D,C		;RESET CHECKSUM IN D

; GET ADDRESS INTO HL

	CALL	GETBYT
	MOV	H,C		;HIGH BYTE OF ADDRESS
	CALL	GETBYT
	MOV	L,C		;LOW BYTE OF ADDRESS

; GET RECORD TYPE IN E

	CALL	GETBYT
	MOV	E,C

; TEST FOR 0-BYTE RECORD, WHIS IS AN ALTERNATE EOF

	MOV	A,B		;CHECK FOR 0-BYTE RECORD
	ORA	A
	JNZ	BYTLUP

	INR	A
	ORA	E
	MOV	E,A		;REMEMBER EOF

	JMP	GCHKSM

;LOOP TO GET DATA INTO MEMORY

BYTLUP:	CALL	GETBYT
	MOV	M,C
	INX	H
	DCR	B
	JNZ	BYTLUP	

; GET AND CHECK CHECKSUM

GCHKSM:	CALL	GETBYT
	MVI	C,CERMSG-MSBASE
	JNZ	EXIT		;TEST CHECKSUM, ERROR IF BAD

; ALL DONE

	MVI	C,DONMSG-MSBASE	;DONE, NOT ERROR
	DCR	E		;RECORD TYPE 1 IS EOF
	JZ	EXIT

	INR	E		;TEST FOR DATA RECORD
	JZ	GETCOL		;YES: GO GET ANOTHER RECORD

; BAD RECORD TYPE

	MVI	C,BRTMSG-MSBASE

;	FALL INTO EXIT

;PRINT EXIT MESSAGE, THEN START OVER

EXIT:	MVI	A,AC0CTS	;STOP THE READER
	OUT	A0CTRL

	SHLD	ERADDR		;SAVE DATA POINTER

	CALL	PRINTF

	JMP	RSTART


; SUBROUTINE TO PRINT MESSAGE AT MSBASE + C	

PRINTF:	LXI	H,MSBASE
	MVI	B,0
	DAD	B		;HL POINTS TO MESSAGE STRING

MSGLUP:	IN	A0STAT		;TEST FOR TTY READY
	ANI	ASTDRE
	JZ	MSGLUP

	MOV	A,M
	OUT	A0TDR		;PRINT CHR NOW
	INX	H

	RLC			;PARITY BIT ENDS MESSAGE
	RC

	JMP	MSGLUP

;SUBROUTINE TO GET 2 HEX DIGITS AND COMBINE THEM INTO A BYTE
; AND ADD RESULT TO CHECKSUM IN A & D. RESULT RETURNED IN C.
; Z FLAG SET IF CHECKSUM IS 0

GETBYT:	XRA	A		;USE B FOR DIGIT ACCUMULATION
	CALL	GETHEX
	RLC			;SHIFT HIGH NIBBLE IN PLACE
	RLC
	RLC
	RLC
	CALL	GETHEX

	MOV	C,A		;SAVE RESULT FOR RETURN
	ADD	D		;COMPUTE CHECKSUM
	MOV	D,A
	RET

; SUBROUTINE TO GET A HEX DIGIT AND COMBINE WITH A

GETHEX:	MOV	C,A		;SAVE PREVIOUS NIBBLE
	CALL	GETCHR
	CPI	'9'+1		;IS CHR BELOW ASCII 9
	JC	GH1		;YES: GO DEAL WITH DIGIT

	CPI	'A'		;IS CHER BETWEEN 9 AND A?
	JC	AERROR		;YES: ERROR
	SUI	'A'-'9'-1	;NO: SUBTRACT OFFSET	

GH1:	SUI	'0'
	CPI	10H
	JNC	AERROR

	ORA	C
	RET

AERROR:	MVI	C,AERMSG-MSBASE
	JMP	EXIT		;PRINT MESSAGE START OVER

; SUBROUTINE TO GET A CHR IN A, IGNORING NULLS

GETCHR:	IN	A0STAT	;TEST FOR TTY DATA
	RAR		;TEST RDR FULL
	JNC	GETCHR	;WAIT FOR DATA

	IN	A0RDR	;GET BYTE FROM PAPER TAPE

	ANI	7FH	;STRIP PARITY
	RNZ		;SKIP OVER NULLS

	JMP	GETCHR

MSBASE:
RDYMSG:	DB	CR,LF,0,'HEXLOAD RDY',CR,LF, 80H
BRTMSG:	DB	'BAD REC TYP',80H+'E'
AERMSG:	DB	'ASCII ER',80H+'R'
CERMSG:	DB	'CKSUM ER',80H+'R'
DONMSG:	DB	'DON',80H+'E'
ERADDR:	DB	0
SSPACE:	DB	16
STACK	EQU	$
	
	END