feat(cpu): add LR35902 register state and opcode dispatch core

This commit is contained in:
dualfroz committed 2026-08-23 15:16:19 +02:00
1 parent 29fa059223
commit 637664740c
2 files changed
+217

No files matched your search

+25
View File
@@ -0,0 +1,25 @@
using System.IO;
namespace GameBoy.Cpu
{
public sealed partial class Cpu
{
public void SaveState(BinaryWriter writer)
{
writer.Write(A); writer.Write(B); writer.Write(C); writer.Write(D);
writer.Write(E); writer.Write(H); writer.Write(L); writer.Write(F);
writer.Write(SP); writer.Write(PC);
writer.Write(Ime); writer.Write(Halted); writer.Write(Stopped);
writer.Write(imeScheduled); writer.Write(haltBug);
}
public void LoadState(BinaryReader reader)
{
A = reader.ReadByte(); B = reader.ReadByte(); C = reader.ReadByte(); D = reader.ReadByte();
E = reader.ReadByte(); H = reader.ReadByte(); L = reader.ReadByte(); F = reader.ReadByte();
SP = reader.ReadUInt16(); PC = reader.ReadUInt16();
Ime = reader.ReadBoolean(); Halted = reader.ReadBoolean(); Stopped = reader.ReadBoolean();
imeScheduled = reader.ReadBoolean(); haltBug = reader.ReadBoolean();
}
}
}
+192
View File
@@ -0,0 +1,192 @@
namespace GameBoy.Cpu
{
public sealed partial class Cpu
{
public const byte FlagZ = 0x80;
public const byte FlagN = 0x40;
public const byte FlagH = 0x20;
public const byte FlagC = 0x10;
public byte A, B, C, D, E, H, L, F;
public ushort SP;
public ushort PC;
public bool Ime;
public bool Halted;
public bool Stopped;
private bool imeScheduled;
private bool haltBug;
private readonly ISystemBus bus;
private readonly InterruptController interrupts;
public Cpu(ISystemBus bus)
{
this.bus = bus;
this.interrupts = bus.Interrupts;
}
public void ResetPostBoot()
{
A = 0x01; F = 0xB0;
B = 0x00; C = 0x13;
D = 0x00; E = 0xD8;
H = 0x01; L = 0x4D;
SP = 0xFFFE;
PC = 0x0100;
Ime = false;
Halted = false;
Stopped = false;
imeScheduled = false;
haltBug = false;
}
public ushort AF
{
get => (ushort)((A << 8) | F);
set { A = (byte)(value >> 8); F = (byte)(value & 0xF0); }
}
public ushort BC
{
get => (ushort)((B << 8) | C);
set { B = (byte)(value >> 8); C = (byte)(value & 0xFF); }
}
public ushort DE
{
get => (ushort)((D << 8) | E);
set { D = (byte)(value >> 8); E = (byte)(value & 0xFF); }
}
public ushort HL
{
get => (ushort)((H << 8) | L);
set { H = (byte)(value >> 8); L = (byte)(value & 0xFF); }
}
private bool FlagSet(byte flag) => (F & flag) != 0;
private void SetFlag(byte flag, bool on)
{
if (on) F |= flag;
else F = (byte)(F & ~flag);
}
private void SetFlags(bool z, bool n, bool h, bool c)
{
F = 0;
if (z) F |= FlagZ;
if (n) F |= FlagN;
if (h) F |= FlagH;
if (c) F |= FlagC;
}
public void Step()
{
if (HandleInterrupts())
return;
if (Halted)
{
bus.Tick4();
return;
}
bool enableImeAfter = imeScheduled;
byte opcode = Fetch8();
Execute(opcode);
if (enableImeAfter)
{
Ime = true;
imeScheduled = false;
}
}
private bool HandleInterrupts()
{
byte pending = interrupts.Pending;
if (pending != 0 && Halted)
Halted = false;
if (pending == 0 || !Ime)
return false;
Ime = false;
imeScheduled = false;
bus.Tick4();
bus.Tick4();
SP--;
bus.Write(SP, (byte)(PC >> 8));
SP--;
bus.Write(SP, (byte)(PC & 0xFF));
byte live = interrupts.Pending;
ushort vector = 0x0000;
if (live != 0)
{
int bit = LowestSetBit(live);
vector = (ushort)(0x40 + bit * 8);
interrupts.Flag = (byte)(interrupts.Flag & ~(1 << bit));
}
bus.Tick4();
PC = vector;
return true;
}
private static int LowestSetBit(byte value)
{
for (int bit = 0; bit < 5; bit++)
if ((value & (1 << bit)) != 0)
return bit;
return 0;
}
private byte Fetch8()
{
byte value = bus.Read(PC);
if (haltBug)
haltBug = false;
else
PC++;
return value;
}
private ushort Fetch16()
{
byte lo = Fetch8();
byte hi = Fetch8();
return (ushort)((hi << 8) | lo);
}
private byte Read8(ushort address) => bus.Read(address);
private void Write8(ushort address, byte value) => bus.Write(address, value);
private void InternalCycle() => bus.Tick4();
private void Push16(ushort value)
{
SP--;
Write8(SP, (byte)(value >> 8));
SP--;
Write8(SP, (byte)(value & 0xFF));
}
private ushort Pop16()
{
byte lo = Read8(SP);
SP++;
byte hi = Read8(SP);
SP++;
return (ushort)((hi << 8) | lo);
}
}
}