Metropoli BBS
VIEWER: s3.pas MODE: TEXT (ASCII)
unit S3;

{ S3  Version 3.00  09.09.1995  Dietmar Meschede }
{                                                }
{ Copyright (c) 1993,1995 Dietmar Meschede       }
{                                                }
{ Use at OWN risk!                               }


{ The main purpose of this unit is to set up a 320x240x256 or }
{ 640x480x256 video mode with a 1 MB linear address window.   }
{                                                             }
{ The unit requires a VGA graphics card with 1 MB (or more)   }
{ video memory and a S3 86C928 (or better) chip.              }
{ The 640x480 video mode requires a VESA graphics card.       }


{$DEFINE PROTECTED}   { The unit runs only in protected mode. }
{$I STDUNIT.OPT}


interface

uses
  NewFrontier;


var
  S3VideoLinearAddress: Longint;  { Linear address of video memory. }

var
  S3Video: Word;    { 16-bit selector to access video memory. }
  S3Video32: Word;  { 32-bit selector to access video memory. }


{ --- VGA Registers --- }

const
  MISC_WT   = $03C2;
  MISC_RD   = $03CC;

  STATUS_0  = $03C2;
  STATUS_1  = $03DA;

  SEQ_ADR   = $03C4;            { Sequencer Registers: SR0-4 }
  SEQ_DATA  = $03C5;

  CRTC_ADR  = $03D4;            { Crt Controller Registers: CR0-18,22,24/26 }
  CRTC_DATA = $03D5;

  ATR_ADR   = $03C0;            { Attribute Controller Registers: AR0-14 }
  ATR_DATA  = $03C1;

const
  SR = SEQ_ADR;
  CR = CRTC_ADR;


{ --- VGA graphics card functions --- }

procedure SetVideoMode(Mode: Byte);
  { Sets a VGA video mode via VGA BIOS. }

procedure TurnScreenOn;
  { Turns the screen on. }

procedure TurnScreenOff;
  { Turns the screen off. }


{ --- VESA graphics card functions --- }

function SetSuperVGAVideoMode(Mode: Word): Boolean;
  { Sets a Super VGA video mode via VESA VBE. }


{ --- S3 graphics card functions --- }

procedure S3Init320x240;
  { Sets up a 320x240x256 video mode with a 1 MB linear
    address window and 512 bytes logical line width. }

procedure S3Init640x480;
  { Sets up a 480x480x256 video mode with a 1 MB linear
    address window and 1024 bytes logical line width. }

procedure ClearS3VideoMemory;
  { Clears the first MB of display memory. Works only
    after calling S3Init320x200 or S3Init640x480. }

procedure S3SetStartAddress(Start: Longint);
  { Sets the display start address. }


implementation


{ --- S3 86C928 VGA Register Descriptions --- }


{ Memory Configuration Register (MEM CNFG) (CR31):                   }

{ Read / Write                                                       }
{ Power On Default: 00h                                              }

{ Bit 0:    CPUA BASE - Enable Base Address Offset                   }
{            0 = Address offset bits 3-0 of the CRT Register Lock    }
{                register (CR35) and bits 3-2 of the Extended System }
{                Control 2 register are disabled.                    }
{            1 = Address offset bits 3-0 of the CRT Register Lock    }
{                register (CR35) and bits 3-2 of the Extended System }
{                Control 2 (CR51) register are enabled for whole VGA }
{                display memory access by the CPU.                   }
{ Bit 3:    ENH MAP - Enhanced Memory Mapping                        }
{            0 = Forces IBM VGA mapping for memory accesses.         }
{            1 = Forces Enhanced Mode mappings.                      }
{ Bits 5-4: STRT ADR 17,16 - Start Address Bits 17-16                }

{ CRT Register Lock Register (CRTR LOCK) (CR35):               }

{ Read / Write                                                 }
{ Power On Default: 00h                                        }

{ Bits 3-0: CPU BASE ADDRESS - CPU Base Address bits 17-14     }
{            These four bits define the addresse base in 64 KB }
{            units of display memory.                          }
{ Bits 7-6: Reserved


{ --- S3 86C928 System Control Registers Descriptions --- }


{ Extended Memory Control 2 Register (EX MCTL 2) (CR40):                }

{ Read / Write                                                          }
{ Power On Default: A4h                                                 }

{ Bit 3: EWRT POST - Enable Fast Write Buffer (Write Posting Into FIFO) }
{         0 = Disable fast write buffer.                                }
{         1 = Enable fast write buffer.                                 }


{ --- S3 86C928 System Extension Registers Descriptions --- }


{ CR51 }

{ Extended System Control 2 Register (EX MCTL 2) (CR51):            }

{ Read / Write                                                      }
{ Power On Default: 00h                                             }

{ Bits 1-0: DISP ST AD - Display Start Address Bits 19-18           }
{ Bits 3-2: CPU BASE - CPU Base Address Bits 19-18                  }
{ Bits 5-4: LOG SCR W - Logical Screen Width Bits 9-8               }
{            These are two extension bits of the Offset register    }
{            (CR13). If the value of these bits is not zero, bit 2  }
{            of the Extended Mode register (CR43) is disabled.      }
{            (CR43, Bit 2: Logical Screen Width Bit 8.)             }


{ Extended Memory Control 2 Register (EX MCTL 2) (CR54):            }

{ Read / Write                                                      }
{ Power On Default: 00h                                             }

{ Bits 2-0: RAC EXT PFTCH - Read Ahead Cache Extra Prefetch Control }
{            Only 0, 1, 3 and 7 are meaningful values.              }
{ Bits 7-3: Reserved                                                }


{ Linear Address Window Control Register (LAW CTL) (CR58): }

{ Read / Write                                             }
{ Power On Default: 00h                                    }

{ Bits 1-0: LAW SIZE - Linear Address Window Size          }
{            00 = 64 KB, 01 = 1 MB, 10 = 2MB, 11 = 4MB     }
{ Bit 2:    ENB RAC - Enable Read Ahead Cache              }
{ Bit 4:    Enable Linear Addressing                       }


{ Linear Address Window Position Registers (LAW POS) (CR59-5A): }

{ Read / Write                                                  }
{ Power On Default: 000Ah                                       }

{ Bits 9-0:   LINEAR ADDRESS WINDOW POSITION                    }
{              Linear Address Window Position bits 25-16.       }
{              LAW-Size = 1 MB: bits 19-16 ignored              }
{              LAW-Size = 2 MB: bits 20-16 ignored              }
{              LAW-Size = 4 MB: bits 21-16 ignored              }
{ Bits 15-10: Reserved


{ --- VGA graphics card functions --- }

function ReadReg(Address: Word; Index: Byte): Byte;
  { Read a VGA register. }
var
  Tmp: Byte;
begin
  if Address = ATR_ADR then begin
    Tmp := Port[STATUS_1];
    Port[ATR_ADR] := (Port[ATR_ADR] and $E0) or (Index and $1F);
    ReadReg := Port[ATR_DATA];
  end { if }
  else begin
    Port[Address] := Index;
    ReadReg := Port[Address+1];
  end; { else }
end; { ReadReg }

function WriteReg(Address: Word; Index, Value: Byte): Byte;
  { Write to a VGA register. }
var
  Tmp: Byte;
begin
  if Address <> ATR_ADR then begin
    Port[Address] := Index;
    Port[Address+1] := Value;
  end { if }
  else begin
    Tmp := Port[STATUS_1];
    Port[ATR_ADR] := (Port[ATR_ADR] and $E0) or (Index and $1F);
    Port[ATR_ADR] := Value;
  end; { else }
end; { WriteReg }

{ export }
procedure SetVideoMode(Mode: Byte); assembler;
  { Sets a VGA video mode via VGA BIOS. }
asm
        mov     al,[Mode]
        xor     ah,ah
        int     10h
end; { SetVideoMode }

{ export }
procedure TurnScreenOn;
  { Turns the screen on. }
begin
  WriteReg(SR, $01, ReadReg(SR, $01) and $DF);
end; { TurnScreenOn }

{ export }
procedure TurnScreenOff;
  { Turns the screen off. }
begin
  WriteReg(SR, $01, ReadReg(SR, $01) or $20);
end; { TurnScreenOff }


{ --- VESA graphics card functions --- }

{ export }
function SetSuperVGAVideoMode(Mode: Word): Boolean; assembler;
  { Sets a Super VGA video mode via VESA VBE. }
asm
        mov     bx,[Mode]
        mov     ax,4F02h
        int     10h
        cmp     ax,004Fh
        mov     ax,True
        je      @@End
        mov     ax,False
@@End:
end; { SetSuperVGAVideoMode }


{ --- S3 graphics card functions --- }

procedure UnlockS3Regs;
  { Enables access to all S3 registers. }
begin
  WriteReg(CR, $38, $48);
  WriteReg(CR, $39, $A0);
end; { UnlockS3Regs }

procedure LockS3Regs;
  { Disables access to extended S3 registers. }
begin
  WriteReg(CR, $38, $00);
  WriteReg(CR, $39, $00);
end; { LockS3Regs }

procedure S3ForceEnhancedModeMappings;
  { Force Enhanced Mode mappings. }
begin
  UnlockS3Regs;
  WriteReg(CR, $31, ReadReg(CR, $31) or $09);   { Enable Base Address Offset and }
  LockS3Regs;                                   { force Enhanced Mode mappings }
end; { S3ForceEnhancedModeMappings }

procedure S3DisableLinearAddressing;
  { Disable Linear Addressing.        }
begin
  UnlockS3Regs;
  WriteReg(CR, $58, ReadReg(CR, $58) and $EC);  { Disable Linear Addressing! }
  WriteReg(CR, $59, $00);                       { Set Linear Address Window  }
  WriteReg(CR, $5A, $0A);                       { Position to A0000h.        }
  LockS3Regs;
end; { S3DisableLinearAddressing }

procedure S3EnableLinearAddressing;
  { Enable 1 MB Linear Address Window at 3000000h. }
begin
  UnlockS3Regs;
  WriteReg(CR, $58, ReadReg(CR, $58) and $EC);  { Disable Linear Addressing! }
  WriteReg(CR, $59, $03);                       { Set Linear Address Window  }
  WriteReg(CR, $5A, $00);                       { Position to 3000000h.      }
  WriteReg(CR, $58,                             { Enable Linear Addressing and }
          (ReadReg(CR, $58) and $EC) or $11);   { set Window size to 1 MB.     }
  LockS3Regs;
end; { S3EnableLinearAddressing }

procedure S3SetReadAheadExtraPrefetch(Prefetch: Integer);
  { Set Read Ahead Extra Prefetch. }
var
  CR58: Byte;
begin
  Prefetch := Prefetch and $07;
  UnlockS3Regs;
  CR58 := ReadReg(CR, $58) and $FB;     { Disable Read Ahead Cache }
  WriteReg(CR, $58, CR58);
  WriteReg(CR, $54, Prefetch);          { Set Read Ahead Extra Prefetch }
  if Prefetch > 0 then
    WriteReg(CR, $58, CR58 or $04);     { Enable Read Ahead Cache if necessary }
  LockS3Regs;
end; { S3SetReadAheadExtraPrefetch }

procedure S3EnableFastWriteBuffer;
  { Enable Fast Write Buffer. }
begin
  UnlockS3Regs;
  WriteReg(CR, $40, ReadReg(CR, $40) or $08);   { Enable Fast Write Buffer }
  LockS3Regs;
end; { S3EnableFastWriteBuffer }

{ export }
procedure S3Init320x240;
  { Sets up a 320x240x256 video mode with a 1 MB linear
    address window and 512 bytes logical line width. }
const
  CrtRegs: array[0..$18] of Byte =
             ($5F, $4F, $50, $82, $56, $82, $0B, $3E,
              $00, $41, $00, $00, $00, $00, $00, $00,
              $EA, $2C, $DF, $40, $40, $E7, $04, $A3, $FF);
var
  i: Byte;
begin
  SetVideoMode($13);                            { Init VGA Mode 13h 320x200x256 }

  TurnScreenOff;

  Port[MISC_WT] := $E7;                         { Init Tweak Mode 320x240     }
  WriteReg(CR, $11, ReadReg(CR, $11) and $7F);  { with logical line width 512 }
  for i := $00 to $18 do
    WriteReg(CR, i, CrtRegs[i]);
  WriteReg(CR, $11, ReadReg(CR, $11) or $80);

  S3ForceEnhancedModeMappings;                  { Enable Linear Addressing }
  S3EnableLinearAddressing;

  S3SetReadAheadExtraPrefetch(1);               { Increase performance }
  S3EnableFastWriteBuffer;

  ClearS3VideoMemory;                           { Important }

  TurnScreenOn;
end; { S3Init320x240 }

{ export }
procedure S3Init640x480;
  { Sets up a 480x480x256 video mode with a 1 MB linear
    address window and 1024 bytes logical line width. }
begin
  SetSuperVGAVideoMode($101);                   { Init VESA Mode 101h }

  TurnScreenOff;

  WriteReg(CR, $13, $80);                       { Logical line width 1024 }

  S3ForceEnhancedModeMappings;                  { Enable Linear Addressing }
  S3EnableLinearAddressing;

  S3SetReadAheadExtraPrefetch(1);               { Increase performance }
  S3EnableFastWriteBuffer;

  ClearS3VideoMemory;

  TurnScreenOn;
end; { S3Init640x480 }

{ export }
procedure ClearS3VideoMemory;
  { Clears the first MB of display memory. Works only
    after calling S3Init320x200 or S3Init640x480. }
begin
  FillChar32(Ptr48(S3Video, 0), $100000, 0);
end; { ClearS3VideoMemory; }

{ export }
procedure S3SetStartAddress(Start: Longint);
  { Sets the display start address. }
begin
  Start := Start shr 2;
  UnlockS3Regs;
  WriteReg(CR, $0D, $00);
  WriteReg(CR, $0D, Byte(Start));
  WriteReg(CR, $0C, Byte(Start shr 8));
  WriteReg(CR, $31, (ReadReg(CR, $31) and $CF) or (Byte(Start shr 12) and $30));
  WriteReg(CR, $51, (ReadReg(CR, $51) and $FC) or (Byte(Start shr 18) and $03));
  LockS3Regs;
end; { S3SetStartAddress }

var
  SaveExit: Pointer;

procedure S3Exit; far;
begin
  ExitProc := SaveExit;
  S3DisableLinearAddressing;
  FreeDescriptor(S3Video32);
  FreeDescriptor(S3Video);
  FreePhysicalAddressMapping(S3VideoLinearAddress);
end; { S3Exit }

var
  Rights: Word;

begin
  S3VideoLinearAddress := 0; S3Video := 0; S3Video32 := 0;
  SaveExit := ExitProc;
  ExitProc := @S3Exit;
  S3VideoLinearAddress := PhysicalAddressMapping($3000000, $100000);
  S3Video := CreateDescriptor(S3VideoLinearAddress, $100000);
  Rights := GetSegmentAccessRights(S3Video);
  Rights := (Rights and $FF70) or $0093;
  SetSegmentAccessRights(S3Video, Rights);
  S3Video32 := CreateData32Alias(S3Video);
end. { unit S3 }
[ RETURN TO DIRECTORY ]