Updated how the debugger is created, and protected against using the

debugger before it has been initialized.

Tweaked the format auto-detection by also looking at the TIA scanline
at which drawing first occurs.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2359 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2012-01-17 22:20:20 +00:00
parent 69db96f441
commit 08ae1c3fe8
14 changed files with 122 additions and 101 deletions

View File

@ -37,6 +37,9 @@
* Fixed compile issues in Irix when using the default compiler
instead of gcc. Thanks go to Rainer M. Canavan for this code.
* Fixed bug in PAL color-loss setting in Video Settings; changing the
settings wouldn't take effect until the ROM was reloaded.
* Added CompuMate bankswitching support to the emulation core;
the SpectraVision Compumate ROM now works.
(FIXME - this may not be complete)

View File

@ -56,7 +56,7 @@
#include "Debugger.hxx"
Debugger* Debugger::myStaticDebugger;
Debugger* Debugger::myStaticDebugger = 0;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static const char* builtin_functions[][3] = {
@ -108,10 +108,10 @@ static const char* pseudo_registers[][2] = {
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Debugger::Debugger(OSystem* osystem)
: DialogContainer(osystem),
myConsole(NULL),
mySystem(NULL),
Debugger::Debugger(OSystem& osystem, Console& console)
: DialogContainer(&osystem),
myConsole(console),
mySystem(console.system()),
myDialog(NULL),
myParser(NULL),
myCartDebug(NULL),
@ -127,6 +127,13 @@ Debugger::Debugger(OSystem* osystem)
{
// Init parser
myParser = new DebuggerParser(this);
// Create debugger subsystems
myCpuDebug = new CpuDebug(*this, myConsole);
myCartDebug = new CartDebug(*this, myConsole, osystem);
myRiotDebug = new RiotDebug(*this, myConsole);
myTiaDebug = new TIADebug(*this, myConsole);
myBreakPoints = new PackedBitArray(0x10000);
myReadTraps = new PackedBitArray(0x10000);
myWriteTraps = new PackedBitArray(0x10000);
@ -142,45 +149,21 @@ Debugger::Debugger(OSystem* osystem)
Debugger::~Debugger()
{
delete myParser;
delete myCartDebug;
delete myCpuDebug;
delete myRiotDebug;
delete myTiaDebug;
delete myBreakPoints;
delete myReadTraps;
delete myWriteTraps;
delete myRewindManager;
myStaticDebugger = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::initialize(Console* console)
void Debugger::initialize()
{
assert(console);
// Keep pointers to these items for efficiency
myConsole = console;
mySystem = &(myConsole->system());
// Create debugger subsystems
delete myCpuDebug;
myCpuDebug = new CpuDebug(*this, *myConsole);
delete myCartDebug;
myCartDebug = new CartDebug(*this, *myConsole, *myOSystem);
delete myRiotDebug;
myRiotDebug = new RiotDebug(*this, *myConsole);
delete myTiaDebug;
myTiaDebug = new TIADebug(*this, *myConsole);
// Initialize breakpoints to known state
clearAllBreakPoints();
clearAllTraps();
// Get the dialog size
int w, h;
myOSystem->settings().getSize("debuggerres", w, h);
@ -375,7 +358,7 @@ string Debugger::setRAM(IntArray& args)
int count = args.size();
int address = args[0];
for(int i = 1; i < count; ++i)
mySystem->poke(address++, args[i]);
mySystem.poke(address++, args[i]);
buf << "changed " << (count-1) << " location";
if(count != 2)
@ -386,7 +369,7 @@ string Debugger::setRAM(IntArray& args)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::saveState(int state)
{
mySystem->clearDirtyPages();
mySystem.clearDirtyPages();
unlockBankswitchState();
myOSystem->state().saveState(state);
@ -396,7 +379,7 @@ void Debugger::saveState(int state)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::loadState(int state)
{
mySystem->clearDirtyPages();
mySystem.clearDirtyPages();
unlockBankswitchState();
myOSystem->state().loadState(state);
@ -407,15 +390,15 @@ void Debugger::loadState(int state)
int Debugger::step()
{
saveOldState();
mySystem->clearDirtyPages();
mySystem.clearDirtyPages();
int cyc = mySystem->cycles();
int cyc = mySystem.cycles();
unlockBankswitchState();
myOSystem->console().tia().updateScanlineByStep();
lockBankswitchState();
return mySystem->cycles() - cyc;
return mySystem.cycles() - cyc;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -432,19 +415,19 @@ int Debugger::step()
int Debugger::trace()
{
// 32 is the 6502 JSR instruction:
if(mySystem->peek(myCpuDebug->pc()) == 32)
if(mySystem.peek(myCpuDebug->pc()) == 32)
{
saveOldState();
mySystem->clearDirtyPages();
mySystem.clearDirtyPages();
int cyc = mySystem->cycles();
int cyc = mySystem.cycles();
int targetPC = myCpuDebug->pc() + 3; // return address
unlockBankswitchState();
myOSystem->console().tia().updateScanlineByTrace(targetPC);
lockBankswitchState();
return mySystem->cycles() - cyc;
return mySystem.cycles() - cyc;
}
else
return step();
@ -453,7 +436,7 @@ int Debugger::trace()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::toggleBreakPoint(int bp)
{
mySystem->m6502().setBreakPoints(myBreakPoints);
mySystem.m6502().setBreakPoints(myBreakPoints);
if(bp < 0) bp = myCpuDebug->pc();
myBreakPoints->toggle(bp);
}
@ -461,7 +444,7 @@ void Debugger::toggleBreakPoint(int bp)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::setBreakPoint(int bp, bool set)
{
mySystem->m6502().setBreakPoints(myBreakPoints);
mySystem.m6502().setBreakPoints(myBreakPoints);
if(bp < 0) bp = myCpuDebug->pc();
if(set)
myBreakPoints->set(bp);
@ -479,14 +462,14 @@ bool Debugger::breakPoint(int bp)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::toggleReadTrap(int t)
{
mySystem->m6502().setTraps(myReadTraps, myWriteTraps);
mySystem.m6502().setTraps(myReadTraps, myWriteTraps);
myReadTraps->toggle(t);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::toggleWriteTrap(int t)
{
mySystem->m6502().setTraps(myReadTraps, myWriteTraps);
mySystem.m6502().setTraps(myReadTraps, myWriteTraps);
myWriteTraps->toggle(t);
}
@ -512,14 +495,14 @@ bool Debugger::writeTrap(int t)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int Debugger::cycles()
{
return mySystem->cycles();
return mySystem.cycles();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::nextScanline(int lines)
{
saveOldState();
mySystem->clearDirtyPages();
mySystem.clearDirtyPages();
unlockBankswitchState();
while(lines)
@ -534,7 +517,7 @@ void Debugger::nextScanline(int lines)
void Debugger::nextFrame(int frames)
{
saveOldState();
mySystem->clearDirtyPages();
mySystem.clearDirtyPages();
unlockBankswitchState();
while(frames)
@ -548,7 +531,7 @@ void Debugger::nextFrame(int frames)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Debugger::rewindState()
{
mySystem->clearDirtyPages();
mySystem.clearDirtyPages();
unlockBankswitchState();
bool result = myRewindManager->rewindState();
@ -562,7 +545,7 @@ void Debugger::clearAllBreakPoints()
{
delete myBreakPoints;
myBreakPoints = new PackedBitArray(0x10000);
mySystem->m6502().setBreakPoints(NULL);
mySystem.m6502().setBreakPoints(NULL);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -572,7 +555,7 @@ void Debugger::clearAllTraps()
delete myWriteTraps;
myReadTraps = new PackedBitArray(0x10000);
myWriteTraps = new PackedBitArray(0x10000);
mySystem->m6502().setTraps(NULL, NULL);
mySystem.m6502().setTraps(NULL, NULL);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -584,11 +567,11 @@ string Debugger::showWatches()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Debugger::setBank(int bank)
{
if(myConsole->cartridge().bankCount() > 1)
if(myConsole.cartridge().bankCount() > 1)
{
myConsole->cartridge().unlockBank();
bool status = myConsole->cartridge().bank(bank);
myConsole->cartridge().lockBank();
myConsole.cartridge().unlockBank();
bool status = myConsole.cartridge().bank(bank);
myConsole.cartridge().lockBank();
return status;
}
return false;
@ -597,7 +580,7 @@ bool Debugger::setBank(int bank)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Debugger::patchROM(int addr, int value)
{
return myConsole->cartridge().patch(addr, value);
return myConsole.cartridge().patch(addr, value);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -638,7 +621,7 @@ void Debugger::setQuitState()
// 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()))
mySystem->m6502().execute(1);
mySystem.m6502().execute(1);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -833,7 +816,7 @@ string Debugger::saveROM(const string& filename) const
FilesystemNode node(path);
ofstream out(node.getPath().c_str(), ios::out | ios::binary);
if(out.is_open() && myConsole->cartridge().save(out))
if(out.is_open() && myConsole.cartridge().save(out))
return node.getRelativePath();
else
return "";
@ -842,15 +825,15 @@ string Debugger::saveROM(const string& filename) const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::lockBankswitchState()
{
mySystem->lockDataBus();
myConsole->cartridge().lockBank();
mySystem.lockDataBus();
myConsole.cartridge().lockBank();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::unlockBankswitchState()
{
mySystem->unlockDataBus();
myConsole->cartridge().unlockBank();
mySystem.unlockDataBus();
myConsole.cartridge().unlockBank();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -83,7 +83,7 @@ class Debugger : public DialogContainer
/**
Create a new debugger parent object
*/
Debugger(OSystem* osystem);
Debugger(OSystem& osystem, Console& console);
/**
Destructor
@ -92,11 +92,9 @@ class Debugger : public DialogContainer
public:
/**
Updates the basedialog to be of the type defined for this derived class.
@param console The console to use for this debugging session.
Initialize the debugger dialog container.
*/
void initialize(Console* console);
void initialize();
/**
Initialize the video subsystem wrt this class.
@ -233,12 +231,12 @@ class Debugger : public DialogContainer
GUI::Rect getTabBounds() const;
/* These are now exposed so Expressions can use them. */
int peek(int addr) { return mySystem->peek(addr); }
int dpeek(int addr) { return mySystem->peek(addr) | (mySystem->peek(addr+1) << 8); }
int peek(int addr) { return mySystem.peek(addr); }
int dpeek(int addr) { return mySystem.peek(addr) | (mySystem.peek(addr+1) << 8); }
int getAccessFlags(uInt16 addr)
{ return mySystem->getAccessFlags(addr); }
{ return mySystem.getAccessFlags(addr); }
void setAccessFlags(uInt16 addr, uInt8 flags)
{ mySystem->setAccessFlags(addr, flags); }
{ mySystem.setAccessFlags(addr, flags); }
void setBreakPoint(int bp, bool set);
@ -303,8 +301,8 @@ class Debugger : public DialogContainer
void loadState(int state);
private:
Console* myConsole;
System* mySystem;
Console& myConsole;
System& mySystem;
DebuggerDialog* myDialog;
DebuggerParser* myParser;

View File

@ -296,7 +296,8 @@ void Cartridge::registerRamArea(uInt16 start, uInt16 size,
void Cartridge::triggerReadFromWritePort(uInt16 address)
{
#ifdef DEBUGGER_SUPPORT
Debugger::debugger().cartDebug().triggerReadFromWritePort(address);
if(!mySystem->autodectMode())
Debugger::debugger().cartDebug().triggerReadFromWritePort(address);
#endif
}

View File

@ -98,9 +98,6 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props)
myControllers[1] = new Joystick(Controller::Right, myEvent, *mySystem);
M6502* m6502 = new M6502(1);
#ifdef DEBUGGER_SUPPORT
m6502->attach(myOSystem->debugger());
#endif
myRiot = new M6532(*this, myOSystem->settings());
myTIA = new TIA(*this, myOSystem->sound(), myOSystem->settings());
@ -116,10 +113,16 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props)
if(myDisplayFormat == "AUTO-DETECT" ||
myOSystem->settings().getBool("rominfo"))
{
// Run the system for 60 frames, looking for PAL scanline patterns
// Run the TIA, looking for PAL scanline patterns
// We turn off the SuperCharger progress bars, otherwise the SC BIOS
// will take over 250 frames!
// The 'fastscbios' option must be changed before the system is reset
// The algorithm used is as follows:
// Run for 60 frames, only consider frames in appropriate scanline range
// If there's a frame that starts drawing at scanline 50 or
// has more than 287 scanlines, count it as PAL
// If at least 20 PAL frames are found, then the format is PAL, else NTSC
bool fastscbios = myOSystem->settings().getBool("fastscbios");
myOSystem->settings().setBool("fastscbios", true);
mySystem->reset(true); // autodetect in reset enabled
@ -127,10 +130,13 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props)
for(int i = 0; i < 60; ++i)
{
myTIA->update();
if(myTIA->scanlines() > 285)
int lines = myTIA->scanlines() - myTIA->startLine();
if((lines >= 180 && lines <= 342) &&
(myTIA->startLine() >= 50 || myTIA->scanlines() >= 287))
++palCount;
}
myDisplayFormat = (palCount >= 20) ? "PAL" : "NTSC";
myDisplayFormat = (palCount >= 25) ? "PAL" : "NTSC";
if(myProperties.get(Display_Format) == "AUTO-DETECT")
autodetected = "*";
@ -202,7 +208,8 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props)
mySystem->reset();
#ifdef DEBUGGER_SUPPORT
myOSystem->debugger().initialize(this);
myOSystem->createDebugger(*this);
m6502->attach(myOSystem->debugger());
#endif
// Finally, add remaining info about the console
@ -331,6 +338,12 @@ void Console::toggleColorLoss()
myOSystem->frameBuffer().showMessage(message);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::toggleColorLoss(bool state)
{
myTIA->enableColorLoss(state);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::togglePalette()
{

View File

@ -88,7 +88,7 @@ class Console : public Serializable
*/
Controller& controller(Controller::Jack jack) const
{
return (jack == Controller::Left) ? *myControllers[0] : *myControllers[1];
return *myControllers[jack];
}
/**
@ -204,6 +204,7 @@ class Console : public Serializable
Toggles the PAL color-loss effect.
*/
void toggleColorLoss();
void toggleColorLoss(bool state);
/**
Initialize the video subsystem wrt this class.

View File

@ -71,7 +71,7 @@ class Controller : public Serializable
/**
Enumeration of the controller jacks
*/
enum Jack { Left, Right };
enum Jack { Left = 0, Right = 1 };
/**
Enumeration of the digital pins of a controller port

View File

@ -245,7 +245,7 @@ bool M6502::execute(uInt32 number)
#ifdef DEBUGGER_SUPPORT
if(myJustHitTrapFlag)
{
if(myDebugger->start(myHitTrapInfo.message, myHitTrapInfo.address))
if(myDebugger && myDebugger->start(myHitTrapInfo.message, myHitTrapInfo.address))
{
myJustHitTrapFlag = false;
return true;
@ -256,7 +256,7 @@ bool M6502::execute(uInt32 number)
{
if(myBreakPoints->isSet(PC))
{
if(myDebugger->start("BP: ", PC))
if(myDebugger && myDebugger->start("BP: ", PC))
return true;
}
}
@ -265,7 +265,7 @@ bool M6502::execute(uInt32 number)
if(cond > -1)
{
string buf = "CBP: " + myBreakCondNames[cond];
if(myDebugger->start(buf))
if(myDebugger && myDebugger->start(buf))
return true;
}
#endif
@ -471,7 +471,7 @@ void M6502::attach(Debugger& debugger)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unsigned int M6502::addCondBreak(Expression *e, const string& name)
uInt32 M6502::addCondBreak(Expression *e, const string& name)
{
myBreakConds.push_back(e);
myBreakCondNames.push_back(name);
@ -479,7 +479,7 @@ unsigned int M6502::addCondBreak(Expression *e, const string& name)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6502::delCondBreak(unsigned int brk)
void M6502::delCondBreak(uInt32 brk)
{
if(brk < myBreakConds.size())
{
@ -506,7 +506,7 @@ const StringList& M6502::getCondBreakNames() const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int M6502::evalCondBreaks()
Int32 M6502::evalCondBreaks()
{
for(uInt32 i = 0; i < myBreakConds.size(); i++)
if(myBreakConds[i]->evaluate())

View File

@ -217,11 +217,11 @@ class M6502 : public Serializable
void setBreakPoints(PackedBitArray* bp);
void setTraps(PackedBitArray* read, PackedBitArray* write);
unsigned int addCondBreak(Expression* e, const string& name);
void delCondBreak(unsigned int brk);
uInt32 addCondBreak(Expression* e, const string& name);
void delCondBreak(uInt32 brk);
void clearCondBreaks();
const StringList& getCondBreakNames() const;
int evalCondBreaks();
Int32 evalCondBreaks();
#endif
private:

View File

@ -280,9 +280,6 @@ bool OSystem::create()
myMenu = new Menu(this);
myCommandMenu = new CommandMenu(this);
myLauncher = new Launcher(this);
#ifdef DEBUGGER_SUPPORT
myDebugger = new Debugger(this);
#endif
myStateManager = new StateManager(this);
// Create the sound object; the sound subsystem isn't actually
@ -310,6 +307,16 @@ bool OSystem::create()
return true;
}
#ifdef DEBUGGER_SUPPORT
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void OSystem::createDebugger(Console& console)
{
delete myDebugger; myDebugger = NULL;
myDebugger = new Debugger(*this, console);
myDebugger->initialize();
}
#endif
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void OSystem::setConfigPaths()
{
@ -588,6 +595,7 @@ void OSystem::deleteConsole()
logMessage(buf.str(), 1);
delete myConsole; myConsole = NULL;
delete myDebugger; myDebugger = NULL;
}
}

View File

@ -165,6 +165,11 @@ class OSystem
StateManager& state() const { return *myStateManager; }
#ifdef DEBUGGER_SUPPORT
/**
Create all child objects which belong to this OSystem
*/
void createDebugger(Console& console);
/**
Get the ROM debugger of the system.

View File

@ -50,6 +50,7 @@ TIA::TIA(Console& console, Sound& sound, Settings& settings)
myFrameYStart(34),
myFrameHeight(210),
myMaximumNumberOfScanlines(262),
myStartScanline(0),
myColorLossEnabled(false),
myPartialFrameFlag(false),
myAutoFrameEnabled(false),
@ -601,8 +602,8 @@ inline void TIA::startFrame()
myColor[M1Color] &= 0xfefefefe;
myColor[BLColor] &= 0xfefefefe;
}
}
myStartScanline = 0x7FFFFFFF;
}
myStartScanline = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1331,12 +1332,10 @@ bool TIA::poke(uInt16 addr, uInt8 value)
if (!(myVBLANK & 0x40))
myINPT4 = myINPT5 = 0x80;
#if 0 // TODO - this isn't yet complete
// Check for the first scanline at which VBLANK is disabled.
// Usually, this will be the first scanline to start drawing.
if(myStartScanline == 0x7FFFFFFF && !(value & 0x10))
if(myStartScanline == 0 && !(value & 0x10))
myStartScanline = scanlines();
#endif
myVBLANK = value;
break;

View File

@ -224,6 +224,14 @@ class TIA : public Device
uInt32 clocksThisLine() const
{ return ((mySystem->cycles() * 3) - myClockWhenFrameStarted) % 228; }
/**
Answers the scanline at which the current frame began drawing.
@return The starting scanline
*/
uInt32 startLine() const
{ return myStartScanline; }
/**
Answers the total number of scanlines the TIA generated in producing
the current frame buffer. For partial frames, this will be the

View File

@ -416,6 +416,8 @@ void VideoDialog::saveConfig()
// PAL color-loss effect
instance().settings().setBool("colorloss", myColorLossCheckbox->getState());
if(&instance().console())
instance().console().toggleColorLoss(myColorLossCheckbox->getState());
// GL stretch setting
instance().settings().setBool("gl_fsmax", myGLStretchCheckbox->getState());