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; } }
/// <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); }
/// <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); }
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; } }
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 + "\"."); } }
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; } }
/// <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); }