From 5d24a136a2f72be065715c65e4bc77fd9e71d02b Mon Sep 17 00:00:00 2001 From: Adrian Conlon <98398945+AdrianConlon@users.noreply.github.com> Date: Fri, 5 Jan 2024 12:52:27 +0000 Subject: [PATCH] Correct loads of undocumented M6502 instructions --- M6502/inc/mos6502.h | 75 ++++++++++++++++-- M6502/src/mos6502.cpp | 173 ++++++++++++++++++++++++++++++++---------- 2 files changed, 205 insertions(+), 43 deletions(-) diff --git a/M6502/inc/mos6502.h b/M6502/inc/mos6502.h index 5c8737c..0749e91 100644 --- a/M6502/inc/mos6502.h +++ b/M6502/inc/mos6502.h @@ -58,8 +58,8 @@ namespace EightBit { [[nodiscard]] virtual uint8_t sub(uint8_t operand, uint8_t data, int borrow = 0) noexcept; [[nodiscard]] uint8_t sbc(uint8_t operand, uint8_t data) noexcept; - [[nodiscard]] uint8_t sub_b(uint8_t operand, uint8_t data, int borrow) noexcept; - [[nodiscard]] uint8_t sub_d(uint8_t operand, uint8_t data, int borrow) noexcept; + [[nodiscard]] uint8_t sub_b(uint8_t operand, uint8_t data, int borrow = 0) noexcept; + [[nodiscard]] uint8_t sub_d(uint8_t operand, uint8_t data, int borrow = 0) noexcept; [[nodiscard]] virtual uint8_t add(uint8_t operand, uint8_t data, int carry = 0) noexcept; [[nodiscard]] uint8_t adc(uint8_t operand, uint8_t data) noexcept; @@ -184,17 +184,82 @@ namespace EightBit { void slo(uint8_t value) noexcept; void sre(uint8_t value) noexcept; + // Unconditional page fixup cycle required + void fixup(const register16_t address, const uint8_t unfixed_page) noexcept { + getBytePaged(unfixed_page, address.low); // Possible fixup for page boundary crossing + BUS().ADDRESS() = address; + } + // Complicated addressing mode implementations void sta_AbsoluteX() noexcept; void sta_AbsoluteY() noexcept; void sta_IndirectIndexedY() noexcept; - void write_A_with_fixup(const register16_t& address, uint8_t unfixed_page) noexcept { - getBytePaged(unfixed_page, address.low); // Possible fixup for page boundary crossing - memoryWrite(address, A()); + void sta_with_fixup(const register16_t address, const uint8_t unfixed_page) noexcept { + fixup(address, unfixed_page); + memoryWrite(A()); } + // Undocumented complicated mode implementations + + // SLO + void slo_AbsoluteX() noexcept; + void slo_AbsoluteY() noexcept; + void slo_IndirectIndexedY() noexcept; + void slo_with_fixup(const register16_t address, const uint8_t unfixed_page) noexcept { + fixup(address, unfixed_page); + slo(memoryRead()); + } + + // ISB + void isb_AbsoluteX() noexcept; + void isb_AbsoluteY() noexcept; + void isb_IndirectIndexedY() noexcept; + void isb_with_fixup(const register16_t address, const uint8_t unfixed_page) noexcept { + fixup(address, unfixed_page); + isb(memoryRead()); + } + + // RLA + void rla_AbsoluteX() noexcept; + void rla_AbsoluteY() noexcept; + void rla_IndirectIndexedY() noexcept; + void rla_with_fixup(const register16_t address, const uint8_t unfixed_page) noexcept { + fixup(address, unfixed_page); + rla(memoryRead()); + } + + // RRA + void rra_AbsoluteX() noexcept; + void rra_AbsoluteY() noexcept; + void rra_IndirectIndexedY() noexcept; + void rra_with_fixup(const register16_t address, const uint8_t unfixed_page) noexcept { + fixup(address, unfixed_page); + rra(memoryRead()); + } + + // DCP + void dcp_AbsoluteX() noexcept; + void dcp_AbsoluteY() noexcept; + void dcp_IndirectIndexedY() noexcept; + void dcp_with_fixup(const register16_t address, const uint8_t unfixed_page) noexcept { + fixup(address, unfixed_page); + dcp(memoryRead()); + } + + // SRE + void sre_AbsoluteX() noexcept; + void sre_AbsoluteY() noexcept; + void sre_IndirectIndexedY() noexcept; + void sre_with_fixup(const register16_t address, const uint8_t unfixed_page) noexcept { + fixup(address, unfixed_page); + sre(memoryRead()); + } + + // NOP + void nop_AbsoluteX() noexcept; + uint8_t x = 0; // index register X uint8_t y = 0; // index register Y uint8_t a = 0; // accumulator diff --git a/M6502/src/mos6502.cpp b/M6502/src/mos6502.cpp index c53947a..4dd3692 100644 --- a/M6502/src/mos6502.cpp +++ b/M6502/src/mos6502.cpp @@ -14,11 +14,11 @@ EightBit::MOS6502::MOS6502(Bus& bus) noexcept }); } -DEFINE_PIN_LEVEL_CHANGERS(NMI, MOS6502); -DEFINE_PIN_LEVEL_CHANGERS(SO, MOS6502); -DEFINE_PIN_LEVEL_CHANGERS(SYNC, MOS6502); -DEFINE_PIN_LEVEL_CHANGERS(RDY, MOS6502); -DEFINE_PIN_LEVEL_CHANGERS(RW, MOS6502); +DEFINE_PIN_LEVEL_CHANGERS(NMI, MOS6502) +DEFINE_PIN_LEVEL_CHANGERS(SO, MOS6502) +DEFINE_PIN_LEVEL_CHANGERS(SYNC, MOS6502) +DEFINE_PIN_LEVEL_CHANGERS(RDY, MOS6502) +DEFINE_PIN_LEVEL_CHANGERS(RW, MOS6502) int EightBit::MOS6502::step() noexcept { resetCycles(); @@ -124,15 +124,15 @@ int EightBit::MOS6502::execute() noexcept { case 0x09: A() = orr(A(), AM_Immediate()); break; // ORA (immediate) case 0x0a: memoryRead(PC()); A() = asl(A()); break; // ASL A (implied) case 0x0b: anc(AM_Immediate()); break; // *ANC (immediate) - case 0x0c: AM_Absolute(); break; // *NOP (absolute) + case 0x0c: { auto ignored = Address_Absolute(); } break; // *NOP (absolute) case 0x0d: A() = orr(A(), AM_Absolute()); break; // ORA (absolute) case 0x0e: memoryReadModifyWrite(asl(AM_Absolute())); break; // ASL (absolute) case 0x0f: slo(AM_Absolute()); break; // *SLO (absolute) - case 0x10: branch(!negative()); break; // BPL (relative) + case 0x10: branch(negative() == 0); break; // BPL (relative) case 0x11: A() = orr(A(), AM_IndirectIndexedY()); break; // ORA (indirect indexed Y) case 0x12: break; - case 0x13: slo(AM_IndirectIndexedY()); break; // *SLO (indirect indexed Y) + case 0x13: slo_IndirectIndexedY(); break; // *SLO (indirect indexed Y) case 0x14: AM_ZeroPageX(); break; // *NOP (zero page, X) case 0x15: A() = orr(A(), AM_ZeroPageX()); break; // ORA (zero page, X) case 0x16: memoryReadModifyWrite(asl(AM_ZeroPageX())); break; // ASL (zero page, X) @@ -140,11 +140,11 @@ int EightBit::MOS6502::execute() noexcept { case 0x18: memoryRead(PC()); P() = clearBit(P(), CF); break; // CLC (implied) case 0x19: A() = orr(A(), AM_AbsoluteY()); break; // ORA (absolute, Y) case 0x1a: memoryRead(PC()); break; // *NOP (implied) - case 0x1b: slo(AM_AbsoluteY()); break; // *SLO (absolute, Y) - case 0x1c: AM_AbsoluteX(); break; // *NOP (absolute, X) + case 0x1b: slo_AbsoluteY(); break; // *SLO (absolute, Y) + case 0x1c: nop_AbsoluteX(); break; // *NOP (absolute, X) case 0x1d: A() = orr(A(), AM_AbsoluteX()); break; // ORA (absolute, X) case 0x1e: memoryReadModifyWrite(asl(AM_AbsoluteX(PageCrossingBehavior::AlwaysReadTwice))); break; // ASL (absolute, X) - case 0x1f: slo(AM_AbsoluteX()); break; // *SLO (absolute, X) + case 0x1f: slo_AbsoluteX(); break; // *SLO (absolute, X) case 0x20: jsr(); break; // JSR (absolute) case 0x21: A() = andr(A(), AM_IndexedIndirectX()); break; // AND (indexed indirect X) @@ -166,7 +166,7 @@ int EightBit::MOS6502::execute() noexcept { case 0x30: branch(negative()); break; // BMI (relative) case 0x31: A() = andr(A(), AM_IndirectIndexedY()); break; // AND (indirect indexed Y) case 0x32: break; - case 0x33: rla(AM_IndirectIndexedY()); break; // *RLA (indirect indexed Y) + case 0x33: rla_IndirectIndexedY(); break; // *RLA (indirect indexed Y) case 0x34: AM_ZeroPageX(); break; // *NOP (zero page, X) case 0x35: A() = andr(A(), AM_ZeroPageX()); break; // AND (zero page, X) case 0x36: memoryReadModifyWrite(rol(AM_ZeroPageX())); break; // ROL (zero page, X) @@ -174,11 +174,11 @@ int EightBit::MOS6502::execute() noexcept { case 0x38: memoryRead(PC()); P() = setBit(P(), CF); break; // SEC (implied) case 0x39: A() = andr(A(), AM_AbsoluteY()); break; // AND (absolute, Y) case 0x3a: memoryRead(PC()); break; // *NOP (implied) - case 0x3b: rla(AM_AbsoluteY()); break; // *RLA (absolute, Y) - case 0x3c: AM_AbsoluteX(); break; // *NOP (absolute, X) + case 0x3b: rla_AbsoluteY(); break; // *RLA (absolute, Y) + case 0x3c: nop_AbsoluteX(); break; // *NOP (absolute, X) case 0x3d: A() = andr(A(), AM_AbsoluteX()); break; // AND (absolute, X) case 0x3e: memoryReadModifyWrite(rol(AM_AbsoluteX(PageCrossingBehavior::AlwaysReadTwice))); break; // ROL (absolute, X) - case 0x3f: rla(AM_AbsoluteX()); break; // *RLA (absolute, X) + case 0x3f: rla_AbsoluteX(); break; // *RLA (absolute, X) case 0x40: memoryRead(PC()); rti(); break; // RTI (implied) case 0x41: A() = eorr(A(), AM_IndexedIndirectX()); break; // EOR (indexed indirect X) @@ -197,10 +197,10 @@ int EightBit::MOS6502::execute() noexcept { case 0x4e: memoryReadModifyWrite(lsr(AM_Absolute())); break; // LSR (absolute) case 0x4f: sre(AM_Absolute()); break; // *SRE (absolute) - case 0x50: branch(!overflow()); break; // BVC (relative) + case 0x50: branch(overflow() == 0); break; // BVC (relative) case 0x51: A() = eorr(A(), AM_IndirectIndexedY()); break; // EOR (indirect indexed Y) case 0x52: break; - case 0x53: sre(AM_IndirectIndexedY()); break; // *SRE (indirect indexed Y) + case 0x53: sre_IndirectIndexedY(); break; // *SRE (indirect indexed Y) case 0x54: AM_ZeroPageX(); break; // *NOP (zero page, X) case 0x55: A() = eorr(A(), AM_ZeroPageX()); break; // EOR (zero page, X) case 0x56: memoryReadModifyWrite(lsr(AM_ZeroPageX())); break; // LSR (zero page, X) @@ -208,11 +208,11 @@ int EightBit::MOS6502::execute() noexcept { case 0x58: memoryRead(PC()); P() = clearBit(P(), IF); break; // CLI (implied) case 0x59: A() = eorr(A(), AM_AbsoluteY()); break; // EOR (absolute, Y) case 0x5a: memoryRead(PC()); break; // *NOP (implied) - case 0x5b: sre(AM_AbsoluteY()); break; // *SRE (absolute, Y) - case 0x5c: AM_AbsoluteX(); break; // *NOP (absolute, X) + case 0x5b: sre_AbsoluteY(); break; // *SRE (absolute, Y) + case 0x5c: nop_AbsoluteX(); break; // *NOP (absolute, X) case 0x5d: A() = eorr(A(), AM_AbsoluteX()); break; // EOR (absolute, X) case 0x5e: memoryReadModifyWrite(lsr(AM_AbsoluteX(PageCrossingBehavior::AlwaysReadTwice))); break; // LSR (absolute, X) - case 0x5f: sre(AM_AbsoluteX()); break; // *SRE (absolute, X) + case 0x5f: sre_AbsoluteX(); break; // *SRE (absolute, X) case 0x60: memoryRead(PC()); rts(); break; // RTS (implied) case 0x61: A() = adc(A(), AM_IndexedIndirectX()); break; // ADC (indexed indirect X) @@ -234,7 +234,7 @@ int EightBit::MOS6502::execute() noexcept { case 0x70: branch(overflow()); break; // BVS (relative) case 0x71: A() = adc(A(), AM_IndirectIndexedY()); break; // ADC (indirect indexed Y) case 0x72: break; - case 0x73: rra(AM_IndirectIndexedY()); break; // *RRA (indirect indexed Y) + case 0x73: rra_IndirectIndexedY(); break; // *RRA (indirect indexed Y) case 0x74: AM_ZeroPageX(); break; // *NOP (zero page, X) case 0x75: A() = adc(A(), AM_ZeroPageX()); break; // ADC (zero page, X) case 0x76: memoryReadModifyWrite(ror(AM_ZeroPageX())); break; // ROR (zero page, X) @@ -242,11 +242,11 @@ int EightBit::MOS6502::execute() noexcept { case 0x78: memoryRead(PC()); P() = setBit(P(), IF); break; // SEI (implied) case 0x79: A() = adc(A(), AM_AbsoluteY()); break; // ADC (absolute, Y) case 0x7a: memoryRead(PC()); break; // *NOP (implied) - case 0x7b: rra(AM_AbsoluteY()); break; // *RRA (absolute, Y) - case 0x7c: AM_AbsoluteX(); break; // *NOP (absolute, X) + case 0x7b: rra_AbsoluteY(); break; // *RRA (absolute, Y) + case 0x7c: nop_AbsoluteX(); break; // *NOP (absolute, X) case 0x7d: A() = adc(A(), AM_AbsoluteX()); break; // ADC (absolute, X) case 0x7e: memoryReadModifyWrite(ror(AM_AbsoluteX(PageCrossingBehavior::AlwaysReadTwice))); break; // ROR (absolute, X) - case 0x7f: rra(AM_AbsoluteX()); break; // *RRA (absolute, X) + case 0x7f: rra_AbsoluteX(); break; // *RRA (absolute, X) case 0x80: AM_Immediate(); break; // *NOP (immediate) case 0x81: memoryWrite(Address_IndexedIndirectX(), A()); break; // STA (indexed indirect X) @@ -265,7 +265,7 @@ int EightBit::MOS6502::execute() noexcept { case 0x8e: memoryWrite(Address_Absolute(), X()); break; // STX (absolute) case 0x8f: memoryWrite(Address_Absolute(), A() & X()); break; // *SAX (absolute) - case 0x90: branch(!carry()); break; // BCC (relative) + case 0x90: branch(carry() == 0); break; // BCC (relative) case 0x91: sta_IndirectIndexedY(); break; // STA (indirect indexed Y) case 0x92: break; case 0x93: break; @@ -333,10 +333,10 @@ int EightBit::MOS6502::execute() noexcept { case 0xce: memoryReadModifyWrite(dec(AM_Absolute())); break; // DEC (absolute) case 0xcf: dcp(AM_Absolute()); break; // *DCP (absolute) - case 0xd0: branch(!zero()); break; // BNE (relative) + case 0xd0: branch(zero() == 0); break; // BNE (relative) case 0xd1: cmp(A(), AM_IndirectIndexedY()); break; // CMP (indirect indexed Y) case 0xd2: break; - case 0xd3: dcp(AM_IndirectIndexedY()); break; // *DCP (indirect indexed Y) + case 0xd3: dcp_IndirectIndexedY(); break; // *DCP (indirect indexed Y) case 0xd4: AM_ZeroPageX(); break; // *NOP (zero page, X) case 0xd5: cmp(A(), AM_ZeroPageX()); break; // CMP (zero page, X) case 0xd6: memoryReadModifyWrite(dec(AM_ZeroPageX())); break; // DEC (zero page, X) @@ -344,11 +344,11 @@ int EightBit::MOS6502::execute() noexcept { case 0xd8: memoryRead(PC()); P() = clearBit(P(), DF); break; // CLD (implied) case 0xd9: cmp(A(), AM_AbsoluteY()); break; // CMP (absolute, Y) case 0xda: memoryRead(PC()); break; // *NOP (implied) - case 0xdb: dcp(AM_AbsoluteY()); break; // *DCP (absolute, Y) - case 0xdc: AM_AbsoluteX(); break; // *NOP (absolute, X) + case 0xdb: dcp_AbsoluteY(); break; // *DCP (absolute, Y) + case 0xdc: nop_AbsoluteX(); break; // *NOP (absolute, X) case 0xdd: cmp(A(), AM_AbsoluteX()); break; // CMP (absolute, X) case 0xde: memoryReadModifyWrite(dec(AM_AbsoluteX(PageCrossingBehavior::AlwaysReadTwice))); break; // DEC (absolute, X) - case 0xdf: dcp(AM_AbsoluteX()); break; // *DCP (absolute, X) + case 0xdf: dcp_AbsoluteX(); break; // *DCP (absolute, X) case 0xe0: cmp(X(), AM_Immediate()); break; // CPX (immediate) case 0xe1: A() = sbc(A(), AM_IndexedIndirectX()); break; // SBC (indexed indirect X) @@ -370,7 +370,7 @@ int EightBit::MOS6502::execute() noexcept { case 0xf0: branch(zero()); break; // BEQ (relative) case 0xf1: A() = sbc(A(), AM_IndirectIndexedY()); break; // SBC (indirect indexed Y) case 0xf2: break; - case 0xf3: isb(AM_IndirectIndexedY()); break; // *ISB (indirect indexed Y) + case 0xf3: isb_IndirectIndexedY(); break; // *ISB (indirect indexed Y) case 0xf4: AM_ZeroPageX(); break; // *NOP (zero page, X) case 0xf5: A() = sbc(A(), AM_ZeroPageX()); break; // SBC (zero page, X) case 0xf6: memoryReadModifyWrite(inc(AM_ZeroPageX())); break; // INC (zero page, X) @@ -378,11 +378,11 @@ int EightBit::MOS6502::execute() noexcept { case 0xf8: memoryRead(PC()); P() = setBit(P(), DF); break; // SED (implied) case 0xf9: A() = sbc(A(), AM_AbsoluteY()); break; // SBC (absolute, Y) case 0xfa: memoryRead(PC()); break; // *NOP (implied) - case 0xfb: isb(AM_AbsoluteY()); break; // *ISB (absolute, Y) - case 0xfc: AM_AbsoluteX(); break; // *NOP (absolute, X) + case 0xfb: isb_AbsoluteY(); break; // *ISB (absolute, Y) + case 0xfc: nop_AbsoluteX(); break; // *NOP (absolute, X) case 0xfd: A() = sbc(A(), AM_AbsoluteX()); break; // SBC (absolute, X) case 0xfe: memoryReadModifyWrite(inc(AM_AbsoluteX(PageCrossingBehavior::AlwaysReadTwice))); break; // INC (absolute, X) - case 0xff: isb(AM_AbsoluteX()); break; // *ISB (absolute, X) + case 0xff: isb_AbsoluteX(); break; // *ISB (absolute, X) } ASSUME(cycles() > 0); @@ -710,7 +710,7 @@ void EightBit::MOS6502::asr(const uint8_t value) noexcept { } void EightBit::MOS6502::axs(const uint8_t value) noexcept { - X() = through(sub(A() & X(), value)); + X() = through(sub_b(A() & X(), value)); P() = clearBit(P(), CF, m_intermediate.high); } @@ -748,15 +748,112 @@ void EightBit::MOS6502::sre(const uint8_t value) noexcept { void EightBit::MOS6502::sta_AbsoluteX() noexcept { const auto [address, page] = Address_AbsoluteX(); - write_A_with_fixup(address, page); + sta_with_fixup(address, page); } void EightBit::MOS6502::sta_AbsoluteY() noexcept { const auto [address, page] = Address_AbsoluteY(); - write_A_with_fixup(address, page); + sta_with_fixup(address, page); } void EightBit::MOS6502::sta_IndirectIndexedY() noexcept { const auto [address, page] = Address_IndirectIndexedY(); - write_A_with_fixup(address, page); + sta_with_fixup(address, page); +} + +// + +void EightBit::MOS6502::slo_AbsoluteX() noexcept { + const auto [address, page] = Address_AbsoluteX(); + slo_with_fixup(address, page); +} + +void EightBit::MOS6502::slo_AbsoluteY() noexcept { + const auto [address, page] = Address_AbsoluteY(); + slo_with_fixup(address, page); +} + +void EightBit::MOS6502::slo_IndirectIndexedY() noexcept { + const auto [address, page] = Address_IndirectIndexedY(); + slo_with_fixup(address, page); +} + +void EightBit::MOS6502::isb_AbsoluteX() noexcept { + const auto [address, page] = Address_AbsoluteX(); + isb_with_fixup(address, page); +} + +void EightBit::MOS6502::isb_AbsoluteY() noexcept { + const auto [address, page] = Address_AbsoluteY(); + isb_with_fixup(address, page); +} + +void EightBit::MOS6502::isb_IndirectIndexedY() noexcept { + const auto [address, page] = Address_IndirectIndexedY(); + isb_with_fixup(address, page); +} + +void EightBit::MOS6502::rla_AbsoluteX() noexcept { + const auto [address, page] = Address_AbsoluteX(); + rla_with_fixup(address, page); +} + +void EightBit::MOS6502::rla_AbsoluteY() noexcept { + const auto [address, page] = Address_AbsoluteY(); + rla_with_fixup(address, page); +} + +void EightBit::MOS6502::rla_IndirectIndexedY() noexcept { + const auto [address, page] = Address_IndirectIndexedY(); + rla_with_fixup(address, page); +} + +void EightBit::MOS6502::rra_AbsoluteX() noexcept { + const auto [address, page] = Address_AbsoluteX(); + rra_with_fixup(address, page); +} + +void EightBit::MOS6502::rra_AbsoluteY() noexcept { + const auto [address, page] = Address_AbsoluteY(); + rra_with_fixup(address, page); +} + +void EightBit::MOS6502::rra_IndirectIndexedY() noexcept { + const auto [address, page] = Address_IndirectIndexedY(); + rra_with_fixup(address, page); +} + +void EightBit::MOS6502::dcp_AbsoluteX() noexcept { + const auto [address, page] = Address_AbsoluteX(); + dcp_with_fixup(address, page); +} + +void EightBit::MOS6502::dcp_AbsoluteY() noexcept { + const auto [address, page] = Address_AbsoluteY(); + dcp_with_fixup(address, page); +} + +void EightBit::MOS6502::dcp_IndirectIndexedY() noexcept { + const auto [address, page] = Address_IndirectIndexedY(); + dcp_with_fixup(address, page); +} + +void EightBit::MOS6502::sre_AbsoluteX() noexcept { + const auto [address, page] = Address_AbsoluteX(); + sre_with_fixup(address, page); +} + +void EightBit::MOS6502::sre_AbsoluteY() noexcept { + const auto [address, page] = Address_AbsoluteY(); + sre_with_fixup(address, page); +} + +void EightBit::MOS6502::sre_IndirectIndexedY() noexcept { + const auto [address, page] = Address_IndirectIndexedY(); + sre_with_fixup(address, page); +} + +void EightBit::MOS6502::nop_AbsoluteX() noexcept { + const auto [address, page] = Address_AbsoluteX(); + fixup(address, page); }