; =============================================================================
;
; Litos - TXT display
;
; =============================================================================
CODE_SECTION 32
; -----------------------------------------------------------------------------
; Enumerate standard videomodes
; -----------------------------------------------------------------------------
; INPUT: EAX = index (0..., -1 = get max. index)
; EBX = display driver
; 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.
; -----------------------------------------------------------------------------
TXTEnumMode: ret
; -----------------------------------------------------------------------------
; Test videomode
; -----------------------------------------------------------------------------
; INPUT: EBX = display driver
; 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)
; -----------------------------------------------------------------------------
TXTTestMode: ret
; -----------------------------------------------------------------------------
; Set videomode
; -----------------------------------------------------------------------------
; INPUT: EBX = display driver
; 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)
; -----------------------------------------------------------------------------
TXTSetMode: ret
; -----------------------------------------------------------------------------
; Clear screen and reset cursor
; -----------------------------------------------------------------------------
; INPUT: EBX = display driver
; NOTES: It clears entire screen, sets offset to 0 and resets cursor.
; -----------------------------------------------------------------------------
; ------------- Push registers
TXTClear: push eax ; push EAX
push ecx ; push ECX
push edi ; push EDI
; ------------- Clear videomemory
mov edi,[ebx+DDPB_BaseAddr] ; EDI <- base address
mov ecx,[ebx+DDPB_MemSize] ; ECX <- size of videomemory
shr ecx,1 ; ECX <- size in characters
shr ecx,1 ; ECX <- size in double characters
mov eax,7200720h ; EAX <- clearing pattern
rep stosd ; clear videomemory
; ------------- Set display offset
xor ecx,ecx ; ECX <- 0
xor edx,edx ; EDX <- 0
call TXTSetOffset ; set display offset
; ------------- Set cursor position
call TXTSetCursor ; set cursor position
; ------------- Set cursor size
mov edx,[ebx+DDPB_FontH] ; EDX <- font height
dec edx ; EDX <- last scan line
mov ecx,edx ; ECX <- last scan line
dec ecx ; ECX <- previous scan line
call TXTSetCurSize ; set cursor size
; ------------- Set cursor on
mov al,1 ; AL <- 1, cursor on
call TXTSetVisible ; set cursor on
; ------------- Pop registers
pop edi ; pop EDI
pop ecx ; pop ECX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Set display offset
; -----------------------------------------------------------------------------
; INPUT: EBX = display driver
; ECX = X coordinate of visible region of display
; EDX = Y coordinate of visible region of display
; -----------------------------------------------------------------------------
; ------------- Check if offset changed
TXTSetOffset: cmp ecx,[ebx+DDPB_OffX] ; check offset X
jne TXTSetOffset2 ; offset changed
cmp edx,[ebx+DDPB_OffY] ; check offset Y
je TXTSetOffset8 ; offset not changed
; ------------- Push registers
TXTSetOffset2: push eax ; push EAX
push ecx ; push ECX
push edx ; push EDX
; ------------- Correct cursor position X
mov eax,ecx ; EAX <- offset X
sub eax,[ebx+DDPB_OffX] ; EAX <- shift X
sub [ebx+DDPB_CurPosX],eax ; correct cursor X
; ------------- Correct cursor position Y
mov eax,edx ; EAX <- offset Y
sub eax,[ebx+DDPB_OffY] ; EAX <- shift Y
sub [ebx+DDPB_CurPosY],eax ; correct cursor Y
; ------------- Store new offset
mov [ebx+DDPB_OffX],ecx ; new offset X
mov [ebx+DDPB_OffY],edx ; new offset Y
; ------------- Calculate new offset (-> EAX)
mov eax,[ebx+DDPB_VirtW] ; EAX <- characters per row
mul edx ; recalc Y offset to characters
add eax,ecx ; EAX <- add X coordinate
; ------------- Set new display offset
mov cl,12 ; CL <- register number
call DispOutWord ; set memory offset
; ------------- Calculate new memory address
shl eax,1 ; EAX <- offset in videomemory
add eax,[ebx+DDPB_BaseAddr] ; EAX <- address in memory
mov [ebx+DDPB_Addr],eax ; store new memory address
; ------------- Pop registers
pop edx ; pop EDX
pop ecx ; pop ECX
pop eax ; pop EAX
TXTSetOffset8: ret
; -----------------------------------------------------------------------------
; Set cursor position
; -----------------------------------------------------------------------------
; INPUT: EBX = display driver
; ECX = cursor column
; EDX = cursor row
; -----------------------------------------------------------------------------
; ------------- Check if cursor position changed
TXTSetCursor: cmp ecx,[ebx+DDPB_CurPosX] ; check cursor column
jne TXTSetCursor2 ; cursor changed
cmp edx,[ebx+DDPB_CurPosY] ; check cursor row
je TXTSetCursor8 ; cors not changed
; ------------- Push registers
TXTSetCursor2: push eax ; push EAX
push ecx ; push ECX
push edx ; push EDX
; ------------- Store new cursor position
mov [ebx+DDPB_CurPosX],ecx ; new cursor position X
mov [ebx+DDPB_CurPosY],edx ; new cursor position Y
; ------------- Calculate cursor offset
mov eax,[ebx+DDPB_VirtW] ; EAX <- characters per row
mul edx ; recalc Y offset to characters
add eax,ecx ; EAX <- add X coordinate
; ------------- Set new cursor offset
mov cl,14 ; CL <- register number
call DispOutWord ; set memory offset
; ------------- Pop registers
pop edx ; pop EDX
pop ecx ; pop ECX
pop eax ; pop EAX
TXTSetCursor8: ret
; -----------------------------------------------------------------------------
; Set cursor size
; -----------------------------------------------------------------------------
; INPUT: EBX = display driver
; ECX = top scan line
; EDX = bottom scan line
; -----------------------------------------------------------------------------
; ------------- Check if cursor size changed
TXTSetCurSize: cmp ecx,[ebx+DDPB_CurSizeT] ; check top scan line
jne TXTSetCurSize2 ; cursor size changed
cmp edx,[ebx+DDPB_CurSizeB] ; check bottom scan line
je TXTSetCurSize8 ; cursor size not changed
; ------------- Store new cursor size
TXTSetCurSize2: mov [ebx+DDPB_CurSizeT],ecx ; store top scan line
mov [ebx+DDPB_CurSizeB],edx ; store bottom scan line
; ------------- Check if cursor is off
test byte [ebx+DDPB_Flags],DDPB_CURON ; is cursor on?
jz TXTSetCurSize8 ; cursor is off
; ------------- Push registers
push eax ; push EAX
push ecx ; push ECX
; ------------- Set new cursor size
mov al,dl ; AL <- bottom scan line
mov ah,cl ; AH <- top scan line
mov cl,10 ; CL <- register of cursor size
call DispOutWord ; set cursor size
; ------------- Pop registers
pop ecx ; pop ECX
pop eax ; pop EAX
TXTSetCurSize8: ret
; -----------------------------------------------------------------------------
; Set cursor visible
; -----------------------------------------------------------------------------
; INPUT: AL = 0 cursor off, 1 cursor on, 2 flip state
; EBX = display driver
; -----------------------------------------------------------------------------
; ------------- Push registers
TXTSetVisible: push eax ; push EAX
push ecx ; push ECX
; ------------- Check if cursor state changed
test byte [ebx+DDPB_Flags],DDPB_CURON ; is cursor ON?
setnz ah ; AH <- 1 cursor on, AL <- cursor off
cmp al,ah ; cursor state changed?
je TXTSetVisible8 ; cursor state not changed
; ------------- Change flag of cursor visibility
xor byte [ebx+DDPB_Flags],DDPB_CURON ; change flag
; ------------- Set new cursor state
or ah,ah ; was cursor on?
mov ax,2020h ; AX <- size of cursor off
jnz TXTSetVisible4 ; cursor was on
mov al,[ebx+DDPB_CurSizeB] ; AL <- bottom scan line
mov ah,[ebx+DDPB_CurSizeT] ; AH <- top scan line
TXTSetVisible4: mov cl,10 ; CL <- register of cursor size
call DispOutWord ; set cursor size
; ------------- Pop registers
TXTSetVisible8: pop ecx ; pop ECX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Load text font
; -----------------------------------------------------------------------------
; INPUT: AL = font bank (0..3 for EGA, 0..7 for VGA)
; AH = font height (1..32, 0=default)
; EBX = display driver
; 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)
; -----------------------------------------------------------------------------
TXTLoadFont: ret
; -----------------------------------------------------------------------------
; Set font bank
; -----------------------------------------------------------------------------
; INPUT: EBX = display driver
; 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)
; -----------------------------------------------------------------------------
TXTSetFont: ret
; -----------------------------------------------------------------------------
; Set border color
; -----------------------------------------------------------------------------
; INPUT: AL = border color (0..15 for 16-color or 0..255 for 256-color)
; EBX = display driver
; -----------------------------------------------------------------------------
TXTSetBorder: ret
; -----------------------------------------------------------------------------
; Set CGA palette (only CGA videomode)
; -----------------------------------------------------------------------------
; INPUT: AL = palette set (0=red/green/yellow, 1=cyan/magenta/white)
; EBX = display driver
; -----------------------------------------------------------------------------
TXTSetPalCGA: ret
; -----------------------------------------------------------------------------
; Set EGA palette
; -----------------------------------------------------------------------------
; INPUT: AL = start index (0..16, last entry is border color)
; EBX = display driver
; 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.
; -----------------------------------------------------------------------------
TXTSetPalEGA: ret
; -----------------------------------------------------------------------------
; Set VGA palette
; -----------------------------------------------------------------------------
; INPUT: AL = start index (0..255)
; EBX = display driver
; 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.
; -----------------------------------------------------------------------------
TXTSetPalVGA: ret
; -----------------------------------------------------------------------------
; Set indexed palette
; -----------------------------------------------------------------------------
; INPUT: EAX = index table (array of bytes with value 0 to 255)
; EBX = display driver
; 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.
; -----------------------------------------------------------------------------
TXTSetPalInx: ret
; -----------------------------------------------------------------------------
; Fill-up region
; -----------------------------------------------------------------------------
; INPUT: AL = color (in graphics mode) or character (in text mode)
; AH = color attribute (only in text mode)
; EBX = display driver
; 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.
; -----------------------------------------------------------------------------
TXTFillUp: ret
; -----------------------------------------------------------------------------
; Move region
; -----------------------------------------------------------------------------
; INPUT: EAX = destination offset in videomemory
; EBX = display driver
; 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.
; -----------------------------------------------------------------------------
TXTMove: ret
; -----------------------------------------------------------------------------
; Get buffer size
; -----------------------------------------------------------------------------
; INPUT: EBX = display driver
; ECX = region width
; EDX = region height
; OUTPUT: EAX = buffer size
; -----------------------------------------------------------------------------
TXTBufferSize: ret
; -----------------------------------------------------------------------------
; Get region
; -----------------------------------------------------------------------------
; INPUT: EAX = destination buffer
; EBX = display driver
; 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.
; -----------------------------------------------------------------------------
TXTGetRegion: ret
; -----------------------------------------------------------------------------
; Set region
; -----------------------------------------------------------------------------
; INPUT: EAX = source buffer
; EBX = display driver
; 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.
; -----------------------------------------------------------------------------
TXTSetRegion: ret
; -----------------------------------------------------------------------------
; Set text region with color
; -----------------------------------------------------------------------------
; INPUT: EAX = source buffer (only characters without attributes)
; EBX = display driver
; 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.
; -----------------------------------------------------------------------------
TXTSetRegCol: ret
; -----------------------------------------------------------------------------
; Set region with color mask
; -----------------------------------------------------------------------------
; INPUT: EAX = source buffer
; EBX = display driver
; 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.
; -----------------------------------------------------------------------------
TXTSetColMask: ret
; -----------------------------------------------------------------------------
; Set region with mask
; -----------------------------------------------------------------------------
; INPUT: EAX = source buffer with data and bit mask
; EBX = display driver
; 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.
; -----------------------------------------------------------------------------
TXTSetMasked: ret
; -----------------------------------------------------------------------------
; Set region with alpha
; -----------------------------------------------------------------------------
; INPUT: EAX = source buffer with data and alpha
; EBX = display driver
; 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).
; -----------------------------------------------------------------------------
TXTSetAlpha: ret
%ifdef AAAA
; -----------------------------------------------------------------------------
; Initialize driver parameter block
; -----------------------------------------------------------------------------
; ------------- Driver pointer
TXTInit: mov ebx,TXTDrvDDPB ; EBX <- driver parameter block
; ------------- Addresses
movzx eax,word [VideoSegm] ; video segment
shl eax,4 ; transfer segment to address
add eax,SYSTEM_ADDR ; + system address
mov [ebx+DDPB_Addr],eax ; virtual address
mov [TXTDrvDDPB2+RES_Start],eax ; start address
; ------------- Control port
mov eax,3b4h ; EAX <- video port for MDA
cmp byte [VideoSegm+1],0b0h ; MDA videomode?
je TXTInit2 ; MDA videomode
mov al,0d4h ; EAX <- video port for CGA
TXTInit2: mov [ebx+DDPB_Port],eax ; control port
; ------------- Display dimension
movzx eax,byte [VideoCols] ; EAX <- number of columns
mov [ebx+DDPB_Dim+DIM_W],eax ; number of columns
shl eax,1 ; EAX <- number of columns * 2
mov [ebx+DDPB_RowBytes],eax ; lenght of row in bytes
movzx eax,byte [VideoRows] ; EDX <- number of rows
mov [ebx+DDPB_Dim+DIM_H],eax ; number of rows
; ------------- Cursor position
movzx eax,byte [VideoPos] ; EAX <- current position
mov [ebx+DDPB_CurPos+POS_X],eax ; cursor position
movzx eax,byte [VideoRow] ; EAX <- current row
mov [ebx+DDPB_CurPos+POS_Y],eax ; cursor row
; ------------- Current color
mov al,[VideoCol] ; AL <- current color
mov [ebx+DDPB_Color],al ; current color
; ------------- Install driver
call DrvLstInsert ; insert driver into list
ret
; -----------------------------------------------------------------------------
; Get information
; -----------------------------------------------------------------------------
; INPUT: AL = info code
; EBX = display driver parameter block
; OUTPUT: EAX = info value
; -----------------------------------------------------------------------------
; ------------- Jump to service
TXTInfo: cmp al,DCHOUT_GETMAX ; check maximal information code
jae TXTInfoErr ; error
movzx eax,al ; EAX <- info code
shl eax,2 ; EAX <- offset in jump table
add eax,[ebx+DDPB_InfoTab] ; EAX <- jump address
jmp dword [eax] ; jump to service
; ------------- Get interface version
TXTGetVer: mov al,0
TXTInfoErr: ret
; ------------- Get window width
TXTGetW: mov eax,[ebx+DDPB_Dim+DIM_W] ; EAX <- display width
ret
; ------------- Get window height
TXTGetH: mov eax,[ebx+DDPB_Dim+DIM_H] ; EAX <- display height
ret
; ------------- Get cursor position X
TXTGetCurX: mov eax,[ebx+DDPB_CurPos+POS_X] ; EAX <- cursor position X
ret
; ------------- Get cursor position Y
TXTGetCurY: mov eax,[ebx+DDPB_CurPos+POS_Y] ; EAX <- cursor position Y
ret
; ------------- Get cursor "on" flag (1=on, 0=off)
TXTGetCurON: test byte [ebx+DDPB_Flags],DDPB_CURSON ; test cursor on flag
setnz al ; EAX <- 1 if flag is on
ret
; ------------- Get cursor "update" flag (1=on,0=off)
TXTGetUpd: test byte [ebx+DDPB_Flags],DDPB_CURSUPD ; test update flag
setnz al ; EAX <- 1 if flag is on
ret
; ------------- Get line height
TXTGetSizH: movzx eax,byte [ebx+DDPB_LineH] ; EAX <- line height
ret
; ------------- Get cursor top scan line
TXTGetSizT: movzx eax,byte [ebx+DDPB_CurSizeT] ; EAX <- cursor top line
ret
; ------------- Get cursor bottom scan line
TXTGetSizB: movzx eax,byte [ebx+DDPB_CurSizeB] ; EAX<-cursor bottom line
ret
; ------------- Get color
TXTGetColor: movzx eax,byte [ebx+DDPB_Color] ; EAX <- color
ret
; -----------------------------------------------------------------------------
; Setup display
; -----------------------------------------------------------------------------
; INPUT: AL = setup code
; EBX = display driver parameter block
; ECX = parameter 1
; EDX = parameter 2
; OUTPUT: CY = error, only for test/set window dimension
; -----------------------------------------------------------------------------
; ------------- Jump to service
TXTSetup: push eax ; push EAX
cmp al,DCHOUT_SETMAX ; check maximal setup code
jae short TXTSetupErr ; error
movzx eax,al ; EAX <- setup code
shl eax,2 ; EAX <- offset in jump table
add eax,[ebx+DDPB_SetupTab] ; EAX <- jump address
mov eax,[eax] ; EAX <- jump address
xchg eax,[esp] ; [ESP] <- jump, EAX <- pop EAX
ret ; jump to service
TXTSetupErr: pop eax ; pop EAX
TXTSetupRet: ret
; ------------- Test window dimension (ECX, EDX)
TXTSetTest:
; !!! TODO
stc ; set error flag
ret
; ------------- Set new window dimension (ECX, EDX)
TXTSetResize:
; !!! TODO
stc ; set error flag
ret
; ------------- Set cursor on
TXTCurOn: bts dword [ebx+DDPB_Flags],DDPB_CURSON_BIT ; cursor is on?
jnc short TXTCurSizeUpd ; update cursor size
ret
; ------------- Set cursor off
TXTCurOff: btr dword [ebx+DDPB_Flags],DDPB_CURSON_BIT ; cursor is off?
jc short TXTCurSizeUpd ; update cursor size
ret
; ------------- Set cursor update on
TXTUpdOn: bts dword [ebx+DDPB_Flags],DDPB_CURSUP_BIT ; update is on?
jnc short TXTSetCur4 ; update cursor position
ret
; ------------- Set cursor update off
TXTUpdOff: and byte [ebx+DDPB_Flags],~DDPB_CURSUPD ; set update off
ret
; ------------- Set cursor size (CL top, DL bottom)
TXTSetSize mov [ebx+DDPB_CurSizeT],cl ; set top scan line
mov [ebx+DDPB_CurSizeB],dl ; set bottom scan line
; TXTCurSizeUpd must follow
; -----------------------------------------------------------------------------
; Update cursor size
; -----------------------------------------------------------------------------
; INPUT: EBX = display driver parameter block
; NOTES: If start is greater than end, cursor will be disabled.
; -----------------------------------------------------------------------------
; It must follow after TXTSetSize
; ------------- Push registers
TXTCurSizeUpd: push eax ; push EAX
push ecx ; push ECX
; ------------- Check if cursor is off
test byte [ebx+DDPB_Flags],DDPB_CURSON ; cursor is on?
jz TXTCurSizeUpd2 ; cursor is on
; ------------- Get cursor size
mov ax,[ebx+DDPB_CurSize] ; AL <- bottom, AH <- top line
; ------------- Cursor off
cmp al,ah ; start is greater than end?
jae TXTCurSizeUpd4 ; cursor is OK
TXTCurSizeUpd2: mov ax,2020h ; MDA flag - cursor is off
; ------------- Set cursor address
TXTCurSizeUpd4: mov cl,10 ; CL <- register of cursor size
call DispOutWordLock ; set cursor address
; ------------- Pop registers
pop ecx ; pop ECX
pop eax ; pop EAX
TXTSetCur6: ret
; -----------------------------------------------------------------------------
; Set cursor position
; -----------------------------------------------------------------------------
; INPUT: EBX = display driver parameter block
; ECX = cursor column
; EDX = cursor row
; -----------------------------------------------------------------------------
; ------------- Check if cursor position changed
TXTSetCur: cmp ecx,[ebx+DDPB_CurPos+POS_X] ; check cursor column
jne short TXTSetCur2 ; cursor changed
cmp edx,[ebx+DDPB_CurPos+POS_Y] ; check cursor row
je short TXTSetCur6 ; cursor not changed
; ------------- Set new cursor position
TXTSetCur2: mov [ebx+DDPB_CurPos+POS_X],ecx ; set cursor column
mov [ebx+DDPB_CurPos+POS_Y],edx ; set cursor row
TXTSetCur4: jmp TXTCurUpdate ; update cursor position
; -----------------------------------------------------------------------------
; Set color
; -----------------------------------------------------------------------------
; INPUT: AL = color
; EBX = display driver parameter block
; -----------------------------------------------------------------------------
TXTSetColor: mov [ebx+DDPB_Color],al ; set color
ret
; -----------------------------------------------------------------------------
; Write one character
; -----------------------------------------------------------------------------
; INPUT: AL = character
; EBX = display driver parameter block
; -----------------------------------------------------------------------------
; ------------- Push registers
TXTWriteChr: push eax ; push EAX
push edx ; push EDX
push edi ; push EDI
xchg eax,edi ; EDI <- push EAX
; ------------- Get current row (-> EAX)
mov eax,[ebx+DDPB_CurPos+POS_Y] ; EAX <- current row
cmp eax,[ebx+DDPB_Dim+DIM_H] ; check row
jae TXTWriteChr4 ; invalid row
mul dword [ebx+DDPB_RowBytes] ; EAX <- recalc row to bytes
; ------------- Get current column (-> EDX)
mov edx,[ebx+DDPB_CurPos+POS_X] ; EDX <- current column
cmp edx,[ebx+DDPB_Dim+DIM_W] ; check column
jae TXTWriteChr4 ; invalid column
; ------------- Calculate address in videomemory (-> EDI)
shl edx,1 ; EDX <- recalc column to bytes
add eax,edx ; EAX <- offset in videomemory
add eax,[ebx+DDPB_Addr] ; EAX <- address
xchg eax,edi ; EDI <- address, AL <- character
; ------------- Store character into videomemory
mov ah,[ebx+DDPB_Color] ; AH <- color of text
stosw ; store character into videomemory
; ------------- Pop registers
TXTWriteChr4: pop edi ; pop EDI
pop edx ; pop EDX
pop eax ; pop EAX
; ------------- Shift cursor position
inc dword [ebx+DDPB_CurPos+POS_X] ; increase column
; TXTCurUpdate must follow.
; -----------------------------------------------------------------------------
; Update cursor
; -----------------------------------------------------------------------------
; NOTES: Cursor can be moved into invalid position (it is not checked).
; -----------------------------------------------------------------------------
; It must follow after TXTWriteChr.
; ------------- Check if auto update cursor position
TXTCurUpdate: test byte [ebx+DDPB_Flags],DDPB_CURSUPD ; update cursor?
jz TXTCurUpdate8 ; don't update cursor
; ------------- Push registers
push eax ; push EAX
push ecx ; push ECX
push edx ; push EDX
; ------------- Set cursor position
mov eax,[ebx+DDPB_CurPos+POS_Y] ; EAX <- current row
mul dword [ebx+DDPB_RowBytes] ; EAX <- recalc row to bytes
shr eax,1 ; EAX <- offset of row
add eax,[ebx+DDPB_CurPos+POS_X] ; add current column
mov cl,14 ; CL <- register of cursor address
call DispOutWordLock ; set cursor address
; ------------- Pop registers
pop edx ; pop EDX
pop ecx ; pop ECX
pop eax ; pop EAX
TXTCurUpdate8: ret
; -----------------------------------------------------------------------------
; Write text string
; -----------------------------------------------------------------------------
; INPUT: EBX = display driver parameter block
; ECX = length of the text
; EDX = text to display
; -----------------------------------------------------------------------------
; ------------- Push registers
TXTWriteStr: push eax ; push EAX
push ecx ; push ECX
push edx ; push EDX
push esi ; push ESI
push edi ; push EDI
mov esi,edx ; ESI <- text to display
; ------------- Get current row (-> EAX)
mov eax,[ebx+DDPB_CurPos+POS_Y] ; EAX <- current row
cmp eax,[ebx+DDPB_Dim+DIM_H] ; check row
jae TXTWriteStr8 ; invalid row
mul dword [ebx+DDPB_RowBytes] ; EAX <- recalc row to bytes
; ------------- Get current column (-> EDX) and limit text length (-> ECX)
mov edi,[ebx+DDPB_Dim+DIM_W] ; EDI <- display width
mov edx,[ebx+DDPB_CurPos+POS_X] ; EDX <- current column
or edx,edx ; is position positive?
js short TXTWriteStr8 ; negative position is invalid
sub edi,edx ; EDI <- remaining columns
cmp edi,ecx ; check length of text
jg TXTWriteStr2 ; text length is OK
mov ecx,edi ; ECX <- limit text length
TXTWriteStr2: or ecx,ecx ; check length of text
jle TXTWriteStr8 ; invalid length of text
; ------------- Calculate address in videomemory (-> EDI)
shl edx,1 ; EDX <- recalc column to bytes
add eax,edx ; EAX <- offset in videomemory
add eax,[ebx+DDPB_Addr] ; EAX <- address
xchg eax,edi ; EDI <- address
; ------------- Move text into videomemory
mov ah,[ebx+DDPB_Color] ; AH <- color of text
TXTWriteStr4: lodsb ; load character
stosw ; store character into videomemory
loop TXTWriteStr4 ; next character
; ------------- Pop registers
TXTWriteStr8: pop edi ; pop EDI
pop esi ; pop ESI
pop edx ; pop EDX
pop ecx ; pop ECX
pop eax ; pop EAX
; ------------- Shift cursor position
add dword [ebx+DDPB_CurPos+POS_X],ecx ; increase column
jmp short TXTCurUpdate ; update cursor
; -----------------------------------------------------------------------------
; Fill-up region (from cursor position)
; -----------------------------------------------------------------------------
; INPUT: AL = character
; EBX = display driver parameter block
; ECX = width of region
; EDX = height of region
; -----------------------------------------------------------------------------
; ------------- Push registers
TXTFillUp: pusha ; push all registers
mov esi,edx ; ESI <- height of region
xchg eax,edi ; EDI <- character
; ------------- Get current row (-> EAX) and limit height (-> ESI)
mov ebp,[ebx+DDPB_Dim+DIM_H] ; EBP <- display height
mov eax,[ebx+DDPB_CurPos+POS_Y] ; EAX <- current row
or eax,eax ; is row positive?
js short TXTFillUp6 ; negative row is invalid
sub ebp,eax ; EBP <- remaining rows
cmp ebp,esi ; check height of region
jg short TXTFillUp2 ; height is OK
mov esi,ebp ; ESI <- limit height of region
TXTFillUp2: or esi,esi ; check height of region
jle short TXTFillUp9 ; invalid height of region
mul dword [ebx+DDPB_RowBytes] ; EAX <- recalc row to bytes
; ------------- Get current column (-> EDX) and limit width (-> ECX)
mov ebp,[ebx+DDPB_Dim+DIM_W] ; EBP <- display width
mov edx,[ebx+DDPB_CurPos+POS_X] ; EDX <- current column
or edx,edx ; is position positive?
js short TXTFillUp9 ; negative position is invalid
sub ebp,edx ; EBP <- remaining columns
cmp ebp,ecx ; check width of region
jg short TXTFillUp3 ; width of region is OK
mov ecx,ebp ; ECX <- limit width of region
TXTFillUp3: or ecx,ecx ; check width of region
jle short TXTFillUp9 ; invalid width of region
; ------------- Calculate address in videomemory (-> EDI)
shl edx,1 ; EDX <- recalc column to bytes
add eax,edx ; EAX <- offset in videomemory
add eax,[ebx+DDPB_Addr] ; EAX <- address
xchg eax,edi ; EDI <- address, AL <- character
; ------------- Prepare registers
movzx eax,al ; EAX <- character
mov ah,[ebx+DDPB_Color] ; AH <- color of text
mov edx,[ebx+DDPB_RowBytes] ; EDX <- bytes per row
sub edx,ecx ; subtract number of characters
sub edx,ecx ; EDX <- address increment
; ------------- Check if it is vertical line (width = 1)
cmp ecx,byte 1 ; width of region = 1?
je short TXTFillUp8 ; fill-up vertical line
; ------------- Prepare double-character (-> EAX)
mov ebp,eax ; EBP <- character
shl eax,16 ; EAX <- character * 16
or eax,ebp ; EAX <- 2 characters
; ------------- Check width of region
mov ebp,ecx ; EBP <- number of characters
shr ebp,1 ; EBP <- characters / 2
jnc short TXTFillUp7 ; even characters
; ------------- Check odd/even address
bt edi,1 ; odd address?
jnc short TXTFillUp5 ; even address
; ------------- Fill-up region with odd characters and odd address
TXTFillUp4: mov ecx,ebp ; ECX <- number of characters/2
stosw ; fill-up odd character
rep stosd ; fill-up one row
add edi,edx ; EDI <- next row
dec esi ; count height of region
jnz short TXTFillUp4 ; next row
popa ; pop all registesr
ret
; ------------- Fill-up region with odd characters and even address
TXTFillUp5: mov ecx,ebp ; ECX <- number of characters/2
rep stosd ; fill-up one row
stosw ; fill-up odd character
add edi,edx ; EDI <- next row
dec esi ; count height of region
jnz short TXTFillUp5 ; next row
TXTFillUp6: popa ; pop all registesr
ret
; ------------- Fill-up region with even characters
TXTFillUp7: mov ecx,ebp ; ECX <- number of characters/2
rep stosd ; fill-up one row
add edi,edx ; EDI <- next row
dec esi ; count height of region
jnz short TXTFillUp7 ; next row
popa ; pop all registesr
ret
; ------------- Fill-up vertical line
TXTFillUp8: stosw ; store one character
add edi,edx ; EDI <- next row
dec esi ; count height of region
jnz short TXTFillUp8 ; next row
; ------------- Pop registers
TXTFillUp9: popa ; pop all registesr
ret
; -----------------------------------------------------------------------------
; Copy region (into cursor position)
; -----------------------------------------------------------------------------
; INPUT: EAX = source column
; EBX = display driver parameter block
; ECX = width of region
; EDX = height of region
; ESI = source row
; -----------------------------------------------------------------------------
; ------------- Push registers
TXTCopy: pusha ; push all registers
; ------------- Limit width of region from source column (-> ECX)
or eax,eax ; check source column
js short TXTCopy6 ; source column is not valid
mov ebp,[ebx+DDPB_Dim+DIM_W] ; EBP <- display width
sub ebp,eax ; EBP <- remaining columns
cmp ebp,ecx ; check width of region
jg short TXTCopy1 ; width of region is OK
mov ecx,ebp ; ECX <- limit width of region
; ------------- Limit height of region from source row (-> EBP)
TXTCopy1: or esi,esi ; check source row
js short TXTCopy6 ; source row is not valid
mov ebp,[ebx+DDPB_Dim+DIM_H] ; EBP <- display height
sub ebp,esi ; EBP <- remaining rows
cmp ebp,edx ; check height of region
jl short TXTCopy2 ; limit height of region
mov ebp,edx ; EBP <- height of region is OK
; ------------- Calculate source address (-> ESI)
TXTCopy2: shl eax,1 ; EAX <- recalc column to bytes
xchg eax,esi ; EAX <- source row, ESI <- column*2
mul dword [ebx+DDPB_RowBytes] ; EAX <- recalc row to bytes
add esi,eax ; ESI <- offset in videomemory
add esi,[ebx+DDPB_Addr] ; ESI <- source address
; ------------- Get destination row (-> EAX) and limit height (-> EBP)
mov edx,[ebx+DDPB_Dim+DIM_H] ; EDX <- display height
mov eax,[ebx+DDPB_CurPos+POS_Y] ; EAX <- current row
or eax,eax ; check destination row
js short TXTCopy6 ; destination row is not valid
sub edx,eax ; EDX <- remaining rows
cmp edx,ebp ; check height of region
jg short TXTCopy3 ; height is OK
mov ebp,edx ; EBP <- limit height of region
TXTCopy3: or ebp,ebp ; check height of region
jle short TXTCopy6 ; invalid height of region
mul dword [ebx+DDPB_RowBytes] ; EAX <- recalc row to bytes
; ------------- Get destination column (-> EDX) and limit width (-> ECX)
mov edi,[ebx+DDPB_Dim+DIM_W] ; EDI <- display width
mov edx,[ebx+DDPB_CurPos+POS_X] ; EDX <- current column
or edx,edx ; check destination column
js short TXTCopy6 ; destination column is not valid
sub edi,edx ; EDI <- remaining columns
cmp edi,ecx ; check width of region
jg short TXTCopy4 ; width of region is OK
mov ecx,edi ; ECX <- limit width of region
TXTCopy4: or ecx,ecx ; check width of region
jle short TXTCopy6 ; invalid width of region
; ------------- Calculate destination address (-> EDI)
shl edx,1 ; EDX <- recalc column to bytes
add eax,edx ; EAX <- offset in videomemory
add eax,[ebx+DDPB_Addr] ; EAX <- address
xchg eax,edi ; EDI <- destination address
; ------------- Prepare registers
mov edx,[ebx+DDPB_RowBytes] ; EDX <- bytes per row
sub edx,ecx ; subtract number of characters
sub edx,ecx ; EDX <- address increment
; ------------- Compare source and destination address
cmp edi,esi ; source and destination is identical?
je TXTCopy6 ; no operation
ja TXTCopy8 ; direction DOWN
; ------------- Direction UP (destination is before source)
xchg eax,ecx ; EAX <- width of region
shr eax,1 ; EAX <- width / 2
jc TXTCopy7 ; odd width
; ------------- Direction UP with even width
TXTCopy5: mov ecx,eax ; ECX <- width of region/2
rep movsd ; move one row
add esi,edx ; ESI <- shift source address
add edi,edx ; EDI <- shift destination address
dec ebp ; counter of rows
jnz TXTCopy5 ; next row
TXTCopy6: popa ; pop all registers
ret
; ------------- Direction UP width odd width
TXTCopy7: mov ecx,eax ; ECX <- width of region/2
rep movsd ; move one row
movsw ; move odd character
add esi,edx ; ESI <- shift source address
add edi,edx ; EDI <- shift destination address
dec ebp ; counter of rows
jnz TXTCopy7 ; next row
popa ; pop all registers
ret
; ------------- Direction DOWN (destination is after source)
TXTCopy8: mov eax,[ebx+DDPB_RowBytes] ; EAX <- bytes per row
push edx ; push EDX
mul ebp ; EAX <- height in bytes
pop edx ; pop EDX
sub eax,edx ; EAX <- behind last row
dec eax ; EAX - 1
dec eax ; EAX <- offset of last character
add esi,eax ; ESI <- source of last character
add edi,eax ; EDI <- destination of last character
std ; direction down
xchg eax,ecx ; EAX <- width of region
; ------------- Transfer with direction DOWN
TXTCopy9: mov ecx,eax ; ECX <- width of region
rep movsw ; move one row
sub esi,edx ; ESI <- shift source address
sub edi,edx ; EDI <- shift destination address
dec ebp ; counter of rows
jnz TXTCopy9 ; next row
cld ; direction up
popa ; pop all registers
ret
; -----------------------------------------------------------------------------
; Set font
; -----------------------------------------------------------------------------
; INPUT: EBX = display driver parameter block
; EDX = font address
; -----------------------------------------------------------------------------
TXTSetFont: ret
; -----------------------------------------------------------------------------
; Set EGA palettes
; -----------------------------------------------------------------------------
; INPUT: EBX = display driver parameter block
; EDX = palettes (16 registers)
; -----------------------------------------------------------------------------
TXTSetPal: ret
%endif
; -----------------------------------------------------------------------------
; Data
; -----------------------------------------------------------------------------
DATA_SECTION
TXTDispTxt: db 'Text display'
TXTDispTxt2:
; ------------- Text display driver DDPB
align 8, db 0
TXTDrvDDPB: RBTREENODE ; red-black tree node
SPINLOCK ; driver lock
db 0,DRV_OUT_TXT ; index, class and subclass
db DPB_STATIC,0 ; flags and class flags
db 0,0,0,1 ; driver version
dd DrvVendorName ; pointer to vendor name
dd TXTDrvName ; pointer to driver name
dd EmptySText ; pointer to model name
dd EmptySText ; modul path
dd TXTDrvDDFB ; pointer to function table
TXTDrvDDPB1: LINKEDLIST TXTDrvDDPB2,TXTDrvDDPB2 ; resource list
dd DDPB_CURON+DDPB_CANTEXT ; flags
dd 8000h ; memory size
dd 0,0 ; cursor position
dd 14,15 ; cursor size
dd 0,0 ; current display offset
dd SYSTEM_ADDR+0b8000h ; memory address
dd TXTDrvUniMap ; mapping from Unicode
dd EGAFontBuff ; font buffer (128*32 = 4 KB)
dd 0 ; ...padding
dd 80,25*4 ; virtual dimension
dd 80,25 ; display dimension
dd 8,16 ; font dimension
dd 60 ; vertical frequency
db VMODE_TEXTCOLOR ; memory mode
db 16 ; total bits per point
db 16 ; bits in one plane
db 1 ; color planes
dd SYSTEM_ADDR+0b8000h ; memory base address
dd 80*25*2 ; size of display page
dd 80*25*2*3 ; maximal offset
dd 80*2 ; bytes per scan line
dd 0 ; size of one plane
dd 3d4h ; control port
times DISPMAXREG db -1 ; cache of display registers
align 4, db 0
TXTDrvDDPB2: LINKEDLIST TXTDrvDDPB1,TXTDrvDDPB1 ; resource list
dd SYSTEM_ADDR+0b8000h ; start of resource
dw 8000h-1 ; size of resource-1
db RES_MEM ; resource type
db RES_STATIC+RES_AUTO ; flags
TXTDrvName: STEXT 'Text display'
; ------------- Test display interface DDFB
align 4, db 0
TXTDrvDDFB: dd DrvStdFuncOK ; device detection
dd DrvStdFuncOK ; device initialization
dd DrvStdFuncERR ; device deinitialization
dd DrvStdFuncERR ; enable device
dd DrvStdFuncERR ; disable device
dd TXTEnumMode ; enumerate videomodes
dd TXTTestMode ; test videomode
dd TXTSetMode ; set videomode
dd TXTClear ; clear screen
dd TXTSetOffset ; set memory offset
dd TXTSetCursor ; set cursor position
dd TXTSetCurSize ; set cursor size
dd TXTSetVisible ; set cursor visible
dd TXTLoadFont ; load text font
dd TXTSetFont ; set font bank
dd TXTSetBorder ; set border color
dd TXTSetPalCGA ; set CGA palette
dd TXTSetPalEGA ; set EGA palette
dd TXTSetPalVGA ; set VGA palette
dd TXTSetPalInx ; set indexed palette
dd TXTFillUp ; fill-up region
dd TXTMove ; move region
dd TXTBufferSize ; get buffer size
dd TXTGetRegion ; get region
dd TXTSetRegion ; set region
dd TXTSetRegCol ; set text region with color
dd TXTSetColMask ; set region with color mask
dd TXTSetMasked ; set region with mask
dd TXTSetAlpha ; set region with alpha
; ------------- Display videomode 1: 40x25 text color, 8 lines per row
DispMode1Reg: db 12 ; number of registers
db 56 ; 0: horizontal total
db 40 ; 1: horizontal displayed
db 45 ; 2: horizontal sync position
db 10 + 0*B4 ; 3: B0..B3=hsync/B4..B7=vsync width
db 31 ; 4: start horizontal retrace
db 6 ; 5: end horizontal retrace
db 25 ; 6: vertical displayed
db 28 ; 7: vertical pulse width - 1
db 2 ; 8: interlace mode
db 7 ; 9: maximum scan lines
db 6 ; 10: first cursor scanline
db 7 ; 11: last cursor scanline
; ------------- Display videomode 3: 80x25 text color, 8 lines per row
DispMode3Reg: db 12 ; number of registers
db 113 ; 0: horizontal total
db 80 ; 1: horizontal displayed
db 90 ; 2: horizontal sync position
db 10 + 0*B4 ; 3: B0..B3=hsync/B4..B7=vsync width
db 31 ; 4: start horizontal retrace
db 6 ; 5: end horizontal retrace
db 25 ; 6: vertical displayed
db 28 ; 7: vertical pulse width - 1
db 2 ; 8: interlace mode
db 7 ; 9: maximum scan lines
db 6 ; 10: first cursor scanline
db 7 ; 11: last cursor scanline
; ------------- Display videomode 4: 320x240 graphic 4-color CGA
DispMode4Reg: db 12 ; number of registers
db 56 ; 0: horizontal total
db 40 ; 1: horizontal displayed
db 32 ; 2: horizontal sync position
db 10 + 0*B4 ; 3: B0..B3=hsync/B4..B7=vsync width
db 127 ; 4: start horizontal retrace
db 6 ; 5: end horizontal retrace
db 100 ; 6: vertical displayed
db 112 ; 7: vertical pulse width - 1
db 2 ; 8: interlace mode
db 1 ; 9: maximum scan lines
db 6 ; 10: first cursor scanline
db 7 ; 11: last cursor scanline
; ------------- Display videomode 7: 80x25 text mono, 8 lines per row
DispMode7Reg: db 12 ; number of registers
db 97 ; 0: horizontal total
db 80 ; 1: horizontal displayed
db 82 ; 2: horizontal sync position
db 15 + 0*B4 ; 3: B0..B3=hsync/B4..B7=vsync width
db 25 ; 4: start horizontal retrace
db 2 ; 5: end horizontal retrace
db 25 ; 6: vertical displayed
db 25 ; 7: vertical pulse width - 1
db 2 ; 8: interlace mode
db 13 ; 9: maximum scan lines
db 11 ; 10: first cursor scanline
db 12 ; 11: last cursor scanline
; ------------- Display videomode on VGA: 640x350 graphic 16 colors
DispMode14Reg: db 12 ; number of registers
db 91 ; 0: horizontal total
db 79 ; 1: last displayed character
db 83 ; 2: start of horizontal sync
db 55 ; 3: end of horizontal sync
db 82 ; 4: start horizontal retrace
db 0 ; 5: end horizontal retrace
db 108 ; 6: vertical displayed LOW
db 31 ; 7: vertical pulse width - 1
db 0 ; 8: interlace mode
db 0 ; 9: maximum scan lines
db 0 ; 10: first cursor scanline
db 0 ; 11: last cursor scanline
; ... TODO
DispTestText: db 'Display 512-character test:'
DispTestText2:
; -----------------------------------------------------------------------------
; Uninitialized data
; -----------------------------------------------------------------------------
BSS_SECTION
; ------------- Mapping from Unicode
TXTDrvUniMap: resd FONTMAP ; mapping from Unicode
|