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 } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -