From 10e6d483b16c6d525d357a306283fb07da923b9a Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 16 Sep 2017 08:54:32 +0200 Subject: [PATCH] added access tracking via poke() code cleanup in DiStella and CartDebug --- src/debugger/CartDebug.cxx | 52 ++++++-- src/debugger/CartDebug.hxx | 1 - src/debugger/DiStella.cxx | 262 ++++++++++++++++--------------------- src/debugger/DiStella.hxx | 3 +- src/emucore/M6502.cxx | 2 +- src/emucore/System.cxx | 10 +- src/emucore/System.hxx | 2 +- 7 files changed, 167 insertions(+), 165 deletions(-) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index d22fe3426..b5a6bae5f 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -1092,35 +1092,59 @@ string CartDebug::saveDisassembly() << ";-----------------------------------------------------------\n\n"; for(uInt16 addr = 0x00; addr <= 0x0F; ++addr) if(myReserved.TIARead[addr] && ourTIAMnemonicR[addr]) - out << ALIGN(16) << ourTIAMnemonicR[addr] << "= $" - << Base::HEX2 << right << addr << " ; (R)\n"; + 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 << 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] << "= $" + out << ALIGN(16) << ourIOMnemonic[addr] << "= $" << Base::HEX4 << right << (addr+0x280) << "\n"; } addrUsed = false; - for(uInt16 addr = 0x80; addr <= 0xFF; ++addr) + for(uInt16 addr = 0x80; addr <= 0xFF; ++addr) 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) - { - if(myReserved.ZPRAM[addr-0x80] && - myUserLabels.find(addr) == myUserLabels.end()) - { - out << ALIGN(16) << ourZPMnemonic[addr-0x80] << "= $" - << Base::HEX2 << right << (addr) << "\n"; - } + for (uInt16 addr = 0x80; addr <= 0xFF; ++addr) { + if (myReserved.ZPRAM[addr - 0x80] && + 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) diff --git a/src/debugger/CartDebug.hxx b/src/debugger/CartDebug.hxx index 804b27a05..4a8b0b965 100644 --- a/src/debugger/CartDebug.hxx +++ b/src/debugger/CartDebug.hxx @@ -317,7 +317,6 @@ class CartDebug : public DebuggerSystem bool IOReadWrite[24]; bool ZPRAM[128]; AddrToLabel Label; - bool breakFound; }; ReservedEquates myReserved; diff --git a/src/debugger/DiStella.cxx b/src/debugger/DiStella.cxx index 128000bef..e191256a1 100644 --- a/src/debugger/DiStella.cxx +++ b/src/debugger/DiStella.cxx @@ -36,42 +36,17 @@ DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list, myDirectives(directives) { bool resolve_code = mySettings.resolveCode; - CartDebug::AddressList& debuggerAddresses = info.addressList; - auto it = debuggerAddresses.cbegin(); - uInt16 start = *it++; + CartDebug::AddressList& debuggerAddresses = info.addressList; + 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; + 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); + ad = Debugger::debugger().dpeek(0xfffe, CartDebug::DATA); + if (!checkBit(ad - myOffset, CartDebug::CODE, false)) { myAddressQueue.push(ad); mark(ad, CartDebug::CODE); - myReserved.breakFound = true; } } diff --git a/src/debugger/DiStella.hxx b/src/debugger/DiStella.hxx index 0ea754e5b..491726b8a 100644 --- a/src/debugger/DiStella.hxx +++ b/src/debugger/DiStella.hxx @@ -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); diff --git a/src/emucore/M6502.cxx b/src/emucore/M6502.cxx index 35786fc08..cb9e94cd0 100644 --- a/src/emucore/M6502.cxx +++ b/src/emucore/M6502.cxx @@ -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; } diff --git a/src/emucore/System.cxx b/src/emucore/System.cxx index 1833f7da7..820d28c31 100644 --- a/src/emucore/System.cxx +++ b/src/emucore/System.cxx @@ -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) { diff --git a/src/emucore/System.hxx b/src/emucore/System.hxx index eedc3ed64..ddde896b3 100644 --- a/src/emucore/System.hxx +++ b/src/emucore/System.hxx @@ -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