; *******************************************
; *               MONITOR                   *
; *  This program is based on the MONITOR   *
; *  program in 8080/Z80 Assembly Language  *
; *  Techniques for Improved Programing by  *
; *  Alan R. Miller. It has been expanded   *
; *  to include a set of new functions and  *
; *  an improved loader. This version is    *
; *  for North Star Horizon with a "window" *
; *  at EC00. See the file MONITOR.DOC for  *
; *  more information.                      *
; *                                         * 
; *  WRITTEN BY:     Gary M. Morin          *
; *  ORIGINATED:     November 14, 1982      *
; *  MODIFIED:       April 29, 1983         *
; *  VERSION         2.3                    *
; *******************************************
;
ORGIN	EQU	100H	;PROGRAM START
DEST	EQU	0F800H	;PROGRAM DESTINATION
HOME	EQU	DEST	;ABORT ADDRESS
BOOT	EQU	0H	;CP/M BOOT
STACK	EQU	DEST-60H
;
PTRTOG	EQU	DEST-1	;PRINTER TOGGLE FLAG
PORTN	EQU	STACK	;PORT AND BYTE
IBUFP	EQU	STACK+3	;BUFFER POINTER
IBUFC	EQU	IBUFP+2	;BUFFER COUNT
IBUFF	EQU	IBUFP+3	;INPUT BUFFER
;
CTRC	EQU	3	;^C [BOOT CPM]
CTRH	EQU	8	;^H
TAB	EQU	9	;^I
LF	EQU	10	;LF [LINE FEED]
CR	EQU	13	;CR [CARRIAGE RETURN]
CTRP	EQU	16	;^P [PRINTER TOGGLE]
CTRQ	EQU	17	;^Q [RESTRT OUTPUT]
CTRS	EQU	19	;^S [INTERUPT OUTPUT]
CTRU	EQU	21	;^U [ERASE LINE]
CTRX	EQU	24	;^X [ABORT]
ESC	EQU	27	;ESCAPE
DEL	EQU	127	;RUBOUT
BACKSP	EQU	CTRH	;BACKSP CHAR
APOS	EQU	(39-'0') AND 0FFH
INC	EQU	0DBH	;IN OP CODE
OUTC	EQU	0D3H	;OUT OP CODE
RETC	EQU	0C9H	;RET OP CODE
;
;================================================
;             North Star Equates
;================================================
;
CSTAT	EQU	3	;CONSOLE STATUS
CDATA	EQU	2	;CONSOLE DATA
CSTATO	EQU	3	;CONSOLE OUTPUT STATUS
CDATAO	EQU	2	;CONSOLE OUTPUT DATA
PSTATO	EQU	5	;PRINTER STATUS
PDATAO	EQU	4	;PRINTER DATA
INMSK	EQU	2	;INPUT MASK
OMSK	EQU	1	;OUTPUT MASK
;
;================================================
;               Start of Code
;================================================
;
	ORG	ORGIN
;
;--> Save the old stack
;
	LXI	H,0	;zero HL
	DAD	SP	;SP to HL
	SHLD	OLDSTK	;save stack
;
;--> Locate important addresses
;
	LXI	B,SOUEND-BEGIN+1
	LXI	H,PROEND
	LXI	D,SOUEND-1
;
;--> Move the code
;
MVLP:	LDAX	D
	DCX	H
	MOV	M,A
	DCX	D
	DCX	B
	MOV	A,B	;ZERO?
	ORA	C	;LOW ORDER BYTE
	JNZ	MVLP
;
;--> JUMP TO MONITOR NOW IN PLACE
;
	JMP	START
;
BEGIN:	NOP
;
;**********************************************
;   BEGINING OF THE ACTUAL  PROGRAM
;
;                  CAUTION
;  ANY LABELS ADDED AFTER THIS POINT MUST BE
;  OF THE FORM  $+OFFSET
;**********************************************
;
OFFSET	EQU	DEST-BEGIN-1
;
START	EQU	$+OFFSET
	JMP	COLD	;COLD START
;
RESTRT	EQU	$+OFFSET
	JMP	WARM	;WARM START
;
;
;--> CONSOLE STATUS ROUTINE
;
INSTAT	EQU	$+OFFSET
	IN	CSTAT	;GET STATUS BYTE
	ANI	INMSK	;READY?
	RET
;
;--> CONSOLE INPUT ROUTINE
;
INPUTT	EQU	$+OFFSET
	CALL	INSTAT	;CHECK STATUS
	JZ	INPUTT	;NOT READY
INPUT2	EQU	$+OFFSET
	IN	CDATA	;GET BYTE
	ANI	DEL
	CPI	CTRX	;ABORT?
	JZ	HOME	;YES
	CPI	CTRC	;CANCEL?
	JZ	BOOT	;YES
	CPI	CTRP	;TOGGLE PRINTER?
	RNZ		;NO
	LDA	PTRTOG	;CHECK FLAG
	CMA		;INVERT
	STA	PTRTOG	;SAVE
	JMP	INPUTT	;GET NEXT
;
;
;--> CONSOLE OUTPUT ROUTINE
;
OUTT	EQU	$+OFFSET
	PUSH	PSW
OUT2	EQU	$+OFFSET
	CALL	INSTAT	;INPUT?
	JZ	OUT4	;NO
	CALL	INPUT2	;GET INPUT
	CPI	CTRS	;FREEZE?
	JNZ	OUT2	;NO
;
;--> FREEZE OUTPUT UNTIL ^Q OR ^X
;
OUT3	EQU	$+OFFSET
	CALL	INPUTT	;INPUT?
;
OUT4	EQU	$+OFFSET
	LDA	PTRTOG	;PRINTER TOGGLE?
	ORA	A
	JNZ	OUT5	;YES
	IN	CSTATO	;CHECK STATUS
	ANI	OMSK
	JZ	OUT2	;NOT READY
	POP	PSW
	OUT	CDATAO	;SEND DATA
	RET
OUT5	EQU	$+OFFSET
	IN	PSTATO	;CHECK PTR STATUS
	ANI	OMSK	;READY?
	JZ	OUT2	;NOT READY
	POP	PSW
	OUT	CDATAO	;SEND TO CONSOLE
	OUT	PDATAO	;SEND TO PRINTER
	RET
;
;--> Cold start routine
;
COLD	EQU	$+OFFSET
	LXI	SP,STACK
	LXI	D,STMSG	;MESSAGE
	CALL	SENDM	;SENDIT
	MVI	A,0	;SET PTRTOG FLAG
	STA	PTRTOG	;STORE IT
;
;--> Warm start routine
;
WARM	EQU	$+OFFSET
	LXI	H,WARM	;PUSH WARM ADDR
	PUSH	H	; ON STACK
	CALL	CRLF	;NEW LINE
	CALL	INPLN	;CONSOLE LINE
	CALL	GETCH	;GET CHARACTER
;
;--> MAIN COMMAND PROCESSOR
;    AFTER ALAN R. MILLER
;
	SUI	'A'	;CONVERT OFFSET
	JC	ERROR	; < A
	CPI	'Z'-'A'+1
	JNC	ERROR	; > Z
	ADD	A	;DOUBLE
	LXI	H,TABLE	;START
	MVI	D,0
	MOV	E,A	;OFFSET
	DAD	D	;ADD TO TABLE
	MOV	E,M	;LOW BYTE
	INX	H
	MOV	D,M	;HIGH BYTE
	XCHG		;INTO H,L
	PCHL		;GO THERE
;
;--> COMMAND TABLE
;
TABLE	EQU	$+OFFSET
	DW	ASCII	;A, ASCII
	DW	RETCPM	;B, BACK TO CPM
	DW	CALLS	;C, CALL SUBROUTINE
	DW	DUMP	;D, DUMP
	DW	ERROR2	;E
	DW	FILL	;F, FILL
	DW	GO	;G, GO
	DW	HMATH	;H, HEX MATH
	DW	IPORT	;I, PORT INPUT
	DW	ERROR2	;J
	DW	ERROR2	;K
	DW	LOAD	;L, LOAD
	DW	MOVE	;M, MOVE
	DW	ERROR2	;N
	DW	OPORT	;O, PORT OUTPUT
	DW	TOGLP	;P, TOGGLE PRINTER
	DW	ERROR2	;Q
	DW	REPL	;R, REPLACE
	DW	SEARCH	;S, SEARCH
	DW	HELP	;T, COMMAND TABLE
	DW	ERROR2	;U
	DW	VERM	;V, VERIFY MEMORY
	DW	ERROR2	;W
	DW	REGS	;X, STACK POINTER
	DW	ERROR2	;Y
	DW	ERROR2	;Z
;
;--> INPUT A COMMAD LINE PLACE IT IN THE BUFFER
;
INPLN	EQU	$+OFFSET
	MVI	A,'-'	;PROMPT
	CALL	OUTT
	MVI	A,'>'	;PROMPT
	CALL	OUTT
;
INPL2	EQU	$+OFFSET
	LXI	H,IBUFF	;BUFFER ADDRESS
	SHLD	IBUFP	;SAVE POINTER
	MVI	C,0	;COUNT
;
INPLI	EQU	$+OFFSET
	CALL	INPUTT	;CONSOLE CHAR
	CPI	' '	;CONTROL?
	JC	INPLC	;YES
	CPI	DEL	;DELETE
	JZ	INPLB	;YES
	CPI	'Z'+1	;UPPER CASE?
	JC	INPL3	;YES
	ANI	5FH	;MAKE UPPER CASE
;
INPL3	EQU	$+OFFSET
	MOV	M,A	;INTO BUFFER
	MVI	A,32	;BUFFER SIZE
	CMP	C	;FULL?
	JZ	INPLI	;YES, LOOP
	MOV	A,M	;GET CHAR
	INX	H	;INCREMENT POINTER
	INR	C	;AND COUNT
;
INPLE	EQU	$+OFFSET
	CALL	OUTT	;SHOW CHAR
	JMP	INPLI	;NEXT CHAR
;
;--> PROCESS CONTROL CHARACTER
;
INPLC	EQU	$+OFFSET
	CPI	CTRH	;^H?
	JZ	INPLB	;YES
	CPI	CR	;RETURN
	JNZ	INPLI	;NO, IGNORE
;
;--> END OF INPUT LINE
;
	MOV	A,C	;COUNT
	STA	IBUFC	;SAVE
;
;--> CARRIAGE-RETURN, LINE FEED ROUTIN
;
CRLF	EQU	$+OFFSET
	MVI	A,CR
	CALL	OUTT	;SEND CR
	MVI	A,LF
	JMP	OUTT	;SEND LF
;
;--> DELETE PRIOR CHARACTER IF ANY
;
INPLB	EQU	$+OFFSET
	MOV	A,C	;CHARACTER COUNT
	ORA	A	;ZERO?
	JZ	INPLI	;YES
	DCX	H	;BACK POINTER
	DCR	C	;AND COUNT
	MVI	A,BACKSP	;CHARACTER
	JMP	INPLE	;SEND
;
;--> GET A CHARACTER FROM CONSOLE BUFFER
;    SET CARRY IF EMPTY
;
GETCH	EQU	$+OFFSET
	PUSH	H	;SAVE REGS
	LHLD	IBUFP	;GET POINTER
	LDA	IBUFC	;AND COUNT
	SUI	1	;DECREMENT W/CARRY
	JC	GETC4	;NO MORE CHARACTERS
	STA	IBUFC	;SAVE NEW COUNT
	MOV	A,M	;GET CHARACTER
	INX	H	;INCREMENT POINTER
	SHLD	IBUFP	;AND SAVE
;
GETC4	EQU	$+OFFSET
	POP	H	;RESTORE REGS
	RET
;
;--> SEND ASCII MESSAGE UNTIL BINARY ZERO
;    IS FOUND. POINTER IS D,E
;
SENDM	EQU	$+OFFSET
	LDAX	D	;GET BYTE
	ORA	A	;ZERO?
	RZ		;YES, DONE
	CALL	OUTT	;SEND IT
	INX	D	;POINTER
	JMP	SENDM	;NEXT
;
;--> DUMP MEMORY IN HEXADECIMAL AND ASCII
;
DUMP	EQU	$+OFFSET
	CALL	RDHLDE	;RANGE
;
DUMP2	EQU	$+OFFSET
	CALL	CRHL	;NEW LINE
;
DUMP3	EQU	$+OFFSET
	MOV	C,M	;GET BYTE
	CALL	OUTHX	;PRINT
	INX	H	;POINTER
	MOV	A,L	;MOVE LOW ORDER BYTE
	ANI	0FH	;LINE END
	JZ	DUMP4	;YES, ASCII
	ANI	3	;SPACE
	CZ	OUTSP	;4 BYTES
	JMP	DUMP3	;NEXT HEX
;
DUMP4	EQU	$+OFFSET
	CALL	OUTSP
	PUSH	D
	LXI	D,-10H	;RESET LINE
	DAD	D
	POP	D
;
DUMP5	EQU	$+OFFSET
	CALL	PASCI	;ASCII DUMP
	CALL	TSTOP	;DONE
	MOV	A,L	;NO
	ANI	0FH	;LINE END
	JNZ	DUMP5	;NO
	JMP	DUMP2
;
;--> DISPLAY MEMORY BYTE IN ASCII IF
;    POSSIBLE, OTHERWISE GIVE DECIMAL PNT
;
;
PASCI	EQU	$+OFFSET
	MOV	A,M	;GET BYTE
	CPI	DEL	;HIT BIT ON?
	JNC	PASC2	;YES
	CPI	' '	;CONTROL CHARACTER?
	JNC	PASC3	;NO
;
PASC2	EQU	$+OFFSET
	MVI	A,'.'	;CHANGE TO DOT
;
PASC3	EQU	$+OFFSET
	JMP	OUTT	;SEND
;
;--> GET H,L AND D,E FROM CONSOLE
;    CHECK THAT D,E IS LARGER
;
RDHLDE	EQU	$+OFFSET
	CALL	HHLDE
;
RDHLD2	EQU	$+OFFSET
	MOV	A,E
	SUB	L	;E - L
	MOV	A,D
	SBB	H	;D - H
	JC	ERROR1	;H,L BIGGER
	RET
;
;--> INPUT H,L AND D,E. SEE THAT 2
;    ADDRESSES ARE ENTERED
;
HHLDE	EQU	$+OFFSET
	CALL	READHL	;H,L
	JC	ERROR1	;ONLY 1 ADDR
	XCHG		;SAVE IN D,E
	CALL	READHL	;D,E
	XCHG		;PUT BACK
	RET
;
;--> INPUT H,L FROM CONSOLE
;
READHL	EQU	$+OFFSET
	PUSH	D
	PUSH	B	;SAVE REGS
	LXI	H,0	;CLEAR
;
RDHL2	EQU	$+OFFSET
	CALL	GETCH	;GET CHARACTER
	JC	RDHL5	;LINE END
	CALL	NIB	;TO BINARY
	JC	RDHL4	;NOT HEX
	DAD	H	;TIMES 2
	DAD	H	;TIMES 4
	DAD	H	;TIMES 8
	DAD	H	;TIMES 16
	ORA	L	;ADD NEW CHARACTER
	MOV	L,A
	JMP	RDHL2	;NEXT
;
;--> CHECK FOR BLANK AT END
;
RDHL4	EQU	$+OFFSET
	CPI	APOS	;APOSTROPHE
	JZ	RDHL5	;ASCII INPUT
	CPI	(' '-'0') AND 0FFH
	JNZ	ERROR	;NO
;
RDHL5	EQU	$+OFFSET
	POP	B
	POP	D	;RESTORE
	RET
;
;--> CONVERT ASCII CHARACTERS TO BINARY
;
NIB	EQU	$+OFFSET
	SUI	'0'	;ASCII BIAS
	RC		; < 0
	CPI	'F'-'0'+1
	CMC		;INVERT
	RC		;ERROR, > F
	CPI	10
	CMC		;INVERT
	RNC		;NUMBER 0-9
	SUI	'A'-'9'-1
	CPI	10	;SKIP : TO
	RET		;LETTER A-F
;

;
;--> START NEW LINE, GIVE ADDRESS
;
CRHL	EQU	$+OFFSET
	CALL	CRLF	;NEW LINE
;
;  PRINT H,L IN HEX
;
OUTHL	EQU	$+OFFSET
	MOV	C,H
	CALL	OUTHX	;H
;
OUTLL	EQU	$+OFFSET
	MOV	C,L
;
;  OUTPUT HEX BYTE FROM C AND A SPACE
;
OUTHEX	EQU	$+OFFSET
	CALL	OUTHX
;
;  OUTPUT A SPACE
;
OUTSP	EQU	$+OFFSET
	MVI	A,' '
	JMP	OUTT
;
;--> OUTPUT A HEX BYTE FROM C
;    BINARY TO ASCII HEX CONVERSION
;
OUTHX	EQU	$+OFFSET
	MOV	A,C
	RAR		;ROTATE
	RAR		;FOUR
	RAR		;BITS TO
	RAR		;RIGHT
	CALL	HEX1	;UPPER CHARACTER
	MOV	A,C	;LOWER CHARACTER
;
HEX1	EQU	$+OFFSET
	ANI	0FH	;TAKE 4 BITS
	ADI	90H
	DAA		;DAA TRICK
	ACI	40H
	DAA
	JMP	OUTT
;
;--> CHECK FOR END, H,L MINUS D,E
;    INCREMENT H,L
;
TSTOP	EQU	$+OFFSET
	INX	H
	MOV	A,E
	SUB	L	; E - L
	MOV	A,D
	SBB	H	; D - H
	RNC		;NOT DONE
	POP	H	;RAISE STACK
	RET
;
;--> ERROR ROUTINES
;
ERROR	EQU	$+OFFSET
	MVI	A,'?'
	CALL	OUTT	;OUTPUT IT
	JMP	RESTRT	;TRY AGAIN
;
ERROR1	EQU	$+OFFSET
	LXI	D,E1MSG	;ERROR MESSAGE ADDR
	CALL	SENDM
	JMP	RESTRT
;
ERROR2	EQU	$+OFFSET
	LXI	D,E2MSG	;ERROR MSG ADDR
	CALL	SENDM
	JMP	RESTRT
;
;--> BACK TO CPM GENTLY
;
RETCPM	EQU	$+OFFSET
	LHLD	OLDSTK
	SPHL
	RET
;
;--> HELP ROUTINE
;
HELP	EQU	$+OFFSET
	LXI	D,INSTR	;INSTRUCTIONS ADDRESS
	CALL	SENDM
	JMP	RESTRT
;
;--> TOGGLE PRINTER ON
;
TOGLP	EQU	$+OFFSET
	LDA	PTRTOG
	CMA
	STA	PTRTOG
	JMP	RESTRT
;
;--> ROUTINES TO CALL A SUBROUTINE AND TO
;    'GO' TO ANYPLACE IN THE MEMORY    
;
GO	EQU	$+OFFSET
	POP	H	;RAISE STACK
;
CALLS	EQU	$+OFFSET
	CALL	READHL	;GET ADDRESS
	PCHL		;GO THERE
;
;--> LOAD HEX OR ASCII CHARACTER INTO MEMORY
;    APOSTROPHE PERCEEDS ASCII CHAR
;    CARRIAGE RETRUN PASSES OVER LOCATION
;
LOAD	EQU	$+OFFSET
	CALL	READHL	;ADDRESS
;
LOAD2	EQU	$+OFFSET
	CALL	OUTHL	;PRINT IT
	CALL	PASCI	;ASCII
	CALL	OUTSP
	MOV	C,M	;ORIG BYTE
	CALL	OUTHEX	;HEX
	PUSH	H	;SAVE PNTR
	CALL	INPL2	;INPUT
	CALL	READHL	; BYTE
	MOV	B,L	; TO B
	POP	H
	CPI	APOS
	JZ	LOAD6	;ASCII INPUT
	MOV	A,C	;HOW MANY
	ORA	A	;NONE?
	JZ	LOAD3	;YES
;
LOAD4	EQU	$+OFFSET
	CALL	CHEKM	;INTO MEMORY
;
LOAD3	EQU	$+OFFSET
	INX	H	;POINTER
	JMP	LOAD2
;
;--> LOAD ASCII CHARACTER
;
LOAD6	EQU	$+OFFSET
	CALL	GETCH
	MOV	B,A
	JMP	LOAD4
;
;--> COPY BYTE FROM B TO MEMORY
;    AND SEE THAT IT GOT THERE
;
CHEKM	EQU	$+OFFSET
	MOV	M,B	;PUT IN MEM
	MOV	A,M	;GET BACK
	CMP	B	;SAME?
	RZ		;YES
;
ERRP	EQU	$+OFFSET
	POP	PSW	;RAISE STACK
;
ERRB	EQU	$+OFFSET
	MVI	A,'B'	;BAD
;
ERR2	EQU	$+OFFSET
	CALL	OUTT
	CALL	OUTSP
	JMP	OUTHL	;POINTER
;
;--> DISPLAY STACK POINTER REGISTER
;
REGS	EQU	$+OFFSET
	LXI	H,0
	DAD	SP
	JMP	OUTHL
;
;--> FILL A PORTION OF MEMORY
;
FILL	EQU	$+OFFSET
	CALL	HLDEBC	;RANGE BYTE
	CPI	APOS	;APOSTROPHE
	JZ	FILL4	;YES, ASCII
	MOV	B,C
;
FILL2	EQU	$+OFFSET
	MOV	A,H	;FILL BYTE
	CPI	STACK SHR 8 ;TO FAR
	JNC	ERROR	;YES
;
FILL3	EQU	$+OFFSET
	CALL	CHEKM	;PUT, CHECK
	CALL	TSTOP	;DONE?
	JMP	FILL2	;NEXT
;
FILL4	EQU	$+OFFSET
	CALL	GETCH	;ASCII CHAR
	MOV	B,A
	JMP	FILL3
;
;--> GET H,L D,E AND B,C
;
HLDEBC	EQU	$+OFFSET
	CALL	HLDECK	;RANGE
	JC	ERROR	;NO BYTE
	PUSH	H
	CALL	READHL	;3RD INPUT
	MOV	B,H	;MOVE TO
	MOV	C,L	; B,C
	POP	H
	RET
;
;--> GET 2 ADDRESSES, CHECK THAT
;    ADDITIONAL DATA IS INCLUDED
;
HLDECK	EQU	$+OFFSET
	CALL	HHLDE	;2ND ADDR
	JC	ERROR1	;THATS ALL
	JMP	RDHLD2	;CHECK
;
;
;--> MOVE A BLOCK OF MEMORY  H,L-D,E TO B,C
;
MOVE	EQU	$+OFFSET
	CALL	HLDEBC	;3 ADDR
;
MOVDN	EQU	$+OFFSET
	CALL	MOVIN	;MOVE CHECK
	CALL	TSTOP	;DONE?
	INX	B	;NO
	JMP	MOVDN
;
MOVIN	EQU	$+OFFSET
	MOV	A,M	;BYTE
	STAX	B	;NEW LOCATION
	LDAX	B	;CHECK
	CMP	M	;IS IT THERE
	RZ		;YES
	MOV	H,B	;ERROR
	MOV	L,C	;INTO H,L
	JMP	ERRP	;SHOW BAD
;
;--> SEARCH FOR 1 OR 2 BYTES OVER THE
;    RANGE H,L D,E. BYTES ARE IN B,C
;    B HAS CARRIAGE RETURN IF ONLY ONE
;    BYTE. PUT SPACE BETWEEN BYTES IF TWO
;    FORMAT: [START] [STOP] [BYTE1] [BYTE2]
;
SEARCH	EQU	$+OFFSET
	CALL	HLDEBC	;RANGE, 1ST BYTE
;
SEAR2	EQU	$+OFFSET
	MVI	B,CR	;SET FOR 1 BYTE
	JC	SEAR3	;ONLY ONE
	PUSH	H
	CALL	READHL	;2ND BYTE
	MOV	B,L	;INTO C
	POP	H
;
SEAR3	EQU	$+OFFSET
	MOV	A,M	;GET BYTE
	CMP	C	;MATCH
	JNZ	SEAR4	;NO
	INX	H	;YES
	MOV	A,B	;ONLY ONE
	CPI	CR
	JZ	SEAR5	;YES
;
;--> FOUND FIRST MATCH, CHECK FOR SECOND
;
	MOV	A,M	;NEXT BYTE
	CMP	B	;MATCH
	JNZ	SEAR4	;NO
;
SEAR5	EQU	$+OFFSET
	DCX	H	;A MATCH
	PUSH	B
	CALL	CRHL	;SHOW ADDRESS
	POP 	B
;
SEAR4	EQU	$+OFFSET
	CALL	TSTOP	;DONE?
	JMP	SEAR3	;NO
;
;--> ASCII SUB-COMMAND PROCESSOR
;
ASCII	EQU	$+OFFSET
	CALL	GETCH	;NEXT CHAR
	CPI	'D'	;DISPLAY
	JZ	ADUMP
	CPI	'S'	;SEARCH
	JZ	ASCS
	CPI	'L'	;LOAD
	JNZ	ERROR
;
;--> LOAD ASCII CHARACTERS INTO MEMORY
;    QUIT ON CONTROL-X
;
	CALL	READHL	;ADDRESS
	CALL	OUTHL	;PRINT IT
;
ALOD2	EQU	$+OFFSET
	CALL	INPUTT	;NEXT CHARACTER
	CALL	OUTT	;PRINT IT
	MOV	B,A	;SAVE
	CALL	CHEKM	;INTO MEMORY
	INX	H	;POINTER
	MOV	A,L
	ANI	7FH	;LINE END?
	JNZ	ALOD2	;NO
	CALL	CRHL	;NEW LINE
	JMP	ALOD2
;
;--> DISPLAY MEMORY IN ASCII.
;
ADUMP	EQU	$+OFFSET
	CALL	RDHLDE	;RANGE
;
ADMP2	EQU	$+OFFSET
	MOV	A,M	;GET BYTE
	CPI	DEL	;HIGH BIT ON?
	JNC	ADMP4	;YES
	CPI	' '	;CONTROL?
	JNC	ADMP3	;NO
	CPI	CR	;CARRIAGE RETURN
	JZ	ADMP3	;YES, OK
	CPI	LF	;LINE FEED
	JZ	ADMP3	;YES, OK
	CPI	TAB
	JNZ	ADMP4	;SKIP OTHER
	MVI	A,' '	;SPACE FOR TAB
;
ADMP3	EQU	$+OFFSET
	CALL	OUTT	;SEND
;
ADMP4	EQU	$+OFFSET
	CALL	TSTOP	;DONE?
	JMP	ADMP2	;NO
;
;--> SEARCH FOR 1 OR 2 ASCII CHARACTERS
;    NO SPACE BETWEEN ASCII CHARACTERS
;    FORMAT [START] [STOP] 1 OR 2 ASCII CHARACTERS
;
ASCS	EQU	$+OFFSET
	CALL	RDHLDE	;RANGE
	CALL	GETCH	;FIRST CHAR
	MOV	C,A
	CALL	GETCH	;2ND OR CR
	JC	SEAR2	;ONLY ONE CHARACTER
	MOV	B,A	;2ND
	JMP	SEAR3
;
;--> INPUT FROM PORT
;
IPORT	EQU	$+OFFSET
	CALL	READHL	;PORT
	MOV	C,L	;PORT TO C
	MVI	A,INC	;IN CODE
	CALL	PUTIO	;SETUP INPUT
	MOV	L,A
	CALL	OUTLL	;HEX VALUE
;
;--> PRINT L REGISTER IN BINARY (8080 VERSION)
;
BITS	EQU	$+OFFSET
	MVI	B,8	;8 BITS
;
BIT2	EQU	$+OFFSET
	MOV	A,L
	ADD	A	;SHIFT LEFT
	MOV	L,A
	MVI	A,'0'/2	;HALF OF 0
	ADC	A	;DOUBLE+CARRY
	CALL	OUTT	;PRINT BIT
	DCR	B
	JNZ	BIT2	;8 TIMES
	RET
;
;--> OUTPUT BYTE FROM DESIGNATED PORT 
;    FORMAT: O,[PORT],[BYTE]
;
OPORT	EQU	$+OFFSET
	CALL	READHL	;PORT
	MOV	C,L
	CALL	READHL	;DATA
	MVI	A,OUTC	;OUT OPCODE
;
;--> I/O ROUTINE AFTER ALAN R. MILLER IN
;    8080/Z80 ASSEMBLY LANGUAGE TECHNIQUES
;    FOR IMPROVED PROGRAMING
;
PUTIO	EQU	$+OFFSET
	STA	PORTN	;IN OR OUT CODE
	MOV	A,C	;PORT NUMBER
	STA	PORTN+1
	MVI	A,RETC	;RET OPCODE
	STA	PORTN+2
	MOV	A,L	;OUTPUT BYTE
	JMP	PORTN	;EXECUTE
;
;--> HEXADECIMAL MATH,
; 
HMATH	EQU	$+OFFSET
	CALL	HHLDE	;TWO NUMBERS
	PUSH	H	;SAVE HL
	DAD	D
	CALL	OUTHL	;PRINT IT
	POP	H
	MOV	A,L
	SUB	E	;LOW BYTES
	MOV	L,A
	MOV	A,H
	SBB	D
	MOV	H,A	;HIGH BYTES
	JMP	OUTHL
;
;--> REPLACE ONE HEX BYTE WITH ANOTHER
;    OVER A GIVEN RANGE
;    FORMAT: R[START] [STOP] [ORIG] [NEW]
;
REPL	EQU	$+OFFSET
	CALL	HLDEBC	;RANGE, 1ST BYTE
	JC	ERROR	;NO 2ND
	PUSH	H
	CALL	READHL	;2ND BYTE
	MOV	C,L	;INTO C
	POP	H
;
REPL2	EQU	$+OFFSET
	MOV	A,M	;FETCH BYTE
	CMP	B	;A MATCH?
	JNZ	REPL3	;NO
	MOV	M,C	;SUBSTITUTE
	MOV	A,C
	CMP	M	;SAME?
	JNZ	ERRB	;NO, BAD
;
REPL3	EQU	$+OFFSET
	CALL	TSTOP	;DONE?
	JMP	REPL2
;
;--> COMPARE TWO BLOCKS OF MEMORY
;    FORMAT: V[1ST BEG.] [1ST END] [2ND BEG]
;
VERM	EQU	$+OFFSET
	CALL	HLDEBC	;THREE ADDRESSES
;
VERM2	EQU	$+OFFSET
	LDAX	B	;FETCH BYTE
	CMP	M	;SAME AS OTHER
	JZ	VERM3	;YES
	PUSH	H	;DIFFERENT
	PUSH	B
	CALL	CRHL	;PRINT 1ST POINTER
	MOV	C,M	;FIRST BYTE
	CALL	OUTHEX	;PRINT IT
	MVI	A,':'
	CALL	OUTT
	POP	H
	CALL	OUTHL	;SECOND POINTER
	MOV	C,M	;2ND BYTE
	CALL	OUTHX	;PRINT IT
	MOV	C,L	;RESTORE C
	MOV	B,H	;AND B
	POP	H	;AND H,L
;
VERM3	EQU	$+OFFSET
	CALL	TSTOP	;DONE?
	INX	B	;SECOND POINTER
	JMP	VERM2
;
;================================================
;                 Messages
;================================================
;
STMSG	EQU	$+OFFSET
	DB	CR,LF
	DB	'NORTH * STAR  Monitor   Version  2.4',CR,LF
	DB	CR,LF
	DB	0
;
INSTR	EQU	$+OFFSET
	DB	CR,LF
	DB	'ASCII LOAD, DUMP -->A[ L  D  S ] [1ST ADR] [2ND ADR] ',CR,LF
        DB      '      or SEARCH',CR,LF
	DB	'BACK GENTLY      -->B',CR,LF
	DB	'CALL SUBROUTINE  -->C[ADR]',CR,LF
	DB	'DUMP MEMORY      -->D[1ST ADR] [2ND ADR]',CR,LF
	DB	'FILL MEMORY      -->F[1ST ADR] [2ND ADR] [HEX BYTE]',CR,LF
	DB	'                 -->F[1ST ADR] [2ND ADR] ''[ASCII]',CR,LF
	DB	'GO ANYWHERE      -->G[ADR]',CR,LF
	DB	'HEX MATH + -     -->H[1ST HEX] [2ND HEX]',CR,LF
	DB	'INPUT FROM PORT  -->I[PORT NUMBER]',CR,LF
	DB	'LOAD MEMORY      -->L[START ADR]',CR,LF
	DB	'                   ADR BYTE [NEW BYTE]   ^X HALT',CR,LF
	DB	'MOVE MEMORY      -->M[1ST ADR] [2ND ADR] [NEW START]',CR,LF
	DB	'OUTPUT TO PORT   -->O[PORT NUMBER] [BYTE]',CR,LF
	DB	'PRINTER TOGGLE   -->P',CR,LF
	DB	'REPLACE MEMORY   -->R[1ST ADR] [2ND ADR] [TARGET] [BYTE]'
	DB	CR,LF
	DB	'SEARCH FOR BYTE  -->S[1ST ADR] [2ND ADR] [BYTE1] [BYTE2]'
	DB	CR,LF
	DB	'COMMAND TABLE    -->T',CR,LF
	DB	'COMPARE BLOCKS   -->V[1ST ADR] [2ND ADR] [1ST ADR BLOCK2]'
	DB	CR,LF
	DB	'DISP STACK POINT -->X',CR,LF
	DB	CR,LF
	DB	0
;
E1MSG	EQU	$+OFFSET
	DB	'ADDRESS RANGE ERROR',CR,LF
	DB	0
;
E2MSG	EQU	$+OFFSET
	DB	'COMMAND ERROR',CR,LF
	DB	0
;
;================================================
;             End of Program
;================================================
;
PROEND	EQU	$+OFFSET
SOUEND:	NOP
;
OLDSTK	EQU	$+OFFSET
	DS	2
;
	END
