Debugger: SPC watch and conditional breakpoints

This commit is contained in:
Sour 2019-04-07 14:38:22 -04:00
parent d89f4ba0cb
commit 35476426c0
21 changed files with 162 additions and 44 deletions

View file

@ -20,7 +20,9 @@ void BreakpointManager::SetBreakpoints(Breakpoint breakpoints[], uint32_t count)
}
}
_bpExpEval.reset(new ExpressionEvaluator(_debugger));
_bpExpEval[(int)CpuType::Cpu].reset(new ExpressionEvaluator(_debugger, CpuType::Cpu));
_bpExpEval[(int)CpuType::Spc].reset(new ExpressionEvaluator(_debugger, CpuType::Spc));
for(uint32_t j = 0; j < count; j++) {
Breakpoint &bp = breakpoints[j];
for(int i = 0; i < BreakpointManager::BreakpointTypeCount; i++) {
@ -28,11 +30,12 @@ void BreakpointManager::SetBreakpoints(Breakpoint breakpoints[], uint32_t count)
bool isEnabled = bp.IsEnabled(); //TODO && _console->GetSettings()->CheckFlag(EmulationFlags::DebuggerWindowEnabled);
if((bp.IsMarked() || isEnabled) && bp.HasBreakpointType(bpType)) {
BreakpointCategory category = bp.GetBreakpointCategory();
CpuType cpuType = category == BreakpointCategory::Spc ? CpuType::Spc : CpuType::Cpu;
_breakpoints[(int)category][i].push_back(bp);
if(bp.HasCondition()) {
bool success = true;
ExpressionData data = _bpExpEval->GetRpnList(bp.GetCondition(), success);
ExpressionData data = _bpExpEval[(int)cpuType]->GetRpnList(bp.GetCondition(), success);
_rpnList[(int)category][i].push_back(success ? data : ExpressionData());
} else {
_rpnList[(int)category][i].push_back(ExpressionData());
@ -71,13 +74,15 @@ bool BreakpointManager::CheckBreakpoint(MemoryOperationInfo operationInfo, Addre
return false;
}
CpuType cpuType = category == BreakpointCategory::Spc ? CpuType::Spc : CpuType::Cpu;
DebugState state;
_debugger->GetState(state);
EvalResultType resultType;
vector<Breakpoint> &breakpoints = _breakpoints[(int)category][(int)type];
for(size_t i = 0; i < breakpoints.size(); i++) {
if(breakpoints[i].Matches(operationInfo.Address, address)) {
if(!breakpoints[i].HasCondition() || _bpExpEval->Evaluate(_rpnList[(int)category][(int)type][i], state, resultType, operationInfo)) {
if(!breakpoints[i].HasCondition() || _bpExpEval[(int)cpuType]->Evaluate(_rpnList[(int)category][(int)type][i], state, resultType, operationInfo)) {
return true;
}
}

View file

@ -21,7 +21,7 @@ private:
vector<ExpressionData> _rpnList[CategoryCount][BreakpointTypeCount];
bool _hasBreakpoint[CategoryCount][BreakpointTypeCount] = {};
unique_ptr<ExpressionEvaluator> _bpExpEval;
unique_ptr<ExpressionEvaluator> _bpExpEval[2]; //CpuType::Spc + 1
BreakpointType GetBreakpointType(MemoryOperationType type);

View file

@ -73,7 +73,8 @@ enum class MemoryOperationType
ExecOpCode = 2,
ExecOperand = 3,
DmaRead = 4,
DmaWrite = 5
DmaWrite = 5,
DummyRead = 6
};
enum class IrqSource

View file

@ -33,12 +33,14 @@ Debugger::Debugger(shared_ptr<Console> console)
_spc = console->GetSpc();
_memoryManager = console->GetMemoryManager();
_watchExpEval.reset(new ExpressionEvaluator(this));
_watchExpEval[(int)CpuType::Cpu].reset(new ExpressionEvaluator(this, CpuType::Cpu));
_watchExpEval[(int)CpuType::Spc].reset(new ExpressionEvaluator(this, CpuType::Spc));
_codeDataLogger.reset(new CodeDataLogger(console->GetCartridge()->DebugGetPrgRomSize(), _memoryManager.get()));
_disassembler.reset(new Disassembler(console, _codeDataLogger));
_traceLogger.reset(new TraceLogger(this, _console));
_memoryDumper.reset(new MemoryDumper(_ppu, console->GetSpc(), _memoryManager, console->GetCartridge()));
_memoryAccessCounter.reset(new MemoryAccessCounter(this, _memoryManager.get()));
_memoryAccessCounter.reset(new MemoryAccessCounter(this, _spc.get(), _memoryManager.get()));
_breakpointManager.reset(new BreakpointManager(this));
_ppuTools.reset(new PpuTools(_console.get(), _ppu.get()));
_eventManager.reset(new EventManager(this, _cpu.get(), _ppu.get()));
@ -187,6 +189,11 @@ void Debugger::ProcessWorkRamWrite(uint32_t addr, uint8_t value)
void Debugger::ProcessSpcRead(uint16_t addr, uint8_t value, MemoryOperationType type)
{
if(type == MemoryOperationType::DummyRead) {
//Ignore all dummy reads for now
return;
}
AddressInfo addressInfo = _spc->GetAbsoluteAddress(addr);
MemoryOperationInfo operation(addr, value, type);
@ -337,15 +344,15 @@ void Debugger::ProcessEvent(EventType type)
}
}
int32_t Debugger::EvaluateExpression(string expression, EvalResultType &resultType, bool useCache)
int32_t Debugger::EvaluateExpression(string expression, CpuType cpuType, EvalResultType &resultType, bool useCache)
{
MemoryOperationInfo operationInfo { 0, 0, MemoryOperationType::Read };
DebugState state;
GetState(state);
if(useCache) {
return _watchExpEval->Evaluate(expression, state, resultType, operationInfo);
return _watchExpEval[(int)cpuType]->Evaluate(expression, state, resultType, operationInfo);
} else {
ExpressionEvaluator expEval(this);
ExpressionEvaluator expEval(this, cpuType);
return expEval.Evaluate(expression, state, resultType, operationInfo);
}
}

View file

@ -46,7 +46,7 @@ private:
shared_ptr<CallstackManager> _callstackManager;
shared_ptr<CallstackManager> _spcCallstackManager;
unique_ptr<ExpressionEvaluator> _watchExpEval;
unique_ptr<ExpressionEvaluator> _watchExpEval[(int)CpuType::Spc + 1];
atomic<bool> _executionStopped;
atomic<uint32_t> _breakRequestCount;
@ -89,7 +89,7 @@ public:
void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi);
void ProcessEvent(EventType type);
int32_t EvaluateExpression(string expression, EvalResultType &resultType, bool useCache);
int32_t EvaluateExpression(string expression, CpuType cpuType, EvalResultType &resultType, bool useCache);
void Run();
void Step(int32_t stepCount, StepType type = StepType::CpuStep);

View file

@ -372,26 +372,44 @@ int32_t ExpressionEvaluator::Evaluate(ExpressionData &data, DebugState &state, E
}*/
} else {
switch(token) {
case EvalValues::RegA: token = state.Cpu.A; break;
case EvalValues::RegX: token = state.Cpu.X; break;
case EvalValues::RegY: token = state.Cpu.Y; break;
case EvalValues::RegSP: token = state.Cpu.SP; break;
case EvalValues::RegPS: token = state.Cpu.PS; break;
case EvalValues::RegPC: token = state.Cpu.PC; break;
//TODO
/*case EvalValues::RegOpPC: token = state.Cpu.DebugPC; break;*/
case EvalValues::PpuFrameCount: token = state.Ppu.FrameCount; break;
case EvalValues::PpuCycle: token = state.Ppu.Cycle; break;
case EvalValues::PpuScanline: token = state.Ppu.Scanline; break;
case EvalValues::Nmi: token = state.Cpu.NmiFlag; resultType = EvalResultType::Boolean; break;
case EvalValues::Irq: token = state.Cpu.IrqSource != 0; resultType = EvalResultType::Boolean; break;
case EvalValues::Value: token = operationInfo.Value; break;
case EvalValues::Address: token = operationInfo.Address; break;
//case EvalValues::AbsoluteAddress: token = _debugger->GetAbsoluteAddress(operationInfo.Address); break;
case EvalValues::IsWrite: token = operationInfo.Type == MemoryOperationType::Write || operationInfo.Type == MemoryOperationType::DmaWrite; break;
case EvalValues::IsRead: token = operationInfo.Type != MemoryOperationType::Write && operationInfo.Type != MemoryOperationType::DmaWrite; break;
//case EvalValues::PreviousOpPC: token = state.CPU.PreviousDebugPC; break;
default:
switch(_cpuType) {
case CpuType::Cpu:
switch(token) {
case EvalValues::RegA: token = state.Cpu.A; break;
case EvalValues::RegX: token = state.Cpu.X; break;
case EvalValues::RegY: token = state.Cpu.Y; break;
case EvalValues::RegSP: token = state.Cpu.SP; break;
case EvalValues::RegPS: token = state.Cpu.PS; break;
case EvalValues::RegPC: token = state.Cpu.PC; break;
case EvalValues::Nmi: token = state.Cpu.NmiFlag; resultType = EvalResultType::Boolean; break;
case EvalValues::Irq: token = state.Cpu.IrqSource != 0; resultType = EvalResultType::Boolean; break;
}
break;
case CpuType::Spc:
switch(token) {
case EvalValues::RegA: token = state.Spc.A; break;
case EvalValues::RegX: token = state.Spc.X; break;
case EvalValues::RegY: token = state.Spc.Y; break;
case EvalValues::RegSP: token = state.Spc.SP; break;
case EvalValues::RegPS: token = state.Spc.PS; break;
case EvalValues::RegPC: token = state.Spc.PC; break;
}
break;
}
break;
}
}
} else if(token >= EvalOperators::Multiplication) {
@ -438,8 +456,8 @@ int32_t ExpressionEvaluator::Evaluate(ExpressionData &data, DebugState &state, E
case EvalOperators::Minus: token = -right; break;
case EvalOperators::BinaryNot: token = ~right; break;
case EvalOperators::LogicalNot: token = !right; break;
case EvalOperators::Bracket: token = _debugger->GetMemoryDumper()->GetMemoryValue(SnesMemoryType::CpuMemory, (uint32_t)right); break;
case EvalOperators::Braces: token = _debugger->GetMemoryDumper()->GetMemoryValueWord(SnesMemoryType::CpuMemory, (uint32_t)right); break;
case EvalOperators::Bracket: token = _debugger->GetMemoryDumper()->GetMemoryValue(_cpuMemory, (uint32_t)right); break;
case EvalOperators::Braces: token = _debugger->GetMemoryDumper()->GetMemoryValueWord(_cpuMemory, (uint32_t)right); break;
default: throw std::runtime_error("Invalid operator");
}
}
@ -448,9 +466,11 @@ int32_t ExpressionEvaluator::Evaluate(ExpressionData &data, DebugState &state, E
return (int32_t)operandStack[0];
}
ExpressionEvaluator::ExpressionEvaluator(Debugger* debugger)
ExpressionEvaluator::ExpressionEvaluator(Debugger* debugger, CpuType cpuType)
{
_debugger = debugger;
_cpuType = cpuType;
_cpuMemory = cpuType == CpuType::Cpu ? SnesMemoryType::CpuMemory : SnesMemoryType::SpcMemory;
}
ExpressionData ExpressionEvaluator::GetRpnList(string expression, bool &success)

View file

@ -105,9 +105,11 @@ private:
std::unordered_map<string, ExpressionData, StringHasher> _cache;
SimpleLock _cacheLock;
int64_t operandStack[1000];
Debugger* _debugger;
CpuType _cpuType;
SnesMemoryType _cpuMemory;
bool IsOperator(string token, int &precedence, bool unaryOperator);
EvalOperators GetOperator(string token, bool unaryOperator);
@ -119,7 +121,7 @@ private:
ExpressionData* PrivateGetRpnList(string expression, bool& success);
public:
ExpressionEvaluator(Debugger* debugger);
ExpressionEvaluator(Debugger* debugger, CpuType cpuType);
int32_t Evaluate(ExpressionData &data, DebugState &state, EvalResultType &resultType, MemoryOperationInfo &operationInfo);
int32_t Evaluate(string expression, DebugState &state, EvalResultType &resultType, MemoryOperationInfo &operationInfo);

View file

@ -4,11 +4,13 @@
#include "DebugBreakHelper.h"
#include "Debugger.h"
#include "MemoryDumper.h"
#include "Spc.h"
MemoryAccessCounter::MemoryAccessCounter(Debugger* debugger, MemoryManager* memoryManager)
MemoryAccessCounter::MemoryAccessCounter(Debugger* debugger, Spc* spc, MemoryManager* memoryManager)
{
_debugger = debugger;
_memoryManager = memoryManager;
_spc = spc;
for(int i = (int)SnesMemoryType::PrgRom; i < (int)SnesMemoryType::Register; i++) {
uint32_t memSize = _debugger->GetMemoryDumper()->GetMemorySize((SnesMemoryType)i);
@ -110,6 +112,15 @@ void MemoryAccessCounter::GetAccessStamps(uint32_t offset, uint32_t length, Snes
}
break;
case SnesMemoryType::SpcMemory:
for(uint32_t i = 0; i < length; i++) {
AddressInfo info = _spc->GetAbsoluteAddress(offset + i);
if(info.Address >= 0) {
stamps[i] = GetStampArray(operationType, info.Type)[info.Address];
}
}
break;
default:
memcpy(stamps, GetStampArray(operationType, memoryType).data() + offset, length * sizeof(uint64_t));
break;
@ -128,6 +139,15 @@ void MemoryAccessCounter::GetAccessCounts(uint32_t offset, uint32_t length, Snes
}
break;
case SnesMemoryType::SpcMemory:
for(uint32_t i = 0; i < length; i++) {
AddressInfo info = _spc->GetAbsoluteAddress(offset + i);
if(info.Address >= 0) {
counts[i] = GetCountArray(operationType, info.Type)[info.Address];
}
}
break;
default:
memcpy(counts, GetCountArray(operationType, memoryType).data() + offset, length * sizeof(uint32_t));
break;

View file

@ -4,6 +4,7 @@
class Debugger;
class MemoryManager;
class Spc;
class MemoryAccessCounter
{
@ -20,13 +21,14 @@ private:
Debugger* _debugger;
MemoryManager* _memoryManager;
Spc* _spc;
vector<uint32_t>& GetCountArray(MemoryOperationType operationType, SnesMemoryType memType);
vector<uint64_t>& GetStampArray(MemoryOperationType operationType, SnesMemoryType memType);
bool IsAddressUninitialized(AddressInfo &addressInfo);
public:
MemoryAccessCounter(Debugger *debugger, MemoryManager* memoryManager);
MemoryAccessCounter(Debugger *debugger, Spc* spc, MemoryManager* memoryManager);
bool ProcessMemoryAccess(AddressInfo &addressInfo, MemoryOperationType operation, uint64_t masterClock);
void ResetCounts();

View file

@ -67,6 +67,12 @@ void MemoryDumper::GetMemoryState(SnesMemoryType type, uint8_t *buffer)
}
break;
case SnesMemoryType::SpcMemory:
for(int i = 0; i <= 0xFFFF; i++) {
buffer[i] = _spc->DebugRead(i);
}
break;
case SnesMemoryType::PrgRom: memcpy(buffer, _cartridge->DebugGetPrgRom(), _cartridge->DebugGetPrgRomSize()); break;
case SnesMemoryType::WorkRam: memcpy(buffer, _memoryManager->DebugGetWorkRam(), MemoryManager::WorkRamSize); break;
case SnesMemoryType::SaveRam: memcpy(buffer, _cartridge->DebugGetSaveRam(), _cartridge->DebugGetSaveRamSize()); break;
@ -94,7 +100,9 @@ void MemoryDumper::SetMemoryValue(SnesMemoryType memoryType, uint32_t address, u
switch(memoryType) {
default: break;
//TODO: Avoid side effects
case SnesMemoryType::CpuMemory: _memoryManager->Write(address, value, MemoryOperationType::Write); break;
case SnesMemoryType::SpcMemory: _spc->DebugWrite(address, value); break;
case SnesMemoryType::PrgRom: _cartridge->DebugGetPrgRom()[address] = value; break;
case SnesMemoryType::WorkRam: _memoryManager->DebugGetWorkRam()[address] = value; break;
@ -118,6 +126,7 @@ uint8_t MemoryDumper::GetMemoryValue(SnesMemoryType memoryType, uint32_t address
default: return 0;
case SnesMemoryType::CpuMemory: return _memoryManager->Peek(address);
case SnesMemoryType::SpcMemory: return _spc->DebugRead(address);
case SnesMemoryType::PrgRom: return _cartridge->DebugGetPrgRom()[address];
case SnesMemoryType::WorkRam: return _memoryManager->DebugGetWorkRam()[address];

View file

@ -59,12 +59,12 @@ void Spc::Idle()
void Spc::DummyRead()
{
Read(_state.PC);
Read(_state.PC, MemoryOperationType::DummyRead);
}
void Spc::DummyRead(uint16_t addr)
{
Read(addr);
Read(addr, MemoryOperationType::DummyRead);
}
void Spc::IncCycleCount(int32_t addr)
@ -89,6 +89,44 @@ void Spc::IncCycleCount(int32_t addr)
_state.Timer2.Run(timerInc);
}
uint8_t Spc::DebugRead(uint16_t addr)
{
if(addr >= 0xFFC0 && _state.RomEnabled) {
return _spcBios[addr & 0x3F];
}
switch(addr) {
case 0xF0: return 0;
case 0xF1: return 0;
case 0xF2: return _state.DspReg;
case 0xF3: return _dsp->read(_state.DspReg & 0x7F);
case 0xF4: return _state.CpuRegs[0];
case 0xF5: return _state.CpuRegs[1];
case 0xF6: return _state.CpuRegs[2];
case 0xF7: return _state.CpuRegs[3];
case 0xF8: return _state.RamReg[0];
case 0xF9: return _state.RamReg[1];
case 0xFA: return 0;
case 0xFB: return 0;
case 0xFC: return 0;
case 0xFD: return _state.Timer0.DebugRead();
case 0xFE: return _state.Timer1.DebugRead();
case 0xFF: return _state.Timer2.DebugRead();
default: return _ram[addr];
}
}
void Spc::DebugWrite(uint16_t addr, uint8_t value)
{
_ram[addr] = value;
}
uint8_t Spc::Read(uint16_t addr, MemoryOperationType type)
{
IncCycleCount(addr);

View file

@ -245,6 +245,9 @@ public:
void Run();
void Reset();
uint8_t DebugRead(uint16_t addr);
void DebugWrite(uint16_t addr, uint8_t value);
uint8_t CpuReadRegister(uint16_t addr);
void CpuWriteRegister(uint32_t addr, uint8_t value);

View file

@ -73,6 +73,11 @@ public:
_target = target;
}
uint8_t DebugRead()
{
return _output & 0x0F;
}
uint8_t GetOutput()
{
uint8_t value = _output & 0x0F;

View file

@ -53,7 +53,7 @@ extern "C"
DllExport const char* GetExecutionTrace(uint32_t lineCount) { return GetDebugger()->GetTraceLogger()->GetExecutionTrace(lineCount); }
DllExport void __stdcall SetBreakpoints(Breakpoint breakpoints[], uint32_t length) { GetDebugger()->GetBreakpointManager()->SetBreakpoints(breakpoints, length); }
DllExport int32_t __stdcall EvaluateExpression(char* expression, EvalResultType *resultType, bool useCache) { return GetDebugger()->EvaluateExpression(expression, *resultType, useCache); }
DllExport int32_t __stdcall EvaluateExpression(char* expression, CpuType cpuType, EvalResultType *resultType, bool useCache) { return GetDebugger()->EvaluateExpression(expression, cpuType, *resultType, useCache); }
DllExport void __stdcall GetCallstack(CpuType cpuType, StackFrameInfo *callstackArray, uint32_t &callstackSize) { GetDebugger()->GetCallstackManager(cpuType)->GetCallstack(callstackArray, callstackSize); }
DllExport void __stdcall GetState(DebugState &state) { GetDebugger()->GetState(state); }

View file

@ -9,6 +9,8 @@ namespace Mesen.GUI.Debugger
{
public partial class frmBreakpoint : BaseConfigForm
{
private CpuType _cpuType;
public frmBreakpoint(Breakpoint breakpoint)
{
InitializeComponent();
@ -32,10 +34,10 @@ namespace Mesen.GUI.Debugger
AddBinding(nameof(Breakpoint.BreakOnExec), chkExec);
AddBinding(nameof(Breakpoint.Condition), txtCondition);
CpuType cpuType = breakpoint.MemoryType == SnesMemoryType.SpcMemory ? CpuType.Spc : CpuType.Cpu;
_cpuType = breakpoint.MemoryType == SnesMemoryType.SpcMemory ? CpuType.Spc : CpuType.Cpu;
cboBreakpointType.Items.Clear();
if(cpuType == CpuType.Cpu) {
if(_cpuType == CpuType.Cpu) {
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.CpuMemory));
cboBreakpointType.Items.Add("-");
@ -57,7 +59,7 @@ namespace Mesen.GUI.Debugger
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.VideoRam));
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.SpriteRam));
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.CGRam));
} else if(cpuType == CpuType.Spc) {
} else if(_cpuType == CpuType.Spc) {
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.SpcMemory));
}
@ -155,7 +157,7 @@ namespace Mesen.GUI.Debugger
{
if(txtCondition.Text.Trim().Length > 0) {
EvalResultType resultType;
DebugApi.EvaluateExpression(txtCondition.Text.Replace(Environment.NewLine, " "), out resultType, false);
DebugApi.EvaluateExpression(txtCondition.Text.Replace(Environment.NewLine, " "), _cpuType, out resultType, false);
if(resultType == EvalResultType.Invalid) {
picExpressionWarning.Visible = true;
return false;

View file

@ -62,7 +62,7 @@ namespace Mesen.GUI.Debugger.Controls
StringBuilder sb = new StringBuilder();
for(UInt32 i = (uint)_lastState.Spc.SP + 1; (i & 0xFF) != 0; i++) {
sb.Append("$");
sb.Append(DebugApi.GetMemoryValue(SnesMemoryType.SpcMemory, i).ToString("X2"));
sb.Append(DebugApi.GetMemoryValue(SnesMemoryType.SpcMemory, 0x100 | i).ToString("X2"));
sb.Append(", ");
}
string stack = sb.ToString();

View file

@ -37,6 +37,8 @@ namespace Mesen.GUI.Debugger
this.DoubleBuffered = true;
}
public CpuType CpuType { get; set; }
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
@ -102,7 +104,7 @@ namespace Mesen.GUI.Debugger
public void UpdateWatch(bool autoResizeColumns = true)
{
List<WatchValueInfo> watchContent = WatchManager.GetWatchContent(_previousValues);
List<WatchValueInfo> watchContent = WatchManager.GetWatchContent(this.CpuType, _previousValues);
_previousValues = watchContent;
bool updating = false;

View file

@ -155,7 +155,7 @@ namespace Mesen.GUI.Debugger
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.CGRam));
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.SpriteRam));
cboMemoryType.Items.Add("-");
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.SpcRam));
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.SpcMemory));
cboMemoryType.SelectedIndex = 0;
cboMemoryType.SetEnumValue(originalValue);

View file

@ -26,7 +26,7 @@ namespace Mesen.GUI.Debugger
}
}
public static List<WatchValueInfo> GetWatchContent(List<WatchValueInfo> previousValues)
public static List<WatchValueInfo> GetWatchContent(CpuType cpuType, List<WatchValueInfo> previousValues)
{
WatchFormatStyle defaultStyle = ConfigManager.Config.Debug.Debugger.WatchFormat;
int defaultByteLength = 1;
@ -56,7 +56,7 @@ namespace Mesen.GUI.Debugger
//Watch expression matches the array display syntax (e.g: [$300,10] = display 10 bytes starting from $300)
newValue = ProcessArrayDisplaySyntax(style, ref forceHasChanged, match);
} else {
Int32 result = DebugApi.EvaluateExpression(exprToEvaluate, out resultType, true);
Int32 result = DebugApi.EvaluateExpression(exprToEvaluate, cpuType, out resultType, true);
switch(resultType) {
case EvalResultType.Numeric: newValue = FormatValue(result, style, byteLength); break;
case EvalResultType.Boolean: newValue = result == 0 ? "false" : "true"; break;

View file

@ -46,7 +46,8 @@ namespace Mesen.GUI.Debugger
}
ctrlBreakpoints.CpuType = _cpuType;
ctrlWatch.CpuType = _cpuType;
InitShortcuts();
InitToolbar();
LoadConfig();

View file

@ -53,7 +53,7 @@ namespace Mesen.GUI
return state;
}
[DllImport(DllPath)] public static extern Int32 EvaluateExpression([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]string expression, out EvalResultType resultType, [MarshalAs(UnmanagedType.I1)]bool useCache);
[DllImport(DllPath)] public static extern Int32 EvaluateExpression([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]string expression, CpuType cpuType, out EvalResultType resultType, [MarshalAs(UnmanagedType.I1)]bool useCache);
[DllImport(DllPath)] public static extern Int32 GetMemorySize(SnesMemoryType type);
[DllImport(DllPath)] public static extern Byte GetMemoryValue(SnesMemoryType type, UInt32 address);
@ -326,7 +326,8 @@ namespace Mesen.GUI
ExecOpCode = 2,
ExecOperand = 3,
DmaRead = 4,
DmaWrite = 5
DmaWrite = 5,
DummyRead = 6
}
public struct MemoryOperationInfo