
; THIS ROUTINE DOES THE ACTUAL SEEKING.

SEEK:	LD	HL,TRKTAB	; CURRENT TRACK TABLE
	LD	A,(HSTDSK)	; CURRENT DRIVE
	LD	C,A		; MAKE IT AN INDEX INTO
	LD	B,0		; TRACK TABLE
	ADD	HL,BC		; ADD IN INDEX
	LD	A,(HL)		; PULL OUT THE TRACK FOR THIS DRIVE
	OUT	(FDCTRK),A	; SEND IT TO THE CONTROLLER
	LD	B,A		; SAVE FOR LATER
	LD	A,(HSTTRK)	; GET THE SOUGHT-AFTER TRACK.
	LD	(HL),A		; PLACE IT IN TRACK TABLE
	CP	B		; SAME TRACK?
	RET	Z		; YES, NO NEED TO SEEK
	OUT	(FDCDAT),A	; AND GIVE IT TO THE CONTROLLER.
	LD	A,SEECMD	; THIS IS THE SEEK COMMAND
	OUT	(FDCCMD),A	; GIVE THE ORDER TO FDC

; NOW TEST FOR COMPLETION

	CALL	WAIT		; WAIT UNTIL NOT BUSY
	AND	SEEMSK		; AND OUT TRACK 0 BIT
	RET			; MAY HAVE FAILED

; THIS ROUTINE LOOPS UNTIL THE FDC IS
; IN A NON-BUSY STATE, OR UNTIL A NOT-
; READY CONDITION IS DETECTED.  TIME-OUT
; FOR DRIVE BUSY OCCURS AT APPROX.
; 1.5 SECONDS AFTER COMMAND
; INITIATION.

WAIT:	LD	A,15		; WE MUST DELAY ABOUT
WAIT10:	DEC	A		; 60 USECS. BEFORE READING 
	JR	NZ,WAIT10	; THE STATUS.

	LD	(TEMPBC),BC	; SAVE REGISTERS
	LD	(TEMPDE),DE
	LD	(TEMPHL),HL
	LD	BC,0C000H	; TIME OUT FOR 1.25 SECONDS
	LD	A,0
	LD	(JMPSW),A	; RESET THE FLAG FOR MESSAGE

WAIT20:	IN	A,(FDCCMD)	; READ THE FDC STATUS--2.75
	LD	(ERFLAG),A	; SAVE IT FOR LATER--3.25
	BIT	FDCRDY,A	; IS THE DEVICE NOT READY?--2.00
	JR	NZ,WAIT50	; YES, THIS IS AN ERROR--1.25

	PUSH	AF		; SAVE REGISTERS--2.75
	LD	A,(JMPSW)	; GET MESSAGE FLAG--3.25
	CP	0		; MESSAGE ALREADY SENT OUT?--1.75
	JR	NZ,WAIT30	; YES, SKIP--1.75
	DEC	BC		; COUNT DOWN--1.50
	LD	A,B		; --2.25
	OR	C		; TIME OUT?--1.00
	CALL	Z,SIGMSG	; YES, PRINT MESSAGE--2.50
WAIT40:	POP	AF		; RESTORE REGISTERS--2.50

	BIT	FDCBSY,A	; ARE WE PROCESSING A COMMAND?--2.00
	JR	NZ,WAIT20	; NO, RETURN ERROR CODE--3.00

	LD	(UNMSTA),A	; UNMASKED STATUS (FOR DEBUG)
	AND	ERRMSK		; MASK OFF NON-ERROR BITS
	LD	(ERFLAG),A	; SAVE STATUS FOR LATER

WAIT50:	LD	HL,(TEMPHL)	; RESTORE REGISTERS
	LD	DE,(TEMPDE)
	LD	BC,(TEMPBC)
	RET

WAIT30:	CALL	CONST		; CONSOLE STATUS
	CP	0		; AVAILABLE INPUT?
	JR	Z,WAIT40	; NO, SKIP
	CALL	CONIN		; GET CHARACTER
	CP	03H		; CONTROL-C?
	JR	NZ,WAIT40	; NO, LOOP BACK

	POP	AF		; RESTORE REGISTERS
	LD	HL,(TEMPHL)
	LD	DE,(TEMPDE)
	LD	BC,(TEMPBC)

	LD	A,FRCCMD	; FORCE TERMINATE
	OUT	(FDCCMD),A
	OUT	(FDCCMD),A
	CALL	RESDMA		; RESET DMA
	LD	A,0
	LD	(DEFDSK),A	; SET DEFAULT DRIVE TO A
	JP	WBOOT		; WARM-BOOT

; THIS ROUTINE PRINTS DOOR MESSAGE WHEN THERE IS AN ACCESS TO
; A DRIVE WITH DOOR OPENED

SIGMSG:	LD	A,1		; SET FLAG
	LD	(JMPSW),A
	LD	A,(HSTDSK)	; CURRENT DRIVE
	ADD	A,41H		; MAKE IT ASCII
	LD	(VDRIVE),A	; SAVE FOR LATER
	LD	HL,RDYMSG	; PRINT DOOR MESSAGE
	CALL	PRTMSG
	RET

; SELECT THE PROPER SIDE OF THE
; DISKETTE TO SEEK, DEPENDING ON
; THE LOGICAL SECTOR NO. IN HSTSEC.
; GO AHEAD AND SET THE FDC SECTOR
; REGISTER.

SELSID:	LD	A,(FDDBYT)	; GET THE DRIVE SELECT LATCH IN MEMORY
	LD	C,A		; HOLD IT IN C FOR A BIT.
	RES	2,C		; CHOOSE SIDE 0, FOR NOW.
	LD	A,(HSTSEC)	; GET THE LOGICAL HOST SECTOR 
	CP	PSPT0		; SECTOR >= THAN MAXIMUM SECTOR?
	JR	C,SELS10	; IF NOT THEN SELECT SIDE 0
	SET	2,C		; CHOOSE SIDE 1.
	SUB	PSPT0		; DE-BIAS SECTOR NO.

SELS10:	INC	A		; PHYSICAL SECTORS HAVE ORIGIN 1
	OUT	(FDCSEC),A	; SEND SECTOR TO CONTROLLER
	LD	(TSEC),A	; SAVE FOR LATER
	LD	A,C		; GET NEW SIDE.
	LD	(FDDBYT),A	; RESTORE IT TO THE MEMORY IMAGE
	OUT	(FDD),A		; AND LATCH
	RET			; ALL DONE.

; SELECT THE DRIVE IN HARDWARE.
; DRIVE TO BE SELECTED IS PASSED
; IN REGISTER A.

SELDRV:	LD	(HL),A		; SAVE CURRENT DRIVE FOR LATER
	LD	C,00010000B	; THIS IS THE MASK FOR DRIVE 0

SELD10:	OR	A		; HAVE WE GOT THE RIGHT MASK?
	JR	Z,SELD20	; YES.
	SLA	C		; SHIFT DRIVE MASK OVER 1 BIT LEFT.
	DEC	A		; DOWN THE COUNTER.
	JR	SELD10		; AND LOOP.

SELD20:	LD	A,(FDDBYT)	; GET MEMORY IMAGE OF DRIVE LATCH
	AND	00001111B	; AND OFF CURRENT DRIVE SELECT BITS.
	OR	C		; OUT WITH THE OLD, IN WITH THE NEW
	LD	(FDDBYT),A	; RESTORE MEMORY IMAGE.
	OUT	(FDD),A		; AND INFORM LATCH ABOUT NEW DRIVE.
	RET

; RESET THE DISK SUBSYSTEM BY RESTORING
; ALL THE HEADS TO TRACK 0.  RESTORING
; DRIVES IN REVERSE ORDER ASSURES THAT
; DRIVE A WILL ALWAYS BE SELECTED UPON
; COMPLETION.

RESDSK:	LD	A,00000010B	; INITIALIZE THE FDD LATCH, MOTOR ON
	LD	(FDDBYT),A	; MEMORY IMAGE.
	OUT	(FDD),A		; HARDWARE LATCH.
	LD	B,MAXDRV	; INITIAL DRIVE NO.

RESD10:	LD	A,B		; SELECT THE DRIVE
	LD	(HSTDSK),A	; STORE IT IN HSTDSK
	LD	HL,DRIVE
	CALL	SELDRV
	CALL	RESTOR		; RESTORE THE HEADS TO TRACK 0
	DEC	B		; DECREMENT DRIVE NO.
	JP	P,RESD10	; LOOP FOR NEXT DRIVE
	RET

; RESTORE THE HEADS ON THE CURRENTLY
; SELECTED DRIVE TO TRACK 0.  THIS IS
; DONE AFTER EACH SEEK, READ, OR, WRITE
; FAILURE. ALSO AT WARM AND COLD BOOT.
; WE MUST RESET THE CURRENT TRACK FOR
; THIS DRIVE ALSO.

RESTOR:	LD	A,(HSTDSK)	; GET THE CURRENT DRIVE
	LD	HL,TRKTAB	; BASE ADDRESS OF CURRENT TRACK TABLE
	LD	E,A
	LD	D,0		; MAKE DRIVE NO. AN INDEX.
	ADD	HL,DE		; ADD IN INDEX.
	LD	(HL),0		; CLEAR CURRENT TRACK TO 0.
	LD	A,RESCMD	; FDC RESTORE COMMAND
	OUT	(FDCCMD),A	; SEND IT.
	CALL	WAIT		; WAIT FOR COMPLETION
	RET

; RESET THE DMA SIX TIMES TOTAL

RESDMA:	PUSH	BC		; DON'T DESTROY REGGIES
	LD	B,6		; COUNTER
RDMA10:	LD	A,11000011B	; RESET THE DMA
	OUT	(DMA),A		; SO THAT IT DOESN'T RUN ON.
	DJNZ	RDMA10		; LOOP FOR ANOTHER TIME
	POP	BC		; RESTORE REGISTER PAIR
	RET			; ALL DONE

; MISCELANEOUS ROUTINES

; PRINT THE STRING POINTED TO BY HL
; AND TERMINATED BY NULL (0).

PRTMSG:	LD	A,(HL)
	OR	A
	RET	Z		; ALL DONE

	LD	C,A
	PUSH	HL
	CALL	CONOUT		; OUTPUT IT
	POP	HL
	INC	HL
	JR	PRTMSG		; AND LOOP BACK

; GENERAL PORT INITIALIZATION ROUTINE
;	ENTRY:		HL	->	PORT ADDRESS
;					BYTE COUNT
;					DATA
;					 |
;					 |

PRTINI:	LD	C,(HL)		; GET PORT ADDRESS
	INC	HL		
PRTENT:	LD	B,(HL)		; GET THE COUNT
	INC	HL		; POINT TO FIRST DATA BYTE
	OTIR			; BLOCK OUTPUT
	RET

; ADDITIONAL HARWARE SYSTEM 
; HARDWARE INITIALIZATION 
; COMES NEXT.

HDWINI:	CALL	RESDSK		; RESET THE DISK SUBSYSTEM
	LD	HL,SIOTAB	; INITIALIZE SIO #1 FOR SERIAL PRINTER
	CALL	PRTINI		; BAUD RATE IS SET UP IN PROM CODE
				; BY READING THE DIP SWITCH

; INITIALIZE MODEM PORT

	LD	C,CTCP0		; CTC #0, FOR MODEM PORT
	LD	A,CTCM0		; CTC #0 CONTROL REGISTER
	OUT	(C),A
	LD	A,BAUD1		; SET BAUD RATE (300)
	OUT	(C),A
	LD	HL,MODTAB	; INITIALIZE MODEM PORT
	CALL	PRTINI

; INITIALIZE TIME AND DATE COUNTER

	LD	C,CTCP3
	LD	A,10110101B	; INITIALIZE TIMER
	OUT	(C),A
	LD	A,156		; PRESET TIMER COUNTER
	OUT	(C),A
	LD	HL,CTCI3
	LD	A,L
	AND	0FEH		; SET TIMER INTERRUPT VECTOR(LSB)
	OUT	(CTCP0),A

	LD	A,10H
	OUT	(SIOBC0),A	; RESET EXT/STATUS LATCH COMMAND
	IN	A,(SIOBC0)
	AND	20H		; CHECK CTS BIT
	LD	A,24H		; CTS+TXMT READY
	JR	Z,XMIT0
	LD	A,0FH		; ENABLE XON/XOFF TO CRT
	LD	(SIGNON),A
	LD	A,4
XMIT0:	LD	(CRTMSK),A	; CRTMSK = 4H(TXMT RDY) OR 24H(CTS+TXMT RDY)
	RET

; THIS ROUTINE TRANSFERS CONTROL TO 
; THE I/O DRIVER INDICATED BY THE 
; APPROPRIATE BITS IN IOBYTE (0003H).
; ENTRY:	HL ->	<DEVICE TYPE>
;			<DEVICE 1 ADDRESS>
;			<DEVICE 2 ADDRESS>
;			<DEVICE 3 ADDRESS>
;			<DEVICE 4 ADDRESS>

IODISP:	POP	HL		; GET DISPATCH TABLE POINTER
	PUSH	BC		; SAVE PERTINENT REGISTERS
	PUSH	DE
	LD	A,(HL)		; DEVICE TYPE
	INC	HL		; ADVANCE POINTER
	LD	B,A		; SAVE DEVICE TYPE FOR LATER
	OR	A		; WHICH DEVICE?
	LD	A,(IOBYTE)	; RETREIVE CURRENT IOBYTE
	JR	Z,IODI20	; NO SHIFTING NEEDED

IODI10:	RRA			; ROTATE BYTE UNTIL DEVICE BITS
	DJNZ	IODI10		; ARE LINED UP WITH BIT 0

IODI20:	AND	03H		; MASK OFF DON'T CARE BITS
	RLA			; FORM WORD OFFSET
	LD	C,A		; FORM 16 BITS, B ALREADY 0
	ADD	HL,BC		; ADD IN BASE ADDRESS
	LD	E,(HL)		; TRANSFER DISPATCH ADDRESS
	INC	HL		; TO REGISTERS DE
	LD	D,(HL)
	EX	DE,HL		; RESULT INTO HL
	POP	DE		; RESTORE REGISTERS
	POP	BC
	JP	(HL)		; OFF WE GO, INTO THE WILD BLUE YONDER!

;
;	TIMER INTERRUPT SERVICE ROUTINE
;       Keeps time and date.
;	Provides capability to set and read time and date.
;	Shuts off floppy disk motor after 30 sec of no access.
;

TCOUNT:
	DI
	LD	(TUSTACK),SP	; SAVE USER STACK
	LD	SP,LSTACK	; SET STACK POINTER TO LOCAL
	PUSH	AF
	PUSH	HL

	LD	HL,(MSECNT)
	INC	HL
	LD	(MSECNT),HL	; INCREMENT 16-BIT MS COUNTER	
;
;	LD	A,10110111B	; INITIALIZE TIMER
;	OUT	(CTCP3),A
;	LD	A,156		; PRESET TIMER COUNTER (1/100 SEC)
;	OUT	(CTCP3),A
;
	LD	HL,CLOCK
	CALL	TCOUN4		; COUNT 1/100 SEC.
	JP	NZ,TEXIT	; SKIP IF NOT OVERFLOW 99 (BCD)
;
	CALL	FLOPOFF		; TURN OFF FLOPPY DISK?
;
; ELSE RESET PRECOUNTER AND ADD 1 TO SEC.
;
	CALL	TCOUN1
	CP	060H		; CHECK FOR SEC. OVERFLOW
	JP	NZ,TEXIT	; SKIP IF NOT
;
	CALL	TCOUN1		; ADD 1 TO MINUTE COUNT
	CP	060H
	JR	NZ,TEXIT	; SKIP IF NOT OVERFLOW
;
; ELSE RESET MINUTE COUNT AND ADD 1 TO HOUR
;
	CALL	TCOUN1
	CP	024H		; CHECK OVERFLOW
	JR	NZ,TEXIT
;
	CALL	TCOUN1		; RESET HOUR TO 0 AND ADD 1 TO DATE COUNT
	CP	029H		; CHECK DATE = 29
	JR	C,TEXIT		; SKIP IF DATE < 29
;
	CALL	NC,CHKM28	; IF DATE >= 29 THEN CHECK MONTH = FEB
	JR	Z,TCOUN3	; SKIP IF FEB 29TH
;
	LD	A,(HL)		; CHECK DATE = 31
	CP	031H
	CALL	NC,CHKM30	; IF DATE >= 30 THEN CHECK MONTH=4,6,9,11?
	JR	Z,TCOUN3	; SKIP IF MONTH = 4,6,9,11
;
	LD	A,(HL)
	CP	032H		; CHECK DATE = 32
	JR	C,TEXIT
;
; ADJUST MONTH AND RESET SET DATE = 1
;
TCOUN3:
	LD	(HL),1		; RESET DATE = 1
	CALL	TCOUN2		; MONTH = MONTH + 1
	CP	013H
	JR	C,TEXIT		; SKIP IF MONTH < 13
	LD	(HL),1		; RESET MONTH = 1
	CALL 	TCOUN2		; AND ADD 1 TO YEAR
	JR	NZ,TEXIT	; SKIP IF LSB OF YEAR > 0
	CALL	TCOUN2		; ELSE ADD 1 TO MSB OF YEAR COUNT
TEXIT:
	POP	HL
	POP	AF
	LD	SP,(TUSTACK)	; RESTORE USER STACK
	EI
	RETI

TCOUN1:
	LD	(HL),0		; RESET BCD TO 0
TCOUN2:
	INC	HL
TCOUN4:
	LD	A,(HL)		; ADD 1 TO NEXT COUNT
	ADD	A,1
	DAA
	LD	(HL),A
	RET
;
; CHECK MONTH = 2
; RETURN Z = 1 IF YES, ELSE Z = 0
;
CHKM28:
	INC	HL
	LD	A,(HL)
	DEC	HL
	CP	2
	RET
;
; CHECK MONTH = 4,6,9 OR 11
; RETURN Z = 1, ELSE Z = 0
;
CHKM30:
	INC	HL
	LD	A,(HL)
	DEC	HL
	CP	4
	RET	Z
	CP	6
	RET	Z
	CP	9
	RET	Z
	CP	011H
	RET
;
; DATE AND TIME INTERFACE ROUTINE
; ENTRY: READ CURRENT DATE AND TIME
;         C-REG = 0 AND DE = DATE AND TIME BUFFER POINTER
;	 SET CURRENT DATE AND TIME
;         C-REG = 1 AND DE = BUFFER POINTER
; RETURN: CURRENT DATE AND TIME IN USER BUFFER
;         FORMAT: MM?DD?YYYY?HH?MM?SS?NN
;
TOD:
	DEC	C
	JR	Z,SETOD		; SET CURRENT DATE AND TIME
;
RDTOD:
	LD	HL,MONTH
	CALL	BCDASC		; CONVERT BCD TO ASCII AND SAVE INTO (DE)
	INC	DE
	DEC	HL		; ADDRESS DATE
	CALL	BCDASC
	INC	DE
	INC	HL		; ADDRESS YEAR
	INC	HL
	INC	HL
	CALL	BCDASC		; SAVE MSB OF YEAR
	DEC	HL		; ADDRESS LSB OF YEAR
	CALL	BCDASC		; SAVE LSB OF YEAR
;
	INC	DE		; SKIP FILLER
	LD	HL,HOUR
	CALL	BCDASC		; SAVE HOUR
	INC	DE
	DEC	HL
	CALL	BCDASC		; SAVE MINUTE
	INC	DE
	DEC	HL
	CALL	BCDASC		; SAVE SECOND
	INC	DE
	DEC	HL
	CALL	BCDASC		; SAVE 1/100 SEC
	LD	A,(TINITF)	; SET A = INITIALIZE FLAG
	RET
;
; SET CURRENT DATE AND TIME
;
SETOD:
	LD	HL,MONTH
	CALL	ASCBCD
	LD	(HL),A		; SET MONTH
	INC	DE
	DEC	HL
	CALL	ASCBCD
	LD	(HL),A		; SET DATE
	INC	DE
	LD	HL,YEAR+1
	CALL	ASCBCD
	LD	(HL),A		; SET YEAR MSB
	DEC	HL
	CALL	ASCBCD		; SET YEAR LSB
	LD	(HL),A
;
	INC	DE
	LD	HL,HOUR
	CALL	ASCBCD
	LD	(HL),A		; SET HOUR
	DEC	HL
	INC	DE
	CALL	ASCBCD
	LD	(HL),A		; SET MINUTE
	DEC	HL
	INC	DE
	CALL	ASCBCD
	LD	(HL),A		; SET SECOND
	DEC	HL
	XOR	A
	LD	(HL),A		; RESET 1/100 SEC COUNT TO 0
	LD	(TINITF),A	; SET DATE AND TIME INITIALIZE FLAG
	RET
;
; CONVERT 1 BYTE BCD TO 2 BYTES ASCII
; AND SAVE IT INTO (DE)
;
BCDASC:
	LD	A,(HL)
	RRA
	RRA
	RRA
	RRA
	CALL	BCDAS1
	LD	A,(HL)
BCDAS1:
	AND	0FH
	OR	'0'
	LD	(DE),A
	INC	DE
	RET
;
; CONVERT 2 BYTE ASCII DIGIT TO 1 BYTE BCD
;
ASCBCD:
	LD	A,(DE)
	RLA
	RLA
	RLA
	RLA
	AND	0F0H
	LD	C,A		; SAVE MSN TO C-REG
	INC	DE
	LD	A,(DE)
	AND	0FH		; GET LSN
	OR	C		; PACK IT
	INC	DE
	RET
;
; TURN FLOPPY DRIVES MOTOR OFF?
;
FLOPOFF:
	LD	A,(FDTIME)	; MOTOR OFF DISABLE
	OR	A
	RET	Z
	DEC	A		; TIME = TIME - 1
	LD	(FDTIME),A
	RET	NZ		; EXIT IF NOT TIMEOUT
	XOR	A
	OUT	(FDD),A		; ELSE RESET DRIVE SELECT AND TURN MOTOR OFF
	LD	(MOTFLG),A	; SET MOTOR OFF INDICATION
	RET
;
; RETURN DE = ADDRESS OF INTERRUPT VECTOR TABLE
; FOR USER PROGRAM WANT TO USE 16-BIT COUNTER
; THAT INCREMENT AT EVERY 10 MS THEN
; DE-2 = LSB COUNT, DE-1 = MSB COUNT

INTADD:
	LD	DE,INTVEC	; SET DE=INTERRUPT TABLE ADDRESS
	RET
     
; THIS ROUTINE FILLS OUT THE DETAILED ERROR MESSAGE TABLE
; OBTAINING VARIABLE VALUES FROM CURRENT STATE.
; THEN CALLS PRTMSG ROUTINE WITH THE TABLE ADDRESS IN HL

ERRPRT:	LD	A,(COMAND)	; CURRENT COMMAND
	CP	80H		; READ?
	JR	NZ,WRMSG	; NO, SKIP
	LD	HL,RMSG		; READ MESSAGE
	JR	ERR10
WRMSG:	LD	HL,WMSG		; WRITE MESSAGE
ERR10:	LD	DE,VCMD		; COMMAND MESSAGE ADDRESS IN TABLE
	LD	BC,5
	LDIR			; STORE IN TABLE
	LD	A,(HSTDSK)	; CURRENT HOST DISK
	ADD	A,41H		; MAKE IT ASCII
	LD	HL,VDRV		; GET DRIVE TABLE ADDRESS
	LD	(HL),A		
	LD	A,(HSTTRK)	; GET CURRENT TRACK NUMBER
	LD	E,A
	LD	D,0
	LD	HL,VTRK		; GET TRACK TABLE ADDRESS
	CALL	CVD2		; CONVERT IT DECIMAL, STORE IN TABLE 
	LD	A,(HSTSEC)	; CURRENT SECTOR NUMBER
	LD	E,A
	LD	D,0
	LD	HL,VSEC
	CALL	CVD2
	LD	HL,VSTAT	; FDC STATUS TABLE ADDRESS
	LD	A,(ERFLAG)	; GET STATUS CODE 
	CALL	FTAB		; CONVERT IT AS HEX ASCII, STORE IN TABLE
	LD	HL,ERRMSG	; ERROR MESSAGE TABLE ADDRESS
	CALL	PRTMSG
	RET

; THIS ROUTINE CONVERTS HEX CODE INTO ASCII AND FILL OUT THE TABLE

FTAB:	PUSH	AF		; SAVE REGISTERS
	RRCA			; ROTATE RIGHT 4 TIMES
	RRCA
	RRCA
	RRCA
	CALL	GHEX		; CONVERT HIGH ORDER 4 BITS TO ASCII
	LD	(HL),A		; STORE INTO TABLE
	INC	HL		; NEXT TABLE LOCATION
	POP	AF		; RESTORE REGISTERS
	CALL	GHEX		
	LD	(HL),A		
	RET

; HEX INTO ASCII ROUTINE

GHEX:	AND	0FH		; STRIP HIGH 4 BITS
	CP	10		; NUMERIC?
	JR	NC,G10		; YES, SKIP FOR ALPHA
	ADD	A,'0'		; ADD 30
	RET
G10:	ADD	A,'A'-10	; ADD 40
	RET

; DECIMAL CONVERSION ROUTINE

CVD2:	LD	BC,10		; 2 DIGIT CONVERSION
	CALL	CVD
CVD1:	LD	BC,1		; 1 DIGIT CONVERSION
	CALL	CVD
	RET	
CVD:	XOR	A
	EX	DE,HL		; SWAP DE(DATA) FOR HL(OUTPUT POINTER)
CVDL:	OR	A		; CLEAR CARRY FLAG
	SBC	HL,BC		; HL(DATA)-BC(POWER OF 10)
	JP	M,CVDX		; IF RESULT=NEG, THEN EXIT
	INC	A		; OTHERWISE, ADD 1 TO RESULT
	JR	CVDL
CVDX:	ADD	HL,BC		; ADD BACK LAST VALUE
	EX	DE,HL		; SWAP BACK DE AND HL
	ADD	A,'0'		; CONVERT RESULT TO ASCII
	LD	(HL),A		; STORE IT IN OUTPUT AREA
	INC	HL		; BUMP OUTPUT POINTER
	RET

; CARRIAGE RETURN, LINE FEED

CRLF:	LD	C,0DH
	CALL	CONOUT		; PRINT A CR
	LD	C,0AH
	JP	CONOUT		; PRINT A LF
	 
; END OF 802FSUBS.MAC

