Merge pull request #1021 from TASVideos/newZ80

New z80 Core
This commit is contained in:
alyosha-tas 2017-10-13 18:42:04 -04:00 committed by GitHub
commit eca4299b87
30 changed files with 4810 additions and 13906 deletions

View File

@ -1186,12 +1186,14 @@
<Compile Include="CPUs\Z80-GB\Registers.cs" />
<Compile Include="CPUs\Z80-GB\Tables.cs" />
<Compile Include="CPUs\Z80-GB\Z80.cs" />
<Compile Include="CPUs\Z80\Disassembler.cs" />
<Compile Include="CPUs\Z80\Execute.cs" />
<Compile Include="CPUs\Z80\Interrupts.cs" />
<Compile Include="CPUs\Z80\Registers.cs" />
<Compile Include="CPUs\Z80\Tables.cs" />
<Compile Include="CPUs\Z80\Z80A.cs" />
<Compile Include="CPUs\Z80A\NewDisassembler.cs" />
<Compile Include="CPUs\Z80A\Execute.cs" />
<Compile Include="CPUs\Z80A\Interrupts.cs" />
<Compile Include="CPUs\Z80A\Registers.cs" />
<Compile Include="CPUs\Z80A\Operations.cs" />
<Compile Include="CPUs\Z80A\Tables_Direct.cs" />
<Compile Include="CPUs\Z80A\Tables_Indirect.cs" />
<Compile Include="CPUs\Z80A\Z80A.cs" />
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
@ -1314,4 +1316,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>

File diff suppressed because it is too large Load Diff

View File

@ -1,55 +0,0 @@
using System;
namespace BizHawk.Emulation.Cores.Components.Z80
{
public partial class Z80A
{
private bool iff1;
public bool IFF1 { get { return iff1; } set { iff1 = value; } }
private bool iff2;
public bool IFF2 { get { return iff2; } set { iff2 = value; } }
private bool interrupt;
public bool Interrupt { get { return interrupt; } set { interrupt = value; } }
private bool nonMaskableInterrupt;
public bool NonMaskableInterrupt
{
get { return nonMaskableInterrupt; }
set { if (value && !nonMaskableInterrupt) NonMaskableInterruptPending = true; nonMaskableInterrupt = value; }
}
private bool nonMaskableInterruptPending;
public bool NonMaskableInterruptPending { get { return nonMaskableInterruptPending; } set { nonMaskableInterruptPending = value; } }
private int interruptMode;
public int InterruptMode
{
get { return interruptMode; }
set { if (value < 0 || value > 2) throw new ArgumentOutOfRangeException(); interruptMode = value; }
}
private bool halted;
public bool Halted { get { return halted; } set { halted = value; } }
public Action IRQCallback = delegate() { };
public Action NMICallback = delegate() { };
private void ResetInterrupts()
{
IFF1 = false;
IFF2 = false;
Interrupt = false;
NonMaskableInterrupt = false;
NonMaskableInterruptPending = false;
InterruptMode = 1;
Halted = false;
}
private void Halt()
{
Halted = true;
}
}
}

View File

@ -1,270 +0,0 @@
using System.Runtime.InteropServices;
using System;
namespace BizHawk.Emulation.Cores.Components.Z80
{
public partial class Z80A
{
[StructLayout(LayoutKind.Explicit)]
[Serializable()]
public struct RegisterPair
{
[FieldOffset(0)]
public ushort Word;
[FieldOffset(0)]
public byte Low;
[FieldOffset(1)]
public byte High;
public RegisterPair(ushort value)
{
Word = value;
Low = (byte)(Word);
High = (byte)(Word >> 8);
}
public static implicit operator ushort(RegisterPair rp)
{
return rp.Word;
}
public static implicit operator RegisterPair(ushort value)
{
return new RegisterPair(value);
}
}
private bool RegFlagC
{
get { return (RegAF.Low & 0x01) != 0; }
set { RegAF.Low = (byte)((RegAF.Low & ~0x01) | (value ? 0x01 : 0x00)); }
}
private bool RegFlagN
{
get { return (RegAF.Low & 0x02) != 0; }
set { RegAF.Low = (byte)((RegAF.Low & ~0x02) | (value ? 0x02 : 0x00)); }
}
private bool RegFlagP
{
get { return (RegAF.Low & 0x04) != 0; }
set { RegAF.Low = (byte)((RegAF.Low & ~0x04) | (value ? 0x04 : 0x00)); }
}
private bool RegFlag3
{
get { return (RegAF.Low & 0x08) != 0; }
set { RegAF.Low = (byte)((RegAF.Low & ~0x08) | (value ? 0x08 : 0x00)); }
}
private bool RegFlagH
{
get { return (RegAF.Low & 0x10) != 0; }
set { RegAF.Low = (byte)((RegAF.Low & ~0x10) | (value ? 0x10 : 0x00)); }
}
private bool RegFlag5
{
get { return (RegAF.Low & 0x20) != 0; }
set { RegAF.Low = (byte)((RegAF.Low & ~0x20) | (value ? 0x20 : 0x00)); }
}
private bool RegFlagZ
{
get { return (RegAF.Low & 0x40) != 0; }
set { RegAF.Low = (byte)((RegAF.Low & ~0x40) | (value ? 0x40 : 0x00)); }
}
private bool RegFlagS
{
get { return (RegAF.Low & 0x80) != 0; }
set { RegAF.Low = (byte)((RegAF.Low & ~0x80) | (value ? 0x80 : 0x00)); }
}
private RegisterPair RegAF;
private RegisterPair RegBC;
private RegisterPair RegDE;
private RegisterPair RegHL;
private RegisterPair RegWZ;
private RegisterPair RegAltAF; // Shadow for A and F
private RegisterPair RegAltBC; // Shadow for B and C
private RegisterPair RegAltDE; // Shadow for D and E
private RegisterPair RegAltHL; // Shadow for H and L
// NOTE: There is no AltWZ register (despite it being shown on various block diagrams)
private byte RegI; // I (interrupt vector)
private byte RegR; // R (memory refresh)
private RegisterPair RegIX; // IX (index register x)
private RegisterPair RegIY; // IY (index register y)
private RegisterPair RegSP; // SP (stack pointer)
private RegisterPair RegPC; // PC (program counter)
private void ResetRegisters()
{
// Clear main registers
RegAF = 0; RegBC = 0; RegDE = 0; RegHL = 0; RegWZ = 0;
// Clear alternate registers
RegAltAF = 0; RegAltBC = 0; RegAltDE = 0; RegAltHL = 0;
// Clear special purpose registers
RegI = 0; RegR = 0;
RegIX.Word = 0; RegIY.Word = 0;
RegSP.Word = 0; RegPC.Word = 0;
}
public byte RegisterA
{
get { return RegAF.High; }
set { RegAF.High = value; }
}
public byte RegisterF
{
get { return RegAF.Low; }
set { RegAF.Low = value; }
}
public ushort RegisterAF
{
get { return RegAF.Word; }
set { RegAF.Word = value; }
}
public byte RegisterB
{
get { return RegBC.High; }
set { RegBC.High = value; }
}
public byte RegisterC
{
get { return RegBC.Low; }
set { RegBC.Low = value; }
}
public ushort RegisterBC
{
get { return RegBC.Word; }
set { RegBC.Word = value; }
}
public byte RegisterD
{
get { return RegDE.High; }
set { RegDE.High = value; }
}
public byte RegisterE
{
get { return RegDE.Low; }
set { RegDE.Low = value; }
}
public ushort RegisterDE
{
get { return RegDE.Word; }
set { RegDE.Word = value; }
}
public byte RegisterH
{
get { return RegHL.High; }
set { RegHL.High = value; }
}
public byte RegisterL
{
get { return RegHL.Low; }
set { RegHL.Low = value; }
}
public ushort RegisterHL
{
get { return RegHL.Word; }
set { RegHL.Word = value; }
}
public byte RegisterW
{
get { return RegWZ.High; }
set { RegWZ.High = value; }
}
public byte RegisterZ
{
get { return RegWZ.Low; }
set { RegWZ.Low = value; }
}
public ushort RegisterWZ
{
get { return RegWZ.Word; }
set { RegWZ.Word = value; }
}
public ushort RegisterPC
{
get { return RegPC.Word; }
set { RegPC.Word = value; }
}
public ushort RegisterSP
{
get { return RegSP.Word; }
set { RegSP.Word = value; }
}
public ushort RegisterIX
{
get { return RegIX.Word; }
set { RegIX.Word = value; }
}
public ushort RegisterIY
{
get { return RegIY.Word; }
set { RegIY.Word = value; }
}
public byte RegisterI
{
get { return RegI; }
set { RegI = value; }
}
public byte RegisterR
{
get { return RegR; }
set { RegR = value; }
}
public ushort RegisterShadowAF
{
get { return RegAltAF.Word; }
set { RegAltAF.Word = value; }
}
public ushort RegisterShadowBC
{
get { return RegAltBC.Word; }
set { RegAltBC.Word = value; }
}
public ushort RegisterShadowDE
{
get { return RegAltDE.Word; }
set { RegAltDE.Word = value; }
}
public ushort RegisterShadowHL
{
get { return RegAltHL.Word; }
set { RegAltHL.Word = value; }
}
}
}

View File

@ -1,331 +0,0 @@
namespace BizHawk.Emulation.Cores.Components.Z80
{
public partial class Z80A
{
private void InitialiseTables()
{
InitTableInc();
InitTableDec();
InitTableParity();
InitTableALU();
InitTableRotShift();
InitTableHalfBorrow();
InitTableHalfCarry();
InitTableNeg();
InitTableDaa();
}
private byte[] TableInc;
private void InitTableInc()
{
TableInc = new byte[256];
for (int i = 0; i < 256; ++i)
TableInc[i] = FlagByte(false, false, i == 0x80, UndocumentedX(i), (i & 0xF) == 0x0, UndocumentedY(i), i == 0, i > 127);
}
private byte[] TableDec;
private void InitTableDec()
{
TableDec = new byte[256];
for (int i = 0; i < 256; ++i)
TableDec[i] = FlagByte(false, true, i == 0x7F, UndocumentedX(i), (i & 0xF) == 0xF, UndocumentedY(i), i == 0, i > 127);
}
private bool[] TableParity;
private void InitTableParity()
{
TableParity = new bool[256];
for (int i = 0; i < 256; ++i)
{
int Bits = 0;
for (int j = 0; j < 8; ++j)
{
Bits += (i >> j) & 1;
}
TableParity[i] = (Bits & 1) == 0;
}
}
private ushort[, , ,] TableALU;
private void InitTableALU()
{
TableALU = new ushort[8, 256, 256, 2]; // Class, OP1, OP2, Carry
for (int i = 0; i < 8; ++i)
{
for (int op1 = 0; op1 < 256; ++op1)
{
for (int op2 = 0; op2 < 256; ++op2)
{
for (int c = 0; c < 2; ++c)
{
int ac = (i == 1 || i == 3) ? c : 0;
bool S = false;
bool Z = false;
bool C = false;
bool H = false;
bool N = false;
bool P = false;
byte result_b = 0;
int result_si = 0;
int result_ui = 0;
// Fetch result
switch (i)
{
case 0:
case 1:
result_si = (sbyte)op1 + (sbyte)op2 + ac;
result_ui = op1 + op2 + ac;
break;
case 2:
case 3:
case 7:
result_si = (sbyte)op1 - (sbyte)op2 - ac;
result_ui = op1 - op2 - ac;
break;
case 4:
result_si = op1 & op2;
break;
case 5:
result_si = op1 ^ op2;
break;
case 6:
result_si = op1 | op2;
break;
}
result_b = (byte)result_si;
// Parity/Carry
switch (i)
{
case 0:
case 1:
case 2:
case 3:
case 7:
P = result_si < -128 || result_si > 127;
C = result_ui < 0 || result_ui > 255;
break;
case 4:
case 5:
case 6:
P = TableParity[result_b];
C = false;
break;
}
// Subtraction
N = i == 2 || i == 3 || i == 7;
// Half carry
switch (i)
{
case 0:
case 1:
H = ((op1 & 0xF) + (op2 & 0xF) + (ac & 0xF)) > 0xF;
break;
case 2:
case 3:
case 7:
H = ((op1 & 0xF) - (op2 & 0xF) - (ac & 0xF)) < 0x0;
break;
case 4:
H = true;
break;
case 5:
case 6:
H = false;
break;
}
// Undocumented
byte UndocumentedFlags = (byte)(result_b & 0x28);
if (i == 7) UndocumentedFlags = (byte)(op2 & 0x28);
S = result_b > 127;
Z = result_b == 0;
if (i == 7) result_b = (byte)op1;
TableALU[i, op1, op2, c] = (ushort)(
result_b * 256 +
((C ? 0x01 : 0) + (N ? 0x02 : 0) + (P ? 0x04 : 0) + (H ? 0x10 : 0) + (Z ? 0x40 : 0) + (S ? 0x80 : 0)) +
(UndocumentedFlags));
}
}
}
}
}
private bool[,] TableHalfBorrow;
private void InitTableHalfBorrow()
{
TableHalfBorrow = new bool[256, 256];
for (int i = 0; i < 256; i++)
{
for (int j = 0; j < 256; j++)
{
TableHalfBorrow[i, j] = ((i & 0xF) - (j & 0xF)) < 0;
}
}
}
private bool[,] TableHalfCarry;
private void InitTableHalfCarry()
{
TableHalfCarry = new bool[256, 256];
for (int i = 0; i < 256; i++)
{
for (int j = 0; j < 256; j++)
{
TableHalfCarry[i, j] = ((i & 0xF) + (j & 0xF)) > 0xF;
}
}
}
private ushort[, ,] TableRotShift;
private void InitTableRotShift()
{
TableRotShift = new ushort[2, 8, 65536]; // All, operation, AF
for (int all = 0; all < 2; all++)
{
for (int y = 0; y < 8; ++y)
{
for (int af = 0; af < 65536; af++)
{
byte Old = (byte)(af >> 8);
bool OldCarry = (af & 0x01) != 0;
ushort newAf = (ushort)(af & ~(0x13)); // Clear HALF-CARRY, SUBTRACT and CARRY flags
byte New = Old;
if ((y & 1) == 0)
{
if ((Old & 0x80) != 0) ++newAf;
New <<= 1;
if ((y & 0x04) == 0)
{
if (((y & 0x02) == 0) ? ((newAf & 0x01) != 0) : OldCarry) New |= 0x01;
}
else
{
if ((y & 0x02) != 0) New |= 0x01;
}
}
else
{
if ((Old & 0x01) != 0) ++newAf;
New >>= 1;
if ((y & 0x04) == 0)
{
if (((y & 0x02) == 0) ? ((newAf & 0x01) != 0) : OldCarry) New |= 0x80;
}
else
{
if ((y & 0x02) == 0) New |= (byte)(Old & 0x80);
}
}
newAf &= 0xFF;
newAf |= (ushort)(New * 256);
if (all == 1)
{
newAf &= unchecked((ushort)~0xC4); // Clear S, Z, P
if (New > 127) newAf |= 0x80;
if (New == 0) newAf |= 0x40;
if (TableParity[New]) newAf |= 0x04;
}
TableRotShift[all, y, af] = (ushort)((newAf & ~0x28) | ((newAf >> 8) & 0x28));
}
}
}
}
private ushort[] TableNeg;
private void InitTableNeg()
{
TableNeg = new ushort[65536];
for (int af = 0; af < 65536; af++)
{
ushort raf = 0;
byte b = (byte)(af >> 8);
byte a = (byte)-b;
raf |= (ushort)(a * 256);
raf |= FlagByte(b != 0x00, true, b == 0x80, UndocumentedX(a), TableHalfCarry[a, b], UndocumentedY(a), a == 0, a > 127);
TableNeg[af] = raf;
}
}
private ushort[] TableDaa;
private void InitTableDaa()
{
TableDaa = new ushort[65536];
for (int af = 0; af < 65536; ++af)
{
byte a = (byte)(af >> 8);
byte tmp = a;
if (IsN(af))
{
if (IsH(af) || ((a & 0x0F) > 0x09)) tmp -= 0x06;
if (IsC(af) || a > 0x99) tmp -= 0x60;
}
else
{
if (IsH(af) || ((a & 0x0F) > 0x09)) tmp += 0x06;
if (IsC(af) || a > 0x99) tmp += 0x60;
}
TableDaa[af] = (ushort)((tmp * 256) + FlagByte(IsC(af) || a > 0x99, IsN(af), TableParity[tmp], UndocumentedX(tmp), ((a ^ tmp) & 0x10) != 0, UndocumentedY(tmp), tmp == 0, tmp > 127));
}
}
private byte FlagByte(bool C, bool N, bool P, bool X, bool H, bool Y, bool Z, bool S)
{
return (byte)(
(C ? 0x01 : 0) +
(N ? 0x02 : 0) +
(P ? 0x04 : 0) +
(X ? 0x08 : 0) +
(H ? 0x10 : 0) +
(Y ? 0x20 : 0) +
(Z ? 0x40 : 0) +
(S ? 0x80 : 0)
);
}
private bool UndocumentedX(int value)
{
return (value & 0x08) != 0;
}
private bool UndocumentedY(int value)
{
return (value & 0x20) != 0;
}
private bool IsC(int value) { return (value & 0x01) != 0; }
private bool IsN(int value) { return (value & 0x02) != 0; }
private bool IsP(int value) { return (value & 0x04) != 0; }
private bool IsX(int value) { return (value & 0x08) != 0; }
private bool IsH(int value) { return (value & 0x10) != 0; }
private bool IsY(int value) { return (value & 0x20) != 0; }
private bool IsZ(int value) { return (value & 0x40) != 0; }
private bool IsS(int value) { return (value & 0x80) != 0; }
}
}

View File

@ -1,142 +0,0 @@
using System;
using System.Globalization;
using System.IO;
using BizHawk.Common;
using BizHawk.Emulation.Common;
// This Z80 emulator is a modified version of Ben Ryves 'Brazil' emulator.
// It is MIT licensed.
// for WZ register details, see: http://www.grimware.org/lib/exe/fetch.php/documentations/devices/z80/z80.memptr.eng.txt
namespace BizHawk.Emulation.Cores.Components.Z80
{
public sealed partial class Z80A
{
public Z80A()
{
InitialiseTables();
Reset();
}
public void Reset()
{
ResetRegisters();
ResetInterrupts();
PendingCycles = 0;
ExpectedExecutedCycles = 0;
TotalExecutedCycles = 0;
}
public void SoftReset()
{
ResetRegisters();
ResetInterrupts();
}
// Memory Access
public Func<ushort, bool, byte> FetchMemory;
public Func<ushort, byte> ReadMemory;
public Action<ushort, byte> WriteMemory;
public byte ReadMemoryWrapper(ushort addr)
{
if (MemoryCallbacks != null)
{
MemoryCallbacks.CallReads(addr);
}
return ReadMemory(addr);
}
public byte FetchFirstMemoryWrapper(ushort addr)
{
if (MemoryCallbacks != null)
{
MemoryCallbacks.CallReads(addr);
}
if (FetchMemory != null)
{
return FetchMemory(addr, true);
}
return ReadMemory(addr);
}
public byte FetchMemoryWrapper(ushort addr)
{
if (MemoryCallbacks != null)
{
MemoryCallbacks.CallReads(addr);
}
if (FetchMemory != null)
{
return FetchMemory(addr, false);
}
return ReadMemory(addr);
}
public void WriteMemoryWrapper(ushort addr, byte value)
{
if (MemoryCallbacks != null)
{
MemoryCallbacks.CallWrites(addr);
}
WriteMemory(addr, value);
}
public IMemoryCallbackSystem MemoryCallbacks { get; set; }
// Utility function, not used by core
public ushort ReadWord(ushort addr)
{
ushort value = ReadMemory(addr++);
value |= (ushort)(ReadMemory(addr) << 8);
return value;
}
// Hardware I/O Port Access
public Func<ushort, byte> ReadHardware;
public Action<ushort, byte> WriteHardware;
// State Save/Load
public void SyncState(Serializer ser)
{
ser.BeginSection("Z80");
ser.Sync("AF", ref RegAF.Word);
ser.Sync("BC", ref RegBC.Word);
ser.Sync("DE", ref RegDE.Word);
ser.Sync("HL", ref RegHL.Word);
ser.Sync("WZ", ref RegWZ.Word);
ser.Sync("ShadowAF", ref RegAltAF.Word);
ser.Sync("ShadowBC", ref RegAltBC.Word);
ser.Sync("ShadowDE", ref RegAltDE.Word);
ser.Sync("ShadowHL", ref RegAltHL.Word);
ser.Sync("I", ref RegI);
ser.Sync("R", ref RegR);
ser.Sync("IX", ref RegIX.Word);
ser.Sync("IY", ref RegIY.Word);
ser.Sync("SP", ref RegSP.Word);
ser.Sync("PC", ref RegPC.Word);
ser.Sync("IRQ", ref interrupt);
ser.Sync("NMI", ref nonMaskableInterrupt);
ser.Sync("NMIPending", ref nonMaskableInterruptPending);
ser.Sync("IM", ref interruptMode);
ser.Sync("IFF1", ref iff1);
ser.Sync("IFF2", ref iff2);
ser.Sync("Halted", ref halted);
ser.Sync("ExecutedCycles", ref totalExecutedCycles);
ser.Sync("PendingCycles", ref pendingCycles);
ser.Sync("EI_pending", ref EI_pending);
ser.EndSection();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,123 @@
using System;
namespace BizHawk.Emulation.Cores.Components.Z80A
{
public partial class Z80A
{
private bool iff1;
public bool IFF1 { get { return iff1; } set { iff1 = value; } }
private bool iff2;
public bool IFF2 { get { return iff2; } set { iff2 = value; } }
private bool nonMaskableInterrupt;
public bool NonMaskableInterrupt
{
get { return nonMaskableInterrupt; }
set { if (value && !nonMaskableInterrupt) NonMaskableInterruptPending = true; nonMaskableInterrupt = value; }
}
private bool nonMaskableInterruptPending;
public bool NonMaskableInterruptPending { get { return nonMaskableInterruptPending; } set { nonMaskableInterruptPending = value; } }
private int interruptMode;
public int InterruptMode
{
get { return interruptMode; }
set { if (value < 0 || value > 2) throw new ArgumentOutOfRangeException(); interruptMode = value; }
}
public Action IRQCallback = delegate () { };
public Action NMICallback = delegate () { };
private void NMI_()
{
cur_instr = new ushort[]
{IDLE,
DEC16, SPl, SPh,
WR, SPl, SPh, PCh,
IDLE,
DEC16, SPl, SPh,
WR, SPl, SPh, PCl,
IDLE,
ASGN, PCl, 0x66,
ASGN, PCh, 0,
IDLE,
OP };
}
// Mode 0 interrupts only take effect if a CALL or RST is on the data bus
// Otherwise operation just continues as normal
// For now assume a NOP is on the data bus, in which case no stack operations occur
//NOTE: TODO: When a CALL is present on the data bus, adjust WZ accordingly
private void INTERRUPT_0(ushort src)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
RD, ALU, PCl, PCh,
IDLE,
INC16, PCl, PCh,
IDLE,
OP };
}
// Just jump to $0038
private void INTERRUPT_1()
{
cur_instr = new ushort[]
{DEC16, SPl, SPh,
IDLE,
WR, SPl, SPh, PCh,
IDLE,
DEC16, SPl, SPh,
IDLE,
WR, SPl, SPh, PCl,
IDLE,
ASGN, PCl, 0x38,
IDLE,
ASGN, PCh, 0,
IDLE,
OP };
}
// Interrupt mode 2 uses the I vector combined with a byte on the data bus
// Again for now we assume only a 0 on the data bus and jump to (0xI00)
private void INTERRUPT_2(ushort src)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
DEC16, SPl, SPh,
WR, SPl, SPh, PCh,
IDLE,
DEC16, SPl, SPh,
WR, SPl, SPh, PCl,
IDLE,
ASGN, PCl, 0,
TR, PCh, I,
IDLE,
IDLE,
RD, Z, PCl, PCh,
INC16, PCl, PCh,
IDLE,
RD, W, PCl, PCh,
IDLE,
TR16, PCl, PCh, Z, W,
OP };
}
private static ushort[] INT_vectors = new ushort[] {0x40, 0x48, 0x50, 0x58, 0x60};
private void ResetInterrupts()
{
IFF1 = false;
IFF2 = false;
NonMaskableInterrupt = false;
NonMaskableInterruptPending = false;
FlagI = false;
InterruptMode = 1;
}
}
}

View File

@ -1,114 +1,27 @@
//http://www.zophar.net/fileuploads/2/10819kouzv/z80undoc.html
//TODO: ex. (IX+00h) could be turned into (IX)
//usage:
//VgMuseum.Z80.Disassembler disasm = new Disassembler();
//ushort pc = RegPC.Word;
//string str = disasm.Disassemble(() => ReadMemory(pc++));
//Console.WriteLine(str);
//please note that however much youre tempted to, timings can't be put in a table here because they depend on how the instruction executes at runtime
using System;
using System;
using System.Collections.Generic;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Components.Z80
namespace BizHawk.Emulation.Cores.Components.Z80A
{
public class Disassembler : IDisassemblable
public sealed partial class Z80A : IDisassemblable
{
readonly static sbyte[,] opcodeSizes = new sbyte[7, 256];
public static void GenerateOpcodeSizes()
{
Disassembler disasm = new Disassembler();
for (int i = 0; i < 256; i++)
{
int pc = 0;
byte[] opcode = { (byte)i, 0, 0, 0 };
disasm.Disassemble(() => opcode[pc++]);
opcodeSizes[0, i] = (sbyte)pc;
}
opcodeSizes[0, 0xCB] = -1;
opcodeSizes[0, 0xED] = -2;
opcodeSizes[0, 0xDD] = -3;
opcodeSizes[0, 0xFD] = -4;
for (int i = 0; i < 256; i++)
{
int pc = 0;
byte[] opcode = { 0xCB, (byte)i, 0, 0, 0 };
disasm.Disassemble(() => opcode[pc++]);
opcodeSizes[1, i] = (sbyte)pc;
}
for (int i = 0; i < 256; i++)
{
int pc = 0;
byte[] opcode = { 0xED, (byte)i, 0, 0, 0 };
disasm.Disassemble(() => opcode[pc++]);
opcodeSizes[2, i] = (sbyte)pc;
}
for (int i = 0; i < 256; i++)
{
int pc = 0;
byte[] opcode = { 0xDD, (byte)i, 0, 0, 0 };
disasm.Disassemble(() => opcode[pc++]);
opcodeSizes[3, i] = (sbyte)pc;
}
opcodeSizes[3, 0xCB] = -5;
opcodeSizes[3, 0xED] = -2;
for (int i = 0; i < 256; i++)
{
int pc = 0;
byte[] opcode = { 0xFD, (byte)i, 0, 0, 0 };
disasm.Disassemble(() => opcode[pc++]);
opcodeSizes[4, i] = (sbyte)pc;
}
opcodeSizes[3, 0xCB] = -6;
opcodeSizes[3, 0xED] = -2;
for (int i = 0; i < 256; i++)
{
int pc = 0;
byte[] opcode = { 0xDD, 0xCB, (byte)i, 0, 0, 0 };
disasm.Disassemble(() => opcode[pc++]);
opcodeSizes[5, i] = (sbyte)pc;
}
for (int i = 0; i < 256; i++)
{
int pc = 0;
byte[] opcode = { 0xFD, 0xCB, (byte)i, 0, 0, 0 };
disasm.Disassemble(() => opcode[pc++]);
opcodeSizes[6, i] = (sbyte)pc;
}
}
static string Result(string format, Func<byte> read)
static string Result(string format, Func<ushort, byte> read, ref ushort addr)
{
//d immediately succeeds the opcode
//n immediate succeeds the opcode and the displacement (if present)
//nn immediately succeeds the opcode and the displacement (if present)
if (format.IndexOf("nn") != -1)
{
byte B = read();
byte C = read();
byte B = read(addr++);
byte C = read(addr++);
format = format.Replace("nn", string.Format("{0:X4}h", B + C * 256));
}
if (format.IndexOf("n") != -1)
{
byte B = read();
byte B = read(addr++);
format = format.Replace("n", string.Format("{0:X2}h", B));
}
@ -116,7 +29,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80
if (format.IndexOf("d") != -1)
{
byte B = read();
byte B = read(addr++);
bool neg = ((B & 0x80) != 0);
char sign = neg ? '-' : '+';
int val = neg ? 256 - B : B;
@ -480,18 +393,19 @@ namespace BizHawk.Emulation.Cores.Components.Z80
"NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", //0x100
};
string DisassembleInternal(Func<byte> read)
public string Disassemble(ushort addr, Func<ushort, byte> read, out ushort size)
{
byte A = read();
ushort start_addr = addr;
byte A = read(addr++);
string format;
switch (A)
{
case 0xCB:
A = read();
A = read(addr++);
format = mnemonicsCB[A];
break;
case 0xDD:
A = read();
A = read(addr++);
switch (A)
{
case 0xCB: format = mnemonicsDDCB[A]; break;
@ -500,11 +414,11 @@ namespace BizHawk.Emulation.Cores.Components.Z80
}
break;
case 0xED:
A = read();
A = read(addr++);
format = mnemonicsED[A];
break;
case 0xFD:
A = read();
A = read(addr++);
switch (A)
{
case 0xCB: format = mnemonicsFDCB[A]; break;
@ -514,12 +428,11 @@ namespace BizHawk.Emulation.Cores.Components.Z80
break;
default: format = mnemonics[A]; break;
}
return format;
}
string temp = Result(format, read, ref addr);
public string Disassemble(Func<byte> read)
{
return Result(DisassembleInternal(read), read);
size = (ushort)(addr - start_addr);
return temp;
}
#region IDisassemblable
@ -543,7 +456,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80
public string Disassemble(MemoryDomain m, uint addr, out int length)
{
int loc = (int)addr;
string ret = Disassemble(() => m.PeekByte(loc++));
ushort unused = 0;
string ret = Disassemble((ushort) addr, a => m.PeekByte(a), out unused);
length = loc - (int)addr;
return ret;
}

View File

@ -0,0 +1,727 @@
using BizHawk.Common.NumberExtensions;
using System;
namespace BizHawk.Emulation.Cores.Components.Z80A
{
public partial class Z80A
{
public void Read_Func(ushort dest, ushort src_l, ushort src_h)
{
Regs[dest] = ReadMemory((ushort)(Regs[src_l] | (Regs[src_h]) << 8));
}
public void I_Read_Func(ushort dest, ushort src_l, ushort src_h, ushort inc)
{
Regs[dest] = ReadMemory((ushort)((Regs[src_l] | (Regs[src_h] << 8)) + inc));
}
public void Write_Func(ushort dest_l, ushort dest_h, ushort src)
{
WriteMemory((ushort)(Regs[dest_l] | (Regs[dest_h] << 8)), (byte)Regs[src]);
}
public void I_Write_Func(ushort dest_l, ushort dest_h, ushort inc, ushort src)
{
WriteMemory((ushort)((Regs[dest_l] | (Regs[dest_h] << 8)) + inc), (byte)Regs[src]);
}
public void OUT_Func(ushort dest, ushort src)
{
WriteHardware(Regs[dest], (byte)(Regs[src]));
}
public void IN_Func(ushort dest, ushort src)
{
Regs[dest] = ReadHardware(Regs[src]);
}
public void TR_Func(ushort dest, ushort src)
{
Regs[dest] = Regs[src];
}
public void TR16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
{
Regs[dest_l] = Regs[src_l];
Regs[dest_h] = Regs[src_h];
}
public void ADD16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
{
int Reg16_d = Regs[dest_l] | (Regs[dest_h] << 8);
int Reg16_s = Regs[src_l] | (Regs[src_h] << 8);
int temp = Reg16_d + Reg16_s;
FlagC = temp.Bit(16);
FlagH = ((Reg16_d & 0xFFF) + (Reg16_s & 0xFFF)) > 0xFFF;
FlagN = false;
Flag3 = (temp & 0x0800) != 0;
Flag5 = (temp & 0x2000) != 0;
Regs[dest_l] = (ushort)(temp & 0xFF);
Regs[dest_h] = (ushort)((temp & 0xFF00) >> 8);
}
public void ADD8_Func(ushort dest, ushort src)
{
int Reg16_d = Regs[dest];
Reg16_d += Regs[src];
FlagC = Reg16_d.Bit(8);
FlagZ = (Reg16_d & 0xFF) == 0;
ushort ans = (ushort)(Reg16_d & 0xFF);
// redo for half carry flag
Reg16_d = Regs[dest] & 0xF;
Reg16_d += (Regs[src] & 0xF);
FlagH = Reg16_d.Bit(4);
FlagN = false;
Flag3 = (ans & 0x08) != 0;
Flag5 = (ans & 0x20) != 0;
FlagP = (Regs[dest].Bit(7) == Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7));
FlagS = ans > 127;
Regs[dest] = ans;
}
public void SUB8_Func(ushort dest, ushort src)
{
int Reg16_d = Regs[dest];
Reg16_d -= Regs[src];
FlagC = Reg16_d.Bit(8);
FlagZ = (Reg16_d & 0xFF) == 0;
ushort ans = (ushort)(Reg16_d & 0xFF);
// redo for half carry flag
Reg16_d = Regs[dest] & 0xF;
Reg16_d -= (Regs[src] & 0xF);
FlagH = Reg16_d.Bit(4);
FlagN = true;
Flag3 = (ans & 0x08) != 0;
Flag5 = (ans & 0x20) != 0;
FlagP = (Regs[dest].Bit(7) != Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7));
FlagS = ans > 127;
Regs[dest] = ans;
}
public void BIT_Func(ushort bit, ushort src)
{
FlagZ = !Regs[src].Bit(bit);
FlagP = FlagZ; // special case
FlagH = true;
FlagN = false;
FlagS = ((bit == 7) && Regs[src].Bit(bit));
Flag5 = Regs[src].Bit(5);
Flag3 = Regs[src].Bit(3);
}
// When doing I* + n bit tests, flags 3 and 5 come from I* + n
// This cooresponds to the high byte of WZ
// This is the same for the (HL) bit tests, except that WZ were not assigned to before the test occurs
public void I_BIT_Func(ushort bit, ushort src)
{
FlagZ = !Regs[src].Bit(bit);
FlagP = FlagZ; // special case
FlagH = true;
FlagN = false;
FlagS = ((bit == 7) && Regs[src].Bit(bit));
Flag5 = Regs[W].Bit(5);
Flag3 = Regs[W].Bit(3);
}
public void SET_Func(ushort bit, ushort src)
{
Regs[src] |= (ushort)(1 << bit);
}
public void RES_Func(ushort bit, ushort src)
{
Regs[src] &= (ushort)(0xFF - (1 << bit));
}
public void ASGN_Func(ushort src, ushort val)
{
Regs[src] = val;
}
public void SLL_Func(ushort src)
{
FlagC = Regs[src].Bit(7);
Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | 0x1);
FlagS = Regs[src].Bit(7);
FlagZ = Regs[src] == 0;
FlagP = TableParity[Regs[src]];
Flag3 = (Regs[src] & 0x08) != 0;
Flag5 = (Regs[src] & 0x20) != 0;
FlagH = false;
FlagN = false;
}
public void SLA_Func(ushort src)
{
FlagC = Regs[src].Bit(7);
Regs[src] = (ushort)((Regs[src] << 1) & 0xFF);
FlagS = Regs[src].Bit(7);
FlagZ = Regs[src] == 0;
FlagP = TableParity[Regs[src]];
Flag3 = (Regs[src] & 0x08) != 0;
Flag5 = (Regs[src] & 0x20) != 0;
FlagH = false;
FlagN = false;
}
public void SRA_Func(ushort src)
{
FlagC = Regs[src].Bit(0);
ushort temp = (ushort)(Regs[src] & 0x80); // MSB doesn't change in this operation
Regs[src] = (ushort)((Regs[src] >> 1) | temp);
FlagS = Regs[src].Bit(7);
FlagZ = Regs[src] == 0;
FlagP = TableParity[Regs[src]];
Flag3 = (Regs[src] & 0x08) != 0;
Flag5 = (Regs[src] & 0x20) != 0;
FlagH = false;
FlagN = false;
}
public void SRL_Func(ushort src)
{
FlagC = Regs[src].Bit(0) ? true : false;
Regs[src] = (ushort)(Regs[src] >> 1);
FlagS = Regs[src].Bit(7);
FlagZ = Regs[src] == 0;
FlagP = TableParity[Regs[src]];
Flag3 = (Regs[src] & 0x08) != 0;
Flag5 = (Regs[src] & 0x20) != 0;
FlagH = false;
FlagN = false;
}
public void CPL_Func(ushort src)
{
Regs[src] = (ushort)((~Regs[src]) & 0xFF);
FlagH = true;
FlagN = true;
Flag3 = (Regs[src] & 0x08) != 0;
Flag5 = (Regs[src] & 0x20) != 0;
}
public void CCF_Func(ushort src)
{
FlagH = FlagC;
FlagC = !FlagC;
FlagN = false;
Flag3 = (Regs[src] & 0x08) != 0;
Flag5 = (Regs[src] & 0x20) != 0;
}
public void SCF_Func(ushort src)
{
FlagC = true;
FlagH = false;
FlagN = false;
Flag3 = (Regs[src] & 0x08) != 0;
Flag5 = (Regs[src] & 0x20) != 0;
}
public void AND8_Func(ushort dest, ushort src)
{
Regs[dest] = (ushort)(Regs[dest] & Regs[src]);
FlagZ = Regs[dest] == 0;
FlagC = false;
FlagH = true;
FlagN = false;
Flag3 = (Regs[dest] & 0x08) != 0;
Flag5 = (Regs[dest] & 0x20) != 0;
FlagS = Regs[dest] > 127;
FlagP = TableParity[Regs[dest]];
}
public void OR8_Func(ushort dest, ushort src)
{
Regs[dest] = (ushort)(Regs[dest] | Regs[src]);
FlagZ = Regs[dest] == 0;
FlagC = false;
FlagH = false;
FlagN = false;
Flag3 = (Regs[dest] & 0x08) != 0;
Flag5 = (Regs[dest] & 0x20) != 0;
FlagS = Regs[dest] > 127;
FlagP = TableParity[Regs[dest]];
}
public void XOR8_Func(ushort dest, ushort src)
{
Regs[dest] = (ushort)((Regs[dest] ^ Regs[src]));
FlagZ = Regs[dest] == 0;
FlagC = false;
FlagH = false;
FlagN = false;
Flag3 = (Regs[dest] & 0x08) != 0;
Flag5 = (Regs[dest] & 0x20) != 0;
FlagS = Regs[dest] > 127;
FlagP = TableParity[Regs[dest]];
}
public void CP8_Func(ushort dest, ushort src)
{
int Reg16_d = Regs[dest];
Reg16_d -= Regs[src];
FlagC = Reg16_d.Bit(8);
FlagZ = (Reg16_d & 0xFF) == 0;
ushort ans = (ushort)(Reg16_d & 0xFF);
// redo for half carry flag
Reg16_d = Regs[dest] & 0xF;
Reg16_d -= (Regs[src] & 0xF);
FlagH = Reg16_d.Bit(4);
FlagN = true;
Flag3 = (Regs[src] & 0x08) != 0;
Flag5 = (Regs[src] & 0x20) != 0;
FlagP = (Regs[dest].Bit(7) != Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7));
FlagS = ans > 127;
}
public void RRC_Func(ushort src)
{
bool imm = src == Aim;
if (imm) { src = A; }
FlagC = Regs[src].Bit(0);
Regs[src] = (ushort)((FlagC ? 0x80 : 0) | (Regs[src] >> 1));
if (!imm)
{
FlagS = Regs[src].Bit(7);
FlagZ = Regs[src] == 0;
FlagP = TableParity[Regs[src]];
}
Flag3 = (Regs[src] & 0x08) != 0;
Flag5 = (Regs[src] & 0x20) != 0;
FlagH = false;
FlagN = false;
}
public void RR_Func(ushort src)
{
bool imm = src == Aim;
if (imm) { src = A; }
ushort c = (ushort)(FlagC ? 0x80 : 0);
FlagC = Regs[src].Bit(0);
Regs[src] = (ushort)(c | (Regs[src] >> 1));
if (!imm)
{
FlagS = Regs[src].Bit(7);
FlagZ = Regs[src] == 0;
FlagP = TableParity[Regs[src]];
}
Flag3 = (Regs[src] & 0x08) != 0;
Flag5 = (Regs[src] & 0x20) != 0;
FlagH = false;
FlagN = false;
}
public void RLC_Func(ushort src)
{
bool imm = src == Aim;
if (imm) { src = A; }
ushort c = (ushort)(Regs[src].Bit(7) ? 1 : 0);
FlagC = Regs[src].Bit(7);
Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | c);
if (!imm)
{
FlagS = Regs[src].Bit(7);
FlagZ = Regs[src] == 0;
FlagP = TableParity[Regs[src]];
}
Flag3 = (Regs[src] & 0x08) != 0;
Flag5 = (Regs[src] & 0x20) != 0;
FlagH = false;
FlagN = false;
}
public void RL_Func(ushort src)
{
bool imm = src == Aim;
if (imm) { src = A; }
ushort c = (ushort)(FlagC ? 1 : 0);
FlagC = Regs[src].Bit(7);
Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | c);
if (!imm)
{
FlagS = Regs[src].Bit(7);
FlagZ = Regs[src] == 0;
FlagP = TableParity[Regs[src]];
}
Flag3 = (Regs[src] & 0x08) != 0;
Flag5 = (Regs[src] & 0x20) != 0;
FlagH = false;
FlagN = false;
}
public void INC8_Func(ushort src)
{
int Reg16_d = Regs[src];
Reg16_d += 1;
FlagZ = (Reg16_d & 0xFF) == 0;
ushort ans = (ushort)(Reg16_d & 0xFF);
// redo for half carry flag
Reg16_d = Regs[src] & 0xF;
Reg16_d += 1;
FlagH = Reg16_d.Bit(4);
FlagN = false;
Regs[src] = ans;
FlagS = Regs[src].Bit(7);
FlagP = Regs[src] == 0x80;
Flag3 = (Regs[src] & 0x08) != 0;
Flag5 = (Regs[src] & 0x20) != 0;
}
public void DEC8_Func(ushort src)
{
int Reg16_d = Regs[src];
Reg16_d -= 1;
FlagZ = (Reg16_d & 0xFF) == 0;
ushort ans = (ushort)(Reg16_d & 0xFF);
// redo for half carry flag
Reg16_d = Regs[src] & 0xF;
Reg16_d -= 1;
FlagH = Reg16_d.Bit(4);
FlagN = true;
Regs[src] = ans;
FlagS = Regs[src].Bit(7);
FlagP = Regs[src] == 0x7F;
Flag3 = (Regs[src] & 0x08) != 0;
Flag5 = (Regs[src] & 0x20) != 0;
}
public void INC16_Func(ushort src_l, ushort src_h)
{
int Reg16_d = Regs[src_l] | (Regs[src_h] << 8);
Reg16_d += 1;
Regs[src_l] = (ushort)(Reg16_d & 0xFF);
Regs[src_h] = (ushort)((Reg16_d & 0xFF00) >> 8);
}
public void DEC16_Func(ushort src_l, ushort src_h)
{
int Reg16_d = Regs[src_l] | (Regs[src_h] << 8);
Reg16_d -= 1;
Regs[src_l] = (ushort)(Reg16_d & 0xFF);
Regs[src_h] = (ushort)((Reg16_d & 0xFF00) >> 8);
}
public void ADC8_Func(ushort dest, ushort src)
{
int Reg16_d = Regs[dest];
int c = FlagC ? 1 : 0;
Reg16_d += (Regs[src] + c);
FlagC = Reg16_d.Bit(8);
FlagZ = (Reg16_d & 0xFF) == 0;
ushort ans = (ushort)(Reg16_d & 0xFF);
// redo for half carry flag
Reg16_d = Regs[dest] & 0xF;
Reg16_d += ((Regs[src] & 0xF) + c);
FlagH = Reg16_d.Bit(4);
FlagN = false;
Flag3 = (ans & 0x08) != 0;
Flag5 = (ans & 0x20) != 0;
FlagP = (Regs[dest].Bit(7) == Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7));
FlagS = ans > 127;
Regs[dest] = ans;
}
public void SBC8_Func(ushort dest, ushort src)
{
int Reg16_d = Regs[dest];
int c = FlagC ? 1 : 0;
Reg16_d -= (Regs[src] + c);
FlagC = Reg16_d.Bit(8);
FlagZ = (Reg16_d & 0xFF) == 0;
ushort ans = (ushort)(Reg16_d & 0xFF);
// redo for half carry flag
Reg16_d = Regs[dest] & 0xF;
Reg16_d -= ((Regs[src] & 0xF) + c);
FlagH = Reg16_d.Bit(4);
FlagN = true;
Flag3 = (ans & 0x08) != 0;
Flag5 = (ans & 0x20) != 0;
FlagP = (Regs[dest].Bit(7) != Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7));
FlagS = ans > 127;
Regs[dest] = ans;
}
public void DA_Func(ushort src)
{
byte a = (byte)Regs[src];
byte temp = a;
if (FlagN)
{
if (FlagH || ((a & 0x0F) > 0x09)) { temp -= 0x06; }
if (FlagC || a > 0x99) { temp -= 0x60; }
}
else
{
if (FlagH || ((a & 0x0F) > 0x09)) { temp += 0x06; }
if (FlagC || a > 0x99) { temp += 0x60; }
}
temp &= 0xFF;
FlagC = FlagC || a > 0x99;
FlagZ = temp == 0;
FlagH = ((a ^ temp) & 0x10) != 0;
FlagP = TableParity[temp];
FlagS = temp > 127;
Flag3 = (temp & 0x08) != 0;
Flag5 = (temp & 0x20) != 0;
Regs[src] = temp;
}
// used for signed operations
public void ADDS_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
{
int Reg16_d = Regs[dest_l];
int Reg16_s = Regs[src_l];
Reg16_d += Reg16_s;
ushort temp = 0;
// since this is signed addition, calculate the high byte carry appropriately
// note that flags are unaffected by this operation
if (Reg16_s.Bit(7))
{
if (((Reg16_d & 0xFF) >= Regs[dest_l]))
{
temp = 0xFF;
}
else
{
temp = 0;
}
}
else
{
temp = (ushort)(Reg16_d.Bit(8) ? 1 : 0);
}
ushort ans_l = (ushort)(Reg16_d & 0xFF);
Regs[dest_l] = ans_l;
Regs[dest_h] += temp;
Regs[dest_h] &= 0xFF;
}
public void EXCH_16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
{
ushort temp = Regs[dest_l];
Regs[dest_l] = Regs[src_l];
Regs[src_l] = temp;
temp = Regs[dest_h];
Regs[dest_h] = Regs[src_h];
Regs[src_h] = temp;
}
public void SBC_16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
{
int Reg16_d = Regs[dest_l] | (Regs[dest_h] << 8);
int Reg16_s = Regs[src_l] | (Regs[src_h] << 8);
int c = FlagC ? 1 : 0;
int ans = Reg16_d - Reg16_s - c;
FlagN = true;
FlagC = ans.Bit(16);
FlagP = (Reg16_d.Bit(15) != Reg16_s.Bit(15)) && (Reg16_d.Bit(15) != ans.Bit(15));
FlagS = (ushort)(ans & 0xFFFF) > 32767;
FlagZ = (ans & 0xFFFF) == 0;
Flag3 = (ans & 0x0800) != 0;
Flag5 = (ans & 0x2000) != 0;
// redo for half carry flag
Reg16_d &= 0xFFF;
Reg16_d -= ((Reg16_s & 0xFFF) + c);
FlagH = Reg16_d.Bit(12);
Regs[dest_l] = (ushort)(ans & 0xFF);
Regs[dest_h] = (ushort)((ans >> 8) & 0xFF);
}
public void ADC_16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
{
int Reg16_d = Regs[dest_l] | (Regs[dest_h] << 8);
int Reg16_s = Regs[src_l] | (Regs[src_h] << 8);
int ans = Reg16_d + Reg16_s + (FlagC ? 1 : 0);
FlagH = ((Reg16_d & 0xFFF) + (Reg16_s & 0xFFF) + (FlagC ? 1 : 0)) > 0xFFF;
FlagN = false;
FlagC = ans.Bit(16);
FlagP = (Reg16_d.Bit(15) == Reg16_s.Bit(15)) && (Reg16_d.Bit(15) != ans.Bit(15));
FlagS = (ans & 0xFFFF) > 32767;
FlagZ = (ans & 0xFFFF) == 0;
Flag3 = (ans & 0x0800) != 0;
Flag5 = (ans & 0x2000) != 0;
Regs[dest_l] = (ushort)(ans & 0xFF);
Regs[dest_h] = (ushort)((ans >> 8) & 0xFF);
}
public void NEG_8_Func(ushort src)
{
int Reg16_d = 0;
Reg16_d -= Regs[src];
FlagC = Regs[src] != 0x0;
FlagZ = (Reg16_d & 0xFF) == 0;
FlagP = Regs[src] == 0x80;
FlagS = (Reg16_d & 0xFF) > 127;
ushort ans = (ushort)(Reg16_d & 0xFF);
// redo for half carry flag
Reg16_d = 0;
Reg16_d -= (Regs[src] & 0xF);
FlagH = Reg16_d.Bit(4);
Regs[src] = ans;
FlagN = true;
Flag3 = (ans & 0x08) != 0;
Flag5 = (ans & 0x20) != 0;
}
public void RRD_Func(ushort dest, ushort src)
{
ushort temp1 = Regs[src];
ushort temp2 = Regs[dest];
Regs[dest] = (ushort)(((temp1 & 0x0F) << 4) + ((temp2 & 0xF0) >> 4));
Regs[src] = (ushort)((temp1 & 0xF0) + (temp2 & 0x0F));
temp1 = Regs[src];
FlagS = temp1 > 127;
FlagZ = temp1 == 0;
FlagH = false;
FlagP = TableParity[temp1];
FlagN = false;
Flag3 = (temp1 & 0x08) != 0;
Flag5 = (temp1 & 0x20) != 0;
}
public void RLD_Func(ushort dest, ushort src)
{
ushort temp1 = Regs[src];
ushort temp2 = Regs[dest];
Regs[dest] = (ushort)((temp1 & 0x0F) + ((temp2 & 0x0F) << 4));
Regs[src] = (ushort)((temp1 & 0xF0) + ((temp2 & 0xF0) >> 4));
temp1 = Regs[src];
FlagS = temp1 > 127;
FlagZ = temp1 == 0;
FlagH = false;
FlagP = TableParity[temp1];
FlagN = false;
Flag3 = (temp1 & 0x08) != 0;
Flag5 = (temp1 & 0x20) != 0;
}
// sets flags for LD/R
public void SET_FL_LD_Func()
{
FlagP = (Regs[C] | (Regs[B] << 8)) != 0;
FlagH = false;
FlagN = false;
Flag5 = ((Regs[ALU] + Regs[A]) & 0x02) != 0;
Flag3 = ((Regs[ALU] + Regs[A]) & 0x08) != 0;
}
// set flags for CP/R
public void SET_FL_CP_Func()
{
int Reg8_d = Regs[A];
int Reg8_s = Regs[ALU];
// get half carry flag
byte temp = (byte)((Reg8_d & 0xF) - (Reg8_s & 0xF));
FlagH = temp.Bit(4);
temp = (byte)(Reg8_d - Reg8_s);
FlagN = true;
FlagZ = temp == 0;
FlagS = temp > 127;
FlagP = (Regs[C] | (Regs[B] << 8)) != 0;
temp = (byte)(Reg8_d - Reg8_s - (FlagH ? 1 : 0));
Flag5 = (temp & 0x02) != 0;
Flag3 = (temp & 0x08) != 0;
}
}
}

View File

@ -0,0 +1,8 @@
TODO:
Mode 0 and 2 interrupts
Check T-cycle level memory access timing
Check R register
new tests for WZ Registers
Memory refresh - IR is pushed onto the address bus at instruction start, does anything need this?
Data Bus - For mode zero and 2 interrupts, need a system that uses it to test

View File

@ -0,0 +1,132 @@
using System.Runtime.InteropServices;
using System;
namespace BizHawk.Emulation.Cores.Components.Z80A
{
public partial class Z80A
{
// registers
// note these are not constants. When shadows are used, they will be changed accordingly
public ushort PCl = 0;
public ushort PCh = 1;
public ushort SPl = 2;
public ushort SPh = 3;
public ushort A = 4;
public ushort F = 5;
public ushort B = 6;
public ushort C = 7;
public ushort D = 8;
public ushort E = 9;
public ushort H = 10;
public ushort L = 11;
public ushort W = 12;
public ushort Z = 13;
public ushort Aim = 14; // use this indicator for RLCA etc., since the Z flag is reset on those
public ushort Ixl = 15;
public ushort Ixh = 16;
public ushort Iyl = 17;
public ushort Iyh = 18;
public ushort Int = 19;
public ushort R = 20;
public ushort I = 21;
public ushort ZERO = 22; // it is convenient to have a register that is always zero, to reuse instructions
public ushort ALU = 23; // This will be temporary arthimatic storage
// shadow registers
public ushort A_s = 24;
public ushort F_s = 25;
public ushort B_s = 26;
public ushort C_s = 27;
public ushort D_s = 28;
public ushort E_s = 29;
public ushort H_s = 30;
public ushort L_s = 31;
public ushort[] Regs = new ushort[36];
public bool FlagI;
public bool FlagC
{
get { return (Regs[5] & 0x01) != 0; }
set { Regs[5] = (ushort)((Regs[5] & ~0x01) | (value ? 0x01 : 0x00)); }
}
public bool FlagN
{
get { return (Regs[5] & 0x02) != 0; }
set { Regs[5] = (ushort)((Regs[5] & ~0x02) | (value ? 0x02 : 0x00)); }
}
public bool FlagP
{
get { return (Regs[5] & 0x04) != 0; }
set { Regs[5] = (ushort)((Regs[5] & ~0x04) | (value ? 0x04 : 0x00)); }
}
public bool Flag3
{
get { return (Regs[5] & 0x08) != 0; }
set { Regs[5] = (ushort)((Regs[5] & ~0x08) | (value ? 0x08 : 0x00)); }
}
public bool FlagH
{
get { return (Regs[5] & 0x10) != 0; }
set { Regs[5] = (ushort)((Regs[5] & ~0x10) | (value ? 0x10 : 0x00)); }
}
public bool Flag5
{
get { return (Regs[5] & 0x20) != 0; }
set { Regs[5] = (ushort)((Regs[5] & ~0x20) | (value ? 0x20 : 0x00)); }
}
public bool FlagZ
{
get { return (Regs[5] & 0x40) != 0; }
set { Regs[5] = (ushort)((Regs[5] & ~0x40) | (value ? 0x40 : 0x00)); }
}
public bool FlagS
{
get { return (Regs[5] & 0x80) != 0; }
set { Regs[5] = (ushort)((Regs[5] & ~0x80) | (value ? 0x80 : 0x00)); }
}
public ushort RegPC
{
get { return (ushort)(Regs[0] | (Regs[1] << 8)); }
set
{
Regs[0] = (ushort)(value & 0xFF);
Regs[1] = (ushort)((value >> 8) & 0xFF);
}
}
private void ResetRegisters()
{
for (int i=0; i < 36; i++)
{
Regs[i] = 0;
}
}
private bool[] TableParity;
private void InitTableParity()
{
TableParity = new bool[256];
for (int i = 0; i < 256; ++i)
{
int Bits = 0;
for (int j = 0; j < 8; ++j)
{
Bits += (i >> j) & 1;
}
TableParity[i] = (Bits & 1) == 0;
}
}
}
}

View File

@ -0,0 +1,581 @@
using System;
namespace BizHawk.Emulation.Cores.Components.Z80A
{
public partial class Z80A
{
// this contains the vectors of instrcution operations
// NOTE: This list is NOT confirmed accurate for each individual cycle
private void NOP_()
{
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
OP };
}
// NOTE: In a real Z80, this operation just flips a switch to choose between 2 registers
// but it's simpler to emulate just by exchanging the register with it's shadow
private void EXCH_()
{
cur_instr = new ushort[]
{EXCH,
IDLE,
IDLE,
OP };
}
private void EXX_()
{
cur_instr = new ushort[]
{EXX,
IDLE,
IDLE,
OP };
}
// this exchanges 2 16 bit registers
private void EXCH_16_(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{EXCH_16, dest_l, dest_h, src_l, src_h,
IDLE,
IDLE,
OP };
}
private void INC_16(ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
INC16, src_l, src_h,
IDLE,
OP };
}
private void DEC_16(ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
DEC16, src_l, src_h,
IDLE,
IDLE,
OP };
}
// this is done in two steps technically, but the flags don't work out using existing funcitons
// so let's use a different function since it's an internal operation anyway
private void ADD_16(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
TR16, Z, W, dest_l, dest_h,
INC16, Z, W,
IDLE,
IDLE,
ADD16, dest_l, dest_h, src_l, src_h,
IDLE,
IDLE,
OP };
}
private void REG_OP(ushort operation, ushort dest, ushort src)
{
cur_instr = new ushort[]
{operation, dest, src,
IDLE,
IDLE,
OP };
}
// Operations using the I and R registers take one T-cycle longer
private void REG_OP_IR(ushort operation, ushort dest, ushort src)
{
cur_instr = new ushort[]
{operation, dest, src,
IDLE,
IDLE,
IDLE,
OP };
}
// note: do not use DEC here since no flags are affected by this operation
private void DJNZ_()
{
if ((Regs[B] - 1) != 0)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
ASGN, B, (ushort)((Regs[B] - 1) & 0xFF),
IDLE,
RD, Z, PCl, PCh,
IDLE,
INC16, PCl, PCh,
IDLE,
ASGN, W, 0,
IDLE,
ADDS, PCl, PCh, Z, W,
TR16, Z, W, PCl, PCh,
OP };
}
else
{
cur_instr = new ushort[]
{IDLE,
ASGN, B, (ushort)((Regs[B] - 1) & 0xFF),
IDLE,
RD, ALU, PCl, PCh,
IDLE,
INC16, PCl, PCh,
IDLE,
OP };
}
}
private void HALT_()
{
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
HALT };
}
private void JR_COND(bool cond)
{
if (cond)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
RD, Z, PCl, PCh,
INC16, PCl, PCh,
IDLE,
IDLE,
ASGN, W, 0,
IDLE,
ADDS, PCl, PCh, Z, W,
TR16, Z, W, PCl, PCh,
IDLE,
OP };
}
else
{
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
RD, ALU, PCl, PCh,
IDLE,
INC16, PCl, PCh,
OP };
}
}
private void JP_COND(bool cond)
{
if (cond)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
RD, Z, PCl, PCh,
INC16, PCl, PCh,
RD, W, PCl, PCh,
IDLE,
INC16, PCl, PCh,
TR16, PCl, PCh, Z, W,
IDLE,
OP };
}
else
{
cur_instr = new ushort[]
{IDLE,
IDLE,
RD, Z, PCl, PCh,
INC16, PCl, PCh,
IDLE,
RD, W, PCl, PCh,
INC16, PCl, PCh,
IDLE,
IDLE,
OP };
}
}
private void RET_()
{
cur_instr = new ushort[]
{IDLE,
IDLE,
RD, Z, SPl, SPh,
INC16, SPl, SPh,
IDLE,
IDLE,
RD, W, SPl, SPh,
INC16, SPl, SPh,
TR16, PCl, PCh, Z, W,
OP };
}
private void RETI_()
{
cur_instr = new ushort[]
{IDLE,
IDLE,
RD, Z, SPl, SPh,
INC16, SPl, SPh,
IDLE,
IDLE,
RD, W, SPl, SPh,
INC16, SPl, SPh,
TR16, PCl, PCh, Z, W,
OP };
}
private void RETN_()
{
cur_instr = new ushort[]
{IDLE,
IDLE,
RD, Z, SPl, SPh,
INC16, SPl, SPh,
IDLE,
RD, W, SPl, SPh,
INC16, SPl, SPh,
EI_RETN,
TR16, PCl, PCh, Z, W,
OP };
}
private void RET_COND(bool cond)
{
if (cond)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
RD, Z, SPl, SPh,
INC16, SPl, SPh,
IDLE,
IDLE,
RD, W, SPl, SPh,
INC16, SPl, SPh,
IDLE,
TR16, PCl, PCh, Z, W,
OP };
}
else
{
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
IDLE,
OP };
}
}
private void CALL_COND(bool cond)
{
if (cond)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
RD, Z, PCl, PCh,
INC16, PCl, PCh,
IDLE,
RD, W, PCl, PCh,
INC16, PCl, PCh,
IDLE,
DEC16, SPl, SPh,
IDLE,
WR, SPl, SPh, PCh,
DEC16, SPl, SPh,
WR, SPl, SPh, PCl,
IDLE,
TR, PCl, Z,
TR, PCh, W,
OP };
}
else
{
cur_instr = new ushort[]
{IDLE,
IDLE,
RD, Z, PCl, PCh,
IDLE,
INC16, PCl, PCh,
IDLE,
RD, W, PCl, PCh,
IDLE,
INC16, PCl, PCh,
OP };
}
}
private void INT_OP(ushort operation, ushort src)
{
cur_instr = new ushort[]
{operation, src,
IDLE,
IDLE,
OP };
}
private void BIT_OP(ushort operation, ushort bit, ushort src)
{
cur_instr = new ushort[]
{operation, bit, src,
IDLE,
IDLE,
OP };
}
private void PUSH_(ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
DEC16, SPl, SPh,
IDLE,
WR, SPl, SPh, src_h,
IDLE,
DEC16, SPl, SPh,
IDLE,
WR, SPl, SPh, src_l,
IDLE,
OP };
}
private void POP_(ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
RD, src_l, SPl, SPh,
IDLE,
INC16, SPl, SPh,
IDLE,
RD, src_h, SPl, SPh,
IDLE,
INC16, SPl, SPh,
IDLE,
OP };
}
private void RST_(ushort n)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
DEC16, SPl, SPh,
WR, SPl, SPh, PCh,
DEC16, SPl, SPh,
WR, SPl, SPh, PCl,
IDLE,
ASGN, Z, n,
ASGN, W, 0,
TR16, PCl, PCh, Z, W,
OP };
}
private void PREFIX_(ushort src)
{
cur_instr = new ushort[]
{PREFIX, src,
IDLE,
IDLE,
OP };
}
private void PREFETCH_(ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{TR16, Z, W, src_l, src_h,
ADDS, Z, W, ALU, ZERO,
IDLE,
OP };
}
private void DI_()
{
cur_instr = new ushort[]
{DI,
IDLE,
IDLE,
OP };
}
private void EI_()
{
cur_instr = new ushort[]
{EI,
IDLE,
IDLE,
OP };
}
private void JP_16(ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{TR, PCl, src_l,
IDLE,
TR, PCh, src_h,
OP };
}
private void LD_SP_16(ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
TR, SPl, src_l,
TR, SPh, src_h,
IDLE,
OP };
}
private void JAM_()
{
cur_instr = new ushort[]
{JAM,
IDLE,
IDLE,
IDLE };
}
private void OUT_()
{
cur_instr = new ushort[]
{IDLE,
RD, ALU, PCl, PCh,
IDLE,
INC16, PCl, PCh,
TR, W, A,
OUT, ALU, A,
TR, Z, ALU,
INC16, Z, ALU,
IDLE,
IDLE,
OP};
}
private void OUT_REG_(ushort dest, ushort src)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
OUT, dest, src,
IDLE,
TR16, Z, W, C, B,
INC16, Z, W,
IDLE,
OP};
}
private void IN_()
{
cur_instr = new ushort[]
{IDLE,
RD, ALU, PCl, PCh,
IDLE,
INC16, PCl, PCh,
TR, W, A,
IN, A, ALU,
TR, Z, ALU,
INC16, Z, W,
IDLE,
IDLE,
OP};
}
private void IN_REG_(ushort dest, ushort src)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
IN, dest, src,
IDLE,
TR16, Z, W, C, B,
INC16, Z, W,
IDLE,
OP};
}
private void REG_OP_16_(ushort op, ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
TR16, Z, W, dest_l, dest_h,
INC16, Z, W,
IDLE,
IDLE,
op, dest_l, dest_h, src_l, src_h,
IDLE,
IDLE,
OP};
}
private void INT_MODE_(ushort src)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
INT_MODE, src,
OP };
}
private void RRD_()
{
cur_instr = new ushort[]
{IDLE,
IDLE,
TR16, Z, W, L, H,
IDLE,
RD, ALU, Z, W,
IDLE,
RRD, ALU, A,
IDLE,
WR, Z, W, ALU,
IDLE,
INC16, Z, W,
IDLE,
IDLE,
OP };
}
private void RLD_()
{
cur_instr = new ushort[]
{IDLE,
IDLE,
TR16, Z, W, L, H,
IDLE,
RD, ALU, Z, W,
IDLE,
RLD, ALU, A,
IDLE,
WR, Z, W, ALU,
IDLE,
INC16, Z, W,
IDLE,
IDLE,
OP };
}
}
}

View File

@ -0,0 +1,478 @@
namespace BizHawk.Emulation.Cores.Components.Z80A
{
public partial class Z80A
{
private void INT_OP_IND(ushort operation, ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
RD, ALU, src_l, src_h,
IDLE,
operation, ALU,
IDLE,
WR, src_l, src_h, ALU,
IDLE,
IDLE,
OP };
}
private void BIT_OP_IND(ushort operation, ushort bit, ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
RD, ALU, src_l, src_h,
IDLE,
operation, bit, ALU,
IDLE,
WR, src_l, src_h, ALU,
IDLE,
IDLE,
OP };
}
// Note that this operation uses I_BIT, same as indexed BIT.
// This is where the strange behaviour in Flag bits 3 and 5 come from.
// normally WZ contain I* + n when doing I_BIT ops, but here we use that code path
// even though WZ is not assigned to, letting it's value from other operations show through
private void BIT_TE_IND(ushort operation, ushort bit, ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
RD, ALU, src_l, src_h,
IDLE,
I_BIT, bit, ALU,
IDLE,
OP };
}
private void REG_OP_IND_INC(ushort operation, ushort dest, ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
RD, ALU, src_l, src_h,
IDLE,
operation, dest, ALU,
INC16, src_l, src_h,
OP };
}
private void REG_OP_IND(ushort operation, ushort dest, ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
TR16, Z, W, src_l, src_h,
RD, ALU, Z, W,
INC16, Z, W,
operation, dest, ALU,
OP };
}
private void LD_16_IND_nn(ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
RD, Z, PCl, PCh,
IDLE,
INC16, PCl, PCh,
IDLE,
RD, W, PCl, PCh,
IDLE,
INC16, PCl, PCh,
IDLE,
WR, Z, W, src_l,
IDLE,
INC16, Z, W,
IDLE,
WR, Z, W, src_h,
IDLE,
OP };
}
private void LD_IND_16_nn(ushort dest_l, ushort dest_h)
{
cur_instr = new ushort[]
{IDLE,
RD, Z, PCl, PCh,
IDLE,
INC16, PCl, PCh,
IDLE,
RD, W, PCl, PCh,
IDLE,
INC16, PCl, PCh,
IDLE,
RD, dest_l, Z, W,
IDLE,
INC16, Z, W,
IDLE,
RD, dest_h, Z, W,
IDLE,
OP };
}
private void LD_8_IND_nn(ushort src)
{
cur_instr = new ushort[]
{IDLE,
RD, Z, PCl, PCh,
IDLE,
INC16, PCl, PCh,
IDLE,
RD, W, PCl, PCh,
IDLE,
INC16, PCl, PCh,
IDLE,
WR, Z, W, src,
INC16, Z, W,
TR, W, A,
OP };
}
private void LD_IND_8_nn(ushort dest)
{
cur_instr = new ushort[]
{IDLE,
RD, Z, PCl, PCh,
IDLE,
INC16, PCl, PCh,
IDLE,
RD, W, PCl, PCh,
IDLE,
INC16, PCl, PCh,
IDLE,
RD, dest, Z, W,
IDLE,
INC16, Z, W,
OP };
}
private void LD_8_IND(ushort dest_l, ushort dest_h, ushort src)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
TR16, Z, W, dest_l, dest_h,
WR, Z, W, src,
INC16, Z, W,
TR, W, A,
OP };
}
private void LD_8_IND_IND(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
RD, ALU, src_l, src_h,
IDLE,
INC16, src_l, src_h,
IDLE,
WR, dest_l, dest_h, ALU,
IDLE,
OP };
}
private void LD_IND_8_INC(ushort dest, ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
RD, dest, src_l, src_h,
IDLE,
INC16, src_l, src_h,
OP };
}
private void LD_IND_8_DEC(ushort dest, ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
RD, dest, src_l, src_h,
IDLE,
DEC16, src_l, src_h,
IDLE,
OP };
}
private void LD_IND_16(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
RD, dest_l, src_l, src_h,
IDLE,
INC16, src_l, src_h,
RD, dest_h, src_l, src_h,
IDLE,
INC16, src_l, src_h,
OP };
}
private void INC_8_IND(ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
RD, ALU, src_l, src_h,
IDLE,
INC8, ALU,
IDLE,
WR, src_l, src_h, ALU,
IDLE,
IDLE,
OP };
}
private void DEC_8_IND(ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
RD, ALU, src_l, src_h,
IDLE,
DEC8, ALU,
IDLE,
WR, src_l, src_h, ALU,
IDLE,
IDLE,
OP };
}
// NOTE: WZ implied for the wollowing 3 functions
private void I_INT_OP(ushort operation, ushort dest)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
RD, ALU, Z, W,
IDLE,
operation, ALU,
IDLE,
WR, Z, W, ALU,
IDLE,
TR, dest, ALU,
IDLE,
OP };
}
private void I_BIT_OP(ushort operation, ushort bit, ushort dest)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
RD, ALU, Z, W,
IDLE,
operation, bit, ALU,
IDLE,
WR, Z, W, ALU,
IDLE,
TR, dest, ALU,
IDLE,
OP };
}
private void I_BIT_TE(ushort bit)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
RD, ALU, Z, W,
IDLE,
I_BIT, bit, ALU,
IDLE,
OP };
}
private void I_OP_n(ushort operation, ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
RD, ALU, PCl, PCh,
INC16, PCl, PCh,
IDLE,
TR16, Z, W, src_l, src_h,
IDLE,
ADDS, Z, W, ALU, ZERO,
IDLE,
RD, ALU, Z, W,
IDLE,
IDLE,
operation, ALU,
IDLE,
IDLE,
IDLE,
WR, Z, W, ALU,
IDLE,
OP };
}
private void I_OP_n_n(ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
RD, ALU, PCl, PCh,
INC16, PCl, PCh,
IDLE,
TR16, Z, W, src_l, src_h,
IDLE,
ADDS, Z, W, ALU, ZERO,
IDLE,
RD, ALU, PCl, PCh,
INC16, PCl, PCh,
IDLE,
WR, Z, W, ALU,
IDLE,
OP };
}
private void I_REG_OP_IND_n(ushort operation, ushort dest, ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
RD, ALU, PCl, PCh,
IDLE,
INC16, PCl, PCh,
IDLE,
TR16, Z, W, src_l, src_h,
IDLE,
ADDS, Z, W, ALU, ZERO,
IDLE,
RD, ALU, Z, W,
IDLE,
operation, dest, ALU,
IDLE,
OP };
}
private void I_LD_8_IND_n(ushort dest_l, ushort dest_h, ushort src)
{
cur_instr = new ushort[]
{IDLE,
RD, ALU, PCl, PCh,
IDLE,
INC16, PCl, PCh,
IDLE,
TR16, Z, W, dest_l, dest_h,
IDLE,
ADDS, Z, W, ALU, ZERO,
IDLE,
WR, Z, W, src,
IDLE,
IDLE,
IDLE,
IDLE,
OP };
}
private void LD_OP_R(ushort operation, ushort repeat_instr)
{
cur_instr = new ushort[]
{RD, ALU, L, H,
IDLE,
WR, E, D, ALU,
IDLE,
operation, L, H,
IDLE,
operation, E, D,
IDLE,
DEC16, C, B,
SET_FL_LD,
IDLE,
OP_R, 0, operation, repeat_instr };
}
private void CP_OP_R(ushort operation, ushort repeat_instr)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
RD, ALU, L, H,
operation, L, H,
IDLE,
IDLE,
DEC16, C, B,
SET_FL_CP,
IDLE,
operation, Z, W,
IDLE,
OP_R, 1, operation, repeat_instr };
}
private void IN_OP_R(ushort operation, ushort repeat_instr)
{
cur_instr = new ushort[]
{IN, ALU, C,
IDLE,
WR, L, H, ALU,
IDLE,
operation, L, H,
IDLE,
TR16, Z, W, C, B,
operation, Z, W,
IDLE,
DEC8, B,
IDLE,
OP_R, 2, operation, repeat_instr };
}
private void OUT_OP_R(ushort operation, ushort repeat_instr)
{
cur_instr = new ushort[]
{RD, ALU, L, H,
IDLE,
OUT, C, ALU,
IDLE,
IDLE,
operation, L, H,
DEC8, B,
IDLE,
TR16, Z, W, C, B,
operation, Z, W,
IDLE,
OP_R, 3, operation, repeat_instr };
}
// this is an indirect change of a a 16 bit register with memory
private void EXCH_16_IND_(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
{
cur_instr = new ushort[]
{IDLE,
IDLE,
RD, Z, dest_l, dest_h,
IDLE,
IDLE,
I_RD, W, dest_l, dest_h, 1,
IDLE,
IDLE,
WR, dest_l, dest_h, src_l,
IDLE,
IDLE,
I_WR, dest_l, dest_h, 1, src_h,
IDLE,
IDLE,
TR16, src_l, src_h, Z, W,
IDLE,
IDLE,
IDLE,
OP };
}
}
}

View File

@ -0,0 +1,704 @@
using System;
using System.Globalization;
using System.IO;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Common.NumberExtensions;
// Z80A CPU
namespace BizHawk.Emulation.Cores.Components.Z80A
{
public sealed partial class Z80A
{
// operations that can take place in an instruction
public const ushort IDLE = 0;
public const ushort OP = 1;
public const ushort OP_R = 2; // used for repeating operations
public const ushort HALT = 3;
public const ushort RD = 4;
public const ushort WR = 5;
public const ushort I_RD = 6;
public const ushort I_WR = 7;
public const ushort TR = 8;
public const ushort TR16 = 9;
public const ushort ADD16 = 10;
public const ushort ADD8 = 11;
public const ushort SUB8 = 12;
public const ushort ADC8 = 13;
public const ushort SBC8 = 14;
public const ushort SBC16 = 15;
public const ushort ADC16 = 16;
public const ushort INC16 = 17;
public const ushort INC8 = 18;
public const ushort DEC16 = 19;
public const ushort DEC8 = 20;
public const ushort RLC = 21;
public const ushort RL = 22;
public const ushort RRC = 23;
public const ushort RR = 24;
public const ushort CPL = 25;
public const ushort DA = 26;
public const ushort SCF = 27;
public const ushort CCF = 28;
public const ushort AND8 = 29;
public const ushort XOR8 = 30;
public const ushort OR8 = 31;
public const ushort CP8 = 32;
public const ushort SLA = 33;
public const ushort SRA = 34;
public const ushort SRL = 35;
public const ushort SLL = 36;
public const ushort BIT = 37;
public const ushort RES = 38;
public const ushort SET = 39;
public const ushort EI = 40;
public const ushort DI = 41;
public const ushort EXCH = 42;
public const ushort EXX = 43;
public const ushort EXCH_16 = 44;
public const ushort PREFIX = 45;
public const ushort PREFETCH = 46;
public const ushort ASGN = 47;
public const ushort ADDS = 48; // signed 16 bit operation used in 2 instructions
public const ushort JAM = 49; // all undocumented opcodes jam the machine
public const ushort EI_RETN = 50;
public const ushort EI_RETI = 51; // reti has no delay in interrupt enable
public const ushort OUT = 52;
public const ushort IN = 53;
public const ushort NEG = 54;
public const ushort INT_MODE = 55;
public const ushort RRD = 56;
public const ushort RLD = 57;
public const ushort SET_FL_LD = 58;
public const ushort SET_FL_CP = 59;
public const ushort I_BIT = 60;
public const ushort HL_BIT = 61;
public Z80A()
{
Reset();
InitTableParity();
}
public void Reset()
{
ResetRegisters();
ResetInterrupts();
TotalExecutedCycles = 0;
cur_instr = new ushort[] { OP };
NO_prefix = true;
}
public IMemoryCallbackSystem MemoryCallbacks { get; set; }
// Memory Access
public Func<ushort, bool, byte> FetchMemory;
public Func<ushort, byte> ReadMemory;
public Action<ushort, byte> WriteMemory;
public Func<ushort, byte> PeekMemory;
public Func<ushort, byte> DummyReadMemory;
// Hardware I/O Port Access
public Func<ushort, byte> ReadHardware;
public Action<ushort, byte> WriteHardware;
//this only calls when the first byte of an instruction is fetched.
public Action<ushort> OnExecFetch;
public void UnregisterMemoryMapper()
{
ReadMemory = null;
WriteMemory = null;
PeekMemory = null;
DummyReadMemory = null;
ReadHardware = null;
WriteHardware = null;
}
public void SetCallbacks
(
Func<ushort, byte> ReadMemory,
Func<ushort, byte> DummyReadMemory,
Func<ushort, byte> PeekMemory,
Action<ushort, byte> WriteMemory,
Func<ushort, byte> ReadHardware,
Action<ushort, byte> WriteHardware
)
{
this.ReadMemory = ReadMemory;
this.DummyReadMemory = DummyReadMemory;
this.PeekMemory = PeekMemory;
this.WriteMemory = WriteMemory;
this.ReadHardware = ReadHardware;
this.WriteHardware = WriteHardware;
}
// Execute instructions
public void ExecuteOne()
{
if (Regs[A] > 255) { Console.WriteLine(RegPC); }
switch (cur_instr[instr_pntr++])
{
case IDLE:
// do nothing
break;
case OP:
// Read the opcode of the next instruction
if (EI_pending > 0 && NO_prefix)
{
EI_pending--;
if (EI_pending == 0)
{
IFF1 = IFF2 = true;
}
}
// Process interrupt requests.
if (nonMaskableInterruptPending && NO_prefix)
{
nonMaskableInterruptPending = false;
if (TraceCallback != null)
{
TraceCallback(new TraceInfo
{
Disassembly = "====NMI====",
RegisterInfo = ""
});
}
iff2 = iff1;
iff1 = false;
NMI_();
NMICallback();
}
else if (iff1 && FlagI && NO_prefix)
{
iff1 = iff2 = false;
EI_pending = 0;
if (TraceCallback != null)
{
TraceCallback(new TraceInfo
{
Disassembly = "====IRQ====",
RegisterInfo = ""
});
}
switch (interruptMode)
{
case 0:
// Requires something to be pushed onto the data bus
// we'll assume it's a zero for now
INTERRUPT_0(0);
break;
case 1:
INTERRUPT_1();
break;
case 2:
// Low byte of interrupt vector comes from data bus
// We'll assume it's zero for now
INTERRUPT_2(0);
break;
}
IRQCallback();
}
else
{
if (OnExecFetch != null) OnExecFetch(RegPC);
if (TraceCallback != null && NO_prefix) TraceCallback(State());
FetchInstruction(ReadMemory(RegPC++));
}
instr_pntr = 0;
Regs[R]++;
Regs[R] &= 0xFF;
break;
case OP_R:
// determine if we repeat based on what operation we are doing
// single execution versions also come here, but never repeat
ushort temp1 = cur_instr[instr_pntr++];
ushort temp2 = cur_instr[instr_pntr++];
ushort temp3 = cur_instr[instr_pntr++];
bool repeat = false;
int Reg16_d = Regs[C] | (Regs[B] << 8);
switch (temp1)
{
case 0:
repeat = Reg16_d != 0;
break;
case 1:
repeat = (Reg16_d != 0) && !FlagZ;
break;
case 2:
repeat = Regs[B] != 0;
break;
case 3:
repeat = Regs[B] != 0;
break;
}
// if we repeat, we do a 5 cycle refresh which decrements PC by 2
// if we don't repeat, continue on as a normal opcode fetch
if (repeat && temp3 > 0)
{
cur_instr = new ushort[]
{IDLE,
DEC16, PCl, PCh,
IDLE,
DEC16, PCl, PCh,
OP };
// adjust WZ register accordingly
switch (temp1)
{
case 0:
// TEST: PC before or after the instruction?
Regs[Z] = Regs[PCl];
Regs[W] = Regs[PCh];
INC16_Func(Z, W);
break;
case 1:
// TEST: PC before or after the instruction?
Regs[Z] = Regs[PCl];
Regs[W] = Regs[PCh];
INC16_Func(Z, W);
break;
case 2:
// Nothing
break;
case 3:
// Nothing
break;
}
}
else
{
// Interrupts can occur at this point, so process them accordingly
// Read the opcode of the next instruction
if (EI_pending > 0 && NO_prefix)
{
EI_pending--;
if (EI_pending == 0)
{
IFF1 = IFF2 = true;
}
}
// Process interrupt requests.
if (nonMaskableInterruptPending && NO_prefix)
{
nonMaskableInterruptPending = false;
if (TraceCallback != null)
{
TraceCallback(new TraceInfo
{
Disassembly = "====NMI====",
RegisterInfo = ""
});
}
iff2 = iff1;
iff1 = false;
NMI_();
NMICallback();
}
else if (iff1 && FlagI && NO_prefix)
{
iff1 = iff2 = false;
EI_pending = 0;
if (TraceCallback != null)
{
TraceCallback(new TraceInfo
{
Disassembly = "====IRQ====",
RegisterInfo = ""
});
}
switch (interruptMode)
{
case 0:
// Requires something to be pushed onto the data bus
// we'll assume it's a zero for now
INTERRUPT_0(0);
break;
case 1:
INTERRUPT_1();
break;
case 2:
// Low byte of interrupt vector comes from data bus
// We'll assume it's zero for now
INTERRUPT_2(0);
break;
}
IRQCallback();
}
else
{
if (OnExecFetch != null) OnExecFetch(RegPC);
if (TraceCallback != null) TraceCallback(State());
FetchInstruction(ReadMemory(RegPC++));
Regs[R]++;
Regs[R] &= 0xFF;
}
}
instr_pntr = 0;
break;
case HALT:
halted = true;
if (EI_pending > 0 && NO_prefix)
{
EI_pending--;
if (EI_pending == 0)
{
IFF1 = IFF2 = true;
}
}
// Process interrupt requests.
if (nonMaskableInterruptPending && NO_prefix)
{
nonMaskableInterruptPending = false;
if (TraceCallback != null)
{
TraceCallback(new TraceInfo
{
Disassembly = "====NMI====",
RegisterInfo = ""
});
}
iff2 = iff1;
iff1 = false;
NMI_();
NMICallback();
halted = false;
}
else if (iff1 && FlagI && NO_prefix)
{
iff1 = iff2 = false;
EI_pending = 0;
if (TraceCallback != null)
{
TraceCallback(new TraceInfo
{
Disassembly = "====IRQ====",
RegisterInfo = ""
});
}
switch (interruptMode)
{
case 0:
// Requires something to be pushed onto the data bus
// we'll assume it's a zero for now
INTERRUPT_0(0);
break;
case 1:
INTERRUPT_1();
break;
case 2:
// Low byte of interrupt vector comes from data bus
// We'll assume it's zero for now
INTERRUPT_2(0);
break;
}
IRQCallback();
halted = false;
}
else
{
Regs[R]++;
Regs[R] &= 0xFF;
cur_instr = new ushort[]
{IDLE,
IDLE,
IDLE,
HALT };
}
instr_pntr = 0;
break;
case RD:
Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case WR:
Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case I_RD:
I_Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case I_WR:
I_Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case TR:
TR_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case TR16:
TR16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case ADD16:
ADD16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case ADD8:
ADD8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case SUB8:
SUB8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case ADC8:
ADC8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case ADC16:
ADC_16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case SBC8:
SBC8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case SBC16:
SBC_16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case INC16:
INC16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case INC8:
INC8_Func(cur_instr[instr_pntr++]);
break;
case DEC16:
DEC16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case DEC8:
DEC8_Func(cur_instr[instr_pntr++]);
break;
case RLC:
RLC_Func(cur_instr[instr_pntr++]);
break;
case RL:
RL_Func(cur_instr[instr_pntr++]);
break;
case RRC:
RRC_Func(cur_instr[instr_pntr++]);
break;
case RR:
RR_Func(cur_instr[instr_pntr++]);
break;
case CPL:
CPL_Func(cur_instr[instr_pntr++]);
break;
case DA:
DA_Func(cur_instr[instr_pntr++]);
break;
case SCF:
SCF_Func(cur_instr[instr_pntr++]);
break;
case CCF:
CCF_Func(cur_instr[instr_pntr++]);
break;
case AND8:
AND8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case XOR8:
XOR8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case OR8:
OR8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case CP8:
CP8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case SLA:
SLA_Func(cur_instr[instr_pntr++]);
break;
case SRA:
SRA_Func(cur_instr[instr_pntr++]);
break;
case SRL:
SRL_Func(cur_instr[instr_pntr++]);
break;
case SLL:
SLL_Func(cur_instr[instr_pntr++]);
break;
case BIT:
BIT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case I_BIT:
I_BIT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case RES:
RES_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case SET:
SET_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case EI:
EI_pending = 2;
break;
case DI:
IFF1 = IFF2 = false;
break;
case EXCH:
EXCH_16_Func(F_s, A_s, F, A);
break;
case EXX:
EXCH_16_Func(C_s, B_s, C, B);
EXCH_16_Func(E_s, D_s, E, D);
EXCH_16_Func(L_s, H_s, L, H);
break;
case EXCH_16:
EXCH_16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case PREFIX:
ushort prefix_src = cur_instr[instr_pntr++];
NO_prefix = false;
if (prefix_src == CBpre) { CB_prefix = true; }
if (prefix_src == EXTDpre) { EXTD_prefix = true; }
if (prefix_src == IXpre) { IX_prefix = true; }
if (prefix_src == IYpre) { IY_prefix = true; }
if (prefix_src == IXCBpre) { IXCB_prefix = true; IXCB_prefetch = true; }
if (prefix_src == IYCBpre) { IYCB_prefix = true; IYCB_prefetch = true; }
Regs[R]++;
Regs[R] &= 0xFF;
break;
case ASGN:
ASGN_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case ADDS:
ADDS_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case JAM:
jammed = true;
instr_pntr--;
break;
case EI_RETI:
// NOTE: This is needed for systems using multiple interrupt sources, it triggers the next interrupt
// Not currently implemented here
break;
case EI_RETN:
iff1 = iff2;
break;
case OUT:
OUT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case IN:
IN_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case NEG:
NEG_8_Func(cur_instr[instr_pntr++]);
break;
case INT_MODE:
interruptMode = cur_instr[instr_pntr++];
break;
case RRD:
RRD_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case RLD:
RLD_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
case SET_FL_LD:
SET_FL_LD_Func();
break;
case SET_FL_CP:
SET_FL_CP_Func();
break;
}
totalExecutedCycles++;
}
// tracer stuff
public Action<TraceInfo> TraceCallback;
public string TraceHeader
{
get { return "Z80A: PC, machine code, mnemonic, operands, registers (AF, BC, DE, HL, IX, IY, SP, Cy), flags (CNP3H5ZS)"; }
}
public TraceInfo State(bool disassemble = true)
{
ushort bytes_read = 0;
string disasm = disassemble ? Disassemble(RegPC, ReadMemory, out bytes_read) : "---";
string byte_code = null;
for (ushort i = 0; i < bytes_read; i++)
{
byte_code += ReadMemory((ushort)(RegPC + i)).ToHexString(2);
if (i < (bytes_read - 1))
{
byte_code += " ";
}
}
return new TraceInfo
{
Disassembly = string.Format(
"{0:X4}: {1} {2}",
RegPC,
byte_code.PadRight(12),
disasm.PadRight(26)),
RegisterInfo = string.Format(
"AF:{0:X4} BC:{1:X4} DE:{2:X4} HL:{3:X4} IX:{4:X4} IY:{5:X4} SP:{6:X4} Cy:{7} {8}{9}{10}{11}{12}{13}{14}{15}{16}",
(Regs[A] << 8) + Regs[F],
(Regs[B] << 8) + Regs[C],
(Regs[D] << 8) + Regs[E],
(Regs[H] << 8) + Regs[L],
(Regs[Ixh] << 8) + Regs[Ixl],
(Regs[Iyh] << 8) + Regs[Iyl],
Regs[SPl] | (Regs[SPh] << 8),
TotalExecutedCycles,
FlagC ? "C" : "c",
FlagN ? "N" : "n",
FlagP ? "P" : "p",
Flag3 ? "3" : "-",
FlagH ? "H" : "h",
Flag5 ? "5" : "-",
FlagZ ? "Z" : "z",
FlagS ? "S" : "s",
FlagI ? "E" : "e")
};
}
// State Save/Load
public void SyncState(Serializer ser)
{
ser.BeginSection("Z80A");
ser.Sync("Regs", ref Regs, false);
ser.Sync("NMI", ref nonMaskableInterrupt);
ser.Sync("NMIPending", ref nonMaskableInterruptPending);
ser.Sync("IM", ref interruptMode);
ser.Sync("IFF1", ref iff1);
ser.Sync("IFF2", ref iff2);
ser.Sync("Halted", ref halted);
ser.Sync("ExecutedCycles", ref totalExecutedCycles);
ser.Sync("EI_pending", ref EI_pending);
ser.Sync("instruction_pointer", ref instr_pntr);
ser.Sync("current instruction", ref cur_instr, false);
ser.Sync("opcode", ref opcode);
ser.Sync("jammped", ref jammed);
ser.Sync("FlagI", ref FlagI);
ser.Sync("NO Preifx", ref NO_prefix);
ser.Sync("CB Preifx", ref CB_prefix);
ser.Sync("IX_prefix", ref IX_prefix);
ser.Sync("IY_prefix", ref IY_prefix);
ser.Sync("IXCB_prefix", ref IXCB_prefix);
ser.Sync("IYCB_prefix", ref IYCB_prefix);
ser.Sync("EXTD_prefix", ref EXTD_prefix);
ser.Sync("IXCB_prefetch", ref IXCB_prefetch);
ser.Sync("IYCB_prefetch", ref IYCB_prefetch);
ser.Sync("PF", ref PF);
ser.EndSection();
}
}
}

View File

@ -12,36 +12,36 @@ namespace BizHawk.Emulation.Cores.Calculators
{
return new Dictionary<string, RegisterValue>
{
["A"] = _cpu.RegisterA,
["AF"] = _cpu.RegisterAF,
["B"] = _cpu.RegisterB,
["BC"] = _cpu.RegisterBC,
["C"] = _cpu.RegisterC,
["D"] = _cpu.RegisterD,
["DE"] = _cpu.RegisterDE,
["E"] = _cpu.RegisterE,
["F"] = _cpu.RegisterF,
["H"] = _cpu.RegisterH,
["HL"] = _cpu.RegisterHL,
["I"] = _cpu.RegisterI,
["IX"] = _cpu.RegisterIX,
["IY"] = _cpu.RegisterIY,
["L"] = _cpu.RegisterL,
["PC"] = _cpu.RegisterPC,
["R"] = _cpu.RegisterR,
["Shadow AF"] = _cpu.RegisterShadowAF,
["Shadow BC"] = _cpu.RegisterShadowBC,
["Shadow DE"] = _cpu.RegisterShadowDE,
["Shadow HL"] = _cpu.RegisterShadowHL,
["SP"] = _cpu.RegisterSP,
["Flag C"] = _cpu.RegisterF.Bit(0),
["Flag N"] = _cpu.RegisterF.Bit(1),
["Flag P/V"] = _cpu.RegisterF.Bit(2),
["Flag 3rd"] = _cpu.RegisterF.Bit(3),
["Flag H"] = _cpu.RegisterF.Bit(4),
["Flag 5th"] = _cpu.RegisterF.Bit(5),
["Flag Z"] = _cpu.RegisterF.Bit(6),
["Flag S"] = _cpu.RegisterF.Bit(7)
["A"] = _cpu.Regs[_cpu.A],
["AF"] = _cpu.Regs[_cpu.F] + (_cpu.Regs[_cpu.A] << 8),
["B"] = _cpu.Regs[_cpu.B],
["BC"] = _cpu.Regs[_cpu.C] + (_cpu.Regs[_cpu.B] << 8),
["C"] = _cpu.Regs[_cpu.C],
["D"] = _cpu.Regs[_cpu.D],
["DE"] = _cpu.Regs[_cpu.E] + (_cpu.Regs[_cpu.D] << 8),
["E"] = _cpu.Regs[_cpu.E],
["F"] = _cpu.Regs[_cpu.F],
["H"] = _cpu.Regs[_cpu.H],
["HL"] = _cpu.Regs[_cpu.L] + (_cpu.Regs[_cpu.H] << 8),
["I"] = _cpu.Regs[_cpu.I],
["IX"] = _cpu.Regs[_cpu.Ixl] + (_cpu.Regs[_cpu.Ixh] << 8),
["IY"] = _cpu.Regs[_cpu.Iyl] + (_cpu.Regs[_cpu.Iyh] << 8),
["L"] = _cpu.Regs[_cpu.L],
["PC"] = _cpu.Regs[_cpu.PCl] + (_cpu.Regs[_cpu.PCh] << 8),
["R"] = _cpu.Regs[_cpu.R],
["Shadow AF"] = _cpu.Regs[_cpu.F_s] + (_cpu.Regs[_cpu.A_s] << 8),
["Shadow BC"] = _cpu.Regs[_cpu.C_s] + (_cpu.Regs[_cpu.B_s] << 8),
["Shadow DE"] = _cpu.Regs[_cpu.E_s] + (_cpu.Regs[_cpu.D_s] << 8),
["Shadow HL"] = _cpu.Regs[_cpu.L_s] + (_cpu.Regs[_cpu.H_s] << 8),
["SP"] = _cpu.Regs[_cpu.Iyl] + (_cpu.Regs[_cpu.Iyh] << 8),
["Flag C"] = _cpu.FlagC,
["Flag N"] = _cpu.FlagN,
["Flag P/V"] = _cpu.FlagP,
["Flag 3rd"] = _cpu.Flag3,
["Flag H"] = _cpu.FlagH,
["Flag 5th"] = _cpu.Flag5,
["Flag Z"] = _cpu.FlagZ,
["Flag S"] = _cpu.FlagS
};
}
@ -49,73 +49,85 @@ namespace BizHawk.Emulation.Cores.Calculators
{
switch (register)
{
default:
throw new InvalidOperationException();
case "A":
_cpu.RegisterA = (byte)value;
break;
case "AF":
_cpu.RegisterAF = (byte)value;
break;
case "B":
_cpu.RegisterB = (byte)value;
break;
case "BC":
_cpu.RegisterBC = (byte)value;
break;
case "C":
_cpu.RegisterC = (byte)value;
break;
case "D":
_cpu.RegisterD = (byte)value;
break;
case "DE":
_cpu.RegisterDE = (byte)value;
break;
case "E":
_cpu.RegisterE = (byte)value;
break;
case "F":
_cpu.RegisterF = (byte)value;
break;
case "H":
_cpu.RegisterH = (byte)value;
break;
case "HL":
_cpu.RegisterHL = (byte)value;
break;
case "I":
_cpu.RegisterI = (byte)value;
break;
case "IX":
_cpu.RegisterIX = (byte)value;
break;
case "IY":
_cpu.RegisterIY = (byte)value;
break;
case "L":
_cpu.RegisterL = (byte)value;
break;
case "PC":
_cpu.RegisterPC = (ushort)value;
break;
case "R":
_cpu.RegisterR = (byte)value;
break;
case "Shadow AF":
_cpu.RegisterShadowAF = (byte)value;
break;
case "Shadow BC":
_cpu.RegisterShadowBC = (byte)value;
break;
case "Shadow DE":
_cpu.RegisterShadowDE = (byte)value;
break;
case "Shadow HL":
_cpu.RegisterShadowHL = (byte)value;
break;
case "SP":
_cpu.RegisterSP = (byte)value;
default:
throw new InvalidOperationException();
case "A":
_cpu.Regs[_cpu.A] = (ushort)value;
break;
case "AF":
_cpu.Regs[_cpu.F] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.A] = (ushort)(value & 0xFF00);
break;
case "B":
_cpu.Regs[_cpu.B] = (ushort)value;
break;
case "BC":
_cpu.Regs[_cpu.C] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.B] = (ushort)(value & 0xFF00);
break;
case "C":
_cpu.Regs[_cpu.C] = (ushort)value;
break;
case "D":
_cpu.Regs[_cpu.D] = (ushort)value;
break;
case "DE":
_cpu.Regs[_cpu.E] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.D] = (ushort)(value & 0xFF00);
break;
case "E":
_cpu.Regs[_cpu.E] = (ushort)value;
break;
case "F":
_cpu.Regs[_cpu.F] = (ushort)value;
break;
case "H":
_cpu.Regs[_cpu.H] = (ushort)value;
break;
case "HL":
_cpu.Regs[_cpu.L] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.H] = (ushort)(value & 0xFF00);
break;
case "I":
_cpu.Regs[_cpu.I] = (ushort)value;
break;
case "IX":
_cpu.Regs[_cpu.Ixl] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.Ixh] = (ushort)(value & 0xFF00);
break;
case "IY":
_cpu.Regs[_cpu.Iyl] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.Iyh] = (ushort)(value & 0xFF00);
break;
case "L":
_cpu.Regs[_cpu.L] = (ushort)value;
break;
case "PC":
_cpu.Regs[_cpu.PCl] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.PCh] = (ushort)(value & 0xFF00);
break;
case "R":
_cpu.Regs[_cpu.R] = (ushort)value;
break;
case "Shadow AF":
_cpu.Regs[_cpu.F_s] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.A_s] = (ushort)(value & 0xFF00);
break;
case "Shadow BC":
_cpu.Regs[_cpu.C_s] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.B_s] = (ushort)(value & 0xFF00);
break;
case "Shadow DE":
_cpu.Regs[_cpu.E_s] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.D_s] = (ushort)(value & 0xFF00);
break;
case "Shadow HL":
_cpu.Regs[_cpu.L_s] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.H_s] = (ushort)(value & 0xFF00);
break;
case "SP":
_cpu.Regs[_cpu.SPl] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.SPh] = (ushort)(value & 0xFF00);
break;
}
}

View File

@ -13,11 +13,13 @@ namespace BizHawk.Emulation.Cores.Calculators
_controller = controller;
_lagged = true;
_cpu.Debug = _tracer.Enabled;
if (_cpu.Debug && _cpu.Logger == null) // TODO, lets not do this on each frame. But lets refactor CoreComm/CoreComm first
if (_tracer.Enabled)
{
_cpu.Logger = s => _tracer.Put(s);
_cpu.TraceCallback = s => _tracer.Put(s);
}
else
{
_cpu.TraceCallback = null;
}
// I eyeballed this speed
@ -26,8 +28,12 @@ namespace BizHawk.Emulation.Cores.Calculators
_onPressed = controller.IsPressed("ON");
// and this was derived from other emus
_cpu.ExecuteCycles(10000);
_cpu.Interrupt = true;
for (int j = 0; j < 10000; j++)
{
_cpu.ExecuteOne();
}
_cpu.FlagI = true;
}
Frame++;

View File

@ -7,55 +7,52 @@ namespace BizHawk.Emulation.Cores.Calculators
{
public partial class TI83 : IStatable
{
private byte[] _stateBuffer;
public bool BinarySaveStatesPreferred
{
get { return true; }
}
public bool BinarySaveStatesPreferred => false;
public void SaveStateText(TextWriter writer)
{
SyncState(new Serializer(writer));
}
public void LoadStateText(TextReader reader)
{
SyncState(new Serializer(reader));
}
public void SaveStateBinary(BinaryWriter bw)
{
SyncState(Serializer.CreateBinaryWriter(bw));
SyncState(new Serializer(bw));
}
public void LoadStateBinary(BinaryReader br)
{
SyncState(Serializer.CreateBinaryReader(br));
}
public void SaveStateText(TextWriter tw)
{
SyncState(Serializer.CreateTextWriter(tw));
}
public void LoadStateText(TextReader tr)
{
SyncState(Serializer.CreateTextReader(tr));
SyncState(new Serializer(br));
}
public byte[] SaveStateBinary()
{
if (_stateBuffer == null)
{
var stream = new MemoryStream();
var writer = new BinaryWriter(stream);
SaveStateBinary(writer);
_stateBuffer = stream.ToArray();
writer.Close();
return _stateBuffer;
}
else
{
var stream = new MemoryStream(_stateBuffer);
var writer = new BinaryWriter(stream);
SaveStateBinary(writer);
writer.Close();
return _stateBuffer;
}
MemoryStream ms = new MemoryStream();
BinaryWriter bw = new BinaryWriter(ms);
SaveStateBinary(bw);
bw.Flush();
return ms.ToArray();
}
private void SyncState(Serializer ser)
{
ser.BeginSection("TI83");
byte[] core = null;
if (ser.IsWriter)
{
var ms = new MemoryStream();
ms.Close();
core = ms.ToArray();
}
_cpu.SyncState(ser);
ser.BeginSection("TI83");
ser.Sync("RAM", ref _ram, false);
ser.Sync("romPageLow3Bits", ref _romPageLow3Bits);
ser.Sync("romPageHighBit", ref _romPageHighBit);

View File

@ -2,7 +2,7 @@ using System;
using System.Globalization;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Components.Z80;
using BizHawk.Emulation.Cores.Components.Z80A;
// http://www.ticalc.org/pub/text/calcinfo/
namespace BizHawk.Emulation.Cores.Calculators
@ -48,7 +48,7 @@ namespace BizHawk.Emulation.Cores.Calculators
_tracer = new TraceBuffer { Header = _cpu.TraceHeader };
ser.Register<ITraceable>(_tracer);
ser.Register<IDisassemblable>(new Disassembler());
ser.Register<IDisassemblable>(_cpu);
}
private readonly TraceBuffer _tracer;
@ -151,7 +151,7 @@ namespace BizHawk.Emulation.Cores.Calculators
if (LinkActive)
{
// Prevent rom calls from disturbing link port activity
if (LinkActive && _cpu.RegisterPC < 0x4000)
if (LinkActive && _cpu.RegPC < 0x4000)
{
return;
}
@ -428,13 +428,13 @@ namespace BizHawk.Emulation.Cores.Calculators
private void IRQCallback()
{
// Console.WriteLine("IRQ with vec {0} and cpu.InterruptMode {1}", cpu.RegisterI, cpu.InterruptMode);
_cpu.Interrupt = false;
//Console.WriteLine("IRQ with vec {0} and cpu.InterruptMode {1}", _cpu.Regs[_cpu.I], _cpu.InterruptMode);
_cpu.FlagI = false;
}
private void NMICallback()
{
Console.WriteLine("NMI");
//Console.WriteLine("NMI");
_cpu.NonMaskableInterrupt = false;
}
@ -447,7 +447,7 @@ namespace BizHawk.Emulation.Cores.Calculators
_ram[i] = 0xFF;
}
_cpu.RegisterPC = _startPC;
_cpu.RegPC = _startPC;
_cpu.IFF1 = false;
_cpu.IFF2 = false;

View File

@ -38,7 +38,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision
public byte Read(IController c, bool left_mode, int wheel)
{
return 0; // needs checking
return 0x7F; // needs checking
}
public ControllerDefinition Definition { get; }

View File

@ -12,36 +12,36 @@ namespace BizHawk.Emulation.Cores.ColecoVision
{
return new Dictionary<string, RegisterValue>
{
["A"] = _cpu.RegisterA,
["AF"] = _cpu.RegisterAF,
["B"] = _cpu.RegisterB,
["BC"] = _cpu.RegisterBC,
["C"] = _cpu.RegisterC,
["D"] = _cpu.RegisterD,
["DE"] = _cpu.RegisterDE,
["E"] = _cpu.RegisterE,
["F"] = _cpu.RegisterF,
["H"] = _cpu.RegisterH,
["HL"] = _cpu.RegisterHL,
["I"] = _cpu.RegisterI,
["IX"] = _cpu.RegisterIX,
["IY"] = _cpu.RegisterIY,
["L"] = _cpu.RegisterL,
["PC"] = _cpu.RegisterPC,
["R"] = _cpu.RegisterR,
["Shadow AF"] = _cpu.RegisterShadowAF,
["Shadow BC"] = _cpu.RegisterShadowBC,
["Shadow DE"] = _cpu.RegisterShadowDE,
["Shadow HL"] = _cpu.RegisterShadowHL,
["SP"] = _cpu.RegisterSP,
["Flag C"] = _cpu.RegisterF.Bit(0),
["Flag N"] = _cpu.RegisterF.Bit(1),
["Flag P/V"] = _cpu.RegisterF.Bit(2),
["Flag 3rd"] = _cpu.RegisterF.Bit(3),
["Flag H"] = _cpu.RegisterF.Bit(4),
["Flag 5th"] = _cpu.RegisterF.Bit(5),
["Flag Z"] = _cpu.RegisterF.Bit(6),
["Flag S"] = _cpu.RegisterF.Bit(7)
["A"] = _cpu.Regs[_cpu.A],
["AF"] = _cpu.Regs[_cpu.F] + (_cpu.Regs[_cpu.A] << 8),
["B"] = _cpu.Regs[_cpu.B],
["BC"] = _cpu.Regs[_cpu.C] + (_cpu.Regs[_cpu.B] << 8),
["C"] = _cpu.Regs[_cpu.C],
["D"] = _cpu.Regs[_cpu.D],
["DE"] = _cpu.Regs[_cpu.E] + (_cpu.Regs[_cpu.D] << 8),
["E"] = _cpu.Regs[_cpu.E],
["F"] = _cpu.Regs[_cpu.F],
["H"] = _cpu.Regs[_cpu.H],
["HL"] = _cpu.Regs[_cpu.L] + (_cpu.Regs[_cpu.H] << 8),
["I"] = _cpu.Regs[_cpu.I],
["IX"] = _cpu.Regs[_cpu.Ixl] + (_cpu.Regs[_cpu.Ixh] << 8),
["IY"] = _cpu.Regs[_cpu.Iyl] + (_cpu.Regs[_cpu.Iyh] << 8),
["L"] = _cpu.Regs[_cpu.L],
["PC"] = _cpu.Regs[_cpu.PCl] + (_cpu.Regs[_cpu.PCh] << 8),
["R"] = _cpu.Regs[_cpu.R],
["Shadow AF"] = _cpu.Regs[_cpu.F_s] + (_cpu.Regs[_cpu.A_s] << 8),
["Shadow BC"] = _cpu.Regs[_cpu.C_s] + (_cpu.Regs[_cpu.B_s] << 8),
["Shadow DE"] = _cpu.Regs[_cpu.E_s] + (_cpu.Regs[_cpu.D_s] << 8),
["Shadow HL"] = _cpu.Regs[_cpu.L_s] + (_cpu.Regs[_cpu.H_s] << 8),
["SP"] = _cpu.Regs[_cpu.Iyl] + (_cpu.Regs[_cpu.Iyh] << 8),
["Flag C"] = _cpu.FlagC,
["Flag N"] = _cpu.FlagN,
["Flag P/V"] = _cpu.FlagP,
["Flag 3rd"] = _cpu.Flag3,
["Flag H"] = _cpu.FlagH,
["Flag 5th"] = _cpu.Flag5,
["Flag Z"] = _cpu.FlagZ,
["Flag S"] = _cpu.FlagS
};
}
@ -52,70 +52,82 @@ namespace BizHawk.Emulation.Cores.ColecoVision
default:
throw new InvalidOperationException();
case "A":
_cpu.RegisterA = (byte)value;
_cpu.Regs[_cpu.A] = (ushort)value;
break;
case "AF":
_cpu.RegisterAF = (byte)value;
_cpu.Regs[_cpu.F] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.A] = (ushort)(value & 0xFF00);
break;
case "B":
_cpu.RegisterB = (byte)value;
_cpu.Regs[_cpu.B] = (ushort)value;
break;
case "BC":
_cpu.RegisterBC = (byte)value;
_cpu.Regs[_cpu.C] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.B] = (ushort)(value & 0xFF00);
break;
case "C":
_cpu.RegisterC = (byte)value;
_cpu.Regs[_cpu.C] = (ushort)value;
break;
case "D":
_cpu.RegisterD = (byte)value;
_cpu.Regs[_cpu.D] = (ushort)value;
break;
case "DE":
_cpu.RegisterDE = (byte)value;
_cpu.Regs[_cpu.E] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.D] = (ushort)(value & 0xFF00);
break;
case "E":
_cpu.RegisterE = (byte)value;
_cpu.Regs[_cpu.E] = (ushort)value;
break;
case "F":
_cpu.RegisterF = (byte)value;
_cpu.Regs[_cpu.F] = (ushort)value;
break;
case "H":
_cpu.RegisterH = (byte)value;
_cpu.Regs[_cpu.H] = (ushort)value;
break;
case "HL":
_cpu.RegisterHL = (byte)value;
_cpu.Regs[_cpu.L] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.H] = (ushort)(value & 0xFF00);
break;
case "I":
_cpu.RegisterI = (byte)value;
_cpu.Regs[_cpu.I] = (ushort)value;
break;
case "IX":
_cpu.RegisterIX = (byte)value;
_cpu.Regs[_cpu.Ixl] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.Ixh] = (ushort)(value & 0xFF00);
break;
case "IY":
_cpu.RegisterIY = (byte)value;
_cpu.Regs[_cpu.Iyl] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.Iyh] = (ushort)(value & 0xFF00);
break;
case "L":
_cpu.RegisterL = (byte)value;
_cpu.Regs[_cpu.L] = (ushort)value;
break;
case "PC":
_cpu.RegisterPC = (ushort)value;
_cpu.Regs[_cpu.PCl] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.PCh] = (ushort)(value & 0xFF00);
break;
case "R":
_cpu.RegisterR = (byte)value;
_cpu.Regs[_cpu.R] = (ushort)value;
break;
case "Shadow AF":
_cpu.RegisterShadowAF = (byte)value;
_cpu.Regs[_cpu.F_s] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.A_s] = (ushort)(value & 0xFF00);
break;
case "Shadow BC":
_cpu.RegisterShadowBC = (byte)value;
_cpu.Regs[_cpu.C_s] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.B_s] = (ushort)(value & 0xFF00);
break;
case "Shadow DE":
_cpu.RegisterShadowDE = (byte)value;
_cpu.Regs[_cpu.E_s] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.D_s] = (ushort)(value & 0xFF00);
break;
case "Shadow HL":
_cpu.RegisterShadowHL = (byte)value;
_cpu.Regs[_cpu.L_s] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.H_s] = (ushort)(value & 0xFF00);
break;
case "SP":
_cpu.RegisterSP = (byte)value;
_cpu.Regs[_cpu.SPl] = (ushort)(value & 0xFF);
_cpu.Regs[_cpu.SPh] = (ushort)(value & 0xFF00);
break;
}
}

View File

@ -24,16 +24,18 @@ namespace BizHawk.Emulation.Cores.ColecoVision
SoftReset();
}
_cpu.Debug = _tracer.Enabled;
_frame++;
_isLag = true;
PSG.BeginFrame(_cpu.TotalExecutedCycles);
if (_cpu.Debug && _cpu.Logger == null) // TODO, lets not do this on each frame. But lets refactor CoreComm/CoreComm first
if (_tracer.Enabled)
{
_cpu.Logger = (s) => _tracer.Put(s);
_cpu.TraceCallback = s => _tracer.Put(s);
}
else
{
_cpu.TraceCallback = null;
}
byte tempRet1 = ControllerDeck.ReadPort1(controller, true, true);
byte tempRet2 = ControllerDeck.ReadPort2(controller, true, true);

View File

@ -7,53 +7,52 @@ namespace BizHawk.Emulation.Cores.ColecoVision
{
public partial class ColecoVision : IStatable
{
public bool BinarySaveStatesPreferred => false;
public bool BinarySaveStatesPreferred
{
get { return true; }
}
public void SaveStateText(TextWriter writer)
{
SyncState(new Serializer(writer));
}
public void LoadStateText(TextReader reader)
{
SyncState(new Serializer(reader));
}
public void SaveStateBinary(BinaryWriter bw)
{
SyncState(Serializer.CreateBinaryWriter(bw));
SyncState(new Serializer(bw));
}
public void LoadStateBinary(BinaryReader br)
{
SyncState(Serializer.CreateBinaryReader(br));
}
public void SaveStateText(TextWriter tw)
{
SyncState(Serializer.CreateTextWriter(tw));
}
public void LoadStateText(TextReader tr)
{
SyncState(Serializer.CreateTextReader(tr));
SyncState(new Serializer(br));
}
public byte[] SaveStateBinary()
{
if (_stateBuffer == null)
{
var stream = new MemoryStream();
var writer = new BinaryWriter(stream);
SaveStateBinary(writer);
_stateBuffer = stream.ToArray();
writer.Close();
return _stateBuffer;
}
else
{
var stream = new MemoryStream(_stateBuffer);
var writer = new BinaryWriter(stream);
SaveStateBinary(writer);
writer.Close();
return _stateBuffer;
}
MemoryStream ms = new MemoryStream();
BinaryWriter bw = new BinaryWriter(ms);
SaveStateBinary(bw);
bw.Flush();
return ms.ToArray();
}
private void SyncState(Serializer ser)
{
ser.BeginSection("Coleco");
byte[] core = null;
if (ser.IsWriter)
{
var ms = new MemoryStream();
ms.Close();
core = ms.ToArray();
}
_cpu.SyncState(ser);
ser.BeginSection("Coleco");
_vdp.SyncState(ser);
PSG.SyncState(ser);
ser.Sync("RAM", ref _ram, false);

View File

@ -1,6 +1,6 @@
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Components;
using BizHawk.Emulation.Cores.Components.Z80;
using BizHawk.Emulation.Cores.Components.Z80A;
namespace BizHawk.Emulation.Cores.ColecoVision
{
@ -53,7 +53,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision
SetupMemoryDomains();
_tracer.Header = _cpu.TraceHeader;
ser.Register<IDisassemblable>(new Disassembler());
ser.Register<IDisassemblable>(_cpu);
ser.Register<ITraceable>(_tracer);
}

View File

@ -2,7 +2,7 @@
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Components.Z80;
using BizHawk.Emulation.Cores.Components.Z80A;
namespace BizHawk.Emulation.Cores.ColecoVision
{
@ -54,14 +54,17 @@ namespace BizHawk.Emulation.Cores.ColecoVision
Cpu.NonMaskableInterrupt = true;
}
Cpu.ExecuteCycles(228);
Cpu.Interrupt = false;
for (int i = 0; i < 228; i++)
{
Cpu.ExecuteOne();
}
Cpu.FlagI = false;
if (Int_pending && scanLine==50)
{
if (EnableInterrupts)
{
Cpu.Interrupt = true;
Cpu.FlagI = true;
Int_pending = false;
}
}

View File

@ -12,36 +12,36 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
{
return new Dictionary<string, RegisterValue>
{
["A"] = Cpu.RegisterA,
["AF"] = Cpu.RegisterAF,
["B"] = Cpu.RegisterB,
["BC"] = Cpu.RegisterBC,
["C"] = Cpu.RegisterC,
["D"] = Cpu.RegisterD,
["DE"] = Cpu.RegisterDE,
["E"] = Cpu.RegisterE,
["F"] = Cpu.RegisterF,
["H"] = Cpu.RegisterH,
["HL"] = Cpu.RegisterHL,
["I"] = Cpu.RegisterI,
["IX"] = Cpu.RegisterIX,
["IY"] = Cpu.RegisterIY,
["L"] = Cpu.RegisterL,
["PC"] = Cpu.RegisterPC,
["R"] = Cpu.RegisterR,
["Shadow AF"] = Cpu.RegisterShadowAF,
["Shadow BC"] = Cpu.RegisterShadowBC,
["Shadow DE"] = Cpu.RegisterShadowDE,
["Shadow HL"] = Cpu.RegisterShadowHL,
["SP"] = Cpu.RegisterSP,
["Flag C"] = Cpu.RegisterF.Bit(0),
["Flag N"] = Cpu.RegisterF.Bit(1),
["Flag P/V"] = Cpu.RegisterF.Bit(2),
["Flag 3rd"] = Cpu.RegisterF.Bit(3),
["Flag H"] = Cpu.RegisterF.Bit(4),
["Flag 5th"] = Cpu.RegisterF.Bit(5),
["Flag Z"] = Cpu.RegisterF.Bit(6),
["Flag S"] = Cpu.RegisterF.Bit(7)
["A"] = Cpu.Regs[Cpu.A],
["AF"] = Cpu.Regs[Cpu.F] + (Cpu.Regs[Cpu.A] << 8),
["B"] = Cpu.Regs[Cpu.B],
["BC"] = Cpu.Regs[Cpu.C] + (Cpu.Regs[Cpu.B] << 8),
["C"] = Cpu.Regs[Cpu.C],
["D"] = Cpu.Regs[Cpu.D],
["DE"] = Cpu.Regs[Cpu.E] + (Cpu.Regs[Cpu.D] << 8),
["E"] = Cpu.Regs[Cpu.E],
["F"] = Cpu.Regs[Cpu.F],
["H"] = Cpu.Regs[Cpu.H],
["HL"] = Cpu.Regs[Cpu.L] + (Cpu.Regs[Cpu.H] << 8),
["I"] = Cpu.Regs[Cpu.I],
["IX"] = Cpu.Regs[Cpu.Ixl] + (Cpu.Regs[Cpu.Ixh] << 8),
["IY"] = Cpu.Regs[Cpu.Iyl] + (Cpu.Regs[Cpu.Iyh] << 8),
["L"] = Cpu.Regs[Cpu.L],
["PC"] = Cpu.Regs[Cpu.PCl] + (Cpu.Regs[Cpu.PCh] << 8),
["R"] = Cpu.Regs[Cpu.R],
["Shadow AF"] = Cpu.Regs[Cpu.F_s] + (Cpu.Regs[Cpu.A_s] << 8),
["Shadow BC"] = Cpu.Regs[Cpu.C_s] + (Cpu.Regs[Cpu.B_s] << 8),
["Shadow DE"] = Cpu.Regs[Cpu.E_s] + (Cpu.Regs[Cpu.D_s] << 8),
["Shadow HL"] = Cpu.Regs[Cpu.L_s] + (Cpu.Regs[Cpu.H_s] << 8),
["SP"] = Cpu.Regs[Cpu.Iyl] + (Cpu.Regs[Cpu.Iyh] << 8),
["Flag C"] = Cpu.FlagC,
["Flag N"] = Cpu.FlagN,
["Flag P/V"] = Cpu.FlagP,
["Flag 3rd"] = Cpu.Flag3,
["Flag H"] = Cpu.FlagH,
["Flag 5th"] = Cpu.Flag5,
["Flag Z"] = Cpu.FlagZ,
["Flag S"] = Cpu.FlagS
};
}
@ -52,70 +52,82 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
default:
throw new InvalidOperationException();
case "A":
Cpu.RegisterA = (byte)value;
Cpu.Regs[Cpu.A] = (ushort)value;
break;
case "AF":
Cpu.RegisterAF = (byte)value;
Cpu.Regs[Cpu.F] = (ushort)(value & 0xFF);
Cpu.Regs[Cpu.A] = (ushort)(value & 0xFF00);
break;
case "B":
Cpu.RegisterB = (byte)value;
Cpu.Regs[Cpu.B] = (ushort)value;
break;
case "BC":
Cpu.RegisterBC = (byte)value;
Cpu.Regs[Cpu.C] = (ushort)(value & 0xFF);
Cpu.Regs[Cpu.B] = (ushort)(value & 0xFF00);
break;
case "C":
Cpu.RegisterC = (byte)value;
Cpu.Regs[Cpu.C] = (ushort)value;
break;
case "D":
Cpu.RegisterD = (byte)value;
Cpu.Regs[Cpu.D] = (ushort)value;
break;
case "DE":
Cpu.RegisterDE = (byte)value;
Cpu.Regs[Cpu.E] = (ushort)(value & 0xFF);
Cpu.Regs[Cpu.D] = (ushort)(value & 0xFF00);
break;
case "E":
Cpu.RegisterE = (byte)value;
Cpu.Regs[Cpu.E] = (ushort)value;
break;
case "F":
Cpu.RegisterF = (byte)value;
Cpu.Regs[Cpu.F] = (ushort)value;
break;
case "H":
Cpu.RegisterH = (byte)value;
Cpu.Regs[Cpu.H] = (ushort)value;
break;
case "HL":
Cpu.RegisterHL = (byte)value;
Cpu.Regs[Cpu.L] = (ushort)(value & 0xFF);
Cpu.Regs[Cpu.H] = (ushort)(value & 0xFF00);
break;
case "I":
Cpu.RegisterI = (byte)value;
Cpu.Regs[Cpu.I] = (ushort)value;
break;
case "IX":
Cpu.RegisterIX = (byte)value;
Cpu.Regs[Cpu.Ixl] = (ushort)(value & 0xFF);
Cpu.Regs[Cpu.Ixh] = (ushort)(value & 0xFF00);
break;
case "IY":
Cpu.RegisterIY = (byte)value;
Cpu.Regs[Cpu.Iyl] = (ushort)(value & 0xFF);
Cpu.Regs[Cpu.Iyh] = (ushort)(value & 0xFF00);
break;
case "L":
Cpu.RegisterL = (byte)value;
Cpu.Regs[Cpu.L] = (ushort)value;
break;
case "PC":
Cpu.RegisterPC = (ushort)value;
Cpu.Regs[Cpu.PCl] = (ushort)(value & 0xFF);
Cpu.Regs[Cpu.PCh] = (ushort)(value & 0xFF00);
break;
case "R":
Cpu.RegisterR = (byte)value;
Cpu.Regs[Cpu.R] = (ushort)value;
break;
case "Shadow AF":
Cpu.RegisterShadowAF = (byte)value;
Cpu.Regs[Cpu.F_s] = (ushort)(value & 0xFF);
Cpu.Regs[Cpu.A_s] = (ushort)(value & 0xFF00);
break;
case "Shadow BC":
Cpu.RegisterShadowBC = (byte)value;
Cpu.Regs[Cpu.C_s] = (ushort)(value & 0xFF);
Cpu.Regs[Cpu.B_s] = (ushort)(value & 0xFF00);
break;
case "Shadow DE":
Cpu.RegisterShadowDE = (byte)value;
Cpu.Regs[Cpu.E_s] = (ushort)(value & 0xFF);
Cpu.Regs[Cpu.D_s] = (ushort)(value & 0xFF00);
break;
case "Shadow HL":
Cpu.RegisterShadowHL = (byte)value;
Cpu.Regs[Cpu.L_s] = (ushort)(value & 0xFF);
Cpu.Regs[Cpu.H_s] = (ushort)(value & 0xFF00);
break;
case "SP":
Cpu.RegisterSP = (byte)value;
Cpu.Regs[Cpu.SPl] = (ushort)(value & 0xFF);
Cpu.Regs[Cpu.SPh] = (ushort)(value & 0xFF00);
break;
}
}

View File

@ -1,95 +1,99 @@
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Sega.MasterSystem
{
public sealed partial class SMS : IEmulator
{
public IEmulatorServiceProvider ServiceProvider { get; }
public ControllerDefinition ControllerDefinition
{
get
{
if (IsGameGear)
{
return GGController;
}
switch(Settings.ControllerType)
{
case "Paddle":
return SMSPaddleController;
case "Light Phaser":
// scale the vertical to the display mode
SMSLightPhaserController.FloatRanges[1] = new ControllerDefinition.FloatRange(0, Vdp.FrameHeight / 2, Vdp.FrameHeight - 1);
return SMSLightPhaserController;
default:
return SmsController;
}
}
}
public void FrameAdvance(IController controller, bool render, bool rendersound)
{
_controller = controller;
_lagged = true;
_frame++;
PSG.BeginFrame(Cpu.TotalExecutedCycles);
Cpu.Debug = Tracer.Enabled;
if (!IsGameGear)
{
PSG.StereoPanning = Settings.ForceStereoSeparation ? ForceStereoByte : (byte)0xFF;
}
if (Cpu.Debug && Cpu.Logger == null) // TODO, lets not do this on each frame. But lets refactor CoreComm/CoreComm first
{
Cpu.Logger = s => Tracer.Put(s);
}
if (IsGameGear == false)
{
Cpu.NonMaskableInterrupt = controller.IsPressed("Pause");
}
if (IsGame3D && Settings.Fix3D)
{
Vdp.ExecFrame((Frame & 1) == 0);
}
else
{
Vdp.ExecFrame(render);
}
PSG.EndFrame(Cpu.TotalExecutedCycles);
if (_lagged)
{
_lagCount++;
_isLag = true;
}
else
{
_isLag = false;
}
}
public int Frame => _frame;
public string SystemId => "SMS";
public bool DeterministicEmulation => true;
public void ResetCounters()
{
_frame = 0;
_lagCount = 0;
_isLag = false;
}
public CoreComm CoreComm { get; }
public void Dispose()
{
}
}
}
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Sega.MasterSystem
{
public sealed partial class SMS : IEmulator
{
public IEmulatorServiceProvider ServiceProvider { get; }
public ControllerDefinition ControllerDefinition
{
get
{
if (IsGameGear)
{
return GGController;
}
switch(Settings.ControllerType)
{
case "Paddle":
return SMSPaddleController;
case "Light Phaser":
// scale the vertical to the display mode
SMSLightPhaserController.FloatRanges[1] = new ControllerDefinition.FloatRange(0, Vdp.FrameHeight / 2, Vdp.FrameHeight - 1);
return SMSLightPhaserController;
default:
return SmsController;
}
}
}
public void FrameAdvance(IController controller, bool render, bool rendersound)
{
_controller = controller;
_lagged = true;
_frame++;
PSG.BeginFrame(Cpu.TotalExecutedCycles);
if (!IsGameGear)
{
PSG.StereoPanning = Settings.ForceStereoSeparation ? ForceStereoByte : (byte)0xFF;
}
if (Tracer.Enabled)
{
Cpu.TraceCallback = s => Tracer.Put(s);
}
else
{
Cpu.TraceCallback = null;
}
if (IsGameGear == false)
{
Cpu.NonMaskableInterrupt = controller.IsPressed("Pause");
}
if (IsGame3D && Settings.Fix3D)
{
Vdp.ExecFrame((Frame & 1) == 0);
}
else
{
Vdp.ExecFrame(render);
}
PSG.EndFrame(Cpu.TotalExecutedCycles);
if (_lagged)
{
_lagCount++;
_isLag = true;
}
else
{
_isLag = false;
}
}
public int Frame => _frame;
public string SystemId => "SMS";
public bool DeterministicEmulation => true;
public void ResetCounters()
{
_frame = 0;
_lagCount = 0;
_isLag = false;
}
public CoreComm CoreComm { get; }
public void Dispose()
{
}
}
}

View File

@ -1,106 +1,100 @@
using System.IO;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Sega.MasterSystem
{
public sealed partial class SMS : IStatable
{
public bool BinarySaveStatesPreferred
{
get { return false; }
}
public void SaveStateBinary(BinaryWriter bw)
{
SyncState(Serializer.CreateBinaryWriter(bw));
}
public void LoadStateBinary(BinaryReader br)
{
SyncState(Serializer.CreateBinaryReader(br));
}
public void SaveStateText(TextWriter tw)
{
SyncState(Serializer.CreateTextWriter(tw));
}
public void LoadStateText(TextReader tr)
{
SyncState(Serializer.CreateTextReader(tr));
}
public byte[] SaveStateBinary()
{
if (_stateBuffer == null)
{
var stream = new MemoryStream();
var writer = new BinaryWriter(stream);
SaveStateBinary(writer);
_stateBuffer = stream.ToArray();
writer.Close();
return _stateBuffer;
}
else
{
var stream = new MemoryStream(_stateBuffer);
var writer = new BinaryWriter(stream);
SaveStateBinary(writer);
writer.Close();
return _stateBuffer;
}
}
private byte[] _stateBuffer;
private void SyncState(Serializer ser)
{
ser.BeginSection("SMS");
Cpu.SyncState(ser);
Vdp.SyncState(ser);
PSG.SyncState(ser);
ser.Sync("RAM", ref SystemRam, false);
ser.Sync("RomBank0", ref RomBank0);
ser.Sync("RomBank1", ref RomBank1);
ser.Sync("RomBank2", ref RomBank2);
ser.Sync("RomBank3", ref RomBank3);
ser.Sync("Port01", ref Port01);
ser.Sync("Port02", ref Port02);
ser.Sync("Port3E", ref Port3E);
ser.Sync("Port3F", ref Port3F);
ser.Sync("Paddle1High", ref Paddle1High);
ser.Sync("Paddle2High", ref Paddle2High);
ser.Sync("LatchLightPhaser", ref LatchLightPhaser);
if (SaveRAM != null)
{
ser.Sync("SaveRAM", ref SaveRAM, false);
ser.Sync("SaveRamBank", ref SaveRamBank);
}
if (ExtRam != null)
{
ser.Sync("ExtRAM", ref ExtRam, true);
}
if (HasYM2413)
{
YM2413.SyncState(ser);
}
ser.Sync("Frame", ref _frame);
ser.Sync("LagCount", ref _lagCount);
ser.Sync("IsLag", ref _isLag);
ser.EndSection();
if (ser.IsReader)
{
SyncAllByteArrayDomains();
}
}
}
}
using System.IO;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Sega.MasterSystem
{
public sealed partial class SMS : IStatable
{
public bool BinarySaveStatesPreferred
{
get { return true; }
}
public void SaveStateText(TextWriter writer)
{
SyncState(new Serializer(writer));
}
public void LoadStateText(TextReader reader)
{
SyncState(new Serializer(reader));
}
public void SaveStateBinary(BinaryWriter bw)
{
SyncState(new Serializer(bw));
}
public void LoadStateBinary(BinaryReader br)
{
SyncState(new Serializer(br));
}
public byte[] SaveStateBinary()
{
MemoryStream ms = new MemoryStream();
BinaryWriter bw = new BinaryWriter(ms);
SaveStateBinary(bw);
bw.Flush();
return ms.ToArray();
}
private void SyncState(Serializer ser)
{
byte[] core = null;
if (ser.IsWriter)
{
var ms = new MemoryStream();
ms.Close();
core = ms.ToArray();
}
Cpu.SyncState(ser);
ser.BeginSection("SMS");
Vdp.SyncState(ser);
PSG.SyncState(ser);
ser.Sync("RAM", ref SystemRam, false);
ser.Sync("RomBank0", ref RomBank0);
ser.Sync("RomBank1", ref RomBank1);
ser.Sync("RomBank2", ref RomBank2);
ser.Sync("RomBank3", ref RomBank3);
ser.Sync("Port01", ref Port01);
ser.Sync("Port02", ref Port02);
ser.Sync("Port3E", ref Port3E);
ser.Sync("Port3F", ref Port3F);
ser.Sync("Paddle1High", ref Paddle1High);
ser.Sync("Paddle2High", ref Paddle2High);
ser.Sync("LatchLightPhaser", ref LatchLightPhaser);
if (SaveRAM != null)
{
ser.Sync("SaveRAM", ref SaveRAM, false);
ser.Sync("SaveRamBank", ref SaveRamBank);
}
if (ExtRam != null)
{
ser.Sync("ExtRAM", ref ExtRam, true);
}
if (HasYM2413)
{
YM2413.SyncState(ser);
}
ser.Sync("Frame", ref _frame);
ser.Sync("LagCount", ref _lagCount);
ser.Sync("IsLag", ref _isLag);
ser.EndSection();
if (ser.IsReader)
{
SyncAllByteArrayDomains();
}
}
}
}

View File

@ -4,7 +4,7 @@ using BizHawk.Common.StringExtensions;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.Components;
using BizHawk.Emulation.Cores.Components;
using BizHawk.Emulation.Cores.Components.Z80;
using BizHawk.Emulation.Cores.Components.Z80A;
/*****************************************************
TODO:
@ -75,11 +75,12 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
HasYM2413 = true;
}
Cpu = new Z80A
Cpu = new Z80A()
{
RegisterSP = 0xDFF0,
ReadHardware = ReadPort,
WriteHardware = WritePort,
ReadMemory = ReadMemory,
WriteMemory = WriteMemory,
MemoryCallbacks = MemoryCallbacks
};
@ -160,7 +161,10 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
}
if (game["SRAM"])
{
SaveRAM = new byte[int.Parse(game.OptionValue("SRAM"))];
Console.WriteLine(SaveRAM.Length);
}
else if (game.NotInDatabase)
SaveRAM = new byte[0x8000];
@ -175,8 +179,11 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
var serviceProvider = ServiceProvider as BasicServiceProvider;
serviceProvider.Register<ITraceable>(Tracer);
serviceProvider.Register<IDisassemblable>(new Disassembler());
serviceProvider.Register<IDisassemblable>(Cpu);
Vdp.ProcessOverscan();
Cpu.ReadMemory = ReadMemory;
Cpu.WriteMemory = WriteMemory;
}
// Constants

View File

@ -4,7 +4,7 @@ using System.IO;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Components.Z80;
using BizHawk.Emulation.Cores.Components.Z80A;
namespace BizHawk.Emulation.Cores.Sega.MasterSystem
@ -113,7 +113,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
StatusByte &= 0x1F;
HIntPending = false;
VIntPending = false;
Cpu.Interrupt = false;
Cpu.FlagI = false;
return returnValue;
}
@ -291,13 +291,13 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
{
case 0: // Mode Control Register 1
CheckVideoMode();
Cpu.Interrupt = (EnableLineInterrupts && HIntPending);
Cpu.Interrupt |= (EnableFrameInterrupts && VIntPending);
Cpu.FlagI = (EnableLineInterrupts && HIntPending);
Cpu.FlagI |= (EnableFrameInterrupts && VIntPending);
break;
case 1: // Mode Control Register 2
CheckVideoMode();
Cpu.Interrupt = (EnableFrameInterrupts && VIntPending);
Cpu.Interrupt |= (EnableLineInterrupts && HIntPending);
Cpu.FlagI = (EnableFrameInterrupts && VIntPending);
Cpu.FlagI |= (EnableLineInterrupts && HIntPending);
break;
case 2: // Name Table Base Address
NameTableBase = CalcNameTableBase();
@ -347,7 +347,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
if (VIntPending && EnableFrameInterrupts)
{
Cpu.Interrupt = true;
Cpu.FlagI = true;
}
}
@ -361,7 +361,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
HIntPending = true;
if (EnableLineInterrupts)
{;
Cpu.Interrupt = true;
Cpu.FlagI = true;
}
lineIntLinesRemaining = Registers[0x0A];
}
@ -383,7 +383,14 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
ProcessLineInterrupt();
Sms.ProcessLineControls();
Cpu.ExecuteCycles(IPeriod);
//Console.Write(Cpu.cur_instr.Length);
//Console.Write(" ");
//Console.WriteLine(Cpu.instr_pntr);
for (int j = 0; j < IPeriod; j++)
{
Cpu.ExecuteOne();
}
if (ScanLine == scanlinesPerFrame - 1)
{