Add OPL4 playback and analyzer support

This commit is contained in:
2026-09-15 14:59:29 +03:00
commit 1686838e03
553 changed files with 50524 additions and 0 deletions
+119
View File
@@ -0,0 +1,119 @@
/*
* Copyright 2007, 2015 Alex Makeev
*
* This file is part of ZXMAK2 (ZX Spectrum virtual machine).
*
* ZXMAK2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZXMAK2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZXMAK2. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
namespace ZXMAK2.Engine.Cpu
{
/// <summary>
/// Represent masks for the Z80 flags register
/// </summary>
public static class CpuFlags
{
#region Flags
/// <summary>
/// Sign Flag
/// [Set if the 2-complement value is negative (copy of MSB)]
/// </summary>
public const byte S = 0x80;
/// <summary>
/// Zero Flag
/// [Set if the value is zero]
/// </summary>
public const byte Z = 0x40;
/// <summary>
/// Undocumented flag F5
/// </summary>
public const byte F5 = 0x20;
/// <summary>
/// Half Carry Flag
/// [Carry from bit 3 to bit 4]
/// </summary>
public const byte H = 0x10;
/// <summary>
/// Undocumented flag F3
/// </summary>
public const byte F3 = 0x08;
/// <summary>
/// P/V - Parity/Overflow Flag
/// [Parity set if even number of bits set.
/// Overflow set if the 2-complement result does not fit in the register]
/// </summary>
public const byte P = 0x04;
/// <summary>
/// Add/Subtract Flag
/// [Set if the last operation was a subtraction]
/// </summary>
public const byte N = 0x02;
/// <summary>
/// Carry Flag
/// [Set if the result did not fit in the register]
/// </summary>
public const byte C = 0x01;
#endregion Flags
#region Inverted Masks
public const byte NotS = S ^ 0xFF;
public const byte NotZ = Z ^ 0xFF;
public const byte NotF5 = F5 ^ 0xFF;
public const byte NotH = H ^ 0xFF;
public const byte NotF3 = F3 ^ 0xFF;
public const byte NotP = P ^ 0xFF;
public const byte NotN = N ^ 0xFF;
public const byte NotC = C ^ 0xFF;
#endregion Inverted Masks
#region Internal flag sets (used by engine)
internal const byte F3F5 = F3 | F5;
internal const byte SF3F5 = S | F3 | F5;
internal const byte PCF3F5 = P | C | F3 | F5;
internal const byte HNCF3F5 = H | N | C | F3 | F5;
internal const byte HPNF3F5 = H | P | N | F3 | F5;
internal const byte HC = H | C;
internal const byte SZP = S | Z | P;
internal const byte SZPC = S | Z | P | C;
internal const byte HN = H | N;
internal const byte NotF3F5 = F3F5 ^ 0xFF;
internal const byte NotSF3F5 = SF3F5 ^ 0xFF;
internal const byte NotPCF3F5 = PCF3F5 ^ 0xFF;
internal const byte NotHNCF3F5 = HNCF3F5 ^ 0xFF;
internal const byte NotHPNF3F5 = HPNF3F5 ^ 0xFF;
internal const byte NotHC = HC ^ 0xFF;
internal const byte NotSZP = SZP ^ 0xFF;
internal const byte NotSZPC = SZPC ^ 0xFF;
internal const byte NotHN = HN ^ 0xFF;
#endregion Internal flag sets (used by engine)
}
}
+31
View File
@@ -0,0 +1,31 @@
/*
* Copyright 2007, 2015 Alex Makeev
*
* This file is part of ZXMAK2 (ZX Spectrum virtual machine).
*
* ZXMAK2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZXMAK2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZXMAK2. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
namespace ZXMAK2.Engine.Cpu
{
public enum CpuModeEx
{
None = 0,
Cb,
Ed,
}
}
+31
View File
@@ -0,0 +1,31 @@
/*
* Copyright 2007, 2015 Alex Makeev
*
* This file is part of ZXMAK2 (ZX Spectrum virtual machine).
*
* ZXMAK2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZXMAK2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZXMAK2. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
namespace ZXMAK2.Engine.Cpu
{
public enum CpuModeIndex
{
None = 0,
Ix,
Iy,
}
}
+168
View File
@@ -0,0 +1,168 @@
/*
* Copyright 2007, 2015 Alex Makeev
*
* This file is part of ZXMAK2 (ZX Spectrum virtual machine).
*
* ZXMAK2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZXMAK2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZXMAK2. If not, see <http://www.gnu.org/licenses/>.
*
* Description: Z80 CPU Emulator [registers part]
* Date: 18.03.2007
*
*/
using System;
using System.Runtime.InteropServices;
using ZXMAK2.Engine.Cpu.Processor;
namespace ZXMAK2.Engine.Cpu
{
[StructLayout(LayoutKind.Explicit)]
public sealed class CpuRegs
{
[FieldOffset(0)]
public ushort AF = 0;
[FieldOffset(2)]
public ushort BC = 0;
[FieldOffset(4)]
public ushort DE = 0;
[FieldOffset(6)]
public ushort HL = 0;
[FieldOffset(8)]
public ushort _AF = 0;
[FieldOffset(10)]
public ushort _BC = 0;
[FieldOffset(12)]
public ushort _DE = 0;
[FieldOffset(14)]
public ushort _HL = 0;
[FieldOffset(16)]
public ushort IX = 0;
[FieldOffset(18)]
public ushort IY = 0;
[FieldOffset(20)]
public ushort IR = 0;
[FieldOffset(22)]
public ushort PC = 0;
[FieldOffset(24)]
public ushort SP = 0;
[FieldOffset(26)]
public ushort MW = 0; // MEMPTR
[FieldOffset(28)]
public byte Q = 0; // TODO: Q flags
[FieldOffset(1)]
public byte A;
[FieldOffset(0)]
public byte F;
[FieldOffset(3)]
public byte B;
[FieldOffset(2)]
public byte C;
[FieldOffset(5)]
public byte D;
[FieldOffset(4)]
public byte E;
[FieldOffset(7)]
public byte H;
[FieldOffset(6)]
public byte L;
[FieldOffset(17)]
public byte XH;
[FieldOffset(16)]
public byte XL;
[FieldOffset(19)]
public byte YH;
[FieldOffset(18)]
public byte YL;
[FieldOffset(21)]
public byte I;
[FieldOffset(20)]
public byte R;
[FieldOffset(27)]
public byte MH;
[FieldOffset(26)]
public byte ML;
[FieldOffset(23)]
public byte PCH = 0;
[FieldOffset(22)]
public byte PCL = 0;
#region Access Lamda Generators
// Access field from an object context
// makes one native instruction lesser
internal Func<byte> CreateRegGetter(int r)
{
return r switch
{
CpuRegId.B => () => B,
CpuRegId.C => () => C,
CpuRegId.D => () => D,
CpuRegId.E => () => E,
CpuRegId.H => () => H,
CpuRegId.L => () => L,
CpuRegId.A => () => A,
CpuRegId.F => () => F,
_ => throw new ArgumentOutOfRangeException(nameof(r)),
};
}
internal Action<byte> CreateRegSetter(int r)
{
return r switch
{
CpuRegId.B => arg => B = arg,
CpuRegId.C => arg => C = arg,
CpuRegId.D => arg => D = arg,
CpuRegId.E => arg => E = arg,
CpuRegId.H => arg => H = arg,
CpuRegId.L => arg => L = arg,
CpuRegId.A => arg => A = arg,
CpuRegId.F => arg => F = arg,
_ => throw new ArgumentOutOfRangeException(nameof(r)),
};
}
internal Func<ushort> CreatePairGetter(int rr)
{
return rr switch
{
CpuRegId.Bc => () => BC,
CpuRegId.De => () => DE,
CpuRegId.Hl => () => HL,
CpuRegId.Sp => () => SP,
_ => throw new ArgumentOutOfRangeException(nameof(rr)),
};
}
internal Action<ushort> CreatePairSetter(int rr)
{
return rr switch
{
CpuRegId.Bc => arg => BC = arg,
CpuRegId.De => arg => DE = arg,
CpuRegId.Hl => arg => HL = arg,
CpuRegId.Sp => arg => SP = arg,
_ => throw new ArgumentOutOfRangeException(nameof(rr)),
};
}
#endregion Access Lamda Generators
}
}
+32
View File
@@ -0,0 +1,32 @@
/*
* Copyright 2007, 2015 Alex Makeev
*
* This file is part of ZXMAK2 (ZX Spectrum virtual machine).
*
* ZXMAK2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZXMAK2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZXMAK2. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
namespace ZXMAK2.Engine.Cpu
{
public enum CpuType
{
ZILOG_NMOS = 0,
ZILOG_CMOS = 1,
NEC_NMOS = 2, // NEC
ST_CMOS = 3, // Z84?
}
}
+29
View File
@@ -0,0 +1,29 @@
/*
* Copyright 2007, 2015 Alex Makeev
*
* This file is part of ZXMAK2 (ZX Spectrum virtual machine).
*
* ZXMAK2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZXMAK2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZXMAK2. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
using ZXMAK2.Engine.Cpu.Processor;
namespace ZXMAK2.Engine.Cpu
{
public sealed class CpuUnit : Z80Cpu
{
}
}
+41
View File
@@ -0,0 +1,41 @@
/*
* Copyright 2007, 2015 Alex Makeev
*
* This file is part of ZXMAK2 (ZX Spectrum virtual machine).
*
* ZXMAK2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZXMAK2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZXMAK2. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
namespace ZXMAK2.Engine.Cpu.Processor
{
internal static class CpuRegId
{
public const int Bc = 0;
public const int De = 1;
public const int Hl = 2;
public const int Sp = 3;
public const int B = 0;
public const int C = 1;
public const int D = 2;
public const int E = 3;
public const int H = 4;
public const int L = 5;
public const int F = 6;
public const int A = 7;
}
}
+681
View File
@@ -0,0 +1,681 @@
/*
* Copyright 2015 Alex Makeev
* Copyright 2009 SMT (ALU tables)
*
* This file is part of ZXMAK2 (ZX Spectrum virtual machine).
*
* ZXMAK2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZXMAK2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZXMAK2. If not, see <http://www.gnu.org/licenses/>.
*
* --------------------------------------------------------------------
* Most of the tables based on the source code of UnrealSpeccy emulator
*
*/
namespace ZXMAK2.Engine.Cpu.Processor
{
public static class CpuTables
{
#region .ctor
static CpuTables()
{
Logf = CreateLogf();
Adcf = CreateAdcf();
// === make_rot === credits to SMT (Unreal)
Rlcaf = new byte[0x100];
Rrcaf = new byte[0x100];
for (var i = 0; i < 0x100; i++)
{
Rlcaf[i] = (byte)(Rlcf[i] & 0x3B); // rra,rla uses same tables
}
for (var i = 0; i < 0x100; i++)
{
Rrcaf[i] = (byte)(Rrcf[i] & 0x3B);
}
// === make_sbc === credits to SMT (Unreal)
Sbcf = new byte[0x20000];
Cpf = new byte[0x10000];
Cpf8b = new byte[0x10000];
for (var c = 0; c < 2; c++)
{
for (var x = 0; x < 0x100; x++)
{
for (var y = 0; y < 0x100; y++)
{
var res = x - y - c;
var fl = res & CpuFlags.SF3F5;
if ((res & 0xFF) == 0) fl |= CpuFlags.Z;
if ((res & 0x10000) != 0) fl |= CpuFlags.C;
var r = (sbyte)x - (sbyte)y - c;
if (r >= 0x80 || r < -0x80) fl |= CpuFlags.P;
if ((((x & 0x0F) - (res & 0x0F) - c) & 0x10) != 0) fl |= CpuFlags.H;
fl |= CpuFlags.N;
Sbcf[c * 0x10000 + x * 0x100 + y] = (byte)fl;
}
}
}
for (var i = 0; i < 0x10000; i++)
{
Cpf[i] = (byte)((Sbcf[i] & CpuFlags.NotF3F5) | (i & CpuFlags.F3F5));
var val = (byte)((i >> 8) - (i & 0xFF) - ((Sbcf[i] & CpuFlags.H) >> 4));
Cpf8b[i] = (byte)((Sbcf[i] & CpuFlags.NotPCF3F5) + (val & CpuFlags.F3) + ((val << 4) & CpuFlags.F5));
}
Parity = new byte[256];
for (var i = 0; i < Parity.Length; i++)
{
// Bit Twiddling Hacks: Compute parity in parallel, 8-bit
var p = (0x6996 >> ((i ^ (i >> 4)) & 0xf)) & 1;
Parity[i] = p == 0 ? CpuFlags.P : (byte)0;
}
}
private static byte[] CreateLogf()
{
// === make_log === credits to SMT (Unreal)
var log_f = new byte[0x100];
for (var x = 0; x < 0x100; x++)
{
var fl = x & CpuFlags.SF3F5;
var p = CpuFlags.P;
for (var i = 0x80; i != 0; i /= 2)
{
if ((x & i) == i) p ^= CpuFlags.P;
}
log_f[x] = (byte)(fl | p);
}
log_f[0] |= CpuFlags.Z;
return log_f;
}
private static byte[] CreateAdcf()
{
// === make_adc === credits to SMT (Unreal)
var adcf = new byte[0x20000];
for (var c = 0; c < 2; c++)
{
for (var x = 0; x < 0x100; x++)
{
for (var y = 0; y < 0x100; y++)
{
uint res = (uint)(x + y + c);
byte fl = 0;
if ((res & 0xFF) == 0) fl |= CpuFlags.Z;
fl |= (byte)(res & CpuFlags.SF3F5);
if (res >= 0x100) fl |= CpuFlags.C;
if ((((x & 0x0F) + (y & 0x0F) + c) & 0x10) != 0) fl |= CpuFlags.H;
int ri = (sbyte)x + (sbyte)y + c;
if (ri >= 0x80 || ri <= -0x81) fl |= CpuFlags.P;
adcf[c * 0x10000 + x * 0x100 + y] = fl;
}
}
}
return adcf;
}
#endregion .ctor
public static readonly byte[] Logf;
public static readonly byte[] Adcf; // flags for adc and add
public static readonly byte[] Rlcaf; // flags for RLCA
public static readonly byte[] Rrcaf; // flags for RRCA
public static readonly byte[] Sbcf; // flags for sub and sbc
public static readonly byte[] Cpf; // flags for cp
public static readonly byte[] Cpf8b; // flags for cpi(r)/cpd(r)
public static readonly byte[] Parity; // parity calculator
public static readonly byte[] Rlcf =
// credits to SMT (Unreal)
[ // for rlc r. may be for rlca (0x3B mask)
0x44,0x00,0x00,0x04,0x08,0x0c,0x0c,0x08
,0x00,0x04,0x04,0x00,0x0c,0x08,0x08,0x0c
,0x20,0x24,0x24,0x20,0x2c,0x28,0x28,0x2c
,0x24,0x20,0x20,0x24,0x28,0x2c,0x2c,0x28
,0x00,0x04,0x04,0x00,0x0c,0x08,0x08,0x0c
,0x04,0x00,0x00,0x04,0x08,0x0c,0x0c,0x08
,0x24,0x20,0x20,0x24,0x28,0x2c,0x2c,0x28
,0x20,0x24,0x24,0x20,0x2c,0x28,0x28,0x2c
,0x80,0x84,0x84,0x80,0x8c,0x88,0x88,0x8c
,0x84,0x80,0x80,0x84,0x88,0x8c,0x8c,0x88
,0xa4,0xa0,0xa0,0xa4,0xa8,0xac,0xac,0xa8
,0xa0,0xa4,0xa4,0xa0,0xac,0xa8,0xa8,0xac
,0x84,0x80,0x80,0x84,0x88,0x8c,0x8c,0x88
,0x80,0x84,0x84,0x80,0x8c,0x88,0x88,0x8c
,0xa0,0xa4,0xa4,0xa0,0xac,0xa8,0xa8,0xac
,0xa4,0xa0,0xa0,0xa4,0xa8,0xac,0xac,0xa8
,0x01,0x05,0x05,0x01,0x0d,0x09,0x09,0x0d
,0x05,0x01,0x01,0x05,0x09,0x0d,0x0d,0x09
,0x25,0x21,0x21,0x25,0x29,0x2d,0x2d,0x29
,0x21,0x25,0x25,0x21,0x2d,0x29,0x29,0x2d
,0x05,0x01,0x01,0x05,0x09,0x0d,0x0d,0x09
,0x01,0x05,0x05,0x01,0x0d,0x09,0x09,0x0d
,0x21,0x25,0x25,0x21,0x2d,0x29,0x29,0x2d
,0x25,0x21,0x21,0x25,0x29,0x2d,0x2d,0x29
,0x85,0x81,0x81,0x85,0x89,0x8d,0x8d,0x89
,0x81,0x85,0x85,0x81,0x8d,0x89,0x89,0x8d
,0xa1,0xa5,0xa5,0xa1,0xad,0xa9,0xa9,0xad
,0xa5,0xa1,0xa1,0xa5,0xa9,0xad,0xad,0xa9
,0x81,0x85,0x85,0x81,0x8d,0x89,0x89,0x8d
,0x85,0x81,0x81,0x85,0x89,0x8d,0x8d,0x89
,0xa5,0xa1,0xa1,0xa5,0xa9,0xad,0xad,0xa9
,0xa1,0xa5,0xa5,0xa1,0xad,0xa9,0xa9,0xad
];
public static readonly byte[] Rrcf =
// credits to SMT (Unreal)
[ // rrc r. may be for rlca (0x3B mask)
0x44,0x81,0x00,0x85,0x00,0x85,0x04,0x81
,0x00,0x85,0x04,0x81,0x04,0x81,0x00,0x85
,0x08,0x8d,0x0c,0x89,0x0c,0x89,0x08,0x8d
,0x0c,0x89,0x08,0x8d,0x08,0x8d,0x0c,0x89
,0x00,0x85,0x04,0x81,0x04,0x81,0x00,0x85
,0x04,0x81,0x00,0x85,0x00,0x85,0x04,0x81
,0x0c,0x89,0x08,0x8d,0x08,0x8d,0x0c,0x89
,0x08,0x8d,0x0c,0x89,0x0c,0x89,0x08,0x8d
,0x20,0xa5,0x24,0xa1,0x24,0xa1,0x20,0xa5
,0x24,0xa1,0x20,0xa5,0x20,0xa5,0x24,0xa1
,0x2c,0xa9,0x28,0xad,0x28,0xad,0x2c,0xa9
,0x28,0xad,0x2c,0xa9,0x2c,0xa9,0x28,0xad
,0x24,0xa1,0x20,0xa5,0x20,0xa5,0x24,0xa1
,0x20,0xa5,0x24,0xa1,0x24,0xa1,0x20,0xa5
,0x28,0xad,0x2c,0xa9,0x2c,0xa9,0x28,0xad
,0x2c,0xa9,0x28,0xad,0x28,0xad,0x2c,0xa9
,0x00,0x85,0x04,0x81,0x04,0x81,0x00,0x85
,0x04,0x81,0x00,0x85,0x00,0x85,0x04,0x81
,0x0c,0x89,0x08,0x8d,0x08,0x8d,0x0c,0x89
,0x08,0x8d,0x0c,0x89,0x0c,0x89,0x08,0x8d
,0x04,0x81,0x00,0x85,0x00,0x85,0x04,0x81
,0x00,0x85,0x04,0x81,0x04,0x81,0x00,0x85
,0x08,0x8d,0x0c,0x89,0x0c,0x89,0x08,0x8d
,0x0c,0x89,0x08,0x8d,0x08,0x8d,0x0c,0x89
,0x24,0xa1,0x20,0xa5,0x20,0xa5,0x24,0xa1
,0x20,0xa5,0x24,0xa1,0x24,0xa1,0x20,0xa5
,0x28,0xad,0x2c,0xa9,0x2c,0xa9,0x28,0xad
,0x2c,0xa9,0x28,0xad,0x28,0xad,0x2c,0xa9
,0x20,0xa5,0x24,0xa1,0x24,0xa1,0x20,0xa5
,0x24,0xa1,0x20,0xa5,0x20,0xa5,0x24,0xa1
,0x2c,0xa9,0x28,0xad,0x28,0xad,0x2c,0xa9
,0x28,0xad,0x2c,0xa9,0x2c,0xa9,0x28,0xad
];
public static readonly byte[] Incf =
// credits to SMT (Unreal)
[
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08
,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x10
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08
,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x30
,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x28
,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x30
,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x28
,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x10
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08
,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x10
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08
,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x30
,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x28
,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x30
,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x28
,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x94
,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x88
,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x90
,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x88
,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0xb0
,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa8
,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xb0
,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa8
,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0x90
,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x88
,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x90
,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x88
,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0xb0
,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa8
,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xb0
,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa8
,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0x50
];
public static readonly byte[] Decf =
// credits to SMT (Unreal)
[
0xba,0x42,0x02,0x02,0x02,0x02,0x02,0x02
,0x02,0x0a,0x0a,0x0a,0x0a,0x0a,0x0a,0x0a
,0x1a,0x02,0x02,0x02,0x02,0x02,0x02,0x02
,0x02,0x0a,0x0a,0x0a,0x0a,0x0a,0x0a,0x0a
,0x1a,0x22,0x22,0x22,0x22,0x22,0x22,0x22
,0x22,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a
,0x3a,0x22,0x22,0x22,0x22,0x22,0x22,0x22
,0x22,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a
,0x3a,0x02,0x02,0x02,0x02,0x02,0x02,0x02
,0x02,0x0a,0x0a,0x0a,0x0a,0x0a,0x0a,0x0a
,0x1a,0x02,0x02,0x02,0x02,0x02,0x02,0x02
,0x02,0x0a,0x0a,0x0a,0x0a,0x0a,0x0a,0x0a
,0x1a,0x22,0x22,0x22,0x22,0x22,0x22,0x22
,0x22,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a
,0x3a,0x22,0x22,0x22,0x22,0x22,0x22,0x22
,0x22,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a
,0x3e,0x82,0x82,0x82,0x82,0x82,0x82,0x82
,0x82,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a
,0x9a,0x82,0x82,0x82,0x82,0x82,0x82,0x82
,0x82,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a
,0x9a,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2
,0xa2,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
,0xba,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2
,0xa2,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
,0xba,0x82,0x82,0x82,0x82,0x82,0x82,0x82
,0x82,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a
,0x9a,0x82,0x82,0x82,0x82,0x82,0x82,0x82
,0x82,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a
,0x9a,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2
,0xa2,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
,0xba,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2
,0xa2,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
];
public static readonly ushort[] Daaf =
// credits to SMT (converted from Unreal)
[
0x0044,0x0100,0x0200,0x0304,0x0400,0x0504,0x0604,0x0700,0x0808,0x090C,
0x1010,0x1114,0x1214,0x1310,0x1414,0x1510,0x1000,0x1104,0x1204,0x1300,
0x1404,0x1500,0x1600,0x1704,0x180C,0x1908,0x2030,0x2134,0x2234,0x2330,
0x2434,0x2530,0x2020,0x2124,0x2224,0x2320,0x2424,0x2520,0x2620,0x2724,
0x282C,0x2928,0x3034,0x3130,0x3230,0x3334,0x3430,0x3534,0x3024,0x3120,
0x3220,0x3324,0x3420,0x3524,0x3624,0x3720,0x3828,0x392C,0x4010,0x4114,
0x4214,0x4310,0x4414,0x4510,0x4000,0x4104,0x4204,0x4300,0x4404,0x4500,
0x4600,0x4704,0x480C,0x4908,0x5014,0x5110,0x5210,0x5314,0x5410,0x5514,
0x5004,0x5100,0x5200,0x5304,0x5400,0x5504,0x5604,0x5700,0x5808,0x590C,
0x6034,0x6130,0x6230,0x6334,0x6430,0x6534,0x6024,0x6120,0x6220,0x6324,
0x6420,0x6524,0x6624,0x6720,0x6828,0x692C,0x7030,0x7134,0x7234,0x7330,
0x7434,0x7530,0x7020,0x7124,0x7224,0x7320,0x7424,0x7520,0x7620,0x7724,
0x782C,0x7928,0x8090,0x8194,0x8294,0x8390,0x8494,0x8590,0x8080,0x8184,
0x8284,0x8380,0x8484,0x8580,0x8680,0x8784,0x888C,0x8988,0x9094,0x9190,
0x9290,0x9394,0x9490,0x9594,0x9084,0x9180,0x9280,0x9384,0x9480,0x9584,
0x9684,0x9780,0x9888,0x998C,0x0055,0x0111,0x0211,0x0315,0x0411,0x0515,
0x0045,0x0101,0x0201,0x0305,0x0401,0x0505,0x0605,0x0701,0x0809,0x090D,
0x1011,0x1115,0x1215,0x1311,0x1415,0x1511,0x1001,0x1105,0x1205,0x1301,
0x1405,0x1501,0x1601,0x1705,0x180D,0x1909,0x2031,0x2135,0x2235,0x2331,
0x2435,0x2531,0x2021,0x2125,0x2225,0x2321,0x2425,0x2521,0x2621,0x2725,
0x282D,0x2929,0x3035,0x3131,0x3231,0x3335,0x3431,0x3535,0x3025,0x3121,
0x3221,0x3325,0x3421,0x3525,0x3625,0x3721,0x3829,0x392D,0x4011,0x4115,
0x4215,0x4311,0x4415,0x4511,0x4001,0x4105,0x4205,0x4301,0x4405,0x4501,
0x4601,0x4705,0x480D,0x4909,0x5015,0x5111,0x5211,0x5315,0x5411,0x5515,
0x5005,0x5101,0x5201,0x5305,0x5401,0x5505,0x5605,0x5701,0x5809,0x590D,
0x6035,0x6131,0x6231,0x6335,0x6431,0x6535,0x6025,0x6121,0x6221,0x6325,
0x6421,0x6525,0x6625,0x6721,0x6829,0x692D,0x7031,0x7135,0x7235,0x7331,
0x7435,0x7531,0x7021,0x7125,0x7225,0x7321,0x7425,0x7521,0x7621,0x7725,
0x782D,0x7929,0x8091,0x8195,0x8295,0x8391,0x8495,0x8591,0x8081,0x8185,
0x8285,0x8381,0x8485,0x8581,0x8681,0x8785,0x888D,0x8989,0x9095,0x9191,
0x9291,0x9395,0x9491,0x9595,0x9085,0x9181,0x9281,0x9385,0x9481,0x9585,
0x9685,0x9781,0x9889,0x998D,0xA0B5,0xA1B1,0xA2B1,0xA3B5,0xA4B1,0xA5B5,
0xA0A5,0xA1A1,0xA2A1,0xA3A5,0xA4A1,0xA5A5,0xA6A5,0xA7A1,0xA8A9,0xA9AD,
0xB0B1,0xB1B5,0xB2B5,0xB3B1,0xB4B5,0xB5B1,0xB0A1,0xB1A5,0xB2A5,0xB3A1,
0xB4A5,0xB5A1,0xB6A1,0xB7A5,0xB8AD,0xB9A9,0xC095,0xC191,0xC291,0xC395,
0xC491,0xC595,0xC085,0xC181,0xC281,0xC385,0xC481,0xC585,0xC685,0xC781,
0xC889,0xC98D,0xD091,0xD195,0xD295,0xD391,0xD495,0xD591,0xD081,0xD185,
0xD285,0xD381,0xD485,0xD581,0xD681,0xD785,0xD88D,0xD989,0xE0B1,0xE1B5,
0xE2B5,0xE3B1,0xE4B5,0xE5B1,0xE0A1,0xE1A5,0xE2A5,0xE3A1,0xE4A5,0xE5A1,
0xE6A1,0xE7A5,0xE8AD,0xE9A9,0xF0B5,0xF1B1,0xF2B1,0xF3B5,0xF4B1,0xF5B5,
0xF0A5,0xF1A1,0xF2A1,0xF3A5,0xF4A1,0xF5A5,0xF6A5,0xF7A1,0xF8A9,0xF9AD,
0x0055,0x0111,0x0211,0x0315,0x0411,0x0515,0x0045,0x0101,0x0201,0x0305,
0x0401,0x0505,0x0605,0x0701,0x0809,0x090D,0x1011,0x1115,0x1215,0x1311,
0x1415,0x1511,0x1001,0x1105,0x1205,0x1301,0x1405,0x1501,0x1601,0x1705,
0x180D,0x1909,0x2031,0x2135,0x2235,0x2331,0x2435,0x2531,0x2021,0x2125,
0x2225,0x2321,0x2425,0x2521,0x2621,0x2725,0x282D,0x2929,0x3035,0x3131,
0x3231,0x3335,0x3431,0x3535,0x3025,0x3121,0x3221,0x3325,0x3421,0x3525,
0x3625,0x3721,0x3829,0x392D,0x4011,0x4115,0x4215,0x4311,0x4415,0x4511,
0x4001,0x4105,0x4205,0x4301,0x4405,0x4501,0x4601,0x4705,0x480D,0x4909,
0x5015,0x5111,0x5211,0x5315,0x5411,0x5515,0x5005,0x5101,0x5201,0x5305,
0x5401,0x5505,0x5605,0x5701,0x5809,0x590D,0x6035,0x6131,0x6231,0x6335,
0x6431,0x6535,0x0046,0x0102,0x0202,0x0306,0x0402,0x0506,0x0606,0x0702,
0x080A,0x090E,0x0402,0x0506,0x0606,0x0702,0x080A,0x090E,0x1002,0x1106,
0x1206,0x1302,0x1406,0x1502,0x1602,0x1706,0x180E,0x190A,0x1406,0x1502,
0x1602,0x1706,0x180E,0x190A,0x2022,0x2126,0x2226,0x2322,0x2426,0x2522,
0x2622,0x2726,0x282E,0x292A,0x2426,0x2522,0x2622,0x2726,0x282E,0x292A,
0x3026,0x3122,0x3222,0x3326,0x3422,0x3526,0x3626,0x3722,0x382A,0x392E,
0x3422,0x3526,0x3626,0x3722,0x382A,0x392E,0x4002,0x4106,0x4206,0x4302,
0x4406,0x4502,0x4602,0x4706,0x480E,0x490A,0x4406,0x4502,0x4602,0x4706,
0x480E,0x490A,0x5006,0x5102,0x5202,0x5306,0x5402,0x5506,0x5606,0x5702,
0x580A,0x590E,0x5402,0x5506,0x5606,0x5702,0x580A,0x590E,0x6026,0x6122,
0x6222,0x6326,0x6422,0x6526,0x6626,0x6722,0x682A,0x692E,0x6422,0x6526,
0x6626,0x6722,0x682A,0x692E,0x7022,0x7126,0x7226,0x7322,0x7426,0x7522,
0x7622,0x7726,0x782E,0x792A,0x7426,0x7522,0x7622,0x7726,0x782E,0x792A,
0x8082,0x8186,0x8286,0x8382,0x8486,0x8582,0x8682,0x8786,0x888E,0x898A,
0x8486,0x8582,0x8682,0x8786,0x888E,0x898A,0x9086,0x9182,0x9282,0x9386,
0x9482,0x9586,0x9686,0x9782,0x988A,0x998E,0x3423,0x3527,0x3627,0x3723,
0x382B,0x392F,0x4003,0x4107,0x4207,0x4303,0x4407,0x4503,0x4603,0x4707,
0x480F,0x490B,0x4407,0x4503,0x4603,0x4707,0x480F,0x490B,0x5007,0x5103,
0x5203,0x5307,0x5403,0x5507,0x5607,0x5703,0x580B,0x590F,0x5403,0x5507,
0x5607,0x5703,0x580B,0x590F,0x6027,0x6123,0x6223,0x6327,0x6423,0x6527,
0x6627,0x6723,0x682B,0x692F,0x6423,0x6527,0x6627,0x6723,0x682B,0x692F,
0x7023,0x7127,0x7227,0x7323,0x7427,0x7523,0x7623,0x7727,0x782F,0x792B,
0x7427,0x7523,0x7623,0x7727,0x782F,0x792B,0x8083,0x8187,0x8287,0x8383,
0x8487,0x8583,0x8683,0x8787,0x888F,0x898B,0x8487,0x8583,0x8683,0x8787,
0x888F,0x898B,0x9087,0x9183,0x9283,0x9387,0x9483,0x9587,0x9687,0x9783,
0x988B,0x998F,0x9483,0x9587,0x9687,0x9783,0x988B,0x998F,0xA0A7,0xA1A3,
0xA2A3,0xA3A7,0xA4A3,0xA5A7,0xA6A7,0xA7A3,0xA8AB,0xA9AF,0xA4A3,0xA5A7,
0xA6A7,0xA7A3,0xA8AB,0xA9AF,0xB0A3,0xB1A7,0xB2A7,0xB3A3,0xB4A7,0xB5A3,
0xB6A3,0xB7A7,0xB8AF,0xB9AB,0xB4A7,0xB5A3,0xB6A3,0xB7A7,0xB8AF,0xB9AB,
0xC087,0xC183,0xC283,0xC387,0xC483,0xC587,0xC687,0xC783,0xC88B,0xC98F,
0xC483,0xC587,0xC687,0xC783,0xC88B,0xC98F,0xD083,0xD187,0xD287,0xD383,
0xD487,0xD583,0xD683,0xD787,0xD88F,0xD98B,0xD487,0xD583,0xD683,0xD787,
0xD88F,0xD98B,0xE0A3,0xE1A7,0xE2A7,0xE3A3,0xE4A7,0xE5A3,0xE6A3,0xE7A7,
0xE8AF,0xE9AB,0xE4A7,0xE5A3,0xE6A3,0xE7A7,0xE8AF,0xE9AB,0xF0A7,0xF1A3,
0xF2A3,0xF3A7,0xF4A3,0xF5A7,0xF6A7,0xF7A3,0xF8AB,0xF9AF,0xF4A3,0xF5A7,
0xF6A7,0xF7A3,0xF8AB,0xF9AF,0x0047,0x0103,0x0203,0x0307,0x0403,0x0507,
0x0607,0x0703,0x080B,0x090F,0x0403,0x0507,0x0607,0x0703,0x080B,0x090F,
0x1003,0x1107,0x1207,0x1303,0x1407,0x1503,0x1603,0x1707,0x180F,0x190B,
0x1407,0x1503,0x1603,0x1707,0x180F,0x190B,0x2023,0x2127,0x2227,0x2323,
0x2427,0x2523,0x2623,0x2727,0x282F,0x292B,0x2427,0x2523,0x2623,0x2727,
0x282F,0x292B,0x3027,0x3123,0x3223,0x3327,0x3423,0x3527,0x3627,0x3723,
0x382B,0x392F,0x3423,0x3527,0x3627,0x3723,0x382B,0x392F,0x4003,0x4107,
0x4207,0x4303,0x4407,0x4503,0x4603,0x4707,0x480F,0x490B,0x4407,0x4503,
0x4603,0x4707,0x480F,0x490B,0x5007,0x5103,0x5203,0x5307,0x5403,0x5507,
0x5607,0x5703,0x580B,0x590F,0x5403,0x5507,0x5607,0x5703,0x580B,0x590F,
0x6027,0x6123,0x6223,0x6327,0x6423,0x6527,0x6627,0x6723,0x682B,0x692F,
0x6423,0x6527,0x6627,0x6723,0x682B,0x692F,0x7023,0x7127,0x7227,0x7323,
0x7427,0x7523,0x7623,0x7727,0x782F,0x792B,0x7427,0x7523,0x7623,0x7727,
0x782F,0x792B,0x8083,0x8187,0x8287,0x8383,0x8487,0x8583,0x8683,0x8787,
0x888F,0x898B,0x8487,0x8583,0x8683,0x8787,0x888F,0x898B,0x9087,0x9183,
0x9283,0x9387,0x9483,0x9587,0x9687,0x9783,0x988B,0x998F,0x9483,0x9587,
0x9687,0x9783,0x988B,0x998F,0x0604,0x0700,0x0808,0x090C,0x0A0C,0x0B08,
0x0C0C,0x0D08,0x0E08,0x0F0C,0x1010,0x1114,0x1214,0x1310,0x1414,0x1510,
0x1600,0x1704,0x180C,0x1908,0x1A08,0x1B0C,0x1C08,0x1D0C,0x1E0C,0x1F08,
0x2030,0x2134,0x2234,0x2330,0x2434,0x2530,0x2620,0x2724,0x282C,0x2928,
0x2A28,0x2B2C,0x2C28,0x2D2C,0x2E2C,0x2F28,0x3034,0x3130,0x3230,0x3334,
0x3430,0x3534,0x3624,0x3720,0x3828,0x392C,0x3A2C,0x3B28,0x3C2C,0x3D28,
0x3E28,0x3F2C,0x4010,0x4114,0x4214,0x4310,0x4414,0x4510,0x4600,0x4704,
0x480C,0x4908,0x4A08,0x4B0C,0x4C08,0x4D0C,0x4E0C,0x4F08,0x5014,0x5110,
0x5210,0x5314,0x5410,0x5514,0x5604,0x5700,0x5808,0x590C,0x5A0C,0x5B08,
0x5C0C,0x5D08,0x5E08,0x5F0C,0x6034,0x6130,0x6230,0x6334,0x6430,0x6534,
0x6624,0x6720,0x6828,0x692C,0x6A2C,0x6B28,0x6C2C,0x6D28,0x6E28,0x6F2C,
0x7030,0x7134,0x7234,0x7330,0x7434,0x7530,0x7620,0x7724,0x782C,0x7928,
0x7A28,0x7B2C,0x7C28,0x7D2C,0x7E2C,0x7F28,0x8090,0x8194,0x8294,0x8390,
0x8494,0x8590,0x8680,0x8784,0x888C,0x8988,0x8A88,0x8B8C,0x8C88,0x8D8C,
0x8E8C,0x8F88,0x9094,0x9190,0x9290,0x9394,0x9490,0x9594,0x9684,0x9780,
0x9888,0x998C,0x9A8C,0x9B88,0x9C8C,0x9D88,0x9E88,0x9F8C,0x0055,0x0111,
0x0211,0x0315,0x0411,0x0515,0x0605,0x0701,0x0809,0x090D,0x0A0D,0x0B09,
0x0C0D,0x0D09,0x0E09,0x0F0D,0x1011,0x1115,0x1215,0x1311,0x1415,0x1511,
0x1601,0x1705,0x180D,0x1909,0x1A09,0x1B0D,0x1C09,0x1D0D,0x1E0D,0x1F09,
0x2031,0x2135,0x2235,0x2331,0x2435,0x2531,0x2621,0x2725,0x282D,0x2929,
0x2A29,0x2B2D,0x2C29,0x2D2D,0x2E2D,0x2F29,0x3035,0x3131,0x3231,0x3335,
0x3431,0x3535,0x3625,0x3721,0x3829,0x392D,0x3A2D,0x3B29,0x3C2D,0x3D29,
0x3E29,0x3F2D,0x4011,0x4115,0x4215,0x4311,0x4415,0x4511,0x4601,0x4705,
0x480D,0x4909,0x4A09,0x4B0D,0x4C09,0x4D0D,0x4E0D,0x4F09,0x5015,0x5111,
0x5211,0x5315,0x5411,0x5515,0x5605,0x5701,0x5809,0x590D,0x5A0D,0x5B09,
0x5C0D,0x5D09,0x5E09,0x5F0D,0x6035,0x6131,0x6231,0x6335,0x6431,0x6535,
0x6625,0x6721,0x6829,0x692D,0x6A2D,0x6B29,0x6C2D,0x6D29,0x6E29,0x6F2D,
0x7031,0x7135,0x7235,0x7331,0x7435,0x7531,0x7621,0x7725,0x782D,0x7929,
0x7A29,0x7B2D,0x7C29,0x7D2D,0x7E2D,0x7F29,0x8091,0x8195,0x8295,0x8391,
0x8495,0x8591,0x8681,0x8785,0x888D,0x8989,0x8A89,0x8B8D,0x8C89,0x8D8D,
0x8E8D,0x8F89,0x9095,0x9191,0x9291,0x9395,0x9491,0x9595,0x9685,0x9781,
0x9889,0x998D,0x9A8D,0x9B89,0x9C8D,0x9D89,0x9E89,0x9F8D,0xA0B5,0xA1B1,
0xA2B1,0xA3B5,0xA4B1,0xA5B5,0xA6A5,0xA7A1,0xA8A9,0xA9AD,0xAAAD,0xABA9,
0xACAD,0xADA9,0xAEA9,0xAFAD,0xB0B1,0xB1B5,0xB2B5,0xB3B1,0xB4B5,0xB5B1,
0xB6A1,0xB7A5,0xB8AD,0xB9A9,0xBAA9,0xBBAD,0xBCA9,0xBDAD,0xBEAD,0xBFA9,
0xC095,0xC191,0xC291,0xC395,0xC491,0xC595,0xC685,0xC781,0xC889,0xC98D,
0xCA8D,0xCB89,0xCC8D,0xCD89,0xCE89,0xCF8D,0xD091,0xD195,0xD295,0xD391,
0xD495,0xD591,0xD681,0xD785,0xD88D,0xD989,0xDA89,0xDB8D,0xDC89,0xDD8D,
0xDE8D,0xDF89,0xE0B1,0xE1B5,0xE2B5,0xE3B1,0xE4B5,0xE5B1,0xE6A1,0xE7A5,
0xE8AD,0xE9A9,0xEAA9,0xEBAD,0xECA9,0xEDAD,0xEEAD,0xEFA9,0xF0B5,0xF1B1,
0xF2B1,0xF3B5,0xF4B1,0xF5B5,0xF6A5,0xF7A1,0xF8A9,0xF9AD,0xFAAD,0xFBA9,
0xFCAD,0xFDA9,0xFEA9,0xFFAD,0x0055,0x0111,0x0211,0x0315,0x0411,0x0515,
0x0605,0x0701,0x0809,0x090D,0x0A0D,0x0B09,0x0C0D,0x0D09,0x0E09,0x0F0D,
0x1011,0x1115,0x1215,0x1311,0x1415,0x1511,0x1601,0x1705,0x180D,0x1909,
0x1A09,0x1B0D,0x1C09,0x1D0D,0x1E0D,0x1F09,0x2031,0x2135,0x2235,0x2331,
0x2435,0x2531,0x2621,0x2725,0x282D,0x2929,0x2A29,0x2B2D,0x2C29,0x2D2D,
0x2E2D,0x2F29,0x3035,0x3131,0x3231,0x3335,0x3431,0x3535,0x3625,0x3721,
0x3829,0x392D,0x3A2D,0x3B29,0x3C2D,0x3D29,0x3E29,0x3F2D,0x4011,0x4115,
0x4215,0x4311,0x4415,0x4511,0x4601,0x4705,0x480D,0x4909,0x4A09,0x4B0D,
0x4C09,0x4D0D,0x4E0D,0x4F09,0x5015,0x5111,0x5211,0x5315,0x5411,0x5515,
0x5605,0x5701,0x5809,0x590D,0x5A0D,0x5B09,0x5C0D,0x5D09,0x5E09,0x5F0D,
0x6035,0x6131,0x6231,0x6335,0x6431,0x6535,0xFABE,0xFBBA,0xFCBE,0xFDBA,
0xFEBA,0xFFBE,0x0046,0x0102,0x0202,0x0306,0x0402,0x0506,0x0606,0x0702,
0x080A,0x090E,0x0A1E,0x0B1A,0x0C1E,0x0D1A,0x0E1A,0x0F1E,0x1002,0x1106,
0x1206,0x1302,0x1406,0x1502,0x1602,0x1706,0x180E,0x190A,0x1A1A,0x1B1E,
0x1C1A,0x1D1E,0x1E1E,0x1F1A,0x2022,0x2126,0x2226,0x2322,0x2426,0x2522,
0x2622,0x2726,0x282E,0x292A,0x2A3A,0x2B3E,0x2C3A,0x2D3E,0x2E3E,0x2F3A,
0x3026,0x3122,0x3222,0x3326,0x3422,0x3526,0x3626,0x3722,0x382A,0x392E,
0x3A3E,0x3B3A,0x3C3E,0x3D3A,0x3E3A,0x3F3E,0x4002,0x4106,0x4206,0x4302,
0x4406,0x4502,0x4602,0x4706,0x480E,0x490A,0x4A1A,0x4B1E,0x4C1A,0x4D1E,
0x4E1E,0x4F1A,0x5006,0x5102,0x5202,0x5306,0x5402,0x5506,0x5606,0x5702,
0x580A,0x590E,0x5A1E,0x5B1A,0x5C1E,0x5D1A,0x5E1A,0x5F1E,0x6026,0x6122,
0x6222,0x6326,0x6422,0x6526,0x6626,0x6722,0x682A,0x692E,0x6A3E,0x6B3A,
0x6C3E,0x6D3A,0x6E3A,0x6F3E,0x7022,0x7126,0x7226,0x7322,0x7426,0x7522,
0x7622,0x7726,0x782E,0x792A,0x7A3A,0x7B3E,0x7C3A,0x7D3E,0x7E3E,0x7F3A,
0x8082,0x8186,0x8286,0x8382,0x8486,0x8582,0x8682,0x8786,0x888E,0x898A,
0x8A9A,0x8B9E,0x8C9A,0x8D9E,0x8E9E,0x8F9A,0x9086,0x9182,0x9282,0x9386,
0x3423,0x3527,0x3627,0x3723,0x382B,0x392F,0x3A3F,0x3B3B,0x3C3F,0x3D3B,
0x3E3B,0x3F3F,0x4003,0x4107,0x4207,0x4303,0x4407,0x4503,0x4603,0x4707,
0x480F,0x490B,0x4A1B,0x4B1F,0x4C1B,0x4D1F,0x4E1F,0x4F1B,0x5007,0x5103,
0x5203,0x5307,0x5403,0x5507,0x5607,0x5703,0x580B,0x590F,0x5A1F,0x5B1B,
0x5C1F,0x5D1B,0x5E1B,0x5F1F,0x6027,0x6123,0x6223,0x6327,0x6423,0x6527,
0x6627,0x6723,0x682B,0x692F,0x6A3F,0x6B3B,0x6C3F,0x6D3B,0x6E3B,0x6F3F,
0x7023,0x7127,0x7227,0x7323,0x7427,0x7523,0x7623,0x7727,0x782F,0x792B,
0x7A3B,0x7B3F,0x7C3B,0x7D3F,0x7E3F,0x7F3B,0x8083,0x8187,0x8287,0x8383,
0x8487,0x8583,0x8683,0x8787,0x888F,0x898B,0x8A9B,0x8B9F,0x8C9B,0x8D9F,
0x8E9F,0x8F9B,0x9087,0x9183,0x9283,0x9387,0x9483,0x9587,0x9687,0x9783,
0x988B,0x998F,0x9A9F,0x9B9B,0x9C9F,0x9D9B,0x9E9B,0x9F9F,0xA0A7,0xA1A3,
0xA2A3,0xA3A7,0xA4A3,0xA5A7,0xA6A7,0xA7A3,0xA8AB,0xA9AF,0xAABF,0xABBB,
0xACBF,0xADBB,0xAEBB,0xAFBF,0xB0A3,0xB1A7,0xB2A7,0xB3A3,0xB4A7,0xB5A3,
0xB6A3,0xB7A7,0xB8AF,0xB9AB,0xBABB,0xBBBF,0xBCBB,0xBDBF,0xBEBF,0xBFBB,
0xC087,0xC183,0xC283,0xC387,0xC483,0xC587,0xC687,0xC783,0xC88B,0xC98F,
0xCA9F,0xCB9B,0xCC9F,0xCD9B,0xCE9B,0xCF9F,0xD083,0xD187,0xD287,0xD383,
0xD487,0xD583,0xD683,0xD787,0xD88F,0xD98B,0xDA9B,0xDB9F,0xDC9B,0xDD9F,
0xDE9F,0xDF9B,0xE0A3,0xE1A7,0xE2A7,0xE3A3,0xE4A7,0xE5A3,0xE6A3,0xE7A7,
0xE8AF,0xE9AB,0xEABB,0xEBBF,0xECBB,0xEDBF,0xEEBF,0xEFBB,0xF0A7,0xF1A3,
0xF2A3,0xF3A7,0xF4A3,0xF5A7,0xF6A7,0xF7A3,0xF8AB,0xF9AF,0xFABF,0xFBBB,
0xFCBF,0xFDBB,0xFEBB,0xFFBF,0x0047,0x0103,0x0203,0x0307,0x0403,0x0507,
0x0607,0x0703,0x080B,0x090F,0x0A1F,0x0B1B,0x0C1F,0x0D1B,0x0E1B,0x0F1F,
0x1003,0x1107,0x1207,0x1303,0x1407,0x1503,0x1603,0x1707,0x180F,0x190B,
0x1A1B,0x1B1F,0x1C1B,0x1D1F,0x1E1F,0x1F1B,0x2023,0x2127,0x2227,0x2323,
0x2427,0x2523,0x2623,0x2727,0x282F,0x292B,0x2A3B,0x2B3F,0x2C3B,0x2D3F,
0x2E3F,0x2F3B,0x3027,0x3123,0x3223,0x3327,0x3423,0x3527,0x3627,0x3723,
0x382B,0x392F,0x3A3F,0x3B3B,0x3C3F,0x3D3B,0x3E3B,0x3F3F,0x4003,0x4107,
0x4207,0x4303,0x4407,0x4503,0x4603,0x4707,0x480F,0x490B,0x4A1B,0x4B1F,
0x4C1B,0x4D1F,0x4E1F,0x4F1B,0x5007,0x5103,0x5203,0x5307,0x5403,0x5507,
0x5607,0x5703,0x580B,0x590F,0x5A1F,0x5B1B,0x5C1F,0x5D1B,0x5E1B,0x5F1F,
0x6027,0x6123,0x6223,0x6327,0x6423,0x6527,0x6627,0x6723,0x682B,0x692F,
0x6A3F,0x6B3B,0x6C3F,0x6D3B,0x6E3B,0x6F3F,0x7023,0x7127,0x7227,0x7323,
0x7427,0x7523,0x7623,0x7727,0x782F,0x792B,0x7A3B,0x7B3F,0x7C3B,0x7D3F,
0x7E3F,0x7F3B,0x8083,0x8187,0x8287,0x8383,0x8487,0x8583,0x8683,0x8787,
0x888F,0x898B,0x8A9B,0x8B9F,0x8C9B,0x8D9F,0x8E9F,0x8F9B,0x9087,0x9183,
0x9283,0x9387,0x9483,0x9587,0x9687,0x9783,0x988B,0x998F,
];
public static readonly byte[] Rl0 =
[
0x44,0x00,0x00,0x04,0x08,0x0c,0x0c,0x08
,0x00,0x04,0x04,0x00,0x0c,0x08,0x08,0x0c
,0x20,0x24,0x24,0x20,0x2c,0x28,0x28,0x2c
,0x24,0x20,0x20,0x24,0x28,0x2c,0x2c,0x28
,0x00,0x04,0x04,0x00,0x0c,0x08,0x08,0x0c
,0x04,0x00,0x00,0x04,0x08,0x0c,0x0c,0x08
,0x24,0x20,0x20,0x24,0x28,0x2c,0x2c,0x28
,0x20,0x24,0x24,0x20,0x2c,0x28,0x28,0x2c
,0x80,0x84,0x84,0x80,0x8c,0x88,0x88,0x8c
,0x84,0x80,0x80,0x84,0x88,0x8c,0x8c,0x88
,0xa4,0xa0,0xa0,0xa4,0xa8,0xac,0xac,0xa8
,0xa0,0xa4,0xa4,0xa0,0xac,0xa8,0xa8,0xac
,0x84,0x80,0x80,0x84,0x88,0x8c,0x8c,0x88
,0x80,0x84,0x84,0x80,0x8c,0x88,0x88,0x8c
,0xa0,0xa4,0xa4,0xa0,0xac,0xa8,0xa8,0xac
,0xa4,0xa0,0xa0,0xa4,0xa8,0xac,0xac,0xa8
,0x45,0x01,0x01,0x05,0x09,0x0d,0x0d,0x09
,0x01,0x05,0x05,0x01,0x0d,0x09,0x09,0x0d
,0x21,0x25,0x25,0x21,0x2d,0x29,0x29,0x2d
,0x25,0x21,0x21,0x25,0x29,0x2d,0x2d,0x29
,0x01,0x05,0x05,0x01,0x0d,0x09,0x09,0x0d
,0x05,0x01,0x01,0x05,0x09,0x0d,0x0d,0x09
,0x25,0x21,0x21,0x25,0x29,0x2d,0x2d,0x29
,0x21,0x25,0x25,0x21,0x2d,0x29,0x29,0x2d
,0x81,0x85,0x85,0x81,0x8d,0x89,0x89,0x8d
,0x85,0x81,0x81,0x85,0x89,0x8d,0x8d,0x89
,0xa5,0xa1,0xa1,0xa5,0xa9,0xad,0xad,0xa9
,0xa1,0xa5,0xa5,0xa1,0xad,0xa9,0xa9,0xad
,0x85,0x81,0x81,0x85,0x89,0x8d,0x8d,0x89
,0x81,0x85,0x85,0x81,0x8d,0x89,0x89,0x8d
,0xa1,0xa5,0xa5,0xa1,0xad,0xa9,0xa9,0xad
,0xa5,0xa1,0xa1,0xa5,0xa9,0xad,0xad,0xa9
];
public static readonly byte[] Rl1 =
[
0x00,0x04,0x04,0x00,0x0c,0x08,0x08,0x0c
,0x04,0x00,0x00,0x04,0x08,0x0c,0x0c,0x08
,0x24,0x20,0x20,0x24,0x28,0x2c,0x2c,0x28
,0x20,0x24,0x24,0x20,0x2c,0x28,0x28,0x2c
,0x04,0x00,0x00,0x04,0x08,0x0c,0x0c,0x08
,0x00,0x04,0x04,0x00,0x0c,0x08,0x08,0x0c
,0x20,0x24,0x24,0x20,0x2c,0x28,0x28,0x2c
,0x24,0x20,0x20,0x24,0x28,0x2c,0x2c,0x28
,0x84,0x80,0x80,0x84,0x88,0x8c,0x8c,0x88
,0x80,0x84,0x84,0x80,0x8c,0x88,0x88,0x8c
,0xa0,0xa4,0xa4,0xa0,0xac,0xa8,0xa8,0xac
,0xa4,0xa0,0xa0,0xa4,0xa8,0xac,0xac,0xa8
,0x80,0x84,0x84,0x80,0x8c,0x88,0x88,0x8c
,0x84,0x80,0x80,0x84,0x88,0x8c,0x8c,0x88
,0xa4,0xa0,0xa0,0xa4,0xa8,0xac,0xac,0xa8
,0xa0,0xa4,0xa4,0xa0,0xac,0xa8,0xa8,0xac
,0x01,0x05,0x05,0x01,0x0d,0x09,0x09,0x0d
,0x05,0x01,0x01,0x05,0x09,0x0d,0x0d,0x09
,0x25,0x21,0x21,0x25,0x29,0x2d,0x2d,0x29
,0x21,0x25,0x25,0x21,0x2d,0x29,0x29,0x2d
,0x05,0x01,0x01,0x05,0x09,0x0d,0x0d,0x09
,0x01,0x05,0x05,0x01,0x0d,0x09,0x09,0x0d
,0x21,0x25,0x25,0x21,0x2d,0x29,0x29,0x2d
,0x25,0x21,0x21,0x25,0x29,0x2d,0x2d,0x29
,0x85,0x81,0x81,0x85,0x89,0x8d,0x8d,0x89
,0x81,0x85,0x85,0x81,0x8d,0x89,0x89,0x8d
,0xa1,0xa5,0xa5,0xa1,0xad,0xa9,0xa9,0xad
,0xa5,0xa1,0xa1,0xa5,0xa9,0xad,0xad,0xa9
,0x81,0x85,0x85,0x81,0x8d,0x89,0x89,0x8d
,0x85,0x81,0x81,0x85,0x89,0x8d,0x8d,0x89
,0xa5,0xa1,0xa1,0xa5,0xa9,0xad,0xad,0xa9
,0xa1,0xa5,0xa5,0xa1,0xad,0xa9,0xa9,0xad
];
public static readonly byte[] Rr0 =
[
0x44,0x45,0x00,0x01,0x00,0x01,0x04,0x05
,0x00,0x01,0x04,0x05,0x04,0x05,0x00,0x01
,0x08,0x09,0x0c,0x0d,0x0c,0x0d,0x08,0x09
,0x0c,0x0d,0x08,0x09,0x08,0x09,0x0c,0x0d
,0x00,0x01,0x04,0x05,0x04,0x05,0x00,0x01
,0x04,0x05,0x00,0x01,0x00,0x01,0x04,0x05
,0x0c,0x0d,0x08,0x09,0x08,0x09,0x0c,0x0d
,0x08,0x09,0x0c,0x0d,0x0c,0x0d,0x08,0x09
,0x20,0x21,0x24,0x25,0x24,0x25,0x20,0x21
,0x24,0x25,0x20,0x21,0x20,0x21,0x24,0x25
,0x2c,0x2d,0x28,0x29,0x28,0x29,0x2c,0x2d
,0x28,0x29,0x2c,0x2d,0x2c,0x2d,0x28,0x29
,0x24,0x25,0x20,0x21,0x20,0x21,0x24,0x25
,0x20,0x21,0x24,0x25,0x24,0x25,0x20,0x21
,0x28,0x29,0x2c,0x2d,0x2c,0x2d,0x28,0x29
,0x2c,0x2d,0x28,0x29,0x28,0x29,0x2c,0x2d
,0x00,0x01,0x04,0x05,0x04,0x05,0x00,0x01
,0x04,0x05,0x00,0x01,0x00,0x01,0x04,0x05
,0x0c,0x0d,0x08,0x09,0x08,0x09,0x0c,0x0d
,0x08,0x09,0x0c,0x0d,0x0c,0x0d,0x08,0x09
,0x04,0x05,0x00,0x01,0x00,0x01,0x04,0x05
,0x00,0x01,0x04,0x05,0x04,0x05,0x00,0x01
,0x08,0x09,0x0c,0x0d,0x0c,0x0d,0x08,0x09
,0x0c,0x0d,0x08,0x09,0x08,0x09,0x0c,0x0d
,0x24,0x25,0x20,0x21,0x20,0x21,0x24,0x25
,0x20,0x21,0x24,0x25,0x24,0x25,0x20,0x21
,0x28,0x29,0x2c,0x2d,0x2c,0x2d,0x28,0x29
,0x2c,0x2d,0x28,0x29,0x28,0x29,0x2c,0x2d
,0x20,0x21,0x24,0x25,0x24,0x25,0x20,0x21
,0x24,0x25,0x20,0x21,0x20,0x21,0x24,0x25
,0x2c,0x2d,0x28,0x29,0x28,0x29,0x2c,0x2d
,0x28,0x29,0x2c,0x2d,0x2c,0x2d,0x28,0x29
];
public static readonly byte[] Rr1 =
[
0x80,0x81,0x84,0x85,0x84,0x85,0x80,0x81
,0x84,0x85,0x80,0x81,0x80,0x81,0x84,0x85
,0x8c,0x8d,0x88,0x89,0x88,0x89,0x8c,0x8d
,0x88,0x89,0x8c,0x8d,0x8c,0x8d,0x88,0x89
,0x84,0x85,0x80,0x81,0x80,0x81,0x84,0x85
,0x80,0x81,0x84,0x85,0x84,0x85,0x80,0x81
,0x88,0x89,0x8c,0x8d,0x8c,0x8d,0x88,0x89
,0x8c,0x8d,0x88,0x89,0x88,0x89,0x8c,0x8d
,0xa4,0xa5,0xa0,0xa1,0xa0,0xa1,0xa4,0xa5
,0xa0,0xa1,0xa4,0xa5,0xa4,0xa5,0xa0,0xa1
,0xa8,0xa9,0xac,0xad,0xac,0xad,0xa8,0xa9
,0xac,0xad,0xa8,0xa9,0xa8,0xa9,0xac,0xad
,0xa0,0xa1,0xa4,0xa5,0xa4,0xa5,0xa0,0xa1
,0xa4,0xa5,0xa0,0xa1,0xa0,0xa1,0xa4,0xa5
,0xac,0xad,0xa8,0xa9,0xa8,0xa9,0xac,0xad
,0xa8,0xa9,0xac,0xad,0xac,0xad,0xa8,0xa9
,0x84,0x85,0x80,0x81,0x80,0x81,0x84,0x85
,0x80,0x81,0x84,0x85,0x84,0x85,0x80,0x81
,0x88,0x89,0x8c,0x8d,0x8c,0x8d,0x88,0x89
,0x8c,0x8d,0x88,0x89,0x88,0x89,0x8c,0x8d
,0x80,0x81,0x84,0x85,0x84,0x85,0x80,0x81
,0x84,0x85,0x80,0x81,0x80,0x81,0x84,0x85
,0x8c,0x8d,0x88,0x89,0x88,0x89,0x8c,0x8d
,0x88,0x89,0x8c,0x8d,0x8c,0x8d,0x88,0x89
,0xa0,0xa1,0xa4,0xa5,0xa4,0xa5,0xa0,0xa1
,0xa4,0xa5,0xa0,0xa1,0xa0,0xa1,0xa4,0xa5
,0xac,0xad,0xa8,0xa9,0xa8,0xa9,0xac,0xad
,0xa8,0xa9,0xac,0xad,0xac,0xad,0xa8,0xa9
,0xa4,0xa5,0xa0,0xa1,0xa0,0xa1,0xa4,0xa5
,0xa0,0xa1,0xa4,0xa5,0xa4,0xa5,0xa0,0xa1
,0xa8,0xa9,0xac,0xad,0xac,0xad,0xa8,0xa9
,0xac,0xad,0xa8,0xa9,0xa8,0xa9,0xac,0xad
];
public static readonly byte[] Sraf =
[
0x44,0x45,0x00,0x01,0x00,0x01,0x04,0x05
,0x00,0x01,0x04,0x05,0x04,0x05,0x00,0x01
,0x08,0x09,0x0c,0x0d,0x0c,0x0d,0x08,0x09
,0x0c,0x0d,0x08,0x09,0x08,0x09,0x0c,0x0d
,0x00,0x01,0x04,0x05,0x04,0x05,0x00,0x01
,0x04,0x05,0x00,0x01,0x00,0x01,0x04,0x05
,0x0c,0x0d,0x08,0x09,0x08,0x09,0x0c,0x0d
,0x08,0x09,0x0c,0x0d,0x0c,0x0d,0x08,0x09
,0x20,0x21,0x24,0x25,0x24,0x25,0x20,0x21
,0x24,0x25,0x20,0x21,0x20,0x21,0x24,0x25
,0x2c,0x2d,0x28,0x29,0x28,0x29,0x2c,0x2d
,0x28,0x29,0x2c,0x2d,0x2c,0x2d,0x28,0x29
,0x24,0x25,0x20,0x21,0x20,0x21,0x24,0x25
,0x20,0x21,0x24,0x25,0x24,0x25,0x20,0x21
,0x28,0x29,0x2c,0x2d,0x2c,0x2d,0x28,0x29
,0x2c,0x2d,0x28,0x29,0x28,0x29,0x2c,0x2d
,0x84,0x85,0x80,0x81,0x80,0x81,0x84,0x85
,0x80,0x81,0x84,0x85,0x84,0x85,0x80,0x81
,0x88,0x89,0x8c,0x8d,0x8c,0x8d,0x88,0x89
,0x8c,0x8d,0x88,0x89,0x88,0x89,0x8c,0x8d
,0x80,0x81,0x84,0x85,0x84,0x85,0x80,0x81
,0x84,0x85,0x80,0x81,0x80,0x81,0x84,0x85
,0x8c,0x8d,0x88,0x89,0x88,0x89,0x8c,0x8d
,0x88,0x89,0x8c,0x8d,0x8c,0x8d,0x88,0x89
,0xa0,0xa1,0xa4,0xa5,0xa4,0xa5,0xa0,0xa1
,0xa4,0xa5,0xa0,0xa1,0xa0,0xa1,0xa4,0xa5
,0xac,0xad,0xa8,0xa9,0xa8,0xa9,0xac,0xad
,0xa8,0xa9,0xac,0xad,0xac,0xad,0xa8,0xa9
,0xa4,0xa5,0xa0,0xa1,0xa0,0xa1,0xa4,0xa5
,0xa0,0xa1,0xa4,0xa5,0xa4,0xa5,0xa0,0xa1
,0xa8,0xa9,0xac,0xad,0xac,0xad,0xa8,0xa9
,0xac,0xad,0xa8,0xa9,0xa8,0xa9,0xac,0xad
];
}
}
+199
View File
@@ -0,0 +1,199 @@
/*
* Copyright 2007, 2015 Alex Makeev
*
* This file is part of ZXMAK2 (ZX Spectrum virtual machine).
*
* ZXMAK2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZXMAK2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZXMAK2. If not, see <http://www.gnu.org/licenses/>.
*
* Description: Z80 CPU Emulator [ALU part]
* Date: 13.04.2007
*
*/
namespace ZXMAK2.Engine.Cpu.Processor
{
public partial class Z80Cpu
{
#region ALU
private void ALU_ADDR(byte src)
{
regs.F = CpuTables.Adcf[regs.A + src * 0x100];
regs.A += src;
}
private void ALU_ADCR(byte src)
{
var carry = regs.F & CpuFlags.C;
regs.F = CpuTables.Adcf[regs.A + src * 0x100 + 0x10000 * carry];
regs.A += (byte)(src + carry);
}
private void ALU_SUBR(byte src)
{
regs.F = CpuTables.Sbcf[regs.A * 0x100 + src];
regs.A -= src;
}
private void ALU_SBCR(byte src)
{
var carry = regs.F & CpuFlags.C;
regs.F = CpuTables.Sbcf[regs.A * 0x100 + src + 0x10000 * carry];
regs.A -= (byte)(src + carry);
}
private void ALU_ANDR(byte src)
{
regs.A &= src;
regs.F = (byte)(CpuTables.Logf[regs.A] | CpuFlags.H);
}
private void ALU_XORR(byte src)
{
regs.A ^= src;
regs.F = CpuTables.Logf[regs.A];
}
private void ALU_ORR(byte src)
{
regs.A |= src;
regs.F = CpuTables.Logf[regs.A];
}
private void ALU_CPR(byte src)
{
regs.F = CpuTables.Cpf[regs.A * 0x100 + src];
}
private byte ALU_INCR(byte x)
{
regs.F = (byte)(CpuTables.Incf[x] | (regs.F & CpuFlags.C));
x++;
return x;
}
private byte ALU_DECR(byte x)
{
regs.F = (byte)(CpuTables.Decf[x] | (regs.F & CpuFlags.C));
x--;
return x;
}
private ushort ALU_ADDHLRR(ushort rhl, ushort rde)
{
regs.F = (byte)(regs.F & CpuFlags.NotHNCF3F5);
regs.F |= (byte)((((rhl & 0x0FFF) + (rde & 0x0FFF)) >> 8) & CpuFlags.H);
uint res = (uint)((rhl & 0xFFFF) + (rde & 0xFFFF));
if ((res & 0x10000) != 0) regs.F |= CpuFlags.C;
regs.F |= (byte)((res >> 8) & CpuFlags.F3F5);
return (ushort)res;
}
#endregion
#region ALU #CB
private byte ALU_RLC(int x)
{
regs.F = CpuTables.Rlcf[x];
x <<= 1;
if ((x & 0x100) != 0) x |= 0x01;
return (byte)x;
}
private byte ALU_RRC(int x)
{
regs.F = CpuTables.Rrcf[x];
if ((x & 0x01) != 0) x = (x >> 1) | 0x80;
else x >>= 1;
return (byte)x;
}
private byte ALU_RL(int x)
{
if ((regs.F & CpuFlags.C) != 0)
{
regs.F = CpuTables.Rl1[x];
x <<= 1;
x++;
}
else
{
regs.F = CpuTables.Rl0[x];
x <<= 1;
}
return (byte)x;
}
private byte ALU_RR(int x)
{
if ((regs.F & CpuFlags.C) != 0)
{
regs.F = CpuTables.Rr1[x];
x >>= 1;
x += 0x80;
}
else
{
regs.F = CpuTables.Rr0[x];
x >>= 1;
}
return (byte)x;
}
private byte ALU_SLA(int x)
{
regs.F = CpuTables.Rl0[x];
x <<= 1;
return (byte)x;
}
private byte ALU_SRA(int x)
{
regs.F = CpuTables.Sraf[x];
x = (x >> 1) + (x & 0x80);
return (byte)x;
}
private byte ALU_SLL(int x)
{
regs.F = CpuTables.Rl1[x];
x <<= 1;
x++;
return (byte)x;
}
private byte ALU_SRL(int x)
{
regs.F = CpuTables.Rr0[x];
x >>= 1;
return (byte)x;
}
private void ALU_BIT(byte src, int bit)
{
regs.F = (byte)(CpuTables.Logf[src & (1 << bit)] | CpuFlags.H | (regs.F & CpuFlags.C) | (src & CpuFlags.F3F5));
}
private void ALU_BITMEM(byte src, int bit)
{
regs.F = (byte)(CpuTables.Logf[src & (1 << bit)] | CpuFlags.H | (regs.F & CpuFlags.C));
regs.F = (byte)((regs.F & CpuFlags.NotF3F5) | (regs.MH & CpuFlags.F3F5));
}
#endregion
}
}
+722
View File
@@ -0,0 +1,722 @@
/*
* Copyright 2007, 2015 Alex Makeev
*
* This file is part of ZXMAK2 (ZX Spectrum virtual machine).
*
* ZXMAK2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZXMAK2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZXMAK2. If not, see <http://www.gnu.org/licenses/>.
*
* Description: Z80 CPU Emulator [direct opcode part]
* Date: 13.04.2007
*
*/
namespace ZXMAK2.Engine.Cpu.Processor
{
public partial class Z80Cpu
{
#region direct/DD/FD
private void INA_NN_(byte cmd) // IN A,(N) [11T]
{
// 11T (4, 3, 4)
regs.MW = RDMEM(regs.PC++); Tact += 3;
regs.MW += (ushort)(regs.A << 8);
regs.A = RDPORT(regs.MW); Tact += 4;
regs.MW++;
}
private void OUT_NN_A(byte cmd) // OUT (N),A [11T]+
{
// 11T (4, 3, 4)
regs.MW = RDMEM(regs.PC++); Tact += 3;
regs.MW += (ushort)(regs.A << 8);
WRPORT(regs.MW, regs.A); Tact += 4;
regs.ML++;
}
private void DI(byte cmd)
{
IFF1 = false;
IFF2 = false;
}
private void EI(byte cmd)
{
IFF1 = true;
IFF2 = true;
BINT = true;
}
private void LDSPHL(byte cmd) // LD SP,HL
{
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
regs.SP = regs.HL;
}
private void EX_SP_HL(byte cmd) // EX (SP),HL
{
// 19T (4, 3, 4, 3, 5)
ushort tmpsp = regs.SP;
regs.MW = RDMEM(tmpsp); Tact += 3;
tmpsp++;
regs.MW += (ushort)(RDMEM(tmpsp) * 0x100); Tact += 3;
RDNOMREQ(tmpsp); Tact += 1;
WRMEM(tmpsp, regs.H); Tact += 3;
tmpsp--;
WRMEM(tmpsp, regs.L); Tact += 3;
WRNOMREQ(tmpsp); Tact++;
WRNOMREQ(tmpsp); Tact++;
regs.HL = regs.MW;
}
private void JP_HL_(byte cmd) // JP (HL)
{
regs.PC = regs.HL;
}
private void EXDEHL(byte cmd) // EX DE,HL
{
(regs.DE, regs.HL) = (regs.HL, regs.DE);
}
private void EXAFAF(byte cmd) // EX AF,AF'
{
(regs._AF, regs.AF) = (regs.AF, regs._AF);
}
private void EXX(byte cmd) // EXX
{
(regs._BC, regs.BC) = (regs.BC, regs._BC);
(regs._DE, regs.DE) = (regs.DE, regs._DE);
(regs._HL, regs.HL) = (regs.HL, regs._HL);
}
#endregion
#region logical
private void RLCA(byte cmd)
{
regs.F = (byte)(CpuTables.Rlcaf[regs.A] | (regs.F & CpuFlags.SZP));
int x = regs.A;
x <<= 1;
if ((x & 0x100) != 0) x |= 0x01;
regs.A = (byte)x;
}
private void RRCA(byte cmd)
{
regs.F = (byte)(CpuTables.Rrcaf[regs.A] | (regs.F & CpuFlags.SZP));
int x = regs.A;
if ((x & 0x01) != 0) x = (x >> 1) | 0x80;
else x >>= 1;
regs.A = (byte)x;
}
private void RLA(byte cmd)
{
var carry = (regs.F & CpuFlags.C) != 0;
regs.F = (byte)(CpuTables.Rlcaf[regs.A] | (regs.F & CpuFlags.SZP)); // use same table with rlca
regs.A = (byte)(regs.A << 1);
if (carry) regs.A |= 0x01;
}
private void RRA(byte cmd)
{
var carry = (regs.F & CpuFlags.C) != 0;
regs.F = (byte)(CpuTables.Rrcaf[regs.A] | (regs.F & CpuFlags.SZP)); // use same table with rrca
regs.A = (byte)(regs.A >> 1);
if (carry) regs.A |= 0x80;
}
private void DAA(byte cmd)
{
regs.AF = CpuTables.Daaf[regs.A + 0x100 * ((regs.F & 3) + ((regs.F >> 2) & 4))];
}
private void CPL(byte cmd)
{
regs.A = (byte)~regs.A;
regs.F = (byte)((regs.F & CpuFlags.NotF3F5) | CpuFlags.HN | (regs.A & CpuFlags.F3F5));
}
private void SCF_ZILOG(byte cmd)
{
regs.F = (byte)((regs.F & CpuFlags.SZP) |
(((regs.F ^ regs.Q) | regs.A) & CpuFlags.F3F5) |
CpuFlags.C);
}
private void SCF_ST_CMOS(byte cmd)
{
regs.F = (byte)((regs.F & CpuFlags.SZP) |
((((regs.F ^ regs.Q) & CpuFlags.F5) | regs.A) & CpuFlags.F3F5) |
CpuFlags.C);
}
private void SCF_NEC_NMOS(byte cmd)
{
regs.F = (byte)((regs.F & CpuFlags.SZP) |
(regs.A & CpuFlags.F3F5) |
CpuFlags.C);
}
private void CCF_ZILOG(byte cmd)
{
regs.F = (byte)(((regs.F & CpuFlags.SZPC) ^ CpuFlags.C) |
(((regs.F ^ regs.Q) | regs.A) & CpuFlags.F3F5) |
((regs.F & CpuFlags.C) << 4));
}
private void CCF_ST_CMOS(byte cmd)
{
regs.F = (byte)(((regs.F & CpuFlags.SZPC) ^ CpuFlags.C) |
((((regs.F ^ regs.Q) & CpuFlags.F5) | regs.A) & CpuFlags.F3F5) |
((regs.F & CpuFlags.C) << 4));
}
private void CCF_NEC_NMOS(byte cmd)
{
regs.F = (byte)(((regs.F & CpuFlags.SZPC) ^ CpuFlags.C) |
(regs.A & CpuFlags.F3F5) |
((regs.F & CpuFlags.C) << 4));
}
#endregion
#region jmp/call/ret/jr
private static readonly byte[] s_conds =
[
CpuFlags.Z,
CpuFlags.C,
CpuFlags.P,
CpuFlags.S
];
private void DJNZ(byte cmd) // DJNZ nn
{
// B==0 => 8T (5, 3)
// B!=0 => 13T (5, 3, 5)
RDNOMREQ(regs.IR); Tact++;
int drel = (sbyte)RDMEM(regs.PC); Tact += 3;
regs.PC++;
if (--regs.B != 0)
{
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
regs.MW = (ushort)(regs.PC + drel);
regs.PC = regs.MW;
}
}
private void JRNN(byte cmd) // JR nn
{
// 12T (4, 3, 5)
int drel = (sbyte)RDMEM(regs.PC); Tact += 3;
regs.PC++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
regs.MW = (ushort)(regs.PC + drel);
regs.PC = regs.MW;
}
private void JRXNN(byte cmd) // JR x,nn
{
// false => 7T (4, 3)
// true => 12 (4, 3, 5)
var cond = (cmd & 0x18) >> 3;
var mask = s_conds[cond >> 1];
var f = regs.AF & mask;
if ((cond & 1) != 0) f ^= mask;
int drel = (sbyte)RDMEM(regs.PC); Tact += 3;
regs.PC++;
if (f == 0)
{
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
regs.MW = (ushort)(regs.PC + drel);
regs.PC = regs.MW;
}
}
private void CALLNNNN(byte cmd) // CALL
{
// 17T (4, 3, 4, 3, 3)
regs.MW = RDMEM(regs.PC); Tact += 3;
regs.PC++;
regs.MW += (ushort)(RDMEM(regs.PC) * 0x100); Tact += 3;
RDNOMREQ(regs.PC); Tact++;
regs.PC++;
regs.SP--;
WRMEM(regs.SP, (byte)(regs.PC >> 8)); Tact += 3;
regs.SP--;
WRMEM(regs.SP, (byte)regs.PC); Tact += 3;
regs.PC = regs.MW;
}
private void CALLXNNNN(byte cmd) // CALL x,#nn
{
// false => 10T (4, 3, 3)
// true => 17T (4, 3, 4, 3, 3)
var cond = (cmd & 0x38) >> 3;
var mask = s_conds[cond >> 1];
var f = regs.AF & mask;
if ((cond & 1) != 0) f ^= mask;
regs.MW = RDMEM(regs.PC); Tact += 3;
regs.PC++;
regs.MW += (ushort)(RDMEM(regs.PC) * 0x100); Tact += 3;
if (f == 0)
{
RDNOMREQ(regs.PC); Tact++;
}
regs.PC++;
if (f == 0)
{
regs.SP--;
WRMEM(regs.SP, (byte)(regs.PC >> 8)); Tact += 3;
regs.SP--;
WRMEM(regs.SP, (byte)regs.PC); Tact += 3;
regs.PC = regs.MW;
}
}
private void RET(byte cmd) // RET
{
// 10T (4, 3, 3)
regs.MW = RDMEM(regs.SP); Tact += 3;
regs.SP++;
regs.MW += (ushort)(RDMEM(regs.SP) * 0x100); Tact += 3;
regs.SP++;
regs.PC = regs.MW;
}
private void RETX(byte cmd) // RET x
{
// false => 5T (5)
// true => 11T (5, 3, 3)
var cond = (cmd & 0x38) >> 3;
var mask = s_conds[cond >> 1];
var f = regs.AF & mask;
if ((cond & 1) != 0) f ^= mask;
RDNOMREQ(regs.IR); Tact++;
if (f == 0)
{
regs.MW = RDMEM(regs.SP); Tact += 3;
regs.SP++;
regs.MW += (ushort)(RDMEM(regs.SP) * 0x100); Tact += 3;
regs.SP++;
regs.PC = regs.MW;
}
}
private void JPNNNN(byte cmd) // JP nnnn
{
// 10T (4, 3, 3)
regs.MW = RDMEM(regs.PC); Tact += 3;
regs.PC++;
regs.MW += (ushort)(RDMEM(regs.PC) * 0x100); Tact += 3;
regs.PC = regs.MW;
}
private void JPXNN(byte cmd) // JP x,#nn ???
{
// 10T (4, 3, 3)
var cond = (cmd & 0x38) >> 3;
var mask = s_conds[cond >> 1];
var f = regs.AF & mask;
if ((cond & 1) != 0) f ^= mask;
regs.MW = RDMEM(regs.PC); Tact += 3;
regs.PC++;
regs.MW += (ushort)(RDMEM(regs.PC) * 0x100); Tact += 3;
regs.PC++;
if (f == 0)
regs.PC = regs.MW;
}
private void RSTNN(byte cmd) // RST #nn ?TIME?
{
// 11T (5, 3, 3)
var rst = (ushort)(cmd & 0x38);
RDNOMREQ(regs.IR); Tact++;
regs.SP--;
WRMEM(regs.SP, (byte)(regs.PC >> 8)); Tact += 3;
regs.SP--;
WRMEM(regs.SP, (byte)regs.PC); Tact += 3;
regs.MW = rst;
regs.PC = regs.MW;
}
#endregion
#region push/pop
private void PUSHRR(byte cmd) // PUSH RR ?TIME?
{
// 11T (5, 3, 3)
var rr = (cmd & 0x30) >> 4;
RDNOMREQ(regs.IR); Tact += 1;
ushort val = rr == CpuRegId.Sp ? regs.AF : _pairGetters[rr]();
regs.SP--;
WRMEM(regs.SP, (byte)(val >> 8)); Tact += 3;
regs.SP--;
WRMEM(regs.SP, (byte)val); Tact += 3;
}
private void POPRR(byte cmd) // POP RR
{
// 10T (4, 3, 3)
var rr = (cmd & 0x30) >> 4;
var val = (ushort)RDMEM(regs.SP);
regs.SP++;
Tact += 3;
val |= (ushort)(RDMEM(regs.SP) << 8);
regs.SP++;
if (rr == CpuRegId.Sp) regs.AF = val;
else _pairSetters[rr](val);
Tact += 3;
}
#endregion
#region ALU
private void ALUAN(byte cmd)
{
// 7T (4, 3)
var op = (cmd & 0x38) >> 3;
var val = RDMEM(regs.PC);
regs.PC++;
_alualg[op](val);
Tact += 3;
}
private void ALUAR(byte cmd) // ADD/ADC/SUB/SBC/AND/XOR/OR/CP A,R
{
var r = cmd & 0x07;
var op = (cmd & 0x38) >> 3;
_alualg[op](_regGetters[r]());
}
private void ALUA_HL_(byte cmd) // ADD/ADC/SUB/SBC/AND/XOR/OR/CP A,(HL)
{
// 7T (4, 3)
var op = (cmd & 0x38) >> 3;
var val = RDMEM(regs.HL);
_alualg[op](val);
Tact += 3;
}
private void ADDHLRR(byte cmd) // ADD HL,RR
{
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
regs.MW = (ushort)(regs.HL + 1);
regs.HL = ALU_ADDHLRR(regs.HL, _pairGetters[(cmd & 0x30) >> 4]());
}
#endregion
#region loads
private void LDA_RR_(byte cmd) // LD A,(RR)
{
// 7T (4, 3)
var rr = (cmd & 0x30) >> 4;
var rrValue = _pairGetters[rr]();
regs.A = RDMEM(rrValue);
regs.MW = (ushort)(rrValue + 1);
Tact += 3;
}
private void LDA_NN_(byte cmd) // LD A,(nnnn)
{
// 13T (4, 3, 3, 3)
ushort adr = RDMEM(regs.PC);
regs.PC++;
Tact += 3;
adr += (ushort)(RDMEM(regs.PC) * 0x100);
regs.PC++;
Tact += 3;
regs.A = RDMEM(adr);
regs.MW = (ushort)(adr + 1);
Tact += 3;
}
private void LDHL_NN_(byte cmd) // LD HL,(nnnn)
{
// 16T (4, 3, 3, 3, 3)
var adr = (ushort)RDMEM(regs.PC);
regs.PC++;
Tact += 3;
adr += (ushort)(RDMEM(regs.PC) * 0x100);
regs.PC++;
Tact += 3;
var val = (ushort)RDMEM(adr);
regs.MW = (ushort)(adr + 1);
Tact += 3;
val += (ushort)(RDMEM(regs.MW) * 0x100);
regs.HL = val;
Tact += 3;
}
private void LD_RR_A(byte cmd) // LD (RR),A
{
// 7T (4, 3)
var rr = (cmd & 0x30) >> 4;
var rrValue = _pairGetters[rr]();
WRMEM(rrValue, regs.A);
regs.MH = regs.A;
regs.ML = (byte)(rrValue + 1);
Tact += 3;
}
private void LD_NN_A(byte cmd) // LD (nnnn),A
{
// 13T (4, 3, 3, 3)
ushort adr = RDMEM(regs.PC);
regs.PC++;
Tact += 3;
adr += (ushort)(RDMEM(regs.PC) * 0x100);
regs.PC++;
Tact += 3;
WRMEM(adr, regs.A);
regs.MH = regs.A;
regs.ML = (byte)(adr + 1);
Tact += 3;
}
private void LD_NN_HL(byte cmd) // LD (nnnn),HL
{
// 16T (4, 3, 3, 3, 3)
ushort adr = RDMEM(regs.PC);
regs.PC++;
Tact += 3;
adr += (ushort)(RDMEM(regs.PC) * 0x100);
regs.PC++;
Tact += 3;
WRMEM(adr, regs.L);
regs.MW = (ushort)(adr + 1);
Tact += 3;
WRMEM(regs.MW, regs.H);
Tact += 3;
}
private void LDRRNNNN(byte cmd) // LD RR,nnnn
{
// 10T (4, 3, 3)
var rr = (cmd & 0x30) >> 4;
ushort val = RDMEM(regs.PC);
regs.PC++;
Tact += 3;
val |= (ushort)(RDMEM(regs.PC) << 8);
regs.PC++;
_pairSetters[rr](val);
Tact += 3;
}
private void LDRNN(byte cmd) // LD R,nn
{
// 7T (4, 3)
var r = (cmd & 0x38) >> 3;
_regSetters[r](RDMEM(regs.PC));
regs.PC++;
Tact += 3;
}
private void LD_HL_NN(byte cmd) // LD (HL),nn
{
// 10T (4, 3, 3)
var val = RDMEM(regs.PC);
regs.PC++;
Tact += 3;
WRMEM(regs.HL, val);
Tact += 3;
}
private void LDRdRs(byte cmd) // LD R1,R2
{
var rsrc = cmd & 0x07;
var rdst = (cmd & 0x38) >> 3;
_regSetters[rdst](_regGetters[rsrc]());
}
private void LD_HL_R(byte cmd) // LD (HL),R
{
// 7T (4, 3)
var r = cmd & 0x07;
WRMEM(regs.HL, _regGetters[r]());
Tact += 3;
}
private void LDR_HL_(byte cmd) // LD R,(HL)
{
// 7T (4, 3)
var r = (cmd & 0x38) >> 3;
_regSetters[r](RDMEM(regs.HL));
Tact += 3;
}
#endregion
#region INC/DEC
private void DECRR(byte cmd) // DEC RR
{
var rr = (cmd & 0x30) >> 4;
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
_pairSetters[rr]((ushort)(_pairGetters[rr]() - 1));
}
private void INCRR(byte cmd) // INC RR
{
var rr = (cmd & 0x30) >> 4;
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
_pairSetters[rr]((ushort)(_pairGetters[rr]() + 1));
}
private void DECR(byte cmd) // DEC R
{
var r = (cmd & 0x38) >> 3;
_regSetters[r](ALU_DECR(_regGetters[r]()));
}
private void INCR(byte cmd) // INC R
{
var r = (cmd & 0x38) >> 3;
_regSetters[r](ALU_INCR(_regGetters[r]()));
}
private void DEC_HL_(byte cmd) // DEC (HL)
{
// 11T (4, 4, 3)
var val = RDMEM(regs.HL); Tact += 3;
RDNOMREQ(regs.HL); Tact++;
val = ALU_DECR(val);
WRMEM(regs.HL, val); Tact += 3;
}
private void INC_HL_(byte cmd) // INC (HL)
{
// 11T (4, 4, 3)
var val = RDMEM(regs.HL); Tact += 3;
RDNOMREQ(regs.HL); Tact++;
val = ALU_INCR(val);
WRMEM(regs.HL, val); Tact += 3;
}
#endregion
private void HALT(byte cmd)
{
HALTED = true;
regs.PC--; // workaround for Z80 snapshot halt issue + comfortable debugging
}
}
}
+212
View File
@@ -0,0 +1,212 @@
/*
* Copyright 2007, 2015 Alex Makeev
*
* This file is part of ZXMAK2 (ZX Spectrum virtual machine).
*
* ZXMAK2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZXMAK2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZXMAK2. If not, see <http://www.gnu.org/licenses/>.
*
* Description: Z80 CPU Emulator [CB prefixed opcodes part]
* Date: 13.04.2007
*
*/
namespace ZXMAK2.Engine.Cpu.Processor
{
public partial class Z80Cpu
{
private void CB_RLC(byte cmd) // RLC r
{
var r = cmd & 7;
_regSetters[r](ALU_RLC(_regGetters[r]()));
}
private void CB_RRC(byte cmd) // RRC r
{
var r = cmd & 7;
_regSetters[r](ALU_RRC(_regGetters[r]()));
}
private void CB_RL(byte cmd) // RL r
{
var r = cmd & 7;
_regSetters[r](ALU_RL(_regGetters[r]()));
}
private void CB_RR(byte cmd) // RR r
{
var r = cmd & 7;
_regSetters[r](ALU_RR(_regGetters[r]()));
}
private void CB_SLA(byte cmd) // SLA r
{
var r = cmd & 7;
_regSetters[r](ALU_SLA(_regGetters[r]()));
}
private void CB_SRA(byte cmd) // SRA r
{
var r = cmd & 7;
_regSetters[r](ALU_SRA(_regGetters[r]()));
}
private void CB_SLL(byte cmd) // *SLL r
{
var r = cmd & 7;
_regSetters[r](ALU_SLL(_regGetters[r]()));
}
private void CB_SRL(byte cmd) // SRL r
{
var r = cmd & 7;
_regSetters[r](ALU_SRL(_regGetters[r]()));
}
private void CB_BIT(byte cmd) // BIT r
{
var r = cmd & 7;
var b = (cmd & 0x38) >> 3;
ALU_BIT(_regGetters[r](), b);
}
private void CB_RES(byte cmd) // RES r
{
var r = cmd & 7;
var m = ~(1 << ((cmd & 0x38) >> 3));
_regSetters[r]((byte)(_regGetters[r]() & m));
}
private void CB_SET(byte cmd) // SET r
{
var r = cmd & 7;
var m = 1 << ((cmd & 0x38) >> 3);
_regSetters[r]((byte)(_regGetters[r]() | m));
}
private void CB_RLCHL(byte cmd) // RLC (HL)
{
// 15T (4, 4, 4, 3)
var val = RDMEM(regs.HL); Tact += 3;
RDNOMREQ(regs.HL); Tact++;
val = ALU_RLC(val);
WRMEM(regs.HL, val); Tact += 3;
}
private void CB_RRCHL(byte cmd) // RRC (HL)
{
// 15T (4, 4, 4, 3)
var val = RDMEM(regs.HL); Tact += 3;
RDNOMREQ(regs.HL); Tact++;
val = ALU_RRC(val);
WRMEM(regs.HL, val); Tact += 3;
}
private void CB_RLHL(byte cmd) // RL (HL)
{
// 15T (4, 4, 4, 3)
var val = RDMEM(regs.HL); Tact += 3;
RDNOMREQ(regs.HL); Tact++;
val = ALU_RL(val);
WRMEM(regs.HL, val); Tact += 3;
}
private void CB_RRHL(byte cmd) // RR (HL) [15T]
{
// 15T (4, 4, 4, 3)
var val = RDMEM(regs.HL); Tact += 3;
RDNOMREQ(regs.HL); Tact++;
val = ALU_RR(val);
WRMEM(regs.HL, val); Tact += 3;
}
private void CB_SLAHL(byte cmd) // SLA (HL) [15T]
{
// 15T (4, 4, 4, 3)
var val = RDMEM(regs.HL); Tact += 3;
RDNOMREQ(regs.HL); Tact++;
val = ALU_SLA(val);
WRMEM(regs.HL, val); Tact += 3;
}
private void CB_SRAHL(byte cmd) // SRA (HL) [15T]
{
// 15T (4, 4, 4, 3)
var val = RDMEM(regs.HL); Tact += 3;
RDNOMREQ(regs.HL); Tact++;
val = ALU_SRA(val);
WRMEM(regs.HL, val); Tact += 3;
}
private void CB_SLLHL(byte cmd) // *SLL (HL) [15T]
{
// 15T (4, 4, 4, 3)
var val = RDMEM(regs.HL); Tact += 3;
RDNOMREQ(regs.HL); Tact++;
val = ALU_SLL(val);
WRMEM(regs.HL, val); Tact += 3;
}
private void CB_SRLHL(byte cmd) // SRL (HL)
{
// 15T (4, 4, 4, 3)
var val = RDMEM(regs.HL); Tact += 3;
RDNOMREQ(regs.HL); Tact++;
val = ALU_SRL(val);
WRMEM(regs.HL, val); Tact += 3;
}
private void CB_BITHL(byte cmd) // BIT (HL) [12T]
{
// 12T (4, 4, 4)
var b = (cmd & 0x38) >> 3;
var val = RDMEM(regs.HL); Tact += 4;
ALU_BITMEM(val, b);
}
private void CB_RESHL(byte cmd) // RES (HL) [15T]
{
// 15 (4, 4, 4, 3)
var m = (byte)~(1 << ((cmd & 0x38) >> 3));
var val = RDMEM(regs.HL); Tact += 3;
RDNOMREQ(regs.HL); Tact++;
val &= m;
WRMEM(regs.HL, val); Tact += 3;
}
private void CB_SETHL(byte cmd) // SET (HL) [15T]
{
// 15T (4, 4, 4, 3)
var m = (byte)(1 << ((cmd & 0x38) >> 3));
var val = RDMEM(regs.HL); Tact += 3;
RDNOMREQ(regs.HL); Tact++;
val |= m;
WRMEM(regs.HL, val); Tact += 3;
}
}
}
+880
View File
@@ -0,0 +1,880 @@
/*
* Copyright 2007, 2015 Alex Makeev
*
* This file is part of ZXMAK2 (ZX Spectrum virtual machine).
*
* ZXMAK2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZXMAK2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZXMAK2. If not, see <http://www.gnu.org/licenses/>.
*
* Description: Z80 CPU Emulator [ED prefixed opcode part]
* Date: 13.04.2007
*
*/
using System;
namespace ZXMAK2.Engine.Cpu.Processor
{
public partial class Z80Cpu
{
private void ED_LDI(byte cmd)
{
// 16T (4, 4, 3, 5)
var val = RDMEM(regs.HL); Tact += 3;
WRMEM(regs.DE, val); Tact += 3;
WRNOMREQ(regs.DE); Tact++;
WRNOMREQ(regs.DE); Tact++;
regs.HL++;
regs.DE++;
regs.BC--;
val += regs.A;
regs.F = (byte)((regs.F & CpuFlags.NotHPNF3F5) |
(val & CpuFlags.F3) | ((val << 4) & CpuFlags.F5));
if (regs.BC != 0) regs.F |= CpuFlags.P;
}
private void ED_CPI(byte cmd)
{
// 16T (4, 4, 3, 5)
var cf = regs.F & CpuFlags.C;
var val = RDMEM(regs.HL); Tact += 3;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
regs.HL++;
regs.F = (byte)(CpuTables.Cpf8b[regs.A * 0x100 + val] + cf);
if (--regs.BC != 0) regs.F |= CpuFlags.P;
regs.MW++;
}
private void ED_INI(byte cmd) // INI [16T]
{
// 16T (4, 5, 3, 4)
RDNOMREQ(regs.IR); Tact++;
var val = RDPORT(regs.BC); Tact += 3;
WRMEM(regs.HL, val); Tact += 3;
regs.MW = (ushort)(regs.BC + 1);
regs.HL++;
regs.B--;
//FUSE
byte flgtmp = (byte)(val + regs.C + 1);
regs.F = (byte)(CpuTables.Logf[regs.B] & CpuFlags.NotP);
if ((CpuTables.Logf[(flgtmp & 0x07) ^ regs.B] & CpuFlags.P) != 0) regs.F |= CpuFlags.P;
if (flgtmp < val) regs.F |= CpuFlags.HC;
if ((val & 0x80) != 0) regs.F |= CpuFlags.N;
Tact++; //?? really?
}
private void ED_OUTI(byte cmd) // OUTI [16T]
{
// 16 (4, 5, 3, 4)
RDNOMREQ(regs.IR); Tact++;
regs.B--;
var val = RDMEM(regs.HL); Tact += 3;
WRPORT(regs.BC, val); Tact += 3;
regs.MW = (ushort)(regs.BC + 1);
regs.HL++;
//FUSE
byte flgtmp = (byte)(val + regs.L);
regs.F = (byte)(CpuTables.Logf[regs.B] & CpuFlags.NotP);
if ((CpuTables.Logf[(flgtmp & 0x07) ^ regs.B] & CpuFlags.P) != 0) regs.F |= CpuFlags.P;
if (flgtmp < val) regs.F |= CpuFlags.HC;
if ((val & 0x80) != 0) regs.F |= CpuFlags.N;
Tact++; //?? really?
}
private void ED_LDD(byte cmd)
{
// 16T (4, 4, 3, 5)
var val = RDMEM(regs.HL); Tact += 3;
WRMEM(regs.DE, val); Tact += 3;
WRNOMREQ(regs.DE); Tact++;
WRNOMREQ(regs.DE); Tact++;
regs.HL--;
regs.DE--;
regs.BC--;
val += regs.A;
regs.F = (byte)((regs.F & CpuFlags.NotHPNF3F5) |
(val & CpuFlags.F3) | ((val << 4) & CpuFlags.F5));
if (regs.BC != 0) regs.F |= CpuFlags.P;
}
private void ED_CPD(byte cmd)
{
// 16T (4, 4, 3, 5)
var cf = regs.F & CpuFlags.C;
var val = RDMEM(regs.HL); Tact += 3;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
regs.HL--;
regs.BC--;
regs.MW--;
regs.F = (byte)(CpuTables.Cpf8b[regs.A * 0x100 + val] + cf);
if (regs.BC != 0) regs.F |= CpuFlags.P;
}
private void ED_IND(byte cmd) // IND [16T]
{
// 16T (4, 5, 3, 4)
RDNOMREQ(regs.IR); Tact++;
var val = RDPORT(regs.BC); Tact += 3;
WRMEM(regs.HL, val); Tact += 3;
regs.MW = (ushort)(regs.BC - 1);
regs.HL--;
regs.B--;
//FUSE
byte flgtmp = (byte)(val + regs.C - 1);
regs.F = (byte)(CpuTables.Logf[regs.B] & CpuFlags.NotP);
if ((CpuTables.Logf[(flgtmp & 0x07) ^ regs.B] & CpuFlags.P) != 0) regs.F |= CpuFlags.P;
if (flgtmp < val) regs.F |= CpuFlags.HC;
if ((val & 0x80) != 0) regs.F |= CpuFlags.N;
Tact++; // ?? really?
}
private void ED_OUTD(byte cmd) // OUTD [16T]
{
// 16T (4, 5, 3, 4)
RDNOMREQ(regs.IR); Tact++;
regs.B--;
var val = RDMEM(regs.HL); Tact += 3;
WRPORT(regs.BC, val); Tact += 3;
regs.MW = (ushort)(regs.BC - 1);
regs.HL--;
//FUSE
byte flgtmp = (byte)(val + regs.L);
regs.F = (byte)(CpuTables.Logf[regs.B] & CpuFlags.NotP);
if ((CpuTables.Logf[(flgtmp & 0x07) ^ regs.B] & CpuFlags.P) != 0) regs.F |= CpuFlags.P;
if (flgtmp < val) regs.F |= CpuFlags.HC;
if ((val & 0x80) != 0) regs.F |= CpuFlags.N;
Tact++; // ?? really?
}
private void ED_LDIR(byte cmd)
{
//BC==0 => 16T (4, 4, 3, 5)
//BC!=0 => 21T (4, 4, 3, 5, 5)
var val = RDMEM(regs.HL); Tact += 3;
WRMEM(regs.DE, val); Tact += 3;
WRNOMREQ(regs.DE); Tact++;
WRNOMREQ(regs.DE); Tact++;
regs.BC--;
val += regs.A;
regs.F &= CpuFlags.NotHPNF3F5;
if (regs.BC != 0)
{
WRNOMREQ(regs.DE); Tact++;
WRNOMREQ(regs.DE); Tact++;
WRNOMREQ(regs.DE); Tact++;
WRNOMREQ(regs.DE); Tact++;
WRNOMREQ(regs.DE); Tact++;
regs.PC--;
regs.MW = regs.PC;
regs.PC--;
// YF = PCi.13; XF = PCi.11
regs.F |= (byte)(regs.PCH & CpuFlags.F3F5);
regs.F |= CpuFlags.P;
}
else
{
// YF = PCi.13; XF = PCi.11
regs.F |= (byte)((val & CpuFlags.F3) | ((val << 4) & CpuFlags.F5));
}
regs.HL++;
regs.DE++;
}
private void ED_CPIR(byte cmd)
{
//BC==0 => 16T (4, 4, 3, 5)
//BC!=0 => 21T (4, 4, 3, 5, 5)
regs.MW++;
var cf = regs.F & CpuFlags.C;
var val = RDMEM(regs.HL); Tact += 3;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
regs.BC--;
regs.F = (byte)(CpuTables.Cpf8b[regs.A * 0x100 + val] + cf);
if (regs.BC != 0)
{
regs.F |= CpuFlags.P;
if ((regs.F & CpuFlags.Z) == 0)
{
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
regs.PC--;
regs.MW = regs.PC;
regs.PC--;
// YF = PCi.13; XF = PCi.11
regs.F &= CpuFlags.NotF3F5;
regs.F |= (byte)(regs.PCH & CpuFlags.F3F5);
}
}
regs.HL++;
}
private void ED_INIR(byte cmd) // INIR [16T/21T]
{
// B==0 => 16T (4, 5, 3, 4)
// B!=0 => 21T (4, 5, 3, 4, 5)
RDNOMREQ(regs.IR); Tact++;
var val = RDPORT(regs.BC); Tact += 3;
var nf = (byte)((val >> 6) & CpuFlags.N);
var t = val + ((regs.C + 1) & 0xff);
var hcf = t > 255 ? CpuFlags.HC : 0;
WRMEM(regs.HL++, val); Tact += 3;
regs.MW = (ushort)(regs.BC + 1);
regs.B--; Tact++;
var pf = CpuTables.Parity[(t & 7) ^ regs.B];
if (regs.B != 0)
{
WRNOMREQ(regs.HL); Tact++;
WRNOMREQ(regs.HL); Tact++;
WRNOMREQ(regs.HL); Tact++;
WRNOMREQ(regs.HL); Tact++;
WRNOMREQ(regs.HL); Tact++;
regs.PC -= 2;
regs.F = (byte)(
/* ZF = 0 */
(regs.B & CpuFlags.S) | /* SF = Bo.7 */
(regs.PCH & CpuFlags.F3F5) | /* YF = PCi.13; XF = PCi.11 */
nf); /* NF = IO.7 */
if (hcf != 0)
{
regs.F |= CpuFlags.C;
if ((val & 0x80) != 0)
{
// PF = PF ^ Parity((B - 1) & 0x7) ^ 1;
// HF = (B & 0x0F) == 0x00;
regs.F |= (byte)(pf ^ CpuTables.Parity[(regs.B - 1) & 7] ^ CpuFlags.P);
if ((regs.B & 0x0f) == 0x00)
regs.F |= CpuFlags.H;
}
else
{
// PF = PF ^ Parity((B + 1) & 0x7) ^ 1;
// HF = (B & 0x0F) == 0x0F;
regs.F |= (byte)(pf ^ CpuTables.Parity[(regs.B + 1) & 7] ^ CpuFlags.P);
if ((regs.B & 0x0f) == 0x0f)
regs.F |= CpuFlags.H;
}
}
else
{
// PF = PF ^ Parity(B & 0x7) ^ 1;
regs.F |= (byte)(pf ^ CpuTables.Parity[regs.B & 7] ^ CpuFlags.P);
}
}
else
{
regs.F = (byte)(CpuFlags.Z | /* ZF = 1; SF, YF, XF = 0 */
hcf | /* HF, CF = T > 255 */
pf | /* PF = ((T & 7) ^ Bo).parity */
nf); /* NF = IO.7 */
}
}
private void ED_OTIR(byte cmd) // OTIR [16T/21T]
{
// B==0 => 16T (4, 5, 3, 4)
// B!=0 => 21T (4, 5, 3, 4, 5)
RDNOMREQ(regs.IR); Tact++;
var val = RDMEM(regs.HL++); Tact += 3;
regs.MW = (ushort)(regs.BC + 1);
var nf = (byte)((val >> 6) & CpuFlags.N);
var t = val + regs.L;
var hcf = t > 255 ? CpuFlags.HC : 0;
regs.B--;
var pf = CpuTables.Parity[(t & 7) ^ regs.B];
WRPORT(regs.BC, val); Tact += 3;
Tact++;
if (regs.B != 0)
{
RDNOMREQ(regs.BC); Tact++;
RDNOMREQ(regs.BC); Tact++;
RDNOMREQ(regs.BC); Tact++;
RDNOMREQ(regs.BC); Tact++;
RDNOMREQ(regs.BC); Tact++;
regs.PC -= 2;
regs.F = (byte)(
/* ZF = 0 */
(regs.B & CpuFlags.S) | /* SF = Bo.7 */
(regs.PCH & CpuFlags.F3F5) |/* YF = PCi.13; XF = PCi.11 */
nf); /* NF = IO.7 */
if (hcf != 0)
{
regs.F |= CpuFlags.C;
if ((val & 0x80) != 0)
{
// PF = PF ^ Parity((B - 1) & 0x7) ^ 1;
// HF = (B & 0x0F) == 0x00;
regs.F |= (byte)(pf ^ CpuTables.Parity[(regs.B - 1) & 7] ^ CpuFlags.P);
if ((regs.B & 0x0f) == 0x00)
regs.F |= CpuFlags.H;
}
else
{
// PF = PF ^ Parity((B + 1) & 0x7) ^ 1;
// HF = (B & 0x0F) == 0x0F;
regs.F |= (byte)(pf ^ CpuTables.Parity[(regs.B + 1) & 7] ^ CpuFlags.P);
if ((regs.B & 0x0f) == 0x0f)
regs.F |= CpuFlags.H;
}
}
else
{
// PF = PF ^ Parity(B & 0x7) ^ 1;
regs.F |= (byte)(pf ^ CpuTables.Parity[regs.B & 7] ^ CpuFlags.P);
}
}
else
{
regs.F = (byte)(CpuFlags.Z | /* ZF = 1; SF, YF, XF = 0 */
hcf | /* HF, CF = T > 255 */
pf | /* PF = ((T & 7) ^ Bo).parity */
nf); /* NF = IO.7 */
}
}
private void ED_LDDR(byte cmd)
{
//BC==0 => 16T (4, 4, 3, 5)
//BC!=0 => 21T (4, 4, 3, 5, 5)
var val = RDMEM(regs.HL); Tact += 3;
WRMEM(regs.DE, val); Tact += 3;
WRNOMREQ(regs.DE); Tact++;
WRNOMREQ(regs.DE); Tact++;
regs.BC--;
val += regs.A;
regs.F &= CpuFlags.NotHPNF3F5;
if (regs.BC != 0)
{
WRNOMREQ(regs.DE); Tact++;
WRNOMREQ(regs.DE); Tact++;
WRNOMREQ(regs.DE); Tact++;
WRNOMREQ(regs.DE); Tact++;
WRNOMREQ(regs.DE); Tact++;
regs.PC--;
regs.MW = regs.PC;
regs.PC--;
// YF = PCi.13; XF = PCi.11
regs.F |= (byte)(regs.PCH & CpuFlags.F3F5);
regs.F |= CpuFlags.P;
}
else
{
// YF = PCi.13; XF = PCi.11
regs.F |= (byte)((val & CpuFlags.F3) | ((val << 4) & CpuFlags.F5));
}
regs.HL--;
regs.DE--;
}
private void ED_CPDR(byte cmd)
{
// BC==0 => 16T (4, 4, 3, 5)
// BC!=0 => 21T (4, 4, 3, 5, 5)
regs.MW--;
var cf = regs.F & CpuFlags.C;
var val = RDMEM(regs.HL); Tact += 3;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
regs.BC--;
regs.F = (byte)(CpuTables.Cpf8b[regs.A * 0x100 + val] + cf);
if (regs.BC != 0)
{
regs.F |= CpuFlags.P;
if ((regs.F & CpuFlags.Z) == 0)
{
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
regs.PC--;
regs.MW = regs.PC;
regs.PC--;
// YF = PCi.13; XF = PCi.11
regs.F &= CpuFlags.NotF3F5;
regs.F |= (byte)(regs.PCH & CpuFlags.F3F5);
}
}
regs.HL--;
}
private void ED_INDR(byte cmd) // INDR [16T/21T]
{
// B==0 => 16 (4, 5, 3, 4)
// B!=0 => 21 (4, 5, 3, 4, 5)
RDNOMREQ(regs.IR); Tact++;
var val = RDPORT(regs.BC); Tact += 3;
var nf = (byte)((val >> 6) & CpuFlags.N);
var t = val + ((regs.C - 1) & 0xff);
var hcf = t > 255 ? CpuFlags.HC : 0;
WRMEM(regs.HL--, val); Tact += 3;
regs.MW = (ushort)(regs.BC - 1);
regs.B--; Tact++;
var pf = CpuTables.Parity[(t & 7) ^ regs.B];
if (regs.B != 0)
{
WRNOMREQ(regs.HL); Tact++;
WRNOMREQ(regs.HL); Tact++;
WRNOMREQ(regs.HL); Tact++;
WRNOMREQ(regs.HL); Tact++;
WRNOMREQ(regs.HL); Tact++;
regs.PC -= 2;
regs.F = (byte)(
/* ZF = 0 */
(regs.B & CpuFlags.S) | /* SF = Bo.7 */
(regs.PCH & CpuFlags.F3F5) |/* YF = PCi.13; XF = PCi.11 */
nf); /* NF = IO.7 */
if (hcf != 0)
{
regs.F |= CpuFlags.C;
if ((val & 0x80) != 0)
{
// PF = PF ^ Parity((B - 1) & 0x7) ^ 1;
// HF = (B & 0x0F) == 0x00;
regs.F |= (byte)(pf ^ CpuTables.Parity[(regs.B - 1) & 7] ^ CpuFlags.P);
if ((regs.B & 0x0f) == 0x00)
regs.F |= CpuFlags.H;
}
else
{
// PF = PF ^ Parity((B + 1) & 0x7) ^ 1;
// HF = (B & 0x0F) == 0x0F;
regs.F |= (byte)(pf ^ CpuTables.Parity[(regs.B + 1) & 7] ^ CpuFlags.P);
if ((regs.B & 0x0f) == 0x0f)
regs.F |= CpuFlags.H;
}
}
else
{
// PF = PF ^ Parity(B & 0x7) ^ 1;
regs.F |= (byte)(pf ^ CpuTables.Parity[regs.B & 7] ^ CpuFlags.P);
}
}
else
{
regs.F = (byte)(CpuFlags.Z | /* ZF = 1; SF, YF, XF = 0 */
hcf | /* HF, CF = T > 255 */
pf | /* PF = ((T & 7) ^ Bo).parity */
nf); /* NF = IO.7 */
}
}
private void ED_OTDR(byte cmd) //OTDR [16T/21T]
{
// B==0 => 16T (4, 5, 3, 4)
// B!=0 => 21T (4, 5, 3, 4, 5)
RDNOMREQ(regs.IR); Tact++;
var val = RDMEM(regs.HL--); Tact += 3;
regs.MW = (ushort)(regs.BC - 1);
var nf = (byte)((val >> 6) & CpuFlags.N);
var t = val + regs.L;
var hcf = t > 255 ? CpuFlags.HC : 0;
regs.B--;
var pf = CpuTables.Parity[(t & 7) ^ regs.B];
WRPORT(regs.BC, val); Tact += 3;
Tact++;
if (regs.B != 0)
{
RDNOMREQ(regs.BC); Tact++;
RDNOMREQ(regs.BC); Tact++;
RDNOMREQ(regs.BC); Tact++;
RDNOMREQ(regs.BC); Tact++;
RDNOMREQ(regs.BC); Tact++;
regs.PC -= 2;
regs.F = (byte)(
/* ZF = 0 */
(regs.B & CpuFlags.S) | /* SF = Bo.7 */
(regs.PCH & CpuFlags.F3F5) |/* YF = PCi.13; XF = PCi.11 */
nf); /* NF = IO.7 */
if (hcf != 0)
{
regs.F |= CpuFlags.C;
if ((val & 0x80) != 0)
{
// PF = PF ^ Parity((B - 1) & 0x7) ^ 1;
// HF = (B & 0x0F) == 0x00;
regs.F |= (byte)(pf ^ CpuTables.Parity[(regs.B - 1) & 7] ^ CpuFlags.P);
if ((regs.B & 0x0f) == 0x00)
regs.F |= CpuFlags.H;
}
else
{
// PF = PF ^ Parity((B + 1) & 0x7) ^ 1;
// HF = (B & 0x0F) == 0x0F;
regs.F |= (byte)(pf ^ CpuTables.Parity[(regs.B + 1) & 7] ^ CpuFlags.P);
if ((regs.B & 0x0f) == 0x0f)
regs.F |= CpuFlags.H;
}
}
else
{
// PF = PF ^ Parity(B & 0x7) ^ 1;
regs.F |= (byte)(pf ^ CpuTables.Parity[regs.B & 7] ^ CpuFlags.P);
}
}
else
{
regs.F = (byte)(CpuFlags.Z | /* ZF = 1; SF, YF, XF = 0 */
hcf | /* HF, CF = T > 255 */
pf | /* PF = ((T & 7) ^ Bo).parity */
nf); /* NF = IO.7 */
}
}
private void ED_INRC(byte cmd) // in R,(c) [12T]
{
// 12T (4, 4, 4)
var r = (cmd & 0x38) >> 3;
regs.MW = regs.BC;
var pval = RDPORT(regs.BC);
regs.MW++;
if (r != CpuRegId.F)
_regSetters[r](pval);
regs.F = (byte)(CpuTables.Logf[pval] | (regs.F & CpuFlags.C));
Tact += 4;
}
private void ED_OUTCR_NMOS(byte cmd) // out (c),R [12T]
{
// 12T (4, 4, 4)
var r = (cmd & 0x38) >> 3;
regs.MW = regs.BC;
if (r != CpuRegId.F)
WRPORT(regs.BC, _regGetters[r]());
else
WRPORT(regs.BC, 0x00); // 0 for Z80 and 0xFF for Z84
regs.MW++;
Tact += 4;
}
private void ED_OUTCR_CMOS(byte cmd) // out (c),R [12T]
{
// 12T (4, 4, 4)
var r = (cmd & 0x38) >> 3;
regs.MW = regs.BC;
if (r != CpuRegId.F)
WRPORT(regs.BC, _regGetters[r]());
else
WRPORT(regs.BC, 0xFF); // 0 for Z80 and 0xFF for Z84
regs.MW++;
Tact += 4;
}
private void ED_ADCHLRR(byte cmd) // adc hl,RR
{
var rr = (cmd & 0x30) >> 4;
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
regs.MW = (ushort)(regs.HL + 1);
byte fl = (byte)((((regs.HL & 0x0FFF) + (_pairGetters[rr]() & 0x0FFF) + (regs.F & CpuFlags.C)) >> 8) & CpuFlags.H);
uint tmp = (uint)((regs.HL & 0xFFFF) + (_pairGetters[rr]() & 0xFFFF) + (regs.F & CpuFlags.C)); // AF???
if ((tmp & 0x10000) != 0) fl |= CpuFlags.C;
if ((tmp & 0xFFFF) == 0) fl |= CpuFlags.Z;
int ri = (int)(short)regs.HL + (int)(short)_pairGetters[rr]() + (int)(regs.F & CpuFlags.C);
if (ri < -0x8000 || ri >= 0x8000) fl |= CpuFlags.P;
regs.HL = (ushort)tmp;
regs.F = (byte)(fl | (regs.H & CpuFlags.SF3F5));
}
private void ED_SBCHLRR(byte cmd) // sbc hl,RR
{
var rr = (cmd & 0x30) >> 4;
RDNOMREQ(regs.IR); Tact += 1;
RDNOMREQ(regs.IR); Tact += 1;
RDNOMREQ(regs.IR); Tact += 1;
RDNOMREQ(regs.IR); Tact += 1;
RDNOMREQ(regs.IR); Tact += 1;
RDNOMREQ(regs.IR); Tact += 1;
RDNOMREQ(regs.IR); Tact += 1;
regs.MW = (ushort)(regs.HL + 1);
byte fl = CpuFlags.N;
fl |= (byte)((((regs.HL & 0x0FFF) - (_pairGetters[rr]() & 0x0FFF) - (regs.F & CpuFlags.C)) >> 8) & CpuFlags.H);
uint tmp = (uint)((regs.HL & 0xFFFF) - (_pairGetters[rr]() & 0xFFFF) - (regs.F & CpuFlags.C)); // AF???
if ((tmp & 0x10000) != 0) fl |= CpuFlags.C;
if ((tmp & 0xFFFF) == 0) fl |= CpuFlags.Z;
int ri = (int)(short)regs.HL - (int)(short)_pairGetters[rr]() - (int)(regs.F & CpuFlags.C);
if (ri < -0x8000 || ri >= 0x8000) fl |= CpuFlags.P;
regs.HL = (ushort)tmp;
regs.F = (byte)(fl | (regs.H & CpuFlags.SF3F5));
}
private void ED_LDRR_NN_(byte cmd) // ld RR,(NN)
{
// 20T (4, 4, 3, 3, 3, 3)
var rr = (cmd & 0x30) >> 4;
var adr = (ushort)RDMEM(regs.PC);
regs.PC++;
Tact += 3;
adr += (ushort)(RDMEM(regs.PC) * 0x100);
regs.PC++;
regs.MW = (ushort)(adr + 1);
Tact += 3;
var val = (ushort)RDMEM(adr);
Tact += 3;
val += (ushort)(RDMEM(regs.MW) * 0x100);
_pairSetters[rr](val);
Tact += 3;
}
private void ED_LD_NN_RR(byte cmd) // ld (NN),RR
{
// 20 (4, 4, 3, 3, 3, 3)
var rr = (cmd & 0x30) >> 4;
var adr = (ushort)RDMEM(regs.PC);
regs.PC++;
Tact += 3;
adr += (ushort)(RDMEM(regs.PC) * 0x100);
regs.PC++;
regs.MW = (ushort)(adr + 1);
var val = _pairGetters[rr]();
Tact += 3;
WRMEM(adr, (byte)val);
Tact += 3;
WRMEM(regs.MW, (byte)(val >> 8));
Tact += 3;
}
private void ED_RETN(byte cmd) // reti/retn
{
// 14T (4, 4, 3, 3)
IFF1 = IFF2;
var adr = (ushort)RDMEM(regs.SP);
Tact += 3;
adr += (ushort)(RDMEM(++regs.SP) * 0x100);
++regs.SP;
regs.PC = adr;
regs.MW = adr;
Tact += 3;
}
private void ED_IM(byte cmd) // im X
{
var mode = (byte)((cmd & 0x18) >> 3);
if (mode < 2) mode = 1;
mode--;
IM = mode;
}
private void ED_LDXRA(byte cmd) // ld I/R,a
{
var ir = (cmd & 0x08) == 0;
RDNOMREQ(regs.IR); Tact++;
if (ir) // I
regs.I = regs.A;
else
regs.R = regs.A;
}
private void ED_LDAXR(byte cmd) // ld a,I/R
{
var ir = (cmd & 0x08) == 0;
RDNOMREQ(regs.IR); Tact++;
if (ir) // I
regs.A = regs.I;
else
regs.A = regs.R;
regs.F = (byte)(((regs.F & CpuFlags.C) | CpuTables.Logf[regs.A]) & CpuFlags.NotP);
switch (_type)
{
case CpuType.ZILOG_NMOS:
case CpuType.NEC_NMOS:
case CpuType.ST_CMOS:
SCANSIG?.Invoke();
if (!(INT && IFF1) && IFF2)
{
regs.F |= CpuFlags.P;
}
break;
case CpuType.ZILOG_CMOS:
if (IFF2)
{
regs.F |= CpuFlags.P;
}
break;
default:
throw new NotImplementedException();
}
}
private void ED_RRD(byte cmd) // RRD
{
// 18T (4, 4, 3, 4, 3)
var tmp = RDMEM(regs.HL); Tact += 3;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
regs.MW = (ushort)(regs.HL + 1);
var val = (byte)((regs.A << 4) | (tmp >> 4));
WRMEM(regs.HL, val); Tact += 3;
regs.A = (byte)((regs.A & 0xF0) | (tmp & 0x0F));
regs.F = (byte)(CpuTables.Logf[regs.A] | (regs.F & CpuFlags.C));
}
private void ED_RLD(byte cmd) // RLD
{
// 18T (4, 4, 3, 4, 3)
var tmp = RDMEM(regs.HL); Tact += 3;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
RDNOMREQ(regs.HL); Tact++;
regs.MW = (ushort)(regs.HL + 1);
var val = (byte)((regs.A & 0x0F) | (tmp << 4));
WRMEM(regs.HL, val); Tact += 3;
regs.A = (byte)((regs.A & 0xF0) | (tmp >> 4));
regs.F = (byte)(CpuTables.Logf[regs.A] | (regs.F & CpuFlags.C));
}
private void ED_NEG(byte cmd) // NEG
{
regs.F = CpuTables.Sbcf[regs.A];
regs.A = (byte)-regs.A;
}
}
}
+485
View File
@@ -0,0 +1,485 @@
/*
* Copyright 2007, 2015 Alex Makeev
*
* This file is part of ZXMAK2 (ZX Spectrum virtual machine).
*
* ZXMAK2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZXMAK2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZXMAK2. If not, see <http://www.gnu.org/licenses/>.
*
* Description: Z80 CPU Emulator [DD/FD prefixed opcode part]
* Date: 13.04.2007
*
*/
using System;
namespace ZXMAK2.Engine.Cpu.Processor
{
public partial class Z80Cpu
{
#region FXxx ops...
private void FX_LDSPHL(byte cmd) // LD SP,IX
{
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
if (FX == CpuModeIndex.Ix)
regs.SP = regs.IX;
else
regs.SP = regs.IY;
}
private void FX_EX_SP_HL(byte cmd) // EX (SP),IX
{
// 23T (4, 4, 3, 4, 3, 5)
var tmpsp = regs.SP;
regs.MW = RDMEM(tmpsp); Tact += 3;
tmpsp++;
regs.MW += (ushort)(RDMEM(tmpsp) * 0x100); Tact += 3;
RDNOMREQ(tmpsp); Tact++;
if (FX == CpuModeIndex.Ix)
{
WRMEM(tmpsp, regs.XH); Tact += 3;
tmpsp--;
WRMEM(tmpsp, regs.XL); Tact += 3;
WRNOMREQ(tmpsp); Tact++;
WRNOMREQ(tmpsp); Tact++;
regs.IX = regs.MW;
}
else
{
WRMEM(tmpsp, regs.YH); Tact += 3;
tmpsp--;
WRMEM(tmpsp, regs.YL); Tact += 3;
WRNOMREQ(tmpsp); Tact++;
WRNOMREQ(tmpsp); Tact++;
regs.IY = regs.MW;
}
}
private void FX_JP_HL_(byte cmd) // JP (IX)
{
if (FX == CpuModeIndex.Ix)
regs.PC = regs.IX;
else
regs.PC = regs.IY;
}
private void FX_PUSHIX(byte cmd) // PUSH IX
{
// 15 (4, 5, 3, 3)
RDNOMREQ(regs.IR); Tact++;
var val = FX == CpuModeIndex.Ix ? regs.IX : regs.IY;
regs.SP--;
WRMEM(regs.SP, (byte)(val >> 8)); Tact += 3;
regs.SP--;
WRMEM(regs.SP, (byte)val); Tact += 3;
}
private void FX_POPIX(byte cmd) // POP IX
{
// 14T (4, 4, 3, 3)
var val = (ushort)RDMEM(regs.SP);
regs.SP++;
Tact += 3;
val |= (ushort)(RDMEM(regs.SP) << 8);
regs.SP++;
if (FX == CpuModeIndex.Ix)
regs.IX = val;
else
regs.IY = val;
Tact += 3;
}
private void FX_ALUAXH(byte cmd) // ADD/ADC/SUB/SBC/AND/XOR/OR/CP A,XH
{
byte val;
if (FX == CpuModeIndex.Ix)
val = (byte)(regs.IX >> 8);
else
val = (byte)(regs.IY >> 8);
_alualg[(cmd & 0x38) >> 3](val);
}
private void FX_ALUAXL(byte cmd) // ADD/ADC/SUB/SBC/AND/XOR/OR/CP A,XL
{
byte val;
if (FX == CpuModeIndex.Ix)
val = (byte)regs.IX;
else
val = (byte)regs.IY;
_alualg[(cmd & 0x38) >> 3](val);
}
private void FX_ALUA_IX_(byte cmd) // ADD/ADC/SUB/SBC/AND/XOR/OR/CP A,(IX)
{
// 19T (4, 4, 3, 5, 3)
var op = (cmd & 0x38) >> 3;
int drel = (sbyte)RDMEM(regs.PC); Tact += 3;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
regs.PC++;
regs.MW = FX == CpuModeIndex.Ix ? regs.IX : regs.IY;
regs.MW = (ushort)(regs.MW + drel);
var val = RDMEM(regs.MW); Tact += 3;
_alualg[op](val);
}
private void FX_ADDIXRR(byte cmd) // ADD IX,RR
{
var rr = (cmd & 0x30) >> 4;
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
var rde = rr switch
{
0 => regs.BC,
1 => regs.DE,
2 => FX == CpuModeIndex.Ix ? regs.IX : regs.IY,
3 => regs.SP,
_ => throw new ArgumentOutOfRangeException(nameof(cmd), "(cmd & 0x30) >> 4 is out of range"),
};
if (FX == CpuModeIndex.Ix)
{
regs.MW = (ushort)(regs.IX + 1);
regs.IX = ALU_ADDHLRR(regs.IX, rde);
}
else
{
regs.MW = (ushort)(regs.IY + 1);
regs.IY = ALU_ADDHLRR(regs.IY, rde);
}
}
private void FX_DECIX(byte cmd) // DEC IX
{
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
if (FX == CpuModeIndex.Ix)
regs.IX--;
else
regs.IY--;
}
private void FX_INCIX(byte cmd) // INC IX
{
RDNOMREQ(regs.IR); Tact++;
RDNOMREQ(regs.IR); Tact++;
if (FX == CpuModeIndex.Ix)
regs.IX++;
else
regs.IY++;
}
private void FX_LDIX_N_(byte cmd) // LD IX,(nnnn)
{
// 20 (4, 4, 3, 3, 3, 3)
var adr = (ushort)RDMEM(regs.PC);
regs.PC++;
Tact += 3;
adr += (ushort)(RDMEM(regs.PC) * 0x100);
regs.PC++;
regs.MW = (ushort)(adr + 1);
Tact += 3;
var val = (ushort)RDMEM(adr);
Tact += 3;
val += (ushort)(RDMEM(regs.MW) * 0x100);
if (FX == CpuModeIndex.Ix)
regs.IX = val;
else
regs.IY = val;
Tact += 3;
}
private void FX_LD_NN_IX(byte cmd) // LD (nnnn),IX
{
// 20 (4, 4, 3, 3, 3, 3)
var hl = FX == CpuModeIndex.Ix ? regs.IX : regs.IY;
var adr = (ushort)RDMEM(regs.PC);
regs.PC++;
Tact += 3;
adr += (ushort)(RDMEM(regs.PC) * 0x100);
regs.PC++;
regs.MW = (ushort)(adr + 1);
Tact += 3;
WRMEM(adr, (byte)hl);
Tact += 3;
WRMEM(regs.MW, (byte)(hl >> 8));
Tact += 3;
}
private void FX_LDIXNNNN(byte cmd) // LD IX,nnnn
{
// 14 (4, 4, 3, 3)
var val = (ushort)RDMEM(regs.PC);
regs.PC++;
Tact += 3;
val |= (ushort)(RDMEM(regs.PC) << 8);
regs.PC++;
if (FX == CpuModeIndex.Ix)
regs.IX = val;
else
regs.IY = val;
Tact += 3;
}
private void FX_DEC_IX_(byte cmd) // DEC (IX)
{
// 23T (4, 4, 3, 5, 4, 3)
int drel = (sbyte)RDMEM(regs.PC); Tact += 3;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
regs.PC++;
regs.MW = FX == CpuModeIndex.Ix ? regs.IX : regs.IY;
regs.MW = (ushort)(regs.MW + drel);
var val = RDMEM(regs.MW); Tact += 3;
RDNOMREQ(regs.MW); Tact++;
val = ALU_DECR(val);
WRMEM(regs.MW, val); Tact += 3;
}
private void FX_INC_IX_(byte cmd) // INC (IX)
{
//23T (4, 4, 3, 5, 4, 3)
int drel = (sbyte)RDMEM(regs.PC); Tact += 3;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
regs.PC++;
regs.MW = FX == CpuModeIndex.Ix ? regs.IX : regs.IY;
regs.MW = (ushort)(regs.MW + drel);
var val = RDMEM(regs.MW); Tact += 3;
RDNOMREQ(regs.MW); Tact++;
val = ALU_INCR(val);
WRMEM(regs.MW, val); Tact += 3;
}
private void FX_LD_IX_NN(byte cmd) // LD (IX),nn
{
// 19 (4, 4, 3, 5, 3)
int drel = (sbyte)RDMEM(regs.PC); Tact += 3;
regs.PC++;
var val = RDMEM(regs.PC); Tact += 3;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
regs.PC++;
regs.MW = FX == CpuModeIndex.Ix ? regs.IX : regs.IY;
regs.MW = (ushort)(regs.MW + drel);
WRMEM(regs.MW, val); Tact += 3;
}
private void FX_LD_IX_R(byte cmd) // LD (IX),R
{
// 19T (4, 4, 3, 5, 3)
var r = cmd & 0x07;
int drel = (sbyte)RDMEM(regs.PC); Tact += 3;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
regs.PC++;
regs.MW = FX == CpuModeIndex.Ix ? regs.IX : regs.IY;
regs.MW = (ushort)(regs.MW + drel);
WRMEM(regs.MW, _regGetters[r]()); Tact += 3;
}
private void FX_LDR_IX_(byte cmd) // LD R,(IX)
{
// 19T (4, 4, 3, 5, 3)
var r = (cmd & 0x38) >> 3;
int drel = (sbyte)RDMEM(regs.PC); Tact += 3;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
regs.PC++;
regs.MW = FX == CpuModeIndex.Ix ? regs.IX : regs.IY;
regs.MW = (ushort)(regs.MW + drel);
_regSetters[r](RDMEM(regs.MW)); Tact += 3;
}
#endregion
#region RdRs...
private void FX_LDHL(byte cmd)
{
if (FX == CpuModeIndex.Ix)
regs.XH = regs.XL;
else
regs.YH = regs.YL;
}
private void FX_LDLH(byte cmd)
{
if (FX == CpuModeIndex.Ix)
regs.XL = regs.XH;
else
regs.YL = regs.YH;
}
private void FX_LDRL(byte cmd)
{
var r = (cmd & 0x38) >> 3;
if (FX == CpuModeIndex.Ix)
_regSetters[r](regs.XL);
else
_regSetters[r](regs.YL);
}
private void FX_LDRH(byte cmd)
{
var r = (cmd & 0x38) >> 3;
if (FX == CpuModeIndex.Ix)
_regSetters[r](regs.XH);
else
_regSetters[r](regs.YH);
}
private void FX_LDLR(byte cmd)
{
var r = cmd & 0x07;
if (FX == CpuModeIndex.Ix)
regs.XL = _regGetters[r]();
else
regs.YL = _regGetters[r]();
}
private void FX_LDHR(byte cmd)
{
var r = cmd & 0x07;
if (FX == CpuModeIndex.Ix)
regs.XH = _regGetters[r]();
else
regs.YH = _regGetters[r]();
}
private void FX_LDLNN(byte cmd) // LD XL,nn
{
// 11T (4, 4, 3)
if (FX == CpuModeIndex.Ix)
regs.XL = RDMEM(regs.PC);
else
regs.YL = RDMEM(regs.PC);
regs.PC++;
Tact += 3;
}
private void FX_LDHNN(byte cmd) // LD XH,nn
{
// 11T (4, 4, 3)
if (FX == CpuModeIndex.Ix)
regs.XH = RDMEM(regs.PC);
else
regs.YH = RDMEM(regs.PC);
regs.PC++;
Tact += 3;
}
private void FX_INCL(byte cmd) // INC XL
{
if (FX == CpuModeIndex.Ix)
regs.XL = ALU_INCR(regs.XL);
else
regs.YL = ALU_INCR(regs.YL);
}
private void FX_INCH(byte cmd) // INC XH
{
if (FX == CpuModeIndex.Ix)
regs.XH = ALU_INCR(regs.XH);
else
regs.YH = ALU_INCR(regs.YH);
}
private void FX_DECL(byte cmd) // DEC XL
{
if (FX == CpuModeIndex.Ix)
regs.XL = ALU_DECR(regs.XL);
else
regs.YL = ALU_DECR(regs.YL);
}
private void FX_DECH(byte cmd) // DEC XH
{
if (FX == CpuModeIndex.Ix)
regs.XH = ALU_DECR(regs.XH);
else
regs.YH = ALU_DECR(regs.YH);
}
#endregion
}
}
+263
View File
@@ -0,0 +1,263 @@
/*
* Copyright 2007, 2011, 2015 Alex Makeev
*
* This file is part of ZXMAK2 (ZX Spectrum virtual machine).
*
* ZXMAK2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZXMAK2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZXMAK2. If not, see <http://www.gnu.org/licenses/>.
*
* Description: Z80 CPU Emulator [FXCB prefixed opcodes part]
* Date: 25.09.2011
*
*/
namespace ZXMAK2.Engine.Cpu.Processor
{
public partial class Z80Cpu
{
private void FXCB_RLC(byte cmd, ushort adr) // *RLC r
{
// 23T (4, 4, 3, 5, 4, 3)
var r = cmd & 7;
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
val = ALU_RLC(val);
_regSetters[r](val);
WRMEM(adr, val); Tact += 3;
}
private void FXCB_RRC(byte cmd, ushort adr) // *RRC r
{
// 23T (4, 4, 3, 5, 4, 3)
var r = cmd & 7;
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
val = ALU_RRC(val);
_regSetters[r](val);
WRMEM(adr, val); Tact += 3;
}
private void FXCB_RL(byte cmd, ushort adr) // *RL r
{
// 23T (4, 4, 3, 5, 4, 3)
var r = cmd & 7;
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
val = ALU_RL(val);
_regSetters[r](val);
WRMEM(adr, val); Tact += 3;
}
private void FXCB_RR(byte cmd, ushort adr) // *RR r
{
// 23T (4, 4, 3, 5, 4, 3)
var r = cmd & 7;
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
val = ALU_RR(val);
_regSetters[r](val);
WRMEM(adr, val); Tact += 3;
}
private void FXCB_SLA(byte cmd, ushort adr) // *SLA r
{
// 23T (4, 4, 3, 5, 4, 3)
var r = cmd & 7;
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
val = ALU_SLA(val);
_regSetters[r](val);
WRMEM(adr, val); Tact += 3;
}
private void FXCB_SRA(byte cmd, ushort adr) // *SRA r
{
// 23T (4, 4, 3, 5, 4, 3)
var r = cmd & 7;
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
val = ALU_SRA(val);
_regSetters[r](val);
WRMEM(adr, val); Tact += 3;
}
private void FXCB_SLL(byte cmd, ushort adr) // **SLL r
{
// 23T (4, 4, 3, 5, 4, 3)
var r = cmd & 7;
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
val = ALU_SLL(val);
_regSetters[r](val);
WRMEM(adr, val); Tact += 3;
}
private void FXCB_SRL(byte cmd, ushort adr) // *SRL r
{
// 23T (4, 4, 3, 5, 4, 3)
var r = cmd & 7;
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
val = ALU_SRL(val);
_regSetters[r](val);
WRMEM(adr, val); Tact += 3;
}
private void FXCB_RES(byte cmd, ushort adr) // *RES b,r,(IX+drel)
{
// 23T (4, 4, 3, 5, 4, 3)
var m = (byte)~(1 << ((cmd & 0x38) >> 3));
var r = cmd & 7;
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
val &= m;
_regSetters[r](val);
WRMEM(adr, val); Tact += 3;
}
private void FXCB_SET(byte cmd, ushort adr) // *SET b,r,(IX+drel)
{
// 23T (4, 4, 3, 5, 4, 3)
var m = (byte)(1 << ((cmd & 0x38) >> 3));
var r = cmd & 7;
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
val |= m;
_regSetters[r](val);
WRMEM(adr, val); Tact += 3;
}
private void FXCB_RLCIX(byte cmd, ushort adr) // RLC (IX+) [23T]
{
// 23T (4, 4, 3, 5, 4, 3)
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
val = ALU_RLC(val);
WRMEM(adr, val); Tact += 3;
}
private void FXCB_RRCIX(byte cmd, ushort adr) // RRC (IX+)
{
// 23T (4, 4, 3, 5, 4, 3)
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
val = ALU_RRC(val);
WRMEM(adr, val); Tact += 3;
}
private void FXCB_RLIX(byte cmd, ushort adr) // RL (IX+)
{
// 23T (4, 4, 3, 5, 4, 3)
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
val = ALU_RL(val);
WRMEM(adr, val); Tact += 3;
}
private void FXCB_RRIX(byte cmd, ushort adr) // RR (IX+)
{
// 23T (4, 4, 3, 5, 4, 3)
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
val = ALU_RR(val);
WRMEM(adr, val); Tact += 3;
}
private void FXCB_SLAIX(byte cmd, ushort adr) // SLA (IX+)
{
// 23T (4, 4, 3, 5, 4, 3)
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
val = ALU_SLA(val);
WRMEM(adr, val); Tact += 3;
}
private void FXCB_SRAIX(byte cmd, ushort adr) // SRA (IX+)
{
// 23T (4, 4, 3, 5, 4, 3)
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
val = ALU_SRA(val);
WRMEM(adr, val); Tact += 3;
}
private void FXCB_SLLIX(byte cmd, ushort adr) // *SLL (IX+)
{
// 23T (4, 4, 3, 5, 4, 3)
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
val = ALU_SLL(val);
WRMEM(adr, val); Tact += 3;
}
private void FXCB_SRLIX(byte cmd, ushort adr) // SRL (IX+)
{
// 23T (4, 4, 3, 5, 4, 3)
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
val = ALU_SRL(val);
WRMEM(adr, val); Tact += 3;
}
private void FXCB_BITIX(byte cmd, ushort adr) // BIT (IX+)
{
// 20T (4, 4, 3, 5, 4)
var b = (cmd & 0x38) >> 3;
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
ALU_BITMEM(val, b);
}
private void FXCB_RESIX(byte cmd, ushort adr) // RES (IX+)
{
// 23T (4, 4, 3, 5, 4, 3)
var m = (byte)~(1 << ((cmd & 0x38) >> 3));
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
val &= m;
WRMEM(adr, val); Tact += 3;
}
private void FXCB_SETIX(byte cmd, ushort adr) // SET (IX+)
{
// 23T (4, 4, 3, 5, 4, 3)
var m = (byte)(1 << ((cmd & 0x38) >> 3));
var val = RDMEM(adr); Tact += 3;
RDNOMREQ(adr); Tact++;
val |= m;
WRMEM(adr, val); Tact += 3;
}
}
}
+297
View File
@@ -0,0 +1,297 @@
/*
* Copyright 2007, 2015 Alex Makeev
*
* This file is part of ZXMAK2 (ZX Spectrum virtual machine).
*
* ZXMAK2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZXMAK2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZXMAK2. If not, see <http://www.gnu.org/licenses/>.
*
*/
using System;
namespace ZXMAK2.Engine.Cpu.Processor
{
public partial class Z80Cpu
{
private readonly Action<byte>[] _opcodes;
private readonly Action<byte>[] _opcodesFx;
private readonly Action<byte>[] _opcodesEd;
private readonly Action<byte>[] _opcodesCb;
private readonly Action<byte, ushort>[] _opcodesFxCb;
private readonly Action<byte>[] _alualg;
private readonly Func<ushort>[] _pairGetters;
private readonly Action<ushort>[] _pairSetters;
private readonly Func<byte>[] _regGetters;
private readonly Action<byte>[] _regSetters;
private Action<byte>[] CreateOpcodes()
{
Action<byte> scf;
Action<byte> ccf;
switch (_type)
{
case CpuType.ZILOG_NMOS:
case CpuType.ZILOG_CMOS:
scf = SCF_ZILOG;
ccf = CCF_ZILOG;
break;
case CpuType.NEC_NMOS:
scf = SCF_NEC_NMOS;
ccf = CCF_NEC_NMOS;
break;
case CpuType.ST_CMOS:
scf = SCF_ST_CMOS;
ccf = CCF_ST_CMOS;
break;
default: throw new NotImplementedException();
}
var opcodes = new Action<byte>[256]
{
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
null, LDRRNNNN, LD_RR_A, INCRR, INCR, DECR, LDRNN, RLCA, EXAFAF, ADDHLRR, LDA_RR_, DECRR, INCR, DECR, LDRNN, RRCA, // 00..0F
DJNZ, LDRRNNNN, LD_RR_A, INCRR, INCR, DECR, LDRNN, RLA, JRNN, ADDHLRR, LDA_RR_, DECRR, INCR, DECR, LDRNN, RRA, // 10..1F
JRXNN, LDRRNNNN, LD_NN_HL, INCRR, INCR, DECR, LDRNN, DAA, JRXNN, ADDHLRR, LDHL_NN_, DECRR, INCR, DECR, LDRNN, CPL, // 20..2F
JRXNN, LDRRNNNN, LD_NN_A, INCRR, INC_HL_, DEC_HL_, LD_HL_NN, scf, JRXNN, ADDHLRR, LDA_NN_, DECRR, INCR, DECR, LDRNN, ccf, // 30..3F
null, LDRdRs, LDRdRs, LDRdRs, LDRdRs, LDRdRs, LDR_HL_, LDRdRs, LDRdRs, null, LDRdRs, LDRdRs, LDRdRs, LDRdRs, LDR_HL_, LDRdRs, // 40..4F
LDRdRs, LDRdRs, null, LDRdRs, LDRdRs, LDRdRs, LDR_HL_, LDRdRs, LDRdRs, LDRdRs, LDRdRs, null, LDRdRs, LDRdRs, LDR_HL_, LDRdRs, // 50..5F
LDRdRs, LDRdRs, LDRdRs, LDRdRs, null, LDRdRs, LDR_HL_, LDRdRs, LDRdRs, LDRdRs, LDRdRs, LDRdRs, LDRdRs, null, LDR_HL_, LDRdRs, // 60..6F
LD_HL_R, LD_HL_R, LD_HL_R, LD_HL_R, LD_HL_R, LD_HL_R, HALT, LD_HL_R, LDRdRs, LDRdRs, LDRdRs, LDRdRs, LDRdRs, LDRdRs, LDR_HL_, null, // 70..7F
ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, ALUA_HL_, ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, ALUA_HL_, ALUAR, // 80..8F
ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, ALUA_HL_, ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, ALUA_HL_, ALUAR, // 90..9F
ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, ALUA_HL_, ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, ALUA_HL_, ALUAR, // A0..AF
ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, ALUA_HL_, ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, ALUA_HL_, ALUAR, // B0..BF
RETX, POPRR, JPXNN, JPNNNN, CALLXNNNN, PUSHRR, ALUAN, RSTNN, RETX, RET, JPXNN, null, CALLXNNNN, CALLNNNN, ALUAN, RSTNN, // C0..CF
RETX, POPRR, JPXNN, OUT_NN_A, CALLXNNNN, PUSHRR, ALUAN, RSTNN, RETX, EXX, JPXNN, INA_NN_, CALLXNNNN, null, ALUAN, RSTNN, // D0..DF
RETX, POPRR, JPXNN, EX_SP_HL, CALLXNNNN, PUSHRR, ALUAN, RSTNN, RETX, JP_HL_, JPXNN, EXDEHL, CALLXNNNN, null, ALUAN, RSTNN, // E0..EF
RETX, POPRR, JPXNN, DI, CALLXNNNN, PUSHRR, ALUAN, RSTNN, RETX, LDSPHL, JPXNN, EI, CALLXNNNN, null, ALUAN, RSTNN, // F0..FF
};
return opcodes;
// patch opcodes with optimized version
//for (var cmd = 0; cmd < 0x100; cmd++)
//{
// opcodes[cmd] =
// EmitOpcodeLdRegReg(cmd) ??
// EmitOpcodeJrXdisp(cmd) ??
// opcodes[cmd];
//}
//return opcodes;
}
private Action<byte>[] CreateOpcodesFx()
{
Action<byte> scf;
Action<byte> ccf;
switch (_type)
{
case CpuType.ZILOG_NMOS:
case CpuType.ZILOG_CMOS:
scf = SCF_ZILOG;
ccf = CCF_ZILOG;
break;
case CpuType.NEC_NMOS:
scf = SCF_NEC_NMOS;
ccf = CCF_NEC_NMOS;
break;
case CpuType.ST_CMOS:
scf = SCF_ST_CMOS;
ccf = CCF_ST_CMOS;
break;
default: throw new NotImplementedException();
}
return
[
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
null, LDRRNNNN, LD_RR_A, INCRR, INCR, DECR, LDRNN, RLCA, EXAFAF, FX_ADDIXRR, LDA_RR_, DECRR, INCR, DECR, LDRNN, RRCA, // 00..0F
DJNZ, LDRRNNNN, LD_RR_A, INCRR, INCR, DECR, LDRNN, RLA, JRNN, FX_ADDIXRR, LDA_RR_, DECRR, INCR, DECR, LDRNN, RRA, // 10..1F
JRXNN, FX_LDIXNNNN, FX_LD_NN_IX, FX_INCIX, FX_INCH, FX_DECH, FX_LDHNN, DAA, JRXNN, FX_ADDIXRR, FX_LDIX_N_, FX_DECIX, FX_INCL, FX_DECL, FX_LDLNN, CPL, // 20..2F
JRXNN, LDRRNNNN, LD_NN_A, INCRR, FX_INC_IX_, FX_DEC_IX_, FX_LD_IX_NN, scf, JRXNN, FX_ADDIXRR, LDA_NN_, DECRR, INCR, DECR, LDRNN, ccf, // 30..3F
null, LDRdRs, LDRdRs, LDRdRs, FX_LDRH, FX_LDRL, FX_LDR_IX_, LDRdRs, LDRdRs, null, LDRdRs, LDRdRs, FX_LDRH, FX_LDRL, FX_LDR_IX_, LDRdRs, // 40..4F
LDRdRs, LDRdRs, null, LDRdRs, FX_LDRH, FX_LDRL, FX_LDR_IX_, LDRdRs, LDRdRs, LDRdRs, LDRdRs, null, FX_LDRH, FX_LDRL, FX_LDR_IX_, LDRdRs, // 50..5F
FX_LDHR, FX_LDHR, FX_LDHR, FX_LDHR, null, FX_LDHL, FX_LDR_IX_, FX_LDHR, FX_LDLR, FX_LDLR, FX_LDLR, FX_LDLR, FX_LDLH, null, FX_LDR_IX_, FX_LDLR,// 60..6F
FX_LD_IX_R, FX_LD_IX_R, FX_LD_IX_R, FX_LD_IX_R, FX_LD_IX_R, FX_LD_IX_R, HALT, FX_LD_IX_R, LDRdRs, LDRdRs, LDRdRs, LDRdRs, FX_LDRH, FX_LDRL, FX_LDR_IX_, null, // 70..7F
ALUAR, ALUAR, ALUAR, ALUAR, FX_ALUAXH, FX_ALUAXL, FX_ALUA_IX_, ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, FX_ALUAXH, FX_ALUAXL, FX_ALUA_IX_, ALUAR, // 80..8F
ALUAR, ALUAR, ALUAR, ALUAR, FX_ALUAXH, FX_ALUAXL, FX_ALUA_IX_, ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, FX_ALUAXH, FX_ALUAXL, FX_ALUA_IX_, ALUAR, // 90..9F
ALUAR, ALUAR, ALUAR, ALUAR, FX_ALUAXH, FX_ALUAXL, FX_ALUA_IX_, ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, FX_ALUAXH, FX_ALUAXL, FX_ALUA_IX_, ALUAR, // A0..AF
ALUAR, ALUAR, ALUAR, ALUAR, FX_ALUAXH, FX_ALUAXL, FX_ALUA_IX_, ALUAR, ALUAR, ALUAR, ALUAR, ALUAR, FX_ALUAXH, FX_ALUAXL, FX_ALUA_IX_, ALUAR, // B0..BF
RETX, POPRR, JPXNN, JPNNNN, CALLXNNNN, PUSHRR, ALUAN, RSTNN, RETX, RET, JPXNN, null, CALLXNNNN, CALLNNNN, ALUAN, RSTNN, // C0..CF
RETX, POPRR, JPXNN, OUT_NN_A, CALLXNNNN, PUSHRR, ALUAN, RSTNN, RETX, EXX, JPXNN, INA_NN_, CALLXNNNN, null, ALUAN, RSTNN, // D0..DF
RETX, FX_POPIX, JPXNN, FX_EX_SP_HL, CALLXNNNN, FX_PUSHIX, ALUAN, RSTNN, RETX, FX_JP_HL_, JPXNN, EXDEHL, CALLXNNNN, null, ALUAN, RSTNN, // E0..EF
RETX, POPRR, JPXNN, DI, CALLXNNNN, PUSHRR, ALUAN, RSTNN, RETX, FX_LDSPHL, JPXNN, EI, CALLXNNNN, null, ALUAN, RSTNN, // F0..FF
];
}
private Action<byte>[] CreateOpcodesEd()
{
Action<byte> ed_outcr = _type switch
{
CpuType.ZILOG_NMOS or CpuType.NEC_NMOS => ED_OUTCR_NMOS,
CpuType.ST_CMOS or CpuType.ZILOG_CMOS => ED_OUTCR_CMOS,
_ => throw new NotImplementedException(),
};
return
[
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, // 00..0F
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, // 10..1F
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, // 20..2F
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, // 30..3F
ED_INRC, ed_outcr, ED_SBCHLRR, ED_LD_NN_RR, ED_NEG, ED_RETN, ED_IM, ED_LDXRA, ED_INRC, ed_outcr, ED_ADCHLRR, ED_LDRR_NN_, ED_NEG, ED_RETN, ED_IM, ED_LDXRA, // 40..4F
ED_INRC, ed_outcr, ED_SBCHLRR, ED_LD_NN_RR, ED_NEG, ED_RETN, ED_IM, ED_LDAXR, ED_INRC, ed_outcr, ED_ADCHLRR, ED_LDRR_NN_, ED_NEG, ED_RETN, ED_IM, ED_LDAXR, // 50..5F
ED_INRC, ed_outcr, ED_SBCHLRR, ED_LD_NN_RR, ED_NEG, ED_RETN, ED_IM, ED_RRD, ED_INRC, ed_outcr, ED_ADCHLRR, ED_LDRR_NN_, ED_NEG, ED_RETN, ED_IM, ED_RLD, // 60..6F
ED_INRC, ed_outcr, ED_SBCHLRR, ED_LD_NN_RR, ED_NEG, ED_RETN, ED_IM, null, ED_INRC, ed_outcr, ED_ADCHLRR, ED_LDRR_NN_, ED_NEG, ED_RETN, ED_IM, null, // 70..7F
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, // 80..8F
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, // 90..9F
ED_LDI, ED_CPI, ED_INI, ED_OUTI, null, null, null, null, ED_LDD, ED_CPD, ED_IND, ED_OUTD, null, null, null, null, // A0..AF
ED_LDIR, ED_CPIR, ED_INIR, ED_OTIR, null, null, null, null, ED_LDDR, ED_CPDR, ED_INDR, ED_OTDR, null, null, null, null, // B0..BF
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, // C0..CF
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, // D0..DF
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, // E0..EF
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null // F0..FF
];
}
private Action<byte>[] CreateOpcodesCb()
{
return
[
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
CB_RLC, CB_RLC, CB_RLC, CB_RLC, CB_RLC, CB_RLC, CB_RLCHL, CB_RLC, CB_RRC, CB_RRC, CB_RRC, CB_RRC, CB_RRC, CB_RRC, CB_RRCHL, CB_RRC, // 00..0F
CB_RL, CB_RL, CB_RL, CB_RL, CB_RL, CB_RL, CB_RLHL, CB_RL, CB_RR, CB_RR, CB_RR, CB_RR, CB_RR, CB_RR, CB_RRHL, CB_RR, // 10..1F
CB_SLA, CB_SLA, CB_SLA, CB_SLA, CB_SLA, CB_SLA, CB_SLAHL, CB_SLA, CB_SRA, CB_SRA, CB_SRA, CB_SRA, CB_SRA, CB_SRA, CB_SRAHL, CB_SRA, // 20..2F
CB_SLL, CB_SLL, CB_SLL, CB_SLL, CB_SLL, CB_SLL, CB_SLLHL, CB_SLL, CB_SRL, CB_SRL, CB_SRL, CB_SRL, CB_SRL, CB_SRL, CB_SRLHL, CB_SRL, // 30..3F
CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BITHL, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BITHL, CB_BIT, // 40..4F
CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BITHL, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BITHL, CB_BIT, // 50..5F
CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BITHL, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BITHL, CB_BIT, // 60..6F
CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BITHL, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BIT, CB_BITHL, CB_BIT, // 70..7F
CB_RES, CB_RES, CB_RES, CB_RES, CB_RES, CB_RES, CB_RESHL, CB_RES, CB_RES, CB_RES, CB_RES, CB_RES, CB_RES, CB_RES, CB_RESHL, CB_RES, // 80..8F
CB_RES, CB_RES, CB_RES, CB_RES, CB_RES, CB_RES, CB_RESHL, CB_RES, CB_RES, CB_RES, CB_RES, CB_RES, CB_RES, CB_RES, CB_RESHL, CB_RES, // 90..9F
CB_RES, CB_RES, CB_RES, CB_RES, CB_RES, CB_RES, CB_RESHL, CB_RES, CB_RES, CB_RES, CB_RES, CB_RES, CB_RES, CB_RES, CB_RESHL, CB_RES, // A0..AF
CB_RES, CB_RES, CB_RES, CB_RES, CB_RES, CB_RES, CB_RESHL, CB_RES, CB_RES, CB_RES, CB_RES, CB_RES, CB_RES, CB_RES, CB_RESHL, CB_RES, // B0..BF
CB_SET, CB_SET, CB_SET, CB_SET, CB_SET, CB_SET, CB_SETHL, CB_SET, CB_SET, CB_SET, CB_SET, CB_SET, CB_SET, CB_SET, CB_SETHL, CB_SET, // C0..CF
CB_SET, CB_SET, CB_SET, CB_SET, CB_SET, CB_SET, CB_SETHL, CB_SET, CB_SET, CB_SET, CB_SET, CB_SET, CB_SET, CB_SET, CB_SETHL, CB_SET, // D0..DF
CB_SET, CB_SET, CB_SET, CB_SET, CB_SET, CB_SET, CB_SETHL, CB_SET, CB_SET, CB_SET, CB_SET, CB_SET, CB_SET, CB_SET, CB_SETHL, CB_SET, // E0..EF
CB_SET, CB_SET, CB_SET, CB_SET, CB_SET, CB_SET, CB_SETHL, CB_SET, CB_SET, CB_SET, CB_SET, CB_SET, CB_SET, CB_SET, CB_SETHL, CB_SET, // F0..FF
];
}
private Action<byte, ushort>[] CreateOpcodesFxCb()
{
return
[
FXCB_RLC, FXCB_RLC, FXCB_RLC, FXCB_RLC, FXCB_RLC, FXCB_RLC, FXCB_RLCIX, FXCB_RLC, FXCB_RRC, FXCB_RRC, FXCB_RRC, FXCB_RRC, FXCB_RRC, FXCB_RRC, FXCB_RRCIX, FXCB_RRC, // 00..0F
FXCB_RL, FXCB_RL, FXCB_RL, FXCB_RL, FXCB_RL, FXCB_RL, FXCB_RLIX, FXCB_RL, FXCB_RR, FXCB_RR, FXCB_RR, FXCB_RR, FXCB_RR, FXCB_RR, FXCB_RRIX, FXCB_RR, // 10..1F
FXCB_SLA, FXCB_SLA, FXCB_SLA, FXCB_SLA, FXCB_SLA, FXCB_SLA, FXCB_SLAIX, FXCB_SLA, FXCB_SRA, FXCB_SRA, FXCB_SRA, FXCB_SRA, FXCB_SRA, FXCB_SRA, FXCB_SRAIX, FXCB_SRA, // 20..2F
FXCB_SLL, FXCB_SLL, FXCB_SLL, FXCB_SLL, FXCB_SLL, FXCB_SLL, FXCB_SLLIX, FXCB_SLL, FXCB_SRL, FXCB_SRL, FXCB_SRL, FXCB_SRL, FXCB_SRL, FXCB_SRL, FXCB_SRLIX, FXCB_SRL, // 30..3F
FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, // 40..4F
FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, // 50..5F
FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, // 60..6F
FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, FXCB_BITIX, // 70..7F
FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RESIX, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RESIX, FXCB_RES, // 80..8F
FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RESIX, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RESIX, FXCB_RES, // 90..9F
FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RESIX, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RESIX, FXCB_RES, // A0..AF
FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RESIX, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RES, FXCB_RESIX, FXCB_RES, // B0..BF
FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SETIX, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SETIX, FXCB_SET, // C0..CF
FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SETIX, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SETIX, FXCB_SET, // D0..DF
FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SETIX, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SETIX, FXCB_SET, // E0..EF
FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SETIX, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SET, FXCB_SETIX, FXCB_SET, // F0..FF
];
}
private Action<byte>[] CreateAluAlg()
{
return
[
ALU_ADDR, ALU_ADCR, ALU_SUBR, ALU_SBCR,
ALU_ANDR, ALU_XORR, ALU_ORR, ALU_CPR,
];
}
#region Optimized emitters
//private Action<byte> EmitOpcodeLdRegReg(int cmd)
//{
// if (cmd < 0x40 || cmd >= 0x80)
// {
// return null;
// }
// var rsrc = cmd & 0x07;
// var rdst = (cmd & 0x38) >> 3;
// if (rsrc == rdst)
// {
// return rsrc == 6 ? HALT : (Action<byte>)null;
// }
// var getter = rsrc != 6 ? regs.CreateRegGetter(rsrc) :
// new Func<byte>(() =>
// {
// // LD R,(HL)
// // 7T (4, 3)
// var value = RDMEM(regs.HL); Tact += 3;
// return value;
// });
// var setter = rdst != 6 ? regs.CreateRegSetter(rdst) :
// new Action<byte>(arg =>
// {
// // LD (HL),R
// // 7T (4, 3)
// WRMEM(regs.HL, arg); Tact += 3;
// });
// return arg => setter(getter());
//}
//private Action<byte> EmitOpcodeJrXdisp(int cmd)
//{
// if (cmd < 0x20 || cmd >= 0x40 || (cmd & 7) != 0)
// {
// return null;
// }
// // JR x,disp
// // false => 7T (4, 3)
// // true => 12 (4, 3, 5)
// var cond = (cmd & 0x18) >> 3;
// var mask = s_conds[cond >> 1];
// var xor = (cond & 1) == 0 ? -1 : 0;
// return new Action<byte>(arg =>
// {
// int drel = (sbyte)RDMEM(regs.PC); Tact += 3;
// regs.PC++;
// var f = (regs.AF ^ xor) & mask;
// if (f == 0)
// {
// return;
// }
// RDNOMREQ(regs.PC); Tact++;
// RDNOMREQ(regs.PC); Tact++;
// RDNOMREQ(regs.PC); Tact++;
// RDNOMREQ(regs.PC); Tact++;
// RDNOMREQ(regs.PC); Tact++;
// regs.MW = (ushort)(regs.PC + drel);
// regs.PC = regs.MW;
// });
//}
#endregion Optimized emitters
}
}
+353
View File
@@ -0,0 +1,353 @@
/*
* Copyright 2007, 2015 Alex Makeev
*
* This file is part of ZXMAK2 (ZX Spectrum virtual machine).
*
* ZXMAK2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZXMAK2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZXMAK2. If not, see <http://www.gnu.org/licenses/>.
*
* Description: Z80 CPU Emulator
* Date: 13.04.2007
*
*/
using System;
using System.Linq;
namespace ZXMAK2.Engine.Cpu.Processor
{
public partial class Z80Cpu
{
public readonly CpuRegs regs = new();
public int RzxCounter;
public long Tact;
public bool HALTED;
public bool IFF1;
public bool IFF2;
public byte IM;
public bool BINT; // last opcode was EI or DD/FD prefix (to prevent INT handling)
public CpuModeIndex FX;
public CpuModeEx XFX;
public ushort LPC; // last opcode PC
public bool INT;
public bool NMI;
public bool RST;
public byte BUS = 0xFF; // state of free data bus
public Action RESET;
public Action NMIACK_M1;
public Action INTACK_M1;
public Func<ushort, byte> RDMEM_M1;
public Func<ushort, byte> RDMEM;
public Action<ushort, byte> WRMEM;
public Func<ushort, byte> RDPORT;
public Action<ushort, byte> WRPORT;
public Action<ushort> RDNOMREQ;
public Action<ushort> WRNOMREQ;
public Action SCANSIG;
private CpuType _type = CpuType.NEC_NMOS;
public CpuType Type
{
get { return _type; }
set { _type = value; InitOpcodeTables(); }
}
public Z80Cpu()
{
_pairGetters = [.. Enumerable.Range(0, 4).Select(regs.CreatePairGetter)];
_pairSetters = [.. Enumerable.Range(0, 4).Select(regs.CreatePairSetter)];
_regGetters = [.. Enumerable.Range(0, 8).Select(regs.CreateRegGetter)];
_regSetters = [.. Enumerable.Range(0, 8).Select(regs.CreateRegSetter)];
_alualg = CreateAluAlg();
_opcodes = new Action<byte>[256];
_opcodesFx = new Action<byte>[256];
_opcodesEd = new Action<byte>[256];
_opcodesCb = new Action<byte>[256];
_opcodesFxCb = new Action<byte, ushort>[256];
InitOpcodeTables();
regs.AF = 0xFF;
regs.BC = 0xFF;
regs.DE = 0xFF;
regs.HL = 0xFF;
regs._AF = 0xFF;
regs._BC = 0xFF;
regs._DE = 0xFF;
regs._HL = 0xFF;
regs.IX = 0xFF;
regs.IY = 0xFF;
regs.IR = 0xFF;
regs.PC = 0xFF;
regs.SP = 0xFF;
regs.MW = 0xFF;
}
private void InitOpcodeTables()
{
InitOpcodeTable(_opcodes, CreateOpcodes());
InitOpcodeTable(_opcodesFx, CreateOpcodesFx());
InitOpcodeTable(_opcodesEd, CreateOpcodesEd());
InitOpcodeTable(_opcodesCb, CreateOpcodesCb());
InitOpcodeTable(_opcodesFxCb, CreateOpcodesFxCb());
}
private static void InitOpcodeTable<T>(T[] opcodes, T[] actions)
{
if (opcodes.Length != actions.Length)
throw new ArgumentOutOfRangeException(nameof(opcodes));
for (var i = 0; i < opcodes.Length; i++)
{
opcodes[i] = actions[i];
}
}
public void ExecCycle()
{
byte cmd = 0;
if (XFX == CpuModeEx.None && FX == CpuModeIndex.None)
{
if (ProcessSignals())
return;
LPC = regs.PC;
cmd = RDMEM_M1(LPC);
}
else
{
if (ProcessSignals())
return;
cmd = RDMEM(regs.PC);
}
Tact += 3;
regs.PC++;
if (XFX == CpuModeEx.Cb)
{
BINT = false;
if (FX != CpuModeIndex.None)
{
// elapsed T: 4, 4, 3
// will be T: 4, 4, 3, 5
int drel = (sbyte)cmd;
regs.MW = FX == CpuModeIndex.Ix ? (ushort)(regs.IX + drel) : (ushort)(regs.IY + drel);
cmd = RDMEM(regs.PC); Tact += 3;
RDNOMREQ(regs.PC); Tact++;
RDNOMREQ(regs.PC); Tact++;
regs.PC++;
_opcodesFxCb[cmd](cmd, regs.MW);
}
else
{
//Refresh();
regs.R = (byte)(((regs.R + 1) & 0x7F) | (regs.R & 0x80));
Tact += 1;
RzxCounter++;
_opcodesCb[cmd](cmd);
}
XFX = CpuModeEx.None;
FX = CpuModeIndex.None;
}
else if (XFX == CpuModeEx.Ed)
{
//Refresh();
regs.R = (byte)(((regs.R + 1) & 0x7F) | (regs.R & 0x80));
Tact += 1;
RzxCounter++;
BINT = false;
_opcodesEd[cmd]?.Invoke(cmd);
XFX = CpuModeEx.None;
FX = CpuModeIndex.None;
}
else if (cmd == 0xDD)
{
//Refresh();
regs.R = (byte)(((regs.R + 1) & 0x7F) | (regs.R & 0x80));
Tact += 1;
RzxCounter++;
FX = CpuModeIndex.Ix;
BINT = true;
}
else if (cmd == 0xFD)
{
//Refresh();
regs.R = (byte)(((regs.R + 1) & 0x7F) | (regs.R & 0x80));
Tact += 1;
RzxCounter++;
FX = CpuModeIndex.Iy;
BINT = true;
}
else if (cmd == 0xCB)
{
//Refresh();
regs.R = (byte)(((regs.R + 1) & 0x7F) | (regs.R & 0x80));
Tact += 1;
RzxCounter++;
XFX = CpuModeEx.Cb;
BINT = true;
}
else if (cmd == 0xED)
{
//Refresh();
regs.R = (byte)(((regs.R + 1) & 0x7F) | (regs.R & 0x80));
Tact += 1;
RzxCounter++;
XFX = CpuModeEx.Ed;
BINT = true;
}
else
{
//Refresh();
regs.R = (byte)(((regs.R + 1) & 0x7F) | (regs.R & 0x80));
Tact += 1;
RzxCounter++;
BINT = false;
(FX == CpuModeIndex.None ? _opcodes[cmd] : _opcodesFx[cmd])?.Invoke(cmd);
FX = CpuModeIndex.None;
}
}
private bool ProcessSignals()
{
if (RST) // RESET
{
// 3T
RESET();
//Refresh(); //+1T
regs.R = (byte)(((regs.R + 1) & 0x7F) | (regs.R & 0x80));
Tact += 1;
RzxCounter++;
FX = CpuModeIndex.None;
XFX = CpuModeEx.None;
HALTED = false;
IFF1 = false;
IFF2 = false;
regs.PC = 0;
regs.IR = 0;
IM = 0;
//regs.SP = 0xFFFF;
//regs.AF = 0xFFFF;
Tact += 2; // total should be 3T?
return true;
}
else if (NMI)
{
// 11T (5, 3, 3)
if (HALTED) // workaround for Z80 snapshot halt issue + comfortable debugging
regs.PC++;
// M1
NMIACK_M1();
Tact += 4;
//Refresh();
regs.R = (byte)(((regs.R + 1) & 0x7F) | (regs.R & 0x80));
Tact += 1;
RzxCounter++;
IFF2 = IFF1;
IFF1 = false;
HALTED = false;
regs.SP--;
// M2
WRMEM(regs.SP, (byte)(regs.PC >> 8));
Tact += 3;
regs.SP--;
// M3
WRMEM(regs.SP, (byte)regs.PC);
regs.PC = 0x0066;
Tact += 3;
return true;
}
else if (INT && (!BINT) && IFF1)
{
// http://www.z80.info/interrup.htm
// IM0: 13T (7,3,3) [RST]
// IM1: 13T (7,3,3)
// IM2: 19T (7,3,3,3,3)
if (HALTED) // workaround for Z80 snapshot halt issue + comfortable debugging
regs.PC++;
INTACK_M1();
// M1: 7T = interrupt acknowledgement; SP--
regs.SP--;
//if (HALTED) ??
// Tact += 2;
Tact += 4 + 2;
//Refresh();
//RzxCounter--; // fix because INTAK should not be calculated
regs.R = (byte)(((regs.R + 1) & 0x7F) | (regs.R & 0x80));
Tact += 1;
IFF1 = false;
IFF2 = false; // proof?
HALTED = false;
// M2
WRMEM(regs.SP, (byte)(regs.PC >> 8)); // M2: 3T write PCH; SP--
regs.SP--;
Tact += 3;
// M3
WRMEM(regs.SP, (byte)regs.PC); // M3: 3T write PCL
Tact += 3;
if (IM == 0) // IM 0: execute instruction taken from BUS with timing T+2???
{
regs.MW = 0x0038; // workaround: just execute #FF
}
else if (IM == 1) // IM 1: execute #FF with timing T+2 (11+2=13T)
{
regs.MW = 0x0038;
}
else // IM 2: VH=reg.I; VL=BUS; PC=[V]
{
// M4
ushort adr = (ushort)((regs.IR & 0xFF00) | BUS);
regs.MW = RDMEM(adr); // M4: 3T read VL
Tact += 3;
// M5
regs.MW += (ushort)(RDMEM(++adr) * 0x100); // M5: 3T read VH, PC=V
Tact += 3;
}
regs.PC = regs.MW;
return true;
}
return false;
}
}
}
File diff suppressed because it is too large Load Diff
+347
View File
@@ -0,0 +1,347 @@
/*
* Copyright 2001, 2007, 2015 Alex Makeev
*
* This file is part of ZXMAK2 (ZX Spectrum virtual machine).
*
* ZXMAK2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZXMAK2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZXMAK2. If not, see <http://www.gnu.org/licenses/>.
*
*/
using System;
using ZXMAK2.Engine.Cpu.Processor;
namespace ZXMAK2.Engine.Cpu.Tools
{
public class TimingTool(Z80Cpu cpu, Func<ushort, byte> reader)
{
private readonly Z80Cpu _cpu = cpu;
private readonly Func<ushort, byte> _memRead = reader;
public string GetTimingString(int addr)
{
var t = GetTiming(addr);
return t.HasValue ? string.Format("{0}T", t) : "N/A";
}
public int? GetTiming(int addr)
{
if (_memRead == null || _cpu == null)
{
return null;
}
var tableNumber = 0;
var perfTime = 0;
var offset = 0;
var opCode = -1;
while (true)
{
opCode = _memRead((ushort)(addr + offset));
var res = s_tables[tableNumber][opCode];
if (res < 0xF0)
{
return res + perfTime;
}
tableNumber = res - 0xF0;
if (tableNumber >= 5)
{
break;
}
perfTime += 4;
offset++;
if (tableNumber == 4)
{
offset++;
}
if (perfTime > 1500000)
{
System.Console.Error.WriteLine("TimingTool.GetTiming: {0}T reached!", perfTime);
return null;
}
}
switch (opCode)
{
case 0x10:
return DjnzTime(perfTime, 0x08, 0x0D);
case 0xB1:
case 0xB2:
case 0xB9:
case 0xBA:
return DjnzTime(perfTime, 0x0C, 0x11);
case 0x20: return FlagTime(perfTime, 0x07, 0x0C, 0x40);
case 0x28: return FlagTime(perfTime, 0x0C, 0x07, 0x40);
case 0x30: return FlagTime(perfTime, 0x07, 0x0C, 0x01);
case 0x38: return FlagTime(perfTime, 0x0C, 0x07, 0x01);
case 0xC0: return FlagTime(perfTime, 0x05, 0x0B, 0x40);
case 0xC8: return FlagTime(perfTime, 0x0B, 0x05, 0x40);
case 0xD0: return FlagTime(perfTime, 0x05, 0x0B, 0x01);
case 0xD8: return FlagTime(perfTime, 0x0B, 0x05, 0x01);
case 0xE0: return FlagTime(perfTime, 0x05, 0x0B, 0x04);
case 0xE8: return FlagTime(perfTime, 0x0B, 0x05, 0x04);
case 0xF0: return FlagTime(perfTime, 0x05, 0x0B, 0x80);
case 0xF8: return FlagTime(perfTime, 0x0B, 0x05, 0x80);
case 0xC4: return FlagTime(perfTime, 0x0A, 0x11, 0x40);
case 0xCC: return FlagTime(perfTime, 0x11, 0x0A, 0x40);
case 0xD4: return FlagTime(perfTime, 0x0A, 0x11, 0x01);
case 0xDC: return FlagTime(perfTime, 0x11, 0x0A, 0x01);
case 0xE4: return FlagTime(perfTime, 0x0A, 0x11, 0x04);
case 0xEC: return FlagTime(perfTime, 0x11, 0x0A, 0x04);
case 0xF4: return FlagTime(perfTime, 0x0A, 0x11, 0x80);
case 0xFC: return FlagTime(perfTime, 0x11, 0x0A, 0x80);
case 0xB0:
case 0xB8:
return RepTime(perfTime, 0x0C, 0x11);
case 0xB3:
case 0xBB:
return RepFlagTime(perfTime, 0x0C, 0x0C, 0x11);
}
System.Console.Error.WriteLine(
"TimingTool.GetTiming: unexpected opCode #{0:2X}",
opCode);
return null;
}
#region Private
private int DjnzTime(int timeBase, int timeEnd, int timeNoEnd)
{
var ifTime = _cpu.regs.B == 0x01 ? timeEnd : timeNoEnd;
return timeBase + ifTime;
}
private int FlagTime(int timeBase, int timeOn, int timeOff, int flagMask)
{
var ifTime = (_cpu.regs.F & flagMask) != 0 ? timeOn : timeOff;
return timeBase + ifTime;
}
private int RepTime(int perfTime, int timeEnd, int timeNoEnd)
{
var ifTime = _cpu.regs.BC == 0x0001 ? timeEnd : timeNoEnd;
return perfTime + ifTime;
}
private int RepFlagTime(int timeEnd, int timeOn, int timeOff, int perfTime)
{
if (_cpu.regs.BC == 0x0001)
{
return perfTime + timeEnd;
}
var data = _memRead(_cpu.regs.HL);
var ifTime = _cpu.regs.F == data ? timeOn : timeOff;
return perfTime + ifTime;
}
#endregion Private
#region Tables
private static readonly int[] s_tableDirect =
[
0x04,0x0A,0x07,0x06,0x04,0x04,0x07,0x04, //;00h-07h
0x04,0x0B,0x07,0x06,0x04,0x04,0x07,0x04, //;08h-0Fh
0xFF,0x0A,0x07,0x06,0x04,0x04,0x07,0x04, //;10h-17h
0x0C,0x0B,0x07,0x06,0x04,0x04,0x07,0x04, //;18h-1Fh
0xFF,0x0A,0x10,0x06,0x04,0x04,0x07,0x04, //;20h-27h
0xFF,0x0B,0x10,0x06,0x04,0x04,0x07,0x04, //;28h-2Fh
0xFF,0x0A,0x0D,0x06,0x0B,0x0B,0x0A,0x04, //;30h-37h
0xFF,0x0B,0x0D,0x06,0x04,0x04,0x07,0x04, //;38h-3Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x07,0x04, //;40h-47h
0x04,0x04,0x04,0x04,0x04,0x04,0x07,0x04, //;48h-4Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x07,0x04, //;50h-57h
0x04,0x04,0x04,0x04,0x04,0x04,0x07,0x04, //;58h-5Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x07,0x04, //;60h-67h
0x04,0x04,0x04,0x04,0x04,0x04,0x07,0x04, //;68h-6Fh
0x07,0x07,0x07,0x07,0x07,0x07,0x04,0x07, //;70h-77h
0x04,0x04,0x04,0x04,0x04,0x04,0x07,0x04, //;78h-7Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x07,0x04, //;80h-87h
0x04,0x04,0x04,0x04,0x04,0x04,0x07,0x04, //;88h-8Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x07,0x04, //;90h-97h
0x04,0x04,0x04,0x04,0x04,0x04,0x07,0x04, //;98h-9Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x07,0x04, //;A0h-A7h
0x04,0x04,0x04,0x04,0x04,0x04,0x07,0x04, //;A8h-AFh
0x04,0x04,0x04,0x04,0x04,0x04,0x07,0x04, //;B0h-B7h
0x04,0x04,0x04,0x04,0x04,0x04,0x07,0x04, //;B8h-BFh
0xFF,0x0A,0x0A,0x0A,0xFF,0x0B,0x07,0x0B, //;C0h-C7h
0xFF,0x0A,0x0A,0xF1,0xFF,0x11,0x07,0x0B, //;C8h-CFh
0xFF,0x0A,0x0A,0x0B,0xFF,0x0B,0x07,0x0B, //;D0h-D7h
0xFF,0x04,0x0A,0x0B,0xFF,0xF3,0x07,0x0B, //;D8h-DFh
0xFF,0x0A,0x0A,0x13,0xFF,0x0B,0x07,0x0B, //;E0h-E7h
0xFF,0x04,0x0A,0x04,0xFF,0xF2,0x07,0x0B, //;E8h-EFh
0xFF,0x0A,0x0A,0x04,0xFF,0x0B,0x07,0x0B, //;F0h-F7h
0xFF,0x06,0x0A,0x04,0xFF,0xF3,0x07,0x0B //;F8h-FFh
];
private static readonly int[] s_tableCb =
[
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;00h-07h
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;08h-0Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;10h-17h
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;18h-1Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;20h-27h
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;28h-2Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;30h-37h
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;38h-3Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04, // ;40h-47h
0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04, // ;48h-4Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04, // ;50h-57h
0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04, // ;58h-5Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04, // ;60h-67h
0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04, // ;68h-6Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04, // ;70h-77h
0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04, // ;78h-7Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;80h-87h
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;88h-8Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;90h-97h
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;98h-9Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;A0h-A7h
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;A8h-AFh
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;B0h-B7h
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;B8h-BFh
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;C0h-C7h
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;C8h-CFh
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;D0h-D7h
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;D8h-DFh
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;E0h-E7h
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;E8h-EFh
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04, // ;F0h-F7h
0x04,0x04,0x04,0x04,0x04,0x04,0x0B,0x04 // ;F8h-FFh
];
private static readonly int[] s_tableEd =
[
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, // ;00h-07h
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, // ;08h-0Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, // ;10h-17h
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, // ;18h-1Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, // ;20h-27h
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, // ;28h-2Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, // ;30h-37h
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, // ;38h-3Fh
0x08,0x08,0x0B,0x10,0x04,0x0A,0x04,0x05, // ;40h-47h
0x08,0x08,0x0B,0x10,0x04,0x0A,0x04,0x05, // ;48h-4Fh
0x08,0x08,0x0B,0x10,0x04,0x0A,0x04,0x05, // ;50h-57h
0x08,0x08,0x0B,0x10,0x04,0x0A,0x04,0x05, // ;58h-5Fh
0x08,0x08,0x0B,0x10,0x04,0x0A,0x04,0x0E, // ;60h-67h
0x08,0x08,0x0B,0x10,0x04,0x0A,0x04,0x0E, // ;68h-6Fh
0x08,0x08,0x0B,0x10,0x04,0x0A,0x04,0x04, // ;70h-77h
0x08,0x08,0x0B,0x10,0x04,0x0A,0x04,0x04, // ;78h-7Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, // ;80h-87h
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, // ;88h-8Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, // ;90h-97h
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, // ;98h-9Fh
0x0C,0x0C,0x0C,0x0C,0x04,0x04,0x04,0x04, // ;A0h-A7h
0x0C,0x0C,0x0C,0x0C,0x04,0x04,0x04,0x04, // ;A8h-AFh
0xFF,0xFF,0xFF,0xFF,0x04,0x04,0x04,0x04, // ;B0h-B7h
0xFF,0xFF,0xFF,0xFF,0x04,0x04,0x04,0x04, // ;B8h-BFh
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, // ;C0h-C7h
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, // ;C8h-CFh
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, // ;D0h-D7h
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, // ;D8h-DFh
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, // ;E0h-E7h
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, // ;E8h-EFh
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, // ;F0h-F7h
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04 // ;F8h-FFh
];
private static readonly int[] s_tableDdFd =
[
0x04,0x0A,0x07,0x06,0x04,0x04,0x07,0x04, // ;00h-07h
0x04,0x0B,0x07,0x06,0x04,0x04,0x07,0x04, // ;08h-0Fh
0xFF,0x0A,0x07,0x06,0x04,0x04,0x07,0x04, // ;10h-17h
0x0C,0x0B,0x07,0x06,0x04,0x04,0x07,0x04, // ;18h-1Fh
0xFF,0x0A,0x10,0x06,0x04,0x04,0x07,0x04, // ;20h-27h
0xFF,0x0B,0x10,0x06,0x04,0x04,0x07,0x04, // ;28h-2Fh
0xFF,0x0A,0x0D,0x06,0x13,0x13,0x0F,0x04, // ;30h-37h
0xFF,0x0B,0x0D,0x06,0x04,0x04,0x0F,0x04, // ;38h-3Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x0F,0x04, // ;40h-47h
0x04,0x04,0x04,0x04,0x04,0x04,0x0F,0x04, // ;48h-4Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x0F,0x04, // ;50h-57h
0x04,0x04,0x04,0x04,0x04,0x04,0x0F,0x04, // ;58h-5Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x0F,0x04, // ;60h-67h
0x04,0x04,0x04,0x04,0x04,0x04,0x0F,0x04, // ;68h-6Fh
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x04,0x0F, // ;70h-77h
0x04,0x04,0x04,0x04,0x04,0x04,0x0F,0x04, // ;78h-7Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x0F,0x04, // ;80h-87h
0x04,0x04,0x04,0x04,0x04,0x04,0x0F,0x04, // ;88h-8Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x0F,0x04, // ;90h-97h
0x04,0x04,0x04,0x04,0x04,0x04,0x0F,0x04, // ;98h-9Fh
0x04,0x04,0x04,0x04,0x04,0x04,0x0F,0x04, // ;A0h-A7h
0x04,0x04,0x04,0x04,0x04,0x04,0x0F,0x04, // ;A8h-AFh
0x04,0x04,0x04,0x04,0x04,0x04,0x0F,0x04, // ;B0h-B7h
0x04,0x04,0x04,0x04,0x04,0x04,0x0F,0x04, // ;B8h-BFh
0xFF,0x0A,0x0A,0x0A,0xFF,0x0B,0x0F,0x0B, // ;C0h-C7h
0xFF,0x0A,0x0A,0xF4,0xFF,0x11,0x0F,0x0B, // ;C8h-CFh
0xFF,0x0A,0x0A,0x0B,0xFF,0x0B,0x0F,0x0B, // ;D0h-D7h
0xFF,0x04,0x0A,0x0B,0xFF,0xF3,0x0F,0x0B, // ;D8h-DFh
0xFF,0x0A,0x0A,0x13,0xFF,0x0B,0x0F,0x0B, // ;E0h-E7h
0xFF,0x04,0x0A,0x04,0xFF,0xF2,0x0F,0x0B, // ;E8h-EFh
0xFF,0x0A,0x0A,0x04,0xFF,0x0B,0x0F,0x0B, // ;F0h-F7h
0xFF,0x06,0x0A,0x04,0xFF,0xF3,0x0F,0x0B // ;F8h-FFh
];
private static readonly int[] s_tableDdCbFdCb =
[
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;00h-07h
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;08h-0Fh
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;10h-17h
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;18h-1Fh
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;20h-27h
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;28h-2Fh
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;30h-37h
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;38h-3Fh
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // ;40h-47h
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // ;48h-4Fh
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // ;50h-57h
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // ;58h-5Fh
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // ;60h-67h
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // ;68h-6Fh
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // ;70h-77h
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // ;78h-7Fh
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;80h-87h
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;88h-8Fh
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;90h-97h
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;98h-9Fh
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;A0h-A7h
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;A8h-AFh
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;B0h-B7h
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;B8h-BFh
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;C0h-C7h
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;C8h-CFh
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;D0h-D7h
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;D8h-DFh
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;E0h-E7h
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;E8h-EFh
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // ;F0h-F7h
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F // ;F8h-FFh
];
private static readonly int[][] s_tables =
[
s_tableDirect,
s_tableCb,
s_tableEd,
s_tableDdFd,
s_tableDdCbFdCb,
];
#endregion Tables
}
}