SECTION .text
VESAModesMax equ 256 ; max. number of VESA videomodes
Screen1W equ 320 ; width of VGA screen
Screen1H equ 200 ; height of VGA screen
Screen2W equ 800 ; width of VESA screen
Screen2H equ 600 ; height of VESA screen
BMPHead equ 54 ; size of head of BMP picture
BMPPal equ 256 ; number of palettes in BMP picture
BMPPalSize equ BMPPal*4 ; size of palettes in BMP file
BMPData equ BMPHead + BMPPalSize ; start of data in BMP file
BMP1Size equ (Screen1W*Screen1H + BMPData + 3) & (~3) ; VGA
BMP2Size equ (Screen2W*Screen2H + BMPData + 3) & (~3) ; VESA
DataSize equ (BMP1Size+BMP2Size+15) & (~15) ; size of graphics
; ----------------------------------------------------------------------------
; Init Graphic
; ----------------------------------------------------------------------------
; INPUT: DS = data segment
; OUTPUT: CY = error, no VGA card
; DESTROY: AX, CX
; ----------------------------------------------------------------------------
; ------------- Test VESA
InitGraph: call InitVESA ; init VESA
jc NoVESA ; error, no VESA
; ------------- Find required videomode (CX = number of videomodes)
call FindVESA ; find videomode
jnc InitGraph7 ; videomode found OK
; ------------- Init VGA videomode (320x200/256)
NoVESA: call SetVGAMode ; set VGA mode
jc InitGraph9 ; error, no VGA card
; ------------- Init parameters for VGA
InitGraph6: call InitVGAPar ; init VGA parameters
; ------------- Move VGA graphic up instead of VESA graphics
call MoveVGA ; move VGA graphics high
jmp short InitGraph8 ; init common parameters
; ------------- Switch to VESA videomode
InitGraph7: call SetVESAMode ; set VESA videomode
jc NoVESA ; error - cannot set videomode
; ------------- Prepare VESA parameters
call InitVESAPar ; init VESA parameters
InitGraph8: clc ; clear error flag
InitGraph9: ret
; ----------------------------------------------------------------------------
; Init VESA
; ----------------------------------------------------------------------------
; INPUT: DS = data segment
; OUTPUT: CX = number of videomodes
; CY = error
; ----------------------------------------------------------------------------
; ------------- Push registers
InitVESA: push ax ; push AX
push bx ; push BX
push dx ; push DX
push si ; push SI
push di ; push DI
push ds ; push DS
push es ; push ES
; ------------- Test VESA
mov al,0 ; AL <- function code
call VESAInt ; test VESA
jc InitVESA8 ; there is not VESA BIOS
; ------------- Check VESA version
mov ax,[VESA+4] ; VESA version
mov [VESAVer],ax ; store VESA version
cmp ax,102h ; minimal version 1.2
jb InitVESA8 ; incorrect VESA version
; ------------- Store VESA videomodes table
push ds ; push DS
pop es ; ES <- DS
mov di,VESAModes ; table of VESA videomodes (dest.)
lds si,[VESA+14] ; table of VESA videomodes (source)
xor cx,cx ; CX <- counter of videomodes
cld ; direction up
InitVESA2: lodsw ; load videomode
stosw ; save videomode
inc ax ; is it end of table?
jz InitVESA3 ; end of table
inc cx ; increase number of videomodes
cmp cx,VESAModesMax ; is videomode table full?
jb InitVESA2 ; next videomode
InitVESA3: or cx,cx ; test number of modes
jnz InitVESA9 ; there are some videomodes, OK
InitVESA8: xor cx,cx ; CX <- 0 error, no videomode
stc ; error flag
; ------------- Pop registers
InitVESA9: pop es ; pop ES
pop ds ; pop DS
pop di ; pop DI
pop si ; pop SI
pop dx ; pop DX
pop bx ; pop BX
pop ax ; pop AX
ret
; ----------------------------------------------------------------------------
; Find VESA videomode
; ----------------------------------------------------------------------------
; INPUT: CX = number of videomodes
; DS = data segment
; OUTPUT: CY = error, videomode not found
; ----------------------------------------------------------------------------
; ------------- Push registers
FindVESA: push ax ; push AX
push cx ; push CX
push si ; push SI
; ------------- Load next videomode
mov si,VESAModes ; SI <- table of videomodes
FindVESA2: cld ; direction up
lodsw ; AX <- load videomode
mov [VESAMode],ax ; push videomode
; ------------- Get information to videomode
push cx ; push CX
xchg ax,cx ; CX <- required videomode
mov al,1 ; AL <- function code
call VESAInt ; get videomode information
pop cx ; pop CX
jc FindVESA4 ; error
; ------------- Is mode supported in hardware?
test byte [VESA],1 ; is mode supported in hardware?
jz FindVESA4 ; mode is not supported
; ------------- Is it graphic mode?
test byte [VESA],10h ; is it graphic videomode?
jz FindVESA4 ; it is not graphic videomode
; ------------- Check segment of videomemory
mov ax,[VESA+8] ; window A start segment
cmp ax,0a000h ; minimal memory segment
jb FindVESA4 ; invalid memory segment
cmp ax,0f000h ; maximal memory segment
jae FindVESA4 ; invalid memory segment
mov [VideoSegm],ax ; store memory segment
; ------------- Check width, height and bites of videomode
cmp word [VESA+18],Screen2W ; check horizontal resolution
jne FindVESA4 ; invalid horizontal resolution
cmp word [VESA+20],Screen2H ; check vertical resolution
jne FindVESA4 ; invalid horizontal resolution
cmp byte [VESA+25],8 ; check number of bits per pixel
jne FindVESA4 ; invalid bits per pixel
; ------------- All OK, store other parameters of VESA videomode
mov ax,[VESA+16] ; bytes per scan line
mov [ScanLine],ax ; store bytes per scan line
clc ; flag OK
jmp short FindVESA8 ; all OK
; ------------- Next videomode
FindVESA4: loop FindVESA2 ; next videomode
stc ; error flag
; ------------- Pop registers
FindVESA8: pop si ; pop SI
pop cx ; pop CX
pop ax ; pop AX
ret
; ----------------------------------------------------------------------------
; Set VGA videomode
; ----------------------------------------------------------------------------
; INPUT: DS = data segment
; OUTPUT: CY = error
; ----------------------------------------------------------------------------
; ------------- Push registers
SetVGAMode: push ax ; push AX
push bx ; push BX
push cx ; push CX
push dx ; push DX
; ------------- Set VGA videomode
mov ax,13h ; AH <- function, AL <- videomode
call Int10 ; call Int 10h interrupt
; ------------- Check, if videomode is set OK
mov ah,0fh ; AH <- function code
call Int10 ; call Int 10h interrupt
cmp al,13h ; is videomode OK?
je SetVGAMode2 ; videomode is OK
stc ; error flag
; ------------- Pop registers
SetVGAMode2: pop dx ; pop DX
pop cx ; pop CX
pop bx ; pop BX
pop ax ; pop AX
ret
; ----------------------------------------------------------------------------
; Prepare VGA parameters
; ----------------------------------------------------------------------------
; INPUT: DS = data segment
; ----------------------------------------------------------------------------
InitVGAPar: mov word [VESAMap],0 ; current VESA memory window
mov word [ScanLine],320; store bytes per scan line
mov word [VideoSegm],0a000h ; videomemory segment
mov word [ScreenW],Screen1W ; width of VGA screen
mov word [ScreenH],Screen1H ; height of VGA screen
ret
; ----------------------------------------------------------------------------
; Move VGA graphics high
; ----------------------------------------------------------------------------
; ------------- Push registers
MoveVGA: push ax ; push AX
push cx ; push CX
push si ; push SI
push di ; push DI
push ds ; push DS
push es ; push ES
; ------------- Prepare segments
mov ds,[cs:GraphSeg]; DS <- old segment of VGA graphics
mov ax,BMP1Size ; size of VGA graphics
mov cl,4 ; CL <- 4 number of rotations
shr ax,cl ; size of VESA graphics in segments
add [cs:GraphSeg],ax; new segment of VGA graphics
mov es,[cs:GraphSeg]; ES <- new segment of VGA graphics
; ------------- Prepare offsets
mov si,[cs:GraphOff]; SI <- old offset of VGA graphics
sub si,BMPData ; SI <- offset of VGA graphics
mov di,(BMP1Size & 0Fh) + BMPData ; new offset
mov word [cs:GraphOff],di ; new offset of VGA graphics
sub di,BMPData ; DI <- new offset of VGA graphics
; ------------- Move VGA graphics
mov cx,BMP1Size/2 ; size of VGA graphics inwords
cld ; direction up
rep movsw ; moving VGA graphics up
; ------------- Pop registers
pop es ; pop ES
pop ds ; pop DS
pop di ; pop DI
pop si ; pop SI
pop cx ; pop CX
pop ax ; pop AX
ret
; ----------------------------------------------------------------------------
; Set VESA videomode
; ----------------------------------------------------------------------------
; INPUT: DS = data segment
; OUTPUT: CY = error
; ----------------------------------------------------------------------------
; ------------- Push registers
SetVESAMode: push ax ; push AX
push bx ; push BX
push cx ; push CX
push dx ; push DX
; ------------- Set VESA videomode
mov al,2 ; AL <- function code
mov bx,[VESAMode] ; BX <- VESA videomode
call VESAInt ; set VESA videomode
jc SetVESAMode2 ; error - cannot set videomode
; ------------- Check VESA videomode
mov al,3 ; AL <- function code
call VESAInt ; get VESA videomode
jc SetVESAMode2 ; error
cmp bx,[VESAMode] ; is ot OK?
je SetVESAMode2 ; it is OK
stc ; error flag
; ------------- Pop registers
SetVESAMode2: pop dx ; pop DX
pop cx ; pop CX
pop bx ; pop BX
pop ax ; pop AX
ret
; ----------------------------------------------------------------------------
; Prepare VESA parameters
; ----------------------------------------------------------------------------
; INPUT: DS = data segment
; ----------------------------------------------------------------------------
InitVESAPar: push ax ; push AX
push cx ; push CX
mov byte [UseVESA],1; flag - using VESA mode
mov ax,BMP1Size ; size of VGA graphics
mov cl,4 ; CL <- 4 number of rotations
shr ax,cl ; size of VESA graphics in segments
add [GraphSeg],ax ; segment of VESA graphics
mov word [GraphOff],(BMP1Size & 0Fh) + BMPData ; offset
mov word [ScreenW],Screen2W ; width of VESA screen
mov word [ScreenH],Screen2H ; height of VESA screen
pop cx ; pop CX
pop ax ; pop AX
ret
; ----------------------------------------------------------------------------
; Set palettes
; ----------------------------------------------------------------------------
; ------------- Push registers
SetPalettes: push ax ; push AX
push cx ; push CX
push dx ; push DX
push si ; push SI
push ds ; push DS
cli ; disable interrupt
; ------------- Address of palettes
mov si,[cs:GraphOff]; SI <- offset of graphics
sub si,BMPPalSize ; SI <- offset of palettes
mov ds,[cs:GraphSeg]; DS <- segment of graphics
; ------------- Set palette pointer
mov dx,3c8h ; DX <- palette pointer register
mov al,0 ; AL <- first palette register
out dx,al ; set first palette register to 0
; ------------- Set palettes
cld ; direction up
inc dx ; DX <- palette registers
mov cx,BMPPal ; CX <- number of palettes
SetPal2: mov al,[si+2] ; AL <- load RED from DS:SI+2
shr al,1 ; AL / 2
shr al,1 ; AL / 4
out dx,al ; set RED color component
mov al,[si+1] ; AL <- load GREEN from DS:SI+1
shr al,1 ; AL / 2
shr al,1 ; AL / 4
out dx,al ; set GREEN color component
lodsb ; AL <- load BLUE from DS:SI
shr al,1 ; AL / 2
shr al,1 ; AL / 4
out dx,al ; set BLUE color component
add si,3 ; shift to next palette
loop SetPal2 ; set next palette
; ------------- Pop registers
sti ; enable interrupt
pop ds ; pop DS
pop si ; pop SI
pop dx ; pop DX
pop cx ; pop CX
pop ax ; pop AX
ret
; ----------------------------------------------------------------------------
; Set address of memory window
; ----------------------------------------------------------------------------
; INPUT: DX = 64 KB segment address
; REMARK: It can be called in VGA mode, VESAMap = 0 and memory < 64 KB
; ----------------------------------------------------------------------------
SetMap: cmp dx,[cs:VESAMap] ; memory window changes?
je SetMap2 ; memory window is not changed
mov [cs:VESAMap],dx ; store new memory window
push ax ; push AX
push bx ; push BX
push cx ; push CX
push dx ; push DX
mov ax,4f05h ; AX <- function code
xor bx,bx ; BX <- 0 select window A
call Int10 ; set memory window
pop dx ; pop DX
pop cx ; pop CX
pop bx ; pop BX
pop ax ; pop AX
SetMap2: ret
; ----------------------------------------------------------------------------
; Call VESA services
; ----------------------------------------------------------------------------
; INPUT: AL = function code
; CS:[VESA} = input parameters
; OUTPUT: CY=error (no SVGA or other error)
; CS:[VESA] = output parameters
; ----------------------------------------------------------------------------
VESAInt: push ax ; push AX
push di ; push DI
push es ; push ES
push cs ; push CS
pop es ; ES <- CS program segment
mov di,VESA ; VESA data buffer
mov ah,4fh ; AH <- function code
call Int10 ; call VESA service
cmp ax,4fh ; is it VESA and is it OK?
je VESAInt2 ; it is VESA and all is OK
stc ; set error flag
VESAInt2: pop es ; pop ES
pop di ; pop DI
pop ax ; pop AX
ret
; ----------------------------------------------------------------------------
; Call Int 10h interrupt with saving registers
; ----------------------------------------------------------------------------
; Notes: Some BIOSes destroy some registers, so we call it with saving them.
; ----------------------------------------------------------------------------
Int10: pushf ; push flags
push si ; push SI
push di ; push DI
push bp ; push BP
push ds ; push DS
push es ; push ES
int 10h ; call INT 10h
pop es ; pop ES
pop ds ; pop DS
pop bp ; pop BP
pop di ; pop DI
pop si ; pop SI
popf ; pop flags
ret
; ----------------------------------------------------------------------------
; Data
; ----------------------------------------------------------------------------
OldVMode: db 3 ; old video mode
ScreenW: dw 320 ; width of currect screen
ScreenH: dw 200 ; height of current screen
GraphSeg: dw 0 ; segment of graphics
GraphOff: dw 0 ; offset of graphics
ScanLine: dw 320 ; bytes per scan line
VideoSegm: dw 0a000h ; video segment (window A)
UseVESA: db 0 ; flag, 1=use VESA mode
VESAVer: dw 0 ; VESA version (0102h = 1.2)
VESAMode: dw 0 ; VESA videomode
VESAMap: dw 0ffffh ; VESA current page of memory
ErrorNoVGA: db "ERROR: Cannot find VGA graphics card!",13,10
db " Press any key to quit...",13,10,0
VESA: times 256 db 0 ; VESA data buffer
VESAModes: times VESAModesMax dw 0 ; table of VESA videomodes
|