Added commandline argument 'gfxformat', also accessible from a right

mouse button context menu in the disassembly listing.  This is used to
set the default display format for GFX data sections (currently, binary
and hex are supported).

Fixed bug in several debugger input areas to accept the '\' symbol.
This symbol is needed when entering data in binary format (it must
prefix the data if the default base for that field isn't binary).

Added 'jump' debugger prompt command, used to scroll the disassembly
to the given address (or there-abouts, if the address isn't valid).

Editing data in the disassembly now won't cause the display to jump to
the current PC.  The display will only move to the PC when it actually
changes.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2123 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2010-09-05 17:57:21 +00:00
parent 00d64f9f02
commit 8f68c677d4
15 changed files with 135 additions and 54 deletions

View File

@ -22,12 +22,12 @@
#include "System.hxx"
#include "DiStella.hxx"
#include "CpuDebug.hxx"
#include "Settings.hxx"
#include "CartDebug.hxx"
#define HEX4 uppercase << hex << setw(4) << setfill('0')
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartDebug::CartDebug(Debugger& dbg, Console& console, const RamAreaList& areas)
CartDebug::CartDebug(Debugger& dbg, Console& console, const RamAreaList& areas,
const Settings& settings)
: DebuggerSystem(dbg, console),
myRWPortAddress(0),
myLabelLength(5) // longest pre-defined label
@ -40,11 +40,16 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const RamAreaList& areas)
addRamArea(i->start, i->size, i->roffset, i->woffset);
// Create bank information for each potential bank, and an extra one for ZP RAM
for(int i = 0; i < myConsole.cartridge().bankCount()+1; ++i)
uInt16 banksize =
!BSPF_equalsIgnoreCase(myConsole.cartridge().name(), "Cartridge2K") ? 4096 : 2048;
BankInfo info;
for(int i = 0; i < myConsole.cartridge().bankCount(); ++i)
{
BankInfo info;
info.banksize = banksize; // TODO - get this from Cart class
myBankInfo.push_back(info);
}
info.banksize = 128; // ZP RAM
myBankInfo.push_back(info);
// We know the address for the startup bank right now
myBankInfo[myConsole.cartridge().startBank()].addressList.push_back(myDebugger.dpeek(0xfffc));
@ -57,6 +62,10 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const RamAreaList& areas)
mySystemAddresses.insert(make_pair(ourTIAMnemonicW[addr], addr));
for(uInt16 addr = 0x280; addr <= 0x297; ++addr)
mySystemAddresses.insert(make_pair(ourIOMnemonic[addr-0x280], addr));
// Add settings for Distella
DiStella::settings.gfx_format =
settings.getInt("gfxformat") == 16 ? kBASE_16 : kBASE_2;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -266,9 +275,7 @@ bool CartDebug::fillDisassemblyList(BankInfo& info, bool resolvedata, uInt16 sea
myDisassembly.list.clear();
myDisassembly.fieldwidth = 10 + myLabelLength;
uInt16 banksize =
!BSPF_equalsIgnoreCase(myConsole.cartridge().name(), "Cartridge2K") ? 4 : 2;
DiStella distella(*this, myDisassembly.list, info, banksize, resolvedata);
DiStella distella(*this, myDisassembly.list, info, resolvedata);
// Parts of the disassembly will be accessed later in different ways
// We place those parts in separate maps, to speed up access
@ -304,9 +311,7 @@ string CartDebug::disassemble(uInt16 start, uInt16 lines) const
Disassembly disasm;
BankInfo info;
info.addressList.push_back(start);
uInt16 banksize =
!BSPF_equalsIgnoreCase(myConsole.cartridge().name(), "Cartridge2K") ? 4 : 2;
DiStella distella(*this, disasm.list, info, banksize, false);
DiStella distella(*this, disasm.list, info, false);
// Fill the string with disassembled data
start &= 0xFFF;
@ -750,9 +755,7 @@ void CartDebug::getBankDirectives(ostringstream& buf, BankInfo& info) const
{
// Disassemble the bank, then scan it for an up-to-date description
DisassemblyList list;
uInt16 banksize =
!BSPF_equalsIgnoreCase(myConsole.cartridge().name(), "Cartridge2K") ? 4 : 2;
DiStella distella(*this, list, info, banksize, true);
DiStella distella(*this, list, info, true);
if(list.size() == 0)
return;

View File

@ -20,6 +20,7 @@
#ifndef CART_DEBUG_HXX
#define CART_DEBUG_HXX
class Settings;
class System;
#include <map>
@ -73,7 +74,8 @@ class CartDebug : public DebuggerSystem
} Disassembly;
public:
CartDebug(Debugger& dbg, Console& console, const RamAreaList& areas);
CartDebug(Debugger& dbg, Console& console, const RamAreaList& areas,
const Settings& settings);
virtual ~CartDebug();
const DebuggerState& getState();
@ -254,6 +256,7 @@ class CartDebug : public DebuggerSystem
uInt16 start; // start of address space
uInt16 end; // end of address space
uInt16 offset; // ORG value
uInt16 banksize; // size of a bank (in bytes)
AddressList addressList; // addresses which PC has hit
DirectiveList directiveList; // overrides for automatic code determination
} BankInfo;

View File

@ -211,7 +211,9 @@ void Debugger::setConsole(Console* console)
delete myCartDebug;
// Register any RAM areas in the Cartridge
// Zero-page RAM is automatically recognized by CartDebug
myCartDebug = new CartDebug(*this, *myConsole, myConsole->cartridge().ramAreas());
myCartDebug = new CartDebug(*this, *myConsole, myConsole->cartridge().ramAreas(),
myOSystem->settings());
cerr << myOSystem->romFile() << endl;
myCartDebug->loadSymbolFile(myOSystem->romFile());
delete myRiotDebug;

View File

@ -47,6 +47,9 @@ class Serializer;
#include "Stack.hxx"
#include "bspf.hxx"
#define HEX4 uppercase << hex << setw(4) << setfill('0')
#define HEX2 uppercase << hex << setw(2) << setfill('0')
typedef map<string,Expression*> FunctionMap;
typedef map<string,string> FunctionDefMap;

View File

@ -1011,6 +1011,28 @@ void DebuggerParser::executeHelp()
commandResult << debugger->builtinHelp();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "jump"
void DebuggerParser::executeJump()
{
int line = -1;
int address = args[0];
// The specific address we want may not exist (it may be part of a data section)
// If so, scroll backward a little until we find it
while(((line = debugger->cartDebug().addressToLine(address)) == -1) &&
((address & 0xFFF) >= 0))
address--;
if(line >= 0)
{
debugger->myRom->scrollTo(line);
commandResult << "disassembly scrolled to address $" << HEX4 << address;
}
else
commandResult << "address $" << HEX4 << args[0] << " doesn't exist";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "listbreaks"
void DebuggerParser::executeListbreaks()
@ -1708,6 +1730,15 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
&DebuggerParser::executeHelp
},
{
"jump",
"Scroll disassembly to address xx",
true,
false,
{ kARG_WORD, kARG_END_ARGS },
&DebuggerParser::executeJump
},
{
"listbreaks",
"List breakpoints",

View File

@ -83,7 +83,7 @@ class DebuggerParser
private:
enum {
kNumCommands = 63,
kNumCommands = 64,
kMAX_ARG_TYPES = 10
};
@ -160,6 +160,7 @@ class DebuggerParser
void executeFunction();
void executeGfx();
void executeHelp();
void executeJump();
void executeListbreaks();
void executeListconfig();
void executeListfunctions();

View File

@ -23,7 +23,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
CartDebug::BankInfo& info, uInt16 banksize, bool resolvedata)
CartDebug::BankInfo& info, bool resolvedata)
: myDbg(dbg),
myList(list)
{
@ -39,7 +39,7 @@ DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
if(start & 0x1000)
{
if(banksize == 4) // 4K ROM space
if(info.banksize == 4096) // 4K ROM space
{
/*============================================
The offset is the address where the code segment
@ -52,7 +52,6 @@ DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
=============================================*/
myAppData.start = 0x0000;
myAppData.end = 0x0FFF;
myAppData.length = 4096;
myOffset = (start - (start % 0x1000));
}
@ -65,7 +64,6 @@ DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
=============================================*/
myAppData.start = 0x0000;
myAppData.end = 0x07FF;
myAppData.length = 2048;
myOffset = (start & 0xF800);
}
@ -75,10 +73,10 @@ DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
// For now, we assume all accesses below $1000 are zero-page
myAppData.start = 0x0080;
myAppData.end = 0x00FF;
myAppData.length = 128;
myOffset = 0;
}
myAppData.length = info.banksize;
info.start = myAppData.start;
info.end = myAppData.end;
@ -152,8 +150,6 @@ DiStella::~DiStella()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DiStella::disasm(uInt32 distart, int pass)
{
#define HEX4 uppercase << hex << setw(4) << setfill('0')
#define HEX2 uppercase << hex << setw(2) << setfill('0')
#define USER_OR_AUTO_LABEL(pre, address, post) \
const string& l = myDbg.getLabel(address, true); \
if(l != EmptyString) nextline << pre << l << post; \
@ -182,9 +178,15 @@ void DiStella::disasm(uInt32 distart, int pass)
else
myDisasmBuf << HEX4 << myPC+myOffset << "' '";
myDisasmBuf << ".byte $" << HEX2 << (int)Debugger::debugger().peek(myPC+myOffset) << " ";
showgfx(Debugger::debugger().peek(myPC+myOffset));
myDisasmBuf << " $" << HEX4 << myPC+myOffset << "'" << HEX2 << Debugger::debugger().peek(myPC+myOffset);
uInt8 byte = Debugger::debugger().peek(myPC+myOffset);
myDisasmBuf << ".byte $" << HEX2 << (int)byte << " |";
for(uInt8 i = 0, c = byte; i < 8; ++i, c <<= 1)
myDisasmBuf << ((c > 127) ? "X" : " ");
myDisasmBuf << "| $" << HEX4 << myPC+myOffset << "'";
if(settings.gfx_format == kBASE_2)
myDisasmBuf << Debugger::to_bin_8(byte);
else
myDisasmBuf << HEX2 << (int)byte;
addEntry(CartDebug::GFX);
}
myPC++;
@ -713,15 +715,6 @@ int DiStella::mark(uInt32 address, MarkType bit)
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DiStella::showgfx(uInt8 c)
{
myDisasmBuf << "|";
for(int i = 0; i < 8; ++i, c <<= 1)
myDisasmBuf << ((c > 127) ? "X" : " ");
myDisasmBuf << "|";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool DiStella::check_range(uInt32 beg, uInt32 end)
{
@ -871,6 +864,11 @@ void DiStella::processDirectives(const CartDebug::DirectiveList& directives)
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DiStella::Settings DiStella::settings = {
kBASE_2
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const DiStella::Instruction_tag DiStella::ourLookup[256] = {
/**** Positive ****/

View File

@ -49,14 +49,22 @@ class DiStella
@param dbg The CartDebug instance containing all label information
@param list The results of the disassembly are placed here
@param addresses The address(es) at which to start disassembly
@param banksize Size of the bank in KB (possible values are 4 or 2)
@param resolvedata If enabled, try to determine code vs. data sections
*/
DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
CartDebug::BankInfo& info, uInt16 banksize = 4, bool resolvedata = true);
CartDebug::BankInfo& info, bool resolvedata);
~DiStella();
public:
// A list of options that can be applied to the disassembly
// This will eventually grow to include all options supported by
// standalone Distella
typedef struct {
BaseFormat gfx_format;
} Settings;
static Settings settings;
private:
// Marked bits
// This is a reference sheet of bits that can be set for a given address, which
@ -83,7 +91,6 @@ class DiStella
// These functions are part of the original Distella code
void disasm(uInt32 distart, int pass);
int mark(uInt32 address, MarkType bit);
void showgfx(uInt8 c);
bool check_range(uInt32 start, uInt32 end);
inline int check_bit(uInt8 bitflags, int i) const { return (bitflags & i); }

View File

@ -637,7 +637,7 @@ bool DataGridWidget::tryInsertChar(char c, int pos)
// Not sure how efficient this is, or should we even care?
c = tolower(c);
if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
c == '%' || c == '#' || c == '$')
c == '\\' || c == '#' || c == '$')
{
_editString.insert(pos, 1, c);
return true;

View File

@ -65,6 +65,8 @@ RomListWidget::RomListWidget(GuiObject* boss, const GUI::Font& font,
l.push_back("Set PC", "setpc");
l.push_back("RunTo PC", "runtopc");
l.push_back("Re-disassemble", "disasm");
l.push_back("Show GFX as binary", "gfxbin");
l.push_back("Show GFX as hex", "gfxhex");
myMenu = new ContextMenu(this, font, l);
// Take advantage of a wide debugger window when possible
@ -126,6 +128,22 @@ void RomListWidget::setList(const CartDebug::Disassembly& disasm,
setDirty(); draw();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RomListWidget::setSelected(int item)
{
if(item < -1 || item >= (int)myDisasm->list.size())
return;
if(isEnabled())
{
if(_editMode)
abortEditMode();
_currentPos = _selectedItem = item;
scrollToSelected();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RomListWidget::setHighlighted(int item)
{
@ -541,7 +559,7 @@ bool RomListWidget::tryInsertChar(char c, int pos)
// Not sure how efficient this is, or should we even care?
c = tolower(c);
if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
c == '%' || c == '#' || c == '$' || c == ' ')
c == '\\' || c == '#' || c == '$' || c == ' ')
{
_editString.insert(pos, 1, c);
return true;

View File

@ -53,6 +53,7 @@ class RomListWidget : public EditableWidget
int getSelected() const { return _selectedItem; }
int getHighlighted() const { return _highlightedItem; }
void setSelected(int item);
void setHighlighted(int item);
const string& getEditString() const;

View File

@ -25,6 +25,7 @@
#include "Debugger.hxx"
#include "DebuggerParser.hxx"
#include "CartDebug.hxx"
#include "DiStella.hxx"
#include "CpuDebug.hxx"
#include "GuiObject.hxx"
#include "InputTextDialog.hxx"
@ -128,9 +129,9 @@ void RomWidget::loadConfig()
myListIsDirty = false;
}
// Update romlist to point to current PC
// Update romlist to point to current PC (if it has changed)
int pcline = cart.addressToLine(dbg.cpuDebug().pc());
if(pcline >= 0)
if(pcline >= 0 && pcline != myRomList->getHighlighted())
myRomList->setHighlighted(pcline);
// Set current bank and number of banks
@ -174,7 +175,18 @@ void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
runtoPC(myRomList->getSelected());
else if(rmb == "disasm")
invalidate();
else if(rmb == "gfxbin")
{
DiStella::settings.gfx_format = kBASE_2;
instance().settings().setString("gfxformat", "2");
invalidate();
}
else if(rmb == "gfxhex")
{
DiStella::settings.gfx_format = kBASE_16;
instance().settings().setString("gfxformat", "16");
invalidate();
}
break;
}
@ -263,11 +275,13 @@ void RomWidget::patchROM(int disasm_line, 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
// Temporarily set to correct base, so we don't have to prefix each byte
// with the type of data
BaseFormat oldbase = instance().debugger().parser().base();
instance().debugger().parser().setBase(kBASE_16);
if(list[disasm_line].type == CartDebug::GFX)
instance().debugger().parser().setBase(DiStella::settings.gfx_format);
else
instance().debugger().parser().setBase(kBASE_16);
command << "rom #" << list[disasm_line].address << " " << bytes;
instance().debugger().run(command.str());

View File

@ -28,13 +28,13 @@ class DataGridWidget;
class EditTextWidget;
class InputTextDialog;
class PopUpWidget;
class RomListWidget;
class StringList;
#include "Array.hxx"
#include "Widget.hxx"
#include "Command.hxx"
#include "CartDebug.hxx"
#include "RomListWidget.hxx"
class RomWidget : public Widget, public CommandSender
{
@ -44,6 +44,7 @@ class RomWidget : public Widget, public CommandSender
void invalidate() { myListIsDirty = true; loadConfig(); }
void scrollTo(int line) { myRomList->setSelected(line); }
void handleCommand(CommandSender* sender, int cmd, int data, int id);
void loadConfig();

View File

@ -152,17 +152,15 @@ string Serializer::getString(void)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Serializer::getBool(void)
{
bool result = false;
char b = getByte();
if(b == (char)TruePattern)
result = true;
return true;
else if(b == (char)FalsePattern)
result = false;
return false;
else
throw "Serializer::getBool() data corruption";
return result;
return false; // to stop compiler from complaining
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -131,6 +131,7 @@ Settings::Settings(OSystem* osystem)
// Debugger options
setInternal("resolvedata", "auto");
setInternal("gfxformat", "2");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -