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);
needState = false;
}
if(expEval.Evaluate(condition, _debugState, value) != 0) {
if(expEval.Evaluate(condition, _debugState, value, absoluteAddr) != 0) {
return true;
}
}

View file

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

View file

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

View file

@ -37,7 +37,23 @@ namespace Mesen.GUI.Debugger
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.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()

View file

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