diff --git a/.gitignore b/.gitignore index 5524d520a..8e6d3e86a 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,5 @@ src/**/*.psess src/**/*.vspx src/**/**.pdb Stella.xcscheme +src/tools/fonts/* + diff --git a/Changes.txt b/Changes.txt index 5d8291b4f..5dbc6047e 100644 --- a/Changes.txt +++ b/Changes.txt @@ -13,11 +13,16 @@ =========================================================================== 6.1 to 6.2: (??? ??, 2020) - * Paddle centering and sensitivity can be adjusted now - * High scores: Score addresses, game variation etc. can be defined for a - game. This allows the user to save high scores for these games. For each - game and variation, the top 10 scores can be saved. + * Added that paddle centering and sensitivity can be adjusted now (TOOD: Doc) + + * Added high scores: Score addresses, game variation etc. can be defined for + a game. This allows the user to save high scores for these games. For each + game and variation, the top 10 scores can be saved. (TOOD: Doc) + + * Added displaying last write address in debugger. (TOOD: Doc) + + * Added detection of color data in DiStella. (TOOD: Doc) 6.0.2 to 6.1: (March 22, 2020) diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx index e7cc60024..06333b13c 100644 --- a/src/common/bspf.hxx +++ b/src/common/bspf.hxx @@ -84,6 +84,7 @@ using ByteArray = std::vector; using ShortArray = std::vector; using StringList = std::vector; using ByteBuffer = std::unique_ptr; // NOLINT +using WordBuffer = std::unique_ptr; // NOLINT // We use KB a lot; let's make a literal for it constexpr uInt32 operator "" _KB(unsigned long long size) diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index 5d2654764..6199bb306 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -900,6 +900,21 @@ string CartDebug::loadConfigFile() buf >> hex >> start >> hex >> end; addDirective(CartDebug::PGFX, start, end, currentbank); } + else if(BSPF::startsWithIgnoreCase(directive, "COL")) + { + buf >> hex >> start >> hex >> end; + addDirective(CartDebug::COL, start, end, currentbank); + } + else if(BSPF::startsWithIgnoreCase(directive, "PCOL")) + { + buf >> hex >> start >> hex >> end; + addDirective(CartDebug::PCOL, start, end, currentbank); + } + else if(BSPF::startsWithIgnoreCase(directive, "BCOL")) + { + buf >> hex >> start >> hex >> end; + addDirective(CartDebug::BCOL, start, end, currentbank); + } else if(BSPF::startsWithIgnoreCase(directive, "DATA")) { buf >> hex >> start >> hex >> end; @@ -966,6 +981,25 @@ string CartDebug::saveConfigFile() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::saveDisassembly() { + string NTSC_COLOR[16] = { + "BLACK", "YELLOW", "BROWN", "ORANGE", + "RED", "MAUVE", "VIOLET", "PURPLE", + "BLUE", "BLUE_CYAN", "CYAN", "CYAN_GREEN", + "GREEN", "GREEN_YELLOW", "GREEN_BEIGE", "BEIGE" + }; + string PAL_COLOR[16] = { + "BLACK0", "BLACK1", "YELLOW", "GREEN_YELLOW", + "ORANGE", "GREEN", "RED", "CYAN_GREEN", + "MAUVE", "CYAN", "VIOLET", "BLUE_CYAN", + "PURPLE", "BLUE", "BLACKE", "BLACKF" + }; + string SECAM_COLOR[8] = { + "BLACK", "BLUE", "RED", "PURPLE", + "GREEN", "CYAN", "YELLOW", "WHITE" + }; + bool isNTSC = myConsole.timing() == ConsoleTiming::ntsc; + bool isPAL = myConsole.timing() == ConsoleTiming::pal; + if(myDisasmFile == "") { const string& propsname = @@ -1064,6 +1098,18 @@ string CartDebug::saveDisassembly() buf << ALIGN(13) << "|" << "$" << Base::HEX4 << tag.address << " (P)"; break; } + case CartDebug::COL: + buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 12) << "; $" << Base::HEX4 << tag.address << " (Px)"; + break; + + case CartDebug::PCOL: + buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 12) << "; $" << Base::HEX4 << tag.address << " (PF)"; + break; + + case CartDebug::BCOL: + buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 12) << "; $" << Base::HEX4 << tag.address << " (BK)"; + break; + case CartDebug::DATA: { buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 8 * 4 - 1) << "; $" << Base::HEX4 << tag.address << " (D)"; @@ -1097,6 +1143,27 @@ string CartDebug::saveDisassembly() << "; ! = page crossed, 1 cycle penalty\n" << "\n processor 6502\n\n"; + out << "\n;-----------------------------------------------------------\n" + << "; Color constants\n" + << ";-----------------------------------------------------------\n\n"; + + if(isNTSC) + { + for(int i = 0; i < 16; ++i) + out << ALIGN(16) << NTSC_COLOR[i] << " = $" << Base::HEX2 << (i << 4) << "\n"; + } + else if(isPAL) + { + for(int i = 0; i < 16; ++i) + out << ALIGN(16) << PAL_COLOR[i] << " = $" << Base::HEX2 << (i << 4) << "\n"; + } + else + { + for(int i = 0; i < 8; ++i) + out << ALIGN(16) << SECAM_COLOR[i] << " = $" << Base::HEX1 << (i << 1) << "\n"; + } + out << "\n"; + bool addrUsed = false; for(uInt16 addr = 0x00; addr <= 0x0F; ++addr) addrUsed = addrUsed || myReserved.TIARead[addr] || (mySystem.getAccessFlags(addr) & WRITE); @@ -1104,6 +1171,7 @@ string CartDebug::saveDisassembly() addrUsed = addrUsed || myReserved.TIAWrite[addr] || (mySystem.getAccessFlags(addr) & DATA); for(uInt16 addr = 0x00; addr <= 0x17; ++addr) addrUsed = addrUsed || myReserved.IOReadWrite[addr]; + if(addrUsed) { out << "\n;-----------------------------------------------------------\n" @@ -1393,7 +1461,7 @@ void CartDebug::addressTypeAsString(ostream& buf, uInt16 addr) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CartDebug::DisasmType CartDebug::disasmTypeAbsolute(uInt8 flags) const +CartDebug::DisasmType CartDebug::disasmTypeAbsolute(uInt16 flags) const { if(flags & CartDebug::CODE) return CartDebug::CODE; @@ -1403,6 +1471,12 @@ CartDebug::DisasmType CartDebug::disasmTypeAbsolute(uInt8 flags) const return CartDebug::GFX; else if(flags & CartDebug::PGFX) return CartDebug::PGFX; + else if(flags & CartDebug::COL) + return CartDebug::COL; + else if(flags & CartDebug::PCOL) + return CartDebug::PCOL; + else if(flags & CartDebug::BCOL) + return CartDebug::BCOL; else if(flags & CartDebug::DATA) return CartDebug::DATA; else if(flags & CartDebug::ROW) @@ -1420,6 +1494,9 @@ void CartDebug::disasmTypeAsString(ostream& buf, DisasmType type) const case CartDebug::TCODE: buf << "TCODE"; break; case CartDebug::GFX: buf << "GFX"; break; case CartDebug::PGFX: buf << "PGFX"; break; + case CartDebug::COL: buf << "COL"; break; + case CartDebug::PCOL: buf << "PCOL"; break; + case CartDebug::BCOL: buf << "BCOL"; break; case CartDebug::DATA: buf << "DATA"; break; case CartDebug::ROW: buf << "ROW"; break; case CartDebug::REFERENCED: @@ -1429,7 +1506,7 @@ void CartDebug::disasmTypeAsString(ostream& buf, DisasmType type) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartDebug::disasmTypeAsString(ostream& buf, uInt8 flags) const +void CartDebug::disasmTypeAsString(ostream& buf, uInt16 flags) const { if(flags) { @@ -1441,6 +1518,12 @@ void CartDebug::disasmTypeAsString(ostream& buf, uInt8 flags) const buf << "GFX "; if(flags & CartDebug::PGFX) buf << "PGFX "; + if(flags & CartDebug::COL) + buf << "COL "; + if(flags & CartDebug::PCOL) + buf << "PCOL "; + if(flags & CartDebug::BCOL) + buf << "BCOL "; if(flags & CartDebug::DATA) buf << "DATA "; if(flags & CartDebug::ROW) diff --git a/src/debugger/CartDebug.hxx b/src/debugger/CartDebug.hxx index 3561b3d3e..e331cc585 100644 --- a/src/debugger/CartDebug.hxx +++ b/src/debugger/CartDebug.hxx @@ -60,14 +60,17 @@ class CartDebug : public DebuggerSystem // debugger, or specified in a Distella cfg file, and are listed in order // of decreasing hierarchy // - CODE = 1 << 7, // 0x80, disassemble-able code segments - TCODE = 1 << 6, // 0x40, (tentative) disassemble-able code segments - GFX = 1 << 5, // 0x20, addresses loaded into GRPx registers - PGFX = 1 << 4, // 0x10, addresses loaded into PFx registers - DATA = 1 << 3, // 0x08, addresses loaded into registers other than GRPx / PFx - ROW = 1 << 2, // 0x04, all other addresses + CODE = 1 << 10, // 0x400, disassemble-able code segments + TCODE = 1 << 9, // 0x200, (tentative) disassemble-able code segments + GFX = 1 << 8, // 0x100, addresses loaded into GRPx registers + PGFX = 1 << 7, // 0x080, addresses loaded into PFx registers + COL = 1 << 6, // 0x040, addresses loaded into COLUPx registers + PCOL = 1 << 5, // 0x010, addresses loaded into COLUPF register + BCOL = 1 << 4, // 0x010, addresses loaded into COLUBK register + DATA = 1 << 3, // 0x008, addresses loaded into registers other than GRPx / PFx + ROW = 1 << 2, // 0x004, all other addresses // special type for poke() - WRITE = TCODE // 0x40, address written to + WRITE = TCODE // 0x200, address written to }; struct DisassemblyTag { DisasmType type{NONE}; @@ -263,7 +266,7 @@ class CartDebug : public DebuggerSystem using LabelToAddr = std::map>; - using AddrTypeArray = std::array; + using AddrTypeArray = std::array; struct DirectiveTag { DisasmType type{NONE}; @@ -305,14 +308,14 @@ class CartDebug : public DebuggerSystem void getBankDirectives(ostream& buf, BankInfo& info) const; // Get disassembly enum type from 'flags', taking precendence into account - DisasmType disasmTypeAbsolute(uInt8 flags) const; + DisasmType disasmTypeAbsolute(uInt16 flags) const; // Convert disassembly enum type to corresponding string and append to buf void disasmTypeAsString(ostream& buf, DisasmType type) const; // Convert all disassembly types in 'flags' to corresponding string and // append to buf - void disasmTypeAsString(ostream& buf, uInt8 flags) const; + void disasmTypeAsString(ostream& buf, uInt16 flags) const; private: const OSystem& myOSystem; diff --git a/src/debugger/Debugger.cxx b/src/debugger/Debugger.cxx index 8cdd525de..ce712bf1f 100644 --- a/src/debugger/Debugger.cxx +++ b/src/debugger/Debugger.cxx @@ -440,19 +440,19 @@ bool Debugger::writeTrap(uInt16 t) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 Debugger::peek(uInt16 addr, uInt8 flags) +uInt8 Debugger::peek(uInt16 addr, uInt16 flags) { return mySystem.peek(addr, flags); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 Debugger::dpeek(uInt16 addr, uInt8 flags) +uInt16 Debugger::dpeek(uInt16 addr, uInt16 flags) { return uInt16(mySystem.peek(addr, flags) | (mySystem.peek(addr+1, flags) << 8)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Debugger::poke(uInt16 addr, uInt8 value, uInt8 flags) +void Debugger::poke(uInt16 addr, uInt8 value, uInt16 flags) { mySystem.poke(addr, value, flags); } @@ -464,13 +464,13 @@ M6502& Debugger::m6502() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int Debugger::peekAsInt(int addr, uInt8 flags) +int Debugger::peekAsInt(int addr, uInt16 flags) { return mySystem.peek(uInt16(addr), flags); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int Debugger::dpeekAsInt(int addr, uInt8 flags) +int Debugger::dpeekAsInt(int addr, uInt16 flags) { return mySystem.peek(uInt16(addr), flags) | (mySystem.peek(uInt16(addr+1), flags) << 8); @@ -483,7 +483,7 @@ int Debugger::getAccessFlags(uInt16 addr) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Debugger::setAccessFlags(uInt16 addr, uInt8 flags) +void Debugger::setAccessFlags(uInt16 addr, uInt16 flags) { mySystem.setAccessFlags(addr, flags); } diff --git a/src/debugger/Debugger.hxx b/src/debugger/Debugger.hxx index 7e9ad0bc1..738404552 100644 --- a/src/debugger/Debugger.hxx +++ b/src/debugger/Debugger.hxx @@ -243,18 +243,18 @@ class Debugger : public DialogContainer static Debugger& debugger() { return *myStaticDebugger; } /** Convenience methods to access peek/poke from System */ - uInt8 peek(uInt16 addr, uInt8 flags = 0); - uInt16 dpeek(uInt16 addr, uInt8 flags = 0); - void poke(uInt16 addr, uInt8 value, uInt8 flags = 0); + uInt8 peek(uInt16 addr, uInt16 flags = 0); + uInt16 dpeek(uInt16 addr, uInt16 flags = 0); + void poke(uInt16 addr, uInt8 value, uInt16 flags = 0); /** Convenience method to access the 6502 from System */ M6502& m6502() const; /** These are now exposed so Expressions can use them. */ - int peekAsInt(int addr, uInt8 flags = 0); - int dpeekAsInt(int addr, uInt8 flags = 0); + int peekAsInt(int addr, uInt16 flags = 0); + int dpeekAsInt(int addr, uInt16 flags = 0); int getAccessFlags(uInt16 addr) const; - void setAccessFlags(uInt16 addr, uInt8 flags); + void setAccessFlags(uInt16 addr, uInt16 flags); uInt32 getBaseAddress(uInt32 addr, bool read); diff --git a/src/debugger/DiStella.cxx b/src/debugger/DiStella.cxx index 9ee79c61e..235b2d9da 100644 --- a/src/debugger/DiStella.cxx +++ b/src/debugger/DiStella.cxx @@ -125,14 +125,25 @@ void DiStella::disasm(uInt32 distart, int pass) goto FIX_LAST; if (checkBits(myPC, CartDebug::GFX | CartDebug::PGFX, - CartDebug::CODE)) { + CartDebug::CODE)) + { if (pass == 2) mark(myPC + myOffset, CartDebug::VALID_ENTRY); if (pass == 3) outputGraphics(); ++myPC; + } else if (checkBits(myPC, CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL, + CartDebug::CODE | CartDebug::GFX | CartDebug::PGFX)) + { + if (pass == 2) + mark(myPC + myOffset, CartDebug::VALID_ENTRY); + if (pass == 3) + outputColors(); + ++myPC; } else if (checkBits(myPC, CartDebug::DATA, - CartDebug::CODE | CartDebug::GFX | CartDebug::PGFX)) { + CartDebug::CODE | CartDebug::GFX | CartDebug::PGFX | + CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL)) + { if (pass == 2) mark(myPC + myOffset, CartDebug::VALID_ENTRY); if (pass == 3) @@ -140,7 +151,9 @@ void DiStella::disasm(uInt32 distart, int pass) else ++myPC; } else if (checkBits(myPC, CartDebug::ROW, - CartDebug::CODE | CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX)) { + CartDebug::CODE | + CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX | + CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL)) { FIX_LAST: if (pass == 2) mark(myPC + myOffset, CartDebug::VALID_ENTRY); @@ -606,12 +619,13 @@ void DiStella::disasmPass1(CartDebug::AddressList& debuggerAddresses) // 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 (checkBits(k, CartDebug::CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX | + CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL, + CartDebug::CODE)) { //if (Debugger::debugger().getAccessFlags(k) & // (CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX)) { // TODO: this should never happen, remove when we are sure - // TODO: NOT USED: uInt8 flags = Debugger::debugger().getAccessFlags(k); + // TODO: NOT USED: uInt16 flags = Debugger::debugger().getAccessFlags(k); myPCEnd = k - 1; break; } @@ -667,8 +681,9 @@ void DiStella::disasmPass1(CartDebug::AddressList& debuggerAddresses) } // Must be ROW / unused bytes - if (!checkBit(k, CartDebug::CODE | CartDebug::GFX | - CartDebug::PGFX | CartDebug::DATA)) + if (!checkBit(k, CartDebug::CODE | CartDebug::GFX | CartDebug::PGFX | + CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL | + CartDebug::DATA)) mark(k + myOffset, CartDebug::ROW); } } @@ -685,7 +700,9 @@ void DiStella::disasmFromAddress(uInt32 distart) while (myPC <= myAppData.end) { // abort when we reach non-code areas - if (checkBits(myPC, CartDebug::CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX, CartDebug::CODE)) { + if (checkBits(myPC, CartDebug::CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX | + CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL, + CartDebug::CODE)) { myPCEnd = (myPC - 1) + myOffset; return; } @@ -823,7 +840,7 @@ void DiStella::disasmFromAddress(uInt32 distart) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int DiStella::mark(uInt32 address, uInt8 mask, bool directive) +int DiStella::mark(uInt32 address, uInt16 mask, bool directive) { /*----------------------------------------------------------------------- For any given offset and code range... @@ -896,16 +913,16 @@ int DiStella::mark(uInt32 address, uInt8 mask, bool directive) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool DiStella::checkBit(uInt16 address, uInt8 mask, bool useDebugger) const +bool DiStella::checkBit(uInt16 address, uInt16 mask, bool useDebugger) const { // The REFERENCED and VALID_ENTRY flags are needed for any inspection of // an address // Since they're set only in the labels array (as the lower two bits), // they must be included in the other bitfields - uInt8 label = myLabels[address & myAppData.end], + uInt16 label = myLabels[address & myAppData.end], lastbits = label & 0x03, - directive = myDirectives[address & myAppData.end] & 0xFC, - debugger = Debugger::debugger().getAccessFlags(address | myOffset) & 0xFC; + directive = myDirectives[address & myAppData.end] & ~0x03, + debugger = Debugger::debugger().getAccessFlags(address | myOffset) & ~0x03; // Any address marked by a manual directive always takes priority if (directive) @@ -918,11 +935,18 @@ bool DiStella::checkBit(uInt16 address, uInt8 mask, bool useDebugger) const return label & mask; } -bool DiStella::checkBits(uInt16 address, uInt8 mask, uInt8 notMask, bool useDebugger) const +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool DiStella::checkBits(uInt16 address, uInt16 mask, uInt16 notMask, bool useDebugger) const { return checkBit(address, mask, useDebugger) && !checkBit(address, notMask, useDebugger); } +/*bool DiStella::isType(uInt16 address) const +{ + return checkBits(address, CartDebug::GFX | CartDebug::PGFX | + CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL); +}*/ + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool DiStella::check_range(uInt16 beg, uInt16 end) const { @@ -999,18 +1023,29 @@ void DiStella::addEntry(CartDebug::DisasmType type) Debugger::debugger().setAccessFlags(tag.address, CartDebug::TCODE); } break; + case CartDebug::GFX: case CartDebug::PGFX: getline(myDisasmBuf, tag.disasm, '\''); getline(myDisasmBuf, tag.bytes); break; + + case CartDebug::COL: + case CartDebug::PCOL: + case CartDebug::BCOL: + getline(myDisasmBuf, tag.disasm, '\''); + getline(myDisasmBuf, tag.bytes); + break; + case CartDebug::DATA: getline(myDisasmBuf, tag.disasm, '\''); getline(myDisasmBuf, tag.bytes); break; + case CartDebug::ROW: getline(myDisasmBuf, tag.disasm); break; + case CartDebug::NONE: default: // should never happen tag.disasm = " "; @@ -1044,7 +1079,7 @@ void DiStella::outputGraphics() myDisasmBuf << ".byte $" << Base::HEX2 << int(byte) << " |"; for (uInt8 i = 0, c = byte; i < 8; ++i, c <<= 1) myDisasmBuf << ((c > 127) ? bitString : " "); - myDisasmBuf << "| $" << Base::HEX4 << myPC + myOffset << "'"; + myDisasmBuf << "| $" << Base::HEX4 << myPC + myOffset << "'"; if (mySettings.gfxFormat == Base::Fmt::_2) myDisasmBuf << Base::toString(byte, Base::Fmt::_2_8); else @@ -1053,6 +1088,74 @@ void DiStella::outputGraphics() addEntry(isPGfx ? CartDebug::PGFX : CartDebug::GFX); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void DiStella::outputColors() +{ + string NTSC_COLOR[16] = { + "BLACK", "YELLOW", "BROWN", "ORANGE", + "RED", "MAUVE", "VIOLET", "PURPLE", + "BLUE", "BLUE_CYAN", "CYAN", "CYAN_GREEN", + "GREEN", "GREEN_YELLOW", "GREEN_BEIGE", "BEIGE" + }; + string PAL_COLOR[16] = { + "BLACK0", "BLACK1", "YELLOW", "GREEN_YELLOW", + "ORANGE", "GREEN", "RED", "CYAN_GREEN", + "MAUVE", "CYAN", "VIOLET", "BLUE_CYAN", + "PURPLE", "BLUE", "BLACKE", "BLACKF" + }; + string SECAM_COLOR[8] = { + "BLACK", "BLUE", "RED", "PURPLE", + "GREEN", "CYAN", "YELLOW", "WHITE" + }; + + uInt8 byte = Debugger::debugger().peek(myPC + myOffset); + + // add extra spacing line when switching from non-colors to colors + if(mySegType != CartDebug::COL && mySegType != CartDebug::NONE) + { + myDisasmBuf << " ' ' "; + addEntry(CartDebug::NONE); + } + mySegType = CartDebug::COL; + + // output label/address + if(checkBit(myPC, CartDebug::REFERENCED)) + myDisasmBuf << Base::HEX4 << myPC + myOffset << "'L" << Base::HEX4 << myPC + myOffset << "'"; + else + myDisasmBuf << Base::HEX4 << myPC + myOffset << "' '"; + + // output color + string color; + + myDisasmBuf << ".byte "; + if(myDbg.myConsole.timing() == ConsoleTiming::ntsc) + { + color = NTSC_COLOR[byte >> 4]; + myDisasmBuf << color << "|$" << Base::HEX1 << (byte & 0xf); + } + else if(myDbg.myConsole.timing() == ConsoleTiming::pal) + { + color = PAL_COLOR[byte >> 4]; + myDisasmBuf << color << "|$" << Base::HEX1 << (byte & 0xf); + } + else + { + color = SECAM_COLOR[(byte >> 1) & 0x7]; + myDisasmBuf << "$" << Base::HEX1 << (byte >> 4) << "|" << color; + } + myDisasmBuf << std::setw(16 - color.length()) << std::setfill(' '); + + // output address + myDisasmBuf << "; $" << Base::HEX4 << myPC + myOffset << " " + << (checkBit(myPC, CartDebug::COL) ? "(Px)" : checkBit(myPC, CartDebug::PCOL) ? "(PF)" : "(BK)"); + + // output color value + myDisasmBuf << "'" << Base::HEX2 << int(byte); + + addEntry(checkBit(myPC, CartDebug::COL) ? CartDebug::COL : + checkBit(myPC, CartDebug::PCOL) ? CartDebug::PCOL : CartDebug::BCOL); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DiStella::outputBytes(CartDebug::DisasmType type) { @@ -1097,7 +1200,9 @@ void DiStella::outputBytes(CartDebug::DisasmType type) ++myPC; } isType = checkBits(myPC, type, - CartDebug::CODE | (type != CartDebug::DATA ? CartDebug::DATA : 0) | CartDebug::GFX | CartDebug::PGFX); + CartDebug::CODE | (type != CartDebug::DATA ? CartDebug::DATA : 0) | + CartDebug::GFX | CartDebug::PGFX | + CartDebug::COL | CartDebug::PCOL | CartDebug::BCOL); referenced = checkBit(myPC, CartDebug::REFERENCED); } if (!lineEmpty) diff --git a/src/debugger/DiStella.hxx b/src/debugger/DiStella.hxx index 16da2b6ba..830835a02 100644 --- a/src/debugger/DiStella.hxx +++ b/src/debugger/DiStella.hxx @@ -87,11 +87,12 @@ class DiStella void disasmFromAddress(uInt32 distart); bool check_range(uInt16 start, uInt16 end) const; - int mark(uInt32 address, uInt8 mask, bool directive = false); - bool checkBit(uInt16 address, uInt8 mask, bool useDebugger = true) const; - - bool checkBits(uInt16 address, uInt8 mask, uInt8 notMask, bool useDebugger = true) const; + int mark(uInt32 address, uInt16 mask, bool directive = false); + bool checkBit(uInt16 address, uInt16 mask, bool useDebugger = true) const; + bool checkBits(uInt16 address, uInt16 mask, uInt16 notMask, bool useDebugger = true) const; + //bool isType(uInt16 address) const; void outputGraphics(); + void outputColors(); void outputBytes(CartDebug::DisasmType type); // Convenience methods to generate appropriate labels diff --git a/src/debugger/gui/RomListWidget.cxx b/src/debugger/gui/RomListWidget.cxx index 8a705f3b1..fdc24fb71 100644 --- a/src/debugger/gui/RomListWidget.cxx +++ b/src/debugger/gui/RomListWidget.cxx @@ -511,7 +511,8 @@ void RomListWidget::drawWidget(bool hilite) // Bytes are only editable if they represent code, graphics, or accessible data // Otherwise, the disassembly should get all remaining space - if(dlist[pos].type & (CartDebug::CODE|CartDebug::GFX|CartDebug::PGFX|CartDebug::DATA)) + if(dlist[pos].type & (CartDebug::CODE|CartDebug::GFX|CartDebug::PGFX| + CartDebug::COL|CartDebug::PCOL|CartDebug::BCOL|CartDebug::DATA)) { if(dlist[pos].type == CartDebug::CODE) { diff --git a/src/emucore/Cart.cxx b/src/emucore/Cart.cxx index 3f1f53690..cd40f886b 100644 --- a/src/emucore/Cart.cxx +++ b/src/emucore/Cart.cxx @@ -117,7 +117,7 @@ void Cartridge::pokeRAM(uInt8& dest, uInt16 address, uInt8 value) void Cartridge::createCodeAccessBase(size_t size) { #ifdef DEBUGGER_SUPPORT - myCodeAccessBase = make_unique(size); + myCodeAccessBase = make_unique(size); std::fill_n(myCodeAccessBase.get(), size, CartDebug::ROW); #else myCodeAccessBase = nullptr; diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index 9e8d40a4b..a7bd1da6b 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -322,7 +322,7 @@ class Cartridge : public Device // The array containing information about every byte of ROM indicating // whether it is used as code. - ByteBuffer myCodeAccessBase; + WordBuffer myCodeAccessBase; // Contains address of illegal RAM write access or 0 uInt16 myRamWriteAccess{0}; diff --git a/src/emucore/Cart4A50.cxx b/src/emucore/Cart4A50.cxx index ead5d9285..ca634ed09 100644 --- a/src/emucore/Cart4A50.cxx +++ b/src/emucore/Cart4A50.cxx @@ -182,7 +182,7 @@ bool Cartridge4A50::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 Cartridge4A50::getAccessFlags(uInt16 address) const +uInt16 Cartridge4A50::getAccessFlags(uInt16 address) const { if((address & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff { @@ -214,7 +214,7 @@ uInt8 Cartridge4A50::getAccessFlags(uInt16 address) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Cartridge4A50::setAccessFlags(uInt16 address, uInt8 flags) +void Cartridge4A50::setAccessFlags(uInt16 address, uInt16 flags) { if((address & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff { diff --git a/src/emucore/Cart4A50.hxx b/src/emucore/Cart4A50.hxx index 863b1a020..210a2604b 100644 --- a/src/emucore/Cart4A50.hxx +++ b/src/emucore/Cart4A50.hxx @@ -158,14 +158,14 @@ class Cartridge4A50 : public Cartridge @param address The address to query */ - uInt8 getAccessFlags(uInt16 address) const override; + uInt16 getAccessFlags(uInt16 address) const override; /** Change the given address to use the given disassembly flags. @param address The address to modify @param flags A bitfield of DisasmType directives for the given address */ - void setAccessFlags(uInt16 address, uInt8 flags) override; + void setAccessFlags(uInt16 address, uInt16 flags) override; /** Check all possible hotspots diff --git a/src/emucore/CartAR.cxx b/src/emucore/CartAR.cxx index b095d446a..59ad6f03f 100644 --- a/src/emucore/CartAR.cxx +++ b/src/emucore/CartAR.cxx @@ -191,14 +191,14 @@ bool CartridgeAR::poke(uInt16 addr, uInt8) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeAR::getAccessFlags(uInt16 address) const +uInt16 CartridgeAR::getAccessFlags(uInt16 address) const { return myCodeAccessBase[(address & 0x07FF) + myImageOffset[(address & 0x0800) ? 1 : 0]]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeAR::setAccessFlags(uInt16 address, uInt8 flags) +void CartridgeAR::setAccessFlags(uInt16 address, uInt16 flags) { myCodeAccessBase[(address & 0x07FF) + myImageOffset[(address & 0x0800) ? 1 : 0]] |= flags; diff --git a/src/emucore/CartAR.hxx b/src/emucore/CartAR.hxx index 039d19bb8..09dc11b3a 100644 --- a/src/emucore/CartAR.hxx +++ b/src/emucore/CartAR.hxx @@ -164,14 +164,14 @@ class CartridgeAR : public Cartridge @param address The address to query */ - uInt8 getAccessFlags(uInt16 address) const override; + uInt16 getAccessFlags(uInt16 address) const override; /** Change the given address to use the given disassembly flags. @param address The address to modify @param flags A bitfield of DisasmType directives for the given address */ - void setAccessFlags(uInt16 address, uInt8 flags) override; + void setAccessFlags(uInt16 address, uInt16 flags) override; // Handle a change to the bank configuration bool bankConfiguration(uInt8 configuration); diff --git a/src/emucore/Device.hxx b/src/emucore/Device.hxx index 444a599af..f405a8739 100644 --- a/src/emucore/Device.hxx +++ b/src/emucore/Device.hxx @@ -102,7 +102,7 @@ class Device : public Serializable @param address The address to modify */ - virtual uInt8 getAccessFlags(uInt16 address) const { return 0; } + virtual uInt16 getAccessFlags(uInt16 address) const { return 0; } /** Change the given address type to use the given disassembly flags @@ -110,7 +110,7 @@ class Device : public Serializable @param address The address to modify @param flags A bitfield of DisasmType directives for the given address */ - virtual void setAccessFlags(uInt16 address, uInt8 flags) { } + virtual void setAccessFlags(uInt16 address, uInt16 flags) { } protected: /// Pointer to the system the device is installed in or the null pointer diff --git a/src/emucore/M6502.cxx b/src/emucore/M6502.cxx index 29863c306..fda514705 100644 --- a/src/emucore/M6502.cxx +++ b/src/emucore/M6502.cxx @@ -104,7 +104,7 @@ void M6502::reset() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -inline uInt8 M6502::peek(uInt16 address, uInt8 flags) +inline uInt8 M6502::peek(uInt16 address, uInt16 flags) { handleHalt(); @@ -144,7 +144,7 @@ inline uInt8 M6502::peek(uInt16 address, uInt8 flags) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -inline void M6502::poke(uInt16 address, uInt8 value, uInt8 flags) +inline void M6502::poke(uInt16 address, uInt8 value, uInt16 flags) { //////////////////////////////////////////////// // TODO - move this logic directly into CartAR diff --git a/src/emucore/M6502.hxx b/src/emucore/M6502.hxx index c05fbc522..dd48315a6 100644 --- a/src/emucore/M6502.hxx +++ b/src/emucore/M6502.hxx @@ -269,7 +269,7 @@ class M6502 : public Serializable @return The byte at the specified address */ - uInt8 peek(uInt16 address, uInt8 flags); + uInt8 peek(uInt16 address, uInt16 flags); /** Change the byte at the specified address to the given value and @@ -278,7 +278,7 @@ class M6502 : 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, uInt8 flags = 0); + void poke(uInt16 address, uInt8 value, uInt16 flags = 0); /** Get the 8-bit value of the Processor Status register. @@ -391,7 +391,7 @@ class M6502 : public Serializable /// accessed specifically by a peek or poke command uInt16 myLastPeekBaseAddress{0}, myLastPokeBaseAddress{0}; // Indicates the type of the last access - uInt8 myFlags{0}; + uInt16 myFlags{0}; /// Indicates the last address used to access data by a peek command /// for the CPU registers (S/A/X/Y) diff --git a/src/emucore/M6532.cxx b/src/emucore/M6532.cxx index dec6d9981..80f828f83 100644 --- a/src/emucore/M6532.cxx +++ b/src/emucore/M6532.cxx @@ -467,7 +467,7 @@ void M6532::createAccessBases() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 M6532::getAccessFlags(uInt16 address) const +uInt16 M6532::getAccessFlags(uInt16 address) const { if (address & IO_BIT) return myIOAccessBase[address & IO_MASK]; @@ -478,7 +478,7 @@ uInt8 M6532::getAccessFlags(uInt16 address) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void M6532::setAccessFlags(uInt16 address, uInt8 flags) +void M6532::setAccessFlags(uInt16 address, uInt16 flags) { // ignore none flag if (flags != CartDebug::NONE) { diff --git a/src/emucore/M6532.hxx b/src/emucore/M6532.hxx index bbda58e31..db93414a3 100644 --- a/src/emucore/M6532.hxx +++ b/src/emucore/M6532.hxx @@ -151,14 +151,14 @@ class M6532 : public Device @param address The address to query */ - uInt8 getAccessFlags(uInt16 address) const override; + uInt16 getAccessFlags(uInt16 address) const override; /** Change the given address to use the given disassembly flags. @param address The address to modify @param flags A bitfield of DisasmType directives for the given address */ - void setAccessFlags(uInt16 address, uInt8 flags) override; + void setAccessFlags(uInt16 address, uInt16 flags) override; #endif // DEBUGGER_SUPPORT private: @@ -225,9 +225,9 @@ class M6532 : public Device // The arrays containing information about every byte of RIOT // indicating whether and how (RW) it is used. - std::array myRAMAccessBase; - std::array myStackAccessBase; - std::array myIOAccessBase; + std::array myRAMAccessBase; + std::array myStackAccessBase; + std::array myIOAccessBase; // The array used to skip the first ZP access tracking std::array myZPAccessDelay; #endif // DEBUGGER_SUPPORT diff --git a/src/emucore/System.cxx b/src/emucore/System.cxx index ee9392b03..e40124c2a 100644 --- a/src/emucore/System.cxx +++ b/src/emucore/System.cxx @@ -99,7 +99,7 @@ void System::clearDirtyPages() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 System::peek(uInt16 addr, uInt8 flags) +uInt8 System::peek(uInt16 addr, uInt16 flags) { const PageAccess& access = getPageAccess(addr); @@ -127,7 +127,7 @@ uInt8 System::peek(uInt16 addr, uInt8 flags) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void System::poke(uInt16 addr, uInt8 value, uInt8 flags) +void System::poke(uInt16 addr, uInt8 value, uInt16 flags) { uInt16 page = (addr & ADDRESS_MASK) >> PAGE_SHIFT; const PageAccess& access = myPageAccessTable[page]; @@ -160,7 +160,7 @@ void System::poke(uInt16 addr, uInt8 value, uInt8 flags) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 System::getAccessFlags(uInt16 addr) const +uInt16 System::getAccessFlags(uInt16 addr) const { #ifdef DEBUGGER_SUPPORT const PageAccess& access = getPageAccess(addr); @@ -175,7 +175,7 @@ uInt8 System::getAccessFlags(uInt16 addr) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void System::setAccessFlags(uInt16 addr, uInt8 flags) +void System::setAccessFlags(uInt16 addr, uInt16 flags) { #ifdef DEBUGGER_SUPPORT const PageAccess& access = getPageAccess(addr); diff --git a/src/emucore/System.hxx b/src/emucore/System.hxx index a9cf75cc2..f4423c491 100644 --- a/src/emucore/System.hxx +++ b/src/emucore/System.hxx @@ -202,7 +202,7 @@ class System : public Serializable @return The byte at the specified address */ - uInt8 peek(uInt16 address, uInt8 flags = 0); + uInt8 peek(uInt16 address, uInt16 flags = 0); /** Change the byte at the specified address to the given value. @@ -217,7 +217,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, uInt8 flags = 0); + void poke(uInt16 address, uInt8 value, uInt16 flags = 0); /** Lock/unlock the data bus. When the bus is locked, peek() and @@ -236,8 +236,8 @@ class System : public Serializable address. Note that while any flag can be used, the disassembly only really acts on CODE/GFX/PGFX/DATA/ROW. */ - uInt8 getAccessFlags(uInt16 address) const; - void setAccessFlags(uInt16 address, uInt8 flags); + uInt16 getAccessFlags(uInt16 address) const; + void setAccessFlags(uInt16 address, uInt16 flags); public: /** @@ -277,7 +277,7 @@ class System : public Serializable conclusively determine if a section of address space is CODE, even if the disassembler failed to mark it as such. */ - uInt8* codeAccessBase{nullptr}; + uInt16* codeAccessBase{nullptr}; /** Pointer to the device associated with this page or to the system's diff --git a/src/emucore/tia/TIA.cxx b/src/emucore/tia/TIA.cxx index 38beebbcf..145eea6e5 100644 --- a/src/emucore/tia/TIA.cxx +++ b/src/emucore/tia/TIA.cxx @@ -568,26 +568,47 @@ bool TIA::poke(uInt16 address, uInt8 value) break; case COLUBK: + { value &= 0xFE; myBackground.setColor(value); myShadowRegisters[address] = value; + #ifdef DEBUGGER_SUPPORT + uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); + if(dataAddr) + mySystem->setAccessFlags(dataAddr, CartDebug::BCOL); + #endif break; + } case COLUP0: + { value &= 0xFE; myPlayfield.setColorP0(value); myMissile0.setColor(value); myPlayer0.setColor(value); myShadowRegisters[address] = value; + #ifdef DEBUGGER_SUPPORT + uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); + if(dataAddr) + mySystem->setAccessFlags(dataAddr, CartDebug::COL); + #endif break; + } case COLUP1: + { value &= 0xFE; myPlayfield.setColorP1(value); myMissile1.setColor(value); myPlayer1.setColor(value); myShadowRegisters[address] = value; + #ifdef DEBUGGER_SUPPORT + uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); + if(dataAddr) + mySystem->setAccessFlags(dataAddr, CartDebug::COL); + #endif break; + } case CTRLPF: flushLineCache(); @@ -599,9 +620,10 @@ bool TIA::poke(uInt16 address, uInt8 value) break; case COLUPF: + { flushLineCache(); value &= 0xFE; - if (myPFColorDelay) + if(myPFColorDelay) myDelayQueue.push(COLUPF, value, 1); else { @@ -609,7 +631,13 @@ bool TIA::poke(uInt16 address, uInt8 value) myBall.setColor(value); myShadowRegisters[address] = value; } + #ifdef DEBUGGER_SUPPORT + uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); + if(dataAddr) + mySystem->setAccessFlags(dataAddr, CartDebug::PCOL); + #endif break; + } case PF0: { @@ -1891,13 +1919,13 @@ void TIA::createAccessBase() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 TIA::getAccessFlags(uInt16 address) const +uInt16 TIA::getAccessFlags(uInt16 address) const { return myAccessBase[address & TIA_MASK]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::setAccessFlags(uInt16 address, uInt8 flags) +void TIA::setAccessFlags(uInt16 address, uInt16 flags) { // ignore none flag if (flags != CartDebug::NONE) { diff --git a/src/emucore/tia/TIA.hxx b/src/emucore/tia/TIA.hxx index 0b3cb4eaf..acb7ee40e 100644 --- a/src/emucore/tia/TIA.hxx +++ b/src/emucore/tia/TIA.hxx @@ -685,14 +685,14 @@ class TIA : public Device * * @param address The address to query */ - uInt8 getAccessFlags(uInt16 address) const override; + uInt16 getAccessFlags(uInt16 address) const override; /** * Change the given address to use the given disassembly flags. * * @param address The address to modify * @param flags A bitfield of DisasmType directives for the given address */ - void setAccessFlags(uInt16 address, uInt8 flags) override; + void setAccessFlags(uInt16 address, uInt16 flags) override; #endif // DEBUGGER_SUPPORT private: @@ -901,7 +901,7 @@ class TIA : public Device #ifdef DEBUGGER_SUPPORT // The arrays containing information about every byte of TIA // indicating whether and how (RW) it is used. - std::array myAccessBase; + std::array myAccessBase; // The array used to skip the first two TIA access trackings std::array myAccessDelay;