;	TITLE      'UPG80 MONITOR SPECIAL SYSTEM VERSION 3-1   31/8/79'
;
;****	FOR S100 SYSTEMS WITH JADE I/O BOARDS.
;
;
;*************************************************************
;
;	UPG80 MONITOR :-
;	MODIFIED VERSION OF AMSAT'S AMS80 V2:0 MONITOR
;	BY H.J.HARVEY
;
; THIS MONITOR IS A MINIMUM 8080 SYSTEM MONITOR TO PROVIDE
; THE BASIC STRUCTURE NECESSARY FOR 8080 DEBUG AND CONTROL.
;
; THE ROUTINES ALLOW FOR MEMORY EXAMINE AND MODIFY,
; TARGET PROGRAM BREAKPOINTING UNDER MONITOR CONTROL,
; USER INTERRUPTS OR RST VECTORS (RST3-RST7),
; SIMPLE ASSEMBLY AND DISASSEMBLY, INPUT AND OUTPUT,
; AND PROVIDE VARIOUS TELETYPE SUPPORT ROUTINES TO LOAD
; AND DUMP MEMORY IN STANDARD 8080 HEX-BINARY.
;
;   THE MONITOR INCLUDES AN EXTENSIVE VECTOR TABLE STARTING
; AT (ROM-ORIGIN + 40H) TO ALLOW USER ACCESS TO A NUMBER
; OF USEFUL SPECIFIC ROUTINES.
;
;*************************************************************
;
;	DEFINE CONSOLE CONTROL CHRS
;
CR	EQU	0DH	;ASCII CARRIAGE-RETURN
LF	EQU	0AH	;ASCII LINE-FEED
;
;	THE FOLLOWING EQUATES ARE USED TO DEFINE THE COLUMN WIDTH
;	OF THE DISPLAY CONSOLE.
;	'R' COMMAND NEEDS 58 COLUMNS FOR A 1-LINE DISPLAY
;	'D' COMMAND NEEDS 53 COLUMNS FOR 16-BYTE DISPLAY
;	'P' COMMAND NEEDS 43 COLUMNS FOR 16-BYTE GROUP
;	COLSW=1 IF MONITOR <58 COLUMNS/LINE
;	COLSW=0 IF MONITOR >57 COLUMNS/LINE
;
COLSW	EQU	0
;
	IF	NOT COLSW
;
;	58+ COLUMN CONSTANTS
;
OSET	EQU	16	;16 BYTES PER LINE
	ENDIF
	IF	COLSW
;
;	<58 COLUMN CONSTANTS
;
OSET	EQU	8	;8 BYTES PER LINE
	ENDIF
;
;
;
;	THE FOLLOWING EQUATES ARE DESIGNED FOR CONSOLE CONTROL
;	OF THE S100 CARD-SET WITH JADE SPI/O BOARDS.
;	ER SYSTEMS WILL REQUIRE DIFFERENT EQUATES, DEPENDING
;	UPON THE SELECTION OF I/O PORTS AND CONTROL SETUPS.
;
CNCTL	EQU	081H	;SYSTEM I/O CONSTANTS
CONST	EQU	081H
CNIN	EQU	001H
CNOUT	EQU	001H
CSCTL	EQU	080H	;CASSETTE CONTROL
CSST	EQU	080H	;CASSETTE STATUS CHANNEL
CSIN	EQU	000H	;CASSETTE INPUT PORT
CSOUT	EQU	000H	;CASSETTE OUTPUT PORT
MODE	EQU	0FFH	;MM5303 UART MODE SELECT
TRDY	EQU	080H	;TRANSMIT READY BIT
RBR	EQU	010H	;READER READY BIT
TMOUT	EQU	10000	;10000 MILLISECOND (10 SECS) TIMEOUT
ONEMS	EQU	130	;CONSTANT FOR 1 MILLISECOND LOOP (F/N DELAY)
RAM	EQU	03F00H	;START OF 256 BYTE RAM.
;
;	ROM AND RAM AREAS CAN NOW BE DEFINED.
;
ROMSW	EQU	1	;ROMSW=1 IF ROM > 0 , OTHERWISE ROMSW=0
ROM	EQU	08000H	;ROM STARTS HERE
REGS	EQU	RAM+256-48	;REGISTER STORE (IN RAM) STARTS HERE
STACK	EQU	REGS	;TOP OF STACK INITIALIZE
;
;	START OF SYSTEM
;
	ORG	ROM
;
;	SET UP SERIAL DATA MODE.
;
PART1:
	DI		;DISABLE ALL INTERRUPTS.
	MVI	A,MODE	;SERIAL I/O MODE.
	JMP	PART2
	DW	RAM
;
;	EXECUTIVE ENTRY ON RST1
;	THIS ENTRY POINT IS USED WHENEVER AN RST1 (CODE CF)
;	IS EXECUTED.
;
EXEC:
	SHLD	SVHL	;SAVE HL
	POP	H	;POP THE CALL ADDRESS INTO HL
	RAR		;PUT CARRY INTO B7 OF ACC
	JMP	BEGIN	;GO ON NOW.
;
;	BREAKPOINT SERVICING INPUT AS RESULT OF 'RST 2'
;	ROUTINE BPAT IS CALLED TO LET THE USER KNOW.
;
BPIN:
	SHLD	SVHL	;SAVE HL
	POP	H	;GRAB BREAKPOINT ADDRESS
	RAR		;ROTATE RIGHT PUTS CARRY INTO ACC B7
	JMP	BPAT	;GO SERVICE IT.
;
;	DEFINE USER INT/SR VECTORS
;	RST3 THROUGH RST7 MAY BE USED EITHER AS HARDWARE
;	OR SOFTWARE INTERRUPT VECTORS.
;	THE ORRESPONDING ADDRESS FOR SERVICE MUST BE
;	SET UP IN THE APPROPRIATE LOCATIONS IN RAM.
;	THESE ADDRESSES CAN BE FOUND BY REFERENCE TO THE LABELS
;	RST3 - RST7 AT THE END OF THIS MONITOR.
;
;****	NOTE THAT THESE CODE GROUPS ARE TO BE LINKED FROM RAM
;	IN PAGE ZERO IF THE MONITOR IS NOT ZERO ORGED.
;
RS3:
	PUSH	H	;SAVE HL
	LHLD	RST3	;FETCH USER VECTOR
	XTHL		;PUT ON STACK RESTORING HL
	RET		;GO TO USER
	DW	ROM	;PAD - ROM START ADDRESS
RS4:
	PUSH	H	;SAVE HL
	LHLD	RST4	;FETCH USER VECTOR
	XTHL		;PUT ON STACK RESTORING HL
	RET		;GO TO USER
	DW	RAM	;PAD - RAM START ADDRESS
RS5:
	PUSH	H	;SAVE HL
	LHLD	RST5	;FETCH USER VECTOR
	XTHL		;PUT ON STACK RESTORING HL
	RET		;GO TO USER
	DW	REGS	;PAD - END OF REG STORE (ALSO T.O.S.)
RS6:
	PUSH	H	;SAVE HL
	LHLD	RST6	;FETCH USER VECTOR
	XTHL		;PUT ON STACK RESTORING HL
	RET		;GO TO USER
	DW	SVA	;PAD - START OF REG STORE.
RS7:
	PUSH	H	;SAVE HL
	LHLD	RST7	;FETCH USER VECTOR
	XTHL		;PUT ON STACK RESTORING HL
	RET		;GO TO USER
	DW	ENDROM	;PAD - END OF ROM DATA
;
;	MONITOR SUPPORT SR VECTORS
;	USER UTILITY SR'S
;
; THE FOLLOWING SET OF JUMPS ARE PROVIDED SOTHAT USER
; PROGRAMS CAN REFERENCE COMMON ENTRY POINTS TO THE VARIOUS
; ROUTINES. THESE LOCATIONS WILL REMAIN CONSTANT WHILE THE
; ACTUAL LOCATION OF EACH ROUTINE MAY CHANGE AS DIFFERENT
; MONITOR REVISIONS OCCUR.
;
;	THE CALLING SEQUENCE FOR EACH SUBROUTIN EMAINS THE
; SAME AS DEFINED IN THE LISTING, WITH ONLY A SLIGHT EXECUTION
; TIME OVERHEAD DUE TO THE EXTRA JUMP.
;
ZTYPE:	JMP	TYPE	;TYPE CHR IN 'A'
ZGETCH:	JMP	GETCH	;GET CHR IN 'A' (PARITY, NO ECHO)
ZCHIN:	JMP	CHIN	; "   "  "   "  (ECHO, NO PARITY)
ZCHINX:	JMP	CHINX	; "   "  "   "  (ECHO/NO ECHO, NO PARITY)
ZMSG:	JMP	MSG	;TYPE MESSAGE, PTR IN HL. TERM 0FFH
ZCRLF:	JMP	CRLF	;TYPE CR/LF
ZSPACE:	JMP	BLANK	;TYPE " "
ZTHXN:	JMP	THXN	;TYPE HEX 'A' B3-B0
ZTHXB:	JMP	THXB	; " "  "   "  B7-B0
ZTHXW:	JMP	THXW	; " "  " 'HL'
ZGHXN:	JMP	GHXN	;GET HEX 'A' B3-B0
ZGHXB:	JMP	GHXB	; "   "   "  B7-B0
ZGHXW:	JMP	GHXW	; "   "  'HL'
ZSTORE:	JMP	STORE	;STORE A IN (HL) AND CHECK
ZNEGDE:	JMP	NEGDE	;NEGATE DE REG
ZPWAIT:	JMP	PWAIT	;TYPE 'PAUSE' THEN AWAIT ANY CHR
ZOKQ:	JMP	OKQ	;TYPE 'OK?', AWAIT CHR, CONTINUE IF ' '
ZECHO:	JMP	ECHCN	;ECHO CONTROL (A=0 MEANS OFF)
ZCNVBN:	JMP	CNVBN	;CONVERT CHARACTER TO BINARY NYBBLE.
ZCSTS:	JMP	CSTS	;LOOK FOR CONSOLE K/B STRIKE.
;
;	UART INITIALIZATION CODE: PART 2.
;	SEND OUT THE COMMAND WORD.
;
PART2:
	OUT	CSCTL	;SET UP CASSETTE I/O
	OUT	CNCTL	;AND CONSOLE I/O.
;
;	ZERO OUT THE CURRENT ADDRESS FOR BREAKPOINT.
;	(NECESSARY TO ALLOW UPDATING)
;
	LXI	H,0	;LOAD 16 BIT ZERO
	SHLD	BPADD	;PUT ALL ZEROS IN BPADD
;
;	BEGIN MONITOR.
;	ENTER HERE FOLLOWING A HARDWARE/SOFTWARE RST1
;
BEGIN:
	SHLD	SVPC	;STORE CALLING PC
	STA	TMPA	;AND CARRY (IN B7)
	RAL		;THEN ROTATE BACK THE ACC.
	LXI	H,0	;NOW TRANSFER THE SP TO HL BY DOING A DUMMY
	DAD	SP	;ADD TO HL. (N.B. CLEARS CARRY)
	SHLD	SVSP	;SAVE THE CALLER SP.
	LXI	SP,SVA+1	;PICK UP REG STORE POINTER
	PUSH	PSW	;TO SAVE PSW
	PUSH	B	;AND BC
	PUSH	D	;AND DE. (HL ALREADY SAVED)
	LXI	H,SVF	;GET THE PSB BYTE
	LDA	TMPA	;PICK UP THE CARRY HOLDER,
	RAL		;ROTATE IT BACK TO CARRY.
	JNC	BGN1	;SKIP IF CARRY NOT SET,
	INR	M	;OTHERWISE RESET CARRY.
BGN1:
	LXI	H,M0	;TYPE MONITOR ENTRY MESSAGE
	JMP	NEXT1
;
;	NEXT MONITOR COMMAND PLEASE.
;	ENTER HERE WHENEVER A NEW COMMAND IS EXPECTED.
;
NEXT:
	LXI	H,M1	;TYPE PROMPT MESSAGE
NEXT1:
	LXI	SP,STACK	;SET STACK POINTER FIRST.
	CALL	MSG
	CALL 	CHIN	;GET COMMAND CHARACTER INTO 'A'
	MOV	B,A	;AND SAVE IT IN 'B'
;
;	SEARCH OP TABLE
;	(IF CALLING COMMAND BYTE IS REQUIRED, IT IS IN 'B')
;
	LXI	H,OPTAB	;HEAD-OF-TABLE VECTOR
	SUI	'A'	;REDUCE CODE TO OFFSET
	CPI	1AH	;SEE IF IT EXCEEDS 'Z' COMMAND.
	JNC	TEND	;IF SO, MAY HAVE BEEN SPECIAL.
	ADD	A	;ALL O.K. MULTIPLY BY 2 (2 BYTES PER ADDR)
	MOV	E,A	;PUT VALUE*2 INTO E
	MVI	D,0	;AND GET ZERO TO CLEAR 'D'
	DAD	D	;ADD OFFSET TO HL (ADDRESS REQUIRED AT <HL>)
	MOV	E,M	;GET LOWER BYTE OF REQUIRED ADDR
	INX	H	;AND THEN GET THE UPPER
	MOV	D,M	;BYTE BEFORE TRANSFERRING
	XCHG		;IT TO HL.
	PCHL		;FINALLY JUMP TO ROUTINE CALLED.
;
;	OPERATION ADDRESS TABLE.
;	CONTAINS AN ADDRESS DESTINATION FOR EACH CHARACTER OF THE
;	ALPHABET (A-Z IN ASCENDING ORDER.)
;
OPTAB:
	DW	GETAD	;A - GET ADDRESS
	DW	BPT	;B - BREAKPOINT SETTER/CLEARER
	DW	CONT	;C - CONTINUE AFTER B/P
	DW	DISP	;D - DISPLAY MEMORY DATA
	DW	PEND	;E - END OF FILE PUNCH
	DW	FILL	;F - FILL MEMORY WITH DATA
	DW	GOTO	;G - PROGRAM GO: NO REGISTER RESTORE.
	DW	ASM80	;H - LINE ASSEMBLER
	DW	INPT	;I - INPUT PORT DATA
	DW	JUMP	;J - PROGRAM JUMP: REGISTER RESTORE.
	DW	KOMP	;K - K(C)OMPARE MEMORY AREAS
	DW	LOAD	;L - LOAD HEX-BINARY TAPE
	DW	MOVE	;M - MOVE MEMORY BLOCK
	DW	NULL	;N - PUNCH NULL BLOCK
	DW	OUTPT	;O - OUTPUT PORT DATA.
	DW	PUNCH	;P - PUNCH HEX-BINARY DATA
	DW	ILLEG
	DW	REGEX	;R - REGISTER EXAMINE/MODIFY
	DW	SEARCH	;S - SEARCH MEMORY FOR BYTE
	DW	ILLEG
	DW	USER	;U - USER DEFINE/USE
	DW	ILLEG
	DW	ILLEG
	DW	GETXA	;X - SET UP XEQ ADDRESS
	DW	DIS80	;Y - 8080 DISASSEMBLY.
	DW	ZERO	;Z - ZERO OUT MEMORY
;
;	N.B.	COMMANDS <CR> <LF> . AND - ARE CHECKED
;		BY ROUTINE 'TEND'
;
;
;	INPUT ONE CHR AND STRIP PARITY
;	ALTERNATIVE ENTRY POINTS ARE:-
;
;		CALL	CHIN
;		....		;RESULT IN 'A'
;	THE INPUT IS ECHO'D IF DATA IS PRINTABLE.
;
;		MVI	A,XX	;XX=0 NO ECHO.
;		CALL	CHINX
;		....		;RESULT IN 'A'
;	ECHO CONTROLLED EACH CALL.
;
;		CALL	CHINN
;		....		;RESULT IN 'A'
;	ECHO CONTROLLED BY PREVIOUS 'CALL ECHCN'
;
CHIN:
	MVI	A,0FFH	;SET ECHO FLAG ON
CHINX:
	CALL	ECHCN	;CALL THE CONTROLLER.
CHINN:
	CALL	GETCH	;GET CHARACTER FROM CONSOLE,
	ANI	7FH	;STRIP ANY PARITY
	PUSH	PSW	;SAVE DATA
	LDA	ECHO	;SEE IF ECHO REQU'D
	ANA	A	;THIS INSTRUCTION SIMPLY SETS FLAGS
	JNZ	CHN1	;TEST FOR ZERO/NON-ZERO CONTROL
	POP	PSW	;NO ECHO. SIMPLY RETURN
	RET
CHN1:
	POP	PSW	;GET DATA AND ECHO
	CPI	' '	;IF NOT CONTROL CHR
	CNC	TYPE
	RET		;BEFORE RETURNING
;
;	MESSAGE PRINT
;	ALLOWS USER TO PRINT A MESSAGE ON THE CONSOLE OUTPUT
;	BY HAVING A STRING OF CHARACTERS FOLLOWED
;	BY DELIMITING 0FFH (-1)
;
;	CALLING SEQUENCE:-
;		LXI	H,ADDRESS
;		CALL	MSG
;		....
;
MSG:
	PUSH	PSW	;SAVE PSW
	PUSH	H	;AND HL
MNXT:
	MOV	A,M	;GET NEXT BYTE
	INX	H	;BUMP BYTE POINTER.
	CPI	0FFH	;CHECK FOR 0FFH (-1) TERMINATOR
	CNZ	TYPE	;NO. TYPE IT
	JNZ	MNXT	;NOW READY FOR ANOTHER TRY
	POP	H	;MESSAGE FINISHED. RESTORE HL
	POP	PSW	;AND PSW
	RET		;BEFORE GOING HOME
;
;	TYPE CR/LF
;	(THE EASY WAY TO START A NEW LINE)
;
;	CALLING SEQUENCE:-
;		CALL	CRLF
;		....
;
CRLF:
	PUSH	H	;SAVE HL
	LXI	H,M2	;GET CR/LF MESSAGE
	CALL	MSG	;TYPE MESSAGE
	POP	H	;RESTORE HL
	RET		;RETURN
;
;
;	TYPE ONE SPACE
;
;	CALLING SEQUENCE:-
;	CALL	BLANK
;	....
;
BLANK:
	PUSH	PSW	;SAVE PSW
	MVI	A,' '	;GET SPACE
	CALL	TYPE	;TYPE IT
	POP	PSW	;RESTORE PSW
	RET		;THEN RETURN
;
;	TYPE 'A' IN HEX
;	OUTPUTS THE 2-BIT HEX VALUE OF ACCUMULATOR
;	TO CONSOLE
;
;	CALLING SEQUENCE:-
;		LDA	DATA
;		CALL	THXB
;		....
;
THXB:
	PUSH	PSW	;SAVE PSW
	RRC		;SHIFT THE LEFT NYBBLE
	RRC		;INTO THE RIGHT NYBBLE
	RRC		;BY DOING 4 ROTATE RIGHTS.
	RRC
	CALL	THXN	;TYPE HEX NYBBLE
	POP	PSW	;RESTORE DATA
;
;	TYPE 'A' B3-B0 IN ASCII
;	TYPES THE 1-BIT HEX VALUE OF THE BOTTOM 4 BITS
;	OF ACCUMULATOR.
;
;	CALLING SEQUENCE:-
;		LDA	DATA
;		CALL 	THXN
;		....
;
THXN:
	PUSH	PSW	;SAVE PSW
	ANI	0FH	;ISOLATE B3-B0 (THROW AWAY B7-B4)
	ADI	090H	;ADJUST
	DAA		;NOW
	ACI	040H	;TO
	DAA		;ASCII
	CALL	TYPE	;BEFORE TYPING
	POP	PSW	;RESTORE PSW
	RET		;THEN RETURN
;
;
;	TYPE A WORD IN HEX
;	TYPES THE 4-BIT HEX VALUE OF THE 16-BIT VALUE
;	HELD IN THE HL REGISTER PAIR.
;
;	CALLING SEQUENCE:-
;		LHLD	WORD
;		CALL	THXW
;		....
;
THXW:
	PUSH	PSW	;SAVE PSW
	MOV	A,H	;GET HIGH BYTE FROM 'H'
	CALL	THXB	;AND TYPE IT
	MOV	A,L	;GET LOW BYTE FROM 'L' AND
	CALL	THXB	;TYPE IT TOO.
	POP	PSW	;RESTORE PSW
	RET		;I'M GOIN HOME
;
;	GET HEX CHR FROM CONSOLE
;	ROUTINE TO GET A SINGLE HEX NYBBLE FROM THE CONSOLE
;	IF THE DIGIT IS VALID (I.E. 0-9,A-F) THEN THE BINARY
;	VALUE IS RETURNED IN 'A' AND THE CARRY IS RESET.
;
;	HOWEVER, IF THE RESULT IS NON-HEX, THE BAD CHARACTER
;	WILL BE IN 'A' AND CARRY WILL BE SET.
;
;	CALLING SEQUENCE:-
;	CALL	GHXN
;	JC	NONHX		;ERROR IF CARRY SET
;
GHXN:
	MVI	A,0FH	;MASK TO KEEP ONLY THE RIGHT NYBBLE
	JMP	GHB1
;
;	GET HEX BYTE FROM CONSOLE
;	SIMILAR TO GHXN, BUT RETURNS BYTE VALUE IF O.K.
;
;	CALLING SEQUENCE:-
;		CALL	GHXB
;		JC	NONHX	;CHECK NO HEX I/P
;
GHXB:
	MVI	A,0FFH	;MASK TO KEEP WHOLE BYTE.
GHB1:
	PUSH	H	;SAVE HL
	CALL	GHXW	;GET HEX DATA VIA GHXW
	JC	GHB2	;PROVIDED THERE HAS BEEN NO ERROR,
	ANA	L	;WE CAN MASK THE NYBBLE/BYTE.
GHB2:
	POP	H	;RESTORE HL
	RET		;RETURN TO CALLER
;
;	GET HEX WORD FROM CONSOLE
;	SIMILAR TO GHXN, BUT RETURNS BINARY WORD (16-BIT)
;	IN HL REG PAIR IF O.K.
;
;	CALLING SEQUENCE:-
;		CALL	GHXW
;		JC	NONHX	;TEST NON HEX I/P
;		....		;RESULT IN HL
;
GHXW:
	PUSH	PSW	;SAVE PSW
	LXI	H,0	;ZERO OUT THE  HL STORE
	CALL	CHINN	;GET FIRST CHARACTER, CONTROLLED ECHO
	CALL	CNVBN	;CONVERT IT TO BINARY NYBBLE
	JC	GHW3	;ANY NON-HEX IS ERROR FIRST TIME.
	MOV	L,A	;SAVE FIRST DIGIT
GHW1:
	CALL	CHINN	;GET ANOTHER CHARACTER
	CALL	CNVBN	;AND CONVERT TO BINARY NYBBLE
	JC	GHW2	;AFTER FIRST DIGIT, CHECK FOR DELIMITER.
	DAD	H	;HL*2	;WE WANT 1-NYBBLE LEFT SHIFT
	DAD	H	;HL*4	;SO WE DOUBLE ADD HL
	DAD	H	;HL*8	;TO ITSELF FOUR TIMES.
	DAD	H	;HL*16	;N.B. TOP DIGIT IS LOST.
	ADD	L	;ALL DONE. ADD DIGIT TO LOWER BYTE
	MOV	L,A	;UPDATE THE LOWER BYTE.
	JMP	GHW1	;NEXT DIGIT PLEASE.
GHW2:
	CPI	CR	;COMPARE WITH CR
	JZ	GHW4
	CPI	' '	;AND SPACE
	JZ	GHW4	;EITHER IS VALID DELIMITER.
GHW3:
	INX	SP	;NON-HEX BAD BYTE IS RETURNED
	INX	SP	;IN A, WITH CARRY SET.
	STC
	RET
GHW4:
	POP	PSW	;NORMAL EXIT, RESTORE PSW
	ORA	A	;WITH CARRY CLEARED.
	RET
;
;	CNVBN:	CONVERT ASCII TO BINARY NYBBLE,
;		IS COMMON TO GHXN,GHXB,GHXW
;
CNVBN:
	CPI	'0'	;FIRST SEE IF <'0'
	RC
	CPI	'9'+1	;NOW SEE IF NUMERIC
	JC	CNVB1	;IT IS IF CARRY ON.
	CPI	'A'	;NOW TRY A-F
	RC		;ERROR RETURN IF CARRY SET
	CPI	'F'+1	;CHECK FOR >F
	CMC		;INVERT CARRY
	RC		;RETURN IF NOT OK.
	SUI	7	;A-F CHR FOUND. SUBTRACT 7
CNVB1:
	SUI	'0'	;NOW MAKE INTO BINARY
	RET		;THEN RETURN
;
;	STORE BYTE IN MEMORY, WITH READ CHECK.
;	IF READ-BACK DOES NOT AGREE WITH STORE REQUEST AN
;	APPROPRIATE ERROR MESSAGE IS ISSUED.
;
;	CALLING SEQUENCE:-
;				;DATA IN 'A', ADR IN 'HL'
;		CALL STORE
;		....		;RETURNS HERE IF O.K.
;				;OTHERWISE RETURNS TO MONITOR.
;
STORE:
	MOV	M,A	;STORE BYTE INTO MEMORY
	CMP	M	;COMPARE MEMORY WITH A
	RZ		;RETURN IF O.K.
	PUSH	H	;SUMTHIN IS WRONG.
	LXI	H,M4	;ISSUE ERROR MESSAGE
	CALL	MSG	;TO ADVISE USER
	POP	H	;RESTORE HL
	JMP	RXAR	;INDICATE ERROR LOC'N
;
;
;	MEMORY EXAMINE/MODIFY.
;
;	ENTER FROM MONITOR BY USING:-
;	A 1234
;	SETS 'ADR' TO '1234H', TYPES CURRENT CONTENTS THEN AWAITS :-
;
;	(1) VALID BYTE TO STORE, THEN BUMPS 'ADR'
;	(2) LF TO SIMPLY BUMP 'ADR'
;	(3) -  TO SIMPLY DECREMENT 'ADR'
;	(4) CR TO RETURN TO MONITOR
;	(5) .  TO RETYPE CURRENT ADR
;
;	IN ADDITION, AT ANY TIME THE USER MAY DIRECTLY
;	ENTER THIS ROUTINE WITH:-
;	(1) .  TO TYPE CONTENTS OF CURRENT 'ADR'
;	(2) -  TO TYPE CONTENTS OF PREVIOUS 'ADR'
;	(3) LF TO TYPE CONTENTS OF NEXT 'ADR'
;	ROUTINE THEN CONTINUES AS ABOVE.
;
GETAD:
	CALL	PUWA	;GET ADR REQUIRED
	XCHG
;
GTA1:
	SHLD	ADR	;SAVE ADR
LOCAT:
	CALL	CRLF	;CR/LF
	LHLD	ADR	;FETCH CURRENT ADR
	CALL	THXW	;TYPE CURRENT ADR
	CALL	BLANK	;FOLLOWED BY SPACE
	MOV	A,M	;FOLLOWED BY BYTE CONTENT
	CALL	THXB
	CALL	BLANK	;YET ANOTHER SPACE
	CALL	GHXB	;LOOK FOR NEW BYTE
	JC	NONHX	;CHECK NON-HEX I/P
	CALL	STORE	;TRY TO STORE DATA BYTE
NXLOC:
	LHLD	ADR	;PICK UP CURRENT ADR
	INX	H	;BUMP 1
	JMP	GTA1	;RESTART PROCESS OF ADR ACCESS.
;
;	ROUTINE 'TEND' IS CALLED FROM MONITOR OP-TAB
;	TABLE END ROUTINE
;
TEND:
	MOV	A,B	;SET 'A' TO COMMAND
NONHX:
	CPI	LF	;SEE IF CHARACTER WAS LF
	JZ	NXLOC	;IF SO, GET NEXT LOC'N
	CPI	'.'	;MAYBE IT WAS '.'
	JZ	LOCAT	;IF SO, GET SAME LOC'N
	CPI	'-'	;OR EVEN '-'
	JZ	LSTLC	;IN WHICH CASE, BACK UP 1 LOC'N
NONH1:
	CPI	CR	;FINAL CHANCE IS CR
	JZ	NEXT	;WHICH MEANS EXIT THE COMMAND
;
;	IN THE EVENT THAT THE COMMAND IS NO GOOD,
;	ENTER HERE.
;
ILLEG:
	LXI	H,M3	;ILLEGAL CALL, SEND QUERY MESSAGE.
ILLG1:
	CALL	MSG	;TYPE IT, THEN
	JMP	NEXT	;'AVE ANOTHER GO.
;
;	PREVIOUS LOCATION REQUEST.
;
LSTLC:
	LHLD	ADR	;BACKUP 1 BYTE
	DCX	H
	JMP	GTA1	;AND TRY AGAIN.
;
;	NEGATE (2'S COMPLEMENT) 'DE' REG PAIR
;
;	CALLING SEQUENCE:-
;		....		;SET UP DE
;		CALL	NEGDE
;		....		;NOW DE=-DE
;
NEGDE:
	PUSH	PSW	;SAVE PSW
	MOV	A,D	;FETCH D
	CMA		;COMPLEMENT IT
	MOV	D,A	;RESTORE
	MOV	A,E	;FETCH E
	CMA		;COMPLEMENT IT TOO
	MOV	E,A	;THE RESTORE
	INX	D	;NOW ADD 1 TO GET 2'S COMPL
	POP	PSW	;RESTORE PSW
	RET		;TAKE RESULTS HOME
;
;	DISPLAY BLOCK OF MEMORY ON CONSOLE.
;	CALLED FROM MONITOR AS:-
;	D XXXX YYYY
;	AFTER THE FIRST LINE, PRINTS XXXX TO YYYY IN
;	8/16 BYTE GROUPS STARTING WITH ADR,MOD 8/16
;	IF XXXX > YYYY ONLY PRINTS CONTENTS OF XXXX
;
DISP:
	CALL	PICKUP	;GET ADDRESS RANGE.
DMRET:
	CALL	CRLF	;NEW LINE
	CALL	THXW	;VECTOR ADR TO CONSOLE
DMNXT:
	CALL	BLANK	;1 SPACE
	MOV	A,M	;GET DATA
	CALL	THXB	;TYPE IT
	CALL	LAST	;ALL DONE?
	CALL	HOLD	;NO. SEE IF HOLD REQUEST.
	MOV	A,L	;ADR MOD8/16?
	ANI	OSET-1
	JNZ	DMNXT	;NO.
	JMP	DMRET	;YES. NEW LINE.
;
;	LOCAL ROUTINE TO TEST FOR HOLD REQUEST.
;	RETURNS IF NO CHARACTER IN INPUT BUFFER.
;	PUTS HOLD ON OUTPUT IF <SP> IS TYPED.
;	OTHERWISE RETURNS TO MONITOR.
;
HOLD:
	CALL	CSTS	;GET CONSOLE STATUS.
	RZ		;ZERO. RETURN.
	XRA	A	;NON-ZERO.
	CALL	CHINX	;GET CHARACTER, NO ECHO.
	CPI	' '	;TEST FOR SPACE
	JNZ	NEXT	;NO SPACE. PANIC.
	JMP	GETCH	;SPACE. AWAIT CONTINUE.
;
;	LOCAL ROUTINE TO PICK UP TWO ADDRESSES,
;	PUTTING THE FIRST ADDRESS INTO HL
;	AND THE NEGATED SECOND ADDRESS INTO DE
;
PICKUP:
	CALL	PUWA	;FROM ADDRESS INTO DE
	CALL	PUWA	;FROM ADDRESS INTO HL,
	JMP	NEGDE	;NEGATED TO ADDRESS IN DE
;
;	JUMP TO ADDRESS WITH REG'S SET
;
;	CALLED FROM MONITOR BY:-
;	J 1234	JUMP TO SPECIFIED HEX ADR
;	J <CR>	JUMP TO ADR FROM LAST RST1
;	(USED AS BREAKPOINT IN PROGRAMS)
;	J <LF>	JUMP TO ADR SET UP BY 'X' COMMAND
;	J .	JUMP TO ADR SET BY LAST USE OF 'A' COMMAND
;
;	RESTORES REGISTERS TO STATE AS SAVED IN RAM ON ENTRY
;	TO THE MONITOR.
;	RESPONSES J <CR> , J <LF> AND J .   WILL TYPE
;	THE STORED ADDRESS BEFORE ASKING FOR OK TO PROCEED.
;
;	REMEMBER IF RST1 WAS USED, THAT THE RETURN ADDRESS MAY
;	NEED TO BE RESET WITH THE 'RP=' COMMAND TO GET YOU
;	BACK TO THE CALLING POINT.
;
;
;	GO DIRECT TO ADR FROM MONITOR.
;	IDENTICAL TO 'J' COMMAND, BUT DOES
;	NOT RESTORE REGISTERS.
;
JUMP:
GOTO:
	PUSH	B	;SAVE INPUT COMMAND
	CALL	PUWB	;GET ADR
	JNC	JMP4	;HEX ADR GIVEN
JMP2:
	LHLD	SVPC	;ASSUME SAVED PC REQUIRED.
	CPI	CR	;SEE IF CR
	JZ	JMP3
	LHLD	XEQAD	;NO. ASSUME 'X' ADDRESS REQUEST.
	CPI	LF	;TRY LF
	JZ	JMP3	;IF NOT,
	LHLD	ADR	;ONLY ALTERNATIVE IS 'ADR'
	CPI	'.'	;MUST BE '.'
	JNZ	ILLEG	;NO. PANIC.
JMP3:
	CALL	THXW	;TYPE HEX ADR
JMP4:
	CALL	OKQ	;IS THIS WHERE WE REALLY WANT TO GO?
	SHLD	GOGO+1	;YES. SET UP JUMP ADR
	MVI	A,0C3H	;THIS IS 'JMP' COMMAND
	STA	GOGO	;WHICH WE SET UP IN RAM
	POP	PSW	;RECOVER COMMAND CHARACTER.
	CPI	'G'	;WAS IT 'G' ?
	JZ	GOGO	;YES. IMMEDIATE JUMP TO PROGRAM.
	LXI	SP,SVE	;NO. RESTORE SP
	POP	D	;AND REGS
	POP	B
	POP	PSW
	LHLD	SVSP	;SAVED SP
	SPHL		;SET NEW SP
	LHLD	SVHL	;AND HL
	JMP	GOGO	;CUNNINGLY EXECUTE BUILT-UP JUMP
;
;	SET UP EXECUTION ADR FROM MONITOR BY:-
;	X 1234
;
GETXA:
	CALL	PUWA	;GET ADR
	XCHG		;INTO HL
	SHLD	XEQAD	;PUT INTO XEQAD
	JMP	NEXT	;BACK TO MONITOR
;
;	LOCAL ROUTINE TO CHECK FOR LAST OPERATION.
;
LAST:
	PUSH	H	;SAVE MEM VECTOR
	DAD	D	;ADD NEGATIVE ADDRESS
	JC	NEXT	;FINITO IF CARRY SET
	POP	H	;NO. RESTORE
	INX	H	;BUMP ADR
	RET		;RETURN
;
;	COMPARE TWO MEMORY BLOCKS, PRINT ANY DIFFERENCES.
;	USES 'MOVE' TO ALLOCATE THE BLOCK ADDRESSES.
;
;	MOVE MEMORY BLOCK FROM MONITOR BY:-
;	M XXXX YYYY ZZZZ
;
;	MOVES BLOCK XXXX TO YYYY INTO ZZZZ ONWARDS
;	TAKE CARE. WILL RESULT IN OVERWRITES IF ZZZZ IS
;	IN THE RANGE XXXX+1 TO YYYY
;	CAN BE USED AS A 'FILL' OPERATION BY PUTTING
;	ZZZZ=XXXX+1. LAST FILL OCCURS AT YYYY+1.
;
KOMP:
MOVE:
	CALL	PUWA	;GET XXXX
	PUSH	D	;SAVE ON STACK
	CALL	PUWA	;GET YYYY IN DE
	CALL	PUWA	;GET ZZZZ IN DE, YYYY GOES TO HL
	XCHG		;DE=Y HL=Z STACK=X
	XTHL		;DE=Y STACK=Z HL=X
	CALL	NEGDE	;NEGATE DE
	MOV	A,B	;GET COMMAND AND SEE
	CPI	'M'	;IF IT WAS 'M'
	JNZ	KOMP1	;JUMP IF IT WAS NOT.
	CALL	OKQ	;MOVE. ARE YOU SURE, USER?
MOV1:
	MOV	A,M	;GET THRU X
	XTHL		;HL=Z STACK=X
	CALL	STORE	;STORE  AND CHECK
	INX	H	;BUMP Z
	XTHL		;RESTORE
	CALL	LAST	;END YET?
	JMP	MOV1	;NO.
;
;	REGISTER MODIFY/EXAMINE. FROM MONITOR BY:-
;
;	R <CR>	TYPE ALL REG CONTENTS
;	RA	ACCUMULATOR
;	RF	FLAGS,PSB
;	RB	REG B
;	RC	REG C
;	RD	REG D
;	RE	REG E
;	RH	REG H
;	RL	REG L
;	RS	STACK POINTER		***
;	RP	PC IF MONITOR 'CALLED'	***
;
; ***	NOTE:	RS, RP GIVE AND EXPECT 4-HEX DIGITS
;
RXLST:	DB	'AFBCDEHL',0	;REGISTER LIST
;
REGEX:
	CALL	CHIN	;GET REGISTER IDENTIFIER
	CPI	CR	;IS IT CR?
	JZ	REXAL	;YEP.
	PUSH	PSW	;NO. SAVE PSW
	MVI	A,'='
	CALL	TYPE	;TYPE A '='
	POP	PSW	;RESTORE IDENT
	LXI	D,SVPC	;ADR OF P.C.
	CPI	'P'	;SEE IF PC REQUEST
	JZ	RX2	;YES.
	INX	D	;POINT TO SP
	INX	D
	CPI	'S'	;IS IT 'S'
	JZ	RX2	;YES.
	MOV	B,A	;NO. SAVE ID IN B
	LXI	H,RXLST	;LIST VECTOR ADR
	LXI	D,SVA	;ADR OF 'A' STORE
RX0:
	MOV	A,M	;GET TABLE ID
	ANA	A	;CHECK FOR END (0)
	JZ	ILLEG	;YES. ILLEGAL REQUEST
	CMP	B	;COMPARE WITH REQUEST
	JZ	RX1	;FOUND?
	INX	H	;NO. NEXT ENTRY
	DCX	D	;NEXT REG
	JMP	RX0	;NEXT TRY.
;
RX1:
	LDAX	D	;GET REG
	CALL	THXB	;TYPE IT OUT
	CALL	BLANK	;FOLLOWED BY SPACE
	CALL	GHXB	;GET RESPONSE
	JC	NONH1	;NON-HEX. TRY CR LATER
	STAX	D	;STORE INPUT IN REG
	JMP	NEXT	;BACK HOME, JAMES.
;
RX2:
	XCHG		;REG ADR TO HL
	MOV	E,M	;LOW S OR P
	INX	H	;BUMP VECTOR
	MOV	D,M	;HI S OR P
	XCHG		;REG VAL IN HL
	CALL	THXW	;TYPE HEX WORD
	CALL	PUWB	;GET CHANGE.
	JC	NONH1	;NON-HEX JUMP
	XCHG		;RESTORE RAM VECTOR
	MOV	M,D	;STORE HI S OR P
	DCX	H	;DROP VECTOR
	MOV	M,E	;STORE LO S OR P
	JMP	NEXT	;RETURN
RXTSE:
	CALL	BLANK	;SPACE
	CALL	TYPE	;TYPE THE ID.
	MVI	A,'='
	JMP	TYPE	;EQUALS
;
REXAL:
	LXI	D,SVA	;ADR OF 'A'
	LXI	H,RXLST	;ID LIST
RXA1:
	MOV	A,M	;GET ID
	ANA	A	;LAST YET? (0)
	JZ	RXA2	;YES
;
;	THIS LITTLE BIT OF CODE GOES IN ONLY IF WE ARE MAKING
;	A 32 COLUMN CONFIGURED DISPLAY MONITOR.
;
	IF	COLSW
	CPI	'E'	;SEE IF NEXT REGISTER IS 'E'
	CZ	CRLF	;IF SO, NEXT LINE PLEASE,
	ENDIF
;
;	THE ALTERNATIVE IS A 5-BYTE DUMMY PATCH.
;
	IF	NOT COLSW
	NOP
	NOP
	NOP
	NOP
	NOP
	ENDIF
;
	CALL	RXTSE	;TYPE ' ',ID,'='
	LDAX	D	;GET REG
	DCX	D	;DROP REG PTR
	INX	H	;BUMP LIST PTR
	CALL	THXB	;TYPE CONTENTS
	JMP	RXA1	;NEXT PLEASE.
RXA2:
	MVI	A,'P'	;DO PC
	CALL	RXTSE
	LHLD	SVPC	;GET PC
	CALL	THXW	;TYPE PC
	MVI	A,'S'	;NOW DO SP
	CALL	RXTSE
	LHLD	SVSP	;GET SP
RXAR:
	CALL	THXW	;TYPE VALUE
	JMP	NEXT	;RETURN TO MOM.
;
;	HEX WORD PICKUPS.
;	PUWA GETS WORD, AND RETURNS TO MONITOR IF ERROR.
;	IF NOT PUTS RESULT IN 'DE'.
;
PUWA:
	CALL	PUWB	;GET A HEX WORD
	JC	ILLEG	;BADDY OUT HERE
	XCHG		;SAVE INTO DE
	RET		;RETURN
;
;	PUWB GETS WORD INTO 'HL' WITHOUT CHECK.
;
PUWB:
	CALL	BLANK	;TYPE A BLANK FIRST.
	JMP	GHXW	;NOW GET THE WORD.
;
;	PAUSE GENERATOR.
;	TYPES THE MESSAGE 'PAUSE' THEN AWAITS ANY KEYSTRIKE
;	(NO ECHO) BEFORE CONTINUING.
;
PWAIT:
	PUSH	H	;SAVE HL
	LXI	H,M5	;MESSAGE 'PAUSE'
	CALL	MSG
	POP	H	;RECOVER
	JMP	GETCH	;ANY RESPONSE WILL DO.
;
;	MONITOR OR USER VERIFY ROUTINE OK?
;	CALLING SEQUENCE:-
;		CALL	OKQ
;		....		;GOES HERE IF RESPONSE IS SP
;				;OTHERWISE ABORTS.
;
OKQ:
	PUSH	PSW	;SAVE PSW
	PUSH	H	;AND HL
	LXI	H,M7	;ADR OF 'OK?' MESSAGE
	CALL	MSG	;PRINT IT
	LXI	H,M8	;PREPARE TO ABORT
	CALL	GETCH	;USER'S REPLY
	ANI	7FH	;MASK OUT PARITY.
	CPI	' '	;TRY ' '
	JNZ	ILLG1	;NO. ABORT
	POP	H	;YES. RESTORE HL
	POP	PSW	;AND PSW
	RET		;AND GO ON.
;
;	ECHO ON/OFF CONTROLLER.
;
;	CALLING SEQUENCE:-
;		MVI	A,XX	;XX=0 FOR OFF
;				;XX<>0 FOR ON
;		CALL	ECHCN
;		....		;NOW SET/RESET.
;
ECHCN:
	STA	ECHO	;STORE REQUIRED VALUE
	RET
;
;	SYSTEM I/O ROUTINES
;
;******* THIS VERSION SUITS JADE PSI/O SYSTEM HARDWARE *******
;
;	USER MUST PUT HIS OWN CONSOLE DRIVER IN HERE
;	IF DIFFERENT TO THE VERSION SHOWN
;
;
;	TYPE A CHARACTER.
;	CALLING SEQUENCE:-
;		LDA	CHR
;		CALL	TYPE	;TYPE IT
;		....
;
;
;	ROUTINE CO IS A PATCH FOR SBC80/SDK80 SYSTEMS
;	WHICH PASS ARGUMENT IN 'C'
;
CO:
	MOV	A,C	;PUT ARGUMENT INTO A
TYPE:
	PUSH	PSW	;SAVE CONTENTS OF 'A'
TYP1:
	IN	CONST	;GET CONSOLE STATUS
	ANI	TRDY	;ZERO INDICATES BUSY.
	JZ	TYP1	;IF SO, TRY AGAIN.
	POP	PSW	;CLEAR. RESTORE 'A'
	OUT	CNOUT	;OUTPUT TO 'CNOUT'
	RET
;
;	RETRIEVE CHARACTER FROM CONSOLE
;	PARITY IS KEPT, BUT NO ECHO GIVEN.
;	CALLING SEQUENCE:-
;		CALL	GETCH	;GET CHARACTER
;		....		;CHARACTER IN 'A'
;
;
;	NOTE: THIS IS ALSO THE ENTRY POINT FOR SDK80/SBC80
;	ROUTINE CI.
;
CI:
GETCH:
	CALL	CSTS	;GET CONSOLE STATUS
	JZ	GETCH	;IF SO, TRY AGAIN.
	IN	CNIN	;READY. GET A CHARACTER.
	RET		;RETURN WITH CHAR IN 'A'
;
;	CONSOLE STATUS ROUTINE. CALLED BY DISP AND PUNCH
;	TO ALLOW STOPPING OF OUTPUT BY TYPING ANY CHAR.
;	THE BREAK CHARACTER IS THE FIRST CHARACTER INPUT
;	TO THE MONITOR AFTER RETURN.
;	(IDEAL BREAK CHARACTER IS <SP>. RESULTS IN MONITOR QUERY)
;
CSTS:
	IN	CONST	;GET CONSOLE STATUS
	ANI	RBR	;INPUT BUFFER READY?
	RET		;RETURN
;
;
;	SYSTEM MESSAGES.
;
M0:	DB	CR,LF,'UPG80 V3:1'
M1:	DB	CR,LF,'* ',0FFH
M2:	DB	CR,LF,0FFH
M3:	DB	' ??',0FFH
M4:	DB	CR,LF,'MEMORY ERR @ ',0FFH
M5:	DB	' PAUSE ',0FFH
M7:	DB	' OK? ',0FFH
M8:	DB	'ABORT',0FFH
	ORG	ROM+0400H
;
M6:	DB	' CKS ERR @ ',0FFH
M10:	DB	CR,LF,'B/P @ ',0FFH
;
;	SEARCH MEMORY FOR A GIVEN BYTE.
;	CALLED FROM MONITOR BY:-
;	S XXXX YYYY VV
;
;	WHERE   XXXX=  STARTING ADDRESS FOR SEARCH
;		YYYY=  FINISHING ADDRESS FOR SEARCH
;		  VV=  BYTE TO BE FOUND
;
;
SEARCH:
	CALL	PICKUP	;GET BLOCK ADDRESSES.
	CALL	GBYTE	;NOW SPACE AND BYTE REF.
	MOV	B,A	;SAVE IT IN 'B'
	CALL	SRC4	;START A NEW LINE
SRC1:
	CALL	HOLD	;SEE IF HOLD CALLED.
	MOV	A,M	;GET COMPARE.
	CMP	B	;COMPARE BYTE WITH MEMORY
	CZ	SRC3	;PRINT ADDRESS IF EQUAL.
SRC2:
	CALL	LAST	;NOW SEE IF ALL DONE.
	JMP	SRC1	;IF NOT, CONTINUE SEARCH
;
;	SRC3	PRINTS ADDRESS
;	SRC4	SETS UP FOR NEW LINE.
;
SCNT	EQU	OSET/2
;
SRC3:
	CALL	BLANK	;ONE SPACE PLEASE,
	CALL	THXW	;FOLLOWED BY THE ADDRESS.
	DCR	C	;DECREMENT THE LINE COUNT
	RNZ		;RETURN PRONTO IF NOT FULL.
SRC4:
	CALL	CRLF	;START ON NEW LINE,
	MVI	C,SCNT	;LOAD SEARCH COUNTER.
	RET		;THEN CONTINUE ON OUR MERRY WAY.
;
;	COMPARE MEMORY. STARTED OUT IN 'MOVE' FUNCTION WHERE
;	IT GOT THE ADDRESSES.
;	CALLED FROM THE MONITOR BY:-
;	K XXXX YYYY ZZZZ
;		WHERE XXXX=START ADDR OF FIRST BLOCK
;		      YYYY=STOP ADDR OF FIRST BLOCK
;		      ZZZZ=START ADDR OF SECOND BLOCK
;	PRINTS OUT ALL OCCURRENCES OF INEQUALITY.
;
KOMP1:
	CALL	HOLD	;SEE IF HOLD REQUESTED.
	MOV	A,M	;GET FIRST BLOCK BYTE.
	XTHL		;SWAP HL AND T.O.S.
	CMP	M	;NOW COMPARE WITH SECOND BYTE
	JZ	KOMP2	;SKIP IF ALL THE SAME.
	CALL	SRC4	;NEW LINE FIRST
	XTHL		;SWAP POINTERS
	CALL	KOMP3	;FIRST ADDR/BYTE
	XTHL		;SWAP THEM BACK
	MOV	A,M	;SECOND BYTE IN.
	CALL	KOMP3	;PRINT THEM TOO.
KOMP2:
	INX	H	;BUMP THE SECOND ADDRESS
	XTHL		;BACK WHERE WE STARTED.
	CALL	LAST	;SEE IF ALL DONE.
	JMP	KOMP1
KOMP3:
	CALL	SRC3	;PRINT SPACE AND ADDRESS.
	CALL	BLANK	;A SPACE
	JMP	THXB	;THEN BYTE VALUE
;
;
;	ZERO OUT A BLOCK OF MEMORY.
;	CALLED FROM MONITOR BY:-
;	Z XXXX YYYY
;	(THE VALUE VV=0 FOR THIS FUNCTION)
;
;
;	FILL BLOCK WITH A VALUE. MONITOR CALL BY:-
;
;	F XXXX YYYY VV
;
;	CAUSES MEMORY LOCATIONS XXXX THRU YYYY TO BE
;	SET TO THE VALUE VV.
;
ZERO:
FILL:
	CALL	PICKUP	;GET BLOCK ADDRESSES.
	MOV	A,B	;GRAB THE COMMAND BYTE (F OR Z)
	CPI	'Z'	;COMPARE WITH 'Z'
	MVI	A,0	;ASSUME ZERO REQUESTED, THEN
	JZ	FILL0	;JUMP IF TRUE.
	CALL	GBYTE	;ELSE GET THE FILLING BYTE.
FILL0:
	CALL	OKQ	;VERIFY FILL/ZERO REQUEST
FILL1:
	CALL	STORE	;STORE AND CHECK
	CALL	LAST	;END IN SIGHT?
	JMP	FILL1	;NOT YET.
;
;****	GET BYTE WITH TEST.
;
GBYTE:
	CALL	BLANK	;LEADING BLANK
	CALL	GHXB	;THEN THE BYTE.
	JC	ILLEG	;TEST LEGALITY.
	RET
;
;	USER DEFINABLE ROUTINES.
;	CALLED FROM MONITOR BY:-
;	U XXXX		;DEFINE USER CALL ADDRESS.
;	U <SP>		;GO TO USER ADDRESS.
;	(IF XXXX=0 THEN USER CALL IS CLEARED)
;
USER:
	CALL	BLANK	;PUT IN A SPACE,
	CALL	GHXW	;THEN GO FOR THE ADDRESS, IF ANY.
	JC	USER2	;SEE IF CARRY SET (BAD DATA?)
	SHLD	USERA	;NO. ADDRESS SET.
	JMP	NEXT
USER2:
	CPI	' '	;CARRY SET. SEE IF USER CALL REQUEST.
	JNZ	ILLEG	;IF NOT, PANIC
	LHLD	USERA	;YES. GET THE ADDRESS.
	MOV	A,L	;NOW SEE IF LEGAL ADDRESS BY
	ORA	H	;LOOKING FOR NON-ZERO ADDRESS.
	JZ	ILLEG
	PCHL		;ALL O.K. GO THERE.
;
;
;
;	ROUTINES TO PUNCH AND LOAD MEMORY.
;	INTEL STANDARD HEX OBJECT TAPE FORMAT IS USED.
;
;	RECORD START	:
;	BYTE COUNT	2-CHARS
;	LOAD ADR	4-CHARS
;	RECORD TYPE	2-CHARS	0=DATA 1=EOF
;	DATA BYTES	(2-CHARS/BYTE)
;	CHECKSUM FROM BYTE-COUNT TO END OF DATA
;	(ALL CHARACTERS MUST BE HEX LEGITIMATE  0-9,A-F)
;
;	EOF RECORD MAY CONTAIN EXECUTION ADR.
;	LOADER GOES TO ADR IF NON-ZERO
;
PUNCH:
	CALL	PUWA	;FROM ADR
	CALL	PUWA	;TO ADR
	CALL	PWAIT	;AWAIT READINESS
;
;	HL=FIRST ADR	DE=LAST ADR
;
PN0:
	MOV	A,L	;GET LOW PART OF START ADR
	ADI	OSET	;INCREMENT BY 8/16
	MOV	C,A	;HOLD IN 'C'
	MOV	A,H	;GET HIGH PART OF START ADR
	ACI	0	;TAKE CARE OF ANY O'FLOW
	MOV	B,A	;HOLD IN 'B'
	MOV	A,E	;NOW LOW PART OF FINAL ADR
	SUB	C	;SUBTRACT LOW START
	MOV	C,A	;PUT IN 'C'
	MOV	A,D	;HIGH PART END ADR.
	SBB	B	;SUBTRACT FROM START.
	JC	PN1	;JUMP IF <OSET LEFT.
	MVI	A,OSET
	JMP	PN2
PN1:
	MOV	A,C	;SET UP FINAL COUNT.
	ADI	OSET+1	;WENT NEGATIVE, ADD 9/17
PN2:
	ORA	A	;SET FLAGS.
	JZ	PDONE
	PUSH	D	;SAVE HI
	MOV	E,A	;LENGTH IN E
	CALL	PN3	;PUNCH HEADER RECORD PARTS.
	JMP	PN4
PN3:
	CALL	CCRLF
	MVI	D,0	;CLEAR CKSUM COUNTER.
	MVI	A,':'	;PUNCH HEADER
	CALL	CTYPE
	MOV	A,E
	CALL	PBYTE	;PUNCH LENGTH
	MOV	A,H
	CALL	PBYTE	;PUNCH ADR HI
	MOV	A,L
	JMP	PBYTE	;PUNCH ADR LO
PN4:
	XRA	A	;CLEAR A
	CALL	PBYTE	;RECORD TYPE=0
PN5:
	MOV	A,M	;GET DATA
	INX	H
	CALL	PBYTE	;FOR PUNCHING
	DCR	E	;DROP COUNT BY 1
	JNZ	PN5	;NOT DONE YET
	XRA	A	;NOW FIND CKSUM
	SUB	D	;AS 2'S COMPL OF 8-BIT SUM
	CALL	PBYTE	;PUNCH IT
	POP	D	;RESTORE HI ADR
	JMP	PN0	;GO AGAIN
;
;	BYTE PUNCHER.
;
PBYTE:
	PUSH	PSW	;HOLD ONTO A,PSB
	CALL	CSTS	;SEE IF USER PANICED.
	JNZ	NEXT
	POP	PSW	;IF NOT, GO ON.
	CALL	CTHXB
	ADD	D	;UPDATE CKSUM
	MOV	D,A
	RET		;GO AGAIN
;
;	ALL DONE NOW.
;
PDONE:
	CALL	CCRLF
PDON1:
	JMP	NEXT	;RETURN TO MOMMA
;
;	PUNCH AN END OF FILE.
;
PEND:
	CALL	PUWB	;ADR OR CR
	JNC	PEND1	;GO IF ADR
	LXI	H,0	;ASSUME CR, PUT ADR=0
	CPI	CR	;WAS IT CR?
	JNZ	ILLEG	;IF NOT, ITS ILLEGAL
PEND1:
	CALL	PWAIT	;AWAIT PROMPT
	MVI	E,0	;ZERO LENGTH
	CALL	PN3
	MVI	A,1	;RECORD TYPE=1
	CALL	PBYTE
	XRA	A
	SUB	D	;CALCULATE THE CKSUM
	CALL	PBYTE	;PUNCH IT.
;
;	PUNCH 100 NULLS
;
NULLS:
	MVI	C,100	;WE WILL PUNCH 100 NULLS (10 INCHES)
	XRA	A
NLS1:
	CALL	CTYPE
	DCR	C
	JNZ	NLS1	;MORE TO GO?
	JMP	PDON1	;NO. RETURN
;
NULL:
	CALL	PWAIT	;THIS ENTRY VIA COMMAND 'N'
	JMP	NULLS	;FOLLOWED RAPIDLY BY NULLS.
;
;	LOAD HEX OBJECT TAPE.
;
;	MONITOR COMMAND 'L'
;	LOAD A HEX-BINARY TAPE AS PRODUCED BY THE 'P'
;	COMMAND.
;	MAY CONTAIN AN OFFSET VALUE, ALLOWING THE DATA TO
;	BE LOADED INTO A DIFFERENT LOCATION TO THAT SPECIFIED
;	BY THE LOAD ADDRESS.
;	E.G.	L 1000   WILL CAUSE THE LOADED DATA TO BE
;	1000H LOCATIONS HIGHER THAN THAT SPECIFIED BY
;	THE BLOCK LOAD ADDRESS.
;
;
LOAD:
	CALL	PUWB	;GET THE OFFSET, IF ANY.
	JNC	LD4
	CPI	CR	;ERROR MAY ONLY BE <CR>
	JNZ	ILLEG
LD4:
	XRA	A	;PREPARE TO
	CALL	ECHCN	;RESET ECHO.
	CALL	CRLF	;NEW LINE PLEASE.
	PUSH	H	;SAVE BIAS ADR
LD5:
	POP	H	;GET BIAS
	PUSH	H	;AND RESTORE
	CALL	RIX	;GET INPUT
	MVI	B,':'	;WAIT FOR ':'
	SUB	B
	JNZ	LD5	;TRY AGAIN
	MOV	D,A	;CLEAR CKSUM
	CALL	BYTE	;GET LENGTH
	JZ	LD7	;ZERO MEANS ALL DONE
	MOV	E,A	;SAVE LENGTH
	CALL	BYTE
	PUSH	PSW	;SAVE HI ADR
	CALL	BYTE
	POP	B	;FETCH MSBYTE
	MOV	C,A	;BC NOW HAS ADR
	PUSH	B	;SAVE IT
	XTHL		;INTO HL
	SHLD	BLKAD	;SAVE BLOCK ADR
	XTHL		;IN CASE OF ERROR
	POP	B
	DAD	B	;RESTORE AND ADD BIAS
	CALL	BYTE	;RECORD TYPE INPUT
LD6:
	CALL	BYTE	;GET DATA BYTES
	CALL	STORE	;STORE
	INX	H
	DCR	E
	JNZ	LD6	;GO ON.
	CALL	BYTE	;GET CKSUM
	JZ	LD5
LDERR:
	LXI	H,M6	;CKSUM ERROR
	CALL	MSG
	LHLD	BLKAD	;ADR OF THIS BLOCK IS
	JMP	RXAR	;NOW GIVEN
LD7:
	CALL	BYTE	;MSB OF XEQAD
	MOV	H,A
	CALL	BYTE
	MOV	L,A
	ORA	H
	JZ	NEXT	;MONITOR IF ADR=0
	PCHL		;OTHERWISE EXECUTE
;
RIX:
	CALL	RI
	JC	ILLEG	;ON ERROR, PRINT '??'
	ANI	7FH	;REMOVE PARITY
	RET
;
;	ROUTINE RI
;	GETS A CHARACTER FROM THE CASSETTE READER INPUT
;
;
RI:
	PUSH	B	;SAVE BC
	LXI	B,TMOUT	;GET TIMEOUT (MILLISECONDS)
RI10:
	CALL	CASTS	;GET READER STATUS
	JNZ	RI15	;READY ON NON-ZERO
	CALL	DELAY	;IF NOT, DELAY 1 MS
	DCX	B	;DECREMENT DELAY COUNT
	MOV	A,B	;SEE IF IT
	ORA	C	;IS ZERO YET.
	JNZ	RI10	;TRY AGAIN IF NOT DONE
	STC		;SET ERROR CARRY
	POP	B	;RESTORE BC
	RET		;TROUBLED RETURN
RI15:
	CALL	CGETCH	;GET DATA.
	ORA	A	;CLEAR CARRY ONLY.
	POP	B	;RESTORE BC
	RET		;SIMPLY RETURN
;
BYTE:
	PUSH	B	;SAVE BC
	CALL	RIX	;READ ASCII
	CALL	CNVBN	;CONVERT TO HEX
	JC	LDERR	;ERROR DETECTOR.
	RLC		;SHIFT LEFT 4 BITS
	RLC
	RLC
	RLC
	MOV	B,A	;SAVE THEM A WHILE
	CALL	RIX	;GET SECOND BYTE
	CALL	CNVBN	;CONVERT TO HEX
	JC	LDERR	;ERROR DETECTOR
	ORA	B	;OR IN THE SAVED NYBBLE
	MOV	C,A	;HOLD BYTE A WHILE.
	ADD	D	;ADD TO CKSUM
	MOV	D,A	;UPDATE CKSUM
	MOV	A,C	;RESTORE BYTE
	POP	B	;RESTORE BC
	RET
;
; FUNCTION DELAY.
;	CAUSES THE SYSTEM TO DELAY FOR 1 MS.
;
DELAY:
	PUSH	B	;SAVE BC
	MVI	B,ONEMS	;GET ONE MS LOOP COUNT
DEL2:
	DCR	B	;DECREMENT LOOP COUNT
	JNZ	DEL2	;NOT YET DONE.
	POP	B	;ALL DONE. GET BC
	RET		;RETURN TO PATIENT WAITER.
;	ENTER HERE FOLLOWING A SOFTWARE RST2
;	I.E. BREAKPOINT SETTING.
;
BPAT:
	SHLD	SVPC	;STORE CALLING PC
	STA	TMPA	;AND CARRY (IN B7)
	RAL		;THEN ROTATE BACK THE ACC.
	LXI	H,0	;NOW TRANSFER THE SP TO HL BY DOING A DUMMY
	DAD	SP	;ADD TO HL. (N.B. CLEARS CARRY)
	SHLD	SVSP	;SAVE THE CALLER SP.
	LXI	SP,SVA+1	;PICK UP REG STORE POINTER
	PUSH	PSW	;TO SAVE PSW
	PUSH	B	;AND BC
	PUSH	D	;AND DE. (HL ALREADY SAVED)
	LXI	H,SVF	;GET THE PSB BYTE
	LDA	TMPA	;PICK UP THE CARRY HOLDER,
	RAL		;ROTATE IT BACK TO CARRY.
	JNC	BP1	;SKIP IF CARRY NOT SET,
	INR	M	;OTHERWISE RESET CARRY.
BP1:
	LXI	SP,STACK	;SET SP TO MONITOR STACK
	LXI	H,M10	;TYPE BREAKPOINT MESSAGE
	CALL	MSG
	LHLD	SVPC	;PICK-UP THE BREAK ADDRESS + 1
	DCX	H	;MAKE IT THE REAL ADDRESS.
	SHLD	SVPC	;RESET THE SAVED PC STORE
	CALL	THXW	;TELL THE USER WHERE HE BROKE.
	CALL	CRLF	;NEXT LINE PLEASE.
	JMP	REXAL	;NOW PRINT THE REGISTER DATA.
;
;
;
;	CONTINUE AFTER A BREAKPOINT HALT
;
;	ASSUMES THAT THE LOCATION OF THE B/P HAS BEEN ALTERED
;	BY A PRIOR
;		B XXXX    COMMAND.
;	CONTINUE CAN ONLY BE USED TO RETURN THE MONITOR TO
;	A PROGRAM WHICH HAS BEEN HALTED BY EXECUTION
;	OF A 'RST 2' INSTRUCTION (0D7H) AT A LOCATION WHOSE CONTENTS
;	ARE SAVED IN 'BPDAT'.
;
CONT:
	LHLD	SVPC	;GET PSEUDO-RESTART.
	MOV	A,L	;PUT LOW PART IN ACC.
	ORA	H	;RESULT WILL BE ZERO IF ALL
	JZ	ILLEG	;BITS ARE ZERO. I.E. NO B/P.
	CALL	BLANK	;PRINT A SPACE
	CALL	THXW	;FOLLOWED BY THE ADDRESS.
	XCHG		;PUT OLD ADDRESS IN DE
	LHLD	BPADD	;NOW GET CURRENT ADDRESS.
	CALL	NEGDE	;NEGATE THE PC ADDRESS.
	DAD	D	;D.P. ADD TO B/P ADDRESS.
	MOV	A,L	;LO RESULT TO ACC,
	ORA	H	;OR IT WITH HI RESULT,
	LHLD	SVPC	;RECOVER PC (MAY NEED IT)
	JNZ	CON3	;SEE IF DE=HL (I.E. ZERO RESULT)
	LXI	H,BPDAT	;GET START ADDRESS OF SAVED INSTRUCTION.
CON3:
	MVI	A,CR	;<CR> FORCES 'J' CONTINUE.
	PUSH	PSW	;SAVE SIMULATED 'J' COMMAND
	JMP	JMP4	;NOW ENTER 'JUMP'.
;
;
;	BREAK-POINT THE PROGRAM AT LOCATION XXXX
;	B XXXX
;
;	MAY ALSO BE USED TO CLEAR A PREVIOUS B/P BY
;	B (CRTN)
;
;	BPT SAVES THE ADDRESS XXXX AND ITS CONTENTS
;	IT THEN REPLACES THE CONTENTS OF XXXX WITH D7 ( RST 2 ).
;	THIS FORCES THE PROGRAM TO SAVE ALL DATA AND RETURN
;	TO THE MONITOR. THE PROGRAM MAY BE RESTARTED FROM
;	XXXX BY A CONTINUE ( C ) COMMAND AFTER IT HAS HALTED.
;
BPT:
;
;****	THIS CONDITIONAL CODE INSERTS THE RST2 JUMP IN RAM IF
;	THE MONITOR IS NOT IN PAGE ZERO.
;
;		ORG	0010H
;		JMP	BPIN
;
	IF	ROMSW
	MVI	A,JMP	;GET A 'JMP'
	STA	0010H	;PUT IT AT 0010H
	LXI	H,BPIN	;GET ADDRESS OF 'BPIN'
	SHLD	0011H	;STORE IT AT 0011H
	ENDIF
	CALL	PUWB	;GET ADDRESS
	JNC	BPT1	;GOT AN ADDRESS - SO PROCEED
	CPI	CR	;NOT AN ADDRESS - WAS IT A CRTN
	JNZ	ILLEG	;NO SO BOMB OUT
	LXI	H,0	;YES SO SIMULATE AN ADDRESS OF ZERO
;
;	BPT WILL REMOVE THE OLD B/P (IF ANY )
;
BPT1:
	PUSH	H	;COME HERE WITH ADDRESS IN HL. SAVE IT ON THE STACK
	LHLD	BPADD	;IS THE PREVIOUS B/P ADDRESS = 0
	MOV	A,L	;PUT LO PART OF ADDRESS IN ACC
	ORA	H	;THEN 'OR' WITH HI PART
	JZ	BPT2	;IT WAS ZERO SO SAVE XXXX AND (XXX)
	LXI	H,BPDAT	;POINT TO THE SAVED DATA FROM THE LAST B/P
	MOV	A,M	;GET IT IN A
	LHLD	BPADD	;GET THE LAST B/P ADDRESS IN HL
	CALL	STORE	;AND RESTORE THE DATA THERE
;
;	BREAKPOINT MAKER.
;	CREATES A GAP IN THE TARGET PROGRAM BY INSERTING AN 'RST 2'
;	IN PLACE OF THE FIRST BYTE OF THE INSTRUCTION.
;	THE INSTRUCTION (ALL BYTES, COUNT COMPUTED) IS PLACED
;	IN A TEMPORARY STORE, ALONG WITH A JUMP TO THE NEXT
;	INSTRUCTION IN THE TARGET PROGRAM.
;
BPT2:
	POP	H	;RETRIEVE B/P ADDRESS FROM STACK.
	SHLD	BPADD	;SAVE IT FOR FUTURE RETURN.
	MOV	A,H	;SEE IF THIS IS
	ORA	L	;ONLY CLEARING
	JZ	NEXT	;THE BREAKPOINT.
	MOV	A,M	;LOAD ITS FIRST BYTE.
	LXI	H,TAB1	;GET START ADDRESS OF TABLE 1
	CPI	40H	;SEE IF THE BYTE IS IN TABLE 1
	JC	BPT3	; I.E. LESS THAN 40H
	LXI	H,TAB2	;GET START OF TABLE 2.
	SUI	0C0H	;SEE IF IT IS IN TABLE 2
	JNC	BPT3	; I.E. >0BFH
	MVI	A,1	;THE GROUP 40H TO 0BFH IS 1-BYTE
	JMP	BPT5	;IN LENGTH.
BPT3:
	MOV	D,A	;RANGE OF BYTE IS NOW 0 TO 64
	RRC		;WE MUST PACK THIS RANGE DOWN
	RRC		;TO 0 TO 15 BYTES OFFSET.
	MVI	B,0	;AND THEN MAKE UP THE
	ANI	0FH	;TRUE ADDRESS BY
	MOV	C,A	;ADDING THE OFFSET TO THE
	DAD	B	;START ADDRESS IN THE TABLE.
	MVI	A,3	;WE MUST ALSO KNOW WHERE IN
	ANA	D	;THE BYTE THE INSTRUCTION SIZE
	MOV	D,A	;IS TO BE FOUND. (SEE NOTE ABOVE TABLE)
	MOV	A,M	;GET THE KEY BYTE.
BPT4:
	DCR	D	;FIND THE KEY POSSY.
	JM	BPT5	;BY DECREMENTING THE 'D' REGISTER UNTIL IT
	RRC		;GOES NEGATIVE. IF NOT FOUND, ROTATE THE KEY
	RRC		;BYTE 2 POSITIONS RIGHT
	JMP	BPT4	;AND TRY AGAIN
BPT5:
	ANI	3	;WE CAN NOW COMPUTE THE BYTE COUNT.
	JZ	ILLEG	;(OF COURSE 0 IS ILLEGAL)
	MOV	C,A	;SAVE THE COUNT IN C
	LXI	H,BPDAT	;DATA STORE ADDRESS
	XCHG		;PUT IT INTO DE
	LHLD	BPADD	;GET THE SOURCE ADDRESS.
BPT6:
	MOV	A,M	;PICK UP THE DATA BYTE AND
	INX	H	;THEN BUMP ADDRESS.
	XCHG		;AFTER SWAPPING HL ADDRESSES,
	MOV	M,A	;PUT IT IN THE BUFFER.
	INX	H	;NOW BUMP STORE ADDRESS,
	XCHG		;BEFORE RESTORING THE ADDRESSES.
	DCR	C	;DECREMENT BYTE COUNTER.
	JNZ	BPT6	;TRY AGAIN IF STILL DATA.
	XCHG		;RETRIEVE THE STORE ADDRESS.
	MVI	M,JMP	;PUT 'JMP' (0C3H) IN STORE.
	INX	H	;BUMP STORE ADDRESS.
	MOV	M,E	;LOW ORDER RETURN ADDRESS.
	INX	H	;BUMP YET AGAIN.
	MOV	M,D	;HIGH ORDER RETURN ADDRESS.
	LHLD	BPADD	;FINALLY REPLACE THE
	MVI	M,0D7H	;B/P WITH AN 'RST 2'
	JMP	NEXT
;
;	BREAKPOINT DATA TABLE.
;	CONSISTS OF A SERIES OF DATA BYTES WHICH DEFINE THE
;	NUMBER OF BYTES IN AN INSTRUCTION, BASED ON THE
;	VALUE OF ITS FIRST BYTE.
;
;	THE TABLE HAS 2 SECTIONS.
; TAB1	CONTAINS DATA FOR BYTES 000H TO 03FH
; TAB2	CONTAINS DATA FOR BYTES 0C0H TO 0FFH
;	EACH BYTE CONTAINS 4 KEYS REPRESENTING THE SIZE OF
;	4 INSTRUCTIONS (RANGE 0-3, 0 IS ILLEGAL)
;	SUCH THAT THE BOTTOM 2 BITS OF THE INSTRUCTION BYTE KEY TO
;	THE TABLE BYTE AS FOLLOWS:-
;	00	BITS B1,B0
;	01	BITS B3,B2
;	10	BITS B5,B4
;	11	BITS B7,B6
;
B00	EQU	0	;KEY 0 DATA BITS
B01	EQU	1
B02	EQU	2
B03	EQU	3
B10	EQU	0	;KEY 1 DATA BITS
B11	EQU	B01*4
B12	EQU	B02*4
B13	EQU	B03*4
B20	EQU	0	;KEY 2 DATA BITS
B21	EQU	B11*4
B22	EQU	B12*4
B23	EQU	B13*4
B30	EQU	0	;KEY 3 DATA BITS
B31	EQU	B21*4
B32	EQU	B22*4
B33	EQU	B23*4
;
TAB1:
	DB	B01+B13+B21+B31
	DB	B01+B11+B22+B31
	DB	B00+B11+B21+B31
	DB	B01+B11+B22+B31
	DB	B00+B13+B21+B31
	DB	B01+B11+B22+B31
	DB	B00+B11+B21+B31
	DB	B01+B11+B22+B31
	DB	B01+B13+B23+B31
	DB	B01+B11+B22+B31
	DB	B00+B11+B23+B31
	DB	B01+B11+B22+B31
	DB	B01+B13+B23+B31
	DB	B01+B11+B22+B31
	DB	B00+B11+B23+B31
	DB	B01+B11+B22+B31
TAB2:
	DB	B01+B11+B23+B33
	DB	B03+B11+B22+B31
	DB	B01+B11+B23+B30
	DB	B03+B13+B22+B31
	DB	B01+B11+B23+B32
	DB	B03+B11+B22+B31
	DB	B01+B10+B23+B32
	DB	B03+B10+B22+B31
	DB	B01+B11+B23+B31
	DB	B03+B11+B22+B31
	DB	B01+B11+B23+B31
	DB	B03+B10+B22+B31
	DB	B01+B11+B23+B31
	DB	B03+B11+B22+B31
	DB	B01+B11+B23+B31
	DB	B03+B10+B22+B31
;
;****	CASSETTE I/O HANDLING ROUTINES.
;
;
;****	CASSETTE OUTPUT CHARACTER.
;
CTYPE:
	PUSH	PSW	;SAVE PSW
CTYP1:
	IN	CSST	;STATUS
	ANI	TRDY	;READY?
	JZ	CTYP1
	POP	PSW	;YES. PRINT
	OUT	CSOUT	;AT CASSETTE.
	RET
;
;****	GET CHARACTER
;
CSI:
CGETCH:
	CALL	CASTS	;GET STATUS
	JZ	CSI
	IN	CSIN	;GET CHR
	RET
;
;****	CASSETTE INPUT STATUS
;
CASTS:
	IN	CSST	;STATUS BYTE
	ANI	RBR	;MASKED
	RET
;
;****	CASSETTE BYTE PUT.
;
CTHXB:
	PUSH	PSW	;SAVE DATA
	RRC		;ROTATE
	RRC		;THE
	RRC		;BYTE
	RRC		;4 BITS.
	CALL	CTHXN	;PRINT 1ST NYBBLE
	POP	PSW	;RECOVER
;
;****	CASSETTE NYBBLE PUT.
;
CTHXN:
	PUSH	PSW	;SAVED
	ANI	0FH	;BOTTOM 4 BITS
	ADI	90H	;MAKE THE
	DAA		;NYBBLE
	ACI	40H	;INTO AN
	DAA		;ASCII CHR 0-F
	CALL	CTYPE	;PUT IT.
	POP	PSW
	RET
;
;****	CASSETTE WORD OUTPUT.
;
CTHXW:
	PUSH	PSW	;SAVE PSW
	MOV	A,H	;DO TOP
	CALL	CTHXB	;BYTE
	MOV	A,L	;THEN BOTTOM
	CALL	CTHXB	;BYTE
	POP	PSW
	RET
;
;****	CASSETTE CRLF OUTPUT.
;
CCRLF:
	PUSH	H	;SAVE HL
	LXI	H,M2	;GET MESSAGE
	CALL	CMSG	;PRINT IT.
	POP	H
	RET
;
;****	CASSETTE MESSAGE.
;
CMSG:
	PUSH	PSW
	PUSH	H	;SAVE PSW AND HL
CMNXT:
	MOV	A,M	;GET BYTE
	INX	H	;BUMP PTR.
	CPI	0FFH	;END FLAG?
	CNZ	CTYPE
	JNZ	CMNXT	;MORE.
	POP	H	;RECOVER HL
	POP	PSW	;AND PSW
	RET
;
;****	CASSETTE BLANK.
;
CBLANK:
	PUSH	PSW
	MVI	A,' '	;A SPACE
	CALL	CTYPE	;IS SENT.
	POP	PSW
	RET
;
;****	GET HEX NYBBLE.
;
CGHXN:
	MVI	A,0FH	;ONLY BOTTOM NYBBLE
	JMP	CGHB1
;
;****	GET HEX BYTE.
;
CGHXB:
	MVI	A,0FFH	;ALL BYTE NEEDED.
CGHB1:
	PUSH	H	;SAVE HL
	CALL	CGHXW	;GET A WORD.
	JC	CGHB2	;ERROR?
	ANA	L	;NYBBLE/BYTE ONLY.
CGHB2:
	POP	H
	RET
;
;****	GET HEX WORD FROM CASSETTE.
;
CGHXW:
	PUSH	PSW	;SAVE PSW
	LXI	H,0	;START WITH NOTHING.
	CALL	CGETCH	;GET CHARACTER
	ANI	7FH	;AND MASK IT.
	CALL	CNVBN	;CONVERT TO BINARY.
	JC	GHW3
	MOV	L,A	;SAVE IT IF O.K.
CGHW1:
	CALL	CGETCH	;AND ANOTHER
	ANI	7FH	;MASKED.
	CALL	CNVBN	;THEN CONVERTED.
	JC	GHW2
	DAD	H	;*2
	DAD	H	;*4
	DAD	H	;*8
	DAD	H	;*16
	ADD	L	;ADD LO BYTE.
	MOV	L,A	;UPDATE
	JMP	CGHW1
;
;
;
;
;
	ORG	ROM + 07DCH
;
;****	JUMP TABLE FOR CASSETTE ROUTINES.
;
ZCTYPE:	JMP	CTYPE
ZCGETC:	JMP	CGETCH
ZCMSG:	JMP	CMSG
ZCCRLF:	JMP	CCRLF
ZCSPAC:	JMP	CBLANK
ZCTHXN:	JMP	CTHXN
ZCTHXB:	JMP	CTHXB
ZCTHXW:	JMP	CTHXW
ZCGHXN:	JMP	CGHXN
ZCGHXB:	JMP	CGHXB
ZCGHXW:	JMP	CGHXW
ZCASTS:	JMP	CASTS
;
	ORG	ROM+0800H
;
QIN:	EQU	0DBH
QOUT:	EQU	0D3H
QRET:	EQU	0C9H
;
;****	INPUT AND OUTPUT PORT DATA ROUTINES.
;
INPT:
OUTPT:
	MVI	A,QIN	;ASSUME 'IN' COMMAND
	STA	BUFF
	CALL	GBYTE	;GET PORT NUMBER.
	STA	BUFF+1	;SAVE IT IN 'BUFF+1'
	MVI	A,QRET	;GET 'RET'
	STA	BUFF+2
	MVI	A,'I'	;SEE IF THIS IS 'IN' COMMAND.
	CMP	B
	JNZ	OUTER	;MUST BE 'OUT'
	CALL	BUFF	;GET INPUT DATA.
	CALL	BLANK	;ONE SPACE,
	CALL	THXB	;FOLLOWED BY THE BYTE.
	CALL	CRLF
	JMP	NEXT
OUTER:
	MVI	A,QOUT	;REPLACE 'IN' WITH 'OUT'
	STA	BUFF
	CALL	GBYTE	;OUTPUT BYTE REQUIRED.
	CALL	CRLF
	CALL	BUFF	;OUTPUT IT.
	JMP	NEXT
;
;
;***********************************************************
;
;	DISASSEMBLER PROGRAM FOR 8080 ROUTINES.
;
;***********************************************************
;
;
;****	FIND START ADDRESS.
;
DIS80:
	CALL	PUWB	;GET START ADDRESS.
	JC	ILLEG	;ERROR EXIT
	CALL	CRLF
	MOV	B,H
	MOV	C,L	;BC NOW HAS MEMORY ADDR.
;
;****	GET BYTE.
;
DIS1:
	MOV	H,B	;PUT MEMORY ADDRESS
	MOV	L,C	;INTO HL
	CALL	THXW	;PRINT IT
	CALL	BLANK	;AND A SPACE.
	LDAX	B	;GET FIRST BYTE.
;
;****	FIND THE TABLE POSITION.
;
	MOV	E,A	;PUT OFFSET INTO C
	MVI	D,0	;AND CLEAR HI BYTE
;
;	ADD OFFSET THREE TIMES.
;
	LXI	H,ATAB1	;TABLE START ADDRESS.
	DAD	D	;ADD OFFSET
	DAD	D	;THREE
	DAD	D	;TIMES.
;
;****	READY TO PROCESS.
;
	MOV	D,M	;LOAD BYTE COUNT.
	MOV	A,D
	INX	H	;BUMP PAST BYTE COUNTER.
	CALL	BPRNT	;PRINT THE BYTES.
	MOV	E,M	;GET OPCODE OFFSET
	MVI	D,0	;INTO DE
	INX	H	;BUMP TABLE POINTER.
	PUSH	H	;AND SAVE IT
	LXI	H,ATAB2	;ADD OFFSET
	DAD	D	;TO THE
	DAD	D	;TABLE HEADER
	DAD	D	;FOUR
	DAD	D	;TIMES.
	MVI	D,4
	CALL	PRNT	;PRINT OPCODE.
	LXI	H,MSGBK	;NOW PRINT
	CALL	MSG	;4 SPACES
	POP	H	;RETRIEVE PTR.
	MOV	E,M	;DITTO FOR OPERAND(S).
	MVI	D,0
	LXI	H,ATAB3
	DAD	D
	DAD	D
	DAD	D
	MVI	D,3
	CALL	PRNT	;PRINT OPERAND(S)
	PUSH	B	;SAVE MEM PTR.
	MVI	H,0	;ZERO OUT H
	MOV	L,A	;PUT BYTE COUNT INTO L
	DAD	B	;BUMP MEMORY ADDRESS.
	MOV	B,H	;PUT BACK INTO
	MOV	C,L	;BC
	POP	H	;RETRIEVE MEMORY ADDRESS.
	DCR	A	;TEST BYTE COUNT
	JZ	DISB1	;FOR ONE
	DCR	A
	JZ	DISB2	;OR TWO
DISB3:
	INX	H	;GET AND
	MOV	E,M	;PRINT
	INX	H	;16 BIT
	MOV	D,M	;DATA
	XCHG		;WORD
	CALL	THXW	;VALUE
	JMP	DISB1
DISB2:
	INX	H	;GET AND
	MOV	A,M	;PRINT 8 BIT
	CALL	THXB	;DATA BYTE VALUE
DISB1:
	CALL	CRLF	;NEW LINE PLEASE.
	CALL	HOLD	;SEE IF HOLD REQUESTED.
	JMP	DIS1	;NO.
;
;****	PRINT CURRENT BYTE IF VALID.
;
BPRNT:
	PUSH	PSW	;SAVE PSW.
	PUSH	B	;SAVE CURRENT MEM PTR.
	MVI	E,3	;PRINT 3 BYTES.
BPRT1:
	LDAX	B	;GET CURRENT MEMORY BYTE.
	DCR	D	;DECREMENT COUNTER.
	CP	THXB	;PRINT IT,
	CM	BLANK	;OR ELSE 2 SPACES.
	CM	BLANK
	CALL	BLANK	;FOLLOWED BY SPACER.
	INX	B	;FINALLY BUMP POINTER.
	DCR	E
	JNZ	BPRT1
	POP	B	;RETRIEVE MEM PTR.
	POP	PSW	;AND PSW.
	RET
;
;****	PRINT A STRING FOLLOWED BY A SPACE.
;
PRNT:
	PUSH	PSW
PRNT1:
	MOV	A,M	;GET DATA BYTE
	CALL	TYPE	;PRINT IT.
	INX	H	;READY FOR NEXT BYTE
	DCR	D	;DECREMENT AND TEST
	JNZ	PRNT1	;LOOP COUNT.
	CALL	BLANK
	POP	PSW
	RET
;
;
;********************************************************
;
;	LINE ASSEMBLER PROGRAM.
;	USES COMMON TABLES WITH DISASSEMBLER.
;
;********************************************************
;
;
ASM80:
	CALL	PUWB	;GET START ADDRESS.
	JC	ILLEG
	CALL	CRLF
ASM1:
	CALL	THXW	;TYPE CURRENT ADDRESS.
	SHLD	MEMADR	;SAVE CURRENT ADDRESS.
	CALL	STRING	;GET THE OPCODE STRING.
	LXI	H,ATAB2	;OPCODE TABLE
	MVI	B,4	;HAS 4 BYTES/ENTRY
	CALL	STCOMP	;SCAN FOR THE GIVEN STRING.
	JC	ILLEG	;CARRY SET ON ERROR.
	STA	OPCODE	;SAVE OPCODE OFFSET.
	LXI	H,ATAB1+1	;FIND A CODE
ASM2:
	CMP	M	;WHICH MATCHES
	INX	H	;SO THAT
	JZ	ASM3	;WE CAN SEE
	INX	H	;IF THE
	INX	H	;THIRD BYTE IN
	JMP	ASM2	;THE TABLE
ASM3:
	MOV	A,M	;HAPPENS TO BE
	CPI	0	;NON-ZERO.
	JZ	ASM4	;I.E. NON-BLANK
	CALL	STRING	;OPERAND STRING REQUIRED.
	LXI	H,ATAB3	;LOOK FOR OPERAND STRING
	MVI	B,3	;IN 3 BYTE/ENTRY OPERAND
	CALL	STCOMP	;TABLE.
	JC	ILLEG
	CALL	BLANK	;SPACE UP
ASM4:
	MOV	E,A	;SAVE OPERAND CODE NUMBER
	LDA	OPCODE	;AND ALSO
	MOV	D,A	;OPCODE CODE NUMBER
	LXI	H,ATAB1+1	;FIND DOUBLE MATCH
	MVI	C,0	;IN THE OPCODE TABLE
ASM5:
	MOV	A,M	;GET TEST BYTE.
	CPI	0FFH	;SEE IF E.O.T.
	JZ	ILLEG	;I.E. -1 BYTE.
	CMP	D	;OPCODE MATCH?
	JNZ	ASM6
	INX	H
	MOV	A,M
	CMP	E	;OPERAND MATCH?
	JZ	ASM7
	DCX	H
ASM6:
	INX	H	;NO. BUMP
	INX	H	;PAST THIS
	INX	H	;ENTRY AND
	INR	C	;INCREMENT TABLE COUNTER.
	JMP	ASM5
ASM7:
	DCX	H	;GOT IT. GO BACK
	DCX	H	;TWO BYTES AND
	MOV	D,M	;GET BYTE COUNT.
	LHLD	MEMADR	;RETRIEVE CURRENT MEM ADDR.
	MOV	A,C	;STORE THE FIRST
	CALL	STORE	;BYTE VALUE
	MOV	A,D	;THEN LOOK AT
	SUI	2	;SIZE OF INSTRUCTION.
	JM	ASB1	;ONE BYTE
	LXI	H,MSGBK	;OR MULTIBYTE.
	CALL	MSG
	CALL	GHXW	;GET A NUMBER.
	JC	ILLEG
	ORA	A	;RESET BYTE FLAG.
	JZ	ASB2	;TWO BYTE.
ASB3:
	XCHG		;NUMBER NOW IN DE.
	LHLD	MEMADR	;GET MEMOR ADDR.
	INX	H	;PUT LO BYTE
	MOV	A,E	;INTO NEXT
	CALL	STORE	;ADDRESS.
	INX	H	;AND HI BYTE
	MOV	A,D	;INTO 3RD BYTE
	CALL	STORE	;ADDRESS.
	JMP	ASB1	;FINISH OFF.
ASB2:
	MOV	A,L	;PUT LO BYTE
	LHLD	MEMADR	;ONLY INTO
	INX	H	;INTO 2ND. BYTE
	CALL	STORE	;ADDRESS.
ASB1:
	INX	H	;BUMP TO NEXT ADDR.
	CALL	CRLF	;NEW LINE,
	JMP	ASM1	;START ALL OVER AGAIN.
;
;****	STRING INPUT ROUTINE.
;	ON RETURN, FIRST 4 BYTES IN 'BUFF' WITH
;	TRAILING BLANKS IF NECESSARY.
;
STRING:
	LXI	H,MSGBK
	CALL	MSG
	LXI	H,2020H	;PUT SPACES
	SHLD	BUFF	;INTO 4 BYTE
	SHLD	BUFF+2	;BUFFER.
	LXI	H,BUFF
	MVI	E,4
STR1:
	CALL	CHIN	;LOOK FOR
	CPI	CR	;<CR> TERMINATOR
	JZ	NEXT
	JMP	STR3
STR2:
	CALL	CHIN	;GET A CHARACTER.
STR3:
	CPI	CR	;LOOK FOR
	RZ		;<CR> OR
	CPI	' '	;SPACE AS
	RZ		;DELIMITER.
	DCR	E	;ONLY THE FIRST
	JM	STR2	;4 BYTES
	MOV	M,A	;ARE STORED.
	INX	H
	JMP	STR2
;
;****	STRING COMPARE ROUTINE.
;	ON INPUT, HL=START OF TEST TABLE
;		  B=BYTE COUNT PER ENTRY.
;	GOOD OUTPUT, CARRY CLI, ACC=OFFSET VALUE.
;	 BAD OUTPUT, CARRY SET, ACC=0FFH.
;
STCOMP:
	MVI	C,0	;CLEAR COUNTER.
STC0:
	PUSH	B	;SAVE COUNTER AND STRING SIZE.
	LXI	D,BUFF	;GET BUFFER START.
STC1:
	LDAX	D	;GET TEST BYTE.
	CMP	M	;SEE IF DIFFERENT.
	JNZ	STC2
	DCR	B	;OR IF ALL BYTES CHECK.
	JZ	STC5
	INX	D	;BUMP POINTERS
	INX	H	;AND THEN
	JMP	STC1	;TRY AGAIN.
STC2:
	MOV	A,M	;DIFFERENT. SAVE CURRENT BYTE.
STC3:
	DCR	B	;BUMP
	INX	H	;PAST
	JZ	STC4	;THIS
	JMP	STC3	;BYTE.
STC4:
	POP	B	;RETRIEVE COUNTERS,
	INR	C	;BUMP COUNTER,
	CPI	0FFH	;SEE IF E.O.T.
	JZ	STC6
	JMP	STC0	;TRY AGAIN.
STC5:
	POP	B	;FOUND A MATCH.
	MOV	A,C	;RETURN ENTRY
	ORA	A	;IN ACC WITH
	RET		;CARRY RESET.
STC6:
	STC		;ERROR RETURN
	RET		;SETS CARRY ONLY.
;
MSGBK:	DB	'    ',0FFH
;
;****	OPERATION CODE TABLE.
;	ARRANGED AS FOLLOWS, ACCORDING TO INSTRUCTION
;	FIRST BYTE VALUE (0-255):-
;
;	FIRST BYTE IS INSTRUCTION SIZE (BYTES)
;	NEXT 4 BYTES ARE OPCODE.
;	NEXT BYTE IS ATAB3 ENTRY NUMBER.
;
ATAB1:
	DB	1,0,0
	DB	3,1,1
	DB	1,2,1
	DB	1,6,1
	DB	1,8,1
	DB	1,9,1
	DB	2,30,1
	DB	1,10,0
	DB	1,88,0
	DB	1,14,1
	DB	1,3,1
	DB	1,7,1
	DB	1,8,2
	DB	1,9,2
	DB	2,30,2
	DB	1,11,0
	DB	1,88,0
	DB	3,1,3
	DB	1,2,3
	DB	1,6,3
	DB	1,8,3
	DB	1,9,3
	DB	2,30,3
	DB	1,12,0
	DB	1,88,0
	DB	1,14,3
	DB	1,3,3
	DB	1,7,3
	DB	1,8,4
	DB	1,9,4
	DB	2,30,4
	DB	1,13,0
	DB	1,85,0
	DB	3,1,5
	DB	3,4,0
	DB	1,6,5
	DB	1,8,5
	DB	1,9,5
	DB	2,30,5
	DB	1,15,0
	DB	1,88,0
	DB	1,14,5
	DB	3,5,0
	DB	1,7,5
	DB	1,8,6
	DB	1,9,6
	DB	2,30,6
	DB	1,16,0
	DB	1,86,0
	DB	3,1,9
	DB	3,17,0
	DB	1,6,9
	DB	1,8,7
	DB	1,9,7
	DB	2,30,7
	DB	1,19,0
	DB	1,88,0
	DB	1,14,9
	DB	3,18,0
	DB	1,7,9
	DB	1,8,8
	DB	1,9,8
	DB	2,30,8
	DB	1,20,0
	DB	1,21,11
	DB	1,21,12
	DB	1,21,13
	DB	1,21,14
	DB	1,21,15
	DB	1,21,16
	DB	1,21,17
	DB	1,21,18
	DB	1,21,19
	DB	1,21,20
	DB	1,21,21
	DB	1,21,22
	DB	1,21,23
	DB	1,21,24
	DB	1,21,25
	DB	1,21,26
	DB	1,21,27
	DB	1,21,28
	DB	1,21,29
	DB	1,21,30
	DB	1,21,31
	DB	1,21,32
	DB	1,21,33
	DB	1,21,34
	DB	1,21,35
	DB	1,21,36
	DB	1,21,37
	DB	1,21,38
	DB	1,21,39
	DB	1,21,40
	DB	1,21,41
	DB	1,21,42
	DB	1,21,43
	DB	1,21,44
	DB	1,21,45
	DB	1,21,46
	DB	1,21,47
	DB	1,21,48
	DB	1,21,49
	DB	1,21,50
	DB	1,21,51
	DB	1,21,52
	DB	1,21,53
	DB	1,21,54
	DB	1,21,55
	DB	1,21,56
	DB	1,21,57
	DB	1,21,58
	DB	1,21,59
	DB	1,21,60
	DB	1,21,61
	DB	1,21,62
	DB	1,21,63
	DB	1,21,64
	DB	1,76,0
	DB	1,21,66
	DB	1,21,67
	DB	1,21,68
	DB	1,21,69
	DB	1,21,70
	DB	1,21,71
	DB	1,21,72
	DB	1,21,73
	DB	1,21,74
	DB	1,22,1
	DB	1,22,2
	DB	1,22,3
	DB	1,22,4
	DB	1,22,5
	DB	1,22,6
	DB	1,22,7
	DB	1,22,8
	DB	1,23,1
	DB	1,23,2
	DB	1,23,3
	DB	1,23,4
	DB	1,23,5
	DB	1,23,6
	DB	1,23,7
	DB	1,23,8
	DB	1,24,1
	DB	1,24,2
	DB	1,24,3
	DB	1,24,4
	DB	1,24,5
	DB	1,24,6
	DB	1,24,7
	DB	1,24,8
	DB	1,25,1
	DB	1,25,2
	DB	1,25,3
	DB	1,25,4
	DB	1,25,5
	DB	1,25,6
	DB	1,25,7
	DB	1,25,8
	DB	1,26,1
	DB	1,26,2
	DB	1,26,3
	DB	1,26,4
	DB	1,26,5
	DB	1,26,6
	DB	1,26,7
	DB	1,26,8
	DB	1,27,1
	DB	1,27,2
	DB	1,27,3
	DB	1,27,4
	DB	1,27,5
	DB	1,27,6
	DB	1,27,7
	DB	1,27,8
	DB	1,28,1
	DB	1,28,2
	DB	1,28,3
	DB	1,28,4
	DB	1,28,5
	DB	1,28,6
	DB	1,28,7
	DB	1,28,8
	DB	1,29,1
	DB	1,29,2
	DB	1,29,3
	DB	1,29,4
	DB	1,29,5
	DB	1,29,6
	DB	1,29,7
	DB	1,29,8
	DB	1,42,0
	DB	1,66,1
	DB	3,43,0
	DB	3,40,0
	DB	3,44,0
	DB	1,67,1
	DB	2,31,0
	DB	1,77,0
	DB	1,45,0
	DB	1,39,0
	DB	3,46,0
	DB	1,88,0
	DB	3,47,0
	DB	3,41,0
	DB	2,32,0
	DB	1,78,0
	DB	1,48,0
	DB	1,66,3
	DB	3,49,0
	DB	2,72,0
	DB	3,50,0
	DB	1,67,3
	DB	2,33,0
	DB	1,79,0
	DB	1,51,0
	DB	1,88,0
	DB	3,52,0
	DB	2,73,0
	DB	3,53,0
	DB	1,88,0
	DB	2,34,0
	DB	1,80,0
	DB	1,54,0
	DB	1,66,5
	DB	3,55,0
	DB	1,68,0
	DB	3,56,0
	DB	1,67,5
	DB	2,35,0
	DB	1,81,0
	DB	1,57,0
	DB	1,69,0
	DB	3,58,0
	DB	1,70,0
	DB	3,59,0
	DB	1,88,0
	DB	2,36,0
	DB	1,82,0
	DB	1,60,0
	DB	1,66,10
	DB	3,61,0
	DB	1,74,0
	DB	3,62,0
	DB	1,67,10
	DB	2,37,0
	DB	1,83,0
	DB	1,63,0
	DB	1,71,0
	DB	3,64,0
	DB	1,75,0
	DB	3,65,0
	DB	1,88,0
	DB	2,38,0
	DB	1,84,0
;
;****	ATAB2 CONTAINS ALL OPCODES.
;
ATAB2:
	DB	'NOP '
	DB	'LXI '
	DB	'STAX'
	DB	'LDAX'
	DB	'SHLD'
	DB	'LHLD'
	DB	'INX '
	DB	'DCX '
	DB	'INR '
	DB	'DCR '
	DB	'RLC '
	DB	'RRC '
	DB	'RAL '
	DB	'RAR '
	DB	'DAD '
	DB	'DAA '
	DB	'CMA '
	DB	'STA '
	DB	'LDA '
	DB	'STC '
	DB	'CMC '
	DB	'MOV '
	DB	'ADD '
	DB	'ADC '
	DB	'SUB '
	DB	'SBB '
	DB	'ANA '
	DB	'XRA '
	DB	'ORA '
	DB	'CMP '
	DB	'MVI '
	DB	'ADI '
	DB	'ACI '
	DB	'SUI '
	DB	'SBI '
	DB	'ANI '
	DB	'XRI '
	DB	'ORI '
	DB	'CPI '
	DB	'RET '
	DB	'JMP '
	DB	'CALL'
	DB	'RNZ '
	DB	'JNZ '
	DB	'CNZ '
	DB	'RZ  '
	DB	'JZ  '
	DB	'CZ  '
	DB	'RNC '
	DB	'JNC '
	DB	'CNC '
	DB	'RC  '
	DB	'JC  '
	DB	'CC  '
	DB	'RPO '
	DB	'JPO '
	DB	'CPO '
	DB	'RPE '
	DB	'JPE '
	DB	'CPE '
	DB	'RP  '
	DB	'JP  '
	DB	'CP  '
	DB	'RM  '
	DB	'JM  '
	DB	'CM  '
	DB	'POP '
	DB	'PUSH'
	DB	'XTHL'
	DB	'PCHL'
	DB	'XCHG'
	DB	'SPHL'
	DB	'OUT '
	DB	'IN  '
	DB	'DI  '
	DB	'EI  '
	DB	'HLT '
	DB	'RST0'
	DB	'RST1'
	DB	'RST2'
	DB	'RST3'
	DB	'RST4'
	DB	'RST5'
	DB	'RST6'
	DB	'RST7'
	DB	'RIM '
	DB	'SIM '
AT2E:	DB	0FFH,0FFH,0FFH,0FFH
	DB	'--- '
;
;****	ATAB3 CONTAINS ALL POSSIBLE OPERANDS.
;
ATAB3:
	DB	'   '
	DB	'B  '
	DB	'C  '
	DB	'D  '
	DB	'E  '
	DB	'H  '
	DB	'L  '
	DB	'M  '
	DB	'A  '
	DB	'SP '
	DB	'PSW'
	DB	'B,B'
	DB	'B,C'
	DB	'B,D'
	DB	'B,E'
	DB	'B,H'
	DB	'B,L'
	DB	'B,M'
	DB	'B,A'
	DB	'C,B'
	DB	'C,C'
	DB	'C,D'
	DB	'C,E'
	DB	'C,H'
	DB	'C,L'
	DB	'C,M'
	DB	'C,A'
	DB	'D,B'
	DB	'D,C'
	DB	'D,D'
	DB	'D,E'
	DB	'D,H'
	DB	'D,L'
	DB	'D,M'
	DB	'D,A'
	DB	'E,B'
	DB	'E,C'
	DB	'E,D'
	DB	'E,E'
	DB	'E,H'
	DB	'E,L'
	DB	'E,M'
	DB	'E,A'
	DB	'H,B'
	DB	'H,C'
	DB	'H,D'
	DB	'H,E'
	DB	'H,H'
	DB	'H,L'
	DB	'H,M'
	DB	'H,A'
	DB	'L,B'
	DB	'L,C'
	DB	'L,D'
	DB	'L,E'
	DB	'L,H'
	DB	'L,L'
	DB	'L,M'
	DB	'L,A'
	DB	'M,B'
	DB	'M,C'
	DB	'M,D'
	DB	'M,E'
	DB	'M,H'
	DB	'M,L'
	DB	'M,M'
	DB	'M,A'
	DB	'A,B'
	DB	'A,C'
	DB	'A,D'
	DB	'A,E'
	DB	'A,H'
	DB	'A,L'
	DB	'A,M'
	DB	'A,A'
AT3E:	DB	0FFH,0FFH,0FFH
;
;	LOAD HEX OBJECT TAPE.
;
;	LOAD A HEX-BINARY TAPE AS PRODUCED BY THE 'P'
;	COMMAND.
;	MAY CONTAIN AN OFFSET VALUE, ALLOWING THE DATA TO
;	BE LOADED INTO A DIFFERENT LOCATION TO THAT SPECIFIED
;	BY THE LOAD ADDRESS.
;
;
SPORT	EQU	083H
DPORT	EQU	083H
SPKT	EQU	080H
;
	ORG	ROM+0F40H
;
LOADF:
	CALL	PUWB	;GET THE OFFSET, IF ANY.
	JNC	LD4F
	CPI	CR	;ERROR MAY ONLY BE <CR>
	JNZ	ILLEG
LD4F:
	CALL	CRLF	;NEW LINE PLEASE.
	PUSH	H	;SAVE BIAS ADR
LD5F:
	POP	H	;GET BIAS
	PUSH	H	;AND RESTORE
	CALL	RIXF	;GET INPUT
	MVI	B,':'	;WAIT FOR ':'
	SUB	B
	JNZ	LD5F	;TRY AGAIN
	MOV	D,A	;CLEAR CKSUM
	CALL	BYTEF	;GET LENGTH
	JZ	LD7F	;ZERO MEANS ALL DONE
	MOV	E,A	;SAVE LENGTH
	CALL	BYTEF
	PUSH	PSW	;SAVE HI ADR
	CALL	BYTEF
	POP	B	;FETCH MSBYTE
	MOV	C,A	;BC NOW HAS ADR
	PUSH	B	;SAVE IT
	XTHL		;INTO HL
	SHLD	BLKAD	;SAVE BLOCK ADR
	XTHL		;IN CASE OF ERROR
	POP	B
	DAD	B	;RESTORE AND ADD BIAS
	CALL	BYTEF	;RECORD TYPE INPUT
LD6F:
	CALL	BYTEF	;GET DATA BYTES
	CALL	STORE	;STORE
	INX	H
	DCR	E
	JNZ	LD6F	;GO ON.
	CALL	BYTEF	;GET CKSUM
	JZ	LD5F
LDERRF:
	LXI	H,M6	;CKSUM ERROR
	CALL	MSG
	LHLD	BLKAD	;ADR OF THIS BLOCK IS
	JMP	RXAR	;NOW GIVEN
LD7F:
	CALL	BYTEF	;MSB OF XEQAD
	MOV	H,A
	CALL	BYTEF
	MOV	L,A
	ORA	H
	JZ	NEXT	;MONITOR IF ADR=0
	PCHL		;OTHERWISE EXECUTE
;
RIXF:
	CALL	RIF
	JC	ILLEG	;ON ERROR, PRINT '??'
	ANI	7FH	;REMOVE PARITY
	RET
;
;	ROUTINE RIF
;	GETS A CHARACTER FROM THE FAST READER INPUT
;	I.E. IT STARTS THE READER, AND EXPECTS QUICK REPLY.
;
;
RIF:
	PUSH	B	;SAVE BC
	PUSH	D	;AND DE
RIF05:
	MVI	C,SPKT	;PRESET CURRENT STATUS
	LXI	D,0	;TIMEOUT COUNT.
RIF10:
	IN	SPORT	;GET STATUS.
	ANI	SPKT	;LOOK AT SPROCKET ONLY.
	MOV	B,A	;SAVE IT.
	MOV	A,C	;OLD STATUS
	CMA		;IS INVERTED
	ANA	B	;SO THAT + EDGE IS FOUND.
	MOV	C,B	;SAVE CURRENT STATUS.
	JNZ	RIF15	;NON-ZERO=GOT IT.
	DCX	D	;DROP T/O COUNT
	MOV	A,D	;SEE IF
	ORA	E	;COUNT IS
	JNZ	RIF10	;ZERO YET.
	STC
	POP	D
	POP	B
	RET
RIF15:
	IN	DPORT	;AND GET DATA.
	ORA	A	;CLEAR CARRY ONLY.
	POP	D
	POP	B	;RESTORE BC
	RET		;SIMPLY RETURN
;
BYTEF:
	PUSH	B	;SAVE BC
	CALL	RIXF	;READ ASCII
	CALL	CNVBN	;CONVERT TO HEX
	JC	LDERR	;ERROR DETECTOR.
	RLC		;SHIFT LEFT 4 BITS
	RLC
	RLC
	RLC
	MOV	B,A	;SAVE THEM A WHILE
	CALL	RIXF	;GET SECOND BYTE
	CALL	CNVBN	;CONVERT TO HEX
	JC	LDERR	;ERROR DETECTOR
	ORA	B	;OR IN THE SAVED NYBBLE
	MOV	C,A	;HOLD BYTE A WHILE.
	ADD	D	;ADD TO CKSUM
	MOV	D,A	;UPDATE CKSUM
	MOV	A,C	;RESTORE BYTE
	POP	B	;RESTORE BC
	RET
;
;
;	END OF ROM ROUTINES.
;
;
ENDROM	EQU	$
;
;
;	SYSTEM RAM AREA DEFINITION.
;
;
	ORG	RAM
;
;	STACK GOES IN HERE, PACKING DOWN FROM
;	STORAGE AREA.
;
	ORG	REGS
;
;	MONITOR REG. SAVE AREA.
;
SVPC:
SVPCL:	DS	1	;SAVED PC LOW
SVPCH:	DS	1	;SAVED PC HI
SVSP:
SVSPL:	DS	1	;SAVED SP LOW
SVSPH:	DS	1	;SAVED SP HI
SVHL:
SVL:	DS	1	;SAVED L
SVH:	DS	1	;SAVED H
SVE:	DS	1	;SAVED E
SVD:	DS	1	;SAVED D
SVC:	DS	1	;SAVED C
SVB:	DS	1	;SAVED B
SVF:	DS	1	;SAVED PSB, FLAGS
SVA:	DS	1	;SAVED ACC
;
;	SPECIALS USED BY MONITOR
;
BUFF:
TMPA:
GOGO:	DS	3
DSA:	DS	2	;START OF ROM DATA
OPCODE:
DFA:	DS	2	;END OF ROM DATA
MEMADR:
ROMADR:	DS	2	;PROM ADDRESS POINTER.
ECHO:	DS	1	;CHARACTER ECHO FLAG 0=NO ECHO
ADR:	DS	2	;EXAMINE/MODIFY ADR
XEQAD:	DS	2	;'X' EXECUTION ADR
BLKAD:	DS	2	;'L' BLOCK ADR
BPADD:	DS	2	;BREAKPOINT SAVE ADDRESS
BPDAT:	DS	6	;BREAKPOINT SAVE DATA
USERA:	DS	2	;USER FUNCTION VECTOR ADDRESS
;
;	USER VECTORS RST3-RST7
;
RST3:	DS	2
RST4:	DS	2
RST5:	DS	2
RST6:	DS	2
RST7:	DS	2
;
;
	END
