;__VDUCONS__________________________________________________________________________________________
;
;	VDUCONS
;
;	VDU DRIVERS BY:  ANDREW LYNCH
;	KEYBOARD DRIVERS BY: DR. JAMES MOXHAM
;	REMAINDER WRITTEN BY: DAN WERNER -- 11/7/2009
; 	CONVERTED TO 6809:  Dan Werner 6/27/2010
;__________________________________________________________________________________________________
;

; DATA CONSTANTS
;__________________________________________________________________________________________________

OSRAM		EQU       $0000
OSEND		EQU       $CBFF
OSUTIL		EQU       $C000

READR		EQU	$F1F0		; READ VDU
WRITR		EQU	$F1F1		; WRITE VDU
SY6545S		EQU	$F1F2		; VDU STATUS/REGISTER
SY6545D		EQU	$F1F3		;
ppia		EQU	$F1F4		; PPI port A
ppib		EQU	$F1F5		; PPI port B
ppic		EQU	$F1F6		; PPI port C
ppicont		EQU	$F1F7		; PPI control port


STATE_NORMAL	EQU	$00		; NORMAL TERMINAL OPS
STATE_ESC	EQU	$01		; ESC MODE
STATE_DIR_L	EQU	$02		; ESC-Y x *
STATE_DIR_C	EQU	$03		; ESC-Y * x

ESC_KEY		EQU	$1B		; ESCAPE CODE




	.ORG	$0000
;__________________________________________________________________________________________________
; MAIN PROGRAM BEGINS HERE
;__________________________________________________________________________________________________
    	JSR	VDU_INIT		; INIT VDU   					
	JSR 	KB_INITIALIZE		; INIT KB
	JSR	PR_INITIALIZE		; INIT PR
    	
   	JSR	DSPMATRIX		; DISPLAY INIT MATRIX SCREEN
	JSR	WAIT_KBHIT		; WAIT FOR A KEYSTROKE
	CLRA				; EMPTY KB QUEUE
	STAA	KB_QUEUE_PTR		; 
	
	JSR	PERF_ERASE_EOS		; CLEAR SCREEN
	JSR	PERF_CURSOR_HOME	; CURSOR HOME	

MLOOP:
	JSR	IS_KBHIT
	CMPA	#$00
	BEQ	MLOOP
	JSR	GET_KEY
	CMPA	#'!'
	BEQ	MEXIT
	JSR	CHARIN
	JMP	MLOOP
MEXIT:	
	SWI
	FCB	$00			; EXIT PROGRAM

	RTS 


;__CHARIN__________________________________________________________________________________________
;
; 	PROCESS INCOMMING CHARACTER AND DISPLAY ON SCREEN OR PERFORM FUNCTION
;	A:  INCOMMING CHARACTER
;__________________________________________________________________________________________________
CHARIN:
	PSHS	A			; STORE A
	LDAA	TERMSTATE		; MOVE CURRENT STATE INTO A
	CMPA	#STATE_NORMAL		; NORMAL PROCESSING STATE?
	BEQ	CHARIN_NORM		;
	CMPA	#STATE_ESC		; ESCAPE PROCESSING STATE?
	BNE	NCHARIN_ESCSTATE	;
	JMP	CHARIN_ESCSTATE		;
NCHARIN_ESCSTATE:		
	CMPA	#STATE_DIR_L		; WAITING FOR Y COORD STATE?
	BEQ	CHARIN_DIR_L_STATE	;
	CMPA	#STATE_DIR_C		; WAITING FOR X COORD STATE?
	BEQ	CHARIN_DIR_C_STATE	;
	LDAA	#STATE_NORMAL		; UNKNOWN STATE, RESET STATE
	STAA	TERMSTATE		;
	PULS	A			; 
	RTS 				;

;__CHARIN_DIR_L_STATE______________________________________________________________________________
;
; 	PROCESS "WAITING FOR Y COORD STATE"
;__________________________________________________________________________________________________
CHARIN_DIR_L_STATE:
	PULS	A			; GET CHAR FROM STACK
	SUBA	#32			; DECODE CHAR INTO USABLE Y COORD
	CMPA	#23			; IS OFF SCREEN?
	BLE	CHARIN_DIR_L_STATE_CONT
	LDAA	#23			; YES, PLACE CRSR ON LAST ROW
CHARIN_DIR_L_STATE_CONT:	
	STAA	TERM_Y			; NO, USE DECODED VALUE	
	LDAA	#STATE_DIR_C		; SET UP STATE TO GET X COORD
	STAA	TERMSTATE		;
	RTS 

;__CHARIN_DIR_C_STATE______________________________________________________________________________
;
; 	PROCESS "WAITING FOR X COORD STATE"
;__________________________________________________________________________________________________	
CHARIN_DIR_C_STATE:
	PULS	A			; GET CHAR FROM STACK
	SUBA	#32			; DECODE CHAR INTO USABLE X COORD
	CMPA	#79			; IS OFF SCREEN?
	BLE	CHARIN_DIR_C_STATE_CONT
	LDAA	#79			; YES, PLACE CRSR IN LAST COLUMN
CHARIN_DIR_C_STATE_CONT:	
	STAA	TERM_X			; NO, USE DECODED VALUE
	JSR 	GOTO_XY			; SET CURSOR POS
	LDAA	#STATE_NORMAL		; RESET STATE TO NORMAL
	STAA	TERMSTATE		;
	RTS 
	
	
;__CHARIN_NORM_____________________________________________________________________________________
;
; 	PROCESS NORMAL STATE
;__________________________________________________________________________________________________	
CHARIN_NORM:
	PULS	A			; GET CHAR FROM STACK
	CMPA	#$0A			; IS LINEFEED?
	BEQ	CHARIN_LF		;
	CMPA	#$09			; IS TAB?
	BEQ	CHARIN_TAB		;
	CMPA	#$08			; IS BS?
	BEQ	CHARIN_BS		;
	CMPA	#$0D			; IS CR?
	BEQ	CHARIN_CR		;
	CMPA	#$07			; IS BELL?
	BEQ	CHAR_IGNORE		;
	CMPA	#$13			; IS XOFF?
	BEQ	CHAR_IGNORE		;
	CMPA	#$11			; IS XON?
	BEQ	CHAR_IGNORE		;
	CMPA	#ESC_KEY		; IS ESC?
	BEQ	CHARIN_ESC		;
	JMP	VDU_PutChar		; NORMAL OUTPUT CHAR
CHAR_IGNORE:
	RTS
		
;__CHARIN_ESC______________________________________________________________________________________
;
; 	PROCESS "ESC" STATE
;__________________________________________________________________________________________________	
CHARIN_ESC:	
	LDAA	#STATE_ESC		; ESC PRESSED, STATE TO ESCPRESSED
	STAA	TERMSTATE		;
    	RTS 
    	
;__CHARIN_LF_______________________________________________________________________________________
;
; 	PROCESS LINE FEED
;__________________________________________________________________________________________________	
CHARIN_LF:
	LDAA	TERM_Y			; MOVE CRSR Y COORD INTO A
	INCA				; INC A
	STAA	TERM_Y			; STORE NEW Y COORD 
	JMP	GOTO_XY			; SET CRSR POSITION
	
	
;__CHARIN_TAB______________________________________________________________________________________
;
; 	PROCESS TABS
;__________________________________________________________________________________________________	
CHARIN_TAB:
	LDX	#TABSTOPS		; SET HL TO TAB STOP TABLE
CHARIN_TAB_LOOP:	
	LDAA	,X+			; GET NEXT TAB STOP
	CMPA	#$00			; IS ZERO?
	BEQ	CHARIN_TAB_EXIT		; END OF TABLE, PROCESS 73+
	CMPA	TERM_X			; IS CURRENT ENTRY > X COORD?
	BLE	CHARIN_TAB_LOOP		; NO, LOOP
	STAA	TERM_X			; YES, USE IT
	JMP	GOTO_XY			; SET CRSR POSITION
CHARIN_TAB_EXIT:	
	LDAA	TERM_X			; COLUMN IS PAST LAST TAB STOP, SET A TO CRSR POS
	CMPA	#79			; IS LAST PHYSICAL POS?	
	BEQ	CHARIN_TAB_EXIT1	; YES, DO NOTHING
	INCA				; NO, INC CRSR BY ONE
	STAA	TERM_X			; STORE NEW X COORD
	JMP	GOTO_XY			; SET CRSR POSITION
CHARIN_TAB_EXIT1:		
	RTS
TABSTOPS:	
	FCB	09,17,25,33,41,49,57,65,73,00
	
		
;__CHARIN_BS_______________________________________________________________________________________
;
; 	PROCESS BACKSPACE
;__________________________________________________________________________________________________	
CHARIN_BS:		
	JMP	PERF_CURSOR_LEFT	; PERFORM CRSR LEFT FUNCTION
	
	
;__CHARIN_CR_______________________________________________________________________________________
;
; 	PROCESS CARRAGE return
;__________________________________________________________________________________________________	
CHARIN_CR:
	CLRA				; MOVE 0 TO X COORD 
	STAA	TERM_X			;
	JMP	GOTO_XY			; GOTO XY COORDS
	
		
;__CHARIN_ESCSTATE_________________________________________________________________________________
;
; 	PROCESS ESC STATE 
;__________________________________________________________________________________________________	
CHARIN_ESCSTATE:
	PULS	A			;
	CMPA	#'A'			; IS CURSOR UP?
	BNE	NPERF_CURSOR_UP		;
	JMP	PERF_CURSOR_UP
NPERF_CURSOR_UP:
	CMPA	#'B'			; IS CURSOR DOWN?
	BNE	NPERF_CURSOR_DOWN	;
	JMP	PERF_CURSOR_DOWN
NPERF_CURSOR_DOWN:	
	CMPA	#'C'			; IS CURSOR RIGHT?
	BNE	NPERF_CURSOR_RIGHT	;
	JMP	PERF_CURSOR_RIGHT
NPERF_CURSOR_RIGHT:	
	CMPA	#'D'			; IS CURSOR LEFT?
	BNE	NPERF_CURSOR_LEFT	;
	JMP	PERF_CURSOR_LEFT
NPERF_CURSOR_LEFT:	
	CMPA	#'F'			; IS ENTER GRAPHICS MODE?
	BEQ	IGNORE_OPTION		;
	CMPA	#'G'			; IS EXIT GRAPHICS MODE?
	BEQ	IGNORE_OPTION		;
	CMPA	#'H'			; IS CURSOR HOME?
	BNE	NPERF_CURSOR_HOME	;
	JMP	PERF_CURSOR_HOME
NPERF_CURSOR_HOME:	
	CMPA	#'I'			; IS CURSOR HOME?
	BEQ	PERF_REVERSE_LF		;
	CMPA	#'Y'			; IS REVERSE LINE FEED?
	BEQ	PERF_DIRECT_ADDRESS	;
	CMPA	#'K'			; IS ERASE TO END OF LINE?
	BEQ	PERF_ERASE_EOL		;
	CMPA	#'J'			; IS ERASE TO END OF SCREEN?
	BNE	NOPERF_ERASE_EOS	;	
	JMP	PERF_ERASE_EOS
NOPERF_ERASE_EOS:
	CMPA	#'Z'			; IS TERMINAL IDENTIFY?
	BNE	NPERF_IDENTIFY		;	
	JMP	PERF_IDENTIFY
NPERF_IDENTIFY:
	CMPA	#'{'			; IS ENTER HOLD SCREEN MODE?
	BEQ	IGNORE_OPTION		;	
	CMPA	#$5C			; IS EXIT HOLD SCREEN MODE?
	BEQ	IGNORE_OPTION		;	
	CMPA	#'='			; IS ENTER ALT KEYPAD MODE?
	BEQ	IGNORE_OPTION		;	
	CMPA	#'}'			; IS EXIT ALT KEYPAD MODE?
	BEQ	IGNORE_OPTION		;	
	JSR	VDU_PutChar		; NORMAL OUTPUT CHAR
IGNORE_OPTION:	
	JMP	SET_STATE_NORMAL	;


;__PERF_REVERSE_LF_________________________________________________________________________________
;
; 	PERFORM REVERSE LINE FEED
;__________________________________________________________________________________________________	
PERF_REVERSE_LF:
	JSR	SET_STATE_NORMAL	; SET STATE TO NORMAL
	LDAA	TERM_Y			; GET CURRENT Y COORD INTO A
	CMPA	#$00			; IS ZERO
	BNE	NREVERSE_SCROLL		; YES, SCROLL SCREEN DOWN ONE LINE
	JMP	REVERSE_SCROLL		;
NREVERSE_SCROLL:	
	DECA				; NO, MOVE CRSR UP ONE LINE
	STAA	TERM_Y			; STORE NEW CRSR POSITION
	JMP	GOTO_XY			; POSITION CRSR
	
	
;__PERF_DIRECT_ADDRESS_____________________________________________________________________________
;
; 	PERFORM DIRECT CURSOR ADDRESSING
;__________________________________________________________________________________________________	
PERF_DIRECT_ADDRESS:	
	LDAA	#STATE_DIR_L		; SET STATE "WAITING FOR Y COORD"
	STAA	TERMSTATE		;
    	RTS 				;
    	
	
;__SET_STATE_NORMAL________________________________________________________________________________
;
; 	SET NORMAL STATE
;__________________________________________________________________________________________________	
SET_STATE_NORMAL:
	LDAA	#STATE_NORMAL		; RESET STATE
	STAA	TERMSTATE		;
	RTS 	
	
;__PERF_ERASE_EOL__________________________________________________________________________________
;
; 	PERFORM ERASE FROM CURSOR POS TO END OF LINE
;__________________________________________________________________________________________________	
PERF_ERASE_EOL:	
	PSHS	D,X,Y
	LDAA	TERM_X
	PSHS	A
	LDAA	TERM_Y
	PSHS	A
	LDAA	TERM_X
	LDAA	#80
	SUBA	TERM_X
	STAA	TEMPW+1
	CLRA	TEMPW
	LDY	TEMPW
PERF_ERASE_EOL1:	
	LDAA	#32			; MOVE SPACE CHARACTER INTO A
	JSR	VDU_PutChar		;
	DEY				;
	CPY	#$0000			;
	BNE	PERF_ERASE_EOL1		;
PERF_ERASE_EOL_DONE:
	PULS	A
	STAA	TERM_Y
	PULS	A
	STAA	TERM_X
	JSR	GOTO_XY			; MOVE CURSOR BACK TO ORIGINAL POSITION
	JSR	SET_STATE_NORMAL	; SET NORMAL STATE
	PULS	D,X,Y,PC

;__PERF_ERASE_EOS__________________________________________________________________________________
;
; 	PERFORM ERASE FROM CURSOR POS TO END OF SCREEN
;__________________________________________________________________________________________________	
PERF_ERASE_EOS:	
	PSHS	D,X,Y
	LDAA	TERM_X
	PSHS	A
	LDAA	TERM_Y
	PSHS	A
	LDAD	VDU_DisplayPos
	SUBD	VDU_DISPLAY_START
	STAD	TEMPW
	LDAD	#$077F			
	SUBD	TEMPW
	STAD	TEMPW
	LDY	TEMPW
PERF_ERASE_EOS1:	
	CPY	#0000
	BEQ	PERF_ERASE_EOS_DONE	
	DEY	
	LDAA	#32			; MOVE SPACE CHARACTER INTO A
	JSR	VDU_PutChar		;
	BRA	PERF_ERASE_EOS1		;
PERF_ERASE_EOS_DONE:
	PULS	A
	STAA	TERM_Y
	PULS	A
	STAA	TERM_X
	JSR	GOTO_XY			; MOVE CURSOR BACK TO ORIGINAL POSITION
	JSR	SET_STATE_NORMAL	; SET NORMAL STATE
	PULS	D,X,Y,PC



	
;__PERF_IDENTIFY___________________________________________________________________________________
;
; 	PERFORM TERMINAL IDENTIFY FUNCTION
;__________________________________________________________________________________________________	
PERF_IDENTIFY:
	LDAA	#ESC_KEY		;
	JSR	KB_ENQUEUE		; STORE ON KB QUEUE
	LDAA	#'/'			;
	JSR	KB_ENQUEUE		; STORE ON KB QUEUE
	LDAA	#'K'			;
	JSR	KB_ENQUEUE		; STORE ON KB QUEUE
	JSR	SET_STATE_NORMAL	; SET NORMAL STATE
	RTS 
	
;__PERF_CURSOR_HOME________________________________________________________________________________
;
; 	PERFORM CURSOR HOME
;__________________________________________________________________________________________________	
PERF_CURSOR_HOME:
	CLRA				; LOAD 0 INTO A
	STAA	TERM_X			; SET X COORD
	STAA	TERM_Y			; SET Y COORD
	JSR	SET_STATE_NORMAL	; SET NORMAL STATE
	JMP	GOTO_XY			; MOVE CURSOR TO POSITION
		
;__PERF_CURSOR_LEFT________________________________________________________________________________
;
; 	PERFORM CURSOR LEFT
;__________________________________________________________________________________________________	
PERF_CURSOR_LEFT:
	LDAA	TERM_X			; GET CURRENT X COORD INTO A
	CMPA	#$00			; IS ZERO?
	BEQ	PERF_CURSOR_ABORT	; YES, ABORT
	DECA				; MOVE ONE TO THE LEFT
	STAA	TERM_X			; STORE NEW CURSOR POSITION
	JSR	SET_STATE_NORMAL	; SET NORMAL STATE	 
	JMP	GOTO_XY			; MOVE CURSOR TO POSITION
	
;__PERF_CURSOR_RIGHT_______________________________________________________________________________
;
; 	PERFORM CURSOR RIGHT
;__________________________________________________________________________________________________	
PERF_CURSOR_RIGHT:
	LDAA	TERM_X			; GET CURRENT X COORD INTO A
	CMPA	#79			; IS END OF LINE?
	BEQ	PERF_CURSOR_ABORT	; YES, ABORT
	INCA				; MOVE ONE TO THE RIGHT
	STAA	TERM_X			; STORE NEW CURSOR POSITION
	JSR	SET_STATE_NORMAL	; SET NORMAL STATE
	JMP	GOTO_XY			; MOVE CURSOR TO POSITION
	
;__PERF_CURSOR_UP__________________________________________________________________________________
;
; 	PERFORM CURSOR UP
;__________________________________________________________________________________________________		
PERF_CURSOR_UP:
	LDAA	TERM_Y			; GET CURRENT Y COORD INTO A
	CMPA	#$00			; IS ZERO?
	BEQ	PERF_CURSOR_ABORT	; YES, ABORT
	DECA				; MOVE UP ONE POSITION
	STAA	TERM_Y			; STORE NEW CURSOR POSITION
	JSR	SET_STATE_NORMAL	; SET NORMAL STATE
	JMP	GOTO_XY			; MOVE CURSOR TO POSTION
	
	
;__PERF_CURSOR_DOWN________________________________________________________________________________
;
; 	PERFORM CURSOR DOWN
;__________________________________________________________________________________________________		
PERF_CURSOR_DOWN:	
	LDAA	TERM_Y			; GET CURRENT Y COORD INTO A
	CMPA	#23			; IS END OF SCREEN?
	BEQ	PERF_CURSOR_ABORT	; YES, ABORT
	INCA				; NO, MOVE DOWN ONE POSITION
	STAA	TERM_Y			; STORE NEW CURSOR POSITION
PERF_CURSOR_ABORT:
	JSR	SET_STATE_NORMAL	; SET NORMAL STATE
	JMP	GOTO_XY			; MOVE CURSOR TO POSITION

			
;__DO_SCROLL_______________________________________________________________________________________
;
; 	SCROLL THE SCREEN UP ONE LINE
;__________________________________________________________________________________________________			
DO_SCROLL:
	PSHS	D			; STORE AF	
	LDAA 	#31	            	; TOGGLE VDU FOR UPDATE
	STAA 	SY6545S         	;
	JSR 	VDU_UpdateCheck 	; WAIT FOR VDU TO BE READY
	LDAD 	VDU_DISPLAY_START	; GET UP START OF DISPLAY
	ADDD	#$0050			; SET AMOUNT TO ADD
	STAD	VDU_DISPLAY_START	; STORE DISPLAY START
	LDX	VDU_DISPLAY_START
	LDAA 	#12			; SAVE START OF DISPLAY TO VDU
	JSR 	VDU_HL2WREG_A		;
    	LDAA	#23			; SET CURSOR TO BEGINNING OF LAST LINE
    	STAA	TERM_Y			;
    	LDAA	TERM_X			;
    	PSHS	A			; STORE X COORD
    	CLRA				;
    	STAA	TERM_X			;
    	JSR	GOTO_XY			; SET CURSOR POSITION TO BEGINNING OF LINE
    	JSR	PERF_ERASE_EOS		; ERASE SCROLLED LINE
	PULS	A			; RESTORE X COORD
	STAA	TERM_X			;
    	JSR	GOTO_XY			; SET CURSOR POSITION
    	PULS	D			; RESTORE AF
    	RTS 				;
    	
;__REVERSE_SCROLL__________________________________________________________________________________
;
; 	SCROLL THE SCREEN DOWN ONE LINE
;__________________________________________________________________________________________________			
REVERSE_SCROLL:
	PSHS	D			; STORE AF
	LDAA 	#31	            	; TOGGLE VDU FOR UPDATE
	STAA 	SY6545S         	;
	JSR 	VDU_UpdateCheck 	; WAIT FOR VDU TO BE READY
	LDAD 	VDU_DISPLAY_START	; GET UP START OF DISPLAY
	ADDD	#$0FFB0			; SET AMOUNT TO SUBTRACT (TWOS COMPLEMENT 50H)
	STAD	VDU_DISPLAY_START	; STORE DISPLAY START
	LDX	VDU_DISPLAY_START	;
	LDAA 	#12			; SAVE START OF DISPLAY TO VDU
	JSR 	VDU_HL2WREG_A		;
    	LDAA	#00			; SET CURSOR TO BEGINNING OF LAST LINE
    	STAA	TERM_Y			;
    	LDAA	TERM_X			;
    	PSHS	A			; STORE X COORD
    	CLRA				;
    	STAA	TERM_X			;
    	JSR	GOTO_XY			; SET CURSOR POSITION TO BEGINNING OF LINE
    	JSR	PERF_ERASE_EOL		; ERASE SCROLLED LINE
	PULS	A			; RESTORE X COORD
	STAA	TERM_X			;
    	JSR	GOTO_XY			; SET CURSOR POSITION
    	PULS	D			; RESTORE AF
    	RTS 				;
    			
	
	
;__WAIT_KBHIT______________________________________________________________________________________
;
; 	WAIT FOR A KEY PRESS
;__________________________________________________________________________________________________			
WAIT_KBHIT:
	JSR 	KB_PROCESS		; JSR keyboard routine
	LDAA	KB_QUEUE_PTR		; IS QUEUE EMPTY?
	CMPA	#$00			; set flags
	BEQ 	WAIT_KBHIT		; if no keys waiting, try again
	RTS 

	
;__IS_KBHIT________________________________________________________________________________________
;
; 	WAS A KEY PRESSED?
;__________________________________________________________________________________________________			
IS_KBHIT:
	JSR 	KB_PROCESS		; JSR keyboard routine
	LDAA	KB_QUEUE_PTR		; ask if keyboard has key waiting
	RTS 
	
				
;__GET_KEY_________________________________________________________________________________________
;
; 	GET KEY PRESS VALUE
;__________________________________________________________________________________________________			
GET_KEY:
	JSR	WAIT_KBHIT		; WAIT FOR A KEY
	LDAA	KB_QUEUE_PTR		; GET QUEUE POINTER
	CMPA	#$00			;
	BEQ	GET_KEY_EXIT		; ABORT IF QUEUE EMPTY
	LDAA	KB_QUEUE		; GET TOP BYTE FROM QUEUE
	PSHS	D,X			; STORE REGISTERS
	LDX	#KB_QUEUE		; GET POINTER TO QUEUE
GET_KEY_LOOP:				;
	INX				; POINT TO NEXT VALUE IN QUEUE
	LDAB	,X			; GET VALUE
	DEX				;
	STAB	,X+			; MOVE IT UP ONE
	CPX	#KB_QUEUE+16
	BNE	GET_KEY_LOOP		; LOOP UNTIL DONE
	DEC	KB_QUEUE_PTR		; DECREASE QUEUE POINTER BY ONE	
	PULS	D,X			; RESTORE VALUE
GET_KEY_EXIT:
	RTS 		

		
		
	
	

;__VDU_INIT_________________________________________________________________________________________
;
; 	INITIALIZE VDU
;__________________________________________________________________________________________________			
VDU_INIT:
	PSHS 	A,Y,X			; STORE A Y X
	JSR 	VDU_CRTInit		; INIT 6545 VDU CHIP	
	LDY 	#2048    		; SET-UP DISPLAY SIZE	
	LDAA 	#31			; TOGGLE VDU FOR UPDATE
	STAA 	SY6545S			;
	LDX	#$0000
VDU_CRTSpaceLoop:			;	
	LDAA 	#18 	           	; write X to R18 and R19 (update address)
	JSR 	VDU_HL2WREG_A  		;
	LDAA 	#31	            	; TOGGLE VDU FOR UPDATE
	STAA 	SY6545S         	;
	JSR 	VDU_UpdateCheck 	; WAIT FOR VDU TO BE READY
	LDAA 	#' '	           	; CLEAR SCREEN
	STAA 	WRITR	         	; send space to dataport
	DEY				; DECREMENT DE
	INX				;
	CPY	#$0000			; IS ZERO?
	BNE 	VDU_CRTSpaceLoop	; NO, LOOP
	LDAA 	#31 	           	; TOGGLE VDU FOR UPDATE
	STAA 	SY6545S         	;
	LDX	#$0000			; SET UP START OF DISPLAY
	STX	VDU_DISPLAY_START	; STORE DISPLAY START
	LDAA 	#12			; SAVE START OF DISPLAY TO VDU
	JSR 	VDU_HL2WREG_A		;
	PULS 	A,Y,X			;
	JSR	PERF_CURSOR_HOME	; CURSOR HOME	
    	JMP 	VDU_CursorOn		; TURN ON CURSOR
	

;__DSPMATRIX_______________________________________________________________________________________
;
; 	DISPLAY INTRO SCREEN
;__________________________________________________________________________________________________			
DSPMATRIX:
	JSR	PERF_CURSOR_HOME	; RESET CURSOR TO HOME POSITION
    	LDX	#TESTMATRIX		; SET HL TO SCREEN IMAGE
	LDY 	#1918    		; SET IMAGE SIZE
DSPMATRIX_LOOP:    	
    	LDAA	,X+			; GET NEXT CHAR FROM IMAGE
    	JSR 	VDU_PutChar		; DUMP CHAR TO DISPLAY
	DEY				; DEC COUNTER
    	CPY	#$0000			; IS COUNTER ZERO?
    	BNE 	DSPMATRIX_LOOP		; NO, LOOP
	JSR	PERF_CURSOR_HOME	; YES, RESET CURSOR TO HOME POSITION
	RTS 

TESTMATRIX:
 FCC "0         1         2         3         4         5         6         7         "
 FCC "01234567890123456789012345678901234567890123456789012345678901234567890123456789"
 FCC "2                                                                               "
 FCC "3                                                                               "
 FCC "4                 ===============================================               "
 FCC "5                                                                               "
 FCC "6                   *     *  ****    *    *        ****   *  *                  "
 FCC "7                   *     *  *   *   *    *       *    *  * *                   "
 FCC "8                   *     *  *    *  *    *       *    *  **                    "
 FCC "9                    *   *   *    *  *    *       *    *  **                    "
 FCC "10                    * *    *   *   *    *       *    *  * *                   "
 FCC "11                     *     ****     ****         ****   *  *                  "
 FCC "12                                                                              "
 FCC "13                ===============================================               "
 FCC "14                                                                              "
 FCC "15                         VDU TEST V0.1   VT-52 EMULATION                      "
 FCC "16                                                                              "
 FCC "17                  **  PRESS ANY KEY TO ENTER TERMINAL MODE **                 "
 FCC "18                                                                              "
 FCC "19                                                                              "
 FCC "21                                                                              "
 FCC "22                                                                              "
 FCC "23                                                                              "
 FCC "24                                                                              "
 FCC "25                                                                              "


;__VDU_HL2WREG_A___________________________________________________________________________________
;
; 	WRITE VALUE IN HL TO REGISTER IN A
;	A: REGISTER TO UPDATE
;	HL: WORD VALUE TO WRITE
;__________________________________________________________________________________________________			
VDU_HL2WREG_A:
	PSHS 	A			; STORE A
    	JSR 	VDU_UpdateCheck 	; WAIT FOR VDU TO BE READY
    	PULS 	A			; RESTORE A
    	STAA 	SY6545S           	; address register
    	PSHS	X			;
    	PULS	B			;
     	STAB 	SY6545D          	; write H to selected register
    	INCA 		               	; increase register number
    	STAA 	SY6545S  		; address register
    	PULS	B	         	;
    	STAB	SY6545D          	; write H to selected register
    	RTS 

;__VDU_UpdateCheck_________________________________________________________________________________
;
; 	WAIT FOR VDU TO BE READY
;__________________________________________________________________________________________________			
VDU_UpdateCheck:
	LDAA	#31
	STAA	SY6545S
VDU_UpdateCheck1:	
    	LDAA 	SY6545S          	; read address/status register
    	ANDA 	#%10000000             	; if bit 7 = 1 than an update strobe has been occured
    	BEQ	VDU_UpdateCheck1	;
	RTS
VDU_Init6845:
    FCB	 $7F, $50, $60, $0C, $1E, $02, $18, $1C, $78, $09, $60, $09, $00, $00, $00, $00

;__VDU_CRTInit_____________________________________________________________________________________
;
; 	INIT VDU CHIP
;__________________________________________________________________________________________________			   	
VDU_CRTInit:
    	PSHS 	D			; STORE D
    	PSHS	X			; STORE X
    	LDAB 	#$0010	         	; B = 16
    	LDX 	#VDU_Init6845	  	; HL = pointer to the default values
    	CLRA 		               	; A = 0
VDU_CRTInitLoop:
    	STAA 	SY6545S          	; SY6545S set register
    	PSHS	A			;
    	LDAA 	,X+	          	; load the next default value in D
    	STAA 	SY6545D        		; $F3 address
    	PULS	A			;
    	INCA				;
    	DECB 		               	; reg + 1
    	CMPB	#$00			;
    	BNE 	VDU_CRTInitLoop		; LOOP UNTIL DONE
    	PULS 	X			; RESTORE X
    	PULS 	D			; RESTORE D    	    	
    	RTS 


;__VDU_CursorOn____________________________________________________________________________________
;
; 	TURN ON CURSOR
;__________________________________________________________________________________________________			   	
VDU_CursorOn:
    	PSHS 	D			; STORE AF
    	LDAB 	#$60			; SET CURSOR VALUE
    	JMP 	VDU_CursorSet		;

;__VDU_CursorOff___________________________________________________________________________________
;
; 	TURN OFF CURSOR
;__________________________________________________________________________________________________			   	   	
VDU_CursorOff:
    	PSHS 	D			; STORE D
    	LDAB 	#$20			; SET CURSOR VALUE
VDU_CursorSet:
    	JSR 	VDU_UpdateCheck    	; WAIT FOR VDU TO BE READY
    	LDAA	#10	            	; R10, cursor start and status
    	STAA 	SY6545S			; 
    	STAB 	SY6545D	        	;
    	PULS 	D			; RESTORE D
    	RTS 

;__GOTO_XY_________________________________________________________________________________________
;
; 	MOVE CURSOR TO POSITON IN TERM_X AND TERM_Y
;__________________________________________________________________________________________________			
GOTO_XY:
	PSHS	D			; STORE D
    	PSHS 	X			; STORE X

	LDAA	TERM_Y			; PLACE Y COORD IN A
	CMPA	#24			; IS 24?
	BEQ	GOTO_XY_SCROLL		; YES, MUST SCROLL
	CLR	TEMPW			;
	LDAA	TERM_X			;
	STAA	TEMPW+1			;	
	LDAA	#80			;
    	LDAB	TERM_Y			;
    	MUL				;    	
    	ADDD	TEMPW			;
    	ADDD    VDU_DISPLAY_START	;
    	STAD	VDU_DisplayPos		;
    	LDX	VDU_DisplayPos
    	LDAA 	#18			; SET UPDATE ADDRESS IN VDU
    	JSR 	VDU_HL2WREG_A		;
    	LDAA 	#31 	           	; TOGGLE VDU FOR UPDATE
    	STAA 	SY6545S         	;
    	LDAA 	#14	            	; set cursor pos
    	JSR 	VDU_HL2WREG_A		;
    	PULS 	X			; RESTORE X
   	PULS 	D			; RESTORE D
    	RTS 
GOTO_XY_SCROLL:  
	JSR	DO_SCROLL  	
    	PULS 	X			; RESTORE X
   	PULS 	D			; RESTORE D
    	RTS 

;__VDU_PutChar______________________________________________________________________________________
;
; 	PLACE CHARACTER ON SCREEN
;	A: CHARACTER TO OUTPUT
;__________________________________________________________________________________________________			   	   	
VDU_PutChar:
    	JSR 	GOTO_XY	        	; 
    	STAA 	WRITR			; OUTPUT CHAR TO VDU
					;    	
    	LDAA	TERM_X			; PLACE X COORD IN A
    	INCA				; INC X COORD
    	STAA	TERM_X			; STORE IN A
    	CMPA	#80			; IS 80?
    	BNE	VDU_PutChar1		; NO, PLACE CHAR ON DISPLAY
    	CLR	TERM_X			; YES, WRAP TO NEXT LINE
    	LDAA	TERM_Y			; A= Y COORD
    	INCA				; INC Y COORD
    	STAA	TERM_Y			; STORE Y
VDU_PutChar1:    
    	JMP 	GOTO_XY	        	; 

    	

    	
	

;__PR_OUTCHAR______________________________________________________________________________________
;
; 	PR_OUTCHAR- OUTPUT CHAR TO PRINTER PORT
;	A: CHAR TO OUTPUT
;__________________________________________________________________________________________________			   	   	
PR_OUTCHAR:
	PSHS	A			; STORE A
PR_OUTCHAR_LOOP:
	LDAA	PPIB			; GET STATUS INFO	
	ANDA	#%10000000		; ONLY INTERESTED IN BUSY FLAG
	BNE	PR_OUTCHAR_LOOP		; LOOP IF BUSY
	PULS	A			; RESTORE AF
	STAA	PPIA			; OUTPUT DATA TO PORT
	LDAA 	#01			; .01 second delay 
	JSR 	KB_delay		; ignore anything back after a reset
	JSR	KB_portcbit0Low		; STROBE
	LDAA 	#01			; .01 second delay 
	JSR 	KB_delay		; ignore anything back after a reset
	JSR	KB_portcbit0High	; STROBE
	RTS 

;__PR_INITIALIZE___________________________________________________________________________________
;
; 	initialise - SET UP PORT FOR PRINTING
;__________________________________________________________________________________________________			   	   	
PR_INITIALIZE:
	JSR	KB_portcbit0High	; STROBE
	JSR	KB_portcbit1High	; FORM FEED
	JSR	KB_portcbit2Low		; DEVICE SELECT
	JSR	KB_portcbit3Low		; DEVICE INIT
	LDAA 	#200			; 1 second delay 
	JSR 	KB_delay		; ignore anything back after a reset
	JSR	KB_portcbit3High	; DEVICE INIT
	RTS 
		

;__KB_INITIALIZE___________________________________________________________________________________
;
; 	initialise - clear some locations and send a reset to the keyboard
;__________________________________________________________________________________________________			   	   	
KB_INITIALIZE:
	JSR 	KB_SETPORTC		; sets port c so can input and output
	JSR 	KB_RESET		; reset to the keyboard
	LDAA 	#200			; 1 second delay as keyboard sends stuff back when reset
	JSR 	KB_delay		; ignore anything back after a reset
	CLRA				; EMPTY KB QUEUE
	STAA	KB_QUEUE_PTR		; 
	RTS 


;__KB_RESET________________________________________________________________________________________
;
; 	RESET THE KEYBOARD
;__________________________________________________________________________________________________			   	   	
KB_RESET:
	JSR 	KB_datahigh		;
	JSR 	KB_clockhigh		;
	LDAB 	#255			;
sf1:	DECB
	BNE 	sf1			;
	JSR 	KB_clocklow		; step 1
	LDAB 	#255			;
sf2:	DECB	
	BNE 	sf2			;
	JSR 	KB_datalow		; step 2
	JSR 	KB_clockhigh		; step 3
	JSR 	KB_waitclocklow		; step 4
	LDAB	#9			; 8 data bits + 1 parity bit low
sf3:	JSR 	KB_datahigh		; step 5
	JSR 	KB_waitclockhigh	; step 6
	JSR 	KB_waitclocklow		; step 7
	DECB
	BNE 	sf3			;
	JSR 	KB_datahigh		; step9
	JSR 	KB_waitclocklow		; step 10 could read the ack bit here if want to
	JSR 	KB_waitclockhigh	; step 11
	LDAB 	#255			;	
sf4:	DECB
	BNE 	sf4			; finish up delay
	RTS 

;__KB_SETPORTC_____________________________________________________________________________________
;
; 	SETUP PORT C OF 8255 FOR KEYBOARD
;__________________________________________________________________________________________________			   	   	
KB_SETPORTC:
	LDAA 	#%10000010		; a=out b=IN, c high=OUT, clow=out
	STAA 	PPICONT 		; PPI control port
	LDAA	#%00000000		; port A to zero as need this for comms to work
	STAA 	PPIA			; PPI port A
	JSR 	KB_datahigh		;
	JSR 	KB_clockhigh		;
	CLRA 				;
	STAA 	CAPSLOCK		; set capslock off to start
	STAA	CTRL			; control off
	STAA 	NUMLOCK			; numlock off
	RTS 
;_________________________________________________________________________________________________
;
; 	port C bit routines
;__________________________________________________________________________________________________			   	   	
KB_portcbit0High:			;
	LDAA 	#%01110001		; see the 8255 data sheet
	BRA	KB_SETBITS		;
KB_portcbit1High:			;
	LDAA 	#%01110011		; see the 8255 data sheet
	BRA	KB_SETBITS		;
KB_portcbit3High:			;
	LDAA 	#%01110111		; see the 8255 data sheet
	BRA	KB_SETBITS		;
KB_portcbit0Low:			;
	LDAA 	#%01110000		; see the 8255 data sheet
	BRA	KB_SETBITS		;
KB_portcbit2Low:			;
	LDAA 	#%01110100		; see the 8255 data sheet
	BRA	KB_SETBITS		;
KB_portcbit3Low:			;
	LDAA 	#%01110110		; see the 8255 data sheet
	BRA	KB_SETBITS		;
KB_datahigh:
	LDAA 	#%01111001		; see the 8255 data sheet
	BRA	KB_SETBITS		;
KB_datalow:				;
	LDAA 	#%01111000		; see the 8255 data sheet
	BRA	KB_SETBITS		;
KB_clockhigh:				;
	LDAA	#%01111011		; bit 5 high
	BRA	KB_SETBITS		;
KB_clocklow:				;				;
	LDAA 	#%01111010		;
KB_SETBITS:				;
	STAA 	PPICONT			;
	RTS 				;



;__KB_waitclocklow_________________________________________________________________________________
;
; waitclocklow samples data bit 0, and waits till
; it goes low, then returns
; also times out after 0.001 seconds
; uses a, changes b
;__________________________________________________________________________________________________			   	   	
KB_waitclocklow:
	PSHS	D
	LDAB 	#255		; for timeout counter
W11L:	LDAA 	PPIB		; get a byte from port b
	ANDA  	#%00000010	; test the clock bit
	BEQ	KB_waitclocklow_EXIT 
	DECB
	BNE	W11L
KB_waitclocklow_EXIT:
	PULS	D,PC	


	
;__KB_waitclockhigh_________________________________________________________________________________
;
; waitclockhigh samples data bit 0, and waits till
; it goes high, then returns
; also times out after 0.001 seconds
; uses a, changes b
;__________________________________________________________________________________________________			   	   	
KB_waitclockHIGH:
	PSHS	D
	LDAB 	#255		; for timeout counter
W11H:	LDAA 	PPIB		; get a byte from port b
	ANDA  	#%00000010	; test the clock bit
	BNE	KB_waitclockHIGH_EXIT 
	DECB
	BNE	W11H
KB_waitclockHIGH_EXIT:
	PULS	D,PC	


;__KB_delay________________________________________________________________________________________
;
; pass A - delay is B*0.005 seconds, BCDEHL all preserved
;__________________________________________________________________________________________________			   	   	
KB_delay:	
	PSHS 	X		;
LOOP1:	LDX 	#740		; adjust this value for your clock 1481=3.68Mhz, 3219=8Mhz (test with A=1000=10 secs)
LOOP2:	DEX			; hl-1
	BNE 	LOOP2		;
	DECA			;
	BNE 	LOOP1		;
	PULS	X,PC		; restore variables & return


;__KB_PROCESS______________________________________________________________________________________
;
;  a=0 if want to know if a byte is available, and a=1 to ask for the byte
;__________________________________________________________________________________________________			   	   	
KB_PROCESS:	
*	JSR	skip		; don't test every one as takes time
*	CMPA	#$00		; is it zero
*	BNE	KB_PROCESS_EXIT	;
 	JSR	KB_waitbyte	; test keyboard. times out after a bit
	JSR 	KB_decodechar	; returns char or 0 for things like keyup, some return directly to cp/m
KB_PROCESS_EXIT:	
	RTS 			; Return to cp/m

	
;-----------------------------------------------
; cpm JSRs the keyboard quite frequently. If a keyboard was like a uart which can be checked
; with one instruction, that would be fine. But checking a keyboard involves putting the clock line low
; then waiting some time for a possible reply, then reading in bits with timeouts and then returning
; this slows down a lot of cp/m processes, eg try TYPE MYPROG and printing out text
skip:
	DEC	skipcount	; subtract 1
	LDAA	skipcount	;
	CMPA	#$00		;
	BNE	sk1		; wordstar is very slow even tried a value of 5 to 200 here
	LDAA	#200		; only act on every n JSRs - bigger=better because this sub is quicker than readbits
	STAA	skipcount	; reset counter
	LDAA 	#00		; flag to say reset counter
sk1:				;
	RTS 

	
;__KB_decodechar____________________________________________________________________________________
;
; decode character pass a and prints out the char
; on the LCD screen
;__________________________________________________________________________________________________			   	   	
KB_decodechar:
	CMPA	#0		; is it zero
	BNE	KB_decodechar_1	;
	RTS 			; return if a zero - no need to do anything
KB_decodechar_1:	
	CMPA	#$F0		; is a key up (need to do special code for shift)
	BEQ 	deckeyup	; ignore char up
	CMPA	#$E0		; two byte keypresses
	BNE 	NOtwobyte	
	JMP	twobyte		;
NOtwobyte:
	CMPA	#$58		; caps lock so toggle
	BNE 	NOcapstog	;
	JMP	capstog	
NOcapstog:	
	CMPA	#$12		; shift (down, because up would be trapped by 0F above)
	BNE 	NOshiftdown	;
	JMP	shiftdown
NOshiftdown:	
	CMPA	#$59		; other shift key
	BNE 	NOshiftdown1	;
	JMP	shiftdown
NOshiftdown1:	
	CMPA	#$14		; control key
	BNE 	NOcontroldown	;
	JMP	controldown
NOcontroldown:
	CMPA	#$5A		; enter key
	BEQ	return		;
	CMPA	#$66		; backspace key
	BEQ	backspace	;
	CMPA	#$0d		; tab key
	BEQ 	tabkey		;
	CMPA	#$76		; escape key
	BEQ	escape		;
	LDX 	#normalkeys	; offset to add
testcontrol:
	LDAB 	ctrl		;
	CMPB	#$FF		;
	BNE	dc1		; no so go back to test caps lock on
	LDAB	A,X		; get the letter, should be smalls 
	SBCB	#96		; a=97 so subtract 96 a=1=^A
	SWI
	FCB	109
	TBA
	JMP	KB_ENQUEUE	; STORE ON KB QUEUE
dc1:	LDAB 	capslock	;
	CMPB	#$FF		;
	BNE 	dc2		;
	LDX 	#normalkeys+$80	; add another 80h to smalls to get caps
dc2:	LDAB 	A,X		;
	SWI
	FCB	109
	TBA
	JMP	KB_ENQUEUE	; STORE ON KB QUEUE 		
				;	
tabkey:				;
	LDAA 	#9		;
	JMP	KB_ENQUEUE	; STORE ON KB QUEUE
backspace:			;
	LDAA	#8		; backspace
	JMP	KB_ENQUEUE	; STORE ON KB QUEUE
escape:				;
	LDAA	#27		;
	JMP	KB_ENQUEUE	; STORE ON KB QUEUE
return:				;
	LDAA	#13		; carriage return
	JMP	KB_ENQUEUE	; STORE ON KB QUEUE
deckeyup:
	JSR 	KB_waitbyte	; ignore key up throw away the character unless a shift 
	CMPA	#$12		; is it a shift
	BNE 	NOshiftup	;
	JMP	shiftup
NOshiftup:
	CMPA	#$59		; other shift key
	BNE	NOshiftup1	;
	JMP	shiftup
NOshiftup1:	
	CMPA	#$14		; control up
	BNE 	NOcontrolup	; control up
	JMP	controlup
NOcontrolup:	
	LDAA	#$00		; nothing captured so send back a zero 
	RTS 
twobyte:; already got EO so get the next character
	JSR 	KB_waitbyte
	CMPA	#$F0		; see the notes - keyup for E0 keys is Eo F0 nn not F0 Eo!!
	BEQ	twobyteup	;
	CMPA	#$71		; delete
	BNE	NOdeletekey	;
	JMP	deletekey	
NOdeletekey:
	CMPA	#$5a		; return on number pad
	BNE	NOreturnkey	;
	JMP	returnkey
NOreturnkey:	
	CMPA	#$72		;
	BEQ	downarrow	;
	CMPA	#$74		;
	BEQ	rightarrow	;
	CMPA	#$6b		;
	BEQ	leftarrow	;
	CMPA	#$75		;
	BEQ	uparrow		;
	CMPA	#$70		;
	BEQ	insert		;
	CMPA	#$7d		;
	BEQ	pageup		;
	CMPA	#$7a		;
	BEQ	pagedown	;
	CMPA	#$6c		;
	BEQ	home		;
	CMPA	#$69		;
	BEQ	end		;
	CLRA 			; returns nothing
	RTS 
twobyteup:			;expect a byte and ignore it
	JSR	KB_waitbyte	;
	CLRA			;
	RTS 			;
home:				;
	LDAA	#$1B		; ESC
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	LDAA	#'?'		; ?
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	LDAA	#'w'		; w
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	RTS 			;
end:				;
	LDAA	#$1B		; ESC
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	LDAA	#'?'		; ?
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	LDAA	#'q'		; q
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	RTS 			;
downarrow:			;
	LDAA	#$1B		; ESC
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	LDAA	#'B'		; B
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	RTS 			;
rightarrow:			;
	LDAA	#$1B		; ESC
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	LDAA	#'C'		; C
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	RTS 			;
leftarrow:			;
	LDAA	#$1B		; ESC
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	LDAA	#'D'		; D
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	RTS 			;
uparrow:			;
	LDAA	#$1B		; ESC
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	LDAA	#'A'		; A
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	RTS 			;	
insert:				;
	LDAA	#$1B		; ESC
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	LDAA	#'?'		; ?
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	LDAA	#'p'		; p
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	RTS 			;
pageup:				;
	LDAA	#$1B		; ESC
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	LDAA	#'?'		; ?
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	LDAA	#'y'		; y
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	RTS 			;
pagedown:			;
	LDAA	#$1B		; ESC
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	LDAA	#'?'		; ?
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	LDAA	#'s'		; s
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	RTS 			;
controldown:			; same code as shiftdown but diff location
	LDAA	#$FF		;
	STAA	ctrl		; control down
	CLRA			;
	RTS 			;
controlup:			; control key up see shift for explanation
	CLRA			;
	STAA 	ctrl		;
	CLRA			;
	RTS 			;
returnkey:			;
	LDAA 	#13		;
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	RTS 			;
deletekey:			;
	LDAA	#$7F		; delete key value that cp/m uses
	JSR	KB_ENQUEUE	; STORE ON KB QUEUE
	RTS 			;
capstog:			;
  	LDAA 	capslock	;
	EORA 	#%11111111	; swap all the bits
	STAA 	capslock	;
	CLRA			; returns nothing
	RTS 			;
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
	LDAA 	#$FF		;
	STAA 	capslock	;
	CLRA			; returns nothing
	RTS 			;
shiftup:			; shiftup turns off caps lock definitely
	CLRA			;
	STAA 	capslock	;
	CLRA			; returns nothing
	RTS 			;

;__KB_ENQUEUE______________________________________________________________________________________
;
;  STORE A BYTE IN THE KEYBOARD QUEUE 
;  A: BYTE TO ENQUEUE
;__________________________________________________________________________________________________			   	   		
KB_ENQUEUE:
	PSHS	D,X		; STORE 
	LDAB	KB_QUEUE_PTR	; PUT QUEUE POINTER IN A
	CMPB	#15		; IS QUEUE FULL
	BGE	KB_ENQUEUE_AB	; YES, ABORT	
	LDX	#KB_QUEUE	; GET QUEUE POINTER
	STAA	B,X		; ENQUEUE VALUE
	INC	KB_QUEUE_PTR	; INC IT
KB_ENQUEUE_AB:
	PULS	D,X,PC		; RESTORE
	
	
;__KB_waitbyte_____________________________________________________________________________________
;
; wait for a byte - tests a number of times if there is a keyboard input,
; overwrites all registers, returns byte in a
;__________________________________________________________________________________________________			   	   		
KB_waitbyte:	
	JSR	KB_clockhigh	; turn on keyboard
	LDX 	#500		; number of times to check 200=slow TYPE , 10=error, 25 ?error 50 ok - this delay has to be there otherwise weird keyup errors
wb1:	PSHS 	X		; store counter
	JSR 	KB_readbits	; test for a low on the clock line
	PULS 	X		; get the counter back
	CMPA	#$00		; test for a zero back from readbits
	BNE	wb2		; if not a zero then must have a byte ie a keyboard press
	DEX			; subtract 1
	BNE	wb1		; loop waiting for a response
wb2:	PSHS 	A		; store the value in a
	JSR 	KB_clocklow	; turn off keyboard
	PULS 	A		; get back byte as clocklow erased it
	RTS 

;__KB_readbits_____________________________________________________________________________________
;
; readbits reads 11 bits in from the keyboard
; first bit is a start bit then 8 bits for the byte
; then a parity bit and a stop bit
; returns after one machine cycle if not low
; uses a, b,d, e 
; returns a=0 if no data, a= scancode (or part thereof)
;__________________________________________________________________________________________________			   	   		
KB_readbits:
	LDAA 	ppib
	ANDA 	#%00000010	; test the clock bit
	BEQ 	r0		; if low then start the capture
	LDAA 	#$00		; returns a=0 if nothing
	RTS 			;
R0:	PSHS	A	
r1:	LDAA 	PPIB		; get a byte from port b
	ANDA  	#%00000010	; test the clock bit
	BEQ	R1
	LDX 	#$0008		; sample 8 times
	LDAA 	#$00		; start with e=0
r2:	LDAA 	PPIB		; get a byte from port b
	ANDA  	#%00000010	; test the clock bit
	BNE	R2
	LDAB 	ppib		; sample the data line
	PULS	A
	RORB			; move the data bit into the carry register
	RORA			; move the carry bit into bit 7 and shift right
	PSHS	A
R3:	LDAA 	PPIB		; get a byte from port b
	ANDA  	#%00000010	; test the clock bit
	BEQ	R3
	DEX			; restore for loop
	BNE 	r2		; do this 8 times
R4:	LDAA 	PPIB		; get a byte from port b
	ANDA  	#%00000010	; test the clock bit
	BNE	R4
R5:	LDAA 	PPIB		; get a byte from port b
	ANDA  	#%00000010	; test the clock bit
	BEQ	R5
R6:	LDAA 	PPIB		; get a byte from port b
	ANDA  	#%00000010	; test the clock bit
	BNE	R6
R7:	LDAA 	PPIB		; get a byte from port b
	ANDA  	#%00000010	; test the clock bit
	BEQ	R7
	PULS	A
	RTS 
	
	
normalkeys: ; The TI character codes, offset from label by keyboard scan code
		FCB 000,000,000,000,000,000,000,000,000,000
		FCB 000,000,000,009,"`",000,000,000,000,000	; 0D = tabkey=9
		FCB 000,"q","1",000,000,000,"z","s","a","w"
		FCB "2",000,000,"c","x","d","e","4","3",000
		FCB 000," ","v","f","t","r","5",000,000,"n"
		FCB "b","h","g","y","6",000,000,000,"m","j"
		FCB "u","7","8",000,000,",","k","i","o","0"
		FCB "9",000,000,".","/","l",";","p","-",000
		FCB 000,000,039,000,"[","=",000,000,000,000	; 39 is '
		FCB 000,"]",000,092,000,000,000,000,000,000	; 92 is \
		FCB 000,000,000,000,000,"1",000,"4","7",000
		FCB 000,000,"0",".","2","5","6","8",000,000
		FCB 000,"+","3","-","*","9",000,000		; pad to 80h bytes
		FCB 000,000,000,000,000,000,000,000,000,000
		FCB 000,000,000,009,"~",000,000,000,000,000	; 0D = tabkey=9
		FCB 000,"Q","!",000,000,000,"Z","S","A","W"
		FCB "@",000,000,"C","X","D","E","$","#",000
		FCB 000," ","V","F","T","R","%",000,000,"N"
		FCB "B","H","G","Y","^",000,000,000,"M","J"
		FCB "U","&","*",000,000,"<","K","I","O",")"
		FCB "(",000,000,">","?","L",":","P","_",000
		FCB 000,000,034,000,"{","+",000,000,000,000	; 34 is "
		FCB 000,"}",000,"|",000,000,000,000,000,000	; 92 is \
		FCB 000,000,000,000,000,"1",000,"4","7",000
		FCB 000,000,"0",".","2","5","6","8",000,000
		FCB 000,"+","3","-","*","9",000,000		; pad to 80h bytes



;__________________________________________________________________________________________________
;
; 	RAM STORAGE AREAS
;__________________________________________________________________________________________________			
TEMPW		FCW	0		;
ALT_KEYPAD	FCB	0		; ALT KEYPAD ENABLED?	
GR_MODE		FCB	0		; GRAPHICS MODE ENABLED?
TERM_X:		FCB	0		; CURSOR X
TERM_Y:		FCB	0		; CURSOR Y
TERMSTATE:	FCB	0		; TERMINAL STATE
					; 0 = NORMAL
					; 1 = ESC RCVD
VDU_DisplayPos:	FCW  	0		; CURRENT DISPLAY POSITION
VDU_DISPLAY_START:
		FCW  	0		; CURRENT DISPLAY POSITION
capslock	FCB  	0		; location for caps lock, either 00000000 or 11111111
ctrl		FCB  	0		; location for ctrl on or off 00000000 or 11111111
numlock		FCB  	0		; location for num lock
skipcount	FCB	0		; only check some JSRs, speeds up a lot of cp/m

KB_QUEUE	FCB	0,0,0,0,0,0,0,0 ; 16 BYTE KB QUEUE
		FCB	0,0,0,0,0,0,0,0
KB_QUEUE_PTR	FCB	0		; POINTER TO QUEUE			

	end
