/// <summary>
        /// Override this method to define the action to execute on the main
        /// thread of Visual Studio -- finally
        /// </summary>
        protected override async Task FinallyOnMainThreadAsync()
        {
            await base.FinallyOnMainThreadAsync();

            if (Success && !IsCancelled && Package.Options.ConfirmCodeExport && Output.ErrorCount == 0)
            {
                VsxDialogs.Show("The code has been exported.");
            }
        }
Exemplo n.º 2
0
 /// <summary>
 /// Override this method to define the action to execute on the main
 /// thread of Visual Studio -- finally
 /// </summary>
 protected override Task FinallyOnMainThread()
 {
     Package.TestManager.CompilatioInProgress = false;
     if (Package.Options.ConfirmTestCompile && Output.ErrorCount == 0)
     {
         VsxDialogs.Show("The unit test code has been successfully compiled.");
     }
     return(Task.FromResult(0));
 }
Exemplo n.º 3
0
        /// <summary>
        /// Override this method to define the action to execute on the main
        /// thread of Visual Studio -- finally
        /// </summary>
        protected override async Task FinallyOnMainThreadAsync()
        {
            await base.FinallyOnMainThreadAsync();

            GC.Collect(2, GCCollectionMode.Forced);
            if (HostPackage.Options.ConfirmCodeCompile && Output.ErrorCount == 0)
            {
                VsxDialogs.Show("The code has been successfully compiled.");
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Override this method to define the action to execute on the main
        /// thread of Visual Studio -- finally
        /// </summary>
        protected override void FinallyOnMainThread()
        {
            Package.CodeManager.CompilatioInProgress = false;
            var options = Package.Options;

            if (options.ConfirmCodeStart)
            {
                VsxDialogs.Show("The code has been started.");
            }
        }
Exemplo n.º 5
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();
            }
Exemplo n.º 6
0
        /// <summary>
        /// Creates the compilation list file as set up in the package options
        /// </summary>
        /// <param name="hierarchy">Hierarchy object</param>
        /// <param name="itemId">Identifier of item to compile</param>
        private void CreateCompilationListFile(IVsHierarchy hierarchy, uint itemId)
        {
            var options = HostPackage.Options;

            if (!options.GenerateCompilationList ||
                options.GenerateForCompileOnly && !(this is CompileCodeCommand))
            {
                return;
            }

            // --- Create list file name
            if (!(hierarchy is IVsProject project))
            {
                return;
            }
            project.GetMkDocument(itemId, out var itemFullPath);
            var codeFile = Path.GetFileNameWithoutExtension(itemFullPath);
            var suffix   = string.IsNullOrWhiteSpace(options.CompilationFileSuffix)
                ? string.Empty
                : DateTime.Now.ToString(options.CompilationFileSuffix);
            var listFilename = $"{codeFile}{suffix}{options.CompilationFileExtension ?? ".list"}";
            var listFolder   = string.IsNullOrWhiteSpace(options.CompilationFileFolder)
                ? LIST_TMP_FOLDER
                : options.CompilationFileFolder;

            // -- Make sure list folder exists
            if (!Directory.Exists(listFolder))
            {
                Directory.CreateDirectory(listFolder);
            }

            // --- Save the list file
            var listContents     = CreateListFileContents();
            var fullListFileName = Path.Combine(listFolder, listFilename);

            try
            {
                File.WriteAllText(fullListFileName, listContents);
            }
            catch
            {
                VsxDialogs.Show($"Error when writing list file {fullListFileName}. "
                                + "The file name may contain invalid characters, or you miss file permissions.",
                                "Error when creating list file.", MessageBoxButton.OK, VsxMessageBoxIcon.Error);
                return;
            }

            if (options.AddCompilationToProject)
            {
                SpectrumProject.AddFileToProject(HostPackage.Options.CompilationProjectFolder,
                                                 fullListFileName, INVALID_FOLDER_MESSAGE, FILE_EXISTS_MESSAGE, false);
            }
        }
Exemplo n.º 7
0
        /// <summary>
        /// Save data blocks
        /// </summary>
        /// <param name="vm">Export parameters</param>
        /// <param name="blocksToSave">Collection of data blocks to save</param>
        private static void SaveDataBlocks(ExportZ80ProgramViewModel vm, IEnumerable <byte[]> blocksToSave)
        {
            try
            {
                // --- Create directory
                var dirName = Path.GetDirectoryName(vm.Filename);
                if (dirName != null && !Directory.Exists(dirName))
                {
                    Directory.CreateDirectory(dirName);
                }

                // --- Save data blocks
                if (vm.Format == ExportFormat.Tzx)
                {
                    using (var writer = new BinaryWriter(File.Create(vm.Filename)))
                    {
                        var header = new TzxHeader();
                        header.WriteTo(writer);

                        foreach (var block in blocksToSave)
                        {
                            var tzxBlock = new TzxStandardSpeedDataBlock
                            {
                                Data       = block,
                                DataLength = (ushort)block.Length
                            };
                            tzxBlock.WriteTo(writer);
                        }
                    }
                }
                else
                {
                    using (var writer = new BinaryWriter(File.Create(vm.Filename)))
                    {
                        foreach (var block in blocksToSave)
                        {
                            writer.Write((ushort)block.Length);
                            writer.Write(block);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                VsxDialogs.Show($"An error has been raised while exporting a program: {ex.Message}",
                                "Errorr when exporting file");
            }
        }
Exemplo n.º 8
0
        /// <summary>
        /// Tests if the compiler is available.
        /// </summary>
        /// <returns>True, if the compiler is installed, and so available.</returns>
        public async Task <bool> IsAvailable()
        {
            var runner = new ZxbRunner(SpectNetPackage.Default.Options.ZxbPath, 10000);

            try
            {
                await runner.RunAsync(new ZxbOptions());
            }
            catch (Exception ex)
            {
                VsxDialogs.Show(string.Format(ZXB_NOT_FOUND_MESSAGE, ex.Message),
                                "Error when running ZXB", MessageBoxButton.OK, VsxMessageBoxIcon.Exclamation);
                return(false);
            }
            return(true);
        }
Exemplo n.º 9
0
 /// <summary>
 /// Override this method to define the async command body te execute on the
 /// background thread
 /// </summary>
 protected override async Task ExecuteAsync()
 {
     if (!(Package.MachineViewModel.SpectrumVm.FloppyDevice is FloppyDevice floppyDevice))
     {
         return;
     }
     try
     {
         await InsertFloppyAsync(floppyDevice, ItemPath);
     }
     catch (Exception)
     {
         VsxDialogs.Show("Cannot mount this virtual floppy disk file. It might be corrupt, or is inaccessible.",
                         "Error inserting floppy", MessageBoxButton.OK, VsxMessageBoxIcon.Exclamation);
     }
 }
Exemplo n.º 10
0
        /// <summary>
        /// Override this method to define the action to execute on the main
        /// thread of Visual Studio -- finally
        /// </summary>
        protected override async Task FinallyOnMainThreadAsync()
        {
            await base.FinallyOnMainThreadAsync();

            if (IsInInjectMode)
            {
                if (HostPackage.Options.ConfirmInjectCode && CodeInjected)
                {
                    VsxDialogs.Show("The code has been injected.");
                }
            }
            else
            {
                if (HostPackage.Options.ConfirmCodeStart && Output.ErrorCount > 0)
                {
                    VsxDialogs.Show("The code has been started.");
                }
            }
        }
Exemplo n.º 11
0
 /// <summary>
 /// Override this method to define the action to execute on the main
 /// thread of Visual Studio -- finally
 /// </summary>
 protected override Task FinallyOnMainThread()
 {
     base.FinallyOnMainThread();
     if (IsInInjectMode)
     {
         if (Package.Options.ConfirmInjectCode && CodeInjected)
         {
             VsxDialogs.Show("The code has been injected.");
         }
     }
     else
     {
         if (Package.Options.ConfirmCodeStart && Output.ErrorCount > 0)
         {
             VsxDialogs.Show("The code has been started.");
         }
     }
     return(Task.FromResult(0));
 }
Exemplo n.º 12
0
        /// <summary>
        /// Sets the active project to the current project file
        /// </summary>
        protected async override Task ExecuteAsync()
        {
            // --- Collect export parameters from the UI
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

            if (DisplayCreateVfddDialog(out var vm))
            {
                return;
            }

            // --- Create a temporary file
            string fullPath;

            try
            {
                var filename = Path.ChangeExtension(Path.GetFileName(vm.Filename), ".vfdd");
                var userPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
                fullPath = Path.Combine(Path.Combine(userPath, "SpectNetFloppies"), filename);
                VirtualFloppyFile.CreateSpectrumFloppyFile(fullPath, vm.Format);
            }
            catch (Exception ex)
            {
                VsxDialogs.Show($"Error: {ex.Message}", "Error creating virtual floppy disk file");
                return;
            }

            // --- Add the temp file to the project
            SpectrumProject.AddFileToProject(SpectNetPackage.Default.Options.VfddFolder, fullPath,
                                             INVALID_FOLDER_MESSAGE, FILE_EXISTS_MESSAGE);

            // --- Remove the temp file
            try
            {
                File.Delete(fullPath);
            }
            catch (Exception)
            {
                // --- This exception is intentionally ignored
            }
        }
Exemplo n.º 13
0
        /// <summary>
        /// Waits while the Spectrum virtual machine starts and reaches its termination point
        /// </summary>
        /// <returns>True, if started within timeout; otherwise, false</returns>
        private async Task <bool> WaitStart()
        {
            const int TIME_OUT_IN_SECONDS = 5;
            var       counter             = 0;

            while (Package.MachineViewModel.VmState != VmState.Paused && counter < TIME_OUT_IN_SECONDS * 10)
            {
                await Task.Delay(100);

                counter++;
            }
            if (Package.MachineViewModel.VmState != VmState.Paused)
            {
                var pane    = OutputWindow.GetPane <SpectrumVmOutputPane>();
                var message = $"The ZX Spectrum virtual machine did not start within {TIME_OUT_IN_SECONDS} seconds.";
                pane.WriteLine(message);
                VsxDialogs.Show(message, "Unexpected issue", MessageBoxButton.OK, VsxMessageBoxIcon.Error);
                Package.MachineViewModel.StopVm();
                return(false);
            }
            return(true);
        }
Exemplo n.º 14
0
        /// <summary>
        /// Exports the memory of the specified virtual machine
        /// </summary>
        /// <param name="spectrumVm"></param>
        public void ExportMemory(ISpectrumVm spectrumVm)
        {
            // --- Parse addresses
            if (!ushort.TryParse(ExportParams.StartAddress, out var startAddress))
            {
                return;
            }
            if (!ushort.TryParse(ExportParams.EndAddress, out var endAddress))
            {
                return;
            }
            try
            {
                var contents = spectrumVm.MemoryDevice.CloneMemory()
                               .Skip(startAddress)
                               .Take(endAddress - startAddress + 1)
                               .ToArray();
                var dirName = Path.GetDirectoryName(ExportParams.Filename);
                if (!string.IsNullOrEmpty(dirName) && !Directory.Exists(dirName))
                {
                    Directory.CreateDirectory(dirName);
                }
                File.WriteAllBytes(ExportParams.Filename, contents);
            }
            catch (Exception ex)
            {
                VsxDialogs.Show($"Error while exporting to file {ExportParams.Filename}: {ex.Message}",
                                "Export disassembly error.", MessageBoxButton.OK, VsxMessageBoxIcon.Error);
            }

            if (!ExportParams.AddToProject)
            {
                return;
            }

            SpectrumProject.AddFileToProject(SpectNetPackage.Default.Options.MemoryExportFolder,
                                             ExportParams.Filename,
                                             INVALID_FOLDER_MESSAGE, FILE_EXISTS_MESSAGE);
        }
Exemplo n.º 15
0
        /// <summary>
        /// Loads the specified .vmstate file
        /// </summary>
        /// <param name="stateFile">Full name of the .vmstate file</param>
        public void LoadVmStateFile(string stateFile)
        {
            var state = File.ReadAllText(stateFile);

            try
            {
                Package.MachineViewModel.SpectrumVm.SetVmState(state, Package.CodeDiscoverySolution.CurrentProject.ModelName);
                Package.MachineViewModel.SpectrumVm.BeeperDevice.Reset();
                Package.MachineViewModel.SpectrumVm.BeeperProvider.Reset();

                var pane = OutputWindow.GetPane <SpectrumVmOutputPane>();
                pane.WriteLine($"Forcing Paused state from {Package.MachineViewModel.VmState}");
                Package.MachineViewModel.ForcePauseVmAfterStateRestore();
            }
            catch (InvalidVmStateException e)
            {
                VsxDialogs.Show(e.OriginalMessage, "Error loading virtual machine state");
            }
            catch (Exception e)
            {
                VsxDialogs.Show($"Unexpected error: {e.Message}", "Error loading virtual machine state");
            }
        }
Exemplo n.º 16
0
        /// <summary>
        /// Stops the Spectrum VM, displays confirmation, if required
        /// </summary>
        /// <returns>Tru, if start confirmed; otherwise, false</returns>
        public async Task <bool> StopSpectrumVm(bool needConfirm)
        {
            var vm           = Package.MachineViewModel;
            var machineState = vm.VmState;

            if (machineState == VmState.Running || machineState == VmState.Paused)
            {
                if (needConfirm)
                {
                    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(false);
                    }
                }

                // --- Stop the machine and allow 50ms to stop.
                Package.MachineViewModel.StopVm();
                await Package.MachineViewModel.MachineController.CompletionTask;

                if (vm.VmState == VmState.Stopped)
                {
                    return(true);
                }

                const string MESSAGE = "The ZX Spectrum virtual machine did not stop.";
                var          pane    = OutputWindow.GetPane <SpectrumVmOutputPane>();
                pane.WriteLine(MESSAGE);
                VsxDialogs.Show(MESSAGE, "Unexpected issue",
                                MessageBoxButton.OK, VsxMessageBoxIcon.Error);
                return(false);
            }
            return(true);
        }
        /// <summary>
        /// Updates the RAM annotation file according to changes
        /// </summary>
        private void OnAnnotationFileChanged(object sender, EventArgs eventArgs)
        {
            var project = SpectNetPackage.Default.ActiveProject;
            var annFile = project?.DefaultAnnotationItem
                          ?? project?.AnnotationProjectItems?.FirstOrDefault();

            RamBankAnnotations.Clear();
            if (annFile == null)
            {
                return;
            }

            RamBankAnnotationFile = annFile.Filename;
            try
            {
                var disAnn = File.ReadAllText(annFile.Filename);
                DisassemblyAnnotation.DeserializeBankAnnotations(disAnn, out var annotations);
                RamBankAnnotations = annotations;
            }
            catch (Exception ex)
            {
                VsxDialogs.Show(ex.Message, "Error loading annotation file", MessageBoxButton.OK, VsxMessageBoxIcon.Error);
            }
        }
Exemplo n.º 18
0
        /// <summary>
        /// Adds the exported file to the project structure
        /// </summary>
        /// <param name="projectFolder">Project folder to add the file</param>
        /// <param name="filename">Filename to add to the project</param>
        /// <param name="invFolderMessage">Message to display when folder name is invalid</param>
        /// <param name="fileExistsMessage">Message to display when file already exists</param>
        /// <param name="confirmOverwrite">When a file exists, the user must confirm overwriting it</param>
        public static void AddFileToProject(string projectFolder, string filename, string invFolderMessage = null,
                                            string fileExistsMessage = null, bool confirmOverwrite = true)
        {
            var folderSegments = projectFolder.Split(new[] { '/', '\\' },
                                                     StringSplitOptions.RemoveEmptyEntries);

            foreach (var segment in folderSegments)
            {
                bool valid;
                try
                {
                    valid = !Path.IsPathRooted(segment);
                }
                catch
                {
                    valid = false;
                }
                if (!valid)
                {
                    VsxDialogs.Show(invFolderMessage ?? DEFAULT_INV_FOLDER_MESSAGE,
                                    "Invalid characters in path");
                    return;
                }
            }

            // --- Obtain the project and its items
            var project      = SpectNetPackage.Default.ActiveRoot;
            var projectItems = project.ProjectItems;
            var currentIndex = 0;
            var find         = true;

            while (currentIndex < folderSegments.Length)
            {
                // --- Find or create folder segments
                var segment = folderSegments[currentIndex];
                if (find)
                {
                    // --- We are in "find" mode
                    var found = false;
                    // --- Search for the folder segment
                    foreach (ProjectItem projItem in projectItems)
                    {
                        var folder = projItem.Properties.Item("FolderName").Value?.ToString();
                        if (string.Compare(folder, segment, StringComparison.InvariantCultureIgnoreCase) == 0)
                        {
                            // --- We found the folder, we'll go no with search within this segment
                            projectItems = projItem.ProjectItems;
                            found        = true;
                            break;
                        }
                    }
                    if (!found)
                    {
                        // --- Move to "create" mode
                        find = false;
                    }
                }
                if (!find)
                {
                    // --- We're in create mode, add and locate the new folder segment
                    var found = false;
                    projectItems.AddFolder(segment);
                    var parent = projectItems.Parent;
                    if (parent is Project projectType)
                    {
                        projectItems = projectType.ProjectItems;
                    }
                    else if (parent is ProjectItem itemType)
                    {
                        projectItems = itemType.ProjectItems;
                    }
                    foreach (ProjectItem projItem in projectItems)
                    {
                        var folder = projItem.Properties.Item("FolderName").Value?.ToString();
                        if (string.Compare(folder, segment, StringComparison.InvariantCultureIgnoreCase) == 0)
                        {
                            // --- We found the folder, we'll go no with search within this segment
                            projectItems = projItem.ProjectItems;
                            found        = true;
                            break;
                        }
                    }
                    if (!found)
                    {
                        // --- This should not happen...
                        VsxDialogs.Show($"The folder segment {segment} could not be created.",
                                        "Adding project item failed");
                        return;
                    }
                }

                // --- Move to the next segment
                currentIndex++;
            }

            // --- Check if that filename exists within the project folder
            var         tempFile = Path.GetFileName(filename);
            ProjectItem toDelete = null;

            foreach (ProjectItem projItem in projectItems)
            {
                var file = Path.GetFileName(projItem.FileNames[0]);
                if (string.Compare(file, tempFile,
                                   StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    if (confirmOverwrite)
                    {
                        var answer = VsxDialogs.Show(fileExistsMessage ?? DEFAULT_FILE_EXISTS_MESSAGE,
                                                     "File already exists",
                                                     MessageBoxButton.YesNo, VsxMessageBoxIcon.Question, 1);
                        if (answer == VsxDialogResult.No)
                        {
                            return;
                        }
                    }
                    toDelete = projItem;
                    break;
                }
            }

            // --- Remove existing file
            toDelete?.Delete();

            // --- Add the item to the appropriate item
            projectItems.AddFromFileCopy(filename);

            // --- Refresh the solution's content
            SpectNetPackage.Default.ActiveProject.CollectItems();
        }
Exemplo n.º 19
0
 /// <summary>
 /// Responds to the event when an invalid machine state has been detected
 /// </summary>
 /// <param name="e">Exception instance</param>
 protected override void OnInvalidVmMachineStateException(InvalidVmStateException e)
 {
     VsxDialogs.Show(e.OriginalMessage, "Error loading virtual machine state");
 }
Exemplo n.º 20
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();
        }
Exemplo n.º 21
0
        /// <summary>
        /// Exports the disassembly using the specified disassembler object
        /// </summary>
        /// <param name="disassembler">Disassembler set up for annotations</param>
        public void ExportDisassembly(Z80Disassembler disassembler)
        {
            // --- Create the disassembly output
            if (!ushort.TryParse(ExportParams.StartAddress, out var startAddress))
            {
                return;
            }
            if (!ushort.TryParse(ExportParams.EndAddress, out var endAddress))
            {
                return;
            }
            var output    = disassembler.Disassemble(startAddress, endAddress);
            var equs      = new Dictionary <string, ushort>();
            var items     = new List <DisassemblyItemViewModel>();
            var addresses = new HashSet <ushort>();

            // --- Create the set of addresses that may be referred through labels
            foreach (var outputItem in output.OutputItems)
            {
                addresses.Add(outputItem.Address);
            }

            // --- Collect all external labels and symbols
            foreach (var outputItem in output.OutputItems)
            {
                items.Add(new DisassemblyItemViewModel(ParentViewModel, outputItem));
                if (outputItem.HasLabelSymbol)
                {
                    // --- Check if it is an external label
                    if (outputItem.SymbolValue >= startAddress && outputItem.SymbolValue <= endAddress)
                    {
                        continue;
                    }
                    if (ParentViewModel.GetLabel(outputItem.SymbolValue, out var extLabel))
                    {
                        equs[extLabel] = outputItem.SymbolValue;
                    }
                }
                // --- Check if literal replacement
                else if (ParentViewModel.GetLiteralReplacement(outputItem.Address, out var literal))
                {
                    equs[literal] = outputItem.SymbolValue;
                }
            }

            // --- Create the exported contents item by item
            var contents = new StringBuilder(4000);

            // --- Export the origin
            contents.AppendLine($"{InstructionIndent}.org #{startAddress:X4}");
            contents.AppendLine();

            // --- Create .EQU lines for external labels and symbols
            contents.AppendLine($"{CommentBegins}External symbols{CommentEnds}");
            foreach (var symbolKey in equs.Keys.OrderBy(k => k))
            {
                if (ExportParams.HangingLabels)
                {
                    contents.AppendLine($"{symbolKey}:");
                    contents.AppendLine($"{InstructionIndent}.equ #{equs[symbolKey]:X4}");
                }
                else
                {
                    contents.AppendLine($"{symbolKey}: .equ #{equs[symbolKey]:X4}");
                }
            }
            contents.AppendLine();

            // --- Iterate output items
            foreach (var item in items)
            {
                var lineContents = new StringBuilder(200);

                // --- Handle prefix comment
                if (item.HasPrefixComment)
                {
                    contents.AppendLine();
                    OutputComment(item.PrefixCommentFormatted, contents, MaxLineLength - CommentCharCount, "");
                }

                // --- Handle label
                if (!string.IsNullOrEmpty(item.LabelFormatted))
                {
                    if (ExportParams.HangingLabels)
                    {
                        // --- Hanging label to a separate line
                        contents.AppendLine($"{item.LabelFormatted}");
                        lineContents.Append(InstructionIndent);
                    }
                    else
                    {
                        // ---Label goes to the instruction line
                        lineContents.Append($"{item.LabelFormatted} ");
                    }
                }
                else
                {
                    // --- Instruction only
                    lineContents.Append(InstructionIndent);
                }

                // --- Instruction part: take care labels that cannot be accessed through instructions
                var instruction = item.InstructionFormatted;
                var instrItem   = item.Item;
                if (item.Item.HasLabelSymbol && !addresses.Contains(item.Item.SymbolValue))
                {
                    if (instrItem.SymbolValue >= startAddress && instrItem.SymbolValue <= endAddress ||
                        !ParentViewModel.GetLabel(instrItem.SymbolValue, out _))
                    {
                        // --- Internal or external label without associated symbol
                        // --- Change the disassembly label name to the corresponding address
                        var addressString = $"#{instrItem.SymbolValue:X4}";
                        instruction = instrItem.Instruction.Substring(0, instrItem.TokenPosition)
                                      + addressString
                                      + instrItem.Instruction.Substring(instrItem.TokenPosition + instrItem.TokenLength);
                    }
                }
                lineContents.Append(instruction);

                // --- Handle line comment
                if (!string.IsNullOrEmpty(item.CommentFormatted))
                {
                    var maxCommentLength = MaxLineLength - CommentCharCount - lineContents.Length - 1;
                    if (maxCommentLength < 20)
                    {
                        // --- Comment does not fit into this line
                        contents.AppendLine(lineContents.ToString());
                        OutputComment(item.CommentFormatted, contents,
                                      MaxLineLength - CommentCharCount - InstructionIndent.Length,
                                      InstructionIndent);
                    }
                    else
                    {
                        // --- Comment fits into this line
                        lineContents.Append(" ");
                        OutputComment(item.CommentFormatted, contents, maxCommentLength, lineContents.ToString());
                    }
                }
                else
                {
                    // --- Output the remainder of the line
                    if (lineContents.Length > 0)
                    {
                        contents.AppendLine(lineContents.ToString());
                    }
                }
            }

            // --- Save the file
            try
            {
                var dirName = Path.GetDirectoryName(ExportParams.Filename);
                if (!string.IsNullOrEmpty(dirName) && !Directory.Exists(dirName))
                {
                    Directory.CreateDirectory(dirName);
                }
                File.WriteAllText(ExportParams.Filename, contents.ToString());
            }
            catch (Exception ex)
            {
                VsxDialogs.Show($"Error while exporting to file {ExportParams.Filename}: {ex.Message}",
                                "Export disassembly error.", MessageBoxButton.OK, VsxMessageBoxIcon.Error);
                return;
            }
            if (!ExportParams.AddToProject)
            {
                return;
            }

            // --- Step #6: Add the saved item to the project
            // --- Check path segment names
            DiscoveryProject.AddFileToProject(SpectNetPackage.Default.Options.DisassExportFolder,
                                              ExportParams.Filename,
                                              INVALID_FOLDER_MESSAGE, FILE_EXISTS_MESSAGE);
        }
Exemplo n.º 22
0
        /// <summary>
        /// Compiles the Z80 code file
        /// </summary>
        protected override async Task ExecuteAsync()
        {
            // --- Prepare the appropriate file to export
            Success = true;
            GetCodeItem(out var hierarchy, out var itemId);

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

            // --- Step #2: Check for zero code length
            if (Output.Segments.Sum(s => s.EmittedCode.Count) == 0)
            {
                VsxDialogs.Show("The length of the compiled code is 0, " +
                                "so there is no code to export.",
                                "No code to export.");
                Success = false;
                return;
            }

            // --- Step #2: Collect export parameters from the UI
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

            if (DisplayExportParameterDialog(out var vm))
            {
                return;
            }

            if (vm.Format == ExportFormat.IntelHex)
            {
                Package.CodeManager.SaveIntelHexFile(vm.Filename, Output);
                return;
            }

            // --- Step #3: Check screen file again
            var useScreenFile = !string.IsNullOrEmpty(vm.ScreenFile) && vm.ScreenFile.Trim().Length > 0;

            if (useScreenFile && !CommonTapeFilePlayer.CheckScreenFile(vm.ScreenFile))
            {
                VsxDialogs.Show("The specified screen file cannot be read as a ZX Spectrum compatible screen file.",
                                "Screen file error.", MessageBoxButton.OK, VsxMessageBoxIcon.Error);
                Success = false;
                return;
            }

            // --- Step #4: Create code segments
            var           codeBlocks   = Package.CodeManager.CreateTapeBlocks(vm.Name, Output, vm.SingleBlock);
            List <byte[]> screenBlocks = null;

            if (useScreenFile)
            {
                screenBlocks = Package.CodeManager.CreatScreenBlocks(vm.ScreenFile);
            }

            // --- Step #5: Create Auto Start header block, if required
            var blocksToSave = new List <byte[]>();

            if (!ushort.TryParse(vm.StartAddress, out var startAddress))
            {
                startAddress = (ushort)ExportStartAddress;
            }
            var autoStartBlocks = Package.CodeManager.CreateAutoStartBlock(
                vm.Name,
                useScreenFile,
                vm.AddPause0,
                vm.Border,
                codeBlocks.Count >> 1,
                startAddress,
                vm.ApplyClear
                    ? Output.Segments.Min(s => s.StartAddress)
                    : (ushort?)null);

            blocksToSave.AddRange(autoStartBlocks);

            // --- Step #6: Save all the blocks
            if (screenBlocks != null)
            {
                blocksToSave.AddRange(screenBlocks);
            }
            blocksToSave.AddRange(codeBlocks);
            SaveDataBlocks(vm, blocksToSave);

            if (!vm.AddToProject)
            {
                return;
            }

            // --- Step #6: Add the saved item to the project
            // --- Check path segment names
            DiscoveryProject.AddFileToProject(Package.Options.TapeFolder, vm.Filename,
                                              INVALID_FOLDER_MESSAGE, FILE_EXISTS_MESSAGE);
        }
Exemplo n.º 23
0
        /// <summary>
        /// Compiles the Z80 code file
        /// </summary>
        protected override async Task ExecuteAsync()
        {
            // --- Prepare the appropriate file to export
            GetCodeItem(out var hierarchy, out var itemId);

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

            // --- Step #2: 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 export.",
                                "No code to export.");
                return;
            }

            // --- Step #2: Collect export parameters from the UI
            await SwitchToMainThreadAsync();

            if (DisplayExportParameterDialog(out var vm))
            {
                return;
            }

            // --- Step #3: Create code segments
            var codeBlocks = Package.CodeManager.CreateTapeBlocks(vm.Name, Output, vm.SingleBlock);

            // --- Step #4: Create Auto Start header block, if required
            var blocksToSave = new List <byte[]>();

            if (!ushort.TryParse(vm.StartAddress, out var startAddress))
            {
                startAddress = (ushort)ExportStartAddress;
            }
            var autoStartBlocks = Package.CodeManager.CreateAutoStartBlock(
                vm.Name,
                codeBlocks.Count >> 1,
                startAddress,
                vm.ApplyClear
                    ? Output.Segments.Min(s => s.StartAddress)
                    : (ushort?)null);

            blocksToSave.AddRange(autoStartBlocks);

            // --- Step #5: Save all the blocks
            blocksToSave.AddRange(codeBlocks);
            SaveDataBlocks(vm, blocksToSave);

            if (!vm.AddToProject)
            {
                return;
            }

            // --- Step #6: Add the saved item to the project
            // --- Check path segment names
            DiscoveryProject.AddFileToProject(Package.Options.TapeFolder, vm.Filename,
                                              INVALID_FOLDER_MESSAGE, FILE_EXISTS_MESSAGE);
        }
Exemplo n.º 24
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:
                    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();
        }
Exemplo n.º 25
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();
        }
Exemplo n.º 26
0
        /// <summary>
        /// Compiles the Z80 code file
        /// </summary>
        protected override async Task ExecuteAsync()
        {
            // --- Prepare the appropriate file to export
            Success = true;

            // --- Step #1: Compile the code
            if (!await CompileCode())
            {
                Success = false;
                return;
            }

            // --- Step #2: Check for zero code length
            if (Output.Segments.Sum(s => s.EmittedCode.Count) == 0)
            {
                VsxDialogs.Show("The length of the compiled code is 0, " +
                                "so there is no code to export.",
                                "No code to export.");
                Success = false;
                return;
            }

            // --- Step #3: Collect export parameters from the UI
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

            if (DisplayExportParameterDialog(out var vm))
            {
                return;
            }

            // --- Step #4: Execute pre-export event
            var codeManager = SpectNetPackage.Default.CodeManager;

            PreexportError  = null;
            PostexportError = null;
            var eventOutput = await codeManager.RunPreExportEvent(ItemFullPath, vm.Filename);

            if (eventOutput != null)
            {
                PreexportError = eventOutput;
                CleanupError   = await codeManager.RunBuildErrorEvent(ItemFullPath);

                DisplayBuildErrors();
                Success = false;
                return;
            }

            vm.Name = Path.GetFileNameWithoutExtension(ItemPath) ?? "MyCode";
            var result = ExportCompiledCode(Output, vm);

            if (result != 0)
            {
                VsxDialogs.Show("The specified screen file cannot be read as a ZX Spectrum compatible screen file.",
                                "Screen file error.", MessageBoxButton.OK, VsxMessageBoxIcon.Error);
                Success = false;
                return;
            }



            if (vm.AddToProject)
            {
                // --- Step #9: Add the saved item to the project
                // --- Check path segment names
                SpectrumProject.AddFileToProject(SpectNetPackage.Default.Options.TapeFolder, vm.Filename,
                                                 INVALID_FOLDER_MESSAGE, FILE_EXISTS_MESSAGE);
            }

            // --- Run post-export event
            // --- Execute post-build event
            eventOutput = await codeManager.RunPostExportEvent(ItemFullPath, vm.Filename);

            if (eventOutput != null)
            {
                PostexportError = eventOutput;
                CleanupError    = await codeManager.RunBuildErrorEvent(ItemFullPath);

                DisplayBuildErrors();
                Success = false;
            }
        }
Exemplo n.º 27
0
 /// <summary>
 /// Responds to the event when an loading the machine state raises an exception
 /// </summary>
 /// <param name="e">Exception instance</param>
 public static void OnLoadVmException(Exception e)
 {
     VsxDialogs.Show($"Unexpected error: {e.Message}", "Error loading virtual machine state");
 }
Exemplo n.º 28
0
 /// <summary>
 /// Responds to the event when an invalid machine state has been detected
 /// </summary>
 /// <param name="e">Exception instance</param>
 public static void OnInvalidVmMachineStateException(InvalidVmStateException e)
 {
     VsxDialogs.Show(e.OriginalMessage, "Error loading virtual machine state");
 }
Exemplo n.º 29
0
        /// <summary>
        /// Compiles the Z80 code file
        /// </summary>
        protected override async Task ExecuteAsync()
        {
            GetItem(out var hierarchy, out var itemId);
            if (hierarchy == null)
            {
                return;
            }

            var codeManager = Package.CodeManager;
            var options     = Package.Options;

            // --- Step #1: Compile
            var start = DateTime.Now;
            var pane  = OutputWindow.GetPane <Z80OutputPane>();

            pane.WriteLine("Z80 Assembler");
            _output = codeManager.Compile(hierarchy, itemId);
            var duration = (DateTime.Now - start).TotalMilliseconds;

            pane.WriteLine($"Compile time: {duration}ms");

            if (_output.ErrorCount != 0)
            {
                // --- Compilation completed with errors
                return;
            }
            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 #2: Check non-zero displacements
            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 #3: Stop the virtual machine if required
            await SwitchToMainThreadAsync();

            Package.ShowToolWindow <SpectrumEmulatorToolWindow>();
            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 3 frames' time to stop.
                Package.MachineViewModel.StopVmCommand.Execute(null);
                await Task.Delay(60);

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

            // --- Step #4: Start the virtual machine so that later we can load the program
            vm.StartVmWithCodeCommand.Execute(null);

            const int timeOutInSeconds = 5;
            var       counter          = 0;

            while (vm.VmState != VmState.Paused && counter < timeOutInSeconds * 10)
            {
                await Task.Delay(100);

                counter++;
            }
            if (vm.VmState != VmState.Paused)
            {
                VsxDialogs.Show($"The ZX Spectrum virtual machine did not start within {timeOutInSeconds} seconds.",
                                "Unexpected issue", MessageBoxButton.OK, VsxMessageBoxIcon.Error);
                vm.StopVmCommand.Execute(null);
            }

            // --- Step #5: Inject the code into the memory
            codeManager.InjectCodeIntoVm(_output);

            // --- Step #6: Jump to execute the code
            vm.SpectrumVm.Cpu.Registers.PC = _output.EntryAddress ?? _output.Segments[0].StartAddress;
            ResumeVm();
        }
Exemplo n.º 30
0
        /// <summary>
        /// Compiles the Z80 code file
        /// </summary>
        protected override async Task ExecuteAsync()
        {
            // --- Prepare the appropriate file to export
            Success = true;

            // --- Step #1: Compile the code
            if (!await CompileCode())
            {
                Success = false;
                return;
            }

            // --- Step #2: Check for zero code length
            if (Output.Segments.Sum(s => s.EmittedCode.Count) == 0)
            {
                VsxDialogs.Show("The length of the compiled code is 0, " +
                                "so there is no code to export.",
                                "No code to export.");
                Success = false;
                return;
            }

            // --- Step #3: Collect export parameters from the UI
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

            if (DisplayExportParameterDialog(out var vm))
            {
                return;
            }

            // --- Step #4: Execute pre-export event
            var codeManager = SpectNetPackage.Default.CodeManager;

            PreexportError  = null;
            PostexportError = null;
            var eventOutput = await codeManager.RunPreExportEvent(ItemFullPath, vm.Filename);

            if (eventOutput != null)
            {
                PreexportError = eventOutput;
                CleanupError   = await codeManager.RunBuildErrorEvent(ItemFullPath);

                DisplayBuildErrors();
                Success = false;
                return;
            }

            if (vm.Format == ExportFormat.IntelHex)
            {
                // --- Step #5: Export to Intel format
                SaveIntelHexFile(vm.Filename, Output);
            }
            else
            {
                // --- Step #5: Check screen file again
                var useScreenFile = !string.IsNullOrEmpty(vm.ScreenFile) && vm.ScreenFile.Trim().Length > 0;
                if (useScreenFile && !CommonTapeFilePlayer.CheckScreenFile(vm.ScreenFile))
                {
                    VsxDialogs.Show("The specified screen file cannot be read as a ZX Spectrum compatible screen file.",
                                    "Screen file error.", MessageBoxButton.OK, VsxMessageBoxIcon.Error);
                    Success = false;
                    return;
                }

                // --- Step #6: Create code segments
                var           codeBlocks   = CreateTapeBlocks(vm.Name, vm.SingleBlock);
                List <byte[]> screenBlocks = null;
                if (useScreenFile)
                {
                    screenBlocks = CreatScreenBlocks(vm.ScreenFile);
                }

                // --- Step #7: Create Auto Start header block, if required
                var blocksToSave = new List <byte[]>();
                if (!ushort.TryParse(vm.StartAddress, out var startAddress))
                {
                    startAddress = (ushort)ExportStartAddress;
                }

                if (vm.AutoStartEnabled)
                {
                    var autoStartBlocks = CreateAutoStartBlock(
                        vm.Name,
                        useScreenFile,
                        vm.AddPause0,
                        vm.Border,
                        startAddress,
                        vm.ApplyClear
                            ? Output.Segments.Min(s => s.StartAddress)
                            : (ushort?)null);
                    blocksToSave.AddRange(autoStartBlocks);
                }

                // --- Step #8: Save all the blocks
                if (screenBlocks != null)
                {
                    blocksToSave.AddRange(screenBlocks);
                }

                blocksToSave.AddRange(codeBlocks);
                SaveDataBlocks(vm, blocksToSave);

                if (vm.AddToProject)
                {
                    // --- Step #9: Add the saved item to the project
                    // --- Check path segment names
                    SpectrumProject.AddFileToProject(SpectNetPackage.Default.Options.TapeFolder, vm.Filename,
                                                     INVALID_FOLDER_MESSAGE, FILE_EXISTS_MESSAGE);
                }
            }

            // --- Run post-export event
            // --- Execute post-build event
            eventOutput = await codeManager.RunPostExportEvent(ItemFullPath, vm.Filename);

            if (eventOutput != null)
            {
                PostexportError = eventOutput;
                CleanupError    = await codeManager.RunBuildErrorEvent(ItemFullPath);

                DisplayBuildErrors();
                Success = false;
            }
        }