Cromemco-Z80-Monitor-Source-198002

;
;
STAT:	EQU	0			;STATUS PORT, DEVICE A
DATA:	EQU	1			;DATA PORT, DEVICE A
ACMNDP:	EQU	2			;COMMAND PORT, DEV. A
ABAUDP:	EQU	0			;BAUD PORT, DEVICE A
APARLP:	EQU	4			;PARALLEL PORT, DEV. A
BCMNDP:	EQU	52H			;COMMAND PORT, DEV. B
BPARLP:	EQU	54H			;PARALLEL PORT, DEV. B
DAV:	EQU	40H			;DATA-AVLAILABLE MASK
TBE:	EQU	8OH			;XMITTER-BUF-EMPTY MASK
;
NBRKPT:	EQU	5			;ALLOW ROOM FOR
BPSTOR:	EQU	NBRKPT*4+2		;BREAKPOINT STORAGE
TEMPS:	EQU	BPSTOR
BPMRK:	EQU	0BH			;USED TO MARK THE SET-
;					;TING OF A BP IN BPSTOR.
RSTLC:	EQU	30H			;RST LOCATION
CASE:	EQU	0			;(REQUIRES UPPER-CASE)
B2F:	EQU	5			;2-BYTE FLAG
PF:	EQU	6			;PRIME-ABLE REG FLAG
CRF:	EQU	7			;CRLF FLAG
;
CR:	EQU	0DH
LF:	EQU	0AH
ESC:	EQU	1BH
ALT:	EQU	7DH
;
;  DISPLACEMENTS FROM IX OF HI BYTE OF REG PAIRS
;
;
DUPC:	EQU	-1			;(FFFF)
DUAF:	EQU	-3			;(FFFD)
DUBC:	EQU	-5			;(FFFB)
DUDE:	EQU	-7			;(FFF9)
DUHL:	EQU	-9			;(FFF7)
DUSP:	EQU	-11			;(FFF5)
DUIX:	EQU	-13			;(FFF3)	
DUIY:	EQU	-15			;(FFF1)
DUIN:	EQU	-17			;(FFEF)        I & THE INTERRUPT FF
DUAF2:	EQU	-19			;(FFED)
DUBC2:	EQU	-21			;(FFEB)
DUDE2:	EQU	-23			;(FFE9)
DUHL2:	EQU	-25			;(FFE7)
;
LENRGS: EQU	DUPC-DUHL2+2
;
;
;
;

	ORG	0E000H
;
; ENTER THE MONITOR FROM RESET.
; COLD START ENTRY. INITIALIZES THE UART
; AND ZEROES THE BREAKPOINT STACK POINTER.
; ALTERS THE A-REGISTER. SAVES ALL OTHER
; REGISTERS EXCEPT THE PROGRAM COUNTER,
; BUT DOES NOT DISPLAY THEM.

CSTART: LD  	A,1
	OUT 	40H,A 			;SELECT BANK B
	PUSH	AF			;SIMULATE UPC
	PUSH	AF			;USER-F-REGISTER
	JR	COMMON
; WARM START ENTRY.  INITIALIZES THE BREAKPOINT
; STORAGE POINTER.  SAVES ALL REGISTERS EXCEPT
; THE PROGRAM COUNTER, BUT DOES NOT DISPLAY THEM.

WSTART:	PUSH	AF			;SIMULATE UPC
	PUSH	AF			;UAF
	LD	A,80H			;FLAG:
	JR	COMMON			;WARM-START ENTRY
;
; CHECK INPUT & RETURN WITH DATA IF READY.
;
CHKIN:	IN	A,STAT
	AND	DAV
	RET	Z
	IN	A,DATA
	RET
;
;
; GET CHARACTER FROM INPUT.
;
GBYTE:	CALL	CHKIN
	JR	Z,GBYTE
	AND	7FH
	RET
;
;
; PRINT CHARACTER.
;
PBYTE:	PUSH	AF
PBY1:	IN	A,STAT
	AND	TBE
	JR	Z,PBY1
	POP	AF
	OUT	DATA,A
	RET
;
;
; SELECT DEVICE A & INITIALIZE ITS BAUD RATE.
; ENTER WITH A=1.
;
INIT:	OUT	BPARLP,A		;SELECT DEVICE A
	OUT	BCMNDP,A		;RESET DEVICE B
;					;[CONTINUE BELOW]
;
;
; INITIALIZE BAUD RATE OF THE CURRENT DEVICE.
;
; PUSH CARRIAGE-RETURN TO SELECT THE PROPER BAUD
; RATE FOR THE CURRENT TERMINAL. (THE MAXIMUM
; NUMBER OF CARRIAGE-RETURNS REQUIRED IS FOUR.)
;
; WITH THE CROMEMCO TUART ANY OF THE FOLLOWING
; BAUD RATES CAN BE SELECTED:
; 19200, 9600, 4800, 2400, 1200, 300, 150, 110.
;
; WITH THE 3P+S:	2400, 300, 110.
;
; TWO CARRIAGE-RETURNS ARE REQUIRED FOR
; ANY UART WITH A FIXED BAUD RATE.
;
INITBAUD: LD	HL,BAUDRS
	LD	C,ABAUDP
	LD	A,11H			;OCTUPLE THE CLOCK
IT1:	OUT	ACMNDP,A		;& RESET CURRENT DEVICE
	OUTI
	CALL	GBYTE
	CALL	GBYTE
	CP	CR
	LD	A,1			;SLOW THE CLOCK
	JR	NZ,IT1
	RET
;
;
; BREAKPOINT ENTRY. INITIALIZES	NOTHING.
; SAVES	ALL REGISTERS AND DISPLAYS THEM.
;
SVMS:	EX	(SP),HL			;ADJUST BRKPT
	DEC	HL			;RET ADDR
	EX	(SP),HL
	PUSH	AF			;UAF
	SUB	A			;FLAG:
					;BREAKPOINT ENTRY;
;
;
COMMON:	PUSH	BC			;UBC
	LD	B,A			;ENTRY FLAG
	PUSH	DE			;UDE
	PUSH	HL			;UHL
;
; PLACE SYS STACK AT HIGHEST PAGE OF
; AVAILABLE RAM.
; ALLOW	ROOM FOR TEMP STORAGE.
;
	LD	HL,00FFH-TEMPS
COM1:	DEC	H
	LD	A,(HL)
	INC	(HL)
	CP	(HL)			;DID IT CHANGE?
	JR	Z,COM1
	DEC	(HL)			;YES. RESTORE IT.
;
	LD	A,B			;ENTRY FLAG
	EX	DE,HL
	LD	HL,9
	ADD	HL,SP			; -> UPC, HI BYTE
	LD	BC,10
	LDDR
;
	INC	DE			;-> UHL,LO ON SYS STK
	EX	DE,HL
	LD	SP,HL			;CURRENT SYS SP
	EX	DE,HL
	LD	BC,DUPC-DUHL+3
	ADD	HL,BC			;HL = USER SP
	PUSH	HL			;USP
	PUSH	IX			;UIX
	PUSH	IY			;UIY
	EX	DE,HL
	ADD	HL,BC
	LD	C,L			;SAVE
	DEC	HL
	PUSH	HL
	POP	IX
	CP	1			;ENTRY?
	JR	C,COM3			;SKIP IF VIA BP.
	LD	(HL),C			;BP PNTR, LO BYTE
	INC	HL
	LD	(HL),0			;BP-STACK ENDMARK
; INITIALIZE THE TUART IF ENTRY WAS VIA RESET.
; (A CONTAINS 1.)
;
	CALL	Z,INIT
;
COM3:	LD	A,I
	LD	H,A
	LD	L,0
	JP	PO,COM4
	INC	L
COM4:	PUSH	HL			;UIN
	EX	AF,AF'
	PUSH	AF			;UAF'
	EX	AF,AF'
	EXX
	PUSH	BC			;UBC'
	PUSH	DE			;UDE'
	PUSH	HL			;UHL'
	EXX
;
;IF CY IS SET, ENTRY WAS VIA A BREAKPOINT
	LD	HL,HEAD
	CALL	NC,PMSG
	LD	BC,[['P'+CASE] SHL 8]+86H ;IF BP ENTRY,
	CALL	C,SUBR3			;DISPLAY THE PC.
;
;
;CLEAR ALL BREAKPOINTS
;
CLBP:	PUSH	IX
	POP	HL			;POINTS TO BPSP,LO
	LD	L,(HL)			;BPSP NOW IN HL
;
CL1:	LD	A,(HL)			;BP STK EMPTY?
	CP	BPMRK			;IF BPMRK, BP IS SET
	JR	NZ,CL2
;
	INC	(HL)			;BP-ERASED MARK
	DEC	HL
	LD	D,(HL)
	DEC	HL
	LD	E,(HL)
	DEC	HL
	LDD				;RESTORE MEM CONTENTS
	JR	CL1
;
CL2:	LD	A,L
	DEC	HL
	LD	(HL),A			;ADJUST BPSP
;
	LD	DE,-LENRGS		;FOR THE BENEFIT
	ADD	HL,DE			;OF ERROR & ESCPE
	LD	SP,HL			;RE-INITIALIZE SP
;
;
;GET 1-BYTE COMMAND.
;RETURNS VALUE IN HL & JUMPS TO THAT ADDR.
;
	CALL	CRLF
CMND:	LD	DE,CMND			;SET-UP RETURN
	PUSH	DE
CMND1:	LD	HL,PRMPT		;RE-ENTRY POINT
	CALL	PMSG			;FOR RECURSION
;HL NOW PNTS TO THE COMMAND TABLE.
;
;GET THE COMMAND.
;DE GETS THE FIRST ALPHA CHAR LESS 'D'.

	CALL	SKSG0			;GET NON-SPACE
	RET	Z			;IF CR, IGNORE.
	SUB	'D'+CASE		; < 'D'?
	JR	C,ERROR
	CP	'W'-'D'+1		; > 'W'?
	JR	NC,ERROR
	LD	E,A
	LD	D,0
;
	LD	C,D			;INITIALIZE FOR SUBR
	EX	DE,HL
	ADD	HL,HL			;TIMES 2
	ADD	HL,DE			; + TBL ADDR
	LD	E,(HL)
	INC	HL
	LD	D,(HL)
	EX	DE,HL
	CALL	SKSG0			;NEXT CMND GHAR
	CP	'M'+CASE		; (USED IN SUBST & DISPL)
	JP	(HL)
;
;
; ERROR & ESCAPE. RETURNS TO CMND WITH SP
; POINTING TO SAVED-REG AREA (UHL').

ERROR:	LD	A,'?'
	CALL	PCHR
ESCPE:	JR	CLBP			;CLEAR ANY BRKPTS
;
;
; PROGRAM PROMS. ABORTS IF DESTINATION
; IS NOT ON A 1K (400H) BOUNDARY, OR IF SWATH
; WIDTH IS NOT A MULTIPLE OF 1K.
;
;
PROG:	CALL	L3NCR
	LD	A,B			;ARE INCREMENT &
	OR	D			;DESTINATION BOTH
	AND	3			;MULTIPLES OF
	OR	C			;1024?
	OR	E	
ERRV1:	JR	NZ,ERROR		;ERROR VECTOR
;
	PUSH	HL			;SOURCE
	LD	HL,320			;# OF ITERATIONS
PR1:	EX	(SP),HL
	CALL	MVE			;MOVE IT
	EX	(SP),HL
	DEC	HL			;ITERATION CT
	LD	A,H
	OR	L
	JR	NZ,PR1
	POP	HL
	JR	VRFY			;VERIFY IT
;
;
;PRINT THE 2 BYTES IN (HL) & (HL-1)
;DECREMENTS HL BY 2. ALTERS A.
;PRESERVES OTHER REGS.
;
P2NMS:	CALL    PNM
	DEC     HL
	CALL    PNM
	DEC     HL	  		; (CONTINUE BELOW)
;
;
;PRINT	SPACE. ALTERS A.
;
SPACE:	LD A,20H	  		; (CONTINUE BELOW)
;
;
;PRINT THE CHARACTER IN THE A-REGISTER.
;(CHKS INPUT FOR ESC.)	PRESERVES ALL REGS.
;
PCHR:	PUSH	AF	         	;SAVE THE CHAR
PC1:	AND	7FH
	CP	ESC
	JR	Z,ESCPE
	CP	ALT			;ALT MODE?
	JR	Z,ESCPE
	CALL	CHKIN
	JR	NZ,PC1
;
PC2:	POP	AF
	PUSH	HL
	PUSH	AF
	AND	7FH
	CALL	PBYTE
	LD	HL,LFNN
	CP	CR
	CALL	Z,PMSG
	CP	'<'			;RECURSIVE CALL
	JR	NZ,PC3			;ON CMND?
	POP	AF
	LD	A,CR			;YES. CONVERT
	PUSH	AF			;'<' TO A CR.
	PUSH	DE
	PUSH	BC
	CALL	CMND1
	POP	BC
	POP	DE
PC3:	POP	AF
	POP	HL
	RET
;
;
; GET CHARACTER. RETURNS IT IN A.
; ALTERS F.
;
GCHR:	CALL	GBYTE
	CALL	PCHR
	JR	Z,GCHR			;IF NULL DON'T RETURN
	RET
;
;
; CRLF.	ALTERS A ONLY.
;
CRLF:	LD	A,CR
	JR	PCHR
;
;
; LOADS	HL WITH	SOURCE ADDR, BC	& DE
; WITH THE INCREMENT. ENDS WITH A CRLF.
;
L2NCR0:	SUB	A

L2NCR:	CALL	LD2N
;
; SKIP INITIAL SPACES.
; IF DELIMITER NOT A CR, ERROR
;
SKSGCR:	CALL	SKSG			;WAIT FOR NON-SPACE
	JR	NZ,ERRV1		;IF NOT CR, ERROR
	EX	DE,HL
	RET
;
;
; PRINT THE NUMBER IN HL, FOLLOWED BY A COLON.
; PRESERVES ALL REGISTERS EXCEPT A.
;
PCADDR:	CALL	CRLF
;
PADDR:	CALL	PNHL
	LD	A,':'
	JR	PCHR
;
;
; COMMAND
;
VERIF:	CALL	L3NCR			;GET 3	OPERANDS
;
; COMPARES TWO AREAS OF MEMORY. ENTER WITH
; SOURCE IN HL, DESTINATION IN DE & COUNT
; IN BC. ALTERS ALL REGISTERS.
;
VRFY:	LD	A,(DE)
	CPI				;COMPARE TO SOURCE
	DEC	HL
	CALL	NZ,PNHL			;PRINT SOURCE ADDR
	CALL	NZ,PSNM	  		; & CONTENTS
	EX	DE,HL
	CALL	NZ,PSNM	  		; & DEBT CONTENTS
	CALL	NZ,PSNHL	  	; & DEBT ADDR
	CALL 	NZ,CRLF
	EX 	DE,HL
	INC 	HL
	INC 	DE
	RET 	PO 			;IF BC=0, DONE.
	JR VRFY
;
;
; COMMAND
;
MOVE:	CALL	L3NCR			;OPERANDS
	CALL	MVE			;MOVE IT
	JR	VRFY
;
;
; LOAD TWO NUMBERS. LOADS DE WITH THE BEGINNING
; ADDR, N1. LOADS BC & HL WITH THE INCREMENT
; N2-Ni+1 (OR WITH N2 IF THE OPR IS 'S').
; RETURNS WITH LAST DELIMITER IN A.
;
LD2N: 	CALL	GNHL			;N1 TO HL, DELIM TO A
EX  	DE,HL  				;SAVE Ni IN DE
CALL	SKSG				;GET NEXT NON-SPACE
CP  	'S'+CASE  			;SWATH?
JR  	NZ,L2N1
;
CALL	GNHL0				;YES. INCREMENT TO HL.
JR	L2N2

L2N1:	CALL	GNHL	        	;INCREMENT
	OR  	A  	         	;CLEAR CY
	SBC 	HL,DE 	        	;N2-Nl
	INC 	HL 	         	;INCLUDE END POINT
L2N2:	LD	B,H
	LD  	C,L  	         	;BC GETS THE INCRM
	RET
;
;
; LOAD 3 OPERANDS. HL GETS THE SOURCE, BC
; THE INCREMENT, AND DE	THE 3RD OPERAND.
;
L3NCR: CALL	LD2N
; (CONTINUE BELOW)
;
;
; ENTER WITH SPACE OR THE FIRST DIGIT
; OF A NUMBER IN A. LOADS HL WITH
; WITH A NEW NUMBER & THEN EXCHANGES
; DE & HL. FINISHES WITH A CRLF.
;
L1NCR: CALL	GNHL	        	 ;SKIP SPACES, LOAD HL
	JR  	SKSGCR  	         ;WAIT FOR A CR
;
;
; CLEARS HL. IF	ENTERED	WITH HEX CHAR IN A,
; SHIFTS IT INTO HL. O/W, IGNORES LEADING
; SPACES. FIRST	CHAR MUST BE HEX. CONTINUES
; SHIFT UNTIL A	NON-HEX	CHAR RECEIVED & THEN
; RETURNS WITH THE LATTER IN A.
; PRESERVES B,C,D,E.
;
;
GNHL0: SUB	A
;
GNHL: PUSH	BC	         	;SAVE
	LD  	HL,0  	         	;CLR BUFFER
; STRIP LEADING	SPACES & GET CHAR
	CALL	SKSG
; FIRST CHAR MUST BE HEX
	CALL	HEXSH	         	;IF HEX, SHIFT INTO HL
	JP  	C,ERROR  	        ;O/W, ERROR
GN1: CALL	GCHR
	CALL	HEXSH			;IF HEX SHIFT INTO HL
	LD  	A,B  			;RESTORE CHAR
	JR  	NC,GN1			;IF HEX, CONTINUE
	POP 	BC			;IF NON-HEX, DONE
	RET
;
;
; IF A CONTAINS	HEX CHAR, SHIFTS BINARY EQUIVALENT
; INTO HL. IF NOT HEX, RET WITH CY SET. SAVES
; ORIGINAL CHAR	IN B
;
HEXSH:	LD	B,A
	SUB	'0'			; < '0'?
	RET	C
	ADD	'0'-['G'+CASE]
	RET	C
	SUB	'A'-'G'
	JR	NC,HX1 			;OK IF >= 'A'
	ADD	['A'+CASE]-['9'+1]
	RET	C
HX1:	ADD	'9'+1-'0'
; THE A-REG NOW CONTAINS THE HEX DIGIT IN BINARY.
; (THE HIGH-ORDER NIBBLE OF A IS 0.)
HXSH4:	ADD	HL,HL 			;SHIFT 4 BITS INTO HL
	ADD	HL,HL
	ADD	HL,HL
	ADD	HL,HL
	OR	L
	LD	L,A
	RET
;
;
; RETURNS WITH A NON-SPACE IN THE A-REG.
; IF ENTERED WITH A-REG CONTAINING A NULL
; OR A SPACE, GETS NEW CHARS UNTIL FIRST
; NON-SPACE OCCURS. ALTERS AF.
;
SKSG0:	SUB	A
;
SKSG:	OR	A			;DOES A CONTAIN NULL?
SK1:	CALL	Z,GCHR
	CP	20H			;SPACE?
	JR	Z,SK1
	CP	CR
	RET
;
;
; PRINT SPACE FOLLOWED BY THE NUMBER POINTED
; TO BY HL. ALTERS A ONLY.
;
PSNM:	CALL	SPACE
;	(CONTINUE BELOW)

; PRINTS THE NUMBER POINTED TO BY HL.
; PRESERVES ALL REGISTERS BUT A.

PNM:	LD	A,(HL)
	JR	P2HEX
;
;
; PRINT THE NUMBER IN HL.
; PRESERVES ALL BUT A.
;
PSNHL:	CALL	SPACE
;
PNHL:	LD	A,H
	CALL	P2HEX
	LD	A,L
;					; (CONTINUE BELOW)
;
;PRINT THE NUMBER IN THE A-REGISTER.
;PRESERVES ALL REGISTERS.
;
P2HEX:	CALL	P1HEX
	RRA
P1HEX:	RRA
	RRA
	RRA
	RRA
	PUSH	AF
	AND	0FH			;MASK
	CP	10D			; < 9?
	JR	C,PH1
	ADD	7			;A THRU F
PH1:	ADD	30H			;ASCII BIAS
	CALL	PCHR			;PRINT IT
	POP	AF
	RET
;
;
;PRINT	MESSAGE. ENTER WITH ADDR OF MSG
;IN HL. THE MESSAGE IS TERMINATED
;AFTER PRINTING A CHARACTER WHOSE
;PARITY BIT WAS SET.
;PRESERVES FLAGS, INCREMENTS HL.
;
PMSG:	PUSH	AF			;SAVE
PS1:	LD	A,(HL)
	INC	HL
	CALL	PCHR
	RLA				;LAST CHARACTER?
	JR	NC,PS1			;IF NOT, LOOP
	POP	AF
	RET
;
;
;MOVE FROM ONE LOCATION TO ANOTHER. ENTER
;WITH SOURCE ADDR IN HL, DEST IN DE, BYTE
;COUNT IN BC.  PRESERVES ALL REGISTERS.
;
MVE:	PUSH	HL			;SOURCE
	PUSH	DE			;DEST
	PUSH	BC			;BYTE COUNT
	LDIR
	POP	BC
	POP	DE
	POP	HL
	RET
;
;
; COMMAND
;
; GO  EXECUTION BEGINS AT USER PC.
;
; COMMAND
;
; GO (ADDR1>/(ADDR2> ... 
; EXECUTION BEGINS AT ADDR1 WITH BREAKPOINTS SET
; AT ADDR2,... ,ADDRN.

GO:
; B GETS NBRKPT+1 (MAX. NUMBER OF BP + 1)
; C, THE BREAKPOINT FLAG, GETS 0 (NO HP SET)
	LD   	BC,[[NBRKPT+1] SHL 8]+0
GO1:	CALL 	SKSG 	 		;WAIT FOR NON-SPACE
	JR   	Z,RETN   	 	;RETN IF CR
	CP	'/'	 		;BP?
	JR   	NZ,GO3
	LD   	C,A   	 		;SET BRKPT FLAG (2FH)
	LD   	HL,RSTLC   	 	;TRANSFER
	LD   	(HL),0C3H   	 	;'JP SVMS' TO
	LD   	HL,SVMS
	LD   	(RSTLC+1),HL   	 	;RST LOC
	SUB  	A
GO3:	CALL 	GNHL 	 		;GET ADDR
	BIT  	5,C  	 		; FLAG SET?
	EX   	DE,HL
	PUSH 	IX
	POP  	HL
	JR   	Z,GO5   	 	;JUMP IF NO BP
;
	DEC  	B  	 		;IF TOO MANY BP,
	JP   	Z,ERROR   	 	;ERROR.
	LD   	L,(HL)   	 	;HL = BPSP
;
	INC  	HL  	 		;BUMP BPSP
	EX   	DE,HL   	 	;DE = BPSP, HL= BP ADDR
	LDI
	DEC  	HL
	LD   	(HL),0C7H+RSTLC 	;RST INSTRUCTION
	EX   	DE,HL   	 	;HL = BPSP
	LD   	(HL),E   	 	;BP ADDR TO STACK
	INC  	HL
	LD   	(HL),D
	INC  	HL
	LD   	(HL),BPMRK   	 	;PUNCTUATION (BP SET)
	LD   	(IX),L
	JR   	GO1
; CHANGE USER PC
GO5:	DEC  	HL
	LD   	(HL),D
	DEC  	HL
	LD   	(HL),E
	JR   	GO1   		 	;BACK FOR MORE
;
RETN:	POP  	HL  	 		;STRIP ADDR FROM STK
	POP  	HL  	 		;UHL'
	POP  	DE  	 		;UDE'
	POP	BC			;UBC'
	POP	AF			;UAF'
	EXX
	EX 	AF,AF'
;
	POP	AF			;UIN
	LD 	I,A 			; UI
	DI
	JR 	NC,RT1
	EI
;IFF NOW RESTORED
RT1:	POP	IY			;UIY
	POP	IX			;UIX
	POP	DE			;USP
;
;COPY THE REMAINDER OF THE SYS STACK
;TO THE USER STACK. IF THIS TRANSFER
;IS MADE WITHOUT ERROR, SWITCH TO THE
;USER STACK. OTHERWISE, RETAIN THE
;SYSTEM STACK.
;
	LD	HL,10D
	LD 	B,L
	ADD	HL,SP
	EX 	DE,HL
RT2:	DEC	DE
	DEC	HL
	LD 	A,(DE)
	LD 	(HL),A
	CP 	(HL)
	JR 	NZ,RT3
	DJNZ	RT2
	LD 	SP,HL
;
RT3:	POP	HL
	POP	DE
	POP	BC
	POP	AF
	RET


;	COMMAND.  DISPLAY REGISTERS.
;
;	DR
;
; COMMAND.  DISPLAY MEMORY.
;
; DM  
;
DISPL:	LD	BC,[['A'+CASE]	SHL 8]+80H ;[FOR DR]
	JR	NZ,SUBR2	 	;IF NOT 'M', DR
;
;
DSPM:	CALL	L2NCR0	 		;GET OPERANDS
DSPM1:	LD	D,16	 		;BYTE COUNT
	CALL	PCADDR	 		;ADDRESS
DM2:	CALL	PSNM			;MEM CONTENTS
	CPI				;INC HL & DEC BC
	JP	PO,CRLF
	DEC	D
	JR	Z,DSPM1
	LD	A,D
	AND	3
	CALL	Z,SPACE
	CALL	Z,SPACE
	JR	DM2
;
;
; COMMAND. SUBSTITUTE MEMORY LOCATION.
;
; SM 
;
; COMMAND. SUBSTITUTE USER-REGISTER.
;
; S
;
; REGISTER NAMES: P [PC] , S [SP]
; A, F, B, C, D, E, H [HL]
; I, N [1FF], X [IX], Y [IY]
; A',F',B',C',D',E',H' [HL'].
;
SUBST:	JR	NZ,SUBR			;IN NOT 'M', SR

SUBM:	SUB	A
	LD	B,A			;1-BYTE MASK
	CALL	L1NCR
	EX	DE,HL			;HL GETS ADDR
SM1:	CALL	Z,PCADDR
	CALL	Z,SPACE
; PRINT CURRENT VALUE, REQUEST NEW VALUE &
; PRINT IT IF GIVEN
	CALL	GSUBV
	RET	Z			;IF CR, DONE.
	INC	HL
	LD	A,7			;PRINT ADDRESS IF IT
	AND	L			;IS A MULTIPLE OF 8
	JR	SM1
;
;
SUBR:	LD	B,A
	CALL	GCHR
	CP	''''
	JR	NZ,SR2
	INC	C			;TURN ON THE PRIME-FLAG
SUBR2:	SUB	A
SR2:	CALL	SKSGCR			;WAIT FOR CR
SR3:	LD	A,B
	SUB	'A'+CASE		;CHECK THE RANGE
	JP	C,ERROR
	CP	'Y'-'A'+1
	JP	NC,ERROR
	LD	E,A
	LD	D,0
	LD	HL,RGTBL
	ADD	HL,DE
	LD	A,(HL)
	OR	A
	JR	Z,SR6	    		;IF ENTRY = 0, SKIP
	LD	E,0
	BIT	0,C	    		;PRIME?
	JR	Z,SR4
	BIT	PF,(HL)			;YES. PRIMEABLE REG?
	JR	Z,SR6	    		;IF NOT, SKIP.
	LD	E,DUAF-DUAF2
SR4:	AND	1FH	    		;STRIP FLAGS FROM ENTRY
	ADD	E
	LD	E,A
	PUSH	BC	    		;SAVE
	LD	A,B	    		;PRINT REG NAME
	CALL	PCHR
	CP	'H'+CASE
	LD	A,'L'+CASE
	CALL	Z,PCHR
	XOR	'L'+CASE XOR '='	;CLEAR CY, A = '='.
	BIT	0,C	    		; PRIME?
	JR	Z,SR5
	LD	A,''''
SR5:	CALL	PCHR
	LD	B,(HL)	    		;SAVE ORIGINAL ENTRY
	PUSH	IX
	POP	HL	   	 	;STACK FRAME
	SBC	HL,DE	    		;HL -> USER REG
	CALL	GSUBV	    		;PRINT VALUE, REQUEST NEW
	LD	A,B	    		;SAVE
	POP	BC
	RET	Z	    		;DONE IF CR
;
SR6:	INC	B	    		;NEXT REG
	RLCA		    		;Y OR H?
	JR	NC,SR3	    		;IF NEITHER, LOOP
	RLCA		    		;YES, IS IT Y?
SUBR3:	CALL	CRLF	    		; [ENTRY FOR DISPLAYING PC
	JR	C,SR8
	LD	B,'A'+CASE		;YES, IT IS Y.
	INC	C	    		;TURN ON PRIME-FLAG
	JR	SR3
SR8:	BIT	0,C	    		;NO. H OR H'?
	JR	Z,SR3	   		;IF H, LOOP.
	RET		    		;IT IS H'. DONE.


; ENTER WITH HL POINTING TO MEMORY &
; B CONTAINING THE 1-BYTE OR 2-BYTE FLAG.
; PRINTS SPACE, CONTENTS OF (HL), & ALSO (HL-1) FOR
; 2-BYTE REGS, GETS SUBSTITUTION VALUE & LOADS IT.
; RETURNS WITH Z-FLAG SET 1FF THE DELIMITER IS
; A CARRIAGE-RETURN.
; PRESERVES BC & HL.
;
GSUBV:	CALL	PNM	 		;PRINT (HL)
	BIT	B2F,B	 		;2-BYTE REG?
	JR	Z,GS1
	DEC	HL
	CALL	PNM	 		;LO BYTE
GS1:	LD	A,C	 		;SUBST-OR-DISPLAY FLAG
	RLCA
	JR	C,GS2			;IF DISPLAY, EXIT.
	LD	A,'.'
	CALL	PCHR
	CALL	GCHR
	CP	'.'+1			;SUBSTITUTION?
GS2:	CALL	C,PCHR			;IF NOT, PRINT ANOTHER.
	JR	C,GS3
	EX	DE,HL
	CALL	GNHL			;NEW VALUE
	EX	DE,HL
	LD	(HL),E
	BIT	B2F,B
	JR	Z,GS3
	INC	HL
	LD	(HL),D
GS3:	CP	CR
	CALL	NZ,SPACE
	RET
;
;
;...SUBDM 00 7E 5 585 BY 5 100 DBE++
;
;
; COMMAND
; SELECT UART-A OR UART-B.
;
; UA
; UB
;
UART:	CALL	L1NCR			;A OR B?
	LD	A,E
	CP	0BH
	JR	NZ,UARTA
	LD	A,80H
	OUT	APARLP,A
	RET
;
UARTA:	SUB	A
	OUT	BPARLP,A
	RET
;
;
; COMMAND
; READ BINARY INPUT FROM DATA PORT
;
READB:	CALL	L2NCR			;GET MEM ADDRS
RB1:	CALL	CHKIN			;GET INPUT
	JR	Z,RB1
	LD	(HL),A			;TO MEM
	CPI
	RET	PO
	JR	RB1
;
;
; COMMAND
; WRITE BINARY OUTPUT TO DATA PORT

WRITB:	CALL	L2NCR			;GET MEM ADDRS
WB1:	LD	A,(HL)
	CALL	PBYTE
	CPI
	RET	PO
	JR	WB1
;
;
; COMMAND
; PRINT NULLS ON THE CURRENT DEVICE.
;
; N 
;
NULLS:	CALL	L1NCR
	LD	B,E
	SUB	A
N2:	CALL	PCHR
	DJNZ	N2
	RET
;
;
; COMMAND
; OUT  
;
OUTP:	CALL	GNHL
	EX	DE,HL			;E GETS DATA
	CALL	L1NCR			;GET PORT NUMBER
;
	LD	C,E			; TO C
	OUT	(C),L
	RET
;

; BAUD RATES.
; WITH THE CROMEMCO TUART:  19200, 9600, 4800,
; 			2400, 1200, 300, 150, 110.
;
; WITH THE 3P+S: 2400, 300, 110.
;
;
BAUDRS:	DB	94H,0CEH,0A2H,92H,88H,84H,82H,1
;
;
LFNN:	DB	LF,0,0 OR 80H
;
;
PRMPT:	DB	':' OR 80H
; THE COMMAND TBL MUST IMMEDIATELY FOLLOW
;
;  THE	PROMPT MESSAGE
	DW	DISPL			;DISPLAY: DM, DR
	DW	ERROR			;E
	DW	ERROR
	DW	GO			;GO; GO/WITH BREAKPOINTS
	DW	ERROR
	DW	INITBAUD		;INITIALIZE BAUD RATE
	DW	ERROR			;J
	DW	ERROR			;K
	DW	ERROR			;L
	DW	MOVE			;MOVE A BLOCK OF MEMORY
	DW	NULLS			;NULLS
	DW	OUTP			;OUTPUT
	DW	PROG			;PROGRAM
	DW	ERROR			;Q
	DW	READB			;READ BINARY OR ASCII
	DW	SUBST			;SUBSTITUTE: SM, SA, SB.
	DW	ERROR			;T
	DW	UART			;UART: UA, UB
	DW	VERIF			;VERIFY BLOCKS OF MEMORY
	DW	WRITB			;WRITE BINARY OR ASCII
;
PM:	EQU	1 SHL PF		;PRIMEABLE-REG MASK
B1M:	EQU	0			;1-BYTE REG MASK
B2M:	EQU	1 SHL B2F		;2-BYTE REG MASK
CRM:	EQU	1 SHL CRF		;CARRIAGE-RETURN MASK

RGTBL:	DB	-DUAF OR PM		;A
	DB	-DUBC OR PM		;B
	DB	-DUBC+1 OR PM		;C
	DB	-DUDE OR PM		;D
	DB	-DUDE+1 OR PM		;E
	DB	-DUAF+1 OR PM		;F
	DB	0
	DB	-DUHL OR PM OR B2M OR CRM ;H [HL]
	DB	-DUIN OR B1N		;I
	DB	0
	DB	0
	DB	0
	DB	0
	DB	-DUIN+1 OR B1M		;N [INTERRUPT FF]
	DB	0
	DB	-DUPC OR B2M		;PC
	DB	0
	DB	0
	DB	-DUSP OR B2M		;SP
	DB	0
	DB	0
	DB	0
	DB	0
	DB	-DUIX OR B2M		;X [IX]
	DB	-DUIY OR B2M OR	CRM 	;Y [IY]
;
;
HEAD:	DB	CR,CR, 'CROMEMCO ZM1.','4' OR 80H
	END	CSTART