diff --git a/M6502/HarteTest_6502/checker_t.cpp b/M6502/HarteTest_6502/checker_t.cpp index 281fbe1..b01757e 100644 --- a/M6502/HarteTest_6502/checker_t.cpp +++ b/M6502/HarteTest_6502/checker_t.cpp @@ -6,7 +6,7 @@ void checker_t::addActualCycle(const uint16_t address, const uint8_t value, cons } void checker_t::addActualCycle(const EightBit::register16_t address, const uint8_t value, const std::string_view action) { - addActualCycle(address.word, value, action); + addActualCycle(address.joined, value, action); } void checker_t::addActualReadCycle(const EightBit::register16_t address, const uint8_t value) { @@ -95,7 +95,7 @@ void checker_t::initialiseState(const test_t test) { const auto initial = test.initial(); - cpu.PC().word = initial.pc(); + cpu.PC().joined = initial.pc(); cpu.S() = initial.s(); cpu.A() = initial.a(); cpu.X() = initial.x(); @@ -113,11 +113,11 @@ void checker_t::initialise() { auto& bus = runner(); - bus.ReadByte.connect([this](EightBit::EventArgs&) { + bus.CPU().ReadMemory.connect([this](EightBit::EventArgs&) { addActualReadCycle(runner().ADDRESS(), runner().DATA()); }); - bus.WrittenByte.connect([this](EightBit::EventArgs&) { + bus.CPU().WrittenMemory.connect([this](EightBit::EventArgs&) { addActualWriteCycle(runner().ADDRESS(), runner().DATA()); }); @@ -166,7 +166,7 @@ bool checker_t::checkState(test_t test) { return false; const auto final = test.final(); - const auto pc_good = check("PC", final.pc(), cpu.PC().word); + const auto pc_good = check("PC", final.pc(), cpu.PC().joined); const auto s_good = check("S", final.s(), cpu.S()); const auto a_good = check("A", final.a(), cpu.A()); const auto x_good = check("X", final.x(), cpu.X()); @@ -218,7 +218,7 @@ void checker_t::check(test_t test) { runner().raisePOWER(); initialiseState(test); - const auto pc = cpu.PC().word; + const auto pc = cpu.PC().joined; m_cycles = cpu.step(); runner().lowerPOWER(); @@ -235,7 +235,7 @@ void checker_t::check(test_t test) { add_disassembly(pc); const auto final = test.final(); - raise("PC", final.pc(), cpu.PC().word); + raise("PC", final.pc(), cpu.PC().joined); raise("S", final.s(), cpu.S()); raise("A", final.a(), cpu.A()); raise("X", final.x(), cpu.X()); diff --git a/M6502/inc/mos6502.h b/M6502/inc/mos6502.h index 6a2df34..df808b8 100644 --- a/M6502/inc/mos6502.h +++ b/M6502/inc/mos6502.h @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -14,6 +13,23 @@ namespace EightBit { class Bus; class MOS6502 : public LittleEndianProcessor { + private: + using base = LittleEndianProcessor; + + private: + uint8_t m_x = 0; // index register X + uint8_t m_y = 0; // index register Y + uint8_t m_a = 0; // accumulator + uint8_t m_s = 0; // stack pointer + uint8_t m_p = 0; // processor status + + register16_t m_intermediate; + + uint8_t m_fixedPage = 0; + uint8_t m_unfixedPage = 0; + + bool m_immediateInstruction = false; + public: DECLARE_PIN_INPUT(NMI) DECLARE_PIN_INPUT(SO) @@ -35,9 +51,6 @@ namespace EightBit { MOS6502(Bus& bus) noexcept; - //Signal ExecutingInstruction; - //Signal ExecutedInstruction; - void execute() noexcept final; void poweredStep() noexcept final; @@ -53,151 +66,131 @@ namespace EightBit { void handleRESET() noexcept final; void handleINT() noexcept final; - void busWrite() noexcept final; - [[nodiscard]] uint8_t busRead() noexcept final; + void memoryWrite() noexcept final; + void memoryRead() noexcept final; - // Instructions with BCD effects - - void sbc() noexcept; - [[nodiscard]] virtual uint8_t sub(uint8_t operand, int borrow = 0) noexcept; - [[nodiscard]] uint8_t sub_b(uint8_t operand, int borrow = 0) noexcept; - [[nodiscard]] uint8_t sub_d(uint8_t operand, int borrow = 0) noexcept; - - virtual void adc() noexcept; - void adc_b() noexcept; - void adc_d() noexcept; - - // Undocumented compound instructions (with BCD effects) - - virtual void arr() noexcept; - void arr_b(uint8_t value) noexcept; - void arr_d(uint8_t value) noexcept; + void getPagedInto(uint8_t page, uint8_t offset, register16_t& into) { Processor::getPagedInto(page, offset, into); } private: - const uint8_t IRQvector = 0xfe; // IRQ vector - const uint8_t RSTvector = 0xfc; // RST vector - const uint8_t NMIvector = 0xfa; // NMI vector + const uint8_t _vectorIRQ = 0xfe; // IRQ vector + const uint8_t _vectorRST = 0xfc; // RST vector + const uint8_t _vectorNMI = 0xfa; // NMI vector void handleNMI() noexcept; void handleSO() noexcept; - enum interrupt_source_t { hardware, software }; - enum interrupt_type_t { reset, non_reset }; - void interrupt(uint8_t vector, interrupt_source_t source = hardware, interrupt_type_t type = non_reset) noexcept; + void adjustInterruptFlags(); + + void reset(); + void interruptMaskable(); + void interruptNonMaskable(); + void BRK() noexcept; constexpr void updateStack(uint8_t position) noexcept { BUS().ADDRESS() = { position, 1 }; } constexpr void lowerStack() noexcept { updateStack(S()--); } constexpr void raiseStack() noexcept { updateStack(++S()); } void push(uint8_t value) noexcept final; - [[nodiscard]] uint8_t pop() noexcept final; + void pop() noexcept final; // Dummy stack push, used during RESET void dummyPush() noexcept; - uint8_t readFromBus() noexcept { - raiseRW(); - return LittleEndianProcessor::busRead(); - } + void readFromMemory() noexcept; + void writeToMemory() noexcept; - void writeToBus() noexcept { - lowerRW(); - LittleEndianProcessor::busWrite(); - } + void modifyWrite(uint8_t data) noexcept; // Read the opcode within the existing cycle - uint8_t fetchInstruction() noexcept final { + [[nodiscard]] uint8_t fetchInstruction() noexcept final; - // Instruction fetch beginning - lowerSYNC(); + #pragma region Addressing modes - assert(cycles() == 1 && "An extra cycle has occurred"); + #pragma region Address page fixup - // Can't use fetchByte, since that would add an extra tick. - Address_Immediate(); - opcode() = readFromBus(); + [[nodiscard]] constexpr auto fixedPage() const noexcept { return m_fixedPage; } + [[nodiscard]] constexpr auto unfixedPage() const noexcept { return m_unfixedPage; } + [[nodiscard]] constexpr auto fixed() const noexcept { return fixedPage() != unfixedPage(); } - assert(cycles() == 1 && "BUS read has introduced stray cycles"); + void maybeFixup() noexcept; + void fixup() noexcept; + void maybeFixupRead() noexcept; + void fixupRead() noexcept; - // Instruction fetch has now completed - raiseSYNC(); - - return opcode(); + constexpr void noteFixedAddress(int address) noexcept { + noteFixedAddress((uint16_t)address); } - // Addressing modes + constexpr void noteFixedAddress(uint16_t address) noexcept { + m_unfixedPage = BUS().ADDRESS().high; + intermediate() = address; + m_fixedPage = intermediate().high; + BUS().ADDRESS().low = intermediate().low; + } - constexpr void noteFixedAddress(register16_t fixed) noexcept { m_fixed_page = fixed.high; BUS().ADDRESS().low = fixed.low; } + #pragma endregion - constexpr void Address_Immediate() noexcept { BUS().ADDRESS() = PC()++; } - void Address_Absolute() noexcept { BUS().ADDRESS() = fetchWord(); } - void Address_ZeroPage() noexcept { BUS().ADDRESS() = { fetchByte(), 0 }; } - void Address_ZeroPageIndirect() noexcept { Address_ZeroPage(); BUS().ADDRESS() = getWordPaged(); } - void Address_Indirect() noexcept { Address_Absolute(); BUS().ADDRESS() = getWordPaged(); } - void Address_ZeroPageWithIndex(uint8_t index) noexcept { AM_ZeroPage(); BUS().ADDRESS().low += index; } - void Address_ZeroPageX() noexcept { Address_ZeroPageWithIndex(X()); } - void Address_ZeroPageY() noexcept { Address_ZeroPageWithIndex(Y()); } - void Address_AbsoluteWithIndex(uint8_t index) noexcept { Address_Absolute(); noteFixedAddress(BUS().ADDRESS() + index); } - void Address_AbsoluteX() noexcept { Address_AbsoluteWithIndex(X()); } - void Address_AbsoluteY() noexcept { Address_AbsoluteWithIndex(Y()); } - void Address_IndexedIndirectX() noexcept { Address_ZeroPageX(); BUS().ADDRESS() = getWordPaged(); } - void Address_IndirectIndexedY() noexcept { Address_ZeroPageIndirect(); noteFixedAddress(BUS().ADDRESS() + Y()); } + #pragma region Address resolution - // Addressing modes, with read + void getAddressPaged() noexcept; + void absoluteAddress() noexcept; + void zeroPageAddress() noexcept; + void zeroPageIndirectAddress() noexcept; + void indirectAddress() noexcept; + void zeroPageWithIndexAddress(uint8_t index) noexcept; + void zeroPageXAddress() noexcept; + void zeroPageYAddress() noexcept; + void absoluteWithIndexAddress(uint8_t index) noexcept; + void absoluteXAddress() noexcept; + void absoluteYAddress() noexcept; + void indexedIndirectXAddress() noexcept; + void indirectIndexedYAddress() noexcept; - void AM_Immediate() noexcept { Address_Immediate(); memoryRead(); } - void AM_Absolute() noexcept { Address_Absolute(); memoryRead(); } - void AM_ZeroPage() noexcept { Address_ZeroPage(); memoryRead(); } - void AM_ZeroPageX() noexcept { Address_ZeroPageX(); memoryRead(); } - void AM_ZeroPageY() noexcept { Address_ZeroPageY(); memoryRead(); } - void AM_IndexedIndirectX() noexcept { Address_IndexedIndirectX(); memoryRead(); } - void AM_AbsoluteX() noexcept { Address_AbsoluteX(); maybe_fixupR(); } - void AM_AbsoluteY() noexcept { Address_AbsoluteY(); maybe_fixupR(); } - void AM_IndirectIndexedY() noexcept { Address_IndirectIndexedY(); maybe_fixupR(); } + #pragma endregion + + #pragma region Address and read + + void immediate() noexcept; + void absolute() noexcept; + void zeroPage() noexcept; + void zeroPageX() noexcept; + void zeroPageY() noexcept; + void indexedIndirectX() noexcept; + void absoluteX() noexcept; + void absoluteY() noexcept; + void indirectIndexedY() noexcept; + + #pragma endregion + + #pragma endregion // Flag checking [[nodiscard]] constexpr auto interruptMasked() const noexcept { return P() & IF; } - [[nodiscard]] constexpr auto decimal() const noexcept { return P() & DF; } + [[nodiscard]] constexpr auto denary() const noexcept { return P() & DF; } - [[nodiscard]] static constexpr auto negative(uint8_t data) noexcept { return data & NF; } - [[nodiscard]] constexpr auto negative() const noexcept { return negative(P()); } + [[nodiscard]] static constexpr auto negativeTest(uint8_t data) noexcept { return data & NF; } + [[nodiscard]] static constexpr auto zeroTest(uint8_t data) noexcept { return data & ZF; } + [[nodiscard]] static constexpr auto carryTest(uint8_t data) noexcept { return data & CF; } + [[nodiscard]] static constexpr auto overflowTest(uint8_t data) noexcept { return data & VF; } - [[nodiscard]] static constexpr auto zero(uint8_t data) noexcept { return data & ZF; } - [[nodiscard]] constexpr auto zero() const noexcept { return zero(P()); } - - [[nodiscard]] static constexpr auto overflow(uint8_t data) noexcept { return data & VF; } - [[nodiscard]] constexpr auto overflow() const noexcept { return overflow(P()); } - - [[nodiscard]] static constexpr auto carry(uint8_t data) noexcept { return data & CF; } - [[nodiscard]] constexpr auto carry() const noexcept { return carry(P()); } + [[nodiscard]] constexpr auto negative() const noexcept { return negativeTest(P()); } + [[nodiscard]] constexpr auto zero() const noexcept { return zeroTest(P()); } + [[nodiscard]] constexpr auto overflow() const noexcept { return overflowTest(P()); } + [[nodiscard]] constexpr auto carry() const noexcept { return carryTest(P()); } // Flag adjustment - constexpr void adjustZero(const uint8_t datum) noexcept { reset_flag(ZF, datum); } - constexpr void adjustNegative(const uint8_t datum) noexcept { set_flag(NF, negative(datum)); } + constexpr void adjustZero(const uint8_t datum) noexcept { resetFlag(ZF, datum); } + constexpr void adjustNegative(const uint8_t datum) noexcept { setFlag(NF, negativeTest(datum)); } constexpr void adjustNZ(const uint8_t datum) noexcept { adjustZero(datum); adjustNegative(datum); } - constexpr void adjustOverflow_add(uint8_t operand) noexcept { - const auto data = BUS().DATA(); - const auto intermediate = m_intermediate.low; - set_flag(VF, negative(~(operand ^ data) & (operand ^ intermediate))); - } - - constexpr void adjustOverflow_subtract(uint8_t operand) noexcept { - const auto data = BUS().DATA(); - const auto intermediate = m_intermediate.low; - set_flag(VF, negative((operand ^ data) & (operand ^ intermediate))); - } - // Miscellaneous - void branch(int condition) noexcept; - [[nodiscard]] constexpr auto through(const uint8_t data) noexcept { adjustNZ(data); return data; @@ -207,107 +200,348 @@ namespace EightBit { return through(BUS().DATA()); } - #define MW(OPERATION) { \ - const auto result = OPERATION(BUS().DATA()); \ - memoryWrite(); \ - memoryWrite(result); \ - } - - void maybe_fixup() noexcept { - if (BUS().ADDRESS().high != m_fixed_page) - fixup(); - } - - void fixup() noexcept { - memoryRead(); - BUS().ADDRESS().high = m_fixed_page; - } - - void maybe_fixupR() noexcept { maybe_fixup(); memoryRead(); } - void fixupR() noexcept { fixup(); memoryRead(); } - // Status flag operations - constexpr static void set_flag(uint8_t& f, int which, int condition) noexcept { f = setBit(f, which, condition); } - constexpr void set_flag(int which, int condition) noexcept { set_flag(P(), which, condition); } - constexpr void set_flag(int which) noexcept { P() = setBit(P(), which); } + constexpr static void setFlag(uint8_t& f, int which, int condition) noexcept { f = setBit(f, which, condition); } + constexpr void setFlag(int which, int condition) noexcept { setFlag(P(), which, condition); } + constexpr void setFlag(int which) noexcept { P() = setBit(P(), which); } - constexpr static void reset_flag(uint8_t& f, int which, int condition) noexcept { f = clearBit(f, which, condition); } - constexpr void reset_flag(int which, int condition) noexcept { reset_flag(P(), which, condition); } - constexpr void reset_flag(int which) noexcept { P() = clearBit(P(), which); } + constexpr static void resetFlag(uint8_t& f, int which, int condition) noexcept { f = clearBit(f, which, condition); } + constexpr void resetFlag(int which, int condition) noexcept { resetFlag(P(), which, condition); } + constexpr void resetFlag(int which) noexcept { P() = clearBit(P(), which); } // Chew up a cycle - void swallow() noexcept { memoryRead(PC()); } - void swallow_stack() noexcept { memoryRead({ S(), 1 }); } - void swallow_fetch() noexcept { fetchByte(); } + void swallowRead() noexcept; + void swallowPop() noexcept; + void swallowFetch() noexcept; - // Instruction implementations + #pragma region Instruction implementations - void andr() noexcept; - void bit() noexcept; - void cmp(uint8_t first) noexcept; - [[nodiscard]] uint8_t dec(uint8_t value) noexcept; - void eorr() noexcept; - [[nodiscard]] uint8_t inc(uint8_t value) noexcept; - void jsr() noexcept; - void orr() noexcept; - void php() noexcept; - void plp() noexcept; - void rti() noexcept; - void rts() noexcept; + #pragma region Miscellaneous - [[nodiscard]] constexpr uint8_t asl(uint8_t value) noexcept { - set_flag(CF, value & NF); + static constexpr void NOP() noexcept { + // No operation! + } + + void JMP() noexcept; + + #pragma endregion + + #pragma region Register to register transfer + + constexpr void TAX() noexcept { X() = through(A()); } + constexpr void TXA() noexcept { A() = through(X()); } + constexpr void TAY() noexcept { Y() = through(A()); } + constexpr void TYA() noexcept { A() = through(Y()); } + constexpr void TXS() noexcept { S() = X(); } + constexpr void TSX() noexcept { X() = through(S()); } + + #pragma endregion + + #pragma region Load and store + + constexpr void LDA() noexcept { A() = through(); } + void STA() noexcept; + + constexpr void LDX() noexcept { X() = through(); } + void STX() noexcept; + + void LDY() noexcept { Y() = through(); } + void STY() noexcept; + + #pragma endregion + + #pragma region Branching + + void fixupBranch(int8_t relative) noexcept; + void branch(bool condition) noexcept; + + void branchNot(int condition) noexcept; + void branch(int condition) noexcept; + + void BCS() noexcept; + void BCC() noexcept; + void BVC() noexcept; + void BMI() noexcept; + void BPL() noexcept; + void BVS() noexcept; + void BEQ() noexcept; + void BNE() noexcept; + + #pragma endregion + + #pragma region Status flag operations + + constexpr void SEI() noexcept { setFlag(IF); } + constexpr void CLI() noexcept { resetFlag(IF); } + constexpr void SEV() noexcept { setFlag(VF); } + constexpr void CLV() noexcept { resetFlag(VF); } + constexpr void SEC() noexcept { setFlag(CF); } + constexpr void CLC() noexcept { resetFlag(CF); } + constexpr void SED() noexcept { setFlag(DF); } + constexpr void CLD() noexcept { resetFlag(DF); } + + #pragma endregion + + #pragma region Instructions with BCD effects + + #pragma region Addition / subtraction + + #pragma region Subtraction + + constexpr void adjustOverflowSubtract(uint8_t operand) noexcept { + const auto data = BUS().DATA(); + const auto result = intermediate().low; + setFlag(VF, negativeTest((operand ^ data) & (operand ^ result))); + } + + constexpr void SBC() noexcept { + const auto operand = A(); + A() = SUB(operand, carryTest(~P())); + PostSUB(operand); + } + + constexpr uint8_t SUB(uint8_t operand, int borrow) noexcept { + return denary() != 0 ? decimalSUB(operand, borrow) : binarySUB(operand, borrow); + } + + constexpr uint8_t binarySUB(uint8_t operand, int borrow = 0) noexcept { + const auto data = BUS().DATA(); + intermediate() = operand - data - borrow; + + const auto result = intermediate().low; + adjustNZ(result); + + return result; + } + + constexpr uint8_t decimalSUB(uint8_t operand, int borrow) noexcept { + + binarySUB(operand, borrow); + + const auto data = BUS().DATA(); + auto low = lowNibble(operand) - lowNibble(data) - borrow; + const auto lowNegative = negativeTest(low); + if (lowNegative != 0) + low -= 6; + + auto high = highNibble(operand) - highNibble(data) - (lowNegative >> 7); + const auto highNegative = negativeTest(high); + if (highNegative != 0) + high -= 6; + + return promoteNibble(high) | lowNibble(low); + } + + constexpr void PostSUB(uint8_t operand) noexcept { + adjustOverflowSubtract(operand); + resetFlag(CF, intermediate().high); + } + + #pragma endregion + + #pragma region Addition + + constexpr void adjustOverflowAdd(uint8_t operand) noexcept { + const auto data = BUS().DATA(); + const auto result = intermediate().low; + setFlag(VF, negativeTest(~(operand ^ data) & (operand ^ result))); + } + + constexpr void ADC() noexcept { ADC(BUS().DATA()); } + + constexpr void ADC(uint8_t data) noexcept { A() = denary() != 0 ? decimalADC(data) : binaryADC(data); } + + [[nodiscard]] constexpr uint8_t binaryADC(uint8_t data) noexcept { + const auto operand = A(); + intermediate() = operand + data + carry(); + adjustOverflowAdd(operand); + setFlag(CF, carryTest(intermediate().high)); + + const auto result = intermediate().low; + adjustNZ(result); + + return result; + } + + [[nodiscard]] constexpr uint8_t decimalADC(uint8_t data) noexcept { + + const auto operand = A(); + + auto low = (uint16_t)(lowerNibble(operand) + lowerNibble(data) + carry()); + intermediate() = higherNibble(operand) + higherNibble(data); + + adjustZero(lowByte((uint16_t)(low + intermediate().joined))); + + if (low > 0x09) + { + intermediate() += 0x10; + low += 0x06; + } + + adjustNegative(intermediate().low); + adjustOverflowAdd(operand); + + if (intermediate().joined > 0x90) + intermediate() += 0x60; + + setFlag(CF, intermediate().high); + + return (uint8_t)(lowerNibble(lowByte((uint16_t)(low + intermediate().joined))) | higherNibble(intermediate().low)); + } + + #pragma endregion + + #pragma endregion + + #pragma endregion + + #pragma region Bitwise operations + + constexpr void ORA() noexcept { ORA(BUS().DATA()); } + constexpr void ORA(uint8_t data) noexcept { A() = through(A() | data); } + + constexpr void AND() noexcept { AND(BUS().DATA()); } + constexpr void AND(uint8_t data) noexcept { A() = through(A() & data); } + + constexpr void EOR() noexcept { EOR(BUS().DATA()); } + constexpr void EOR(uint8_t data) noexcept { A() = through(A() ^ data); } + + constexpr void bitSet(uint8_t mask) noexcept { adjustZero(A() & mask); } + + constexpr void BIT() noexcept { + const auto data = BUS().DATA(); + setFlag(VF, overflowTest(data)); + bitSet(data); + adjustNegative(data); + } + + #pragma endregion + + #pragma region Comparison operations + + constexpr void CMP(uint8_t first, uint8_t second) noexcept { + intermediate() = first - second; + adjustNZ(intermediate().low); + resetFlag(CF, intermediate().high); + } + + constexpr void CMP() noexcept { CMP(A(), BUS().DATA()); } + + constexpr void CPX() noexcept { CMP(X(), BUS().DATA()); } + + constexpr void CPY() noexcept { CMP(Y(), BUS().DATA()); } + + #pragma endregion + + #pragma region Increment/decrement + + [[nodiscard]] constexpr auto DEC(uint8_t value) noexcept { return through(value - 1); } + constexpr void DEX() noexcept { X() = DEC(X()); } + constexpr void DEY() noexcept { Y() = DEC(Y()); } + void DEC(); + + [[nodiscard]] constexpr auto INC(uint8_t value) noexcept { return through(value + 1); } + constexpr void INX() noexcept { X() = INC(X()); } + constexpr void INY() noexcept { Y() = INC(Y()); } + void INC(); + + #pragma endregion + + #pragma region Stack operations + + void JSR(); + + void PHA(); + void PLA(); + void PHP(); + void PLP(); + + void RTI(); + void RTS(); + + #pragma endregion + + #pragma region Shift/rotate operations + + #pragma region Shift + + void ASL(); + constexpr void ASLA() noexcept { A() = ASL(A()); } + constexpr uint8_t ASL(uint8_t value) noexcept { + setFlag(CF, negativeTest(value)); return through(value << 1); } - [[nodiscard]] constexpr uint8_t rol(uint8_t operand) noexcept { - const auto carryIn = carry(); - return through(asl(operand) | carryIn); - } - - [[nodiscard]] constexpr uint8_t lsr(uint8_t value) noexcept { - set_flag(CF, value & CF); + void LSR(); + constexpr void LSRA() noexcept { A() = LSR(A()); } + constexpr uint8_t LSR(uint8_t value) noexcept { + setFlag(CF, carryTest(value)); return through(value >> 1); } - [[nodiscard]] constexpr uint8_t ror(uint8_t operand) noexcept { + #pragma endregion + + #pragma region Rotate + + void ROL(); + constexpr void ROLA() noexcept { A() = ROL(A()); } + constexpr uint8_t ROL(uint8_t value) noexcept { const auto carryIn = carry(); - return through(lsr(operand) | (carryIn << 7)); + return through(ASL(value) | carryIn); } - // Undocumented compound instructions + void ROR(); + constexpr void RORA() noexcept { A() = ROR(A()); } + constexpr uint8_t ROR(uint8_t value) noexcept { + const auto carryIn = carry(); + return through(LSR(value) | (carryIn << 7)); + } - void anc() noexcept; - void axs() noexcept; - void jam() noexcept; + #pragma endregion - void storeFixupEffect(uint8_t data) noexcept { memoryWrite(data & (BUS().ADDRESS().high + 1)); } + #pragma endregion - void sha() noexcept { storeFixupEffect(A() & X()); } - void sya() noexcept { storeFixupEffect(Y()); } - void sxa() noexcept { storeFixupEffect(X()); } - void tas() noexcept { S() = A() & X(); sha(); } - void las() noexcept { A() = X() = S() = through(memoryRead() & S()); } - void ane() noexcept { A() = through((A() | 0xee) & X() & BUS().DATA()); } - void atx() noexcept { A() = X() = through((A() | 0xee) & BUS().DATA()); } - void asr() noexcept { andr(); A() = lsr(A()); } + #pragma region Undocumented instructions - void isb() noexcept { MW(inc); sbc(); } - void slo() noexcept { MW(asl); orr(); } - void rla() noexcept { MW(rol); andr(); } - void sre() noexcept { MW(lsr); eorr(); } - void rra() noexcept { MW(ror); adc(); } - void dcp() noexcept { MW(dec); cmp(A()); } + #pragma region Undocumented instructions with BCD effects - uint8_t m_x = 0; // index register X - uint8_t m_y = 0; // index register Y - uint8_t m_a = 0; // accumulator - uint8_t m_s = 0; // stack pointer - uint8_t m_p = 0; // processor status + void ARR(); + uint8_t coreARR(); + void decimalARR(); + void binaryARR(); - register16_t m_intermediate; + #pragma endregion - uint8_t m_fixed_page = 0; + #pragma region Undocumented instructions with fixup effects + + void storeFixupEffect(uint8_t data); + + void SHA(); + void SYA(); + void SXA(); + + #pragma endregion + + void SAX(); + void LAX(); + void ANC(); + void AXS(); + void JAM(); + void TAS(); + void LAS(); + void ANE(); + void ATX(); + void ASR(); + void ISB(); + void RLA(); + void RRA(); + void SLO(); + void SRE(); + void DCP(); + + #pragma endregion + + #pragma endregion }; } \ No newline at end of file diff --git a/M6502/src/Disassembly.cpp b/M6502/src/Disassembly.cpp index 8996b48..f6fb10e 100644 --- a/M6502/src/Disassembly.cpp +++ b/M6502/src/Disassembly.cpp @@ -56,7 +56,7 @@ std::string EightBit::Disassembly::disassemble(uint16_t current) { output << dump_ByteValue(cell) << " "; auto byte = BUS().peek(current + 1); - uint16_t relative = processor.PC().word + 2 + (int8_t)byte; + uint16_t relative = processor.PC().joined + 2 + (int8_t)byte; auto aaa = (cell & 0b11100000) >> 5; auto bbb = (cell & 0b00011100) >> 2; @@ -475,7 +475,7 @@ uint8_t EightBit::Disassembly::getByte(uint16_t address) { } uint16_t EightBit::Disassembly::getShort(uint16_t address) { - return processor.peekShort(address).word; + return processor.peekShort(address).joined; } //// diff --git a/M6502/src/mos6502.cpp b/M6502/src/mos6502.cpp index 4f35d76..dbebd00 100644 --- a/M6502/src/mos6502.cpp +++ b/M6502/src/mos6502.cpp @@ -2,7 +2,7 @@ #include "../inc/mos6502.h" EightBit::MOS6502::MOS6502(Bus& bus) noexcept -: LittleEndianProcessor(bus) { +: base(bus) { RaisedPOWER.connect([this](EventArgs) { X() = Bit7; Y() = 0; @@ -22,364 +22,575 @@ DEFINE_PIN_LEVEL_CHANGERS(RW, MOS6502) void EightBit::MOS6502::poweredStep() noexcept { - tick(); // A cycle is used, whether RDY is high or not + // A cycle is used, whether RDY is high or not + tick(); - if (UNLIKELY(lowered(SO()))) + if (lowered(SO())) handleSO(); - if (LIKELY(raised(RDY()))) { + if (raised(RDY())) { - fetchInstruction(); + m_immediateInstruction = false; + opcode() = fetchInstruction(); // Priority: RESET > NMI > INT - if (UNLIKELY(lowered(RESET()))) + if (lowered(RESET())) handleRESET(); - else if (UNLIKELY(lowered(NMI()))) + else if (lowered(NMI())) handleNMI(); - else if (UNLIKELY(lowered(INT()) && !interruptMasked())) + else if (lowered(INT()) && !interruptMasked()) handleINT(); else execute(); } } -// Interrupt (etc.) handlers +uint8_t EightBit::MOS6502::fetchInstruction() noexcept { -void EightBit::MOS6502::handleSO() noexcept { - raiseSO(); - P() |= VF; + // Instruction fetch beginning + lowerSYNC(); + + assert(cycles() == 1 && "An extra cycle has occurred"); + + // Can't use fetchByte, since that would add an extra tick. + immediateAddress(); + + ReadingMemory.fire(); + readFromMemory(); + ReadMemory.fire(); + + assert(cycles() == 1 && "BUS read has introduced stray cycles"); + + // Instruction fetch has now completed + raiseSYNC(); + + return BUS().DATA(); } +// Interrupt (etc.) handlers + void EightBit::MOS6502::handleRESET() noexcept { raiseRESET(); - interrupt(RSTvector, hardware, reset); -} - -void EightBit::MOS6502::handleNMI() noexcept { - raiseNMI(); - interrupt(NMIvector); + reset(); } void EightBit::MOS6502::handleINT() noexcept { raiseINT(); - interrupt(IRQvector); + interruptMaskable(); } -void EightBit::MOS6502::interrupt(uint8_t vector, interrupt_source_t source, interrupt_type_t type) noexcept { - if (type == reset) { - dummyPush(); - dummyPush(); - dummyPush(); - } else { - pushWord(PC()); - push(P() | (source == hardware ? 0 : BF)); - } - set_flag(IF); // Disable IRQ - jump(Processor::getWordPaged(0xff, vector)); +void EightBit::MOS6502::handleNMI() noexcept { + raiseNMI(); + interruptNonMaskable(); +} + +void EightBit::MOS6502::handleSO() noexcept { + raiseSO(); + SEV(); +} + +void EightBit::MOS6502::adjustInterruptFlags() { + SEI(); // Disable IRQ +} + +void EightBit::MOS6502::reset() { + dummyPush(); + dummyPush(); + dummyPush(); + getPagedInto(0xff, _vectorRST, PC()); + adjustInterruptFlags(); +} + +void EightBit::MOS6502::interruptMaskable() { + pushShort(PC()); + push(P()); + getPagedInto(0xff, _vectorIRQ, PC()); + adjustInterruptFlags(); +} + +void EightBit::MOS6502::interruptNonMaskable() { + pushShort(PC()); + push(P()); + getPagedInto(0xff, _vectorNMI, PC()); + adjustInterruptFlags(); +} + +void EightBit::MOS6502::BRK() noexcept { + pushShort(PC()); + push(P() | BF); + getPagedInto(0xff, _vectorIRQ, PC()); + adjustInterruptFlags(); +} + +void EightBit::MOS6502::swallowRead() noexcept { + base::memoryRead(PC()); +} + +void EightBit::MOS6502::swallowPop() noexcept { + base::memoryRead({ S(), 1 }); +} + +void EightBit::MOS6502::swallowFetch() noexcept { + fetchByte(); +} + +void EightBit::MOS6502::memoryWrite() noexcept { + WritingMemory.fire(); + tick(); + writeToMemory(); + WrittenMemory.fire(); +} + +void EightBit::MOS6502::memoryRead() noexcept { + ReadingMemory.fire(); + tick(); + readFromMemory(); + ReadMemory.fire(); +} + +void EightBit::MOS6502::readFromMemory() noexcept { + raiseRW(); + base::memoryRead(); +} + +void EightBit::MOS6502::writeToMemory() noexcept { + lowerRW(); + base::memoryWrite(); +} + +void EightBit::MOS6502::modifyWrite(uint8_t data) noexcept { + // The read will have already taken place... + memoryWrite(); // Modify cycle + Processor::memoryWrite(data); // Write cycle } // -void EightBit::MOS6502::busWrite() noexcept { - tick(); - writeToBus(); +#pragma region Address page fixup + +void EightBit::MOS6502::maybeFixup() noexcept { + if (BUS().ADDRESS().high != fixedPage()) + fixup(); } -uint8_t EightBit::MOS6502::busRead() noexcept { - tick(); - return readFromBus(); +void EightBit::MOS6502::fixup() noexcept { + memoryRead(); + BUS().ADDRESS().high = fixedPage(); } +void EightBit::MOS6502::maybeFixupRead() noexcept { + maybeFixup(); + memoryRead(); +} + +void EightBit::MOS6502::fixupRead() noexcept { + fixup(); + memoryRead(); +} + +#pragma endregion + +#pragma region Address resolution + +void EightBit::MOS6502::getAddressPaged() noexcept { + getShortPaged(); + BUS().ADDRESS() = intermediate(); +} + +void EightBit::MOS6502::absoluteAddress() noexcept { + fetchShortAddress(); +} + +void EightBit::MOS6502::zeroPageAddress() noexcept { + fetchByte(); + BUS().ADDRESS() = BUS().DATA(); +} + +void EightBit::MOS6502::zeroPageIndirectAddress() noexcept { + zeroPageAddress(); + getAddressPaged(); +} + +void EightBit::MOS6502::indirectAddress() noexcept { + absoluteAddress(); + getAddressPaged(); +} + +void EightBit::MOS6502::zeroPageWithIndexAddress(uint8_t index) noexcept { + zeroPage(); + BUS().ADDRESS().low += index; +} + +void EightBit::MOS6502::zeroPageXAddress() noexcept { + zeroPageWithIndexAddress(X()); +} + +void EightBit::MOS6502::zeroPageYAddress() noexcept { + zeroPageWithIndexAddress(Y()); +} + +void EightBit::MOS6502::absoluteWithIndexAddress(uint8_t index) noexcept { + absoluteAddress(); + noteFixedAddress(BUS().ADDRESS().joined + index); +} + +void EightBit::MOS6502::absoluteXAddress() noexcept { + absoluteWithIndexAddress(X()); +} + +void EightBit::MOS6502::absoluteYAddress() noexcept { + absoluteWithIndexAddress(Y()); +} + +void EightBit::MOS6502::indexedIndirectXAddress() noexcept { + zeroPageXAddress(); + getAddressPaged(); +} + +void EightBit::MOS6502::indirectIndexedYAddress() noexcept { + zeroPageIndirectAddress(); + noteFixedAddress(BUS().ADDRESS().joined + Y()); +} + +#pragma endregion + +#pragma region Address and read + +void EightBit::MOS6502::immediate() noexcept { + m_immediateInstruction = true; + fetchByte(); +} + +void EightBit::MOS6502::absolute() noexcept { + absoluteAddress(); + memoryRead(); +} + +void EightBit::MOS6502::zeroPage() noexcept { + zeroPageAddress(); + memoryRead(); +} + +void EightBit::MOS6502::zeroPageX() noexcept { + zeroPageXAddress(); + memoryRead(); +} + +void EightBit::MOS6502::zeroPageY() noexcept { + zeroPageYAddress(); + memoryRead(); +} + +void EightBit::MOS6502::indexedIndirectX() noexcept { + indexedIndirectXAddress(); + memoryRead(); +} + +void EightBit::MOS6502::absoluteX() noexcept { + absoluteXAddress(); + maybeFixupRead(); +} + +void EightBit::MOS6502::absoluteY() noexcept { + absoluteYAddress(); + maybeFixupRead(); +} + +void EightBit::MOS6502::indirectIndexedY() noexcept { + indirectIndexedYAddress(); + maybeFixupRead(); +} + +#pragma endregion + // void EightBit::MOS6502::execute() noexcept { switch (opcode()) { - case 0x00: swallow_fetch(); interrupt(IRQvector, software); break; // BRK (implied) - case 0x01: AM_IndexedIndirectX(); orr(); break; // ORA (indexed indirect X) - case 0x02: jam(); break; // *JAM - case 0x03: AM_IndexedIndirectX(); slo(); break; // *SLO (indexed indirect X) - case 0x04: AM_ZeroPage(); break; // *NOP (zero page) - case 0x05: AM_ZeroPage(); orr(); break; // ORA (zero page) - case 0x06: AM_ZeroPage(); MW(asl); break; // ASL (zero page) - case 0x07: AM_ZeroPage(); slo(); break; // *SLO (zero page) - case 0x08: swallow(); php(); break; // PHP (implied) - case 0x09: AM_Immediate(); orr(); break; // ORA (immediate) - case 0x0a: swallow(); A() = asl(A()); break; // ASL A (implied) - case 0x0b: AM_Immediate(); anc(); break; // *ANC (immediate) - case 0x0c: AM_Absolute(); break; // *NOP (absolute) - case 0x0d: AM_Absolute(); orr(); break; // ORA (absolute) - case 0x0e: AM_Absolute(); MW(asl); break; // ASL (absolute) - case 0x0f: AM_Absolute(); slo(); break; // *SLO (absolute) + case 0x00: swallowFetch(); BRK(); break; // BRK (implied) + case 0x01: indexedIndirectX(); ORA(); break; // ORA (indexed indirect X) + case 0x02: swallowRead(); JAM(); break; // *JAM + case 0x03: indexedIndirectX(); SLO(); break; // *SLO (indexed indirect X) + case 0x04: zeroPage(); NOP(); break; // *NOP (zero page) + case 0x05: zeroPage(); ORA(); break; // ORA (zero page) + case 0x06: zeroPage(); ASL(); break; // ASL (zero page) + case 0x07: zeroPage(); SLO(); break; // *SLO (zero page) + case 0x08: swallowRead(); PHP(); break; // PHP (implied) + case 0x09: immediate(); ORA(); break; // ORA (immediate) + case 0x0a: swallowRead(); ASLA(); break; // ASL A (implied) + case 0x0b: immediate(); ANC(); break; // *ANC (immediate) + case 0x0c: absolute(); NOP(); break; // *NOP (absolute) + case 0x0d: absolute(); ORA(); break; // ORA (absolute) + case 0x0e: absolute(); ASL(); break; // ASL (absolute) + case 0x0f: absolute(); SLO(); break; // *SLO (absolute) - case 0x10: branch(negative() == 0); break; // BPL (relative) - case 0x11: AM_IndirectIndexedY(); orr(); break; // ORA (indirect indexed Y) - case 0x12: jam(); break; // *JAM - case 0x13: Address_IndirectIndexedY(); fixupR(); slo(); break; // *SLO (indirect indexed Y) - case 0x14: AM_ZeroPageX(); break; // *NOP (zero page, X) - case 0x15: AM_ZeroPageX(); orr(); break; // ORA (zero page, X) - case 0x16: AM_ZeroPageX(); MW(asl); break; // ASL (zero page, X) - case 0x17: AM_ZeroPageX(); slo(); break; // *SLO (zero page, X) - case 0x18: swallow(); reset_flag(CF); break; // CLC (implied) - case 0x19: AM_AbsoluteY(); orr(); break; // ORA (absolute, Y) - case 0x1a: swallow(); break; // *NOP (implied) - case 0x1b: Address_AbsoluteY(); fixupR(); slo(); break; // *SLO (absolute, Y) - case 0x1c: Address_AbsoluteX(); maybe_fixupR(); break; // *NOP (absolute, X) - case 0x1d: AM_AbsoluteX(); orr(); break; // ORA (absolute, X) - case 0x1e: Address_AbsoluteX(); fixupR(); MW(asl); break; // ASL (absolute, X) - case 0x1f: Address_AbsoluteX(); fixupR(); slo(); break; // *SLO (absolute, X) + case 0x10: immediate(); BPL(); break; // BPL (relative) + case 0x11: indirectIndexedY(); ORA(); break; // ORA (indirect indexed Y) + case 0x12: swallowRead(); JAM(); break; // *JAM + case 0x13: indirectIndexedYAddress(); fixupRead(); SLO(); break; // *SLO (indirect indexed Y) + case 0x14: zeroPageX(); NOP(); break; // *NOP (zero page, X) + case 0x15: zeroPageX(); ORA(); break; // ORA (zero page, X) + case 0x16: zeroPageX(); ASL(); break; // ASL (zero page, X) + case 0x17: zeroPageX(); SLO(); break; // *SLO (zero page, X) + case 0x18: swallowRead(); resetFlag(CF); break; // CLC (implied) + case 0x19: absoluteY(); ORA(); break; // ORA (absolute, Y) + case 0x1a: swallowRead(); NOP(); break; // *NOP (implied) + case 0x1b: absoluteYAddress(); fixupRead(); SLO(); break; // *SLO (absolute, Y) + case 0x1c: absoluteXAddress(); maybeFixupRead(); break; // *NOP (absolute, X) + case 0x1d: absoluteX(); ORA(); break; // ORA (absolute, X) + case 0x1e: absoluteXAddress(); fixupRead(); ASL(); break; // ASL (absolute, X) + case 0x1f: absoluteXAddress(); fixupRead(); SLO(); break; // *SLO (absolute, X) - case 0x20: jsr(); break; // JSR (absolute) - case 0x21: AM_IndexedIndirectX(); andr(); break; // AND (indexed indirect X) - case 0x22: jam(); break; // *JAM - case 0x23: AM_IndexedIndirectX(); rla();; break; // *RLA (indexed indirect X) - case 0x24: AM_ZeroPage(); bit(); break; // BIT (zero page) - case 0x25: AM_ZeroPage(); andr(); break; // AND (zero page) - case 0x26: AM_ZeroPage(); MW(rol); break; // ROL (zero page) - case 0x27: AM_ZeroPage(); rla();; break; // *RLA (zero page) - case 0x28: swallow(); plp(); break; // PLP (implied) - case 0x29: AM_Immediate(); andr(); break; // AND (immediate) - case 0x2a: swallow(); A() = rol(A()); break; // ROL A (implied) - case 0x2b: AM_Immediate(); anc(); break; // *ANC (immediate) - case 0x2c: AM_Absolute(); bit(); break; // BIT (absolute) - case 0x2d: AM_Absolute(); andr(); break; // AND (absolute) - case 0x2e: AM_Absolute(); MW(rol); break; // ROL (absolute) - case 0x2f: AM_Absolute(); rla();; break; // *RLA (absolute) + case 0x20: JSR(); break; // JSR (absolute) + case 0x21: indexedIndirectX(); AND(); break; // AND (indexed indirect X) + case 0x22: swallowRead(); JAM(); break; // *JAM + case 0x23: indexedIndirectX(); RLA();; break; // *RLA (indexed indirect X) + case 0x24: zeroPage(); BIT(); break; // BIT (zero page) + case 0x25: zeroPage(); AND(); break; // AND (zero page) + case 0x26: zeroPage(); ROL(); break; // ROL (zero page) + case 0x27: zeroPage(); RLA();; break; // *RLA (zero page) + case 0x28: swallowRead(); PLP(); break; // PLP (implied) + case 0x29: immediate(); AND(); break; // AND (immediate) + case 0x2a: swallowRead(); ROLA(); break; // ROL A (implied) + case 0x2b: immediate(); ANC(); break; // *ANC (immediate) + case 0x2c: absolute(); BIT(); break; // BIT (absolute) + case 0x2d: absolute(); AND(); break; // AND (absolute) + case 0x2e: absolute(); ROL(); break; // ROL (absolute) + case 0x2f: absolute(); RLA();; break; // *RLA (absolute) - case 0x30: branch(negative()); break; // BMI (relative) - case 0x31: AM_IndirectIndexedY(); andr(); break; // AND (indirect indexed Y) - case 0x32: jam(); break; // *JAM - case 0x33: Address_IndirectIndexedY(); fixupR(); rla();; break; // *RLA (indirect indexed Y) - case 0x34: AM_ZeroPageX(); break; // *NOP (zero page, X) - case 0x35: AM_ZeroPageX(); andr(); break; // AND (zero page, X) - case 0x36: AM_ZeroPageX(); MW(rol); break; // ROL (zero page, X) - case 0x37: AM_ZeroPageX(); rla();; break; // *RLA (zero page, X) - case 0x38: swallow(); set_flag(CF); break; // SEC (implied) - case 0x39: AM_AbsoluteY(); andr(); break; // AND (absolute, Y) - case 0x3a: swallow(); break; // *NOP (implied) - case 0x3b: Address_AbsoluteY(); fixupR(); rla();; break; // *RLA (absolute, Y) - case 0x3c: Address_AbsoluteX(); maybe_fixupR(); break; // *NOP (absolute, X) - case 0x3d: AM_AbsoluteX(); andr(); break; // AND (absolute, X) - case 0x3e: Address_AbsoluteX(); fixupR(); MW(rol); break; // ROL (absolute, X) - case 0x3f: Address_AbsoluteX(); fixupR(); rla();; break; // *RLA (absolute, X) + case 0x30: immediate(); BMI(); break; // BMI (relative) + case 0x31: indirectIndexedY(); AND(); break; // AND (indirect indexed Y) + case 0x32: swallowRead(); JAM(); break; // *JAM + case 0x33: indirectIndexedYAddress(); fixupRead(); RLA(); break; // *RLA (indirect indexed Y) + case 0x34: zeroPageX(); NOP(); break; // *NOP (zero page, X) + case 0x35: zeroPageX(); AND(); break; // AND (zero page, X) + case 0x36: zeroPageX(); ROL(); break; // ROL (zero page, X) + case 0x37: zeroPageX(); RLA();; break; // *RLA (zero page, X) + case 0x38: swallowRead(); SEC(); break; // SEC (implied) + case 0x39: absoluteY(); AND(); break; // AND (absolute, Y) + case 0x3a: swallowRead(); NOP(); break; // *NOP (implied) + case 0x3b: absoluteYAddress(); fixupRead(); RLA(); break; // *RLA (absolute, Y) + case 0x3c: absoluteXAddress(); maybeFixupRead(); NOP(); break; // *NOP (absolute, X) + case 0x3d: absoluteX(); AND(); break; // AND (absolute, X) + case 0x3e: absoluteXAddress(); fixupRead(); ROL(); break; // ROL (absolute, X) + case 0x3f: absoluteXAddress(); fixupRead(); RLA(); break; // *RLA (absolute, X) - case 0x40: swallow(); rti(); break; // RTI (implied) - case 0x41: AM_IndexedIndirectX(); eorr(); break; // EOR (indexed indirect X) - case 0x42: jam(); break; // *JAM - case 0x43: AM_IndexedIndirectX(); sre(); break; // *SRE (indexed indirect X) - case 0x44: AM_ZeroPage(); break; // *NOP (zero page) - case 0x45: AM_ZeroPage(); eorr(); break; // EOR (zero page) - case 0x46: AM_ZeroPage(); MW(lsr); break; // LSR (zero page) - case 0x47: AM_ZeroPage(); sre(); break; // *SRE (zero page) - case 0x48: swallow(); push(A()); break; // PHA (implied) - case 0x49: AM_Immediate(); eorr(); break; // EOR (immediate) - case 0x4a: swallow(); A() = lsr(A()); break; // LSR A (implied) - case 0x4b: AM_Immediate(); asr(); break; // *ASR (immediate) - case 0x4c: Address_Absolute(); jump(BUS().ADDRESS()); break; // JMP (absolute) - case 0x4d: AM_Absolute(); eorr(); break; // EOR (absolute) - case 0x4e: AM_Absolute(); MW(lsr); break; // LSR (absolute) - case 0x4f: AM_Absolute(); sre(); break; // *SRE (absolute) + case 0x40: swallowRead(); RTI(); break; // RTI (implied) + case 0x41: indexedIndirectX(); EOR(); break; // EOR (indexed indirect X) + case 0x42: swallowRead(); JAM(); break; // *JAM + case 0x43: indexedIndirectX(); SRE(); break; // *SRE (indexed indirect X) + case 0x44: zeroPage(); NOP(); break; // *NOP (zero page) + case 0x45: zeroPage(); EOR(); break; // EOR (zero page) + case 0x46: zeroPage(); LSR(); break; // LSR (zero page) + case 0x47: zeroPage(); SRE(); break; // *SRE (zero page) + case 0x48: swallowRead(); PHA(); break; // PHA (implied) + case 0x49: immediate(); EOR(); break; // EOR (immediate) + case 0x4a: swallowRead(); LSRA(); break; // LSR A (implied) + case 0x4b: immediate(); ASR(); break; // *ASR (immediate) + case 0x4c: absoluteAddress(); JMP(); break; // JMP (absolute) + case 0x4d: absolute(); EOR(); break; // EOR (absolute) + case 0x4e: absolute(); LSR(); break; // LSR (absolute) + case 0x4f: absolute(); SRE(); break; // *SRE (absolute) - case 0x50: branch(overflow() == 0); break; // BVC (relative) - case 0x51: AM_IndirectIndexedY(); eorr(); break; // EOR (indirect indexed Y) - case 0x52: jam(); break; // *JAM - case 0x53: Address_IndirectIndexedY(); fixupR(); sre(); break; // *SRE (indirect indexed Y) - case 0x54: AM_ZeroPageX(); break; // *NOP (zero page, X) - case 0x55: AM_ZeroPageX(); eorr(); break; // EOR (zero page, X) - case 0x56: AM_ZeroPageX(); MW(lsr); break; // LSR (zero page, X) - case 0x57: AM_ZeroPageX(); sre(); break; // *SRE (zero page, X) - case 0x58: swallow(); reset_flag(IF); break; // CLI (implied) - case 0x59: AM_AbsoluteY(); eorr(); break; // EOR (absolute, Y) - case 0x5a: swallow(); break; // *NOP (implied) - case 0x5b: Address_AbsoluteY(); fixupR(); sre(); break; // *SRE (absolute, Y) - case 0x5c: Address_AbsoluteX(); maybe_fixupR(); break; // *NOP (absolute, X) - case 0x5d: AM_AbsoluteX(); eorr(); break; // EOR (absolute, X) - case 0x5e: Address_AbsoluteX(); fixupR(); MW(lsr); break; // LSR (absolute, X) - case 0x5f: Address_AbsoluteX(); fixupR(); sre(); break; // *SRE (absolute, X) + case 0x50: immediate(); BVC(); break; // BVC (relative) + case 0x51: indirectIndexedY(); EOR(); break; // EOR (indirect indexed Y) + case 0x52: swallowRead(); JAM(); break; // *JAM + case 0x53: indirectIndexedYAddress(); fixupRead(); SRE(); break; // *SRE (indirect indexed Y) + case 0x54: zeroPageX(); NOP(); break; // *NOP (zero page, X) + case 0x55: zeroPageX(); EOR(); break; // EOR (zero page, X) + case 0x56: zeroPageX(); LSR(); break; // LSR (zero page, X) + case 0x57: zeroPageX(); SRE(); break; // *SRE (zero page, X) + case 0x58: swallowRead(); CLI(); break; // CLI (implied) + case 0x59: absoluteY(); EOR(); break; // EOR (absolute, Y) + case 0x5a: swallowRead(); NOP(); break; // *NOP (implied) + case 0x5b: absoluteYAddress(); fixupRead(); SRE(); break; // *SRE (absolute, Y) + case 0x5c: absoluteXAddress(); maybeFixupRead(); NOP(); break; // *NOP (absolute, X) + case 0x5d: absoluteX(); EOR(); break; // EOR (absolute, X) + case 0x5e: absoluteXAddress(); fixupRead(); LSR(); break; // LSR (absolute, X) + case 0x5f: absoluteXAddress(); fixupRead(); SRE(); break; // *SRE (absolute, X) - case 0x60: swallow(); rts(); break; // RTS (implied) - case 0x61: AM_IndexedIndirectX(); adc(); break; // ADC (indexed indirect X) - case 0x62: jam(); break; // *JAM - case 0x63: AM_IndexedIndirectX(); rra(); break; // *RRA (indexed indirect X) - case 0x64: AM_ZeroPage(); break; // *NOP (zero page) - case 0x65: AM_ZeroPage(); adc(); break; // ADC (zero page) - case 0x66: AM_ZeroPage(); MW(ror); break; // ROR (zero page) - case 0x67: AM_ZeroPage(); rra(); break; // *RRA (zero page) - case 0x68: swallow(); swallow_stack(); A() = through(pop()); break; // PLA (implied) - case 0x69: AM_Immediate(); adc(); break; // ADC (immediate) - case 0x6a: swallow(); A() = ror(A()); break; // ROR A (implied) - case 0x6b: AM_Immediate(); arr(); break; // *ARR (immediate) - case 0x6c: Address_Indirect(); jump(BUS().ADDRESS()); break; // JMP (indirect) - case 0x6d: AM_Absolute(); adc(); break; // ADC (absolute) - case 0x6e: AM_Absolute(); MW(ror); break; // ROR (absolute) - case 0x6f: AM_Absolute(); rra(); break; // *RRA (absolute) + case 0x60: swallowRead(); RTS(); break; // RTS (implied) + case 0x61: indexedIndirectX(); ADC(); break; // ADC (indexed indirect X) + case 0x62: swallowRead(); JAM(); break; // *JAM + case 0x63: indexedIndirectX(); RRA(); break; // *RRA (indexed indirect X) + case 0x64: zeroPage(); NOP(); break; // *NOP (zero page) + case 0x65: zeroPage(); ADC(); break; // ADC (zero page) + case 0x66: zeroPage(); ROR(); break; // ROR (zero page) + case 0x67: zeroPage(); RRA(); break; // *RRA (zero page) + case 0x68: swallowRead(); PLA(); break; // PLA (implied) + case 0x69: immediate(); ADC(); break; // ADC (immediate) + case 0x6a: swallowRead(); RORA(); break; // ROR A (implied) + case 0x6b: immediate(); ARR(); break; // *ARR (immediate) + case 0x6c: indirectAddress(); JMP(); break; // JMP (indirect) + case 0x6d: absolute(); ADC(); break; // ADC (absolute) + case 0x6e: absolute(); ROR(); break; // ROR (absolute) + case 0x6f: absolute(); RRA(); break; // *RRA (absolute) - case 0x70: branch(overflow()); break; // BVS (relative) - case 0x71: AM_IndirectIndexedY(); adc(); break; // ADC (indirect indexed Y) - case 0x72: jam(); break; // *JAM - case 0x73: Address_IndirectIndexedY(); fixupR(); rra(); break; // *RRA (indirect indexed Y) - case 0x74: AM_ZeroPageX(); break; // *NOP (zero page, X) - case 0x75: AM_ZeroPageX(); adc(); break; // ADC (zero page, X) - case 0x76: AM_ZeroPageX(); MW(ror); break; // ROR (zero page, X) - case 0x77: AM_ZeroPageX(); rra(); break; // *RRA (zero page, X) - case 0x78: swallow(); set_flag(IF); break; // SEI (implied) - case 0x79: AM_AbsoluteY(); adc(); break; // ADC (absolute, Y) - case 0x7a: swallow(); break; // *NOP (implied) - case 0x7b: Address_AbsoluteY(); fixupR(); rra(); break; // *RRA (absolute, Y) - case 0x7c: Address_AbsoluteX(); maybe_fixupR(); break; // *NOP (absolute, X) - case 0x7d: AM_AbsoluteX(); adc(); break; // ADC (absolute, X) - case 0x7e: Address_AbsoluteX(); fixupR(); MW(ror); break; // ROR (absolute, X) - case 0x7f: Address_AbsoluteX(); fixupR(); rra(); break; // *RRA (absolute, X) + case 0x70: immediate(); BVS(); break; // BVS (relative) + case 0x71: indirectIndexedY(); ADC(); break; // ADC (indirect indexed Y) + case 0x72: swallowRead(); JAM(); break; // *JAM + case 0x73: indirectIndexedYAddress(); fixupRead(); RRA(); break; // *RRA (indirect indexed Y) + case 0x74: zeroPageX(); NOP(); break; // *NOP (zero page, X) + case 0x75: zeroPageX(); ADC(); break; // ADC (zero page, X) + case 0x76: zeroPageX(); ROR(); break; // ROR (zero page, X) + case 0x77: zeroPageX(); RRA(); break; // *RRA (zero page, X) + case 0x78: swallowRead(); SEI(); break; // SEI (implied) + case 0x79: absoluteY(); ADC(); break; // ADC (absolute, Y) + case 0x7a: swallowRead(); NOP(); break; // *NOP (implied) + case 0x7b: absoluteYAddress(); fixupRead(); RRA(); break; // *RRA (absolute, Y) + case 0x7c: absoluteXAddress(); maybeFixupRead(); NOP(); break; // *NOP (absolute, X) + case 0x7d: absoluteX(); ADC(); break; // ADC (absolute, X) + case 0x7e: absoluteXAddress(); fixupRead(); ROR(); break; // ROR (absolute, X) + case 0x7f: absoluteXAddress(); fixupRead(); RRA(); break; // *RRA (absolute, X) - case 0x80: AM_Immediate(); break; // *NOP (immediate) - case 0x81: Address_IndexedIndirectX(); memoryWrite(A()); break; // STA (indexed indirect X) - case 0x82: AM_Immediate(); break; // *NOP (immediate) - case 0x83: Address_IndexedIndirectX(); memoryWrite(A() & X()); break; // *SAX (indexed indirect X) - case 0x84: Address_ZeroPage(); memoryWrite(Y()); break; // STY (zero page) - case 0x85: Address_ZeroPage(); memoryWrite(A()); break; // STA (zero page) - case 0x86: Address_ZeroPage(); memoryWrite(X()); break; // STX (zero page) - case 0x87: Address_ZeroPage(); memoryWrite(A() & X()); break; // *SAX (zero page) - case 0x88: swallow(); Y() = dec(Y()); break; // DEY (implied) - case 0x89: AM_Immediate(); break; // *NOP (immediate) - case 0x8a: swallow(); A() = through(X()); break; // TXA (implied) - case 0x8b: AM_Immediate(); ane(); break; // *ANE (immediate) - case 0x8c: Address_Absolute(); memoryWrite(Y()); break; // STY (absolute) - case 0x8d: Address_Absolute(); memoryWrite(A()); break; // STA (absolute) - case 0x8e: Address_Absolute(); memoryWrite(X()); break; // STX (absolute) - case 0x8f: Address_Absolute(); memoryWrite(A() & X()); break; // *SAX (absolute) + case 0x80: immediate(); NOP(); break; // *NOP (immediate) + case 0x81: indexedIndirectXAddress(); STA(); break; // STA (indexed indirect X) + case 0x82: immediate(); NOP(); break; // *NOP (immediate) + case 0x83: indexedIndirectXAddress(); SAX(); break; // *SAX (indexed indirect X) + case 0x84: zeroPageAddress(); STY(); break; // STY (zero page) + case 0x85: zeroPageAddress(); STA(); break; // STA (zero page) + case 0x86: zeroPageAddress(); STX(); break; // STX (zero page) + case 0x87: zeroPageAddress(); SAX(); break; // *SAX (zero page) + case 0x88: swallowRead(); DEY(); break; // DEY (implied) + case 0x89: immediate(); NOP(); break; // *NOP (immediate) + case 0x8a: swallowRead(); TXA(); break; // TXA (implied) + case 0x8b: immediate(); ANE(); break; // *ANE (immediate) + case 0x8c: absoluteAddress(); STY(); break; // STY (absolute) + case 0x8d: absoluteAddress(); STA(); break; // STA (absolute) + case 0x8e: absoluteAddress(); STX(); break; // STX (absolute) + case 0x8f: absoluteAddress(); SAX(); break; // *SAX (absolute) - case 0x90: branch(carry() == 0); break; // BCC (relative) - case 0x91: Address_IndirectIndexedY(); fixup(); memoryWrite(A()); break; // STA (indirect indexed Y) - case 0x92: jam(); break; // *JAM - case 0x93: Address_IndirectIndexedY(); fixup(); sha(); break; // *SHA (indirect indexed, Y) - case 0x94: Address_ZeroPageX(); memoryWrite(Y()); break; // STY (zero page, X) - case 0x95: Address_ZeroPageX(); memoryWrite(A()); break; // STA (zero page, X) - case 0x96: Address_ZeroPageY(); memoryWrite(X()); break; // STX (zero page, Y) - case 0x97: Address_ZeroPageY(); memoryWrite(A() & X()); break; // *SAX (zero page, Y) - case 0x98: swallow(); A() = through(Y()); break; // TYA (implied) - case 0x99: Address_AbsoluteY(); fixup(); memoryWrite(A()); break; // STA (absolute, Y) - case 0x9a: swallow(); S() = X(); break; // TXS (implied) - case 0x9b: Address_AbsoluteY(); fixup(); tas(); break; // *TAS (absolute, Y) - case 0x9c: Address_AbsoluteX(); fixup(); sya(); break; // *SYA (absolute, X) - case 0x9d: Address_AbsoluteX(); fixup(); memoryWrite(A()); break; // STA (absolute, X) - case 0x9e: Address_AbsoluteY(); fixup(); sxa(); break; // *SXA (absolute, Y) - case 0x9f: Address_AbsoluteY(); fixup(); sha(); break; // *SHA (absolute, Y) + case 0x90: immediate(); BCC(); break; // BCC (relative) + case 0x91: indirectIndexedYAddress(); fixup(); STA(); break; // STA (indirect indexed Y) + case 0x92: swallowRead(); JAM(); break; // *JAM + case 0x93: indirectIndexedYAddress(); fixup(); SHA(); break; // *SHA (indirect indexed, Y) + case 0x94: zeroPageXAddress(); STY(); break; // STY (zero page, X) + case 0x95: zeroPageXAddress(); STA(); break; // STA (zero page, X) + case 0x96: zeroPageYAddress(); STX(); break; // STX (zero page, Y) + case 0x97: zeroPageYAddress(); SAX(); break; // *SAX (zero page, Y) + case 0x98: swallowRead(); TYA(); break; // TYA (implied) + case 0x99: absoluteYAddress(); fixup(); STA(); break; // STA (absolute, Y) + case 0x9a: swallowRead(); TXS(); break; // TXS (implied) + case 0x9b: absoluteYAddress(); fixup(); TAS(); break; // *TAS (absolute, Y) + case 0x9c: absoluteXAddress(); fixup(); SYA(); break; // *SYA (absolute, X) + case 0x9d: absoluteXAddress(); fixup(); STA(); break; // STA (absolute, X) + case 0x9e: absoluteYAddress(); fixup(); SXA(); break; // *SXA (absolute, Y) + case 0x9f: absoluteYAddress(); fixup(); SHA(); break; // *SHA (absolute, Y) - case 0xa0: AM_Immediate(); Y() = through(); break; // LDY (immediate) - case 0xa1: AM_IndexedIndirectX(); A() = through(); break; // LDA (indexed indirect X) - case 0xa2: AM_Immediate(); X() = through(); break; // LDX (immediate) - case 0xa3: AM_IndexedIndirectX(); A() = X() = through(); break; // *LAX (indexed indirect X) - case 0xa4: AM_ZeroPage(); Y() = through(); break; // LDY (zero page) - case 0xa5: AM_ZeroPage(); A() = through(); break; // LDA (zero page) - case 0xa6: AM_ZeroPage(); X() = through(); break; // LDX (zero page) - case 0xa7: AM_ZeroPage(); A() = X() = through(); break; // *LAX (zero page) - case 0xa8: swallow(); Y() = through(A()); break; // TAY (implied) - case 0xa9: AM_Immediate(); A() = through(); break; // LDA (immediate) - case 0xaa: swallow(); X() = through(A()); break; // TAX (implied) - case 0xab: AM_Immediate(); atx(); break; // *ATX (immediate) - case 0xac: AM_Absolute(); Y() = through(); break; // LDY (absolute) - case 0xad: AM_Absolute(); A() = through(); break; // LDA (absolute) - case 0xae: AM_Absolute(); X() = through(); break; // LDX (absolute) - case 0xaf: AM_Absolute(); A() = X() = through(); break; // *LAX (absolute) + case 0xa0: immediate(); LDY(); break; // LDY (immediate) + case 0xa1: indexedIndirectX(); LDA(); break; // LDA (indexed indirect X) + case 0xa2: immediate(); LDX(); break; // LDX (immediate) + case 0xa3: indexedIndirectX(); LAX(); break; // *LAX (indexed indirect X) + case 0xa4: zeroPage(); LDY(); break; // LDY (zero page) + case 0xa5: zeroPage(); LDA(); break; // LDA (zero page) + case 0xa6: zeroPage(); LDX(); break; // LDX (zero page) + case 0xa7: zeroPage(); LAX(); break; // *LAX (zero page) + case 0xa8: swallowRead(); TAY(); break; // TAY (implied) + case 0xa9: immediate(); LDA(); break; // LDA (immediate) + case 0xaa: swallowRead(); TAX(); break; // TAX (implied) + case 0xab: immediate(); ATX(); break; // *ATX (immediate) + case 0xac: absolute(); LDY(); break; // LDY (absolute) + case 0xad: absolute(); LDA(); break; // LDA (absolute) + case 0xae: absolute(); LDX(); break; // LDX (absolute) + case 0xaf: absolute(); LAX(); break; // *LAX (absolute) - case 0xb0: branch(carry()); break; // BCS (relative) - case 0xb1: AM_IndirectIndexedY(); A() = through(); break; // LDA (indirect indexed Y) - case 0xb2: jam(); break; // *JAM - case 0xb3: AM_IndirectIndexedY(); A() = X() = through(); break; // *LAX (indirect indexed Y) - case 0xb4: AM_ZeroPageX(); Y() = through(); break; // LDY (zero page, X) - case 0xb5: AM_ZeroPageX(); A() = through(); break; // LDA (zero page, X) - case 0xb6: AM_ZeroPageY(); X() = through(); break; // LDX (zero page, Y) - case 0xb7: AM_ZeroPageY(); A() = X() = through(); break; // *LAX (zero page, Y) - case 0xb8: swallow(); reset_flag(VF); break; // CLV (implied) - case 0xb9: AM_AbsoluteY(); A() = through(); break; // LDA (absolute, Y) - case 0xba: swallow(); X() = through(S()); break; // TSX (implied) - case 0xbb: Address_AbsoluteY(); maybe_fixup(); las(); break; // *LAS (absolute, Y) - case 0xbc: AM_AbsoluteX(); Y() = through(); break; // LDY (absolute, X) - case 0xbd: AM_AbsoluteX(); A() = through(); break; // LDA (absolute, X) - case 0xbe: AM_AbsoluteY(); X() = through(); break; // LDX (absolute, Y) - case 0xbf: AM_AbsoluteY(); A() = X() = through(); break; // *LAX (absolute, Y) + case 0xb0: immediate(); BCS(); break; // BCS (relative) + case 0xb1: indirectIndexedY(); LDA(); break; // LDA (indirect indexed Y) + case 0xb2: swallowRead(); JAM(); break; // *JAM + case 0xb3: indirectIndexedY(); LAX(); break; // *LAX (indirect indexed Y) + case 0xb4: zeroPageX(); LDY(); break; // LDY (zero page, X) + case 0xb5: zeroPageX(); LDA(); break; // LDA (zero page, X) + case 0xb6: zeroPageY(); LDX(); break; // LDX (zero page, Y) + case 0xb7: zeroPageY(); LAX(); break; // *LAX (zero page, Y) + case 0xb8: swallowRead(); CLV(); break; // CLV (implied) + case 0xb9: absoluteY(); LDA(); break; // LDA (absolute, Y) + case 0xba: swallowRead(); TSX(); break; // TSX (implied) + case 0xbb: absoluteYAddress(); maybeFixupRead(); LAS(); break; // *LAS (absolute, Y) + case 0xbc: absoluteX(); LDY(); break; // LDY (absolute, X) + case 0xbd: absoluteX(); LDA(); break; // LDA (absolute, X) + case 0xbe: absoluteY(); LDX(); break; // LDX (absolute, Y) + case 0xbf: absoluteY(); LAX(); break; // *LAX (absolute, Y) - case 0xc0: AM_Immediate(); cmp(Y()); break; // CPY (immediate) - case 0xc1: AM_IndexedIndirectX(); cmp(A()); break; // CMP (indexed indirect X) - case 0xc2: AM_Immediate(); break; // *NOP (immediate) - case 0xc3: AM_IndexedIndirectX(); dcp(); break; // *DCP (indexed indirect X) - case 0xc4: AM_ZeroPage(); cmp(Y()); break; // CPY (zero page) - case 0xc5: AM_ZeroPage(); cmp(A()); break; // CMP (zero page) - case 0xc6: AM_ZeroPage(); MW(dec); break; // DEC (zero page) - case 0xc7: AM_ZeroPage(); dcp(); break; // *DCP (zero page) - case 0xc8: swallow(); Y() = inc(Y()); break; // INY (implied) - case 0xc9: AM_Immediate(); cmp(A()); break; // CMP (immediate) - case 0xca: swallow(); X() = dec(X()); break; // DEX (implied) - case 0xcb: AM_Immediate(); axs(); break; // *AXS (immediate) - case 0xcc: AM_Absolute(); cmp(Y()); break; // CPY (absolute) - case 0xcd: AM_Absolute(); cmp(A()); break; // CMP (absolute) - case 0xce: AM_Absolute(); MW(dec); break; // DEC (absolute) - case 0xcf: AM_Absolute(); dcp(); break; // *DCP (absolute) + case 0xc0: immediate(); CPY(); break; // CPY (immediate) + case 0xc1: indexedIndirectX(); CMP(); break; // CMP (indexed indirect X) + case 0xc2: immediate(); NOP(); break; // *NOP (immediate) + case 0xc3: indexedIndirectX(); DCP(); break; // *DCP (indexed indirect X) + case 0xc4: zeroPage(); CPY(); break; // CPY (zero page) + case 0xc5: zeroPage(); CMP(); break; // CMP (zero page) + case 0xc6: zeroPage(); DEC(); break; // DEC (zero page) + case 0xc7: zeroPage(); DCP(); break; // *DCP (zero page) + case 0xc8: swallowRead(); INY(); break; // INY (implied) + case 0xc9: immediate(); CMP(); break; // CMP (immediate) + case 0xca: swallowRead(); DEX(); break; // DEX (implied) + case 0xcb: immediate(); AXS(); break; // *AXS (immediate) + case 0xcc: absolute(); CPY(); break; // CPY (absolute) + case 0xcd: absolute(); CMP(); break; // CMP (absolute) + case 0xce: absolute(); DEC(); break; // DEC (absolute) + case 0xcf: absolute(); DCP(); break; // *DCP (absolute) - case 0xd0: branch(zero() == 0); break; // BNE (relative) - case 0xd1: AM_IndirectIndexedY(); cmp(A()); break; // CMP (indirect indexed Y) - case 0xd2: jam(); break; // *JAM - case 0xd3: Address_IndirectIndexedY(); fixupR(); dcp(); break; // *DCP (indirect indexed Y) - case 0xd4: AM_ZeroPageX(); break; // *NOP (zero page, X) - case 0xd5: AM_ZeroPageX(); cmp(A()); break; // CMP (zero page, X) - case 0xd6: AM_ZeroPageX(); MW(dec); break; // DEC (zero page, X) - case 0xd7: AM_ZeroPageX(); dcp(); break; // *DCP (zero page, X) - case 0xd8: swallow(); reset_flag(DF); break; // CLD (implied) - case 0xd9: AM_AbsoluteY(); cmp(A()); break; // CMP (absolute, Y) - case 0xda: swallow(); break; // *NOP (implied) - case 0xdb: Address_AbsoluteY(); fixupR(); dcp(); break; // *DCP (absolute, Y) - case 0xdc: Address_AbsoluteX(); maybe_fixupR(); break; // *NOP (absolute, X) - case 0xdd: AM_AbsoluteX(); cmp(A()); break; // CMP (absolute, X) - case 0xde: Address_AbsoluteX(); fixupR(); MW(dec); break; // DEC (absolute, X) - case 0xdf: Address_AbsoluteX(); fixupR(); dcp(); break; // *DCP (absolute, X) + case 0xd0: immediate(); BNE(); break; // BNE (relative) + case 0xd1: indirectIndexedY(); CMP(); break; // CMP (indirect indexed Y) + case 0xd2: swallowRead(); JAM(); break; // *JAM + case 0xd3: indirectIndexedYAddress(); fixupRead(); DCP(); break; // *DCP (indirect indexed Y) + case 0xd4: zeroPageX(); NOP(); break; // *NOP (zero page, X) + case 0xd5: zeroPageX(); CMP(); break; // CMP (zero page, X) + case 0xd6: zeroPageX(); DEC(); break; // DEC (zero page, X) + case 0xd7: zeroPageX(); DCP(); break; // *DCP (zero page, X) + case 0xd8: swallowRead(); CLD(); break; // CLD (implied) + case 0xd9: absoluteY(); CMP(); break; // CMP (absolute, Y) + case 0xda: swallowRead(); NOP(); break; // *NOP (implied) + case 0xdb: absoluteYAddress(); fixupRead(); DCP(); break; // *DCP (absolute, Y) + case 0xdc: absoluteXAddress(); maybeFixupRead(); NOP(); break; // *NOP (absolute, X) + case 0xdd: absoluteX(); CMP(); break; // CMP (absolute, X) + case 0xde: absoluteXAddress(); fixupRead(); DEC(); break; // DEC (absolute, X) + case 0xdf: absoluteXAddress(); fixupRead(); DCP(); break; // *DCP (absolute, X) - case 0xe0: AM_Immediate(); cmp(X()); break; // CPX (immediate) - case 0xe1: AM_IndexedIndirectX(); sbc(); break; // SBC (indexed indirect X) - case 0xe2: AM_Immediate(); break; // *NOP (immediate) - case 0xe3: AM_IndexedIndirectX(); isb(); break; // *ISB (indexed indirect X) - case 0xe4: AM_ZeroPage(); cmp(X()); break; // CPX (zero page) - case 0xe5: AM_ZeroPage(); sbc(); break; // SBC (zero page) - case 0xe6: AM_ZeroPage(); MW(inc); break; // INC (zero page) - case 0xe7: AM_ZeroPage(); isb(); break; // *ISB (zero page) - case 0xe8: swallow(); X() = inc(X()); break; // INX (implied) - case 0xe9: AM_Immediate(); sbc(); break; // SBC (immediate) - case 0xea: swallow(); break; // NOP (implied) - case 0xeb: AM_Immediate(); sbc(); break; // *SBC (immediate) - case 0xec: AM_Absolute(); cmp(X()); break; // CPX (absolute) - case 0xed: AM_Absolute(); sbc(); break; // SBC (absolute) - case 0xee: AM_Absolute(); MW(inc); break; // INC (absolute) - case 0xef: AM_Absolute(); isb(); break; // *ISB (absolute) + case 0xe0: immediate(); CPX(); break; // CPX (immediate) + case 0xe1: indexedIndirectX(); SBC(); break; // SBC (indexed indirect X) + case 0xe2: immediate(); NOP(); break; // *NOP (immediate) + case 0xe3: indexedIndirectX(); ISB(); break; // *ISB (indexed indirect X) + case 0xe4: zeroPage(); CPX(); break; // CPX (zero page) + case 0xe5: zeroPage(); SBC(); break; // SBC (zero page) + case 0xe6: zeroPage(); INC(); break; // INC (zero page) + case 0xe7: zeroPage(); ISB(); break; // *ISB (zero page) + case 0xe8: swallowRead(); INX(); break; // INX (implied) + case 0xe9: immediate(); SBC(); break; // SBC (immediate) + case 0xea: swallowRead(); NOP(); break; // NOP (implied) + case 0xeb: immediate(); SBC(); break; // *SBC (immediate) + case 0xec: absolute(); CPX(); break; // CPX (absolute) + case 0xed: absolute(); SBC(); break; // SBC (absolute) + case 0xee: absolute(); INC(); break; // INC (absolute) + case 0xef: absolute(); ISB(); break; // *ISB (absolute) - case 0xf0: branch(zero()); break; // BEQ (relative) - case 0xf1: AM_IndirectIndexedY(); sbc(); break; // SBC (indirect indexed Y) - case 0xf2: jam(); break; // *JAM - case 0xf3: Address_IndirectIndexedY(); fixupR(); isb(); break; // *ISB (indirect indexed Y) - case 0xf4: AM_ZeroPageX(); break; // *NOP (zero page, X) - case 0xf5: AM_ZeroPageX(); sbc(); break; // SBC (zero page, X) - case 0xf6: AM_ZeroPageX(); MW(inc); break; // INC (zero page, X) - case 0xf7: AM_ZeroPageX(); isb(); break; // *ISB (zero page, X) - case 0xf8: swallow(); set_flag(DF); break; // SED (implied) - case 0xf9: AM_AbsoluteY(); sbc(); break; // SBC (absolute, Y) - case 0xfa: swallow(); break; // *NOP (implied) - case 0xfb: Address_AbsoluteY(); fixupR(); isb(); break; // *ISB (absolute, Y) - case 0xfc: Address_AbsoluteX(); maybe_fixupR(); break; // *NOP (absolute, X) - case 0xfd: AM_AbsoluteX(); sbc(); break; // SBC (absolute, X) - case 0xfe: Address_AbsoluteX(); fixupR(); MW(inc); break; // INC (absolute, X) - case 0xff: Address_AbsoluteX(); fixupR(); isb(); break; // *ISB (absolute, X) + case 0xf0: immediate(); BEQ(); break; // BEQ (relative) + case 0xf1: indirectIndexedY(); SBC(); break; // SBC (indirect indexed Y) + case 0xf2: swallowRead(); JAM(); break; // *JAM + case 0xf3: indirectIndexedYAddress(); fixupRead(); ISB(); break; // *ISB (indirect indexed Y) + case 0xf4: zeroPageX(); NOP(); break; // *NOP (zero page, X) + case 0xf5: zeroPageX(); SBC(); break; // SBC (zero page, X) + case 0xf6: zeroPageX(); INC(); break; // INC (zero page, X) + case 0xf7: zeroPageX(); ISB(); break; // *ISB (zero page, X) + case 0xf8: swallowRead(); SED(); break; // SED (implied) + case 0xf9: absoluteY(); SBC(); break; // SBC (absolute, Y) + case 0xfa: swallowRead(); NOP(); break; // *NOP (implied) + case 0xfb: absoluteYAddress(); fixupRead(); ISB(); break; // *ISB (absolute, Y) + case 0xfc: absoluteXAddress(); maybeFixupRead(); NOP(); break; // *NOP (absolute, X) + case 0xfd: absoluteX(); SBC(); break; // SBC (absolute, X) + case 0xfe: absoluteXAddress(); fixupRead(); INC(); break; // INC (absolute, X) + case 0xff: absoluteXAddress(); fixupRead(); ISB(); break; // *ISB (absolute, X) } } -//// - void EightBit::MOS6502::push(uint8_t value) noexcept { lowerStack(); - memoryWrite(value); + base::memoryWrite(value); } -uint8_t EightBit::MOS6502::pop() noexcept { +void EightBit::MOS6502::pop() noexcept { raiseStack(); - return memoryRead(); + memoryRead(); } void EightBit::MOS6502::dummyPush() noexcept { @@ -387,214 +598,253 @@ void EightBit::MOS6502::dummyPush() noexcept { tick(); // In place of the memory write } -//// +#pragma region Instruction implementations -void EightBit::MOS6502::branch(const int condition) noexcept { - AM_Immediate(); +#pragma region Miscellaneous + +void EightBit::MOS6502::JMP() noexcept { + jump(BUS().ADDRESS()); +} + +#pragma endregion + +#pragma region Load and store + +void EightBit::MOS6502::STA() noexcept { + base::memoryWrite(A()); +} + +void EightBit::MOS6502::STX() noexcept { + base::memoryWrite(X()); +} + +void EightBit::MOS6502::STY() noexcept { + base::memoryWrite(Y()); +} + +#pragma endregion + +#pragma region Branching + +void EightBit::MOS6502::fixupBranch(int8_t relative) noexcept { + noteFixedAddress(PC().joined + relative); + maybeFixup(); +} + +void EightBit::MOS6502::branch(bool condition) noexcept { if (condition) { - const auto relative = int8_t(BUS().DATA()); - swallow(); - const auto address = PC() + relative; - noteFixedAddress(address); - jump(address); - maybe_fixup(); + int8_t relative = BUS().DATA(); + swallowRead(); + fixupBranch(relative); + JMP(); } } -//// - -void EightBit::MOS6502::sbc() noexcept { - - const auto operand = A(); - A() = sub(operand, carry(~P())); - - adjustOverflow_subtract(operand); - adjustNZ(m_intermediate.low); - reset_flag(CF, m_intermediate.high); +void EightBit::MOS6502::branchNot(int condition) noexcept { + branch(condition == 0); } -uint8_t EightBit::MOS6502::sub(const uint8_t operand, const int borrow) noexcept { - return decimal() ? sub_d(operand, borrow) : sub_b(operand, borrow); +void EightBit::MOS6502::branch(int condition) noexcept { + branch(condition != 0); } -uint8_t EightBit::MOS6502::sub_b(const uint8_t operand, const int borrow) noexcept { - const auto data = BUS().DATA(); - m_intermediate.word = operand - data - borrow; - return m_intermediate.low; +void EightBit::MOS6502::BCS() noexcept { + branch(carry()); } -uint8_t EightBit::MOS6502::sub_d(const uint8_t operand, const int borrow) noexcept { - - const auto data = BUS().DATA(); - - m_intermediate.word = operand - data - borrow; - - uint8_t low = lowNibble(operand) - lowNibble(data) - borrow; - const auto lowNegative = negative(low); - if (lowNegative) - low -= 6; - - uint8_t high = highNibble(operand) - highNibble(data) - (lowNegative >> 7); - const auto highNegative = negative(high); - if (highNegative) - high -= 6; - - return promoteNibble(high) | lowNibble(low); +void EightBit::MOS6502::BCC() noexcept { + branchNot(carry()); } -void EightBit::MOS6502::adc() noexcept { - decimal() ? adc_d() : adc_b(); +void EightBit::MOS6502::BVC() noexcept { + branchNot(overflow()); } -void EightBit::MOS6502::adc_b() noexcept { - - const auto operand = A(); - const auto data = BUS().DATA(); - m_intermediate.word = operand + data + carry(); - - adjustOverflow_add(operand); - set_flag(CF, carry(m_intermediate.high)); - - adjustNZ(m_intermediate.low); - - A() = m_intermediate.low; +void EightBit::MOS6502::BMI() noexcept { + branch(negative()); } -void EightBit::MOS6502::adc_d() noexcept { - - const auto operand = A(); - const auto data = BUS().DATA(); - - register16_t low = lowerNibble(operand) + lowerNibble(data) + carry(); - m_intermediate = higherNibble(operand) + higherNibble(data); - auto& high = m_intermediate; - - adjustZero((low + high).low); - - if (low.word > 0x09) { - high += 0x10; - low += 0x06; - } - - adjustNegative(high.low); - adjustOverflow_add(operand); - - if (high.word > 0x90) - high += 0x60; - - set_flag(CF, high.high); - - A() = lowerNibble(low.low) | higherNibble(high.low); +void EightBit::MOS6502::BPL() noexcept { + branchNot(negative()); } -void EightBit::MOS6502::andr() noexcept { - A() = through(A() & BUS().DATA()); +void EightBit::MOS6502::BVS() noexcept { + branch(overflow()); } -void EightBit::MOS6502::bit() noexcept { - const auto data = BUS().DATA(); - set_flag(VF, overflow(data)); - adjustZero(A() & data); - adjustNegative(data); +void EightBit::MOS6502::BEQ() noexcept { + branch(zero()); +} +void EightBit::MOS6502::BNE() noexcept { + branchNot(zero()); } -void EightBit::MOS6502::cmp(const uint8_t first) noexcept { - const auto second = BUS().DATA(); - const register16_t result = first - second; - adjustNZ(result.low); - reset_flag(CF, result.high); +#pragma endregion + +#pragma region Increment/decrement + +void EightBit::MOS6502::DEC() { + modifyWrite(DEC(BUS().DATA())); } -uint8_t EightBit::MOS6502::dec(const uint8_t value) noexcept { - return through(value - 1); +void EightBit::MOS6502::INC() { + modifyWrite(INC(BUS().DATA())); } -void EightBit::MOS6502::eorr() noexcept { - A() = through(A() ^ BUS().DATA()); +#pragma endregion + +#pragma region Stack operations + +void EightBit::MOS6502::JSR() { + fetchByte(); + auto low = BUS().DATA(); + swallowPop(); + pushShort(PC()); + fetchByte(); + auto high = BUS().DATA(); + PC() = { low, high }; } -uint8_t EightBit::MOS6502::inc(const uint8_t value) noexcept { - return through(value + 1); +void EightBit::MOS6502::PHA() { + push(A()); } -void EightBit::MOS6502::jsr() noexcept { - const auto low = fetchByte(); - swallow_stack(); - pushWord(PC()); - PC() = { low, fetchByte() }; +void EightBit::MOS6502::PLA() { + swallowPop(); + pop(); + LDA(); } -void EightBit::MOS6502::orr() noexcept { - A() = through(A() | BUS().DATA()); +void EightBit::MOS6502::PHP() { + push(setBit(P(), BF)); } -void EightBit::MOS6502::php() noexcept { - push(P() | BF); +void EightBit::MOS6502::PLP() { + swallowPop(); + pop(); + P() = clearBit(setBit(BUS().DATA(), RF), BF); } -void EightBit::MOS6502::plp() noexcept { - swallow_stack(); - P() = (pop() | RF) & ~BF; +void EightBit::MOS6502::RTI() { + PLP(); + base::ret(); } -void EightBit::MOS6502::rti() noexcept { - plp(); - ret(); +void EightBit::MOS6502::RTS() { + swallowPop(); + base::ret(); + swallowFetch(); } -void EightBit::MOS6502::rts() noexcept { - swallow_stack(); - ret(); - swallow_fetch(); +#pragma endregion + +#pragma region Shift/rotate operations + +#pragma region Shift + +void EightBit::MOS6502::ASL() { + modifyWrite(ASL(BUS().DATA())); } -// Undocumented compound instructions - -void EightBit::MOS6502::anc() noexcept { - andr(); - set_flag(CF, A() & NF); +void EightBit::MOS6502::LSR() { + modifyWrite(LSR(BUS().DATA())); } -void EightBit::MOS6502::arr() noexcept { - const auto value = BUS().DATA(); - decimal() ? arr_d(value) : arr_b(value); +#pragma endregion + +#pragma region Rotate + +void EightBit::MOS6502::ROL() { + modifyWrite(ROL(BUS().DATA())); } -void EightBit::MOS6502::arr_d(const uint8_t value) noexcept { +void EightBit::MOS6502::ROR() { + modifyWrite(ROR(BUS().DATA())); +} +#pragma endregion + +#pragma endregion + +#pragma region Undocumented instructions + +#pragma region Undocumented instructions with BCD effects + +void EightBit::MOS6502::ARR() { + denary() != 0 ? decimalARR() : binaryARR(); +} + +uint8_t EightBit::MOS6502::coreARR() { + A() &= BUS().DATA(); + const auto unshiftedA = A(); + RORA(); + setFlag(VF, overflowTest((A() ^ A() << 1))); + return unshiftedA; +} + +void EightBit::MOS6502::decimalARR() { // 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)); - set_flag(VF, overflow((A() ^ (A() << 1)))); - + const auto unshiftedA = coreARR(); if (lowerNibble(unshiftedA) + (unshiftedA & 0x1) > 5) - A() = lowerNibble(A() + 6) | higherNibble(A()); - - set_flag(CF, higherNibble(unshiftedA) + (unshiftedA & 0x10) > 0x50); - - if (carry()) + A() = lowerNibble((A() + 6)) | higherNibble(A()); + setFlag(CF, higherNibble(unshiftedA) + (unshiftedA & 0x10) > 0x50); + if (carry() != 0) A() += 0x60; } -void EightBit::MOS6502::arr_b(const uint8_t value) noexcept { - A() &= value; - A() = through((A() >> 1) | (carry() << 7)); - set_flag(CF, A() & VF); - set_flag(VF, overflow((A() ^ (A() << 1)))); +void EightBit::MOS6502::binaryARR() { + coreARR(); + setFlag(CF, overflowTest(A())); } -void EightBit::MOS6502::axs() noexcept { - X() = through(sub_b(A() & X())); - reset_flag(CF, m_intermediate.high); +#pragma endregion + +#pragma region Undocumented instructions with fixup effects + +void EightBit::MOS6502::storeFixupEffect(uint8_t data) { + const uint8_t mask = unfixedPage() + 1; // base_hi + 1, always + const uint8_t updated = data & mask; + if (fixed()) + BUS().ADDRESS().high = updated; + base::memoryWrite(updated); } -void EightBit::MOS6502::jam() noexcept { - BUS().ADDRESS() = PC(); - memoryRead(); - memoryRead(0xffff); +void EightBit::MOS6502::SHA() { + storeFixupEffect(A() & X()); +} + +void EightBit::MOS6502::SYA() { + storeFixupEffect(Y()); +} + +void EightBit::MOS6502::SXA() { + storeFixupEffect(X()); +} + +#pragma endregion + +void EightBit::MOS6502::SAX() { + base::memoryWrite(A() & X()); +} + +void EightBit::MOS6502::LAX() { + LDA(); + LDX(); +} + +void EightBit::MOS6502::ANC() { + AND(); + setFlag(CF, negativeTest(A())); +} + +void EightBit::MOS6502::AXS() { + X() = through(binarySUB(A() & X())); + resetFlag(CF, intermediate().high); +} + +void EightBit::MOS6502::JAM() { + base::memoryRead(0xff, 0xff); BUS().ADDRESS().low = 0xfe; memoryRead(); memoryRead(); @@ -606,3 +856,59 @@ void EightBit::MOS6502::jam() noexcept { memoryRead(); memoryRead(); } + +void EightBit::MOS6502::TAS() { + S() = A() & X(); + SHA(); +} + +void EightBit::MOS6502::LAS() { + A() = X() = S() = through(BUS().DATA() & S()); +} + +void EightBit::MOS6502::ANE() { + A() = through((A() | 0xee) & X() & BUS().DATA()); +} + +void EightBit::MOS6502::ATX() { + A() = X() = through((A() | 0xee) & BUS().DATA()); +} + +void EightBit::MOS6502::ASR() { + AND(); + LSRA(); +} + +void EightBit::MOS6502::ISB() { + INC(); + SBC(); +} + +void EightBit::MOS6502::RLA() { + ROL(); + AND(); +} + +void EightBit::MOS6502::RRA() { + ROR(); + ADC(); +} + +void EightBit::MOS6502::SLO() { + ASL(); + ORA(); +} + +void EightBit::MOS6502::SRE() { + LSR(); + EOR(); +} + +void EightBit::MOS6502::DCP() { + DEC(); + CMP(); +} + +#pragma endregion + +#pragma endregion diff --git a/M6502/test/Board.cpp b/M6502/test/Board.cpp index 7180d27..bb18259 100644 --- a/M6502/test/Board.cpp +++ b/M6502/test/Board.cpp @@ -30,7 +30,7 @@ void Board::initialise() noexcept { auto programFilename = m_configuration.getProgram(); auto programPath = m_configuration.getRomDirectory() + "/" + m_configuration.getProgram(); auto loadAddress = m_configuration.getLoadAddress(); - m_ram.load(programPath, loadAddress.word); + m_ram.load(programPath, loadAddress.joined); // Disassembly output if (m_configuration.isDebugMode()) @@ -47,7 +47,7 @@ void Board::initialise() noexcept { std::cout << "Y=" << (int)CPU().Y() << ", "; std::cout << "S=" << (int)CPU().S() << "\t"; - std::cout << m_disassembler.disassemble(address.word); + std::cout << m_disassembler.disassemble(address.joined); std::cout << "\n"; }); diff --git a/inc/Processor.h b/inc/Processor.h index 2f8b566..450d314 100644 --- a/inc/Processor.h +++ b/inc/Processor.h @@ -66,6 +66,11 @@ namespace EightBit { virtual void memoryWrite() noexcept; void busWrite() noexcept; + void memoryRead(uint8_t low, uint8_t high) noexcept { + BUS().ADDRESS() = { low, high }; + memoryRead(); + } + void memoryRead(register16_t address) noexcept; virtual void memoryRead() noexcept; void busRead() noexcept;