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 "Cart.hxx"
|
||||||
#include "DebuggerSystem.hxx"
|
#include "DebuggerSystem.hxx"
|
||||||
#include "System.hxx"
|
#include "System.hxx"
|
||||||
|
#include "M6502.hxx"
|
||||||
|
|
||||||
// Function type for CartDebug instance methods
|
// Function type for CartDebug instance methods
|
||||||
class CartDebug;
|
class CartDebug;
|
||||||
|
@ -127,6 +128,11 @@ class CartDebug : public DebuggerSystem
|
||||||
// write port area.
|
// write port area.
|
||||||
int readFromWritePort();
|
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
|
// The following two methods are meant to be used together
|
||||||
// First, a call is made to disassemble(), which updates the disassembly
|
// First, a call is made to disassemble(), which updates the disassembly
|
||||||
// list; it will figure out when an actual complete disassembly is
|
// 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)" },
|
{ "_diff0a", "*SWCHB & $40", "Left diff. set to A (hard)" },
|
||||||
{ "_diff1b", "!(*SWCHB & $80)", "Right diff. set to B (easy)" },
|
{ "_diff1b", "!(*SWCHB & $80)", "Right diff. set to B (easy)" },
|
||||||
{ "_diff1a", "*SWCHB & $80", "Right diff. set to A (hard)" },
|
{ "_diff1a", "*SWCHB & $80", "Right diff. set to A (hard)" },
|
||||||
|
|
||||||
// empty string marks end of list, do not remove
|
// empty string marks end of list, do not remove
|
||||||
{ 0, 0, 0 }
|
{ 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" },
|
{ "_rwport", "Address at which a read from a write port occurred" },
|
||||||
{ "_scan", "Current scanline count" },
|
{ "_scan", "Current scanline count" },
|
||||||
{ "_vblank", "Whether vertical blank is enabled (1 or 0)" },
|
{ "_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
|
// empty string marks end of list, do not remove
|
||||||
{ 0, 0 }
|
{ 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())
|
if(myOSystem.eventHandler().enterDebugMode())
|
||||||
{
|
{
|
||||||
|
@ -175,8 +177,7 @@ bool Debugger::start(const string& message, int address)
|
||||||
ostringstream buf;
|
ostringstream buf;
|
||||||
buf << message;
|
buf << message;
|
||||||
if(address > -1)
|
if(address > -1)
|
||||||
buf << Common::Base::HEX4 << address;
|
buf << cartDebug().getLabel(address, read);
|
||||||
|
|
||||||
myDialog->message().setText(buf.str());
|
myDialog->message().setText(buf.str());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -367,24 +368,43 @@ bool Debugger::breakPoint(uInt16 bp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Debugger::toggleReadTrap(uInt16 t)
|
void Debugger::addReadTrap(uInt16 t)
|
||||||
{
|
{
|
||||||
readTraps().initialize();
|
readTraps().initialize();
|
||||||
readTraps().toggle(t);
|
readTraps().add(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
void Debugger::addWriteTrap(uInt16 t)
|
||||||
void Debugger::toggleWriteTrap(uInt16 t)
|
|
||||||
{
|
{
|
||||||
writeTraps().initialize();
|
writeTraps().initialize();
|
||||||
writeTraps().toggle(t);
|
writeTraps().add(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Debugger::toggleTrap(uInt16 t)
|
void Debugger::addTrap(uInt16 t)
|
||||||
{
|
{
|
||||||
toggleReadTrap(t);
|
addReadTrap(t);
|
||||||
toggleWriteTrap(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);
|
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)
|
void Debugger::nextScanline(int lines)
|
||||||
|
|
|
@ -88,7 +88,7 @@ class Debugger : public DialogContainer
|
||||||
@param message Message to display when entering debugger
|
@param message Message to display when entering debugger
|
||||||
@param address An address associated with the message
|
@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 = "");
|
bool startWithFatalError(const string& message = "");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -145,8 +145,8 @@ class Debugger : public DialogContainer
|
||||||
TiaOutputWidget& tiaOutput() const { return myDialog->tiaOutput(); }
|
TiaOutputWidget& tiaOutput() const { return myDialog->tiaOutput(); }
|
||||||
|
|
||||||
PackedBitArray& breakPoints() const { return mySystem.m6502().breakPoints(); }
|
PackedBitArray& breakPoints() const { return mySystem.m6502().breakPoints(); }
|
||||||
PackedBitArray& readTraps() const { return mySystem.m6502().readTraps(); }
|
TrapArray& readTraps() const { return mySystem.m6502().readTraps(); }
|
||||||
PackedBitArray& writeTraps() const { return mySystem.m6502().writeTraps(); }
|
TrapArray& writeTraps() const { return mySystem.m6502().writeTraps(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Run the debugger command and return the result.
|
Run the debugger command and return the result.
|
||||||
|
@ -214,6 +214,7 @@ class Debugger : public DialogContainer
|
||||||
{ mySystem.setAccessFlags(addr, flags); }
|
{ mySystem.setAccessFlags(addr, flags); }
|
||||||
|
|
||||||
void setBreakPoint(uInt16 bp, bool set);
|
void setBreakPoint(uInt16 bp, bool set);
|
||||||
|
uInt32 getBaseAddress(uInt32 addr, bool read);
|
||||||
|
|
||||||
bool patchROM(uInt16 addr, uInt8 value);
|
bool patchROM(uInt16 addr, uInt8 value);
|
||||||
|
|
||||||
|
@ -256,9 +257,12 @@ class Debugger : public DialogContainer
|
||||||
void toggleBreakPoint(uInt16 bp);
|
void toggleBreakPoint(uInt16 bp);
|
||||||
|
|
||||||
bool breakPoint(uInt16 bp);
|
bool breakPoint(uInt16 bp);
|
||||||
void toggleReadTrap(uInt16 t);
|
void addReadTrap(uInt16 t);
|
||||||
void toggleWriteTrap(uInt16 t);
|
void addWriteTrap(uInt16 t);
|
||||||
void toggleTrap(uInt16 t);
|
void addTrap(uInt16 t);
|
||||||
|
void removeReadTrap(uInt16 t);
|
||||||
|
void removeWriteTrap(uInt16 t);
|
||||||
|
void removeTrap(uInt16 t);
|
||||||
bool readTrap(uInt16 t);
|
bool readTrap(uInt16 t);
|
||||||
bool writeTrap(uInt16 t);
|
bool writeTrap(uInt16 t);
|
||||||
void clearAllTraps();
|
void clearAllTraps();
|
||||||
|
|
|
@ -543,31 +543,32 @@ string DebuggerParser::eval()
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
string DebuggerParser::trapStatus(uInt32 addr, bool& enabled)
|
string DebuggerParser::trapStatus(const Trap& trap)
|
||||||
{
|
{
|
||||||
string result;
|
stringstream result;
|
||||||
result += Base::toString(addr);
|
string lblb = debugger.cartDebug().getLabel(trap.begin, !trap.write);
|
||||||
result += ": ";
|
string lble = debugger.cartDebug().getLabel(trap.end, !trap.write);
|
||||||
bool r = debugger.readTrap(addr);
|
|
||||||
bool w = debugger.writeTrap(addr);
|
if(lblb != "") {
|
||||||
enabled = r || w;
|
result << " (";
|
||||||
if(r && w)
|
result << lblb;
|
||||||
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 += ")";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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))
|
if(debugger.breakPoint(i))
|
||||||
out << "break #" << i << endl;
|
out << "break #" << i << endl;
|
||||||
|
|
||||||
|
// TODO: new trapif
|
||||||
for(uInt32 i = 0; i < 0x10000; ++i)
|
for(uInt32 i = 0; i < 0x10000; ++i)
|
||||||
{
|
{
|
||||||
bool r = debugger.readTrap(i);
|
bool r = debugger.readTrap(i);
|
||||||
bool w = debugger.writeTrap(i);
|
bool w = debugger.writeTrap(i);
|
||||||
|
|
||||||
if(r && w)
|
if(r && w)
|
||||||
|
@ -744,8 +746,9 @@ void DebuggerParser::executeClearconfig()
|
||||||
// "cleartraps"
|
// "cleartraps"
|
||||||
void DebuggerParser::executeCleartraps()
|
void DebuggerParser::executeCleartraps()
|
||||||
{
|
{
|
||||||
myTraps.clear();
|
|
||||||
debugger.clearAllTraps();
|
debugger.clearAllTraps();
|
||||||
|
debugger.cpuDebug().m6502().clearCondTraps();
|
||||||
|
myTraps.clear();
|
||||||
commandResult << "all traps cleared";
|
commandResult << "all traps cleared";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -861,6 +864,24 @@ void DebuggerParser::executeDelfunction()
|
||||||
commandResult << "function " << argStrings[0] << " built-in or not found";
|
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"
|
// "delwatch"
|
||||||
void DebuggerParser::executeDelwatch()
|
void DebuggerParser::executeDelwatch()
|
||||||
|
@ -1089,7 +1110,7 @@ void DebuggerParser::executeListbreaks()
|
||||||
commandResult << "\nbreakifs:\n";
|
commandResult << "\nbreakifs:\n";
|
||||||
for(uInt32 i = 0; i < conds.size(); i++)
|
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;
|
if(i != (conds.size() - 1)) commandResult << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1127,11 +1148,37 @@ void DebuggerParser::executeListfunctions()
|
||||||
// "listtraps"
|
// "listtraps"
|
||||||
void DebuggerParser::executeListtraps()
|
void DebuggerParser::executeListtraps()
|
||||||
{
|
{
|
||||||
if(myTraps.size() > 0)
|
StringList names = debugger.cpuDebug().m6502().getCondTrapNames();
|
||||||
|
|
||||||
|
if(myTraps.size() != names.size())
|
||||||
{
|
{
|
||||||
bool enabled = true;
|
commandResult << "Internal error! Different trap sizes.";
|
||||||
for(const auto& trap: myTraps)
|
return;
|
||||||
commandResult << trapStatus(trap, enabled) << " + mirrors" << endl;
|
}
|
||||||
|
|
||||||
|
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
|
else
|
||||||
commandResult << "no traps set";
|
commandResult << "no traps set";
|
||||||
|
@ -1482,71 +1529,153 @@ void DebuggerParser::executeTrace()
|
||||||
// "trap"
|
// "trap"
|
||||||
void DebuggerParser::executeTrap()
|
void DebuggerParser::executeTrap()
|
||||||
{
|
{
|
||||||
if(argCount > 2)
|
executeTraps(true, true, "trap");
|
||||||
{
|
}
|
||||||
commandResult << red("Command takes one or two arguments") << endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uInt32 beg = args[0];
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt32 end = argCount == 2 ? args[1] : beg;
|
// "trapif"
|
||||||
if(beg > 0xFFFF || end > 0xFFFF)
|
void DebuggerParser::executeTrapif()
|
||||||
{
|
{
|
||||||
commandResult << red("One or more addresses are invalid") << endl;
|
executeTraps(true, true, "trapif", true);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(uInt32 addr = beg; addr <= end; ++addr)
|
|
||||||
executeTrapRW(addr, true, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
// "trapread"
|
// "trapread"
|
||||||
void DebuggerParser::executeTrapread()
|
void DebuggerParser::executeTrapread()
|
||||||
{
|
{
|
||||||
if(argCount > 2)
|
executeTraps(true, false, "trapread");
|
||||||
{
|
}
|
||||||
commandResult << red("Command takes one or two arguments") << endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uInt32 beg = args[0];
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt32 end = argCount == 2 ? args[1] : beg;
|
// "trapreadif"
|
||||||
if(beg > 0xFFFF || end > 0xFFFF)
|
void DebuggerParser::executeTrapreadif()
|
||||||
{
|
{
|
||||||
commandResult << red("One or more addresses are invalid") << endl;
|
executeTraps(true, false, "trapreadif", true);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(uInt32 addr = beg; addr <= end; ++addr)
|
|
||||||
executeTrapRW(addr, true, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
// "trapwrite"
|
// "trapwrite"
|
||||||
void DebuggerParser::executeTrapwrite()
|
void DebuggerParser::executeTrapwrite()
|
||||||
{
|
{
|
||||||
if(argCount > 2)
|
executeTraps(false, true, "trapwrite");
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
// wrapper function for trap/trapread/trapwrite commands
|
// "trapwriteif"
|
||||||
void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
|
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))
|
switch(debugger.cartDebug().addressType(addr))
|
||||||
{
|
{
|
||||||
|
@ -1556,10 +1685,11 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
|
||||||
{
|
{
|
||||||
if((i & 0x1080) == 0x0000)
|
if((i & 0x1080) == 0x0000)
|
||||||
{
|
{
|
||||||
if(read && (i & 0x000F) == addr)
|
// @sa666666: This seems wrong. E.g. trapread 40 4f will never trigger
|
||||||
debugger.toggleReadTrap(i);
|
if(read && (i & 0x000F) == (addr & 0x000F))
|
||||||
if(write && (i & 0x003F) == addr)
|
add ? debugger.addReadTrap(i) : debugger.removeReadTrap(i);
|
||||||
debugger.toggleWriteTrap(i);
|
if(write && (i & 0x003F) == (addr & 0x003F))
|
||||||
|
add ? debugger.addWriteTrap(i) : debugger.removeWriteTrap(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1568,10 +1698,12 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
|
||||||
{
|
{
|
||||||
for(uInt32 i = 0; i <= 0xFFFF; ++i)
|
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(read)
|
||||||
if(write) debugger.toggleWriteTrap(i);
|
add ? debugger.addReadTrap(i) : debugger.removeReadTrap(i);
|
||||||
|
if(write)
|
||||||
|
add ? debugger.addWriteTrap(i) : debugger.removeWriteTrap(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1580,10 +1712,12 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
|
||||||
{
|
{
|
||||||
for(uInt32 i = 0; i <= 0xFFFF; ++i)
|
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(read)
|
||||||
if(write) debugger.toggleWriteTrap(i);
|
add ? debugger.addReadTrap(i) : debugger.removeReadTrap(i);
|
||||||
|
if(write)
|
||||||
|
add ? debugger.addWriteTrap(i) : debugger.removeWriteTrap(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1596,21 +1730,16 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
|
||||||
{
|
{
|
||||||
if((i % 0x2000 >= 0x1000) && (i & 0x0FFF) == (addr & 0x0FFF))
|
if((i % 0x2000 >= 0x1000) && (i & 0x0FFF) == (addr & 0x0FFF))
|
||||||
{
|
{
|
||||||
if(read) debugger.toggleReadTrap(i);
|
if(read)
|
||||||
if(write) debugger.toggleWriteTrap(i);
|
add ? debugger.addReadTrap(i) : debugger.removeReadTrap(i);
|
||||||
|
if(write)
|
||||||
|
add ? debugger.addWriteTrap(i) : debugger.removeWriteTrap(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
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)
|
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",
|
"delwatch",
|
||||||
"Delete watch <xx>",
|
"Delete watch <xx>",
|
||||||
|
@ -2333,6 +2472,17 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||||
std::mem_fn(&DebuggerParser::executeTrap)
|
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",
|
"trapread",
|
||||||
"Trap read access to address(es) xx [yy]",
|
"Trap read access to address(es) xx [yy]",
|
||||||
|
@ -2344,6 +2494,17 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||||
std::mem_fn(&DebuggerParser::executeTrapread)
|
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",
|
"trapwrite",
|
||||||
"Trap write access to address(es) xx [yy]",
|
"Trap write access to address(es) xx [yy]",
|
||||||
|
@ -2355,6 +2516,17 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||||
std::mem_fn(&DebuggerParser::executeTrapwrite)
|
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",
|
"type",
|
||||||
"Show disassembly type for address xx [yy]",
|
"Show disassembly type for address xx [yy]",
|
||||||
|
|
|
@ -68,7 +68,7 @@ class DebuggerParser
|
||||||
bool saveScriptFile(string file);
|
bool saveScriptFile(string file);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum { kNumCommands = 72 };
|
enum { kNumCommands = 76 };
|
||||||
|
|
||||||
// Constants for argument processing
|
// Constants for argument processing
|
||||||
enum {
|
enum {
|
||||||
|
@ -100,7 +100,15 @@ class DebuggerParser
|
||||||
parameters parms[10];
|
parameters parms[10];
|
||||||
std::function<void (DebuggerParser*)> executor;
|
std::function<void (DebuggerParser*)> executor;
|
||||||
};
|
};
|
||||||
|
struct Trap
|
||||||
|
{
|
||||||
|
bool read;
|
||||||
|
bool write;
|
||||||
|
uInt32 begin;
|
||||||
|
uInt32 end;
|
||||||
|
string condition;
|
||||||
|
};
|
||||||
|
|
||||||
// Reference to our debugger object
|
// Reference to our debugger object
|
||||||
Debugger& debugger;
|
Debugger& debugger;
|
||||||
|
|
||||||
|
@ -117,9 +125,12 @@ class DebuggerParser
|
||||||
|
|
||||||
StringList myWatches;
|
StringList myWatches;
|
||||||
|
|
||||||
|
|
||||||
// Keep track of traps (read and/or write)
|
// Keep track of traps (read and/or write)
|
||||||
std::set<uInt32> myTraps;
|
vector<unique_ptr<Trap>> myTraps;
|
||||||
string trapStatus(uInt32 addr, bool& enabled);
|
/*std::set<uInt32> myTraps;
|
||||||
|
std::vector<uInt32> myTrapIfs;*/
|
||||||
|
string trapStatus(const Trap& trap);
|
||||||
|
|
||||||
// List of available command methods
|
// List of available command methods
|
||||||
void executeA();
|
void executeA();
|
||||||
|
@ -139,8 +150,9 @@ class DebuggerParser
|
||||||
void executeData();
|
void executeData();
|
||||||
void executeDebugColors();
|
void executeDebugColors();
|
||||||
void executeDefine();
|
void executeDefine();
|
||||||
void executeDelbreakif();
|
void executeDelbreakif();
|
||||||
void executeDelfunction();
|
void executeDelfunction();
|
||||||
|
void executeDeltrap();
|
||||||
void executeDelwatch();
|
void executeDelwatch();
|
||||||
void executeDisasm();
|
void executeDisasm();
|
||||||
void executeDump();
|
void executeDump();
|
||||||
|
@ -184,9 +196,13 @@ class DebuggerParser
|
||||||
void executeTia();
|
void executeTia();
|
||||||
void executeTrace();
|
void executeTrace();
|
||||||
void executeTrap();
|
void executeTrap();
|
||||||
|
void executeTrapif();
|
||||||
void executeTrapread();
|
void executeTrapread();
|
||||||
void executeTrapwrite();
|
void executeTrapreadif();
|
||||||
void executeTrapRW(uInt32 addr, bool read, bool write); // not exposed by debugger
|
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 executeType();
|
||||||
void executeUHex();
|
void executeUHex();
|
||||||
void executeUndef();
|
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),
|
myLastAddress(0),
|
||||||
myLastPeekAddress(0),
|
myLastPeekAddress(0),
|
||||||
myLastPokeAddress(0),
|
myLastPokeAddress(0),
|
||||||
|
myLastPeekBaseAddress(0),
|
||||||
|
myLastPokeBaseAddress(0),
|
||||||
myLastSrcAddressS(-1),
|
myLastSrcAddressS(-1),
|
||||||
myLastSrcAddressA(-1),
|
myLastSrcAddressA(-1),
|
||||||
myLastSrcAddressX(-1),
|
myLastSrcAddressX(-1),
|
||||||
|
@ -65,7 +67,7 @@ M6502::M6502(const Settings& settings)
|
||||||
{
|
{
|
||||||
#ifdef DEBUGGER_SUPPORT
|
#ifdef DEBUGGER_SUPPORT
|
||||||
myDebugger = nullptr;
|
myDebugger = nullptr;
|
||||||
myJustHitTrapFlag = false;
|
myJustHitReadTrapFlag = myJustHitWriteTrapFlag = false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +100,7 @@ void M6502::reset()
|
||||||
// Load PC from the reset vector
|
// Load PC from the reset vector
|
||||||
PC = uInt16(mySystem->peek(0xfffc)) | (uInt16(mySystem->peek(0xfffd)) << 8);
|
PC = uInt16(mySystem->peek(0xfffc)) | (uInt16(mySystem->peek(0xfffd)) << 8);
|
||||||
|
|
||||||
myLastAddress = myLastPeekAddress = myLastPokeAddress = 0;
|
myLastAddress = myLastPeekAddress = myLastPokeAddress = myLastPeekBaseAddress = myLastPokeBaseAddress;
|
||||||
myLastSrcAddressS = myLastSrcAddressA =
|
myLastSrcAddressS = myLastSrcAddressA =
|
||||||
myLastSrcAddressX = myLastSrcAddressY = -1;
|
myLastSrcAddressX = myLastSrcAddressY = -1;
|
||||||
myDataAddressForPoke = 0;
|
myDataAddressForPoke = 0;
|
||||||
|
@ -120,18 +122,23 @@ inline uInt8 M6502::peek(uInt16 address, uInt8 flags)
|
||||||
}
|
}
|
||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
mySystem->incrementCycles(SYSTEM_CYCLES_PER_CPU);
|
mySystem->incrementCycles(SYSTEM_CYCLES_PER_CPU);
|
||||||
|
uInt8 result = mySystem->peek(address, flags);
|
||||||
|
myLastPeekAddress = address;
|
||||||
|
|
||||||
#ifdef DEBUGGER_SUPPORT
|
#ifdef DEBUGGER_SUPPORT
|
||||||
if(myReadTraps.isInitialized() && myReadTraps.isSet(address))
|
if(myReadTraps.isInitialized() && myReadTraps.isSet(address))
|
||||||
{
|
{
|
||||||
myJustHitTrapFlag = true;
|
myLastPeekBaseAddress = myDebugger->getBaseAddress(myLastPeekAddress, true); // mirror handling
|
||||||
myHitTrapInfo.message = "RTrap: ";
|
int cond = evalCondTraps();
|
||||||
myHitTrapInfo.address = address;
|
if(cond > -1)
|
||||||
|
{
|
||||||
|
myJustHitReadTrapFlag = true;
|
||||||
|
myHitTrapInfo.message = "RTrap(" + myTrapCondNames[cond] + "): ";
|
||||||
|
myHitTrapInfo.address = address;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif // DEBUGGER_SUPPORT
|
#endif // DEBUGGER_SUPPORT
|
||||||
|
|
||||||
uInt8 result = mySystem->peek(address, flags);
|
|
||||||
myLastPeekAddress = address;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,19 +153,23 @@ inline void M6502::poke(uInt16 address, uInt8 value, uInt8 flags)
|
||||||
myLastAddress = address;
|
myLastAddress = address;
|
||||||
}
|
}
|
||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
mySystem->incrementCycles(SYSTEM_CYCLES_PER_CPU);
|
mySystem->incrementCycles(SYSTEM_CYCLES_PER_CPU);
|
||||||
|
mySystem->poke(address, value, flags);
|
||||||
|
myLastPokeAddress = address;
|
||||||
|
|
||||||
#ifdef DEBUGGER_SUPPORT
|
#ifdef DEBUGGER_SUPPORT
|
||||||
if(myWriteTraps.isInitialized() && myWriteTraps.isSet(address))
|
if(myWriteTraps.isInitialized() && myWriteTraps.isSet(address))
|
||||||
{
|
{
|
||||||
myJustHitTrapFlag = true;
|
myLastPokeBaseAddress = myDebugger->getBaseAddress(myLastPokeAddress, false); // mirror handling
|
||||||
myHitTrapInfo.message = "WTrap: ";
|
int cond = evalCondTraps();
|
||||||
myHitTrapInfo.address = address;
|
if(cond > -1)
|
||||||
|
{
|
||||||
|
myJustHitWriteTrapFlag = true;
|
||||||
|
myHitTrapInfo.message = "WTrap(" + myTrapCondNames[cond] + "): ";
|
||||||
|
myHitTrapInfo.address = address;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif // DEBUGGER_SUPPORT
|
#endif // DEBUGGER_SUPPORT
|
||||||
|
|
||||||
mySystem->poke(address, value, flags);
|
|
||||||
myLastPokeAddress = address;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -189,11 +200,11 @@ bool M6502::execute(uInt32 number)
|
||||||
for(; !myExecutionStatus && (number != 0); --number)
|
for(; !myExecutionStatus && (number != 0); --number)
|
||||||
{
|
{
|
||||||
#ifdef DEBUGGER_SUPPORT
|
#ifdef DEBUGGER_SUPPORT
|
||||||
if(myJustHitTrapFlag)
|
if(myJustHitReadTrapFlag || myJustHitWriteTrapFlag)
|
||||||
{
|
{
|
||||||
if(myDebugger && myDebugger->start(myHitTrapInfo.message, myHitTrapInfo.address))
|
myJustHitReadTrapFlag = myJustHitWriteTrapFlag = false;
|
||||||
{
|
if(myDebugger && myDebugger->start(myHitTrapInfo.message, myHitTrapInfo.address, myJustHitReadTrapFlag))
|
||||||
myJustHitTrapFlag = false;
|
{
|
||||||
return true;
|
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())
|
if(brk < myBreakConds.size())
|
||||||
{
|
{
|
||||||
Vec::removeAt(myBreakConds, brk);
|
Vec::removeAt(myBreakConds, brk);
|
||||||
Vec::removeAt(myBreakCondNames, brk);
|
Vec::removeAt(myBreakCondNames, brk);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -437,4 +450,37 @@ const StringList& M6502::getCondBreakNames() const
|
||||||
{
|
{
|
||||||
return myBreakCondNames;
|
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
|
#endif // DEBUGGER_SUPPORT
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include "Expression.hxx"
|
#include "Expression.hxx"
|
||||||
#include "PackedBitArray.hxx"
|
#include "PackedBitArray.hxx"
|
||||||
|
#include "TrapArray.hxx"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class Settings;
|
class Settings;
|
||||||
|
@ -148,7 +149,21 @@ class M6502 : public Serializable
|
||||||
return myLastPokeAddress ?
|
return myLastPokeAddress ?
|
||||||
(myLastPokeAddress != myLastPeekAddress ? myLastPeekAddress : 0) :
|
(myLastPokeAddress != myLastPeekAddress ? myLastPeekAddress : 0) :
|
||||||
myLastPeekAddress;
|
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.
|
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);
|
void attach(Debugger& debugger);
|
||||||
|
|
||||||
PackedBitArray& breakPoints() { return myBreakPoints; }
|
PackedBitArray& breakPoints() { return myBreakPoints; }
|
||||||
PackedBitArray& readTraps() { return myReadTraps; }
|
//PackedBitArray& readTraps() { return myReadTraps; }
|
||||||
PackedBitArray& writeTraps() { return myWriteTraps; }
|
//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);
|
uInt32 addCondBreak(Expression* e, const string& name);
|
||||||
void delCondBreak(uInt32 brk);
|
bool delCondBreak(uInt32 brk);
|
||||||
void clearCondBreaks();
|
void clearCondBreaks();
|
||||||
const StringList& getCondBreakNames() const;
|
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
|
#endif // DEBUGGER_SUPPORT
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -329,6 +355,9 @@ class M6502 : public Serializable
|
||||||
/// Indicates the last address which was accessed specifically
|
/// Indicates the last address which was accessed specifically
|
||||||
/// by a peek or poke command
|
/// by a peek or poke command
|
||||||
uInt16 myLastPeekAddress, myLastPokeAddress;
|
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
|
/// Indicates the last address used to access data by a peek command
|
||||||
/// for the CPU registers (S/A/X/Y)
|
/// for the CPU registers (S/A/X/Y)
|
||||||
|
@ -359,14 +388,25 @@ class M6502 : public Serializable
|
||||||
return -1; // no break hit
|
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
|
/// Pointer to the debugger for this processor or the null pointer
|
||||||
Debugger* myDebugger;
|
Debugger* myDebugger;
|
||||||
|
|
||||||
// Addresses for which the specified action should occur
|
// 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?
|
// Did we just now hit a trap?
|
||||||
bool myJustHitTrapFlag;
|
bool myJustHitReadTrapFlag;
|
||||||
|
bool myJustHitWriteTrapFlag;
|
||||||
struct HitTrapInfo {
|
struct HitTrapInfo {
|
||||||
string message;
|
string message;
|
||||||
int address;
|
int address;
|
||||||
|
@ -375,6 +415,8 @@ class M6502 : public Serializable
|
||||||
|
|
||||||
vector<unique_ptr<Expression>> myBreakConds;
|
vector<unique_ptr<Expression>> myBreakConds;
|
||||||
StringList myBreakCondNames;
|
StringList myBreakCondNames;
|
||||||
|
vector<unique_ptr<Expression>> myTrapConds;
|
||||||
|
StringList myTrapCondNames;
|
||||||
#endif // DEBUGGER_SUPPORT
|
#endif // DEBUGGER_SUPPORT
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -575,6 +575,7 @@
|
||||||
<ClInclude Include="..\debugger\gui\RomListSettings.hxx" />
|
<ClInclude Include="..\debugger\gui\RomListSettings.hxx" />
|
||||||
<ClInclude Include="..\debugger\gui\SaveKeyWidget.hxx" />
|
<ClInclude Include="..\debugger\gui\SaveKeyWidget.hxx" />
|
||||||
<ClInclude Include="..\debugger\gui\TrakBallWidget.hxx" />
|
<ClInclude Include="..\debugger\gui\TrakBallWidget.hxx" />
|
||||||
|
<ClInclude Include="..\debugger\TrapArray.hxx" />
|
||||||
<ClInclude Include="..\emucore\AmigaMouse.hxx" />
|
<ClInclude Include="..\emucore\AmigaMouse.hxx" />
|
||||||
<ClInclude Include="..\emucore\AtariMouse.hxx" />
|
<ClInclude Include="..\emucore\AtariMouse.hxx" />
|
||||||
<ClInclude Include="..\emucore\BSType.hxx" />
|
<ClInclude Include="..\emucore\BSType.hxx" />
|
||||||
|
|
|
@ -1751,6 +1751,9 @@
|
||||||
<ClInclude Include="..\debugger\gui\TrakBallWidget.hxx">
|
<ClInclude Include="..\debugger\gui\TrakBallWidget.hxx">
|
||||||
<Filter>Header Files\debugger</Filter>
|
<Filter>Header Files\debugger</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\debugger\TrapArray.hxx">
|
||||||
|
<Filter>Header Files\debugger</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="stella.ico">
|
<None Include="stella.ico">
|
||||||
|
|
|
@ -206,6 +206,10 @@ CartMethod getCartSpecial(char* ch)
|
||||||
return &CartDebug::getBank;
|
return &CartDebug::getBank;
|
||||||
else if(BSPF::equalsIgnoreCase(ch, "_rwport"))
|
else if(BSPF::equalsIgnoreCase(ch, "_rwport"))
|
||||||
return &CartDebug::readFromWritePort;
|
return &CartDebug::readFromWritePort;
|
||||||
|
else if(BSPF::equalsIgnoreCase(ch, "__lastread"))
|
||||||
|
return &CartDebug::lastReadBaseAddress;
|
||||||
|
else if(BSPF::equalsIgnoreCase(ch, "__lastwrite"))
|
||||||
|
return &CartDebug::lastWriteBaseAddress;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue