mirror of https://github.com/stella-emu/stella.git
add option to break on RAM writes to read ports
This commit is contained in:
parent
4b0f255b8d
commit
9a44366f85
|
@ -31,7 +31,8 @@ Cartridge::Cartridge(const Settings& settings, const string& md5)
|
|||
myBankChanged(true),
|
||||
myCodeAccessBase(nullptr),
|
||||
myStartBank(0),
|
||||
myBankLocked(false)
|
||||
myBankLocked(false),
|
||||
myRamWriteAccess(0)
|
||||
{
|
||||
auto to_uInt32 = [](const string& s, uInt32 pos) {
|
||||
return uInt32(std::stoul(s.substr(pos, 8), nullptr, 16));
|
||||
|
|
|
@ -111,18 +111,30 @@ class Cartridge : public Device
|
|||
To be called at the start of each instruction.
|
||||
Clears information about all accesses to cart RAM.
|
||||
*/
|
||||
void clearAllRAMAccesses() { myRAMAccesses.clear(); }
|
||||
void clearAllRAMAccesses() {
|
||||
myRAMAccesses.clear();
|
||||
myRamWriteAccess = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
To be called at the end of each instruction.
|
||||
Answers whether an access in the last instruction cycle generated
|
||||
an illegal RAM access.
|
||||
an illegal read RAM access.
|
||||
|
||||
@return Address of illegal access if one occurred, else 0
|
||||
*/
|
||||
uInt16 getIllegalRAMAccess() const {
|
||||
uInt16 getIllegalRAMReadAccess() const {
|
||||
return myRAMAccesses.size() > 0 ? myRAMAccesses[0] : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
To be called at the end of each instruction.
|
||||
Answers whether an access in the last instruction cycle generated
|
||||
an illegal RAM write access.
|
||||
|
||||
@return Address of illegal access if one occurred, else 0
|
||||
*/
|
||||
uInt16 getIllegalRAMWriteAccess() const { return myRamWriteAccess; }
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
@ -315,6 +327,9 @@ class Cartridge : public Device
|
|||
// whether it is used as code.
|
||||
ByteBuffer myCodeAccessBase;
|
||||
|
||||
// Contains address of illegal RAM write access or 0
|
||||
uInt16 myRamWriteAccess;
|
||||
|
||||
private:
|
||||
// The startup bank to use (where to look for the reset vector address)
|
||||
uInt16 myStartBank;
|
||||
|
|
|
@ -121,12 +121,12 @@ bool Cartridge3E::poke(uInt16 address, uInt8 value)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Writing to the read port should be ignored, but (TODO) trigger a break if option enabled
|
||||
// Writing to the read port should be ignored, but trigger a break if option enabled
|
||||
uInt8 dummy;
|
||||
|
||||
pokeRAM(dummy, pokeAddress, value);
|
||||
myRamWriteAccess = pokeAddress;
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,10 +90,11 @@ bool Cartridge4KSC::poke(uInt16 address, uInt8 value)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Writing to the read port should be ignored, but (TODO) trigger a break if option enabled
|
||||
// Writing to the read port should be ignored, but trigger a break if option enabled
|
||||
uInt8 dummy;
|
||||
|
||||
pokeRAM(dummy, address, value);
|
||||
myRamWriteAccess = address;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,10 +105,11 @@ bool CartridgeBFSC::poke(uInt16 address, uInt8 value)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Writing to the read port should be ignored, but (TODO) trigger a break if option enabled
|
||||
// Writing to the read port should be ignored, but trigger a break if option enabled
|
||||
uInt8 dummy;
|
||||
|
||||
pokeRAM(dummy, pokeAddress, value);
|
||||
myRamWriteAccess = pokeAddress;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,10 +105,11 @@ bool CartridgeDFSC::poke(uInt16 address, uInt8 value)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Writing to the read port should be ignored, but (TODO) trigger a break if option enabled
|
||||
// Writing to the read port should be ignored, but trigger a break if option enabled
|
||||
uInt8 dummy;
|
||||
|
||||
pokeRAM(dummy, pokeAddress, value);
|
||||
myRamWriteAccess = pokeAddress;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,10 +105,11 @@ bool CartridgeEFSC::poke(uInt16 address, uInt8 value)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Writing to the read port should be ignored, but (TODO) trigger a break if option enabled
|
||||
// Writing to the read port should be ignored, but trigger a break if option enabled
|
||||
uInt8 dummy;
|
||||
|
||||
pokeRAM(dummy, pokeAddress, value);
|
||||
myRamWriteAccess = pokeAddress;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,10 +105,11 @@ bool CartridgeF4SC::poke(uInt16 address, uInt8 value)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Writing to the read port should be ignored, but (TODO) trigger a break if option enabled
|
||||
// Writing to the read port should be ignored, but trigger a break if option enabled
|
||||
uInt8 dummy;
|
||||
|
||||
pokeRAM(dummy, pokeAddress, value);
|
||||
myRamWriteAccess = pokeAddress;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,10 +145,11 @@ bool CartridgeF6SC::poke(uInt16 address, uInt8 value)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Writing to the read port should be ignored, but (TODO) trigger a break if option enabled
|
||||
// Writing to the read port should be ignored, but trigger a break if option enabled
|
||||
uInt8 dummy;
|
||||
|
||||
pokeRAM(dummy, address, value);
|
||||
myRamWriteAccess = address;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -125,10 +125,11 @@ bool CartridgeF8SC::poke(uInt16 address, uInt8 value)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Writing to the read port should be ignored, but (TODO) trigger a break if option enabled
|
||||
// Writing to the read port should be ignored, but trigger a break if option enabled
|
||||
uInt8 dummy;
|
||||
|
||||
pokeRAM(dummy, address, value);
|
||||
myRamWriteAccess = address;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,10 +135,11 @@ bool CartridgeFA::poke(uInt16 address, uInt8 value)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Writing to the read port should be ignored, but (TODO) trigger a break if option enabled
|
||||
// Writing to the read port should be ignored, but trigger a break if option enabled
|
||||
uInt8 dummy;
|
||||
|
||||
pokeRAM(dummy, address, value);
|
||||
myRamWriteAccess = address;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -202,10 +202,11 @@ bool CartridgeFA2::poke(uInt16 address, uInt8 value)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Writing to the read port should be ignored, but (TODO) trigger a break if option enabled
|
||||
// Writing to the read port should be ignored, but trigger a break if option enabled
|
||||
uInt8 dummy;
|
||||
|
||||
pokeRAM(dummy, address, value);
|
||||
myRamWriteAccess = address;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -137,10 +137,11 @@ bool CartridgeWD::poke(uInt16 address, uInt8 value)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Writing to the read port should be ignored, but (TODO) trigger a break if option enabled
|
||||
// Writing to the read port should be ignored, but trigger a break if option enabled
|
||||
uInt8 dummy;
|
||||
|
||||
pokeRAM(dummy, address, value);
|
||||
myRamWriteAccess = address;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,6 +76,7 @@ M6502::M6502(const Settings& settings)
|
|||
myHaltRequested(false),
|
||||
myGhostReadsTrap(false),
|
||||
myReadFromWritePortBreak(false),
|
||||
myWriteToReadPortBreak(false),
|
||||
myStepStateByInstruction(false)
|
||||
{
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
|
@ -125,6 +126,7 @@ void M6502::reset()
|
|||
myHaltRequested = false;
|
||||
myGhostReadsTrap = mySettings.getBool("dbg.ghostreadstrap");
|
||||
myReadFromWritePortBreak = devSettings ? mySettings.getBool("dev.rwportbreak") : false;
|
||||
myWriteToReadPortBreak = devSettings ? mySettings.getBool("dev.wrportbreak") : false;
|
||||
|
||||
myLastBreakCycle = ULLONG_MAX;
|
||||
}
|
||||
|
@ -354,7 +356,7 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
|
|||
#ifdef DEBUGGER_SUPPORT
|
||||
if(myReadFromWritePortBreak)
|
||||
{
|
||||
uInt16 rwpAddr = mySystem->cart().getIllegalRAMAccess();
|
||||
uInt16 rwpAddr = mySystem->cart().getIllegalRAMReadAccess();
|
||||
if(rwpAddr)
|
||||
{
|
||||
ostringstream msg;
|
||||
|
@ -363,6 +365,18 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (myWriteToReadPortBreak)
|
||||
{
|
||||
uInt16 wrpAddr = mySystem->cart().getIllegalRAMWriteAccess();
|
||||
if (wrpAddr)
|
||||
{
|
||||
ostringstream msg;
|
||||
msg << "WRP[@ $" << Common::Base::HEX4 << wrpAddr << "]: ";
|
||||
result.setDebugger(currentCycles, msg.str(), oldPC);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif // DEBUGGER_SUPPORT
|
||||
} catch (const FatalEmulationError& e) {
|
||||
myExecutionStatus |= FatalErrorBit;
|
||||
|
|
|
@ -237,6 +237,7 @@ class M6502 : public Serializable
|
|||
|
||||
void setGhostReadsTrap(bool enable) { myGhostReadsTrap = enable; }
|
||||
void setReadFromWritePortBreak(bool enable) { myReadFromWritePortBreak = enable; }
|
||||
void setWriteToReadPortBreak(bool enable) { myWriteToReadPortBreak = enable; }
|
||||
#endif // DEBUGGER_SUPPORT
|
||||
|
||||
private:
|
||||
|
@ -449,6 +450,7 @@ class M6502 : public Serializable
|
|||
|
||||
bool myGhostReadsTrap; // trap on ghost reads
|
||||
bool myReadFromWritePortBreak; // trap on reads from write ports
|
||||
bool myWriteToReadPortBreak; // trap on writes to read ports
|
||||
bool myStepStateByInstruction;
|
||||
|
||||
private:
|
||||
|
|
|
@ -162,6 +162,7 @@ Settings::Settings()
|
|||
setPermanent("dis.showaddr", "true");
|
||||
setPermanent("dis.relocate", "false");
|
||||
setPermanent("dev.rwportbreak", "true");
|
||||
setPermanent("dev.wrportbreak", "true");
|
||||
#endif
|
||||
|
||||
// Player settings
|
||||
|
|
|
@ -56,7 +56,7 @@ DeveloperDialog::DeveloperDialog(OSystem& osystem, DialogContainer& parent,
|
|||
int xpos, ypos;
|
||||
|
||||
// Set real dimensions
|
||||
setSize(54 * fontWidth + 10, 15 * (lineHeight + VGAP) + 14 + _th, max_w, max_h);
|
||||
setSize(54 * fontWidth + 10, 16 * (lineHeight + VGAP) + 14 + _th, max_w, max_h);
|
||||
|
||||
// The tab widget
|
||||
xpos = 2; ypos = 4;
|
||||
|
@ -159,6 +159,11 @@ void DeveloperDialog::addEmulationTab(const GUI::Font& font)
|
|||
"Break on reads from write ports");
|
||||
wid.push_back(myRWPortBreakWidget);
|
||||
ypos += lineHeight + VGAP;
|
||||
|
||||
myWRPortBreakWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1,
|
||||
"Break on writes to read ports");
|
||||
wid.push_back(myWRPortBreakWidget);
|
||||
ypos += lineHeight + VGAP;
|
||||
#endif
|
||||
|
||||
// Thumb ARM emulation exception
|
||||
|
@ -613,6 +618,8 @@ void DeveloperDialog::loadSettings(SettingsSet set)
|
|||
#ifdef DEBUGGER_SUPPORT
|
||||
// Read from write ports break
|
||||
myRWPortBreak[set] = devSettings ? instance().settings().getBool("dev.rwportbreak") : false;
|
||||
// Write to read ports break
|
||||
myWRPortBreak[set] = devSettings ? instance().settings().getBool("dev.wrportbreak") : false;
|
||||
#endif
|
||||
// Thumb ARM emulation exception
|
||||
myThumbException[set] = devSettings ? instance().settings().getBool("dev.thumb.trapfatal") : false;
|
||||
|
@ -666,9 +673,13 @@ void DeveloperDialog::saveSettings(SettingsSet set)
|
|||
if(devSettings)
|
||||
instance().settings().setValue("dev.tiadriven", myUndrivenPins[set]);
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
if(devSettings)
|
||||
if (devSettings)
|
||||
{
|
||||
// Read from write ports break
|
||||
instance().settings().setValue("dev.rwportbreak", myRWPortBreak[set]);
|
||||
// Write to read ports break
|
||||
instance().settings().setValue("dev.wrportbreak", myWRPortBreak[set]);
|
||||
}
|
||||
#endif
|
||||
if(devSettings)
|
||||
// Thumb ARM emulation exception
|
||||
|
@ -727,6 +738,7 @@ void DeveloperDialog::getWidgetStates(SettingsSet set)
|
|||
#ifdef DEBUGGER_SUPPORT
|
||||
// Read from write ports break
|
||||
myRWPortBreak[set] = myRWPortBreakWidget->getState();
|
||||
myWRPortBreak[set] = myWRPortBreakWidget->getState();
|
||||
#endif
|
||||
// Thumb ARM emulation exception
|
||||
myThumbException[set] = myThumbExceptionWidget->getState();
|
||||
|
@ -778,6 +790,7 @@ void DeveloperDialog::setWidgetStates(SettingsSet set)
|
|||
#ifdef DEBUGGER_SUPPORT
|
||||
// Read from write ports break
|
||||
myRWPortBreakWidget->setState(myRWPortBreak[set]);
|
||||
myWRPortBreakWidget->setState(myWRPortBreak[set]);
|
||||
#endif
|
||||
// Thumb ARM emulation exception
|
||||
myThumbExceptionWidget->setState(myThumbException[set]);
|
||||
|
@ -934,9 +947,12 @@ void DeveloperDialog::saveConfig()
|
|||
if(instance().hasConsole())
|
||||
instance().console().system().m6502().setGhostReadsTrap(myGhostReadsTrapWidget->getState());
|
||||
|
||||
// Read from write ports break
|
||||
if(instance().hasConsole())
|
||||
// Read from write ports and write to read ports breaks
|
||||
if (instance().hasConsole())
|
||||
{
|
||||
instance().console().system().m6502().setReadFromWritePortBreak(myRWPortBreakWidget->getState());
|
||||
instance().console().system().m6502().setWriteToReadPortBreak(myWRPortBreakWidget->getState());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -960,6 +976,7 @@ void DeveloperDialog::setDefaults()
|
|||
#ifdef DEBUGGER_SUPPORT
|
||||
// Reads from write ports
|
||||
myRWPortBreak[set] = devSettings ? true : false;
|
||||
myWRPortBreak[set] = devSettings ? true : false;
|
||||
#endif
|
||||
// Thumb ARM emulation exception
|
||||
myThumbException[set] = devSettings ? true : false;
|
||||
|
@ -1137,6 +1154,7 @@ void DeveloperDialog::handleSettings(bool devSettings)
|
|||
myUndrivenPinsWidget->setEnabled(devSettings);
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
myRWPortBreakWidget->setEnabled(devSettings);
|
||||
myWRPortBreakWidget->setEnabled(devSettings);
|
||||
#endif
|
||||
myThumbExceptionWidget->setEnabled(devSettings);
|
||||
|
||||
|
|
|
@ -99,6 +99,7 @@ class DeveloperDialog : public Dialog
|
|||
CheckboxWidget* myUndrivenPinsWidget;
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
CheckboxWidget* myRWPortBreakWidget;
|
||||
CheckboxWidget* myWRPortBreakWidget;
|
||||
#endif
|
||||
CheckboxWidget* myThumbExceptionWidget;
|
||||
CheckboxWidget* myEEPROMAccessWidget;
|
||||
|
@ -159,6 +160,7 @@ class DeveloperDialog : public Dialog
|
|||
bool myUndrivenPins[2];
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
bool myRWPortBreak[2];
|
||||
bool myWRPortBreak[2];
|
||||
#endif
|
||||
bool myThumbException[2];
|
||||
bool myEEPROMAccess[2];
|
||||
|
|
Loading…
Reference in New Issue