From cc07a7e5026a4fc9bfc461d031a8fe871296dbd9 Mon Sep 17 00:00:00 2001 From: stephena Date: Sun, 5 Feb 2006 02:49:47 +0000 Subject: [PATCH] Some minor tweaks which will hopefully speed things up for the GP2X port. Resurrected the low-compatibility 6502 CPU code, since it's supposed to be somewhat faster. This is activated internally by GP2X by settings "cpu" to "low". This can also be set from the commandline, but I'm not going to document the fact. All systems that can handle hi-compat mode should be using it. git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@999 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba --- stella/src/emucore/Console.cxx | 8 +- stella/src/emucore/TIA.hxx | 14 +- stella/src/emucore/m6502/module.mk | 1 + stella/src/emucore/m6502/src/M6502Low.cxx | 300 ++ stella/src/emucore/m6502/src/M6502Low.hxx | 119 + stella/src/emucore/m6502/src/M6502Low.ins | 4374 +++++++++++++++++++++ stella/src/emucore/m6502/src/M6502Low.m4 | 286 ++ stella/src/emucore/m6502/src/System.cxx | 7 +- stella/src/emucore/m6502/src/System.hxx | 8 +- stella/src/gp2x/SettingsGP2X.cxx | 5 +- 10 files changed, 5105 insertions(+), 17 deletions(-) create mode 100644 stella/src/emucore/m6502/src/M6502Low.cxx create mode 100644 stella/src/emucore/m6502/src/M6502Low.hxx create mode 100644 stella/src/emucore/m6502/src/M6502Low.ins create mode 100644 stella/src/emucore/m6502/src/M6502Low.m4 diff --git a/stella/src/emucore/Console.cxx b/stella/src/emucore/Console.cxx index 5276e0078..f752c7f29 100644 --- a/stella/src/emucore/Console.cxx +++ b/stella/src/emucore/Console.cxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: Console.cxx,v 1.82 2006-01-25 01:42:46 stephena Exp $ +// $Id: Console.cxx,v 1.83 2006-02-05 02:49:47 stephena Exp $ //============================================================================ #include @@ -31,6 +31,7 @@ #include "Joystick.hxx" #include "Keyboard.hxx" #include "M6502Hi.hxx" +#include "M6502Low.hxx" #include "M6532.hxx" #include "MediaSrc.hxx" #include "Paddles.hxx" @@ -156,7 +157,10 @@ Console::Console(const uInt8* image, uInt32 size, const string& md5, mySystem = new System(13, 6); M6502* m6502; - m6502 = new M6502High(1); + if(myOSystem->settings().getString("cpu") == "low") + m6502 = new M6502Low(1); + else + m6502 = new M6502High(1); #ifdef DEVELOPER_SUPPORT m6502->attach(myOSystem->debugger()); #endif diff --git a/stella/src/emucore/TIA.hxx b/stella/src/emucore/TIA.hxx index e91b8821e..a6267a472 100644 --- a/stella/src/emucore/TIA.hxx +++ b/stella/src/emucore/TIA.hxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: TIA.hxx,v 1.33 2005-10-11 19:38:10 stephena Exp $ +// $Id: TIA.hxx,v 1.34 2006-02-05 02:49:47 stephena Exp $ //============================================================================ #ifndef TIA_HXX @@ -42,7 +42,7 @@ class Settings; be displayed on screen. @author Bradford W. Mott - @version $Id: TIA.hxx,v 1.33 2005-10-11 19:38:10 stephena Exp $ + @version $Id: TIA.hxx,v 1.34 2006-02-05 02:49:47 stephena Exp $ */ class TIA : public Device , public MediaSource { @@ -259,7 +259,7 @@ class TIA : public Device , public MediaSource private: // Update the current frame buffer up to one scanline - void updateFrameScanline(uInt32 clocksToUpdate, uInt32 hpos); + inline void updateFrameScanline(uInt32 clocksToUpdate, uInt32 hpos); // Update the current frame buffer to the specified color clock void updateFrame(Int32 clock); @@ -273,11 +273,11 @@ class TIA : public Device , public MediaSource // Clear both internal TIA buffers to black (palette color 0) void clearBuffers(); - // set up bookkeeping for the next frame - void startFrame(); + // Set up bookkeeping for the next frame + inline void startFrame(); - // update bookkeeping at end of frame - void endFrame(); + // Update bookkeeping at end of frame + inline void endFrame(); private: // Console the TIA is associated with diff --git a/stella/src/emucore/m6502/module.mk b/stella/src/emucore/m6502/module.mk index c9c8e87cb..9361d5b96 100644 --- a/stella/src/emucore/m6502/module.mk +++ b/stella/src/emucore/m6502/module.mk @@ -3,6 +3,7 @@ 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 diff --git a/stella/src/emucore/m6502/src/M6502Low.cxx b/stella/src/emucore/m6502/src/M6502Low.cxx new file mode 100644 index 000000000..d9780ddc0 --- /dev/null +++ b/stella/src/emucore/m6502/src/M6502Low.cxx @@ -0,0 +1,300 @@ +//============================================================================ +// +// 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: M6502Low.cxx,v 1.8 2006-02-05 02:49:47 stephena Exp $ +//============================================================================ + +#include "M6502Low.hxx" +#include "Serializer.hxx" +#include "Deserializer.hxx" + +#ifdef DEVELOPER_SUPPORT + #include "Debugger.hxx" +#endif + +#define debugStream cout + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +M6502Low::M6502Low(uInt32 systemCyclesPerProcessorCycle) + : M6502(systemCyclesPerProcessorCycle) +{ +#ifdef DEVELOPER_SUPPORT + myJustHitTrapFlag = false; +#endif +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +M6502Low::~M6502Low() +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +inline uInt8 M6502Low::peek(uInt16 address) +{ +#ifdef DEVELOPER_SUPPORT + if(myReadTraps != NULL && myReadTraps->isSet(address)) + { + myJustHitTrapFlag = true; + myHitTrapInfo.message = "Read trap: "; + myHitTrapInfo.address = address; + } +#endif + + return mySystem->peek(address); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +inline void M6502Low::poke(uInt16 address, uInt8 value) +{ +#ifdef DEVELOPER_SUPPORT + if(myWriteTraps != NULL && myWriteTraps->isSet(address)) + { + myJustHitTrapFlag = true; + myHitTrapInfo.message = "Write trap: "; + myHitTrapInfo.address = address; + } +#endif + + mySystem->poke(address, value); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +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 DEVELOPER_SUPPORT + if(myJustHitTrapFlag) + { + if(myDebugger->start(myHitTrapInfo.message, myHitTrapInfo.address)) + { + myJustHitTrapFlag = false; + return true; + } + } + + if(myBreakPoints != NULL) + { + if(myBreakPoints->isSet(PC)) + { + if(myDebugger->start("Breakpoint hit: ", 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; + } + +#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.putInt(A); // Accumulator + out.putInt(X); // X index register + out.putInt(Y); // Y index register + out.putInt(SP); // Stack Pointer + out.putInt(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.putInt(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.getInt(); // Accumulator + X = (uInt8) in.getInt(); // X index register + Y = (uInt8) in.getInt(); // Y index register + SP = (uInt8) in.getInt(); // Stack Pointer + IR = (uInt8) in.getInt(); // 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.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* M6502Low::name() const +{ + return "M6502Low"; +} diff --git a/stella/src/emucore/m6502/src/M6502Low.hxx b/stella/src/emucore/m6502/src/M6502Low.hxx new file mode 100644 index 000000000..7fd75903f --- /dev/null +++ b/stella/src/emucore/m6502/src/M6502Low.hxx @@ -0,0 +1,119 @@ +//============================================================================ +// +// 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: M6502Low.hxx,v 1.5 2006-02-05 02:49:47 stephena Exp $ +//============================================================================ + +#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: M6502Low.hxx,v 1.5 2006-02-05 02:49:47 stephena Exp $ +*/ +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 + diff --git a/stella/src/emucore/m6502/src/M6502Low.ins b/stella/src/emucore/m6502/src/M6502Low.ins new file mode 100644 index 000000000..d2ecfaff5 --- /dev/null +++ b/stella/src/emucore/m6502/src/M6502Low.ins @@ -0,0 +1,4374 @@ +//============================================================================ +// +// 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: M6502Low.ins,v 1.4 2006-02-05 02:49:47 stephena Exp $ +//============================================================================ + +/** + Code to handle addressing modes and branch instructions for + low compatibility emulation + + @author Bradford W. Mott + @version $Id: M6502Low.ins,v 1.4 2006-02-05 02:49:47 stephena Exp $ +*/ + +#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: M6502Low.ins,v 1.4 2006-02-05 02:49:47 stephena Exp $ +//============================================================================ + +/** + Code and cases to emulate each of the 6502 instruction + + @author Bradford W. Mott + @version $Id: M6502Low.ins,v 1.4 2006-02-05 02:49:47 stephena Exp $ +*/ + +#ifndef NOTSAMEPAGE + #define NOTSAMEPAGE(_addr1, _addr2) (((_addr1) ^ (_addr2)) & 0xff00) +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +case 0x69: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + uInt8 oldA = A; + + if(!D) + { + Int16 sum = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((sum > 127) || (sum < -128)); + + sum = (Int16)A + (Int16)operand + (C ? 1 : 0); + A = sum; + C = (sum > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 sum = ourBCDTable[0][A] + ourBCDTable[0][operand] + (C ? 1 : 0); + + C = (sum > 99); + A = ourBCDTable[1][sum & 0xff]; + notZ = A; + N = A & 0x80; + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0x65: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + uInt8 oldA = A; + + if(!D) + { + Int16 sum = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((sum > 127) || (sum < -128)); + + sum = (Int16)A + (Int16)operand + (C ? 1 : 0); + A = sum; + C = (sum > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 sum = ourBCDTable[0][A] + ourBCDTable[0][operand] + (C ? 1 : 0); + + C = (sum > 99); + A = ourBCDTable[1][sum & 0xff]; + notZ = A; + N = A & 0x80; + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0x75: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ + uInt8 oldA = A; + + if(!D) + { + Int16 sum = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((sum > 127) || (sum < -128)); + + sum = (Int16)A + (Int16)operand + (C ? 1 : 0); + A = sum; + C = (sum > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 sum = ourBCDTable[0][A] + ourBCDTable[0][operand] + (C ? 1 : 0); + + C = (sum > 99); + A = ourBCDTable[1][sum & 0xff]; + notZ = A; + N = A & 0x80; + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0x6d: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + uInt8 oldA = A; + + if(!D) + { + Int16 sum = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((sum > 127) || (sum < -128)); + + sum = (Int16)A + (Int16)operand + (C ? 1 : 0); + A = sum; + C = (sum > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 sum = ourBCDTable[0][A] + ourBCDTable[0][operand] + (C ? 1 : 0); + + C = (sum > 99); + A = ourBCDTable[1][sum & 0xff]; + notZ = A; + N = A & 0x80; + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0x7d: +{ + 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); +} +{ + uInt8 oldA = A; + + if(!D) + { + Int16 sum = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((sum > 127) || (sum < -128)); + + sum = (Int16)A + (Int16)operand + (C ? 1 : 0); + A = sum; + C = (sum > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 sum = ourBCDTable[0][A] + ourBCDTable[0][operand] + (C ? 1 : 0); + + C = (sum > 99); + A = ourBCDTable[1][sum & 0xff]; + notZ = A; + N = A & 0x80; + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0x79: +{ + 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); +} +{ + uInt8 oldA = A; + + if(!D) + { + Int16 sum = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((sum > 127) || (sum < -128)); + + sum = (Int16)A + (Int16)operand + (C ? 1 : 0); + A = sum; + C = (sum > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 sum = ourBCDTable[0][A] + ourBCDTable[0][operand] + (C ? 1 : 0); + + C = (sum > 99); + A = ourBCDTable[1][sum & 0xff]; + notZ = A; + N = A & 0x80; + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0x61: +{ + uInt8 pointer = peek(PC++) + X; + operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operand = peek(operandAddress); +} +{ + uInt8 oldA = A; + + if(!D) + { + Int16 sum = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((sum > 127) || (sum < -128)); + + sum = (Int16)A + (Int16)operand + (C ? 1 : 0); + A = sum; + C = (sum > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 sum = ourBCDTable[0][A] + ourBCDTable[0][operand] + (C ? 1 : 0); + + C = (sum > 99); + A = ourBCDTable[1][sum & 0xff]; + notZ = A; + N = A & 0x80; + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0x71: +{ + 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); +} +{ + uInt8 oldA = A; + + if(!D) + { + Int16 sum = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((sum > 127) || (sum < -128)); + + sum = (Int16)A + (Int16)operand + (C ? 1 : 0); + A = sum; + C = (sum > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 sum = ourBCDTable[0][A] + ourBCDTable[0][operand] + (C ? 1 : 0); + + C = (sum > 99); + A = ourBCDTable[1][sum & 0xff]; + notZ = A; + N = A & 0x80; + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + + +case 0x4b: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + A &= operand; + + // Set carry flag according to the right-most bit + C = A & 0x01; + + A = (A >> 1) & 0x7f; + + notZ = A; + N = A & 0x80; +} +break; + + +case 0x0b: +case 0x2b: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + A &= operand; + notZ = A; + N = A & 0x80; + C = N; +} +break; + + +case 0x29: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + A &= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x25: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + A &= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x35: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ + A &= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x2d: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + A &= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x3d: +{ + 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); +} +{ + A &= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x39: +{ + 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); +} +{ + A &= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x21: +{ + uInt8 pointer = peek(PC++) + X; + operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operand = peek(operandAddress); +} +{ + A &= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x31: +{ + 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); +} +{ + A &= operand; + notZ = A; + N = A & 0x80; +} +break; + + +case 0x8b: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + // NOTE: The implementation of this instruction is based on + // information from the 64doc.txt file. This instruction is + // reported to be unstable! + A = (A | 0xee) & X & operand; + notZ = A; + N = A & 0x80; +} +break; + + +case 0x6b: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + // NOTE: The implementation of this instruction is based on + // information from the 64doc.txt file. There are mixed + // reports on its operation! + if(!D) + { + A &= operand; + A = ((A >> 1) & 0x7f) | (C ? 0x80 : 0x00); + + C = A & 0x40; + V = (A & 0x40) ^ ((A & 0x20) << 1); + + notZ = A; + N = A & 0x80; + } + else + { + uInt8 value = A & operand; + + A = ((value >> 1) & 0x7f) | (C ? 0x80 : 0x00); + N = C; + notZ = A; + V = (value ^ A) & 0x40; + + if(((value & 0x0f) + (value & 0x01)) > 0x05) + { + A = (A & 0xf0) | ((A + 0x06) & 0x0f); + } + + if(((value & 0xf0) + (value & 0x10)) > 0x50) + { + A = (A + 0x60) & 0xff; + C = 1; + } + else + { + C = 0; + } + } +} +break; + + +case 0x0a: +{ +} +{ + // Set carry flag according to the left-most bit in A + C = A & 0x80; + + A <<= 1; + + notZ = A; + N = A & 0x80; +} +break; + +case 0x06: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + // Set carry flag according to the left-most bit in value + C = operand & 0x80; + + operand <<= 1; + poke(operandAddress, operand); + + notZ = operand; + N = operand & 0x80; +} +break; + +case 0x16: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ + // Set carry flag according to the left-most bit in value + C = operand & 0x80; + + operand <<= 1; + poke(operandAddress, operand); + + notZ = operand; + N = operand & 0x80; +} +break; + +case 0x0e: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + // Set carry flag according to the left-most bit in value + C = operand & 0x80; + + operand <<= 1; + poke(operandAddress, operand); + + notZ = operand; + N = operand & 0x80; +} +break; + +case 0x1e: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += X; + operand = peek(operandAddress); +} +{ + // Set carry flag according to the left-most bit in value + C = operand & 0x80; + + operand <<= 1; + poke(operandAddress, operand); + + notZ = operand; + N = operand & 0x80; +} +break; + + +case 0x90: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + if(!C) + { + uInt16 address = PC + (Int8)operand; + mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ? + mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle); + PC = address; + } +} +break; + + +case 0xb0: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + if(C) + { + uInt16 address = PC + (Int8)operand; + mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ? + mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle); + PC = address; + } +} +break; + + +case 0xf0: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + if(!notZ) + { + uInt16 address = PC + (Int8)operand; + mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ? + mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle); + PC = address; + } +} +break; + + +case 0x24: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + notZ = (A & operand); + N = operand & 0x80; + V = operand & 0x40; +} +break; + +case 0x2C: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + notZ = (A & operand); + N = operand & 0x80; + V = operand & 0x40; +} +break; + + +case 0x30: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + if(N) + { + uInt16 address = PC + (Int8)operand; + mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ? + mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle); + PC = address; + } +} +break; + + +case 0xD0: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + if(notZ) + { + uInt16 address = PC + (Int8)operand; + mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ? + mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle); + PC = address; + } +} +break; + + +case 0x10: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + if(!N) + { + uInt16 address = PC + (Int8)operand; + mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ? + mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle); + PC = address; + } +} +break; + + +case 0x00: +{ + peek(PC++); + + B = true; + + poke(0x0100 + SP--, PC >> 8); + poke(0x0100 + SP--, PC & 0x00ff); + poke(0x0100 + SP--, PS()); + + I = true; + + PC = peek(0xfffe); + PC |= ((uInt16)peek(0xffff) << 8); +} +break; + + +case 0x50: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + if(!V) + { + uInt16 address = PC + (Int8)operand; + mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ? + mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle); + PC = address; + } +} +break; + + +case 0x70: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + if(V) + { + uInt16 address = PC + (Int8)operand; + mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ? + mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle); + PC = address; + } +} +break; + + +case 0x18: +{ +} +{ + C = false; +} +break; + + +case 0xd8: +{ +} +{ + D = false; +} +break; + + +case 0x58: +{ +} +{ + I = false; +} +break; + + +case 0xb8: +{ +} +{ + V = false; +} +break; + + +case 0xc9: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + uInt16 value = (uInt16)A - (uInt16)operand; + + notZ = value; + N = value & 0x0080; + C = !(value & 0x0100); +} +break; + +case 0xc5: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + uInt16 value = (uInt16)A - (uInt16)operand; + + notZ = value; + N = value & 0x0080; + C = !(value & 0x0100); +} +break; + +case 0xd5: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ + uInt16 value = (uInt16)A - (uInt16)operand; + + notZ = value; + N = value & 0x0080; + C = !(value & 0x0100); +} +break; + +case 0xcd: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + uInt16 value = (uInt16)A - (uInt16)operand; + + notZ = value; + N = value & 0x0080; + C = !(value & 0x0100); +} +break; + +case 0xdd: +{ + 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); +} +{ + uInt16 value = (uInt16)A - (uInt16)operand; + + notZ = value; + N = value & 0x0080; + C = !(value & 0x0100); +} +break; + +case 0xd9: +{ + 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); +} +{ + uInt16 value = (uInt16)A - (uInt16)operand; + + notZ = value; + N = value & 0x0080; + C = !(value & 0x0100); +} +break; + +case 0xc1: +{ + uInt8 pointer = peek(PC++) + X; + operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operand = peek(operandAddress); +} +{ + uInt16 value = (uInt16)A - (uInt16)operand; + + notZ = value; + N = value & 0x0080; + C = !(value & 0x0100); +} +break; + +case 0xd1: +{ + 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); +} +{ + uInt16 value = (uInt16)A - (uInt16)operand; + + notZ = value; + N = value & 0x0080; + C = !(value & 0x0100); +} +break; + + +case 0xe0: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + uInt16 value = (uInt16)X - (uInt16)operand; + + notZ = value; + N = value & 0x0080; + C = !(value & 0x0100); +} +break; + +case 0xe4: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + uInt16 value = (uInt16)X - (uInt16)operand; + + notZ = value; + N = value & 0x0080; + C = !(value & 0x0100); +} +break; + +case 0xec: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + uInt16 value = (uInt16)X - (uInt16)operand; + + notZ = value; + N = value & 0x0080; + C = !(value & 0x0100); +} +break; + + +case 0xc0: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + uInt16 value = (uInt16)Y - (uInt16)operand; + + notZ = value; + N = value & 0x0080; + C = !(value & 0x0100); +} +break; + +case 0xc4: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + uInt16 value = (uInt16)Y - (uInt16)operand; + + notZ = value; + N = value & 0x0080; + C = !(value & 0x0100); +} +break; + +case 0xcc: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + uInt16 value = (uInt16)Y - (uInt16)operand; + + notZ = value; + N = value & 0x0080; + C = !(value & 0x0100); +} +break; + + +case 0xcf: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + uInt8 value = operand - 1; + poke(operandAddress, value); + + uInt16 value2 = (uInt16)A - (uInt16)value; + notZ = value2; + N = value2 & 0x0080; + C = !(value2 & 0x0100); +} +break; + +case 0xdf: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += X; + operand = peek(operandAddress); +} +{ + uInt8 value = operand - 1; + poke(operandAddress, value); + + uInt16 value2 = (uInt16)A - (uInt16)value; + notZ = value2; + N = value2 & 0x0080; + C = !(value2 & 0x0100); +} +break; + +case 0xdb: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += Y; + operand = peek(operandAddress); +} +{ + uInt8 value = operand - 1; + poke(operandAddress, value); + + uInt16 value2 = (uInt16)A - (uInt16)value; + notZ = value2; + N = value2 & 0x0080; + C = !(value2 & 0x0100); +} +break; + +case 0xc7: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + uInt8 value = operand - 1; + poke(operandAddress, value); + + uInt16 value2 = (uInt16)A - (uInt16)value; + notZ = value2; + N = value2 & 0x0080; + C = !(value2 & 0x0100); +} +break; + +case 0xd7: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ + uInt8 value = operand - 1; + poke(operandAddress, value); + + uInt16 value2 = (uInt16)A - (uInt16)value; + notZ = value2; + N = value2 & 0x0080; + C = !(value2 & 0x0100); +} +break; + +case 0xc3: +{ + uInt8 pointer = peek(PC++) + X; + operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operand = peek(operandAddress); +} +{ + uInt8 value = operand - 1; + poke(operandAddress, value); + + uInt16 value2 = (uInt16)A - (uInt16)value; + notZ = value2; + N = value2 & 0x0080; + C = !(value2 & 0x0100); +} +break; + +case 0xd3: +{ + uInt8 pointer = peek(PC++); + operandAddress = (uInt16)peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operandAddress += Y; + operand = peek(operandAddress); +} +{ + uInt8 value = operand - 1; + poke(operandAddress, value); + + uInt16 value2 = (uInt16)A - (uInt16)value; + notZ = value2; + N = value2 & 0x0080; + C = !(value2 & 0x0100); +} +break; + + +case 0xc6: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + uInt8 value = operand - 1; + poke(operandAddress, value); + + notZ = value; + N = value & 0x80; +} +break; + +case 0xd6: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ + uInt8 value = operand - 1; + poke(operandAddress, value); + + notZ = value; + N = value & 0x80; +} +break; + +case 0xce: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + uInt8 value = operand - 1; + poke(operandAddress, value); + + notZ = value; + N = value & 0x80; +} +break; + +case 0xde: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += X; + operand = peek(operandAddress); +} +{ + uInt8 value = operand - 1; + poke(operandAddress, value); + + notZ = value; + N = value & 0x80; +} +break; + + +case 0xca: +{ +} +{ + X--; + + notZ = X; + N = X & 0x80; +} +break; + + +case 0x88: +{ +} +{ + Y--; + + notZ = Y; + N = Y & 0x80; +} +break; + + +case 0x49: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + A ^= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x45: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + A ^= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x55: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ + A ^= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x4d: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + A ^= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x5d: +{ + 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); +} +{ + A ^= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x59: +{ + 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); +} +{ + A ^= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x41: +{ + uInt8 pointer = peek(PC++) + X; + operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operand = peek(operandAddress); +} +{ + A ^= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x51: +{ + 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); +} +{ + A ^= operand; + notZ = A; + N = A & 0x80; +} +break; + + +case 0xe6: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + uInt8 value = operand + 1; + poke(operandAddress, value); + + notZ = value; + N = value & 0x80; +} +break; + +case 0xf6: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ + uInt8 value = operand + 1; + poke(operandAddress, value); + + notZ = value; + N = value & 0x80; +} +break; + +case 0xee: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + uInt8 value = operand + 1; + poke(operandAddress, value); + + notZ = value; + N = value & 0x80; +} +break; + +case 0xfe: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += X; + operand = peek(operandAddress); +} +{ + uInt8 value = operand + 1; + poke(operandAddress, value); + + notZ = value; + N = value & 0x80; +} +break; + + +case 0xe8: +{ +} +{ + X++; + notZ = X; + N = X & 0x80; +} +break; + + +case 0xc8: +{ +} +{ + Y++; + notZ = Y; + N = Y & 0x80; +} +break; + + +case 0xef: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + operand = operand + 1; + poke(operandAddress, operand); + + uInt8 oldA = A; + + if(!D) + { + operand = ~operand; + Int16 difference = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((difference > 127) || (difference < -128)); + + difference = ((Int16)A) + ((Int16)operand) + (C ? 1 : 0); + A = difference; + C = (difference > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 difference = ourBCDTable[0][A] - ourBCDTable[0][operand] + - (C ? 0 : 1); + + if(difference < 0) + difference += 100; + + A = ourBCDTable[1][difference]; + notZ = A; + N = A & 0x80; + + C = (oldA >= (operand + (C ? 0 : 1))); + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0xff: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += X; + operand = peek(operandAddress); +} +{ + operand = operand + 1; + poke(operandAddress, operand); + + uInt8 oldA = A; + + if(!D) + { + operand = ~operand; + Int16 difference = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((difference > 127) || (difference < -128)); + + difference = ((Int16)A) + ((Int16)operand) + (C ? 1 : 0); + A = difference; + C = (difference > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 difference = ourBCDTable[0][A] - ourBCDTable[0][operand] + - (C ? 0 : 1); + + if(difference < 0) + difference += 100; + + A = ourBCDTable[1][difference]; + notZ = A; + N = A & 0x80; + + C = (oldA >= (operand + (C ? 0 : 1))); + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0xfb: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += Y; + operand = peek(operandAddress); +} +{ + operand = operand + 1; + poke(operandAddress, operand); + + uInt8 oldA = A; + + if(!D) + { + operand = ~operand; + Int16 difference = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((difference > 127) || (difference < -128)); + + difference = ((Int16)A) + ((Int16)operand) + (C ? 1 : 0); + A = difference; + C = (difference > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 difference = ourBCDTable[0][A] - ourBCDTable[0][operand] + - (C ? 0 : 1); + + if(difference < 0) + difference += 100; + + A = ourBCDTable[1][difference]; + notZ = A; + N = A & 0x80; + + C = (oldA >= (operand + (C ? 0 : 1))); + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0xe7: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + operand = operand + 1; + poke(operandAddress, operand); + + uInt8 oldA = A; + + if(!D) + { + operand = ~operand; + Int16 difference = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((difference > 127) || (difference < -128)); + + difference = ((Int16)A) + ((Int16)operand) + (C ? 1 : 0); + A = difference; + C = (difference > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 difference = ourBCDTable[0][A] - ourBCDTable[0][operand] + - (C ? 0 : 1); + + if(difference < 0) + difference += 100; + + A = ourBCDTable[1][difference]; + notZ = A; + N = A & 0x80; + + C = (oldA >= (operand + (C ? 0 : 1))); + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0xf7: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ + operand = operand + 1; + poke(operandAddress, operand); + + uInt8 oldA = A; + + if(!D) + { + operand = ~operand; + Int16 difference = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((difference > 127) || (difference < -128)); + + difference = ((Int16)A) + ((Int16)operand) + (C ? 1 : 0); + A = difference; + C = (difference > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 difference = ourBCDTable[0][A] - ourBCDTable[0][operand] + - (C ? 0 : 1); + + if(difference < 0) + difference += 100; + + A = ourBCDTable[1][difference]; + notZ = A; + N = A & 0x80; + + C = (oldA >= (operand + (C ? 0 : 1))); + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0xe3: +{ + uInt8 pointer = peek(PC++) + X; + operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operand = peek(operandAddress); +} +{ + operand = operand + 1; + poke(operandAddress, operand); + + uInt8 oldA = A; + + if(!D) + { + operand = ~operand; + Int16 difference = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((difference > 127) || (difference < -128)); + + difference = ((Int16)A) + ((Int16)operand) + (C ? 1 : 0); + A = difference; + C = (difference > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 difference = ourBCDTable[0][A] - ourBCDTable[0][operand] + - (C ? 0 : 1); + + if(difference < 0) + difference += 100; + + A = ourBCDTable[1][difference]; + notZ = A; + N = A & 0x80; + + C = (oldA >= (operand + (C ? 0 : 1))); + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0xf3: +{ + uInt8 pointer = peek(PC++); + operandAddress = (uInt16)peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operandAddress += Y; + operand = peek(operandAddress); +} +{ + operand = operand + 1; + poke(operandAddress, operand); + + uInt8 oldA = A; + + if(!D) + { + operand = ~operand; + Int16 difference = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((difference > 127) || (difference < -128)); + + difference = ((Int16)A) + ((Int16)operand) + (C ? 1 : 0); + A = difference; + C = (difference > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 difference = ourBCDTable[0][A] - ourBCDTable[0][operand] + - (C ? 0 : 1); + + if(difference < 0) + difference += 100; + + A = ourBCDTable[1][difference]; + notZ = A; + N = A & 0x80; + + C = (oldA >= (operand + (C ? 0 : 1))); + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + + +case 0x4c: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; +} +{ + PC = operandAddress; +} +break; + +case 0x6c: +{ + 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); +} +{ + PC = operandAddress; +} +break; + + +case 0x20: +{ + uInt8 low = peek(PC++); + peek(0x0100 + SP); + + // It seems that the 650x does not push the address of the next instruction + // on the stack it actually pushes the address of the next instruction + // minus one. This is compensated for in the RTS instruction + poke(0x0100 + SP--, PC >> 8); + poke(0x0100 + SP--, PC & 0xff); + + PC = low | ((uInt16)peek(PC++) << 8); +} +break; + + +case 0xbb: +{ + 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); +} +{ + A = X = SP = SP & operand; + notZ = A; + N = A & 0x80; +} +break; + + +case 0xaf: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + A = operand; + X = operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0xbf: +{ + 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); +} +{ + A = operand; + X = operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0xa7: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + A = operand; + X = operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0xb7: +{ + operandAddress = (uInt8)(peek(PC++) + Y); + operand = peek(operandAddress); +} +{ + A = operand; + X = operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0xa3: +{ + uInt8 pointer = peek(PC++) + X; + operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operand = peek(operandAddress); +} +{ + A = operand; + X = operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0xb3: +{ + 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); +} +{ + A = operand; + X = operand; + notZ = A; + N = A & 0x80; +} +break; + + +case 0xa9: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + A = operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0xa5: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + A = operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0xb5: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ + A = operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0xad: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + A = operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0xbd: +{ + 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); +} +{ + A = operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0xb9: +{ + 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); +} +{ + A = operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0xa1: +{ + uInt8 pointer = peek(PC++) + X; + operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operand = peek(operandAddress); +} +{ + A = operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0xb1: +{ + 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); +} +{ + A = operand; + notZ = A; + N = A & 0x80; +} +break; + + +case 0xa2: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + X = operand; + notZ = X; + N = X & 0x80; +} +break; + +case 0xa6: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + X = operand; + notZ = X; + N = X & 0x80; +} +break; + +case 0xb6: +{ + operandAddress = (uInt8)(peek(PC++) + Y); + operand = peek(operandAddress); +} +{ + X = operand; + notZ = X; + N = X & 0x80; +} +break; + +case 0xae: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + X = operand; + notZ = X; + N = X & 0x80; +} +break; + +case 0xbe: +{ + 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); +} +{ + X = operand; + notZ = X; + N = X & 0x80; +} +break; + + +case 0xa0: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + Y = operand; + notZ = Y; + N = Y & 0x80; +} +break; + +case 0xa4: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + Y = operand; + notZ = Y; + N = Y & 0x80; +} +break; + +case 0xb4: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ + Y = operand; + notZ = Y; + N = Y & 0x80; +} +break; + +case 0xac: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + Y = operand; + notZ = Y; + N = Y & 0x80; +} +break; + +case 0xbc: +{ + 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); +} +{ + Y = operand; + notZ = Y; + N = Y & 0x80; +} +break; + + +case 0x4a: +{ +} +{ + // Set carry flag according to the right-most bit + C = A & 0x01; + + A = (A >> 1) & 0x7f; + + notZ = A; + N = A & 0x80; +} +break; + + +case 0x46: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + // Set carry flag according to the right-most bit in value + C = operand & 0x01; + + operand = (operand >> 1) & 0x7f; + poke(operandAddress, operand); + + notZ = operand; + N = operand & 0x80; +} +break; + +case 0x56: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ + // Set carry flag according to the right-most bit in value + C = operand & 0x01; + + operand = (operand >> 1) & 0x7f; + poke(operandAddress, operand); + + notZ = operand; + N = operand & 0x80; +} +break; + +case 0x4e: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + // Set carry flag according to the right-most bit in value + C = operand & 0x01; + + operand = (operand >> 1) & 0x7f; + poke(operandAddress, operand); + + notZ = operand; + N = operand & 0x80; +} +break; + +case 0x5e: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += X; + operand = peek(operandAddress); +} +{ + // Set carry flag according to the right-most bit in value + C = operand & 0x01; + + operand = (operand >> 1) & 0x7f; + poke(operandAddress, operand); + + notZ = operand; + N = operand & 0x80; +} +break; + + +case 0xab: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + // NOTE: The implementation of this instruction is based on + // information from the 64doc.txt file. This instruction is + // reported to be very unstable! + A = X = (A | 0xee) & operand; + notZ = A; + N = A & 0x80; +} +break; + + +case 0x1a: +case 0x3a: +case 0x5a: +case 0x7a: +case 0xda: +case 0xea: +case 0xfa: +{ +} +{ +} +break; + +case 0x80: +case 0x82: +case 0x89: +case 0xc2: +case 0xe2: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ +} +break; + +case 0x04: +case 0x44: +case 0x64: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ +} +break; + +case 0x14: +case 0x34: +case 0x54: +case 0x74: +case 0xd4: +case 0xf4: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ +} +break; + +case 0x0c: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ +} +break; + +case 0x1c: +case 0x3c: +case 0x5c: +case 0x7c: +case 0xdc: +case 0xfc: +{ + 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); +} +{ +} +break; + + +case 0x09: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + A |= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x05: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + A |= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x15: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ + A |= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x0d: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + A |= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x1d: +{ + 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); +} +{ + A |= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x19: +{ + 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); +} +{ + A |= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x01: +{ + uInt8 pointer = peek(PC++) + X; + operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operand = peek(operandAddress); +} +{ + A |= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x11: +{ + 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); +} +{ + A |= operand; + notZ = A; + N = A & 0x80; +} +break; + + +case 0x48: +{ +} +{ + poke(0x0100 + SP--, A); +} +break; + + +case 0x08: +{ +} +{ + poke(0x0100 + SP--, PS()); +} +break; + + +case 0x68: +{ +} +{ + peek(0x0100 + SP++); + A = peek(0x0100 + SP); + notZ = A; + N = A & 0x80; +} +break; + + +case 0x28: +{ +} +{ + peek(0x0100 + SP++); + PS(peek(0x0100 + SP)); +} +break; + + +case 0x2f: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + uInt8 value = (operand << 1) | (C ? 1 : 0); + poke(operandAddress, value); + + A &= value; + C = operand & 0x80; + notZ = A; + N = A & 0x80; +} +break; + +case 0x3f: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += X; + operand = peek(operandAddress); +} +{ + uInt8 value = (operand << 1) | (C ? 1 : 0); + poke(operandAddress, value); + + A &= value; + C = operand & 0x80; + notZ = A; + N = A & 0x80; +} +break; + +case 0x3b: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += Y; + operand = peek(operandAddress); +} +{ + uInt8 value = (operand << 1) | (C ? 1 : 0); + poke(operandAddress, value); + + A &= value; + C = operand & 0x80; + notZ = A; + N = A & 0x80; +} +break; + +case 0x27: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + uInt8 value = (operand << 1) | (C ? 1 : 0); + poke(operandAddress, value); + + A &= value; + C = operand & 0x80; + notZ = A; + N = A & 0x80; +} +break; + +case 0x37: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ + uInt8 value = (operand << 1) | (C ? 1 : 0); + poke(operandAddress, value); + + A &= value; + C = operand & 0x80; + notZ = A; + N = A & 0x80; +} +break; + +case 0x23: +{ + uInt8 pointer = peek(PC++) + X; + operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operand = peek(operandAddress); +} +{ + uInt8 value = (operand << 1) | (C ? 1 : 0); + poke(operandAddress, value); + + A &= value; + C = operand & 0x80; + notZ = A; + N = A & 0x80; +} +break; + +case 0x33: +{ + uInt8 pointer = peek(PC++); + operandAddress = (uInt16)peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operandAddress += Y; + operand = peek(operandAddress); +} +{ + uInt8 value = (operand << 1) | (C ? 1 : 0); + poke(operandAddress, value); + + A &= value; + C = operand & 0x80; + notZ = A; + N = A & 0x80; +} +break; + + +case 0x2a: +{ +} +{ + bool oldC = C; + + // Set carry flag according to the left-most bit + C = A & 0x80; + + A = (A << 1) | (oldC ? 1 : 0); + + notZ = A; + N = A & 0x80; +} +break; + + +case 0x26: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + bool oldC = C; + + // Set carry flag according to the left-most bit in operand + C = operand & 0x80; + + operand = (operand << 1) | (oldC ? 1 : 0); + poke(operandAddress, operand); + + notZ = operand; + N = operand & 0x80; +} +break; + +case 0x36: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ + bool oldC = C; + + // Set carry flag according to the left-most bit in operand + C = operand & 0x80; + + operand = (operand << 1) | (oldC ? 1 : 0); + poke(operandAddress, operand); + + notZ = operand; + N = operand & 0x80; +} +break; + +case 0x2e: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + bool oldC = C; + + // Set carry flag according to the left-most bit in operand + C = operand & 0x80; + + operand = (operand << 1) | (oldC ? 1 : 0); + poke(operandAddress, operand); + + notZ = operand; + N = operand & 0x80; +} +break; + +case 0x3e: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += X; + operand = peek(operandAddress); +} +{ + bool oldC = C; + + // Set carry flag according to the left-most bit in operand + C = operand & 0x80; + + operand = (operand << 1) | (oldC ? 1 : 0); + poke(operandAddress, operand); + + notZ = operand; + N = operand & 0x80; +} +break; + + +case 0x6a: +{ +} +{ + bool oldC = C; + + // Set carry flag according to the right-most bit + C = A & 0x01; + + A = ((A >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); + + notZ = A; + N = A & 0x80; +} +break; + +case 0x66: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + bool oldC = C; + + // Set carry flag according to the right-most bit + C = operand & 0x01; + + operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); + poke(operandAddress, operand); + + notZ = operand; + N = operand & 0x80; +} +break; + +case 0x76: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ + bool oldC = C; + + // Set carry flag according to the right-most bit + C = operand & 0x01; + + operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); + poke(operandAddress, operand); + + notZ = operand; + N = operand & 0x80; +} +break; + +case 0x6e: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + bool oldC = C; + + // Set carry flag according to the right-most bit + C = operand & 0x01; + + operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); + poke(operandAddress, operand); + + notZ = operand; + N = operand & 0x80; +} +break; + +case 0x7e: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += X; + operand = peek(operandAddress); +} +{ + bool oldC = C; + + // Set carry flag according to the right-most bit + C = operand & 0x01; + + operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); + poke(operandAddress, operand); + + notZ = operand; + N = operand & 0x80; +} +break; + + +case 0x6f: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + uInt8 oldA = A; + bool oldC = C; + + // Set carry flag according to the right-most bit + C = operand & 0x01; + + operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); + poke(operandAddress, operand); + + if(!D) + { + Int16 sum = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((sum > 127) || (sum < -128)); + + sum = (Int16)A + (Int16)operand + (C ? 1 : 0); + A = sum; + C = (sum > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 sum = ourBCDTable[0][A] + ourBCDTable[0][operand] + (C ? 1 : 0); + + C = (sum > 99); + A = ourBCDTable[1][sum & 0xff]; + notZ = A; + N = A & 0x80; + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0x7f: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += X; + operand = peek(operandAddress); +} +{ + uInt8 oldA = A; + bool oldC = C; + + // Set carry flag according to the right-most bit + C = operand & 0x01; + + operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); + poke(operandAddress, operand); + + if(!D) + { + Int16 sum = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((sum > 127) || (sum < -128)); + + sum = (Int16)A + (Int16)operand + (C ? 1 : 0); + A = sum; + C = (sum > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 sum = ourBCDTable[0][A] + ourBCDTable[0][operand] + (C ? 1 : 0); + + C = (sum > 99); + A = ourBCDTable[1][sum & 0xff]; + notZ = A; + N = A & 0x80; + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0x7b: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += Y; + operand = peek(operandAddress); +} +{ + uInt8 oldA = A; + bool oldC = C; + + // Set carry flag according to the right-most bit + C = operand & 0x01; + + operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); + poke(operandAddress, operand); + + if(!D) + { + Int16 sum = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((sum > 127) || (sum < -128)); + + sum = (Int16)A + (Int16)operand + (C ? 1 : 0); + A = sum; + C = (sum > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 sum = ourBCDTable[0][A] + ourBCDTable[0][operand] + (C ? 1 : 0); + + C = (sum > 99); + A = ourBCDTable[1][sum & 0xff]; + notZ = A; + N = A & 0x80; + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0x67: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + uInt8 oldA = A; + bool oldC = C; + + // Set carry flag according to the right-most bit + C = operand & 0x01; + + operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); + poke(operandAddress, operand); + + if(!D) + { + Int16 sum = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((sum > 127) || (sum < -128)); + + sum = (Int16)A + (Int16)operand + (C ? 1 : 0); + A = sum; + C = (sum > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 sum = ourBCDTable[0][A] + ourBCDTable[0][operand] + (C ? 1 : 0); + + C = (sum > 99); + A = ourBCDTable[1][sum & 0xff]; + notZ = A; + N = A & 0x80; + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0x77: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ + uInt8 oldA = A; + bool oldC = C; + + // Set carry flag according to the right-most bit + C = operand & 0x01; + + operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); + poke(operandAddress, operand); + + if(!D) + { + Int16 sum = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((sum > 127) || (sum < -128)); + + sum = (Int16)A + (Int16)operand + (C ? 1 : 0); + A = sum; + C = (sum > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 sum = ourBCDTable[0][A] + ourBCDTable[0][operand] + (C ? 1 : 0); + + C = (sum > 99); + A = ourBCDTable[1][sum & 0xff]; + notZ = A; + N = A & 0x80; + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0x63: +{ + uInt8 pointer = peek(PC++) + X; + operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operand = peek(operandAddress); +} +{ + uInt8 oldA = A; + bool oldC = C; + + // Set carry flag according to the right-most bit + C = operand & 0x01; + + operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); + poke(operandAddress, operand); + + if(!D) + { + Int16 sum = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((sum > 127) || (sum < -128)); + + sum = (Int16)A + (Int16)operand + (C ? 1 : 0); + A = sum; + C = (sum > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 sum = ourBCDTable[0][A] + ourBCDTable[0][operand] + (C ? 1 : 0); + + C = (sum > 99); + A = ourBCDTable[1][sum & 0xff]; + notZ = A; + N = A & 0x80; + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0x73: +{ + uInt8 pointer = peek(PC++); + operandAddress = (uInt16)peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operandAddress += Y; + operand = peek(operandAddress); +} +{ + uInt8 oldA = A; + bool oldC = C; + + // Set carry flag according to the right-most bit + C = operand & 0x01; + + operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); + poke(operandAddress, operand); + + if(!D) + { + Int16 sum = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((sum > 127) || (sum < -128)); + + sum = (Int16)A + (Int16)operand + (C ? 1 : 0); + A = sum; + C = (sum > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 sum = ourBCDTable[0][A] + ourBCDTable[0][operand] + (C ? 1 : 0); + + C = (sum > 99); + A = ourBCDTable[1][sum & 0xff]; + notZ = A; + N = A & 0x80; + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + + +case 0x40: +{ +} +{ + peek(0x0100 + SP++); + PS(peek(0x0100 + SP++)); + PC = peek(0x0100 + SP++); + PC |= ((uInt16)peek(0x0100 + SP) << 8); +} +break; + + +case 0x60: +{ +} +{ + peek(0x0100 + SP++); + PC = peek(0x0100 + SP++); + PC |= ((uInt16)peek(0x0100 + SP) << 8); + peek(PC++); +} +break; + + +case 0x8f: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; +} +{ + poke(operandAddress, A & X); +} +break; + +case 0x87: +{ + operandAddress = peek(PC++); +} +{ + poke(operandAddress, A & X); +} +break; + +case 0x97: +{ + operandAddress = (uInt8)(peek(PC++) + Y); +} +{ + poke(operandAddress, A & X); +} +break; + +case 0x83: +{ + uInt8 pointer = peek(PC++) + X; + operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8); +} +{ + poke(operandAddress, A & X); +} +break; + + +case 0xe9: +case 0xeb: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + uInt8 oldA = A; + + if(!D) + { + operand = ~operand; + Int16 difference = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((difference > 127) || (difference < -128)); + + difference = ((Int16)A) + ((Int16)operand) + (C ? 1 : 0); + A = difference; + C = (difference > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 difference = ourBCDTable[0][A] - ourBCDTable[0][operand] + - (C ? 0 : 1); + + if(difference < 0) + difference += 100; + + A = ourBCDTable[1][difference]; + notZ = A; + N = A & 0x80; + + C = (oldA >= (operand + (C ? 0 : 1))); + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0xe5: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + uInt8 oldA = A; + + if(!D) + { + operand = ~operand; + Int16 difference = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((difference > 127) || (difference < -128)); + + difference = ((Int16)A) + ((Int16)operand) + (C ? 1 : 0); + A = difference; + C = (difference > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 difference = ourBCDTable[0][A] - ourBCDTable[0][operand] + - (C ? 0 : 1); + + if(difference < 0) + difference += 100; + + A = ourBCDTable[1][difference]; + notZ = A; + N = A & 0x80; + + C = (oldA >= (operand + (C ? 0 : 1))); + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0xf5: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ + uInt8 oldA = A; + + if(!D) + { + operand = ~operand; + Int16 difference = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((difference > 127) || (difference < -128)); + + difference = ((Int16)A) + ((Int16)operand) + (C ? 1 : 0); + A = difference; + C = (difference > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 difference = ourBCDTable[0][A] - ourBCDTable[0][operand] + - (C ? 0 : 1); + + if(difference < 0) + difference += 100; + + A = ourBCDTable[1][difference]; + notZ = A; + N = A & 0x80; + + C = (oldA >= (operand + (C ? 0 : 1))); + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0xed: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + uInt8 oldA = A; + + if(!D) + { + operand = ~operand; + Int16 difference = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((difference > 127) || (difference < -128)); + + difference = ((Int16)A) + ((Int16)operand) + (C ? 1 : 0); + A = difference; + C = (difference > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 difference = ourBCDTable[0][A] - ourBCDTable[0][operand] + - (C ? 0 : 1); + + if(difference < 0) + difference += 100; + + A = ourBCDTable[1][difference]; + notZ = A; + N = A & 0x80; + + C = (oldA >= (operand + (C ? 0 : 1))); + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0xfd: +{ + 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); +} +{ + uInt8 oldA = A; + + if(!D) + { + operand = ~operand; + Int16 difference = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((difference > 127) || (difference < -128)); + + difference = ((Int16)A) + ((Int16)operand) + (C ? 1 : 0); + A = difference; + C = (difference > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 difference = ourBCDTable[0][A] - ourBCDTable[0][operand] + - (C ? 0 : 1); + + if(difference < 0) + difference += 100; + + A = ourBCDTable[1][difference]; + notZ = A; + N = A & 0x80; + + C = (oldA >= (operand + (C ? 0 : 1))); + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0xf9: +{ + 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); +} +{ + uInt8 oldA = A; + + if(!D) + { + operand = ~operand; + Int16 difference = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((difference > 127) || (difference < -128)); + + difference = ((Int16)A) + ((Int16)operand) + (C ? 1 : 0); + A = difference; + C = (difference > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 difference = ourBCDTable[0][A] - ourBCDTable[0][operand] + - (C ? 0 : 1); + + if(difference < 0) + difference += 100; + + A = ourBCDTable[1][difference]; + notZ = A; + N = A & 0x80; + + C = (oldA >= (operand + (C ? 0 : 1))); + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0xe1: +{ + uInt8 pointer = peek(PC++) + X; + operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operand = peek(operandAddress); +} +{ + uInt8 oldA = A; + + if(!D) + { + operand = ~operand; + Int16 difference = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((difference > 127) || (difference < -128)); + + difference = ((Int16)A) + ((Int16)operand) + (C ? 1 : 0); + A = difference; + C = (difference > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 difference = ourBCDTable[0][A] - ourBCDTable[0][operand] + - (C ? 0 : 1); + + if(difference < 0) + difference += 100; + + A = ourBCDTable[1][difference]; + notZ = A; + N = A & 0x80; + + C = (oldA >= (operand + (C ? 0 : 1))); + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + +case 0xf1: +{ + 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); +} +{ + uInt8 oldA = A; + + if(!D) + { + operand = ~operand; + Int16 difference = (Int16)((Int8)A) + (Int16)((Int8)operand) + (C ? 1 : 0); + V = ((difference > 127) || (difference < -128)); + + difference = ((Int16)A) + ((Int16)operand) + (C ? 1 : 0); + A = difference; + C = (difference > 0xff); + notZ = A; + N = A & 0x80; + } + else + { + Int16 difference = ourBCDTable[0][A] - ourBCDTable[0][operand] + - (C ? 0 : 1); + + if(difference < 0) + difference += 100; + + A = ourBCDTable[1][difference]; + notZ = A; + N = A & 0x80; + + C = (oldA >= (operand + (C ? 0 : 1))); + V = ((oldA ^ A) & 0x80) && ((A ^ operand) & 0x80); + } +} +break; + + +case 0xcb: +{ + operandAddress = PC++; + operand = peek(operandAddress); +} +{ + uInt16 value = (uInt16)(X & A) - (uInt16)operand; + X = (value & 0xff); + + notZ = X; + N = X & 0x80; + C = !(value & 0x0100); +} +break; + + +case 0x38: +{ +} +{ + C = true; +} +break; + + +case 0xf8: +{ +} +{ + D = true; +} +break; + + +case 0x78: +{ +} +{ + I = true; +} +break; + + +case 0x9f: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += Y; +} +{ + // NOTE: There are mixed reports on the actual operation + // of this instruction! + poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1)); +} +break; + +case 0x93: +{ + uInt8 pointer = peek(PC++); + operandAddress = (uInt16)peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operandAddress += Y; +} +{ + // NOTE: There are mixed reports on the actual operation + // of this instruction! + poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1)); +} +break; + + +case 0x9b: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += Y; +} +{ + // NOTE: There are mixed reports on the actual operation + // of this instruction! + SP = A & X; + poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1)); +} +break; + + +case 0x9e: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += Y; +} +{ + // NOTE: There are mixed reports on the actual operation + // of this instruction! + poke(operandAddress, X & (((operandAddress >> 8) & 0xff) + 1)); +} +break; + + +case 0x9c: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += X; +} +{ + // NOTE: There are mixed reports on the actual operation + // of this instruction! + poke(operandAddress, Y & (((operandAddress >> 8) & 0xff) + 1)); +} +break; + + +case 0x0f: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + // Set carry flag according to the left-most bit in value + C = operand & 0x80; + + operand <<= 1; + poke(operandAddress, operand); + + A |= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x1f: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += X; + operand = peek(operandAddress); +} +{ + // Set carry flag according to the left-most bit in value + C = operand & 0x80; + + operand <<= 1; + poke(operandAddress, operand); + + A |= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x1b: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += Y; + operand = peek(operandAddress); +} +{ + // Set carry flag according to the left-most bit in value + C = operand & 0x80; + + operand <<= 1; + poke(operandAddress, operand); + + A |= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x07: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + // Set carry flag according to the left-most bit in value + C = operand & 0x80; + + operand <<= 1; + poke(operandAddress, operand); + + A |= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x17: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ + // Set carry flag according to the left-most bit in value + C = operand & 0x80; + + operand <<= 1; + poke(operandAddress, operand); + + A |= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x03: +{ + uInt8 pointer = peek(PC++) + X; + operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operand = peek(operandAddress); +} +{ + // Set carry flag according to the left-most bit in value + C = operand & 0x80; + + operand <<= 1; + poke(operandAddress, operand); + + A |= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x13: +{ + uInt8 pointer = peek(PC++); + operandAddress = (uInt16)peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operandAddress += Y; + operand = peek(operandAddress); +} +{ + // Set carry flag according to the left-most bit in value + C = operand & 0x80; + + operand <<= 1; + poke(operandAddress, operand); + + A |= operand; + notZ = A; + N = A & 0x80; +} +break; + + +case 0x4f: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operand = peek(operandAddress); +} +{ + // Set carry flag according to the right-most bit in value + C = operand & 0x01; + + operand = (operand >> 1) & 0x7f; + poke(operandAddress, operand); + + A ^= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x5f: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += X; + operand = peek(operandAddress); +} +{ + // Set carry flag according to the right-most bit in value + C = operand & 0x01; + + operand = (operand >> 1) & 0x7f; + poke(operandAddress, operand); + + A ^= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x5b: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += Y; + operand = peek(operandAddress); +} +{ + // Set carry flag according to the right-most bit in value + C = operand & 0x01; + + operand = (operand >> 1) & 0x7f; + poke(operandAddress, operand); + + A ^= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x47: +{ + operandAddress = peek(PC++); + operand = peek(operandAddress); +} +{ + // Set carry flag according to the right-most bit in value + C = operand & 0x01; + + operand = (operand >> 1) & 0x7f; + poke(operandAddress, operand); + + A ^= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x57: +{ + operandAddress = (uInt8)(peek(PC++) + X); + operand = peek(operandAddress); +} +{ + // Set carry flag according to the right-most bit in value + C = operand & 0x01; + + operand = (operand >> 1) & 0x7f; + poke(operandAddress, operand); + + A ^= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x43: +{ + uInt8 pointer = peek(PC++) + X; + operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operand = peek(operandAddress); +} +{ + // Set carry flag according to the right-most bit in value + C = operand & 0x01; + + operand = (operand >> 1) & 0x7f; + poke(operandAddress, operand); + + A ^= operand; + notZ = A; + N = A & 0x80; +} +break; + +case 0x53: +{ + uInt8 pointer = peek(PC++); + operandAddress = (uInt16)peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operandAddress += Y; + operand = peek(operandAddress); +} +{ + // Set carry flag according to the right-most bit in value + C = operand & 0x01; + + operand = (operand >> 1) & 0x7f; + poke(operandAddress, operand); + + A ^= operand; + notZ = A; + N = A & 0x80; +} +break; + + +case 0x85: +{ + operandAddress = peek(PC++); +} +{ + poke(operandAddress, A); +} +break; + +case 0x95: +{ + operandAddress = (uInt8)(peek(PC++) + X); +} +{ + poke(operandAddress, A); +} +break; + +case 0x8d: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; +} +{ + poke(operandAddress, A); +} +break; + +case 0x9d: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += X; +} +{ + poke(operandAddress, A); +} +break; + +case 0x99: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; + operandAddress += Y; +} +{ + poke(operandAddress, A); +} +break; + +case 0x81: +{ + uInt8 pointer = peek(PC++) + X; + operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8); +} +{ + poke(operandAddress, A); +} +break; + +case 0x91: +{ + uInt8 pointer = peek(PC++); + operandAddress = (uInt16)peek(pointer) | ((uInt16)peek(pointer + 1) << 8); + operandAddress += Y; +} +{ + poke(operandAddress, A); +} +break; + + +case 0x86: +{ + operandAddress = peek(PC++); +} +{ + poke(operandAddress, X); +} +break; + +case 0x96: +{ + operandAddress = (uInt8)(peek(PC++) + Y); +} +{ + poke(operandAddress, X); +} +break; + +case 0x8e: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; +} +{ + poke(operandAddress, X); +} +break; + + +case 0x84: +{ + operandAddress = peek(PC++); +} +{ + poke(operandAddress, Y); +} +break; + +case 0x94: +{ + operandAddress = (uInt8)(peek(PC++) + X); +} +{ + poke(operandAddress, Y); +} +break; + +case 0x8c: +{ + operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8); + PC += 2; +} +{ + poke(operandAddress, Y); +} +break; + + +case 0xaa: +{ +} +{ + X = A; + notZ = X; + N = X & 0x80; +} +break; + + +case 0xa8: +{ +} +{ + Y = A; + notZ = Y; + N = Y & 0x80; +} +break; + + +case 0xba: +{ +} +{ + X = SP; + notZ = X; + N = X & 0x80; +} +break; + + +case 0x8a: +{ +} +{ + A = X; + notZ = A; + N = A & 0x80; +} +break; + + +case 0x9a: +{ +} +{ + SP = X; +} +break; + + +case 0x98: +{ +} +{ + A = Y; + notZ = A; + N = A & 0x80; +} +break; + + diff --git a/stella/src/emucore/m6502/src/M6502Low.m4 b/stella/src/emucore/m6502/src/M6502Low.m4 new file mode 100644 index 000000000..e26495b6b --- /dev/null +++ b/stella/src/emucore/m6502/src/M6502Low.m4 @@ -0,0 +1,286 @@ +//============================================================================ +// +// 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: M6502Low.m4,v 1.4 2006-02-05 02:49:47 stephena Exp $ +//============================================================================ + +/** + Code to handle addressing modes and branch instructions for + low compatibility emulation + + @author Bradford W. Mott + @version $Id: M6502Low.m4,v 1.4 2006-02-05 02:49:47 stephena Exp $ +*/ + +#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; + } +}') + + diff --git a/stella/src/emucore/m6502/src/System.cxx b/stella/src/emucore/m6502/src/System.cxx index 39b95373e..a537c5100 100644 --- a/stella/src/emucore/m6502/src/System.cxx +++ b/stella/src/emucore/m6502/src/System.cxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: System.cxx,v 1.16 2005-12-29 21:16:28 stephena Exp $ +// $Id: System.cxx,v 1.17 2006-02-05 02:49:47 stephena Exp $ //============================================================================ #include @@ -318,8 +318,10 @@ uInt8 System::peek(uInt16 addr) result = access.device->peek(addr); } +#ifdef DEVELOPER_SUPPORT if(!myDataBusLocked) myDataBusState = result; +#endif return result; } @@ -339,8 +341,10 @@ void System::poke(uInt16 addr, uInt8 value) access.device->poke(addr, value); } +#ifdef DEVELOPER_SUPPORT if(!myDataBusLocked) myDataBusState = value; +#endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -354,4 +358,3 @@ void System::unlockDataBus() { myDataBusLocked = false; } - diff --git a/stella/src/emucore/m6502/src/System.hxx b/stella/src/emucore/m6502/src/System.hxx index d9193a3cb..fb4f9b888 100644 --- a/stella/src/emucore/m6502/src/System.hxx +++ b/stella/src/emucore/m6502/src/System.hxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: System.hxx,v 1.12 2005-12-09 19:09:49 stephena Exp $ +// $Id: System.hxx,v 1.13 2006-02-05 02:49:47 stephena Exp $ //============================================================================ #ifndef SYSTEM_HXX @@ -47,7 +47,7 @@ class Deserializer; dynamic code for that page of memory. @author Bradford W. Mott - @version $Id: System.hxx,v 1.12 2005-12-09 19:09:49 stephena Exp $ + @version $Id: System.hxx,v 1.13 2006-02-05 02:49:47 stephena Exp $ */ class System { @@ -207,7 +207,7 @@ class System @return The number of system cycles which have passed */ - uInt32 cycles() const + inline uInt32 cycles() const { return myCycles; } @@ -217,7 +217,7 @@ class System @param amount The amount to add to the system cycles counter */ - void incrementCycles(uInt32 amount) + inline void incrementCycles(uInt32 amount) { myCycles += amount; } diff --git a/stella/src/gp2x/SettingsGP2X.cxx b/stella/src/gp2x/SettingsGP2X.cxx index bb8bdba36..ead0bb699 100644 --- a/stella/src/gp2x/SettingsGP2X.cxx +++ b/stella/src/gp2x/SettingsGP2X.cxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: SettingsGP2X.cxx,v 1.4 2006-01-30 01:01:44 stephena Exp $ +// $Id: SettingsGP2X.cxx,v 1.5 2006-02-05 02:49:46 stephena Exp $ // Modified on 2006/01/04 by Alex Zaballa for use on GP2X //============================================================================ @@ -35,7 +35,8 @@ SettingsGP2X::SettingsGP2X(OSystem* osystem) set("tiafreq", "22050"); set("clipvol", "false"); set("joymouse", "true"); - set("pp", "no"); // always disable phosphor until we get a faster framebuffer + set("pp", "no"); // always disable phosphor until we get a faster framebuffer + set("cpu", "low"); // use lower-compatibility CPU emulation for more speed } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -