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)
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()
{

View File

@ -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

View File

@ -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",

View File

@ -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();

View File

@ -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);
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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:

View File

@ -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);

View File

@ -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;
}