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
===========================================================================
3.8.1 to 3.9: (XXXXX xx, 2013)
* Disassembly from debugger ...
-Have fun!
3.8 to 3.8.1: (March 3, 2013)
* Added support for TIA RSYNC writes, thanks to Omegamatrix of AtariAge.
@ -27,8 +34,6 @@
* The OSX DMG archive now contains proper modification dates.
-Have fun!
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 capacity() const { return _capacity; }
void clear()
void clear(bool fullerase = true)
{
if(_data)
if(fullerase)
{
delete [] _data;
_data = 0;
if(_data)
{
delete [] _data;
_data = 0;
}
_capacity = 0;
}
_size = 0;
_capacity = 0;
}
bool isEmpty() const

View File

@ -17,6 +17,8 @@
// $Id$
//============================================================================
#include <time.h>
#include "bspf.hxx"
#include "Array.hxx"
#include "System.hxx"
@ -26,6 +28,7 @@
#include "CpuDebug.hxx"
#include "OSystem.hxx"
#include "Settings.hxx"
#include "Version.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 found = false;
myDisassembly.list.clear();
myDisassembly.list.reserve(2048);
myDisassembly.fieldwidth = 10 + myLabelLength;
DiStella distella(*this, myDisassembly.list, info,
DiStella distella(*this, myDisassembly.list, info, DiStella::settings,
myDisLabels, myDisDirectives, resolvedata);
// Parts of the disassembly will be accessed later in different ways
// We place those parts in separate maps, to speed up access
bool found = false;
myAddrToLineList.clear();
for(uInt32 i = 0; i < myDisassembly.list.size(); ++i)
{
@ -320,8 +322,8 @@ string CartDebug::disassemble(uInt16 start, uInt16 lines) const
BankInfo info;
uInt8 labels[0x1000], directives[0x1000];
info.addressList.push_back(start);
DiStella distella(*this, disasm.list, info, (uInt8*)labels,
(uInt8*)directives, false);
DiStella distella(*this, disasm.list, info, DiStella::settings,
(uInt8*)labels, (uInt8*)directives, false);
// Fill the string with disassembled data
start &= 0xFFF;
@ -836,6 +838,119 @@ string CartDebug::saveConfigFile(string file)
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)
{
@ -965,8 +1080,8 @@ void CartDebug::getBankDirectives(ostream& buf, BankInfo& info) const
{
// Disassemble the bank, then scan it for an up-to-date description
DisassemblyList list;
DiStella distella(*this, list, info, (uInt8*)myDisLabels,
(uInt8*)myDisDirectives, true);
DiStella distella(*this, list, info, DiStella::settings,
(uInt8*)myDisLabels, (uInt8*)myDisDirectives, true);
if(list.size() == 0)
return;

View File

@ -230,10 +230,11 @@ class CartDebug : public DebuggerSystem
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 saveConfigFile(string file = "");
string saveDisassembly(string file = "");
/**
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();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "savedis"
void DebuggerParser::executeSavedisassembly()
{
if(argCount == 1)
commandResult << debugger->cartDebug().saveDisassembly(argStrings[0]);
else
commandResult << debugger->cartDebug().saveDisassembly();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "saverom"
void DebuggerParser::executeSaverom()
@ -2101,6 +2111,15 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
&DebuggerParser::executeSaveconfig
},
{
"savedis",
"Save Distella disassembly [to file xx]",
false,
false,
{ kARG_FILE, kARG_MULTI_BYTE },
&DebuggerParser::executeSavedisassembly
},
{
"saverom",
"Save (possibly patched) ROM to file xx",

View File

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

View File

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

View File

@ -40,23 +40,6 @@
*/
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:
// A list of options that can be applied to the disassembly
// 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 rflag; // Relocate calls out of address range (-r in Distella)
} 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:
// Indicate that a new line of disassembly has been completed
@ -88,6 +89,7 @@ class DiStella
private:
const CartDebug& myDbg;
CartDebug::DisassemblyList& myList;
const Settings& mySettings;
stringstream myDisasmBuf;
queue<uInt16> myAddressQueue;
uInt16 myOffset, myPC, myPCBeg, myPCEnd;