;*************************************
;                MONITOR EQUATES
;*************************************
;
BRCHR	EQU	1BH	; CODE FOR BREAK CHARACTER (ESCAPE)
BRTAB	EQU	3FAH	; LOCATION OF START OF BRANCH TABLE IN ROM
CMD	EQU	025H	; COMMAND INSTRUCTION  FOR USART  INITIALIZATION
CNCTL	EQU	005H	; CONSOLE (USART) CONTROL PORT
CNIN	EQU	004H	; CONSOLE INPUT PORT
CNOUT	EQU	004H	; CONSOLE OUTPUT PORT
CONST	EQU	005H	; CONSOLE STATUS INPUT PORT
CR	EQU	0DH	; CODE FOR CARRIAGE RETURN
ESC	EQU	1BH	; CODE FOR ESCAPE CHARACTER
HCHAR	EQU	0FH	; MASK TO SELECT LOWER HEX CHAR FROM BYTE
INVRT	EQU	0FFH	; MASK TO INVERT HALF BYTE FLAG
LF	EQU	0AH	; CODE FOR LINE FEED
;LSGNON	EQU	---	; LENGTH OF SIGNON MESSAGE - DEFINED LATER
MODE	EQU	0CEH	; MODE SET FOR USART INITIALIZATION
;MSTAK	EQU	---	; START OF MONITOR STACK - DEFINED LATER
;NCMDS	EQU	---	; NUMBER OF VALID COMMANDS
NEWLN	EQU	0FH	; MASK FOR CHECKING MEMORY ADDR DISPLAY
PRTYO	EQU	07FH	; MASK TO CLEAR PARITY BIT FROM CONSOLE CHAR
REGS	EQU	0FFFFH-18 ; START OF REGISTER SAVE AREA
RBR	EQU	2	; MASK TO TEST RECEIVER STATUS
;RTABS	EQU	---	; SIZE OF ENTRY IN RTAB TABLE
TERM	EQU	1BH	; CODE FOR ICMD TERMINATING CHARACTER (ESCAPE)
TRDY	EQU	1	; MASK TO TEST TRANSMITTER STATUS
UPPER	EQU	0FFH	; DENOTES UPPER HALF OF BYTE IN ICMD
TXBE	EQU	04H	; USART TRANSMITTER BUFFER EMPTY
TTYADV	EQU	27H	; TTY READER ADVANCE COMMAND
ONEMS	EQU	131	; 1 MILLISECOND CONSTANT
;
PTC	EQU	0FH	; READER/PUNCH CONTROL PORT
PTRC	EQU	0EH	; CONTROL
PTRS	EQU	0EH	; STATUS
PTRD	EQU	0DH	; DATA
PTCW	EQU	83H	; CONTROL WORD
STR	EQU	10H	; STEP
PTRR	EQU	01H	; READY
;
COC	EQU	036H	; 8253 COMMAND
BRF	EQU	710	; 110 BAUD RATE FACTOR
CCP	EQU	03H	; COMMAND PORT
LC2P	EQU	00H	; LOAD COUNTER 2 PORT
;
;****************************************
;
;                   MONITOR MACROS
;
;****************************************
;
TRUE	MACRO	WHERE	; BRANCH IF FUCTION RETURNS TRUE (SUCCESS)
	JC	WHERE
	ENDM
;
FALSE	MACRO	WHERE	; BRANCH IF FUNCTION RETURNS FALSE (FAILURE)
	JNC	WHERE
	ENDM
;
;***********************************************
;
;                 USART INITIALIZATION CODE
;
;***********************************************
;
;	THE USART IS ASSUMED TO COME UP IN THE RESET POSITION (THIS
;	FUNCTION IS TAKEN CARE OF BY THE HARDWARE). THE USART WILL
;	BE INITIALIZED IN THE SAME WAY FOR EITHER A TTY OR CRT
;	INTERFACE. THE FOLLOWING PARAMETERS ARE USED:
;
;	MODE INSTRUCTION
;	____ ___________
;
;	2 STOP BITS 
;	PARITY DISABLED
;	8 BIT CHARACTERS
;	BAUD RATE FACTOR OF 64
;
;	COMMAND INSTRUCTION
;	------- -----------
;
;	NO HUNT MODE
;	NOT(RTS) FORCED TO 0
;	RECIEVE ENABLED
;	TRANSMIT ENABLED
;
	MVI	A,MODE
	OUT	CNCTL	; OUTPUT MODE SET TO USART
	JMP	INUST	; BRANCH TO COMPLETE USART INITIALIZATION
	NOP		; FILLER
;
;*****************************************************************
;
;                       RESTART ENTRY POINT
;
;*****************************************************************
;
GO:
	SHLD	LSAVE	; SAVE HL REGISTERS
	POP	H	; GET TOP OF STACK ENTRY
	SHLD	PSAVE	; ASSUME THIS IS LAST P COUNTER
	PUSH	PSW	; SAVE A,F/F'S
	LXI	H,2	; SET HL TO 2 SO THAT STACK POINTER SAVED CORRECTLY
	DAD	SP	; GET STACK POINTER VALUE
	SHLD	SSAVE	; SAVE USERS'S STACK PONTER
	POP	PSW	; RESTORE A,F/F'S
	LXI	SP,ASAVE+1	; NEW VALUE FOR STACK POINTER
	JMP	ADROUT
;
;********************************************
;
;                  PRINT SIGNON MESSAGE
;
;************************************************
;
SOMSG:
	LXI	H,SGNON	; GET ADDRESS OF SIGNON MESSAGE
	MVI	B,LSGNON	; COUNTER FOR CHARACTERS IN MESSAGE
MSGL:
	MOV	C,M	; FETCH NEXT CHAR TO C REG
	CALL	CO	; SEND IT TO THE CONSOLE
	INX	H	; POINT TO NEXT CHARACTER
	DCR	B	; DECREMENT BYTE COUNTER
	JNZ	MSGL	; RETURN FOR NEXT CHARACTER
;
;****************************************
;
;            COMMAND RECOGNIZING ROUTINE
;
;******************************************
;
; FUNCTION: GETCM
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: GETCH,ECHO,ERROR
; DESTROYS: A,B,C,H,L,F/F'S
; DESCRIPTION: GETCM RECIEVES AN INPUT CHARACTER FROM THE USER
;	AND ATTEMPTS TO LOCATE THIS CHARACTER IN ITS COMMAND
;	CHARACTER TABLE. IF SUCCESSFUL, THE ROUTINE
;	CORRESPONDING TO THIS CHARACTER IS SELECTED FROM
;	A TABLE OF COMMAND ROUTINE ADDRESSES, AND CONTROL 
;	IS TRANSFERRED TO THIS ROUTINE. IF THE CHARACTER
;	DOES NOT MATCH ANY ENTRIES, CONTROL IS PASSED TO
;	THE ERROR HANDLER.
;
GETCM:
	LXI	SP,MSTAK	; ALWAYS WANT TO RESET STACK PTR TO MONITOR
			; /STARTING VALUE SO ROUTINES NEEDN'T CLEAN UP
	MVI	C,'.'	; PROMPT CHARACTER TO C
	CALL 	ECHO	; SEND PROMPT CHARACTER TO USER TERMINAL
	CALL	GETCH	; GET COMMAND CHARACTER TO A
	CALL	ECHO	; ECHO CHARACTER TO USER
	MOV	A,C	; PUT COMMAND CHARACTER INTO ACCUMULATOR
	LXI	B,NCMDS	; C CONTAINS LOOP AND INDEX COUNT
	LXI	H,CTAB	; HL POINTS INTO COMMAND TABLE
GTC05:
	CMP	M	; COMPARE TABLE ENTRY AND CHARACTER
	JZ	GTC10	; BRANCH IF EQUAL - COMMAND RECOGNIZED
	INX	H	; ELSE, INCREMENT TABLEPOINTER
	DCR	C	; DECREMENT LOOP COUNT
	JNZ	GTC05	; BRANCH IF NOT AT TABLE END
	JMP	ERROR	; ELSE, COMMAND CHARACTER IS ILLEGAL
GTC10:
	LXI	H,CADR	; IF GOOD COMMAND, LOAD ADDRESS OF TABLE
			; /OF COMMAND ROUTINE ADDRESSES
	DAD	B	; ADD WHAT IS LEFT OF LOOP COUNT
	DAD	B	; ADD AGAIN - EACH ENTRY IN CADR IS 2 BYTES LONG
	MOV	A,M	; GET LSP OF ADDRESS OF TABLE ENTRY TO A
	INX	H	; POINT TO NEXT BYTE IN TABLE
	MOV	H,M	; GET MSP OF ADDRESS OF TABLE ENTRY TO H
	MOV	L,A	; PUT LSP OF ADDRESS OF TABLE ENTRY INTO L
	PCHL		; NEXT INSTRUCTION COMES FROM COMMAND ROUTINE
;
;***********************************************************
;
;                   COMMAND IMPLEMENTING ROUTINES
;
;***********************************************************
;
; FUNCTION: DCMD
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: ECHO,NMOUT,HILO,GETCM,CROUT,GETNM
; DESTROYS: A,B,C,D,E,H,L,F/F'S
; DESCRIPTION: DCMD IMPLEMENTS THE DISPLAY MEMORY (D) COMMAND
;
DCMD:
	MVI	C,2	; GET TWO NUMBERS FROM INPUT STREAM
	CALL	GETNM
	POP	D	; ENDING ADDRESS TO DE
	POP	H	; STARTING ADDRESS TO HL
DCM05:
	CALL	CROUT	; ECHO CARRIAGE RETURN/LINE FEED
	CALL	ADRD	; DISPLAY ADDRESS
DCM10:
	MVI	C,' '
	CALL	ECHO	; USE BLANK AS SEPERATOR
	MOV	A,M	; GET CONTENTS OF NEXT MEMORY LOCATION
	CALL	NMOUT	; DISPLAY CONTENTS
	CALL	BREAK	; SEE IF USER WANTS OUT
	TRUE	EXIT	; IF SO, BRANCH TO EXIT
	CALL	HILO	; SEE IF ADDRESS OF DISPLAYED LOCATION IS
			; /GREATER THAN OR EQUAL TO ENDING ADDRESS
	TRUE	EXIT	; EXIT IF NO MORE TO DISPLAY
	INX	H	; IF MORE TO GO, POINT TO NEXT LOC TO DISPLAY
	MOV	A,L	; GET LOW ORDER BITS OF NEW ADDRESS
	ANI	NEWLN	; SEE IF LAST HEX DIGIT OF ADDRESS DENOTES
			; /START OF NEW LINE
	JNZ	DCM10	; NO - NOT AT END OF LINE
	JMP	DCM05	; YES - START NEW LINE WITH ADDRESS
;
;*************************************************************************
;
; FUNCTION: GCMD
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: ERROR,GETHX,RSTTF
; DESTROYS: A,B,C,D,E,H,F/F'S
; DESCRIPTION: GCMD IMPLEMENTS THE BEGIN EXECUTION (G) COMMAND
;
GCMD:
	CALL	GETHX	; GET ADDRESS (IF PRESENT) FROM INPUT STREAM
	FALSE	GCM05	; BRANCH IF NO NUMBER PRESENT
	MOV	A,D	; ELSE, GET TERMINATOR
	CPI	CR	; SEE IF CARRIAGE RETURN
	JNZ	ERROR	;  ERROR IF NOT PROPERLY TERMINATED
	LXI	H,PSAVE	 ; WANT NUMBER TO REPLACE SAVE PGM COUNTER
	MOV	M,C
	INX	H
	MOV	M,B
	JMP	GCM10
GCM05:
	MOV	A,D	; IF NO STARTING ADDRESS,MAKE SURE THAT 
	CPI	CR	; /CARRIAGE RETURN TERMINATED COMMAND
	JNZ	ERROR	; ERROR IF NOT
GCM10:
	JMP	RSTTF	; RESTORE REGISTERS AND BEGIN EXECUTION
;
;************************************************************
; FUNCTION: ICMD
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: ERROR,ECHO,GETCH,VALDL,VALDG,CNVBN,STHLF,GETNM,CROUT
; DESTROYS: A,B,C,D,E,H,L,F/F'S
; DESCRIPTION: ICMD IMPLEMENTS THE INSERT CODE INTO MEMORY (I) COMMAND.
;
ICMD:
	MVI	C,1
	CALL	GETNM	; GET SINGLE NUMBER FROM INPUT STREAM
	MVI	A,UPPER
	STA	TEMP	; TEMP WILL HOLD THE UPPER/LOWER HALF BYTE FLAG
	POP	D	; ADDRESS OF START TO DE
ICM05:
	CALL	GETCH	; GET A CHARACTER FROM INPUT STREAM
	CALL	ECHO	; ECHO IT
	MOV	A,C	; PUT CHARACTER BACK INTO A
	CPI	TERM	; SEE IF CHARACTER IS A TERMINATING CHARACTER
	JZ	ICM25	; IF SO, ALL DONE ENTERING CHARACTERS
	CALL	VALDL	; ELSE, SEE IF VALID DELIMITER
	TRUE	ICM05	; IF SO SIMPLY IGNORE THIS CHARACTER
	CALL	VALDG	; ELSE, CHECK TO SEE IF VALID HEX DIGIT
	FALSE	ICM20	; IF NOT, BRANCH TO HANDLE ERROR CONDITION
	CALL	CNVBN	; CONVERT DIGIT TO BINARY
	MOV	C,A	; MOVE RESULT TO C
	CALL	STHLF	; STORE IN APPROPIATE HALF WORD
	LDA	TEMP	; GET HALF BYTE FLAG
	ORA	A	; SET F/F'S
	JNZ	ICM10	; BRANCH IF FLAG SET FOR UPPER
	INX	D	; IF LOWER, INC ADDRESS OF BYTE TO STORE IN
ICM10:
	XRI	INVRT	; TOGGLE STATE OF FLAG
	STA	TEMP	; PUT NEW VALUE OF FLAG BACK
	JMP	ICM05	; PROCESS NEXT DIGIT
ICM20:
	CALL	STHF0	; ILLEGAL CHARACTER
	JMP	ERROR	; MAKE SURE ENTIRE BYTE FILLED THEN ERROR
ICM25:
	CALL	STHF0	; HERE FOR ESCAPE CHARACTER - INPUT IS DONE
	JMP	EXIT
;
;*********************************************************************
;
; FUNTION: MCMD
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: GETCM,HILO,GETNM
; DESTROYS: A,B,C,D,E,H,L,F/F'S
; DESCRIPTION: MCMD IMPLEMENTS THE MOVE DATA IN MEMORY (M) COMMAND
;
MCMD:
	MVI	C,3
	CALL	GETNM	; GET 3 NUMBERS FROM INPUT STREAM
	POP	B	; DESTINATION ADDRESS TO BC
	POP	H	; ENDING ADDRESS TO HL
	POP	D	; STARTING ADDRESS TO DE
MCM05:
	PUSH	H	; SAVE ENDING ADDRESS
	MOV	H,D
	MOV	L,E	; SOURCE ADDRESS TO HL
	MOV	A,M	; GET SOURCE BYTE
	MOV	H,B	
	MOV	L,C	; DESTINATION ADDRESS TO HL
	MOV	M,A	; MOVE BYTE TO DESTINATION
	INX	B	; INCREMENT DESTINATION ADDRESS
	MOV	A,B
	ORA	C	; TEST FOR DESTINATION ADDRESS OVERFLOW
	JZ	GETCM	; IF SO CAN TERMINATE COMMAND
	INX	D	; INCREMENT SOURCE ADDRESS
	POP	H	; ELSE, GET BACK ENDING ADDRESS
	CALL	HILO	; SEE IF ENDING ADDR>=SOURCE ADDR
	FALSE	GETCM	; IF NOT, COMMAND IS DONE
	JMP	MCM05	; MOVE ANOTHER BYTE
;
;*********************************************************************
;
; FUNCTION: SCMD
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: GETHX,GETCM,NMOUT,ECHO
; DESTROYS: A,B,C,D,E,H,L,F/F'S
; DESCRIPTION: SCMD IMPLEMENTS THE SUBSTITUTE INTO MEMORY (S) COMMAND
;
SCMD:
	CALL	GETHX	; GET A NUMBER, IF PRESENT, FROM INPUT
	PUSH	B
	POP	H	; GET NUMBER TO HL - DENOTES MEMORY LOCATION
SCM05:
	MOV	A,D	; GET TERMINATOR
	CPI	' '	; SEE IF SPACE
	JZ	SCM10	; YES - CONTINUE PROCESSING
	CPI	','	; ELSE, SEE IF COMMA
	JNZ	GETCM	; NO - TERMINATE COMMAND
SCM10:
	MOV	A,M	; GET CONTENTS OF SPECIFIED LOCATION TO A
	CALL	NMOUT	; DISPLAY CONTENTS ON CONSOLE
	MVI	C,'-'
	CALL	ECHO	; USE DASH FOR SEPERATOR
	CALL	GETHX	; GET NEW VALUE FOR MEMORY LOCATION, IF ANY
	FALSE	SCM15	; IF NO VALUE PRESENT, BRANCH
	MOV	M,C	; ELSE, STORE LOWER 8 BITS OF NUMBER ENTERED
SCM15:
	INX	H	; INCREMENT ADDRESS OF MEMORY LOCATION TO VIEW
	JMP	SCM05
;
;*********************************************************************
;
; FUNCTION: XCMD
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: GETCH,ECHHO,REGDS,GETCM,ERROR,RGADR,NMOUT,CROUT,GETHX
; DESTROYS: A,B,C,D,E,H,L,F/F'S
; DESCRIPTION: XCMD IMPLEMENTS THE REGISTER EXAMINE AND CHANGE (X)
; 		COMMAND.
;
XCMD:
	CALL	GETCH	; GET REGISTER IDENTIFIER
	CALL	ECHO	; ECHO IT
	MOV	A,C
	CPI	CR
	JNZ	XCM05	; BRANCH IF NOT CARRIAGE RETURN
	CALL	REGDS	; ELSE, DISPLAY REGISTER CONTENTS
	JMP	GETCM	; THEN TERMINATE COMMAND
XCM05:
	MOV	C,A	; GET REGISTER IDENTIFIER TO C
	CALL	RGADR	; CONVERT IDENTIFIER INTO RTAB TABLE ADDR
	PUSH	B
	POP	H	; PUT POINTER TO REGISTER ENTRY INTO HL
	MVI	C,' '
	CALL	ECHO	; ECHO SPACE TO USER
	MOV	A,C
	STA	TEMP	; PUT SPACE INTO TEMP AS DELIMITER
XCM10:
	LDA	TEMP	; GET TERMINATOR
	CPI	' '	; SEE IF BLANK
	JZ	XCM15	; YES - GO CHECK POINTER INTO TABLE
	CPI	','	; NO - SEE IF COMMA
	JNZ	GETCM	; NO - MUST BE CARRIAGE RETURN TO END COMMAND
XCM15:
	MOV	A,M
	ORA	A	; SET F/F'S
	JZ	EXIT	; BRANCH IF AT END OF TABLE
	PUSH	H	; PUT POINTER ON STACK
	MOV	E,M	
	MVI	D,HIGH (REGS); FETCH ADDRESS OF SAVE LOCATION FROM
	INX	H		; /TABLE
	MOV	B,M	; FETCH LENGTH FLAG FROM TABLE
	PUSH	D	; SAVE ADDRESS OF SAVE LOCATION
	PUSH	D
	POP	H	; MOVE ADDRESS TO HL
	PUSH	B	; SAVE LENGTH FLAG
	MOV	A,M	; GET 8 BITS OF REGISTER FROM SAVE LOCATION
	CALL	NMOUT	; DISPLAY IT
	POP	PSW	; GET BACK LENGTH FLAG
	PUSH	PSW	; SAVE IT AGAIN
	ORA	A	; SET F/F'S
	JZ	XCM20	; IF 8 BIT REGISTER, NOTHING MORE TO DISPLAY
	DCX	H	; ELSE, FOR 16 BIT REGISTER, GET LOWER 8 BITS
	MOV	A,M
	CALL	NMOUT	; DISPLAY THEM
XCM20:
	MVI	C,'-'
	CALL	ECHO	; USE DASH AS SEPERATOR
	CALL	GETHX	; SEE IF THERE IS A VALUE TO PUT INTO REGISTER
	FALSE	XCM30	; NO - GO CHECK FOR NEXT REGISTER
	MOV	A,D
	STA	TEMP	; ELSE, SAVE THE TERMINATOR FOR NOW
	POP	PSW	; GET BACK LENGTH FLAG
	POP	H	; PUT ADDRESS OF SAVE LOCATION INTO HL
	ORA	A	; SET F/F'S
	JZ	XCM25	; IF 8 BIT REGISTER, BRANCH
	MOV	M,B	; SAVE UPPER 8 BITS
	DCX	H	; POINT TO SAVE LOCATION FOR LOWER 8 BITS
XCM25:
	MOV	M,C	; STORE ALL OF 8 BIT OR LOWER 1/2 OF 16 BIT REG
XCM27:
	LXI	D,RTABS	; SIZE OF ENTRY IN RTAB TABLE
	POP	H	; POINTER INTO REGISTER TABLE RTAB
	DAD	D	; ADD ENTRY SIZE TO POINTER
	JMP	XCM10	; DO NEXT REGISTER
XCM30:
	MOV	A,D	; GET TERMINATOR
	STA	TEMP	; SAVE IN MEMORY
	POP	D	; CLEAR STACK OF LENGTH FLAG AND ADDRESS
	POP	D	; /OF SAVE LOCATION
	JMP	XCM27	; GO INCREMENT REGISTER TABLE POINTER
;
;***********************************************************************
;
;                UTILITY ROUTINES
;
;***********************************************************************
;
; FUNCTION: ADRD
; INPUTS: HL - ADDRESS TO BE DISPLAYED
; OUTPUTS: NONE
; CALLS: NMOUT
; DESTROYS: A
; DESCRIPTION: ADRD OUTPUTS TO THE CONSOLE THE ADDRESS
;              CONTAINED IN THE H,L REGISTERS.
;
ADRD:
	MOV	A,H	; DISPLAY FIRST HALF OF ADDRESS
	CALL	NMOUT
	MOV	A,L	; DISPLAY SECOND HALF OF ADDRESS
	CALL	NMOUT	
	RET		; RETURN TO CALLING ROUTINE
;
;***********************************************************************
;
; FUNCTION: ADROUT
; INPUTS: USER REGISTERS ON THE STACK 
; OUTPUTS: NOTHING
; CALLS: ECHO,ADRD
; DESTROYS:A,B,C,D,E,H,L,F/F'S
; DESCRIPTION: ADROUT SAVES THE USER REGISTERS AND OUTPUTS TO THE
;              CONSOLE THE USER P COUNTER AFTER A RST 1 INSTRUCTION.
;
ADROUT:
	PUSH	PSW	; SAVE A AND FLAGS
	PUSH	B	; SAVE B AND C
	PUSH	D	; SAVE D AND E
	MVI	C,'#'
	CALL	ECHO	; OUTPUT '#'
	LHLD	PSAVE	; LOAD USER P COUNTER
	CALL	ADRD	; DISPLAY ADDRESS
	JMP	EXIT	; GET NEW COMMAND
;
; FUNCTION: BREAK
; INPUTS: NONE
; OUTPUTS: CARRY - 1 IF ESCAPE CHARACTER INPUT
;                - 0 IF ANY OTHER CHARACTER OR NO CHARACTER PENDING
; CALLS: NOTHING
; DESTROYS: A,F/F'S
; DESCRIPTION: BRAEK IS USED TO SENSE AN ESCAPE CHARACTER FROM
;              THE USER. IF NO CHARACTER IS PENDING, OR IF THE
;              PENDING CHARACTER IS NOT THE ESCAPE, THEN A FAILURE
;              RETURN (CARRY=0) IS TAKEN. IN THIS CASE, THE
;              PENDING CHARACTER (IF ANY) IS LOST. IF THE PENDING 
;              CHARACTER IS AN ESCAPE CHARACTER, BREAK TAKES A SUCCESS
;              RETURN (CARRY=1).
;
BREAK:
	IN	CONST	; GET CONSOLE STATUS
	ANI	RBR	; SEE IF CHARACTER PENDING
	JZ	FRET	; NO - TAKE FAILURE RETURN
	IN	CNIN	; YES - PICK UP CHARACTER
	ANI	PRTYO	; STRIP OF PARITY BIT
	CPI	BRCHR	; SEE IF BREAK CHARACTER
	JZ	SRET	; YES - SUCCESS RETURN
	JMP	FRET	; NO - FAILURE RETURN - CHARACTER LOST
;
; INPUTS: NONE
; OUTPUTS: A - CHARACTER FROM CONSOLE
; CALLS: NOTHING
; DESTROYS: A,F/F'S
; DESCRIPTION: CI WAITS UNTIL A CHARACTER HAS BEEN ENTERED AT THE
;              CONSOLE AND THEN RETURNS THE CHARACTER, VIA THE A
;              REGISTER, TO THE CALLING ROUTINE. THIS ROUTINE
;              IS CALLED BY THE USER VIA A JUMP TABLE IN RAM.
;
CI:
	IN	CONST	; GET STATUS OF CONSOLE
	ANI	RBR	; CHECK FOR RECEIVER BUFFER READY
	JZ	CI	; NOT YET - WAIT
	IN	CNIN	; READY SO GET CHARACTER
	RET
;
;*******************************************************
;
; FUNCTION: CNVBN
; INPUTS: C - ASCII CHARACTER '0'-'9' OR 'A'-'F'
; OUTPUTS: A - 0 TO F HEX
; CALLS: NOTHING
; DESTROYS: A,F/F'S
; DESCRIPTION: CNVBN CONVERTS THE ASCII REPRESENTATION OF A HEX
;              CHARACTER INTO ITS CORRESPONDIG BINARY VALUE. CNVBN
;              DOES NOT CHECK THE VALIDITY OF ITS INPUT.
;
CNVBN:
	MOV	A,C
	SUI	'0'	; SUBTRACT CODE FOR '0' FROM ARGUMENT
	CPI	10	; WANT TO TEST FOR RESULT OF 0 TO 9
	RM		; IF SO, THEN ALL DONE
	SUI	7	; ELSE, RESULT BETWEEN 17 AND 23 DECIMAL
	RET		; SO RETURN AFTER SUBTRACTING BIAS OF 7
;
;**********************************************************
;
; FUNCTION: CO
; INPUTS; C - CHARACTER TO OUTPUT TO CONSOLE
; OUTPUTS: C - CHARACTER OUTPUT TO CONSOLE
; CALLS: NOTHING
; DESTROYS: A,F/F'S
; DESCRIPTION: CO WAITS UNTIL THE THE CONSOLE IS READY TO ACCEPT
;              A CHARACTER AND THEN SENDS THE INPUT ARGUMENT
;              TO THE CONSOLE.
;
CO:
	IN	CONST	; GET STATUS OF CONSOLE
	ANI	TRDY	; SEE IF TRANSMITTER READY
	JZ	CO	; NO - WAIT
	MOV	A,C	; ELSE, MOVE CHARACTER TO A REGISTER FOR OUTPUT
	OUT	CNOUT	; SEND TO CONSOLE
	RET
;
;*******************************************************
;
; FUNCTION: CROUT
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: ECHO
; DESTROYS: A,B,C,F/F'S
; DESCRIPTION: CROUT SENDS A CARRIAGE REURN (AND THENCE A LINE
;              FEED) TO THE CONSOLE
;
CROUT:
	MVI	C,CR
	CALL	ECHO	; OUTPUT CARRIAGE RETURN TO USER TERMINAL
	RET
;
;*******************************************************
;
; FUNCTION: ECHO
; INPUTS: C - CHARACTER TO ECHO TO TERMINAL
; OUTPUTS: C - CHARACTER ECHOED TO TERMINAL
; CALLS: CO
; DESTROYS: A,B,F/F'S
; DESCRIPTION: ECHO TAKES A SINGLE CHARACTER AS INPUT AND, VIA
;              THE MONITOR, SENDS THAT CHARACTER TO THE USER
;              TERMINAL. A CARRIAGE RETURN IS ECHOED AS CARRIAGE
;              RETURN/ LINE FEED, AND AN ESCAPE CHARACTER IS ECHOED
;              AS $
;
ECHO:
	MOV	B,C	; SAVE ARGUMENT
	MVI	A,ESC
	CMP	B	; SEE IF ECHOING AN ESCAPE CHARACTER
	JNZ	ECH05	; NO - BRANCH
	MVI	C,'$'	; YES - ECHO AS $
ECH05:
	CALL	CO	; DO OUTPUT THROUGH MONITOR
	MVI	A,CR
	CMP	B	; SEE IF ECHOING A CARRIAGE RETURN
	JNZ	ECH10	; NO - NO NEED FOR SPECIAL ACTION
	MVI	C,LF	; YES - WANT TO ECHO A LINE FEED, TOO
	CALL	CO
ECH10:
	MOV	C,B	; RESTORE ARGUMENT
	RET
;
;***********************************************************************
;
; FUNCTION: ERROR
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: ECHO,CROUT,GETCM
; DESTROYS: A,B,C,F/F'S
; DESCRIPTION: ERROR PRINTS THE ERROR CHARACTER (CURRENTLY AN ASTERISK)
;              ON THE CONSOLE, FOLLOWED BY A CARRIAGE RETURN-LINE FEED,
;              AND THEN RETURNS CONTROL TO THE COMMAND RECOGNISER.
;
ERROR:
	MVI	C,'#'
	CALL	ECHO	; SEND # TO CONSOLE
EXIT:
	CALL	CROUT	; SKIP TO BEGINING OF NEXT LINE
	JMP	GETCM	; TRY AGAIN FOR ANOTHER COMMAND
;
;***********************************************************************
;
; FUNCTION: FRET
; INPUTS: NONE
; OUTPUTS: CARRY - ALWAYS 0
; CALLS: NOTHING
; DESTROYS: CARRY
; DESCRIPTION: FRET IS JUMPED TO BY ANY ROUTINE THAT WISHES TO
;              INDICATE FAILURE ON RETURN. FRET SETS THE CARRY
;              FALSE, DENOTING FAILURE, AND THEN RETURNS TO THE
;              CALLER OF THE ROUTINE INVOKING FRET
;
FRET: 
	STC		; FIRST SET CARRY TRUE
	CMC		; THEN COMPLIMENT IT TO MAKE IT FALSE
	RET		; RETURN APPROPRIATELY
;
;***********************************************************************
;
; FUNCTION: GETCH
; INPUTS: NONE
; OUTPUTS: C - NEXT CHARACTER IN INPUT STREAM
; CALLS: CI
; DESTROYS: A,C,F/F'S
; DESCRIPTION: GETCH RETURNS THE NEXT CHARACTER IN THE INPUT STREAM
;              TO THE CALLING PROGRAM
;
GETCH:
	CALL	CI	; GET CHARACTER FROM TERMINAL
	ANI	PRTYO	; TURN OFF PARITY BIT IN CASE SET BY CONSOLE
	MOV	C,A	; PUT VALUE IN C REGISTER FOR RETURN
	RET
;
;***********************************************************************
;
; FUNCTION: GETHX
; INPUTS: NONE
; OUTPUTS: BC - 16 BIT INTEGER
;          D - CHARACTER WHICH TERMINATED THE INTEGER
;          CARRY - 1 IF FIRST CHARACTER NOT DELIMITER
;                - 0 IF FIRST CHARACTER IS DELIMITER
; CALLS: GETCH,ECHO,VALDL,VALDG,CNVBN,ERROR
; DESTROYS: A,B,C,D,E,F/F'S
; DESCRIPTION: GETHX ACCEPTS A STRING OF HEX DIGITS FROM THE INPUT
;              STREAM AND RETURNS THEIR VALUE AS A 16 BIT BINARY
;              INTEGER. IF MORE THAN 4 HEX DIGITS ARE ENTERED,
;              ONLY THE LAST 4 ARE USED. THE NUMBER TERMINATES WHEN 
;              A VALID DELIMITER IS ENCOUNTERED. THE DELIMITER IS
;              ALSO RETURNED AS AN OUTPUT OF THE FUNCTION. ILLEGAL
;              CHARACTERS (NOT HEX CHARACTERS OR DELIMITERS) CAUSE AN
;              ERROR INDICATION. IF THE FIRST (VALID) CHARACTER
;              ENCONTERED IN THE INPUT STREAM IS NOT A DELIMITER,
;              GETHX WILL RETURN WITH THE CARRY BIT SET TO 1;
;              OTHERWISE, THE CARRY BIT IS SET TO 0 AND THE CONTENTS 
;              OF BC ARE UNDEFINED.
;
GETHX:
	PUSH	H	; SAVE HL
	LXI	H,0	; INITIALISE RESULT
	MVI	E,0	; INITIALISE DIGIT FLAG TO FALSE
GHX05: 
	CALL	GETCH	; GET A CHARACTER
	CALL	ECHO	; ECHO THE CHARACTER
	CALL	VALDL	; SEE IF DELIMITER
	FALSE	GHX10	; NO - BRANCH
	MOV	D,C	; YES - ALL DONE, BUT WANT TO RETURN DELIMITER
	PUSH	H
	POP	B	; MOVE RESULT TO BC
	POP	H	; RESTORE HL
	MOV	A,E	; GET FLAG
	ORA	A	; SET F/F'S
	JNZ	SRET	; IF FLAG NON-0, A NUMBER HAS BEEN FOUND
	JZ	FRET	; ELSE, DELIMITER WAS FIRST CHARACTER
GHX10:
	CALL	VALDG	; IF NOT DELIMITER, SEE IF DIGIT
	FALSE	ERROR	; ERROR IF NOT A VALID DIGIT, EITHER
	CALL	CNVBN	; CONVERT DIGIT TO ITS BINARY VALUE
	MVI	E,0FFH	; SET DIGIT FLAG NON-0
	DAD	H	; *2
	DAD	H	; *4
	DAD	H	; *8
	DAD	H	; *16
	MVI	B,0	; CLEAR UPPER 8 BITS OF BC PAIR
	MOV	C,A	; BINARY VALUE OF CHARACTER INTO C
	DAD	B	; ADD THHIS VALUE TO PARTIAL RESULT
	JMP	GHX05	; GET NEXT CHARACTER
;
;***********************************************************************
;
; FUNCTION: GETNM
; INPUTS: C - COUNT OF NUMBERS TO FIND IN INPUT STREAM
; OUTPUTS: TOP OF STACK - NUMBERS FOUND IN REVERSE ORDER (LAST ON TOP
;                         OF STACK)
; CALLS: GETHX,HILO,ERROR
; DESTROYS: A,B,C,D,E,H,L,F/F'S
; DESCRIPTION: GETNM FINDS A SPECIFIED COUNT OF NUMBERS , BETWEEN 1
;              AND 3, INCLUSIVE, IN THE INPUT
;              STREAM AND RETURNS THEIR VALUES ON THE STACK. IF 2
;              OR MORE NUMBERS ARE REQUESTED, THEN THE FIRST MUST BE
;              LESS THAN OR EQUAL TO THE SECOND, OR THE FIRST AND
;              SECOND NUMBERS WILL BE SET EQUAL. THE LAST NUMBER
;              REQUESTED MUST BE TERMINATED BY A CARRIAGE RETURN
;              OR AN ERROR INDICATION WILL RESULT.
;
GETNM: 	
	MVI	L,3	; PUT MAXIMUM ARGUMENT COUNT INTO L
	MOV	A,C	; GET THE ACTUAL ARGUMENT COUNT
	ANI	3	; FORCE TO MAXIMUM OF 3
	RZ		; IF 0,DON'T BOTHER TO DO ANYTHING
	MOV	H,A	; ELSE, PUT ACTUAL COUNT INTO H
GNM05:
	CALL	GETHX	; GET A NUMBER FROM INPUT STREAM
	FALSE	ERROR	; ERROR IF NOT THERE - TOO FEW NUMBERS
	PUSH	B	; ELSE, SAVE NUMBER ON STACK
	DCR	L	; DECREMENT MAXIMUM ARGUMENT COUNT
	DCR	H	; DECREMENT ACTUAL ARGUMENT COUNT
	JZ	GNM10	; BRANCH IF NO MORE NUMBERS WANTED
	MOV	A,D	; ELSE, GET NUMBER TERMINATOR TO A
	CPI	CR	; SEE IF CARRIAGE RETURN
	JZ	ERROR	; ERROR IF SO - TOO FEW NUMBERS
	JMP	GNM05	; ELSE, PROCESS NEXT NUMBER
GNM10:
	MOV	A,D	; WHEN COUNT0, CHECK LAST TERMINATOR
	CPI	CR
	JNZ	ERROR	; ERROR IF NOT CARRIAGE RETURN
	LXI	B,0FFFFH	; HL GETS LARGEST NUMBER
	MOV	A,L	; GET WHAT'S LEFT OF MAXIMUM ARG COUNT
	ORA	A	; CHECK FOR 0
	JZ	GNM20	; IF YES, THREE NUMBERS WERE INPUT
GNM15:
	PUSH	B	; IF NOT, FILL REMAINING ARGUMENTS WITH 0FFFFH
	DCR	L
	JNZ	GNM15
GNM20:
	POP	B	; GET THE THREE ARGUMENTS OUT
	POP	D
	POP	H
	CALL	HILO	; SEE IF FIRST >= SECOND
	FALSE	GNM25	; NO - BRANCH
	MOV	D,H
	MOV	E,L	; YES - MAKE SECOND EQUAL TO THE FIRST
GNM25:
	XTHL		; PUT FIRST ON STACK - GET RETURN ADDR
	PUSH	D	; PUT SECOND ON STACK
	PUSH	B	; PUT THIRD ON STACK
	PUSH	H	; PUT RETURN ADDRESS ON STACK
GNM30:
	DCR	A	; DECRIMENT RESIDUAL COUNT
	RM		; IF NEGATIVE, PROPER RESULTS ON STACK
	POP	H	; ELSE, GET RETURN ADDR
	XTHL		; REPLACE TOP RESULT WITH RETURN ADDR
	JMP	GNM30	; TRY AGAIN
;
;*********************************************************************
;
; FUNCTION: HILO
; INPUTS: DE - 16 BIT INTEGER
; 	  HL - 16 BIT INTEGER
; OUTPUTS: CARRY - 0 IF HL<DE
;                - 1 IF HL>=DE
; CALLS: NOTHING
; DESTROYS: A,F/F'S
; DESCRIPTION: HILO COMPARES THE 2 16 BIT INTEGERS IN HL AND DE. THE
;              INTEGERS ARE TREATED AS UNSIGNED NUMBERS. THE CARRY
;              BIT IS SET ACCORDING TO THE RESULT OF THE COMPARISON.;
HILO:
	PUSH	B	; SAVE BC
	MOV	B,A	; SAVE A REGISTER
	INX	H	; INCREMENT HL BY 1
	MOV	A,H	; WANT TO TEST FOR 0 RESULT AFTER
	ORA	L	; /INCREMENTING
	DCX	H	; RESTORE HL
	STC		; SET CARRY
	JZ	HIL05	; IF SO, CARRY IS SET PROPERLY
	MOV	A,L	; IF NOT, MOVE L TO A
	SUB	E	; SUBTRACT E
	MOV	A,H	; MOVE H TO A
	SBB	D	; SUBTRACT D WITH BORROW
	CMC		; COMPLIMENT CARRY FOR CORRECT CARRY BIT VALUE
HIL05:
	MOV	A,B	; RESTORE A
	POP	B	; RESTORE BC
	RET		; EXIT
;
;*********************************************************************
;
; FUNCTION: INUST
; INPUTS: NONE
; OUTPUTS: NOTHING
; CALLS: NOTHING
; DESTROYS: A,HH,L,SP
; DESCRIPTION: INUST OUTPUTS TO THE USART THE COMMAND WORD
;              AND INITIALIZES THE STACK POINTER.
;
INUST:
	MVI	A,CMD
	OUT	CNCTL	; OUTPUT COMMAND WORD TO USART
;
	MVI	A,COC	; SET 8253 FOR 110 BAUD RATE
	OUT	CCP
	MVI	A,LOW(BRF)
	OUT	LC2P
	MVI	A,HIGH(BRF)
	OUT	LC2P
;
	MVI	A,PTCW	; SET UP PARALLEL I/O FOR HIGH SPEED PAPER TAPE
	OUT	PTC
	LXI	H,MSTAK-44	; LOAD POINTER TO STACK
	SHLD	SSAVE	; INITIALIZE USER STACK POINTER
	LXI	SP,MSTAK	; INITIALIZE MONITOR STACK
	JMP	SOMSG	; GO TO PRINT SIGNON MESSAGE
;
;*********************************************************************
;
; FUNCTION: NMOUT
; INPUTS: A - 8 BIT INTEGER
; OUTPUTS: NONE
; CALLS: ECHO,PRVAL
; DESTROYS: A,B,C,F/F'S
; DESCRIPTION: NMOUT CONVERTS THE 8 BIT, UNSIGNED INTEGER IN THE
;              A REGISTER INTO 2 ASCII CHARACTERS. THHE ASCII CHARACTERS
;              ARE THE ONES REPRESENTING THE 8 BITS. THESE TWO
;              CHRACTERS ARE SENT TO THE CONSOLE AT THE CURRENT PRINT
;              POSITION OF THE CONSOLE.
;
NMOUT:
	PUSH	PSW	; SAVE ARGUMENT
	RRC
	RRC
	RRC
	RRC		; GET UPPER 4 BITS TO LOW 4 BIT POSITIONS
	CALL	PRVAL	; CONVERT LOWER 4 BITS TO ASCII
	CALL	ECHO	; SEND TO TERMINAL
	POP	PSW	; GET BACK ARGUMENT
	CALL	PRVAL
	CALL	ECHO
	RET
;
;*********************************************************************
;
; FUNCTION: PRVAL
; INPUTS: A - INTEGER, RANGE 0 TO F
; OUTPUTS: A - ASCII CHARACTER
; CALLS: NOTHING
; DESTROYS: NOTHING
; DESCRIPTION: PRVAL CONVERTS A NUMBER IN THE RANGE 0 TO F HEX TO
;              THE CORRESPONDING ASCII CHARACTERS, 0-9,A-F. PRVAL
;              DOES NOT CHECK THE VALIDITY OF ITS INPUT ARGUMENT.
;
PRVAL:
	ANI	HCHAR	; MASK OUT UPPER 4 BITS - WANT 1 HEX CHAR
	ADI	90H	; SET UP A SO THAT A-F CAUSE A CARRY
	DAA		; ADJUST CONTENTS OF A REGISTER
	ACI	40H	; ADD IN CARRY AND ADJUST UPPER 4 BITS
	DAA		; ADJUST CONTENTS OF A REGISTER AGAIN
	MOV	C,A	; MOVE ASCII CHARACTER TO C
	RET		; ALL DONE
;
;*********************************************************************
;
; FUNCTION: REGDS
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: ECHHO,NMOUT,ERROR,CROUT
; DESTROYS: A,B,C,D,E,HH,L,F/F'S
; DESCRIPTION: REGDS DISPLAYS THE CONTENTS OF THE REGISTER SAVE
;              LOCATIONS, IN FORMATTED FORM, ON THE CONSOLE. THE
;              DISPLAY IS DRIVEN FROM A TABLE, RTAB, WHICH CONTAINS
;              THE REGISTER'S PRINT SYMBOL, SAVE LOCATION ADDRESS,
;              AND LENGTH (8 OR 16 BITS).
;
REGDS:
	LXI	H,RTAB	; LOAD HL WITHHH ADDRESS OF START OF TABLE
REG05:
	MOV	C,M	; GET PRINT SYMBOL OF REGISTER
	MOV	A,C
	ORA	A	; TEST FOR 0 - END OF TABLE
	JNZ	REG10	; IF NOT END, BRANCH
	CALL	CROUT	; ELSE, CARRIAGE RETURN/LINE FEED TO END
	RET		; /DISPLAY
REG10:
	CALL	ECHO	; ECHO CHARACTER
	MVI	C,'='
	CALL	ECHO	; OUTPUT EQUALS SIGN, I.E. A=
	INX	H	; POINT TO START OF SAVE LOCATION ADDRESS
	MOV	E,M	; GET LSP OF SAVE LOCATION ADDRESS TO E
	MVI	D,HIGH (REGS); PUT MSP OF SAVE LOC ADDRESS INTO D
	INX	H	; POINT TO LENGTH FLAG
	LDAX	D	; GET CONTENTS OF SAVE ADDRESS
	CALL	NMOUT	; DISPLAY ON CONSOLE
	MOV	A,M	; GET LENGTH FLAG
	ORA	A	; SET SIGN F/F
	JZ	REG15	; IF 0, REGISTER IS 8 BITS
	DCX	D	; ELSE, 16 BIT REGISTER SO MORE TO DISPLAY
	LDAX	D	; GET LOWER 8 BITS
	CALL	NMOUT	; DISPLAY THEM
REG15:
	MVI	C,' '
	CALL	ECHO	; OUTPUT BLANK CHARACTER
	INX	H	; POINT TO START OF NEXT TABLE ENTRY
	JMP	REG05	; DO NEXT REGISTER
;
;*********************************************************************
;
; FUNCTION: RGADR
; INPUTS: C - CHARACTER DENOTING REGISTER
; OUTPUTS: BC - ADDRESS OF ENTRY IN RTAB CORRESPONDING TO REGISTER
; CALLS: ERROR
; DESTROYS: A,B,C,D,E,H,L,F/F'S
; DESCRIPTION: RGADR TAKES A SINGLE CHARACTER AS INPUT . THIS CHARACTER
;              DENOTES A REGISTER. RGADR SEARCHES THE TABLE RTAB
;              FOR A MATCH ON THE INPUT ARGUMENT. IF ONE OCCURS,
;              RGADR RETURNS THE ADDRESS OF THE ADDRESS OF THE
;              SAVE LOCATION CORRESPONDING TO THE REGISTER.
;              THIS ADDRESS POINTS INTO RTAB. IF NO MATCH OCCURS, THEN
;              THE REGISTER IDENTIFIER IS ILLEGAL AND CONTROL IS
;              PASSED TO THE ERROR ROUTINE.
;
RGADR:
	LXI	H,RTAB	; HL GETS ADDRES OF TABLE START
	LXI	D,RTABS	; DE GET SIZE OF A TABLE ENTRY     
RGA05:
	MOV	A,M	; GET REGISTER IDENTIFIER
	ORA	A	; CHECK FOR TABLE END (IDENTIFIER IS 0)
	JZ	ERROR	; IF AT END OF TABLE, ARGUMENT IS ILLEGAL
	CMP	C	; ELSE, COMPARE TABLE ENTRY AND ARGUMENT
	JZ	RGA10	; IF EQUAL, WE'VE FOUND WHAT WERE LOOKING FOR
	DAD	D	; ELSE, INCREMENT TABLE POINTER TO NEXT ENTRY
	JMP	RGA05	; TRY AGAIN
RGA10:
	INX	H	; IF A MATCH, INCREMENT TABLE POINTER TO
	MOV	B,H	; /SAVE LOCATION ADDRESS
	MOV	C,L	; RETURN THIS VALUE
	RET
;
;*********************************************************************
;
; FUNCTION: RSTTF
; INPUTS: NONE 
; OUTPUTS: NONE
; CALLS: NOTHING
; DESTROYS: A,B,C,D,E,H,L,F/F'S
; DESCRIPTION: RSTTF RESTORES ALL CPU REGISTER, FLIP/FLOPS, STACK
;              POINTER AND PROGRAM COUNTER FROM THEIR RESPECTIVE
;              SAVE LOCATIONS IN MEMORY. THE ROUTINE THEN TRANSFERS 
;              CONTROL TO THE LOCATION SPECIFIED BY THE PROGRAM
;              COUNTER (I.E. THE RESTORED VALUE). THE ROUTINE
;              EXITS WITH THE INTERRUPTS ENABLED.
;
RSTTF:
	DI		; DISABLE INTERRUPTS WHILE RESTORING THINGS
	LXI	SP,MSTAK	; SET MONITOR STACK POINTER TO START
			; /OF STACK
	POP	D	; START ALSO END OF REGISTER SAVE AREA
	POP	B
	POP	PSW
	LHLD	SSAVE	; RESTORE USER STACK POINTER
	SPHL
	LHLD	PSAVE	
	PUSH	H	; PUT USER RETURN ADDRESS ON USER STACK
	LHLD	LSAVE	; RESTORE HL REGISTERS
	EI		; ENABLE INTERRUPTS NOW
	RET		; JUMP TO RESTORED PC LOCATION
;
;*********************************************************************
;
; FUNCTION: SRET
; INPUTS: NONE
; OUTPUTS: CARRY = 1
; DESTROYS: CARRY
; DESCRIPTION: SRET IS JUMPED TO BY ROUTINES WISHING TO RETURN SUCCESS.
;              SRET SETS THE CARRY TRUE AND THEN RETURNS TO THE
;              CALLER OF THE ROUTINE INVOKING SRET.
;
SRET:
	STC		; SET CARRY TRUE
	RET		; RETURN APPROPRIATELY
;
;*********************************************************************
;
; FUNTION: STHF0
; INPUTS: DE - 16 BIT ADDRESS OF BYTE TO BE STORED INTO
; OUTPUTS: NONE
; CALLS: NOTHING
; DESTROYS: A,B,C,H,L,F/F'S
; DESCRIPTION: STHF0 CHECKS THE HALF BYTE FLAG IN TEMP TO SEE IF
;              IT IS SET TO LOWER. IF SO, STHF0 STORES A 0 TO
;              PAD OUT THE LOWER HALF OF THE ADDRESSED BYTE;
;              OTHERWISE, THE ROUTINE TAKES NO ACTION.
;
STHF0:
	LDA	TEMP	; GET HALF BYTE FLAG
	ORA	A	; SET F/F'S
	RNZ		; IF SET TO UPPER, DON'T DO ANYTHING
	MVI	C,0	; ELSE, WANT TO STORE THE VALUE 0
	CALL	STHLF	; DO IT
	RET
;
;*********************************************************************
;
; FUNCTION: STHLF
; INPUTS: C - 4 BIT VALUE TO BE STORED IN HALF BYTE
;         DE - 16 BIT ADDRESS OF BYTE TO BE STORED INTO
; OUTPUTS: NONE
; CALLS: NOTHING
; DESTROYS: A,B,C,H,L,F/F'S
; DESCRIPTION: STHLF TAKES THE 4 BIT VALUE IN C AND STORES IT IN
;              HALF OF THE BYTE ADDRESSED BY REGISTERS DE. THE
;              HALF BYTE USED (EITHER UPPER OR LOWER) IS DENOTED
;              BY THE VALUE OF THE FLAG IN TEMP. STHLF ASSUMES
;              THAT THIS FLAG HAS BEEN PREVIOUSLY SET
;              (NOMINALLY BY ICMD).
;
STHLF:
	PUSH	D
	POP	H	; MOVE ADDRESS OF BYTE INTO HL
	MOV	A,C	; GET VALUE
	ANI	0FH	; FORCE TO 4 BIT LENGTH
	MOV	C,A	; PUT VALUE BACK
	LDA	TEMP	; GET HALF BYTE FLAG
	ORA	A	; CHECK FOR LOWER HALF
	JNZ	STH05	; BRANCH IF NOT
	MOV	A,M	; ELSE, GET BYTE
	ANI	0F0H	; CLEAR LOWER 4 BITS
	ORA	C	; OR IN VALUE
	MOV	M,A	; PUT BYTE BACK
	RET
STH05:
	MOV	A,M	; IF UPPER HALF, GET BYTE
	ANI	0FH	; CLEAR UPPER 4 BITS
	MOV	B,A	; SAVE BYTE IN B
	MOV	A,C	; GET VALUE
	RRC
	RRC
	RRC
	RRC		; ALIGN TO UPPER 4 BITS
	ORA	B	; OR IN ORIGINAL LOWER 4 BITS
	MOV	M,A	; PUT NEW CONFIGURATION BACK
	RET
;
;*********************************************************************
;
; FUNCTION: VALDG
; INPUTS: C - ASCII CHARACTER
; OUTPUTS: CARRY - 1 IF CHARACTER REPRESENTS VALID HEX DIGIT
;                - 0 OTHERWISE
; CALLS: NOTHING
; DESTROYS: A,F/F'S
; DECRIPTION: VALDG RETURNS SUCCESS IF ITS INPUT ARGUMENT IS
;             AN ASCII CHARACTER REPRESENTING A VALID HEX DIGIT
;             (0-9,A-F), AND FAILURE OTHERWISE.
;
VALDG:
	MOV	A,C
	CPI	'0'	; TEST CHARACTER AGAINST '0'
	JM	FRET	;F A CODE LESS, CANNOT BE VALID DIGIT
	CPI	'9'	; ELSE, SEE IF IN RANGE '0'-'9'
	JM	SRET	; CODE BETWEEN '0' AND '9'
	JZ	SRET	; CODE EQUAL '9'
	CPI	'A'	; NOT A DIGIT - TRY FOR A LETTER
	JM	FRET	; NO - CODE BETWEEN '9' AND 'A'
	CPI	'G'
	JP	FRET	; NO - CODE GREATER THAN 'F'
	JMP	SRET	; OKAY - CODE IS 'A' TO 'F', INCLUSIVE
;
;
;**********************************************************************
;
;
; FUNCTION: VALDL
; INPUTS: C - CHARACTER
; OUTPUTS: CARRY - 1 IF INPUT ARGUMENT VALID DELIMITER
;                - 0 OTHERWISE
; CALLS: NOTHING
; DESTROYS: A,F/F'S
; DESCRIPTION: VALDL RETURNS SUCCESS IF ITS INPUT ARGUMENT IS A VALID
;              DELIMITER CHARACTER (SPACE, COMMA, CARRIAGE RETURN) AND
;              FAILURE OTHERWISE.
;
VALDL:
	MOV	A,C
	CPI	','	; CHECK FOR COMMA
	JZ	SRET
	CPI	CR	; CHECK FOR CARRIAGE RETURN
	JZ	SRET
	CPI	' '	; CHECK FOR SPACE
	JZ	SRET
	JMP	FRET	; ERROR IF NONE OF THE ABOVE
;
;*********************************************************************
;
;
;                        MONITOR TABLES
;
;
;*********************************************************************
;
;
SGNON:
	DB	CR,LF,'PASK''S MONITOR V6.0',CR,LF


LSGNON		EQU	$-SGNON ; LENGTH OF SIGNON MESSAGE
;
CADR:			; TABLE OF ADDRESSES OF COMMAND ROUTINES
	DW	0	; DUMMY
	DW	XCMD
	DW	SCMD
	DW	MCMD
	DW	ICMD
	DW	GCMD
	DW	DCMD
	DW	RCMD
	DW	WCMD
;
CTAB:			; TABLE OF VALID COMMAND CHARACTERS
	DB	'W'
	DB	'R'
	DB	'D'
	DB	'G'
	DB	'I'
	DB	'M'
	DB	'S'
	DB	'X'
NCMDS	EQU	$-CTAB	; NUMBER OF VALID COMMANDS
;
RTAB:			; TABLE OF REGISTER INFORMATION
	DB	'A'	; REGISTER IDENTIFIER
	DB	ASAVE AND 0FFH	; ADDRESS OF REGISTER SAVE LOCATION
	DB	0	; LENGTH FLAG 0=8 BITS, 1=16 BITS
RTABS	EQU	$-RTAB	; SIZE OF AN ENTRY IN THIS TABLE
	DB	'B'
	DB	BSAVE AND 0FFH
	DB	0
	DB	'C'
	DB	CSAVE AND 0FFH
	DB	0
	DB	'D'
	DB	DSAVE AND 0FFH
	DB	0
	DB	'E'
	DB	ESAVE AND 0FFH
	DB	0
	DB	'F'
	DB	FSAVE AND 0FFH
	DB	0
	DB	'H'
	DB	HSAVE AND 0FFH
	DB	0
	DB	'L'
	DB	LSAVE AND 0FFH
	DB	0
	DB	'M'
	DB	HSAVE AND 0FFH
	DB	1
	DB	'P'
	DB	PSAVE+1 AND 0FFH
	DB	1
	DB	'S'
	DB	SSAVE+1 AND 0FFH
	DB	1
	DB	0	; END OF TABLE MARKERS
	DB	0
;
;********************************************************************
;
	ORG	BRTAB
;
	JMP	CO	; BRANCH TABLE FOR USER ACCESSIBLE ROUTINES
	JMP	CI
	JMP	RI
	JMP	PO
;
;********************************************************************
;
; FUNCTION: RCMD
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: GETCH,ECHO,CO RICH,BYTE
; DESTROYS: A,B,C,D,E,H,L,F/F`S
; DESCRIPTION: RCMD IMPLIMENTS THE READ HEXADECIMAL TAPE (R)
;              COMMAND
;
RCMD:
	CALL	GETCH	; GET CARRIAGE RETURN CHARACTER
	CALL	ECHO	; ECHO IT
	MOV	A,C	; MOVE IT TO A REGISTER
	CPI	CR	; SEE IF CARRIAGE RETURN
	JNZ	ERROR	; ERROR IF NOT PROPERLY TERMINATED
RCM05:
	CALL	RICH	; READ CHARACTER FROM TAPE
	CPI	':'	; SEE IF RECORD MARK
	JNZ	RCM05	; TRY AGAIN IF NOT MARK
	XRA	A	; ZERO A REGISTER
	MOV	D,A	; INITIALISE D FOR HOLDING THE CHECKSUM
	CALL	BYTE	; READ TWO CHARACTERS FROM TAPE
	JZ	GETCM	; IF ZERO RECORD LENGTH, ALL DONE
	MOV	E,A	; OTHERWISE, PUT THE RECORD LENGTH IN E
	CALL	BYTE	; GET MSB OF LOAD ADDRESS
	MOV	H,A	; MOVE TO H
	CALL	BYTE	; GET LSB OF LOAD ADDRESS
	MOV	L,A	; MOVE TO L
	CALL	BYTE	; GET RECORD TYPE
	MOV	C,E	; MOVE RECORD LENGTH TO C
RCM10:
	CALL	BYTE	; READ DATA FROM TAPE
	MOV	M,A	; PUT DATA INTO MEMORY
	INX	H	; INCREMENT HL FOR NEXT LOCATION
	DCR	E	; DECREMENT RECORD LENGTH
	JNZ	RCM10	; LOOP UNTIL DONE
	CALL	BYTE	; READ CHECKSUM FROM TAPE
	JNZ	ERROR	; CHECKSUM ERROR IF NOT ZERO
	JMP	RCM05	; GET ANOTHER RECORD
;
;********************************************************************
;
; FUNCTION: WCMD
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: GETNM,LEAD,PO,PBYTE,PADR,PEOL,PEOF
; DESTROYS: A,B,C,D,E,H,L,F/F`S
; DESCRIPTION: WCMD IMPLEMENTS THE WRITE HEXADECIMAL TAPE (W)
;              COMMAND.
;
WCMD:
	MVI	C,2
	CALL	GETNM	; GET 2 NUMBERS FROM INPUT STREAM
	CALL	LEAD	; PUNCH 60 NULL CHARACTERS FOR TAPE LEADER
	POP	D	; ENDING ADDRESS TO DE
	POP	H	; STARTING ADDRESS TO HL
WCM05:
	MOV	A,L	; MOVE L TO A
	ADI	16	; INCREMENT THE LSB OF STARTING ADDRESS BY 16
	MOV	C,A	; MOVE RESULT TO C
	MOV	A,H	; MOVE H TO A
	ACI	0	; ADD CARRY IN FROM PREVIOUS OPERATION
	MOV	B,A	; SAVE RESULT IN B
	MOV	A,E	; NOW MOVE LSB OF ENDING ADDRESS TO A
	SUB	C	; SUBTRACT LSB OF STARTING ADDRESS
	MOV	C,A	; SAVE IN C
	MOV	A,D	; NOW GET MSB OF STARTING ADDRESS IN A
	SBB	B	; SUBTRACT MSB OF STARTING ADDRESS
	JC	WCM10	; BRANCH IF THE RECORD LENGTH IS NOT 16
	MVI	A,16	; OTHERWISE SET A TO RECORD LENGTH OF 16
	JMP	WCM15	; NOW BRANCH TO PUNCH THE RECORD
WCM10:
	MOV	A,C	; THIS IS THE LAST RECORD
	ADI	17	; SO SET A TO REMAINING DATA LENGTH
WCM15:
	ORA	A	; CHECK FOR RECORD LENGTH OF ZERO
	JZ	WCM25	; IF IT IS, ALL DONE
	PUSH	D	; OTHERWISE, SAVE ENDING ADDRESS
	MOV	E,A	; PUT RECORD LENGTH IN E
	MVI	D,0	; INITIALISE D FOR HOLDING CHECKSUM
	MVI	C,':'
	CALL	PO	; PUNCH RECORD MARK CHARACTER
	MOV	A,E	; PUT RECORD LENGTH IN A
	CALL	PBYTE	; PUNCH RECORD LENGTH
	CALL	PADR	; PUNCH STARTING ADDRESS
	XRA	A	; ZERO A
	CALL	PBYTE	; PUNCH RECORD TYPE
WCM20:
	MOV	A,M	; GET DATA TO BE PUNCHED FROM MEMORY
	CALL	PBYTE	; PUNCH IT
	INX	H	; INCREMENT MEMORY ADDRESS
	DCR	E	; DECREMENT LENGTH COUNT
	JNZ	WCM20	; LOOP UNTIL ALL DATA PUNCHED
	XRA	A
	SUB	D	; PUNCH CHECKSUM
	CALL	PBYTE
	POP	D	; RESTORE ENDING ADDRESS
	CALL	PEOL	; PUNCH CARRIAGE RETURN LINE FEED
	JMP	WCM05
WCM25:
	CALL	PEOF	; PUNCH END OF FILE RECORD
	JMP	EXIT	; ALL DONE
;
;********************************************************************
;
; FUNCTION: BYTE
; INPUTS: D - CURRENT VALUE OF CHECKSUM
; OUTPUTS: A - HEXADECIMAL CHARACTER
; 	   D - UPDATED VALUE OF CHECKSUM
; CALLS: RICH,CNVBN
; DESTROYS: A,B,C,D,F/F`
; DESCRIPTION: BYTE READS 2 ASCII CHARACTERS FROM THE TELETYPEWRITER
;              AND CONVERTS THE CHARACTERS TO ONE HEXADECIMAL CHARACTER.
;              THE A REGISTER CONTAINS THE FINAL CHARACTER AND THE
;              D REGISTER CONTAINS THE UPDTATED VALUE OF
;              THE CHECKSUM.
BYTE:
	PUSH	B	; SAVE BC
	CALL	RICH	; READ ASCII CHARACTER FROM TAPE
	MOV	C,A
	CALL	CNVBN	; CONVERT CHARACTER TO HEXADECIMAL
	RLC		; POSITION VALUE INTO UPPER 4 BITS
	RLC
	RLC
	RLC
	MOV	B,A	; SAVE RESULTS IN B
	CALL	RICH	; GET ANOTHER CHARACTER FROM TAPE
	MOV	C,A
	CALL	CNVBN	; CONVERT IT
	ORA	B	; OR IN THE UPPER 4 BITS
	MOV	C,A	; SAVE
	ADD	D	; INCREMENT CHECKSUM
	MOV	D,A
	MOV	A,C	; RESTORE HEX DATA TO A REGISTER
	POP	B	; RESTORE BC
	RET
;
;********************************************************************
;
; FUNCTION: DELAY
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: NOTHING
; DESTROYS: F/F`S
; DESCRIPTION: DELAY PROVIDES A PROGRAMED DELAY OF 1 MILLISECOND
;              FOR TAPE READER OPERATION.
;
DELAY:
	PUSH	B	; SAVE BC REGISTERS
	MVI	B,ONEMS	; LOAD 1 MILLISECOND CONSTANT
DEL1:
	DCR	B	; DECREMENT INNER COUNTER
	JNZ	DEL1	; JUMP IF NOT DONE
	POP	B	; RESTORE BC REGISTERS
	RET		; RETURN TO CALLING ROUTINE
;
;********************************************************************
;
; FUNCTION: LEAD
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: PO
; DESTROYS: B,C,F/F`S
; DESCRIPTION:LEAD OUTPUTS 60 NULL CHARACTERS TO PAPER TAPE TO FORM A
;             LEADER.
;
LEAD:
	MVI	B,60	; LOAD B WITH A COUNT OF 60
LE05:
	MVI	C,0
	CALL	PO	; PUNCH NULL CHARACTER
	DCR	B	; DECREMENT COUNT
	JNZ	LE05	; DO IT AGAIN IF NOT DONE
	RET
;
;********************************************************************
;
; FUNCTION: PADR
; INPUTS: HL - ADDRESS TO BE PUNCHED
; OUTPUTS: NONE
; CALLS: PBYTE
; DESTROYS: A
; DESCRIPTION: PADR PUNCHES ON THE TELETYPEWRITER THE ADDRESS
;              CONTAINED IN THE H,L REGISTERS.
;
PADR:
	MOV	A,H	; PUNCH FIRST HALF OF ADDRESS
	CALL	PBYTE
	MOV	A,L	; PUNCH SECOND HALF OF ADDRESS
	CALL	PBYTE
	RET		; RETURN TO CALLING ROUTINE
;
;********************************************************************
;
; FUNCTION: PBYTE
; INPUTS: A - CHARACTER TO BE PUNCHED
;         D - CURRENT VALUE OF CHECKSUM
; OUTPUTS: D - UPDATED VALUE OF CHECKSUM
; CALLS: PRVAL,PO
; DESTROYS: A,F/F`S
; DESCRIPTION: PBYTE CONVERTS THE HEXADECIMAL VALUE IN THE A REGISTER
;              INTO TWO ASCII CHARACTERS AND PUNCHES THESE CHARACTERS
;              ON PAPER TAPE. THE CHECKSUM CONTAINED IN D IS UPDATED.
;
PBYTE:
	PUSH	PSW	; SAVE A,F/F`S
	RRC		; POSITION UPPER 4 BITS INTO LOWER 4 BITS
	RRC
	RRC
	RRC
	CALL	PRVAL	; CONVERT UPPER 4 BITS JUST ROTATED TO ASCII
	CALL	PO	; PUNCH CHARACTER
	POP	PSW	; RESTORE A,F/F`S
	PUSH	PSW	; SAVE A AGAIN
	CALL	PRVAL	; CONVERT LOWER 4 BITS TO ASCII CHARACTER
	CALL	PO	; PUNCH CHARACTER
	POP	PSW	; RESTORE A
	ADD	D	; ADD VALUE TO CHECKSUM
	MOV	D,A	; UPDATE D REGISTER WITH NEW CHECKSUM
	RET		; RETURN TO CALLING ROUTINE
;
;*********************************************************************
;
; FUNCTION: PEOF
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: PO,PBYTE,PADR,LEAD
; DESTROYS: A,C,D,H,L,F/F`S
; DESCRIPTION: PEOF PUNCHES THE END OF FILE RECORD CONSISTING OF A RECORD
;              MARK,A LOAD ADDRESS OF 0, THE RECORD TYPE, AND THE
;              RECORD CHECKSUM.
;
PEOF:
	MVI	C,':'
	CALL	PO	; PUNCH RECORD MARK
	XRA	A	; ZERO CHECKSUM
	MOV	D,A	; SAVE IN D REGISTER
	CALL	PBYTE	; PUNCH RECORD LENGTH
	LXI	H,0	; LOAD HL WITH ZERO ADDRESS
	CALL	PADR	; PUNCH IT
	MVI	A,1	; LOAD A WITH RECORD TYPE
	CALL	PBYTE	; PUNCH IT
	XRA	A	; ZERO A
	SUB	D	; COMPUTE CHECKSUM
	CALL	PBYTE	; PUNCH IT
	CALL	LEAD	; PUNCH TRAILER
	RET
;
;********************************************************************
;
; FUNCTION: PEOL
; INPUTS: NONE
; OUTPUTS: NONE
; CALLS: PO
; DESTROYS: C
; DESCRIPTION: PEOL PUNCHES A CARRIAGE RETURN AND LINE FEED ONTO
;              PAPER TAPE.
;
PEOL:
	MVI	C,CR
	CALL	PO	; PUNCH CARRIAGE RETURN CHARACTER
	MVI	C,LF
	CALL	PO	; PUNCH LINE FEED CHARACTER
	RET
;
;********************************************************************
;
; FUNCTION: PO
; INPUTS: C - CHARACTER TO BE PUNCHED
; OUTPUTS: NONE
; CALLS: CO
; DESTROYS: NOTHING
; DESCRIPTION: PO PUNCHES THE CHARACTER SUPPLIED IN THE C REGISTER TO
;              THE USER TELETYPEWRITER.
;
PO:
	CALL	CO	; CALL CONSOLE OUT TO PERFORM CHARACTER OUTPUT
	RET
;
;********************************************************************
;
; FUNCTION: RICH
; INPUTS: NONE
; OUTPUTS: A - ZERO,CARRY - 1 IF END OF FILE
;          A - CHARACTER, CARRY - 0 IF VALID CHARACTER
;
RICH:
	CALL	RI	; READ A CHARACTER FROM TAPE
	JC	ERROR	; JUMP IF READER TIMEOUT ERROR
	ANI	PRTYO	; REMOVE PARITY BIT
	RET		; RETURN TO CALLING ROUTINE
;
;********************************************************************
;
; FUNCTION: RI
; INPUTS: NONE
; OUTPUTS: A - ZERO, CARRY - 1 IF END OF FILE
;          A - CHARACTER, CARRY - 0 IF VALID CHARACTER
; CALLS: DELAY
; DESTROYS: A,F/F`S
; DESCRIPTION: RI READS A CHARACTER FROM THE TTY TAPE READER.
;
RI:
	PUSH	B	; SAVE BC
	MVI	A,STR	; STEP READER
	OUT	PTRC
	MVI	A,0
	OUT	PTRC
	MVI	B,250	; INITIALIZE TIMER FOR 250MS
RI10:
	IN	PTRS	; INPUT READER STATUS
	CMA
	ANI	PTRR	; CHECK FOR READER READY
	JNZ	RI15	; YES - DATA IS READY
	CALL	DELAY	; DELAY 1MS
	DCR	B	; DECREMENT TIMER
	JNZ	RI10	; JUMP IF TIMER NOT EXPIRED
	XRA	A	; ZERO A
	STC		; SET CARRY INDICATING EOF
	POP	B	; RESTORE BC
	RET		; RETURN TO CALLING ROUTINE
RI15:
	IN	PTRD	; INPUT DATA CHARACTER
	CMA
	ORA	A	; CLEAR CARRY
	POP	B	; RESTORE BC
	RET		; RETURN TO CALLING ROUTINE
;
;********************************************************************
;
COPYRT:
	DB	'(C) 1976 INTEL CORP'
;
;********************************************************************
;
	ORG	REGS	; ORG TO REGISTER SAVE - STACK GOES IN HERE
;
MSTAK		EQU	$	; START OF MONITOR STACK
ESAVE:		DB	0	; E REGISTER SAVE LOCATION
DSAVE:		DB	0	; D REGISTER SAVE LOCATION
CSAVE:		DB	0	; C REGISTER SAVE LOCATION
BSAVE:		DB	0	; B REGISTER SAVE LOCATION
FSAVE:		DB	0	; FLAGS SAVE LOCATION
ASAVE:		DB	0	; A REGISTER SAVE LOCATION
LSAVE:		DB	0	; L REGISTER SAVE LOCATION
HSAVE:		DB	0	; H REGISTER SAVE LOCATION
PSAVE:		DW	0	; PGM COUNTER SAVE LOCATION
SSAVE:		DW	0	; USER STACK POINTER SAVE LOCATION
TEMP:		DB	0	; TEMPORY MONITOR CELL
;
	END
