commit
eca4299b87
|
@ -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
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -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 };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue