Esempio n. 1
0
 static void ListDevices(string[] args)
 {
     try
     {
         foreach (DISPLAY_DEVICE d in ScreenDevice.GetDesktopDevices())
         {
             Console.WriteLine("DEVICE \"" + d.DeviceName + "\":");
             Console.WriteLine("    name = {0}", d.DeviceName);
             Console.WriteLine("  string = {0}", d.DeviceString);
             Console.WriteLine("   flags = {0}", d.StateFlags);
             Console.WriteLine("     key = {0}", d.DeviceKey);
             Console.WriteLine();
         }
     }
     catch (User32Exception e)
     {
         Console.WriteLine("ERROR: " + e.Message);
         return;
     }
 }
Esempio n. 2
0
        /// <summary>
        /// The main execution cycle of the Spectrum VM
        /// </summary>
        /// <param name="token">Cancellation token</param>
        /// <param name="options">Execution options</param>
        /// <return>True, if the cycle completed; false, if it has been cancelled</return>
        public bool ExecuteCycle(CancellationToken token, ExecuteCycleOptions options)
        {
            ExecuteCycleOptions          = options;
            ExecutionCompletionReason    = ExecutionCompletionReason.None;
            LastExecutionStartTact       = Cpu.Tacts;
            LastExecutionContentionValue = ContentionAccumulated;

            // --- We use these variables to calculate wait time at the end of the frame
            var cycleStartTime  = Clock.GetCounter();
            var cycleStartTact  = Cpu.Tacts;
            var cycleFrameCount = 0;

            // --- We use this variable to check whether to stop in Debug mode
            var executedInstructionCount = -1;

            // --- Loop #1: The main cycle that goes on until cancelled
            while (!token.IsCancellationRequested)
            {
                if (_frameCompleted)
                {
                    // --- This counter helps us to calculate where we are in the frame after
                    // --- each CPU operation cycle
                    LastFrameStartCpuTick = Cpu.Tacts - Overflow;

                    // --- Notify devices to start a new frame
                    OnNewFrame();
                    LastRenderedUlaTact = Overflow;
                    _frameCompleted     = false;
                }

                // --- Loop #2: The physical frame cycle that goes on while CPU and ULA
                // --- processes everything whithin a physical frame (0.019968 second)
                while (!_frameCompleted)
                {
                    // --- Check for leaving maskable interrupt mode
                    if (RunsInMaskableInterrupt)
                    {
                        if (Cpu.Registers.PC == 0x0052)
                        {
                            // --- We leave the maskable interrupt mode when the
                            // --- current instruction completes
                            RunsInMaskableInterrupt = false;
                        }
                    }

                    // --- Check debug mode when a CPU instruction has been entirelly executed
                    if (!Cpu.IsInOpExecution)
                    {
                        // --- Check for cancellation
                        if (token.IsCancellationRequested)
                        {
                            ExecutionCompletionReason = ExecutionCompletionReason.Cancelled;
                            return(false);
                        }

                        // --- The next instruction is about to be executed
                        executedInstructionCount++;

                        // --- Check for timeout
                        if (options.TimeoutTacts > 0 &&
                            cycleStartTact + options.TimeoutTacts < Cpu.Tacts)
                        {
                            ExecutionCompletionReason = ExecutionCompletionReason.Timeout;
                            return(false);
                        }

                        // --- Check for reaching the termination point
                        if (options.EmulationMode == EmulationMode.UntilExecutionPoint)
                        {
                            if (options.TerminationPoint < 0x4000)
                            {
                                // --- ROM & address must match
                                if (options.TerminationRom == MemoryDevice.GetSelectedRomIndex() &&
                                    options.TerminationPoint == Cpu.Registers.PC)
                                {
                                    // --- We reached the termination point within ROM
                                    ExecutionCompletionReason = ExecutionCompletionReason.TerminationPointReached;
                                    return(true);
                                }
                            }
                            else if (options.TerminationPoint == Cpu.Registers.PC)
                            {
                                // --- We reached the termination point within RAM
                                ExecutionCompletionReason = ExecutionCompletionReason.TerminationPointReached;
                                return(true);
                            }
                        }

                        // --- Check for entering maskable interrupt mode
                        if (Cpu.MaskableInterruptModeEntered)
                        {
                            RunsInMaskableInterrupt = true;
                        }

                        // --- Check for a debugging stop point
                        if (options.EmulationMode == EmulationMode.Debugger)
                        {
                            if (IsDebugStop(options, executedInstructionCount))
                            {
                                // --- At this point, the cycle should be stopped because of debugging reasons
                                // --- The screen should be refreshed
                                ScreenDevice.OnFrameCompleted();
                                ExecutionCompletionReason = ExecutionCompletionReason.BreakpointReached;
                                return(true);
                            }
                        }
                    }

                    // --- Check for interrupt signal generation
                    InterruptDevice.CheckForInterrupt(CurrentFrameTact);

                    // --- Run a single Z80 instruction
                    Cpu.ExecuteCpuCycle();
                    _lastBreakpoint = null;

                    // --- Run a rendering cycle according to the current CPU tact count
                    var lastTact = CurrentFrameTact;
                    ScreenDevice.RenderScreen(LastRenderedUlaTact + 1, lastTact);
                    LastRenderedUlaTact = lastTact;

                    // --- Exit if the emulation mode specifies so
                    if (options.EmulationMode == EmulationMode.UntilHalt &&
                        (Cpu.StateFlags & Z80StateFlags.Halted) != 0)
                    {
                        ExecutionCompletionReason = ExecutionCompletionReason.Halted;
                        return(true);
                    }

                    // --- Notify each CPU-bound device that the current operation has been completed
                    foreach (var device in _cpuBoundDevices)
                    {
                        device.OnCpuOperationCompleted();
                    }

                    // --- Decide whether this frame has been completed
                    _frameCompleted = !Cpu.IsInOpExecution && CurrentFrameTact >= _frameTacts;
                } // -- End Loop #2

                // --- A physical frame has just been completed. Take care about screen refresh
                cycleFrameCount++;
                FrameCount++;

                // --- Notify devices that the current frame completed
                OnFrameCompleted();

                // --- Exit if the emulation mode specifies so
                if (options.EmulationMode == EmulationMode.UntilFrameEnds)
                {
                    ExecutionCompletionReason = ExecutionCompletionReason.FrameCompleted;
                    return(true);
                }

                // --- Wait while the frame time ellapses
                if (!ExecuteCycleOptions.FastVmMode)
                {
                    var nextFrameCounter = cycleStartTime + cycleFrameCount * PhysicalFrameClockCount;
                    Clock.WaitUntil((long)nextFrameCounter, token);
                }

                // --- Start a new frame and carry on
                Overflow = CurrentFrameTact % _frameTacts;
            } // --- End Loop #1

            // --- The cycle has been interrupted by cancellation
            ExecutionCompletionReason = ExecutionCompletionReason.Cancelled;
            return(false);
        }
Esempio n. 3
0
        /// <summary>
        /// The main execution cycle of the Spectrum VM
        /// </summary>
        /// <param name="token">Cancellation token</param>
        /// <param name="options">Execution options</param>
        /// <param name="completeOnCpuFrame">The cycle should complete on CPU frame completion</param>
        /// <return>True, if the cycle completed; false, if it has been cancelled</return>
        public bool ExecuteCycle(CancellationToken token, ExecuteCycleOptions options, bool completeOnCpuFrame = false)
        {
            ExecuteCycleOptions       = options;
            ExecutionCompletionReason = ExecutionCompletionReason.None;
            LastExecutionStartTact    = Cpu.Tacts;

            // --- We use this variables to check whether to stop in Debug mode
            var executedInstructionCount = -1;
            var entryStepOutDepth        = Cpu.StackDebugSupport.StepOutStackDepth;

            // --- Check if we're just start running the next frame
            if (HasFrameCompleted)
            {
                // --- This counter helps us to calculate where we are in the frame after
                // --- each CPU operation cycle
                LastFrameStartCpuTick = Cpu.Tacts - Overflow;

                // --- Notify devices to start a new frame
                OnNewFrame();
                LastRenderedUlaTact = Overflow;
                HasFrameCompleted   = false;
            }

            // --- The physical frame cycle that goes on while CPU and ULA
            // --- processes everything within a physical frame (0.019968 second)
            while (!HasFrameCompleted)
            {
                // --- Check debug mode when a CPU instruction has been entirely executed
                if (!Cpu.IsInOpExecution)
                {
                    // --- The next instruction is about to be executed
                    executedInstructionCount++;

                    // --- Check for cancellation
                    if (token.IsCancellationRequested)
                    {
                        ExecutionCompletionReason = ExecutionCompletionReason.Cancelled;
                        return(false);
                    }

                    // --- Check for CPU frame completion
                    if (completeOnCpuFrame && Cpu.Tacts > LastExecutionStartTact + CPU_FRAME)
                    {
                        ExecutionCompletionReason = ExecutionCompletionReason.CpuFrameCompleted;
                        return(true);
                    }

                    // --- Check for several termination modes
                    switch (options.EmulationMode)
                    {
                    // --- Check for reaching the termination point
                    case EmulationMode.UntilExecutionPoint when options.TerminationPoint < 0x4000:
                    {
                        // --- ROM & address must match
                        if (options.TerminationRom == MemoryDevice.GetSelectedRomIndex() &&
                            options.TerminationPoint == Cpu.Registers.PC)
                        {
                            // --- We reached the termination point within ROM
                            ExecutionCompletionReason = ExecutionCompletionReason.TerminationPointReached;
                            return(true);
                        }

                        break;
                    }

                    // --- Check if we reached the termination point within RAM
                    case EmulationMode.UntilExecutionPoint
                        when options.TerminationPoint == Cpu.Registers.PC:

                        ExecutionCompletionReason = ExecutionCompletionReason.TerminationPointReached;
                        return(true);

                    // --- Check for a debugging stop point
                    case EmulationMode.Debugger
                        when IsDebugStop(options, executedInstructionCount, entryStepOutDepth) &&
                        DebugConditionSatisfied():

                        // --- At this point, the cycle should be stopped because of debugging reasons
                        // --- The screen should be refreshed
                        ExecutionCompletionReason = ExecutionCompletionReason.BreakpointReached;

                        return(true);
                    }
                }

                // --- Check for interrupt signal generation
                InterruptDevice.CheckForInterrupt(CurrentFrameTact);

                // --- Run a single Z80 instruction
                Cpu.ExecuteCpuCycle();
                _lastBreakpoint = null;

                // --- Run a rendering cycle according to the current CPU tact count
                var lastTact = CurrentFrameTact;
                ScreenDevice.RenderScreen(LastRenderedUlaTact + 1, lastTact);
                LastRenderedUlaTact = lastTact;

                // --- Exit if the CPU is HALTed and the emulation mode specifies so
                if (options.EmulationMode == EmulationMode.UntilHalt &&
                    (Cpu.StateFlags & Z80StateFlags.Halted) != 0)
                {
                    ExecutionCompletionReason = ExecutionCompletionReason.Halted;
                    return(true);
                }

                // --- Notify each CPU-bound device that the current operation has been completed
                foreach (var device in _cpuBoundDevices)
                {
                    device.OnCpuOperationCompleted();
                }

                // --- Decide whether this frame has been completed
                HasFrameCompleted = !Cpu.IsInOpExecution && CurrentFrameTact >= FrameTacts;
            }

            // --- A physical frame has just been completed. Take care about screen refresh
            FrameCount++;
            Overflow = CurrentFrameTact % FrameTacts;

            // --- Notify devices that the current frame completed
            OnFrameCompleted();

            // --- We exit the cycle when the render frame has completed
            ExecutionCompletionReason = ExecutionCompletionReason.RenderFrameCompleted;
            return(true);
        }
Esempio n. 4
0
        static void GetResolution(string[] args)
        {
            string deviceName          = null;
            DisplaySettingsQueryMode d = DisplaySettingsQueryMode.QueryCurrentResolution;

            OptionSet p = new OptionSet()
            {
                {
                    "d|device=", "the {NAME} of the screen device.",
                    v => deviceName = v
                },
                {
                    "o|option=", "the query {OPTION}. (all, current, registry)",
                    v => {
                        switch (v.Trim().ToLower())
                        {
                        case "current": d = DisplaySettingsQueryMode.QueryCurrentResolution; break;

                        case "all": d = DisplaySettingsQueryMode.QueryAllSupported; break;

                        case "registry": d = DisplaySettingsQueryMode.QueryRegistryResolution; break;
                        }
                    }
                }
            };
            List <string> extra;

            try
            {
                extra = p.Parse(args);
            }
            catch (OptionException e)
            {
                Console.WriteLine("ERROR: " + e.Message);
                return;
            }

            if (deviceName == null)
            {
                Console.WriteLine("ERROR: No device name has not been specified.");
                return;
            }

            try
            {
                foreach (DEVMODE ds in ScreenDevice.GetDeviceResolutions(ScreenDevice.GetDesktopDeviceByName(deviceName), d))
                {
                    Console.WriteLine(
                        "{0} x {1}, " +
                        "{2} bit, " +
                        "{3} hertz",
                        ds.dmPelsWidth,
                        ds.dmPelsHeight,
                        ds.dmBitsPerPel,
                        ds.dmDisplayFrequency
                        );
                }
            }
            catch (User32Exception e)
            {
                Console.WriteLine("ERROR: " + e.Message);
                return;
            }
        }
Esempio n. 5
0
        static void RestoreCurrentResolution(string[] args)
        {
            string    profileName = "Default";
            bool      silent      = false;
            OptionSet p           = new OptionSet()
            {
                {
                    "p|profile=", "the {PROFILENAME} of the screen resolution. (\"Default\" is the default profile.)",
                    v => profileName = RegistryHandler.sanitizeProfileName(v)
                },
                {
                    "q|quiet", "be quiet",
                    v => silent = v != null
                }
            };
            List <string> extra;

            try
            {
                extra = p.Parse(args);
            }
            catch (OptionException e)
            {
                if (!silent)
                {
                    Console.WriteLine("ERROR: " + e.Message);
                }
                return;
            }

            foreach (RegistryProfileDeviceSettings rpds in RegistryHandler.getProfile(profileName))
            {
                try
                {
                    if (!silent)
                    {
                        Console.WriteLine("Restoring Screen resolution: " + rpds);
                    }
                    DISPLAY_DEVICE d = ScreenDevice.GetDesktopDeviceByName(rpds.DeviceName);
                    if (rpds.Frequency > 0 && rpds.Bits > 0)
                    {
                        try
                        {
                            ScreenDevice.ChangeResolution(ref d, rpds.Width, rpds.Height, rpds.Bits, rpds.Frequency);
                        }
                        catch (User32Exception)
                        {
                            rpds.Frequency = 0;
                            if (!silent)
                            {
                                Console.WriteLine("Failed to change resolution, restoring without frequency: " + rpds);
                            }
                            ScreenDevice.ChangeResolution(ref d, rpds.Width, rpds.Height, rpds.Bits);
                        }
                    }
                    else if (rpds.Bits > 0)
                    {
                        ScreenDevice.ChangeResolution(ref d, rpds.Width, rpds.Height, rpds.Bits);
                    }
                    else
                    {
                        ScreenDevice.ChangeResolution(ref d, rpds.Width, rpds.Height);
                    }
                }
                catch (Exception e)
                {
                    if (!silent)
                    {
                        Console.WriteLine("ERROR: " + e.Message);
                    }
                }
            }
            if (!silent)
            {
                Console.WriteLine("Screen resolution has been restored from profile \"" + profileName + "\".");
            }
        }
Esempio n. 6
0
        static void SetResolution(string[] args)
        {
            string deviceName = null;
            int    width      = 0;
            int    height     = 0;
            short  bits       = 0;
            int    frequency  = 0;

            OptionSet p = new OptionSet()
            {
                {
                    "d|device=", "the {NAME} of the screen device.",
                    v => deviceName = v
                },
                {
                    "w|width=", "the display resolution {WIDTH} in pixels.",
                    (int v) => width = v
                },
                {
                    "h|height=", "the display resolution {HEIGHT} in pixels.",
                    (int v) => height = v
                },
                {
                    "b|bits=", "the display resolution {BITS}.",
                    (short v) => bits = v
                },
                {
                    "f|frequency=", "the display resolution {FREQUENCY} in hertz.",
                    (short v) => bits = v
                }
            };
            List <string> extra;

            try
            {
                extra = p.Parse(args);
            }
            catch (OptionException e)
            {
                Console.WriteLine("ERROR: " + e.Message);
                return;
            }

            if (deviceName == null)
            {
                Console.WriteLine("ERROR: No device name has not been specified.");
                return;
            }

            if (width <= 0)
            {
                Console.WriteLine("ERROR: Invalid width specified.");
                return;
            }

            if (height <= 0)
            {
                Console.WriteLine("ERROR: Invalid height specified.");
                return;
            }

            try
            {
                DISPLAY_DEVICE d = ScreenDevice.GetDesktopDeviceByName(deviceName);
                if (frequency > 0 && bits > 0)
                {
                    ScreenDevice.ChangeResolution(ref d, width, height, bits, frequency);
                }
                else if (bits > 0)
                {
                    ScreenDevice.ChangeResolution(ref d, width, height, bits);
                }
                else
                {
                    ScreenDevice.ChangeResolution(ref d, width, height);
                }
            }
            catch (User32Exception e)
            {
                Console.WriteLine("ERROR: " + e.Message);
                return;
            }
        }
Esempio n. 7
0
        /// <summary>
        /// The main execution cycle of the Spectrum VM
        /// </summary>
        /// <param name="token">Cancellation token</param>
        /// <param name="options">Execution options</param>
        /// <return>True, if the cycle completed; false, if it has been cancelled</return>
        public bool ExecuteCycle(CancellationToken token, ExecuteCycleOptions options)
        {
            ExecuteCycleOptions = options;

            // --- We use these variables to calculate wait time at the end of the frame
            var cycleStartTime  = Clock.GetCounter();
            var cycleFrameCount = 0;

            // --- We use this variable to check whether to stop in Debug mode
            var executedInstructionCount = -1;

            // --- Loop #1: The main cycle that goes on until cancelled
            while (!token.IsCancellationRequested)
            {
                if (_frameCompleted)
                {
                    // --- This counter helps us to calculate where we are in the frame after
                    // --- each CPU operation cycle
                    LastFrameStartCpuTick = Cpu.Tacts - Overflow;

                    // --- Notify devices to start a new frame
                    OnNewFrame();
                    LastRenderedUlaTact = Overflow;
                    _frameCompleted     = false;
                }

                // --- We use this timestamp for debug information calculation
                var currentFrameStartCounter = Clock.GetCounter();

                DebugInfoProvider.CpuTime             = 0;
                DebugInfoProvider.ScreenRenderingTime = 0;

                // --- Loop #2: The physical frame cycle that goes on while CPU and ULA
                // --- processes everything whithin a physical frame (0.019968 second)
                while (!_frameCompleted)
                {
                    // --- Check debug mode when a CPU instruction has been entirelly executed
                    if (!Cpu.IsInOpExecution)
                    {
                        // --- Check for cancellation
                        if (token.IsCancellationRequested)
                        {
                            return(false);
                        }

                        // --- The next instruction is about to be executed
                        executedInstructionCount++;

                        // --- Check for reaching the termination point
                        if (options.EmulationMode == EmulationMode.UntilExecutionPoint &&
                            options.TerminationPoint == Cpu.Registers.PC)
                        {
                            // --- We reached the termination point
                            return(true);
                        }

                        // --- Check for a debugging stop point
                        if (options.EmulationMode == EmulationMode.Debugger)
                        {
                            if (IsDebugStop(options.DebugStepMode, executedInstructionCount))
                            {
                                // --- At this point, the cycle should be stopped because of debugging reasons
                                // --- The screen should be refreshed
                                ScreenDevice.OnFrameCompleted();
                                return(true);
                            }
                        }
                    }

                    // --- Check for interrupt signal generation
                    InterruptDevice.CheckForInterrupt(CurrentFrameTact);

                    // --- Run a single Z80 instruction
                    var cpuStart = Clock.GetCounter();
                    Cpu.ExecuteCpuCycle();
                    DebugInfoProvider.CpuTime += Clock.GetCounter() - cpuStart;

                    // --- Run a rendering cycle according to the current CPU tact count
                    var lastTact    = CurrentFrameTact;
                    var renderStart = Clock.GetCounter();
                    ScreenDevice.RenderScreen(LastRenderedUlaTact + 1, lastTact);
                    DebugInfoProvider.ScreenRenderingTime += Clock.GetCounter() - renderStart;
                    LastRenderedUlaTact = lastTact;

                    // --- Exit if the emulation mode specifies so
                    if (options.EmulationMode == EmulationMode.UntilHalt &&
                        (Cpu.StateFlags & Z80StateFlags.Halted) != 0)
                    {
                        return(true);
                    }

                    // --- Notify each CPU-bound device that the current operation has been completed
                    foreach (var device in _cpuBoundDevices)
                    {
                        device.OnCpuOperationCompleted();
                    }

                    // --- Decide whether this frame has been completed
                    _frameCompleted = !Cpu.IsInOpExecution && CurrentFrameTact >= _frameTacts;
                } // -- End Loop #2

                // --- A physical frame has just been completed. Take care about screen refresh
                cycleFrameCount++;
                FrameCount++;

                // --- Calculate debug information
                DebugInfoProvider.FrameTime   = Clock.GetCounter() - currentFrameStartCounter;
                DebugInfoProvider.UtilityTime = DebugInfoProvider.FrameTime - DebugInfoProvider.CpuTime
                                                - DebugInfoProvider.ScreenRenderingTime;
                DebugInfoProvider.CpuTimeInMs             = DebugInfoProvider.CpuTime / (double)Clock.GetFrequency() * 1000;
                DebugInfoProvider.ScreenRenderingTimeInMs =
                    DebugInfoProvider.ScreenRenderingTime / (double)Clock.GetFrequency() * 1000;
                DebugInfoProvider.UtilityTimeInMs =
                    DebugInfoProvider.UtilityTime / (double)Clock.GetFrequency() * 1000;
                DebugInfoProvider.FrameTimeInMs = DebugInfoProvider.FrameTime / (double)Clock.GetFrequency() * 1000;

                // --- Notify devices that the current frame completed
                OnFrameCompleted();

                // --- Exit if the emulation mode specifies so
                if (options.EmulationMode == EmulationMode.UntilFrameEnds)
                {
                    return(true);
                }

                // --- Wait while the frame time ellapses
                var nextFrameCounter = cycleStartTime + cycleFrameCount * PhysicalFrameClockCount;
                Clock.WaitUntil((long)nextFrameCounter, token);

                // --- Start a new frame and carry on
                Overflow = CurrentFrameTact % _frameTacts;
            } // --- End Loop #1

            // --- The cycle has been inerrupted by cancellation
            return(false);
        }