diff --git a/src/debugger/BreakpointMap.cxx b/src/debugger/BreakpointMap.cxx index 181f21a3d..7ee9377f9 100644 --- a/src/debugger/BreakpointMap.cxx +++ b/src/debugger/BreakpointMap.cxx @@ -27,8 +27,10 @@ BreakpointMap::BreakpointMap(void) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void BreakpointMap::add(const Breakpoint& breakpoint, const uInt32 flags) { + Breakpoint bp = convertBreakpoint(breakpoint); + myInitialized = true; - myMap[breakpoint] = flags; + myMap[bp] = flags; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -40,7 +42,14 @@ void BreakpointMap::add(const uInt16 addr, const uInt8 bank, const uInt32 flags) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void BreakpointMap::erase(const Breakpoint& breakpoint) { - myMap.erase(breakpoint); + // 16 bit breakpoint + if(!myMap.erase(breakpoint)) + { + // 13 bit breakpoint + Breakpoint bp13(breakpoint.addr & ADDRESS_MASK, breakpoint.bank); + + myMap.erase(bp13); + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -52,10 +61,18 @@ void BreakpointMap::erase(const uInt16 addr, const uInt8 bank) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 BreakpointMap::get(const Breakpoint& breakpoint) const { + // 16 bit breakpoint auto find = myMap.find(breakpoint); if(find != myMap.end()) return find->second; + // 13 bit breakpoint + Breakpoint bp13(breakpoint.addr & ADDRESS_MASK, breakpoint.bank); + + find = myMap.find(bp13); + if(find != myMap.end()) + return find->second; + return 0; } @@ -66,10 +83,17 @@ uInt32 BreakpointMap::get(uInt16 addr, uInt8 bank) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool BreakpointMap::check(const Breakpoint & breakpoint) const +bool BreakpointMap::check(const Breakpoint& breakpoint) const { + // 16 bit breakpoint auto find = myMap.find(breakpoint); + if(find != myMap.end()) + return true; + // 13 bit breakpoint + Breakpoint bp13(breakpoint.addr & ADDRESS_MASK, breakpoint.bank); + + find = myMap.find(bp13); return (find != myMap.end()); } @@ -90,3 +114,12 @@ BreakpointMap::BreakpointList BreakpointMap::getBreakpoints() const return map; } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +BreakpointMap::Breakpoint BreakpointMap::convertBreakpoint(const Breakpoint& breakpoint) +{ + if(breakpoint.bank == ANY_BANK) + return Breakpoint(breakpoint.addr, ANY_BANK); + else + return Breakpoint(breakpoint.addr & ADDRESS_MASK, breakpoint.bank); +} diff --git a/src/debugger/BreakpointMap.hxx b/src/debugger/BreakpointMap.hxx index 49074e58e..fe09d6997 100644 --- a/src/debugger/BreakpointMap.hxx +++ b/src/debugger/BreakpointMap.hxx @@ -30,11 +30,13 @@ class BreakpointMap { private: - static const uInt16 ADDRESS_MASK = 0x1fff; // either 0x1fff or 0xffff (not needed then) + static const uInt16 ADDRESS_MASK = 0x1fff; // either 0x1fff or 0xffff (not needed then) public: // breakpoint flags - static const uInt32 ONE_SHOT = 1 << 0; // used to 'trace' command + static const uInt32 ONE_SHOT = 1 << 0; // used for 'trace' command + + static const uInt8 ANY_BANK = 255; // breakpoint valid in any bank struct Breakpoint { @@ -44,13 +46,20 @@ public: Breakpoint() : addr(0), bank(0) { } Breakpoint(const Breakpoint& bp) - : addr(bp.addr & ADDRESS_MASK), bank(bp.bank) { } + : addr(bp.addr), bank(bp.bank) { } explicit Breakpoint(uInt16 c_addr, uInt8 c_bank) - : addr(c_addr & ADDRESS_MASK), bank(c_bank) { } + : addr(c_addr), bank(c_bank) { } bool operator==(const Breakpoint& other) const { - return (addr == other.addr && bank == other.bank); + if(addr == other.addr) + { + if(bank == ANY_BANK || other.bank == ANY_BANK) + return true; + else + return bank == other.bank; + } + return false; } bool operator<(const Breakpoint& other) const { @@ -89,10 +98,12 @@ public: size_t size() { return myMap.size(); } private: + Breakpoint convertBreakpoint(const Breakpoint& breakpoint); + struct BreakpointHash { size_t operator()(const Breakpoint& bp) const { return std::hash()( - uInt64(bp.addr) * 13 + uInt64(bp.bank) + uInt64(bp.addr) * 13 // only check for address, bank check via == operator ); } }; diff --git a/src/debugger/Debugger.cxx b/src/debugger/Debugger.cxx index 17b25553b..f8de366d7 100644 --- a/src/debugger/Debugger.cxx +++ b/src/debugger/Debugger.cxx @@ -335,7 +335,7 @@ int Debugger::trace() if(!checkBreakPoint(targetPC, bank)) { // add temporary breakpoint and remove later - setBreakPoint(targetPC, bank, true); + setBreakPoint(targetPC, bank, BreakpointMap::ONE_SHOT); } unlockSystem(); @@ -351,19 +351,19 @@ int Debugger::trace() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Debugger::setBreakPoint(uInt16 addr, Int8 bank, bool oneShot) +bool Debugger::setBreakPoint(uInt16 addr, uInt8 bank, uInt32 flags) { bool exists = checkBreakPoint(addr, bank); if(exists) return false; - breakPoints().add(addr, bank, oneShot ? BreakpointMap::ONE_SHOT : 0); + breakPoints().add(addr, bank, flags); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Debugger::clearBreakPoint(uInt16 addr, Int8 bank) +bool Debugger::clearBreakPoint(uInt16 addr, uInt8 bank) { bool exists = checkBreakPoint(addr, bank); @@ -375,13 +375,13 @@ bool Debugger::clearBreakPoint(uInt16 addr, Int8 bank) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Debugger::checkBreakPoint(uInt16 addr, Int8 bank) +bool Debugger::checkBreakPoint(uInt16 addr, uInt8 bank) { return breakPoints().check(addr, bank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Debugger::toggleBreakPoint(uInt16 addr, Int8 bank) +bool Debugger::toggleBreakPoint(uInt16 addr, uInt8 bank) { if(checkBreakPoint(addr, bank)) clearBreakPoint(addr, bank); diff --git a/src/debugger/Debugger.hxx b/src/debugger/Debugger.hxx index 7eea1530d..f9f1ca925 100644 --- a/src/debugger/Debugger.hxx +++ b/src/debugger/Debugger.hxx @@ -162,29 +162,29 @@ class Debugger : public DialogContainer Returns true if successfully set */ - bool setBreakPoint(uInt16 addr, Int8 bank = ANY_BANK, - bool oneShot = false); + bool setBreakPoint(uInt16 addr, uInt8 bank = ANY_BANK, + uInt32 flags = 0); /** Clears a breakpoint. Returns true if successfully cleared */ - bool clearBreakPoint(uInt16 addr, Int8 bank); + bool clearBreakPoint(uInt16 addr, uInt8 bank); /** Toggles a breakpoint Returns new state of breakpoint */ - bool toggleBreakPoint(uInt16 addr, Int8 bank); + bool toggleBreakPoint(uInt16 addr, uInt8 bank); /** Checks for a breakpoint. Returns true if existing, else false */ - bool checkBreakPoint(uInt16 addr, Int8 bank); + bool checkBreakPoint(uInt16 addr, uInt8 bank); /** Run the debugger command and return the result. diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index 045d7f326..0e818f079 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -807,6 +807,23 @@ void DebuggerParser::executeBreakif() commandResult << red("invalid expression"); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// "breaklabel" +void DebuggerParser::executeBreaklabel() +{ + uInt16 addr; + + if(argCount == 0) + addr = debugger.cpuDebug().pc(); + else + addr = args[0]; + + bool set = debugger.toggleBreakPoint(addr, BreakpointMap::ANY_BANK); + + commandResult << (set ? "set" : "cleared"); + commandResult << " breakpoint at $" << Base::HEX4 << addr << " (no mirrors)"; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "c" void DebuggerParser::executeC() @@ -1461,7 +1478,11 @@ void DebuggerParser::executeListbreaks() { if(count % 6) buf << ", "; - buf << debugger.cartDebug().getLabel(bp.addr, true, 4) << " #" << int(bp.bank); + buf << debugger.cartDebug().getLabel(bp.addr, true, 4); + if(bp.bank != 255) + buf << " #" << int(bp.bank); + else + buf << " *"; if(!(++count % 6)) buf << endl; } } @@ -2322,11 +2343,21 @@ DebuggerParser::Command DebuggerParser::commands[NumCommands] = { "Set/clear breakpoint on ", "Condition can include multiple items, see documentation\nExample: breakif _scan>100", true, - false, + true, { Parameters::ARG_WORD, Parameters::ARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeBreakif) }, + { + "breaklabel", + "Set/clear breakpoint on [address] (no mirrors, all banks)", + "Example: breaklabel, breaklabel MainLoop", + false, + true, + { Parameters::ARG_WORD, Parameters::ARG_END_ARGS }, + std::mem_fn(&DebuggerParser::executeBreaklabel) + }, + { "c", "Carry Flag: set (0 or 1), or toggle (no arg)", diff --git a/src/debugger/DebuggerParser.hxx b/src/debugger/DebuggerParser.hxx index ecfc84148..9da8e7ae1 100644 --- a/src/debugger/DebuggerParser.hxx +++ b/src/debugger/DebuggerParser.hxx @@ -88,7 +88,7 @@ class DebuggerParser }; // List of commands available - static constexpr uInt32 NumCommands = 94; + static constexpr uInt32 NumCommands = 95; struct Command { string cmdString; string description; @@ -143,6 +143,7 @@ class DebuggerParser void executeBase(); void executeBreak(); void executeBreakif(); + void executeBreaklabel(); void executeC(); void executeCheat(); void executeClearbreaks();