private void CpuLoop()
{
var tlibResult = 0;
if(ClockSource.HasEntries && advanceShouldBeRestarted)
{
try
{
ClockSource.Advance(0, true);
advanceShouldBeRestarted = false;
}
catch(OperationCanceledException)
{
return;
}
}
while(true)
{
if(!(DisableInterruptsWhileStepping && executionMode == ExecutionMode.SingleStep) && TlibIsIrqSet() == 0 && interruptEvents.Any(x => x.WaitOne(0)))
{
for(var i = 0; i < interruptEvents.Length; i++)
{
var decodedInterrupt = DecodeInterrupt(i);
TlibSetIrq((int)decodedInterrupt, interruptEvents[i].WaitOne(0) ? 1 : 0);
}
//this.NoisyLog("IRQ not active while event set, added.");
}
try
{
bool doIteration;
lock(haltedFinishedEvent)
{
doIteration = !isHalted;
}
if(doIteration)
{
Action queuedAction;
while(actionsToExecuteInCpuThread.TryDequeue(out queuedAction))
{
queuedAction();
}
HandleStepping(true);
pauseGuard.Enter();
skipNextStepping = true;
tlibResult = TlibExecute();
pauseGuard.Leave();
}
}
catch(CpuAbortException)
{
this.NoisyLog("CPU abort detected, halting.");
isAborted = true;
InvokeHalted(new HaltArguments(HaltReason.Abort));
break;
}
catch(OperationCanceledException)
{
advanceShouldBeRestarted = true;
break;
}
if(tlibResult == BreakpointResult)
{
ExecuteHooks(PC);
// it is necessary to deactivate hooks installed on this PC before
// calling `tlib_execute` again to avoid a loop;
// we need to do this because creating a breakpoint has caused special
// exeption-rising, block-breaking `trap` instruction to be
// generated by the tcg;
// in order to execute code after the breakpoint we must first remove
// this `trap` and retranslate the code right after it;
// this is achieved by deactivating the breakpoint (i.e., unregistering
// from tlib, but keeping it in C#), executing the beginning of the next
// block and registering the breakpoint again in the OnBlockBegin hook
DeactivateHooks(PC);
}
if(PauseEvent.WaitOne(0))
{
break;
}
if(CheckHalted())
{
if(ClockSource.HasEntries)
{
try
{
var timeToSleep = new TimeSpan(Time.Consts.TimeQuantum.Ticks * ClockSource.NearestLimitIn);
var timeToSleepInMs = Math.Min(int.MaxValue, (int)timeToSleep.TotalMilliseconds);
if(timeToSleepInMs > 0)
{
if(!AdvanceImmediately)
{
WaitHandle.WaitAny(waitHandles, timeToSleepInMs);
}
ClockSource.Advance(Time.Utilities.SecondsToTicks(timeToSleepInMs / 1000.0));
}
else
{
ClockSource.Advance(ClockSource.NearestLimitIn);
}
}
catch(OperationCanceledException)
{
advanceShouldBeRestarted = true;
break;
}
}
else
{
WaitHandle.WaitAny(waitHandles);
}
}
}
}