#pragma once #include #include namespace natsukashii::gb::core { #define REGIMPL(type1, reg1, type2, reg2) \ struct reg##reg1##reg2 { \ reg##reg1##reg2() {} \ union { \ type1 reg1; \ type2 reg2; \ }; \ u16 raw = 0; \ } reg1##reg2 struct RegF { RegF() : raw(0) {} RegF(const u8& val) : raw(val) {} RegF& operator=(const u8& rhs) { raw |= ((rhs >> 7) << 7); raw |= ((rhs >> 6) << 6); raw |= ((rhs >> 5) << 5); raw |= ((rhs >> 4) << 4); return *this; } bool zero() { return (raw >> 7) & 1; } bool negative() { return (raw >> 6) & 1; } bool halfcarry() { return (raw >> 5) & 1; } bool carry() { return (raw >> 4) & 1; } void reset() { zero(false); negative(false); halfcarry(false); carry(false); } void set(bool z, bool n, bool hc, bool ca) { zero(z); negative(n); halfcarry(hc); carry(ca); } u8& get() { return raw; } private: u8 raw = 0; void zero(const bool& rhs) { raw &= ~0xF; raw |= (rhs << 7); } void negative(const bool& rhs) { raw &= ~0xF; raw |= (rhs << 6); } void halfcarry(const bool& rhs) { raw &= ~0xF; raw |= (rhs << 5); } void carry(const bool& rhs) { raw &= ~0xF; raw |= (rhs << 4); } }; struct Registers { REGIMPL(u8, A, RegF, F); REGIMPL(u8, B, u8, C); REGIMPL(u8, D, u8, E); REGIMPL(u8, H, u8, L); u16 pc = 0, sp = 0; u8& a() { return AF.A; } RegF& f() { return AF.F; } u8& b() { return BC.B; } u8& c() { return BC.C; } u8& d() { return DE.D; } u8& e() { return DE.E; } u8& h() { return HL.H; } u8& l() { return HL.L; } u16& af() { return AF.raw; } u16& bc() { return BC.raw; } u16& de() { return DE.raw; } u16& hl() { return HL.raw; } }; struct Cpu { Cpu(); void Step(Mem&); private: void FetchDecodeExecute(Mem& mem); Registers regs; template u16 GetR16(u8 bits) { static_assert(group > 0 && group < 3, "Invalid GetR16 group"); if constexpr (group == 1) { switch(bits & 3) { case 0: return regs.bc(); case 1: return regs.de(); case 2: return regs.hl(); case 3: return regs.sp; } } else if constexpr (group == 2) { switch(bits & 3) { case 0: return regs.bc(); case 1: return regs.de(); case 2: return regs.hl()++; case 3: return regs.hl()--; } } else if constexpr (group == 3) { switch(bits & 3) { case 0: return regs.bc(); case 1: return regs.de(); case 2: return regs.hl(); case 3: return regs.af(); } } } template void SetR16(u8 bits, u16 val) { static_assert(group > 0 && group < 3, "Invalid SetR16 group"); if constexpr (group == 1) { switch(bits & 3) { case 0: regs.bc() = val; break; case 1: regs.de() = val; break; case 2: regs.hl() = val; break; case 3: regs.sp = val; break; } } else if constexpr (group == 2) { switch(bits & 3) { case 0: regs.bc() = val; break; case 1: regs.de() = val; break; case 2: regs.hl() = val; regs.hl()++; break; case 3: regs.hl() = val; regs.hl()--; break; } } else if constexpr (group == 3) { switch(bits & 3) { case 0: regs.bc() = val; break; case 1: regs.de() = val; break; case 2: regs.hl() = val; break; case 3: regs.af() = val; break; } } } u8 GetR8(u8 bits, Mem& mem) { switch(bits & 7) { case 0: return regs.b(); case 1: return regs.c(); case 2: return regs.d(); case 3: return regs.e(); case 4: return regs.h(); case 5: return regs.l(); case 6: return mem.Read8(regs.hl()); case 7: return regs.a(); } return 0; } void SetR8(u8 bits, u8 val, Mem& mem) { switch(bits & 7) { case 0: regs.b() = val; break; case 1: regs.c() = val; break; case 2: regs.d() = val; break; case 3: regs.e() = val; break; case 4: regs.h() = val; break; case 5: regs.l() = val; break; case 6: return mem.Write8(regs.hl(), val); case 7: regs.a() = val; break; } } }; }