Updated debugger symbol handling to differentiate between addresses that

have different labels depending on if they're being read or written.
This means that, for example, reading address 0x0 from the TIA will use
label 'CXM0P', while writing the same address will use label 'VSYNC'.
There's still more work to do in this area, since we still need to
differentiate between symbols that hold addresses, and ones that hold
constants.  And I'm not sure how to do that, since the DASM .sym file
doesn't export that info.

Added gl_lib = 'opengl32.dll' to the settings for Win32.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1497 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2008-05-04 17:16:39 +00:00
parent d6ed407f1b
commit 27441fadbf
15 changed files with 602 additions and 533 deletions

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CpuDebug.cxx,v 1.11 2008-04-19 21:11:52 stephena Exp $
// $Id: CpuDebug.cxx,v 1.12 2008-05-04 17:16:39 stephena Exp $
//============================================================================
#include <sstream>
@ -118,31 +118,35 @@ string CpuDebug::toString()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int CpuDebug::disassemble(int address, string& result, EquateList* equateList)
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::ourAccessModeTable[opcode] == M6502::Read);
switch(M6502::ourAddressingModeTable[opcode])
{
case M6502::Absolute:
buf << M6502::ourInstructionMnemonicTable[opcode] << " "
<< equateList->getFormatted(dpeek(mySystem, address + 1), 4) << " ; "
<< list.getFormatted(dpeek(mySystem, address + 1), 4, isRead) << " ; "
<< M6502::ourInstructionProcessorCycleTable[opcode];
count = 3;
break;
case M6502::AbsoluteX:
buf << M6502::ourInstructionMnemonicTable[opcode] << " "
<< equateList->getFormatted(dpeek(mySystem, address + 1), 4) << ",x ; "
<< list.getFormatted(dpeek(mySystem, address + 1), 4, isRead) << ",x ; "
<< M6502::ourInstructionProcessorCycleTable[opcode];
count = 3;
break;
case M6502::AbsoluteY:
buf << M6502::ourInstructionMnemonicTable[opcode] << " "
<< equateList->getFormatted(dpeek(mySystem, address + 1), 4) << ",y ; "
<< list.getFormatted(dpeek(mySystem, address + 1), 4, isRead) << ",y ; "
<< M6502::ourInstructionProcessorCycleTable[opcode];
count = 3;
break;
@ -162,49 +166,49 @@ int CpuDebug::disassemble(int address, string& result, EquateList* equateList)
case M6502::Indirect:
buf << M6502::ourInstructionMnemonicTable[opcode] << " ("
<< equateList->getFormatted(dpeek(mySystem, address + 1), 4) << ") ; "
<< list.getFormatted(dpeek(mySystem, address + 1), 4, isRead) << ") ; "
<< M6502::ourInstructionProcessorCycleTable[opcode];
count = 3;
break;
case M6502::IndirectX:
buf << M6502::ourInstructionMnemonicTable[opcode] << " ("
<< equateList->getFormatted(mySystem.peek(address + 1), 2) << ",x) ; "
<< list.getFormatted(mySystem.peek(address + 1), 2, isRead) << ",x) ; "
<< M6502::ourInstructionProcessorCycleTable[opcode];
count = 2;
break;
case M6502::IndirectY:
buf << M6502::ourInstructionMnemonicTable[opcode] << " ("
<< equateList->getFormatted(mySystem.peek(address + 1), 2) << "),y ; "
<< list.getFormatted(mySystem.peek(address + 1), 2, isRead) << "),y ; "
<< M6502::ourInstructionProcessorCycleTable[opcode];
count = 2;
break;
case M6502::Relative:
buf << M6502::ourInstructionMnemonicTable[opcode] << " "
<< equateList->getFormatted(address + 2 + ((Int16)(Int8)mySystem.peek(address + 1)), 4)
<< list.getFormatted(address + 2 + ((Int16)(Int8)mySystem.peek(address + 1)), 4, isRead)
<< " ; " << M6502::ourInstructionProcessorCycleTable[opcode];
count = 2;
break;
case M6502::Zero:
buf << M6502::ourInstructionMnemonicTable[opcode] << " "
<< equateList->getFormatted(mySystem.peek(address + 1), 2) << " ; "
<< list.getFormatted(mySystem.peek(address + 1), 2, isRead) << " ; "
<< M6502::ourInstructionProcessorCycleTable[opcode];
count = 2;
break;
case M6502::ZeroX:
buf << M6502::ourInstructionMnemonicTable[opcode] << " "
<< equateList->getFormatted(mySystem.peek(address + 1), 2) << ",x ; "
<< list.getFormatted(mySystem.peek(address + 1), 2, isRead) << ",x ; "
<< M6502::ourInstructionProcessorCycleTable[opcode];
count = 2;
break;
case M6502::ZeroY:
buf << M6502::ourInstructionMnemonicTable[opcode] << " "
<< equateList->getFormatted(mySystem.peek(address + 1), 2) << ",y ; "
<< list.getFormatted(mySystem.peek(address + 1), 2, isRead) << ",y ; "
<< M6502::ourInstructionProcessorCycleTable[opcode];
count = 2;
break;

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CpuDebug.hxx,v 1.13 2008-04-19 21:11:52 stephena Exp $
// $Id: CpuDebug.hxx,v 1.14 2008-05-04 17:16:39 stephena Exp $
//============================================================================
#ifndef CPU_DEBUG_HXX
@ -52,7 +52,7 @@ class CpuDebug : public DebuggerSystem
// I know, we ain't supposed to do this...
M6502& m6502() { return mySystem.m6502(); }
int disassemble(int address, string& result, EquateList* equateList);
int disassemble(int address, string& result, EquateList& list);
int dPeek(int address);
int getBank();

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Debugger.cxx,v 1.125 2008-05-02 01:19:48 stephena Exp $
// $Id: Debugger.cxx,v 1.126 2008-05-04 17:16:39 stephena Exp $
//============================================================================
#include "bspf.hxx"
@ -120,7 +120,6 @@ Debugger::Debugger(OSystem* osystem)
// Init parser
myParser = new DebuggerParser(this);
myEquateList = new EquateList();
myBreakPoints = new PackedBitArray(0x10000);
myReadTraps = new PackedBitArray(0x10000);
myWriteTraps = new PackedBitArray(0x10000);
@ -575,9 +574,9 @@ const string& Debugger::disassemble(int start, int lines)
string cpubuf;
do {
buffer << myEquateList->getFormatted(start, 4) << ": ";
buffer << myEquateList->getFormatted(start, 4, true) << ": ";
int count = myCpuDebug->disassemble(start, cpubuf, myEquateList);
int count = myCpuDebug->disassemble(start, cpubuf, *myEquateList);
for(int i = 0; i < count; i++)
buffer << hex << setw(2) << setfill('0') << peek(start++) << dec;
@ -601,11 +600,11 @@ void Debugger::disassemble(IntArray& addr, StringList& addrLabel,
do
{
addrLabel.push_back(myEquateList->getFormatted(start, 4) + ":");
addrLabel.push_back(myEquateList->getFormatted(start, 4, true) + ":");
addr.push_back(start);
cpubuf = "";
int count = myCpuDebug->disassemble(start, cpubuf, myEquateList);
int count = myCpuDebug->disassemble(start, cpubuf, *myEquateList);
tmp = "";
for(int i=0; i<count; i++) {

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: DebuggerParser.cxx,v 1.106 2008-05-01 23:08:24 stephena Exp $
// $Id: DebuggerParser.cxx,v 1.107 2008-05-04 17:16:39 stephena Exp $
//============================================================================
#include <fstream>
@ -562,7 +562,8 @@ string DebuggerParser::eval()
char buf[50];
string ret;
for(int i=0; i<argCount; i++) {
string label = debugger->equates().getLabel(args[i]);
// TODO - technically, we should determine if the label is read or write
string label = debugger->equates().getLabel(args[i], true);
if(label != "") {
ret += label;
ret += ": ";
@ -601,7 +602,8 @@ string DebuggerParser::trapStatus(int addr)
else
result += " none ";
string l = debugger->equates().getLabel(addr);
// TODO - technically, we should determine if the label is read or write
const string& l = debugger->equates().getLabel(addr, true);
if(l != "") {
result += " (";
result += l;
@ -984,7 +986,7 @@ void DebuggerParser::executeListbreaks()
{
if(debugger->breakpoints().isSet(i))
{
buf << debugger->equates().getFormatted(i, 4) << " ";
buf << debugger->equates().getFormatted(i, 4, true) << " ";
if(! (++count % 8) ) buf << "\n";
}
}

View File

@ -1,44 +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-2008 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: Equate.hxx,v 1.8 2008-02-24 16:51:52 stephena Exp $
//============================================================================
#ifndef EQUATE_HXX
#define EQUATE_HXX
#include "bspf.hxx"
enum {
EQF_ANY = 1 << 0, // matches any type of label
EQF_READ = 1 << 1, // address can be read from
EQF_WRITE = 1 << 2, // address can be written to
EQF_USER = 1 << 3, // equate is user-defined, not built-in
// When used in a search, EQF_ROM matches only ROM addresses,
// and EQF_RAM only matches RAM addresses. Both RAM and ROM addresses
// are by definition user-defined, since the built-in equates are
// for the TIA and RIOT only.
EQF_ROM = EQF_READ | EQF_USER,
EQF_RAM = EQF_WRITE | EQF_READ | EQF_USER
};
struct Equate {
string label;
int address;
int flags;
};
#endif

View File

@ -13,19 +13,307 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: EquateList.cxx,v 1.30 2008-05-02 01:19:48 stephena Exp $
// $Id: EquateList.cxx,v 1.31 2008-05-04 17:16:39 stephena Exp $
//============================================================================
#include <fstream>
#include "bspf.hxx"
#include "Equate.hxx"
#include "EquateList.hxx"
#include "Debugger.hxx"
// built in labels
static Equate hardCodedEquates[] = {
#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, int 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(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
}
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(int addr, bool isRead) const
{
AddrToLabel::const_iterator iter;
// Is this a read or write?
// For now, there aren't separate read & write lists for user labels
if(isRead)
{
if((iter = mySystemReadLabels.find(addr)) != mySystemReadLabels.end())
return iter->second.label;
else if((iter = myUserLabels.find(addr)) != myUserLabels.end())
return iter->second.label;
}
else
{
if((iter = mySystemWriteLabels.find(addr)) != mySystemWriteLabels.end())
return iter->second.label;
else if((iter = myUserLabels.find(addr)) != myUserLabels.end())
return iter->second.label;
}
return EmptyString;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string EquateList::getFormatted(int addr, int places, bool isRead) const
{
char fmt[10], buf[255];
const string& label = getLabel(addr, isRead);
if(label != "")
return label;
sprintf(fmt, "$%%0%dx", places);
sprintf(buf, fmt, addr);
return buf;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const EquateList::Equate EquateList::ourSystemEquates[kSystemEquateSize] = {
// Standard $00-based TIA write locations:
{ "VSYNC", 0x00, EQF_WRITE },
{ "VBLANK", 0x01, EQF_WRITE },
@ -187,271 +475,14 @@ static Equate hardCodedEquates[] = {
{ "INPT5.30", 0x3D, EQF_READ },
// Standard RIOT locations (read, write, or both):
{ "SWCHA", 0x280, EQF_READ | EQF_WRITE },
{ "SWCHB", 0x282, EQF_READ | EQF_WRITE },
{ "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 },
{ "TIM1024T", 0x297, EQF_WRITE }
{ "T1024T", 0x297, EQF_WRITE }
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EquateList::EquateList()
{
int size = sizeof(hardCodedEquates)/sizeof(struct Equate);
for(int i = 0; i < size; i++)
{
Equate e = hardCodedEquates[i];
myHardcodedFwdMap.insert(make_pair(e.label, e));
myHardcodedRevMap.insert(make_pair(e.address, e));
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EquateList::~EquateList()
{
myHardcodedFwdMap.clear();
myHardcodedRevMap.clear();
myUserFwdMap.clear();
myUserRevMap.clear();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EquateList::addEquate(const string& label, int address)
{
// First check if this already exists as a hard-coded equate
LabelToAddr::const_iterator iter = myHardcodedFwdMap.find(label);
if(iter != myHardcodedFwdMap.end() && iter->second.address == address)
{
cerr << "skipping " << label << endl;
return;
}
removeEquate(label);
cerr << "add: label = " << label << ", address = " << hex << address << endl;
// Create a new user equate, and analyze the address to determine its
// probable type (ie, what flags?)
Equate e;
e.label = label;
e.address = address;
e.flags = EQF_USER;
if(address >= 0x80 && address <= 0xff)
e.flags |= EQF_RAM;
else if(address & 0xf000 == 0xf000)
e.flags |= EQF_ROM;
myUserFwdMap.insert(make_pair(label, e));
myUserRevMap.insert(make_pair(address, e));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool EquateList::removeEquate(const string& label)
{
LabelToAddr::iterator iter = myUserFwdMap.find(label);
if(iter == myUserFwdMap.end())
{
return false;
}
else
{
// FIXME: error check?
// FIXME: memory leak!
myUserRevMap.erase( myUserRevMap.find(iter->second.address) );
myUserFwdMap.erase(iter);
return true;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string& EquateList::getLabel(int addr, const int flags)
{
AddrToLabel::const_iterator iter = myHardcodedRevMap.find(addr);
if(iter != myHardcodedRevMap.end())
{
// FIXME - until we fix the issue of correctly setting the equate
// flags to something other than 'EQF_ANY' by default,
// this comparison will almost always fail
if(1)//flags == EQF_ANY || iter->second.flags & flags)
return iter->second.label;
}
return EmptyString;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string EquateList::getFormatted(int addr, int places, const int flags)
{
char fmt[10], buf[255];
const string& label = getLabel(addr, flags);
if(label != "")
return label;
sprintf(fmt, "$%%0%dx", places);
sprintf(buf, fmt, addr);
return buf;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int EquateList::getAddress(const string& label, const int flags)
{
LabelToAddr::const_iterator iter = myHardcodedFwdMap.find(label);
if(iter == myHardcodedFwdMap.end())
return -1;
else
return iter->second.address;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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;
myUserFwdMap.clear();
myUserRevMap.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)
{
char buf[256];
ofstream out(file.c_str());
if(!out.is_open())
return false;
out << "--- Symbol List (sorted by symbol)" << endl;
LabelToAddr::iterator iter;
for(iter = myHardcodedFwdMap.begin(); iter != myHardcodedFwdMap.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)
{
int count = 0;
myCompletions = myCompPrefix = "";
LabelToAddr::iterator iter;
for(iter = myHardcodedFwdMap.begin(); iter != myHardcodedFwdMap.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;
}

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: EquateList.hxx,v 1.20 2008-05-02 01:19:48 stephena Exp $
// $Id: EquateList.hxx,v 1.21 2008-05-04 17:16:39 stephena Exp $
//============================================================================
#ifndef EQUATELIST_HXX
@ -22,7 +22,6 @@
#include <map>
#include "bspf.hxx"
#include "Equate.hxx"
class EquateList
{
@ -42,10 +41,15 @@ class EquateList
/**
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
*/
const string& getLabel(int addr, const int flags = EQF_ANY);
string getFormatted(int addr, int places, const int flags = EQF_ANY);
int getAddress(const string& label, const int flags = EQF_ANY);
const string& getLabel(int addr, bool isRead) const;
string getFormatted(int addr, int places, bool isRead) const;
int getAddress(const string& label) const;
/**
Load user equates from the given symbol file (generated by DASM)
@ -61,26 +65,46 @@ class EquateList
Methods used by the command parser for tab-completion
*/
int countCompletions(const char *in);
const string& getCompletions() { return myCompletions; }
const string& getCompletionPrefix() { return myCompPrefix; }
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
};
struct Equate {
string label;
int address;
equate_t flags;
};
typedef map<int, Equate> AddrToLabel;
typedef map<string, Equate> 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);
private:
typedef map<int, Equate> AddrToLabel;
typedef map<string, Equate> LabelToAddr;
enum { kSystemEquateSize = 158 };
static const Equate ourSystemEquates[kSystemEquateSize];
string myCompletions;
string myCompPrefix;
LabelToAddr myHardcodedFwdMap;
AddrToLabel myHardcodedRevMap;
LabelToAddr mySystemAddresses;
AddrToLabel mySystemReadLabels; // labels used in a read context
AddrToLabel mySystemWriteLabels; // labels used in a write context
LabelToAddr myUserFwdMap;
AddrToLabel myUserRevMap;
LabelToAddr myUserAddresses;
AddrToLabel myUserLabels;
};
#endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: RiotDebug.cxx,v 1.2 2008-04-29 15:13:15 stephena Exp $
// $Id: RiotDebug.cxx,v 1.3 2008-05-04 17:16:39 stephena Exp $
//============================================================================
#include <sstream>
@ -228,17 +228,13 @@ string RiotDebug::toString()
const RiotState& oldstate = (RiotState&) getOldState();
string ret;
ret += myDebugger.valueToString(0x280) + "/" +
myDebugger.equates().getFormatted(0x280, 2) + "=" +
ret += myDebugger.valueToString(0x280) + "/SWCHA" +
myDebugger.invIfChanged(state.SWCHA, oldstate.SWCHA) + " ";
ret += myDebugger.valueToString(0x281) + "/" +
myDebugger.equates().getFormatted(0x281, 2) + "=" +
ret += myDebugger.valueToString(0x281) + "/SWACNT" +
myDebugger.invIfChanged(state.SWACNT, oldstate.SWACNT) + " ";
ret += myDebugger.valueToString(0x282) + "/" +
myDebugger.equates().getFormatted(0x282, 2) + "=" +
ret += myDebugger.valueToString(0x282) + "/SWCHB" +
myDebugger.invIfChanged(state.SWCHB, oldstate.SWCHB) + " ";
ret += myDebugger.valueToString(0x283) + "/" +
myDebugger.equates().getFormatted(0x283, 2) + "=" +
ret += myDebugger.valueToString(0x283) + "/SWBCNT" +
myDebugger.invIfChanged(state.SWBCNT, oldstate.SWBCNT) + " ";
ret += "\n";

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CpuWidget.cxx,v 1.11 2008-03-23 17:43:22 stephena Exp $
// $Id: CpuWidget.cxx,v 1.12 2008-05-04 17:16:39 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -281,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, EQF_ROM));
myPCLabel->setEditString(dbg.equates().getLabel(state.PC, true));
}

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: RamWidget.cxx,v 1.16 2008-03-23 17:43:22 stephena Exp $
// $Id: RamWidget.cxx,v 1.17 2008-05-04 17:16:39 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -177,7 +177,7 @@ void RamWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
value = myRamGrid->getSelectedValue();
myLabel->setEditString(
instance()->debugger().equates().getLabel(addr+kRamStart, EQF_RAM));
instance()->debugger().equates().getLabel(addr+kRamStart, true));
myDecValue->setEditString(instance()->debugger().valueToString(value, kBASE_10));
myBinValue->setEditString(instance()->debugger().valueToString(value, kBASE_2));
break;

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: TiaWidget.cxx,v 1.11 2008-04-19 21:11:52 stephena Exp $
// $Id: TiaWidget.cxx,v 1.12 2008-05-04 17:16:39 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -789,7 +789,9 @@ void TiaWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
addr = myRamGrid->getSelectedAddr();
value = myRamGrid->getSelectedValue();
myLabel->setEditString(dbg.equates().getLabel(addr));
// We're using the read-addresses here
// Should we also add write-addresses, or remove this entirely?
myLabel->setEditString(dbg.equates().getLabel(addr, true));
myDecValue->setEditString(dbg.valueToString(value, kBASE_10));
myBinValue->setEditString(dbg.valueToString(value, kBASE_2));

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: M6502.cxx,v 1.22 2008-02-06 13:45:22 stephena Exp $
// $Id: M6502.cxx,v 1.23 2008-05-04 17:16:39 stephena Exp $
//============================================================================
#include "M6502.hxx"
@ -26,7 +26,9 @@
M6502::M6502(uInt32 systemCyclesPerProcessorCycle)
: myExecutionStatus(0),
mySystem(0),
mySystemCyclesPerProcessorCycle(systemCyclesPerProcessorCycle)
mySystemCyclesPerProcessorCycle(systemCyclesPerProcessorCycle),
myLastAccessWasRead(true),
myTotalInstructionCount(0)
{
#ifdef DEBUGGER_SUPPORT
myDebugger = NULL;
@ -49,8 +51,6 @@ M6502::M6502(uInt32 systemCyclesPerProcessorCycle)
myInstructionSystemCycleTable[t] = ourInstructionProcessorCycleTable[t] *
mySystemCyclesPerProcessorCycle;
}
myTotalInstructionCount = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -85,6 +85,8 @@ void M6502::reset()
// Load PC from the reset vector
PC = (uInt16)mySystem->peek(0xfffc) | ((uInt16)mySystem->peek(0xfffd) << 8);
myTotalInstructionCount = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -105,12 +107,6 @@ void M6502::stop()
myExecutionStatus |= StopExecutionBit;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M6502::AddressingMode M6502::addressingMode(uInt8 opcode) const
{
return ourAddressingModeTable[opcode];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 M6502::PS() const
{
@ -280,6 +276,89 @@ M6502::AddressingMode M6502::ourAddressingModeTable[256] = {
AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M6502::AccessMode M6502::ourAccessModeTable[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::ourInstructionProcessorCycleTable[256] = {
// 0 1 2 3 4 5 6 7 8 9 a b c d e f
@ -353,60 +432,6 @@ const char* M6502::ourInstructionMnemonicTable[256] = {
};
#ifdef DEBUGGER_SUPPORT
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// This needs to be a list of all 256 opcodes and the type of memory
// access they do (read, write, read/modify/write, or none). The
// disassemble() method will use this to figure out what kind of label
// to use in the disassembly.
//// const char* M6502::ourLabelTypeTable[256] = {
//// };
////
//// // disassemble() will use isXXX methods to determine what type of
//// // label to show to the user (e.g. isTIA == true means to show a
//// // non-user label; isRAM == true means to show a user r/w label, etc)
////
//// // These methods were based on (and checked against) Kroko's
//// // 2600 memory map, found at
//// // http://www.qotile.net/minidig/docs/2600_mem_map.txt
////
//// // is the address in RIOT RAM?
//// bool isRAM(int addr) {
//// int y = addr & 0xf00;
//// int z = addr & 0xff;
////
//// return !isROM(addr)
//// &&
//// z >= 0x80
//// &&
//// (y == 0 || y == 0x100 || y == 0x400 || y == 0x500 ||
//// y == 0x800 || y == 0x900 || y == 0xc00 || y == 0xd00);
//// }
////
//// // is the address one of the non-RAM RIOT areas?
//// bool isRIOT(int addr) {
//// int y = addr & 0xf00;
//// int z = addr & 0xff;
////
//// return !isROM(addr)
//// &&
//// z >= 0x80
//// &&
//// (y == 0x200 || y == 0x300 || y == 0x600 || y == 0x700 ||
//// y == 0xa00 || y == 0xb00 || y == 0xe00 || y == 0xf00);
//// }
////
//// // is the address in one of the TIA mirrors?
//// bool isTIA(int addr) {
//// int z = addr & 0xff;
//// return !isROM(addr) && (z < 0x80);
//// }
////
//// // is the address in ROM?
//// bool isROM(int addr) {
//// // ROM addresses are $xnnn where x is odd
//// return addr % 8192 > 4095;
//// }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6502::attach(Debugger& debugger)
{
@ -415,7 +440,7 @@ void M6502::attach(Debugger& debugger)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unsigned int M6502::addCondBreak(Expression *e, string name)
unsigned int M6502::addCondBreak(Expression *e, const string& name)
{
myBreakConds.push_back(e);
myBreakCondNames.push_back(name);
@ -443,7 +468,7 @@ void M6502::clearCondBreaks()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const StringList& M6502::getCondBreakNames()
const StringList& M6502::getCondBreakNames() const
{
return myBreakCondNames;
}
@ -452,11 +477,8 @@ const StringList& M6502::getCondBreakNames()
int M6502::evalCondBreaks()
{
for(unsigned int i=0; i<myBreakConds.size(); i++)
{
Expression* e = myBreakConds[i];
if(e->evaluate())
if(myBreakConds[i]->evaluate())
return i;
}
return -1; // no break hit
}

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: M6502.hxx,v 1.21 2008-02-06 13:45:22 stephena Exp $
// $Id: M6502.hxx,v 1.22 2008-05-04 17:16:39 stephena Exp $
//============================================================================
#ifndef M6502_HXX
@ -41,7 +41,7 @@ typedef Common::Array<Expression*> ExpressionList;
has a 64K addressing space.
@author Bradford W. Mott
@version $Id: M6502.hxx,v 1.21 2008-02-06 13:45:22 stephena Exp $
@version $Id: M6502.hxx,v 1.22 2008-05-04 17:16:39 stephena Exp $
*/
class M6502
{
@ -62,6 +62,14 @@ class M6502
Zero, ZeroX, ZeroY
};
/**
Enumeration of the 6502 access modes
*/
enum AccessMode
{
Read, Write, None
};
public:
/**
Create a new 6502 microprocessor with the specified cycle
@ -133,7 +141,17 @@ class M6502
@param opcode The opcode of the instruction
@return The addressing mode of the instruction
*/
AddressingMode addressingMode(uInt8 opcode) const;
AddressingMode addressingMode(uInt8 opcode) const
{ return ourAddressingModeTable[opcode]; }
/**
Get the access mode of the specified instruction
@param opcode The opcode of the instruction
@return The access mode of the instruction
*/
AccessMode accessMode(uInt8 opcode) const
{ return ourAccessModeTable[opcode]; }
public:
/**
@ -174,10 +192,17 @@ class M6502
/**
Answer true iff the last memory access was a read.
@return true iff last access was a read.
@return true iff last access was a read
*/
bool lastAccessWasRead() const { return myLastAccessWasRead; }
/**
Get the total number of instructions executed so far.
@return The number of executed instructions
*/
int totalInstructionCount() const { return myTotalInstructionCount; }
public:
/**
Overload the ostream output operator for addressing modes.
@ -199,12 +224,11 @@ class M6502
// TODO - document these methods
void setBreakPoints(PackedBitArray *bp);
void setTraps(PackedBitArray *read, PackedBitArray *write);
int totalInstructionCount() { return myTotalInstructionCount; }
unsigned int addCondBreak(Expression *e, string name);
unsigned int addCondBreak(Expression *e, const string& name);
void delCondBreak(unsigned int brk);
void clearCondBreaks();
const StringList& getCondBreakNames();
const StringList& getCondBreakNames() const;
int evalCondBreaks();
#endif
@ -239,26 +263,6 @@ class M6502
bool notZ; // Z flag complement for processor status register
bool C; // C flag for processor status register
#ifdef DEBUGGER_SUPPORT
/// Pointer to the debugger for this processor or the null pointer
Debugger* myDebugger;
PackedBitArray* myBreakPoints;
PackedBitArray* myReadTraps;
PackedBitArray* myWriteTraps;
// Did we just now hit a trap?
bool myJustHitTrapFlag;
struct HitTrapInfo {
string message;
int address;
};
HitTrapInfo myHitTrapInfo;
StringList myBreakCondNames;
ExpressionList myBreakConds;
#endif
/**
Bit fields used to indicate that certain conditions need to be
handled such as stopping execution, fatal errors, maskable interrupts
@ -289,10 +293,38 @@ class M6502
/// Indicates if the last memory access was a read or not
bool myLastAccessWasRead;
/// The total number of instructions executed so far
int myTotalInstructionCount;
#ifdef DEBUGGER_SUPPORT
/// Pointer to the debugger for this processor or the null pointer
Debugger* myDebugger;
PackedBitArray* myBreakPoints;
PackedBitArray* myReadTraps;
PackedBitArray* myWriteTraps;
// Did we just now hit a trap?
bool myJustHitTrapFlag;
struct HitTrapInfo {
string message;
int address;
};
HitTrapInfo myHitTrapInfo;
StringList myBreakCondNames;
ExpressionList myBreakConds;
#endif
protected:
/// Addressing mode for each of the 256 opcodes
/// This specifies how the opcode argument is addressed
static AddressingMode ourAddressingModeTable[256];
/// Access mode for each of the 256 opcodes
/// This specifies how the opcode will access its argument
static AccessMode ourAccessModeTable[256];
/// Lookup table used for binary-code-decimal math
static uInt8 ourBCDTable[2][256];
@ -304,8 +336,6 @@ class M6502
/// Table of instruction mnemonics
static const char* ourInstructionMnemonicTable[256];
int myTotalInstructionCount;
};
#endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: M6502Low.cxx,v 1.14 2008-02-06 13:45:22 stephena Exp $
// $Id: M6502Low.cxx,v 1.15 2008-05-04 17:16:39 stephena Exp $
//============================================================================
#include "M6502Low.hxx"
@ -142,6 +142,8 @@ bool M6502Low::execute(uInt32 number)
cerr << "Illegal Instruction! " << hex << (int) IR << endl;
}
myTotalInstructionCount++;
#ifdef DEBUG
debugStream << hex << setw(4) << operandAddress << " ";
debugStream << setw(4) << ourInstructionMnemonicTable[IR];

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: SettingsWin32.cxx,v 1.28 2008-03-08 23:34:24 stephena Exp $
// $Id: SettingsWin32.cxx,v 1.29 2008-05-04 17:16:39 stephena Exp $
//============================================================================
#include "bspf.hxx"
@ -24,6 +24,7 @@
SettingsWin32::SettingsWin32(OSystem* osystem)
: Settings(osystem)
{
setInternal("gl_lib", "opengl32.dll");
// Anything less than this usually causes sound skipping
setInternal("fragsize", "2048");
// Most Windows systems work better without this