/* PRIVATE VARIABLES **********************************************************/
-static CONST DWORD MemoryBase[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
-static CONST DWORD MemoryLimit[] = { 0xAFFFF, 0xAFFFF, 0xB7FFF, 0xBFFFF };
+static CONST DWORD MemoryBase[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
+static CONST DWORD MemorySize[] = { 0x20000, 0x10000, 0x8000, 0x8000 };
/*
* Activate this line if you want to use the real
// static VGA_REGISTERS VgaRegisters;
-static BOOLEAN InVerticalRetrace = FALSE;
-static BOOLEAN InHorizontalRetrace = FALSE;
+static ULONGLONG VerticalRetraceCycle = 0ULL;
+static ULONGLONG HorizontalRetraceCycle = 0ULL;
static BOOLEAN NeedsUpdate = FALSE;
static BOOLEAN ModeChanged = FALSE;
return MemoryBase[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
}
-static inline DWORD VgaGetVideoLimitAddress(VOID)
-{
- return MemoryLimit[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
-}
-
static VOID VgaUpdateCursorPosition(VOID)
{
/*
static inline DWORD VgaTranslateReadAddress(DWORD Address)
{
- DWORD Offset = Address - VgaGetVideoBaseAddress();
+ DWORD Offset = LOWORD(Address - VgaGetVideoBaseAddress());
BYTE Plane;
/* Check for chain-4 and odd-even mode */
Plane = VgaGcRegisters[VGA_GC_READ_MAP_SEL_REG] & 0x03;
}
- return Offset + Plane * VGA_BANK_SIZE;
+ /* Return the offset on plane 0 for read mode 1 */
+ if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_READ) return Offset;
+ else return Offset + Plane * VGA_BANK_SIZE;
}
static inline DWORD VgaTranslateWriteAddress(DWORD Address)
{
- DWORD Offset = Address - VgaGetVideoBaseAddress();
+ DWORD Offset = LOWORD(Address - VgaGetVideoBaseAddress());
/* Check for chain-4 and odd-even mode */
if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
static BOOLEAN VgaInitializePalette(VOID)
{
- INT i;
+ UINT i;
BOOLEAN Result = FALSE;
LPLOGPALETTE Palette, TextPalette;
{
SHORT i, j, k;
DWORD AddressSize = VgaGetAddressSize();
- DWORD Address = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG],
- VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG]);
DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
+ BYTE PresetRowScan = VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] & 0x1F;
+ DWORD Address = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG],
+ VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG])
+ + PresetRowScan * ScanlineSize
+ + ((VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] >> 5) & 3);
/*
* If console framebuffer is NULL, that means something went wrong
/* Graphics mode */
PBYTE GraphicsBuffer = (PBYTE)ConsoleFramebuffer;
DWORD InterlaceHighBit = VGA_INTERLACE_HIGH_BIT;
+ SHORT X;
/*
* Synchronize access to the graphics framebuffer
{
BYTE PixelData = 0;
+ /* Apply horizontal pixel panning */
+ if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
+ {
+ X = j + ((VgaAcRegisters[VGA_AC_HORZ_PANNING_REG] & 0x0F) >> 1);
+ }
+ else
+ {
+ X = j + (VgaAcRegisters[VGA_AC_HORZ_PANNING_REG] & 0x0F);
+ }
+
/* Check the shifting mode */
if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFT256)
{
if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
{
/* One byte per pixel */
- PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
- + LOWORD((Address + (j / VGA_NUM_BANKS))
+ PixelData = VgaMemory[(X % VGA_NUM_BANKS) * VGA_BANK_SIZE
+ + LOWORD((Address + (X / VGA_NUM_BANKS))
* AddressSize)];
}
else
{
/* 4-bits per pixel */
- PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
- + LOWORD((Address + (j / (VGA_NUM_BANKS * 2)))
+ PixelData = VgaMemory[(X % VGA_NUM_BANKS) * VGA_BANK_SIZE
+ + LOWORD((Address + (X / (VGA_NUM_BANKS * 2)))
* AddressSize)];
/* Check if we should use the highest 4 bits or lowest 4 */
- if (((j / VGA_NUM_BANKS) % 2) == 0)
+ if (((X / VGA_NUM_BANKS) % 2) == 0)
{
/* Highest 4 */
PixelData >>= 4;
* 2 bits shifted from plane 0 and 2 for the first 4 pixels,
* then 2 bits shifted from plane 1 and 3 for the next 4
*/
- DWORD BankNumber = (j / 4) % 2;
- DWORD Offset = Address + (j / 8);
+ DWORD BankNumber = (X / 4) % 2;
+ DWORD Offset = Address + (X / 8);
BYTE LowPlaneData = VgaMemory[BankNumber * VGA_BANK_SIZE + LOWORD(Offset * AddressSize)];
BYTE HighPlaneData = VgaMemory[(BankNumber + 2) * VGA_BANK_SIZE + LOWORD(Offset * AddressSize)];
/* Extract the two bits from each plane */
- LowPlaneData = (LowPlaneData >> (6 - ((j % 4) * 2))) & 0x03;
- HighPlaneData = (HighPlaneData >> (6 - ((j % 4) * 2))) & 0x03;
+ LowPlaneData = (LowPlaneData >> (6 - ((X % 4) * 2))) & 0x03;
+ HighPlaneData = (HighPlaneData >> (6 - ((X % 4) * 2))) & 0x03;
/* Combine them into the pixel */
PixelData = LowPlaneData | (HighPlaneData << 2);
{
/* The data is on plane k, 4 pixels per byte */
BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
- + LOWORD((Address + (j / VGA_NUM_BANKS))
+ + LOWORD((Address + (X / VGA_NUM_BANKS))
* AddressSize)];
/* The mask of the first bit in the pair */
- BYTE BitMask = 1 << (((3 - (j % VGA_NUM_BANKS)) * 2) + 1);
+ BYTE BitMask = 1 << (((3 - (X % VGA_NUM_BANKS)) * 2) + 1);
/* Bits 0, 1, 2 and 3 come from the first bit of the pair */
if (PlaneData & BitMask) PixelData |= 1 << k;
for (k = 0; k < VGA_NUM_BANKS; k++)
{
BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
- + LOWORD((Address + (j / (VGA_NUM_BANKS * 2)))
+ + LOWORD((Address + (X / (VGA_NUM_BANKS * 2)))
* AddressSize)];
/* If the bit on that plane is set, set it */
- if (PlaneData & (1 << (7 - (j % 8)))) PixelData |= 1 << k;
+ if (PlaneData & (1 << (7 - (X % 8)))) PixelData |= 1 << k;
}
}
}
PCHAR_CELL CharBuffer = (PCHAR_CELL)ConsoleFramebuffer;
CHAR_CELL CharInfo;
+ /*
+ * Technically, the horizontal panning and preset row count should
+ * affect text mode too. However, it works on pixels and not characters,
+ * so we can't support it currently.
+ */
+
/* Loop through the scanlines */
for (i = 0; i < CurrResolution.Y; i++)
{
case VGA_INSTAT1_READ_COLOR:
{
BYTE Result = 0;
+ BOOLEAN Vsync, Hsync;
+ ULONGLONG Cycles = GetCycleCount();
+ ULONG CyclesPerMicrosecond = (ULONG)((GetCycleSpeed() + 500000ULL) / 1000000ULL);
+ ULONG Dots = (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & 1) ? 9 : 8;
+ ULONG Clock = ((VgaMiscRegister >> 2) & 1) ? 28 : 25;
+ ULONG HorizTotalDots = ((ULONG)VgaCrtcRegisters[VGA_CRTC_HORZ_TOTAL_REG] + 5) * Dots;
+ ULONG VblankStart, VblankEnd, HblankStart, HblankEnd;
+ ULONG HblankDuration, VblankDuration;
+
+ /* Calculate the vertical blanking duration in cycles */
+ VblankStart = VgaCrtcRegisters[VGA_CRTC_START_VERT_BLANKING_REG] & 0x7F;
+ VblankEnd = VgaCrtcRegisters[VGA_CRTC_END_VERT_BLANKING_REG] & 0x7F;
+ if (VblankEnd < VblankStart) VblankEnd |= 0x80;
+ VblankDuration = ((VblankEnd - VblankStart) * HorizTotalDots
+ * CyclesPerMicrosecond + (Clock >> 1)) / Clock;
+
+ /* Calculate the horizontal blanking duration in cycles */
+ HblankStart = VgaCrtcRegisters[VGA_CRTC_START_HORZ_BLANKING_REG] & 0x1F;
+ HblankEnd = VgaCrtcRegisters[VGA_CRTC_END_HORZ_BLANKING_REG] & 0x1F;
+ if (HblankEnd < HblankStart) HblankEnd |= 0x20;
+ HblankDuration = ((HblankEnd - HblankStart) * Dots
+ * CyclesPerMicrosecond + (Clock >> 1)) / Clock;
+
+ Vsync = (Cycles - VerticalRetraceCycle) < (ULONGLONG)VblankDuration;
+ Hsync = (Cycles - HorizontalRetraceCycle) < (ULONGLONG)HblankDuration;
/* Reset the AC latch */
VgaAcLatch = FALSE;
+ /* Reverse the polarity, if needed */
+ if (VgaMiscRegister & VGA_MISC_VSYNCP) Vsync = !Vsync;
+ if (VgaMiscRegister & VGA_MISC_HSYNCP) Hsync = !Hsync;
+
/* Set a flag if there is a vertical or horizontal retrace */
- if (InVerticalRetrace || InHorizontalRetrace) Result |= VGA_STAT_DD;
+ if (Vsync || Hsync) Result |= VGA_STAT_DD;
/* Set an additional flag if there was a vertical retrace */
- if (InVerticalRetrace) Result |= VGA_STAT_VRETRACE;
-
- /* Clear the flags */
- InHorizontalRetrace = InVerticalRetrace = FALSE;
+ if (Vsync) Result |= VGA_STAT_VRETRACE;
return Result;
}
{
case VGA_GC_MISC_REG:
{
+ /* Remove any existing VGA memory hook */
+ MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000);
+
+ if (VgaMiscRegister & VGA_MISC_RAM_ENABLED)
+ {
+ UCHAR MemoryMap = (VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03;
+
+ /* Register a memory hook */
+ MemInstallFastMemoryHook((PVOID)MemoryBase[MemoryMap],
+ MemorySize[MemoryMap],
+ VgaReadMemory,
+ VgaWriteMemory);
+ }
+
/* The GC misc register decides if it's text or graphics mode */
ModeChanged = TRUE;
break;
static inline VOID VgaWriteDac(BYTE Data)
{
- INT i, PaletteIndex;
+ UINT i, PaletteIndex;
PALETTEENTRY Entry;
/* Set the value */
UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
}
- // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
+ /* Remove any existing VGA memory hook */
+ MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000);
+
+ if (VgaMiscRegister & VGA_MISC_RAM_ENABLED)
+ {
+ UCHAR MemoryMap = (VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03;
+
+ /* Register a memory hook */
+ MemInstallFastMemoryHook((PVOID)MemoryBase[MemoryMap],
+ MemorySize[MemoryMap],
+ VgaReadMemory,
+ VgaWriteMemory);
+ }
+
break;
}
UNREFERENCED_PARAMETER(ElapsedTime);
- /* Set the vertical retrace flag */
- InVerticalRetrace = TRUE;
+ /* Set the vertical retrace cycle */
+ VerticalRetraceCycle = GetCycleCount();
/* If nothing has changed, just return */
// if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate)
{
UNREFERENCED_PARAMETER(ElapsedTime);
- /* Set the flag */
- InHorizontalRetrace = TRUE;
+ /* Set the cycle */
+ HorizontalRetraceCycle = GetCycleCount();
}
/* PUBLIC FUNCTIONS ***********************************************************/
VgaVerticalRetrace(0);
}
-VOID NTAPI VgaReadMemory(ULONG Address, PVOID Buffer, ULONG Size)
+VOID FASTCALL VgaReadMemory(ULONG Address, PVOID Buffer, ULONG Size)
{
- DWORD i;
+ DWORD i, j;
DWORD VideoAddress;
PUCHAR BufPtr = (PUCHAR)Buffer;
DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address, Size);
- Address = min(max(Address, VgaGetVideoBaseAddress()), VgaGetVideoLimitAddress());
- Size = min(Size, VgaGetVideoLimitAddress() - Address + 1);
/* Ignore if video RAM access is disabled */
if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
- /* Loop through each byte */
- for (i = 0; i < Size; i++)
+ if (!(VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_READ))
+ {
+ /* Loop through each byte */
+ for (i = 0; i < Size; i++)
+ {
+ VideoAddress = VgaTranslateReadAddress(Address + i);
+
+ /* Copy the value to the buffer */
+ BufPtr[i] = VgaMemory[VideoAddress];
+ }
+ }
+ else
{
- VideoAddress = VgaTranslateReadAddress(Address + i);
+ /* Loop through each byte */
+ for (i = 0; i < Size; i++)
+ {
+ BYTE Result = 0xFF;
- /* Copy the value to the buffer */
- BufPtr[i] = VgaMemory[VideoAddress];
+ /* This should always return a plane 0 address for read mode 1 */
+ VideoAddress = VgaTranslateReadAddress(Address + i);
+
+ for (j = 0; j < VGA_NUM_BANKS; j++)
+ {
+ /* Don't consider ignored banks */
+ if (!(VgaGcRegisters[VGA_GC_COLOR_IGNORE_REG] & (1 << j))) continue;
+
+ if (VgaGcRegisters[VGA_GC_COLOR_COMPARE_REG] & (1 << j))
+ {
+ /* Comparing with 11111111 */
+ Result &= VgaMemory[j * VGA_BANK_SIZE + LOWORD(VideoAddress)];
+ }
+ else
+ {
+ /* Comparing with 00000000 */
+ Result &= ~(VgaMemory[j * VGA_BANK_SIZE + LOWORD(VideoAddress)]);
+ }
+ }
+
+ /* Copy the value to the buffer */
+ BufPtr[i] = Result;
+ }
}
/* Load the latch registers */
VgaLatchRegisters[3] = VgaMemory[(3 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
}
-BOOLEAN NTAPI VgaWriteMemory(ULONG Address, PVOID Buffer, ULONG Size)
+BOOLEAN FASTCALL VgaWriteMemory(ULONG Address, PVOID Buffer, ULONG Size)
{
DWORD i, j;
DWORD VideoAddress;
PUCHAR BufPtr = (PUCHAR)Buffer;
DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address, Size);
- Address = min(max(Address, VgaGetVideoBaseAddress()), VgaGetVideoLimitAddress());
- Size = min(Size, VgaGetVideoLimitAddress() - Address + 1);
/* Ignore if video RAM access is disabled */
if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return TRUE;
/* Clear the VGA memory */
VgaClearMemory();
-
- /* Register the memory hook */
- MemInstallFastMemoryHook((PVOID)0xA0000, 0x20000, VgaReadMemory, VgaWriteMemory);
/* Register the I/O Ports */
RegisterIoPort(0x3CC, VgaReadPort, NULL); // VGA_MISC_READ