#define DEF(BITS) \ static inline Word MOS6502_ROR##BITS(struct MOS6502* self, Word opcode) { \ Word value = MOS6502_loadValue(self, opcode)&BITS_MAXVALUE; \ Word p = P; \ if(value&0x01) \ SET_P(P | F_Carry##BITS); \ else \ SET_P(P &~ F_Carry##BITS); \ value >>= 1; \ value |= (p & F_Carry##BITS) ? (((BITS_MAXVALUE - 1)>>1) + 1)/*HIGHBIT*/ : 0; \ MOS6502_storeValue(self, opcode, value); \ MOS6502_updateFlags(self, value); \ return NEW_PC; \ } \ static inline Word MOS6502_INC##BITS(struct MOS6502* self, Word opcode) { \ Word value = MOS6502_loadValue(self, opcode)&BITS_MAXVALUE; \ if(value == BITS_MAXVALUE) \ value = 0; \ else \ ++value; \ MOS6502_storeValue(self, opcode, value); \ MOS6502_updateFlags(self, value); \ return NEW_PC; \ } \ static inline Word MOS6502_ADC##BITS(struct MOS6502* self, Word opcode) { \ if((opcode&2) == 2) { /* emulate invalid instruction RRA */ \ MOS6502_ROR##BITS(self, opcode); \ /* fallthrough */ \ } \ if((P&F_Decimal) != 0) \ return MOS6502_ADC_decimal(self, opcode); \ SET_P(P&~F_Overflow##BITS); \ Word a = A&BITS_MAXVALUE; \ Word b = MOS6502_loadValue(self, opcode)&BITS_MAXVALUE; \ Word r = (a + b)&BITS_MAXVALUE; \ int nc = (r < a && r < b); \ if(P&F_Carry##BITS) { \ r = (r + 1)&BITS_MAXVALUE; \ if(r == 0) \ nc = 1; \ } \ if(nc) \ SET_P(P | F_Carry##BITS); \ else \ SET_P(P &~ F_Carry##BITS); \ int bOverflow = (negative##BITS##P(b) == negative##BITS##P(a)) && (negative##BITS##P(r) != negative##BITS##P(a)); \ if(bOverflow) \ SET_P(P | F_Overflow##BITS); \ SET_A(r); \ return NEW_PC; \ } \ static inline Word MOS6502_SBC##BITS(struct MOS6502* self, Word opcode) { \ if((opcode&2) == 2) { /* emulate invalid instruction INS */ \ MOS6502_INC##BITS(self, opcode); \ /* fallthrough */ \ } \ if(P&F_Decimal) \ return MOS6502_SBC_decimal(self, opcode); \ SET_P(P&~F_Overflow##BITS); \ Word v; \ Word a = A&BITS_MAXVALUE; \ Word s = MOS6502_loadValue(self, opcode)&BITS_MAXVALUE; \ int nc = (s <= a); \ Word r = (a - s)&BITS_MAXVALUE; \ if((P&F_Carry##BITS) == 0) { \ if(r == 0) \ nc = 0; \ r = (r - 1)&BITS_MAXVALUE; \ } \ SET_A(r); \ v = negative##BITS##P(a ^ s) && negative##BITS##P(a ^ r); /* FIXME */ \ if(nc) \ SET_P(P | F_Carry##BITS); \ else \ SET_P(P&~F_Carry##BITS); \ if(v) \ SET_P(P | F_Overflow##BITS); \ return NEW_PC; \ } \ static inline Word MOS6502_ASL##BITS(struct MOS6502* self, Word opcode) { \ Word value = MOS6502_loadValue(self, opcode); \ if(negative##BITS##P(value)) \ SET_P(P | F_Carry##BITS); \ else \ SET_P(P&~F_Carry##BITS); \ value = (value << 1)&BITS_MAXVALUE; \ MOS6502_storeValue(self, opcode, value); \ MOS6502_updateFlags(self, value); \ return NEW_PC; \ } \ static inline Word MOS6502_ROL##BITS(struct MOS6502* self, Word opcode) { \ Word value = MOS6502_loadValue(self, opcode)&BITS_MAXVALUE; \ Word p = P; \ if(negative##BITS##P(value)) \ SET_P(P | F_Carry##BITS); \ else \ SET_P(P &~ F_Carry##BITS); \ value = (value << 1)&BITS_MAXVALUE; \ value |= (p & F_Carry##BITS) ? 1 : 0; \ MOS6502_storeValue(self, opcode, value); \ MOS6502_updateFlags(self, value); \ return NEW_PC; \ } \ static inline Word MOS6502_LSR##BITS(struct MOS6502* self, Word opcode) { \ Word value = MOS6502_loadValue(self, opcode)&BITS_MAXVALUE; \ if(value&0x01) \ SET_P(P | F_Carry##BITS); \ else \ SET_P(P &~ F_Carry##BITS); \ value >>= 1; \ MOS6502_storeValue(self, opcode, value); \ MOS6502_updateFlags(self, value); \ return NEW_PC; \ } \ static inline Word MOS6502_DEC##BITS(struct MOS6502* self, Word opcode) { \ Word value = MOS6502_loadValue(self, opcode)&BITS_MAXVALUE; \ if(value == 0) \ value = BITS_MAXVALUE; \ else \ --value; \ MOS6502_storeValue(self, opcode, value); \ MOS6502_updateFlags(self, value); \ return NEW_PC; \ } \ static inline Word MOS6502_DEX##BITS(struct MOS6502* self, Word opcode) { \ Word value = X&BITS_MAXVALUE; \ if(value == 0) \ value = BITS_MAXVALUE; \ else \ --value; \ SET_X(value); \ return NEW_PC; \ } \ static inline Word MOS6502_DEY##BITS(struct MOS6502* self, Word opcode) { \ Word value = Y&BITS_MAXVALUE; \ if(value == 0) \ value = BITS_MAXVALUE; \ else \ --value; \ SET_Y(value); \ return NEW_PC; \ } \ static inline Word MOS6502_INY##BITS(struct MOS6502* self, Word opcode) { \ Word value = Y&BITS_MAXVALUE; \ if(value == BITS_MAXVALUE) \ value = 0; \ else \ ++value; \ SET_Y(value); \ return NEW_PC; \ } \ static inline Word MOS6502_INX##BITS(struct MOS6502* self, Word opcode) { \ /* does NOT affect carry */ \ Word value = X&BITS_MAXVALUE; \ if(value == BITS_MAXVALUE) \ value = 0; \ else \ ++value; \ SET_X(value); \ return NEW_PC; \ } \ static inline Word MOS6502_CMP##BITS(struct MOS6502* self, Word opcode) { \ switch(opcode) { \ case 0xCF: \ case 0xDF: \ case 0xDB: \ case 0xC7: \ case 0xD7: \ case 0xC3: \ case 0xD3: /* emulate invalid instruction DCM / DCP */ \ MOS6502_DEC##BITS(self, opcode); \ /* fallthrough */ \ } \ Word a = A&BITS_MAXVALUE; \ Word b = MOS6502_loadValue(self, opcode)&BITS_MAXVALUE; \ MOS6502_compare(self, a, b); \ if(a < b) \ SET_P(P &~ F_Carry##BITS); \ else \ SET_P(P | F_Carry##BITS); \ return NEW_PC; \ } \ static inline Word MOS6502_CPX##BITS(struct MOS6502* self, Word opcode) { \ Word a = X&BITS_MAXVALUE; \ Word b = MOS6502_loadValue(self, opcode)&BITS_MAXVALUE; \ MOS6502_compare(self, a, b); \ if(a < b) \ SET_P(P &~ F_Carry##BITS); \ else \ SET_P(P | F_Carry##BITS); \ return NEW_PC; \ } \ static inline Word MOS6502_CPY##BITS(struct MOS6502* self, Word opcode) { \ Word a = Y&BITS_MAXVALUE; \ Word b = MOS6502_loadValue(self, opcode)&BITS_MAXVALUE; \ MOS6502_compare(self, a, b); \ if(a < b) \ SET_P(P &~ F_Carry##BITS); \ else \ SET_P(P | F_Carry##BITS); \ return NEW_PC; \ } \ static Word MOS6502_BPL##BITS(struct MOS6502* self, Word opcode) { \ BRANCH_COND(opcode, (P&F_Negative##BITS) == 0); \ } \ static Word MOS6502_BMI##BITS(struct MOS6502* self, Word opcode) { \ BRANCH_COND(opcode, (P&F_Negative##BITS) != 0); \ } \ static Word MOS6502_BVC##BITS(struct MOS6502* self, Word opcode) { \ BRANCH_COND(opcode, (P&(F_Overflow##BITS | F_Overflowline)) == 0); \ } \ static Word MOS6502_BVS##BITS(struct MOS6502* self, Word opcode) { \ BRANCH_COND(opcode, (P&(F_Overflow##BITS | F_Overflowline)) != 0); \ } \ static Word MOS6502_BCC##BITS(struct MOS6502* self, Word opcode) { \ BRANCH_COND(opcode, (P&F_Carry##BITS) == 0); \ } \ static Word MOS6502_BCS##BITS(struct MOS6502* self, Word opcode) { \ BRANCH_COND(opcode, (P&F_Carry##BITS) != 0); \ } \ static Word MOS6502_BNE##BITS(struct MOS6502* self, Word opcode) { \ BRANCH_COND(opcode, (P&F_Zero##BITS) == 0); \ } \ static Word MOS6502_BEQ##BITS(struct MOS6502* self, Word opcode) { \ BRANCH_COND(opcode, (P&F_Zero##BITS) != 0); \ } \ static Word MOS6502_ALR##BITS(struct MOS6502* self, Word opcode) { /* invalid instruction */ \ /* should be CLC, AND, LSR but doesn't work that way */ \ Word value = MOS6502_loadValue(self, opcode)&BITS_MAXVALUE; \ value &= A; \ if((value&1) != 0) \ SET_P(P | F_Carry##BITS); \ else \ SET_P(P&~F_Carry##BITS); \ SET_A(value >> 1); \ return NEW_PC; \ } \ static Word MOS6502_ARR##BITS(struct MOS6502* self, Word opcode) { /* invalid instruction */ /* immediate only */ \ Word value = MOS6502_loadValue(self, opcode)&BITS_MAXVALUE; \ value &= A; \ if((P&F_Decimal) != 0) { \ Word value2 = value; \ Word p = P; \ value2 >>= 1; \ value2 |= (p&F_Carry##BITS) ? (((BITS_MAXVALUE - 1)>>1) + 1)/*HIGHBIT*/ : 0; \ if((value2 ^ value)&0x40) \ SET_P(P | F_Overflow##BITS); \ else \ SET_P(P&~F_Overflow##BITS); \ int z = value2 == 0; \ if((value&0xF) + (value&0x1) > 5) \ value2 = (value2&0xF0) | ((value2 + 0x06)&0x0F); \ if((value&0xF0) + (value&0x10) > 0x50) { \ value2 = (value2&0x0F) | ((value2 + 0x60)&0xF0); \ SET_P(P | F_Carry##BITS); \ } else \ SET_P(P&~F_Carry##BITS); \ A = value2; \ if(p&F_Carry##BITS) \ SET_P(P | F_Negative##BITS); \ else \ SET_P(P&~F_Negative##BITS); \ if(z) \ SET_P(P | F_Zero##BITS); \ else \ SET_P(P&~F_Zero##BITS); \ } else { \ value >>= 1; \ value |= (P&F_Carry##BITS) ? (((BITS_MAXVALUE - 1)>>1) + 1)/*HIGHBIT*/ : 0; \ SET_A(value); \ if((value&0x40) != 0) \ SET_P(P | F_Carry##BITS); \ else \ SET_P(P&~F_Carry##BITS); \ if((((value&0x40) != 0) ^ ((value&0x20) << 1)) != 0) \ SET_P(P | F_Overflow##BITS); \ else \ SET_P(P & ~ F_Overflow##BITS); \ } \ return NEW_PC; \ } \ static inline Word MOS6502_SAX##BITS(struct MOS6502* self, Word opcode) { /* invalid instruction */ \ Word a = A&X&BITS_MAXVALUE; \ Word b = MOS6502_loadValue(self, opcode)&BITS_MAXVALUE; \ Word r = (a - b)&BITS_MAXVALUE; \ MOS6502_compare(self, a, b); \ if(a < b) \ SET_P(P &~ F_Carry##BITS); \ else \ SET_P(P | F_Carry##BITS); \ SET_X(r); \ return NEW_PC; \ } \ static Word MOS6502_SinvalidA##BITS(struct MOS6502* self, Word opcode, Word value) { /* invalid instruction */ \ /* only abs x addressing mode used */ \ /* this still doesn't work and also this instruction is evil and whoever uses is should feel bad. */ \ Word m = (((MOS6502_loadValue(self, 0x4C/*immediate 16*/) + X)>>8) + 1)&BITS_MAXVALUE; \ value &= m; \ MOS6502_storeValue(self, opcode, value); \ return NEW_PC; \ }