; =============================================================================
;
; 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
|