mirror of https://github.com/stella-emu/stella.git
The CPU emulation now always uses what was previously called 'Hi' mode.
The low-compatibility mode was removed, as it hasn't been tested in years, and for the CPU work I have to do in the coming months, I only want to worry about one CPU class. All reference to M6502Hi/M6502Low has been removed; the CPU class is now simply known as M6502. Commented out the recent fix for Q-Bert screen refresh issues, since there's an underlying TIA emulation problem that is causing it. git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1729 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
61914d3b3e
commit
b99ed19695
|
@ -19,7 +19,7 @@
|
|||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#include "M6502Hi.hxx"
|
||||
#include "M6502.hxx"
|
||||
#include "Random.hxx"
|
||||
#include "System.hxx"
|
||||
#include "CartAR.hxx"
|
||||
|
@ -80,7 +80,7 @@ void CartridgeAR::install(System& system)
|
|||
uInt16 shift = mySystem->pageShift();
|
||||
uInt16 mask = mySystem->pageMask();
|
||||
|
||||
my6502 = &(M6502High&)mySystem->m6502();
|
||||
my6502 = &(mySystem->m6502());
|
||||
|
||||
// Make sure the system we're being installed in has a page size that'll work
|
||||
assert((0x1000 & mask) == 0);
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#ifndef CARTRIDGEAR_HXX
|
||||
#define CARTRIDGEAR_HXX
|
||||
|
||||
class M6502High;
|
||||
class M6502;
|
||||
class System;
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
@ -165,7 +165,7 @@ class CartridgeAR : public Cartridge
|
|||
|
||||
private:
|
||||
// Pointer to the 6502 processor in the system
|
||||
M6502High* my6502;
|
||||
M6502* my6502;
|
||||
|
||||
// Indicates the offest within the image for the corresponding bank
|
||||
uInt32 myImageOffset[2];
|
||||
|
|
|
@ -32,8 +32,7 @@
|
|||
#include "Joystick.hxx"
|
||||
#include "Keyboard.hxx"
|
||||
#include "KidVid.hxx"
|
||||
#include "M6502Hi.hxx"
|
||||
#include "M6502Low.hxx"
|
||||
#include "M6502.hxx"
|
||||
#include "M6532.hxx"
|
||||
#include "Paddles.hxx"
|
||||
#include "Props.hxx"
|
||||
|
@ -98,11 +97,7 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props)
|
|||
myControllers[0] = new Joystick(Controller::Left, *myEvent, *mySystem);
|
||||
myControllers[1] = new Joystick(Controller::Right, *myEvent, *mySystem);
|
||||
|
||||
M6502* m6502;
|
||||
if(myOSystem->settings().getString("cpu") == "low")
|
||||
m6502 = new M6502Low(1);
|
||||
else
|
||||
m6502 = new M6502High(1);
|
||||
M6502* m6502 = new M6502(1);
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
m6502->attach(myOSystem->debugger());
|
||||
#endif
|
||||
|
|
|
@ -931,6 +931,7 @@ void EventHandler::handleEvent(Event::Type event, int state)
|
|||
break;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if 0
|
||||
case Event::ConsoleReset:
|
||||
if(state)
|
||||
{
|
||||
|
@ -938,7 +939,7 @@ void EventHandler::handleEvent(Event::Type event, int state)
|
|||
myOSystem->frameBuffer().refresh();
|
||||
}
|
||||
break;
|
||||
|
||||
#endif
|
||||
case Event::Fry:
|
||||
myFryingFlag = bool(state);
|
||||
return;
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
License Information and Copyright Notice
|
||||
===============================================================================
|
||||
|
||||
Copyright (C) 1995-2002 Bradford W. Mott <bwmott@acm.org>
|
||||
Copyright (C) 1995-2009 Bradford W. Mott <bwmott@acm.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
|
|
@ -3,8 +3,6 @@ MODULE := src/emucore/m6502
|
|||
MODULE_OBJS := \
|
||||
src/emucore/m6502/src/Device.o \
|
||||
src/emucore/m6502/src/M6502.o \
|
||||
src/emucore/m6502/src/M6502Low.o \
|
||||
src/emucore/m6502/src/M6502Hi.o \
|
||||
src/emucore/m6502/src/NullDev.o \
|
||||
src/emucore/m6502/src/System.o
|
||||
|
||||
|
|
|
@ -16,25 +16,36 @@
|
|||
// $Id$
|
||||
//============================================================================
|
||||
|
||||
#include "M6502.hxx"
|
||||
//#define DEBUG_OUTPUT
|
||||
#define debugStream cout
|
||||
|
||||
#include "Serializer.hxx"
|
||||
#include "Deserializer.hxx"
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
#include "Debugger.hxx"
|
||||
#include "Expression.hxx"
|
||||
#endif
|
||||
|
||||
#include "M6502.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
M6502::M6502(uInt32 systemCyclesPerProcessorCycle)
|
||||
: myExecutionStatus(0),
|
||||
mySystem(0),
|
||||
mySystemCyclesPerProcessorCycle(systemCyclesPerProcessorCycle),
|
||||
myLastAccessWasRead(true),
|
||||
myTotalInstructionCount(0)
|
||||
myTotalInstructionCount(0),
|
||||
myNumberOfDistinctAccesses(0),
|
||||
myLastAddress(0)
|
||||
{
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
myDebugger = NULL;
|
||||
myBreakPoints = NULL;
|
||||
myReadTraps = NULL;
|
||||
myWriteTraps = NULL;
|
||||
|
||||
myJustHitTrapFlag = false;
|
||||
#endif
|
||||
|
||||
// Compute the System Cycle table
|
||||
|
@ -43,6 +54,11 @@ M6502::M6502(uInt32 systemCyclesPerProcessorCycle)
|
|||
myInstructionSystemCycleTable[t] = ourInstructionProcessorCycleTable[t] *
|
||||
mySystemCyclesPerProcessorCycle;
|
||||
}
|
||||
|
||||
|
||||
debugStream << "( Fm Ln Cyc Clk) ( P0 P1 M0 M1 BL) "
|
||||
<< "flags A X Y SP Code Disasm" << endl
|
||||
<< endl;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -134,6 +150,280 @@ void M6502::PS(uInt8 ps)
|
|||
C = ps & 0x01;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
inline uInt8 M6502::peek(uInt16 address)
|
||||
{
|
||||
if(address != myLastAddress)
|
||||
{
|
||||
myNumberOfDistinctAccesses++;
|
||||
myLastAddress = address;
|
||||
}
|
||||
mySystem->incrementCycles(mySystemCyclesPerProcessorCycle);
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
if(myReadTraps != NULL && myReadTraps->isSet(address))
|
||||
{
|
||||
myJustHitTrapFlag = true;
|
||||
myHitTrapInfo.message = "RTrap: ";
|
||||
myHitTrapInfo.address = address;
|
||||
}
|
||||
#endif
|
||||
|
||||
uInt8 result = mySystem->peek(address);
|
||||
myLastAccessWasRead = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
inline void M6502::poke(uInt16 address, uInt8 value)
|
||||
{
|
||||
if(address != myLastAddress)
|
||||
{
|
||||
myNumberOfDistinctAccesses++;
|
||||
myLastAddress = address;
|
||||
}
|
||||
mySystem->incrementCycles(mySystemCyclesPerProcessorCycle);
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
if(myWriteTraps != NULL && myWriteTraps->isSet(address))
|
||||
{
|
||||
myJustHitTrapFlag = true;
|
||||
myHitTrapInfo.message = "WTrap: ";
|
||||
myHitTrapInfo.address = address;
|
||||
}
|
||||
#endif
|
||||
|
||||
mySystem->poke(address, value);
|
||||
myLastAccessWasRead = false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool M6502::execute(uInt32 number)
|
||||
{
|
||||
// Clear all of the execution status bits except for the fatal error bit
|
||||
myExecutionStatus &= FatalErrorBit;
|
||||
|
||||
// Loop until execution is stopped or a fatal error occurs
|
||||
for(;;)
|
||||
{
|
||||
for(; !myExecutionStatus && (number != 0); --number)
|
||||
{
|
||||
uInt16 operandAddress = 0;
|
||||
uInt8 operand = 0;
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
if(myJustHitTrapFlag)
|
||||
{
|
||||
if(myDebugger->start(myHitTrapInfo.message, myHitTrapInfo.address))
|
||||
{
|
||||
myJustHitTrapFlag = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(myBreakPoints != NULL)
|
||||
{
|
||||
if(myBreakPoints->isSet(PC))
|
||||
{
|
||||
if(myDebugger->start("BP: ", PC))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int cond = evalCondBreaks();
|
||||
if(cond > -1)
|
||||
{
|
||||
string buf = "CBP: " + myBreakCondNames[cond];
|
||||
if(myDebugger->start(buf))
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Fetch instruction at the program counter
|
||||
IR = peek(PC++);
|
||||
|
||||
#ifdef DEBUG_OUTPUT
|
||||
debugStream << ::hex << setw(2) << (int)A << " "
|
||||
<< ::hex << setw(2) << (int)X << " "
|
||||
<< ::hex << setw(2) << (int)Y << " "
|
||||
<< ::hex << setw(2) << (int)SP << " "
|
||||
<< setw(4) << (PC-1) << ": "
|
||||
<< setw(2) << (int)IR << " "
|
||||
// << "<" << ourAddressingModeTable[IR] << " ";
|
||||
// debugStream << hex << setw(4) << operandAddress << " ";
|
||||
<< setw(3) << ourInstructionMnemonicTable[IR]
|
||||
|
||||
// debugStream << "PS=" << ::hex << setw(2) << (int)PS() << " ";
|
||||
|
||||
// debugStream << "Cyc=" << dec << mySystem->cycles();
|
||||
<< endl;
|
||||
#endif
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
myTotalInstructionCount++;
|
||||
}
|
||||
|
||||
// See if we need to handle an interrupt
|
||||
if((myExecutionStatus & MaskableInterruptBit) ||
|
||||
(myExecutionStatus & NonmaskableInterruptBit))
|
||||
{
|
||||
// Yes, so handle the interrupt
|
||||
interruptHandler();
|
||||
}
|
||||
|
||||
// See if execution has been stopped
|
||||
if(myExecutionStatus & StopExecutionBit)
|
||||
{
|
||||
// Yes, so answer that everything finished fine
|
||||
return true;
|
||||
}
|
||||
|
||||
// See if a fatal error has occured
|
||||
if(myExecutionStatus & FatalErrorBit)
|
||||
{
|
||||
// Yes, so answer that something when wrong
|
||||
return false;
|
||||
}
|
||||
|
||||
// See if we've executed the specified number of instructions
|
||||
if(number == 0)
|
||||
{
|
||||
// Yes, so answer that everything finished fine
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void M6502::interruptHandler()
|
||||
{
|
||||
// Handle the interrupt
|
||||
if((myExecutionStatus & MaskableInterruptBit) && !I)
|
||||
{
|
||||
mySystem->incrementCycles(7 * mySystemCyclesPerProcessorCycle);
|
||||
mySystem->poke(0x0100 + SP--, (PC - 1) >> 8);
|
||||
mySystem->poke(0x0100 + SP--, (PC - 1) & 0x00ff);
|
||||
mySystem->poke(0x0100 + SP--, PS() & (~0x10));
|
||||
D = false;
|
||||
I = true;
|
||||
PC = (uInt16)mySystem->peek(0xFFFE) | ((uInt16)mySystem->peek(0xFFFF) << 8);
|
||||
}
|
||||
else if(myExecutionStatus & NonmaskableInterruptBit)
|
||||
{
|
||||
mySystem->incrementCycles(7 * mySystemCyclesPerProcessorCycle);
|
||||
mySystem->poke(0x0100 + SP--, (PC - 1) >> 8);
|
||||
mySystem->poke(0x0100 + SP--, (PC - 1) & 0x00ff);
|
||||
mySystem->poke(0x0100 + SP--, PS() & (~0x10));
|
||||
D = false;
|
||||
PC = (uInt16)mySystem->peek(0xFFFA) | ((uInt16)mySystem->peek(0xFFFB) << 8);
|
||||
}
|
||||
|
||||
// Clear the interrupt bits in myExecutionStatus
|
||||
myExecutionStatus &= ~(MaskableInterruptBit | NonmaskableInterruptBit);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool M6502::save(Serializer& out)
|
||||
{
|
||||
string CPU = name();
|
||||
|
||||
try
|
||||
{
|
||||
out.putString(CPU);
|
||||
|
||||
out.putByte((char)A); // Accumulator
|
||||
out.putByte((char)X); // X index register
|
||||
out.putByte((char)Y); // Y index register
|
||||
out.putByte((char)SP); // Stack Pointer
|
||||
out.putByte((char)IR); // Instruction register
|
||||
out.putInt(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((char)myExecutionStatus);
|
||||
|
||||
// Indicates the number of distinct memory accesses
|
||||
out.putInt(myNumberOfDistinctAccesses);
|
||||
// Indicates the last address which was accessed
|
||||
out.putInt(myLastAddress);
|
||||
|
||||
}
|
||||
catch(char *msg)
|
||||
{
|
||||
cerr << msg << endl;
|
||||
return false;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cerr << "Unknown error in save state for " << CPU << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool M6502::load(Deserializer& in)
|
||||
{
|
||||
string CPU = name();
|
||||
|
||||
try
|
||||
{
|
||||
if(in.getString() != CPU)
|
||||
return false;
|
||||
|
||||
A = (uInt8) in.getByte(); // Accumulator
|
||||
X = (uInt8) in.getByte(); // X index register
|
||||
Y = (uInt8) in.getByte(); // Y index register
|
||||
SP = (uInt8) in.getByte(); // Stack Pointer
|
||||
IR = (uInt8) in.getByte(); // Instruction register
|
||||
PC = (uInt16) in.getInt(); // Program Counter
|
||||
|
||||
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
|
||||
|
||||
myExecutionStatus = (uInt8) in.getByte();
|
||||
|
||||
// Indicates the number of distinct memory accesses
|
||||
myNumberOfDistinctAccesses = (uInt32) in.getInt();
|
||||
// Indicates the last address which was accessed
|
||||
myLastAddress = (uInt16) in.getInt();
|
||||
}
|
||||
catch(char *msg)
|
||||
{
|
||||
cerr << msg << endl;
|
||||
return false;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cerr << "Unknown error in load state for " << CPU << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
ostream& operator<<(ostream& out, const M6502::AddressingMode& mode)
|
||||
{
|
||||
|
|
|
@ -36,12 +36,17 @@ class PackedBitArray;
|
|||
typedef Common::Array<Expression*> ExpressionList;
|
||||
|
||||
/**
|
||||
This is an abstract base class for classes that emulate the
|
||||
6502 microprocessor. The 6502 is an 8-bit microprocessor that
|
||||
has a 64K addressing space.
|
||||
The 6502 is an 8-bit microprocessor that has a 64K addressing space.
|
||||
This class provides a high compatibility 6502 microprocessor emulator.
|
||||
|
||||
The memory accesses and cycle counts it generates are valid at the
|
||||
sub-instruction level and "false" reads are generated (such as the ones
|
||||
produced by the Indirect,X addressing when it crosses a page boundary).
|
||||
This provides provides better compatibility for hardware that has side
|
||||
effects and for games which are very time sensitive.
|
||||
|
||||
@author Bradford W. Mott
|
||||
@version $Id$
|
||||
@version $Id$
|
||||
*/
|
||||
class M6502
|
||||
{
|
||||
|
@ -92,68 +97,25 @@ class M6502
|
|||
|
||||
@param system The system the processor should install itself in
|
||||
*/
|
||||
virtual void install(System& system);
|
||||
void install(System& system);
|
||||
|
||||
/**
|
||||
Reset the processor to its power-on state. This method should not
|
||||
be invoked until the entire 6502 system is constructed and installed
|
||||
since it involves reading the reset vector from memory.
|
||||
*/
|
||||
virtual void reset();
|
||||
void reset();
|
||||
|
||||
/**
|
||||
Request a maskable interrupt
|
||||
*/
|
||||
virtual void irq();
|
||||
void irq();
|
||||
|
||||
/**
|
||||
Request a non-maskable interrupt
|
||||
*/
|
||||
virtual void nmi();
|
||||
void nmi();
|
||||
|
||||
/**
|
||||
Saves the current state of this device to the given Serializer.
|
||||
|
||||
@param out The serializer device to save to.
|
||||
@return The result of the save. True on success, false on failure.
|
||||
*/
|
||||
virtual bool save(Serializer& out) = 0;
|
||||
|
||||
/**
|
||||
Loads the current state of this device from the given Deserializer.
|
||||
|
||||
@param in The deserializer device to load from.
|
||||
@return The result of the load. True on success, false on failure.
|
||||
*/
|
||||
virtual bool load(Deserializer& in) = 0;
|
||||
|
||||
/**
|
||||
Get a null terminated string which is the processor's name (i.e. "M6532")
|
||||
|
||||
@return The name of the device
|
||||
*/
|
||||
virtual const char* name() const = 0;
|
||||
|
||||
public:
|
||||
/**
|
||||
Get the addressing mode of the specified instruction
|
||||
|
||||
@param opcode The opcode of the instruction
|
||||
@return The addressing mode of the instruction
|
||||
*/
|
||||
AddressingMode addressingMode(uInt8 opcode) const
|
||||
{ return ourAddressingModeTable[opcode]; }
|
||||
|
||||
/**
|
||||
Get the access mode of the specified instruction
|
||||
|
||||
@param opcode The opcode of the instruction
|
||||
@return The access mode of the instruction
|
||||
*/
|
||||
AccessMode accessMode(uInt8 opcode) const
|
||||
{ return ourAccessModeTable[opcode]; }
|
||||
|
||||
public:
|
||||
/**
|
||||
Execute instructions until the specified number of instructions
|
||||
is executed, someone stops execution, or an error occurs. Answers
|
||||
|
@ -162,7 +124,7 @@ class M6502
|
|||
@param number Indicates the number of instructions to execute
|
||||
@return true iff execution stops normally
|
||||
*/
|
||||
virtual bool execute(uInt32 number) = 0;
|
||||
bool execute(uInt32 number);
|
||||
|
||||
/**
|
||||
Tell the processor to stop executing instructions. Invoking this
|
||||
|
@ -177,10 +139,7 @@ class M6502
|
|||
|
||||
@return true iff a fatal error has occured
|
||||
*/
|
||||
bool fatalError() const
|
||||
{
|
||||
return myExecutionStatus & FatalErrorBit;
|
||||
}
|
||||
bool fatalError() const { return myExecutionStatus & FatalErrorBit; }
|
||||
|
||||
/**
|
||||
Get the 16-bit value of the Program Counter register.
|
||||
|
@ -203,7 +162,13 @@ class M6502
|
|||
*/
|
||||
int totalInstructionCount() const { return myTotalInstructionCount; }
|
||||
|
||||
public:
|
||||
/**
|
||||
Get the number of memory accesses to distinct memory locations
|
||||
|
||||
@return The number of memory accesses to distinct memory locations
|
||||
*/
|
||||
uInt32 distinctAccesses() const { return myNumberOfDistinctAccesses; }
|
||||
|
||||
/**
|
||||
Overload the ostream output operator for addressing modes.
|
||||
|
||||
|
@ -212,8 +177,50 @@ class M6502
|
|||
*/
|
||||
friend ostream& operator<<(ostream& out, const AddressingMode& mode);
|
||||
|
||||
/**
|
||||
Saves the current state of this device to the given Serializer.
|
||||
|
||||
@param out The serializer device to save to.
|
||||
@return The result of the save. True on success, false on failure.
|
||||
*/
|
||||
bool save(Serializer& out);
|
||||
|
||||
/**
|
||||
Loads the current state of this device from the given Deserializer.
|
||||
|
||||
@param in The deserializer device to load from.
|
||||
@return The result of the load. True on success, false on failure.
|
||||
*/
|
||||
bool load(Deserializer& in);
|
||||
|
||||
/**
|
||||
Get a null terminated string which is the processor's name (i.e. "M6532")
|
||||
|
||||
@return The name of the device
|
||||
*/
|
||||
const char* name() const { return "M6502High"; }
|
||||
|
||||
public:
|
||||
/**
|
||||
Get the addressing mode of the specified instruction
|
||||
|
||||
@param opcode The opcode of the instruction
|
||||
@return The addressing mode of the instruction
|
||||
*/
|
||||
AddressingMode addressingMode(uInt8 opcode) const
|
||||
{ return ourAddressingModeTable[opcode]; }
|
||||
|
||||
/**
|
||||
Get the access mode of the specified instruction
|
||||
|
||||
@param opcode The opcode of the instruction
|
||||
@return The access mode of the instruction
|
||||
*/
|
||||
AccessMode accessMode(uInt8 opcode) const
|
||||
{ return ourAccessModeTable[opcode]; }
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
public:
|
||||
/**
|
||||
Attach the specified debugger.
|
||||
|
||||
|
@ -232,7 +239,23 @@ class M6502
|
|||
int evalCondBreaks();
|
||||
#endif
|
||||
|
||||
protected:
|
||||
private:
|
||||
/**
|
||||
Get the byte at the specified address and update the cycle count.
|
||||
|
||||
@return The byte at the specified address
|
||||
*/
|
||||
inline uInt8 peek(uInt16 address);
|
||||
|
||||
/**
|
||||
Change the byte at the specified address to the given value and
|
||||
update the cycle count.
|
||||
|
||||
@param address The address where the value should be stored
|
||||
@param value The value to be stored at the address
|
||||
*/
|
||||
inline void poke(uInt16 address, uInt8 value);
|
||||
|
||||
/**
|
||||
Get the 8-bit value of the Processor Status register.
|
||||
|
||||
|
@ -247,7 +270,12 @@ class M6502
|
|||
*/
|
||||
void PS(uInt8 ps);
|
||||
|
||||
protected:
|
||||
/**
|
||||
Called after an interrupt has be requested using irq() or nmi()
|
||||
*/
|
||||
void interruptHandler();
|
||||
|
||||
private:
|
||||
uInt8 A; // Accumulator
|
||||
uInt8 X; // X index register
|
||||
uInt8 Y; // Y index register
|
||||
|
@ -266,12 +294,7 @@ class M6502
|
|||
/**
|
||||
Bit fields used to indicate that certain conditions need to be
|
||||
handled such as stopping execution, fatal errors, maskable interrupts
|
||||
and non-maskable interrupts
|
||||
*/
|
||||
uInt8 myExecutionStatus;
|
||||
|
||||
/**
|
||||
Constants used for setting bits in myExecutionStatus
|
||||
and non-maskable interrupts (in myExecutionStatus)
|
||||
*/
|
||||
enum
|
||||
{
|
||||
|
@ -280,6 +303,7 @@ class M6502
|
|||
MaskableInterruptBit = 0x04,
|
||||
NonmaskableInterruptBit = 0x08
|
||||
};
|
||||
uInt8 myExecutionStatus;
|
||||
|
||||
/// Pointer to the system the processor is installed in or the null pointer
|
||||
System* mySystem;
|
||||
|
@ -296,6 +320,12 @@ class M6502
|
|||
/// The total number of instructions executed so far
|
||||
int myTotalInstructionCount;
|
||||
|
||||
/// Indicates the numer of distinct memory accesses
|
||||
uInt32 myNumberOfDistinctAccesses;
|
||||
|
||||
/// Indicates the last address which was accessed
|
||||
uInt16 myLastAddress;
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
/// Pointer to the debugger for this processor or the null pointer
|
||||
Debugger* myDebugger;
|
||||
|
@ -316,7 +346,7 @@ class M6502
|
|||
ExpressionList myBreakConds;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
private:
|
||||
/// Addressing mode for each of the 256 opcodes
|
||||
/// This specifies how the opcode argument is addressed
|
||||
static AddressingMode ourAddressingModeTable[256];
|
||||
|
|
|
@ -13,118 +13,17 @@
|
|||
// See the file "license" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id$
|
||||
//============================================================================
|
||||
|
||||
/**
|
||||
Code to handle addressing modes and branch instructions for
|
||||
high compatibility emulation
|
||||
|
||||
@author Bradford W. Mott
|
||||
@version $Id$
|
||||
*/
|
||||
|
||||
#ifndef NOTSAMEPAGE
|
||||
#define NOTSAMEPAGE(_addr1, _addr2) (((_addr1) ^ (_addr2)) & 0xff00)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// Copyright (c) 1995-2005 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$
|
||||
// $Id: M6502.ins 1724 2009-05-13 13:55:40Z stephena $
|
||||
//============================================================================
|
||||
|
||||
/**
|
||||
Code and cases to emulate each of the 6502 instruction
|
||||
Code and cases to emulate each of the 6502 instructions.
|
||||
|
||||
Recompile with the following:
|
||||
'm4 M6502[Hi|Low].m4 M6502.m4 > M6502[Hi|Low].ins'
|
||||
'm4 M6502.m4 > M6502.ins'
|
||||
|
||||
@author Bradford W. Mott
|
||||
@version $Id$
|
||||
@version $Id: M6502.m4 1724 2009-05-13 13:55:40Z stephena $
|
||||
*/
|
||||
|
||||
#ifndef NOTSAMEPAGE
|
||||
|
@ -254,6 +153,77 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -17,10 +17,10 @@
|
|||
//============================================================================
|
||||
|
||||
/**
|
||||
Code and cases to emulate each of the 6502 instruction
|
||||
Code and cases to emulate each of the 6502 instructions.
|
||||
|
||||
Recompile with the following:
|
||||
'm4 M6502[Hi|Low].m4 M6502.m4 > M6502[Hi|Low].ins'
|
||||
'm4 M6502.m4 > M6502.ins'
|
||||
|
||||
@author Bradford W. Mott
|
||||
@version $Id$
|
||||
|
@ -30,6 +30,290 @@
|
|||
#define NOTSAMEPAGE(_addr1, _addr2) (((_addr1) ^ (_addr2)) & 0xff00)
|
||||
#endif
|
||||
|
||||
define(M6502_IMPLIED, `{
|
||||
peek(PC);
|
||||
}')
|
||||
|
||||
define(M6502_IMMEDIATE_READ, `{
|
||||
operand = peek(PC++);
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTE_READ, `{
|
||||
uInt16 address = peek(PC++);
|
||||
address |= ((uInt16)peek(PC++) << 8);
|
||||
operand = peek(address);
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTE_WRITE, `{
|
||||
operandAddress = peek(PC++);
|
||||
operandAddress |= ((uInt16)peek(PC++) << 8);
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTE_READMODIFYWRITE, `{
|
||||
operandAddress = peek(PC++);
|
||||
operandAddress |= ((uInt16)peek(PC++) << 8);
|
||||
operand = peek(operandAddress);
|
||||
poke(operandAddress, operand);
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTEX_READ, `{
|
||||
uInt16 low = peek(PC++);
|
||||
uInt16 high = ((uInt16)peek(PC++) << 8);
|
||||
operand = peek(high | (uInt8)(low + X));
|
||||
if((low + X) > 0xFF)
|
||||
operand = peek((high | low) + X);
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTEX_WRITE, `{
|
||||
uInt16 low = peek(PC++);
|
||||
uInt16 high = ((uInt16)peek(PC++) << 8);
|
||||
peek(high | (uInt8)(low + X));
|
||||
operandAddress = (high | low) + X;
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTEX_READMODIFYWRITE, `{
|
||||
uInt16 low = peek(PC++);
|
||||
uInt16 high = ((uInt16)peek(PC++) << 8);
|
||||
peek(high | (uInt8)(low + X));
|
||||
operandAddress = (high | low) + X;
|
||||
operand = peek(operandAddress);
|
||||
poke(operandAddress, operand);
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTEY_READ, `{
|
||||
uInt16 low = peek(PC++);
|
||||
uInt16 high = ((uInt16)peek(PC++) << 8);
|
||||
operand = peek(high | (uInt8)(low + Y));
|
||||
if((low + Y) > 0xFF)
|
||||
operand = peek((high | low) + Y);
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTEY_WRITE, `{
|
||||
uInt16 low = peek(PC++);
|
||||
uInt16 high = ((uInt16)peek(PC++) << 8);
|
||||
peek(high | (uInt8)(low + Y));
|
||||
operandAddress = (high | low) + Y;
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTEY_READMODIFYWRITE, `{
|
||||
uInt16 low = peek(PC++);
|
||||
uInt16 high = ((uInt16)peek(PC++) << 8);
|
||||
peek(high | (uInt8)(low + Y));
|
||||
operandAddress = (high | low) + Y;
|
||||
operand = peek(operandAddress);
|
||||
poke(operandAddress, operand);
|
||||
}')
|
||||
|
||||
define(M6502_ZERO_READ, `{
|
||||
operand = peek(peek(PC++));
|
||||
}')
|
||||
|
||||
define(M6502_ZERO_WRITE, `{
|
||||
operandAddress = peek(PC++);
|
||||
}')
|
||||
|
||||
define(M6502_ZERO_READMODIFYWRITE, `{
|
||||
operandAddress = peek(PC++);
|
||||
operand = peek(operandAddress);
|
||||
poke(operandAddress, operand);
|
||||
}')
|
||||
|
||||
define(M6502_ZEROX_READ, `{
|
||||
uInt8 address = peek(PC++);
|
||||
peek(address);
|
||||
address += X;
|
||||
operand = peek(address);
|
||||
}')
|
||||
|
||||
define(M6502_ZEROX_WRITE, `{
|
||||
operandAddress = peek(PC++);
|
||||
peek(operandAddress);
|
||||
operandAddress = (operandAddress + X) & 0xFF;
|
||||
}')
|
||||
|
||||
define(M6502_ZEROX_READMODIFYWRITE, `{
|
||||
operandAddress = peek(PC++);
|
||||
peek(operandAddress);
|
||||
operandAddress = (operandAddress + X) & 0xFF;
|
||||
operand = peek(operandAddress);
|
||||
poke(operandAddress, operand);
|
||||
}')
|
||||
|
||||
define(M6502_ZEROY_READ, `{
|
||||
uInt8 address = peek(PC++);
|
||||
peek(address);
|
||||
address += Y;
|
||||
operand = peek(address);
|
||||
}')
|
||||
|
||||
define(M6502_ZEROY_WRITE, `{
|
||||
operandAddress = peek(PC++);
|
||||
peek(operandAddress);
|
||||
operandAddress = (operandAddress + Y) & 0xFF;
|
||||
}')
|
||||
|
||||
define(M6502_ZEROY_READMODIFYWRITE, `{
|
||||
operandAddress = peek(PC++);
|
||||
peek(operandAddress);
|
||||
operandAddress = (operandAddress + Y) & 0xFF;
|
||||
operand = peek(operandAddress);
|
||||
poke(operandAddress, operand);
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECT, `{
|
||||
uInt16 addr = peek(PC++);
|
||||
addr |= ((uInt16)peek(PC++) << 8);
|
||||
|
||||
// Simulate the error in the indirect addressing mode!
|
||||
uInt16 high = NOTSAMEPAGE(addr, addr + 1) ? (addr & 0xff00) : (addr + 1);
|
||||
|
||||
operandAddress = peek(addr);
|
||||
operandAddress |= ((uInt16)peek(high) << 8);
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECTX_READ, `{
|
||||
uInt8 pointer = peek(PC++);
|
||||
peek(pointer);
|
||||
pointer += X;
|
||||
uInt16 address = peek(pointer++);
|
||||
address |= ((uInt16)peek(pointer) << 8);
|
||||
operand = peek(address);
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECTX_WRITE, `{
|
||||
uInt8 pointer = peek(PC++);
|
||||
peek(pointer);
|
||||
pointer += X;
|
||||
operandAddress = peek(pointer++);
|
||||
operandAddress |= ((uInt16)peek(pointer) << 8);
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECTX_READMODIFYWRITE, `{
|
||||
uInt8 pointer = peek(PC++);
|
||||
peek(pointer);
|
||||
pointer += X;
|
||||
operandAddress = peek(pointer++);
|
||||
operandAddress |= ((uInt16)peek(pointer) << 8);
|
||||
operand = peek(operandAddress);
|
||||
poke(operandAddress, operand);
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECTY_READ, `{
|
||||
uInt8 pointer = peek(PC++);
|
||||
uInt16 low = peek(pointer++);
|
||||
uInt16 high = ((uInt16)peek(pointer) << 8);
|
||||
operand = peek(high | (uInt8)(low + Y));
|
||||
if((low + Y) > 0xFF)
|
||||
operand = peek((high | low) + Y);
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECTY_WRITE, `{
|
||||
uInt8 pointer = peek(PC++);
|
||||
uInt16 low = peek(pointer++);
|
||||
uInt16 high = ((uInt16)peek(pointer) << 8);
|
||||
peek(high | (uInt8)(low + Y));
|
||||
operandAddress = (high | low) + Y;
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECTY_READMODIFYWRITE, `{
|
||||
uInt8 pointer = peek(PC++);
|
||||
uInt16 low = peek(pointer++);
|
||||
uInt16 high = ((uInt16)peek(pointer) << 8);
|
||||
peek(high | (uInt8)(low + Y));
|
||||
operandAddress = (high | low) + Y;
|
||||
operand = peek(operandAddress);
|
||||
poke(operandAddress, operand);
|
||||
}')
|
||||
|
||||
|
||||
define(M6502_BCC, `{
|
||||
if(!C)
|
||||
{
|
||||
peek(PC);
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
if(NOTSAMEPAGE(PC, address))
|
||||
peek((PC & 0xFF00) | (address & 0x00FF));
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BCS, `{
|
||||
if(C)
|
||||
{
|
||||
peek(PC);
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
if(NOTSAMEPAGE(PC, address))
|
||||
peek((PC & 0xFF00) | (address & 0x00FF));
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BEQ, `{
|
||||
if(!notZ)
|
||||
{
|
||||
peek(PC);
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
if(NOTSAMEPAGE(PC, address))
|
||||
peek((PC & 0xFF00) | (address & 0x00FF));
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BMI, `{
|
||||
if(N)
|
||||
{
|
||||
peek(PC);
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
if(NOTSAMEPAGE(PC, address))
|
||||
peek((PC & 0xFF00) | (address & 0x00FF));
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BNE, `{
|
||||
if(notZ)
|
||||
{
|
||||
peek(PC);
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
if(NOTSAMEPAGE(PC, address))
|
||||
peek((PC & 0xFF00) | (address & 0x00FF));
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BPL, `{
|
||||
if(!N)
|
||||
{
|
||||
peek(PC);
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
if(NOTSAMEPAGE(PC, address))
|
||||
peek((PC & 0xFF00) | (address & 0x00FF));
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BVC, `{
|
||||
if(!V)
|
||||
{
|
||||
peek(PC);
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
if(NOTSAMEPAGE(PC, address))
|
||||
peek((PC & 0xFF00) | (address & 0x00FF));
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BVS, `{
|
||||
if(V)
|
||||
{
|
||||
peek(PC);
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
if(NOTSAMEPAGE(PC, address))
|
||||
peek((PC & 0xFF00) | (address & 0x00FF));
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_ADC, `{
|
||||
if(!D)
|
||||
{
|
||||
|
|
|
@ -1,332 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// 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$
|
||||
//============================================================================
|
||||
|
||||
//#define DEBUG_OUTPUT
|
||||
|
||||
#include "M6502Hi.hxx"
|
||||
#include "Serializer.hxx"
|
||||
#include "Deserializer.hxx"
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
#include "Debugger.hxx"
|
||||
#endif
|
||||
|
||||
#define debugStream cout
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
M6502High::M6502High(uInt32 systemCyclesPerProcessorCycle)
|
||||
: M6502(systemCyclesPerProcessorCycle)
|
||||
{
|
||||
myNumberOfDistinctAccesses = 0;
|
||||
myLastAddress = 0;
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
myJustHitTrapFlag = false;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
debugStream << "( Fm Ln Cyc Clk) ( P0 P1 M0 M1 BL) "
|
||||
<< "flags A X Y SP Code Disasm" << endl
|
||||
<< endl;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
M6502High::~M6502High()
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
inline uInt8 M6502High::peek(uInt16 address)
|
||||
{
|
||||
if(address != myLastAddress)
|
||||
{
|
||||
myNumberOfDistinctAccesses++;
|
||||
myLastAddress = address;
|
||||
}
|
||||
mySystem->incrementCycles(mySystemCyclesPerProcessorCycle);
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
if(myReadTraps != NULL && myReadTraps->isSet(address))
|
||||
{
|
||||
myJustHitTrapFlag = true;
|
||||
myHitTrapInfo.message = "RTrap: ";
|
||||
myHitTrapInfo.address = address;
|
||||
}
|
||||
#endif
|
||||
|
||||
uInt8 result = mySystem->peek(address);
|
||||
myLastAccessWasRead = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
inline void M6502High::poke(uInt16 address, uInt8 value)
|
||||
{
|
||||
if(address != myLastAddress)
|
||||
{
|
||||
myNumberOfDistinctAccesses++;
|
||||
myLastAddress = address;
|
||||
}
|
||||
mySystem->incrementCycles(mySystemCyclesPerProcessorCycle);
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
if(myWriteTraps != NULL && myWriteTraps->isSet(address))
|
||||
{
|
||||
myJustHitTrapFlag = true;
|
||||
myHitTrapInfo.message = "WTrap: ";
|
||||
myHitTrapInfo.address = address;
|
||||
}
|
||||
#endif
|
||||
|
||||
mySystem->poke(address, value);
|
||||
myLastAccessWasRead = false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool M6502High::execute(uInt32 number)
|
||||
{
|
||||
// Clear all of the execution status bits except for the fatal error bit
|
||||
myExecutionStatus &= FatalErrorBit;
|
||||
|
||||
// Loop until execution is stopped or a fatal error occurs
|
||||
for(;;)
|
||||
{
|
||||
for(; !myExecutionStatus && (number != 0); --number)
|
||||
{
|
||||
uInt16 operandAddress = 0;
|
||||
uInt8 operand = 0;
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
if(myJustHitTrapFlag)
|
||||
{
|
||||
if(myDebugger->start(myHitTrapInfo.message, myHitTrapInfo.address))
|
||||
{
|
||||
myJustHitTrapFlag = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(myBreakPoints != NULL)
|
||||
{
|
||||
if(myBreakPoints->isSet(PC))
|
||||
{
|
||||
if(myDebugger->start("BP: ", PC))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int cond = evalCondBreaks();
|
||||
if(cond > -1)
|
||||
{
|
||||
string buf = "CBP: " + myBreakCondNames[cond];
|
||||
if(myDebugger->start(buf))
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Fetch instruction at the program counter
|
||||
IR = peek(PC++);
|
||||
|
||||
#ifdef DEBUG_OUTPUT
|
||||
debugStream << ::hex << setw(2) << (int)A << " "
|
||||
<< ::hex << setw(2) << (int)X << " "
|
||||
<< ::hex << setw(2) << (int)Y << " "
|
||||
<< ::hex << setw(2) << (int)SP << " "
|
||||
<< setw(4) << (PC-1) << ": "
|
||||
<< setw(2) << (int)IR << " "
|
||||
// << "<" << ourAddressingModeTable[IR] << " ";
|
||||
// debugStream << hex << setw(4) << operandAddress << " ";
|
||||
<< setw(3) << ourInstructionMnemonicTable[IR]
|
||||
|
||||
// debugStream << "PS=" << ::hex << setw(2) << (int)PS() << " ";
|
||||
|
||||
// debugStream << "Cyc=" << dec << mySystem->cycles();
|
||||
<< endl;
|
||||
#endif
|
||||
|
||||
// Call code to execute the instruction
|
||||
switch(IR)
|
||||
{
|
||||
// 6502 instruction emulation is generated by an M4 macro file
|
||||
#include "M6502Hi.ins"
|
||||
|
||||
default:
|
||||
// Oops, illegal instruction executed so set fatal error flag
|
||||
myExecutionStatus |= FatalErrorBit;
|
||||
}
|
||||
|
||||
myTotalInstructionCount++;
|
||||
}
|
||||
|
||||
// See if we need to handle an interrupt
|
||||
if((myExecutionStatus & MaskableInterruptBit) ||
|
||||
(myExecutionStatus & NonmaskableInterruptBit))
|
||||
{
|
||||
// Yes, so handle the interrupt
|
||||
interruptHandler();
|
||||
}
|
||||
|
||||
// See if execution has been stopped
|
||||
if(myExecutionStatus & StopExecutionBit)
|
||||
{
|
||||
// Yes, so answer that everything finished fine
|
||||
return true;
|
||||
}
|
||||
|
||||
// See if a fatal error has occured
|
||||
if(myExecutionStatus & FatalErrorBit)
|
||||
{
|
||||
// Yes, so answer that something when wrong
|
||||
return false;
|
||||
}
|
||||
|
||||
// See if we've executed the specified number of instructions
|
||||
if(number == 0)
|
||||
{
|
||||
// Yes, so answer that everything finished fine
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void M6502High::interruptHandler()
|
||||
{
|
||||
// Handle the interrupt
|
||||
if((myExecutionStatus & MaskableInterruptBit) && !I)
|
||||
{
|
||||
mySystem->incrementCycles(7 * mySystemCyclesPerProcessorCycle);
|
||||
mySystem->poke(0x0100 + SP--, (PC - 1) >> 8);
|
||||
mySystem->poke(0x0100 + SP--, (PC - 1) & 0x00ff);
|
||||
mySystem->poke(0x0100 + SP--, PS() & (~0x10));
|
||||
D = false;
|
||||
I = true;
|
||||
PC = (uInt16)mySystem->peek(0xFFFE) | ((uInt16)mySystem->peek(0xFFFF) << 8);
|
||||
}
|
||||
else if(myExecutionStatus & NonmaskableInterruptBit)
|
||||
{
|
||||
mySystem->incrementCycles(7 * mySystemCyclesPerProcessorCycle);
|
||||
mySystem->poke(0x0100 + SP--, (PC - 1) >> 8);
|
||||
mySystem->poke(0x0100 + SP--, (PC - 1) & 0x00ff);
|
||||
mySystem->poke(0x0100 + SP--, PS() & (~0x10));
|
||||
D = false;
|
||||
PC = (uInt16)mySystem->peek(0xFFFA) | ((uInt16)mySystem->peek(0xFFFB) << 8);
|
||||
}
|
||||
|
||||
// Clear the interrupt bits in myExecutionStatus
|
||||
myExecutionStatus &= ~(MaskableInterruptBit | NonmaskableInterruptBit);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool M6502High::save(Serializer& out)
|
||||
{
|
||||
string CPU = name();
|
||||
|
||||
try
|
||||
{
|
||||
out.putString(CPU);
|
||||
|
||||
out.putByte((char)A); // Accumulator
|
||||
out.putByte((char)X); // X index register
|
||||
out.putByte((char)Y); // Y index register
|
||||
out.putByte((char)SP); // Stack Pointer
|
||||
out.putByte((char)IR); // Instruction register
|
||||
out.putInt(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((char)myExecutionStatus);
|
||||
|
||||
// Indicates the number of distinct memory accesses
|
||||
out.putInt(myNumberOfDistinctAccesses);
|
||||
// Indicates the last address which was accessed
|
||||
out.putInt(myLastAddress);
|
||||
|
||||
}
|
||||
catch(char *msg)
|
||||
{
|
||||
cerr << msg << endl;
|
||||
return false;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cerr << "Unknown error in save state for " << CPU << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool M6502High::load(Deserializer& in)
|
||||
{
|
||||
string CPU = name();
|
||||
|
||||
try
|
||||
{
|
||||
if(in.getString() != CPU)
|
||||
return false;
|
||||
|
||||
A = (uInt8) in.getByte(); // Accumulator
|
||||
X = (uInt8) in.getByte(); // X index register
|
||||
Y = (uInt8) in.getByte(); // Y index register
|
||||
SP = (uInt8) in.getByte(); // Stack Pointer
|
||||
IR = (uInt8) in.getByte(); // Instruction register
|
||||
PC = (uInt16) in.getInt(); // Program Counter
|
||||
|
||||
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
|
||||
|
||||
myExecutionStatus = (uInt8) in.getByte();
|
||||
|
||||
// Indicates the number of distinct memory accesses
|
||||
myNumberOfDistinctAccesses = (uInt32) in.getInt();
|
||||
// Indicates the last address which was accessed
|
||||
myLastAddress = (uInt16) in.getInt();
|
||||
}
|
||||
catch(char *msg)
|
||||
{
|
||||
cerr << msg << endl;
|
||||
return false;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cerr << "Unknown error in load state for " << CPU << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const char* M6502High::name() const
|
||||
{
|
||||
return "M6502High";
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// 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 M6502HIGH_HXX
|
||||
#define M6502HIGH_HXX
|
||||
|
||||
class M6502High;
|
||||
class Serializer;
|
||||
class Deserializer;
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "M6502.hxx"
|
||||
|
||||
/**
|
||||
This class provides a high compatibility 6502 microprocessor emulator.
|
||||
The memory accesses and cycle counts it generates are valid at the
|
||||
sub-instruction level and "false" reads are generated (such as the ones
|
||||
produced by the Indirect,X addressing when it crosses a page boundary).
|
||||
This provides provides better compatibility for hardware that has side
|
||||
effects and for games which are very time sensitive.
|
||||
|
||||
@author Bradford W. Mott
|
||||
@version $Id$
|
||||
*/
|
||||
class M6502High : public M6502
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Create a new high compatibility 6502 microprocessor with the
|
||||
specified cycle multiplier.
|
||||
|
||||
@param systemCyclesPerProcessorCycle The cycle multiplier
|
||||
*/
|
||||
M6502High(uInt32 systemCyclesPerProcessorCycle);
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
virtual ~M6502High();
|
||||
|
||||
public:
|
||||
/**
|
||||
Execute instructions until the specified number of instructions
|
||||
is executed, someone stops execution, or an error occurs. Answers
|
||||
true iff execution stops normally.
|
||||
|
||||
@param number Indicates the number of instructions to execute
|
||||
@return true iff execution stops normally
|
||||
*/
|
||||
virtual bool execute(uInt32 number);
|
||||
|
||||
/**
|
||||
Saves the current state of this device to the given Serializer.
|
||||
|
||||
@param out The serializer device to save to.
|
||||
@return The result of the save. True on success, false on failure.
|
||||
*/
|
||||
virtual bool save(Serializer& out);
|
||||
|
||||
/**
|
||||
Loads the current state of this device from the given Deserializer.
|
||||
|
||||
@param in The deserializer device to load from.
|
||||
@return The result of the load. True on success, false on failure.
|
||||
*/
|
||||
virtual bool load(Deserializer& in);
|
||||
|
||||
/**
|
||||
Get a null terminated string which is the processors's name (i.e. "M6532")
|
||||
|
||||
@return The name of the device
|
||||
*/
|
||||
virtual const char* name() const;
|
||||
|
||||
public:
|
||||
/**
|
||||
Get the number of memory accesses to distinct memory locations
|
||||
|
||||
@return The number of memory accesses to distinct memory locations
|
||||
*/
|
||||
uInt32 distinctAccesses() const
|
||||
{
|
||||
return myNumberOfDistinctAccesses;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
Called after an interrupt has be requested using irq() or nmi()
|
||||
*/
|
||||
void interruptHandler();
|
||||
|
||||
protected:
|
||||
/*
|
||||
Get the byte at the specified address and update the cycle
|
||||
count
|
||||
|
||||
@return The byte at the specified address
|
||||
*/
|
||||
inline uInt8 peek(uInt16 address);
|
||||
|
||||
/**
|
||||
Change the byte at the specified address to the given value and
|
||||
update the cycle count
|
||||
|
||||
@param address The address where the value should be stored
|
||||
@param value The value to be stored at the address
|
||||
*/
|
||||
inline void poke(uInt16 address, uInt8 value);
|
||||
|
||||
private:
|
||||
// Indicates the numer of distinct memory accesses
|
||||
uInt32 myNumberOfDistinctAccesses;
|
||||
|
||||
// Indicates the last address which was accessed
|
||||
uInt16 myLastAddress;
|
||||
};
|
||||
#endif
|
||||
|
|
@ -1,314 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// Copyright (c) 1995-2005 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$
|
||||
//============================================================================
|
||||
|
||||
/**
|
||||
Code to handle addressing modes and branch instructions for
|
||||
high compatibility emulation
|
||||
|
||||
@author Bradford W. Mott
|
||||
@version $Id$
|
||||
*/
|
||||
|
||||
#ifndef NOTSAMEPAGE
|
||||
#define NOTSAMEPAGE(_addr1, _addr2) (((_addr1) ^ (_addr2)) & 0xff00)
|
||||
#endif
|
||||
|
||||
define(M6502_IMPLIED, `{
|
||||
peek(PC);
|
||||
}')
|
||||
|
||||
define(M6502_IMMEDIATE_READ, `{
|
||||
operand = peek(PC++);
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTE_READ, `{
|
||||
uInt16 address = peek(PC++);
|
||||
address |= ((uInt16)peek(PC++) << 8);
|
||||
operand = peek(address);
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTE_WRITE, `{
|
||||
operandAddress = peek(PC++);
|
||||
operandAddress |= ((uInt16)peek(PC++) << 8);
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTE_READMODIFYWRITE, `{
|
||||
operandAddress = peek(PC++);
|
||||
operandAddress |= ((uInt16)peek(PC++) << 8);
|
||||
operand = peek(operandAddress);
|
||||
poke(operandAddress, operand);
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTEX_READ, `{
|
||||
uInt16 low = peek(PC++);
|
||||
uInt16 high = ((uInt16)peek(PC++) << 8);
|
||||
operand = peek(high | (uInt8)(low + X));
|
||||
if((low + X) > 0xFF)
|
||||
operand = peek((high | low) + X);
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTEX_WRITE, `{
|
||||
uInt16 low = peek(PC++);
|
||||
uInt16 high = ((uInt16)peek(PC++) << 8);
|
||||
peek(high | (uInt8)(low + X));
|
||||
operandAddress = (high | low) + X;
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTEX_READMODIFYWRITE, `{
|
||||
uInt16 low = peek(PC++);
|
||||
uInt16 high = ((uInt16)peek(PC++) << 8);
|
||||
peek(high | (uInt8)(low + X));
|
||||
operandAddress = (high | low) + X;
|
||||
operand = peek(operandAddress);
|
||||
poke(operandAddress, operand);
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTEY_READ, `{
|
||||
uInt16 low = peek(PC++);
|
||||
uInt16 high = ((uInt16)peek(PC++) << 8);
|
||||
operand = peek(high | (uInt8)(low + Y));
|
||||
if((low + Y) > 0xFF)
|
||||
operand = peek((high | low) + Y);
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTEY_WRITE, `{
|
||||
uInt16 low = peek(PC++);
|
||||
uInt16 high = ((uInt16)peek(PC++) << 8);
|
||||
peek(high | (uInt8)(low + Y));
|
||||
operandAddress = (high | low) + Y;
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTEY_READMODIFYWRITE, `{
|
||||
uInt16 low = peek(PC++);
|
||||
uInt16 high = ((uInt16)peek(PC++) << 8);
|
||||
peek(high | (uInt8)(low + Y));
|
||||
operandAddress = (high | low) + Y;
|
||||
operand = peek(operandAddress);
|
||||
poke(operandAddress, operand);
|
||||
}')
|
||||
|
||||
define(M6502_ZERO_READ, `{
|
||||
operand = peek(peek(PC++));
|
||||
}')
|
||||
|
||||
define(M6502_ZERO_WRITE, `{
|
||||
operandAddress = peek(PC++);
|
||||
}')
|
||||
|
||||
define(M6502_ZERO_READMODIFYWRITE, `{
|
||||
operandAddress = peek(PC++);
|
||||
operand = peek(operandAddress);
|
||||
poke(operandAddress, operand);
|
||||
}')
|
||||
|
||||
define(M6502_ZEROX_READ, `{
|
||||
uInt8 address = peek(PC++);
|
||||
peek(address);
|
||||
address += X;
|
||||
operand = peek(address);
|
||||
}')
|
||||
|
||||
define(M6502_ZEROX_WRITE, `{
|
||||
operandAddress = peek(PC++);
|
||||
peek(operandAddress);
|
||||
operandAddress = (operandAddress + X) & 0xFF;
|
||||
}')
|
||||
|
||||
define(M6502_ZEROX_READMODIFYWRITE, `{
|
||||
operandAddress = peek(PC++);
|
||||
peek(operandAddress);
|
||||
operandAddress = (operandAddress + X) & 0xFF;
|
||||
operand = peek(operandAddress);
|
||||
poke(operandAddress, operand);
|
||||
}')
|
||||
|
||||
define(M6502_ZEROY_READ, `{
|
||||
uInt8 address = peek(PC++);
|
||||
peek(address);
|
||||
address += Y;
|
||||
operand = peek(address);
|
||||
}')
|
||||
|
||||
define(M6502_ZEROY_WRITE, `{
|
||||
operandAddress = peek(PC++);
|
||||
peek(operandAddress);
|
||||
operandAddress = (operandAddress + Y) & 0xFF;
|
||||
}')
|
||||
|
||||
define(M6502_ZEROY_READMODIFYWRITE, `{
|
||||
operandAddress = peek(PC++);
|
||||
peek(operandAddress);
|
||||
operandAddress = (operandAddress + Y) & 0xFF;
|
||||
operand = peek(operandAddress);
|
||||
poke(operandAddress, operand);
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECT, `{
|
||||
uInt16 addr = peek(PC++);
|
||||
addr |= ((uInt16)peek(PC++) << 8);
|
||||
|
||||
// Simulate the error in the indirect addressing mode!
|
||||
uInt16 high = NOTSAMEPAGE(addr, addr + 1) ? (addr & 0xff00) : (addr + 1);
|
||||
|
||||
operandAddress = peek(addr);
|
||||
operandAddress |= ((uInt16)peek(high) << 8);
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECTX_READ, `{
|
||||
uInt8 pointer = peek(PC++);
|
||||
peek(pointer);
|
||||
pointer += X;
|
||||
uInt16 address = peek(pointer++);
|
||||
address |= ((uInt16)peek(pointer) << 8);
|
||||
operand = peek(address);
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECTX_WRITE, `{
|
||||
uInt8 pointer = peek(PC++);
|
||||
peek(pointer);
|
||||
pointer += X;
|
||||
operandAddress = peek(pointer++);
|
||||
operandAddress |= ((uInt16)peek(pointer) << 8);
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECTX_READMODIFYWRITE, `{
|
||||
uInt8 pointer = peek(PC++);
|
||||
peek(pointer);
|
||||
pointer += X;
|
||||
operandAddress = peek(pointer++);
|
||||
operandAddress |= ((uInt16)peek(pointer) << 8);
|
||||
operand = peek(operandAddress);
|
||||
poke(operandAddress, operand);
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECTY_READ, `{
|
||||
uInt8 pointer = peek(PC++);
|
||||
uInt16 low = peek(pointer++);
|
||||
uInt16 high = ((uInt16)peek(pointer) << 8);
|
||||
operand = peek(high | (uInt8)(low + Y));
|
||||
if((low + Y) > 0xFF)
|
||||
operand = peek((high | low) + Y);
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECTY_WRITE, `{
|
||||
uInt8 pointer = peek(PC++);
|
||||
uInt16 low = peek(pointer++);
|
||||
uInt16 high = ((uInt16)peek(pointer) << 8);
|
||||
peek(high | (uInt8)(low + Y));
|
||||
operandAddress = (high | low) + Y;
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECTY_READMODIFYWRITE, `{
|
||||
uInt8 pointer = peek(PC++);
|
||||
uInt16 low = peek(pointer++);
|
||||
uInt16 high = ((uInt16)peek(pointer) << 8);
|
||||
peek(high | (uInt8)(low + Y));
|
||||
operandAddress = (high | low) + Y;
|
||||
operand = peek(operandAddress);
|
||||
poke(operandAddress, operand);
|
||||
}')
|
||||
|
||||
|
||||
define(M6502_BCC, `{
|
||||
if(!C)
|
||||
{
|
||||
peek(PC);
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
if(NOTSAMEPAGE(PC, address))
|
||||
peek((PC & 0xFF00) | (address & 0x00FF));
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BCS, `{
|
||||
if(C)
|
||||
{
|
||||
peek(PC);
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
if(NOTSAMEPAGE(PC, address))
|
||||
peek((PC & 0xFF00) | (address & 0x00FF));
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BEQ, `{
|
||||
if(!notZ)
|
||||
{
|
||||
peek(PC);
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
if(NOTSAMEPAGE(PC, address))
|
||||
peek((PC & 0xFF00) | (address & 0x00FF));
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BMI, `{
|
||||
if(N)
|
||||
{
|
||||
peek(PC);
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
if(NOTSAMEPAGE(PC, address))
|
||||
peek((PC & 0xFF00) | (address & 0x00FF));
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BNE, `{
|
||||
if(notZ)
|
||||
{
|
||||
peek(PC);
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
if(NOTSAMEPAGE(PC, address))
|
||||
peek((PC & 0xFF00) | (address & 0x00FF));
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BPL, `{
|
||||
if(!N)
|
||||
{
|
||||
peek(PC);
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
if(NOTSAMEPAGE(PC, address))
|
||||
peek((PC & 0xFF00) | (address & 0x00FF));
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BVC, `{
|
||||
if(!V)
|
||||
{
|
||||
peek(PC);
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
if(NOTSAMEPAGE(PC, address))
|
||||
peek((PC & 0xFF00) | (address & 0x00FF));
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BVS, `{
|
||||
if(V)
|
||||
{
|
||||
peek(PC);
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
if(NOTSAMEPAGE(PC, address))
|
||||
peek((PC & 0xFF00) | (address & 0x00FF));
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
|
@ -1,305 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// Copyright (c) 1995-2009 by Bradford W. Mott and the Stella team
|
||||
//
|
||||
// See the file "license" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id$
|
||||
//============================================================================
|
||||
|
||||
#include "M6502Low.hxx"
|
||||
#include "Serializer.hxx"
|
||||
#include "Deserializer.hxx"
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
#include "Debugger.hxx"
|
||||
#endif
|
||||
|
||||
#define debugStream cout
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
M6502Low::M6502Low(uInt32 systemCyclesPerProcessorCycle)
|
||||
: M6502(systemCyclesPerProcessorCycle)
|
||||
{
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
myJustHitTrapFlag = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
M6502Low::~M6502Low()
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
inline uInt8 M6502Low::peek(uInt16 address)
|
||||
{
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
if(myReadTraps != NULL && myReadTraps->isSet(address))
|
||||
{
|
||||
myJustHitTrapFlag = true;
|
||||
myHitTrapInfo.message = "RTrap: ";
|
||||
myHitTrapInfo.address = address;
|
||||
}
|
||||
#endif
|
||||
|
||||
uInt8 result = mySystem->peek(address);
|
||||
myLastAccessWasRead = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
inline void M6502Low::poke(uInt16 address, uInt8 value)
|
||||
{
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
if(myWriteTraps != NULL && myWriteTraps->isSet(address))
|
||||
{
|
||||
myJustHitTrapFlag = true;
|
||||
myHitTrapInfo.message = "WTrap: ";
|
||||
myHitTrapInfo.address = address;
|
||||
}
|
||||
#endif
|
||||
|
||||
mySystem->poke(address, value);
|
||||
myLastAccessWasRead = false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool M6502Low::execute(uInt32 number)
|
||||
{
|
||||
// Clear all of the execution status bits except for the fatal error bit
|
||||
myExecutionStatus &= FatalErrorBit;
|
||||
|
||||
// Loop until execution is stopped or a fatal error occurs
|
||||
for(;;)
|
||||
{
|
||||
for(; !myExecutionStatus && (number != 0); --number)
|
||||
{
|
||||
uInt16 operandAddress = 0;
|
||||
uInt8 operand = 0;
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
if(myJustHitTrapFlag)
|
||||
{
|
||||
if(myDebugger->start(myHitTrapInfo.message, myHitTrapInfo.address))
|
||||
{
|
||||
myJustHitTrapFlag = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(myBreakPoints != NULL)
|
||||
{
|
||||
if(myBreakPoints->isSet(PC))
|
||||
{
|
||||
if(myDebugger->start("BP: ", PC))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int cond = evalCondBreaks();
|
||||
if(cond > -1)
|
||||
{
|
||||
string buf = "CBP: " + myBreakCondNames[cond];
|
||||
if(myDebugger->start(buf))
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
debugStream << "PC=" << hex << setw(4) << PC << " ";
|
||||
#endif
|
||||
|
||||
// Fetch instruction at the program counter
|
||||
IR = peek(PC++);
|
||||
|
||||
#ifdef DEBUG
|
||||
debugStream << "IR=" << hex << setw(2) << (int)IR << " ";
|
||||
debugStream << "<" << ourAddressingModeTable[IR] << " ";
|
||||
#endif
|
||||
|
||||
// Update system cycles
|
||||
mySystem->incrementCycles(myInstructionSystemCycleTable[IR]);
|
||||
|
||||
// Call code to execute the instruction
|
||||
switch(IR)
|
||||
{
|
||||
// 6502 instruction emulation is generated by an M4 macro file
|
||||
#include "M6502Low.ins"
|
||||
|
||||
default:
|
||||
// Oops, illegal instruction executed so set fatal error flag
|
||||
myExecutionStatus |= FatalErrorBit;
|
||||
cerr << "Illegal Instruction! " << hex << (int) IR << endl;
|
||||
}
|
||||
|
||||
myTotalInstructionCount++;
|
||||
|
||||
#ifdef DEBUG
|
||||
debugStream << hex << setw(4) << operandAddress << " ";
|
||||
debugStream << setw(4) << ourInstructionMnemonicTable[IR];
|
||||
debugStream << "> ";
|
||||
debugStream << "A=" << ::hex << setw(2) << (int)A << " ";
|
||||
debugStream << "X=" << ::hex << setw(2) << (int)X << " ";
|
||||
debugStream << "Y=" << ::hex << setw(2) << (int)Y << " ";
|
||||
debugStream << "PS=" << ::hex << setw(2) << (int)PS() << " ";
|
||||
debugStream << "SP=" << ::hex << setw(2) << (int)SP << " ";
|
||||
debugStream << "Cyc=" << dec << mySystem->cycles();
|
||||
debugStream << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
// See if we need to handle an interrupt
|
||||
if((myExecutionStatus & MaskableInterruptBit) ||
|
||||
(myExecutionStatus & NonmaskableInterruptBit))
|
||||
{
|
||||
// Yes, so handle the interrupt
|
||||
interruptHandler();
|
||||
}
|
||||
|
||||
// See if execution has been stopped
|
||||
if(myExecutionStatus & StopExecutionBit)
|
||||
{
|
||||
// Yes, so answer that everything finished fine
|
||||
return true;
|
||||
}
|
||||
|
||||
// See if a fatal error has occured
|
||||
if(myExecutionStatus & FatalErrorBit)
|
||||
{
|
||||
// Yes, so answer that something when wrong
|
||||
return false;
|
||||
}
|
||||
|
||||
// See if we've executed the specified number of instructions
|
||||
if(number == 0)
|
||||
{
|
||||
// Yes, so answer that everything finished fine
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void M6502Low::interruptHandler()
|
||||
{
|
||||
// Handle the interrupt
|
||||
if((myExecutionStatus & MaskableInterruptBit) && !I)
|
||||
{
|
||||
mySystem->incrementCycles(7 * mySystemCyclesPerProcessorCycle);
|
||||
mySystem->poke(0x0100 + SP--, (PC - 1) >> 8);
|
||||
mySystem->poke(0x0100 + SP--, (PC - 1) & 0x00ff);
|
||||
mySystem->poke(0x0100 + SP--, PS() & (~0x10));
|
||||
D = false;
|
||||
I = true;
|
||||
PC = (uInt16)mySystem->peek(0xFFFE) | ((uInt16)mySystem->peek(0xFFFF) << 8);
|
||||
}
|
||||
else if(myExecutionStatus & NonmaskableInterruptBit)
|
||||
{
|
||||
mySystem->incrementCycles(7 * mySystemCyclesPerProcessorCycle);
|
||||
mySystem->poke(0x0100 + SP--, (PC - 1) >> 8);
|
||||
mySystem->poke(0x0100 + SP--, (PC - 1) & 0x00ff);
|
||||
mySystem->poke(0x0100 + SP--, PS() & (~0x10));
|
||||
D = false;
|
||||
PC = (uInt16)mySystem->peek(0xFFFA) | ((uInt16)mySystem->peek(0xFFFB) << 8);
|
||||
}
|
||||
|
||||
// Clear the interrupt bits in myExecutionStatus
|
||||
myExecutionStatus &= ~(MaskableInterruptBit | NonmaskableInterruptBit);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool M6502Low::save(Serializer& out)
|
||||
{
|
||||
string CPU = name();
|
||||
|
||||
try
|
||||
{
|
||||
out.putString(CPU);
|
||||
|
||||
out.putByte((char)A); // Accumulator
|
||||
out.putByte((char)X); // X index register
|
||||
out.putByte((char)Y); // Y index register
|
||||
out.putByte((char)SP); // Stack Pointer
|
||||
out.putByte((char)IR); // Instruction register
|
||||
out.putInt(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((char)myExecutionStatus);
|
||||
}
|
||||
catch(char *msg)
|
||||
{
|
||||
cerr << msg << endl;
|
||||
return false;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cerr << "Unknown error in save state for " << CPU << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool M6502Low::load(Deserializer& in)
|
||||
{
|
||||
string CPU = name();
|
||||
|
||||
try
|
||||
{
|
||||
if(in.getString() != CPU)
|
||||
return false;
|
||||
|
||||
A = (uInt8) in.getByte(); // Accumulator
|
||||
X = (uInt8) in.getByte(); // X index register
|
||||
Y = (uInt8) in.getByte(); // Y index register
|
||||
SP = (uInt8) in.getByte(); // Stack Pointer
|
||||
IR = (uInt8) in.getByte(); // Instruction register
|
||||
PC = (uInt16) in.getInt(); // Program Counter
|
||||
|
||||
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
|
||||
|
||||
myExecutionStatus = (uInt8) in.getByte();
|
||||
}
|
||||
catch(char *msg)
|
||||
{
|
||||
cerr << msg << endl;
|
||||
return false;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cerr << "Unknown error in load state for " << CPU << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const char* M6502Low::name() const
|
||||
{
|
||||
return "M6502Low";
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// 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 M6502LOW_HXX
|
||||
#define M6502LOW_HXX
|
||||
|
||||
class M6502Low;
|
||||
class Serializer;
|
||||
class Deserializer;
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "M6502.hxx"
|
||||
|
||||
/**
|
||||
This class provides a low compatibility 6502 microprocessor emulator.
|
||||
The memory accesses and cycle updates of this emulator are not 100%
|
||||
accurate as shown below:
|
||||
|
||||
1. Only memory accesses which are actually needed are done
|
||||
(i.e. no "false" reads and writes are performed)
|
||||
|
||||
2. Cycle counts are updated at the beginning of the instruction
|
||||
execution and not valid at the sub-instruction level
|
||||
|
||||
If speed is the most important issue then use this class, however, if
|
||||
better compatibility is neccessary use one of the other 6502 classes.
|
||||
|
||||
@author Bradford W. Mott
|
||||
@version $Id$
|
||||
*/
|
||||
class M6502Low : public M6502
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Create a new low compatibility 6502 microprocessor with the specified
|
||||
cycle multiplier.
|
||||
|
||||
@param systemCyclesPerProcessorCycle The cycle multiplier
|
||||
*/
|
||||
M6502Low(uInt32 systemCyclesPerProcessorCycle);
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
virtual ~M6502Low();
|
||||
|
||||
public:
|
||||
/**
|
||||
Execute instructions until the specified number of instructions
|
||||
is executed, someone stops execution, or an error occurs. Answers
|
||||
true iff execution stops normally.
|
||||
|
||||
@param number Indicates the number of instructions to execute
|
||||
@return true iff execution stops normally
|
||||
*/
|
||||
virtual bool execute(uInt32 number);
|
||||
|
||||
/**
|
||||
Saves the current state of this device to the given Serializer.
|
||||
|
||||
@param out The serializer device to save to.
|
||||
@return The result of the save. True on success, false on failure.
|
||||
*/
|
||||
virtual bool save(Serializer& out);
|
||||
|
||||
/**
|
||||
Loads the current state of this device from the given Deserializer.
|
||||
|
||||
@param in The deserializer device to load from.
|
||||
@return The result of the load. True on success, false on failure.
|
||||
*/
|
||||
virtual bool load(Deserializer& in);
|
||||
|
||||
/**
|
||||
Get a null terminated string which is the processors's name (i.e. "M6532")
|
||||
|
||||
@return The name of the device
|
||||
*/
|
||||
virtual const char* name() const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
Called after an interrupt has be requested using irq() or nmi()
|
||||
*/
|
||||
void interruptHandler();
|
||||
|
||||
protected:
|
||||
/*
|
||||
Get the byte at the specified address
|
||||
|
||||
@return The byte at the specified address
|
||||
*/
|
||||
inline uInt8 peek(uInt16 address);
|
||||
|
||||
/**
|
||||
Change the byte at the specified address to the given value
|
||||
|
||||
@param address The address where the value should be stored
|
||||
@param value The value to be stored at the address
|
||||
*/
|
||||
inline void poke(uInt16 address, uInt8 value);
|
||||
};
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,286 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// Copyright (c) 1995-2005 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$
|
||||
//============================================================================
|
||||
|
||||
/**
|
||||
Code to handle addressing modes and branch instructions for
|
||||
low compatibility emulation
|
||||
|
||||
@author Bradford W. Mott
|
||||
@version $Id$
|
||||
*/
|
||||
|
||||
#ifndef NOTSAMEPAGE
|
||||
#define NOTSAMEPAGE(_addr1, _addr2) (((_addr1) ^ (_addr2)) & 0xff00)
|
||||
#endif
|
||||
|
||||
define(M6502_IMPLIED, `{
|
||||
}')
|
||||
|
||||
define(M6502_IMMEDIATE_READ, `{
|
||||
operandAddress = PC++;
|
||||
operand = peek(operandAddress);
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTE_READ, `{
|
||||
operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8);
|
||||
PC += 2;
|
||||
operand = peek(operandAddress);
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTE_WRITE, `{
|
||||
operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8);
|
||||
PC += 2;
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTE_READMODIFYWRITE, `{
|
||||
operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8);
|
||||
PC += 2;
|
||||
operand = peek(operandAddress);
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTEX_READ, `{
|
||||
operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8);
|
||||
PC += 2;
|
||||
|
||||
// See if we need to add one cycle for indexing across a page boundary
|
||||
if(NOTSAMEPAGE(operandAddress, operandAddress + X))
|
||||
{
|
||||
mySystem->incrementCycles(mySystemCyclesPerProcessorCycle);
|
||||
}
|
||||
|
||||
operandAddress += X;
|
||||
operand = peek(operandAddress);
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTEX_WRITE, `{
|
||||
operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8);
|
||||
PC += 2;
|
||||
operandAddress += X;
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTEX_READMODIFYWRITE, `{
|
||||
operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8);
|
||||
PC += 2;
|
||||
operandAddress += X;
|
||||
operand = peek(operandAddress);
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTEY_READ, `{
|
||||
operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8);
|
||||
PC += 2;
|
||||
|
||||
// See if we need to add one cycle for indexing across a page boundary
|
||||
if(NOTSAMEPAGE(operandAddress, operandAddress + Y))
|
||||
{
|
||||
mySystem->incrementCycles(mySystemCyclesPerProcessorCycle);
|
||||
}
|
||||
|
||||
operandAddress += Y;
|
||||
operand = peek(operandAddress);
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTEY_WRITE, `{
|
||||
operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8);
|
||||
PC += 2;
|
||||
operandAddress += Y;
|
||||
}')
|
||||
|
||||
define(M6502_ABSOLUTEY_READMODIFYWRITE, `{
|
||||
operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8);
|
||||
PC += 2;
|
||||
operandAddress += Y;
|
||||
operand = peek(operandAddress);
|
||||
}')
|
||||
|
||||
define(M6502_ZERO_READ, `{
|
||||
operandAddress = peek(PC++);
|
||||
operand = peek(operandAddress);
|
||||
}')
|
||||
|
||||
define(M6502_ZERO_WRITE, `{
|
||||
operandAddress = peek(PC++);
|
||||
}')
|
||||
|
||||
define(M6502_ZERO_READMODIFYWRITE, `{
|
||||
operandAddress = peek(PC++);
|
||||
operand = peek(operandAddress);
|
||||
}')
|
||||
|
||||
define(M6502_ZEROX_READ, `{
|
||||
operandAddress = (uInt8)(peek(PC++) + X);
|
||||
operand = peek(operandAddress);
|
||||
}')
|
||||
|
||||
define(M6502_ZEROX_WRITE, `{
|
||||
operandAddress = (uInt8)(peek(PC++) + X);
|
||||
}')
|
||||
|
||||
define(M6502_ZEROX_READMODIFYWRITE, `{
|
||||
operandAddress = (uInt8)(peek(PC++) + X);
|
||||
operand = peek(operandAddress);
|
||||
}')
|
||||
|
||||
define(M6502_ZEROY_READ, `{
|
||||
operandAddress = (uInt8)(peek(PC++) + Y);
|
||||
operand = peek(operandAddress);
|
||||
}')
|
||||
|
||||
define(M6502_ZEROY_WRITE, `{
|
||||
operandAddress = (uInt8)(peek(PC++) + Y);
|
||||
}')
|
||||
|
||||
define(M6502_ZEROY_READMODIFYWRITE, `{
|
||||
operandAddress = (uInt8)(peek(PC++) + Y);
|
||||
operand = peek(operandAddress);
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECT, `{
|
||||
uInt16 addr = peek(PC) | ((uInt16)peek(PC + 1) << 8);
|
||||
PC += 2;
|
||||
|
||||
// Simulate the error in the indirect addressing mode!
|
||||
uInt16 high = NOTSAMEPAGE(addr, addr + 1) ? (addr & 0xff00) : (addr + 1);
|
||||
|
||||
operandAddress = peek(addr) | ((uInt16)peek(high) << 8);
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECTX_READ, `{
|
||||
uInt8 pointer = peek(PC++) + X;
|
||||
operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8);
|
||||
operand = peek(operandAddress);
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECTX_WRITE, `{
|
||||
uInt8 pointer = peek(PC++) + X;
|
||||
operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8);
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECTX_READMODIFYWRITE, `{
|
||||
uInt8 pointer = peek(PC++) + X;
|
||||
operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8);
|
||||
operand = peek(operandAddress);
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECTY_READ, `{
|
||||
uInt8 pointer = peek(PC++);
|
||||
operandAddress = (uInt16)peek(pointer) | ((uInt16)peek(pointer + 1) << 8);
|
||||
|
||||
if(NOTSAMEPAGE(operandAddress, operandAddress + Y))
|
||||
{
|
||||
mySystem->incrementCycles(mySystemCyclesPerProcessorCycle);
|
||||
}
|
||||
|
||||
operandAddress += Y;
|
||||
operand = peek(operandAddress);
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECTY_WRITE, `{
|
||||
uInt8 pointer = peek(PC++);
|
||||
operandAddress = (uInt16)peek(pointer) | ((uInt16)peek(pointer + 1) << 8);
|
||||
operandAddress += Y;
|
||||
}')
|
||||
|
||||
define(M6502_INDIRECTY_READMODIFYWRITE, `{
|
||||
uInt8 pointer = peek(PC++);
|
||||
operandAddress = (uInt16)peek(pointer) | ((uInt16)peek(pointer + 1) << 8);
|
||||
operandAddress += Y;
|
||||
operand = peek(operandAddress);
|
||||
}')
|
||||
|
||||
|
||||
define(M6502_BCC, `{
|
||||
if(!C)
|
||||
{
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ?
|
||||
mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle);
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BCS, `{
|
||||
if(C)
|
||||
{
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ?
|
||||
mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle);
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BEQ, `{
|
||||
if(!notZ)
|
||||
{
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ?
|
||||
mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle);
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BMI, `{
|
||||
if(N)
|
||||
{
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ?
|
||||
mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle);
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BNE, `{
|
||||
if(notZ)
|
||||
{
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ?
|
||||
mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle);
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BPL, `{
|
||||
if(!N)
|
||||
{
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ?
|
||||
mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle);
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BVC, `{
|
||||
if(!V)
|
||||
{
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ?
|
||||
mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle);
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
define(M6502_BVS, `{
|
||||
if(V)
|
||||
{
|
||||
uInt16 address = PC + (Int8)operand;
|
||||
mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ?
|
||||
mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle);
|
||||
PC = address;
|
||||
}
|
||||
}')
|
||||
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
License Information and Copyright Notice
|
||||
===============================================================================
|
||||
|
||||
Copyright (C) 1995-2002 Bradford W. Mott <bwmott@acm.org>
|
||||
Copyright (C) 1995-2009 Bradford W. Mott <bwmott@acm.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -34,4 +34,3 @@ BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|||
PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN
|
||||
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
|
||||
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
|
||||
|
|
Loading…
Reference in New Issue