mirror of
https://github.com/libretro/stella2023.git
synced 2025-02-12 20:49:02 +00:00
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:
parent
3c801a7dd4
commit
b97d5120b9
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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]",
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user