[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]