diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index 2e3b451a..7e2eb306 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -43,14 +43,19 @@
+
+
+
+
+
@@ -188,6 +193,11 @@
+
+
+
+
+
@@ -367,17 +377,18 @@
-
+
+
@@ -444,6 +455,11 @@
+
+
+
+
+
@@ -543,7 +559,6 @@
Create
-
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index e96252cc..87ac85b8 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -10,9 +10,6 @@
SNES
-
- Debugger
-
Debugger
@@ -801,14 +798,21 @@
+
+
+
+
+
+
+
+
+
+
SNES
-
- Debugger
-
Debugger
@@ -1238,6 +1242,13 @@
+
+
+
+
+
+
+
diff --git a/Core/Debugger/BaseTraceLogger.h b/Core/Debugger/BaseTraceLogger.h
new file mode 100644
index 00000000..d8eeefb3
--- /dev/null
+++ b/Core/Debugger/BaseTraceLogger.h
@@ -0,0 +1,517 @@
+#pragma once
+#include "stdafx.h"
+#include
+#include "Utilities/SimpleLock.h"
+#include "Debugger/DisassemblyInfo.h"
+#include "Debugger/Debugger.h"
+#include "Debugger/DebugTypes.h"
+#include "Debugger/LabelManager.h"
+#include "Debugger/DebugTypes.h"
+#include "Debugger/DebugUtilities.h"
+#include "Debugger/DebugBreakHelper.h"
+#include "Debugger/ITraceLogger.h"
+#include "Debugger/ExpressionEvaluator.h"
+#include "Utilities/HexUtilities.h"
+#include "Shared/Emulator.h"
+#include "Shared/EmuSettings.h"
+
+class IConsole;
+class Debugger;
+class LabelManager;
+class MemoryDumper;
+class EmuSettings;
+
+enum class RowDataType
+{
+ Text = 0,
+ ByteCode,
+ Disassembly,
+ EffectiveAddress,
+ MemoryValue,
+ Align,
+ PC,
+ A,
+ B,
+ C,
+ D,
+ E,
+ F,
+ H,
+ K,
+ L,
+ M,
+ N,
+ X,
+ Y,
+ DB,
+ SP,
+ PS,
+ Cycle,
+ Scanline,
+ HClock,
+ FrameCount,
+ CycleCount,
+
+ R0,
+ R1,
+ R2,
+ R3,
+ R4,
+ R5,
+ R6,
+ R7,
+ R8,
+ R9,
+ R10,
+ R11,
+ R12,
+ R13,
+ R14,
+ R15,
+ Src,
+ Dst,
+
+ MAR,
+ MDR,
+ DPR,
+ ML,
+ MH,
+ PB,
+ P,
+
+ RP,
+ DP,
+ DR,
+ SR,
+ TR,
+ TRB,
+
+ FlagsA,
+ FlagsB
+};
+
+struct TraceLogPpuState
+{
+ uint32_t Cycle;
+ uint32_t HClock;
+ int32_t Scanline;
+ uint32_t FrameCount;
+};
+
+struct RowPart
+{
+ RowDataType DataType;
+ string Text;
+ bool DisplayInHex;
+ int MinWidth;
+};
+
+template
+class BaseTraceLogger : public ITraceLogger
+{
+protected:
+ static constexpr int ExecutionLogSize = 30000;
+
+ TraceLoggerOptions _options;
+ IConsole* _console;
+ EmuSettings* _settings;
+ LabelManager* _labelManager;
+ MemoryDumper* _memoryDumper;
+ Debugger* _debugger;
+
+ CpuType _cpuType = CpuType::Cpu;
+ SnesMemoryType _cpuMemoryType = SnesMemoryType::CpuMemory;
+
+ vector _rowParts;
+
+ uint32_t _currentPos = 0;
+
+ bool _pendingLog = false;
+ CpuStateType _lastState = {};
+ DisassemblyInfo _lastDisassemblyInfo = {};
+
+ CpuStateType* _cpuState = nullptr;
+ DisassemblyInfo *_disassemblyCache = nullptr;
+ uint64_t* _rowIds = nullptr;
+ TraceLogPpuState* _ppuState = nullptr;
+
+ unique_ptr _expEvaluator;
+ ExpressionData _conditionData;
+
+ void WriteByteCode(DisassemblyInfo& info, RowPart& rowPart, string& output)
+ {
+ string byteCode;
+ info.GetByteCode(byteCode);
+ if(!rowPart.DisplayInHex) {
+ //Remove $ marks if not in "hex" mode (but still display the bytes as hex)
+ byteCode.erase(std::remove(byteCode.begin(), byteCode.end(), '$'), byteCode.end());
+ }
+ WriteStringValue(output, byteCode, rowPart);
+ }
+
+ void WriteDisassembly(DisassemblyInfo& info, RowPart& rowPart, uint8_t sp, uint32_t pc, string& output)
+ {
+ int indentLevel = 0;
+ string code;
+
+ if(_options.IndentCode) {
+ indentLevel = 0xFF - (sp & 0xFF);
+ code = std::string(indentLevel, ' ');
+ }
+
+ LabelManager* labelManager = _options.UseLabels ? _labelManager : nullptr;
+ info.GetDisassembly(code, pc, labelManager, _settings);
+ WriteStringValue(output, code, rowPart);
+ }
+
+ void WriteEffectiveAddress(DisassemblyInfo& info, RowPart& rowPart, void* cpuState, string& output, SnesMemoryType cpuMemoryType, CpuType cpuType)
+ {
+ int32_t effectiveAddress = info.GetEffectiveAddress(_debugger, cpuState, cpuType);
+ if(effectiveAddress >= 0) {
+ if(_options.UseLabels) {
+ AddressInfo addr { effectiveAddress, cpuMemoryType };
+ string label = _labelManager->GetLabel(addr);
+ if(!label.empty()) {
+ WriteStringValue(output, " [" + label + "]", rowPart);
+ return;
+ }
+ }
+ WriteStringValue(output, " [" + HexUtilities::ToHex24(effectiveAddress) + "]", rowPart);
+ }
+ }
+
+ void WriteMemoryValue(DisassemblyInfo& info, RowPart& rowPart, void* cpuState, string& output, SnesMemoryType memType, CpuType cpuType)
+ {
+ int32_t address = info.GetEffectiveAddress(_debugger, cpuState, cpuType);
+ if(address >= 0) {
+ uint8_t valueSize;
+ uint16_t value = info.GetMemoryValue(address, _memoryDumper, memType, valueSize);
+ if(rowPart.DisplayInHex) {
+ output += "= $";
+ if(valueSize == 2) {
+ WriteIntValue(output, (uint16_t)value, rowPart);
+ } else {
+ WriteIntValue(output, (uint8_t)value, rowPart);
+ }
+ } else {
+ output += "= ";
+ }
+ }
+ }
+
+ void GetStatusFlag(const char* activeStatusLetters, const char* inactiveStatusLetters, string& output, uint8_t ps, RowPart& part, int length = 8)
+ {
+ if(part.DisplayInHex) {
+ WriteIntValue(output, ps, part);
+ } else {
+ string flags;
+ for(int i = 0; i < length; i++) {
+ if(ps & 0x80) {
+ flags += activeStatusLetters[i];
+ } else if(part.MinWidth >= length) {
+ flags += inactiveStatusLetters[i];
+ }
+ ps <<= 1;
+ }
+ WriteStringValue(output, flags, part);
+ }
+ }
+
+ void WriteAlign(int originalSize, RowPart& rowPart, string& output)
+ {
+ if((int)output.size() - originalSize < rowPart.MinWidth) {
+ output += std::string(rowPart.MinWidth - (output.size() - originalSize), ' ');
+ }
+ }
+
+ void WriteIntValue(string& output, uint32_t value, RowPart& rowPart)
+ {
+ string str = rowPart.DisplayInHex ? HexUtilities::ToHex(value) : std::to_string(value);
+ if(rowPart.MinWidth > (int)str.size()) {
+ if(rowPart.DisplayInHex) {
+ str = std::string(rowPart.MinWidth - str.size(), '0') + str;
+ } else {
+ str += std::string(rowPart.MinWidth - str.size(), ' ');
+ }
+ }
+ output += str;
+ }
+
+ void WriteIntValue(string& output, int32_t value, RowPart& rowPart)
+ {
+ string str = rowPart.DisplayInHex ? HexUtilities::ToHex(value) : std::to_string(value);
+ output += str;
+ if(rowPart.MinWidth > (int)str.size()) {
+ output += std::string(rowPart.MinWidth - str.size(), ' ');
+ }
+ }
+
+ void WriteIntValue(string& output, uint16_t value, RowPart& rowPart)
+ {
+ string str = rowPart.DisplayInHex ? HexUtilities::ToHex(value) : std::to_string(value);
+ output += str;
+ if(rowPart.MinWidth > (int)str.size()) {
+ output += std::string(rowPart.MinWidth - str.size(), ' ');
+ }
+ }
+
+ void WriteIntValue(string& output, uint8_t value, RowPart& rowPart)
+ {
+ string str = rowPart.DisplayInHex ? HexUtilities::ToHex(value) : std::to_string(value);
+ output += str;
+ if(rowPart.MinWidth > (int)str.size()) {
+ output += std::string(rowPart.MinWidth - str.size(), ' ');
+ }
+ }
+
+ void WriteStringValue(string& output, string value, RowPart& rowPart)
+ {
+ output += value;
+ if(rowPart.MinWidth > (int)value.size()) {
+ output += std::string(rowPart.MinWidth - value.size(), ' ');
+ }
+ }
+
+ void AddRow(CpuStateType& cpuState, DisassemblyInfo& disassemblyInfo)
+ {
+ _disassemblyCache[_currentPos] = disassemblyInfo;
+ _cpuState[_currentPos] = cpuState;
+ ((TraceLoggerType*)this)->LogPpuState();
+
+ _rowIds[_currentPos] = ITraceLogger::NextRowId;
+ ITraceLogger::NextRowId++;
+
+ _pendingLog = false;
+
+ /*if(_logToFile) {
+ ((TraceLoggerType*)this)->GetTraceRow(_outputBuffer, _disassemblyCache[_currentPos], cpuState);
+ if(_outputBuffer.size() > 32768) {
+ _outputFile << _outputBuffer;
+ _outputBuffer.clear();
+ }
+ }*/
+
+ _currentPos = (_currentPos + 1) % ExecutionLogSize;
+ }
+
+ void ParseFormatString(string format)
+ {
+ _rowParts.clear();
+
+ std::regex formatRegex = std::regex("(\\[\\s*([^[]*?)\\s*(,\\s*([\\d]*)\\s*(h){0,1}){0,1}\\s*\\])|([^[]*)", std::regex_constants::icase);
+ std::sregex_iterator start = std::sregex_iterator(format.cbegin(), format.cend(), formatRegex);
+ std::sregex_iterator end = std::sregex_iterator();
+
+ for(std::sregex_iterator it = start; it != end; it++) {
+ const std::smatch& match = *it;
+
+ if(match.str(1) == "") {
+ RowPart part = {};
+ part.DataType = RowDataType::Text;
+ part.Text = match.str(6);
+ _rowParts.push_back(part);
+ } else {
+ RowPart part = {};
+
+ string tag = match.str(2);
+ part.DataType = InternalGetFormatTagType(tag);
+ if(part.DataType == RowDataType::Text) {
+ part.Text = "[Invalid tag]";
+ }
+
+ if(!match.str(4).empty()) {
+ try {
+ part.MinWidth = std::stoi(match.str(4));
+ } catch(std::exception&) {
+ }
+ }
+ part.DisplayInHex = match.str(5) == "h";
+
+ _rowParts.push_back(part);
+ }
+ }
+ }
+
+ RowDataType InternalGetFormatTagType(string& tag)
+ {
+ if(tag == "ByteCode") {
+ return RowDataType::ByteCode;
+ } else if(tag == "Disassembly") {
+ return RowDataType::Disassembly;
+ } else if(tag == "EffectiveAddress") {
+ return RowDataType::EffectiveAddress;
+ } else if(tag == "MemoryValue") {
+ return RowDataType::MemoryValue;
+ } else if(tag == "Align") {
+ return RowDataType::Align;
+ } else if(tag == "PC") {
+ return RowDataType::PC;
+ } else if(tag == "Cycle") {
+ return RowDataType::Cycle;
+ } else if(tag == "HClock") {
+ return RowDataType::HClock;
+ } else if(tag == "Scanline") {
+ return RowDataType::Scanline;
+ } else if(tag == "FrameCount") {
+ return RowDataType::FrameCount;
+ } else if(tag == "CycleCount") {
+ return RowDataType::CycleCount;
+ }
+
+ return GetFormatTagType(tag);
+ }
+
+ virtual RowDataType GetFormatTagType(string& tag) = 0;
+
+ void ProcessSharedTag(RowPart& rowPart, string& output, CpuStateType& cpuState, TraceLogPpuState& ppuState, DisassemblyInfo& disassemblyInfo)
+ {
+ switch(rowPart.DataType) {
+ case RowDataType::Text: output += rowPart.Text; break;
+ case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break;
+ case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, ((TraceLoggerType*)this)->GetStackPointer(cpuState), ((TraceLoggerType*)this)->GetProgramCounter(cpuState), output); break;
+ case RowDataType::EffectiveAddress: WriteEffectiveAddress(disassemblyInfo, rowPart, &cpuState, output, _cpuMemoryType, _cpuType); break;
+ case RowDataType::MemoryValue: WriteMemoryValue(disassemblyInfo, rowPart, &cpuState, output, _cpuMemoryType, _cpuType); break;
+ case RowDataType::Align: WriteAlign(0, rowPart, output); break;
+
+ case RowDataType::Cycle: WriteIntValue(output, ppuState.Cycle, rowPart); break;
+ case RowDataType::Scanline: WriteIntValue(output, ppuState.Scanline, rowPart); break;
+ case RowDataType::HClock: WriteIntValue(output, ppuState.HClock, rowPart); break;
+ case RowDataType::FrameCount: WriteIntValue(output, ppuState.FrameCount, rowPart); break;
+ case RowDataType::CycleCount:
+ WriteIntValue(output, (uint32_t)(((TraceLoggerType*)this)->GetCycleCount(cpuState) >> 32), rowPart);
+ WriteIntValue(output, (uint32_t)((TraceLoggerType*)this)->GetCycleCount(cpuState), rowPart);
+ break;
+
+ case RowDataType::PC: WriteStringValue(output, HexUtilities::ToHex(((TraceLoggerType*)this)->GetProgramCounter(cpuState)), rowPart); break;
+ }
+ }
+
+public:
+ BaseTraceLogger(Debugger* debugger, CpuType cpuType)
+ {
+ _debugger = debugger;
+ _console = debugger->GetConsole();
+ _settings = debugger->GetEmulator()->GetSettings();
+ _labelManager = debugger->GetLabelManager().get();
+ _memoryDumper = debugger->GetMemoryDumper();
+ _options = {};
+ _currentPos = 0;
+ _pendingLog = false;
+
+ _disassemblyCache = new DisassemblyInfo[BaseTraceLogger::ExecutionLogSize];
+ _rowIds = new uint64_t[BaseTraceLogger::ExecutionLogSize];
+ memset(_disassemblyCache, 0, sizeof(DisassemblyInfo) * BaseTraceLogger::ExecutionLogSize);
+ memset(_rowIds, 0, sizeof(uint64_t) * BaseTraceLogger::ExecutionLogSize);
+
+ _ppuState = new TraceLogPpuState[BaseTraceLogger::ExecutionLogSize];
+ memset(_ppuState, 0, sizeof(TraceLogPpuState) * BaseTraceLogger::ExecutionLogSize);
+
+ _cpuState = new CpuStateType[BaseTraceLogger::ExecutionLogSize];
+ memset(_cpuState, 0, sizeof(CpuStateType) * BaseTraceLogger::ExecutionLogSize);
+
+ _cpuType = cpuType;
+ _cpuMemoryType = DebugUtilities::GetCpuMemoryType(cpuType);
+
+ _expEvaluator.reset(new ExpressionEvaluator(debugger, cpuType));
+ }
+
+ virtual ~BaseTraceLogger()
+ {
+ delete[] _disassemblyCache;
+ delete[] _rowIds;
+ delete[] _ppuState;
+ delete[] _cpuState;
+ }
+
+ void Clear()
+ {
+ }
+
+ void LogNonExec(MemoryOperationInfo& operation)
+ {
+ if(_pendingLog) {
+ int pos = _currentPos - 1;
+ if(pos < 0) {
+ pos = BaseTraceLogger::ExecutionLogSize - 1;
+ }
+
+ if(ConditionMatches(_lastState, _lastDisassemblyInfo, operation)) {
+ AddRow(_lastState, _lastDisassemblyInfo);
+ _pendingLog = false;
+ }
+ }
+ }
+
+ void Log(CpuStateType& cpuState, DisassemblyInfo& disassemblyInfo, MemoryOperationInfo& operation)
+ {
+ if(_enabled) {
+ //For the sake of performance, only log data for the CPUs we're actively displaying/logging
+ if(ConditionMatches(cpuState, disassemblyInfo, operation)) {
+ AddRow(cpuState, disassemblyInfo);
+ } else {
+ _pendingLog = true;
+ _lastState = cpuState;
+ _lastDisassemblyInfo = disassemblyInfo;
+ }
+ }
+ }
+
+ void SetOptions(TraceLoggerOptions options) override
+ {
+ DebugBreakHelper helper(_debugger);
+ _options = options;
+
+ _enabled = options.Enabled;
+
+ string condition = _options.Condition;
+ string format = _options.Format;
+
+ _conditionData = ExpressionData();
+ if(!condition.empty()) {
+ bool success = false;
+ ExpressionData rpnList = _expEvaluator->GetRpnList(condition, success);
+ if(success) {
+ _conditionData = rpnList;
+ }
+ }
+
+ ParseFormatString(format);
+ }
+
+ int64_t GetRowId(uint32_t offset) override
+ {
+ int32_t pos = ((int32_t)_currentPos - (int32_t)offset);
+ int32_t i = (pos > 0 ? pos : BaseTraceLogger::ExecutionLogSize + pos) - 1;
+ if(!_disassemblyCache[i].IsInitialized()) {
+ return -1;
+ }
+ return _rowIds[i];
+ }
+
+ bool ConditionMatches(BaseState &state, DisassemblyInfo &disassemblyInfo, MemoryOperationInfo &operationInfo)
+ {
+ if(!_conditionData.RpnQueue.empty()) {
+ EvalResultType type;
+ if(!_expEvaluator->Evaluate(_conditionData, state, type, operationInfo)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void GetExecutionTrace(TraceRow& row, uint32_t offset) override
+ {
+ int pos = ((int)_currentPos - offset);
+ int index = (pos > 0 ? pos : BaseTraceLogger::ExecutionLogSize + pos) - 1;
+
+ CpuStateType& state = _cpuState[index];
+ string logOutput;
+ ((TraceLoggerType*)this)->GetTraceRow(logOutput, state, _ppuState[index], _disassemblyCache[index]);
+
+ row.Type = _cpuType;
+ _disassemblyCache[index].GetByteCode(row.ByteCode);
+ row.ByteCodeSize = _disassemblyCache[index].GetOpSize();
+ row.ProgramCounter = ((TraceLoggerType*)this)->GetProgramCounter(state);
+ memcpy(row.LogOutput, logOutput.c_str(), logOutput.size());
+ }
+};
diff --git a/Core/Debugger/CodeDataLogger.cpp b/Core/Debugger/CodeDataLogger.cpp
index 6ae1c4e2..c12f7c21 100644
--- a/Core/Debugger/CodeDataLogger.cpp
+++ b/Core/Debugger/CodeDataLogger.cpp
@@ -100,17 +100,15 @@ void CodeDataLogger::CalculateStats()
void CodeDataLogger::SetFlags(int32_t absoluteAddr, uint8_t flags)
{
- if(absoluteAddr >= 0 && absoluteAddr < (int32_t)_prgSize) {
- if((_cdlData[absoluteAddr] & flags) != flags) {
- if(flags & CdlFlags::Code) {
- _cdlData[absoluteAddr] = flags | (_cdlData[absoluteAddr] & ~(CdlFlags::Data | CdlFlags::IndexMode8 | CdlFlags::MemoryMode8));
- } else if(flags & CdlFlags::Data) {
- if(!IsCode(absoluteAddr)) {
- _cdlData[absoluteAddr] |= flags;
- }
- } else {
+ if((_cdlData[absoluteAddr] & flags) != flags) {
+ if(flags & CdlFlags::Code) {
+ _cdlData[absoluteAddr] = flags | (_cdlData[absoluteAddr] & ~(CdlFlags::Data | CdlFlags::IndexMode8 | CdlFlags::MemoryMode8));
+ } else if(flags & CdlFlags::Data) {
+ if(!IsCode(absoluteAddr)) {
_cdlData[absoluteAddr] |= flags;
}
+ } else {
+ _cdlData[absoluteAddr] |= flags;
}
}
}
diff --git a/Core/Debugger/DebugTypes.h b/Core/Debugger/DebugTypes.h
index fa766bd8..6ac4c436 100644
--- a/Core/Debugger/DebugTypes.h
+++ b/Core/Debugger/DebugTypes.h
@@ -263,7 +263,7 @@ struct StepRequest
int32_t StepCount = -1;
int32_t PpuStepCount = -1;
int32_t BreakAddress = -1;
- int32_t BreakScanline = -1;
+ int32_t BreakScanline = INT32_MIN;
};
enum class CpuType : uint8_t
diff --git a/Core/Debugger/DebugUtilities.h b/Core/Debugger/DebugUtilities.h
index 142f09e0..c332476f 100644
--- a/Core/Debugger/DebugUtilities.h
+++ b/Core/Debugger/DebugUtilities.h
@@ -6,7 +6,7 @@
class DebugUtilities
{
public:
- static SnesMemoryType GetCpuMemoryType(CpuType type)
+ static constexpr SnesMemoryType GetCpuMemoryType(CpuType type)
{
switch(type) {
case CpuType::Cpu: return SnesMemoryType::CpuMemory;
@@ -22,7 +22,7 @@ public:
throw std::runtime_error("Invalid CPU type");
}
- static CpuType ToCpuType(SnesMemoryType type)
+ static constexpr CpuType ToCpuType(SnesMemoryType type)
{
switch(type) {
case SnesMemoryType::SpcMemory:
@@ -81,7 +81,7 @@ public:
return SnesMemoryType::NesMemory;
}
- static bool IsPpuMemory(SnesMemoryType memType)
+ static constexpr bool IsPpuMemory(SnesMemoryType memType)
{
switch(memType) {
case SnesMemoryType::VideoRam:
@@ -102,7 +102,7 @@ public:
}
}
- static bool IsRomMemory(SnesMemoryType memType)
+ static constexpr bool IsRomMemory(SnesMemoryType memType)
{
switch(memType) {
case SnesMemoryType::PrgRom:
diff --git a/Core/Debugger/Debugger.cpp b/Core/Debugger/Debugger.cpp
index aa1e704f..8b78fe33 100644
--- a/Core/Debugger/Debugger.cpp
+++ b/Core/Debugger/Debugger.cpp
@@ -2,7 +2,6 @@
#include "Debugger/Debugger.h"
#include "Debugger/DebugTypes.h"
#include "Debugger/DisassemblyInfo.h"
-#include "Debugger/TraceLogger.h"
#include "Debugger/MemoryDumper.h"
#include "Debugger/MemoryAccessCounter.h"
#include "Debugger/CodeDataLogger.h"
@@ -46,6 +45,7 @@
#include "Shared/NotificationManager.h"
#include "Shared/BaseState.h"
#include "Shared/Emulator.h"
+#include "Debugger/ITraceLogger.h"
#include "Shared/Interfaces/IConsole.h"
#include "Utilities/HexUtilities.h"
#include "Utilities/FolderUtilities.h"
@@ -53,6 +53,8 @@
#include "MemoryOperationType.h"
#include "EventType.h"
+uint64_t ITraceLogger::NextRowId = 0;
+
Debugger::Debugger(Emulator* emu, IConsole* console)
{
_executionStopped = true;
@@ -67,14 +69,13 @@ Debugger::Debugger(Emulator* emu, IConsole* console)
_memoryDumper.reset(new MemoryDumper(this));
_disassembler.reset(new Disassembler(console, this));
- _traceLogger.reset(new TraceLogger(this));
_memoryAccessCounter.reset(new MemoryAccessCounter(this));
- _ppuTools.reset(new PpuTools(_emu));
+ _ppuTools.reset(new PpuTools(this, _emu));
_scriptManager.reset(new ScriptManager(this));
- vector cpuTypes = _emu->GetCpuTypes();
- _mainCpuType = cpuTypes[0];
- for(CpuType type : cpuTypes) {
+ _cpuTypes = _emu->GetCpuTypes();
+ _mainCpuType = _cpuTypes[0];
+ for(CpuType type : _cpuTypes) {
unique_ptr &debugger = _debuggers[(int)type].Debugger;
switch(type) {
case CpuType::Cpu: debugger.reset(new CpuDebugger(this, CpuType::Cpu)); break;
@@ -91,6 +92,10 @@ Debugger::Debugger(Emulator* emu, IConsole* console)
_debuggers[(int)type].Evaluator.reset(new ExpressionEvaluator(this, type));
}
+ for(CpuType type : _cpuTypes) {
+ _debuggers[(int)type].Debugger->Init();
+ }
+
_breakRequestCount = 0;
_suspendRequestCount = 0;
@@ -134,10 +139,25 @@ void Debugger::Reset()
}
}
+template
+DebuggerType* Debugger::GetDebugger()
+{
+ return (DebuggerType*)_debuggers[(int)type].Debugger.get();
+}
+
template
void Debugger::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType)
{
- _debuggers[(int)type].Debugger->ProcessRead(addr, value, opType);
+ switch(type) {
+ case CpuType::Cpu: GetDebugger()->ProcessRead(addr, value, opType); break;
+ case CpuType::Spc: GetDebugger()->ProcessRead(addr, value, opType); break;
+ case CpuType::NecDsp: GetDebugger()->ProcessRead(addr, value, opType); break;
+ case CpuType::Sa1: GetDebugger()->ProcessRead(addr, value, opType); break;
+ case CpuType::Gsu: GetDebugger()->ProcessRead(addr, value, opType); break;
+ case CpuType::Cx4: GetDebugger()->ProcessRead(addr, value, opType); break;
+ case CpuType::Gameboy: GetDebugger()->ProcessRead(addr, value, opType); break;
+ case CpuType::Nes: GetDebugger()->ProcessRead(addr, value, opType); break;
+ }
if(_scriptManager->HasScript()) {
_scriptManager->ProcessMemoryOperation(addr, value, opType, type);
@@ -147,7 +167,16 @@ void Debugger::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationTy
template
void Debugger::ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType)
{
- _debuggers[(int)type].Debugger->ProcessWrite(addr, value, opType);
+ switch(type) {
+ case CpuType::Cpu: GetDebugger()->ProcessWrite(addr, value, opType); break;
+ case CpuType::Spc: GetDebugger()->ProcessWrite(addr, value, opType); break;
+ case CpuType::NecDsp: GetDebugger()->ProcessWrite(addr, value, opType); break;
+ case CpuType::Sa1: GetDebugger()->ProcessWrite(addr, value, opType); break;
+ case CpuType::Gsu: GetDebugger()->ProcessWrite(addr, value, opType); break;
+ case CpuType::Cx4: GetDebugger()->ProcessWrite(addr, value, opType); break;
+ case CpuType::Gameboy: GetDebugger()->ProcessWrite(addr, value, opType); break;
+ case CpuType::Nes: GetDebugger()->ProcessWrite(addr, value, opType); break;
+ }
if(_scriptManager->HasScript()) {
_scriptManager->ProcessMemoryOperation(addr, value, opType, type);
@@ -181,22 +210,17 @@ void Debugger::ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memo
template
void Debugger::ProcessPpuCycle()
{
- uint16_t scanline = 0;
- uint16_t cycle = 0;
+ int16_t scanline;
+ uint16_t cycle;
switch(type) {
- case CpuType::Cpu:
- case CpuType::Gameboy:
- case CpuType::Nes:
- _debuggers[(int)type].Debugger->ProcessPpuCycle(scanline, cycle);
- break;
+ case CpuType::Cpu: GetDebugger()->ProcessPpuCycle(scanline, cycle); break;
+ case CpuType::Gameboy: GetDebugger()->ProcessPpuCycle(scanline, cycle); break;
+ case CpuType::Nes: GetDebugger()->ProcessPpuCycle(scanline, cycle); break;
+ default: throw std::runtime_error("Invalid cpu type");
}
_ppuTools->UpdateViewers(scanline, cycle, type);
-
- if(_breakRequestCount > 0) {
- SleepUntilResume(BreakSource::Unspecified);
- }
}
void Debugger::SleepUntilResume(BreakSource source, MemoryOperationInfo *operation, int breakpointId)
@@ -205,11 +229,11 @@ void Debugger::SleepUntilResume(BreakSource source, MemoryOperationInfo *operati
return;
}
- _emu->GetSoundMixer()->StopAudio();
-
_executionStopped = true;
if(source != BreakSource::Unspecified || _breakRequestCount == 0) {
+ _emu->GetSoundMixer()->StopAudio();
+
//Only trigger code break event if the pause was caused by user action
BreakEvent evt = {};
evt.BreakpointId = breakpointId;
@@ -222,7 +246,7 @@ void Debugger::SleepUntilResume(BreakSource source, MemoryOperationInfo *operati
}
while((_waitForBreakResume && !_suspendRequestCount) || _breakRequestCount) {
- std::this_thread::sleep_for(std::chrono::duration(10));
+ std::this_thread::sleep_for(std::chrono::duration(_breakRequestCount ? 1 : 10));
}
_executionStopped = false;
@@ -363,6 +387,7 @@ void Debugger::SuspendDebugger(bool release)
void Debugger::BreakImmediately(BreakSource source)
{
+ //TODO
bool gbDebugger = _settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled);
if(source == BreakSource::GbDisableLcdOutsideVblank && (!gbDebugger || !_settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnDisableLcdOutsideVblank))) {
return;
@@ -437,8 +462,8 @@ void Debugger::RebuildPrgCache(CpuType cpuType)
uint32_t prgRomSize = cdl->GetPrgSize();
AddressInfo addrInfo;
+ //TODO
addrInfo.Type = cpuType == CpuType::Gameboy ? SnesMemoryType::GbPrgRom : SnesMemoryType::PrgRom;
-
for(uint32_t i = 0; i < prgRomSize; i++) {
if(cdl->IsCode(i)) {
addrInfo.Address = (int32_t)i;
@@ -535,9 +560,55 @@ void Debugger::SaveRomToDisk(string filename, bool saveAsIps, CdlStripOption str
}*/
}
-shared_ptr Debugger::GetTraceLogger()
+ITraceLogger* Debugger::GetTraceLogger(CpuType cpuType)
{
- return _traceLogger;
+ if(_debuggers[(int)cpuType].Debugger) {
+ return _debuggers[(int)cpuType].Debugger->GetTraceLogger();
+ }
+ return nullptr;
+}
+
+uint32_t Debugger::GetExecutionTrace(TraceRow output[], uint32_t startOffset, uint32_t maxLineCount)
+{
+ DebugBreakHelper helper(this);
+
+ uint32_t offsetsByCpu[(int)DebugUtilities::GetLastCpuType() + 1] = {};
+
+ vector cpuTypes = _emu->GetCpuTypes();
+
+ uint32_t count = 0;
+ int64_t lastRowId = ITraceLogger::NextRowId;
+ while(count < maxLineCount) {
+ bool added = false;
+ for(CpuType cpuType : cpuTypes) {
+ ITraceLogger* logger = GetTraceLogger(cpuType);
+ if(logger) {
+ uint32_t& offset = offsetsByCpu[(int)cpuType];
+ int64_t rowId = logger->GetRowId(offset);
+ if(rowId == -1 || rowId != lastRowId - 1) {
+ continue;
+ }
+
+ lastRowId = rowId;
+
+ if(startOffset > 0) {
+ //Skip rows until the part the UI wants to display is reached
+ startOffset--;
+ } else {
+ logger->GetExecutionTrace(output[count], offset);
+ count++;
+ }
+ offset++;
+ added = true;
+ break;
+ }
+ }
+ if(!added) {
+ break;
+ }
+ }
+
+ return count;
}
MemoryDumper* Debugger::GetMemoryDumper()
diff --git a/Core/Debugger/Debugger.h b/Core/Debugger/Debugger.h
index 68650397..26e098fc 100644
--- a/Core/Debugger/Debugger.h
+++ b/Core/Debugger/Debugger.h
@@ -16,7 +16,6 @@ class InternalRegisters;
class DmaController;
class EmuSettings;
-class TraceLogger;
class ExpressionEvaluator;
class MemoryDumper;
class MemoryAccessCounter;
@@ -31,7 +30,9 @@ class Breakpoint;
class IEventManager;
class IAssembler;
class IDebugger;
+class ITraceLogger;
+struct TraceRow;
struct BaseState;
enum class EventType;
@@ -55,10 +56,10 @@ private:
CpuInfo _debuggers[(int)DebugUtilities::GetLastCpuType() + 1];
CpuType _mainCpuType = CpuType::Cpu;
+ vector _cpuTypes;
ConsoleType _consoleType = ConsoleType::Snes;
shared_ptr _scriptManager;
- shared_ptr _traceLogger;
shared_ptr _memoryDumper;
shared_ptr _memoryAccessCounter;
shared_ptr _codeDataLogger;
@@ -77,6 +78,8 @@ private:
void Reset();
+ template DebuggerType* GetDebugger();
+
public:
Debugger(Emulator* emu, IConsole* console);
~Debugger();
@@ -126,7 +129,9 @@ public:
void SaveRomToDisk(string filename, bool saveAsIps, CdlStripOption stripOption);
- shared_ptr GetTraceLogger();
+ uint32_t GetExecutionTrace(TraceRow output[], uint32_t startOffset, uint32_t maxLineCount);
+
+ ITraceLogger* GetTraceLogger(CpuType cpuType);
MemoryDumper* GetMemoryDumper();
shared_ptr GetMemoryAccessCounter();
shared_ptr GetCodeDataLogger(CpuType cpuType);
diff --git a/Core/Debugger/Disassembler.cpp b/Core/Debugger/Disassembler.cpp
index 5147a3d8..1a55dccb 100644
--- a/Core/Debugger/Disassembler.cpp
+++ b/Core/Debugger/Disassembler.cpp
@@ -55,7 +55,7 @@ uint32_t Disassembler::BuildCache(AddressInfo &addrInfo, uint8_t cpuFlags, CpuTy
int returnSize = 0;
int32_t address = addrInfo.Address;
- while(address >= 0 && address < (int32_t)src.Cache.size()) {
+ do {
DisassemblyInfo &disInfo = src.Cache[address];
if(!disInfo.IsInitialized() || !disInfo.IsValid(cpuFlags)) {
disInfo.Initialize(src.Data+address, cpuFlags, type);
@@ -77,7 +77,7 @@ uint32_t Disassembler::BuildCache(AddressInfo &addrInfo, uint8_t cpuFlags, CpuTy
disInfo.UpdateCpuFlags(cpuFlags);
address += disInfo.GetOpSize();
- }
+ } while(address >= 0 && address < (int32_t)src.Cache.size());
return returnSize;
}
diff --git a/Core/Debugger/ExpressionEvaluator.h b/Core/Debugger/ExpressionEvaluator.h
index 65c80dd1..b7f8d04f 100644
--- a/Core/Debugger/ExpressionEvaluator.h
+++ b/Core/Debugger/ExpressionEvaluator.h
@@ -127,8 +127,8 @@ public:
struct ExpressionData
{
- std::vector RpnQueue;
- std::vector Labels;
+ vector RpnQueue;
+ vector Labels;
};
class ExpressionEvaluator
@@ -138,9 +138,9 @@ private:
static const vector _binaryPrecedence;
static const vector _unaryOperators;
static const vector _unaryPrecedence;
- static const std::unordered_set _operators;
+ static const unordered_set _operators;
- std::unordered_map _cache;
+ unordered_map _cache;
SimpleLock _cacheLock;
Debugger* _debugger;
diff --git a/Core/Debugger/IDebugger.h b/Core/Debugger/IDebugger.h
index 60102325..ffac1fde 100644
--- a/Core/Debugger/IDebugger.h
+++ b/Core/Debugger/IDebugger.h
@@ -7,7 +7,9 @@ class CallstackManager;
class IAssembler;
class IEventManager;
class CodeDataLogger;
+class ITraceLogger;
struct BaseState;
+enum class EventType;
enum class MemoryOperationType;
class IDebugger
@@ -18,17 +20,17 @@ public:
virtual void Step(int32_t stepCount, StepType type) = 0;
virtual void Reset() = 0;
virtual void Run() = 0;
+
+ virtual void Init() {}
- virtual void ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType opType) {}
- virtual void ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType opType) {}
virtual void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi) {}
- virtual void ProcessPpuCycle(uint16_t& cycle, uint16_t& scanline) {}
virtual BreakpointManager* GetBreakpointManager() = 0;
virtual shared_ptr GetCallstackManager() = 0;
virtual shared_ptr GetAssembler() = 0;
virtual shared_ptr GetEventManager() = 0;
virtual shared_ptr GetCodeDataLogger() = 0;
+ virtual ITraceLogger* GetTraceLogger() = 0;
virtual BaseState& GetState() = 0;
};
\ No newline at end of file
diff --git a/Core/Debugger/ITraceLogger.h b/Core/Debugger/ITraceLogger.h
new file mode 100644
index 00000000..4fb4fa92
--- /dev/null
+++ b/Core/Debugger/ITraceLogger.h
@@ -0,0 +1,36 @@
+#pragma once
+#include "stdafx.h"
+#include "DebugTypes.h"
+
+struct TraceRow
+{
+ uint32_t ProgramCounter;
+ CpuType Type;
+ uint8_t ByteCode[4];
+ uint8_t ByteCodeSize;
+ char LogOutput[500];
+};
+
+struct TraceLoggerOptions
+{
+ bool Enabled;
+ bool IndentCode;
+ bool UseLabels;
+ char Condition[1000];
+ char Format[1000];
+};
+
+class ITraceLogger
+{
+protected:
+ bool _enabled = false;
+
+public:
+ static uint64_t NextRowId;
+
+ virtual int64_t GetRowId(uint32_t offset) = 0;
+ virtual void GetExecutionTrace(TraceRow& row, uint32_t offset) = 0;
+ virtual void SetOptions(TraceLoggerOptions options) = 0;
+
+ __forceinline bool IsEnabled() { return _enabled; }
+};
diff --git a/Core/Debugger/MemoryDumper.cpp b/Core/Debugger/MemoryDumper.cpp
index 9d338f0e..c83bd113 100644
--- a/Core/Debugger/MemoryDumper.cpp
+++ b/Core/Debugger/MemoryDumper.cpp
@@ -35,8 +35,11 @@ MemoryDumper::MemoryDumper(Debugger* debugger)
_spc = c->GetSpc().get();
_memoryManager = c->GetMemoryManager().get();
_cartridge = c->GetCartridge().get();
+ _gameboy = c->GetCartridge()->GetGameboy();
} else if(NesConsole* c = dynamic_cast(console)) {
_nesMemoryManager = c->GetMemoryManager();
+ } else if(Gameboy* c = dynamic_cast(console)) {
+ _gameboy = c;
}
}
@@ -122,8 +125,8 @@ void MemoryDumper::GetMemoryState(SnesMemoryType type, uint8_t *buffer)
break;
case SnesMemoryType::GameboyMemory: {
- if(_cartridge->GetGameboy()) {
- GbMemoryManager* memManager = _cartridge->GetGameboy()->GetMemoryManager();
+ if(_gameboy) {
+ GbMemoryManager* memManager = _gameboy->GetMemoryManager();
for(int i = 0; i <= 0xFFFF; i++) {
buffer[i] = memManager->DebugRead(i);
}
@@ -183,7 +186,7 @@ void MemoryDumper::SetMemoryValue(SnesMemoryType memoryType, uint32_t address, u
case SnesMemoryType::Sa1Memory: _cartridge->GetSa1()->GetMemoryMappings()->DebugWrite(address, value); break;
case SnesMemoryType::GsuMemory: _cartridge->GetGsu()->GetMemoryMappings()->DebugWrite(address, value); break;
case SnesMemoryType::Cx4Memory: _cartridge->GetCx4()->GetMemoryMappings()->DebugWrite(address, value); break;
- case SnesMemoryType::GameboyMemory: _cartridge->GetGameboy()->GetMemoryManager()->DebugWrite(address, value); break;
+ case SnesMemoryType::GameboyMemory: _gameboy->GetMemoryManager()->DebugWrite(address, value); break;
case SnesMemoryType::NesMemory: _nesMemoryManager->DebugWrite(address, value); break;
default:
@@ -217,7 +220,7 @@ uint8_t MemoryDumper::GetMemoryValue(SnesMemoryType memoryType, uint32_t address
case SnesMemoryType::Sa1Memory: return _cartridge->GetSa1()->GetMemoryMappings()->Peek(address);
case SnesMemoryType::GsuMemory: return _cartridge->GetGsu()->GetMemoryMappings()->Peek(address);
case SnesMemoryType::Cx4Memory: return _cartridge->GetCx4()->GetMemoryMappings()->Peek(address);
- case SnesMemoryType::GameboyMemory: return _cartridge->GetGameboy()->GetMemoryManager()->DebugRead(address);
+ case SnesMemoryType::GameboyMemory: return _gameboy->GetMemoryManager()->DebugRead(address);
case SnesMemoryType::NesMemory: return _nesMemoryManager->DebugRead(address);
default:
diff --git a/Core/Debugger/MemoryDumper.h b/Core/Debugger/MemoryDumper.h
index 0a5f5125..e3013185 100644
--- a/Core/Debugger/MemoryDumper.h
+++ b/Core/Debugger/MemoryDumper.h
@@ -8,6 +8,7 @@ class NesMemoryManager;
class BaseCartridge;
class Ppu;
class Spc;
+class Gameboy;
class Emulator;
class Debugger;
class Disassembler;
@@ -16,14 +17,15 @@ enum class SnesMemoryType;
class MemoryDumper
{
private:
- Emulator* _emu;
- Ppu* _ppu;
- Spc* _spc;
- MemoryManager* _memoryManager;
- NesMemoryManager* _nesMemoryManager;
- BaseCartridge* _cartridge;
- Debugger* _debugger;
- Disassembler* _disassembler;
+ Emulator* _emu = nullptr;
+ Ppu* _ppu = nullptr;
+ Spc* _spc = nullptr;
+ Gameboy* _gameboy = nullptr;
+ MemoryManager* _memoryManager = nullptr;
+ NesMemoryManager* _nesMemoryManager = nullptr;
+ BaseCartridge* _cartridge = nullptr;
+ Debugger* _debugger = nullptr;
+ Disassembler* _disassembler = nullptr;
public:
MemoryDumper(Debugger* debugger);
diff --git a/Core/Debugger/PpuTools.cpp b/Core/Debugger/PpuTools.cpp
index 70c3f9b6..b18ad84c 100644
--- a/Core/Debugger/PpuTools.cpp
+++ b/Core/Debugger/PpuTools.cpp
@@ -1,6 +1,7 @@
#include "stdafx.h"
#include "Debugger/PpuTools.h"
#include "Debugger/DebugTypes.h"
+#include "Debugger/DebugBreakHelper.h"
#include "Shared/NotificationManager.h"
#include "Shared/SettingTypes.h"
#include "SNES/SnesDefaultVideoFilter.h"
@@ -10,9 +11,10 @@
#include "SNES/MemoryManager.h"
#include "Gameboy/GbTypes.h"
-PpuTools::PpuTools(Emulator *emu)
+PpuTools::PpuTools(Debugger* debugger, Emulator *emu)
{
_emu = emu;
+ _debugger = debugger;
}
uint8_t PpuTools::GetTilePixelColor(const uint8_t* ram, const uint32_t ramMask, const uint8_t bpp, const uint32_t pixelStart, const uint8_t shift)
@@ -387,7 +389,8 @@ void PpuTools::GetSpritePreview(GetSpritePreviewOptions options, PpuState state,
void PpuTools::SetViewerUpdateTiming(uint32_t viewerId, uint16_t scanline, uint16_t cycle, CpuType cpuType)
{
- //TODO Thread safety
+ DebugBreakHelper helper(_debugger);
+
ViewerRefreshConfig cfg;
cfg.Scanline = scanline;
cfg.Cycle = cycle;
@@ -397,7 +400,7 @@ void PpuTools::SetViewerUpdateTiming(uint32_t viewerId, uint16_t scanline, uint1
void PpuTools::RemoveViewer(uint32_t viewerId)
{
- //TODO Thread safety
+ DebugBreakHelper helper(_debugger);
_updateTimings.erase(viewerId);
}
diff --git a/Core/Debugger/PpuTools.h b/Core/Debugger/PpuTools.h
index 2633abbf..a701c3b5 100644
--- a/Core/Debugger/PpuTools.h
+++ b/Core/Debugger/PpuTools.h
@@ -5,6 +5,8 @@
#include "Shared/NotificationManager.h"
#include "SNES/PpuTypes.h"
+class Debugger;
+class Emulator;
class Ppu;
struct GbPpuState;
@@ -18,7 +20,8 @@ struct ViewerRefreshConfig
class PpuTools
{
private:
- Emulator *_emu;
+ Emulator* _emu;
+ Debugger* _debugger;
unordered_map _updateTimings;
uint8_t GetTilePixelColor(const uint8_t* ram, const uint32_t ramMask, const uint8_t bpp, const uint32_t pixelStart, const uint8_t shift);
@@ -29,7 +32,7 @@ private:
uint32_t GetRgbPixelColor(uint32_t* colors, uint8_t colorIndex, uint8_t palette, uint8_t bpp, bool directColorMode, uint16_t basePaletteOffset);
public:
- PpuTools(Emulator *emu);
+ PpuTools(Debugger* debugger, Emulator *emu);
void GetTileView(GetTileViewOptions options, uint8_t *source, uint32_t srcSize, uint32_t* palette, uint32_t *outBuffer);
void GetTilemap(GetTilemapOptions options, PpuState state, uint8_t* vram, uint8_t* cgram, uint32_t *outBuffer);
diff --git a/Core/Debugger/TraceLogFileSaver.h b/Core/Debugger/TraceLogFileSaver.h
new file mode 100644
index 00000000..b350b33e
--- /dev/null
+++ b/Core/Debugger/TraceLogFileSaver.h
@@ -0,0 +1,42 @@
+#pragma once
+#include "stdafx.h"
+
+class TraceLogFileSaver
+{
+private:
+ bool _logToFile;
+ string _outputFilepath;
+ string _outputBuffer;
+ ofstream _outputFile;
+
+public:
+ void StartLogging(string filename)
+ {
+ _outputBuffer.clear();
+ _outputFile.open(filename, ios::out | ios::binary);
+ _logToFile = true;
+ }
+
+ void StopLogging()
+ {
+ if(_logToFile) {
+ _logToFile = false;
+ if(_outputFile) {
+ if(!_outputBuffer.empty()) {
+ _outputFile << _outputBuffer;
+ }
+ _outputFile.close();
+ }
+ }
+ }
+
+ /*void LogExtraInfo(const char* log, uint32_t cycleCount)
+ {
+ if(_logToFile) {
+ //Flush current buffer
+ _outputFile << _outputBuffer;
+ _outputBuffer.clear();
+ _outputFile << "[" << log << " - Cycle: " << std::to_string(cycleCount) << "]" << (_options.UseWindowsEol ? "\r\n" : "\n");
+ }
+ }*/
+};
\ No newline at end of file
diff --git a/Core/Debugger/TraceLogger.cpp b/Core/Debugger/TraceLogger.cpp
deleted file mode 100644
index 4e5c4444..00000000
--- a/Core/Debugger/TraceLogger.cpp
+++ /dev/null
@@ -1,789 +0,0 @@
-#include "stdafx.h"
-#include
-#include
-#include "Debugger/TraceLogger.h"
-#include "Debugger/DisassemblyInfo.h"
-#include "Debugger/Debugger.h"
-#include "Debugger/LabelManager.h"
-#include "Debugger/DebugTypes.h"
-#include "Debugger/DebugUtilities.h"
-#include "Debugger/DebugBreakHelper.h"
-#include "SNES/MemoryManager.h"
-#include "SNES/Console.h"
-#include "SNES/CpuTypes.h"
-#include "SNES/SpcTypes.h"
-#include "SNES/Coprocessors/DSP/NecDspTypes.h"
-#include "SNES/PpuTypes.h"
-#include "SNES/Coprocessors/CX4/Cx4Types.h"
-#include "SNES/Coprocessors/GSU/GsuTypes.h"
-#include "Gameboy/GbTypes.h"
-#include "NES/NesTypes.h"
-#include "Utilities/HexUtilities.h"
-#include "Shared/Emulator.h"
-#include "Shared/EmuSettings.h"
-
-string TraceLogger::_executionTrace = "";
-
-TraceLogger::TraceLogger(Debugger* debugger)
-{
- _debugger = debugger;
- _console = debugger->GetConsole();
- _settings = debugger->GetEmulator()->GetSettings();
- _labelManager = debugger->GetLabelManager().get();
- _memoryDumper = debugger->GetMemoryDumper();
- _options = {};
- _currentPos = 0;
- _logCount = 0;
- _logToFile = false;
- _pendingLog = false;
-
- _snesCpuState = new CpuState[TraceLogger::ExecutionLogSize];
- _spcState = new SpcState[TraceLogger::ExecutionLogSize];
- _necDspState = new NecDspState[TraceLogger::ExecutionLogSize];
- _gsuState = new GsuState[TraceLogger::ExecutionLogSize];
- _cx4State = new Cx4State[TraceLogger::ExecutionLogSize];
- _gbCpuState = new GbCpuState[TraceLogger::ExecutionLogSize];
- _nesCpuState = new NesCpuState[TraceLogger::ExecutionLogSize];
-
- _disassemblyCache = new DisassemblyInfo[TraceLogger::ExecutionLogSize];
- _logCpuType = new CpuType[TraceLogger::ExecutionLogSize];
-
- SetOptions({});
- _logCpu[(int)CpuType::Nes] = true;
-}
-
-TraceLogger::~TraceLogger()
-{
- StopLogging();
-
- delete[] _disassemblyCache;
- delete[] _logCpuType;
-
- delete[] _snesCpuState;
- delete[] _spcState;
- delete[] _necDspState;
- delete[] _gsuState;
- delete[] _cx4State;
- delete[] _gbCpuState;
- delete[] _nesCpuState;
-}
-
-template
-void TraceLogger::WriteValue(string &output, T value, RowPart& rowPart)
-{
- string str = rowPart.DisplayInHex ? HexUtilities::ToHex(value) : std::to_string(value);
- output += str;
- if(rowPart.MinWidth > (int)str.size()) {
- output += std::string(rowPart.MinWidth - str.size(), ' ');
- }
-}
-
-template<>
-void TraceLogger::WriteValue(string &output, string value, RowPart& rowPart)
-{
- output += value;
- if(rowPart.MinWidth > (int)value.size()) {
- output += std::string(rowPart.MinWidth - value.size(), ' ');
- }
-}
-
-void TraceLogger::SetOptions(TraceLoggerOptions options)
-{
- DebugBreakHelper helper(_debugger);
- _options = options;
-
- _logCpu[(int)CpuType::Cpu] = options.LogCpu;
- _logCpu[(int)CpuType::Spc] = options.LogSpc;
- _logCpu[(int)CpuType::NecDsp] = options.LogNecDsp;
- _logCpu[(int)CpuType::Sa1] = options.LogSa1;
- _logCpu[(int)CpuType::Gsu] = options.LogGsu;
- _logCpu[(int)CpuType::Cx4] = options.LogCx4;
- _logCpu[(int)CpuType::Gameboy] = options.LogGameboy;
- _logCpu[(int)CpuType::Nes] = options.LogNes;
-
- string condition = _options.Condition;
- string format = _options.Format;
-
- /*_conditionData = ExpressionData();
- if(!condition.empty()) {
- bool success = false;
- ExpressionData rpnList = _expEvaluator->GetRpnList(condition, success);
- if(success) {
- _conditionData = rpnList;
- }
- }*/
-
- ParseFormatString(_rowParts, format);
- ParseFormatString(_spcRowParts, "[PC,4h] [ByteCode,11h] [Disassembly][EffectiveAddress] [MemoryValue,h][Align,48] A:[A,2h] X:[X,2h] Y:[Y,2h] S:[SP,2h] P:[P,8] H:[Cycle,3] V:[Scanline,3]");
- ParseFormatString(_dspRowParts, "[PC,4h] [ByteCode,11h] [Disassembly] [Align,65] [A,2h] S:[SP,2h] H:[Cycle,3] V:[Scanline,3]");
- ParseFormatString(_gsuRowParts, "[PC,6h] [ByteCode,11h] [Disassembly] [Align,50] SRC:[X,2] DST:[Y,2] R0:[A,2h] H:[Cycle,3] V:[Scanline,3]");
- ParseFormatString(_cx4RowParts, "[PC,6h] [ByteCode,11h] [Disassembly] [Align,45] [A,2h] H:[Cycle,3] V:[Scanline,3]");
- ParseFormatString(_gbRowParts, "[PC,6h] [ByteCode,11h] [Disassembly] [Align,45] A:[A,2h] B:[B,2h] C:[C,2h] D:[D,2h] E:[E,2h] HL:[H,2h][L,2h] F:[F,2h] SP:[SP,4h] CYC:[Cycle,3] LY:[Scanline,3]");
- ParseFormatString(_nesRowParts, "[PC,4h] [ByteCode,11h] [Disassembly][EffectiveAddress] [MemoryValue,2h][Align,48] A:[A,2h] X:[X,2h] Y:[Y,2h] P:[P,8] SP:[SP,2h] CYC:[Cycle,3] SL:[Scanline,3] FC:[FrameCount] CPU Cycle:[CycleCount]");
-}
-
-void TraceLogger::ParseFormatString(vector &rowParts, string format)
-{
- rowParts.clear();
-
- std::regex formatRegex = std::regex("(\\[\\s*([^[]*?)\\s*(,\\s*([\\d]*)\\s*(h){0,1}){0,1}\\s*\\])|([^[]*)", std::regex_constants::icase);
- std::sregex_iterator start = std::sregex_iterator(format.cbegin(), format.cend(), formatRegex);
- std::sregex_iterator end = std::sregex_iterator();
-
- for(std::sregex_iterator it = start; it != end; it++) {
- const std::smatch& match = *it;
-
- if(match.str(1) == "") {
- RowPart part = {};
- part.DataType = RowDataType::Text;
- part.Text = match.str(6);
- rowParts.push_back(part);
- } else {
- RowPart part = {};
-
- string dataType = match.str(2);
- if(dataType == "ByteCode") {
- part.DataType = RowDataType::ByteCode;
- } else if(dataType == "Disassembly") {
- part.DataType = RowDataType::Disassembly;
- } else if(dataType == "EffectiveAddress") {
- part.DataType = RowDataType::EffectiveAddress;
- } else if(dataType == "MemoryValue") {
- part.DataType = RowDataType::MemoryValue;
- } else if(dataType == "Align") {
- part.DataType = RowDataType::Align;
- } else if(dataType == "PC") {
- part.DataType = RowDataType::PC;
- } else if(dataType == "A") {
- part.DataType = RowDataType::A;
- } else if(dataType == "B") {
- part.DataType = RowDataType::B;
- } else if(dataType == "C") {
- part.DataType = RowDataType::C;
- } else if(dataType == "D") {
- part.DataType = RowDataType::D;
- } else if(dataType == "E") {
- part.DataType = RowDataType::E;
- } else if(dataType == "F") {
- part.DataType = RowDataType::F;
- } else if(dataType == "H") {
- part.DataType = RowDataType::H;
- } else if(dataType == "L") {
- part.DataType = RowDataType::L;
- } else if(dataType == "X") {
- part.DataType = RowDataType::X;
- } else if(dataType == "Y") {
- part.DataType = RowDataType::Y;
- } else if(dataType == "D") {
- part.DataType = RowDataType::D;
- } else if(dataType == "DB") {
- part.DataType = RowDataType::DB;
- } else if(dataType == "P") {
- part.DataType = RowDataType::PS;
- } else if(dataType == "SP") {
- part.DataType = RowDataType::SP;
- } else if(dataType == "Cycle") {
- part.DataType = RowDataType::Cycle;
- } else if(dataType == "HClock") {
- part.DataType = RowDataType::HClock;
- } else if(dataType == "Scanline") {
- part.DataType = RowDataType::Scanline;
- } else if(dataType == "FrameCount") {
- part.DataType = RowDataType::FrameCount;
- } else if(dataType == "CycleCount") {
- part.DataType = RowDataType::CycleCount;
- } else {
- part.DataType = RowDataType::Text;
- part.Text = "[Invalid tag]";
- }
-
- if(!match.str(4).empty()) {
- try {
- part.MinWidth = std::stoi(match.str(4));
- } catch(std::exception&) {
- }
- }
- part.DisplayInHex = match.str(5) == "h";
-
- rowParts.push_back(part);
- }
- }
-}
-
-void TraceLogger::StartLogging(string filename)
-{
- _outputBuffer.clear();
- _outputFile.open(filename, ios::out | ios::binary);
- _logToFile = true;
-}
-
-void TraceLogger::StopLogging()
-{
- if(_logToFile) {
- _logToFile = false;
- if(_outputFile) {
- if(!_outputBuffer.empty()) {
- _outputFile << _outputBuffer;
- }
- _outputFile.close();
- }
- }
-}
-
-void TraceLogger::LogExtraInfo(const char *log, uint32_t cycleCount)
-{
- if(_logToFile && _options.ShowExtraInfo) {
- //Flush current buffer
- _outputFile << _outputBuffer;
- _outputBuffer.clear();
- _outputFile << "[" << log << " - Cycle: " << std::to_string(cycleCount) << "]" << (_options.UseWindowsEol ? "\r\n" : "\n");
- }
-}
-
-template
-void TraceLogger::GetStatusFlag(string &output, uint8_t ps, RowPart& part)
-{
- constexpr char cpuActiveStatusLetters[8] = { 'N', 'V', 'M', 'X', 'D', 'I', 'Z', 'C' };
- constexpr char cpuInactiveStatusLetters[8] = { 'n', 'v', 'm', 'x', 'd', 'i', 'z', 'c' };
-
- constexpr char spcActiveStatusLetters[8] = { 'N', 'V', 'P', 'B', 'H', 'I', 'Z', 'C' };
- constexpr char spcInactiveStatusLetters[8] = { 'n', 'v', 'p', 'b', 'h', 'i', 'z', 'c' };
-
- constexpr char nesActiveStatusLetters[8] = { 'N', 'V', '-', '-', 'D', 'I', 'Z', 'C' };
- constexpr char nesInactiveStatusLetters[8] = { 'n', 'v', '-', '-', 'd', 'i', 'z', 'c' };
-
- const char *activeStatusLetters = cpuType == CpuType::Cpu ? cpuActiveStatusLetters : (cpuType == CpuType::Spc ? spcActiveStatusLetters : nesActiveStatusLetters);
- const char *inactiveStatusLetters = cpuType == CpuType::Cpu ? cpuInactiveStatusLetters : (cpuType == CpuType::Spc ? spcInactiveStatusLetters : nesInactiveStatusLetters);
-
- if(part.DisplayInHex) {
- WriteValue(output, ps, part);
- } else {
- string flags;
- for(int i = 0; i < 8; i++) {
- if(ps & 0x80) {
- flags += activeStatusLetters[i];
- } else if(part.MinWidth >= 8) {
- flags += inactiveStatusLetters[i];
- }
- ps <<= 1;
- }
- WriteValue(output, flags, part);
- }
-}
-
-void TraceLogger::WriteByteCode(DisassemblyInfo &info, RowPart &rowPart, string &output)
-{
- string byteCode;
- info.GetByteCode(byteCode);
- if(!rowPart.DisplayInHex) {
- //Remove $ marks if not in "hex" mode (but still display the bytes as hex)
- byteCode.erase(std::remove(byteCode.begin(), byteCode.end(), '$'), byteCode.end());
- }
- WriteValue(output, byteCode, rowPart);
-}
-
-void TraceLogger::WriteDisassembly(DisassemblyInfo &info, RowPart &rowPart, uint8_t sp, uint32_t pc, string &output)
-{
- int indentLevel = 0;
- string code;
-
- if(_options.IndentCode) {
- indentLevel = 0xFF - (sp & 0xFF);
- code = std::string(indentLevel, ' ');
- }
-
- LabelManager* labelManager = _options.UseLabels ? _labelManager : nullptr;
- info.GetDisassembly(code, pc, labelManager, _settings);
- WriteValue(output, code, rowPart);
-}
-
-void TraceLogger::WriteEffectiveAddress(DisassemblyInfo &info, RowPart &rowPart, void *cpuState, string &output, SnesMemoryType cpuMemoryType, CpuType cpuType)
-{
- int32_t effectiveAddress = info.GetEffectiveAddress(_debugger, cpuState, cpuType);
- if(effectiveAddress >= 0) {
- if(_options.UseLabels) {
- AddressInfo addr { effectiveAddress, cpuMemoryType };
- string label = _labelManager->GetLabel(addr);
- if(!label.empty()) {
- WriteValue(output, " [" + label + "]", rowPart);
- return;
- }
- }
- WriteValue(output, " [" + HexUtilities::ToHex24(effectiveAddress) + "]", rowPart);
- }
-}
-
-void TraceLogger::WriteMemoryValue(DisassemblyInfo &info, RowPart &rowPart, void *cpuState, string &output, SnesMemoryType memType, CpuType cpuType)
-{
- int32_t address = info.GetEffectiveAddress(_debugger, cpuState, cpuType);
- if(address >= 0) {
- uint8_t valueSize;
- uint16_t value = info.GetMemoryValue(address, _memoryDumper, memType, valueSize);
- if(rowPart.DisplayInHex) {
- output += "= $";
- if(valueSize == 2) {
- WriteValue(output, (uint16_t)value, rowPart);
- } else {
- WriteValue(output, (uint8_t)value, rowPart);
- }
- } else {
- output += "= ";
- }
- }
-}
-
-void TraceLogger::WriteAlign(int originalSize, RowPart &rowPart, string &output)
-{
- if((int)output.size() - originalSize < rowPart.MinWidth) {
- output += std::string(rowPart.MinWidth - (output.size() - originalSize), ' ');
- }
-}
-
-void TraceLogger::GetTraceRow(string &output, CpuState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo, SnesMemoryType memType, CpuType cpuType)
-{
- int originalSize = (int)output.size();
- uint32_t pcAddress = (cpuState.K << 16) | cpuState.PC;
- for(RowPart& rowPart : _rowParts) {
- switch(rowPart.DataType) {
- case RowDataType::Text: output += rowPart.Text; break;
- case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break;
- case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, (uint8_t)cpuState.SP, pcAddress, output); break;
- case RowDataType::EffectiveAddress: WriteEffectiveAddress(disassemblyInfo, rowPart, &cpuState, output, memType, cpuType); break;
- case RowDataType::MemoryValue: WriteMemoryValue(disassemblyInfo, rowPart, &cpuState, output, memType, cpuType); break;
- case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break;
-
- case RowDataType::PC: WriteValue(output, HexUtilities::ToHex24(pcAddress), rowPart); break;
- case RowDataType::A: WriteValue(output, cpuState.A, rowPart); break;
- case RowDataType::X: WriteValue(output, cpuState.X, rowPart); break;
- case RowDataType::Y: WriteValue(output, cpuState.Y, rowPart); break;
- case RowDataType::D: WriteValue(output, cpuState.D, rowPart); break;
- case RowDataType::DB: WriteValue(output, cpuState.DBR, rowPart); break;
- case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); break;
- case RowDataType::PS: GetStatusFlag(output, cpuState.PS, rowPart); break;
- case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break;
- case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break;
- case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); break;
- case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break;
- case RowDataType::CycleCount:
- WriteValue(output, (uint32_t)(cpuState.CycleCount >> 32), rowPart);
- WriteValue(output, (uint32_t)cpuState.CycleCount, rowPart);
- break;
- default: break;
- }
- }
- output += _options.UseWindowsEol ? "\r\n" : "\n";
-}
-
-void TraceLogger::GetTraceRow(string &output, SpcState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo)
-{
- int originalSize = (int)output.size();
- uint32_t pcAddress = cpuState.PC;
- for(RowPart& rowPart : _spcRowParts) {
- switch(rowPart.DataType) {
- case RowDataType::Text: output += rowPart.Text; break;
- case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break;
- case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, cpuState.SP, pcAddress, output); break;
- case RowDataType::EffectiveAddress: WriteEffectiveAddress(disassemblyInfo, rowPart, &cpuState, output, SnesMemoryType::SpcMemory, CpuType::Spc); break;
- case RowDataType::MemoryValue: WriteMemoryValue(disassemblyInfo, rowPart, &cpuState, output, SnesMemoryType::SpcMemory, CpuType::Spc); break;
- case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break;
-
- case RowDataType::PC: WriteValue(output, HexUtilities::ToHex((uint16_t)pcAddress), rowPart); break;
- case RowDataType::A: WriteValue(output, cpuState.A, rowPart); break;
- case RowDataType::X: WriteValue(output, cpuState.X, rowPart); break;
- case RowDataType::Y: WriteValue(output, cpuState.Y, rowPart); break;
- case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); break;
- case RowDataType::PS: GetStatusFlag(output, cpuState.PS, rowPart); break;
- case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break;
- case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break;
- case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); break;
- case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break;
-
- default: break;
- }
- }
- output += _options.UseWindowsEol ? "\r\n" : "\n";
-}
-
-void TraceLogger::GetTraceRow(string &output, NecDspState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo)
-{
- int originalSize = (int)output.size();
- uint32_t pcAddress = cpuState.PC;
- for(RowPart& rowPart : _dspRowParts) {
- switch(rowPart.DataType) {
- case RowDataType::Text: output += rowPart.Text; break;
- case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break;
- case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, cpuState.SP, pcAddress, output); break;
- case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break;
-
- case RowDataType::PC: WriteValue(output, HexUtilities::ToHex((uint16_t)pcAddress), rowPart); break;
- case RowDataType::A:
- output += "A:" + HexUtilities::ToHex(cpuState.A);
- output += " B:" + HexUtilities::ToHex(cpuState.B);
- output += " DR:" + HexUtilities::ToHex(cpuState.DR);
- output += " DP:" + HexUtilities::ToHex(cpuState.DP);
- output += " SR:" + HexUtilities::ToHex(cpuState.SR);
- output += " K:" + HexUtilities::ToHex(cpuState.K);
- output += " L:" + HexUtilities::ToHex(cpuState.L);
- output += " M:" + HexUtilities::ToHex(cpuState.M);
- output += " N:" + HexUtilities::ToHex(cpuState.N);
- output += " RP:" + HexUtilities::ToHex(cpuState.RP);
- output += " TR:" + HexUtilities::ToHex(cpuState.TR);
- output += " TRB:" + HexUtilities::ToHex(cpuState.TRB) + " ";
- //output += "FA=" + HexUtilities::ToHex(cpuState.FlagsA);
- //output += "FB=" + HexUtilities::ToHex(cpuState.FlagsB);
- WriteValue(output, cpuState.A, rowPart);
- break;
- case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); break;
- case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break;
- case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break;
- case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); break;
- case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break;
- default: break;
- }
- }
- output += _options.UseWindowsEol ? "\r\n" : "\n";
-}
-
-void TraceLogger::GetTraceRow(string &output, GsuState &gsuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo)
-{
- int originalSize = (int)output.size();
- uint32_t pcAddress = (gsuState.ProgramBank << 16) | gsuState.R[15];
- for(RowPart& rowPart : _gsuRowParts) {
- switch(rowPart.DataType) {
- case RowDataType::Text: output += rowPart.Text; break;
- case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break;
- case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, 0, pcAddress, output); break;
- case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break;
-
- case RowDataType::PC: WriteValue(output, HexUtilities::ToHex24(pcAddress), rowPart); break;
- case RowDataType::A:
- WriteValue(output, gsuState.R[0], rowPart);
- for(int i = 1; i < 16; i++) {
- output += " R" + std::to_string(i) + ":" + HexUtilities::ToHex(gsuState.R[i]);
- }
- break;
- case RowDataType::X: WriteValue(output, gsuState.SrcReg, rowPart); break;
- case RowDataType::Y: WriteValue(output, gsuState.DestReg, rowPart); break;
-
- case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break;
- case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break;
- case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); break;
- case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break;
- default: break;
- }
- }
- output += _options.UseWindowsEol ? "\r\n" : "\n";
-}
-
-
-void TraceLogger::GetTraceRow(string &output, Cx4State &cx4State, PpuState &ppuState, DisassemblyInfo &disassemblyInfo)
-{
- int originalSize = (int)output.size();
- uint32_t pcAddress = (cx4State.Cache.Address[cx4State.Cache.Page] + (cx4State.PC * 2)) & 0xFFFFFF;
- for(RowPart& rowPart : _cx4RowParts) {
- switch(rowPart.DataType) {
- case RowDataType::Text: output += rowPart.Text; break;
- case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break;
- case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, 0, pcAddress, output); break;
- case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break;
-
- case RowDataType::PC: WriteValue(output, HexUtilities::ToHex24(pcAddress), rowPart); break;
- case RowDataType::A:
- output += " A:" + HexUtilities::ToHex24(cx4State.A);
- output += string(" ") + (cx4State.Carry ? "C" : "c") + (cx4State.Zero ? "Z" : "z") + (cx4State.Overflow ? "V" : "v") + (cx4State.Negative ? "N" : "n");
-
- output += " PC:" + HexUtilities::ToHex(cx4State.PC);
- output += " MAR:" + HexUtilities::ToHex24(cx4State.MemoryAddressReg);
- output += " MDR:" + HexUtilities::ToHex24(cx4State.MemoryDataReg);
- output += " DPR:" + HexUtilities::ToHex24(cx4State.DataPointerReg);
- output += " ML:" + HexUtilities::ToHex24((uint32_t)cx4State.Mult & 0xFFFFFF);
- output += " MH:" + HexUtilities::ToHex24((uint32_t)(cx4State.Mult >> 24) & 0xFFFFFF);
- for(int i = 0; i < 16; i++) {
- output += " R" + std::to_string(i) + ":" + HexUtilities::ToHex24(cx4State.Regs[i]);
- }
- break;
-
- case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break;
- case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break;
- case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); break;
- case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break;
- default: break;
- }
- }
- output += _options.UseWindowsEol ? "\r\n" : "\n";
-}
-
-void TraceLogger::GetTraceRow(string& output, GbCpuState& cpuState, GbPpuState& ppuState, DisassemblyInfo& disassemblyInfo)
-{
- int originalSize = (int)output.size();
- uint32_t pcAddress = cpuState.PC;
- for(RowPart& rowPart : _gbRowParts) {
- switch(rowPart.DataType) {
- case RowDataType::Text: output += rowPart.Text; break;
- case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break;
- case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, (uint8_t)cpuState.SP, pcAddress, output); break;
- case RowDataType::EffectiveAddress: WriteEffectiveAddress(disassemblyInfo, rowPart, &cpuState, output, SnesMemoryType::GameboyMemory, CpuType::Gameboy); break;
- case RowDataType::MemoryValue: WriteMemoryValue(disassemblyInfo, rowPart, &cpuState, output, SnesMemoryType::GameboyMemory, CpuType::Gameboy); break;
- case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break;
-
- case RowDataType::PC: WriteValue(output, HexUtilities::ToHex((uint16_t)pcAddress), rowPart); break;
- case RowDataType::A: WriteValue(output, cpuState.A, rowPart); break;
- case RowDataType::B: WriteValue(output, cpuState.B, rowPart); break;
- case RowDataType::C: WriteValue(output, cpuState.C, rowPart); break;
- case RowDataType::D: WriteValue(output, cpuState.D, rowPart); break;
- case RowDataType::E: WriteValue(output, cpuState.E, rowPart); break;
- case RowDataType::F: WriteValue(output, cpuState.Flags, rowPart); break;
- case RowDataType::H: WriteValue(output, cpuState.H, rowPart); break;
- case RowDataType::L: WriteValue(output, cpuState.L, rowPart); break;
- case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); break;
- case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break;
- case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break;
- case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break;
- default: break;
- }
- }
- output += _options.UseWindowsEol ? "\r\n" : "\n";
-}
-
-void TraceLogger::GetTraceRow(string &output, NesCpuState &cpuState, NesPpuState &ppuState, DisassemblyInfo &disassemblyInfo)
-{
- int originalSize = (int)output.size();
- for(RowPart& rowPart : _nesRowParts) {
- switch(rowPart.DataType) {
- case RowDataType::Text: output += rowPart.Text; break;
- case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break;
- case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, cpuState.SP, cpuState.PC, output); break;
- case RowDataType::EffectiveAddress: WriteEffectiveAddress(disassemblyInfo, rowPart, &cpuState, output, SnesMemoryType::NesMemory, CpuType::Nes); break;
- case RowDataType::MemoryValue: WriteMemoryValue(disassemblyInfo, rowPart, &cpuState, output, SnesMemoryType::NesMemory, CpuType::Nes); break;
- case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break;
-
- case RowDataType::PC: WriteValue(output, HexUtilities::ToHex((uint16_t)cpuState.PC), rowPart); break;
- case RowDataType::A: WriteValue(output, cpuState.A, rowPart); break;
- case RowDataType::X: WriteValue(output, cpuState.X, rowPart); break;
- case RowDataType::Y: WriteValue(output, cpuState.Y, rowPart); break;
- case RowDataType::SP: WriteValue(output, cpuState.SP, rowPart); break;
- case RowDataType::PS: GetStatusFlag(output, cpuState.PS, rowPart); break;
- case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break;
- case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break;
- case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break;
- case RowDataType::CycleCount:
- WriteValue(output, (uint32_t)(cpuState.CycleCount >> 32), rowPart);
- WriteValue(output, (uint32_t)cpuState.CycleCount, rowPart);
- break;
-
- default: break;
- }
- }
- output += _options.UseWindowsEol ? "\r\n" : "\n";
-}
-
-/*
-bool TraceLogger::ConditionMatches(DebugState &state, DisassemblyInfo &disassemblyInfo, OperationInfo &operationInfo)
-{
- if(!_conditionData.RpnQueue.empty()) {
- EvalResultType type;
- if(!_expEvaluator->Evaluate(_conditionData, state, type, operationInfo)) {
- if(operationInfo.OperationType == MemoryOperationType::ExecOpCode) {
- //Condition did not match, keep state/disassembly info for instruction's subsequent cycles
- _lastState = state;
- _lastDisassemblyInfo = disassemblyInfo;
- _pendingLog = true;
- }
- return false;
- }
- }
- return true;
-}
-*/
-
-void TraceLogger::GetTraceRow(string &output, CpuType cpuType, DisassemblyInfo &disassemblyInfo, BaseState &state)
-{
- PpuState ppu = {};
- GbPpuState gbPpu = {};
- NesPpuState nesPpu = {};
- switch(cpuType) {
- case CpuType::Cpu: GetTraceRow(output, (CpuState&)state, ppu, disassemblyInfo, SnesMemoryType::CpuMemory, cpuType); break;
- case CpuType::Spc: GetTraceRow(output, (SpcState&)state, ppu, disassemblyInfo); break;
- case CpuType::NecDsp: GetTraceRow(output, (NecDspState&)state, ppu, disassemblyInfo); break;
- case CpuType::Sa1: GetTraceRow(output, (CpuState&)state, ppu, disassemblyInfo, SnesMemoryType::Sa1Memory, cpuType); break;
- case CpuType::Gsu: GetTraceRow(output, (GsuState&)state, ppu, disassemblyInfo); break;
- case CpuType::Cx4: GetTraceRow(output, (Cx4State&)state, ppu, disassemblyInfo); break;
- case CpuType::Gameboy: GetTraceRow(output, (GbCpuState&)state, gbPpu, disassemblyInfo); break;
- case CpuType::Nes: GetTraceRow(output, (NesCpuState&)state, nesPpu, disassemblyInfo); break;
- default: throw std::runtime_error("Trace logger - Unsupported CPU type");
- }
-}
-
-template
-void TraceLogger::AddRow(CpuType cpuType, T& cpuState, DisassemblyInfo &disassemblyInfo)
-{
- _logCpuType[_currentPos] = cpuType;
- _disassemblyCache[_currentPos] = disassemblyInfo;
-
- switch(cpuType) {
- case CpuType::Cpu: _snesCpuState[_currentPos] = (CpuState&)cpuState; break;
- case CpuType::Spc: _spcState[_currentPos] = (SpcState&)cpuState; break;
- case CpuType::NecDsp: _necDspState[_currentPos] = (NecDspState&)cpuState; break;
- case CpuType::Sa1: _snesCpuState[_currentPos] = (CpuState&)cpuState; break;
- case CpuType::Gsu: _gsuState[_currentPos] = (GsuState&)cpuState; break;
- case CpuType::Cx4: _cx4State[_currentPos] = (Cx4State&)cpuState; break;
- case CpuType::Gameboy: _gbCpuState[_currentPos] = (GbCpuState&)cpuState; break;
- case CpuType::Nes: _nesCpuState[_currentPos] = (NesCpuState&)cpuState; break;
- default: throw std::runtime_error("Trace logger - Unsupported CPU type");
- }
-
- _pendingLog = false;
-
- if(_logCount < ExecutionLogSize) {
- _logCount++;
- }
-
- if(_logToFile) {
- GetTraceRow(_outputBuffer, cpuType, _disassemblyCache[_currentPos], cpuState);
- if(_outputBuffer.size() > 32768) {
- _outputFile << _outputBuffer;
- _outputBuffer.clear();
- }
- }
-
- _currentPos = (_currentPos + 1) % ExecutionLogSize;
-}
-/*
-void TraceLogger::LogNonExec(OperationInfo& operationInfo)
-{
- if(_pendingLog) {
- if(ConditionMatches(_lastState, _lastDisassemblyInfo, operationInfo)) {
- AddRow(_lastDisassemblyInfo, _lastState);
- }
- }
-}*/
-
-template
-void TraceLogger::Log(CpuType cpuType, T& cpuState, DisassemblyInfo &disassemblyInfo)
-{
- if(_logCpu[(int)cpuType]) {
- //For the sake of performance, only log data for the CPUs we're actively displaying/logging
- //if(ConditionMatches(state, disassemblyInfo, operationInfo)) {
- AddRow(cpuType, cpuState, disassemblyInfo);
- //}
- }
-}
-
-void TraceLogger::Clear()
-{
- _logCount = 0;
-}
-
-const char* TraceLogger::GetExecutionTrace(uint32_t lineCount)
-{
- DebugBreakHelper helper(_debugger);
- _executionTrace.clear();
-
- int startPos = (_currentPos > 0 ? _currentPos : TraceLogger::ExecutionLogSize) - 1;
-
- bool enabled = false;
- for(int i = 0; i <= (int)DebugUtilities::GetLastCpuType(); i++) {
- enabled |= _logCpu[i];
- }
-
- if(enabled && lineCount > 0) {
- for(int i = 0; i < TraceLogger::ExecutionLogSize; i++) {
- int index = (startPos - i);
- if(index < 0) {
- index = TraceLogger::ExecutionLogSize + index;
- }
-
- if((i > 0 && startPos == index) || !_disassemblyCache[index].IsInitialized()) {
- //If the entire array was checked, or this element is not initialized, stop
- break;
- }
-
- CpuType cpuType = _logCpuType[index];
- if(!_logCpu[(int)cpuType]) {
- //This line isn't for a CPU currently being logged
- continue;
- }
-
- BaseState* state;
- switch(cpuType) {
- case CpuType::Cpu: {
- state = &_snesCpuState[index];
- CpuState* snesCpu = (CpuState*)state;
- _executionTrace += "\x2\x1" + HexUtilities::ToHex24((snesCpu->K << 16) | snesCpu->PC) + "\x1";
- break;
- }
-
- case CpuType::Spc: {
- state = &_spcState[index];
- SpcState* spc = (SpcState*)state;
- _executionTrace += "\x3\x1" + HexUtilities::ToHex(spc->PC) + "\x1";
- break;
- }
-
- case CpuType::NecDsp: {
- state = &_spcState[index];
- NecDspState* necDsp = (NecDspState*)state;
- _executionTrace += "\x4\x1" + HexUtilities::ToHex(necDsp->PC) + "\x1";
- break;
- }
-
- case CpuType::Sa1: {
- state = &_snesCpuState[index];
- CpuState* sa1 = (CpuState*)state;
- _executionTrace += "\x4\x1" + HexUtilities::ToHex24((sa1->K << 16) | sa1->PC) + "\x1";
- break;
- }
-
- case CpuType::Gsu: {
- state = &_gsuState[index];
- GsuState* gsu = (GsuState*)state;
- _executionTrace += "\x4\x1" + HexUtilities::ToHex24((gsu->ProgramBank << 16) | gsu->R[15]) + "\x1";
- break;
- }
-
- case CpuType::Cx4: {
- state = &_cx4State[index];
- Cx4State* cx4 = (Cx4State*)state;
- _executionTrace += "\x4\x1" + HexUtilities::ToHex24((cx4->Cache.Address[cx4->Cache.Page] + (cx4->PC * 2)) & 0xFFFFFF) + "\x1";
- break;
- }
-
- case CpuType::Gameboy: {
- state = &_gbCpuState[index];
- GbCpuState* gb = (GbCpuState*)state;
- _executionTrace += "\x4\x1" + HexUtilities::ToHex(gb->PC) + "\x1";
- break;
- }
-
- case CpuType::Nes: {
- state = &_nesCpuState[index];
- NesCpuState* nes = (NesCpuState*)state;
- _executionTrace += "\x4\x1" + HexUtilities::ToHex(nes->PC) + "\x1";
- break;
- }
-
- default:
- throw std::runtime_error("Trace logger - Unsupported CPU type");
- }
-
- string byteCode;
- _disassemblyCache[index].GetByteCode(byteCode);
- _executionTrace += byteCode + "\x1";
- GetTraceRow(_executionTrace, cpuType, _disassemblyCache[index], *state);
-
- lineCount--;
- if(lineCount == 0) {
- break;
- }
- }
- }
- return _executionTrace.c_str();
-}
-
-template void TraceLogger::Log(CpuType cpuType, CpuState& cpuState, DisassemblyInfo& disassemblyInfo);
-template void TraceLogger::Log(CpuType cpuType, SpcState& cpuState, DisassemblyInfo& disassemblyInfo);
-template void TraceLogger::Log(CpuType cpuType, GsuState& cpuState, DisassemblyInfo& disassemblyInfo);
-template void TraceLogger::Log(CpuType cpuType, Cx4State& cpuState, DisassemblyInfo& disassemblyInfo);
-template void TraceLogger::Log(CpuType cpuType, NecDspState& cpuState, DisassemblyInfo& disassemblyInfo);
-template void TraceLogger::Log(CpuType cpuType, GbCpuState& cpuState, DisassemblyInfo& disassemblyInfo);
-template void TraceLogger::Log(CpuType cpuType, NesCpuState& cpuState, DisassemblyInfo& disassemblyInfo);
diff --git a/Core/Debugger/TraceLogger.h b/Core/Debugger/TraceLogger.h
deleted file mode 100644
index 90643ba7..00000000
--- a/Core/Debugger/TraceLogger.h
+++ /dev/null
@@ -1,172 +0,0 @@
-#pragma once
-#include "stdafx.h"
-#include "DisassemblyInfo.h"
-#include "DebugUtilities.h"
-#include "Utilities/SimpleLock.h"
-
-class IConsole;
-class Debugger;
-class LabelManager;
-class MemoryDumper;
-class EmuSettings;
-
-struct CpuState;
-struct NecDspState;
-struct GsuState;
-struct Cx4State;
-struct PpuState;
-struct SpcState;
-struct GbPpuState;
-struct GbCpuState;
-struct NesCpuState;
-struct NesPpuState;
-struct BaseState;
-
-struct TraceLoggerOptions
-{
- bool LogCpu;
- bool LogSpc;
- bool LogNecDsp;
- bool LogSa1;
- bool LogGsu;
- bool LogCx4;
- bool LogGameboy;
- bool LogNes;
-
- bool ShowExtraInfo;
- bool IndentCode;
- bool UseLabels;
- bool UseWindowsEol;
- bool ExtendZeroPage;
-
- char Condition[1000];
- char Format[1000];
-};
-
-enum class RowDataType
-{
- Text = 0,
- ByteCode,
- Disassembly,
- EffectiveAddress,
- MemoryValue,
- Align,
- PC,
- A,
- B,
- C,
- D,
- E,
- F,
- H,
- L,
- X,
- Y,
- DB,
- SP,
- PS,
- Cycle,
- Scanline,
- HClock,
- FrameCount,
- CycleCount
-};
-
-struct RowPart
-{
- RowDataType DataType;
- string Text;
- bool DisplayInHex;
- int MinWidth;
-};
-
-class TraceLogger
-{
-private:
- static constexpr int ExecutionLogSize = 30000;
-
- //Must be static to be thread-safe when switching game
- static string _executionTrace;
-
- TraceLoggerOptions _options;
- string _outputFilepath;
- string _outputBuffer;
- ofstream _outputFile;
- IConsole* _console;
- EmuSettings* _settings;
- LabelManager* _labelManager;
- MemoryDumper* _memoryDumper;
- Debugger* _debugger;
-
- vector _rowParts;
- vector _spcRowParts;
- vector _dspRowParts;
- vector _gsuRowParts;
- vector _cx4RowParts;
- vector _gbRowParts;
- vector _nesRowParts;
-
- bool _logCpu[(int)DebugUtilities::GetLastCpuType() + 1] = {};
-
- bool _pendingLog;
- //CpuState _lastState;
- //DisassemblyInfo _lastDisassemblyInfo;
-
- bool _logToFile;
- uint32_t _currentPos;
- uint32_t _logCount;
-
- CpuState* _snesCpuState;
- SpcState* _spcState;
- NecDspState* _necDspState;
- GsuState* _gsuState;
- Cx4State* _cx4State;
- GbCpuState* _gbCpuState;
- NesCpuState* _nesCpuState;
-
- DisassemblyInfo *_disassemblyCache = nullptr;
- CpuType* _logCpuType = nullptr;
-
- template void GetStatusFlag(string &output, uint8_t ps, RowPart& part);
-
- void WriteByteCode(DisassemblyInfo &info, RowPart &rowPart, string &output);
- void WriteDisassembly(DisassemblyInfo &info, RowPart &rowPart, uint8_t sp, uint32_t pc, string &output);
- void WriteEffectiveAddress(DisassemblyInfo &info, RowPart &rowPart, void *cpuState, string &output, SnesMemoryType cpuMemoryType, CpuType cpuType);
- void WriteMemoryValue(DisassemblyInfo &info, RowPart &rowPart, void *cpuState, string &output, SnesMemoryType memType, CpuType cpuType);
- void WriteAlign(int originalSize, RowPart &rowPart, string &output);
-
- template void AddRow(CpuType cpuType, T& cpuState, DisassemblyInfo& disassemblyInfo);
-
- //bool ConditionMatches(DebugState &state, DisassemblyInfo &disassemblyInfo, OperationInfo &operationInfo);
-
- void ParseFormatString(vector &rowParts, string format);
-
- void GetTraceRow(string &output, CpuType cpuType, DisassemblyInfo &disassemblyInfo, BaseState &state);
- void GetTraceRow(string &output, CpuState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo, SnesMemoryType memType, CpuType cpuType);
- void GetTraceRow(string &output, SpcState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo);
- void GetTraceRow(string &output, NecDspState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo);
- void GetTraceRow(string &output, GsuState &gsuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo);
- void GetTraceRow(string& output, Cx4State& cx4State, PpuState& ppuState, DisassemblyInfo& disassemblyInfo);
- void GetTraceRow(string &output, GbCpuState &gbState, GbPpuState &gbPpuState, DisassemblyInfo &disassemblyInfo);
- void GetTraceRow(string& output, NesCpuState& cpuState, NesPpuState& ppuState, DisassemblyInfo& disassemblyInfo);
-
- template void WriteValue(string &output, T value, RowPart& rowPart);
-
-public:
- TraceLogger(Debugger* debugger);
- ~TraceLogger();
-
- __forceinline bool IsCpuLogged(CpuType type) { return _logCpu[(int)type]; }
-
- template void Log(CpuType cpuType, T& cpuState, DisassemblyInfo& disassemblyInfo);
-
- void Clear();
- //void LogNonExec(OperationInfo& operationInfo);
- void SetOptions(TraceLoggerOptions options);
- void StartLogging(string filename);
- void StopLogging();
-
- void LogExtraInfo(const char *log, uint32_t cycleCount);
-
- const char* GetExecutionTrace(uint32_t lineCount);
-};
diff --git a/Core/Gameboy/Debugger/GbDebugger.cpp b/Core/Gameboy/Debugger/GbDebugger.cpp
index b90a78b4..52f06e9e 100644
--- a/Core/Gameboy/Debugger/GbDebugger.cpp
+++ b/Core/Gameboy/Debugger/GbDebugger.cpp
@@ -3,9 +3,9 @@
#include "Gameboy/Debugger/GbDebugger.h"
#include "Gameboy/Debugger/GameboyDisUtils.h"
#include "Gameboy/Debugger/GbEventManager.h"
+#include "Gameboy/Debugger/GbTraceLogger.h"
#include "Debugger/DisassemblyInfo.h"
#include "Debugger/Disassembler.h"
-#include "Debugger/TraceLogger.h"
#include "Debugger/CallstackManager.h"
#include "Debugger/BreakpointManager.h"
#include "Debugger/Debugger.h"
@@ -28,7 +28,6 @@ GbDebugger::GbDebugger(Debugger* debugger)
_debugger = debugger;
_emu = debugger->GetEmulator();
- _traceLogger = debugger->GetTraceLogger().get();
_disassembler = debugger->GetDisassembler().get();
_memoryAccessCounter = debugger->GetMemoryAccessCounter().get();
@@ -39,11 +38,13 @@ GbDebugger::GbDebugger(Debugger* debugger)
}
_cpu = _gameboy->GetCpu();
+ _ppu = _gameboy->GetPpu();
_settings = debugger->GetEmulator()->GetSettings();
_codeDataLogger.reset(new CodeDataLogger(SnesMemoryType::GbPrgRom, _gameboy->DebugGetMemorySize(SnesMemoryType::GbPrgRom), CpuType::Gameboy));
+ _traceLogger.reset(new GbTraceLogger(debugger, _ppu));
- _eventManager.reset(new GbEventManager(debugger, _gameboy->GetCpu(), _gameboy->GetPpu()));
+ _eventManager.reset(new GbEventManager(debugger, _gameboy->GetCpu(), _ppu));
_callstackManager.reset(new CallstackManager(debugger));
_breakpointManager.reset(new BreakpointManager(debugger, CpuType::Gameboy, _eventManager.get()));
_step.reset(new StepRequest());
@@ -71,11 +72,11 @@ void GbDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType t
MemoryOperationInfo operation { addr, value, type };
BreakSource breakSource = BreakSource::Unspecified;
- GbCpuState state = _cpu->GetState();
+ GbCpuState& state = _cpu->GetState();
uint16_t pc = state.PC;
if(type == MemoryOperationType::ExecOpCode) {
- if(_traceLogger->IsCpuLogged(CpuType::Gameboy) || _settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled)) {
+ if(_traceLogger->IsEnabled() || _settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled)) {
if(addressInfo.Address >= 0) {
if(addressInfo.Type == SnesMemoryType::GbPrgRom) {
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code);
@@ -83,9 +84,9 @@ void GbDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType t
_disassembler->BuildCache(addressInfo, 0, CpuType::Gameboy);
}
- if(_traceLogger->IsCpuLogged(CpuType::Gameboy)) {
+ if(_traceLogger->IsEnabled()) {
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, 0, CpuType::Gameboy);
- _traceLogger->Log(CpuType::Gameboy, state, disInfo);
+ _traceLogger->Log(state, disInfo, operation);
}
}
@@ -137,12 +138,21 @@ void GbDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType t
if(addressInfo.Address >= 0 && addressInfo.Type == SnesMemoryType::GbPrgRom) {
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code);
}
+
+ if(_traceLogger->IsEnabled()) {
+ _traceLogger->LogNonExec(operation);
+ }
+
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _emu->GetMasterClock());
} else {
if(addressInfo.Address >= 0 && addressInfo.Type == SnesMemoryType::GbPrgRom) {
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Data);
}
+ if(_traceLogger->IsEnabled()) {
+ _traceLogger->LogNonExec(operation);
+ }
+
if(addr < 0xFE00 || addr >= 0xFF80) {
if(_memoryAccessCounter->ProcessMemoryRead(addressInfo, _emu->GetMasterClock())) {
//Memory access was a read on an uninitialized memory address
@@ -177,6 +187,10 @@ void GbDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType
_disassembler->InvalidateCache(addressInfo, CpuType::Gameboy);
}
+ if(_traceLogger->IsEnabled()) {
+ _traceLogger->LogNonExec(operation);
+ }
+
if(addr == 0xFFFF || (addr >= 0xFE00 && addr < 0xFF80) || (addr >= 0x8000 && addr <= 0x9FFF)) {
_eventManager->AddEvent(DebugEventType::Register, operation);
}
@@ -225,10 +239,10 @@ void GbDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool
_eventManager->AddEvent(DebugEventType::Irq);
}
-void GbDebugger::ProcessPpuCycle(uint16_t &scanline, uint16_t &cycle)
+void GbDebugger::ProcessPpuCycle(int16_t &scanline, uint16_t &cycle)
{
- scanline = _gameboy->GetPpu()->GetScanline();
- cycle = _gameboy->GetPpu()->GetCycle();
+ scanline = _ppu->GetScanline();
+ cycle = _ppu->GetCycle();
if(_step->PpuStepCount > 0) {
_step->PpuStepCount--;
@@ -238,7 +252,6 @@ void GbDebugger::ProcessPpuCycle(uint16_t &scanline, uint16_t &cycle)
}
if(cycle == 0 && scanline == _step->BreakScanline) {
- _step->BreakScanline = -1;
_debugger->SleepUntilResume(BreakSource::PpuStep);
}
}
@@ -272,3 +285,8 @@ BaseState& GbDebugger::GetState()
{
return _cpu->GetState();
}
+
+ITraceLogger* GbDebugger::GetTraceLogger()
+{
+ return _traceLogger.get();
+}
diff --git a/Core/Gameboy/Debugger/GbDebugger.h b/Core/Gameboy/Debugger/GbDebugger.h
index c01a8884..d9302a76 100644
--- a/Core/Gameboy/Debugger/GbDebugger.h
+++ b/Core/Gameboy/Debugger/GbDebugger.h
@@ -5,7 +5,7 @@
class Disassembler;
class Debugger;
-class TraceLogger;
+class GbTraceLogger;
class Gameboy;
class CallstackManager;
class MemoryAccessCounter;
@@ -17,6 +17,7 @@ class GbAssembler;
class Emulator;
class CodeDataLogger;
class GbCpu;
+class GbPpu;
enum class MemoryOperationType;
@@ -25,8 +26,8 @@ class GbDebugger final : public IDebugger
Debugger* _debugger;
Emulator* _emu;
GbCpu* _cpu;
+ GbPpu* _ppu;
Disassembler* _disassembler;
- TraceLogger* _traceLogger;
MemoryAccessCounter* _memoryAccessCounter;
Gameboy* _gameboy;
EmuSettings* _settings;
@@ -37,6 +38,7 @@ class GbDebugger final : public IDebugger
unique_ptr _breakpointManager;
unique_ptr _step;
shared_ptr _assembler;
+ unique_ptr _traceLogger;
uint8_t _prevOpCode = 0xFF;
uint32_t _prevProgramCounter = 0;
@@ -48,10 +50,10 @@ public:
void Reset() override;
- void ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type) override;
- void ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type) override;
+ void ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type);
+ void ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type);
void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi) override;
- void ProcessPpuCycle(uint16_t &scanline, uint16_t &cycle) override;
+ void ProcessPpuCycle(int16_t &scanline, uint16_t &cycle);
void Run() override;
void Step(int32_t stepCount, StepType type) override;
@@ -61,6 +63,7 @@ public:
shared_ptr GetCallstackManager() override;
shared_ptr GetCodeDataLogger() override;
BreakpointManager* GetBreakpointManager() override;
+ ITraceLogger* GetTraceLogger() override;
BaseState& GetState() override;
};
\ No newline at end of file
diff --git a/Core/Gameboy/Debugger/GbTraceLogger.cpp b/Core/Gameboy/Debugger/GbTraceLogger.cpp
new file mode 100644
index 00000000..d4a9c85b
--- /dev/null
+++ b/Core/Gameboy/Debugger/GbTraceLogger.cpp
@@ -0,0 +1,75 @@
+#include "stdafx.h"
+#include "Gameboy/Debugger/GbTraceLogger.h"
+#include "Gameboy/GbPpu.h"
+#include "Gameboy/GbTypes.h"
+#include "Debugger/DisassemblyInfo.h"
+#include "Debugger/Debugger.h"
+#include "Debugger/DebugTypes.h"
+#include "Utilities/HexUtilities.h"
+
+GbTraceLogger::GbTraceLogger(Debugger* debugger, GbPpu* ppu) : BaseTraceLogger(debugger, CpuType::Gameboy)
+{
+ _ppu = ppu;
+
+ TraceLoggerOptions options = {};
+ SetOptions(options);
+}
+
+RowDataType GbTraceLogger::GetFormatTagType(string& tag)
+{
+ if(tag == "A") {
+ return RowDataType::A;
+ } else if(tag == "B") {
+ return RowDataType::B;
+ } else if(tag == "C") {
+ return RowDataType::C;
+ } else if(tag == "D") {
+ return RowDataType::D;
+ } else if(tag == "E") {
+ return RowDataType::E;
+ } else if(tag == "F") {
+ return RowDataType::F;
+ } else if(tag == "H") {
+ return RowDataType::H;
+ } else if(tag == "L") {
+ return RowDataType::L;
+ } else if(tag == "PS") {
+ return RowDataType::PS;
+ } else if(tag == "SP") {
+ return RowDataType::SP;
+ } else {
+ return RowDataType::Text;
+ }
+}
+
+void GbTraceLogger::GetTraceRow(string &output, GbCpuState &cpuState, TraceLogPpuState &ppuState, DisassemblyInfo &disassemblyInfo)
+{
+ constexpr char activeStatusLetters[8] = { 'Z', 'N', 'H', 'C' };
+ constexpr char inactiveStatusLetters[8] = { 'z', 'n', 'h', 'c' };
+
+ for(RowPart& rowPart : _rowParts) {
+ switch(rowPart.DataType) {
+ case RowDataType::A: WriteIntValue(output, cpuState.A, rowPart); break;
+ case RowDataType::B: WriteIntValue(output, cpuState.B, rowPart); break;
+ case RowDataType::C: WriteIntValue(output, cpuState.C, rowPart); break;
+ case RowDataType::D: WriteIntValue(output, cpuState.D, rowPart); break;
+ case RowDataType::E: WriteIntValue(output, cpuState.E, rowPart); break;
+ case RowDataType::F: WriteIntValue(output, cpuState.Flags, rowPart); break;
+ case RowDataType::H: WriteIntValue(output, cpuState.H, rowPart); break;
+ case RowDataType::L: WriteIntValue(output, cpuState.L, rowPart); break;
+ case RowDataType::SP: WriteIntValue(output, cpuState.SP, rowPart); break;
+ case RowDataType::PS: GetStatusFlag(activeStatusLetters, inactiveStatusLetters, output, cpuState.Flags, rowPart, 4); break;
+ default: ProcessSharedTag(rowPart, output, cpuState, ppuState, disassemblyInfo); break;
+ }
+ }
+}
+
+void GbTraceLogger::LogPpuState()
+{
+ _ppuState[_currentPos] = {
+ _ppu->GetCycle(),
+ _ppu->GetCycle(),
+ _ppu->GetScanline(),
+ _ppu->GetFrameCount()
+ };
+}
\ No newline at end of file
diff --git a/Core/Gameboy/Debugger/GbTraceLogger.h b/Core/Gameboy/Debugger/GbTraceLogger.h
new file mode 100644
index 00000000..0b2ad6d5
--- /dev/null
+++ b/Core/Gameboy/Debugger/GbTraceLogger.h
@@ -0,0 +1,27 @@
+#pragma once
+#include "stdafx.h"
+#include "Debugger/BaseTraceLogger.h"
+#include "Gameboy/GbTypes.h"
+
+class DisassemblyInfo;
+class Debugger;
+class GbPpu;
+
+class GbTraceLogger : public BaseTraceLogger
+{
+private:
+ GbPpu* _ppu = nullptr;
+
+protected:
+ RowDataType GetFormatTagType(string& tag) override;
+
+public:
+ GbTraceLogger(Debugger* debugger, GbPpu* ppu);
+
+ void GetTraceRow(string& output, GbCpuState& cpuState, TraceLogPpuState& ppuState, DisassemblyInfo& disassemblyInfo);
+ void LogPpuState();
+
+ __forceinline uint32_t GetProgramCounter(GbCpuState& state) { return state.PC; }
+ __forceinline uint64_t GetCycleCount(GbCpuState& state) { return 0; } //TODO
+ __forceinline uint8_t GetStackPointer(GbCpuState& state) { return (uint8_t)state.SP; }
+};
diff --git a/Core/NES/Debugger/NesDebugger.cpp b/Core/NES/Debugger/NesDebugger.cpp
index b3a93e77..64c972a9 100644
--- a/Core/NES/Debugger/NesDebugger.cpp
+++ b/Core/NES/Debugger/NesDebugger.cpp
@@ -1,7 +1,6 @@
#include "stdafx.h"
#include "Debugger/DisassemblyInfo.h"
#include "Debugger/Disassembler.h"
-#include "Debugger/TraceLogger.h"
#include "Debugger/CallstackManager.h"
#include "Debugger/BreakpointManager.h"
#include "Debugger/CodeDataLogger.h"
@@ -17,6 +16,7 @@
#include "NES/Debugger/NesDebugger.h"
#include "NES/Debugger/NesAssembler.h"
#include "NES/Debugger/NesEventManager.h"
+#include "NES/Debugger/NesTraceLogger.h"
#include "Utilities/HexUtilities.h"
#include "Utilities/FolderUtilities.h"
#include "Shared/EmuSettings.h"
@@ -34,7 +34,7 @@ NesDebugger::NesDebugger(Debugger* debugger)
_ppu = console->GetPpu();
_mapper = console->GetMapper();
- _traceLogger = debugger->GetTraceLogger().get();
+ _traceLogger.reset(new NesTraceLogger(debugger, _ppu));
_disassembler = debugger->GetDisassembler().get();
_memoryAccessCounter = debugger->GetMemoryAccessCounter().get();
_settings = debugger->GetEmulator()->GetSettings();
@@ -64,13 +64,15 @@ void NesDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
{
AddressInfo addressInfo = _mapper->GetAbsoluteAddress(addr);
MemoryOperationInfo operation = { addr, value, type };
-
- NesCpuState state = _cpu->GetState();
-
+ NesCpuState& state = _cpu->GetState();
BreakSource breakSource = BreakSource::Unspecified;
+ if(IsRegister(operation)) {
+ _eventManager->AddEvent(DebugEventType::Register, operation);
+ }
+
if(type == MemoryOperationType::ExecOpCode) {
- bool needDisassemble = _traceLogger->IsCpuLogged(CpuType::Nes) || _settings->CheckDebuggerFlag(DebuggerFlags::NesDebuggerEnabled);
+ bool needDisassemble = _traceLogger->IsEnabled() || _settings->CheckDebuggerFlag(DebuggerFlags::NesDebuggerEnabled);
if(addressInfo.Address >= 0) {
if(addressInfo.Type == SnesMemoryType::NesPrgRom) {
uint8_t flags = CdlFlags::Code;
@@ -85,9 +87,9 @@ void NesDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
}
}
- if(_traceLogger->IsCpuLogged(CpuType::Nes)) {
+ if(_traceLogger->IsEnabled()) {
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, state.PS, CpuType::Nes);
- _traceLogger->Log(CpuType::Nes, state, disInfo);
+ _traceLogger->Log(state, disInfo, operation);
}
uint32_t pc = state.PC;
@@ -127,11 +129,20 @@ void NesDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
if(addressInfo.Type == SnesMemoryType::NesPrgRom && addressInfo.Address >= 0) {
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code);
}
+
+ if(_traceLogger->IsEnabled()) {
+ _traceLogger->LogNonExec(operation);
+ }
+
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _cpu->GetCycleCount());
} else {
if(addressInfo.Type == SnesMemoryType::NesPrgRom && addressInfo.Address >= 0) {
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Data);
}
+
+ if(_traceLogger->IsEnabled()) {
+ _traceLogger->LogNonExec(operation);
+ }
if(_memoryAccessCounter->ProcessMemoryRead(addressInfo, _cpu->GetCycleCount())) {
//Memory access was a read on an uninitialized memory address
@@ -148,10 +159,6 @@ void NesDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
}
}
- if(IsRegister(operation)) {
- _eventManager->AddEvent(DebugEventType::Register, operation);
- }
-
_debugger->ProcessBreakConditions(_step->StepCount == 0, _breakpointManager.get(), operation, addressInfo, breakSource);
}
@@ -167,6 +174,10 @@ void NesDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType
_eventManager->AddEvent(DebugEventType::Register, operation);
}
+ if(_traceLogger->IsEnabled()) {
+ _traceLogger->LogNonExec(operation);
+ }
+
_memoryAccessCounter->ProcessMemoryWrite(addressInfo, _cpu->GetCycleCount());
_debugger->ProcessBreakConditions(false, _breakpointManager.get(), operation, addressInfo);
@@ -208,7 +219,7 @@ void NesDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool
//_eventManager->AddEvent(forNmi ? DebugEventType::Nmi : DebugEventType::Irq);
}
-void NesDebugger::ProcessPpuCycle(uint16_t& scanline, uint16_t& cycle)
+void NesDebugger::ProcessPpuCycle(int16_t& scanline, uint16_t& cycle)
{
scanline = _ppu->GetCurrentScanline();
cycle = _ppu->GetCurrentCycle();
@@ -221,7 +232,6 @@ void NesDebugger::ProcessPpuCycle(uint16_t& scanline, uint16_t& cycle)
}
if(cycle == 0 && scanline == _step->BreakScanline) {
- _step->BreakScanline = -1;
_debugger->SleepUntilResume(BreakSource::PpuStep);
}
}
@@ -269,3 +279,8 @@ BaseState& NesDebugger::GetState()
{
return _cpu->GetState();
}
+
+ITraceLogger* NesDebugger::GetTraceLogger()
+{
+ return _traceLogger.get();
+}
diff --git a/Core/NES/Debugger/NesDebugger.h b/Core/NES/Debugger/NesDebugger.h
index a5785a9b..ed649c91 100644
--- a/Core/NES/Debugger/NesDebugger.h
+++ b/Core/NES/Debugger/NesDebugger.h
@@ -5,7 +5,6 @@
class Disassembler;
class Debugger;
-class TraceLogger;
class CallstackManager;
class MemoryAccessCounter;
class MemoryManager;
@@ -15,6 +14,7 @@ class ScriptManager;
class BreakpointManager;
class IAssembler;
class IEventManager;
+class NesTraceLogger;
class Emulator;
class NesCpu;
@@ -28,7 +28,6 @@ class NesDebugger final : public IDebugger
Debugger* _debugger;
Emulator* _emu;
Disassembler* _disassembler;
- TraceLogger* _traceLogger;
MemoryAccessCounter* _memoryAccessCounter;
EmuSettings* _settings;
@@ -42,6 +41,7 @@ class NesDebugger final : public IDebugger
shared_ptr _assembler;
shared_ptr _callstackManager;
unique_ptr _breakpointManager;
+ unique_ptr _traceLogger;
unique_ptr _step;
bool _enableBreakOnUninitRead = false;
@@ -55,15 +55,16 @@ public:
void Reset() override;
- void ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type) override;
- void ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type) override;
+ void ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type);
+ void ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type);
void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi) override;
- void ProcessPpuCycle(uint16_t& scanline, uint16_t& cycle) override;
+ void ProcessPpuCycle(int16_t& scanline, uint16_t& cycle);
void Run() override;
void Step(int32_t stepCount, StepType type) override;
BreakpointManager* GetBreakpointManager() override;
+ ITraceLogger* GetTraceLogger() override;
shared_ptr GetCallstackManager() override;
shared_ptr GetAssembler() override;
shared_ptr GetEventManager() override;
diff --git a/Core/NES/Debugger/NesTraceLogger.cpp b/Core/NES/Debugger/NesTraceLogger.cpp
new file mode 100644
index 00000000..4c0423b0
--- /dev/null
+++ b/Core/NES/Debugger/NesTraceLogger.cpp
@@ -0,0 +1,60 @@
+#include "stdafx.h"
+#include "NES/Debugger/NesTraceLogger.h"
+#include "NES/NesPpu.h"
+#include "NES/NesTypes.h"
+#include "Debugger/DisassemblyInfo.h"
+#include "Debugger/Debugger.h"
+#include "Debugger/DebugTypes.h"
+#include "Utilities/HexUtilities.h"
+
+NesTraceLogger::NesTraceLogger(Debugger* debugger, BaseNesPpu* ppu) : BaseTraceLogger(debugger, CpuType::Nes)
+{
+ _ppu = ppu;
+
+ TraceLoggerOptions options = {};
+ SetOptions(options);
+}
+
+RowDataType NesTraceLogger::GetFormatTagType(string& tag)
+{
+ if(tag == "A") {
+ return RowDataType::A;
+ } else if(tag == "X") {
+ return RowDataType::X;
+ } else if(tag == "Y") {
+ return RowDataType::Y;
+ } else if(tag == "P") {
+ return RowDataType::PS;
+ } else if(tag == "SP") {
+ return RowDataType::SP;
+ } else {
+ return RowDataType::Text;
+ }
+}
+
+void NesTraceLogger::GetTraceRow(string &output, NesCpuState &cpuState, TraceLogPpuState &ppuState, DisassemblyInfo &disassemblyInfo)
+{
+ constexpr char activeStatusLetters[8] = { 'N', 'V', '-', '-', 'D', 'I', 'Z', 'C' };
+ constexpr char inactiveStatusLetters[8] = { 'n', 'v', '-', '-', 'd', 'i', 'z', 'c' };
+
+ for(RowPart& rowPart : _rowParts) {
+ switch(rowPart.DataType) {
+ case RowDataType::A: WriteIntValue(output, cpuState.A, rowPart); break;
+ case RowDataType::X: WriteIntValue(output, cpuState.X, rowPart); break;
+ case RowDataType::Y: WriteIntValue(output, cpuState.Y, rowPart); break;
+ case RowDataType::SP: WriteIntValue(output, cpuState.SP, rowPart); break;
+ case RowDataType::PS: GetStatusFlag(activeStatusLetters, inactiveStatusLetters, output, cpuState.PS, rowPart); break;
+ default: ProcessSharedTag(rowPart, output, cpuState, ppuState, disassemblyInfo); break;
+ }
+ }
+}
+
+void NesTraceLogger::LogPpuState()
+{
+ _ppuState[_currentPos] = {
+ _ppu->GetCurrentCycle(),
+ _ppu->GetCurrentCycle(),
+ _ppu->GetCurrentScanline(),
+ _ppu->GetFrameCount()
+ };
+}
\ No newline at end of file
diff --git a/Core/NES/Debugger/NesTraceLogger.h b/Core/NES/Debugger/NesTraceLogger.h
new file mode 100644
index 00000000..c093cc5e
--- /dev/null
+++ b/Core/NES/Debugger/NesTraceLogger.h
@@ -0,0 +1,27 @@
+#pragma once
+#include "stdafx.h"
+#include "Debugger/BaseTraceLogger.h"
+#include "NES/NesTypes.h"
+
+class DisassemblyInfo;
+class Debugger;
+class BaseNesPpu;
+
+class NesTraceLogger : public BaseTraceLogger
+{
+private:
+ BaseNesPpu* _ppu = nullptr;
+
+protected:
+ RowDataType GetFormatTagType(string& tag) override;
+
+public:
+ NesTraceLogger(Debugger* debugger, BaseNesPpu* ppu);
+
+ void GetTraceRow(string& output, NesCpuState& cpuState, TraceLogPpuState& ppuState, DisassemblyInfo& disassemblyInfo);
+ void LogPpuState();
+
+ __forceinline uint32_t GetProgramCounter(NesCpuState& state) { return state.PC; }
+ __forceinline uint64_t GetCycleCount(NesCpuState& state) { return state.CycleCount; }
+ __forceinline uint8_t GetStackPointer(NesCpuState& state) { return (uint8_t)state.SP; }
+};
diff --git a/Core/SNES/BaseCartridge.cpp b/Core/SNES/BaseCartridge.cpp
index 99e21152..efe5ce1e 100644
--- a/Core/SNES/BaseCartridge.cpp
+++ b/Core/SNES/BaseCartridge.cpp
@@ -630,6 +630,7 @@ bool BaseCartridge::LoadGameboy(VirtualFile& romFile)
if(_coprocessorType == CoprocessorType::SGB) {
_gameboy.reset(new Gameboy(_emu, true));
if(_gameboy->LoadRom(romFile) == LoadRomResult::Success) {
+ _emu->RegisterMemory(SnesMemoryType::PrgRom, _prgRom, _prgRomSize);
return _gameboy->IsSgb();
}
}
diff --git a/Core/SNES/Console.cpp b/Core/SNES/Console.cpp
index b889e3ad..605194f8 100644
--- a/Core/SNES/Console.cpp
+++ b/Core/SNES/Console.cpp
@@ -222,7 +222,19 @@ PpuFrameInfo Console::GetPpuFrame()
vector Console::GetCpuTypes()
{
- return { CpuType::Cpu, CpuType::Spc };
+ vector cpuTypes = { CpuType::Cpu, CpuType::Spc };
+ if(_cart->GetGsu()) {
+ cpuTypes.push_back(CpuType::Gsu);
+ } else if(_cart->GetDsp()) {
+ cpuTypes.push_back(CpuType::NecDsp);
+ } else if(_cart->GetCx4()) {
+ cpuTypes.push_back(CpuType::Cx4);
+ } else if(_cart->GetGameboy()) {
+ cpuTypes.push_back(CpuType::Gameboy);
+ } else if(_cart->GetSa1()) {
+ cpuTypes.push_back(CpuType::Sa1);
+ }
+ return cpuTypes;
}
void Console::SaveBattery()
diff --git a/Core/SNES/Debugger/CpuDebugger.cpp b/Core/SNES/Debugger/CpuDebugger.cpp
index 3ce342f8..d04e4e14 100644
--- a/Core/SNES/Debugger/CpuDebugger.cpp
+++ b/Core/SNES/Debugger/CpuDebugger.cpp
@@ -10,10 +10,10 @@
#include "SNES/Debugger/SnesAssembler.h"
#include "SNES/Debugger/CpuDebugger.h"
#include "SNES/Debugger/SnesEventManager.h"
+#include "SNES/Debugger/TraceLogger/SnesCpuTraceLogger.h"
#include "Debugger/DebugTypes.h"
#include "Debugger/DisassemblyInfo.h"
#include "Debugger/Disassembler.h"
-#include "Debugger/TraceLogger.h"
#include "Debugger/CallstackManager.h"
#include "Debugger/BreakpointManager.h"
#include "Debugger/CodeDataLogger.h"
@@ -35,7 +35,6 @@ CpuDebugger::CpuDebugger(Debugger* debugger, CpuType cpuType)
_debugger = debugger;
Console* console = (Console*)debugger->GetConsole();
- _traceLogger = debugger->GetTraceLogger().get();
_disassembler = debugger->GetDisassembler().get();
_memoryAccessCounter = debugger->GetMemoryAccessCounter().get();
_cpu = console->GetCpu().get();
@@ -45,7 +44,14 @@ CpuDebugger::CpuDebugger(Debugger* debugger, CpuType cpuType)
_cart = console->GetCartridge().get();
_spc = console->GetSpc().get();
_ppu = console->GetPpu().get();
+ _traceLogger.reset(new SnesCpuTraceLogger(debugger, cpuType, _ppu, _memoryManager));
+ if(_cpuType == CpuType::Cpu) {
+ _memoryMappings = _memoryManager->GetMemoryMappings();
+ } else {
+ _memoryMappings = _sa1->GetMemoryMappings();
+ }
+
if(cpuType == CpuType::Sa1) {
_codeDataLogger = _debugger->GetCodeDataLogger(CpuType::Cpu);
} else {
@@ -62,6 +68,14 @@ CpuDebugger::CpuDebugger(Debugger* debugger, CpuType cpuType)
//Enable breaking on uninit reads when debugger is opened at power on
_enableBreakOnUninitRead = true;
}
+
+ _debuggerEnabledFlag = _cpuType == CpuType::Cpu ? DebuggerFlags::CpuDebuggerEnabled : DebuggerFlags::Sa1DebuggerEnabled;
+}
+
+void CpuDebugger::Init()
+{
+ _spcTraceLogger = _debugger->GetTraceLogger(CpuType::Spc);
+ _dspTraceLogger = _debugger->GetTraceLogger(CpuType::NecDsp);
}
void CpuDebugger::Reset()
@@ -73,29 +87,33 @@ void CpuDebugger::Reset()
void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type)
{
- AddressInfo addressInfo = GetMemoryMappings().GetAbsoluteAddress(addr);
+ AddressInfo addressInfo = _memoryMappings->GetAbsoluteAddress(addr);
MemoryOperationInfo operation = { addr, value, type };
- CpuState state = GetCpuState();
+ CpuState& state = GetCpuState();
BreakSource breakSource = BreakSource::Unspecified;
+ if(IsRegister(addr)) {
+ _eventManager->AddEvent(DebugEventType::Register, operation);
+ }
+
if(type == MemoryOperationType::ExecOpCode) {
- bool needDisassemble = _traceLogger->IsCpuLogged(_cpuType) || _settings->CheckDebuggerFlag(_cpuType == CpuType::Cpu ? DebuggerFlags::CpuDebuggerEnabled : DebuggerFlags::Sa1DebuggerEnabled);
if(addressInfo.Address >= 0) {
+ uint8_t cpuFlags = state.PS & (ProcFlags::IndexMode8 | ProcFlags::MemoryMode8);
if(addressInfo.Type == SnesMemoryType::PrgRom) {
- uint8_t flags = CdlFlags::Code | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8));
+ uint8_t flags = CdlFlags::Code | cpuFlags;
if(_prevOpCode == 0x20 || _prevOpCode == 0x22 || _prevOpCode == 0xFC) {
flags |= CdlFlags::SubEntryPoint;
}
_codeDataLogger->SetFlags(addressInfo.Address, flags);
}
- if(needDisassemble) {
- _disassembler->BuildCache(addressInfo, state.PS & (ProcFlags::IndexMode8 | ProcFlags::MemoryMode8), _cpuType);
+ if(_traceLogger->IsEnabled() || _settings->CheckDebuggerFlag(_debuggerEnabledFlag)) {
+ _disassembler->BuildCache(addressInfo, cpuFlags, _cpuType);
}
}
- if(_traceLogger->IsCpuLogged(_cpuType)) {
+ if(_traceLogger->IsEnabled()) {
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, state.PS, _cpuType);
- _traceLogger->Log(_cpuType, state, disInfo);
+ _traceLogger->Log(state, disInfo, operation);
}
uint32_t pc = (state.K << 16) | state.PC;
@@ -103,8 +121,8 @@ void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
//JSR, JSL
uint8_t opSize = DisassemblyInfo::GetOpSize(_prevOpCode, state.PS, _cpuType);
uint32_t returnPc = (_prevProgramCounter & 0xFF0000) | (((_prevProgramCounter & 0xFFFF) + opSize) & 0xFFFF);
- AddressInfo srcAddress = GetMemoryMappings().GetAbsoluteAddress(_prevProgramCounter);
- AddressInfo retAddress = GetMemoryMappings().GetAbsoluteAddress(returnPc);
+ AddressInfo srcAddress = _memoryMappings->GetAbsoluteAddress(_prevProgramCounter);
+ AddressInfo retAddress = _memoryMappings->GetAbsoluteAddress(returnPc);
_callstackManager->Push(srcAddress, _prevProgramCounter, addressInfo, pc, retAddress, returnPc, StackFrameFlags::None);
} else if(_prevOpCode == 0x60 || _prevOpCode == 0x6B || _prevOpCode == 0x40) {
//RTS, RTL, RTI
@@ -146,11 +164,17 @@ void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
if(addressInfo.Type == SnesMemoryType::PrgRom && addressInfo.Address >= 0) {
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8)));
}
+ if(_traceLogger->IsEnabled()) {
+ _traceLogger->LogNonExec(operation);
+ }
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock());
} else {
if(addressInfo.Type == SnesMemoryType::PrgRom && addressInfo.Address >= 0) {
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Data | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8)));
}
+ if(_traceLogger->IsEnabled()) {
+ _traceLogger->LogNonExec(operation);
+ }
if(_memoryAccessCounter->ProcessMemoryRead(addressInfo, _memoryManager->GetMasterClock())) {
//Memory access was a read on an uninitialized memory address
@@ -167,16 +191,12 @@ void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
}
}
- if(IsRegister(addr)) {
- _eventManager->AddEvent(DebugEventType::Register, operation);
- }
-
_debugger->ProcessBreakConditions(_step->StepCount == 0, _breakpointManager.get(), operation, addressInfo, breakSource);
}
void CpuDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type)
{
- AddressInfo addressInfo = GetMemoryMappings().GetAbsoluteAddress(addr);
+ AddressInfo addressInfo = _memoryMappings->GetAbsoluteAddress(addr);
MemoryOperationInfo operation = { addr, value, type };
if(addressInfo.Address >= 0 && (addressInfo.Type == SnesMemoryType::WorkRam || addressInfo.Type == SnesMemoryType::SaveRam)) {
_disassembler->InvalidateCache(addressInfo, _cpuType);
@@ -186,6 +206,10 @@ void CpuDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType
_eventManager->AddEvent(DebugEventType::Register, operation);
}
+ if(_traceLogger->IsEnabled()) {
+ _traceLogger->LogNonExec(operation);
+ }
+
_memoryAccessCounter->ProcessMemoryWrite(addressInfo, _memoryManager->GetMasterClock());
_debugger->ProcessBreakConditions(false, _breakpointManager.get(), operation, addressInfo);
@@ -225,25 +249,20 @@ void CpuDebugger::Step(int32_t stepCount, StepType type)
void CpuDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi)
{
- AddressInfo src = GetMemoryMappings().GetAbsoluteAddress(_prevProgramCounter);
- AddressInfo ret = GetMemoryMappings().GetAbsoluteAddress(originalPc);
- AddressInfo dest = GetMemoryMappings().GetAbsoluteAddress(currentPc);
+ AddressInfo src = _memoryMappings->GetAbsoluteAddress(_prevProgramCounter);
+ AddressInfo ret = _memoryMappings->GetAbsoluteAddress(originalPc);
+ AddressInfo dest = _memoryMappings->GetAbsoluteAddress(currentPc);
_callstackManager->Push(src, _prevProgramCounter, dest, currentPc, ret, originalPc, forNmi ? StackFrameFlags::Nmi : StackFrameFlags::Irq);
_eventManager->AddEvent(forNmi ? DebugEventType::Nmi : DebugEventType::Irq);
}
-void CpuDebugger::ProcessPpuCycle(uint16_t &scanline, uint16_t &cycle)
+void CpuDebugger::ProcessPpuCycle(int16_t &scanline, uint16_t &cycle)
{
- if(_cpuType == CpuType::Cpu) {
- scanline = _ppu->GetScanline();
- cycle = _memoryManager->GetHClock();
-
- //Catch up SPC/DSP as needed (if we're tracing or debugging those particular CPUs)
- if(_traceLogger->IsCpuLogged(CpuType::Spc) || _settings->CheckDebuggerFlag(DebuggerFlags::SpcDebuggerEnabled)) {
- _spc->Run();
- } else if(_traceLogger->IsCpuLogged(CpuType::NecDsp)) {
- _cart->RunCoprocessors();
- }
+ //Catch up SPC/DSP as needed (if we're tracing or debugging those particular CPUs)
+ if(_spcTraceLogger->IsEnabled()) {
+ _spc->Run();
+ } else if(_dspTraceLogger && _dspTraceLogger->IsEnabled()) {
+ _cart->RunCoprocessors();
}
if(_step->PpuStepCount > 0) {
@@ -253,18 +272,11 @@ void CpuDebugger::ProcessPpuCycle(uint16_t &scanline, uint16_t &cycle)
}
}
- if(cycle == 0 && scanline == _step->BreakScanline) {
- _step->BreakScanline = -1;
- _debugger->SleepUntilResume(BreakSource::PpuStep);
- }
-}
+ scanline = _ppu->GetScanline();
+ cycle = _memoryManager->GetHClock();
-MemoryMappings& CpuDebugger::GetMemoryMappings()
-{
- if(_cpuType == CpuType::Cpu) {
- return *_memoryManager->GetMemoryMappings();
- } else {
- return *_sa1->GetMemoryMappings();
+ if(cycle == 0 && scanline == _step->BreakScanline) {
+ _debugger->SleepUntilResume(BreakSource::PpuStep);
}
}
@@ -287,6 +299,11 @@ shared_ptr CpuDebugger::GetCallstackManager()
return _callstackManager;
}
+ITraceLogger* CpuDebugger::GetTraceLogger()
+{
+ return _traceLogger.get();
+}
+
BreakpointManager* CpuDebugger::GetBreakpointManager()
{
return _breakpointManager.get();
diff --git a/Core/SNES/Debugger/CpuDebugger.h b/Core/SNES/Debugger/CpuDebugger.h
index 7c6d8abc..8c18dacc 100644
--- a/Core/SNES/Debugger/CpuDebugger.h
+++ b/Core/SNES/Debugger/CpuDebugger.h
@@ -6,7 +6,7 @@
class Disassembler;
class Debugger;
-class TraceLogger;
+class SnesCpuTraceLogger;
class Cpu;
class CallstackManager;
class MemoryAccessCounter;
@@ -28,7 +28,6 @@ class CpuDebugger final : public IDebugger
{
Debugger* _debugger;
Disassembler* _disassembler;
- TraceLogger* _traceLogger;
MemoryAccessCounter* _memoryAccessCounter;
MemoryManager* _memoryManager;
EmuSettings* _settings;
@@ -37,37 +36,43 @@ class CpuDebugger final : public IDebugger
BaseCartridge* _cart;
Spc* _spc;
Ppu* _ppu;
+ MemoryMappings* _memoryMappings;
shared_ptr _codeDataLogger;
-
shared_ptr _eventManager;
shared_ptr _assembler;
shared_ptr _callstackManager;
unique_ptr _breakpointManager;
unique_ptr _step;
+ unique_ptr _traceLogger;
+
+ ITraceLogger* _spcTraceLogger = nullptr;
+ ITraceLogger* _dspTraceLogger = nullptr;
+ DebuggerFlags _debuggerEnabledFlag = DebuggerFlags::CpuDebuggerEnabled;
CpuType _cpuType;
bool _enableBreakOnUninitRead = false;
uint8_t _prevOpCode = 0xFF;
uint32_t _prevProgramCounter = 0;
- MemoryMappings& GetMemoryMappings();
CpuState& GetCpuState();
bool IsRegister(uint32_t addr);
public:
CpuDebugger(Debugger* debugger, CpuType cpuType);
+ void Init() override;
void Reset() override;
- void ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type) override;
- void ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type) override;
+ void ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type);
+ void ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type);
void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi) override;
- void ProcessPpuCycle(uint16_t &scanline, uint16_t &cycle) override;
+ void ProcessPpuCycle(int16_t &scanline, uint16_t &cycle);
void Run() override;
void Step(int32_t stepCount, StepType type) override;
+ ITraceLogger* GetTraceLogger() override;
BreakpointManager* GetBreakpointManager() override;
shared_ptr GetCallstackManager() override;
shared_ptr GetAssembler() override;
diff --git a/Core/SNES/Debugger/Cx4Debugger.cpp b/Core/SNES/Debugger/Cx4Debugger.cpp
index 64744489..aa536014 100644
--- a/Core/SNES/Debugger/Cx4Debugger.cpp
+++ b/Core/SNES/Debugger/Cx4Debugger.cpp
@@ -2,7 +2,6 @@
#include "Cx4Debugger.h"
#include "Debugger/DisassemblyInfo.h"
#include "Debugger/Disassembler.h"
-#include "Debugger/TraceLogger.h"
#include "Debugger/CallstackManager.h"
#include "Debugger/BreakpointManager.h"
#include "Debugger/Debugger.h"
@@ -12,6 +11,7 @@
#include "SNES/BaseCartridge.h"
#include "SNES/MemoryManager.h"
#include "SNES/Console.h"
+#include "SNES/Debugger/TraceLogger/Cx4TraceLogger.h"
#include "SNES/Coprocessors/CX4/Cx4.h"
#include "Shared/Emulator.h"
#include "Shared/EmuSettings.h"
@@ -20,14 +20,17 @@
Cx4Debugger::Cx4Debugger(Debugger* debugger)
{
+ Console* console = (Console*)debugger->GetConsole();
+
_debugger = debugger;
_codeDataLogger = debugger->GetCodeDataLogger(CpuType::Cpu).get();
- _traceLogger = debugger->GetTraceLogger().get();
_disassembler = debugger->GetDisassembler().get();
_memoryAccessCounter = debugger->GetMemoryAccessCounter().get();
- _cx4 = ((Console*)debugger->GetConsole())->GetCartridge()->GetCx4();
- _memoryManager = ((Console*)debugger->GetConsole())->GetMemoryManager().get();
+ _cx4 = console->GetCartridge()->GetCx4();
+ _memoryManager = console->GetMemoryManager().get();
_settings = debugger->GetEmulator()->GetSettings();
+
+ _traceLogger.reset(new Cx4TraceLogger(debugger, console->GetPpu().get(), _memoryManager));
_breakpointManager.reset(new BreakpointManager(debugger, CpuType::Cx4));
_step.reset(new StepRequest());
@@ -39,7 +42,7 @@ void Cx4Debugger::Reset()
void Cx4Debugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type)
{
- Cx4State state = _cx4->GetState();
+ Cx4State& state = _cx4->GetState();
addr = (state.Cache.Address[state.Cache.Page] + (state.PC * 2)) & 0xFFFFFF;
AddressInfo addressInfo = _cx4->GetMemoryMappings()->GetAbsoluteAddress(addr);
@@ -52,12 +55,12 @@ void Cx4Debugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
_codeDataLogger->SetFlags(addressInfo.Address + 1, CdlFlags::Code | CdlFlags::Cx4);
}
- if(_traceLogger->IsCpuLogged(CpuType::Cx4) || _settings->CheckDebuggerFlag(DebuggerFlags::Cx4DebuggerEnabled)) {
+ if(_traceLogger->IsEnabled() || _settings->CheckDebuggerFlag(DebuggerFlags::Cx4DebuggerEnabled)) {
_disassembler->BuildCache(addressInfo, 0, CpuType::Cx4);
- if(_traceLogger->IsCpuLogged(CpuType::Cx4)) {
+ if(_traceLogger->IsEnabled()) {
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, 0, CpuType::Cx4);
- _traceLogger->Log(CpuType::Cx4, state, disInfo);
+ _traceLogger->Log(state, disInfo, operation);
}
}
@@ -73,6 +76,9 @@ void Cx4Debugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
if(addressInfo.Type == SnesMemoryType::PrgRom) {
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Data | CdlFlags::Cx4);
}
+ if(_traceLogger->IsEnabled()) {
+ _traceLogger->LogNonExec(operation);
+ }
_memoryAccessCounter->ProcessMemoryRead(addressInfo, _memoryManager->GetMasterClock());
}
@@ -85,6 +91,9 @@ void Cx4Debugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType
MemoryOperationInfo operation { (uint32_t)addr, value, type };
_debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo);
_memoryAccessCounter->ProcessMemoryWrite(addressInfo, _memoryManager->GetMasterClock());
+ if(_traceLogger->IsEnabled()) {
+ _traceLogger->LogNonExec(operation);
+ }
}
void Cx4Debugger::Run()
@@ -141,3 +150,8 @@ BaseState& Cx4Debugger::GetState()
{
return _cx4->GetState();
}
+
+ITraceLogger* Cx4Debugger::GetTraceLogger()
+{
+ return _traceLogger.get();
+}
diff --git a/Core/SNES/Debugger/Cx4Debugger.h b/Core/SNES/Debugger/Cx4Debugger.h
index 3a5fe35e..f339e958 100644
--- a/Core/SNES/Debugger/Cx4Debugger.h
+++ b/Core/SNES/Debugger/Cx4Debugger.h
@@ -5,7 +5,7 @@
class Disassembler;
class Debugger;
-class TraceLogger;
+class Cx4TraceLogger;
class CodeDataLogger;
class Cx4;
class CallstackManager;
@@ -20,7 +20,6 @@ class Cx4Debugger final : public IDebugger
{
Debugger* _debugger;
Disassembler* _disassembler;
- TraceLogger* _traceLogger;
CodeDataLogger* _codeDataLogger;
MemoryAccessCounter* _memoryAccessCounter;
MemoryManager* _memoryManager;
@@ -29,6 +28,7 @@ class Cx4Debugger final : public IDebugger
unique_ptr _breakpointManager;
unique_ptr _step;
+ unique_ptr _traceLogger;
uint32_t _prevProgramCounter = 0;
@@ -37,8 +37,8 @@ public:
void Reset() override;
- void ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type) override;
- void ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type) override;
+ void ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type);
+ void ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type);
void Run() override;
void Step(int32_t stepCount, StepType type) override;
@@ -48,6 +48,7 @@ public:
shared_ptr GetAssembler() override;
shared_ptr GetEventManager() override;
shared_ptr GetCodeDataLogger() override;
+ ITraceLogger* GetTraceLogger() override;
BaseState& GetState() override;
};
\ No newline at end of file
diff --git a/Core/SNES/Debugger/GsuDebugger.cpp b/Core/SNES/Debugger/GsuDebugger.cpp
index daa98f60..bfbe12c0 100644
--- a/Core/SNES/Debugger/GsuDebugger.cpp
+++ b/Core/SNES/Debugger/GsuDebugger.cpp
@@ -4,9 +4,9 @@
#include "SNES/Console.h"
#include "SNES/BaseCartridge.h"
#include "SNES/Coprocessors/GSU/Gsu.h"
+#include "SNES/Debugger/TraceLogger/GsuTraceLogger.h"
#include "Debugger/DisassemblyInfo.h"
#include "Debugger/Disassembler.h"
-#include "Debugger/TraceLogger.h"
#include "Debugger/CallstackManager.h"
#include "Debugger/BreakpointManager.h"
#include "Debugger/ExpressionEvaluator.h"
@@ -19,14 +19,17 @@
GsuDebugger::GsuDebugger(Debugger* debugger)
{
+ Console* console = (Console*)debugger->GetConsole();
+
_debugger = debugger;
_codeDataLogger = debugger->GetCodeDataLogger(CpuType::Cpu).get();
- _traceLogger = debugger->GetTraceLogger().get();
_disassembler = debugger->GetDisassembler().get();
_memoryAccessCounter = debugger->GetMemoryAccessCounter().get();
- _gsu = ((Console*)debugger->GetConsole())->GetCartridge()->GetGsu();
- _memoryManager = ((Console*)debugger->GetConsole())->GetMemoryManager().get();
+ _gsu = console->GetCartridge()->GetGsu();
+ _memoryManager = console->GetMemoryManager().get();
_settings = debugger->GetEmulator()->GetSettings();
+
+ _traceLogger.reset(new GsuTraceLogger(debugger, console->GetPpu().get(), _memoryManager));
_breakpointManager.reset(new BreakpointManager(debugger, CpuType::Gsu));
_step.reset(new StepRequest());
@@ -52,15 +55,15 @@ void GsuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code | CdlFlags::Gsu);
}
- if(_traceLogger->IsCpuLogged(CpuType::Gsu) || _settings->CheckDebuggerFlag(DebuggerFlags::GsuDebuggerEnabled)) {
+ if(_traceLogger->IsEnabled() || _settings->CheckDebuggerFlag(DebuggerFlags::GsuDebuggerEnabled)) {
GsuState gsuState = _gsu->GetState();
_disassembler->BuildCache(addressInfo, gsuState.SFR.GetFlagsHigh() & 0x13, CpuType::Gsu);
- if(_traceLogger->IsCpuLogged(CpuType::Gsu)) {
+ if(_traceLogger->IsEnabled()) {
gsuState.R[15] = addr;
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, 0, CpuType::Gsu);
- _traceLogger->Log(CpuType::Gsu, gsuState, disInfo);
+ _traceLogger->Log(gsuState, disInfo, operation);
}
}
@@ -75,6 +78,9 @@ void GsuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
if(addressInfo.Type == SnesMemoryType::PrgRom) {
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Data | CdlFlags::Gsu);
}
+ if(_traceLogger->IsEnabled()) {
+ _traceLogger->LogNonExec(operation);
+ }
_memoryAccessCounter->ProcessMemoryRead(addressInfo, _memoryManager->GetMasterClock());
}
@@ -87,6 +93,10 @@ void GsuDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType
MemoryOperationInfo operation { addr, value, type };
_debugger->ProcessBreakConditions(false, GetBreakpointManager(), operation, addressInfo);
+ if(_traceLogger->IsEnabled()) {
+ _traceLogger->LogNonExec(operation);
+ }
+
_disassembler->InvalidateCache(addressInfo, CpuType::Gsu);
_memoryAccessCounter->ProcessMemoryWrite(addressInfo, _memoryManager->GetMasterClock());
}
@@ -142,3 +152,8 @@ BaseState& GsuDebugger::GetState()
{
return _gsu->GetState();
}
+
+ITraceLogger* GsuDebugger::GetTraceLogger()
+{
+ return _traceLogger.get();
+}
diff --git a/Core/SNES/Debugger/GsuDebugger.h b/Core/SNES/Debugger/GsuDebugger.h
index bd7907f1..63863a55 100644
--- a/Core/SNES/Debugger/GsuDebugger.h
+++ b/Core/SNES/Debugger/GsuDebugger.h
@@ -5,13 +5,13 @@
class Disassembler;
class Debugger;
-class TraceLogger;
class CodeDataLogger;
class Gsu;
class MemoryAccessCounter;
class MemoryManager;
class BreakpointManager;
class EmuSettings;
+class GsuTraceLogger;
enum class MemoryOperationType;
@@ -19,7 +19,6 @@ class GsuDebugger final : public IDebugger
{
Debugger* _debugger;
Disassembler* _disassembler;
- TraceLogger* _traceLogger;
CodeDataLogger* _codeDataLogger;
MemoryAccessCounter* _memoryAccessCounter;
MemoryManager* _memoryManager;
@@ -28,6 +27,7 @@ class GsuDebugger final : public IDebugger
unique_ptr _breakpointManager;
unique_ptr _step;
+ unique_ptr _traceLogger;
uint8_t _prevOpCode = 0xFF;
uint32_t _prevProgramCounter = 0;
@@ -37,8 +37,8 @@ public:
void Reset() override;
- void ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type) override;
- void ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type) override;
+ void ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type);
+ void ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type);
void Run() override;
void Step(int32_t stepCount, StepType type) override;
@@ -48,6 +48,7 @@ public:
shared_ptr GetAssembler() override;
shared_ptr GetEventManager() override;
shared_ptr GetCodeDataLogger() override;
+ ITraceLogger* GetTraceLogger() override;
BaseState& GetState() override;
};
\ No newline at end of file
diff --git a/Core/SNES/Debugger/NecDspDebugger.cpp b/Core/SNES/Debugger/NecDspDebugger.cpp
index 59c2251f..6d28eab6 100644
--- a/Core/SNES/Debugger/NecDspDebugger.cpp
+++ b/Core/SNES/Debugger/NecDspDebugger.cpp
@@ -4,9 +4,9 @@
#include "SNES/Console.h"
#include "SNES/Coprocessors/DSP/NecDsp.h"
#include "SNES/Debugger/NecDspDebugger.h"
+#include "SNES/Debugger/TraceLogger/NecDspTraceLogger.h"
#include "Debugger/DisassemblyInfo.h"
#include "Debugger/Disassembler.h"
-#include "Debugger/TraceLogger.h"
#include "Debugger/CallstackManager.h"
#include "Debugger/BreakpointManager.h"
#include "Debugger/Debugger.h"
@@ -18,11 +18,14 @@
NecDspDebugger::NecDspDebugger(Debugger* debugger)
{
+ Console* console = (Console*)debugger->GetConsole();
+
_debugger = debugger;
- _traceLogger = debugger->GetTraceLogger().get();
_disassembler = debugger->GetDisassembler().get();
- _dsp = ((Console*)debugger->GetConsole())->GetCartridge()->GetDsp();
+ _dsp = console->GetCartridge()->GetDsp();
_settings = debugger->GetEmulator()->GetSettings();
+
+ _traceLogger.reset(new NecDspTraceLogger(debugger, console->GetPpu().get(), console->GetMemoryManager().get()));
_breakpointManager.reset(new BreakpointManager(debugger, CpuType::NecDsp));
_step.reset(new StepRequest());
@@ -38,13 +41,12 @@ void NecDspDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationTy
MemoryOperationInfo operation { (uint32_t)addr, value, type };
if(type == MemoryOperationType::ExecOpCode) {
- if(_traceLogger->IsCpuLogged(CpuType::NecDsp) || _settings->CheckDebuggerFlag(DebuggerFlags::NecDspDebuggerEnabled)) {
+ if(_traceLogger->IsEnabled() || _settings->CheckDebuggerFlag(DebuggerFlags::NecDspDebuggerEnabled)) {
_disassembler->BuildCache(addressInfo, 0, CpuType::NecDsp);
- if(_traceLogger->IsCpuLogged(CpuType::NecDsp)) {
+ if(_traceLogger->IsEnabled()) {
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, 0, CpuType::NecDsp);
- NecDspState state = _dsp->GetState();
- _traceLogger->Log(CpuType::NecDsp, state, disInfo);
+ _traceLogger->Log(_dsp->GetState(), disInfo, operation);
}
}
@@ -63,6 +65,10 @@ void NecDspDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationT
AddressInfo addressInfo { (int32_t)addr, SnesMemoryType::DspDataRam }; //Writes never affect the DSP ROM
MemoryOperationInfo operation { addr, value, type };
_debugger->ProcessBreakConditions(false, GetBreakpointManager(), operation, addressInfo);
+
+ if(_traceLogger->IsEnabled()) {
+ _traceLogger->LogNonExec(operation);
+ }
}
void NecDspDebugger::Run()
@@ -119,3 +125,8 @@ BaseState& NecDspDebugger::GetState()
{
return _dsp->GetState();
}
+
+ITraceLogger* NecDspDebugger::GetTraceLogger()
+{
+ return _traceLogger.get();
+}
diff --git a/Core/SNES/Debugger/NecDspDebugger.h b/Core/SNES/Debugger/NecDspDebugger.h
index f6eb2be9..c923a3e7 100644
--- a/Core/SNES/Debugger/NecDspDebugger.h
+++ b/Core/SNES/Debugger/NecDspDebugger.h
@@ -5,7 +5,7 @@
class Disassembler;
class Debugger;
-class TraceLogger;
+class NecDspTraceLogger;
class NecDsp;
class CallstackManager;
class MemoryAccessCounter;
@@ -19,12 +19,12 @@ class NecDspDebugger final : public IDebugger
{
Debugger* _debugger;
Disassembler* _disassembler;
- TraceLogger* _traceLogger;
NecDsp* _dsp;
EmuSettings* _settings;
unique_ptr _breakpointManager;
unique_ptr _step;
+ unique_ptr _traceLogger;
uint32_t _prevProgramCounter = 0;
@@ -33,8 +33,8 @@ public:
void Reset() override;
- void ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type) override;
- void ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type) override;
+ void ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type);
+ void ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type);
void Run() override;
void Step(int32_t stepCount, StepType type) override;
@@ -44,7 +44,7 @@ public:
shared_ptr GetAssembler() override;
shared_ptr GetEventManager() override;
shared_ptr GetCodeDataLogger() override;
+ ITraceLogger* GetTraceLogger() override;
- // Inherited via IDebugger
- virtual BaseState& GetState() override;
+ BaseState& GetState() override;
};
\ No newline at end of file
diff --git a/Core/SNES/Debugger/SpcDebugger.cpp b/Core/SNES/Debugger/SpcDebugger.cpp
index 954d43b7..e94d3b65 100644
--- a/Core/SNES/Debugger/SpcDebugger.cpp
+++ b/Core/SNES/Debugger/SpcDebugger.cpp
@@ -3,9 +3,9 @@
#include "SNES/MemoryManager.h"
#include "SNES/Console.h"
#include "SNES/Debugger/SpcDebugger.h"
+#include "SNES/Debugger/TraceLogger/SpcTraceLogger.h"
#include "Debugger/DisassemblyInfo.h"
#include "Debugger/Disassembler.h"
-#include "Debugger/TraceLogger.h"
#include "Debugger/CallstackManager.h"
#include "Debugger/BreakpointManager.h"
#include "Debugger/Debugger.h"
@@ -18,13 +18,16 @@
SpcDebugger::SpcDebugger(Debugger* debugger)
{
_debugger = debugger;
- _traceLogger = debugger->GetTraceLogger().get();
_disassembler = debugger->GetDisassembler().get();
_memoryAccessCounter = debugger->GetMemoryAccessCounter().get();
- _spc = ((Console*)debugger->GetConsole())->GetSpc().get();
- _memoryManager = ((Console*)debugger->GetConsole())->GetMemoryManager().get();
+
+ Console* console = (Console*)debugger->GetConsole();
+ _spc = console->GetSpc().get();
+ _memoryManager = console->GetMemoryManager().get();
_settings = debugger->GetEmulator()->GetSettings();
+ _traceLogger.reset(new SpcTraceLogger(debugger, console->GetPpu().get(), console->GetMemoryManager().get()));
+
_callstackManager.reset(new CallstackManager(debugger));
_breakpointManager.reset(new BreakpointManager(debugger, CpuType::Spc));
_step.reset(new StepRequest());
@@ -48,14 +51,14 @@ void SpcDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
BreakSource breakSource = BreakSource::Unspecified;
if(type == MemoryOperationType::ExecOpCode) {
- SpcState spcState = _spc->GetState();
+ SpcState& spcState = _spc->GetState();
- if(_traceLogger->IsCpuLogged(CpuType::Spc) || _settings->CheckDebuggerFlag(DebuggerFlags::SpcDebuggerEnabled)) {
+ if(_traceLogger->IsEnabled() || _settings->CheckDebuggerFlag(DebuggerFlags::SpcDebuggerEnabled)) {
_disassembler->BuildCache(addressInfo, 0, CpuType::Spc);
- if(_traceLogger->IsCpuLogged(CpuType::Spc)) {
+ if(_traceLogger->IsEnabled()) {
DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, 0, CpuType::Spc);
- _traceLogger->Log(CpuType::Spc, spcState, disInfo);
+ _traceLogger->Log(spcState, disInfo, operation);
}
}
@@ -96,8 +99,14 @@ void SpcDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock());
} else if(type == MemoryOperationType::ExecOperand) {
_memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock());
+ if(_traceLogger->IsEnabled()) {
+ _traceLogger->LogNonExec(operation);
+ }
} else {
_memoryAccessCounter->ProcessMemoryRead(addressInfo, _memoryManager->GetMasterClock());
+ if(_traceLogger->IsEnabled()) {
+ _traceLogger->LogNonExec(operation);
+ }
}
_debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo, breakSource);
@@ -112,6 +121,10 @@ void SpcDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType
_disassembler->InvalidateCache(addressInfo, CpuType::Spc);
_memoryAccessCounter->ProcessMemoryWrite(addressInfo, _memoryManager->GetMasterClock());
+
+ if(_traceLogger->IsEnabled()) {
+ _traceLogger->LogNonExec(operation);
+ }
}
void SpcDebugger::Run()
@@ -173,3 +186,8 @@ BaseState& SpcDebugger::GetState()
{
return _spc->GetState();
}
+
+ITraceLogger* SpcDebugger::GetTraceLogger()
+{
+ return _traceLogger.get();
+}
diff --git a/Core/SNES/Debugger/SpcDebugger.h b/Core/SNES/Debugger/SpcDebugger.h
index 8bc93b1d..a4eca051 100644
--- a/Core/SNES/Debugger/SpcDebugger.h
+++ b/Core/SNES/Debugger/SpcDebugger.h
@@ -5,7 +5,7 @@
class Disassembler;
class Debugger;
-class TraceLogger;
+class SpcTraceLogger;
class Spc;
class CallstackManager;
class MemoryAccessCounter;
@@ -19,7 +19,6 @@ class SpcDebugger final : public IDebugger
{
Debugger* _debugger;
Disassembler* _disassembler;
- TraceLogger* _traceLogger;
MemoryAccessCounter* _memoryAccessCounter;
MemoryManager* _memoryManager;
Spc* _spc;
@@ -27,6 +26,7 @@ class SpcDebugger final : public IDebugger
shared_ptr _callstackManager;
unique_ptr _breakpointManager;
+ unique_ptr _traceLogger;
unique_ptr _step;
uint8_t _prevOpCode = 0xFF;
@@ -37,8 +37,8 @@ public:
void Reset() override;
- void ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type) override;
- void ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type) override;
+ void ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type);
+ void ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type);
void Run() override;
void Step(int32_t stepCount, StepType type) override;
@@ -48,6 +48,7 @@ public:
shared_ptr GetAssembler() override;
shared_ptr GetEventManager() override;
shared_ptr GetCodeDataLogger() override;
+ ITraceLogger* GetTraceLogger() override;
BaseState& GetState() override;
};
\ No newline at end of file
diff --git a/Core/SNES/Debugger/TraceLogger/Cx4TraceLogger.cpp b/Core/SNES/Debugger/TraceLogger/Cx4TraceLogger.cpp
new file mode 100644
index 00000000..ae0d2e6d
--- /dev/null
+++ b/Core/SNES/Debugger/TraceLogger/Cx4TraceLogger.cpp
@@ -0,0 +1,128 @@
+#include "stdafx.h"
+#include "SNES/Debugger/TraceLogger/Cx4TraceLogger.h"
+#include "SNES/Ppu.h"
+#include "SNES/MemoryManager.h"
+#include "SNES/Coprocessors/GSU/GsuTypes.h"
+#include "Debugger/DisassemblyInfo.h"
+#include "Debugger/Debugger.h"
+#include "Debugger/DebugTypes.h"
+#include "Utilities/HexUtilities.h"
+
+Cx4TraceLogger::Cx4TraceLogger(Debugger* debugger, Ppu* ppu, MemoryManager* memoryManager) : BaseTraceLogger(debugger, CpuType::Gsu)
+{
+ _ppu = ppu;
+ _memoryManager = memoryManager;
+
+ TraceLoggerOptions options = {};
+ SetOptions(options);
+}
+
+RowDataType Cx4TraceLogger::GetFormatTagType(string& tag)
+{
+ if(tag == "R0") {
+ return RowDataType::R0;
+ } else if(tag == "R1") {
+ return RowDataType::R1;
+ } else if(tag == "R2") {
+ return RowDataType::R2;
+ } else if(tag == "R3") {
+ return RowDataType::R3;
+ } else if(tag == "R4") {
+ return RowDataType::R4;
+ } else if(tag == "R5") {
+ return RowDataType::R5;
+ } else if(tag == "R6") {
+ return RowDataType::R6;
+ } else if(tag == "R7") {
+ return RowDataType::R7;
+ } else if(tag == "R8") {
+ return RowDataType::R8;
+ } else if(tag == "R9") {
+ return RowDataType::R9;
+ } else if(tag == "R10") {
+ return RowDataType::R10;
+ } else if(tag == "R11") {
+ return RowDataType::R11;
+ } else if(tag == "R12") {
+ return RowDataType::R12;
+ } else if(tag == "R13") {
+ return RowDataType::R13;
+ } else if(tag == "R14") {
+ return RowDataType::R14;
+ } else if(tag == "R15") {
+ return RowDataType::R15;
+ } else if(tag == "MAR") {
+ return RowDataType::MAR;
+ } else if(tag == "MDR") {
+ return RowDataType::MDR;
+ } else if(tag == "DPR") {
+ return RowDataType::DPR;
+ } else if(tag == "ML") {
+ return RowDataType::ML;
+ } else if(tag == "MH") {
+ return RowDataType::MH;
+ } else if(tag == "PB") {
+ return RowDataType::PB;
+ } else if(tag == "P") {
+ return RowDataType::P;
+ } else if(tag == "PS") {
+ return RowDataType::PS;
+ } else if(tag == "A") {
+ return RowDataType::A;
+ } else {
+ return RowDataType::Text;
+ }
+}
+
+void Cx4TraceLogger::GetTraceRow(string& output, Cx4State& cpuState, TraceLogPpuState& ppuState, DisassemblyInfo& disassemblyInfo)
+{
+ for(RowPart& rowPart : _rowParts) {
+ switch(rowPart.DataType) {
+ case RowDataType::PS: {
+ string status = string(cpuState.Carry ? "C" : "c") + (cpuState.Zero ? "Z" : "z") + (cpuState.Overflow ? "V" : "v") + (cpuState.Negative ? "N" : "n");
+ WriteStringValue(output, status, rowPart);
+ break;
+ }
+
+ case RowDataType::A: WriteIntValue(output, cpuState.A, rowPart); break;
+
+ case RowDataType::R0: WriteIntValue(output, cpuState.Regs[0], rowPart); break;
+ case RowDataType::R1: WriteIntValue(output, cpuState.Regs[1], rowPart); break;
+ case RowDataType::R2: WriteIntValue(output, cpuState.Regs[2], rowPart); break;
+ case RowDataType::R3: WriteIntValue(output, cpuState.Regs[3], rowPart); break;
+ case RowDataType::R4: WriteIntValue(output, cpuState.Regs[4], rowPart); break;
+ case RowDataType::R5: WriteIntValue(output, cpuState.Regs[5], rowPart); break;
+ case RowDataType::R6: WriteIntValue(output, cpuState.Regs[6], rowPart); break;
+ case RowDataType::R7: WriteIntValue(output, cpuState.Regs[7], rowPart); break;
+ case RowDataType::R8: WriteIntValue(output, cpuState.Regs[8], rowPart); break;
+ case RowDataType::R9: WriteIntValue(output, cpuState.Regs[9], rowPart); break;
+ case RowDataType::R10: WriteIntValue(output, cpuState.Regs[10], rowPart); break;
+ case RowDataType::R11: WriteIntValue(output, cpuState.Regs[11], rowPart); break;
+ case RowDataType::R12: WriteIntValue(output, cpuState.Regs[12], rowPart); break;
+ case RowDataType::R13: WriteIntValue(output, cpuState.Regs[13], rowPart); break;
+ case RowDataType::R14: WriteIntValue(output, cpuState.Regs[14], rowPart); break;
+ case RowDataType::R15: WriteIntValue(output, cpuState.Regs[15], rowPart); break;
+
+ case RowDataType::MAR: WriteIntValue(output, cpuState.MemoryAddressReg, rowPart); break;
+ case RowDataType::MDR: WriteIntValue(output, cpuState.MemoryDataReg, rowPart); break;
+ case RowDataType::DPR: WriteIntValue(output, cpuState.DataPointerReg, rowPart); break;
+ case RowDataType::ML: WriteIntValue(output, (uint32_t)(cpuState.Mult & 0xFFFFFF), rowPart); break;
+ case RowDataType::MH: WriteIntValue(output, (uint32_t)(cpuState.Mult >> 24), rowPart); break;
+
+ case RowDataType::PB: WriteIntValue(output, cpuState.PB, rowPart); break;
+ case RowDataType::P: WriteIntValue(output, cpuState.P, rowPart); break;
+
+ default: ProcessSharedTag(rowPart, output, cpuState, ppuState, disassemblyInfo); break;
+ }
+ }
+}
+
+void Cx4TraceLogger::LogPpuState()
+{
+ _ppuState[_currentPos] = {
+ _ppu->GetCycle(),
+ _memoryManager->GetHClock(),
+ _ppu->GetScanline(),
+ _ppu->GetFrameCount()
+ };
+}
\ No newline at end of file
diff --git a/Core/SNES/Debugger/TraceLogger/Cx4TraceLogger.h b/Core/SNES/Debugger/TraceLogger/Cx4TraceLogger.h
new file mode 100644
index 00000000..8b6454f4
--- /dev/null
+++ b/Core/SNES/Debugger/TraceLogger/Cx4TraceLogger.h
@@ -0,0 +1,29 @@
+#pragma once
+#include "stdafx.h"
+#include "Debugger/BaseTraceLogger.h"
+#include "SNES/Coprocessors/CX4/Cx4Types.h"
+
+class DisassemblyInfo;
+class Debugger;
+class Ppu;
+class MemoryManager;
+
+class Cx4TraceLogger : public BaseTraceLogger
+{
+private:
+ Ppu* _ppu = nullptr;
+ MemoryManager* _memoryManager = nullptr;
+
+protected:
+ RowDataType GetFormatTagType(string& tag) override;
+
+public:
+ Cx4TraceLogger(Debugger* debugger, Ppu* ppu, MemoryManager* memoryManager);
+
+ void GetTraceRow(string& output, Cx4State& cpuState, TraceLogPpuState& ppuState, DisassemblyInfo& disassemblyInfo);
+ void LogPpuState();
+
+ __forceinline uint32_t GetProgramCounter(Cx4State& state) { return (state.Cache.Address[state.Cache.Page] + (state.PC * 2)) & 0xFFFFFF; }
+ __forceinline uint64_t GetCycleCount(Cx4State& state) { return state.CycleCount; }
+ __forceinline uint8_t GetStackPointer(Cx4State& state) { return state.SP; }
+};
diff --git a/Core/SNES/Debugger/TraceLogger/GsuTraceLogger.cpp b/Core/SNES/Debugger/TraceLogger/GsuTraceLogger.cpp
new file mode 100644
index 00000000..6497ed7d
--- /dev/null
+++ b/Core/SNES/Debugger/TraceLogger/GsuTraceLogger.cpp
@@ -0,0 +1,100 @@
+#include "stdafx.h"
+#include "SNES/Debugger/TraceLogger/GsuTraceLogger.h"
+#include "SNES/Ppu.h"
+#include "SNES/MemoryManager.h"
+#include "SNES/Coprocessors/GSU/GsuTypes.h"
+#include "Debugger/DisassemblyInfo.h"
+#include "Debugger/Debugger.h"
+#include "Debugger/DebugTypes.h"
+#include "Utilities/HexUtilities.h"
+
+GsuTraceLogger::GsuTraceLogger(Debugger* debugger, Ppu* ppu, MemoryManager* memoryManager) : BaseTraceLogger(debugger, CpuType::Gsu)
+{
+ _ppu = ppu;
+ _memoryManager = memoryManager;
+
+ TraceLoggerOptions options = {};
+ SetOptions(options);
+}
+
+RowDataType GsuTraceLogger::GetFormatTagType(string& tag)
+{
+ if(tag == "R0") {
+ return RowDataType::R0;
+ } else if(tag == "R1") {
+ return RowDataType::R1;
+ } else if(tag == "R2") {
+ return RowDataType::R2;
+ } else if(tag == "R3") {
+ return RowDataType::R3;
+ } else if(tag == "R4") {
+ return RowDataType::R4;
+ } else if(tag == "R5") {
+ return RowDataType::R5;
+ } else if(tag == "R6") {
+ return RowDataType::R6;
+ } else if(tag == "R7") {
+ return RowDataType::R7;
+ } else if(tag == "R8") {
+ return RowDataType::R8;
+ } else if(tag == "R9") {
+ return RowDataType::R9;
+ } else if(tag == "R10") {
+ return RowDataType::R10;
+ } else if(tag == "R11") {
+ return RowDataType::R11;
+ } else if(tag == "R12") {
+ return RowDataType::R12;
+ } else if(tag == "R13") {
+ return RowDataType::R13;
+ } else if(tag == "R14") {
+ return RowDataType::R14;
+ } else if(tag == "R15") {
+ return RowDataType::R15;
+ } else if(tag == "SRC") {
+ return RowDataType::Src;
+ } else if(tag == "DST") {
+ return RowDataType::Dst;
+ } else {
+ return RowDataType::Text;
+ }
+}
+
+void GsuTraceLogger::GetTraceRow(string &output, GsuState &cpuState, TraceLogPpuState &ppuState, DisassemblyInfo &disassemblyInfo)
+{
+ for(RowPart& rowPart : _rowParts) {
+ switch(rowPart.DataType) {
+ case RowDataType::R0: WriteIntValue(output, cpuState.R[0], rowPart); break;
+ case RowDataType::R1: WriteIntValue(output, cpuState.R[1], rowPart); break;
+ case RowDataType::R2: WriteIntValue(output, cpuState.R[2], rowPart); break;
+ case RowDataType::R3: WriteIntValue(output, cpuState.R[3], rowPart); break;
+ case RowDataType::R4: WriteIntValue(output, cpuState.R[4], rowPart); break;
+ case RowDataType::R5: WriteIntValue(output, cpuState.R[5], rowPart); break;
+ case RowDataType::R6: WriteIntValue(output, cpuState.R[6], rowPart); break;
+ case RowDataType::R7: WriteIntValue(output, cpuState.R[7], rowPart); break;
+ case RowDataType::R8: WriteIntValue(output, cpuState.R[8], rowPart); break;
+ case RowDataType::R9: WriteIntValue(output, cpuState.R[9], rowPart); break;
+ case RowDataType::R10: WriteIntValue(output, cpuState.R[10], rowPart); break;
+ case RowDataType::R11: WriteIntValue(output, cpuState.R[11], rowPart); break;
+ case RowDataType::R12: WriteIntValue(output, cpuState.R[12], rowPart); break;
+ case RowDataType::R13: WriteIntValue(output, cpuState.R[13], rowPart); break;
+ case RowDataType::R14: WriteIntValue(output, cpuState.R[14], rowPart); break;
+ case RowDataType::R15: WriteIntValue(output, cpuState.R[15], rowPart); break;
+
+ case RowDataType::Src: WriteIntValue(output, cpuState.SrcReg, rowPart); break;
+ case RowDataType::Dst: WriteIntValue(output, cpuState.DestReg, rowPart); break;
+
+ default: ProcessSharedTag(rowPart, output, cpuState, ppuState, disassemblyInfo); break;
+ }
+ }
+}
+
+void GsuTraceLogger::LogPpuState()
+{
+ _ppuState[_currentPos] = {
+ _ppu->GetCycle(),
+ _memoryManager->GetHClock(),
+ _ppu->GetScanline(),
+ _ppu->GetFrameCount()
+ };
+}
\ No newline at end of file
diff --git a/Core/SNES/Debugger/TraceLogger/GsuTraceLogger.h b/Core/SNES/Debugger/TraceLogger/GsuTraceLogger.h
new file mode 100644
index 00000000..af256c44
--- /dev/null
+++ b/Core/SNES/Debugger/TraceLogger/GsuTraceLogger.h
@@ -0,0 +1,29 @@
+#pragma once
+#include "stdafx.h"
+#include "Debugger/BaseTraceLogger.h"
+#include "SNES/Coprocessors/GSU/GsuTypes.h"
+
+class DisassemblyInfo;
+class Debugger;
+class Ppu;
+class MemoryManager;
+
+class GsuTraceLogger : public BaseTraceLogger
+{
+private:
+ Ppu* _ppu = nullptr;
+ MemoryManager* _memoryManager = nullptr;
+
+protected:
+ RowDataType GetFormatTagType(string& tag) override;
+
+public:
+ GsuTraceLogger(Debugger* debugger, Ppu* ppu, MemoryManager* memoryManager);
+
+ void GetTraceRow(string& output, GsuState& cpuState, TraceLogPpuState& ppuState, DisassemblyInfo& disassemblyInfo);
+ void LogPpuState();
+
+ __forceinline uint32_t GetProgramCounter(GsuState& state) { return (state.ProgramBank << 16) | state.R[15]; }
+ __forceinline uint64_t GetCycleCount(GsuState& state) { return state.CycleCount; }
+ __forceinline uint8_t GetStackPointer(GsuState& state) { return 0; }
+};
diff --git a/Core/SNES/Debugger/TraceLogger/NecDspTraceLogger.cpp b/Core/SNES/Debugger/TraceLogger/NecDspTraceLogger.cpp
new file mode 100644
index 00000000..1785b07a
--- /dev/null
+++ b/Core/SNES/Debugger/TraceLogger/NecDspTraceLogger.cpp
@@ -0,0 +1,105 @@
+#include "stdafx.h"
+#include "SNES/Debugger/TraceLogger/NecDspTraceLogger.h"
+#include "SNES/Ppu.h"
+#include "SNES/MemoryManager.h"
+#include "SNES/Coprocessors/GSU/GsuTypes.h"
+#include "Debugger/DisassemblyInfo.h"
+#include "Debugger/Debugger.h"
+#include "Debugger/DebugTypes.h"
+#include "Utilities/HexUtilities.h"
+
+NecDspTraceLogger::NecDspTraceLogger(Debugger* debugger, Ppu* ppu, MemoryManager* memoryManager) : BaseTraceLogger(debugger, CpuType::Gsu)
+{
+ _ppu = ppu;
+ _memoryManager = memoryManager;
+
+ TraceLoggerOptions options = {};
+ SetOptions(options);
+}
+
+RowDataType NecDspTraceLogger::GetFormatTagType(string& tag)
+{
+ if(tag == "A") {
+ return RowDataType::A;
+ } else if(tag == "B") {
+ return RowDataType::B;
+ }if(tag == "FlagsA") {
+ return RowDataType::FlagsA;
+ } else if(tag == "FlagsB") {
+ return RowDataType::FlagsB;
+ } else if(tag == "K") {
+ return RowDataType::K;
+ } else if(tag == "L") {
+ return RowDataType::L;
+ } else if(tag == "M") {
+ return RowDataType::M;
+ } else if(tag == "N") {
+ return RowDataType::N;
+ } else if(tag == "RP") {
+ return RowDataType::RP;
+ } else if(tag == "DP") {
+ return RowDataType::DP;
+ } else if(tag == "DR") {
+ return RowDataType::DR;
+ } else if(tag == "SR") {
+ return RowDataType::SR;
+ } else if(tag == "TR") {
+ return RowDataType::TR;
+ } else if(tag == "TRB") {
+ return RowDataType::TRB;
+ } else if(tag == "R12") {
+ return RowDataType::R12;
+ } else if(tag == "R13") {
+ return RowDataType::R13;
+ } else if(tag == "R14") {
+ return RowDataType::R14;
+ } else if(tag == "R15") {
+ return RowDataType::R15;
+ } else if(tag == "SRC") {
+ return RowDataType::Src;
+ } else if(tag == "DST") {
+ return RowDataType::Dst;
+ } else {
+ return RowDataType::Text;
+ }
+}
+
+void NecDspTraceLogger::WriteAccFlagsValue(string& output, NecDspAccFlags flags, RowPart& rowPart)
+{
+ string status = string(flags.Carry ? "C" : "c") + (flags.Zero ? "Z" : "z") + (flags.Overflow0 ? "V" : "v") + (flags.Overflow1 ? "V" : "v") + (flags.Sign0 ? "N" : "n") + (flags.Sign1 ? "N" : "n");
+ WriteStringValue(output, status, rowPart);
+}
+
+void NecDspTraceLogger::GetTraceRow(string& output, NecDspState& cpuState, TraceLogPpuState& ppuState, DisassemblyInfo& disassemblyInfo)
+{
+ for(RowPart& rowPart : _rowParts) {
+ switch(rowPart.DataType) {
+ case RowDataType::A: WriteIntValue(output, cpuState.A, rowPart); break;
+ case RowDataType::FlagsA: WriteAccFlagsValue(output, cpuState.FlagsA, rowPart); break;
+ case RowDataType::B: WriteIntValue(output, cpuState.B, rowPart); break;
+ case RowDataType::FlagsB: WriteAccFlagsValue(output, cpuState.FlagsB, rowPart); break;
+ case RowDataType::K: WriteIntValue(output, cpuState.K, rowPart); break;
+ case RowDataType::L: WriteIntValue(output, cpuState.L, rowPart); break;
+ case RowDataType::M: WriteIntValue(output, cpuState.M, rowPart); break;
+ case RowDataType::N: WriteIntValue(output, cpuState.N, rowPart); break;
+ case RowDataType::RP: WriteIntValue(output, cpuState.RP, rowPart); break;
+ case RowDataType::DP: WriteIntValue(output, cpuState.DP, rowPart); break;
+ case RowDataType::DR: WriteIntValue(output, cpuState.DR, rowPart); break;
+ case RowDataType::SR: WriteIntValue(output, cpuState.SR, rowPart); break;
+ case RowDataType::TR: WriteIntValue(output, cpuState.TR, rowPart); break;
+ case RowDataType::TRB: WriteIntValue(output, cpuState.TRB, rowPart); break;
+
+ default: ProcessSharedTag(rowPart, output, cpuState, ppuState, disassemblyInfo); break;
+ }
+ }
+}
+
+void NecDspTraceLogger::LogPpuState()
+{
+ _ppuState[_currentPos] = {
+ _ppu->GetCycle(),
+ _memoryManager->GetHClock(),
+ _ppu->GetScanline(),
+ _ppu->GetFrameCount()
+ };
+}
\ No newline at end of file
diff --git a/Core/SNES/Debugger/TraceLogger/NecDspTraceLogger.h b/Core/SNES/Debugger/TraceLogger/NecDspTraceLogger.h
new file mode 100644
index 00000000..176e7692
--- /dev/null
+++ b/Core/SNES/Debugger/TraceLogger/NecDspTraceLogger.h
@@ -0,0 +1,31 @@
+#pragma once
+#include "stdafx.h"
+#include "Debugger/BaseTraceLogger.h"
+#include "SNES/Coprocessors/DSP/NecDspTypes.h"
+
+class DisassemblyInfo;
+class Debugger;
+class Ppu;
+class MemoryManager;
+
+class NecDspTraceLogger : public BaseTraceLogger
+{
+private:
+ Ppu* _ppu = nullptr;
+ MemoryManager* _memoryManager = nullptr;
+
+protected:
+ RowDataType GetFormatTagType(string& tag) override;
+
+ void WriteAccFlagsValue(string& output, NecDspAccFlags flags, RowPart& rowPart);
+
+public:
+ NecDspTraceLogger(Debugger* debugger, Ppu* ppu, MemoryManager* memoryManager);
+
+ void GetTraceRow(string& output, NecDspState& cpuState, TraceLogPpuState& ppuState, DisassemblyInfo& disassemblyInfo);
+ void LogPpuState();
+
+ __forceinline uint32_t GetProgramCounter(NecDspState& state) { return state.PC; }
+ __forceinline uint64_t GetCycleCount(NecDspState& state) { return 0; } //TODO
+ __forceinline uint8_t GetStackPointer(NecDspState& state) { return state.SP; }
+};
diff --git a/Core/SNES/Debugger/TraceLogger/SnesCpuTraceLogger.cpp b/Core/SNES/Debugger/TraceLogger/SnesCpuTraceLogger.cpp
new file mode 100644
index 00000000..20c8e00e
--- /dev/null
+++ b/Core/SNES/Debugger/TraceLogger/SnesCpuTraceLogger.cpp
@@ -0,0 +1,67 @@
+#include "stdafx.h"
+#include "SNES/Debugger/TraceLogger/SnesCpuTraceLogger.h"
+#include "SNES/CpuTypes.h"
+#include "SNES/Ppu.h"
+#include "SNES/MemoryManager.h"
+#include "Debugger/DisassemblyInfo.h"
+#include "Debugger/Debugger.h"
+#include "Debugger/DebugTypes.h"
+
+SnesCpuTraceLogger::SnesCpuTraceLogger(Debugger* debugger, CpuType cpuType, Ppu* ppu, MemoryManager* memoryManager) : BaseTraceLogger(debugger, cpuType)
+{
+ _ppu = ppu;
+ _memoryManager = memoryManager;
+
+ TraceLoggerOptions options = {};
+ SetOptions(options);
+}
+
+RowDataType SnesCpuTraceLogger::GetFormatTagType(string& tag)
+{
+ if(tag == "A") {
+ return RowDataType::A;
+ } else if(tag == "X") {
+ return RowDataType::X;
+ } else if(tag == "Y") {
+ return RowDataType::Y;
+ } else if(tag == "D") {
+ return RowDataType::D;
+ } else if(tag == "DB") {
+ return RowDataType::DB;
+ } else if(tag == "P") {
+ return RowDataType::PS;
+ } else if(tag == "SP") {
+ return RowDataType::SP;
+ } else {
+ return RowDataType::Text;
+ }
+}
+
+void SnesCpuTraceLogger::GetTraceRow(string &output, CpuState &cpuState, TraceLogPpuState &ppuState, DisassemblyInfo &disassemblyInfo)
+{
+ constexpr char activeStatusLetters[8] = { 'N', 'V', 'M', 'X', 'D', 'I', 'Z', 'C' };
+ constexpr char inactiveStatusLetters[8] = { 'n', 'v', 'm', 'x', 'd', 'i', 'z', 'c' };
+
+ for(RowPart& rowPart : _rowParts) {
+ switch(rowPart.DataType) {
+ case RowDataType::A: WriteIntValue(output, cpuState.A, rowPart); break;
+ case RowDataType::X: WriteIntValue(output, cpuState.X, rowPart); break;
+ case RowDataType::Y: WriteIntValue(output, cpuState.Y, rowPart); break;
+ case RowDataType::D: WriteIntValue(output, cpuState.D, rowPart); break;
+ case RowDataType::DB: WriteIntValue(output, cpuState.DBR, rowPart); break;
+ case RowDataType::SP: WriteIntValue(output, cpuState.SP, rowPart); break;
+ case RowDataType::PS: GetStatusFlag(activeStatusLetters, inactiveStatusLetters, output, cpuState.PS, rowPart); break;
+ default: ProcessSharedTag(rowPart, output, cpuState, ppuState, disassemblyInfo); break;
+ }
+ }
+}
+
+void SnesCpuTraceLogger::LogPpuState()
+{
+ _ppuState[_currentPos] = {
+ _ppu->GetCycle(),
+ _memoryManager->GetHClock(),
+ _ppu->GetScanline(),
+ _ppu->GetFrameCount()
+ };
+}
\ No newline at end of file
diff --git a/Core/SNES/Debugger/TraceLogger/SnesCpuTraceLogger.h b/Core/SNES/Debugger/TraceLogger/SnesCpuTraceLogger.h
new file mode 100644
index 00000000..ebad008b
--- /dev/null
+++ b/Core/SNES/Debugger/TraceLogger/SnesCpuTraceLogger.h
@@ -0,0 +1,29 @@
+#pragma once
+#include "stdafx.h"
+#include "Debugger/BaseTraceLogger.h"
+#include "SNES/CpuTypes.h"
+
+class DisassemblyInfo;
+class Debugger;
+class Ppu;
+class MemoryManager;
+
+class SnesCpuTraceLogger : public BaseTraceLogger
+{
+private:
+ Ppu* _ppu = nullptr;
+ MemoryManager* _memoryManager = nullptr;
+
+protected:
+ RowDataType GetFormatTagType(string& tag) override;
+
+public:
+ SnesCpuTraceLogger(Debugger* debugger, CpuType cpuType, Ppu* ppu, MemoryManager* memoryManager);
+
+ void GetTraceRow(string &output, CpuState &cpuState, TraceLogPpuState &ppuState, DisassemblyInfo &disassemblyInfo);
+ void LogPpuState();
+
+ __forceinline uint32_t GetProgramCounter(CpuState& state) { return (state.K << 16) | state.PC; }
+ __forceinline uint64_t GetCycleCount(CpuState& state) { return state.CycleCount; }
+ __forceinline uint8_t GetStackPointer(CpuState& state) { return (uint8_t)state.SP; }
+};
diff --git a/Core/SNES/Debugger/TraceLogger/SpcTraceLogger.cpp b/Core/SNES/Debugger/TraceLogger/SpcTraceLogger.cpp
new file mode 100644
index 00000000..470b0510
--- /dev/null
+++ b/Core/SNES/Debugger/TraceLogger/SpcTraceLogger.cpp
@@ -0,0 +1,61 @@
+#include "stdafx.h"
+#include "SNES/Debugger/TraceLogger/SpcTraceLogger.h"
+#include "SNES/CpuTypes.h"
+#include "SNES/Ppu.h"
+#include "SNES/MemoryManager.h"
+#include "Debugger/DisassemblyInfo.h"
+#include "Debugger/Debugger.h"
+#include "Debugger/DebugTypes.h"
+
+SpcTraceLogger::SpcTraceLogger(Debugger* debugger, Ppu* ppu, MemoryManager* memoryManager) : BaseTraceLogger(debugger, CpuType::Spc)
+{
+ _ppu = ppu;
+ _memoryManager = memoryManager;
+
+ TraceLoggerOptions options = {};
+ SetOptions(options);
+}
+
+RowDataType SpcTraceLogger::GetFormatTagType(string& tag)
+{
+ if(tag == "A") {
+ return RowDataType::A;
+ } else if(tag == "X") {
+ return RowDataType::X;
+ } else if(tag == "Y") {
+ return RowDataType::Y;
+ } else if(tag == "P") {
+ return RowDataType::PS;
+ } else if(tag == "SP") {
+ return RowDataType::SP;
+ } else {
+ return RowDataType::Text;
+ }
+}
+
+void SpcTraceLogger::GetTraceRow(string &output, SpcState &cpuState, TraceLogPpuState &ppuState, DisassemblyInfo &disassemblyInfo)
+{
+ constexpr char activeStatusLetters[8] = { 'N', 'V', 'P', 'B', 'H', 'I', 'Z', 'C' };
+ constexpr char inactiveStatusLetters[8] = { 'n', 'v', 'p', 'b', 'h', 'i', 'z', 'c' };
+
+ for(RowPart& rowPart : _rowParts) {
+ switch(rowPart.DataType) {
+ case RowDataType::A: WriteIntValue(output, cpuState.A, rowPart); break;
+ case RowDataType::X: WriteIntValue(output, cpuState.X, rowPart); break;
+ case RowDataType::Y: WriteIntValue(output, cpuState.Y, rowPart); break;
+ case RowDataType::SP: WriteIntValue(output, cpuState.SP, rowPart); break;
+ case RowDataType::PS: GetStatusFlag(activeStatusLetters, inactiveStatusLetters, output, cpuState.PS, rowPart); break;
+ default: ProcessSharedTag(rowPart, output, cpuState, ppuState, disassemblyInfo); break;
+ }
+ }
+}
+
+void SpcTraceLogger::LogPpuState()
+{
+ _ppuState[_currentPos] = {
+ _ppu->GetCycle(),
+ _memoryManager->GetHClock(),
+ _ppu->GetScanline(),
+ _ppu->GetFrameCount()
+ };
+}
\ No newline at end of file
diff --git a/Core/SNES/Debugger/TraceLogger/SpcTraceLogger.h b/Core/SNES/Debugger/TraceLogger/SpcTraceLogger.h
new file mode 100644
index 00000000..cc06529d
--- /dev/null
+++ b/Core/SNES/Debugger/TraceLogger/SpcTraceLogger.h
@@ -0,0 +1,29 @@
+#pragma once
+#include "stdafx.h"
+#include "Debugger/BaseTraceLogger.h"
+#include "SNES/SpcTypes.h"
+
+class DisassemblyInfo;
+class Debugger;
+class Ppu;
+class MemoryManager;
+
+class SpcTraceLogger : public BaseTraceLogger
+{
+private:
+ Ppu* _ppu = nullptr;
+ MemoryManager* _memoryManager = nullptr;
+
+protected:
+ RowDataType GetFormatTagType(string& tag) override;
+
+public:
+ SpcTraceLogger(Debugger* debugger, Ppu* ppu, MemoryManager* memoryManager);
+
+ void GetTraceRow(string &output, SpcState &cpuState, TraceLogPpuState &ppuState, DisassemblyInfo &disassemblyInfo);
+ void LogPpuState();
+
+ __forceinline uint32_t GetProgramCounter(SpcState& state) { return state.PC; }
+ __forceinline uint64_t GetCycleCount(SpcState& state) { return state.Cycle; }
+ __forceinline uint8_t GetStackPointer(SpcState& state) { return state.SP; }
+};
diff --git a/Core/SNES/Spc.cpp b/Core/SNES/Spc.cpp
index d4adbd64..7c1df43d 100644
--- a/Core/SNES/Spc.cpp
+++ b/Core/SNES/Spc.cpp
@@ -337,7 +337,8 @@ uint8_t Spc::DspReadRam(uint16_t addr)
{
uint8_t value = _ram[addr];
#ifndef DUMMYSPC
- _emu->ProcessMemoryRead(addr, value, MemoryOperationType::Read);
+ //TODO
+ //_emu->ProcessMemoryRead(addr, value, MemoryOperationType::Read);
#endif
return value;
}
@@ -345,7 +346,8 @@ uint8_t Spc::DspReadRam(uint16_t addr)
void Spc::DspWriteRam(uint16_t addr, uint8_t value)
{
#ifndef DUMMYSPC
- _emu->ProcessMemoryWrite(addr, value, MemoryOperationType::Write);
+ //TODO
+ //_emu->ProcessMemoryWrite(addr, value, MemoryOperationType::Write);
#endif
_ram[addr] = value;
}
diff --git a/InteropDLL/DebugApiWrapper.cpp b/InteropDLL/DebugApiWrapper.cpp
index 6a048c9d..a879fea7 100644
--- a/InteropDLL/DebugApiWrapper.cpp
+++ b/InteropDLL/DebugApiWrapper.cpp
@@ -1,7 +1,6 @@
#include "stdafx.h"
#include "Core/Shared/Emulator.h"
#include "Core/Debugger/Debugger.h"
-#include "Core/Debugger/TraceLogger.h"
#include "Core/Debugger/MemoryDumper.h"
#include "Core/Debugger/MemoryAccessCounter.h"
#include "Core/Debugger/Disassembler.h"
@@ -16,6 +15,7 @@
#include "Core/Debugger/Profiler.h"
#include "Core/Debugger/IAssembler.h"
#include "Core/Debugger/IEventManager.h"
+#include "Core/Debugger/ITraceLogger.h"
#include "Core/Gameboy/GbTypes.h"
extern shared_ptr _emu;
@@ -51,11 +51,13 @@ extern "C"
DllExport uint32_t __stdcall GetDisassemblyOutput(CpuType type, uint32_t lineIndex, CodeLineData output[], uint32_t rowCount) { return GetDebugger()->GetDisassembler()->GetDisassemblyOutput(type, lineIndex, output, rowCount); }
DllExport int32_t __stdcall SearchDisassembly(CpuType type, const char* searchString, int32_t startPosition, int32_t endPosition, bool searchBackwards) { return GetDebugger()->GetDisassembler()->SearchDisassembly(type, searchString, startPosition, endPosition, searchBackwards); }
- DllExport void __stdcall SetTraceOptions(TraceLoggerOptions options) { GetDebugger()->GetTraceLogger()->SetOptions(options); }
- DllExport void __stdcall StartTraceLogger(char* filename) { GetDebugger()->GetTraceLogger()->StartLogging(filename); }
- DllExport void __stdcall StopTraceLogger() { GetDebugger()->GetTraceLogger()->StopLogging(); }
- DllExport void __stdcall ClearTraceLog() { GetDebugger()->GetTraceLogger()->Clear(); }
- DllExport const char* GetExecutionTrace(uint32_t lineCount) { return GetDebugger()->GetTraceLogger()->GetExecutionTrace(lineCount); }
+ //DllExport void __stdcall ClearTraceLog() { GetDebugger()->GetTraceLogger()->Clear(); }
+
+ DllExport void __stdcall SetTraceOptions(CpuType type, TraceLoggerOptions options) { GetDebugger()->GetTraceLogger(type)->SetOptions(options); }
+ DllExport uint32_t __stdcall GetExecutionTrace(TraceRow output[], uint32_t startOffset, uint32_t lineCount) { return GetDebugger()->GetExecutionTrace(output, startOffset, lineCount); }
+
+ //DllExport void __stdcall StartLogTraceToFile(char* filename) { GetDebugger()->GetTraceLogger()->StartLogging(filename); }
+ //DllExport void __stdcall StopLogTraceToFile() { GetDebugger()->GetTraceLogger()->StopLogging(); }
DllExport void __stdcall SetBreakpoints(Breakpoint breakpoints[], uint32_t length) { GetDebugger()->SetBreakpoints(breakpoints, length); }
DllExport int32_t __stdcall EvaluateExpression(char* expression, CpuType cpuType, EvalResultType *resultType, bool useCache) { return GetDebugger()->EvaluateExpression(expression, cpuType, *resultType, useCache); }
diff --git a/NewUI/Config/Debugger/DebugConfig.cs b/NewUI/Config/Debugger/DebugConfig.cs
index 9a96f9a9..de1697c2 100644
--- a/NewUI/Config/Debugger/DebugConfig.cs
+++ b/NewUI/Config/Debugger/DebugConfig.cs
@@ -13,7 +13,7 @@ namespace Mesen.Config
public class DebugConfig
{
//public DebuggerShortcutsConfig Shortcuts = new DebuggerShortcutsConfig();
- public TraceLoggerInfo TraceLogger = new TraceLoggerInfo();
+ public TraceLoggerConfig TraceLogger = new TraceLoggerConfig();
public HexEditorConfig HexEditor = new HexEditorConfig();
public EventViewerConfig EventViewer = new EventViewerConfig();
public DebuggerConfig Debugger = new DebuggerConfig();
diff --git a/NewUI/Config/Debugger/TraceLoggerConfig.cs b/NewUI/Config/Debugger/TraceLoggerConfig.cs
new file mode 100644
index 00000000..2a6a8c6d
--- /dev/null
+++ b/NewUI/Config/Debugger/TraceLoggerConfig.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml;
+using System.Xml.Serialization;
+using Avalonia;
+using Avalonia.Media;
+using Mesen.Debugger;
+using Mesen.ViewModels;
+
+namespace Mesen.Config
+{
+ public class TraceLoggerConfig : ViewModelBase
+ {
+ public bool AutoRefresh { get; set; } = true;
+
+ public Size WindowSize { get; set; } = new Size(0, 0);
+ public Point WindowLocation { get; set; } = new Point(0, 0);
+ public string FontFamily { get; set; } = DebuggerConfig.MonospaceFontFamily;
+ public FontStyle FontStyle { get; set; } = FontStyle.Normal;
+ public float FontSize { get; set; } = DebuggerConfig.DefaultFontSize;
+ public int TextZoom { get; set; } = 100;
+
+ public TraceLoggerCpuConfig SnesCpu { get; set; }
+ public TraceLoggerCpuConfig SpcCpu { get; set; }
+ public TraceLoggerCpuConfig Sa1Cpu { get; set; }
+ public TraceLoggerCpuConfig GsuCpu { get; set; }
+ public TraceLoggerCpuConfig Cx4Cpu { get; set; }
+ public TraceLoggerCpuConfig NecDspCpu { get; set; }
+
+ public TraceLoggerCpuConfig NesCpu { get; set; }
+ public TraceLoggerCpuConfig GameboyCpu { get; set; }
+
+ public TraceLoggerConfig()
+ {
+ SnesCpu = new TraceLoggerCpuConfig() {
+ Enabled = true,
+ Format = "[Disassembly][EffectiveAddress] [MemoryValue,h][Align,28] A:[A,4h] X:[X,4h] Y:[Y,4h] S:[SP,4h] D:[D,4h] DB:[DB,2h] P:[P,h] H:[HClock,3] V:[Scanline,3]"
+ };
+
+ SpcCpu = new TraceLoggerCpuConfig() {
+ Enabled = true,
+ Format = "[Disassembly][EffectiveAddress] [MemoryValue,h][Align,28] A:[A,2h] X:[X,2h] Y:[Y,2h] S:[SP,2h] P:[P,8] H:[HClock,3] V:[Scanline,3]"
+ };
+
+ Sa1Cpu = new TraceLoggerCpuConfig() {
+ Enabled = true,
+ Format = "[Disassembly][EffectiveAddress] [MemoryValue,h][Align,28] A:[A,4h] X:[X,4h] Y:[Y,4h] S:[SP,4h] D:[D,4h] DB:[DB,2h] P:[P,h] H:[HClock,3] V:[Scanline,3]"
+ };
+
+ GsuCpu = new TraceLoggerCpuConfig() {
+ Enabled = true,
+ Format = "[Disassembly][Align,28] SRC:[SRC,2h] DST:[DST,2h] R0:[R0,4h] R1:[R1,4h] R2:[R2,4h] R3:[R3,4h] R4:[R4,4h] R5:[R5,4h] R6:[R6,4h] R7:[R7,4h] R8:[R8,4h] R9:[R9,4h] R10:[R10,4h] R11:[R11,4h] R12:[R12,4h] R13:[R13,4h] R14:[R14,4h] R15:[R15,4h] H:[Cycle,3] V:[Scanline,3]"
+ };
+
+ Cx4Cpu = new TraceLoggerCpuConfig() {
+ Enabled = true,
+ Format = "[Disassembly][Align,28] A:[A,6h] MAR:[MAR,6h] MDR:[MDR,6h] DPR:[DPR,6h] ML:[ML,6h] MH:[MH,6h] P:[P,4h] PB:[PB,4h] PS:[PS] R0:[R0,6h] R1:[R1,6h] R2:[R2,6h] R3:[R3,6h] R4:[R4,6h] R5:[R5,6h] R6:[R6,6h] R7:[R7,6h] R8:[R8,6h] R9:[R9,6h] R10:[R10,6h] R11:[R11,6h] R12:[R12,6h] R13:[R13,6h] R14:[R14,6h] R15:[R15,6h] H:[Cycle,3] V:[Scanline,3]"
+ };
+
+ NecDspCpu = new TraceLoggerCpuConfig() {
+ Enabled = true,
+ Format = "[Disassembly][Align,28] A:[A,4h] [FlagsA] B:[A,4h] [FlagsB] K:[K,4h] L:[L,4h] M:[M,4h] N:[N,4h] RP:[RP,4h] DP:[DP,4h] DR:[DR,4h] SR:[SR,4h] TR:[TR,4h] TRB:[TRB,4h] H:[Cycle,3] V:[Scanline,3]"
+ };
+
+ NesCpu = new TraceLoggerCpuConfig() {
+ Enabled = true,
+ Format = "[Disassembly][EffectiveAddress] [MemoryValue,h][Align,28] A:[A,2h] X:[X,2h] Y:[Y,2h] S:[SP,2h] P:[P,h] V:[Scanline,3] H:[Cycle,3]"
+ };
+
+ GameboyCpu = new TraceLoggerCpuConfig() {
+ Enabled = true,
+ Format = "[Disassembly][EffectiveAddress] [MemoryValue,h][Align,28] A:[A,2h] B:[B,2h] C:[C,2h] D:[D,2h] E:[E,2h] F:[PS,4] HL:[H,2h][L,2h] V:[Scanline,3] H:[Cycle,3]"
+ };
+ }
+ }
+}
diff --git a/NewUI/Config/Debugger/TraceLoggerCpuConfig.cs b/NewUI/Config/Debugger/TraceLoggerCpuConfig.cs
new file mode 100644
index 00000000..6a2ad315
--- /dev/null
+++ b/NewUI/Config/Debugger/TraceLoggerCpuConfig.cs
@@ -0,0 +1,35 @@
+using ReactiveUI.Fody.Helpers;
+
+namespace Mesen.Config
+{
+ public class TraceLoggerCpuConfig : BaseConfig
+ {
+ [Reactive] public bool Enabled { get; set; }
+
+ [Reactive] public bool ShowByteCode { get; set; }
+ [Reactive] public bool ShowRegisters { get; set; }
+ [Reactive] public bool ShowCpuCycles { get; set; }
+
+ [Reactive] public bool ShowPpuCycles { get; set; }
+ [Reactive] public bool ShowPpuScanline { get; set; }
+ [Reactive] public bool ShowPpuFrames { get; set; }
+
+ [Reactive] public bool IndentCode { get; set; }
+ [Reactive] public bool ShowEffectiveAddresses { get; set; }
+ [Reactive] public bool ShowMemoryValues { get; set; }
+ [Reactive] public bool UseLabels { get; set; }
+
+ [Reactive] public StatusFlagFormat StatusFormat { get; set; }
+
+ [Reactive] public bool OverrideFormat { get; set; }
+ [Reactive] public string Format { get; set; } = "";
+ [Reactive] public string Condition { get; set; } = "";
+ }
+
+ public enum StatusFlagFormat
+ {
+ Hexadecimal = 0,
+ Text = 1,
+ CompactText = 2
+ }
+}
diff --git a/NewUI/Config/Debugger/TraceLoggerInfo.cs b/NewUI/Config/Debugger/TraceLoggerInfo.cs
deleted file mode 100644
index 34b96498..00000000
--- a/NewUI/Config/Debugger/TraceLoggerInfo.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Xml;
-using System.Xml.Serialization;
-using Avalonia;
-using Avalonia.Media;
-using Mesen.Debugger;
-
-namespace Mesen.Config
-{
- public class TraceLoggerInfo
- {
- public TraceLoggerOptions LogOptions;
- public bool AutoRefresh = true;
- public int LineCount = 1000;
-
- public Size WindowSize = new Size(0, 0);
- public Point WindowLocation;
- public string FontFamily = DebuggerConfig.MonospaceFontFamily;
- public FontStyle FontStyle = FontStyle.Normal;
- public float FontSize = DebuggerConfig.DefaultFontSize;
- public int TextZoom = 100;
-
- public TraceLoggerInfo()
- {
- LogOptions = new TraceLoggerOptions() {
- LogCpu = true,
- ShowByteCode = true,
- ShowEffectiveAddresses = true,
- ShowPpuFrames = false,
- ShowPpuCycles = true,
- ShowPpuScanline = true,
- ShowRegisters = true,
- UseLabels = false,
- StatusFormat = StatusFlagFormat.Text
- };
- }
- }
-
- public class TraceLoggerOptions
- {
- public bool LogCpu;
- public bool LogSpc;
- public bool LogNecDsp;
- public bool LogSa1;
- public bool LogGsu;
- public bool LogCx4;
- public bool LogGameboy;
-
- public bool ShowByteCode;
- public bool ShowRegisters;
- public bool ShowCpuCycles;
- public bool ShowPpuCycles;
- public bool ShowPpuScanline;
- public bool ShowPpuFrames;
- public bool ShowExtraInfo;
- public bool IndentCode;
- public bool ShowEffectiveAddresses;
- public bool ShowMemoryValues;
- public bool UseLabels;
- public bool ExtendZeroPage;
- public bool UseWindowsEol = true; //TODO
-
- public StatusFlagFormat StatusFormat;
-
- public bool OverrideFormat;
- public string Format = "";
- }
-
- public enum StatusFlagFormat
- {
- Hexadecimal = 0,
- Text = 1,
- CompactText = 2
- }
-}
diff --git a/NewUI/Debugger/Controls/DisassemblyViewer.cs b/NewUI/Debugger/Controls/DisassemblyViewer.cs
index b67462de..5c09604e 100644
--- a/NewUI/Debugger/Controls/DisassemblyViewer.cs
+++ b/NewUI/Debugger/Controls/DisassemblyViewer.cs
@@ -42,11 +42,17 @@ namespace Mesen.Debugger.Controls
private double RowHeight => this.LetterSize.Height;
private int VisibleRows => (int)(Bounds.Height / RowHeight) - 1;
+ private bool _scrollByAddress = false;
private bool _updatingScroll = false;
static DisassemblyViewer()
{
- AffectsRender(DataProviderProperty, ScrollPositionProperty, StyleProviderProperty);
+ //AffectsRender(DataProviderProperty, ScrollPositionProperty, StyleProviderProperty);
+ DataProviderProperty.Changed.AddClassHandler((x, e) => {
+ x.Refresh();
+ x.InvalidateVisual();
+ });
+
ScrollPositionProperty.Changed.AddClassHandler((x, e) => {
if(x._updatingScroll) {
return;
@@ -54,20 +60,28 @@ namespace Mesen.Debugger.Controls
x.Refresh();
- x._updatingScroll = true;
- CodeLineData[] lines = x._lines;
- if(e.OldValue is int oldValue && e.NewValue is int newValue && oldValue < newValue) {
- foreach(CodeLineData line in lines) {
- if(line.Address >= 0 && newValue < line.Address) {
- x.ScrollPosition = line.Address;
- break;
+ if(x._scrollByAddress) {
+ x._updatingScroll = true;
+ CodeLineData[] lines = x._lines;
+ if(e.OldValue is int oldValue && e.NewValue is int newValue && oldValue < newValue) {
+ foreach(CodeLineData line in lines) {
+ if(line.Address >= 0 && newValue < line.Address) {
+ x.ScrollPosition = line.Address;
+ break;
+ }
}
}
+ x._updatingScroll = false;
}
- x._updatingScroll = false;
+ x.InvalidateVisual();
});
}
+ public DisassemblyViewer()
+ {
+ ClipToBounds = true;
+ }
+
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);
@@ -76,13 +90,14 @@ namespace Mesen.Debugger.Controls
int rowNumber = (int)(p.Position.Y / LetterSize.Height);
CodeLineData[] lines = _lines;
if(rowNumber < lines.Length) {
+ CpuType cpuType = lines[rowNumber].CpuType;
AddressInfo relAddress = new AddressInfo() {
Address = lines[rowNumber].Address,
- Type = DataProvider.CpuType.ToMemoryType()
+ Type = cpuType.ToMemoryType()
};
AddressInfo absAddress = DebugApi.GetAbsoluteAddress(relAddress);
- BreakpointManager.ToggleBreakpoint(absAddress.Address < 0 ? relAddress : absAddress, DataProvider.CpuType);
+ BreakpointManager.ToggleBreakpoint(absAddress.Address < 0 ? relAddress : absAddress, cpuType);
}
}
@@ -111,14 +126,16 @@ namespace Mesen.Debugger.Controls
InitFontAndLetterSize();
_lines = dp?.GetCodeLines(scrollPosition, VisibleRows + 3) ?? new CodeLineData[0];
- foreach(CodeLineData line in _lines) {
- if(line.Address >= 0) {
- if(ScrollPosition != line.Address) {
- _updatingScroll = true;
- ScrollPosition = line.Address;
- _updatingScroll = false;
+ if(_scrollByAddress) {
+ foreach(CodeLineData line in _lines) {
+ if(line.Address >= 0) {
+ if(ScrollPosition != line.Address) {
+ _updatingScroll = true;
+ ScrollPosition = line.Address;
+ _updatingScroll = false;
+ }
+ break;
}
- break;
}
}
}
@@ -141,7 +158,7 @@ namespace Mesen.Debugger.Controls
string addrFormat = "X" + DataProvider.CpuType.GetAddressSize();
double symbolMargin = 20;
double addressMargin = Math.Floor(LetterSize.Width * DataProvider.CpuType.GetAddressSize() + symbolMargin) + 0.5;
- double byteCodeMargin = Math.Floor(LetterSize.Width * (4 * DataProvider.CpuType.GetByteCodeSize()));
+ double byteCodeMargin = Math.Floor(LetterSize.Width * (3 * DataProvider.CpuType.GetByteCodeSize()));
double codeIndent = Math.Floor(LetterSize.Width * 2) + 0.5;
//Draw margin (address)
@@ -261,7 +278,6 @@ namespace Mesen.Debugger.Controls
public interface ILineStyleProvider
{
LineProperties GetLineStyle(CodeLineData lineData, int lineIndex);
- string? GetLineComment(int lineIndex);
List GetCodeColors(CodeLineData lineData, bool highlightCode, string addressFormat, Color? textColor, bool showMemoryValues);
}
diff --git a/NewUI/Debugger/Disassembly/BaseStyleProvider.cs b/NewUI/Debugger/Disassembly/BaseStyleProvider.cs
index aeb25aa7..5f773f1b 100644
--- a/NewUI/Debugger/Disassembly/BaseStyleProvider.cs
+++ b/NewUI/Debugger/Disassembly/BaseStyleProvider.cs
@@ -15,8 +15,6 @@ namespace Mesen.Debugger.Disassembly
{
public int? ActiveAddress { get; set; }
- public string? GetLineComment(int lineIndex) => null;
-
public static void ConfigureActiveStatement(LineProperties props)
{
props.FgColor = Colors.Black;
diff --git a/NewUI/Debugger/Disassembly/CodeLineData.cs b/NewUI/Debugger/Disassembly/CodeLineData.cs
index 9c429f67..a692ad95 100644
--- a/NewUI/Debugger/Disassembly/CodeLineData.cs
+++ b/NewUI/Debugger/Disassembly/CodeLineData.cs
@@ -15,20 +15,20 @@ namespace Mesen.Debugger
public string Text = "";
- public Int32 Address;
- public Int32 AbsoluteAddress;
+ public Int32 Address = -1;
+ public Int32 AbsoluteAddress = -1;
public LineFlags Flags;
public int? CustomIndent = null;
- public byte OpSize;
+ public byte OpSize = 0;
public string ByteCode = "";
public string Comment = "";
- public Int32 EffectiveAddress;
- public UInt16 Value;
- public byte ValueSize;
+ public Int32 EffectiveAddress = -1;
+ public UInt16 Value = 0;
+ public byte ValueSize = 0;
public string GetEffectiveAddressString(string format)
{
@@ -90,7 +90,7 @@ namespace Mesen.Debugger
this.OpSize = data.OpSize;
this.ByteCode = "";
for(int i = 0; i < this.OpSize; i++) {
- this.ByteCode += "$" + data.ByteCode[i].ToString("X2") + " ";
+ this.ByteCode += data.ByteCode[i].ToString("X2") + " ";
}
this.Address = data.Address;
diff --git a/NewUI/Debugger/ViewModels/TraceLoggerViewModel.cs b/NewUI/Debugger/ViewModels/TraceLoggerViewModel.cs
new file mode 100644
index 00000000..0af49e9a
--- /dev/null
+++ b/NewUI/Debugger/ViewModels/TraceLoggerViewModel.cs
@@ -0,0 +1,178 @@
+using Avalonia.Controls;
+using Avalonia.Media;
+using Mesen.Config;
+using Mesen.Debugger.Controls;
+using Mesen.Debugger.Disassembly;
+using Mesen.Interop;
+using Mesen.Localization;
+using Mesen.ViewModels;
+using ReactiveUI;
+using ReactiveUI.Fody.Helpers;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Mesen.Debugger.ViewModels
+{
+ public class TraceLoggerViewModel : ViewModelBase
+ {
+ [Reactive] public TraceLoggerCodeDataProvider DataProvider { get; set; } = new TraceLoggerCodeDataProvider();
+ [Reactive] public TraceLoggerStyleProvider StyleProvider { get; set; } = new TraceLoggerStyleProvider();
+ [Reactive] public int ScrollPosition { get; set; } = 0;
+ [Reactive] public int MaxScrollPosition { get; set; } = 0;
+
+ [Reactive] public List Tabs { get; set; } = new List();
+
+ public TraceLoggerViewModel()
+ {
+ if(Design.IsDesignMode) {
+ return;
+ }
+
+ UpdateAvailableTabs();
+ }
+
+ public void UpdateAvailableTabs()
+ {
+ List tabs = new();
+ RomInfo romInfo = EmuApi.GetRomInfo();
+ StyleProvider.SetConsoleType(romInfo.ConsoleType);
+ foreach(CpuType type in romInfo.CpuTypes) {
+ tabs.Add(new TraceLoggerOptionTab() {
+ TabName = ResourceHelper.GetEnumText(type),
+ CpuType = type,
+ Options = type switch {
+ CpuType.Cpu => ConfigManager.Config.Debug.TraceLogger.SnesCpu.Clone(),
+ CpuType.Spc => ConfigManager.Config.Debug.TraceLogger.SpcCpu.Clone(),
+ CpuType.Gameboy => ConfigManager.Config.Debug.TraceLogger.GameboyCpu.Clone(),
+ CpuType.Nes => ConfigManager.Config.Debug.TraceLogger.NesCpu.Clone(),
+ CpuType.Sa1 => ConfigManager.Config.Debug.TraceLogger.Sa1Cpu.Clone(),
+ CpuType.Gsu => ConfigManager.Config.Debug.TraceLogger.GsuCpu.Clone(),
+ CpuType.Cx4 => ConfigManager.Config.Debug.TraceLogger.Cx4Cpu.Clone(),
+ CpuType.NecDsp => ConfigManager.Config.Debug.TraceLogger.NecDspCpu.Clone(),
+ _ => throw new Exception("Unsupported cpu type")
+ }
+ });
+ }
+
+ Tabs = tabs;
+ }
+
+ public void UpdateLog()
+ {
+ foreach(TraceLoggerOptionTab tab in Tabs) {
+ InteropTraceLoggerOptions options = new InteropTraceLoggerOptions() {
+ Enabled = tab.Options.Enabled,
+ UseLabels = true,
+ Format = Encoding.UTF8.GetBytes(tab.Options.Format),
+ Condition = Encoding.UTF8.GetBytes(tab.Options.Condition)
+ };
+
+ Array.Resize(ref options.Condition, 1000);
+ Array.Resize(ref options.Format, 1000);
+
+ DebugApi.SetTraceOptions(tab.CpuType, options);
+ }
+
+ DataProvider = new TraceLoggerCodeDataProvider();
+ MaxScrollPosition = DataProvider.GetLineCount();
+ ScrollPosition = MaxScrollPosition - 0x20;
+ }
+ }
+
+ public class TraceLoggerOptionTab
+ {
+ [Reactive] public string TabName { get; set; } = "";
+ [Reactive] public CpuType CpuType { get; set; } = CpuType.Cpu;
+
+ public TraceLoggerCpuConfig Options { get; set; } = new TraceLoggerCpuConfig();
+ }
+
+ public class TraceLoggerCodeDataProvider : ICodeDataProvider
+ {
+ public TraceLoggerCodeDataProvider()
+ {
+ }
+
+ public bool UseOptimizedSearch { get { return false; } }
+
+ public CpuType CpuType => CpuType.Cpu;
+
+ public int GetLineCount()
+ {
+ return 30000;
+ }
+
+ public int GetNextResult(string searchString, int startPosition, int endPosition, bool searchBackwards)
+ {
+ throw new NotImplementedException();
+ }
+
+ public CodeLineData[] GetCodeLines(int startIndex, int rowCount)
+ {
+ TraceRow[] rows = DebugApi.GetExecutionTrace((uint)(30000 - startIndex), (uint)rowCount);
+
+ List lines = new(rowCount);
+ for(int i = 0; i < rows.Length; i++) {
+ lines.Insert(0, new CodeLineData(rows[i].Type) {
+ Address = (int)rows[i].ProgramCounter,
+ Text = rows[i].GetOutput(),
+ ByteCode = rows[i].GetByteCode(),
+ EffectiveAddress = -1
+ });
+ }
+
+ while(lines.Count < rowCount) {
+ lines.Insert(0, new CodeLineData(CpuType.Cpu));
+ }
+
+ return lines.ToArray();
+ }
+ }
+
+ public class TraceLoggerStyleProvider : ILineStyleProvider
+ {
+ private LineProperties _defaultLine = new LineProperties() { AddressColor = null, LineBgColor = null };
+ private LineProperties _spcLine = new LineProperties() { AddressColor = Color.FromRgb(30, 145, 30), LineBgColor = Color.FromRgb(230, 245, 230) };
+ private LineProperties _coprocLine = new LineProperties() { AddressColor = Color.FromRgb(30, 30, 145), LineBgColor = Color.FromRgb(230, 230, 245) };
+ private ConsoleType _consoleType = ConsoleType.Snes;
+
+ public TraceLoggerStyleProvider()
+ {
+ }
+
+ public List GetCodeColors(CodeLineData lineData, bool highlightCode, string addressFormat, Color? textColor, bool showMemoryValues)
+ {
+ return CodeHighlighting.GetCpuHighlights(lineData, highlightCode, addressFormat, textColor, showMemoryValues);
+ }
+
+ public LineProperties GetLineStyle(CodeLineData lineData, int lineIndex)
+ {
+ switch(lineData.CpuType) {
+ case CpuType.Spc: return _spcLine;
+
+ case CpuType.NecDsp:
+ case CpuType.Sa1:
+ case CpuType.Gsu:
+ case CpuType.Cx4:
+ return _coprocLine;
+
+ case CpuType.Gameboy:
+ if(_consoleType == ConsoleType.Snes) {
+ return _coprocLine;
+ }
+ break;
+
+ default: break;
+ }
+
+ return _defaultLine;
+ }
+
+ internal void SetConsoleType(ConsoleType consoleType)
+ {
+ _consoleType = consoleType;
+ }
+ }
+
+}
diff --git a/NewUI/Debugger/Windows/TraceLoggerWindow.axaml b/NewUI/Debugger/Windows/TraceLoggerWindow.axaml
new file mode 100644
index 00000000..46dbace8
--- /dev/null
+++ b/NewUI/Debugger/Windows/TraceLoggerWindow.axaml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NewUI/Debugger/Windows/TraceLoggerWindow.axaml.cs b/NewUI/Debugger/Windows/TraceLoggerWindow.axaml.cs
new file mode 100644
index 00000000..f03cac0f
--- /dev/null
+++ b/NewUI/Debugger/Windows/TraceLoggerWindow.axaml.cs
@@ -0,0 +1,87 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Avalonia.LogicalTree;
+using Avalonia.Markup.Xaml;
+using Avalonia.Media;
+using Avalonia.Threading;
+using AvaloniaEdit;
+using AvaloniaEdit.Highlighting;
+using AvaloniaEdit.Highlighting.Xshd;
+using Mesen.Debugger.Controls;
+using Mesen.Debugger.ViewModels;
+using Mesen.Interop;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Reflection;
+using System.Xml;
+
+namespace Mesen.Debugger.Windows
+{
+ public class TraceLoggerWindow : Window
+ {
+ private NotificationListener? _listener = null;
+ private TraceLoggerViewModel Model => ((TraceLoggerViewModel)DataContext!);
+ private int _refreshCounter = 0;
+
+ public TraceLoggerWindow()
+ {
+ InitializeComponent();
+#if DEBUG
+ this.AttachDevTools();
+#endif
+ }
+
+ protected override void OnOpened(EventArgs e)
+ {
+ base.OnOpened(e);
+
+ if(Design.IsDesignMode) {
+ return;
+ }
+
+ _listener = new NotificationListener();
+ _listener.OnNotification += listener_OnNotification;
+ }
+
+ protected override void OnClosing(CancelEventArgs e)
+ {
+ base.OnClosing(e);
+ _listener?.Dispose();
+ }
+
+ private void listener_OnNotification(NotificationEventArgs e)
+ {
+ switch(e.NotificationType) {
+ case ConsoleNotificationType.GameLoaded:
+ Model.UpdateAvailableTabs();
+ break;
+
+ case ConsoleNotificationType.CodeBreak: {
+ Dispatcher.UIThread.Post(() => {
+ Model.UpdateLog();
+ });
+ break;
+ }
+
+ case ConsoleNotificationType.PpuFrameDone: {
+ _refreshCounter++;
+ if(_refreshCounter == 9) {
+ //Refresh every 9 frames, ~7fps
+ Dispatcher.UIThread.Post(() => {
+ Model.UpdateLog();
+ });
+ _refreshCounter = 0;
+ }
+ break;
+ }
+ }
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}
diff --git a/NewUI/Interop/DebugApi.cs b/NewUI/Interop/DebugApi.cs
index beb35d18..31f8eb1b 100644
--- a/NewUI/Interop/DebugApi.cs
+++ b/NewUI/Interop/DebugApi.cs
@@ -20,10 +20,26 @@ namespace Mesen.Interop
[DllImport(DllPath)] public static extern void ResumeExecution();
[DllImport(DllPath)] public static extern void Step(CpuType cpuType, Int32 instructionCount, StepType type = StepType.Step);
- [DllImport(DllPath)] public static extern void StartTraceLogger([MarshalAs(UnmanagedType.LPUTF8Str)]string filename);
+ /*[DllImport(DllPath)] public static extern void StartTraceLogger([MarshalAs(UnmanagedType.LPUTF8Str)]string filename);
[DllImport(DllPath)] public static extern void StopTraceLogger();
- [DllImport(DllPath)] public static extern void SetTraceOptions(InteropTraceLoggerOptions options);
- [DllImport(DllPath)] public static extern void ClearTraceLog();
+ [DllImport(DllPath)] public static extern void ClearTraceLog();*/
+
+ [DllImport(DllPath)] public static extern void SetTraceOptions(CpuType cpuType, InteropTraceLoggerOptions options);
+
+ [DllImport(DllPath, EntryPoint = "GetExecutionTrace")] private static extern UInt32 GetExecutionTraceWrapper(IntPtr output, UInt32 startOffset, UInt32 maxRowCount);
+ public static TraceRow[] GetExecutionTrace(UInt32 startOffset, UInt32 maxRowCount)
+ {
+ TraceRow[] rows = new TraceRow[maxRowCount];
+
+ GCHandle handle = GCHandle.Alloc(rows, GCHandleType.Pinned);
+ IntPtr ptr = handle.AddrOfPinnedObject();
+ UInt32 rowCount = DebugApi.GetExecutionTraceWrapper(ptr, startOffset, maxRowCount);
+ handle.Free();
+
+ Array.Resize(ref rows, (int)rowCount);
+
+ return rows;
+ }
[DllImport(DllPath, EntryPoint = "GetDebuggerLog")] private static extern IntPtr GetDebuggerLogWrapper();
public static string GetLog() { return Utf8Utilities.PtrToStringUtf8(DebugApi.GetDebuggerLogWrapper()).Replace("\n", Environment.NewLine); }
@@ -49,9 +65,6 @@ namespace Mesen.Interop
[DllImport(DllPath)] public static extern int SearchDisassembly(CpuType type, [MarshalAs(UnmanagedType.LPUTF8Str)]string searchString, int startPosition, int endPosition, [MarshalAs(UnmanagedType.I1)]bool searchBackwards);
- [DllImport(DllPath, EntryPoint = "GetExecutionTrace")] private static extern IntPtr GetExecutionTraceWrapper(UInt32 lineCount);
- public static string GetExecutionTrace(UInt32 lineCount) { return Utf8Utilities.PtrToStringUtf8(DebugApi.GetExecutionTraceWrapper(lineCount)); }
-
[DllImport(DllPath, EntryPoint = "GetState")] private static extern void GetState(IntPtr state, CpuType cpuType);
public static T GetState(CpuType cpuType) where T : struct, BaseState
@@ -654,19 +667,9 @@ namespace Mesen.Interop
[Serializable]
public struct InteropTraceLoggerOptions
{
- [MarshalAs(UnmanagedType.I1)] public bool LogCpu;
- [MarshalAs(UnmanagedType.I1)] public bool LogSpc;
- [MarshalAs(UnmanagedType.I1)] public bool LogNecDsp;
- [MarshalAs(UnmanagedType.I1)] public bool LogSa1;
- [MarshalAs(UnmanagedType.I1)] public bool LogGsu;
- [MarshalAs(UnmanagedType.I1)] public bool LogCx4;
- [MarshalAs(UnmanagedType.I1)] public bool LogGameboy;
-
- [MarshalAs(UnmanagedType.I1)] public bool ShowExtraInfo;
+ [MarshalAs(UnmanagedType.I1)] public bool Enabled;
[MarshalAs(UnmanagedType.I1)] public bool IndentCode;
[MarshalAs(UnmanagedType.I1)] public bool UseLabels;
- [MarshalAs(UnmanagedType.I1)] public bool UseWindowsEol;
- [MarshalAs(UnmanagedType.I1)] public bool ExtendZeroPage;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1000)]
public byte[] Condition;
@@ -843,4 +846,41 @@ namespace Mesen.Interop
public UInt64 MaxCycles;
public AddressInfo Address;
}
+
+ public unsafe struct TraceRow
+ {
+ public UInt32 ProgramCounter;
+ public CpuType Type;
+
+ public fixed byte ByteCode[4];
+ public byte ByteCodeSize;
+
+ public fixed byte LogOutput[500];
+
+ public unsafe string GetOutput()
+ {
+ fixed(byte* output = LogOutput) {
+ int i;
+ for(i = 0; i < 500; i++) {
+ if(output[i] == 0) {
+ break;
+ }
+ }
+
+ return UTF8Encoding.UTF8.GetString(output, i);
+ }
+ }
+
+ public unsafe string GetByteCode()
+ {
+ fixed(byte* output = ByteCode) {
+ StringBuilder sb = new StringBuilder();
+ int i;
+ for(i = 0; i < ByteCodeSize && i < 4; i++) {
+ sb.Append(ByteCode[i].ToString("X2") + " ");
+ }
+ return sb.ToString().Trim();
+ }
+ }
+ }
}
diff --git a/NewUI/Localization/resources.en.xml b/NewUI/Localization/resources.en.xml
index 63c13f49..272725fb 100644
--- a/NewUI/Localization/resources.en.xml
+++ b/NewUI/Localization/resources.en.xml
@@ -798,6 +798,13 @@
Stop
+
+