Made M6502 own all breakpoint/trap info instead of sharing pointers to

it with the debugger (this eliminates more new's and empties another d'tor.

Re-wrote PackedBitArray to use a bitset instead of home-made code.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@3075 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2014-11-16 16:13:58 +00:00
parent c997fc3001
commit 29fe39dd99
9 changed files with 82 additions and 201 deletions

View File

@ -115,9 +115,6 @@ Debugger::Debugger(OSystem& osystem, Console& console)
myConsole(console),
mySystem(console.system()),
myDialog(nullptr),
myBreakPoints(nullptr),
myReadTraps(nullptr),
myWriteTraps(nullptr),
myWidth(DebuggerDialog::kSmallFontMinW),
myHeight(DebuggerDialog::kSmallFontMinH)
{
@ -130,10 +127,6 @@ Debugger::Debugger(OSystem& osystem, Console& console)
myRiotDebug = make_ptr<RiotDebug>(*this, myConsole);
myTiaDebug = make_ptr<TIADebug>(*this, myConsole);
myBreakPoints = new PackedBitArray(0x10000);
myReadTraps = new PackedBitArray(0x10000);
myWriteTraps = new PackedBitArray(0x10000);
// Allow access to this object from any class
// Technically this violates pure OO programming, but since I know
// there will only be ever one instance of debugger in Stella,
@ -144,9 +137,6 @@ Debugger::Debugger(OSystem& osystem, Console& console)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Debugger::~Debugger()
{
delete myBreakPoints;
delete myReadTraps;
delete myWriteTraps;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -362,41 +352,39 @@ int Debugger::trace()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::toggleBreakPoint(int bp)
{
mySystem.m6502().setBreakPoints(myBreakPoints);
breakPoints().initialize();
if(bp < 0) bp = myCpuDebug->pc();
myBreakPoints->toggle(bp);
breakPoints().toggle(bp);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::setBreakPoint(int bp, bool set)
{
mySystem.m6502().setBreakPoints(myBreakPoints);
breakPoints().initialize();
if(bp < 0) bp = myCpuDebug->pc();
if(set)
myBreakPoints->set(bp);
else
myBreakPoints->clear(bp);
if(set) breakPoints().set(bp);
else breakPoints().clear(bp);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Debugger::breakPoint(int bp)
{
if(bp < 0) bp = myCpuDebug->pc();
return myBreakPoints->isSet(bp) != 0;
return breakPoints().isSet(bp);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::toggleReadTrap(int t)
{
mySystem.m6502().setTraps(myReadTraps, myWriteTraps);
myReadTraps->toggle(t);
readTraps().initialize();
readTraps().toggle(t);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::toggleWriteTrap(int t)
{
mySystem.m6502().setTraps(myReadTraps, myWriteTraps);
myWriteTraps->toggle(t);
writeTraps().initialize();
writeTraps().toggle(t);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -409,13 +397,13 @@ void Debugger::toggleTrap(int t)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Debugger::readTrap(int t)
{
return myReadTraps->isSet(t) != 0;
return readTraps().isInitialized() && readTraps().isSet(t);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Debugger::writeTrap(int t)
{
return myWriteTraps->isSet(t) != 0;
return writeTraps().isInitialized() && writeTraps().isSet(t);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -463,19 +451,14 @@ bool Debugger::rewindState()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::clearAllBreakPoints()
{
delete myBreakPoints;
myBreakPoints = new PackedBitArray(0x10000);
mySystem.m6502().setBreakPoints(nullptr);
breakPoints().clearAll();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::clearAllTraps()
{
delete myReadTraps;
delete myWriteTraps;
myReadTraps = new PackedBitArray(0x10000);
myWriteTraps = new PackedBitArray(0x10000);
mySystem.m6502().setTraps(nullptr, nullptr);
readTraps().clearAll();
writeTraps().clearAll();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -527,7 +510,7 @@ void Debugger::setQuitState()
// execute one instruction on quit. If we're
// sitting at a breakpoint/trap, this will get us past it.
// Somehow this feels like a hack to me, but I don't know why
// if(myBreakPoints->isSet(myCpuDebug->pc()))
// if(breakPoints().isSet(myCpuDebug->pc()))
mySystem.m6502().execute(1);
}
@ -548,6 +531,11 @@ bool Debugger::delFunction(const string& name)
if(iter == myFunctions.end())
return false;
// We never want to delete built-in functions
for(int i = 0; builtin_functions[i][0] != 0; ++i)
if(name == builtin_functions[i][0])
return false;
myFunctions.erase(name);
const auto& def_iter = myFunctionDefs.find(name);

View File

@ -26,7 +26,6 @@ class CartDebug;
class CpuDebug;
class RiotDebug;
class TIADebug;
class M6502;
class TiaInfoWidget;
class TiaOutputWidget;
class TiaZoomWidget;
@ -44,6 +43,7 @@ class ButtonWidget;
#include "DialogContainer.hxx"
#include "DebuggerDialog.hxx"
#include "DebuggerParser.hxx"
#include "M6502.hxx"
#include "System.hxx"
#include "Stack.hxx"
#include "bspf.hxx"
@ -158,13 +158,14 @@ class Debugger : public DialogContainer
const GUI::Font& lfont() const { return myDialog->lfont(); }
const GUI::Font& nlfont() const { return myDialog->nfont(); }
DebuggerParser& parser() const { return *myParser; }
PackedBitArray& breakpoints() const { return *myBreakPoints; }
PackedBitArray& readtraps() const { return *myReadTraps; }
PackedBitArray& writetraps() const { return *myWriteTraps; }
PromptWidget& prompt() const { return myDialog->prompt(); }
RomWidget& rom() const { return myDialog->rom(); }
TiaOutputWidget& tiaOutput() const { return myDialog->tiaOutput(); }
PackedBitArray& breakPoints() const { return mySystem.m6502().breakPoints(); }
PackedBitArray& readTraps() const { return mySystem.m6502().readTraps(); }
PackedBitArray& writeTraps() const { return mySystem.m6502().writeTraps(); }
/**
Run the debugger command and return the result.
*/
@ -302,10 +303,6 @@ class Debugger : public DialogContainer
unique_ptr<RiotDebug> myRiotDebug;
unique_ptr<TIADebug> myTiaDebug;
PackedBitArray* myBreakPoints;
PackedBitArray* myReadTraps;
PackedBitArray* myWriteTraps;
static Debugger* myStaticDebugger;
FunctionMap myFunctions;

View File

@ -869,7 +869,7 @@ void DebuggerParser::executeDelfunction()
if(debugger.delFunction(argStrings[0]))
commandResult << "removed function " << argStrings[0];
else
commandResult << "function " << argStrings[0] << " not found";
commandResult << "function " << argStrings[0] << " built-in or not found";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1042,7 +1042,7 @@ void DebuggerParser::executeListbreaks()
for(uInt32 i = 0; i < 0x10000; i++)
{
if(debugger.breakpoints().isSet(i))
if(debugger.breakPoints().isSet(i))
{
buf << debugger.cartDebug().getLabel(i, true, 4) << " ";
if(! (++count % 8) ) buf << "\n";

View File

@ -1,82 +0,0 @@
//============================================================================
//
// 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-2014 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.
//
// $Id$
//============================================================================
#include "bspf.hxx"
#include "PackedBitArray.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PackedBitArray::PackedBitArray(uInt32 length)
: words(length / WORD_SIZE + 1)
{
bits = new uInt32[ words ];
for(uInt32 i = 0; i < words; ++i)
bits[i] = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PackedBitArray::~PackedBitArray()
{
delete[] bits;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 PackedBitArray::isSet(uInt32 bit) const
{
uInt32 word = bit / WORD_SIZE;
bit %= WORD_SIZE;
return (bits[word] & (1 << bit));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 PackedBitArray::isClear(uInt32 bit) const
{
uInt32 word = bit / WORD_SIZE;
bit %= WORD_SIZE;
return !(bits[word] & (1 << bit));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PackedBitArray::toggle(uInt32 bit)
{
uInt32 word = bit / WORD_SIZE;
bit %= WORD_SIZE;
bits[word] ^= (1 << bit);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PackedBitArray::set(uInt32 bit)
{
uInt32 word = bit / WORD_SIZE;
bit %= WORD_SIZE;
bits[word] |= (1 << bit);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PackedBitArray::clear(uInt32 bit)
{
uInt32 word = bit / WORD_SIZE;
bit %= WORD_SIZE;
bits[word] &= (~(1 << bit));
}

View File

@ -17,36 +17,40 @@
// $Id$
//============================================================================
#ifndef PACKEDBITARRAY_HXX
#define PACKEDBITARRAY_HXX
#ifndef PACKED_BIT_ARRAY_HXX
#define PACKED_BIT_ARRAY_HXX
#include <bitset>
#include "bspf.hxx"
class PackedBitArray
{
public:
PackedBitArray(uInt32 length);
~PackedBitArray();
PackedBitArray() : myInitialized(false) { }
uInt32 isSet(uInt32 bit) const;
uInt32 isClear(uInt32 bit) const;
bool isSet(uInt32 bit) const { return myBits[bit]; }
bool isClear(uInt32 bit) const { return !myBits[bit]; }
void set(uInt32 bit);
void clear(uInt32 bit);
void toggle(uInt32 bit);
void set(uInt32 bit) { myBits[bit] = true; }
void clear(uInt32 bit) { myBits[bit] = false; }
void toggle(uInt32 bit) { myBits.flip(bit); }
void initialize() { myInitialized = true; }
void clearAll() { myInitialized = false; myBits.reset(); }
bool isInitialized() const { return myInitialized; }
private:
// Copy constructor and assignment operator not supported
PackedBitArray(const PackedBitArray&);
PackedBitArray& operator = (const PackedBitArray&);
// number of unsigned ints (size/wordSize):
uInt32 words;
// The actual bits
bitset<0x10000> myBits;
// the array itself:
uInt32* bits;
static const uInt32 WORD_SIZE = sizeof(uInt32) * 8;
// Indicates whether we should treat this bitset as initialized
bool myInitialized;
};
#endif

View File

@ -78,7 +78,7 @@ void RomWidget::loadConfig()
myListIsDirty |= cart.disassemble(myListIsDirty);
if(myListIsDirty)
{
myRomList->setList(cart.disassembly(), dbg.breakpoints());
myRomList->setList(cart.disassembly(), dbg.breakPoints());
myListIsDirty = false;
}

View File

@ -3,7 +3,6 @@ MODULE := src/debugger
MODULE_OBJS := \
src/debugger/Debugger.o \
src/debugger/DebuggerParser.o \
src/debugger/PackedBitArray.o \
src/debugger/CartDebug.o \
src/debugger/CpuDebug.o \
src/debugger/DiStella.o \

View File

@ -62,11 +62,7 @@ M6502::M6502(const Settings& settings)
myDataAddressForPoke(0)
{
#ifdef DEBUGGER_SUPPORT
myDebugger = nullptr;
myBreakPoints = nullptr;
myReadTraps = nullptr;
myWriteTraps = nullptr;
myDebugger = nullptr;
myJustHitTrapFlag = false;
#endif
}
@ -130,14 +126,13 @@ inline uInt8 M6502::peek(uInt16 address, uInt8 flags)
mySystem->incrementCycles(SYSTEM_CYCLES_PER_CPU);
#ifdef DEBUGGER_SUPPORT
if(myReadTraps != nullptr && myReadTraps->isSet(address))
if(myReadTraps.isInitialized() && myReadTraps.isSet(address))
{
myJustHitTrapFlag = true;
myHitTrapInfo.message = "RTrap: ";
myHitTrapInfo.address = address;
}
//cerr << "addr = " << HEX4 << address << ", flags = " << Debugger::to_bin_8(flags) << endl;
#endif
#endif // DEBUGGER_SUPPORT
uInt8 result = mySystem->peek(address, flags);
myLastAccessWasRead = true;
@ -159,13 +154,13 @@ inline void M6502::poke(uInt16 address, uInt8 value)
mySystem->incrementCycles(SYSTEM_CYCLES_PER_CPU);
#ifdef DEBUGGER_SUPPORT
if(myWriteTraps != nullptr && myWriteTraps->isSet(address))
if(myWriteTraps.isInitialized() && myWriteTraps.isSet(address))
{
myJustHitTrapFlag = true;
myHitTrapInfo.message = "WTrap: ";
myHitTrapInfo.address = address;
}
#endif
#endif // DEBUGGER_SUPPORT
mySystem->poke(address, value);
myLastAccessWasRead = false;
@ -193,10 +188,9 @@ bool M6502::execute(uInt32 number)
}
}
if(myBreakPoints)
if(myBreakPoints->isSet(PC))
if(myDebugger && myDebugger->start("BP: ", PC))
return true;
if(myBreakPoints.isInitialized() && myBreakPoints.isSet(PC))
if(myDebugger && myDebugger->start("BP: ", PC))
return true;
int cond = evalCondBreaks();
if(cond > -1)
@ -392,7 +386,7 @@ void M6502::attach(Debugger& debugger)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 M6502::addCondBreak(Expression *e, const string& name)
uInt32 M6502::addCondBreak(Expression* e, const string& name)
{
myBreakConds.emplace_back(unique_ptr<Expression>(e));
myBreakCondNames.push_back(name);
@ -421,27 +415,4 @@ const StringList& M6502::getCondBreakNames() const
{
return myBreakCondNames;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 M6502::evalCondBreaks()
{
for(uInt32 i = 0; i < myBreakConds.size(); i++)
if(myBreakConds[i]->evaluate())
return i;
return -1; // no break hit
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6502::setBreakPoints(PackedBitArray *bp)
{
myBreakPoints = bp;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6502::setTraps(PackedBitArray *read, PackedBitArray *write)
{
myReadTraps = read;
myWriteTraps = write;
}
#endif // DEBUGGER_SUPPORT

View File

@ -20,19 +20,20 @@
#ifndef M6502_HXX
#define M6502_HXX
class M6502;
class Debugger;
class CpuDebug;
class Expression;
class PackedBitArray;
#ifdef DEBUGGER_SUPPORT
class Debugger;
class CpuDebug;
#include "Expression.hxx"
#include "PackedBitArray.hxx"
#endif
class Settings;
#include "bspf.hxx"
#include "System.hxx"
#include "Serializable.hxx"
typedef vector<unique_ptr<Expression>> ExpressionList;
/**
The 6502 is an 8-bit microprocessor that has a 64K addressing space.
This class provides a high compatibility 6502 microprocessor emulator.
@ -202,22 +203,18 @@ class M6502 : public Serializable
#ifdef DEBUGGER_SUPPORT
public:
/**
Attach the specified debugger.
@param debugger The debugger to attach to the microprocessor.
*/
// Attach the specified debugger.
void attach(Debugger& debugger);
void setBreakPoints(PackedBitArray* bp);
void setTraps(PackedBitArray* read, PackedBitArray* write);
PackedBitArray& breakPoints() { return myBreakPoints; }
PackedBitArray& readTraps() { return myReadTraps; }
PackedBitArray& writeTraps() { return myWriteTraps; }
uInt32 addCondBreak(Expression* e, const string& name);
void delCondBreak(uInt32 brk);
void clearCondBreaks();
const StringList& getCondBreakNames() const;
Int32 evalCondBreaks();
#endif
#endif // DEBUGGER_SUPPORT
private:
/**
@ -349,12 +346,19 @@ class M6502 : public Serializable
static constexpr uInt32 SYSTEM_CYCLES_PER_CPU = 1;
#ifdef DEBUGGER_SUPPORT
Int32 evalCondBreaks() {
for(uInt32 i = 0; i < myBreakConds.size(); i++)
if(myBreakConds[i]->evaluate())
return i;
return -1; // no break hit
};
/// Pointer to the debugger for this processor or the null pointer
Debugger* myDebugger;
PackedBitArray* myBreakPoints;
PackedBitArray* myReadTraps;
PackedBitArray* myWriteTraps;
// Addresses for which the specified action should occur
PackedBitArray myBreakPoints, myReadTraps, myWriteTraps;
// Did we just now hit a trap?
bool myJustHitTrapFlag;
@ -364,9 +368,9 @@ class M6502 : public Serializable
};
HitTrapInfo myHitTrapInfo;
vector<unique_ptr<Expression>> myBreakConds;
StringList myBreakCondNames;
ExpressionList myBreakConds;
#endif
#endif // DEBUGGER_SUPPORT
};
#endif