#include "cpu.h" #include "cpu_opcodes.h" struct cpu6502_t { int pc; /* Program counter */ int sp; /* Stack pointer */ int a; /* Accumulator */ int x; /* X Index */ int y; /* Y Index */ int p; /* Processor status */ mapper_t* mapper; opcode_t opcodes[256]; int irq_requested; int irq_type; }; /* Private funcs prototypes */ void cpu_push(cpu6502_t* cpu, int value); int cpu_pop(cpu6502_t* cpu); void cpu_stackwrap(cpu6502_t* cpu); void cpu_fill_opcode(cpu6502_t* cpu, int inst, int op, int addr_mode, int size, int cycles); void cpu_create_opcodes(cpu6502_t* cpu); void cpu_init(cpu6502_t** cpu) { cpu6502_t* pThis = NULL; (*cpu) = (cpu6502_t*)malloc(sizeof(cpu6502_t)); assert((*cpu)); pThis = (*cpu); pThis->mapper = NULL; cpu_create_opcodes(pThis); } void cpu_kill(cpu6502_t* cpu) { cpu6502_t* pThis = cpu; assert(pThis); free(pThis); } void cpu_reset(cpu6502_t* cpu) { cpu6502_t* pThis = cpu; assert(pThis); pThis->pc = 0x7FFF; /* 0x8000 - 1 */ pThis->sp = 0x01FF; pThis->a = 0x0; pThis->x = 0x0; pThis->y = 0x0; pThis->p = FLAG_UNUSED | FLAG_BREAK | FLAG_DECIMAL | FLAG_INTERRUPT | FLAG_ZERO; pThis->irq_requested = 0; pThis->irq_type = 0; printf("MSG: CPU reset.\n"); } void cpu_set_mapper(cpu6502_t* cpu, mapper_t* mapper) { assert(cpu && mapper); cpu->mapper = mapper; } void cpu_request_irq(cpu6502_t* cpu, int type) { cpu6502_t* pThis = cpu; assert(pThis); if (pThis->irq_requested) { if (type == IRQ_NORMAL) { return; } printf("ERR: IRQ too fast!\n"); } pThis->irq_requested = 1; pThis->irq_type = type; } int cpu_emulate(cpu6502_t* cpu) { cpu6502_t* pThis = cpu; opcode_t opcode; int opaddress = 0x0; int address = 0x0; int cycles = 0; int extra_cycle = 0; assert(pThis); assert(pThis->mapper); if (pThis->irq_requested) { switch (pThis->irq_type) { case IRQ_NORMAL: { int tpc; printf("MSG: IRQ_NORMAL.\n"); if ((pThis->p >> 2) & 0x1) { printf("MSG: Interrupt masked.\n"); break; } tpc = pThis->pc + 1; cpu_push(pThis, (tpc >> 8) & 0xFF); cpu_push(pThis, tpc & 0xFF); cpu_push(pThis, pThis->p); pThis->p |= FLAG_INTERRUPT; pThis->p = (pThis->p & ~FLAG_BREAK); tpc = mapper_read16(pThis->mapper, 0xFFFE); pThis->pc = tpc - 1; break; } case IRQ_NMI: { if (mapper_read(pThis->mapper, 0x2000) & 0x80) { int tpc; printf("MSG: IRQ_NMI.\n"); tpc = pThis->pc + 1; cpu_push(pThis, (tpc >> 8) & 0xFF); cpu_push(pThis, tpc & 0xFF); cpu_push(pThis, pThis->p); tpc = mapper_read16(pThis->mapper, 0xFFFA); pThis->pc = tpc - 1; } break; } case IRQ_RESET: { printf("MSG: IRQ_RESET.\n"); pThis->pc = mapper_read16(pThis->mapper, 0xFFFC); pThis->pc--; break; } } } /* Fetch op from memory */ opcode = pThis->opcodes[mapper_read(pThis->mapper, pThis->pc + 1)]; if (opcode.inst == 0xFF) { /* TODO: Add kill code? */ printf("Crash: Invalid opcode at $%04X!\n", pThis->pc + 1); return 0; } /* Increment program counter */ opaddress = pThis->pc; pThis->pc += opcode.size; /* Store cycles */ cycles = opcode.cycles; /* Find address */ switch (opcode.addr_mode) { case ADDRMODE_ZP: { /* Zero Page. Address is given, no high byte. */ address = mapper_read(pThis->mapper, opaddress + 2); break; }; case ADDRMODE_REL: { /* Relative. */ address = mapper_read(pThis->mapper, opaddress + 2); if (address < 0x80) { address += pThis->pc; } else { address += pThis->pc - 0xFF; } break; }; case ADDRMODE_IMP: { /* Implied. Ignore. */ break; }; case ADDRMODE_ABS: { /* Absolute. Use the next two bytes as an address. */ address = mapper_read16(pThis->mapper, opaddress + 2); break; }; case ADDRMODE_ACC: { /* Accumulator. */ address = pThis->a; break; }; case ADDRMODE_IMM: { /* Immediate. */ address = pThis->pc; break; }; case ADDRMODE_ZPX: { /* Zero Page Index. Use address from opcode then add X register. */ address = (mapper_read(pThis->mapper, opaddress + 2) + pThis->x) & 0xFF; break; }; case ADDRMODE_ZPY: { /* Zero Page Index. Use address from opcode then add Y register. */ address = (mapper_read(pThis->mapper, opaddress + 2) + pThis->y) & 0xFF; break; }; case ADDRMODE_ABSX: { /* Absolute Index. Same as Zero Page but with the high byte. */ address = mapper_read16(pThis->mapper, opaddress + 2); if ((address & 0xFF00) != ((address + pThis->x) & 0xFF00)) { extra_cycle = 1; } address += pThis->x; break; }; case ADDRMODE_ABSY: { /* Absolute Index. Same as Zero Page but with the high byte. */ address = mapper_read16(pThis->mapper, opaddress + 2); if ((address & 0xFF00) != ((address + pThis->y) & 0xFF00)) { extra_cycle = 1; } address += pThis->y; break; }; case ADDRMODE_PREIDXIND: { /* Pre-indexed Indirect. Find the 16-bit address starting at the given location in Zero Page plus the X register. Value is the contents of that address. */ address = mapper_read(pThis->mapper, opaddress + 2); if ((address & 0xFF00) != ((address + pThis->x) & 0xFF00)) { extra_cycle = 1; } address += pThis->x; address &= 0xFF; address = mapper_read16(pThis->mapper, address); break; }; case ADDRMODE_POSTIDXIND: { /* Post-indexed Indirect. Find the 16-bit address contained in the given location in Zero Page. Add to that address the contents of the Y register. Fetch value stored at that address. */ address = mapper_read16(pThis->mapper, mapper_read(pThis->mapper, opaddress + 2)); if ((address & 0xFF00) != ((address + pThis->y) & 0xFF00)) { extra_cycle = 1; } address += pThis->y; break; }; case ADDRMODE_INDABS: { /* Indirect Absolute. Value of 16-bit address is the sought for 16-bit address. */ address = mapper_read16(pThis->mapper, opaddress + 2); address = mapper_read16(pThis->mapper, address); break; }; } address &= 0xFFFF; printf("$%04X: %s $%04X (= $%2X).\n", opaddress + 1, instnames[opcode.inst], address, mapper_read(pThis->mapper, address)); switch(opcode.inst) { case INST_ADC: { int t; t = pThis->a + mapper_read(pThis->mapper, address) + (pThis->p & 0x1); /* OVERFLOW */ if (pThis->a <= 0x7F && t > 0x7F) { pThis->p |= FLAG_OVERFLOW; } else { pThis->p = pThis->p & ~FLAG_OVERFLOW; } /* OVERFLOW */ pThis->p = (pThis->p & ~FLAG_CARRY) | (t > 0xFF ? 1 : 0); pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((t >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (t ? 0 : 1) << 1; pThis->a = t & 0xFF; cycles += extra_cycle; break; } case INST_AND: { pThis->a = (pThis->a & mapper_read(pThis->mapper, address)) & 0xFF; pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->a >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->a ? 0 : 1) << 1; if (opcode.addr_mode == ADDRMODE_POSTIDXIND) { cycles += extra_cycle; } break; } case INST_ASL: { if (opcode.addr_mode == ADDRMODE_ACC) { pThis->p = (pThis->p & ~FLAG_CARRY) | ((pThis->a >> 7) & 0x1); pThis->a = (pThis->a << 1) & 0xFF; pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->a >> 7) & 0x1); pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->a ? 0 : 1) << 1; } else { int t = mapper_read(pThis->mapper, address); pThis->p = (pThis->p & ~FLAG_CARRY) | ((t >> 7) & 0x1); t = (t << 1) & 0xFF; pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((t >> 7) & 0x1); pThis->p = (pThis->p & ~FLAG_ZERO) | (t ? 0 : 1) << 1; mapper_write(pThis->mapper, address, t); } break; } case INST_BCC: { if (!(pThis->p & 0x1)) { if ((opaddress & 0xFF00) != (address & 0xFF00)) { cycles += 2; } else { cycles += 1; } pThis->pc = address; } break; } case INST_BCS: { if (pThis->p & 0x1) { /* Yet another mystery, investigate */ if ((opaddress & 0xFF00) != (address & 0xFF00)) { cycles += 2; } else { cycles += 1; } pThis->pc = address; } break; } case INST_BEQ: { if ((pThis->p >> 1) & 0x1) { if ((opaddress & 0xFF00) != (address & 0xFF00)) { cycles += 2; } else { cycles += 1; } pThis->pc = address; } break; } case INST_BIT: { int t = mapper_read(pThis->mapper, address); pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((t >> 7) & 0x1); pThis->p = (pThis->p & ~FLAG_OVERFLOW) | ((t >> 6) & 0x1); t &= pThis->a; pThis->p = (pThis->p & ~FLAG_ZERO) | (t ? 0 : 1) << 1; break; } case INST_BMI: { if ((pThis->p >> 7) & 0x1) { cycles++; pThis->pc = address; } break; } case INST_BNE: { if (!((pThis->p >> 1) & 0x1)) { if ((opaddress & 0xFF00) != (address & 0xFF00)) { cycles += 2; } else { cycles += 1; } pThis->pc = address; } break; } case INST_BPL: { if (!((pThis->p >> 7) & 0x1)) { if ((opaddress & 0xFF00) != (address & 0xFF00)) { cycles += 2; } else { cycles += 1; } pThis->pc = address; } break; } case INST_BRK: { pThis->pc += 2; cpu_push(pThis, (pThis->pc >> 8) & 0xFF); cpu_push(pThis, pThis->pc & 0xFF); pThis->p |= FLAG_BREAK; cpu_push(pThis, pThis->p); pThis->p |= FLAG_INTERRUPT; pThis->pc = mapper_read16(pThis->mapper, 0xFFFE); pThis->pc--; break; } case INST_BVC: { if (!((pThis->p >> 6) & 0x1)) { if ((opaddress & 0xFF00) != (address & 0xFF00)) { cycles += 2; } else { cycles += 1; } pThis->pc = address; } break; } case INST_BVS: { if ((pThis->p >> 6) & 0x1) { if ((opaddress & 0xFF00) != (address & 0xFF00)) { cycles += 2; } else { cycles += 1; } pThis->pc = address; } break; } case INST_CLC: { pThis->p = (pThis->p & ~FLAG_CARRY); break; } case INST_CLD: { pThis->p = (pThis->p & ~FLAG_DECIMAL); break; } case INST_CLI: { pThis->p = (pThis->p & ~FLAG_INTERRUPT); break; } case INST_CLV: { pThis->p = (pThis->p & ~FLAG_OVERFLOW); break; } case INST_CMP: { int t; t = pThis->a - mapper_read(pThis->mapper, address); pThis->p = (pThis->p & ~FLAG_CARRY) | (t >= 0x0 ? 1 : 0); pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((t >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (t ? 0 : 1) << 1; break; } case INST_CPX: { int t; t = pThis->x - mapper_read(pThis->mapper, address); pThis->p = (pThis->p & ~FLAG_CARRY) | (t >= 0x0 ? 1 : 0); pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((t >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (t ? 0 : 1) << 1; break; } case INST_CPY: { int t; t = pThis->y - mapper_read(pThis->mapper, address); pThis->p = (pThis->p & ~FLAG_CARRY) | (t >= 0x0 ? 1 : 0); pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((t >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (t ? 0 : 1) << 1; break; } case INST_DEC: { int t; t = (mapper_read(pThis->mapper, address) - 1) & 0xFF; pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->x >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->x ? 0 : 1) << 1; mapper_write(pThis->mapper, address, t); break; } case INST_DEX: { pThis->x = (pThis->x - 1) & 0xFF; pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->x >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->x ? 0 : 1) << 1; break; } case INST_DEY: { pThis->y = (pThis->y - 1) & 0xFF; pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->y >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->y ? 0 : 1) << 1; break; } case INST_EOR: { pThis->a = (pThis->a ^ mapper_read(pThis->mapper, address)) & 0xFF; pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->a >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->a ? 0 : 1) << 1; cycles += extra_cycle; break; } case INST_INC: { int t; t = (mapper_read(pThis->mapper, address) + 1) & 0xFF; pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->x >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->x ? 0 : 1) << 1; mapper_write(pThis->mapper, address, t); break; } case INST_INX: { pThis->x = (pThis->x + 1) & 0xFF; pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->x >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->x ? 0 : 1) << 1; break; } case INST_INY: { pThis->y = (pThis->y + 1) & 0xFF; pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->y >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->y ? 0 : 1) << 1; break; } case INST_JMP: { pThis->pc = address - 1; break; } case INST_JSR: { cpu_push(pThis, (pThis->pc >> 8) & 0xFF); cpu_push(pThis, pThis->pc & 0xFF); pThis->pc = address - 1; break; } case INST_LDA: { pThis->a = mapper_read(pThis->mapper, address); pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->a >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->a ? 0 : 1) << 1; cycles += extra_cycle; break; } case INST_LDX: { pThis->x = mapper_read(pThis->mapper, address); pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->x >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->x ? 0 : 1) << 1; cycles += extra_cycle; break; } case INST_LDY: { pThis->y = mapper_read(pThis->mapper, address); pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->y >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->y ? 0 : 1) << 1; cycles += extra_cycle; break; } case INST_LSR: { if (opcode.addr_mode == ADDRMODE_ACC) { pThis->p = (pThis->p & ~FLAG_CARRY) | ((pThis->a >> 7) & 0x1); pThis->a >>= 1; pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->a ? 0 : 1) << 1; } else { int t = mapper_read(pThis->mapper, address); pThis->p = (pThis->p & ~FLAG_CARRY) | ((t >> 7) & 0x1); t >>= 1; pThis->p = (pThis->p & ~FLAG_ZERO) | (t ? 0 : 1) << 1; mapper_write(pThis->mapper, address, t); } pThis->p = (pThis->p & ~FLAG_NEGATIVE); break; } case INST_NOP: { /* No OPeration */ break; } case INST_ORA: { pThis->a = (pThis->a | mapper_read(pThis->mapper, address)) & 0xFF; pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->a >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->a ? 0 : 1) << 1; if (opcode.addr_mode == ADDRMODE_POSTIDXIND) { cycles += extra_cycle; } break; } case INST_PHA: { cpu_push(pThis, pThis->a); break; } case INST_PHP: { pThis->p |= FLAG_BREAK; cpu_push(pThis, pThis->p); break; } case INST_PLA: { pThis->a = cpu_pop(pThis); pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->a >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->a ? 0 : 1) << 1; break; } case INST_PLP: { pThis->p = cpu_pop(pThis) | FLAG_UNUSED; break; } case INST_ROL: { int val; int t; if (opcode.addr_mode == ADDRMODE_ACC) { val = pThis->a; } else { val = mapper_read(pThis->mapper, address); } t = (val >> 7) & 0x1; val <<= 1; val |= (pThis->p & 0x1); pThis->p = (pThis->p & ~FLAG_CARRY) | (t & 0x1); pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((val >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (val ? 0 : 1) << 1; if (opcode.addr_mode == ADDRMODE_ACC) { pThis->a = val; } else { mapper_write(pThis->mapper, address, val); } break; } case INST_ROR: { int val; int t; if (opcode.addr_mode == ADDRMODE_ACC) { val = pThis->a; } else { val = mapper_read(pThis->mapper, address); } t = val & 0x1; val >>= 1; val |= (pThis->p & 0x1) ? 0x80 : 0x00; pThis->p = (pThis->p & ~FLAG_CARRY) | (t & 0x1); pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((val >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (val ? 0 : 1) << 1; if (opcode.addr_mode == ADDRMODE_ACC) { pThis->a = val; } else { mapper_write(pThis->mapper, address, val); } break; } case INST_RTI: { pThis->p = cpu_pop(pThis) | FLAG_UNUSED; pThis->pc = cpu_pop(pThis); pThis->pc += cpu_pop(pThis) << 8; if (pThis->pc == 0xFFFF) { return 0; } pThis->pc--; break; } case INST_RTS: { pThis->pc = cpu_pop(pThis); pThis->pc += cpu_pop(pThis) << 8; if (pThis->pc == 0xFFFF) { return 0; /* W00t? End of mem, of course, but... */ } break; } case INST_SBC: { int t; t = pThis->a - mapper_read(pThis->mapper, address) - (1 - (pThis->p & 0x1)); /* OVERFLOW */ if (pThis->a > 0x7F && t <= 0x7F) { pThis->p |= FLAG_OVERFLOW; } else { pThis->p = pThis->p & ~FLAG_OVERFLOW; } /* OVERFLOW */ pThis->p = (pThis->p & ~FLAG_CARRY) | (t < 0x0 ? 0 : 1); pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((t >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (t ? 0 : 1) << 1; pThis->a = t & 0xFF; if (opcode.addr_mode == ADDRMODE_POSTIDXIND) {/* Why? */ cycles += extra_cycle; } break; } case INST_SEC: { pThis->p |= FLAG_CARRY; break; } case INST_SED: { pThis->p |= FLAG_DECIMAL; break; } case INST_SEI: { pThis->p |= FLAG_INTERRUPT; break; } case INST_STA: { mapper_write(pThis->mapper, address, pThis->a); break; } case INST_STX: { mapper_write(pThis->mapper, address, pThis->x); break; } case INST_STY: { mapper_write(pThis->mapper, address, pThis->y); break; } case INST_TAX: { pThis->x = pThis->a; pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->x >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->x ? 0 : 1) << 1; break; } case INST_TAY: { pThis->y = pThis->a; pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->y >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->y ? 0 : 1) << 1; break; } case INST_TSX: { pThis->x = pThis->sp - 0x0100; pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->x >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->x ? 0 : 1) << 1; break; } case INST_TXA: { pThis->a = pThis->x; pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->a >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->a ? 0 : 1) << 1; break; } case INST_TXS: { pThis->sp = pThis->x + 0x0100; cpu_stackwrap(pThis); break; } case INST_TYA: { pThis->a = pThis->y; pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->a >> 7) & 0x1) << 7; pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->a ? 0 : 1) << 1; break; } } /* DEBUG OUTPUT */ printf("DBG: PC=$%04X A=$%02X X=$%02X Y=$%02X SP=$%04X", pThis->pc, pThis->a, pThis->x, pThis->y, pThis->sp); printf(" P=%d%d%d%d%d%d%d%d\n", (pThis->p >> 7) & 0x1, (pThis->p >> 6) & 0x1, (pThis->p >> 5) & 0x1, (pThis->p >> 4) & 0x1, (pThis->p >> 3) & 0x1, (pThis->p >> 2) & 0x1, (pThis->p >> 1) & 0x1, pThis->p & 0x1); /* DEBUG OUTPUT */ return cycles; } void cpu_dump_instructiontable(cpu6502_t* cpu) { int x, y; cpu6502_t* pThis = cpu; assert(pThis); printf(" "); for (x = 0x0; x < 0x10; x++) { printf("%c %X ", 179, x); } printf("\n"); for (y = 0x0; y < 0x10; y++) { printf("%c%c%c", 196, 196, 196); for (x = 0x0; x < 0x10; x++) { printf("%c%c%c%c%c%c", 197, 196, 196, 196, 196, 196); } printf("\n"); printf(" %X ", y); for (x = 0x0; x < 0x10; x++) { int op = ((y << 4) | x) & 0xFF; int inst = pThis->opcodes[op].inst; if (inst == 0xFF) { printf("%c ", 179); } else { printf("%c %s ", 179, instnames[inst]); } } printf("\n"); } } int cpu_get_pc(cpu6502_t* cpu) { cpu6502_t* pThis = cpu; assert(pThis); return pThis->pc + 1; } int cpu_get_a(cpu6502_t* cpu) { cpu6502_t* pThis = cpu; assert(pThis); return pThis->a; } int cpu_get_x(cpu6502_t* cpu) { cpu6502_t* pThis = cpu; assert(pThis); return pThis->x; } int cpu_get_y(cpu6502_t* cpu) { cpu6502_t* pThis = cpu; assert(pThis); return pThis->y; } opcode_t cpu_get_op(cpu6502_t* cpu, int hex) { cpu6502_t* pThis = cpu; assert(pThis); return pThis->opcodes[mapper_read(pThis->mapper, hex)]; } /* Private funcs */ void cpu_push(cpu6502_t* cpu, int value) { cpu6502_t* pThis = cpu; assert(pThis); mapper_write(pThis->mapper, pThis->sp, value); pThis->sp--; cpu_stackwrap(pThis); } int cpu_pop(cpu6502_t* cpu) { cpu6502_t* pThis = cpu; assert(pThis); pThis->sp++; cpu_stackwrap(pThis); return mapper_read(pThis->mapper, pThis->sp); } void cpu_stackwrap(cpu6502_t* cpu) { cpu6502_t* pThis = cpu; assert(pThis); pThis->sp = 0x0100 | (pThis->sp & 0xFF); } void cpu_fill_opcode(cpu6502_t* cpu, int inst, int op, int addr_mode, int size, int cycles) { cpu6502_t* pThis = cpu; assert(pThis); pThis->opcodes[op].inst = inst & 0xFF; pThis->opcodes[op].addr_mode = addr_mode & 0xFF; pThis->opcodes[op].size = size & 0xFF; pThis->opcodes[op].cycles = cycles & 0xFF; pThis->opcodes[op].inst_name = instnames[inst]; } void cpu_create_opcodes(cpu6502_t* cpu) { int t; cpu6502_t* pThis = cpu; assert(pThis); for (t = 0; t < 256; t++) { pThis->opcodes[t].inst = 0xFF; pThis->opcodes[t].addr_mode = 0x0; pThis->opcodes[t].size = 0x0; pThis->opcodes[t].cycles = 0x0; pThis->opcodes[t].inst_name = NULL; } /* ADC */ cpu_fill_opcode(pThis, INST_ADC, 0x69, ADDRMODE_IMM, 2, 2); cpu_fill_opcode(pThis, INST_ADC, 0x65, ADDRMODE_ZP, 2, 3); cpu_fill_opcode(pThis, INST_ADC, 0x75, ADDRMODE_ZPX, 2, 4); cpu_fill_opcode(pThis, INST_ADC, 0x6D, ADDRMODE_ABS, 3, 4); cpu_fill_opcode(pThis, INST_ADC, 0x7D, ADDRMODE_ABSX, 3, 4); cpu_fill_opcode(pThis, INST_ADC, 0x79, ADDRMODE_ABSY, 3, 4); cpu_fill_opcode(pThis, INST_ADC, 0x61, ADDRMODE_PREIDXIND, 2, 6); cpu_fill_opcode(pThis, INST_ADC, 0x71, ADDRMODE_POSTIDXIND, 2, 5); /* AND */ cpu_fill_opcode(pThis, INST_AND, 0x29, ADDRMODE_IMM, 2, 2); cpu_fill_opcode(pThis, INST_AND, 0x25, ADDRMODE_ZP, 2, 3); cpu_fill_opcode(pThis, INST_AND, 0x35, ADDRMODE_ZPX, 2, 4); cpu_fill_opcode(pThis, INST_AND, 0x2D, ADDRMODE_ABS, 3, 4); cpu_fill_opcode(pThis, INST_AND, 0x3D, ADDRMODE_ABSX, 3, 4); cpu_fill_opcode(pThis, INST_AND, 0x39, ADDRMODE_ABSY, 3, 4); cpu_fill_opcode(pThis, INST_AND, 0x21, ADDRMODE_PREIDXIND, 2, 6); cpu_fill_opcode(pThis, INST_AND, 0x31, ADDRMODE_POSTIDXIND, 2, 5); /* ASL */ cpu_fill_opcode(pThis, INST_ASL, 0x0A, ADDRMODE_ACC, 1, 2); cpu_fill_opcode(pThis, INST_ASL, 0x06, ADDRMODE_ZP, 2, 5); cpu_fill_opcode(pThis, INST_ASL, 0x16, ADDRMODE_ZPX, 2, 6); cpu_fill_opcode(pThis, INST_ASL, 0x0E, ADDRMODE_ABS, 3, 6); cpu_fill_opcode(pThis, INST_ASL, 0x1E, ADDRMODE_ABSX, 3, 7); /* BCC */ cpu_fill_opcode(pThis, INST_BCC, 0x90, ADDRMODE_REL, 2, 2); /* BCS */ cpu_fill_opcode(pThis, INST_BCS, 0xB0, ADDRMODE_REL, 2, 2); /* BEQ */ cpu_fill_opcode(pThis, INST_BEQ, 0xF0, ADDRMODE_REL, 2, 2); /* BIT */ cpu_fill_opcode(pThis, INST_BIT, 0x24, ADDRMODE_ZP, 2, 3); cpu_fill_opcode(pThis, INST_BIT, 0x2C, ADDRMODE_ABS, 3, 4); /* BMI */ cpu_fill_opcode(pThis, INST_BMI, 0x30, ADDRMODE_REL, 2, 2); /* BNE */ cpu_fill_opcode(pThis, INST_BNE, 0xD0, ADDRMODE_REL, 2, 2); /* BPL */ cpu_fill_opcode(pThis, INST_BPL, 0x10, ADDRMODE_REL, 2, 2); /* BRK */ cpu_fill_opcode(pThis, INST_BRK, 0x00, ADDRMODE_IMP, 1, 7); /* BVC */ cpu_fill_opcode(pThis, INST_BVC, 0x50, ADDRMODE_REL, 2, 2); /* BVS */ cpu_fill_opcode(pThis, INST_BVS, 0x70, ADDRMODE_REL, 2, 2); /* CLC */ cpu_fill_opcode(pThis, INST_CLC, 0x18, ADDRMODE_IMP, 1, 2); /* CLD */ cpu_fill_opcode(pThis, INST_CLD, 0xD8, ADDRMODE_IMP, 1, 2); /* CLI */ cpu_fill_opcode(pThis, INST_CLI, 0x58, ADDRMODE_IMP, 1, 2); /* CLV */ cpu_fill_opcode(pThis, INST_CLV, 0xB8, ADDRMODE_IMP, 1, 2); /* CMP */ cpu_fill_opcode(pThis, INST_CMP, 0xC9, ADDRMODE_IMM, 2, 2); cpu_fill_opcode(pThis, INST_CMP, 0xC5, ADDRMODE_ZP, 2, 3); cpu_fill_opcode(pThis, INST_CMP, 0xD5, ADDRMODE_ZPX, 2, 4); cpu_fill_opcode(pThis, INST_CMP, 0xCD, ADDRMODE_ABS, 3, 4); cpu_fill_opcode(pThis, INST_CMP, 0xDD, ADDRMODE_ABSX, 3, 4); cpu_fill_opcode(pThis, INST_CMP, 0xD9, ADDRMODE_ABSY, 3, 4); cpu_fill_opcode(pThis, INST_CMP, 0xC1, ADDRMODE_PREIDXIND, 2, 6); cpu_fill_opcode(pThis, INST_CMP, 0xD1, ADDRMODE_POSTIDXIND, 2, 5); /* CPX */ cpu_fill_opcode(pThis, INST_CPX, 0xE0, ADDRMODE_IMM, 2, 2); cpu_fill_opcode(pThis, INST_CPX, 0xE4, ADDRMODE_ZP, 2, 3); cpu_fill_opcode(pThis, INST_CPX, 0xEC, ADDRMODE_ABS, 3, 4); /* CPY */ cpu_fill_opcode(pThis, INST_CPY, 0xC0, ADDRMODE_IMM, 2, 2); cpu_fill_opcode(pThis, INST_CPY, 0xC4, ADDRMODE_ZP, 2, 3); cpu_fill_opcode(pThis, INST_CPY, 0xCC, ADDRMODE_ABS, 3, 4); /* DEC */ cpu_fill_opcode(pThis, INST_DEC, 0xC6, ADDRMODE_ZP, 2, 5); cpu_fill_opcode(pThis, INST_DEC, 0xD6, ADDRMODE_ZPX, 2, 6); cpu_fill_opcode(pThis, INST_DEC, 0xCE, ADDRMODE_ABS, 3, 6); cpu_fill_opcode(pThis, INST_DEC, 0xDE, ADDRMODE_ABSX, 3, 7); /* DEX */ cpu_fill_opcode(pThis, INST_DEX, 0xCA, ADDRMODE_IMP, 1, 2); /* DEY */ cpu_fill_opcode(pThis, INST_DEY, 0x88, ADDRMODE_IMP, 1, 2); /* EOR */ cpu_fill_opcode(pThis, INST_EOR, 0x49, ADDRMODE_IMM, 2, 2); cpu_fill_opcode(pThis, INST_EOR, 0x45, ADDRMODE_ZP, 2, 3); cpu_fill_opcode(pThis, INST_EOR, 0x55, ADDRMODE_ZPX, 2, 4); cpu_fill_opcode(pThis, INST_EOR, 0x4D, ADDRMODE_ABS, 3, 4); cpu_fill_opcode(pThis, INST_EOR, 0x5D, ADDRMODE_ABSX, 3, 4); cpu_fill_opcode(pThis, INST_EOR, 0x59, ADDRMODE_ABSY, 3, 4); cpu_fill_opcode(pThis, INST_EOR, 0x41, ADDRMODE_PREIDXIND, 2, 6); cpu_fill_opcode(pThis, INST_EOR, 0x51, ADDRMODE_POSTIDXIND, 2, 5); /* INC */ cpu_fill_opcode(pThis, INST_INC, 0xE6, ADDRMODE_ZP, 2, 5); cpu_fill_opcode(pThis, INST_INC, 0xF6, ADDRMODE_ZPX, 2, 6); cpu_fill_opcode(pThis, INST_INC, 0xEE, ADDRMODE_ABS, 3, 6); cpu_fill_opcode(pThis, INST_INC, 0xFE, ADDRMODE_ABSX, 3, 7); /* INX */ cpu_fill_opcode(pThis, INST_INX, 0xE8, ADDRMODE_IMP, 1, 2); /* INY */ cpu_fill_opcode(pThis, INST_INY, 0xC8, ADDRMODE_IMP, 1, 2); /* JMP */ cpu_fill_opcode(pThis, INST_JMP, 0x4C, ADDRMODE_ABS, 3, 3); cpu_fill_opcode(pThis, INST_JMP, 0x6C, ADDRMODE_INDABS, 3, 5); /* JSR */ cpu_fill_opcode(pThis, INST_JSR, 0x20, ADDRMODE_ABS, 3, 6); /* LDA */ cpu_fill_opcode(pThis, INST_LDA, 0xA9, ADDRMODE_IMM, 2, 2); cpu_fill_opcode(pThis, INST_LDA, 0xA5, ADDRMODE_ZP, 2, 3); cpu_fill_opcode(pThis, INST_LDA, 0xB5, ADDRMODE_ZPX, 2, 4); cpu_fill_opcode(pThis, INST_LDA, 0xAD, ADDRMODE_ABS, 3, 4); cpu_fill_opcode(pThis, INST_LDA, 0xBD, ADDRMODE_ABSX, 3, 4); cpu_fill_opcode(pThis, INST_LDA, 0xB9, ADDRMODE_ABSY, 3, 4); cpu_fill_opcode(pThis, INST_LDA, 0xA1, ADDRMODE_PREIDXIND, 2, 6); cpu_fill_opcode(pThis, INST_LDA, 0xB1, ADDRMODE_POSTIDXIND, 2, 5); /* LDX */ cpu_fill_opcode(pThis, INST_LDX, 0xA2, ADDRMODE_IMM, 2, 2); cpu_fill_opcode(pThis, INST_LDX, 0xA6, ADDRMODE_ZP, 2, 3); cpu_fill_opcode(pThis, INST_LDX, 0xB6, ADDRMODE_ZPY, 2, 4); cpu_fill_opcode(pThis, INST_LDX, 0xAE, ADDRMODE_ABS, 3, 4); cpu_fill_opcode(pThis, INST_LDX, 0xBE, ADDRMODE_ABSY, 3, 4); /* LDY */ cpu_fill_opcode(pThis, INST_LDY, 0xA0, ADDRMODE_IMM, 2, 2); cpu_fill_opcode(pThis, INST_LDY, 0xA4, ADDRMODE_ZP, 2, 3); cpu_fill_opcode(pThis, INST_LDY, 0xB4, ADDRMODE_ZPY, 2, 4); cpu_fill_opcode(pThis, INST_LDY, 0xAC, ADDRMODE_ABS, 3, 4); cpu_fill_opcode(pThis, INST_LDY, 0xBC, ADDRMODE_ABSY, 3, 4); /* LSR */ cpu_fill_opcode(pThis, INST_LSR, 0x4A, ADDRMODE_ACC, 1, 2); cpu_fill_opcode(pThis, INST_LSR, 0x46, ADDRMODE_ZP, 2, 5); cpu_fill_opcode(pThis, INST_LSR, 0x56, ADDRMODE_ZPX, 2, 6); cpu_fill_opcode(pThis, INST_LSR, 0x4E, ADDRMODE_ABS, 3, 6); cpu_fill_opcode(pThis, INST_LSR, 0x5E, ADDRMODE_ABSX, 3, 7); /* NOP */ cpu_fill_opcode(pThis, INST_NOP, 0xEA, ADDRMODE_IMP, 1, 2); /* ORA */ cpu_fill_opcode(pThis, INST_ORA, 0x09, ADDRMODE_IMM, 2, 2); cpu_fill_opcode(pThis, INST_ORA, 0x05, ADDRMODE_ZP, 2, 3); cpu_fill_opcode(pThis, INST_ORA, 0x15, ADDRMODE_ZPX, 2, 4); cpu_fill_opcode(pThis, INST_ORA, 0x0D, ADDRMODE_ABS, 3, 4); cpu_fill_opcode(pThis, INST_ORA, 0x1D, ADDRMODE_ABSX, 3, 4); cpu_fill_opcode(pThis, INST_ORA, 0x19, ADDRMODE_ABSY, 3, 4); cpu_fill_opcode(pThis, INST_ORA, 0x01, ADDRMODE_PREIDXIND, 2, 6); cpu_fill_opcode(pThis, INST_ORA, 0x11, ADDRMODE_POSTIDXIND, 2, 5); /* PHA */ cpu_fill_opcode(pThis, INST_PHA, 0x48, ADDRMODE_IMP, 1, 3); /* PHP */ cpu_fill_opcode(pThis, INST_PHP, 0x08, ADDRMODE_IMP, 1, 3); /* PLA */ cpu_fill_opcode(pThis, INST_PLA, 0x68, ADDRMODE_IMP, 1, 4); /* PLP */ cpu_fill_opcode(pThis, INST_PLP, 0x28, ADDRMODE_IMP, 1, 4); /* ROL */ cpu_fill_opcode(pThis, INST_ROL, 0x2A, ADDRMODE_ACC, 1, 2); cpu_fill_opcode(pThis, INST_ROL, 0x26, ADDRMODE_ZP, 2, 5); cpu_fill_opcode(pThis, INST_ROL, 0x36, ADDRMODE_ZPX, 2, 6); cpu_fill_opcode(pThis, INST_ROL, 0x2E, ADDRMODE_ABS, 3, 6); cpu_fill_opcode(pThis, INST_ROL, 0x3E, ADDRMODE_ABSX, 3, 7); /* ROR */ cpu_fill_opcode(pThis, INST_ROR, 0x6A, ADDRMODE_ACC, 1, 2); cpu_fill_opcode(pThis, INST_ROR, 0x66, ADDRMODE_ZP, 2, 5); cpu_fill_opcode(pThis, INST_ROR, 0x76, ADDRMODE_ZPX, 2, 6); cpu_fill_opcode(pThis, INST_ROR, 0x6E, ADDRMODE_ABS, 3, 6); cpu_fill_opcode(pThis, INST_ROR, 0x7E, ADDRMODE_ABSX, 3, 7); /* RTI */ cpu_fill_opcode(pThis, INST_RTI, 0x40, ADDRMODE_IMP, 1, 6); /* RTS */ cpu_fill_opcode(pThis, INST_RTS, 0x60, ADDRMODE_IMP, 1, 6); /* SBC */ cpu_fill_opcode(pThis, INST_SBC, 0xE9, ADDRMODE_IMM, 2, 2); cpu_fill_opcode(pThis, INST_SBC, 0xE5, ADDRMODE_ZP, 2, 3); cpu_fill_opcode(pThis, INST_SBC, 0xF5, ADDRMODE_ZPX, 2, 4); cpu_fill_opcode(pThis, INST_SBC, 0xED, ADDRMODE_ABS, 3, 4); cpu_fill_opcode(pThis, INST_SBC, 0xFD, ADDRMODE_ABSX, 3, 4); cpu_fill_opcode(pThis, INST_SBC, 0xF9, ADDRMODE_ABSY, 3, 4); cpu_fill_opcode(pThis, INST_SBC, 0xE1, ADDRMODE_PREIDXIND, 2, 6); cpu_fill_opcode(pThis, INST_SBC, 0xF1, ADDRMODE_POSTIDXIND, 2, 5); /* SEC */ cpu_fill_opcode(pThis, INST_SEC, 0x38, ADDRMODE_IMP, 1, 2); /* SED */ cpu_fill_opcode(pThis, INST_SED, 0xF8, ADDRMODE_IMP, 1, 2); /* SEI */ cpu_fill_opcode(pThis, INST_SEI, 0x78, ADDRMODE_IMP, 1, 2); /* STA */ cpu_fill_opcode(pThis, INST_STA, 0x85, ADDRMODE_ZP, 2, 3); cpu_fill_opcode(pThis, INST_STA, 0x95, ADDRMODE_ZPX, 2, 4); cpu_fill_opcode(pThis, INST_STA, 0x8D, ADDRMODE_ABS, 3, 4); cpu_fill_opcode(pThis, INST_STA, 0x9D, ADDRMODE_ABSX, 3, 5); cpu_fill_opcode(pThis, INST_STA, 0x99, ADDRMODE_ABSY, 3, 5); cpu_fill_opcode(pThis, INST_STA, 0x81, ADDRMODE_PREIDXIND, 2, 6); cpu_fill_opcode(pThis, INST_STA, 0x91, ADDRMODE_POSTIDXIND, 2, 6); /* STX */ cpu_fill_opcode(pThis, INST_STX, 0x86, ADDRMODE_ZP, 2, 3); cpu_fill_opcode(pThis, INST_STX, 0x96, ADDRMODE_ZPY, 2, 4); cpu_fill_opcode(pThis, INST_STX, 0x8E, ADDRMODE_ABS, 3, 4); /* STY */ cpu_fill_opcode(pThis, INST_STY, 0x84, ADDRMODE_ZP, 2, 3); cpu_fill_opcode(pThis, INST_STY, 0x94, ADDRMODE_ZPY, 2, 4); cpu_fill_opcode(pThis, INST_STY, 0x8C, ADDRMODE_ABS, 3, 4); /* TAX */ cpu_fill_opcode(pThis, INST_TAX, 0xAA, ADDRMODE_IMP, 1, 2); /* TAY */ cpu_fill_opcode(pThis, INST_TAY, 0xA8, ADDRMODE_IMP, 1, 2); /* TSX */ cpu_fill_opcode(pThis, INST_TSX, 0xBA, ADDRMODE_IMP, 1, 2); /* TXA */ cpu_fill_opcode(pThis, INST_TXA, 0x8A, ADDRMODE_IMP, 1, 2); /* TXS */ cpu_fill_opcode(pThis, INST_TXS, 0x9A, ADDRMODE_IMP, 1, 2); /* TYA */ cpu_fill_opcode(pThis, INST_TYA, 0x98, ADDRMODE_IMP, 1, 2); }