From 8e656aba3b07788aee11705e188e4431c46b7e68 Mon Sep 17 00:00:00 2001 From: Brad Grantham Date: Mon, 8 Jul 2024 07:49:11 -0700 Subject: [PATCH] import latest 6502 https://github.com/bradgrantham/cpu6502.git 8fb6aec1a855fa940011f3a95d0455dacf5559e0 --- cpu6502.h | 1948 ++++++++++++++++++++++++++--------------------------- 1 file changed, 948 insertions(+), 1000 deletions(-) diff --git a/cpu6502.h b/cpu6502.h index e1881a8..7408a6e 100644 --- a/cpu6502.h +++ b/cpu6502.h @@ -14,10 +14,12 @@ void write(uint16_t addr, uint8_t data); */ +// verify timing + /* Candidates for refactor effective address - carry flag from BCD and !BCD addition + arithmetic operation including BCD */ #ifndef CPU6502_H @@ -28,7 +30,7 @@ #include #ifndef EMULATE_65C02 -#define EMULATE_65C02 1 +#define EMULATE_65C02 0 #endif /* EMULATE_65C02 */ template @@ -37,8 +39,6 @@ struct CPU6502 CLK &clk; BUS &bus; - const static int32_t cycles[256]; - static constexpr uint8_t N = 0x80; static constexpr uint8_t V = 0x40; static constexpr uint8_t B2 = 0x20; @@ -58,21 +58,38 @@ struct CPU6502 INT, } exception; - std::vector> writes; + // XXX For debugging, normally couldn't set CPU PC directly + void set_pc(uint16_t addr) + { + pc = addr; + exception = NONE; + } + + uint8_t read(uint16_t address) + { + clk.add_cpu_cycles(1); + return bus.read(address); + } + + void write(uint16_t address, uint8_t value) + { + clk.add_cpu_cycles(1); + bus.write(address, value); + } void stack_push(uint8_t d) { - writes.push_back(std::make_pair(0x100 + s--, d)); + write(0x100 + s--, d); } uint8_t stack_pull() { - return bus.read(0x100 + ++s); + return read(0x100 + ++s); } uint8_t read_pc_inc() { - return bus.read(pc++); + return read(pc++); } void flag_change(uint8_t flag, bool v) @@ -80,7 +97,7 @@ struct CPU6502 if(v) { p |= flag; } else { - p &= ~flag; + p = (p & ~flag) | B2 | B; } } @@ -91,7 +108,7 @@ struct CPU6502 void flag_clear(uint8_t flag) { - p &= ~flag; + p = (p & ~flag) | B2 | B; } uint8_t carry() @@ -101,7 +118,7 @@ struct CPU6502 bool isset(uint8_t flag) { - return p & flag; + return (p | B | B2) & flag; } void set_flags(uint8_t flags, uint8_t v) @@ -152,17 +169,17 @@ struct CPU6502 a(0), x(0), y(0), - s(0xFF), - p(I), + s(0xFD), + p(I | B | B2 | Z), // XXX flooh m6502 starts up with Z set...? exception(RESET) { } void reset() { - s = 0xFF; - uint8_t low = bus.read(0xFFFC); - uint8_t high = bus.read(0xFFFD); + s = 0xFD; + uint8_t low = read(0xFFFC); + uint8_t high = read(0xFFFD); pc = low + high * 256; exception = NONE; } @@ -171,9 +188,9 @@ struct CPU6502 { stack_push((pc - 1) >> 8); stack_push((pc - 1) & 0xFF); - stack_push(p | B2); - uint8_t low = bus.read(0xFFFE); - uint8_t high = bus.read(0xFFFF); + stack_push((p | B2) & ~B); + uint8_t low = read(0xFFFE); + uint8_t high = read(0xFFFF); pc = low + high * 256; exception = NONE; } @@ -182,13 +199,161 @@ struct CPU6502 { stack_push((pc - 1) >> 8); stack_push((pc - 1) & 0xFF); - stack_push(p | B2); - uint8_t low = bus.read(0xFFFA); - uint8_t high = bus.read(0xFFFB); + stack_push((p | B2) & ~B); + uint8_t low = read(0xFFFA); + uint8_t high = read(0xFFFB); pc = low + high * 256; exception = NONE; } + void adc_bcd(uint8_t m, uint8_t carry) + { + uint8_t bcd_a = a / 16 * 10 + a % 16; + uint8_t bcd_m = m / 16 * 10 + m % 16; + flag_change(C, ((uint16_t)bcd_a + (uint16_t)bcd_m + carry) > 99); + flag_change(V, adc_overflow_d(bcd_a, bcd_m, carry)); + bcd_a = bcd_a + bcd_m + carry; + set_flags(N | Z, (bcd_a % 100)); + a = (bcd_a % 100) / 10 * 16 + bcd_a % 10; +#if EMULATE_65C02 + clk.add_cpu_cycles(1); // 1 more cycle for decimal mode on 65C02 +#endif /* EMULATE_65C02 */ + } + + void sbc_bcd(uint8_t m, uint8_t borrow) + { + uint8_t bcd_a = a / 16 * 10 + a % 16; + uint8_t bcd_m = m / 16 * 10 + m % 16; + flag_change(C, !(bcd_a < bcd_m + borrow)); + flag_change(V, sbc_overflow_d(bcd_a, bcd_m, borrow)); + if(bcd_m + borrow <= bcd_a) { + bcd_a = (bcd_a - (bcd_m + borrow)) % 100; + } else { + bcd_a = bcd_a + 100 - (bcd_m + borrow); + } + set_flags(N | Z, (bcd_a % 100)); + a = (bcd_a % 100) / 10 * 16 + bcd_a % 10; +#if EMULATE_65C02 + clk.add_cpu_cycles(1); // 1 more cycle for decimal mode on 65C02 +#endif /* EMULATE_65C02 */ + } + + void branch(bool condition) + { + int32_t rel = (read_pc_inc() + 128) % 256 - 128; + if(condition) { + clk.add_cpu_cycles(1); // 1 more cycle if branch taken + if((pc + rel) / 256 != pc / 256) { + clk.add_cpu_cycles(1); // 1 more cycle if address crosses pages + } + pc += rel; + } + } + + uint16_t absolute() + { + uint8_t low = read_pc_inc(); + uint8_t high = read_pc_inc(); + uint16_t address = low + high * 256; + return address; + } + + uint16_t indirect() + { + uint8_t low = read_pc_inc(); + uint8_t high = read_pc_inc(); + uint16_t addr = low + high * 256; + uint8_t addrl = read(addr); + uint8_t addrh = read(addr + 1); + return addrl + addrh * 256; + } + + uint16_t absolute_indexed_indirect() + { + uint8_t low = read_pc_inc(); + uint8_t high = read_pc_inc(); + uint16_t addr = low + high * 256 + x; + uint8_t addrl = read(addr); + uint8_t addrh = read(addr + 1); + return addrl + addrh * 256; + } + + uint16_t zeropage() + { + uint8_t address = read_pc_inc(); + return address; + } + + uint16_t zeropage_indirect() + { + uint8_t zpg = read_pc_inc(); + uint8_t low = read(zpg); + uint8_t high = read((zpg + 1) & 0xFF); + uint16_t address = low + high * 256; + return address; + } + + uint16_t zeropage_indexed_X() + { + uint8_t address = (read_pc_inc() + x) & 0xFF; + clk.add_cpu_cycles(1); + return address; + } + + uint16_t zeropage_indexed_Y() + { + uint8_t address = (read_pc_inc() + y) & 0xFF; + clk.add_cpu_cycles(1); + return address; + } + + uint16_t indirect_indexed(bool is_write) + { + uint8_t zpg = read_pc_inc(); + uint8_t low = read(zpg); + uint8_t high = read((zpg + 1) & 0xFF); + uint16_t base = low + high * 256; + uint16_t address = base + y; + if(is_write || ((base & 0xFF00) != (address & 0xFF00))) { + clk.add_cpu_cycles(1); + } + return address; + } + + uint16_t indexed_indirect() + { + uint8_t zpg = (read_pc_inc() + x) & 0xFF; + clk.add_cpu_cycles(1); + uint8_t low = read(zpg); + uint8_t high = read((zpg + 1) & 0xFF); + uint16_t address = low + high * 256; + return address; + } + + uint16_t absolute_indexed_X(bool is_write) + { + uint8_t low = read_pc_inc(); + uint8_t high = read_pc_inc(); + uint16_t base = low + high * 256; + uint16_t address = base + x; + if(is_write || ((base & 0xFF00) != (address & 0xFF00))) { + clk.add_cpu_cycles(1); + } + return address; + } + + uint16_t absolute_indexed_Y(bool is_write) + { + uint8_t low = read_pc_inc(); + uint8_t high = read_pc_inc(); + uint16_t base = low + high * 256; + uint16_t address = base + y; + if(is_write || ((base & 0xFF00) != (address & 0xFF00))) { + clk.add_cpu_cycles(1); + } + return address; + } + void cycle() { if(exception == RESET) { @@ -205,6 +370,220 @@ struct CPU6502 uint8_t m; switch(inst) { +// -- timing updated from CPU manual + + case 0x0A: { // ASL A + flag_change(C, a & 0x80); + set_flags(N | Z, a = a << 1); + clk.add_cpu_cycles(1); + break; + } + + case 0xEA: { // NOP + clk.add_cpu_cycles(1); + break; + } + + case 0x8A: { // TXA impl + set_flags(N | Z, a = x); + clk.add_cpu_cycles(1); + break; + } + + case 0xAA: { // TAX impl + set_flags(N | Z, x = a); + clk.add_cpu_cycles(1); + break; + } + + case 0xBA: { // TSX impl + set_flags(N | Z, x = s); + clk.add_cpu_cycles(1); + break; + } + + case 0x9A: { // TXS impl + s = x; + clk.add_cpu_cycles(1); + break; + } + + case 0xA8: { // TAY impl + set_flags(N | Z, y = a); + clk.add_cpu_cycles(1); + break; + } + + case 0x98: { // TYA impl + set_flags(N | Z, a = y); + clk.add_cpu_cycles(1); + break; + } + + case 0x18: { // CLC impl + flag_clear(C); + clk.add_cpu_cycles(1); + break; + } + + case 0x38: { // SEC impl + flag_set(C); + clk.add_cpu_cycles(1); + break; + } + + case 0xF8: { // SED impl + flag_set(D); + clk.add_cpu_cycles(1); + break; + } + + case 0xD8: { // CLD impl + flag_clear(D); + clk.add_cpu_cycles(1); + break; + } + + case 0x58: { // CLI impl + flag_clear(I); + clk.add_cpu_cycles(1); + break; + } + + case 0x78: { // SEI impl + flag_set(I); + clk.add_cpu_cycles(1); + break; + } + + case 0xB8: { // CLV impl + flag_clear(V); + clk.add_cpu_cycles(1); + break; + } + + case 0xCA: { // DEX impl + set_flags(N | Z, x = x - 1); + clk.add_cpu_cycles(1); + break; + } + + case 0x88: { // DEY impl + set_flags(N | Z, y = y - 1); + clk.add_cpu_cycles(1); + break; + } + + case 0xE8: { // INX impl + set_flags(N | Z, x = x + 1); + clk.add_cpu_cycles(1); + break; + } + + case 0xC8: { // INY impl + set_flags(N | Z, y = y + 1); + clk.add_cpu_cycles(1); + break; + } + + case 0x71: { // ADC (ind), Y + uint16_t addr = indirect_indexed(false); + m = read(addr); + uint8_t carry = isset(C) ? 1 : 0; + if(isset(D)) { + adc_bcd(m, carry); + } else { + flag_change(C, ((uint16_t)a + (uint16_t)m + carry) > 0xFF); + flag_change(V, adc_overflow(a, m, carry)); + set_flags(N | Z, a = a + m + carry); + } + break; + } + + case 0x61: { // ADC (ind, X) + uint16_t addr = indexed_indirect(); + m = read(addr); + uint8_t carry = isset(C) ? 1 : 0; + if(isset(D)) { + adc_bcd(m, carry); + } else { + flag_change(C, ((uint16_t)a + (uint16_t)m + carry) > 0xFF); + flag_change(V, adc_overflow(a, m, carry)); + set_flags(N | Z, a = a + m + carry); + } + break; + } + + case 0x6D: { // ADC abs + uint16_t addr = absolute(); + m = read(addr); + uint8_t carry = isset(C) ? 1 : 0; + if(isset(D)) { + adc_bcd(m, carry); + } else { + flag_change(C, ((uint16_t)a + (uint16_t)m + carry) > 0xFF); + flag_change(V, adc_overflow(a, m, carry)); + set_flags(N | Z, a = a + m + carry); + } + break; + } + + case 0x65: { // ADC zpg + uint8_t zpg = zeropage(); + m = read(zpg); + uint8_t carry = isset(C) ? 1 : 0; + if(isset(D)) { + adc_bcd(m, carry); + } else { + flag_change(C, ((uint16_t)a + (uint16_t)m + carry) > 0xFF); + flag_change(V, adc_overflow(a, m, carry)); + set_flags(N | Z, a = a + m + carry); + } + break; + } + + case 0x7D: { // ADC abs, X + uint16_t addr = absolute_indexed_X(false); + m = read(addr); + uint8_t carry = isset(C) ? 1 : 0; + if(isset(D)) { + adc_bcd(m, carry); + } else { + flag_change(C, ((uint16_t)a + (uint16_t)m + carry) > 0xFF); + flag_change(V, adc_overflow(a, m, carry)); + set_flags(N | Z, a = a + m + carry); + } + break; + } + + case 0x79: { // ADC abs, Y + uint16_t addr = absolute_indexed_Y(false); + m = read(addr); + uint8_t carry = isset(C) ? 1 : 0; + if(isset(D)) { + adc_bcd(m, carry); + } else { + flag_change(C, ((uint16_t)a + (uint16_t)m + carry) > 0xFF); + flag_change(V, adc_overflow(a, m, carry)); + set_flags(N | Z, a = a + m + carry); + } + break; + } + + case 0x69: { // ADC imm + m = read_pc_inc(); + uint8_t carry = isset(C) ? 1 : 0; + if(isset(D)) { + adc_bcd(m, carry); + } else { + flag_change(C, ((uint16_t)a + (uint16_t)m + carry) > 0xFF); + flag_change(V, adc_overflow(a, m, carry)); + set_flags(N | Z, a = a + m + carry); + } + break; + } + + case 0x00: { // BRK stack_push((pc + 1) >> 8); stack_push((pc + 1) & 0xFF); @@ -213,360 +592,256 @@ struct CPU6502 #if EMULATE_65C02 p &= ~D; #endif /* EMULATE_65C02 */ - uint8_t low = bus.read(0xFFFE); - uint8_t high = bus.read(0xFFFF); + uint8_t low = read(0xFFFE); + uint8_t high = read(0xFFFF); + clk.add_cpu_cycles(1); pc = low + high * 256; exception = NONE; break; } - case 0xEA: { // NOP - break; - } - - case 0x8A: { // TXA - set_flags(N | Z, a = x); - break; - } - - case 0xAA: { // TAX - set_flags(N | Z, x = a); - break; - } - - case 0xBA: { // TSX - set_flags(N | Z, x = s); - break; - } - - case 0x9A: { // TXS - s = x; - break; - } - - case 0xA8: { // TAY - set_flags(N | Z, y = a); - break; - } - - case 0x98: { // TYA - set_flags(N | Z, a = y); - break; - } - - case 0x18: { // CLC - flag_clear(C); - break; - } - - case 0x38: { // SEC - flag_set(C); - break; - } - - case 0xF8: { // SED - flag_set(D); - break; - } - - case 0xD8: { // CLD - flag_clear(D); - break; - } - - case 0x58: { // CLI - flag_clear(I); - break; - } - - case 0x78: { // SEI - flag_set(I); - break; - } - - case 0xB8: { // CLV - flag_clear(V); + case 0x20: { // JSR abs + uint16_t to_push = pc + 1; + uint16_t addr = absolute(); + stack_push(to_push >> 8); + stack_push(to_push & 0xFF); + clk.add_cpu_cycles(1); + pc = addr; break; } case 0xC6: { // DEC zpg - uint8_t zpg = read_pc_inc(); - set_flags(N | Z, m = bus.read(zpg) - 1); - writes.push_back(std::make_pair(zpg, m)); + uint8_t zpg = zeropage(); + set_flags(N | Z, m = read(zpg) - 1); + clk.add_cpu_cycles(1); + write(zpg, m); break; } case 0xD6: { // DEC zpg, X - uint8_t zpg = (read_pc_inc() + x) % 0xFF; - set_flags(N | Z, m = bus.read(zpg) - 1); - writes.push_back(std::make_pair(zpg, m)); - break; - } - - case 0xDE: { // DEC abs, X - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256 + x; - set_flags(N | Z, m = bus.read(addr) - 1); - writes.push_back(std::make_pair(addr, m)); + uint8_t zpg = zeropage_indexed_X(); + set_flags(N | Z, m = read(zpg) - 1); + clk.add_cpu_cycles(1); + write(zpg, m); break; } case 0xCE: { // DEC abs - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - set_flags(N | Z, m = bus.read(addr) - 1); - writes.push_back(std::make_pair(addr, m)); + uint16_t addr = absolute(); + set_flags(N | Z, m = read(addr) - 1); + clk.add_cpu_cycles(1); + write(addr, m); break; } - case 0xCA: { // DEX - set_flags(N | Z, x = x - 1); - break; - } - - case 0xFE: { // INC abs, X - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256 + x; - if((addr - x) / 256 != addr / 256) - clk.add_cpu_cycles(1); - set_flags(N | Z, m = bus.read(addr) + 1); - writes.push_back(std::make_pair(addr, m)); - break; - } - - case 0xEE: { // INC abs - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - set_flags(N | Z, m = bus.read(addr) + 1); - writes.push_back(std::make_pair(addr, m)); + case 0xDE: { // DEC abs, X + uint16_t addr = absolute_indexed_X(true); + set_flags(N | Z, m = read(addr) - 1); + clk.add_cpu_cycles(1); + write(addr, m); break; } case 0xE6: { // INC zpg - uint8_t zpg = read_pc_inc(); - set_flags(N | Z, m = bus.read(zpg) + 1); - writes.push_back(std::make_pair(zpg, m)); + uint8_t zpg = zeropage(); + set_flags(N | Z, m = read(zpg) + 1); + clk.add_cpu_cycles(1); + write(zpg, m); break; } case 0xF6: { // INC zpg, X - uint8_t zpg = (read_pc_inc() + x) & 0xFF; - set_flags(N | Z, m = bus.read(zpg) + 1); - writes.push_back(std::make_pair(zpg, m)); + uint8_t zpg = zeropage_indexed_X(); + set_flags(N | Z, m = read(zpg) + 1); + clk.add_cpu_cycles(1); + write(zpg, m); break; } - case 0xE8: { // INX - set_flags(N | Z, x = x + 1); + case 0xEE: { // INC abs + uint16_t addr = absolute(); + set_flags(N | Z, m = read(addr) + 1); + clk.add_cpu_cycles(1); + write(addr, m); break; } - case 0xC8: { // INY - set_flags(N | Z, y = y + 1); + case 0xFE: { // INC abs, X + uint16_t addr = absolute_indexed_X(true); + set_flags(N | Z, m = read(addr) + 1); + clk.add_cpu_cycles(1); + write(addr, m); break; } - case 0x10: { // BPL - int32_t rel = (read_pc_inc() + 128) % 256 - 128; - if(!isset(N)) { - clk.add_cpu_cycles(1); - if((pc + rel) / 256 != pc / 256) - clk.add_cpu_cycles(1); - pc += rel; - } + case 0x10: { // BPL rel + branch(!isset(N)); break; } - case 0x50: { // BVC - int32_t rel = (read_pc_inc() + 128) % 256 - 128; - if(!isset(V)) { - clk.add_cpu_cycles(1); - if((pc + rel) / 256 != pc / 256) - clk.add_cpu_cycles(1); - pc += rel; - } + case 0x50: { // BVC rel + branch(!isset(V)); break; } - case 0x70: { // BVS - int32_t rel = (read_pc_inc() + 128) % 256 - 128; - if(isset(V)) { - clk.add_cpu_cycles(1); - if((pc + rel) / 256 != pc / 256) - clk.add_cpu_cycles(1); - pc += rel; - } + case 0x70: { // BVS rel + branch(isset(V)); break; } - case 0x30: { // BMI - int32_t rel = (read_pc_inc() + 128) % 256 - 128; - if(isset(N)) { - clk.add_cpu_cycles(1); - if((pc + rel) / 256 != pc / 256) - clk.add_cpu_cycles(1); - pc += rel; - } + case 0x30: { // BMI rel + branch(isset(N)); break; } - case 0x90: { // BCC - int32_t rel = (read_pc_inc() + 128) % 256 - 128; - if(!isset(C)) { - clk.add_cpu_cycles(1); - if((pc + rel) / 256 != pc / 256) - clk.add_cpu_cycles(1); - pc += rel; - } + case 0x90: { // BCC rel + branch(!isset(C)); break; } - case 0xB0: { // BCS - int32_t rel = (read_pc_inc() + 128) % 256 - 128; - if(isset(C)) { - clk.add_cpu_cycles(1); - if((pc + rel) / 256 != pc / 256) - clk.add_cpu_cycles(1); - pc += rel; - } + case 0xB0: { // BCS rel + branch(isset(C)); break; } - case 0xD0: { // BNE - int32_t rel = (read_pc_inc() + 128) % 256 - 128; - if(!isset(Z)) { - clk.add_cpu_cycles(1); - if((pc + rel) / 256 != pc / 256) - clk.add_cpu_cycles(1); - pc += rel; - } + case 0xD0: { // BNE rel + branch(!isset(Z)); break; } - case 0xF0: { // BEQ - int32_t rel = (read_pc_inc() + 128) % 256 - 128; - if(isset(Z)) { - clk.add_cpu_cycles(1); - if((pc + rel) / 256 != pc / 256) - clk.add_cpu_cycles(1); - pc += rel; - } + case 0xF0: { // BEQ rel + branch(isset(Z)); break; } +#if EMULATE_65C02 + case 0x80: { // BRA rel, 65C02 + branch(true); + break; + } +#endif case 0xA1: { // LDA (ind, X) - uint8_t zpg = (read_pc_inc() + x) & 0xFF; - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256; - set_flags(N | Z, a = bus.read(addr)); + uint16_t addr = indexed_indirect(); + set_flags(N | Z, a = read(addr)); break; } case 0xB5: { // LDA zpg, X - uint8_t zpg = read_pc_inc(); - uint16_t addr = zpg + x; - set_flags(N | Z, a = bus.read(addr & 0xFF)); + uint8_t addr = zeropage_indexed_X(); + set_flags(N | Z, a = read(addr)); break; } - case 0xB1: { // LDA ind, Y - uint8_t zpg = read_pc_inc(); - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256 + y; - if((addr - y) / 256 != addr / 256) - clk.add_cpu_cycles(1); - set_flags(N | Z, a = bus.read(addr)); + case 0xB1: { // LDA (ind), Y + uint16_t addr = indirect_indexed(false); + set_flags(N | Z, a = read(addr)); break; } + case 0x4A: { // LSR A + flag_change(C, a & 0x01); + clk.add_cpu_cycles(1); + set_flags(N | Z, a = a >> 1); + break; + } + + case 0x2A: { // ROL A + bool c = isset(C); + flag_change(C, a & 0x80); + clk.add_cpu_cycles(1); + set_flags(N | Z, a = (c ? 0x01 : 0x00) | (a << 1)); + break; + } + + case 0x6A: { // ROR A + bool c = isset(C); + flag_change(C, a & 0x01); + clk.add_cpu_cycles(1); + set_flags(N | Z, a = (c ? 0x80 : 0x00) | (a >> 1)); + break; + } + +// -- in progress + case 0xA5: { // LDA zpg - uint8_t zpg = read_pc_inc(); - set_flags(N | Z, a = bus.read(zpg)); + uint8_t zpg = zeropage(); + set_flags(N | Z, a = read(zpg)); break; } + case 0xB9: { // LDA abs, Y + uint16_t addr = absolute_indexed_Y(false); + set_flags(N | Z, a = read(addr)); + break; + } + + case 0xBD: { // LDA abs, X + uint16_t addr = absolute_indexed_X(false); + set_flags(N | Z, a = read(addr)); + break; + } + + case 0xA9: { // LDA imm + uint8_t imm = read_pc_inc(); + set_flags(N | Z, a = imm); + break; + } + + case 0xAD: { // LDA abs + uint16_t addr = absolute(); + set_flags(N | Z, a = read(addr)); + break; + } + +#if EMULATE_65C02 + + case 0xB2: { // LDA (zpg), 65C02 + uint16_t addr = zeropage_indirect(); + set_flags(N | Z, a = read(addr)); + break; + } + +#endif + +// -- timing not updated from CPU manual + case 0xDD: { // CMP abs, X - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr + x); - if((addr + x) / 256 != addr / 256) - clk.add_cpu_cycles(1); + uint16_t addr = absolute_indexed_X(false); + m = read(addr); flag_change(C, m <= a); set_flags(N | Z, m = a - m); break; } case 0xC1: { // CMP (ind, X) - uint8_t zpg = (read_pc_inc() + x) & 0xFF; - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256; - m = bus.read(addr); + uint16_t addr = indexed_indirect(); + m = read(addr); flag_change(C, m <= a); set_flags(N | Z, m = a - m); break; } case 0xD9: { // CMP abs, Y - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr + y); - if((addr + y) / 256 != addr / 256) - clk.add_cpu_cycles(1); + uint16_t addr = absolute_indexed_Y(false); + m = read(addr); flag_change(C, m <= a); set_flags(N | Z, m = a - m); break; } - case 0xB9: { // LDA abs, Y - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - set_flags(N | Z, a = bus.read(addr + y)); - if((addr + y) / 256 != addr / 256) - clk.add_cpu_cycles(1); - break; - } - case 0xBC: { // LDY abs, X - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - set_flags(N | Z, y = bus.read(addr + x)); - if((addr + x) / 256 != addr / 256) - clk.add_cpu_cycles(1); - break; - } - - case 0xBD: { // LDA abs, X - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - set_flags(N | Z, a = bus.read(addr + x)); - if((addr + x) / 256 != addr / 256) - clk.add_cpu_cycles(1); + uint16_t addr = absolute_indexed_X(false); + set_flags(N | Z, y = read(addr)); break; } case 0xF5: { // SBC zpg, X - uint8_t zpg = (read_pc_inc() + x) & 0xFF; - m = bus.read(zpg); + uint8_t zpg = zeropage_indexed_X(); + m = read(zpg); uint8_t borrow = isset(C) ? 0 : 1; if(isset(D)) { - uint8_t bcd = a / 16 * 10 + a % 16; - flag_change(C, !(bcd < m + borrow)); - flag_change(V, sbc_overflow_d(bcd, m, borrow)); - set_flags(N | Z, bcd = bcd - (m + borrow)); - a = bcd / 10 * 16 + bcd % 10; + sbc_bcd(m, borrow); } else { flag_change(C, !(a < (m + borrow))); flag_change(V, sbc_overflow(a, m, borrow)); @@ -576,15 +851,11 @@ struct CPU6502 } case 0xE5: { // SBC zpg - uint8_t zpg = read_pc_inc(); - m = bus.read(zpg); + uint8_t zpg = zeropage(); + m = read(zpg); uint8_t borrow = isset(C) ? 0 : 1; if(isset(D)) { - uint8_t bcd = a / 16 * 10 + a % 16; - flag_change(C, !(bcd < m + borrow)); - flag_change(V, sbc_overflow_d(bcd, m, borrow)); - set_flags(N | Z, bcd = bcd - (m + borrow)); - a = bcd / 10 * 16 + bcd % 10; + sbc_bcd(m, borrow); } else { flag_change(C, !(a < (m + borrow))); flag_change(V, sbc_overflow(a, m, borrow)); @@ -593,21 +864,28 @@ struct CPU6502 break; } - case 0xE1: { // SBC ind, X - uint8_t zpg = (read_pc_inc() + x) & 0xFF; - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256; - if((addr - y) / 256 != addr / 256) - clk.add_cpu_cycles(1); - m = bus.read(addr); +#if EMULATE_65C02 + case 0xF2: { // SBC (zpg), 65C02 + uint16_t addr = zeropage_indirect(); + m = read(addr); uint8_t borrow = isset(C) ? 0 : 1; if(isset(D)) { - uint8_t bcd = a / 16 * 10 + a % 16; - flag_change(C, !(bcd < m + borrow)); - flag_change(V, sbc_overflow_d(bcd, m, borrow)); - set_flags(N | Z, bcd = bcd - (m + borrow)); - a = bcd / 10 * 16 + bcd % 10; + sbc_bcd(m, borrow); + } else { + flag_change(C, !(a < (m + borrow))); + flag_change(V, sbc_overflow(a, m, borrow)); + set_flags(N | Z, a = a - (m + borrow)); + } + break; + } +#endif /* EMULATE_65C02 */ + + case 0xE1: { // SBC (ind, X), 65C02 + uint16_t addr = indexed_indirect(); + m = read(addr); + uint8_t borrow = isset(C) ? 0 : 1; + if(isset(D)) { + sbc_bcd(m, borrow); } else { flag_change(C, !(a < (m + borrow))); flag_change(V, sbc_overflow(a, m, borrow)); @@ -616,21 +894,12 @@ struct CPU6502 break; } - case 0xF1: { // SBC ind, Y - uint8_t zpg = read_pc_inc(); - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256 + y; - if((addr - y) / 256 != addr / 256) - clk.add_cpu_cycles(1); - m = bus.read(addr); + case 0xF1: { // SBC (ind), Y + uint16_t addr = indirect_indexed(false); + m = read(addr); uint8_t borrow = isset(C) ? 0 : 1; if(isset(D)) { - uint8_t bcd = a / 16 * 10 + a % 16; - flag_change(C, !(bcd < m + borrow)); - flag_change(V, sbc_overflow_d(bcd, m, borrow)); - set_flags(N | Z, bcd = bcd - (m + borrow)); - a = bcd / 10 * 16 + bcd % 10; + sbc_bcd(m, borrow); } else { flag_change(C, !(a < (m + borrow))); flag_change(V, sbc_overflow(a, m, borrow)); @@ -640,19 +909,11 @@ struct CPU6502 } case 0xF9: { // SBC abs, Y - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256 + y; - if((addr - y) / 256 != addr / 256) - clk.add_cpu_cycles(1); - uint8_t m = bus.read(addr); + uint16_t addr = absolute_indexed_Y(false); + uint8_t m = read(addr); uint8_t borrow = isset(C) ? 0 : 1; if(isset(D)) { - uint8_t bcd = a / 16 * 10 + a % 16; - flag_change(C, !(bcd < m + borrow)); - flag_change(V, sbc_overflow_d(bcd, m, borrow)); - set_flags(N | Z, bcd = bcd - (m + borrow)); - a = bcd / 10 * 16 + bcd % 10; + sbc_bcd(m, borrow); } else { flag_change(C, !(a < (m + borrow))); flag_change(V, sbc_overflow(a, m, borrow)); @@ -662,19 +923,11 @@ struct CPU6502 } case 0xFD: { // SBC abs, X - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256 + x; - if((addr - x) / 256 != addr / 256) - clk.add_cpu_cycles(1); - uint8_t m = bus.read(addr); + uint16_t addr = absolute_indexed_X(false); + uint8_t m = read(addr); uint8_t borrow = isset(C) ? 0 : 1; if(isset(D)) { - uint8_t bcd = a / 16 * 10 + a % 16; - flag_change(C, !(bcd < m + borrow)); - flag_change(V, sbc_overflow_d(bcd, m, borrow)); - set_flags(N | Z, bcd = bcd - (m + borrow)); - a = bcd / 10 * 16 + bcd % 10; + sbc_bcd(m, borrow); } else { flag_change(C, !(a < (m + borrow))); flag_change(V, sbc_overflow(a, m, borrow)); @@ -684,17 +937,11 @@ struct CPU6502 } case 0xED: { // SBC abs - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - uint8_t m = bus.read(addr); + uint16_t addr = absolute(); + uint8_t m = read(addr); uint8_t borrow = isset(C) ? 0 : 1; if(isset(D)) { - uint8_t bcd = a / 16 * 10 + a % 16; - flag_change(C, !(bcd < m + borrow)); - flag_change(V, sbc_overflow_d(bcd, m, borrow)); - set_flags(N | Z, bcd = bcd - (m + borrow)); - a = bcd / 10 * 16 + bcd % 10; + sbc_bcd(m, borrow); } else { flag_change(C, !(a < (m + borrow))); flag_change(V, sbc_overflow(a, m, borrow)); @@ -707,11 +954,7 @@ struct CPU6502 uint8_t m = read_pc_inc(); uint8_t borrow = isset(C) ? 0 : 1; if(isset(D)) { - uint8_t bcd = a / 16 * 10 + a % 16; - flag_change(C, !(bcd < m + borrow)); - flag_change(V, sbc_overflow_d(bcd, m, borrow)); - set_flags(N | Z, bcd = bcd - (m + borrow)); - a = bcd / 10 * 16 + bcd % 10; + sbc_bcd(m, borrow); } else { flag_change(C, !(a < (m + borrow))); flag_change(V, sbc_overflow(a, m, borrow)); @@ -720,312 +963,152 @@ struct CPU6502 break; } - case 0x71: { // ADC (ind), Y - uint8_t zpg = read_pc_inc(); - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256 + y; - if((addr - y) / 256 != addr / 256) - clk.add_cpu_cycles(1); - m = bus.read(addr); - uint8_t carry = isset(C) ? 1 : 0; - if(isset(D)) { - uint8_t bcd = a / 16 * 10 + a % 16; - flag_change(C, ((uint16_t)bcd + (uint16_t)m + carry) > 99); - flag_change(V, adc_overflow_d(bcd, m, carry)); - set_flags(N | Z, bcd = bcd + m + carry); - a = bcd / 10 * 16 + bcd % 10 - (isset(C) ? 0xA0 : 0); - } else { - flag_change(C, ((uint16_t)a + (uint16_t)m + carry) > 0xFF); - flag_change(V, adc_overflow(a, m, carry)); - set_flags(N | Z, a = a + m + carry); - } - break; - } - - case 0x61: { // ADC (ind, X) - uint8_t zpg = (read_pc_inc() + x) & 0xFF; - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256; - if((addr - y) / 256 != addr / 256) - clk.add_cpu_cycles(1); - m = bus.read(addr); - uint8_t carry = isset(C) ? 1 : 0; - if(isset(D)) { - uint8_t bcd = a / 16 * 10 + a % 16; - flag_change(C, ((uint16_t)bcd + (uint16_t)m + carry) > 99); - flag_change(V, adc_overflow_d(bcd, m, carry)); - set_flags(N | Z, bcd = bcd + m + carry); - a = bcd / 10 * 16 + bcd % 10 - (isset(C) ? 0xA0 : 0); - } else { - flag_change(C, ((uint16_t)a + (uint16_t)m + carry) > 0xFF); - flag_change(V, adc_overflow(a, m, carry)); - set_flags(N | Z, a = a + m + carry); - } - break; - } - - case 0x6D: { // ADC abs - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr); - uint8_t carry = isset(C) ? 1 : 0; - if(isset(D)) { - uint8_t bcd = a / 16 * 10 + a % 16; - flag_change(C, ((uint16_t)bcd + (uint16_t)m + carry) > 99); - flag_change(V, adc_overflow_d(bcd, m, carry)); - set_flags(N | Z, bcd = bcd + m + carry); - a = bcd / 10 * 16 + bcd % 10 - (isset(C) ? 0xA0 : 0); - } else { - flag_change(C, ((uint16_t)a + (uint16_t)m + carry) > 0xFF); - flag_change(V, adc_overflow(a, m, carry)); - set_flags(N | Z, a = a + m + carry); - } - break; - } - - case 0x65: { // ADC - uint8_t zpg = read_pc_inc(); - m = bus.read(zpg); - uint8_t carry = isset(C) ? 1 : 0; - if(isset(D)) { - uint8_t bcd = a / 16 * 10 + a % 16; - flag_change(C, ((uint16_t)bcd + (uint16_t)m + carry) > 99); - flag_change(V, adc_overflow_d(bcd, m, carry)); - set_flags(N | Z, bcd = bcd + m + carry); - a = bcd / 10 * 16 + bcd % 10 - (isset(C) ? 0xA0 : 0); - } else { - flag_change(C, ((uint16_t)a + (uint16_t)m + carry) > 0xFF); - flag_change(V, adc_overflow(a, m, carry)); - set_flags(N | Z, a = a + m + carry); - } - break; - } - - case 0x7D: { // ADC abs, X - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256 + x; - if((addr - x) / 256 != addr / 256) - clk.add_cpu_cycles(1); - m = bus.read(addr); - uint8_t carry = isset(C) ? 1 : 0; - if(isset(D)) { - uint8_t bcd = a / 16 * 10 + a % 16; - flag_change(C, ((uint16_t)bcd + (uint16_t)m + carry) > 99); - flag_change(V, adc_overflow_d(bcd, m, carry)); - set_flags(N | Z, bcd = bcd + m + carry); - a = bcd / 10 * 16 + bcd % 10 - (isset(C) ? 0xA0 : 0); - } else { - flag_change(C, ((uint16_t)a + (uint16_t)m + carry) > 0xFF); - flag_change(V, adc_overflow(a, m, carry)); - set_flags(N | Z, a = a + m + carry); - } - break; - } - - case 0x79: { // ADC abs, Y - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256 + y; - if((addr - y) / 256 != addr / 256) - clk.add_cpu_cycles(1); - m = bus.read(addr); - uint8_t carry = isset(C) ? 1 : 0; - if(isset(D)) { - uint8_t bcd = a / 16 * 10 + a % 16; - flag_change(C, ((uint16_t)bcd + (uint16_t)m + carry) > 99); - flag_change(V, adc_overflow_d(bcd, m, carry)); - set_flags(N | Z, bcd = bcd + m + carry); - a = bcd / 10 * 16 + bcd % 10 - (isset(C) ? 0xA0 : 0); - } else { - flag_change(C, ((uint16_t)a + (uint16_t)m + carry) > 0xFF); - flag_change(V, adc_overflow(a, m, carry)); - set_flags(N | Z, a = a + m + carry); - } - break; - } - - case 0x69: { // ADC - m = read_pc_inc(); - uint8_t carry = isset(C) ? 1 : 0; - if(isset(D)) { - uint8_t bcd = a / 16 * 10 + a % 16; - flag_change(C, ((uint16_t)bcd + (uint16_t)m + carry) > 99); - flag_change(V, adc_overflow_d(bcd, m, carry)); - set_flags(N | Z, bcd = bcd + m + carry); - a = bcd / 10 * 16 + bcd % 10 - (isset(C) ? 0xA0 : 0); - } else { - flag_change(C, ((uint16_t)a + (uint16_t)m + carry) > 0xFF); - flag_change(V, adc_overflow(a, m, carry)); - set_flags(N | Z, a = a + m + carry); - } - break; - } - case 0x0E: { // ASL abs - uint16_t addr = read_pc_inc() + read_pc_inc() * 256; - m = bus.read(addr); + uint16_t addr = absolute(); + m = read(addr); + clk.add_cpu_cycles(1); flag_change(C, m & 0x80); set_flags(N | Z, m = m << 1); - writes.push_back(std::make_pair(addr, m)); + write(addr, m); break; } - case 0x1E: { // ASL abs - uint16_t addr = read_pc_inc() + read_pc_inc() * 256; - m = bus.read(addr + x); + case 0x1E: { // ASL abs, X +#if EMULATE_65C02 + uint16_t addr = absolute_indexed_X(false); +#else /* !EMULATE_65C02 */ + uint16_t addr = absolute_indexed_X(true); +#endif /* EMULATE_65C02 */ + m = read(addr); + clk.add_cpu_cycles(1); flag_change(C, m & 0x80); set_flags(N | Z, m = m << 1); - writes.push_back(std::make_pair(addr + x, m)); + write(addr, m); break; } - case 0x06: { // ASL - uint8_t zpg = read_pc_inc(); - m = bus.read(zpg); + case 0x06: { // ASL zpg + uint8_t zpg = zeropage(); + m = read(zpg); + clk.add_cpu_cycles(1); flag_change(C, m & 0x80); set_flags(N | Z, m = m << 1); - writes.push_back(std::make_pair(zpg, m)); + write(zpg, m); break; } - case 0x16: { // ASL - uint8_t zpg = read_pc_inc(); - m = bus.read((zpg + x) & 0xFF); + case 0x16: { // ASL zpg, X + uint8_t zpg = zeropage_indexed_X(); + m = read(zpg); + clk.add_cpu_cycles(1); flag_change(C, m & 0x80); set_flags(N | Z, m = m << 1); - bus.write((zpg + x) & 0xFF, m); - break; - } - - case 0x0A: { // ASL - flag_change(C, a & 0x80); - set_flags(N | Z, a = a << 1); + write(zpg, m); break; } case 0x5E: { // LSR abs, X - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr + x); +#if EMULATE_65C02 + uint16_t addr = absolute_indexed_X(false); +#else /* !EMULATE_65C02 */ + uint16_t addr = absolute_indexed_X(true); +#endif /* EMULATE_65C02 */ + m = read(addr); + clk.add_cpu_cycles(1); flag_change(C, m & 0x01); set_flags(N | Z, m = m >> 1); - writes.push_back(std::make_pair(addr + x, m)); + write(addr, m); break; } - case 0x46: { // LSR - uint8_t zpg = read_pc_inc(); - m = bus.read(zpg); + case 0x46: { // LSR zpg + uint8_t zpg = zeropage(); + m = read(zpg); + clk.add_cpu_cycles(1); flag_change(C, m & 0x01); set_flags(N | Z, m = m >> 1); - writes.push_back(std::make_pair(zpg, m)); + write(zpg, m); break; } case 0x56: { // LSR zpg, X - uint8_t zpg = read_pc_inc() + x; - m = bus.read(zpg & 0xFF); + uint8_t zpg = zeropage_indexed_X(); + m = read(zpg); + clk.add_cpu_cycles(1); flag_change(C, m & 0x01); set_flags(N | Z, m = m >> 1); - writes.push_back(std::make_pair(zpg, m)); + write(zpg, m); break; } - case 0x4E: { // LSR - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr); + case 0x4E: { // LSR abs + uint16_t addr = absolute(); + m = read(addr); + clk.add_cpu_cycles(1); flag_change(C, m & 0x01); set_flags(N | Z, m = m >> 1); - writes.push_back(std::make_pair(addr, m)); - break; - } - - case 0x4A: { // LSR - flag_change(C, a & 0x01); - set_flags(N | Z, a = a >> 1); + write(addr, m); break; } case 0x68: { // PLA + clk.add_cpu_cycles(1); + clk.add_cpu_cycles(1); // Pipelined pre-increment set_flags(N | Z, a = stack_pull()); break; } case 0x48: { // PHA + clk.add_cpu_cycles(1); stack_push(a); break; } case 0x01: { // ORA (ind, X) - uint8_t zpg = (read_pc_inc() + x) & 0xFF; - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256; - m = bus.read(addr); + uint16_t addr = indexed_indirect(); + m = read(addr); set_flags(N | Z, a = a | m); break; } case 0x15: { // ORA zpg, X - uint8_t zpg = (read_pc_inc() + x) & 0xFF; - m = bus.read(zpg); + uint8_t zpg = zeropage_indexed_X(); + m = read(zpg); set_flags(N | Z, a = a | m); break; } case 0x0D: { // ORA abs - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr); + uint16_t addr = absolute(); + m = read(addr); set_flags(N | Z, a = a | m); break; } case 0x19: { // ORA abs, Y - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr + y); - if((addr + y) / 256 != addr / 256) - clk.add_cpu_cycles(1); + uint16_t addr = absolute_indexed_Y(false); + m = read(addr); set_flags(N | Z, a = a | m); break; } case 0x1D: { // ORA abs, X - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr + x); - if((addr + x) / 256 != addr / 256) - clk.add_cpu_cycles(1); + uint16_t addr = absolute_indexed_X(false); + m = read(addr); set_flags(N | Z, a = a | m); break; } case 0x11: { // ORA (ind), Y - uint8_t zpg = read_pc_inc(); - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256 + y; - if((addr - y) / 256 != addr / 256) - clk.add_cpu_cycles(1); - m = bus.read(addr); + uint16_t addr = indirect_indexed(false); + m = read(addr); set_flags(N | Z, a = a | m); break; } case 0x05: { // ORA zpg - uint8_t zpg = read_pc_inc(); - m = bus.read(zpg); + uint8_t zpg = zeropage(); + m = read(zpg); set_flags(N | Z, a = a | m); break; } @@ -1036,65 +1119,54 @@ struct CPU6502 break; } +#if EMULATE_65C02 + case 0x32: { // AND (zpg), 65C02 + uint16_t addr = zeropage_indirect(); + m = read(addr); + set_flags(N | Z, a = a & m); + break; + } +#endif /* EMULATE_65C02 */ + case 0x35: { // AND zpg, X - uint8_t zpg = (read_pc_inc() + x) & 0xFF; - set_flags(N | Z, a = a & bus.read(zpg)); + uint8_t zpg = zeropage_indexed_X(); + set_flags(N | Z, a = a & read(zpg)); break; } case 0x21: { // AND (ind, X) - uint8_t zpg = (read_pc_inc() + x) & 0xFF; - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256; - if((addr - y) / 256 != addr / 256) - clk.add_cpu_cycles(1); - set_flags(N | Z, a = a & bus.read(addr)); + uint16_t addr = indexed_indirect(); + set_flags(N | Z, a = a & read(addr)); break; } - case 0x31: { // AND (ind), y - uint8_t zpg = read_pc_inc(); - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256 + y; - if((addr - y) / 256 != addr / 256) - clk.add_cpu_cycles(1); - set_flags(N | Z, a = a & bus.read(addr)); + case 0x31: { // AND (ind), Y + uint16_t addr = indirect_indexed(false); + set_flags(N | Z, a = a & read(addr)); break; } - case 0x3D: { // AND abs, x - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - set_flags(N | Z, a = a & bus.read(addr + x)); - if((addr + x) / 256 != addr / 256) - clk.add_cpu_cycles(1); + case 0x3D: { // AND abs, X + uint16_t addr = absolute_indexed_X(false); + set_flags(N | Z, a = a & read(addr)); break; } - case 0x39: { // AND abs, y - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - set_flags(N | Z, a = a & bus.read(addr + y)); - if((addr + y) / 256 != addr / 256) - clk.add_cpu_cycles(1); + case 0x39: { // AND abs, Y + uint16_t addr = absolute_indexed_Y(false); + set_flags(N | Z, a = a & read(addr)); break; } case 0x2D: { // AND abs - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - set_flags(N | Z, a = a & bus.read(addr)); + uint16_t addr = absolute(); + set_flags(N | Z, a = a & read(addr)); break; } case 0x25: { // AND zpg - uint8_t zpg = read_pc_inc(); - set_flags(N | Z, a = a & bus.read(zpg)); + uint8_t zpg = zeropage(); + set_flags(N | Z, a = a & read(zpg)); break; } @@ -1104,458 +1176,407 @@ struct CPU6502 break; } - case 0x88: { // DEY - set_flags(N | Z, y = y - 1); - break; - } - case 0x7E: { // ROR abs, X - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr + x); +#if EMULATE_65C02 + uint16_t addr = absolute_indexed_X(false); +#else /* !EMULATE_65C02 */ + uint16_t addr = absolute_indexed_X(true); +#endif /* EMULATE_65C02 */ + m = read(addr); + clk.add_cpu_cycles(1); bool c = isset(C); flag_change(C, m & 0x01); set_flags(N | Z, m = (c ? 0x80 : 0x00) | (m >> 1)); - writes.push_back(std::make_pair(addr + x, m)); + write(addr, m); break; } - case 0x36: { // ROL zpg,X - uint8_t zpg = (read_pc_inc() + x) & 0xFF; - m = bus.read(zpg); + case 0x36: { // ROL zpg, X + uint8_t zpg = zeropage_indexed_X(); + m = read(zpg); + clk.add_cpu_cycles(1); bool c = isset(C); flag_change(C, m & 0x80); set_flags(N | Z, m = (c ? 0x01 : 0x00) | (m << 1)); - writes.push_back(std::make_pair(zpg, m)); + write(zpg, m); break; } case 0x3E: { // ROL abs, X - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr + x); +#if EMULATE_65C02 + uint16_t addr = absolute_indexed_X(false); +#else /* !EMULATE_65C02 */ + uint16_t addr = absolute_indexed_X(true); +#endif /* EMULATE_65C02 */ + m = read(addr); + clk.add_cpu_cycles(1); bool c = isset(C); flag_change(C, m & 0x80); set_flags(N | Z, m = (c ? 0x01 : 0x00) | (m << 1)); - writes.push_back(std::make_pair(addr + x, m)); - break; - } - - case 0x2A: { // ROL - bool c = isset(C); - flag_change(C, a & 0x80); - set_flags(N | Z, a = (c ? 0x01 : 0x00) | (a << 1)); - break; - } - - case 0x6A: { // ROR - bool c = isset(C); - flag_change(C, a & 0x01); - set_flags(N | Z, a = (c ? 0x80 : 0x00) | (a >> 1)); + write(addr, m); break; } case 0x6E: { // ROR abs - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr); + uint16_t addr = absolute(); + m = read(addr); + clk.add_cpu_cycles(1); bool c = isset(C); flag_change(C, m & 0x01); set_flags(N | Z, m = (c ? 0x80 : 0x00) | (m >> 1)); - writes.push_back(std::make_pair(addr, m)); + write(addr, m); break; } - case 0x66: { // ROR - uint8_t zpg = read_pc_inc(); - m = bus.read(zpg); + case 0x66: { // ROR zpg + uint8_t zpg = zeropage(); + m = read(zpg); + clk.add_cpu_cycles(1); bool c = isset(C); flag_change(C, m & 0x01); set_flags(N | Z, m = (c ? 0x80 : 0x00) | (m >> 1)); - writes.push_back(std::make_pair(zpg, m)); + write(zpg, m); break; } - case 0x76: { // ROR - uint8_t zpg = (read_pc_inc() + x) & 0xFF; - m = bus.read(zpg); + case 0x76: { // ROR zpg, X + uint8_t zpg = zeropage_indexed_X(); + m = read(zpg); + clk.add_cpu_cycles(1); bool c = isset(C); flag_change(C, m & 0x01); set_flags(N | Z, m = (c ? 0x80 : 0x00) | (m >> 1)); - writes.push_back(std::make_pair(zpg, m)); + write(zpg, m); break; } case 0x2E: { // ROL abs - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr); + uint16_t addr = absolute(); + m = read(addr); + clk.add_cpu_cycles(1); bool c = isset(C); flag_change(C, m & 0x80); set_flags(N | Z, m = (c ? 0x01 : 0x00) | (m << 1)); - writes.push_back(std::make_pair(addr, m)); + write(addr, m); break; } - case 0x26: { // ROL - uint8_t zpg = read_pc_inc(); + case 0x26: { // ROL zpg + uint8_t zpg = zeropage(); bool c = isset(C); - m = bus.read(zpg); + m = read(zpg); + clk.add_cpu_cycles(1); flag_change(C, m & 0x80); set_flags(N | Z, m = (c ? 0x01 : 0x00) | (m << 1)); - writes.push_back(std::make_pair(zpg, m)); + write(zpg, m); break; } - case 0x4C: { // JMP - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; + case 0x4C: { // JMP abs + uint16_t addr = absolute(); pc = addr; break; } case 0x6C: { // JMP indirect - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - uint8_t addrl = bus.read(addr); - uint8_t addrh = bus.read(addr + 1); - addr = addrl + addrh * 256; + uint16_t addr = indirect(); pc = addr; break; } - case 0x9D: { // STA abs, x - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - writes.push_back(std::make_pair(addr + x, a)); + case 0x9D: { // STA abs, X + uint16_t addr = absolute_indexed_X(true); + write(addr, a); break; } - case 0x99: { // STA - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - writes.push_back(std::make_pair(addr + y, a)); + case 0x99: { // STA abs, Y + uint16_t addr = absolute_indexed_Y(true); + write(addr, a); break; } case 0x91: { // STA (ind), Y - uint8_t zpg = read_pc_inc(); - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256 + y; - writes.push_back(std::make_pair(addr, a)); + uint16_t addr = indirect_indexed(true); + write(addr, a); break; } case 0x81: { // STA (ind, X) - uint8_t zpg = (read_pc_inc() + x) & 0xFF; - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256; - writes.push_back(std::make_pair(addr, a)); + uint16_t addr = indexed_indirect(); + write(addr, a); break; } - case 0x8D: { // STA - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - writes.push_back(std::make_pair(addr, a)); + case 0x8D: { // STA abs + uint16_t addr = absolute(); + write(addr, a); break; } case 0x08: { // PHP + clk.add_cpu_cycles(1); stack_push(p | B2 | B); break; } case 0x28: { // PLP - p = stack_pull() & ~ (B2 | B); + clk.add_cpu_cycles(1); + clk.add_cpu_cycles(1); // Pipelined pre-increment + p = stack_pull() | B2 | B; break; } - case 0x24: { // BIT - uint8_t zpg = read_pc_inc(); - m = bus.read(zpg); + case 0x24: { // BIT zpg + uint8_t zpg = zeropage(); + m = read(zpg); flag_change(Z, (a & m) == 0); flag_change(N, m & 0x80); flag_change(V, m & 0x40); break; } - case 0x2C: { // BIT - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr); + case 0x34: { // BIT zpg, X + uint8_t zpg = zeropage_indexed_X(); + m = read(zpg); flag_change(Z, (a & m) == 0); flag_change(N, m & 0x80); flag_change(V, m & 0x40); break; } - case 0xB4: { // LDY - uint8_t zpg = read_pc_inc(); - set_flags(N | Z, y = bus.read((zpg + x) & 0xFF)); + case 0x3C: { // BIT abs, X + uint16_t addr = absolute_indexed_X(false); + m = read(addr); + flag_change(Z, (a & m) == 0); + flag_change(N, m & 0x80); + flag_change(V, m & 0x40); + break; + } + + case 0x2C: { // BIT abs + uint16_t addr = absolute(); + m = read(addr); + flag_change(Z, (a & m) == 0); + flag_change(N, m & 0x80); + flag_change(V, m & 0x40); + break; + } + + case 0xB4: { // LDY zpg, X + uint8_t zpg = zeropage_indexed_X(); + set_flags(N | Z, y = read(zpg)); break; } case 0xAE: { // LDX abs - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - set_flags(N | Z, x = bus.read(addr)); + uint16_t addr = absolute(); + set_flags(N | Z, x = read(addr)); break; } - case 0xBE: { // LDX - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256 + y; - if((addr - y) / 256 != addr / 256) - clk.add_cpu_cycles(1); - set_flags(N | Z, x = bus.read(addr)); + case 0xBE: { // LDX abs, Y + uint16_t addr = absolute_indexed_Y(false); + set_flags(N | Z, x = read(addr)); break; } - case 0xA6: { // LDX - uint8_t zpg = read_pc_inc(); - set_flags(N | Z, x = bus.read(zpg)); + case 0xA6: { // LDX zpg + uint8_t zpg = zeropage(); + set_flags(N | Z, x = read(zpg)); break; } case 0xB6: { // LDX zpg, Y - uint8_t zpg = (read_pc_inc() + y) & 0xFF; - set_flags(N | Z, x = bus.read(zpg)); + uint8_t zpg = zeropage_indexed_Y(); + set_flags(N | Z, x = read(zpg)); break; } - case 0xA4: { // LDY - uint8_t zpg = read_pc_inc(); - set_flags(N | Z, y = bus.read(zpg)); + case 0xA4: { // LDY zpg + uint8_t zpg = zeropage(); + set_flags(N | Z, y = read(zpg)); break; } - case 0xAC: { // LDY - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - set_flags(N | Z, y = bus.read(addr)); + case 0xAC: { // LDY abs + uint16_t addr = absolute(); + set_flags(N | Z, y = read(addr)); break; } - case 0xA2: { // LDX + case 0xA2: { // LDX imm uint8_t imm = read_pc_inc(); set_flags(N | Z, x = imm); break; } - case 0xA0: { // LDY + case 0xA0: { // LDY imm uint8_t imm = read_pc_inc(); set_flags(N | Z, y = imm); break; } - case 0xA9: { // LDA - uint8_t imm = read_pc_inc(); - set_flags(N | Z, a = imm); - break; - } - - case 0xAD: { // LDA - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - set_flags(N | Z, a = bus.read(addr)); - break; - } - case 0xCC: { // CPY abs - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr); + uint16_t addr = absolute(); + m = read(addr); flag_change(C, m <= y); set_flags(N | Z, m = y - m); break; } case 0xEC: { // CPX abs - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr); + uint16_t addr = absolute(); + m = read(addr); flag_change(C, m <= x); set_flags(N | Z, m = x - m); break; } - case 0xE0: { // CPX - uint8_t imm = read_pc_inc(); - flag_change(C, imm <= x); - set_flags(N | Z, imm = x - imm); - break; - } - - case 0xC0: { // CPY + case 0xC0: { // CPY imm uint8_t imm = read_pc_inc(); flag_change(C, imm <= y); set_flags(N | Z, imm = y - imm); break; } + case 0xE0: { // CPX imm + uint8_t imm = read_pc_inc(); + flag_change(C, imm <= x); + set_flags(N | Z, imm = x - imm); + break; + } + +#if EMULATE_65C02 + case 0x52: { // EOR (zpg), 65C02 + uint16_t addr = zeropage_indirect(); + m = read(addr); + set_flags(N | Z, a = a ^ m); + break; + } +#endif /* EMULATE_65C02 */ + case 0x55: { // EOR zpg, X - uint8_t zpg = read_pc_inc() + x; - m = bus.read(zpg & 0xFF); + uint8_t zpg = zeropage_indexed_X(); + m = read(zpg); set_flags(N | Z, a = a ^ m); break; } case 0x41: { // EOR (ind, X) - uint8_t zpg = (read_pc_inc() + x) & 0xFF; - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256; - m = bus.read(addr); + uint16_t addr = indexed_indirect(); + m = read(addr); set_flags(N | Z, a = a ^ m); break; } case 0x4D: { // EOR abs - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr); + uint16_t addr = absolute(); + m = read(addr); set_flags(N | Z, a = a ^ m); break; } case 0x5D: { // EOR abs, X - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr + x); - if((addr + x) / 256 != addr / 256) - clk.add_cpu_cycles(1); + uint16_t addr = absolute_indexed_X(false); + m = read(addr); set_flags(N | Z, a = a ^ m); break; } case 0x59: { // EOR abs, Y - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr + y); - if((addr + y) / 256 != addr / 256) - clk.add_cpu_cycles(1); + uint16_t addr = absolute_indexed_Y(false); + m = read(addr); set_flags(N | Z, a = a ^ m); break; } - case 0x45: { // EOR - uint8_t zpg = read_pc_inc(); - set_flags(N | Z, a = a ^ bus.read(zpg)); + case 0x45: { // EOR zpg + uint8_t zpg = zeropage(); + set_flags(N | Z, a = a ^ read(zpg)); break; } - case 0x49: { // EOR + case 0x49: { // EOR imm uint8_t imm = read_pc_inc(); set_flags(N | Z, a = a ^ imm); break; } - case 0x51: { // EOR - uint8_t zpg = read_pc_inc(); - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256 + y; - if((addr - y) / 256 != addr / 256) - clk.add_cpu_cycles(1); - m = bus.read(addr); + case 0x51: { // EOR (ind), Y + uint16_t addr = indirect_indexed(false); + m = read(addr); set_flags(N | Z, a = a ^ m); break; } - case 0xD1: { // CMP - uint8_t zpg = read_pc_inc(); - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256 + y; - if((addr - y) / 256 != addr / 256) - clk.add_cpu_cycles(1); - m = bus.read(addr); + case 0xD1: { // CMP (ind), Y + uint16_t addr = indirect_indexed(false); + m = read(addr); flag_change(C, m <= a); set_flags(N | Z, m = a - m); break; } - case 0xC5: { // CMP - uint8_t zpg = read_pc_inc(); - m = bus.read(zpg); + case 0xC5: { // CMP zpg + uint8_t zpg = zeropage(); + m = read(zpg); flag_change(C, m <= a); set_flags(N | Z, m = a - m); break; } - case 0xCD: { // CMP - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr); + case 0xCD: { // CMP abs + uint16_t addr = absolute(); + m = read(addr); flag_change(C, m <= a); set_flags(N | Z, m = a - m); break; } - case 0xC9: { // CMP + case 0xC9: { // CMP imm uint8_t imm = read_pc_inc(); flag_change(C, imm <= a); set_flags(N | Z, imm = a - imm); break; } - case 0xD5: { // CMP - uint8_t zpg = read_pc_inc() + x; - m = bus.read(zpg & 0xFF); + case 0xD5: { // CMP zpg, X + uint8_t zpg = zeropage_indexed_X(); + m = read(zpg); flag_change(C, m <= a); set_flags(N | Z, m = a - m); break; } - case 0xE4: { // CPX - uint8_t zpg = read_pc_inc(); - m = bus.read(zpg); + case 0xE4: { // CPX zpg + uint8_t zpg = zeropage(); + m = read(zpg); flag_change(C, m <= x); set_flags(N | Z, m = x - m); break; } - case 0xC4: { // CPY - uint8_t zpg = read_pc_inc(); - m = bus.read(zpg); + case 0xC4: { // CPY zpg + uint8_t zpg = zeropage(); + m = read(zpg); flag_change(C, m <= y); set_flags(N | Z, m = y - m); break; } - case 0x85: { // STA - uint8_t zpg = read_pc_inc(); - writes.push_back(std::make_pair(zpg, a)); + case 0x85: { // STA zpg + uint8_t zpg = zeropage(); + write(zpg, a); break; } case 0x40: { // RTI - p = stack_pull() & ~ (B2 | B); + clk.add_cpu_cycles(1); + p = stack_pull() | B2 | B; + clk.add_cpu_cycles(1); // Pipelined pre-increment uint8_t pcl = stack_pull(); uint8_t pch = stack_pull(); pc = pcl + pch * 256; @@ -1563,80 +1584,63 @@ struct CPU6502 } case 0x60: { // RTS + clk.add_cpu_cycles(1); + clk.add_cpu_cycles(1); // Pipelined pre-increment uint8_t pcl = stack_pull(); uint8_t pch = stack_pull(); + clk.add_cpu_cycles(1); pc = pcl + pch * 256 + 1; break; } - case 0x95: { // STA - uint8_t zpg = read_pc_inc(); - bus.write((zpg + x) & 0xFF, a); + case 0x94: { // STY zpg, X + uint8_t zpg = zeropage_indexed_X(); + write(zpg, y); break; } - case 0x94: { // STY - uint8_t zpg = read_pc_inc(); - bus.write((zpg + x) & 0xFF, y); + case 0x95: { // STA zpg, X + uint8_t zpg = zeropage_indexed_X(); + write(zpg, a); break; } case 0x8E: { // STX abs - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - writes.push_back(std::make_pair(addr, x)); + uint16_t addr = absolute(); + write(addr, x); break; } - case 0x86: { // STX - uint8_t zpg = read_pc_inc(); - writes.push_back(std::make_pair(zpg, x)); + case 0x86: { // STX zpg + uint8_t zpg = zeropage(); + write(zpg, x); break; } case 0x96: { // STX zpg, Y - uint8_t zpg = read_pc_inc(); - uint16_t addr = (zpg + y) & 0xFF; - writes.push_back(std::make_pair(addr, x)); + uint8_t zpg = zeropage_indexed_Y(); + write(zpg, x); break; } - case 0x84: { // STY - uint8_t zpg = read_pc_inc(); - writes.push_back(std::make_pair(zpg, y)); + case 0x84: { // STY zpg + uint8_t zpg = zeropage(); + write(zpg, y); break; } - case 0x8C: { // STY - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - writes.push_back(std::make_pair(addr, y)); - break; - } - - case 0x20: { // JSR - stack_push((pc + 1) >> 8); - stack_push((pc + 1) & 0xFF); - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - pc = addr; + case 0x8C: { // STY abs + uint16_t addr = absolute(); + write(addr, y); break; } case 0x75: { // ADC zpg, X - uint8_t zpg = read_pc_inc(); - uint16_t addr = (zpg + x)& 0xFF; - m = bus.read(addr); + uint8_t addr = zeropage_indexed_X(); + m = read(addr); uint8_t carry = isset(C) ? 1 : 0; if(isset(D)) { - uint8_t bcd = a / 16 * 10 + a % 16; - flag_change(C, ((uint16_t)bcd + (uint16_t)m + carry) > 99); - flag_change(V, adc_overflow_d(bcd, m, carry)); - set_flags(N | Z, bcd = bcd + m + carry); - a = bcd / 10 * 16 + bcd % 10; + adc_bcd(m, carry); } else { flag_change(C, ((uint16_t)a + (uint16_t)m + carry) > 0xFF); flag_change(V, adc_overflow(a, m, carry)); @@ -1652,9 +1656,9 @@ struct CPU6502 case 0x0F: case 0x1F: case 0x2F: case 0x3F: case 0x4F: case 0x5F: case 0x6F: case 0x7F: { // BBRn zpg, rel, 65C02 int whichbit = (inst >> 4) & 0x7; - uint8_t zpg = read_pc_inc(); - uint8_t m = bus.read(zpg); - int32_t rel = (read_pc_inc() + 128) % 256 - 128; + uint8_t zpg = zeropage(); + uint8_t m = read(zpg); + int32_t rel = (read_pc_inc() + 128) & 0xFF - 128; if(!(m & (1 << whichbit))) { // if((pc + rel) / 256 != pc / 256) // clk.add_cpu_cycles(1); // XXX ??? @@ -1666,9 +1670,9 @@ struct CPU6502 case 0x8F: case 0x9F: case 0xAF: case 0xBF: case 0xCF: case 0xDF: case 0xEF: case 0xFF: { // BBSn zpg, rel, 65C02 int whichbit = (inst >> 4) & 0x7; - uint8_t zpg = read_pc_inc(); - uint8_t m = bus.read(zpg); - int32_t rel = (read_pc_inc() + 128) % 256 - 128; + uint8_t zpg = zeropage(); + uint8_t m = read(zpg); + int32_t rel = (read_pc_inc() + 128) & 0xFF - 128; if(m & (1 << whichbit)) { // if((pc + rel) / 256 != pc / 256) // clk.add_cpu_cycles(1); // XXX ??? @@ -1683,34 +1687,32 @@ struct CPU6502 } case 0x7A: { // PLY, 65C02 + clk.add_cpu_cycles(1); // Pipelined pre-increment set_flags(N | Z, y = stack_pull()); break; } case 0xFA: { // PLX, 65C02 + clk.add_cpu_cycles(1); // Pipelined pre-increment set_flags(N | Z, x = stack_pull()); break; } - case 0x80: { // BRA imm, 65C02 - int32_t rel = (read_pc_inc() + 128) % 256 - 128; - if((pc + rel) / 256 != pc / 256) - clk.add_cpu_cycles(1); - pc += rel; + case 0x64: { // STZ zpg, 65C02 + uint8_t zpg = zeropage(); + write(zpg, 0); break; } - case 0x64: { // STZ zpg, 65C02 - uint8_t zpg = read_pc_inc(); - writes.push_back(std::make_pair(zpg, 0)); + case 0x74: { // STZ zpg, X, 65C02 + uint8_t zpg = zeropage_indexed_X(); + write(zpg, 0); break; } case 0x9C: { // STZ abs, 65C02 - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - writes.push_back(std::make_pair(addr, 0x0)); + uint16_t addr = absolute(); + write(addr, 0x0); break; } @@ -1719,37 +1721,18 @@ struct CPU6502 break; } - case 0xB2: { // LDA (zpg), 65C02 - uint8_t zpg = read_pc_inc(); - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256; - set_flags(N | Z, a = bus.read(addr)); - break; - } - case 0x92: { // STA (zpg), 65C02 - uint8_t zpg = read_pc_inc(); - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256; - writes.push_back(std::make_pair(addr, a)); + uint16_t addr = zeropage_indirect(); + write(addr, a); break; } case 0x72: { // ADC (zpg), 65C02 - uint8_t zpg = read_pc_inc(); - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256; - m = bus.read(addr); + uint16_t addr = zeropage_indirect(); + m = read(addr); uint8_t carry = isset(C) ? 1 : 0; if(isset(D)) { - uint8_t bcd = a / 16 * 10 + a % 16; - flag_change(C, ((uint16_t)bcd + (uint16_t)m + carry) > 99); - flag_change(V, adc_overflow_d(bcd, m, carry)); - set_flags(N | Z, bcd = bcd + m + carry); - a = bcd / 10 * 16 + bcd % 10; + adc_bcd(m, carry); } else { flag_change(C, ((uint16_t)a + (uint16_t)m + carry) > 0xFF); flag_change(V, adc_overflow(a, m, carry)); @@ -1759,7 +1742,7 @@ struct CPU6502 } case 0x3A: { // DEC, 65C02 - set_flags(N | Z, a = a - 1); + set_flags(N | Z, a = a - 1); break; } @@ -1768,66 +1751,55 @@ struct CPU6502 break; } - case 0x12: { // ORA (ind), 65C02 - uint8_t zpg = read_pc_inc(); - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256; - m = bus.read(addr); + case 0x12: { // ORA (zpg), 65C02 + uint16_t addr = zeropage_indirect(); + m = read(addr); set_flags(N | Z, a = a | m); break; } case 0xD2: { // CMP (zpg), 65C02 instruction - uint8_t zpg = read_pc_inc(); - uint8_t low = bus.read(zpg); - uint8_t high = bus.read((zpg + 1) & 0xFF); - uint16_t addr = low + high * 256; - m = bus.read(addr); + uint16_t addr = zeropage_indirect(); + m = read(addr); flag_change(C, m <= a); set_flags(N | Z, m = a - m); break; } case 0x1C: { // TRB abs, 65C02 instruction - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr); + uint16_t addr = absolute(); + m = read(addr); set_flags(Z, m & a); - writes.push_back(std::make_pair(addr, m & ~a)); + write(addr, m & ~a); break; } case 0x14: { // TRB zpg, 65C02 instruction - uint8_t zpgaddr = read_pc_inc(); - m = bus.read(zpgaddr); + uint8_t zpgaddr = zeropage(); + m = read(zpgaddr); set_flags(Z, m & a); - writes.push_back(std::make_pair(zpgaddr, m & ~a)); + write(zpgaddr, m & ~a); break; } case 0x0C: { // TSB abs, 65C02 instruction - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - m = bus.read(addr); + uint16_t addr = absolute(); + m = read(addr); set_flags(Z, m & a); - writes.push_back(std::make_pair(addr, m | a)); + write(addr, m | a); break; } - case 0x04: { // TRB zpg, 65C02 instruction - uint8_t zpgaddr = read_pc_inc(); - m = bus.read(zpgaddr); + case 0x04: { // TSB zpg, 65C02 instruction + uint8_t zpgaddr = zeropage(); + m = read(zpgaddr); set_flags(Z, m & a); - writes.push_back(std::make_pair(zpgaddr, m | a)); + write(zpgaddr, m | a); break; } case 0x02: case 0x22: case 0x42: case 0x62: case 0x82: case 0xC2: case 0xE2: { // two-byte NOP, 2 cycles - uint8_t ignored = read_pc_inc(); - (void)ignored; + [[maybe_unused]] uint8_t ignored = read_pc_inc(); break; } @@ -1842,40 +1814,29 @@ struct CPU6502 } case 0x44: { // two-byte NOP, 3 cycles - uint8_t ignored = read_pc_inc(); - (void)ignored; + [[maybe_unused]] uint8_t ignored = read_pc_inc(); break; } case 0x54: case 0xD4: case 0xF4: { // two-byte NOP, 4 cycles - uint8_t ignored = read_pc_inc(); - (void)ignored; + [[maybe_unused]] uint8_t ignored = read_pc_inc(); break; } case 0x5C: { // three-byte NOP, 8 cycles - uint8_t ignored1 = read_pc_inc(); - (void)ignored1; - uint8_t ignored2 = read_pc_inc(); - (void)ignored2; + [[maybe_unused]] uint8_t ignored1 = read_pc_inc(); + [[maybe_unused]] uint8_t ignored2 = read_pc_inc(); break; } case 0xDC: case 0xFC: { // three-byte NOP, 4 cycles - uint8_t ignored1 = read_pc_inc(); - (void)ignored1; - uint8_t ignored2 = read_pc_inc(); - (void)ignored2; + [[maybe_unused]] uint8_t ignored1 = read_pc_inc(); + [[maybe_unused]] uint8_t ignored2 = read_pc_inc(); break; } - case 0x7C: { // JMP (ind, X), 65C02 instruction - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256 + x; - uint8_t addrl = bus.read(addr); - uint8_t addrh = bus.read(addr + 1); - addr = addrl + addrh * 256; + case 0x7C: { // JMP (abs, X), 65C02 instruction + uint16_t addr = absolute_indexed_indirect(); pc = addr; break; } @@ -1887,10 +1848,8 @@ struct CPU6502 } case 0x9E: { // STZ abs, X - uint8_t low = read_pc_inc(); - uint8_t high = read_pc_inc(); - uint16_t addr = low + high * 256; - writes.push_back(std::make_pair(addr + x, 0)); + uint16_t addr = absolute_indexed_X(false); + write(addr, 0); break; } @@ -1898,54 +1857,24 @@ struct CPU6502 case 0x04: { // NOP zpg uint8_t zpgaddr = read_pc_inc(); - m = bus.read(zpgaddr); + m = read(zpgaddr); break; } - #endif /* EMULATE_65C02 */ - default: + default: { printf("unhandled instruction %02X at %04X\n", inst, pc - 1); fflush(stdout); exit(1); + } } - assert(cycles[inst] > 0); - // Hack for putting writes near the end of the instruction to hopefully - // match real timing - clk.add_cpu_cycles(cycles[inst] - writes.size()); - for(size_t i = 0; i < writes.size(); i++) { - const auto& write = writes[i]; - clk.add_cpu_cycles(1); - bus.write(write.first, write.second); - } - writes.clear(); } }; -template -const int32_t CPU6502::cycles[256] = -{ -#if EMULATE_65C02 - /* 0 1 2 3 4 5 6 7 8 9 0 A B C D E */ - /* 0x0- */ 7, 6, 2, 1, 5, 3, 5, 0, 3, 2, 2, 1, 6, 4, 6, 5, - /* 0x1- */ 2, 5, 5, 1, 5, 4, 6, 0, 2, 4, 2, 1, 6, 4, 7, 5, - /* 0x2- */ 6, 6, 2, 1, 3, 3, 5, 0, 4, 2, 2, 1, 4, 4, 6, 5, - /* 0x3- */ 2, 5, 0, 1, 0, 4, 6, 0, 2, 4, 2, 1, 0, 4, 7, 5, - /* 0x4- */ 6, 6, 2, 1, 3, 3, 5, 0, 3, 2, 2, 1, 3, 4, 6, 5, - /* 0x5- */ 2, 5, 0, 1, 4, 4, 6, 0, 2, 4, 3, 1, 8, 4, 7, 5, - /* 0x6- */ 6, 6, 2, 1, 3, 3, 5, 0, 4, 2, 2, 1, 5, 4, 6, 5, - /* 0x7- */ 2, 5, 5, 1, 0, 4, 6, 0, 2, 4, 4, 1, 6, 4, 7, 5, - /* 0x8- */ 2, 6, 2, 1, 3, 3, 3, 0, 2, 2, 2, 1, 4, 4, 4, 5, - /* 0x9- */ 2, 6, 5, 1, 4, 4, 4, 0, 2, 5, 2, 1, 4, 5, 5, 5, - /* 0xA- */ 2, 6, 2, 1, 3, 3, 3, 0, 2, 2, 2, 1, 4, 4, 4, 5, - /* 0xB- */ 2, 5, 5, 1, 4, 4, 4, 0, 2, 4, 2, 1, 4, 4, 4, 5, - /* 0xC- */ 2, 6, 2, 1, 3, 3, 5, 0, 2, 2, 2, 1, 4, 4, 3, 5, - /* 0xD- */ 2, 5, 5, 1, 4, 4, 6, 0, 2, 4, 3, 1, 4, 4, 7, 5, - /* 0xE- */ 2, 6, 2, 1, 3, 3, 5, 0, 2, 2, 2, 2, 4, 4, 6, 5, - /* 0xF- */ 2, 5, 0, 1, 4, 4, 6, 0, 2, 4, 4, 1, 4, 4, 7, 5, -#else /* ! EMULATE_65C02 */ - /* 0 1 2 3 4 5 6 7 8 9 0 A B C D E */ +#if 0 +#if ! EMULATE_65C02 + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ /* 0x0- */ 7, 6, 2, 1, 3, 3, 5, 0, 3, 2, 2, 1, 6, 4, 6, 5, /* 0x1- */ 2, 5, 5, 1, 5, 4, 6, 0, 2, 4, 2, 1, 6, 4, 7, 5, /* 0x2- */ 6, 6, 2, 1, 3, 3, 5, 0, 4, 2, 2, 1, 4, 4, 6, 5, @@ -1962,8 +1891,27 @@ const int32_t CPU6502::cycles[256] = /* 0xD- */ 2, 5, 5, 1, 4, 4, 6, 0, 2, 4, 3, 1, 4, 4, 7, 5, /* 0xE- */ 2, 6, 2, 1, 3, 3, 5, 0, 2, 2, 2, 2, 4, 4, 6, 5, /* 0xF- */ 2, 5, 0, 1, 4, 4, 6, 0, 2, 4, 4, 1, 4, 4, 7, 5, +#else /* EMULATE_65C02 */ + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + /* 0x0- */ 7, 6, 2, 1, 5, 3, 5, 0, 3, 2, 2, 1, 6, 4, 6, 5, + /* 0x1- */ 2, 5, 5, 1, 5, 4, 6, 0, 2, 4, 2, 1, 6, 4, 6, 5, + /* 0x2- */ 6, 6, 2, 1, 3, 3, 5, 0, 4, 2, 2, 1, 4, 4, 6, 5, + /* 0x3- */ 2, 5, 0, 1, 4, 4, 6, 0, 2, 4, 2, 1, 0, 4, 6, 5, + /* 0x4- */ 6, 6, 2, 1, 3, 3, 5, 0, 3, 2, 2, 1, 3, 4, 6, 5, + /* 0x5- */ 2, 5, 0, 1, 4, 4, 6, 0, 2, 4, 3, 1, 8, 4, 6, 5, + /* 0x6- */ 6, 6, 2, 1, 3, 3, 5, 0, 4, 2, 2, 1, 5, 4, 6, 5, + /* 0x7- */ 2, 5, 5, 1, 4, 4, 6, 0, 2, 4, 4, 1, 6, 4, 6, 5, + /* 0x8- */ 2, 6, 2, 1, 3, 3, 3, 0, 2, 2, 2, 1, 4, 4, 4, 5, + /* 0x9- */ 2, 6, 5, 1, 4, 4, 4, 0, 2, 5, 2, 1, 4, 5, 6, 5, + /* 0xA- */ 2, 6, 2, 1, 3, 3, 3, 0, 2, 2, 2, 1, 4, 4, 4, 5, + /* 0xB- */ 2, 5, 5, 1, 4, 4, 4, 0, 2, 4, 2, 1, 4, 4, 4, 5, + /* 0xC- */ 2, 6, 2, 1, 3, 3, 5, 0, 2, 2, 2, 1, 4, 4, 3, 5, + /* 0xD- */ 2, 5, 5, 1, 4, 4, 6, 0, 2, 4, 3, 1, 4, 4, 7, 5, + /* 0xE- */ 2, 6, 2, 1, 3, 3, 5, 0, 2, 2, 2, 2, 4, 4, 6, 5, + /* 0xF- */ 2, 5, 0, 1, 4, 4, 6, 0, 2, 4, 4, 1, 4, 4, 7, 5, #endif /* EMULATE_65C02 */ -}; + +#endif #endif // CPU6502_H