mirror of https://github.com/stella-emu/stella.git
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:
parent
00f8ffb686
commit
19f146038d
|
@ -198,9 +198,7 @@ void Debugger::setConsole(Console* console)
|
|||
|
||||
// Register any RAM areas in the Cartridge
|
||||
// Zero-page RAM is automatically recognized by RamDebug
|
||||
const Cartridge::RamAreaList& areas = 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);
|
||||
myRamDebug->addRamArea(myConsole->cartridge().ramAreas());
|
||||
|
||||
delete myRiotDebug;
|
||||
myRiotDebug = new RiotDebug(*this, *myConsole);
|
||||
|
|
|
@ -23,8 +23,7 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
RamDebug::RamDebug(Debugger& dbg, Console& console)
|
||||
: DebuggerSystem(dbg, console),
|
||||
myReadFromWritePortAddress(0)
|
||||
: DebuggerSystem(dbg, console)
|
||||
{
|
||||
// Zero-page RAM is always present
|
||||
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()
|
||||
{
|
||||
|
@ -84,17 +91,19 @@ void RamDebug::write(uInt16 addr, uInt8 value)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int RamDebug::readFromWritePort()
|
||||
{
|
||||
int retval = myReadFromWritePortAddress;
|
||||
if(retval > 0)
|
||||
myReadFromWritePortAddress = 0;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RamDebug::setReadFromWritePort(uInt16 address)
|
||||
{
|
||||
myReadFromWritePortAddress = address;
|
||||
uInt16 addr = mySystem.m6502().lastReadAddress();
|
||||
if(addr & 0x1000)
|
||||
{
|
||||
addr &= 0x0FFF;
|
||||
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;
|
||||
if(addr >= start && addr < end)
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -23,6 +23,7 @@ class System;
|
|||
|
||||
#include "bspf.hxx"
|
||||
#include "Array.hxx"
|
||||
#include "Cart.hxx"
|
||||
#include "DebuggerSystem.hxx"
|
||||
|
||||
// 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)
|
||||
*/
|
||||
void addRamArea(uInt16 start, uInt16 size, uInt16 roffset, uInt16 woffset);
|
||||
void addRamArea(const RamAreaList& areas);
|
||||
|
||||
const DebuggerState& getState();
|
||||
const DebuggerState& getOldState() { return myOldState; }
|
||||
|
@ -66,22 +68,15 @@ class RamDebug : public DebuggerSystem
|
|||
uInt8 read(uInt16 addr);
|
||||
void write(uInt16 addr, uInt8 value);
|
||||
|
||||
// These methods are used by the debugger when we wish to know
|
||||
// if an illegal read from a write port has been performed.
|
||||
// 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.
|
||||
// Return the address at which an invalid read was performed in a
|
||||
// write port area.
|
||||
int readFromWritePort();
|
||||
void setReadFromWritePort(uInt16 address);
|
||||
|
||||
private:
|
||||
RamState myState;
|
||||
RamState myOldState;
|
||||
|
||||
uInt16 myReadFromWritePortAddress;
|
||||
RamAreaList myRamAreas;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -251,20 +251,13 @@ bool Cartridge::save(ofstream& out)
|
|||
void Cartridge::registerRamArea(uInt16 start, uInt16 size,
|
||||
uInt16 roffset, uInt16 woffset)
|
||||
{
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
RamArea area;
|
||||
area.start = start;
|
||||
area.size = size;
|
||||
area.roffset = roffset;
|
||||
area.woffset = woffset;
|
||||
myRamAreaList.push_back(area);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Cartridge::triggerReadFromWritePort(uInt16 address)
|
||||
{
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
if(&Debugger::debugger().ramDebug())
|
||||
Debugger::debugger().ramDebug().setReadFromWritePort(address);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,13 @@ class Settings;
|
|||
#include "Array.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
|
||||
game and handles any bankswitching performed by the cartridge.
|
||||
|
@ -85,20 +92,9 @@ class Cartridge : public Device
|
|||
void lockBank() { myBankLocked = true; }
|
||||
void unlockBank() { myBankLocked = false; }
|
||||
|
||||
public:
|
||||
/**
|
||||
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;
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
const RamAreaList& ramAreas() { return myRamAreaList; }
|
||||
#endif
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
@ -173,14 +169,6 @@ class Cartridge : public Device
|
|||
*/
|
||||
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:
|
||||
/**
|
||||
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;
|
||||
|
||||
private:
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
// Contains RamArea entries for those carts with accessible RAM.
|
||||
RamAreaList myRamAreaList;
|
||||
|
||||
#endif
|
||||
// Contains info about this cartridge in string format
|
||||
static string myAboutString;
|
||||
|
||||
|
|
|
@ -110,13 +110,8 @@ uInt8 Cartridge3E::peek(uInt16 address)
|
|||
// Reading from the write port triggers an unwanted write
|
||||
uInt8 value = mySystem->getDataBusState(0xFF);
|
||||
|
||||
if(myBankLocked)
|
||||
return value;
|
||||
else
|
||||
{
|
||||
triggerReadFromWritePort(address);
|
||||
return myRam[(address & 0x03FF) + ((myCurrentBank - 256) << 10)] = value;
|
||||
}
|
||||
if(myBankLocked) return value;
|
||||
else return myRam[(address & 0x03FF) + ((myCurrentBank - 256) << 10)] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,13 +113,8 @@ uInt8 CartridgeCV::peek(uInt16 address)
|
|||
// Reading from the write port triggers an unwanted write
|
||||
uInt8 value = mySystem->getDataBusState(0xFF);
|
||||
|
||||
if(myBankLocked)
|
||||
return value;
|
||||
else
|
||||
{
|
||||
triggerReadFromWritePort(address);
|
||||
return myRAM[address & 0x03FF] = value;
|
||||
}
|
||||
if(myBankLocked) return value;
|
||||
else return myRAM[address & 0x03FF] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -111,13 +111,8 @@ uInt8 CartridgeE7::peek(uInt16 address)
|
|||
// Reading from the write port triggers an unwanted write
|
||||
uInt8 value = mySystem->getDataBusState(0xFF);
|
||||
|
||||
if(myBankLocked)
|
||||
return value;
|
||||
else
|
||||
{
|
||||
triggerReadFromWritePort(address);
|
||||
return myImage[(myCurrentSlice[address >> 11] << 11) + (address & 0x07FF)] = value;
|
||||
}
|
||||
if(myBankLocked) return value;
|
||||
else return myImage[(myCurrentSlice[address >> 11] << 11) + (address & 0x07FF)] = value;
|
||||
}
|
||||
else
|
||||
return myImage[(myCurrentSlice[address >> 11] << 11) + (address & 0x07FF)];
|
||||
|
|
|
@ -104,13 +104,8 @@ uInt8 CartridgeEFSC::peek(uInt16 address)
|
|||
// Reading from the write port triggers an unwanted write
|
||||
uInt8 value = mySystem->getDataBusState(0xFF);
|
||||
|
||||
if(myBankLocked)
|
||||
return value;
|
||||
else
|
||||
{
|
||||
triggerReadFromWritePort(address);
|
||||
return myRAM[address] = value;
|
||||
}
|
||||
if(myBankLocked) return value;
|
||||
else return myRAM[address] = value;
|
||||
}
|
||||
else
|
||||
return myImage[(myCurrentBank << 12) + address];
|
||||
|
|
|
@ -104,13 +104,8 @@ uInt8 CartridgeF4SC::peek(uInt16 address)
|
|||
// Reading from the write port triggers an unwanted write
|
||||
uInt8 value = mySystem->getDataBusState(0xFF);
|
||||
|
||||
if(myBankLocked)
|
||||
return value;
|
||||
else
|
||||
{
|
||||
triggerReadFromWritePort(address);
|
||||
return myRAM[address] = value;
|
||||
}
|
||||
if(myBankLocked) return value;
|
||||
else return myRAM[address] = value;
|
||||
}
|
||||
else
|
||||
return myImage[(myCurrentBank << 12) + address];
|
||||
|
|
|
@ -127,13 +127,8 @@ uInt8 CartridgeF6SC::peek(uInt16 address)
|
|||
// Reading from the write port triggers an unwanted write
|
||||
uInt8 value = mySystem->getDataBusState(0xFF);
|
||||
|
||||
if(myBankLocked)
|
||||
return value;
|
||||
else
|
||||
{
|
||||
triggerReadFromWritePort(address);
|
||||
return myRAM[address] = value;
|
||||
}
|
||||
if(myBankLocked) return value;
|
||||
else return myRAM[address] = value;
|
||||
}
|
||||
else
|
||||
return myImage[(myCurrentBank << 12) + address];
|
||||
|
|
|
@ -117,13 +117,8 @@ uInt8 CartridgeF8SC::peek(uInt16 address)
|
|||
// Reading from the write port triggers an unwanted write
|
||||
uInt8 value = mySystem->getDataBusState(0xFF);
|
||||
|
||||
if(myBankLocked)
|
||||
return value;
|
||||
else
|
||||
{
|
||||
triggerReadFromWritePort(address);
|
||||
return myRAM[address] = value;
|
||||
}
|
||||
if(myBankLocked) return value;
|
||||
else return myRAM[address] = value;
|
||||
}
|
||||
else
|
||||
return myImage[(myCurrentBank << 12) + address];
|
||||
|
|
|
@ -122,13 +122,8 @@ uInt8 CartridgeFA::peek(uInt16 address)
|
|||
// Reading from the write port triggers an unwanted write
|
||||
uInt8 value = mySystem->getDataBusState(0xFF);
|
||||
|
||||
if(myBankLocked)
|
||||
return value;
|
||||
else
|
||||
{
|
||||
triggerReadFromWritePort(address);
|
||||
return myRAM[address] = value;
|
||||
}
|
||||
if(myBankLocked) return value;
|
||||
else return myRAM[address] = value;
|
||||
}
|
||||
else
|
||||
return myImage[(myCurrentBank << 12) + address];
|
||||
|
|
|
@ -146,13 +146,8 @@ uInt8 CartridgeMC::peek(uInt16 address)
|
|||
// Reading from the write port triggers an unwanted write
|
||||
uInt8 value = mySystem->getDataBusState(0xFF);
|
||||
|
||||
if(myBankLocked)
|
||||
return value;
|
||||
else
|
||||
{
|
||||
triggerReadFromWritePort(address);
|
||||
return myRAM[(uInt32)((block & 0x3F) << 9) + (address & 0x01FF)] = value;
|
||||
}
|
||||
if(myBankLocked) return value;
|
||||
else return myRAM[(uInt32)((block & 0x3F) << 9) + (address & 0x01FF)] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#ifndef CONSOLE_HXX
|
||||
#define CONSOLE_HXX
|
||||
|
||||
class Console;
|
||||
class Controller;
|
||||
class Event;
|
||||
class Switches;
|
||||
|
|
|
@ -34,7 +34,9 @@ M6502::M6502(uInt32 systemCyclesPerProcessorCycle)
|
|||
myLastAccessWasRead(true),
|
||||
myTotalInstructionCount(0),
|
||||
myNumberOfDistinctAccesses(0),
|
||||
myLastAddress(0)
|
||||
myLastAddress(0),
|
||||
myLastPeekAddress(0),
|
||||
myLastPokeAddress(0)
|
||||
{
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
myDebugger = NULL;
|
||||
|
@ -169,6 +171,7 @@ inline uInt8 M6502::peek(uInt16 address)
|
|||
|
||||
uInt8 result = mySystem->peek(address);
|
||||
myLastAccessWasRead = true;
|
||||
myLastPeekAddress = address;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -193,6 +196,7 @@ inline void M6502::poke(uInt16 address, uInt8 value)
|
|||
|
||||
mySystem->poke(address, value);
|
||||
myLastAccessWasRead = false;
|
||||
myLastPokeAddress = address;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -206,9 +210,6 @@ bool M6502::execute(uInt32 number)
|
|||
{
|
||||
for(; !myExecutionStatus && (number != 0); --number)
|
||||
{
|
||||
uInt16 operandAddress = 0;
|
||||
uInt8 operand = 0;
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
if(myJustHitTrapFlag)
|
||||
{
|
||||
|
@ -236,6 +237,11 @@ bool M6502::execute(uInt32 number)
|
|||
return true;
|
||||
}
|
||||
#endif
|
||||
uInt16 operandAddress = 0;
|
||||
uInt8 operand = 0;
|
||||
|
||||
// Reset the peek/poke address pointers
|
||||
myLastPeekAddress = myLastPokeAddress = 0;
|
||||
|
||||
// Fetch instruction at the program counter
|
||||
IR = peek(PC++);
|
||||
|
|
|
@ -154,6 +154,20 @@ class M6502 : public Serializable
|
|||
*/
|
||||
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.
|
||||
|
||||
|
@ -325,6 +339,10 @@ class M6502 : public Serializable
|
|||
/// Indicates the last address which was accessed
|
||||
uInt16 myLastAddress;
|
||||
|
||||
/// Indicates the last address which was accessed specifically
|
||||
/// by a peek or poke command
|
||||
uInt16 myLastPeekAddress, myLastPokeAddress;
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
/// Pointer to the debugger for this processor or the null pointer
|
||||
Debugger* myDebugger;
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
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.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue