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;