Cosmos/source/Cosmos.HAL2/Drivers/PCI/Video/VMWareSVGAII.cs
2018-06-28 21:59:42 +01:00

349 lines
11 KiB
C#

using System;
using Cosmos.Core;
namespace Cosmos.HAL.Drivers.PCI.Video
{
public class VMWareSVGAII
{
public enum Register : ushort
{
ID = 0,
Enable = 1,
Width = 2,
Height = 3,
MaxWidth = 4,
MaxHeight = 5,
Depth = 6,
BitsPerPixel = 7,
PseudoColor = 8,
RedMask = 9,
GreenMask = 10,
BlueMask = 11,
BytesPerLine = 12,
FrameBufferStart = 13,
FrameBufferOffset = 14,
VRamSize = 15,
FrameBufferSize = 16,
Capabilities = 17,
MemStart = 18,
MemSize = 19,
ConfigDone = 20,
Sync = 21,
Busy = 22,
GuestID = 23,
CursorID = 24,
CursorX = 25,
CursorY = 26,
CursorOn = 27,
HostBitsPerPixel = 28,
ScratchSize = 29,
MemRegs = 30,
NumDisplays = 31,
PitchLock = 32,
/// <summary>
/// Indicates maximum size of FIFO Registers.
/// </summary>
FifoNumRegisters = 293
}
private enum ID : uint
{
Magic = 0x900000,
V0 = Magic << 8,
V1 = (Magic << 8) | 1,
V2 = (Magic << 8) | 2,
Invalid = 0xFFFFFFFF
}
public enum FIFO : uint
{ // values are multiplied by 4 to access the array by byte index
Min = 0,
Max = 4,
NextCmd = 8,
Stop = 12
}
private enum FIFOCommand
{
Update = 1,
RECT_FILL = 2,
RECT_COPY = 3,
DEFINE_BITMAP = 4,
DEFINE_BITMAP_SCANLINE = 5,
DEFINE_PIXMAP = 6,
DEFINE_PIXMAP_SCANLINE = 7,
RECT_BITMAP_FILL = 8,
RECT_PIXMAP_FILL = 9,
RECT_BITMAP_COPY = 10,
RECT_PIXMAP_COPY = 11,
FREE_OBJECT = 12,
RECT_ROP_FILL = 13,
RECT_ROP_COPY = 14,
RECT_ROP_BITMAP_FILL = 15,
RECT_ROP_PIXMAP_FILL = 16,
RECT_ROP_BITMAP_COPY = 17,
RECT_ROP_PIXMAP_COPY = 18,
DEFINE_CURSOR = 19,
DISPLAY_CURSOR = 20,
MOVE_CURSOR = 21,
DEFINE_ALPHA_CURSOR = 22
}
private enum IOPortOffset : byte
{
Index = 0,
Value = 1,
Bios = 2,
IRQ = 3
}
[Flags]
private enum Capability
{
None = 0,
RectFill = 1,
RectCopy = 2,
RectPatFill = 4,
LecacyOffscreen = 8,
RasterOp = 16,
Cursor = 32,
CursorByPass = 64,
CursorByPass2 = 128,
EigthBitEmulation = 256,
AlphaCursor = 512,
Glyph = 1024,
GlyphClipping = 0x00000800,
Offscreen1 = 0x00001000,
AlphaBlend = 0x00002000,
ThreeD = 0x00004000,
ExtendedFifo = 0x00008000,
MultiMon = 0x00010000,
PitchLock = 0x00020000,
IrqMask = 0x00040000,
DisplayTopology = 0x00080000,
Gmr = 0x00100000,
Traces = 0x00200000,
Gmr2 = 0x00400000,
ScreenObject2 = 0x00800000
}
private IOPort IndexPort;
private IOPort ValuePort;
private IOPort BiosPort;
private IOPort IRQPort;
private MemoryBlock Video_Memory;
private MemoryBlock FIFO_Memory;
private PCIDevice device;
private uint height;
private uint width;
private uint depth;
private uint capabilities;
public VMWareSVGAII()
{
device = (HAL.PCI.GetDevice(HAL.VendorID.VMWare, HAL.DeviceID.SVGAIIAdapter));
device.EnableMemory(true);
uint basePort = device.BaseAddressBar[0].BaseAddress;
IndexPort = new IOPort((ushort)(basePort + (uint)IOPortOffset.Index));
ValuePort = new IOPort((ushort)(basePort + (uint)IOPortOffset.Value));
BiosPort = new IOPort((ushort)(basePort + (uint)IOPortOffset.Bios));
IRQPort = new IOPort((ushort)(basePort + (uint)IOPortOffset.IRQ));
WriteRegister(Register.ID, (uint)ID.V2);
if (ReadRegister(Register.ID) != (uint)ID.V2)
return;
Video_Memory = new MemoryBlock(ReadRegister(Register.FrameBufferStart), ReadRegister(Register.VRamSize));
capabilities = ReadRegister(Register.Capabilities);
InitializeFIFO();
}
protected void InitializeFIFO()
{
FIFO_Memory = new MemoryBlock(ReadRegister(Register.MemStart), ReadRegister(Register.MemSize));
FIFO_Memory[(uint)FIFO.Min] = (uint)Register.FifoNumRegisters * sizeof(uint);
FIFO_Memory[(uint)FIFO.Max] = FIFO_Memory.Size;
FIFO_Memory[(uint)FIFO.NextCmd] = FIFO_Memory[(uint)FIFO.Min];
FIFO_Memory[(uint)FIFO.Stop] = FIFO_Memory[(uint)FIFO.Min];
WriteRegister(Register.ConfigDone, 1);
}
public void SetMode(uint width, uint height, uint depth = 32)
{
// Depth is color depth in bytes.
this.depth = (depth / 8);
this.width = width;
this.height = height;
WriteRegister(Register.Width, width);
WriteRegister(Register.Height, height);
WriteRegister(Register.BitsPerPixel, depth);
WriteRegister(Register.Enable, 1);
InitializeFIFO();
}
protected void WriteRegister(Register register, uint value)
{
IndexPort.DWord = (uint)register;
ValuePort.DWord = value;
}
protected uint ReadRegister(Register register)
{
IndexPort.DWord = (uint)register;
return ValuePort.DWord;
}
protected uint GetFIFO(FIFO cmd)
{
return FIFO_Memory[(uint)cmd];
}
protected uint SetFIFO(FIFO cmd, uint value)
{
return FIFO_Memory[(uint)cmd] = value;
}
protected void WaitForFifo()
{
WriteRegister(Register.Sync, 1);
while (ReadRegister(Register.Busy) != 0) { }
}
protected void WriteToFifo(uint value)
{
if (((GetFIFO(FIFO.NextCmd) == GetFIFO(FIFO.Max) - 4) && GetFIFO(FIFO.Stop) == GetFIFO(FIFO.Min)) ||
(GetFIFO(FIFO.NextCmd) + 4 == GetFIFO(FIFO.Stop)))
WaitForFifo();
SetFIFO((FIFO)GetFIFO(FIFO.NextCmd), value);
SetFIFO(FIFO.NextCmd, GetFIFO(FIFO.NextCmd) + 4);
if (GetFIFO(FIFO.NextCmd) == GetFIFO(FIFO.Max))
SetFIFO(FIFO.NextCmd, GetFIFO(FIFO.Min));
}
public void Update(uint x, uint y, uint width, uint height)
{
WriteToFifo((uint)FIFOCommand.Update);
WriteToFifo(x);
WriteToFifo(y);
WriteToFifo(width);
WriteToFifo(height);
WaitForFifo();
}
public void SetPixel(uint x, uint y,uint color)
{
Video_Memory[((y * width + x) * depth)] = color;
}
public uint GetPixel(uint x, uint y)
{
return Video_Memory[((y * width + x) * depth)];
}
public void Clear(uint color)
{
Fill(0, 0, width, height, color);
}
public void Copy(uint x, uint y, uint newX, uint newY, uint width, uint height)
{
if ((capabilities & (uint)Capability.RectCopy) != 0)
{
WriteToFifo((uint)FIFOCommand.RECT_COPY);
WriteToFifo(x);
WriteToFifo(y);
WriteToFifo(newX);
WriteToFifo(newY);
WriteToFifo(width);
WriteToFifo(height);
WaitForFifo();
}
else
throw new NotImplementedException("VMWareSVGAII Copy()");
}
public void Fill(uint x, uint y, uint width, uint height, uint color)
{
if ((capabilities & (uint)Capability.RectFill) != 0)
{
WriteToFifo((uint)FIFOCommand.RECT_FILL);
WriteToFifo(color);
WriteToFifo(x);
WriteToFifo(y);
WriteToFifo(width);
WriteToFifo(height);
WaitForFifo();
}
else
{
if ((capabilities & (uint)Capability.RectCopy) != 0)
{
// fill first line and copy it to all other
uint xTarget = (x + width);
uint yTarget = (y + height);
for (uint xTmp = x; xTmp < xTarget; xTmp++)
{
SetPixel(xTmp, y, color);
}
// refresh first line for copy process
Update(x, y, width, 1);
for (uint yTmp = y + 1; yTmp < yTarget; yTmp++)
{
Copy(x, y, x, yTmp, width, 1);
}
}
else
{
uint xTarget = (x + width);
uint yTarget = (y + height);
for (uint xTmp = x; xTmp < xTarget; xTmp++)
{
for (uint yTmp = y; yTmp < yTarget; yTmp++)
{
SetPixel(xTmp, yTmp, color);
}
}
Update(x, y, width, height);
}
}
}
public void DefineCursor()
{
WaitForFifo();
WriteToFifo((uint)FIFOCommand.DEFINE_CURSOR);
WriteToFifo(1);
WriteToFifo(0);
WriteToFifo(0);
WriteToFifo(2);
WriteToFifo(2);
WriteToFifo(1);
WriteToFifo(1);
for (int i = 0; i < 4; i++)
WriteToFifo(0);
for (int i = 0; i < 4; i++)
WriteToFifo(0xFFFFFF);
WaitForFifo();
}
public void SetCursor(bool visible, uint x, uint y)
{
WriteRegister(Register.CursorID, 1);
if (visible)
{
WaitForFifo();
WriteToFifo((uint)FIFOCommand.MOVE_CURSOR);
WriteToFifo(x);
WriteToFifo(y);
}
WriteRegister(Register.CursorOn, (uint)(visible ? 1 : 0));
}
}
}