add option to break on RAM writes to read ports

This commit is contained in:
thrust26 2019-09-15 17:04:25 +02:00
parent 4b0f255b8d
commit 9a44366f85
18 changed files with 84 additions and 21 deletions

View File

@ -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));

View File

@ -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;

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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:

View File

@ -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

View File

@ -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);

View File

@ -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];