Debugger: Improved expression evaluator when dealing with memory addresses + added "address" and "romaddress" special values

This commit is contained in:
Souryo 2016-06-05 11:51:46 -04:00
parent 8112f906b7
commit 956834d4a5
6 changed files with 103 additions and 60 deletions

View file

@ -205,7 +205,7 @@ bool Debugger::HasMatchingBreakpoint(BreakpointType type, uint32_t addr, int16_t
GetState(&_debugState); GetState(&_debugState);
needState = false; needState = false;
} }
if(expEval.Evaluate(condition, _debugState, value) != 0) { if(expEval.Evaluate(condition, _debugState, value, absoluteAddr) != 0) {
return true; return true;
} }
} }

View file

@ -79,6 +79,10 @@ bool ExpressionEvaluator::CheckSpecialTokens(string expression, size_t &pos, str
output += std::to_string(EvalValues::Nmi); output += std::to_string(EvalValues::Nmi);
} else if(!token.compare("value")) { } else if(!token.compare("value")) {
output += std::to_string(EvalValues::Value); output += std::to_string(EvalValues::Value);
} else if(!token.compare("address")) {
output += std::to_string(EvalValues::Address);
} else if(!token.compare("romaddress")) {
output += std::to_string(EvalValues::AbsoluteAddress);
} else { } else {
return false; return false;
} }
@ -98,15 +102,8 @@ string ExpressionEvaluator::GetNextToken(string expression, size_t &pos)
for(size_t len = expression.size(); pos < len; pos++) { for(size_t len = expression.size(); pos < len; pos++) {
char c = std::tolower(expression[pos]); char c = std::tolower(expression[pos]);
if((c == '$' || c == '[') && pos == initialPos) { if(c == '$' && pos == initialPos) {
if(c == '$') { isHex = true;
isHex = true;
} else if(c == '[') {
isMemoryAddress = true;
//Pretend the token starts after this
initialPos++;
}
} else if((c >= '0' && c <= '9') || (isHex && c >= 'a' && c <= 'f')) { } else if((c >= '0' && c <= '9') || (isHex && c >= 'a' && c <= 'f')) {
if(isNumber || output.empty()) { if(isNumber || output.empty()) {
output += c; output += c;
@ -117,14 +114,8 @@ string ExpressionEvaluator::GetNextToken(string expression, size_t &pos)
} }
} else if(isNumber) { } else if(isNumber) {
//First non-numeric character, done //First non-numeric character, done
if(c == ']') {
if(isMemoryAddress) {
validMemoryAddress = true;
}
pos++;
}
break; break;
} else if(c == '(' || c == ')' || c == '-' || c == '+' || c == '~') { } else if(c == '(' || c == ')' || c == '[' || c == ']' || c == '-' || c == '+' || c == '~') {
if(output.empty()) { if(output.empty()) {
output += c; output += c;
pos++; pos++;
@ -172,12 +163,6 @@ string ExpressionEvaluator::GetNextToken(string expression, size_t &pos)
output = std::to_string(x); output = std::to_string(x);
} }
if(isMemoryAddress && validMemoryAddress) {
uint32_t address = std::stoi(output) % 0xFFFF;
address += EvalValues::MemoryAddress;
output = std::to_string(address);
}
return output; return output;
} }
@ -221,6 +206,16 @@ void ExpressionEvaluator::ToRpn(string expression, vector<int> &outputQueue)
opStack.pop(); opStack.pop();
} }
opStack.pop(); opStack.pop();
} else if(token[0] == '[') {
opStack.push(EvalOperators::Bracket);
precedenceStack.push(0);
} else if(token[0] == ']') {
while(opStack.top() != EvalOperators::Bracket) {
outputQueue.push_back(opStack.top());
opStack.pop();
}
outputQueue.push_back(opStack.top());
opStack.pop();
} else { } else {
outputQueue.push_back(std::stoi(token)); outputQueue.push_back(std::stoi(token));
} }
@ -232,7 +227,7 @@ void ExpressionEvaluator::ToRpn(string expression, vector<int> &outputQueue)
} }
} }
int32_t ExpressionEvaluator::EvaluateExpression(vector<int> *outputQueue, DebugState &state, EvalResultType &resultType, int16_t memoryValue) int32_t ExpressionEvaluator::EvaluateExpression(vector<int> *outputQueue, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr)
{ {
int pos = 0; int pos = 0;
int right = 0; int right = 0;
@ -257,11 +252,8 @@ int32_t ExpressionEvaluator::EvaluateExpression(vector<int> *outputQueue, DebugS
case EvalValues::PpuCycle: token = state.PPU.Cycle; break; case EvalValues::PpuCycle: token = state.PPU.Cycle; break;
case EvalValues::PpuScanline: token = state.PPU.Scanline; break; case EvalValues::PpuScanline: token = state.PPU.Scanline; break;
case EvalValues::Value: token = memoryValue; break; case EvalValues::Value: token = memoryValue; break;
} case EvalValues::Address: token = debugger->GetRelativeAddress(memoryAddr); break;
case EvalValues::AbsoluteAddress: token = memoryAddr; break;
if(token >= EvalValues::MemoryAddress) {
uint16_t memoryAddress = token - EvalValues::MemoryAddress;
token = debugger->GetMemoryValue(memoryAddress);
} }
} else if(token >= EvalOperators::Multiplication) { } else if(token >= EvalOperators::Multiplication) {
right = operandStack[--pos]; right = operandStack[--pos];
@ -291,6 +283,7 @@ int32_t ExpressionEvaluator::EvaluateExpression(vector<int> *outputQueue, DebugS
case EvalOperators::LogicalOr: token = left || right; resultType = EvalResultType::Boolean; break; case EvalOperators::LogicalOr: token = left || right; resultType = EvalResultType::Boolean; break;
//Unary operators //Unary operators
case EvalOperators::Bracket: token = debugger->GetMemoryValue(right); break;
case EvalOperators::Plus: token = right; break; case EvalOperators::Plus: token = right; break;
case EvalOperators::Minus: token = -right; break; case EvalOperators::Minus: token = -right; break;
case EvalOperators::BinaryNot: token = ~right; break; case EvalOperators::BinaryNot: token = ~right; break;
@ -307,7 +300,7 @@ ExpressionEvaluator::ExpressionEvaluator()
{ {
} }
int32_t ExpressionEvaluator::PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue) int32_t ExpressionEvaluator::PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr)
{ {
vector<int> *outputQueue = nullptr; vector<int> *outputQueue = nullptr;
@ -332,19 +325,19 @@ int32_t ExpressionEvaluator::PrivateEvaluate(string expression, DebugState &stat
outputQueue = &_outputCache[expression]; outputQueue = &_outputCache[expression];
} }
return EvaluateExpression(outputQueue, state, resultType, memoryValue); return EvaluateExpression(outputQueue, state, resultType, memoryValue, memoryAddr);
} }
int32_t ExpressionEvaluator::Evaluate(string expression, DebugState &state, int16_t memoryValue) int32_t ExpressionEvaluator::Evaluate(string expression, DebugState &state, int16_t memoryValue, uint32_t memoryAddr)
{ {
EvalResultType resultType; EvalResultType resultType;
return Evaluate(expression, state, resultType, memoryValue); return Evaluate(expression, state, resultType, memoryValue, memoryAddr);
} }
int32_t ExpressionEvaluator::Evaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue) int32_t ExpressionEvaluator::Evaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr)
{ {
try { try {
return PrivateEvaluate(expression, state, resultType, memoryValue); return PrivateEvaluate(expression, state, resultType, memoryValue, memoryAddr);
} catch(std::exception) { } catch(std::exception) {
resultType = EvalResultType::Invalid; resultType = EvalResultType::Invalid;
return 0; return 0;
@ -356,7 +349,7 @@ bool ExpressionEvaluator::Validate(string expression)
try { try {
DebugState state; DebugState state;
EvalResultType type; EvalResultType type;
PrivateEvaluate(expression, state, type, 0); PrivateEvaluate(expression, state, type, 0, 0);
return true; return true;
} catch(std::exception e) { } catch(std::exception e) {
return false; return false;

View file

@ -35,8 +35,11 @@ enum EvalOperators
BinaryNot = 2000000052, BinaryNot = 2000000052,
LogicalNot = 2000000053, LogicalNot = 2000000053,
//Used to read ram address
Bracket = 2000000054,
//Special value, not used as an operator //Special value, not used as an operator
Parenthesis = 2000000100 Parenthesis = 2000000100,
}; };
enum EvalValues enum EvalValues
@ -51,8 +54,8 @@ enum EvalValues
Nmi = 2000000107, Nmi = 2000000107,
Irq = 2000000108, Irq = 2000000108,
Value = 2000000109, Value = 2000000109,
Address = 2000000110,
MemoryAddress = 2000100000 AbsoluteAddress = 2000000111,
}; };
enum EvalResultType enum EvalResultType
@ -89,13 +92,13 @@ private:
bool CheckSpecialTokens(string expression, size_t &pos, string &output); bool CheckSpecialTokens(string expression, size_t &pos, string &output);
string GetNextToken(string expression, size_t &pos); string GetNextToken(string expression, size_t &pos);
void ToRpn(string expression, vector<int> &outputQueue); void ToRpn(string expression, vector<int> &outputQueue);
int32_t EvaluateExpression(vector<int> *outputQueue, DebugState &state, EvalResultType &resultType, int16_t memoryValue); int32_t EvaluateExpression(vector<int> *outputQueue, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr);
int32_t PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue); int32_t PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr);
public: public:
ExpressionEvaluator(); ExpressionEvaluator();
int32_t Evaluate(string expression, DebugState &state, int16_t memoryValue = 0); int32_t Evaluate(string expression, DebugState &state, int16_t memoryValue = 0, uint32_t memoryAddr = 0);
int32_t Evaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue = 0); int32_t Evaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue = 0, uint32_t memoryAddr = 0);
bool Validate(string expression); bool Validate(string expression);
}; };

View file

@ -37,7 +37,23 @@ namespace Mesen.GUI.Debugger
AddBinding("Condition", txtCondition); AddBinding("Condition", txtCondition);
this.toolTip.SetToolTip(this.chkAbsolute, "Check to set an absolute address based on the exact address in PRG/CHR ROM (not CPU/PPU memory)"); this.toolTip.SetToolTip(this.chkAbsolute, "Check to set an absolute address based on the exact address in PRG/CHR ROM (not CPU/PPU memory)");
this.toolTip.SetToolTip(this.picHelp, "Most expressions/operators are accepted (C++ syntax)." + Environment.NewLine + "Note: Use the $ prefix to denote hexadecimal values." + Environment.NewLine + Environment.NewLine + "A/X/Y/PS/SP: Value of registers" + Environment.NewLine +"Irq/Nmi: True if the Irq/Nmi flags are set" + Environment.NewLine + "Cycle/Scanline: Current cycle (0-340)/scanline(-1 to 260) of the PPU" + Environment.NewLine + "Value: Current value being read/written from/to memory" + Environment.NewLine + "[<address>]: Value at address (CPU)" + Environment.NewLine + Environment.NewLine + "Examples:" + Environment.NewLine + "a == 10 || x == $23" + Environment.NewLine + "scanline == 10 && (cycle >= 55 && cycle <= 100)" + Environment.NewLine + "x == [$150] || y == [10]"); this.toolTip.SetToolTip(this.picHelp,
"Most expressions/operators are accepted (C++ syntax)." + Environment.NewLine +
"Note: Use the $ prefix to denote hexadecimal values." + Environment.NewLine + Environment.NewLine +
"A/X/Y/PS/SP: Value of registers" + Environment.NewLine +
"Irq/Nmi: True if the Irq/Nmi flags are set" + Environment.NewLine +
"Cycle/Scanline: Current cycle (0-340)/scanline(-1 to 260) of the PPU" + Environment.NewLine +
"Value: Current value being read/written from/to memory" + Environment.NewLine +
"Address: Current CPU memory address being read/written" + Environment.NewLine +
"RomAddress: Current ROM address being read/written" + Environment.NewLine +
"[<address>]: Value at address (CPU)" + Environment.NewLine + Environment.NewLine +
"Examples:" + Environment.NewLine +
"a == 10 || x == $23" + Environment.NewLine +
"scanline == 10 && (cycle >= 55 && cycle <= 100)" + Environment.NewLine +
"x == [$150] || y == [10]" + Environment.NewLine +
"[[$15] + y] -> Reads the value at address $15, adds Y to it and reads the value at the resulting address."
);
} }
protected override bool ValidateInput() protected override bool ValidateInput()

View file

@ -61,8 +61,9 @@
this.mnuToggleBreakpoint = new System.Windows.Forms.ToolStripMenuItem(); this.mnuToggleBreakpoint = new System.Windows.Forms.ToolStripMenuItem();
this.mnuDisableEnableBreakpoint = new System.Windows.Forms.ToolStripMenuItem(); this.mnuDisableEnableBreakpoint = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator(); this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator();
this.mnuRunOneFrame = new System.Windows.Forms.ToolStripMenuItem();
this.mnuRunPpuCycle = new System.Windows.Forms.ToolStripMenuItem(); this.mnuRunPpuCycle = new System.Windows.Forms.ToolStripMenuItem();
this.mnuRunScanline = new System.Windows.Forms.ToolStripMenuItem();
this.mnuRunOneFrame = new System.Windows.Forms.ToolStripMenuItem();
this.searchToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.searchToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.mnuFind = new System.Windows.Forms.ToolStripMenuItem(); this.mnuFind = new System.Windows.Forms.ToolStripMenuItem();
this.mnuFindNext = new System.Windows.Forms.ToolStripMenuItem(); this.mnuFindNext = new System.Windows.Forms.ToolStripMenuItem();
@ -99,7 +100,7 @@
this.lblChrAnalysis = new System.Windows.Forms.ToolStripStatusLabel(); this.lblChrAnalysis = new System.Windows.Forms.ToolStripStatusLabel();
this.lblChrAnalysisResult = new System.Windows.Forms.ToolStripStatusLabel(); this.lblChrAnalysisResult = new System.Windows.Forms.ToolStripStatusLabel();
this.tmrCdlRatios = new System.Windows.Forms.Timer(this.components); this.tmrCdlRatios = new System.Windows.Forms.Timer(this.components);
this.mnuRunScanline = new System.Windows.Forms.ToolStripMenuItem(); this.picWatchHelp = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
this.splitContainer.Panel1.SuspendLayout(); this.splitContainer.Panel1.SuspendLayout();
this.splitContainer.Panel2.SuspendLayout(); this.splitContainer.Panel2.SuspendLayout();
@ -112,6 +113,7 @@
this.grpCallstack.SuspendLayout(); this.grpCallstack.SuspendLayout();
this.menuStrip.SuspendLayout(); this.menuStrip.SuspendLayout();
this.statusStrip.SuspendLayout(); this.statusStrip.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picWatchHelp)).BeginInit();
this.SuspendLayout(); this.SuspendLayout();
// //
// splitContainer // splitContainer
@ -230,6 +232,7 @@
// //
// grpWatch // grpWatch
// //
this.grpWatch.Controls.Add(this.picWatchHelp);
this.grpWatch.Controls.Add(this.ctrlWatch); this.grpWatch.Controls.Add(this.ctrlWatch);
this.grpWatch.Dock = System.Windows.Forms.DockStyle.Fill; this.grpWatch.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpWatch.Location = new System.Drawing.Point(3, 3); this.grpWatch.Location = new System.Drawing.Point(3, 3);
@ -409,14 +412,6 @@
this.toolStripMenuItem2.Name = "toolStripMenuItem2"; this.toolStripMenuItem2.Name = "toolStripMenuItem2";
this.toolStripMenuItem2.Size = new System.Drawing.Size(255, 6); this.toolStripMenuItem2.Size = new System.Drawing.Size(255, 6);
// //
// mnuRunOneFrame
//
this.mnuRunOneFrame.Name = "mnuRunOneFrame";
this.mnuRunOneFrame.ShortcutKeys = System.Windows.Forms.Keys.F8;
this.mnuRunOneFrame.Size = new System.Drawing.Size(258, 22);
this.mnuRunOneFrame.Text = "Run one frame";
this.mnuRunOneFrame.Click += new System.EventHandler(this.mnuRunOneFrame_Click);
//
// mnuRunPpuCycle // mnuRunPpuCycle
// //
this.mnuRunPpuCycle.Name = "mnuRunPpuCycle"; this.mnuRunPpuCycle.Name = "mnuRunPpuCycle";
@ -425,6 +420,22 @@
this.mnuRunPpuCycle.Text = "Run one PPU cycle"; this.mnuRunPpuCycle.Text = "Run one PPU cycle";
this.mnuRunPpuCycle.Click += new System.EventHandler(this.mnuRunPpuCycle_Click); this.mnuRunPpuCycle.Click += new System.EventHandler(this.mnuRunPpuCycle_Click);
// //
// mnuRunScanline
//
this.mnuRunScanline.Name = "mnuRunScanline";
this.mnuRunScanline.ShortcutKeys = System.Windows.Forms.Keys.F7;
this.mnuRunScanline.Size = new System.Drawing.Size(258, 22);
this.mnuRunScanline.Text = "Run one scanline";
this.mnuRunScanline.Click += new System.EventHandler(this.mnuRunScanline_Click);
//
// mnuRunOneFrame
//
this.mnuRunOneFrame.Name = "mnuRunOneFrame";
this.mnuRunOneFrame.ShortcutKeys = System.Windows.Forms.Keys.F8;
this.mnuRunOneFrame.Size = new System.Drawing.Size(258, 22);
this.mnuRunOneFrame.Text = "Run one frame";
this.mnuRunOneFrame.Click += new System.EventHandler(this.mnuRunOneFrame_Click);
//
// searchToolStripMenuItem // searchToolStripMenuItem
// //
this.searchToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.searchToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
@ -716,13 +727,15 @@
this.tmrCdlRatios.Interval = 300; this.tmrCdlRatios.Interval = 300;
this.tmrCdlRatios.Tick += new System.EventHandler(this.tmrCdlRatios_Tick); this.tmrCdlRatios.Tick += new System.EventHandler(this.tmrCdlRatios_Tick);
// //
// mnuRunScanline // picWatchHelp
// //
this.mnuRunScanline.Name = "mnuRunScanline"; this.picWatchHelp.Image = global::Mesen.GUI.Properties.Resources.Help;
this.mnuRunScanline.ShortcutKeys = System.Windows.Forms.Keys.F7; this.picWatchHelp.Location = new System.Drawing.Point(43, 0);
this.mnuRunScanline.Size = new System.Drawing.Size(258, 22); this.picWatchHelp.Name = "picWatchHelp";
this.mnuRunScanline.Text = "Run one scanline"; this.picWatchHelp.Size = new System.Drawing.Size(14, 14);
this.mnuRunScanline.Click += new System.EventHandler(this.mnuRunScanline_Click); this.picWatchHelp.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
this.picWatchHelp.TabIndex = 1;
this.picWatchHelp.TabStop = false;
// //
// frmDebugger // frmDebugger
// //
@ -751,6 +764,7 @@
this.menuStrip.PerformLayout(); this.menuStrip.PerformLayout();
this.statusStrip.ResumeLayout(false); this.statusStrip.ResumeLayout(false);
this.statusStrip.PerformLayout(); this.statusStrip.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.picWatchHelp)).EndInit();
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout(); this.PerformLayout();
@ -826,5 +840,6 @@
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem5; private System.Windows.Forms.ToolStripSeparator toolStripMenuItem5;
private System.Windows.Forms.ToolStripMenuItem mnuPpuPartialDraw; private System.Windows.Forms.ToolStripMenuItem mnuPpuPartialDraw;
private System.Windows.Forms.ToolStripMenuItem mnuRunScanline; private System.Windows.Forms.ToolStripMenuItem mnuRunScanline;
private System.Windows.Forms.PictureBox picWatchHelp;
} }
} }

View file

@ -38,6 +38,22 @@ namespace Mesen.GUI.Debugger
BreakpointManager.BreakpointsChanged += BreakpointManager_BreakpointsChanged; BreakpointManager.BreakpointsChanged += BreakpointManager_BreakpointsChanged;
this.ctrlBreakpoints.RefreshList(); this.ctrlBreakpoints.RefreshList();
RefreshBreakpoints(); RefreshBreakpoints();
this.toolTip.SetToolTip(this.picWatchHelp,
"Most expressions/operators are accepted (C++ syntax)." + Environment.NewLine +
"Note: Use the $ prefix to denote hexadecimal values." + Environment.NewLine + Environment.NewLine +
"A/X/Y/PS/SP: Value of registers" + Environment.NewLine +
"Irq/Nmi: True if the Irq/Nmi flags are set" + Environment.NewLine +
"Cycle/Scanline: Current cycle (0-340)/scanline(-1 to 260) of the PPU" + Environment.NewLine +
"Value: Current value being read/written from/to memory" + Environment.NewLine +
"[<address>]: Value at address (CPU)" + Environment.NewLine + Environment.NewLine +
"Examples:" + Environment.NewLine +
"a == 10 || x == $23" + Environment.NewLine +
"scanline == 10 && (cycle >= 55 && cycle <= 100)" + Environment.NewLine +
"x == [$150] || y == [10]" + Environment.NewLine +
"[[$15] + y] -> Reads the value at address $15, adds Y to it and reads the value at the resulting address."
);
} }
} }