/// <summary> /// Initialization of the package; this method is called right after the package is sited, so this is the place /// where you can put all the initialization code that rely on services provided by VisualStudio. /// </summary> protected override void OnInitialize() { // --- Prepare project system extension files CheckCpsFiles(); // --- We are going to use this singleton instance Default = this; RegisterEditorFactory(new RomEditorFactory()); RegisterEditorFactory(new TzxEditorFactory()); RegisterEditorFactory(new TapEditorFactory()); RegisterEditorFactory(new DisAnnEditorFactory()); RegisterEditorFactory(new SpConfEditorFactory()); // --- Prepare for package shutdown _packageDteEvents = ApplicationObject.Events.DTEEvents; _packageDteEvents.OnBeginShutdown += () => { PackageClosing?.Invoke(this, EventArgs.Empty); }; _solutionEvents = ApplicationObject.Events.SolutionEvents; _solutionEvents.Opened += OnSolutionOpened; _solutionEvents.AfterClosing += OnSolutionClosed; // --- Create other helper objects DebugInfoProvider = new VsIntegratedSpectrumDebugInfoProvider(); CodeManager = new Z80CodeManager(); TestManager = new Z80TestManager(); StateFileManager = new VmStateFileManager(); ErrorList = new ErrorListWindow(); TaskList = new TaskListWindow(); }
protected override async Task ExecuteAsync() { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); var folder = HostPackage.Options.VmStateSaveFileFolder; var filename = VsxDialogs.FileOpen(VMSTATE_FILTER, folder); if (filename == null) { return; } // --- Stop the virtual machine, provided it runs var options = HostPackage.Options; var pane = OutputWindow.GetPane <SpectrumVmOutputPane>(); var vm = HostPackage.EmulatorViewModel; var machineState = vm.MachineState; if ((machineState == VmState.Running || machineState == VmState.Paused)) { if (options.ConfirmMachineRestart) { var answer = VsxDialogs.Show("Are you sure, you want to restart " + "the ZX Spectrum virtual machine?", "The ZX Spectum virtual machine is running", MessageBoxButton.YesNo, VsxMessageBoxIcon.Question, 1); if (answer == VsxDialogResult.No) { return; } } // --- Stop the machine and allow 50ms to stop. await HostPackage.EmulatorViewModel.Machine.Stop(); await Task.Delay(50); if (vm.MachineState != VmState.Stopped) { const string MESSAGE = "The ZX Spectrum virtual machine did not stop."; await pane.WriteLineAsync(MESSAGE); VsxDialogs.Show(MESSAGE, "Unexpected issue", MessageBoxButton.OK, VsxMessageBoxIcon.Error); return; } } // --- Load the file and keep it paused VmStateFileManager.LoadVmStateFile(filename); HostPackage.EmulatorViewModel.ForceScreenRefresh(); HostPackage.EmulatorViewModel.ForcePauseVmAfterStateRestore(); }
/// <summary> /// Initialization of the package; this method is called right after the package is sited, so this is the place /// where you can put all the initialization code that rely on services provided by VisualStudio. /// </summary> protected override async Task OnInitializeAsync() { // --- We are going to use this singleton instance Default = this; // --- Prepare project system extension files CheckCpsFiles(); await JoinableTaskFactory.SwitchToMainThreadAsync(); RegisterEditorFactory(new RomEditorFactory()); RegisterEditorFactory(new TzxEditorFactory()); RegisterEditorFactory(new TapEditorFactory()); RegisterEditorFactory(new DisAnnEditorFactory()); RegisterEditorFactory(new SpConfEditorFactory()); RegisterEditorFactory(new VfddEditorFactory()); // --- Register providers SpectrumMachine.Reset(); SpectrumMachine.RegisterProvider <IRomProvider>(() => new PackageRomProvider()); SpectrumMachine.RegisterProvider <IKeyboardProvider>(() => new KeyboardProvider()); SpectrumMachine.RegisterProvider <IKempstonProvider>(() => new KempstonProvider()); SpectrumMachine.RegisterProvider <IBeeperProvider>(() => new AudioWaveProvider()); SpectrumMachine.RegisterProvider <ITapeProvider>(() => new VsIntegratedTapeProvider()); SpectrumMachine.RegisterProvider <ISoundProvider>(() => new AudioWaveProvider(AudioProviderType.Psg)); DebugInfoProvider = new VsIntegratedSpectrumDebugInfoProvider(); SpectrumMachine.RegisterProvider <ISpectrumDebugInfoProvider>(() => DebugInfoProvider); // --- Prepare for package shutdown _packageDteEvents = ApplicationObject.Events.DTEEvents; _packageDteEvents.OnBeginShutdown += () => { PackageClosing?.Invoke(this, EventArgs.Empty); }; _solutionEvents = ApplicationObject.Events.SolutionEvents; _solutionEvents.Opened += OnSolutionOpened; _solutionEvents.AfterClosing += OnSolutionClosed; // --- Create other helper objects CodeManager = new Z80CodeManager(); TestManager = new Z80TestManager(); StateFileManager = new VmStateFileManager(); ErrorList = new ErrorListWindow(); TaskList = new TaskListWindow(); }
/// <summary> /// Compiles the Z80 code file /// </summary> protected override async Task ExecuteAsync() { // --- Prepare the appropriate file to compile/run CodeInjected = false; // --- Step #1: Compile the code var success = await Task.Run(() => CompileCode()); if (!success) { return; } // --- Step #2: Check machine compatibility var modelName = SpectNetPackage.Default.Solution.ActiveProject?.ModelName; SpectrumModelType modelType; if (Output.ModelType == null) { switch (modelName) { case SpectrumModels.ZX_SPECTRUM_48: modelType = SpectrumModelType.Spectrum48; break; case SpectrumModels.ZX_SPECTRUM_128: modelType = SpectrumModelType.Spectrum128; break; case SpectrumModels.ZX_SPECTRUM_P3_E: modelType = SpectrumModelType.SpectrumP3; break; case SpectrumModels.ZX_SPECTRUM_NEXT: modelType = SpectrumModelType.Next; break; default: modelType = SpectrumModelType.Spectrum48; break; } } else { modelType = Output.ModelType.Value; } // --- We may display dialogs, so we go back to the main thread await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); if (!SpectrumModels.IsModelCompatibleWith(modelName, modelType)) { VsxDialogs.Show("The model type defined in the code is not compatible with the " + "Spectum virtual machine of this project.", "Cannot run code."); return; } // --- Step #3: Check for zero code length if (Output.Segments.Sum(s => s.EmittedCode.Count) == 0) { VsxDialogs.Show("The lenght of the compiled code is 0, " + "so there is no code to inject into the virtual machine and run.", "No code to run."); return; } // --- Step #4: Check non-zero displacements var options = HostPackage.Options; if (Output.Segments.Any(s => (s.Displacement ?? 0) != 0) && options.ConfirmNonZeroDisplacement) { var answer = VsxDialogs.Show("The compiled code contains non-zero displacement" + "value, so the displaced code may fail. Are you sure you want to run the code?", "Non-zero displacement found", MessageBoxButton.YesNo, VsxMessageBoxIcon.Question, 1); if (answer == VsxDialogResult.No) { return; } } var vm = HostPackage.EmulatorViewModel; var pane = OutputWindow.GetPane <SpectrumVmOutputPane>(); HostPackage.ShowToolWindow <SpectrumEmulatorToolWindow>(); // --- Step #5: Prepare the machine to be in the appropriate mode if (IsInInjectMode) { if (vm.MachineState == VmState.Running || vm.MachineState != VmState.Paused && vm.MachineState != VmState.Stopped && vm.MachineState != VmState.None) { VsxDialogs.Show("To inject the code into the virtual machine, please pause it first.", "The virtual machine is running"); return; } } else { var stopped = await SpectrumVmManager.StopSpectrumVmAsync(options.ConfirmMachineRestart); if (!stopped) { return; } } // --- Step #6: Start the virtual machine and run it to the injection point if (vm.MachineState == VmState.Stopped || vm.MachineState == VmState.None) { await pane.WriteLineAsync("Starting the virtual machine in code injection mode."); // --- Use specific startup for each model. var started = true; try { switch (modelName) { case SpectrumModels.ZX_SPECTRUM_48: await VmStateFileManager.SetSpectrum48StartupState(); break; case SpectrumModels.ZX_SPECTRUM_128: if (modelType == SpectrumModelType.Spectrum48) { await VmStateFileManager.SetSpectrum128In48StartupState(); } else { await VmStateFileManager.SetSpectrum128In128StartupState(); } break; case SpectrumModels.ZX_SPECTRUM_P3_E: if (modelType == SpectrumModelType.Spectrum48) { await VmStateFileManager.SetSpectrumP3In48StartupState(); } else { await VmStateFileManager.SetSpectrumP3InP3StartupState(); } break; case SpectrumModels.ZX_SPECTRUM_NEXT: // --- Implement later return; default: // --- Implement later return; } } catch (Exception) { started = false; } if (!started) { return; } } // --- Step #7: Inject the code into the memory, and force // --- new disassembly await pane.WriteLineAsync("Injecting code into the Spectrum virtual machine."); HostPackage.CodeManager.InjectCodeIntoVm(Output); CodeInjected = true; // --- Step #8: Jump to execute the code var continuationPoint = GetContinuationAddress(); if (continuationPoint.HasValue) { vm.Machine.SpectrumVm.Cpu.Registers.PC = continuationPoint.Value; await pane.WriteLineAsync($"Resuming code execution at address {vm.Machine.SpectrumVm.Cpu.Registers.PC:X4}."); } vm.MemViewPoint = (ushort)MemoryStartAddress; vm.DisAssViewPoint = (ushort)DisassemblyStartAddress; vm.StackDebugSupport.ClearStepOutStack(); GetAffectedItem(out var hierarchy, out var itemId); var ext = string.Empty; if (hierarchy is IVsProject project) { project.GetMkDocument(itemId, out var itemFullPath); ext = Path.GetExtension(itemFullPath) ?? string.Empty; } if (ext.ToLower() == ".zxbas") { // --- Push the MAIN_EXECUTION loop address to the stack var memDevice = vm.Machine.SpectrumVm.MemoryDevice; var spValue = vm.Machine.SpectrumVm.Cpu.Registers.SP; var mainExec = VmStateFileManager.SP48_MAIN_EXEC_ADDR; memDevice.Write((ushort)(spValue - 1), (byte)(mainExec >> 8)); memDevice.Write((ushort)(spValue - 2), (byte)mainExec); vm.Machine.SpectrumVm.Cpu.Registers.SP -= 2; } ResumeVm(); }