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.