/*
* 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 .
*
*/
using System;
using ZXMAK2.Engine.Cpu.Processor;
namespace ZXMAK2.Engine.Cpu.Tools
{
public class TimingTool(Z80Cpu cpu, Func reader)
{
private readonly Z80Cpu _cpu = cpu;
private readonly Func _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
}
}