X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=subsystems%2Fmvdm%2Fntvdm%2Fhardware%2Fvideo%2Fsvga.c;h=209f8ead5a91890b704c199d21db2b8b8d1884f8;hp=f10cd3398ad0c92e777ac21ff494327e6008f0f5;hb=807331436ee5de09dbd34013fbbf237b7a92cc63;hpb=321bcc056d3a807b7c212f91663b592178f8b819 diff --git a/subsystems/mvdm/ntvdm/hardware/video/svga.c b/subsystems/mvdm/ntvdm/hardware/video/svga.c index f10cd3398ad..209f8ead5a9 100644 --- a/subsystems/mvdm/ntvdm/hardware/video/svga.c +++ b/subsystems/mvdm/ntvdm/hardware/video/svga.c @@ -25,6 +25,9 @@ /* PRIVATE VARIABLES **********************************************************/ +#define WRAP_OFFSET(x) ((VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_ADDR_WRAP) \ + ? ((x) & 0xFFFFF) : LOWORD(x)) + static CONST DWORD MemoryBase[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 }; static CONST DWORD MemorySize[] = { 0x20000, 0x10000, 0x08000, 0x08000 }; @@ -269,10 +272,11 @@ static BYTE VgaDacRegisters[VGA_PALETTE_SIZE]; // static VGA_REGISTERS VgaRegisters; -static ULONGLONG VerticalRetraceCycle = 0ULL; static ULONGLONG HorizontalRetraceCycle = 0ULL; -static PHARDWARE_TIMER VSyncTimer; static PHARDWARE_TIMER HSyncTimer; +static DWORD ScanlineCounter = 0; +static DWORD StartAddressLatch = 0; +static DWORD ScanlineSizeLatch = 0; static BOOLEAN NeedsUpdate = FALSE; static BOOLEAN ModeChanged = FALSE; @@ -313,7 +317,12 @@ static inline DWORD VgaGetVideoBaseAddress(VOID) static inline DWORD VgaGetAddressSize(VOID) { - if (VgaCrtcRegisters[VGA_CRTC_UNDERLINE_REG] & VGA_CRTC_UNDERLINE_DWORD) + if (VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES) + { + /* Packed pixel addressing */ + return 1; + } + else if (VgaCrtcRegisters[VGA_CRTC_UNDERLINE_REG] & VGA_CRTC_UNDERLINE_DWORD) { /* Double-word addressing */ return 4; // sizeof(DWORD) @@ -330,49 +339,29 @@ static inline DWORD VgaGetAddressSize(VOID) } } -static inline DWORD VgaTranslateReadAddress(DWORD Address) +static inline DWORD VgaTranslateAddress(DWORD Address) { DWORD Offset = LOWORD(Address - VgaGetVideoBaseAddress()); - BYTE Plane; + DWORD ExtOffset = ((VgaGcRegisters[SVGA_GC_EXT_MODE_REG] & SVGA_GC_EXT_MODE_WND_B) && (Offset & (1 << 15))) + ? VgaGcRegisters[SVGA_GC_OFFSET_1_REG] + : VgaGcRegisters[SVGA_GC_OFFSET_0_REG]; /* Check for chain-4 and odd-even mode */ if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4) { - /* The lowest two bits are the plane number */ - Plane = Offset & 0x03; + /* Clear the lowest two bits since they're used to select the bank */ Offset &= ~3; } else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE) { - /* The LSB is the plane number */ - Plane = Offset & 0x01; + /* Clear the lowest bit since it's used to select odd/even */ Offset &= ~1; } - else - { - /* Use the read mode */ - Plane = VgaGcRegisters[VGA_GC_READ_MAP_SEL_REG] & 0x03; - } - - /* 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 = LOWORD(Address - VgaGetVideoBaseAddress()); - - /* Check for chain-4 and odd-even mode */ - if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4) + if (ExtOffset) { - /* Clear the lowest two bits since they're used to select the bank */ - Offset &= ~3; - } - else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE) - { - /* Clear the lowest bit since it's used to select odd/even */ - Offset &= ~1; + /* Add the extended offset */ + Offset += ExtOffset << ((VgaGcRegisters[SVGA_GC_EXT_MODE_REG] & SVGA_GC_EXT_MODE_GRAN) ? 14 : 12); } /* Return the offset on plane 0 */ @@ -748,15 +737,11 @@ static VOID VgaUpdateFramebuffer(VOID) { SHORT i, j, k; DWORD AddressSize = VgaGetAddressSize(); - DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2; - BYTE PresetRowScan = VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] & 0x1F; + DWORD Address = StartAddressLatch; BYTE BytePanning = (VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] >> 5) & 3; - DWORD Address = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG], - VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG]) - + PresetRowScan * ScanlineSize - + BytePanning; WORD LineCompare = VgaCrtcRegisters[VGA_CRTC_LINE_COMPARE_REG] - | ((VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_LC8) << 4); + | ((VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_LC8) << 4) + | ((VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_LC9) << 3); BYTE PixelShift = VgaAcRegisters[VGA_AC_HORZ_PANNING_REG] & 0x0F; /* @@ -829,112 +814,116 @@ static VOID VgaUpdateFramebuffer(VOID) /* Apply horizontal pixel panning */ if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) { - X = j + (PixelShift >> 1); + X = j + ((PixelShift >> 1) & 0x03); } else { - X = j + PixelShift; + X = j + ((PixelShift < 8) ? PixelShift : -1); } - /* Check the shifting mode */ - if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFT256) + if (VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES) { - /* 4 bits shifted from each plane */ + // TODO: Check for high color modes - /* Check if this is 16 or 256 color mode */ - if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) - { - /* One byte per pixel */ - PixelData = VgaMemory[(X % VGA_NUM_BANKS) * VGA_BANK_SIZE - + LOWORD((Address + (X / VGA_NUM_BANKS)) - * AddressSize)]; - } - else + /* 256 color mode */ + PixelData = VgaMemory[Address + X]; + } + else + { + /* Check the shifting mode */ + if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFT256) { - /* 4-bits per pixel */ + /* 4 bits shifted from each plane */ - 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 (((X / VGA_NUM_BANKS) % 2) == 0) + /* Check if this is 16 or 256 color mode */ + if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) { - /* Highest 4 */ - PixelData >>= 4; + /* One byte per pixel */ + PixelData = VgaMemory[WRAP_OFFSET((Address + (X / VGA_NUM_BANKS)) * AddressSize) + * VGA_NUM_BANKS + (X % VGA_NUM_BANKS)]; } else { - /* Lowest 4 */ - PixelData &= 0x0F; + /* 4-bits per pixel */ + + PixelData = VgaMemory[WRAP_OFFSET((Address + (X / (VGA_NUM_BANKS * 2))) * AddressSize) + * VGA_NUM_BANKS + ((X / 2) % VGA_NUM_BANKS)]; + + /* Check if we should use the highest 4 bits or lowest 4 */ + if ((X % 2) == 0) + { + /* Highest 4 */ + PixelData >>= 4; + } + else + { + /* Lowest 4 */ + PixelData &= 0x0F; + } } } - } - else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFTREG) - { - /* Check if this is 16 or 256 color mode */ - if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) + else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFTREG) { - // TODO: NOT IMPLEMENTED - DPRINT1("8-bit interleaved mode is not implemented!\n"); + /* Check if this is 16 or 256 color mode */ + if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) + { + // TODO: NOT IMPLEMENTED + DPRINT1("8-bit interleaved mode is not implemented!\n"); + } + else + { + /* + * 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 = (X / 4) % 2; + DWORD Offset = Address + (X / 8); + BYTE LowPlaneData = VgaMemory[WRAP_OFFSET(Offset * AddressSize) * VGA_NUM_BANKS + BankNumber]; + BYTE HighPlaneData = VgaMemory[WRAP_OFFSET(Offset * AddressSize) * VGA_NUM_BANKS + (BankNumber + 2)]; + + /* Extract the two bits from each plane */ + LowPlaneData = (LowPlaneData >> (6 - ((X % 4) * 2))) & 0x03; + HighPlaneData = (HighPlaneData >> (6 - ((X % 4) * 2))) & 0x03; + + /* Combine them into the pixel */ + PixelData = LowPlaneData | (HighPlaneData << 2); + } } else { - /* - * 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 = (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 - ((X % 4) * 2))) & 0x03; - HighPlaneData = (HighPlaneData >> (6 - ((X % 4) * 2))) & 0x03; - - /* Combine them into the pixel */ - PixelData = LowPlaneData | (HighPlaneData << 2); - } - } - else - { - /* 1 bit shifted from each plane */ - - /* Check if this is 16 or 256 color mode */ - if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) - { - /* 8 bits per pixel, 2 on each plane */ + /* 1 bit shifted from each plane */ - for (k = 0; k < VGA_NUM_BANKS; k++) + /* Check if this is 16 or 256 color mode */ + if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) { - /* The data is on plane k, 4 pixels per byte */ - BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE - + LOWORD((Address + (X / VGA_NUM_BANKS)) - * AddressSize)]; + /* 8 bits per pixel, 2 on each plane */ - /* The mask of the first bit in the pair */ - BYTE BitMask = 1 << (((3 - (X % VGA_NUM_BANKS)) * 2) + 1); + for (k = 0; k < VGA_NUM_BANKS; k++) + { + /* The data is on plane k, 4 pixels per byte */ + BYTE PlaneData = VgaMemory[WRAP_OFFSET((Address + (X >> 2)) * AddressSize) * VGA_NUM_BANKS + k]; - /* Bits 0, 1, 2 and 3 come from the first bit of the pair */ - if (PlaneData & BitMask) PixelData |= 1 << k; + /* The mask of the first bit in the pair */ + BYTE BitMask = 1 << (((3 - (X % VGA_NUM_BANKS)) * 2) + 1); - /* Bits 4, 5, 6 and 7 come from the second bit of the pair */ - if (PlaneData & (BitMask >> 1)) PixelData |= 1 << (k + 4); - } - } - else - { - /* 4 bits per pixel, 1 on each plane */ + /* 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++) + /* Bits 4, 5, 6 and 7 come from the second bit of the pair */ + if (PlaneData & (BitMask >> 1)) PixelData |= 1 << (k + 4); + } + } + else { - BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE - + LOWORD((Address + (X / (VGA_NUM_BANKS * 2))) - * AddressSize)]; + /* 4 bits per pixel, 1 on each plane */ + + for (k = 0; k < VGA_NUM_BANKS; k++) + { + BYTE PlaneData = VgaMemory[WRAP_OFFSET((Address + (X >> 3)) * AddressSize) * VGA_NUM_BANKS + k]; - /* If the bit on that plane is set, set it */ - if (PlaneData & (1 << (7 - (X % 8)))) PixelData |= 1 << k; + /* If the bit on that plane is set, set it */ + if (PlaneData & (1 << (7 - (X % 8)))) PixelData |= 1 << k; + } } } } @@ -946,8 +935,26 @@ static VOID VgaUpdateFramebuffer(VOID) * if external palette access is disabled, otherwise (in case * of palette loading) it is a blank pixel. */ - PixelData = (VgaAcPalDisable ? VgaAcRegisters[PixelData & 0x0F] - : 0); + + if (VgaAcPalDisable) + { + if (!(VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_P54S)) + { + /* Bits 4 and 5 are taken from the palette register */ + PixelData = ((VgaAcRegisters[VGA_AC_COLOR_SEL_REG] << 4) & 0xC0) + | (VgaAcRegisters[PixelData & 0x0F] & 0x3F); + } + else + { + /* Bits 4 and 5 are taken from the color select register */ + PixelData = (VgaAcRegisters[VGA_AC_COLOR_SEL_REG] << 4) + | (VgaAcRegisters[PixelData & 0x0F] & 0x0F); + } + } + else + { + PixelData = 0; + } } /* Take into account DoubleVision mode when checking for pixel updates */ @@ -1015,7 +1022,7 @@ static VOID VgaUpdateFramebuffer(VOID) if (!(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) || (i & 1)) { /* Move to the next scanline */ - Address += ScanlineSize; + Address += ScanlineSizeLatch; } } @@ -1044,13 +1051,13 @@ static VOID VgaUpdateFramebuffer(VOID) /* Loop through the characters */ for (j = 0; j < CurrResolution.X; j++) { - CurrentAddr = LOWORD((Address + j) * AddressSize); + CurrentAddr = WRAP_OFFSET((Address + j) * AddressSize); /* Plane 0 holds the character itself */ - CharInfo.Char = VgaMemory[CurrentAddr]; + CharInfo.Char = VgaMemory[CurrentAddr * VGA_NUM_BANKS]; /* Plane 1 holds the attribute */ - CharInfo.Attributes = VgaMemory[CurrentAddr + VGA_BANK_SIZE]; + CharInfo.Attributes = VgaMemory[CurrentAddr * VGA_NUM_BANKS + 1]; /* Now check if the resulting character data has changed */ if ((CharBuffer[i * CurrResolution.X + j].Char != CharInfo.Char) || @@ -1065,7 +1072,7 @@ static VOID VgaUpdateFramebuffer(VOID) } /* Move to the next scanline */ - Address += ScanlineSize; + Address += ScanlineSizeLatch; } } } @@ -1113,20 +1120,35 @@ static BYTE WINAPI VgaReadPort(USHORT Port) { BYTE Result = 0; BOOLEAN Vsync, Hsync; - ULONGLONG Cycles = GetCycleCount(); - ULONG CyclesPerMicrosecond = (ULONG)((GetCycleSpeed() + 500000ULL) / 1000000ULL); + ULONGLONG Cycles = CurrentCycleCount; + ULONG CyclesPerMicrosecond = (ULONG)((CurrentIps + 500000ULL) / 1000000ULL); ULONG Dots = (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & 1) ? 9 : 8; ULONG Clock = VgaGetClockFrequency() / 1000000; - 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; + ULONG HblankStart, HblankEnd; + ULONG HblankDuration; + ULONG VerticalRetraceStart = VgaCrtcRegisters[VGA_CRTC_START_VERT_RETRACE_REG]; + ULONG VerticalRetraceEnd; + + VerticalRetraceStart |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VRS8) << 6; + VerticalRetraceStart |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VRS9) << 2; + + VerticalRetraceEnd = VerticalRetraceStart + (VgaCrtcRegisters[VGA_CRTC_END_VERT_RETRACE_REG] & 0x0F); + + if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) + { + BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F); + + if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE) + { + VerticalRetraceStart <<= 1; + VerticalRetraceEnd <<= 1; + } + else + { + VerticalRetraceStart *= MaximumScanLine; + VerticalRetraceEnd *= MaximumScanLine; + } + } /* Calculate the horizontal blanking duration in cycles */ HblankStart = VgaCrtcRegisters[VGA_CRTC_START_HORZ_BLANKING_REG] & 0x1F; @@ -1135,16 +1157,12 @@ static BYTE WINAPI VgaReadPort(USHORT Port) HblankDuration = ((HblankEnd - HblankStart) * Dots * CyclesPerMicrosecond + (Clock >> 1)) / Clock; - Vsync = (Cycles - VerticalRetraceCycle) < (ULONGLONG)VblankDuration; + Vsync = ScanlineCounter >= VerticalRetraceStart && ScanlineCounter <= VerticalRetraceEnd; 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 (Vsync || Hsync) Result |= VGA_STAT_DD; @@ -1158,7 +1176,7 @@ static BYTE WINAPI VgaReadPort(USHORT Port) return VgaFeatureRegister; case VGA_AC_INDEX: - return VgaAcIndex; + return VgaAcIndex | (VgaAcPalDisable ? 0x20 : 0x00); case VGA_AC_READ: return VgaAcRegisters[VgaAcIndex]; @@ -1278,7 +1296,7 @@ static inline VOID VgaWriteGc(BYTE Data) UCHAR MemoryMap = (VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03; /* Register a memory hook */ - MemInstallFastMemoryHook((PVOID)MemoryBase[MemoryMap], + MemInstallFastMemoryHook(UlongToPtr(MemoryBase[MemoryMap]), MemorySize[MemoryMap], VgaReadMemory, VgaWriteMemory); @@ -1448,7 +1466,7 @@ static VOID WINAPI VgaWritePort(USHORT Port, BYTE Data) UCHAR MemoryMap = (VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03; /* Register a memory hook */ - MemInstallFastMemoryHook((PVOID)MemoryBase[MemoryMap], + MemInstallFastMemoryHook(UlongToPtr(MemoryBase[MemoryMap]), MemorySize[MemoryMap], VgaReadMemory, VgaWriteMemory); @@ -1592,13 +1610,8 @@ static VOID WINAPI VgaWritePort(USHORT Port, BYTE Data) SvgaHdrCounter = 0; } -static VOID FASTCALL VgaVerticalRetrace(ULONGLONG ElapsedTime) +static inline VOID VgaVerticalRetrace(VOID) { - UNREFERENCED_PARAMETER(ElapsedTime); - - /* Set the vertical retrace cycle */ - VerticalRetraceCycle = GetCycleCount(); - /* If nothing has changed, just return */ // if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate) // return; @@ -1641,10 +1654,72 @@ static VOID FASTCALL VgaVerticalRetrace(ULONGLONG ElapsedTime) static VOID FASTCALL VgaHorizontalRetrace(ULONGLONG ElapsedTime) { + ULONG VerticalTotal = VgaCrtcRegisters[VGA_CRTC_VERT_TOTAL_REG]; + ULONG VerticalRetraceStart = VgaCrtcRegisters[VGA_CRTC_START_VERT_RETRACE_REG]; + BOOLEAN BeforeVSync; + ULONG ElapsedCycles = CurrentCycleCount - HorizontalRetraceCycle; + ULONG Dots = (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & 1) ? 9 : 8; + ULONG HorizTotalDots = ((ULONG)VgaCrtcRegisters[VGA_CRTC_HORZ_TOTAL_REG] + 5) * Dots; + BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F); + ULONG HSyncsPerSecond, HSyncs; UNREFERENCED_PARAMETER(ElapsedTime); + if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) HorizTotalDots >>= 1; + + HSyncsPerSecond = VgaGetClockFrequency() / HorizTotalDots; + HSyncs = (ElapsedCycles * HSyncsPerSecond + (CurrentIps >> 1)) / CurrentIps; + if (HSyncs == 0) HSyncs = 1; + + VerticalTotal |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VT8) << 8; + VerticalTotal |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VT9) << 4; + + VerticalRetraceStart |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VRS8) << 6; + VerticalRetraceStart |= (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VRS9) << 2; + + if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) + { + if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE) + { + VerticalRetraceStart <<= 1; + VerticalTotal <<= 1; + } + else + { + VerticalRetraceStart *= MaximumScanLine; + VerticalTotal *= MaximumScanLine; + } + } + /* Set the cycle */ - HorizontalRetraceCycle = GetCycleCount(); + HorizontalRetraceCycle = CurrentCycleCount; + + /* Increment the scanline counter, but make sure we don't skip any part of the vertical retrace */ + BeforeVSync = (ScanlineCounter < VerticalRetraceStart); + ScanlineCounter += HSyncs; + if (BeforeVSync && ScanlineCounter >= VerticalRetraceStart) ScanlineCounter = VerticalRetraceStart; + + if (ScanlineCounter == VerticalRetraceStart) + { + /* Save the scanline size */ + ScanlineSizeLatch = ((DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] + + (((DWORD)VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_OFFSET_BIT8) << 4)) * 2; + if (VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES) ScanlineSizeLatch <<= 2; + + /* Save the starting address */ + StartAddressLatch = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG], + VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG]) + + ((VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_ADDR_BIT16) << 16) + + ((VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_ADDR_BITS1718) << 15) + + ((VgaCrtcRegisters[SVGA_CRTC_OVERLAY_REG] & SVGA_CRTC_EXT_ADDR_BIT19) << 12) + + (VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] & 0x1F) * ScanlineSizeLatch + + ((VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] >> 5) & 3); + } + + if (ScanlineCounter > VerticalTotal) + { + ScanlineCounter = 0; + VgaVerticalRetrace(); + } } /* PUBLIC FUNCTIONS ***********************************************************/ @@ -1674,12 +1749,20 @@ COORD VgaGetDisplayResolution(VOID) if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) { - /* Multiply the horizontal resolution by the 9/8 dot mode */ - Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM) - ? 8 : 9; + /* In "High Resolution" mode, the width of a character is always 8 pixels */ + if (VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES) + { + Resolution.X *= 8; + } + else + { + /* Multiply the horizontal resolution by the 9/8 dot mode */ + Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM) + ? 8 : 9; - /* The horizontal resolution is halved in 8-bit mode */ - if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2; + /* The horizontal resolution is halved in 8-bit mode */ + if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2; + } } if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE) @@ -1699,68 +1782,201 @@ COORD VgaGetDisplayResolution(VOID) VOID VgaRefreshDisplay(VOID) { - VgaVerticalRetrace(0); + /* Save the scanline size */ + ScanlineSizeLatch = ((DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] + + (((DWORD)VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_OFFSET_BIT8) << 4)) * 2; + if (VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES) ScanlineSizeLatch <<= 2; + + /* Save the starting address */ + StartAddressLatch = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG], + VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG]) + + ((VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_ADDR_BIT16) << 16) + + ((VgaCrtcRegisters[SVGA_CRTC_EXT_DISPLAY_REG] & SVGA_CRTC_EXT_ADDR_BITS1718) << 15) + + ((VgaCrtcRegisters[SVGA_CRTC_OVERLAY_REG] & SVGA_CRTC_EXT_ADDR_BIT19) << 12) + + (VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] & 0x1F) * ScanlineSizeLatch + + ((VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] >> 5) & 3); + + VgaVerticalRetrace(); } VOID FASTCALL VgaReadMemory(ULONG Address, PVOID Buffer, ULONG Size) { - DWORD i, j; + DWORD i; DWORD VideoAddress; PUCHAR BufPtr = (PUCHAR)Buffer; DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address, Size); /* Ignore if video RAM access is disabled */ + if (!Size) return; if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return; if (!(VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_READ)) { - /* Loop through each byte */ - for (i = 0; i < Size; i++) + VideoAddress = VgaTranslateAddress(Address); + + /* Check for packed pixel, chain-4, and odd-even mode */ + if (VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES) { - VideoAddress = VgaTranslateReadAddress(Address + i); + /* Just copy from the video memory */ + PVOID VideoMemory = &VgaMemory[VideoAddress + (Address & 3)]; - /* Copy the value to the buffer */ - BufPtr[i] = VgaMemory[VideoAddress]; + switch (Size) + { + case sizeof(UCHAR): + *(PUCHAR)Buffer = *(PUCHAR)VideoMemory; + return; + + case sizeof(USHORT): + *(PUSHORT)Buffer = *(PUSHORT)VideoMemory; + return; + + case sizeof(ULONG): + *(PULONG)Buffer = *(PULONG)VideoMemory; + return; + + case sizeof(ULONGLONG): + *(PULONGLONG)Buffer = *(PULONGLONG)VideoMemory; + return; + + default: +#if defined(__GNUC__) + __builtin_memcpy(Buffer, VideoMemory, Size); +#else + RtlCopyMemory(Buffer, VideoMemory, Size); +#endif + } + } + else if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4) + { + i = 0; + + /* Write the unaligned part first */ + if (Address & 3) + { + switch (Address & 3) + { + case 1: + BufPtr[i++] = VgaMemory[VideoAddress * VGA_NUM_BANKS + 1]; + case 2: + BufPtr[i++] = VgaMemory[VideoAddress * VGA_NUM_BANKS + 2]; + case 3: + BufPtr[i++] = VgaMemory[VideoAddress * VGA_NUM_BANKS + 3]; + } + + VideoAddress += 4; + } + + /* Copy the aligned dwords */ + while ((i + 3) < Size) + { + *(PULONG)&BufPtr[i] = *(PULONG)&VgaMemory[VideoAddress * VGA_NUM_BANKS]; + + i += 4; + VideoAddress += 4; + } + + /* Write the remaining part */ + if (i < Size) + { + switch (Size - i - 3) + { + case 3: + BufPtr[i] = VgaMemory[VideoAddress * VGA_NUM_BANKS + ((Address + i) & 3)]; + i++; + case 2: + BufPtr[i] = VgaMemory[VideoAddress * VGA_NUM_BANKS + ((Address + i) & 3)]; + i++; + case 1: + BufPtr[i] = VgaMemory[VideoAddress * VGA_NUM_BANKS + ((Address + i) & 3)]; + i++; + } + } + } + else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE) + { + i = 0; + + /* Check if the starting address is odd */ + if (Address & 1) + { + BufPtr[i++] = VgaMemory[VideoAddress * VGA_NUM_BANKS + 1]; + VideoAddress += 2; + } + + while (i < (Size - 1)) + { + *(PUSHORT)&BufPtr[i] = *(PUSHORT)&VgaMemory[VideoAddress * VGA_NUM_BANKS]; + + i += 2; + VideoAddress += 2; + } + + /* Check if there is one more byte to read */ + if (i == Size - 1) BufPtr[i] = VgaMemory[VideoAddress * VGA_NUM_BANKS + ((Address + i) & 1)]; + } + else + { + /* Use the selected map */ + BYTE Plane = VgaGcRegisters[VGA_GC_READ_MAP_SEL_REG] & 0x03; + + for (i = 0; i < Size; i++) + { + /* Copy the value to the buffer */ + BufPtr[i] = VgaMemory[(VideoAddress++) * VGA_NUM_BANKS + Plane]; + } } } else { + const ULONG BitExpandInvertTable[] = + { + 0xFFFFFFFF, 0xFFFFFF00, 0xFFFF00FF, 0xFFFF0000, + 0xFF00FFFF, 0xFF00FF00, 0xFF0000FF, 0xFF000000, + 0x00FFFFFF, 0x00FFFF00, 0x00FF00FF, 0x00FF0000, + 0x0000FFFF, 0x0000FF00, 0x000000FF, 0x00000000 + }; + + ULONG ColorCompareBytes = BitExpandInvertTable[VgaGcRegisters[VGA_GC_COLOR_COMPARE_REG] & 0x0F]; + ULONG ColorIgnoreBytes = BitExpandInvertTable[VgaGcRegisters[VGA_GC_COLOR_IGNORE_REG] & 0x0F]; + + /* + * These values can also be computed in the following way, but using the table seems to be faster: + * + * ColorCompareBytes = VgaGcRegisters[VGA_GC_COLOR_COMPARE_REG] * 0x000204081; + * ColorCompareBytes &= 0x01010101; + * ColorCompareBytes = ~((ColorCompareBytes << 8) - ColorCompareBytes); + * + * ColorIgnoreBytes = VgaGcRegisters[VGA_GC_COLOR_IGNORE_REG] * 0x000204081; + * ColorIgnoreBytes &= 0x01010101; + * ColorIgnoreBytes = ~((ColorIgnoreBytes << 8) - ColorIgnoreBytes); + */ + /* Loop through each byte */ for (i = 0; i < Size; i++) { - BYTE Result = 0xFF; + ULONG PlaneData = 0; - /* This should always return a plane 0 address for read mode 1 */ - VideoAddress = VgaTranslateReadAddress(Address + i); + /* This should always return a plane 0 address */ + VideoAddress = VgaTranslateAddress(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; + /* Read all 4 planes */ + PlaneData = *(PULONG)&VgaMemory[VideoAddress * VGA_NUM_BANKS]; - 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)]); - } - } + /* Reverse the bytes for which the color compare register is zero */ + PlaneData ^= ColorCompareBytes; - /* Copy the value to the buffer */ - BufPtr[i] = Result; + /* Apply the color ignore register */ + PlaneData |= ColorIgnoreBytes; + + /* Store the value in the buffer */ + BufPtr[i] = (PlaneData & (PlaneData >> 8) & (PlaneData >> 16) & (PlaneData >> 24)) & 0xFF; } } /* Load the latch registers */ - VgaLatchRegisters[0] = VgaMemory[LOWORD(VideoAddress)]; - VgaLatchRegisters[1] = VgaMemory[VGA_BANK_SIZE + LOWORD(VideoAddress)]; - VgaLatchRegisters[2] = VgaMemory[(2 * VGA_BANK_SIZE) + LOWORD(VideoAddress)]; - VgaLatchRegisters[3] = VgaMemory[(3 * VGA_BANK_SIZE) + LOWORD(VideoAddress)]; + VideoAddress = VgaTranslateAddress(Address + Size - 1); + *(PULONG)VgaLatchRegisters = *(PULONG)&VgaMemory[WRAP_OFFSET(VideoAddress) * VGA_NUM_BANKS]; } BOOLEAN FASTCALL VgaWriteMemory(ULONG Address, PVOID Buffer, ULONG Size) @@ -1777,38 +1993,78 @@ BOOLEAN FASTCALL VgaWriteMemory(ULONG Address, PVOID Buffer, ULONG Size) /* Also ignore if write access to all planes is disabled */ if ((VgaSeqRegisters[VGA_SEQ_MASK_REG] & 0x0F) == 0x00) return TRUE; - /* Loop through each byte */ - for (i = 0; i < Size; i++) + if (!(VgaSeqRegisters[SVGA_SEQ_EXT_MODE_REG] & SVGA_SEQ_EXT_MODE_HIGH_RES)) { - VideoAddress = VgaTranslateWriteAddress(Address + i); - - for (j = 0; j < VGA_NUM_BANKS; j++) + /* Loop through each byte */ + for (i = 0; i < Size; i++) { - /* Make sure the page is writeable */ - if (!(VgaSeqRegisters[VGA_SEQ_MASK_REG] & (1 << j))) continue; + VideoAddress = VgaTranslateAddress(Address + i); - /* Check if this is chain-4 mode */ - if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4) + for (j = 0; j < VGA_NUM_BANKS; j++) { - if (((Address + i) & 0x03) != j) + /* Make sure the page is writeable */ + if (!(VgaSeqRegisters[VGA_SEQ_MASK_REG] & (1 << j))) continue; + + /* Check if this is chain-4 mode */ + if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4) { - /* This plane will not be accessed */ - continue; + if (((Address + i) & 0x03) != j) + { + /* This plane will not be accessed */ + continue; + } } - } - /* Check if this is odd-even mode */ - if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE) - { - if (((Address + i) & 0x01) != (j & 1)) + /* Check if this is odd-even mode */ + if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE) { - /* This plane will not be accessed */ - continue; + if (((Address + i) & 0x01) != (j & 1)) + { + /* This plane will not be accessed */ + continue; + } } + + /* Copy the value to the VGA memory */ + VgaMemory[VideoAddress * VGA_NUM_BANKS + j] = VgaTranslateByteForWriting(BufPtr[i], j); } + } + } + else + { + PVOID VideoMemory; - /* Copy the value to the VGA memory */ - VgaMemory[VideoAddress + j * VGA_BANK_SIZE] = VgaTranslateByteForWriting(BufPtr[i], j); + // TODO: Apply the page write mask! + // TODO: Check whether the write mode stuff applies to packed-pixel modes + + /* Just copy to the video memory */ + VideoAddress = VgaTranslateAddress(Address); + VideoMemory = &VgaMemory[VideoAddress + (Address & 3)]; + + switch (Size) + { + case sizeof(UCHAR): + *(PUCHAR)VideoMemory = *(PUCHAR)Buffer; + return TRUE; + + case sizeof(USHORT): + *(PUSHORT)VideoMemory = *(PUSHORT)Buffer; + return TRUE; + + case sizeof(ULONG): + *(PULONG)VideoMemory = *(PULONG)Buffer; + return TRUE; + + case sizeof(ULONGLONG): + *(PULONGLONG)VideoMemory = *(PULONGLONG)Buffer; + return TRUE; + + default: +#if defined(__GNUC__) + __builtin_memcpy(VideoMemory, Buffer, Size); +#else + RtlCopyMemory(VideoMemory, Buffer, Size); +#endif } } @@ -1823,22 +2079,20 @@ VOID VgaClearMemory(VOID) VOID VgaWriteTextModeFont(UINT FontNumber, CONST UCHAR* FontData, UINT Height) { UINT i, j; - PUCHAR FontMemory = (PUCHAR)&VgaMemory[VGA_BANK_SIZE * VGA_FONT_BANK + (FontNumber * VGA_FONT_SIZE)]; - ASSERT(Height <= VGA_MAX_FONT_HEIGHT); - for (i = 0 ; i < VGA_FONT_CHARACTERS; i++) + for (i = 0; i < VGA_FONT_CHARACTERS; i++) { /* Write the character */ for (j = 0; j < Height; j++) { - FontMemory[i * VGA_MAX_FONT_HEIGHT + j] = FontData[i * Height + j]; + VgaMemory[(i * VGA_MAX_FONT_HEIGHT + j) * VGA_NUM_BANKS + VGA_FONT_BANK] = FontData[i * Height + j]; } /* Clear the unused part */ for (j = Height; j < VGA_MAX_FONT_HEIGHT; j++) { - FontMemory[i * VGA_MAX_FONT_HEIGHT + j] = 0; + VgaMemory[(i * VGA_MAX_FONT_HEIGHT + j) * VGA_NUM_BANKS + VGA_FONT_BANK] = 0; } } } @@ -1883,7 +2137,6 @@ BOOLEAN VgaInitialize(HANDLE TextHandle) RegisterIoPort(0x3D9, VgaReadPort, VgaWritePort); // CGA_PAL_CTRL_REG HSyncTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, HZ_TO_NS(31469), VgaHorizontalRetrace); - VSyncTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, HZ_TO_NS(60), VgaVerticalRetrace); /* Return success */ return TRUE; @@ -1894,7 +2147,6 @@ VOID VgaCleanup(VOID) /* Do a final display refresh */ VgaRefreshDisplay(); - DestroyHardwareTimer(VSyncTimer); DestroyHardwareTimer(HSyncTimer); /* Leave the current video mode */