ref: 2b7e9f69fbd3802da36575de0bd7c8cb5a3716a8
dir: /snes/cpu.c/
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <stdbool.h> #include <assert.h> #include <stddef.h> #include "cpu.h" #include "snes.h" static const int cyclesPerOpcode[256] = { 7, 6, 7, 4, 5, 3, 5, 6, 3, 2, 2, 4, 6, 4, 6, 5, 2, 5, 5, 7, 5, 4, 6, 6, 2, 4, 2, 2, 6, 4, 7, 5, 6, 6, 8, 4, 3, 3, 5, 6, 4, 2, 2, 5, 4, 4, 6, 5, 2, 5, 5, 7, 4, 4, 6, 6, 2, 4, 2, 2, 4, 4, 7, 5, 6, 6, 2, 4, 7, 3, 5, 6, 3, 2, 2, 3, 3, 4, 6, 5, 2, 5, 5, 7, 7, 4, 6, 6, 2, 4, 3, 2, 4, 4, 7, 5, 6, 6, 6, 4, 3, 3, 5, 6, 4, 2, 2, 6, 5, 4, 6, 5, 2, 5, 5, 7, 4, 4, 6, 6, 2, 4, 4, 2, 6, 4, 7, 5, 3, 6, 4, 4, 3, 3, 3, 6, 2, 2, 2, 3, 4, 4, 4, 5, 2, 6, 5, 7, 4, 4, 4, 6, 2, 5, 2, 2, 4, 5, 5, 5, 2, 6, 2, 4, 3, 3, 3, 6, 2, 2, 2, 4, 4, 4, 4, 5, 2, 5, 5, 7, 4, 4, 4, 6, 2, 4, 2, 2, 4, 4, 4, 5, 2, 6, 3, 4, 3, 3, 5, 6, 2, 2, 2, 3, 4, 4, 6, 5, 2, 5, 5, 7, 6, 4, 6, 6, 2, 4, 3, 3, 6, 4, 7, 5, 2, 6, 3, 4, 3, 3, 5, 6, 2, 2, 2, 3, 4, 4, 6, 5, 2, 5, 5, 7, 5, 4, 6, 6, 2, 4, 4, 2, 8, 4, 7, 5 }; static uint8_t cpu_read(Cpu* cpu, uint32_t adr); static void cpu_write(Cpu* cpu, uint32_t adr, uint8_t val); static uint8_t cpu_readOpcode(Cpu* cpu); static uint16_t cpu_readOpcodeWord(Cpu* cpu); void cpu_setFlags(Cpu* cpu, uint8_t value); static void cpu_setZN(Cpu* cpu, uint16_t value, bool byte); static void cpu_doBranch(Cpu* cpu, uint8_t value, bool check); static uint8_t cpu_pullByte(Cpu* cpu); static void cpu_pushByte(Cpu* cpu, uint8_t value); static uint16_t cpu_pullWord(Cpu* cpu); static void cpu_pushWord(Cpu* cpu, uint16_t value); static uint16_t cpu_readWord(Cpu* cpu, uint32_t adrl, uint32_t adrh); static void cpu_writeWord(Cpu* cpu, uint32_t adrl, uint32_t adrh, uint16_t value, bool reversed); static void cpu_doInterrupt(Cpu* cpu, bool irq); static void cpu_doOpcode(Cpu* cpu, uint8_t opcode); // addressing modes and opcode functions not declared, only used after defintions static uint8_t cpu_read(Cpu* cpu, uint32_t adr) { // assume mem is a pointer to a Snes return snes_cpuRead((Snes*) cpu->mem, adr); } static void cpu_write(Cpu* cpu, uint32_t adr, uint8_t val) { // assume mem is a pointer to a Snes snes_cpuWrite((Snes*) cpu->mem, adr, val); } Cpu* cpu_init(void* mem, int memType) { Cpu* cpu = (Cpu * )malloc(sizeof(Cpu)); cpu->mem = mem; cpu->memType = memType; return cpu; } void cpu_free(Cpu* cpu) { free(cpu); } void cpu_reset(Cpu* cpu) { cpu->a = 0; cpu->x = 0; cpu->y = 0; cpu->sp = 0x100; cpu->pc = cpu_read(cpu, 0xfffc) | (cpu_read(cpu, 0xfffd) << 8); cpu->dp = 0; cpu->k = 0; cpu->db = 0; cpu->c = false; cpu->z = false; cpu->v = false; cpu->n = false; cpu->i = true; cpu->d = false; cpu->xf = true; cpu->mf = true; cpu->e = true; cpu->irqWanted = false; cpu->nmiWanted = false; cpu->waiting = false; cpu->stopped = false; cpu->cyclesUsed = 0; cpu->spBreakpoint = 0x0; cpu->in_emu = 0; } void cpu_saveload(Cpu *cpu, SaveLoadFunc *func, void *ctx) { func(ctx, &cpu->a, offsetof(Cpu, cyclesUsed) - offsetof(Cpu, a)); cpu->spBreakpoint = 0x0; } int cpu_runOpcode(Cpu* cpu) { cpu->cyclesUsed = 0; if(cpu->stopped) return 1; if(cpu->waiting) { if(cpu->irqWanted || cpu->nmiWanted) { cpu->waiting = false; } return 1; } // not stopped or waiting, execute a opcode or go to interrupt if((!cpu->i && cpu->irqWanted) || cpu->nmiWanted) { if (cpu->in_emu) { printf("nmi while in emu!\n"); } cpu->cyclesUsed = 7; // interrupt: at least 7 cycles if(cpu->nmiWanted) { cpu->nmiWanted = false; cpu_doInterrupt(cpu, false); } else { // must be irq cpu_doInterrupt(cpu, true); } } else { uint8_t opcode = cpu_readOpcode(cpu); cpu->cyclesUsed = cyclesPerOpcode[opcode]; cpu_doOpcode(cpu, opcode); } return cpu->cyclesUsed; } static uint8_t cpu_readOpcode(Cpu* cpu) { return cpu_read(cpu, (cpu->k << 16) | cpu->pc++); } static uint16_t cpu_readOpcodeWord(Cpu* cpu) { uint8_t low = cpu_readOpcode(cpu); return low | (cpu_readOpcode(cpu) << 8); } uint8_t cpu_getFlags(Cpu* cpu) { uint8_t val = cpu->n << 7; val |= cpu->v << 6; val |= cpu->mf << 5; val |= cpu->xf << 4; val |= cpu->d << 3; val |= cpu->i << 2; val |= cpu->z << 1; val |= (uint8_t)cpu->c; return val; } void cpu_setFlags(Cpu* cpu, uint8_t val) { cpu->n = val & 0x80; cpu->v = val & 0x40; cpu->mf = val & 0x20; cpu->xf = val & 0x10; cpu->d = val & 8; cpu->i = val & 4; cpu->z = val & 2; cpu->c = val & 1; if(cpu->e) { cpu->mf = true; cpu->xf = true; cpu->sp = (cpu->sp & 0xff) | 0x100; } if(cpu->xf) { cpu->x &= 0xff; cpu->y &= 0xff; } } static void cpu_setZN(Cpu* cpu, uint16_t value, bool byte) { if(byte) { cpu->z = (value & 0xff) == 0; cpu->n = value & 0x80; } else { cpu->z = value == 0; cpu->n = value & 0x8000; } } static void cpu_doBranch(Cpu* cpu, uint8_t value, bool check) { if(check) { cpu->cyclesUsed++; // taken branch: 1 extra cycle cpu->pc += (int8_t) value; } } static uint8_t cpu_pullByte(Cpu* cpu) { cpu->sp++; if(cpu->e) cpu->sp = (cpu->sp & 0xff) | 0x100; return cpu_read(cpu, cpu->sp); } static void cpu_pushByte(Cpu* cpu, uint8_t value) { cpu_write(cpu, cpu->sp, value); cpu->sp--; if(cpu->e) cpu->sp = (cpu->sp & 0xff) | 0x100; } static uint16_t cpu_pullWord(Cpu* cpu) { uint8_t value = cpu_pullByte(cpu); return value | (cpu_pullByte(cpu) << 8); } static void cpu_pushWord(Cpu* cpu, uint16_t value) { cpu_pushByte(cpu, value >> 8); cpu_pushByte(cpu, value & 0xff); } static uint16_t cpu_readWord(Cpu* cpu, uint32_t adrl, uint32_t adrh) { uint8_t value = cpu_read(cpu, adrl); return value | (cpu_read(cpu, adrh) << 8); } static void cpu_writeWord(Cpu* cpu, uint32_t adrl, uint32_t adrh, uint16_t value, bool reversed) { if(reversed) { cpu_write(cpu, adrh, value >> 8); cpu_write(cpu, adrl, value & 0xff); } else { cpu_write(cpu, adrl, value & 0xff); cpu_write(cpu, adrh, value >> 8); } } static void cpu_doInterrupt(Cpu* cpu, bool irq) { cpu_pushByte(cpu, cpu->k); cpu_pushWord(cpu, cpu->pc); cpu_pushByte(cpu, cpu_getFlags(cpu)); cpu->cyclesUsed++; // native mode: 1 extra cycle cpu->i = true; cpu->d = false; cpu->k = 0; if(irq) { cpu->pc = cpu_readWord(cpu, 0xffee, 0xffef); } else { // nmi cpu->pc = cpu_readWord(cpu, 0xffea, 0xffeb); } } // addressing modes static uint32_t cpu_adrImm(Cpu* cpu, uint32_t* low, bool xFlag) { if((xFlag && cpu->xf) || (!xFlag && cpu->mf)) { *low = (cpu->k << 16) | cpu->pc++; return 0; } else { *low = (cpu->k << 16) | cpu->pc++; return (cpu->k << 16) | cpu->pc++; } } static uint32_t cpu_adrDp(Cpu* cpu, uint32_t* low) { uint8_t adr = cpu_readOpcode(cpu); if(cpu->dp & 0xff) cpu->cyclesUsed++; // dpr not 0: 1 extra cycle *low = (cpu->dp + adr) & 0xffff; return (cpu->dp + adr + 1) & 0xffff; } static uint32_t cpu_adrDpx(Cpu* cpu, uint32_t* low) { uint8_t adr = cpu_readOpcode(cpu); if(cpu->dp & 0xff) cpu->cyclesUsed++; // dpr not 0: 1 extra cycle *low = (cpu->dp + adr + cpu->x) & 0xffff; return (cpu->dp + adr + cpu->x + 1) & 0xffff; } static uint32_t cpu_adrDpy(Cpu* cpu, uint32_t* low) { uint8_t adr = cpu_readOpcode(cpu); if(cpu->dp & 0xff) cpu->cyclesUsed++; // dpr not 0: 1 extra cycle *low = (cpu->dp + adr + cpu->y) & 0xffff; return (cpu->dp + adr + cpu->y + 1) & 0xffff; } static uint32_t cpu_adrIdp(Cpu* cpu, uint32_t* low) { uint8_t adr = cpu_readOpcode(cpu); if(cpu->dp & 0xff) cpu->cyclesUsed++; // dpr not 0: 1 extra cycle uint16_t pointer = cpu_readWord(cpu, (cpu->dp + adr) & 0xffff, (cpu->dp + adr + 1) & 0xffff); *low = (cpu->db << 16) + pointer; return ((cpu->db << 16) + pointer + 1) & 0xffffff; } static uint32_t cpu_adrIdx(Cpu* cpu, uint32_t* low) { uint8_t adr = cpu_readOpcode(cpu); if(cpu->dp & 0xff) cpu->cyclesUsed++; // dpr not 0: 1 extra cycle uint16_t pointer = cpu_readWord(cpu, (cpu->dp + adr + cpu->x) & 0xffff, (cpu->dp + adr + cpu->x + 1) & 0xffff); *low = (cpu->db << 16) + pointer; return ((cpu->db << 16) + pointer + 1) & 0xffffff; } static uint32_t cpu_adrIdy(Cpu* cpu, uint32_t* low, bool write) { uint8_t adr = cpu_readOpcode(cpu); if(cpu->dp & 0xff) cpu->cyclesUsed++; // dpr not 0: 1 extra cycle uint16_t pointer = cpu_readWord(cpu, (cpu->dp + adr) & 0xffff, (cpu->dp + adr + 1) & 0xffff); if(write && (!cpu->xf || ((pointer >> 8) != ((pointer + cpu->y) >> 8)))) cpu->cyclesUsed++; // x = 0 or page crossed, with writing opcode: 1 extra cycle *low = ((cpu->db << 16) + pointer + cpu->y) & 0xffffff; return ((cpu->db << 16) + pointer + cpu->y + 1) & 0xffffff; } static uint32_t cpu_adrIdl(Cpu* cpu, uint32_t* low) { uint8_t adr = cpu_readOpcode(cpu); if(cpu->dp & 0xff) cpu->cyclesUsed++; // dpr not 0: 1 extra cycle uint32_t pointer = cpu_readWord(cpu, (cpu->dp + adr) & 0xffff, (cpu->dp + adr + 1) & 0xffff); pointer |= cpu_read(cpu, (cpu->dp + adr + 2) & 0xffff) << 16; *low = pointer; return (pointer + 1) & 0xffffff; } static uint32_t cpu_adrIly(Cpu* cpu, uint32_t* low) { uint8_t adr = cpu_readOpcode(cpu); if(cpu->dp & 0xff) cpu->cyclesUsed++; // dpr not 0: 1 extra cycle uint32_t pointer = cpu_readWord(cpu, (cpu->dp + adr) & 0xffff, (cpu->dp + adr + 1) & 0xffff); pointer |= cpu_read(cpu, (cpu->dp + adr + 2) & 0xffff) << 16; *low = (pointer + cpu->y) & 0xffffff; return (pointer + cpu->y + 1) & 0xffffff; } static uint32_t cpu_adrSr(Cpu* cpu, uint32_t* low) { uint8_t adr = cpu_readOpcode(cpu); *low = (cpu->sp + adr) & 0xffff; return (cpu->sp + adr + 1) & 0xffff; } static uint32_t cpu_adrIsy(Cpu* cpu, uint32_t* low) { uint8_t adr = cpu_readOpcode(cpu); uint16_t pointer = cpu_readWord(cpu, (cpu->sp + adr) & 0xffff, (cpu->sp + adr + 1) & 0xffff); *low = ((cpu->db << 16) + pointer + cpu->y) & 0xffffff; return ((cpu->db << 16) + pointer + cpu->y + 1) & 0xffffff; } static uint32_t cpu_adrAbs(Cpu* cpu, uint32_t* low) { uint16_t adr = cpu_readOpcodeWord(cpu); *low = (cpu->db << 16) + adr; return ((cpu->db << 16) + adr + 1) & 0xffffff; } static uint32_t cpu_adrAbx(Cpu* cpu, uint32_t* low, bool write) { uint16_t adr = cpu_readOpcodeWord(cpu); if(write && (!cpu->xf || ((adr >> 8) != ((adr + cpu->x) >> 8)))) cpu->cyclesUsed++; // x = 0 or page crossed, with writing opcode: 1 extra cycle *low = ((cpu->db << 16) + adr + cpu->x) & 0xffffff; return ((cpu->db << 16) + adr + cpu->x + 1) & 0xffffff; } static uint32_t cpu_adrAby(Cpu* cpu, uint32_t* low, bool write) { uint16_t adr = cpu_readOpcodeWord(cpu); if(write && (!cpu->xf || ((adr >> 8) != ((adr + cpu->y) >> 8)))) cpu->cyclesUsed++; // x = 0 or page crossed, with writing opcode: 1 extra cycle *low = ((cpu->db << 16) + adr + cpu->y) & 0xffffff; return ((cpu->db << 16) + adr + cpu->y + 1) & 0xffffff; } static uint32_t cpu_adrAbl(Cpu* cpu, uint32_t* low) { uint32_t adr = cpu_readOpcodeWord(cpu); adr |= cpu_readOpcode(cpu) << 16; *low = adr; return (adr + 1) & 0xffffff; } static uint32_t cpu_adrAlx(Cpu* cpu, uint32_t* low) { uint32_t adr = cpu_readOpcodeWord(cpu); adr |= cpu_readOpcode(cpu) << 16; *low = (adr + cpu->x) & 0xffffff; return (adr + cpu->x + 1) & 0xffffff; } static uint16_t cpu_adrIax(Cpu* cpu) { uint16_t adr = cpu_readOpcodeWord(cpu); return cpu_readWord(cpu, (cpu->k << 16) | ((adr + cpu->x) & 0xffff), (cpu->k << 16) | ((adr + cpu->x + 1) & 0xffff)); } // opcode functions static void cpu_and(Cpu* cpu, uint32_t low, uint32_t high) { if(cpu->mf) { uint8_t value = cpu_read(cpu, low); cpu->a = (cpu->a & 0xff00) | ((cpu->a & value) & 0xff); } else { cpu->cyclesUsed++; // m = 0: 1 extra cycle uint16_t value = cpu_readWord(cpu, low, high); cpu->a &= value; } cpu_setZN(cpu, cpu->a, cpu->mf); } static void cpu_ora(Cpu* cpu, uint32_t low, uint32_t high) { if(cpu->mf) { uint8_t value = cpu_read(cpu, low); cpu->a = (cpu->a & 0xff00) | ((cpu->a | value) & 0xff); } else { cpu->cyclesUsed++; // m = 0: 1 extra cycle uint16_t value = cpu_readWord(cpu, low, high); cpu->a |= value; } cpu_setZN(cpu, cpu->a, cpu->mf); } static void cpu_eor(Cpu* cpu, uint32_t low, uint32_t high) { if(cpu->mf) { uint8_t value = cpu_read(cpu, low); cpu->a = (cpu->a & 0xff00) | ((cpu->a ^ value) & 0xff); } else { cpu->cyclesUsed++; // m = 0: 1 extra cycle uint16_t value = cpu_readWord(cpu, low, high); cpu->a ^= value; } cpu_setZN(cpu, cpu->a, cpu->mf); } static void cpu_adc(Cpu* cpu, uint32_t low, uint32_t high) { if(cpu->mf) { uint8_t value = cpu_read(cpu, low); int result = 0; if(cpu->d) { result = (cpu->a & 0xf) + (value & 0xf) + cpu->c; if(result > 0x9) result = ((result + 0x6) & 0xf) + 0x10; result = (cpu->a & 0xf0) + (value & 0xf0) + result; } else { result = (cpu->a & 0xff) + value + cpu->c; } cpu->v = (cpu->a & 0x80) == (value & 0x80) && (value & 0x80) != (result & 0x80); if(cpu->d && result > 0x9f) result += 0x60; cpu->c = result > 0xff; cpu->a = (cpu->a & 0xff00) | (result & 0xff); } else { cpu->cyclesUsed++; // m = 0: 1 extra cycle uint16_t value = cpu_readWord(cpu, low, high); int result = 0; if(cpu->d) { result = (cpu->a & 0xf) + (value & 0xf) + cpu->c; if(result > 0x9) result = ((result + 0x6) & 0xf) + 0x10; result = (cpu->a & 0xf0) + (value & 0xf0) + result; if(result > 0x9f) result = ((result + 0x60) & 0xff) + 0x100; result = (cpu->a & 0xf00) + (value & 0xf00) + result; if(result > 0x9ff) result = ((result + 0x600) & 0xfff) + 0x1000; result = (cpu->a & 0xf000) + (value & 0xf000) + result; } else { result = cpu->a + value + cpu->c; } cpu->v = (cpu->a & 0x8000) == (value & 0x8000) && (value & 0x8000) != (result & 0x8000); if(cpu->d && result > 0x9fff) result += 0x6000; cpu->c = result > 0xffff; cpu->a = result; } cpu_setZN(cpu, cpu->a, cpu->mf); } static void cpu_sbc(Cpu* cpu, uint32_t low, uint32_t high) { if(cpu->mf) { uint8_t value = cpu_read(cpu, low) ^ 0xff; int result = 0; if(cpu->d) { result = (cpu->a & 0xf) + (value & 0xf) + cpu->c; if(result < 0x10) result = (result - 0x6) & ((result - 0x6 < 0) ? 0xf : 0x1f); result = (cpu->a & 0xf0) + (value & 0xf0) + result; } else { result = (cpu->a & 0xff) + value + cpu->c; } cpu->v = (cpu->a & 0x80) == (value & 0x80) && (value & 0x80) != (result & 0x80); if(cpu->d && result < 0x100) result -= 0x60; cpu->c = result > 0xff; cpu->a = (cpu->a & 0xff00) | (result & 0xff); } else { cpu->cyclesUsed++; // m = 0: 1 extra cycle uint16_t value = cpu_readWord(cpu, low, high) ^ 0xffff; int result = 0; if(cpu->d) { result = (cpu->a & 0xf) + (value & 0xf) + cpu->c; if(result < 0x10) result = (result - 0x6) & ((result - 0x6 < 0) ? 0xf : 0x1f); result = (cpu->a & 0xf0) + (value & 0xf0) + result; if(result < 0x100) result = (result - 0x60) & ((result - 0x60 < 0) ? 0xff : 0x1ff); result = (cpu->a & 0xf00) + (value & 0xf00) + result; if(result < 0x1000) result = (result - 0x600) & ((result - 0x600 < 0) ? 0xfff : 0x1fff); result = (cpu->a & 0xf000) + (value & 0xf000) + result; } else { result = cpu->a + value + cpu->c; } cpu->v = (cpu->a & 0x8000) == (value & 0x8000) && (value & 0x8000) != (result & 0x8000); if(cpu->d && result < 0x10000) result -= 0x6000; cpu->c = result > 0xffff; cpu->a = result; } cpu_setZN(cpu, cpu->a, cpu->mf); } static void cpu_cmp(Cpu* cpu, uint32_t low, uint32_t high) { int result = 0; if(cpu->mf) { uint8_t value = cpu_read(cpu, low) ^ 0xff; result = (cpu->a & 0xff) + value + 1; cpu->c = result > 0xff; } else { cpu->cyclesUsed++; // m = 0: 1 extra cycle uint16_t value = cpu_readWord(cpu, low, high) ^ 0xffff; result = cpu->a + value + 1; cpu->c = result > 0xffff; } cpu_setZN(cpu, result, cpu->mf); } static void cpu_cpx(Cpu* cpu, uint32_t low, uint32_t high) { int result = 0; if(cpu->xf) { uint8_t value = cpu_read(cpu, low) ^ 0xff; result = (cpu->x & 0xff) + value + 1; cpu->c = result > 0xff; } else { cpu->cyclesUsed++; // x = 0: 1 extra cycle uint16_t value = cpu_readWord(cpu, low, high) ^ 0xffff; result = cpu->x + value + 1; cpu->c = result > 0xffff; } cpu_setZN(cpu, result, cpu->xf); } static void cpu_cpy(Cpu* cpu, uint32_t low, uint32_t high) { int result = 0; if(cpu->xf) { uint8_t value = cpu_read(cpu, low) ^ 0xff; result = (cpu->y & 0xff) + value + 1; cpu->c = result > 0xff; } else { cpu->cyclesUsed++; // x = 0: 1 extra cycle uint16_t value = cpu_readWord(cpu, low, high) ^ 0xffff; result = cpu->y + value + 1; cpu->c = result > 0xffff; } cpu_setZN(cpu, result, cpu->xf); } static void cpu_bit(Cpu* cpu, uint32_t low, uint32_t high) { if(cpu->mf) { uint8_t value = cpu_read(cpu, low); uint8_t result = (cpu->a & 0xff) & value; cpu->z = result == 0; cpu->n = value & 0x80; cpu->v = value & 0x40; } else { cpu->cyclesUsed++; // m = 0: 1 extra cycle uint16_t value = cpu_readWord(cpu, low, high); uint16_t result = cpu->a & value; cpu->z = result == 0; cpu->n = value & 0x8000; cpu->v = value & 0x4000; } } static void cpu_lda(Cpu* cpu, uint32_t low, uint32_t high) { if(cpu->mf) { cpu->a = (cpu->a & 0xff00) | cpu_read(cpu, low); } else { cpu->cyclesUsed++; // m = 0: 1 extra cycle cpu->a = cpu_readWord(cpu, low, high); } cpu_setZN(cpu, cpu->a, cpu->mf); } static void cpu_ldx(Cpu* cpu, uint32_t low, uint32_t high) { if(cpu->xf) { cpu->x = cpu_read(cpu, low); } else { cpu->cyclesUsed++; // x = 0: 1 extra cycle cpu->x = cpu_readWord(cpu, low, high); } cpu_setZN(cpu, cpu->x, cpu->xf); } static void cpu_ldy(Cpu* cpu, uint32_t low, uint32_t high) { if(cpu->xf) { cpu->y = cpu_read(cpu, low); } else { cpu->cyclesUsed++; // x = 0: 1 extra cycle cpu->y = cpu_readWord(cpu, low, high); } cpu_setZN(cpu, cpu->y, cpu->xf); } static void cpu_sta(Cpu* cpu, uint32_t low, uint32_t high) { if(cpu->mf) { cpu_write(cpu, low, cpu->a); } else { cpu->cyclesUsed++; // m = 0: 1 extra cycle cpu_writeWord(cpu, low, high, cpu->a, false); } } static void cpu_stx(Cpu* cpu, uint32_t low, uint32_t high) { if(cpu->xf) { cpu_write(cpu, low, cpu->x); } else { cpu->cyclesUsed++; // x = 0: 1 extra cycle cpu_writeWord(cpu, low, high, cpu->x, false); } } static void cpu_sty(Cpu* cpu, uint32_t low, uint32_t high) { if(cpu->xf) { cpu_write(cpu, low, cpu->y); } else { cpu->cyclesUsed++; // x = 0: 1 extra cycle cpu_writeWord(cpu, low, high, cpu->y, false); } } static void cpu_stz(Cpu* cpu, uint32_t low, uint32_t high) { if(cpu->mf) { cpu_write(cpu, low, 0); } else { cpu->cyclesUsed++; // m = 0: 1 extra cycle cpu_writeWord(cpu, low, high, 0, false); } } static void cpu_ror(Cpu* cpu, uint32_t low, uint32_t high) { bool carry = false; int result = 0; if(cpu->mf) { uint8_t value = cpu_read(cpu, low); carry = value & 1; result = (value >> 1) | (cpu->c << 7); cpu_write(cpu, low, result); } else { cpu->cyclesUsed += 2; // m = 0: 2 extra cycles uint16_t value = cpu_readWord(cpu, low, high); carry = value & 1; result = (value >> 1) | (cpu->c << 15); cpu_writeWord(cpu, low, high, result, true); } cpu_setZN(cpu, result, cpu->mf); cpu->c = carry; } static void cpu_rol(Cpu* cpu, uint32_t low, uint32_t high) { int result = 0; if(cpu->mf) { result = (cpu_read(cpu, low) << 1) | (uint8_t)cpu->c; cpu->c = result & 0x100; cpu_write(cpu, low, result); } else { cpu->cyclesUsed += 2; // m = 0: 2 extra cycles result = (cpu_readWord(cpu, low, high) << 1) | (uint8_t)cpu->c; cpu->c = result & 0x10000; cpu_writeWord(cpu, low, high, result, true); } cpu_setZN(cpu, result, cpu->mf); } static void cpu_lsr(Cpu* cpu, uint32_t low, uint32_t high) { int result = 0; if(cpu->mf) { uint8_t value = cpu_read(cpu, low); cpu->c = value & 1; result = value >> 1; cpu_write(cpu, low, result); } else { cpu->cyclesUsed += 2; // m = 0: 2 extra cycles uint16_t value = cpu_readWord(cpu, low, high); cpu->c = value & 1; result = value >> 1; cpu_writeWord(cpu, low, high, result, true); } cpu_setZN(cpu, result, cpu->mf); } static void cpu_asl(Cpu* cpu, uint32_t low, uint32_t high) { int result = 0; if(cpu->mf) { result = cpu_read(cpu, low) << 1; cpu->c = result & 0x100; cpu_write(cpu, low, result); } else { cpu->cyclesUsed += 2; // m = 0: 2 extra cycles result = cpu_readWord(cpu, low, high) << 1; cpu->c = result & 0x10000; cpu_writeWord(cpu, low, high, result, true); } cpu_setZN(cpu, result, cpu->mf); } static void cpu_inc(Cpu* cpu, uint32_t low, uint32_t high) { int result = 0; if(cpu->mf) { result = cpu_read(cpu, low) + 1; cpu_write(cpu, low, result); } else { cpu->cyclesUsed += 2; // m = 0: 2 extra cycles result = cpu_readWord(cpu, low, high) + 1; cpu_writeWord(cpu, low, high, result, true); } cpu_setZN(cpu, result, cpu->mf); } static void cpu_dec(Cpu* cpu, uint32_t low, uint32_t high) { int result = 0; if(cpu->mf) { result = cpu_read(cpu, low) - 1; cpu_write(cpu, low, result); } else { cpu->cyclesUsed += 2; // m = 0: 2 extra cycles result = cpu_readWord(cpu, low, high) - 1; cpu_writeWord(cpu, low, high, result, true); } cpu_setZN(cpu, result, cpu->mf); } static void cpu_tsb(Cpu* cpu, uint32_t low, uint32_t high) { if(cpu->mf) { uint8_t value = cpu_read(cpu, low); cpu->z = ((cpu->a & 0xff) & value) == 0; cpu_write(cpu, low, value | (cpu->a & 0xff)); } else { cpu->cyclesUsed += 2; // m = 0: 2 extra cycles uint16_t value = cpu_readWord(cpu, low, high); cpu->z = (cpu->a & value) == 0; cpu_writeWord(cpu, low, high, value | cpu->a, true); } } static void cpu_trb(Cpu* cpu, uint32_t low, uint32_t high) { if(cpu->mf) { uint8_t value = cpu_read(cpu, low); cpu->z = ((cpu->a & 0xff) & value) == 0; cpu_write(cpu, low, value & ~(cpu->a & 0xff)); } else { cpu->cyclesUsed += 2; // m = 0: 2 extra cycles uint16_t value = cpu_readWord(cpu, low, high); cpu->z = (cpu->a & value) == 0; cpu_writeWord(cpu, low, high, value & ~cpu->a, true); } } void HookedFunctionRts(int is_long); static void cpu_doOpcode(Cpu* cpu, uint8_t opcode) { switch(opcode) { case 0x00: { // brk imp uint32_t addr = (cpu->k << 16) | cpu->pc; switch (addr - 1) { // Uncle_AtHome case 3 will read random memory. case 0x5DEC7: *(uint8_t *)&cpu->a = cpu_read(cpu, 0x5DEB0 + (cpu->y & 0xff)); if (cpu_read(cpu, 0xD90 + (cpu->x & 0xff)) == 2) { cpu->pc = 0xdeea; return; } cpu->pc += 2; return; // Overlord_StalfosTrap doesn't initialize the sprite_D memory location case 0x9be5e: *(uint8_t *)&cpu->a = 224; cpu_write(cpu, 0xDE0 + (uint8_t)cpu->y, 0); cpu->pc++; return; case 0x1AF9A4: // Lanmola_SpawnShrapnel uses undefined carry value *(uint8_t *)&cpu->a += 4; cpu->c = 0; cpu->pc++; return; /* .9E:8A46 E5 E2 sbc.b A, BYTE BG2HOFS_copy2 .9E:8A48 E5 08 sbc.b A, R8 .9E:8A4A 69 0C adc.b A, #0xC . */ case 0x1E8A46: // carry junk cpu->a = cpu->a - cpu_read(cpu, 0xe2) - cpu_read(cpu, 8) + 12; cpu->pc += 5; return; /* .9E:8A52 E5 E8 sbc.b A, BYTE BG2VOFS_copy2 .9E:8A54 69 08 adc.b A, #8 .9E:8A56 E5 09 sbc.b A, R9 .9E:8A58 69 08 adc.b A, #8 */ case 0x1E8A52: // carry junk cpu->a = cpu->a - cpu_read(cpu, 0xe8) + 8 - cpu_read(cpu, 9) + 8; cpu->pc += 7; return; case 0x9a966: // TAgalong_DrawInner doesn't init scratch_0 / scratch_1 for(int i = 0; i < 4; i++) cpu_write(cpu, 0x72 + i, 0); cpu->pc += 1; return; case 0x8f708: cpu->pc += 0; cpu_write(cpu, 0x75, 0); goto case_iny_c8; case 0x1de0e5: // GreatCatfish_ConversateThenSubmerge - not carry preserving if ((uint8_t)cpu->a >= 160) cpu->pc = 0xe164; else cpu->pc += 1; return; case 0x6d0b6: case 0x6d0c6: { // Sprite_CommonItemPickup - wrong carry chain cpu->c = ((uint8_t)cpu->a >= 4); cpu->a = cpu->a - 4; cpu->pc += 1; return; } case 0x1d8f29: case 0x1dc812: case 0x6ED0B: case 0x9b478: case 0x9b46c: cpu->c = 0; goto adc_69; case 0x9B468: case 0x9B46A: case 0x9B474: case 0x9B476: cpu->c = 1; goto sbc_e5; case 0x9B60C: cpu->c = 1; goto sbc_e9; case 0x1DCDEB: cpu->y = cpu_read(cpu, 0x0eb0 + (cpu->x & 0xff)); // BC B0 0E mov.b Y, sprite_head_dir[X] cpu->a = cpu->x; return; } assert(0); #if 0 cpu_pushByte(cpu, cpu->k); cpu_pushWord(cpu, cpu->pc + 1); cpu_pushByte(cpu, cpu_getFlags(cpu)); cpu->cyclesUsed++; // native mode: 1 extra cycle cpu->i = true; cpu->d = false; cpu->k = 0; cpu->pc = cpu_readWord(cpu, 0xffe6, 0xffe7); #endif break; } case 0x01: { // ora idx uint32_t low = 0; uint32_t high = cpu_adrIdx(cpu, &low); cpu_ora(cpu, low, high); break; } case 0x02: { // cop imm(s) cpu_readOpcode(cpu); cpu_pushByte(cpu, cpu->k); cpu_pushWord(cpu, cpu->pc); cpu_pushByte(cpu, cpu_getFlags(cpu)); cpu->cyclesUsed++; // native mode: 1 extra cycle cpu->i = true; cpu->d = false; cpu->k = 0; cpu->pc = cpu_readWord(cpu, 0xffe4, 0xffe5); break; } case 0x03: { // ora sr uint32_t low = 0; uint32_t high = cpu_adrSr(cpu, &low); cpu_ora(cpu, low, high); break; } case 0x04: { // tsb dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_tsb(cpu, low, high); break; } case 0x05: { // ora dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_ora(cpu, low, high); break; } case 0x06: { // asl dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_asl(cpu, low, high); break; } case 0x07: { // ora idl uint32_t low = 0; uint32_t high = cpu_adrIdl(cpu, &low); cpu_ora(cpu, low, high); break; } case 0x08: { // php imp cpu_pushByte(cpu, cpu_getFlags(cpu)); break; } case 0x09: { // ora imm(m) uint32_t low = 0; uint32_t high = cpu_adrImm(cpu, &low, false); cpu_ora(cpu, low, high); break; } case 0x0a: { // asla imp if(cpu->mf) { cpu->c = cpu->a & 0x80; cpu->a = (cpu->a & 0xff00) | ((cpu->a << 1) & 0xff); } else { cpu->c = cpu->a & 0x8000; cpu->a <<= 1; } cpu_setZN(cpu, cpu->a, cpu->mf); break; } case 0x0b: { // phd imp cpu_pushWord(cpu, cpu->dp); break; } case 0x0c: { // tsb abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_tsb(cpu, low, high); break; } case 0x0d: { // ora abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_ora(cpu, low, high); break; } case 0x0e: { // asl abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_asl(cpu, low, high); break; } case 0x0f: { // ora abl uint32_t low = 0; uint32_t high = cpu_adrAbl(cpu, &low); cpu_ora(cpu, low, high); break; } case 0x10: { // bpl rel cpu_doBranch(cpu, cpu_readOpcode(cpu), !cpu->n); break; } case 0x11: { // ora idy(r) uint32_t low = 0; uint32_t high = cpu_adrIdy(cpu, &low, false); cpu_ora(cpu, low, high); break; } case 0x12: { // ora idp uint32_t low = 0; uint32_t high = cpu_adrIdp(cpu, &low); cpu_ora(cpu, low, high); break; } case 0x13: { // ora isy uint32_t low = 0; uint32_t high = cpu_adrIsy(cpu, &low); cpu_ora(cpu, low, high); break; } case 0x14: { // trb dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_trb(cpu, low, high); break; } case 0x15: { // ora dpx uint32_t low = 0; uint32_t high = cpu_adrDpx(cpu, &low); cpu_ora(cpu, low, high); break; } case 0x16: { // asl dpx uint32_t low = 0; uint32_t high = cpu_adrDpx(cpu, &low); cpu_asl(cpu, low, high); break; } case 0x17: { // ora ily uint32_t low = 0; uint32_t high = cpu_adrIly(cpu, &low); cpu_ora(cpu, low, high); break; } case 0x18: { // clc imp cpu->c = false; break; } case 0x19: { // ora aby(r) uint32_t low = 0; uint32_t high = cpu_adrAby(cpu, &low, false); cpu_ora(cpu, low, high); break; } case 0x1a: { // inca imp if(cpu->mf) { cpu->a = (cpu->a & 0xff00) | ((cpu->a + 1) & 0xff); } else { cpu->a++; } cpu_setZN(cpu, cpu->a, cpu->mf); break; } case 0x1b: { // tcs imp cpu->sp = cpu->a; break; } case 0x1c: { // trb abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_trb(cpu, low, high); break; } case 0x1d: { // ora abx(r) uint32_t low = 0; uint32_t high = cpu_adrAbx(cpu, &low, false); cpu_ora(cpu, low, high); break; } case 0x1e: { // asl abx uint32_t low = 0; uint32_t high = cpu_adrAbx(cpu, &low, true); cpu_asl(cpu, low, high); break; } case 0x1f: { // ora alx uint32_t low = 0; uint32_t high = cpu_adrAlx(cpu, &low); cpu_ora(cpu, low, high); break; } case 0x20: { // jsr abs uint16_t value = cpu_readOpcodeWord(cpu); cpu_pushWord(cpu, cpu->pc - 1); cpu->pc = value; break; } case 0x21: { // and idx uint32_t low = 0; uint32_t high = cpu_adrIdx(cpu, &low); cpu_and(cpu, low, high); break; } case 0x22: { // jsl abl uint16_t value = cpu_readOpcodeWord(cpu); uint8_t newK = cpu_readOpcode(cpu); cpu_pushByte(cpu, cpu->k); cpu_pushWord(cpu, cpu->pc - 1); cpu->pc = value; cpu->k = newK; break; } case 0x23: { // and sr uint32_t low = 0; uint32_t high = cpu_adrSr(cpu, &low); cpu_and(cpu, low, high); break; } case 0x24: { // bit dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_bit(cpu, low, high); break; } case 0x25: { // and dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_and(cpu, low, high); break; } case 0x26: { // rol dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_rol(cpu, low, high); break; } case 0x27: { // and idl uint32_t low = 0; uint32_t high = cpu_adrIdl(cpu, &low); cpu_and(cpu, low, high); break; } case 0x28: { // plp imp cpu_setFlags(cpu, cpu_pullByte(cpu)); break; } case 0x29: { // and imm(m) uint32_t low = 0; uint32_t high = cpu_adrImm(cpu, &low, false); cpu_and(cpu, low, high); break; } case 0x2a: { // rola imp int result = (cpu->a << 1) | (uint8_t)cpu->c; if(cpu->mf) { cpu->c = result & 0x100; cpu->a = (cpu->a & 0xff00) | (result & 0xff); } else { cpu->c = result & 0x10000; cpu->a = result; } cpu_setZN(cpu, cpu->a, cpu->mf); break; } case 0x2b: { // pld imp cpu->dp = cpu_pullWord(cpu); cpu_setZN(cpu, cpu->dp, false); break; } case 0x2c: { // bit abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_bit(cpu, low, high); break; } case 0x2d: { // and abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_and(cpu, low, high); break; } case 0x2e: { // rol abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_rol(cpu, low, high); break; } case 0x2f: { // and abl uint32_t low = 0; uint32_t high = cpu_adrAbl(cpu, &low); cpu_and(cpu, low, high); break; } case 0x30: { // bmi rel cpu_doBranch(cpu, cpu_readOpcode(cpu), cpu->n); break; } case 0x31: { // and idy(r) uint32_t low = 0; uint32_t high = cpu_adrIdy(cpu, &low, false); cpu_and(cpu, low, high); break; } case 0x32: { // and idp uint32_t low = 0; uint32_t high = cpu_adrIdp(cpu, &low); cpu_and(cpu, low, high); break; } case 0x33: { // and isy uint32_t low = 0; uint32_t high = cpu_adrIsy(cpu, &low); cpu_and(cpu, low, high); break; } case 0x34: { // bit dpx uint32_t low = 0; uint32_t high = cpu_adrDpx(cpu, &low); cpu_bit(cpu, low, high); break; } case 0x35: { // and dpx uint32_t low = 0; uint32_t high = cpu_adrDpx(cpu, &low); cpu_and(cpu, low, high); break; } case 0x36: { // rol dpx uint32_t low = 0; uint32_t high = cpu_adrDpx(cpu, &low); cpu_rol(cpu, low, high); break; } case 0x37: { // and ily uint32_t low = 0; uint32_t high = cpu_adrIly(cpu, &low); cpu_and(cpu, low, high); break; } case 0x38: { // sec imp cpu->c = true; break; } case 0x39: { // and aby(r) uint32_t low = 0; uint32_t high = cpu_adrAby(cpu, &low, false); cpu_and(cpu, low, high); break; } case 0x3a: { // deca imp if(cpu->mf) { cpu->a = (cpu->a & 0xff00) | ((cpu->a - 1) & 0xff); } else { cpu->a--; } cpu_setZN(cpu, cpu->a, cpu->mf); break; } case 0x3b: { // tsc imp cpu->a = cpu->sp; cpu_setZN(cpu, cpu->a, false); break; } case 0x3c: { // bit abx(r) uint32_t low = 0; uint32_t high = cpu_adrAbx(cpu, &low, false); cpu_bit(cpu, low, high); break; } case 0x3d: { // and abx(r) uint32_t low = 0; uint32_t high = cpu_adrAbx(cpu, &low, false); cpu_and(cpu, low, high); break; } case 0x3e: { // rol abx uint32_t low = 0; uint32_t high = cpu_adrAbx(cpu, &low, true); cpu_rol(cpu, low, high); break; } case 0x3f: { // and alx uint32_t low = 0; uint32_t high = cpu_adrAlx(cpu, &low); cpu_and(cpu, low, high); break; } case 0x40: { // rti imp cpu_setFlags(cpu, cpu_pullByte(cpu)); cpu->cyclesUsed++; // native mode: 1 extra cycle cpu->pc = cpu_pullWord(cpu); cpu->k = cpu_pullByte(cpu); break; } case 0x41: { // eor idx uint32_t low = 0; uint32_t high = cpu_adrIdx(cpu, &low); cpu_eor(cpu, low, high); break; } case 0x42: { // wdm imm(s) cpu_readOpcode(cpu); break; } case 0x43: { // eor sr uint32_t low = 0; uint32_t high = cpu_adrSr(cpu, &low); cpu_eor(cpu, low, high); break; } case 0x44: { // mvp bm uint8_t dest = cpu_readOpcode(cpu); uint8_t src = cpu_readOpcode(cpu); cpu->db = dest; cpu_write(cpu, (dest << 16) | cpu->y, cpu_read(cpu, (src << 16) | cpu->x)); cpu->a--; cpu->x--; cpu->y--; if(cpu->a != 0xffff) { cpu->pc -= 3; } if(cpu->xf) { cpu->x &= 0xff; cpu->y &= 0xff; } break; } case 0x45: { // eor dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_eor(cpu, low, high); break; } case 0x46: { // lsr dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_lsr(cpu, low, high); break; } case 0x47: { // eor idl uint32_t low = 0; uint32_t high = cpu_adrIdl(cpu, &low); cpu_eor(cpu, low, high); break; } case 0x48: { // pha imp if(cpu->mf) { cpu_pushByte(cpu, cpu->a); } else { cpu->cyclesUsed++; // m = 0: 1 extra cycle cpu_pushWord(cpu, cpu->a); } break; } case 0x49: { // eor imm(m) uint32_t low = 0; uint32_t high = cpu_adrImm(cpu, &low, false); cpu_eor(cpu, low, high); break; } case 0x4a: { // lsra imp cpu->c = cpu->a & 1; if(cpu->mf) { cpu->a = (cpu->a & 0xff00) | ((cpu->a >> 1) & 0x7f); } else { cpu->a >>= 1; } cpu_setZN(cpu, cpu->a, cpu->mf); break; } case 0x4b: { // phk imp cpu_pushByte(cpu, cpu->k); break; } case 0x4c: { // jmp abs cpu->pc = cpu_readOpcodeWord(cpu); break; } case 0x4d: { // eor abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_eor(cpu, low, high); break; } case 0x4e: { // lsr abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_lsr(cpu, low, high); break; } case 0x4f: { // eor abl uint32_t low = 0; uint32_t high = cpu_adrAbl(cpu, &low); cpu_eor(cpu, low, high); break; } case 0x50: { // bvc rel cpu_doBranch(cpu, cpu_readOpcode(cpu), !cpu->v); break; } case 0x51: { // eor idy(r) uint32_t low = 0; uint32_t high = cpu_adrIdy(cpu, &low, false); cpu_eor(cpu, low, high); break; } case 0x52: { // eor idp uint32_t low = 0; uint32_t high = cpu_adrIdp(cpu, &low); cpu_eor(cpu, low, high); break; } case 0x53: { // eor isy uint32_t low = 0; uint32_t high = cpu_adrIsy(cpu, &low); cpu_eor(cpu, low, high); break; } case 0x54: { // mvn bm uint8_t dest = cpu_readOpcode(cpu); uint8_t src = cpu_readOpcode(cpu); cpu->db = dest; cpu_write(cpu, (dest << 16) | cpu->y, cpu_read(cpu, (src << 16) | cpu->x)); cpu->a--; cpu->x++; cpu->y++; if(cpu->a != 0xffff) { cpu->pc -= 3; } if(cpu->xf) { cpu->x &= 0xff; cpu->y &= 0xff; } break; } case 0x55: { // eor dpx uint32_t low = 0; uint32_t high = cpu_adrDpx(cpu, &low); cpu_eor(cpu, low, high); break; } case 0x56: { // lsr dpx uint32_t low = 0; uint32_t high = cpu_adrDpx(cpu, &low); cpu_lsr(cpu, low, high); break; } case 0x57: { // eor ily uint32_t low = 0; uint32_t high = cpu_adrIly(cpu, &low); cpu_eor(cpu, low, high); break; } case 0x58: { // cli imp cpu->i = false; break; } case 0x59: { // eor aby(r) uint32_t low = 0; uint32_t high = cpu_adrAby(cpu, &low, false); cpu_eor(cpu, low, high); break; } case 0x5a: { // phy imp if(cpu->xf) { cpu_pushByte(cpu, cpu->y); } else { cpu->cyclesUsed++; // m = 0: 1 extra cycle cpu_pushWord(cpu, cpu->y); } break; } case 0x5b: { // tcd imp cpu->dp = cpu->a; cpu_setZN(cpu, cpu->dp, false); break; } case 0x5c: { // jml abl uint16_t value = cpu_readOpcodeWord(cpu); cpu->k = cpu_readOpcode(cpu); cpu->pc = value; break; } case 0x5d: { // eor abx(r) uint32_t low = 0; uint32_t high = cpu_adrAbx(cpu, &low, false); cpu_eor(cpu, low, high); break; } case 0x5e: { // lsr abx uint32_t low = 0; uint32_t high = cpu_adrAbx(cpu, &low, true); cpu_lsr(cpu, low, high); break; } case 0x5f: { // eor alx uint32_t low = 0; uint32_t high = cpu_adrAlx(cpu, &low); cpu_eor(cpu, low, high); break; } case 0x60: { // rts imp //if (cpu->spBreakpoint) // fprintf(stderr, "0x%x: rts 0x%x 0x%x\n", cpu->k<<16 | cpu->pc, cpu->spBreakpoint, cpu->sp); if (cpu->sp >= cpu->spBreakpoint && cpu->spBreakpoint) { assert(cpu->sp == cpu->spBreakpoint); cpu->spBreakpoint = 0; HookedFunctionRts(0); } cpu->pc = cpu_pullWord(cpu) + 1; break; } case 0x61: { // adc idx uint32_t low = 0; uint32_t high = cpu_adrIdx(cpu, &low); cpu_adc(cpu, low, high); break; } case 0x62: { // per rll uint16_t value = cpu_readOpcodeWord(cpu); cpu_pushWord(cpu, cpu->pc + (int16_t) value); break; } case 0x63: { // adc sr uint32_t low = 0; uint32_t high = cpu_adrSr(cpu, &low); cpu_adc(cpu, low, high); break; } case 0x64: { // stz dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_stz(cpu, low, high); break; } case 0x65: { // adc dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_adc(cpu, low, high); break; } case 0x66: { // ror dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_ror(cpu, low, high); break; } case 0x67: { // adc idl uint32_t low = 0; uint32_t high = cpu_adrIdl(cpu, &low); cpu_adc(cpu, low, high); break; } case 0x68: { // pla imp if(cpu->mf) { cpu->a = (cpu->a & 0xff00) | cpu_pullByte(cpu); } else { cpu->cyclesUsed++; // 16-bit m: 1 extra cycle cpu->a = cpu_pullWord(cpu); } cpu_setZN(cpu, cpu->a, cpu->mf); break; } adc_69: case 0x69: { // adc imm(m) uint32_t low = 0; uint32_t high = cpu_adrImm(cpu, &low, false); cpu_adc(cpu, low, high); break; } case 0x6a: { // rora imp bool carry = cpu->a & 1; if(cpu->mf) { cpu->a = (cpu->a & 0xff00) | ((cpu->a >> 1) & 0x7f) | (cpu->c << 7); } else { cpu->a = (cpu->a >> 1) | (cpu->c << 15); } cpu->c = carry; cpu_setZN(cpu, cpu->a, cpu->mf); break; } case 0x6b: { // rtl imp //if (cpu->spBreakpoint) // fprintf(stderr, "0x%x: rtl 0x%x 0x%x\n", cpu->k<<16 | cpu->pc, cpu->spBreakpoint, cpu->sp); if (cpu->sp >= cpu->spBreakpoint && cpu->spBreakpoint) { assert(cpu->sp == cpu->spBreakpoint); cpu->spBreakpoint = 0; HookedFunctionRts(1); } cpu->pc = cpu_pullWord(cpu) + 1; cpu->k = cpu_pullByte(cpu); break; } case 0x6c: { // jmp ind uint16_t adr = cpu_readOpcodeWord(cpu); cpu->pc = cpu_readWord(cpu, adr, (adr + 1) & 0xffff); break; } case 0x6d: { // adc abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_adc(cpu, low, high); break; } case 0x6e: { // ror abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_ror(cpu, low, high); break; } case 0x6f: { // adc abl uint32_t low = 0; uint32_t high = cpu_adrAbl(cpu, &low); cpu_adc(cpu, low, high); break; } case 0x70: { // bvs rel cpu_doBranch(cpu, cpu_readOpcode(cpu), cpu->v); break; } case 0x71: { // adc idy(r) uint32_t low = 0; uint32_t high = cpu_adrIdy(cpu, &low, false); cpu_adc(cpu, low, high); break; } case 0x72: { // adc idp uint32_t low = 0; uint32_t high = cpu_adrIdp(cpu, &low); cpu_adc(cpu, low, high); break; } case 0x73: { // adc isy uint32_t low = 0; uint32_t high = cpu_adrIsy(cpu, &low); cpu_adc(cpu, low, high); break; } case 0x74: { // stz dpx uint32_t low = 0; uint32_t high = cpu_adrDpx(cpu, &low); cpu_stz(cpu, low, high); break; } case 0x75: { // adc dpx uint32_t low = 0; uint32_t high = cpu_adrDpx(cpu, &low); cpu_adc(cpu, low, high); break; } case 0x76: { // ror dpx uint32_t low = 0; uint32_t high = cpu_adrDpx(cpu, &low); cpu_ror(cpu, low, high); break; } case 0x77: { // adc ily uint32_t low = 0; uint32_t high = cpu_adrIly(cpu, &low); cpu_adc(cpu, low, high); break; } case 0x78: { // sei imp cpu->i = true; break; } case 0x79: { // adc aby(r) uint32_t low = 0; uint32_t high = cpu_adrAby(cpu, &low, false); cpu_adc(cpu, low, high); break; } case 0x7a: { // ply imp if(cpu->xf) { cpu->y = cpu_pullByte(cpu); } else { cpu->cyclesUsed++; // 16-bit x: 1 extra cycle cpu->y = cpu_pullWord(cpu); } cpu_setZN(cpu, cpu->y, cpu->xf); break; } case 0x7b: { // tdc imp cpu->a = cpu->dp; cpu_setZN(cpu, cpu->a, false); break; } case 0x7c: { // jmp iax cpu->pc = cpu_adrIax(cpu); break; } case 0x7d: { // adc abx(r) uint32_t low = 0; uint32_t high = cpu_adrAbx(cpu, &low, false); cpu_adc(cpu, low, high); break; } case 0x7e: { // ror abx uint32_t low = 0; uint32_t high = cpu_adrAbx(cpu, &low, true); cpu_ror(cpu, low, high); break; } case 0x7f: { // adc alx uint32_t low = 0; uint32_t high = cpu_adrAlx(cpu, &low); cpu_adc(cpu, low, high); break; } case 0x80: { // bra rel cpu->pc += (int8_t) cpu_readOpcode(cpu); break; } case 0x81: { // sta idx uint32_t low = 0; uint32_t high = cpu_adrIdx(cpu, &low); cpu_sta(cpu, low, high); break; } case 0x82: { // brl rll cpu->pc += (int16_t) cpu_readOpcodeWord(cpu); break; } case 0x83: { // sta sr uint32_t low = 0; uint32_t high = cpu_adrSr(cpu, &low); cpu_sta(cpu, low, high); break; } case 0x84: { // sty dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_sty(cpu, low, high); break; } case 0x85: { // sta dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_sta(cpu, low, high); break; } case 0x86: { // stx dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_stx(cpu, low, high); break; } case 0x87: { // sta idl uint32_t low = 0; uint32_t high = cpu_adrIdl(cpu, &low); cpu_sta(cpu, low, high); break; } case 0x88: { // dey imp if(cpu->xf) { cpu->y = (cpu->y - 1) & 0xff; } else { cpu->y--; } cpu_setZN(cpu, cpu->y, cpu->xf); break; } case 0x89: { // biti imm(m) if(cpu->mf) { uint8_t result = (cpu->a & 0xff) & cpu_readOpcode(cpu); cpu->z = result == 0; } else { cpu->cyclesUsed++; // m = 0: 1 extra cycle uint16_t result = cpu->a & cpu_readOpcodeWord(cpu); cpu->z = result == 0; } break; } case 0x8a: { // txa imp if(cpu->mf) { cpu->a = (cpu->a & 0xff00) | (cpu->x & 0xff); } else { cpu->a = cpu->x; } cpu_setZN(cpu, cpu->a, cpu->mf); break; } case 0x8b: { // phb imp cpu_pushByte(cpu, cpu->db); break; } case 0x8c: { // sty abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_sty(cpu, low, high); break; } case 0x8d: { // sta abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_sta(cpu, low, high); break; } case 0x8e: { // stx abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_stx(cpu, low, high); break; } case 0x8f: { // sta abl uint32_t low = 0; uint32_t high = cpu_adrAbl(cpu, &low); cpu_sta(cpu, low, high); break; } case 0x90: { // bcc rel cpu_doBranch(cpu, cpu_readOpcode(cpu), !cpu->c); break; } case 0x91: { // sta idy uint32_t low = 0; uint32_t high = cpu_adrIdy(cpu, &low, true); cpu_sta(cpu, low, high); break; } case 0x92: { // sta idp uint32_t low = 0; uint32_t high = cpu_adrIdp(cpu, &low); cpu_sta(cpu, low, high); break; } case 0x93: { // sta isy uint32_t low = 0; uint32_t high = cpu_adrIsy(cpu, &low); cpu_sta(cpu, low, high); break; } case 0x94: { // sty dpx uint32_t low = 0; uint32_t high = cpu_adrDpx(cpu, &low); cpu_sty(cpu, low, high); break; } case 0x95: { // sta dpx uint32_t low = 0; uint32_t high = cpu_adrDpx(cpu, &low); cpu_sta(cpu, low, high); break; } case 0x96: { // stx dpy uint32_t low = 0; uint32_t high = cpu_adrDpy(cpu, &low); cpu_stx(cpu, low, high); break; } case 0x97: { // sta ily uint32_t low = 0; uint32_t high = cpu_adrIly(cpu, &low); cpu_sta(cpu, low, high); break; } case 0x98: { // tya imp if(cpu->mf) { cpu->a = (cpu->a & 0xff00) | (cpu->y & 0xff); } else { cpu->a = cpu->y; } cpu_setZN(cpu, cpu->a, cpu->mf); break; } case 0x99: { // sta aby uint32_t low = 0; uint32_t high = cpu_adrAby(cpu, &low, true); cpu_sta(cpu, low, high); break; } case 0x9a: { // txs imp cpu->sp = cpu->x; break; } case 0x9b: { // txy imp if(cpu->xf) { cpu->y = cpu->x & 0xff; } else { cpu->y = cpu->x; } cpu_setZN(cpu, cpu->y, cpu->xf); break; } case 0x9c: { // stz abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_stz(cpu, low, high); break; } case 0x9d: { // sta abx uint32_t low = 0; uint32_t high = cpu_adrAbx(cpu, &low, true); cpu_sta(cpu, low, high); break; } case 0x9e: { // stz abx uint32_t low = 0; uint32_t high = cpu_adrAbx(cpu, &low, true); cpu_stz(cpu, low, high); break; } case 0x9f: { // sta alx uint32_t low = 0; uint32_t high = cpu_adrAlx(cpu, &low); cpu_sta(cpu, low, high); break; } case 0xa0: { // ldy imm(x) uint32_t low = 0; uint32_t high = cpu_adrImm(cpu, &low, true); cpu_ldy(cpu, low, high); break; } case 0xa1: { // lda idx uint32_t low = 0; uint32_t high = cpu_adrIdx(cpu, &low); cpu_lda(cpu, low, high); break; } case 0xa2: { // ldx imm(x) uint32_t low = 0; uint32_t high = cpu_adrImm(cpu, &low, true); cpu_ldx(cpu, low, high); break; } case 0xa3: { // lda sr uint32_t low = 0; uint32_t high = cpu_adrSr(cpu, &low); cpu_lda(cpu, low, high); break; } case 0xa4: { // ldy dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_ldy(cpu, low, high); break; } case 0xa5: { // lda dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_lda(cpu, low, high); break; } case 0xa6: { // ldx dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_ldx(cpu, low, high); break; } case 0xa7: { // lda idl uint32_t low = 0; uint32_t high = cpu_adrIdl(cpu, &low); cpu_lda(cpu, low, high); break; } case 0xa8: { // tay imp if(cpu->xf) { cpu->y = cpu->a & 0xff; } else { cpu->y = cpu->a; } cpu_setZN(cpu, cpu->y, cpu->xf); break; } case 0xa9: { // lda imm(m) uint32_t low = 0; uint32_t high = cpu_adrImm(cpu, &low, false); cpu_lda(cpu, low, high); break; } case 0xaa: { // tax imp if(cpu->xf) { cpu->x = cpu->a & 0xff; } else { cpu->x = cpu->a; } cpu_setZN(cpu, cpu->x, cpu->xf); break; } case 0xab: { // plb imp cpu->db = cpu_pullByte(cpu); cpu_setZN(cpu, cpu->db, true); break; } case 0xac: { // ldy abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_ldy(cpu, low, high); break; } case 0xad: { // lda abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_lda(cpu, low, high); break; } case 0xae: { // ldx abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_ldx(cpu, low, high); break; } case 0xaf: { // lda abl uint32_t low = 0; uint32_t high = cpu_adrAbl(cpu, &low); cpu_lda(cpu, low, high); break; } case 0xb0: { // bcs rel cpu_doBranch(cpu, cpu_readOpcode(cpu), cpu->c); break; } case 0xb1: { // lda idy(r) uint32_t low = 0; uint32_t high = cpu_adrIdy(cpu, &low, false); cpu_lda(cpu, low, high); break; } case 0xb2: { // lda idp uint32_t low = 0; uint32_t high = cpu_adrIdp(cpu, &low); cpu_lda(cpu, low, high); break; } case 0xb3: { // lda isy uint32_t low = 0; uint32_t high = cpu_adrIsy(cpu, &low); cpu_lda(cpu, low, high); break; } case 0xb4: { // ldy dpx uint32_t low = 0; uint32_t high = cpu_adrDpx(cpu, &low); cpu_ldy(cpu, low, high); break; } case 0xb5: { // lda dpx uint32_t low = 0; uint32_t high = cpu_adrDpx(cpu, &low); cpu_lda(cpu, low, high); break; } case 0xb6: { // ldx dpy uint32_t low = 0; uint32_t high = cpu_adrDpy(cpu, &low); cpu_ldx(cpu, low, high); break; } case 0xb7: { // lda ily uint32_t low = 0; uint32_t high = cpu_adrIly(cpu, &low); cpu_lda(cpu, low, high); break; } case 0xb8: { // clv imp cpu->v = false; break; } case 0xb9: { // lda aby(r) uint32_t low = 0; uint32_t high = cpu_adrAby(cpu, &low, false); cpu_lda(cpu, low, high); break; } case 0xba: { // tsx imp if(cpu->xf) { cpu->x = cpu->sp & 0xff; } else { cpu->x = cpu->sp; } cpu_setZN(cpu, cpu->x, cpu->xf); break; } case 0xbb: { // tyx imp if(cpu->xf) { cpu->x = cpu->y & 0xff; } else { cpu->x = cpu->y; } cpu_setZN(cpu, cpu->x, cpu->xf); break; } case 0xbc: { // ldy abx(r) uint32_t low = 0; uint32_t high = cpu_adrAbx(cpu, &low, false); cpu_ldy(cpu, low, high); break; } case 0xbd: { // lda abx(r) uint32_t low = 0; uint32_t high = cpu_adrAbx(cpu, &low, false); cpu_lda(cpu, low, high); break; } case 0xbe: { // ldx aby(r) uint32_t low = 0; uint32_t high = cpu_adrAby(cpu, &low, false); cpu_ldx(cpu, low, high); break; } case 0xbf: { // lda alx uint32_t low = 0; uint32_t high = cpu_adrAlx(cpu, &low); cpu_lda(cpu, low, high); break; } case 0xc0: { // cpy imm(x) uint32_t low = 0; uint32_t high = cpu_adrImm(cpu, &low, true); cpu_cpy(cpu, low, high); break; } case 0xc1: { // cmp idx uint32_t low = 0; uint32_t high = cpu_adrIdx(cpu, &low); cpu_cmp(cpu, low, high); break; } case 0xc2: { // rep imm(s) cpu_setFlags(cpu, cpu_getFlags(cpu) & ~cpu_readOpcode(cpu)); break; } case 0xc3: { // cmp sr uint32_t low = 0; uint32_t high = cpu_adrSr(cpu, &low); cpu_cmp(cpu, low, high); break; } case 0xc4: { // cpy dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_cpy(cpu, low, high); break; } case 0xc5: { // cmp dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_cmp(cpu, low, high); break; } case 0xc6: { // dec dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_dec(cpu, low, high); break; } case 0xc7: { // cmp idl uint32_t low = 0; uint32_t high = cpu_adrIdl(cpu, &low); cpu_cmp(cpu, low, high); break; } case_iny_c8: case 0xc8: { // iny imp if(cpu->xf) { cpu->y = (cpu->y + 1) & 0xff; } else { cpu->y++; } cpu_setZN(cpu, cpu->y, cpu->xf); break; } case 0xc9: { // cmp imm(m) uint32_t low = 0; uint32_t high = cpu_adrImm(cpu, &low, false); cpu_cmp(cpu, low, high); break; } case 0xca: { // dex imp if(cpu->xf) { cpu->x = (cpu->x - 1) & 0xff; } else { cpu->x--; } cpu_setZN(cpu, cpu->x, cpu->xf); break; } case 0xcb: { // wai imp cpu->waiting = true; break; } case 0xcc: { // cpy abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_cpy(cpu, low, high); break; } case 0xcd: { // cmp abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_cmp(cpu, low, high); break; } case 0xce: { // dec abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_dec(cpu, low, high); break; } case 0xcf: { // cmp abl uint32_t low = 0; uint32_t high = cpu_adrAbl(cpu, &low); cpu_cmp(cpu, low, high); break; } case 0xd0: { // bne rel cpu_doBranch(cpu, cpu_readOpcode(cpu), !cpu->z); break; } case 0xd1: { // cmp idy(r) uint32_t low = 0; uint32_t high = cpu_adrIdy(cpu, &low, false); cpu_cmp(cpu, low, high); break; } case 0xd2: { // cmp idp uint32_t low = 0; uint32_t high = cpu_adrIdp(cpu, &low); cpu_cmp(cpu, low, high); break; } case 0xd3: { // cmp isy uint32_t low = 0; uint32_t high = cpu_adrIsy(cpu, &low); cpu_cmp(cpu, low, high); break; } case 0xd4: { // pei dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_pushWord(cpu, cpu_readWord(cpu, low, high)); break; } case 0xd5: { // cmp dpx uint32_t low = 0; uint32_t high = cpu_adrDpx(cpu, &low); cpu_cmp(cpu, low, high); break; } case 0xd6: { // dec dpx uint32_t low = 0; uint32_t high = cpu_adrDpx(cpu, &low); cpu_dec(cpu, low, high); break; } case 0xd7: { // cmp ily uint32_t low = 0; uint32_t high = cpu_adrIly(cpu, &low); cpu_cmp(cpu, low, high); break; } case 0xd8: { // cld imp cpu->d = false; break; } case 0xd9: { // cmp aby(r) uint32_t low = 0; uint32_t high = cpu_adrAby(cpu, &low, false); cpu_cmp(cpu, low, high); break; } case 0xda: { // phx imp if(cpu->xf) { cpu_pushByte(cpu, cpu->x); } else { cpu->cyclesUsed++; // m = 0: 1 extra cycle cpu_pushWord(cpu, cpu->x); } break; } case 0xdb: { // stp imp cpu->stopped = true; break; } case 0xdc: { // jml ial uint16_t adr = cpu_readOpcodeWord(cpu); cpu->pc = cpu_readWord(cpu, adr, (adr + 1) & 0xffff); cpu->k = cpu_read(cpu, (adr + 2) & 0xffff); break; } case 0xdd: { // cmp abx(r) uint32_t low = 0; uint32_t high = cpu_adrAbx(cpu, &low, false); cpu_cmp(cpu, low, high); break; } case 0xde: { // dec abx uint32_t low = 0; uint32_t high = cpu_adrAbx(cpu, &low, true); cpu_dec(cpu, low, high); break; } case 0xdf: { // cmp alx uint32_t low = 0; uint32_t high = cpu_adrAlx(cpu, &low); cpu_cmp(cpu, low, high); break; } case 0xe0: { // cpx imm(x) uint32_t low = 0; uint32_t high = cpu_adrImm(cpu, &low, true); cpu_cpx(cpu, low, high); break; } case 0xe1: { // sbc idx uint32_t low = 0; uint32_t high = cpu_adrIdx(cpu, &low); cpu_sbc(cpu, low, high); break; } case 0xe2: { // sep imm(s) cpu_setFlags(cpu, cpu_getFlags(cpu) | cpu_readOpcode(cpu)); break; } case 0xe3: { // sbc sr uint32_t low = 0; uint32_t high = cpu_adrSr(cpu, &low); cpu_sbc(cpu, low, high); break; } case 0xe4: { // cpx dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_cpx(cpu, low, high); break; } sbc_e5: case 0xe5: { // sbc dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_sbc(cpu, low, high); break; } case 0xe6: { // inc dp uint32_t low = 0; uint32_t high = cpu_adrDp(cpu, &low); cpu_inc(cpu, low, high); break; } case 0xe7: { // sbc idl uint32_t low = 0; uint32_t high = cpu_adrIdl(cpu, &low); cpu_sbc(cpu, low, high); break; } case 0xe8: { // inx imp if(cpu->xf) { cpu->x = (cpu->x + 1) & 0xff; } else { cpu->x++; } cpu_setZN(cpu, cpu->x, cpu->xf); break; } sbc_e9: case 0xe9: { // sbc imm(m) uint32_t low = 0; uint32_t high = cpu_adrImm(cpu, &low, false); cpu_sbc(cpu, low, high); break; } case 0xea: { // nop imp // no operation break; } case 0xeb: { // xba imp uint8_t low = cpu->a & 0xff; uint8_t high = cpu->a >> 8; cpu->a = (low << 8) | high; cpu_setZN(cpu, high, true); break; } case 0xec: { // cpx abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_cpx(cpu, low, high); break; } case 0xed: { // sbc abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_sbc(cpu, low, high); break; } case 0xee: { // inc abs uint32_t low = 0; uint32_t high = cpu_adrAbs(cpu, &low); cpu_inc(cpu, low, high); break; } case 0xef: { // sbc abl uint32_t low = 0; uint32_t high = cpu_adrAbl(cpu, &low); cpu_sbc(cpu, low, high); break; } case 0xf0: { // beq rel cpu_doBranch(cpu, cpu_readOpcode(cpu), cpu->z); break; } case 0xf1: { // sbc idy(r) uint32_t low = 0; uint32_t high = cpu_adrIdy(cpu, &low, false); cpu_sbc(cpu, low, high); break; } case 0xf2: { // sbc idp uint32_t low = 0; uint32_t high = cpu_adrIdp(cpu, &low); cpu_sbc(cpu, low, high); break; } case 0xf3: { // sbc isy uint32_t low = 0; uint32_t high = cpu_adrIsy(cpu, &low); cpu_sbc(cpu, low, high); break; } case 0xf4: { // pea imm(l) cpu_pushWord(cpu, cpu_readOpcodeWord(cpu)); break; } case 0xf5: { // sbc dpx uint32_t low = 0; uint32_t high = cpu_adrDpx(cpu, &low); cpu_sbc(cpu, low, high); break; } case 0xf6: { // inc dpx uint32_t low = 0; uint32_t high = cpu_adrDpx(cpu, &low); cpu_inc(cpu, low, high); break; } case 0xf7: { // sbc ily uint32_t low = 0; uint32_t high = cpu_adrIly(cpu, &low); cpu_sbc(cpu, low, high); break; } case 0xf8: { // sed imp cpu->d = true; break; } case 0xf9: { // sbc aby(r) uint32_t low = 0; uint32_t high = cpu_adrAby(cpu, &low, false); cpu_sbc(cpu, low, high); break; } case 0xfa: { // plx imp if(cpu->xf) { cpu->x = cpu_pullByte(cpu); } else { cpu->cyclesUsed++; // 16-bit x: 1 extra cycle cpu->x = cpu_pullWord(cpu); } cpu_setZN(cpu, cpu->x, cpu->xf); break; } case 0xfb: { // xce imp bool temp = cpu->c; cpu->c = cpu->e; cpu->e = temp; cpu_setFlags(cpu, cpu_getFlags(cpu)); // updates x and m flags, clears upper half of x and y if needed break; } case 0xfc: { // jsr iax uint16_t value = cpu_adrIax(cpu); cpu_pushWord(cpu, cpu->pc - 1); cpu->pc = value; break; } case 0xfd: { // sbc abx(r) uint32_t low = 0; uint32_t high = cpu_adrAbx(cpu, &low, false); cpu_sbc(cpu, low, high); break; } case 0xfe: { // inc abx uint32_t low = 0; uint32_t high = cpu_adrAbx(cpu, &low, true); cpu_inc(cpu, low, high); break; } case 0xff: { // sbc alx uint32_t low = 0; uint32_t high = cpu_adrAlx(cpu, &low); cpu_sbc(cpu, low, high); break; } } }