Major surgery on the breakpoint support. It all seems to work correctly

now: set/clear a breakpoint, clear all breakpoints, list breakpoints
(including labels in the output!). The 6502 no longer gets "stuck" on a
breakpoint if you quit the debugger while the current PC is a breakpoint.

Some work on the prompt console. The CPU state information shouldn't be
stale any more.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@516 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
urchlay 2005-06-17 03:49:10 +00:00
parent f1617b1db8
commit 379aa0c3ed
11 changed files with 132 additions and 72 deletions

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Debugger.cxx,v 1.12 2005-06-16 16:26:27 stephena Exp $
// $Id: Debugger.cxx,v 1.13 2005-06-17 03:49:08 urchlay Exp $
//============================================================================
#include "bspf.hxx"
@ -44,7 +44,7 @@ Debugger::Debugger(OSystem* osystem)
// Init parser
myParser = new DebuggerParser(this);
equateList = new EquateList();
breakPoints = new PackedBitArray(0xffff);
breakPoints = new PackedBitArray(0x10000);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -65,7 +65,9 @@ void Debugger::initialize()
h = kDebuggerHeight - y;
delete myBaseDialog;
myBaseDialog = new DebuggerDialog(myOSystem, this, x, y, w, h);
DebuggerDialog *dd = new DebuggerDialog(myOSystem, this, x, y, w, h);
myPrompt = dd->prompt();
myBaseDialog = dd;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -101,6 +103,7 @@ const string Debugger::state()
string result;
char buf[255], bbuf[255];
//cerr << "state(): pc is " << myDebugger->pc() << endl;
result += "\nPC=";
result += to_hex_16(myDebugger->pc());
result += " A=";
@ -120,6 +123,11 @@ const string Debugger::state()
sprintf(buf, "%d", mySystem->cycles());
result += buf;
result += "\n ";
char *label = equateList->getLabel(myDebugger->pc());
if(label != NULL) {
result += label;
result += ": ";
}
int count = myDebugger->disassemble(myDebugger->pc(), buf, equateList);
for(int i=0; i<count; i++) {
sprintf(bbuf, "%02x ", readRAM(myDebugger->pc() + i));
@ -257,17 +265,28 @@ const string Debugger::dumpTIA()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::start()
bool Debugger::start()
{
if(myOSystem->eventHandler().state() != EventHandler::S_DEBUGGER)
if(myOSystem->eventHandler().state() != EventHandler::S_DEBUGGER) {
myOSystem->eventHandler().enterDebugMode();
myPrompt->printPrompt();
return true;
} else {
return false;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::quit()
{
if(myOSystem->eventHandler().state() == EventHandler::S_DEBUGGER)
if(myOSystem->eventHandler().state() == EventHandler::S_DEBUGGER) {
// execute one instruction on quit, IF we're
// sitting at a breakpoint. This will get us past it.
// Somehow this feels like a hack to me, but I don't know why
if(breakPoints->isSet(myDebugger->pc()))
mySystem->m6502().execute(1);
myOSystem->eventHandler().leaveDebugMode();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -360,10 +379,13 @@ EquateList *Debugger::equates() {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::toggleBreakPoint(int bp) {
mySystem->m6502().setBreakPoints(breakPoints);
if(bp < 0) bp = myDebugger->pc();
breakPoints->toggle(bp);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Debugger::breakPoint(int bp) {
if(bp < 0) bp = myDebugger->pc();
return breakPoints->isSet(bp) != 0;
}

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Debugger.hxx,v 1.8 2005-06-16 12:28:53 stephena Exp $
// $Id: Debugger.hxx,v 1.9 2005-06-17 03:49:08 urchlay Exp $
//============================================================================
#ifndef DEBUGGER_HXX
@ -30,6 +30,7 @@ class D6502;
#include "M6502.hxx"
#include "EquateList.hxx"
#include "PackedBitArray.hxx"
#include "PromptWidget.hxx"
#include "bspf.hxx"
enum {
@ -48,7 +49,7 @@ enum {
for all debugging operations in Stella (parser, 6502 debugger, etc).
@author Stephen Anthony
@version $Id: Debugger.hxx,v 1.8 2005-06-16 12:28:53 stephena Exp $
@version $Id: Debugger.hxx,v 1.9 2005-06-17 03:49:08 urchlay Exp $
*/
class Debugger : public DialogContainer
{
@ -124,7 +125,7 @@ class Debugger : public DialogContainer
// set a bunch of RAM locations at once
const string setRAM(int argCount, int *args);
void start();
bool start();
void quit();
void trace();
void step();
@ -142,6 +143,7 @@ class Debugger : public DialogContainer
void formatFlags(int f, char *out);
EquateList *equates();
PromptWidget *prompt();
protected:
Console* myConsole;
@ -151,6 +153,7 @@ class Debugger : public DialogContainer
D6502* myDebugger;
EquateList *equateList;
PackedBitArray *breakPoints;
PromptWidget *myPrompt;
};
#endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: DebuggerParser.cxx,v 1.8 2005-06-16 16:18:57 urchlay Exp $
// $Id: DebuggerParser.cxx,v 1.9 2005-06-17 03:49:08 urchlay Exp $
//============================================================================
#include "bspf.hxx"
@ -170,6 +170,24 @@ bool DebuggerParser::subStringMatch(const string& needle, const string& haystack
return false;
}
string DebuggerParser::listBreaks() {
char buf[255];
int count = 0;
string ret;
for(unsigned int i=0; i<0x10000; i++) {
if(debugger->breakPoints->isSet(i)) {
sprintf(buf, "%s ", debugger->equateList->getFormatted(i, 4));
ret += buf;
if(! (++count % 8) ) ret += "\n";
}
}
if(count)
return ret;
else
return "no breakpoints set";
}
string DebuggerParser::run(const string& command) {
string result;
@ -194,7 +212,7 @@ string DebuggerParser::run(const string& command) {
// TODO: de-uglify this somehow. (it may not be worth doing?)
if(subStringMatch(verb, "quit")) {
if(subStringMatch(verb, "quit") || subStringMatch(verb, "run")) {
debugger->quit();
return "";
} else if(subStringMatch(verb, "a")) {
@ -266,44 +284,57 @@ string DebuggerParser::run(const string& command) {
} else if(subStringMatch(verb, "reset")) {
debugger->reset();
} else if(subStringMatch(verb, "break")) {
if(argCount == 1) {
debugger->toggleBreakPoint(args[0]);
if(debugger->breakPoint(args[0]))
return "Set breakpoint";
else
return "Cleared breakpoint";
} else {
return "one argument required";
int bp = -1;
if(argCount > 1) {
return "zero or one arguments required";
} else if(argCount == 0) {
bp = -1;
} else if(argCount == 1) {
bp = args[0];
}
debugger->toggleBreakPoint(bp);
if(debugger->breakPoint(bp))
return "Set breakpoint";
else
return "Cleared breakpoint";
} else if(subStringMatch(verb, "listbreaks")) {
return listBreaks();
} else if(subStringMatch(verb, "clearbreaks")) {
//debugger->clearAllBreakPoints();
return "cleared all breakpoints";
} else if(subStringMatch(verb, "help") || verb == "?") {
// please leave each option on its own line so they're
// easy to sort - bkw
return
"a xx - Set Accumulator to xx\n"
// "break - Show all breakpoints\n"
"break xx - Set/clear breakpoint at address xx\n"
"c - Toggle Carry Flag\n"
"d - Toggle Decimal Flag\n"
"loadsym f - Load DASM symbols from file f\n"
"n - Toggle Negative Flag\n"
"pc xx - Set Program Counter to xx\n"
"ram - Show RIOT RAM contents\n"
"ram xx yy - Set RAM location xx to value yy (multiple values may be given)\n"
"reset - Jump to 6502 init vector (does not reset TIA/RIOT)\n"
"s xx - Set Stack Pointer to xx\n"
"step - Single-step\n"
"tia - Show TIA register contents\n"
"trace - Single-step treating subroutine calls as one instruction\n"
"v - Toggle Overflow Flag\n"
"x xx - Set X register to xx\n"
"y xx - Set Y register to xx\n"
"z - Toggle Zero Flag\n"
"a xx - Set Accumulator to xx\n"
"break - Set/clear breakpoint at current PC\n"
"break xx - Set/clear breakpoint at address xx\n"
"c - Toggle Carry Flag\n"
"clearbreaks - Clear all breakpoints\n"
"d - Toggle Decimal Flag\n"
"listbreaks - List all breakpoints\n"
"loadsym f - Load DASM symbols from file f\n"
"n - Toggle Negative Flag\n"
"pc xx - Set Program Counter to xx\n"
"ram - Show RIOT RAM contents\n"
"ram xx yy - Set RAM location xx to value yy (multiple values may be given)\n"
"reset - Jump to 6502 init vector (does not reset TIA/RIOT)\n"
"run - Exit debugger (back to emulator)\n"
"s xx - Set Stack Pointer to xx\n"
"step - Single-step\n"
"tia - Show TIA register contents\n"
"trace - Single-step treating subroutine calls as one instruction\n"
"v - Toggle Overflow Flag\n"
"x xx - Set X register to xx\n"
"y xx - Set Y register to xx\n"
"z - Toggle Zero Flag\n"
;
} else {
return "unimplemented command (try \"help\")";
}
// result += debugger->state();
return result;
}

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: DebuggerParser.hxx,v 1.4 2005-06-14 03:11:03 urchlay Exp $
// $Id: DebuggerParser.hxx,v 1.5 2005-06-17 03:49:08 urchlay Exp $
//============================================================================
#ifndef DEBUGGER_PARSER_HXX
@ -34,6 +34,7 @@ class DebuggerParser
void setDone();
string run(const string& command);
bool getArgs(const string& command);
string listBreaks();
private:
int DebuggerParser::conv_hex_digit(char d);

View File

@ -2,16 +2,6 @@
#include "bspf.hxx"
#include "PackedBitArray.hxx"
/*
boolean set();
boolean clear();
void set(int bit);
void clear(int bit);
void toggle(int bit);
*/
PackedBitArray::PackedBitArray(int length) {
size = length;
words = length / wordSize + 1;
@ -21,8 +11,6 @@ PackedBitArray::PackedBitArray(int length) {
// start out zeroed already?
for(int i=0; i<words; i++)
bits[i] = 0;
// cerr << "size==" << size << " words==" << words << endl;
}
PackedBitArray::~PackedBitArray() {
@ -47,8 +35,6 @@ void PackedBitArray::toggle(unsigned int bit) {
unsigned int word = bit / wordSize;
bit %= wordSize;
// cerr << "word==" << word << ", bit==" << bit << endl;
bits[word] ^= (1 << bit);
}

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: M6502Hi.cxx,v 1.5 2005-06-16 12:28:54 stephena Exp $
// $Id: M6502Hi.cxx,v 1.6 2005-06-17 03:49:09 urchlay Exp $
//============================================================================
#include "M6502Hi.hxx"
@ -76,8 +76,11 @@ bool M6502High::execute(uInt32 number)
if(breakPoints != NULL)
{
if(breakPoints->isSet(PC))
myDebugger->start();
if(breakPoints->isSet(PC)) {
if(myDebugger->start()) {
return true;
}
}
}
#ifdef DEBUG

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: M6502Low.cxx,v 1.5 2005-06-16 12:28:54 stephena Exp $
// $Id: M6502Low.cxx,v 1.6 2005-06-17 03:49:10 urchlay Exp $
//============================================================================
#include "M6502Low.hxx"
@ -63,7 +63,8 @@ bool M6502Low::execute(uInt32 number)
if(breakPoints != NULL)
{
if(breakPoints->isSet(PC))
myDebugger->start();
if(myDebugger->start())
return true;
}
#ifdef DEBUG

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: DebuggerDialog.cxx,v 1.11 2005-06-16 22:18:02 stephena Exp $
// $Id: DebuggerDialog.cxx,v 1.12 2005-06-17 03:49:10 urchlay Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -40,8 +40,8 @@ DebuggerDialog::DebuggerDialog(OSystem* osystem, DialogContainer* parent,
// 1) The Prompt/console tab
myTab->addTab("Prompt");
PromptWidget* prompt = new PromptWidget(myTab, 2, 2, _w - vBorder, _h - 25);
myTab->setParentWidget(0, prompt, prompt);
myPrompt = new PromptWidget(myTab, 2, 2, _w - vBorder, _h - 25);
myTab->setParentWidget(0, myPrompt, myPrompt);
// 2) The CPU tab
myTab->addTab("CPU");
@ -85,3 +85,8 @@ void DebuggerDialog::handleKeyDown(int ascii, int keycode, int modifiers)
{
myTab->handleKeyDown(ascii, keycode, modifiers);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PromptWidget *DebuggerDialog::prompt() {
return myPrompt;
}

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: DebuggerDialog.hxx,v 1.7 2005-06-16 00:55:59 stephena Exp $
// $Id: DebuggerDialog.hxx,v 1.8 2005-06-17 03:49:10 urchlay Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -27,6 +27,7 @@ class DialogContainer;
class TabWidget;
#include "Dialog.hxx"
#include "PromptWidget.hxx"
class DebuggerDialog : public Dialog
{
@ -35,11 +36,13 @@ class DebuggerDialog : public Dialog
int x, int y, int w, int h);
~DebuggerDialog();
PromptWidget *prompt();
virtual void loadConfig();
virtual void handleKeyDown(int ascii, int keycode, int modifiers);
protected:
TabWidget* myTab;
PromptWidget *myPrompt;
};
#endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: PromptWidget.cxx,v 1.7 2005-06-16 16:18:57 urchlay Exp $
// $Id: PromptWidget.cxx,v 1.8 2005-06-17 03:49:10 urchlay Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -78,7 +78,7 @@ PromptWidget::PromptWidget(GuiObject* boss, int x, int y, int w, int h)
string version = string("Stella version ") + STELLA_VERSION + "\n";
print(version.c_str());
print("Debugger is ready\n");
print( instance()->debugger().state() + "\n"); // FIXME: this doesn't work yet
//print( instance()->debugger().state() + "\n"); // FIXME: this doesn't work yet
print(PROMPT);
_promptStartPos = _promptEndPos = _currentPos;
}
@ -137,6 +137,12 @@ void PromptWidget::handleMouseWheel(int x, int y, int direction)
_scrollBar->handleMouseWheel(x, y, direction);
}
void PromptWidget::printPrompt() {
print( instance()->debugger().state() + "\n");
print(PROMPT);
_promptStartPos = _promptEndPos = _currentPos;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PromptWidget::handleKeyDown(int ascii, int keycode, int modifiers)
{
@ -174,9 +180,7 @@ bool PromptWidget::handleKeyDown(int ascii, int keycode, int modifiers)
delete [] str;
}
print( instance()->debugger().state() + "\n");
print(PROMPT);
_promptStartPos = _promptEndPos = _currentPos;
printPrompt();
draw();
instance()->frameBuffer().refresh();

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: PromptWidget.hxx,v 1.2 2005-06-16 00:56:00 stephena Exp $
// $Id: PromptWidget.hxx,v 1.3 2005-06-17 03:49:10 urchlay Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -49,6 +49,9 @@ class PromptWidget : public Widget, public CommandSender
int vprintf(const char *format, va_list argptr);
#undef putchar
void putchar(int c);
void print(const char *str);
void print(string str);
void printPrompt();
protected:
inline char &buffer(int idx) { return _buffer[idx % kBufferSize]; }
@ -57,8 +60,6 @@ class PromptWidget : public Widget, public CommandSender
void drawCaret();
void putcharIntern(int c);
void insertIntoPrompt(const char *str);
void print(const char *str);
void print(string str);
void updateScrollBuffer();
void scrollToCurrent();