Checking in WIP for DiStella integration. The disassembly is now shown in

the RomListWidget instead of being printed to the terminal.  There are still
graphical glitches with this, but for a first pass, it's nice to see actual
Distella output in Stella.

Partially working 'disasm' command from the PromptWidget.  Currently, it
only disassembles cart address space (aka, 0x1000 or above).

Removed the old disassembly code from CartDebug.  Still TODO is fix the
label stuff, both in getting DiStella to use it, and adding/removing
labels.  This is greatly reduced now that we only have to worry about
user labels.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1934 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2010-02-07 21:23:26 +00:00
parent 03191759ab
commit 8ca34a4d90
8 changed files with 183 additions and 735 deletions

View File

@ -169,177 +169,74 @@ string CartDebug::toString()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string& CartDebug::disassemble(int start, int lines)
bool CartDebug::disassemble(bool autocode)
{
static string result= "";
ostringstream buffer;
string cpubuf;
bool changed = false;
if(start < 0x80 || start > 0xffff)
return result;
// Test current disassembly; don't re-disassemble if it hasn't changed
// ...
changed = true; // FIXME
do {
buffer << getLabel(start, true, 4) << ": ";
int count = disassemble(start, cpubuf);
for(int i = 0; i < count; i++)
buffer << hex << setw(2) << setfill('0') << myDebugger.peek(start++) << " " << dec;
if(count < 3) buffer << " ";
if(count < 2) buffer << " ";
buffer << " " << cpubuf << "\n";
} while(--lines > 0 && start <= 0xffff);
result = buffer.str();
return result;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartDebug::disassemble(IntArray& addr, StringList& addrLabel,
StringList& bytes, StringList& data,
int start, int end)
{
if(start < 0x80 || end > 0xffff)
return;
string cpubuf, tmp;
char buf[255];
do {
addr.push_back(start);
addrLabel.push_back(getLabel(start, true, 4) + ":");
cpubuf = "";
int count = disassemble(start, cpubuf);
tmp = "";
for(int i = 0; i < count; i++)
{
sprintf(buf, "%02x ", myDebugger.peek(start++));
tmp += buf;
}
bytes.push_back(tmp);
data.push_back(cpubuf);
}
while(start <= end);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartDebug::disassemble(DisassemblyList& list, uInt16 start, bool autocode)
{
DiStella distella;
distella.disassemble(list, start, autocode);
// TODO - look at list, extract address to label mappings
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int CartDebug::disassemble(int address, string& result)
{
ostringstream buf;
int count = 0;
int opcode = mySystem.peek(address);
// Are we looking at a read or write operation?
// It will determine what type of label to use
bool isRead = (CartDebug::AccessModeTable[opcode] == CartDebug::Read);
switch(CartDebug::AddressModeTable[opcode])
if(changed)
{
case CartDebug::Absolute:
buf << CartDebug::InstructionMnemonicTable[opcode] << " "
<< getLabel(myDebugger.dpeek(address + 1), isRead, 4) << " ; "
<< M6502::ourInstructionCycleTable[opcode];
count = 3;
break;
myDisassembly.clear();
myAddrToLineList.clear();
case CartDebug::AbsoluteX:
buf << CartDebug::InstructionMnemonicTable[opcode] << " "
<< getLabel(myDebugger.dpeek(address + 1), isRead, 4) << ",x ; "
<< M6502::ourInstructionCycleTable[opcode];
count = 3;
break;
// TODO - add logic to determine correct start address to use
// it will depend on the current bank and PC
uInt16 start = myDebugger.dpeek(0xfffc);
case CartDebug::AbsoluteY:
buf << CartDebug::InstructionMnemonicTable[opcode] << " "
<< getLabel(myDebugger.dpeek(address + 1), isRead, 4) << ",y ; "
<< M6502::ourInstructionCycleTable[opcode];
count = 3;
break;
DiStella distella(myDisassembly, start, autocode);
case CartDebug::Immediate:
buf << CartDebug::InstructionMnemonicTable[opcode] << " #$"
<< hex << setw(2) << setfill('0') << (int) mySystem.peek(address + 1) << " ; "
<< dec << M6502::ourInstructionCycleTable[opcode];
count = 2;
break;
// Parts of the disassembly will be accessed later in different ways
// We place those parts in separate maps, to speed up access
for(uInt32 i = 0; i < myDisassembly.size(); ++i)
{
const DisassemblyTag& tag = myDisassembly[i];
case CartDebug::Implied:
buf << CartDebug::InstructionMnemonicTable[opcode] << " ; "
<< M6502::ourInstructionCycleTable[opcode];
count = 1;
break;
// Create a mapping from addresses to line numbers
if(tag.address != 0)
myAddrToLineList.insert(make_pair(tag.address, i));
case CartDebug::Indirect:
buf << CartDebug::InstructionMnemonicTable[opcode] << " ("
<< getLabel(myDebugger.dpeek(address + 1), isRead, 4) << ") ; "
<< M6502::ourInstructionCycleTable[opcode];
count = 3;
break;
case CartDebug::IndirectX:
buf << CartDebug::InstructionMnemonicTable[opcode] << " ("
<< getLabel(mySystem.peek(address + 1), isRead, 2) << ",x) ; "
<< M6502::ourInstructionCycleTable[opcode];
count = 2;
break;
case CartDebug::IndirectY:
buf << CartDebug::InstructionMnemonicTable[opcode] << " ("
<< getLabel(mySystem.peek(address + 1), isRead, 2) << "),y ; "
<< M6502::ourInstructionCycleTable[opcode];
count = 2;
break;
case CartDebug::Relative:
buf << CartDebug::InstructionMnemonicTable[opcode] << " "
<< getLabel(address + 2 + ((Int16)(Int8)mySystem.peek(address + 1)), isRead, 4)
<< " ; " << M6502::ourInstructionCycleTable[opcode];
count = 2;
break;
case CartDebug::Zero:
buf << CartDebug::InstructionMnemonicTable[opcode] << " "
<< getLabel(mySystem.peek(address + 1), isRead, 2) << " ; "
<< M6502::ourInstructionCycleTable[opcode];
count = 2;
break;
case CartDebug::ZeroX:
buf << CartDebug::InstructionMnemonicTable[opcode] << " "
<< getLabel(mySystem.peek(address + 1), isRead, 2) << ",x ; "
<< M6502::ourInstructionCycleTable[opcode];
count = 2;
break;
case CartDebug::ZeroY:
buf << CartDebug::InstructionMnemonicTable[opcode] << " "
<< getLabel(mySystem.peek(address + 1), isRead, 2) << ",y ; "
<< M6502::ourInstructionCycleTable[opcode];
count = 2;
break;
default:
buf << "dc $" << hex << setw(2) << setfill('0') << (int) opcode << " ; "
<< dec << M6502::ourInstructionCycleTable[opcode];
count = 1;
break;
// TODO - look at list, extract address to label mappings
// we need these for label support in the UI and promptwidget
}
}
result = buf.str();
return count;
return changed;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int CartDebug::addressToLine(uInt16 address) const
{
map<uInt16, int>::const_iterator iter = myAddrToLineList.find(address);
return iter != myAddrToLineList.end() ? iter->second : 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string CartDebug::disassemble(uInt16 start, uInt16 lines) const
{
if(!(start & 0x1000))
return "Disassembly below 0x1000 not yet supported";
DisassemblyList list;
DiStella distella(list, start, false);
// Fill the string with disassembled data
start &= 0xFFF;
ostringstream buffer;
for(uInt32 i = 0; i < list.size() && lines > 0; ++i)
{
const CartDebug::DisassemblyTag& tag = list[i];
if((tag.address & 0xfff) >= start)
{
buffer << uppercase << hex << setw(4) << setfill('0') << tag.address
<< ": " << tag.disasm << " " << tag.bytes << endl;
--lines;
}
}
return buffer.str();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -677,396 +574,3 @@ int CartDebug::extractValue(char *c) const
}
return ret;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const CartDebug::Equate CartDebug::ourSystemEquates[kSystemEquateSize] = {
// Standard $00-based TIA write locations:
{ "VSYNC", 0x00, EQF_WRITE },
{ "VBLANK", 0x01, EQF_WRITE },
{ "WSYNC", 0x02, EQF_WRITE },
{ "RSYNC", 0x03, EQF_WRITE },
{ "NUSIZ0", 0x04, EQF_WRITE },
{ "NUSIZ1", 0x05, EQF_WRITE },
{ "COLUP0", 0x06, EQF_WRITE },
{ "COLUP1", 0x07, EQF_WRITE },
{ "COLUPF", 0x08, EQF_WRITE },
{ "COLUBK", 0x09, EQF_WRITE },
{ "CTRLPF", 0x0A, EQF_WRITE },
{ "REFP0", 0x0B, EQF_WRITE },
{ "REFP1", 0x0C, EQF_WRITE },
{ "PF0", 0x0D, EQF_WRITE },
{ "PF1", 0x0E, EQF_WRITE },
{ "PF2", 0x0F, EQF_WRITE },
{ "RESP0", 0x10, EQF_WRITE },
{ "RESP1", 0x11, EQF_WRITE },
{ "RESM0", 0x12, EQF_WRITE },
{ "RESM1", 0x13, EQF_WRITE },
{ "RESBL", 0x14, EQF_WRITE },
{ "AUDC0", 0x15, EQF_WRITE },
{ "AUDC1", 0x16, EQF_WRITE },
{ "AUDF0", 0x17, EQF_WRITE },
{ "AUDF1", 0x18, EQF_WRITE },
{ "AUDV0", 0x19, EQF_WRITE },
{ "AUDV1", 0x1A, EQF_WRITE },
{ "GRP0", 0x1B, EQF_WRITE },
{ "GRP1", 0x1C, EQF_WRITE },
{ "ENAM0", 0x1D, EQF_WRITE },
{ "ENAM1", 0x1E, EQF_WRITE },
{ "ENABL", 0x1F, EQF_WRITE },
{ "HMP0", 0x20, EQF_WRITE },
{ "HMP1", 0x21, EQF_WRITE },
{ "HMM0", 0x22, EQF_WRITE },
{ "HMM1", 0x23, EQF_WRITE },
{ "HMBL", 0x24, EQF_WRITE },
{ "VDELP0", 0x25, EQF_WRITE },
{ "VDEL01", 0x26, EQF_WRITE },
{ "VDELP1", 0x26, EQF_WRITE },
{ "VDELBL", 0x27, EQF_WRITE },
{ "RESMP0", 0x28, EQF_WRITE },
{ "RESMP1", 0x29, EQF_WRITE },
{ "HMOVE", 0x2A, EQF_WRITE },
{ "HMCLR", 0x2B, EQF_WRITE },
{ "CXCLR", 0x2C, EQF_WRITE },
// Mirrored $40-based TIA write locations:
{ "VSYNC.40", 0x40, EQF_WRITE },
{ "VBLANK.40", 0x41, EQF_WRITE },
{ "WSYNC.40", 0x42, EQF_WRITE },
{ "RSYNC.40", 0x43, EQF_WRITE },
{ "NUSIZ0.40", 0x44, EQF_WRITE },
{ "NUSIZ1.40", 0x45, EQF_WRITE },
{ "COLUP0.40", 0x46, EQF_WRITE },
{ "COLUP1.40", 0x47, EQF_WRITE },
{ "COLUPF.40", 0x48, EQF_WRITE },
{ "COLUBK.40", 0x49, EQF_WRITE },
{ "CTRLPF.40", 0x4A, EQF_WRITE },
{ "REFP0.40", 0x4B, EQF_WRITE },
{ "REFP1.40", 0x4C, EQF_WRITE },
{ "PF0.40", 0x4D, EQF_WRITE },
{ "PF1.40", 0x4E, EQF_WRITE },
{ "PF2.40", 0x4F, EQF_WRITE },
{ "RESP0.40", 0x50, EQF_WRITE },
{ "RESP1.40", 0x51, EQF_WRITE },
{ "RESM0.40", 0x52, EQF_WRITE },
{ "RESM1.40", 0x53, EQF_WRITE },
{ "RESBL.40", 0x54, EQF_WRITE },
{ "AUDC0.40", 0x55, EQF_WRITE },
{ "AUDC1.40", 0x56, EQF_WRITE },
{ "AUDF0.40", 0x57, EQF_WRITE },
{ "AUDF1.40", 0x58, EQF_WRITE },
{ "AUDV0.40", 0x59, EQF_WRITE },
{ "AUDV1.40", 0x5A, EQF_WRITE },
{ "GRP0.40", 0x5B, EQF_WRITE },
{ "GRP1.40", 0x5C, EQF_WRITE },
{ "ENAM0.40", 0x5D, EQF_WRITE },
{ "ENAM1.40", 0x5E, EQF_WRITE },
{ "ENABL.40", 0x5F, EQF_WRITE },
{ "HMP0.40", 0x60, EQF_WRITE },
{ "HMP1.40", 0x61, EQF_WRITE },
{ "HMM0.40", 0x62, EQF_WRITE },
{ "HMM1.40", 0x63, EQF_WRITE },
{ "HMBL.40", 0x64, EQF_WRITE },
{ "VDELP0.40", 0x65, EQF_WRITE },
{ "VDEL01.40", 0x66, EQF_WRITE },
{ "VDELP1.40", 0x66, EQF_WRITE },
{ "VDELBL.40", 0x67, EQF_WRITE },
{ "RESMP0.40", 0x68, EQF_WRITE },
{ "RESMP1.40", 0x69, EQF_WRITE },
{ "HMOVE.40", 0x6A, EQF_WRITE },
{ "HMCLR.40", 0x6B, EQF_WRITE },
{ "CXCLR.40", 0x6C, EQF_WRITE },
// Standard $00-based TIA read locations:
{ "CXM0P", 0x00, EQF_READ },
{ "CXM1P", 0x01, EQF_READ },
{ "CXP0FB", 0x02, EQF_READ },
{ "CXP1FB", 0x03, EQF_READ },
{ "CXM0FB", 0x04, EQF_READ },
{ "CXM1FB", 0x05, EQF_READ },
{ "CXBLPF", 0x06, EQF_READ },
{ "CXPPMM", 0x07, EQF_READ },
{ "INPT0", 0x08, EQF_READ },
{ "INPT1", 0x09, EQF_READ },
{ "INPT2", 0x0A, EQF_READ },
{ "INPT3", 0x0B, EQF_READ },
{ "INPT4", 0x0C, EQF_READ },
{ "INPT5", 0x0D, EQF_READ },
// Mirrored $10-based TIA read locations:
{ "CXM0P.10", 0x10, EQF_READ },
{ "CXM1P.10", 0x11, EQF_READ },
{ "CXP0FB.10", 0x12, EQF_READ },
{ "CXP1FB.10", 0x13, EQF_READ },
{ "CXM0FB.10", 0x14, EQF_READ },
{ "CXM1FB.10", 0x15, EQF_READ },
{ "CXBLPF.10", 0x16, EQF_READ },
{ "CXPPMM.10", 0x17, EQF_READ },
{ "INPT0.10", 0x18, EQF_READ },
{ "INPT1.10", 0x19, EQF_READ },
{ "INPT2.10", 0x1A, EQF_READ },
{ "INPT3.10", 0x1B, EQF_READ },
{ "INPT4.10", 0x1C, EQF_READ },
{ "INPT5.10", 0x1D, EQF_READ },
// Mirrored $20-based TIA read locations:
{ "CXM0P.20", 0x20, EQF_READ },
{ "CXM1P.20", 0x21, EQF_READ },
{ "CXP0FB.20", 0x22, EQF_READ },
{ "CXP1FB.20", 0x23, EQF_READ },
{ "CXM0FB.20", 0x24, EQF_READ },
{ "CXM1FB.20", 0x25, EQF_READ },
{ "CXBLPF.20", 0x26, EQF_READ },
{ "CXPPMM.20", 0x27, EQF_READ },
{ "INPT0.20", 0x28, EQF_READ },
{ "INPT1.20", 0x29, EQF_READ },
{ "INPT2.20", 0x2A, EQF_READ },
{ "INPT3.20", 0x2B, EQF_READ },
{ "INPT4.20", 0x2C, EQF_READ },
{ "INPT5.20", 0x2D, EQF_READ },
// Mirrored $30-based TIA read locations:
{ "CXM0P.30", 0x30, EQF_READ },
{ "CXM1P.30", 0x31, EQF_READ },
{ "CXP0FB.30", 0x32, EQF_READ },
{ "CXP1FB.30", 0x33, EQF_READ },
{ "CXM0FB.30", 0x34, EQF_READ },
{ "CXM1FB.30", 0x35, EQF_READ },
{ "CXBLPF.30", 0x36, EQF_READ },
{ "CXPPMM.30", 0x37, EQF_READ },
{ "INPT0.30", 0x38, EQF_READ },
{ "INPT1.30", 0x39, EQF_READ },
{ "INPT2.30", 0x3A, EQF_READ },
{ "INPT3.30", 0x3B, EQF_READ },
{ "INPT4.30", 0x3C, EQF_READ },
{ "INPT5.30", 0x3D, EQF_READ },
// Standard RIOT locations (read, write, or both):
{ "SWCHA", 0x280, EQF_RW },
{ "SWCHB", 0x282, EQF_RW },
{ "SWACNT", 0x281, EQF_WRITE },
{ "SWBCNT", 0x283, EQF_WRITE },
{ "INTIM", 0x284, EQF_READ },
{ "TIMINT", 0x285, EQF_READ },
{ "TIM1T", 0x294, EQF_WRITE },
{ "TIM8T", 0x295, EQF_WRITE },
{ "TIM64T", 0x296, EQF_WRITE },
{ "T1024T", 0x297, EQF_WRITE }
};
///////////////////////////////////////////////////////////////////
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartDebug::AddressingMode CartDebug::AddressModeTable[256] = {
Implied, IndirectX, Invalid, IndirectX, // 0x0?
Zero, Zero, Zero, Zero,
Implied, Immediate, Implied, Immediate,
Absolute, Absolute, Absolute, Absolute,
Relative, IndirectY, Invalid, IndirectY, // 0x1?
ZeroX, ZeroX, ZeroX, ZeroX,
Implied, AbsoluteY, Implied, AbsoluteY,
AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX,
Absolute, IndirectX, Invalid, IndirectX, // 0x2?
Zero, Zero, Zero, Zero,
Implied, Immediate, Implied, Immediate,
Absolute, Absolute, Absolute, Absolute,
Relative, IndirectY, Invalid, IndirectY, // 0x3?
ZeroX, ZeroX, ZeroX, ZeroX,
Implied, AbsoluteY, Implied, AbsoluteY,
AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX,
Implied, IndirectX, Invalid, IndirectX, // 0x4?
Zero, Zero, Zero, Zero,
Implied, Immediate, Implied, Immediate,
Absolute, Absolute, Absolute, Absolute,
Relative, IndirectY, Invalid, IndirectY, // 0x5?
ZeroX, ZeroX, ZeroX, ZeroX,
Implied, AbsoluteY, Implied, AbsoluteY,
AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX,
Implied, IndirectX, Invalid, IndirectX, // 0x6?
Zero, Zero, Zero, Zero,
Implied, Immediate, Implied, Immediate,
Indirect, Absolute, Absolute, Absolute,
Relative, IndirectY, Invalid, IndirectY, // 0x7?
ZeroX, ZeroX, ZeroX, ZeroX,
Implied, AbsoluteY, Implied, AbsoluteY,
AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX,
Immediate, IndirectX, Immediate, IndirectX, // 0x8?
Zero, Zero, Zero, Zero,
Implied, Immediate, Implied, Immediate,
Absolute, Absolute, Absolute, Absolute,
Relative, IndirectY, Invalid, IndirectY, // 0x9?
ZeroX, ZeroX, ZeroY, ZeroY,
Implied, AbsoluteY, Implied, AbsoluteY,
AbsoluteX, AbsoluteX, AbsoluteY, AbsoluteY,
Immediate, IndirectX, Immediate, IndirectX, // 0xA?
Zero, Zero, Zero, Zero,
Implied, Immediate, Implied, Immediate,
Absolute, Absolute, Absolute, Absolute,
Relative, IndirectY, Invalid, IndirectY, // 0xB?
ZeroX, ZeroX, ZeroY, ZeroY,
Implied, AbsoluteY, Implied, AbsoluteY,
AbsoluteX, AbsoluteX, AbsoluteY, AbsoluteY,
Immediate, IndirectX, Immediate, IndirectX, // 0xC?
Zero, Zero, Zero, Zero,
Implied, Immediate, Implied, Immediate,
Absolute, Absolute, Absolute, Absolute,
Relative, IndirectY, Invalid, IndirectY, // 0xD?
ZeroX, ZeroX, ZeroX, ZeroX,
Implied, AbsoluteY, Implied, AbsoluteY,
AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX,
Immediate, IndirectX, Immediate, IndirectX, // 0xE?
Zero, Zero, Zero, Zero,
Implied, Immediate, Implied, Immediate,
Absolute, Absolute, Absolute, Absolute,
Relative, IndirectY, Invalid, IndirectY, // 0xF?
ZeroX, ZeroX, ZeroX, ZeroX,
Implied, AbsoluteY, Implied, AbsoluteY,
AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartDebug::AccessMode CartDebug::AccessModeTable[256] = {
None, Read, None, Write, // 0x0?
None, Read, Write, Write,
None, Read, Write, Read,
None, Read, Write, Write,
Read, Read, None, Write, // 0x1?
None, Read, Write, Write,
None, Read, None, Write,
None, Read, Write, Write,
Read, Read, None, Write, // 0x2?
Read, Read, Write, Write,
None, Read, Write, Read,
Read, Read, Write, Write,
Read, Read, None, Write, // 0x3?
None, Read, Write, Write,
None, Read, None, Write,
None, Read, Write, Write,
None, Read, None, Write, // 0x4?
None, Read, Write, Write,
None, Read, Write, Read,
Read, Read, Write, Write,
Read, Read, None, Write, // 0x5?
None, Read, Write, Write,
None, Read, None, Write,
None, Read, Write, Write,
None, Read, None, Write, // 0x6?
None, Read, Write, Write,
None, Read, Write, Read,
Read, Read, Write, Write,
Read, Read, None, Write, // 0x7?
None, Read, Write, Write,
None, Read, None, Write,
None, Read, Write, Write,
None, Write, None, Write, // 0x8?
Write, Write, Write, Write,
None, None, None, Read,
Write, Write, Write, Write,
Read, Write, None, Write, // 0x9?
Write, Write, Write, Write,
None, Write, None, Write,
Write, Write, Write, Write,
Read, Read, Read, Read, // 0xA?
Read, Read, Read, Read,
None, Read, None, Read,
Read, Read, Read, Read,
Read, Read, None, Read, // 0xB?
Read, Read, Read, Read,
None, Read, None, Read,
Read, Read, Read, Read,
Read, Read, None, Write, // 0xC?
Read, Read, Write, Write,
None, Read, None, Read,
Read, Read, Write, Write,
Read, Read, None, Write, // 0xD?
None, Read, Write, Write,
None, Read, None, Write,
None, Read, Write, Write,
Read, Read, None, Write, // 0xE?
Read, Read, Write, Write,
None, Read, None, Read,
Read, Read, Write, Write,
Read, Read, None, Write, // 0xF?
None, Read, Write, Write,
None, Read, None, Write,
None, Read, Write, Write
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* CartDebug::InstructionMnemonicTable[256] = {
"BRK", "ORA", "n/a", "slo", "nop", "ORA", "ASL", "slo", // 0x0?
"PHP", "ORA", "ASLA", "anc", "nop", "ORA", "ASL", "slo",
"BPL", "ORA", "n/a", "slo", "nop", "ORA", "ASL", "slo", // 0x1?
"CLC", "ORA", "nop", "slo", "nop", "ORA", "ASL", "slo",
"JSR", "AND", "n/a", "rla", "BIT", "AND", "ROL", "rla", // 0x2?
"PLP", "AND", "ROLA", "anc", "BIT", "AND", "ROL", "rla",
"BMI", "AND", "n/a", "rla", "nop", "AND", "ROL", "rla", // 0x3?
"SEC", "AND", "nop", "rla", "nop", "AND", "ROL", "rla",
"RTI", "EOR", "n/a", "sre", "nop", "EOR", "LSR", "sre", // 0x4?
"PHA", "EOR", "LSRA", "asr", "JMP", "EOR", "LSR", "sre",
"BVC", "EOR", "n/a", "sre", "nop", "EOR", "LSR", "sre", // 0x5?
"CLI", "EOR", "nop", "sre", "nop", "EOR", "LSR", "sre",
"RTS", "ADC", "n/a", "rra", "nop", "ADC", "ROR", "rra", // 0x6?
"PLA", "ADC", "RORA", "arr", "JMP", "ADC", "ROR", "rra",
"BVS", "ADC", "n/a", "rra", "nop", "ADC", "ROR", "rra", // 0x7?
"SEI", "ADC", "nop", "rra", "nop", "ADC", "ROR", "rra",
"nop", "STA", "nop", "sax", "STY", "STA", "STX", "sax", // 0x8?
"DEY", "nop", "TXA", "ane", "STY", "STA", "STX", "sax",
"BCC", "STA", "n/a", "sha", "STY", "STA", "STX", "sax", // 0x9?
"TYA", "STA", "TXS", "shs", "shy", "STA", "shx", "sha",
"LDY", "LDA", "LDX", "lax", "LDY", "LDA", "LDX", "lax", // 0xA?
"TAY", "LDA", "TAX", "lxa", "LDY", "LDA", "LDX", "lax",
"BCS", "LDA", "n/a", "lax", "LDY", "LDA", "LDX", "lax", // 0xB?
"CLV", "LDA", "TSX", "las", "LDY", "LDA", "LDX", "lax",
"CPY", "CMP", "nop", "dcp", "CPY", "CMP", "DEC", "dcp", // 0xC?
"INY", "CMP", "DEX", "sbx", "CPY", "CMP", "DEC", "dcp",
"BNE", "CMP", "n/a", "dcp", "nop", "CMP", "DEC", "dcp", // 0xD?
"CLD", "CMP", "nop", "dcp", "nop", "CMP", "DEC", "dcp",
"CPX", "SBC", "nop", "isb", "CPX", "SBC", "INC", "isb", // 0xE?
"INX", "SBC", "NOP", "sbc", "CPX", "SBC", "INC", "isb",
"BEQ", "SBC", "n/a", "isb", "nop", "SBC", "INC", "isb", // 0xF?
"SED", "SBC", "nop", "isb", "nop", "SBC", "INC", "isb"
};

View File

@ -21,6 +21,8 @@
class System;
#include <map>
#include "bspf.hxx"
#include "Array.hxx"
#include "Cart.hxx"
@ -83,32 +85,44 @@ class CartDebug : public DebuggerSystem
*/
void addRamArea(uInt16 start, uInt16 size, uInt16 roffset, uInt16 woffset);
////////////////////////////////////////
/**
Disassemble from the starting address the specified number of lines
and place result in a string.
*/
const string& disassemble(int start, int lines);
/**
Disassemble from the starting address to the ending address
and place addresses, bytes and data in given arrays.
*/
void disassemble(IntArray& addr, StringList& addrLabel,
StringList& bytes, StringList& data,
int start, int end);
// The following two methods are meant to be used together
// First, a call is made to disassemble(), which updates the disassembly
// list; it will figure out when an actual complete disassembly is
// required, and when the previous results can be used
//
// Later, successive calls to disassemblyList() simply return the
// previous results; no disassembly is done in this case
/**
Disassemble from the given address using the Distella disassembler
Address-to-label mappings (and vice-versa) are also determined here
@return True if disassembly changed from previous call, else false
*/
void disassemble(DisassemblyList& list, uInt16 start, bool autocode);
bool disassemble(bool autocode);
/**
Get the results from the most recent call to disassemble()
*/
const DisassemblyList& disassemblyList() const { return myDisassembly; }
/**
Determine the line in the disassembly that corresponds to the given
address. A value of zero indicates that no such address exists.
*/
int addressToLine(uInt16 address) const;
/**
Disassemble from the starting address the specified number of lines.
Note that automatic code determination is turned off for this method;
it will treat all address contents as instructions.
*/
string disassemble(uInt16 start, uInt16 lines) const;
int getBank();
int bankCount();
string getCartType();
////////////////////////////////////////
////////////////////////////////////////
/**
Add a label and associated address
*/
@ -148,9 +162,7 @@ class CartDebug : public DebuggerSystem
int countCompletions(const char *in);
const string& getCompletions() const { return myCompletions; }
const string& getCompletionPrefix() const { return myCompPrefix; }
private:
int disassemble(int address, string& result);
////////////////////////////////////////
private:
enum equate_t {
@ -186,6 +198,7 @@ class CartDebug : public DebuggerSystem
CartState myOldState;
DisassemblyList myDisassembly;
map<uInt16, int> myAddrToLineList;
LabelToAddr mySystemAddresses;
AddrToLabel mySystemReadLabels; // labels used in a read context
@ -200,40 +213,6 @@ class CartDebug : public DebuggerSystem
string myCompPrefix;
uInt16 myRWPortAddress;
enum { kSystemEquateSize = 158 };
static const Equate ourSystemEquates[kSystemEquateSize];
//////////////////////////////////////////////
/**
Enumeration of the 6502 addressing modes
*/
enum AddressingMode
{
Absolute, AbsoluteX, AbsoluteY, Immediate, Implied,
Indirect, IndirectX, IndirectY, Invalid, Relative,
Zero, ZeroX, ZeroY
};
/**
Enumeration of the 6502 access modes
*/
enum AccessMode
{
Read, Write, None
};
/// Addressing mode for each of the 256 opcodes
/// This specifies how the opcode argument is addressed
static AddressingMode AddressModeTable[256];
/// Access mode for each of the 256 opcodes
/// This specifies how the opcode will access its argument
static AccessMode AccessModeTable[256];
/// Table of instruction mnemonics
static const char* InstructionMnemonicTable[256];
//////////////////////////////////////////////
};
#endif

View File

@ -25,19 +25,9 @@
#include "DiStella.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DiStella::DiStella()
DiStella::DiStella(CartDebug::DisassemblyList& list, uInt16 start,
bool autocode)
: labels(NULL) /* array of information about addresses-- can be from 2K-48K bytes in size */
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DiStella::~DiStella()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 DiStella::disassemble(CartDebug::DisassemblyList& list, uInt16 start,
bool autocode)
{
while(!myAddressQueue.empty())
myAddressQueue.pop();
@ -52,7 +42,7 @@ uInt32 DiStella::disassemble(CartDebug::DisassemblyList& list, uInt16 start,
if (labels == NULL)
{
fprintf (stderr, "Malloc failed for 'labels' variable\n");
return 0;
return;
}
memset(labels,0,myAppData.length);
@ -103,8 +93,11 @@ uInt32 DiStella::disassemble(CartDebug::DisassemblyList& list, uInt16 start,
disasm(list, myOffset, 3);
free(labels); /* Free dynamic memory before program ends */
}
return list.size();
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DiStella::~DiStella()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -139,8 +132,8 @@ void DiStella::disasm(CartDebug::DisassemblyList& list, uInt32 distart, int pass
else
myBuf << HEX4 << myPC+myOffset << "' '";
myBuf << ".byte $" << HEX2 << (int)Debugger::debugger().peek(myPC|0x1000) << " ; ";
showgfx(Debugger::debugger().peek(myPC|0x1000));
myBuf << ".byte $" << HEX2 << (int)Debugger::debugger().peek(myPC+myOffset) << " ; ";
showgfx(Debugger::debugger().peek(myPC+myOffset));
myBuf << " $" << HEX4 << myPC+myOffset;
addEntry(list);
}
@ -154,7 +147,7 @@ void DiStella::disasm(CartDebug::DisassemblyList& list, uInt32 distart, int pass
{
bytes = 1;
myBuf << HEX4 << myPC+myOffset << "'L" << myPC+myOffset << "'.byte "
<< "$" << HEX2 << (int)Debugger::debugger().peek(myPC|0x1000);
<< "$" << HEX2 << (int)Debugger::debugger().peek(myPC+myOffset);
}
myPC++;
@ -167,11 +160,11 @@ void DiStella::disasm(CartDebug::DisassemblyList& list, uInt32 distart, int pass
if (bytes == 17)
{
addEntry(list);
myBuf << " ' '.byte $" << HEX2 << (int)Debugger::debugger().peek(myPC|0x1000);
myBuf << " ' '.byte $" << HEX2 << (int)Debugger::debugger().peek(myPC+myOffset);
bytes = 1;
}
else
myBuf << ",$" << HEX2 << (int)Debugger::debugger().peek(myPC|0x1000);
myBuf << ",$" << HEX2 << (int)Debugger::debugger().peek(myPC+myOffset);
}
myPC++;
}
@ -185,7 +178,7 @@ void DiStella::disasm(CartDebug::DisassemblyList& list, uInt32 distart, int pass
}
else
{
op = Debugger::debugger().peek(myPC|0x1000);
op = Debugger::debugger().peek(myPC+myOffset);
/* version 2.1 bug fix */
if (pass == 2)
mark(myPC+myOffset, VALID_ENTRY);
@ -254,7 +247,7 @@ void DiStella::disasm(CartDebug::DisassemblyList& list, uInt32 distart, int pass
else
myBuf << HEX4 << myPC+myOffset << "' '";
op = Debugger::debugger().peek(myPC|0x1000); myPC++;
op = Debugger::debugger().peek(myPC+myOffset); myPC++;
myBuf << ".byte $" << HEX2 << (int)op;
addEntry(list);
}
@ -321,7 +314,7 @@ void DiStella::disasm(CartDebug::DisassemblyList& list, uInt32 distart, int pass
case ABSOLUTE:
{
ad = Debugger::debugger().dpeek(myPC|0x1000); myPC+=2;
ad = Debugger::debugger().dpeek(myPC+myOffset); myPC+=2;
labfound = mark(ad, REFERENCED);
if (pass == 1)
{
@ -380,7 +373,7 @@ void DiStella::disasm(CartDebug::DisassemblyList& list, uInt32 distart, int pass
case ZERO_PAGE:
{
d1 = Debugger::debugger().peek(myPC|0x1000); myPC++;
d1 = Debugger::debugger().peek(myPC+myOffset); myPC++;
labfound = mark(d1, REFERENCED);
if (pass == 3)
{
@ -402,7 +395,7 @@ void DiStella::disasm(CartDebug::DisassemblyList& list, uInt32 distart, int pass
case IMMEDIATE:
{
d1 = Debugger::debugger().peek(myPC|0x1000); myPC++;
d1 = Debugger::debugger().peek(myPC+myOffset); myPC++;
if (pass == 3)
{
sprintf(linebuff," #$%.2X ",d1);
@ -415,7 +408,7 @@ void DiStella::disasm(CartDebug::DisassemblyList& list, uInt32 distart, int pass
case ABSOLUTE_X:
{
ad = Debugger::debugger().dpeek(myPC|0x1000); myPC+=2;
ad = Debugger::debugger().dpeek(myPC+myOffset); myPC+=2;
labfound = mark(ad, REFERENCED);
if (pass == 3)
{
@ -465,7 +458,7 @@ void DiStella::disasm(CartDebug::DisassemblyList& list, uInt32 distart, int pass
case ABSOLUTE_Y:
{
ad = Debugger::debugger().dpeek(myPC|0x1000); myPC+=2;
ad = Debugger::debugger().dpeek(myPC+myOffset); myPC+=2;
labfound = mark(ad, REFERENCED);
if (pass == 3)
{
@ -514,7 +507,7 @@ void DiStella::disasm(CartDebug::DisassemblyList& list, uInt32 distart, int pass
case INDIRECT_X:
{
d1 = Debugger::debugger().peek(myPC|0x1000); myPC++;
d1 = Debugger::debugger().peek(myPC+myOffset); myPC++;
if (pass == 3)
{
sprintf(linebuff," ($%.2X,X)",d1);
@ -527,7 +520,7 @@ void DiStella::disasm(CartDebug::DisassemblyList& list, uInt32 distart, int pass
case INDIRECT_Y:
{
d1 = Debugger::debugger().peek(myPC|0x1000); myPC++;
d1 = Debugger::debugger().peek(myPC+myOffset); myPC++;
if (pass == 3)
{
sprintf(linebuff," ($%.2X),Y",d1);
@ -540,7 +533,7 @@ void DiStella::disasm(CartDebug::DisassemblyList& list, uInt32 distart, int pass
case ZERO_PAGE_X:
{
d1 = Debugger::debugger().peek(myPC|0x1000); myPC++;
d1 = Debugger::debugger().peek(myPC+myOffset); myPC++;
labfound = mark(d1, REFERENCED);
if (pass == 3)
{
@ -562,7 +555,7 @@ void DiStella::disasm(CartDebug::DisassemblyList& list, uInt32 distart, int pass
case ZERO_PAGE_Y:
{
d1 = Debugger::debugger().peek(myPC|0x1000); myPC++;
d1 = Debugger::debugger().peek(myPC+myOffset); myPC++;
labfound = mark(d1,REFERENCED);
if (pass == 3)
{
@ -584,7 +577,7 @@ void DiStella::disasm(CartDebug::DisassemblyList& list, uInt32 distart, int pass
case RELATIVE:
{
d1 = Debugger::debugger().peek(myPC|0x1000); myPC++;
d1 = Debugger::debugger().peek(myPC+myOffset); myPC++;
ad = d1;
if (d1 >= 128)
ad = d1 - 256;
@ -620,7 +613,7 @@ void DiStella::disasm(CartDebug::DisassemblyList& list, uInt32 distart, int pass
case ABS_INDIRECT:
{
ad = Debugger::debugger().dpeek(myPC|0x1000); myPC+=2;
ad = Debugger::debugger().dpeek(myPC+myOffset); myPC+=2;
labfound = mark(ad, REFERENCED);
if (pass == 3)
{

View File

@ -41,10 +41,6 @@
*/
class DiStella
{
public:
DiStella();
~DiStella();
public:
/**
Disassemble the current state of the System from the given start address.
@ -52,11 +48,11 @@ class DiStella
@param list The results of the disassembly are placed here
@param start The address at which to start disassembly
@param autocode If enabled, try to determine code vs. data sections
@return The number of lines that were disassembled
*/
uInt32 disassemble(CartDebug::DisassemblyList& list, uInt16 start,
bool autocode = true);
DiStella(CartDebug::DisassemblyList& list, uInt16 start,
bool autocode = true);
~DiStella();
private:
// Marked bits

View File

@ -52,12 +52,15 @@ RomListWidget::~RomListWidget()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RomListWidget::setList(StringList& label, StringList& bytes, StringList& disasm,
BoolArray& state)
void RomListWidget::setList(const CartDebug::DisassemblyList& list,
const BoolArray& state)
{
myLabel = label;
myDisasm = disasm;
myList = &list;
// TODO - maybe there's a better way than copying all the bytes again??
StringList bytes;
for(uInt32 i = 0; i < list.size(); ++i)
bytes.push_back(list[i].bytes);
CheckListWidget::setList(bytes, state);
}
@ -85,7 +88,8 @@ void RomListWidget::drawWidget(bool hilite)
{
//cerr << "RomListWidget::drawWidget\n";
FBSurface& s = _boss->dialog().surface();
int i, pos, xpos, ypos, len = _list.size();
const CartDebug::DisassemblyList& dlist = *myList;
int i, pos, xpos, ypos, len = dlist.size();
string buffer;
int deltax;
@ -126,11 +130,11 @@ void RomListWidget::drawWidget(bool hilite)
}
// Draw labels
s.drawString(_font, myLabel[pos], xpos, ypos,
s.drawString(_font, dlist[pos].label, xpos, ypos,
myLabelWidth, kTextColor);
// Draw disassembly
s.drawString(_font, myDisasm[pos], xpos + myLabelWidth, ypos,
s.drawString(_font, dlist[pos].disasm, xpos + myLabelWidth, ypos,
r.left, kTextColor);
// Draw editable bytes

View File

@ -26,7 +26,7 @@ class CheckboxWidget;
class ContextMenu;
#include "CheckListWidget.hxx"
#include "CartDebug.hxx"
/** RomListWidget */
class RomListWidget : public CheckListWidget
@ -38,8 +38,7 @@ class RomListWidget : public CheckListWidget
int x, int y, int w, int h);
virtual ~RomListWidget();
void setList(StringList& label, StringList& bytes, StringList& disasm,
BoolArray& state);
void setList(const CartDebug::DisassemblyList& list, const BoolArray& state);
protected:
void handleMouseDown(int x, int y, int button, int clickCount);
@ -56,7 +55,7 @@ class RomListWidget : public CheckListWidget
int myLabelWidth;
int myBytesWidth;
StringList myLabel, myDisasm;
const CartDebug::DisassemblyList* myList;
};
#endif

View File

@ -100,9 +100,6 @@ RomWidget::RomWidget(GuiObject* boss, const GUI::Font& font, int x, int y)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RomWidget::~RomWidget()
{
myAddrList.clear();
myLineList.clear();
delete mySaveRom;
}
@ -166,71 +163,39 @@ void RomWidget::loadConfig()
// Fill romlist the current bank of source or disassembly
// Only reload full bank when necessary
if(myListIsDirty || bankChanged)
// TODO - bank changes aren't the only time that the disassembly needs to
// be redone; ROMs which dynamically change cart address space and
// have self-modifying code need to be taken into account
// As well, we don't always start from the 0xfffc; this only
// happens in the startup bank
myListIsDirty |= cart.disassemble(true);
if(myListIsDirty)
{
/*
// Clear old mappings
myAddrList.clear();
myLineList.clear();
StringList label, data, disasm;
const CartDebug::DisassemblyList& list = cart.disassemblyList();
BoolArray state;
// Disassemble zero-page RAM and entire bank and reset breakpoints
cart.disassemble(myAddrList, label, data, disasm, 0x80, 0xff);
cart.disassemble(myAddrList, label, data, disasm, 0xf000, 0xffff);
PackedBitArray& bp = dbg.breakpoints();
for(unsigned int i = 0; i < data.size(); ++i)
for(uInt32 i = 0; i < list.size(); ++i)
{
if(bp.isSet(myAddrList[i]))
const CartDebug::DisassemblyTag& tag = list[i];
if(tag.address != 0 && bp.isSet(tag.address))
state.push_back(true);
else
state.push_back(false);
}
// Create a mapping from addresses to line numbers
for(unsigned int i = 0; i < myAddrList.size(); ++i)
myLineList.insert(make_pair(myAddrList[i], i));
myRomList->setList(label, data, disasm, state);
myRomList->setList(list, state);
// Restore the old bank, in case we inadvertently switched while reading.
dbg.setBank(myCurrentBank);
*/
CartDebug::DisassemblyList list;
cart.disassemble(list, dbg.dpeek(0xfffc), true);
for(uInt32 i = 0; i < list.size(); ++i)
{
const CartDebug::DisassemblyTag& tag = list[i];
printf("%.4X|%5s|%s|%s|\n", tag.address, tag.label.c_str(), tag.disasm.c_str(), tag.bytes.c_str());
}
myListIsDirty = false;
}
// Update romlist to point to current PC
// Take mirroring of PC into account, as well as zero-page RAM
int pc = dbg.cpuDebug().pc();
if(pc & 0x1000) pc |= 0xe000;
AddrToLine::iterator iter = myLineList.find(pc);
// if current PC not found, do an update (we're executing what
// we thought was an operand)
// This doesn't help, and seems to actually hurt.
/*
if(iter == myLineList.end()) {
incrementalUpdate(myRomList->currentPos(), myRomList->rows());
iter = myLineList.find(pc);
}
*/
if(iter != myLineList.end())
myRomList->setHighlighted(iter->second);
int pcline = cart.addressToLine(dbg.cpuDebug().pc());
if(pcline > 0)
myRomList->setHighlighted(pcline);
// Set current bank
IntArray alist;
@ -249,34 +214,53 @@ void RomWidget::loadConfig()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RomWidget::setBreak(int data)
{
const CartDebug::DisassemblyList& list =
instance().debugger().cartDebug().disassemblyList();
if(data >= (int)list.size()) return;
bool state = myRomList->getState(data);
instance().debugger().setBreakPoint(myAddrList[data], state);
if(list[data].address != 0)
instance().debugger().setBreakPoint(list[data].address, state);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RomWidget::setPC(int data)
{
ostringstream command;
command << "pc #" << myAddrList[data];
instance().debugger().run(command.str());
const CartDebug::DisassemblyList& list =
instance().debugger().cartDebug().disassemblyList();
if(data >= (int)list.size()) return;
if(list[data].address != 0)
{
ostringstream command;
command << "pc #" << list[data].address;
instance().debugger().run(command.str());
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RomWidget::patchROM(int data, const string& bytes)
{
ostringstream command;
const CartDebug::DisassemblyList& list =
instance().debugger().cartDebug().disassemblyList();
if(data >= (int)list.size()) return;
// Temporarily set to base 16, since that's the format the disassembled
// byte string is in. This eliminates the need to prefix each byte with
// a '$' character
BaseFormat oldbase = instance().debugger().parser().base();
instance().debugger().parser().setBase(kBASE_16);
if(list[data].address != 0)
{
ostringstream command;
command << "rom #" << myAddrList[data] << " " << bytes;
instance().debugger().run(command.str());
// Temporarily set to base 16, since that's the format the disassembled
// byte string is in. This eliminates the need to prefix each byte with
// a '$' character
BaseFormat oldbase = instance().debugger().parser().base();
instance().debugger().parser().setBase(kBASE_16);
// Restore previous base
instance().debugger().parser().setBase(oldbase);
command << "rom #" << list[data].address << " " << bytes;
instance().debugger().run(command.str());
// Restore previous base
instance().debugger().parser().setBase(oldbase);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -29,14 +29,10 @@ class InputTextDialog;
class RomListWidget;
class StringList;
#include <map>
#include "Array.hxx"
#include "Widget.hxx"
#include "Command.hxx"
typedef map<int,int> AddrToLine;
#include "CartDebug.hxx"
class RomWidget : public Widget, public CommandSender
{
@ -60,14 +56,7 @@ class RomWidget : public Widget, public CommandSender
kRomNameEntered = 'RWrn'
};
RomListWidget* myRomList;
/** List of addresses indexed by line number */
IntArray myAddrList;
/** List of line numbers indexed by address */
AddrToLine myLineList;
RomListWidget* myRomList;
DataGridWidget* myBank;
EditTextWidget* myBankCount;
InputTextDialog* mySaveRom;