diff --git a/src/debugger/Debugger.cxx b/src/debugger/Debugger.cxx index ef8119ee6..ec9e1d302 100644 --- a/src/debugger/Debugger.cxx +++ b/src/debugger/Debugger.cxx @@ -387,6 +387,26 @@ void Debugger::toggleTrap(uInt16 t) toggleWriteTrap(t); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Debugger::addReadTrap(uInt16 t) +{ + readTraps().initialize(); + readTraps().add(t); +} + +void Debugger::addWriteTrap(uInt16 t) +{ + writeTraps().initialize(); + writeTraps().add(t); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Debugger::addTrap(uInt16 t) +{ + addReadTrap(t); + addWriteTrap(t); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::readTrap(uInt16 t) { @@ -399,6 +419,39 @@ bool Debugger::writeTrap(uInt16 t) return writeTraps().isInitialized() && writeTraps().isSet(t); } +/*// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Debugger::toggleReadTrapIf(uInt16 t) +{ + readTrapIfs().initialize(); + readTrapIfs().toggle(t); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Debugger::toggleWriteTrapIf(uInt16 t) +{ + writeTrapIfs().initialize(); + writeTrapIfs().toggle(t); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Debugger::toggleTrapIf(uInt16 t) +{ + toggleReadTrapIf(t); + toggleWriteTrapIf(t); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool Debugger::readTrapIf(uInt16 t) +{ + return readTrapIfs().isInitialized() && readTrapIfs().isSet(t); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool Debugger::writeTrapIf(uInt16 t) +{ + return writeTrapIfs().isInitialized() && writeTrapIfs().isSet(t); +}*/ + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::nextScanline(int lines) { diff --git a/src/debugger/Debugger.hxx b/src/debugger/Debugger.hxx index bdefeb719..5decd30ab 100644 --- a/src/debugger/Debugger.hxx +++ b/src/debugger/Debugger.hxx @@ -145,8 +145,10 @@ class Debugger : public DialogContainer TiaOutputWidget& tiaOutput() const { return myDialog->tiaOutput(); } PackedBitArray& breakPoints() const { return mySystem.m6502().breakPoints(); } - PackedBitArray& readTraps() const { return mySystem.m6502().readTraps(); } - PackedBitArray& writeTraps() const { return mySystem.m6502().writeTraps(); } + TrapArray& readTraps() const { return mySystem.m6502().readTraps(); } + TrapArray& writeTraps() const { return mySystem.m6502().writeTraps(); } + /*PackedBitArray& readTrapIfs() const { return mySystem.m6502().readTrapIfs(); } + PackedBitArray& writeTrapIfs() const { return mySystem.m6502().writeTrapIfs(); }*/ /** Run the debugger command and return the result. @@ -259,8 +261,16 @@ class Debugger : public DialogContainer void toggleReadTrap(uInt16 t); void toggleWriteTrap(uInt16 t); void toggleTrap(uInt16 t); + void addReadTrap(uInt16 t); + void addWriteTrap(uInt16 t); + void addTrap(uInt16 t); bool readTrap(uInt16 t); bool writeTrap(uInt16 t); + /*void toggleReadTrapIf(uInt16 t); + void toggleWriteTrapIf(uInt16 t); + void toggleTrapIf(uInt16 t); + bool readTrapIf(uInt16 t); + bool writeTrapIf(uInt16 t);*/ void clearAllTraps(); // Set a bunch of RAM locations at once diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index c1a4b12ac..5cebb73f7 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -548,7 +548,7 @@ string DebuggerParser::trapStatus(uInt32 addr, bool& enabled) string result; result += Base::toString(addr); result += ": "; - bool r = debugger.readTrap(addr); + bool r = debugger.readTrap(addr); // TODO trapif bool w = debugger.writeTrap(addr); enabled = r || w; if(r && w) @@ -591,7 +591,7 @@ bool DebuggerParser::saveScriptFile(string file) for(uInt32 i = 0; i < 0x10000; ++i) { - bool r = debugger.readTrap(i); + bool r = debugger.readTrap(i); // TODO trapif bool w = debugger.writeTrap(i); if(r && w) @@ -745,7 +745,9 @@ void DebuggerParser::executeClearconfig() void DebuggerParser::executeCleartraps() { myTraps.clear(); + myTrapIfs.clear(); // TODO trapif debugger.clearAllTraps(); + //debugger.cpuDebug().m6502().clearCondTraps(); commandResult << "all traps cleared"; } @@ -861,6 +863,14 @@ void DebuggerParser::executeDelfunction() commandResult << "function " << argStrings[0] << " built-in or not found"; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// "deltrapif" +void DebuggerParser::executeDeltrapif() +{ + //debugger.cpuDebug().m6502().delCondTrap(args[0]); + // TODO trapif +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "delwatch" void DebuggerParser::executeDelwatch() @@ -1129,11 +1139,40 @@ void DebuggerParser::executeListtraps() { if(myTraps.size() > 0) { + commandResult << "traps:\n"; bool enabled = true; + uInt32 i = 0; + for(const auto& trap: myTraps) - commandResult << trapStatus(trap, enabled) << " + mirrors" << endl; + { + commandResult << trapStatus(trap, enabled) << " + mirrors"; + if(i != (myTraps.size() - 1)) commandResult << endl; + i++; + } } - else + // TODO trapif + /*if(myTrapIfs.size() > 0) + { + StringList conds = debugger.cpuDebug().m6502().getCondTrapNames(); + commandResult << "trapifs:\n"; + if(myTrapIfs.size() != conds.size()) + { + // should never happen + commandResult << "ERROR! trapif condition size != address ranges size"; + return; + } + bool enabled = true; + uInt32 i = 0; + + for(const auto& trap : myTrapIfs) + { + commandResult << i << ": " << conds[i] << ", "; + //commandResult << trapStatus(trap.address, enabled, true) << " + mirrors"; + if(i != (myTrapIfs.size() - 1)) commandResult << endl; + i++; + } + }*/ + if(myTraps.size() == 0 && myTrapIfs.size() == 0) commandResult << "no traps set"; } @@ -1482,58 +1521,71 @@ void DebuggerParser::executeTrace() // "trap" void DebuggerParser::executeTrap() { - if(argCount > 2) - { - commandResult << red("Command takes one or two arguments") << endl; - return; - } + executeTraps(true, true); +} - uInt32 beg = args[0]; - uInt32 end = argCount == 2 ? args[1] : beg; - if(beg > 0xFFFF || end > 0xFFFF) - { - commandResult << red("One or more addresses are invalid") << endl; - return; - } - - for(uInt32 addr = beg; addr <= end; ++addr) - executeTrapRW(addr, true, true); +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// "trapif" +void DebuggerParser::executeTrapif() +{ + executeTraps(true, true, true, "trapif"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "trapread" void DebuggerParser::executeTrapread() { - if(argCount > 2) - { - commandResult << red("Command takes one or two arguments") << endl; - return; - } + executeTraps(true, false); +} - uInt32 beg = args[0]; - uInt32 end = argCount == 2 ? args[1] : beg; - if(beg > 0xFFFF || end > 0xFFFF) - { - commandResult << red("One or more addresses are invalid") << endl; - return; - } - - for(uInt32 addr = beg; addr <= end; ++addr) - executeTrapRW(addr, true, false); +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// "trapreadif" +void DebuggerParser::executeTrapreadif() +{ + executeTraps(true, false, true, "trapreadif"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "trapwrite" void DebuggerParser::executeTrapwrite() { - if(argCount > 2) + executeTraps(false, true); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// "trapwriteif" +void DebuggerParser::executeTrapwriteif() +{ + executeTraps(false, true, true, "trapwriteif"); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// Wrapper function for trap(if)s +void DebuggerParser::executeTraps(bool read, bool write, bool cond, string command) +{ + int ofs = cond ? 1 : 0; + + if(argCount > ofs + 2) { - commandResult << red("Command takes one or two arguments") << endl; + commandResult << (cond ? red("Command takes two or three arguments") : red("Command takes one or two arguments")) << endl; return; } - uInt32 beg = args[0]; - uInt32 end = argCount == 2 ? args[1] : beg; + /*if(cond) + { + int res = YaccParser::parse(argStrings[0].c_str()); + if(res == 0) + { + uInt32 ret = debugger.cpuDebug().m6502().addCondTrap( + YaccParser::getResult(), argStrings[0]); + commandResult << "Added " << command << " " << Base::toString(ret) << ", "; + } + else + commandResult << red("invalid expression"); + }*/ + + uInt32 beg = args[ofs]; + uInt32 end = argCount == ofs + 2 ? args[ofs + 1] : beg; if(beg > 0xFFFF || end > 0xFFFF) { commandResult << red("One or more addresses are invalid") << endl; @@ -1541,12 +1593,12 @@ void DebuggerParser::executeTrapwrite() } for(uInt32 addr = beg; addr <= end; ++addr) - executeTrapRW(addr, false, true); + executeTrapRW(addr, read, write, cond); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // wrapper function for trap/trapread/trapwrite commands -void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write) +void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write, bool cond) { switch(debugger.cartDebug().addressType(addr)) { @@ -1557,7 +1609,7 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write) if((i & 0x1080) == 0x0000) { if(read && (i & 0x000F) == addr) - debugger.toggleReadTrap(i); + debugger.toggleReadTrap(i); if(write && (i & 0x003F) == addr) debugger.toggleWriteTrap(i); } @@ -1570,8 +1622,10 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write) { if((i & 0x1080) == 0x0080 && (i & 0x0200) != 0x0000 && (i & 0x02FF) == addr) { - if(read) debugger.toggleReadTrap(i); - if(write) debugger.toggleWriteTrap(i); + if(read) + debugger.toggleReadTrap(i); + if(write) + debugger.toggleWriteTrap(i); } } break; @@ -1582,8 +1636,10 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write) { if((i & 0x1080) == 0x0080 && (i & 0x0200) == 0x0000 && (i & 0x00FF) == addr) { - if(read) debugger.toggleReadTrap(i); - if(write) debugger.toggleWriteTrap(i); + if(read) + debugger.toggleReadTrap(i); + if(write) + debugger.toggleWriteTrap(i); } } break; @@ -1596,8 +1652,10 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write) { if((i % 0x2000 >= 0x1000) && (i & 0x0FFF) == (addr & 0x0FFF)) { - if(read) debugger.toggleReadTrap(i); - if(write) debugger.toggleWriteTrap(i); + if(read) + debugger.toggleReadTrap(i); + if(write) + debugger.toggleWriteTrap(i); } } } @@ -1607,10 +1665,9 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write) bool trapEnabled = false; const string& result = trapStatus(addr, trapEnabled); - if(trapEnabled) myTraps.insert(addr); - else myTraps.erase(addr); - - commandResult << result << " + mirrors" << endl; + + if(trapEnabled) cond ? myTrapIfs.push_back(addr) : myTraps.insert(addr); + else cond ? myTrapIfs.size() : myTraps.erase(addr); // TODO trapif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1891,6 +1948,16 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = { std::mem_fn(&DebuggerParser::executeDelfunction) }, + { + "deltrapif", + "Delete conditional trapif ", + "Example: deltrapif 0", + true, + false, + { kARG_WORD, kARG_END_ARGS }, + std::mem_fn(&DebuggerParser::executeDeltrapif) + }, + { "delwatch", "Delete watch ", @@ -2333,6 +2400,17 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = { std::mem_fn(&DebuggerParser::executeTrap) }, + { + "trapif", + "On trap R/W access to address(es) xx [yy]", + "Set a conditional R/W trap on the given address(es) and all mirrors\nCondition can include multiple items.\n" + "Example: trapif _scan>100 GRP0, trapif _bank==1 f000 f100", + true, + false, + { kARG_WORD, kARG_MULTI_BYTE }, + std::mem_fn(&DebuggerParser::executeTrapif) + }, + { "trapread", "Trap read access to address(es) xx [yy]", @@ -2344,6 +2422,17 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = { std::mem_fn(&DebuggerParser::executeTrapread) }, + { + "trapreadif", + "On trap read access to address(es) xx [yy]", + "Set a conditional read trap on the given address(es) and all mirrors\nCondition can include multiple items.\n" + "Example: trapreadif _scan>100 GRP0, trapreadif _bank==1 f000 f100", + true, + false, + { kARG_WORD, kARG_MULTI_BYTE }, + std::mem_fn(&DebuggerParser::executeTrapreadif) + }, + { "trapwrite", "Trap write access to address(es) xx [yy]", @@ -2355,6 +2444,17 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = { std::mem_fn(&DebuggerParser::executeTrapwrite) }, + { + "trapwriteif", + "On trap write access to address(es) xx [yy]", + "Set a conditional write trap on the given address(es) and all mirrors\nCondition can include multiple items.\n" + "Example: trapwriteif _scan>100 GRP0, trapwriteif _bank==1 f000 f100", + true, + false, + { kARG_WORD, kARG_MULTI_BYTE }, + std::mem_fn(&DebuggerParser::executeTrapwriteif) + }, + { "type", "Show disassembly type for address xx [yy]", diff --git a/src/debugger/DebuggerParser.hxx b/src/debugger/DebuggerParser.hxx index e9e403ac0..66ebcae42 100644 --- a/src/debugger/DebuggerParser.hxx +++ b/src/debugger/DebuggerParser.hxx @@ -68,7 +68,7 @@ class DebuggerParser bool saveScriptFile(string file); private: - enum { kNumCommands = 72 }; + enum { kNumCommands = 76 }; // Constants for argument processing enum { @@ -100,7 +100,7 @@ class DebuggerParser parameters parms[10]; std::function executor; }; - + // Reference to our debugger object Debugger& debugger; @@ -119,6 +119,7 @@ class DebuggerParser // Keep track of traps (read and/or write) std::set myTraps; + std::vector myTrapIfs; string trapStatus(uInt32 addr, bool& enabled); // List of available command methods @@ -140,6 +141,7 @@ class DebuggerParser void executeDebugColors(); void executeDefine(); void executeDelbreakif(); + void executeDeltrapif(); void executeDelfunction(); void executeDelwatch(); void executeDisasm(); @@ -184,9 +186,13 @@ class DebuggerParser void executeTia(); void executeTrace(); void executeTrap(); + void executeTrapif(); void executeTrapread(); - void executeTrapwrite(); - void executeTrapRW(uInt32 addr, bool read, bool write); // not exposed by debugger + void executeTrapreadif(); + void executeTrapwrite(); + void executeTrapwriteif(); + void executeTraps(bool read, bool write, bool cond = false, string command = ""); + void executeTrapRW(uInt32 addr, bool read, bool write, bool cond = false); // not exposed by debugger void executeType(); void executeUHex(); void executeUndef(); diff --git a/src/emucore/M6502.cxx b/src/emucore/M6502.cxx index 6aa430eec..ce9a08544 100644 --- a/src/emucore/M6502.cxx +++ b/src/emucore/M6502.cxx @@ -128,6 +128,16 @@ inline uInt8 M6502::peek(uInt16 address, uInt8 flags) myHitTrapInfo.message = "RTrap: "; myHitTrapInfo.address = address; } + /*if(myReadTrapIfs.isInitialized() && myReadTrapIfs.isSet(address)) + { + int cond = evalCondTraps(); + if(cond > -1) + { + myJustHitTrapFlag = true; + myHitTrapInfo.message = "RTrapIf (" + myTrapCondNames[cond] + "): "; + myHitTrapInfo.address = address; + } + }*/ #endif // DEBUGGER_SUPPORT uInt8 result = mySystem->peek(address, flags); @@ -155,6 +165,17 @@ inline void M6502::poke(uInt16 address, uInt8 value, uInt8 flags) myHitTrapInfo.message = "WTrap: "; myHitTrapInfo.address = address; } + /*if(myWriteTrapIfs.isInitialized() && myWriteTrapIfs.isSet(address)) + { + int cond = evalCondTraps(); + if(cond > -1) + { + myJustHitTrapFlag = true; + myHitTrapInfo.message = "WTrapIf (" + myTrapCondNames[cond] + "): "; + myHitTrapInfo.address = address; + } + }*/ + #endif // DEBUGGER_SUPPORT mySystem->poke(address, value, flags); @@ -437,4 +458,36 @@ const StringList& M6502::getCondBreakNames() const { return myBreakCondNames; } + +/*// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt32 M6502::addCondTrap(Expression* e, const string& name) +{ + //myTrapConds.emplace_back(e); + myTrapCondNames.push_back(name); + return uInt32(myTrapConds.size() - 1); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void M6502::delCondTrap(uInt32 brk) +{ + if(brk < myTrapConds.size()) + { + myTrapConds.erase(brk); + //Vec::removeAt(myTrapConds, brk); + Vec::removeAt(myTrapCondNames, brk); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void M6502::clearCondTraps() +{ + myTrapConds.clear(); + myTrapCondNames.clear(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const StringList& M6502::getCondTrapNames() const +{ + return myTrapCondNames; +}*/ #endif // DEBUGGER_SUPPORT diff --git a/src/emucore/M6502.hxx b/src/emucore/M6502.hxx index b22a5727f..7e21ea5c5 100644 --- a/src/emucore/M6502.hxx +++ b/src/emucore/M6502.hxx @@ -24,6 +24,7 @@ #include "Expression.hxx" #include "PackedBitArray.hxx" + #include "TrapArray.hxx" #endif class Settings; @@ -207,13 +208,23 @@ class M6502 : public Serializable void attach(Debugger& debugger); PackedBitArray& breakPoints() { return myBreakPoints; } - PackedBitArray& readTraps() { return myReadTraps; } - PackedBitArray& writeTraps() { return myWriteTraps; } + //PackedBitArray& readTraps() { return myReadTraps; } + //PackedBitArray& writeTraps() { return myWriteTraps; } + //PackedBitArray& readTrapIfs() { return myReadTrapIfs; } + //PackedBitArray& writeTrapIfs() { return myWriteTrapIfs; } + TrapArray& readTraps() { return myReadTraps; } + TrapArray& writeTraps() { return myWriteTraps; } uInt32 addCondBreak(Expression* e, const string& name); void delCondBreak(uInt32 brk); void clearCondBreaks(); const StringList& getCondBreakNames() const; + + /*uInt32 addCondTrap(Expression* e, const string& name); + void delCondTrap(uInt32 brk); + void clearCondTraps(); + const StringList& getCondTrapNames() const;*/ + #endif // DEBUGGER_SUPPORT private: @@ -359,11 +370,21 @@ class M6502 : public Serializable return -1; // no break hit } + /*Int32 evalCondTraps() + { + for(uInt32 i = 0; i < myTrapConds.size(); i++) + if(myTrapConds[i]->evaluate()) + return i; + + return -1; // no trapif hit + }*/ + /// Pointer to the debugger for this processor or the null pointer Debugger* myDebugger; // Addresses for which the specified action should occur - PackedBitArray myBreakPoints, myReadTraps, myWriteTraps; + PackedBitArray myBreakPoints;// , myReadTraps, myWriteTraps, myReadTrapIfs, myWriteTrapIfs; + TrapArray myReadTraps, myWriteTraps; // Did we just now hit a trap? bool myJustHitTrapFlag; @@ -375,6 +396,8 @@ class M6502 : public Serializable vector> myBreakConds; StringList myBreakCondNames; + //std::map> myTrapConds; + //StringList myTrapCondNames; #endif // DEBUGGER_SUPPORT private: diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index 54e8a5635..f4cf3e333 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -575,6 +575,7 @@ + diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index fcedc20ed..de22defe1 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -1751,6 +1751,9 @@ Header Files\debugger + + Header Files\debugger +