1 // 2 // Copyright (c) 2010-2024 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 8 using System.IO; 9 using System.Text; 10 using System.Collections.Generic; 11 using Antmicro.Renode.Utilities; 12 using Antmicro.Renode.Logging; 13 using Antmicro.Renode.Peripherals.CPU.Disassembler; 14 15 namespace Antmicro.Renode.Peripherals.CPU 16 { 17 public class TraceTextWriter : TraceWriter 18 { 19 public static IReadOnlyList<TraceFormat> SupportedFormats = new List<TraceFormat> 20 { 21 TraceFormat.PC, 22 TraceFormat.Opcode, 23 TraceFormat.PCAndOpcode, 24 TraceFormat.Disassembly 25 }.AsReadOnly(); 26 TraceTextWriter(TranslationCPU cpu, string path, TraceFormat format, bool compress)27 public TraceTextWriter(TranslationCPU cpu, string path, TraceFormat format, bool compress) 28 : base(cpu, path, format, compress) 29 { 30 disassemblyCache = new LRUCache<uint, Disassembler.DisassemblyResult>(CacheSize); 31 stringBuilder = new StringBuilder(); 32 textWriter = new StreamWriter(stream, Encoding.ASCII); 33 } 34 Write(ExecutionTracer.Block block)35 public override void Write(ExecutionTracer.Block block) 36 { 37 var pc = block.FirstInstructionPC; 38 var pcVirtual = block.FirstInstructionVirtualPC; 39 var counter = 0; 40 var hasAdditionalData = block.AdditionalDataInTheBlock.TryDequeue(out var nextAdditionalData); 41 42 while(counter < (int)block.InstructionsCount) 43 { 44 if(!TryReadAndDisassembleInstruction(pc, block.DisassemblyFlags, out var result)) 45 { 46 stringBuilder.AppendFormat("Couldn't disassemble opcode at PC 0x{0:X}\n", pc); 47 break; 48 } 49 else 50 { 51 switch(format) 52 { 53 case TraceFormat.PC: 54 stringBuilder.AppendFormat("0x{0:X}\n", result.PC); 55 break; 56 57 case TraceFormat.Opcode: 58 stringBuilder.AppendFormat("0x{0}\n", result.OpcodeString.ToUpper()); 59 break; 60 61 case TraceFormat.PCAndOpcode: 62 stringBuilder.AppendFormat("0x{0:X}: 0x{1}\n", result.PC, result.OpcodeString.ToUpper()); 63 break; 64 65 case TraceFormat.Disassembly: 66 var symbol = AttachedCPU.Bus.FindSymbolAt(pc, AttachedCPU); 67 var disassembly = result.ToString().Replace("\t", " "); 68 if(symbol != null) 69 { 70 stringBuilder.AppendFormat("{0, -60} [{1}]\n", disassembly, symbol); 71 } 72 else 73 { 74 stringBuilder.AppendFormat("{0}\n", disassembly); 75 } 76 break; 77 } 78 while(hasAdditionalData && (nextAdditionalData.PC == pcVirtual)) 79 { 80 stringBuilder.AppendFormat("{0}\n", nextAdditionalData.GetStringRepresentation()); 81 hasAdditionalData = block.AdditionalDataInTheBlock.TryDequeue(out nextAdditionalData); 82 } 83 pc += (ulong)result.OpcodeSize; 84 pcVirtual += (ulong)result.OpcodeSize; 85 counter++; 86 } 87 FlushIfNecessary(); 88 } 89 } 90 FlushBuffer()91 public override void FlushBuffer() 92 { 93 textWriter.Write(stringBuilder); 94 textWriter.Flush(); 95 stream.Flush(); 96 stringBuilder.Clear(); 97 } 98 Dispose(bool disposing)99 protected override void Dispose(bool disposing) 100 { 101 if(disposed) 102 { 103 return; 104 } 105 106 if(disposing) 107 { 108 FlushBuffer(); 109 textWriter?.Dispose(); 110 stream?.Dispose(); 111 } 112 disposed = true; 113 } 114 FlushIfNecessary()115 private void FlushIfNecessary() 116 { 117 if(stringBuilder.Length > BufferFlushLevel) 118 { 119 FlushBuffer(); 120 } 121 } 122 123 private bool disposed; 124 125 private readonly TextWriter textWriter; 126 private readonly StringBuilder stringBuilder; 127 128 private const int CacheSize = 100000; 129 private const int BufferFlushLevel = 1000000; 130 } 131 } 132