mirror of https://github.com/stella-emu/stella.git
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:
parent
12c9edaed0
commit
e0dd8b1451
|
@ -37,15 +37,15 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const RamAreaList& areas)
|
|||
for(RamAreaList::const_iterator i = areas.begin(); i != areas.end(); ++i)
|
||||
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)
|
||||
{
|
||||
AddressList l;
|
||||
myEntryAddresses.push_back(l);
|
||||
BankInfo info;
|
||||
myBankInfo.push_back(info);
|
||||
}
|
||||
|
||||
// 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));
|
||||
|
||||
// Add system equates
|
||||
|
@ -64,9 +64,12 @@ CartDebug::~CartDebug()
|
|||
myUserAddresses.clear();
|
||||
mySystemAddresses.clear();
|
||||
|
||||
for(uInt32 i = 0; i < myEntryAddresses.size(); ++i)
|
||||
myEntryAddresses[i].clear();
|
||||
myEntryAddresses.clear();
|
||||
for(uInt32 i = 0; i < myBankInfo.size(); ++i)
|
||||
{
|
||||
myBankInfo[i].addressList.clear();
|
||||
myBankInfo[i].directiveList.clear();
|
||||
}
|
||||
myBankInfo.clear();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -206,14 +209,15 @@ bool CartDebug::disassemble(const string& resolvedata, bool force)
|
|||
if(changed)
|
||||
{
|
||||
// Are we disassembling from ROM or ZP RAM?
|
||||
AddressList& addresses = (PC & 0x1000) ? myEntryAddresses[getBank()] :
|
||||
myEntryAddresses[myEntryAddresses.size()-1];
|
||||
BankInfo& info = (PC & 0x1000) ? myBankInfo[getBank()] :
|
||||
myBankInfo[myBankInfo.size()-1];
|
||||
|
||||
// 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
|
||||
// $bxxx, it must be changed
|
||||
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;
|
||||
|
||||
// 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
|
||||
if(resolvedata == "never")
|
||||
fillDisassemblyList(addresses, false, PC);
|
||||
fillDisassemblyList(info, false, PC);
|
||||
else if(resolvedata == "always")
|
||||
fillDisassemblyList(addresses, true, PC);
|
||||
fillDisassemblyList(info, true, PC);
|
||||
else // 'auto'
|
||||
{
|
||||
// First try with resolvedata on, then turn off if PC isn't found
|
||||
if(!fillDisassemblyList(addresses, true, PC))
|
||||
fillDisassemblyList(addresses, false, PC);
|
||||
if(!fillDisassemblyList(info, true, PC))
|
||||
fillDisassemblyList(info, false, PC);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -254,8 +258,7 @@ bool CartDebug::disassemble(const string& resolvedata, bool force)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartDebug::fillDisassemblyList(AddressList& addresses,
|
||||
bool resolvedata, uInt16 search)
|
||||
bool CartDebug::fillDisassemblyList(BankInfo& info, bool resolvedata, uInt16 search)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
|
@ -263,7 +266,7 @@ bool CartDebug::fillDisassemblyList(AddressList& addresses,
|
|||
myDisassembly.fieldwidth = 10 + myLabelLength;
|
||||
uInt16 banksize =
|
||||
!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
|
||||
// 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];
|
||||
|
||||
// Only non-zero addresses are valid
|
||||
if(tag.address != 0)
|
||||
// Only addresses marked as 'CODE' can possibly be in the program counter
|
||||
if(tag.type == CODE)
|
||||
{
|
||||
// Create a mapping from addresses to line numbers
|
||||
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
|
||||
{
|
||||
Disassembly disasm;
|
||||
AddressList addresses;
|
||||
addresses.push_back(start);
|
||||
BankInfo info;
|
||||
info.addressList.push_back(start);
|
||||
uInt16 banksize =
|
||||
!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
|
||||
start &= 0xFFF;
|
||||
|
@ -335,6 +338,21 @@ string CartDebug::disassemble(uInt16 start, uInt16 lines) const
|
|||
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()
|
||||
{
|
||||
|
|
|
@ -32,9 +32,6 @@ class System;
|
|||
#include "StringList.hxx"
|
||||
#include "DebuggerSystem.hxx"
|
||||
|
||||
// Array of addresses
|
||||
typedef list<uInt16> AddressList;
|
||||
|
||||
// pointer types for CartDebug instance methods
|
||||
typedef int (CartDebug::*CARTDEBUG_INT_METHOD)();
|
||||
|
||||
|
@ -55,7 +52,14 @@ class CartDebug : public DebuggerSystem
|
|||
friend class DiStella;
|
||||
|
||||
public:
|
||||
enum DisasmType {
|
||||
GFX = 1 << 0,
|
||||
DATA = 1 << 1,
|
||||
CODE = 1 << 2,
|
||||
NONE = 1 << 3
|
||||
};
|
||||
struct DisassemblyTag {
|
||||
DisasmType type;
|
||||
uInt16 address;
|
||||
string label;
|
||||
string disasm;
|
||||
|
@ -146,6 +150,20 @@ class CartDebug : public DebuggerSystem
|
|||
*/
|
||||
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
|
||||
// for the desired information.
|
||||
/**
|
||||
|
@ -212,10 +230,25 @@ class CartDebug : public DebuggerSystem
|
|||
};
|
||||
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
|
||||
// Return whether the search address was actually in the list
|
||||
bool fillDisassemblyList(AddressList& addresses,
|
||||
bool resolvedata, uInt16 search);
|
||||
bool fillDisassemblyList(BankInfo& bankinfo, bool resolvedata, uInt16 search);
|
||||
|
||||
// Extract labels and values from the given character stream
|
||||
string extractLabel(const char* c) const;
|
||||
|
@ -225,12 +258,8 @@ class CartDebug : public DebuggerSystem
|
|||
CartState myState;
|
||||
CartState myOldState;
|
||||
|
||||
// A list of 'entry' addresses for each bank in a cart
|
||||
// An entry address is the one at which time the debugger 'enters' the
|
||||
// disassembler
|
||||
// The startup bank will normally be 0xfffc, while the others are
|
||||
// determined when the debugger is first opened
|
||||
Common::Array<AddressList> myEntryAddresses;
|
||||
// A complete record of relevant diassembly information for each bank
|
||||
Common::Array<BankInfo> myBankInfo;
|
||||
|
||||
// Used for the disassembly display, and mapping from addresses
|
||||
// to corresponding lines of text in that display
|
||||
|
|
|
@ -790,6 +790,27 @@ void DebuggerParser::executeCls()
|
|||
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"
|
||||
void DebuggerParser::executeColortest()
|
||||
|
@ -809,6 +830,27 @@ void DebuggerParser::executeD()
|
|||
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"
|
||||
void DebuggerParser::executeDefine()
|
||||
|
@ -895,25 +937,6 @@ void DebuggerParser::executeExec()
|
|||
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"
|
||||
void DebuggerParser::executeFrame()
|
||||
|
@ -945,6 +968,46 @@ void DebuggerParser::executeFunction()
|
|||
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"
|
||||
void DebuggerParser::executeListbreaks()
|
||||
|
@ -1475,6 +1538,15 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
|||
&DebuggerParser::executeCls
|
||||
},
|
||||
|
||||
{
|
||||
"code",
|
||||
"Mark 'CODE' range in disassembly",
|
||||
true,
|
||||
true,
|
||||
{ kARG_WORD, kARG_MULTI_BYTE },
|
||||
&DebuggerParser::executeCode
|
||||
},
|
||||
|
||||
{
|
||||
"colortest",
|
||||
"Show value xx as TIA color",
|
||||
|
@ -1493,6 +1565,15 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
|||
&DebuggerParser::executeD
|
||||
},
|
||||
|
||||
{
|
||||
"data",
|
||||
"Mark 'DATA' range in disassembly",
|
||||
true,
|
||||
true,
|
||||
{ kARG_WORD, kARG_MULTI_BYTE },
|
||||
&DebuggerParser::executeData
|
||||
},
|
||||
|
||||
{
|
||||
"define",
|
||||
"Define label xx for address yy",
|
||||
|
@ -1574,6 +1655,15 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
|||
&DebuggerParser::executeFunction
|
||||
},
|
||||
|
||||
{
|
||||
"gfx",
|
||||
"Mark 'CFX' range in disassembly",
|
||||
true,
|
||||
true,
|
||||
{ kARG_WORD, kARG_MULTI_BYTE },
|
||||
&DebuggerParser::executeGfx
|
||||
},
|
||||
|
||||
{
|
||||
"help",
|
||||
"This cruft",
|
||||
|
|
|
@ -83,7 +83,7 @@ class DebuggerParser
|
|||
|
||||
private:
|
||||
enum {
|
||||
kNumCommands = 57,
|
||||
kNumCommands = 60,
|
||||
kMAX_ARG_TYPES = 10
|
||||
};
|
||||
|
||||
|
@ -145,8 +145,10 @@ class DebuggerParser
|
|||
void executeCleartraps();
|
||||
void executeClearwatches();
|
||||
void executeCls();
|
||||
void executeCode();
|
||||
void executeColortest();
|
||||
void executeD();
|
||||
void executeData();
|
||||
void executeDefine();
|
||||
void executeDelbreakif();
|
||||
void executeDelfunction();
|
||||
|
@ -156,6 +158,7 @@ class DebuggerParser
|
|||
void executeExec();
|
||||
void executeFrame();
|
||||
void executeFunction();
|
||||
void executeGfx();
|
||||
void executeHelp();
|
||||
void executeListbreaks();
|
||||
void executeListfunctions();
|
||||
|
|
|
@ -23,17 +23,18 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
|
||||
AddressList& addresses, uInt16 banksize, bool resolvedata)
|
||||
CartDebug::BankInfo& info, uInt16 banksize, bool resolvedata)
|
||||
: myDbg(dbg),
|
||||
myList(list)
|
||||
{
|
||||
CartDebug::AddressList addresses = info.addressList;
|
||||
if(addresses.size() == 0)
|
||||
return;
|
||||
|
||||
while(!myAddressQueue.empty())
|
||||
myAddressQueue.pop();
|
||||
|
||||
AddressList::iterator it = addresses.begin();
|
||||
CartDebug::AddressList::iterator it = addresses.begin();
|
||||
uInt16 start = *it++;
|
||||
|
||||
if(start & 0x1000)
|
||||
|
@ -79,6 +80,10 @@ DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
|
|||
myOffset = 0;
|
||||
}
|
||||
|
||||
info.start = myAppData.start;
|
||||
info.end = myAppData.end;
|
||||
info.offset = myOffset;
|
||||
|
||||
memset(labels, 0, 0x1000);
|
||||
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
|
||||
disasm(myOffset, 2);
|
||||
|
||||
|
@ -174,10 +182,10 @@ void DiStella::disasm(uInt32 distart, int pass)
|
|||
else
|
||||
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));
|
||||
myDisasmBuf << " $" << HEX4 << myPC+myOffset;
|
||||
addEntry();
|
||||
myDisasmBuf << " $" << HEX4 << myPC+myOffset << "'" << HEX2 << Debugger::debugger().peek(myPC+myOffset);
|
||||
addEntry(CartDebug::GFX);
|
||||
}
|
||||
myPC++;
|
||||
}
|
||||
|
@ -201,7 +209,7 @@ void DiStella::disasm(uInt32 distart, int pass)
|
|||
bytes++;
|
||||
if (bytes == 17)
|
||||
{
|
||||
addEntry();
|
||||
addEntry(CartDebug::DATA);
|
||||
myDisasmBuf << " ' '.byte $" << HEX2 << (int)Debugger::debugger().peek(myPC+myOffset);
|
||||
bytes = 1;
|
||||
}
|
||||
|
@ -213,9 +221,9 @@ void DiStella::disasm(uInt32 distart, int pass)
|
|||
|
||||
if (pass == 3)
|
||||
{
|
||||
addEntry();
|
||||
addEntry(CartDebug::DATA);
|
||||
myDisasmBuf << " ' ' ";
|
||||
addEntry();
|
||||
addEntry(CartDebug::NONE);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -275,7 +283,7 @@ void DiStella::disasm(uInt32 distart, int pass)
|
|||
/* Line information is already printed; append .byte since last instruction will
|
||||
put recompilable object larger that original binary file */
|
||||
myDisasmBuf << ".byte $" << HEX2 << (int)op;
|
||||
addEntry();
|
||||
addEntry(CartDebug::DATA);
|
||||
|
||||
if (myPC == myAppData.end)
|
||||
{
|
||||
|
@ -286,7 +294,7 @@ void DiStella::disasm(uInt32 distart, int pass)
|
|||
|
||||
op = Debugger::debugger().peek(myPC+myOffset); myPC++;
|
||||
myDisasmBuf << ".byte $" << HEX2 << (int)op;
|
||||
addEntry();
|
||||
addEntry(CartDebug::DATA);
|
||||
}
|
||||
}
|
||||
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
|
||||
Instruction (i.e. BMI) by simply clearing the buffer to print */
|
||||
myDisasmBuf << ".byte $" << HEX2 << (int)op;
|
||||
addEntry();
|
||||
addEntry(CartDebug::DATA);
|
||||
nextline.str("");
|
||||
nextlinebytes.str("");
|
||||
}
|
||||
|
@ -615,11 +623,11 @@ void DiStella::disasm(uInt32 distart, int pass)
|
|||
myDisasmBuf << nextline.str() << "'"
|
||||
<< ";" << dec << (int)ourLookup[op].cycles << "'"
|
||||
<< nextlinebytes.str();
|
||||
addEntry();
|
||||
addEntry(CartDebug::CODE);
|
||||
if (op == 0x40 || op == 0x60)
|
||||
{
|
||||
myDisasmBuf << " ' ' ";
|
||||
addEntry();
|
||||
addEntry(CartDebug::NONE);
|
||||
}
|
||||
|
||||
nextline.str("");
|
||||
|
@ -646,8 +654,8 @@ int DiStella::mark(uInt32 address, MarkType bit)
|
|||
We sweep for hardware/system equates, which are valid addresses,
|
||||
outside the scope of the code/data range. For these, we mark its
|
||||
corresponding hardware/system array element, and return "2" or "3"
|
||||
(depending on which system/hardware element was accessed), or "5"
|
||||
for zero-page RAM. If this was not the case...
|
||||
(depending on which system/hardware element was accessed).
|
||||
If this was not the case...
|
||||
|
||||
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
|
||||
|
@ -708,28 +716,44 @@ int DiStella::mark(uInt32 address, MarkType bit)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DiStella::showgfx(uInt8 c)
|
||||
{
|
||||
#if 0
|
||||
int i;
|
||||
|
||||
myDisasmBuf << "|";
|
||||
for(i = 0;i < 8; i++)
|
||||
{
|
||||
if (c > 127)
|
||||
myDisasmBuf << "X";
|
||||
else
|
||||
myDisasmBuf << " ";
|
||||
|
||||
c = c << 1;
|
||||
}
|
||||
for(int i = 0; i < 8; ++i, c <<= 1)
|
||||
myDisasmBuf << ((c > 127) ? "X" : " ");
|
||||
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;
|
||||
|
||||
// Type
|
||||
tag.type = type;
|
||||
|
||||
// Address
|
||||
myDisasmBuf.seekg(0, ios::beg);
|
||||
if(myDisasmBuf.peek() == ' ')
|
||||
|
@ -766,6 +790,25 @@ void DiStella::addEntry()
|
|||
// Up to this point the field sizes are fixed, until we get to
|
||||
// variable length labels, cycle counts, etc
|
||||
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())
|
||||
{
|
||||
case ' ':
|
||||
|
@ -780,11 +823,51 @@ void DiStella::addEntry()
|
|||
getline(myDisasmBuf, tag.bytes);
|
||||
break;
|
||||
}
|
||||
*/
|
||||
myList.push_back(tag);
|
||||
|
||||
DONE_WITH_ADD:
|
||||
myDisasmBuf.clear();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -53,7 +53,7 @@ class DiStella
|
|||
@param resolvedata If enabled, try to determine code vs. data sections
|
||||
*/
|
||||
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();
|
||||
|
||||
|
@ -74,12 +74,17 @@ class DiStella
|
|||
// Indicate that a new line of disassembly has been completed
|
||||
// In the original Distella code, this indicated a new line to be printed
|
||||
// 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
|
||||
void disasm(uInt32 distart, int pass);
|
||||
int mark(uInt32 address, MarkType bit);
|
||||
void showgfx(uInt8 c);
|
||||
bool check_range(uInt32 start, uInt32 end);
|
||||
inline int check_bit(uInt8 bitflags, int i) const { return (bitflags & i); }
|
||||
|
||||
private:
|
||||
|
|
|
@ -64,6 +64,7 @@ RomListWidget::RomListWidget(GuiObject* boss, const GUI::Font& font,
|
|||
l.push_back("Save ROM", "saverom");
|
||||
l.push_back("Set PC", "setpc");
|
||||
l.push_back("RunTo PC", "runtopc");
|
||||
l.push_back("Re-disassemble", "disasm");
|
||||
myMenu = new ContextMenu(this, font, l);
|
||||
|
||||
// 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);
|
||||
|
||||
recalc();
|
||||
|
||||
setDirty(); draw();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -425,7 +428,8 @@ void RomListWidget::drawWidget(bool hilite)
|
|||
// Draw the list items
|
||||
int ccountw = _fontWidth << 1,
|
||||
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;
|
||||
if(actualwidth < small_disasmw)
|
||||
small_disasmw = actualwidth;
|
||||
|
@ -454,16 +458,24 @@ void RomListWidget::drawWidget(bool hilite)
|
|||
// Draw labels
|
||||
s.drawString(_font, dlist[pos].label, xpos, ypos, _labelWidth, kTextColor);
|
||||
|
||||
// Sometimes there aren't any bytes to display, in which case the disassembly
|
||||
// should get all remaining space
|
||||
if(dlist[pos].bytes != "")
|
||||
// Bytes are only editable if they represent code or graphics
|
||||
// Otherwise, the disassembly should get all remaining space
|
||||
if(dlist[pos].type & (CartDebug::CODE | CartDebug::GFX))
|
||||
{
|
||||
// Draw disassembly and cycle count
|
||||
// TODO - cycle count should be aligned as close as possible to the disassembly
|
||||
s.drawString(_font, dlist[pos].disasm, xpos + _labelWidth, ypos,
|
||||
small_disasmw, kTextColor);
|
||||
s.drawString(_font, dlist[pos].ccount, xpos + _labelWidth + small_disasmw, ypos,
|
||||
ccountw, kTextColor);
|
||||
if(dlist[pos].type == CartDebug::CODE)
|
||||
{
|
||||
// Draw disassembly and cycle count
|
||||
s.drawString(_font, dlist[pos].disasm, xpos + _labelWidth, ypos,
|
||||
small_disasmw, 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
|
||||
s.vLine(_x + r.x() - 7, ypos, ypos + _fontHeight - 1, kColor);
|
||||
|
|
|
@ -172,6 +172,8 @@ void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
|||
setPC(myRomList->getSelected());
|
||||
else if(rmb == "runtopc")
|
||||
runtoPC(myRomList->getSelected());
|
||||
else if(rmb == "disasm")
|
||||
invalidate();
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue