예제 #1
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();
        }
예제 #2
0
        /// <summary>
        /// Checks if the current Spectrum model of the project in compatible with the
        /// specified model type
        /// </summary>
        /// <param name="type">Model type</param>
        /// <returns>
        /// True, if the project's Spectrum model is compatible with the specified one;
        /// otherwise, false
        /// </returns>
        public static bool IsCurrentModelCompatibleWith(SpectrumModelType type)
        {
            var modelName = Default.CodeDiscoverySolution?.CurrentProject?.ModelName;

            return(SpectrumModels.IsModelCompatibleWith(modelName, type));
        }