import ; import ; import ; using Byte = unsigned char; using Word = uint16_t; struct Mem { static constexpr uint32_t MAX_MEM = 1024 * 64; Byte Data[MAX_MEM]; auto Initialise() -> void { for (uint32_t i{}; i < MAX_MEM; ++i) { Data[i] = 0; } } // Read 1 byte auto operator[](uint32_t Address) const -> Byte { return Data[Address]; } auto operator[](uint32_t Address) -> Byte { return Data[Address]; } // write 2 bytes auto WriteWord(Word Value, uint32_t Address, uint32_t &Cycles) -> void { Data[Address] = Value & 0xFF; Data[Address + 1] = (Value >> 8); Cycles -= 2; } }; struct CPU { Word PC{}; // Program counter Word SP{}; // Stack pointer Byte A{}, X{}, Y{}; // registers // Status flags Byte C : 1; Byte Z : 1; Byte I : 1; Byte D : 1; Byte B : 1; Byte V : 1; Byte N : 1; auto Reset(Mem &mem) -> void { PC = 0xFFFC; SP = 0x0100; C = 0; Z = 0; I = 0; D = 0; B = 0; V = 0; N = 0; A = 0; X = 0; Y = 0; mem.Initialise(); } auto FetchByte(uint32_t &Cycles, Mem &mem) -> Byte { Byte Data{mem[PC]}; ++PC; --Cycles; return Data; } auto FetchWord(uint32_t &Cycles, Mem &mem) -> Word { // 6502 is little endian Word Data{mem[PC]}; ++PC; Data |= (mem[PC] << 8); ++PC; Cycles += 2; return Data; } auto ReadByte(uint32_t &Cycles, Byte Address, Mem &mem) -> Byte { Byte Data{mem[Address]}; --Cycles; return Data; } // opcodes static constexpr Byte INS_LDA_IM{0xA9}, INS_LDA_ZP{0xA5}, INS_LDA_ZPX{0xB5}, INS_JSR{0x20}; auto LDASetStatus() -> void { Z = (A == 0); N = (A & 0b10'000'000) > 0; } auto Execute(uint32_t Cycles, Mem &mem) -> void { while (Cycles > 0) { Byte Ins{FetchByte(Cycles, mem)}; switch (Ins) { case INS_LDA_IM: { Byte Value{FetchByte(Cycles, mem)}; A = Value; LDASetStatus(); break; } case INS_LDA_ZP: { Byte ZeroPageAddress{FetchByte(Cycles, mem)}; A = ReadByte(Cycles, ZeroPageAddress, mem); LDASetStatus(); break; } case INS_LDA_ZPX: { Byte ZeroPageAddress{FetchByte(Cycles, mem)}; ZeroPageAddress += X; --Cycles; A = ReadByte(Cycles, ZeroPageAddress, mem); LDASetStatus(); break; } case INS_JSR: { Word SubAddr{FetchWord(Cycles, mem)}; mem[SP] = PC - 1; mem.WriteWord(PC - 1, SP, Cycles); PC = SubAddr; --Cycles; break; } default: { printf("Instruction not handled %d", Ins); } } } } }; int main() { Mem mem{}; CPU cpu{}; cpu.Reset(mem); cpu.Execute(2, mem); return 0; }