mirror of https://github.com/stella-emu/stella.git
Merge branch 'trapif_attempt_1'
This commit is contained in:
commit
20babc832a
|
@ -30,6 +30,7 @@ class CartDebugWidget;
|
|||
#include "Cart.hxx"
|
||||
#include "DebuggerSystem.hxx"
|
||||
#include "System.hxx"
|
||||
#include "M6502.hxx"
|
||||
|
||||
// Function type for CartDebug instance methods
|
||||
class CartDebug;
|
||||
|
@ -127,6 +128,11 @@ class CartDebug : public DebuggerSystem
|
|||
// write port area.
|
||||
int readFromWritePort();
|
||||
|
||||
// Return the base (= non-mirrored) address of the last CPU read
|
||||
int lastReadBaseAddress() { return mySystem.m6502().lastReadBaseAddress(); }
|
||||
// Return the base (= non-mirrored) address of the last CPU write
|
||||
int lastWriteBaseAddress() { return mySystem.m6502().lastWriteBaseAddress(); }
|
||||
|
||||
// The following two methods are meant to be used together
|
||||
// First, a call is made to disassemble(), which updates the disassembly
|
||||
// list; it will figure out when an actual complete disassembly is
|
||||
|
|
|
@ -85,7 +85,6 @@ static const char* const builtin_functions[][3] = {
|
|||
{ "_diff0a", "*SWCHB & $40", "Left diff. set to A (hard)" },
|
||||
{ "_diff1b", "!(*SWCHB & $80)", "Right diff. set to B (easy)" },
|
||||
{ "_diff1a", "*SWCHB & $80", "Right diff. set to A (hard)" },
|
||||
|
||||
// empty string marks end of list, do not remove
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
@ -104,7 +103,10 @@ static const char* const pseudo_registers[][2] = {
|
|||
{ "_rwport", "Address at which a read from a write port occurred" },
|
||||
{ "_scan", "Current scanline count" },
|
||||
{ "_vblank", "Whether vertical blank is enabled (1 or 0)" },
|
||||
{ "_vsync", "Whether vertical sync is enabled (1 or 0)" },
|
||||
{ "_vsync", "Whether vertical sync is enabled (1 or 0)" },
|
||||
// CPU address access functions:
|
||||
/*{ "__lastread", "last CPU read address" },
|
||||
{ "__lastwrite", "last CPU write address" },*/
|
||||
|
||||
// empty string marks end of list, do not remove
|
||||
{ 0, 0 }
|
||||
|
@ -166,7 +168,7 @@ FBInitStatus Debugger::initializeVideo()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::start(const string& message, int address)
|
||||
bool Debugger::start(const string& message, int address, bool read)
|
||||
{
|
||||
if(myOSystem.eventHandler().enterDebugMode())
|
||||
{
|
||||
|
@ -175,8 +177,7 @@ bool Debugger::start(const string& message, int address)
|
|||
ostringstream buf;
|
||||
buf << message;
|
||||
if(address > -1)
|
||||
buf << Common::Base::HEX4 << address;
|
||||
|
||||
buf << cartDebug().getLabel(address, read);
|
||||
myDialog->message().setText(buf.str());
|
||||
return true;
|
||||
}
|
||||
|
@ -367,24 +368,43 @@ bool Debugger::breakPoint(uInt16 bp)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::toggleReadTrap(uInt16 t)
|
||||
void Debugger::addReadTrap(uInt16 t)
|
||||
{
|
||||
readTraps().initialize();
|
||||
readTraps().toggle(t);
|
||||
readTraps().add(t);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::toggleWriteTrap(uInt16 t)
|
||||
void Debugger::addWriteTrap(uInt16 t)
|
||||
{
|
||||
writeTraps().initialize();
|
||||
writeTraps().toggle(t);
|
||||
writeTraps().add(t);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::toggleTrap(uInt16 t)
|
||||
void Debugger::addTrap(uInt16 t)
|
||||
{
|
||||
toggleReadTrap(t);
|
||||
toggleWriteTrap(t);
|
||||
addReadTrap(t);
|
||||
addWriteTrap(t);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::removeReadTrap(uInt16 t)
|
||||
{
|
||||
readTraps().initialize();
|
||||
readTraps().remove(t);
|
||||
}
|
||||
|
||||
void Debugger::removeWriteTrap(uInt16 t)
|
||||
{
|
||||
writeTraps().initialize();
|
||||
writeTraps().remove(t);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::removeTrap(uInt16 t)
|
||||
{
|
||||
removeReadTrap(t);
|
||||
removeWriteTrap(t);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -398,6 +418,48 @@ bool Debugger::writeTrap(uInt16 t)
|
|||
{
|
||||
return writeTraps().isInitialized() && writeTraps().isSet(t);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 Debugger::getBaseAddress(uInt32 addr, bool read)
|
||||
{
|
||||
if((addr & 0x1080) == 0x0000) // (addr & 0b 0001 0000 1000 0000) == 0b 0000 0000 0000 0000
|
||||
if(read)
|
||||
// ADDR_TIA read (%xxx0 xxxx 0xxx ????)
|
||||
return addr & 0x000f; // 0b 0000 0000 0000 1111
|
||||
else
|
||||
// ADDR_TIA write (%xxx0 xxxx 0x?? ????)
|
||||
return addr & 0x003f; // 0b 0000 0000 0011 1111
|
||||
|
||||
// ADDR_ZPRAM (%xxx0 xx0x 1??? ????)
|
||||
if((addr & 0x1280) == 0x0080) // (addr & 0b 0001 0010 1000 0000) == 0b 0000 0000 1000 0000
|
||||
return addr & 0x00ff; // 0b 0000 0000 1111 1111
|
||||
|
||||
// ADDR_ROM
|
||||
if(addr & 0x1000)
|
||||
return addr & 0x1fff; // 0b 0001 1111 1111 1111
|
||||
|
||||
// ADDR_IO read/write I/O registers (%xxx0 xx1x 1xxx x0??)
|
||||
if((addr & 0x1284) == 0x0280) // (addr & 0b 0001 0010 1000 0100) == 0b 0000 0010 1000 0000
|
||||
return addr & 0x0283; // 0b 0000 0010 1000 0011
|
||||
|
||||
// ADDR_IO write timers (%xxx0 xx1x 1xx1 ?1??)
|
||||
if(!read && (addr & 0x1294) == 0x0294) // (addr & 0b 0001 0010 1001 0100) == 0b 0000 0010 1001 0100
|
||||
return addr & 0x029f; // 0b 0000 0010 1001 1111
|
||||
|
||||
// ADDR_IO read timers (%xxx0 xx1x 1xxx ?1x0)
|
||||
if(read && (addr & 0x1285) == 0x0284) // (addr & 0b 0001 0010 1000 0101) == 0b 0000 0010 1000 0100
|
||||
return addr & 0x028c; // 0b 0000 0010 1000 1100
|
||||
|
||||
// ADDR_IO read timer/PA7 interrupt (%xxx0 xx1x 1xxx x1x1)
|
||||
if(read && (addr & 0x1285) == 0x0285) // (addr & 0b 0001 0010 1000 0101) == 0b 0000 0010 1000 0101
|
||||
return addr & 0x0285; // 0b 0000 0010 1000 0101
|
||||
|
||||
// ADDR_IO write PA7 edge control (%xxx0 xx1x 1xx0 x1??)
|
||||
if(!read && (addr & 0x1294) == 0x0284) // (addr & 0b 0001 0010 1001 0100) == 0b 0000 0010 1000 0100
|
||||
return addr & 0x0287; // 0b 0000 0010 1000 0111
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::nextScanline(int lines)
|
||||
|
|
|
@ -88,7 +88,7 @@ class Debugger : public DialogContainer
|
|||
@param message Message to display when entering debugger
|
||||
@param address An address associated with the message
|
||||
*/
|
||||
bool start(const string& message = "", int address = -1);
|
||||
bool start(const string& message = "", int address = -1, bool read = true);
|
||||
bool startWithFatalError(const string& message = "");
|
||||
|
||||
/**
|
||||
|
@ -145,8 +145,8 @@ 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(); }
|
||||
|
||||
/**
|
||||
Run the debugger command and return the result.
|
||||
|
@ -214,6 +214,7 @@ class Debugger : public DialogContainer
|
|||
{ mySystem.setAccessFlags(addr, flags); }
|
||||
|
||||
void setBreakPoint(uInt16 bp, bool set);
|
||||
uInt32 getBaseAddress(uInt32 addr, bool read);
|
||||
|
||||
bool patchROM(uInt16 addr, uInt8 value);
|
||||
|
||||
|
@ -256,9 +257,12 @@ class Debugger : public DialogContainer
|
|||
void toggleBreakPoint(uInt16 bp);
|
||||
|
||||
bool breakPoint(uInt16 bp);
|
||||
void toggleReadTrap(uInt16 t);
|
||||
void toggleWriteTrap(uInt16 t);
|
||||
void toggleTrap(uInt16 t);
|
||||
void addReadTrap(uInt16 t);
|
||||
void addWriteTrap(uInt16 t);
|
||||
void addTrap(uInt16 t);
|
||||
void removeReadTrap(uInt16 t);
|
||||
void removeWriteTrap(uInt16 t);
|
||||
void removeTrap(uInt16 t);
|
||||
bool readTrap(uInt16 t);
|
||||
bool writeTrap(uInt16 t);
|
||||
void clearAllTraps();
|
||||
|
|
|
@ -543,31 +543,32 @@ string DebuggerParser::eval()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string DebuggerParser::trapStatus(uInt32 addr, bool& enabled)
|
||||
string DebuggerParser::trapStatus(const Trap& trap)
|
||||
{
|
||||
string result;
|
||||
result += Base::toString(addr);
|
||||
result += ": ";
|
||||
bool r = debugger.readTrap(addr);
|
||||
bool w = debugger.writeTrap(addr);
|
||||
enabled = r || w;
|
||||
if(r && w)
|
||||
result += "read|write";
|
||||
else if(r)
|
||||
result += "read";
|
||||
else if(w)
|
||||
result += "write";
|
||||
else
|
||||
result += "none";
|
||||
|
||||
const string& l = debugger.cartDebug().getLabel(addr, !w);
|
||||
if(l != "") {
|
||||
result += " (";
|
||||
result += l;
|
||||
result += ")";
|
||||
stringstream result;
|
||||
string lblb = debugger.cartDebug().getLabel(trap.begin, !trap.write);
|
||||
string lble = debugger.cartDebug().getLabel(trap.end, !trap.write);
|
||||
|
||||
if(lblb != "") {
|
||||
result << " (";
|
||||
result << lblb;
|
||||
}
|
||||
|
||||
return result;
|
||||
if(trap.begin != trap.end)
|
||||
{
|
||||
if(lble != "")
|
||||
{
|
||||
if (lblb != "")
|
||||
result << " ";
|
||||
else
|
||||
result << " (";
|
||||
result << lble;
|
||||
}
|
||||
}
|
||||
if (lblb != "" || lble != "")
|
||||
result << ")";
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -589,9 +590,10 @@ bool DebuggerParser::saveScriptFile(string file)
|
|||
if(debugger.breakPoint(i))
|
||||
out << "break #" << i << endl;
|
||||
|
||||
// TODO: new trapif
|
||||
for(uInt32 i = 0; i < 0x10000; ++i)
|
||||
{
|
||||
bool r = debugger.readTrap(i);
|
||||
bool r = debugger.readTrap(i);
|
||||
bool w = debugger.writeTrap(i);
|
||||
|
||||
if(r && w)
|
||||
|
@ -744,8 +746,9 @@ void DebuggerParser::executeClearconfig()
|
|||
// "cleartraps"
|
||||
void DebuggerParser::executeCleartraps()
|
||||
{
|
||||
myTraps.clear();
|
||||
debugger.clearAllTraps();
|
||||
debugger.cpuDebug().m6502().clearCondTraps();
|
||||
myTraps.clear();
|
||||
commandResult << "all traps cleared";
|
||||
}
|
||||
|
||||
|
@ -861,6 +864,24 @@ void DebuggerParser::executeDelfunction()
|
|||
commandResult << "function " << argStrings[0] << " built-in or not found";
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "deltrap"
|
||||
void DebuggerParser::executeDeltrap()
|
||||
{
|
||||
int index = args[0];
|
||||
|
||||
if(debugger.cpuDebug().m6502().delCondTrap(index))
|
||||
{
|
||||
for(uInt32 addr = myTraps[index]->begin; addr <= myTraps[index]->end; ++addr)
|
||||
executeTrapRW(addr, myTraps[index]->read, myTraps[index]->write, false);
|
||||
// @sa666666: please check this:
|
||||
Vec::removeAt(myTraps, index);
|
||||
commandResult << "removed trap " << Base::toString(index);
|
||||
}
|
||||
else
|
||||
commandResult << "no such trap";
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "delwatch"
|
||||
void DebuggerParser::executeDelwatch()
|
||||
|
@ -1089,7 +1110,7 @@ void DebuggerParser::executeListbreaks()
|
|||
commandResult << "\nbreakifs:\n";
|
||||
for(uInt32 i = 0; i < conds.size(); i++)
|
||||
{
|
||||
commandResult << i << ": " << conds[i];
|
||||
commandResult << Base::toString(i) << ": " << conds[i];
|
||||
if(i != (conds.size() - 1)) commandResult << endl;
|
||||
}
|
||||
}
|
||||
|
@ -1127,11 +1148,37 @@ void DebuggerParser::executeListfunctions()
|
|||
// "listtraps"
|
||||
void DebuggerParser::executeListtraps()
|
||||
{
|
||||
if(myTraps.size() > 0)
|
||||
StringList names = debugger.cpuDebug().m6502().getCondTrapNames();
|
||||
|
||||
if(myTraps.size() != names.size())
|
||||
{
|
||||
bool enabled = true;
|
||||
for(const auto& trap: myTraps)
|
||||
commandResult << trapStatus(trap, enabled) << " + mirrors" << endl;
|
||||
commandResult << "Internal error! Different trap sizes.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (names.size() > 0)
|
||||
{
|
||||
for(uInt32 i = 0; i < names.size(); i++)
|
||||
{
|
||||
commandResult << Base::toString(i) << ": ";
|
||||
|
||||
if(myTraps[i]->read && myTraps[i]->write)
|
||||
commandResult << "read|write";
|
||||
else if(myTraps[i]->read)
|
||||
commandResult << "read ";
|
||||
else if(myTraps[i]->write)
|
||||
commandResult << " write";
|
||||
else
|
||||
commandResult << "none";
|
||||
|
||||
commandResult << " " << names[i];
|
||||
commandResult << " " << Base::toString(myTraps[i]->begin);
|
||||
if (myTraps[i]->begin != myTraps[i]->end)
|
||||
commandResult << " " << Base::toString(myTraps[i]->end);
|
||||
commandResult << trapStatus(*myTraps[i]);
|
||||
commandResult << " + mirrors";
|
||||
if(i != (names.size() - 1)) commandResult << endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
commandResult << "no traps set";
|
||||
|
@ -1482,71 +1529,153 @@ void DebuggerParser::executeTrace()
|
|||
// "trap"
|
||||
void DebuggerParser::executeTrap()
|
||||
{
|
||||
if(argCount > 2)
|
||||
{
|
||||
commandResult << red("Command takes one or two arguments") << endl;
|
||||
return;
|
||||
}
|
||||
executeTraps(true, true, "trap");
|
||||
}
|
||||
|
||||
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, "trapif", true);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "trapread"
|
||||
void DebuggerParser::executeTrapread()
|
||||
{
|
||||
if(argCount > 2)
|
||||
{
|
||||
commandResult << red("Command takes one or two arguments") << endl;
|
||||
return;
|
||||
}
|
||||
executeTraps(true, false, "trapread");
|
||||
}
|
||||
|
||||
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, "trapreadif", true);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "trapwrite"
|
||||
void DebuggerParser::executeTrapwrite()
|
||||
{
|
||||
if(argCount > 2)
|
||||
{
|
||||
commandResult << red("Command takes one or two arguments") << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
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, false, true);
|
||||
executeTraps(false, true, "trapwrite");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// wrapper function for trap/trapread/trapwrite commands
|
||||
void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
|
||||
// "trapwriteif"
|
||||
void DebuggerParser::executeTrapwriteif()
|
||||
{
|
||||
executeTraps(false, true, "trapwriteif", true);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Wrapper function for trap(if)s
|
||||
void DebuggerParser::executeTraps(bool read, bool write, string command, bool hasCond)
|
||||
{
|
||||
if(hasCond)
|
||||
{
|
||||
if(argCount < 1 || argCount > 3)
|
||||
{
|
||||
commandResult << red("Command takes one to three arguments");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(argCount > 2)
|
||||
{
|
||||
commandResult << red("Command takes one or two arguments");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int ofs = hasCond ? 1 : 0;
|
||||
uInt32 begin = args[ofs];
|
||||
uInt32 end = argCount == ofs + 2 ? args[ofs + 1] : begin;
|
||||
// mirrors
|
||||
uInt32 beginRead = debugger.getBaseAddress(begin, true);
|
||||
uInt32 endRead = debugger.getBaseAddress(end, true);
|
||||
uInt32 beginWrite = debugger.getBaseAddress(begin, false);
|
||||
uInt32 endWrite = debugger.getBaseAddress(end, false);
|
||||
|
||||
if(begin > 0xFFFF || end > 0xFFFF || begin > end)
|
||||
{
|
||||
commandResult << red("One or more addresses are invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
// parenthesize provided and address range condition(s) (begin)
|
||||
stringstream parserBuf, displayBuf;
|
||||
if(hasCond)
|
||||
parserBuf << "(" << argStrings[0] << ")&&(";
|
||||
|
||||
// add address range condition(s) to provided condition
|
||||
if(read)
|
||||
{
|
||||
if(beginRead != endRead)
|
||||
parserBuf << "__lastread>=" << Base::toString(beginRead) << "&&__lastread<=" << Base::toString(endRead);
|
||||
else
|
||||
parserBuf << "__lastread==" << Base::toString(beginRead);
|
||||
}
|
||||
if(read && write)
|
||||
parserBuf << "||";
|
||||
if(write)
|
||||
{
|
||||
if(beginWrite != endWrite)
|
||||
parserBuf << "__lastwrite>=" << Base::toString(beginWrite) << "&&__lastwrite<=" << Base::toString(endWrite);
|
||||
else
|
||||
parserBuf << "__lastwrite==" << Base::toString(beginWrite);
|
||||
}
|
||||
// parenthesize provided condition (end)
|
||||
if(hasCond)
|
||||
parserBuf << ")";
|
||||
|
||||
const string parserCondition = parserBuf.str();
|
||||
|
||||
int res = YaccParser::parse(parserCondition.c_str());
|
||||
if(res == 0)
|
||||
{
|
||||
// duplicates will remove each other
|
||||
bool add = true;
|
||||
for(uInt32 i = 0; i < myTraps.size(); i++)
|
||||
{
|
||||
if(myTraps[i]->begin == begin && myTraps[i]->end == end &&
|
||||
myTraps[i]->read == read && myTraps[i]->write == write &&
|
||||
myTraps[i]->condition == parserCondition)
|
||||
{
|
||||
if(debugger.cpuDebug().m6502().delCondTrap(i))
|
||||
{
|
||||
add = false;
|
||||
// @sa666666: please check this:
|
||||
Vec::removeAt(myTraps, i);
|
||||
commandResult << "Removed trap " << Base::toString(i);
|
||||
break;
|
||||
}
|
||||
commandResult << "Internal error! Duplicate trap removal failed!";
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(add)
|
||||
{
|
||||
uInt32 ret = debugger.cpuDebug().m6502().addCondTrap(
|
||||
YaccParser::getResult(), hasCond ? argStrings[0] : " ");
|
||||
commandResult << "Added trap " << Base::toString(ret);
|
||||
|
||||
// @sa666666: please check this:
|
||||
myTraps.emplace_back(new Trap{ read, write, begin, end, parserCondition });
|
||||
}
|
||||
|
||||
for(uInt32 addr = begin; addr <= end; ++addr)
|
||||
executeTrapRW(addr, read, write, add);
|
||||
}
|
||||
else
|
||||
{
|
||||
commandResult << red("invalid expression");
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// wrapper function for trap(if)/trapread(if)/trapwrite(if) commands
|
||||
void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write, bool add)
|
||||
{
|
||||
switch(debugger.cartDebug().addressType(addr))
|
||||
{
|
||||
|
@ -1556,10 +1685,11 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
|
|||
{
|
||||
if((i & 0x1080) == 0x0000)
|
||||
{
|
||||
if(read && (i & 0x000F) == addr)
|
||||
debugger.toggleReadTrap(i);
|
||||
if(write && (i & 0x003F) == addr)
|
||||
debugger.toggleWriteTrap(i);
|
||||
// @sa666666: This seems wrong. E.g. trapread 40 4f will never trigger
|
||||
if(read && (i & 0x000F) == (addr & 0x000F))
|
||||
add ? debugger.addReadTrap(i) : debugger.removeReadTrap(i);
|
||||
if(write && (i & 0x003F) == (addr & 0x003F))
|
||||
add ? debugger.addWriteTrap(i) : debugger.removeWriteTrap(i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1568,10 +1698,12 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
|
|||
{
|
||||
for(uInt32 i = 0; i <= 0xFFFF; ++i)
|
||||
{
|
||||
if((i & 0x1080) == 0x0080 && (i & 0x0200) != 0x0000 && (i & 0x02FF) == addr)
|
||||
if((i & 0x1280) == 0x0280 && (i & 0x029F) == (addr & 0x029F))
|
||||
{
|
||||
if(read) debugger.toggleReadTrap(i);
|
||||
if(write) debugger.toggleWriteTrap(i);
|
||||
if(read)
|
||||
add ? debugger.addReadTrap(i) : debugger.removeReadTrap(i);
|
||||
if(write)
|
||||
add ? debugger.addWriteTrap(i) : debugger.removeWriteTrap(i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1580,10 +1712,12 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
|
|||
{
|
||||
for(uInt32 i = 0; i <= 0xFFFF; ++i)
|
||||
{
|
||||
if((i & 0x1080) == 0x0080 && (i & 0x0200) == 0x0000 && (i & 0x00FF) == addr)
|
||||
if((i & 0x1280) == 0x0080 && (i & 0x00FF) == (addr & 0x00FF))
|
||||
{
|
||||
if(read) debugger.toggleReadTrap(i);
|
||||
if(write) debugger.toggleWriteTrap(i);
|
||||
if(read)
|
||||
add ? debugger.addReadTrap(i) : debugger.removeReadTrap(i);
|
||||
if(write)
|
||||
add ? debugger.addWriteTrap(i) : debugger.removeWriteTrap(i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1596,21 +1730,16 @@ 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)
|
||||
add ? debugger.addReadTrap(i) : debugger.removeReadTrap(i);
|
||||
if(write)
|
||||
add ? debugger.addWriteTrap(i) : debugger.removeWriteTrap(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool trapEnabled = false;
|
||||
const string& result = trapStatus(addr, trapEnabled);
|
||||
if(trapEnabled) myTraps.insert(addr);
|
||||
else myTraps.erase(addr);
|
||||
|
||||
commandResult << result << " + mirrors" << endl;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1891,6 +2020,16 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
|||
std::mem_fn(&DebuggerParser::executeDelfunction)
|
||||
},
|
||||
|
||||
{
|
||||
"deltrap",
|
||||
"Delete trap <xx>",
|
||||
"Example: deltrap 0",
|
||||
true,
|
||||
false,
|
||||
{ kARG_WORD, kARG_END_ARGS },
|
||||
std::mem_fn(&DebuggerParser::executeDeltrap)
|
||||
},
|
||||
|
||||
{
|
||||
"delwatch",
|
||||
"Delete watch <xx>",
|
||||
|
@ -2333,6 +2472,17 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
|||
std::mem_fn(&DebuggerParser::executeTrap)
|
||||
},
|
||||
|
||||
{
|
||||
"trapif",
|
||||
"On <condition> 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 +2494,17 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
|||
std::mem_fn(&DebuggerParser::executeTrapread)
|
||||
},
|
||||
|
||||
{
|
||||
"trapreadif",
|
||||
"On <condition> 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 +2516,17 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
|||
std::mem_fn(&DebuggerParser::executeTrapwrite)
|
||||
},
|
||||
|
||||
{
|
||||
"trapwriteif",
|
||||
"On <condition> 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]",
|
||||
|
|
|
@ -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,15 @@ class DebuggerParser
|
|||
parameters parms[10];
|
||||
std::function<void (DebuggerParser*)> executor;
|
||||
};
|
||||
|
||||
struct Trap
|
||||
{
|
||||
bool read;
|
||||
bool write;
|
||||
uInt32 begin;
|
||||
uInt32 end;
|
||||
string condition;
|
||||
};
|
||||
|
||||
// Reference to our debugger object
|
||||
Debugger& debugger;
|
||||
|
||||
|
@ -117,9 +125,12 @@ class DebuggerParser
|
|||
|
||||
StringList myWatches;
|
||||
|
||||
|
||||
// Keep track of traps (read and/or write)
|
||||
std::set<uInt32> myTraps;
|
||||
string trapStatus(uInt32 addr, bool& enabled);
|
||||
vector<unique_ptr<Trap>> myTraps;
|
||||
/*std::set<uInt32> myTraps;
|
||||
std::vector<uInt32> myTrapIfs;*/
|
||||
string trapStatus(const Trap& trap);
|
||||
|
||||
// List of available command methods
|
||||
void executeA();
|
||||
|
@ -139,8 +150,9 @@ class DebuggerParser
|
|||
void executeData();
|
||||
void executeDebugColors();
|
||||
void executeDefine();
|
||||
void executeDelbreakif();
|
||||
void executeDelbreakif();
|
||||
void executeDelfunction();
|
||||
void executeDeltrap();
|
||||
void executeDelwatch();
|
||||
void executeDisasm();
|
||||
void executeDump();
|
||||
|
@ -184,9 +196,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, string command, bool cond = false);
|
||||
void executeTrapRW(uInt32 addr, bool read, bool write, bool add = true); // not exposed by debugger
|
||||
void executeType();
|
||||
void executeUHex();
|
||||
void executeUndef();
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef TRAP_ARRAY_HXX
|
||||
#define TRAP_ARRAY_HXX
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
||||
class TrapArray
|
||||
{
|
||||
public:
|
||||
TrapArray() : myInitialized(false) {}
|
||||
|
||||
bool isSet(const uInt16 address) const { return myCount[address]; }
|
||||
bool isClear(const uInt16 address) const { return myCount[address] == 0; }
|
||||
|
||||
void add(const uInt16 address) { myCount[address]++; }
|
||||
void remove(const uInt16 address) { myCount[address]--; }
|
||||
//void toggle(uInt16 address) { myCount[address] ? remove(address) : add(address); } // TODO condition
|
||||
|
||||
void initialize() {
|
||||
if(!myInitialized)
|
||||
memset(myCount, 0, sizeof(myCount));
|
||||
myInitialized = true;
|
||||
}
|
||||
void clearAll() { myInitialized = false; memset(myCount, 0, sizeof(myCount)); }
|
||||
|
||||
bool isInitialized() const { return myInitialized; }
|
||||
|
||||
private:
|
||||
// The actual counts
|
||||
uInt8 myCount[0x10000];
|
||||
|
||||
// Indicates whether we should treat this array as initialized
|
||||
bool myInitialized;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
TrapArray(const TrapArray&) = delete;
|
||||
TrapArray(TrapArray&&) = delete;
|
||||
TrapArray& operator=(const TrapArray&) = delete;
|
||||
TrapArray& operator=(TrapArray&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -55,6 +55,8 @@ M6502::M6502(const Settings& settings)
|
|||
myLastAddress(0),
|
||||
myLastPeekAddress(0),
|
||||
myLastPokeAddress(0),
|
||||
myLastPeekBaseAddress(0),
|
||||
myLastPokeBaseAddress(0),
|
||||
myLastSrcAddressS(-1),
|
||||
myLastSrcAddressA(-1),
|
||||
myLastSrcAddressX(-1),
|
||||
|
@ -65,7 +67,7 @@ M6502::M6502(const Settings& settings)
|
|||
{
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
myDebugger = nullptr;
|
||||
myJustHitTrapFlag = false;
|
||||
myJustHitReadTrapFlag = myJustHitWriteTrapFlag = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -98,7 +100,7 @@ void M6502::reset()
|
|||
// Load PC from the reset vector
|
||||
PC = uInt16(mySystem->peek(0xfffc)) | (uInt16(mySystem->peek(0xfffd)) << 8);
|
||||
|
||||
myLastAddress = myLastPeekAddress = myLastPokeAddress = 0;
|
||||
myLastAddress = myLastPeekAddress = myLastPokeAddress = myLastPeekBaseAddress = myLastPokeBaseAddress;
|
||||
myLastSrcAddressS = myLastSrcAddressA =
|
||||
myLastSrcAddressX = myLastSrcAddressY = -1;
|
||||
myDataAddressForPoke = 0;
|
||||
|
@ -120,18 +122,23 @@ inline uInt8 M6502::peek(uInt16 address, uInt8 flags)
|
|||
}
|
||||
////////////////////////////////////////////////
|
||||
mySystem->incrementCycles(SYSTEM_CYCLES_PER_CPU);
|
||||
uInt8 result = mySystem->peek(address, flags);
|
||||
myLastPeekAddress = address;
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
if(myReadTraps.isInitialized() && myReadTraps.isSet(address))
|
||||
{
|
||||
myJustHitTrapFlag = true;
|
||||
myHitTrapInfo.message = "RTrap: ";
|
||||
myHitTrapInfo.address = address;
|
||||
myLastPeekBaseAddress = myDebugger->getBaseAddress(myLastPeekAddress, true); // mirror handling
|
||||
int cond = evalCondTraps();
|
||||
if(cond > -1)
|
||||
{
|
||||
myJustHitReadTrapFlag = true;
|
||||
myHitTrapInfo.message = "RTrap(" + myTrapCondNames[cond] + "): ";
|
||||
myHitTrapInfo.address = address;
|
||||
}
|
||||
}
|
||||
#endif // DEBUGGER_SUPPORT
|
||||
|
||||
uInt8 result = mySystem->peek(address, flags);
|
||||
myLastPeekAddress = address;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -146,19 +153,23 @@ inline void M6502::poke(uInt16 address, uInt8 value, uInt8 flags)
|
|||
myLastAddress = address;
|
||||
}
|
||||
////////////////////////////////////////////////
|
||||
mySystem->incrementCycles(SYSTEM_CYCLES_PER_CPU);
|
||||
mySystem->incrementCycles(SYSTEM_CYCLES_PER_CPU);
|
||||
mySystem->poke(address, value, flags);
|
||||
myLastPokeAddress = address;
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
if(myWriteTraps.isInitialized() && myWriteTraps.isSet(address))
|
||||
{
|
||||
myJustHitTrapFlag = true;
|
||||
myHitTrapInfo.message = "WTrap: ";
|
||||
myHitTrapInfo.address = address;
|
||||
myLastPokeBaseAddress = myDebugger->getBaseAddress(myLastPokeAddress, false); // mirror handling
|
||||
int cond = evalCondTraps();
|
||||
if(cond > -1)
|
||||
{
|
||||
myJustHitWriteTrapFlag = true;
|
||||
myHitTrapInfo.message = "WTrap(" + myTrapCondNames[cond] + "): ";
|
||||
myHitTrapInfo.address = address;
|
||||
}
|
||||
}
|
||||
#endif // DEBUGGER_SUPPORT
|
||||
|
||||
mySystem->poke(address, value, flags);
|
||||
myLastPokeAddress = address;
|
||||
#endif // DEBUGGER_SUPPORT
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -189,11 +200,11 @@ bool M6502::execute(uInt32 number)
|
|||
for(; !myExecutionStatus && (number != 0); --number)
|
||||
{
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
if(myJustHitTrapFlag)
|
||||
if(myJustHitReadTrapFlag || myJustHitWriteTrapFlag)
|
||||
{
|
||||
if(myDebugger && myDebugger->start(myHitTrapInfo.message, myHitTrapInfo.address))
|
||||
{
|
||||
myJustHitTrapFlag = false;
|
||||
myJustHitReadTrapFlag = myJustHitWriteTrapFlag = false;
|
||||
if(myDebugger && myDebugger->start(myHitTrapInfo.message, myHitTrapInfo.address, myJustHitReadTrapFlag))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -416,13 +427,15 @@ uInt32 M6502::addCondBreak(Expression* e, const string& name)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void M6502::delCondBreak(uInt32 brk)
|
||||
bool M6502::delCondBreak(uInt32 brk)
|
||||
{
|
||||
if(brk < myBreakConds.size())
|
||||
{
|
||||
Vec::removeAt(myBreakConds, brk);
|
||||
Vec::removeAt(myBreakCondNames, brk);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -437,4 +450,37 @@ 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);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool M6502::delCondTrap(uInt32 brk)
|
||||
{
|
||||
if(brk < myTrapConds.size())
|
||||
{
|
||||
Vec::removeAt(myTrapConds, brk);
|
||||
Vec::removeAt(myTrapCondNames, brk);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void M6502::clearCondTraps()
|
||||
{
|
||||
myTrapConds.clear();
|
||||
myTrapCondNames.clear();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const StringList& M6502::getCondTrapNames() const
|
||||
{
|
||||
return myTrapCondNames;
|
||||
}
|
||||
#endif // DEBUGGER_SUPPORT
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "Expression.hxx"
|
||||
#include "PackedBitArray.hxx"
|
||||
#include "TrapArray.hxx"
|
||||
#endif
|
||||
|
||||
class Settings;
|
||||
|
@ -148,7 +149,21 @@ class M6502 : public Serializable
|
|||
return myLastPokeAddress ?
|
||||
(myLastPokeAddress != myLastPeekAddress ? myLastPeekAddress : 0) :
|
||||
myLastPeekAddress;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Return the last address that was part of a read/peek.
|
||||
|
||||
@return The address of the last read
|
||||
*/
|
||||
uInt16 lastReadBaseAddress() const { return myLastPeekBaseAddress; }
|
||||
|
||||
/**
|
||||
Return the last address that was part of a write/poke.
|
||||
|
||||
@return The address of the last write
|
||||
*/
|
||||
uInt16 lastWriteBaseAddress() const { return myLastPokeBaseAddress; }
|
||||
|
||||
/**
|
||||
Return the source of the address that was used for a write/poke.
|
||||
|
@ -207,13 +222,24 @@ 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; }
|
||||
|
||||
// methods for 'breakif' handling
|
||||
uInt32 addCondBreak(Expression* e, const string& name);
|
||||
void delCondBreak(uInt32 brk);
|
||||
bool delCondBreak(uInt32 brk);
|
||||
void clearCondBreaks();
|
||||
const StringList& getCondBreakNames() const;
|
||||
|
||||
// methods for 'trapif' handling
|
||||
uInt32 addCondTrap(Expression* e, const string& name);
|
||||
bool delCondTrap(uInt32 brk);
|
||||
void clearCondTraps();
|
||||
const StringList& getCondTrapNames() const;
|
||||
#endif // DEBUGGER_SUPPORT
|
||||
|
||||
private:
|
||||
|
@ -329,6 +355,9 @@ class M6502 : public Serializable
|
|||
/// Indicates the last address which was accessed specifically
|
||||
/// by a peek or poke command
|
||||
uInt16 myLastPeekAddress, myLastPokeAddress;
|
||||
/// Indicates the last base (= non-mirrored) address which was
|
||||
/// accessed specifically by a peek or poke command
|
||||
uInt16 myLastPeekBaseAddress, myLastPokeBaseAddress;
|
||||
|
||||
/// Indicates the last address used to access data by a peek command
|
||||
/// for the CPU registers (S/A/X/Y)
|
||||
|
@ -359,14 +388,25 @@ 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;
|
||||
bool myJustHitReadTrapFlag;
|
||||
bool myJustHitWriteTrapFlag;
|
||||
struct HitTrapInfo {
|
||||
string message;
|
||||
int address;
|
||||
|
@ -375,6 +415,8 @@ class M6502 : public Serializable
|
|||
|
||||
vector<unique_ptr<Expression>> myBreakConds;
|
||||
StringList myBreakCondNames;
|
||||
vector<unique_ptr<Expression>> myTrapConds;
|
||||
StringList myTrapCondNames;
|
||||
#endif // DEBUGGER_SUPPORT
|
||||
|
||||
private:
|
||||
|
|
|
@ -575,6 +575,7 @@
|
|||
<ClInclude Include="..\debugger\gui\RomListSettings.hxx" />
|
||||
<ClInclude Include="..\debugger\gui\SaveKeyWidget.hxx" />
|
||||
<ClInclude Include="..\debugger\gui\TrakBallWidget.hxx" />
|
||||
<ClInclude Include="..\debugger\TrapArray.hxx" />
|
||||
<ClInclude Include="..\emucore\AmigaMouse.hxx" />
|
||||
<ClInclude Include="..\emucore\AtariMouse.hxx" />
|
||||
<ClInclude Include="..\emucore\BSType.hxx" />
|
||||
|
|
|
@ -1751,6 +1751,9 @@
|
|||
<ClInclude Include="..\debugger\gui\TrakBallWidget.hxx">
|
||||
<Filter>Header Files\debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\debugger\TrapArray.hxx">
|
||||
<Filter>Header Files\debugger</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="stella.ico">
|
||||
|
|
|
@ -206,6 +206,10 @@ CartMethod getCartSpecial(char* ch)
|
|||
return &CartDebug::getBank;
|
||||
else if(BSPF::equalsIgnoreCase(ch, "_rwport"))
|
||||
return &CartDebug::readFromWritePort;
|
||||
else if(BSPF::equalsIgnoreCase(ch, "__lastread"))
|
||||
return &CartDebug::lastReadBaseAddress;
|
||||
else if(BSPF::equalsIgnoreCase(ch, "__lastwrite"))
|
||||
return &CartDebug::lastWriteBaseAddress;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue