예제 #1
0
        /// <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();
        }
예제 #2
0
            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();
            }
예제 #3
0
        /// <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();
        }
예제 #4
0
        /// <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();
        }