#include "cpu.h" #include "cpu-internal.h" #include "memory.h" #include "ppu.h" #include "common.h" CPU_STATE cpu; // CPU Memory byte CPU_RAM[0x8000]; byte cpu_ram_read(word address) { return CPU_RAM[address & 0x7FF]; } void cpu_ram_write(word address, byte data) { CPU_RAM[address & 0x7FF] = data; } static byte op_code; // Current instruction code int op_value, op_address; // Arguments for current instruction int op_cycles; // Additional instruction cycles used (e.g. when paging occurs) static unsigned long long cpu_cycles; // Total CPU Cycles Since Power Up (wraps) static void (*cpu_op_address_mode[256])(); // Array of address modes static void (*cpu_op_handler[256])(); // Array of instruction function pointers static bool cpu_op_in_base_instruction_set[256]; // true if instruction is in base 6502 instruction set static char *cpu_op_name[256]; // Instruction names static int cpu_op_cycles[256]; // CPU cycles used by instructions static const byte cpu_zn_flag_table[256] = { zero_flag,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag, negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag, negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag, negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag, negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag, negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag, negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag, negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag, negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag, negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag, negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag, negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag, negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag, negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag, negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag, negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag,negative_flag, }; // Interrupt Addresses word cpu_nmi_interrupt_address() { return memory_readw(0xFFFA); } word cpu_reset_interrupt_address() { return memory_readw(0xFFFC); } word cpu_irq_interrupt_address() { return memory_readw(0xFFFE); } // Stack Routines void cpu_stack_pushb(byte data) { memory_writeb(0x100 + cpu.SP--, data); } void cpu_stack_pushw(word data) { memory_writew(0xFF + cpu.SP, data); cpu.SP -= 2; } byte cpu_stack_popb() { return memory_readb(0x100 + ++cpu.SP); } word cpu_stack_popw() { cpu.SP += 2; return memory_readw(0xFF + cpu.SP); } // CPU Instructions void ____FE____() { /* Instruction for future Extension */ } #define cpu_flag_set(flag) common_bit_set(cpu.P, flag) #define cpu_modify_flag(flag, value) common_modify_bitb(&cpu.P, flag, value) #define cpu_set_flag(flag) common_set_bitb(&cpu.P, flag) #define cpu_unset_flag(flag) common_unset_bitb(&cpu.P, flag) #define cpu_update_zn_flags(value) cpu.P = (cpu.P & ~(zero_flag | negative_flag)) | cpu_zn_flag_table[value] #define cpu_branch(flag) if (flag) cpu.PC = op_address; #define cpu_compare(reg) \ int result = reg - op_value; \ cpu_modify_flag(carry_bp, result >= 0); \ cpu_modify_flag(zero_bp, result == 0); \ cpu_modify_flag(negative_bp, (result >> 7) & 1); // CPU Instructions // NOP void cpu_op_nop() {} // Addition void cpu_op_adc() { int result = cpu.A + op_value + (cpu_flag_set(carry_bp) ? 1 : 0); cpu_modify_flag(carry_bp, !!(result & 0x100)); cpu_modify_flag(overflow_bp, !!(~(cpu.A ^ op_value) & (cpu.A ^ result) & 0x80)); cpu.A = result & 0xFF; cpu_update_zn_flags(cpu.A); } // Subtraction void cpu_op_sbc() { int result = cpu.A - op_value - (cpu_flag_set(carry_bp) ? 0 : 1); cpu_modify_flag(carry_bp, !(result & 0x100)); cpu_modify_flag(overflow_bp, !!((cpu.A ^ op_value) & (cpu.A ^ result) & 0x80)); cpu.A = result & 0xFF; cpu_update_zn_flags(cpu.A); } // Bit Manipulation Operations void cpu_op_and() { cpu_update_zn_flags(cpu.A &= op_value); } void cpu_op_bit() { cpu_modify_flag(zero_bp, !(cpu.A & op_value)); cpu.P = (cpu.P & 0x3F) | (0xC0 & op_value); } void cpu_op_eor() { cpu_update_zn_flags(cpu.A ^= op_value); } void cpu_op_ora() { cpu_update_zn_flags(cpu.A |= op_value); } void cpu_op_asla() { cpu_modify_flag(carry_bp, cpu.A & 0x80); cpu.A <<= 1; cpu_update_zn_flags(cpu.A); } void cpu_op_asl() { cpu_modify_flag(carry_bp, op_value & 0x80); op_value <<= 1; op_value &= 0xFF; cpu_update_zn_flags(op_value); memory_writeb(op_address, op_value); } void cpu_op_lsra() { int value = cpu.A >> 1; cpu_modify_flag(carry_bp, cpu.A & 0x01); cpu.A = value & 0xFF; cpu_update_zn_flags(value); } void cpu_op_lsr() { cpu_modify_flag(carry_bp, op_value & 0x01); op_value >>= 1; op_value &= 0xFF; memory_writeb(op_address, op_value); cpu_update_zn_flags(op_value); } void cpu_op_rola() { int value = cpu.A << 1; value |= cpu_flag_set(carry_bp) ? 1 : 0; cpu_modify_flag(carry_bp, value > 0xFF); cpu.A = value & 0xFF; cpu_update_zn_flags(cpu.A); } void cpu_op_rol() { op_value <<= 1; op_value |= cpu_flag_set(carry_bp) ? 1 : 0; cpu_modify_flag(carry_bp, op_value > 0xFF); op_value &= 0xFF; memory_writeb(op_address, op_value); cpu_update_zn_flags(op_value); } void cpu_op_rora() { unsigned char carry = cpu_flag_set(carry_bp); cpu_modify_flag(carry_bp, cpu.A & 0x01); cpu.A = (cpu.A >> 1) | (carry << 7); cpu_modify_flag(zero_bp, cpu.A == 0); cpu_modify_flag(negative_bp, !!carry); } void cpu_op_ror() { unsigned char carry = cpu_flag_set(carry_bp); cpu_modify_flag(carry_bp, op_value & 0x01); op_value = ((op_value >> 1) | (carry << 7)) & 0xFF; cpu_modify_flag(zero_bp, op_value == 0); cpu_modify_flag(negative_bp, !!carry); memory_writeb(op_address, op_value); } // Loading void cpu_op_lda() { cpu_update_zn_flags(cpu.A = op_value); } void cpu_op_ldx() { cpu_update_zn_flags(cpu.X = op_value); } void cpu_op_ldy() { cpu_update_zn_flags(cpu.Y = op_value); } // Storing void cpu_op_sta() { memory_writeb(op_address, cpu.A); } void cpu_op_stx() { memory_writeb(op_address, cpu.X); } void cpu_op_sty() { memory_writeb(op_address, cpu.Y); } // Transfering void cpu_op_tax() { cpu_update_zn_flags(cpu.X = cpu.A); } void cpu_op_txa() { cpu_update_zn_flags(cpu.A = cpu.X); } void cpu_op_tay() { cpu_update_zn_flags(cpu.Y = cpu.A); } void cpu_op_tya() { cpu_update_zn_flags(cpu.A = cpu.Y); } void cpu_op_tsx() { cpu_update_zn_flags(cpu.X = cpu.SP); } void cpu_op_txs() { cpu.SP = cpu.X; } // Branching Positive void cpu_op_bcs() { cpu_branch(cpu_flag_set(carry_bp)); } void cpu_op_beq() { cpu_branch(cpu_flag_set(zero_bp)); } void cpu_op_bmi() { cpu_branch(cpu_flag_set(negative_bp)); } void cpu_op_bvs() { cpu_branch(cpu_flag_set(overflow_bp)); } // Branching Negative void cpu_op_bne() { cpu_branch(!cpu_flag_set(zero_bp)); } void cpu_op_bcc() { cpu_branch(!cpu_flag_set(carry_bp)); } void cpu_op_bpl() { cpu_branch(!cpu_flag_set(negative_bp)); } void cpu_op_bvc() { cpu_branch(!cpu_flag_set(overflow_bp)); } // Jumping void cpu_op_jmp() { cpu.PC = op_address; } // Subroutines void cpu_op_jsr() { cpu_stack_pushw(cpu.PC - 1); cpu.PC = op_address; } void cpu_op_rts() { cpu.PC = cpu_stack_popw() + 1; } // Interruptions void cpu_op_brk() { cpu_stack_pushw(cpu.PC - 1); cpu_stack_pushb(cpu.P); cpu.P |= unused_flag | break_flag; cpu.PC = cpu_nmi_interrupt_address(); } void cpu_op_rti() { cpu.P = cpu_stack_popb() | unused_flag; cpu.PC = cpu_stack_popw(); } // Flags void cpu_op_clc() { cpu_unset_flag(carry_bp); } void cpu_op_cld() { cpu_unset_flag(decimal_bp); } void cpu_op_cli() { cpu_unset_flag(interrupt_bp); } void cpu_op_clv() { cpu_unset_flag(overflow_bp); } void cpu_op_sec() { cpu_set_flag(carry_bp); } void cpu_op_sed() { cpu_set_flag(decimal_bp); } void cpu_op_sei() { cpu_set_flag(interrupt_bp); } // Comparison void cpu_op_cmp() { cpu_compare(cpu.A); } void cpu_op_cpx() { cpu_compare(cpu.X); } void cpu_op_cpy() { cpu_compare(cpu.Y); } // Increment void cpu_op_inc() { byte result = op_value + 1; memory_writeb(op_address, result); cpu_update_zn_flags(result); } void cpu_op_inx() { cpu_update_zn_flags(++cpu.X); } void cpu_op_iny() { cpu_update_zn_flags(++cpu.Y); } // Decrement void cpu_op_dec() { byte result = op_value - 1; memory_writeb(op_address, result); cpu_update_zn_flags(result); } void cpu_op_dex() { cpu_update_zn_flags(--cpu.X); } void cpu_op_dey() { cpu_update_zn_flags(--cpu.Y); } // Stack void cpu_op_php() { cpu_stack_pushb(cpu.P | 0x30); } void cpu_op_pha() { cpu_stack_pushb(cpu.A); } void cpu_op_pla() { cpu.A = cpu_stack_popb(); cpu_update_zn_flags(cpu.A); } void cpu_op_plp() { cpu.P = (cpu_stack_popb() & 0xEF) | 0x20; } // Extended Instruction Set void cpu_op_aso() { cpu_op_asl(); cpu_op_ora(); } void cpu_op_axa() { memory_writeb(op_address, cpu.A & cpu.X & (op_address >> 8)); } void cpu_op_axs() { memory_writeb(op_address, cpu.A & cpu.X); } void cpu_op_dcm() { op_value--; op_value &= 0xFF; memory_writeb(op_address, op_value); cpu_op_cmp(); } void cpu_op_ins() { op_value = (op_value + 1) & 0xFF; memory_writeb(op_address, op_value); cpu_op_sbc(); } void cpu_op_lax() { cpu_update_zn_flags(cpu.A = cpu.X = op_value); } void cpu_op_lse() { cpu_op_lsr(); cpu_op_eor(); } void cpu_op_rla() { cpu_op_rol(); cpu_op_and(); } void cpu_op_rra() { cpu_op_ror(); cpu_op_adc(); } // Base 6502 instruction set #define CPU_OP_BIS(o, c, f, n, a) \ cpu_op_cycles[0x##o] = c; \ cpu_op_handler[0x##o] = cpu_op_##f; \ cpu_op_name[0x##o] = n; \ cpu_op_address_mode[0x##o] = cpu_address_##a; \ cpu_op_in_base_instruction_set[0x##o] = true; // Not implemented instructions #define CPU_OP_NII(o, a) \ cpu_op_cycles[0x##o] = 1; \ cpu_op_handler[0x##o] = ____FE____; \ cpu_op_name[0x##o] = "NOP"; \ cpu_op_address_mode[0x##o] = cpu_address_##a; \ cpu_op_in_base_instruction_set[0x##o] = false; // Extended instruction set found in other CPUs and implemented for compatibility #define CPU_OP_EIS(o, c, f, n, a) \ cpu_op_cycles[0x##o] = c; \ cpu_op_handler[0x##o] = cpu_op_##f; \ cpu_op_name[0x##o] = n; \ cpu_op_address_mode[0x##o] = cpu_address_##a; \ cpu_op_in_base_instruction_set[0x##o] = false; // CPU Lifecycle void cpu_init() { CPU_OP_BIS(00, 7, brk, "BRK", implied) CPU_OP_BIS(01, 6, ora, "ORA", indirect_x) CPU_OP_BIS(05, 3, ora, "ORA", zero_page) CPU_OP_BIS(06, 5, asl, "ASL", zero_page) CPU_OP_BIS(08, 3, php, "PHP", implied) CPU_OP_BIS(09, 2, ora, "ORA", immediate) CPU_OP_BIS(0A, 2, asla,"ASL", implied) CPU_OP_BIS(0D, 4, ora, "ORA", absolute) CPU_OP_BIS(0E, 6, asl, "ASL", absolute) CPU_OP_BIS(10, 2, bpl, "BPL", relative) CPU_OP_BIS(11, 5, ora, "ORA", indirect_y) CPU_OP_BIS(15, 4, ora, "ORA", zero_page_x) CPU_OP_BIS(16, 6, asl, "ASL", zero_page_x) CPU_OP_BIS(18, 2, clc, "CLC", implied) CPU_OP_BIS(19, 4, ora, "ORA", absolute_y) CPU_OP_BIS(1D, 4, ora, "ORA", absolute_x) CPU_OP_BIS(1E, 7, asl, "ASL", absolute_x) CPU_OP_BIS(20, 6, jsr, "JSR", absolute) CPU_OP_BIS(21, 6, and, "AND", indirect_x) CPU_OP_BIS(24, 3, bit, "BIT", zero_page) CPU_OP_BIS(25, 3, and, "AND", zero_page) CPU_OP_BIS(26, 5, rol, "ROL", zero_page) CPU_OP_BIS(28, 4, plp, "PLP", implied) CPU_OP_BIS(29, 2, and, "AND", immediate) CPU_OP_BIS(2A, 2, rola,"ROL", implied) CPU_OP_BIS(2C, 4, bit, "BIT", absolute) CPU_OP_BIS(2D, 2, and, "AND", absolute) CPU_OP_BIS(2E, 6, rol, "ROL", absolute) CPU_OP_BIS(30, 2, bmi, "BMI", relative) CPU_OP_BIS(31, 5, and, "AND", indirect_y) CPU_OP_BIS(35, 4, and, "AND", zero_page_x) CPU_OP_BIS(36, 6, rol, "ROL", zero_page_x) CPU_OP_BIS(38, 2, sec, "SEC", implied) CPU_OP_BIS(39, 4, and, "AND", absolute_y) CPU_OP_BIS(3D, 4, and, "AND", absolute_x) CPU_OP_BIS(3E, 7, rol, "ROL", absolute_x) CPU_OP_BIS(40, 6, rti, "RTI", implied) CPU_OP_BIS(41, 6, eor, "EOR", indirect_x) CPU_OP_BIS(45, 3, eor, "EOR", zero_page) CPU_OP_BIS(46, 5, lsr, "LSR", zero_page) CPU_OP_BIS(48, 3, pha, "PHA", implied) CPU_OP_BIS(49, 2, eor, "EOR", immediate) CPU_OP_BIS(4A, 2, lsra,"LSR", implied) CPU_OP_BIS(4C, 3, jmp, "JMP", absolute) CPU_OP_BIS(4D, 4, eor, "EOR", absolute) CPU_OP_BIS(4E, 6, lsr, "LSR", absolute) CPU_OP_BIS(50, 2, bvc, "BVC", relative) CPU_OP_BIS(51, 5, eor, "EOR", indirect_y) CPU_OP_BIS(55, 4, eor, "EOR", zero_page_x) CPU_OP_BIS(56, 6, lsr, "LSR", zero_page_x) CPU_OP_BIS(58, 2, cli, "CLI", implied) CPU_OP_BIS(59, 4, eor, "EOR", absolute_y) CPU_OP_BIS(5D, 4, eor, "EOR", absolute_x) CPU_OP_BIS(5E, 7, lsr, "LSR", absolute_x) CPU_OP_BIS(60, 6, rts, "RTS", implied) CPU_OP_BIS(61, 6, adc, "ADC", indirect_x) CPU_OP_BIS(65, 3, adc, "ADC", zero_page) CPU_OP_BIS(66, 5, ror, "ROR", zero_page) CPU_OP_BIS(68, 4, pla, "PLA", implied) CPU_OP_BIS(69, 2, adc, "ADC", immediate) CPU_OP_BIS(6A, 2, rora,"ROR", implied) CPU_OP_BIS(6C, 5, jmp, "JMP", indirect) CPU_OP_BIS(6D, 4, adc, "ADC", absolute) CPU_OP_BIS(6E, 6, ror, "ROR", absolute) CPU_OP_BIS(70, 2, bvs, "BVS", relative) CPU_OP_BIS(71, 5, adc, "ADC", indirect_y) CPU_OP_BIS(75, 4, adc, "ADC", zero_page_x) CPU_OP_BIS(76, 6, ror, "ROR", zero_page_x) CPU_OP_BIS(78, 2, sei, "SEI", implied) CPU_OP_BIS(79, 4, adc, "ADC", absolute_y) CPU_OP_BIS(7D, 4, adc, "ADC", absolute_x) CPU_OP_BIS(7E, 7, ror, "ROR", absolute_x) CPU_OP_BIS(81, 6, sta, "STA", indirect_x) CPU_OP_BIS(84, 3, sty, "STY", zero_page) CPU_OP_BIS(85, 3, sta, "STA", zero_page) CPU_OP_BIS(86, 3, stx, "STX", zero_page) CPU_OP_BIS(88, 2, dey, "DEY", implied) CPU_OP_BIS(8A, 2, txa, "TXA", implied) CPU_OP_BIS(8C, 4, sty, "STY", absolute) CPU_OP_BIS(8D, 4, sta, "STA", absolute) CPU_OP_BIS(8E, 4, stx, "STX", absolute) CPU_OP_BIS(90, 2, bcc, "BCC", relative) CPU_OP_BIS(91, 6, sta, "STA", indirect_y) CPU_OP_BIS(94, 4, sty, "STY", zero_page_x) CPU_OP_BIS(95, 4, sta, "STA", zero_page_x) CPU_OP_BIS(96, 4, stx, "STX", zero_page_y) CPU_OP_BIS(98, 2, tya, "TYA", implied) CPU_OP_BIS(99, 5, sta, "STA", absolute_y) CPU_OP_BIS(9A, 2, txs, "TXS", implied) CPU_OP_BIS(9D, 5, sta, "STA", absolute_x) CPU_OP_BIS(A0, 2, ldy, "LDY", immediate) CPU_OP_BIS(A1, 6, lda, "LDA", indirect_x) CPU_OP_BIS(A2, 2, ldx, "LDX", immediate) CPU_OP_BIS(A4, 3, ldy, "LDY", zero_page) CPU_OP_BIS(A5, 3, lda, "LDA", zero_page) CPU_OP_BIS(A6, 3, ldx, "LDX", zero_page) CPU_OP_BIS(A8, 2, tay, "TAY", implied) CPU_OP_BIS(A9, 2, lda, "LDA", immediate) CPU_OP_BIS(AA, 2, tax, "TAX", implied) CPU_OP_BIS(AC, 4, ldy, "LDY", absolute) CPU_OP_BIS(AD, 4, lda, "LDA", absolute) CPU_OP_BIS(AE, 4, ldx, "LDX", absolute) CPU_OP_BIS(B0, 2, bcs, "BCS", relative) CPU_OP_BIS(B1, 5, lda, "LDA", indirect_y) CPU_OP_BIS(B4, 4, ldy, "LDY", zero_page_x) CPU_OP_BIS(B5, 4, lda, "LDA", zero_page_x) CPU_OP_BIS(B6, 4, ldx, "LDX", zero_page_y) CPU_OP_BIS(B8, 2, clv, "CLV", implied) CPU_OP_BIS(B9, 4, lda, "LDA", absolute_y) CPU_OP_BIS(BA, 2, tsx, "TSX", implied) CPU_OP_BIS(BC, 4, ldy, "LDY", absolute_x) CPU_OP_BIS(BD, 4, lda, "LDA", absolute_x) CPU_OP_BIS(BE, 4, ldx, "LDX", absolute_y) CPU_OP_BIS(C0, 2, cpy, "CPY", immediate) CPU_OP_BIS(C1, 6, cmp, "CMP", indirect_x) CPU_OP_BIS(C4, 3, cpy, "CPY", zero_page) CPU_OP_BIS(C5, 3, cmp, "CMP", zero_page) CPU_OP_BIS(C6, 5, dec, "DEC", zero_page) CPU_OP_BIS(C8, 2, iny, "INY", implied) CPU_OP_BIS(C9, 2, cmp, "CMP", immediate) CPU_OP_BIS(CA, 2, dex, "DEX", implied) CPU_OP_BIS(CC, 4, cpy, "CPY", absolute) CPU_OP_BIS(CD, 4, cmp, "CMP", absolute) CPU_OP_BIS(CE, 6, dec, "DEC", absolute) CPU_OP_BIS(D0, 2, bne, "BNE", relative) CPU_OP_BIS(D1, 5, cmp, "CMP", indirect_y) CPU_OP_BIS(D5, 4, cmp, "CMP", zero_page_x) CPU_OP_BIS(D6, 6, dec, "DEC", zero_page_x) CPU_OP_BIS(D8, 2, cld, "CLD", implied) CPU_OP_BIS(D9, 4, cmp, "CMP", absolute_y) CPU_OP_BIS(DD, 4, cmp, "CMP", absolute_x) CPU_OP_BIS(DE, 7, dec, "DEC", absolute_x) CPU_OP_BIS(E0, 2, cpx, "CPX", immediate) CPU_OP_BIS(E1, 6, sbc, "SBC", indirect_x) CPU_OP_BIS(E4, 3, cpx, "CPX", zero_page) CPU_OP_BIS(E5, 3, sbc, "SBC", zero_page) CPU_OP_BIS(E6, 5, inc, "INC", zero_page) CPU_OP_BIS(E8, 2, inx, "INX", implied) CPU_OP_BIS(E9, 2, sbc, "SBC", immediate) CPU_OP_BIS(EA, 2, nop, "NOP", implied) CPU_OP_BIS(EC, 4, cpx, "CPX", absolute) CPU_OP_BIS(ED, 4, sbc, "SBC", absolute) CPU_OP_BIS(EE, 6, inc, "INC", absolute) CPU_OP_BIS(F0, 2, beq, "BEQ", relative) CPU_OP_BIS(F1, 5, sbc, "SBC", indirect_y) CPU_OP_BIS(F5, 4, sbc, "SBC", zero_page_x) CPU_OP_BIS(F6, 6, inc, "INC", zero_page_x) CPU_OP_BIS(F8, 2, sed, "SED", implied) CPU_OP_BIS(F9, 4, sbc, "SBC", absolute_y) CPU_OP_BIS(FD, 4, sbc, "SBC", absolute_x) CPU_OP_BIS(FE, 7, inc, "INC", absolute_x) CPU_OP_EIS(03, 8, aso, "SLO", indirect_x) CPU_OP_EIS(07, 5, aso, "SLO", zero_page) CPU_OP_EIS(0F, 6, aso, "SLO", absolute) CPU_OP_EIS(13, 8, aso, "SLO", indirect_y) CPU_OP_EIS(17, 6, aso, "SLO", zero_page_x) CPU_OP_EIS(1B, 7, aso, "SLO", absolute_y) CPU_OP_EIS(1F, 7, aso, "SLO", absolute_x) CPU_OP_EIS(23, 8, rla, "RLA", indirect_x) CPU_OP_EIS(27, 5, rla, "RLA", zero_page) CPU_OP_EIS(2F, 6, rla, "RLA", absolute) CPU_OP_EIS(33, 8, rla, "RLA", indirect_y) CPU_OP_EIS(37, 6, rla, "RLA", zero_page_x) CPU_OP_EIS(3B, 7, rla, "RLA", absolute_y) CPU_OP_EIS(3F, 7, rla, "RLA", absolute_x) CPU_OP_EIS(43, 8, lse, "SRE", indirect_x) CPU_OP_EIS(47, 5, lse, "SRE", zero_page) CPU_OP_EIS(4F, 6, lse, "SRE", absolute) CPU_OP_EIS(53, 8, lse, "SRE", indirect_y) CPU_OP_EIS(57, 6, lse, "SRE", zero_page_x) CPU_OP_EIS(5B, 7, lse, "SRE", absolute_y) CPU_OP_EIS(5F, 7, lse, "SRE", absolute_x) CPU_OP_EIS(63, 8, rra, "RRA", indirect_x) CPU_OP_EIS(67, 5, rra, "RRA", zero_page) CPU_OP_EIS(6F, 6, rra, "RRA", absolute) CPU_OP_EIS(73, 8, rra, "RRA", indirect_y) CPU_OP_EIS(77, 6, rra, "RRA", zero_page_x) CPU_OP_EIS(7B, 7, rra, "RRA", absolute_y) CPU_OP_EIS(7F, 7, rra, "RRA", absolute_x) CPU_OP_EIS(83, 6, axs, "SAX", indirect_x) CPU_OP_EIS(87, 3, axs, "SAX", zero_page) CPU_OP_EIS(8F, 4, axs, "SAX", absolute) CPU_OP_EIS(93, 6, axa, "SAX", indirect_y) CPU_OP_EIS(97, 4, axs, "SAX", zero_page_y) CPU_OP_EIS(9F, 5, axa, "SAX", absolute_y) CPU_OP_EIS(A3, 6, lax, "LAX", indirect_x) CPU_OP_EIS(A7, 3, lax, "LAX", zero_page) CPU_OP_EIS(AF, 4, lax, "LAX", absolute) CPU_OP_EIS(B3, 5, lax, "LAX", indirect_y) CPU_OP_EIS(B7, 4, lax, "LAX", zero_page_y) CPU_OP_EIS(BF, 4, lax, "LAX", absolute_y) CPU_OP_EIS(C3, 8, dcm, "DCP", indirect_x) CPU_OP_EIS(C7, 5, dcm, "DCP", zero_page) CPU_OP_EIS(CF, 6, dcm, "DCP", absolute) CPU_OP_EIS(D3, 8, dcm, "DCP", indirect_y) CPU_OP_EIS(D7, 6, dcm, "DCP", zero_page_x) CPU_OP_EIS(DB, 7, dcm, "DCP", absolute_y) CPU_OP_EIS(DF, 7, dcm, "DCP", absolute_x) CPU_OP_EIS(E3, 8, ins, "ISB", indirect_x) CPU_OP_EIS(E7, 5, ins, "ISB", zero_page) CPU_OP_EIS(EB, 2, sbc, "SBC", immediate) CPU_OP_EIS(EF, 6, ins, "ISB", absolute) CPU_OP_EIS(F3, 8, ins, "ISB", indirect_y) CPU_OP_EIS(F7, 6, ins, "ISB", zero_page_x) CPU_OP_EIS(FB, 7, ins, "ISB", absolute_y) CPU_OP_EIS(FF, 7, ins, "ISB", absolute_x) CPU_OP_NII(04, zero_page) CPU_OP_NII(0C, absolute) CPU_OP_NII(14, zero_page_x) CPU_OP_NII(1A, implied) CPU_OP_NII(1C, absolute_x) CPU_OP_NII(34, zero_page_x) CPU_OP_NII(3A, implied) CPU_OP_NII(3C, absolute_x) CPU_OP_NII(44, zero_page) CPU_OP_NII(54, zero_page_x) CPU_OP_NII(5A, implied) CPU_OP_NII(5C, absolute_x) CPU_OP_NII(64, zero_page) CPU_OP_NII(74, zero_page_x) CPU_OP_NII(7A, implied) CPU_OP_NII(7C, absolute_x) CPU_OP_NII(80, immediate) CPU_OP_NII(D4, zero_page_x) CPU_OP_NII(DA, implied) CPU_OP_NII(DC, absolute_x) CPU_OP_NII(F4, zero_page_x) CPU_OP_NII(FA, implied) CPU_OP_NII(FC, absolute_x) cpu.P = 0x24; cpu.SP = 0x00; cpu.A = cpu.X = cpu.Y = 0; } void cpu_reset() { cpu.PC = cpu_reset_interrupt_address(); cpu.SP -= 3; cpu.P |= interrupt_flag; } void cpu_interrupt() { if (ppu_generates_nmi()) { cpu.P |= interrupt_flag; cpu_unset_flag(unused_bp); cpu_stack_pushw(cpu.PC); cpu_stack_pushb(cpu.P); cpu.PC = cpu_nmi_interrupt_address(); } } unsigned long long cpu_clock() { return cpu_cycles; } void cpu_run(long cycles) { cycles /= 3; while (cycles > 0) { op_code = memory_readb(cpu.PC++); if (cpu_op_address_mode[op_code] == NULL) { } else { cpu_op_address_mode[op_code](); cpu_op_handler[op_code](); } cycles -= cpu_op_cycles[op_code] + op_cycles; cpu_cycles -= cpu_op_cycles[op_code] + op_cycles; op_cycles = 0; } }