;
;==================================================================================================
;   DSKY NEXT GENERATION TEST APPLICATION
;==================================================================================================
;
; TO BUILD:
;
; TASM -t80 -g3 -fFF TSTDSKNG.ASM TSTDSKNG.COM TSTDSKNG.LST
;
; PIO 82C55 I/O IS DECODED TO PORT $60-$67 (ADJUST BELOW AS NEEDED)
; ASSUMES UART AT PORT $68 (ADJUST BELOW AS NEEDED)
;
; THIS CODE IS BELIEVED TO BE COMPATIBLE WITH PPIDE OR PPISD
; RUNNING ON SAME PPI BUS.
;
FALSE:		.EQU	0
TRUE:		.EQU	!FALSE
;
DSKY_OSC:	.EQU	3000000		; OSCILLATOR FREQ IN HZ
;
BDOS:		.EQU	TRUE		; BDOS OR DIRECT TO 8250ISH
DSKY_PROTO:	.EQU	FALSE		; SET FOR DSKYNG PROTOTYPE
;
UART_BASE:	.EQU 	$68		; UART BASE IO ADDRESS
PPI_BASE_DEF:	.EQU	$60		; PPI BASE IO PORT
;
; LED SEGMENTS (BIT VALUES)
;
;	+--01--+
;	20    02
;	+--40--+
;	10    04
;	+--08--+  80
;
; KEY CODE MAP (KEY CODES) CSCCCRRR
;                          ||||||||
;                          |||||+++-- ROW
;                          ||+++----- COL
;                          |+-------- SHIFT
;                          +--------- CONTROL
;
;	00	08	10	18	23
;	01	09	11	19	22
;	02	0A	12	1A	21
;	03	0B	13	1B	20
;	04	0C	14	1C	SHIFT
;	05	0D	15	1D	CONTROL
;
; LED BIT MAP (BIT VALUES)
;
;	$08	$09	$0A	$0B	$0C
;	---	---	---	---	---
;	01	01	01	01	01
;	02	02	02	02	02
;	04      04      04      04	04
;	08      08      08      08	08
;	10      10      10      10	10
;	20      20      20      20	20
;
PPIA:		.EQU 	0	; PORT A OFFSET
PPIB:		.EQU 	1	; PORT B OFFSET
PPIC:		.EQU 	2	; PORT C OFFSET
PPIX:	 	.EQU 	3	; PIO CONTROL PORT OFFSET
;
DSKY_PPIX_RD:	.EQU	%10010010	; PPIX VALUE FOR READS
DSKY_PPIX_WR:	.EQU	%10000010	; PPIX VALUE FOR WRITES
;
; PIO CHANNEL C:
;
;	7	6	5	4	3	2	1	0
;	RES	0	0	CS	CS	/RD	/WR	A0
;
; SETTING BITS 3 & 4 WILL ASSERT /CS ON 3279
; CLEAR BITS 1 OR 2 TO ASSERT READ/WRITE
;
;
#IF (DSKY_PROTO)
;
DSKY_PPI_IDLE:	.EQU	%01100000
;
DSKY_RDBIT	.EQU	6
DSKY_WRBIT	.EQU	5
;
#ELSE
;
DSKY_PPI_IDLE:	.EQU	%00000110
;
DSKY_RDBIT	.EQU	2
DSKY_WRBIT	.EQU	1
;
#ENDIF
;
DSKY_CMD_CLR:	.EQU	%11011111	; CLEAR (ALL OFF)
DSKY_CMD_CLRX:	.EQU	%11010011	; CLEAR (ALL ON)
DSKY_CMD_WDSP:	.EQU	%10010000	; WRITE DISPLAY RAM
DSKY_CMD_RDSP:	.EQU	%01110000	; READ DISPLAY RAM
DSKY_CMD_CLK:	.EQU	%00100000	; SET CLK PRESCALE
DSKY_CMD_FIFO:	.EQU	%01000000	; READ FIFO
;
DSKY_PRESCL:	.EQU	DSKY_OSC / 100000	; PRESCALER
;
	.ORG	$100
;
	; SAVE PREVIOUS STACK POINTER, AND SWITCH TO OUR STACK
	LD	(STACKSAV),SP
	LD	SP,STACK
;
	CALL	PRTSTRD
	.DB	"\r\nNextGenDSKY$"
;
#IF (DSKY_PROTO)
	CALL	PRTSTRD
	.DB	" Prototype$"
#ENDIF
;
	CALL	PRTSTRD
	.DB	" Test Program, v1.4a, 2021-07-18$"
;
	CALL	GET_BASE
	JP	NZ,EXIT
;
	CALL	PRTSTRD
	.DB	"\r\nDSKYng PPI base port: 0x$"
	LD	A,(PPI_BASE)
	CALL	PRTHEXBYTE
	CALL	NEWLINE
;
	CALL	DSKY_INIT
	CALL	DSKY_READ
;
	CALL	PRTSTRD
	.DB	"\r\nCLEAR Command (all ON)$"
	LD	A,DSKY_CMD_CLRX
	CALL	DSKY_CMD
	CALL	WAITKEY
	CALL	DSKY_READ
;
	CALL	PRTSTRD
	.DB	"\r\nCLEAR Command (all OFF)$"
	LD	A,DSKY_CMD_CLR
	CALL	DSKY_CMD
	CALL	WAITKEY
	CALL	DSKY_READ
;
	CALL	PRTSTRD
	.DB	"\r\nIndividual segments and LEDs$"
	LD	HL,PAT1
	LD	B,PAT1LN
	LD	C,0
	CALL	DSKY_PUTSTR
	CALL	WAITKEY
	CALL	DSKY_READ
;
	CALL	PRTSTRD
	.DB	"\r\nIncrementing segments and LEDs$"
	LD	HL,PAT2
	LD	B,PAT2LN
	LD	C,0
	CALL	DSKY_PUTSTR
	CALL	WAITKEY
	CALL	DSKY_READ
;
	CALL	PRTSTRD
	.DB	"\r\nOmit individual segments and LEDs$"
	LD	HL,PAT3
	LD	B,PAT3LN
	LD	C,0
	CALL	DSKY_PUTSTR
	CALL	WAITKEY
	CALL	DSKY_READ
;
	; DISPLAY HEX DIGITS 0-7
;
	CALL	PRTSTRD
	.DB	"\r\nHex digits 0-7$"
	LD	HL,HEX1
	LD	B,HEX1LN
	LD	C,0
	CALL	DSKY_PUTENCSTR
	CALL	WAITKEY
	CALL	DSKY_READ
;
	CALL	PRTSTRD
	.DB	"\r\nHex digits 8-F$"
	LD	HL,HEX2
	LD	B,HEX2LN
	LD	C,0
	CALL	DSKY_PUTENCSTR
	CALL	WAITKEY
	CALL	DSKY_READ
;
	CALL	DSKY_BLANK
;
	; WAIT FOR KEY THEN DISPLAY FIFO CONTENTS
	CALL	PRTSTRD
	.DB	"\r\nPress keys on pad (console key to end)...$"
;
	; CLEAR BUFFER
	LD	HL,DSPBUF
	LD	A,$10
	LD	B,8
M1:
	LD	(HL),A
	INC	HL
	DJNZ	M1
;
	; DISPLAY INIITAL BUFFER
	LD	B,8
	LD	C,0
	LD	HL,DSPBUF
	CALL	DSKY_PUTENCSTR
;
M2:
	CALL	CST			; CONSOLE STATUS
	JP	NZ,M4			; ABORT IF KEY PRESSED
	CALL	DSKY_STAT
	AND	$3F			; DUMP 2 HIGH BITS
	JR	Z,M2			; LOOP IF STATUS ZERO
	CALL	PRTSTRD
	.DB	"\r\nFIFO status=$"
	CALL	PRTHEXBYTE
	AND	$0F			; ISOLATE THE CUR FIFO LEN
	JR	Z,M2			; LOOP IF NOTHING THERE
	PUSH	AF
	LD	A,DSKY_CMD_FIFO
	CALL	DSKY_CMD
	POP	BC			; B := CUR FIFO LEN
	CALL	PRTSTRD
	.DB	", key code(s)=$"

M3:
	PUSH	BC
	CALL	DSKY_DIN
	XOR	%11000000		; FLIP CONTROL & SHIFT MODIFIERS
	CALL	PRTHEXBYTE
	CALL	PC_SPACE
	; SHIFT BUFFER
	LD	HL,DSPBUF+5
	LD	DE,DSPBUF+7
	LD	BC,6
	LDDR
	; PUT NEW VALUE AT START
	PUSH	AF
	RRCA
	RRCA
	RRCA
	RRCA
	AND	$0F
	LD	(DSPBUF),A
	POP	AF
	PUSH	AF
	AND	$0F
	LD	(DSPBUF+1),A
	; UPDATE THE DISPLAY
	LD	B,8
	LD	C,0
	LD	HL,DSPBUF
	CALL	DSKY_PUTENCSTR
	POP	AF
	; TOGGLE LED, KEY CODE: CSCCCRRR
	PUSH	AF
	AND	$07			; ISOLATE ROW
	LD	B,A			; SAVE IN B
	POP	AF
	RRCA
	RRCA
	RRCA
	AND	$07			; ISOLATE COLUMN
	LD	C,A			; SAVE IN C
	CALL	DSKY_TOGLED		; TOGGLE LED AT ROW/COL
	POP	BC			; INSIDE LOOP COUNTER
	DJNZ	M3
	JP	M2			; LOOP
M4:
	CALL	CIN			; DUMP PENDING CONSOLE KEY
;
	; DANCING LIGHTS
	CALL	PRTSTRD
	.DB	"\r\nDance, Baby, Dance (console key to end)...$"

	LD	A,DSKY_CMD_CLR
	CALL	DSKY_CMD
;



	LD	E,$01			; STARTING VALUE
M5:
	CALL	CST			; CONSOLE STATUS
	JR	NZ,M8			; ABORT IF KEY PRESSED
	LD	B,16			; NUMBER OF BYTES
	LD	C,$00			; STARTING LOCATION (BYTE)
M6:
	LD	A,E
	CALL	DSKY_PUTBYTE
	INC	C			; NEXT LOCATION
	DJNZ	M6			; INNER LOOP FOR ALL BYTES
	RLC	E			; ROTATE THE VALUE
	LD	B,0			; DELAY LOOP
M7:
	CALL	DLY64
	DJNZ	M7
	JR	M5			; REPEAT OUTER LOOP
M8:
	CALL	CIN			; DUMP PENDING CONSOLE KEY
;
	; CLEAR ALL
	LD	A,DSKY_CMD_CLR
	CALL	DSKY_CMD
;
EXIT:
	; GOODBYE
	CALL	PRTSTRD
	.DB	"\r\nThank you, please call again\r\n$"
;
	; CLEAN UP AND RETURN TO OS
	LD	SP,(STACKSAV)
;
	RET
;
; SETUP PPI FOR WRITING: PUT PPI PORT A IN OUTPUT MODE
; AVOID REWRTING PPIX IF ALREADY IN OUTPUT MODE
;
DSKY_PPIWR:
	PUSH	AF
	PUSH	BC
;
	LD	A,(PPI_BASE)
	ADD	A,PPIX
	LD	C,A
;
	; CHECK FOR WRITE MODE
	LD	A,(PPIX_VAL)
	CP	DSKY_PPIX_WR
	JR	Z,DSKY_PPIWR1
;
	; SET PPI TO WRITE MODE
	LD	A,DSKY_PPIX_WR
	OUT	(C),A
	LD	(PPIX_VAL),A
;
	; RESTORE PORT C (MAY NOT BE NEEDED)
	LD	A,DSKY_PPI_IDLE
	DEC	C
	OUT	(C),A
;
DSKY_PPIWR1:
;
	POP	BC
	POP	AF
	RET
;
; SETUP PPI FOR READING: PUT PPI PORT A IN INPUT MODE
; AVOID REWRTING PPIX IF ALREADY IN INPUT MODE
;
DSKY_PPIRD:
	PUSH	AF
	PUSH	BC
;
	LD	A,(PPI_BASE)
	ADD	A,PPIX
	LD	C,A
;
	; CHECK FOR READ MODE
	LD	A,(PPIX_VAL)
	CP	DSKY_PPIX_RD
	JR	Z,DSKY_PPIRD1
;
	; SET PPI TO READ MODE
	LD	A,DSKY_PPIX_RD
	OUT	(C),A
	LD	(PPIX_VAL),A
;
	; RESTORE PORT C (MAY NOT BE NEEDED)
	LD	A,DSKY_PPI_IDLE
	DEC	C
	OUT	(C),A
;
DSKY_PPIRD1:
	POP	BC
	POP	AF
	RET
;
; RELEASE USE OF PPI
;
DSKY_PPIIDLE:
	JR	DSKY_PPIRD		; SAME AS READ MODE
;
;
;
DSKY_INIT:
	; RESET DSKY
	CALL	DSKY_RES
	; SET CLOCK SCALER TO 20
	LD	A,DSKY_CMD_CLK | DSKY_PRESCL
	CALL	DSKY_CMD
	LD	A,%00001000		; dan
	CALL	DSKY_CMD
;
	RET
;
; HARDWARE RESET 8279 BY PULSING RESET LINE
;
DSKY_RES:
;
	PUSH	BC
	LD	A,(PPI_BASE)
	ADD	A,PPIC
	LD	C,A
	; SETUP PPI
	CALL	DSKY_PPIRD
	; INIT 8279 VALUES TO IDLE STATE
	LD	A,DSKY_PPI_IDLE
	OUT	(C),A
	; PULSE RESET SIGNAL ON 8279
	SET	7,A
	OUT	(C),A
	RES	7,A
	OUT	(C),A
	; DONE
	CALL	DSKY_PPIIDLE
	POP	BC
	RET
;
; COMMAND IN A
; TRASHES BC
;
DSKY_CMD:
	LD	B,$01
	JR	DSKY_DOUT2
;
; DATA VALUE IN A
; TRASHES BC
;
DSKY_DOUT:
	LD	B,$00
;
DSKY_DOUT2:
;
	; SAVE INCOMING DATA BYTE
	PUSH	AF
;
	; SET PPI LINE CONFIG TO WRITE MODE
	CALL	DSKY_PPIWR
;
	; SETUP
	LD	A,(PPI_BASE)
	ADD	A,PPIC
	LD	C,A
;
	; SET ADDRESS FIRST
	LD	A,DSKY_PPI_IDLE
	OR	B
	OUT	(C),A
;
	; ASSERT 8279 /CS
	SET	3,A
	SET	4,A
	OUT	(C),A
;
	; PPIC WORKING VALUE TO REG B NOW
	LD	B,A
;
	; ASSERT DATA BYTE VALUE
	DEC	C
	DEC	C
	POP	AF
	OUT	(C),A
	INC	C
	INC	C
;
	; PULSE /WR
	RES	DSKY_WRBIT,B
	OUT	(C),B
	NOP			; MAY NOT BE NEEDED
	SET	DSKY_WRBIT,B
	OUT	(C),B
;
	; DEASSERT /CS
	RES	3,B
	RES	4,B
	OUT	(C),B
;
	; CLEAR ADDRESS BIT
	RES	0,B
	OUT	(C),B
;
	; DONE
	CALL	DSKY_PPIIDLE
	RET
;
; STATUS VALUE IN A
; TRASHES BC
;
DSKY_STAT:
	LD	B,$01
	JR	DSKY_DIN2
;
; DATA VALUE RETURNED IN A
; TRASHES BC
;
DSKY_DIN:
	LD	B,$00
;
DSKY_DIN2:
	; SET PPI LINE CONFIG TO WRITE MODE
	CALL	DSKY_PPIRD
;
	; SETUP
	LD	A,(PPI_BASE)
	ADD	A,PPIC
	LD	C,A
;
	; SET ADDRESS FIRST
	LD	A,DSKY_PPI_IDLE
	OR	B
	OUT	(C),A
;
	; ASSERT 8279 /CS
	SET	3,A
	SET	4,A
	OUT	(C),A
;
	; PPIC WORKING VALUE TO REG B NOW
	LD	B,A
;
	; ASSERT /RD
	RES	DSKY_RDBIT,B
	OUT	(C),B
;
	; GET VALUE
	DEC	C
	DEC	C
	IN	A,(C)
	INC	C
	INC	C
;
	; DEASSERT /RD
	SET	DSKY_RDBIT,B
	OUT	(C),B
;
	; DEASSERT /CS
	RES	3,B
	RES	4,B
	OUT	(C),B
;
	; CLEAR ADDRESS BIT
	RES	0,B
	OUT	(C),B
;
	; DONE
	CALL	DSKY_PPIIDLE
	RET
;
; BLANK THE DISPLAY (WITHOUT USING CLEAR)
;
DSKY_BLANK:
	LD	A,DSKY_CMD_WDSP
	CALL	DSKY_CMD
	LD	B,16
DSKY_BLANK1:
	PUSH	BC
	LD	A,$FF
	CALL	DSKY_DOUT
	POP	BC
	DJNZ	DSKY_BLANK1
	RET
;
; WRITE A RAW BYTE VALUE TO DSKY DISPLAY RAM
; AT LOCATION IN REGISTER C, VALUE IN A.
;
DSKY_PUTBYTE:
	PUSH	BC
	PUSH	AF
	LD	A,C
	ADD	A,DSKY_CMD_WDSP
	CALL	DSKY_CMD
	POP	AF
	XOR	$FF
	CALL	DSKY_DOUT
	POP	BC
	RET
;
; READ A RAW BYTE VALUE FROM DSKY DISPLAY RAM
; AT LOCATION IN REGISTER C, VALUE RETURNED IN A
;
DSKY_GETBYTE:
	PUSH	BC
	LD	A,C
	ADD	A,DSKY_CMD_RDSP
	CALL	DSKY_CMD
	CALL	DSKY_DIN
	XOR	$FF
	POP	BC
	RET
;
; WRITE A STRING OF RAW BYTE VALUES TO DSKY DISPLAY RAM
; AT LOCATION IN REGISTER C, LENGTH IN B, ADDRESS IN HL.
;
DSKY_PUTSTR:
	PUSH	BC
	LD	A,C
	ADD	A,DSKY_CMD_WDSP
	CALL	DSKY_CMD
	POP	BC
;
DSKY_PUTSTR1:
	LD	A,(HL)
	XOR	$FF
	INC	HL
	PUSH	BC
	CALL	DSKY_DOUT
	POP	BC
	DJNZ	DSKY_PUTSTR1
	RET
;
; READ A STRING OF RAW BYTE VALUES FROM DSKY DISPLAY RAM
; AT LOCATION IN REGISTER C, LENGTH IN B, ADDRESS IN HL.
;
DSKY_GETSTR:
	PUSH	BC
	LD	A,C
	ADD	A,DSKY_CMD_RDSP
	CALL	DSKY_CMD
	POP	BC
;
DSKY_GETSTR1:
	PUSH	BC
	CALL	DSKY_DIN
	POP	BC
	XOR	$FF
	LD	(HL),A
	INC	HL
	DJNZ	DSKY_GETSTR1
	RET
;
; HL IS ADR OF ENCODED STRING OF BYTES
; B IS LEN OF STRING (BYTES)
; C IS POSITION IN DISPLAY RAM TO WRITE
;
DSKY_PUTENCSTR:
	PUSH	BC
	LD	A,C
	ADD	A,DSKY_CMD_WDSP
	CALL	DSKY_CMD
	POP	BC
	EX	DE,HL
DSKY_PUTENCSTR1:
	LD	A,(DE)
	INC	DE
	LD	HL,HEXMAP
	CALL	ADDHLA
	LD	A,(HL)
	XOR	$FF
	PUSH	BC
	CALL	DSKY_DOUT
	POP	BC
	DJNZ	DSKY_PUTENCSTR1
	RET
;
; TOGGLE LED AT ROW (B) AND COLUMN (C)
;
DSKY_TOGLED:
	; CONVERT B (ROW) TO BIT VALUE
	XOR	A
	INC	B
	SCF
DSKY_TOGLED1:
	RLA
	DJNZ	DSKY_TOGLED1
	LD	B,A
	; LED COLS START AT 8
	LD	A,8
	ADD	A,C
	LD	C,A
	; FLIP THE BIT
	CALL	DSKY_GETBYTE	; GET CURRENT COL BITMAP
	XOR	B		; FLIP DESIRED BIT
	CALL	DSKY_PUTBYTE	; WRITE VLAUE BACK TO COLUMN
	RET
;
; READ AND PRINT DISPLAY RAM (RAW BYTES)
;
DSKY_READ:
	CALL	PRTSTRD
	.DB	"\r\nRead display RAM: $"
	LD	B,16			; 16 BYTES
	LD	C,0			; POSITION 0
	LD	HL,DSPBUF
	CALL	DSKY_GETSTR
	LD	B,$10
	LD	HL,DSPBUF
DSKY_READ1:
	LD	A,(HL)
	INC	HL
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
	DJNZ	DSKY_READ1
	RET
;
;
;
GET_BASE:
	CALL	PRTSTRD
	.DB	"\r\nDSKYng PPI base port [0x$"
	LD	A,(PPI_BASE)
	CALL	PRTHEXBYTE
	CALL	PRTSTRD
	.DB	"]: $"
	LD	A,(PPI_BASE)
	CALL	GETHEXBYTE
	JR	C,GET_BASE1
	LD	(PPI_BASE),A
	XOR	A
	RET
;
GET_BASE1:
	CALL	PRTSTRD
	.DB	"\r\nInvalid DSKYng PPI base port value!$"
	JR	GET_BASE
;
; OUTPUT CHARACTER FROM A
;
COUT:
	PUSH	AF			;
	PUSH	BC			;
	PUSH	DE			;
	PUSH	HL			;

#IF (BDOS)
	LD	C,2			; BDOS FUNC: CONSOLE OUTPUT
	LD	E,A			; CHARACTER TO E
	CALL	$0005			; CALL BDOS
#ELSE
	LD 	C,A
COUT1:
	IN	A,(UART_BASE + 05H)	; READ LINE STATUS REGISTER
	AND	20H			; TEST IF UART IS READY TO SEND
	JP	Z,COUT1			; IF NOT REPEAT
	LD	A,C			; GET TO ACCUMULATOR
	OUT	(UART_BASE),A		; THEN WRITE THE CHAR TO UART (UART0 = 068h + $00)
#ENDIF

	POP	HL			;
	POP	DE			;
	POP	BC			;
	POP	AF			;
	RET				; DONE
;
; INPUT CHARACTER TO A
;
CIN:
	PUSH	BC			;
	PUSH	DE			;
	PUSH	HL			;
#IF BDOS
CIN1:
	LD	C,6			; BDOS FUNC: DIRECT CONSOLE I/O
	LD	E,$FF			; SET FOR INPUT
	CALL	$0005			; CALL BDOS, CHARACTER TO A
	OR	A			; CHECK FOR NO CHAR, $00
	JR	Z,CIN1			; LOOP TIL WE GET A CHAR
#ELSE
CIN1:
	CALL	CST			; IS A CHAR READY TO BE READ FROM UART?
	CP	00H			;
	JP	Z,CIN1			; NO?  TRY AGAIN
	IN	A,(UART_BASE)		; YES? READ THE CHAR FROM THE UART (UART0 = 068h + $00)
#ENDIF
	POP	HL			;
	POP	DE			;
	POP	BC			;
	RET				; DONE
;
; RETURN INPUT STATUS IN A (0 = NO CHAR, !=0 CHAR WAITING)
;
CST:
	PUSH	BC			;
	PUSH	DE			;
	PUSH	HL			;
#IF BDOS
	LD	C,$0B			; BDOS FUNC: GET CONSOLE STATUS
	CALL	$0005			; CALL BDOS
	OR	A			; SET FLAGS
#ELSE
					; CONSOLE STATUS, RETURN 0FFH IF CHARACTER READY, 00H IF NOT
	IN	A,(UART_BASE + 05H)	; READ LINE STATUS REGISTER (UART5 = 068h + $05)
	AND	01H			; TEST IF DATA IN RECEIVE BUFFER
					; IS THERE A CHAR READY? 0=NO, 1=YES
	JP	Z,CST1			;
	LD	A,0FFH			; YES, PUT 0FFh IN A AND RETURN
CST1:					;
					; NO, LEAVE 000h IN A AND RETURN
#ENDIF
	POP	HL			;
	POP	DE			;
	POP	BC			;
	RET				; DONE
;
; WAIT FOR A KEY
;
WAITKEY:
	PUSH	AF
	CALL	PRTSTRD
	.DB	", press a key to continue...$"
	CALL	CIN
	CP	$1B
	JP	Z,EXIT
	POP	AF
	RET
;
;==================================================================================================
; UTILITY FUNCTIONS
;==================================================================================================
;
;
CHR_BEL:	.EQU	07H
CHR_CR:		.EQU	0DH
CHR_LF:		.EQU	0AH
CHR_BS:		.EQU	08H
CHR_ESC:	.EQU	1BH
;
;__________________________________________________________________________________________________
;
; UTILITY PROCS TO PRINT SINGLE CHARACTERS WITHOUT TRASHING ANY REGISTERS
;
PC_SPACE:
	PUSH	AF
	LD	A,' '
	JR	PC_PRTCHR

PC_PERIOD:
	PUSH	AF
	LD	A,'.'
	JR	PC_PRTCHR

PC_COLON:
	PUSH	AF
	LD	A,':'
	JR	PC_PRTCHR

PC_COMMA:
	PUSH	AF
	LD	A,','
	JR	PC_PRTCHR

PC_LBKT:
	PUSH	AF
	LD	A,'['
	JR	PC_PRTCHR

PC_RBKT:
	PUSH	AF
	LD	A,']'
	JR	PC_PRTCHR

PC_LT:
	PUSH	AF
	LD	A,'<'
	JR	PC_PRTCHR

PC_GT:
	PUSH	AF
	LD	A,'>'
	JR	PC_PRTCHR

PC_LPAREN:
	PUSH	AF
	LD	A,'('
	JR	PC_PRTCHR

PC_RPAREN:
	PUSH	AF
	LD	A,')'
	JR	PC_PRTCHR

PC_ASTERISK:
	PUSH	AF
	LD	A,'*'
	JR	PC_PRTCHR

PC_CR:
	PUSH	AF
	LD	A,CHR_CR
	JR	PC_PRTCHR

PC_LF:
	PUSH	AF
	LD	A,CHR_LF
	JR	PC_PRTCHR

PC_PRTCHR:
	CALL	COUT
	POP	AF
	RET

NEWLINE2:
	CALL	NEWLINE
NEWLINE:
	CALL	PC_CR
	CALL	PC_LF
	RET
;
; PRINT A CHARACTER REFERENCED BY POINTER AT TOP OF STACK
; USAGE:
;   CALL PRTCH
;   DB  'X'
;
PRTCH:
	EX	(SP),HL
	PUSH	AF
	LD	A,(HL)
	CALL	COUT
	POP	AF
	INC	HL
	EX	(SP),HL
	RET
;
; PRINT A STRING AT ADDRESS SPECIFIED IN HL
; STRING MUST BE TERMINATED BY '$'
; USAGE:
;   LD	HL,MYSTR
;   CALL PRTSTR
;   ...
;   MYSTR: DB  "HELLO$"
;
PRTSTR:
	LD	A,(HL)
	INC	HL
	CP	'$'
	RET	Z
	CALL	COUT
	JR	PRTSTR
;
; PRINT A STRING DIRECT: REFERENCED BY POINTER AT TOP OF STACK
; STRING MUST BE TERMINATED BY '$'
; USAGE:
;   CALL PRTSTRD
;   DB  "HELLO$"
;   ...
;
PRTSTRD:
	EX	(SP),HL
	PUSH	AF
	CALL	PRTSTR
	POP	AF
	EX	(SP),HL
	RET
;
; PRINT A STRING INDIRECT: REFERENCED BY INDIRECT POINTER AT TOP OF STACK
; STRING MUST BE TERMINATED BY '$'
; USAGE:
;   CALL PRTSTRI(MYSTRING)
;   MYSTRING	DB	"HELLO$"
;
PRTSTRI:
	EX	(SP),HL
	PUSH	AF
	LD	A,(HL)
	INC	HL
	PUSH	HL
	LD	H,(HL)
	LD	L,A
	CALL	PRTSTR
	POP	HL
	INC	HL
	POP	AF
	EX	(SP),HL
	RET
;
; PRINT THE HEX BYTE VALUE IN A
;
PRTHEXBYTE:
	PUSH	AF
	PUSH	DE
	CALL	HEXASCII
	LD	A,D
	CALL	COUT
	LD	A,E
	CALL	COUT
	POP	DE
	POP	AF
	RET
;
; PRINT THE HEX WORD VALUE IN BC
;
PRTHEXWORD:
	PUSH	AF
	LD	A,B
	CALL	PRTHEXBYTE
	LD	A,C
	CALL	PRTHEXBYTE
	POP	AF
	RET
;
; PRINT THE HEX WORD VALUE IN HL
;
PRTHEXWORDHL:
	PUSH	AF
	LD	A,H
	CALL	PRTHEXBYTE
	LD	A,L
	CALL	PRTHEXBYTE
	POP	AF
	RET
;
; CONVERT BINARY VALUE IN A TO ASCII HEX CHARACTERS IN DE
;
HEXASCII:
	LD	D,A
	CALL	HEXCONV
	LD	E,A
	LD	A,D
	RLCA
	RLCA
	RLCA
	RLCA
	CALL	HEXCONV
	LD	D,A
	RET
;
; CONVERT LOW NIBBLE OF A TO ASCII HEX
;
HEXCONV:
	AND	0FH	     ;LOW NIBBLE ONLY
	ADD	A,90H
	DAA
	ADC	A,40H
	DAA
	RET
;
;
;
GETHEXBYTE:
	PUSH	AF			; SAVE INCOMING VALUE
	LD	C,0AH			; BDOS READ CONSOLE BUFFER
	LD	DE,CONBUF
	CALL	5			; GET EDITED STRING
	CALL	NEWLINE
	POP	DE			; RESTORE INCOMING TO D

	; OK WE SHOULD NOW HAVE A STRING WITH A HEX NUMBER
	LD	HL,CONBUF
	INC	HL
	LD	A,(HL)			; GET CHARACTER COUNT
	INC	HL
	CP	3
	JR	C,GHB0			; OK IF <= 2 CHARS
	SCF				; SIGNAL ERROR
	RET				; AND RETURN

GHB0:
	OR	A			; SET FLAGS
	JR	NZ,GHB1			; GOT CHARS, GO AHEAD
	LD	A,D			; RESTORE INCOMING VALUE
	OR	A			; SIGNAL SUCCESS
	RET				; AND DONE

GHB1:
	LD	B,A			; COUNT TO B
	LD	C,0			; INITIAL VALUE

GHB2:
	LD	A,(HL)			; GET NEXT CHAR
	INC	HL
	CALL	ISHEX
	RET	C			; ABORT ON NON-HEX CHAR

	; OK WE ARE HERE WHEN WE HAVE A VALID CHARACTER (0-9,A-F,A-F) NEED TO CONVERT TO BINARY
	; CHARACTER IS STILL IN A

	CP	3AH			; TEST FOR 0-9
	JP	M,GHB2C
	CP	47H			; TEST FOR A-F
	JP	M,GHB2B
	CP	67H			; TEST FOR A-F
	JP	M,GHB2A
GHB2A:	SUB	20H			; CHARACTER IS A-F
GHB2B:	SUB	07H			; CHARACTER IS A-F
GHB2C:	SUB	30H			; CHARACTER IS 0-9

	RLC	C			; MULTIPLY CUR VALUE BY 16
	RLC	C
	RLC	C
	RLC	C
	ADD	A,C			; ADD TO ACCUM
	LD	C,A			; PUT BACK IN C

	DJNZ	GHB2			; LOOP THRU ALL CHARS

	LD	A,C			; INTO A FOR RETURN
	OR	A			; SIGNAL SUCCESS
	RET				; DONE

ISHEX:
	CP	30H			; CHECK IF LESS THAN CHARACTER 0
	JP	M,NOTHEX
	CP	3AH			; CHECK FOR > 9
	JP	M,ISHX1			; OK, CHARACTER IS 1-9

	CP	41H			; CHECK FOR CHARACTER LESS THAN A
	JP	M,NOTHEX
	CP	47H			; CHECK FOR CHARACTERS > F
	JP	M,ISHX1

	CP	61H			; CHECK FOR CHARACTERS < A
	JP	M,NOTHEX

	CP	67H			; CHECK FOR CHARACTER > F
	JP	M,ISHX1
NOTHEX:
	SCF				; SET CARRY TO INDICATE FAIL
	RET

ISHX1:
	SCF
	CCF
	RET
;
; SHORT DELAY FUNCTIONS.  NO CLOCK SPEED COMPENSATION, SO THEY
; WILL RUN LONGER ON SLOWER SYSTEMS.  THE NUMBER INDICATES THE
; NUMBER OF CALL/RET INVOCATIONS.  A SINGLE CALL/RET IS
; 27 T-STATES ON A Z80, 25 T-STATES ON A Z180
;
;			; Z80	Z180
;			; ----	----
DLY64:	CALL	DLY32	; 1728	1600
DLY32:	CALL	DLY16	; 864	800
DLY16:	CALL	DLY8	; 432	400
DLY8:	CALL	DLY4	; 216	200
DLY4:	CALL	DLY2	; 108	100
DLY2:	CALL	DLY1	; 54	50
DLY1:	RET		; 27	25
;
; ADD HL,A
;
;   A REGISTER IS DESTROYED!
;
ADDHLA:
	ADD	A,L
	LD	L,A
	RET	NC
	INC	H
	RET
;
; STORAGE
;
PPI_BASE:	.DB	PPI_BASE_DEF
;
CONBUF:		.DB	8		; MAXIMUM CHARS
		.DB	0		; COUNT
		.FILL	8		; SIZE OF BUFFER
;
PPIX_VAL:	.DB	0
;
DSPBUF:	.FILL	16,0
;
PAT1:	.DB	$01,$02,$04,$08,$10,$20,$40,$80
	.DB	$11,$22,$44,$88,$00,$00,$00,$00
PAT1LN:	.EQU	$ - PAT1
PAT2:	.DB	$01,$03,$07,$0F,$1F,$3F,$7F,$FF
	.DB	$11,$33,$77,$FF,$00,$00,$00,$00
PAT2LN:	.EQU	$ - PAT2
PAT3:	.DB	$FE,$FD,$FB,$F7,$EF,$DF,$BF,$7F
	.DB	$77,$BB,$DD,$EE,$00,$00,$00,$00
PAT3LN:	.EQU	$ - PAT3
BLANK:	.DB	$00,$00,$00,$00,$00,$00,$00,$00
	.DB	$00,$00,$00,$00,$00,$00,$00,$00
BLNKLN:	.EQU	$ - BLANK
HEX1:	.DB	$0,$1,$2,$3,$4,$5,$6,$7
HEX1LN:	.EQU	$ - HEX1
HEX2:	.DB	$8,$9,$A,$B,$C,$D,$E,$F
HEX2LN:	.EQU	$ - HEX2
;
HEXMAP:
	;	'0'  '1'  '2'  '3'  '4'  '5'  '6'  '7'
	.DB	$3F, $06, $5B, $4F, $66, $6D, $7D, $07
	;	'8'  '9'  'A'  'B'  'C'  'D'  'E'  'F'
	.DB	$7F, $67, $77, $7C, $39, $5E, $79, $71
	;
	.DB	$00
;
STACKSAV:	.DW	0
STACKSIZ:	.EQU	$100		; WE ARE A STACK PIG
		.FILL	STACKSIZ,0
STACK:		.EQU	$
;
	.END
