{       VGA Mode Set Functions:

       Set the current video mode to mode 13h or mode 3 (text)
       WITHOUT the BIOS call!

       I learned some of this from an assembly file that I couldn't
       assemble (wouldn't work in TASM or NASM).
       I am recoding it for NASM right now, but popped it out with
       Turbo Pascal just to see if it'd work.  It did.

       Feel free to use this code, but beware:  It doesn't like
       Windows '95 a whole lot unless the DOS window is already
       full screen.

       This is good for demos/games that use their own file system and
       boot code, when by the time that the graphics function is called,
       you are already in protected mode and don't wanna switch back just
       to call a stupid 16bit real mode BIOS routine.

       If you can expand it to other modes (ModeX) or even SVGA, PLEASE
       drop me a line at [email protected]

       Enjoy the code!
       Jeremy A. Mika
       Genetic Fantasia
}

uses crt;
type
  VGAMode = record
    BIOSmode, BIOScols : byte;
    VidSeg:word;
    Misc,Feature:byte;
    Seq:array[0..4] of byte;
    Crtc:array[0..$18] of byte;
    Gfx:array[0..$8] of byte;
    Att:array[0..$14] of byte;
  end;
procedure setmode(mode:VGAMode);
const
  MISC = $3c2;
  SEQ = $3c4;
  CRTC = $3d4;
  GRAPHICS = $3ce;
  FEATURE = $3da;
  ATTRIB = $3c0;
  STATUS = $3da;

  VREND = $11;
  NOPROT = $7f;

  ENABLEATTRIB = $20;

  CURSORTOPDATA = 17;
  CURSORBOTTOMDATA = 18;

  BIOSMODE = $49;
  COLUMNS = $4a;

procedure outw(ad:word;x,y:byte);assembler;
asm
   mov ah,x
   mov al,y
   mov dx,ad
   out dx,ax
end;

var x:byte;
begin
    ASM
       mov dx,3dah
@1:     in al,dx
       test al,8
       jz @1
@2:     in al,dx
       test al,8
       jnz @2
    END;
 mem[$40:BIOSMODE]:=mode.BIOSmode;
 mem[$40:COLUMNS]:=mode.BIOScols;
 mem[$40:$61]:=mode.crtc[$a];
 mem[$40:$60]:=mode.crtc[$b];
 port[MISC]:=mode.misc;
 delay(0);
 port[FEATURE]:=mode.feature;
 delay(0);
 for x:=0 to 4 do begin
   outw(SEQ,mode.seq[x],x);
   delay(0);
 end;
 port[CRTC]:=$11;
 port[CRTC]:=mode.crtc[$11] and $7F;  {No protection!}

 for x:=0 to $18 do begin
   outw(CRTC,mode.crtc[x],x);
   delay(0);
 end;

 for x:=0 to $8 do begin
   outw(GRAPHICS,mode.gfx[x],x);
   delay(0);
 end;

 x:=port[$3da];
 delay(0);

 for x:=0 to $14 do begin
   port[ATTRIB]:=x;
   delay(0);
   port[ATTRIB]:=mode.att[x];
   delay(0);
 end;
 port[ATTRIB]:=$20;
 delay(0);
end;

const
  Mode13:VGAMode = (BIOSmode:$13; BIOScols:40;
                  VidSeg:$a000;
                  Misc:$63; Feature:$00;
                  Seq:($03,$01,$0f,$00,$0e);
                  Crtc:($5f,$4f,$50,$82,$54,$80,$bf,$1f,$00,$41,$00,$00,
                        $00,$00,$00,$00,$9c,$0e,$8f,$28,$40,$96,$b9,$a3,
                        $ff);
                  Gfx:($00,$00,$00,$00,$00,$50,$07,$0f,$ff);
                  Att:($00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0a,$0b,$0c,
                       $0d,$0e,$0f,
                       $41,$00,$0f,$00,$00)
                  );
  Mode03:VGAMode = (BIOSmode:$03; BIOScols:80;
                  VidSeg:$b800;
                  Misc:$67; Feature:$00;
                  Seq:($03,$00,$03,$00,$02);
                  Crtc:($5f,$4f,$50,$82,$55,$81,$bf,$1f,$00,$4f,$0e,$0f,
                        $00,$00,$00,$00,$9c,$0e,$8f,$28,$1f,$96,$b9,$a3,
                        $ff);
                  Gfx:($00,$00,$00,$00,$00,$10,$0e,$00,$ff);
                  Att:($00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0a,$0b,$0c,
                       $0d,$0e,$0f,
                       $0c,$00,$0f,$08,$00)
                  );

var x:byte;
 buf:array[1..2000] of char;
begin
 readln;
 move(mem[$b800:0],buf,2000);
 setmode(Mode13);
 for x:=0 to 255 do
 mem[$a000:x]:=2;
 repeat
 until keypressed;
 readkey;
 for x:=0 to 255 do begin
   setmode(Mode13);
   setmode(Mode03);
   move(buf,mem[$b800:0],2000);
 end;
 readln;
end.