;	<< ZAP 1-K MONITOR SYSTEM >>
;		by
;	TECHNICAL DESIGN LABS, INC.
;	RESEARCH PARK
;	PRINCETON, NEW JERSEY 08540
;
;	COPYRIGHT JAN. 1977 TDL INC.
;
;	ASSEMBLED by Roger Amidon
;
.PREL	;THIS MONITOR SUPPLIED IN RELOCATING FORMAT
;
LENGTH  = Z	;SIZE OF THIS MONITOR
;
.TITLE "	<Zap Monitor, Version 2.0, Jan. 16 1977>"
.SBTTL  /  Copyright 1977 by TECHNICAL DESIGN LABS, INC./
;	<I/O DEVICES>
;
;-TELEPRINTER
;
TTI	= 1	;DATA IN PORT
TTO	= 1	;DATA OUT PORT
TTS	= 0	;STATUS PORT (IN)
TTYDA	= 1	;DATA AVAILABLE MASK BIT
TTYBE	= 80H	;XMTR BUFFER EMPTY MASK
;
RCP	= 3	;READER CONTROL PORT.
		;THIS PORT IS PULSED ONCE
		;FOR EACH READER REQUEST
		;TO SUPPORT A CONTROLLED
		;READER.
;
;	<CONSTANTS>
;
I	= 0		;'I' REG. VALUE
FALSE	= 0		;ISN'T SO
TRUE	= # FALSE	;IT IS SO
CR	= 0DH		;ASCII CARRIAGE RETURN
LF	= 0AH		;ASCII LINE FEED
BELL	= 7		;DING
RUB	= 0FFH		;RUB OUT
FIL	= 00		;FILL CHARACTERS AFTER CRLF
MAX	= 7		;NUMBER OF QUES IN EOF
;
;
;	PROGRAM CODE BEGINS HERE
;
ZAP:	JMP	BEGIN	;GO AROUND VECTORS
			; GET MEMORY SIZE,
			; AND CONTINUE AHEAD
;
;	<VECTORS FOR CALLING PROGRAMS>
;
; THESE VECTORS MAY BE USED BY USER WRITTEN
; PROGRAMS TO SIMPLIFY THE HANDLING OF I/O
; FROM SYSTEM TO SYSTEM.  WHATEVER THE CURRENT
; ASSIGNED DEVICE, THESE VECTORS WILL PERFORM
; THE REQUIRED I/O OPERATION, AND RETURN TO
; THE CALLING PROGRAM. (RET)
;
; THE REGISTER CONVENTION USED FOLLOWS-
;
; ANY INPUT OR OUTPUT DEVICE-
;	CHARACTER TO BE OUTPUT IN 'C' REGISTER.
;	CHARACTER WILL BE IN 'A' REGISTER UPON
;	RETURNING FROM AN INPUT OR OUTPUT.
; 'CSTS'-
;	RETURNS TRUE (0FFH IN 'A' REG.) IF THERE IS
;	SOMETHING WAITING, AND ZERO (00) IF NOT.
; 'IOCHK'-
;	RETURNS WITH THE CURRENT I/O CONFIGURATION
;	BYTE IN 'A' REGISTER.
; 'IOSET'-
;	I/O CANNOT BE MODIFIED IN THIS 1K VERSION
; 'MEMCK'-
;	RETURNS WITH THE HIGHEST ALLOWED USER
;	MEMORY LOCATION. 'B'=HIGH BYTE, 'A'=LOW.
; 'TRAP'-
;	THIS IS THE 'BREAKPOINT' ENTRY POINT.
;	NOT USED IN THE 1K VERSION, GOES TO THE
;	'ERROR' ROUTINE TO RESET THE MONITOR'S
;	STACK.
;
	JMP	CI	;CONSOLE INPUT
	JMP	RI	;READER INPUT
	JMP	CO	;CONSOLE OUTPUT
	JMP	PO	;PUNCH OUTPUT
	JMP	CO	;LIST OUTPUT
	JMP	CSTS	;CONSOLE STATUS
	MVI	A,0	;I/O CHECK
IOSET:	RET		;SET TO TTY CONFIGURATION
	JMP	IOSET	;CAN'T SET I/O ON 1K VERSION
	JMP	MEMCK	;MEMORY LIMIT CHECK
ERROR:	CALL	MEMSIZ	;RESET BACK TO MONITOR (TRAP)
	SPHL		;RE-ESTABLISH A STACK
	MVI	C,'*'	;ANNOUNCE ERROR
	CALL	CO
	JMPR	START
;
;	MONITOR NAME & VERSION
;
MSG:	.BYTE	CR,LF,FIL,FIL,FIL
	.ASCII  'Zap V'
	.ASCII  '2.0'
;
MSGL	= .-MSG
;
STACK	= .-2		;A FAKE STACK TO GET STARTED
;
	.WORD	AHEAD	;AFTER MEMORY SIZE
;
AHEAD:	SPHL		;SET TRUE STACK
	MVI	B,MSGL	;SAY HELLO TO THE FOLKS 
	CALL	TOM	;OUTPUT SIGN-ON MSG
START:	MVI	C,'>'	;PROMPT CHARACTER
	LXI	H,START ;MAIN 'WORK' LOOP
	PUSH	H	;SET UP A RETURN TO HERE
	CALL	CRLF
	CALL	CO
STAR0:	CALL	TI	;GET A CONSOLE CHARACTER
	ANI	7FH	;IGNORE NULLS
	JRZ	STAR0	;GET ANOTHER
	MVI	C,2	;SET-UP C REG.
	CPI	'D'	;SEE IF 'DISPLAY' COMMAND
	JRNZ	EOF
;
; THIS DISPLAYS THE CONTENTS OF MEMORY IN BASE HEX
; WITH THE STARTING LOCATION ON EACH LINE.(BETWEEN
; THE TWO PARAMETERS GIVEN). 16 BYTES PER LINE MAX.
;
DISP:	CALL	EXLF	;GET DISPLAY RANGE
..D0:	CALL	LFADR	;CRLF & PRINT ADDR.
..D1:	CALL	BLK	;SPACE OVER
	MOV	A,M
	CALL	LBYTE
	CALL	HILOX	;RANGE CHECK
	MOV	A,L
	ANI	0FH	;SEE IF TIME TO CRLF
	JRNZ	..D1
	JMPR	..D0
;
; THIS OUTPUTS THE END OF FILE (EOF) PATTERN
; FOR THE CHECKSUM LOADER. IT IS USED AFTER
; PUNCHING A BLOCK OF MEMORY WITH THE 'W'
; COMMAND.  AN ADDRESS PARAMETER MAY BE GIVEN,
; WHICH WILL BE INCLUDED IN THE END FILE.
;
EOF:	CPI	'E'	;SEE IF 'EOF'
	JRNZ	FILL
	CALL	EXPR1	;GET OPTIONAL ADDR.
	CALL	PEOL	;CRLF TO PUNCH
	MVI	C,':'	;FILE MARKER CUE
	CALL	PO
	XRA	A	;ZERO LENGTH
	CALL	PBYTE
	POP	H
	CALL	PADR	;PUNCH OPTIONAL ADDR.
	XRA	A	;FILE TYPE=0
	CALL	PBYTE	;PUNCH IT
	JMP	NULL	;TRAILER & RETURN
;
; THIS COMMAND WILL FILL A BLOCK OF MEMORY
; WITH A VALUE. IE; F0,1FFF,0  FILLS FROM
; <1> TO <2> WITH THE BYTE <3>. HANDY FOR
; INITIALIZING A BLOCK TO A SPECIFIC VALUE, OR
; MEMORY TO A CONSTANT VALUE BEFORE LOADING
; A PROGRAM. (ZERO IS ESPECIALLY USEFUL.)
;
FILL:	CPI	'F'	;SEE IF 'FILL'
	JRNZ	GOTO
	CALL	EXPR3	;GET 3 PARAMETERS
..F:	MOV	M,C	;STORE THE BYTE
	CALL	HILO
	JRNC	..F
	POP	D	;RESTORE STACK
	JMPR	START	; IN CASE OF ACCIDENTS
;
; THIS COMMAND ALLOWS EXECUTION OF ANOTHER
; PROGRAM.
;
GOTO:	CPI	'G'	;SEE IF 'GOTO'
	JRNZ	TEST
	CALL	EXPR1	;GET AN ADDRESS TO GO TO
	JMP	CRLF	;CRLF & EXECUTE
;
; THIS IS A 'QUICKIE' MEMORY TEST TO SPOT
; HARD MEMORY FAILURES, OR ACCIDENTLY
; PROTECTED MEMORY LOCATIONS. IT IS NOT
; MEANT TO BE THE DEFINITIVE MEMORY DIAGNOSTIC.
; IT IS, HOWEVER, NON-DESTRUCTIVE. ERRORS ARE
; PRINTED ON THE CONSOLE AS FOLLOWS-
; "<ADDR> 04" WHERE, IN THIS PARTICULAR
; EXAMPLE, BIT 2 IS THE BAD BIT.
; BIT LOCATION OF THE FAILURE IS EASILY
; DETERMINED. NON-R/W MEMORY WILL DISPLAY
; <ADDR>  FF  (ALL BITS BAD)
;
TEST:	CPI	'J'	;SEE IF 'TEST'
	JRNZ	MOVE
	CALL	EXLF	;GET TWO PARAMS
..T1:	MOV	A,M	;READ A BYTE
	MOV	B,A	;SAVE IN B REG.
	CMA
	MOV	M,A	;READ/COMPLIMENT/WRITE
	XRA	M	; & COMPARE
	JRZ	..T2	;SKIP IF ZERO (OK)
	EXAF		;SAVE BAD BYTE
	CALL	HLSP	;PRINT BAD ADDR
	EXAF		;GET BAD BYTE BACK
	CALL	LBYTE	;PRINT IT
	CALL	CRLF
..T2:	MOV	M,B	;REPLACE BYTE
	CALL	HILOX	;RANGE TEST
	JMPR	..T1
;
; THIS COMMAND MOVES MASS AMOUNTS OF MEMORY
; FROM <1> THRU <2> TO THE ADDRESS STARTING
; AT <3>.  THIS ROUTINE SHOULD BE USED WITH
; SOME CAUTION, AS IT COULD SMASH MEMORY IF
; CARELESSLY IMPLEMENTED.
;
;	M<1>,<2>,<3>
;
MOVE:	CPI	'M'	;SEE IF 'MOVE'
	JRNZ	READ
	CALL	EXPR3	;GET 3 PARAMETERS
..M:	MOV	A,M	;PICK UP
	STAX	B	;PUT DOWN
	INX	B	;MOVE UP
	CALL	HILOX	;CHECK IF DONE
	JMPR	..M
;
; THIS COMMAND READS THE CHECK-SUMMED HEX FILES
; FOR BOTH THE NORMAL INTEL FORMAT AND THE TDL
; RELOCATING FORMAT. ON BOTH FILES, A 'BIAS' MAY
; BE ADDED, WHICH WILL CAUSE THE OBJECT CODE TO
; BE PLACED IN A LOCATION OTHER THAN ITS
; INTENDED EXECUTION LOCATION. THE BIAS IS ADDED TO
; WHAT WOULD HAVE BEEN THE NORMAL LOADING
; LOCATION, AND WILL WRAP AROUND TO ENABLE
; LOADING ANY PROGRAM ANYWHERE IN MEMORY.
;
; WHEN LOADING A RELOCATABLE FILE, AN ADDITIONAL
; PARAMETER MAY BE ADDED, WHICH REPRESENTS THE
; ACTUAL EXECUTION ADDRESS DESIRED. THIS ALSO MAY
; BE ANY LOCATION IN MEMORY.
;
; EXAMPLES:
;
; R[CR] =0 BIAS, 0 EXECUTION ADDR.
; R<ADDR1>[CR] =<1>BIAS, 0 EXECUTION ADDR.
; R,<ADDR1>[CR] =0 BIAS, <1> EXECUTION ADDR.
; R<ADDR1>,<ADDR2>[CR] =<1>BIAS, <2> EXECUTION ADDR.
;
READ:	CPI	'R'	;SEE IF 'READ' COMMAND
	JNZ	SUBS
	CALL	EXPR1	;GET BIAS, IF ANY
	MOV	A,B	;LOOK AT DELIMITER
	SUI	CR	;ALL DONE?
	MOV	B,A	;SET UP RELOCATION OF 0
	MOV	C,A	; IF CR ENTERED
	POP	D	;BIAS AMOUNT
	JRZ	..R0	;CR ENTERED
	CALL	EXPR1	;GET RELOCATION
	POP	B	;ACTUAL RELOCATION VALUE
..R0:	XCHG
	EXX		;HL'=BIAS, BC'=RELOCATION
	CALL	CRLF
LOD0:	CALL	RIFF	;GET A CHARACTER
	ANI	7FH	;KILL PARITY BIT
	SUI	':'	;ABSOLUTE FILE CUE?
	MOV	B,A	;SAVE CUE CLUE
	ANI	0FEH	;KILL BIT 0
	JRNZ	LOD0	; NO, KEEP LOOKING
	MOV	D,A	;ZERO CHECKSUM
	CALL	SBYTE	;GET FILE LENGTH
	MOV	E,A	;SAVE IN E REG.
	CALL	SBYTE	;GET LOAD MSB
	PUSH	PSW	;SAVE IT
	CALL	SBYTE	;GET LOAD LSB
	EXX		;CHANGE GEARS
	POP	D	;RECOVER MSB
	MOV	E,A	;FULL LOAD ADDR
	PUSH	B	;BC'=RELOCATION
	PUSH	D	;DE'=LOAD ADDR
	PUSH	H	; HL'=BIAS
	DAD	D	; BIAS+LOAD
	XTHL		;RESTORE HL'
	POP	X	; X=BIAS+LOAD
	EXX		;DOWNSHIFT
	POP	H	;HL=LOAD ADDR
	CALL	SBYTE	;GET FILE TYPE
	DCR	A	;1=REL. FILE, 0=ABS.
	MOV	A,B	;SAVE CUE BIT
	POP	B	;BC=RELOCATION
	JRNZ	..A	;ABSOLUTE FILE
	DAD	B	;ELSE RELOCATE
	DADX	B	;BOTH X & HL
..A:	INR	E	;TEST LENGTH
	DCR	E	;0=DONE
	RZ
	DCR	A	;TEST CUE
	JRZ	LODR	;RELATIVE
..L1:	CALL	SBYTE	;NEXT
	CALL	STORE	;STORE IT
	JRNZ	..L1	;MORE COMING
LOD4:	CALL	SBYTE	;GET CHECKSUM
	JRZ	LOD0	;GOOD CHECKSUM
	JMP	ERROR	;BAD, ABORT
LODR:	MVI	L,1	;SET-UP BIT COUNTER
..L1:	CALL	LODCB	;GET THE BIT
	JRC	..L3	;DOUBLE BIT
..L5:	CALL	STORE	;WRITE IT
	JRNZ	..L1
	JMPR	LOD4	;TEST CHECKSUM
..L3:	MOV	C,A	;SAVE LOW BYTE
	CALL	LODCB	;NEXT CONTROL BIT
	MOV	B,A	;SAVE HIGH BYTE
	EXX
	PUSH	B	;GET RELOCATION
	EXX
	XTHL		;INTO HL
	DAD	B	;RELOCATE
	MOV	A,L	;LOW BYTE
	CALL	STORE	;STORE IT
	MOV	A,H	;HIGH BYTE
	POP	H	;RESTORE HL
	JMPR	..L5	;DO THIS AGAIN
LODCB:	DCR	L	;COUNT BITS
	JRNZ	..LC1	;MORE LEFT
	CALL	SBYTE	;GET NEXT
	DCR	E	;COUNT BYTES
	MOV	H,A	;SAVE THE BITS
	MVI	L,8	;8 BITS/BYTE
..LC1:	CALL	SBYTE	;GET A DATA BYTE
	SLAR	H	;TEST NEXT BIT
	RET
SBYTE:	PUSH	B	;PRESERVE BC
	CALL	RIBBLE	;GET A CONVERTED ASCII CHAR.
	RLC
	RLC
	RLC
	RLC		;MOVE IT TO HIGH NIBBLE
	MOV	C,A	;SAVE IT
	CALL	RIBBLE	;GET OTHER HALF
	ORA	C	;MAKE WHOLE
	MOV	C,A	;SAVE AGAIN IN C
	ADD	D	;UPDATE CHECKSUM
	MOV	D,A	;NEW CHECKSUM
	MOV	A,C	;CONVERTED BYTE
	POP	B
	RET
STORE:	MOV	0(X),A	;WRITE TO MEMORY
	INX	X	;ADVANCE POINTER
	DCR	E	;COUNT DOWN
	RET
;
; THIS ROUTINE ALLOWS BOTH INSPECTION OF &
; MODIFICATION OF MEMORY ON A BYTE BY BYTE
; BASIS. IT TAKES ONE ADDRESS PARAMETER,
; FOLLOWED BY A SPACE.  THE DATA AT THAT
; LOCATION WILL BE DISPLAYED. IF IT IS
; DESIRED TO CHANGE IT, THE VALUE IS THEN
; ENTERED.  A FOLLOWING SPACE WILL DISPLAY
; THE NEXT BYTE.  A CARRIAGE RETURN [CR]
; WILL TERMINATE THE COMMAND.  THE SYSTEM
; ADDS A CRLF AT LOCATIONS ENDING WITH EITHER
; XXX0 OR XXX8. TO AID IN DETERMINING THE
; PRESENT ADDRESS, IT IS PRINTED AFTER
; EACH CRLF.  A BACKARROW [_] WILL BACK
; UP THE POINTER AND DISPLAY THE
; PREVIOUS LOCATION.
;
SUBS:	CPI	'S'	;SEE IF 'SUBSTITUTE'
	JRNZ	WRITE
	CALL	EXPR1	;GET STARTING ADDR.
	POP	H
..S0:	MOV	A,M
	CALL	LBYTE	;DISPLAY THE BYTE
	CALL	COPCK	;MODIFY?
	RC		; NO, ALL DONE
	JRZ	..S1	;DON'T MODIFY
	CPI	'_'	;BACKUP?
	JRZ	..S2
	PUSH	H	;SAVE POINTER
	MVI	C,1
	LXI	H,0
	CALL	EX1	;GET NEW VALUE
	POP	D	;VALUE IN E
	POP	H
	MOV	M,E	;MODIFY
	MOV	A,B	;TEST DELIMITER
	CPI	CR
	RZ		;DONE
..S1:	INX	H
..S3:	MOV	A,L	;SEE IF TIME TO CRLF
	ANI	7
	CZ	LFADR	;TIME TO CRLF
	JMPR	..S0
..S2:	DCX	H	;DECREMENT POINTER
	JMPR	..S3	;AND PRINT DATA THERE.
;
;
; THIS ROUTINE DUMPS MEMORY IN THE STANDARD
; INTEL HEX-FILE FORMAT.  A START & END
; PARAMETER IS REQUIRED. AT THE CONCLUSION
; OF THE DUMP, AN "END OF FILE" SHOULD BE
; GENERATED WITH THE "E" COMMAND.
;
WRITE:	CPI	'W'	;SEE IF 'WRITE' COMMAND
	JRNZ	SIZE
	CALL	EXLF	;GET TWO PARAMETERS
	CALL	CI	;PAUSE FOR PUNCH-ON
..W0:	CALL	PEOL	;CRLF TO PUNCH
	LXI	B,':'	;START-OF-FILE CUE
	CALL	PO	;PUNCH IT
	PUSH	D	;SAVE
	PUSH	H	; POINTERS
..W1:	INR	B	;CALCULATE FILE LENGTH
	CALL	HILO
	JRC	..W4	;SHORT FILE
	MVI	A,24	;24 BYTES PER FILE
	SUB	B	;ENOUGH YET?
	JRNZ	..W1	; NO.
	POP	H	;GET START ADDR BACK.
	CALL	..W2	;SEND THE BLOCK
	POP	D	;RESTORE END OF FILE POINTER
	JMPR	..W0	;KEEP GOING
..W2:	MOV	D,A	;INITIALIZE CHECKSUM
	MOV	A,B	;FILE LENGTH
	CALL	PBYTE	;PUNCH IT
	CALL	PADR	;PUNCH ADDRESS
	XRA	A	;FILE TYPE=0
	CALL	PBYTE	;PUNCH IT
..W3:	MOV	A,M	;GET A DATA BYTE
	CALL	PBYTE	;PUNCH IT
	INX	H	;POINT TO NEXT BYTE
	DJNZ	..W3	;DECREMENT FILE COUNT
	XRA	A
	SUB	D	;CALCULATE CHECKSUM
	JMP	PBYTE	;PUNCH IT, RETURN
..W4:	POP	H	;CLEAR STACK
	POP	D	; OF POINTERS
	XRA	A	;SET-UP A
	JMPR	..W2	;FINISH UP & RETURN
;
;
; THIS IS A MESSAGE OUTPUT ROUTINE.
; IT IS USED BY THE SIGN-ON AND CRLF.
; POINTER IS IN HL (WHEN ENTERED AT
; TOM1) AND LENGTH IN B REG.
;
TOM:	LXI	H,MSG
TOM1:	MOV	C,M	;GET A CHARACTER
	INX	H	;MOVE POINTER
	CALL	CO	;OUTPUT IT
	DJNZ	TOM1	;KEEP GOING TILL B=0
	CALL	CSTS	;SEE IF AN ABORT REQUEST
	ORA	A	; WAITING.
	RZ		;NO.
;
; SEE IF CONTROL-C IS WAITING
; ABORT IF SO.
;
	CALL	CI
	ANI	7FH	;KILL PARITY BIT
	CPI	3	;CONTROL-C?
	RNZ
;
ERRX:	JMP	ERROR
;
;
; THIS GETS A READER CHARACTER,
; AND COMAPRES IT WITH 'D' REG.
; IT ABORTS ON AN 'OUT-OF-DATA'
; CONDITION.
;
RIFF:	CALL	RI	;GET READER CHARACTER
	JRC	ERRX	;ABORT ON CARRY
	CMP	D	;TEST D
	RET
;
; THIS ROUTINE WILL RETURN THE
; CURRENT VALUE OF THE HIGHEST
; READ/WRITE MEMORY LOCATION THAT
; IS AVAILABLE ON THE SYSTEM.
; IT WILL "SEARCH" FOR MEMORY
; STARTING AT THE BOTTOM OF MEMORY
; AND GO UPWARDS UNTIL NON-R/W MEMORY
; IS FOUND.
;
SIZE:	CPI	'Z'	;SEE IF 'SIZE' COMMAND
	JRNZ	UNLD
	CALL	MEMSIZ	;GET THE VALUE
;
;
; CRLF BEFORE HLSP ROUTINE
;
LFADR:	CALL	CRLF
;
; PRINT THE CURRENT VALUE OF H&L,
; AND A SPACE.
;
HLSP:	CALL	LADR
;
; PRINT A SPACE ON THE CONSOLE
;
BLK:	MVI	C,' '
;
; THIS IS THE MAIN CONSOLE
; OUTPUT ROUTINE.
; TELEPRINTER CONFIGURATION
; I/O DRIVER.
;
CO:	IN	TTS
	ANI	TTYBE
	JRNZ	CO
	MOV	A,C
	OUT	TTO
	RET
;
; SEND CRLF TO PUNCH DEVICE
;
PEOL:	MVI	C,CR
	CALL	PO
	MVI	C,LF
;
; THIS IS THE 'PUNCH' OUTPUT
; DRIVER. IT IS SET UP FOR THE
; TTY PORTS, BUT MAY BE MODIFIED
; FOR ANOTHER PORT, FOR TRUE
; SEPARATION OF THE CONSOLE
; AND READER/PUNCH DEVICES.
;
; (I.E. - PORT 6 & 7 FOR CASSETTE, ETC.)
;
PO:	IN	TTS	;STATUS PORT
	ANI	TTYBE	;TRANSMITTER BUFFER EMPTY?
	JRNZ	PO	;IF NOT, LOOP.
	MOV	A,C	;GET CHARACTER TO OUTPUT
	OUT	TTO	;TO DATA PORT
	RET		;DONE
;
; THIS IS A BINARY DUMP ROUTINE THAT MAY BE
; USED WITH BOTH PAPER-TAPE AND/OR CASSETTE
; SYSTEMS.  IT PUNCHES A START-OF-FILE MARK
; AND THEN PUNCHES IN FULL 8-BITS DIRECTLY
; FROM MEMORY.  IT IS FOLLOWED BY AN END-OF-
; FILE MARKER. THESE DUMPS MAY BE LOADED
; USING THE "L" COMMAND. THEY ARE USEFUL
; FOR FAST LOADING.
;
;	U<A1>,<A2>[CR]
; PUNCHES FROM <A1> THRU <A2>
;
UNLD:	CPI	'U'	;SEE IF 'UNLOAD' COMMAND
	JRNZ	NULLX
	CALL	EXLF	;GET TWO PARAMETERS
	CALL	CI	;PAUSE FOR PUNCH-ON (TTY)
	CALL	LEAD	;PUNCH LEADER
	CALL	MARK	;PUNCH FILE MARKER
..U:	MOV	C,M	;GET MEMORY BYTE
	CALL	PO	;PUNCH IT
	CALL	HILO	;SEE IF DONE
	JRNC	..U
	CALL	MARK	;PUNCH END FILE MARKER
	JMPR	NULL
;
; THIS PUNCHES NULLS (LEADER/TRAILER).
; IT RETURNS "QUIET"
;
NULLX:	CPI	'N'	;SEE IF 'NULL'
	JRNZ	HEXN
NULL:	CALL	LEAD	;PUNCH NULLS
	JMP	STAR0	;RETURN QUIET
;
; CONVERT HEX TO ASCII
;
CBYTE:	RRC
	RRC
	RRC
	RRC
;
CONV:	ANI	0FH	;LOW NIBBLE ONLY
	ADI	90H
	DAA
	ACI	40H
	DAA
	MOV	C,A
	RET
;
; GET TWO PARAMETERS, PLACE
; THEM IN DE & HL, AND THEN
; CRLF.
;
EXLF:	CALL	EXPR
	POP	D
	POP	H
;
; CONSOLE CARRIAGE RETURN &
; LINE FEED ROUTINE.
;
; THE NUMBER OF FILL CHARACTERS
; MAY BE ADJUSTED TO 0-3 BY THE
; VALUE PLACED IN THE B REG. MINIMUM
; VALUE FOR "B" IS TWO (2). MAXIMUM
; IS FIVE (5).
;
CRLF:	PUSH	H	;SAVE HL
	PUSH	B	; & BC
	MVI	B,4	;CRLF LENGTH (SET FOR 2 FILLS)
	CALL	TOM	;SEND CRLF
	POP	B
	POP	H
	RET
;
; TEST THE CONSOLE'S
; KEYBOARD FOR A KEY-PRESS.
; RETURN TRUE (0FFH IN A REG)
; IF THERE IS A CHARACTER
; WAITING.
;
CSTS:	IN	TTS
	ANI	TTYDA
	MVI	A,FALSE
	RNZ		;MAY NEED PATCHING***
	CMA		;IF DIFFERENT I/O USED
	RET
;
; GET THREE PARAMETERS AND
; CRLF.
;
EXPR3:	INR	C
	CALL	EXPR
	CALL	CRLF
	POP	B
	POP	D
	POP	H
	RET
;
; GET ONE PARAMETER.
; NO CRLF.
;
EXPR1:	MVI	C,1
;
; THIS IS THE MAIN "PARAMETER-GETTING" ROUTINE.
; THIS ROUTINE WILL ABORT ON A NON-HEX CHARACTER.
; HEX CHARACTERS, AND PLACES THEM UP ON THE STACK.
; (AS ONE 16 BIT VALUE, CONTAINED IN TWO
; 8-BIT BYTES.)  IF A CARRIAGE RETURN IS ENTERED,
; IT WILL PLACE THE VALUE OF "0000" IN THE STACK.
;
EXPR:	LXI	H,0	;INITIALIZE HL TO ZERO
EX0:	CALL	TI	;GET SOMETHING FROM CONSOLE
EX1:	MOV	B,A	;SAVE IT
	CALL	NIBBLE	;CONVERT ASCII TO HEX.
	JRC	..EX2	;ILLEGAL CHARACTER DETECTED
	DAD	H	;MULTIPLY BY 16
	DAD	H
	DAD	H
	DAD	H
	ORA	L	;OR IN THE SINGLE NIBBLE
	MOV	L,A
	JMPR	EX0	;GET SOME MORE
..EX2:	XTHL		;SAVE UP IN STACK
	PUSH	H	;REPLACE THE RETURN
	MOV	A,B	;TEST THE DELIMITER
	CALL	QCHK
	JRNC	..EX3	;DELIMITER ENTERED?
	DCR	C	;CR, SHOULD GO TO ZERO
	RZ		; RETURN IF IT DOES
..EX3:	JNZ	ERROR	;SOMETHING WRONG
	DCR	C	;DO THIS AGAIN?
	JRNZ	EXPR	; YES.
	RET		;ELSE RETURN
;
; RANGE TESTING ROUTINES.
; CARRY SET INDICATES RANGE EXCEEDED.
;
HILOX:	CALL	HILO
	RNC		;OK
	POP	D	;RETURN ONE LEVEL BACK
	RET
;
HILO:	INX	H	;INCREMENT HL
	MOV	A,H	;TEST FOR CROSSING 64K BORDER
	ORA	L
	STC		;CARRY SET=STOP
	RZ		;YES, BORDER CROSSED
	MOV	A,E	;NOW, TEST HL VS. DE
	SUB	L
	MOV	A,D
	SBB	H
	RET		;IF CARRY WAS SET, THEN STOP
;
;	HEXADECIMAL MATH ROUTINE
;
; THIS ROUTINE IS USEFUL FOR
; DETERMINING RELATIVE JUMP
; OFFSETS.  IT RETURNS THE SUM
; & DIFFERENCE OF TWO PARAMETERS.
;
;	H<X>,<Y>
;
;  X+Y	X-Y
;
HEXN:	CPI	'H'	;SEE IF HEX MATH
	JNZ	LOAD
	CALL	EXLF
	PUSH	H	;SAVE HL FOR LATER
	DAD	D	;GET SUM
	CALL	HLSP	;PRINT IT
	POP	H	;THIS IS LATER
	ORA	A	;CLEAR CARRY
	DSBC	D	;GET DIFFERENCE & PRINT IT
;
; PRINT H&L ON CONSOLE
;
LADR:	MOV	A,H
	CALL	LBYTE
	MOV	A,L
LBYTE:	PUSH	PSW
	CALL	CBYTE
	CALL	CO
	POP	PSW
	CALL	CONV
	JMP	CO
;
; THIS ROUTINE SENDS EIGHT RUBOUTS
; TO THE PUNCH DEVICE.
;
MARK:	LXI	B,08FFH ;SET-UP B&C
	JMPR	LE0
;
; THIS ROUTINE SENDS BLANKS TO THE
; PUNCH DEVICE.
;
LEAD:	LXI	B,4800H ;PRESET FOR SOME NULLS
LE0:	CALL	PO
	DJNZ	LE0
	RET
;
; THIS ROUTINE RETURNS TO A USER
; PROGRAM THE CURRENT TOP OF
; MEMORY VALUE MINUS WORKSPACE
; AREA USED BY THE MONITOR.
;
MEMCK:	PUSH	H
	CALL	MEMSIZ
	MOV	B,H
	MVI	A,0C0H	;LEAVE SOME ROOM FOR STACK
	POP	H
	RET
;
;	WE BEGIN IN THE MIDDLE......
;
BEGIN:	MVI	A,I	;INITIAL 'I' REG. VALUE
	STAI		;NEEDED IF USING INTERUPT.
	XRA	A	;CLEAR READER CONTROL
	OUT	RCP	; PORT.
	LXI	SP,STACK	;SET UP A FAKE STACK
;
	.BYTE	(MVI)		;SKIP OVER PUSH
;
; THIS IS A CALLED ROUTINE USED
; TO CALCULATE THE TOP OF MEMORY
; STARTING FROM THE BOTTOM OF
; MEMORY, AND SEARCHING UPWARD UNTIL
; FIRST R/W MEMORY IS FOUND, AND THEN
; CONTINUING UNTIL THE END OF THE R/W
; MEMORY. THIS ALLOWS R.O.M. AT ZERO,
; AND INSURES A CONTINUOUS MEMORY BLOCK
; HAS BEEN FOUND.
; IT IS USED BY THE ERROR ROUTINE TO
; RESET THE STACK POINTER.
;
MEMSIZ: PUSH	B
	LXI	B,ZAP	;POINT TO START OF MONITOR
	LXI	H,-1	;RAM SEARCH STARTING PT.-1
..M0:	INR	H	;FIRST FIND R/W MEMORY
	MOV	A,M
	CMA
	MOV	M,A
	CMP	M
	CMA
	MOV	M,A
	JRNZ	..M0
..M1:	INR	H	;R/W FOUND, NOW FIND END
	MOV	A,M
	CMA
	MOV	M,A
	CMP	M
	CMA
	MOV	M,A
	JRNZ	..M2
	MOV	A,H	;TEST FOR MONITOR BORDER
	CMP	B
	JRNZ	..M1	;NOT THERE YET
..M2:	DCR	H	;BACK UP
	POP	B
	RET		;VALUE IN HL
;
; THIS GETS A READER CHARACTER, AND
; CONVERTS IT FROM ASCII TO HEX.
;
RIBBLE: CALL	RIFF
	ANI	7FH
NIBBLE: SUI	'0'	;QUALIFY & CONVERT
	RC		;<0
	CPI	'G'-'0' ;>F?
	CMC		;PERVERT CARRY
	RC
	CPI	10	;NMBR?
	CMC		;PERVERT AGAIN
	RNC		;RETURN CLEAN
	SUI 'A'-'9'-1	;ADJUST
	CPI	10	;FILTER ":" THRU "@"
	RET
;
; SEND H&L VALUE TO PUNCH DEVICE
;
PADR:	MOV	A,H
	CALL	PBYTE
	MOV	A,L
;
; PUNCH A SINGLE BYTE
;
PBYTE:	PUSH	PSW	;NIBBLE AT A TIME
	CALL	CBYTE
	CALL	PO
	POP	PSW	;NEXT NIBBLE
	PUSH	PSW	;SAVE FOR CHECKSUM
	CALL	CONV
	CALL	PO
	POP	PSW	;ORIGINAL BYTE HERE
	ADD	D	;ADDED TO CHECKSUM
	MOV	D,A	;UPDATE CHECKSUM
	RET
;
;
COPCK:	MVI	C,'-'
	CALL	CO
	CALL	TI
;
; TEST FOR DELIMITERS
;
QCHK:	CPI	' '	;RETURN ZERO IF DELIMITER
	RZ
	CPI	','
	RZ
	CPI	CR	;RETURN W/CARRY SET IF CR
	STC
	RZ
	CMC		;ELSE NON-ZERO, NO CARRY
	RET
;
; MAIN CONSOLE INPUT ROUTINE
;
CI:	IN	TTS
	ANI	TTYDA
	JRNZ	CI
	IN	TTI
	RET
;
; READER INPUT ROUTINE, WITH
; TIME-OUT DELAY. INCLUDES
; PULSING OF HARDWARE PORT
; TO INDICATE REQUEST FOR
; READER DATA.
;
; THIS MAY BE ALTERED TO ANY
; I/O PORT CONFIGURATION TO ENABLE
; SEPARATE READER/PUNCH DEVICE.
;
RI:	PUSH	H
	MVI	A,0FFH	;MAY BE ALTERED TO SUIT
	OUT	RCP	;PULSE READER CONTROL PORT
	XRA	A	;CLEAR IT
	OUT	RCP
	MOV	H,A	;CLEAR FOR TIME-OUT TEST
RI0:	IN	TTS	;MAY BE MODIFIED ***
	ANI	TTYDA	;BUT ALWAYS USE 'ANI'
	JRZ	RI2	;TO CLEAR CARRY
	PUSH	B
	MVI	B,0FFH	;SHORTEN FOR HIGH-SPEED DEVICE
DL0:	XTHL		;WASTE TIME
	XTHL		;FOR DELAY
	DJNZ	DL0
	POP	B
	DCR	H
	JRNZ	RI0
RI1:	STC		;*NOTE: CARRY SET TO INDICATE
			; NO DATA.
RI2:	IN	TTI
RID:	POP	H
	RET
;
; THIS ROUTINE READS A BINARY FILE
; IMAGE, IN THE FORM AS PUNCHED IN
; THE "U" (UNLOAD) COMMAND.  IT TAKES
; ONE PARAMETER, WHICH IS THE STARTING
; ADDRESS OF THE LOAD, AND WILL PRINT
; THE LAST ADDRESS(+1) LOADED ON THE
; CONSOLE DEVICE.
;
LOAD:	CPI	'L'	;SEE IF 'LOAD' COMMAND
	JRNZ	NEXT
	CALL	EXPR1	;INITIAL LOAD ADDRESS
	POP	H
	CALL	CRLF
	MVI	D,0FFH	;START-OF-FILE TAG
..L0:	MVI	B,4	;FIND AT LEAST FOUR 0FFH'S
..L1:	CALL	RIFF
	JRNZ	..L0
	DJNZ	..L1
..L2:	CALL	RIFF	;4 FOUND, NOW WAIT FOR NON-0FFH
	JRZ	..L2
	MOV	M,A	;FIRST REAL DATA BYTE
	MVI	A,BELL	;TELL TTY
	OUT	TTO
..L3:	INX	H
	CALL	RIFF
	JRZ	..EL	;POSSIBLE END OF FILE
	MOV	M,A
	JMPR	..L3
..EL:	MVI	B,1	;INITIALIZE
..EL0:	CALL	RIFF
	JRNZ	..EL1
	INR	B	;COUNT QUES
	MVI	A,MAX	;LOOK FOR EOF
	CMP	B	;FOUND MAX?
	JRNZ	..EL0	;NOPE
	JMP	LADR	;YEP, PRINT END ADDR
..EL1:	MOV	M,D
	INX	H
	DJNZ	..EL1
	MOV	M,A	;REAL BYTE
	JMPR	..L3
;
;
; THIS IS THE INTERNAL KEYBOARD
; HANDLING ROUTINE. IT WILL IGNORE
; RUBOUTS (0FFH) AND BLANKS (00),
; AND IT WILL NOT ECHO CR'S & N'S.
; (NO N'S FOR THE "NULL" COMMAND).
; IT CONVERTS LOWER CASE TO UPPER
; CASE FOR THE LOOK-UP OF COMMANDS.
;
; OTHER CHARACTERS ARE ECHOED AS THEY
; ARE RECIEVED.
;
TI:	CALL	CI
	ANI	7FH	;KILL PARITY BIT
	INR	A	;IGNORE RUBOUTS
	RM
	DCR	A	;IGNORE NULLS
	RZ
	CPI	'N'	;IGNORE N'S FOR NULL CMND
	RZ
	CPI	'n'
	JRZ	..T
	CPI	CR	;IGNORE CR'S
	RZ
	PUSH	B
	MOV	C,A
	CALL	CO
	MOV	A,C
	POP	B
	CPI	'A'-1	;CONVERT TO UPPER CASE
	RC
	CPI	'z'+1
	RNC
..T:	ANI	05FH
	RET
;
;
;
;
NEXT:	RET		;ADDITIONAL COMMANDS
			;MAY BE TESTED FROM HERE,
			;AND THE MONITOR EXTENDED
			;FROM BEYOND THIS POINT.
;
;
	Z:
			;END OF PROGRAM
;
;
;
.END	ZAP
;

