First pass at adding diassembly output from the debugger. It's already

working quite well for a single-bank ROM, but more work is required for
multi-bank.  Output is currently sent to the console, as I'm still in
the formatting phase.  Saving to a file will be easy once the format
is nailed down.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2657 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2013-03-04 23:35:26 +00:00
parent 85d20516d4
commit ffc99a9345
8 changed files with 192 additions and 45 deletions

View File

@ -12,6 +12,13 @@
Release History Release History
=========================================================================== ===========================================================================
3.8.1 to 3.9: (XXXXX xx, 2013)
* Disassembly from debugger ...
-Have fun!
3.8 to 3.8.1: (March 3, 2013) 3.8 to 3.8.1: (March 3, 2013)
* Added support for TIA RSYNC writes, thanks to Omegamatrix of AtariAge. * Added support for TIA RSYNC writes, thanks to Omegamatrix of AtariAge.
@ -27,8 +34,6 @@
* The OSX DMG archive now contains proper modification dates. * The OSX DMG archive now contains proper modification dates.
-Have fun!
3.7.5 to 3.8: (February 21, 2013) 3.7.5 to 3.8: (February 21, 2013)

View File

@ -132,15 +132,18 @@ class Array
unsigned int size() const { return _size; } unsigned int size() const { return _size; }
unsigned int capacity() const { return _capacity; } unsigned int capacity() const { return _capacity; }
void clear() void clear(bool fullerase = true)
{ {
if(_data) if(fullerase)
{ {
delete [] _data; if(_data)
_data = 0; {
delete [] _data;
_data = 0;
}
_capacity = 0;
} }
_size = 0; _size = 0;
_capacity = 0;
} }
bool isEmpty() const bool isEmpty() const

View File

@ -17,6 +17,8 @@
// $Id$ // $Id$
//============================================================================ //============================================================================
#include <time.h>
#include "bspf.hxx" #include "bspf.hxx"
#include "Array.hxx" #include "Array.hxx"
#include "System.hxx" #include "System.hxx"
@ -26,6 +28,7 @@
#include "CpuDebug.hxx" #include "CpuDebug.hxx"
#include "OSystem.hxx" #include "OSystem.hxx"
#include "Settings.hxx" #include "Settings.hxx"
#include "Version.hxx"
#include "CartDebug.hxx" #include "CartDebug.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -277,16 +280,15 @@ bool CartDebug::disassemble(const string& resolvedata, bool force)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartDebug::fillDisassemblyList(BankInfo& info, bool resolvedata, uInt16 search) bool CartDebug::fillDisassemblyList(BankInfo& info, bool resolvedata, uInt16 search)
{ {
bool found = false;
myDisassembly.list.clear(); myDisassembly.list.clear();
myDisassembly.list.reserve(2048); myDisassembly.list.reserve(2048);
myDisassembly.fieldwidth = 10 + myLabelLength; myDisassembly.fieldwidth = 10 + myLabelLength;
DiStella distella(*this, myDisassembly.list, info, DiStella distella(*this, myDisassembly.list, info, DiStella::settings,
myDisLabels, myDisDirectives, resolvedata); myDisLabels, myDisDirectives, resolvedata);
// Parts of the disassembly will be accessed later in different ways // Parts of the disassembly will be accessed later in different ways
// We place those parts in separate maps, to speed up access // We place those parts in separate maps, to speed up access
bool found = false;
myAddrToLineList.clear(); myAddrToLineList.clear();
for(uInt32 i = 0; i < myDisassembly.list.size(); ++i) for(uInt32 i = 0; i < myDisassembly.list.size(); ++i)
{ {
@ -320,8 +322,8 @@ string CartDebug::disassemble(uInt16 start, uInt16 lines) const
BankInfo info; BankInfo info;
uInt8 labels[0x1000], directives[0x1000]; uInt8 labels[0x1000], directives[0x1000];
info.addressList.push_back(start); info.addressList.push_back(start);
DiStella distella(*this, disasm.list, info, (uInt8*)labels, DiStella distella(*this, disasm.list, info, DiStella::settings,
(uInt8*)directives, false); (uInt8*)labels, (uInt8*)directives, false);
// Fill the string with disassembled data // Fill the string with disassembled data
start &= 0xFFF; start &= 0xFFF;
@ -836,6 +838,119 @@ string CartDebug::saveConfigFile(string file)
return DebuggerParser::red("config file not found"); return DebuggerParser::red("config file not found");
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string CartDebug::saveDisassembly(string file)
{
#define ALIGN(x) setfill(' ') << left << setw(x)
if(myConsole.cartridge().bankCount() > 1)
return DebuggerParser::red("multi-bank ROM not yet supported");
// Output stream for disassembly
ostringstream buf;
// Some boilerplate, similar to what DiStella adds
time_t currtime;
time(&currtime);
buf << "; Disassembly of " << file << "\n"
<< "; Disassembled " << ctime(&currtime)
<< "; Using Stella " << STELLA_VERSION << "\n"
<< ";\n"
<< "; Command Line arguments: TODO - add args\n"
<< "\n"
<< "; Legend: * = CODE not yet run (preliminary code)\n"
<< "; D = DATA directive (referenced in some way)\n"
<< "; G = GFX directive, shown as 'X' (stored in player, missile, ball)\n"
<< "; P = PGFX directive, shown as 'x' (stored in playfield)\n"
<< "\n"
<< " processor 6502\n"
<< " TODO - add equates\n"
<< "\n";
// Use specific settings for disassembly output
// This will most likely differ from what you see in the debugger
DiStella::Settings settings;
settings.gfx_format = DiStella::settings.gfx_format;
settings.show_addresses = false;
settings.fflag = DiStella::settings.fflag;
settings.rflag = DiStella::settings.rflag;
Disassembly disasm;
disasm.list.reserve(2048);
disasm.fieldwidth = 10 + myLabelLength;
for(int bank = 0; bank < myConsole.cartridge().bankCount(); ++bank)
{
BankInfo& info = myBankInfo[bank];
// Disassemble bank
disasm.list.clear(false); // don't fully de-allocate space
DiStella distella(*this, disasm.list, info, settings,
myDisLabels, myDisDirectives, true);
buf << " ORG $" << HEX4 << info.offset << "\n\n";
// Format in 'distella' style
for(uInt32 i = 0; i < disasm.list.size(); ++i)
{
const DisassemblyTag& tag = disasm.list[i];
// Add label (if any)
if(tag.label != "")
buf << ALIGN(7) << (tag.label+":");
else
buf << " ";
switch(tag.type)
{
case CartDebug::CODE:
{
buf << ALIGN(16) << tag.disasm << tag.ccount << "\n";
break;
}
case CartDebug::NONE:
{
buf << "\n";
break;
}
case CartDebug::ROW:
{
buf << tag.disasm << "\n";
break;
}
case CartDebug::GFX:
{
buf << tag.disasm.substr(0, 9) << " ; |";
for(int i = 12; i < 20; ++i)
buf << ((tag.disasm[i] == '\x1e') ? "X" : " ");
buf << "| $" << HEX4 << tag.address << " (G)\n";
break;
}
case CartDebug::PGFX:
{
buf << tag.disasm.substr(0, 9) << " ; |";
for(int i = 12; i < 20; ++i)
buf << ((tag.disasm[i] == '\x1f') ? "x" : " ");
buf << "| $" << HEX4 << tag.address << " (P)\n";
break;
}
case CartDebug::DATA:
{
buf << tag.disasm.substr(0, 9) << " ; $" << HEX4 << tag.address << " (D)\n";
break;
}
default:
{
buf << "\n";
break;
}
}
}
}
cout << buf.str() << endl; // TODO - redirect to file
return DebuggerParser::red("not save to file yet");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string CartDebug::listConfig(int bank) string CartDebug::listConfig(int bank)
{ {
@ -965,8 +1080,8 @@ void CartDebug::getBankDirectives(ostream& buf, BankInfo& info) const
{ {
// Disassemble the bank, then scan it for an up-to-date description // Disassemble the bank, then scan it for an up-to-date description
DisassemblyList list; DisassemblyList list;
DiStella distella(*this, list, info, (uInt8*)myDisLabels, DiStella distella(*this, list, info, DiStella::settings,
(uInt8*)myDisDirectives, true); (uInt8*)myDisLabels, (uInt8*)myDisDirectives, true);
if(list.size() == 0) if(list.size() == 0)
return; return;

View File

@ -230,10 +230,11 @@ class CartDebug : public DebuggerSystem
string loadSymbolFile(string file = ""); string loadSymbolFile(string file = "");
/** /**
Load/save Distella config file (Distella directives) Load/save Distella config file (Distella directives) and disassembly
*/ */
string loadConfigFile(string file = ""); string loadConfigFile(string file = "");
string saveConfigFile(string file = ""); string saveConfigFile(string file = "");
string saveDisassembly(string file = "");
/** /**
Show Distella directives (both set by the user and determined by Distella) Show Distella directives (both set by the user and determined by Distella)

View File

@ -1422,6 +1422,16 @@ void DebuggerParser::executeSaveconfig()
commandResult << debugger->cartDebug().saveConfigFile(); commandResult << debugger->cartDebug().saveConfigFile();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "savedis"
void DebuggerParser::executeSavedisassembly()
{
if(argCount == 1)
commandResult << debugger->cartDebug().saveDisassembly(argStrings[0]);
else
commandResult << debugger->cartDebug().saveDisassembly();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "saverom" // "saverom"
void DebuggerParser::executeSaverom() void DebuggerParser::executeSaverom()
@ -2101,6 +2111,15 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
&DebuggerParser::executeSaveconfig &DebuggerParser::executeSaveconfig
}, },
{
"savedis",
"Save Distella disassembly [to file xx]",
false,
false,
{ kARG_FILE, kARG_MULTI_BYTE },
&DebuggerParser::executeSavedisassembly
},
{ {
"saverom", "saverom",
"Save (possibly patched) ROM to file xx", "Save (possibly patched) ROM to file xx",

View File

@ -90,7 +90,7 @@ class DebuggerParser
private: private:
enum { enum {
kNumCommands = 70, kNumCommands = 71,
kMAX_ARG_TYPES = 10 kMAX_ARG_TYPES = 10
}; };
@ -193,6 +193,7 @@ class DebuggerParser
void executeS(); void executeS();
void executeSave(); void executeSave();
void executeSaveconfig(); void executeSaveconfig();
void executeSavedisassembly();
void executeSaverom(); void executeSaverom();
void executeSaveses(); void executeSaveses();
void executeSavestate(); void executeSavestate();

View File

@ -23,10 +23,11 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list, DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
CartDebug::BankInfo& info, uInt8* labels, uInt8* directives, CartDebug::BankInfo& info, const DiStella::Settings& settings,
bool resolvedata) uInt8* labels, uInt8* directives, bool resolvedata)
: myDbg(dbg), : myDbg(dbg),
myList(list), myList(list),
mySettings(settings),
myLabels(labels), myLabels(labels),
myDirectives(directives) myDirectives(directives)
{ {
@ -228,7 +229,7 @@ void DiStella::disasm(uInt32 distart, int pass)
for(uInt8 i = 0, c = byte; i < 8; ++i, c <<= 1) for(uInt8 i = 0, c = byte; i < 8; ++i, c <<= 1)
myDisasmBuf << ((c > 127) ? bit_string : " "); myDisasmBuf << ((c > 127) ? bit_string : " ");
myDisasmBuf << "| $" << HEX4 << myPC+myOffset << "'"; myDisasmBuf << "| $" << HEX4 << myPC+myOffset << "'";
if(settings.gfx_format == kBASE_2) if(mySettings.gfx_format == kBASE_2)
myDisasmBuf << Debugger::debugger().valueToString(byte, kBASE_2_8); myDisasmBuf << Debugger::debugger().valueToString(byte, kBASE_2_8);
else else
myDisasmBuf << HEX2 << (int)byte; myDisasmBuf << HEX2 << (int)byte;
@ -458,7 +459,7 @@ void DiStella::disasm(uInt32 distart, int pass)
} }
else if (pass == 3) else if (pass == 3)
{ {
if (ad < 0x100 && settings.fflag) if (ad < 0x100 && mySettings.fflag)
nextline << ".w "; nextline << ".w ";
else else
nextline << " "; nextline << " ";
@ -473,7 +474,7 @@ void DiStella::disasm(uInt32 distart, int pass)
nextline << CartDebug::ourIOMnemonic[ad-0x280]; nextline << CartDebug::ourIOMnemonic[ad-0x280];
nextlinebytes << HEX2 << (int)(ad&0xff) << " " << HEX2 << (int)(ad>>8); nextlinebytes << HEX2 << (int)(ad&0xff) << " " << HEX2 << (int)(ad>>8);
} }
else if (labfound == 4 && settings.rflag) else if (labfound == 4 && mySettings.rflag)
{ {
int tmp = (ad & myAppData.end)+myOffset; int tmp = (ad & myAppData.end)+myOffset;
USER_OR_AUTO_LABEL("", tmp, ""); USER_OR_AUTO_LABEL("", tmp, "");
@ -530,7 +531,7 @@ void DiStella::disasm(uInt32 distart, int pass)
} }
else if (pass == 3) else if (pass == 3)
{ {
if (ad < 0x100 && settings.fflag) if (ad < 0x100 && mySettings.fflag)
nextline << ".wx "; nextline << ".wx ";
else else
nextline << " "; nextline << " ";
@ -545,7 +546,7 @@ void DiStella::disasm(uInt32 distart, int pass)
nextline << CartDebug::ourIOMnemonic[ad-0x280] << ",X"; nextline << CartDebug::ourIOMnemonic[ad-0x280] << ",X";
nextlinebytes << HEX2 << (int)(ad&0xff) << " " << HEX2 << (int)(ad>>8); nextlinebytes << HEX2 << (int)(ad&0xff) << " " << HEX2 << (int)(ad>>8);
} }
else if (labfound == 4 && settings.rflag) else if (labfound == 4 && mySettings.rflag)
{ {
int tmp = (ad & myAppData.end)+myOffset; int tmp = (ad & myAppData.end)+myOffset;
USER_OR_AUTO_LABEL("", tmp, ",X"); USER_OR_AUTO_LABEL("", tmp, ",X");
@ -574,7 +575,7 @@ void DiStella::disasm(uInt32 distart, int pass)
} }
else if (pass == 3) else if (pass == 3)
{ {
if (ad < 0x100 && settings.fflag) if (ad < 0x100 && mySettings.fflag)
nextline << ".wy "; nextline << ".wy ";
else else
nextline << " "; nextline << " ";
@ -589,7 +590,7 @@ void DiStella::disasm(uInt32 distart, int pass)
nextline << CartDebug::ourIOMnemonic[ad-0x280] << ",Y"; nextline << CartDebug::ourIOMnemonic[ad-0x280] << ",Y";
nextlinebytes << HEX2 << (int)(ad&0xff) << " " << HEX2 << (int)(ad>>8); nextlinebytes << HEX2 << (int)(ad&0xff) << " " << HEX2 << (int)(ad>>8);
} }
else if (labfound == 4 && settings.rflag) else if (labfound == 4 && mySettings.rflag)
{ {
int tmp = (ad & myAppData.end)+myOffset; int tmp = (ad & myAppData.end)+myOffset;
USER_OR_AUTO_LABEL("", tmp, ",Y"); USER_OR_AUTO_LABEL("", tmp, ",Y");
@ -705,7 +706,7 @@ void DiStella::disasm(uInt32 distart, int pass)
} }
else if (pass == 3) else if (pass == 3)
{ {
if (ad < 0x100 && settings.fflag) if (ad < 0x100 && mySettings.fflag)
nextline << ".ind "; nextline << ".ind ";
else else
nextline << " "; nextline << " ";
@ -915,7 +916,7 @@ void DiStella::addEntry(CartDebug::DisasmType type)
{ {
if(myDisasmBuf.peek() != ' ') if(myDisasmBuf.peek() != ' ')
getline(myDisasmBuf, tag.label, '\''); getline(myDisasmBuf, tag.label, '\'');
else if(settings.show_addresses && tag.type == CartDebug::CODE) else if(mySettings.show_addresses && tag.type == CartDebug::CODE)
{ {
// Have addresses indented, to differentiate from actual labels // Have addresses indented, to differentiate from actual labels
char address[7]; char address[7];

View File

@ -40,23 +40,6 @@
*/ */
class DiStella class DiStella
{ {
public:
/**
Disassemble the current state of the System from the given start address.
@param dbg The CartDebug instance containing all label information
@param list The results of the disassembly are placed here
@param info Various info about the current bank
@param labels Array storing label info determined by Distella
@param directives Array storing directive info determined by Distella
@param resolvedata If enabled, try to determine code vs. data sections
*/
DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
CartDebug::BankInfo& info, uInt8* labels, uInt8* directives,
bool resolvedata);
~DiStella();
public: public:
// A list of options that can be applied to the disassembly // A list of options that can be applied to the disassembly
// This will eventually grow to include all options supported by // This will eventually grow to include all options supported by
@ -67,7 +50,25 @@ class DiStella
bool fflag; // Forces correct address length (-f in Distella) bool fflag; // Forces correct address length (-f in Distella)
bool rflag; // Relocate calls out of address range (-r in Distella) bool rflag; // Relocate calls out of address range (-r in Distella)
} Settings; } Settings;
static Settings settings; static Settings settings; // Default settings
public:
/**
Disassemble the current state of the System from the given start address.
@param dbg The CartDebug instance containing all label information
@param list The results of the disassembly are placed here
@param info Various info about the current bank
@param settings The various distella flags/options to use
@param labels Array storing label info determined by Distella
@param directives Array storing directive info determined by Distella
@param resolvedata If enabled, try to determine code vs. data sections
*/
DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
CartDebug::BankInfo& info, const DiStella::Settings& settings,
uInt8* labels, uInt8* directives, bool resolvedata);
~DiStella();
private: private:
// Indicate that a new line of disassembly has been completed // Indicate that a new line of disassembly has been completed
@ -88,6 +89,7 @@ class DiStella
private: private:
const CartDebug& myDbg; const CartDebug& myDbg;
CartDebug::DisassemblyList& myList; CartDebug::DisassemblyList& myList;
const Settings& mySettings;
stringstream myDisasmBuf; stringstream myDisasmBuf;
queue<uInt16> myAddressQueue; queue<uInt16> myAddressQueue;
uInt16 myOffset, myPC, myPCBeg, myPCEnd; uInt16 myOffset, myPC, myPCBeg, myPCEnd;