;****************************************************************
;*							   	*
;* TURMONH is TURMON with the DUMP function removed and		*
;*    replaced with a "H"ex Load (Intel Hex) function.		*
;*    The stack is set to the top of 32K of memory (8000)	*
;*    instead of FC00.						*
;*								*
;*    To load a hex file, type the letter "H" (no return). 	*
;*    There is no user feedback when the "H" is typed other	*
;*    than you might notice the front panel light pattern 	*
;*    change. At this point, send the hex file through the	*
;*    console serial port. As each line is read, a colon is 	*
;*    displayed as a progress indicator. Once the file has 	*
;*    been read, control returns to the Turnkey Monitor and 	*
;*    the "." prompt is displayed				*
;*							       	*
;*    Created by Mike Douglas 7/6/2014			       	*
;*							       	*
;* THIS IS A 256 BYTE PROM MONITOR FOR USE WITH THE ALTAIR     	*
;* 8800B TURNKEY MODULE.  THIS MONITOR PROVIDES THE USER WITH  	*
;* THE FOLLOWING FUNCTIONS:                                    	*
;*                                                             	*
;*     1)  MEMORY EXAMINE AND CHANGE FUNCTION                  	*
;*             YOU CAN EXAMINE AND CHANGE THE CONTENTS OF ANY  	*
;*             VALID MEMORY LOCATION  				*
;*				                         	*
;*     2)  MEMORY DUMP FUNCTION  	** REMOVED ** 		*
;*            YOU CAN DUMP IN THE ALTAIR BINARY PUNCH FORMAT   	*
;*            BETWEEN ANY TWO VALID MEMORY LOCATIONS           	*
;*								*
;*     3)  JUMP TO FUNCTION                                    	*
;*            YOU CAN CAUSE THE MONITOR TO JUMP TO ANY         	*
;*            LOCATION AND START EXECUTING THE PROGRAMS THERE  	*
;*                                                             	*
;* THE MONITOR CAN BE REENTERED FROM THE USER'S PROGRAM        	*
;* SO THAT THE FEATURES OF THE MONITOR ARE ALWAYS AVAILABLE    	*
;* TO ANY USER PROGRAM.                                        	*
;*                                                             	*
;****************************************************************
;
; MITS TURNKEY MONITOR
; C.W. VERTREES		01/13/1977
; REVISED		01/17/1977
;			01/19/1977
;			01/20/1977

ACIACR	EQU	10H		; SIO STATUS AND COMMAND REGISTER
ACIADR	EQU	ACIACR+1	; SIO DATA REGISTER
SIORST	EQU	03H		; ACIA MASTER RESET
SIOINIT	EQU	11H		; /16, 8 BITS, NO PARITY, 2 STOP, NO INTS
SENSESW	EQU	0FFH		; FRONT PANEL SENSE SWITCHES

LEADCH	EQU	0DH		; PUNCH LEADER CHAR
LEADCNT	EQU	3CH		; PUNCH LEADER COUNT
SOFB	EQU	3CH		; PUNCH "START OF BLOCK" CHAR

PROMPT	EQU	'.'		; COMMAND PROMPT

STACK	EQU	08000H		;STACK AT TOP OF 32k RAM

	ORG	0FD00H

TURMON:	MVI	A,SIORST	; RESET 2SIO
	OUT	ACIACR		; AND INITIALIZE
	MVI	A,SIOINIT
	OUT	ACIACR

ENTER:	LXI	SP,STACK	; LOAD STACK
	CALL	CRLF		; FORMAT OUTPUT
	MVI	A,PROMPT	; HELLO MONITOR
	CALL	OUTCHK

	CALL	INCH		; GET COMMAND FROM USER

	CPI	'M'
	JZ	MEM		; DO MEMORY EXAMINE

	CPI	'H'
	CZ	hexLoad		; DO A HEX FILE LOAD

	CPI	'J'
	JNZ	ENTER		; valid command not entered

	CALL	OCTL6		; DO A JUMP, GET ADDRESS
	PCHL			; LOAD PC AND GO

; THIS CONTROL STRUCTURE HANDLES THE MEMORY
; EXAMINE AND CHANGE FUNCTION
;
MEM:	CALL	OCTL6		; GET ADDRESS

	DB	3EH		; "MVI A," SKIP NEXT (BOMB A)
CONT:	INX	H		; INCREMENT ADDRESS
	CALL	CRLF		; NEW LINE

	MOV	D,H		; STORE ADDRESS IN D/E
	MOV	E,L
	CALL	PRINT6		; PRINT ADDRESS

	LDAX	D		; LOAD DATA
	MOV	H,A
	CALL	PRINT3		; PRINT DATA BYTE

	CALL	OCTL3		; GET NEW DATA

	XCHG			; RESTORE ADDRESS
	JC	CONT		; NO NEW DATA

	MOV	M,A		; STORE DATA
	CMP	M		; COMPARE DEPOSIT
	JZ	CONT		; OK, DO NEXT

ERR:	MVI	A,'?'		; FLAG BAD DEPOSIT
	CALL	OUTCHK		; PRINT '?'
	JMP	ENTER		; RESTART WITH CLEAN STACK

;--------------------------------------------------------------------
;  hexLoad - Load Intel Hex file
;--------------------------------------------------------------------
; Look for ':' at the start of a new hex line, then load the line
;   length into D and the load address into HL

hexLoad	call	getNib		;returns zero true if ':' read
	jnz	hexLoad		;no, keep looking
	call	OUTCHK		;transmit ':' as progress tick
	call	getByte		;input two hex digits (byte count)
	jz	flush		;count of 0 means end, exit
	mov	d,a		;d = byte count on line
	call	getByte		;get MSB of address in H
	mov	h,a
	call	getByte		;MSB of address in L
	mov	l,a
	call	getByte		;ignore record type

; Receive the data bytes of the record and move to memory

data	call	getByte		;read a data byte (2 hex digits)
	mov	m,a		;store in memory
	inx	h
	dcr	d
	jnz	data
	jmp	hexLoad		;do next line

; Eat up characters for the next second so the characters don't go to
;   the monitor ROM (DE=0 on entry).

flush	in	ACIADR		;(10) flush possible character
	dcx	d		;(5) decrement timeout
	mov	a,d		;(5)
	ora	e		;(4)
	jnz	flush		;(10) loop until zero
	ret			;exit

;--------------------------------------------------------------
; getByte - read one ASCII hex bytes and convert to binary in A
;--------------------------------------------------------------
getByte	call	getNib		;get ASCII hex nibble in binary
	add	a		;put in msn, zero lsn
	add	a
	add	a
	add	a
	mov	e,a		;save byte with MSN in E

; 2nd byte (LSN)

	call	getNib
	add	e		;combine msn and lsn
	ret

;---------------------------------------------------------------
; getNib - read one ASCII hex nibble and convert to binary in A
;---------------------------------------------------------------
getNib	in	ACIACR		;wait for new character
	rrc
	jnc	getNib
	in	ACIADR		;get the character
	cpi	':'		;start of record character?
	rz			;yes, return with zero flag true
	sui	'0'		;'0' to 0
	cpi	10		;0-9 ?
	rc			;yes, done (zero flag is false)
	sui	7		;convert A-F
	ret			;zero flag is false

;---------------------------------------------------------------
;CRLF - display CR/LF sequence
;---------------------------------------------------------------
CRLF:	MVI	A,0DH		; DO A CRLF AND RETURN TO MONITOR
	CALL	OUTCHK
	MVI	A,0AH
	JMP	OUTCHK


; THIS SUBROUTINE BUILDS 3/6 OCTAL DIGITS IN H&L
;
; SPECIAL RETURN PROVIDED BY A "SPACE", CARRY BIT SET.
; ONLY VALID OCTAL OR "SPACE" ACCEPTED. ALL OTHERS FLAGGED AND
; CONTROL RETURNS TO MONITOR.

OCTL6:	DB	6		; LOAD B WITH A 6, SKIP NEXT
OCTL3:	DB	6		; LOAD B WITH 3
	DB	3
	LXI	H,0		; CLEAR H/L FOR LESS THAN 6 DIG RET

AGN:	mvi	c,1		; c non-zero means echo on
	CALL	INCH		; GET CHARACTER
	MOV	C,A		; STORE IN C
	CPI	' '		; COMPARE TO "SPACE"

	STC			; SET THE CARRY
	RZ			; RETURN IF "SPACE"
	ANI	0B8H		; TEST FOR VALID OCTAL

	XRI	30H

	JNZ	ERR		; BAD, FLAG & RET TO MON

	MOV	A,C		; RESTORE CHAR
	ANI	7		; STRIP OFF ASCII

	DAD	H		; SHIFT H&L LEFT 3 BITS
	DAD	H
	DAD	H
	ADD	L
	MOV	L,A		; PUT OCTAL IN H
	DCR	B		; THROUGH?
	JNZ	AGN		; NO, DO AGAIN

	RET			; YES, NORM RETURN

; THIS SUBROUTINE PRINTS 3 OCTAL DIGITS FROM H
; OR 6 OCTAL DIGITS FROM H AND L
;
; DIGITS ARE FOLLOWED BY A SPACE

PRINT6:	MVI	B,6		; LOAD CNTR W/6

	XRA	A		; CLEAR A
	JMP	NEXT1		; SHIFT ONE BIT

PRINT3:	MVI	B,3		; LOAD CNTR W/3

	DB	0E6H		; SKIP NEXT, SHIFT 2 BITS
NEXT3:	DAD	H		; SHIFT H/L LEFT 3 INTO A
	RAL
	DAD	H
	RAL
NEXT1:	DAD	H
	RAL
	ANI	7		; STRIP OFF OCTAL

	ORI	30H		; ADD ASCII

	CALL	OUTCHK		; PRINT IT

	DCR	B		; THROUGH?
	JNZ	NEXT3		; NO, SHIFT NEXT THREE

SPACE:	MVI	A,' '		; YES, PRINT SPACE

	JMP	OUTCHK		; AND RETURN

; RETURN TO CALLING PROGRAM THROUGH OUTCHK
; THIS SUBROUTINE WILL INPUT A CHARACTER, STRIP
; PARITY AND AUTOMATICLY ECHO THE CHARACTER.

INCH:	IN	ACIACR		; READ STATUS
	RRC
	JNC	INCH		; NOT READY

	IN	ACIADR		; read the character

OUTCHK:	PUSH	PSW		; SAVE CHARACTER

LOOP:	IN	ACIACR		; READ STATUS
	RRC
	RRC
	JNC	LOOP		; READY ?

	POP	PSW		; YES, GET CHAR
	OUT	ACIADR		; PRINT CHARACTER

	RET			; FROM WHENCE YE CAME

	END
