diff --git a/src/debugger/Debugger.hxx b/src/debugger/Debugger.hxx index 31a17330d..01ba1f890 100644 --- a/src/debugger/Debugger.hxx +++ b/src/debugger/Debugger.hxx @@ -65,6 +65,7 @@ class Debugger : public DialogContainer // directly, and not touch the instance variables friend class DebuggerParser; friend class EventHandler; + friend class M6502; public: /** diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index 2c65f5ede..2ba4c04d7 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -652,6 +652,10 @@ string DebuggerParser::saveScriptFile(string file) for(const auto& cond : conds) out << "breakif {" << cond << "}" << endl; + conds = debugger.m6502().getCondSaveStateNames(); + for(const auto& cond : conds) + out << "savestateif {" << cond << "}" << endl; + StringList names = debugger.m6502().getCondTrapNames(); for(uInt32 i = 0; i < myTraps.size(); ++i) { @@ -807,6 +811,14 @@ void DebuggerParser::executeClearconfig() commandResult << debugger.cartDebug().clearConfig(); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// "clearbreaks" +void DebuggerParser::executeClearsavestateifs() +{ + debugger.m6502().clearCondSaveStates(); + commandResult << "all savestate points cleared"; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "cleartraps" void DebuggerParser::executeCleartraps() @@ -932,6 +944,16 @@ void DebuggerParser::executeDelfunction() commandResult << "function " << argStrings[0] << " built-in or not found"; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// "delsavestateif" +void DebuggerParser::executeDelsavestateif() +{ + if(debugger.m6502().delCondSaveState(args[0])) + commandResult << "removed savestateif " << Base::toString(args[0]); + else + commandResult << red("no such savestateif"); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "deltrap" void DebuggerParser::executeDeltrap() @@ -1212,6 +1234,31 @@ void DebuggerParser::executeListfunctions() commandResult << "no user-defined functions"; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// "listsavestateifs" +void DebuggerParser::executeListsavestateifs() +{ + ostringstream buf; + int count = 0; + + StringList conds = debugger.m6502().getCondSaveStateNames(); + if(conds.size() > 0) + { + if(count) + commandResult << endl; + commandResult << "savestateif:" << endl; + for(uInt32 i = 0; i < conds.size(); i++) + { + commandResult << Base::toString(i) << ": " << conds[i]; + if(i != (conds.size() - 1)) commandResult << endl; + } + } + + if(commandResult.str() == "") + commandResult << "no savestateifs defined"; +} + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "listtraps" void DebuggerParser::executeListtraps() @@ -1542,6 +1589,21 @@ void DebuggerParser::executeSavestate() commandResult << red("invalid slot (must be 0-9)"); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// "savestateif" +void DebuggerParser::executeSavestateif() +{ + int res = YaccParser::parse(argStrings[0].c_str()); + if(res == 0) + { + uInt32 ret = debugger.m6502().addCondSaveState( + YaccParser::getResult(), argStrings[0]); + commandResult << "Added savestateif " << Base::toString(ret); + } + else + commandResult << red("invalid expression"); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "scanline" void DebuggerParser::executeScanline() @@ -1981,6 +2043,16 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = { std::mem_fn(&DebuggerParser::executeClearbreaks) }, + { + "clearsavestateifs", + "Clear all savestate points", + "Example: clearsavestateifss (no parameters)", + false, + true, + { kARG_END_ARGS }, + std::mem_fn(&DebuggerParser::executeClearsavestateifs) + }, + { "clearconfig", "Clear Distella config directives [bank xx]", @@ -2101,6 +2173,16 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = { std::mem_fn(&DebuggerParser::executeDelfunction) }, + { + "delsavestateif", + "Delete conditional savestate point ", + "Example: delsavestateif 0", + true, + false, + { kARG_WORD, kARG_END_ARGS }, + std::mem_fn(&DebuggerParser::executeDelsavestateif) + }, + { "deltrap", "Delete trap ", @@ -2245,6 +2327,16 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = { std::mem_fn(&DebuggerParser::executeListfunctions) }, + { + "listsavestateifs", + "List savestate points", + "Example: listsavestateifs (no parameters)", + false, + false, + { kARG_END_ARGS }, + std::mem_fn(&DebuggerParser::executeListsavestateifs) + }, + { "listtraps", "List traps", @@ -2502,6 +2594,16 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = { std::mem_fn(&DebuggerParser::executeSavestate) }, + { + "savestateif", + "Create savestate on ", + "Condition can include multiple items, see documentation\nExample: savestateif pc==f000", + true, + false, + { kARG_WORD, kARG_END_ARGS }, + std::mem_fn(&DebuggerParser::executeSavestateif) + }, + { "scanline", "Advance emulation by scanlines (default=1)", diff --git a/src/debugger/DebuggerParser.hxx b/src/debugger/DebuggerParser.hxx index c451d71bb..b804ace65 100644 --- a/src/debugger/DebuggerParser.hxx +++ b/src/debugger/DebuggerParser.hxx @@ -66,7 +66,7 @@ class DebuggerParser string saveScriptFile(string file); private: - enum { kNumCommands = 77 }; + enum { kNumCommands = 81 }; // Constants for argument processing enum { @@ -142,6 +142,7 @@ class DebuggerParser void executeCheat(); void executeClearbreaks(); void executeClearconfig(); + void executeClearsavestateifs(); void executeCleartraps(); void executeClearwatches(); void executeCls(); @@ -153,6 +154,7 @@ class DebuggerParser void executeDefine(); void executeDelbreakif(); void executeDelfunction(); + void executeDelsavestateif(); void executeDeltrap(); void executeDelwatch(); void executeDisasm(); @@ -167,6 +169,7 @@ class DebuggerParser void executeListbreaks(); void executeListconfig(); void executeListfunctions(); + void executeListsavestateifs(); void executeListtraps(); void executeLoadconfig(); void executeLoadstate(); @@ -192,6 +195,7 @@ class DebuggerParser void executeSaveses(); void executeSavesnap(); void executeSavestate(); + void executeSavestateif(); void executeScanline(); void executeStep(); void executeTia(); diff --git a/src/emucore/M6502.cxx b/src/emucore/M6502.cxx index 9ba1dbc4f..6c4eb4385 100644 --- a/src/emucore/M6502.cxx +++ b/src/emucore/M6502.cxx @@ -219,10 +219,16 @@ bool M6502::execute(uInt32 number) int cond = evalCondBreaks(); if(cond > -1) { - string buf = "CBP: " + myBreakCondNames[cond]; + string buf = "CBP: " + myCondBreakNames[cond]; if(myDebugger && myDebugger->start(buf)) return true; } + + cond = evalCondSaveStates(); + if(cond > -1) + { + myDebugger->saveOldState("conditional savestate"); + } #endif // DEBUGGER_SUPPORT uInt16 operandAddress = 0, intermediateAddress = 0; @@ -424,18 +430,18 @@ void M6502::attach(Debugger& debugger) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 M6502::addCondBreak(Expression* e, const string& name) { - myBreakConds.emplace_back(e); - myBreakCondNames.push_back(name); - return uInt32(myBreakConds.size() - 1); + myCondBreaks.emplace_back(e); + myCondBreakNames.push_back(name); + return uInt32(myCondBreaks.size() - 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool M6502::delCondBreak(uInt32 brk) +bool M6502::delCondBreak(uInt32 idx) { - if(brk < myBreakConds.size()) + if(idx < myCondBreaks.size()) { - Vec::removeAt(myBreakConds, brk); - Vec::removeAt(myBreakCondNames, brk); + Vec::removeAt(myCondBreaks, idx); + Vec::removeAt(myCondBreakNames, idx); return true; } return false; @@ -444,14 +450,47 @@ bool M6502::delCondBreak(uInt32 brk) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6502::clearCondBreaks() { - myBreakConds.clear(); - myBreakCondNames.clear(); + myCondBreaks.clear(); + myCondBreakNames.clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const StringList& M6502::getCondBreakNames() const { - return myBreakCondNames; + return myCondBreakNames; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt32 M6502::addCondSaveState(Expression* e, const string& name) +{ + myCondSaveStates.emplace_back(e); + myCondSaveStateNames.push_back(name); + return uInt32(myCondSaveStates.size() - 1); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool M6502::delCondSaveState(uInt32 idx) +{ + if(idx < myCondSaveStates.size()) + { + Vec::removeAt(myCondSaveStates, idx); + Vec::removeAt(myCondSaveStateNames, idx); + return true; + } + return false; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void M6502::clearCondSaveStates() +{ + myCondSaveStates.clear(); + myCondSaveStateNames.clear(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const StringList& M6502::getCondSaveStateNames() const +{ + return myCondSaveStateNames; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/M6502.hxx b/src/emucore/M6502.hxx index 876fe7e6a..d23c4369b 100644 --- a/src/emucore/M6502.hxx +++ b/src/emucore/M6502.hxx @@ -222,19 +222,21 @@ class M6502 : public Serializable void attach(Debugger& debugger); PackedBitArray& breakPoints() { return myBreakPoints; } - //PackedBitArray& readTraps() { return myReadTraps; } - //PackedBitArray& writeTraps() { return myWriteTraps; } - //PackedBitArray& readTrapIfs() { return myReadTrapIfs; } - //PackedBitArray& writeTrapIfs() { return myWriteTrapIfs; } TrapArray& readTraps() { return myReadTraps; } TrapArray& writeTraps() { return myWriteTraps; } // methods for 'breakif' handling uInt32 addCondBreak(Expression* e, const string& name); - bool delCondBreak(uInt32 brk); + bool delCondBreak(uInt32 idx); void clearCondBreaks(); const StringList& getCondBreakNames() const; + // methods for 'savestateif' handling + uInt32 addCondSaveState(Expression* e, const string& name); + bool delCondSaveState(uInt32 idx); + void clearCondSaveStates(); + const StringList& getCondSaveStateNames() const; + // methods for 'trapif' handling uInt32 addCondTrap(Expression* e, const string& name); bool delCondTrap(uInt32 brk); @@ -380,14 +382,29 @@ class M6502 : public Serializable bool myHaltRequested; #ifdef DEBUGGER_SUPPORT + enum CondAction + { + breakAction, + saveStateAction + }; + Int32 evalCondBreaks() { - for(uInt32 i = 0; i < myBreakConds.size(); i++) - if(myBreakConds[i]->evaluate()) + for(uInt32 i = 0; i < myCondBreaks.size(); i++) + if(myCondBreaks[i]->evaluate()) return i; return -1; // no break hit } + Int32 evalCondSaveStates() + { + for(uInt32 i = 0; i < myCondSaveStates.size(); i++) + if(myCondSaveStates[i]->evaluate()) + return i; + + return -1; // no save state point hit + } + Int32 evalCondTraps() { for(uInt32 i = 0; i < myTrapConds.size(); i++) @@ -413,10 +430,13 @@ class M6502 : public Serializable }; HitTrapInfo myHitTrapInfo; - vector> myBreakConds; - StringList myBreakCondNames; + vector> myCondBreaks; + StringList myCondBreakNames; + vector> myCondSaveStates; + StringList myCondSaveStateNames; vector> myTrapConds; StringList myTrapCondNames; + #endif // DEBUGGER_SUPPORT private: