diff --git a/docs/index.html b/docs/index.html
index 7c8126ba5..88c55e07c 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -1025,6 +1025,12 @@
Description |
+
+ -autocode <0|1|2> |
+ Try to differentiate between code vs. data sections in the
+ disassembler. See the Debugger section for more information. |
+
+
-debuggerres <WxH> |
Set the size of the debugger window. |
diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx
index 314cfec13..764c100f6 100644
--- a/src/debugger/CartDebug.cxx
+++ b/src/debugger/CartDebug.cxx
@@ -184,61 +184,88 @@ string CartDebug::toString()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool CartDebug::disassemble(bool autocode)
+bool CartDebug::disassemble(const string& autocode, bool force)
{
// Test current disassembly; don't re-disassemble if it hasn't changed
- // ...
- bool changed = myConsole.cartridge().bankChanged();
+ // Also check if the current PC is in the current list
+ uInt16 PC = myDebugger.cpuDebug().pc();
+ bool changed = force || myConsole.cartridge().bankChanged() ||
+ (addressToLine(PC) == -1);
if(changed)
{
- myDisassembly.clear();
- myAddrToLineList.clear();
-
// We only use the reset vector when we're actually in the startup bank
// Otherwise, we look at previous accesses to this bank to begin
// If no previous address exists, use the current program counter
uInt16 start = myStartAddresses[getBank()];
+ if(start == 0)
+ start = myStartAddresses[getBank()] = PC;
+ // For now, DiStella can't handle address space below 0x1000
+ if(!(start & 0x1000))
+ return false;
+
+#if 0
cerr << "start addresses: ";
for(int i = 0; i < myConsole.cartridge().bankCount(); ++i) cerr << " " << setw(4) << hex << myStartAddresses[i];
cerr << endl;
cerr << "current bank = " << getBank() << ", start bank = " << myConsole.cartridge().startBank() << endl
- << "reset = " << hex << 0xfffc << ", pc = " << hex << myDebugger.cpuDebug().pc() << endl
- << "start = " << hex << start << endl;
- if(start == 0)
- start = myStartAddresses[getBank()] = myDebugger.cpuDebug().pc();
-cerr << "actual start = " << hex << start << endl << endl;
+ << "reset = " << hex << 0xfffc << ", pc = " << hex << PC << endl
+ << "start = " << hex << start << endl << endl;
+#endif
- // For now, DiStella can't handle address space below 0x1000
- if(!(start & 0x1000))
- return true;
-
-autocode = false;
- DiStella distella(myDisassembly, start, autocode);
-
- // Parts of the disassembly will be accessed later in different ways
- // We place those parts in separate maps, to speed up access
- for(uInt32 i = 0; i < myDisassembly.size(); ++i)
+ // Check whether to use the 'autocode' functionality from Distella
+ if(autocode == "0") // 'never'
+ fillDisassemblyList(start, false, PC);
+ else if(autocode == "1") // always
+ fillDisassemblyList(start, true, PC);
+ else // automatic
{
- const DisassemblyTag& tag = myDisassembly[i];
-
- // Create a mapping from addresses to line numbers
- if(tag.address != 0)
- myAddrToLineList.insert(make_pair(tag.address, i));
-
- // TODO - look at list, extract address to label mappings
- // we need these for label support in the UI and promptwidget
+ // First try with autocode on, then turn off if PC isn't found
+ if(!fillDisassemblyList(start, true, PC))
+ fillDisassemblyList(start, false, PC);
}
}
return changed;
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+bool CartDebug::fillDisassemblyList(uInt16 start, bool autocode, uInt16 search)
+{
+ bool found = false;
+
+ myDisassembly.clear();
+ DiStella distella(myDisassembly, start, autocode);
+
+ // Parts of the disassembly will be accessed later in different ways
+ // We place those parts in separate maps, to speed up access
+ myAddrToLineList.clear();
+ for(uInt32 i = 0; i < myDisassembly.size(); ++i)
+ {
+ const DisassemblyTag& tag = myDisassembly[i];
+
+ // Only non-zero addresses are valid
+ if(tag.address != 0)
+ {
+ // Create a mapping from addresses to line numbers
+ myAddrToLineList.insert(make_pair(tag.address, i));
+
+ // Did we find the search value?
+ if(tag.address == search)
+ found = true;
+ }
+
+ // TODO - look at list, extract address to label mappings
+ // we need these for label support in the UI and promptwidget
+ }
+ return found;
+}
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int CartDebug::addressToLine(uInt16 address) const
{
map::const_iterator iter = myAddrToLineList.find(address);
- return iter != myAddrToLineList.end() ? iter->second : 0;
+ return iter != myAddrToLineList.end() ? iter->second : -1;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/src/debugger/CartDebug.hxx b/src/debugger/CartDebug.hxx
index 869a3e939..af83bc190 100644
--- a/src/debugger/CartDebug.hxx
+++ b/src/debugger/CartDebug.hxx
@@ -100,9 +100,12 @@ class CartDebug : public DebuggerSystem
Disassemble from the given address using the Distella disassembler
Address-to-label mappings (and vice-versa) are also determined here
+ @param autocode Whether to determine code vs data sections
+ @param force Force a re-disassembly, even if the state hasn't changed
+
@return True if disassembly changed from previous call, else false
*/
- bool disassemble(bool autocode);
+ bool disassemble(const string& autocode, bool force = false);
/**
Get the results from the most recent call to disassemble()
@@ -178,6 +181,10 @@ class CartDebug : public DebuggerSystem
};
AddrType addressType(uInt16 addr) const;
+ // Actually call DiStella to fill the DisassemblyList structure
+ // Return whether the search address was actually in the list
+ bool fillDisassemblyList(uInt16 start, bool autocode, uInt16 search);
+
// Extract labels and values from the given character stream
string extractLabel(char *c) const;
int extractValue(char *c) const;
diff --git a/src/debugger/DiStella.cxx b/src/debugger/DiStella.cxx
index 6c1db376c..503daa274 100644
--- a/src/debugger/DiStella.cxx
+++ b/src/debugger/DiStella.cxx
@@ -24,7 +24,7 @@
DiStella::DiStella(CartDebug::DisassemblyList& list, uInt16 start,
bool autocode)
: myList(list),
- labels(NULL) /* array of information about addresses-- can be from 2K-48K bytes in size */
+ labels(NULL) /* array of information about addresses */
{
while(!myAddressQueue.empty())
myAddressQueue.pop();
diff --git a/src/debugger/DiStella.hxx b/src/debugger/DiStella.hxx
index 20d898675..2e5a2a4bc 100644
--- a/src/debugger/DiStella.hxx
+++ b/src/debugger/DiStella.hxx
@@ -49,8 +49,7 @@ class DiStella
@param start The address at which to start disassembly
@param autocode If enabled, try to determine code vs. data sections
*/
- DiStella(CartDebug::DisassemblyList& list, uInt16 start,
- bool autocode = true);
+ DiStella(CartDebug::DisassemblyList& list, uInt16 start, bool autocode = true);
~DiStella();
diff --git a/src/debugger/PackedBitArray.cxx b/src/debugger/PackedBitArray.cxx
index d316eba59..c88210287 100644
--- a/src/debugger/PackedBitArray.cxx
+++ b/src/debugger/PackedBitArray.cxx
@@ -19,50 +19,64 @@
#include "bspf.hxx"
#include "PackedBitArray.hxx"
-PackedBitArray::PackedBitArray(int length) {
- size = length;
- words = length / wordSize + 1;
- bits = new unsigned int[ words ];
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+PackedBitArray::PackedBitArray(uInt32 length)
+ : size(length),
+ words(length / wordSize + 1)
+{
+ bits = new uInt32[ words ];
- for(int i=0; idialog().surface();
int row, col, deltax;
- string buffer;
// Draw the internal grid and labels
int linewidth = _cols * _colWidth;
@@ -542,16 +541,14 @@ void DataGridWidget::drawWidget(bool hilite)
if (_selectedItem == pos && _editMode)
{
- buffer = _editString;
adjustOffset();
deltax = -_editScrollOffset;
- s.drawString(_font, buffer, x, y, _colWidth, kTextColor,
+ s.drawString(_font, _editString, x, y, _colWidth, kTextColor,
kTextAlignLeft, deltax, false);
}
else
{
- buffer = _valueStringList[pos];
deltax = 0;
uInt32 color = kTextColor;
@@ -567,7 +564,7 @@ void DataGridWidget::drawWidget(bool hilite)
else if(_hiliteList[pos])
color = kDbgColorHi;
- s.drawString(_font, buffer, x, y, _colWidth, color);
+ s.drawString(_font, _valueStringList[pos], x, y, _colWidth, color);
}
}
}
diff --git a/src/debugger/gui/RomListWidget.cxx b/src/debugger/gui/RomListWidget.cxx
index 811d06c9e..2d83fcc62 100644
--- a/src/debugger/gui/RomListWidget.cxx
+++ b/src/debugger/gui/RomListWidget.cxx
@@ -20,17 +20,44 @@
//============================================================================
#include "bspf.hxx"
+#include "Debugger.hxx"
#include "ContextMenu.hxx"
+#include "Widget.hxx"
+#include "ScrollBarWidget.hxx"
#include "RomListWidget.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RomListWidget::RomListWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, int w, int h)
- : CheckListWidget(boss, font, x, y, w, h),
- myMenu(NULL)
+ : EditableWidget(boss, font, x, y, 16, 16),
+ myMenu(NULL),
+ _rows(0),
+ _cols(0),
+ _currentPos(0),
+ _selectedItem(-1),
+ _highlightedItem(-1),
+ _currentKeyDown(0),
+ _editMode(false)
{
+ _flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS;
_type = kRomListWidget;
+ _bgcolor = kWidColor;
+ _bgcolorhi = kWidColor;
+ _textcolor = kTextColor;
+ _textcolorhi = kTextColor;
+ _cols = w / _fontWidth;
+ _rows = h / _fontHeight;
+
+ // Set real dimensions
+ _w = w - kScrollBarWidth;
+ _h = h + 2;
+
+ // Create scrollbar and attach to the list
+ myScrollBar = new ScrollBarWidget(boss, font, _x + _w, _y, kScrollBarWidth, _h);
+ myScrollBar->setTarget(this);
+
+ // Add context menu
StringMap l;
// l.push_back("Add bookmark");
l.push_back("Save ROM", "saverom");
@@ -43,6 +70,30 @@ RomListWidget::RomListWidget(GuiObject* boss, const GUI::Font& font,
myLabelWidth = BSPF_max(16, int(0.35 * (numchars - 12))) * fontWidth;
myBytesWidth = 12 * fontWidth;
+
+ //////////////////////////////////////////////////////
+ // Add checkboxes
+ int ypos = _y + 2;
+
+ // rowheight is determined by largest item on a line,
+ // possibly meaning that number of rows will change
+ _fontHeight = BSPF_max(_fontHeight, CheckboxWidget::boxSize());
+ _rows = h / _fontHeight;
+
+ // Create a CheckboxWidget for each row in the list
+ CheckboxWidget* t;
+ for(int i = 0; i < _rows; ++i)
+ {
+ t = new CheckboxWidget(boss, font, _x + 2, ypos, "", kCheckActionCmd);
+ t->setTarget(this);
+ t->setID(i);
+ t->drawBox(false);
+ t->setFill(true);
+ t->setTextColor(kTextColorEm);
+ ypos += _fontHeight;
+
+ myCheckList.push_back(t);
+ }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -53,20 +104,115 @@ RomListWidget::~RomListWidget()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RomListWidget::setList(const CartDebug::DisassemblyList& list,
- const BoolArray& state)
+ const PackedBitArray& state)
{
myList = &list;
+ myBPState = &state;
- // TODO - maybe there's a better way than copying all the bytes again??
- StringList bytes;
- for(uInt32 i = 0; i < list.size(); ++i)
- bytes.push_back(list[i].bytes);
- CheckListWidget::setList(bytes, state);
+ // Enable all checkboxes
+ for(int i = 0; i < _rows; ++i)
+ myCheckList[i]->setFlags(WIDGET_ENABLED);
+
+ // Then turn off any extras
+ if((int)myList->size() < _rows)
+ for(int i = myList->size(); i < _rows; ++i)
+ myCheckList[i]->clearFlags(WIDGET_ENABLED);
+
+ recalc();
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void RomListWidget::setHighlighted(int item)
+{
+ if(item < -1 || item >= (int)myList->size())
+ return;
+
+ if(isEnabled())
+ {
+ if(_editMode)
+ abortEditMode();
+
+ _highlightedItem = item;
+
+ // Only scroll the list if we're about to pass the page boundary
+ if(_currentPos == 0)
+ _currentPos = _highlightedItem;
+ else if(_highlightedItem == _currentPos + _rows)
+ _currentPos += _rows;
+
+ scrollToHighlighted();
+ }
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+const string& RomListWidget::getEditString() const
+{
+ if(_selectedItem < -1 || _selectedItem >= (int)myList->size())
+ return EmptyString;
+ else
+ return _editString;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+int RomListWidget::findItem(int x, int y) const
+{
+ return (y - 1) / _fontHeight + _currentPos;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void RomListWidget::recalc()
+{
+ int size = myList->size();
+
+ if (_currentPos >= size)
+ _currentPos = size - 1;
+ if (_currentPos < 0)
+ _currentPos = 0;
+
+ if(_selectedItem < 0 || _selectedItem >= size)
+ _selectedItem = 0;
+
+ _editMode = false;
+
+ myScrollBar->_numEntries = myList->size();
+ myScrollBar->_entriesPerPage = _rows;
+
+ // Reset to normal data entry
+ abortEditMode();
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void RomListWidget::scrollToCurrent(int item)
+{
+ // Only do something if the current item is not in our view port
+ if (item < _currentPos)
+ {
+ // it's above our view
+ _currentPos = item;
+ }
+ else if (item >= _currentPos + _rows )
+ {
+ // it's below our view
+ _currentPos = item - _rows + 1;
+ }
+
+ if (_currentPos < 0 || _rows > (int)myList->size())
+ _currentPos = 0;
+ else if (_currentPos + _rows > (int)myList->size())
+ _currentPos = myList->size() - _rows;
+
+ myScrollBar->_currentPos = _currentPos;
+ myScrollBar->recalc();
+
+ setDirty(); draw();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RomListWidget::handleMouseDown(int x, int y, int button, int clickCount)
{
+ if (!isEnabled())
+ return;
+
// Grab right mouse button for context menu, send left to base class
if(button == 2)
{
@@ -74,13 +220,184 @@ void RomListWidget::handleMouseDown(int x, int y, int button, int clickCount)
myMenu->show(x + getAbsX(), y + getAbsY());
}
else
- ListWidget::handleMouseDown(x, y, button, clickCount);
+ {
+ // First check whether the selection changed
+ int newSelectedItem;
+ newSelectedItem = findItem(x, y);
+ if (newSelectedItem > (int)myList->size() - 1)
+ newSelectedItem = -1;
+
+ if (_selectedItem != newSelectedItem)
+ {
+ if (_editMode)
+ abortEditMode();
+ _selectedItem = newSelectedItem;
+ setDirty(); draw();
+ }
+ }
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void RomListWidget::handleMouseUp(int x, int y, int button, int clickCount)
+{
+ // If this was a double click and the mouse is still over the selected item,
+ // send the double click command
+ if (clickCount == 2 && (_selectedItem == findItem(x, y)))
+ {
+ // Start edit mode
+ if(_editable && !_editMode)
+ startEditMode();
+ }
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void RomListWidget::handleMouseWheel(int x, int y, int direction)
+{
+ myScrollBar->handleMouseWheel(x, y, direction);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+bool RomListWidget::handleKeyDown(int ascii, int keycode, int modifiers)
+{
+ // Ignore all Alt-mod keys
+ if(instance().eventHandler().kbdAlt(modifiers))
+ return true;
+
+ bool handled = true;
+ int oldSelectedItem = _selectedItem;
+
+ if (_editMode)
+ {
+ // Class EditableWidget handles all text editing related key presses for us
+ handled = EditableWidget::handleKeyDown(ascii, keycode, modifiers);
+ }
+ else
+ {
+ // not editmode
+ switch (keycode)
+ {
+ case ' ': // space
+ // Snap list back to currently highlighted line
+ if(_highlightedItem >= 0)
+ {
+ _currentPos = _highlightedItem;
+ scrollToHighlighted();
+ }
+ break;
+
+ default:
+ handled = false;
+ }
+ }
+
+ if (_selectedItem != oldSelectedItem)
+ {
+ myScrollBar->draw();
+ scrollToSelected();
+ }
+
+ _currentKeyDown = keycode;
+ return handled;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+bool RomListWidget::handleKeyUp(int ascii, int keycode, int modifiers)
+{
+ if (keycode == _currentKeyDown)
+ _currentKeyDown = 0;
+ return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool RomListWidget::handleEvent(Event::Type e)
{
- return ListWidget::handleEvent(e); // override CheckListWidget::handleEvent()
+ if(!isEnabled() || _editMode)
+ return false;
+
+ bool handled = true;
+ int oldSelectedItem = _selectedItem;
+
+ switch(e)
+ {
+ case Event::UISelect:
+ if (_selectedItem >= 0)
+ {
+ if (_editable)
+ startEditMode();
+ }
+ break;
+
+ case Event::UIUp:
+ if (_selectedItem > 0)
+ _selectedItem--;
+ break;
+
+ case Event::UIDown:
+ if (_selectedItem < (int)myList->size() - 1)
+ _selectedItem++;
+ break;
+
+ case Event::UIPgUp:
+ _selectedItem -= _rows - 1;
+ if (_selectedItem < 0)
+ _selectedItem = 0;
+ break;
+
+ case Event::UIPgDown:
+ _selectedItem += _rows - 1;
+ if (_selectedItem >= (int)myList->size() )
+ _selectedItem = myList->size() - 1;
+ break;
+
+ case Event::UIHome:
+ _selectedItem = 0;
+ break;
+
+ case Event::UIEnd:
+ _selectedItem = myList->size() - 1;
+ break;
+
+ default:
+ handled = false;
+ }
+
+ if (_selectedItem != oldSelectedItem)
+ {
+ myScrollBar->draw();
+ scrollToSelected();
+ }
+
+ return handled;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void RomListWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
+{
+ switch (cmd)
+ {
+ case kCheckActionCmd:
+ // We let the parent class handle this
+ // Pass it as a kRLBreakpointChangedCmd command, since that's the intent
+ sendCommand(kRLBreakpointChangedCmd, myCheckList[id]->getState(), _currentPos+id);
+ break;
+
+ case kSetPositionCmd:
+ if (_currentPos != (int)data)
+ {
+ _currentPos = data;
+ setDirty(); draw();
+ }
+ break;
+ }
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void RomListWidget::lostFocusWidget()
+{
+ _editMode = false;
+
+ // Reset to normal data entry
+ abortEditMode();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -90,7 +407,6 @@ void RomListWidget::drawWidget(bool hilite)
FBSurface& s = _boss->dialog().surface();
const CartDebug::DisassemblyList& dlist = *myList;
int i, pos, xpos, ypos, len = dlist.size();
- string buffer;
int deltax;
// Draw a thin frame around the list and to separate columns
@@ -101,15 +417,15 @@ void RomListWidget::drawWidget(bool hilite)
s.vLine(_x + CheckboxWidget::boxSize() + 5, _y, _y + _h - 1, kColor);
// Draw the list items
- GUI::Rect r = getEditRect();
- GUI::Rect l = getLineRect();
+ const GUI::Rect& r = getEditRect();
+ const GUI::Rect& l = getLineRect();
xpos = _x + CheckboxWidget::boxSize() + 10; ypos = _y + 2;
for (i = 0, pos = _currentPos; i < _rows && pos < len; i++, pos++, ypos += _fontHeight)
{
// Draw checkboxes for correct lines (takes scrolling into account)
- _checkList[i]->setState(_stateList[pos]);
- _checkList[i]->setDirty();
- _checkList[i]->draw();
+ myCheckList[i]->setState(myBPState->isSet(dlist[pos].address));
+ myCheckList[i]->setDirty();
+ myCheckList[i]->draw();
// Draw highlighted item in a frame
if (_highlightedItem == pos)
@@ -140,24 +456,22 @@ void RomListWidget::drawWidget(bool hilite)
// Draw editable bytes
if (_selectedItem == pos && _editMode)
{
- buffer = _editString;
adjustOffset();
deltax = -_editScrollOffset;
- s.drawString(_font, buffer, _x + r.left, ypos, r.width(), kTextColor,
+ s.drawString(_font, _editString, _x + r.left, ypos, r.width(), kTextColor,
kTextAlignLeft, deltax, false);
}
else
{
- buffer = _list[pos];
deltax = 0;
- s.drawString(_font, buffer, _x + r.left, ypos, r.width(), kTextColor);
+ s.drawString(_font, dlist[pos].bytes, _x + r.left, ypos, r.width(), kTextColor);
}
}
// Only draw the caret while editing, and if it's in the current viewport
- if(_editMode && (_selectedItem >= _scrollBar->_currentPos) &&
- (_selectedItem < _scrollBar->_currentPos + _rows))
+ if(_editMode && (_selectedItem >= myScrollBar->_currentPos) &&
+ (_selectedItem < myScrollBar->_currentPos + _rows))
drawCaret();
}
@@ -202,3 +516,45 @@ bool RomListWidget::tryInsertChar(char c, int pos)
else
return false;
}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void RomListWidget::startEditMode()
+{
+ if (_editable && !_editMode && _selectedItem >= 0)
+ {
+ // Does this line represent an editable area?
+ if((*myList)[_selectedItem].bytes == "")
+ return;
+
+ _editMode = true;
+
+ // Widget gets raw data while editing
+ EditableWidget::startEditMode();
+ setEditString((*myList)[_selectedItem].bytes);
+ }
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void RomListWidget::endEditMode()
+{
+ if (!_editMode)
+ return;
+
+ // Send a message that editing finished with a return/enter key press
+ // The parent then calls getEditString() to get the newly entered data
+ _editMode = false;
+ sendCommand(kRLRomChangedCmd, _selectedItem, _id);
+
+ // Reset to normal data entry
+ EditableWidget::endEditMode();
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void RomListWidget::abortEditMode()
+{
+ // Undo any changes made
+ _editMode = false;
+
+ // Reset to normal data entry
+ EditableWidget::abortEditMode();
+}
diff --git a/src/debugger/gui/RomListWidget.hxx b/src/debugger/gui/RomListWidget.hxx
index 076164c59..186ab2ffd 100644
--- a/src/debugger/gui/RomListWidget.hxx
+++ b/src/debugger/gui/RomListWidget.hxx
@@ -22,14 +22,24 @@
#ifndef ROM_LIST_WIDGET_HXX
#define ROM_LIST_WIDGET_HXX
-class CheckboxWidget;
class ContextMenu;
+class ScrollBarWidget;
+class PackedBitArray;
+#include "Array.hxx"
+#include "StringList.hxx"
#include "CheckListWidget.hxx"
#include "CartDebug.hxx"
+#include "EditableWidget.hxx"
+
+// Some special commands for this widget
+enum {
+ kRLBreakpointChangedCmd = 'RLbp', // click on the checkbox for a breakpoint
+ kRLRomChangedCmd = 'RLpr' // ROM item data changed - 'data' will be item index
+};
/** RomListWidget */
-class RomListWidget : public CheckListWidget
+class RomListWidget : public EditableWidget
{
friend class RomWidget;
@@ -38,24 +48,60 @@ class RomListWidget : public CheckListWidget
int x, int y, int w, int h);
virtual ~RomListWidget();
- void setList(const CartDebug::DisassemblyList& list, const BoolArray& state);
+ void setList(const CartDebug::DisassemblyList& list, const PackedBitArray& state);
+
+ int getSelected() const { return _selectedItem; }
+ int getHighlighted() const { return _highlightedItem; }
+ void setHighlighted(int item);
+
+ const string& getEditString() const;
+ void startEditMode();
+ void endEditMode();
protected:
void handleMouseDown(int x, int y, int button, int clickCount);
+ void handleMouseUp(int x, int y, int button, int clickCount);
+ void handleMouseWheel(int x, int y, int direction);
+ bool handleKeyDown(int ascii, int keycode, int modifiers);
+ bool handleKeyUp(int ascii, int keycode, int modifiers);
bool handleEvent(Event::Type e);
+ void handleCommand(CommandSender* sender, int cmd, int data, int id);
void drawWidget(bool hilite);
GUI::Rect getLineRect() const;
GUI::Rect getEditRect() const;
+ int findItem(int x, int y) const;
+ void recalc();
+
bool tryInsertChar(char c, int pos);
+ void abortEditMode();
+ void lostFocusWidget();
+ void scrollToSelected() { scrollToCurrent(_selectedItem); }
+ void scrollToHighlighted() { scrollToCurrent(_highlightedItem); }
+
private:
- ContextMenu* myMenu;
+ void scrollToCurrent(int item);
+
+ private:
+ ContextMenu* myMenu;
+ ScrollBarWidget* myScrollBar;
+
int myLabelWidth;
int myBytesWidth;
+ int _rows;
+ int _cols;
+ int _currentPos;
+ int _selectedItem;
+ int _highlightedItem;
+ int _currentKeyDown;
+ bool _editMode;
+
const CartDebug::DisassemblyList* myList;
+ const PackedBitArray* myBPState;
+ Common::Array myCheckList;
};
#endif
diff --git a/src/debugger/gui/RomWidget.cxx b/src/debugger/gui/RomWidget.cxx
index 0f0ad6d27..ebbc87bf3 100644
--- a/src/debugger/gui/RomWidget.cxx
+++ b/src/debugger/gui/RomWidget.cxx
@@ -25,11 +25,11 @@
#include "DebuggerParser.hxx"
#include "CartDebug.hxx"
#include "CpuDebug.hxx"
-#include "DataGridWidget.hxx"
-#include "PackedBitArray.hxx"
#include "GuiObject.hxx"
#include "InputTextDialog.hxx"
#include "EditTextWidget.hxx"
+#include "PopUpWidget.hxx"
+#include "StringList.hxx"
#include "ContextMenu.hxx"
#include "RomListWidget.hxx"
#include "RomWidget.hxx"
@@ -45,45 +45,50 @@ RomWidget::RomWidget(GuiObject* boss, const GUI::Font& font, int x, int y)
int xpos, ypos;
StaticTextWidget* t;
+ WidgetArray wid;
- // Create bank editable area
- xpos = x + 40; ypos = y + 7;
+ // Show current bank
+ xpos = x; ypos = y + 7;
t = new StaticTextWidget(boss, font, xpos, ypos,
- font.getStringWidth("Current bank: "),
+ font.getStringWidth("Bank (current/total):"),
font.getFontHeight(),
- "Current bank:", kTextAlignLeft);
+ "Bank (current/total):", kTextAlignLeft);
xpos += t->getWidth() + 10;
- myBank = new DataGridWidget(boss, font, xpos, ypos-2,
- 1, 1, 4, 8, kBASE_10);
- myBank->setTarget(this);
- myBank->setRange(0, instance().debugger().cartDebug().bankCount());
- if(instance().debugger().cartDebug().bankCount() <= 1)
- myBank->setEditable(false);
- addFocusWidget(myBank);
+ myBank = new EditTextWidget(boss, font, xpos, ypos-2,
+ 4 * font.getMaxCharWidth(),
+ font.getLineHeight(), "");
+ myBank->setEditable(false);
// Show number of banks
- xpos += myBank->getWidth() + 45;
- t = new StaticTextWidget(boss, font, xpos, ypos,
- font.getStringWidth("Total banks: "),
- font.getFontHeight(),
- "Total banks:", kTextAlignLeft);
-
- xpos += t->getWidth() + 10;
- myBankCount = new EditTextWidget(boss, font, xpos, ypos-2,
- font.getStringWidth("XXXX"),
- font.getLineHeight(), "");
+ xpos += myBank->getWidth() + 5;
+ myBankCount =
+ new EditTextWidget(boss, font, xpos, ypos-2, 4 * font.getMaxCharWidth(),
+ font.getLineHeight(), "");
myBankCount->setEditable(false);
+ // 'Autocode' setting for Distella
+ xpos += myBankCount->getWidth() + 20;
+ StringMap items;
+ items.push_back("Never", "0");
+ items.push_back("Always", "1");
+ items.push_back("Automatic", "2");
+ myAutocode =
+ new PopUpWidget(boss, font, xpos, ypos-2, font.getStringWidth("Automatic"),
+ font.getLineHeight(), items,
+ "Determine code: ", font.getStringWidth("Determine code: "),
+ kAutocodeChanged);
+ myAutocode->setTarget(this);
+ addFocusWidget(myAutocode);
+
// Create rom listing
xpos = x; ypos += myBank->getHeight() + 4;
- GUI::Rect dialog = instance().debugger().getDialogBounds();
+ const GUI::Rect& dialog = instance().debugger().getDialogBounds();
int w = dialog.width() - x - 5, h = dialog.height() - ypos - 3;
myRomList = new RomListWidget(boss, font, xpos, ypos, w, h);
myRomList->setTarget(this);
myRomList->myMenu->setTarget(this);
- myRomList->setStyle(kSolidFill);
addFocusWidget(myRomList);
// Calculate real dimensions
@@ -95,6 +100,9 @@ RomWidget::RomWidget(GuiObject* boss, const GUI::Font& font, int x, int y)
label.push_back("Filename: ");
mySaveRom = new InputTextDialog(boss, font, label);
mySaveRom->setTarget(this);
+
+ // By default, we try to automatically determine code vs. data sections
+ myAutocode->setSelected(instance().settings().getString("autocode"), "2");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -103,17 +111,46 @@ RomWidget::~RomWidget()
delete mySaveRom;
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void RomWidget::loadConfig()
+{
+ Debugger& dbg = instance().debugger();
+ CartDebug& cart = dbg.cartDebug();
+ bool bankChanged = myCurrentBank != cart.getBank();
+ myCurrentBank = cart.getBank();
+
+ // Fill romlist the current bank of source or disassembly
+ myListIsDirty |= cart.disassemble(myAutocode->getSelectedTag(), myListIsDirty);
+ if(myListIsDirty)
+ {
+ myRomList->setList(cart.disassemblyList(), dbg.breakpoints());
+ myListIsDirty = false;
+ }
+
+ // Update romlist to point to current PC
+ int pcline = cart.addressToLine(dbg.cpuDebug().pc());
+ if(pcline > 0)
+ myRomList->setHighlighted(pcline);
+
+ // Set current bank and number of banks
+ myBank->setEditString(instance().debugger().valueToString(myCurrentBank, kBASE_10), bankChanged);
+ myBankCount->setEditString(instance().debugger().valueToString(cart.bankCount(), kBASE_10));
+}
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
{
switch(cmd)
{
- case kListItemChecked:
- setBreak(data);
+ case kRLBreakpointChangedCmd:
+ // 'id' is the line in the disassemblylist to be accessed
+ // 'data' is the state of the breakpoint at 'id'
+ setBreak(id, data);
break;
- case kListItemDataChangedCmd:
- patchROM(data, myRomList->getSelectedString());
+ case kRLRomChangedCmd:
+ // 'data' is the line in the disassemblylist to be accessed
+ patchROM(data, myRomList->getEditString());
break;
case kCMenuItemSelectedCmd:
@@ -132,6 +169,12 @@ void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
break;
}
+ case kAutocodeChanged:
+ instance().settings().setString("autocode", myAutocode->getSelectedTag());
+ invalidate();
+ loadConfig();
+ break;
+
case kRomNameEntered:
{
const string& rom = mySaveRom->getResult();
@@ -144,108 +187,43 @@ void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
}
break;
}
-
- case kDGItemDataChangedCmd:
- {
- int bank = myBank->getSelectedValue();
- instance().debugger().setBank(bank);
- }
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void RomWidget::loadConfig()
-{
- Debugger& dbg = instance().debugger();
- CartDebug& cart = dbg.cartDebug();
- bool bankChanged = myCurrentBank != cart.getBank();
- myCurrentBank = cart.getBank();
-
- // Fill romlist the current bank of source or disassembly
- // Only reload full bank when necessary
- // TODO - bank changes aren't the only time that the disassembly needs to
- // be redone; ROMs which dynamically change cart address space and
- // have self-modifying code need to be taken into account
- // As well, we don't always start from the 0xfffc; this only
- // happens in the startup bank
- myListIsDirty |= cart.disassemble(true);
- if(myListIsDirty)
- {
- const CartDebug::DisassemblyList& list = cart.disassemblyList();
- BoolArray state;
-
- PackedBitArray& bp = dbg.breakpoints();
- for(uInt32 i = 0; i < list.size(); ++i)
- {
- const CartDebug::DisassemblyTag& tag = list[i];
- if(tag.address != 0 && bp.isSet(tag.address))
- state.push_back(true);
- else
- state.push_back(false);
- }
-
- myRomList->setList(list, state);
-
- // Restore the old bank, in case we inadvertently switched while reading.
-// dbg.setBank(myCurrentBank); // TODO - why is this here?
-
- myListIsDirty = false;
- }
-
- // Update romlist to point to current PC
- int pcline = cart.addressToLine(dbg.cpuDebug().pc());
- if(pcline > 0)
- myRomList->setHighlighted(pcline);
-
- // Set current bank
- IntArray alist;
- IntArray vlist;
- BoolArray changed;
-
- alist.push_back(-1);
- vlist.push_back(cart.getBank());
- changed.push_back(bankChanged);
- myBank->setList(alist, vlist, changed);
-
- // Indicate total number of banks
- myBankCount->setEditString(dbg.valueToString(cart.bankCount(), kBASE_10));
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void RomWidget::setBreak(int data)
+void RomWidget::setBreak(int disasm_line, bool state)
{
const CartDebug::DisassemblyList& list =
instance().debugger().cartDebug().disassemblyList();
- if(data >= (int)list.size()) return;
+ if(disasm_line >= (int)list.size()) return;
- bool state = myRomList->getState(data);
- if(list[data].address != 0)
- instance().debugger().setBreakPoint(list[data].address, state);
+ if(list[disasm_line].address != 0)
+ instance().debugger().setBreakPoint(list[disasm_line].address, state);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void RomWidget::setPC(int data)
+void RomWidget::setPC(int disasm_line)
{
const CartDebug::DisassemblyList& list =
instance().debugger().cartDebug().disassemblyList();
- if(data >= (int)list.size()) return;
+ if(disasm_line >= (int)list.size()) return;
- if(list[data].address != 0)
+ if(list[disasm_line].address != 0)
{
ostringstream command;
- command << "pc #" << list[data].address;
+ command << "pc #" << list[disasm_line].address;
instance().debugger().run(command.str());
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void RomWidget::patchROM(int data, const string& bytes)
+void RomWidget::patchROM(int disasm_line, const string& bytes)
{
const CartDebug::DisassemblyList& list =
instance().debugger().cartDebug().disassemblyList();
- if(data >= (int)list.size()) return;
+ if(disasm_line >= (int)list.size()) return;
- if(list[data].address != 0)
+ if(list[disasm_line].address != 0)
{
ostringstream command;
@@ -255,7 +233,7 @@ void RomWidget::patchROM(int data, const string& bytes)
BaseFormat oldbase = instance().debugger().parser().base();
instance().debugger().parser().setBase(kBASE_16);
- command << "rom #" << list[data].address << " " << bytes;
+ command << "rom #" << list[disasm_line].address << " " << bytes;
instance().debugger().run(command.str());
// Restore previous base
diff --git a/src/debugger/gui/RomWidget.hxx b/src/debugger/gui/RomWidget.hxx
index 0ac17fc98..ded25c494 100644
--- a/src/debugger/gui/RomWidget.hxx
+++ b/src/debugger/gui/RomWidget.hxx
@@ -23,9 +23,9 @@
#define ROM_WIDGET_HXX
class GuiObject;
-class DataGridWidget;
class EditTextWidget;
class InputTextDialog;
+class PopUpWidget;
class RomListWidget;
class StringList;
@@ -46,19 +46,21 @@ class RomWidget : public Widget, public CommandSender
void loadConfig();
private:
- void setBreak(int data);
- void setPC(int data);
- void patchROM(int data, const string& bytes);
+ void setBreak(int disasm_line, bool state);
+ void setPC(int disasm_line);
+ void patchROM(int disasm_line, const string& bytes);
void saveROM(const string& rom);
private:
enum {
- kRomNameEntered = 'RWrn'
+ kAutocodeChanged = 'ACch',
+ kRomNameEntered = 'RWrn'
};
RomListWidget* myRomList;
- DataGridWidget* myBank;
+ EditTextWidget* myBank;
EditTextWidget* myBankCount;
+ PopUpWidget* myAutocode;
InputTextDialog* mySaveRom;
bool myListIsDirty;
diff --git a/src/emucore/Cart.cxx b/src/emucore/Cart.cxx
index 3db33607a..f40189800 100644
--- a/src/emucore/Cart.cxx
+++ b/src/emucore/Cart.cxx
@@ -206,7 +206,7 @@ string Cartridge::createFromMultiCart(const uInt8*& image, uInt32& size,
image += i*size;
// We need a new md5 and name
- md5 = MD5(image, size);
+ md5 = MD5(image, size);
ostringstream buf;
buf << " [G" << (i+1) << "]";
id = buf.str();
@@ -347,7 +347,7 @@ string Cartridge::autodetectType(const uInt8* image, uInt32 size)
// TODO - this should really be in a method that checks the first
// 512 bytes of ROM and finds if either the lower 256 bytes or
// higher 256 bytes are all the same. For now, we assume that
- // all carts of 12K are CBS RAM Plus/FASC.
+ // all carts of 12K are CBS RAM Plus/FA.
type = "FA";
}
else if(size == 16384) // 16K
diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx
index 55eadb3bd..0072e4b18 100644
--- a/src/emucore/Settings.cxx
+++ b/src/emucore/Settings.cxx
@@ -125,6 +125,9 @@ Settings::Settings(OSystem* osystem)
setInternal("fastscbios", "false");
setExternal("romloadcount", "0");
setExternal("maxres", "0x0");
+
+ // Debugger options
+ setInternal("autocode", "2");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -396,6 +399,7 @@ void Settings::usage()
<< " The following options are meant for developers\n"
<< " Arguments are more fully explained in the manual\n"
<< endl
+ << " -autocode <0|1|2> Set automatic code vs. data determination in the disassembler\n"
<< " -debuggerres The resolution to use in debugger mode\n"
<< " -break Set a breakpoint at 'address'\n"
<< " -debug Start in debugger mode\n"
diff --git a/src/gui/Dialog.cxx b/src/gui/Dialog.cxx
index 29023c2f4..8bfd3e2ad 100644
--- a/src/gui/Dialog.cxx
+++ b/src/gui/Dialog.cxx
@@ -158,9 +158,9 @@ void Dialog::addToFocusList(WidgetArray& list, int id)
// Make sure the array is large enough
while((int)_ourFocusList.size() <= id)
{
- Focus f;
- f.focusedWidget = NULL;
- _ourFocusList.push_back(f);
+ Focus f;
+ f.focusedWidget = NULL;
+ _ourFocusList.push_back(f);
}
_ourFocusList[id].focusList.push_back(list);
diff --git a/src/gui/EditTextWidget.cxx b/src/gui/EditTextWidget.cxx
index 4e4c5c7f5..b646ace1c 100644
--- a/src/gui/EditTextWidget.cxx
+++ b/src/gui/EditTextWidget.cxx
@@ -19,6 +19,8 @@
// Copyright (C) 2002-2004 The ScummVM project
//============================================================================
+#include
+
#include "OSystem.hxx"
#include "FrameBuffer.hxx"
#include "Dialog.hxx"
@@ -28,20 +30,22 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EditTextWidget::EditTextWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, int w, int h, const string& text)
- : EditableWidget(boss, font, x, y - 1, w, h + 2)
+ : EditableWidget(boss, font, x, y - 1, w, h + 2),
+ _editable(true),
+ _changed(false)
{
_flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS;
_type = kEditTextWidget;
- _editable = true;
startEditMode(); // We're always in edit mode
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void EditTextWidget::setEditString(const string& str)
+void EditTextWidget::setEditString(const string& str, bool changed)
{
EditableWidget::setEditString(str);
_backupString = str;
+ _changed = changed;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -74,6 +78,10 @@ void EditTextWidget::drawWidget(bool hilite)
//cerr << "EditTextWidget::drawWidget\n";
FBSurface& s = _boss->dialog().surface();
+ // Highlight changes
+ if(_changed)
+ s.fillRect(_x, _y, _w, _h, kDbgChangedColor);
+
// Draw a thin frame around us.
s.hLine(_x, _y, _x + _w - 1, kColor);
s.hLine(_x, _y + _h - 1, _x +_w - 1, kShadowColor);
@@ -83,7 +91,8 @@ void EditTextWidget::drawWidget(bool hilite)
// Draw the text
adjustOffset();
s.drawString(_font, _editString, _x + 2, _y + 2, getEditRect().width(),
- _textcolor, kTextAlignLeft, -_editScrollOffset, false);
+ !_changed ? _textcolor : kDbgChangedTextColor,
+ kTextAlignLeft, -_editScrollOffset, false);
// Draw the caret
drawCaret();
diff --git a/src/gui/EditTextWidget.hxx b/src/gui/EditTextWidget.hxx
index ca5a23de7..7d041fe15 100644
--- a/src/gui/EditTextWidget.hxx
+++ b/src/gui/EditTextWidget.hxx
@@ -33,7 +33,7 @@ class EditTextWidget : public EditableWidget
EditTextWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, int w, int h, const string& text);
- void setEditString(const string& str);
+ void setEditString(const string& str, bool changed = false);
virtual void handleMouseDown(int x, int y, int button, int clickCount);
@@ -50,6 +50,7 @@ class EditTextWidget : public EditableWidget
protected:
string _backupString;
int _editable;
+ bool _changed;
};
#endif
diff --git a/src/gui/EditableWidget.hxx b/src/gui/EditableWidget.hxx
index a265aea17..254516bb2 100644
--- a/src/gui/EditableWidget.hxx
+++ b/src/gui/EditableWidget.hxx
@@ -54,9 +54,9 @@ class EditableWidget : public Widget, public CommandSender
virtual bool wantsFocus() { return _editable; }
protected:
- virtual void startEditMode() { setFlags(WIDGET_WANTS_RAWDATA); }
- virtual void endEditMode() { clearFlags(WIDGET_WANTS_RAWDATA); }
- virtual void abortEditMode() { clearFlags(WIDGET_WANTS_RAWDATA); }
+ virtual void startEditMode() { setFlags(WIDGET_WANTS_RAWDATA); _editString = ""; }
+ virtual void endEditMode() { clearFlags(WIDGET_WANTS_RAWDATA); _editString = ""; }
+ virtual void abortEditMode() { clearFlags(WIDGET_WANTS_RAWDATA); _editString = ""; }
virtual GUI::Rect getEditRect() const = 0;
virtual int getCaretOffset() const;
diff --git a/src/gui/ListWidget.cxx b/src/gui/ListWidget.cxx
index fb4b902d2..fdadc64e2 100644
--- a/src/gui/ListWidget.cxx
+++ b/src/gui/ListWidget.cxx
@@ -41,7 +41,6 @@ ListWidget::ListWidget(GuiObject* boss, const GUI::Font& font,
_highlightedItem(-1),
_currentKeyDown(0),
_editMode(false),
- _caretInverse(true),
_quickSelect(quickSelect),
_quickSelectTime(0)
{
diff --git a/src/gui/ListWidget.hxx b/src/gui/ListWidget.hxx
index 1a6f2b920..021e38dc0 100644
--- a/src/gui/ListWidget.hxx
+++ b/src/gui/ListWidget.hxx
@@ -104,9 +104,7 @@ class ListWidget : public EditableWidget
int _selectedItem;
int _highlightedItem;
int _currentKeyDown;
-
bool _editMode;
- bool _caretInverse;
ScrollBarWidget* _scrollBar;