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:
stephena 2009-05-17 19:30:10 +00:00
parent 61914d3b3e
commit b99ed19695
18 changed files with 759 additions and 6080 deletions

View File

@ -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);

View File

@ -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];

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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)
{

View File

@ -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];

View File

@ -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 @@

View File

@ -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)
{

View File

@ -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";
}

View File

@ -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

View File

@ -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;
}
}')

View File

@ -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";
}

View File

@ -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

View File

@ -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;
}
}')

View File

@ -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.