enum Addressing { eImmediate, eAccumulator, eAbsolute, eAbsoluteIndexedX, eAbsoluteIndexedY, eZeroPage, eZeroPageIndexedX, eZeroPageIndexedY, eIndexedIndirect, eIndirectIndexed, eImplied, eIndirectAbsolute, eRelative }; typedef int Addressing; //Holds address of current instruction. void (*current_instruction)(Addressing, address); struct AddData{ int cycles; int length; byte value; }; AddData fAddress(Addressing addr, short x) { AddData ret; // VALUE switch(addr){ case eImmediate: ret.value = x; break; case eAccumulator: ret.value = acc; break; case eAbsolute: ret.value = Memory[x]; break; case eAbsoluteIndexedX: ret.value = Memory[(x + X)]; break; case eAbsoluteIndexedY: ret.value = Memory[(x + Y)]; break; case eZeroPage: ret.value = Memory[(x & 0x00FF)]; break; case eZeroPageIndexedX: ret.value = Memory[((x + X) & 0x00FF)]; break; case eZeroPageIndexedY: ret.value = Memory[((x + Y) & 0x00FF)]; break; case eIndexedIndirect: ret.value = Memory[ (((address)Memory[x+X+1])<<8) + (Memory[x+X]) ]; break; case eIndirectIndexed: ret.value = Memory[ (((address)Memory[x+1])<<8) + (Memory[x]) + Y ]; break; } // LENGTH switch(addr){ case eAbsolute: case eAbsoluteIndexedX: case eAbsoluteIndexedY: ret.length = 3; break; case eAccumulator: ret.length = 1; break; default: ret.length = 2; break; } // CYCLES switch(current_function){ // Initial value case &fADC: case &fAND: case &fBIT: case &fCMP: case &fCPX: case &fCPY: case &fEOR: case &fLDA: case &fLDX: case &fLDY: case &fORA: case &fSBC: case &fSTX: case &fSTY: switch(addr){ case eImmediate: ret.cycles = 2; break; case eZeroPage: ret.cycles = 3; break; case eZeroPageIndexedX: case eAbsolute: case eAbsoluteIndexedX: case eAbsoluteIndexedY: ret.cycles = 4; break; case eIndexedIndirect: ret.cycles = 6; break; case eIndirectIndexed: ret.cycles = 5; break; } break; case &fASL: case &fDEC: case &fINC: case &fLSR: case &fROL: case &fROR: switch(addr){ case eAccumulator: ret.cycles = 2; break; case eZeroPage: ret.cycles = 5; break; case eZeroPageIndexedX: case eAbsolute: ret.cycles = 6; break; case eAbsoluteIndexedX: ret.cycles = 7; break; } break; case &fSTA: switch(addr){ case eZeroPage: ret.cycles = 3; break; case eZeroPageIndexedX: case eAbsolute: ret.cycles = 4; break; case eAbsoluteIndexedX: case eAbsoluteIndexedY: ret.cycles = 5; break; case eIndexedIndirect: case eIndirectIndexed: ret.cycles = 6; break; } break; case &fBRK: ret.cycles = 7; break; case &RTI: case &RTS: case &JSR: ret.cycles = 6; break; case &fJMP: ret.cycles = 5; break; case &fPLA: case &fPLP: ret.cycles = 4; break; case &fPHA: case &fPHP: ret.cycles = 3; break; default: //Any instruction which doesn't fit any of these conditions is probably an implied/relative mode instruction which costs 2 cycles ret.cycles = 2; } switch(current_function){ // Page Boundary case &fADC: case &fSBC: case &fLDA: case &fLDX: case &fLDY: case &fEOR: case &fAND: case &fORA: case &fCMP: switch(addr){ case eAbsoluteIndexedX: if ((x & 0xFFFC) != ((x + X) & 0xFFFC)) ret.cycles++; break; case eAbsoluteIndexedY: if ((x & 0xFFFC) != ((x + Y) & 0xFFFC)) ret.cycles++; break; case eIndirectIndexed: //I am not 100% sure if this is the correct handling a page boundary cross with indirect indexed addressing. also its kinda ugly if( (((((address)Memory[x+1])<<8) + (Memory[x]) + Y) & 0xFFFC) != (((((address)Memory[x+1])<<8) + (Memory[x])) & 0xFFFC)) ret.cycles++; break; } } }