#pragma once #include #include const unsigned int INSTRUCTION_COUNT = 256; const unsigned int RAM_SIZE = 2048; const unsigned int SRAM_SIZE = 8192; const unsigned int IRQ_VECTOR_MSB = 0xFFFF; const unsigned int IRQ_VECTOR_LSB = 0xFFFE; class NES; class Status { friend class NES; public: void SetByte(uint8_t byte) { negative = (byte & 0x80u) >> 7u; overflow = (byte & 0x40u) >> 6u; b1 = (byte & 0x20u) >> 5u; b0 = (byte & 0x10u) >> 4u; decimal = (byte & 0x08u) >> 3u; interruptDisable = (byte & 0x04u) >> 2u; zero = (byte & 0x02u) >> 1u; carry = (byte & 0x01u); } uint8_t GetByte() { return negative << 7u | overflow << 6u | b1 << 5u | b0 << 4u | decimal << 3u | interruptDisable << 2u | zero << 1u | carry; } uint8_t carry; uint8_t zero; uint8_t interruptDisable; uint8_t decimal; uint8_t b0; uint8_t b1; uint8_t overflow; uint8_t negative; }; class CPU; class Instruction { public: char const* name; uint8_t cycles; using CpuFunc = void (CPU::*)(); CpuFunc fetch; CpuFunc execute; }; class CPU { public: CPU(); uint64_t Cycle(); void Log(); void Reset(); void NMI(); void WriteMemory(uint16_t address, uint8_t value); uint8_t ReadMemory(uint16_t address); friend class NES; void StackPush(uint8_t val); uint8_t StackPop(); // --------------- HELPERS --------------- // static bool TestBits(uint8_t value, uint8_t bits); static bool IsNegative(uint8_t value); static bool IsPageBoundaryCrossed(uint16_t before, uint16_t after); static uint16_t ComposeAddress(uint8_t msb, uint8_t lsb); // --------------- ADDRESS MODES --------------- // // Operand is implied by the instruction void Implicit(); // Operand is the byte/STA void Immediate(); // Operand contains a zero-page address (0x00 to 0xFF) // Byte is retrieved from that address in memory void ZeroPage(); // Operand is added to X to get effective address, with wrap around back to 0x00 void ZeroPageX(); // Operand is added to X to get effective address, with wrap around back to 0x00 void ZeroPageY(); // Operand is the memory location void Absolute(); // Operand contains an absolute address which can be added to X to get a new address // If the address after adding X crosses a page-boundary, an additional cycle occurs void AbsoluteX(); // Operand contains an absolute address which can be added to Y to get a new address // If the address after adding Y crosses a page-boundary, an additional cycle occurs void AbsoluteY(); // Operand contains address of LSB of effective address - MSB is in address + 1 void Indirect(); // Operand contains a zero-page address (0x00 to 0xFF) // Value in X is added to operand to retrieve two bytes of address in memory (addition will wrap around back to 0x00) // Effective address is used to retrieve the byte void IndirectX(); // Operand contains a zero-page address (0x00 to 0xFF) // Two bytes of address are retrieved from that address in memory // Y is added to that address and the new address is used to retrieve the byte // If the addition of Y causes a page-boundary crossing, an additional cycle occurs void IndirectY(); // Operand is an offset from current instruction used for branching void Relative(); // --------------- LOGICAL --------------- // void AND(); void EOR(); void ORA(); void BIT(); // --------------- ARITHMETIC --------------- // void ADC(); void SBC(); void CMP(); void CPX(); void CPY(); // --------------- LOAD/STORE --------------- // void STA(); void STX(); void STY(); void LDA(); void LDX(); void LDY(); // --------------- TRANSFERS --------------- // void TXA(); void TYA(); void TXS(); void TAX(); void TAY(); void TSX(); // --------------- STACK --------------- // void PHP(); void PLP(); void PHA(); void PLA(); // --------------- INCREMENTS & DECREMENTS --------------- // void INC(); void INX(); void INY(); void DEC(); void DEX(); void DEY(); // --------------- SHIFTS --------------- // void ASL(); void LSR(); void ROL(); void ROR(); // --------------- JUMPS & CALLS --------------- // void JMP(); void JSR(); void RTS(); // --------------- STATUS FLAG CHANGES --------------- // void CLC(); void SEC(); void CLI(); void SEI(); void CLV(); void CLD(); void SED(); // --------------- BRANCHES --------------- // void BPL(); void BMI(); void BVC(); void BVS(); void BCC(); void BCS(); void BNE(); void BEQ(); // --------------- SYSTEM --------------- // void BRK(); void NOP(); void RTI(); // --------------- UNOFFICIAL --------------- // void LAX(); void SAX(); void DCP(); void ISC(); void SLO(); void RLA(); void SRE(); void RRA(); void ANC(); void ALR(); void ARR(); void AXS(); // Machine features uint8_t ram[RAM_SIZE]{}; uint8_t sram[SRAM_SIZE]{}; uint16_t pc{}; uint8_t sp{}; uint8_t acc{}; uint8_t x{}; uint8_t y{}; Status status{}; uint64_t prevCycles{}; uint64_t cycles{}; bool irq{}; // Emulator variables bool pageBoundaryCrossed{}; uint8_t opcode{}; uint16_t fetchedAddress{}; uint8_t fetchedByte{}; Instruction instructions[INSTRUCTION_COUNT]{}; NES* nes; };