#pragma once #include #include #include #include #include #include #include #include namespace EightBit { class MOS6502 : public Processor { public: enum StatusBits { NF = Bit7, // Negative VF = Bit6, // Overflow RF = Bit5, // reserved BF = Bit4, // Brk DF = Bit3, // D (use BCD for arithmetic) IF = Bit2, // I (IRQ disable) ZF = Bit1, // Zero CF = Bit0, // Carry }; MOS6502(Bus& bus); Signal ExecutingInstruction; Signal ExecutedInstruction; virtual int execute(uint8_t opcode) final; virtual int step() final; virtual void powerOn() override; uint8_t X() const { return x; } uint8_t& X() { return x; } uint8_t Y() const { return y; } uint8_t& Y() { return y; } uint8_t A() const { return a; } uint8_t& A() { return a; } uint8_t S() const { return s; } uint8_t& S() { return s; } uint8_t P() const { return p; } uint8_t& P() { return p; } PinLevel SO() const { return m_soLine; } // In PinLevel& SO() { return m_soLine; } // In protected: virtual void reset() final; virtual uint8_t SUB(uint8_t operand, uint8_t data, int borrow = 0); uint8_t SBC(uint8_t operand, uint8_t data); uint8_t SUB_b(uint8_t operand, uint8_t data, int borrow); uint8_t SUB_d(uint8_t operand, uint8_t data, int borrow); virtual uint8_t ADD(uint8_t operand, uint8_t data, int carry = 0); uint8_t ADC(uint8_t operand, uint8_t data); uint8_t ADD_b(uint8_t operand, uint8_t data, int carry); uint8_t ADD_d(uint8_t operand, uint8_t data, int carry); private: void interrupt(uint8_t vector); void adjustZero(uint8_t datum) { clearFlag(P(), ZF, datum); } void adjustNegative(uint8_t datum) { setFlag(P(), NF, datum & NF); } void adjustNZ(uint8_t datum) { adjustZero(datum); adjustNegative(datum); } register16_t getWordPaged(uint8_t page, uint8_t offset); uint8_t getBytePaged(uint8_t page, uint8_t offset); void setBytePaged(uint8_t page, uint8_t offset, uint8_t value); virtual void push(uint8_t value) final; virtual uint8_t pop() final; // Address resolution register16_t Address_Absolute() { return fetchWord(); } uint8_t Address_ZeroPage() { return fetchByte(); } register16_t Address_ZeroPageIndirect() { return getWordPaged(0, Address_ZeroPage()); } register16_t Address_Indirect() { const auto address = Address_Absolute(); return getWordPaged(address.high, address.low); } uint8_t Address_ZeroPageX() { return Address_ZeroPage() + X(); } uint8_t Address_ZeroPageY() { return Address_ZeroPage() + Y(); } std::tuple Address_AbsoluteX() { auto address = Address_Absolute(); const auto page = address.high; address.word += X(); return std::tuple(address, address.high != page); } std::tuple Address_AbsoluteY() { auto address = Address_Absolute(); const auto page = address.high; address.word += Y(); return std::tuple(address, address.high != page); } register16_t Address_IndexedIndirectX() { return getWordPaged(0, Address_ZeroPageX()); } std::tuple Address_IndirectIndexedY() { auto address = Address_ZeroPageIndirect(); const auto page = address.high; address.word += Y(); return std::tuple(address, address.high != page); } // Addressing modes, read uint8_t AM_Immediate() { return fetchByte(); } uint8_t AM_Absolute() { return BUS().read(Address_Absolute()); } uint8_t AM_ZeroPage() { return BUS().read(Address_ZeroPage()); } uint8_t AM_AbsoluteX() { const auto ap = Address_AbsoluteX(); if (UNLIKELY(std::get<1>(ap))) addCycle(); return BUS().read(std::get<0>(ap)); } uint8_t AM_AbsoluteY() { const auto ap = Address_AbsoluteY(); if (UNLIKELY(std::get<1>(ap))) addCycle(); return BUS().read(std::get<0>(ap)); } uint8_t AM_ZeroPageX() { return BUS().read(Address_ZeroPageX()); } uint8_t AM_ZeroPageY() { return BUS().read(Address_ZeroPageY()); } uint8_t AM_IndexedIndirectX() { return BUS().read(Address_IndexedIndirectX()); } uint8_t AM_IndirectIndexedY() { const auto ap = Address_IndirectIndexedY(); if (UNLIKELY(std::get<1>(ap))) addCycle(); return BUS().read(std::get<0>(ap)); } // Addressing modes, write void AM_Absolute(uint8_t value) { BUS().write(Address_Absolute(), value); } void AM_ZeroPage(uint8_t value) { BUS().write(Address_ZeroPage(), value); } void AM_AbsoluteX(uint8_t value) { BUS().write(std::get<0>(Address_AbsoluteX()), value); } void AM_AbsoluteY(uint8_t value) { BUS().write(std::get<0>(Address_AbsoluteY()), value); } void AM_ZeroPageX(uint8_t value) { BUS().write(Address_ZeroPageX(), value); } void AM_ZeroPageY(uint8_t value) { BUS().write(Address_ZeroPageY(), value); } void AM_IndexedIndirectX(uint8_t value) { BUS().write(Address_IndexedIndirectX(), value); } void AM_IndirectIndexedY(uint8_t value) { BUS().write(std::get<0>(Address_IndirectIndexedY()), value); } // Operations void DCP(uint8_t value) { BUS().write(--value); CMP(A(), value); } void ISB(uint8_t value) { BUS().write(++value); A() = SBC(A(), value); } void SLO(uint8_t value) { const auto result = ASL(value); BUS().write(result); ORA(result); } void SRE(uint8_t value) { const auto result = LSR(value); BUS().write(result); EORA(result); } void RLA(uint8_t value) { const auto result = ROL(value); BUS().write(result); ANDA(result); } void RRA(uint8_t value) { const auto result = ROR(value); BUS().write(result); A() = ADC(A(), result); } void LAX(uint8_t value) { adjustNZ(X() = A() = value); } void AAC(uint8_t value) { ANDA(value); setFlag(P(), CF, A() & Bit7); } void ASR(uint8_t value) { A() = LSR(A() & value); } void ARR(uint8_t value) { } void ATX(uint8_t value) { ANDA(value); X() = A(); } void AXS(uint8_t value) { } // uint8_t DEC(uint8_t value) { const auto result = --value; adjustNZ(result); return result; } uint8_t INC(uint8_t value) { const auto result = ++value; adjustNZ(result); return result; } void ORA(uint8_t value) { adjustNZ(A() |= value); } void ANDA(uint8_t value) { adjustNZ(A() &= value); } void EORA(uint8_t value) { adjustNZ(A() ^= value); } uint8_t ROR(uint8_t value); uint8_t LSR(uint8_t value); void BIT(uint8_t data); uint8_t ROL(uint8_t value); uint8_t ASL(uint8_t value); void CMP(uint8_t first, uint8_t second); void Branch(int8_t displacement); void Branch(bool flag); void PHP(); void PLP(); void JSR_abs(); void RTI(); void RTS(); void JMP_abs(); void JMP_ind(); void BRK(); // All interrupt vectors are on the 0xFF page const uint8_t IRQvector = 0xfe; const uint8_t RSTvector = 0xfc; const uint8_t NMIvector = 0xfa; uint8_t x = 0; // index register X uint8_t y = 0; // index register Y uint8_t a = 0; // accumulator uint8_t s = 0; // stack pointer uint8_t p = 0; // processor status PinLevel m_soLine = Low; register16_t m_intermediate; }; }