diff --git a/Core/Debugger.cpp b/Core/Debugger.cpp index f891a2a5..ea1fe766 100644 --- a/Core/Debugger.cpp +++ b/Core/Debugger.cpp @@ -52,6 +52,9 @@ Debugger::Debugger(shared_ptr console, shared_ptr cpu, shared_ptr< _profiler.reset(new Profiler(this)); _traceLogger.reset(new TraceLogger(this, memoryManager, _labelManager)); + _bpExpEval.reset(new ExpressionEvaluator(this)); + _watchExpEval.reset(new ExpressionEvaluator(this)); + _stepOut = false; _stepCount = -1; _stepOverAddr = -1; @@ -246,15 +249,20 @@ void Debugger::SetBreakpoints(Breakpoint breakpoints[], uint32_t length) _hasBreakpoint[i] = false; } - ExpressionEvaluator expEval(this); + _bpExpEval.reset(new ExpressionEvaluator(this)); for(uint32_t j = 0; j < length; j++) { Breakpoint &bp = breakpoints[j]; for(int i = 0; i < Debugger::BreakpointTypeCount; i++) { bool isEnabled = bp.IsEnabled() && _console->GetSettings()->CheckFlag(EmulationFlags::DebuggerWindowEnabled); if((bp.IsMarked() || isEnabled) && bp.HasBreakpointType((BreakpointType)i)) { _breakpoints[i].push_back(bp); - vector *rpnList = expEval.GetRpnList(bp.GetCondition()); - _breakpointRpnList[i].push_back(rpnList ? *rpnList : vector()); + + bool success = true; + if(bp.HasCondition()) { + ExpressionData data = _bpExpEval->GetRpnList(bp.GetCondition(), success); + _breakpointRpnList[i].push_back(success ? data : ExpressionData()); + } + _hasBreakpoint[i] = true; } } @@ -318,7 +326,7 @@ void Debugger::ProcessBreakpoints(BreakpointType type, OperationInfo &operationI GetState(&_debugState, false); needState = false; } - if(_bpExpEval.Evaluate(_breakpointRpnList[(int)type][i], _debugState, resultType, operationInfo) != 0) { + if(_bpExpEval->Evaluate(_breakpointRpnList[(int)type][i], _debugState, resultType, operationInfo) != 0) { processBreakpoint(breakpoint); } } @@ -341,12 +349,17 @@ void Debugger::ProcessBreakpoints(BreakpointType type, OperationInfo &operationI } } -int32_t Debugger::EvaluateExpression(string expression, EvalResultType &resultType) +int32_t Debugger::EvaluateExpression(string expression, EvalResultType &resultType, bool useCache) { DebugState state; OperationInfo operationInfo { 0, 0, MemoryOperationType::DummyRead }; GetState(&state); - return _watchExpEval.Evaluate(expression, state, resultType, operationInfo); + if(useCache) { + return _watchExpEval->Evaluate(expression, state, resultType, operationInfo); + } else { + ExpressionEvaluator expEval(this); + return expEval.Evaluate(expression, state, resultType, operationInfo); + } } void Debugger::UpdateCallstack(uint8_t instruction, uint32_t addr) diff --git a/Core/Debugger.h b/Core/Debugger.h index 8db330b8..8318b4d2 100644 --- a/Core/Debugger.h +++ b/Core/Debugger.h @@ -10,7 +10,6 @@ using std::unordered_set; #include "../Utilities/SimpleLock.h" #include "DebuggerTypes.h" -#include "ExpressionEvaluator.h" class CPU; class APU; @@ -29,7 +28,10 @@ class ScriptHost; class TraceLogger; class Breakpoint; class CodeDataLogger; +class ExpressionEvaluator; +struct ExpressionData; +enum EvalResultType : int32_t; enum class CdlStripFlag; class Debugger @@ -67,7 +69,7 @@ private: atomic _executionStopped; atomic _suspendCount; vector _breakpoints[BreakpointTypeCount]; - vector> _breakpointRpnList[BreakpointTypeCount]; + vector _breakpointRpnList[BreakpointTypeCount]; bool _hasBreakpoint[BreakpointTypeCount] = {}; vector _frozenAddresses; @@ -79,8 +81,8 @@ private: unordered_set _functionEntryPoints; - ExpressionEvaluator _watchExpEval = ExpressionEvaluator(this); - ExpressionEvaluator _bpExpEval = ExpressionEvaluator(this); + unique_ptr _watchExpEval; + unique_ptr _bpExpEval; DebugState _debugState; SimpleLock _breakLock; @@ -215,7 +217,7 @@ public: shared_ptr GetMemoryDumper(); shared_ptr GetMemoryAccessCounter(); - int32_t EvaluateExpression(string expression, EvalResultType &resultType); + int32_t EvaluateExpression(string expression, EvalResultType &resultType, bool useCache); void ProcessPpuCycle(); bool ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uint8_t &value); diff --git a/Core/ExpressionEvaluator.cpp b/Core/ExpressionEvaluator.cpp index 104238d8..7ecbc0d4 100644 --- a/Core/ExpressionEvaluator.cpp +++ b/Core/ExpressionEvaluator.cpp @@ -8,12 +8,9 @@ #include "LabelManager.h" #include "../Utilities/HexUtilities.h" -std::unordered_map, StringHasher> ExpressionEvaluator::_outputCache; -SimpleLock ExpressionEvaluator::_cacheLock; - const vector ExpressionEvaluator::_binaryOperators = { { "*", "/", "%", "+", "-", "<<", ">>", "<", "<=", ">", ">=", "==", "!=", "&", "^", "|", "&&", "||" } }; const vector ExpressionEvaluator::_binaryPrecedence = { { 10, 10, 10, 9, 9, 8, 8, 7, 7, 7, 7, 6, 6, 5, 4, 3, 2, 1 } }; -const vector ExpressionEvaluator::_unaryOperators = { { "+", "-", "!", "~" } }; +const vector ExpressionEvaluator::_unaryOperators = { { "+", "-", "~", "!" } }; const vector ExpressionEvaluator::_unaryPrecedence = { { 11, 11, 11, 11 } }; bool ExpressionEvaluator::IsOperator(string token, int &precedence, bool unaryOperator) @@ -41,20 +38,20 @@ EvalOperators ExpressionEvaluator::GetOperator(string token, bool unaryOperator) if(unaryOperator) { for(size_t i = 0, len = _unaryOperators.size(); i < len; i++) { if(token.compare(_unaryOperators[i]) == 0) { - return (EvalOperators)(2000000050 + i); + return (EvalOperators)(EvalOperators::Plus + i); } } } else { for(size_t i = 0, len = _binaryOperators.size(); i < len; i++) { if(token.compare(_binaryOperators[i]) == 0) { - return (EvalOperators)(2000000000 + i); + return (EvalOperators)(EvalOperators::Multiplication + i); } } } return EvalOperators::Addition; } -bool ExpressionEvaluator::CheckSpecialTokens(string expression, size_t &pos, string &output) +bool ExpressionEvaluator::CheckSpecialTokens(string expression, size_t &pos, string &output, ExpressionData &data) { string token; size_t initialPos = pos; @@ -70,46 +67,46 @@ bool ExpressionEvaluator::CheckSpecialTokens(string expression, size_t &pos, str } } while(pos < len); - if(!token.compare("a")) { - output += std::to_string(EvalValues::RegA); - } else if(!token.compare("x")) { - output += std::to_string(EvalValues::RegX); - } else if(!token.compare("y")) { - output += std::to_string(EvalValues::RegY); - } else if(!token.compare("ps")) { - output += std::to_string(EvalValues::RegPS); - } else if(!token.compare("sp")) { - output += std::to_string(EvalValues::RegSP); - } else if(!token.compare("pc")) { - output += std::to_string(EvalValues::RegPC); - } else if(!token.compare("oppc")) { - output += std::to_string(EvalValues::RegOpPC); - } else if(!token.compare("frame")) { - output += std::to_string(EvalValues::PpuFrameCount); - } else if(!token.compare("cycle")) { - output += std::to_string(EvalValues::PpuCycle); - } else if(!token.compare("scanline")) { - output += std::to_string(EvalValues::PpuScanline); - } else if(!token.compare("irq")) { - output += std::to_string(EvalValues::Irq); - } else if(!token.compare("nmi")) { - 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 if(!token.compare("iswrite")) { - output += std::to_string(EvalValues::IsWrite); - } else if(!token.compare("isread")) { - output += std::to_string(EvalValues::IsRead); + if(token == "a") { + output += std::to_string((int64_t)EvalValues::RegA); + } else if(token == "x") { + output += std::to_string((int64_t)EvalValues::RegX); + } else if(token == "y") { + output += std::to_string((int64_t)EvalValues::RegY); + } else if(token == "ps") { + output += std::to_string((int64_t)EvalValues::RegPS); + } else if(token == "sp") { + output += std::to_string((int64_t)EvalValues::RegSP); + } else if(token == "pc") { + output += std::to_string((int64_t)EvalValues::RegPC); + } else if(token == "oppc") { + output += std::to_string((int64_t)EvalValues::RegOpPC); + } else if(token == "frame") { + output += std::to_string((int64_t)EvalValues::PpuFrameCount); + } else if(token == "cycle") { + output += std::to_string((int64_t)EvalValues::PpuCycle); + } else if(token == "scanline") { + output += std::to_string((int64_t)EvalValues::PpuScanline); + } else if(token == "irq") { + output += std::to_string((int64_t)EvalValues::Irq); + } else if(token == "nmi") { + output += std::to_string((int64_t)EvalValues::Nmi); + } else if(token == "value") { + output += std::to_string((int64_t)EvalValues::Value); + } else if(token == "address") { + output += std::to_string((int64_t)EvalValues::Address); + } else if(token == "romaddress") { + output += std::to_string((int64_t)EvalValues::AbsoluteAddress); + } else if(token == "iswrite") { + output += std::to_string((int64_t)EvalValues::IsWrite); + } else if(token == "isread") { + output += std::to_string((int64_t)EvalValues::IsRead); } else { string originalExpression = expression.substr(initialPos, pos - initialPos); - int32_t address = _debugger->GetLabelManager()->GetLabelRelativeAddress(originalExpression); - if(address >= 0) { - _containsCustomLabels = true; - output += std::to_string(address); + bool validLabel = _debugger->GetLabelManager()->ContainsLabel(originalExpression); + if(validLabel) { + data.Labels.push_back(originalExpression); + output += std::to_string(EvalValues::FirstLabelIndex + data.Labels.size() - 1); } else { return false; } @@ -118,7 +115,7 @@ bool ExpressionEvaluator::CheckSpecialTokens(string expression, size_t &pos, str return true; } -string ExpressionEvaluator::GetNextToken(string expression, size_t &pos) +string ExpressionEvaluator::GetNextToken(string expression, size_t &pos, ExpressionData &data) { string output; bool isOperator = false; @@ -171,7 +168,7 @@ string ExpressionEvaluator::GetNextToken(string expression, size_t &pos) break; } else { if(output.empty()) { - if(CheckSpecialTokens(expression, pos, output)) { + if(CheckSpecialTokens(expression, pos, output, data)) { break; } } @@ -188,7 +185,7 @@ string ExpressionEvaluator::GetNextToken(string expression, size_t &pos) return output; } -bool ExpressionEvaluator::ProcessSpecialOperator(EvalOperators evalOp, std::stack &opStack, std::stack &precedenceStack, vector &outputQueue) +bool ExpressionEvaluator::ProcessSpecialOperator(EvalOperators evalOp, std::stack &opStack, std::stack &precedenceStack, vector &outputQueue) { if(opStack.empty()) { return false; @@ -211,7 +208,7 @@ bool ExpressionEvaluator::ProcessSpecialOperator(EvalOperators evalOp, std::stac return true; } -bool ExpressionEvaluator::ToRpn(string expression, vector &outputQueue) +bool ExpressionEvaluator::ToRpn(string expression, ExpressionData &data) { std::stack opStack = std::stack(); std::stack precedenceStack; @@ -223,7 +220,7 @@ bool ExpressionEvaluator::ToRpn(string expression, vector &outputQueue) bool previousTokenIsOp = true; while(true) { - string token = GetNextToken(expression, position); + string token = GetNextToken(expression, position, data); if(token.empty()) { break; } @@ -239,7 +236,7 @@ bool ExpressionEvaluator::ToRpn(string expression, vector &outputQueue) if((unaryOperator && precedence < precedenceStack.top()) || (!unaryOperator && precedence <= precedenceStack.top())) { opStack.pop(); precedenceStack.pop(); - outputQueue.push_back(topOp); + data.RpnQueue.push_back(topOp); } } opStack.push(op); @@ -253,7 +250,7 @@ bool ExpressionEvaluator::ToRpn(string expression, vector &outputQueue) previousTokenIsOp = true; } else if(token[0] == ')') { parenthesisCount--; - if(!ProcessSpecialOperator(EvalOperators::Parenthesis, opStack, precedenceStack, outputQueue)) { + if(!ProcessSpecialOperator(EvalOperators::Parenthesis, opStack, precedenceStack, data.RpnQueue)) { return false; } } else if(token[0] == '[') { @@ -262,7 +259,7 @@ bool ExpressionEvaluator::ToRpn(string expression, vector &outputQueue) precedenceStack.push(0); } else if(token[0] == ']') { bracketCount--; - if(!ProcessSpecialOperator(EvalOperators::Bracket, opStack, precedenceStack, outputQueue)) { + if(!ProcessSpecialOperator(EvalOperators::Bracket, opStack, precedenceStack, data.RpnQueue)) { return false; } } else if(token[0] == '{') { @@ -271,14 +268,14 @@ bool ExpressionEvaluator::ToRpn(string expression, vector &outputQueue) precedenceStack.push(0); } else if(token[0] == '}') { braceCount--; - if(!ProcessSpecialOperator(EvalOperators::Braces, opStack, precedenceStack, outputQueue)){ + if(!ProcessSpecialOperator(EvalOperators::Braces, opStack, precedenceStack, data.RpnQueue)){ return false; } } else { if(token[0] < '0' || token[0] > '9') { return false; } else { - outputQueue.push_back(std::stoi(token)); + data.RpnQueue.push_back(std::stoll(token)); } } } @@ -289,43 +286,62 @@ bool ExpressionEvaluator::ToRpn(string expression, vector &outputQueue) } while(!opStack.empty()) { - outputQueue.push_back(opStack.top()); + data.RpnQueue.push_back(opStack.top()); opStack.pop(); } return true; } -int32_t ExpressionEvaluator::Evaluate(vector &rpnList, DebugState &state, EvalResultType &resultType, OperationInfo &operationInfo) +int32_t ExpressionEvaluator::Evaluate(ExpressionData &data, DebugState &state, EvalResultType &resultType, OperationInfo &operationInfo) { + if(data.RpnQueue.empty()) { + resultType = EvalResultType::Invalid; + return 0; + } + int pos = 0; - int right = 0; - int left = 0; + int64_t right = 0; + int64_t left = 0; resultType = EvalResultType::Numeric; - for(size_t i = 0, len = rpnList.size(); i < len; i++) { - int token = rpnList[i]; + for(size_t i = 0, len = data.RpnQueue.size(); i < len; i++) { + int64_t token = data.RpnQueue[i]; if(token >= EvalValues::RegA) { //Replace value with a special value - 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::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; break; - case EvalValues::Irq: token = state.CPU.IRQFlag; 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.OperationType == MemoryOperationType::Write; break; - case EvalValues::IsRead: token = operationInfo.OperationType == MemoryOperationType::Read; break; + if(token >= EvalValues::FirstLabelIndex) { + int64_t labelIndex = token - EvalValues::FirstLabelIndex; + if((size_t)labelIndex < data.Labels.size()) { + token = _debugger->GetLabelManager()->GetLabelRelativeAddress(data.Labels[labelIndex]); + } else { + token = -1; + } + if(token < 0) { + //Label is no longer valid + resultType = EvalResultType::Invalid; + return 0; + } + } 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; + 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; break; + case EvalValues::Irq: token = state.CPU.IRQFlag; 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.OperationType == MemoryOperationType::Write; break; + case EvalValues::IsRead: token = operationInfo.OperationType == MemoryOperationType::Read; break; + } } } else if(token >= EvalOperators::Multiplication) { right = operandStack[--pos]; @@ -371,14 +387,14 @@ int32_t ExpressionEvaluator::Evaluate(vector &rpnList, 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(DebugMemoryType::CpuMemory, right); break; - case EvalOperators::Braces: token = _debugger->GetMemoryDumper()->GetMemoryValueWord(DebugMemoryType::CpuMemory, right); break; + case EvalOperators::Bracket: token = _debugger->GetMemoryDumper()->GetMemoryValue(DebugMemoryType::CpuMemory, (uint32_t)right); break; + case EvalOperators::Braces: token = _debugger->GetMemoryDumper()->GetMemoryValueWord(DebugMemoryType::CpuMemory, (uint32_t)right); break; default: throw std::runtime_error("Invalid operator"); } } operandStack[pos++] = token; } - return operandStack[0]; + return (int32_t)operandStack[0]; } ExpressionEvaluator::ExpressionEvaluator(Debugger* debugger) @@ -386,55 +402,55 @@ ExpressionEvaluator::ExpressionEvaluator(Debugger* debugger) _debugger = debugger; } -vector* ExpressionEvaluator::GetRpnList(string expression) +ExpressionData ExpressionEvaluator::GetRpnList(string expression, bool &success) { - vector output; - bool success; - return GetRpnList(expression, output, success); + ExpressionData* cachedData = PrivateGetRpnList(expression, success); + if(cachedData) { + return *cachedData; + } else { + return ExpressionData(); + } } -vector* ExpressionEvaluator::GetRpnList(string expression, vector &output, bool& success) +ExpressionData* ExpressionEvaluator::PrivateGetRpnList(string expression, bool& success) { - vector *outputQueue = nullptr; + ExpressionData *cachedData = nullptr; { LockHandler lock = _cacheLock.AcquireSafe(); - auto cacheOutputQueue = _outputCache.find(expression); - if(cacheOutputQueue != _outputCache.end()) { - outputQueue = &(cacheOutputQueue->second); + auto result = _cache.find(expression); + if(result != _cache.end()) { + cachedData = &(result->second); } } - if(outputQueue == nullptr) { + if(cachedData == nullptr) { string fixedExp = expression; fixedExp.erase(std::remove(fixedExp.begin(), fixedExp.end(), ' '), fixedExp.end()); - success = ToRpn(fixedExp, output); - - if(success && !_containsCustomLabels) { + ExpressionData data; + success = ToRpn(fixedExp, data); + if(success) { LockHandler lock = _cacheLock.AcquireSafe(); - _outputCache[expression] = output; - outputQueue = &_outputCache[expression]; + _cache[expression] = data; + cachedData = &_cache[expression]; } + } else { + success = true; } - return outputQueue; + return cachedData; } int32_t ExpressionEvaluator::PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, OperationInfo &operationInfo, bool& success) { success = true; - vector output; - vector *rpnList = GetRpnList(expression, output, success); + ExpressionData *cachedData = PrivateGetRpnList(expression, success); if(!success) { return 0; } - if(!rpnList) { - rpnList = &output; - } - - return Evaluate(*rpnList, state, resultType, operationInfo); + return Evaluate(*cachedData, state, resultType, operationInfo); } int32_t ExpressionEvaluator::Evaluate(string expression, DebugState &state, EvalResultType &resultType, OperationInfo &operationInfo) diff --git a/Core/ExpressionEvaluator.h b/Core/ExpressionEvaluator.h index 69d6d5c8..d56e58a1 100644 --- a/Core/ExpressionEvaluator.h +++ b/Core/ExpressionEvaluator.h @@ -8,64 +8,66 @@ class Debugger; -enum EvalOperators +enum EvalOperators : int64_t { //Binary operators - Multiplication = 2000000000, - Division = 2000000001, - Modulo = 2000000002, - Addition = 2000000003, - Substration = 2000000004, - ShiftLeft = 2000000005, - ShiftRight = 2000000006, - SmallerThan = 2000000007, - SmallerOrEqual = 2000000008, - GreaterThan = 2000000009, - GreaterOrEqual = 2000000010, - Equal = 2000000011, - NotEqual = 2000000012, - BinaryAnd = 2000000013, - BinaryXor = 2000000014, - BinaryOr = 2000000015, - LogicalAnd = 2000000016, - LogicalOr = 2000000017, + Multiplication = 20000000000, + Division = 20000000001, + Modulo = 20000000002, + Addition = 20000000003, + Substration = 20000000004, + ShiftLeft = 20000000005, + ShiftRight = 20000000006, + SmallerThan = 20000000007, + SmallerOrEqual = 20000000008, + GreaterThan = 20000000009, + GreaterOrEqual = 20000000010, + Equal = 20000000011, + NotEqual = 20000000012, + BinaryAnd = 20000000013, + BinaryXor = 20000000014, + BinaryOr = 20000000015, + LogicalAnd = 20000000016, + LogicalOr = 20000000017, //Unary operators - Plus = 2000000050, - Minus = 2000000051, - BinaryNot = 2000000052, - LogicalNot = 2000000053, + Plus = 20000000050, + Minus = 20000000051, + BinaryNot = 20000000052, + LogicalNot = 20000000053, //Used to read ram address - Bracket = 2000000054, //Read byte - Braces = 2000000055, //Read word + Bracket = 20000000054, //Read byte + Braces = 20000000055, //Read word //Special value, not used as an operator - Parenthesis = 2000000100, + Parenthesis = 20000000100, }; -enum EvalValues +enum EvalValues : int64_t { - RegA = 2000000100, - RegX = 2000000101, - RegY = 2000000102, - RegSP = 2000000103, - RegPS = 2000000104, - RegPC = 2000000105, - RegOpPC = 2000000106, - PpuFrameCount = 2000000107, - PpuCycle = 2000000108, - PpuScanline = 2000000109, - Nmi = 2000000110, - Irq = 2000000111, - Value = 2000000112, - Address = 2000000113, - AbsoluteAddress = 2000000114, - IsWrite = 2000000115, - IsRead = 2000000116, + RegA = 20000000100, + RegX = 20000000101, + RegY = 20000000102, + RegSP = 20000000103, + RegPS = 20000000104, + RegPC = 20000000105, + RegOpPC = 20000000106, + PpuFrameCount = 20000000107, + PpuCycle = 20000000108, + PpuScanline = 20000000109, + Nmi = 20000000110, + Irq = 20000000111, + Value = 20000000112, + Address = 20000000113, + AbsoluteAddress = 20000000114, + IsWrite = 20000000115, + IsRead = 20000000116, + + FirstLabelIndex = 20000002000, }; -enum EvalResultType +enum EvalResultType : int32_t { Numeric = 0, Boolean = 1, @@ -83,6 +85,12 @@ public: } }; +struct ExpressionData +{ + std::vector RpnQueue; + std::vector Labels; +}; + class ExpressionEvaluator { private: @@ -91,28 +99,27 @@ private: static const vector _unaryOperators; static const vector _unaryPrecedence; - static std::unordered_map, StringHasher> _outputCache; - static SimpleLock _cacheLock; + std::unordered_map _cache; + SimpleLock _cacheLock; - int operandStack[1000]; + int64_t operandStack[1000]; Debugger* _debugger; - bool _containsCustomLabels = false; bool IsOperator(string token, int &precedence, bool unaryOperator); EvalOperators GetOperator(string token, bool unaryOperator); - bool CheckSpecialTokens(string expression, size_t &pos, string &output); - string GetNextToken(string expression, size_t &pos); - bool ProcessSpecialOperator(EvalOperators evalOp, std::stack &opStack, std::stack &precedenceStack, vector &outputQueue); - bool ToRpn(string expression, vector &outputQueue); + bool CheckSpecialTokens(string expression, size_t &pos, string &output, ExpressionData &data); + string GetNextToken(string expression, size_t &pos, ExpressionData &data); + bool ProcessSpecialOperator(EvalOperators evalOp, std::stack &opStack, std::stack &precedenceStack, vector &outputQueue); + bool ToRpn(string expression, ExpressionData &data); int32_t PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, OperationInfo &operationInfo, bool &success); - vector* GetRpnList(string expression, vector &output, bool& success); + ExpressionData* PrivateGetRpnList(string expression, bool& success); public: ExpressionEvaluator(Debugger* debugger); - int32_t Evaluate(vector &outputQueue, DebugState &state, EvalResultType &resultType, OperationInfo &operationInfo); + int32_t Evaluate(ExpressionData &data, DebugState &state, EvalResultType &resultType, OperationInfo &operationInfo); int32_t Evaluate(string expression, DebugState &state, EvalResultType &resultType, OperationInfo &operationInfo); - vector* GetRpnList(string expression); + ExpressionData GetRpnList(string expression, bool &success); bool Validate(string expression); }; \ No newline at end of file diff --git a/Core/LabelManager.cpp b/Core/LabelManager.cpp index 63693286..3909d629 100644 --- a/Core/LabelManager.cpp +++ b/Core/LabelManager.cpp @@ -133,7 +133,12 @@ void LabelManager::GetLabelAndComment(uint16_t relativeAddr, string &label, stri } } -int32_t LabelManager::GetLabelRelativeAddress(string label) +bool LabelManager::ContainsLabel(string &label) +{ + return _codeLabelReverseLookup.find(label) != _codeLabelReverseLookup.end(); +} + +int32_t LabelManager::GetLabelRelativeAddress(string &label) { auto result = _codeLabelReverseLookup.find(label); if(result != _codeLabelReverseLookup.end()) { diff --git a/Core/LabelManager.h b/Core/LabelManager.h index bd086d74..b4fc14fc 100644 --- a/Core/LabelManager.h +++ b/Core/LabelManager.h @@ -35,12 +35,14 @@ public: void SetLabel(uint32_t address, AddressType addressType, string label, string comment); void DeleteLabels(); - int32_t GetLabelRelativeAddress(string label); + int32_t GetLabelRelativeAddress(string &label); string GetLabel(uint16_t relativeAddr, bool checkRegisters); string GetComment(uint16_t relativeAddr); void GetLabelAndComment(uint16_t relativeAddr, string &label, string &comment); + bool ContainsLabel(string &label); + bool HasLabelOrComment(uint16_t relativeAddr); bool HasLabelOrComment(uint32_t absoluteAddr, AddressType addressType); }; diff --git a/Core/TraceLogger.cpp b/Core/TraceLogger.cpp index 46eabc0b..64963719 100644 --- a/Core/TraceLogger.cpp +++ b/Core/TraceLogger.cpp @@ -56,11 +56,12 @@ void TraceLogger::SetOptions(TraceLoggerOptions options) string format = _options.Format; auto lock = _lock.AcquireSafe(); - _conditionRpnList.clear(); + _conditionData = ExpressionData(); if(!condition.empty()) { - vector *rpnList = _expEvaluator->GetRpnList(condition); - if(rpnList) { - _conditionRpnList = *rpnList; + bool success = false; + ExpressionData rpnList = _expEvaluator->GetRpnList(condition, success); + if(success) { + _conditionData = rpnList; } } @@ -252,9 +253,9 @@ void TraceLogger::GetTraceRow(string &output, State &cpuState, PPUDebugState &pp bool TraceLogger::ConditionMatches(DebugState &state, DisassemblyInfo &disassemblyInfo, OperationInfo &operationInfo) { - if(!_conditionRpnList.empty()) { + if(!_conditionData.RpnQueue.empty()) { EvalResultType type; - if(!_expEvaluator->Evaluate(_conditionRpnList, state, type, operationInfo)) { + 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; diff --git a/Core/TraceLogger.h b/Core/TraceLogger.h index 56adb11d..9a3f4fd2 100644 --- a/Core/TraceLogger.h +++ b/Core/TraceLogger.h @@ -3,10 +3,10 @@ #include "DebuggerTypes.h" #include "../Utilities/SimpleLock.h" #include "DisassemblyInfo.h" +#include "ExpressionEvaluator.h" class MemoryManager; class LabelManager; -class ExpressionEvaluator; class Debugger; enum class RowDataType @@ -65,7 +65,7 @@ private: shared_ptr _labelManager; shared_ptr _expEvaluator; - vector _conditionRpnList; + ExpressionData _conditionData; vector _rowParts; diff --git a/GUI.NET/Debugger/WatchManager.cs b/GUI.NET/Debugger/WatchManager.cs index 664c88c3..84ca2eff 100644 --- a/GUI.NET/Debugger/WatchManager.cs +++ b/GUI.NET/Debugger/WatchManager.cs @@ -38,7 +38,7 @@ namespace Mesen.GUI.Debugger //Watch expression matches the array display syntax (e.g: [$300,10] = display 10 bytes starting from $300) newValue = ProcessArrayDisplaySyntax(useHex, ref forceHasChanged, match); } else { - Int32 result = InteropEmu.DebugEvaluateExpression(expression, out resultType); + Int32 result = InteropEmu.DebugEvaluateExpression(expression, out resultType, true); switch(resultType) { case EvalResultType.Numeric: newValue = useHex ? ("$" + result.ToString("X2")) : result.ToString(); break; case EvalResultType.Boolean: newValue = result == 0 ? "false" : "true"; break; diff --git a/GUI.NET/Debugger/frmBreakpoint.cs b/GUI.NET/Debugger/frmBreakpoint.cs index bfcc3102..3ed80582 100644 --- a/GUI.NET/Debugger/frmBreakpoint.cs +++ b/GUI.NET/Debugger/frmBreakpoint.cs @@ -99,7 +99,7 @@ namespace Mesen.GUI.Debugger txtFrom.Focus(); txtFrom.SelectionStart = 0; txtFrom.SelectionLength = 0; - } else { + } else if(bp.AddressType == BreakpointAddressType.SingleAddress) { txtAddress.Focus(); txtAddress.SelectionStart = 0; txtAddress.SelectionLength = 0; @@ -159,7 +159,7 @@ namespace Mesen.GUI.Debugger { if(txtCondition.Text.Trim().Length > 0) { EvalResultType resultType; - InteropEmu.DebugEvaluateExpression(txtCondition.Text.Replace(Environment.NewLine, " "), out resultType); + InteropEmu.DebugEvaluateExpression(txtCondition.Text.Replace(Environment.NewLine, " "), out resultType, false); if(resultType == EvalResultType.Invalid) { picExpressionWarning.Visible = true; return false; diff --git a/GUI.NET/Debugger/frmTraceLogger.cs b/GUI.NET/Debugger/frmTraceLogger.cs index 5ed018c5..ed5c636c 100644 --- a/GUI.NET/Debugger/frmTraceLogger.cs +++ b/GUI.NET/Debugger/frmTraceLogger.cs @@ -367,7 +367,7 @@ namespace Mesen.GUI.Debugger { if(txtCondition.Text.Length > 0) { EvalResultType resultType; - InteropEmu.DebugEvaluateExpression(txtCondition.Text, out resultType); + InteropEmu.DebugEvaluateExpression(txtCondition.Text, out resultType, false); picExpressionWarning.Visible = (resultType == EvalResultType.Invalid); } else { picExpressionWarning.Visible = false; diff --git a/GUI.NET/InteropEmu.cs b/GUI.NET/InteropEmu.cs index 0976e20c..543a612f 100644 --- a/GUI.NET/InteropEmu.cs +++ b/GUI.NET/InteropEmu.cs @@ -285,7 +285,7 @@ namespace Mesen.GUI [DllImport(DLLPath)] public static extern void DebugSetFreezeState(UInt16 address, [MarshalAs(UnmanagedType.I1)]bool frozen); [DllImport(DLLPath)] public static extern void DebugSetNextStatement(UInt16 addr); - [DllImport(DLLPath)] public static extern Int32 DebugEvaluateExpression([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string expression, out EvalResultType resultType); + [DllImport(DLLPath)] public static extern Int32 DebugEvaluateExpression([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string expression, out EvalResultType resultType, [MarshalAs(UnmanagedType.I1)]bool useCache); [DllImport(DLLPath)] public static extern void DebugStartTraceLogger([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filename); [DllImport(DLLPath)] public static extern void DebugStopTraceLogger(); diff --git a/InteropDLL/DebugWrapper.cpp b/InteropDLL/DebugWrapper.cpp index f04e6a8c..4f08c4c1 100644 --- a/InteropDLL/DebugWrapper.cpp +++ b/InteropDLL/DebugWrapper.cpp @@ -96,7 +96,7 @@ extern "C" DllExport void __stdcall DebugGetCdlData(uint32_t offset, uint32_t length, DebugMemoryType memoryType, uint8_t* cdlData) { GetDebugger()->GetCodeDataLogger()->GetCdlData(offset, length, memoryType, cdlData); } DllExport void __stdcall DebugMarkPrgBytesAs(uint32_t start, uint32_t end, CdlPrgFlags type) { GetDebugger()->GetCodeDataLogger()->MarkPrgBytesAs(start, end, type); } - DllExport int32_t __stdcall DebugEvaluateExpression(char* expression, EvalResultType *resultType) { return GetDebugger()->EvaluateExpression(expression, *resultType); } + DllExport int32_t __stdcall DebugEvaluateExpression(char* expression, EvalResultType *resultType, bool useCache) { return GetDebugger()->EvaluateExpression(expression, *resultType, useCache); } DllExport void __stdcall DebugSetTraceOptions(TraceLoggerOptions options) { GetDebugger()->GetTraceLogger()->SetOptions(options); } DllExport void __stdcall DebugStartTraceLogger(char* filename) { GetDebugger()->GetTraceLogger()->StartLogging(filename); }