;DISP2/ASM
*TITLE	'DISP2 - DISPLAY DRIVER PACKAGE'
;
;	DISP2 IS A GENERAL PURPOSE DISPLAY PACKAGE.
;	THIS PACKAGE CONSISTS OF 8 ROUTINES:
;
;		$VDCHAR - WRITE A CHARACTER SCROLL
;		$VDGRAF - WRITE A CHARACTER GRAPHICS
;		$VDREAD - READ A CHARACTER GRAPHICS
;		$VIDKEY - WRITE LINE & ACCEPT KEYBOARD
;		$CURSOR - CURSOR ON/OFF & BLINK
;		$SCROLL - SCROLL PROTECT TOP LINES
;		$VIDRAM - VIDEO/RAM TRANSFER
;		$SCREEN - WRITE SCREEN TO DEVICE
;
*EJECT
;	DISPLAY DRIVER CONSTANTS
;
DDCB@	EQU	1		;DISPLAY DCB NUMBER
VLEN	EQU	2048		;2K VIDEO MEMORY
;
;	HARDWARE ADDRESSING MODEL-II
;
CRTA	EQU	0FCH		;CRTC ADD REGISTER
CRTD	EQU	0FDH		;CRTC DATA REGISTER
MDSL	EQU	0FFH		;MODE SEL PORT
VIDEO	EQU	0F800H		;START VIDEO MEMORY
;
;	SPECIAL CHARACTERS SUPPORTED
;
SOH	EQU	1		;BLINKING CURSOR ON
STX	EQU	2		;CURSOR OFF
ETX	EQU	3		;SLOW BLINK CURSOR ON
EOT	EQU	4		;NON-BLINK CURSOR
BS	EQU	8		;BACKSPACE
HT	EQU	9		;HORIZONTAL TAB
LF	EQU	10		;LINE FEED
VT	EQU	11		;CURSOR BEG PREVIOUS
CR	EQU	13		;CARRIAGE RETURN
DC4	EQU	20		;HOME CURSOR SCROLL AREA
ETB	EQU	23		;ERASE TO END LINE
CAN	EQU	24		;ERASE TO END SCREEN
EM	EQU	25		;SET NORMAL DISPLAY MODE
SUB	EQU	26		;SET REVERSE DISPLAY MODE
ESC	EQU	27		;ERASE SCREEN & HOME
FS	EQU	28		;CURSOR LEFT
GS	EQU	29		;CURSOR RIGHT
RS	EQU	30		;80 CHAR/LINE MODE
VS	EQU	31		;40 CHAR/LINE MODE
SCD	EQU	0F9H		;SPECIAL GRAF CODES
;
;	MISC ERROR CODES
;
ERR3	EQU	3		;PARAMETER ERROR
;
;	MACHINE INSTRUCTIONS
;
ORA	EQU	0F6H		;OR	N
XRA	EQU	0AFH		;XOR	A
;
*EJECT
;	$VDCHAR - VIDEO CHARACTER I/O
;
;	ENT	 B =	CHARACTER 0-127
;		IX =>	DISPLAY DCB
;
DSPCODE PUSH	BC		;SAVE CHARS
	LD	E,(IX+11)	;COL
	LD	D,(IX+12)	;ROW
	BIT	0,(IX+5)	;XLATE?
	JR	Z,VDCHR0	;IF NOT
	LD	A,B		;GET CHAR
	LD	L,(IX+6)
	LD	H,(IX+7)	;HL => XLATE TABLE
	LD	B,(IX+8)	;XLATE LENGTH
	CALL	XLATE		;TRANSLATE!
	LD	B,A		;B = CHAR
;
VDCHR0	CALL	VDSEL		;SELECT VIDEO
	LD	A,B		;GET CHAR
	CP	' '             ;CTL?
	JR	C,VDCHR3	;IF YES
	CALL	VCHR13		;OUTPUT
;
VDCHR1	CALL	VDOFF		;DE-SEL VIDEO
	CALL	PTCUR		;POSN CURSOR
	LD	(IX+11),E	;SAVE COL
	LD	(IX+12),D	;SAVE ROW
	POP	BC		;GET CHARS
	XOR	A		;Z STATUS
	RET
;
;	CONTROL CODE HANDLER
;
VDCHR3	LD	HL,VDCHR1	;RET ADD
	PUSH	HL		;TO STACK
;
	PUSH	DE		;SAVE CURSOR
	LD	HL,CTLTBL	;HL => CTL TABLE
VDCHR4	INC	(HL)
	DEC	(HL)		;END TABLE?
	JR	Z,VDCHR5	;NO CODE
	CP	(HL)		;FOUND?
	INC	HL		;NEXT
	LD	E,(HL)
	INC	HL
	LD	D,(HL)		;DE = ADDRESS
	INC	HL		;HL => NEXT CODE
	JR	NZ,VDCHR4	;NOT FOUND
	EX	DE,HL		;HL => ROUTINE
	POP	DE		;RESTORE
	JP	(HL)		;GO!
;
VDCHR5	POP	DE		;RESTORE
	RET
;
;	BACKSPACE CURSOR ROUTINE
;
VDCHR6	CALL	VDCHR7		;CURSOR LEFT
	LD	A,(IX+9)	;HL => CURSOR
	OR	' '             ;BLANK W/MODE
	LD	(DE),A		;OUTPUT
	RET
;
;	CURSOR LEFT ROUTINE
;
VDCHR7	DEC	DE		;BKSP COL
	JR	VDCHR9		;CHECK IF OK
;
;	CURSOR UP ROUTINE
;
VDCHR8	CALL	FNDBEG		;LOCATE START LINE
	LD	E,(IX+10)
	LD	D,0		;DE = LINE LENGTH
	SBC	HL,DE		;MOVE UP
	EX	DE,HL		;DE => CURSOR
;
VDCHR9	LD	L,(IX+13)
	LD	H,(IX+14)	;HL => START VIDEO
	PUSH	HL		;SAVE START
	SCF
	SBC	HL,DE		;CURSOR+1 > START?
	POP	HL		;GET START
	RET	C		;IF YES
	EX	DE,HL		;DE => START
	RET
;
;	POSN CURSOR TO NEXT TAB POSN
;
VCHR10	LD	A,E		;GET COL
	AND	0F8H		;FORCE TAB ZONE
	LD	E,A		;E = TAB ZONE
	LD	L,8		;TAB
	JR	VCHR32		;SKIP
;
;	POSITION TO NEXT LINE
;
VCHR11	CALL	FNDBEG		;LOCATE START LINE
	EX	DE,HL		;DE => CURSOR LINE
VCHR12	LD	L,(IX+10)
VCHR32	LD	H,0		;HL = LINE LENGTH
	ADD	HL,DE		;HL => NEXT LINE
	EX	DE,HL		;DE => CURSOR
	JR	VCHR15		;SCROLL
;
;	OUTPUT CHARACTER HERE
;
VCHR13	OR	(IX+9)		;MODE
	LD	(DE),A		;OUTPUT CHAR
;
;	CURSOR RIGHT ROUTINE
;
VCHR14	INC	DE		;CURSOR FORWARD
VCHR15	LD	L,(IX+15)
	LD	H,(IX+16)	;END VIDEO+1
	SCF			;CLR CRY
	SBC	HL,DE		;SCROLL?
	RET	NC		;IF NOT
;
;	SCROLL VIDEO ROUTINE
;
VCHR16	LD	L,(IX+13)
	LD	H,(IX+14)	;HL => 1ST SCROLL LINE
	PUSH	HL		;SAVE 1ST LINE
	LD	E,(IX+10)
	LD	D,0		;DE = LINE LENGTH
	ADD	HL,DE		;HL => 2ND SCROLL LINE
	LD	C,(IX+17)
	LD	B,(IX+18)	;BC = SCROLL COUNT
	POP	DE		;DE => 1ST LINE
	LDIR			;SCROLL!
;
;	CLEAR TO END-OF FRAME
;
VCHR17	LD	L,(IX+15)
	LD	H,(IX+16)	;END VIDEO+1
	OR	A		;CLR CRY
	SBC	HL,DE		;HL = COUNT
;
VCHR18	PUSH	DE		;SAVE
	LD	B,H
	LD	C,L		;BC = COUNT
	EX	DE,HL		;HL => CURSOR
	LD	A,(IX+9)	;CHAR MODE
	OR	' '             ;BLANK
VCHR19	LD	(HL),A		;OUTPUT
	CPI			;NEXT
	JP	PE,VCHR19	;TIL DONE
	POP	DE		;RESTORE
	RET
;
;	CLEAR TO END-OF-LINE
;
VCHR20	CALL	FNDBEG		;LOCATE START LINE
	LD	C,(IX+10)
	LD	B,0		;BC = LINE LENGTH
	ADD	HL,BC		;HL => END BLANK AREA
	SBC	HL,DE		;HL = BLANK COUNT
	JR	VCHR18		;CLEAR
;
;	SET CURSOR CONTROLS
;
VCHR21	CALL	CURSR2		;SET CURSOR PARAMS
	RET
;
;	NORMAL/REVERSE CHAR MODES
;
VCHR22	RES	7,(IX+9)	;NORMAL MODE
	RET
VCHR23	SET	7,(IX+9)	;REVERSE MODE
	RET
;
;	40 & 80 CHAR/LINE MODES
;
VCHR24	LD	HL,VMASK	;VIDEO MASK
	RES	4,(HL)		;NORMAL MODE
	CALL	VCHR27		;CLS
	LD	HL,CRTD80	;CRTC DATA 80
	LD	DE,DVRD80	;DRIVER DATA 80
	JR	VCHR30		;SKIP
;
VCHR25	LD	HL,VMASK	;VIDEO MASK
	SET	4,(HL)		;WIDE MODE
	CALL	VCHR27		;CLS
	LD	HL,CRTD40	;CRTC DATA 40
	LD	DE,DVRD40	;DRIVER DATA 40
;
VCHR30	LD	BC,4<8+CRTD	;COUNT+REG
	XOR	A		;START
VCHR31	OUT	(CRTA),A	;SET REG
	INC	A		;NEXT REG
	OUTI			;MOVE DATA
	JR	NZ,VCHR31	;TIL DONE
;
	PUSH	IX
	POP	HL		;HL => DCB
	LD	BC,10		;OFFSET
	ADD	HL,BC		;HL => INFO
	EX	DE,HL		;DE => INFO
	LD	BC,9		;COUNT
	LDIR			;MOVE!
;
;	HOME CURSOR SCROLL MODE
;
VCHR26	LD	E,(IX+13)	;1ST SCROLL LINE
	LD	D,(IX+14)	;DE => START SCROLL
	RET
;
;	CLEAR SCREEN & HOME CURSOR
;
VCHR27	LD	DE,VIDEO	;START VIDEO
	LD	HL,1920 	;FULL SCREEN
	JR	VCHR18		;BLANK VIDEO
;
;	TABLE OF CONTROL CODES
;
CTLTBL	DEFB	SOH		;SLOW BLINK ON
	DEFW	VCHR21
	DEFB	STX		;CURSOR OFF
	DEFW	VCHR21
	DEFB	ETX		;FAST BLINK ON
	DEFW	VCHR21
	DEFB	EOT		;NON-BLINK CURSOR
	DEFW	VCHR21
	DEFB	BS		;BACKSPACE
	DEFW	VDCHR6
	DEFB	HT		;HORIZONTAL TAB
	DEFW	VCHR10
	DEFB	VT		;VERTICAL TAB
	DEFW	VDCHR8
	DEFB	LF		;LINE FEED
	DEFW	VCHR12
	DEFB	CR		;CARRIAGE RETURN
	DEFW	VCHR11
	DEFB	DC4		;HOME SCROLL AREA
	DEFW	VCHR26
	DEFB	ETB		;ERACE TO END LINE
	DEFW	VCHR20
	DEFB	CAN		;ERACE TO END FRAME
	DEFW	VCHR17
	DEFB	EM		;NORMAL MODE
	DEFW	VCHR22
	DEFB	SUB		;REVERSE MODE
	DEFW	VCHR23
	DEFB	ESC		;CLEAR SCREEN
	DEFW	VCHR27
	DEFB	FS		;CURSOR LEFT
	DEFW	VDCHR7
	DEFB	GS		;CURSOR RIGHT
	DEFW	VCHR14
	DEFB	RS		;80 CHAR MODE
	DEFW	VCHR24
	DEFB	VS		;40 CHAR MODE
	DEFW	VCHR25
	DEFB	0		;END OF TABLE
;
;	DRIVER INITIALIZATION
;
DVRD80	DEFB	80		;CHARS/LINE
	DEFW	VIDEO		;CURSOR POSN
	DEFW	VIDEO		;START SCROLL
	DEFW	VIDEO+1920	;END SCROLL
	DEFW	1840		;SCROLL COUNT
;
DVRD40	DEFB	40		;CHARS/LINE
	DEFW	VIDEO		;CURSOR POSN
	DEFW	VIDEO		;START SCROLL
	DEFW	VIDEO+960	;END SCROLL
	DEFW	920		;SCROLL COUNT
;
;	CRTC INITIALIZATION
;
CRTD80	DEFB	80+19		;H. TOTAL
	DEFB	80		;H. DISPLAYED
	DEFB	80+4		;H. SYNC POSITION
	DEFB	8		;H. SYNC WIDTH
;
CRTD40	DEFB	40+9		;H. TOTAL
	DEFB	40		;H. DISPLAYED
	DEFB	40+3		;H. SYNC POSITION
	DEFB	4		;H. SYNC WIDTH
;
*EJECT
;	$SCROLL - SCROLL PROTECT VIDEO
;
;	ENT	 B =	LINES 0-22
;
SCROLL	CALL	REGSAV		;SAVE REG
	LD	A,DDCB@ 	;DISPLAY DEVICE
	CALL	LOCDCB		;LOCATE DCB
	LD	A,B
	CP	23		;VALID?
	LD	A,ERR3		;PARAMETER ERROR
	RET	NC		;IF NOT
;
;	DETERMINE START SCROLL
;
	LD	L,(IX+10)
	LD	H,0		;HL = LINE LEN
	LD	A,B		;A = MULTIPLIER
	CALL	DMULT		;HL => 1ST SCROLL LINE
	LD	D,L
	LD	E,A		;DE = RESULT
	LD	HL,VIDEO	;OFFSET
	ADD	HL,DE		;HL => VIDEO ADD
	LD	(IX+13),L
	LD	(IX+14),H	;SET START VIDEO
;
;	DETERMINE SCROLL COUNT
;
	LD	E,(IX+15)
	LD	D,(IX+16)	;DE => END VIDEO
	EX	DE,HL
	SBC	HL,DE		;HL = COUNT
	LD	C,(IX+10)
	LD	B,0		;BC = LINE LENGTH
	SBC	HL,BC		;LESS 1 LINE
	LD	(IX+17),L
	LD	(IX+18),H	;SAVE SCROLL COUNT
	XOR	A		;NO ERROR
	RET
;
*EJECT
;	$CURSOR - SET CURSOR CONTROLS
;
;	ENT	 B =	FUNCTION SWITCH
;
CURSOR	PUSH	BC		;SAVE
	INC	B
	DEC	B
	JR	Z,CURSR1	;IF ZERO
	LD	B,-1
CURSR1	INC	B
	INC	B		;CORRECT 0-1
	CALL	CURSR2		;DO IT!
	POP	BC		;RESTORE
	RET
;
;	ENT	 B =	1-4
;
CURSR2	PUSH	HL		;SAVE
	LD	HL,CURTBL-1	;HL => TABLE
	LD	A,10		;REG #
	OUT	(CRTA),A	;SET REG
	XOR	A
	OR	B		;VALID?
	JR	Z,CURSR4	;IF NOT
	CP	5		;VALID?
	JR	NC,CURSR4	;IF NOT
CURSR3	INC	HL		;NEXT
	DJNZ	CURSR3		;TIL FOUND
	LD	A,(HL)		;GET DATA
	OUT	(CRTD),A	;SET DATA
	POP	HL		;RESTORE
	XOR	A		;STATUS
	RET
;
CURSR4	LD	A,ERR3		;PARAMETER ERROR
	OR	A		;STATUS
	RET
;
CURTBL	DEFB	01100101B	;1/32 BLINK ON
	DEFB	00100101B	;CURSOR OFF
	DEFB	01000101B	;1/16 BLINK ON
	DEFB	00000101B	;BLINK OFF
;
*EJECT
;	$VIDRAM - VIDEO/RAM TRANSFER
;
;	ENT	 B =	FUNCTION CODE
;		HL =>	RAM BUFFER
;
VIDRAM	CALL	REGSAV		;SAVE REG
	LD	A,DDCB@ 	;DISPLAY DEVICE
	CALL	LOCDCB		;LOCATE DCB
;
	EX	DE,HL		;DE => RAM
	LD	A,B		;GET CODE
	LD	L,(IX+15)
	LD	H,(IX+16)	;HL => END VIDEO
	LD	BC,VIDEO	;DE => START VIDEO
	PUSH	BC		;SAVE
	OR	A		;CLR CRY
	SBC	HL,BC		;HL = COUNT
	LD	C,L
	LD	B,H		;BC = COUNT
	POP	HL
	OR	A		;GET FUNCTION
	JR	NZ,VIDRM1	;VIDEO TO RAM
	EX	DE,HL		;RAM TO VIDEO
VIDRM1	CALL	VDSEL		;SELECT VIDEO
	LDIR			;DO IT!
	CALL	VDOFF		;DE-SEL VIDEO
	XOR	A		;NO ERROR
	RET
;
*EJECT
;	$VDGRAF - VIDEO GRAPHICS ROUTINE
;
;	ENT	 B =	ROW NUMBER 0-23
;		 C =	COL NUMBER 0-79
;		 D =	LENGTH BUFFER
;		HL =>	TEXT BUFFER
;
VDGRAF	CALL	REGSAV		;SAVE REG
	LD	A,DDCB@ 	;DISPLAY DEVICE
	CALL	LOCDCB		;LOCATE DCB
;
	CALL	CVCR2		;BC => CURSOR
	LD	A,D		;GET LENGTH
	EX	DE,HL		;DE => TEXT BUFF
	PUSH	BC
	POP	HL		;HL => CURSOR
	OR	A		;BUFFER LEN
	JR	Z,VDGRF4	;POSN CURSOR
	LD	B,A		;B = COUNT
	LD	C,(IX+9)	;CHAR MODE
	CALL	VDSEL		;SELECT VIDEO
	CALL	FVCUR		;FORCE CURSOR VALID
;
VDGRF1	LD	A,(DE)		;GET CHAR
	CP	SCD		;SPECIAL CODE
	JR	NC,VDGRF5	;IF SPECIAL
	OR	C		;CHAR MODE
	LD	(HL),A		;TO VIDEO
	INC	HL		;NEXT
VDGRF3	CALL	FVCUR		;FORCE CURSOR VALID
	INC	DE		;NEXT
	DJNZ	VDGRF1		;TIL DONE
	CALL	VDOFF		;DE-SEL VIDEO
;
VDGRF4	EX	DE,HL		;DE => CURSOR
	CALL	PTCUR		;POSN CURSOR
	LD	(IX+11),E	;SAVE COL
	LD	(IX+12),D	;SAVE ROW
	XOR	A		;NO ERROR
	RET
;
;	HANDLE SPECIAL CONTROLS
;
VDGRF5	PUSH	HL		;SAVE
	LD	HL,VDGRF3	;RETURN ADD
	EX	(SP),HL 	;TO STACK
;
	SUB	SCD		;NORMAL MODE
	JR	Z,VDGRF7
	DEC	A		;REVERSE MODE
	JR	Z,VDGRF8	;GO!
	DEC	A		;HOME CURSOR
	JR	Z,VDGRF9	;GO!
	DEC	A		;CURSOR BACK
	JR	Z,VGRF10	;GO!
	DEC	A		;CURSOR FORWARD
	JR	Z,VGRF11	;GO!
	DEC	A		;CURSOR UP
	JR	Z,VGRF12	;GO!
;
;	CURSOR DOWN ROUTINE
;
VDGRF6	PUSH	DE		;SAVE
	LD	E,(IX+10)	;LINE LENGTH
	LD	D,0
	ADD	HL,DE		;HL => NEXT LINE
	POP	DE		;RESTORE
	RET
;
;	CURSOR UP ROUTINE
;
VGRF12	PUSH	DE		;SAVE
	LD	E,(IX+10)
	LD	D,0		;DE = LINE LEN
	OR	A		;CLR CRY
	SBC	HL,DE		;HL => PREVIOUS LINE
	POP	DE		;RESTORE
	RET
;
;	SET CHARACTER MODES
;
VDGRF7	RES	7,C		;NORMAL MODE
	RET
VDGRF8	SET	7,C		;REV MODE
	RET
;
;	LEFT/RIGHT ROUTINES
;
VGRF10	DEC	HL		;CURSOR BACK
	RET
VGRF11	INC	HL		;CURSOR FORWARD
	RET
;
;	CURSOR HOME ROUTINE
;
VDGRF9	LD	HL,VIDEO	;CURSOR HOME
	RET
;
*EJECT
;	$VDREAD - VIDEO READ ROUTINE
;
;	ENT	 B =	ROW NUMBER 0-23
;		 C =	COL NUMBER 0-79
;		 D =	LENGTH BUFFER
;		HL =>	TEXT BUFFER
;
VDREAD	PUSH	DE		;SAVE REGISTERS
	PUSH	HL
	PUSH	IX
	LD	A,DDCB@ 	;DISPLAY DEVICE
	CALL	LOCDCB		;LOCATE DCB
	INC	D
	DEC	D		;GET CURSOR?
	JR	Z,VDRED2	;IF YES
;
	CALL	CVCR2		;CONVERT CURSOR
	EX	DE,HL		;DE => BUFFER
	PUSH	BC		;SAVE CURSOR
	LD	C,H		;B = COUNT
	LD	B,0		;BC = COUNT
	POP	HL		;HL => CURSOR
	CALL	VDSEL		;SELECT VIDEO
;
VDRED1	CALL	FVCUR		;FORCE ON VIDEO
	LDI			;TO BUFF
	JP	PE,VDRED1	;TIL DONE
	CALL	VDOFF		;DE-SEL VIDEO
;
VDRED2	LD	C,(IX+11)
	LD	B,(IX+12)	;BC => CURSOR
	CALL	CVCR1		;BC = CURSOR ROW,COL
	POP	IX		;RESTORE REG
	POP	HL
	POP	DE
	XOR	A
	RET
;
*EJECT
;	$SCREEN - OUTPUT SCREEN ROUTINE
;
;	ENT	DE =>	DEVICE DCB
;
SCREEN	CALL	REGSAV		;SAVE REGISTERS
	LD	A,DDCB@ 	;DISPLAY DEVICE
	CALL	LOCDCB		;LOCATE DCB
	LD	HL,VIDEO	;HL => VIDEO
;
SCREN1	LD	C,(IX+10)	;CHARS/LINE
SCREN2	CALL	VDSEL		;SELECT VIDEO
	LD	B,(HL)		;B = CHAR
	CALL	VDOFF		;DE-SEL VIDEO
	CALL	PUT		;TO DEVICE!
	RET	NZ		;IF ERROR
	INC	HL		;NEXT
	DEC	C		;NEXT
	JR	NZ,SCREN2	;TIL EOL
	LD	B,CR		;C/R
	CALL	PUT		;OUTPUT
	RET	NZ		;IF ERROR
	LD	C,(IX+15)
	LD	B,(IX+16)	;BC => END VIDEO
	SBC	HL,BC		;DONE?
	RET	Z		;IF YES
	ADD	HL,BC		;CORRECT
	JR	SCREN1		;TIL DONE
;
*EJECT
;	POSITION CURSOR ROUTINE
;
;	ENT	DE =	CURSOR POSN
;
PTCUR	LD	A,14		;REG #
	OUT	(CRTA),A	;SET REG
	LD	A,D		;MSB
	AND	7		;FORCE VALID
	OUT	(CRTD),A	;SET MSB
	LD	A,15		;REG #
	OUT	(CRTA),A	;SET REG
	LD	A,E		;LSB
	OUT	(CRTD),A	;SET LSB
	RET
;
;	CONVERT CURSOR TO ROW/COL
;
;	ENT	BC =>	CURSOR
;	EXT	BC =	ROW,COL
;
CVCR1	PUSH	HL		;SAVE
	LD	L,C		;LSB CURSOR
	LD	A,B
	AND	7		;IGNORE ADDRESS
	LD	H,A		;HL = CURSOR POSN
	LD	A,(IX+10)	;CHARS/LINE
	CALL	DDIVD		;DO IT!
	LD	C,A		;COL
	LD	B,L		;ROW
	POP	HL		;RESTORE
	RET
;
;	CONVERT ROW/COL TO CURSOR
;
;	ENT	BC =	ROW,COL
;	EXT	BC =>	CURSOR
;
CVCR2	PUSH	HL		;SAVE REG
	PUSH	DE
	LD	A,(IX+10)	;CHARS/LINE
	LD	L,B
	LD	H,0		;HL = ROW
	CALL	DMULT		;GET MSB
	ADD	A,C		;+ COL
	LD	C,A		;C = LSB
	LD	A,VIDEO<-8	;RAM OFFSET
	ADC	A,L		;+MSB
	LD	B,A		;BC = POSN
	POP	DE		;RESTORE REG
	POP	HL
	RET
;
;	LOCATE START OF LINE
;
;	ENT	DE =>	CURSOR
;
FNDBEG	PUSH	DE		;SAVE CURSOR
	LD	HL,VIDEO	;HL => START VIDEO
	LD	C,(IX+10)
	LD	B,0		;BC = LINE LENGTH
FNBEG1	PUSH	HL		;SAVE
	ADD	HL,BC		;HL => NEXT LINE
	SCF
	SBC	HL,DE		;COMPARE
	POP	HL		;RESTORE
	JR	NC,FNBEG2	;LINE >= CURSOR+1
	ADD	HL,BC		;HL => NEXT LINE
	JR	FNBEG1		;TIL DONE
FNBEG2	POP	DE		;GET CURSOR
	RET
;
;	FORCE CURSOR ON VIDEO
;
;	ENT	HL =>	CURSOR
;
FVCUR	PUSH	DE		;SAVE
	EX	DE,HL		;DE => CURSOR
	LD	HL,2048 	;-VIDEO
	ADD	HL,DE		;CURSOR < START?
	JR	C,FVCR1 	;IF NOT
	LD	E,(IX+15)
	LD	D,(IX+16)	;DE => END VIDEO
	ADD	HL,DE		;HL => NEW CURSOR
	POP	DE		;RESTORE
	RET
;
FVCR1	LD	L,(IX+15)
	LD	H,(IX+16)	;HL => END VIDEO
	SBC	HL,DE		;END+1 >= CURSOR+1?
	EX	DE,HL		;HL => CURSOR
	JR	NC,FVCR2	;IF NOT
	LD	HL,VIDEO	;START VIDEO
	SBC	HL,DE		;HL => NEW CURSOR
FVCR2	POP	DE		;RESTORE
	RET
;
;	SELECT VIDEO ROUTINE
;
VDSEL	POP	AF		;GET CALLER
	LD	(TSP),SP	;SAVE STACK
	LD	SP,(LSP)	;NEW STACK
	PUSH	AF		;PUT CALLER
	LD	A,(VMASK)	;VIDEO MASK
	OR	80H		;SEL VIDEO
	LD	(VMASK),A	;SAVE MASK
	OUT	(MDSL),A	;SEL VIDEO
	RET
;
;	DE-SEL VIDEO ROUTINE
;
VDOFF	LD	A,(VMASK)	;VIDEO MASK
	AND	7FH		;DE-SEL VIDEO
	LD	(VMASK),A	;SAVE MASK
	OUT	(MDSL),A	;DE-SEL
	POP	AF		;GET CALLER
	LD	SP,(TSP)	;RESTORE STACK
	PUSH	AF		;PUT CALLER
	RET
 