322 lines
8.0 KiB
C#
322 lines
8.0 KiB
C#
namespace BizHawk.Emulation.CPUs.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; }
|
|
}
|
|
}
|