Enhance disassembly (determine correct bank offset, preliminary solution for simple 4K bankswitching, e.g. standard Atari)

This commit is contained in:
thrust26 2020-03-31 18:12:38 +02:00
parent 32cd6e2a5b
commit cae2266df0
5 changed files with 89 additions and 37 deletions

View File

@ -238,11 +238,51 @@ string CartDebug::toString()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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
// Also check if the current PC is in the current list
bool bankChanged = myConsole.cartridge().bankChanged();
uInt16 PC = myDebugger.cpuDebug().pc();
int pcline = addressToLine(PC);
bool pcfound = (pcline != -1) && (uInt32(pcline) < myDisassembly.list.size()) &&
(myDisassembly.list[pcline].disasm[0] != '.');
@ -254,8 +294,9 @@ bool CartDebug::disassemble(bool force)
if(changed)
{
// Are we disassembling from ROM or ZP RAM?
BankInfo& info = (PC & 0x1000) ? myBankInfo[getBank(PC)] :
myBankInfo[myBankInfo.size()-1];
BankInfo& info = myBankInfo[bank];
//(PC & 0x1000) ? myBankInfo[getBank(PC)] :
//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
@ -1044,6 +1085,7 @@ string CartDebug::saveDisassembly()
// prepare for switching banks
myConsole.cartridge().unlockBank();
uInt32 origin = 0;
for(int bank = 0; bank < bankCount; ++bank)
{
@ -1055,7 +1097,8 @@ string CartDebug::saveDisassembly()
BankInfo& info = myBankInfo[bank];
// 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
if(info.addressList.size() == 0)
@ -1081,8 +1124,9 @@ string CartDebug::saveDisassembly()
if(bankCount == 1)
buf << " ORG $" << Base::HEX4 << info.offset << "\n\n";
else
buf << " ORG $" << Base::HEX4 << ((0x0000 + bank * 0x1000) & 0xffff) << "\n"
buf << " ORG $" << Base::HEX4 << origin << "\n"
<< " RORG $" << Base::HEX4 << info.offset << "\n\n";
origin += info.size;
// Format in 'distella' style
for(uInt32 i = 0; i < disasm.list.size(); ++i)

View File

@ -94,23 +94,16 @@ class CartDebug : public DebuggerSystem
// Return the base (= non-mirrored) address of the last CPU write
int lastWriteBaseAddress();
// 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
@param force Force a re-disassembly, even if the state hasn't changed
@return True if disassembly changed from previous call, else false
*/
// TODO
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()
*/
@ -278,6 +271,19 @@ class CartDebug : public DebuggerSystem
};
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
// Return whether the search address was actually in the list
bool fillDisassemblyList(BankInfo& bankinfo, uInt16 search);

View File

@ -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),
// they must be included in the other bitfields
uInt16 label = myLabels[address & myAppData.end],
lastbits = label & 0x03,
directive = myDirectives[address & myAppData.end] & ~0x03,
debugger = Debugger::debugger().getAccessFlags(address | myOffset) & ~0x03;
lastbits = label & (Device::REFERENCED | Device::VALID_ENTRY),
directive = myDirectives[address & myAppData.end] & ~(Device::REFERENCED | Device::VALID_ENTRY),
debugger = Debugger::debugger().getAccessFlags(address | myOffset) & ~(Device::REFERENCED | Device::VALID_ENTRY);
// Any address marked by a manual directive always takes priority
if (directive)

View File

@ -44,18 +44,20 @@ class Device : public Serializable
// 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
// 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
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()
WRITE = TCODE // 0x200, address written to
};

View File

@ -106,7 +106,7 @@ uInt8 System::peek(uInt16 addr, Device::AccessFlags flags)
#ifdef DEBUGGER_SUPPORT
// Set access type
if(access.romAccessBase)
*(access.romAccessBase + (addr & PAGE_MASK)) |= flags;
*(access.romAccessBase + (addr & PAGE_MASK)) |= (flags | (addr & Device::HADDR));
else
access.device->setAccessFlags(addr, flags);
#endif
@ -135,7 +135,7 @@ void System::poke(uInt16 addr, uInt8 value, Device::AccessFlags flags)
#ifdef DEBUGGER_SUPPORT
// Set access type
if(access.romAccessBase)
*(access.romAccessBase + (addr & PAGE_MASK)) |= flags;
*(access.romAccessBase + (addr & PAGE_MASK)) |= (flags | (addr & Device::HADDR));
else
access.device->setAccessFlags(addr, flags);
#endif
@ -177,7 +177,7 @@ void System::setAccessFlags(uInt16 addr, Device::AccessFlags flags)
const PageAccess& access = getPageAccess(addr);
if(access.romAccessBase)
*(access.romAccessBase + (addr & PAGE_MASK)) |= flags;
*(access.romAccessBase + (addr & PAGE_MASK)) |= (flags | (addr & Device::HADDR));
else
access.device->setAccessFlags(addr, flags);
}