2001-12-27 19:54:36 +00:00
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// MM MM 6666 555555 0000 2222
|
|
|
|
// MMMM MMMM 66 66 55 00 00 22 22
|
|
|
|
// MM MMM MM 66 55 00 00 22
|
|
|
|
// MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
|
|
|
|
// MM MM 66 66 55 00 00 22
|
|
|
|
// MM MM 66 66 55 55 00 00 22
|
|
|
|
// MM MM 6666 5555 0000 222222
|
|
|
|
//
|
2017-12-29 20:40:37 +00:00
|
|
|
// Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony
|
2010-04-10 21:37:23 +00:00
|
|
|
// and the Stella Team
|
2001-12-27 19:54:36 +00:00
|
|
|
//
|
2010-01-10 03:23:32 +00:00
|
|
|
// See the file "License.txt" for information on usage and redistribution of
|
2001-12-27 19:54:36 +00:00
|
|
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
|
|
|
//============================================================================
|
|
|
|
|
2006-12-15 16:43:12 +00:00
|
|
|
#ifdef DEBUGGER_SUPPORT
|
2009-05-17 19:30:10 +00:00
|
|
|
#include "Debugger.hxx"
|
2005-08-24 22:54:30 +00:00
|
|
|
#include "Expression.hxx"
|
The emulation core now tracks access to DATA areas (currently, any address
used as a peek operand). Still TODO is deal with poke areas, which would
be relevant in carts with extended RAM.
The interaction between the internal tracking and Distella is now much
tighter, in that knowledge gained by Distella is used in the core code,
and vice versa. This allows the best of both worlds, where the internal
tracking finds stuff at runtime (that couldn't be found in a static
analysis), and Distella tracks potential paths (that haven't occurred at
runtime yet).
Added 'type' debugger prompt command, which basically queries an address
for its disassembly type (CODE/GFX/DATA, etc).
Added debugger commands to query the last address used in an operation
for various registers, but they're only stubs at the moment.
Updated the bankswitch schemes to deal with accesses in and around the
hotspot areas. Previously, peek accesses in these areas weren't being
recorded as DATA areas.
git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2145 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
2010-10-10 20:24:22 +00:00
|
|
|
#include "CartDebug.hxx"
|
2010-10-18 18:39:57 +00:00
|
|
|
#include "PackedBitArray.hxx"
|
2017-12-18 12:28:23 +00:00
|
|
|
#include "Base.hxx"
|
The emulation core now tracks access to DATA areas (currently, any address
used as a peek operand). Still TODO is deal with poke areas, which would
be relevant in carts with extended RAM.
The interaction between the internal tracking and Distella is now much
tighter, in that knowledge gained by Distella is used in the core code,
and vice versa. This allows the best of both worlds, where the internal
tracking finds stuff at runtime (that couldn't be found in a static
analysis), and Distella tracks potential paths (that haven't occurred at
runtime yet).
Added 'type' debugger prompt command, which basically queries an address
for its disassembly type (CODE/GFX/DATA, etc).
Added debugger commands to query the last address used in an operation
for various registers, but they're only stubs at the moment.
Updated the bankswitch schemes to deal with accesses in and around the
hotspot areas. Previously, peek accesses in these areas weren't being
recorded as DATA areas.
git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2145 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
2010-10-10 20:24:22 +00:00
|
|
|
|
|
|
|
// Flags for disassembly types
|
|
|
|
#define DISASM_CODE CartDebug::CODE
|
2017-10-11 14:53:54 +00:00
|
|
|
// #define DISASM_GFX CartDebug::GFX // TODO - uncomment when needed
|
|
|
|
// #define DISASM_PGFX CartDebug::PGFX // TODO - uncomment when needed
|
The emulation core now tracks access to DATA areas (currently, any address
used as a peek operand). Still TODO is deal with poke areas, which would
be relevant in carts with extended RAM.
The interaction between the internal tracking and Distella is now much
tighter, in that knowledge gained by Distella is used in the core code,
and vice versa. This allows the best of both worlds, where the internal
tracking finds stuff at runtime (that couldn't be found in a static
analysis), and Distella tracks potential paths (that haven't occurred at
runtime yet).
Added 'type' debugger prompt command, which basically queries an address
for its disassembly type (CODE/GFX/DATA, etc).
Added debugger commands to query the last address used in an operation
for various registers, but they're only stubs at the moment.
Updated the bankswitch schemes to deal with accesses in and around the
hotspot areas. Previously, peek accesses in these areas weren't being
recorded as DATA areas.
git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2145 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
2010-10-10 20:24:22 +00:00
|
|
|
#define DISASM_DATA CartDebug::DATA
|
2017-10-11 14:53:54 +00:00
|
|
|
// #define DISASM_ROW CartDebug::ROW // TODO - uncomment when needed
|
2017-09-16 20:37:19 +00:00
|
|
|
#define DISASM_WRITE CartDebug::WRITE
|
The emulation core now tracks access to DATA areas (currently, any address
used as a peek operand). Still TODO is deal with poke areas, which would
be relevant in carts with extended RAM.
The interaction between the internal tracking and Distella is now much
tighter, in that knowledge gained by Distella is used in the core code,
and vice versa. This allows the best of both worlds, where the internal
tracking finds stuff at runtime (that couldn't be found in a static
analysis), and Distella tracks potential paths (that haven't occurred at
runtime yet).
Added 'type' debugger prompt command, which basically queries an address
for its disassembly type (CODE/GFX/DATA, etc).
Added debugger commands to query the last address used in an operation
for various registers, but they're only stubs at the moment.
Updated the bankswitch schemes to deal with accesses in and around the
hotspot areas. Previously, peek accesses in these areas weren't being
recorded as DATA areas.
git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2145 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
2010-10-10 20:24:22 +00:00
|
|
|
#define DISASM_NONE 0
|
|
|
|
#else
|
|
|
|
// Flags for disassembly types
|
|
|
|
#define DISASM_CODE 0
|
2017-10-11 14:53:54 +00:00
|
|
|
// #define DISASM_GFX 0 // TODO - uncomment when needed
|
|
|
|
// #define DISASM_PGFX 0 // TODO - uncomment when needed
|
The emulation core now tracks access to DATA areas (currently, any address
used as a peek operand). Still TODO is deal with poke areas, which would
be relevant in carts with extended RAM.
The interaction between the internal tracking and Distella is now much
tighter, in that knowledge gained by Distella is used in the core code,
and vice versa. This allows the best of both worlds, where the internal
tracking finds stuff at runtime (that couldn't be found in a static
analysis), and Distella tracks potential paths (that haven't occurred at
runtime yet).
Added 'type' debugger prompt command, which basically queries an address
for its disassembly type (CODE/GFX/DATA, etc).
Added debugger commands to query the last address used in an operation
for various registers, but they're only stubs at the moment.
Updated the bankswitch schemes to deal with accesses in and around the
hotspot areas. Previously, peek accesses in these areas weren't being
recorded as DATA areas.
git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2145 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
2010-10-10 20:24:22 +00:00
|
|
|
#define DISASM_DATA 0
|
2017-10-11 14:53:54 +00:00
|
|
|
// #define DISASM_ROW 0 // TODO - uncomment when needed
|
The emulation core now tracks access to DATA areas (currently, any address
used as a peek operand). Still TODO is deal with poke areas, which would
be relevant in carts with extended RAM.
The interaction between the internal tracking and Distella is now much
tighter, in that knowledge gained by Distella is used in the core code,
and vice versa. This allows the best of both worlds, where the internal
tracking finds stuff at runtime (that couldn't be found in a static
analysis), and Distella tracks potential paths (that haven't occurred at
runtime yet).
Added 'type' debugger prompt command, which basically queries an address
for its disassembly type (CODE/GFX/DATA, etc).
Added debugger commands to query the last address used in an operation
for various registers, but they're only stubs at the moment.
Updated the bankswitch schemes to deal with accesses in and around the
hotspot areas. Previously, peek accesses in these areas weren't being
recorded as DATA areas.
git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2145 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
2010-10-10 20:24:22 +00:00
|
|
|
#define DISASM_NONE 0
|
2017-10-11 14:53:54 +00:00
|
|
|
#define DISASM_WRITE 0
|
2005-08-24 22:54:30 +00:00
|
|
|
#endif
|
2013-07-21 00:27:52 +00:00
|
|
|
#include "Settings.hxx"
|
2014-11-08 21:27:36 +00:00
|
|
|
#include "Vec.hxx"
|
2001-12-27 19:54:36 +00:00
|
|
|
|
2018-07-13 15:01:37 +00:00
|
|
|
#include "TIA.hxx"
|
|
|
|
#include "M6532.hxx"
|
2017-11-20 18:57:05 +00:00
|
|
|
#include "System.hxx"
|
2009-05-17 19:30:10 +00:00
|
|
|
#include "M6502.hxx"
|
2018-05-23 22:13:43 +00:00
|
|
|
#include "DispatchResult.hxx"
|
2009-05-17 19:30:10 +00:00
|
|
|
|
2001-12-27 19:54:36 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2014-11-03 13:22:57 +00:00
|
|
|
M6502::M6502(const Settings& settings)
|
2008-05-04 17:16:39 +00:00
|
|
|
: myExecutionStatus(0),
|
2014-11-16 00:28:39 +00:00
|
|
|
mySystem(nullptr),
|
2013-07-21 00:27:52 +00:00
|
|
|
mySettings(settings),
|
2015-12-05 01:30:17 +00:00
|
|
|
A(0), X(0), Y(0), SP(0), IR(0), PC(0),
|
|
|
|
N(false), V(false), B(false), D(false), I(false), notZ(false), C(false),
|
2017-12-15 18:12:46 +00:00
|
|
|
icycles(0),
|
2009-05-17 19:30:10 +00:00
|
|
|
myNumberOfDistinctAccesses(0),
|
2009-11-11 20:53:57 +00:00
|
|
|
myLastAddress(0),
|
|
|
|
myLastPeekAddress(0),
|
2010-10-11 00:44:25 +00:00
|
|
|
myLastPokeAddress(0),
|
2017-10-08 10:25:23 +00:00
|
|
|
myLastPeekBaseAddress(0),
|
|
|
|
myLastPokeBaseAddress(0),
|
2013-08-20 14:00:25 +00:00
|
|
|
myLastSrcAddressS(-1),
|
|
|
|
myLastSrcAddressA(-1),
|
|
|
|
myLastSrcAddressX(-1),
|
|
|
|
myLastSrcAddressY(-1),
|
2017-05-26 23:00:03 +00:00
|
|
|
myDataAddressForPoke(0),
|
2017-10-11 14:53:54 +00:00
|
|
|
myOnHaltCallback(nullptr),
|
2017-12-16 20:28:44 +00:00
|
|
|
myHaltRequested(false),
|
2018-01-10 02:46:50 +00:00
|
|
|
myGhostReadsTrap(true),
|
2017-12-16 20:28:44 +00:00
|
|
|
myStepStateByInstruction(false)
|
2001-12-27 19:54:36 +00:00
|
|
|
{
|
2006-12-15 16:43:12 +00:00
|
|
|
#ifdef DEBUGGER_SUPPORT
|
2014-11-16 16:13:58 +00:00
|
|
|
myDebugger = nullptr;
|
2017-10-08 10:25:23 +00:00
|
|
|
myJustHitReadTrapFlag = myJustHitWriteTrapFlag = false;
|
2005-08-24 22:54:30 +00:00
|
|
|
#endif
|
2001-12-27 19:54:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void M6502::install(System& system)
|
|
|
|
{
|
|
|
|
// Remember which system I'm installed in
|
|
|
|
mySystem = &system;
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void M6502::reset()
|
|
|
|
{
|
|
|
|
// Clear the execution status flags
|
|
|
|
myExecutionStatus = 0;
|
|
|
|
|
2014-10-23 15:52:39 +00:00
|
|
|
// Set registers to random or default values
|
2017-11-18 12:14:27 +00:00
|
|
|
bool devSettings = mySettings.getBool("dev.settings");
|
2017-11-24 19:38:21 +00:00
|
|
|
const string& cpurandom = mySettings.getString(devSettings ? "dev.cpurandom" : "plr.cpurandom");
|
2016-04-02 23:47:46 +00:00
|
|
|
SP = BSPF::containsIgnoreCase(cpurandom, "S") ?
|
2017-02-21 21:21:53 +00:00
|
|
|
mySystem->randGenerator().next() : 0xfd;
|
2016-04-02 23:47:46 +00:00
|
|
|
A = BSPF::containsIgnoreCase(cpurandom, "A") ?
|
2014-10-23 15:52:39 +00:00
|
|
|
mySystem->randGenerator().next() : 0x00;
|
2016-04-02 23:47:46 +00:00
|
|
|
X = BSPF::containsIgnoreCase(cpurandom, "X") ?
|
2014-10-23 15:52:39 +00:00
|
|
|
mySystem->randGenerator().next() : 0x00;
|
2016-04-02 23:47:46 +00:00
|
|
|
Y = BSPF::containsIgnoreCase(cpurandom, "Y") ?
|
2014-10-23 15:52:39 +00:00
|
|
|
mySystem->randGenerator().next() : 0x00;
|
2016-04-02 23:47:46 +00:00
|
|
|
PS(BSPF::containsIgnoreCase(cpurandom, "P") ?
|
2014-10-23 15:52:39 +00:00
|
|
|
mySystem->randGenerator().next() : 0x20);
|
2001-12-27 19:54:36 +00:00
|
|
|
|
2017-12-15 18:12:46 +00:00
|
|
|
icycles = 0;
|
2017-12-15 17:13:29 +00:00
|
|
|
|
2001-12-27 19:54:36 +00:00
|
|
|
// Load PC from the reset vector
|
2015-09-14 21:33:50 +00:00
|
|
|
PC = uInt16(mySystem->peek(0xfffc)) | (uInt16(mySystem->peek(0xfffd)) << 8);
|
2008-05-04 17:16:39 +00:00
|
|
|
|
2017-10-08 10:25:23 +00:00
|
|
|
myLastAddress = myLastPeekAddress = myLastPokeAddress = myLastPeekBaseAddress = myLastPokeBaseAddress;
|
2010-11-10 14:01:41 +00:00
|
|
|
myLastSrcAddressS = myLastSrcAddressA =
|
2013-08-20 14:00:25 +00:00
|
|
|
myLastSrcAddressX = myLastSrcAddressY = -1;
|
2010-10-21 21:01:00 +00:00
|
|
|
myDataAddressForPoke = 0;
|
2017-05-26 23:00:03 +00:00
|
|
|
|
|
|
|
myHaltRequested = false;
|
2017-12-18 18:16:41 +00:00
|
|
|
myGhostReadsTrap = mySettings.getBool("dbg.ghostreadstrap");
|
2018-08-06 15:51:47 +00:00
|
|
|
|
|
|
|
myLastBreakCycle = -1;
|
2001-12-27 19:54:36 +00:00
|
|
|
}
|
|
|
|
|
2009-05-17 19:30:10 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
The emulation core now tracks access to DATA areas (currently, any address
used as a peek operand). Still TODO is deal with poke areas, which would
be relevant in carts with extended RAM.
The interaction between the internal tracking and Distella is now much
tighter, in that knowledge gained by Distella is used in the core code,
and vice versa. This allows the best of both worlds, where the internal
tracking finds stuff at runtime (that couldn't be found in a static
analysis), and Distella tracks potential paths (that haven't occurred at
runtime yet).
Added 'type' debugger prompt command, which basically queries an address
for its disassembly type (CODE/GFX/DATA, etc).
Added debugger commands to query the last address used in an operation
for various registers, but they're only stubs at the moment.
Updated the bankswitch schemes to deal with accesses in and around the
hotspot areas. Previously, peek accesses in these areas weren't being
recorded as DATA areas.
git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2145 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
2010-10-10 20:24:22 +00:00
|
|
|
inline uInt8 M6502::peek(uInt16 address, uInt8 flags)
|
2009-05-17 19:30:10 +00:00
|
|
|
{
|
2017-06-23 22:35:17 +00:00
|
|
|
handleHalt();
|
2017-05-26 23:00:03 +00:00
|
|
|
|
2013-05-30 16:07:19 +00:00
|
|
|
////////////////////////////////////////////////
|
|
|
|
// TODO - move this logic directly into CartAR
|
2009-05-17 19:30:10 +00:00
|
|
|
if(address != myLastAddress)
|
|
|
|
{
|
|
|
|
myNumberOfDistinctAccesses++;
|
|
|
|
myLastAddress = address;
|
|
|
|
}
|
2013-05-30 16:07:19 +00:00
|
|
|
////////////////////////////////////////////////
|
2014-11-03 13:22:57 +00:00
|
|
|
mySystem->incrementCycles(SYSTEM_CYCLES_PER_CPU);
|
2017-12-15 18:12:46 +00:00
|
|
|
icycles += SYSTEM_CYCLES_PER_CPU;
|
2017-10-07 16:25:56 +00:00
|
|
|
uInt8 result = mySystem->peek(address, flags);
|
|
|
|
myLastPeekAddress = address;
|
2009-05-17 19:30:10 +00:00
|
|
|
|
|
|
|
#ifdef DEBUGGER_SUPPORT
|
2017-12-18 18:16:41 +00:00
|
|
|
if(myReadTraps.isInitialized() && myReadTraps.isSet(address)
|
|
|
|
&& (myGhostReadsTrap || flags != DISASM_NONE))
|
2009-05-17 19:30:10 +00:00
|
|
|
{
|
2017-10-08 08:43:26 +00:00
|
|
|
myLastPeekBaseAddress = myDebugger->getBaseAddress(myLastPeekAddress, true); // mirror handling
|
2017-10-06 21:06:59 +00:00
|
|
|
int cond = evalCondTraps();
|
|
|
|
if(cond > -1)
|
|
|
|
{
|
2017-10-11 14:53:54 +00:00
|
|
|
myJustHitReadTrapFlag = true;
|
2017-12-18 12:28:23 +00:00
|
|
|
stringstream msg;
|
2017-12-19 08:01:26 +00:00
|
|
|
msg << "RTrap" << (flags == DISASM_NONE ? "G[" : "[") << Common::Base::HEX2 << cond << "]"
|
|
|
|
<< (myTrapCondNames[cond].empty() ? ": " : "If: {" + myTrapCondNames[cond] + "} ");
|
2017-12-18 12:28:23 +00:00
|
|
|
myHitTrapInfo.message = msg.str();
|
2017-10-06 21:06:59 +00:00
|
|
|
myHitTrapInfo.address = address;
|
|
|
|
}
|
2017-10-07 16:25:56 +00:00
|
|
|
}
|
2014-11-16 16:13:58 +00:00
|
|
|
#endif // DEBUGGER_SUPPORT
|
2009-05-17 19:30:10 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2017-09-16 20:37:19 +00:00
|
|
|
inline void M6502::poke(uInt16 address, uInt8 value, uInt8 flags)
|
2009-05-17 19:30:10 +00:00
|
|
|
{
|
2013-05-30 16:07:19 +00:00
|
|
|
////////////////////////////////////////////////
|
|
|
|
// TODO - move this logic directly into CartAR
|
2009-05-17 19:30:10 +00:00
|
|
|
if(address != myLastAddress)
|
|
|
|
{
|
|
|
|
myNumberOfDistinctAccesses++;
|
|
|
|
myLastAddress = address;
|
|
|
|
}
|
2013-05-30 16:07:19 +00:00
|
|
|
////////////////////////////////////////////////
|
2017-10-11 14:53:54 +00:00
|
|
|
mySystem->incrementCycles(SYSTEM_CYCLES_PER_CPU);
|
2017-12-15 18:12:46 +00:00
|
|
|
icycles += SYSTEM_CYCLES_PER_CPU;
|
2017-10-11 14:53:54 +00:00
|
|
|
mySystem->poke(address, value, flags);
|
2017-10-07 16:25:56 +00:00
|
|
|
myLastPokeAddress = address;
|
2009-05-17 19:30:10 +00:00
|
|
|
|
|
|
|
#ifdef DEBUGGER_SUPPORT
|
2014-11-16 16:13:58 +00:00
|
|
|
if(myWriteTraps.isInitialized() && myWriteTraps.isSet(address))
|
2009-05-17 19:30:10 +00:00
|
|
|
{
|
2017-10-08 08:43:26 +00:00
|
|
|
myLastPokeBaseAddress = myDebugger->getBaseAddress(myLastPokeAddress, false); // mirror handling
|
2017-10-06 21:06:59 +00:00
|
|
|
int cond = evalCondTraps();
|
|
|
|
if(cond > -1)
|
|
|
|
{
|
2017-10-08 10:25:23 +00:00
|
|
|
myJustHitWriteTrapFlag = true;
|
2017-12-18 12:28:23 +00:00
|
|
|
stringstream msg;
|
|
|
|
msg << "WTrap[" << Common::Base::HEX2 << cond << "]" << (myTrapCondNames[cond].empty() ? ": " : "If: {" + myTrapCondNames[cond] + "} ");
|
|
|
|
myHitTrapInfo.message = msg.str();
|
2017-10-06 21:06:59 +00:00
|
|
|
myHitTrapInfo.address = address;
|
|
|
|
}
|
2017-10-07 16:25:56 +00:00
|
|
|
}
|
2017-10-11 14:53:54 +00:00
|
|
|
#endif // DEBUGGER_SUPPORT
|
2009-05-17 19:30:10 +00:00
|
|
|
}
|
|
|
|
|
2017-05-26 23:00:03 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void M6502::requestHalt()
|
|
|
|
{
|
|
|
|
if (!myOnHaltCallback) throw runtime_error("onHaltCallback not configured");
|
|
|
|
myHaltRequested = true;
|
|
|
|
}
|
|
|
|
|
2017-06-23 22:35:17 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
inline void M6502::handleHalt()
|
|
|
|
{
|
|
|
|
if (myHaltRequested) {
|
|
|
|
myOnHaltCallback();
|
|
|
|
myHaltRequested = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-17 19:30:10 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2018-07-02 01:53:11 +00:00
|
|
|
void M6502::execute(uInt64 number, DispatchResult& result)
|
2018-01-06 22:33:25 +00:00
|
|
|
{
|
2018-05-23 22:13:43 +00:00
|
|
|
_execute(number, result);
|
2018-01-06 22:33:25 +00:00
|
|
|
|
2018-01-10 02:46:50 +00:00
|
|
|
#ifdef DEBUGGER_SUPPORT
|
2018-01-06 22:33:25 +00:00
|
|
|
// Debugger hack: this ensures that stepping a "STA WSYNC" will actually end at the
|
|
|
|
// beginning of the next line (otherwise, the next instruction would be stepped in order for
|
|
|
|
// the halt to take effect). This is safe because as we know that the next cycle will be a read
|
|
|
|
// cycle anyway.
|
|
|
|
handleHalt();
|
2018-05-04 23:08:09 +00:00
|
|
|
#endif
|
2018-01-06 22:33:25 +00:00
|
|
|
|
|
|
|
// Make sure that the hardware state matches the current system clock. This is necessary
|
2018-05-04 23:08:09 +00:00
|
|
|
// to maintain a consistent state for the debugger after stepping and to make sure
|
|
|
|
// that audio samples are generated for the whole timeslice.
|
2018-01-06 22:33:25 +00:00
|
|
|
mySystem->tia().updateEmulation();
|
|
|
|
mySystem->m6532().updateEmulation();
|
2018-05-23 22:13:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2018-07-02 01:53:11 +00:00
|
|
|
bool M6502::execute(uInt64 number)
|
2018-05-23 22:13:43 +00:00
|
|
|
{
|
|
|
|
DispatchResult result;
|
|
|
|
|
2018-08-04 21:38:28 +00:00
|
|
|
execute(number, result);
|
2018-01-06 22:33:25 +00:00
|
|
|
|
2018-05-23 22:13:43 +00:00
|
|
|
return result.isSuccess();
|
2018-01-06 22:33:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2018-07-02 01:53:11 +00:00
|
|
|
inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
|
2009-05-17 19:30:10 +00:00
|
|
|
{
|
|
|
|
// Clear all of the execution status bits except for the fatal error bit
|
|
|
|
myExecutionStatus &= FatalErrorBit;
|
|
|
|
|
2017-12-16 20:28:44 +00:00
|
|
|
#ifdef DEBUGGER_SUPPORT
|
|
|
|
TIA& tia = mySystem->tia();
|
|
|
|
M6532& riot = mySystem->m6532();
|
|
|
|
#endif
|
|
|
|
|
2018-05-21 22:18:07 +00:00
|
|
|
uInt64 previousCycles = mySystem->cycles();
|
2018-07-02 01:53:11 +00:00
|
|
|
uInt64 currentCycles = 0;
|
2018-05-04 22:47:48 +00:00
|
|
|
|
2009-05-17 19:30:10 +00:00
|
|
|
// Loop until execution is stopped or a fatal error occurs
|
|
|
|
for(;;)
|
|
|
|
{
|
2018-05-21 22:18:07 +00:00
|
|
|
while (!myExecutionStatus && currentCycles < cycles * SYSTEM_CYCLES_PER_CPU)
|
2009-05-17 19:30:10 +00:00
|
|
|
{
|
2018-01-10 02:46:50 +00:00
|
|
|
#ifdef DEBUGGER_SUPPORT
|
2018-05-23 22:19:49 +00:00
|
|
|
// Don't break if we haven't actually executed anything yet
|
2018-08-06 15:51:47 +00:00
|
|
|
if (myLastBreakCycle != mySystem->cycles()) {
|
2018-05-23 22:19:49 +00:00
|
|
|
if(myJustHitReadTrapFlag || myJustHitWriteTrapFlag)
|
|
|
|
{
|
|
|
|
bool read = myJustHitReadTrapFlag;
|
|
|
|
myJustHitReadTrapFlag = myJustHitWriteTrapFlag = false;
|
|
|
|
|
2018-08-06 15:51:47 +00:00
|
|
|
myLastBreakCycle = mySystem->cycles();
|
2018-05-23 22:19:49 +00:00
|
|
|
result.setDebugger(currentCycles, myHitTrapInfo.message, myHitTrapInfo.address, read);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(myBreakPoints.isInitialized() && myBreakPoints.isSet(PC)) {
|
2018-08-06 15:51:47 +00:00
|
|
|
myLastBreakCycle = mySystem->cycles();
|
2018-05-23 22:19:49 +00:00
|
|
|
result.setDebugger(currentCycles, "BP: ", PC);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int cond = evalCondBreaks();
|
|
|
|
if(cond > -1)
|
|
|
|
{
|
|
|
|
stringstream msg;
|
|
|
|
msg << "CBP[" << Common::Base::HEX2 << cond << "]: " << myCondBreakNames[cond];
|
|
|
|
|
2018-08-06 15:51:47 +00:00
|
|
|
myLastBreakCycle = mySystem->cycles();
|
2018-05-23 22:19:49 +00:00
|
|
|
result.setDebugger(currentCycles, msg.str());
|
|
|
|
return;
|
|
|
|
}
|
2009-05-17 19:30:10 +00:00
|
|
|
}
|
2017-11-19 17:52:27 +00:00
|
|
|
|
2018-05-23 22:19:49 +00:00
|
|
|
int cond = evalCondSaveStates();
|
2017-11-19 17:52:27 +00:00
|
|
|
if(cond > -1)
|
|
|
|
{
|
2017-12-18 12:28:23 +00:00
|
|
|
stringstream msg;
|
|
|
|
msg << "conditional savestate [" << Common::Base::HEX2 << cond << "]";
|
|
|
|
myDebugger->addState(msg.str());
|
2017-11-19 17:52:27 +00:00
|
|
|
}
|
2018-01-10 02:46:50 +00:00
|
|
|
#endif // DEBUGGER_SUPPORT
|
2014-11-16 00:28:39 +00:00
|
|
|
|
2010-10-11 00:44:25 +00:00
|
|
|
uInt16 operandAddress = 0, intermediateAddress = 0;
|
2009-11-11 20:53:57 +00:00
|
|
|
uInt8 operand = 0;
|
|
|
|
|
|
|
|
// Reset the peek/poke address pointers
|
2010-10-21 21:01:00 +00:00
|
|
|
myLastPeekAddress = myLastPokeAddress = myDataAddressForPoke = 0;
|
2009-05-17 19:30:10 +00:00
|
|
|
|
2017-12-15 18:12:46 +00:00
|
|
|
icycles = 0;
|
2009-05-17 19:30:10 +00:00
|
|
|
// Fetch instruction at the program counter
|
The emulation core now tracks access to DATA areas (currently, any address
used as a peek operand). Still TODO is deal with poke areas, which would
be relevant in carts with extended RAM.
The interaction between the internal tracking and Distella is now much
tighter, in that knowledge gained by Distella is used in the core code,
and vice versa. This allows the best of both worlds, where the internal
tracking finds stuff at runtime (that couldn't be found in a static
analysis), and Distella tracks potential paths (that haven't occurred at
runtime yet).
Added 'type' debugger prompt command, which basically queries an address
for its disassembly type (CODE/GFX/DATA, etc).
Added debugger commands to query the last address used in an operation
for various registers, but they're only stubs at the moment.
Updated the bankswitch schemes to deal with accesses in and around the
hotspot areas. Previously, peek accesses in these areas weren't being
recorded as DATA areas.
git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2145 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
2010-10-10 20:24:22 +00:00
|
|
|
IR = peek(PC++, DISASM_CODE); // This address represents a code section
|
2009-05-17 19:30:10 +00:00
|
|
|
|
|
|
|
// Call code to execute the instruction
|
|
|
|
switch(IR)
|
|
|
|
{
|
|
|
|
// 6502 instruction emulation is generated by an M4 macro file
|
|
|
|
#include "M6502.ins"
|
|
|
|
|
|
|
|
default:
|
|
|
|
// Oops, illegal instruction executed so set fatal error flag
|
|
|
|
myExecutionStatus |= FatalErrorBit;
|
|
|
|
}
|
2017-12-16 20:28:44 +00:00
|
|
|
|
2018-05-21 22:18:07 +00:00
|
|
|
currentCycles = (mySystem->cycles() - previousCycles);
|
|
|
|
|
2018-01-10 02:46:50 +00:00
|
|
|
#ifdef DEBUGGER_SUPPORT
|
|
|
|
if(myStepStateByInstruction)
|
|
|
|
{
|
2018-01-06 23:31:24 +00:00
|
|
|
// Check out M6502::execute for an explanation.
|
|
|
|
handleHalt();
|
|
|
|
|
2017-12-16 20:28:44 +00:00
|
|
|
tia.updateEmulation();
|
|
|
|
riot.updateEmulation();
|
|
|
|
}
|
2018-01-10 02:46:50 +00:00
|
|
|
#endif
|
2009-05-17 19:30:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// See if we need to handle an interrupt
|
2016-12-30 00:00:30 +00:00
|
|
|
if((myExecutionStatus & MaskableInterruptBit) ||
|
2009-05-17 19:30:10 +00:00
|
|
|
(myExecutionStatus & NonmaskableInterruptBit))
|
|
|
|
{
|
|
|
|
// Yes, so handle the interrupt
|
|
|
|
interruptHandler();
|
|
|
|
}
|
|
|
|
|
|
|
|
// See if execution has been stopped
|
|
|
|
if(myExecutionStatus & StopExecutionBit)
|
|
|
|
{
|
|
|
|
// Yes, so answer that everything finished fine
|
2018-05-23 22:13:43 +00:00
|
|
|
result.setOk(currentCycles);
|
|
|
|
return;
|
2009-05-17 19:30:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// See if a fatal error has occured
|
|
|
|
if(myExecutionStatus & FatalErrorBit)
|
|
|
|
{
|
|
|
|
// Yes, so answer that something when wrong
|
2018-05-23 22:13:43 +00:00
|
|
|
result.setFatal(currentCycles + icycles);
|
|
|
|
return;
|
2009-05-17 19:30:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// See if we've executed the specified number of instructions
|
2018-05-04 22:47:48 +00:00
|
|
|
if (currentCycles >= cycles * SYSTEM_CYCLES_PER_CPU)
|
2009-05-17 19:30:10 +00:00
|
|
|
{
|
|
|
|
// Yes, so answer that everything finished fine
|
2018-05-23 22:13:43 +00:00
|
|
|
result.setOk(currentCycles);
|
|
|
|
return;
|
2009-05-17 19:30:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void M6502::interruptHandler()
|
|
|
|
{
|
|
|
|
// Handle the interrupt
|
|
|
|
if((myExecutionStatus & MaskableInterruptBit) && !I)
|
|
|
|
{
|
2014-11-03 13:22:57 +00:00
|
|
|
mySystem->incrementCycles(7 * SYSTEM_CYCLES_PER_CPU);
|
2009-05-17 19:30:10 +00:00
|
|
|
mySystem->poke(0x0100 + SP--, (PC - 1) >> 8);
|
|
|
|
mySystem->poke(0x0100 + SP--, (PC - 1) & 0x00ff);
|
|
|
|
mySystem->poke(0x0100 + SP--, PS() & (~0x10));
|
|
|
|
D = false;
|
|
|
|
I = true;
|
2015-09-14 21:33:50 +00:00
|
|
|
PC = uInt16(mySystem->peek(0xFFFE)) | (uInt16(mySystem->peek(0xFFFF)) << 8);
|
2009-05-17 19:30:10 +00:00
|
|
|
}
|
|
|
|
else if(myExecutionStatus & NonmaskableInterruptBit)
|
|
|
|
{
|
2014-11-03 13:22:57 +00:00
|
|
|
mySystem->incrementCycles(7 * SYSTEM_CYCLES_PER_CPU);
|
2009-05-17 19:30:10 +00:00
|
|
|
mySystem->poke(0x0100 + SP--, (PC - 1) >> 8);
|
|
|
|
mySystem->poke(0x0100 + SP--, (PC - 1) & 0x00ff);
|
|
|
|
mySystem->poke(0x0100 + SP--, PS() & (~0x10));
|
|
|
|
D = false;
|
2015-09-14 21:33:50 +00:00
|
|
|
PC = uInt16(mySystem->peek(0xFFFA)) | (uInt16(mySystem->peek(0xFFFB)) << 8);
|
2009-05-17 19:30:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Clear the interrupt bits in myExecutionStatus
|
|
|
|
myExecutionStatus &= ~(MaskableInterruptBit | NonmaskableInterruptBit);
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
OK, this looks like a huge update, but it's only because of some Serializer
class reworking. Serializer class now handles read/write of state from
files as well as in-memory streams. As a result, Deserializer class has
been removed.
Added state rewinding to the debugger. For now, this is limited to 100
levels of undo, with a new state generated each time a step/trace/frame/
scanline advance is performed. The undo level is 'rolling', in that it
remembers the last 100 levels (so you lose the oldest states when you
start adding more than 100). For now, this is tied to the 'Alt-r' key
in the debugger. Still TODO is add a button for it, and clean up some
TIA output issues when rewinding.
Added support for 6K version of Supercharger ROMs (this fixes issues
with the 6K version of Cubis).
Cleaned up the Serializable infrastructure, making sure that all
classes that need to implement it actually do so now.
Fixed issue with editable widgets in the UI, where pressing Enter
on the keypad wasn't actually being registered.
git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1849 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
2009-08-05 16:05:34 +00:00
|
|
|
bool M6502::save(Serializer& out) const
|
2009-05-17 19:30:10 +00:00
|
|
|
{
|
OK, this looks like a huge update, but it's only because of some Serializer
class reworking. Serializer class now handles read/write of state from
files as well as in-memory streams. As a result, Deserializer class has
been removed.
Added state rewinding to the debugger. For now, this is limited to 100
levels of undo, with a new state generated each time a step/trace/frame/
scanline advance is performed. The undo level is 'rolling', in that it
remembers the last 100 levels (so you lose the oldest states when you
start adding more than 100). For now, this is tied to the 'Alt-r' key
in the debugger. Still TODO is add a button for it, and clean up some
TIA output issues when rewinding.
Added support for 6K version of Supercharger ROMs (this fixes issues
with the 6K version of Cubis).
Cleaned up the Serializable infrastructure, making sure that all
classes that need to implement it actually do so now.
Fixed issue with editable widgets in the UI, where pressing Enter
on the keypad wasn't actually being registered.
git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1849 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
2009-08-05 16:05:34 +00:00
|
|
|
const string& CPU = name();
|
2009-05-17 19:30:10 +00:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
out.putString(CPU);
|
|
|
|
|
2012-05-20 14:23:48 +00:00
|
|
|
out.putByte(A); // Accumulator
|
|
|
|
out.putByte(X); // X index register
|
|
|
|
out.putByte(Y); // Y index register
|
|
|
|
out.putByte(SP); // Stack Pointer
|
|
|
|
out.putByte(IR); // Instruction register
|
|
|
|
out.putShort(PC); // Program Counter
|
|
|
|
|
|
|
|
out.putBool(N); // N flag for processor status register
|
|
|
|
out.putBool(V); // V flag for processor status register
|
|
|
|
out.putBool(B); // B flag for processor status register
|
|
|
|
out.putBool(D); // D flag for processor status register
|
|
|
|
out.putBool(I); // I flag for processor status register
|
|
|
|
out.putBool(notZ); // Z flag complement for processor status register
|
|
|
|
out.putBool(C); // C flag for processor status register
|
|
|
|
|
|
|
|
out.putByte(myExecutionStatus);
|
2009-05-17 19:30:10 +00:00
|
|
|
|
|
|
|
// Indicates the number of distinct memory accesses
|
|
|
|
out.putInt(myNumberOfDistinctAccesses);
|
2010-10-21 21:01:00 +00:00
|
|
|
// Indicates the last address(es) which was accessed
|
2012-05-20 14:23:48 +00:00
|
|
|
out.putShort(myLastAddress);
|
|
|
|
out.putShort(myLastPeekAddress);
|
|
|
|
out.putShort(myLastPokeAddress);
|
|
|
|
out.putShort(myDataAddressForPoke);
|
2013-08-20 14:00:25 +00:00
|
|
|
out.putInt(myLastSrcAddressS);
|
|
|
|
out.putInt(myLastSrcAddressA);
|
|
|
|
out.putInt(myLastSrcAddressX);
|
|
|
|
out.putInt(myLastSrcAddressY);
|
2017-05-26 23:00:03 +00:00
|
|
|
|
|
|
|
out.putBool(myHaltRequested);
|
2017-12-16 20:28:44 +00:00
|
|
|
out.putBool(myStepStateByInstruction);
|
2017-12-18 18:16:41 +00:00
|
|
|
out.putBool(myGhostReadsTrap);
|
2018-08-06 15:51:47 +00:00
|
|
|
out.putLong(myLastBreakCycle);
|
2009-05-17 19:30:10 +00:00
|
|
|
}
|
2012-05-25 12:41:19 +00:00
|
|
|
catch(...)
|
2009-05-17 19:30:10 +00:00
|
|
|
{
|
2012-05-25 12:41:19 +00:00
|
|
|
cerr << "ERROR: M6502::save" << endl;
|
2009-05-17 19:30:10 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
OK, this looks like a huge update, but it's only because of some Serializer
class reworking. Serializer class now handles read/write of state from
files as well as in-memory streams. As a result, Deserializer class has
been removed.
Added state rewinding to the debugger. For now, this is limited to 100
levels of undo, with a new state generated each time a step/trace/frame/
scanline advance is performed. The undo level is 'rolling', in that it
remembers the last 100 levels (so you lose the oldest states when you
start adding more than 100). For now, this is tied to the 'Alt-r' key
in the debugger. Still TODO is add a button for it, and clean up some
TIA output issues when rewinding.
Added support for 6K version of Supercharger ROMs (this fixes issues
with the 6K version of Cubis).
Cleaned up the Serializable infrastructure, making sure that all
classes that need to implement it actually do so now.
Fixed issue with editable widgets in the UI, where pressing Enter
on the keypad wasn't actually being registered.
git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1849 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
2009-08-05 16:05:34 +00:00
|
|
|
bool M6502::load(Serializer& in)
|
2009-05-17 19:30:10 +00:00
|
|
|
{
|
OK, this looks like a huge update, but it's only because of some Serializer
class reworking. Serializer class now handles read/write of state from
files as well as in-memory streams. As a result, Deserializer class has
been removed.
Added state rewinding to the debugger. For now, this is limited to 100
levels of undo, with a new state generated each time a step/trace/frame/
scanline advance is performed. The undo level is 'rolling', in that it
remembers the last 100 levels (so you lose the oldest states when you
start adding more than 100). For now, this is tied to the 'Alt-r' key
in the debugger. Still TODO is add a button for it, and clean up some
TIA output issues when rewinding.
Added support for 6K version of Supercharger ROMs (this fixes issues
with the 6K version of Cubis).
Cleaned up the Serializable infrastructure, making sure that all
classes that need to implement it actually do so now.
Fixed issue with editable widgets in the UI, where pressing Enter
on the keypad wasn't actually being registered.
git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1849 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
2009-08-05 16:05:34 +00:00
|
|
|
const string& CPU = name();
|
2009-05-17 19:30:10 +00:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if(in.getString() != CPU)
|
|
|
|
return false;
|
|
|
|
|
2012-05-20 14:23:48 +00:00
|
|
|
A = in.getByte(); // Accumulator
|
|
|
|
X = in.getByte(); // X index register
|
|
|
|
Y = in.getByte(); // Y index register
|
|
|
|
SP = in.getByte(); // Stack Pointer
|
|
|
|
IR = in.getByte(); // Instruction register
|
|
|
|
PC = in.getShort(); // Program Counter
|
2009-05-17 19:30:10 +00:00
|
|
|
|
2012-05-20 14:23:48 +00:00
|
|
|
N = in.getBool(); // N flag for processor status register
|
|
|
|
V = in.getBool(); // V flag for processor status register
|
|
|
|
B = in.getBool(); // B flag for processor status register
|
|
|
|
D = in.getBool(); // D flag for processor status register
|
|
|
|
I = in.getBool(); // I flag for processor status register
|
|
|
|
notZ = in.getBool(); // Z flag complement for processor status register
|
|
|
|
C = in.getBool(); // C flag for processor status register
|
2009-05-17 19:30:10 +00:00
|
|
|
|
2012-05-20 14:23:48 +00:00
|
|
|
myExecutionStatus = in.getByte();
|
2009-05-17 19:30:10 +00:00
|
|
|
|
|
|
|
// Indicates the number of distinct memory accesses
|
2012-05-20 14:23:48 +00:00
|
|
|
myNumberOfDistinctAccesses = in.getInt();
|
2010-10-21 21:01:00 +00:00
|
|
|
// Indicates the last address(es) which was accessed
|
2012-05-20 14:23:48 +00:00
|
|
|
myLastAddress = in.getShort();
|
|
|
|
myLastPeekAddress = in.getShort();
|
|
|
|
myLastPokeAddress = in.getShort();
|
|
|
|
myDataAddressForPoke = in.getShort();
|
2013-08-20 14:00:25 +00:00
|
|
|
myLastSrcAddressS = in.getInt();
|
|
|
|
myLastSrcAddressA = in.getInt();
|
|
|
|
myLastSrcAddressX = in.getInt();
|
|
|
|
myLastSrcAddressY = in.getInt();
|
2017-05-26 23:00:03 +00:00
|
|
|
|
|
|
|
myHaltRequested = in.getBool();
|
2017-12-16 20:28:44 +00:00
|
|
|
myStepStateByInstruction = in.getBool();
|
2017-12-18 18:16:41 +00:00
|
|
|
myGhostReadsTrap = in.getBool();
|
2018-08-06 15:51:47 +00:00
|
|
|
|
|
|
|
myLastBreakCycle = in.getLong();
|
2009-05-17 19:30:10 +00:00
|
|
|
}
|
2012-05-25 12:41:19 +00:00
|
|
|
catch(...)
|
2009-05-17 19:30:10 +00:00
|
|
|
{
|
2015-02-06 16:34:01 +00:00
|
|
|
cerr << "ERROR: M6502::load" << endl;
|
2009-05-17 19:30:10 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-12-17 21:07:56 +00:00
|
|
|
#ifdef DEBUGGER_SUPPORT
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void M6502::attach(Debugger& debugger)
|
|
|
|
{
|
|
|
|
// Remember the debugger for this microprocessor
|
|
|
|
myDebugger = &debugger;
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2014-11-16 16:13:58 +00:00
|
|
|
uInt32 M6502::addCondBreak(Expression* e, const string& name)
|
2009-12-17 21:07:56 +00:00
|
|
|
{
|
2017-11-19 17:52:27 +00:00
|
|
|
myCondBreaks.emplace_back(e);
|
|
|
|
myCondBreakNames.push_back(name);
|
2017-12-16 20:28:44 +00:00
|
|
|
|
|
|
|
updateStepStateByInstruction();
|
|
|
|
|
2017-11-19 17:52:27 +00:00
|
|
|
return uInt32(myCondBreaks.size() - 1);
|
2009-12-17 21:07:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2017-11-19 17:52:27 +00:00
|
|
|
bool M6502::delCondBreak(uInt32 idx)
|
2009-12-17 21:07:56 +00:00
|
|
|
{
|
2017-11-19 17:52:27 +00:00
|
|
|
if(idx < myCondBreaks.size())
|
2009-12-17 21:07:56 +00:00
|
|
|
{
|
2017-11-19 17:52:27 +00:00
|
|
|
Vec::removeAt(myCondBreaks, idx);
|
|
|
|
Vec::removeAt(myCondBreakNames, idx);
|
2017-12-16 20:28:44 +00:00
|
|
|
|
|
|
|
updateStepStateByInstruction();
|
|
|
|
|
2017-10-07 16:25:56 +00:00
|
|
|
return true;
|
2009-12-17 21:07:56 +00:00
|
|
|
}
|
2017-10-07 16:25:56 +00:00
|
|
|
return false;
|
2009-12-17 21:07:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void M6502::clearCondBreaks()
|
|
|
|
{
|
2017-11-19 17:52:27 +00:00
|
|
|
myCondBreaks.clear();
|
|
|
|
myCondBreakNames.clear();
|
2017-12-16 20:28:44 +00:00
|
|
|
|
|
|
|
updateStepStateByInstruction();
|
2009-12-17 21:07:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
const StringList& M6502::getCondBreakNames() const
|
|
|
|
{
|
2017-11-19 17:52:27 +00:00
|
|
|
return myCondBreakNames;
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
uInt32 M6502::addCondSaveState(Expression* e, const string& name)
|
|
|
|
{
|
|
|
|
myCondSaveStates.emplace_back(e);
|
|
|
|
myCondSaveStateNames.push_back(name);
|
2017-12-16 20:28:44 +00:00
|
|
|
|
|
|
|
updateStepStateByInstruction();
|
|
|
|
|
2017-11-19 17:52:27 +00:00
|
|
|
return uInt32(myCondSaveStates.size() - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
bool M6502::delCondSaveState(uInt32 idx)
|
|
|
|
{
|
|
|
|
if(idx < myCondSaveStates.size())
|
|
|
|
{
|
|
|
|
Vec::removeAt(myCondSaveStates, idx);
|
|
|
|
Vec::removeAt(myCondSaveStateNames, idx);
|
2017-12-16 20:28:44 +00:00
|
|
|
|
|
|
|
updateStepStateByInstruction();
|
|
|
|
|
2017-11-19 17:52:27 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void M6502::clearCondSaveStates()
|
|
|
|
{
|
|
|
|
myCondSaveStates.clear();
|
|
|
|
myCondSaveStateNames.clear();
|
2017-12-16 20:28:44 +00:00
|
|
|
|
|
|
|
updateStepStateByInstruction();
|
2017-11-19 17:52:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
const StringList& M6502::getCondSaveStateNames() const
|
|
|
|
{
|
|
|
|
return myCondSaveStateNames;
|
2009-12-17 21:07:56 +00:00
|
|
|
}
|
2017-10-06 21:06:59 +00:00
|
|
|
|
2017-10-07 12:17:34 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2017-10-06 21:06:59 +00:00
|
|
|
uInt32 M6502::addCondTrap(Expression* e, const string& name)
|
|
|
|
{
|
2017-10-07 12:17:34 +00:00
|
|
|
myTrapConds.emplace_back(e);
|
2017-10-06 21:06:59 +00:00
|
|
|
myTrapCondNames.push_back(name);
|
2017-12-16 20:28:44 +00:00
|
|
|
|
|
|
|
updateStepStateByInstruction();
|
|
|
|
|
2017-10-06 21:06:59 +00:00
|
|
|
return uInt32(myTrapConds.size() - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2017-10-07 16:25:56 +00:00
|
|
|
bool M6502::delCondTrap(uInt32 brk)
|
2017-10-06 21:06:59 +00:00
|
|
|
{
|
|
|
|
if(brk < myTrapConds.size())
|
|
|
|
{
|
2017-10-07 12:17:34 +00:00
|
|
|
Vec::removeAt(myTrapConds, brk);
|
2017-10-06 21:06:59 +00:00
|
|
|
Vec::removeAt(myTrapCondNames, brk);
|
2017-12-16 20:28:44 +00:00
|
|
|
|
|
|
|
updateStepStateByInstruction();
|
|
|
|
|
2017-10-07 16:25:56 +00:00
|
|
|
return true;
|
2017-10-06 21:06:59 +00:00
|
|
|
}
|
2017-10-07 16:25:56 +00:00
|
|
|
return false;
|
2017-10-11 14:53:54 +00:00
|
|
|
}
|
2017-10-06 21:06:59 +00:00
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void M6502::clearCondTraps()
|
|
|
|
{
|
|
|
|
myTrapConds.clear();
|
|
|
|
myTrapCondNames.clear();
|
2017-12-16 20:28:44 +00:00
|
|
|
|
|
|
|
updateStepStateByInstruction();
|
2017-10-06 21:06:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
const StringList& M6502::getCondTrapNames() const
|
|
|
|
{
|
|
|
|
return myTrapCondNames;
|
2017-10-07 12:17:34 +00:00
|
|
|
}
|
2018-03-31 23:03:25 +00:00
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void M6502::updateStepStateByInstruction()
|
|
|
|
{
|
|
|
|
myStepStateByInstruction = myCondBreaks.size() || myCondSaveStates.size() ||
|
|
|
|
myTrapConds.size();
|
|
|
|
}
|
|
|
|
|
2014-11-16 00:28:39 +00:00
|
|
|
#endif // DEBUGGER_SUPPORT
|