Example #1
0
        /// <summary>
        /// Compiles the Z80 code file
        /// </summary>
        protected override async Task ExecuteAsync()
        {
            // --- Prepare the appropriate file to compile/run
            GetCodeItem(out var hierarchy, out var itemId);

            // --- Step #1: Compile the code
            if (!CompileCode(hierarchy, itemId))
            {
                return;
            }

            // --- Step #2: Check machine compatibility
            var modelName = SpectNetPackage.Default.CodeDiscoverySolution?.CurrentProject?.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;
            }
            if (!SpectNetPackage.IsCurrentModelCompatibleWith(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 = Package.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;
                }
            }

            // --- Step #5: Stop the virtual machine if required
            await SwitchToMainThreadAsync();

            Package.ShowToolWindow <SpectrumEmulatorToolWindow>();
            var pane    = OutputWindow.GetPane <SpectrumVmOutputPane>();
            var vm      = Package.MachineViewModel;
            var stopped = await Package.CodeManager.StopSpectrumVm(options.ConfirmMachineRestart);

            if (!stopped)
            {
                return;
            }

            // --- Step #6: Start the virtual machine so that later we can load the program
            pane.WriteLine("Starting the virtual machine in code injection mode.");

            // --- Use specific startup for each model.
            bool started = true;

            try
            {
                switch (modelName)
                {
                case SpectrumModels.ZX_SPECTRUM_48:
                    await Package.StateFileManager.SetSpectrum48StartupState();

                    break;

                case SpectrumModels.ZX_SPECTRUM_128:
                    if (modelType == SpectrumModelType.Spectrum48)
                    {
                        await Package.StateFileManager.SetSpectrum128In48StartupState();
                    }
                    else
                    {
                        await Package.StateFileManager.SetSpectrum128In128StartupState();
                    }
                    break;

                case SpectrumModels.ZX_SPECTRUM_P3_E:
                    if (modelType == SpectrumModelType.Spectrum48)
                    {
                        await Package.StateFileManager.SetSpectrumP3In48StartupState();
                    }
                    else
                    {
                        await Package.StateFileManager.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
            pane.WriteLine("Injecting code into the Spectrum virtual machine.");
            Package.CodeManager.InjectCodeIntoVm(Output);

            // --- Step #8: Jump to execute the code
            var continuationPoint = GetContinuationAddress();

            if (continuationPoint.HasValue)
            {
                vm.SpectrumVm.Cpu.Registers.PC = continuationPoint.Value;
                pane.WriteLine($"Resuming code execution at address {vm.SpectrumVm.Cpu.Registers.PC:X4}.");
            }
            ResumeVm();
        }
        /// <summary>
        /// Compiles the Z80 code file
        /// </summary>
        protected override async Task ExecuteAsync()
        {
            // --- Prepare the appropriate file to compile/run
            GetCodeItem(out var hierarchy, out var itemId);

            // --- Step #1: Compile the code
            if (!CompileCode(hierarchy, itemId))
            {
                return;
            }

            // --- Step #2: Check machine compatibility
            var modelName = SpectNetPackage.Default.CodeDiscoverySolution?.CurrentProject?.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:
                    modelType = SpectrumModelType.SpectrumP3;
                    break;

                case SpectrumModels.ZX_SPECTRUM_NEXT:
                    modelType = SpectrumModelType.Next;
                    break;

                default:
                    modelType = SpectrumModelType.Spectrum48;
                    break;
                }
            }
            else
            {
                modelType = Output.ModelType.Value;
            }
            if (!SpectNetPackage.IsCurrentModelCompatibleWith(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 = Package.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;
                }
            }

            // --- Step #5: Stop the virtual machine if required
            await SwitchToMainThreadAsync();

            Package.ShowToolWindow <SpectrumEmulatorToolWindow>();
            var pane         = OutputWindow.GetPane <SpectrumVmOutputPane>();
            var vm           = Package.MachineViewModel;
            var machineState = vm.VmState;

            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.
                Package.MachineViewModel.StopVm();
                await Task.Delay(50);

                if (vm.VmState != VmState.Stopped)
                {
                    const string MESSAGE = "The ZX Spectrum virtual machine did not stop.";
                    pane.WriteLine(MESSAGE);
                    VsxDialogs.Show(MESSAGE, "Unexpected issue",
                                    MessageBoxButton.OK, VsxMessageBoxIcon.Error);
                    return;
                }
            }

            // --- Step #6: Start the virtual machine so that later we can load the program
            pane.WriteLine("Starting the virtual machine in code injection mode.");

            // --- Use specific startup for each model.
            switch (modelName)
            {
            case SpectrumModels.ZX_SPECTRUM_48:
                // --- Run in ZX Spectrum 48K mode
                vm.RestartVmAndRunToTerminationPoint(0, SP48_MAIN_EXEC_ADDR);
                if (!await WaitStart())
                {
                    return;
                }
                break;

            case SpectrumModels.ZX_SPECTRUM_128:
                // --- Wait while the main menu appears
                vm.RestartVmAndRunToTerminationPoint(0, SP128_MAIN_WAITING_LOOP);
                if (!await WaitStart())
                {
                    return;
                }

                if (modelType == SpectrumModelType.Spectrum48)
                {
                    vm.RunVmToTerminationPoint(1, SP48_MAIN_EXEC_ADDR);

                    // --- Move to Spectrum 48 mode
                    QueueKeyStroke(SpectrumKeyCode.N6, SpectrumKeyCode.CShift);
                    await Task.Delay(WAIT_FOR_MENU_KEY);

                    QueueKeyStroke(SpectrumKeyCode.N6, SpectrumKeyCode.CShift);
                    await Task.Delay(WAIT_FOR_MENU_KEY);

                    QueueKeyStroke(SpectrumKeyCode.N6, SpectrumKeyCode.CShift);
                    await Task.Delay(WAIT_FOR_MENU_KEY);

                    QueueKeyStroke(SpectrumKeyCode.Enter);
                    if (!await WaitStart())
                    {
                        return;
                    }
                }
                else
                {
                    vm.RunVmToTerminationPoint(0, SP128_RETURN_TO_EDITOR);
                    // --- Move to Spectrum 128 mode
                    QueueKeyStroke(SpectrumKeyCode.N6, SpectrumKeyCode.CShift);
                    await Task.Delay(WAIT_FOR_MENU_KEY);

                    QueueKeyStroke(SpectrumKeyCode.Enter);
                    if (!await WaitStart())
                    {
                        return;
                    }
                }
                break;

            case SpectrumModels.ZX_SPECTRUM_P3:
                // --- Implement later
                return;

            case SpectrumModels.ZX_SPECTRUM_NEXT:
                // --- Implement later
                return;

            default:
                // --- Implement later
                return;
            }

            // --- Step #7: Inject the code into the memory, and force
            // --- new disassembly
            pane.WriteLine("Injecting code into the Spectrum virtual machine.");
            Package.CodeManager.InjectCodeIntoVm(Output);

            // --- Step #8: Jump to execute the code
            var continuationPoint = GetContinuationAddress();

            if (continuationPoint.HasValue)
            {
                vm.SpectrumVm.Cpu.Registers.PC = continuationPoint.Value;
                pane.WriteLine($"Resuming code execution at address {vm.SpectrumVm.Cpu.Registers.PC:X4}.");
            }
            ResumeVm();
        }