feat(cpu): add LR35902 register state and opcode dispatch core
This commit is contained in:
1 parent
29fa059223
commit
637664740c
2 files changed
+217
No files matched your search
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user