/// <summary> /// Sets up the annotations for the current machine. /// </summary> public void SetupMachineAnnotations() { // --- Read ROM annotations var spectrumVm = Parent.SpectrumVm; RomPageAnnotations = new Dictionary <int, DisassemblyAnnotation>(); RomAnnotationFiles = new Dictionary <int, string>(); var romConfig = spectrumVm.RomConfiguration; var roms = romConfig.NumberOfRoms; for (var i = 0; i < roms; i++) { var annFile = spectrumVm.RomProvider.GetAnnotationResourceName(romConfig.RomName, roms == 1 ? -1 : i); var annData = spectrumVm.RomProvider.LoadRomAnnotations(romConfig.RomName, roms == 1 ? -1 : i); DisassemblyAnnotation.Deserialize(annData, out var annotation); RomPageAnnotations.Add(i, annotation); RomAnnotationFiles.Add(i, annFile); } // --- Read the initial RAM annotations RamBankAnnotations = new Dictionary <int, DisassemblyAnnotation>(); SpectNetPackage.Default.CodeManager.AnnotationFileChanged += OnAnnotationFileChanged; OnAnnotationFileChanged(null, EventArgs.Empty); // --- Register Disassembly providers to use if (RomPageAnnotations.TryGetValue(romConfig.Spectrum48RomIndex, out var spectrumRomAnn)) { Z80Disassembler.SetProvider <ISpectrum48RomLabelProvider>( new Spectrum48RomLabelProvider(spectrumRomAnn)); } }
private void RefreshDisassembly() { unchecked { Z80Disassembler.DisassembledInstruction disasm; byte[] instr = new byte[4]; disasmStrBuilder.Clear(); int baseAddress = (int)disasmAddrUpDown.Value; for (int i = 0; i < 64; i += disasm.Length) { for (int j = 0; j < 4; j++) { instr[j] = Cpu.MemoryRead(this, (ushort)(baseAddress + i + j)); } disasmStrBuilder.Append(((ushort)(baseAddress + i)).ToString("X4")); disasmStrBuilder.Append(": "); disasm = Z80Disassembler.DisassembleInstruction(instr, (ushort)(baseAddress + i)); for (int j = 0; j < 4; j++) { if (j < disasm.Length) { disasmStrBuilder.Append(instr[j].ToString("X2")); } else { disasmStrBuilder.Append(" "); } } disasmStrBuilder.Append(" "); disasmStrBuilder.Append(disasm.Disassembly); disasmStrBuilder.AppendLine(); } disassemblyTextBox.Text = disasmStrBuilder.ToString(); } }
private MachineInstruction RunTest(params byte [] bytes) { var image = new LoadedImage(Address.Ptr16(0x0100), bytes); var rdr = new LeImageReader(image, 0); var dasm = new Z80Disassembler(rdr); return dasm.First(); }
private MachineInstruction RunTest(params byte [] bytes) { var image = new MemoryArea(Address.Ptr16(0x0100), bytes); var rdr = new LeImageReader(image, 0); var dasm = new Z80Disassembler(rdr); return(dasm.First()); }
void RefreshExecHistroy() { unchecked { if (!Cpu.TraceLastExec) { return; } Z80Disassembler.DisassembledInstruction disasm; byte[] instr = new byte[4]; historyStrBuilder.Clear(); historyStrBuilder.AppendLine(" SP AF BC DE HL AF' BC' DE' HL' IX IY IR IFF"); //int baseAddress = Cpu.PC; int pos = (Cpu.LastExecPtr - 1) & Z80Cpu.LastExecMask; for (int i = 0; i < instrShowCount; i++) { /*for (int j = 0; j < 4; j++) * { * instr[j] = Cpu.LastExecOpcode[pos, j]; * }*/ instr[0] = (byte)(Cpu.LastExecData[pos, 0] & 0xFF); instr[1] = (byte)(Cpu.LastExecData[pos, 0] >> 8); instr[2] = (byte)(Cpu.LastExecData[pos, 1] & 0xFF); instr[3] = (byte)(Cpu.LastExecData[pos, 1] >> 8); ushort PC = Cpu.LastExecData[pos, 2]; //str.Append(Cpu.LastExecAddress[pos].ToString("X4")); historyStrBuilder.Append(PC.ToString("X4")); historyStrBuilder.Append(": "); disasm = Z80Disassembler.DisassembleInstruction(instr, PC); for (int j = 0; j < 4; j++) { if (j < disasm.Length) { historyStrBuilder.Append(instr[j].ToString("X2")); } else { historyStrBuilder.Append(" "); } } historyStrBuilder.Append(" "); historyStrBuilder.Append(disasm.Disassembly); for (int k = disasm.Disassembly.Length; k < 16; k++) { historyStrBuilder.Append(" "); } for (int k = 3; k < 16; k++) { historyStrBuilder.Append(Cpu.LastExecData[pos, k].ToString("X4")); historyStrBuilder.Append(" "); } historyStrBuilder.AppendLine(); pos = (pos - 1) & Z80Cpu.LastExecMask; } disassemblyTextBox.Text = historyStrBuilder.ToString(); } }
public static void Test(SpectrumSpecificDisassemblyFlags flags, string[] expected, params byte[] opCodes) { var map = new MemoryMap { new MemorySection(0x0000, (ushort)(opCodes.Length - 1)) }; var disassembler = new Z80Disassembler(map, opCodes, flags); var output = disassembler.Disassemble(); output.OutputItems.Count.ShouldBe(expected.Length); for (var i = 0; i < expected.Length; i++) { output.OutputItems[i].Instruction.ToLower().ShouldBe(expected[i]); } }
public void CreateFileTest() { // --- Arrange var romP = new ResourceRomProvider(typeof(ResourceRomProvider).Assembly); var romInfo = romP.LoadRom("ZXSpectrum48"); romInfo.RomBytes.ShouldNotBeNull(); var disassembler = new Z80Disassembler(romInfo.MemorySections, romInfo.RomBytes); var output = disassembler.Disassemble(0x0000, 0x7FF); // --- Act using (var writer = File.CreateText(@"C:\Temp\Disassembly07ff.z80asm")) { disassembler.SaveDisassembly(writer, output, romInfo.Annotations); } }
public static void Test(string expected, params byte[] opCodes) { var map = new MemoryMap { new MemorySection(0x0000, (ushort)(opCodes.Length - 1)) }; var disassembler = new Z80Disassembler(map, opCodes); var output = disassembler.Disassemble(); output.OutputItems.Count.ShouldBe(1); var item = output.OutputItems[0]; item.Instruction.ToLower().ShouldBe(expected.ToLower()); item.LastAddress.ShouldBe((ushort)(opCodes.Length - 1)); item.OpCodes.Trim().ShouldBe(string.Join(" ", opCodes.Select(o => $"{o:X2}"))); }
public override void Main(Z80DasmArgs args) { WriteInfoMessage("Disassembling ~Cyan~{0}~R~", args.InputBinaryFile); var symbolFile = Path.ChangeExtension( Path.GetFullPath(args.InputBinaryFile.FullName), "symbols"); Dictionary <ushort, string> symbols; if (File.Exists(symbolFile)) { WriteSuccessMessage("Found symbol file ~Cyan~{0}~R~", symbolFile); symbols = SymbolFileReader.Read(symbolFile); } else { WriteInfoMessage("Could not find symbol file for binary"); symbols = new Dictionary <ushort, string>(); } string dasm; using (var reader = new BinaryReader(args.InputBinaryFile.OpenRead())) { var disassembler = new Z80Disassembler(reader, symbols); var instructions = disassembler.Disassemble(); dasm = new Z80AssemblyFormatter(symbols).Format(instructions); } if (!string.IsNullOrEmpty(args.OutputDisassemblyFile)) { WriteInfoMessage( "Writing disassembled instructions to ~Cyan~{0}~R~", args.OutputDisassemblyFile); File.WriteAllText(args.OutputDisassemblyFile, dasm); } else { Cli.WriteLine(Cli.Escape(dasm)); } WriteSuccessMessage("Done"); }
private void UpdateExecutionHistory() { ushort address = m_execution_control.TVC.CPU.Registers.PC; Z80DisassemblerInstruction instruction; Z80Disassembler disassembler = new Z80Disassembler(); for (int i = 0; i < 2; i++) { ExecutionHistoryEntry history = m_execution_control.ExecutionHistory[i]; if (history.TCycle > 0) { disassembler.ReadByte = history.ReadMemory; instruction = disassembler.Disassemble(history.PC); instruction.TStates = history.TCycle; instruction.TStates2 = 0; } else { instruction = null; } UpdateAddress(instruction, 1 - i); UpdateBytes(instruction, 1 - i); UpdateMnemonics(instruction, 1 - i); UpdateOperand1(instruction, 1 - i); UpdateOperand2(instruction, 1 - i); UpdateTCycle(instruction, 1 - i); } for (int i = 2; i < 5; i++) { instruction = m_disassembler.Disassemble(address); UpdateAddress(instruction, i); UpdateBytes(instruction, i); UpdateMnemonics(instruction, i); UpdateOperand1(instruction, i); UpdateOperand2(instruction, i); UpdateTCycle(instruction, i); address += instruction.Length; } }
public void Rst28SectionWorksAsExpected() { // --- Arrange var opCodes = new byte[] { 0x02, 0xE1, 0x34, 0xF1, 0x38, 0xAA, 0x3B, 0x29, 0x00 }; var expected = new[] { ".defb #02", ".defb #e1", ".defb #34", ".defb #f1, #38, #aa, #3b, #29", "nop" }; var expComment = new[] { "(delete)", "(get-mem-1)", "(stk-data)", "(1.442695)", null }; // --- Act var map = new MemoryMap { new MemorySection(0x0000, (ushort)(opCodes.Length - 2), MemorySectionType.Rst28Calculator), new MemorySection((ushort)(opCodes.Length - 1), (ushort)(opCodes.Length - 1)) }; var disassembler = new Z80Disassembler(map, opCodes); var output = disassembler.Disassemble(); // --- Assert output.OutputItems.Count.ShouldBe(expected.Length); for (var i = 0; i < expected.Length; i++) { output.OutputItems[i].Instruction.ToLower().ShouldBe(expected[i]); } output.OutputItems.Count.ShouldBe(expComment.Length); for (var i = 0; i < expected.Length; i++) { output.OutputItems[i].HardComment?.ToLower().ShouldBe(expComment[i]); } }
public void RefreshView() { RegistersTextBox.Text = _currentDevice.Cpu.Registers + "\r\nTick: " + _currentDevice.Cpu.TickCount + "\r\n\r\n" + "LCDC: " + ((byte)_currentDevice.Gpu.Lcdc).ToString("X2") + "\r\n" + "STAT: " + ((byte)_currentDevice.Gpu.Stat).ToString("X2") + "\r\n" + "LY: " + _currentDevice.Gpu.LY.ToString("X2") + "\r\n" + "ScY: " + _currentDevice.Gpu.ScY.ToString("X2") + "\r\n" + "ScX: " + _currentDevice.Gpu.ScX.ToString("X2") + "\r\n" + "\r\n" + "TIMA: " + _currentDevice.Timer.Tima.ToString("X2") + "\r\n" + "TMA: " + _currentDevice.Timer.Tma.ToString("X2") + "\r\n" + "TAC: " + ((byte)_currentDevice.Timer.Tac).ToString("X2") + "\r\n"; ; DisassemblyView.Items.Clear(); var disassembler = new Z80Disassembler(_currentDevice.Memory); disassembler.Position = _currentDevice.Cpu.Registers.PC; for (int i = 0; i < 30 && disassembler.Position < 0xFFFF; i++) { var instruction = disassembler.ReadNextInstruction(); DisassemblyView.Items.Add(new InstructionItem(_currentDevice, instruction)); } }
private void SimulationThread() { double delay_time; m_disassembler = new Z80Disassembler(); m_disassembler.ReadByte = ReadMemory; m_stopwatch = new Stopwatch(); m_instruction_start_pc = TVC.CPU.Registers.PC; m_instruction_t_cycle = 0; m_debug_event_timestamp = DateTime.Now; delay_time = 0; while (m_thread_running) { // handle execution state change switch (m_execution_state_request) { // change to pause state case ExecutionStateRequest.Pause: m_execution_state_request = ExecutionStateRequest.NoChange; m_last_execution_state = m_execution_state; m_execution_state = ExecutionState.Paused; m_execution_state_changed_event.Set(); break; case ExecutionStateRequest.Restore: m_execution_state_request = ExecutionStateRequest.NoChange; m_execution_state = m_last_execution_state; m_execution_state_changed_event.Set(); break; // change to running case ExecutionStateRequest.Run: m_execution_state_request = ExecutionStateRequest.NoChange; m_execution_state = ExecutionState.Running; m_execution_state_changed_event.Set(); break; // full speed run case ExecutionStateRequest.RunFullSpeed: m_execution_state_request = ExecutionStateRequest.NoChange; m_execution_state = ExecutionState.RunningFullSpeed; m_execution_state_changed_event.Set(); break; // resets computer case ExecutionStateRequest.Reset: m_execution_state_request = ExecutionStateRequest.NoChange; TVC.Reset(); m_execution_state_changed_event.Set(); break; // no change case ExecutionStateRequest.NoChange: // do nothing break; } // execute according the execution state switch (m_execution_state) { case ExecutionState.Running: { uint ellapsed_tick; //m_stopwatch.Restart(); ellapsed_tick = RunOneFrame(); GenerateDebugEvent(false); //m_stopwatch.Stop(); //delay_time += TVC.CPUTickToMillisec(ellapsed_tick) - m_stopwatch.Elapsed.TotalMilliseconds; m_thread_event.WaitOne(1000); /* * if (delay_time > 0) * { * int delay = (int)Math.Truncate(delay_time); * * m_stopwatch.Restart(); * m_thread_event.WaitOne(delay); * m_stopwatch.Stop(); * delay_time -= m_stopwatch.Elapsed.TotalMilliseconds; * } * else * { * // execution is behind the schedule -> no delay * m_thread_event.WaitOne(0); * * delay_time = 0; * } */ } break; case ExecutionState.RunningFullSpeed: RunOneFrame(); GenerateDebugEvent(false); m_thread_event.WaitOne(0); break; case ExecutionState.Paused: m_thread_event.WaitOne(1000); break; } } }
/// <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); }
static void Main(string[] args) { string path; if (args.Length < 1) { Console.WriteLine("Enter file path: "); path = Console.ReadLine(); } else { path = args[0]; } var data = File.ReadAllBytes(path); var mem = new byte[65536]; Array.Copy(data, 0, mem, 0x100, data.Length); var cpu = new Z80Disassembler(mem); while (true) { Console.Write("> "); var input = Console.ReadLine(); var cmdArgs = input.Split(' '); switch (cmdArgs[0].ToLower()) { case "d": case "dis": case "disassemble": { var addr = Convert.ToUInt16(cmdArgs[1], 16); var output = cpu.Disassemble(addr); foreach (var disassembledInstruction in output) { Console.WriteLine($"[0x{disassembledInstruction.Address:X4}]: {disassembledInstruction.Mnemonic}"); } break; } case "x": case "examine": { var addr = Convert.ToUInt16(cmdArgs[1], 16); var len = 1; if (cmdArgs.Length > 2) { len = Convert.ToUInt16(cmdArgs[2]); } for (var i = 0; i < len; i++) { Console.WriteLine($"[0x{addr + i:X2}]: {mem[addr + i]:X2}"); } break; } default: Console.WriteLine($"Unrecognized command: {cmdArgs[0]}"); break; } } }
public ExecutionHistoryPage() { m_disassembler = new Z80Disassembler(); InitializeComponent(); }