Debugger: Trace Logger improvements (Last 30k instructions visible, performance fixes, options are saved)

This commit is contained in:
Souryo 2017-03-04 15:18:00 -05:00
parent 4f6776f30b
commit 312a07bbdd
20 changed files with 814 additions and 333 deletions

View File

@ -5,6 +5,7 @@
#include "Snapshotable.h"
#include "TraceLogger.h"
#include "EmulationSettings.h"
#include "CpuState.h"
namespace PSFlags
{
@ -24,9 +25,9 @@ namespace PSFlags
enum AddrMode
{
None, Acc, Imp, Imm, Rel,
Zero, ZeroX, ZeroY,
Zero, Abs, ZeroX, ZeroY,
Ind, IndX, IndY, IndYW,
Abs, AbsX, AbsXW, AbsY, AbsYW
AbsX, AbsXW, AbsY, AbsYW
};
enum class IRQSource
@ -37,22 +38,6 @@ enum class IRQSource
FdsDisk = 8,
};
struct State
{
uint16_t PC = 0;
uint8_t SP = 0;
uint8_t A = 0;
uint8_t X = 0;
uint8_t Y = 0;
uint8_t PS = 0;
uint32_t IRQFlag = 0;
int32_t CycleCount = 0;
bool NMIFlag = false;
//Used by debugger
uint16_t DebugPC = 0;
};
class CPU : public Snapshotable
{
public:

View File

@ -321,7 +321,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<SDLCheck>false</SDLCheck>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<OmitFramePointers>true</OmitFramePointers>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
@ -333,6 +333,11 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<ShowIncludes>
</ShowIncludes>
<BufferSecurityCheck>
</BufferSecurityCheck>
<ControlFlowGuard>false</ControlFlowGuard>
<RuntimeTypeInfo>
</RuntimeTypeInfo>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -435,6 +440,7 @@
<ClInclude Include="Caltron41.h" />
<ClInclude Include="Cc21.h" />
<ClInclude Include="ColorDreams46.h" />
<ClInclude Include="CpuState.h" />
<ClInclude Include="CrossFeedFilter.h" />
<ClInclude Include="DaouInfosys.h" />
<ClInclude Include="DebugBreakHelper.h" />
@ -583,6 +589,7 @@
<ClInclude Include="OekaKids.h" />
<ClInclude Include="OekaKidsTablet.h" />
<ClInclude Include="PlayerListMessage.h" />
<ClInclude Include="PpuState.h" />
<ClInclude Include="Profiler.h" />
<ClInclude Include="Racermate.h" />
<ClInclude Include="ReverbFilter.h" />

View File

@ -1117,6 +1117,12 @@
<ClInclude Include="Eh8813A.h">
<Filter>Nes\Mappers\Unif</Filter>
</ClInclude>
<ClInclude Include="PpuState.h">
<Filter>Nes</Filter>
</ClInclude>
<ClInclude Include="CpuState.h">
<Filter>Nes</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">

18
Core/CpuState.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include "stdafx.h"
struct State
{
uint16_t PC = 0;
uint8_t SP = 0;
uint8_t A = 0;
uint8_t X = 0;
uint8_t Y = 0;
uint8_t PS = 0;
uint32_t IRQFlag = 0;
int32_t CycleCount = 0;
bool NMIFlag = false;
//Used by debugger
uint16_t DebugPC = 0;
};

View File

@ -33,6 +33,7 @@ Debugger::Debugger(shared_ptr<Console> console, shared_ptr<CPU> cpu, shared_ptr<
_memoryDumper.reset(new MemoryDumper(_ppu, _memoryManager, _mapper, _codeDataLogger, this));
_memoryAccessCounter.reset(new MemoryAccessCounter(this));
_profiler.reset(new Profiler(this));
_traceLogger.reset(new TraceLogger(memoryManager, _labelManager));
_stepOut = false;
_stepCount = -1;
@ -381,12 +382,8 @@ bool Debugger::PrivateProcessRamOperation(MemoryOperationType type, uint16_t &ad
breakDone = SleepUntilResume();
shared_ptr<TraceLogger> logger = _traceLogger;
if(logger) {
DebugState state;
GetState(&state);
logger->Log(state, _disassembler->GetDisassemblyInfo(absoluteAddr, absoluteRamAddr, addr));
}
GetState(&_debugState, false);
_traceLogger->Log(_debugState.CPU, _debugState.PPU, _disassembler->GetDisassemblyInfo(absoluteAddr, absoluteRamAddr, addr));
} else {
_profiler->ProcessCycle();
}
@ -623,17 +620,6 @@ void Debugger::SetNextStatement(uint16_t addr)
}
}
void Debugger::StartTraceLogger(TraceLoggerOptions options)
{
string traceFilepath = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), "Trace - " + FolderUtilities::GetFilename(_romName, false) + ".log");
_traceLogger.reset(new TraceLogger(traceFilepath, _memoryManager, options));
}
void Debugger::StopTraceLogger()
{
_traceLogger.reset();
}
void Debugger::ProcessPpuCycle()
{
if(Debugger::Instance) {
@ -682,6 +668,11 @@ void Debugger::GetFunctionEntryPoints(int32_t* entryPoints)
entryPoints[i] = -1;
}
shared_ptr<TraceLogger> Debugger::GetTraceLogger()
{
return _traceLogger;
}
shared_ptr<MemoryDumper> Debugger::GetMemoryDumper()
{
return _memoryDumper;

View File

@ -155,7 +155,7 @@ public:
void StopTraceLogger();
shared_ptr<Profiler> GetProfiler();
shared_ptr<TraceLogger> GetTraceLogger();
shared_ptr<MemoryDumper> GetMemoryDumper();
shared_ptr<MemoryAccessCounter> GetMemoryAccessCounter();

View File

@ -78,9 +78,9 @@ void Disassembler::BuildOpCodeTables(bool useLowerCase)
if(useLowerCase) {
string name = opName[i];
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
DisassemblyInfo::OPName[i] = name;
DisassemblyInfo::OPName[i] = name + " ";
} else {
DisassemblyInfo::OPName[i] = opName[i];
DisassemblyInfo::OPName[i] = opName[i] + " ";
}
DisassemblyInfo::OPMode[i] = opMode[i];
@ -341,8 +341,11 @@ string Disassembler::GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t memo
output += commentLines;
output += labelLine;
string effectiveAddress = showEffectiveAddresses ? info->GetEffectiveAddressString(cpuState, memoryManager, labelManager) : "";
output += GetLine(" " + info->ToString(memoryAddr, memoryManager, labelManager), commentString, memoryAddr, source != _internalRam ? addr : -1, info->GetByteCode(), effectiveAddress, speculativeCode);
char* effectiveAddress = info->GetEffectiveAddressString(cpuState, memoryManager.get(), labelManager.get());
if(!effectiveAddress) {
effectiveAddress = "";
}
output += GetLine(" " + string(info->ToString(memoryAddr, memoryManager.get(), labelManager.get())), commentString, memoryAddr, source != _internalRam ? addr : -1, info->GetByteCode(), effectiveAddress, speculativeCode);
if(info->IsSubExitPoint()) {
output += GetLine("__sub end__") + GetLine();

View File

@ -8,69 +8,112 @@ string DisassemblyInfo::OPName[256];
AddrMode DisassemblyInfo::OPMode[256];
uint32_t DisassemblyInfo::OPSize[256];
string DisassemblyInfo::ToString(uint32_t memoryAddr, shared_ptr<MemoryManager> memoryManager, shared_ptr<LabelManager> labelManager)
static const char* hexTable[256] = {
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F",
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F",
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F",
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF",
"B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
"C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
"E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
"F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"
};
char* DisassemblyInfo::ToString(uint32_t memoryAddr, MemoryManager* memoryManager, LabelManager* labelManager)
{
string out;
out.reserve(25);
uint16_t length;
return ToString(memoryAddr, memoryManager, labelManager, length);
}
char* DisassemblyInfo::ToString(uint32_t memoryAddr, MemoryManager* memoryManager, LabelManager* labelManager, uint16_t &length)
{
uint8_t opCode = *_opPointer;
if(DisassemblyInfo::OPName[opCode].empty()) {
out = "invalid opcode";
} else {
out = DisassemblyInfo::OPName[opCode];
}
memcpy(_toStringBuffer, DisassemblyInfo::OPName[opCode].c_str(), 4);
length = 4;
uint16_t* ptrPos = &length;
uint16_t opAddr = GetOpAddr(memoryAddr);
string operandValue;
if(labelManager && _opMode != AddrMode::Imm) {
operandValue = labelManager->GetLabel(opAddr, true);
}
if(operandValue.empty()) {
if(_opSize == 2 && _opMode != AddrMode::Rel) {
operandValue += "$" + HexUtilities::ToHex((uint8_t)opAddr);
} else {
operandValue += "$" + HexUtilities::ToHex((uint16_t)opAddr);
}
uint8_t operandLength = 0;
char operandBuffer[7];
char* opBuffer = operandBuffer;
operandBuffer[0] = '$';
if(_opSize == 2 && _opMode != AddrMode::Rel) {
memcpy(operandBuffer + 1, hexTable[opAddr], 2);
operandLength = 3;
} else {
memcpy(operandBuffer + 1, hexTable[opAddr >> 8], 2);
memcpy(operandBuffer + 3, hexTable[opAddr & 0xFF], 2);
operandLength = 5;
}
out += " ";
auto writeChar = [=](char c) -> void {
_toStringBuffer[(*ptrPos)++] = c;
};
auto copyOperand = [=]() -> void {
if(labelManager && _opMode != AddrMode::Imm) {
string label = labelManager->GetLabel(opAddr, true);
if(!label.empty()) {
memcpy(_toStringBuffer + (*ptrPos), label.c_str(), label.size());
(*ptrPos) += (uint16_t)label.size();
return;
}
}
memcpy(_toStringBuffer + (*ptrPos), opBuffer, operandLength);
(*ptrPos) += operandLength;
};
switch(_opMode) {
case AddrMode::Acc: out += "A"; break;
case AddrMode::Imm: out += "#" + operandValue; break;
case AddrMode::Ind: out += "(" + operandValue + ")"; break;
case AddrMode::IndX: out += "(" + operandValue + ",X)"; break;
case AddrMode::Acc: writeChar('A'); break;
case AddrMode::Imm: writeChar('#'); copyOperand(); break;
case AddrMode::Ind: writeChar('('); copyOperand(); writeChar(')'); break;
case AddrMode::IndX: writeChar('('); copyOperand(); memcpy(_toStringBuffer + length, ",X)", 3); length += 3; break;
case AddrMode::IndY:
case AddrMode::IndYW:
out += "(" + operandValue + "),Y";
writeChar('(');
copyOperand();
memcpy(_toStringBuffer + length, "),Y", 3);
length += 3;
break;
case AddrMode::Abs:
case AddrMode::Rel:
case AddrMode::Zero:
out += operandValue;
copyOperand();
break;
case AddrMode::AbsX:
case AddrMode::AbsXW:
case AddrMode::ZeroX:
out += operandValue + ",X";
copyOperand();
memcpy(_toStringBuffer + length, ",X", 2);
length += 2;
break;
case AddrMode::AbsY:
case AddrMode::AbsYW:
case AddrMode::ZeroY:
out += operandValue + ",Y";
copyOperand();
memcpy(_toStringBuffer + length, ",Y", 2);
length += 2;
break;
default: break;
}
return out;
_toStringBuffer[length] = 0;
return _toStringBuffer;
}
uint16_t DisassemblyInfo::GetOpAddr(uint16_t memoryAddr)
@ -105,32 +148,53 @@ void DisassemblyInfo::SetSubEntryPoint()
_isSubEntryPoint = true;
}
string DisassemblyInfo::GetEffectiveAddressString(State& cpuState, shared_ptr<MemoryManager> memoryManager, shared_ptr<LabelManager> labelManager)
char* DisassemblyInfo::GetEffectiveAddressString(State& cpuState, MemoryManager* memoryManager, LabelManager* labelManager)
{
int32_t effectiveAddress = GetEffectiveAddress(cpuState, memoryManager);
if(effectiveAddress < 0) {
return "";
uint16_t length;
return GetEffectiveAddressString(cpuState, memoryManager, labelManager, length);
}
char* DisassemblyInfo::GetEffectiveAddressString(State& cpuState, MemoryManager* memoryManager, LabelManager* labelManager, uint16_t& length)
{
if(_opMode <= AddrMode::Abs) {
length = 0;
return nullptr;
} else {
int32_t effectiveAddress = GetEffectiveAddress(cpuState, memoryManager);
_effectiveAddressBuffer[0] = ' ';
_effectiveAddressBuffer[1] = '@';
_effectiveAddressBuffer[2] = ' ';
if(labelManager) {
string label = labelManager->GetLabel(effectiveAddress, true);
if(!label.empty()) {
return " @ " + label;
memcpy(_effectiveAddressBuffer + 3, label.c_str(), label.size());
length = (uint16_t)label.size() + 3;
_effectiveAddressBuffer[length] = 0;
return _effectiveAddressBuffer;
}
}
string output;
output = " @ $";
_effectiveAddressBuffer[3] = '$';
if(_opMode == AddrMode::ZeroX || _opMode == AddrMode::ZeroY) {
output += HexUtilities::ToHex((uint8_t)effectiveAddress);
memcpy(_effectiveAddressBuffer + 4, hexTable[effectiveAddress], 2);
_effectiveAddressBuffer[6] = 0;
length = 6;
} else {
output += HexUtilities::ToHex((uint16_t)effectiveAddress);
memcpy(_effectiveAddressBuffer + 4, hexTable[effectiveAddress >> 8], 2);
memcpy(_effectiveAddressBuffer + 6, hexTable[effectiveAddress & 0xFF], 2);
_effectiveAddressBuffer[8] = 0;
length = 8;
}
return output;
return _effectiveAddressBuffer;
}
}
int32_t DisassemblyInfo::GetEffectiveAddress(State& cpuState, shared_ptr<MemoryManager> memoryManager)
int32_t DisassemblyInfo::GetEffectiveAddress(State& cpuState, MemoryManager* memoryManager)
{
switch(_opMode) {
case AddrMode::ZeroX: return (uint8_t)(*(_opPointer + 1) + cpuState.X); break;

View File

@ -20,15 +20,21 @@ private:
uint32_t _opSize = 0;
AddrMode _opMode;
char _toStringBuffer[1000];
char _effectiveAddressBuffer[1000];
public:
DisassemblyInfo(uint8_t* opPointer, bool isSubEntryPoint);
void SetSubEntryPoint();
int32_t GetEffectiveAddress(State& cpuState, shared_ptr<MemoryManager> memoryManager);
string GetEffectiveAddressString(State& cpuState, shared_ptr<MemoryManager> memoryManager, shared_ptr<LabelManager> labelManager);
int32_t GetEffectiveAddress(State& cpuState, MemoryManager* memoryManager);
char* GetEffectiveAddressString(State& cpuState, MemoryManager* memoryManager, LabelManager* labelManager);
char* GetEffectiveAddressString(State& cpuState, MemoryManager* memoryManager, LabelManager* labelManager, uint16_t &length);
string ToString(uint32_t memoryAddr, shared_ptr<MemoryManager> memoryManager, shared_ptr<LabelManager> labelManager);
char* ToString(uint32_t memoryAddr, MemoryManager* memoryManager, LabelManager* labelManager);
char* ToString(uint32_t memoryAddr, MemoryManager* memoryManager, LabelManager* labelManager, uint16_t &length);
string GetByteCode();
uint32_t GetSize();
uint16_t GetOpAddr(uint16_t memoryAddr);

View File

@ -24,6 +24,10 @@ void LabelManager::SetLabel(uint32_t address, AddressType addressType, string la
_codeLabels.erase(address);
if(!label.empty()) {
if(label.size() > 400) {
//Restrict labels to 400 bytes
label = label.substr(0, 400);
}
_codeLabels.emplace(address, label);
_codeLabelReverseLookup.emplace(label, address);
}

View File

@ -4,6 +4,7 @@
#include "Snapshotable.h"
#include "MemoryManager.h"
#include "EmulationSettings.h"
#include "PpuState.h"
enum class NesModel;
@ -20,75 +21,6 @@ enum PPURegisters
SpriteDMA = 0x4014,
};
struct PPUControlFlags
{
bool VerticalWrite;
uint16_t SpritePatternAddr;
uint16_t BackgroundPatternAddr;
bool LargeSprites;
bool VBlank;
bool Grayscale;
bool BackgroundMask;
bool SpriteMask;
bool BackgroundEnabled;
bool SpritesEnabled;
bool IntensifyRed;
bool IntensifyGreen;
bool IntensifyBlue;
};
struct PPUStatusFlags
{
bool SpriteOverflow;
bool Sprite0Hit;
bool VerticalBlank;
};
struct PPUState
{
uint8_t Control;
uint8_t Mask;
uint8_t Status;
uint32_t SpriteRamAddr;
uint16_t VideoRamAddr;
uint8_t XScroll;
uint16_t TmpVideoRamAddr;
bool WriteToggle;
uint16_t HighBitShift;
uint16_t LowBitShift;
};
struct TileInfo
{
uint8_t LowByte;
uint8_t HighByte;
uint32_t PaletteOffset;
uint16_t TileAddr; //used by HD ppu
uint8_t OffsetY; //used by HD ppu
};
struct SpriteInfo : TileInfo
{
bool HorizontalMirror;
bool BackgroundPriority;
uint8_t SpriteX;
bool VerticalMirror; //used by HD ppu
};
struct PPUDebugState
{
PPUControlFlags ControlFlags;
PPUStatusFlags StatusFlags;
PPUState State;
int32_t Scanline;
uint32_t Cycle;
uint32_t FrameCount;
};
class PPU : public IMemoryHandler, public Snapshotable
{
protected:

71
Core/PpuState.h Normal file
View File

@ -0,0 +1,71 @@
#pragma once
#include "stdafx.h"
struct PPUControlFlags
{
bool VerticalWrite;
uint16_t SpritePatternAddr;
uint16_t BackgroundPatternAddr;
bool LargeSprites;
bool VBlank;
bool Grayscale;
bool BackgroundMask;
bool SpriteMask;
bool BackgroundEnabled;
bool SpritesEnabled;
bool IntensifyRed;
bool IntensifyGreen;
bool IntensifyBlue;
};
struct PPUStatusFlags
{
bool SpriteOverflow;
bool Sprite0Hit;
bool VerticalBlank;
};
struct PPUState
{
uint8_t Control;
uint8_t Mask;
uint8_t Status;
uint32_t SpriteRamAddr;
uint16_t VideoRamAddr;
uint8_t XScroll;
uint16_t TmpVideoRamAddr;
bool WriteToggle;
uint16_t HighBitShift;
uint16_t LowBitShift;
};
struct TileInfo
{
uint8_t LowByte;
uint8_t HighByte;
uint32_t PaletteOffset;
uint16_t TileAddr; //used by HD ppu
uint8_t OffsetY; //used by HD ppu
};
struct SpriteInfo : TileInfo
{
bool HorizontalMirror;
bool BackgroundPriority;
uint8_t SpriteX;
bool VerticalMirror; //used by HD ppu
};
struct PPUDebugState
{
PPUControlFlags ControlFlags;
PPUStatusFlags StatusFlags;
PPUState State;
int32_t Scanline;
uint32_t Cycle;
uint32_t FrameCount;
};

View File

@ -4,38 +4,58 @@
#include "DebugState.h"
#include "Console.h"
#include "MemoryManager.h"
#include "LabelManager.h"
#include "../Utilities/HexUtilities.h"
#include "../Utilities/FolderUtilities.h"
TraceLogger *TraceLogger::_instance = nullptr;
TraceLogger::TraceLogger(string outputFilepath, shared_ptr<MemoryManager> memoryManager, TraceLoggerOptions options)
TraceLogger::TraceLogger(shared_ptr<MemoryManager> memoryManager, shared_ptr<LabelManager> labelManager)
{
_memoryManager = memoryManager;
_outputFile.open(outputFilepath, ios::out | ios::binary);
_options = options;
_firstLine = true;
_labelManager = labelManager;
_instance = this;
_currentPos = 0;
_logToFile = false;
}
TraceLogger::~TraceLogger()
{
Console::Pause();
if(_instance == this) {
_instance = nullptr;
}
if(_outputFile) {
if(!_outputBuffer.empty()) {
_outputFile << _outputBuffer;
}
_outputFile.close();
}
Console::Resume();
StopLogging();
_instance = nullptr;
}
void TraceLogger::SetOptions(TraceLoggerOptions options)
{
_options = options;
}
void TraceLogger::StartLogging(string filename)
{
_outputFile.open(filename, ios::out | ios::binary);
_logToFile = true;
_firstLine = true;
}
void TraceLogger::StopLogging()
{
if(_logToFile) {
Console::Pause();
if(_outputFile) {
if(!_outputBuffer.empty()) {
_outputFile << _outputBuffer;
}
_outputFile.close();
}
Console::Resume();
_logToFile = false;
}
}
void TraceLogger::LogStatic(string log)
{
if(_instance && _instance->_options.ShowExtraInfo) {
if(_instance && _instance->_logToFile && _instance->_options.ShowExtraInfo && !_instance->_firstLine) {
//Flush current buffer
_instance->_outputFile << _instance->_outputBuffer;
_instance->_outputBuffer.clear();
@ -44,75 +64,108 @@ void TraceLogger::LogStatic(string log)
}
}
void TraceLogger::Log(DebugState &state, shared_ptr<DisassemblyInfo> disassemblyInfo)
void TraceLogger::GetTraceRow(string &output, State &cpuState, PPUDebugState &ppuState, shared_ptr<DisassemblyInfo> &disassemblyInfo, bool firstLine)
{
//Roughly adjust PPU cycle & scanline to take into account the PPU already ran 3 cycles by the time we get here
short ppuCycle = (short)ppuState.Cycle - 3;
short scanline = (short)ppuState.Scanline;
if(ppuCycle < 0) {
ppuCycle = 341 + ppuCycle;
scanline--;
if(scanline < -1) {
scanline = EmulationSettings::GetNesModel() == NesModel::NTSC ? 260 : 310;
}
}
if(!firstLine) {
output += "\n";
}
output += HexUtilities::ToHex(cpuState.DebugPC) + " ";
if(_options.ShowByteCode) {
output += disassemblyInfo->GetByteCode() + std::string(13 - disassemblyInfo->GetByteCode().size(), ' ');
}
int indentLevel = 0;
if(_options.IndentCode) {
indentLevel = 0xFF - cpuState.SP;
output += std::string(indentLevel, ' ');
}
uint16_t disassemblyLength = 0;
uint16_t effectiveAddressLength = 0;
LabelManager* labelManager = _options.UseLabels ? _labelManager.get() : nullptr;
char* disassembly = disassemblyInfo->ToString(cpuState.DebugPC, _memoryManager.get(), labelManager, disassemblyLength);
char* effectiveAddress = (_options.ShowEffectiveAddresses ? disassemblyInfo->GetEffectiveAddressString(cpuState, _memoryManager.get(), labelManager, effectiveAddressLength) : nullptr);
output += disassembly;
if(effectiveAddress) {
output += effectiveAddress;
}
output += std::string(32 - disassemblyLength - effectiveAddressLength, ' ');
if(_options.ShowRegisters) {
output += " A:" + HexUtilities::ToHex(cpuState.A) +
" X:" + HexUtilities::ToHex(cpuState.X) +
" Y:" + HexUtilities::ToHex(cpuState.Y) +
" P:" + HexUtilities::ToHex(cpuState.PS) +
" SP:" + HexUtilities::ToHex(cpuState.SP);
}
if(_options.ShowPpuCycles) {
string str = std::to_string(ppuCycle);
output += " CYC:" + std::string(3 - str.size(), ' ') + str;
}
if(_options.ShowPpuScanline) {
string str = std::to_string(scanline);
output += " SL:" + std::string(3 - str.size(), ' ') + str;
}
if(_options.ShowPpuFrames) {
output += " FC:" + std::to_string(ppuState.FrameCount);
}
if(_options.ShowCpuCycles) {
output += " CPU Cycle:" + std::to_string(cpuState.CycleCount);
}
}
SimpleLock _lock;
void TraceLogger::Log(State &cpuState, PPUDebugState &ppuState, shared_ptr<DisassemblyInfo> disassemblyInfo)
{
if(disassemblyInfo) {
State &cpuState = state.CPU;
PPUDebugState &ppuState = state.PPU;
string disassembly = disassemblyInfo->ToString(cpuState.DebugPC, _memoryManager, nullptr);
//Roughly adjust PPU cycle & scanline to take into account the PPU already ran 3 cycles by the time we get here
short ppuCycle = (short)ppuState.Cycle - 3;
short scanline = (short)ppuState.Scanline;
if(ppuCycle < 0) {
ppuCycle = 341 + ppuCycle;
scanline--;
if(scanline < -1) {
scanline = EmulationSettings::GetNesModel() == NesModel::NTSC ? 260 : 310;
auto lock = _lock.AcquireSafe();
_disassemblyCache[_currentPos] = disassemblyInfo;
_cpuStateCache[_currentPos] = cpuState;
_ppuStateCache[_currentPos] = ppuState;
_currentPos = (_currentPos + 1) % ExecutionLogSize;
if(_logToFile) {
GetTraceRow(_outputBuffer, cpuState, ppuState, disassemblyInfo, _firstLine);
if(_outputBuffer.size() > 32768) {
_outputFile << _outputBuffer;
_outputBuffer.clear();
}
_firstLine = false;
}
if(!_firstLine) {
_outputBuffer += "\n";
}
_outputBuffer += HexUtilities::ToHex(cpuState.DebugPC) + " ";
if(_options.ShowByteCode) {
_outputBuffer += disassemblyInfo->GetByteCode() + std::string(13 - disassemblyInfo->GetByteCode().size(), ' ');
}
int indentLevel = 0;
if(_options.IndentCode) {
indentLevel = 0xFF - state.CPU.SP;
_outputBuffer += std::string(indentLevel, ' ');
}
string codeString = disassembly + (_options.ShowEffectiveAddresses ? disassemblyInfo->GetEffectiveAddressString(state.CPU, _memoryManager, nullptr) : "");
_outputBuffer += codeString + std::string(32 - codeString.size(), ' ');
if(_options.ShowRegisters) {
_outputBuffer += " A:" + HexUtilities::ToHex(cpuState.A) +
" X:" + HexUtilities::ToHex(cpuState.X) +
" Y:" + HexUtilities::ToHex(cpuState.Y) +
" P:" + HexUtilities::ToHex(cpuState.PS) +
" SP:" + HexUtilities::ToHex(cpuState.SP);
}
if(_options.ShowPpuCycles) {
string str = std::to_string(ppuCycle);
_outputBuffer += " CYC:" + std::string(3 - str.size(), ' ') + str;
}
if(_options.ShowPpuScanline) {
string str = std::to_string(scanline);
_outputBuffer += " SL:" + std::string(3 - str.size(), ' ') + str;
}
if(_options.ShowPpuFrames) {
_outputBuffer += " FC:" + std::to_string(ppuState.FrameCount);
}
if(_options.ShowCpuCycles) {
_outputBuffer += " CPU Cycle:" + std::to_string(cpuState.CycleCount);
}
if(_outputBuffer.size() > 32768) {
_outputFile << _outputBuffer;
_outputBuffer.clear();
}
_firstLine = false;
}
}
const char* TraceLogger::GetExecutionTrace(uint32_t lineCount)
{
_executionTrace.clear();
auto lock = _lock.AcquireSafe();
int startPos = _currentPos + ExecutionLogSize - lineCount;
bool firstLine = true;
for(int i = 0; i < (int)lineCount; i++) {
int index = (startPos + i) % ExecutionLogSize;
if(_disassemblyCache[index]) {
GetTraceRow(_executionTrace, _cpuStateCache[index], _ppuStateCache[index], _disassemblyCache[index], firstLine);
firstLine = false;
}
}
return _executionTrace.c_str();
}

View File

@ -1,9 +1,11 @@
#pragma once
#include "stdafx.h"
#include "CpuState.h"
#include "PpuState.h"
class DisassemblyInfo;
class MemoryManager;
struct DebugState;
class LabelManager;
struct TraceLoggerOptions
{
@ -16,6 +18,7 @@ struct TraceLoggerOptions
bool ShowExtraInfo;
bool IndentCode;
bool ShowEffectiveAddresses;
bool UseLabels;
};
class TraceLogger
@ -28,12 +31,30 @@ private:
ofstream _outputFile;
bool _firstLine;
shared_ptr<MemoryManager> _memoryManager;
shared_ptr<LabelManager> _labelManager;
constexpr static int ExecutionLogSize = 30000;
bool _logToFile;
uint16_t _currentPos;
State _cpuStateCache[ExecutionLogSize] = {};
PPUDebugState _ppuStateCache[ExecutionLogSize] = {};
int _memoryAddrCache[ExecutionLogSize] = {};
shared_ptr<DisassemblyInfo> _disassemblyCache[ExecutionLogSize] = {};
string _executionTrace;
public:
TraceLogger(string outputFilepath, shared_ptr<MemoryManager> memoryManager, TraceLoggerOptions options);
TraceLogger(shared_ptr<MemoryManager> memoryManager, shared_ptr<LabelManager> labelManager);
~TraceLogger();
void Log(DebugState &state, shared_ptr<DisassemblyInfo> disassemblyInfo);
void Log(State &cpuState, PPUDebugState &ppuState, shared_ptr<DisassemblyInfo> disassemblyInfo);
void SetOptions(TraceLoggerOptions options);
void StartLogging(string filename);
void StopLogging();
void GetTraceRow(string &output, State &cpuState, PPUDebugState &ppuState, shared_ptr<DisassemblyInfo> &disassemblyInfo, bool firstLine);
const char* GetExecutionTrace(uint32_t lineCount);
static void LogStatic(string log);
};

View File

@ -144,6 +144,19 @@ namespace Mesen.GUI.Config
public bool BreakOnOpen = true;
public bool BreakOnReset = true;
public bool TraceAutoRefresh = true;
public int TraceLineCount = 1000;
public bool TraceIndentCode = false;
public bool TraceShowByteCode = true;
public bool TraceShowCpuCycles = false;
public bool TraceShowEffectiveAddresses = true;
public bool TraceShowExtraInfo = true;
public bool TraceShowFrameCount = false;
public bool TraceShowPpuCycles = true;
public bool TraceShowPpuScanline = true;
public bool TraceShowRegisters = true;
internal bool TraceUseLabels;
public DebugInfo()
{
LeftView = new DebugViewInfo();

View File

@ -27,24 +27,43 @@
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.btnOpenTrace = new System.Windows.Forms.Button();
this.btnStartLogging = new System.Windows.Forms.Button();
this.btnStopLogging = new System.Windows.Forms.Button();
this.grpLogOptions = new System.Windows.Forms.GroupBox();
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
this.chkShowCpuCycles = new System.Windows.Forms.CheckBox();
this.chkShowEffectiveAddresses = new System.Windows.Forms.CheckBox();
this.chkShowPpuCycles = new System.Windows.Forms.CheckBox();
this.chkShowRegisters = new System.Windows.Forms.CheckBox();
this.chkShowPpuScanline = new System.Windows.Forms.CheckBox();
this.chkShowFrameCount = new System.Windows.Forms.CheckBox();
this.chkShowExtraInfo = new System.Windows.Forms.CheckBox();
this.chkShowByteCode = new System.Windows.Forms.CheckBox();
this.chkIndentCode = new System.Windows.Forms.CheckBox();
this.chkShowEffectiveAddresses = new System.Windows.Forms.CheckBox();
this.chkShowByteCode = new System.Windows.Forms.CheckBox();
this.chkShowFrameCount = new System.Windows.Forms.CheckBox();
this.chkShowPpuScanline = new System.Windows.Forms.CheckBox();
this.chkShowCpuCycles = new System.Windows.Forms.CheckBox();
this.chkUseLabels = new System.Windows.Forms.CheckBox();
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
this.grpExecutionLog = new System.Windows.Forms.GroupBox();
this.txtTraceLog = new System.Windows.Forms.TextBox();
this.tmrUpdateLog = new System.Windows.Forms.Timer(this.components);
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
this.showToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.logLinesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.mnu100Lines = new System.Windows.Forms.ToolStripMenuItem();
this.mnu1000Lines = new System.Windows.Forms.ToolStripMenuItem();
this.mnu10000Lines = new System.Windows.Forms.ToolStripMenuItem();
this.mnu30000Lines = new System.Windows.Forms.ToolStripMenuItem();
this.mnuAutoRefresh = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
this.mnuRefresh = new System.Windows.Forms.ToolStripMenuItem();
this.tableLayoutPanel1.SuspendLayout();
this.grpLogOptions.SuspendLayout();
this.tableLayoutPanel2.SuspendLayout();
this.tableLayoutPanel3.SuspendLayout();
this.grpExecutionLog.SuspendLayout();
this.menuStrip1.SuspendLayout();
this.SuspendLayout();
//
// tableLayoutPanel1
@ -57,23 +76,21 @@
this.tableLayoutPanel1.Controls.Add(this.btnStartLogging, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.btnStopLogging, 1, 0);
this.tableLayoutPanel1.Controls.Add(this.grpLogOptions, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.chkIndentCode, 0, 2);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 314);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 3;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(339, 193);
this.tableLayoutPanel1.Size = new System.Drawing.Size(442, 206);
this.tableLayoutPanel1.TabIndex = 0;
//
// btnOpenTrace
//
this.btnOpenTrace.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnOpenTrace.Enabled = false;
this.btnOpenTrace.Location = new System.Drawing.Point(241, 3);
this.btnOpenTrace.Location = new System.Drawing.Point(344, 3);
this.btnOpenTrace.Name = "btnOpenTrace";
this.btnOpenTrace.Size = new System.Drawing.Size(95, 23);
this.btnOpenTrace.TabIndex = 2;
@ -107,52 +124,55 @@
//
this.tableLayoutPanel1.SetColumnSpan(this.grpLogOptions, 3);
this.grpLogOptions.Controls.Add(this.tableLayoutPanel2);
this.grpLogOptions.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpLogOptions.Location = new System.Drawing.Point(3, 32);
this.grpLogOptions.Name = "grpLogOptions";
this.grpLogOptions.Size = new System.Drawing.Size(333, 132);
this.grpLogOptions.Size = new System.Drawing.Size(436, 168);
this.grpLogOptions.TabIndex = 3;
this.grpLogOptions.TabStop = false;
this.grpLogOptions.Text = "Log Contents";
this.grpLogOptions.Text = "Log Options";
//
// tableLayoutPanel2
//
this.tableLayoutPanel2.ColumnCount = 3;
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33332F));
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33334F));
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33334F));
this.tableLayoutPanel2.Controls.Add(this.chkShowEffectiveAddresses, 0, 3);
this.tableLayoutPanel2.Controls.Add(this.chkShowCpuCycles, 1, 0);
this.tableLayoutPanel2.Controls.Add(this.chkShowPpuCycles, 0, 1);
this.tableLayoutPanel2.Controls.Add(this.chkShowRegisters, 0, 0);
this.tableLayoutPanel2.Controls.Add(this.chkShowPpuScanline, 1, 1);
this.tableLayoutPanel2.Controls.Add(this.chkShowFrameCount, 2, 1);
this.tableLayoutPanel2.Controls.Add(this.chkShowExtraInfo, 0, 4);
this.tableLayoutPanel2.Controls.Add(this.chkIndentCode, 0, 6);
this.tableLayoutPanel2.Controls.Add(this.chkShowByteCode, 0, 2);
this.tableLayoutPanel2.Controls.Add(this.chkShowFrameCount, 2, 2);
this.tableLayoutPanel2.Controls.Add(this.chkShowPpuScanline, 2, 1);
this.tableLayoutPanel2.Controls.Add(this.chkShowCpuCycles, 2, 0);
this.tableLayoutPanel2.Controls.Add(this.chkUseLabels, 2, 6);
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 16);
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
this.tableLayoutPanel2.RowCount = 6;
this.tableLayoutPanel2.RowCount = 7;
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel2.Size = new System.Drawing.Size(327, 113);
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.Size = new System.Drawing.Size(430, 149);
this.tableLayoutPanel2.TabIndex = 0;
//
// chkShowCpuCycles
// chkShowEffectiveAddresses
//
this.chkShowCpuCycles.AutoSize = true;
this.chkShowCpuCycles.Checked = true;
this.chkShowCpuCycles.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkShowCpuCycles.Location = new System.Drawing.Point(111, 3);
this.chkShowCpuCycles.Name = "chkShowCpuCycles";
this.chkShowCpuCycles.Size = new System.Drawing.Size(82, 17);
this.chkShowCpuCycles.TabIndex = 3;
this.chkShowCpuCycles.Text = "CPU Cycles";
this.chkShowCpuCycles.UseVisualStyleBackColor = true;
this.chkShowEffectiveAddresses.AutoSize = true;
this.chkShowEffectiveAddresses.Checked = true;
this.chkShowEffectiveAddresses.CheckState = System.Windows.Forms.CheckState.Checked;
this.tableLayoutPanel2.SetColumnSpan(this.chkShowEffectiveAddresses, 2);
this.chkShowEffectiveAddresses.Location = new System.Drawing.Point(3, 72);
this.chkShowEffectiveAddresses.Name = "chkShowEffectiveAddresses";
this.chkShowEffectiveAddresses.Size = new System.Drawing.Size(150, 17);
this.chkShowEffectiveAddresses.TabIndex = 10;
this.chkShowEffectiveAddresses.Text = "Show Effective Addresses";
this.chkShowEffectiveAddresses.UseVisualStyleBackColor = true;
//
// chkShowPpuCycles
//
@ -178,28 +198,6 @@
this.chkShowRegisters.Text = "Registers";
this.chkShowRegisters.UseVisualStyleBackColor = true;
//
// chkShowPpuScanline
//
this.chkShowPpuScanline.AutoSize = true;
this.chkShowPpuScanline.Checked = true;
this.chkShowPpuScanline.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkShowPpuScanline.Location = new System.Drawing.Point(111, 26);
this.chkShowPpuScanline.Name = "chkShowPpuScanline";
this.chkShowPpuScanline.Size = new System.Drawing.Size(92, 17);
this.chkShowPpuScanline.TabIndex = 6;
this.chkShowPpuScanline.Text = "PPU Scanline";
this.chkShowPpuScanline.UseVisualStyleBackColor = true;
//
// chkShowFrameCount
//
this.chkShowFrameCount.AutoSize = true;
this.chkShowFrameCount.Location = new System.Drawing.Point(220, 26);
this.chkShowFrameCount.Name = "chkShowFrameCount";
this.chkShowFrameCount.Size = new System.Drawing.Size(86, 17);
this.chkShowFrameCount.TabIndex = 7;
this.chkShowFrameCount.Text = "Frame Count";
this.chkShowFrameCount.UseVisualStyleBackColor = true;
//
// chkShowExtraInfo
//
this.chkShowExtraInfo.AutoSize = true;
@ -213,6 +211,17 @@
this.chkShowExtraInfo.Text = "Additional information (IRQ, NMI, etc.)";
this.chkShowExtraInfo.UseVisualStyleBackColor = true;
//
// chkIndentCode
//
this.chkIndentCode.AutoSize = true;
this.tableLayoutPanel2.SetColumnSpan(this.chkIndentCode, 2);
this.chkIndentCode.Location = new System.Drawing.Point(3, 129);
this.chkIndentCode.Name = "chkIndentCode";
this.chkIndentCode.Size = new System.Drawing.Size(194, 17);
this.chkIndentCode.TabIndex = 8;
this.chkIndentCode.Text = "Indent code based on stack pointer";
this.chkIndentCode.UseVisualStyleBackColor = true;
//
// chkShowByteCode
//
this.chkShowByteCode.AutoSize = true;
@ -225,48 +234,201 @@
this.chkShowByteCode.Text = "Byte Code";
this.chkShowByteCode.UseVisualStyleBackColor = true;
//
// chkIndentCode
// chkShowFrameCount
//
this.chkIndentCode.AutoSize = true;
this.tableLayoutPanel1.SetColumnSpan(this.chkIndentCode, 3);
this.chkIndentCode.Location = new System.Drawing.Point(3, 170);
this.chkIndentCode.Name = "chkIndentCode";
this.chkIndentCode.Size = new System.Drawing.Size(194, 17);
this.chkIndentCode.TabIndex = 8;
this.chkIndentCode.Text = "Indent code based on stack pointer";
this.chkIndentCode.UseVisualStyleBackColor = true;
this.chkShowFrameCount.AutoSize = true;
this.chkShowFrameCount.Location = new System.Drawing.Point(289, 49);
this.chkShowFrameCount.Name = "chkShowFrameCount";
this.chkShowFrameCount.Size = new System.Drawing.Size(86, 17);
this.chkShowFrameCount.TabIndex = 7;
this.chkShowFrameCount.Text = "Frame Count";
this.chkShowFrameCount.UseVisualStyleBackColor = true;
//
// chkShowEffectiveAddresses
// chkShowPpuScanline
//
this.chkShowEffectiveAddresses.AutoSize = true;
this.chkShowEffectiveAddresses.Checked = true;
this.chkShowEffectiveAddresses.CheckState = System.Windows.Forms.CheckState.Checked;
this.tableLayoutPanel2.SetColumnSpan(this.chkShowEffectiveAddresses, 2);
this.chkShowEffectiveAddresses.Location = new System.Drawing.Point(3, 72);
this.chkShowEffectiveAddresses.Name = "chkShowEffectiveAddresses";
this.chkShowEffectiveAddresses.Size = new System.Drawing.Size(150, 17);
this.chkShowEffectiveAddresses.TabIndex = 10;
this.chkShowEffectiveAddresses.Text = "Show Effective Addresses";
this.chkShowEffectiveAddresses.UseVisualStyleBackColor = true;
this.chkShowPpuScanline.AutoSize = true;
this.chkShowPpuScanline.Checked = true;
this.chkShowPpuScanline.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkShowPpuScanline.Location = new System.Drawing.Point(289, 26);
this.chkShowPpuScanline.Name = "chkShowPpuScanline";
this.chkShowPpuScanline.Size = new System.Drawing.Size(92, 17);
this.chkShowPpuScanline.TabIndex = 6;
this.chkShowPpuScanline.Text = "PPU Scanline";
this.chkShowPpuScanline.UseVisualStyleBackColor = true;
//
// chkShowCpuCycles
//
this.chkShowCpuCycles.AutoSize = true;
this.chkShowCpuCycles.Checked = true;
this.chkShowCpuCycles.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkShowCpuCycles.Location = new System.Drawing.Point(289, 3);
this.chkShowCpuCycles.Name = "chkShowCpuCycles";
this.chkShowCpuCycles.Size = new System.Drawing.Size(82, 17);
this.chkShowCpuCycles.TabIndex = 3;
this.chkShowCpuCycles.Text = "CPU Cycles";
this.chkShowCpuCycles.UseVisualStyleBackColor = true;
//
// chkUseLabels
//
this.chkUseLabels.AutoSize = true;
this.chkUseLabels.Location = new System.Drawing.Point(289, 129);
this.chkUseLabels.Name = "chkUseLabels";
this.chkUseLabels.Size = new System.Drawing.Size(79, 17);
this.chkUseLabels.TabIndex = 11;
this.chkUseLabels.Text = "Use Labels";
this.chkUseLabels.UseVisualStyleBackColor = true;
//
// tableLayoutPanel3
//
this.tableLayoutPanel3.ColumnCount = 2;
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel3.Controls.Add(this.tableLayoutPanel1, 0, 1);
this.tableLayoutPanel3.Controls.Add(this.grpExecutionLog, 0, 0);
this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel3.Location = new System.Drawing.Point(0, 24);
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
this.tableLayoutPanel3.RowCount = 2;
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel3.Size = new System.Drawing.Size(808, 523);
this.tableLayoutPanel3.TabIndex = 1;
//
// grpExecutionLog
//
this.tableLayoutPanel3.SetColumnSpan(this.grpExecutionLog, 2);
this.grpExecutionLog.Controls.Add(this.txtTraceLog);
this.grpExecutionLog.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpExecutionLog.Location = new System.Drawing.Point(3, 3);
this.grpExecutionLog.Name = "grpExecutionLog";
this.grpExecutionLog.Size = new System.Drawing.Size(802, 305);
this.grpExecutionLog.TabIndex = 2;
this.grpExecutionLog.TabStop = false;
this.grpExecutionLog.Text = "Execution Log";
//
// txtTraceLog
//
this.txtTraceLog.BackColor = System.Drawing.SystemColors.Window;
this.txtTraceLog.Dock = System.Windows.Forms.DockStyle.Fill;
this.txtTraceLog.Location = new System.Drawing.Point(3, 16);
this.txtTraceLog.Multiline = true;
this.txtTraceLog.Name = "txtTraceLog";
this.txtTraceLog.ReadOnly = true;
this.txtTraceLog.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.txtTraceLog.Size = new System.Drawing.Size(796, 286);
this.txtTraceLog.TabIndex = 1;
//
// tmrUpdateLog
//
this.tmrUpdateLog.Interval = 150;
this.tmrUpdateLog.Tick += new System.EventHandler(this.tmrUpdateLog_Tick);
//
// menuStrip1
//
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.showToolStripMenuItem});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Size = new System.Drawing.Size(808, 24);
this.menuStrip1.TabIndex = 2;
this.menuStrip1.Text = "menuStrip1";
//
// showToolStripMenuItem
//
this.showToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.logLinesToolStripMenuItem,
this.mnuAutoRefresh,
this.toolStripMenuItem1,
this.mnuRefresh});
this.showToolStripMenuItem.Name = "showToolStripMenuItem";
this.showToolStripMenuItem.Size = new System.Drawing.Size(44, 20);
this.showToolStripMenuItem.Text = "View";
//
// logLinesToolStripMenuItem
//
this.logLinesToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnu100Lines,
this.mnu1000Lines,
this.mnu10000Lines,
this.mnu30000Lines});
this.logLinesToolStripMenuItem.Name = "logLinesToolStripMenuItem";
this.logLinesToolStripMenuItem.Size = new System.Drawing.Size(141, 22);
this.logLinesToolStripMenuItem.Text = "Line Count";
//
// mnu100Lines
//
this.mnu100Lines.Name = "mnu100Lines";
this.mnu100Lines.Size = new System.Drawing.Size(104, 22);
this.mnu100Lines.Text = "100";
this.mnu100Lines.Click += new System.EventHandler(this.mnu100Lines_Click);
//
// mnu1000Lines
//
this.mnu1000Lines.Checked = true;
this.mnu1000Lines.CheckState = System.Windows.Forms.CheckState.Checked;
this.mnu1000Lines.Name = "mnu1000Lines";
this.mnu1000Lines.Size = new System.Drawing.Size(104, 22);
this.mnu1000Lines.Text = "1000";
this.mnu1000Lines.Click += new System.EventHandler(this.mnu1000Lines_Click);
//
// mnu10000Lines
//
this.mnu10000Lines.Name = "mnu10000Lines";
this.mnu10000Lines.Size = new System.Drawing.Size(104, 22);
this.mnu10000Lines.Text = "10000";
this.mnu10000Lines.Click += new System.EventHandler(this.mnu10000Lines_Click);
//
// mnu30000Lines
//
this.mnu30000Lines.Name = "mnu30000Lines";
this.mnu30000Lines.Size = new System.Drawing.Size(104, 22);
this.mnu30000Lines.Text = "30000";
this.mnu30000Lines.Click += new System.EventHandler(this.mnu30000Lines_Click);
//
// mnuAutoRefresh
//
this.mnuAutoRefresh.Checked = true;
this.mnuAutoRefresh.CheckOnClick = true;
this.mnuAutoRefresh.CheckState = System.Windows.Forms.CheckState.Checked;
this.mnuAutoRefresh.Name = "mnuAutoRefresh";
this.mnuAutoRefresh.Size = new System.Drawing.Size(141, 22);
this.mnuAutoRefresh.Text = "Auto-refresh";
//
// toolStripMenuItem1
//
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(138, 6);
//
// mnuRefresh
//
this.mnuRefresh.Name = "mnuRefresh";
this.mnuRefresh.ShortcutKeys = System.Windows.Forms.Keys.F5;
this.mnuRefresh.Size = new System.Drawing.Size(141, 22);
this.mnuRefresh.Text = "Refresh";
this.mnuRefresh.Click += new System.EventHandler(this.mnuRefresh_Click);
//
// frmTraceLogger
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(339, 193);
this.Controls.Add(this.tableLayoutPanel1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.ClientSize = new System.Drawing.Size(808, 547);
this.Controls.Add(this.tableLayoutPanel3);
this.Controls.Add(this.menuStrip1);
this.Name = "frmTraceLogger";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Trace Logger";
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
this.grpLogOptions.ResumeLayout(false);
this.tableLayoutPanel2.ResumeLayout(false);
this.tableLayoutPanel2.PerformLayout();
this.tableLayoutPanel3.ResumeLayout(false);
this.grpExecutionLog.ResumeLayout(false);
this.grpExecutionLog.PerformLayout();
this.menuStrip1.ResumeLayout(false);
this.menuStrip1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
@ -287,5 +449,20 @@
private System.Windows.Forms.CheckBox chkIndentCode;
private System.Windows.Forms.Button btnOpenTrace;
private System.Windows.Forms.CheckBox chkShowEffectiveAddresses;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
private System.Windows.Forms.TextBox txtTraceLog;
private System.Windows.Forms.Timer tmrUpdateLog;
private System.Windows.Forms.GroupBox grpExecutionLog;
private System.Windows.Forms.MenuStrip menuStrip1;
private System.Windows.Forms.ToolStripMenuItem showToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem logLinesToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem mnuAutoRefresh;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1;
private System.Windows.Forms.ToolStripMenuItem mnuRefresh;
private System.Windows.Forms.ToolStripMenuItem mnu100Lines;
private System.Windows.Forms.ToolStripMenuItem mnu1000Lines;
private System.Windows.Forms.ToolStripMenuItem mnu10000Lines;
private System.Windows.Forms.ToolStripMenuItem mnu30000Lines;
private System.Windows.Forms.CheckBox chkUseLabels;
}
}

View File

@ -9,29 +9,65 @@ using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Mesen.GUI.Config;
using Mesen.GUI.Controls;
using Mesen.GUI.Forms;
namespace Mesen.GUI.Debugger
{
public partial class frmTraceLogger : BaseForm
{
private int _lineCount;
private bool _loggingEnabled = false;
private string _lastFilename;
public frmTraceLogger()
{
InitializeComponent();
DebugInfo debugInfo = ConfigManager.Config.DebugInfo;
mnuAutoRefresh.Checked = debugInfo.TraceAutoRefresh;
_lineCount = debugInfo.TraceLineCount;
chkIndentCode.Checked = debugInfo.TraceIndentCode;
chkShowByteCode.Checked = debugInfo.TraceShowByteCode;
chkShowCpuCycles.Checked = debugInfo.TraceShowCpuCycles;
chkShowEffectiveAddresses.Checked = debugInfo.TraceShowEffectiveAddresses;
chkShowExtraInfo.Checked = debugInfo.TraceShowExtraInfo;
chkShowFrameCount.Checked = debugInfo.TraceShowFrameCount;
chkShowPpuCycles.Checked = debugInfo.TraceShowPpuCycles;
chkShowPpuScanline.Checked = debugInfo.TraceShowPpuScanline;
chkShowRegisters.Checked = debugInfo.TraceShowRegisters;
chkUseLabels.Checked = debugInfo.TraceUseLabels;
UpdateMenu();
txtTraceLog.Font = new Font(BaseControl.MonospaceFontFamily, 10);
tmrUpdateLog.Start();
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
DebugInfo debugInfo = ConfigManager.Config.DebugInfo;
debugInfo.TraceAutoRefresh = mnuAutoRefresh.Checked;
debugInfo.TraceLineCount = _lineCount;
debugInfo.TraceIndentCode = chkIndentCode.Checked;
debugInfo.TraceShowByteCode = chkShowByteCode.Checked;
debugInfo.TraceShowCpuCycles = chkShowCpuCycles.Checked;
debugInfo.TraceShowEffectiveAddresses = chkShowEffectiveAddresses.Checked;
debugInfo.TraceShowExtraInfo = chkShowExtraInfo.Checked;
debugInfo.TraceShowFrameCount = chkShowFrameCount.Checked;
debugInfo.TraceShowPpuCycles = chkShowPpuCycles.Checked;
debugInfo.TraceShowPpuScanline = chkShowPpuScanline.Checked;
debugInfo.TraceShowRegisters = chkShowRegisters.Checked;
debugInfo.TraceUseLabels = chkUseLabels.Checked;
ConfigManager.ApplyChanges();
if(_loggingEnabled) {
InteropEmu.DebugStopTraceLogger();
}
}
private void btnStartLogging_Click(object sender, EventArgs e)
private void SetOptions()
{
TraceLoggerOptions options = new TraceLoggerOptions() {
ShowByteCode = chkShowByteCode.Checked,
@ -42,16 +78,31 @@ namespace Mesen.GUI.Debugger
ShowPpuScanline = chkShowPpuScanline.Checked,
ShowRegisters = chkShowRegisters.Checked,
IndentCode = chkIndentCode.Checked,
ShowEffectiveAddresses = chkShowEffectiveAddresses.Checked
ShowEffectiveAddresses = chkShowEffectiveAddresses.Checked,
UseLabels = chkUseLabels.Checked
};
InteropEmu.DebugStartTraceLogger(options);
InteropEmu.DebugSetTraceOptions(options);
}
btnStartLogging.Enabled = false;
btnStopLogging.Enabled = true;
btnOpenTrace.Enabled = true;
private void btnStartLogging_Click(object sender, EventArgs e)
{
using(SaveFileDialog sfd = new SaveFileDialog()) {
sfd.FileName = "Trace logs (*.txt)|*.txt";
sfd.FileName = "Trace - " + InteropEmu.GetRomInfo().GetRomName() + ".txt";
sfd.InitialDirectory = ConfigManager.DebuggerFolder;
if(sfd.ShowDialog() == DialogResult.OK) {
_lastFilename = sfd.FileName;
SetOptions();
InteropEmu.DebugStartTraceLogger(sfd.FileName);
_loggingEnabled = true;
btnStartLogging.Enabled = false;
btnStopLogging.Enabled = true;
btnOpenTrace.Enabled = false;
_loggingEnabled = true;
}
}
}
private void btnStopLogging_Click(object sender, EventArgs e)
@ -59,13 +110,80 @@ namespace Mesen.GUI.Debugger
InteropEmu.DebugStopTraceLogger();
btnStartLogging.Enabled = true;
btnStopLogging.Enabled = false;
btnOpenTrace.Enabled = true;
}
private void btnOpenTrace_Click(object sender, EventArgs e)
{
try {
System.Diagnostics.Process.Start(Path.Combine(ConfigManager.DebuggerFolder, "Trace - " + InteropEmu.GetRomInfo().GetRomName() + ".log"));
System.Diagnostics.Process.Start(_lastFilename);
} catch { }
}
private void RefreshLog()
{
SetOptions();
string newTrace = InteropEmu.DebugGetExecutionTrace((UInt32)_lineCount).Replace("\n", Environment.NewLine);
if(newTrace != txtTraceLog.Text) {
txtTraceLog.Text = newTrace;
txtTraceLog.SelectionStart = txtTraceLog.TextLength;
txtTraceLog.ScrollToCaret();
}
}
private void UpdateMenu()
{
mnu30000Lines.Checked = _lineCount == 30000;
mnu10000Lines.Checked = _lineCount == 10000;
mnu1000Lines.Checked = _lineCount == 1000;
mnu100Lines.Checked = _lineCount == 100;
if(_lineCount >= 10000) {
mnuAutoRefresh.Checked = false;
} else if(_lineCount == 1000) {
tmrUpdateLog.Interval = 250;
} else {
tmrUpdateLog.Interval = 150;
}
mnuAutoRefresh.Enabled = _lineCount < 10000;
}
private void tmrUpdateLog_Tick(object sender, EventArgs e)
{
if(mnuAutoRefresh.Checked) {
RefreshLog();
}
}
private void mnu30000Lines_Click(object sender, EventArgs e)
{
_lineCount = 30000;
UpdateMenu();
}
private void mnu10000Lines_Click(object sender, EventArgs e)
{
_lineCount = 10000;
UpdateMenu();
}
private void mnu1000Lines_Click(object sender, EventArgs e)
{
_lineCount = 1000;
UpdateMenu();
}
private void mnu100Lines_Click(object sender, EventArgs e)
{
_lineCount = 100;
UpdateMenu();
}
private void mnuRefresh_Click(object sender, EventArgs e)
{
RefreshLog();
}
}
}

View File

@ -120,4 +120,10 @@
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="tmrUpdateLog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>107, 17</value>
</metadata>
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>238, 17</value>
</metadata>
</root>

View File

@ -195,10 +195,13 @@ namespace Mesen.GUI
[DllImport(DLLPath)] public static extern void DebugSetNextStatement(UInt16 addr);
[DllImport(DLLPath)] public static extern Int32 DebugEvaluateExpression([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string expression, out EvalResultType resultType);
[DllImport(DLLPath)] public static extern void DebugStartTraceLogger(TraceLoggerOptions options);
[DllImport(DLLPath)] public static extern void DebugStopTraceLogger();
[DllImport(DLLPath)] public static extern void DebugStartTraceLogger([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filename);
[DllImport(DLLPath)] public static extern void DebugStopTraceLogger();
[DllImport(DLLPath)] public static extern void DebugSetTraceOptions(TraceLoggerOptions options);
[DllImport(DLLPath, EntryPoint = "DebugGetExecutionTrace")] private static extern IntPtr DebugGetExecutionTraceWrapper(UInt32 lineCount);
public static string DebugGetExecutionTrace(UInt32 lineCount) { return PtrToStringUtf8(InteropEmu.DebugGetExecutionTraceWrapper(lineCount)); }
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool DebugLoadCdlFile([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string cdlFilepath);
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool DebugSaveCdlFile([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string cdlFilepath);
[DllImport(DLLPath)] public static extern void DebugGetCdlRatios(ref CdlRatios ratios);
@ -806,6 +809,7 @@ namespace Mesen.GUI
[MarshalAs(UnmanagedType.I1)] public bool ShowExtraInfo;
[MarshalAs(UnmanagedType.I1)] public bool IndentCode;
[MarshalAs(UnmanagedType.I1)] public bool ShowEffectiveAddresses;
[MarshalAs(UnmanagedType.I1)] public bool UseLabels;
}
public enum ProfilerDataType

View File

@ -74,8 +74,10 @@ extern "C"
DllExport int32_t __stdcall DebugEvaluateExpression(char* expression, EvalResultType *resultType) { return GetDebugger()->EvaluateExpression(expression, *resultType); }
DllExport void __stdcall DebugStartTraceLogger(TraceLoggerOptions options) { GetDebugger()->StartTraceLogger(options); }
DllExport void __stdcall DebugStopTraceLogger() { GetDebugger()->StopTraceLogger(); }
DllExport void __stdcall DebugSetTraceOptions(TraceLoggerOptions options) { GetDebugger()->GetTraceLogger()->SetOptions(options); }
DllExport void __stdcall DebugStartTraceLogger(char* filename) { GetDebugger()->GetTraceLogger()->StartLogging(filename); }
DllExport void __stdcall DebugStopTraceLogger() { GetDebugger()->GetTraceLogger()->StopLogging(); }
DllExport const char* DebugGetExecutionTrace(uint32_t lineCount) { return GetDebugger()->GetTraceLogger()->GetExecutionTrace(lineCount); }
DllExport void __stdcall DebugSetMemoryValue(DebugMemoryType type, uint32_t address, uint8_t value) { return GetDebugger()->GetMemoryDumper()->SetMemoryValue(type, address, value); }
DllExport int32_t __stdcall DebugGetMemorySize(DebugMemoryType type) { return GetDebugger()->GetMemorySize(type); }