mirror of https://github.com/stella-emu/stella.git
added option to log breaks and traps instead of interrupting emulation (resolves #741)
This commit is contained in:
parent
54af434260
commit
fbbb86f964
11
Changes.txt
11
Changes.txt
|
@ -12,6 +12,15 @@
|
||||||
Release History
|
Release History
|
||||||
===========================================================================
|
===========================================================================
|
||||||
|
|
||||||
|
6.5.3 to 6.6 (??? ??, 202?)
|
||||||
|
|
||||||
|
* Added web links for many games
|
||||||
|
|
||||||
|
* Added optional logging of breaks and traps
|
||||||
|
|
||||||
|
-Have fun!
|
||||||
|
|
||||||
|
|
||||||
6.5.2 to 6.5.3 (April 20, 2021)
|
6.5.2 to 6.5.3 (April 20, 2021)
|
||||||
|
|
||||||
* Added context-sensitive help.
|
* Added context-sensitive help.
|
||||||
|
@ -26,8 +35,6 @@
|
||||||
|
|
||||||
* Fixed immediate disassembling when switching options in debugger.
|
* Fixed immediate disassembling when switching options in debugger.
|
||||||
|
|
||||||
-Have fun!
|
|
||||||
|
|
||||||
|
|
||||||
6.5.1 to 6.5.2 (February 25, 2021)
|
6.5.1 to 6.5.2 (February 25, 2021)
|
||||||
|
|
||||||
|
|
|
@ -609,7 +609,7 @@ command that takes arguments.</p>
|
||||||
<h4><a name="Breakpoints">Breakpoints</a></h4>
|
<h4><a name="Breakpoints">Breakpoints</a></h4>
|
||||||
|
|
||||||
<p>A breakpoint is a "hotspot" in your program that causes the emulator
|
<p>A breakpoint is a "hotspot" in your program that causes the emulator
|
||||||
to stop emulating and jump into the debugger. You can set as many
|
to stop emulating and jump into the debugger ¹. You can set as many
|
||||||
breakpoints as you like. The command is "break xx yy" where xx is any
|
breakpoints as you like. The command is "break xx yy" where xx is any
|
||||||
expression and yy a bank number. Both arguments are optional. If you have
|
expression and yy a bank number. Both arguments are optional. If you have
|
||||||
created a symbol file, you can use labels for the expression.</p>
|
created a symbol file, you can use labels for the expression.</p>
|
||||||
|
@ -633,6 +633,9 @@ breakpoint on & off, like a light switch.</p>
|
||||||
<p>You could also use "clearbreaks" to remove all the breakpoints. Also,
|
<p>You could also use "clearbreaks" to remove all the breakpoints. Also,
|
||||||
there is a "listbreaks" command that will list them all.</p>
|
there is a "listbreaks" command that will list them all.</p>
|
||||||
|
|
||||||
|
<p>¹ By enabling "logbreaks" you can log the current state into
|
||||||
|
the System Log and continue emulation instead.</p>
|
||||||
|
|
||||||
<h4><a name="ConditionalBreaks">Conditional Breaks</a></h4>
|
<h4><a name="ConditionalBreaks">Conditional Breaks</a></h4>
|
||||||
|
|
||||||
<p>A conditional breakpoint causes the emulator to enter the debugger when
|
<p>A conditional breakpoint causes the emulator to enter the debugger when
|
||||||
|
@ -973,6 +976,7 @@ clearsavestateifs - Clear all savestate points
|
||||||
loadconfig - Load DiStella config file
|
loadconfig - Load DiStella config file
|
||||||
loadallstates - Load all emulator states
|
loadallstates - Load all emulator states
|
||||||
loadstate - Load emulator state xx (0-9)
|
loadstate - Load emulator state xx (0-9)
|
||||||
|
logbreaks - Logs breaks and traps and continues emulation
|
||||||
n - Negative Flag: set (0 or 1), or toggle (no arg)
|
n - Negative Flag: set (0 or 1), or toggle (no arg)
|
||||||
palette - Show current TIA palette
|
palette - Show current TIA palette
|
||||||
pc - Set Program Counter to address xx
|
pc - Set Program Counter to address xx
|
||||||
|
|
|
@ -56,7 +56,8 @@ void Logger::logMessage(const string& message, Level level)
|
||||||
cout << message << endl << std::flush;
|
cout << message << endl << std::flush;
|
||||||
myLogMessages += message + "\n";
|
myLogMessages += message + "\n";
|
||||||
}
|
}
|
||||||
else if(static_cast<int>(level) <= myLogLevel)
|
else if(static_cast<int>(level) <= myLogLevel ||
|
||||||
|
level == Logger::Level::ALWAYS)
|
||||||
{
|
{
|
||||||
if(myLogToConsole)
|
if(myLogToConsole)
|
||||||
cout << message << endl << std::flush;
|
cout << message << endl << std::flush;
|
||||||
|
|
|
@ -30,15 +30,16 @@ class Logger {
|
||||||
ERR = 0, // cannot use ERROR???
|
ERR = 0, // cannot use ERROR???
|
||||||
INFO = 1,
|
INFO = 1,
|
||||||
DEBUG = 2,
|
DEBUG = 2,
|
||||||
|
ALWAYS = 3,
|
||||||
MIN = ERR,
|
MIN = ERR,
|
||||||
MAX = DEBUG
|
MAX = ALWAYS
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static Logger& instance();
|
static Logger& instance();
|
||||||
|
|
||||||
static void log(const string& message, Level level);
|
static void log(const string& message, Level level = Level::ALWAYS);
|
||||||
|
|
||||||
static void error(const string& message);
|
static void error(const string& message);
|
||||||
|
|
||||||
|
|
|
@ -206,7 +206,7 @@ int main(int ac, char* av[])
|
||||||
|
|
||||||
// Create the full OSystem after the settings, since settings are
|
// Create the full OSystem after the settings, since settings are
|
||||||
// probably needed for defaults
|
// probably needed for defaults
|
||||||
Logger::debug("Creating the OSystem ...");
|
Logger::log("Creating the OSystem ...");
|
||||||
if(!theOSystem->initialize(globalOpts))
|
if(!theOSystem->initialize(globalOpts))
|
||||||
{
|
{
|
||||||
Logger::error("ERROR: Couldn't create OSystem");
|
Logger::error("ERROR: Couldn't create OSystem");
|
||||||
|
|
|
@ -123,6 +123,7 @@ bool Debugger::start(const string& message, int address, bool read,
|
||||||
{
|
{
|
||||||
if(myOSystem.eventHandler().enterDebugMode())
|
if(myOSystem.eventHandler().enterDebugMode())
|
||||||
{
|
{
|
||||||
|
myFirstLog = true;
|
||||||
// This must be done *after* we enter debug mode,
|
// This must be done *after* we enter debug mode,
|
||||||
// so the message isn't erased
|
// so the message isn't erased
|
||||||
ostringstream buf;
|
ostringstream buf;
|
||||||
|
@ -442,6 +443,80 @@ bool Debugger::writeTrap(uInt16 t)
|
||||||
return writeTraps().isInitialized() && writeTraps().isSet(t);
|
return writeTraps().isInitialized() && writeTraps().isSet(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void Debugger::log(const string& triggerMsg)
|
||||||
|
{
|
||||||
|
const CartDebug::Disassembly& disasm = myCartDebug->disassembly();
|
||||||
|
int pc = myCpuDebug->pc();
|
||||||
|
|
||||||
|
if(myFirstLog)
|
||||||
|
{
|
||||||
|
ostringstream msg;
|
||||||
|
|
||||||
|
msg << "Trigger: Frame Scn Cy Pxl | PS A X Y SP | ";
|
||||||
|
if(myCartDebug->romBankCount() > 1)
|
||||||
|
if(myCartDebug->romBankCount() > 9)
|
||||||
|
msg << "Bk/";
|
||||||
|
else
|
||||||
|
msg << "B/";
|
||||||
|
msg << "Addr Code Disam";
|
||||||
|
Logger::log(msg.str());
|
||||||
|
myFirstLog = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First find the lines in the range, and determine the longest string
|
||||||
|
uInt16 start = pc & 0xFFF;
|
||||||
|
uInt32 list_size = uInt32(disasm.list.size());
|
||||||
|
uInt32 pos;
|
||||||
|
|
||||||
|
for(pos = 0; pos < list_size; ++pos)
|
||||||
|
{
|
||||||
|
const CartDebug::DisassemblyTag& tag = disasm.list[pos];
|
||||||
|
|
||||||
|
if((tag.address & 0xfff) >= start)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CartDebug::DisassemblyTag& tag = disasm.list[pos];
|
||||||
|
ostringstream msg;
|
||||||
|
|
||||||
|
msg << std::left << std::setw(10) << std::setfill(' ') << triggerMsg;
|
||||||
|
msg << Base::toString(myTiaDebug->frameCount(), Base::Fmt::_10_5) << " "
|
||||||
|
<< Base::toString(myTiaDebug->scanlines(), Base::Fmt::_10_3) << " "
|
||||||
|
<< Base::toString(myTiaDebug->clocksThisLine() / 3, Base::Fmt::_10_02) << " "
|
||||||
|
<< Base::toString(myTiaDebug->clocksThisLine() - 68, Base::Fmt::_10_3) << " | ";
|
||||||
|
msg << (myCpuDebug->n() ? "N" : "n")
|
||||||
|
<< (myCpuDebug->v() ? "V" : "v") << "-"
|
||||||
|
<< (myCpuDebug->b() ? "B" : "b")
|
||||||
|
<< (myCpuDebug->d() ? "D" : "d")
|
||||||
|
<< (myCpuDebug->i() ? "I" : "i")
|
||||||
|
<< (myCpuDebug->z() ? "Z" : "z")
|
||||||
|
<< (myCpuDebug->c() ? "C" : "c") << " "
|
||||||
|
<< Base::HEX2 << myCpuDebug->a() << " "
|
||||||
|
<< Base::HEX2 << myCpuDebug->x() << " "
|
||||||
|
<< Base::HEX2 << myCpuDebug->y() << " "
|
||||||
|
<< Base::HEX2 << myCpuDebug->sp() << " |";
|
||||||
|
|
||||||
|
if(myCartDebug->romBankCount() > 1)
|
||||||
|
{
|
||||||
|
if(myCartDebug->romBankCount() > 9)
|
||||||
|
msg << Base::toString(myCartDebug->getBank(pc), Base::Fmt::_10) << "/";
|
||||||
|
else
|
||||||
|
msg << " " << myCartDebug->getBank(pc) << "/";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
msg << " ";
|
||||||
|
|
||||||
|
msg << Base::HEX4 << pc << " "
|
||||||
|
<< std::left << std::setw(8) << std::setfill(' ') << tag.bytes << " "
|
||||||
|
<< tag.disasm.substr(0, 7);
|
||||||
|
|
||||||
|
if(tag.disasm.length() > 8)
|
||||||
|
msg << tag.disasm.substr(8);
|
||||||
|
|
||||||
|
Logger::log(msg.str());
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt8 Debugger::peek(uInt16 addr, Device::AccessFlags flags)
|
uInt8 Debugger::peek(uInt16 addr, Device::AccessFlags flags)
|
||||||
{
|
{
|
||||||
|
|
|
@ -321,6 +321,7 @@ class Debugger : public DialogContainer
|
||||||
bool readTrap(uInt16 t);
|
bool readTrap(uInt16 t);
|
||||||
bool writeTrap(uInt16 t);
|
bool writeTrap(uInt16 t);
|
||||||
void clearAllTraps();
|
void clearAllTraps();
|
||||||
|
void log(const string& triggerMsg);
|
||||||
|
|
||||||
// Set a bunch of RAM locations at once
|
// Set a bunch of RAM locations at once
|
||||||
string setRAM(IntArray& args);
|
string setRAM(IntArray& args);
|
||||||
|
@ -363,6 +364,7 @@ class Debugger : public DialogContainer
|
||||||
static std::array<PseudoRegister, 16> ourPseudoRegisters;
|
static std::array<PseudoRegister, 16> ourPseudoRegisters;
|
||||||
|
|
||||||
static constexpr Int8 ANY_BANK = -1;
|
static constexpr Int8 ANY_BANK = -1;
|
||||||
|
bool myFirstLog{true};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// rewind/unwind n states
|
// rewind/unwind n states
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
#include "Expression.hxx"
|
#include "Expression.hxx"
|
||||||
#include "FSNode.hxx"
|
#include "FSNode.hxx"
|
||||||
#include "OSystem.hxx"
|
#include "OSystem.hxx"
|
||||||
|
#include "System.hxx"
|
||||||
|
#include "M6502.hxx"
|
||||||
#include "Settings.hxx"
|
#include "Settings.hxx"
|
||||||
#include "PromptWidget.hxx"
|
#include "PromptWidget.hxx"
|
||||||
#include "RomWidget.hxx"
|
#include "RomWidget.hxx"
|
||||||
|
@ -1664,6 +1666,16 @@ void DebuggerParser::executeLoadstate()
|
||||||
commandResult << red("invalid slot (must be 0-9)");
|
commandResult << red("invalid slot (must be 0-9)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void DebuggerParser::executeLogBreaks()
|
||||||
|
{
|
||||||
|
bool enable = !debugger.mySystem.m6502().getLogBreaks();
|
||||||
|
|
||||||
|
debugger.mySystem.m6502().setLogBreaks(enable);
|
||||||
|
settings.setValue("dbg.logbreaks", enable);
|
||||||
|
commandResult << "logbreaks " << (enable ? "enabled" : "disabled");
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
// "n"
|
// "n"
|
||||||
void DebuggerParser::executeN()
|
void DebuggerParser::executeN()
|
||||||
|
@ -2475,7 +2487,7 @@ void DebuggerParser::executeZ()
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
// List of all commands available to the parser
|
// List of all commands available to the parser
|
||||||
std::array<DebuggerParser::Command, 100> DebuggerParser::commands = { {
|
DebuggerParser::CommandArray DebuggerParser::commands = { {
|
||||||
{
|
{
|
||||||
"a",
|
"a",
|
||||||
"Set Accumulator to <value>",
|
"Set Accumulator to <value>",
|
||||||
|
@ -3025,6 +3037,16 @@ std::array<DebuggerParser::Command, 100> DebuggerParser::commands = { {
|
||||||
std::mem_fn(&DebuggerParser::executeLoadstate)
|
std::mem_fn(&DebuggerParser::executeLoadstate)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"logbreaks",
|
||||||
|
"Toggle logging of breaks/traps and continue emulation",
|
||||||
|
"Example: logbreaks (no parameters)",
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
{ Parameters::ARG_END_ARGS },
|
||||||
|
std::mem_fn(&DebuggerParser::executeLogBreaks)
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"n",
|
"n",
|
||||||
"Negative Flag: set (0 or 1), or toggle (no arg)",
|
"Negative Flag: set (0 or 1), or toggle (no arg)",
|
||||||
|
|
|
@ -101,7 +101,8 @@ class DebuggerParser
|
||||||
std::array<Parameters, 10> parms;
|
std::array<Parameters, 10> parms;
|
||||||
std::function<void (DebuggerParser*)> executor;
|
std::function<void (DebuggerParser*)> executor;
|
||||||
};
|
};
|
||||||
static std::array<Command, 100> commands;
|
using CommandArray = std::array<Command, 101>;
|
||||||
|
static CommandArray commands;
|
||||||
|
|
||||||
struct Trap
|
struct Trap
|
||||||
{
|
{
|
||||||
|
@ -201,6 +202,7 @@ class DebuggerParser
|
||||||
void executeLoadallstates();
|
void executeLoadallstates();
|
||||||
void executeLoadconfig();
|
void executeLoadconfig();
|
||||||
void executeLoadstate();
|
void executeLoadstate();
|
||||||
|
void executeLogBreaks();
|
||||||
void executeN();
|
void executeN();
|
||||||
void executePalette();
|
void executePalette();
|
||||||
void executePc();
|
void executePc();
|
||||||
|
|
|
@ -557,6 +557,8 @@ void PromptWidget::loadConfig()
|
||||||
print(instance().debugger().cartDebug().loadConfigFile() + "\n");
|
print(instance().debugger().cartDebug().loadConfigFile() + "\n");
|
||||||
print(instance().debugger().cartDebug().loadListFile() + "\n");
|
print(instance().debugger().cartDebug().loadListFile() + "\n");
|
||||||
print(instance().debugger().cartDebug().loadSymbolFile() + "\n");
|
print(instance().debugger().cartDebug().loadSymbolFile() + "\n");
|
||||||
|
if(instance().settings().getBool("dbg.logbreaks"))
|
||||||
|
print(DebuggerParser::inverse(" logbreaks enabled \n"));
|
||||||
print(PROMPT);
|
print(PROMPT);
|
||||||
|
|
||||||
_promptStartPos = _promptEndPos = _currentPos;
|
_promptStartPos = _promptEndPos = _currentPos;
|
||||||
|
|
|
@ -93,6 +93,7 @@ void M6502::reset()
|
||||||
myGhostReadsTrap = mySettings.getBool("dbg.ghostreadstrap");
|
myGhostReadsTrap = mySettings.getBool("dbg.ghostreadstrap");
|
||||||
myReadFromWritePortBreak = devSettings ? mySettings.getBool("dev.rwportbreak") : false;
|
myReadFromWritePortBreak = devSettings ? mySettings.getBool("dev.rwportbreak") : false;
|
||||||
myWriteToReadPortBreak = devSettings ? mySettings.getBool("dev.wrportbreak") : false;
|
myWriteToReadPortBreak = devSettings ? mySettings.getBool("dev.wrportbreak") : false;
|
||||||
|
myLogBreaks = mySettings.getBool("dbg.logbreaks");
|
||||||
|
|
||||||
myLastBreakCycle = ULLONG_MAX;
|
myLastBreakCycle = ULLONG_MAX;
|
||||||
}
|
}
|
||||||
|
@ -162,7 +163,7 @@ inline void M6502::poke(uInt16 address, uInt8 value, Device::AccessFlags flags)
|
||||||
{
|
{
|
||||||
myJustHitWriteTrapFlag = true;
|
myJustHitWriteTrapFlag = true;
|
||||||
stringstream msg;
|
stringstream msg;
|
||||||
msg << "WTrap[" << Common::Base::HEX2 << cond << "]" << (myTrapCondNames[cond].empty() ? ": " : "If: {" + myTrapCondNames[cond] + "} ");
|
msg << "WTrap[" << Common::Base::HEX2 << cond << "]" << (myTrapCondNames[cond].empty() ? ":" : "If: {" + myTrapCondNames[cond] + "}");
|
||||||
myHitTrapInfo.message = msg.str();
|
myHitTrapInfo.message = msg.str();
|
||||||
myHitTrapInfo.address = address;
|
myHitTrapInfo.address = address;
|
||||||
}
|
}
|
||||||
|
@ -243,11 +244,17 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
|
||||||
myJustHitReadTrapFlag = myJustHitWriteTrapFlag = false;
|
myJustHitReadTrapFlag = myJustHitWriteTrapFlag = false;
|
||||||
|
|
||||||
myLastBreakCycle = mySystem->cycles();
|
myLastBreakCycle = mySystem->cycles();
|
||||||
result.setDebugger(currentCycles, myHitTrapInfo.message,
|
|
||||||
|
if(myLogBreaks)
|
||||||
|
myDebugger->log(myHitTrapInfo.message);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.setDebugger(currentCycles, myHitTrapInfo.message + " ",
|
||||||
read ? "Read trap" : "Write trap",
|
read ? "Read trap" : "Write trap",
|
||||||
myHitTrapInfo.address, read);
|
myHitTrapInfo.address, read);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(myBreakPoints.isInitialized())
|
if(myBreakPoints.isInitialized())
|
||||||
{
|
{
|
||||||
|
@ -260,30 +267,44 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
|
||||||
if(myBreakPoints.get(PC, bank) & BreakpointMap::ONE_SHOT)
|
if(myBreakPoints.get(PC, bank) & BreakpointMap::ONE_SHOT)
|
||||||
{
|
{
|
||||||
myBreakPoints.erase(PC, bank);
|
myBreakPoints.erase(PC, bank);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if(myLogBreaks)
|
||||||
|
myDebugger->log("BP:");
|
||||||
|
else
|
||||||
{
|
{
|
||||||
ostringstream msg;
|
ostringstream msg;
|
||||||
|
|
||||||
msg << "BP: $" << Common::Base::HEX4 << PC << ", bank #" << std::dec << int(bank);
|
msg << "BP: $" << Common::Base::HEX4 << PC << ", bank #" << std::dec << int(bank);
|
||||||
result.setDebugger(currentCycles, msg.str(), "Breakpoint");
|
result.setDebugger(currentCycles, msg.str(), "Breakpoint");
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int cond = evalCondBreaks();
|
int cond = evalCondBreaks();
|
||||||
if(cond > -1)
|
if(cond > -1)
|
||||||
{
|
{
|
||||||
ostringstream msg;
|
ostringstream msg;
|
||||||
|
|
||||||
msg << "CBP[" << Common::Base::HEX2 << cond << "]: " << myCondBreakNames[cond];
|
|
||||||
|
|
||||||
myLastBreakCycle = mySystem->cycles();
|
myLastBreakCycle = mySystem->cycles();
|
||||||
|
|
||||||
|
if(myLogBreaks)
|
||||||
|
{
|
||||||
|
msg << "CBP[" << Common::Base::HEX2 << cond << "]:";
|
||||||
|
myDebugger->log(msg.str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg << "CBP[" << Common::Base::HEX2 << cond << "]: " << myCondBreakNames[cond];
|
||||||
result.setDebugger(currentCycles, msg.str(), "Conditional breakpoint");
|
result.setDebugger(currentCycles, msg.str(), "Conditional breakpoint");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int cond = evalCondSaveStates();
|
int cond = evalCondSaveStates();
|
||||||
if(cond > -1)
|
if(cond > -1)
|
||||||
|
|
|
@ -255,6 +255,8 @@ class M6502 : public Serializable
|
||||||
void setGhostReadsTrap(bool enable) { myGhostReadsTrap = enable; }
|
void setGhostReadsTrap(bool enable) { myGhostReadsTrap = enable; }
|
||||||
void setReadFromWritePortBreak(bool enable) { myReadFromWritePortBreak = enable; }
|
void setReadFromWritePortBreak(bool enable) { myReadFromWritePortBreak = enable; }
|
||||||
void setWriteToReadPortBreak(bool enable) { myWriteToReadPortBreak = enable; }
|
void setWriteToReadPortBreak(bool enable) { myWriteToReadPortBreak = enable; }
|
||||||
|
void setLogBreaks(bool enable) { myLogBreaks = enable; }
|
||||||
|
bool getLogBreaks() { return myLogBreaks; }
|
||||||
#endif // DEBUGGER_SUPPORT
|
#endif // DEBUGGER_SUPPORT
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -469,6 +471,7 @@ class M6502 : public Serializable
|
||||||
bool myReadFromWritePortBreak{false}; // trap on reads from write ports
|
bool myReadFromWritePortBreak{false}; // trap on reads from write ports
|
||||||
bool myWriteToReadPortBreak{false}; // trap on writes to read ports
|
bool myWriteToReadPortBreak{false}; // trap on writes to read ports
|
||||||
bool myStepStateByInstruction{false};
|
bool myStepStateByInstruction{false};
|
||||||
|
bool myLogBreaks{false}; // log breaks/taps and continue emulation
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Following constructors and assignment operators not supported
|
// Following constructors and assignment operators not supported
|
||||||
|
|
|
@ -188,6 +188,7 @@ Settings::Settings()
|
||||||
setPermanent("dbg.fontstyle", "0");
|
setPermanent("dbg.fontstyle", "0");
|
||||||
setPermanent("dbg.uhex", "false");
|
setPermanent("dbg.uhex", "false");
|
||||||
setPermanent("dbg.ghostreadstrap", "true");
|
setPermanent("dbg.ghostreadstrap", "true");
|
||||||
|
setPermanent("dbg.logbreaks", "false");
|
||||||
setPermanent("dis.resolve", "true");
|
setPermanent("dis.resolve", "true");
|
||||||
setPermanent("dis.gfxformat", "2");
|
setPermanent("dis.gfxformat", "2");
|
||||||
setPermanent("dis.showaddr", "true");
|
setPermanent("dis.showaddr", "true");
|
||||||
|
@ -614,6 +615,7 @@ void Settings::usage() const
|
||||||
<< " normal)\n"
|
<< " normal)\n"
|
||||||
<< " -dbg.ghostreadstrap <1|0> Debugger traps on 'ghost' reads\n"
|
<< " -dbg.ghostreadstrap <1|0> Debugger traps on 'ghost' reads\n"
|
||||||
<< " -dbg.uhex <0|1> lower-/uppercase HEX display\n"
|
<< " -dbg.uhex <0|1> lower-/uppercase HEX display\n"
|
||||||
|
<< " -dbg.logbreaks <0|1> log breaks and traps and continue emulation\n"
|
||||||
<< " -break <address> Set a breakpoint at 'address'\n"
|
<< " -break <address> Set a breakpoint at 'address'\n"
|
||||||
<< " -debug Start in debugger mode\n"
|
<< " -debug Start in debugger mode\n"
|
||||||
<< endl
|
<< endl
|
||||||
|
|
Loading…
Reference in New Issue