[Back to EGAVGA SWAG index] [Back to Main SWAG index] [Original]
UNIT VESAdrv;
INTERFACE
const ProgName :string[80] = 'VESA driver interface by Pî'#$0D#$0A'$';
ProgVersion:word = $0102; { programmed for VESA version 1.2 }
MaxVertical = 480*2; { max. vertical lines you need }
{ double if 2 pages required }
VesaSign :longint = $41534556; { = 'VESA' }
StatusOk :WORD = $004f; { default ok response after int 10 }
{.........!.........!.........!}
VesaErrors :ARRAY[0..5] OF STRING[30] =('Vesa init ok. ',
'?Error getting vesainfo. ',
'?Vesa not detected. ',
'?Vesa not detected. ',
'?Error getting vesamodeinfo. ',
'?Error opening vesamode. ');
MaxBanks = 256; { maximum bank switch }
type
TVerticalPosInfo = ARRAY[0..MaxVertical-1] OF RECORD { extra help for finding}
Address :Word; { memory addres }
Bank:Byte; { memory bank }
reserved:byte;
end;
TVesaInfoBlock = record
VESASignature : longint; {'VESA' check as number}
VESAVersion : word; { version hi.lo }
OEMStringPtr : pointer; { pointer to OEM string }
Capabilities : longint; { Capabilities field }
VideoModePtr : pointer; { pointer to supported modes }
TotalMemory : word; { x64k available memory }
reserved : array[1..236] of byte; {unused yet}
end;
TVesaModeInfoBlock = record
ModeAttributes : word; { mode attributes }
WinAAttributes : byte; { window A attributes }
WinBAttributes : byte; { window B attributes }
WinGranularity : word; { window granularity }
WinSize : word; { window size }
WinASegment : word; { window A start segment }
WinBSegment : word; { window B start segment }
WinFuncPtr : pointer; { pointer to windor function }
BytesPerScanLine : word; { bytes per scan line }
XResolution : word; { horizontal resolution }
YResolution : word; { vertical resolution }
XCharSize : byte; { character cell width }
YCharSize : byte; { character cell height }
NumberOfPlanes : byte; { number of memory planes }
BitsPerPixel : byte; { bits per pixel }
NumberOfBanks : byte; { number of banks }
MemoryModel : byte; { memory model type }
BankSize : byte; { bank size in kb }
NumberOfImagePages : byte; { number of images }
Reserved : byte; { reserved for page function }
RedMaskSize : byte; { size of direct color red mask }
RedFieldPosition : byte; { bit position of LSB of red mask }
GreenMaskSize : byte; { size of direct color green mask }
GreenFieldPosition : byte; { bit position of LSB of green mask }
BlueMaskSize : byte; { size of direct color blue mask }
BlueFieldPosition : byte; { bit position of LSB of blue mask }
RsvdMaskSize : byte; { size of direct color reserved mask }
DirectColorModeInfo: byte; { Direct Color mode attributes }
Reserved2 : array[1..216] of byte; { remainder }
end;
function InitVesaMode(RequestMode:word;ClearScreen:BOOLEAN):word;
procedure PutPixel(X,Y:Integer; C:Word);
procedure DrawBitMap(X,Y, XS,YS:Integer;ImageData:Pointer);
procedure Draw0BitMap(X,Y, XS,YS:Integer;ImageData:Pointer);
procedure SetDisplayStart(X,Y:Word);
procedure CloseVesaMode;
var
VesaInfo : TVesaInfoBlock; { get your own info here }
VesaModeInfo : TVesaModeInfoBlock; { get your own info here }
VerticalPosInfo: TVerticalPosInfo; { get your own info here }
BankTable : ARRAY[0..MaxBanks] OF Word;
CurrentBank,
WritePage,
VisualPage : word;
WinSizeBytes : word; { winsize in bytes.. 0 = 64k }
IMPLEMENTATION
{==== initialize video mode ====}
function InitVesaMode(RequestMode:word;ClearScreen:BOOLEAN):word; assembler;
asm
xor si,si { Error step value }
inc si { start with one }
mov ax,ds
mov es,ax
mov ax,$4f00; { return SuperVGA information }
mov di, OFFSET VesaInfo; { into buffer VesaInfo }
int $10;
cmp ax,StatusOk; { Status okay ? }
{1} jnz @ErrorInit; { no, then halt init }
inc si { next check }
mov ax, WORD PTR VesaInfo.VESASignature; { check first two chars }
cmp ax, WORD PTR VesaSign
{2} jnz @ErrorInit
inc si { next check }
mov ax, WORD PTR VesaInfo.VESASignature+2; { check next two chars }
cmp ax, WORD PTR VesaSign+2
{3} jnz @ErrorInit
{ primary test for VESA done, try to get videomode info }
inc si { next check }
mov ax, $4f01 { return videomode information }
mov cx, RequestMode { requested mode }
mov di, OFFSET VesaModeInfo { into buffer VesaModeInfo }
int $10;
cmp ax, StatusOk; { did this work out good? }
{4} jnz @ErrorInit
{ start opening videomode }
inc si { next check }
mov ax, $4f02;
mov bh, ClearScreen; { must clear screen }
xor bh, $01; { invert bit }
shl bh, 7; { move bit to d15 }
xor bl, bl; { clear lower byte }
or bx, RequestMode; { combine with videomode }
int $10;
cmp ax, StatusOk { did this work out good? }
{5} jnz @ErrorInit
{ build vertical pos info block }
inc si { next check }
mov cx, MaxVertical { how many times }
mov di, OFFSET VerticalPosInfo;
xor bx, bx; { startbank=0 }
xor ax, ax; { address =0 }
mov dx, WORD PTR VesaModeInfo.WinSize;
mov WinSizeBytes, dx
xchg dl, dh { multiply this with 1024 }
shl dh, 2
(* mov dx, $1000 *)
{ set info }
@VPosLoop:
mov ds:[di+0],ax { place addres in vpos infoblock}
mov ds:[di+2],bl { place bank in vpos infoblock }
mov ds:[di+3],bh { place bank in vpos infoblock }
add di,4 { add to next pos. in array}
add ax, WORD PTR VesaModeInfo.XResolution { increment address}
jc @IncBank { in case 64k buffer carry is gen. here! }
cmp ax, dx { check if bank is passed}
jb @DoLoop;
sub ax, dx { decrement ax with size to start again 4k-buf}
@IncBank:
inc bx;
@DoLoop:
Loop @VPosLoop;
{ built bankswitchtable }
mov di, OFFSET BankTable
xor bx, bx { start at bank 0 }
@BankLoop:
mov ax,bx { get banknr }
mov cx, 64
mul cx
mov cx, WORD PTR VesaModeInfo.WinGranularity
jcxz @@be
div cx
@@be:
mov ds:[di],ax { save value }
inc di
inc di
inc bx
cmp bx,MaxBanks
jb @BankLoop
{ buffer has been built for easy use! }
XOR CX,CX
mov CurrentBank, CX { clear current bank to 0 first time}
mov WritePage, CX { write to page 0 }
mov VisualPage, CX { visual page = 0 }
xor bx,bx; { perpare for int.}
mov dx,cx; { get banknr from cx }
mov ax,$4f05; { irq init }
int $10;
(* jmp @okinit; *)
{ all ok part }
@OkInit:
XOR AX,AX
@ErrorInit:
@End:
end;
{====}
procedure PutPixel(X,Y:Integer; C:Word); assembler;
asm
mov ax,Y
add ax,WritePage
mov di,X
mov dx,VesaModeInfo.BytesPerScanLine
mul dx
add di,ax
adc dx,0
cmp dx,CurrentBank { out of current window boundary? }
je @@1 { no }
{==== bankswitch ====}
MOV BX,DX
MOV CurrentBank,BX
ADD BX, BX
ADD BX, OFFSET BankTable
mov DX, DS:[BX]
mov AX, $4F05
xor BX, BX
int 10h
@@1:
mov AX ,c
mov es,SegA000
mov es:[di], al
end;
(*asm
mov ax,y
add ax,WritePage
shl ax,2
mov si, OFFSET VerticalPosInfo
add si, ax
mov ax, ds:[si] { get address }
mov es,SegA000 { get video segment }
mov di,ax { get video address }
mov ax, ds:[si+2] { get bank }
add di,x { add x coordinate to address }
adc ax,0 { perhaps bank add }
cmp ax, CurrentBank; { check if bank is same }
jz @PutPix; { bank is already ok! }
mov CurrentBank,ax; { set new bank }
xor bx,bx; { perpare for int.}
mov dx,ax; { get banknr from ax }
mov ax,$4f05; { irq init }
int $10;
@PutPix:
mov ax,C; { get color}
mov es:[di],ax; { finally put the pixel}
end;
*)
procedure SetBank; near;assembler;
{ IN: BX = Which bank }
asm
ADD BX, BX
ADD BX, OFFSET BankTable
mov DX, DS:[BX]
mov AX, $4F05
xor BX, BX
int 10h
end;
procedure DrawBitMap(X,Y, XS,YS:Integer;ImageData:Pointer); assembler;
var
SaveDS, MemInc,CurBank : word;
Count,BPLine, WinGran : word;
asm
cld
mov SaveDS,ds
mov ax,CurrentBank
mov CurBank,ax
mov ax,VesaModeInfo.WinGranularity
mov WinGran,ax
mov ax,Y
add ax,WritePage
mov di,X
mov dx,VesaModeInfo.BytesPerScanLine
mul dx
add di,ax
adc dx,0
cmp dx,CurBank { out of current window boundary? }
je @@1 { no }
{==== bankswitch ====}
MOV BX,DX
MOV CurBank,BX
ADD BX, BX
ADD BX, OFFSET BankTable
mov DX, DS:[BX]
mov AX, $4F05
xor BX, BX
int 10h
@@1: mov bx,VesaModeInfo.BytesPerScanLine
{ move from buffer to video memory }
mov es,SegA000
lds si, ImageData
mov cx, XS
mov BPLine,cx
sub bx,cx
mov MemInc,bx
mov ax, YS
mov Count,ax
{ check if switch is necessary, for one line! }
@@2: mov ax,di
add ax,CX { BPLine }
jnc @one_row { no carry so one full row }
{ check what's before }
xor cx,cx
sub cx,di
shr cx,1 { copy partially line directly }
rep movsw
jnc @pfini { ready with one partial line }
movsb { just one byte with copy , no rep is slow start }
@pfini:
push ax { save rest for later }
inc CurBank
{==== bankswitch ====}
mov ax,CurBank
mov cx, 64
mul cx
mov cx, WinGran
(* or cx,cx *)
jcxz @@e2
div cx
mov dx, ax
mov ax, $4F05
xor bx, bx
int 10h
@@e2:
pop ax
@@2_1: { switch done, do other half }
mov cx,ax
@One_Row:
shr cx,1 { copy partially line directly, part 2 after switch }
rep movsw
jnc @fini { ready with one partial line }
movsb { just one byte with copy , no rep is slow start }
@fini: { Finished, add for next line }
add di,MemInc
jc @@2_2sw
mov cx,BPLine
dec Count
jnz @@2
jmp @@EndDrw
@@2_2sw:
inc CurBank
{==== bankswitch ====}
mov ax, CurBank
mov cx, 64
mul cx
mov cx, WinGran
(* or cx,cx *)
jcxz @@e3
div cx
mov dx, ax
mov ax, $4F05
xor bx, bx
int 10h
@@e3:
mov cx,BPLine
dec Count
jnz @@2
@@EndDrw:
mov ds,SaveDS
mov ax,CurBank
mov CurrentBank,ax
end;
procedure Draw0BitMap(X,Y, XS,YS:Integer;ImageData:Pointer); assembler;
var
SaveDS : word;
MemInc : word;
OldBank,CurBank : word;
Count,BPLine : word;
asm
cld
mov SaveDS,ds
mov ax,CurrentBank
mov CurBank,ax
mov ax,Y
add ax,WritePage
mov di,X
mov dx,VesaModeInfo.BytesPerScanLine
mul dx
add di,ax
adc dx,0
cmp dx,CurBank { out of current window boundary? }
je @@1 { no }
mov CurBank,dx
mov bx,dx
call SetBank { move memory window to new position }
@@1: mov bx,VesaModeInfo.BytesPerScanLine
{ move from buffer to video memory }
mov es,SegA000
lds si, ImageData
mov cx, XS
mov BPLine,cx
sub bx,cx
mov MemInc,bx
mov ax, YS
mov Count,ax
{ check if switch is necessary, for one line! }
@@2: mov ax,di
add ax,CX {BPLine}
jnc @One_row { no carry so one full row }
@no_one_row: { there is a switch now in this line }
{ check what's before }
push ax { save rest for later }
xor cx,cx
sub cx,di
jcxz @pfini
xor ah,ah
@part1opnieuw:
lodsb
cmp al,ah
jz @part1zero { a zero value, so don't put this}
mov es:[di],al
@part1zero:
inc di
dec cx
jnz @part1opnieuw
@pfini:
inc CurBank
push ds
mov bx,CurBank
mov ds,SaveDs
call SetBank
pop ds
@@2_1: { switch done, do other half }
pop cx
jcxz @fini
@One_row:
xor ah,ah
@part2opnieuw:
lodsb
cmp al,ah
jz @part2zero { a zero value, so don't put this}
mov es:[di],al
@part2zero:
inc di
dec cx
jnz @part2opnieuw
@fini: { Finished, add for next line }
add di,MemInc
jc @@2_2sw
mov cx,BPLine
dec Count
jnz @@2
jmp @@EndDrw
@@2_2sw:
inc CurBank
push ds
mov bx,CurBank
mov ds,SaveDs
call SetBank
pop ds
mov cx,BPLine
dec Count
jnz @@2
@@EndDrw:
mov ds,SaveDS
end;
{====}
procedure SetDisplayStart(X,Y:Word); assembler;
asm
mov ax,$4f07;
xor bx,bx
mov cx,x
mov dx,y
int $10;
end;
{===}
procedure CloseVesaMode; assembler;
asm
mov ax,$4f03; { standard way of reseting videocard }
int $10;
mov ax,$0003; { standard way of reseting videocard }
int $10;
end;
begin
end.
[Back to EGAVGA SWAG index] [Back to Main SWAG index] [Original]