2005-08-30 17:51:26 +00:00
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// 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
|
|
|
|
//
|
2010-01-10 02:58:28 +00:00
|
|
|
// Copyright (c) 1995-2010 by Bradford W. Mott and the Stella team
|
2005-08-30 17:51:26 +00:00
|
|
|
//
|
|
|
|
// See the file "license" for information on usage and redistribution of
|
|
|
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
|
|
|
//
|
2009-05-13 13:55:40 +00:00
|
|
|
// $Id$
|
2005-08-30 17:51:26 +00:00
|
|
|
//
|
|
|
|
// Based on code from ScummVM - Scumm Interpreter
|
|
|
|
// Copyright (C) 2002-2004 The ScummVM project
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
#include "Debugger.hxx"
|
2005-09-07 18:34:52 +00:00
|
|
|
#include "DebuggerParser.hxx"
|
2005-08-30 17:51:26 +00:00
|
|
|
#include "CpuDebug.hxx"
|
2005-10-13 18:53:07 +00:00
|
|
|
#include "DataGridWidget.hxx"
|
2005-09-23 17:38:27 +00:00
|
|
|
#include "PackedBitArray.hxx"
|
2005-08-30 17:51:26 +00:00
|
|
|
#include "GuiObject.hxx"
|
2005-10-06 17:28:55 +00:00
|
|
|
#include "InputTextDialog.hxx"
|
2005-11-27 22:37:25 +00:00
|
|
|
#include "EditTextWidget.hxx"
|
2005-09-07 18:34:52 +00:00
|
|
|
#include "ContextMenu.hxx"
|
2005-08-30 17:51:26 +00:00
|
|
|
#include "RomListWidget.hxx"
|
|
|
|
#include "RomWidget.hxx"
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
RomWidget::RomWidget(GuiObject* boss, const GUI::Font& font, int x, int y)
|
2006-02-22 17:38:04 +00:00
|
|
|
: Widget(boss, font, x, y, 16, 16),
|
2005-08-30 17:51:26 +00:00
|
|
|
CommandSender(boss),
|
2005-09-15 19:43:36 +00:00
|
|
|
myListIsDirty(true),
|
2005-08-30 17:51:26 +00:00
|
|
|
mySourceAvailable(false),
|
|
|
|
myCurrentBank(-1)
|
|
|
|
{
|
2006-11-06 00:52:04 +00:00
|
|
|
_type = kRomWidget;
|
|
|
|
|
2007-08-12 23:05:12 +00:00
|
|
|
int xpos, ypos;
|
2005-10-13 18:53:07 +00:00
|
|
|
StaticTextWidget* t;
|
|
|
|
|
|
|
|
// Create bank editable area
|
2005-10-14 13:50:00 +00:00
|
|
|
xpos = x + 40; ypos = y + 7;
|
2006-02-22 17:38:04 +00:00
|
|
|
t = new StaticTextWidget(boss, font, xpos, ypos,
|
2005-10-13 18:53:07 +00:00
|
|
|
font.getStringWidth("Current bank: "),
|
|
|
|
font.getFontHeight(),
|
|
|
|
"Current bank:", kTextAlignLeft);
|
|
|
|
|
|
|
|
xpos += t->getWidth() + 10;
|
|
|
|
myBank = new DataGridWidget(boss, font, xpos, ypos-2,
|
2009-06-03 14:49:42 +00:00
|
|
|
1, 1, 4, 8, kBASE_10);
|
2005-10-13 18:53:07 +00:00
|
|
|
myBank->setTarget(this);
|
2008-06-13 13:14:52 +00:00
|
|
|
myBank->setRange(0, instance().debugger().bankCount());
|
|
|
|
if(instance().debugger().bankCount() <= 1)
|
2005-10-14 13:50:00 +00:00
|
|
|
myBank->setEditable(false);
|
2005-10-13 18:53:07 +00:00
|
|
|
addFocusWidget(myBank);
|
|
|
|
|
|
|
|
// Show number of banks
|
|
|
|
xpos += myBank->getWidth() + 45;
|
2006-02-22 17:38:04 +00:00
|
|
|
t = new StaticTextWidget(boss, font, xpos, ypos,
|
2005-10-13 18:53:07 +00:00
|
|
|
font.getStringWidth("Total banks: "),
|
|
|
|
font.getFontHeight(),
|
|
|
|
"Total banks:", kTextAlignLeft);
|
|
|
|
|
|
|
|
xpos += t->getWidth() + 10;
|
2006-02-22 17:38:04 +00:00
|
|
|
myBankCount = new EditTextWidget(boss, font, xpos, ypos-2,
|
2009-06-03 14:49:42 +00:00
|
|
|
font.getStringWidth("XXXX"),
|
|
|
|
font.getLineHeight(), "");
|
2005-10-13 18:53:07 +00:00
|
|
|
myBankCount->setEditable(false);
|
|
|
|
|
|
|
|
// Create rom listing
|
2005-10-14 13:50:00 +00:00
|
|
|
xpos = x; ypos += myBank->getHeight() + 4;
|
2008-06-13 13:14:52 +00:00
|
|
|
GUI::Rect dialog = instance().debugger().getDialogBounds();
|
2007-08-12 23:05:12 +00:00
|
|
|
int w = dialog.width() - x - 5, h = dialog.height() - ypos - 3;
|
2005-10-22 15:43:17 +00:00
|
|
|
|
2005-10-13 18:53:07 +00:00
|
|
|
myRomList = new RomListWidget(boss, font, xpos, ypos, w, h);
|
2005-08-30 17:51:26 +00:00
|
|
|
myRomList->setTarget(this);
|
2005-09-07 18:34:52 +00:00
|
|
|
myRomList->myMenu->setTarget(this);
|
2005-08-30 17:51:26 +00:00
|
|
|
myRomList->setStyle(kSolidFill);
|
|
|
|
addFocusWidget(myRomList);
|
|
|
|
|
|
|
|
// Calculate real dimensions
|
|
|
|
_w = myRomList->getWidth();
|
|
|
|
_h = myRomList->getHeight();
|
2005-10-06 17:28:55 +00:00
|
|
|
|
|
|
|
// Create dialog box for save ROM (get name)
|
2005-11-27 22:37:25 +00:00
|
|
|
StringList label;
|
|
|
|
label.push_back("Filename: ");
|
2008-06-19 19:15:44 +00:00
|
|
|
mySaveRom = new InputTextDialog(boss, font, label);
|
2005-10-06 17:28:55 +00:00
|
|
|
mySaveRom->setTarget(this);
|
2005-08-30 17:51:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
RomWidget::~RomWidget()
|
|
|
|
{
|
|
|
|
myAddrList.clear();
|
|
|
|
myLineList.clear();
|
2009-01-11 15:01:36 +00:00
|
|
|
|
|
|
|
delete mySaveRom;
|
2005-08-30 17:51:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
|
|
|
{
|
|
|
|
switch(cmd)
|
|
|
|
{
|
|
|
|
case kListScrolledCmd:
|
2005-09-13 18:27:42 +00:00
|
|
|
incrementalUpdate(data, myRomList->rows());
|
2005-08-30 17:51:26 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case kListItemChecked:
|
2005-09-07 18:34:52 +00:00
|
|
|
setBreak(data);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case kListItemDataChangedCmd:
|
|
|
|
patchROM(data, myRomList->getSelectedString());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case kCMenuItemSelectedCmd:
|
2005-08-30 17:51:26 +00:00
|
|
|
{
|
2008-07-25 12:41:41 +00:00
|
|
|
const string& rmb = myRomList->myMenu->getSelectedTag();
|
2005-09-07 18:34:52 +00:00
|
|
|
|
2008-07-25 12:41:41 +00:00
|
|
|
if(rmb == "saverom")
|
2005-10-06 17:28:55 +00:00
|
|
|
{
|
2008-06-19 19:15:44 +00:00
|
|
|
mySaveRom->show(_x + 50, _y + 80);
|
2005-10-06 17:28:55 +00:00
|
|
|
mySaveRom->setTitle("");
|
|
|
|
mySaveRom->setEmitSignal(kRomNameEntered);
|
|
|
|
}
|
2008-07-25 12:41:41 +00:00
|
|
|
else if(rmb == "setpc")
|
2005-09-07 18:34:52 +00:00
|
|
|
setPC(myRomList->getSelected());
|
2005-08-30 17:51:26 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2005-10-06 17:28:55 +00:00
|
|
|
|
|
|
|
case kRomNameEntered:
|
|
|
|
{
|
|
|
|
const string& rom = mySaveRom->getResult();
|
|
|
|
if(rom == "")
|
|
|
|
mySaveRom->setTitle("Invalid name");
|
|
|
|
else
|
|
|
|
{
|
|
|
|
saveROM(rom);
|
2008-06-13 13:14:52 +00:00
|
|
|
parent().removeDialog();
|
2005-10-06 17:28:55 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2005-10-13 18:53:07 +00:00
|
|
|
|
|
|
|
case kDGItemDataChangedCmd:
|
|
|
|
{
|
|
|
|
int bank = myBank->getSelectedValue();
|
2008-06-13 13:14:52 +00:00
|
|
|
instance().debugger().setBank(bank);
|
2005-10-13 18:53:07 +00:00
|
|
|
}
|
2005-08-30 17:51:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void RomWidget::loadConfig()
|
|
|
|
{
|
2008-06-13 13:14:52 +00:00
|
|
|
Debugger& dbg = instance().debugger();
|
2005-10-13 18:53:07 +00:00
|
|
|
bool bankChanged = myCurrentBank != dbg.getBank();
|
2005-09-13 18:27:42 +00:00
|
|
|
|
2005-08-30 17:51:26 +00:00
|
|
|
// Only reload full bank when necessary
|
2005-10-13 18:53:07 +00:00
|
|
|
if(myListIsDirty || bankChanged)
|
2005-08-30 17:51:26 +00:00
|
|
|
{
|
|
|
|
initialUpdate();
|
2005-09-15 19:43:36 +00:00
|
|
|
myListIsDirty = false;
|
2005-08-30 17:51:26 +00:00
|
|
|
}
|
|
|
|
else // only reload what's in current view
|
|
|
|
{
|
2005-09-13 18:27:42 +00:00
|
|
|
incrementalUpdate(myRomList->currentPos(), myRomList->rows());
|
2005-08-30 17:51:26 +00:00
|
|
|
}
|
2005-09-13 18:27:42 +00:00
|
|
|
myCurrentBank = dbg.getBank();
|
|
|
|
|
2005-08-30 17:51:26 +00:00
|
|
|
// Update romlist to point to current PC
|
2009-08-30 19:37:10 +00:00
|
|
|
// Take mirroring of PC into account, as well as zero-page RAM
|
|
|
|
int pc = dbg.cpuDebug().pc();
|
|
|
|
if(pc & 0x1000) pc |= 0xe000;
|
2005-08-30 17:51:26 +00:00
|
|
|
AddrToLine::iterator iter = myLineList.find(pc);
|
2005-10-12 03:32:28 +00:00
|
|
|
|
|
|
|
// if current PC not found, do an update (we're executing what
|
|
|
|
// we thought was an operand)
|
|
|
|
|
|
|
|
// This doesn't help, and seems to actually hurt.
|
|
|
|
/*
|
|
|
|
if(iter == myLineList.end()) {
|
|
|
|
incrementalUpdate(myRomList->currentPos(), myRomList->rows());
|
|
|
|
iter = myLineList.find(pc);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
2005-08-30 17:51:26 +00:00
|
|
|
if(iter != myLineList.end())
|
|
|
|
myRomList->setHighlighted(iter->second);
|
2005-10-13 18:53:07 +00:00
|
|
|
|
|
|
|
// Set current bank
|
|
|
|
IntArray alist;
|
|
|
|
IntArray vlist;
|
|
|
|
BoolArray changed;
|
|
|
|
|
|
|
|
alist.push_back(-1);
|
|
|
|
vlist.push_back(dbg.getBank());
|
|
|
|
changed.push_back(bankChanged);
|
|
|
|
myBank->setList(alist, vlist, changed);
|
|
|
|
|
|
|
|
// Indicate total number of banks
|
2007-08-17 16:12:50 +00:00
|
|
|
myBankCount->setEditString(dbg.valueToString(dbg.bankCount(), kBASE_10));
|
2005-08-30 17:51:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void RomWidget::initialUpdate()
|
|
|
|
{
|
2008-06-13 13:14:52 +00:00
|
|
|
Debugger& dbg = instance().debugger();
|
2008-03-23 17:43:22 +00:00
|
|
|
PackedBitArray& bp = dbg.breakpoints();
|
2005-08-30 17:51:26 +00:00
|
|
|
|
2005-10-13 00:59:30 +00:00
|
|
|
// Reading from ROM might trigger a bankswitch, so save the current bank
|
|
|
|
myCurrentBank = dbg.getBank();
|
|
|
|
|
2005-08-30 17:51:26 +00:00
|
|
|
// Fill romlist the current bank of source or disassembly
|
|
|
|
if(mySourceAvailable)
|
2005-09-15 19:43:36 +00:00
|
|
|
; // TODO - actually implement this
|
2005-08-30 17:51:26 +00:00
|
|
|
else
|
|
|
|
{
|
2005-09-01 19:14:09 +00:00
|
|
|
// Clear old mappings
|
2005-08-30 17:51:26 +00:00
|
|
|
myAddrList.clear();
|
|
|
|
myLineList.clear();
|
|
|
|
|
2005-09-01 19:14:09 +00:00
|
|
|
StringList label, data, disasm;
|
|
|
|
BoolArray state;
|
|
|
|
|
2009-08-30 19:37:10 +00:00
|
|
|
// Disassemble zero-page RAM and entire bank and reset breakpoints
|
2009-09-09 15:59:22 +00:00
|
|
|
// dbg.disassemble(myAddrList, label, data, disasm, 0x80, 0xff);
|
2009-08-30 19:37:10 +00:00
|
|
|
dbg.disassemble(myAddrList, label, data, disasm, 0xf000, 0xffff);
|
2005-08-30 17:51:26 +00:00
|
|
|
for(unsigned int i = 0; i < data.size(); ++i)
|
2005-09-23 17:38:27 +00:00
|
|
|
{
|
2008-03-23 17:43:22 +00:00
|
|
|
if(bp.isSet(myAddrList[i]))
|
2005-09-23 17:38:27 +00:00
|
|
|
state.push_back(true);
|
|
|
|
else
|
|
|
|
state.push_back(false);
|
|
|
|
}
|
2005-08-30 17:51:26 +00:00
|
|
|
|
|
|
|
// Create a mapping from addresses to line numbers
|
|
|
|
myLineList.clear();
|
|
|
|
for(unsigned int i = 0; i < myAddrList.size(); ++i)
|
|
|
|
myLineList.insert(make_pair(myAddrList[i], i));
|
|
|
|
|
2005-09-01 19:14:09 +00:00
|
|
|
myRomList->setList(label, data, disasm, state);
|
2005-08-30 17:51:26 +00:00
|
|
|
}
|
2005-10-13 00:59:30 +00:00
|
|
|
|
|
|
|
// Restore the old bank, in case we inadvertently switched while reading.
|
|
|
|
dbg.setBank(myCurrentBank);
|
2005-08-30 17:51:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2005-09-13 18:27:42 +00:00
|
|
|
void RomWidget::incrementalUpdate(int line, int rows)
|
2005-08-30 17:51:26 +00:00
|
|
|
{
|
2005-09-15 19:43:36 +00:00
|
|
|
// TODO - implement this
|
2005-08-30 17:51:26 +00:00
|
|
|
}
|
2005-09-07 18:34:52 +00:00
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void RomWidget::setBreak(int data)
|
|
|
|
{
|
2005-09-23 17:38:27 +00:00
|
|
|
bool state = myRomList->getState(data);
|
2008-06-13 13:14:52 +00:00
|
|
|
instance().debugger().setBreakPoint(myAddrList[data], state);
|
2005-09-07 18:34:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void RomWidget::setPC(int data)
|
|
|
|
{
|
|
|
|
ostringstream command;
|
|
|
|
command << "pc #" << myAddrList[data];
|
2008-06-13 13:14:52 +00:00
|
|
|
instance().debugger().run(command.str());
|
2005-09-07 18:34:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void RomWidget::patchROM(int data, const string& bytes)
|
|
|
|
{
|
|
|
|
ostringstream command;
|
|
|
|
|
|
|
|
// Temporarily set to base 16, since that's the format the disassembled
|
|
|
|
// byte string is in. This eliminates the need to prefix each byte with
|
|
|
|
// a '$' character
|
2008-06-13 13:14:52 +00:00
|
|
|
BaseFormat oldbase = instance().debugger().parser().base();
|
|
|
|
instance().debugger().parser().setBase(kBASE_16);
|
2005-09-07 18:34:52 +00:00
|
|
|
|
|
|
|
command << "rom #" << myAddrList[data] << " " << bytes;
|
2008-06-13 13:14:52 +00:00
|
|
|
instance().debugger().run(command.str());
|
2005-09-07 18:34:52 +00:00
|
|
|
|
|
|
|
// Restore previous base
|
2008-06-13 13:14:52 +00:00
|
|
|
instance().debugger().parser().setBase(oldbase);
|
2005-09-07 18:34:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2005-10-06 17:28:55 +00:00
|
|
|
void RomWidget::saveROM(const string& rom)
|
2005-09-07 18:34:52 +00:00
|
|
|
{
|
2005-10-06 17:28:55 +00:00
|
|
|
ostringstream command;
|
|
|
|
command << "saverom " << rom;
|
2008-06-13 13:14:52 +00:00
|
|
|
instance().debugger().run(command.str());
|
2005-09-07 18:34:52 +00:00
|
|
|
}
|