mirror of https://github.com/stella-emu/stella.git
Enhance disassembly (determine correct bank offset, preliminary solution for simple 4K bankswitching, e.g. standard Atari)
This commit is contained in:
parent
32cd6e2a5b
commit
cae2266df0
|
@ -238,11 +238,51 @@ string CartDebug::toString()
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool CartDebug::disassemble(bool force)
|
bool CartDebug::disassemble(bool force)
|
||||||
|
{
|
||||||
|
uInt16 PC = myDebugger.cpuDebug().pc();
|
||||||
|
int bank = (PC & 0x1000) ? getBank(PC) : int(myBankInfo.size()) - 1;
|
||||||
|
|
||||||
|
return disassemble(bank, PC, force);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool CartDebug::disassembleBank(int bank)
|
||||||
|
{
|
||||||
|
// isolate the high 3 address bits, count them and
|
||||||
|
// select the most frequent to define the bank offset
|
||||||
|
BankInfo& info = myBankInfo[bank];
|
||||||
|
uInt16 count[8];
|
||||||
|
|
||||||
|
for(int i = 0; i < 8; ++i)
|
||||||
|
count[i] = 0;
|
||||||
|
|
||||||
|
for(uInt32 addr = 0x1000; addr < 0x1000 + info.size; ++addr)
|
||||||
|
{
|
||||||
|
Device::AccessFlags flags = mySystem.getAccessFlags(addr);
|
||||||
|
// only count really accessed addresses
|
||||||
|
if (flags & ~Device::ROW)
|
||||||
|
count[(flags & Device::HADDR) >> 13]++;
|
||||||
|
}
|
||||||
|
uInt16 max = 0, maxIdx = 0;
|
||||||
|
for(int idx = 0; idx < 8; ++idx)
|
||||||
|
{
|
||||||
|
if(count[idx] > max)
|
||||||
|
{
|
||||||
|
max = count[idx];
|
||||||
|
maxIdx = idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info.offset = maxIdx << 13 | 0x1000;
|
||||||
|
|
||||||
|
return disassemble(bank, info.offset, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool CartDebug::disassemble(int bank, uInt16 PC, bool force)
|
||||||
{
|
{
|
||||||
// Test current disassembly; don't re-disassemble if it hasn't changed
|
// Test current disassembly; don't re-disassemble if it hasn't changed
|
||||||
// Also check if the current PC is in the current list
|
// Also check if the current PC is in the current list
|
||||||
bool bankChanged = myConsole.cartridge().bankChanged();
|
bool bankChanged = myConsole.cartridge().bankChanged();
|
||||||
uInt16 PC = myDebugger.cpuDebug().pc();
|
|
||||||
int pcline = addressToLine(PC);
|
int pcline = addressToLine(PC);
|
||||||
bool pcfound = (pcline != -1) && (uInt32(pcline) < myDisassembly.list.size()) &&
|
bool pcfound = (pcline != -1) && (uInt32(pcline) < myDisassembly.list.size()) &&
|
||||||
(myDisassembly.list[pcline].disasm[0] != '.');
|
(myDisassembly.list[pcline].disasm[0] != '.');
|
||||||
|
@ -254,8 +294,9 @@ bool CartDebug::disassemble(bool force)
|
||||||
if(changed)
|
if(changed)
|
||||||
{
|
{
|
||||||
// Are we disassembling from ROM or ZP RAM?
|
// Are we disassembling from ROM or ZP RAM?
|
||||||
BankInfo& info = (PC & 0x1000) ? myBankInfo[getBank(PC)] :
|
BankInfo& info = myBankInfo[bank];
|
||||||
myBankInfo[myBankInfo.size()-1];
|
//(PC & 0x1000) ? myBankInfo[getBank(PC)] :
|
||||||
|
//myBankInfo[myBankInfo.size()-1];
|
||||||
|
|
||||||
// If the offset has changed, all old addresses must be 'converted'
|
// 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
|
// For example, if the list contains any $fxxx and the address space is now
|
||||||
|
@ -1044,6 +1085,7 @@ string CartDebug::saveDisassembly()
|
||||||
|
|
||||||
// prepare for switching banks
|
// prepare for switching banks
|
||||||
myConsole.cartridge().unlockBank();
|
myConsole.cartridge().unlockBank();
|
||||||
|
uInt32 origin = 0;
|
||||||
|
|
||||||
for(int bank = 0; bank < bankCount; ++bank)
|
for(int bank = 0; bank < bankCount; ++bank)
|
||||||
{
|
{
|
||||||
|
@ -1055,7 +1097,8 @@ string CartDebug::saveDisassembly()
|
||||||
BankInfo& info = myBankInfo[bank];
|
BankInfo& info = myBankInfo[bank];
|
||||||
|
|
||||||
// TODO: make PageAccess ready for multi-bank ROMs
|
// TODO: make PageAccess ready for multi-bank ROMs
|
||||||
disassemble();
|
// TODO: define offset if still undefined
|
||||||
|
disassembleBank(bank);
|
||||||
|
|
||||||
// An empty address list means that DiStella can't do a disassembly
|
// An empty address list means that DiStella can't do a disassembly
|
||||||
if(info.addressList.size() == 0)
|
if(info.addressList.size() == 0)
|
||||||
|
@ -1081,8 +1124,9 @@ string CartDebug::saveDisassembly()
|
||||||
if(bankCount == 1)
|
if(bankCount == 1)
|
||||||
buf << " ORG $" << Base::HEX4 << info.offset << "\n\n";
|
buf << " ORG $" << Base::HEX4 << info.offset << "\n\n";
|
||||||
else
|
else
|
||||||
buf << " ORG $" << Base::HEX4 << ((0x0000 + bank * 0x1000) & 0xffff) << "\n"
|
buf << " ORG $" << Base::HEX4 << origin << "\n"
|
||||||
<< " RORG $" << Base::HEX4 << info.offset << "\n\n";
|
<< " RORG $" << Base::HEX4 << info.offset << "\n\n";
|
||||||
|
origin += info.size;
|
||||||
|
|
||||||
// Format in 'distella' style
|
// Format in 'distella' style
|
||||||
for(uInt32 i = 0; i < disasm.list.size(); ++i)
|
for(uInt32 i = 0; i < disasm.list.size(); ++i)
|
||||||
|
|
|
@ -94,23 +94,16 @@ class CartDebug : public DebuggerSystem
|
||||||
// Return the base (= non-mirrored) address of the last CPU write
|
// Return the base (= non-mirrored) address of the last CPU write
|
||||||
int lastWriteBaseAddress();
|
int lastWriteBaseAddress();
|
||||||
|
|
||||||
// The following two methods are meant to be used together
|
// TODO
|
||||||
// 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
|
|
||||||
|
|
||||||
@param force Force a re-disassembly, even if the state hasn't changed
|
|
||||||
|
|
||||||
@return True if disassembly changed from previous call, else false
|
|
||||||
*/
|
|
||||||
bool disassemble(bool force = false);
|
bool disassemble(bool force = false);
|
||||||
|
bool disassembleBank(int bank);
|
||||||
|
|
||||||
|
// First, a call is made to disassemble(), which updates the disassembly
|
||||||
|
// list, is required; it will figure out when an actual complete
|
||||||
|
// disassembly is required, and when the previous results can be used
|
||||||
|
//
|
||||||
|
// Later, successive calls to disassembly() simply return the
|
||||||
|
// previous results; no disassembly is done in this case
|
||||||
/**
|
/**
|
||||||
Get the results from the most recent call to disassemble()
|
Get the results from the most recent call to disassemble()
|
||||||
*/
|
*/
|
||||||
|
@ -278,6 +271,19 @@ class CartDebug : public DebuggerSystem
|
||||||
};
|
};
|
||||||
ReservedEquates myReserved;
|
ReservedEquates myReserved;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Disassemble from the given address using the Distella disassembler
|
||||||
|
Address-to-label mappings (and vice-versa) are also determined here
|
||||||
|
|
||||||
|
@param bank The current bank to disassemble
|
||||||
|
@param PC A program counter to start with
|
||||||
|
@param force Force a re-disassembly, even if the state hasn't changed
|
||||||
|
|
||||||
|
@return True if disassembly changed from previous call, else false
|
||||||
|
*/
|
||||||
|
bool disassemble(int bank, uInt16 PC, bool force = false);
|
||||||
|
|
||||||
|
|
||||||
// Actually call DiStella to fill the DisassemblyList structure
|
// Actually call DiStella to fill the DisassemblyList structure
|
||||||
// Return whether the search address was actually in the list
|
// Return whether the search address was actually in the list
|
||||||
bool fillDisassemblyList(BankInfo& bankinfo, uInt16 search);
|
bool fillDisassemblyList(BankInfo& bankinfo, uInt16 search);
|
||||||
|
|
|
@ -969,9 +969,9 @@ bool DiStella::checkBit(uInt16 address, uInt16 mask, bool useDebugger) const
|
||||||
// Since they're set only in the labels array (as the lower two bits),
|
// Since they're set only in the labels array (as the lower two bits),
|
||||||
// they must be included in the other bitfields
|
// they must be included in the other bitfields
|
||||||
uInt16 label = myLabels[address & myAppData.end],
|
uInt16 label = myLabels[address & myAppData.end],
|
||||||
lastbits = label & 0x03,
|
lastbits = label & (Device::REFERENCED | Device::VALID_ENTRY),
|
||||||
directive = myDirectives[address & myAppData.end] & ~0x03,
|
directive = myDirectives[address & myAppData.end] & ~(Device::REFERENCED | Device::VALID_ENTRY),
|
||||||
debugger = Debugger::debugger().getAccessFlags(address | myOffset) & ~0x03;
|
debugger = Debugger::debugger().getAccessFlags(address | myOffset) & ~(Device::REFERENCED | Device::VALID_ENTRY);
|
||||||
|
|
||||||
// Any address marked by a manual directive always takes priority
|
// Any address marked by a manual directive always takes priority
|
||||||
if (directive)
|
if (directive)
|
||||||
|
|
|
@ -44,18 +44,20 @@ class Device : public Serializable
|
||||||
|
|
||||||
// The following correspond to specific types that can be set within the
|
// 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
|
// debugger, or specified in a Distella cfg file, and are listed in order
|
||||||
// of decreasing hierarchy
|
// of increasing hierarchy
|
||||||
//
|
//
|
||||||
CODE = 1 << 11, // 0x800, disassemble-able code segments
|
|
||||||
TCODE = 1 << 10, // 0x400, (tentative) disassemble-able code segments
|
|
||||||
GFX = 1 << 9, // 0x200, addresses loaded into GRPx registers
|
|
||||||
PGFX = 1 << 8, // 0x100, addresses loaded into PFx registers
|
|
||||||
COL = 1 << 7, // 0x080, addresses loaded into COLUPx registers
|
|
||||||
PCOL = 1 << 6, // 0x040, addresses loaded into COLUPF register
|
|
||||||
BCOL = 1 << 5, // 0x020, addresses loaded into COLUBK register
|
|
||||||
AUD = 1 << 4, // 0x010, addresses loaded into audio registers
|
|
||||||
DATA = 1 << 3, // 0x008, addresses loaded into registers other than GRPx / PFx / COLUxx, AUDxx
|
|
||||||
ROW = 1 << 2, // 0x004, all other addresses
|
ROW = 1 << 2, // 0x004, all other addresses
|
||||||
|
DATA = 1 << 3, // 0x008, addresses loaded into registers other than GRPx / PFx / COLUxx, AUDxx
|
||||||
|
AUD = 1 << 4, // 0x010, addresses loaded into audio registers
|
||||||
|
BCOL = 1 << 5, // 0x020, addresses loaded into COLUBK register
|
||||||
|
PCOL = 1 << 6, // 0x040, addresses loaded into COLUPF register
|
||||||
|
COL = 1 << 7, // 0x080, addresses loaded into COLUPx registers
|
||||||
|
PGFX = 1 << 8, // 0x100, addresses loaded into PFx registers
|
||||||
|
GFX = 1 << 9, // 0x200, addresses loaded into GRPx registers
|
||||||
|
TCODE = 1 << 10, // 0x400, (tentative) disassemble-able code segments
|
||||||
|
CODE = 1 << 11, // 0x800, disassemble-able code segments
|
||||||
|
// special bits for address
|
||||||
|
HADDR = 1 << 13 | 1 << 14 | 1 << 15, // 0xe000, // highest 3 address bits
|
||||||
// special type for poke()
|
// special type for poke()
|
||||||
WRITE = TCODE // 0x200, address written to
|
WRITE = TCODE // 0x200, address written to
|
||||||
};
|
};
|
||||||
|
|
|
@ -106,7 +106,7 @@ uInt8 System::peek(uInt16 addr, Device::AccessFlags flags)
|
||||||
#ifdef DEBUGGER_SUPPORT
|
#ifdef DEBUGGER_SUPPORT
|
||||||
// Set access type
|
// Set access type
|
||||||
if(access.romAccessBase)
|
if(access.romAccessBase)
|
||||||
*(access.romAccessBase + (addr & PAGE_MASK)) |= flags;
|
*(access.romAccessBase + (addr & PAGE_MASK)) |= (flags | (addr & Device::HADDR));
|
||||||
else
|
else
|
||||||
access.device->setAccessFlags(addr, flags);
|
access.device->setAccessFlags(addr, flags);
|
||||||
#endif
|
#endif
|
||||||
|
@ -134,8 +134,8 @@ void System::poke(uInt16 addr, uInt8 value, Device::AccessFlags flags)
|
||||||
|
|
||||||
#ifdef DEBUGGER_SUPPORT
|
#ifdef DEBUGGER_SUPPORT
|
||||||
// Set access type
|
// Set access type
|
||||||
if (access.romAccessBase)
|
if(access.romAccessBase)
|
||||||
*(access.romAccessBase + (addr & PAGE_MASK)) |= flags;
|
*(access.romAccessBase + (addr & PAGE_MASK)) |= (flags | (addr & Device::HADDR));
|
||||||
else
|
else
|
||||||
access.device->setAccessFlags(addr, flags);
|
access.device->setAccessFlags(addr, flags);
|
||||||
#endif
|
#endif
|
||||||
|
@ -177,7 +177,7 @@ void System::setAccessFlags(uInt16 addr, Device::AccessFlags flags)
|
||||||
const PageAccess& access = getPageAccess(addr);
|
const PageAccess& access = getPageAccess(addr);
|
||||||
|
|
||||||
if(access.romAccessBase)
|
if(access.romAccessBase)
|
||||||
*(access.romAccessBase + (addr & PAGE_MASK)) |= flags;
|
*(access.romAccessBase + (addr & PAGE_MASK)) |= (flags | (addr & Device::HADDR));
|
||||||
else
|
else
|
||||||
access.device->setAccessFlags(addr, flags);
|
access.device->setAccessFlags(addr, flags);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue