Example #1
0
            protected override async Task ExecuteAsync()
            {
                await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

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

                // --- Save the file into the vmstate folder
                var filename = Path.Combine(HostPackage.Options.VmStateSaveFileFolder, vm.Filename);

                filename = Path.ChangeExtension(filename, ".vmstate");

                var spectrum = HostPackage.EmulatorViewModel.Machine.SpectrumVm;
                var state    = spectrum.GetVmState(HostPackage.Solution.ActiveProject.ModelName);

                var folder = Path.GetDirectoryName(filename);

                if (folder != null && !Directory.Exists(folder))
                {
                    Directory.CreateDirectory(folder);
                }
                File.WriteAllText(filename, state);

                SpectrumProject.AddFileToProject(HostPackage.Options.VmStateProjectFolder, filename,
                                                 INVALID_FOLDER_MESSAGE, FILE_EXISTS_MESSAGE);
            }
Example #2
0
 /// <summary>
 /// The virtual machine has just saved a file.
 /// </summary>
 private void MachineOnLeftSaveMode(object sender, SaveModeEventArgs e)
 {
     Dispatcher.Invoke(() =>
     {
         SpectrumProject.AddFileToProject(
             SpectNetPackage.Default.Options.TapeFolder,
             e.FileName,
             INVALID_FOLDER_MESSAGE,
             FILE_EXISTS_MESSAGE);
     });
 }
Example #3
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);
            }
        }
        /// <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
            }
        }
Example #5
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);
        }
Example #6
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
            SpectrumProject.AddFileToProject(SpectNetPackage.Default.Options.DisassExportFolder,
                                             ExportParams.Filename,
                                             INVALID_FOLDER_MESSAGE, FILE_EXISTS_MESSAGE);
        }
        /// <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;
            }
        }
        /// <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;
            }
        }