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 }