309 lines
8.2 KiB
C#
309 lines
8.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace MCEmuCore.GBMonolith
|
|
{
|
|
class CpuRegisters
|
|
{
|
|
enum Register { A, B, C, D, E, H, L };
|
|
private readonly byte[] Registers = new byte[7];
|
|
public readonly FlagRegister Flags = new FlagRegister();
|
|
|
|
#region Register Accessors
|
|
public byte A
|
|
{
|
|
get
|
|
{
|
|
return Registers[(int)Register.A];
|
|
}
|
|
set
|
|
{
|
|
Registers[(int)Register.A] = value;
|
|
}
|
|
}
|
|
public byte B
|
|
{
|
|
get
|
|
{
|
|
return Registers[(int)Register.B];
|
|
}
|
|
set
|
|
{
|
|
Registers[(int)Register.B] = value;
|
|
}
|
|
}
|
|
public byte D
|
|
{
|
|
get
|
|
{
|
|
return Registers[(int)Register.D];
|
|
}
|
|
set
|
|
{
|
|
Registers[(int)Register.D] = value;
|
|
}
|
|
}
|
|
public byte H
|
|
{
|
|
get
|
|
{
|
|
return Registers[(int)Register.H];
|
|
}
|
|
set
|
|
{
|
|
Registers[(int)Register.H] = value;
|
|
}
|
|
}
|
|
public byte F
|
|
{
|
|
get
|
|
{
|
|
return Flags.Value;
|
|
}
|
|
set
|
|
{
|
|
Flags.Value = value;
|
|
}
|
|
}
|
|
public byte C
|
|
{
|
|
get
|
|
{
|
|
return Registers[(int)Register.C];
|
|
}
|
|
set
|
|
{
|
|
Registers[(int)Register.C] = value;
|
|
}
|
|
}
|
|
public byte E
|
|
{
|
|
get
|
|
{
|
|
return Registers[(int)Register.E];
|
|
}
|
|
set
|
|
{
|
|
Registers[(int)Register.E] = value;
|
|
}
|
|
}
|
|
public byte L
|
|
{
|
|
get
|
|
{
|
|
return Registers[(int)Register.L];
|
|
}
|
|
set
|
|
{
|
|
Registers[(int)Register.L] = value;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Wide Register Accessors
|
|
public ushort AF
|
|
{
|
|
get
|
|
{
|
|
ushort retVal = Flags.Value;
|
|
retVal += (ushort)((Registers[(int)Register.A]) << 8);
|
|
return retVal;
|
|
}
|
|
set
|
|
{
|
|
Flags.Value = (byte)(value & 0x00FF);
|
|
Registers[(int)Register.A] = (byte)((value & 0xFF00) >> 8);
|
|
}
|
|
}
|
|
public ushort BC
|
|
{
|
|
get
|
|
{
|
|
ushort retVal = Registers[(int)Register.C];
|
|
retVal += (ushort)((Registers[(int)Register.B]) << 8);
|
|
return retVal;
|
|
}
|
|
set
|
|
{
|
|
Registers[(int)Register.C] = (byte)(value & 0x00FF);
|
|
Registers[(int)Register.B] = (byte)((value & 0xFF00) >> 8);
|
|
}
|
|
}
|
|
public ushort DE
|
|
{
|
|
get
|
|
{
|
|
ushort retVal = Registers[(int)Register.E];
|
|
retVal += (ushort)((Registers[(int)Register.D]) << 8);
|
|
return retVal;
|
|
}
|
|
set
|
|
{
|
|
Registers[(int)Register.E] = (byte)(value & 0x00FF);
|
|
Registers[(int)Register.D] = (byte)((value & 0xFF00) >> 8);
|
|
}
|
|
}
|
|
public ushort HL
|
|
{
|
|
get
|
|
{
|
|
ushort retVal = Registers[(int)Register.L];
|
|
retVal += (ushort)((Registers[(int)Register.H]) << 8);
|
|
return retVal;
|
|
}
|
|
set
|
|
{
|
|
Registers[(int)Register.L] = (byte)(value & 0x00FF);
|
|
Registers[(int)Register.H] = (byte)((value & 0xFF00) >> 8);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
public ushort SP { get; set; }
|
|
public ushort PC { get; set; }
|
|
|
|
#region Constructors
|
|
public CpuRegisters()
|
|
{
|
|
AF = 0x01B0;
|
|
BC = 0x0013;
|
|
DE = 0x00D8;
|
|
HL = 0x014D;
|
|
}
|
|
public CpuRegisters(ushort initValue) : base()
|
|
{
|
|
AF = initValue;
|
|
BC = initValue;
|
|
DE = initValue;
|
|
HL = initValue;
|
|
}
|
|
public CpuRegisters(byte A, byte F, ushort SP, ushort PC)
|
|
{
|
|
this.A = A;
|
|
this.F = F;
|
|
this.SP = SP;
|
|
this.PC = PC;
|
|
}
|
|
public CpuRegisters(byte A, byte F, byte B, byte C, byte D, byte E, byte H, byte L, ushort SP, ushort PC) : this(A, F, SP, PC)
|
|
{
|
|
this.B = B;
|
|
this.C = C;
|
|
this.D = D;
|
|
this.E = E;
|
|
this.H = H;
|
|
this.L = L;
|
|
}
|
|
public CpuRegisters(byte A, byte F, ushort BC, ushort DE, ushort HL, ushort SP, ushort PC) : this(A, F, SP, PC)
|
|
{
|
|
this.BC = BC;
|
|
this.DE = DE;
|
|
this.HL = HL;
|
|
}
|
|
#endregion
|
|
|
|
public Dictionary<string, ushort> DumpRegisters()
|
|
{
|
|
return new Dictionary<string, ushort>
|
|
{
|
|
{ "A", A },
|
|
{ "F", F },
|
|
{ "B", B },
|
|
{ "C", C },
|
|
{ "D", D },
|
|
{ "E", E },
|
|
{ "H", H },
|
|
{ "L", L },
|
|
{ "AF", AF },
|
|
{ "BC", BC },
|
|
{ "DE", DE },
|
|
{ "HL", HL },
|
|
{ "PC", PC },
|
|
{ "SP", SP }
|
|
};
|
|
}
|
|
|
|
#region Print Functions
|
|
public void PrintSingleStatus()
|
|
{
|
|
Console.WriteLine("Register status:");
|
|
Console.WriteLine($"A:\t{A}\tF:\t{F}");
|
|
Console.WriteLine($"B:\t{B}\tC:\t{C}");
|
|
Console.WriteLine($"D:\t{D}\tE:\t{E}");
|
|
Console.WriteLine($"H:\t{H}\tL:\t{L}\r\n");
|
|
}
|
|
public void PrintWideStatus()
|
|
{
|
|
Console.WriteLine("Wide Register status:");
|
|
Console.WriteLine($"AF:\t{AF}");
|
|
Console.WriteLine($"BC:\t{BC}");
|
|
Console.WriteLine($"DE:\t{DE}");
|
|
Console.WriteLine($"HL:\t{HL}");
|
|
}
|
|
public void PrintFlags()
|
|
{
|
|
Console.WriteLine("Flag status:");
|
|
Console.WriteLine($"Zero:\t\t{Flags.Zero}");
|
|
Console.WriteLine($"Subtract:\t{Flags.Subtract}");
|
|
Console.WriteLine($"Half Carry:\t{Flags.HalfCarry}");
|
|
Console.WriteLine($"Carry:\t\t{Flags.Carry}");
|
|
Console.WriteLine($"Raw Register:\t{Convert.ToString(Flags.Value, 2)}");
|
|
}
|
|
#endregion
|
|
|
|
public class FlagRegister
|
|
{
|
|
protected internal byte Value { get; set; }
|
|
#region Boolean Flag Properties
|
|
public bool Zero
|
|
{
|
|
get { return (Value & 0b1000_0000) != 0; }
|
|
set
|
|
{
|
|
if (value)
|
|
Value |= 0b1000_0000;
|
|
else
|
|
Value &= 0b0111_1111;
|
|
}
|
|
}
|
|
public bool Subtract
|
|
{
|
|
get { return (Value & 0b0100_0000) != 0; }
|
|
set
|
|
{
|
|
if (value)
|
|
Value |= 0b0100_0000;
|
|
else
|
|
Value &= 0b1011_1111;
|
|
}
|
|
}
|
|
public bool HalfCarry
|
|
{
|
|
get { return (Value & 0b0010_0000) != 0; }
|
|
set
|
|
{
|
|
if (value)
|
|
Value |= 0b0010_0000;
|
|
else
|
|
Value &= 0b1101_1111;
|
|
}
|
|
}
|
|
public bool Carry
|
|
{
|
|
get { return (Value & 0b0001_0000) != 0; }
|
|
set
|
|
{
|
|
if (value)
|
|
Value |= 0b0001_0000;
|
|
else
|
|
Value &= 0b1110_1111;
|
|
}
|
|
}
|
|
#endregion
|
|
public bool IsValid
|
|
{
|
|
get { return (Value & 0b0000_1111) == 0; }
|
|
}
|
|
}
|
|
}
|
|
}
|