Added more accurate functionality for the _rwport debugger command. It now

properly distinguishes between intermediate reads which are part of writes,
and ordinary reads.  In the former case, only a read which has a different
address than a write is flagged as an error; intermediate reads acting on
the same address as the corresponding write are considered normal, and won't
trigger a break.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1901 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2009-11-11 20:53:57 +00:00
parent 00f8ffb686
commit 19f146038d
18 changed files with 87 additions and 125 deletions

View File

@ -198,9 +198,7 @@ void Debugger::setConsole(Console* console)
// Register any RAM areas in the Cartridge // Register any RAM areas in the Cartridge
// Zero-page RAM is automatically recognized by RamDebug // Zero-page RAM is automatically recognized by RamDebug
const Cartridge::RamAreaList& areas = myConsole->cartridge().ramAreas(); myRamDebug->addRamArea(myConsole->cartridge().ramAreas());
for(Cartridge::RamAreaList::const_iterator i = areas.begin(); i != areas.end(); ++i)
myRamDebug->addRamArea(i->start, i->size, i->roffset, i->woffset);
delete myRiotDebug; delete myRiotDebug;
myRiotDebug = new RiotDebug(*this, *myConsole); myRiotDebug = new RiotDebug(*this, *myConsole);

View File

@ -23,8 +23,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RamDebug::RamDebug(Debugger& dbg, Console& console) RamDebug::RamDebug(Debugger& dbg, Console& console)
: DebuggerSystem(dbg, console), : DebuggerSystem(dbg, console)
myReadFromWritePortAddress(0)
{ {
// Zero-page RAM is always present // Zero-page RAM is always present
addRamArea(0x80, 128, 0, 0); addRamArea(0x80, 128, 0, 0);
@ -51,6 +50,14 @@ void RamDebug::addRamArea(uInt16 start, uInt16 size,
} }
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RamDebug::addRamArea(const RamAreaList& areas)
{
myRamAreas = areas;
for(RamAreaList::const_iterator i = areas.begin(); i != areas.end(); ++i)
addRamArea(i->start, i->size, i->roffset, i->woffset);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const DebuggerState& RamDebug::getState() const DebuggerState& RamDebug::getState()
{ {
@ -84,17 +91,19 @@ void RamDebug::write(uInt16 addr, uInt8 value)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int RamDebug::readFromWritePort() int RamDebug::readFromWritePort()
{ {
int retval = myReadFromWritePortAddress; uInt16 addr = mySystem.m6502().lastReadAddress();
if(retval > 0) if(addr & 0x1000)
myReadFromWritePortAddress = 0; {
addr &= 0x0FFF;
return retval; for(RamAreaList::const_iterator i = myRamAreas.begin(); i != myRamAreas.end(); ++i)
} {
uInt16 start = (i->start + i->woffset) & 0x0FFF;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 end = (i->start + i->woffset + i->size) & 0x0FFF;
void RamDebug::setReadFromWritePort(uInt16 address) if(addr >= start && addr < end)
{ return addr;
myReadFromWritePortAddress = address; }
}
return 0;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -23,6 +23,7 @@ class System;
#include "bspf.hxx" #include "bspf.hxx"
#include "Array.hxx" #include "Array.hxx"
#include "Cart.hxx"
#include "DebuggerSystem.hxx" #include "DebuggerSystem.hxx"
// pointer types for RamDebug instance methods // pointer types for RamDebug instance methods
@ -53,6 +54,7 @@ class RamDebug : public DebuggerSystem
@param woffset Offset to use when writing to RAM (write port) @param woffset Offset to use when writing to RAM (write port)
*/ */
void addRamArea(uInt16 start, uInt16 size, uInt16 roffset, uInt16 woffset); void addRamArea(uInt16 start, uInt16 size, uInt16 roffset, uInt16 woffset);
void addRamArea(const RamAreaList& areas);
const DebuggerState& getState(); const DebuggerState& getState();
const DebuggerState& getOldState() { return myOldState; } const DebuggerState& getOldState() { return myOldState; }
@ -66,22 +68,15 @@ class RamDebug : public DebuggerSystem
uInt8 read(uInt16 addr); uInt8 read(uInt16 addr);
void write(uInt16 addr, uInt8 value); void write(uInt16 addr, uInt8 value);
// These methods are used by the debugger when we wish to know // Return the address at which an invalid read was performed in a
// if an illegal read from a write port has been performed. // write port area.
// It's up to each Cartridge to report the error, and a
// conditional breakpoint must be set in the debugger to check
// for occurrences of this.
//
// Note that each time readFromWritePort() returns a hit, the status
// is reset.
int readFromWritePort(); int readFromWritePort();
void setReadFromWritePort(uInt16 address);
private: private:
RamState myState; RamState myState;
RamState myOldState; RamState myOldState;
uInt16 myReadFromWritePortAddress; RamAreaList myRamAreas;
}; };
#endif #endif

View File

@ -251,20 +251,13 @@ bool Cartridge::save(ofstream& out)
void Cartridge::registerRamArea(uInt16 start, uInt16 size, void Cartridge::registerRamArea(uInt16 start, uInt16 size,
uInt16 roffset, uInt16 woffset) uInt16 roffset, uInt16 woffset)
{ {
#ifdef DEBUGGER_SUPPORT
RamArea area; RamArea area;
area.start = start; area.start = start;
area.size = size; area.size = size;
area.roffset = roffset; area.roffset = roffset;
area.woffset = woffset; area.woffset = woffset;
myRamAreaList.push_back(area); myRamAreaList.push_back(area);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge::triggerReadFromWritePort(uInt16 address)
{
#ifdef DEBUGGER_SUPPORT
if(&Debugger::debugger().ramDebug())
Debugger::debugger().ramDebug().setReadFromWritePort(address);
#endif #endif
} }

View File

@ -30,6 +30,13 @@ class Settings;
#include "Array.hxx" #include "Array.hxx"
#include "Device.hxx" #include "Device.hxx"
#ifdef DEBUGGER_SUPPORT
struct RamArea {
uInt16 start; uInt16 size; uInt16 roffset; uInt16 woffset;
};
typedef Common::Array<RamArea> RamAreaList;
#endif
/** /**
A cartridge is a device which contains the machine code for a A cartridge is a device which contains the machine code for a
game and handles any bankswitching performed by the cartridge. game and handles any bankswitching performed by the cartridge.
@ -85,20 +92,9 @@ class Cartridge : public Device
void lockBank() { myBankLocked = true; } void lockBank() { myBankLocked = true; }
void unlockBank() { myBankLocked = false; } void unlockBank() { myBankLocked = false; }
public: #ifdef DEBUGGER_SUPPORT
/**
The following list contains addressable areas of ROM that are mapped
to RAM (usually Superchip, but there are other types). Since such
RAM is normally mapped in at different addresses for read and write
ports, read and write offsets must be considered.
@return List of addressable RAM areas (can be empty)
*/
struct RamArea {
uInt16 start; uInt16 size; uInt16 roffset; uInt16 woffset;
};
typedef Common::Array<RamArea> RamAreaList;
const RamAreaList& ramAreas() { return myRamAreaList; } const RamAreaList& ramAreas() { return myRamAreaList; }
#endif
public: public:
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -173,14 +169,6 @@ class Cartridge : public Device
*/ */
void registerRamArea(uInt16 start, uInt16 size, uInt16 roffset, uInt16 woffset); void registerRamArea(uInt16 start, uInt16 size, uInt16 roffset, uInt16 woffset);
/**
Indicate that an illegal read from the write port has occurred.
This message is sent to the debugger (if support exists).
@param address The write port address where the read occurred
*/
void triggerReadFromWritePort(uInt16 address);
private: private:
/** /**
Get an image pointer and size for a ROM that is part of a larger, Get an image pointer and size for a ROM that is part of a larger,
@ -292,9 +280,10 @@ class Cartridge : public Device
bool myBankLocked; bool myBankLocked;
private: private:
#ifdef DEBUGGER_SUPPORT
// Contains RamArea entries for those carts with accessible RAM. // Contains RamArea entries for those carts with accessible RAM.
RamAreaList myRamAreaList; RamAreaList myRamAreaList;
#endif
// Contains info about this cartridge in string format // Contains info about this cartridge in string format
static string myAboutString; static string myAboutString;

View File

@ -110,13 +110,8 @@ uInt8 Cartridge3E::peek(uInt16 address)
// Reading from the write port triggers an unwanted write // Reading from the write port triggers an unwanted write
uInt8 value = mySystem->getDataBusState(0xFF); uInt8 value = mySystem->getDataBusState(0xFF);
if(myBankLocked) if(myBankLocked) return value;
return value; else return myRam[(address & 0x03FF) + ((myCurrentBank - 256) << 10)] = value;
else
{
triggerReadFromWritePort(address);
return myRam[(address & 0x03FF) + ((myCurrentBank - 256) << 10)] = value;
}
} }
} }
} }

View File

@ -113,13 +113,8 @@ uInt8 CartridgeCV::peek(uInt16 address)
// Reading from the write port triggers an unwanted write // Reading from the write port triggers an unwanted write
uInt8 value = mySystem->getDataBusState(0xFF); uInt8 value = mySystem->getDataBusState(0xFF);
if(myBankLocked) if(myBankLocked) return value;
return value; else return myRAM[address & 0x03FF] = value;
else
{
triggerReadFromWritePort(address);
return myRAM[address & 0x03FF] = value;
}
} }
else else
{ {

View File

@ -111,13 +111,8 @@ uInt8 CartridgeE7::peek(uInt16 address)
// Reading from the write port triggers an unwanted write // Reading from the write port triggers an unwanted write
uInt8 value = mySystem->getDataBusState(0xFF); uInt8 value = mySystem->getDataBusState(0xFF);
if(myBankLocked) if(myBankLocked) return value;
return value; else return myImage[(myCurrentSlice[address >> 11] << 11) + (address & 0x07FF)] = value;
else
{
triggerReadFromWritePort(address);
return myImage[(myCurrentSlice[address >> 11] << 11) + (address & 0x07FF)] = value;
}
} }
else else
return myImage[(myCurrentSlice[address >> 11] << 11) + (address & 0x07FF)]; return myImage[(myCurrentSlice[address >> 11] << 11) + (address & 0x07FF)];

View File

@ -104,13 +104,8 @@ uInt8 CartridgeEFSC::peek(uInt16 address)
// Reading from the write port triggers an unwanted write // Reading from the write port triggers an unwanted write
uInt8 value = mySystem->getDataBusState(0xFF); uInt8 value = mySystem->getDataBusState(0xFF);
if(myBankLocked) if(myBankLocked) return value;
return value; else return myRAM[address] = value;
else
{
triggerReadFromWritePort(address);
return myRAM[address] = value;
}
} }
else else
return myImage[(myCurrentBank << 12) + address]; return myImage[(myCurrentBank << 12) + address];

View File

@ -104,13 +104,8 @@ uInt8 CartridgeF4SC::peek(uInt16 address)
// Reading from the write port triggers an unwanted write // Reading from the write port triggers an unwanted write
uInt8 value = mySystem->getDataBusState(0xFF); uInt8 value = mySystem->getDataBusState(0xFF);
if(myBankLocked) if(myBankLocked) return value;
return value; else return myRAM[address] = value;
else
{
triggerReadFromWritePort(address);
return myRAM[address] = value;
}
} }
else else
return myImage[(myCurrentBank << 12) + address]; return myImage[(myCurrentBank << 12) + address];

View File

@ -127,13 +127,8 @@ uInt8 CartridgeF6SC::peek(uInt16 address)
// Reading from the write port triggers an unwanted write // Reading from the write port triggers an unwanted write
uInt8 value = mySystem->getDataBusState(0xFF); uInt8 value = mySystem->getDataBusState(0xFF);
if(myBankLocked) if(myBankLocked) return value;
return value; else return myRAM[address] = value;
else
{
triggerReadFromWritePort(address);
return myRAM[address] = value;
}
} }
else else
return myImage[(myCurrentBank << 12) + address]; return myImage[(myCurrentBank << 12) + address];

View File

@ -117,13 +117,8 @@ uInt8 CartridgeF8SC::peek(uInt16 address)
// Reading from the write port triggers an unwanted write // Reading from the write port triggers an unwanted write
uInt8 value = mySystem->getDataBusState(0xFF); uInt8 value = mySystem->getDataBusState(0xFF);
if(myBankLocked) if(myBankLocked) return value;
return value; else return myRAM[address] = value;
else
{
triggerReadFromWritePort(address);
return myRAM[address] = value;
}
} }
else else
return myImage[(myCurrentBank << 12) + address]; return myImage[(myCurrentBank << 12) + address];

View File

@ -122,13 +122,8 @@ uInt8 CartridgeFA::peek(uInt16 address)
// Reading from the write port triggers an unwanted write // Reading from the write port triggers an unwanted write
uInt8 value = mySystem->getDataBusState(0xFF); uInt8 value = mySystem->getDataBusState(0xFF);
if(myBankLocked) if(myBankLocked) return value;
return value; else return myRAM[address] = value;
else
{
triggerReadFromWritePort(address);
return myRAM[address] = value;
}
} }
else else
return myImage[(myCurrentBank << 12) + address]; return myImage[(myCurrentBank << 12) + address];

View File

@ -146,13 +146,8 @@ uInt8 CartridgeMC::peek(uInt16 address)
// Reading from the write port triggers an unwanted write // Reading from the write port triggers an unwanted write
uInt8 value = mySystem->getDataBusState(0xFF); uInt8 value = mySystem->getDataBusState(0xFF);
if(myBankLocked) if(myBankLocked) return value;
return value; else return myRAM[(uInt32)((block & 0x3F) << 9) + (address & 0x01FF)] = value;
else
{
triggerReadFromWritePort(address);
return myRAM[(uInt32)((block & 0x3F) << 9) + (address & 0x01FF)] = value;
}
} }
} }
} }

View File

@ -19,7 +19,6 @@
#ifndef CONSOLE_HXX #ifndef CONSOLE_HXX
#define CONSOLE_HXX #define CONSOLE_HXX
class Console;
class Controller; class Controller;
class Event; class Event;
class Switches; class Switches;

View File

@ -34,7 +34,9 @@ M6502::M6502(uInt32 systemCyclesPerProcessorCycle)
myLastAccessWasRead(true), myLastAccessWasRead(true),
myTotalInstructionCount(0), myTotalInstructionCount(0),
myNumberOfDistinctAccesses(0), myNumberOfDistinctAccesses(0),
myLastAddress(0) myLastAddress(0),
myLastPeekAddress(0),
myLastPokeAddress(0)
{ {
#ifdef DEBUGGER_SUPPORT #ifdef DEBUGGER_SUPPORT
myDebugger = NULL; myDebugger = NULL;
@ -169,6 +171,7 @@ inline uInt8 M6502::peek(uInt16 address)
uInt8 result = mySystem->peek(address); uInt8 result = mySystem->peek(address);
myLastAccessWasRead = true; myLastAccessWasRead = true;
myLastPeekAddress = address;
return result; return result;
} }
@ -193,6 +196,7 @@ inline void M6502::poke(uInt16 address, uInt8 value)
mySystem->poke(address, value); mySystem->poke(address, value);
myLastAccessWasRead = false; myLastAccessWasRead = false;
myLastPokeAddress = address;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -206,9 +210,6 @@ bool M6502::execute(uInt32 number)
{ {
for(; !myExecutionStatus && (number != 0); --number) for(; !myExecutionStatus && (number != 0); --number)
{ {
uInt16 operandAddress = 0;
uInt8 operand = 0;
#ifdef DEBUGGER_SUPPORT #ifdef DEBUGGER_SUPPORT
if(myJustHitTrapFlag) if(myJustHitTrapFlag)
{ {
@ -236,6 +237,11 @@ bool M6502::execute(uInt32 number)
return true; return true;
} }
#endif #endif
uInt16 operandAddress = 0;
uInt8 operand = 0;
// Reset the peek/poke address pointers
myLastPeekAddress = myLastPokeAddress = 0;
// Fetch instruction at the program counter // Fetch instruction at the program counter
IR = peek(PC++); IR = peek(PC++);

View File

@ -154,6 +154,20 @@ class M6502 : public Serializable
*/ */
bool lastAccessWasRead() const { return myLastAccessWasRead; } bool lastAccessWasRead() const { return myLastAccessWasRead; }
/**
Return the last address that was part of a read/peek. Note that
reads which are part of a write are not considered here, unless
they're not the same as the last write address. This eliminates
accesses that are part of a normal read/write cycle.
@return The address of the last read
*/
uInt16 lastReadAddress() const {
return myLastPokeAddress ?
(myLastPokeAddress != myLastPeekAddress ? myLastPeekAddress : 0) :
myLastPeekAddress;
}
/** /**
Get the total number of instructions executed so far. Get the total number of instructions executed so far.
@ -325,6 +339,10 @@ class M6502 : public Serializable
/// Indicates the last address which was accessed /// Indicates the last address which was accessed
uInt16 myLastAddress; uInt16 myLastAddress;
/// Indicates the last address which was accessed specifically
/// by a peek or poke command
uInt16 myLastPeekAddress, myLastPokeAddress;
#ifdef DEBUGGER_SUPPORT #ifdef DEBUGGER_SUPPORT
/// 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;

View File

@ -28,7 +28,7 @@
namespace GUI { namespace GUI {
/*! @brief simple class for handling both 2D position and size /*! @brief simple class for handling both 2D position and size
This small class is an helper for position and size values. This small class is an helper for position and size values.
*/ */