;__CVDUTEST________________________________________________________________________________________
;
;	CVDUTEST   COLOR VDU TEST
;
;	WRITTEN BY: DAN WERNER -- 11/4/2011
;__________________________________________________________________________________________________
;

; DATA CONSTANTS
;__________________________________________________________________________________________________
;IDE REGISTER		IO PORT		; FUNCTION
M8563Status 	.EQU	$E4
M8563Register 	.EQU	$E4
M8563Data 	.EQU	$E5

I8242Status 	.EQU	$E3
I8242Command	.EQU 	$E3
I8242Data 	.EQU	$E2


	.ORG	$0100
;__________________________________________________________________________________________________
; MAIN PROGRAM BEGINS HERE
;__________________________________________________________________________________________________
INITVDU:
    	CALL	VDU_INIT		; INIT VDU
	CALL 	KB_INITIALIZE		; INIT KB

    	CALL	DSPMATRIX		; DISPLAY INIT MATRIX SCREEN
	CALL	WAIT_KBHIT		; WAIT FOR A KEYSTROKE

LOOP1:
	CALL	GET_KEY
	LD	C,14
	CP	13
	JP	Z,LOOP2
	CP	27
	JP	Z,LOOP3
	CP	'6'
	JP	Z,LOOP4
	CALL 	VDU_PutChar		; DUMP CHAR TO DISPLAY
	JP	LOOP1
LOOP2:
    	LD  	A,0			; YES, WRAP TO NEXT LINE
    	LD	(TERM_X),A		; STORE X
    	LD	A,(TERM_Y)		; A= Y COORD
    	INC 	A			; INC Y COORD
    	LD	(TERM_Y),A		; STORE Y
    	CALL 	GOTO_XY 	       	; YES, HANDLE SCROLLING
	JP	LOOP1
LOOP3:
	LD	C,00H			; CP/M SYSTEM RESET CALL
	CALL	0005H			; RETURN TO PROMPT
	RET
LOOP4:
	CALL	REVERSE_SCROLL
	JP	LOOP1


;__DO_SCROLL_______________________________________________________________________________________
;
; 	SCROLL THE SCREEN UP ONE LINE
;__________________________________________________________________________________________________			
DO_SCROLL:
	PUSH	AF			; STORE AF	
DO_SCROLLE1:
	PUSH	HL			; STORE HL
	PUSH	BC			; STORE BC
	
    	LD 	B, 24			; GET REGISTER 24	
	CALL	VDU_GREG		;
	OR	80H			; TURN ON COPY BIT
       	LD	D,A			; PARK IT
     	
	LD 	HL, (VDU_DISPLAY_START)	; GET UP START OF DISPLAY
	LD	E,23			;
DO_SCROLL1:	
    	LD 	B, 18			; SET UPDATE(DEST) POS IN VDU
    	LD	A,H			;
    	CALL	VDU_WREG		; WRITE IT
    	LD 	B, 19			; SET UPDATE(DEST) POS IN VDU
    	LD	A,L			;
    	CALL	VDU_WREG		; WRITE IT
    	LD	BC,0050H		;
	ADD	HL,BC			;
       	LD 	B, 32			; SET SOURCE POS IN VDU
    	LD	A,H			;
    	CALL	VDU_WREG		; WRITE IT
    	LD 	B, 33			; SET SOURCE POS IN VDU
    	LD	A,L			;
    	CALL	VDU_WREG		; WRITE IT
    	
    	LD 	B, 24			; SET COPY
    	LD	A,D			;
    	CALL	VDU_WREG		; WRITE IT
 	    	
    	LD 	B, 30			; SET AMOUNT TO COPY
    	LD	A,050H			;
    	CALL	VDU_WREG		; WRITE IT
	DEC	A
    	LD	A,E			;
    	CP	00H			;
      	JP	NZ,DO_SCROLL1		; LOOP TILL DONE
      	
	LD 	HL, (VDU_DISPLAY_START)	; GET UP START OF DISPLAY
	LD	BC,0820H		;
	ADD	HL,BC			;
	LD	E,23
DO_SCROLL2:	
    	LD 	B, 18			; SET UPDATE(DEST) POS IN VDU
    	LD	A,H			;
    	CALL	VDU_WREG		; WRITE IT
    	LD 	B, 19			; SET UPDATE(DEST) POS IN VDU
    	LD	A,L			;
    	CALL	VDU_WREG		; WRITE IT
    	LD	BC,0050H		;
	ADD	HL,BC			;
       	LD 	B, 32			; SET SOURCE POS IN VDU
    	LD	A,H			;
    	CALL	VDU_WREG		; WRITE IT
    	LD 	B, 33			; SET SOURCE POS IN VDU
    	LD	A,L			;
    	CALL	VDU_WREG		; WRITE IT
    	
    	LD 	B, 24			; SET COPY
    	LD	A,D			;
    	CALL	VDU_WREG		; WRITE IT
 	    	
    	LD 	B, 30			; SET AMOUNT TO COPY
    	LD	A,050H			;
    	CALL	VDU_WREG		; WRITE IT
	DEC	E
    	LD	A,E			;
    	CP	00H			;
      	JP	NZ,DO_SCROLL2		; LOOP TILL DONE      	

    	
    	LD	A,23			; SET CURSOR TO BEGINNING OF LAST LINE
    	LD	(TERM_Y),A		;
    	LD	A,(TERM_X)		;
    	PUSH	AF			; STORE X COORD
    	LD	A,0			;
    	LD	(TERM_X),A		;
    	CALL	GOTO_XY			; SET CURSOR POSITION TO BEGINNING OF LINE
	POP	AF			; RESTORE X COORD
    	POP	BC			; RESTORE BC	
    	CALL	PERF_ERASE_EOL		; ERASE SCROLLED LINE
	LD	(TERM_X),A		;
   	CALL	GOTO_XY			; SET CURSOR POSITION
    	POP	HL			; RESTORE HL
    	POP	AF			; RESTORE AF
    	RET				;
    	
;__REVERSE_SCROLL__________________________________________________________________________________
;
; 	SCROLL THE SCREEN DOWN ONE LINE
;__________________________________________________________________________________________________			
REVERSE_SCROLL:
	PUSH	AF			; STORE AF	
	PUSH	HL			; STORE HL
	PUSH	BC			; STORE BC
	
    	LD 	B, 24			; GET REGISTER 24	
	CALL	VDU_GREG		;
	OR	80H			; TURN ON COPY BIT
       	LD	E,A			; PARK IT
     	
	LD 	HL, (VDU_DISPLAY_START)	; GET UP START OF DISPLAY
	LD	BC,0730H		;
	ADD  	HL,BC
	LD	D,23			;
REVERSE_SCROLL1:	
    	LD 	B, 18			; SET UPDATE(DEST) POS IN VDU
    	LD	A,H			;
    	CALL	VDU_WREG		; WRITE IT
    	LD 	B, 19			; SET UPDATE(DEST) POS IN VDU
    	LD	A,L			;
    	CALL	VDU_WREG		; WRITE IT
    	LD	BC,0FFB0H		;
	ADD	HL,BC			;
       	LD 	B, 32			; SET SOURCE POS IN VDU
    	LD	A,H			;
    	CALL	VDU_WREG		; WRITE IT
    	LD 	B, 33			; SET SOURCE POS IN VDU
    	LD	A,L			;
    	CALL	VDU_WREG		; WRITE IT
    	
    	LD 	B, 24			; SET COPY
    	LD	A,E			;
    	CALL	VDU_WREG		; WRITE IT
 	    	
    	LD 	B, 30			; SET AMOUNT TO COPY
    	LD	A,050H			;
    	CALL	VDU_WREG		; WRITE IT

	DEC	D
    	LD	A,D			;
    	CP	00H			;
      	JP	NZ,REVERSE_SCROLL1	; LOOP TILL DONE

     	
	LD 	HL, (VDU_DISPLAY_START)	; GET UP START OF DISPLAY
	LD	BC,0F50H		;
	ADD	HL,BC
	LD	D,23			;
REVERSE_SCROLL2:	
    	LD 	B, 18			; SET UPDATE(DEST) POS IN VDU
    	LD	A,H			;
    	CALL	VDU_WREG		; WRITE IT
    	LD 	B, 19			; SET UPDATE(DEST) POS IN VDU
    	LD	A,L			;
    	CALL	VDU_WREG		; WRITE IT
    	LD	BC,0FFB0H		;
	ADD	HL,BC			;
       	LD 	B, 32			; SET SOURCE POS IN VDU
    	LD	A,H			;
    	CALL	VDU_WREG		; WRITE IT
    	LD 	B, 33			; SET SOURCE POS IN VDU
    	LD	A,L			;
    	CALL	VDU_WREG		; WRITE IT
    	
    	LD 	B, 24			; SET COPY
    	LD	A,E			;
    	CALL	VDU_WREG		; WRITE IT
 	    	
    	LD 	B, 30			; SET AMOUNT TO COPY
    	LD	A,050H			;
    	CALL	VDU_WREG		; WRITE IT

	DEC	D
    	LD	A,D			;
    	CP	00H			;
      	JP	NZ,REVERSE_SCROLL2	; LOOP TILL DONE    	
    	LD	A,0			; SET CURSOR TO BEGINNING OF FIRST LINE
    	LD	(TERM_Y),A		;
    	LD	A,(TERM_X)		;
   	PUSH	AF			; STORE X COORD
    	LD	A,0			;
    	LD	(TERM_X),A		;
    	CALL	GOTO_XY			; SET CURSOR POSITION TO BEGINNING OF LINE
    	POP	AF			; RESTORE AF
    	POP	BC			; RESTORE BC
    	CALL	PERF_ERASE_EOL		; ERASE SCROLLED LINE
	LD	(TERM_X),A		;
   	CALL	GOTO_XY			; SET CURSOR POSITION
    	POP	HL			; RESTORE HL
    	POP	AF			; RESTORE AF
    	RET				;
	
	

;__VDU_INIT_________________________________________________________________________________________
;
; 	INITIALIZE VDU
;__________________________________________________________________________________________________			
VDU_INIT:
	PUSH 	AF			; STORE AF
	PUSH 	DE			; STORE DE
	PUSH 	HL			; STORE HL
	PUSH	BC			; STORE BC

	CALL 	VDU_CRTInit		; INIT 8563 VDU CHIP	
	CALL	VDU_LOADFONT		;
	CALL	PERF_CURSOR_HOME	; CURSOR HOME
	LD	C,14			;	
	CALL	PERF_ERASE_EOS		; CLEAR SCREEN
    	CALL 	VDU_CursorOn		; TURN ON CURSOR

    	POP	BC			;
       	POP 	HL			;
	POP 	DE			;
	POP 	AF			;

   	RET	
	
;__PERF_CURSOR_HOME________________________________________________________________________________
;
; 	PERFORM CURSOR HOME
;__________________________________________________________________________________________________	
PERF_CURSOR_HOME:
	LD	A,0			; LOAD 0 INTO A
	LD	(TERM_X),A		; SET X COORD
	LD	(TERM_Y),A		; SET Y COORD
	JP	GOTO_XY			; MOVE CURSOR TO POSITION

;__PERF_ERASE_EOS__________________________________________________________________________________
;
; 	PERFORM ERASE FROM CURSOR POS TO END OF SCREEN
;       C= DEFAULT COLOR
;__________________________________________________________________________________________________	
PERF_ERASE_EOS:	
	PUSH	HL
	PUSH	AF
	PUSH	BC

    	LD 	HL, (VDU_DisplayPos)	; GET CURRENT DISPLAY ADDRESS
    	LD 	B, 18			; SET UPDATE CSR POS IN VDU
    	LD	A,H			;
    	CALL	VDU_WREG		; WRITE IT
    	LD 	B, 19			; SET UPDATE CSR POS IN VDU
    	LD	A,L			;
    	CALL	VDU_WREG		; WRITE IT   		
	CALL	GOTO_XY			; MOVE CURSOR 
	LD	DE,0820H		; SET SCREEN SIZE INTO HL
PERF_ERASE_EOS_LOOP:		
    	LD 	A, ' '           	; MOVE SPACE CHARACTER INTO A
	LD	B,31			;
       	CALL	VDU_WREG	 	; WRITE IT TO SCREEN, VDU WILL AUTO INC TO NEXT ADDRESS
      	DEC	DE			; DEC COUNTER
    	LD 	A,D			; IS COUNTER 0 YET?
    	OR 	E			;
    	JP 	NZ,PERF_ERASE_EOS_LOOP	; NO, LOOP
	LD	DE,0820H		; SET SCREEN SIZE INTO HL
PERF_ERASE_EOS_CLOOP:		
    	LD 	A, C	           	; MOVE COLOR INTO A
	LD	B,31			;
       	CALL	VDU_WREG	 	; WRITE IT TO SCREEN, VDU WILL AUTO INC TO NEXT ADDRESS
      	DEC	DE			; DEC COUNTER
    	LD 	A,D			; IS COUNTER 0 YET?
    	OR 	E			;
    	JP 	NZ,PERF_ERASE_EOS_CLOOP	; NO, LOOP
    	
	CALL	GOTO_XY			; YES, MOVE CURSOR BACK TO ORIGINAL POSITION
	POP	BC
	POP	AF
	POP	HL
	RET	

;__PERF_ERASE_EOL__________________________________________________________________________________
;
; 	PERFORM ERASE FROM CURSOR POS TO END OF LINE
;       C=DEFAULT COLOR
;__________________________________________________________________________________________________	
PERF_ERASE_EOL:	
	PUSH	HL
	PUSH	AF
	PUSH	BC

	LD	A,(TERM_X)		; GET CURRENT CURSOR X COORD
	LD	D,A			; STORE IT IN C
	LD	A,80			; MOVE CURRENT LINE WIDTH INTO A
	SUB	D			; GET REMAINING POSITIONS ON CURRENT LINE
	LD	B,A			; MOVE IT INTO B
PERF_ERASE_EOL_LOOP:		
    	LD 	A, ' '           	; MOVE SPACE CHARACTER INTO A
	CALL	VDU_PutCharRAW		;
	DJNZ    PERF_ERASE_EOL_LOOP	; LOOP UNTIL DONE
	CALL	GOTO_XY			; MOVE CURSOR BACK TO ORIGINAL POSITION
	POP	BC
	POP	AF
	POP	HL
	RET
		
;__DSPMATRIX_______________________________________________________________________________________
;
; 	DISPLAY INTRO SCREEN
;__________________________________________________________________________________________________			
DSPMATRIX:
	CALL	PERF_CURSOR_HOME	; RESET CURSOR TO HOME POSITION
    	LD	HL,TESTMATRIX		; SET HL TO SCREEN IMAGE
	LD 	DE, 1919   		; SET IMAGE SIZE
	LD	C,00000011B		; SET COLOR
DSPMATRIX_LOOP:    	
    	LD 	A,(HL)			; GET NEXT CHAR FROM IMAGE
    	call 	VDU_PutChar		; DUMP CHAR TO DISPLAY
    	INC	HL			; INC POINTER
	DEC	DE			; DEC COUNTER
    	LD 	A,D			; IS COUNTER ZERO?
    	OR 	E			;
    	JP 	NZ,DSPMATRIX_LOOP	; NO, LOOP
	CALL	PERF_CURSOR_HOME	; YES, RESET CURSOR TO HOME POSITION
	RET

TESTMATRIX:
 .TEXT "0         1         2         3         4         5         6         7         "
 .TEXT "01234567890123456789012345678901234567890123456789012345678901234567890123456789"
 .TEXT "2                                                                               "
 .TEXT "3                                                                               "
 .TEXT "4               =====================================================           "
 .TEXT "5                                                                               "
 .TEXT "6                 ****   *     *  ****    *    *        ****   *  *             "
 .TEXT "7                *    *  *     *  *   *   *    *       *    *  * *              "
 .TEXT "8                *       *     *  *    *  *    *       *    *  **               "
 .TEXT "9                *        *   *   *    *  *    *       *    *  **               "
 .TEXT "10               *    *    * *    *   *   *    *       *    *  * *              "
 .TEXT "11                ****      *     ****     ****         ****   *  *             "
 .TEXT "12                                                                              "
 .TEXT "13              =====================================================           "
 .TEXT "14                                                                              "
 .TEXT "15                         VDU TEST V0.1   VT-52 EMULATION                      "
 .TEXT "16                                                                              "
 .TEXT "17                  **  PRESS ANY KEY TO ENTER TERMINAL MODE **                 "
 .TEXT "18                                                                              "
 .TEXT "19                                                                              "
 .TEXT "21                                                                              "
 .TEXT "22                                                                              "
 .TEXT "23                                                                              "
 .TEXT "24                                                                              "
 

;__VDU_WREG________________________________________________________________________________________
;
; 	WRITE VALUE IN A TO REGISTER IN B
;	B: REGISTER TO UPDATE
;	A: VALUE TO WRITE
;__________________________________________________________________________________________________			
VDU_WREG:
	PUSH 	AF			; STORE AF
VDU_WREG_1:	
	IN 	A,(M8563Status)         ; read address/status register
    	BIT 	7,A             	; if bit 7 = 1 than an update strobe has been occured
    	JR 	Z,VDU_WREG_1	  	; wait for ready
	LD	A,B			;
       	OUT 	(M8563Register),A      	; select register 
VDU_WREG_2:	
	IN 	A,(M8563Status)         ; read address/status register
    	BIT 	7,A             	; if bit 7 = 1 than an update strobe has been occured
    	JR 	Z,VDU_WREG_2	  	; wait for ready
	POP	AF			;
       	OUT 	(M8563Data),A      	; PUT DATA
    	RET


;__VDU_GREG________________________________________________________________________________________
;
; 	GET VALUE FROM REGISTER IN B PLACE IN A
;	B: REGISTER TO GET
;	A: VALUE 
;__________________________________________________________________________________________________			
VDU_GREG:
	IN 	A,(M8563Status)         ; read address/status register
    	BIT 	7,A             	; if bit 7 = 1 than an update strobe has been occured
    	JR 	Z,VDU_GREG	  	; wait for ready
	LD	A,B			;
       	OUT 	(M8563Register) , A    	; select register 
VDU_GREG_1:	
	IN 	A,(M8563Status)         ; read address/status register
    	BIT 	7,A             	; if bit 7 = 1 than an update strobe has been occured
    	JR 	Z,VDU_GREG_1	  	; wait for ready
       	IN 	A,(M8563Data)       	; GET DATA 
    	RET



VDU_Init8563:
    .DB		126,80,102,73,32,224,25,29,252,231,160,231,0,0,7,128
    .DB		18,23,15,208,8,32,120,232,32,71,240,0,47,231,79,7,15,208,125,100,245	
 
;__VDU_CRTInit_____________________________________________________________________________________
;
; 	INIT VDU CHIP
;__________________________________________________________________________________________________			   	
VDU_CRTInit:
    	PUSH 	AF			; STORE AF
    	PUSH 	BC			; STORE BC
    	PUSH 	HL			; STORE HL
    	
    	LD 	B,$00	        	; B = 0 
    	LD 	HL,VDU_Init8563  	; HL = pointer to the default values
    	XOR 	A               	; A = 0
VDU_CRTInitLoop:
	LD	A,(HL)			; GET VALUE
	CALL	VDU_WREG		; WRITE IT
	INC	HL
	INC	B			; 
	LD	A,B			;
	CP	37			;
	JR	NZ,VDU_CRTInitLoop	; LOOP UNTIL DONE
    	POP 	HL			; RESTORE HL
    	POP	BC			; RESTORE BC
    	POP	AF			; RESTORE AF
    	RET


;__VDU_CursorOn____________________________________________________________________________________
;
; 	TURN ON CURSOR
;__________________________________________________________________________________________________			   	
VDU_CursorOn:
    	PUSH 	AF			; STORE AF
    	LD 	A, $60			; SET CURSOR VALUE
    	JP 	VDU_CursorSet		;

;__VDU_CursorOff___________________________________________________________________________________
;
; 	TURN OFF CURSOR
;__________________________________________________________________________________________________			   	   	
VDU_CursorOff:
    	PUSH 	AF			; STORE AF
    	LD 	A, $20			; SET CURSOR VALUE
VDU_CursorSet:
	PUSH 	BC			; STORE BC
	LD	B,10
	CALL	VDU_WREG		; WRITE IT
    	POP 	BC			; RESTORE BC
    	POP 	AF			; RESTORE AF
    	RET

;__GOTO_XY_________________________________________________________________________________________
;
; 	MOVE CURSOR TO POSITON IN TERM_X AND TERM_Y
;__________________________________________________________________________________________________			
GOTO_XY:
	PUSH	AF			; STORE AF

	LD	A,(TERM_Y)		; PLACE Y COORD IN A
	CP	24			; IS 24?
	JP	Z,DO_SCROLLE1		; YES, MUST SCROLL

    	PUSH 	BC			; STORE BC
    	PUSH 	DE			; STORE DE
	LD	A,(TERM_X)		;
	LD	H,A			;
    	LD	A,(TERM_Y)		;
    	LD	L,A			;    	
    	PUSH 	HL			; STORE HL
    	LD 	B, A             	; B = Y COORD
    	LD 	DE, 80			; MOVE LINE LENGTH INTO DE
    	LD 	HL, 0			; MOVE 0 INTO HL
    	LD 	A, B             	; A=B
    	CP 	0			; Y=0?
    	JP 	Z, VDU_YLoopEnd  	; THEN DO NOT MULTIPLY BY 80
VDU_YLoop:              		; HL = 80 * Y
    	ADD 	HL, DE			; HL=HL+DE
    	DJNZ 	VDU_YLoop		; LOOP 
VDU_YLoopEnd:				;
    	POP 	DE              	; DE = org HL
    	LD 	E, D             	; E = X
    	LD 	D, 0             	; D = 0
    	ADD 	HL, DE          	; HL = HL + X
    	LD 	(VDU_DisplayPos), HL	;
	PUSH	HL			;
	POP	DE			;
	LD	HL,(VDU_DISPLAY_START)	;
	ADD	HL,DE			;    		
    	LD 	B, 18			; SET UPDATE ADDRESS IN VDU
    	LD	A,H			;
    	CALL	VDU_WREG		; WRITE IT
    	LD 	B, 19			; SET UPDATE ADDRESS IN VDU
    	LD	A,L			;
    	CALL	VDU_WREG		; WRITE IT
    	
    	LD 	B, 14			; SET UPDATE CSR POS IN VDU
    	LD	A,H			;
    	CALL	VDU_WREG		; WRITE IT
    	LD 	B, 15			; SET UPDATE CSR POS IN VDU
    	LD	A,L			;
    	CALL	VDU_WREG		; WRITE IT
    	POP 	DE			; RESTORE DE
   	POP 	BC			; RESTORE BC
    	POP 	AF			; RESTORE AF
    	RET

;__VDU_PutChar______________________________________________________________________________________
;
; 	PLACE CHARACTER ON SCREEN
;	A: CHARACTER TO OUTPUT
;	C: COLOR
;__________________________________________________________________________________________________			   	   	
VDU_PutChar:
	PUSH	DE			; STORE DE
    	PUSH 	AF			; STORE AF
    	PUSH	HL			; STORE HL
    	LD	D,A			; STORE CHAR IN D
    	LD	A,(TERM_X)		; PLACE X COORD IN A
    	INC	A			; INC X COORD
    	LD	(TERM_X),A		; STORE IN A
    	CP	80			; IS 80?
    	JP	NZ,VDU_PutChar1		; NO, PLACE CHAR ON DISPLAY
    	LD  	A,0			; YES, WRAP TO NEXT LINE
    	LD	(TERM_X),A		; STORE X
    	LD	A,(TERM_Y)		; A= Y COORD
    	INC 	A			; INC Y COORD
    	LD	(TERM_Y),A		; STORE Y
    	CP	24			; IS PAST END OF SCREEN?
    	CALL 	Z,GOTO_XY        	; YES, HANDLE SCROLLING
VDU_PutChar1:				;
					;
    	LD 	HL, (VDU_DisplayPos)	; GET CURRENT DISPLAY ADDRESS
    	LD 	B, 18			; SET UPDATE CSR POS IN VDU
    	LD	A,H			;
    	CALL	VDU_WREG		; WRITE IT
    	LD 	B, 19			; SET UPDATE CSR POS IN VDU
    	LD	A,L			;
    	CALL	VDU_WREG		; WRITE IT   	
       	LD	A,D			; RESTORE CHAR
    	LD	B,31			;
    	CALL	VDU_WREG		; WRITE IT
	PUSH	HL			;
	LD	DE,$0820		;
    	ADD    	HL,DE			;
    	LD 	B, 18			; SET UPDATE CSR POS IN VDU
    	LD	A,H			;
    	CALL	VDU_WREG		; WRITE IT
    	LD 	B, 19			; SET UPDATE CSR POS IN VDU
    	LD	A,L			;
    	CALL	VDU_WREG		; WRITE IT   	
       	LD	A,C			; GET COLOR
    	LD	B,31			;
    	CALL	VDU_WREG		; WRITE IT
	POP	HL			; RESTORE ADDRESS
    	INC 	HL			; INCREMENT IT
    	LD 	(VDU_DisplayPos), HL	; STORE CURRENT DISPLAY ADDRESS
    	PUSH	HL			; MOVE HL TO DE
    	POP	DE			;
    	LD	HL,(VDU_DISPLAY_START)	;
    	ADD	HL,DE			;    	
    	LD 	B, 14			; SET UPDATE CSR POS IN VDU
    	LD	A,H			;
    	CALL	VDU_WREG		; WRITE IT
    	LD 	B, 15			; SET UPDATE CSR POS IN VDU
    	LD	A,L			;
    	CALL	VDU_WREG		; WRITE IT
    	
    	POP 	HL			; RESTORE HL
    	POP 	AF			; RESTORE AF
    	POP	DE			; RESTORE DE
    	RET

VDU_PutCharRAW:	
	PUSH	BC			;
	LD	D,A			;
    	LD 	HL, (VDU_DisplayPos)	; GET CURRENT DISPLAY ADDRESS
    	LD 	B, 18			; SET UPDATE CSR POS IN VDU
    	LD	A,H			;
    	CALL	VDU_WREG		; WRITE IT
    	LD 	B, 19			; SET UPDATE CSR POS IN VDU
    	LD	A,L			;
    	CALL	VDU_WREG		; WRITE IT   	
       	LD	A,D			; RESTORE CHAR
    	LD	B,31			;
    	CALL	VDU_WREG		; WRITE IT
	PUSH	HL			;
	LD	DE,$0820		;
    	ADD    	HL,DE			;
    	LD 	B, 18			; SET UPDATE CSR POS IN VDU
    	LD	A,H			;
    	CALL	VDU_WREG		; WRITE IT
    	LD 	B, 19			; SET UPDATE CSR POS IN VDU
    	LD	A,L			;
    	CALL	VDU_WREG		; WRITE IT   	
       	LD	A,C			; GET COLOR
    	LD	B,31			;
    	CALL	VDU_WREG		; WRITE IT
	POP	HL			; RESTORE ADDRESS
    	INC 	HL			; INCREMENT IT
    	LD 	(VDU_DisplayPos), HL	; STORE CURRENT DISPLAY ADDRESS
    	POP	BC
	RET
	   	
;__VDU_LOADFONT____________________________________________________________________________________
;
; 	LOAD SCREEN FONT
;__________________________________________________________________________________________________			   	   	
VDU_LOADFONT:
	PUSH 	AF
	PUSH	BC
	
	LD	HL,$2000		; SET FONT LOCATION
					;
   	LD 	B, 18			; SET UPDATE ADDRESS IN VDU
    	LD	A,H			;
    	CALL	VDU_WREG		; WRITE IT
    	LD 	B, 19			; SET UPDATE ADDRESS IN VDU
    	LD	A,L			;
    	CALL	VDU_WREG		; WRITE IT

    	LD	B,$00			; FONT SIZE
    	LD	C,$20			; FONT SIZE
	LD	HL,FONT			; FONT DATA
VDU_LOADFONT_LOOP:
	IN 	A,(M8563Status)         ; read address/status register
    	BIT 	7,A             	; if bit 7 = 1 than an update strobe has been occured
    	JR 	Z,VDU_LOADFONT_LOOP  	; wait for ready
	LD	A,31			;
       	OUT 	(M8563Register) , A    	; select register 
VDU_LOADFONT_LOOP_1:	
	IN 	A,(M8563Status)         ; read address/status register
    	BIT 	7,A             	; if bit 7 = 1 than an update strobe has been occured
    	JR 	Z,VDU_LOADFONT_LOOP_1  	; wait for ready
	LD	A,(HL)			;
       	OUT 	(M8563Data) , A      	; PUT DATA
       	INC	HL
       	DJNZ	VDU_LOADFONT_LOOP	;
	DEC	C			;
	JP	NZ,VDU_LOADFONT_LOOP	;	
       	POP	BC
       	POP	AF
       	RET    		

;__KB_INITIALIZE___________________________________________________________________________________
;
; 	INIT KEYBOARD CONTROLLER
;__________________________________________________________________________________________________
KB_INITIALIZE:
	LD	C,0aaH			; SELF TEST
	CALL	I8242CommandPut		;
	LD	C,060H			; SET COMMAND REGISTER
	CALL	I8242CommandPut		;
	LD	C,$60			; XLAT ENABLED, MOUSE DISABLED, NO INTS
	CALL	I8242DataPut		;
	LD	C,0a7H			; DISABLE MOUSE
	CALL	I8242CommandPut		;
	LD	C,0aeH			; ENABLE KEYBOARD
	CALL	I8242CommandPut		;
	LD	A,0			; EMPTY KB QUEUE
	LD	(KB_QUEUE_PTR),A	; 
	RET

;__I8242CommandPut_________________________________________________________________________________
;
; 	WRITE VALUE IN A TO 8242
;	C: VALUE TO WRITE
;__________________________________________________________________________________________________	
I8242CommandPut:
	IN 	A,(I8242Status)         ; read status register
    	BIT 	1,A             	; if bit 1 = 1 
    	JR 	NZ,I8242CommandPut  	; wait for ready
	LD	A,C			;
       	OUT 	(I8242Command),A      	; select register 
	RET

;__I8242DataPut____________________________________________________________________________________
;
; 	WRITE VALUE IN A TO 8242
;	C: VALUE TO WRITE
;__________________________________________________________________________________________________	
I8242DataPut:
	IN 	A,(I8242Status)         ; read status register
    	BIT 	1,A             	; if bit 1 = 1 
    	JR 	NZ,I8242DataPut  	; wait for ready
	LD	A,C			;
       	OUT 	(I8242Data),A      	; select register 
	RET

;__WAIT_KBHIT______________________________________________________________________________________
;
; 	WAIT FOR A KEY PRESS
;__________________________________________________________________________________________________			
WAIT_KBHIT:
	CALL 	KB_PROCESS		; call keyboard routine
	LD	A,(KB_QUEUE_PTR)	; IS QUEUE EMPTY?
	OR 	A			; set flags
	JP 	Z,WAIT_KBHIT		; if no keys waiting, try again
	RET
	
;__IS_KBHIT________________________________________________________________________________________
;
; 	WAS A KEY PRESSED?
;__________________________________________________________________________________________________			
IS_KBHIT:
	CALL 	KB_PROCESS		; call keyboard routine
	LD 	A,(KB_QUEUE_PTR)	; ask if keyboard has key waiting
	RET
	
				
;__GET_KEY_________________________________________________________________________________________
;
; 	GET KEY PRESS VALUE
;__________________________________________________________________________________________________			
GET_KEY:
	CALL	WAIT_KBHIT		; WAIT FOR A KEY
	LD	A,(KB_QUEUE_PTR)	; GET QUEUE POINTER
	OR	A			;
	RET	Z			; ABORT IF QUEUE EMPTY
	PUSH	BC			; STORE BC
	LD	B,A			; STORE QUEUE COUNT FOR LATER
	PUSH	HL			; STORE HL
	LD	A,(KB_QUEUE)		; GET TOP BYTE FROM QUEUE
	PUSH 	AF			; STORE IT
	LD	HL,KB_QUEUE		; GET POINTER TO QUEUE
GET_KEY_LOOP:				;
	INC	HL			; POINT TO NEXT VALUE IN QUEUE
	LD	A,(HL)			; GET VALUE
	DEC 	HL			;
	LD	(HL),A			; MOVE IT UP ONE
	INC	HL			;
	DJNZ	GET_KEY_LOOP		; LOOP UNTIL DONE
	LD	A,(KB_QUEUE_PTR)	; DECREASE QUEUE POINTER BY ONE	
	DEC	A			;
	LD	(KB_QUEUE_PTR),A	;
	POP	AF			; RESTORE VALUE
	POP	HL			; RESTORE HL
	POP	BC			; RESTORE BC
	RET		
	

;__KB_PROCESS______________________________________________________________________________________
;
;  a=0 if want to know if a byte is available, and a=1 to ask for the byte
;__________________________________________________________________________________________________			   	   	
KB_PROCESS:	
	IN 	A,(I8242Status)         ; read status register
    	BIT 	0,A             	; if bit 0 = 0 
    	RET 	Z		 	; EXIT
	IN	A,(I8242Data)		; GET BYTE
	call 	KB_decodechar		; returns char or 0 for things like keyup, some return directly to cp/m
	ret				; return to cp/m

;__KB_waitbyte______________________________________________________________________________________
;
;  WAIT FOR byte TO BE available
;__________________________________________________________________________________________________			   	   	
KB_waitbyte:	
	IN 	A,(I8242Status)         ; read status register
    	BIT 	0,A             	; if bit 0 = 0 
    	jp 	Z,KB_waitbyte		; LOOP
    	IN	A,(I8242Data)		; GET BYTE
	RET


	
;__KB_decodechar____________________________________________________________________________________
;
; decode character pass a and prints out the char
; on the LCD screen
;__________________________________________________________________________________________________			   	   	
KB_decodechar:
	cp	0		; is it zero
	ret	z		; return if a zero - no need to do anything

	ld 	c,a		;
	cp	0AAh		; shift (down, because up would be trapped by 0F above)
	jp 	z,shiftup	;
	cp	0B6h		; other shift key
	jp 	z,shiftup	;
	cp	9Dh		; control key
	jp 	z,controlup	;
	AND 	80H             ; if bit 7 = 1 
	RET 	nz		; ignore char up
	ld 	a,C		;
	cp 	0E0h		; TWO BYTE
	JP	Z,twobyte	;
	cp 	03Ah		; caps lock so toggle
	jp 	z,capstog	;
	cp	2Ah		; shift (down, because up would be trapped by 0F above)
	jp 	z,shiftdown	;
	cp	36h		; other shift key
	jp 	z,shiftdown	;
	cp	01Dh		; control key
	jp 	z,controldown	;
	ld 	c,a		;
	ld 	b,0		; add bc to hl
	ld 	hl,normalkeys	; offset to add
	add 	hl,bc		;	
	ld 	a,(ctrl)	;
	cp 	0		; is control being held down?
	jR	z,dc1		; no so go back to test caps lock on
	ld	a,(hl)		; get the letter, should be smalls 
	sub	96		; a=97 so subtract 96 a=1=^A
	JP	KB_ENQUEUE	; STORE ON KB QUEUE
dc1:	ld 	a,(capslock)	;
	cp 	0		; is it 0, if so then don't add the caps offset
	jr 	z,dc2		;
	ld 	c,080h		; add another 50h to smalls to get caps
	add 	hl,bc		;
dc2:	ld 	a,(hl)		;
	JP	KB_ENQUEUE	; STORE ON KB QUEUE
twobyte:; already got EO so get the next character
	call 	KB_waitbyte
	cp	053h		; delete
	jp	z,deletekey	;
	cp	01Ch		; return on number pad
	jp	z,returnkey	;
	cp	050h		;
	jp	z,downarrow	;
	cp	04Dh		;
	jp	z,rightarrow	;
	cp	04Bh		;
	jp	z,leftarrow	;
	cp	048h		;
	jp	z,uparrow	;
	cp	052h		;
	jp	z,insert	;
	cp	049h		;
	jp	z,pageup	;
	cp	051h		;
	jp	z,pagedown	;
	cp	047h		;
	jp	z,home		;
	cp	04Fh		;
	jp	z,end		;
	ld 	a,0		; returns nothing
	ret
home:				;
	ld	a,1BH		; ESC
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ld	a,'?'		; ?
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ld	a,'w'		; w
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ret			;
end:				;
	ld	a,1BH		; ESC
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ld	a,'?'		; ?
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ld	a,'q'		; q
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ret			;
downarrow:			;
	ld	a,1BH		; ESC
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ld	a,'B'		; B
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ret			;
rightarrow:			;
	ld	a,1BH		; ESC
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ld	a,'C'		; C
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ret			;
leftarrow:			;
	ld	a,1BH		; ESC
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ld	a,'D'		; D
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ret			;
uparrow:			;
	ld	a,1BH		; ESC
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ld 	a,'A'		; A
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ret			;	
insert:				;
	ld	a,1BH		; ESC
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ld	a,'?'		; ?
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ld	a,'p'		; p
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ret			;
pageup:				;
	ld	a,1BH		; ESC
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ld	a,'?'		; ?
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ld	a,'y'		; y
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ret			;
pagedown:			;
	ld	a,1BH		; ESC
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ld	a,'?'		; ?
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ld	a,'s'		; s
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ret			;
controldown:			; same code as shiftdown but diff location
	ld 	a,0ffh		;
	ld	(ctrl),a	; control down
	ld	a,0		;
	ret			;
controlup:			; control key up see shift for explanation
	ld	a,0		;
	ld 	(ctrl),a	;
	ld 	a,0		;
	ret			;
returnkey:			;
	ld 	a,13		;
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ret			;
deletekey:			;
	ld 	a,07fh		; delete key value that cp/m uses
	CALL	KB_ENQUEUE	; STORE ON KB QUEUE
	ret			;
capstog:			;
  	ld 	a,(capslock)	;
	xor 	11111111B	; swap all the bits
	ld 	(capslock),a	;
	ld	a,0		; returns nothing
	ret			;
shiftdown:			; shift is special - hold it down and it autorepeats
				; so once it is down, turn caps on and ignore all further shifts
				; only an F0+shift turns caps lock off again
	ld 	a,0ffh		;
	ld 	(capslock),a	;
	ld 	a,0		; returns nothing
	ret			;
shiftup:			; shiftup turns off caps lock definitely
	ld 	a,0		;
	ld 	(capslock),a	;
	ld 	a,0		; returns nothing
	ret			;

;__KB_ENQUEUE______________________________________________________________________________________
;
;  STORE A BYTE IN THE KEYBOARD QUEUE 
;  A: BYTE TO ENQUEUE
;__________________________________________________________________________________________________			   	   		
KB_ENQUEUE:
	PUSH	DE		; STORE DE
	PUSH	HL		; STORE HL	
	PUSH	AF		; STORE VALUE
	LD	A,(KB_QUEUE_PTR); PUT QUEUE POINTER IN A
	CP	15		; IS QUEUE FULL
	JP	P,KB_ENQUEUE_AB	; YES, ABORT	
	LD	HL,KB_QUEUE	; GET QUEUE POINTER
	PUSH	HL		; MOVE HL TO BC
	POP	BC		; 
	LD	H,0		; ZERO OUT H
	LD	L,A		; PLACE QUEUE POINTER IN L
	ADD	HL,BC		; POINT HL AT THE NEXT LOACTION TO ADD VALUE
	POP	AF		; RESTORE VALUE
	LD	(HL),A		; ENQUEUE VALUE
	LD	A,(KB_QUEUE_PTR); GET QUEUE POINTER
	INC	A		; INC IT
	LD	(KB_QUEUE_PTR),A; STORE QUEUE POINTER
KB_ENQUEUE_AB:
	POP	HL		; RESTORE HL
	POP	DE		; RESTORE DE
	RET
	
	

	
normalkeys: ; The TI character codes, offset from label by keyboard scan code
		.db 000,027,"1","2","3","4","5","6","7","8","9","0","-","=",008,009			;00-0F
		.DB "q","w","e","r","t","y","u","i","o","p","[","]",013,000,"a","s"			;10-1F
		.DB "d","f","g","h","j","k","l",";",27H,60H,000,092,"z","x","c","v"			;20-2F
		.DB "b","n","m",",",".","/",000,000,000," ",000,000,000,000,000,000			;30-3F
		.DB 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000			;40-4F
		.db 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000			;50-5F
		.db 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000			;60-6F
		.db 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000			;70-7F
		.db 000,027,"!","@","#","$","%","^","&","*","(",")","_","+",008,009
		.DB "Q","W","E","R","T","Y","U","I","O","P","{","}",013,000,"A","S"
		.DB "D","F","G","H","J","K","L",":",034,"~",000,"|","Z","X","C","V"
		.DB "B","N","M","<",">","?",000,000,000," ",000,000,000,000,000,000
		.db 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000
		.DB 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000
		.db 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000
		.db 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000
		
		
;		.DB	  0,"*",  0,"*","*","*","*","*",  0,"*","*","*","*",09H,"`",00H
;		.DB   	  0,  0,  0,  0,  0,"q","1",  0,  0,  0,"z","s","a","w","2",0
;		.DB   	  0,"c","x","d","e","4","3",  0,  0," ","v","f","t","r","5",0
;		.DB   	  0,"n","b","h","g","y","6",  0,  0,  0,"m","j","u","7","8",0
;		.DB   	  0,",","k","i","o","0","9",  0,  0,".","/","l",";","p","-",0
;		.DB   	  0,  0,27H,  0,"[","=",  0,  0,  0,  0,0DH,"]",  0,5CH,  0,0
;		.DB   	  0,  0,  0,  0,  0,  0,08H,  0,  0,11H,  0,13H,10H,  0,  0,  0
;		.DB 	0BH,7FH,03H,15H,04H,05H,1BH,00H,"*",02H,18H,16H,0CH,17H,"*",0
;		.DB   	  0,  0,  0,"*",  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0

	
 .include "font.asm"	

;__________________________________________________________________________________________________
;
; 	RAM STORAGE AREAS
;__________________________________________________________________________________________________			

ALT_KEYPAD	.DB	0		; ALT KEYPAD ENABLED?	
GR_MODE		.DB	0		; GRAPHICS MODE ENABLED?
TERM_X:		.DB	0		; CURSOR X
TERM_Y:		.DB	0		; CURSOR Y
TERMSTATE:	.DB	0		; TERMINAL STATE
					; 0 = NORMAL
					; 1 = ESC RCVD
VDU_DisplayPos:	.DW  	0		; CURRENT DISPLAY POSITION
VDU_DISPLAY_START:
		.DW  	0		; CURRENT DISPLAY POSITION
capslock	.DB  	0		; location for caps lock, either 00000000 or 11111111
ctrl		.DB  	0		; location for ctrl on or off 00000000 or 11111111
numlock		.DB  	0		; location for num lock
skipcount	.DB	0		; only check some calls, speeds up a lot of cp/m

KB_QUEUE	.DB	0,0,0,0,0,0,0,0 ; 16 BYTE KB QUEUE
		.DB	0,0,0,0,0,0,0,0
KB_QUEUE_PTR	.DB	0		; POINTER TO QUEUE			
PARKSTACK	.DW	0000		; SAVE STACK POINTER 

		.DB	0,0,0,0,0,0,0,0 ;
		.DB	0,0,0,0,0,0,0,0	;
		.DB	0,0,0,0,0,0,0,0 ;
		.DB	0,0,0,0,0,0,0,0	;
		.DB	0,0,0,0,0,0,0,0 ;
		.DB	0,0,0,0,0,0,0,0	;
		.DB	0,0,0,0,0,0,0,0 ;
		.DB	0,0,0,0,0,0,0,0	;
		.DB	0,0,0,0,0,0,0,0 ;
		.DB	0,0,0,0,0,0,0,0	;
		.DB	0,0,0,0,0,0,0,0 ;
		.DB	0,0,0,0,0,0,0,0	;
TERMSTACK:	.DB	0		;


	.end
