Tvùrce webu je i pro tebe! Postav tøeba web. Bez grafika. Bez kodéra. Hned.
wz

VT102.ASM

VT102 Terminal Emulator


; =============================================================================
;
;                        Litos - VT102 terminal emulator
;
; =============================================================================

		CODE_SECTION	32


; ------------- Macro - call display function (%1=function offset,EBX=terminal)

%macro		VT_FNC	1

		push	ebx		; push EBX
		push	dword %%1	; push return address
		mov	ebx,[ebx+VT_Disp] ; EBX <- display driver
		DRVFNC	ebx, %1		; call driver function
%%1:		pop	ebx		; pop EBX
%endmacro

; ------------- Set Escape service (EBX = terminal interface)

%define VTESC_NORM mov dword [ebx+VT_Esc],VT1WEscNorm	; no escape (normal)
%define VTESC_ESC  mov dword [ebx+VT_Esc],VT1WEscEsc	; Esc character
%define VTESC_SBL  mov dword [ebx+VT_Esc],VT1WEscSBL	; square bracket [
%define VTESC_PAR  mov dword [ebx+VT_Esc],VT1WEscPar	; start of num. param.
%define VTESC_KEY  mov dword [ebx+VT_Esc],VT1WEscKey	; function key
%define VTESC_HASH mov dword [ebx+VT_Esc],VT1WEscHash	; hash #
%define VTESC_RBL  mov dword [ebx+VT_Esc],VT1WEscRBL	; round bracket left (
%define VTESC_RBR  mov dword [ebx+VT_Esc],VT1WEscRBR	; round bracket right )
%define VTESC_PER  mov dword [ebx+VT_Esc],VT1WEscPer	; percent %
%define VTESC_NSTD mov dword [ebx+VT_Esc],VT1WEscNStd	; non standard
%define VTESC_PAL  mov dword [ebx+VT_Esc],VT1WEscPal	; palette

; -----------------------------------------------------------------------------
;                            Enumerate videomodes
; -----------------------------------------------------------------------------
; INPUT:	EAX = index (0..., -1 = get max. index)
;		EBX = terminal interface
;		EDX = videomode structure VMODE (NULL=not used)
; OUTPUT:	CY = invalid index (EAX = maximum index)
;		NC = videomode is valid (EDX structure is filled-up)
;		EAX = index or maximum index (in case of error)
; NOTES: Structure VMODE (EDX) will be filled-up (if EDX is not NULL).
;	 This function enumerates only recommended standard videomodes.
; -----------------------------------------------------------------------------

VTEnumMode:	VT_FNC	DDFB_EnumMode
		ret

; -----------------------------------------------------------------------------
;                             Test videomode
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
;		EDX = videomode structure VMODE (full dimension, display
;			dimension, font dimension, frequency and memory mode
;			entries can be set or 0 = auto)
; OUTPUT:	CY = invalid videomode
;		NC = videomode is valid (EDX structure is filled-up)
; -----------------------------------------------------------------------------

VTTestMode:	VT_FNC	DDFB_TestMode
		ret

; -----------------------------------------------------------------------------
;                                Set videomode
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
;		EDX = videomode structure VMODE (full dimension, display
;			dimension, font dimension, frequency and memory mode
;			entries can be set or 0 = auto)
; OUTPUT:	CY = invalid videomode
;		NC = videomode is valid and set (EDX structure is filled-up)
; -----------------------------------------------------------------------------

VTSetMode:	VT_FNC	DDFB_SetMode
		ret

; -----------------------------------------------------------------------------
;                         Clear screen and reset cursor
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; NOTES:	It clears entire screen, sets offset to 0 and resets cursor.
; -----------------------------------------------------------------------------

VTClear:	VT_FNC	DDFB_Clear
		ret

; -----------------------------------------------------------------------------
;                              Set display offset
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
;		ECX = X coordinate of visible region of display
;		EDX = Y coordinate of visible region of display
; -----------------------------------------------------------------------------

VTSetOffset:	VT_FNC	DDFB_SetOffset
		ret

; -----------------------------------------------------------------------------
;                            Set cursor position
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
;		ECX = cursor column
;		EDX = cursor row
; -----------------------------------------------------------------------------

VTSetCursor:	VT_FNC	DDFB_SetCursor
		ret

; -----------------------------------------------------------------------------
;                             Set cursor size
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
;		ECX = top scan line
;		EDX = bottom scan line
; -----------------------------------------------------------------------------

VTSetCurSize:	VT_FNC	DDFB_SetCurSize
		ret

; -----------------------------------------------------------------------------
;                            Set cursor visible
; -----------------------------------------------------------------------------
; INPUT:	AL = 0 cursor off, 1 cursor on, 2 flip state
;		EBX = terminal interface
; -----------------------------------------------------------------------------

VTSetVisible:	VT_FNC	DDFB_SetVisible
		ret

; -----------------------------------------------------------------------------
;                             Load text font
; -----------------------------------------------------------------------------
; INPUT:	AL = font bank (0..3 for EGA, 0..7 for VGA)
;		AH = font height (1..32, 0=default)
;		EBX = terminal interface
;		CL = first index (0..255)
;		DL = last index (0..255, must not be lesser than first index)
;		ESI = pointer to font (character with start index)
; -----------------------------------------------------------------------------

VTLoadFont:	VT_FNC	DDFB_LoadFont
		ret

; -----------------------------------------------------------------------------
;                            Set font bank
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
;		CL = font bank for color attribute bit 3 = 0 (0..3 or 0..7)
;		DL = font bank for color attribute bit 3 = 1 (0..3 or 0..7)
; -----------------------------------------------------------------------------

VTSetFont:	VT_FNC	DDFB_SetFont
		ret

; -----------------------------------------------------------------------------
;                             Set border color
; -----------------------------------------------------------------------------
; INPUT:	AL = border color (0..15 for 16-color or 0..255 for 256-color)
;		EBX = terminal interface
; -----------------------------------------------------------------------------

VTSetBorder:	VT_FNC	DDFB_SetBorder
		ret

; -----------------------------------------------------------------------------
;                      Set CGA palette (only CGA videomode)
; -----------------------------------------------------------------------------
; INPUT:	AL = palette set (0=red/green/yellow, 1=cyan/magenta/white)
;		EBX = terminal interface
; -----------------------------------------------------------------------------

VTSetPalCGA:	VT_FNC	DDFB_SetPalCGA
		ret

; -----------------------------------------------------------------------------
;                              Set EGA palette
; -----------------------------------------------------------------------------
; INPUT:	AL = start index (0..16, last entry is border color)
;		EBX = terminal interface
;		CL = stop index (0..16)
;		EDX = pointer to EGA palette (palette entry with start index)
; NOTES: EGA palettes are array of 17 bytes: B0 blue 2/3, B1 green 2/3,
;	 B2 red 2/3, B3 blue 1/3, B4 green 1/3, B5 red 1/3. Last palette entry
;	 (index 16) is border color. On VGA card EGA palette is index into
;	 VGA palette table indexed 64 to 127.
; -----------------------------------------------------------------------------

VTSetPalEGA:	VT_FNC	DDFB_SetPalEGA
		ret

; -----------------------------------------------------------------------------
;                              Set VGA palette
; -----------------------------------------------------------------------------
; INPUT:	AL = start index (0..255)
;		EBX = terminal interface
;		CL = stop index (0..255)
;		EDX = pointer to VGA palette (palette entry with start index)
; NOTES: VGA palettes are array of byte triples: red, green and blue color
;	 components with range 0 to 63.
; -----------------------------------------------------------------------------

VTSetPalVGA:	VT_FNC	DDFB_SetPalVGA
		ret

; -----------------------------------------------------------------------------
;                              Set indexed palette
; -----------------------------------------------------------------------------
; INPUT:	EAX = index table (array of bytes with value 0 to 255)
;		EBX = terminal interface
;		ECX = number of color entries (1 to 255)
;		EDX = pointer to VGA palette
; NOTES: VGA palettes are array of byte triples: red, green and blue color
;	 components with range 0 to 63.
; -----------------------------------------------------------------------------

VTSetPalInx:	VT_FNC	DDFB_SetPalInx
		ret

; -----------------------------------------------------------------------------
;                              Fill-up region
; -----------------------------------------------------------------------------
; INPUT:	AL = color (in graphics mode) or character (in text mode)
;		AH = color attribute (only in text mode)
;		EBX = terminal interface
;		ECX = region width
;		EDX = region height
;		ESI = region left margin (in display area)
;		EDI = region top margin (in display area)
; NOTES: Parameters are not checked and can be used to fill-up hide regions.
; -----------------------------------------------------------------------------

VTFillUp:	VT_FNC	DDFB_FillUp
		ret

; -----------------------------------------------------------------------------
;                               Move region
; -----------------------------------------------------------------------------
; INPUT:	EAX = destination offset in videomemory
;		EBX = terminal interface
;		ECX = region width
;		EDX = region height
;		ESI = region left margin (in display area)
;		EDI = region top margin (in display area)
; NOTES: Parameters are not checked and can be used to move in invisible area.
; -----------------------------------------------------------------------------

VTMove:		VT_FNC	DDFB_Move
		ret

; -----------------------------------------------------------------------------
;                               Get buffer size
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
;		ECX = region width
;		EDX = region height
; OUTPUT:	EAX = buffer size
; -----------------------------------------------------------------------------

VTBufferSize:	VT_FNC	DDFB_BufferSize
		ret

; -----------------------------------------------------------------------------
;                                 Get region
; -----------------------------------------------------------------------------
; INPUT:	EAX = destination buffer
;		EBX = terminal interface
;		ECX = region width
;		EDX = region height
;		ESI = region left margin (in display area)
;		EDI = region top margin (in display area)
; NOTES: Parameters are not checked and can be used to get hide regions.
; -----------------------------------------------------------------------------

VTGetRegion:	VT_FNC	DDFB_GetRegion
		ret

; -----------------------------------------------------------------------------
;                                 Set region
; -----------------------------------------------------------------------------
; INPUT:	EAX = source buffer
;		EBX = terminal interface
;		ECX = region width
;		EDX = region height
;		ESI = region left margin (in display area)
;		EDI = region top margin (in display area)
; NOTES: Parameters are not checked and can be used to set hide regions.
; -----------------------------------------------------------------------------

VTSetRegion:	VT_FNC	DDFB_SetRegion
		ret

; -----------------------------------------------------------------------------
;                        Set text region with color
; -----------------------------------------------------------------------------
; INPUT:	EAX = source buffer (only characters without color attributes)
;		EBX = terminal interface
;		ECX = region width
;		EDX = region height
;		ESI = region left margin (in display area)
;		EDI = region top margin (in display area)
;		EBP = color attribute
; NOTES: Parameters are not checked and can be used to set hide regions.
; -----------------------------------------------------------------------------

VTSetRegCol:	VT_FNC	DDFB_SetRegCol
		ret

; -----------------------------------------------------------------------------
;                         Set region with color mask
; -----------------------------------------------------------------------------
; INPUT:	EAX = source buffer
;		EBX = terminal interface
;		ECX = region width
;		EDX = region height
;		ESI = region left margin (in display area)
;		EDI = region top margin (in display area)
;		EBP = transparent color
; NOTES: Parameters are not checked and can be used to set hide regions.
; -----------------------------------------------------------------------------

VTSetColMask:	VT_FNC	DDFB_SetColMask
		ret

; -----------------------------------------------------------------------------
;                            Set region with mask
; -----------------------------------------------------------------------------
; INPUT:	EAX = source buffer with data and bit mask
;		EBX = terminal interface
;		ECX = region width
;		EDX = region height
;		ESI = region left margin (in display area)
;		EDI = region top margin (in display area)
; NOTES: Parameters are not checked and can be used to set hide regions.
;	 Bit mask follow after region data, one bit = 1 if point is visible.
; -----------------------------------------------------------------------------

VTSetMasked:	VT_FNC	DDFB_SetMasked
		ret

; -----------------------------------------------------------------------------
;                            Set region with alpha
; -----------------------------------------------------------------------------
; INPUT:	EAX = source buffer with data and alpha
;		EBX = terminal interface
;		ECX = region width
;		EDX = region height
;		ESI = region left margin (in display area)
;		EDI = region top margin (in display area)
; NOTES: Parameters are not checked and can be used to set hide regions.
;	 Alpha is array of bytes in range 0 (transparent) to 255 (opaque).
; -----------------------------------------------------------------------------

VTSetAlpha:	VT_FNC	DDFB_SetAlpha
		ret

; -----------------------------------------------------------------------------
;                       Write key into keyboard buffer
; -----------------------------------------------------------------------------
; INPUT:	EAX = key code
;		EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Push registers

VTWriteKey:	push	ebx		; push EBX
		push	edx		; push EDX

; ------------- Call old function

		mov	edx,[ebx+VT_WKeyFnc] ; EDX <- function
		mov	ebx,[ebx+VT_WKeyData] ; EBX <- old private data
		call	edx		; write key

; ------------- Pop registers

		pop	edx		; pop EDX
		pop	ebx		; pop EBX
		ret

; -----------------------------------------------------------------------------
;                      Write character into keyboard buffer
; -----------------------------------------------------------------------------
; INPUT:	AL = character
;		EBX = terminal interface
; -----------------------------------------------------------------------------

VTWriteKeyChar:	push	eax		; push EAX
		movzx	eax,al		; EAX <- character to write
		or	eax,VIRTKEY_CHAR ; add character flags
		call	VTWriteKey	; write character
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                           Write respond string
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
;		ECX = string length (ECX > 0)
;		EDX = string address
; -----------------------------------------------------------------------------

; ------------- Push registers

VTRespond:	push	eax		; push EAX
		push	ecx		; push ECX
		push	esi		; push ESI

; ------------- Write text

		mov	esi,edx		; ESI <- string to write
		mov	eax,VIRTKEY_CHAR ; prepare character flags
VTRespond2:	lodsb			; load character
		call	VTWriteKey	; write character
		loop	VTRespond2	; next character

; ------------- Pop registers

		pop	esi		; pop ESI
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                      Write number into keyboard buffer
; -----------------------------------------------------------------------------
; INPUT:	EAX = signed number
;		EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Push registers

VTWriteKeyNum:	push	eax		; push EAX
		push	ecx		; push ECX
		push	edx		; push EDX
		push	esi		; push ESI
		
; ------------- Write negative sign

		or	eax,eax		; is number negative?
		jns	VTWriteKeyNum2	; number is not negative
		push	eax		; push EAX
		mov	al,"-"		; AL <- minus character
		call	VTWriteKeyChar	; write minus character
		pop	eax		; pop EAX
		neg	eax		; EAX <- positive number

; ------------- Divide number into digits

VTWriteKeyNum2:	xor	ecx,ecx		; ECX <- 0, counter
		mov	esi,10		; ESI <- divider
VTWriteKeyNum3:	xor	edx,edx		; EDX <- 0
		div	esi		; divide one digit
		push	edx		; push one digit
		inc	ecx		; increase character counter
		or	eax,eax		; is number zero?
		jnz	VTWriteKeyNum3	; decode next character

; ------------- Write characters to console

VTWriteKeyNum4:	pop	eax		; pop one digit
		add	al,"0"		; convert digit to ASCII character
		call	VTWriteKeyChar	; write one digit
		loop	VTWriteKeyNum4	; write next character

; ------------- Pop registers

		pop	esi		; pop ESI
		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                 Respond start of Escape sequence (CSI character)
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

VTReportCSI:	push	eax		; push EAX
		mov	al,ESC		; AL <- ESC character
		call	VTWriteKeyChar	; write ESC character
		mov	al,"["		; AL <- "[" character
		call	VTWriteKeyChar	; write "[" character
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                       Report string with 1 parameter
; -----------------------------------------------------------------------------
; INPUT:	EAX = parameter
;		EBX = terminal interface
;		DL = terminating character
; -----------------------------------------------------------------------------

; ------------- Write starting escape sequence

VT1Report:	call	VTReportCSI	; respond start of Escape sequence

; ------------- Write parameter

		call	VTWriteKeyNum	; write parameter

; ------------- Write terminating character

VT1Report2:	push	eax		; push EAX
		mov	al,dl		; AL <- terminating character
		call	VTWriteKeyChar	; write terminating character
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                       Report string with 2 parameters
; -----------------------------------------------------------------------------
; INPUT:	EAX = first parameter
;		EBX = terminal interface
;		ECX = second parameter
;		DL = terminating character
; -----------------------------------------------------------------------------

; ------------- Write starting escape sequence

VT2Report:	call	VTReportCSI	; respond start of Escape sequence

; ------------- Write first parameter

		call	VTWriteKeyNum	; write first parameter

; ------------- Write data separator

		push	eax		; push EAX
		mov	al,";"		; AL <- ";" character
		call	VTWriteKeyChar	; write data separator
		pop	eax		; pop EAX

; ------------- Write second parameter

		xchg	eax,ecx		; EAX <- second parameter
		call	VTWriteKeyNum	; write second parameter
		xchg	eax,ecx		; return parameters
		jmp	short VT1Report2 ; write terminating character

; -----------------------------------------------------------------------------
;                         Report current cursor position
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Push registers

VTReportCur:	push	eax		; push EAX
		push 	ecx		; push ECX
		push	edx		; push EDX

; ------------- Report cursor position

		mov	eax,[ebx+VT_PosX] ; EAX <- cursor X
		inc	eax		; EAX <- X starting 1
		mov	ecx,[ebx+VT_PosY] ; ECX <- cursor Y
		inc	ecx		; ECX <- Y starting 1
		test	byte [ebx+VT_Flags],VT_USESCROLL ; use scroll windows?
		jz	VTReportCur2	; no
		add	ecx,[ebx+VT_ScrollT] ; ECX <- add top line of window
VTReportCur2:	mov	dl,"R"		; DL <- terminating character
		call	VT2Report	; report cursor position

; ------------- Pop registers

		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                           Report terminal status
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Push registers

VTReportState:	push	ecx		; push ECX
		push	edx		; push EDX

; ------------- Report state string

		mov	edx,VTRepStrOK ; EDX <- ident string
		mov	ecx,VTRepStrOK2-VTRepStrOK ; ECX <- length
		call	VTRespond	; write response string

; ------------- Pop registers

		pop	edx		; pop EDX
		pop	ecx		; pop ECX	
		ret

; -----------------------------------------------------------------------------
;                             Report ID string
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Push registers

VTReportID:	push	ecx		; push ECX
		push	edx		; push EDX

; ------------- Report ID string

		mov	edx,VTRepStrID ; EDX <- ident string
		mov	ecx,VTRepStrID2-VTRepStrID ; ECX <- length
		call	VTRespond	; write response string

; ------------- Pop registers

		pop	edx		; pop EDX
		pop	ecx		; pop ECX	
		ret

; -----------------------------------------------------------------------------
;                        Temporary turn update OFF
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

VTTempUpdOff:	and	byte [ebx+VT_Flags],~VT_UPDATE ; clear update flag
		ret

; -----------------------------------------------------------------------------
;               Temporary turn update ON if it is updated on
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

VTTempUpdOn:	bts	dword [ebx+VT_Flags],VT_UPDATE_BIT ; test and set flag
		jnc	VTUpdateCur	; flag was off, update cursor
		ret

; -----------------------------------------------------------------------------
;                          Write one character
; -----------------------------------------------------------------------------
; INPUT:	AL = character
;		EBX = terminal interface
; -----------------------------------------------------------------------------

;VTWriteChr:	DCHOUT_FNC DCHOUT_WriteChr
;		ret

; -----------------------------------------------------------------------------
;                             Write text string
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
;		ECX = length
;		EDX = buffer with text string
; -----------------------------------------------------------------------------

;VTEWriteStr:	DCHOUT_FNC DCHOUT_WriteStr
;		ret

; -----------------------------------------------------------------------------
;                       Fill-up region (from cursor position)
; -----------------------------------------------------------------------------
; INPUT:	AL = character
;		EBX = terminal interface
;		ECX = region width
;		EDX = region height
; -----------------------------------------------------------------------------

;VTEFillUp:	DCHOUT_FNC DCHOUT_FillUp
;		ret

; -----------------------------------------------------------------------------
;                       Copy region (into cursor position)
; -----------------------------------------------------------------------------
; INPUT:	EAX = source column
;		EBX = terminal interface
;		ECX = region width
;		EDX = region height
;		ESI = source row
; -----------------------------------------------------------------------------

;VTECopy:	DCHOUT_FNC DCHOUT_Copy
;		ret

; -----------------------------------------------------------------------------
;                          Set cursor position
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
;		ECX = column
;		EDX = row
; -----------------------------------------------------------------------------

;VTESetCur:	DCHOUT_FNC DCHOUT_Cursor
;		ret

; -----------------------------------------------------------------------------
;                          Update color attributes
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Push registers

VTUpdateAttr:	push	eax		; push EAX
		push	ecx		; push ECX

; ------------- Prepare registers (-> CL, AL)

		mov	al,[ebx+VT_Color] ; AL <- current color
		mov	cl,[ebx+VT_Attrib] ; CL <- attribute flags

; ------------- Prepare color for monochromatic mode

		test	byte [ebx+VT_Flags2],VT_MONO ; monochromatic mode?
		jz	VTUpdateAttr1	; color mode
		mov	al,COL_NORMAL	; AL <- 07h, normal color

; ------------- Underline

VTUpdateAttr1:	test	cl,VT_UNDER	; underline?
		jz	VTUpdateAttr2	; no underline
		and	al,0f0h		; mask background color
		or	al,[ebx+VT_UnderColor] ; add underline color

; ------------- Dark

VTUpdateAttr2:	test	cl,VT_DARK	; dark?
		jz	VTUpdateAttr22	; no dark
		and	al,0f0h		; mask background color
		or	al,[ebx+VT_DarkColor] ; add dark color

; ------------- No intenity on 512-character mode

VTUpdateAttr22:	test	byte [ebx+VT_Flags2],VT_512CHAR ; 512-character mode?
		jz	VTUpdateAttr3	; no 512-character mode
		and	al,~COL_FGINT	; clear intensity flag

; ------------- Inverse

VTUpdateAttr3:	test	cl,VT_INVERSE	; should be inverted?
		jz	VTUpdateAttr4	; no inverse
		mov	ch,al		; CH <- color and attributes
		and	ch,88h		; CH <- mask attributes
		mov	ah,0		; AH <- 0
		shl	eax,4		; rotate background color to AH
		or	al,ah		; exchange colors
		and	al,77h		; mask color
		or	al,ch		; add attributes

; ------------- Invisible

VTUpdateAttr4:	test	cl,VT_INVIS	; invisible?
		jz	VTUpdateAttr5	; no invisible
		and	al,70h		; mask background color
		mov	ah,al		; AH <- background color
		shr	ah,4		; rotate color
		or	al,ah		; set background color to foreground
       		jmp	short VTUpdateAttr9

; ------------- Foreground intensity

VTUpdateAttr5:	test	cl,VT_INTENS	; intensity?
		jz	VTUpdateAttr6	; no intensity
		test	byte [ebx+VT_Flags2],VT_512CHAR ; 512-character mode?
		jnz	VTUpdateAttr6	; 512-character mode
		or	al,COL_FGINT	; set intensity flag

; ------------- Background intensity

VTUpdateAttr6:	test	byte [ebx+VT_Flags2],VT_HIGHBG ; high intensity bg?
		jz	VTUpdateAttr7	; no 
		test	cl,VT_BGINTENS	; background intensity?
		jnz	VTUpdateAttr8	; set background intensity
		jmp	short VTUpdateAttr9

; ------------- Blinking

VTUpdateAttr7:	test	cl,VT_BLINK	; blinking?
		jz	VTUpdateAttr9	; no
VTUpdateAttr8:	or	al,COL_BGINT	; set bg intensity or blinking

; ------------- Store new color attribute

VTUpdateAttr9:	mov	[ebx+VT_ColorAttr],al ; store new color with attributes

; ------------- Clearing character

		and	al,~COL_CHAR2	; ckear alternate charset flag
		mov	[ebx+VT_ClearChar+1],al ; clearing character 1
		mov	[ebx+VT_ClearChar+3],al ; clearing character 2

; ------------- Pop registers

		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                            Scroll region up
; -----------------------------------------------------------------------------
; INPUT:	EAX = number of rows to scroll region
;		EBX = terminal interface
;		ECX = top row (first row of region)
;		EDX = bottom row (last row of region + 1)
; -----------------------------------------------------------------------------

; ------------- Push registers

VTScrollUp:	pusha			; push all registers

; ------------- Limit minimal top row (-> ECX)

		or	ecx,ecx		; check minimal top row
		jns	VTScrollUp2	; top row is OK
		xor	ecx,ecx		; ECX <- 0, minimal top row

; ------------- Limit maximal bottom row (-> EDX)

VTScrollUp2:	mov	esi,[ebx+VT_DimH] ; ESI <- display height
		cmp	edx,esi		; check maximal bottom row
		jle	VTScrollUp3	; maximal bottom row is OK
		mov	edx,esi		; EDX <- maximal bottom row

; ------------- Check top (ECX) and bottom (EDX) row overlap

VTScrollUp3:	sub	edx,ecx		; EDX <- height of scrolling region
		jle	VTScrollUp9	; top and bottom rows overlap

; ------------- Limit maximal number of rows (-> EAX)

		cmp	eax,edx		; check number of rows
		jl	VTScrollUp4	; number of rows is OK
		mov	eax,edx		; EAX <- limit number of rows

; ------------- Check minimal bumber of rows (EAX)

VTScrollUp4:	or	eax,eax		; check number of rows
		jle	VTScrollUp9	; invalid number of rows (must be >= 1)

; ------------- Number of rows to scroll (-> EDX)

		sub	edx,eax		; EDX <- number of rows

; ------------- Destination address (-> EDI)

		push	edx		; push EDX (number of rows to scroll)
		push	eax		; push EAX (distance to scroll)

		mov	eax,[ebx+VT_ScanLine] ; EAX <- scan line size
		mov	ebp,eax		; EBP <- push scan line size
		mul	ecx		; recalc top line to offset
		add	eax,[ebx+VT_Addr] ; EAX <- destination address
		xchg	edi,eax		; EDI <- destination address

; ------------- Source address (-> ESI)

		pop	eax		; pop EAX (distance to scroll)
		mul	ebp		; EAX <- shift offset
		lea	esi,[edi+eax]	; ESI <- source address

; ------------- Height of scrolled part (-> ECX)

		xchg	eax,ecx		; ECX <- shift offset
		pop	eax		; EAX <- number of rows to scroll
		mul	ebp		; EAX <- scrolled data size
		shr	eax,1		; EAX <- scrolled data size in words
		xchg	eax,ecx		; ECX <- data size, EAX <- shift offset

; ------------- Move rows

		shr	ecx,1		; ECX <- data size / 4
		rep	movsd		; move rows in DWORDs
		adc	ecx,ecx		; ECX <- odd row
		rep	movsw		; move odd row
		xchg	eax,ecx		; ECX <- shift offset

; ------------- Clear new rows

		mov	eax,[ebx+VT_ClearChar] ; EAX <- clearing character
		shr	ecx,2		; ECX <- data size / 4
		rep	stosd		; clear rows in DWORDs
		adc	ecx,ecx		; ECX <- odd row
		rep	stosw		; clear odd row

; ------------- Pop registers

VTScrollUp9:	popa			; pop all registers
		ret

; -----------------------------------------------------------------------------
;                            Scroll region down
; -----------------------------------------------------------------------------
; INPUT:	EAX = number of rows to scroll region
;		EBX = terminal interface
;		ECX = top row (first row of region)
;		EDX = bottom row (last row of region + 1)
; -----------------------------------------------------------------------------

; ------------- Push registers

VTScrollDown:	pusha			; push all registers

; ------------- Limit minimal top row (-> ECX)

		or	ecx,ecx		; check minimal top row
		jns	VTScrollDown2	; top row is OK
		xor	ecx,ecx		; ECX <- 0, minimal top row

; ------------- Limit maximal bottom row (-> EDX)

VTScrollDown2:	mov	esi,[ebx+VT_DimH] ; ESI <- display height
		cmp	edx,esi		; check maximal bottom row
		jle	VTScrollDown3	; maximal bottom row is OK
		mov	edx,esi		; EDX <- maximal bottom row

; ------------- Check top (ECX) and bottom (EDX) row overlap

VTScrollDown3:	mov	esi,edx		; ESI <- bottom row
		sub	esi,ecx		; ESI <- height of region
		jle	VTScrollDown9	; top and bottom rows overlap

; ------------- Limit maximal number of rows (-> EAX)

		cmp	eax,esi		; check number of rows
		jl	VTScrollDown4	; number of rows is OK
		mov	eax,esi		; EAX <- limit number of rows

; ------------- Check minimal bumber of rows (EAX)

VTScrollDown4:	or	eax,eax		; check number of rows
		jle	VTScrollDown9	; invalid number of rows (must be >= 1)

; ------------- Number of rows to scroll (-> ESI)

		sub	esi,eax		; ESI <- rows to scroll

; ------------- Destination address (-> EDI)

		push	esi		; push ESI (rows to scroll)
		push	eax		; push EAX (distance to scroll)

		mov	eax,[ebx+VT_ScanLine] ; EAX <- scan line size
		mov	ebp,eax		; EBP <- push scan line size
		mul	edx		; recalc bottom row to offset
		add	eax,[ebx+VT_Addr] ; EAX <- destination address
		xchg	edi,eax		; EDI <- destination address
		dec	edi		; EDI -= 1
		dec	edi		; EDI <- last word

; ------------- Source address (-> ESI)

		pop	eax		; pop EAX (distance to scroll)
		mul	ebp		; EAX <- shift offset
		mov	esi,edi		; ESI <- destination address
		sub	esi,eax		; ESI <- source address

; ------------- Height of scrolled part (-> ECX)

		xchg	eax,ecx		; ECX <- shift offset
		pop	eax		; EAX <- number of rows to scroll
		mul	ebp		; EAX <- scrolled data size
		shr	eax,1		; EAX <- scrolled data size in words
		xchg	eax,ecx		; ECX <- data size, EAX <- shift offset

; ------------- Move rows

		std			; set direction down
		rep	movsw		; move rows
		xchg	eax,ecx		; ECX <- shift offset

; ------------- Clear new rows

		mov	eax,[ebx+VT_ClearChar] ; EAX <- clearing character
		shr	ecx,1		; ECX <- data size / 4
		rep	stosw		; clear rows
		cld			; set direction up

; ------------- Pop registers

VTScrollDown9:	popa			; pop all registers
		ret

; -----------------------------------------------------------------------------
;                  Go to relative position (without update cursor)
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
;		ECX = new column
;		EDX = new row
; NOTES:	It limits values to valid ranges.
;		Coordinates can be relative to scrolling region.
; -----------------------------------------------------------------------------

VTGoToXYRel:	test	byte [ebx+VT_Flags],VT_USESCROLL ; use sroll window?
		jz	short VTGoToXY	; don't use scroll window
		push	edx		; push EDX
		add	edx,[ebx+VT_ScrollT] ; EDX <- add scrolling region top
		call	VTGoToXY	; go to position
		pop	edx		; pop EDX
		ret

; -----------------------------------------------------------------------------
;                  Go to absolute position (without update cursor)
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
;		ECX = new column
;		EDX = new row
; NOTES:	It limits values to valid ranges.
; -----------------------------------------------------------------------------

; ------------- Push registers

VTGoToXY:	push	eax		; push EAX
		push	ecx		; push ECX
		push	edx		; push EDX
		push	esi		; push ESI

; ------------- Limit minimal column (-> ECX)

		or	ecx,ecx		; column underflow?
		jns	VTGoToXY2	; no underflow
		xor	ecx,ecx		; ECX <- 0, minimal column

; ------------- Limit maximal column (-> ECX)

VTGoToXY2:	mov	eax,[ebx+VT_DimW] ; display width
		cmp	ecx,eax		; column overflow?
		jl	VTGoToXY3	; no overflow
		xchg	eax,ecx		; ECX <- display width
		dec	ecx		; ECX <- maximal column
VTGoToXY3:	mov	[ebx+VT_PosX],ecx ; set new cursor column

; ------------- Prepare minimal (-> EAX) and maximal (-> ESI) row

		xor	eax,eax		; EAX <- 0, minimal row
		mov	esi,[ebx+VT_DimH] ; ESI <- display height
		test	byte [ebx+VT_Flags],VT_USESCROLL ; use sroll window?
		jz	VTGoToXY4	; don't use scroll window
		mov	eax,[ebx+VT_ScrollT] ; EAX <- scroll top
		mov	esi,[ebx+VT_ScrollB] ; ESI <- scroll bottom

; ------------- Limit minimal row (-> EAX)

VTGoToXY4:	cmp	eax,edx		; row underflow?
		jg	VTGoToXY5	; row underflow (use minimal row)
		xchg	eax,edx		; EAX <- no underflow, use new row

; ------------- Limit maximal row (-> EAX)

VTGoToXY5:	cmp	eax,esi		; row overflow?
		jl	VTGoToXY6	; no overflow
		xchg	eax,esi		; EAX <- display height
		dec	eax		; EAX <- maximal row
VTGoToXY6:	mov	[ebx+VT_PosY],eax ; set new cursor row

; ------------- Calculate new cursor address

		mul	dword [ebx+VT_ScanLine] ; recalc row to offset
		shl	ecx,1		; ECX <- column * 2
		add	eax,ecx		; EAX <- cursor offset
		add	eax,[ebx+VT_Addr] ; EAX <- cursor address
		mov	[ebx+VT_Current],eax ; current cursor address

; ------------- Clear wrap request

		and	byte [ebx+VT_Flags],~VT_NEEDWRAP ; clear wrap request

; ------------- Pop registers

		pop	esi		; pop ESI
		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                           Invert screen region
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
;		ECX = number of characters (it must be greater 0)
;		ESI = videomemory address
; NOTES: It exchanges background and foreground color of characters.
; -----------------------------------------------------------------------------

; ------------- Push registers

VTInvert:	push	eax		; push EAX
		push	ecx		; push ECX
		push 	esi		; push ESI

; ------------- Invert characters

VTInvert2:	lodsw			; load one character
		mov	al,ah		; AL <- color attributes
		and	ax,8877h	; mask colors and attributes
		ror	al,4		; rotate colors
		or	al,ah		; AL <- new colors
		mov	[esi-1],al	; set new colors
		loop	VTInvert2	; next character

; ------------- Pop registers

		pop	esi		; pop ESI
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret		

; -----------------------------------------------------------------------------
;                    Insert characters at cursor position
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
;		ECX = number of characters
; NOTES: It shifts rest of line to the right.
; -----------------------------------------------------------------------------

; ------------- Push registers

VTInsChar:	push	eax		; push EAX
		push	ecx		; push ECX
		push	edx		; push EDX
		push	esi		; push ESI
		push	edi		; push EDI

; ------------- Limit number of characters (-> ECX)

		mov	eax,[ebx+VT_DimW] ; EAX <- display dimension
		sub	eax,[ebx+VT_PosX] ; EAX <- characters to end of line
		mov	edi,eax		; EDI <- characters to end of line
		cmp	eax,ecx		; check number of characters
		jge	VTInsChar2	; number of characters is OK
		xchg	eax,ecx		; ECX <- limit number of characters

; ------------- Check number of characters (ECX)

VTInsChar2:	or	ecx,ecx		; check number of characters
		jle	VTInsChar9	; invalid number of characters

; ------------- Prepare destination address (-> EDI)

		mov	eax,[ebx+VT_PosY] ; EAX <- cursor row
		inc	eax		; EAX <- next row
		mul	dword [ebx+VT_ScanLine] ; recalc row to offset
		add	eax,[ebx+VT_Addr] ; EAX <- address
		dec	eax		; EAX -= 1
		dec	eax		; EAX <- last character
		xchg	eax,edi		; EDI <- destination, EAX <- chars

; ------------- Prepare source address (-> ESI)

		mov	esi,edi		; ESI <- destination address
		sub	esi,ecx		; ESI -= characters to move
		sub	esi,ecx		; ESI <- source address (last char)

; ------------- Move rest of row

		sub	eax,ecx		; EAX <- characters to move
		xchg	eax,ecx		; ECX <- characters, EAX <- offset
		std			; set direction down
		rep	movsw		; shift rest of row

; ------------- Clear new positions

		xchg	eax,ecx		; ECX <- offset
		mov	eax,[ebx+VT_ClearChar] ; EAX <- clearing character
		rep	stosw		; clear new positions
		cld			; set direction up

; ------------- Clear wrap request

VTInsChar9:	and	byte [ebx+VT_Flags],~VT_NEEDWRAP ; clear wrap request

; ------------- Pop registers

		pop	edi		; pop EDI
		pop	esi		; pop ESI
		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                    Delete characters from cursor position
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
;		ECX = number of characters
; NOTES: It shifts rest of line to the left.
; -----------------------------------------------------------------------------

; ------------- Push registers

VTDelChar:	push	eax		; push EAX
		push	ecx		; push ECX
		push	edx		; push EDX
		push	esi		; push ESI
		push	edi		; push EDI

; ------------- Limit number of characters (-> ECX)

		mov	eax,[ebx+VT_DimW] ; EAX <- display dimension
		sub	eax,[ebx+VT_PosX] ; EAX <- characters to end of line
		mov	edi,eax		; EDI <- characters to end of line
		cmp	eax,ecx		; check number of characters
		jge	VTDelChar2	; number of characters is OK
		xchg	eax,ecx		; ECX <- limit number of characters

; ------------- Check number of characters (ECX)

VTDelChar2:	or	ecx,ecx		; check number of characters
		jle	VTDelChar9	; invalid number of characters

; ------------- Prepare destination (-> EDI) and source (-> ESI) address

		mov	edi,[ebx+VT_Current] ; EDI <- current cursor address
		lea	esi,[edi+ecx*2]	; ESI <- source address

; ------------- Move rest of row

		sub	eax,ecx		; EAX <- characters to move
		xchg	eax,ecx		; ECX <- characters, EAX <- offset
		rep	movsw		; shift rest of row

; ------------- Clear new positions

		xchg	eax,ecx		; ECX <- offset
		mov	eax,[ebx+VT_ClearChar] ; EAX <- clearing character
		rep	stosw		; clear new positions

; ------------- Clear wrap request

VTDelChar9:	and	byte [ebx+VT_Flags],~VT_NEEDWRAP ; clear wrap request

; ------------- Pop registers

		pop	edi		; pop EDI
		pop	esi		; pop ESI
		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                   Write BEL character (07h, ^G, without update cursor)
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; NOTES:	It rings a tone.
; -----------------------------------------------------------------------------

VTWriteBEL:	; TODO

		ret

; -----------------------------------------------------------------------------
;                      Clear display or its part ("Esc [ n J" or "CSI n J")
; -----------------------------------------------------------------------------
; INPUT:	AL = parameter
;			0 = from cursor to end of display (inclusive)
;			1 = from start of display to cursor (inclusive)
;			2 = entire display
;		EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Push registers

VTClearDisp:	push	eax		; push EAX
		push	ecx		; push ECX
		push	edx		; push EDX
		push 	edi		; push EDI

; ------------- Prepare to erase from cursor to end of display

		mov	edi,[ebx+VT_Current] ; EDI <- cursor address
		mov	ecx,[ebx+VT_EndAddr] ; ECX <- end address of display
		sub	ecx,edi		; ECX <- offset from cursor
		mov	edx,ecx		; EDX <- size of rest of screen
		or	al,al		; erase from cursor to end of display?
		jz	VTClearDisp2	; yes

; ------------- Prepare to erase from start of display to cursor (inclusive)

		mov	ecx,edi		; EDI <- cursor address
		mov	edi,[ebx+VT_Addr] ; EDI <- videomemory address
		sub	ecx,edi		; ECX <- offset to cursor
		inc	ecx		; inclusive cursor position
		inc	ecx		; inclusive cursor position
		cmp	al,1		; erase from start to cursor?
		je	VTClearDisp2	; yes

; ------------- Prepare to erase entire display

		cmp	al,2		; erase whole screen?
		jne	VTClearDisp9	; no, invalid parameter
		dec	ecx		; ECX <- return cursor offset
		dec	ecx		; ECX <- return cursor offset
		add	ecx,edx		; ECX <- size of whole screen

; ------------- Erase display

VTClearDisp2:	mov	eax,[ebx+VT_ClearChar] ; EAX <- clearing character
		shr	ecx,2		; ECX <- data size / 4
		rep	stosd		; clear rows in DWORDs
		adc	ecx,ecx		; ECX <- odd row
		rep	stosw		; clear odd row

; ------------- Clear wrap request

		and	byte [ebx+VT_Flags],~VT_NEEDWRAP ; clear wrap request

; ------------- Pop registers

VTClearDisp9:	pop	edi		; pop EDI
		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                      Clear row or its part ("Esc [ n K" or "CSI n K")
; -----------------------------------------------------------------------------
; INPUT:	AL = parameter
;			0 = from cursor to end of line (inclusive)
;			1 = from start of line to cursor (inclusive)
;			2 = entire line
;		EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Push registers

VTClearRow:	push	eax		; push EAX
		push	ecx		; push ECX
		push 	edi		; push EDI

; ------------- Prepare to erase from cursor to end of line

		mov	edi,[ebx+VT_Current] ; EDI <- cursor address
		mov	ecx,[ebx+VT_DimW] ; ECX <- display width
		sub	ecx,[ebx+VT_PosX] ; ECX <- remaining characters
		or	al,al		; erase from cursor to end of line?
		jz	VTClearRow2	; yes

; ------------- Prepare to erase from start of line to cursor (inclusive)

		mov	ecx,[ebx+VT_PosX] ; ECX <- cursor column
		sub	edi,ecx		; EDI -= cursor column
		sub	edi,ecx		; EDI <- start address of line
		inc	ecx		; inclusive cursor position
		cmp	al,1		; erase from start to cursor?
		je	VTClearRow2	; yes

; ------------- Prepare to erase entire line

		cmp	al,2		; erase whole screen?
		jne	VTClearRow9	; no, invalid parameter
		mov	ecx,[ebx+VT_DimW] ; ECX <- display width

; ------------- Erase line

VTClearRow2:	mov	eax,[ebx+VT_ClearChar] ; EAX <- clearing character
		rep	stosw		; clear odd row

; ------------- Clear wrap request

		and	byte [ebx+VT_Flags],~VT_NEEDWRAP ; clear wrap request

; ------------- Pop registers

VTClearRow9:	pop	edi		; pop EDI
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;            Clear characters from cursor ("Esc [ n X" or "CSI n X")
; -----------------------------------------------------------------------------
; INPUT:	EAX = number of characters (limited to end of line)
;		EBX = terminal interface
; NOTES: This escape sequence is not defined in VT100 terminal.
; -----------------------------------------------------------------------------

; ------------- Push registers

VTClearChar:	push	eax		; push EAX
		push	ecx		; push ECX
		push 	edi		; push EDI

; ------------- Limit minimal number of characters (-> EAX)

		or	eax,eax		; check minimal number of characters
		jg	VTClearChar2	; number of characters is OK
		xor	eax,eax		; EAX <- 0
		inc	eax		; EAX <- 1, minimal number of chars

; ------------- Limit maximal number of characters (-> ECX)

VTClearChar2:	mov	ecx,[ebx+VT_DimW] ; ECX <- display width
		sub	ecx,[ebx+VT_PosX] ; ECX <- remaining characters
		cmp	eax,ecx		; check number of characters
		jg	VTClearChar4	; limit number of characters
		xchg	eax,ecx		; ECX <- requested number of characters

; ------------- Erase characters

VTClearChar4:	mov	eax,[ebx+VT_ClearChar] ; EAX <- clearing character
		mov	edi,[ebx+VT_Current] ; EDI <- cursor address
		rep	stosw		; clear odd row

; ------------- Clear wrap request

		and	byte [ebx+VT_Flags],~VT_NEEDWRAP ; clear wrap request

; ------------- Pop registers

		pop	edi		; pop EDI
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                       Set default color attributes
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

VTSetDefCol:	push	eax		; push EAX
		and	byte [ebx+VT_Attrib],~VT_ATTRMASK ; clear attributes
		mov	al,[ebx+VT_DefColor] ; AL <- default color
		mov	[ebx+VT_Color],al ; set color to default
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;            Set color attributes ("Esc [ n m" or "CSI n m")
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; NOTES: This escape sequence takes one or more parameters.
; -----------------------------------------------------------------------------

; ------------- Push registers

VT1WEscGotm:
VTSetAttr:	push	eax		; push EAX
		push	ecx		; push ECX
		push	edx		; push EDX
		push	esi		; push ESI

; ------------- Prepare parameters

		lea	esi,[ebx+VT_Param] ; ESI <- parameters
		movzx	ecx,byte [ebx+VT_ParNum] ; ECX <- number of parameters
		cmp	ecx,byte VT_PARAMS ; all parameters?
		je	VTSetAttr2	; all parameters are entered
		inc	ecx		; include last parameter		

; ------------- Jump to parameter service

VTSetAttr2:	lodsd			; EAX <- load parameter
		cmp	eax,byte 107	; check maximal parameter
		ja	VTSetAttr8	; invalid parameter
		call	[VTSetAttrTab+eax*4] ; jump to service
VTSetAttr8:	loop	VTSetAttr2	; next parameter
		call	VTUpdateAttr	; update color attributes

; ------------- Pop registers

VTSetAttr9:	pop	esi		; pop ESI
		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
VTSetAttrT:	ret

; ------------- 1: set bold intensity ON

VTSetAttrT1:	or	byte [ebx+VT_Attrib],VT_INTENS ; set intensity ON
		and	byte [ebx+VT_Attrib],~VT_DARK ; set dark OFF
		ret

; ------------- 2: set dark intensity ON

VTSetAttrT2:	or	byte [ebx+VT_Attrib],VT_DARK ; set dark ON
		and	byte [ebx+VT_Attrib],~VT_INTENS ; set intensity OFF
		ret

; ------------- 3: set italic ON (unsupported)

; ------------- 4: set underline ON

VTSetAttrT4:	or	byte [ebx+VT_Attrib],VT_UNDER ; set underline ON
		ret

; ------------- 5: set blinking slow ON, 6: set blinking rapid ON

VTSetAttrT5:
VTSetAttrT6:	or	byte [ebx+VT_Attrib],VT_BLINK ; set blinking ON
		ret

; ------------- 7: set inverse ON

VTSetAttrT7:	or	byte [ebx+VT_Attrib],VT_INVERSE ; set inverse ON
		ret

; ------------- 8: set invisible ON

VTSetAttrT8:	or	byte [ebx+VT_Attrib],VT_INVIS ; set invisible ON
		ret

; ------------- 9: set strikethrough ON (unsupported)

; ------------- 10: select primary character set

VTSetAttrT10:	call	VTUpdTrans	; set current character set
		and	byte [ebx+VT_Flags],~(VT_CTRL+VT_ALTCHAR) ; reset flags
		ret				

; ------------- 11: select first alternate character set

VTSetAttrT11:	and	byte [ebx+VT_Flags],~VT_ALTCHAR ; reset alternate chars
VTSetAttrT112:	mov	dword [ebx+VT_CharSet],CharSet437 ; character set IBM
		or	byte [ebx+VT_Flags],VT_CTRL ; display CTRL characters
		ret				

; ------------- 12: select second alternate character set

VTSetAttrT12:	or	byte [ebx+VT_Flags],VT_ALTCHAR ; set alternate chars
		jmp	short VTSetAttrT112

; ------------- 13..19: select third..ninth alternate char. set (unsupported)

; ------------- 20: select gothic character set (unsupported)

; ------------- 21, 22: set bold/dark intensity OFF

VTSetAttrT21:
VTSetAttrT22:	and	byte [ebx+VT_Attrib],~(VT_INTENS+VT_DARK) ; normal int.
		ret

; ------------- 23: set italic OFF (unsupported)

; ------------- 24: set underline OFF

VTSetAttrT24:	and	byte [ebx+VT_Attrib],~VT_UNDER ; set underline OFF
		ret

; ------------- 25: set blinking OFF

VTSetAttrT25:	and	byte [ebx+VT_Attrib],~VT_BLINK ; set blinking OFF
		ret

; ------------- 26: proporcional ON (unsupported)

; ------------- 27: set inverse OFF

VTSetAttrT27:	and	byte [ebx+VT_Attrib],~VT_INVERSE ; set inverse OFF
		ret

; ------------- 28: set invisible OFF

VTSetAttrT28:	and	byte [ebx+VT_Attrib],~VT_INVIS ; set invisible OFF
		ret

; ------------- 29: set strikethrough OFF (unsupported)

; ------------- 30..37: set foreground color

VTSetAttrT30:	mov	al,[VTSetAttrColTab + eax - 30] ; AL <- color
VTSetAttrT302:	and	byte [ebx+VT_Color],0f0h ; clear foreground
		or	[ebx+VT_Color],al ; set foreground color
		ret

; ------------- 40..47: set background color

VTSetAttrT40:	mov	al,[VTSetAttrColTab + eax - 40] ; AL <- color
VTSetAttrT401:	shl	al,4		; AL <- rotate color
VTSetAttrT402:	and	byte [ebx+VT_Color],0fh ; clear background
		or	[ebx+VT_Color],al ; set background color
		ret

; ------------- 38: underline ON, use default foreground

VTSetAttrT38:	or	byte [ebx+VT_Attrib],VT_UNDER ; set underline ON
VTSetAttrT382:	mov	al,[ebx+VT_DefColor] ; AL <- default color
		and	al,0fh		; AL <- mask foreground color
		jmp	short VTSetAttrT302 ; set color

; ------------- 39: underline OFF, use default foreground

VTSetAttrT39:	and	byte [ebx+VT_Attrib],~VT_UNDER ; set underline OFF
		jmp	short VTSetAttrT38

; ------------- 48: reserved

; ------------- 49: use default background

VTSetAttrT49:	mov	al,[ebx+VT_DefColor] ; AL <- default color
		and	al,0f0h		; AL <- mask background color
		jmp	short VTSetAttrT402

; ------------- 50: proporcional OFF (unsupported)

; ------------- 51: framed ON (unsupported)

; ------------- 52: encircled ON (unsupported)

; ------------- 53: overlined ON (unsupported)

; ------------- 54: framed and encircled OFF (unsupported)

; ------------- 55: overlined OFF (unsupported)

; ------------- 56..59: reserved

; ------------- 60..64: ideogram (unsupported)

; ------------- 65..89: reserved

; ------------- 90..97: set foreground color bright

VTSetAttrT90:	or	byte [ebx+VT_Attrib],VT_INTENS ; set intensity ON
		mov	al,[VTSetAttrColTab + eax - 90] ; AL <- color
		jmp	short VTSetAttrT302

; ------------- 98..99: reserved

; ------------- 100..107: set background color bright

VTSetAttrT100:	or	byte [ebx+VT_Attrib],VT_BGINTENS ; set bg intensity ON
		mov	al,[VTSetAttrColTab + eax - 100] ; AL <- color
		jmp	short VTSetAttrT401

; -----------------------------------------------------------------------------
;                   Write TAB character (without update cursor)
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; NOTES:	It moves cursor to next tab stop.
; -----------------------------------------------------------------------------

; ------------- Push registers

VTWriteTAB:	push	eax		; push EAX
		push	ecx		; push ECX
		push	edx		; push EDX
		
; ------------- Prepare right margin (-> ECX)

		mov	ecx,[ebx+VT_DimW] ; ECX <- display width
		dec	ecx		; ECX <- last column
		xor	eax,eax		; EAX <- 0
		mov	al,VT_TABS-1	; EAX <- max. tab stop
		cmp	ecx,eax		; check max. tab stop
		jbe	short VTWriteTAB2 ; display width is OK
		xchg	eax,ecx		; ECX <- limit display width

; ------------- Prepare cursor position (-> EAX, EDX)

VTWriteTAB2:	mov	eax,[ebx+VT_PosX] ; EAX <- cursor position
		mov	edx,[ebx+VT_Current] ; EDX <- cursor address

; ------------- Find next tab stop

VTWriteTAB6:	cmp	eax,ecx		; is it right margin?
		jae	short VTWriteTAB8 ; it is right margin
		inc	eax		; increase cursor position
		inc	edx		; increase cursor address
		inc	edx		; increase cursor address
		bt	dword [ebx+VT_Tabs],eax ; test tab position
		jnc	short VTWriteTAB6 ; continue search tab stop

; ------------- Store new cursor position

VTWriteTAB8:	mov	[ebx+VT_PosX],eax ; store new cursor position
		mov	[ebx+VT_Current],edx ; store new cursor address

; ------------- Pop registers

		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                                Set tab stop
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

VTTabSet:	push	eax		; push EAX
		mov	eax,[ebx+VT_PosX] ; EAX <- cursor position
		cmp	eax,VT_TABS	; is position valid?
		jae	VTTabSet2	; position is not valid
		bts	dword [ebx+VT_Tabs],eax ; set tab stop
VTTabSet2:	pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                               Reset tab stop
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

VTTabRes:	push	eax		; push EAX
		mov	eax,[ebx+VT_PosX] ; EAX <- cursor position
		cmp	eax,VT_TABS	; is position valid?
		jae	VTTabRes2	; position is not valid
		btr	dword [ebx+VT_Tabs],eax ; reset tab stop
VTTabRes2:	pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                            Default tab stops
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Push registers

VTTabDef:	push	eax		; push EAX
		mov	eax,01010101h	; tab stop each 8 characters
VTTabDef2:	push	ecx		; push ECX
		push	edi		; push EDI

; ------------- Initialize/clear tab stops (after 8 positions)

		mov	ecx,VT_TABS/32	; EAX <- number of DWORDS
		lea	edi,[ebx+VT_Tabs] ; EDI <- tab stops
		rep	stosd		; initialize tab stops

; ------------- Pop registers

		pop	edi		; pop EDI
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                            Clear all tab stops
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Push registers

VTTabClear:	push	eax		; push EAX
		xor	eax,eax		; EAX <- 0
		jmp	short VTTabDef2

; -----------------------------------------------------------------------------
;                    Move cursor left (without update cursor)
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Push registers

VTLeft:		push	eax		; push EAX

; ------------- Check if it is already left margin

		mov	eax,[ebx+VT_PosX] ; EAX <- cursor position
		or	eax,eax		; is it left margin?
		jz	VTLeft2		; it is left margin

; ------------- Decrease position

		dec	eax		; decrease position
		mov	[ebx+VT_PosX],eax ; store new position
		sub	dword [ebx+VT_Current],byte 2 ; decrease cursor address
		and	byte [ebx+VT_Flags],~VT_NEEDWRAP ; clear wrap request

; ------------- Pop registers

VTLeft2:	pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                   Move cursor up (without update cursor)
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; NOTES:	It moves cursor up by one row and possibly scrolls region down.
; -----------------------------------------------------------------------------

; ------------- Push registers

VTUp:		push	eax		; push EAX
		push	ecx		; push ECX

; ------------- Check if it is top scrolling row

		mov	eax,[ebx+VT_PosY] ; EAX <- cursor row
		mov	ecx,[ebx+VT_ScrollT] ; ECX <- top scrolling row
		cmp	eax,ecx		; is it top scrolling row?
		jne	VTUp2		; it is not top scroll

; ------------- Scroll scrolling region down by one row

		push	edx		; push EDX
		xor	eax,eax		; EAX <- 0
		inc	eax		; EAX <- 1, number of rows to scroll
		mov	edx,[ebx+VT_ScrollB] ; EDX <- bottom scrolling row
		call	VTScrollDown	; scroll region down by one row
		pop	edx		; pop EDX
		jmp	short VTUp8	; row stays unchanged

; ------------- Store new row

VTUp2:		dec	eax		; decrease row
		jl	VTUp8		; invalid row
		mov	[ebx+VT_PosY],eax ; store new cursor row
		mov	eax,[ebx+VT_ScanLine] ; EAX <- bytes per row
		sub	[ebx+VT_Current],eax ; correct cursor address
VTUp8:		and	byte [ebx+VT_Flags],~VT_NEEDWRAP ; clear wrap request

; ------------- Pop registers

		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                       Write LF character with auto CR
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; NOTES:	It moves cursor one row down and possibly scrolls region up.
; -----------------------------------------------------------------------------

VTWriteLFAuto:	test	byte [ebx+VT_Flags],VT_AUTOCR ; auto CR after LF?
		jz	short VTDown	; only move cursor down
		call	VTWriteCR	; write CR character

; VTDown must follow

; -----------------------------------------------------------------------------
;                   Move cursor down (without update cursor)
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; NOTES:	It moves cursor down by one row and possibly scrolls region up.
; -----------------------------------------------------------------------------

; ------------- Push registers

VTDown:		push	eax		; push EAX
		push	edx		; push EDX

; ------------- Increase row

		mov	eax,[ebx+VT_PosY] ; EAX <- cursor row
		inc	eax		; increase row

; ------------- Check if it is bottom scrolling row

		mov	edx,[ebx+VT_ScrollB] ; EDX <- bottom scrolling row
		cmp	eax,edx		; is it bottom scrolling row?
		jne	VTDown2		; it is not bottom scroll

; ------------- Scroll scrolling region up by one row

		push	ecx		; push ECX
		xor	eax,eax		; EAX <- 0
		inc	eax		; EAX <- 1, number of rows to scroll
		mov	ecx,[ebx+VT_ScrollT] ; ECX <- top scrolling row
		call	VTScrollUp	; scroll region up by one row
		pop	ecx		; pop ECX
		jmp	short VTDown8	; row stays unchanged

; ------------- Store new row

VTDown2:	cmp	eax,[ebx+VT_DimH] ; is this row valid?
		jae	VTDown8		; row is not valid		
		mov	[ebx+VT_PosY],eax ; store new cursor row
		mov	eax,[ebx+VT_ScanLine] ; EAX <- bytes per row
		add	[ebx+VT_Current],eax ; correct cursor address
VTDown8:	and	byte [ebx+VT_Flags],~VT_NEEDWRAP ; clear wrap request

; ------------- Pop registers

		pop	edx		; pop EDX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;               Write CR and LF characters (without update cursor)
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

VTWriteCRLF:	call	VTWriteCR	; write CR character
		jmp	short VTDown	; move cursor down

; -----------------------------------------------------------------------------
;             Write CR character (0Dh, ^M, without update cursor)
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; NOTES:	It moves cursor to left margin.
; -----------------------------------------------------------------------------

VTWriteCR:	push	eax		; push EAX
		xor	eax,eax		; EAX <- 0
		xchg	eax,[ebx+VT_PosX] ; EAX <- cursor column, X <- 0
		shl	eax,1		; EAX <- cursor X * 2
		sub	[ebx+VT_Current],eax ; correct cursor address
		and	byte [ebx+VT_Flags],~VT_NEEDWRAP ; clear wrap request
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                              Set NumLock ON
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

VTNumLockOn:

	; TODO
		ret

; -----------------------------------------------------------------------------
;                              Set NumLock OFF
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

VTNumLockOff:

	; TODO
		ret

; -----------------------------------------------------------------------------
;                           Clear parameters
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Push registers

VTClearPar:	push	eax		; push EAX
		push	ecx		; push ECX
		push	edi		; push EDI

; ------------- Clear parameters

		xor	eax,eax		; EAX <- 0
		xor	ecx,ecx		; ECX <- 0
		mov	cl,VT_PARAMS	; ECX <- number of paramters
		lea	edi,[ebx+VT_Param] ; EDI <- parameters
		rep	stosd		; clear parameters
		mov	[ebx+VT_ParNum],al ; set number of parameters to 0

; ------------- Pop registers

		pop	edi		; pop EDI
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                        Prepare standard palettes
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Push registers

VTInitPalette:	push	eax		; push EAX
		push	ecx		; push ECX
		push	edx		; push EDX
		push	esi		; push ESI
		push	edi		; push EDI

; ------------- Prepare palette table (-> EDX)

		mov	edx,EGAStdPal	; EDX <- standard palettes 16 colors
		test	byte [ebx+VT_Flags2],VT_512CHAR ; use 512-char display?
		jz	VTInitPalette2	; use 256-char display
		mov	edx,EGA8Pal	; EDX <- palettes 8 colors

; ------------- Copy standard palettes

VTInitPalette2:	lea	edi,[ebx+VT_Palettes] ; EDI <- palette table
		xor	ecx,ecx		; ECX <- 0
		mov	cl,16		; ECX <- number of palettes
VTInitPalette4:	movzx	eax,byte [edx]	; EAX <- palette index
		inc	edx		; increase EGA palette pointer
		lea	esi,[VGAStdPal+eax*2]
		add	esi,eax		; ESI <- palette address
		movsw			; copy red and green component
		movsb			; copy blue component
		loop	VTInitPalette4	; copy next color

; ------------- Pop registers

		pop	edi		; pop EDI
		pop	esi		; pop ESI
		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                            Set terminal palette
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Push registers

VTSetPalette:	push	eax		; push EAX
		push	ecx		; push ECX
		push	edx		; push EDX

; ------------- Set EGA palettes

		mov	al,0		; AL <- 0, start index
		mov	cl,16		; CL <- 16, stop index
		mov	edx,EGAStdPal	; EDX <- standard palettes 16 colors
		test	byte [ebx+VT_Flags2],VT_512CHAR ; use 512-char display?
		jz	VTSetPalette2	; use 256-char display
		mov	edx,EGA8Pal	; EDX <- palettes 8 colors
VTSetPalette2:	call	VTSetPalEGA	; set EGA palettes

; ------------- Set VGA palettes

		mov	eax,EGAStdPal	; EAX <- EGA standard palettes
		xor	ecx,ecx		; ECX <- 0
		mov	cl,16		; ECX <- 16, number of palettes
		lea	edx,[ebx+VT_Palettes] ; EDX <- palettes
		call	VTSetPalInx	; set indexed palettes

; ------------- Pop registers

		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret
	
; -----------------------------------------------------------------------------
;               Escape sequence - set color palette ("ESC ] P xxxxxxx")
; -----------------------------------------------------------------------------
; INPUT:	AL = character
;		EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Push registers

VT1WEscPal:	push	eax		; push EAX
		push	edx		; push EDX

; ------------- Convert character to BIN value

		call	CharHexToBin	; convert character to BIN value
		jc	VT1WEscPal6	; invalid character

; ------------- Store one character into parameter table

		movzx	edx,byte [ebx+VT_ParNum] ; EDX <- number of parameters
		mov	byte [ebx+VT_Param+edx+3],al ; store parameter
		inc	edx		; increase number of parameters
		mov	[ebx+VT_ParNum],dl ; store new number of parameters
		cmp	dl,7		; check number of parameters
		jne	VT1WEscPal8	; not last parameter

; ------------- Push registes 2

		push	ecx		; push ECX

; ------------- Prepare palette address (-> EDX)

		movzx	eax,byte [ebx+VT_Param+3] ; EAX <- palette index
		movzx	eax,byte [VTSetAttrColTab+eax] ; EAX <- remap color
		test	byte [ebx+VT_Flags2],VT_512CHAR ; use 512-char display?
		jz	VT1WEscPal2	; use 256-char display
		and	al,7		; mask to low 
VT1WEscPal2:	mov	ecx,eax		; ECX <- palette index
		lea	edx,[ebx+VT_Palettes+eax*2] ; EDX <- palette addres
		add	edx,eax		; EDX <- palette address

; ------------- Get red component
				
		mov	eax,[ebx+VT_Param+4] ; AL <- red high, AH <- red low
		shl	al,4		; AL <- rotate HIGH to position
		or	al,ah		; AL <- packed red component
		shr	al,2		; AL <- range 0 to 63
		mov	[edx],al	; store red component

; ------------- Get green component

		shr	eax,16		; AL <- green high, AH <- green low
		shl	al,4		; AL <- rotate HIGH to position
		or	al,ah		; AL <- packed green component
		shr	al,2		; AL <- range 0 to 63
		mov	[edx+1],al	; store green component

; ------------- Get blue component

		mov	ax,[ebx+VT_Param+4+4] ; AL <- blue high, AH <- blue low
		shl	al,4		; AL <- rotate HIGH to position
		or	al,ah		; AL <- packed blue component
		shr	al,2		; AL <- range 0 to 63
		mov	[edx+2],al	; store blue component

; ------------- Copy palette to high color

		test	byte [ebx+VT_Flags2],VT_512CHAR ; use 512-char display?
		jz	VT1WEscPal3	; use 256-char display
		mov	[edx+2+8*3],al	; set blue high
		mov	ax,[edx]	; AX <- red and green
		mov	[edx+8*3],ax	; set red and green high

; ------------- Set palette

VT1WEscPal3:	mov	al,[EGAStdPal+ecx] ; AL <- palette index
		test	byte [ebx+VT_Flags2],VT_512CHAR ; use 512-char display?
		jz	VT1WEscPal4	; use 256-char display
		mov	al,[EGA8Pal+ecx] ; AL <- palette index
VT1WEscPal4:	mov	cl,al		; CL <- stop index
		call	VTSetPalVGA	; set palette

; ------------- Pop registers 2

		pop	ecx		; pop ECX

; ------------- Reset escape mode

VT1WEscPal6:	VTESC_NORM		; reset escape mode

; ------------- Pop registers

VT1WEscPal8:	pop	edx		; pop EDX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                    Escape sequence - set terminal command
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; NOTES: It uses first parameter.
; -----------------------------------------------------------------------------

; ------------- Push registers

VT1WEscGotSBR:
VT1WSetTerm:	push	eax		; push EAX

; ------------- Jump to parameter service

		mov	eax,[ebx+VT_Param] ; EAX <- first parameter
		cmp	eax,byte 15	; check maximal parameter
		ja	VT1WSetTermRet	; invalid parameter
		call	[VTSetTermTab+eax*4] ; jump to service

; ------------- Pop registers

VT1WSetTermRet:	pop	eax		; pop EAX
		ret

; ------------- 1: set color for underline mode

VT1WSetTerm1:	test	byte [ebx+VT_Flags2],VT_MONO ; monochromatic mode?
		jnz	VT1WSetTerm0	; monochromatic mode
		mov	eax,[ebx+VT_Param+4] ; EAX <- second parameter
		cmp	eax,byte 16	; check valid parameter
		jae	VT1WSetTerm0	; invalid parameter
		mov	al,[VTSetAttrColTab+eax] ; AL <- color
		mov	[ebx+VT_UnderColor],al ; set underline color
		test	byte [ebx+VT_Attrib],VT_UNDER ; use underline color?
		jz	VT1WSetTerm0	; don't use underline color
VT1WSetTerm02:	call	VTUpdateAttr	; update color attributes
VT1WSetTerm0:	ret

; ------------- 2: set color for half intensity mode

VT1WSetTerm2:	test	byte [ebx+VT_Flags2],VT_MONO ; monochromatic mode?
		jnz	VT1WSetTerm0	; monochromatic mode
		mov	eax,[ebx+VT_Param+4] ; EAX <- second parameter
		cmp	eax,byte 16	; check valid parameter
		jae	VT1WSetTerm0	; invalid parameter
		mov	al,[VTSetAttrColTab+eax] ; AL <- color
		mov	[ebx+VT_DarkColor],al ; set dark color
		test	byte [ebx+VT_Attrib],VT_DARK ; use dark color?
		jz	VT1WSetTerm0	; don't use dark color
		jmp	short VT1WSetTerm02 ; update color attributes

; ------------- 8: store color as default

VT1WSetTerm8:	mov	al,[ebx+VT_Color] ; AL <- current color
		mov	[ebx+VT_DefColor],al ; store default color
		call	VTSetDefCol	; set default color
		jmp	short VT1WSetTerm02 ; update color attributes

; ------------- 9: set blanking interval

VT1WSetTerm9:
		; TODO
		ret

; ------------- 10: set bell frequency in Hz

VT1WSetTerm10:
		; TODO
		ret

; ------------- 11: set bell duration in ms

VT1WSetTerm11:
		; TODO
		ret

; ------------- 12: bring specified console to the front

VT1WSetTerm12:
		; TODO
		ret

; ------------- 13: unblank the screen

VT1WSetTerm13:
		; TODO
		ret

; ------------- 14: set VESA powerdown interval

VT1WSetTerm14:
		; TODO
		ret

; ------------- 15: activate previous console

VT1WSetTerm15:
		; TODO
		ret

; -----------------------------------------------------------------------------
;                    Escape sequence - set terminal modes
; -----------------------------------------------------------------------------
; INPUT:	AL = new state of parameters (TRUE or FALSE)
;		EBX = terminal interface
; NOTES: It goes through all parameters and sets/resets their states.
; -----------------------------------------------------------------------------

; ------------- Push registers

VT1WSetMode:	push	eax		; push EAX
		push	ecx		; push ECX
		push	esi		; push ESI
		push	ebp		; push EBP

; ------------- Prepare parameters

		movzx	ebp,al		; EBP <- required state of parameter
		lea	esi,[ebx+VT_Param] ; EDX <- parameters
		movzx	ecx,byte [ebx+VT_ParNum] ; ECX <- number of parameters
		jecxz	VT1WSetMode9	; no parameter

; ------------- Get one parameter

VT1WSetMode2:	lodsd			; EAX <- read parameter
		cmp	eax,byte 100	; check maximal parameter
		ja	VT1WSetMode8	; invalid parameter

; ------------- 1: set keyboard

		cmp	al,1
		jne	VT1WSetMode21
		; TODO

; ------------- 3: set 80/132 mode

VT1WSetMode21:	
		; TODO

; ------------- Get next parameter

VT1WSetMode8:	loop	VT1WSetMode2	; next parameter

; ------------- Pop registers

VT1WSetMode9:	pop	ebp		; pop EBP
		pop	esi		; pop ESI
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret
; -----------------------------------------------------------------------------
;                         Write character (not control code)
; -----------------------------------------------------------------------------
; INPUT:	AL = character to write
;		EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Push registers

VT1WEscNorm:
VT1WriteCh:	push	eax		; push EAX
		push	ecx		; push ECX
		push	edx		; push EDX
		push	edi		; push EDI

; ------------- Prepare UTF character

		movzx	eax,al		; EAX <- character
		test	byte [ebx+VT_Flags2],VT_USEUTF ; use UTF?
		jz	VT1WriteCh6	; don't use UTF

; ------------- Check if it is valid ASCII character

		cmp	al,80h		; is it valid ASCII character?
		jae	VT1WriteCh2	; it is not ASCII character
		cmp	byte [ebx+VT_UtfNum],0 ; is it first UTF character?
		je	VT1WriteCh8	; it is valid ASCII character
		jmp	VT1WriteCh7	; invalid character

; ------------- Check if it is first UTF character	

VT1WriteCh2:	cmp	byte [ebx+VT_UtfNum],0 ; is it first UTF character?
		jne	VT1WriteCh4	; it is not first UTF character

; ------------- Check validity of first byte

		cmp	al,0c0h		; minimal value
		jb	VT1WriteCh7	; invalid character
		cmp	al,0feh		; detection character
		jae	VT1WriteCh9	; ignore detection byte

; ------------- Start receiving UTF character

		xor	ecx,ecx		; ECX <- 0
		mov	ch,al		; CH <- first UTF data bits

		inc	ecx		; CL <- 1 character remain
		and	ch,1fh		; 5 bits
		cmp	al,0e0h		; 2 byte code
		jb	VT1WriteCh3	; 2 bytes

		inc	ecx		; CL <- 2 characters remain
		and	ch,0fh		; 4 bits
		cmp	al,0f0h		; 3 byte code
		jb	VT1WriteCh3	; 3 bytes

		inc	ecx		; CL <- 3 characters remain
		and	ch,7		; 3 bits
		cmp	al,0f8h		; 4 byte code
		jb	VT1WriteCh3	; 4 bytes

		inc	ecx		; CL <- 4 characters remain
		and	ch,3		; 2 bits
		cmp	al,0fch		; 5 byte code
		jb	VT1WriteCh3	; 5 bytes

		inc	ecx		; CL <- 5 characters remain
		and	ch,1		; 1 bit

VT1WriteCh3:	mov	[ebx+VT_UtfNum],cl ; number of UTF characters
		movzx	ecx,ch		; ECX <- first bits
		mov	[ebx+VT_UtfChar],ecx ; UTF character accumulator
		jmp	short VT1WriteCh9

; ------------- Receive next UTF character

VT1WriteCh4:	cmp	al,0c0h		; check valid value
		jae	VT1WriteCh7	; invalid character
		shl	dword [ebx+VT_UtfChar],6 ; rotate accumulator
		and	al,3fh		; mask valid bits
		or	[ebx+VT_UtfChar],al ; add bits to accumulator
		dec	byte [ebx+VT_UtfNum] ; decrease UTF counter
		jnz	VT1WriteCh9	; not all characters
		mov	eax,[ebx+VT_UtfChar] ; EAX <- Unicode character
		jmp	short VT1WriteCh66 ; decode Unicode character

; ------------- Convert character to Unicode

VT1WriteCh6:	cmp	al,80h		; ASCII character?
		jb	VT1WriteCh8	; valid ASCII character
		mov	edx,[ebx+VT_CharSet] ; EDX <- current character set
		mov	edx,[edx+CHSET_ToUni] ; EDX <- table to Unicode
		mov	ax,[edx+eax*2-128*2] ; EAX <- Unicode
		or	eax,eax		; valid code?
		jz	VT1WriteCh72	; invalid code

; ------------- Decode Unicode character to display code

VT1WriteCh66:   xor	edx,edx		; EDX <- 0
		mov	dl,"?"		; DL <- invalid character
		push	ebx		; push EBX
		mov	ebx,[ebx+VT_Disp] ; EBX <- display driver
		call	DispMapChar	; map Unicode to display code
		pop	ebx		; pop EBX
		jmp	short VT1WriteCh8
	
; ------------- Store character

VT1WriteCh7:	mov	byte [ebx+VT_UtfNum],0 ; clear UTF counter
VT1WriteCh72:	mov	al,"?"		; AL <- replacement character
		mov	ah,0
VT1WriteCh8:	or	ah,[ebx+VT_ColorAttr] ; AH <- current color
		mov	edi,[ebx+VT_Current] ; EDI <- cursor address
		stosw			; store character with color

; ------------- Increase cursor position

		mov	eax,[ebx+VT_PosX] ; EAX <- cursor X position
		inc	eax		; increase cursor position
		cmp	eax,[ebx+VT_DimW] ; check end of line
		jb	VT1WriteCh88	; position is OK
		sub	edi,eax
		sub	edi,eax		; EDI <- address of start of row
		xor	eax,eax		; EAX <- reset to start of row
VT1WriteCh88:	mov	[ebx+VT_Current],edi ; store new cursor address
		mov	[ebx+VT_PosX],eax ; store new cursor X position
		or	eax,eax		; start of row?
		jnz	VT1WriteCh9	; no
		call	VTDown		; move cursor down

; ------------- Pop registers

VT1WriteCh9:	pop	edi		; pop EDI
		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                   Write one character (without update cursor)
; -----------------------------------------------------------------------------
; INPUT:	AL = character to write
;		EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Check if it is control character

VT1Write:	cmp	al,32		; is it control character?
		jae	short VT1WriteDel ; it is not control character

; ------------- Jump to service of control character

		push	eax		; push EAX
		movzx	eax,al		; EAX <- character code
		mov	eax,[VTCtrlTab+eax*4] ; EAX <- service address
		xchg	eax,[esp]	; EAX <- pop EAX, [ESP] <- jump address
		ret			; jump to service

; ------------- 7fh Del (ignored)

VT1WriteDel:	cmp	al,7fh		; Del character?
		je	short VT1WriteNul ; ignore Del character

; ------------- 9Bh (CSI, extended Esc)

		cmp	al,80h+ESC	; extended Esc?
		jne	short VT1WriteChar ; not extended Esc
                VTESC_SBL		; square bracket [

; ------------- 00h ^@,NULL (ignored)

VT1WriteNul:	ret

; ------------- Jump to Esc service

VT1WriteChar:	jmp	dword [ebx+VT_Esc] ; jump to Esc service

; ------------- Write character

VT1WEscNorm0:	VTESC_NORM		; clear escape flag
		jmp	VT1WEscNorm	; write normal character

; ------------- 18h ^X, 1Ah ^Z (Reset Esc flag)

VT1WriteNEsc:	VTESC_NORM		; reset escape mode
		ret

; ------------- 1Bh ^[,ESC (start Escape sequence)

VT1WriteESC:	cmp	dword [ebx+VT_Esc],VT1WEscEsc ; double Esc?
		je	short VT1WEscNorm0 ; double Esc, it will be normal char
		VTESC_ESC		; Esc character
		ret

; ============= Server first character after Esc

; ------------- Esc [, start CSI sequence

VT1WEscEsc:	cmp	al,"["
		jne	short VT1WEscEsc2
                VTESC_SBL		; square bracket [
		ret

; ------------- Esc ], non standard escape sequence

VT1WEscEsc2:	cmp	al,"]"
		jne	short VT1WEscEsc3
		VTESC_NSTD		; non standard escape sequence
		ret

; ------------- Esc %

VT1WEscEsc3:	cmp	al,"%"
		jne	short VT1WEscEsc4
		VTESC_PER		; percent
		ret

; ------------- Esc (

VT1WEscEsc4:	cmp	al,"("
		jne	short VT1WEscEsc5
		VTESC_RBL		; round bracket left (
		ret

; ------------- Esc )

VT1WEscEsc5:	cmp	al,")"
		jne	short VT1WEscEsc6
		VTESC_RBR		; round bracket right )
		ret

; ------------- Esc #

VT1WEscEsc6:	cmp	al,"#"
		jne	short VT1WEscEsc7
		VTESC_HASH		; hash #
		ret

; ------------- Esc E (new line)

VT1WEscEsc7:	VTESC_NORM		; reset escape mode
		cmp	al,"E"
		je	near VTWriteCRLF ; write CR/LF characters

; ------------- Esc M (row up)

		cmp	al,"M"
		je	near VTUp	; move cursor up by one row

; ------------- Esc D (row down)

		cmp	al,"D"
		je	near VTDown	; move cursor down by one row

;-------------- Esc H (set tab stop)

		cmp	al,"H"
		je	near VTTabSet	; set tab stop

; ------------- Esc Z

		cmp	al,"Z"
		je	near VTReportID	; report ID string

; ------------- Esc 7 (push state)

		cmp	al,"7"
		je	near VTPush	; push state

; ------------- Esc 8 (pop state)

		cmp	al,"8"
		je	near VTPop	; pop state

; ------------- Esc c (reset terminal)

		cmp	al,"c"
		jne	short VT1WEscEsc8
		call	VTReset		; reset terminal
		push	eax		; push EAX
		mov	al,2		; AL <- 2, clear entire display
		call	VTClearDisp	; clear display
		pop	eax		; pop EAX
		ret

; ------------- Esc > (NumLock on)

VT1WEscEsc8:	cmp	al,">"
		je	near VTNumLockOn ; set NumLock ON

; ------------- Esc = (NumLock off)

		cmp	al,"="
		je	near VTNumLockOff ; set NumLock OFF
		ret

; ============= Esc [, start of receiving parameters

VT1WEscSBL:	call	VTClearPar	; clear parameters
		VTESC_PAR		; get num. param.

; ------------- Esc [ [ n, function key

		cmp	al,"["
		jne	VT1WEscSBL2
		VTESC_KEY		; function key
		ret

; ------------- Esc [ ?

VT1WEscSBL2:	and	byte [ebx+VT_Flags],~VT_ESCQUES ; clear "?" flag
		cmp	al,"?"
		jne	VT1WEscPar
		or	byte [ebx+VT_Flags],VT_ESCQUES ; set "?" flag
		ret

; ============= Esc [, receive parameters

; ------------- Data separator, shift to next parameter

VT1WEscPar:	cmp	al,";"		; data separator?
		jne	VT1WEscPar3	; no
		cmp	byte [ebx+VT_ParNum],VT_PARAMS ; check number of params
		jae	VT1WEscPar2	; parameter buffer is full
		inc	byte [ebx+VT_ParNum] ; increase number of parameters
VT1WEscPar2:	ret	

; ------------- Convert ASCII digit character to binary

VT1WEscPar3:	push	eax		; push EAX
		call	CharDigToBin	; convert character to binary
		jc	VT1WEscPar9	; invalid digit character
		movzx	eax,al		; EAX <- digit

; ------------- Add digit to current parameter

		push	ecx		; push ECX
		push	edx		; push EDX

		movzx	ecx,byte [ebx+VT_ParNum] ; ECX <- number of parameters
		lea	ecx,[ebx+VT_Param+4*ecx] ; ECX <- pointer to parameter
		push	eax		; push digit
		xor	eax,eax		; EAX <- 0
		mov	al,10		; EAX <- 10
		mul	dword [ecx]	; EAX <- old number * 10
		pop	edx		; pop EDX (digit)
		add	eax,edx		; add new digit
		mov	[ecx],eax	; store new number		

		pop	edx		; pop EDX
		pop	ecx		; pop ECX

		pop	eax		; pop EAX
		ret

; ------------- Reset escape mode

VT1WEscPar9:	VTESC_NORM		; reset escape mode
		pop	eax		; pop EAX

; ============= Esc [, got all parameters

; ------------- Esc [ n h, Esc [ ? n h, set mode ON

		cmp	al,"h"
		jne	VT1WEscGot2
		mov	al,TRUE
		jmp	VT1WSetMode	; set mode ON

; ------------- Esc [ n l, Esc [ ? n l, set mode OFF

VT1WEscGot2:	cmp	al,"l"
		jne	VT1WEscGot3
		mov	al,FALSE
		jmp	VT1WSetMode	; set mode OFF

; ------------- Esc [ ? n c, set cursor type (this is answer to ID)

VT1WEscGot3:	test	byte [ebx+VT_Flags],VT_ESCQUES ; "?" mark?
		jz	VT1WEscGotJump	; no "?" mark
		cmp	al,"c"
		jne	VT1WEscGot4
	; TODO
		ret

; ------------- Esc [ ? n m, set complement mask

VT1WEscGot4:	cmp	al,"m"
		jne	VT1WEscGot0
	; TODO
VT1WEscGot0:	ret

; ------------- Esc [, Jump to service

VT1WEscGotJump:	cmp	al,"@"		; minimal character
		jb	VT1WEscGot0	; invalid character
		cmp	al,"z"		; maximal character
		ja	VT1WEscGot0	; invalid character

		push	eax		; push EAX
		movzx	eax,al		; EAX <- character code
		mov	eax,[VTSBLTab+eax*4-"@"*4] ; EAX <- service address
		xchg	eax,[esp]	; EAX <- pop EAX, [ESP] <- jump address
		ret			; jump to service

; ------------- Esc [ n n, status report

VT1WEscGotn:
	; TODO
		ret

; ------------- Esc [ n n H, Esc [ n n f, go to absolute X,Y coordinate

VT1WEscGotH:
VT1WEscGotf:	push	ecx		; push ECX
		push	edx		; push EDX

		mov	edx,[ebx+VT_Param] ; EDX <- first parameter, Y
		or	edx,edx		; is parameter zero?
		jz	VT1WEscGotH4	; parameter is zero
		dec	edx		; correction

VT1WEscGotH4:	mov	ecx,[ebx+VT_Param+4] ; ECX <- second parameter, X
		jecxz	VT1WEscGotH6	; parameter is zero
		dec	ecx		; correction

VT1WEscGotH6:	call	VTGoToXYRel	; go to relative position
		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		ret

; ------------- Esc [ n d, go to Y coordinate relative to scolling region

VT1WEscGotd:	push	ecx		; push ECX
		push	edx		; push EDX

		mov	edx,[ebx+VT_Param] ; EDX <- first parameter
		or	edx,edx		; is parameter zero?
		jz	VT1WEscGotd4	; parameter is zero
		dec	edx		; correction
VT1WEscGotd4:	mov	ecx,[ebx+VT_PosX] ; ECX <- position X
		jmp	short VT1WEscGotH6

; ------------- Esc [ n A, shift Y coordinate up

VT1WEscGotA:	push	ecx		; push ECX
		mov	ecx,[ebx+VT_PosX] ; ECX <- position X
VT1WEscGotA4:	push	edx		; push EDX

		mov	edx,[ebx+VT_Param] ; EDX <- first parameter
		or	edx,edx		; is parameter zero?
		jnz	VT1WEscGotA6	; parameter is not zero
		inc	edx		; EDX <- 1, minimal coordinate
VT1WEscGotA6:	neg	edx		; EDX <- negative Y increment
VT1WEscGotA8:	add	edx,[ebx+VT_PosY] ; EDX <- new position Y
VT1WEscGotA9:	call	VTGoToXY	; go to position
		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		ret

; ------------- Esc [ n F, shift Y coordinate up to begin of line

VT1WEscGotF:	push	ecx		; push ECX
		xor	ecx,ecx		; ECX <- 0, new X position
		jmp	short VT1WEscGotA4

; ------------- Esc [ n B, Esc [ n e, shift Y coordinate down

VT1WEscGotB:
VT1WEscGote:	push	ecx		; push ECX
		mov	ecx,[ebx+VT_PosX] ; ECX <- position X
VT1WEscGotB4:	push	edx		; push EDX

		mov	edx,[ebx+VT_Param] ; EDX <- first parameter
		or	edx,edx		; is parameter zero?
		jnz	VT1WEscGotA8	; parameter is not zero
		inc	edx		; EDX <- 1, minimal coordinate
		jmp	short VT1WEscGotA8

; ------------- Esc [ n E, shift Y coordinate down to begin of line

VT1WEscGotE:	push	ecx		; push ECX
		xor	ecx,ecx		; ECX <- 0, new X position
		jmp	short VT1WEscGotB4

; ------------- Esc [ n G, Esc [ n `, go to absolute X coordinate

VT1WEscGotG:
VT1WEscGotGA:	push	ecx		; push ECX
		push	edx		; push EDX

		mov	ecx,[ebx+VT_Param] ; ECX <- first parameter
		jecxz	VT1WEscGotG4	; parameter is zero
		dec	ecx		; correction
VT1WEscGotG4:	mov	edx,[ebx+VT_PosY] ; EDX <- position Y
		jmp	short VT1WEscGotA9

; ------------- Esc [ n D, shift X coordinate left

VT1WEscGotD:	push	ecx		; push ECX
		push	edx		; push EDX

		mov	ecx,[ebx+VT_Param] ; ECX <- first parameter
		or	ecx,ecx		; is parameter zero?
		jnz	VT1WEscGotD6	; parameter is not zero
		inc	ecx		; ECX <- 1, minimal coordinate
VT1WEscGotD6:	neg	ecx		; ECX <- negative X increment
VT1WEscGotD8:	add	ecx,[ebx+VT_PosX] ; ECX <- new position X
		jmp	short VT1WEscGotG4

; ------------- Esc [ n C, Esc [ n a, shift X coordinate right

VT1WEscGotC:
VT1WEscGota:	push	ecx		; push ECX
		push	edx		; push EDX

		mov	ecx,[ebx+VT_Param] ; ECX <- first parameter
		or	ecx,ecx		; is parameter zero?
		jnz	VT1WEscGotD8	; parameter is not zero
		inc	ecx		; ECX <- 1, minimal coordinate
		jmp	short VT1WEscGotD8

; ------------- Esc [ n J, clear display (0=to end, 1=to start, 2=entire)

VT1WEscGotJ:	push	eax		; push EAX
		mov	eax,[ebx+VT_Param] ; EAX <- first parameter
		cmp	eax,byte 2	; check valid parameter
		ja	VT1WEscGotJ4	; invalid parameter
		jb	VT1WEscGotJ2	; 0 or 1
		test	byte [ebx+VT_Flags2],VT_ANSI ; ANSI.SYS compatible
		jz	VT1WEscGotJ2	; no

		push	ecx		; push ECX
		push	edx		; push EDX
		xor	ecx,ecx		; ECX <- 0
		xor	edx,edx		; EDX <- 0
		call	VTGoToXYRel	; go to relative position
		pop	edx		; pop EDX
		pop	ecx		; pop ECX

VT1WEscGotJ2:	call	VTClearDisp	; clear display
VT1WEscGotJ4:	pop	eax		; pop EAX
		ret

; ------------- Esc [ n K, clear line (0=to end, 1=to start, 2=entire)

VT1WEscGotK:	push	eax		; push EAX
		mov	eax,[ebx+VT_Param] ; EAX <- first parameter
		cmp	eax,byte 2	; check valid parameter
		ja	VT1WEscGotK2	; invalid parameter
		call	VTClearRow	; clear row
VT1WEscGotK2:	pop	eax		; pop EAX
		ret

; ------------- Esc [ n L, scroll down from current row to end of scroll region

VT1WEscGotL:	push	eax		; push EAX
		push	ecx		; push ECX
		push	edx		; push EDX

		mov	eax,[ebx+VT_Param] ; EAX <- first parameter
		mov	ecx,[ebx+VT_PosY] ; ECX <- current row
		mov	edx,[ebx+VT_ScrollB] ; EDX <- scrolling region bottom
		sub	edx,ecx		; EDX <- number of rows
		jbe	VT1WEscGotL8	; invalid cursor position
		cmp	eax,edx		; check number of rows
		jb	VT1WEscGotL2	; number of rows is OK
		mov	eax,edx		; EAX <- limit number of rows
VT1WEscGotL2:	or	eax,eax		; is parameter zero?
		jnz	VT1WEscGotL4	; no
		inc	eax		; EAX <- 1, minimal rows
VT1WEscGotL4:	add	edx,ecx		; EDX <- bottom row
		call	VTScrollDown	; scroll region down
		and	byte [ebx+VT_Flags],~VT_NEEDWRAP ; clear wrap request

VT1WEscGotL8:	pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; ------------- Esc [ n M, scroll up from current row to end of scroll region

VT1WEscGotM:	push	eax		; push EAX
		push	ecx		; push ECX
		push	edx		; push EDX

		mov	eax,[ebx+VT_Param] ; EAX <- first parameter
		mov	ecx,[ebx+VT_PosY] ; ECX <- current row
		mov	edx,[ebx+VT_ScrollB] ; EDX <- scrolling region bottom
		sub	edx,ecx		; EDX <- number of rows
		jbe	VT1WEscGotM8	; invalid cursor position
		cmp	eax,edx		; check number of rows
		jb	VT1WEscGotM2	; number of rows is OK
		mov	eax,edx		; EAX <- limit number of rows
VT1WEscGotM2:	or	eax,eax		; is parameter zero?
		jnz	VT1WEscGotM4	; no
		inc	eax		; EAX <- 1, minimal rows
VT1WEscGotM4:	add	edx,ecx		; EDX <- bottom row
		call	VTScrollUp	; scroll region up
		and	byte [ebx+VT_Flags],~VT_NEEDWRAP ; clear wrap request

VT1WEscGotM8:	pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; ------------- Esc [ n P, delete characters from cursor to end of line

VT1WEscGotP:	push	ecx		; push ECX
		mov	ecx,[ebx+VT_Param] ; ECX <- first parameter
		or	ecx,ecx		; is parameter zero?
		jnz	VT1WEscGotP2	; parameter is not zero
		inc	ecx		; ECX <- 1, default value
VT1WEscGotP2:	call	VTDelChar	; delete characters
		pop	ecx		; pop ECX
		ret

; ------------- Esc [ n c, respond string

VT1WEscGotc:	cmp	dword [ebx+VT_Param],byte 0 ; is any parameter?
		jne	near VTReportID	; report ID string
		ret

; ------------- Esc [ n g, clear tab stop (0=current, 3=all)

VT1WEscGotg:	cmp	dword [ebx+VT_Param],byte 0 ; reset tab stop?
		je	near VTTabRes	; reset tab stop
		cmp	dword [ebx+VT_Param],byte 3 ; clear all tab stops?
		je	near VTTabClear	; clear all tab stops
		ret

; ------------- Esc [ n q, set LED state

VT1WEscGotq:
	; TODO
		ret

; ------------- Esc [ n;n r, set region

VT1WEscGotr:    push	eax		; push EAX
		push	ecx		; push ECX
		push	edx		; push EDX

		mov	eax,[ebx+VT_DimH] ; EAX <- display height
		mov	ecx,[ebx+VT_Param] ; ECX <- first parameter (TOP)
		jecxz	VT1WEscGotr2	; first parameter is zero
		dec	ecx		; correction

VT1WEscGotr2:	cmp	ecx,eax		; check parameter range
		jb	VT1WEscGotr4	; parameter is OK
		mov	ecx,eax		; ECX <- display height
		dec	ecx		; ECX <- last row

VT1WEscGotr4:	mov	edx,[ebx+VT_Param+4] ; EDX <- second parameter (BOTTOM)
		or	edx,edx		; is second parameter zero?
		jnz	VT1WEscGotr6	; second parameter is not zero
		xchg	eax,edx		; EDX <- display height
VT1WEscGotr6:	dec	edx		; correction

		cmp	ecx,edx		; is TOP < BOTTOM ?
		jae	VT1WEscGotr8	; invalid parameters
		mov	[ebx+VT_ScrollT],ecx ; scrolling region top
		mov	[ebx+VT_ScrollB],edx ; scrolling region bottom

		xor	ecx,ecx		; ECX <- 0, column
		xor	edx,edx		; EDX <- 0, row
		call	VTGoToXYRel	; set cursor to [0;0]

VT1WEscGotr8:	pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; ------------- Esc [ n X, clear characters from cursor

VT1WEscGotX:	push	eax		; push EAX
		mov	eax,[ebx+VT_Param] ; EAX <- first parameter
		call	VTClearChar	; clear characters
		pop	eax		; pop EAX
		ret

; ------------- Esc [ n @, insert characters

VT1WEscGotAt:	push	ecx		; push ECX
		mov	ecx,[ebx+VT_Param] ; ECX <- first parameter
		or	ecx,ecx		; is parameter zero?
		jnz	VT1WEscGotAt2	; parameter is not zero
		inc	ecx		; ECX <- 1, default value
VT1WEscGotAt2:	call	VTInsChar	; insert characters
		pop	ecx		; pop ECX
		ret

; ============= Esc ], Non standard Esc sequance

; ------------- Esc ] P, set palettes

VT1WEscNStd:	cmp	al,"P"
		jne	VT1WEscNStd2
		call	VTClearPar	; clear parameters
		VTESC_PAL		; set palettes
		ret

; ------------- Esc ] R, reset palettes

VT1WEscNStd2:	VTESC_NORM		; reset escape mode
		cmp	al,"R"
		jne	VT1WEscNStd3
		call	VTInitPalette	; initialize palettes
		call	VTSetPalette	; set terminal palettes
VT1WEscNStd3:	ret

; ============= Esc % sequence, set UTF mode

VT1WEscPer:	VTESC_NORM		; reset escape mode
		cmp	al,"@"
		jne	VT1WEscPer2
		and	byte [ebx+VT_Flags2],~VT_USEUTF ; don't use UTF
VT1WEscPer2:	cmp	al,"G"
		je	VT1WEscPer4
		cmp	al,"8"
		jne	VT1WEscPer6
VT1WEscPer4:	or	byte [ebx+VT_Flags2],VT_USEUTF ; use UTF
VT1WEscPer6:	ret

; ============= Esc (, set G0 charset

VT1WEscRBL:	push	ecx		; push ECX

		mov	ecx,CharSetDEC	; ECX <- DEC charset
		cmp	al,"0"
		je	VT1WEscRBL2

		mov	ecx,CharSet1252	; ECX <- Latin 1 Windows charset
		cmp	al,"B"
		je	VT1WEscRBL2

		mov	ecx,CharSet437	; ECX <- IBM 437 charset
		cmp	al,"U"
		je	VT1WEscRBL2

		mov	ecx,CharSet1250	; ECX <- Latin 2 Windows charset
		cmp	al,"K"
		jne	VT1WEscRBL4

VT1WEscRBL2:	mov	[ebx+VT_CharsetG0],ecx ; set G0 charset
		call	VTUpdTrans	; update translation table

VT1WEscRBL4:	pop	ecx		; pop ECX

; VT1WEscKey must follow

; ============= Esc [ [ n, function key

VT1WEscKey:	VTESC_NORM		; reset escape mode
		ret

; ============= Esc ), set G1 charset

VT1WEscRBR:	push	ecx		; push ECX

		mov	ecx,CharSetDEC	; ECX <- DEC charset
		cmp	al,"0"
		je	VT1WEscRBR2

		mov	ecx,CharSet1252	; ECX <- Latin 1 Windows charset
		cmp	al,"B"
		je	VT1WEscRBR2

		mov	ecx,CharSet437	; ECX <- IBM 437 charset
		cmp	al,"U"
		je	VT1WEscRBR2

		mov	ecx,CharSet1250	; ECX <- Latin 2 Windows charset
		cmp	al,"K"
		jne	VT1WEscRBR4

VT1WEscRBR2:	mov	[ebx+VT_CharsetG1],ecx ; set G1 charset
		call	VTUpdTrans	; update translation table

VT1WEscRBR4:	pop	ecx		; pop ECX
		jmp	short VT1WEscKey

; ============= Esc # 8, screen allignment test

VT1WEscHash:	VTESC_NORM		; reset escape mode
		cmp	al,"8"
		jne	VT1WEscHash8

		push	eax		; push EAX
		xor	dword [ebx+VT_ClearChar],("e" << 16)+"e"
		mov	al,2
		call	VTClearDisp	; clear display
		xor	dword [ebx+VT_ClearChar],("e" << 16)+"e"
		pop	eax		; pop EAX
		ret
VT1WEscHash8:	ret

; -----------------------------------------------------------------------------
;                             Write one character
; -----------------------------------------------------------------------------
; INPUT:	AL = character to write
;		EBX = terminal interface
; -----------------------------------------------------------------------------

VTWrite:	call	VT1Write	; write one character

; VTUpdateCur must follow

; -----------------------------------------------------------------------------
;                          Update cursor position
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------
; It must follow after VTWrite

VTUpdateCur:	push	ecx		; push ECX
		push	edx		; push EDX

		mov	ecx,[ebx+VT_PosX] ; ECX <- cursor column
		mov	edx,[ebx+VT_PosY] ; EDX <- cursor row
		call	VTSetCursor	; set cursor position

		pop	edx		; pop EDX
		pop	ecx		; pop ECX
VTMWrite9:	ret

; -----------------------------------------------------------------------------
;                            Multi-write character
; -----------------------------------------------------------------------------
; INPUT:	EAX = output buffer
;		EBX = terminal interface
;		ECX = number of bytes
; -----------------------------------------------------------------------------

; ------------- Push registers

VTMWrite:	jecxz	VTMWrite9	; no data
		push	eax		; push EAX
		push	ecx		; push ECX
		push	esi		; push ESI

; ------------- Write characters

		xchg	eax,esi		; ESI <- output buffer
VTMWrite2:	lodsb			; AL <- load character
		call	VT1Write	; write character
		loop	VTMWrite2	; next character

; ------------- Pop registers

VTMWrite8:	pop	esi		; pop ESI
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		jmp	short VTUpdateCur ; update cursor

; -----------------------------------------------------------------------------
;                                 Push state
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Push registers

VT1WEscGots:				; Esc [ s
VTPush:		push	eax		; push EAX

; ------------- Save cursor position

		mov	eax,[ebx+VT_PosX] ; EAX <- cursor column
		mov	[ebx+VT_PushPosX],eax
		mov	eax,[ebx+VT_PosY] ; EAX <- cursor row
		mov	[ebx+VT_PushPosY],eax
		mov	eax,[ebx+VT_Current] ; EAX <- current address
		mov	[ebx+VT_PushAddr],eax

; ------------- Save color and charset

		mov	al,[ebx+VT_Color] ; AL <- color
		mov	[ebx+VT_PushColor],al
		mov	al,[ebx+VT_Attrib] ; AL <- attributes
		mov	[ebx+VT_PushAttrib],al
		mov	eax,[ebx+VT_CharsetG0] ; EAX <- G0 charset
		mov	[ebx+VT_PushG0],eax
		mov	eax,[ebx+VT_CharsetG1] ; EAX <- G1 charset
		mov	[ebx+VT_PushG1],eax

; ------------- Pop registers

		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                        Pop state (without update cursor)
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Push registers

VT1WEscGotu:				; Esc [ u
VTPop:		push	eax		; push EAX

; ------------- Restore cursor position

		mov	eax,[ebx+VT_PushPosX] ; EAX <- cursor column
		mov	[ebx+VT_PosX],eax
		mov	eax,[ebx+VT_PushPosY] ; EAX <- cursor row
		mov	[ebx+VT_PosY],eax
		mov	eax,[ebx+VT_PushAddr] ; EAX <- current address
		mov	[ebx+VT_Current],eax

; ------------- Restore color and charset

		mov	al,[ebx+VT_PushColor] ; AL <- color
		mov	[ebx+VT_Color],al
		mov	al,[ebx+VT_PushAttrib] ; AL <- attributes
		mov	[ebx+VT_Attrib],al
		mov	eax,[ebx+VT_PushG0] ; EAX <- G0 charset
		mov	[ebx+VT_CharsetG0],eax
		mov	eax,[ebx+VT_PushG1] ; EAX <- G1 charset
		mov	[ebx+VT_CharsetG1],eax
		call	VTUpdTrans	; update translation table
		call	VTUpdateAttr	; update color attributes
		and	byte [ebx+VT_Flags],~VT_NEEDWRAP ; clear wrap request

; ------------- Pop registers

		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                           Switch to G1 charset
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

VTSetG1:	or	byte [ebx+VT_Flags],VT_CTRL ; display control chars
		or	byte [ebx+VT_Attrib],VT_CHARG1 ; use G1 charset
		jmp	short VTUpdTrans ; update translation table

; -----------------------------------------------------------------------------
;                           Switch to G0 charset
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

VTSetG0:	and	byte [ebx+VT_Flags],~VT_CTRL ; don't display controls
		and	byte [ebx+VT_Attrib],~VT_CHARG1 ; don't use G1

; VTUpdTrans must follow

; -----------------------------------------------------------------------------
;                       Update character translation table
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Push registers

VTUpdTrans:	push	eax		; push EAX

; ------------- Set new translation table

		mov	eax,[ebx+VT_CharsetG1] ; EAX <- charset G1
		test	byte [ebx+VT_Attrib],VT_CHARG1 ; use G1 charset?
		jnz	VTUpdTrans2	; use G1 charset
		mov	eax,[ebx+VT_CharsetG0] ; EAX <- charset G0
VTUpdTrans2:	mov	[ebx+VT_CharSet],eax ; store current character set

; ------------- Pop registers

		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                   Reset terminal (without update cursor)
; -----------------------------------------------------------------------------
; INPUT:	EBX = terminal interface
; -----------------------------------------------------------------------------

; ------------- Push registers

VTReset:	push	eax		; push EAX
		push	ecx		; push ECX
		push	edi		; push EDI

; ------------- Get driver parameters

		mov	edi,[ebx+VT_Disp] ; EDI <- display driver
		mov	eax,[edi+DDPB_Addr] ; EAX <- current display address
		mov	[ebx+VT_Addr],eax ; set videomemory address
		mov	[ebx+VT_Current],eax ; set current cursor address
		add	eax,[edi+DDPB_DispSize] ; EAX <- end of videomemory
		mov	[ebx+VT_EndAddr],eax ; set end address of display
		mov	eax,[edi+DDPB_ScanLine] ; EAX <- bytes per scan line
		mov	[ebx+VT_ScanLine],eax ; store bytes per scan line		

; ------------- Display dimension

		mov	eax,[edi+DDPB_VirtW] ; EAX <- virtual width
		mov	[ebx+VT_DimW],eax ; store display width
		mov	eax,[edi+DDPB_VirtH] ; EAX <- virtual height
		mov	[ebx+VT_ScrollB],eax ; bottom line of scroll.region+1
		mov	[ebx+VT_DimH],eax ; store display height

; ------------- Set default parameters

		mov	byte [ebx+VT_Flags],VT_DEFFLAGS ; default flags
		mov	byte [ebx+VT_Flags2],VT_DEFFLAGS2 ; default flags 2
		mov	byte [ebx+VT_Attrib],VT_DEFATTR ; default attributes
		xor	eax,eax		; EAX <- 0
		mov	byte [ebx+VT_ParNum],al ; clear parameters
		mov	[ebx+VT_ScrollT],eax ; top line of scrolling region

; ------------- Cursor position (here is EAX = 0)

		mov	[ebx+VT_PosX],eax ; reset cursor X
		mov	[ebx+VT_PosY],eax ; reset cursor Y

; ------------- Default color

		call	VTSetDefCol	; set default color attributes
		call	VTUpdateAttr	; update color attributes

; ------------- Default charset

		mov	dword [ebx+VT_CharsetG0],CharSet437 ; G0 charset
		mov	dword [ebx+VT_CharsetG1],CharSetDEC ; G1 charset
		call	VTSetG0		; switch to G0 charset

; ------------- Set normal Esc service

		VTESC_NORM		; set normal Esc service
 
; ------------- Initialize default tab stops (after 8 positions)

		call	VTTabDef	; default tab stops

; ------------- Push current state

		call	VTPush		; push current state

; ------------- Pop registers

		pop	edi		; pop EDI
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                      Initialize VT100 terminal emulator
; -----------------------------------------------------------------------------

; ------------- Prepare registers

VTInit:		mov	ebx,VTBuff	; EBX <- VT100 first terminal
		mov	esi,KeybBuff	; ESI <- keyboard buffer
		xor	edx,edx		; EDX <- 0
		inc	edx		; EDX <- 1, console mask

; ------------- Install default display interface

VTInit2:	mov	dword [ebx+VT_Disp],VGADrvDDPB ; display driver

; ------------- Install new write key function

		mov	eax,VTWriteKey	; EAX <- new function
		xchg	eax,[esi+KBUF_WKeyFnc] ; EAX <- old function
		mov	[ebx+VT_WKeyFnc],eax ; save old function
		mov	eax,ebx		; EAX <- terminal
		xchg	eax,[esi+KBUF_WKeyData] ; EAX <- old data
		mov	[ebx+VT_WKeyData],eax ; save old data

; ------------- Set initial parameters

		mov	byte [ebx+VT_Flags2],VT_DEFFLAGS2 ; default flags 2

		movzx	eax,byte [VideoCols] ; EAX <- number of columns
		mov	[ebx+VT_DimW],eax ; width of window
		movzx	eax,byte [VideoRows] ; EAX <- number of rows
		mov	[ebx+VT_DimH],eax ; height of window
		mov	byte [ebx+VT_DefColor],COL_NORMAL ; default color
		mov	byte [ebx+VT_UnderColor],COL_INTENS ; underline
		mov	byte [ebx+VT_DarkColor],COL_DARK ; low intensity
		test	byte [ebx+VT_Flags2],VT_512CHAR ; 512-char mode?
		jz	VTInit3		; no 512-char mode
		mov	byte [ebx+VT_UnderColor],COL_YELLOW ; underline
		mov	byte [ebx+VT_DarkColor],COL_GREEN ; low intensity
VTInit3:	test	byte [ebx+VT_Flags2],VT_MONO ; MONO mode?
		jz	VTInit4		; no MONO mode
		mov	byte [ebx+VT_UnderColor],COL_UNDER ; underline
VTInit4:	
		mov	byte [ebx+VT_ClearChar]," " ; clearing character
		mov	byte [ebx+VT_ClearChar+2]," " ; clearing character 2

; ------------- Reset parameters

		call	VTReset		; reset terminal

; ------------- Initialize standard palettes

		call	VTInitPalette	; initialize palettes
		call	VTSetPalette	; set terminal palettes

; ------------- Install console service

		mov	eax,VTWrite	; EAX <- write function
		call	ConRegWrite	; register function
		mov	eax,VTMWrite	; EAX <- multi-write function
		call	ConRegMWrite	; register function

; ------------- Update terminal

		call	VTPop		; pop current state
		
; ------------- Next terminal

		add	ebx,VTERM_size	; EBX <- next terminal
		shl	edx,1		; shift console mask
		jnz	VTInit2		; next terminal

; TODO
		mov	ecx,DispCharTab
		mov	edx,CP437ToUniTab
		mov	esi,DispCharTabLat
		test	byte [VTBuff+VT_Flags2],VT_512CHAR ; 512-char mode?
		jnz	VTInit3		; 512-char mode
		xor	esi,esi
VTInit8:	mov	edi,F14
		mov	ebx,VGADrvDDPB
		call	DispLoadSet

		mov	cl,0
		mov	dl,1
		test	byte [VTBuff+VT_Flags2],VT_512CHAR ; 512-char mode?
		jnz	VTInit9		; 512-char mode
		mov	dl,0
VTInit9:	call	DispSetFont
		ret

; -----------------------------------------------------------------------------
;                                   Data
; -----------------------------------------------------------------------------

		DATA_SECTION

; ------------- Jump table for control characters

		align	4,db 0
VTCtrlTab:	dd	VT1WriteNul	; 00h ^@,NUL (ignored)
		dd	VT1WriteChar	; 01h ^A
		dd	VT1WriteChar	; 02h ^B
		dd	VT1WriteChar	; 03h ^C,ETX
		dd	VT1WriteChar	; 04h ^D,EOT
		dd	VT1WriteChar	; 05h ^E,ENQ (answerback)
		dd	VT1WriteChar	; 06h ^F
		dd	VTWriteBEL	; 07h ^G,BEL (generates bell tone)
		dd	VTLeft		; 08h ^H,BS (moves cursor left)
		dd	VTWriteTAB	; 09h ^I,HT,TAB (moves to next tab)
		dd	VTWriteLFAuto	; 0Ah ^J,LF (new line), with auto CR
		dd	VTWriteLFAuto	; 0Bh ^K,VT (processed as LF)
		dd	VTWriteLFAuto	; 0Ch ^L,FF (processed as LF)
		dd	VTWriteCR	; 0Dh ^M,CR (moves to left margin)
		dd	VTSetG1		; 0Eh ^N,SO (selects G1 charset)
		dd	VTSetG0		; 0Fh ^O,SI (selects G0 charset)
		dd	VT1WriteChar	; 10h ^P
		dd	VT1WriteChar	; 11h ^Q,DC1,^Q,XON (resume transm.)
		dd	VT1WriteChar	; 12h ^R
		dd	VT1WriteChar	; 13h ^S,DC3,^S,XOFF (stop transm)
		dd	VT1WriteChar	; 14h ^T
		dd	VT1WriteChar	; 15h ^U
		dd	VT1WriteChar	; 16h ^V
		dd	VT1WriteChar	; 17h ^W
		dd	VT1WriteNEsc	; 18h ^X (reset Esc flag)
		dd	VT1WriteChar	; 19h ^Y
		dd	VT1WriteNEsc	; 1Ah ^Z (reset Esc flag)
		dd	VT1WriteESC	; 1Bh ^[,ESC (start Escape sequence)
		dd	VT1WriteChar	; 1Ch ^\
		dd	VT1WriteChar	; 1Dh ^]
		dd	VT1WriteChar	; 1Eh ^^
		dd	VT1WriteChar	; 1Fh ^_

; ------------- Jump table for "Esc [" sequence (not "Esc [ ?")

		align	4,db 0
VTSBLTab:	dd	VT1WEscGotAt	; @
		dd	VT1WEscGotA	; A
		dd	VT1WEscGotB	; B
		dd	VT1WEscGotC	; C
		dd	VT1WEscGotD	; D
		dd	VT1WEscGotE	; E
		dd	VT1WEscGotF	; F
		dd	VT1WEscGotG	; G
		dd	VT1WEscGotH	; H
		dd	VT1WEscGot0	; I
		dd	VT1WEscGotJ	; J
		dd	VT1WEscGotK	; K
		dd	VT1WEscGotL	; L
		dd	VT1WEscGotM	; M
		dd	VT1WEscGot0	; N
		dd	VT1WEscGot0	; O
		dd	VT1WEscGotP	; P
		dd	VT1WEscGot0	; Q
		dd	VT1WEscGot0	; R
		dd	VT1WEscGot0	; S
		dd	VT1WEscGot0	; T
		dd	VT1WEscGot0	; U
		dd	VT1WEscGot0	; V
		dd	VT1WEscGot0	; W
		dd	VT1WEscGotX	; X
		dd	VT1WEscGot0	; Y
		dd	VT1WEscGot0	; Z

		dd	VT1WEscGot0	; [
		dd	VT1WEscGot0	; backslash
		dd	VT1WEscGotSBR	; ]
		dd	VT1WEscGot0	; ^
		dd	VT1WEscGot0	; _
		dd	VT1WEscGotGA	; `

		dd	VT1WEscGota	; a
		dd	VT1WEscGot0	; b
		dd	VT1WEscGotc	; c
		dd	VT1WEscGotd	; d
		dd	VT1WEscGote	; e
		dd	VT1WEscGotf	; f
		dd	VT1WEscGotg	; g
		dd	VT1WEscGot0	; h
		dd	VT1WEscGot0	; i
		dd	VT1WEscGot0	; j
		dd	VT1WEscGot0	; k
		dd	VT1WEscGot0	; l
		dd	VT1WEscGotm	; m
		dd	VT1WEscGotn	; n
		dd	VT1WEscGot0	; o
		dd	VT1WEscGot0	; p
		dd	VT1WEscGotq	; q
		dd	VT1WEscGotr	; r
		dd	VT1WEscGots	; s
		dd	VT1WEscGot0	; t
		dd	VT1WEscGotu	; u
		dd	VT1WEscGot0	; v
		dd	VT1WEscGot0	; w
		dd	VT1WEscGot0	; x
		dd	VT1WEscGot0	; y
		dd	VT1WEscGot0	; z

; ------------- Jump table to set color attribute

		align	4,db 0
VTSetAttrTab:	dd	VTSetDefCol	; 0: all attributes OFF
		dd	VTSetAttrT1	; 1: set bold intensity ON
		dd	VTSetAttrT2	; 2: set dark intentisy ON
		dd	VTSetAttrT	; 3: set italic ON (unsupported)
		dd	VTSetAttrT4	; 4: set underline ON
		dd	VTSetAttrT5	; 5: set blinking slow ON
		dd	VTSetAttrT6	; 6: set blinking rapid ON
		dd	VTSetAttrT7	; 7: set inverse ON
		dd	VTSetAttrT8	; 8: set invisible ON
		dd	VTSetAttrT	; 9: set strikethrough ON (unsupported)
		dd	VTSetAttrT10	; 10: select primary font
		dd	VTSetAttrT11	; 11: first alternate font
					;   (displays characters < 20h)
		dd	VTSetAttrT12	; 12: second alternate font
					;   (extended ASCII characters)
%rep 8
		dd	VTSetAttrT	; 13..20: alternate font
%endrep
		dd	VTSetAttrT21	; 21: set bold intensity OFF
		dd	VTSetAttrT22	; 22: set dark intensity OFF
		dd	VTSetAttrT	; 23: set italic OFF (unsupported)
		dd	VTSetAttrT24	; 24: set underline OFF
		dd	VTSetAttrT25	; 25: set blinking OFF
		dd	VTSetAttrT	; 26: proporcional ON (unsupported)
		dd	VTSetAttrT27	; 27: set inverse OFF
		dd	VTSetAttrT28	; 28: set invisible OFF
		dd	VTSetAttrT	; 29: set strikethrough OFF (unsup.)
		dd	VTSetAttrT30	; 30: set foreground color to black
		dd	VTSetAttrT30	; 31: set foreground color to red
		dd	VTSetAttrT30	; 32: set foreground color to green
		dd	VTSetAttrT30	; 33: set foreground color to yellow
		dd	VTSetAttrT30	; 34: set foreground color to blue
		dd	VTSetAttrT30	; 35: set foreground color to magenta
		dd	VTSetAttrT30	; 36: set foreground color to cyan
		dd	VTSetAttrT30	; 37: set foreground color to white
		dd	VTSetAttrT38	; 38: underline ON, default foreground
		dd	VTSetAttrT39	; 39: underline OFF, default foreground
		dd	VTSetAttrT40	; 40: set background color to black
		dd	VTSetAttrT40	; 41: set background color to red
		dd	VTSetAttrT40	; 42: set background color to green
		dd	VTSetAttrT40	; 43: set background color to yellow
		dd	VTSetAttrT40	; 44: set background color to blue
		dd	VTSetAttrT40	; 45: set background color to magenta
		dd	VTSetAttrT40	; 46: set background color to cyan
		dd	VTSetAttrT40	; 47: set background color to white
		dd	VTSetAttrT	; 48: reserved
		dd	VTSetAttrT49	; 49: use default background
		dd	VTSetAttrT	; 50: proporcional OFF (unsupported)
		dd	VTSetAttrT	; 51: framed ON (unsupported)
		dd	VTSetAttrT	; 52: encircled ON (unsupported)
		dd	VTSetAttrT	; 53: overlined ON (unsupported)
		dd	VTSetAttrT	; 54: framed and encircled OFF (unsup.)
		dd	VTSetAttrT	; 55: overlined OFF (unsupported)

%rep 90-56
		dd	VTSetAttrT	; 56..89: reserved
%endrep
%rep 8
		dd	VTSetAttrT90	; 90..97: set foreground bright
%endrep
		dd	VTSetAttrT	; 98: reserved
		dd	VTSetAttrT	; 99: reserved
%rep 8
		dd	VTSetAttrT100	; 100..107: set background bright
%endrep

; ------------- Color table for VT100 terminal

VTSetAttrColTab:db	COL_BLACK	; black
		db	COL_RED		; red
		db	COL_GREEN	; green
		db	COL_YELLOW	; yellow (brown)
		db	COL_BLUE	; blue
		db	COL_MAGENTA	; magenta
		db	COL_CYAN	; cyan
		db	COL_WHITE	; white
		db	COL_LBLACK	; light black (gray)
		db	COL_LRED	; light red
		db	COL_LGREEN	; light green
		db	COL_LYELLOW	; light yellow
		db	COL_LBLUE	; light blue
		db	COL_LMAGENTA	; light magenta
		db	COL_LCYAN	; light cyan
		db	COL_LWHITE	; light white

; ------------- Jump table to set terminal command

		align	4,db 0
VTSetTermTab:	dd	VT1WSetTerm0	; 0
		dd	VT1WSetTerm1	; 1
		dd	VT1WSetTerm2	; 2
		dd	VT1WSetTerm0	; 3
		dd	VT1WSetTerm0	; 4
		dd	VT1WSetTerm0	; 5
		dd	VT1WSetTerm0	; 6
		dd	VT1WSetTerm0	; 7
		dd	VT1WSetTerm8	; 8
		dd	VT1WSetTerm9	; 9
		dd	VT1WSetTerm10	; 10
		dd	VT1WSetTerm11	; 11
		dd	VT1WSetTerm12	; 12
		dd	VT1WSetTerm13	; 13
		dd	VT1WSetTerm14	; 14
		dd	VT1WSetTerm15	; 15

; ------------- Report string OK

VTRepStrOK:	db	ESC,'[0n'
VTRepStrOK2:

; ------------- VT100 identification string (not used)

;VTRepStr0ID:	db	ESC,'[?1;2c'
;VTRepStr0ID2:

; ------------- VT102 identification string

VTRepStrID:	db	ESC,'[?6c'
VTRepStrID2:

; -----------------------------------------------------------------------------
;                            Uninitialized data
; -----------------------------------------------------------------------------

		BSS_SECTION

		align	8, resb 1

; ------------- VT100 terminal interfaces

		align	4, resb 1
VTBuff:		resb	VTERM_size*CONSOLE_NUM ; VT100 terminal interfaces

Back to source browser