diff --git a/M6502/inc/mos6502.h b/M6502/inc/mos6502.h index 851d1df..7d3371e 100644 --- a/M6502/inc/mos6502.h +++ b/M6502/inc/mos6502.h @@ -56,6 +56,8 @@ namespace EightBit { void busWrite() noexcept final; [[nodiscard]] uint8_t busRead() noexcept final; + // Instructions with BCD effects + [[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 = 0) noexcept; @@ -66,6 +68,12 @@ namespace EightBit { [[nodiscard]] uint8_t add_b(uint8_t operand, uint8_t data, int carry) noexcept; [[nodiscard]] uint8_t add_d(uint8_t operand, uint8_t data, int carry) noexcept; + // Undocumented compound instructions (with BCD effects) + + virtual void arr(uint8_t value) noexcept; + virtual void arr_b(uint8_t value) noexcept; + virtual void arr_d(uint8_t value) noexcept; + private: const uint8_t IRQvector = 0xfe; // IRQ vector const uint8_t RSTvector = 0xfc; // RST vector @@ -174,7 +182,6 @@ namespace EightBit { // Undocumented compound instructions void anc(uint8_t value) noexcept; - void arr(uint8_t value) noexcept; void asr(uint8_t value) noexcept; void axs(uint8_t value) noexcept; void dcp(uint8_t value) noexcept; diff --git a/M6502/src/mos6502.cpp b/M6502/src/mos6502.cpp index b707d52..69ce799 100644 --- a/M6502/src/mos6502.cpp +++ b/M6502/src/mos6502.cpp @@ -698,10 +698,33 @@ void EightBit::MOS6502::anc(const uint8_t value) noexcept { } void EightBit::MOS6502::arr(const uint8_t value) noexcept { - A() = andr(A(), value); - A() = ror(A()); + decimal() ? arr_d(value) : arr_b(value); +} + +void EightBit::MOS6502::arr_d(const uint8_t value) noexcept { + + // With thanks to https://github.com/TomHarte/CLK + // What a very strange instruction ARR is... + + A() &= value; + auto unshiftedA = A(); + A() = through((A() >> 1) | (carry() << 7)); + P() = setBit(P(), VF, (A() ^ (A() << 1)) & VF); + + if (lowerNibble(unshiftedA) + (unshiftedA & 0x1) > 5) + A() = lowerNibble(A() + 6) | higherNibble(A()); + + P() = setBit(P(), CF, higherNibble(unshiftedA) + (unshiftedA & 0x10) > 0x50); + + if (carry()) + A() += 0x60; +} + +void EightBit::MOS6502::arr_b(const uint8_t value) noexcept { + A() &= value; + A() = through((A() >> 1) | (carry() << 7)); P() = setBit(P(), CF, A() & Bit6); - P() = setBit(P(), VF, ((A() & Bit6) >> 6) ^((A() & Bit5) >> 5)); + P() = setBit(P(), VF, (A() ^ (A() << 1)) & VF); } void EightBit::MOS6502::asr(const uint8_t value) noexcept {