Beispiel #1
0
        /// <summary>
        /// Starts the virtual machine and runs it until the execution cycle is completed for
        /// a reason.
        /// </summary>
        /// <param name="cancellationToken">Cancellation token</param>
        /// <returns>The reason why the execution completed.</returns>
        public async Task RenderShadowScreen(CancellationToken cancellationToken)
        {
            var lastRunStart         = _clockProvider.GetCounter();
            var lastRenderFrameStart = lastRunStart;

            SpectrumVm.ShadowScreenDevice.FrameCount  = SpectrumVm.ScreenDevice.FrameCount;
            SpectrumVm.ShadowScreenDevice.BorderColor = SpectrumVm.ScreenDevice.BorderColor;
            var frameCount = 0;

            while (!cancellationToken.IsCancellationRequested)
            {
                var lastFrameEnd = _clockProvider.GetCounter();
                LastRenderFrameTicks = lastFrameEnd - lastRenderFrameStart;
                lastRenderFrameStart = lastFrameEnd;
                frameCount++;

                // --- Do additional task when render frame completed
                var screenTacts = SpectrumVm.ScreenConfiguration.ScreenRenderingFrameTactCount;
                SpectrumVm.ShadowScreenDevice.RenderScreen(0, screenTacts - 1);
                SpectrumVm.ShadowScreenDevice.OnNewFrame();
                var renderFrameArgs = new RenderFrameEventArgs(SpectrumVm.ShadowScreenDevice.GetPixelBuffer());
                RenderFrameCompleted?.Invoke(this, renderFrameArgs);
                if (renderFrameArgs.Cancel)
                {
                    return;
                }

                var waitInTicks = lastRunStart + frameCount * _physicalFrameClockCount
                                  - _clockProvider.GetCounter() - _physicalFrameClockCount * 0.2;
                var waitInMs = 1000.0 * waitInTicks / _clockProvider.GetFrequency();
                if (waitInMs > 0)
                {
                    await Task.Delay((int)waitInMs, cancellationToken);

                    if (cancellationToken.IsCancellationRequested)
                    {
                        return;
                    }
                }
                else
                {
                    await Task.Delay(1, cancellationToken);
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Starts the virtual machine and runs it until the execution cycle is completed for
        /// a reason.
        /// </summary>
        /// <param name="cancellationToken">Cancellation token</param>
        /// <param name="options">Virtual machine execution options</param>
        /// <returns>The reason why the execution completed.</returns>
        private async Task <ExecutionCompletionReason> StartAndRun(CancellationToken cancellationToken,
                                                                   ExecuteCycleOptions options)
        {
            LastExecutionContentionValue = ContentionAccumulated;
            var lastRunStart         = _clockProvider.GetCounter();
            var lastRenderFrameStart = lastRunStart;
            var frameCount           = 0;
            var completed            = false;

            while (!completed)
            {
                // --- Execute a single CPU Frame
                var lastCpuFrameStart = _clockProvider.GetCounter();
                var cycleCompleted    = SpectrumVm.ExecuteCycle(cancellationToken, options, true);
                LastCpuFrameTicks = _clockProvider.GetCounter() - lastCpuFrameStart;
                if (!cycleCompleted)
                {
                    return(ExecutionCompletionReason.Cancelled);
                }

                // --- Check for emulated keys
                CpuFrameCount++;
                var hasEmulatedKey = SpectrumVm.KeyboardProvider?.EmulateKeyStroke();
                if (hasEmulatedKey != true)
                {
                    // --- Keyboard scan
                    var keyStatusArgs = new KeyStatusEventArgs();
                    KeyScanning?.Invoke(this, keyStatusArgs);
                    foreach (var keyStatus in keyStatusArgs.KeyStatusList)
                    {
                        SpectrumVm.KeyboardDevice.SetStatus(keyStatus);
                    }
                }

                // --- Do additional tasks when CPU frame completed
                var cancelArgs = new CancelEventArgs(false);
                CpuFrameCompleted?.Invoke(this, cancelArgs);
                if (cancelArgs.Cancel)
                {
                    return(ExecutionCompletionReason.Cancelled);
                }

                switch (SpectrumVm.ExecutionCompletionReason)
                {
                case ExecutionCompletionReason.TerminationPointReached:
                case ExecutionCompletionReason.BreakpointReached:
                case ExecutionCompletionReason.Halted:
                case ExecutionCompletionReason.Exception:
                    completed = true;
                    break;

                case ExecutionCompletionReason.RenderFrameCompleted:
                    var lastFrameEnd = _clockProvider.GetCounter();
                    LastRenderFrameTicks = lastFrameEnd - lastRenderFrameStart;
                    lastRenderFrameStart = lastFrameEnd;
                    completed            = options.EmulationMode == EmulationMode.UntilRenderFrameEnds;
                    frameCount++;
                    RenderFrameCount++;

                    // --- Do additional task when render frame completed
                    var renderFrameArgs = new RenderFrameEventArgs(SpectrumVm.ScreenDevice.GetPixelBuffer());
                    RenderFrameCompleted?.Invoke(this, renderFrameArgs);
                    if (renderFrameArgs.Cancel)
                    {
                        return(ExecutionCompletionReason.Cancelled);
                    }

                    // --- Wait for the next render frame, unless completed
                    if (!completed)
                    {
                        var waitInTicks = lastRunStart + frameCount * _physicalFrameClockCount
                                          - _clockProvider.GetCounter() - _physicalFrameClockCount * 0.2;
                        var waitInMs = 1000.0 * waitInTicks / _clockProvider.GetFrequency();
                        if (waitInMs > 0)
                        {
                            await Task.Delay((int)waitInMs, cancellationToken);

                            if (cancellationToken.IsCancellationRequested)
                            {
                                return(ExecutionCompletionReason.Cancelled);
                            }
                        }
                        else
                        {
                            await Task.Delay(1, cancellationToken);
                        }
                    }
                    break;
                }
            }

            // --- Done, pass back the reason of completing the run
            return(SpectrumVm.ExecutionCompletionReason);
        }