First pass at extending the disassembler to support CODE/DATA/GFX commands

from a Distella config file.  For now, the commands are only accessible
within the debugger prompt, and can only be added (no removal/editing).


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2120 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2010-08-30 12:04:56 +00:00
parent 12c9edaed0
commit e0dd8b1451
8 changed files with 336 additions and 94 deletions

View File

@ -37,15 +37,15 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const RamAreaList& areas)
for(RamAreaList::const_iterator i = areas.begin(); i != areas.end(); ++i) for(RamAreaList::const_iterator i = areas.begin(); i != areas.end(); ++i)
addRamArea(i->start, i->size, i->roffset, i->woffset); addRamArea(i->start, i->size, i->roffset, i->woffset);
// Create an addresslist for each potential bank, and an extra one for ZP RAM // Create bank information for each potential bank, and an extra one for ZP RAM
for(int i = 0; i < myConsole.cartridge().bankCount()+1; ++i) for(int i = 0; i < myConsole.cartridge().bankCount()+1; ++i)
{ {
AddressList l; BankInfo info;
myEntryAddresses.push_back(l); myBankInfo.push_back(info);
} }
// We know the address for the startup bank right now // We know the address for the startup bank right now
myEntryAddresses[myConsole.cartridge().startBank()].push_back(myDebugger.dpeek(0xfffc)); myBankInfo[myConsole.cartridge().startBank()].addressList.push_back(myDebugger.dpeek(0xfffc));
addLabel("START", myDebugger.dpeek(0xfffc)); addLabel("START", myDebugger.dpeek(0xfffc));
// Add system equates // Add system equates
@ -64,9 +64,12 @@ CartDebug::~CartDebug()
myUserAddresses.clear(); myUserAddresses.clear();
mySystemAddresses.clear(); mySystemAddresses.clear();
for(uInt32 i = 0; i < myEntryAddresses.size(); ++i) for(uInt32 i = 0; i < myBankInfo.size(); ++i)
myEntryAddresses[i].clear(); {
myEntryAddresses.clear(); myBankInfo[i].addressList.clear();
myBankInfo[i].directiveList.clear();
}
myBankInfo.clear();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -206,14 +209,15 @@ bool CartDebug::disassemble(const string& resolvedata, bool force)
if(changed) if(changed)
{ {
// Are we disassembling from ROM or ZP RAM? // Are we disassembling from ROM or ZP RAM?
AddressList& addresses = (PC & 0x1000) ? myEntryAddresses[getBank()] : BankInfo& info = (PC & 0x1000) ? myBankInfo[getBank()] :
myEntryAddresses[myEntryAddresses.size()-1]; myBankInfo[myBankInfo.size()-1];
// If the offset has changed, all old addresses must be 'converted' // If the offset has changed, all old addresses must be 'converted'
// For example, if the list contains any $fxxx and the address space is now // For example, if the list contains any $fxxx and the address space is now
// $bxxx, it must be changed // $bxxx, it must be changed
uInt16 offset = (PC - (PC % 0x1000)); uInt16 offset = (PC - (PC % 0x1000));
for(AddressList::iterator i = addresses.begin(); i != addresses.end(); ++i) AddressList& addresses = info.addressList;
for(list<uInt16>::iterator i = addresses.begin(); i != addresses.end(); ++i)
*i = (*i & 0xFFF) + offset; *i = (*i & 0xFFF) + offset;
// Only add addresses when absolutely necessary, to cut down on the // Only add addresses when absolutely necessary, to cut down on the
@ -239,14 +243,14 @@ bool CartDebug::disassemble(const string& resolvedata, bool force)
// Check whether to use the 'resolvedata' functionality from Distella // Check whether to use the 'resolvedata' functionality from Distella
if(resolvedata == "never") if(resolvedata == "never")
fillDisassemblyList(addresses, false, PC); fillDisassemblyList(info, false, PC);
else if(resolvedata == "always") else if(resolvedata == "always")
fillDisassemblyList(addresses, true, PC); fillDisassemblyList(info, true, PC);
else // 'auto' else // 'auto'
{ {
// First try with resolvedata on, then turn off if PC isn't found // First try with resolvedata on, then turn off if PC isn't found
if(!fillDisassemblyList(addresses, true, PC)) if(!fillDisassemblyList(info, true, PC))
fillDisassemblyList(addresses, false, PC); fillDisassemblyList(info, false, PC);
} }
} }
@ -254,8 +258,7 @@ bool CartDebug::disassemble(const string& resolvedata, bool force)
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartDebug::fillDisassemblyList(AddressList& addresses, bool CartDebug::fillDisassemblyList(BankInfo& info, bool resolvedata, uInt16 search)
bool resolvedata, uInt16 search)
{ {
bool found = false; bool found = false;
@ -263,7 +266,7 @@ bool CartDebug::fillDisassemblyList(AddressList& addresses,
myDisassembly.fieldwidth = 10 + myLabelLength; myDisassembly.fieldwidth = 10 + myLabelLength;
uInt16 banksize = uInt16 banksize =
!BSPF_equalsIgnoreCase(myConsole.cartridge().name(), "Cartridge2K") ? 4 : 2; !BSPF_equalsIgnoreCase(myConsole.cartridge().name(), "Cartridge2K") ? 4 : 2;
DiStella distella(*this, myDisassembly.list, addresses, banksize, resolvedata); DiStella distella(*this, myDisassembly.list, info, banksize, 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
@ -272,8 +275,8 @@ bool CartDebug::fillDisassemblyList(AddressList& addresses,
{ {
const DisassemblyTag& tag = myDisassembly.list[i]; const DisassemblyTag& tag = myDisassembly.list[i];
// Only non-zero addresses are valid // Only addresses marked as 'CODE' can possibly be in the program counter
if(tag.address != 0) if(tag.type == CODE)
{ {
// Create a mapping from addresses to line numbers // Create a mapping from addresses to line numbers
myAddrToLineList.insert(make_pair(tag.address, i)); myAddrToLineList.insert(make_pair(tag.address, i));
@ -297,11 +300,11 @@ int CartDebug::addressToLine(uInt16 address) const
string CartDebug::disassemble(uInt16 start, uInt16 lines) const string CartDebug::disassemble(uInt16 start, uInt16 lines) const
{ {
Disassembly disasm; Disassembly disasm;
AddressList addresses; BankInfo info;
addresses.push_back(start); info.addressList.push_back(start);
uInt16 banksize = uInt16 banksize =
!BSPF_equalsIgnoreCase(myConsole.cartridge().name(), "Cartridge2K") ? 4 : 2; !BSPF_equalsIgnoreCase(myConsole.cartridge().name(), "Cartridge2K") ? 4 : 2;
DiStella distella(*this, disasm.list, addresses, banksize, false); DiStella distella(*this, disasm.list, info, banksize, false);
// Fill the string with disassembled data // Fill the string with disassembled data
start &= 0xFFF; start &= 0xFFF;
@ -335,6 +338,21 @@ string CartDebug::disassemble(uInt16 start, uInt16 lines) const
return buffer.str(); return buffer.str();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartDebug::addDirective(CartDebug::DisasmType type, uInt16 start, uInt16 end)
{
BankInfo& info = (myDebugger.cpuDebug().pc() & 0x1000) ?
myBankInfo[getBank()] : myBankInfo[myBankInfo.size()-1];
DirectiveTag tag;
tag.type = type;
tag.start = start;
tag.end = end;
info.directiveList.push_back(tag);
// FIXME - process the request somehow; don't just automatically add it to the list
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int CartDebug::getBank() int CartDebug::getBank()
{ {

View File

@ -32,9 +32,6 @@ class System;
#include "StringList.hxx" #include "StringList.hxx"
#include "DebuggerSystem.hxx" #include "DebuggerSystem.hxx"
// Array of addresses
typedef list<uInt16> AddressList;
// pointer types for CartDebug instance methods // pointer types for CartDebug instance methods
typedef int (CartDebug::*CARTDEBUG_INT_METHOD)(); typedef int (CartDebug::*CARTDEBUG_INT_METHOD)();
@ -55,7 +52,14 @@ class CartDebug : public DebuggerSystem
friend class DiStella; friend class DiStella;
public: public:
enum DisasmType {
GFX = 1 << 0,
DATA = 1 << 1,
CODE = 1 << 2,
NONE = 1 << 3
};
struct DisassemblyTag { struct DisassemblyTag {
DisasmType type;
uInt16 address; uInt16 address;
string label; string label;
string disasm; string disasm;
@ -146,6 +150,20 @@ class CartDebug : public DebuggerSystem
*/ */
string disassemble(uInt16 start, uInt16 lines) const; string disassemble(uInt16 start, uInt16 lines) const;
/**
Add a directive to the disassembler. Directives are basically overrides
for the automatic code determination algorithm in Distella, since some
things can't be automatically determined. For now, these directives
have exactly the same syntax as in a distella configuration file.
@param type Currently, CODE/DATA/GFX are supported
@param start The start address (inclusive) to mark with the given type
@param end The end address (inclusive) to mark with the given type
@return The disassembly represented as a string
*/
void addDirective(CartDebug::DisasmType type, uInt16 start, uInt16 end);
// The following are convenience methods that query the cartridge object // The following are convenience methods that query the cartridge object
// for the desired information. // for the desired information.
/** /**
@ -212,10 +230,25 @@ class CartDebug : public DebuggerSystem
}; };
AddrType addressType(uInt16 addr) const; AddrType addressType(uInt16 addr) const;
typedef struct {
DisasmType type;
uInt16 start;
uInt16 end;
} DirectiveTag;
typedef list<uInt16> AddressList;
typedef list<DirectiveTag> DirectiveList;
typedef struct {
uInt16 start; // start of address space
uInt16 end; // end of address space
uInt16 offset; // ORG value
AddressList addressList; // addresses which PC has hit
DirectiveList directiveList; // overrides for automatic code determination
} BankInfo;
// Actually call DiStella to fill the DisassemblyList structure // Actually call DiStella to fill the DisassemblyList structure
// Return whether the search address was actually in the list // Return whether the search address was actually in the list
bool fillDisassemblyList(AddressList& addresses, bool fillDisassemblyList(BankInfo& bankinfo, bool resolvedata, uInt16 search);
bool resolvedata, uInt16 search);
// Extract labels and values from the given character stream // Extract labels and values from the given character stream
string extractLabel(const char* c) const; string extractLabel(const char* c) const;
@ -225,12 +258,8 @@ class CartDebug : public DebuggerSystem
CartState myState; CartState myState;
CartState myOldState; CartState myOldState;
// A list of 'entry' addresses for each bank in a cart // A complete record of relevant diassembly information for each bank
// An entry address is the one at which time the debugger 'enters' the Common::Array<BankInfo> myBankInfo;
// disassembler
// The startup bank will normally be 0xfffc, while the others are
// determined when the debugger is first opened
Common::Array<AddressList> myEntryAddresses;
// Used for the disassembly display, and mapping from addresses // Used for the disassembly display, and mapping from addresses
// to corresponding lines of text in that display // to corresponding lines of text in that display

View File

@ -790,6 +790,27 @@ void DebuggerParser::executeCls()
commandResult << ""; commandResult << "";
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "code"
void DebuggerParser::executeCode()
{
if(argCount != 2)
{
commandResult << red("Specify start and end of range only");
return;
}
else if(args[1] < args[0])
{
commandResult << red("Start address must be <= end address");
return;
}
debugger->cartDebug().addDirective(CartDebug::CODE, args[0], args[1]);
commandResult << "added CODE directive on range $" << hex << args[0]
<< " $" << hex << args[1];
debugger->myRom->invalidate();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "colortest" // "colortest"
void DebuggerParser::executeColortest() void DebuggerParser::executeColortest()
@ -809,6 +830,27 @@ void DebuggerParser::executeD()
debugger->cpuDebug().setD(args[0]); debugger->cpuDebug().setD(args[0]);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "data"
void DebuggerParser::executeData()
{
if(argCount != 2)
{
commandResult << red("Specify start and end of range only");
return;
}
else if(args[1] < args[0])
{
commandResult << red("Start address must be <= end address");
return;
}
debugger->cartDebug().addDirective(CartDebug::DATA, args[0], args[1]);
commandResult << "added DATA directive on range $" << hex << args[0]
<< " $" << hex << args[1];
debugger->myRom->invalidate();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "define" // "define"
void DebuggerParser::executeDefine() void DebuggerParser::executeDefine()
@ -895,25 +937,6 @@ void DebuggerParser::executeExec()
commandResult << exec(file); commandResult << exec(file);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "help"
void DebuggerParser::executeHelp()
{
// Find length of longest command
uInt16 clen = 0;
for(int i = 0; i < kNumCommands; ++i)
{
uInt16 len = commands[i].cmdString.length();
if(len > clen) clen = len;
}
for(int i = 0; i < kNumCommands; ++i)
commandResult << setw(clen) << right << commands[i].cmdString
<< " - " << commands[i].description << endl;
commandResult << debugger->builtinHelp();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "frame" // "frame"
void DebuggerParser::executeFrame() void DebuggerParser::executeFrame()
@ -945,6 +968,46 @@ void DebuggerParser::executeFunction()
commandResult << red("invalid expression"); commandResult << red("invalid expression");
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "gfx"
void DebuggerParser::executeGfx()
{
if(argCount != 2)
{
commandResult << red("Specify start and end of range only");
return;
}
else if(args[1] < args[0])
{
commandResult << red("Start address must be <= end address");
return;
}
debugger->cartDebug().addDirective(CartDebug::GFX, args[0], args[1]);
commandResult << "added GFX directive on range $" << hex << args[0]
<< " $" << hex << args[1];
debugger->myRom->invalidate();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "help"
void DebuggerParser::executeHelp()
{
// Find length of longest command
uInt16 clen = 0;
for(int i = 0; i < kNumCommands; ++i)
{
uInt16 len = commands[i].cmdString.length();
if(len > clen) clen = len;
}
for(int i = 0; i < kNumCommands; ++i)
commandResult << setw(clen) << right << commands[i].cmdString
<< " - " << commands[i].description << endl;
commandResult << debugger->builtinHelp();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "listbreaks" // "listbreaks"
void DebuggerParser::executeListbreaks() void DebuggerParser::executeListbreaks()
@ -1475,6 +1538,15 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
&DebuggerParser::executeCls &DebuggerParser::executeCls
}, },
{
"code",
"Mark 'CODE' range in disassembly",
true,
true,
{ kARG_WORD, kARG_MULTI_BYTE },
&DebuggerParser::executeCode
},
{ {
"colortest", "colortest",
"Show value xx as TIA color", "Show value xx as TIA color",
@ -1493,6 +1565,15 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
&DebuggerParser::executeD &DebuggerParser::executeD
}, },
{
"data",
"Mark 'DATA' range in disassembly",
true,
true,
{ kARG_WORD, kARG_MULTI_BYTE },
&DebuggerParser::executeData
},
{ {
"define", "define",
"Define label xx for address yy", "Define label xx for address yy",
@ -1574,6 +1655,15 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
&DebuggerParser::executeFunction &DebuggerParser::executeFunction
}, },
{
"gfx",
"Mark 'CFX' range in disassembly",
true,
true,
{ kARG_WORD, kARG_MULTI_BYTE },
&DebuggerParser::executeGfx
},
{ {
"help", "help",
"This cruft", "This cruft",

View File

@ -83,7 +83,7 @@ class DebuggerParser
private: private:
enum { enum {
kNumCommands = 57, kNumCommands = 60,
kMAX_ARG_TYPES = 10 kMAX_ARG_TYPES = 10
}; };
@ -145,8 +145,10 @@ class DebuggerParser
void executeCleartraps(); void executeCleartraps();
void executeClearwatches(); void executeClearwatches();
void executeCls(); void executeCls();
void executeCode();
void executeColortest(); void executeColortest();
void executeD(); void executeD();
void executeData();
void executeDefine(); void executeDefine();
void executeDelbreakif(); void executeDelbreakif();
void executeDelfunction(); void executeDelfunction();
@ -156,6 +158,7 @@ class DebuggerParser
void executeExec(); void executeExec();
void executeFrame(); void executeFrame();
void executeFunction(); void executeFunction();
void executeGfx();
void executeHelp(); void executeHelp();
void executeListbreaks(); void executeListbreaks();
void executeListfunctions(); void executeListfunctions();

View File

@ -23,17 +23,18 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list, DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
AddressList& addresses, uInt16 banksize, bool resolvedata) CartDebug::BankInfo& info, uInt16 banksize, bool resolvedata)
: myDbg(dbg), : myDbg(dbg),
myList(list) myList(list)
{ {
CartDebug::AddressList addresses = info.addressList;
if(addresses.size() == 0) if(addresses.size() == 0)
return; return;
while(!myAddressQueue.empty()) while(!myAddressQueue.empty())
myAddressQueue.pop(); myAddressQueue.pop();
AddressList::iterator it = addresses.begin(); CartDebug::AddressList::iterator it = addresses.begin();
uInt16 start = *it++; uInt16 start = *it++;
if(start & 0x1000) if(start & 0x1000)
@ -79,6 +80,10 @@ DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
myOffset = 0; myOffset = 0;
} }
info.start = myAppData.start;
info.end = myAppData.end;
info.offset = myOffset;
memset(labels, 0, 0x1000); memset(labels, 0, 0x1000);
myAddressQueue.push(start); myAddressQueue.push(start);
@ -129,6 +134,9 @@ DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
} }
} }
// Process any directives later, as they override automatic code determination
processDirectives(info.directiveList);
// Second pass // Second pass
disasm(myOffset, 2); disasm(myOffset, 2);
@ -174,10 +182,10 @@ void DiStella::disasm(uInt32 distart, int pass)
else else
myDisasmBuf << HEX4 << myPC+myOffset << "' '"; myDisasmBuf << HEX4 << myPC+myOffset << "' '";
myDisasmBuf << ".byte $" << HEX2 << (int)Debugger::debugger().peek(myPC+myOffset) << " ; "; myDisasmBuf << ".byte $" << HEX2 << (int)Debugger::debugger().peek(myPC+myOffset) << " ";
showgfx(Debugger::debugger().peek(myPC+myOffset)); showgfx(Debugger::debugger().peek(myPC+myOffset));
myDisasmBuf << " $" << HEX4 << myPC+myOffset; myDisasmBuf << " $" << HEX4 << myPC+myOffset << "'" << HEX2 << Debugger::debugger().peek(myPC+myOffset);
addEntry(); addEntry(CartDebug::GFX);
} }
myPC++; myPC++;
} }
@ -201,7 +209,7 @@ void DiStella::disasm(uInt32 distart, int pass)
bytes++; bytes++;
if (bytes == 17) if (bytes == 17)
{ {
addEntry(); addEntry(CartDebug::DATA);
myDisasmBuf << " ' '.byte $" << HEX2 << (int)Debugger::debugger().peek(myPC+myOffset); myDisasmBuf << " ' '.byte $" << HEX2 << (int)Debugger::debugger().peek(myPC+myOffset);
bytes = 1; bytes = 1;
} }
@ -213,9 +221,9 @@ void DiStella::disasm(uInt32 distart, int pass)
if (pass == 3) if (pass == 3)
{ {
addEntry(); addEntry(CartDebug::DATA);
myDisasmBuf << " ' ' "; myDisasmBuf << " ' ' ";
addEntry(); addEntry(CartDebug::NONE);
} }
} }
else else
@ -275,7 +283,7 @@ void DiStella::disasm(uInt32 distart, int pass)
/* Line information is already printed; append .byte since last instruction will /* Line information is already printed; append .byte since last instruction will
put recompilable object larger that original binary file */ put recompilable object larger that original binary file */
myDisasmBuf << ".byte $" << HEX2 << (int)op; myDisasmBuf << ".byte $" << HEX2 << (int)op;
addEntry(); addEntry(CartDebug::DATA);
if (myPC == myAppData.end) if (myPC == myAppData.end)
{ {
@ -286,7 +294,7 @@ void DiStella::disasm(uInt32 distart, int pass)
op = Debugger::debugger().peek(myPC+myOffset); myPC++; op = Debugger::debugger().peek(myPC+myOffset); myPC++;
myDisasmBuf << ".byte $" << HEX2 << (int)op; myDisasmBuf << ".byte $" << HEX2 << (int)op;
addEntry(); addEntry(CartDebug::DATA);
} }
} }
myPCEnd = myAppData.end + myOffset; myPCEnd = myAppData.end + myOffset;
@ -306,7 +314,7 @@ void DiStella::disasm(uInt32 distart, int pass)
/* Line information is already printed, but we can remove the /* Line information is already printed, but we can remove the
Instruction (i.e. BMI) by simply clearing the buffer to print */ Instruction (i.e. BMI) by simply clearing the buffer to print */
myDisasmBuf << ".byte $" << HEX2 << (int)op; myDisasmBuf << ".byte $" << HEX2 << (int)op;
addEntry(); addEntry(CartDebug::DATA);
nextline.str(""); nextline.str("");
nextlinebytes.str(""); nextlinebytes.str("");
} }
@ -615,11 +623,11 @@ void DiStella::disasm(uInt32 distart, int pass)
myDisasmBuf << nextline.str() << "'" myDisasmBuf << nextline.str() << "'"
<< ";" << dec << (int)ourLookup[op].cycles << "'" << ";" << dec << (int)ourLookup[op].cycles << "'"
<< nextlinebytes.str(); << nextlinebytes.str();
addEntry(); addEntry(CartDebug::CODE);
if (op == 0x40 || op == 0x60) if (op == 0x40 || op == 0x60)
{ {
myDisasmBuf << " ' ' "; myDisasmBuf << " ' ' ";
addEntry(); addEntry(CartDebug::NONE);
} }
nextline.str(""); nextline.str("");
@ -646,8 +654,8 @@ int DiStella::mark(uInt32 address, MarkType bit)
We sweep for hardware/system equates, which are valid addresses, We sweep for hardware/system equates, which are valid addresses,
outside the scope of the code/data range. For these, we mark its outside the scope of the code/data range. For these, we mark its
corresponding hardware/system array element, and return "2" or "3" corresponding hardware/system array element, and return "2" or "3"
(depending on which system/hardware element was accessed), or "5" (depending on which system/hardware element was accessed).
for zero-page RAM. If this was not the case... If this was not the case...
Next we check if it is a code "mirror". For the 2600, address ranges Next we check if it is a code "mirror". For the 2600, address ranges
are limited with 13 bits, so other addresses can exist outside of the are limited with 13 bits, so other addresses can exist outside of the
@ -708,28 +716,44 @@ int DiStella::mark(uInt32 address, MarkType bit)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DiStella::showgfx(uInt8 c) void DiStella::showgfx(uInt8 c)
{ {
#if 0
int i;
myDisasmBuf << "|"; myDisasmBuf << "|";
for(i = 0;i < 8; i++) for(int i = 0; i < 8; ++i, c <<= 1)
{ myDisasmBuf << ((c > 127) ? "X" : " ");
if (c > 127)
myDisasmBuf << "X";
else
myDisasmBuf << " ";
c = c << 1;
}
myDisasmBuf << "|"; myDisasmBuf << "|";
#endif
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DiStella::addEntry() bool DiStella::check_range(uInt32 beg, uInt32 end)
{
if(beg > end)
{
cerr << "Beginning of range greater than end: start = " << hex << beg
<< ", end = " << hex << endl;
return false;
}
else if(beg > myAppData.end + myOffset)
{
cerr << "Beginning of range out of range: start = " << hex << beg
<< ", range = " << hex << (myAppData.end + myOffset) << endl;
return false;
}
else if(beg < myOffset)
{
cerr << "Beginning of range out of range: start = " << hex << beg
<< ", offset = " << hex << myOffset << endl;
return false;
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DiStella::addEntry(CartDebug::DisasmType type)
{ {
CartDebug::DisassemblyTag tag; CartDebug::DisassemblyTag tag;
// Type
tag.type = type;
// Address // Address
myDisasmBuf.seekg(0, ios::beg); myDisasmBuf.seekg(0, ios::beg);
if(myDisasmBuf.peek() == ' ') if(myDisasmBuf.peek() == ' ')
@ -766,6 +790,25 @@ void DiStella::addEntry()
// Up to this point the field sizes are fixed, until we get to // Up to this point the field sizes are fixed, until we get to
// variable length labels, cycle counts, etc // variable length labels, cycle counts, etc
myDisasmBuf.seekg(11, ios::beg); myDisasmBuf.seekg(11, ios::beg);
switch(tag.type)
{
case CartDebug::CODE:
getline(myDisasmBuf, tag.disasm, '\'');
getline(myDisasmBuf, tag.ccount, '\'');
getline(myDisasmBuf, tag.bytes);
break;
case CartDebug::DATA:
getline(myDisasmBuf, tag.disasm);
break;
case CartDebug::GFX:
getline(myDisasmBuf, tag.disasm, '\'');
getline(myDisasmBuf, tag.bytes);
break;
case CartDebug::NONE:
tag.disasm = " ";
break;
}
/*
switch(myDisasmBuf.peek()) switch(myDisasmBuf.peek())
{ {
case ' ': case ' ':
@ -780,11 +823,51 @@ void DiStella::addEntry()
getline(myDisasmBuf, tag.bytes); getline(myDisasmBuf, tag.bytes);
break; break;
} }
*/
myList.push_back(tag); myList.push_back(tag);
DONE_WITH_ADD: DONE_WITH_ADD:
myDisasmBuf.clear(); myDisasmBuf.clear();
myDisasmBuf.str(""); myDisasmBuf.str("");
#if 0
// debugging output
cerr << (tag.type == CartDebug::CODE ? "CODE" : (tag.type == CartDebug::DATA ? "DATA" :
(tag.type == CartDebug::GFX ? "GFX " : "NONE"))) << "|"
<< hex << setw(4) << setfill('0') << tag.address << "|"
<< tag.label << "|" << tag.disasm << "|" << tag.ccount << "|" << "|"
<< tag.bytes << endl;
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DiStella::processDirectives(const CartDebug::DirectiveList& directives)
{
for(CartDebug::DirectiveList::const_iterator i = directives.begin();
i != directives.end(); ++i)
{
const CartDebug::DirectiveTag tag = *i;
if(check_range(tag.start, tag.end))
{
MarkType type;
switch(tag.type)
{
case CartDebug::DATA :
type = DATA;
break;
case CartDebug::GFX :
type = GFX;
break;
case CartDebug::CODE :
type = REACHABLE;
break;
default:
continue; // skip this tag
}
for(uInt32 k = tag.start; k <= tag.end; ++k)
mark(k, type);
}
}
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -53,7 +53,7 @@ class DiStella
@param resolvedata If enabled, try to determine code vs. data sections @param resolvedata If enabled, try to determine code vs. data sections
*/ */
DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list, DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
AddressList& addresses, uInt16 banksize = 4, bool resolvedata = true); CartDebug::BankInfo& info, uInt16 banksize = 4, bool resolvedata = true);
~DiStella(); ~DiStella();
@ -74,12 +74,17 @@ class DiStella
// Indicate that a new line of disassembly has been completed // Indicate that a new line of disassembly has been completed
// In the original Distella code, this indicated a new line to be printed // In the original Distella code, this indicated a new line to be printed
// Here, we add a new entry to the DisassemblyList // Here, we add a new entry to the DisassemblyList
void addEntry(); void addEntry(CartDebug::DisasmType type);
// Process directives given in the list
// Directives are basically the contents of a distella configuration file
void processDirectives(const CartDebug::DirectiveList& directives);
// These functions are part of the original Distella code // These functions are part of the original Distella code
void disasm(uInt32 distart, int pass); void disasm(uInt32 distart, int pass);
int mark(uInt32 address, MarkType bit); int mark(uInt32 address, MarkType bit);
void showgfx(uInt8 c); void showgfx(uInt8 c);
bool check_range(uInt32 start, uInt32 end);
inline int check_bit(uInt8 bitflags, int i) const { return (bitflags & i); } inline int check_bit(uInt8 bitflags, int i) const { return (bitflags & i); }
private: private:

View File

@ -64,6 +64,7 @@ RomListWidget::RomListWidget(GuiObject* boss, const GUI::Font& font,
l.push_back("Save ROM", "saverom"); l.push_back("Save ROM", "saverom");
l.push_back("Set PC", "setpc"); l.push_back("Set PC", "setpc");
l.push_back("RunTo PC", "runtopc"); l.push_back("RunTo PC", "runtopc");
l.push_back("Re-disassemble", "disasm");
myMenu = new ContextMenu(this, font, l); myMenu = new ContextMenu(this, font, l);
// Take advantage of a wide debugger window when possible // Take advantage of a wide debugger window when possible
@ -121,6 +122,8 @@ void RomListWidget::setList(const CartDebug::Disassembly& disasm,
myCheckList[i]->clearFlags(WIDGET_ENABLED); myCheckList[i]->clearFlags(WIDGET_ENABLED);
recalc(); recalc();
setDirty(); draw();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -425,7 +428,8 @@ void RomListWidget::drawWidget(bool hilite)
// Draw the list items // Draw the list items
int ccountw = _fontWidth << 1, int ccountw = _fontWidth << 1,
large_disasmw = _w - l.x() - _labelWidth, large_disasmw = _w - l.x() - _labelWidth,
small_disasmw = large_disasmw - r.width() - (ccountw << 1), medium_disasmw = large_disasmw - r.width(),
small_disasmw = medium_disasmw - (ccountw << 1),
actualwidth = myDisasm->fieldwidth * _fontWidth; actualwidth = myDisasm->fieldwidth * _fontWidth;
if(actualwidth < small_disasmw) if(actualwidth < small_disasmw)
small_disasmw = actualwidth; small_disasmw = actualwidth;
@ -454,16 +458,24 @@ void RomListWidget::drawWidget(bool hilite)
// Draw labels // Draw labels
s.drawString(_font, dlist[pos].label, xpos, ypos, _labelWidth, kTextColor); s.drawString(_font, dlist[pos].label, xpos, ypos, _labelWidth, kTextColor);
// Sometimes there aren't any bytes to display, in which case the disassembly // Bytes are only editable if they represent code or graphics
// should get all remaining space // Otherwise, the disassembly should get all remaining space
if(dlist[pos].bytes != "") if(dlist[pos].type & (CartDebug::CODE | CartDebug::GFX))
{ {
// Draw disassembly and cycle count if(dlist[pos].type == CartDebug::CODE)
// TODO - cycle count should be aligned as close as possible to the disassembly {
s.drawString(_font, dlist[pos].disasm, xpos + _labelWidth, ypos, // Draw disassembly and cycle count
small_disasmw, kTextColor); s.drawString(_font, dlist[pos].disasm, xpos + _labelWidth, ypos,
s.drawString(_font, dlist[pos].ccount, xpos + _labelWidth + small_disasmw, ypos, small_disasmw, kTextColor);
ccountw, kTextColor); s.drawString(_font, dlist[pos].ccount, xpos + _labelWidth + small_disasmw, ypos,
ccountw, kTextColor);
}
else
{
// Draw disassembly only
s.drawString(_font, dlist[pos].disasm, xpos + _labelWidth, ypos,
medium_disasmw, kTextColor);
}
// Draw separator // Draw separator
s.vLine(_x + r.x() - 7, ypos, ypos + _fontHeight - 1, kColor); s.vLine(_x + r.x() - 7, ypos, ypos + _fontHeight - 1, kColor);

View File

@ -172,6 +172,8 @@ void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
setPC(myRomList->getSelected()); setPC(myRomList->getSelected());
else if(rmb == "runtopc") else if(rmb == "runtopc")
runtoPC(myRomList->getSelected()); runtoPC(myRomList->getSelected());
else if(rmb == "disasm")
invalidate();
break; break;
} }