
;************************************************************************
;*									*
;*			UTILITY SUBROUTINES				*
;*									*
;************************************************************************

;			OSCOR-1
;			4 SEPTEMBER 1980
;			R. DAVID POGGE

			ORG 0400H

	; GLOBAL ADDRESSES

	ABORT	EQU	0008H
	INPUT	EQU	0046H
	MONIT	EQU	0040H
	OUTPUT	EQU	0043H

	; VARIABLES

	A2	EQU	8002H
	A3	EQU	8004H
	A4	EQU	8006H



	; QUOTE SUBROUTINE

QUOTE:	XTHL		; MOVE SUBROUTINE RETURN ADDRESS TO H&L
FETCH:	MOV A,M		; FETCH ASCII CODE
	INX H		; INCREMENT H&L TO POINT TO NEXT CODE OR RETURN ADDRESS
	ANA A		; SET ZERO FLAG IF A=0
	JZ RETURN	; IF ASCII CODE IS NULL, GO TO "RETURN"
	CALL OUTPUT	; IF NOT NULL, PRINT IT
	JMP FETCH	; THEN FETCH NEXT CODE
RETURN:	XTHL		; PUT RETURN ADDRESS ON STACK
	RET		; RETURN FROM SUBROUTINE




	; HEX TO ASCII SUBROUTINE

HEX2A:	ADI 30H		; CONVERTS NUMBERS 0 TO 9
	CPI 3AH		; BY ADDING 30
	RC		; IF ASCII 0 TO 9, THEN RETURN
	ADI 7H		; IF ASCII A TO F, THEN ADD 7 MORE
	RET		; AND RETURN



	; PRINT LOW NIBBLE SUBROUTINE

PLNIB:	ANI 0FH		; MASK HIGH ORDER BITS
	CALL HEX2A	; CONVERT LOW NIBBLE TO ASCII
	JMP OUTPUT	; PRINT IT AND RETURN




	; PRINT HIGH NIBBLE SUBROUTINE

PHNIB:	RRC		; MOVE HIGH NIBBLE INTO LOW NIBBLE
	RRC
	RRC
	RRC
	JMP PLNIB	; PRINT IT USING "PRINT LOW NIBBLE" AND RETURN




	; PRINT HEX SUBROUTINE

PHEX:	PUSH PSW	; STORE ACCUM ON STACK
	CALL PHNIB	; PRINT HIGH NIBBLE
	POP PSW		; RESTORE ACCUMULATOR
	JMP PLNIB	; PRINT LOW NIBBLE AND RETURN




	; PRINT H/L REGISTER PAIR SUBROUTINE

PHLREG:	MOV A,H
	CALL PHEX	; PRINT H REGISTER
	MOV A,L
	JMP PHEX	; PRINT L REGISTER




	; ASCII TO HEX SUBROUTINE

A2HEX:	SUI 30H		; SUBTRACT #30
	CC ABORT	; IF ASCII < 0, THEN ABORT
	CPI 0AH		; IF ASCII 0-9
	RC		; THEN RETURN
	SUI 7H		; SUBTRACT 7 MORE
	CPI 0AH		; IF ASCII ":" THROUGH "@"
	CC ABORT	; THEN ABORT
	CPI 10H		; IF ASCII "G" OR HIGHER
	CNC ABORT	; THEN ABORT
	RET		; OTHERWISE, RETURN



	; DUMP SUBROUTINE

DUMP:	LHLD A3		; LET D/E = A3
	XCHG
	LHLD A2		; LET H/L = A2
LINE:	MVI B,16	; LET B = WORD COUNTER (16 WORDS PER LINE)
	CALL PHLREG	; PRINT ADDRESS IN H/L
WORD:	MVI A,20H	; PRINT A SPACE
	CALL OUTPUT
	MOV A,M		; FETCH DATA POINTED TO BY H/L
	CALL PHEX	; PRINT IT
	INX H		; INCREMENT POINTER H/L
	MOV A,E		; COMPARE H/L TO D/E
	CMP L
	MOV A,D
	SBB H
	JC DMPRET	; IF H/L>D/E, THEN RETURN
	DCR B		; DECREMENT WORD COUNTER
	JNZ WORD	; IF NOT DONE, GOT TO "WORD"
	CALL QUOTE	; OTHERWISE, USE QUOTE TO
	DB 0DH		; PRINT A CARRIAGE RETURN
	DB 0AH		; AND LINE FEED
	DB 00H		; (NULL)
	JMP LINE	; AND GO TO "LINE"
DMPRET:	CALL QUOTE	; USE QUOTE TO PRINT 2 SPACES
	DB 20H		; <SP>
	DB 20H		; <SP>
	DB 00H		; (NULL)
	RET		; AND RETURN




	; H/L FILL SUBROUTINE

HLFILL:	PUSH PSW	; STORE ASCII CODE ON STACK
	CALL OUTPUT	; PRINT CHARACTER
	DAD H		; SHIFT H/L LEFT 4 TIMES
	DAD H
	DAD H
	DAD H
	POP PSW		; GET ASCII CODE FROM STACK
	CALL A2HEX	; CONVERT IT TO HEX
	ORA L		; APPEND TO REGISTER L
	MOV L,A
	RET		; AND RETURN









	; INPUT HEX DATA TO H/L REGISTER PAIR SUBROUTINE

INHL:	LXI H,0000H	; CLEAR H/L PAIR
INHL1:	CALL INPUT	; READ KEYBOARD
	CPI 20H
	RZ		; RETURN IF SPACE BAR
	CPI 0DH
	RZ		; OR RETURN IF <CR>
	CALL HLFILL	; OTHERWISE FILL H/L
	JMP INHL1	; AND READ KEYBOARD AGAIN




	; SURE? SUBROUTINE

SURE:	CALL QUOTE	; PROMPT WITH ". ARE YOU SURE? (Y/N)"
	DB 2EH		; .
	DB 20H		; <SP>
	DB 41H		; A
	DB 52H		; R
	DB 45H		; E
	DB 20H		; <SP>
	DB 59H		; Y
	DB 4FH		; O
	DB 55H		; U
	DB 20H		; <SP>
	DB 53H		; S
	DB 55H		; U
	DB 52H		; R
	DB 45H		; E
	DB 3FH		; ?
	DB 20H		; <SP>
	DB 28H		; (
	DB 59H		; Y
	DB 2FH		; /
	DB 4EH		; N
	DB 29H		; )
	DB 0DH		; <CR>
	DB 0AH		; <LF>
	DB 00H		; NULL
	CALL INPUT	; READ KEYBOARD
	CPI 59H		; COMPARE WITH ASCII "Y"
	JZ YES
NO:	CALL QUOTE
	DB 4EH		; N
	DB 4FH		; O
	DB 0DH		; <CR>
	DB 0AH		; <LF>
	DB 00H
	JMP MONIT




YES:	CALL QUOTE
	DB 59H		; Y
	DB 45H		; E
	DB 53H		; S
	DB 0DH		; <CR>
	DB 0AH		; <LF>
	DB 00H
	RET




	; BACK SUBROUTINE

	; THE INITIAL CONDITIONS FOR THIS SUBROUTINE ARE:
	; REG B/C = -N, WHERE N=NUMBER OF BYTES TO MOVE
	; REG D/E = A4, THE LAST ADDRESS OF THE DESTINATION BLOCK
	; REG H/L = A2, THE LAST ADDRESS OF THE SOURCE BLOCK

BACK:	MOV A,M		; (A2) GOES TO ACCUMULATOR
	STAX D		; ACCUMULATOR GOES TO (A4)
	DCX H		; DECREMENT POINTER A2
	DCX D		; DECREMENT POINTER A4
	INX B		; INCREMENT BYTE COUNTER
	XRA A		; CLEAR ACCUMULATOR
	ADD C		; IF BYTE COUNTER NOT ZERO
	JNZ BACK	; THEN GO TO "BACK"
	ADD B
	JNZ BACK
	RET		; OTHERWISE, RETURN




	; FORWARD SUBROUTINE

	; THE INITIAL CONDITIONS FOR THIS SUBROUTINE ARE:
	; REG B/C = -N, WHERE N = NUMBER OF BYTES TO MOVE
	; REG D/E = A3, THE FIRST ADDRESS OF THE DESTINATION BLOCK
	; REG H/L = A1, THE FIRST ADDRESS OF THE SOURCE BLOCK

FWD:	MOV A,M		; (A1) GOES TO ACCUMULATOR
	STAX D		; ACCUMULATOR GOES TO (A3)
	INX H		; INCREMENT POINTER A1
	INX D		; INCREMENT POINTER A3
	INX B		; INCREMENT BYTE COUNTER
	MVI A,0H
	ADD C		; IF BYTE COUNTER NOT ZERO
	JNZ FWD		; THEN GO TO "FWD"
	ADD B
	JNZ FWD
	RET		; OTHERWISE, RETURN



	END
 <LF>
	DB 00H
	JMP MONIT




YES:	CALL QUOTE
	DB 59H		; Y
	DB 45H		; E
	DB 53H	