Implement cycle-based timing for VGA.


svn path=/trunk/; revision=68095
This commit is contained in:
Aleksandar Andrejevic 2015-06-09 19:22:52 +00:00
parent d4365a1beb
commit f3c5b91037
4 changed files with 58 additions and 30 deletions

View file

@ -36,26 +36,28 @@
/* VARIABLES ******************************************************************/ /* VARIABLES ******************************************************************/
static LIST_ENTRY Timers; static LIST_ENTRY Timers;
static ULONGLONG Cycles = 0ULL;
static ULONGLONG CurrentIps = 20000000ULL; // 20 MIPS is a good estimate
static LARGE_INTEGER StartPerfCount, Frequency; static LARGE_INTEGER StartPerfCount, Frequency;
// static ULONG StartTickCount; // static ULONG StartTickCount;
static LARGE_INTEGER Counter; static LARGE_INTEGER Counter;
static ULONG CurrentTickCount; static ULONG CurrentTickCount;
static ULONGLONG LastCycles = 0ULL;
#ifdef IPS_DISPLAY
static PHARDWARE_TIMER IpsTimer; static PHARDWARE_TIMER IpsTimer;
static ULONGLONG Cycles = 0ULL;
#endif
/* PRIVATE FUNCTIONS **********************************************************/ /* PRIVATE FUNCTIONS **********************************************************/
#ifdef IPS_DISPLAY static VOID FASTCALL IpsCallback(ULONGLONG ElapsedTime)
static VOID FASTCALL IpsDisplayCallback(ULONGLONG ElapsedTime)
{ {
DPRINT1("NTVDM: %I64u Instructions Per Second\n", Cycles / ElapsedTime); CurrentIps = (Cycles - LastCycles) / ElapsedTime;
Cycles = 0ULL;
} #ifdef IPS_DISPLAY
DPRINT1("NTVDM: %I64u Instructions Per Second\n", CurrentIps);
#endif #endif
LastCycles = Cycles;
}
/* PUBLIC FUNCTIONS ***********************************************************/ /* PUBLIC FUNCTIONS ***********************************************************/
VOID ClockUpdate(VOID) VOID ClockUpdate(VOID)
@ -76,10 +78,7 @@ VOID ClockUpdate(VOID)
for (i = 0; VdmRunning && CpuRunning && (i < STEPS_PER_CYCLE); i++) for (i = 0; VdmRunning && CpuRunning && (i < STEPS_PER_CYCLE); i++)
{ {
CpuStep(); CpuStep();
#ifdef IPS_DISPLAY
++Cycles; ++Cycles;
#endif
} }
for (Entry = Timers.Flink; Entry != &Timers; Entry = Entry->Flink) for (Entry = Timers.Flink; Entry != &Timers; Entry = Entry->Flink)
@ -199,6 +198,16 @@ VOID DestroyHardwareTimer(PHARDWARE_TIMER Timer)
} }
} }
ULONGLONG GetCycleCount(VOID)
{
return Cycles;
}
ULONGLONG GetCycleSpeed(VOID)
{
return CurrentIps;
}
BOOLEAN ClockInitialize(VOID) BOOLEAN ClockInitialize(VOID)
{ {
InitializeListHead(&Timers); InitializeListHead(&Timers);
@ -215,16 +224,12 @@ BOOLEAN ClockInitialize(VOID)
/* Find the starting tick count */ /* Find the starting tick count */
// StartTickCount = GetTickCount(); // StartTickCount = GetTickCount();
#ifdef IPS_DISPLAY IpsTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, HZ_TO_NS(1), IpsCallback);
IpsTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, HZ_TO_NS(1), IpsDisplayCallback);
if (IpsTimer == NULL) if (IpsTimer == NULL)
{ {
wprintf(L"FATAL: Cannot create IPS display timer.\n"); wprintf(L"FATAL: Cannot create IPS timer.\n");
return FALSE; return FALSE;
} }
#endif
return TRUE; return TRUE;
} }

View file

@ -44,6 +44,9 @@ VOID DisableHardwareTimer(PHARDWARE_TIMER Timer);
VOID SetHardwareTimerDelay(PHARDWARE_TIMER Timer, ULONGLONG NewDelay); VOID SetHardwareTimerDelay(PHARDWARE_TIMER Timer, ULONGLONG NewDelay);
VOID DestroyHardwareTimer(PHARDWARE_TIMER Timer); VOID DestroyHardwareTimer(PHARDWARE_TIMER Timer);
ULONGLONG GetCycleCount(VOID);
ULONGLONG GetCycleSpeed(VOID);
VOID ClockUpdate(VOID); VOID ClockUpdate(VOID);
BOOLEAN ClockInitialize(VOID); BOOLEAN ClockInitialize(VOID);

View file

@ -282,8 +282,8 @@ static BYTE VgaDacRegisters[VGA_PALETTE_SIZE];
// static VGA_REGISTERS VgaRegisters; // static VGA_REGISTERS VgaRegisters;
static BOOLEAN InVerticalRetrace = FALSE; static ULONGLONG VerticalRetraceCycle = 0ULL;
static BOOLEAN InHorizontalRetrace = FALSE; static ULONGLONG HorizontalRetraceCycle = 0ULL;
static BOOLEAN NeedsUpdate = FALSE; static BOOLEAN NeedsUpdate = FALSE;
static BOOLEAN ModeChanged = FALSE; static BOOLEAN ModeChanged = FALSE;
@ -1413,8 +1413,31 @@ static BYTE WINAPI VgaReadPort(USHORT Port)
case VGA_INSTAT1_READ_COLOR: case VGA_INSTAT1_READ_COLOR:
{ {
BYTE Result = 0; BYTE Result = 0;
BOOLEAN Vsync = InVerticalRetrace; BOOLEAN Vsync, Hsync;
BOOLEAN Hsync = InHorizontalRetrace; 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 */ /* Reset the AC latch */
VgaAcLatch = FALSE; VgaAcLatch = FALSE;
@ -1429,9 +1452,6 @@ static BYTE WINAPI VgaReadPort(USHORT Port)
/* Set an additional flag if there was a vertical retrace */ /* Set an additional flag if there was a vertical retrace */
if (Vsync) Result |= VGA_STAT_VRETRACE; if (Vsync) Result |= VGA_STAT_VRETRACE;
/* Clear the flags */
InHorizontalRetrace = InVerticalRetrace = FALSE;
return Result; return Result;
} }
@ -1787,8 +1807,8 @@ static VOID FASTCALL VgaVerticalRetrace(ULONGLONG ElapsedTime)
UNREFERENCED_PARAMETER(ElapsedTime); UNREFERENCED_PARAMETER(ElapsedTime);
/* Set the vertical retrace flag */ /* Set the vertical retrace cycle */
InVerticalRetrace = TRUE; VerticalRetraceCycle = GetCycleCount();
/* If nothing has changed, just return */ /* If nothing has changed, just return */
// if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate) // if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate)
@ -1859,8 +1879,8 @@ static VOID FASTCALL VgaHorizontalRetrace(ULONGLONG ElapsedTime)
{ {
UNREFERENCED_PARAMETER(ElapsedTime); UNREFERENCED_PARAMETER(ElapsedTime);
/* Set the flag */ /* Set the cycle */
InHorizontalRetrace = TRUE; HorizontalRetraceCycle = GetCycleCount();
} }
/* PUBLIC FUNCTIONS ***********************************************************/ /* PUBLIC FUNCTIONS ***********************************************************/

View file

@ -161,7 +161,7 @@ enum
VGA_CRTC_OFFSET_REG, VGA_CRTC_OFFSET_REG,
VGA_CRTC_UNDERLINE_REG, VGA_CRTC_UNDERLINE_REG,
VGA_CRTC_START_VERT_BLANKING_REG, VGA_CRTC_START_VERT_BLANKING_REG,
VGA_CRTC_END_VERT_BLANKING, VGA_CRTC_END_VERT_BLANKING_REG,
VGA_CRTC_MODE_CONTROL_REG, VGA_CRTC_MODE_CONTROL_REG,
VGA_CRTC_LINE_COMPARE_REG, VGA_CRTC_LINE_COMPARE_REG,
VGA_CRTC_MAX_REG VGA_CRTC_MAX_REG