diff --git a/src/Emulator/Cores/tlib b/src/Emulator/Cores/tlib index abfca538f..55c8360db 160000 --- a/src/Emulator/Cores/tlib +++ b/src/Emulator/Cores/tlib @@ -1 +1 @@ -Subproject commit abfca538ff73b61a4913041dd94e6916a328c77b +Subproject commit 55c8360dbd576ca0d341b73c95d109a2a88e6b80 diff --git a/src/Emulator/Peripherals/Peripherals/CPU/BaseCPU.cs b/src/Emulator/Peripherals/Peripherals/CPU/BaseCPU.cs index 1e4d2cc35..e8fa9117c 100644 --- a/src/Emulator/Peripherals/Peripherals/CPU/BaseCPU.cs +++ b/src/Emulator/Peripherals/Peripherals/CPU/BaseCPU.cs @@ -792,14 +792,13 @@ protected CpuResult CpuThreadBodyInner(bool singleStep, bool skipThisRound = fal this.Trace(); var instructionsToSkip = Math.Min(InstructionsToNearestLimit(), instructionsLeftThisRound); - virtualTimeAhead = machine.LocalTimeSource.ElapsedVirtualHostTimeDifference; - if(!machine.LocalTimeSource.AdvanceImmediately && virtualTimeAhead.Ticks > 0 && instructionsToSkip > 0) + if(!machine.LocalTimeSource.AdvanceImmediately && instructionsToSkip > 0) { - // Don't fall behind realtime by sleeping - var intervalToSleep = TimeInterval.FromCPUCycles(instructionsToSkip, PerformanceInMips, out var cyclesResiduum).WithTicksMin(virtualTimeAhead.Ticks); + // Sleep for the full remaining quantum while waiting for an interrupt. + // sleeper.Interrupt() from OnGPIO will wake us early when an IRQ arrives, + // so we only burn host CPU for the actual wait duration, not the full quantum. + var intervalToSleep = TimeInterval.FromCPUCycles(instructionsToSkip, PerformanceInMips, out var cyclesResiduum); sleeper.Sleep(intervalToSleep.ToTimeSpan(out var nsResiduum), out var intervalSlept); - // If we have a CPU of less than 10 MIPS, it might be the case that the interval slept (which is in units of 100 ns) - // is less than 1 instruction. Just round up it in this case. instructionsToSkip = Math.Max(TimeInterval.FromTimeSpan(intervalSlept, nsResiduum).ToCPUCycles(PerformanceInMips, out var _) + cyclesResiduum, 1); }