mirror of https://github.com/stella-emu/stella.git
OK, this is the first pass at a huge reorganization of the debugger
classes. First off, the distella code has been integrated into a DiStella class. This code isn't yet tied to the debugger, but it does at least compile and generate valid output. The RamDebug class has been replaced by a CartDebug class, which takes responsibility for the previous RamDebug stuff as well as things related to Cart address space (read from write ports, disassembly, etc). Fixed E7 bankswitching when reading from the write port in the upper 256byte area. Fixed 'read from write port functionality' in general for all carts that supported it previously. Basically, if _rwport is enabled, the address is checked to be an actual read (vs. one that's part of a normal write cycle), *and* it's actually an illegal access (each cart/bankswitch type now provides a hint to indicate this condition). Still TODO is clean up the rework, properly integrate DiStella, and fix labels and defines (which seem to be completely broken). git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1922 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
e234139a3c
commit
28114a8c51
File diff suppressed because it is too large
Load Diff
|
@ -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<DisassemblyTag> 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<uInt16, Equate> AddrToLabel;
|
||||
typedef map<string, Equate> 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
|
|
@ -19,8 +19,8 @@
|
|||
#include <sstream>
|
||||
|
||||
#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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; i<count; i++) {
|
||||
sprintf(buf, "%02x ", peek(start++));
|
||||
tmp += buf;
|
||||
}
|
||||
bytes.push_back(tmp);
|
||||
|
||||
data.push_back(cpubuf);
|
||||
}
|
||||
while(start <= end);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::nextScanline(int lines)
|
||||
{
|
||||
|
@ -686,30 +611,12 @@ void Debugger::clearAllTraps()
|
|||
mySystem->m6502().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();
|
||||
|
||||
|
|
|
@ -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<string,string> 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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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; i<argCount; i++) {
|
||||
// TODO - technically, we should determine if the label is read or write
|
||||
string label = debugger->equates().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; i<args[0] + 3; i++)
|
||||
commandResult += debugger->getSourceLines(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)",
|
||||
|
|
|
@ -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();
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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 <queue>
|
||||
|
||||
#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<DisassemblyTag> 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<uInt16> 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
|
|
@ -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 <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#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 }
|
||||
};
|
|
@ -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 <map>
|
||||
|
||||
#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<uInt16, 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);
|
||||
|
||||
// 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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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)];
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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"
|
||||
};
|
||||
|
|
|
@ -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<Expression*> 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
|
||||
|
|
|
@ -734,7 +734,7 @@
|
|||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\debugger\RamDebug.cxx"
|
||||
RelativePath="..\debugger\CartDebug.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
@ -1352,7 +1352,7 @@
|
|||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\debugger\RamDebug.hxx"
|
||||
RelativePath="..\debugger\CartDebug.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
|
|
@ -26,8 +26,8 @@
|
|||
//#endif
|
||||
|
||||
#include "Expression.hxx"
|
||||
#include "CartDebug.hxx"
|
||||
#include "CpuDebug.hxx"
|
||||
#include "RamDebug.hxx"
|
||||
#include "TIADebug.hxx"
|
||||
|
||||
#include "DebuggerExpressions.hxx"
|
||||
|
@ -42,22 +42,22 @@ string errMsg;
|
|||
#include "y.tab.c"
|
||||
|
||||
const string& errorMessage() {
|
||||
return errMsg;
|
||||
return errMsg;
|
||||
}
|
||||
|
||||
Expression *getResult() {
|
||||
return result.exp;
|
||||
lastExp = 0;
|
||||
return result.exp;
|
||||
lastExp = 0;
|
||||
}
|
||||
|
||||
|
||||
const char *input, *c;
|
||||
|
||||
enum {
|
||||
ST_DEFAULT,
|
||||
ST_IDENTIFIER,
|
||||
ST_OPERATOR,
|
||||
ST_SPACE
|
||||
ST_DEFAULT,
|
||||
ST_IDENTIFIER,
|
||||
ST_OPERATOR,
|
||||
ST_SPACE
|
||||
};
|
||||
|
||||
int state = ST_DEFAULT;
|
||||
|
@ -65,35 +65,35 @@ int state = ST_DEFAULT;
|
|||
//extern int yylval; // bison provides this
|
||||
|
||||
void setInput(const char *in) {
|
||||
input = c = in;
|
||||
state = ST_DEFAULT;
|
||||
input = c = in;
|
||||
state = ST_DEFAULT;
|
||||
}
|
||||
|
||||
int parse(const char *in) {
|
||||
lastExp = 0;
|
||||
errMsg = "(no error)";
|
||||
setInput(in);
|
||||
return yyparse();
|
||||
lastExp = 0;
|
||||
errMsg = "(no error)";
|
||||
setInput(in);
|
||||
return yyparse();
|
||||
}
|
||||
|
||||
/* hand-rolled lexer. Hopefully faster than flex... */
|
||||
inline bool is_base_prefix(char x) { return ( (x=='\\' || x=='$' || x=='#') ); }
|
||||
|
||||
inline bool is_identifier(char x) {
|
||||
return ( (x>='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
|
||||
}
|
||||
|
|
|
@ -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 <val> NUMBER
|
||||
%token <val> ERR
|
||||
%token <equate> EQUATE
|
||||
%token <cpuMethod> CPU_METHOD
|
||||
%token <ramMethod> RAM_METHOD
|
||||
%token <tiaMethod> TIA_METHOD
|
||||
%token <cartMethod> CART_METHOD
|
||||
%token <cpuMethod> CPU_METHOD
|
||||
%token <tiaMethod> TIA_METHOD
|
||||
%token <function> 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; }
|
||||
;
|
||||
%%
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue