BizHawk/BizHawk.Emulation/CPUs/Z80/Z80A.cs

209 lines
8.2 KiB
C#

using System;
using System.Globalization;
using System.IO;
// This Z80 emulator is a modified version of Ben Ryves 'Brazil' emulator.
// It is MIT licensed.
namespace BizHawk.Emulation.CPUs.Z80
{
/// <summary>
/// ZiLOG Z80A CPU Emulator
/// </summary>
public sealed partial class Z80A
{
/// <summary>
/// Creates an instance of the <see cref="Z80A"/> emulator class.
/// </summary>
public Z80A()
{
InitialiseTables();
Reset();
}
/// <summary>
/// Reset the Z80 to its initial state
/// </summary>
public void Reset()
{
ResetRegisters();
ResetInterrupts();
PendingCycles = 0;
ExpectedExecutedCycles = 0;
TotalExecutedCycles = 0;
}
/// <summary>
/// Reset the Z80 to its initial state, but don't modify cycle counters. For use where Z80 may be reset
/// </summary>
public void SoftReset()
{
ResetRegisters();
ResetInterrupts();
}
// Memory Access
public Func<ushort, byte> ReadMemory;
public Action<ushort, byte> WriteMemory;
public void UnregisterMemoryMapper()
{
ReadMemory = null;
WriteMemory = null;
}
// Hardware I/O Port Access
public Func<ushort, byte> ReadHardware;
public Action<ushort, byte> WriteHardware;
// State Save/Load
public void SaveStateText(TextWriter writer)
{
writer.WriteLine("[Z80]");
writer.WriteLine("AF {0:X4}", RegAF.Word);
writer.WriteLine("BC {0:X4}", RegBC.Word);
writer.WriteLine("DE {0:X4}", RegDE.Word);
writer.WriteLine("HL {0:X4}", RegHL.Word);
writer.WriteLine("ShadowAF {0:X4}", RegAltAF.Word);
writer.WriteLine("ShadowBC {0:X4}", RegAltBC.Word);
writer.WriteLine("ShadowDE {0:X4}", RegAltDE.Word);
writer.WriteLine("ShadowHL {0:X4}", RegAltHL.Word);
writer.WriteLine("I {0:X2}", RegI);
writer.WriteLine("R {0:X2}", RegR);
writer.WriteLine("IX {0:X4}", RegIX.Word);
writer.WriteLine("IY {0:X4}", RegIY.Word);
writer.WriteLine("SP {0:X4}", RegSP.Word);
writer.WriteLine("PC {0:X4}", RegPC.Word);
writer.WriteLine("IRQ {0}", interrupt);
writer.WriteLine("NMI {0}", nonMaskableInterrupt);
writer.WriteLine("NMIPending {0}", nonMaskableInterruptPending);
writer.WriteLine("IM {0}", InterruptMode);
writer.WriteLine("IFF1 {0}", IFF1);
writer.WriteLine("IFF2 {0}", IFF2);
writer.WriteLine("Halted {0}", Halted);
writer.WriteLine("ExecutedCycles {0}", TotalExecutedCycles);
writer.WriteLine("PendingCycles {0}", PendingCycles);
writer.WriteLine("[/Z80]");
writer.WriteLine();
}
public void LoadStateText(TextReader reader)
{
while (true)
{
string[] args = reader.ReadLine().Split(' ');
if (args[0].Trim() == "") continue;
if (args[0] == "[/Z80]") break;
if (args[0] == "AF")
RegAF.Word = ushort.Parse(args[1], NumberStyles.HexNumber);
else if (args[0] == "BC")
RegBC.Word = ushort.Parse(args[1], NumberStyles.HexNumber);
else if (args[0] == "DE")
RegDE.Word = ushort.Parse(args[1], NumberStyles.HexNumber);
else if (args[0] == "HL")
RegHL.Word = ushort.Parse(args[1], NumberStyles.HexNumber);
else if (args[0] == "ShadowAF")
RegAltAF.Word = ushort.Parse(args[1], NumberStyles.HexNumber);
else if (args[0] == "ShadowBC")
RegAltBC.Word = ushort.Parse(args[1], NumberStyles.HexNumber);
else if (args[0] == "ShadowDE")
RegAltDE.Word = ushort.Parse(args[1], NumberStyles.HexNumber);
else if (args[0] == "ShadowHL")
RegAltHL.Word = ushort.Parse(args[1], NumberStyles.HexNumber);
else if (args[0] == "I")
RegI = byte.Parse(args[1], NumberStyles.HexNumber);
else if (args[0] == "R")
RegR = byte.Parse(args[1], NumberStyles.HexNumber);
else if (args[0] == "IX")
RegIX.Word = ushort.Parse(args[1], NumberStyles.HexNumber);
else if (args[0] == "IY")
RegIY.Word = ushort.Parse(args[1], NumberStyles.HexNumber);
else if (args[0] == "SP")
RegSP.Word = ushort.Parse(args[1], NumberStyles.HexNumber);
else if (args[0] == "PC")
RegPC.Word = ushort.Parse(args[1], NumberStyles.HexNumber);
else if (args[0] == "IRQ")
interrupt = bool.Parse(args[1]);
else if (args[0] == "NMI")
nonMaskableInterrupt = bool.Parse(args[1]);
else if (args[0] == "NMIPending")
nonMaskableInterruptPending = bool.Parse(args[1]);
else if (args[0] == "IM")
InterruptMode = int.Parse(args[1]);
else if (args[0] == "IFF1")
IFF1 = bool.Parse(args[1]);
else if (args[0] == "IFF2")
IFF2 = bool.Parse(args[1]);
else if (args[0] == "Halted")
Halted = bool.Parse(args[1]);
else if (args[0] == "ExecutedCycles")
TotalExecutedCycles = int.Parse(args[1]);
else if (args[0] == "PendingCycles")
PendingCycles = int.Parse(args[1]);
else
Console.WriteLine("Skipping unrecognized identifier " + args[0]);
}
}
public void SaveStateBinary(BinaryWriter writer)
{
writer.Write(RegAF.Word);
writer.Write(RegBC.Word);
writer.Write(RegDE.Word);
writer.Write(RegHL.Word);
writer.Write(RegAltAF.Word);
writer.Write(RegAltBC.Word);
writer.Write(RegAltDE.Word);
writer.Write(RegAltHL.Word);
writer.Write(RegAltAF.Word);
writer.Write(RegI);
writer.Write(RegR);
writer.Write(RegIX.Word);
writer.Write(RegIY.Word);
writer.Write(RegSP.Word);
writer.Write(RegPC.Word);
writer.Write(interrupt);
writer.Write(nonMaskableInterrupt);
writer.Write(nonMaskableInterruptPending);
writer.Write(InterruptMode);
writer.Write(IFF1);
writer.Write(IFF2);
writer.Write(Halted);
writer.Write(TotalExecutedCycles);
writer.Write(PendingCycles);
}
public void LoadStateBinary(BinaryReader reader)
{
RegAF.Word = reader.ReadUInt16();
RegBC.Word = reader.ReadUInt16();
RegDE.Word = reader.ReadUInt16();
RegHL.Word = reader.ReadUInt16();
RegAltAF.Word = reader.ReadUInt16();
RegAltBC.Word = reader.ReadUInt16();
RegAltDE.Word = reader.ReadUInt16();
RegAltHL.Word = reader.ReadUInt16();
RegAltAF.Word = reader.ReadUInt16();
RegI = reader.ReadByte();
RegR = reader.ReadByte();
RegIX.Word = reader.ReadUInt16();
RegIY.Word = reader.ReadUInt16();
RegSP.Word = reader.ReadUInt16();
RegPC.Word = reader.ReadUInt16();
interrupt = reader.ReadBoolean();
nonMaskableInterrupt = reader.ReadBoolean();
nonMaskableInterruptPending = reader.ReadBoolean();
InterruptMode = reader.ReadInt32();
IFF1 = reader.ReadBoolean();
IFF2 = reader.ReadBoolean();
Halted = reader.ReadBoolean();
TotalExecutedCycles = reader.ReadInt32();
PendingCycles = reader.ReadInt32();
}
}
}