diff --git a/Changes.txt b/Changes.txt index 4b8d84ad1..ee51842ef 100644 --- a/Changes.txt +++ b/Changes.txt @@ -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) diff --git a/src/common/Array.hxx b/src/common/Array.hxx index cd3739357..313bd861b 100644 --- a/src/common/Array.hxx +++ b/src/common/Array.hxx @@ -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 diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index b5313aa9b..4dea993ff 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -17,6 +17,8 @@ // $Id$ //============================================================================ +#include + #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; diff --git a/src/debugger/CartDebug.hxx b/src/debugger/CartDebug.hxx index 2fcd5a2bc..569c05ab1 100644 --- a/src/debugger/CartDebug.hxx +++ b/src/debugger/CartDebug.hxx @@ -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) diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index ee6122eee..d65b5954b 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -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", diff --git a/src/debugger/DebuggerParser.hxx b/src/debugger/DebuggerParser.hxx index ba9892ee1..9446840bf 100644 --- a/src/debugger/DebuggerParser.hxx +++ b/src/debugger/DebuggerParser.hxx @@ -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(); diff --git a/src/debugger/DiStella.cxx b/src/debugger/DiStella.cxx index c2ce4adfc..9b663c42a 100644 --- a/src/debugger/DiStella.cxx +++ b/src/debugger/DiStella.cxx @@ -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]; diff --git a/src/debugger/DiStella.hxx b/src/debugger/DiStella.hxx index e008affc8..507d5e7dc 100644 --- a/src/debugger/DiStella.hxx +++ b/src/debugger/DiStella.hxx @@ -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 myAddressQueue; uInt16 myOffset, myPC, myPCBeg, myPCEnd;