mirror of https://github.com/stella-emu/stella.git
added access tracking via poke()
code cleanup in DiStella and CartDebug
This commit is contained in:
parent
7b63dc6f22
commit
10e6d483b1
|
@ -1094,10 +1094,12 @@ string CartDebug::saveDisassembly()
|
|||
if(myReserved.TIARead[addr] && ourTIAMnemonicR[addr])
|
||||
out << ALIGN(16) << ourTIAMnemonicR[addr] << "= $"
|
||||
<< Base::HEX2 << right << addr << " ; (R)\n";
|
||||
out << "\n";
|
||||
for(uInt16 addr = 0x00; addr <= 0x3F; ++addr)
|
||||
if(myReserved.TIAWrite[addr] && ourTIAMnemonicW[addr])
|
||||
out << ALIGN(16) << ourTIAMnemonicW[addr] << "= $"
|
||||
<< Base::HEX2 << right << addr << " ; (W)\n";
|
||||
out << "\n";
|
||||
for(uInt16 addr = 0x00; addr <= 0x17; ++addr)
|
||||
if(myReserved.IOReadWrite[addr] && ourIOMnemonic[addr])
|
||||
out << ALIGN(16) << ourIOMnemonic[addr] << "= $"
|
||||
|
@ -1109,18 +1111,40 @@ string CartDebug::saveDisassembly()
|
|||
addrUsed = addrUsed || myReserved.ZPRAM[addr-0x80];
|
||||
if(addrUsed)
|
||||
{
|
||||
bool addLine = false;
|
||||
out << "\n\n;-----------------------------------------------------------\n"
|
||||
<< "; RIOT RAM (zero-page) labels\n"
|
||||
<< ";-----------------------------------------------------------\n\n";
|
||||
for(uInt16 addr = 0x80; addr <= 0xFF; ++addr)
|
||||
{
|
||||
for (uInt16 addr = 0x80; addr <= 0xFF; ++addr) {
|
||||
if (myReserved.ZPRAM[addr - 0x80] &&
|
||||
myUserLabels.find(addr) == myUserLabels.end())
|
||||
{
|
||||
myUserLabels.find(addr) == myUserLabels.end()) {
|
||||
if (addLine)
|
||||
out << "\n";
|
||||
out << ALIGN(16) << ourZPMnemonic[addr - 0x80] << "= $"
|
||||
<< Base::HEX2 << right << (addr) << "\n";
|
||||
addLine = false;
|
||||
}/* else if (Debugger::debugger().getAccessFlags(addr) & DATA) {
|
||||
if (addLine)
|
||||
out << "\n";
|
||||
out << ALIGN(16) << ourZPMnemonic[addr - 0x80] << "= $"
|
||||
<< Base::HEX2 << right << (addr) << "; (*)\n";
|
||||
addLine = false;
|
||||
}*/ else
|
||||
addLine = true;
|
||||
}
|
||||
}
|
||||
for (uInt16 addr = 0x1000; addr <= 0x10FF; ++addr)
|
||||
out << Debugger::debugger().getAccessFlags(addr) << "\n";
|
||||
/*
|
||||
; $93
|
||||
; $94
|
||||
; §94(*)
|
||||
; $96
|
||||
; §97(*)
|
||||
; $98
|
||||
; $99
|
||||
; $9a
|
||||
; $9b(*)
|
||||
*/
|
||||
}
|
||||
|
||||
if(myReserved.Label.size() > 0)
|
||||
|
|
|
@ -317,7 +317,6 @@ class CartDebug : public DebuggerSystem
|
|||
bool IOReadWrite[24];
|
||||
bool ZPRAM[128];
|
||||
AddrToLabel Label;
|
||||
bool breakFound;
|
||||
};
|
||||
ReservedEquates myReserved;
|
||||
|
||||
|
|
|
@ -37,41 +37,16 @@ DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
|
|||
{
|
||||
bool resolve_code = mySettings.resolveCode;
|
||||
CartDebug::AddressList& debuggerAddresses = info.addressList;
|
||||
auto it = debuggerAddresses.cbegin();
|
||||
uInt16 start = *it++;
|
||||
uInt16 start = *debuggerAddresses.cbegin();
|
||||
|
||||
myOffset = info.offset;
|
||||
if (start & 0x1000) {
|
||||
if (info.size == 4096) // 4K ROM space
|
||||
{
|
||||
/*============================================
|
||||
The offset is the address where the code segment
|
||||
starts. For a 4K game, it is usually 0xf000.
|
||||
|
||||
Example:
|
||||
Start address = $D973, so therefore
|
||||
Offset to code = $D000
|
||||
Code range = $D000-$DFFF
|
||||
=============================================*/
|
||||
info.start = myAppData.start = 0x0000;
|
||||
info.end = myAppData.end = 0x0FFF;
|
||||
|
||||
// Keep previous offset; it may be different between banks
|
||||
if (info.offset == 0)
|
||||
info.offset = myOffset = (start - (start % 0x1000));
|
||||
} else // 2K ROM space (also includes 'Sub2K' ROMs)
|
||||
{
|
||||
/*============================================
|
||||
The offset is the address where the code segment
|
||||
starts. For a 2K game, it is usually 0xf800,
|
||||
but can also be 0xf000.
|
||||
=============================================*/
|
||||
info.start = myAppData.start = 0x0000;
|
||||
info.end = myAppData.end = info.size - 1;
|
||||
// Keep previous offset; it may be different between banks
|
||||
if (info.offset == 0)
|
||||
info.offset = myOffset = (start - (start % info.size));
|
||||
}
|
||||
} else // ZP RAM
|
||||
{
|
||||
} else { // ZP RAM
|
||||
// For now, we assume all accesses below $1000 are zero-page
|
||||
info.start = myAppData.start = 0x0080;
|
||||
info.end = myAppData.end = 0x00FF;
|
||||
|
@ -84,116 +59,13 @@ DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
|
|||
|
||||
memset(myLabels, 0, 0x1000);
|
||||
memset(myDirectives, 0, 0x1000);
|
||||
myReserved.breakFound = false;
|
||||
|
||||
while (!myAddressQueue.empty())
|
||||
myAddressQueue.pop();
|
||||
myAddressQueue.push(start);
|
||||
|
||||
// Process any directives first, as they override automatic code determination
|
||||
processDirectives(info.directiveList);
|
||||
|
||||
if (resolve_code) {
|
||||
// After we've disassembled from all addresses in the address list,
|
||||
// use all access points determined by Stella during emulation
|
||||
int codeAccessPoint = 0;
|
||||
|
||||
// Sometimes we get a circular reference, in that processing a certain
|
||||
// PC address leads us to a sequence of addresses that end up trying
|
||||
// to process the same address again. We detect such consecutive PC
|
||||
// addresses and only process the first one
|
||||
uInt16 lastPC = 0;
|
||||
bool duplicateFound = false;
|
||||
int count = 0;
|
||||
|
||||
|
||||
uInt8 flags = Debugger::debugger().getAccessFlags(0xf52c);
|
||||
//checkBit(0xf52c, CartDebug::DATA);
|
||||
|
||||
while (!(myAddressQueue.empty() || duplicateFound)) {
|
||||
|
||||
/*if (++count == 2)
|
||||
break;*/
|
||||
|
||||
uInt16 pcBeg = myPC = lastPC = myAddressQueue.front();
|
||||
|
||||
myAddressQueue.pop();
|
||||
//disasm(myPC, 1);
|
||||
disasmPass1(myPC);
|
||||
|
||||
if (pcBeg <= myPCEnd) {
|
||||
// Tentatively mark all addresses in the range as CODE
|
||||
// Note that this is a 'best-effort' approach, since
|
||||
// Distella will normally keep going until the end of the
|
||||
// range or branch is encountered
|
||||
// However, addresses *specifically* marked as DATA/GFX/PGFX
|
||||
// in the emulation core indicate that the CODE range has finished
|
||||
// Therefore, we stop at the first such address encountered
|
||||
for (uInt32 k = pcBeg; k <= myPCEnd; k++) {
|
||||
/*if (Debugger::debugger().getAccessFlags(k) &
|
||||
(CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX)) {
|
||||
myPCEnd = k - 1;
|
||||
if (k == 0xf5c6)
|
||||
k = k;
|
||||
break;
|
||||
}*/
|
||||
mark(k, CartDebug::CODE);
|
||||
}
|
||||
}
|
||||
|
||||
// When we get to this point, all addresses have been processed
|
||||
// starting from the initial one in the address list
|
||||
// If so, process the next one in the list that hasn't already
|
||||
// been marked as CODE
|
||||
// If it *has* been marked, it can be removed from consideration
|
||||
// in all subsequent passes
|
||||
//
|
||||
// Once the address list has been exhausted, we process all addresses
|
||||
// determined during emulation to represent code, which *haven't* already
|
||||
// been considered
|
||||
//
|
||||
// Note that we can't simply add all addresses right away, since
|
||||
// the processing of a single address can cause others to be added in
|
||||
// the ::disasm method
|
||||
// All of these have to be exhausted before considering a new address
|
||||
while (myAddressQueue.empty() && it != debuggerAddresses.end()) {
|
||||
uInt16 addr = *it;
|
||||
|
||||
if (!checkBit(addr - myOffset, CartDebug::CODE)) {
|
||||
myAddressQueue.push(addr);
|
||||
++it;
|
||||
} else // remove this address, it is redundant
|
||||
it = debuggerAddresses.erase(it);
|
||||
}
|
||||
|
||||
// Stella itself can provide hints on whether an address has ever
|
||||
// been referenced as CODE
|
||||
while (myAddressQueue.empty() && codeAccessPoint <= myAppData.end) {
|
||||
if ((Debugger::debugger().getAccessFlags(codeAccessPoint + myOffset) & CartDebug::CODE)
|
||||
&& !(myLabels[codeAccessPoint & myAppData.end] & CartDebug::CODE)) {
|
||||
myAddressQueue.push(codeAccessPoint + myOffset);
|
||||
++codeAccessPoint;
|
||||
break;
|
||||
}
|
||||
++codeAccessPoint;
|
||||
}
|
||||
duplicateFound = !myAddressQueue.empty() && (myAddressQueue.front() == lastPC); // TODO: check!
|
||||
} // while
|
||||
|
||||
for (int k = 0; k <= myAppData.end; k++) {
|
||||
// Let the emulation core know about tentative code
|
||||
if (checkBit(k, CartDebug::CODE) &&
|
||||
!(Debugger::debugger().getAccessFlags(k + myOffset) & CartDebug::CODE)
|
||||
&& myOffset != 0) {
|
||||
Debugger::debugger().setAccessFlags(k + myOffset, CartDebug::TCODE);
|
||||
}
|
||||
|
||||
// Must be ROW / unused bytes
|
||||
if (!checkBit(k, CartDebug::CODE | CartDebug::GFX |
|
||||
CartDebug::PGFX | CartDebug::DATA))
|
||||
mark(k + myOffset, CartDebug::ROW);
|
||||
}
|
||||
} // resolve code
|
||||
if (resolve_code)
|
||||
// First pass
|
||||
disasmPass1(info.addressList);
|
||||
|
||||
// Second pass
|
||||
disasm(myOffset, 2);
|
||||
|
@ -217,10 +89,6 @@ DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
|
|||
|
||||
// Third pass
|
||||
disasm(myOffset, 3);
|
||||
|
||||
for (uInt16 addr = 0x80; addr <= 0xFF; ++addr) {
|
||||
//myReserved.ZPRAM[addr - 0x80]
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -690,7 +558,110 @@ void DiStella::disasm(uInt32 distart, int pass)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DiStella::disasmPass1(uInt32 distart)
|
||||
void DiStella::disasmPass1(CartDebug::AddressList& debuggerAddresses)
|
||||
{
|
||||
auto it = debuggerAddresses.cbegin();
|
||||
uInt16 start = *it++;
|
||||
|
||||
// After we've disassembled from all addresses in the address list,
|
||||
// use all access points determined by Stella during emulation
|
||||
int codeAccessPoint = 0;
|
||||
|
||||
// Sometimes we get a circular reference, in that processing a certain
|
||||
// PC address leads us to a sequence of addresses that end up trying
|
||||
// to process the same address again. We detect such consecutive PC
|
||||
// addresses and only process the first one
|
||||
uInt16 lastPC = 0;
|
||||
bool duplicateFound = false;
|
||||
int count = 0;
|
||||
|
||||
while (!myAddressQueue.empty())
|
||||
myAddressQueue.pop();
|
||||
myAddressQueue.push(start);
|
||||
|
||||
while (!(myAddressQueue.empty() || duplicateFound)) {
|
||||
uInt16 pcBeg = myPC = lastPC = myAddressQueue.front();
|
||||
myAddressQueue.pop();
|
||||
|
||||
disasmFromAddress(myPC);
|
||||
|
||||
if (pcBeg <= myPCEnd) {
|
||||
// Tentatively mark all addresses in the range as CODE
|
||||
// Note that this is a 'best-effort' approach, since
|
||||
// Distella will normally keep going until the end of the
|
||||
// range or branch is encountered
|
||||
// However, addresses *specifically* marked as DATA/GFX/PGFX
|
||||
// in the emulation core indicate that the CODE range has finished
|
||||
// Therefore, we stop at the first such address encountered
|
||||
for (uInt32 k = pcBeg; k <= myPCEnd; k++) {
|
||||
if (checkBits(k, CartDebug::CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX,
|
||||
CartDebug::CODE)) {
|
||||
//if (Debugger::debugger().getAccessFlags(k) &
|
||||
// (CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX)) {
|
||||
Uint8 flags = Debugger::debugger().getAccessFlags(k);
|
||||
myPCEnd = k - 1;
|
||||
break;
|
||||
}
|
||||
mark(k, CartDebug::CODE);
|
||||
}
|
||||
}
|
||||
|
||||
// When we get to this point, all addresses have been processed
|
||||
// starting from the initial one in the address list
|
||||
// If so, process the next one in the list that hasn't already
|
||||
// been marked as CODE
|
||||
// If it *has* been marked, it can be removed from consideration
|
||||
// in all subsequent passes
|
||||
//
|
||||
// Once the address list has been exhausted, we process all addresses
|
||||
// determined during emulation to represent code, which *haven't* already
|
||||
// been considered
|
||||
//
|
||||
// Note that we can't simply add all addresses right away, since
|
||||
// the processing of a single address can cause others to be added in
|
||||
// the ::disasm method
|
||||
// All of these have to be exhausted before considering a new address
|
||||
while (myAddressQueue.empty() && it != debuggerAddresses.end()) {
|
||||
uInt16 addr = *it;
|
||||
|
||||
if (!checkBit(addr - myOffset, CartDebug::CODE)) {
|
||||
myAddressQueue.push(addr);
|
||||
++it;
|
||||
} else // remove this address, it is redundant
|
||||
it = debuggerAddresses.erase(it);
|
||||
}
|
||||
|
||||
// Stella itself can provide hints on whether an address has ever
|
||||
// been referenced as CODE
|
||||
while (myAddressQueue.empty() && codeAccessPoint <= myAppData.end) {
|
||||
if ((Debugger::debugger().getAccessFlags(codeAccessPoint + myOffset) & CartDebug::CODE)
|
||||
&& !(myLabels[codeAccessPoint & myAppData.end] & CartDebug::CODE)) {
|
||||
myAddressQueue.push(codeAccessPoint + myOffset);
|
||||
++codeAccessPoint;
|
||||
break;
|
||||
}
|
||||
++codeAccessPoint;
|
||||
}
|
||||
duplicateFound = !myAddressQueue.empty() && (myAddressQueue.front() == lastPC); // TODO: check!
|
||||
} // while
|
||||
|
||||
for (int k = 0; k <= myAppData.end; k++) {
|
||||
// Let the emulation core know about tentative code
|
||||
if (checkBit(k, CartDebug::CODE) &&
|
||||
!(Debugger::debugger().getAccessFlags(k + myOffset) & CartDebug::CODE)
|
||||
&& myOffset != 0) {
|
||||
Debugger::debugger().setAccessFlags(k + myOffset, CartDebug::TCODE);
|
||||
}
|
||||
|
||||
// Must be ROW / unused bytes
|
||||
if (!checkBit(k, CartDebug::CODE | CartDebug::GFX |
|
||||
CartDebug::PGFX | CartDebug::DATA))
|
||||
mark(k + myOffset, CartDebug::ROW);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DiStella::disasmFromAddress(uInt32 distart)
|
||||
{
|
||||
uInt8 opcode, d1;
|
||||
uInt16 ad;
|
||||
|
@ -819,11 +790,10 @@ void DiStella::disasmPass1(uInt32 distart)
|
|||
|
||||
// mark BRK vector
|
||||
if (opcode == 0x00) {
|
||||
if (!myReserved.breakFound) {
|
||||
ad = Debugger::debugger().dpeek(0xfffe, CartDebug::DATA);
|
||||
if (!checkBit(ad - myOffset, CartDebug::CODE, false)) {
|
||||
myAddressQueue.push(ad);
|
||||
mark(ad, CartDebug::CODE);
|
||||
myReserved.breakFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -82,7 +82,8 @@ class DiStella
|
|||
|
||||
// These functions are part of the original Distella code
|
||||
void disasm(uInt32 distart, int pass);
|
||||
void disasmPass1(uInt32 distart);
|
||||
void disasmPass1(CartDebug::AddressList& debuggerAddresses);
|
||||
void disasmFromAddress(uInt32 distart);
|
||||
|
||||
bool check_range(uInt16 start, uInt16 end) const;
|
||||
int mark(uInt32 address, uInt8 mask, bool directive = false);
|
||||
|
|
|
@ -155,7 +155,7 @@ inline void M6502::poke(uInt16 address, uInt8 value)
|
|||
}
|
||||
#endif // DEBUGGER_SUPPORT
|
||||
|
||||
mySystem->poke(address, value);
|
||||
mySystem->poke(address, value, CartDebug::DATA); // can't think of anything else but data
|
||||
myLastPokeAddress = address;
|
||||
}
|
||||
|
||||
|
|
|
@ -137,11 +137,19 @@ uInt8 System::peek(uInt16 addr, uInt8 flags)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void System::poke(uInt16 addr, uInt8 value)
|
||||
void System::poke(uInt16 addr, uInt8 value, uInt8 flags)
|
||||
{
|
||||
uInt16 page = (addr & ADDRESS_MASK) >> PAGE_SHIFT;
|
||||
const PageAccess& access = myPageAccessTable[page];
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
// Set access type
|
||||
if (access.codeAccessBase)
|
||||
*(access.codeAccessBase + (addr & PAGE_MASK)) |= flags;
|
||||
else
|
||||
access.device->setAccessFlags(addr, flags);
|
||||
#endif
|
||||
|
||||
// See if this page uses direct accessing or not
|
||||
if(access.directPokeBase)
|
||||
{
|
||||
|
|
|
@ -210,7 +210,7 @@ class System : public Serializable
|
|||
@param address The address where the value should be stored
|
||||
@param value The value to be stored at the address
|
||||
*/
|
||||
void poke(uInt16 address, uInt8 value);
|
||||
void poke(uInt16 address, uInt8 value, uInt8 flags = 0);
|
||||
|
||||
/**
|
||||
Lock/unlock the data bus. When the bus is locked, peek() and
|
||||
|
|
Loading…
Reference in New Issue