mirror of https://github.com/stella-emu/stella.git
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:
parent
85d20516d4
commit
ffc99a9345
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue