From 28114a8c517fddfbd208bc0e44a20a8b83859c08 Mon Sep 17 00:00:00 2001 From: stephena Date: Sun, 17 Jan 2010 16:48:45 +0000 Subject: [PATCH] OK, this is the first pass at a huge reorganization of the debugger classes. First off, the distella code has been integrated into a DiStella class. This code isn't yet tied to the debugger, but it does at least compile and generate valid output. The RamDebug class has been replaced by a CartDebug class, which takes responsibility for the previous RamDebug stuff as well as things related to Cart address space (read from write ports, disassembly, etc). Fixed E7 bankswitching when reading from the write port in the upper 256byte area. Fixed 'read from write port functionality' in general for all carts that supported it previously. Basically, if _rwport is enabled, the address is checked to be an actual read (vs. one that's part of a normal write cycle), *and* it's actually an illegal access (each cart/bankswitch type now provides a hint to indicate this condition). Still TODO is clean up the rework, properly integrate DiStella, and fix labels and defines (which seem to be completely broken). git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1922 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba --- src/debugger/CartDebug.cxx | 1062 ++++++++++++++++++++ src/debugger/CartDebug.hxx | 232 +++++ src/debugger/CpuDebug.cxx | 125 +-- src/debugger/CpuDebug.hxx | 14 +- src/debugger/Debugger.cxx | 139 +-- src/debugger/Debugger.hxx | 47 +- src/debugger/DebuggerExpressions.hxx | 12 +- src/debugger/DebuggerParser.cxx | 68 +- src/debugger/DebuggerParser.hxx | 4 +- src/debugger/DiStella.cxx | 1360 ++++++++++++++++++++++++++ src/debugger/DiStella.hxx | 146 +++ src/debugger/EquateList.cxx | 542 ---------- src/debugger/EquateList.hxx | 122 --- src/debugger/RamDebug.cxx | 164 ---- src/debugger/RamDebug.hxx | 82 -- src/debugger/gui/CpuWidget.cxx | 3 +- src/debugger/gui/PromptWidget.cxx | 10 +- src/debugger/gui/RamWidget.cxx | 23 +- src/debugger/gui/RomListWidget.cxx | 34 +- src/debugger/gui/RomWidget.cxx | 104 +- src/debugger/gui/RomWidget.hxx | 4 - src/debugger/gui/TiaWidget.cxx | 4 +- src/debugger/module.mk | 4 +- src/emucore/Cart.cxx | 11 +- src/emucore/Cart.hxx | 7 + src/emucore/Cart3E.cxx | 10 +- src/emucore/CartCV.cxx | 9 +- src/emucore/CartE7.cxx | 19 +- src/emucore/CartEFSC.cxx | 10 +- src/emucore/CartF4SC.cxx | 13 +- src/emucore/CartF6SC.cxx | 10 +- src/emucore/CartF8SC.cxx | 10 +- src/emucore/CartFA.cxx | 10 +- src/emucore/M6502.cxx | 221 +---- src/emucore/M6502.hxx | 39 +- src/win32/Stella.vcproj | 4 +- src/yacc/YaccParser.cxx | 499 +++++----- src/yacc/stella.y | 18 +- src/yacc/y.tab.c | 28 +- src/yacc/y.tab.h | 14 +- 40 files changed, 3293 insertions(+), 1944 deletions(-) create mode 100644 src/debugger/CartDebug.cxx create mode 100644 src/debugger/CartDebug.hxx create mode 100644 src/debugger/DiStella.cxx create mode 100644 src/debugger/DiStella.hxx delete mode 100644 src/debugger/EquateList.cxx delete mode 100644 src/debugger/EquateList.hxx delete mode 100644 src/debugger/RamDebug.cxx delete mode 100644 src/debugger/RamDebug.hxx diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx new file mode 100644 index 000000000..1afc17bcd --- /dev/null +++ b/src/debugger/CartDebug.cxx @@ -0,0 +1,1062 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2009 by Bradford W. Mott and the Stella team +// +// See the file "license" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +// +// $Id$ +//============================================================================ + +#include "bspf.hxx" +#include "Array.hxx" +#include "System.hxx" +#include "CartDebug.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +CartDebug::CartDebug(Debugger& dbg, Console& console, const RamAreaList& areas) + : DebuggerSystem(dbg, console), + myRWPortAddress(0) +{ + // Zero-page RAM is always present + addRamArea(0x80, 128, 0, 0); + + // Add extended RAM + myRamAreas = areas; + for(RamAreaList::const_iterator i = areas.begin(); i != areas.end(); ++i) + addRamArea(i->start, i->size, i->roffset, i->woffset); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartDebug::addRamArea(uInt16 start, uInt16 size, + uInt16 roffset, uInt16 woffset) +{ + // First make sure this area isn't already present + for(uInt32 i = 0; i < myState.rport.size(); ++i) + if(myState.rport[i] == start + roffset || + myState.wport[i] == start + woffset) + return; + + // Otherwise, add a new area + for(uInt32 i = 0; i < size; ++i) + { + myState.rport.push_back(i + start + roffset); + myState.wport.push_back(i + start + woffset); + + myOldState.rport.push_back(i + start + roffset); + myOldState.wport.push_back(i + start + woffset); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const DebuggerState& CartDebug::getState() +{ + myState.ram.clear(); + for(uInt32 i = 0; i < myState.rport.size(); ++i) + myState.ram.push_back(read(myState.rport[i])); + + return myState; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartDebug::saveOldState() +{ + myOldState.ram.clear(); + for(uInt32 i = 0; i < myOldState.rport.size(); ++i) + myOldState.ram.push_back(read(myOldState.rport[i])); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt8 CartDebug::read(uInt16 addr) +{ + return mySystem.peek(addr); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartDebug::write(uInt16 addr, uInt8 value) +{ + mySystem.poke(addr, value); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int CartDebug::readFromWritePort() +{ + uInt16 peekAddress = myRWPortAddress; + myRWPortAddress = 0; + + // A read from the write port occurs when the read is actually in the write + // port address space AND the last access was actually a read (the latter + // differentiates between reads that are normally part of a write cycle vs. + // ones that are illegal + if(mySystem.m6502().lastReadAddress() && peekAddress & 0x1000) + { + uInt16 addr = peekAddress & 0x0FFF; + for(RamAreaList::const_iterator i = myRamAreas.begin(); i != myRamAreas.end(); ++i) + { + uInt16 start = (i->start + i->woffset) & 0x0FFF; + uInt16 end = (i->start + i->woffset + i->size) & 0x0FFF; + if(addr >= start && addr < end) + return peekAddress; + } + } + return 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartDebug::toString() +{ + string result; + char buf[128]; + uInt32 bytesPerLine; + + switch(myDebugger.parser().base()) + { + case kBASE_16: + case kBASE_10: + bytesPerLine = 0x10; + break; + + case kBASE_2: + bytesPerLine = 0x04; + break; + + case kBASE_DEFAULT: + default: + return DebuggerParser::red("invalid base, this is a BUG"); + } + + const CartState& state = (CartState&) getState(); + const CartState& oldstate = (CartState&) getOldState(); + + uInt32 curraddr = 0, bytesSoFar = 0; + for(uInt32 i = 0; i < state.ram.size(); i += bytesPerLine, bytesSoFar += bytesPerLine) + { + // We detect different 'pages' of RAM when the addresses jump by + // more than the number of bytes on the previous line, or when 256 + // bytes have been previously output + if(state.rport[i] - curraddr > bytesPerLine || bytesSoFar >= 256) + { + sprintf(buf, "%04x: (rport = %04x, wport = %04x)\n", + state.rport[i], state.rport[i], state.wport[i]); + buf[2] = buf[3] = 'x'; + result += DebuggerParser::red(buf); + bytesSoFar = 0; + } + curraddr = state.rport[i]; + sprintf(buf, "%.2x: ", curraddr & 0x00ff); + result += buf; + + for(uInt8 j = 0; j < bytesPerLine; ++j) + { + result += myDebugger.invIfChanged(state.ram[i+j], oldstate.ram[i+j]); + result += " "; + + if(j == 0x07) result += " "; + } + result += "\n"; + } + + return result; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const string& CartDebug::disassemble(int start, int lines) +{ + static string result= ""; + ostringstream buffer; + string cpubuf; + + if(start < 0x80 || start > 0xffff) + return result; + + do { + buffer << getLabel(start, true, 4) << ": "; + + int count = disassemble(start, cpubuf); + for(int i = 0; i < count; i++) + buffer << hex << setw(2) << setfill('0') << myDebugger.peek(start++) << " " << dec; + + if(count < 3) buffer << " "; + if(count < 2) buffer << " "; + + buffer << " " << cpubuf << "\n"; + } while(--lines > 0 && start <= 0xffff); + + result = buffer.str(); + return result; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartDebug::disassemble(IntArray& addr, StringList& addrLabel, + StringList& bytes, StringList& data, + int start, int end) +{ + if(start < 0x80 || end > 0xffff) + return; + + string cpubuf, tmp; + char buf[255]; + + do { + addr.push_back(start); + addrLabel.push_back(getLabel(start, true, 4) + ":"); + + cpubuf = ""; + int count = disassemble(start, cpubuf); + + tmp = ""; + for(int i = 0; i < count; i++) + { + sprintf(buf, "%02x ", myDebugger.peek(start++)); + tmp += buf; + } + bytes.push_back(tmp); + + data.push_back(cpubuf); + } + while(start <= end); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int CartDebug::disassemble(int address, string& result) +{ + ostringstream buf; + int count = 0; + int opcode = mySystem.peek(address); + + // Are we looking at a read or write operation? + // It will determine what type of label to use + bool isRead = (CartDebug::AccessModeTable[opcode] == CartDebug::Read); + + switch(CartDebug::AddressModeTable[opcode]) + { + case CartDebug::Absolute: + buf << CartDebug::InstructionMnemonicTable[opcode] << " " + << getLabel(myDebugger.dpeek(address + 1), isRead, 4) << " ; " + << M6502::ourInstructionCycleTable[opcode]; + count = 3; + break; + + case CartDebug::AbsoluteX: + buf << CartDebug::InstructionMnemonicTable[opcode] << " " + << getLabel(myDebugger.dpeek(address + 1), isRead, 4) << ",x ; " + << M6502::ourInstructionCycleTable[opcode]; + count = 3; + break; + + case CartDebug::AbsoluteY: + buf << CartDebug::InstructionMnemonicTable[opcode] << " " + << getLabel(myDebugger.dpeek(address + 1), isRead, 4) << ",y ; " + << M6502::ourInstructionCycleTable[opcode]; + count = 3; + break; + + case CartDebug::Immediate: + buf << CartDebug::InstructionMnemonicTable[opcode] << " #$" + << hex << setw(2) << setfill('0') << (int) mySystem.peek(address + 1) << " ; " + << dec << M6502::ourInstructionCycleTable[opcode]; + count = 2; + break; + + case CartDebug::Implied: + buf << CartDebug::InstructionMnemonicTable[opcode] << " ; " + << M6502::ourInstructionCycleTable[opcode]; + count = 1; + break; + + case CartDebug::Indirect: + buf << CartDebug::InstructionMnemonicTable[opcode] << " (" + << getLabel(myDebugger.dpeek(address + 1), isRead, 4) << ") ; " + << M6502::ourInstructionCycleTable[opcode]; + count = 3; + break; + + case CartDebug::IndirectX: + buf << CartDebug::InstructionMnemonicTable[opcode] << " (" + << getLabel(mySystem.peek(address + 1), isRead, 2) << ",x) ; " + << M6502::ourInstructionCycleTable[opcode]; + count = 2; + break; + + case CartDebug::IndirectY: + buf << CartDebug::InstructionMnemonicTable[opcode] << " (" + << getLabel(mySystem.peek(address + 1), isRead, 2) << "),y ; " + << M6502::ourInstructionCycleTable[opcode]; + count = 2; + break; + + case CartDebug::Relative: + buf << CartDebug::InstructionMnemonicTable[opcode] << " " + << getLabel(address + 2 + ((Int16)(Int8)mySystem.peek(address + 1)), isRead, 4) + << " ; " << M6502::ourInstructionCycleTable[opcode]; + count = 2; + break; + + case CartDebug::Zero: + buf << CartDebug::InstructionMnemonicTable[opcode] << " " + << getLabel(mySystem.peek(address + 1), isRead, 2) << " ; " + << M6502::ourInstructionCycleTable[opcode]; + count = 2; + break; + + case CartDebug::ZeroX: + buf << CartDebug::InstructionMnemonicTable[opcode] << " " + << getLabel(mySystem.peek(address + 1), isRead, 2) << ",x ; " + << M6502::ourInstructionCycleTable[opcode]; + count = 2; + break; + + case CartDebug::ZeroY: + buf << CartDebug::InstructionMnemonicTable[opcode] << " " + << getLabel(mySystem.peek(address + 1), isRead, 2) << ",y ; " + << M6502::ourInstructionCycleTable[opcode]; + count = 2; + break; + + default: + buf << "dc $" << hex << setw(2) << setfill('0') << (int) opcode << " ; " + << dec << M6502::ourInstructionCycleTable[opcode]; + count = 1; + break; + } + + result = buf.str(); + return count; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int CartDebug::getBank() +{ + return myConsole.cartridge().bank(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int CartDebug::bankCount() +{ + return myConsole.cartridge().bankCount(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartDebug::getCartType() +{ + return myConsole.cartridge().name(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartDebug::addLabel(const string& label, uInt16 address) +{ + // First check if this already exists as a hard-coded equate + LabelToAddr::const_iterator iter = mySystemAddresses.find(label); + if(iter != mySystemAddresses.end() && iter->second.address == address) + return; + + // Create a new user equate, and determine if its RAM or ROM + // For now, these are the only types we care about + // Technically, addresses above 0x1000 are ROM and are read-only + // However, somes ROMs have dedicated RAM mapped to those addresses + // as well, and we don't yet have an infrastructure to determine that, + // so the entire region is marked as read-write + equate_t flags = EQF_READ; +#if 0 + if(address >= 0x80 && address <= 0xff) + flags = EQF_RW; + else if((address & 0x1000) == 0x1000) + flags = EQF_RW; + else + { + cerr << "label = " << label << ", address = " << hex << address << " discarded\n"; + return; // don't know what else to do for now + } +#else + // The above section of code is deactivated until a better means of + // determining constants vs. addresses is found + flags = EQF_RW; +#endif + + removeLabel(label); + + Equate e; + e.label = label; + e.address = address; + e.flags = flags; + + myUserAddresses.insert(make_pair(label, e)); + myUserLabels.insert(make_pair(address, e)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartDebug::removeLabel(const string& label) +{ + // Note that only user-defined equates can be removed + LabelToAddr::iterator iter = myUserAddresses.find(label); + if(iter != myUserAddresses.end()) + { + // Erase the label + myUserAddresses.erase(iter); + + // And also erase the address assigned to it + AddrToLabel::iterator iter2 = myUserLabels.find(iter->second.address); + if(iter2 != myUserLabels.end()) + myUserLabels.erase(iter2); + + return true; + } + return false; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const string& CartDebug::getLabel(uInt16 addr, bool isRead, int places) const +{ + static string result; + AddrToLabel::const_iterator iter; + + // Is this a read or write? + // For now, there aren't separate read & write lists for user labels + const AddrToLabel& systemLabels = isRead ? + (const AddrToLabel&) mySystemReadLabels : + (const AddrToLabel&) mySystemWriteLabels; + + // Determine the type of address to access the correct list + // These addresses were based on (and checked against) Kroko's 2600 memory + // map, found at http://www.qotile.net/minidig/docs/2600_mem_map.txt + address_t type = ADDR_ROM; + if(addr % 0x2000 < 0x1000) + { + uInt16 z = addr & 0x00ff; + if(z < 0x80) + type = ADDR_TIA; + else + { + switch(addr & 0x0f00) + { + case 0x000: + case 0x100: + case 0x400: + case 0x500: + case 0x800: + case 0x900: + case 0xc00: + case 0xd00: + type = ADDR_RAM; + break; + case 0x200: + case 0x300: + case 0x600: + case 0x700: + case 0xa00: + case 0xb00: + case 0xe00: + case 0xf00: + type = ADDR_RIOT; + break; + } + } + } + + switch(type) + { + case ADDR_TIA: + if((iter = systemLabels.find(addr&0x7f)) != systemLabels.end()) + return iter->second.label; + else if((iter = myUserLabels.find(addr)) != myUserLabels.end()) + return iter->second.label; + break; + + case ADDR_RIOT: // FIXME - add mirrors for RIOT + if((iter = systemLabels.find(addr)) != systemLabels.end()) + return iter->second.label; + else if((iter = myUserLabels.find(addr)) != myUserLabels.end()) + return iter->second.label; + break; + + case ADDR_RAM: + case ADDR_ROM: + // These addresses can never be in the system labels list + if((iter = myUserLabels.find(addr)) != myUserLabels.end()) + return iter->second.label; + break; + } + + if(places > -1) + { + ostringstream buf; + buf << "$" << setw(places) << hex << addr; + return result = buf.str(); + } + + return EmptyString; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int CartDebug::getAddress(const string& label) const +{ + LabelToAddr::const_iterator iter; + + if((iter = mySystemAddresses.find(label)) != mySystemAddresses.end()) + return iter->second.address; + else if((iter = myUserAddresses.find(label)) != myUserAddresses.end()) + return iter->second.address; + else + return -1; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartDebug::loadSymbolFile(const string& f) +{ + string file = f; + string::size_type spos; + if( (spos = file.find_last_of('.')) != string::npos ) + file.replace(spos, file.size(), ".sym"); + else + file += ".sym"; + + int pos = 0, lines = 0, curVal; + string curLabel; + char line[1024]; + + ifstream in(file.c_str()); + if(!in.is_open()) + return "Unable to read symbols from " + file; + + myUserAddresses.clear(); + myUserLabels.clear(); + + while( !in.eof() ) + { + curVal = 0; + curLabel = ""; + + int got = in.get(); + + if(got == -1 || got == '\r' || got == '\n' || pos == 1023) { + line[pos] = '\0'; + pos = 0; + + if(strlen(line) > 0 && line[0] != '-') + { + curLabel = extractLabel(line); + if((curVal = extractValue(line)) < 0) + return "invalid symbol file"; + + addLabel(curLabel, curVal); + + lines++; + } + } + else + { + line[pos++] = got; + } + } + in.close(); + return "loaded " + file + " OK"; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartDebug::saveSymbolFile(const string& file) +{ + // Only user-defined equates are saved; system equates are always + // available, so there's no need to save them + char buf[256]; + + ofstream out(file.c_str()); + if(!out.is_open()) + return false; + + out << "--- Symbol List (sorted by symbol)" << endl; + + LabelToAddr::const_iterator iter; + for(iter = myUserAddresses.begin(); iter != myUserAddresses.end(); iter++) + { + sprintf(buf, "%-24s %04x \n", iter->second.label.c_str(), iter->second.address); + out << buf; + } + + out << "--- End of Symbol List." << endl; + + return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int CartDebug::countCompletions(const char *in) +{ + myCompletions = myCompPrefix = ""; + return countCompletions(in, mySystemAddresses) + + countCompletions(in, myUserAddresses); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int CartDebug::countCompletions(const char *in, LabelToAddr& addresses) +{ + int count = 0; + + LabelToAddr::iterator iter; + for(iter = addresses.begin(); iter != addresses.end(); iter++) + { + const char *l = iter->first.c_str(); + + if(BSPF_strncasecmp(l, in, strlen(in)) == 0) + { + if(myCompPrefix == "") + myCompPrefix += l; + else + { + int nonMatch = 0; + const char *c = myCompPrefix.c_str(); + while(*c != '\0' && tolower(*c) == tolower(l[nonMatch])) + { + c++; + nonMatch++; + } + myCompPrefix.erase(nonMatch, myCompPrefix.length()); + } + + if(count++) myCompletions += " "; + myCompletions += l; + } + } + + return count; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string CartDebug::extractLabel(char *c) const +{ + string l = ""; + while(*c != ' ') + l += *c++; + + return l; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int CartDebug::extractValue(char *c) const +{ + while(*c != ' ') + { + if(*c == '\0') + return -1; + c++; + } + + while(*c == ' ') + { + if(*c == '\0') + return -1; + c++; + } + + int ret = 0; + for(int i=0; i<4; i++) + { + if(*c >= '0' && *c <= '9') + ret = (ret << 4) + (*c) - '0'; + else if(*c >= 'a' && *c <= 'f') + ret = (ret << 4) + (*c) - 'a' + 10; + else + return -1; + c++; + } + return ret; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const CartDebug::Equate CartDebug::ourSystemEquates[kSystemEquateSize] = { +// Standard $00-based TIA write locations: + { "VSYNC", 0x00, EQF_WRITE }, + { "VBLANK", 0x01, EQF_WRITE }, + { "WSYNC", 0x02, EQF_WRITE }, + { "RSYNC", 0x03, EQF_WRITE }, + { "NUSIZ0", 0x04, EQF_WRITE }, + { "NUSIZ1", 0x05, EQF_WRITE }, + { "COLUP0", 0x06, EQF_WRITE }, + { "COLUP1", 0x07, EQF_WRITE }, + { "COLUPF", 0x08, EQF_WRITE }, + { "COLUBK", 0x09, EQF_WRITE }, + { "CTRLPF", 0x0A, EQF_WRITE }, + { "REFP0", 0x0B, EQF_WRITE }, + { "REFP1", 0x0C, EQF_WRITE }, + { "PF0", 0x0D, EQF_WRITE }, + { "PF1", 0x0E, EQF_WRITE }, + { "PF2", 0x0F, EQF_WRITE }, + { "RESP0", 0x10, EQF_WRITE }, + { "RESP1", 0x11, EQF_WRITE }, + { "RESM0", 0x12, EQF_WRITE }, + { "RESM1", 0x13, EQF_WRITE }, + { "RESBL", 0x14, EQF_WRITE }, + { "AUDC0", 0x15, EQF_WRITE }, + { "AUDC1", 0x16, EQF_WRITE }, + { "AUDF0", 0x17, EQF_WRITE }, + { "AUDF1", 0x18, EQF_WRITE }, + { "AUDV0", 0x19, EQF_WRITE }, + { "AUDV1", 0x1A, EQF_WRITE }, + { "GRP0", 0x1B, EQF_WRITE }, + { "GRP1", 0x1C, EQF_WRITE }, + { "ENAM0", 0x1D, EQF_WRITE }, + { "ENAM1", 0x1E, EQF_WRITE }, + { "ENABL", 0x1F, EQF_WRITE }, + { "HMP0", 0x20, EQF_WRITE }, + { "HMP1", 0x21, EQF_WRITE }, + { "HMM0", 0x22, EQF_WRITE }, + { "HMM1", 0x23, EQF_WRITE }, + { "HMBL", 0x24, EQF_WRITE }, + { "VDELP0", 0x25, EQF_WRITE }, + { "VDEL01", 0x26, EQF_WRITE }, + { "VDELP1", 0x26, EQF_WRITE }, + { "VDELBL", 0x27, EQF_WRITE }, + { "RESMP0", 0x28, EQF_WRITE }, + { "RESMP1", 0x29, EQF_WRITE }, + { "HMOVE", 0x2A, EQF_WRITE }, + { "HMCLR", 0x2B, EQF_WRITE }, + { "CXCLR", 0x2C, EQF_WRITE }, + +// Mirrored $40-based TIA write locations: + { "VSYNC.40", 0x40, EQF_WRITE }, + { "VBLANK.40", 0x41, EQF_WRITE }, + { "WSYNC.40", 0x42, EQF_WRITE }, + { "RSYNC.40", 0x43, EQF_WRITE }, + { "NUSIZ0.40", 0x44, EQF_WRITE }, + { "NUSIZ1.40", 0x45, EQF_WRITE }, + { "COLUP0.40", 0x46, EQF_WRITE }, + { "COLUP1.40", 0x47, EQF_WRITE }, + { "COLUPF.40", 0x48, EQF_WRITE }, + { "COLUBK.40", 0x49, EQF_WRITE }, + { "CTRLPF.40", 0x4A, EQF_WRITE }, + { "REFP0.40", 0x4B, EQF_WRITE }, + { "REFP1.40", 0x4C, EQF_WRITE }, + { "PF0.40", 0x4D, EQF_WRITE }, + { "PF1.40", 0x4E, EQF_WRITE }, + { "PF2.40", 0x4F, EQF_WRITE }, + { "RESP0.40", 0x50, EQF_WRITE }, + { "RESP1.40", 0x51, EQF_WRITE }, + { "RESM0.40", 0x52, EQF_WRITE }, + { "RESM1.40", 0x53, EQF_WRITE }, + { "RESBL.40", 0x54, EQF_WRITE }, + { "AUDC0.40", 0x55, EQF_WRITE }, + { "AUDC1.40", 0x56, EQF_WRITE }, + { "AUDF0.40", 0x57, EQF_WRITE }, + { "AUDF1.40", 0x58, EQF_WRITE }, + { "AUDV0.40", 0x59, EQF_WRITE }, + { "AUDV1.40", 0x5A, EQF_WRITE }, + { "GRP0.40", 0x5B, EQF_WRITE }, + { "GRP1.40", 0x5C, EQF_WRITE }, + { "ENAM0.40", 0x5D, EQF_WRITE }, + { "ENAM1.40", 0x5E, EQF_WRITE }, + { "ENABL.40", 0x5F, EQF_WRITE }, + { "HMP0.40", 0x60, EQF_WRITE }, + { "HMP1.40", 0x61, EQF_WRITE }, + { "HMM0.40", 0x62, EQF_WRITE }, + { "HMM1.40", 0x63, EQF_WRITE }, + { "HMBL.40", 0x64, EQF_WRITE }, + { "VDELP0.40", 0x65, EQF_WRITE }, + { "VDEL01.40", 0x66, EQF_WRITE }, + { "VDELP1.40", 0x66, EQF_WRITE }, + { "VDELBL.40", 0x67, EQF_WRITE }, + { "RESMP0.40", 0x68, EQF_WRITE }, + { "RESMP1.40", 0x69, EQF_WRITE }, + { "HMOVE.40", 0x6A, EQF_WRITE }, + { "HMCLR.40", 0x6B, EQF_WRITE }, + { "CXCLR.40", 0x6C, EQF_WRITE }, + +// Standard $00-based TIA read locations: + { "CXM0P", 0x00, EQF_READ }, + { "CXM1P", 0x01, EQF_READ }, + { "CXP0FB", 0x02, EQF_READ }, + { "CXP1FB", 0x03, EQF_READ }, + { "CXM0FB", 0x04, EQF_READ }, + { "CXM1FB", 0x05, EQF_READ }, + { "CXBLPF", 0x06, EQF_READ }, + { "CXPPMM", 0x07, EQF_READ }, + { "INPT0", 0x08, EQF_READ }, + { "INPT1", 0x09, EQF_READ }, + { "INPT2", 0x0A, EQF_READ }, + { "INPT3", 0x0B, EQF_READ }, + { "INPT4", 0x0C, EQF_READ }, + { "INPT5", 0x0D, EQF_READ }, + +// Mirrored $10-based TIA read locations: + { "CXM0P.10", 0x10, EQF_READ }, + { "CXM1P.10", 0x11, EQF_READ }, + { "CXP0FB.10", 0x12, EQF_READ }, + { "CXP1FB.10", 0x13, EQF_READ }, + { "CXM0FB.10", 0x14, EQF_READ }, + { "CXM1FB.10", 0x15, EQF_READ }, + { "CXBLPF.10", 0x16, EQF_READ }, + { "CXPPMM.10", 0x17, EQF_READ }, + { "INPT0.10", 0x18, EQF_READ }, + { "INPT1.10", 0x19, EQF_READ }, + { "INPT2.10", 0x1A, EQF_READ }, + { "INPT3.10", 0x1B, EQF_READ }, + { "INPT4.10", 0x1C, EQF_READ }, + { "INPT5.10", 0x1D, EQF_READ }, + +// Mirrored $20-based TIA read locations: + { "CXM0P.20", 0x20, EQF_READ }, + { "CXM1P.20", 0x21, EQF_READ }, + { "CXP0FB.20", 0x22, EQF_READ }, + { "CXP1FB.20", 0x23, EQF_READ }, + { "CXM0FB.20", 0x24, EQF_READ }, + { "CXM1FB.20", 0x25, EQF_READ }, + { "CXBLPF.20", 0x26, EQF_READ }, + { "CXPPMM.20", 0x27, EQF_READ }, + { "INPT0.20", 0x28, EQF_READ }, + { "INPT1.20", 0x29, EQF_READ }, + { "INPT2.20", 0x2A, EQF_READ }, + { "INPT3.20", 0x2B, EQF_READ }, + { "INPT4.20", 0x2C, EQF_READ }, + { "INPT5.20", 0x2D, EQF_READ }, + +// Mirrored $30-based TIA read locations: + { "CXM0P.30", 0x30, EQF_READ }, + { "CXM1P.30", 0x31, EQF_READ }, + { "CXP0FB.30", 0x32, EQF_READ }, + { "CXP1FB.30", 0x33, EQF_READ }, + { "CXM0FB.30", 0x34, EQF_READ }, + { "CXM1FB.30", 0x35, EQF_READ }, + { "CXBLPF.30", 0x36, EQF_READ }, + { "CXPPMM.30", 0x37, EQF_READ }, + { "INPT0.30", 0x38, EQF_READ }, + { "INPT1.30", 0x39, EQF_READ }, + { "INPT2.30", 0x3A, EQF_READ }, + { "INPT3.30", 0x3B, EQF_READ }, + { "INPT4.30", 0x3C, EQF_READ }, + { "INPT5.30", 0x3D, EQF_READ }, + +// Standard RIOT locations (read, write, or both): + { "SWCHA", 0x280, EQF_RW }, + { "SWCHB", 0x282, EQF_RW }, + { "SWACNT", 0x281, EQF_WRITE }, + { "SWBCNT", 0x283, EQF_WRITE }, + { "INTIM", 0x284, EQF_READ }, + { "TIMINT", 0x285, EQF_READ }, + { "TIM1T", 0x294, EQF_WRITE }, + { "TIM8T", 0x295, EQF_WRITE }, + { "TIM64T", 0x296, EQF_WRITE }, + { "T1024T", 0x297, EQF_WRITE } +}; + +/////////////////////////////////////////////////////////////////// +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +CartDebug::AddressingMode CartDebug::AddressModeTable[256] = { + Implied, IndirectX, Invalid, IndirectX, // 0x0? + Zero, Zero, Zero, Zero, + Implied, Immediate, Implied, Immediate, + Absolute, Absolute, Absolute, Absolute, + + Relative, IndirectY, Invalid, IndirectY, // 0x1? + ZeroX, ZeroX, ZeroX, ZeroX, + Implied, AbsoluteY, Implied, AbsoluteY, + AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX, + + Absolute, IndirectX, Invalid, IndirectX, // 0x2? + Zero, Zero, Zero, Zero, + Implied, Immediate, Implied, Immediate, + Absolute, Absolute, Absolute, Absolute, + + Relative, IndirectY, Invalid, IndirectY, // 0x3? + ZeroX, ZeroX, ZeroX, ZeroX, + Implied, AbsoluteY, Implied, AbsoluteY, + AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX, + + Implied, IndirectX, Invalid, IndirectX, // 0x4? + Zero, Zero, Zero, Zero, + Implied, Immediate, Implied, Immediate, + Absolute, Absolute, Absolute, Absolute, + + Relative, IndirectY, Invalid, IndirectY, // 0x5? + ZeroX, ZeroX, ZeroX, ZeroX, + Implied, AbsoluteY, Implied, AbsoluteY, + AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX, + + Implied, IndirectX, Invalid, IndirectX, // 0x6? + Zero, Zero, Zero, Zero, + Implied, Immediate, Implied, Immediate, + Indirect, Absolute, Absolute, Absolute, + + Relative, IndirectY, Invalid, IndirectY, // 0x7? + ZeroX, ZeroX, ZeroX, ZeroX, + Implied, AbsoluteY, Implied, AbsoluteY, + AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX, + + Immediate, IndirectX, Immediate, IndirectX, // 0x8? + Zero, Zero, Zero, Zero, + Implied, Immediate, Implied, Immediate, + Absolute, Absolute, Absolute, Absolute, + + Relative, IndirectY, Invalid, IndirectY, // 0x9? + ZeroX, ZeroX, ZeroY, ZeroY, + Implied, AbsoluteY, Implied, AbsoluteY, + AbsoluteX, AbsoluteX, AbsoluteY, AbsoluteY, + + Immediate, IndirectX, Immediate, IndirectX, // 0xA? + Zero, Zero, Zero, Zero, + Implied, Immediate, Implied, Immediate, + Absolute, Absolute, Absolute, Absolute, + + Relative, IndirectY, Invalid, IndirectY, // 0xB? + ZeroX, ZeroX, ZeroY, ZeroY, + Implied, AbsoluteY, Implied, AbsoluteY, + AbsoluteX, AbsoluteX, AbsoluteY, AbsoluteY, + + Immediate, IndirectX, Immediate, IndirectX, // 0xC? + Zero, Zero, Zero, Zero, + Implied, Immediate, Implied, Immediate, + Absolute, Absolute, Absolute, Absolute, + + Relative, IndirectY, Invalid, IndirectY, // 0xD? + ZeroX, ZeroX, ZeroX, ZeroX, + Implied, AbsoluteY, Implied, AbsoluteY, + AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX, + + Immediate, IndirectX, Immediate, IndirectX, // 0xE? + Zero, Zero, Zero, Zero, + Implied, Immediate, Implied, Immediate, + Absolute, Absolute, Absolute, Absolute, + + Relative, IndirectY, Invalid, IndirectY, // 0xF? + ZeroX, ZeroX, ZeroX, ZeroX, + Implied, AbsoluteY, Implied, AbsoluteY, + AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +CartDebug::AccessMode CartDebug::AccessModeTable[256] = { + None, Read, None, Write, // 0x0? + None, Read, Write, Write, + None, Read, Write, Read, + None, Read, Write, Write, + + Read, Read, None, Write, // 0x1? + None, Read, Write, Write, + None, Read, None, Write, + None, Read, Write, Write, + + Read, Read, None, Write, // 0x2? + Read, Read, Write, Write, + None, Read, Write, Read, + Read, Read, Write, Write, + + Read, Read, None, Write, // 0x3? + None, Read, Write, Write, + None, Read, None, Write, + None, Read, Write, Write, + + None, Read, None, Write, // 0x4? + None, Read, Write, Write, + None, Read, Write, Read, + Read, Read, Write, Write, + + Read, Read, None, Write, // 0x5? + None, Read, Write, Write, + None, Read, None, Write, + None, Read, Write, Write, + + None, Read, None, Write, // 0x6? + None, Read, Write, Write, + None, Read, Write, Read, + Read, Read, Write, Write, + + Read, Read, None, Write, // 0x7? + None, Read, Write, Write, + None, Read, None, Write, + None, Read, Write, Write, + + None, Write, None, Write, // 0x8? + Write, Write, Write, Write, + None, None, None, Read, + Write, Write, Write, Write, + + Read, Write, None, Write, // 0x9? + Write, Write, Write, Write, + None, Write, None, Write, + Write, Write, Write, Write, + + Read, Read, Read, Read, // 0xA? + Read, Read, Read, Read, + None, Read, None, Read, + Read, Read, Read, Read, + + Read, Read, None, Read, // 0xB? + Read, Read, Read, Read, + None, Read, None, Read, + Read, Read, Read, Read, + + Read, Read, None, Write, // 0xC? + Read, Read, Write, Write, + None, Read, None, Read, + Read, Read, Write, Write, + + Read, Read, None, Write, // 0xD? + None, Read, Write, Write, + None, Read, None, Write, + None, Read, Write, Write, + + Read, Read, None, Write, // 0xE? + Read, Read, Write, Write, + None, Read, None, Read, + Read, Read, Write, Write, + + Read, Read, None, Write, // 0xF? + None, Read, Write, Write, + None, Read, None, Write, + None, Read, Write, Write +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const char* CartDebug::InstructionMnemonicTable[256] = { + "BRK", "ORA", "n/a", "slo", "nop", "ORA", "ASL", "slo", // 0x0? + "PHP", "ORA", "ASLA", "anc", "nop", "ORA", "ASL", "slo", + + "BPL", "ORA", "n/a", "slo", "nop", "ORA", "ASL", "slo", // 0x1? + "CLC", "ORA", "nop", "slo", "nop", "ORA", "ASL", "slo", + + "JSR", "AND", "n/a", "rla", "BIT", "AND", "ROL", "rla", // 0x2? + "PLP", "AND", "ROLA", "anc", "BIT", "AND", "ROL", "rla", + + "BMI", "AND", "n/a", "rla", "nop", "AND", "ROL", "rla", // 0x3? + "SEC", "AND", "nop", "rla", "nop", "AND", "ROL", "rla", + + "RTI", "EOR", "n/a", "sre", "nop", "EOR", "LSR", "sre", // 0x4? + "PHA", "EOR", "LSRA", "asr", "JMP", "EOR", "LSR", "sre", + + "BVC", "EOR", "n/a", "sre", "nop", "EOR", "LSR", "sre", // 0x5? + "CLI", "EOR", "nop", "sre", "nop", "EOR", "LSR", "sre", + + "RTS", "ADC", "n/a", "rra", "nop", "ADC", "ROR", "rra", // 0x6? + "PLA", "ADC", "RORA", "arr", "JMP", "ADC", "ROR", "rra", + + "BVS", "ADC", "n/a", "rra", "nop", "ADC", "ROR", "rra", // 0x7? + "SEI", "ADC", "nop", "rra", "nop", "ADC", "ROR", "rra", + + "nop", "STA", "nop", "sax", "STY", "STA", "STX", "sax", // 0x8? + "DEY", "nop", "TXA", "ane", "STY", "STA", "STX", "sax", + + "BCC", "STA", "n/a", "sha", "STY", "STA", "STX", "sax", // 0x9? + "TYA", "STA", "TXS", "shs", "shy", "STA", "shx", "sha", + + "LDY", "LDA", "LDX", "lax", "LDY", "LDA", "LDX", "lax", // 0xA? + "TAY", "LDA", "TAX", "lxa", "LDY", "LDA", "LDX", "lax", + + "BCS", "LDA", "n/a", "lax", "LDY", "LDA", "LDX", "lax", // 0xB? + "CLV", "LDA", "TSX", "las", "LDY", "LDA", "LDX", "lax", + + "CPY", "CMP", "nop", "dcp", "CPY", "CMP", "DEC", "dcp", // 0xC? + "INY", "CMP", "DEX", "sbx", "CPY", "CMP", "DEC", "dcp", + + "BNE", "CMP", "n/a", "dcp", "nop", "CMP", "DEC", "dcp", // 0xD? + "CLD", "CMP", "nop", "dcp", "nop", "CMP", "DEC", "dcp", + + "CPX", "SBC", "nop", "isb", "CPX", "SBC", "INC", "isb", // 0xE? + "INX", "SBC", "NOP", "sbc", "CPX", "SBC", "INC", "isb", + + "BEQ", "SBC", "n/a", "isb", "nop", "SBC", "INC", "isb", // 0xF? + "SED", "SBC", "nop", "isb", "nop", "SBC", "INC", "isb" +}; diff --git a/src/debugger/CartDebug.hxx b/src/debugger/CartDebug.hxx new file mode 100644 index 000000000..39c2a7a14 --- /dev/null +++ b/src/debugger/CartDebug.hxx @@ -0,0 +1,232 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2009 by Bradford W. Mott and the Stella team +// +// See the file "license" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +// +// $Id$ +//============================================================================ + +#ifndef CART_DEBUG_HXX +#define CART_DEBUG_HXX + +class System; + +#include "bspf.hxx" +#include "Array.hxx" +#include "Cart.hxx" +#include "DebuggerSystem.hxx" + +// pointer types for CartDebug instance methods +typedef int (CartDebug::*CARTDEBUG_INT_METHOD)(); + +// call the pointed-to method on the (global) CPU debugger object. +#define CALL_CARTDEBUG_METHOD(method) ( ( Debugger::debugger().cartDebug().*method)() ) + +class CartState : public DebuggerState +{ + public: + IntArray ram; // The actual data values + IntArray rport; // Address for reading from RAM + IntArray wport; // Address for writing to RAM +}; + +class CartDebug : public DebuggerSystem +{ + public: + struct DisassemblyTag { + int address; + string disasm; + string bytes; + }; + typedef Common::Array DisassemblyList; + + public: + CartDebug(Debugger& dbg, Console& console, const RamAreaList& areas); + + const DebuggerState& getState(); + const DebuggerState& getOldState() { return myOldState; } + + void saveOldState(); + string toString(); + + // The following assume that the given addresses are using the + // correct read/write port ranges; no checking will be done to + // confirm this. + uInt8 read(uInt16 addr); + void write(uInt16 addr, uInt8 value); + + // Return the address at which an invalid read was performed in a + // write port area. + int readFromWritePort(); + + // Indicate that a read from write port has occurred. + void triggerReadFromWritePort(uInt16 addr) { myRWPortAddress = addr; } + + /** + Let the Cart debugger subsystem treat this area as addressable memory. + + @param start The beginning of the RAM area (0x0000 - 0x2000) + @param size Total number of bytes of area + @param roffset Offset to use when reading from RAM (read port) + @param woffset Offset to use when writing to RAM (write port) + */ + void addRamArea(uInt16 start, uInt16 size, uInt16 roffset, uInt16 woffset); + +//////////////////////////////////////// + /** + Disassemble from the starting address the specified number of lines + and place result in a string. + */ + const string& disassemble(int start, int lines); + + /** + Disassemble from the starting address to the ending address + and place addresses, bytes and data in given arrays. + */ + void disassemble(IntArray& addr, StringList& addrLabel, + StringList& bytes, StringList& data, + int start, int end); + + int getBank(); + int bankCount(); + string getCartType(); +//////////////////////////////////////// + + /** + Add a label and associated address + */ + void addLabel(const string& label, uInt16 address); + + /** + Remove the given label and its associated address + */ + bool removeLabel(const string& label); + + /** + Accessor methods for labels and addresses + + The mapping from address to label can be one-to-many (ie, an + address can have different labels depending on its context, and + whether its being read or written; if isRead is true, the context + is a read, else it's a write + If places is not -1 and a label hasn't been defined, return a + formatted hexidecimal address + */ + const string& getLabel(uInt16 addr, bool isRead, int places = -1) const; + int getAddress(const string& label) const; + + /** + Load user equates from the given symbol file (generated by DASM) + */ + string loadSymbolFile(const string& file); + + /** + Save user equates into a symbol file similar to that generated by DASM + */ + bool saveSymbolFile(const string& file); + + /** + Methods used by the command parser for tab-completion + */ + int countCompletions(const char *in); + const string& getCompletions() const { return myCompletions; } + const string& getCompletionPrefix() const { return myCompPrefix; } + + private: + int disassemble(int address, string& result); + + private: + enum equate_t { + EQF_READ = 1 << 0, // address can be read from + EQF_WRITE = 1 << 1, // address can be written to + EQF_RW = EQF_READ | EQF_WRITE // address can be both read and written + }; + enum address_t { + ADDR_TIA = 1 << 0, + ADDR_RAM = 1 << 1, + ADDR_RIOT = 1 << 2, + ADDR_ROM = 1 << 3 + }; + struct Equate { + string label; + uInt16 address; + equate_t flags; + }; + + typedef map AddrToLabel; + typedef map LabelToAddr; + + private: + // Extract labels and values from the given character stream + string extractLabel(char *c) const; + int extractValue(char *c) const; + + // Count completions for the given mapping + int countCompletions(const char *in, LabelToAddr& addresses); + + private: + CartState myState; + CartState myOldState; + + DisassemblyList myDisassembly; + + LabelToAddr mySystemAddresses; + AddrToLabel mySystemReadLabels; // labels used in a read context + AddrToLabel mySystemWriteLabels; // labels used in a write context + + LabelToAddr myUserAddresses; + AddrToLabel myUserLabels; + + RamAreaList myRamAreas; + + string myCompletions; + string myCompPrefix; + + uInt16 myRWPortAddress; + + enum { kSystemEquateSize = 158 }; + static const Equate ourSystemEquates[kSystemEquateSize]; + +////////////////////////////////////////////// + /** + Enumeration of the 6502 addressing modes + */ + enum AddressingMode + { + Absolute, AbsoluteX, AbsoluteY, Immediate, Implied, + Indirect, IndirectX, IndirectY, Invalid, Relative, + Zero, ZeroX, ZeroY + }; + + /** + Enumeration of the 6502 access modes + */ + enum AccessMode + { + Read, Write, None + }; + + /// Addressing mode for each of the 256 opcodes + /// This specifies how the opcode argument is addressed + static AddressingMode AddressModeTable[256]; + + /// Access mode for each of the 256 opcodes + /// This specifies how the opcode will access its argument + static AccessMode AccessModeTable[256]; + + /// Table of instruction mnemonics + static const char* InstructionMnemonicTable[256]; +////////////////////////////////////////////// +}; + +#endif diff --git a/src/debugger/CpuDebug.cxx b/src/debugger/CpuDebug.cxx index 30cc3b817..9d936d146 100644 --- a/src/debugger/CpuDebug.cxx +++ b/src/debugger/CpuDebug.cxx @@ -19,8 +19,8 @@ #include #include "Array.hxx" -#include "EquateList.hxx" #include "M6502.hxx" +#include "CartDebug.hxx" #include "TIADebug.hxx" #include "CpuDebug.hxx" @@ -113,131 +113,10 @@ string CpuDebug::toString() result += buf; result += "\n "; - result += myDebugger.disassemble(state.PC, 1); + result += myDebugger.cartDebug().disassemble(state.PC, 1); return result; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int CpuDebug::disassemble(int address, string& result, EquateList& list) -{ - ostringstream buf; - int count = 0; - int opcode = mySystem.peek(address); - - // Are we looking at a read or write operation? - // It will determine what type of label to use - bool isRead = (M6502::AccessModeTable[opcode] == M6502::Read); - - switch(M6502::AddressModeTable[opcode]) - { - case M6502::Absolute: - buf << M6502::InstructionMnemonicTable[opcode] << " " - << list.getLabel(dpeek(mySystem, address + 1), isRead, 4) << " ; " - << M6502::InstructionCycleTable[opcode]; - count = 3; - break; - - case M6502::AbsoluteX: - buf << M6502::InstructionMnemonicTable[opcode] << " " - << list.getLabel(dpeek(mySystem, address + 1), isRead, 4) << ",x ; " - << M6502::InstructionCycleTable[opcode]; - count = 3; - break; - - case M6502::AbsoluteY: - buf << M6502::InstructionMnemonicTable[opcode] << " " - << list.getLabel(dpeek(mySystem, address + 1), isRead, 4) << ",y ; " - << M6502::InstructionCycleTable[opcode]; - count = 3; - break; - - case M6502::Immediate: - buf << M6502::InstructionMnemonicTable[opcode] << " #$" - << hex << setw(2) << setfill('0') << (int) mySystem.peek(address + 1) << " ; " - << dec << M6502::InstructionCycleTable[opcode]; - count = 2; - break; - - case M6502::Implied: - buf << M6502::InstructionMnemonicTable[opcode] << " ; " - << M6502::InstructionCycleTable[opcode]; - count = 1; - break; - - case M6502::Indirect: - buf << M6502::InstructionMnemonicTable[opcode] << " (" - << list.getLabel(dpeek(mySystem, address + 1), isRead, 4) << ") ; " - << M6502::InstructionCycleTable[opcode]; - count = 3; - break; - - case M6502::IndirectX: - buf << M6502::InstructionMnemonicTable[opcode] << " (" - << list.getLabel(mySystem.peek(address + 1), isRead, 2) << ",x) ; " - << M6502::InstructionCycleTable[opcode]; - count = 2; - break; - - case M6502::IndirectY: - buf << M6502::InstructionMnemonicTable[opcode] << " (" - << list.getLabel(mySystem.peek(address + 1), isRead, 2) << "),y ; " - << M6502::InstructionCycleTable[opcode]; - count = 2; - break; - - case M6502::Relative: - buf << M6502::InstructionMnemonicTable[opcode] << " " - << list.getLabel(address + 2 + ((Int16)(Int8)mySystem.peek(address + 1)), isRead, 4) - << " ; " << M6502::InstructionCycleTable[opcode]; - count = 2; - break; - - case M6502::Zero: - buf << M6502::InstructionMnemonicTable[opcode] << " " - << list.getLabel(mySystem.peek(address + 1), isRead, 2) << " ; " - << M6502::InstructionCycleTable[opcode]; - count = 2; - break; - - case M6502::ZeroX: - buf << M6502::InstructionMnemonicTable[opcode] << " " - << list.getLabel(mySystem.peek(address + 1), isRead, 2) << ",x ; " - << M6502::InstructionCycleTable[opcode]; - count = 2; - break; - - case M6502::ZeroY: - buf << M6502::InstructionMnemonicTable[opcode] << " " - << list.getLabel(mySystem.peek(address + 1), isRead, 2) << ",y ; " - << M6502::InstructionCycleTable[opcode]; - count = 2; - break; - - default: - buf << "dc $" << hex << setw(2) << setfill('0') << (int) opcode << " ; " - << dec << M6502::InstructionCycleTable[opcode]; - count = 1; - break; - } - - result = buf.str(); - return count; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// This doesn't really belong here (banks are Cart properties), but it -// makes like much easier for the expression parser. -int CpuDebug::getBank() -{ - return Debugger::debugger().getBank(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int CpuDebug::dPeek(int address) -{ - return dpeek(mySystem, address); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setPC(int pc) { diff --git a/src/debugger/CpuDebug.hxx b/src/debugger/CpuDebug.hxx index 19c407ea0..ca7940207 100644 --- a/src/debugger/CpuDebug.hxx +++ b/src/debugger/CpuDebug.hxx @@ -49,20 +49,16 @@ class CpuDebug : public DebuggerSystem void saveOldState(); string toString(); - // I know, we ain't supposed to do this... + // I know, we ain't supposed to do this... M6502& m6502() { return mySystem.m6502(); } - int disassemble(int address, string& result, EquateList& list); - int dPeek(int address); - int getBank(); - int pc() { return mySystem.m6502().PC; } int sp() { return mySystem.m6502().SP; } int a() { return mySystem.m6502().A; } int x() { return mySystem.m6502().X; } int y() { return mySystem.m6502().Y; } - // these return int, not boolean! + // These return int, not boolean! int n() { return mySystem.m6502().N; } int v() { return mySystem.m6502().V; } int b() { return mySystem.m6502().B; } @@ -94,12 +90,6 @@ class CpuDebug : public DebuggerSystem void toggleZ(); void toggleC(); - private: - static int dpeek(System& system, int address) - { - return system.peek(address) | (system.peek(address + 1) << 8); - } - private: CpuState myState; CpuState myOldState; diff --git a/src/debugger/Debugger.cxx b/src/debugger/Debugger.cxx index 81a26811f..1db450924 100644 --- a/src/debugger/Debugger.cxx +++ b/src/debugger/Debugger.cxx @@ -36,9 +36,8 @@ #include "M6502.hxx" #include "Cart.hxx" -#include "EquateList.hxx" +#include "CartDebug.hxx" #include "CpuDebug.hxx" -#include "RamDebug.hxx" #include "RiotDebug.hxx" #include "TIADebug.hxx" @@ -95,15 +94,14 @@ Debugger::Debugger(OSystem* osystem) myConsole(NULL), mySystem(NULL), myParser(NULL), + myCartDebug(NULL), myCpuDebug(NULL), - myRamDebug(NULL), myRiotDebug(NULL), myTiaDebug(NULL), myTiaInfo(NULL), myTiaOutput(NULL), myTiaZoom(NULL), myRom(NULL), - myEquateList(NULL), myBreakPoints(NULL), myReadTraps(NULL), myWriteTraps(NULL), @@ -138,12 +136,11 @@ Debugger::~Debugger() { delete myParser; + delete myCartDebug; delete myCpuDebug; - delete myRamDebug; delete myRiotDebug; delete myTiaDebug; - delete myEquateList; delete myBreakPoints; delete myReadTraps; delete myWriteTraps; @@ -193,12 +190,11 @@ void Debugger::setConsole(Console* console) delete myCpuDebug; myCpuDebug = new CpuDebug(*this, *myConsole); - delete myRamDebug; - myRamDebug = new RamDebug(*this, *myConsole); - + delete myCartDebug; // Register any RAM areas in the Cartridge - // Zero-page RAM is automatically recognized by RamDebug - myRamDebug->addRamArea(myConsole->cartridge().ramAreas()); + // Zero-page RAM is automatically recognized by CartDebug + myCartDebug = new CartDebug(*this, *myConsole, myConsole->cartridge().ramAreas()); + myCartDebug->loadSymbolFile(myOSystem->romFile()); delete myRiotDebug; myRiotDebug = new RiotDebug(*this, *myConsole); @@ -206,14 +202,12 @@ void Debugger::setConsole(Console* console) delete myTiaDebug; myTiaDebug = new TIADebug(*this, *myConsole); - // Initialize equates and breakpoints to known state - delete myEquateList; - myEquateList = new EquateList(); + // Initialize breakpoints to known state clearAllBreakPoints(); clearAllTraps(); - autoLoadSymbols(myOSystem->romFile()); - loadListFile(); +// FIXME - these will probably be removed +// loadListFile(); // Make sure cart RAM is added before this is called, // otherwise the debugger state won't know about it @@ -243,21 +237,7 @@ void Debugger::quit() myOSystem->eventHandler().leaveDebugMode(); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Debugger::autoLoadSymbols(string fileName) -{ - string file = fileName; - - string::size_type pos; - if( (pos = file.find_last_of('.')) != string::npos ) - file.replace(pos, file.size(), ".sym"); - else - file += ".sym"; - - string ret = myEquateList->loadFile(file); - // cerr << "loading syms from file " << file << ": " << ret << endl; -} - +#if 0 // FIXME - remove this // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Debugger::loadListFile(string f) { @@ -335,6 +315,7 @@ string Debugger::getSourceLines(int addr) const else return ""; } +#endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::autoExec() @@ -431,8 +412,7 @@ const string Debugger::invIfChanged(int reg, int oldReg) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::reset() { - int pc = myCpuDebug->dPeek(0xfffc); - myCpuDebug->setPC(pc); + myCpuDebug->setPC(dpeek(0xfffc)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -579,61 +559,6 @@ int Debugger::cycles() return mySystem->cycles(); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const string& Debugger::disassemble(int start, int lines) -{ - static string result; - ostringstream buffer; - string cpubuf; - - do { - buffer << myEquateList->getLabel(start, true, 4) << ": "; - - int count = myCpuDebug->disassemble(start, cpubuf, *myEquateList); - for(int i = 0; i < count; i++) - buffer << hex << setw(2) << setfill('0') << peek(start++) << dec; - - if(count < 3) buffer << " "; - if(count < 2) buffer << " "; - - buffer << " " << cpubuf << "\n"; - } while(--lines > 0 && start <= 0xffff); - - result = buffer.str(); - return result; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Debugger::disassemble(IntArray& addr, StringList& addrLabel, - StringList& bytes, StringList& data, - int start, int end) -{ - if(start < 0x80 || end > 0xffff) - return; - - string cpubuf, tmp; - char buf[255]; - - do - { - addrLabel.push_back(myEquateList->getLabel(start, true, 4) + ":"); - addr.push_back(start); - - cpubuf = ""; - int count = myCpuDebug->disassemble(start, cpubuf, *myEquateList); - - tmp = ""; - for(int i=0; im6502().setTraps(NULL, NULL); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int Debugger::peek(int addr) -{ - return mySystem->peek(addr); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int Debugger::dpeek(int addr) -{ - return mySystem->peek(addr) | (mySystem->peek(addr+1) << 8); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Debugger::showWatches() { return myParser->showWatches(); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Debugger::addLabel(string label, int address) -{ - myEquateList->addEquate(label, address); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::reloadROM() { @@ -729,24 +636,6 @@ bool Debugger::setBank(int bank) return false; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int Debugger::getBank() -{ - return myConsole->cartridge().bank(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int Debugger::bankCount() -{ - return myConsole->cartridge().bankCount(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string Debugger::getCartType() -{ - return myConsole->cartridge().name(); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::patchROM(int addr, int value) { @@ -756,8 +645,8 @@ bool Debugger::patchROM(int addr, int value) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::saveOldState(bool addrewind) { + myCartDebug->saveOldState(); myCpuDebug->saveOldState(); - myRamDebug->saveOldState(); myRiotDebug->saveOldState(); myTiaDebug->saveOldState(); diff --git a/src/debugger/Debugger.hxx b/src/debugger/Debugger.hxx index 492e48f11..7c2beaa95 100644 --- a/src/debugger/Debugger.hxx +++ b/src/debugger/Debugger.hxx @@ -22,8 +22,8 @@ class OSystem; class Console; class System; +class CartDebug; class CpuDebug; -class RamDebug; class RiotDebug; class TIADebug; class TiaInfoWidget; @@ -40,7 +40,6 @@ class Serializer; #include "DialogContainer.hxx" #include "M6502.hxx" #include "DebuggerParser.hxx" -#include "EquateList.hxx" #include "PackedBitArray.hxx" #include "PromptWidget.hxx" #include "Rect.hxx" @@ -136,9 +135,9 @@ class Debugger : public DialogContainer CpuDebug& cpuDebug() const { return *myCpuDebug; } /** - The debugger subsystem responsible for all RAM state + The debugger subsystem responsible for all Cart RAM/ROM state */ - RamDebug& ramDebug() const { return *myRamDebug; } + CartDebug& cartDebug() const { return *myCartDebug; } /** The debugger subsystem responsible for all RIOT state @@ -150,11 +149,6 @@ class Debugger : public DialogContainer */ TIADebug& tiaDebug() const { return *myTiaDebug; } - /** - List of English-like aliases for 6502 opcodes and operands. - */ - EquateList& equates() const { return *myEquateList; } - DebuggerParser& parser() const { return *myParser; } PackedBitArray& breakpoints() const { return *myBreakPoints; } PackedBitArray& readtraps() const { return *myReadTraps; } @@ -170,20 +164,6 @@ class Debugger : public DialogContainer */ int cycles(); - /** - Disassemble from the starting address the specified number of lines - and place result in a string. - */ - const string& disassemble(int start, int lines); - - /** - Disassemble from the starting address to the ending address - and place addresses, bytes and data in given arrays. - */ - void disassemble(IntArray& addr, StringList& addrLabel, - StringList& bytes, StringList& data, - int start, int end); - void autoExec(); string showWatches(); @@ -292,17 +272,11 @@ class Debugger : public DialogContainer GUI::Rect getTabBounds() const; /* These are now exposed so Expressions can use them. */ - int peek(int addr); - int dpeek(int addr); - int getBank(); - int bankCount(); + int peek(int addr) { return mySystem->peek(addr); } + int dpeek(int addr) { return mySystem->peek(addr) | (mySystem->peek(addr+1) << 8); } void setBreakPoint(int bp, bool set); - string loadListFile(string f = ""); - string getSourceLines(int addr) const; - bool haveListFile() const { return sourceLines.size() > 0; } - bool saveROM(const string& filename) const; bool setBank(int bank); @@ -357,26 +331,20 @@ class Debugger : public DialogContainer const string setRAM(IntArray& args); void reset(); - void autoLoadSymbols(string file); void clearAllBreakPoints(); PromptWidget *prompt() { return myPrompt; } - void addLabel(string label, int address); - string getCartType(); void saveState(int state); void loadState(int state); private: - typedef multimap ListFile; - typedef ListFile::const_iterator ListIter; - Console* myConsole; System* mySystem; DebuggerParser* myParser; + CartDebug* myCartDebug; CpuDebug* myCpuDebug; - RamDebug* myRamDebug; RiotDebug* myRiotDebug; TIADebug* myTiaDebug; @@ -386,14 +354,11 @@ class Debugger : public DialogContainer RomWidget* myRom; EditTextWidget* myMessage; - EquateList* myEquateList; PackedBitArray* myBreakPoints; PackedBitArray* myReadTraps; PackedBitArray* myWriteTraps; PromptWidget* myPrompt; - ListFile sourceLines; - static Debugger* myStaticDebugger; FunctionMap functions; diff --git a/src/debugger/DebuggerExpressions.hxx b/src/debugger/DebuggerExpressions.hxx index b8eb36ba0..3eba0e01b 100644 --- a/src/debugger/DebuggerExpressions.hxx +++ b/src/debugger/DebuggerExpressions.hxx @@ -20,8 +20,8 @@ #define DEBUGGER_EXPRESSIONS_HXX #include "bspf.hxx" +#include "CartDebug.hxx" #include "CpuDebug.hxx" -#include "RamDebug.hxx" #include "TIADebug.hxx" #include "Debugger.hxx" #include "Expression.hxx" @@ -124,7 +124,7 @@ class EquateExpression : public Expression { public: EquateExpression(const string& label) : Expression(0, 0), myLabel(label) {} - uInt16 evaluate() { return Debugger::debugger().equates().getAddress(myLabel); } + uInt16 evaluate() { return Debugger::debugger().cartDebug().getAddress(myLabel); } private: string myLabel; @@ -260,14 +260,14 @@ class PlusExpression : public Expression }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -class RamMethodExpression : public Expression +class CartMethodExpression : public Expression { public: - RamMethodExpression(RAMDEBUG_INT_METHOD method) : Expression(0, 0), myMethod(method) {} - uInt16 evaluate() { return CALL_RAMDEBUG_METHOD(myMethod); } + CartMethodExpression(CARTDEBUG_INT_METHOD method) : Expression(0, 0), myMethod(method) {} + uInt16 evaluate() { return CALL_CARTDEBUG_METHOD(myMethod); } private: - RAMDEBUG_INT_METHOD myMethod; + CARTDEBUG_INT_METHOD myMethod; }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index 613fc2e5f..6a13fdfc7 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -22,8 +22,8 @@ #include "Dialog.hxx" #include "Debugger.hxx" +#include "CartDebug.hxx" #include "CpuDebug.hxx" -#include "RamDebug.hxx" #include "RiotDebug.hxx" #include "TIADebug.hxx" #include "DebuggerParser.hxx" @@ -266,8 +266,8 @@ int DebuggerParser::decipher_arg(const string &str) else if(arg == "s") result = state.SP; else if(arg == "pc" || arg == ".") result = state.PC; else { // Not a special, must be a regular arg: check for label first - const char *a = arg.c_str(); - result = debugger->equates().getAddress(arg); + const char* a = arg.c_str(); + result = debugger->cartDebug().getAddress(arg); if(result < 0) { // if not label, must be a number if(bin) { // treat as binary @@ -562,7 +562,7 @@ string DebuggerParser::eval() string ret; for(int i=0; iequates().getLabel(args[i], true); + const string& label = debugger->cartDebug().getLabel(args[i], true); if(label != "") { ret += label; ret += ": "; @@ -602,7 +602,7 @@ string DebuggerParser::trapStatus(int addr) result += " none "; // TODO - technically, we should determine if the label is read or write - const string& l = debugger->equates().getLabel(addr, true); + const string& l = debugger->cartDebug().getLabel(addr, true); if(l != "") { result += " ("; result += l; @@ -668,14 +668,14 @@ void DebuggerParser::executeA() // "bank" void DebuggerParser::executeBank() { - int banks = debugger->bankCount(); + int banks = debugger->cartDebug().bankCount(); if(argCount == 0) { - commandResult += debugger->getCartType(); + commandResult += debugger->cartDebug().getCartType(); commandResult += ": "; if(banks < 2) commandResult += red("bankswitching not supported by this cartridge"); else { - commandResult += debugger->valueToString(debugger->getBank()); + commandResult += debugger->valueToString(debugger->cartDebug().getBank()); commandResult += "/"; commandResult += debugger->valueToString(banks); } @@ -844,7 +844,7 @@ void DebuggerParser::executeD() void DebuggerParser::executeDefine() { // TODO: check if label already defined? - debugger->addLabel(argStrings[0], args[1]); + debugger->cartDebug().addLabel(argStrings[0], args[1]); debugger->myRom->invalidate(); commandResult = "label " + argStrings[0] + " defined as " + debugger->valueToString(args[1]); } @@ -888,7 +888,7 @@ void DebuggerParser::executeDisasm() return; } - commandResult = debugger->disassemble(start, lines); + commandResult = debugger->cartDebug().disassemble(start, lines); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -971,17 +971,6 @@ void DebuggerParser::executeFunction() } } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// "list" -void DebuggerParser::executeList() -{ - if(!debugger->haveListFile()) - commandResult = "no list file loaded (try \"loadlist file.lst\")"; - - for(int i=args[0] - 2; igetSourceLines(i); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "listbreaks" void DebuggerParser::executeListbreaks() @@ -993,7 +982,7 @@ void DebuggerParser::executeListbreaks() { if(debugger->breakpoints().isSet(i)) { - buf << debugger->equates().getLabel(i, true, 4) << " "; + buf << debugger->cartDebug().getLabel(i, true, 4) << " "; if(! (++count % 8) ) buf << "\n"; } } @@ -1061,18 +1050,11 @@ void DebuggerParser::executeLoadstate() } } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// "loadlist" -void DebuggerParser::executeLoadlist() -{ - commandResult = debugger->loadListFile(argStrings[0]); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "loadsym" void DebuggerParser::executeLoadsym() { - commandResult = debugger->equates().loadFile(argStrings[0]); + commandResult = debugger->cartDebug().loadSymbolFile(argStrings[0]); debugger->myRom->invalidate(); } @@ -1105,7 +1087,7 @@ void DebuggerParser::executePrint() void DebuggerParser::executeRam() { if(argCount == 0) - commandResult = debugger->ramDebug().toString(); + commandResult = debugger->cartDebug().toString(); else commandResult = debugger->setRAM(args); } @@ -1178,7 +1160,7 @@ void DebuggerParser::executeRunTo() do { cycles += debugger->step(); - string next = debugger->disassemble(debugger->cpuDebug().pc(), 1); + string next = debugger->cartDebug().disassemble(debugger->cpuDebug().pc(), 1); done = (next.find(argStrings[0]) != string::npos); ++count; } while(!done && count < 10000); @@ -1246,7 +1228,7 @@ void DebuggerParser::executeSavestate() // "savesym" void DebuggerParser::executeSavesym() { - if(debugger->equates().saveFile(argStrings[0])) + if(debugger->cartDebug().saveSymbolFile(argStrings[0])) commandResult = "saved symbols to file " + argStrings[0]; else commandResult = red("I/O error"); @@ -1321,7 +1303,7 @@ void DebuggerParser::executeTrapwrite() // "undef" void DebuggerParser::executeUndef() { - if(debugger->equates().removeEquate(argStrings[0])) + if(debugger->cartDebug().removeLabel(argStrings[0])) { debugger->myRom->invalidate(); commandResult = argStrings[0] + " now undefined"; @@ -1565,15 +1547,6 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = { &DebuggerParser::executeHelp }, - { - "list", - "List source (if loaded with loadlist)", - true, - false, - { kARG_WORD, kARG_END_ARGS }, - &DebuggerParser::executeList - }, - { "listbreaks", "List breakpoints", @@ -1601,15 +1574,6 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = { &DebuggerParser::executeListwatches }, - { - "loadlist", - "Load DASM listing file", - true, - true, - { kARG_FILE, kARG_END_ARGS }, - &DebuggerParser::executeLoadlist - }, - { "loadstate", "Load emulator state (0-9)", diff --git a/src/debugger/DebuggerParser.hxx b/src/debugger/DebuggerParser.hxx index 1d36fd444..377d53879 100644 --- a/src/debugger/DebuggerParser.hxx +++ b/src/debugger/DebuggerParser.hxx @@ -81,7 +81,7 @@ class DebuggerParser private: enum { - kNumCommands = 58, + kNumCommands = 56, kMAX_ARG_TYPES = 10 // TODO: put in separate header file Command.hxx }; @@ -157,11 +157,9 @@ class DebuggerParser void executeFrame(); void executeFunction(); void executeHelp(); - void executeList(); void executeListbreaks(); void executeListtraps(); void executeListwatches(); - void executeLoadlist(); void executeLoadstate(); void executeLoadsym(); void executeN(); diff --git a/src/debugger/DiStella.cxx b/src/debugger/DiStella.cxx new file mode 100644 index 000000000..0ba956b2c --- /dev/null +++ b/src/debugger/DiStella.cxx @@ -0,0 +1,1360 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2009 by Bradford W. Mott and the Stella team +// +// See the file "license" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +// +// $Id$ +//============================================================================ + +#include +#include +#include +#include + +#include "bspf.hxx" +//#include "CartDebug.hxx" +#include "DiStella.hxx" + +static void ADD_ENTRY(DisassemblyList& list, int address, const char* disasm, const char* bytes) +{ + DisassemblyTag t; + t.address = address; + t.disasm = disasm; + t.bytes = bytes; + list.push_back(t); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +DiStella::DiStella() + : mem(NULL), /* copied data from the file-- can be from 2K-48K bytes in size */ + labels(NULL) /* array of information about addresses-- can be from 2K-48K bytes in size */ +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +DiStella::~DiStella() +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int DiStella::disassemble(DisassemblyList& list, const char* datafile) +{ + while(!myAddressQueue.empty()) + myAddressQueue.pop(); + + app_data.start = 0x0; + app_data.load = 0x0000; + app_data.length = 0; + app_data.end = 0x0FFF; + app_data.disp_data = 0; + + /* Flag defaults */ + cflag = 0; + dflag = 1; + + if (!file_load(datafile)) + { + fprintf(stderr,"Unable to load %s\n", datafile); + return -1; + } + + /*====================================*/ + /* Allocate memory for "labels" variable */ + labels=(uInt8*) malloc(app_data.length); + if (labels == NULL) + { + fprintf (stderr, "Malloc failed for 'labels' variable\n"); + return -1; + } + memset(labels,0,app_data.length); + /*====================================*/ + + + /*----------------------------------------------------- + The last 3 words of a program are as follows: + + .word INTERRUPT (isr_adr) + .word START (start_adr) + .word BRKroutine (brk_adr) + + Since we always process START, move the Program + Counter 3 bytes back from the final byte. + -----------------------------------------------------*/ + + pc=app_data.end-3; + + start_adr=read_adr(); + + if (app_data.end == 0x7ff) /* 2K case */ + { + /*============================================ + What is the offset? Well, it's an address + where the code segment starts. For a 2K game, + it is usually 0xf800, which would then have the + code data end at 0xffff, but that is not + necessarily the case. Because the Atari 2600 + only has 13 address lines, it's possible that + the "code" can be considered to start in a lot + of different places. So, we use the start + address as a reference to determine where the + offset is, logically-anded to produce an offset + that is a multiple of 2K. + + Example: + Start address = $D973, so therefore + Offset to code = $D800 + Code range = $D800-$DFFF + =============================================*/ + offset=(start_adr & 0xf800); + } + else if (app_data.end == 0xfff) /* 4K case */ + { + /*============================================ + The offset is the address where the code segment + starts. For a 4K game, it is usually 0xf000, + which would then have the code data end at 0xffff, + but that is not necessarily the case. Because the + Atari 2600 only has 13 address lines, it's possible + that the "code" can be considered to start in a lot + of different places. So, we use the start + address as a reference to determine where the + offset is, logically-anded to produce an offset + that is a multiple of 4K. + + Example: + Start address = $D973, so therefore + Offset to code = $D000 + Code range = $D000-$DFFF + =============================================*/ + offset=(start_adr - (start_adr % 0x1000)); + } + +#if 0 + if (cflag && !load_config(config)) + { + fprintf(stderr,"Unable to load config file %s\n",config); + return -1; + } +#endif + + myAddressQueue.push(start_adr); + + if (dflag) + { + while(!myAddressQueue.empty()) + { + pc = myAddressQueue.front(); + pcbeg = pc; + myAddressQueue.pop(); + disasm(pc, 1, list); + for (int k = pcbeg; k <= pcend; k++) + mark(k, REACHABLE); + } + + for (int k = 0; k <= app_data.end; k++) + { + if (!check_bit(labels[k], REACHABLE)) + mark(k+offset, DATA); + } + } + + // Second pass + disasm(offset, 2, list); + +#if 0 + if (cflag) { + printf("; %s contents:\n;\n",config); + while (fgets(parms,79,cfg) != NULL) + printf("; %s",parms); + } + printf("\n"); +#endif + + /* Print Line equates on screen */ +#if 0 + for (int i = 0; i <= app_data.end; i++) + { + if ((labels[i] & (REFERENCED | VALID_ENTRY)) == REFERENCED) + { + /* so, if we have a piece of code referenced somewhere else, but cannot locate the label + in code (i.e because the address is inside of a multi-byte instruction, then we + print that address on screen for reference */ + printf("L%.4X = ",i+offset); + printf("$%.4X\n",i+offset); + } + } +#endif + + // Third pass + strcpy(linebuff,""); + strcpy(nextline,""); + disasm(offset, 3, list); + + free(labels); /* Free dynamic memory before program ends */ + free(mem); /* Free dynamic memory before program ends */ + +return 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt32 DiStella::filesize(FILE *stream) +{ + uInt32 curpos, length; + + curpos = ftell(stream); + fseek(stream, 0L, SEEK_END); + length = ftell(stream); + fseek(stream, curpos, SEEK_SET); + return length; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt32 DiStella::read_adr() +{ + uInt8 d1,d2; + + d1 = mem[pc++]; + d2 = mem[pc++]; + + return (uInt32) ((d2 << 8)+d1); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int DiStella::file_load(const char* file) +{ + FILE *fn; + + fn=fopen(file,"rb"); + if (fn == NULL) + return 0; + + if (app_data.length == 0) + app_data.length = filesize(fn); + + if (app_data.length == 2048) + app_data.end = 0x7ff; + else if (app_data.length == 4096) + app_data.end = 0xfff; + else + { + printf("Error: .bin file must be 2048 or 4096 bytes\n"); + exit(1); + } + + /*====================================*/ + /* Dynamically allocate memory for "mem" variable */ + mem=(uInt8 *)malloc(app_data.length); + if (mem == NULL) + { + printf ("Malloc failed for 'mem' variable\n"); + exit(1); + } + memset(mem,0,app_data.length); + /*====================================*/ + + rewind(fn); /* Point to beginning of file again */ + + /* if no header exists, just read in the file data */ + fread(&mem[app_data.load],1,app_data.length,fn); + + fclose(fn); /* Data is read in, so close the file */ + + if (app_data.start == 0) + app_data.start = app_data.load; + + return 1; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int DiStella::load_config(const char *file) +{ + char cfg_line[80]; + char cfg_tok[80]; + uInt32 cfg_beg, cfg_end; + + lineno=0; + + if ((cfg=fopen(file,"r")) == NULL) + return 0; + + cfg_beg=cfg_end=0; + + while (fgets(cfg_line,79,cfg)!=NULL) { + strcpy(cfg_tok,""); + sscanf(cfg_line,"%s %x %x",cfg_tok,&cfg_beg,&cfg_end); + if (!strcmp(cfg_tok,"DATA")) { + check_range(cfg_beg,cfg_end); + for(;cfg_beg<=cfg_end;) { + mark(cfg_beg,DATA); + if (cfg_beg == cfg_end) + cfg_end = 0; + else + cfg_beg++; + } + } else if (!strcmp(cfg_tok,"GFX")) { + check_range(cfg_beg,cfg_end); + for(;cfg_beg<=cfg_end;) { + mark(cfg_beg,GFX); + if (cfg_beg == cfg_end) + cfg_end = 0; + else + cfg_beg++; + } + } else if (!strcmp(cfg_tok,"ORG")) { + offset = cfg_beg; + } else if (!strcmp(cfg_tok,"CODE")) { + check_range(cfg_beg,cfg_end); + for(;cfg_beg<=cfg_end;) { + mark(cfg_beg,REACHABLE); + if (cfg_beg == cfg_end) + cfg_end = 0; + else + cfg_beg++; + } + } else { + fprintf(stderr,"Invalid line in config file - line %d ignored\n",lineno); + } + } + rewind(cfg); + return 1; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void DiStella::check_range(uInt32 beg, uInt32 end) +{ + lineno++; + if (beg > end) { + fprintf(stderr,"Beginning of range greater than End in config file in line %d\n",lineno); + exit(1); + } + + if (beg > app_data.end + offset) { + fprintf(stderr,"Beginning of range out of range in line %d\n",lineno); + exit(1); + } + + if (beg < offset) { + fprintf(stderr,"Beginning of range out of range in line %d\n",lineno); + exit(1); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void DiStella::disasm(uInt32 distart, int pass, DisassemblyList& list) +{ + uInt8 op, d1, opsrc; + uInt32 ad; + short amode; + int i, bytes, labfound, addbranch; + + /* pc=app_data.start; */ + pc = distart - offset; +//cerr << " ==> pc = " << pc << "(" << pass << ")" << endl; + while(pc <= app_data.end) + { +#if 0 + if(pass == 3) + { + if (pc+offset == start_adr) + printf("START:\n"); + } +#endif + if(check_bit(labels[pc], GFX)) + /* && !check_bit(labels[pc], REACHABLE))*/ + { + if (pass == 2) + mark(pc+offset,VALID_ENTRY); + else if (pass == 3) + { + if (check_bit(labels[pc],REFERENCED)) + printf("L%.4X: ",pc+offset); + else + printf(" "); + + printf(".byte $%.2X ; ",mem[pc]); + showgfx(mem[pc]); + printf(" $%.4X\n",pc+offset); + } + pc++; + } + else if (check_bit(labels[pc], DATA) && !check_bit(labels[pc], GFX)) + /* && !check_bit(labels[pc],REACHABLE)) { */ + { + mark(pc+offset, VALID_ENTRY); + if (pass == 3) + { + bytes = 1; + printf("L%.4X: .byte ",pc+offset); + printf("$%.2X",mem[pc]); + } + pc++; + + while (check_bit(labels[pc], DATA) && !check_bit(labels[pc], REFERENCED) + && !check_bit(labels[pc], GFX) && pass == 3 && pc <= app_data.end) + { + if (pass == 3) + { + bytes++; + if (bytes == 17) + { + printf("\n .byte $%.2X",mem[pc]); + bytes = 1; + } + else + printf(",$%.2X",mem[pc]); + } + pc++; + } + + if (pass == 3) + printf("\n"); + } + else + { + op = mem[pc]; + /* version 2.1 bug fix */ + if (pass == 2) + mark(pc+offset, VALID_ENTRY); + else if (pass == 3) + { + if (check_bit(labels[pc], REFERENCED)) + printf("L%.4X: ", pc+offset); + else + printf(" "); + } + + amode = ourLookup[op].addr_mode; + if (app_data.disp_data) + { + for (i = 0; i < ourCLength[amode]; i++) + if (pass == 3) + printf("%02X ",mem[pc+i]); + + if (pass == 3) + printf(" "); + } + + pc++; + + if (ourLookup[op].mnemonic[0] == '.') + { + amode = IMPLIED; + if (pass == 3) + { + sprintf(linebuff,".byte $%.2X ;",op); + strcat(nextline,linebuff); + } + } + + if (pass == 1) + { + opsrc = ourLookup[op].source; + /* M_REL covers BPL, BMI, BVC, BVS, BCC, BCS, BNE, BEQ + M_ADDR = JMP $NNNN, JSR $NNNN + M_AIND = JMP Abs, Indirect */ + if ((opsrc == M_REL) || (opsrc == M_ADDR) || (opsrc == M_AIND)) + addbranch = 1; + else + addbranch = 0; + } + else if (pass == 3) + { + sprintf(linebuff,"%s",ourLookup[op].mnemonic); + strcat(nextline,linebuff); + } + + if (pc >= app_data.end) + { + switch(amode) + { + case ABSOLUTE: + case ABSOLUTE_X: + case ABSOLUTE_Y: + case INDIRECT_X: + case INDIRECT_Y: + case ABS_INDIRECT: + { + if (pass == 3) + { + /* Line information is already printed; append .byte since last instruction will + put recompilable object larger that original binary file */ + printf(".byte $%.2X\n",op); + + if (pc == app_data.end) + { + if (check_bit(labels[pc],REFERENCED)) + printf("L%.4X: ",pc+offset); + else + printf(" "); + + op = mem[pc++]; + printf(".byte $%.2X\n",op); + } + } + pcend = app_data.end + offset; + return; + } + + case ZERO_PAGE: + case IMMEDIATE: + case ZERO_PAGE_X: + case ZERO_PAGE_Y: + case RELATIVE: + { + if (pc > app_data.end) + { + if (pass == 3) + { + /* Line information is already printed, but we can remove the + Instruction (i.e. BMI) by simply clearing the buffer to print */ + strcpy(nextline,""); + sprintf(linebuff,".byte $%.2X",op); + strcat(nextline,linebuff); + + printf("%s",nextline); + printf("\n"); + strcpy(nextline,""); + } + pc++; + pcend = app_data.end + offset; + return; + } + } + + default: + break; + } + } + + /* Version 2.1 added the extensions to mnemonics */ + switch(amode) + { + #if 0 + case IMPLIED: + { + if (op == 0x40 || op == 0x60) + if (pass == 3) + { + sprintf(linebuff,"\n"); + strcat(nextline,linebuff); + } + break; + } + #endif + case ACCUMULATOR: + { + if (pass == 3) + sprintf(linebuff," A"); + + strcat(nextline,linebuff); + break; + } + + case ABSOLUTE: + { + ad = read_adr(); + labfound = mark(ad, REFERENCED); + if (pass == 1) + { + if ((addbranch) && !check_bit(labels[ad & app_data.end], REACHABLE)) + { + if (ad > 0xfff) + myAddressQueue.push((ad & app_data.end) + offset); + + mark(ad, REACHABLE); + } + } + else if (pass == 3) + { + if (ad < 0x100) + { + sprintf(linebuff,".w "); + strcat(nextline,linebuff); + } + else + { + sprintf(linebuff," "); + strcat(nextline,linebuff); + } + if (labfound == 1) + { + sprintf(linebuff,"L%.4X",ad); + strcat(nextline,linebuff); + } + else if (labfound == 3) + { + sprintf(linebuff,"%s",ourIOMnemonic[ad-0x280]); + strcat(nextline,linebuff); + } + else if (labfound == 4) + { + sprintf(linebuff,"L%.4X",(ad & app_data.end)+offset); + strcat(nextline,linebuff); + } + else + { + sprintf(linebuff,"$%.4X",ad); + strcat(nextline,linebuff); + } + } + break; + } + + case ZERO_PAGE: + { + d1 = mem[pc++]; + labfound = mark(d1, REFERENCED); + if (pass == 3) + { + if (labfound == 2) + { + sprintf(linebuff," %s", ourTIAMnemonic[d1]); + strcat(nextline,linebuff); + } + else + { + sprintf(linebuff," $%.2X ",d1); + strcat(nextline,linebuff); + } + } + break; + } + + case IMMEDIATE: + { + d1 = mem[pc++]; + if (pass == 3) + { + sprintf(linebuff," #$%.2X ",d1); + strcat(nextline,linebuff); + } + break; + } + + case ABSOLUTE_X: + { + ad = read_adr(); + labfound = mark(ad, REFERENCED); + if (pass == 3) + { + if (ad < 0x100) + { + sprintf(linebuff,".wx "); + strcat(nextline,linebuff); + } + else + { + sprintf(linebuff," "); + strcat(nextline,linebuff); + } + + if (labfound == 1) + { + sprintf(linebuff,"L%.4X,X",ad); + strcat(nextline,linebuff); + } + else if (labfound == 3) + { + sprintf(linebuff,"%s,X",ourIOMnemonic[ad-0x280]); + strcat(nextline,linebuff); + } + else if (labfound == 4) + { + sprintf(linebuff,"L%.4X,X",(ad & app_data.end)+offset); + strcat(nextline,linebuff); + } + else + { + sprintf(linebuff,"$%.4X,X",ad); + strcat(nextline,linebuff); + } + } + break; + } + + case ABSOLUTE_Y: + { + ad = read_adr(); + labfound = mark(ad, REFERENCED); + if (pass == 3) + { + if (ad < 0x100) + { + sprintf(linebuff,".wy "); + strcat(nextline,linebuff); + } + else + { + sprintf(linebuff," "); + strcat(nextline,linebuff); + } + if (labfound == 1) + { + sprintf(linebuff,"L%.4X,Y",ad); + strcat(nextline,linebuff); + } + else if (labfound == 3) + { + sprintf(linebuff,"%s,Y",ourIOMnemonic[ad-0x280]); + strcat(nextline,linebuff); + } + else if (labfound == 4) + { + sprintf(linebuff,"L%.4X,Y",(ad & app_data.end)+offset); + strcat(nextline,linebuff); + } + else + { + sprintf(linebuff,"$%.4X,Y",ad); + strcat(nextline,linebuff); + } + } + break; + } + + case INDIRECT_X: + { + d1 = mem[pc++]; + if (pass == 3) + { + sprintf(linebuff," ($%.2X,X)",d1); + strcat(nextline,linebuff); + } + break; + } + + case INDIRECT_Y: + { + d1 = mem[pc++]; + if (pass == 3) + { + sprintf(linebuff," ($%.2X),Y",d1); + strcat(nextline,linebuff); + } + break; + } + + case ZERO_PAGE_X: + { + d1 = mem[pc++]; + labfound = mark(d1, REFERENCED); + if (pass == 3) + { + if (labfound == 2) + { + sprintf(linebuff," %s,X", ourTIAMnemonic[d1]); + strcat(nextline,linebuff); + } + else + { + sprintf(linebuff," $%.2X,X",d1); + strcat(nextline,linebuff); + } + } + break; + } + + case ZERO_PAGE_Y: + { + d1 = mem[pc++]; + labfound = mark(d1,REFERENCED); + if (pass == 3) + { + if (labfound == 2) + { + sprintf(linebuff," %s,Y", ourTIAMnemonic[d1]); + strcat(nextline,linebuff); + } + else + { + sprintf(linebuff," $%.2X,Y",d1); + strcat(nextline,linebuff); + } + } + break; + } + + case RELATIVE: + { + d1 = mem[pc++]; + ad = d1; + if (d1 >= 128) + ad = d1 - 256; + + labfound = mark(pc+ad+offset, REFERENCED); + if (pass == 1) + { + if ((addbranch) && !check_bit(labels[pc+ad], REACHABLE)) + { + myAddressQueue.push(pc+ad+offset); + mark(pc+ad+offset, REACHABLE); + /* addressq=addq(addressq,pc+offset); */ + } + } + else if (pass == 3) + { + if (labfound == 1) + { + sprintf(linebuff," L%.4X",pc+ad+offset); + strcat(nextline,linebuff); + } + else + { + sprintf(linebuff," $%.4X",pc+ad+offset); + strcat(nextline,linebuff); + } + } + break; + } + + case ABS_INDIRECT: + { + ad = read_adr(); + labfound = mark(ad, REFERENCED); + if (pass == 3) + { + if (ad < 0x100) + { + sprintf(linebuff,".ind "); + strcat(nextline,linebuff); + } + else + { + sprintf(linebuff," "); + strcat(nextline,linebuff); + } + } + if (labfound == 1) + { + sprintf(linebuff,"(L%04X)",ad); + strcat(nextline,linebuff); + } + else if (labfound == 3) + { + sprintf(linebuff,"(%s)",ourIOMnemonic[ad-0x280]); + strcat(nextline,linebuff); + } + else + { + sprintf(linebuff,"($%04X)",ad); + strcat(nextline,linebuff); + } + break; + } + } // end switch + + if (pass == 1) + { + if (!strcmp(ourLookup[op].mnemonic,"RTS") || + !strcmp(ourLookup[op].mnemonic,"JMP") || + /* !strcmp(ourLookup[op].mnemonic,"BRK") || */ + !strcmp(ourLookup[op].mnemonic,"RTI")) + { + pcend = (pc-1) + offset; + return; + } + } + else if (pass == 3) + { + printf("%.4X | %s", pc+offset, nextline); +// printf("%s", nextline); + if (strlen(nextline) <= 15) + { + /* Print spaces to align cycle count data */ + for (charcnt=0;charcnt<15-strlen(nextline);charcnt++) + printf(" "); + } + printf(";%d",ourLookup[op].cycles); + printf("\n"); + if (op == 0x40 || op == 0x60) + printf("\n"); + + strcpy(nextline,""); + } + } + } /* while loop */ + + /* Just in case we are disassembling outside of the address range, force the pcend to EOF */ + pcend = app_data.end + offset; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int DiStella::mark(uInt32 address, MarkType bit) +{ + /*----------------------------------------------------------------------- + For any given offset and code range... + + If we're between the offset and the end of the code range, we mark + the bit in the labels array for that data. The labels array is an + array of label info for each code address. If this is the case, + return "1", else... + + We sweep for hardware/system equates, which are valid addresses, + outside the scope of the code/data range. For these, we mark its + corresponding hardware/system array element, and return "2" or "3" + (depending on which system/hardware element was accessed). If this + was not the case... + + Next we check if it is a code "mirror". For the 2600, address ranges + are limited with 13 bits, so other addresses can exist outside of the + standard code/data range. For these, we mark the element in the "labels" + array that corresponds to the mirrored address, and return "4" + + If all else fails, it's not a valid address, so return 0. + + A quick example breakdown for a 2600 4K cart: + =========================================================== + $00-$3d = system equates (WSYNC, etc...); mark the array's element + with the appropriate bit; return 2. + $0280-$0297 = system equates (INPT0, etc...); mark the array's element + with the appropriate bit; return 3. + $1000-$1FFF = CODE/DATA, mark the code/data array for the mirrored address + with the appropriate bit; return 4. + $3000-$3FFF = CODE/DATA, mark the code/data array for the mirrored address + with the appropriate bit; return 4. + $5000-$5FFF = CODE/DATA, mark the code/data array for the mirrored address + with the appropriate bit; return 4. + $7000-$7FFF = CODE/DATA, mark the code/data array for the mirrored address + with the appropriate bit; return 4. + $9000-$9FFF = CODE/DATA, mark the code/data array for the mirrored address + with the appropriate bit; return 4. + $B000-$BFFF = CODE/DATA, mark the code/data array for the mirrored address + with the appropriate bit; return 4. + $D000-$DFFF = CODE/DATA, mark the code/data array for the mirrored address + with the appropriate bit; return 4. + $F000-$FFFF = CODE/DATA, mark the code/data array for the address + with the appropriate bit; return 1. + Anything else = invalid, return 0. + =========================================================== + -----------------------------------------------------------------------*/ + + if (address >= offset && address <= app_data.end + offset) + { + labels[address-offset] = labels[address-offset] | bit; + return 1; + } + else if (address >= 0 && address <= 0x3d) + { + reserved[address] = 1; + return 2; + } + else if (address >= 0x280 && address <= 0x297) + { + ioresrvd[address-0x280] = 1; + return 3; + } + else if (address > 0x1000) + { + /* 2K & 4K case */ + labels[address & app_data.end] = labels[address & app_data.end] | bit; + return 4; + } + else + return 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int DiStella::check_bit(uInt8 bitflags, int i) +{ + return (int)(bitflags & i); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void DiStella::showgfx(uInt8 c) +{ + int i; + + printf("|"); + for(i = 0;i < 8; i++) + { + if (c > 127) + printf("X"); + else + printf(" "); + + c = c << 1; + } + printf("|"); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const DiStella::Instruction_tag DiStella::ourLookup[256] = { +/**** Positive ****/ + + /* 00 */ { "BRK", IMPLIED, M_NONE, M_PC, 7 }, /* Pseudo Absolute */ + /* 01 */ { "ORA", INDIRECT_X, M_INDX, M_AC, 6 }, /* (Indirect,X) */ + /* 02 */ { ".JAM", IMPLIED, M_NONE, M_NONE, 0 }, /* TILT */ + /* 03 */ { ".SLO", INDIRECT_X, M_INDX, M_INDX, 8 }, + + /* 04 */ { ".NOOP", ZERO_PAGE, M_NONE, M_NONE, 3 }, + /* 05 */ { "ORA", ZERO_PAGE, M_ZERO, M_AC, 3 }, /* Zeropage */ + /* 06 */ { "ASL", ZERO_PAGE, M_ZERO, M_ZERO, 5 }, /* Zeropage */ + /* 07 */ { ".SLO", ZERO_PAGE, M_ZERO, M_ZERO, 5 }, + + /* 08 */ { "PHP", IMPLIED, M_SR, M_NONE, 3 }, + /* 09 */ { "ORA", IMMEDIATE, M_IMM, M_AC, 2 }, /* Immediate */ + /* 0a */ { "ASL", ACCUMULATOR, M_AC, M_AC, 2 }, /* Accumulator */ + /* 0b */ { ".ANC", IMMEDIATE, M_ACIM, M_ACNC, 2 }, + + /* 0c */ { ".NOOP", ABSOLUTE, M_NONE, M_NONE, 4 }, + /* 0d */ { "ORA", ABSOLUTE, M_ABS, M_AC, 4 }, /* Absolute */ + /* 0e */ { "ASL", ABSOLUTE, M_ABS, M_ABS, 6 }, /* Absolute */ + /* 0f */ { ".SLO", ABSOLUTE, M_ABS, M_ABS, 6 }, + + /* 10 */ { "BPL", RELATIVE, M_REL, M_NONE, 2 }, + /* 11 */ { "ORA", INDIRECT_Y, M_INDY, M_AC, 5 }, /* (Indirect),Y */ + /* 12 */ { ".JAM", IMPLIED, M_NONE, M_NONE, 0 }, /* TILT */ + /* 13 */ { ".SLO", INDIRECT_Y, M_INDY, M_INDY, 8 }, + + /* 14 */ { ".NOOP", ZERO_PAGE_X, M_NONE, M_NONE, 4 }, + /* 15 */ { "ORA", ZERO_PAGE_X, M_ZERX, M_AC, 4 }, /* Zeropage,X */ + /* 16 */ { "ASL", ZERO_PAGE_X, M_ZERX, M_ZERX, 6 }, /* Zeropage,X */ + /* 17 */ { ".SLO", ZERO_PAGE_X, M_ZERX, M_ZERX, 6 }, + + /* 18 */ { "CLC", IMPLIED, M_NONE, M_FC, 2 }, + /* 19 */ { "ORA", ABSOLUTE_Y, M_ABSY, M_AC, 4 }, /* Absolute,Y */ + /* 1a */ { ".NOOP", IMPLIED, M_NONE, M_NONE, 2 }, + /* 1b */ { ".SLO", ABSOLUTE_Y, M_ABSY, M_ABSY, 7 }, + + /* 1c */ { ".NOOP", ABSOLUTE_X, M_NONE, M_NONE, 4 }, + /* 1d */ { "ORA", ABSOLUTE_X, M_ABSX, M_AC, 4 }, /* Absolute,X */ + /* 1e */ { "ASL", ABSOLUTE_X, M_ABSX, M_ABSX, 7 }, /* Absolute,X */ + /* 1f */ { ".SLO", ABSOLUTE_X, M_ABSX, M_ABSX, 7 }, + + /* 20 */ { "JSR", ABSOLUTE, M_ADDR, M_PC, 6 }, + /* 21 */ { "AND", INDIRECT_X, M_INDX, M_AC, 6 }, /* (Indirect ,X) */ + /* 22 */ { ".JAM", IMPLIED, M_NONE, M_NONE, 0 }, /* TILT */ + /* 23 */ { ".RLA", INDIRECT_X, M_INDX, M_INDX, 8 }, + + /* 24 */ { "BIT", ZERO_PAGE, M_ZERO, M_NONE, 3 }, /* Zeropage */ + /* 25 */ { "AND", ZERO_PAGE, M_ZERO, M_AC, 3 }, /* Zeropage */ + /* 26 */ { "ROL", ZERO_PAGE, M_ZERO, M_ZERO, 5 }, /* Zeropage */ + /* 27 */ { ".RLA", ZERO_PAGE, M_ZERO, M_ZERO, 5 }, + + /* 28 */ { "PLP", IMPLIED, M_NONE, M_SR, 4 }, + /* 29 */ { "AND", IMMEDIATE, M_IMM, M_AC, 2 }, /* Immediate */ + /* 2a */ { "ROL", ACCUMULATOR, M_AC, M_AC, 2 }, /* Accumulator */ + /* 2b */ { ".ANC", IMMEDIATE, M_ACIM, M_ACNC, 2 }, + + /* 2c */ { "BIT", ABSOLUTE, M_ABS, M_NONE, 4 }, /* Absolute */ + /* 2d */ { "AND", ABSOLUTE, M_ABS, M_AC, 4 }, /* Absolute */ + /* 2e */ { "ROL", ABSOLUTE, M_ABS, M_ABS, 6 }, /* Absolute */ + /* 2f */ { ".RLA", ABSOLUTE, M_ABS, M_ABS, 6 }, + + /* 30 */ { "BMI", RELATIVE, M_REL, M_NONE, 2 }, + /* 31 */ { "AND", INDIRECT_Y, M_INDY, M_AC, 5 }, /* (Indirect),Y */ + /* 32 */ { ".JAM", IMPLIED, M_NONE, M_NONE, 0 }, /* TILT */ + /* 33 */ { ".RLA", INDIRECT_Y, M_INDY, M_INDY, 8 }, + + /* 34 */ { ".NOOP", ZERO_PAGE_X, M_NONE, M_NONE, 4 }, + /* 35 */ { "AND", ZERO_PAGE_X, M_ZERX, M_AC, 4 }, /* Zeropage,X */ + /* 36 */ { "ROL", ZERO_PAGE_X, M_ZERX, M_ZERX, 6 }, /* Zeropage,X */ + /* 37 */ { ".RLA", ZERO_PAGE_X, M_ZERX, M_ZERX, 6 }, + + /* 38 */ { "SEC", IMPLIED, M_NONE, M_FC, 2 }, + /* 39 */ { "AND", ABSOLUTE_Y, M_ABSY, M_AC, 4 }, /* Absolute,Y */ + /* 3a */ { ".NOOP", IMPLIED, M_NONE, M_NONE, 2 }, + /* 3b */ { ".RLA", ABSOLUTE_Y, M_ABSY, M_ABSY, 7 }, + + /* 3c */ { ".NOOP", ABSOLUTE_X, M_NONE, M_NONE, 4 }, + /* 3d */ { "AND", ABSOLUTE_X, M_ABSX, M_AC, 4 }, /* Absolute,X */ + /* 3e */ { "ROL", ABSOLUTE_X, M_ABSX, M_ABSX, 7 }, /* Absolute,X */ + /* 3f */ { ".RLA", ABSOLUTE_X, M_ABSX, M_ABSX, 7 }, + + /* 40 */ { "RTI" , IMPLIED, M_NONE, M_PC, 6 }, + /* 41 */ { "EOR", INDIRECT_X, M_INDX, M_AC, 6 }, /* (Indirect,X) */ + /* 42 */ { ".JAM", IMPLIED, M_NONE, M_NONE, 0 }, /* TILT */ + /* 43 */ { ".SRE", INDIRECT_X, M_INDX, M_INDX, 8 }, + + /* 44 */ { ".NOOP", ZERO_PAGE, M_NONE, M_NONE, 3 }, + /* 45 */ { "EOR", ZERO_PAGE, M_ZERO, M_AC, 3 }, /* Zeropage */ + /* 46 */ { "LSR", ZERO_PAGE, M_ZERO, M_ZERO, 5 }, /* Zeropage */ + /* 47 */ { ".SRE", ZERO_PAGE, M_ZERO, M_ZERO, 5 }, + + /* 48 */ { "PHA", IMPLIED, M_AC, M_NONE, 3 }, + /* 49 */ { "EOR", IMMEDIATE, M_IMM, M_AC, 2 }, /* Immediate */ + /* 4a */ { "LSR", ACCUMULATOR, M_AC, M_AC, 2 }, /* Accumulator */ + /* 4b */ { ".ASR", IMMEDIATE, M_ACIM, M_AC, 2 }, /* (AC & IMM) >>1 */ + + /* 4c */ { "JMP", ABSOLUTE, M_ADDR, M_PC, 3 }, /* Absolute */ + /* 4d */ { "EOR", ABSOLUTE, M_ABS, M_AC, 4 }, /* Absolute */ + /* 4e */ { "LSR", ABSOLUTE, M_ABS, M_ABS, 6 }, /* Absolute */ + /* 4f */ { ".SRE", ABSOLUTE, M_ABS, M_ABS, 6 }, + + /* 50 */ { "BVC", RELATIVE, M_REL, M_NONE, 2 }, + /* 51 */ { "EOR", INDIRECT_Y, M_INDY, M_AC, 5 }, /* (Indirect),Y */ + /* 52 */ { ".JAM", IMPLIED, M_NONE, M_NONE, 0 }, /* TILT */ + /* 53 */ { ".SRE", INDIRECT_Y, M_INDY, M_INDY, 8 }, + + /* 54 */ { ".NOOP", ZERO_PAGE_X, M_NONE, M_NONE, 4 }, + /* 55 */ { "EOR", ZERO_PAGE_X, M_ZERX, M_AC, 4 }, /* Zeropage,X */ + /* 56 */ { "LSR", ZERO_PAGE_X, M_ZERX, M_ZERX, 6 }, /* Zeropage,X */ + /* 57 */ { ".SRE", ZERO_PAGE_X, M_ZERX, M_ZERX, 6 }, + + /* 58 */ { "CLI", IMPLIED, M_NONE, M_FI, 2 }, + /* 59 */ { "EOR", ABSOLUTE_Y, M_ABSY, M_AC, 4 }, /* Absolute,Y */ + /* 5a */ { ".NOOP", IMPLIED, M_NONE, M_NONE, 2 }, + /* 5b */ { ".SRE", ABSOLUTE_Y, M_ABSY, M_ABSY, 7 }, + + /* 5c */ { ".NOOP", ABSOLUTE_X, M_NONE, M_NONE, 4 }, + /* 5d */ { "EOR", ABSOLUTE_X, M_ABSX, M_AC, 4 }, /* Absolute,X */ + /* 5e */ { "LSR", ABSOLUTE_X, M_ABSX, M_ABSX, 7 }, /* Absolute,X */ + /* 5f */ { ".SRE", ABSOLUTE_X, M_ABSX, M_ABSX, 7 }, + + /* 60 */ { "RTS", IMPLIED, M_NONE, M_PC, 6 }, + /* 61 */ { "ADC", INDIRECT_X, M_INDX, M_AC, 6 }, /* (Indirect,X) */ + /* 62 */ { ".JAM", IMPLIED, M_NONE, M_NONE, 0 }, /* TILT */ + /* 63 */ { ".RRA", INDIRECT_X, M_INDX, M_INDX, 8 }, + + /* 64 */ { ".NOOP", ZERO_PAGE, M_NONE, M_NONE, 3 }, + /* 65 */ { "ADC", ZERO_PAGE, M_ZERO, M_AC, 3 }, /* Zeropage */ + /* 66 */ { "ROR", ZERO_PAGE, M_ZERO, M_ZERO, 5 }, /* Zeropage */ + /* 67 */ { ".RRA", ZERO_PAGE, M_ZERO, M_ZERO, 5 }, + + /* 68 */ { "PLA", IMPLIED, M_NONE, M_AC, 4 }, + /* 69 */ { "ADC", IMMEDIATE, M_IMM, M_AC, 2 }, /* Immediate */ + /* 6a */ { "ROR", ACCUMULATOR, M_AC, M_AC, 2 }, /* Accumulator */ + /* 6b */ { ".ARR", IMMEDIATE, M_ACIM, M_AC, 2 }, /* ARR isn't typo */ + + /* 6c */ { "JMP", ABS_INDIRECT, M_AIND, M_PC, 5 }, /* Indirect */ + /* 6d */ { "ADC", ABSOLUTE, M_ABS, M_AC, 4 }, /* Absolute */ + /* 6e */ { "ROR", ABSOLUTE, M_ABS, M_ABS, 6 }, /* Absolute */ + /* 6f */ { ".RRA", ABSOLUTE, M_ABS, M_ABS, 6 }, + + /* 70 */ { "BVS", RELATIVE, M_REL, M_NONE, 2 }, + /* 71 */ { "ADC", INDIRECT_Y, M_INDY, M_AC, 5 }, /* (Indirect),Y */ + /* 72 */ { ".JAM", IMPLIED, M_NONE, M_NONE, 0 }, /* TILT relative? */ + /* 73 */ { ".RRA", INDIRECT_Y, M_INDY, M_INDY, 8 }, + + /* 74 */ { ".NOOP", ZERO_PAGE_X, M_NONE, M_NONE, 4 }, + /* 75 */ { "ADC", ZERO_PAGE_X, M_ZERX, M_AC, 4 }, /* Zeropage,X */ + /* 76 */ { "ROR", ZERO_PAGE_X, M_ZERX, M_ZERX, 6 }, /* Zeropage,X */ + /* 77 */ { ".RRA", ZERO_PAGE_X, M_ZERX, M_ZERX, 6 }, + + /* 78 */ { "SEI", IMPLIED, M_NONE, M_FI, 2 }, + /* 79 */ { "ADC", ABSOLUTE_Y, M_ABSY, M_AC, 4 }, /* Absolute,Y */ + /* 7a */ { ".NOOP", IMPLIED, M_NONE, M_NONE, 2 }, + /* 7b */ { ".RRA", ABSOLUTE_Y, M_ABSY, M_ABSY, 7 }, + + /* 7c */ { ".NOOP", ABSOLUTE_X, M_NONE, M_NONE, 4 }, + /* 7d */ { "ADC", ABSOLUTE_X, M_ABSX, M_AC, 4 }, /* Absolute,X */ + /* 7e */ { "ROR", ABSOLUTE_X, M_ABSX, M_ABSX, 7 }, /* Absolute,X */ + /* 7f */ { ".RRA", ABSOLUTE_X, M_ABSX, M_ABSX, 7 }, + + /**** Negative ****/ + + /* 80 */ { ".NOOP", IMMEDIATE, M_NONE, M_NONE, 2 }, + /* 81 */ { "STA", INDIRECT_X, M_AC, M_INDX, 6 }, /* (Indirect,X) */ + /* 82 */ { ".NOOP", IMMEDIATE, M_NONE, M_NONE, 2 }, + /* 83 */ { ".SAX", INDIRECT_X, M_ANXR, M_INDX, 6 }, + + /* 84 */ { "STY", ZERO_PAGE, M_YR, M_ZERO, 3 }, /* Zeropage */ + /* 85 */ { "STA", ZERO_PAGE, M_AC, M_ZERO, 3 }, /* Zeropage */ + /* 86 */ { "STX", ZERO_PAGE, M_XR, M_ZERO, 3 }, /* Zeropage */ + /* 87 */ { ".SAX", ZERO_PAGE, M_ANXR, M_ZERO, 3 }, + + /* 88 */ { "DEY", IMPLIED, M_YR, M_YR, 2 }, + /* 89 */ { ".NOOP", IMMEDIATE, M_NONE, M_NONE, 2 }, + /* 8a */ { "TXA", IMPLIED, M_XR, M_AC, 2 }, + /**** ver abnormal: usually AC = AC | #$EE & XR & #$oper ****/ + /* 8b */ { ".ANE", IMMEDIATE, M_AXIM, M_AC, 2 }, + + /* 8c */ { "STY", ABSOLUTE, M_YR, M_ABS, 4 }, /* Absolute */ + /* 8d */ { "STA", ABSOLUTE, M_AC, M_ABS, 4 }, /* Absolute */ + /* 8e */ { "STX", ABSOLUTE, M_XR, M_ABS, 4 }, /* Absolute */ + /* 8f */ { ".SAX", ABSOLUTE, M_ANXR, M_ABS, 4 }, + + /* 90 */ { "BCC", RELATIVE, M_REL, M_NONE, 2 }, + /* 91 */ { "STA", INDIRECT_Y, M_AC, M_INDY, 6 }, /* (Indirect),Y */ + /* 92 */ { ".JAM", IMPLIED, M_NONE, M_NONE, 0 }, /* TILT relative? */ + /* 93 */ { ".SHA", INDIRECT_Y, M_ANXR, M_STH0, 6 }, + + /* 94 */ { "STY", ZERO_PAGE_X, M_YR, M_ZERX, 4 }, /* Zeropage,X */ + /* 95 */ { "STA", ZERO_PAGE_X, M_AC, M_ZERX, 4 }, /* Zeropage,X */ + /* 96 */ { "STX", ZERO_PAGE_Y, M_XR, M_ZERY, 4 }, /* Zeropage,Y */ + /* 97 */ { ".SAX", ZERO_PAGE_Y, M_ANXR, M_ZERY, 4 }, + + /* 98 */ { "TYA", IMPLIED, M_YR, M_AC, 2 }, + /* 99 */ { "STA", ABSOLUTE_Y, M_AC, M_ABSY, 5 }, /* Absolute,Y */ + /* 9a */ { "TXS", IMPLIED, M_XR, M_SP, 2 }, + /*** This s very mysterious comm AND ... */ + /* 9b */ { ".SHS", ABSOLUTE_Y, M_ANXR, M_STH3, 5 }, + + /* 9c */ { ".SHY", ABSOLUTE_X, M_YR, M_STH2, 5 }, + /* 9d */ { "STA", ABSOLUTE_X, M_AC, M_ABSX, 5 }, /* Absolute,X */ + /* 9e */ { ".SHX", ABSOLUTE_Y, M_XR , M_STH1, 5 }, + /* 9f */ { ".SHA", ABSOLUTE_Y, M_ANXR, M_STH1, 5 }, + + /* a0 */ { "LDY", IMMEDIATE, M_IMM, M_YR, 2 }, /* Immediate */ + /* a1 */ { "LDA", INDIRECT_X, M_INDX, M_AC, 6 }, /* (indirect,X) */ + /* a2 */ { "LDX", IMMEDIATE, M_IMM, M_XR, 2 }, /* Immediate */ + /* a3 */ { ".LAX", INDIRECT_X, M_INDX, M_ACXR, 6 }, /* (indirect,X) */ + + /* a4 */ { "LDY", ZERO_PAGE, M_ZERO, M_YR, 3 }, /* Zeropage */ + /* a5 */ { "LDA", ZERO_PAGE, M_ZERO, M_AC, 3 }, /* Zeropage */ + /* a6 */ { "LDX", ZERO_PAGE, M_ZERO, M_XR, 3 }, /* Zeropage */ + /* a7 */ { ".LAX", ZERO_PAGE, M_ZERO, M_ACXR, 3 }, + + /* a8 */ { "TAY", IMPLIED, M_AC, M_YR, 2 }, + /* a9 */ { "LDA", IMMEDIATE, M_IMM, M_AC, 2 }, /* Immediate */ + /* aa */ { "TAX", IMPLIED, M_AC, M_XR, 2 }, + /* ab */ { ".LXA", IMMEDIATE, M_ACIM, M_ACXR, 2 }, /* LXA isn't a typo */ + + /* ac */ { "LDY", ABSOLUTE, M_ABS, M_YR, 4 }, /* Absolute */ + /* ad */ { "LDA", ABSOLUTE, M_ABS, M_AC, 4 }, /* Absolute */ + /* ae */ { "LDX", ABSOLUTE, M_ABS, M_XR, 4 }, /* Absolute */ + /* af */ { ".LAX", ABSOLUTE, M_ABS, M_ACXR, 4 }, + + /* b0 */ { "BCS", RELATIVE, M_REL, M_NONE, 2 }, + /* b1 */ { "LDA", INDIRECT_Y, M_INDY, M_AC, 5 }, /* (indirect),Y */ + /* b2 */ { ".JAM", IMPLIED, M_NONE, M_NONE, 0 }, /* TILT */ + /* b3 */ { ".LAX", INDIRECT_Y, M_INDY, M_ACXR, 5 }, + + /* b4 */ { "LDY", ZERO_PAGE_X, M_ZERX, M_YR, 4 }, /* Zeropage,X */ + /* b5 */ { "LDA", ZERO_PAGE_X, M_ZERX, M_AC, 4 }, /* Zeropage,X */ + /* b6 */ { "LDX", ZERO_PAGE_Y, M_ZERY, M_XR, 4 }, /* Zeropage,Y */ + /* b7 */ { ".LAX", ZERO_PAGE_Y, M_ZERY, M_ACXR, 4 }, + + /* b8 */ { "CLV", IMPLIED, M_NONE, M_FV, 2 }, + /* b9 */ { "LDA", ABSOLUTE_Y, M_ABSY, M_AC, 4 }, /* Absolute,Y */ + /* ba */ { "TSX", IMPLIED, M_SP, M_XR, 2 }, + /* bb */ { ".LAS", ABSOLUTE_Y, M_SABY, M_ACXS, 4 }, + + /* bc */ { "LDY", ABSOLUTE_X, M_ABSX, M_YR, 4 }, /* Absolute,X */ + /* bd */ { "LDA", ABSOLUTE_X, M_ABSX, M_AC, 4 }, /* Absolute,X */ + /* be */ { "LDX", ABSOLUTE_Y, M_ABSY, M_XR, 4 }, /* Absolute,Y */ + /* bf */ { ".LAX", ABSOLUTE_Y, M_ABSY, M_ACXR, 4 }, + + /* c0 */ { "CPY", IMMEDIATE, M_IMM, M_NONE, 2 }, /* Immediate */ + /* c1 */ { "CMP", INDIRECT_X, M_INDX, M_NONE, 6 }, /* (Indirect,X) */ + /* c2 */ { ".NOOP", IMMEDIATE, M_NONE, M_NONE, 2 }, /* occasional TILT */ + /* c3 */ { ".DCP", INDIRECT_X, M_INDX, M_INDX, 8 }, + + /* c4 */ { "CPY", ZERO_PAGE, M_ZERO, M_NONE, 3 }, /* Zeropage */ + /* c5 */ { "CMP", ZERO_PAGE, M_ZERO, M_NONE, 3 }, /* Zeropage */ + /* c6 */ { "DEC", ZERO_PAGE, M_ZERO, M_ZERO, 5 }, /* Zeropage */ + /* c7 */ { ".DCP", ZERO_PAGE, M_ZERO, M_ZERO, 5 }, + + /* c8 */ { "INY", IMPLIED, M_YR, M_YR, 2 }, + /* c9 */ { "CMP", IMMEDIATE, M_IMM, M_NONE, 2 }, /* Immediate */ + /* ca */ { "DEX", IMPLIED, M_XR, M_XR, 2 }, + /* cb */ { ".SBX", IMMEDIATE, M_IMM, M_XR, 2 }, + + /* cc */ { "CPY", ABSOLUTE, M_ABS, M_NONE, 4 }, /* Absolute */ + /* cd */ { "CMP", ABSOLUTE, M_ABS, M_NONE, 4 }, /* Absolute */ + /* ce */ { "DEC", ABSOLUTE, M_ABS, M_ABS, 6 }, /* Absolute */ + /* cf */ { ".DCP", ABSOLUTE, M_ABS, M_ABS, 6 }, + + /* d0 */ { "BNE", RELATIVE, M_REL, M_NONE, 2 }, + /* d1 */ { "CMP", INDIRECT_Y, M_INDY, M_NONE, 5 }, /* (Indirect),Y */ + /* d2 */ { ".JAM", IMPLIED, M_NONE, M_NONE, 0 }, /* TILT */ + /* d3 */ { ".DCP", INDIRECT_Y, M_INDY, M_INDY, 8 }, + + /* d4 */ { ".NOOP", ZERO_PAGE_X, M_NONE, M_NONE, 4 }, + /* d5 */ { "CMP", ZERO_PAGE_X, M_ZERX, M_NONE, 4 }, /* Zeropage,X */ + /* d6 */ { "DEC", ZERO_PAGE_X, M_ZERX, M_ZERX, 6 }, /* Zeropage,X */ + /* d7 */ { ".DCP", ZERO_PAGE_X, M_ZERX, M_ZERX, 6 }, + + /* d8 */ { "CLD", IMPLIED, M_NONE, M_FD, 2 }, + /* d9 */ { "CMP", ABSOLUTE_Y, M_ABSY, M_NONE, 4 }, /* Absolute,Y */ + /* da */ { ".NOOP", IMPLIED, M_NONE, M_NONE, 2 }, + /* db */ { ".DCP", ABSOLUTE_Y, M_ABSY, M_ABSY, 7 }, + + /* dc */ { ".NOOP", ABSOLUTE_X, M_NONE, M_NONE, 4 }, + /* dd */ { "CMP", ABSOLUTE_X, M_ABSX, M_NONE, 4 }, /* Absolute,X */ + /* de */ { "DEC", ABSOLUTE_X, M_ABSX, M_ABSX, 7 }, /* Absolute,X */ + /* df */ { ".DCP", ABSOLUTE_X, M_ABSX, M_ABSX, 7 }, + + /* e0 */ { "CPX", IMMEDIATE, M_IMM, M_NONE, 2 }, /* Immediate */ + /* e1 */ { "SBC", INDIRECT_X, M_INDX, M_AC, 6 }, /* (Indirect,X) */ + /* e2 */ { ".NOOP", IMMEDIATE, M_NONE, M_NONE, 2 }, + /* e3 */ { ".ISB", INDIRECT_X, M_INDX, M_INDX, 8 }, + + /* e4 */ { "CPX", ZERO_PAGE, M_ZERO, M_NONE, 3 }, /* Zeropage */ + /* e5 */ { "SBC", ZERO_PAGE, M_ZERO, M_AC, 3 }, /* Zeropage */ + /* e6 */ { "INC", ZERO_PAGE, M_ZERO, M_ZERO, 5 }, /* Zeropage */ + /* e7 */ { ".ISB", ZERO_PAGE, M_ZERO, M_ZERO, 5 }, + + /* e8 */ { "INX", IMPLIED, M_XR, M_XR, 2 }, + /* e9 */ { "SBC", IMMEDIATE, M_IMM, M_AC, 2 }, /* Immediate */ + /* ea */ { "NOP", IMPLIED, M_NONE, M_NONE, 2 }, + /* eb */ { ".USBC", IMMEDIATE, M_IMM, M_AC, 2 }, /* same as e9 */ + + /* ec */ { "CPX", ABSOLUTE, M_ABS, M_NONE, 4 }, /* Absolute */ + /* ed */ { "SBC", ABSOLUTE, M_ABS, M_AC, 4 }, /* Absolute */ + /* ee */ { "INC", ABSOLUTE, M_ABS, M_ABS, 6 }, /* Absolute */ + /* ef */ { ".ISB", ABSOLUTE, M_ABS, M_ABS, 6 }, + + /* f0 */ { "BEQ", RELATIVE, M_REL, M_NONE, 2 }, + /* f1 */ { "SBC", INDIRECT_Y, M_INDY, M_AC, 5 }, /* (Indirect),Y */ + /* f2 */ { ".JAM", IMPLIED, M_NONE, M_NONE, 0 }, /* TILT */ + /* f3 */ { ".ISB", INDIRECT_Y, M_INDY, M_INDY, 8 }, + + /* f4 */ { ".NOOP", ZERO_PAGE_X, M_NONE, M_NONE, 4 }, + /* f5 */ { "SBC", ZERO_PAGE_X, M_ZERX, M_AC, 4 }, /* Zeropage,X */ + /* f6 */ { "INC", ZERO_PAGE_X, M_ZERX, M_ZERX, 6 }, /* Zeropage,X */ + /* f7 */ { ".ISB", ZERO_PAGE_X, M_ZERX, M_ZERX, 6 }, + + /* f8 */ { "SED", IMPLIED, M_NONE, M_FD, 2 }, + /* f9 */ { "SBC", ABSOLUTE_Y, M_ABSY, M_AC, 4 }, /* Absolute,Y */ + /* fa */ { ".NOOP", IMPLIED, M_NONE, M_NONE, 2 }, + /* fb */ { ".ISB", ABSOLUTE_Y, M_ABSY, M_ABSY, 7 }, + + /* fc */ { ".NOOP", ABSOLUTE_X, M_NONE, M_NONE, 4 }, + /* fd */ { "SBC", ABSOLUTE_X, M_ABSX, M_AC, 4 }, /* Absolute,X */ + /* fe */ { "INC", ABSOLUTE_X, M_ABSX, M_ABSX, 7 }, /* Absolute,X */ + /* ff */ { ".ISB", ABSOLUTE_X, M_ABSX, M_ABSX, 7 } +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const char* DiStella::ourTIAMnemonic[62] = { + "VSYNC", "VBLANK", "WSYNC", "RSYNC", "NUSIZ0", "NUSIZ1", "COLUP0", "COLUP1", + "COLUPF", "COLUBK", "CTRLPF", "REFP0", "REFP1", "PF0", "PF1", "PF2", "RESP0", + "RESP1", "RESM0", "RESM1", "RESBL", "AUDC0", "AUDC1", "AUDF0", "AUDF1", + "AUDV0", "AUDV1", "GRP0", "GRP1", "ENAM0", "ENAM1", "ENABL", "HMP0", "HMP1", + "HMM0", "HMM1", "HMBL", "VDELP0", "VDELP1", "VDELBL", "RESMP0", "RESMP1", + "HMOVE", "HMCLR", "CXCLR", "$2D", "$2E", "$2F", "CXM0P", "CXM1P", "CXP0FB", + "CXP1FB", "CXM0FB", "CXM1FB", "CXBLPF", "CXPPMM", "INPT0", "INPT1", "INPT2", + "INPT3", "INPT4", "INPT5" +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const char* DiStella::ourIOMnemonic[24] = { + "SWCHA", "SWACNT", "SWCHB", "SWBCNT", "INTIM", "$0285", "$0286", "$0287", + "$0288", "$0289", "$028A", "$028B", "$028C", "$028D", "$028E", "$028F", + "$0290", "$0291", "$0292", "$0293", "TIM1T", "TIM8T", "TIM64T", "T1024T" +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const int DiStella::ourCLength[14] = { + 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 0 +}; + +#ifdef USE_MAIN +int main(int ac, char* av[]) +{ + DiStella dis; + DisassemblyList list; + + dis.disassemble(list, av[1]); + + printf("Disassembly results:\n\n"); + for(uInt32 i = 0; i < list.size(); ++i) + { + const DisassemblyTag& tag = list[i]; + printf("%.4X | %s %s\n", tag.address, tag.disasm.c_str(), tag.bytes.c_str()); + } + + return 0; +} +#endif diff --git a/src/debugger/DiStella.hxx b/src/debugger/DiStella.hxx new file mode 100644 index 000000000..a64fe577a --- /dev/null +++ b/src/debugger/DiStella.hxx @@ -0,0 +1,146 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2009 by Bradford W. Mott and the Stella team +// +// See the file "license" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +// +// $Id$ +//============================================================================ + +#ifndef DISTELLA_HXX +#define DISTELLA_HXX + +#include + +#include "Array.hxx" +#include "bspf.hxx" + +//#include "CartDebug.hxx" + +//// The following will go in CartDebug + struct DisassemblyTag { + int address; + string disasm; + string bytes; + }; + typedef Common::Array DisassemblyList; +////////////////////////////////////////////////////////////// + +class DiStella +{ + public: + DiStella(); + ~DiStella(); + + public: + int disassemble(DisassemblyList& list, const char* datafile); + + private: + struct resource { + uInt16 start; + uInt16 load; + uInt32 length; + uInt16 end; + int disp_data; + } app_data; + + /* Memory */ + uInt8* mem; + uInt8* labels; + + uInt8 reserved[64]; + uInt8 ioresrvd[24]; + uInt8 pokresvd[16]; + char linebuff[256],nextline[256]; + FILE* cfg; + + uInt32 pc, pcbeg, pcend, offset, start_adr; + int cflag, dflag, lineno, charcnt; + + queue myAddressQueue; + + private: + // Marked bits + // This is a reference sheet of bits that can be set for a given address, which + // are stored in the labels[] array. + enum MarkType { + REFERENCED = 1 << 0, /* code somewhere in the program references it, i.e. LDA $F372 referenced $F372 */ + VALID_ENTRY = 1 << 1, /* addresses that can have a label placed in front of it. A good counterexample + would be "FF00: LDA $FE00"; $FF01 would be in the middle of a multi-byte + instruction, and therefore cannot be labelled. */ + DATA = 1 << 2, + GFX = 1 << 3, + REACHABLE = 1 << 4 /* disassemble-able code segments */ + }; + + /** + Enumeration of the 6502 addressing modes + */ + enum AddressingMode + { + IMPLIED, ACCUMULATOR, IMMEDIATE, + ZERO_PAGE, ZERO_PAGE_X, ZERO_PAGE_Y, + ABSOLUTE, ABSOLUTE_X, ABSOLUTE_Y, + ABS_INDIRECT, INDIRECT_X, INDIRECT_Y, + RELATIVE, ASS_CODE + }; + + /** + Enumeration of the 6502 access modes + */ + enum AccessMode + { + M_NONE, M_AC, M_XR, M_YR, M_SP, M_SR, M_PC, M_IMM, M_ZERO, M_ZERX, M_ZERY, + M_ABS, M_ABSX, M_ABSY, M_AIND, M_INDX, M_INDY, M_REL, M_FC, M_FD, M_FI, + M_FV, M_ADDR, M_, + + M_ACIM, /* Source: AC & IMMED (bus collision) */ + M_ANXR, /* Source: AC & XR (bus collision) */ + M_AXIM, /* Source: (AC | #EE) & XR & IMMED (bus collision) */ + M_ACNC, /* Dest: M_AC and Carry = Negative */ + M_ACXR, /* Dest: M_AC, M_XR */ + + M_SABY, /* Source: (ABS_Y & SP) (bus collision) */ + M_ACXS, /* Dest: M_AC, M_XR, M_SP */ + M_STH0, /* Dest: Store (src & Addr_Hi+1) to (Addr +0x100) */ + M_STH1, + M_STH2, + M_STH3 + }; + +uInt32 filesize(FILE *stream); +uInt32 read_adr(); +int file_load(const char* file); +int load_config(const char* file); +void check_range(uInt32 beg, uInt32 end); +void disasm(uInt32 distart, int pass, DisassemblyList& list); +int mark(uInt32 address, MarkType bit); +int check_bit(uInt8 bitflags, int i); +void showgfx(uInt8 c); + + struct Instruction_tag { + const char* mnemonic; + AddressingMode addr_mode; + AccessMode source; + AccessMode destination; + uInt8 cycles; + }; + static const Instruction_tag ourLookup[256]; + + /// Table of instruction mnemonics + static const char* ourTIAMnemonic[62]; + static const char* ourIOMnemonic[24]; + + static const int ourCLength[14]; +}; + +#endif diff --git a/src/debugger/EquateList.cxx b/src/debugger/EquateList.cxx deleted file mode 100644 index a7580aafd..000000000 --- a/src/debugger/EquateList.cxx +++ /dev/null @@ -1,542 +0,0 @@ -//============================================================================ -// -// SSSS tt lll lll -// SS SS tt ll ll -// SS tttttt eeee ll ll aaaa -// SSSS tt ee ee ll ll aa -// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" -// SS SS tt ee ll ll aa aa -// SSSS ttt eeeee llll llll aaaaa -// -// Copyright (c) 1995-2010 by Bradford W. Mott and the Stella Team -// -// See the file "License.txt" for information on usage and redistribution of -// this file, and for a DISCLAIMER OF ALL WARRANTIES. -// -// $Id$ -//============================================================================ - -#include -#include - -#include "bspf.hxx" -#include "Debugger.hxx" - -#include "EquateList.hxx" - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -EquateList::EquateList() -{ - for(int i = 0; i < kSystemEquateSize; i++) - { - const Equate& e = ourSystemEquates[i]; - mySystemAddresses.insert(make_pair(e.label, e)); - - // Certain hardcoded addresses have different labels in read and write - // mode; we use separate lists for those - if(e.flags & EQF_READ) - mySystemReadLabels.insert(make_pair(e.address, e)); - if(e.flags & EQF_WRITE) - mySystemWriteLabels.insert(make_pair(e.address, e)); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -EquateList::~EquateList() -{ - mySystemAddresses.clear(); - mySystemReadLabels.clear(); - mySystemWriteLabels.clear(); - - myUserAddresses.clear(); - myUserLabels.clear(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void EquateList::addEquate(const string& label, uInt16 address) -{ - // First check if this already exists as a hard-coded equate - LabelToAddr::const_iterator iter = mySystemAddresses.find(label); - if(iter != mySystemAddresses.end() && iter->second.address == address) - return; - - // Create a new user equate, and determine if its RAM or ROM - // For now, these are the only types we care about - // Technically, addresses above 0x1000 are ROM and are read-only - // However, somes ROMs have dedicated RAM mapped to those addresses - // as well, and we don't yet have an infrastructure to determine that, - // so the entire region is marked as read-write - equate_t flags = EQF_READ; -#if 0 - if(address >= 0x80 && address <= 0xff) - flags = EQF_RW; - else if((address & 0x1000) == 0x1000) - flags = EQF_RW; - else - { - cerr << "label = " << label << ", address = " << hex << address << " discarded\n"; - return; // don't know what else to do for now - } -#else - // The above section of code is deactivated until a better means of - // determining constants vs. addresses is found - flags = EQF_RW; -#endif - - removeEquate(label); - - Equate e; - e.label = label; - e.address = address; - e.flags = flags; - - myUserAddresses.insert(make_pair(label, e)); - myUserLabels.insert(make_pair(address, e)); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool EquateList::removeEquate(const string& label) -{ - // Note that only user-defined equates can be removed - LabelToAddr::iterator iter = myUserAddresses.find(label); - if(iter != myUserAddresses.end()) - { - // Erase the label - myUserAddresses.erase(iter); - - // And also erase the address assigned to it - AddrToLabel::iterator iter2 = myUserLabels.find(iter->second.address); - if(iter2 != myUserLabels.end()) - myUserLabels.erase(iter2); - - return true; - } - return false; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const string& EquateList::getLabel(uInt16 addr, bool isRead, int places) -{ - AddrToLabel::const_iterator iter; - - // Is this a read or write? - // For now, there aren't separate read & write lists for user labels - AddrToLabel& systemLabels = isRead ? mySystemReadLabels : mySystemWriteLabels; - - // Determine the type of address to access the correct list - addressType(addr); - switch(myAddressType) - { - case ADDR_TIA: - if((iter = systemLabels.find(addr&0x7f)) != systemLabels.end()) - return iter->second.label; - else if((iter = myUserLabels.find(addr)) != myUserLabels.end()) - return iter->second.label; - break; - - case ADDR_RIOT: // FIXME - add mirrors for RIOT - if((iter = systemLabels.find(addr)) != systemLabels.end()) - return iter->second.label; - else if((iter = myUserLabels.find(addr)) != myUserLabels.end()) - return iter->second.label; - break; - - case ADDR_RAM: - case ADDR_ROM: - // These addresses can never be in the system labels list - if((iter = myUserLabels.find(addr)) != myUserLabels.end()) - return iter->second.label; - break; - } - - if(places > -1) - { - ostringstream buf; - buf << "$" << setw(places) << hex << addr; - return myCurrentLabel = buf.str(); - } - - return EmptyString; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int EquateList::getAddress(const string& label) const -{ - LabelToAddr::const_iterator iter; - - if((iter = mySystemAddresses.find(label)) != mySystemAddresses.end()) - return iter->second.address; - else if((iter = myUserAddresses.find(label)) != myUserAddresses.end()) - return iter->second.address; - else - return -1; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string EquateList::loadFile(const string& file) -{ - int pos = 0, lines = 0, curVal; - string curLabel; - char line[1024]; - - ifstream in(file.c_str()); - if(!in.is_open()) - return "Unable to read symbols from " + file; - - myUserAddresses.clear(); - myUserLabels.clear(); - - while( !in.eof() ) - { - curVal = 0; - curLabel = ""; - - int got = in.get(); - - if(got == -1 || got == '\r' || got == '\n' || pos == 1023) { - line[pos] = '\0'; - pos = 0; - - if(strlen(line) > 0 && line[0] != '-') - { - curLabel = extractLabel(line); - if((curVal = extractValue(line)) < 0) - return "invalid symbol file"; - - addEquate(curLabel, curVal); - - lines++; - } - } - else - { - line[pos++] = got; - } - } - in.close(); - - return "loaded " + file + " OK"; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool EquateList::saveFile(const string& file) -{ - // Only user-defined equates are saved; system equates are always - // available, so there's no need to save them - char buf[256]; - - ofstream out(file.c_str()); - if(!out.is_open()) - return false; - - out << "--- Symbol List (sorted by symbol)" << endl; - - LabelToAddr::const_iterator iter; - for(iter = myUserAddresses.begin(); iter != myUserAddresses.end(); iter++) - { - sprintf(buf, "%-24s %04x \n", iter->second.label.c_str(), iter->second.address); - out << buf; - } - - out << "--- End of Symbol List." << endl; - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int EquateList::countCompletions(const char *in) -{ - myCompletions = myCompPrefix = ""; - return countCompletions(in, mySystemAddresses) + - countCompletions(in, myUserAddresses); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int EquateList::countCompletions(const char *in, LabelToAddr& addresses) -{ - int count = 0; - - LabelToAddr::iterator iter; - for(iter = addresses.begin(); iter != addresses.end(); iter++) - { - const char *l = iter->first.c_str(); - - if(BSPF_strncasecmp(l, in, strlen(in)) == 0) - { - if(myCompPrefix == "") - myCompPrefix += l; - else - { - int nonMatch = 0; - const char *c = myCompPrefix.c_str(); - while(*c != '\0' && tolower(*c) == tolower(l[nonMatch])) - { - c++; - nonMatch++; - } - myCompPrefix.erase(nonMatch, myCompPrefix.length()); - } - - if(count++) myCompletions += " "; - myCompletions += l; - } - } - - return count; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string EquateList::extractLabel(char *c) -{ - string l = ""; - while(*c != ' ') - l += *c++; - - return l; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int EquateList::extractValue(char *c) -{ - while(*c != ' ') - { - if(*c == '\0') - return -1; - c++; - } - - while(*c == ' ') - { - if(*c == '\0') - return -1; - c++; - } - - int ret = 0; - for(int i=0; i<4; i++) - { - if(*c >= '0' && *c <= '9') - ret = (ret << 4) + (*c) - '0'; - else if(*c >= 'a' && *c <= 'f') - ret = (ret << 4) + (*c) - 'a' + 10; - else - return -1; - c++; - } - return ret; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -inline void EquateList::addressType(uInt16 addr) -{ - // These addresses were based on (and checked against) Kroko's 2600 memory - // map, found at http://www.qotile.net/minidig/docs/2600_mem_map.txt - myAddressType = ADDR_ROM; - if(addr % 0x2000 < 0x1000) - { - uInt16 z = addr & 0x00ff; - if(z < 0x80) - myAddressType = ADDR_TIA; - else - { - switch(addr & 0x0f00) - { - case 0x000: - case 0x100: - case 0x400: - case 0x500: - case 0x800: - case 0x900: - case 0xc00: - case 0xd00: - myAddressType = ADDR_RAM; - break; - case 0x200: - case 0x300: - case 0x600: - case 0x700: - case 0xa00: - case 0xb00: - case 0xe00: - case 0xf00: - myAddressType = ADDR_RIOT; - break; - } - } - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const EquateList::Equate EquateList::ourSystemEquates[kSystemEquateSize] = { -// Standard $00-based TIA write locations: - { "VSYNC", 0x00, EQF_WRITE }, - { "VBLANK", 0x01, EQF_WRITE }, - { "WSYNC", 0x02, EQF_WRITE }, - { "RSYNC", 0x03, EQF_WRITE }, - { "NUSIZ0", 0x04, EQF_WRITE }, - { "NUSIZ1", 0x05, EQF_WRITE }, - { "COLUP0", 0x06, EQF_WRITE }, - { "COLUP1", 0x07, EQF_WRITE }, - { "COLUPF", 0x08, EQF_WRITE }, - { "COLUBK", 0x09, EQF_WRITE }, - { "CTRLPF", 0x0A, EQF_WRITE }, - { "REFP0", 0x0B, EQF_WRITE }, - { "REFP1", 0x0C, EQF_WRITE }, - { "PF0", 0x0D, EQF_WRITE }, - { "PF1", 0x0E, EQF_WRITE }, - { "PF2", 0x0F, EQF_WRITE }, - { "RESP0", 0x10, EQF_WRITE }, - { "RESP1", 0x11, EQF_WRITE }, - { "RESM0", 0x12, EQF_WRITE }, - { "RESM1", 0x13, EQF_WRITE }, - { "RESBL", 0x14, EQF_WRITE }, - { "AUDC0", 0x15, EQF_WRITE }, - { "AUDC1", 0x16, EQF_WRITE }, - { "AUDF0", 0x17, EQF_WRITE }, - { "AUDF1", 0x18, EQF_WRITE }, - { "AUDV0", 0x19, EQF_WRITE }, - { "AUDV1", 0x1A, EQF_WRITE }, - { "GRP0", 0x1B, EQF_WRITE }, - { "GRP1", 0x1C, EQF_WRITE }, - { "ENAM0", 0x1D, EQF_WRITE }, - { "ENAM1", 0x1E, EQF_WRITE }, - { "ENABL", 0x1F, EQF_WRITE }, - { "HMP0", 0x20, EQF_WRITE }, - { "HMP1", 0x21, EQF_WRITE }, - { "HMM0", 0x22, EQF_WRITE }, - { "HMM1", 0x23, EQF_WRITE }, - { "HMBL", 0x24, EQF_WRITE }, - { "VDELP0", 0x25, EQF_WRITE }, - { "VDEL01", 0x26, EQF_WRITE }, - { "VDELP1", 0x26, EQF_WRITE }, - { "VDELBL", 0x27, EQF_WRITE }, - { "RESMP0", 0x28, EQF_WRITE }, - { "RESMP1", 0x29, EQF_WRITE }, - { "HMOVE", 0x2A, EQF_WRITE }, - { "HMCLR", 0x2B, EQF_WRITE }, - { "CXCLR", 0x2C, EQF_WRITE }, - -// Mirrored $40-based TIA write locations: - { "VSYNC.40", 0x40, EQF_WRITE }, - { "VBLANK.40", 0x41, EQF_WRITE }, - { "WSYNC.40", 0x42, EQF_WRITE }, - { "RSYNC.40", 0x43, EQF_WRITE }, - { "NUSIZ0.40", 0x44, EQF_WRITE }, - { "NUSIZ1.40", 0x45, EQF_WRITE }, - { "COLUP0.40", 0x46, EQF_WRITE }, - { "COLUP1.40", 0x47, EQF_WRITE }, - { "COLUPF.40", 0x48, EQF_WRITE }, - { "COLUBK.40", 0x49, EQF_WRITE }, - { "CTRLPF.40", 0x4A, EQF_WRITE }, - { "REFP0.40", 0x4B, EQF_WRITE }, - { "REFP1.40", 0x4C, EQF_WRITE }, - { "PF0.40", 0x4D, EQF_WRITE }, - { "PF1.40", 0x4E, EQF_WRITE }, - { "PF2.40", 0x4F, EQF_WRITE }, - { "RESP0.40", 0x50, EQF_WRITE }, - { "RESP1.40", 0x51, EQF_WRITE }, - { "RESM0.40", 0x52, EQF_WRITE }, - { "RESM1.40", 0x53, EQF_WRITE }, - { "RESBL.40", 0x54, EQF_WRITE }, - { "AUDC0.40", 0x55, EQF_WRITE }, - { "AUDC1.40", 0x56, EQF_WRITE }, - { "AUDF0.40", 0x57, EQF_WRITE }, - { "AUDF1.40", 0x58, EQF_WRITE }, - { "AUDV0.40", 0x59, EQF_WRITE }, - { "AUDV1.40", 0x5A, EQF_WRITE }, - { "GRP0.40", 0x5B, EQF_WRITE }, - { "GRP1.40", 0x5C, EQF_WRITE }, - { "ENAM0.40", 0x5D, EQF_WRITE }, - { "ENAM1.40", 0x5E, EQF_WRITE }, - { "ENABL.40", 0x5F, EQF_WRITE }, - { "HMP0.40", 0x60, EQF_WRITE }, - { "HMP1.40", 0x61, EQF_WRITE }, - { "HMM0.40", 0x62, EQF_WRITE }, - { "HMM1.40", 0x63, EQF_WRITE }, - { "HMBL.40", 0x64, EQF_WRITE }, - { "VDELP0.40", 0x65, EQF_WRITE }, - { "VDEL01.40", 0x66, EQF_WRITE }, - { "VDELP1.40", 0x66, EQF_WRITE }, - { "VDELBL.40", 0x67, EQF_WRITE }, - { "RESMP0.40", 0x68, EQF_WRITE }, - { "RESMP1.40", 0x69, EQF_WRITE }, - { "HMOVE.40", 0x6A, EQF_WRITE }, - { "HMCLR.40", 0x6B, EQF_WRITE }, - { "CXCLR.40", 0x6C, EQF_WRITE }, - -// Standard $00-based TIA read locations: - { "CXM0P", 0x00, EQF_READ }, - { "CXM1P", 0x01, EQF_READ }, - { "CXP0FB", 0x02, EQF_READ }, - { "CXP1FB", 0x03, EQF_READ }, - { "CXM0FB", 0x04, EQF_READ }, - { "CXM1FB", 0x05, EQF_READ }, - { "CXBLPF", 0x06, EQF_READ }, - { "CXPPMM", 0x07, EQF_READ }, - { "INPT0", 0x08, EQF_READ }, - { "INPT1", 0x09, EQF_READ }, - { "INPT2", 0x0A, EQF_READ }, - { "INPT3", 0x0B, EQF_READ }, - { "INPT4", 0x0C, EQF_READ }, - { "INPT5", 0x0D, EQF_READ }, - -// Mirrored $10-based TIA read locations: - { "CXM0P.10", 0x10, EQF_READ }, - { "CXM1P.10", 0x11, EQF_READ }, - { "CXP0FB.10", 0x12, EQF_READ }, - { "CXP1FB.10", 0x13, EQF_READ }, - { "CXM0FB.10", 0x14, EQF_READ }, - { "CXM1FB.10", 0x15, EQF_READ }, - { "CXBLPF.10", 0x16, EQF_READ }, - { "CXPPMM.10", 0x17, EQF_READ }, - { "INPT0.10", 0x18, EQF_READ }, - { "INPT1.10", 0x19, EQF_READ }, - { "INPT2.10", 0x1A, EQF_READ }, - { "INPT3.10", 0x1B, EQF_READ }, - { "INPT4.10", 0x1C, EQF_READ }, - { "INPT5.10", 0x1D, EQF_READ }, - -// Mirrored $20-based TIA read locations: - { "CXM0P.20", 0x20, EQF_READ }, - { "CXM1P.20", 0x21, EQF_READ }, - { "CXP0FB.20", 0x22, EQF_READ }, - { "CXP1FB.20", 0x23, EQF_READ }, - { "CXM0FB.20", 0x24, EQF_READ }, - { "CXM1FB.20", 0x25, EQF_READ }, - { "CXBLPF.20", 0x26, EQF_READ }, - { "CXPPMM.20", 0x27, EQF_READ }, - { "INPT0.20", 0x28, EQF_READ }, - { "INPT1.20", 0x29, EQF_READ }, - { "INPT2.20", 0x2A, EQF_READ }, - { "INPT3.20", 0x2B, EQF_READ }, - { "INPT4.20", 0x2C, EQF_READ }, - { "INPT5.20", 0x2D, EQF_READ }, - -// Mirrored $30-based TIA read locations: - { "CXM0P.30", 0x30, EQF_READ }, - { "CXM1P.30", 0x31, EQF_READ }, - { "CXP0FB.30", 0x32, EQF_READ }, - { "CXP1FB.30", 0x33, EQF_READ }, - { "CXM0FB.30", 0x34, EQF_READ }, - { "CXM1FB.30", 0x35, EQF_READ }, - { "CXBLPF.30", 0x36, EQF_READ }, - { "CXPPMM.30", 0x37, EQF_READ }, - { "INPT0.30", 0x38, EQF_READ }, - { "INPT1.30", 0x39, EQF_READ }, - { "INPT2.30", 0x3A, EQF_READ }, - { "INPT3.30", 0x3B, EQF_READ }, - { "INPT4.30", 0x3C, EQF_READ }, - { "INPT5.30", 0x3D, EQF_READ }, - -// Standard RIOT locations (read, write, or both): - { "SWCHA", 0x280, EQF_RW }, - { "SWCHB", 0x282, EQF_RW }, - { "SWACNT", 0x281, EQF_WRITE }, - { "SWBCNT", 0x283, EQF_WRITE }, - { "INTIM", 0x284, EQF_READ }, - { "TIMINT", 0x285, EQF_READ }, - { "TIM1T", 0x294, EQF_WRITE }, - { "TIM8T", 0x295, EQF_WRITE }, - { "TIM64T", 0x296, EQF_WRITE }, - { "T1024T", 0x297, EQF_WRITE } -}; diff --git a/src/debugger/EquateList.hxx b/src/debugger/EquateList.hxx deleted file mode 100644 index 65427f6d8..000000000 --- a/src/debugger/EquateList.hxx +++ /dev/null @@ -1,122 +0,0 @@ -//============================================================================ -// -// SSSS tt lll lll -// SS SS tt ll ll -// SS tttttt eeee ll ll aaaa -// SSSS tt ee ee ll ll aa -// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" -// SS SS tt ee ll ll aa aa -// SSSS ttt eeeee llll llll aaaaa -// -// Copyright (c) 1995-2010 by Bradford W. Mott and the Stella Team -// -// See the file "License.txt" for information on usage and redistribution of -// this file, and for a DISCLAIMER OF ALL WARRANTIES. -// -// $Id$ -//============================================================================ - -#ifndef EQUATELIST_HXX -#define EQUATELIST_HXX - -#include - -#include "bspf.hxx" - -class EquateList -{ - public: - EquateList(); - ~EquateList(); - - /** - Add an equate consisting of the given label and address - */ - void addEquate(const string& label, uInt16 address); - - /** - Remove the equate with the given label - */ - bool removeEquate(const string& label); - - /** - Accessor methods for labels and addresses - - The mapping from address to label can be one-to-many (ie, an - address can have different labels depending on its context, and - whether its being read or written; if isRead is true, the context - is a read, else it's a write - If places is not -1 and a label hasn't been defined, return a - formatted hexidecimal address - */ - const string& getLabel(uInt16 addr, bool isRead, int places = -1); - int getAddress(const string& label) const; - - /** - Load user equates from the given symbol file (generated by DASM) - */ - string loadFile(const string& file); - - /** - Save user equates into a symbol file similar to that generated by DASM - */ - bool saveFile(const string& file); - - /** - Methods used by the command parser for tab-completion - */ - int countCompletions(const char *in); - const string& getCompletions() const { return myCompletions; } - const string& getCompletionPrefix() const { return myCompPrefix; } - - private: - enum equate_t { - EQF_READ = 1 << 0, // address can be read from - EQF_WRITE = 1 << 1, // address can be written to - EQF_RW = EQF_READ | EQF_WRITE // address can be both read and written - }; - enum address_t { - ADDR_TIA = 1 << 0, - ADDR_RAM = 1 << 1, - ADDR_RIOT = 1 << 2, - ADDR_ROM = 1 << 3 - }; - struct Equate { - string label; - uInt16 address; - equate_t flags; - }; - - typedef map AddrToLabel; - typedef map LabelToAddr; - - private: - // Extract labels and values from the given character stream - string extractLabel(char *c); - int extractValue(char *c); - - // Count completions for the given mapping - int countCompletions(const char *in, LabelToAddr& addresses); - - // Determine what type address we're dealing with - inline void addressType(uInt16 addr); - - private: - enum { kSystemEquateSize = 158 }; - static const Equate ourSystemEquates[kSystemEquateSize]; - - string myCompletions; - string myCompPrefix; - - LabelToAddr mySystemAddresses; - AddrToLabel mySystemReadLabels; // labels used in a read context - AddrToLabel mySystemWriteLabels; // labels used in a write context - - LabelToAddr myUserAddresses; - AddrToLabel myUserLabels; - - address_t myAddressType; - string myCurrentLabel; -}; - -#endif diff --git a/src/debugger/RamDebug.cxx b/src/debugger/RamDebug.cxx deleted file mode 100644 index 2c46a2564..000000000 --- a/src/debugger/RamDebug.cxx +++ /dev/null @@ -1,164 +0,0 @@ -//============================================================================ -// -// SSSS tt lll lll -// SS SS tt ll ll -// SS tttttt eeee ll ll aaaa -// SSSS tt ee ee ll ll aa -// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" -// SS SS tt ee ll ll aa aa -// SSSS ttt eeeee llll llll aaaaa -// -// Copyright (c) 1995-2010 by Bradford W. Mott and the Stella Team -// -// See the file "License.txt" for information on usage and redistribution of -// this file, and for a DISCLAIMER OF ALL WARRANTIES. -// -// $Id$ -//============================================================================ - -#include "bspf.hxx" -#include "Array.hxx" -#include "System.hxx" -#include "RamDebug.hxx" - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -RamDebug::RamDebug(Debugger& dbg, Console& console) - : DebuggerSystem(dbg, console) -{ - // Zero-page RAM is always present - addRamArea(0x80, 128, 0, 0); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void RamDebug::addRamArea(uInt16 start, uInt16 size, - uInt16 roffset, uInt16 woffset) -{ - // First make sure this area isn't already present - for(uInt32 i = 0; i < myState.rport.size(); ++i) - if(myState.rport[i] == start + roffset || - myState.wport[i] == start + woffset) - return; - - // Otherwise, add a new area - for(uInt32 i = 0; i < size; ++i) - { - myState.rport.push_back(i + start + roffset); - myState.wport.push_back(i + start + woffset); - - myOldState.rport.push_back(i + start + roffset); - myOldState.wport.push_back(i + start + woffset); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void RamDebug::addRamArea(const RamAreaList& areas) -{ - myRamAreas = areas; - for(RamAreaList::const_iterator i = areas.begin(); i != areas.end(); ++i) - addRamArea(i->start, i->size, i->roffset, i->woffset); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const DebuggerState& RamDebug::getState() -{ - myState.ram.clear(); - for(uInt32 i = 0; i < myState.rport.size(); ++i) - myState.ram.push_back(read(myState.rport[i])); - - return myState; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void RamDebug::saveOldState() -{ - myOldState.ram.clear(); - for(uInt32 i = 0; i < myOldState.rport.size(); ++i) - myOldState.ram.push_back(read(myOldState.rport[i])); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 RamDebug::read(uInt16 addr) -{ - return mySystem.peek(addr); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void RamDebug::write(uInt16 addr, uInt8 value) -{ - mySystem.poke(addr, value); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int RamDebug::readFromWritePort() -{ - uInt16 addr = mySystem.m6502().lastReadAddress(); - if(addr & 0x1000) - { - addr &= 0x0FFF; - for(RamAreaList::const_iterator i = myRamAreas.begin(); i != myRamAreas.end(); ++i) - { - uInt16 start = (i->start + i->woffset) & 0x0FFF; - uInt16 end = (i->start + i->woffset + i->size) & 0x0FFF; - if(addr >= start && addr < end) - return addr; - } - } - return 0; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string RamDebug::toString() -{ - string result; - char buf[128]; - uInt32 bytesPerLine; - - switch(myDebugger.parser().base()) - { - case kBASE_16: - case kBASE_10: - bytesPerLine = 0x10; - break; - - case kBASE_2: - bytesPerLine = 0x04; - break; - - case kBASE_DEFAULT: - default: - return DebuggerParser::red("invalid base, this is a BUG"); - } - - const RamState& state = (RamState&) getState(); - const RamState& oldstate = (RamState&) getOldState(); - - uInt32 curraddr = 0, bytesSoFar = 0; - for(uInt32 i = 0; i < state.ram.size(); i += bytesPerLine, bytesSoFar += bytesPerLine) - { - // We detect different 'pages' of RAM when the addresses jump by - // more than the number of bytes on the previous line, or when 256 - // bytes have been previously output - if(state.rport[i] - curraddr > bytesPerLine || bytesSoFar >= 256) - { - sprintf(buf, "%04x: (rport = %04x, wport = %04x)\n", - state.rport[i], state.rport[i], state.wport[i]); - buf[2] = buf[3] = 'x'; - result += DebuggerParser::red(buf); - bytesSoFar = 0; - } - curraddr = state.rport[i]; - sprintf(buf, "%.2x: ", curraddr & 0x00ff); - result += buf; - - for(uInt8 j = 0; j < bytesPerLine; ++j) - { - result += myDebugger.invIfChanged(state.ram[i+j], oldstate.ram[i+j]); - result += " "; - - if(j == 0x07) result += " "; - } - result += "\n"; - } - - return result; -} diff --git a/src/debugger/RamDebug.hxx b/src/debugger/RamDebug.hxx deleted file mode 100644 index f3d3bda42..000000000 --- a/src/debugger/RamDebug.hxx +++ /dev/null @@ -1,82 +0,0 @@ -//============================================================================ -// -// SSSS tt lll lll -// SS SS tt ll ll -// SS tttttt eeee ll ll aaaa -// SSSS tt ee ee ll ll aa -// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" -// SS SS tt ee ll ll aa aa -// SSSS ttt eeeee llll llll aaaaa -// -// Copyright (c) 1995-2010 by Bradford W. Mott and the Stella Team -// -// See the file "License.txt" for information on usage and redistribution of -// this file, and for a DISCLAIMER OF ALL WARRANTIES. -// -// $Id$ -//============================================================================ - -#ifndef RAM_DEBUG_HXX -#define RAM_DEBUG_HXX - -class System; - -#include "bspf.hxx" -#include "Array.hxx" -#include "Cart.hxx" -#include "DebuggerSystem.hxx" - -// pointer types for RamDebug instance methods -typedef int (RamDebug::*RAMDEBUG_INT_METHOD)(); - -// call the pointed-to method on the (global) CPU debugger object. -#define CALL_RAMDEBUG_METHOD(method) ( ( Debugger::debugger().ramDebug().*method)() ) - -class RamState : public DebuggerState -{ - public: - IntArray ram; // The actual data values - IntArray rport; // Address for reading from RAM - IntArray wport; // Address for writing to RAM -}; - -class RamDebug : public DebuggerSystem -{ - public: - RamDebug(Debugger& dbg, Console& console); - - /** - Let the RAM debugger subsystem treat this area as addressable memory. - - @param start The beginning of the RAM area (0x0000 - 0x2000) - @param size Total number of bytes of area - @param roffset Offset to use when reading from RAM (read port) - @param woffset Offset to use when writing to RAM (write port) - */ - void addRamArea(uInt16 start, uInt16 size, uInt16 roffset, uInt16 woffset); - void addRamArea(const RamAreaList& areas); - - const DebuggerState& getState(); - const DebuggerState& getOldState() { return myOldState; } - - void saveOldState(); - string toString(); - - // The following assume that the given addresses are using the - // correct read/write port ranges; no checking will be done to - // confirm this. - uInt8 read(uInt16 addr); - void write(uInt16 addr, uInt8 value); - - // Return the address at which an invalid read was performed in a - // write port area. - int readFromWritePort(); - - private: - RamState myState; - RamState myOldState; - - RamAreaList myRamAreas; -}; - -#endif diff --git a/src/debugger/gui/CpuWidget.cxx b/src/debugger/gui/CpuWidget.cxx index fda91f8df..3f7a12a5f 100644 --- a/src/debugger/gui/CpuWidget.cxx +++ b/src/debugger/gui/CpuWidget.cxx @@ -24,6 +24,7 @@ #include "OSystem.hxx" #include "GuiObject.hxx" #include "Debugger.hxx" +#include "CartDebug.hxx" #include "CpuDebug.hxx" #include "Widget.hxx" #include "DataGridWidget.hxx" @@ -280,5 +281,5 @@ void CpuWidget::fillGrid() changed.push_back(state.PSbits[i] != oldstate.PSbits[i]); myPSRegister->setState(state.PSbits, changed); - myPCLabel->setEditString(dbg.equates().getLabel(state.PC, true)); + myPCLabel->setEditString(dbg.cartDebug().getLabel(state.PC, true)); } diff --git a/src/debugger/gui/PromptWidget.cxx b/src/debugger/gui/PromptWidget.cxx index 8cdf903b3..719d544f9 100644 --- a/src/debugger/gui/PromptWidget.cxx +++ b/src/debugger/gui/PromptWidget.cxx @@ -31,7 +31,7 @@ #include "DebuggerParser.hxx" #include "PromptWidget.hxx" -#include "EquateList.hxx" +#include "CartDebug.hxx" #define PROMPT "> " @@ -253,8 +253,8 @@ bool PromptWidget::handleKeyDown(int ascii, int keycode, int modifiers) else { // we got a delimiter, so this must be a label: - EquateList& equates = instance().debugger().equates(); - possibilities = equates.countCompletions(str + lastDelimPos + 1); + CartDebug& cart = instance().debugger().cartDebug(); + possibilities = cart.countCompletions(str + lastDelimPos + 1); if(possibilities < 1) { delete[] str; @@ -262,8 +262,8 @@ bool PromptWidget::handleKeyDown(int ascii, int keycode, int modifiers) } // TODO - perhaps use strings instead of char pointers - completionList = equates.getCompletions().c_str(); - prefix = equates.getCompletionPrefix().c_str(); + completionList = cart.getCompletions().c_str(); + prefix = cart.getCompletionPrefix().c_str(); } if(possibilities == 1) diff --git a/src/debugger/gui/RamWidget.cxx b/src/debugger/gui/RamWidget.cxx index 244ef831d..4427989eb 100644 --- a/src/debugger/gui/RamWidget.cxx +++ b/src/debugger/gui/RamWidget.cxx @@ -27,7 +27,7 @@ #include "GuiObject.hxx" #include "InputTextDialog.hxx" #include "OSystem.hxx" -#include "RamDebug.hxx" +#include "CartDebug.hxx" #include "Widget.hxx" #include "RamWidget.hxx" @@ -159,8 +159,8 @@ void RamWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) // memory location int addr, value; - RamDebug& dbg = instance().debugger().ramDebug(); - const RamState& state = (RamState&) dbg.getState(); + CartDebug& dbg = instance().debugger().cartDebug(); + const CartState& state = (CartState&) dbg.getState(); switch(cmd) { case kDGItemDataChangedCmd: @@ -193,8 +193,7 @@ void RamWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) addr = myRamGrid->getSelectedAddr(); value = myRamGrid->getSelectedValue(); - myLabel->setEditString( - instance().debugger().equates().getLabel(state.rport[addr], true)); + myLabel->setEditString(dbg.getLabel(state.rport[addr], true)); myDecValue->setEditString(instance().debugger().valueToString(value, kBASE_10)); myBinValue->setEditString(instance().debugger().valueToString(value, kBASE_2)); break; @@ -267,10 +266,10 @@ void RamWidget::fillGrid(bool updateOld) if(updateOld) myOldValueList.clear(); - RamDebug& dbg = instance().debugger().ramDebug(); + CartDebug& dbg = instance().debugger().cartDebug(); - const RamState& state = (RamState&) dbg.getState(); - const RamState& oldstate = (RamState&) dbg.getOldState(); + const CartState& state = (CartState&) dbg.getState(); + const CartState& oldstate = (CartState&) dbg.getOldState(); // Jump to the correct 128 byte 'window' in the RAM area // This assumes that the RAM areas are aligned on 128 byte boundaries @@ -346,8 +345,8 @@ string RamWidget::doSearch(const string& str) // Now, search all memory locations for this value, and add it to the // search array bool hitfound = false; - RamDebug& dbg = instance().debugger().ramDebug(); - const RamState& state = (RamState&) dbg.getState(); + CartDebug& dbg = instance().debugger().cartDebug(); + const CartState& state = (CartState&) dbg.getState(); for(uInt32 addr = 0; addr < state.ram.size(); ++addr) { int value = state.ram[addr]; @@ -415,8 +414,8 @@ string RamWidget::doCompare(const string& str) // Now, search all memory locations previously 'found' for this value bool hitfound = false; - RamDebug& dbg = instance().debugger().ramDebug(); - const RamState& state = (RamState&) dbg.getState(); + CartDebug& dbg = instance().debugger().cartDebug(); + const CartState& state = (CartState&) dbg.getState(); IntArray tempAddrList, tempValueList; mySearchState.clear(); for(uInt32 i = 0; i < state.rport.size(); ++i) diff --git a/src/debugger/gui/RomListWidget.cxx b/src/debugger/gui/RomListWidget.cxx index 128b5d5d5..fff5b8a67 100644 --- a/src/debugger/gui/RomListWidget.cxx +++ b/src/debugger/gui/RomListWidget.cxx @@ -41,7 +41,7 @@ RomListWidget::RomListWidget(GuiObject* boss, const GUI::Font& font, const int fontWidth = font.getMaxCharWidth(), numchars = w / fontWidth; - myLabelWidth = BSPF_max(20, int(0.35 * (numchars - 12))) * fontWidth; + myLabelWidth = BSPF_max(16, int(0.35 * (numchars - 12))) * fontWidth; myBytesWidth = 12 * fontWidth; } @@ -85,7 +85,7 @@ void RomListWidget::drawWidget(bool hilite) { //cerr << "RomListWidget::drawWidget\n"; FBSurface& s = _boss->dialog().surface(); - int i, pos, len = _list.size(); + int i, pos, xpos, ypos, len = _list.size(); string buffer; int deltax; @@ -97,18 +97,16 @@ void RomListWidget::drawWidget(bool hilite) s.vLine(_x + CheckboxWidget::boxSize() + 5, _y, _y + _h - 1, kColor); // Draw the list items - for (i = 0, pos = _currentPos; i < _rows && pos < len; i++, pos++) + GUI::Rect r = getEditRect(); + GUI::Rect l = getLineRect(); + xpos = _x + CheckboxWidget::boxSize() + 10; ypos = _y + 2; + for (i = 0, pos = _currentPos; i < _rows && pos < len; i++, pos++, ypos += _fontHeight) { // Draw checkboxes for correct lines (takes scrolling into account) _checkList[i]->setState(_stateList[pos]); _checkList[i]->setDirty(); _checkList[i]->draw(); - const int y = _y + 2 + _fontHeight * i; - - GUI::Rect l = getLineRect(); - GUI::Rect r = getEditRect(); - // Draw highlighted item in a frame if (_highlightedItem == pos) { @@ -127,12 +125,13 @@ void RomListWidget::drawWidget(bool hilite) r.width(), _fontHeight, kTextColorHi); } - // Draw labels and actual disassembly - s.drawString(_font, myLabel[pos], _x + r.left - myLabelWidth, y, + // Draw labels + s.drawString(_font, myLabel[pos], xpos, ypos, myLabelWidth, kTextColor); - s.drawString(_font, myDisasm[pos], _x + r.right, y, - _w - r.right, kTextColor); + // Draw disassembly + s.drawString(_font, myDisasm[pos], xpos + myLabelWidth, ypos, + r.left, kTextColor); // Draw editable bytes if (_selectedItem == pos && _editMode) @@ -141,14 +140,14 @@ void RomListWidget::drawWidget(bool hilite) adjustOffset(); deltax = -_editScrollOffset; - s.drawString(_font, buffer, _x + r.left, y, r.width(), kTextColor, + s.drawString(_font, buffer, _x + r.left, ypos, r.width(), kTextColor, kTextAlignLeft, deltax, false); } else { buffer = _list[pos]; deltax = 0; - s.drawString(_font, buffer, _x + r.left, y, r.width(), kTextColor); + s.drawString(_font, buffer, _x + r.left, ypos, r.width(), kTextColor); } } @@ -176,12 +175,11 @@ GUI::Rect RomListWidget::getLineRect() const GUI::Rect RomListWidget::getEditRect() const { GUI::Rect r(2, 1, _w, _fontHeight); - const int yoffset = (_selectedItem - _currentPos) * _fontHeight, - xoffset = CheckboxWidget::boxSize() + 10; + const int yoffset = (_selectedItem - _currentPos) * _fontHeight; r.top += yoffset; r.bottom += yoffset; - r.left += xoffset + myLabelWidth; - r.right = r.left + myBytesWidth; + r.left += _w - myBytesWidth; + r.right = _w; return r; } diff --git a/src/debugger/gui/RomWidget.cxx b/src/debugger/gui/RomWidget.cxx index 52a4f9012..b040996d7 100644 --- a/src/debugger/gui/RomWidget.cxx +++ b/src/debugger/gui/RomWidget.cxx @@ -23,6 +23,7 @@ #include "Debugger.hxx" #include "DebuggerParser.hxx" +#include "CartDebug.hxx" #include "CpuDebug.hxx" #include "DataGridWidget.hxx" #include "PackedBitArray.hxx" @@ -38,7 +39,6 @@ RomWidget::RomWidget(GuiObject* boss, const GUI::Font& font, int x, int y) : Widget(boss, font, x, y, 16, 16), CommandSender(boss), myListIsDirty(true), - mySourceAvailable(false), myCurrentBank(-1) { _type = kRomWidget; @@ -57,8 +57,8 @@ RomWidget::RomWidget(GuiObject* boss, const GUI::Font& font, int x, int y) myBank = new DataGridWidget(boss, font, xpos, ypos-2, 1, 1, 4, 8, kBASE_10); myBank->setTarget(this); - myBank->setRange(0, instance().debugger().bankCount()); - if(instance().debugger().bankCount() <= 1) + myBank->setRange(0, instance().debugger().cartDebug().bankCount()); + if(instance().debugger().cartDebug().bankCount() <= 1) myBank->setEditable(false); addFocusWidget(myBank); @@ -111,10 +111,6 @@ void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { - case kListScrolledCmd: - incrementalUpdate(data, myRomList->rows()); - break; - case kListItemChecked: setBreak(data); break; @@ -164,19 +160,45 @@ void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) void RomWidget::loadConfig() { Debugger& dbg = instance().debugger(); - bool bankChanged = myCurrentBank != dbg.getBank(); + CartDebug& cart = dbg.cartDebug(); + bool bankChanged = myCurrentBank != cart.getBank(); + myCurrentBank = cart.getBank(); + // Fill romlist the current bank of source or disassembly // Only reload full bank when necessary if(myListIsDirty || bankChanged) { - initialUpdate(); + // Clear old mappings + myAddrList.clear(); + myLineList.clear(); + + StringList label, data, disasm; + BoolArray state; + + // Disassemble zero-page RAM and entire bank and reset breakpoints + cart.disassemble(myAddrList, label, data, disasm, 0x80, 0xff); + cart.disassemble(myAddrList, label, data, disasm, 0xf000, 0xffff); + + PackedBitArray& bp = dbg.breakpoints(); + for(unsigned int i = 0; i < data.size(); ++i) + { + if(bp.isSet(myAddrList[i])) + state.push_back(true); + else + state.push_back(false); + } + + // Create a mapping from addresses to line numbers + for(unsigned int i = 0; i < myAddrList.size(); ++i) + myLineList.insert(make_pair(myAddrList[i], i)); + + myRomList->setList(label, data, disasm, state); + + // Restore the old bank, in case we inadvertently switched while reading. + dbg.setBank(myCurrentBank); + myListIsDirty = false; } - else // only reload what's in current view - { - incrementalUpdate(myRomList->currentPos(), myRomList->rows()); - } - myCurrentBank = dbg.getBank(); // Update romlist to point to current PC // Take mirroring of PC into account, as well as zero-page RAM @@ -204,62 +226,12 @@ void RomWidget::loadConfig() BoolArray changed; alist.push_back(-1); - vlist.push_back(dbg.getBank()); + vlist.push_back(cart.getBank()); changed.push_back(bankChanged); myBank->setList(alist, vlist, changed); // Indicate total number of banks - myBankCount->setEditString(dbg.valueToString(dbg.bankCount(), kBASE_10)); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void RomWidget::initialUpdate() -{ - Debugger& dbg = instance().debugger(); - PackedBitArray& bp = dbg.breakpoints(); - - // Reading from ROM might trigger a bankswitch, so save the current bank - myCurrentBank = dbg.getBank(); - - // Fill romlist the current bank of source or disassembly - if(mySourceAvailable) - ; // TODO - actually implement this - else - { - // Clear old mappings - myAddrList.clear(); - myLineList.clear(); - - StringList label, data, disasm; - BoolArray state; - - // Disassemble zero-page RAM and entire bank and reset breakpoints -// dbg.disassemble(myAddrList, label, data, disasm, 0x80, 0xff); - dbg.disassemble(myAddrList, label, data, disasm, 0xf000, 0xffff); - for(unsigned int i = 0; i < data.size(); ++i) - { - if(bp.isSet(myAddrList[i])) - state.push_back(true); - else - state.push_back(false); - } - - // Create a mapping from addresses to line numbers - myLineList.clear(); - for(unsigned int i = 0; i < myAddrList.size(); ++i) - myLineList.insert(make_pair(myAddrList[i], i)); - - myRomList->setList(label, data, disasm, state); - } - - // Restore the old bank, in case we inadvertently switched while reading. - dbg.setBank(myCurrentBank); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void RomWidget::incrementalUpdate(int line, int rows) -{ - // TODO - implement this + myBankCount->setEditString(dbg.valueToString(cart.bankCount(), kBASE_10)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/debugger/gui/RomWidget.hxx b/src/debugger/gui/RomWidget.hxx index 34f389be4..c0880dd39 100644 --- a/src/debugger/gui/RomWidget.hxx +++ b/src/debugger/gui/RomWidget.hxx @@ -50,9 +50,6 @@ class RomWidget : public Widget, public CommandSender void loadConfig(); private: - void initialUpdate(); - void incrementalUpdate(int line, int rows); - void setBreak(int data); void setPC(int data); void patchROM(int data, const string& bytes); @@ -76,7 +73,6 @@ class RomWidget : public Widget, public CommandSender InputTextDialog* mySaveRom; bool myListIsDirty; - bool mySourceAvailable; int myCurrentBank; }; diff --git a/src/debugger/gui/TiaWidget.cxx b/src/debugger/gui/TiaWidget.cxx index 64f9538e6..fafd90f16 100644 --- a/src/debugger/gui/TiaWidget.cxx +++ b/src/debugger/gui/TiaWidget.cxx @@ -25,6 +25,7 @@ #include "FrameBuffer.hxx" #include "GuiObject.hxx" #include "OSystem.hxx" +#include "CartDebug.hxx" #include "TIADebug.hxx" #include "ToggleBitWidget.hxx" #include "TogglePixelWidget.hxx" @@ -598,6 +599,7 @@ void TiaWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) string buf; Debugger& dbg = instance().debugger(); + CartDebug& cart = dbg.cartDebug(); TIADebug& tia = dbg.tiaDebug(); switch(cmd) @@ -751,7 +753,7 @@ void TiaWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) // We're using the read-addresses here // Should we also add write-addresses, or remove this entirely? - myLabel->setEditString(dbg.equates().getLabel(addr, true)); + myLabel->setEditString(cart.getLabel(addr, true)); myDecValue->setEditString(dbg.valueToString(value, kBASE_10)); myBinValue->setEditString(dbg.valueToString(value, kBASE_2)); diff --git a/src/debugger/module.mk b/src/debugger/module.mk index 5a9e4868e..701dc7f78 100644 --- a/src/debugger/module.mk +++ b/src/debugger/module.mk @@ -3,11 +3,11 @@ MODULE := src/debugger MODULE_OBJS := \ src/debugger/Debugger.o \ src/debugger/DebuggerParser.o \ - src/debugger/EquateList.o \ src/debugger/Expression.o \ src/debugger/PackedBitArray.o \ + src/debugger/CartDebug.o \ src/debugger/CpuDebug.o \ - src/debugger/RamDebug.o \ + src/debugger/DiStella.o \ src/debugger/RiotDebug.o \ src/debugger/TIADebug.o diff --git a/src/emucore/Cart.cxx b/src/emucore/Cart.cxx index e901ae341..bbc6269b0 100644 --- a/src/emucore/Cart.cxx +++ b/src/emucore/Cart.cxx @@ -53,7 +53,7 @@ #include "Settings.hxx" #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" - #include "RamDebug.hxx" + #include "CartDebug.hxx" #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -263,6 +263,15 @@ void Cartridge::registerRamArea(uInt16 start, uInt16 size, #endif } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Cartridge::triggerReadFromWritePort(uInt16 address) +{ +#ifdef DEBUGGER_SUPPORT + if(&Debugger::debugger().cartDebug()) + Debugger::debugger().cartDebug().triggerReadFromWritePort(address); +#endif +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Cartridge::autodetectType(const uInt8* image, uInt32 size) { diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index dfb07d30d..27504253d 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -169,6 +169,13 @@ class Cartridge : public Device */ void registerRamArea(uInt16 start, uInt16 size, uInt16 roffset, uInt16 woffset); + /** + Indicate that an illegal read from a write port has occurred. + + @param address The address of the illegal read + */ + void triggerReadFromWritePort(uInt16 address); + private: /** Get an image pointer and size for a ROM that is part of a larger, diff --git a/src/emucore/Cart3E.cxx b/src/emucore/Cart3E.cxx index 870db6651..6233ac777 100644 --- a/src/emucore/Cart3E.cxx +++ b/src/emucore/Cart3E.cxx @@ -95,6 +95,7 @@ void Cartridge3E::install(System& system) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Cartridge3E::peek(uInt16 address) { + uInt16 peekAddress = address; address &= 0x0FFF; if(address < 0x0800) @@ -110,8 +111,13 @@ uInt8 Cartridge3E::peek(uInt16 address) // Reading from the write port triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); - if(myBankLocked) return value; - else return myRam[(address & 0x03FF) + ((myCurrentBank - 256) << 10)] = value; + if(myBankLocked) + return value; + else + { + triggerReadFromWritePort(peekAddress); + return myRam[(address & 0x03FF) + ((myCurrentBank - 256) << 10)] = value; + } } } } diff --git a/src/emucore/CartCV.cxx b/src/emucore/CartCV.cxx index e836f0002..6b94f0161 100644 --- a/src/emucore/CartCV.cxx +++ b/src/emucore/CartCV.cxx @@ -113,8 +113,13 @@ uInt8 CartridgeCV::peek(uInt16 address) // Reading from the write port triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); - if(myBankLocked) return value; - else return myRAM[address & 0x03FF] = value; + if(myBankLocked) + return value; + else + { + triggerReadFromWritePort(address); + return myRAM[address & 0x03FF] = value; + } } else { diff --git a/src/emucore/CartE7.cxx b/src/emucore/CartE7.cxx index 5ead1cd6a..cb7b012c8 100644 --- a/src/emucore/CartE7.cxx +++ b/src/emucore/CartE7.cxx @@ -92,6 +92,7 @@ void CartridgeE7::install(System& system) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeE7::peek(uInt16 address) { + uInt16 peekAddress = address; address &= 0x0FFF; // Switch banks if necessary @@ -109,16 +110,26 @@ uInt8 CartridgeE7::peek(uInt16 address) // Reading from the 1K write port @ $1000 triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); - if(myBankLocked) return value; - else return myRAM[address & 0x03FF] = value; + if(myBankLocked) + return value; + else + { + triggerReadFromWritePort(peekAddress); + return myRAM[address & 0x03FF] = value; + } } else if((address >= 0x0800) && (address <= 0x08FF)) { // Reading from the 256B write port @ $1800 triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); - if(myBankLocked) return value; - else return myRAM[1024 + (myCurrentRAM << 8) + (address & 0x00FF)] = value; + if(myBankLocked) + return value; + else + { + triggerReadFromWritePort(peekAddress); + return myRAM[1024 + (myCurrentRAM << 8) + (address & 0x00FF)] = value; + } } else return myImage[(myCurrentSlice[address >> 11] << 11) + (address & 0x07FF)]; diff --git a/src/emucore/CartEFSC.cxx b/src/emucore/CartEFSC.cxx index 8e36af03a..1e385c72f 100644 --- a/src/emucore/CartEFSC.cxx +++ b/src/emucore/CartEFSC.cxx @@ -93,6 +93,7 @@ void CartridgeEFSC::install(System& system) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeEFSC::peek(uInt16 address) { + uInt16 peekAddress = address; address &= 0x0FFF; // Switch banks if necessary @@ -104,8 +105,13 @@ uInt8 CartridgeEFSC::peek(uInt16 address) // Reading from the write port triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); - if(myBankLocked) return value; - else return myRAM[address] = value; + if(myBankLocked) + return value; + else + { + triggerReadFromWritePort(peekAddress); + return myRAM[address] = value; + } } else return myImage[(myCurrentBank << 12) + address]; diff --git a/src/emucore/CartF4SC.cxx b/src/emucore/CartF4SC.cxx index c9962fcbd..71dcaaa33 100644 --- a/src/emucore/CartF4SC.cxx +++ b/src/emucore/CartF4SC.cxx @@ -93,6 +93,7 @@ void CartridgeF4SC::install(System& system) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeF4SC::peek(uInt16 address) { + uInt16 peekAddress = address; address &= 0x0FFF; // Switch banks if necessary @@ -104,12 +105,14 @@ uInt8 CartridgeF4SC::peek(uInt16 address) // Reading from the write port triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); - if(myBankLocked) return value; - else return myRAM[address] = value; + if(myBankLocked) + return value; + else + { + triggerReadFromWritePort(peekAddress); + return myRAM[address] = value; + } } - else - return myImage[(myCurrentBank << 12) + address]; - // NOTE: This does not handle accessing RAM, however, this function // should never be called for RAM because of the way page accessing diff --git a/src/emucore/CartF6SC.cxx b/src/emucore/CartF6SC.cxx index 5309fc17a..5c1de730e 100644 --- a/src/emucore/CartF6SC.cxx +++ b/src/emucore/CartF6SC.cxx @@ -93,6 +93,7 @@ void CartridgeF6SC::install(System& system) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeF6SC::peek(uInt16 address) { + uInt16 peekAddress = address; address &= 0x0FFF; // Switch banks if necessary @@ -127,8 +128,13 @@ uInt8 CartridgeF6SC::peek(uInt16 address) // Reading from the write port triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); - if(myBankLocked) return value; - else return myRAM[address] = value; + if(myBankLocked) + return value; + else + { + triggerReadFromWritePort(peekAddress); + return myRAM[address] = value; + } } else return myImage[(myCurrentBank << 12) + address]; diff --git a/src/emucore/CartF8SC.cxx b/src/emucore/CartF8SC.cxx index 7346a0d86..faf6040b8 100644 --- a/src/emucore/CartF8SC.cxx +++ b/src/emucore/CartF8SC.cxx @@ -93,6 +93,7 @@ void CartridgeF8SC::install(System& system) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeF8SC::peek(uInt16 address) { + uInt16 peekAddress = address; address &= 0x0FFF; // Switch banks if necessary @@ -117,8 +118,13 @@ uInt8 CartridgeF8SC::peek(uInt16 address) // Reading from the write port triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); - if(myBankLocked) return value; - else return myRAM[address] = value; + if(myBankLocked) + return value; + else + { + triggerReadFromWritePort(peekAddress); + return myRAM[address] = value; + } } else return myImage[(myCurrentBank << 12) + address]; diff --git a/src/emucore/CartFA.cxx b/src/emucore/CartFA.cxx index b98286b53..08faf5454 100644 --- a/src/emucore/CartFA.cxx +++ b/src/emucore/CartFA.cxx @@ -93,6 +93,7 @@ void CartridgeFA::install(System& system) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeFA::peek(uInt16 address) { + uInt16 peekAddress = address; address &= 0x0FFF; // Switch banks if necessary @@ -122,8 +123,13 @@ uInt8 CartridgeFA::peek(uInt16 address) // Reading from the write port triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); - if(myBankLocked) return value; - else return myRAM[address] = value; + if(myBankLocked) + return value; + else + { + triggerReadFromWritePort(peekAddress); + return myRAM[address] = value; + } } else return myImage[(myCurrentBank << 12) + address]; diff --git a/src/emucore/M6502.cxx b/src/emucore/M6502.cxx index 6063904bb..17d941767 100644 --- a/src/emucore/M6502.cxx +++ b/src/emucore/M6502.cxx @@ -50,7 +50,7 @@ M6502::M6502(uInt32 systemCyclesPerProcessorCycle) // Compute the System Cycle table for(uInt32 t = 0; t < 256; ++t) { - myInstructionSystemCycleTable[t] = InstructionCycleTable[t] * + myInstructionSystemCycleTable[t] = ourInstructionCycleTable[t] * mySystemCyclesPerProcessorCycle; } @@ -537,173 +537,7 @@ void M6502::setTraps(PackedBitArray *read, PackedBitArray *write) #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -M6502::AddressingMode M6502::AddressModeTable[256] = { - Implied, IndirectX, Invalid, IndirectX, // 0x0? - Zero, Zero, Zero, Zero, - Implied, Immediate, Implied, Immediate, - Absolute, Absolute, Absolute, Absolute, - - Relative, IndirectY, Invalid, IndirectY, // 0x1? - ZeroX, ZeroX, ZeroX, ZeroX, - Implied, AbsoluteY, Implied, AbsoluteY, - AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX, - - Absolute, IndirectX, Invalid, IndirectX, // 0x2? - Zero, Zero, Zero, Zero, - Implied, Immediate, Implied, Immediate, - Absolute, Absolute, Absolute, Absolute, - - Relative, IndirectY, Invalid, IndirectY, // 0x3? - ZeroX, ZeroX, ZeroX, ZeroX, - Implied, AbsoluteY, Implied, AbsoluteY, - AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX, - - Implied, IndirectX, Invalid, IndirectX, // 0x4? - Zero, Zero, Zero, Zero, - Implied, Immediate, Implied, Immediate, - Absolute, Absolute, Absolute, Absolute, - - Relative, IndirectY, Invalid, IndirectY, // 0x5? - ZeroX, ZeroX, ZeroX, ZeroX, - Implied, AbsoluteY, Implied, AbsoluteY, - AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX, - - Implied, IndirectX, Invalid, IndirectX, // 0x6? - Zero, Zero, Zero, Zero, - Implied, Immediate, Implied, Immediate, - Indirect, Absolute, Absolute, Absolute, - - Relative, IndirectY, Invalid, IndirectY, // 0x7? - ZeroX, ZeroX, ZeroX, ZeroX, - Implied, AbsoluteY, Implied, AbsoluteY, - AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX, - - Immediate, IndirectX, Immediate, IndirectX, // 0x8? - Zero, Zero, Zero, Zero, - Implied, Immediate, Implied, Immediate, - Absolute, Absolute, Absolute, Absolute, - - Relative, IndirectY, Invalid, IndirectY, // 0x9? - ZeroX, ZeroX, ZeroY, ZeroY, - Implied, AbsoluteY, Implied, AbsoluteY, - AbsoluteX, AbsoluteX, AbsoluteY, AbsoluteY, - - Immediate, IndirectX, Immediate, IndirectX, // 0xA? - Zero, Zero, Zero, Zero, - Implied, Immediate, Implied, Immediate, - Absolute, Absolute, Absolute, Absolute, - - Relative, IndirectY, Invalid, IndirectY, // 0xB? - ZeroX, ZeroX, ZeroY, ZeroY, - Implied, AbsoluteY, Implied, AbsoluteY, - AbsoluteX, AbsoluteX, AbsoluteY, AbsoluteY, - - Immediate, IndirectX, Immediate, IndirectX, // 0xC? - Zero, Zero, Zero, Zero, - Implied, Immediate, Implied, Immediate, - Absolute, Absolute, Absolute, Absolute, - - Relative, IndirectY, Invalid, IndirectY, // 0xD? - ZeroX, ZeroX, ZeroX, ZeroX, - Implied, AbsoluteY, Implied, AbsoluteY, - AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX, - - Immediate, IndirectX, Immediate, IndirectX, // 0xE? - Zero, Zero, Zero, Zero, - Implied, Immediate, Implied, Immediate, - Absolute, Absolute, Absolute, Absolute, - - Relative, IndirectY, Invalid, IndirectY, // 0xF? - ZeroX, ZeroX, ZeroX, ZeroX, - Implied, AbsoluteY, Implied, AbsoluteY, - AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -M6502::AccessMode M6502::AccessModeTable[256] = { - None, Read, None, Write, // 0x0? - None, Read, Write, Write, - None, Read, Write, Read, - None, Read, Write, Write, - - Read, Read, None, Write, // 0x1? - None, Read, Write, Write, - None, Read, None, Write, - None, Read, Write, Write, - - Read, Read, None, Write, // 0x2? - Read, Read, Write, Write, - None, Read, Write, Read, - Read, Read, Write, Write, - - Read, Read, None, Write, // 0x3? - None, Read, Write, Write, - None, Read, None, Write, - None, Read, Write, Write, - - None, Read, None, Write, // 0x4? - None, Read, Write, Write, - None, Read, Write, Read, - Read, Read, Write, Write, - - Read, Read, None, Write, // 0x5? - None, Read, Write, Write, - None, Read, None, Write, - None, Read, Write, Write, - - None, Read, None, Write, // 0x6? - None, Read, Write, Write, - None, Read, Write, Read, - Read, Read, Write, Write, - - Read, Read, None, Write, // 0x7? - None, Read, Write, Write, - None, Read, None, Write, - None, Read, Write, Write, - - None, Write, None, Write, // 0x8? - Write, Write, Write, Write, - None, None, None, Read, - Write, Write, Write, Write, - - Read, Write, None, Write, // 0x9? - Write, Write, Write, Write, - None, Write, None, Write, - Write, Write, Write, Write, - - Read, Read, Read, Read, // 0xA? - Read, Read, Read, Read, - None, Read, None, Read, - Read, Read, Read, Read, - - Read, Read, None, Read, // 0xB? - Read, Read, Read, Read, - None, Read, None, Read, - Read, Read, Read, Read, - - Read, Read, None, Write, // 0xC? - Read, Read, Write, Write, - None, Read, None, Read, - Read, Read, Write, Write, - - Read, Read, None, Write, // 0xD? - None, Read, Write, Write, - None, Read, None, Write, - None, Read, Write, Write, - - Read, Read, None, Write, // 0xE? - Read, Read, Write, Write, - None, Read, None, Read, - Read, Read, Write, Write, - - Read, Read, None, Write, // 0xF? - None, Read, Write, Write, - None, Read, None, Write, - None, Read, Write, Write -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 M6502::InstructionCycleTable[256] = { +uInt32 M6502::ourInstructionCycleTable[256] = { // 0 1 2 3 4 5 6 7 8 9 a b c d e f 7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6, // 0 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, // 1 @@ -721,55 +555,4 @@ uInt32 M6502::InstructionCycleTable[256] = { 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, // d 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, // e 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7 // f - }; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const char* M6502::InstructionMnemonicTable[256] = { - "BRK", "ORA", "n/a", "slo", "nop", "ORA", "ASL", "slo", // 0x0? - "PHP", "ORA", "ASLA", "anc", "nop", "ORA", "ASL", "slo", - - "BPL", "ORA", "n/a", "slo", "nop", "ORA", "ASL", "slo", // 0x1? - "CLC", "ORA", "nop", "slo", "nop", "ORA", "ASL", "slo", - - "JSR", "AND", "n/a", "rla", "BIT", "AND", "ROL", "rla", // 0x2? - "PLP", "AND", "ROLA", "anc", "BIT", "AND", "ROL", "rla", - - "BMI", "AND", "n/a", "rla", "nop", "AND", "ROL", "rla", // 0x3? - "SEC", "AND", "nop", "rla", "nop", "AND", "ROL", "rla", - - "RTI", "EOR", "n/a", "sre", "nop", "EOR", "LSR", "sre", // 0x4? - "PHA", "EOR", "LSRA", "asr", "JMP", "EOR", "LSR", "sre", - - "BVC", "EOR", "n/a", "sre", "nop", "EOR", "LSR", "sre", // 0x5? - "CLI", "EOR", "nop", "sre", "nop", "EOR", "LSR", "sre", - - "RTS", "ADC", "n/a", "rra", "nop", "ADC", "ROR", "rra", // 0x6? - "PLA", "ADC", "RORA", "arr", "JMP", "ADC", "ROR", "rra", - - "BVS", "ADC", "n/a", "rra", "nop", "ADC", "ROR", "rra", // 0x7? - "SEI", "ADC", "nop", "rra", "nop", "ADC", "ROR", "rra", - - "nop", "STA", "nop", "sax", "STY", "STA", "STX", "sax", // 0x8? - "DEY", "nop", "TXA", "ane", "STY", "STA", "STX", "sax", - - "BCC", "STA", "n/a", "sha", "STY", "STA", "STX", "sax", // 0x9? - "TYA", "STA", "TXS", "shs", "shy", "STA", "shx", "sha", - - "LDY", "LDA", "LDX", "lax", "LDY", "LDA", "LDX", "lax", // 0xA? - "TAY", "LDA", "TAX", "lxa", "LDY", "LDA", "LDX", "lax", - - "BCS", "LDA", "n/a", "lax", "LDY", "LDA", "LDX", "lax", // 0xB? - "CLV", "LDA", "TSX", "las", "LDY", "LDA", "LDX", "lax", - - "CPY", "CMP", "nop", "dcp", "CPY", "CMP", "DEC", "dcp", // 0xC? - "INY", "CMP", "DEX", "sbx", "CPY", "CMP", "DEC", "dcp", - - "BNE", "CMP", "n/a", "dcp", "nop", "CMP", "DEC", "dcp", // 0xD? - "CLD", "CMP", "nop", "dcp", "nop", "CMP", "DEC", "dcp", - - "CPX", "SBC", "nop", "isb", "CPX", "SBC", "INC", "isb", // 0xE? - "INX", "SBC", "NOP", "sbc", "CPX", "SBC", "INC", "isb", - - "BEQ", "SBC", "n/a", "isb", "nop", "SBC", "INC", "isb", // 0xF? - "SED", "SBC", "nop", "isb", "nop", "SBC", "INC", "isb" }; diff --git a/src/emucore/M6502.hxx b/src/emucore/M6502.hxx index ec34494b4..36341820f 100644 --- a/src/emucore/M6502.hxx +++ b/src/emucore/M6502.hxx @@ -19,7 +19,6 @@ #ifndef M6502_HXX #define M6502_HXX -class D6502; class M6502; class Debugger; class CpuDebug; @@ -49,8 +48,9 @@ typedef Common::Array ExpressionList; */ class M6502 : public Serializable { - // The 6502 debugger class is a friend who needs special access - friend class CpuDebug; + // The 6502 and Cart debugger classes are friends who need special access + friend class CartDebug; + friend class CpuDebug; public: /** @@ -132,7 +132,7 @@ class M6502 : public Serializable */ bool lastAccessWasRead() const { return myLastAccessWasRead; } - /** + /** Return the last address that was part of a read/peek. Note that reads which are part of a write are not considered here, unless they're not the same as the last write address. This eliminates @@ -315,40 +315,11 @@ class M6502 : public Serializable #endif private: - /** - Enumeration of the 6502 addressing modes - */ - enum AddressingMode - { - Absolute, AbsoluteX, AbsoluteY, Immediate, Implied, - Indirect, IndirectX, IndirectY, Invalid, Relative, - Zero, ZeroX, ZeroY - }; - - /** - Enumeration of the 6502 access modes - */ - enum AccessMode - { - Read, Write, None - }; - - /// Addressing mode for each of the 256 opcodes - /// This specifies how the opcode argument is addressed - static AddressingMode AddressModeTable[256]; - - /// Access mode for each of the 256 opcodes - /// This specifies how the opcode will access its argument - static AccessMode AccessModeTable[256]; - /** Table of instruction processor cycle times. In some cases additional cycles will be added during the execution of an instruction. */ - static uInt32 InstructionCycleTable[256]; - - /// Table of instruction mnemonics - static const char* InstructionMnemonicTable[256]; + static uInt32 ourInstructionCycleTable[256]; }; #endif diff --git a/src/win32/Stella.vcproj b/src/win32/Stella.vcproj index 5fc487094..321ae253f 100755 --- a/src/win32/Stella.vcproj +++ b/src/win32/Stella.vcproj @@ -734,7 +734,7 @@ > ='0' && x<='9') || - (x>='a' && x<='z') || - (x>='A' && x<='Z') || - x=='.' || x=='_' ); + return ( (x>='0' && x<='9') || + (x>='a' && x<='z') || + (x>='A' && x<='Z') || + x=='.' || x=='_' ); } inline bool is_operator(char x) { - return ( (x=='+' || x=='-' || x=='*' || + return ( (x=='+' || x=='-' || x=='*' || x=='/' || x=='<' || x=='>' || x=='|' || x=='&' || x=='^' || x=='!' || x=='~' || x=='(' || x==')' || x=='=' || x=='%' || - x=='[' || x==']' ) ); + x=='[' || x==']' ) ); } // const_to_int converts a string into a number, in either the @@ -101,279 +101,266 @@ inline bool is_operator(char x) { // Returns -1 on error, since negative numbers are the parser's // responsibility, not the lexer's int const_to_int(char *c) { - // what base is the input in? - BaseFormat base = Debugger::debugger().parser().base(); + // what base is the input in? + BaseFormat base = Debugger::debugger().parser().base(); - switch(*c) { - case '\\': - base = kBASE_2; - c++; - break; + switch(*c) { + case '\\': + base = kBASE_2; + c++; + break; - case '#': - base = kBASE_10; - c++; - break; + case '#': + base = kBASE_10; + c++; + break; - case '$': - base = kBASE_16; - c++; - break; + case '$': + base = kBASE_16; + c++; + break; - default: // not a base_prefix, use default base - break; - } + default: // not a base_prefix, use default base + break; + } - int ret = 0; - switch(base) { - case kBASE_2: - while(*c) { - if(*c != '0' && *c != '1') - return -1; - ret *= 2; - ret += (*c - '0'); - c++; - } - return ret; + int ret = 0; + switch(base) { + case kBASE_2: + while(*c) { + if(*c != '0' && *c != '1') + return -1; + ret *= 2; + ret += (*c - '0'); + c++; + } + return ret; - case kBASE_10: - while(*c) { - if(!isdigit(*c)) - return -1; - ret *= 10; - ret += (*c - '0'); - c++; - } - return ret; + case kBASE_10: + while(*c) { + if(!isdigit(*c)) + return -1; + ret *= 10; + ret += (*c - '0'); + c++; + } + return ret; - case kBASE_16: - while(*c) { // FIXME: error check! - if(!isxdigit(*c)) - return -1; - int dig = (*c - '0'); - if(dig > 9) dig = tolower(*c) - 'a' + 10; - ret *= 16; - ret += dig; - c++; - } - return ret; + case kBASE_16: + while(*c) { // FIXME: error check! + if(!isxdigit(*c)) + return -1; + int dig = (*c - '0'); + if(dig > 9) dig = tolower(*c) - 'a' + 10; + ret *= 16; + ret += dig; + c++; + } + return ret; - default: - fprintf(stderr, "INVALID BASE in lexer!"); - return 0; - } + default: + fprintf(stderr, "INVALID BASE in lexer!"); + return 0; + } } // TODO: store in a map or something // special methods that get e.g. CPU registers -CPUDEBUG_INT_METHOD getCpuSpecial(char *c) { - if(strcmp(c, "a") == 0) - return &CpuDebug::a; - - if(strcmp(c, "x") == 0) - return &CpuDebug::x; - - if(strcmp(c, "y") == 0) - return &CpuDebug::y; - - if(strcmp(c, "pc") == 0) - return &CpuDebug::pc; - - if(strcmp(c, "sp") == 0) - return &CpuDebug::sp; - - if(strcmp(c, "c") == 0) - return &CpuDebug::c; - - if(strcmp(c, "z") == 0) - return &CpuDebug::z; - - if(strcmp(c, "n") == 0) - return &CpuDebug::n; - - if(strcmp(c, "v") == 0) - return &CpuDebug::v; - - if(strcmp(c, "d") == 0) - return &CpuDebug::d; - - if(strcmp(c, "i") == 0) - return &CpuDebug::i; - - if(strcmp(c, "b") == 0) - return &CpuDebug::b; - - if(strcmp(c, "_bank") == 0) - return &CpuDebug::getBank; - - return 0; +CPUDEBUG_INT_METHOD getCpuSpecial(char *c) +{ + if(strcmp(c, "a") == 0) + return &CpuDebug::a; + else if(strcmp(c, "x") == 0) + return &CpuDebug::x; + else if(strcmp(c, "y") == 0) + return &CpuDebug::y; + else if(strcmp(c, "pc") == 0) + return &CpuDebug::pc; + else if(strcmp(c, "sp") == 0) + return &CpuDebug::sp; + else if(strcmp(c, "c") == 0) + return &CpuDebug::c; + else if(strcmp(c, "z") == 0) + return &CpuDebug::z; + else if(strcmp(c, "n") == 0) + return &CpuDebug::n; + else if(strcmp(c, "v") == 0) + return &CpuDebug::v; + else if(strcmp(c, "d") == 0) + return &CpuDebug::d; + else if(strcmp(c, "i") == 0) + return &CpuDebug::i; + else if(strcmp(c, "b") == 0) + return &CpuDebug::b; + else + return 0; } -// special methods that get RAM internal state -RAMDEBUG_INT_METHOD getRamSpecial(char *c) { - if(strcmp(c, "_rwport") == 0) - return &RamDebug::readFromWritePort; - - return 0; +// special methods that get Cart RAM/ROM internal state +CARTDEBUG_INT_METHOD getCartSpecial(char *c) +{ + if(strcmp(c, "_bank") == 0) + return &CartDebug::getBank; + else if(strcmp(c, "_rwport") == 0) + return &CartDebug::readFromWritePort; + else + return 0; } // special methods that get TIA internal state -TIADEBUG_INT_METHOD getTiaSpecial(char *c) { - if(strcmp(c, "_scan") == 0) - return &TIADebug::scanlines; - - if(strcmp(c, "_fcount") == 0) - return &TIADebug::frameCount; - - if(strcmp(c, "_cclocks") == 0) - return &TIADebug::clocksThisLine; - - if(strcmp(c, "_vsync") == 0) - return &TIADebug::vsyncAsInt; - - if(strcmp(c, "_vblank") == 0) - return &TIADebug::vblankAsInt; - - return 0; +TIADEBUG_INT_METHOD getTiaSpecial(char *c) +{ + if(strcmp(c, "_scan") == 0) + return &TIADebug::scanlines; + else if(strcmp(c, "_fcount") == 0) + return &TIADebug::frameCount; + else if(strcmp(c, "_cclocks") == 0) + return &TIADebug::clocksThisLine; + else if(strcmp(c, "_vsync") == 0) + return &TIADebug::vsyncAsInt; + else if(strcmp(c, "_vblank") == 0) + return &TIADebug::vblankAsInt; + else + return 0; } int yylex() { - static char idbuf[255]; - char o, p; - yylval.val = 0; - while(*c != '\0') { - //fprintf(stderr, "looking at %c, state %d\n", *c, state); - switch(state) { - case ST_SPACE: - yylval.val = 0; - if(isspace(*c)) { - c++; - } else if(is_identifier(*c) || is_base_prefix(*c)) { - state = ST_IDENTIFIER; - } else if(is_operator(*c)) { - state = ST_OPERATOR; - } else { - state = ST_DEFAULT; - } + static char idbuf[255]; + char o, p; + yylval.val = 0; + while(*c != '\0') { + //fprintf(stderr, "looking at %c, state %d\n", *c, state); + switch(state) { + case ST_SPACE: + yylval.val = 0; + if(isspace(*c)) { + c++; + } else if(is_identifier(*c) || is_base_prefix(*c)) { + state = ST_IDENTIFIER; + } else if(is_operator(*c)) { + state = ST_OPERATOR; + } else { + state = ST_DEFAULT; + } - break; + break; - case ST_IDENTIFIER: - { - CPUDEBUG_INT_METHOD cpuMeth; - RAMDEBUG_INT_METHOD ramMeth; - TIADEBUG_INT_METHOD tiaMeth; + case ST_IDENTIFIER: + { + CARTDEBUG_INT_METHOD cartMeth; + CPUDEBUG_INT_METHOD cpuMeth; + TIADEBUG_INT_METHOD tiaMeth; - char *bufp = idbuf; - *bufp++ = *c++; // might be a base prefix - while(is_identifier(*c)) { // may NOT be base prefixes - *bufp++ = *c++; - //fprintf(stderr, "yylval==%d, *c==%c\n", yylval, *c); - } - *bufp = '\0'; - state = ST_DEFAULT; + char *bufp = idbuf; + *bufp++ = *c++; // might be a base prefix + while(is_identifier(*c)) { // may NOT be base prefixes + *bufp++ = *c++; + //fprintf(stderr, "yylval==%d, *c==%c\n", yylval, *c); + } + *bufp = '\0'; + state = ST_DEFAULT; - // Note: specials (like "a" for accumulator) have priority over - // numbers. So "a" always means accumulator, not hex 0xa. User - // is welcome to use a base prefix ("$a"), or a capital "A", - // to mean 0xa. + // Note: specials (like "a" for accumulator) have priority over + // numbers. So "a" always means accumulator, not hex 0xa. User + // is welcome to use a base prefix ("$a"), or a capital "A", + // to mean 0xa. - // Also, labels have priority over specials, so Bad Things will - // happen if the user defines a label that matches one of - // the specials. Who would do that, though? + // Also, labels have priority over specials, so Bad Things will + // happen if the user defines a label that matches one of + // the specials. Who would do that, though? - if(Debugger::debugger().equates().getAddress(idbuf) > -1) { - yylval.equate = idbuf; - return EQUATE; - } else if( (cpuMeth = getCpuSpecial(idbuf)) ) { - yylval.cpuMethod = cpuMeth; - return CPU_METHOD; - } else if( (ramMeth = getRamSpecial(idbuf)) ) { - yylval.ramMethod = ramMeth; - return RAM_METHOD; - } else if( (tiaMeth = getTiaSpecial(idbuf)) ) { - yylval.tiaMethod = tiaMeth; - return TIA_METHOD; - } else if( Debugger::debugger().getFunction(idbuf) != 0) { - yylval.function = idbuf; - return FUNCTION; - } else { - yylval.val = const_to_int(idbuf); - if(yylval.val >= 0) - return NUMBER; - else - return ERR; - } - } + if(Debugger::debugger().cartDebug().getAddress(idbuf) > -1) { + yylval.equate = idbuf; + return EQUATE; + } else if( (cpuMeth = getCpuSpecial(idbuf)) ) { + yylval.cpuMethod = cpuMeth; + return CPU_METHOD; + } else if( (cartMeth = getCartSpecial(idbuf)) ) { + yylval.cartMethod = cartMeth; + return CART_METHOD; + } else if( (tiaMeth = getTiaSpecial(idbuf)) ) { + yylval.tiaMethod = tiaMeth; + return TIA_METHOD; + } else if( Debugger::debugger().getFunction(idbuf) != 0) { + yylval.function = idbuf; + return FUNCTION; + } else { + yylval.val = const_to_int(idbuf); + if(yylval.val >= 0) + return NUMBER; + else + return ERR; + } + } - case ST_OPERATOR: - o = *c++; - if(!*c) return o; - if(isspace(*c)) { - state = ST_SPACE; - return o; - } else if(is_identifier(*c) || is_base_prefix(*c)) { - state = ST_IDENTIFIER; - return o; - } else { - state = ST_DEFAULT; - p = *c++; - //fprintf(stderr, "o==%c, p==%c\n", o, p); - if(o == '>' && p == '=') - return GTE; - else if(o == '<' && p == '=') - return LTE; - else if(o == '!' && p == '=') - return NE; - else if(o == '=' && p == '=') - return EQ; - else if(o == '|' && p == '|') - return LOG_OR; - else if(o == '&' && p == '&') - return LOG_AND; - else if(o == '<' && p == '<') - return SHL; - else if(o == '>' && p == '>') - return SHR; - else { - c--; - return o; - } - } + case ST_OPERATOR: + o = *c++; + if(!*c) return o; + if(isspace(*c)) { + state = ST_SPACE; + return o; + } else if(is_identifier(*c) || is_base_prefix(*c)) { + state = ST_IDENTIFIER; + return o; + } else { + state = ST_DEFAULT; + p = *c++; + //fprintf(stderr, "o==%c, p==%c\n", o, p); + if(o == '>' && p == '=') + return GTE; + else if(o == '<' && p == '=') + return LTE; + else if(o == '!' && p == '=') + return NE; + else if(o == '=' && p == '=') + return EQ; + else if(o == '|' && p == '|') + return LOG_OR; + else if(o == '&' && p == '&') + return LOG_AND; + else if(o == '<' && p == '<') + return SHL; + else if(o == '>' && p == '>') + return SHR; + else { + c--; + return o; + } + } - break; + break; - case ST_DEFAULT: - default: - yylval.val = 0; - if(isspace(*c)) { - state = ST_SPACE; - } else if(is_identifier(*c) || is_base_prefix(*c)) { - state = ST_IDENTIFIER; - } else if(is_operator(*c)) { - state = ST_OPERATOR; - } else { - yylval.val = *c++; - return yylval.val; - } - break; - } - } + case ST_DEFAULT: + default: + yylval.val = 0; + if(isspace(*c)) { + state = ST_SPACE; + } else if(is_identifier(*c) || is_base_prefix(*c)) { + state = ST_IDENTIFIER; + } else if(is_operator(*c)) { + state = ST_OPERATOR; + } else { + yylval.val = *c++; + return yylval.val; + } + break; + } + } - //fprintf(stderr, "end of input\n"); - return 0; // hit NUL, end of input. + //fprintf(stderr, "end of input\n"); + return 0; // hit NUL, end of input. } #if 0 int main(int argc, char **argv) { - int l; + int l; - set_input(argv[1]); - while( (l = yylex()) != 0 ) - printf("ret %d, %d\n", l, yylval); + set_input(argv[1]); + while( (l = yylex()) != 0 ) + printf("ret %d, %d\n", l, yylval); - printf("%d\n", yylval); + printf("%d\n", yylval); } #endif } diff --git a/src/yacc/stella.y b/src/yacc/stella.y index c85731f71..ff0b48634 100644 --- a/src/yacc/stella.y +++ b/src/yacc/stella.y @@ -6,7 +6,7 @@ Expression* lastExp = 0; #define YYERROR_VERBOSE 1 /* dump Expression stack during parsing? */ -#define DEBUG_EXP 0 +#define DEBUG_EXP 1 /* #define DEBUG_EXP 1 */ int yylex(); @@ -29,9 +29,9 @@ void yyerror(const char *e) { %union { int val; char *equate; - CPUDEBUG_INT_METHOD cpuMethod; - RAMDEBUG_INT_METHOD ramMethod; - TIADEBUG_INT_METHOD tiaMethod; + CARTDEBUG_INT_METHOD cartMethod; + CPUDEBUG_INT_METHOD cpuMethod; + TIADEBUG_INT_METHOD tiaMethod; Expression *exp; char *function; } @@ -40,9 +40,9 @@ void yyerror(const char *e) { %token NUMBER %token ERR %token EQUATE -%token CPU_METHOD -%token RAM_METHOD -%token TIA_METHOD +%token CART_METHOD +%token CPU_METHOD +%token TIA_METHOD %token FUNCTION /* Non-terminals */ @@ -97,9 +97,9 @@ expression: expression '+' expression { if(DEBUG_EXP) fprintf(stderr, " +"); $$ | NUMBER { if(DEBUG_EXP) fprintf(stderr, " %d", $1); $$ = new ConstExpression($1); lastExp = $$; } | EQUATE { if(DEBUG_EXP) fprintf(stderr, " %s", $1); $$ = new EquateExpression($1); lastExp = $$; } | CPU_METHOD { if(DEBUG_EXP) fprintf(stderr, " (CpuMethod)"); $$ = new CpuMethodExpression($1); lastExp = $$; } - | RAM_METHOD { if(DEBUG_EXP) fprintf(stderr, " (RamMethod)"); $$ = new RamMethodExpression($1); lastExp = $$; } + | CART_METHOD { if(DEBUG_EXP) fprintf(stderr, " (CartMethod)"); $$ = new CartMethodExpression($1); lastExp = $$; } | TIA_METHOD { if(DEBUG_EXP) fprintf(stderr, " (TiaMethod)"); $$ = new TiaMethodExpression($1); lastExp = $$; } | FUNCTION { if(DEBUG_EXP) fprintf(stderr, " (function)"); $$ = new FunctionExpression($1); lastExp = $$; } - | ERR { if(DEBUG_EXP) fprintf(stderr, " ERR"); yyerror((char*)"Invalid label or constant"); return 1; } + | ERR { if(DEBUG_EXP) fprintf(stderr, " ERR: "); yyerror((char*)"Invalid label or constant"); return 1; } ; %% diff --git a/src/yacc/y.tab.c b/src/yacc/y.tab.c index 3761713a4..e051dafa8 100644 --- a/src/yacc/y.tab.c +++ b/src/yacc/y.tab.c @@ -77,7 +77,7 @@ Expression* lastExp = 0; #define YYERROR_VERBOSE 1 /* dump Expression stack during parsing? */ -#define DEBUG_EXP 0 +#define DEBUG_EXP 1 /* #define DEBUG_EXP 1 */ int yylex(); @@ -128,8 +128,8 @@ void yyerror(const char *e) { NUMBER = 258, ERR = 259, EQUATE = 260, - CPU_METHOD = 261, - RAM_METHOD = 262, + CART_METHOD = 261, + CPU_METHOD = 262, TIA_METHOD = 263, FUNCTION = 264, LOG_OR = 265, @@ -149,8 +149,8 @@ void yyerror(const char *e) { #define NUMBER 258 #define ERR 259 #define EQUATE 260 -#define CPU_METHOD 261 -#define RAM_METHOD 262 +#define CART_METHOD 261 +#define CPU_METHOD 262 #define TIA_METHOD 263 #define FUNCTION 264 #define LOG_OR 265 @@ -177,9 +177,9 @@ typedef union YYSTYPE int val; char *equate; - CPUDEBUG_INT_METHOD cpuMethod; - RAMDEBUG_INT_METHOD ramMethod; - TIADEBUG_INT_METHOD tiaMethod; + CARTDEBUG_INT_METHOD cartMethod; + CPUDEBUG_INT_METHOD cpuMethod; + TIADEBUG_INT_METHOD tiaMethod; Expression *exp; char *function; @@ -489,7 +489,7 @@ static const yytype_int8 yyrhs[] = 32, 40, -1, 33, 40, -1, 12, 40, -1, 34, 40, -1, 23, 40, -1, 24, 40, -1, 35, 40, 36, -1, 40, 31, 40, 37, -1, 3, -1, 5, - -1, 6, -1, 7, -1, 8, -1, 9, -1, 4, + -1, 7, -1, 6, -1, 8, -1, 9, -1, 4, -1 }; @@ -508,8 +508,8 @@ static const yytype_uint8 yyrline[] = First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { - "$end", "error", "$undefined", "NUMBER", "ERR", "EQUATE", "CPU_METHOD", - "RAM_METHOD", "TIA_METHOD", "FUNCTION", "'-'", "'+'", "'*'", "'/'", + "$end", "error", "$undefined", "NUMBER", "ERR", "EQUATE", "CART_METHOD", + "CPU_METHOD", "TIA_METHOD", "FUNCTION", "'-'", "'+'", "'*'", "'/'", "'%'", "LOG_OR", "LOG_AND", "LOG_NOT", "'|'", "'^'", "'&'", "SHL", "SHR", "'<'", "'>'", "EQ", "NE", "LTE", "GTE", "DEREF", "UMINUS", "'['", "'~'", "'!'", "'@'", "'('", "')'", "']'", "$accept", "statement", "expression", 0 @@ -551,7 +551,7 @@ static const yytype_uint8 yyr2[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 0, 30, 36, 31, 32, 33, 34, 35, 0, 0, + 0, 30, 36, 31, 33, 32, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 21, 24, 26, 27, 22, 23, 25, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1687,7 +1687,7 @@ yyreduce: /* Line 1455 of yacc.c */ #line 100 "stella.y" - { if(DEBUG_EXP) fprintf(stderr, " (RamMethod)"); (yyval.exp) = new RamMethodExpression((yyvsp[(1) - (1)].ramMethod)); lastExp = (yyval.exp); } + { if(DEBUG_EXP) fprintf(stderr, " (CartMethod)"); (yyval.exp) = new CartMethodExpression((yyvsp[(1) - (1)].cartMethod)); lastExp = (yyval.exp); } break; case 34: @@ -1708,7 +1708,7 @@ yyreduce: /* Line 1455 of yacc.c */ #line 103 "stella.y" - { if(DEBUG_EXP) fprintf(stderr, " ERR"); yyerror((char*)"Invalid label or constant"); return 1; } + { if(DEBUG_EXP) fprintf(stderr, " ERR: "); yyerror((char*)"Invalid label or constant"); return 1; } break; diff --git a/src/yacc/y.tab.h b/src/yacc/y.tab.h index 65b1a8c43..c6d0d7db8 100644 --- a/src/yacc/y.tab.h +++ b/src/yacc/y.tab.h @@ -42,8 +42,8 @@ NUMBER = 258, ERR = 259, EQUATE = 260, - CPU_METHOD = 261, - RAM_METHOD = 262, + CART_METHOD = 261, + CPU_METHOD = 262, TIA_METHOD = 263, FUNCTION = 264, LOG_OR = 265, @@ -63,8 +63,8 @@ #define NUMBER 258 #define ERR 259 #define EQUATE 260 -#define CPU_METHOD 261 -#define RAM_METHOD 262 +#define CART_METHOD 261 +#define CPU_METHOD 262 #define TIA_METHOD 263 #define FUNCTION 264 #define LOG_OR 265 @@ -91,9 +91,9 @@ typedef union YYSTYPE int val; char *equate; - CPUDEBUG_INT_METHOD cpuMethod; - RAMDEBUG_INT_METHOD ramMethod; - TIADEBUG_INT_METHOD tiaMethod; + CARTDEBUG_INT_METHOD cartMethod; + CPUDEBUG_INT_METHOD cpuMethod; + TIADEBUG_INT_METHOD tiaMethod; Expression *exp; char *function;