Some debugger/disassembly work:

- Removed 'SKIP' directive, since it wasn't implemented anyway, and
    I see no way to implement it

  - Add 'aflag' setting to diassembly output, matching usage in Distella.
    This is needed for diassembly output, otherwise DASM barfs on the code.

  - Fixed several long-standing bugs in Distella disassembly wrt ROW
    directives and labeling.  Previously, the output you see in the debugger
    wasn't completely correct, since it wasn't compiling properly in DASM.

  - Illegal opcodes are now shown as .byte directives; this allows the code
    to compile in DASM.

  - Print 16 bytes per line in .byte directive in external disassembly,
    same as Distella.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2665 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2013-03-10 22:12:37 +00:00
parent 3c801a7dd4
commit b97d5120b9
8 changed files with 83 additions and 101 deletions

View File

@ -84,8 +84,10 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
myOSystem.settings().getInt("dis.gfxformat") == 16 ? kBASE_16 : kBASE_2;
DiStella::settings.show_addresses =
myOSystem.settings().getBool("dis.showaddr");
DiStella::settings.rflag = myOSystem.settings().getBool("dis.relocate");
DiStella::settings.aflag = false; // Not currently configurable
DiStella::settings.fflag = true; // Not currently configurable
DiStella::settings.rflag = myOSystem.settings().getBool("dis.relocate");
DiStella::settings.bwidth = 9; // TODO - configure based on window size
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -329,10 +331,10 @@ string CartDebug::disassemble(uInt16 start, uInt16 lines) const
{
Disassembly disasm;
BankInfo info;
uInt8 labels[0x1000], directives[0x1000];
info.addressList.push_back(start);
DiStella distella(*this, disasm.list, info, DiStella::settings,
labels, directives, (ReservedEquates&)myReserved, false);
(uInt8*)myDisLabels, (uInt8*)myDisDirectives,
(ReservedEquates&)myReserved, false);
// Fill the string with disassembled data
start &= 0xFFF;
@ -761,12 +763,6 @@ string CartDebug::loadConfigFile(string file)
// TODO - figure out what to do with this
buf >> hex >> start;
}
else if(BSPF_startsWithIgnoreCase(directive, "SKIP"))
{
// For now, treat this as CODE
buf >> hex >> start >> hex >> end;
addDirective(CartDebug::CODE, start, end, currentbank);
}
else if(BSPF_startsWithIgnoreCase(directive, "CODE"))
{
buf >> hex >> start >> hex >> end;
@ -864,7 +860,7 @@ string CartDebug::saveDisassembly(string file)
buf << "; Disassembly of " << file << "\n"
<< "; Disassembled " << ctime(&currtime)
<< "; Using Stella " << STELLA_VERSION << "\n;\n"
<< "; Command Line arguments: TODO - add args\n;\n"
<< "; Settings used: 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 '#' (stored in player, missile, ball)\n"
@ -874,12 +870,12 @@ string CartDebug::saveDisassembly(string file)
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
if(myReserved.TIARead[addr] && ourTIAMnemonicR[addr][0] != '$')
buf << ALIGN(7) << ourTIAMnemonicR[addr] << " = $"
<< HEX2 << addr << " ; (R)\n";
<< HEX2 << right << addr << " ; (R)\n";
for(uInt16 addr = 0x00; addr <= 0x3F; ++addr)
if(myReserved.TIAWrite[addr] && ourTIAMnemonicW[addr][0] != '$')
buf << ALIGN(7) << ourTIAMnemonicW[addr] << " = $"
<< HEX2 << addr << " ; (W)\n";
<< HEX2 << right << addr << " ; (W)\n";
for(uInt16 addr = 0x00; addr <= 0x17; ++addr)
if(myReserved.IOReadWrite[addr] && ourIOMnemonic[addr][0] != '$')
@ -893,8 +889,10 @@ string CartDebug::saveDisassembly(string file)
DiStella::Settings settings;
settings.gfx_format = DiStella::settings.gfx_format;
settings.show_addresses = false;
settings.aflag = false; // Otherwise DASM gets confused
settings.fflag = DiStella::settings.fflag;
settings.rflag = DiStella::settings.rflag;
settings.bwidth = 17; // default from Distella
Disassembly disasm;
disasm.list.reserve(2048);
@ -1168,7 +1166,6 @@ void CartDebug::disasmTypeAsString(ostream& buf, DisasmType type) const
{
switch(type)
{
case CartDebug::SKIP: buf << "SKIP"; break;
case CartDebug::CODE: buf << "CODE"; break;
case CartDebug::GFX: buf << "GFX"; break;
case CartDebug::PGFX: buf << "PGFX"; break;
@ -1185,8 +1182,6 @@ void CartDebug::disasmTypeAsString(ostream& buf, uInt8 flags) const
{
if(flags)
{
if(flags & CartDebug::SKIP)
buf << "SKIP ";
if(flags & CartDebug::CODE)
buf << "CODE ";
if(flags & CartDebug::GFX)

View File

@ -55,18 +55,17 @@ class CartDebug : public DebuggerSystem
public:
enum DisasmType {
NONE = 0,
VALID_ENTRY = 1 << 0, /* addresses that can have a label placed in front of it.
REFERENCED = 1 << 0, /* code somewhere in the program references it,
i.e. LDA $F372 referenced $F372 */
VALID_ENTRY = 1 << 1, /* addresses that can have a label placed in front of it.
A good counterexample would be "FF00: LDA $FE00"; $FF01
would be in the middle of a multi-byte instruction, and
therefore cannot be labelled. */
REFERENCED = 1 << 1, /* code somewhere in the program references it,
i.e. LDA $F372 referenced $F372 */
// The following correspond to specific types that can be set within the
// debugger, or specified in a Distella cfg file, and are listed in order
// of decreasing hierarchy
//
SKIP = 1 << 7, // TODO - document this
CODE = 1 << 6, // disassemble-able code segments
GFX = 1 << 5, // addresses loaded into GRPx registers
PGFX = 1 << 4, // addresses loaded into PFx registers

View File

@ -1474,31 +1474,6 @@ void DebuggerParser::executeScanline()
if(count != 1) commandResult << "s";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "skip"
void DebuggerParser::executeSkip()
{
commandResult << red("Not yet implemented");
/*
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;
}
bool result = debugger->cartDebug().addDirective(
CartDebug::SKIP, args[0], args[1]);
commandResult << (result ? "added" : "removed") << " SKIP directive on range $"
<< hex << args[0] << " $" << hex << args[1];
debugger->myRom->invalidate();
*/
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "step"
void DebuggerParser::executeStep()
@ -2156,15 +2131,6 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
&DebuggerParser::executeScanline
},
{
"skip",
"Mark 'SKIP' range in disassembly",
true,
false,
{ kARG_WORD, kARG_MULTI_BYTE },
&DebuggerParser::executeSkip
},
{
"step",
"Single step CPU [with count xx]",

View File

@ -90,7 +90,7 @@ class DebuggerParser
private:
enum {
kNumCommands = 71,
kNumCommands = 70,
kMAX_ARG_TYPES = 10
};
@ -198,7 +198,6 @@ class DebuggerParser
void executeSaveses();
void executeSavestate();
void executeScanline();
void executeSkip();
void executeStep();
void executeTia();
void executeTrace();

View File

@ -173,11 +173,10 @@ DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
}
}
}
for (int k = 0; k <= myAppData.end; k++)
{
if (!check_bit(k, CartDebug::SKIP|CartDebug::CODE|CartDebug::GFX|
CartDebug::PGFX|CartDebug::DATA))
if (!check_bit(k, CartDebug::CODE | CartDebug::GFX |
CartDebug::PGFX | CartDebug::DATA))
mark(k+myOffset, CartDebug::ROW);
}
}
@ -215,9 +214,9 @@ void DiStella::disasm(uInt32 distart, int pass)
{
if(check_bit(myPC, CartDebug::GFX|CartDebug::PGFX) && !check_bit(myPC, CartDebug::CODE))
{
if (pass == 2)
mark(myPC+myOffset, CartDebug::VALID_ENTRY);
else if (pass == 3)
mark(myPC+myOffset, CartDebug::VALID_ENTRY);
if (pass == 3)
{
if (check_bit(myPC, CartDebug::REFERENCED))
myDisasmBuf << HEX4 << myPC+myOffset << "'L" << HEX4 << myPC+myOffset << "'";
@ -262,40 +261,65 @@ void DiStella::disasm(uInt32 distart, int pass)
else if (check_bit(myPC, CartDebug::ROW) &&
!check_bit(myPC, CartDebug::CODE|CartDebug::DATA|CartDebug::GFX|CartDebug::PGFX))
{
mark(myPC+myOffset, CartDebug::VALID_ENTRY);
if (pass == 2)
mark(myPC+myOffset, CartDebug::VALID_ENTRY);
if (pass == 3)
{
bytes = 1;
myDisasmBuf << HEX4 << myPC+myOffset << "'L" << HEX4 << myPC+myOffset << "'.byte "
<< "$" << HEX2 << (int)Debugger::debugger().peek(myPC+myOffset);
}
myPC++;
while (check_bit(myPC, CartDebug::ROW) &&
!check_bit(myPC, CartDebug::CODE|CartDebug::DATA|CartDebug::GFX|CartDebug::PGFX)
&& pass == 3 && myPC <= myAppData.end)
{
bytes++;
if (bytes == 9) // TODO - perhaps make this configurable to size of output area
bool row = check_bit(myPC, CartDebug::ROW) &&
!check_bit(myPC, CartDebug::CODE | CartDebug::DATA |
CartDebug::GFX | CartDebug::PGFX);
bool referenced = check_bit(myPC, CartDebug::REFERENCED);
bool line_empty = true;
while (row && myPC <= myAppData.end)
{
addEntry(CartDebug::ROW);
myDisasmBuf << " ' '.byte $" << HEX2 << (int)Debugger::debugger().peek(myPC+myOffset);
bytes = 1;
if(referenced) // start a new line with a label
{
if(!line_empty)
{
addEntry(CartDebug::ROW);
line_empty = true;
}
myDisasmBuf << HEX4 << myPC+myOffset << "'L" << HEX4
<< myPC+myOffset << "'.byte " << "$" << HEX2
<< (int)Debugger::debugger().peek(myPC+myOffset);
myPC++;
bytes = 1;
line_empty = false;
}
else if(line_empty) // start a new line without a label
{
myDisasmBuf << " ' '.byte $" << HEX2 << (int)Debugger::debugger().peek(myPC+myOffset);
myPC++;
bytes = 1;
line_empty = false;
}
// Otherwise, append bytes to the current line, up until the maximum
else if(++bytes == mySettings.bwidth)
{
addEntry(CartDebug::ROW);
line_empty = true;
}
else
{
myDisasmBuf << ",$" << HEX2 << (int)Debugger::debugger().peek(myPC+myOffset);
myPC++;
}
row = check_bit(myPC, CartDebug::ROW) &&
!check_bit(myPC, CartDebug::CODE | CartDebug::DATA |
CartDebug::GFX | CartDebug::PGFX);
referenced = check_bit(myPC, CartDebug::REFERENCED);
}
else
myDisasmBuf << ",$" << HEX2 << (int)Debugger::debugger().peek(myPC+myOffset);
myPC++;
}
if (pass == 3)
{
addEntry(CartDebug::ROW);
if(!line_empty)
addEntry(CartDebug::ROW);
myDisasmBuf << " ' ' ";
addEntry(CartDebug::NONE);
}
else
myPC++;
}
else // The following sections must be SKIP or CODE
else // The following sections must be CODE
{
// Add label (if any)
//
@ -316,15 +340,15 @@ void DiStella::disasm(uInt32 distart, int pass)
addr_mode = ourLookup[op].addr_mode;
myPC++;
#if 0
// FIXME - the following condition is never true
if (ourLookup[op].mnemonic[0] == '.')
// Undefined opcodes are in lowercase letters
// Original Distella has those opcodes starting with a '.'
if (islower(ourLookup[op].mnemonic[0]))
{
addr_mode = IMPLIED;
if (pass == 3)
nextline << ".byte $" << HEX2 << (int)op << " ;";
}
#endif
if (pass == 1)
{
/* M_REL covers BPL, BMI, BVC, BVS, BCC, BCS, BNE, BEQ
@ -433,7 +457,7 @@ void DiStella::disasm(uInt32 distart, int pass)
#endif
case ACCUMULATOR:
{
if (pass == 3)
if (pass == 3 && mySettings.aflag)
nextline << " A";
break;
}
@ -969,9 +993,6 @@ void DiStella::addEntry(CartDebug::DisasmType type)
myDisasmBuf.seekg(11, ios::beg);
switch(tag.type)
{
case CartDebug::SKIP: // TODO - handle this
tag.disasm = " ";
break;
case CartDebug::CODE:
getline(myDisasmBuf, tag.disasm, '\'');
getline(myDisasmBuf, tag.ccount, '\'');
@ -1025,9 +1046,11 @@ void DiStella::processDirectives(const CartDebug::DirectiveList& directives)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DiStella::Settings DiStella::settings = {
kBASE_2, // gfx_format
true, // show_addresses
true, // show_addresses (not used externally; always off)
false, // aflag (-a in Distella)
true, // fflag (-f in Distella)
false // rflag (-r in Distella)
false, // rflag (-r in Distella)
9 // number of bytes to use with .byte directive
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -46,9 +46,11 @@ class DiStella
// standalone Distella
typedef struct {
BaseFormat gfx_format;
bool show_addresses;
bool show_addresses; // Show PC addresses (always off for external output)
bool aflag; // Turns 'A' off in accumulator instructions (-a in Distella)
bool fflag; // Forces correct address length (-f in Distella)
bool rflag; // Relocate calls out of address range (-r in Distella)
int bwidth; // Number of bytes to use per line (with .byte xxx)
} Settings;
static Settings settings; // Default settings

View File

@ -27,7 +27,6 @@
#include "PackedBitArray.hxx"
// Flags for disassembly types
#define DISASM_SKIP CartDebug::SKIP
#define DISASM_CODE CartDebug::CODE
#define DISASM_GFX CartDebug::GFX
#define DISASM_PGFX CartDebug::PGFX
@ -36,7 +35,6 @@
#define DISASM_NONE 0
#else
// Flags for disassembly types
#define DISASM_SKIP 0
#define DISASM_CODE 0
#define DISASM_GFX 0
#define DISASM_PGFX 0

View File

@ -290,7 +290,7 @@ class System : public Serializable
/**
Access and modify the disassembly type flags for the given
address. Note that while any flag can be used, the disassembly
only really acts on SKIP/CODE/GFX/PGFX/DATA/ROW.
only really acts on CODE/GFX/PGFX/DATA/ROW.
*/
uInt8 getAccessFlags(uInt16 address);
void setAccessFlags(uInt16 address, uInt8 flags);