;======================================================================
;	EF9345 DRIVER FOR ROMWBW
;
;	PARTS WRITTEN BY: ALAN COX
;	REVISED/ENHANCED BY LASZLO SZOLNOKI -- 01/2024
;======================================================================
; TODO:
;	- 40X24 IMPLEMENTATION
;======================================================================
; EF9345 DRIVER - CONSTANTS
;======================================================================
;
TERMENABLE	.SET	TRUE      	; INCLUDE TERMINAL PSEUDODEVICE DRIVER
;
EF_BASE		.EQU	$F0
EF_SETREG	.EQU	EF_BASE + 4
EF_DATAACC	.EQU	EF_BASE + 5
EF_RESET	.EQU	EF_BASE + 6
;
EF_SIZE		.EQU	V80X24
;
EF_R0		.EQU	$20
EF_R1		.EQU	EF_R0+1
EF_R2		.EQU	EF_R0+2
EF_R3		.EQU	EF_R0+3
EF_R4		.EQU	EF_R0+4
EF_R5		.EQU	EF_R0+5
EF_R6		.EQU	EF_R0+6
EF_R7		.EQU	EF_R0+7
;
EF_XA		.EQU	EF_R5
EF_YA		.EQU	EF_R4
EF_XP		.EQU	EF_R7
EF_YP		.EQU	EF_R6
;
EF_EXEC		.EQU	00001000b
;
EF_TGSREG	.EQU 	1
EF_MATREG	.EQU	2
EF_PATREG	.EQU	3
EF_DORREG	.EQU	4
EF_RORREG	.EQU	7
;EF_WRTINDIR	.EQU 10000000b
;
; CMD
;
EF_NOP		.EQU	$91		;
EF_IND		.EQU	$80		;
EF_CLF		.EQU	$05		;
EF_OCT		.EQU	$30		;
EF_OCTAUX	.EQU	$04		; AUXILIARY POITER
EF_KRF		.EQU	$00		; NO AUTOINCREMENT
EF_KRL		.EQU	$50		; NO AUTOINCREMENT
EF_INY		.EQU	$B0		; INC Y
;
;EF_IND_TGS	.EQU	$81
;EF_IND_MAT	.EQU	$82
;EF_IND_PAT	.EQU	$83
;EF_IND_DOR	.EQU	$84
;EF_IND_ROR	.EQU	$87
EF_RREG		.EQU	00001000b
;EF_WREG	.EQU    ~EF_RREG
;
; | 1 | 0 | 0| 0| R/!W | r | r | r |   IND command
;                        0   0   1     TGS
;                        0   1   0     MAT
;                        0   1   1     PAT
;                        1   0   0     DOR
;                        1   0   1
;                        1   1   0
;                        1   1   1     ROR
;						MAT5	MAT4
; fixed complemented	  0		  0
; flash complemented	  1		  0
; fixed underlined		  0		  1
; flash underlined		  1		  1
;
EF_NOCU		.EQU	10111111B	; MAT6 = 0 : NO CURSOR
EF_BLK		.EQU	00100000B	; MAT5 = 1 : BLINK CURSOR
EF_NOBL		.EQU	11011111B	; MAT5 = 0 : NO BLINK
;
EF_BLOK		.EQU	11101111b	; MAT4 = 0 : BLOCK CURSOR
EF_ULIN		.EQU	00010000b	; MAT4 = 1 : UNDERLINE CURSOR
;
EF_CURENA	.EQU	TRUE		; ENABLE CURSOR
;
EF_MARCOL	.EQU	00000000B	; MARGIN COLOR BLACK : MAT0 = R, MAT1 = G, MAT2 = B
EF_MARENA	.EQU	00001000B	; MARGIN INSERT : MAT3 = 1
;
EF_CUREN	.EQU	01000000B	; MAT6 = 1 : CURSOR ENABLED
EF_DISCU	.EQU	10111111B	; MAT6 = 0 : NO CURSOR
;
EF_BLINK	.EQU	00100000B	; MAT5 = 1 : BLINK CURSOR
EF_NOBLINK	.EQU	11011111B	; MAT5 = 0 : NO BLINK
;
EF_COMPL	.EQU	11101111b	; MAT4 = 0 : BLOCK CURSOR
;
EF_FLASHCHAR	.EQU    00001000B
EF_REVERSCHAR	.EQU    10000000B
;
#IF EF_CURENA
EF_CSTY 	.EQU	EF_CUREN | EF_BLINK | EF_ULIN | EF_MARENA | EF_MARCOL
#ELSE
EF_CSTY 	.EQU	EF_MARENA | EF_MARCOL
#ENDIF
;
FIRSTLINE	.EQU	8
;
#IF (EF_SIZE=V80X24)			; V80X24
EF_DLINES	.EQU	24
EF_DROWS	.EQU	80
EF_DSCANL	.EQU	10
; ATTRIBUTES
EF_FLASH	.EQU	01000100B
EF_NEGATIVE	.EQU	10001000B
EF_UNDERLINE	.EQU	00100010B
EF_COLORSET	.EQU	00010001B
#ENDIF
;
#IF (EF_SIZE=V40X24)
EF_DLINES	.EQU	24
EF_DROWS	.EQU	40
EF_DSCANL	.EQU	10
; ATTRIBUTES
EF_FLASH	.EQU	01000100B
EF_NEGATIVE	.EQU	10001000B
EF_UNDERLINE	.EQU	00100010B
EF_COLORSET	.EQU	00010001B
#ENDIF
;
; DISTRICTS
;
EF_DIST0 	.EQU 	0
EF_DIST1 	.EQU 	$20
EF_DIST2 	.EQU 	$80
EF_DIST3 	.EQU 	$A0
;
EF_BG_BLACK	.EQU	$0
EF_BG_RED	.EQU	$10
EF_BG_GREEN	.EQU	$20
EF_BG_BROWN	.EQU	$30
EF_BG_BLUE	.EQU	$40
EF_BG_MAGENTA	.EQU	$50
EF_BG_CYAN	.EQU	$60
EF_BG_WHITE	.EQU	$70
EF_FG_BLACK	.EQU	0
EF_FG_RED	.EQU	1
EF_FG_GREEN	.EQU	2
EF_FG_BROWN	.EQU	3
EF_FG_BLUE	.EQU	4
EF_FG_MAGENTA	.EQU	5
EF_FG_CYAN	.EQU	6
EF_FG_WHITE	.EQU	7
;
EF_SCREENSIZE	.EQU	EF_DROWS * EF_DLINES
;
	DEVECHO	"EF: IO="
	DEVECHO	EF_BASE
	DEVECHO	"\n"
;
;======================================================================
; VDU DRIVER - INITIALIZATION
;======================================================================
;
EF_INIT:
;
	LD IY,EF_IDAT			; POITER TO INSTANCE DATA
;
	CALL	NEWLINE			; FORMATTING
	PRTS("EF : IO=0x$")
	LD	A,EF_BASE
	CALL	PRTHEXBYTE

	PRTS(" MODE=$")			; OUTPUT DISPLAY FORMAT
	LD	A,EF_DROWS
	CALL	PRTDECB
	PRTS("X$")
	LD	A,EF_DLINES
	CALL	PRTDECB

	CALL	EF_PROBE		; CHECK FOR HW EXISTENCE
	JR	Z,EF_INIT1		; CONTINUE IF HW PRESENT
;
	PRTS(" NOT PRESENT$")
	XOR	A
	OR	-8			; HARDWARE NOT PRESENT
	RET
;
EF_INIT1:
	OUT (EF_RESET),A		; HARDWARE RESET
;
	LD	A,EF_DIST0
	LD	(EF_CON_BANKY),A		;
;
	CALL 	EF_CRTINIT		; INIT EF9345 CHIP
;
; ADD OURSELVES TO VDA DISPATCH TABLE
	LD	BC,EF_FNTBL		; BC := FUNCTION TABLE ADDRESS
 	LD	DE,EF_IDAT		; DE := VDU INSTANCE DATA PTR
	CALL	VDA_ADDENT		; ADD ENTRY, A := UNIT ASSIGNED
;
#IF TERMENABLE
	; INITIALIZE EMULATION
	LD	C,A			; ASSIGNED VIDEO UNIT IN C
	LD	DE,EF_FNTBL		; DE := FUNCTION TABLE ADDRESS
	LD	HL,EF_IDAT		; HL := VDU INSTANCE DATA PTR
	CALL	TERM_ATTACH		; DO IT
#ENDIF
;
	XOR	A			; SIGNAL SUCCESS
	RET
;
EF_CRTINIT:
	LD	DE,(EF_R0+EF_EXEC)*256 + EF_NOP	; FORCE NOP
	CALL	EF_WWRREG
;
	LD	HL,EF_INIT9345		; INITIAL SETUP PARAMETERS
	CALL	EF_LOAD_MODE
;
	LD	DE,0
	LD	(EF_VDA_OFFSET),DE
;
#IF (EF_SIZE = V40X24)
	XOR	A
	LD	(EF_VDATYPESET),A
#ENDIF
;
; E = CHARACTER ATTRIBUTES : E0 = BLINK, E1 = UNDELINE, E2 = REVERSE, E3  = COLOR SET
; VIDEO SET CHARACTER ATTRIBUTE FOR SCROLL, KRL, ETC.
	LD	E,00000000B
	CALL	EF_VDASAT
;
	LD	E,EF_BG_BLACK + EF_FG_WHITE	; SET CHARACTER COLOR
	CALL	EF_VDASCO
;
; VIDEO SET CURSOR STYLE
; ENTRY: C = VIDEO UNIT, D = START/END, E = STYLE : E0 = BLINK/FLASH, E1 = UNDELINE, E2 = REVERSE/COMPLEMENT
; MAT5 = 1 : FLASH, MAT4 = 0 : COMPLEMENT
; RETURN A = STATUS
	LD	E,3				; UNDERLINED BLINKING
	CALL	EF_VDASCS
;
	CALL	EF_CLEARALL
;
	LD	DE,0				; SET CURSOR TO 0,0
	CALL	EF_VDASCP
	RET
;
EF_CLEARALL:
	LD	DE,0				; SET CURSOR 0,0
	CALL	EF_VDASCP			; D = ROW, E = COLUMNS
	LD	HL,EF_DROWS * EF_DLINES
;
	LD	E,' '
	CALL	EF_VDAFIL
	XOR	A
	RET
;
; R1 := C BYTE IS THE CHARACTER CODE
; R2 := B BYTE TYPE AND SET, OTHER PARAMETERS
; R3 := A BYTE ATTRIBUTES, NEGATIVE, FG COLOR, FLASH, BG COLOR
;
#IF (EF_SIZE=V80X24)
EF_KRL80:
	PUSH	DE
	LD	DE,EF_R0*256 + EF_KRL	; R0 KRL COMMAND
	CALL	EF_WWRREG
	LD	D,EF_R3
	LD	A,(EF_VDAATTR)		; DOUBLE ATTRIBUTES FOR LOWER NIBBLE
	LD	E,A
	CALL	EF_WWRREG
	POP	DE
	RET
#ENDIF
;
#IF (EF_SIZE = V40X24)
EF_KRF40:
	PUSH	DE
	LD	DE,EF_R0*256 + KRF
	CALL	EF_WWRREG
	LD	D,R3
	LD	A,(EF_VDACOLOR)
	LD	B,A
	LD	A,(EF_VDAATTR)
	OR	B
	LD	E,A				; COLOR
	CALL	EF_WRREG
	LD	D,EF_R2
	LD	A,(EF_VDATYPESET)
	LD	E,A
	CALL	EF_WRREG
	POP	DE
	XOR	A
	RET
#ENDIF
;
;----------------------------------------------------------------------
; PROBE FOR EF9345 HARDWARE
;----------------------------------------------------------------------
;
; ON RETURN, ZF SET INDICATES HARDWARE FOUND
;
EF_PROBE:
	LD	DE,EF_R1*256+'a'
	LD	H,E
	CALL	EF_WRREG
	CALL	EF_RDREG
	CP	H
	RET
;
;----------------------------------------------------------------------
; WAIT FOR VDU TO BE READY FOR A DATA READ/WRITE
;----------------------------------------------------------------------
;
EF_WAITRDY:
	LD	A,EF_R0
	OUT	(EF_SETREG),A
	IN	A,(EF_DATAACC)
	RLA
	JR	C,EF_WAITRDY
	RET
;
;----------------------------------------------------------------------
; UPDATE EF9345 REGISTERS
;   EF_WRREG WRITES VALUE IN E TO EF9345 REGISTER SPECIFIED IN D
;	EF_WWRREG AFTER WAITING FOR READY WRITES VALUE IN E TO EF9345 REGISTER SPECIFIED IN D
;-------------------------------------------------------------------	--
;
EF_WWRREG:
	CALL	EF_WAITRDY
EF_WRREG:
	LD	A,D
	OUT	(EF_SETREG),A
	LD	A,E
	OUT	(EF_DATAACC),A
	RET
;
;----------------------------------------------------------------------
; READ EF9345 REGISTERS
;   EF_RDREG READS EF9345 REGISTER SPECIFIED IN D AND RETURNS VALUE IN A AND E
;----------------------------------------------------------------------
EF_RDREG:
	CALL	EF_WAITRDY
	LD	A,D
	OUT	(EF_SETREG),A
	IN	A,(EF_DATAACC)
	LD	E,A
	RET
;
;----------------------------------------------------------------------
; READ INDIRECT EF9345 REGISTERS
;   EF_READ_INDIR READS EF9345 REGISTER SPECIFIED IN D AND RETURNS VALUE IN A AND E
;----------------------------------------------------------------------
;
EF_READ_INDIR:
	LD	A,EF_IND
	OR	D
	OR	EF_RREG
	LD	E,A
	LD	D,EF_R0 + EF_EXEC
	CALL	EF_WWRREG
	LD	D,EF_R1
	CALL	EF_RDREG
	RET
;
;----------------------------------------------------------------------
; WRITES INDIRECT EF9345 REGISTERS
;   EF_LOAD_INDIR WRITES VALUE IN E TO INDIRECT EF9345 REGISTER SPECIFIED IN D
;----------------------------------------------------------------------
;
EF_LOAD_INDIR:				; D = TARGET REGISTER, E = VALUE TO WRITE
	PUSH	DE
	LD	D,EF_R1
	CALL	EF_WWRREG
	POP	DE
	PUSH	DE
	LD	A,EF_IND
	OR	D
	LD	E,A
	LD	D,EF_R0 + EF_EXEC
	CALL	EF_WWRREG
	POP	DE
	RET
;
EF_LOAD_MODE:				; LOAD MODE
	LD	D,EF_TGSREG			; START INDIRECT REGISTER 1 : TGS
	LD	B,EF_INIT_CNT		; LOAD 5 INDIRECT REGISTERS
EF_MODEREG:
	LD	E,(HL)
	CALL	EF_LOAD_INDIR
	INC	HL
	INC	D
	LD	A,EF_INIT_CNT
	CP	D
	JR	NZ,EF_NOSKIP
	INC	D
	INC	D
	LD	E,(HL)
	LD	A,(EF_CON_BANKY)
	ADD	A,E
	LD	E,A
	CALL	EF_LOAD_INDIR
	RET
EF_NOSKIP:
	DJNZ	EF_MODEREG
	RET
;
EF_GETXY:				; D = ROW, E = COLUMNS
	CALL	EF_GETX
	CALL	EF_GETY
	RET
;
EF_GETX:				; E = COLUMNS
	CALL	EF_WAITRDY
	LD	D,EF_XP
	CALL	EF_RDREG
#IF (EF_SIZE=V80X24)
	RLCA				; CORRECTION 80 ROWS MODE
#ENDIF
	LD	E,A
	RET
;
EF_GETY:				; D = ROW
	CALL	EF_WAITRDY
	PUSH	DE
	LD	D,EF_YP
	CALL	EF_RDREG
	AND	00011111B
	PUSH	HL
	LD	HL,(EF_VDA_OFFSET)
	SUB	H
	POP	HL
	SUB	FIRSTLINE
	POP	DE
	LD	D,A
	RET
;
EF_LOADFONTS:
	PRTS("Not implemented$")
	CALL	NEWLINE
	SYSCHKERR(ERR_NOTIMPL)		; NOT IMPLEMENTED (YET)
	LD	A,-2
	OR	A
	RET
;
EF_NOTIMP:
	PRTS("Not implemented$")
	CALL	NEWLINE
	SYSCHKERR(ERR_NOTIMPL)		; NOT IMPLEMENTED (YET)
	XOR	A
	OR	-2			; FUNCTION NOT IMPLEMENTED
	RET
;
EF_CURSORON:				; CURSOR DISPLAY ENABLE
	PUSH	DE
	PUSH	AF
	LD	D,EF_MATREG		; LOAD CURSOR ENABLE
	CALL	EF_READ_INDIR
	OR	01000000B
	LD	D,EF_MATREG		; SET CURPOS ENABLE
	LD	E,A
	CALL	EF_LOAD_INDIR
	POP	AF
	POP	DE
	RET
;
EF_CURSOROFF:
	PUSH	DE
	PUSH	AF
	LD	D,EF_MATREG		; LOAD CURSOR ENABLE
	CALL	EF_READ_INDIR
	AND	10111111B
	LD	D,EF_MATREG		; SET CURSOR ENABLE
	LD	E,A
	CALL	EF_LOAD_INDIR
	POP	AF
	POP	DE
	RET
;
EF_INCCURSOR:				; CURSOR POSITION, D = ROW, E = COLUMN
; Y , X WITH	MODULO DROWS
	PUSH	DE
	PUSH	HL
	LD	HL,(EF_VDA_OFFSET)
	LD	DE,(EF_VDA_POS)
	ADD	HL,DE
	INC	DE
	LD	A,EF_DROWS
	CP	E
	JR	NZ,EF_CURS0
	LD	E,0
	INC	D
	LD	A,EF_DLINES
	CP	D
	JR	NZ,EF_CURS0
;	LD	D,0
	DEC	D			; Y REMAINS INSIDE THE BOUNDARY
	LD	(EF_VDA_POS),DE
	CALL	EF_VDASCP
	POP	HL
	POP	DE
	OR	-6			; PARAMETER OUT OF RANGE
	RET
EF_CURS0:
	LD	(EF_VDA_POS),DE
	CALL	EF_VDASCP
	POP	HL
	POP	DE
	RET
;
;----------------------------------------------------------------------
;  DISPLAY CONTROLLER CHIP INITIALIZATION
;----------------------------------------------------------------------
;
EF_INIT9345:
#IF (EF_SIZE=V80X24)		; E)
EF_TGS:	.DB 11000010b		; 80 char/row, long char code (12 bits) : TGS Register interlaced
EF_MAT:	.DB EF_CSTY		; 01001000b		; cursor enabled, fixed complent cursor, margin color = black : MAT Register
EF_PAT:	.DB 01111110b		; 80 char/row, long code, upper/lower bulk on, conceal on,
				; I high during active disp. area, status row disebled : PAT Register
EF_DOR:	.DB 10001111b		; DOR(3:0) = 1111   : color c0 = white, DOR(7:4) = 1000 : color c1 = black
EF_ROR:	.DB 00001000b		; ROR(7:5) =   000  : displayed page memory starts from block 0
				; ROR(4:0) = 01000 : origin row = 8
#ENDIF
;
#IF (EF_SIZE=V40X24)
EF_TGS:	.DB 00000000B		; 40 char/row, long char code (24 bits) : TGS Register interlaced
EF_MAT:	.DB EF_CSTY		; 01001100B cursor enabled, fixed complent cursor, margin color = black : MAT Register
EF_PAT:	.DB 01111110B		; 40 char/row, long code, upper/lower bulk on, conceal on,
				; I high during active disp. area, status row disebled : PAT Register
; DOR register initialization
;
; DOR(3:0) = 0011 : alpha UDS slices in block 3
; DOR(6:4) = 001 : semigraphic uds slices in block 2 and 3
; DOR 7 = 0 : Quadrichrome slices from block 0
EF_DOR:	.DB 0		;
EF_ROR:	.DB 00001000B		; ROR(7:5) =   000  : displayed page memory starts from block 0
				; ROR(4:0) = 01000 : origin row = 8
#ENDIF

EF_INIT_CNT:	.EQU	$ - EF_INIT9345
;
;======================================================================
; EF9345 DRIVER - VIDEO DISPLAY ADAPTER FUNCTIONS
;======================================================================
;
EF_FNTBL:
	.DW	EF_VDAINI
	.DW	EF_VDAQRY
	.DW	EF_VDARES
	.DW	EF_VDADEV
	.DW	EF_VDASCS
	.DW	EF_VDASCP
	.DW	EF_VDASAT
	.DW	EF_VDASCO
	.DW	EF_VDAWRC
	.DW	EF_VDAFIL
	.DW	EF_VDACPY
	.DW	EF_VDASCR
	.DW	EF_NOTIMP		; PPK_STAT
	.DW	EF_NOTIMP		; PPK_FLUSH
	.DW	EF_NOTIMP		; PPK_READ
	.DW	EF_VDARDC
#IF (($ - EF_FNTBL) != (VDA_FNCNT * 2))
	.ECHO	"*** INVALID VDU FUNCTION TABLE ***\n"
#ENDIF
;
EF_VDAINI:
; VIDEO INITIALIZE
; FULL REINITIALIZATION, CLEAR SCREEN, CURRENTLY IGNORES VIDEO MODE AND BITMAP DATA
	PUSH	HL
	CALL	EF_INIT1
	POP	HL
	LD	A,L
	OR	H
	CALL	NZ,EF_LOADFONTS

	CALL	EF_CLEARALL
	CALL	EF_LOADCSTYLE
	LD	DE,0
	LD	(EF_VDA_OFFSET),DE
	CALL	EF_VDASCP

	XOR	A
	RET
;
EF_VDAQRY:
; VIDEO QUERY
; ENTRY: C = VIDEO UNIT, HL = FONT BITMAT
; RETURN: C = VIDEO MODE, D = ROWS, E = COLUMNS, HL = FONT BITMAT
	LD	C,$00			; MODE ZERO IS ALL WE KNOW
	LD	D,EF_DLINES
	LD	E,EF_DROWS
	LD	HL,0			; EXTRACTION OF CURRENT BITMAP DATA NOT SUPPORTED
	XOR	A			; SIGNAL SUCCESS
	RET
;
EF_VDARES:
; VIDEO RESET
; SOFT RESET
;
	XOR	A
	RET
;
EF_VDADEV:
; VIDEO DEVICE
; ENTRY: C = VIDEO UNIT
; RETURN: D := DEVICE TYPE, E := DEVICE NUMBER, H := DEVICE UNIT MODE, L := DEVICE I/O BASE ADDRESS
	LD	DE,(VDADEV_EF * 256) + 0	; D := DEVICE TYPE
						; E := PHYSICAL UNIT IS ALWAYS ZERO
	LD	HL,EF_BASE			; H INDICATES THE VARIANT OF THE CHIP OR CIRCUIT, H = 0 : NO VARIANTS
						; L := BASE I/O ADDRESS
	XOR	A				; SIGNAL SUCCESS
	RET
;
EF_VDASCS:
; VIDEO SET CURSOR STYLE
; ENTRY: C = VIDEO UNIT, D = START/END, E = STYLE : E0 = BLINK/FLASH, E1 = UNDELINE, E2 = REVERSE/COMPLEMENT
; MAT5 = 1 : FLASH, MAT4 = 0 : COMPLEMENT
; RETURN A = STATUS
	XOR	A
	SRA	E
	JR	NC,EF_VDASCS0
	OR	EF_BLINK		; CURSOR IS BLINKING
EF_VDASCS0:
	SRA	E
	JR	NC,EF_VDASCS1
	OR	EF_ULIN			; UNDERLINED CURSOR
	JR	EF_VDASCS2
EF_VDASCS1:
	SRA	E
	JR	NC,EF_VDASCS2
	AND	EF_COMPL
EF_VDASCS2:
	LD	(EF_VDACATTR),A
	CALL	EF_LOADCSTYLE
	XOR	A
	RET
;
EF_VDASCP:
; SET VIDEO CURSOR POSITION
; ENTRY: C = VIDEO UNIT, D = ROW, E = COLUMN
; RETURN A = STATUS
; CHECKING THE FEASIBILITY OF THE INPUT VALUES
	LD	A,EF_DLINES-1
	CP	D
	JR	C,EF_VDASCP0
	LD	A,EF_DROWS-1
	CP	E
	JR	C,EF_VDASCP0
	LD	(EF_VDA_POS),DE		; D = ROW, E = COLUMNS
;
	PUSH	DE
#IF (EF_SIZE=V80X24)
	RRC	E			; ADJUST TO 80 COLUMN LAYOUT
#ENDIF
	LD	D,EF_XP			; X POSITION
	CALL	EF_WWRREG
	POP	DE
;
	PUSH	HL
	LD	HL,(EF_VDA_OFFSET)
	LD	A,H
	POP	HL
;
	ADD	A,FIRSTLINE
	ADD	A,D
	CP	FIRSTLINE+EF_DLINES
	JR	C,EF_SETYP0
	SUB	EF_DLINES
EF_SETYP0:
	LD	E,A
	LD	A,(EF_CON_BANKY)	; STAY IN DISTRICT
	OR	E
	LD	E,A
	LD	D,EF_YP
	CALL	EF_WWRREG
	XOR	A
	RET
EF_VDASCP0:
	XOR	A
	OR	-6			; PARAMETERS OUT OF RANGE $FF
	RET
;
EF_VDASAT:
; VIDEO SET CHARACTER ATTRIBUTE FOR SCROLL, KRL, ETC.
; ENTRY: C = VIDEO UNIT, E = ATTRIBUTE
; 80 CHARACTER/ROW STYLE := E0 = BLINK, E1 = UNDELINE, E2 = REVERSE, E3 = COLOR SELECT
; 40 CHARACTER/ROW STYLE := E0 = BLINK, E1 = UNDELINE, E2 = REVERSE, E3 = COLOR SELECT, E4..E7 = TYPE AND SET
; B(0)		:= INSERT
; B(1)		:= DOUBLE HIGHT
; B(2)		:= concealed character appears as a space on the screen
; B(3)		:= DOUBLE WIDTH
; B(4..7) 	:= TYPE AND SET
; RETURN A = STATUS
#IF (EF_SIZE=V80X24)
	XOR	A
	SRA	E			; IS BLINKING
	JR	NC,EF_VDASAT0
	OR	EF_FLASH
EF_VDASAT0:
	SRA	E
	JR	NC,EF_VDASAT1
	OR	EF_UNDERLINE		; UNDERLINED CURSOR
EF_VDASAT1:
	SRA	E
	JR	NC,EF_VDASAT
	OR	EF_NEGATIVE		; NEGATIVE CURSOR
EF_VDASAT2:
	SRA	E
	JR	NC,EF_VDASAT3
	OR	EF_COLORSET
EF_VDASAT3:
#ENDIF
#IF (EF_SIZE=V40X24)
; set VDATYPESET
	LD	A,E
	AND	$F0
	LD	(EF_VDATYPESET),A
	XOR	A
	SRA	E			; IS BLINKING
	JR	NC,EF_VDASAT0
	OR	EF_FLASHCHAR
EF_VDASAT0:
	SRA	E
	SRA	E
	JR	NC,EF_VDASAT1
	OR	EF_REVERSCHAR
EF_VDASAT1:
#ENDIF
	LD	(EF_VDAATTR),A
	XOR	A
	RET
;
EF_LOADCSTYLE:
	LD	A,(EF_VDACATTR)
	LD	B,A
	LD	D,EF_MATREG
	CALL	EF_READ_INDIR
	AND	11001111B
	OR	B
	LD	E,A
	LD	D,EF_MATREG
	CALL	EF_LOAD_INDIR
	RET
;
EF_VDASCO:
; VIDEO SET CHARACTER COLOR
; ENTRY C = VIDEO UNIT, E = COLOR
; RETURN A = STATUS
	CALL	EF_WAITRDY
#IF (EF_SIZE=V80X24)	; COLOR SETUP USE MARGIN COLOR IN MAT AND
	LD	A,E
	LD	B,A			; B = BG
	SRL	B
	SRL	B
	SRL	B
	SRL	B
	AND	$F8			; MASK BG COLOR
	LD	A,E
	AND	$07			; MASK FG COLOR
	LD	C,A			; C = FG
	LD	D,EF_DORREG		; LOAD FG COLOR FROM DOR(3..0)
	CALL	EF_READ_INDIR
	AND	$F8
	OR	C			; SET NEW FG COLOR
	LD	E,A
	LD	D,EF_DORREG		; LOAD NEW FG COLOR
	CALL	EF_LOAD_INDIR
;
	LD	D,EF_MATREG		; LOAD BG COLOR
	CALL	EF_READ_INDIR
	AND	$F8			; MASK BG COLOR
	OR	B			; SET NEW BG COLOR
	LD	E,A
	LD	D,EF_MATREG		; LOAD NEW BG COLOR
	CALL	EF_LOAD_INDIR
#ENDIF
#IF (EF_SIZE=V40X24)
	LD	HL,EF_VDACOLOR
	LD	A,E
	AND	$7			; MASK FG COLOR
	RLD
	LD	A,E
	SRL	A			; BG COLOR TO LOW ORDER FOUR BITS
	SRL	A
	SRL	A
	SRL	A
	RLD
#ENDIF
	XOR A
	RET
;
EF_VDAWRC:
; VIDEO WRITE CHARACTER,
; ENTRY C = VIDEO UNIT, E = CHARACTER
; RETURN A = STATUS
#IF (EF_SIZE=V80X24)
	CALL	EF_KRL80
	LD	D,EF_R1+EF_EXEC
	CALL	EF_WWRREG
#ENDIF
#IF (EF_SIZE=V40X24)
	CALL	EF_KRF40
	LD	D,EF_R1+EF_EXEC
	CALL	EF_WWRREG
#ENDIF
	CALL	EF_INCCURSOR
	XOR	A
	RET
;
EF_VDAFIL:
; VIDEO FILL
; ENTRY: C = VIDEO UNIT, E = CHARACTER, HL = COUNT OF CHARACTERS
; RETURN A = STATUS
	CALL	EF_CURSOROFF
EF_VDAFIL0:
	CALL	EF_VDAWRC
	DEC	HL
	LD	A,H
	OR	L
	JR	NZ,EF_VDAFIL0
	CALL	EF_CURSORON
	XOR	A
	RET
;
EF_VDACPY:
; VIDEO COPY
; ENTRY C = VIDEO UNIT, D = SOURCE ROW, E =  SOURCE COLUMN, L = COUNT
; RETURN A = STATUS
	PUSH	DE			; SAVE SOURCE
	LD	A,L
	LD	(EF_CPYCNT),A
	CALL	EF_CURSOROFF
	CALL	EF_GETXY		; GET AND SAVE CURRENT CURSOR POSITION
	LD	(EF_CURPOS),DE
; CHECK END OF SCREEN
	LD	H,D			; D = CURRENT LINE
	LD	E,EF_DROWS		; CHARACTERS IN ROW
	CALL	MULT8			; LINES * DROWS
	POP	DE
	PUSH	DE
	LD	D,0
	ADD	HL,DE			; ADD CHARACTERS IN CURRENT LINE := USED CHARACTERS
	EX	DE,HL
	LD	HL,EF_DLINES*EF_DROWS	; AVAILABLE CHARACTER COUNT
	XOR	A
	SBC	HL,DE			; REMAINING CHARACTERS = AVAILABLE - USED
	LD	C,L			; SAVE REMAINING CHARACTER COUNT
	LD	A,(EF_CPYCNT)
	LD	B,A
	LD	E,A
	LD	D,0
	SBC	HL,DE			; COMPARE COPY COUNT WITH AVAILABLE
	JR	NC,EF_CPY0
	LD	B,C			; ADJUST COPY COUNT
EF_CPY0:
	POP	DE
	CALL	EF_VDASCP		; SET SOURCE AS CURSOR
	LD	HL,EF_BUF
	PUSH	BC
EF_CPYRD:
#IF (EF_SIZE=V80X24)
	PUSH	BC
	CALL	EF_VDARDC
	POP	BC
	LD	(HL),E
	INC	HL
#ENDIF
#IF (EF_SIZE=V40X24)
	PUSH	HL
	PUSH	BC
	CALL	 EF_VDARDC
	LD	A,L
	POP	BC
	POP	HL
	LD	(HL),E
	INC	HL
	LD	(HL),A
	INC	HL
#ENDIF
	CALL	EF_INCCURSOR
	DJNZ	EF_CPYRD
	LD	DE,(EF_CURPOS)		; RECOVER AND SET CURSOR POSITION
	CALL	EF_VDASCP
	POP	BC
	LD	HL,EF_BUF
EF_CPYWR:
#IF (EF_SIZE=V80X24)
	PUSH	BC
	LD	E,(HL)
	CALL	EF_VDAWRC
	INC	HL
	POP	BC
	DJNZ	EF_CPYWR
#ENDIF
#IF (EF_SIZE=V40X24)
	PUSH	BC
	LD	E,(HL)
	INC	HL
	PUSH	HL
	LD	L,(HL)
	CALL	EF_VDAWRC
	POP	HL
	INC	HL
	POP	BC
	DJNZ	EF_CPYWR
#ENDIF
	; RESTORE CURSOR
	LD	DE,(EF_CURPOS)
	CALL	EF_VDASCP
	CALL	EF_CURSORON
	XOR	A
	RET
;
EF_VDASCR:
; VIDEO SCROLL
; ENTRY: C = VIDEO UNIT, E = LINES
; RETURN A = STATUS
	CALL	EF_CURSOROFF
EF_VDASCR0:
	LD	A,E
	OR	A
	JR	Z,EF_VDASCR2		; SCROLL 0, NOTHING TO DO
	PUSH	DE
	RLCA
	JR	C,EF_VDASCR1
	CALL	EF_SCRUP
	POP	DE
	DEC	E
	JR	EF_VDASCR0
EF_VDASCR1:
	CALL	EF_SCRDOWN
	POP	DE
	INC	E
	JP	EF_VDASCR0
EF_VDASCR2:
	CALL	EF_CURSORON
	RET
;
EF_SCRUP:
	LD	HL,(EF_VDA_OFFSET)
	LD	DE,$0100 		; inc y
	ADD	HL,DE
	LD	A,H
	CP	EF_DLINES
	JR	NZ,EF_SCRUP0
	LD	HL,0
EF_SCRUP0:
	LD	(EF_VDA_OFFSET),HL
	LD	A,(EF_CON_BANKY)
	ADD	A,H
	ADD	A,FIRSTLINE
	LD	E,A
	LD	D,EF_RORREG
	CALL	EF_LOAD_INDIR
; fill exposed line
	LD	HL,(EF_VDA_POS)
	PUSH	HL
	LD	HL,(EF_DLINES-1)*256
	EX	DE,HL
EF_SCRCLEAR:
	CALL	EF_VDASCP
	LD	E,' '
	LD	HL,EF_DROWS
	CALL	EF_VDAFIL
;
	POP	HL
	EX	DE,HL
	CALL	EF_VDASCP
	RET
;
EF_SCRDOWN:
	XOR	A
	LD	HL,(EF_VDA_OFFSET)
	LD	DE,$FF00
	ADD	HL,DE
	LD	A,$FF
	CP	H
	JR	NZ,EF_SCRDOWN0
	LD	H,EF_DLINES-1
EF_SCRDOWN0:
	LD	(EF_VDA_OFFSET),HL
	LD	A,(EF_CON_BANKY)
	ADD	A,FIRSTLINE
	ADD	A,H
	LD	E,A
	LD	D,EF_RORREG
	CALL	EF_LOAD_INDIR
; fill exposed line
	LD	HL,(EF_VDA_POS)
	PUSH	HL
	LD	DE,0
;	JR	EF_SCRCLEAR
	CALL	EF_VDASCP
	LD	E,' '
	LD	HL,EF_DROWS
	CALL	EF_VDAFIL
;
	POP	HL
	EX	DE,HL
	CALL	EF_VDASCP
	RET
;
EF_VDARDC:
; READ CHARACTER AT CURRENT VIDEO POSITION
; ENTRY: C = VIDEO UNIT
; RETURN: A = STATUS, E = CHARACTER, B = CHARACTER COLOR, C = CHARACTER ATTRIBUTES, L = CHARACTER TYPESET, 40X24 ONLY
#IF (EF_SIZE = V80X24)
	LD	D,EF_R0
	LD	A,EF_KRL		; R0 KRL COMMAND NO AUTOINC
	OR	EF_RREG
	LD	E,A
	CALL	EF_WWRREG
	LD	D,EF_R3 + EF_EXEC	; READ ATTRIBUTES
	CALL	EF_RDREG
	LD	C,A
	CALL	EF_WAITRDY
	LD	D,EF_R1+EF_EXEC
	CALL	EF_RDREG
	PUSH	DE
; READ COLOR
	LD	D,EF_DORREG		; LOAD FG COLOR
	CALL	EF_READ_INDIR
	AND	$07
	LD	B,A
	LD	D,EF_MATREG		; LOAD BG COLOR
	CALL	EF_READ_INDIR
	RLCA
	RLCA
	RLCA
	RLCA
	AND	$70
	OR	B
	LD	B,A
	POP	DE
	XOR	A
;	LD	L,A
	RET
#ENDIF
#IF (EF_SIZE = V40X24)
	LD	D,R0
	LD	A,KRF			; R0 KRL COMMAND NO AUTOINC
	OR	EF_RREG
	LD	E,A
	CALL	EF_WWRREG
	LD	D,EF_R3 + EF_EXEC	; READ CHARACTER ATTRIBUTES
	CALL	EF_RDREG
	AND	$77
	LD	B,A
	RLC	B
	RLC	B
	RLC	B
	RLC	B
	LD	A,E
	AND	$88
	LD	C,A
	LD	D,EF_R2 + EF_EXEC	; READ CHARACTER TYPESET
	CALL	EF_RDREG
	LD	L,A
	LD	D,EF_R1+EF_EXEC		; READ CHARACTER
	CALL	EF_RDREG
	XOR	A
	RET
#ENDIF
;
EF_IDAT:
	.DB	KBDMODE_NONE	; PS/2 8242 KEYBOARD CONTROLLER
	.DB	0
	.DB	0
;
EF_VDA_POS	.DW	0
EF_CURPOS	.DW	0
EF_CPYCNT	.DB	0
EF_VDA_OFFSET	.DW	0
EF_CON_BANKY	.DB	0
EF_VDAATTR	.DB	0		; CHARACTER ATTRIBUTES
EF_VDACATTR	.DB	0		; CURSOR ATTRIBUTES
EF_VDACOLOR	.DB	0		; CHARACTER COLOR
#IF (EF_SIZE = V40X24)
EF_VDATYPESET	.DB	0		; 40 CHAR/ROW PARAMETER
#ENDIF
EF_BUF:
#IF (EF_SIZE = V80X24)
	.FILL	EF_DLINES*EF_DROWS	;256,0	; COPY BUFFER
#ENDIF
#IF (EF_SIZE = V40X24)
	.FILL 2*EF_DLINES*EF_DROWS	;512,0
#ENDIF
