接入Essgss.Unity到本项目

This commit is contained in:
sin365 2025-02-14 16:09:33 +08:00
parent d4ba9c0ccb
commit 69dd59e0f6
283 changed files with 23902 additions and 1 deletions

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b136ca247e0175d48a98c06d18889c44
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,15 @@
public static class AppEnvironment
{
#if DEBUG
public static readonly bool DebugMode = true;
#else
public static readonly bool DebugMode = false;
#endif
public static readonly bool EnableCustomUnhandledExceptionHandler = true;
public static readonly bool TemporaryDisableCustomExceptionForm = false;
public static readonly bool EnableLogger = false;
public static readonly bool EnableSuperSlowCPULogger = false;
public static readonly bool EnableOpenGLDebug = false;
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ce38d9b5f910b4c4185e3fab7eb45ecf

View File

@ -0,0 +1,169 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
namespace Essgee.Utilities
{
internal unsafe static class AxiMemoryEx
{
static HashSet<GCHandle> GCHandles = new HashSet<GCHandle>();
public static void Init()
{
FreeAllGCHandle();
set_TempBuffer = new byte[0x100000];
}
public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref uint* ptr)
{
GetObjectPtr(srcObj, ref handle, out IntPtr intptr);
ptr = (uint*)intptr;
}
public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref short* ptr)
{
GetObjectPtr(srcObj, ref handle, out IntPtr intptr);
ptr = (short*)intptr;
}
public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref ushort* ptr)
{
GetObjectPtr(srcObj, ref handle, out IntPtr intptr);
ptr = (ushort*)intptr;
}
public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref int* ptr)
{
GetObjectPtr(srcObj, ref handle, out IntPtr intptr);
ptr = (int*)intptr;
}
public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref byte* ptr)
{
GetObjectPtr(srcObj, ref handle, out IntPtr intptr);
ptr = (byte*)intptr;
}
static void GetObjectPtr(this object srcObj, ref GCHandle handle, out IntPtr intptr)
{
ReleaseGCHandle(ref handle);
handle = GCHandle.Alloc(srcObj, GCHandleType.Pinned);
GCHandles.Add(handle);
intptr = handle.AddrOfPinnedObject();
}
public static void ReleaseGCHandle(this ref GCHandle handle)
{
if (handle.IsAllocated)
handle.Free();
GCHandles.Remove(handle);
}
public static void FreeAllGCHandle()
{
foreach (var handle in GCHandles)
{
if (handle.IsAllocated)
handle.Free();
}
GCHandles.Clear();
}
#region TempBuffer
static byte[] TempBuffer_src;
static GCHandle TempBuffer_handle;
public static byte* TempBuffer;
public static byte[] set_TempBuffer
{
set
{
TempBuffer_handle.ReleaseGCHandle();
if (value == null)
return;
TempBuffer_src = value;
TempBuffer_src.GetObjectPtr(ref TempBuffer_handle, ref TempBuffer);
}
}
#endregion
public static void Write(this BinaryWriter bw, byte* bufferPtr, int offset, int count)
{
// 使用指针复制数据到临时数组
Buffer.MemoryCopy(bufferPtr + offset, TempBuffer, 0, count);
// 使用BinaryWriter写入临时数组
bw.Write(TempBuffer_src, 0, count);
}
public static void Write(this FileStream fs, byte* bufferPtr, int offset, int count)
{
// 使用指针复制数据到临时数组
Buffer.MemoryCopy(bufferPtr + offset, TempBuffer, 0, count);
// 使用BinaryWriter写入临时数组
fs.Write(TempBuffer_src, 0, count);
}
public static int Read(this FileStream fs, byte* bufferPtr, int offset, int count)
{
// 使用BinaryWriter写入临时数组
count = fs.Read(TempBuffer_src, offset, count);
// 使用指针复制数据到临时数组
Buffer.MemoryCopy(TempBuffer, bufferPtr + offset, 0, count);
return count;
}
}
internal unsafe static class AxiArray
{
public static void Copy(byte* src, int srcindex, byte* target, int targetindex, int count)
{
int singlesize = sizeof(byte);
long totalBytesToCopy = count * singlesize;
Buffer.MemoryCopy(&src[srcindex], &target[targetindex], totalBytesToCopy, totalBytesToCopy);
}
public static void Copy(short* src, int srcindex, short* target, int targetindex, int count)
{
int singlesize = sizeof(short);
long totalBytesToCopy = count * singlesize;
Buffer.MemoryCopy(&src[srcindex], &target[targetindex], totalBytesToCopy, totalBytesToCopy);
}
public static void Copy(ushort* src, int srcindex, ushort* target, int targetindex, int count)
{
int singlesize = sizeof(ushort);
long totalBytesToCopy = count * singlesize;
Buffer.MemoryCopy(&src[srcindex], &target[targetindex], totalBytesToCopy, totalBytesToCopy);
}
public static void Copy(byte* src, byte* target, int index, int count)
{
int singlesize = sizeof(byte);
long totalBytesToCopy = count * singlesize;
Buffer.MemoryCopy(&src[index], &target[index], totalBytesToCopy, totalBytesToCopy);
}
public static void Copy(ushort* src, ushort* target, int index, int count)
{
int singlesize = sizeof(ushort);
long totalBytesToCopy = count * singlesize;
Buffer.MemoryCopy(&src[index], &target[index], totalBytesToCopy, totalBytesToCopy);
}
public static void Copy(ushort* src, ushort* target, int count)
{
int singlesize = sizeof(ushort);
long totalBytesToCopy = count * singlesize;
Buffer.MemoryCopy(src, target, totalBytesToCopy, totalBytesToCopy);
}
public static void Copy(byte* src, byte* target, int count)
{
int singlesize = sizeof(byte);
long totalBytesToCopy = count * singlesize;
Buffer.MemoryCopy(src, target, totalBytesToCopy, totalBytesToCopy);
}
public static void Clear(byte* data, int index, int lenght)
{
for (int i = index; i < lenght; i++, index++)
data[index] = 0;
}
public static void Clear(ushort* data, int index, int lenght)
{
for (int i = index; i < lenght; i++, index++)
data[index] = 0;
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 922bbb45b85e7de4f8bce1c6f407009f

View File

@ -0,0 +1,58 @@
using Essgee.Emulation.Configuration;
using Essgee.Utilities;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Collections.Generic;
using System.Drawing;
namespace Essgee
{
public class Configuration
{
public const int RecentFilesCapacity = 15;
public const string DefaultShaderName = "Basic";
public bool LimitFps { get; set; }
public bool ShowFps { get; set; }
public bool Mute { get; set; }
public float Volume { get; set; }
public int SampleRate { get; set; }
public bool LowPassFilter { get; set; }
public int ScreenSize { get; set; }
//[JsonConverter(typeof(StringEnumConverter))]
public ScreenSizeMode ScreenSizeMode { get; set; }
public string LastShader { get; set; }
public bool EnableXInput { get; set; }
public bool EnableRumble { get; set; }
public bool AutoPause { get; set; }
public List<string> RecentFiles { get; set; }
//[JsonConverter(typeof(InterfaceDictionaryConverter<IConfiguration>))]
public Dictionary<string, IConfiguration> Machines { get; set; }
public Dictionary<string, Point> DebugWindows { get; set; }
public Configuration()
{
LimitFps = true;
ShowFps = false;
Mute = false;
Volume = 1.0f;
SampleRate = 44100;
LowPassFilter = true;
ScreenSize = 2;
ScreenSizeMode = ScreenSizeMode.Scale;
LastShader = DefaultShaderName;
EnableXInput = false;
EnableRumble = false;
AutoPause = true;
RecentFiles = new List<string>(RecentFilesCapacity);
Machines = new Dictionary<string, IConfiguration>();
DebugWindows = new Dictionary<string, Point>();
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1cb6affe10cc31441b6301f115fbc2ab

View File

@ -0,0 +1,44 @@
using Essgee;
using System;
public static class EmuStandInfo
{
//À´×ÔmetaData
//public static string datDirectoryPath;
//public static string metadataDatabaseFilePath;
public static string jsonConfigFileName;//= "Config.json";
public static string saveDataDirectoryName;//= "Saves";
public static string screenshotDirectoryName;//= "Screenshots";
public static string saveStateDirectoryName;//= "Savestates";
public static string extraDataDirectoryName;//= "Extras";
public static string ProductName;//= "";
public static string programDataDirectory;// = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), ProductName);
public static string programConfigPath;// = Path.Combine(programDataDirectory, jsonConfigFileName);
public static Configuration Configuration { get; set; }
public static string ShaderPath;//= Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets", "Shaders");
public static string SaveDataPath;//= Path.Combine(programDataDirectory, saveDataDirectoryName);
public static string ScreenshotPath;//= Path.Combine(programDataDirectory, screenshotDirectoryName);
public static string SaveStatePath;//= Path.Combine(programDataDirectory, saveStateDirectoryName);
public static string ExtraDataPath;//= Path.Combine(programDataDirectory, extraDataDirectoryName);
static Random mRandom;
public static Random Random
{
get
{
if (mRandom == null)
{
mRandom = new Random();
}
return mRandom;
}
}
public static string ProductVersion { get; set; }
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c668ecd37f7dd4e4092fcac10c385c9b

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 267425c59f2efba48a44a3b55a5eb01d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ab3f0235ad62cb046ac1518f29d21e81
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,19 @@
namespace Essgee.Emulation.Audio
{
public partial class CGBAudio
{
public class CGBWave : Wave, IDMGAudioChannel
{
public override void Reset()
{
base.Reset();
for (var i = 0; i < sampleBuffer.Length; i += 2)
{
sampleBuffer[i + 0] = 0x00;
sampleBuffer[i + 1] = 0xFF;
}
}
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 595436ed6c508904399695fee24279ff

View File

@ -0,0 +1,25 @@
using System.Collections.Generic;
namespace Essgee.Emulation.Audio
{
public partial class CGBAudio : DMGAudio, IAudio
{
public CGBAudio()
{
//channelSampleBuffer = new List<short>[numChannels];
//for (int i = 0; i < numChannels; i++) channelSampleBuffer[i] = new List<short>();
//mixedSampleBuffer = new List<short>();
//改为二维数组
channelSampleBuffer_Init(numChannels, 1470);
mixedSampleBuffer_set = new short[1470];
channel1 = new Square(true);
channel2 = new Square(false);
channel3 = new CGBWave();
channel4 = new Noise();
samplesPerFrame = cyclesPerFrame = cyclesPerSample = -1;
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 40f2c16e17787974881d5614068c46b7

View File

@ -0,0 +1,214 @@
using System;
namespace Essgee.Emulation.Audio
{
public partial class DMGAudio
{
public class Noise : IDMGAudioChannel
{
static readonly int[] divisors = new int[]
{
8, 16, 32, 48, 64, 80, 96, 112
};
// NR41
byte lengthLoad;
// NR42
byte envelopeStartingVolume, envelopePeriodReload;
bool envelopeAddMode;
// NR43
byte clockShift, divisorCode;
bool lfsrWidthMode;
// NR44
bool trigger, lengthEnable;
//
// Noise
int noiseCounter;
ushort lfsr;
// Envelope
int volume, envelopeCounter;
bool isEnvelopeUpdateEnabled;
// Misc
bool isChannelEnabled, isDacEnabled;
int lengthCounter;
public int OutputVolume { get; private set; }
public bool IsActive { get { return lengthCounter != 0; } }
public Noise()
{
//
}
public void Reset()
{
noiseCounter = 0;
lfsr = 0;
volume = 15;
envelopeCounter = 0;
isEnvelopeUpdateEnabled = false;
isChannelEnabled = isDacEnabled = false;
lengthCounter = 0;
OutputVolume = volume;
}
public void LengthCounterClock()
{
if (lengthCounter > 0 && lengthEnable)
{
lengthCounter--;
if (lengthCounter == 0)
isChannelEnabled = false;
}
}
public void SweepClock()
{
throw new Exception("Channel type does not support sweep");
}
public void VolumeEnvelopeClock()
{
envelopeCounter--;
if (envelopeCounter == 0)
{
envelopeCounter = envelopePeriodReload;
if (isEnvelopeUpdateEnabled)
{
var newVolume = volume;
if (envelopeAddMode) newVolume++;
else newVolume--;
if (newVolume >= 0 && newVolume <= 15)
volume = newVolume;
else
isEnvelopeUpdateEnabled = false;
}
}
}
public void Step()
{
if (!isChannelEnabled) return;
noiseCounter--;
if (noiseCounter == 0)
{
noiseCounter = divisors[divisorCode] << clockShift;
var result = (lfsr & 0b1) ^ ((lfsr >> 1) & 0b1);
lfsr = (ushort)((lfsr >> 1) | (result << 14));
if (lfsrWidthMode)
lfsr = (ushort)((lfsr & 0b10111111) | (result << 6));
}
OutputVolume = isDacEnabled && ((lfsr & 0b1) == 0) ? volume : 0;
}
private void Trigger()
{
isChannelEnabled = true;
if (lengthCounter == 0) lengthCounter = 64;
noiseCounter = divisors[divisorCode] << clockShift;
volume = envelopeStartingVolume;
envelopeCounter = envelopePeriodReload;
isEnvelopeUpdateEnabled = true;
lfsr = 0x7FFF;
}
public void WritePort(byte port, byte value)
{
switch (port)
{
case 0:
break;
case 1:
lengthLoad = (byte)((value >> 0) & 0b111111);
lengthCounter = 64 - lengthLoad;
break;
case 2:
envelopeStartingVolume = (byte)((value >> 4) & 0b1111);
envelopeAddMode = ((value >> 3) & 0b1) == 0b1;
envelopePeriodReload = (byte)((value >> 0) & 0b111);
isDacEnabled = ((value >> 3) & 0b11111) != 0;
break;
case 3:
clockShift = (byte)((value >> 4) & 0b1111);
lfsrWidthMode = ((value >> 3) & 0b1) == 0b1;
divisorCode = (byte)((value >> 0) & 0b111);
break;
case 4:
trigger = ((value >> 7) & 0b1) == 0b1;
lengthEnable = ((value >> 6) & 0b1) == 0b1;
if (trigger) Trigger();
break;
}
}
public byte ReadPort(byte port)
{
switch (port)
{
case 0:
return 0xFF;
case 1:
return 0xFF;
case 2:
return (byte)(
(envelopeStartingVolume << 4) |
(envelopeAddMode ? (1 << 3) : 0) |
(envelopePeriodReload << 0));
case 3:
return (byte)(
(clockShift << 4) |
(lfsrWidthMode ? (1 << 3) : 0) |
(divisorCode << 0));
case 4:
return (byte)(
0xBF |
(lengthEnable ? (1 << 6) : 0));
default:
return 0xFF;
}
}
public void WriteWaveRam(byte offset, byte value)
{
throw new Exception("Channel type does have Wave RAM");
}
public byte ReadWaveRam(byte offset)
{
throw new Exception("Channel type does have Wave RAM");
}
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 0992ef0e8260e124c9667aea4433025c

View File

@ -0,0 +1,269 @@
using System;
namespace Essgee.Emulation.Audio
{
public partial class DMGAudio
{
public class Square : IDMGAudioChannel
{
static readonly bool[,] dutyCycleTable = new bool[,]
{
{ false, false, false, false, false, false, false, true, }, // 00000001 12.5%
{ true, false, false, false, false, false, false, true, }, // 10000001 25%
{ true, false, false, false, false, true, true, true, }, // 10000111 50%
{ false, true, true, true, true, true, true, false, } // 01111110 75%
};
// NR10/20
byte sweepPeriodReload, sweepShift;
bool sweepNegate;
// NR11/21
byte dutyCycle, lengthLoad;
// NR12/22
byte envelopeStartingVolume, envelopePeriodReload;
bool envelopeAddMode;
// NR13/23
byte frequencyLSB;
// NR14/24
bool trigger, lengthEnable;
byte frequencyMSB;
//
readonly bool channelSupportsSweep;
// Sweep
bool isSweepEnabled;
int sweepCounter, sweepFreqShadow;
// Frequency
int frequencyCounter;
// Envelope
int volume, envelopeCounter;
bool isEnvelopeUpdateEnabled;
// Misc
bool isChannelEnabled, isDacEnabled;
int lengthCounter, dutyCounter;
public int OutputVolume { get; private set; }
public bool IsActive { get { return lengthCounter != 0; } }
public Square(bool hasSweep)
{
channelSupportsSweep = hasSweep;
}
public void Reset()
{
isSweepEnabled = false;
sweepCounter = sweepFreqShadow = 0;
frequencyCounter = 0;
volume = 15;
envelopeCounter = 0;
isEnvelopeUpdateEnabled = false;
isChannelEnabled = isDacEnabled = false;
lengthCounter = dutyCounter = 0;
OutputVolume = volume;
}
public void LengthCounterClock()
{
if (lengthCounter > 0 && lengthEnable)
{
lengthCounter--;
if (lengthCounter == 0)
isChannelEnabled = false;
}
}
public void SweepClock()
{
if (!channelSupportsSweep) return;
sweepCounter--;
if (sweepCounter == 0)
{
sweepCounter = sweepPeriodReload;
if (isSweepEnabled && sweepPeriodReload != 0)
{
var newFrequency = PerformSweepCalculations();
if (newFrequency <= 2047 && sweepShift != 0)
{
sweepFreqShadow = newFrequency;
frequencyMSB = (byte)((newFrequency >> 8) & 0b111);
frequencyLSB = (byte)(newFrequency & 0xFF);
PerformSweepCalculations();
}
}
}
}
public void VolumeEnvelopeClock()
{
envelopeCounter--;
if (envelopeCounter == 0)
{
envelopeCounter = envelopePeriodReload;
if (isEnvelopeUpdateEnabled)
{
var newVolume = volume;
if (envelopeAddMode) newVolume++;
else newVolume--;
if (newVolume >= 0 && newVolume <= 15)
volume = newVolume;
else
isEnvelopeUpdateEnabled = false;
}
}
}
public void Step()
{
if (!isChannelEnabled) return;
frequencyCounter--;
if (frequencyCounter == 0)
{
frequencyCounter = (2048 - ((frequencyMSB << 8) | frequencyLSB)) * 4;
dutyCounter++;
dutyCounter %= 8;
}
OutputVolume = isDacEnabled && dutyCycleTable[dutyCycle, dutyCounter] ? volume : 0;
}
private void Trigger()
{
isChannelEnabled = true;
if (lengthCounter == 0) lengthCounter = 64;
frequencyCounter = (2048 - ((frequencyMSB << 8) | frequencyLSB)) * 4;
volume = envelopeStartingVolume;
envelopeCounter = envelopePeriodReload;
isEnvelopeUpdateEnabled = true;
if (channelSupportsSweep)
{
sweepFreqShadow = (frequencyMSB << 8) | frequencyLSB;
sweepCounter = sweepPeriodReload;
isSweepEnabled = sweepPeriodReload != 0 || sweepShift != 0;
if (sweepShift != 0)
PerformSweepCalculations();
}
}
private int PerformSweepCalculations()
{
var newFrequency = sweepFreqShadow >> sweepShift;
if (sweepNegate) newFrequency = -newFrequency;
newFrequency += sweepFreqShadow;
if (newFrequency > 2047) isChannelEnabled = false;
return newFrequency;
}
public void WritePort(byte port, byte value)
{
switch (port)
{
case 0:
if (channelSupportsSweep)
{
sweepPeriodReload = (byte)((value >> 4) & 0b111);
sweepNegate = ((value >> 3) & 0b1) == 0b1;
sweepShift = (byte)((value >> 0) & 0b111);
}
break;
case 1:
dutyCycle = (byte)((value >> 6) & 0b11);
lengthLoad = (byte)((value >> 0) & 0b111111);
lengthCounter = 64 - lengthLoad;
break;
case 2:
envelopeStartingVolume = (byte)((value >> 4) & 0b1111);
envelopeAddMode = ((value >> 3) & 0b1) == 0b1;
envelopePeriodReload = (byte)((value >> 0) & 0b111);
isDacEnabled = ((value >> 3) & 0b11111) != 0;
break;
case 3:
frequencyLSB = value;
break;
case 4:
trigger = ((value >> 7) & 0b1) == 0b1;
lengthEnable = ((value >> 6) & 0b1) == 0b1;
frequencyMSB = (byte)((value >> 0) & 0b111);
if (trigger) Trigger();
break;
}
}
public byte ReadPort(byte port)
{
switch (port)
{
case 0:
if (channelSupportsSweep)
{
return (byte)(
0x80 |
(sweepPeriodReload << 4) |
(sweepNegate ? (1 << 3) : 0) |
(sweepShift << 0));
}
else
return 0xFF;
case 1:
return (byte)(
0x3F |
(dutyCycle << 6));
case 2:
return (byte)(
(envelopeStartingVolume << 4) |
(envelopeAddMode ? (1 << 3) : 0) |
(envelopePeriodReload << 0));
case 4:
return (byte)(
0xBF |
(lengthEnable ? (1 << 6) : 0));
default:
return 0xFF;
}
}
public void WriteWaveRam(byte offset, byte value)
{
throw new Exception("Channel type does have Wave RAM");
}
public byte ReadWaveRam(byte offset)
{
throw new Exception("Channel type does have Wave RAM");
}
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: eab50abebc5d5f341889e031ded6a571

View File

@ -0,0 +1,186 @@
using System;
namespace Essgee.Emulation.Audio
{
public partial class DMGAudio
{
public class Wave : IDMGAudioChannel
{
// NR30
bool isDacEnabled;
// NR31
byte lengthLoad;
// NR32
byte volumeCode;
// NR33
byte frequencyLSB;
// NR34
bool trigger, lengthEnable;
byte frequencyMSB;
// Wave
protected byte[] sampleBuffer;
int frequencyCounter, positionCounter, volume;
// Misc
bool isChannelEnabled;
int lengthCounter;
public int OutputVolume { get; private set; }
public bool IsActive { get { return isDacEnabled; } } // TODO: correct? lengthCounter check makes Zelda Oracle games hang
public Wave()
{
sampleBuffer = new byte[16];
}
public virtual void Reset()
{
for (var i = 0; i < sampleBuffer.Length; i++) sampleBuffer[i] = (byte)EmuStandInfo.Random.Next(255);
frequencyCounter = positionCounter = 0;
volume = 15;
isChannelEnabled = isDacEnabled = false;
lengthCounter = 0;
OutputVolume = volume;
}
public void LengthCounterClock()
{
if (lengthCounter > 0 && lengthEnable)
{
lengthCounter--;
if (lengthCounter == 0)
isChannelEnabled = false;
}
}
public void SweepClock()
{
throw new Exception("Channel type does not support sweep");
}
public void VolumeEnvelopeClock()
{
throw new Exception("Channel type does not support envelope");
}
public void Step()
{
if (!isChannelEnabled) return;
frequencyCounter--;
if (frequencyCounter == 0)
{
frequencyCounter = (2048 - ((frequencyMSB << 8) | frequencyLSB)) * 2;
positionCounter++;
positionCounter %= 32;
var value = sampleBuffer[positionCounter / 2];
if ((positionCounter & 0b1) == 0) value >>= 4;
value &= 0b1111;
if (volumeCode != 0)
volume = value >> (volumeCode - 1);
else
volume = 0;
}
OutputVolume = isDacEnabled ? volume : 0;
}
private void Trigger()
{
isChannelEnabled = true;
if (lengthCounter == 0) lengthCounter = 256;
frequencyCounter = (2048 - ((frequencyMSB << 8) | frequencyLSB)) * 2;
positionCounter = 0;
}
public void WritePort(byte port, byte value)
{
switch (port)
{
case 0:
isDacEnabled = ((value >> 7) & 0b1) == 0b1;
break;
case 1:
lengthLoad = value;
lengthCounter = 256 - lengthLoad;
break;
case 2:
volumeCode = (byte)((value >> 5) & 0b11);
break;
case 3:
frequencyLSB = value;
break;
case 4:
trigger = ((value >> 7) & 0b1) == 0b1;
lengthEnable = ((value >> 6) & 0b1) == 0b1;
frequencyMSB = (byte)((value >> 0) & 0b111);
if (trigger) Trigger();
break;
}
}
public byte ReadPort(byte port)
{
switch (port)
{
case 0:
return (byte)(
0x7F |
(isDacEnabled ? (1 << 7) : 0));
case 1:
return 0xFF;
case 2:
return (byte)(
0x9F |
(volumeCode << 5));
case 4:
return (byte)(
0xBF |
(lengthEnable ? (1 << 6) : 0));
default:
return 0xFF;
}
}
// TODO: more details on behavior on access w/ channel enabled
public void WriteWaveRam(byte offset, byte value)
{
if (!isDacEnabled)
sampleBuffer[offset & (sampleBuffer.Length - 1)] = value;
else
sampleBuffer[positionCounter & (sampleBuffer.Length - 1)] = value;
}
public byte ReadWaveRam(byte offset)
{
if (!isDacEnabled)
return sampleBuffer[offset & (sampleBuffer.Length - 1)];
else
return 0xFF;
}
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a9f4769005789914785d05d63578c931

View File

@ -0,0 +1,494 @@
using Essgee.EventArguments;
using Essgee.Exceptions;
using Essgee.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
namespace Essgee.Emulation.Audio
{
public unsafe partial class DMGAudio : IAudio
{
// https://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware
// http://emudev.de/gameboy-emulator/bleeding-ears-time-to-add-audio/
// https://github.com/GhostSonic21/GhostBoy/blob/master/GhostBoy/APU.cpp
protected const int numChannels = 4;
protected const string channel1OptionName = "AudioEnableCh1Square";
protected const string channel2OptionName = "AudioEnableCh2Square";
protected const string channel3OptionName = "AudioEnableCh3Wave";
protected const string channel4OptionName = "AudioEnableCh4Noise";
protected IDMGAudioChannel channel1, channel2, channel3, channel4;
// FF24 - NR50
byte[] volumeRightLeft;
bool[] vinEnableRightLeft;
// FF25 - NR51
bool[] channel1Enable, channel2Enable, channel3Enable, channel4Enable;
// FF26 - NR52
bool isSoundHwEnabled;
protected int frameSequencerReload, frameSequencerCounter, frameSequencer;
//protected List<short>[] channelSampleBuffer;
#region //指针化 channelSampleBuffer
static short[][] channelSampleBuffer_src;
static GCHandle[] channelSampleBuffer_handle;
public static short*[] channelSampleBuffer;
public static int[] channelSampleBufferLength;
public static int channelSampleBuffer_writePos;
public static bool channelSampleBuffer_IsNull => channelSampleBuffer == null;
public static void channelSampleBuffer_Init(int length1, int Lenght2)
{
if (channelSampleBuffer_src != null)
{
for (int i = 0; i < channelSampleBuffer_src.Length; i++)
channelSampleBuffer_handle[i].ReleaseGCHandle();
}
channelSampleBuffer_src = new short[length1][];
channelSampleBuffer_handle = new GCHandle[length1];
channelSampleBuffer = new short*[length1];
channelSampleBuffer_writePos = 0;
for (int i = 0; i < channelSampleBuffer_src.Length; i++)
{
channelSampleBuffer_src[i] = new short[Lenght2];
channelSampleBuffer_src[i].GetObjectPtr(ref channelSampleBuffer_handle[i], ref channelSampleBuffer[i]);
}
}
#endregion
//protected List<short> mixedSampleBuffer;
#region //指针化 mixedSampleBuffer
short[] mixedSampleBuffer_src;
GCHandle mixedSampleBuffer_handle;
public short* mixedSampleBuffer;
public int mixedSampleBufferLength;
public int mixedSampleBuffer_writePos;
public bool mixedSampleBuffer_IsNull => mixedSampleBuffer == null;
public short[] mixedSampleBuffer_set
{
set
{
mixedSampleBuffer_handle.ReleaseGCHandle();
mixedSampleBuffer_src = value;
mixedSampleBufferLength = value.Length;
mixedSampleBuffer_writePos = 0;
mixedSampleBuffer_src.GetObjectPtr(ref mixedSampleBuffer_handle, ref mixedSampleBuffer);
}
}
#endregion
public virtual event EventHandler<EnqueueSamplesEventArgs> EnqueueSamples;
public virtual void OnEnqueueSamples(EnqueueSamplesEventArgs e) { EnqueueSamples?.Invoke(this, e); }
protected int sampleRate, numOutputChannels;
//
double clockRate, refreshRate;
protected int samplesPerFrame, cyclesPerFrame, cyclesPerSample;
[StateRequired]
int sampleCycleCount, frameCycleCount;
protected bool channel1ForceEnable, channel2ForceEnable, channel3ForceEnable, channel4ForceEnable;
public (string Name, string Description)[] RuntimeOptions => new (string name, string description)[]
{
(channel1OptionName, "Channel 1 (Square)"),
(channel2OptionName, "Channel 2 (Square)"),
(channel3OptionName, "Channel 3 (Wave)"),
(channel4OptionName, "Channel 4 (Noise)")
};
public DMGAudio()
{
//channelSampleBuffer = new List<short>[numChannels];
//for (int i = 0; i < numChannels; i++) channelSampleBuffer[i] = new List<short>();
//mixedSampleBuffer = new List<short>();
//改为二维数组
channelSampleBuffer_Init(numChannels, 1470);
mixedSampleBuffer_set = new short[1470];
channel1 = new Square(true);
channel2 = new Square(false);
channel3 = new Wave();
channel4 = new Noise();
samplesPerFrame = cyclesPerFrame = cyclesPerSample = -1;
channel1ForceEnable = true;
channel2ForceEnable = true;
channel3ForceEnable = true;
channel4ForceEnable = true;
}
public object GetRuntimeOption(string name)
{
switch (name)
{
case channel1OptionName: return channel1ForceEnable;
case channel2OptionName: return channel2ForceEnable;
case channel3OptionName: return channel3ForceEnable;
case channel4OptionName: return channel4ForceEnable;
default: return null;
}
}
public void SetRuntimeOption(string name, object value)
{
switch (name)
{
case channel1OptionName: channel1ForceEnable = (bool)value; break;
case channel2OptionName: channel2ForceEnable = (bool)value; break;
case channel3OptionName: channel3ForceEnable = (bool)value; break;
case channel4OptionName: channel4ForceEnable = (bool)value; break;
}
}
public void SetSampleRate(int rate)
{
sampleRate = rate;
ConfigureTimings();
}
public void SetOutputChannels(int channels)
{
numOutputChannels = channels;
ConfigureTimings();
}
public void SetClockRate(double clock)
{
clockRate = clock;
ConfigureTimings();
}
public void SetRefreshRate(double refresh)
{
refreshRate = refresh;
ConfigureTimings();
}
private void ConfigureTimings()
{
samplesPerFrame = (int)(sampleRate / refreshRate);
cyclesPerFrame = (int)Math.Round(clockRate / refreshRate);
cyclesPerSample = (cyclesPerFrame / samplesPerFrame);
volumeRightLeft = new byte[numOutputChannels];
vinEnableRightLeft = new bool[numOutputChannels];
channel1Enable = new bool[numOutputChannels];
channel2Enable = new bool[numOutputChannels];
channel3Enable = new bool[numOutputChannels];
channel4Enable = new bool[numOutputChannels];
FlushSamples();
}
public virtual void Startup()
{
Reset();
if (samplesPerFrame == -1) throw new EmulationException("GB PSG: Timings not configured, invalid samples per frame");
if (cyclesPerFrame == -1) throw new EmulationException("GB PSG: Timings not configured, invalid cycles per frame");
if (cyclesPerSample == -1) throw new EmulationException("GB PSG: Timings not configured, invalid cycles per sample");
}
public virtual void Shutdown()
{
//
}
public virtual void Reset()
{
FlushSamples();
channel1.Reset();
channel2.Reset();
channel3.Reset();
channel4.Reset();
for (var i = 0; i < numOutputChannels; i++)
{
volumeRightLeft[i] = 0;
vinEnableRightLeft[i] = false;
channel1Enable[i] = false;
channel2Enable[i] = false;
channel3Enable[i] = false;
channel4Enable[i] = false;
}
frameSequencerReload = (int)(clockRate / 512);
frameSequencerCounter = frameSequencerReload;
frameSequencer = 0;
sampleCycleCount = frameCycleCount = 0;
}
public void Step(int clockCyclesInStep)
{
if (!isSoundHwEnabled) return;
sampleCycleCount += clockCyclesInStep;
frameCycleCount += clockCyclesInStep;
for (int i = 0; i < clockCyclesInStep; i++)
{
frameSequencerCounter--;
if (frameSequencerCounter == 0)
{
frameSequencerCounter = frameSequencerReload;
switch (frameSequencer)
{
case 0:
channel1.LengthCounterClock();
channel2.LengthCounterClock();
channel3.LengthCounterClock();
channel4.LengthCounterClock();
break;
case 1:
break;
case 2:
channel1.SweepClock();
channel1.LengthCounterClock();
channel2.LengthCounterClock();
channel3.LengthCounterClock();
channel4.LengthCounterClock();
break;
case 3:
break;
case 4:
channel1.LengthCounterClock();
channel2.LengthCounterClock();
channel3.LengthCounterClock();
channel4.LengthCounterClock();
break;
case 5:
break;
case 6:
channel1.SweepClock();
channel1.LengthCounterClock();
channel2.LengthCounterClock();
channel3.LengthCounterClock();
channel4.LengthCounterClock();
break;
case 7:
channel1.VolumeEnvelopeClock();
channel2.VolumeEnvelopeClock();
channel4.VolumeEnvelopeClock();
break;
}
frameSequencer++;
if (frameSequencer >= 8)
frameSequencer = 0;
}
channel1.Step();
channel2.Step();
channel3.Step();
channel4.Step();
}
if (sampleCycleCount >= cyclesPerSample)
{
GenerateSample();
sampleCycleCount -= cyclesPerSample;
}
//if (mixedSampleBuffer.Count >= (samplesPerFrame * numOutputChannels))
if (mixedSampleBuffer_writePos >= (samplesPerFrame * numOutputChannels))
{
//EnqueueSamplesEventArgs eventArgs = EnqueueSamplesEventArgs.Create(
// numChannels,
// channelSampleBuffer.Select(x => x.ToArray()).ToArray(),
// new bool[] { !channel1ForceEnable, !channel2ForceEnable, !channel3ForceEnable, !channel4ForceEnable },
// mixedSampleBuffer.ToArray());
EnqueueSamplesEventArgs eventArgs = EnqueueSamplesEventArgs.Create(
numChannels,
channelSampleBuffer,
new bool[] { !channel1ForceEnable, !channel2ForceEnable, !channel3ForceEnable, !channel4ForceEnable },
mixedSampleBuffer,
mixedSampleBuffer_writePos);
OnEnqueueSamples(eventArgs);
FlushSamples();
eventArgs.Release();
}
if (frameCycleCount >= cyclesPerFrame)
{
frameCycleCount -= cyclesPerFrame;
sampleCycleCount = frameCycleCount;
}
}
protected virtual void GenerateSample()
{
for (int i = 0; i < numOutputChannels; i++)
{
/* Generate samples */
var ch1 = (short)(((channel1Enable[i] ? channel1.OutputVolume : 0) * (volumeRightLeft[i] + 1)) << 8);
var ch2 = (short)(((channel2Enable[i] ? channel2.OutputVolume : 0) * (volumeRightLeft[i] + 1)) << 8);
var ch3 = (short)(((channel3Enable[i] ? channel3.OutputVolume : 0) * (volumeRightLeft[i] + 1)) << 8);
var ch4 = (short)(((channel4Enable[i] ? channel4.OutputVolume : 0) * (volumeRightLeft[i] + 1)) << 8);
//废弃旧的数组方式
//channelSampleBuffer[0].Add(ch1);
//channelSampleBuffer[1].Add(ch2);
//channelSampleBuffer[2].Add(ch3);
//channelSampleBuffer[3].Add(ch4);
//二维指针下标
channelSampleBuffer_writePos++;
channelSampleBuffer[0][channelSampleBuffer_writePos] = ch1;
channelSampleBuffer[1][channelSampleBuffer_writePos] = ch2;
channelSampleBuffer[2][channelSampleBuffer_writePos] = ch3;
channelSampleBuffer[3][channelSampleBuffer_writePos] = ch4;
/* Mix samples */
var mixed = 0;
if (channel1ForceEnable) mixed += ch1;
if (channel2ForceEnable) mixed += ch2;
if (channel3ForceEnable) mixed += ch3;
if (channel4ForceEnable) mixed += ch4;
mixed /= numChannels;
//废弃旧的方式
//mixedSampleBuffer.Add((short)mixed);
//指针下标
mixedSampleBuffer_writePos++;
mixedSampleBuffer[mixedSampleBuffer_writePos] = (short)mixed;
}
}
public void FlushSamples()
{
//for (int i = 0; i < numChannels; i++)
// channelSampleBuffer[i].Clear();
channelSampleBuffer_writePos = 0;
//mixedSampleBuffer.Clear();
mixedSampleBuffer_writePos = 0;
}
public virtual byte ReadPort(byte port)
{
// Channels
if (port >= 0x10 && port <= 0x14)
return channel1.ReadPort((byte)(port - 0x10));
else if (port >= 0x15 && port <= 0x19)
return channel2.ReadPort((byte)(port - 0x15));
else if (port >= 0x1A && port <= 0x1E)
return channel3.ReadPort((byte)(port - 0x1A));
else if (port >= 0x1F && port <= 0x23)
return channel4.ReadPort((byte)(port - 0x1F));
// Channel 3 Wave RAM
else if (port >= 0x30 && port <= 0x3F)
return channel3.ReadWaveRam((byte)(port - 0x30));
// Control ports
else
switch (port)
{
case 0x24:
return (byte)(
(vinEnableRightLeft[1] ? (1 << 7) : 0) |
(volumeRightLeft[1] << 4) |
(vinEnableRightLeft[0] ? (1 << 3) : 0) |
(volumeRightLeft[0] << 0));
case 0x25:
return (byte)(
(channel4Enable[1] ? (1 << 7) : 0) |
(channel3Enable[1] ? (1 << 6) : 0) |
(channel2Enable[1] ? (1 << 5) : 0) |
(channel1Enable[1] ? (1 << 4) : 0) |
(channel4Enable[0] ? (1 << 3) : 0) |
(channel3Enable[0] ? (1 << 2) : 0) |
(channel2Enable[0] ? (1 << 1) : 0) |
(channel1Enable[0] ? (1 << 0) : 0));
case 0x26:
return (byte)(
0x70 |
(isSoundHwEnabled ? (1 << 7) : 0) |
(channel4.IsActive ? (1 << 3) : 0) |
(channel3.IsActive ? (1 << 2) : 0) |
(channel2.IsActive ? (1 << 1) : 0) |
(channel1.IsActive ? (1 << 0) : 0));
default:
return 0xFF;
}
}
public virtual void WritePort(byte port, byte value)
{
// Channels
if (port >= 0x10 && port <= 0x14)
channel1.WritePort((byte)(port - 0x10), value);
else if (port >= 0x15 && port <= 0x19)
channel2.WritePort((byte)(port - 0x15), value);
else if (port >= 0x1A && port <= 0x1E)
channel3.WritePort((byte)(port - 0x1A), value);
else if (port >= 0x1F && port <= 0x23)
channel4.WritePort((byte)(port - 0x1F), value);
// Channel 3 Wave RAM
else if (port >= 0x30 && port <= 0x3F)
channel3.WriteWaveRam((byte)(port - 0x30), value);
// Control ports
else
switch (port)
{
case 0x24:
vinEnableRightLeft[1] = ((value >> 7) & 0b1) == 0b1;
volumeRightLeft[1] = (byte)((value >> 4) & 0b111);
vinEnableRightLeft[0] = ((value >> 3) & 0b1) == 0b1;
volumeRightLeft[0] = (byte)((value >> 0) & 0b111);
break;
case 0x25:
channel4Enable[1] = ((value >> 7) & 0b1) == 0b1;
channel3Enable[1] = ((value >> 6) & 0b1) == 0b1;
channel2Enable[1] = ((value >> 5) & 0b1) == 0b1;
channel1Enable[1] = ((value >> 4) & 0b1) == 0b1;
channel4Enable[0] = ((value >> 3) & 0b1) == 0b1;
channel3Enable[0] = ((value >> 2) & 0b1) == 0b1;
channel2Enable[0] = ((value >> 1) & 0b1) == 0b1;
channel1Enable[0] = ((value >> 0) & 0b1) == 0b1;
break;
case 0x26:
isSoundHwEnabled = ((value >> 7) & 0b1) == 0b1;
break;
}
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b1912726afeeb8a48bd9e35bf55fe8e3

View File

@ -0,0 +1,26 @@
using Essgee.EventArguments;
using System;
namespace Essgee.Emulation.Audio
{
interface IAudio
{
event EventHandler<EnqueueSamplesEventArgs> EnqueueSamples;
void OnEnqueueSamples(EnqueueSamplesEventArgs e);
(string Name, string Description)[] RuntimeOptions { get; }
object GetRuntimeOption(string name);
void SetRuntimeOption(string name, object value);
void Startup();
void Shutdown();
void Reset();
void Step(int clockCyclesInStep);
void SetSampleRate(int rate);
void SetOutputChannels(int channels);
void SetClockRate(double clock);
void SetRefreshRate(double refresh);
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c7d71d4c287c7024f88c3e76da01431f

View File

@ -0,0 +1,19 @@
namespace Essgee.Emulation.Audio
{
public interface IDMGAudioChannel
{
int OutputVolume { get; }
bool IsActive { get; }
void Reset();
void LengthCounterClock();
void SweepClock();
void VolumeEnvelopeClock();
void Step();
void WritePort(byte port, byte value);
byte ReadPort(byte port);
void WriteWaveRam(byte offset, byte value);
byte ReadWaveRam(byte offset);
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b23834762d9307449a8e4b923fb2688b

View File

@ -0,0 +1,468 @@
using Essgee.EventArguments;
using Essgee.Exceptions;
using Essgee.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using static Essgee.Emulation.Utilities;
namespace Essgee.Emulation.Audio
{
public unsafe class SN76489 : IAudio
{
/* http://www.smspower.org/Development/SN76489 */
/* Differences in various system's PSGs: http://forums.nesdev.com/viewtopic.php?p=190216#p190216 */
protected const int numChannels = 4, numToneChannels = 3, noiseChannelIndex = 3;
protected const string channel1OptionName = "AudioEnableCh1Square";
protected const string channel2OptionName = "AudioEnableCh2Square";
protected const string channel3OptionName = "AudioEnableCh3Square";
protected const string channel4OptionName = "AudioEnableCh4Noise";
/* Noise generation constants */
protected virtual ushort noiseLfsrMask => 0x7FFF;
protected virtual ushort noiseTappedBits => 0x0003; /* Bits 0 and 1 */
protected virtual int noiseBitShift => 14;
/* Sample generation & event handling */
//protected List<short>[] channelSampleBuffer;
#region //指针化 channelSampleBuffer
static short[][] channelSampleBuffer_src;
static GCHandle[] channelSampleBuffer_handle;
public static short*[] channelSampleBuffer;
public static int[] channelSampleBufferLength;
public static int channelSampleBuffer_writePos;
public static bool channelSampleBuffer_IsNull => channelSampleBuffer == null;
public static void channelSampleBuffer_Init(int length1, int Lenght2)
{
if (channelSampleBuffer_src != null)
{
for (int i = 0; i < channelSampleBuffer_src.Length; i++)
channelSampleBuffer_handle[i].ReleaseGCHandle();
}
channelSampleBuffer_src = new short[length1][];
channelSampleBuffer_handle = new GCHandle[length1];
channelSampleBuffer = new short*[length1];
channelSampleBuffer_writePos = 0;
for (int i = 0; i < channelSampleBuffer_src.Length; i++)
{
channelSampleBuffer_src[i] = new short[Lenght2];
channelSampleBuffer_src[i].GetObjectPtr(ref channelSampleBuffer_handle[i], ref channelSampleBuffer[i]);
}
}
#endregion
//protected List<short> mixedSampleBuffer;
#region //指针化 mixedSampleBuffer
short[] mixedSampleBuffer_src;
GCHandle mixedSampleBuffer_handle;
public short* mixedSampleBuffer;
public int mixedSampleBufferLength;
public int mixedSampleBuffer_writePos;
public bool mixedSampleBuffer_IsNull => mixedSampleBuffer == null;
public short[] mixedSampleBuffer_set
{
set
{
mixedSampleBuffer_handle.ReleaseGCHandle();
mixedSampleBuffer_src = value;
mixedSampleBufferLength = value.Length;
mixedSampleBuffer_writePos = 0;
mixedSampleBuffer_src.GetObjectPtr(ref mixedSampleBuffer_handle, ref mixedSampleBuffer);
}
}
#endregion
public virtual event EventHandler<EnqueueSamplesEventArgs> EnqueueSamples;
public virtual void OnEnqueueSamples(EnqueueSamplesEventArgs e) { EnqueueSamples?.Invoke(this, e); }
/* Audio output variables */
protected int sampleRate, numOutputChannels;
/* Channel registers */
[StateRequired]
protected ushort[] volumeRegisters; /* Channels 0-3: 4 bits */
[StateRequired]
protected ushort[] toneRegisters; /* Channels 0-2 (tone): 10 bits; channel 3 (noise): 3 bits */
/* Channel counters */
[StateRequired]
protected ushort[] channelCounters; /* 10-bit counters */
[StateRequired]
protected bool[] channelOutput;
/* Volume attenuation table */
protected short[] volumeTable; /* 2dB change per volume register step */
/* Latched channel/type */
[StateRequired]
byte latchedChannel, latchedType;
/* Linear-feedback shift register, for noise generation */
[StateRequired]
protected ushort noiseLfsr; /* 15-bit */
/* Timing variables */
double clockRate, refreshRate;
int samplesPerFrame, cyclesPerFrame, cyclesPerSample;
[StateRequired]
int sampleCycleCount, frameCycleCount, dividerCount;
/* User-facing channel toggles */
protected bool channel1ForceEnable, channel2ForceEnable, channel3ForceEnable, channel4ForceEnable;
public (string Name, string Description)[] RuntimeOptions => new (string name, string description)[]
{
(channel1OptionName, "Channel 1 (Square)"),
(channel2OptionName, "Channel 2 (Square)"),
(channel3OptionName, "Channel 3 (Square)"),
(channel4OptionName, "Channel 4 (Noise)")
};
public SN76489()
{
//channelSampleBuffer = new List<short>[numChannels];
//for (int i = 0; i < numChannels; i++) channelSampleBuffer[i] = new List<short>();
//mixedSampleBuffer = new List<short>();
//改为二维数组
channelSampleBuffer_Init(numChannels, 1470);
mixedSampleBuffer_set = new short[1470];
volumeRegisters = new ushort[numChannels];
toneRegisters = new ushort[numChannels];
channelCounters = new ushort[numChannels];
channelOutput = new bool[numChannels];
volumeTable = new short[16];
for (int i = 0; i < volumeTable.Length; i++)
volumeTable[i] = (short)(short.MaxValue * Math.Pow(2.0, i * -2.0 / 6.0));
volumeTable[15] = 0;
samplesPerFrame = cyclesPerFrame = cyclesPerSample = -1;
channel1ForceEnable = true;
channel2ForceEnable = true;
channel3ForceEnable = true;
channel4ForceEnable = true;
}
public object GetRuntimeOption(string name)
{
switch (name)
{
case channel1OptionName: return channel1ForceEnable;
case channel2OptionName: return channel2ForceEnable;
case channel3OptionName: return channel3ForceEnable;
case channel4OptionName: return channel4ForceEnable;
default: return null;
}
}
public void SetRuntimeOption(string name, object value)
{
switch (name)
{
case channel1OptionName: channel1ForceEnable = (bool)value; break;
case channel2OptionName: channel2ForceEnable = (bool)value; break;
case channel3OptionName: channel3ForceEnable = (bool)value; break;
case channel4OptionName: channel4ForceEnable = (bool)value; break;
}
}
public void SetSampleRate(int rate)
{
sampleRate = rate;
ConfigureTimings();
}
public void SetOutputChannels(int channels)
{
numOutputChannels = channels;
ConfigureTimings();
}
public void SetClockRate(double clock)
{
clockRate = clock;
ConfigureTimings();
}
public void SetRefreshRate(double refresh)
{
refreshRate = refresh;
ConfigureTimings();
}
private void ConfigureTimings()
{
samplesPerFrame = (int)(sampleRate / refreshRate);
cyclesPerFrame = (int)(clockRate / refreshRate);
cyclesPerSample = (cyclesPerFrame / samplesPerFrame);
FlushSamples();
}
public virtual void Startup()
{
Reset();
if (samplesPerFrame == -1) throw new EmulationException("SN76489: Timings not configured, invalid samples per frame");
if (cyclesPerFrame == -1) throw new EmulationException("SN76489: Timings not configured, invalid cycles per frame");
if (cyclesPerSample == -1) throw new EmulationException("SN76489: Timings not configured, invalid cycles per sample");
}
public virtual void Shutdown()
{
//
}
public virtual void Reset()
{
FlushSamples();
latchedChannel = latchedType = 0x00;
noiseLfsr = 0x4000;
for (int i = 0; i < numChannels; i++)
{
volumeRegisters[i] = 0x000F;
toneRegisters[i] = 0x0000;
}
sampleCycleCount = frameCycleCount = dividerCount = 0;
}
public void Step(int clockCyclesInStep)
{
sampleCycleCount += clockCyclesInStep;
frameCycleCount += clockCyclesInStep;
for (int i = 0; i < clockCyclesInStep; i++)
{
dividerCount++;
if (dividerCount == 16)
{
for (int ch = 0; ch < numToneChannels; ch++)
StepToneChannel(ch);
StepNoiseChannel();
dividerCount = 0;
}
}
if (sampleCycleCount >= cyclesPerSample)
{
GenerateSample();
sampleCycleCount -= cyclesPerSample;
}
//if (mixedSampleBuffer.Count >= (samplesPerFrame * numOutputChannels))
if (mixedSampleBuffer_writePos >= (samplesPerFrame * numOutputChannels))
{
//EnqueueSamplesEventArgs eventArgs = EnqueueSamplesEventArgs.Create(
// numChannels,
// channelSampleBuffer.Select(x => x.ToArray()).ToArray(),
// new bool[] { !channel1ForceEnable, !channel2ForceEnable, !channel3ForceEnable, !channel4ForceEnable },
// mixedSampleBuffer.ToArray());
EnqueueSamplesEventArgs eventArgs = EnqueueSamplesEventArgs.Create(
numChannels,
channelSampleBuffer,
new bool[] { !channel1ForceEnable, !channel2ForceEnable, !channel3ForceEnable, !channel4ForceEnable },
mixedSampleBuffer,
mixedSampleBufferLength);
OnEnqueueSamples(eventArgs);
FlushSamples();
eventArgs.Release();
}
if (frameCycleCount >= cyclesPerFrame)
{
frameCycleCount -= cyclesPerFrame;
sampleCycleCount = frameCycleCount;
}
}
private void StepToneChannel(int ch)
{
/* Check for counter underflow */
if ((channelCounters[ch] & 0x03FF) > 0)
channelCounters[ch]--;
/* Counter underflowed, reload and flip output bit, then generate sample */
if ((channelCounters[ch] & 0x03FF) == 0)
{
channelCounters[ch] = (ushort)(toneRegisters[ch] & 0x03FF);
channelOutput[ch] = !channelOutput[ch];
}
}
private void StepNoiseChannel()
{
int chN = noiseChannelIndex;
{
/* Check for counter underflow */
if ((channelCounters[chN] & 0x03FF) > 0)
channelCounters[chN]--;
/* Counter underflowed, reload and flip output bit */
if ((channelCounters[chN] & 0x03FF) == 0)
{
switch (toneRegisters[chN] & 0x3)
{
case 0x0: channelCounters[chN] = 0x10; break;
case 0x1: channelCounters[chN] = 0x20; break;
case 0x2: channelCounters[chN] = 0x40; break;
case 0x3: channelCounters[chN] = (ushort)(toneRegisters[2] & 0x03FF); break;
}
channelOutput[chN] = !channelOutput[chN];
if (channelOutput[chN])
{
/* Check noise type, then generate sample */
bool isWhiteNoise = (((toneRegisters[chN] >> 2) & 0x1) == 0x1);
ushort newLfsrBit = (ushort)((isWhiteNoise ? CheckParity((ushort)(noiseLfsr & noiseTappedBits)) : (noiseLfsr & 0x01)) << noiseBitShift);
noiseLfsr = (ushort)((newLfsrBit | (noiseLfsr >> 1)) & noiseLfsrMask);
}
}
}
}
protected virtual void GenerateSample()
{
for (int i = 0; i < numOutputChannels; i++)
{
/* Generate samples */
var ch1 = (short)(volumeTable[volumeRegisters[0]] * ((toneRegisters[0] < 2 ? true : channelOutput[0]) ? 1.0 : 0.0));
var ch2 = (short)(volumeTable[volumeRegisters[1]] * ((toneRegisters[1] < 2 ? true : channelOutput[1]) ? 1.0 : 0.0));
var ch3 = (short)(volumeTable[volumeRegisters[2]] * ((toneRegisters[2] < 2 ? true : channelOutput[2]) ? 1.0 : 0.0));
var ch4 = (short)(volumeTable[volumeRegisters[3]] * (noiseLfsr & 0x1));
//废弃旧的数组方式
//channelSampleBuffer[0].Add(ch1);
//channelSampleBuffer[1].Add(ch2);
//channelSampleBuffer[2].Add(ch3);
//channelSampleBuffer[3].Add(ch4);
//二维指针下标
channelSampleBuffer_writePos++;
channelSampleBuffer[0][channelSampleBuffer_writePos] = ch1;
channelSampleBuffer[1][channelSampleBuffer_writePos] = ch2;
channelSampleBuffer[2][channelSampleBuffer_writePos] = ch3;
channelSampleBuffer[3][channelSampleBuffer_writePos] = ch4;
/* Mix samples */
var mixed = 0;
if (channel1ForceEnable) mixed += ch1;
if (channel2ForceEnable) mixed += ch2;
if (channel3ForceEnable) mixed += ch3;
if (channel4ForceEnable) mixed += ch4;
mixed /= numChannels;
//废弃旧的方式
//mixedSampleBuffer.Add((short)mixed);
//指针下标
mixedSampleBuffer_writePos++;
mixedSampleBuffer[mixedSampleBuffer_writePos] = (short)mixed;
}
}
public void FlushSamples()
{
//for (int i = 0; i < numChannels; i++)
// channelSampleBuffer[i].Clear();
channelSampleBuffer_writePos = 0;
//mixedSampleBuffer.Clear();
mixedSampleBuffer_writePos = 0;
}
private ushort CheckParity(ushort val)
{
val ^= (ushort)(val >> 8);
val ^= (ushort)(val >> 4);
val ^= (ushort)(val >> 2);
val ^= (ushort)(val >> 1);
return (ushort)(val & 0x1);
}
public virtual byte ReadPort(byte port)
{
throw new EmulationException("SN76489: Cannot read ports");
}
public virtual void WritePort(byte port, byte data)
{
if (IsBitSet(data, 7))
{
/* LATCH/DATA byte; get channel (0-3) and type (0 is tone/noise, 1 is volume) */
latchedChannel = (byte)((data >> 5) & 0x03);
latchedType = (byte)((data >> 4) & 0x01);
/* Mask off non-data bits */
data &= 0x0F;
/* If target is channel 3 noise (3 bits), mask off highest bit */
if (latchedChannel == 3 && latchedType == 0)
data &= 0x07;
/* Write to register */
if (latchedType == 0)
{
/* Data is tone/noise */
toneRegisters[latchedChannel] = (ushort)((toneRegisters[latchedChannel] & 0x03F0) | data);
}
else
{
/* Data is volume */
volumeRegisters[latchedChannel] = data;
}
}
else
{
/* DATA byte; mask off non-data bits */
data &= 0x3F;
/* Write to register */
if (latchedType == 0)
{
/* Data is tone/noise */
if (latchedChannel == 3)
{
/* Target is channel 3 noise, mask off excess bits and write to low bits of register */
toneRegisters[latchedChannel] = (ushort)(data & 0x07);
}
else
{
/* Target is not channel 3 noise, write to high bits of register */
toneRegisters[latchedChannel] = (ushort)((toneRegisters[latchedChannel] & 0x000F) | (data << 4));
}
}
else
{
/* Data is volume; mask off excess bits and write to low bits of register */
volumeRegisters[latchedChannel] = (ushort)(data & 0x0F);
}
}
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 5b081ff484b016a4faafebb32b5d6bd1

View File

@ -0,0 +1,88 @@
using Essgee.Utilities;
namespace Essgee.Emulation.Audio
{
public unsafe class SegaGGPSG : SegaSMSPSG
{
public const int PortStereoControl = 0x06;
[StateRequired]
readonly bool[] channel0Enable, channel1Enable, channel2Enable, channel3Enable;
public SegaGGPSG() : base()
{
channel0Enable = new bool[2];
channel1Enable = new bool[2];
channel2Enable = new bool[2];
channel3Enable = new bool[2];
}
public override void Reset()
{
base.Reset();
WritePort(PortStereoControl, 0xFF);
}
protected override void GenerateSample()
{
for (int i = 0; i < numOutputChannels; i++)
{
/* Generate samples */
var ch1 = (channel0Enable[i] ? (short)(volumeTable[volumeRegisters[0]] * ((toneRegisters[0] < 2 ? true : channelOutput[0]) ? 1.0 : 0.0)) : (short)0);
var ch2 = (channel1Enable[i] ? (short)(volumeTable[volumeRegisters[1]] * ((toneRegisters[1] < 2 ? true : channelOutput[1]) ? 1.0 : 0.0)) : (short)0);
var ch3 = (channel2Enable[i] ? (short)(volumeTable[volumeRegisters[2]] * ((toneRegisters[2] < 2 ? true : channelOutput[2]) ? 1.0 : 0.0)) : (short)0);
var ch4 = (channel3Enable[i] ? (short)(volumeTable[volumeRegisters[3]] * (noiseLfsr & 0x1)) : (short)0);
//废弃旧的数组方式
//channelSampleBuffer[0].Add(ch1);
//channelSampleBuffer[1].Add(ch2);
//channelSampleBuffer[2].Add(ch3);
//channelSampleBuffer[3].Add(ch4);
//二维指针下标
channelSampleBuffer_writePos++;
channelSampleBuffer[0][channelSampleBuffer_writePos] = ch1;
channelSampleBuffer[1][channelSampleBuffer_writePos] = ch2;
channelSampleBuffer[2][channelSampleBuffer_writePos] = ch3;
channelSampleBuffer[3][channelSampleBuffer_writePos] = ch4;
/* Mix samples */
var mixed = 0;
if (channel1ForceEnable) mixed += ch1;
if (channel2ForceEnable) mixed += ch2;
if (channel3ForceEnable) mixed += ch3;
if (channel4ForceEnable) mixed += ch4;
mixed /= numChannels;
//废弃旧的方式
//mixedSampleBuffer.Add((short)mixed);
//指针下标
mixedSampleBuffer_writePos++;
mixedSampleBuffer[mixedSampleBuffer_writePos] = (short)mixed;
}
}
public override void WritePort(byte port, byte data)
{
if (port == PortStereoControl)
{
/* Stereo control */
channel0Enable[0] = ((data & 0x10) != 0); /* Ch1 Left */
channel0Enable[1] = ((data & 0x01) != 0); /* Ch1 Right */
channel1Enable[0] = ((data & 0x20) != 0); /* Ch2 Left */
channel1Enable[1] = ((data & 0x02) != 0); /* Ch2 Right */
channel2Enable[0] = ((data & 0x40) != 0); /* Ch3 Left */
channel2Enable[1] = ((data & 0x04) != 0); /* Ch3 Right */
channel3Enable[0] = ((data & 0x80) != 0); /* Ch4 Left */
channel3Enable[1] = ((data & 0x08) != 0); /* Ch4 Right */
}
else
base.WritePort(port, data);
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 63b4d9dd3dcd81942aab4e783f7ca197

View File

@ -0,0 +1,19 @@
namespace Essgee.Emulation.Audio
{
public class SegaSMSPSG : SN76489
{
/* LFSR is 16 bits, tapped bits are 0 and 3 (mask 0x0009), going into bit 15 */
protected override ushort noiseLfsrMask => 0xFFFF;
protected override ushort noiseTappedBits => 0x0009;
protected override int noiseBitShift => 15;
public SegaSMSPSG() : base() { }
public override void Reset()
{
base.Reset();
noiseLfsr = 0x8000;
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: bdf808e342a96d74fbbe4a6ea16509eb

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 11616634c9d44b541b8505293e437778
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,13 @@
namespace Essgee.Emulation.CPU
{
interface ICPU
{
void Startup();
void Shutdown();
void Reset();
int Step();
void SetStackPointer(ushort value);
void SetProgramCounter(ushort value);
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: d1eb29143cb5d8e49bb3ebe09e89a215

View File

@ -0,0 +1,53 @@
namespace Essgee.Emulation.CPU
{
public partial class SM83
{
public static class CycleCounts
{
public const int AdditionalJumpCond8Taken = 4;
public const int AdditionalRetCondTaken = 12;
public const int AdditionalCallCondTaken = 12;
// 32 cycles == dummy
public static readonly int[] NoPrefix = new int[]
{
4, 12, 8, 8, 4, 4, 8, 4, 20, 8, 8, 8, 4, 4, 8, 4, /* 0x00 - 0x0F */
4, 12, 8, 8, 4, 4, 8, 4, 12, 8, 8, 8, 4, 4, 8, 4, /* 0x10 - 0x1F */
8, 12, 8, 8, 4, 4, 8, 4, 8, 8, 8, 8, 4, 4, 8, 4, /* 0x20 - 0x2F */
8, 12, 8, 8, 12, 12, 12, 4, 8, 8, 8, 8, 4, 4, 8, 4, /* 0x30 - 0x3F */
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4, /* 0x40 - 0x4F */
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4, /* 0x50 - 0x5F */
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4, /* 0x60 - 0x6F */
8, 8, 8, 8, 8, 8, 4, 8, 4, 4, 4, 4, 4, 4, 8, 4, /* 0x70 - 0x7F */
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4, /* 0x80 - 0x8F */
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4, /* 0x90 - 0x9F */
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4, /* 0xA0 - 0xAF */
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4, /* 0xB0 - 0xBF */
8, 12, 12, 16, 12, 16, 8, 16, 8, 16, 12, 32, 12, 24, 8, 16, /* 0xC0 - 0xCF */
8, 12, 12, 32, 12, 16, 8, 16, 8, 16, 12, 32, 12, 32, 8, 16, /* 0xD0 - 0xDF */
12, 12, 8, 32, 32, 16, 8, 16, 16, 4, 16, 32, 32, 32, 8, 16, /* 0xE0 - 0xEF */
12, 12, 8, 4, 32, 16, 8, 16, 12, 8, 16, 4, 32, 32, 8, 16 /* 0xF0 - 0xFF */
};
public static readonly int[] PrefixCB = new int[]
{
8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, /* 0x00 - 0x0F */
8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, /* 0x10 - 0x1F */
8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, /* 0x20 - 0x2F */
8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, /* 0x30 - 0x3F */
8, 8, 8, 8, 8, 8, 12, 8, 8, 8, 8, 8, 8, 8, 12, 8, /* 0x40 - 0x4F */
8, 8, 8, 8, 8, 8, 12, 8, 8, 8, 8, 8, 8, 8, 12, 8, /* 0x50 - 0x5F */
8, 8, 8, 8, 8, 8, 12, 8, 8, 8, 8, 8, 8, 8, 12, 8, /* 0x60 - 0x6F */
8, 8, 8, 8, 8, 8, 12, 8, 8, 8, 8, 8, 8, 8, 12, 8, /* 0x70 - 0x7F */
8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, /* 0x80 - 0x8F */
8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, /* 0x90 - 0x9F */
8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, /* 0xA0 - 0xAF */
8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, /* 0xB0 - 0xBF */
8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, /* 0xC0 - 0xCF */
8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, /* 0xD0 - 0xDF */
8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8, /* 0xE0 - 0xEF */
8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8 /* 0xF0 - 0xFF */
};
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e1d2dab87d28f044ca71114b277aee3a

View File

@ -0,0 +1,201 @@
using System.Linq;
namespace Essgee.Emulation.CPU
{
public partial class SM83
{
static readonly string[] opcodeMnemonicNoPrefix =
{
/* +00 +01 +02 +03 +04 +05 +06 +07 */
"NOP", "LD BC, 0x{0:X4}", "LD (BC), A", "INC BC", "INC B", "DEC B", "LD B, 0x{0:X2}", "RLCA", /* 0x00 */
"LD (0x{0:X4}), SP", "ADD HL, BC", "LD A, (BC)", "DEC BC", "INC C", "DEC C", "LD C, 0x{0:X2}", "RRCA", /* 0x08 */
"STOP", "LD DE, 0x{0:X4}", "LD (DE), A", "INC DE", "INC D", "DEC D", "LD D, 0x{0:X2}", "RLA", /* 0x10 */
"JR 0x{0:X2}", "ADD HL, DE", "LD A, (DE)", "DEC DE", "INC E", "DEC E", "LD E, 0x{0:X2}", "RRA", /* 0x18 */
"JR NZ, 0x{0:X2}", "LD HL, 0x{0:X4}", "LDI (HL), A", "INC HL", "INC H", "DEC H", "LD H, 0x{0:X2}", "DAA", /* 0x20 */
"JR Z, 0x{0:X2}", "ADD HL, HL", "LDI A, (HL)", "DEC HL", "INC L", "DEC L", "LD L, 0x{0:X2}", "CPL", /* 0x28 */
"JR NC, 0x{0:X2}", "LD SP, 0x{0:X4}", "LDD (HL), A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL), 0x{0:X2}", "SCF", /* 0x30 */
"JR C, 0x{0:X2}", "ADD HL, SP", "LDD A, (HL)", "DEC SP", "INC A", "DEC A", "LD A, 0x{0:X2}", "CCF", /* 0x38 */
"LD B, B", "LD B, C", "LD B, D", "LD B, E", "LD B, H", "LD B, L", "LD B, (HL)", "LD B, A", /* 0x40 */
"LD C, B", "LD C, C", "LD C, D", "LD C, E", "LD C, H", "LD C, L", "LD C, (HL)", "LD C, A", /* 0x48 */
"LD D, B", "LD D, C", "LD D, D", "LD D, E", "LD D, H", "LD D, L", "LD D, (HL)", "LD D, A", /* 0x50 */
"LD E, B", "LD E, C", "LD E, D", "LD E, E", "LD E, H", "LD E, L", "LD E, (HL)", "LD E, A", /* 0x58 */
"LD H, B", "LD H, C", "LD H, D", "LD H, E", "LD H, H", "LD H, L", "LD H, (HL)", "LD H, A", /* 0x60 */
"LD L, B", "LD L, C", "LD L, D", "LD L, E", "LD L, H", "LD L, L", "LD L, (HL)", "LD L, A", /* 0x68 */
"LD (HL), B", "LD (HL), C", "LD (HL), D", "LD (HL), E", "LD (HL), H", "LD (HL), L", "HALT", "LD (HL), A", /* 0x70 */
"LD A, B", "LD A, C", "LD A, D", "LD A, E", "LD A, H", "LD A, L", "LD A, (HL)", "LD A, A", /* 0x78 */
"ADD B", "ADD C", "ADD D", "ADD E", "ADD H", "ADD L", "ADD (HL)", "ADD A", /* 0x80 */
"ADC B", "ADC C", "ADC D", "ADC E", "ADC H", "ADC L", "ADC (HL)", "ADC A", /* 0x88 */
"SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A", /* 0x90 */
"SBC B", "SBC C", "SBC D", "SBC E", "SBC H", "SBC L", "SBC (HL)", "SBC A", /* 0x98 */
"AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A", /* 0xA0 */
"XOR B", "XOR C", "XOR D", "XOR E", "XOR H", "XOR L", "XOR (HL)", "XOR A", /* 0xA8 */
"OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A", /* 0xB0 */
"CP B", "CP C", "CP D", "CP E", "CP H", "CP L", "CP (HL)", "CP A", /* 0xB8 */
"RET NZ", "POP BC", "JP NZ, 0x{0:X4}", "JP 0x{0:X4}", "CALL NZ, 0x{0:X4}", "PUSH BC", "ADD 0x{0:X2}", "RST 00", /* 0xC0 */
"RET Z", "RET", "JP Z, 0x{0:X4}", string.Empty, "CALL Z, 0x{0:X4}", "CALL 0x{0:X4}", "ADC 0x{0:X2}", "RST 08", /* 0xC8 */
"RET NC", "POP DE", "JP NC, 0x{0:X4}", ".DB 0xD3", "CALL NC, 0x{0:X4}", "PUSH DE", "SUB 0x{0:X2}", "RST 10", /* 0xD0 */
"RET C", "RETI", "JP C, 0x{0:X4}", ".DB 0xDB", "CALL C, 0x{0:X4}", ".DB 0xDD", "SBC 0x{0:X2}", "RST 18", /* 0xD8 */
"LD (FF00+0x{0:X2}), A", "POP HL", "LD (FF00+C), A", ".DB 0xE3", ".DB 0xE4", "PUSH HL", "AND 0x{0:X2}", "RST 20", /* 0xE0 */
"ADD SP, 0x{0:X2}", "LD PC, HL", "LD (0x{0:X4}), A", ".DB 0xEB", ".DB 0xEC", ".DB 0xED", "XOR 0x{0:X2}", "RST 28", /* 0xE8 */
"LD A, (FF00+0x{0:X2})", "POP AF", "LD A, (FF00+C)", "DI", ".DB 0xF4", "PUSH AF", "OR 0x{0:X2}", "RST 30", /* 0xF0 */
"LD HL, SP+0x{0:X2}", "LD SP, HL", "LD A, (0x{0:X4})", "EI", ".DB 0xFC", ".DB 0xFD", "CP 0x{0:X2}", "RST 38" /* 0xF8 */
};
static readonly int[] opcodeLengthNoPrefix =
{
1, 3, 1, 1, 1, 1, 2, 1, 3, 1, 1, 1, 1, 1, 2, 1,
2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1,
2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1,
2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 3, 3, 3, 1, 2, 1, 1, 1, 3, 2, 3, 3, 2, 1,
1, 1, 3, 1, 3, 1, 2, 1, 1, 1, 3, 1, 3, 1, 2, 1,
2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1,
2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1
};
static readonly string[] opcodeMnemonicPrefixCB = new string[]
{
/* +00 +01 +02 +03 +04 +05 +06 +07 */
"RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A", /* 0x00 */
"RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (HL)", "RRC A", /* 0x08 */
"RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A", /* 0x10 */
"RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (HL)", "RR A", /* 0x18 */
"SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A", /* 0x20 */
"SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (HL)", "SRA A", /* 0x28 */
"SWAP B", "SWAP C", "SWAP D", "SWAP E", "SWAP H", "SWAP L", "SWAP (HL)", "SWAP A", /* 0x30 */
"SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A", /* 0x38 */
"BIT 0, B", "BIT 0, C", "BIT 0, D", "BIT 0, E", "BIT 0, H", "BIT 0, L", "BIT 0, (HL)", "BIT 0, A", /* 0x40 */
"BIT 1, B", "BIT 1, C", "BIT 1, D", "BIT 1, E", "BIT 1, H", "BIT 1, L", "BIT 1, (HL)", "BIT 1, A", /* 0x48 */
"BIT 2, B", "BIT 2, C", "BIT 2, D", "BIT 2, E", "BIT 2, H", "BIT 2, L", "BIT 2, (HL)", "BIT 2, A", /* 0x50 */
"BIT 3, B", "BIT 3, C", "BIT 3, D", "BIT 3, E", "BIT 3, H", "BIT 3, L", "BIT 3, (HL)", "BIT 3, A", /* 0x58 */
"BIT 4, B", "BIT 4, C", "BIT 4, D", "BIT 4, E", "BIT 4, H", "BIT 4, L", "BIT 4, (HL)", "BIT 4, A", /* 0x60 */
"BIT 5, B", "BIT 5, C", "BIT 5, D", "BIT 5, E", "BIT 5, H", "BIT 5, L", "BIT 5, (HL)", "BIT 5, A", /* 0x68 */
"BIT 6, B", "BIT 6, C", "BIT 6, D", "BIT 6, E", "BIT 6, H", "BIT 6, L", "BIT 6, (HL)", "BIT 6, A", /* 0x70 */
"BIT 7, B", "BIT 7, C", "BIT 7, D", "BIT 7, E", "BIT 7, H", "BIT 7, L", "BIT 7, (HL)", "BIT 7, A", /* 0x78 */
"RES 0, B", "RES 0, C", "RES 0, D", "RES 0, E", "RES 0, H", "RES 0, L", "RES 0, (HL)", "RES 0, A", /* 0x80 */
"RES 1, B", "RES 1, C", "RES 1, D", "RES 1, E", "RES 1, H", "RES 1, L", "RES 1, (HL)", "RES 1, A", /* 0x88 */
"RES 2, B", "RES 2, C", "RES 2, D", "RES 2, E", "RES 2, H", "RES 2, L", "RES 2, (HL)", "RES 2, A", /* 0x90 */
"RES 3, B", "RES 3, C", "RES 3, D", "RES 3, E", "RES 3, H", "RES 3, L", "RES 3, (HL)", "RES 3, A", /* 0x98 */
"RES 4, B", "RES 4, C", "RES 4, D", "RES 4, E", "RES 4, H", "RES 4, L", "RES 4, (HL)", "RES 4, A", /* 0xA0 */
"RES 5, B", "RES 5, C", "RES 5, D", "RES 5, E", "RES 5, H", "RES 5, L", "RES 5, (HL)", "RES 5, A", /* 0xA8 */
"RES 6, B", "RES 6, C", "RES 6, D", "RES 6, E", "RES 6, H", "RES 6, L", "RES 6, (HL)", "RES 6, A", /* 0xB0 */
"RES 7, B", "RES 7, C", "RES 7, D", "RES 7, E", "RES 7, H", "RES 7, L", "RES 7, (HL)", "RES 7, A", /* 0xB8 */
"SET 0, B", "SET 0, C", "SET 0, D", "SET 0, E", "SET 0, H", "SET 0, L", "SET 0, (HL)", "SET 0, A", /* 0xC0 */
"SET 1, B", "SET 1, C", "SET 1, D", "SET 1, E", "SET 1, H", "SET 1, L", "SET 1, (HL)", "SET 1, A", /* 0xC8 */
"SET 2, B", "SET 2, C", "SET 2, D", "SET 2, E", "SET 2, H", "SET 2, L", "SET 2, (HL)", "SET 2, A", /* 0xD0 */
"SET 3, B", "SET 3, C", "SET 3, D", "SET 3, E", "SET 3, H", "SET 3, L", "SET 3, (HL)", "SET 3, A", /* 0xD8 */
"SET 4, B", "SET 4, C", "SET 4, D", "SET 4, E", "SET 4, H", "SET 4, L", "SET 4, (HL)", "SET 4, A", /* 0xE0 */
"SET 5, B", "SET 5, C", "SET 5, D", "SET 5, E", "SET 5, H", "SET 5, L", "SET 5, (HL)", "SET 5, A", /* 0xE8 */
"SET 6, B", "SET 6, C", "SET 6, D", "SET 6, E", "SET 6, H", "SET 6, L", "SET 6, (HL)", "SET 6, A", /* 0xF0 */
"SET 7, B", "SET 7, C", "SET 7, D", "SET 7, E", "SET 7, H", "SET 7, L", "SET 7, (HL)", "SET 7, A" /* 0xF8 */
};
static readonly int[] opcodeLengthPrefixCB = new int[]
{
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
};
public static string PrintRegisters(SM83 cpu)
{
return $"AF:{cpu.af.Word:X4} BC:{cpu.bc.Word:X4} DE:{cpu.de.Word:X4} HL:{cpu.hl.Word:X4} SP:{cpu.sp:X4}";
}
public static string PrintFlags(SM83 cpu)
{
return $"{(cpu.IsFlagSet(Flags.Zero) ? "Z" : "-")}{(cpu.IsFlagSet(Flags.Subtract) ? "N" : "-")}{(cpu.IsFlagSet(Flags.HalfCarry) ? "H" : "-")}{(cpu.IsFlagSet(Flags.Carry) ? "C" : "-")}";
}
public static string PrintInterrupt(SM83 cpu)
{
var intFlags = (InterruptSource)cpu.memoryReadDelegate(0xFF0F);
var intEnable = (InterruptSource)cpu.memoryReadDelegate(0xFFFF);
var intFlagsString =
$"{((intFlags & InterruptSource.VBlank) != 0 ? "V" : "-")}" +
$"{((intFlags & InterruptSource.LCDCStatus) != 0 ? "L" : "-")}" +
$"{((intFlags & InterruptSource.TimerOverflow) != 0 ? "T" : "-")}" +
$"{((intFlags & InterruptSource.SerialIO) != 0 ? "S" : "-")}" +
$"{((intFlags & InterruptSource.Keypad) != 0 ? "K" : "-")}";
var intEnableString =
$"{((intEnable & InterruptSource.VBlank) != 0 ? "V" : "-")}" +
$"{((intEnable & InterruptSource.LCDCStatus) != 0 ? "L" : "-")}" +
$"{((intEnable & InterruptSource.TimerOverflow) != 0 ? "T" : "-")}" +
$"{((intEnable & InterruptSource.SerialIO) != 0 ? "S" : "-")}" +
$"{((intEnable & InterruptSource.Keypad) != 0 ? "K" : "-")}";
return $"IME:{(cpu.ime ? "1" : "0")} IF:{intFlagsString} IE:{intEnableString}";
}
public static string DisassembleOpcode(SM83 cpu, ushort address)
{
var opcode = DisassembleGetOpcodeBytes(cpu, address);
return $"0x{address:X4} | {DisassembleMakeByteString(cpu, opcode).PadRight(15)} | {DisassembleMakeMnemonicString(cpu, opcode)}";
}
public static byte[] DisassembleGetOpcodeBytes(SM83 cpu, ushort address)
{
var opcode = new byte[3];
for (int i = 0; i < opcode.Length; i++)
opcode[i] = address + i <= 0xFFFF ? cpu.memoryReadDelegate((ushort)(address + i)) : (byte)0;
return opcode;
}
public static int DisassembleGetOpcodeLen(SM83 cpu, byte[] opcode)
{
if (opcode[0] == 0xCB)
return opcodeLengthPrefixCB[opcode[1]];
else
return opcodeLengthNoPrefix[opcode[0]];
}
public static string DisassembleMakeByteString(SM83 cpu, byte[] opcode)
{
return string.Join(" ", opcode.Select(x => $"{x:X2}").Take(DisassembleGetOpcodeLen(cpu, opcode)));
}
public static string DisassembleMakeMnemonicString(SM83 cpu, byte[] opcode)
{
var len = DisassembleGetOpcodeLen(cpu, opcode);
var start = opcode[0] == 0xCB ? 1 : 0;
var mnemonics = opcode[0] == 0xCB ? opcodeMnemonicPrefixCB : opcodeMnemonicNoPrefix;
switch (len - start)
{
case 1: return mnemonics[opcode[start]];
case 2: return string.Format(mnemonics[opcode[start]], opcode[start + 1]);
case 3: return string.Format(mnemonics[opcode[start]], (opcode[start + 2] << 8 | opcode[start + 1]));
default: return string.Empty;
}
}
private string MakeUnimplementedOpcodeString(string prefix, ushort address)
{
var opcode = DisassembleGetOpcodeBytes(this, address);
return $"Unimplemented {(prefix != string.Empty ? prefix + " " : prefix)}opcode {DisassembleMakeByteString(this, opcode)} ({DisassembleMakeMnemonicString(this, opcode)})";
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 7de4aca2c5f71b94b9509b8ad7b6ef8f

View File

@ -0,0 +1,281 @@
namespace Essgee.Emulation.CPU
{
public partial class SM83
{
static SimpleOpcodeDelegate[] opcodesNoPrefix = new SimpleOpcodeDelegate[]
{
/* 0x00 */
new SimpleOpcodeDelegate((c) => { /* NOP */ }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate16(ref c.bc.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.bc.Word, c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.Increment16(ref c.bc.Word); }),
new SimpleOpcodeDelegate((c) => { c.Increment8(ref c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.Decrement8(ref c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate8(ref c.bc.High, false); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeftAccumulatorCircular(); }),
new SimpleOpcodeDelegate((c) => { c.WriteMemory16(c.ReadMemory16(c.pc), c.sp); c.pc += 2; }),
new SimpleOpcodeDelegate((c) => { c.Add16(ref c.hl, c.bc.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterFromMemory8(ref c.af.High, c.bc.Word, false); }),
new SimpleOpcodeDelegate((c) => { c.Decrement16(ref c.bc.Word); }),
new SimpleOpcodeDelegate((c) => { c.Increment8(ref c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.Decrement8(ref c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate8(ref c.bc.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.RotateRightAccumulatorCircular(); }),
/* 0x10 */
new SimpleOpcodeDelegate((c) => { c.Stop(); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate16(ref c.de.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.de.Word, c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.Increment16(ref c.de.Word); }),
new SimpleOpcodeDelegate((c) => { c.Increment8(ref c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.Decrement8(ref c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate8(ref c.de.High, false); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeftAccumulator(); }),
new SimpleOpcodeDelegate((c) => { c.Jump8(); }),
new SimpleOpcodeDelegate((c) => { c.Add16(ref c.hl, c.de.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterFromMemory8(ref c.af.High, c.de.Word, false); }),
new SimpleOpcodeDelegate((c) => { c.Decrement16(ref c.de.Word); }),
new SimpleOpcodeDelegate((c) => { c.Increment8(ref c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.Decrement8(ref c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate8(ref c.de.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.RotateRightAccumulator(); }),
/* 0x20 */
new SimpleOpcodeDelegate((c) => { c.JumpConditional8(!c.IsFlagSet(Flags.Zero)); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate16(ref c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.WriteMemory8(c.hl.Word++, c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.Increment16(ref c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.Increment8(ref c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.Decrement8(ref c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate8(ref c.hl.High, false); }),
new SimpleOpcodeDelegate((c) => { c.DecimalAdjustAccumulator(); }),
new SimpleOpcodeDelegate((c) => { c.JumpConditional8(c.IsFlagSet(Flags.Zero)); }),
new SimpleOpcodeDelegate((c) => { c.Add16(ref c.hl, c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.af.High = c.ReadMemory8(c.hl.Word++); }),
new SimpleOpcodeDelegate((c) => { c.Decrement16(ref c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.Increment8(ref c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.Decrement8(ref c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate8(ref c.hl.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.af.High ^= 0xFF; c.SetFlag(Flags.Subtract | Flags.HalfCarry); }),
/* 0x30 */
new SimpleOpcodeDelegate((c) => { c.JumpConditional8(!c.IsFlagSet(Flags.Carry)); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate16(ref c.sp); }),
new SimpleOpcodeDelegate((c) => { c.WriteMemory8(c.hl.Word--, c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.Increment16(ref c.sp); }),
new SimpleOpcodeDelegate((c) => { c.IncrementMemory8(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.DecrementMemory8(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.hl.Word, c.ReadMemory8(c.pc++)); }),
new SimpleOpcodeDelegate((c) => { c.SetFlag(Flags.Carry); c.ClearFlag(Flags.Subtract | Flags.HalfCarry); }),
new SimpleOpcodeDelegate((c) => { c.JumpConditional8(c.IsFlagSet(Flags.Carry)); }),
new SimpleOpcodeDelegate((c) => { c.Add16(ref c.hl, c.sp); }),
new SimpleOpcodeDelegate((c) => { c.af.High = c.ReadMemory8(c.hl.Word--);}),
new SimpleOpcodeDelegate((c) => { c.Decrement16(ref c.sp); }),
new SimpleOpcodeDelegate((c) => { c.Increment8(ref c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.Decrement8(ref c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate8(ref c.af.High, false); }),
new SimpleOpcodeDelegate((c) => { c.ClearFlag(Flags.Subtract); c.ClearFlag(Flags.HalfCarry); c.SetClearFlagConditional(Flags.Carry, !c.IsFlagSet(Flags.Carry)); }),
/* 0x40 */
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.High, c.bc.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.High, c.bc.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.High, c.de.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.High, c.de.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.High, c.hl.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.High, c.hl.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.bc.High = c.ReadMemory8(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.High, c.af.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.Low, c.bc.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.Low, c.bc.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.Low, c.de.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.Low, c.de.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.Low, c.hl.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.Low, c.hl.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.bc.Low = c.ReadMemory8(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.Low, c.af.High, false); }),
/* 0x50 */
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.High, c.bc.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.High, c.bc.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.High, c.de.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.High, c.de.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.High, c.hl.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.High, c.hl.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.de.High = c.ReadMemory8(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.High, c.af.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.Low, c.bc.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.Low, c.bc.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.Low, c.de.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.Low, c.de.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.Low, c.hl.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.Low, c.hl.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.de.Low = c.ReadMemory8(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.Low, c.af.High, false); }),
/* 0x60 */
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.High, c.bc.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.High, c.bc.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.High, c.de.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.High, c.de.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.High, c.hl.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.High, c.hl.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.hl.High = c.ReadMemory8(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.High, c.af.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.Low, c.bc.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.Low, c.bc.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.Low, c.de.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.Low, c.de.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.Low, c.hl.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.Low, c.hl.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.hl.Low = c.ReadMemory8(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.Low, c.af.High, false); }),
/* 0x70 */
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.hl.Word, c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.hl.Word, c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.hl.Word, c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.hl.Word, c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.hl.Word, c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.hl.Word, c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.EnterHaltState(); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.hl.Word, c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.af.High, c.bc.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.af.High, c.bc.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.af.High, c.de.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.af.High, c.de.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.af.High, c.hl.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.af.High, c.hl.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.af.High = c.ReadMemory8(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.af.High, c.af.High, false); }),
/* 0x80 */
new SimpleOpcodeDelegate((c) => { c.Add8(c.bc.High, false); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.bc.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.de.High, false); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.de.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.hl.High, false); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.hl.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.ReadMemory8(c.hl.Word), false); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.af.High, false); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.bc.High, true); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.bc.Low, true); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.de.High, true); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.de.Low, true); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.hl.High, true); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.hl.Low, true); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.ReadMemory8(c.hl.Word), true); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.af.High, true); }),
/* 0x90 */
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.bc.High, false); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.bc.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.de.High, false); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.de.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.hl.High, false); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.hl.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.ReadMemory8(c.hl.Word), false); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.af.High, false); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.bc.High, true); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.bc.Low, true); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.de.High, true); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.de.Low, true); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.hl.High, true); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.hl.Low, true); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.ReadMemory8(c.hl.Word), true); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.af.High, true); }),
/* 0xA0 */
new SimpleOpcodeDelegate((c) => { c.And8(c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.And8(c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.And8(c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.And8(c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.And8(c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.And8(c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.And8(c.ReadMemory8(c.hl.Word)); }),
new SimpleOpcodeDelegate((c) => { c.And8(c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.Xor8(c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.Xor8(c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.Xor8(c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.Xor8(c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.Xor8(c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.Xor8(c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.Xor8(c.ReadMemory8(c.hl.Word)); }),
new SimpleOpcodeDelegate((c) => { c.Xor8(c.af.High); }),
/* 0xB0 */
new SimpleOpcodeDelegate((c) => { c.Or8(c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.Or8(c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.Or8(c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.Or8(c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.Or8(c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.Or8(c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.Or8(c.ReadMemory8(c.hl.Word)); }),
new SimpleOpcodeDelegate((c) => { c.Or8(c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.Cp8(c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.Cp8(c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.Cp8(c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.Cp8(c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.Cp8(c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.Cp8(c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.Cp8(c.ReadMemory8(c.hl.Word)); }),
new SimpleOpcodeDelegate((c) => { c.Cp8(c.af.High); }),
/* 0xC0 */
new SimpleOpcodeDelegate((c) => { c.ReturnConditional(!c.IsFlagSet(Flags.Zero)); }),
new SimpleOpcodeDelegate((c) => { c.Pop(ref c.bc); }),
new SimpleOpcodeDelegate((c) => { c.JumpConditional16(!c.IsFlagSet(Flags.Zero)); }),
new SimpleOpcodeDelegate((c) => { c.JumpConditional16(true); }),
new SimpleOpcodeDelegate((c) => { c.CallConditional16(!c.IsFlagSet(Flags.Zero)); }),
new SimpleOpcodeDelegate((c) => { c.Push(c.bc); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.ReadMemory8(c.pc++), false); }),
new SimpleOpcodeDelegate((c) => { c.Restart(0x0000); }),
new SimpleOpcodeDelegate((c) => { c.ReturnConditional(c.IsFlagSet(Flags.Zero)); }),
new SimpleOpcodeDelegate((c) => { c.Return(); }),
new SimpleOpcodeDelegate((c) => { c.JumpConditional16(c.IsFlagSet(Flags.Zero)); }),
new SimpleOpcodeDelegate((c) => { /* CB - handled elsewhere */ }),
new SimpleOpcodeDelegate((c) => { c.CallConditional16(c.IsFlagSet(Flags.Zero)); }),
new SimpleOpcodeDelegate((c) => { c.Call16(); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.ReadMemory8(c.pc++), true); }),
new SimpleOpcodeDelegate((c) => { c.Restart(0x0008); }),
/* 0xD0 */
new SimpleOpcodeDelegate((c) => { c.ReturnConditional(!c.IsFlagSet(Flags.Carry)); }),
new SimpleOpcodeDelegate((c) => { c.Pop(ref c.de); }),
new SimpleOpcodeDelegate((c) => { c.JumpConditional16(!c.IsFlagSet(Flags.Carry)); }),
new SimpleOpcodeDelegate((c) => { c.pc--; }),
new SimpleOpcodeDelegate((c) => { c.CallConditional16(!c.IsFlagSet(Flags.Carry)); }),
new SimpleOpcodeDelegate((c) => { c.Push(c.de); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.ReadMemory8(c.pc++), false); }),
new SimpleOpcodeDelegate((c) => { c.Restart(0x0010); }),
new SimpleOpcodeDelegate((c) => { c.ReturnConditional(c.IsFlagSet(Flags.Carry)); }),
new SimpleOpcodeDelegate((c) => { c.ime = true; c.imeDelay = false; c.Return(); }),
new SimpleOpcodeDelegate((c) => { c.JumpConditional16(c.IsFlagSet(Flags.Carry)); }),
new SimpleOpcodeDelegate((c) => { c.pc--; }),
new SimpleOpcodeDelegate((c) => { c.CallConditional16(c.IsFlagSet(Flags.Carry)); }),
new SimpleOpcodeDelegate((c) => { c.pc--; }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.ReadMemory8(c.pc++), true); }),
new SimpleOpcodeDelegate((c) => { c.Restart(0x0018); }),
/* 0xE0 */
new SimpleOpcodeDelegate((c) => { c.WriteMemory8((ushort)(0xFF00 + c.ReadMemory8(c.pc++)), c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.Pop(ref c.hl); }),
new SimpleOpcodeDelegate((c) => { c.WriteMemory8((ushort)(0xFF00 + c.bc.Low), c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.pc--; }),
new SimpleOpcodeDelegate((c) => { c.pc--; }),
new SimpleOpcodeDelegate((c) => { c.Push(c.hl); }),
new SimpleOpcodeDelegate((c) => { c.And8(c.ReadMemory8(c.pc++)); }),
new SimpleOpcodeDelegate((c) => { c.Restart(0x0020); }),
new SimpleOpcodeDelegate((c) => { c.AddSPNN(); }),
new SimpleOpcodeDelegate((c) => { c.pc = c.hl.Word; }),
new SimpleOpcodeDelegate((c) => { c.WriteMemory8(c.ReadMemory16(c.pc), c.af.High); c.pc += 2; }),
new SimpleOpcodeDelegate((c) => { c.pc--; }),
new SimpleOpcodeDelegate((c) => { c.pc--; }),
new SimpleOpcodeDelegate((c) => { c.pc--; }),
new SimpleOpcodeDelegate((c) => { c.Xor8(c.ReadMemory8(c.pc++)); }),
new SimpleOpcodeDelegate((c) => { c.Restart(0x0028); }),
/* 0xF0 */
new SimpleOpcodeDelegate((c) => { c.af.High = c.ReadMemory8((ushort)(0xFF00 + c.ReadMemory8(c.pc++))); }),
new SimpleOpcodeDelegate((c) => { c.PopAF(); }),
new SimpleOpcodeDelegate((c) => { c.af.High = c.ReadMemory8((ushort)(0xFF00 + c.bc.Low)); }),
new SimpleOpcodeDelegate((c) => { c.DisableInterrupts(); }),
new SimpleOpcodeDelegate((c) => { c.pc--; }),
new SimpleOpcodeDelegate((c) => { c.Push(c.af); }),
new SimpleOpcodeDelegate((c) => { c.Or8(c.ReadMemory8(c.pc++)); }),
new SimpleOpcodeDelegate((c) => { c.Restart(0x0030); }),
new SimpleOpcodeDelegate((c) => { c.LoadHLSPNN(); }),
new SimpleOpcodeDelegate((c) => { c.sp = c.hl.Word; }),
new SimpleOpcodeDelegate((c) => { c.af.High = c.ReadMemory8(c.ReadMemory16(c.pc)); c.pc += 2; }),
new SimpleOpcodeDelegate((c) => { c.EnableInterrupts(); }),
new SimpleOpcodeDelegate((c) => { c.pc--; }),
new SimpleOpcodeDelegate((c) => { c.pc--; }),
new SimpleOpcodeDelegate((c) => { c.Cp8(c.ReadMemory8(c.pc++)); }),
new SimpleOpcodeDelegate((c) => { c.Restart(0x0038); })
};
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e4fe2d8ddc2d10849b6c7c6d64db0d4f

View File

@ -0,0 +1,281 @@
namespace Essgee.Emulation.CPU
{
public partial class SM83
{
static SimpleOpcodeDelegate[] opcodesPrefixCB = new SimpleOpcodeDelegate[]
{
/* 0x00 */
new SimpleOpcodeDelegate((c) => { c.RotateLeftCircular(ref c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeftCircular(ref c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeftCircular(ref c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeftCircular(ref c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeftCircular(ref c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeftCircular(ref c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeftCircular(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeftCircular(ref c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateRightCircular(ref c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateRightCircular(ref c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateRightCircular(ref c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateRightCircular(ref c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateRightCircular(ref c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateRightCircular(ref c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateRightCircular(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.RotateRightCircular(ref c.af.High); }),
/* 0x10 */
new SimpleOpcodeDelegate((c) => { c.RotateLeft(ref c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeft(ref c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeft(ref c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeft(ref c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeft(ref c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeft(ref c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeft(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeft(ref c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateRight(ref c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateRight(ref c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateRight(ref c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateRight(ref c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateRight(ref c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateRight(ref c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateRight(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.RotateRight(ref c.af.High); }),
/* 0x20 */
new SimpleOpcodeDelegate((c) => { c.ShiftLeftArithmetic(ref c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftArithmetic(ref c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftArithmetic(ref c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftArithmetic(ref c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftArithmetic(ref c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftArithmetic(ref c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftArithmetic(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftArithmetic(ref c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightArithmetic(ref c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightArithmetic(ref c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightArithmetic(ref c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightArithmetic(ref c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightArithmetic(ref c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightArithmetic(ref c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightArithmetic(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightArithmetic(ref c.af.High); }),
/* 0x30 */
new SimpleOpcodeDelegate((c) => { c.Swap(ref c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.Swap(ref c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.Swap(ref c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.Swap(ref c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.Swap(ref c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.Swap(ref c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.Swap(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.Swap(ref c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightLogical(ref c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightLogical(ref c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightLogical(ref c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightLogical(ref c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightLogical(ref c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightLogical(ref c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightLogical(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightLogical(ref c.af.High); }),
/* 0x40 */
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.Low, 0); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.Low, 0); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Low, 0); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Word, 0); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.af.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.High, 1); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.Low, 1); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.High, 1); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.Low, 1); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.High, 1); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Low, 1); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Word, 1); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.af.High, 1); }),
/* 0x50 */
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.Low, 2); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.Low, 2); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Low, 2); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Word, 2); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.af.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.High, 3); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.Low, 3); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.High, 3); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.Low, 3); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.High, 3); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Low, 3); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Word, 3); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.af.High, 3); }),
/* 0x60 */
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.Low, 4); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.Low, 4); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Low, 4); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Word, 4); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.af.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.High, 5); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.Low, 5); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.High, 5); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.Low, 5); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.High, 5); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Low, 5); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Word, 5); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.af.High, 5); }),
/* 0x70 */
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.Low, 6); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.Low, 6); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Low, 6); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Word, 6); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.af.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.High, 7); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.Low, 7); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.High, 7); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.Low, 7); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.High, 7); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Low, 7); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Word, 7); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.af.High, 7); }),
/* 0x80 */
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.Low, 0); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.Low, 0); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.Low, 0); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(c.hl.Word, 0); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.af.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.High, 1); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.Low, 1); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.High, 1); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.Low, 1); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.High, 1); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.Low, 1); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(c.hl.Word, 1); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.af.High, 1); }),
/* 0x90 */
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.Low, 2); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.Low, 2); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.Low, 2); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(c.hl.Word, 2); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.af.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.High, 3); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.Low, 3); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.High, 3); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.Low, 3); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.High, 3); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.Low, 3); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(c.hl.Word, 3); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.af.High, 3); }),
/* 0xA0 */
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.Low, 4); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.Low, 4); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.Low, 4); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(c.hl.Word, 4); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.af.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.High, 5); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.Low, 5); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.High, 5); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.Low, 5); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.High, 5); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.Low, 5); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(c.hl.Word, 5); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.af.High, 5); }),
/* 0xB0 */
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.Low, 6); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.Low, 6); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.Low, 6); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(c.hl.Word, 6); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.af.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.High, 7); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.Low, 7); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.High, 7); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.Low, 7); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.High, 7); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.Low, 7); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(c.hl.Word, 7); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.af.High, 7); }),
/* 0xC0 */
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.Low, 0); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.Low, 0); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.Low, 0); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(c.hl.Word, 0); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.af.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.High, 1); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.Low, 1); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.High, 1); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.Low, 1); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.High, 1); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.Low, 1); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(c.hl.Word, 1); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.af.High, 1); }),
/* 0xD0 */
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.Low, 2); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.Low, 2); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.Low, 2); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(c.hl.Word, 2); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.af.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.High, 3); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.Low, 3); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.High, 3); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.Low, 3); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.High, 3); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.Low, 3); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(c.hl.Word, 3); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.af.High, 3); }),
/* 0xE0 */
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.Low, 4); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.Low, 4); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.Low, 4); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(c.hl.Word, 4); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.af.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.High, 5); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.Low, 5); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.High, 5); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.Low, 5); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.High, 5); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.Low, 5); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(c.hl.Word, 5); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.af.High, 5); }),
/* 0xF0 */
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.Low, 6); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.Low, 6); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.Low, 6); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(c.hl.Word, 6); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.af.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.High, 7); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.Low, 7); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.High, 7); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.Low, 7); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.High, 7); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.Low, 7); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(c.hl.Word, 7); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.af.High, 7); }),
};
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 36c6024a407a43f43bf41f1e38274ad9

View File

@ -0,0 +1,25 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Essgee.Emulation.CPU
{
public partial class SM83
{
[DebuggerDisplay("{Word}")]
[StructLayout(LayoutKind.Explicit)]
[Serializable]
public struct Register
{
[NonSerialized]
[FieldOffset(0)]
public byte Low;
[NonSerialized]
[FieldOffset(1)]
public byte High;
[FieldOffset(0)]
public ushort Word;
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e29886b06189649459149576fcb83444

View File

@ -0,0 +1,972 @@
using Essgee.Exceptions;
using Essgee.Utilities;
using System;
using System.Linq;
using static Essgee.Emulation.Utilities;
namespace Essgee.Emulation.CPU
{
public partial class SM83 : ICPU
{
[Flags]
enum Flags : byte
{
UnusedBit0 = (1 << 0), /* (0) */
UnusedBit1 = (1 << 1), /* (0) */
UnusedBit2 = (1 << 2), /* (0) */
UnusedBit3 = (1 << 3), /* (0) */
Carry = (1 << 4), /* C */
HalfCarry = (1 << 5), /* H */
Subtract = (1 << 6), /* N */
Zero = (1 << 7) /* Z */
}
[Flags]
public enum InterruptSource : byte
{
VBlank = 0,
LCDCStatus = 1,
TimerOverflow = 2,
SerialIO = 3,
Keypad = 4
}
public delegate byte MemoryReadDelegate(ushort address);
public delegate void MemoryWriteDelegate(ushort address, byte value);
public delegate void RequestInterruptDelegate(InterruptSource source);
delegate void SimpleOpcodeDelegate(SM83 c);
protected MemoryReadDelegate memoryReadDelegate;
protected MemoryWriteDelegate memoryWriteDelegate;
[StateRequired]
protected Register af, bc, de, hl;
[StateRequired]
protected ushort sp, pc;
[StateRequired]
protected bool ime, imeDelay, halt, doHaltBug;
[StateRequired]
protected byte op;
[StateRequired]
protected int currentCycles;
string logFile;
int numLogEntries;
string[] logEntries;
public SM83(MemoryReadDelegate memoryRead, MemoryWriteDelegate memoryWrite)
{
af = bc = de = hl = new Register();
memoryReadDelegate = memoryRead;
memoryWriteDelegate = memoryWrite;
if (AppEnvironment.EnableSuperSlowCPULogger)
{
logFile = @"D:\Temp\Essgee\log-lr35902.txt";
numLogEntries = 0;
logEntries = new string[2000];
}
}
public virtual void Startup()
{
Reset();
if (memoryReadDelegate == null) throw new EmulationException("SM83: Memory read method is null");
if (memoryWriteDelegate == null) throw new EmulationException("SM83: Memory write method is null");
}
public virtual void Shutdown()
{
if (AppEnvironment.EnableSuperSlowCPULogger && logEntries != null)
{
System.IO.File.AppendAllText(logFile, string.Join("", logEntries.Take(numLogEntries)));
}
//
}
public virtual void Reset()
{
af.Word = bc.Word = de.Word = hl.Word = 0;
pc = 0;
sp = 0;
ime = imeDelay = halt = doHaltBug = false;
currentCycles = 0;
}
public int Step()
{
currentCycles = 0;
/* Handle delayed interrupt enable */
if (imeDelay)
{
ime = true;
imeDelay = false;
}
/* Check interrupts */
HandleInterrupts();
if (halt)
{
/* CPU halted */
currentCycles = 4;
}
else
{
if (AppEnvironment.EnableSuperSlowCPULogger && logEntries != null)
{
string disasm = string.Format("{0} | {1} | {2} | {3}\n", DisassembleOpcode(this, pc).PadRight(48), PrintRegisters(this), PrintFlags(this), PrintInterrupt(this));
logEntries[numLogEntries++] = disasm;
if (numLogEntries >= logEntries.Length)
{
System.IO.File.AppendAllText(logFile, string.Join("", logEntries));
numLogEntries = 0;
}
}
/* Do HALT bug */
if (doHaltBug)
{
pc--;
doHaltBug = false;
}
/* Fetch and execute opcode */
op = ReadMemory8(pc++);
switch (op)
{
case 0xCB: ExecuteOpCB(); break;
default: ExecuteOpcodeNoPrefix(op); break;
}
}
return currentCycles;
}
#region Opcode Execution and Cycle Management
private void ExecuteOpcodeNoPrefix(byte op)
{
opcodesNoPrefix[op](this);
currentCycles += CycleCounts.NoPrefix[op];
}
private void ExecuteOpCB()
{
byte cbOp = ReadMemory8(pc++);
opcodesPrefixCB[cbOp](this);
currentCycles += CycleCounts.PrefixCB[cbOp];
}
#endregion
#region Helpers (Flags, etc.)
public void SetStackPointer(ushort value)
{
sp = value;
}
public void SetProgramCounter(ushort value)
{
pc = value;
}
public void SetRegisterAF(ushort value)
{
af.Word = value;
}
public void SetRegisterBC(ushort value)
{
bc.Word = value;
}
public void SetRegisterDE(ushort value)
{
de.Word = value;
}
public void SetRegisterHL(ushort value)
{
hl.Word = value;
}
private void SetFlag(Flags flags)
{
af.Low |= (byte)flags;
}
private void ClearFlag(Flags flags)
{
af.Low &= (byte)~flags;
}
private void SetClearFlagConditional(Flags flags, bool condition)
{
if (condition)
af.Low |= (byte)flags;
else
af.Low &= (byte)~flags;
}
private bool IsFlagSet(Flags flags)
{
return (((Flags)af.Low & flags) == flags);
}
#endregion
#region Interrupt, Halt and Stop State Handling
public void RequestInterrupt(InterruptSource source)
{
memoryWriteDelegate(0xFF0F, (byte)(memoryReadDelegate(0xFF0F) | (byte)(1 << (byte)source)));
}
private void HandleInterrupts()
{
var intEnable = memoryReadDelegate(0xFFFF);
var intFlags = memoryReadDelegate(0xFF0F);
if ((intEnable & intFlags) != 0)
{
LeaveHaltState();
if (ime)
{
if (ServiceInterrupt(InterruptSource.VBlank, intEnable, intFlags)) return;
if (ServiceInterrupt(InterruptSource.LCDCStatus, intEnable, intFlags)) return;
if (ServiceInterrupt(InterruptSource.TimerOverflow, intEnable, intFlags)) return;
if (ServiceInterrupt(InterruptSource.SerialIO, intEnable, intFlags)) return;
if (ServiceInterrupt(InterruptSource.Keypad, intEnable, intFlags)) return;
}
}
}
private bool ServiceInterrupt(InterruptSource intSource, byte intEnable, byte intFlags)
{
var intSourceBit = (byte)(1 << (byte)intSource);
if (((intEnable & intSourceBit) == intSourceBit) && ((intFlags & intSourceBit) == intSourceBit))
{
ime = false;
currentCycles += 20;
return RestartFromInterrupt(intSource);
}
return false;
}
protected virtual void EnterHaltState()
{
if (ime)
{
halt = true;
pc--;
}
else
{
if ((memoryReadDelegate(0xFF0F) & memoryReadDelegate(0xFFFF) & 0x1F) != 0)
doHaltBug = true;
else
halt = true;
}
}
private void LeaveHaltState()
{
if (halt)
{
halt = false;
if (ime)
pc++;
}
}
#endregion
#region Memory Access Functions
private byte ReadMemory8(ushort address)
{
return memoryReadDelegate(address);
}
private void WriteMemory8(ushort address, byte value)
{
memoryWriteDelegate(address, value);
}
private ushort ReadMemory16(ushort address)
{
return (ushort)((memoryReadDelegate((ushort)(address + 1)) << 8) | memoryReadDelegate(address));
}
private void WriteMemory16(ushort address, ushort value)
{
memoryWriteDelegate(address, (byte)(value & 0xFF));
memoryWriteDelegate((ushort)(address + 1), (byte)(value >> 8));
}
#endregion
#region Opcodes: 8-Bit Load Group
protected void LoadRegisterFromMemory8(ref byte register, ushort address, bool specialRegs)
{
LoadRegister8(ref register, ReadMemory8(address), specialRegs);
}
protected void LoadRegisterImmediate8(ref byte register, bool specialRegs)
{
LoadRegister8(ref register, ReadMemory8(pc++), specialRegs);
}
protected void LoadRegister8(ref byte register, byte value, bool specialRegs)
{
register = value;
}
protected void LoadMemory8(ushort address, byte value)
{
WriteMemory8(address, value);
}
#endregion
#region Opcodes: 16-Bit Load Group
protected void LoadRegisterImmediate16(ref ushort register)
{
LoadRegister16(ref register, ReadMemory16(pc));
pc += 2;
}
protected void LoadRegister16(ref ushort register, ushort value)
{
register = value;
}
protected void Push(Register register)
{
WriteMemory8(--sp, register.High);
WriteMemory8(--sp, register.Low);
}
protected void Pop(ref Register register)
{
register.Low = ReadMemory8(sp++);
register.High = ReadMemory8(sp++);
}
#endregion
#region Opcodes: 8-Bit Arithmetic Group
protected void Add8(byte operand, bool withCarry)
{
int operandWithCarry = (operand + (withCarry && IsFlagSet(Flags.Carry) ? 1 : 0));
int result = (af.High + operandWithCarry);
SetClearFlagConditional(Flags.Zero, ((result & 0xFF) == 0x00));
ClearFlag(Flags.Subtract);
SetClearFlagConditional(Flags.HalfCarry, (((af.High ^ result ^ operand) & 0x10) != 0));
SetClearFlagConditional(Flags.Carry, (result > 0xFF));
af.High = (byte)result;
}
protected void Subtract8(byte operand, bool withCarry)
{
int operandWithCarry = (operand + (withCarry && IsFlagSet(Flags.Carry) ? 1 : 0));
int result = (af.High - operandWithCarry);
SetClearFlagConditional(Flags.Zero, ((result & 0xFF) == 0x00));
SetFlag(Flags.Subtract);
SetClearFlagConditional(Flags.HalfCarry, (((af.High ^ result ^ operand) & 0x10) != 0));
SetClearFlagConditional(Flags.Carry, (af.High < operandWithCarry));
af.High = (byte)result;
}
protected void And8(byte operand)
{
int result = (af.High & operand);
SetClearFlagConditional(Flags.Zero, ((result & 0xFF) == 0x00));
ClearFlag(Flags.Subtract);
SetFlag(Flags.HalfCarry);
ClearFlag(Flags.Carry);
af.High = (byte)result;
}
protected void Or8(byte operand)
{
int result = (af.High | operand);
SetClearFlagConditional(Flags.Zero, ((result & 0xFF) == 0x00));
ClearFlag(Flags.Subtract);
ClearFlag(Flags.HalfCarry);
ClearFlag(Flags.Carry);
af.High = (byte)result;
}
protected void Xor8(byte operand)
{
int result = (af.High ^ operand);
SetClearFlagConditional(Flags.Zero, ((result & 0xFF) == 0x00));
ClearFlag(Flags.Subtract);
ClearFlag(Flags.HalfCarry);
ClearFlag(Flags.Carry);
af.High = (byte)result;
}
protected void Cp8(byte operand)
{
int result = (af.High - operand);
SetClearFlagConditional(Flags.Zero, ((result & 0xFF) == 0x00));
SetFlag(Flags.Subtract);
SetClearFlagConditional(Flags.HalfCarry, (((af.High ^ result ^ operand) & 0x10) != 0));
SetClearFlagConditional(Flags.Carry, (af.High < operand));
}
protected void Increment8(ref byte register)
{
byte result = (byte)(register + 1);
SetClearFlagConditional(Flags.Zero, (result == 0x00));
ClearFlag(Flags.Subtract);
SetClearFlagConditional(Flags.HalfCarry, ((register & 0x0F) == 0x0F));
// C
register = result;
}
protected void IncrementMemory8(ushort address)
{
byte value = ReadMemory8(address);
Increment8(ref value);
WriteMemory8(address, value);
}
protected void Decrement8(ref byte register)
{
byte result = (byte)(register - 1);
SetClearFlagConditional(Flags.Zero, (result == 0x00));
SetFlag(Flags.Subtract);
SetClearFlagConditional(Flags.HalfCarry, ((register & 0x0F) == 0x00));
// C
register = result;
}
protected void DecrementMemory8(ushort address)
{
byte value = ReadMemory8(address);
Decrement8(ref value);
WriteMemory8(address, value);
}
#endregion
#region Opcodes: General-Purpose Arithmetic and CPU Control Group
protected void DecimalAdjustAccumulator()
{
int value = af.High;
if (!IsFlagSet(Flags.Subtract))
{
if (IsFlagSet(Flags.HalfCarry) || ((value & 0x0F) > 9))
value += 0x06;
if (IsFlagSet(Flags.Carry) || (value > 0x9F))
value += 0x60;
}
else
{
if (IsFlagSet(Flags.HalfCarry))
value = (value - 0x06) & 0xFF;
if (IsFlagSet(Flags.Carry))
value -= 0x60;
}
ClearFlag(Flags.HalfCarry);
ClearFlag(Flags.Zero);
if ((value & 0x100) != 0) SetFlag(Flags.Carry);
value &= 0xFF;
if (value == 0) SetFlag(Flags.Zero);
af.High = (byte)value;
}
protected void Negate()
{
int result = (0 - af.High);
SetClearFlagConditional(Flags.Zero, ((result & 0xFF) == 0x00));
SetFlag(Flags.Subtract);
SetClearFlagConditional(Flags.HalfCarry, ((0 - (af.High & 0x0F)) < 0));
SetClearFlagConditional(Flags.Carry, (af.High != 0x00));
af.High = (byte)result;
}
protected void EnableInterrupts()
{
ime = false;
imeDelay = true;
}
protected void DisableInterrupts()
{
ime = false;
}
#endregion
#region Opcodes: 16-Bit Arithmetic Group
protected void Add16(ref Register dest, ushort operand)
{
int operandWithCarry = (short)operand;
int result = (dest.Word + operandWithCarry);
// Z
ClearFlag(Flags.Subtract);
SetClearFlagConditional(Flags.HalfCarry, (((dest.Word & 0x0FFF) + (operandWithCarry & 0x0FFF)) > 0x0FFF));
SetClearFlagConditional(Flags.Carry, (((dest.Word & 0xFFFF) + (operandWithCarry & 0xFFFF)) > 0xFFFF));
dest.Word = (ushort)result;
}
protected void Increment16(ref ushort register)
{
register++;
}
protected void Decrement16(ref ushort register)
{
register--;
}
#endregion
#region Opcodes: Rotate and Shift Group
protected byte RotateLeft(ushort address)
{
byte value = ReadMemory8(address);
RotateLeft(ref value);
WriteMemory8(address, value);
return value;
}
protected void RotateLeft(ref byte value)
{
bool isCarrySet = IsFlagSet(Flags.Carry);
bool isMsbSet = IsBitSet(value, 7);
value <<= 1;
if (isCarrySet) SetBit(ref value, 0);
SetClearFlagConditional(Flags.Zero, (value == 0x00));
ClearFlag(Flags.Subtract);
ClearFlag(Flags.HalfCarry);
SetClearFlagConditional(Flags.Carry, isMsbSet);
}
protected byte RotateLeftCircular(ushort address)
{
byte value = ReadMemory8(address);
RotateLeftCircular(ref value);
WriteMemory8(address, value);
return value;
}
protected void RotateLeftCircular(ref byte value)
{
bool isMsbSet = IsBitSet(value, 7);
value <<= 1;
if (isMsbSet) SetBit(ref value, 0);
SetClearFlagConditional(Flags.Zero, (value == 0x00));
ClearFlag(Flags.Subtract);
ClearFlag(Flags.HalfCarry);
SetClearFlagConditional(Flags.Carry, isMsbSet);
}
protected byte RotateRight(ushort address)
{
byte value = ReadMemory8(address);
RotateRight(ref value);
WriteMemory8(address, value);
return value;
}
protected void RotateRight(ref byte value)
{
bool isCarrySet = IsFlagSet(Flags.Carry);
bool isLsbSet = IsBitSet(value, 0);
value >>= 1;
if (isCarrySet) SetBit(ref value, 7);
SetClearFlagConditional(Flags.Zero, (value == 0x00));
ClearFlag(Flags.Subtract);
ClearFlag(Flags.HalfCarry);
SetClearFlagConditional(Flags.Carry, isLsbSet);
}
protected byte RotateRightCircular(ushort address)
{
byte value = ReadMemory8(address);
RotateRightCircular(ref value);
WriteMemory8(address, value);
return value;
}
protected void RotateRightCircular(ref byte value)
{
bool isLsbSet = IsBitSet(value, 0);
value >>= 1;
if (isLsbSet) SetBit(ref value, 7);
SetClearFlagConditional(Flags.Zero, (value == 0x00));
ClearFlag(Flags.Subtract);
ClearFlag(Flags.HalfCarry);
SetClearFlagConditional(Flags.Carry, isLsbSet);
}
protected void RotateLeftAccumulator()
{
bool isCarrySet = IsFlagSet(Flags.Carry);
bool isMsbSet = IsBitSet(af.High, 7);
af.High <<= 1;
if (isCarrySet) SetBit(ref af.High, 0);
ClearFlag(Flags.Zero);
ClearFlag(Flags.Subtract);
ClearFlag(Flags.HalfCarry);
SetClearFlagConditional(Flags.Carry, isMsbSet);
}
protected void RotateLeftAccumulatorCircular()
{
bool isMsbSet = IsBitSet(af.High, 7);
af.High <<= 1;
if (isMsbSet) SetBit(ref af.High, 0);
ClearFlag(Flags.Zero);
ClearFlag(Flags.Subtract);
ClearFlag(Flags.HalfCarry);
SetClearFlagConditional(Flags.Carry, isMsbSet);
}
protected void RotateRightAccumulator()
{
bool isCarrySet = IsFlagSet(Flags.Carry);
bool isLsbSet = IsBitSet(af.High, 0);
af.High >>= 1;
if (isCarrySet) SetBit(ref af.High, 7);
ClearFlag(Flags.Zero);
ClearFlag(Flags.Subtract);
ClearFlag(Flags.HalfCarry);
SetClearFlagConditional(Flags.Carry, isLsbSet);
}
protected void RotateRightAccumulatorCircular()
{
bool isLsbSet = IsBitSet(af.High, 0);
af.High >>= 1;
if (isLsbSet) SetBit(ref af.High, 7);
ClearFlag(Flags.Zero);
ClearFlag(Flags.Subtract);
ClearFlag(Flags.HalfCarry);
SetClearFlagConditional(Flags.Carry, isLsbSet);
}
protected byte ShiftLeftArithmetic(ushort address)
{
byte value = ReadMemory8(address);
ShiftLeftArithmetic(ref value);
WriteMemory8(address, value);
return value;
}
protected void ShiftLeftArithmetic(ref byte value)
{
bool isMsbSet = IsBitSet(value, 7);
value <<= 1;
SetClearFlagConditional(Flags.Zero, (value == 0x00));
ClearFlag(Flags.Subtract);
ClearFlag(Flags.HalfCarry);
SetClearFlagConditional(Flags.Carry, isMsbSet);
}
protected byte ShiftRightArithmetic(ushort address)
{
byte value = ReadMemory8(address);
ShiftRightArithmetic(ref value);
WriteMemory8(address, value);
return value;
}
protected void ShiftRightArithmetic(ref byte value)
{
bool isLsbSet = IsBitSet(value, 0);
bool isMsbSet = IsBitSet(value, 7);
value >>= 1;
if (isMsbSet) SetBit(ref value, 7);
SetClearFlagConditional(Flags.Zero, (value == 0x00));
ClearFlag(Flags.Subtract);
ClearFlag(Flags.HalfCarry);
SetClearFlagConditional(Flags.Carry, isLsbSet);
}
protected byte ShiftRightLogical(ushort address)
{
byte value = ReadMemory8(address);
ShiftRightLogical(ref value);
WriteMemory8(address, value);
return value;
}
protected void ShiftRightLogical(ref byte value)
{
bool isLsbSet = IsBitSet(value, 0);
value >>= 1;
SetClearFlagConditional(Flags.Zero, (value == 0x00));
ClearFlag(Flags.Subtract);
ClearFlag(Flags.HalfCarry);
SetClearFlagConditional(Flags.Carry, isLsbSet);
}
#endregion
#region Opcodes: Bit Set, Reset and Test Group
protected byte SetBit(ushort address, int bit)
{
byte value = ReadMemory8(address);
SetBit(ref value, bit);
WriteMemory8(address, value);
return value;
}
protected void SetBit(ref byte value, int bit)
{
value |= (byte)(1 << bit);
}
protected byte ResetBit(ushort address, int bit)
{
byte value = ReadMemory8(address);
ResetBit(ref value, bit);
WriteMemory8(address, value);
return value;
}
protected void ResetBit(ref byte value, int bit)
{
value &= (byte)~(1 << bit);
}
protected void TestBit(ushort address, int bit)
{
byte value = ReadMemory8(address);
TestBit(value, bit);
}
protected void TestBit(byte value, int bit)
{
bool isBitSet = ((value & (1 << bit)) != 0);
SetClearFlagConditional(Flags.Zero, !isBitSet);
ClearFlag(Flags.Subtract);
SetFlag(Flags.HalfCarry);
// C
}
#endregion
#region Opcodes: Jump Group
protected void Jump8()
{
pc += (ushort)(((sbyte)ReadMemory8(pc)) + 1);
}
protected void JumpConditional8(bool condition)
{
if (condition)
{
Jump8();
currentCycles += CycleCounts.AdditionalJumpCond8Taken;
}
else
pc++;
}
protected void JumpConditional16(bool condition)
{
if (condition)
pc = ReadMemory16(pc);
else
pc += 2;
}
#endregion
#region Opcodes: Call and Return Group
protected void Call16()
{
WriteMemory8(--sp, (byte)((pc + 2) >> 8));
WriteMemory8(--sp, (byte)((pc + 2) & 0xFF));
pc = ReadMemory16(pc);
}
protected void CallConditional16(bool condition)
{
if (condition)
{
Call16();
currentCycles += CycleCounts.AdditionalCallCondTaken;
}
else
pc += 2;
}
protected void Return()
{
pc = ReadMemory16(sp);
sp += 2;
}
protected void ReturnConditional(bool condition)
{
if (condition)
{
Return();
currentCycles += CycleCounts.AdditionalRetCondTaken;
}
}
protected void Restart(ushort address)
{
WriteMemory8(--sp, (byte)(pc >> 8));
WriteMemory8(--sp, (byte)(pc & 0xFF));
pc = address;
}
protected bool RestartFromInterrupt(InterruptSource intSource)
{
// https://github.com/Gekkio/mooneye-gb/blob/ca7ff30/tests/acceptance/interrupts/ie_push.s
var address = (ushort)(0x0040 + (byte)((int)intSource << 3));
var intSourceBit = (byte)(1 << (byte)intSource);
WriteMemory8(--sp, (byte)(pc >> 8));
var newIntEnable = memoryReadDelegate(0xFFFF);
var continueRestart = (newIntEnable & intSourceBit) != 0;
WriteMemory8(--sp, (byte)(pc & 0xFF));
if (continueRestart)
{
pc = address;
memoryWriteDelegate(0xFF0F, (byte)(memoryReadDelegate(0xFF0F) & (byte)~intSourceBit));
}
else
pc = 0x0000;
return continueRestart;
}
#endregion
#region Opcodes: SM83-specific Opcodes
protected void PopAF()
{
af.Low = (byte)(ReadMemory8(sp++) & 0xF0);
af.High = ReadMemory8(sp++);
}
protected void Swap(ushort address)
{
byte value = ReadMemory8(address);
Swap(ref value);
WriteMemory8(address, value);
}
protected void Swap(ref byte value)
{
value = (byte)((value & 0xF0) >> 4 | (value & 0x0F) << 4);
SetClearFlagConditional(Flags.Zero, (value == 0x00));
ClearFlag(Flags.Subtract);
ClearFlag(Flags.HalfCarry);
ClearFlag(Flags.Carry);
}
protected virtual void Stop()
{
pc++;
}
private void AddSPNN()
{
byte offset = ReadMemory8(pc++);
ClearFlag(Flags.Zero);
ClearFlag(Flags.Subtract);
SetClearFlagConditional(Flags.HalfCarry, (((sp & 0x0F) + (offset & 0x0F)) > 0x0F));
SetClearFlagConditional(Flags.Carry, (((sp & 0xFF) + (byte)(offset & 0xFF)) > 0xFF));
sp = (ushort)(sp + (sbyte)offset);
}
private void LoadHLSPNN()
{
byte offset = ReadMemory8(pc++);
ClearFlag(Flags.Zero);
ClearFlag(Flags.Subtract);
SetClearFlagConditional(Flags.HalfCarry, (((sp & 0x0F) + (offset & 0x0F)) > 0x0F));
SetClearFlagConditional(Flags.Carry, (((sp & 0xFF) + (byte)(offset & 0xFF)) > 0xFF));
hl.Word = (ushort)(sp + (sbyte)offset);
}
#endregion
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 18c6dc23d0278e847b2cc8483998c6fc

View File

@ -0,0 +1,57 @@
namespace Essgee.Emulation.CPU
{
public class SM83CGB : SM83
{
// TODO: better way of implementing this?
public bool IsDoubleSpeed { get; private set; }
public SM83CGB(MemoryReadDelegate memoryRead, MemoryWriteDelegate memoryWrite) : base(memoryRead, memoryWrite) { }
protected override void EnterHaltState()
{
if (ime)
{
halt = true;
pc--;
}
else
{
if ((memoryReadDelegate(0xFF0F) & memoryReadDelegate(0xFFFF) & 0x1F) != 0)
currentCycles += 8;
else
halt = true;
}
}
protected override void Stop()
{
pc++;
// Perform speed switch; get IO register value
var key1 = memoryReadDelegate(0xFF4D);
// Is speed switch pending?
if ((key1 & 0b1) != 0)
{
// Clear pending flag
key1 &= 0xFE;
if (((key1 >> 7) & 0b1) != 0)
{
// Was double speed, now normal speed
key1 &= 0x7F;
IsDoubleSpeed = false;
}
else
{
// Was normal speed, now double speed
key1 |= 0x80;
IsDoubleSpeed = true;
}
// Write register value
memoryWriteDelegate(0xFF4D, key1);
}
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: cf45a7372b4385e429895c45fe9f4db0

View File

@ -0,0 +1,95 @@
namespace Essgee.Emulation.CPU
{
public partial class Z80A
{
public static class CycleCounts
{
public const int AdditionalJumpCond8Taken = 5;
public const int AdditionalRetCondTaken = 6;
public const int AdditionalCallCondTaken = 7;
public const int AdditionalRepeatByteOps = 5;
public const int AdditionalDDFDOps = 4;
public const int AdditionalDDFDCBOps = 8;
public static readonly int[] NoPrefix = new int[]
{
4, 10, 7, 6, 4, 4, 7, 4, 4, 11, 7, 6, 4, 4, 7, 4, /* 0x00 - 0x0F */
8, 10, 7, 6, 4, 4, 7, 4, 12, 11, 7, 6, 4, 4, 7, 4, /* 0x10 - 0x1F */
7, 10, 16, 6, 4, 4, 7, 4, 7, 11, 16, 6, 4, 4, 4, 4, /* 0x20 - 0x2F */
7, 10, 13, 6, 11, 11, 10, 4, 7, 11, 13, 6, 4, 4, 7, 4, /* 0x30 - 0x3F */
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, /* 0x40 - 0x4F */
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, /* 0x50 - 0x5F */
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, /* 0x60 - 0x6F */
7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4, /* 0x70 - 0x7F */
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, /* 0x80 - 0x8F */
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, /* 0x90 - 0x9F */
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, /* 0xA0 - 0xAF */
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, /* 0xB0 - 0xBF */
5, 10, 10, 10, 10, 11, 7, 11, 5, 10, 10, 0, 10, 17, 7, 11, /* 0xC0 - 0xCF */
5, 10, 10, 11, 10, 11, 7, 11, 5, 4, 10, 11, 10, 0, 7, 11, /* 0xD0 - 0xDF */
5, 10, 10, 19, 10, 11, 7, 11, 5, 4, 10, 4, 10, 0, 7, 11, /* 0xE0 - 0xEF */
5, 10, 10, 4, 10, 11, 7, 11, 5, 6, 10, 4, 10, 0, 7, 11 /* 0xF0 - 0xFF */
};
public static readonly int[] PrefixED = new int[]
{
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* 0x00 - 0x0F */
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* 0x10 - 0x1F */
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* 0x20 - 0x2F */
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* 0x30 - 0x3F */
12, 12, 15, 20, 8, 14, 8, 9, 12, 12, 15, 20, 8, 14, 8, 9, /* 0x40 - 0x4F */
12, 12, 15, 20, 8, 14, 8, 9, 12, 12, 15, 20, 8, 14, 8, 9, /* 0x50 - 0x5F */
12, 12, 15, 20, 8, 14, 8, 18, 12, 12, 15, 20, 8, 14, 8, 18, /* 0x60 - 0x6F */
12, 12, 15, 20, 8, 14, 8, 4, 12, 12, 15, 20, 8, 14, 8, 4, /* 0x70 - 0x7F */
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* 0x80 - 0x8F */
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* 0x90 - 0x9F */
16, 16, 16, 16, 8, 8, 8, 8, 16, 16, 16, 16, 8, 8, 8, 8, /* 0xA0 - 0xAF */
16, 16, 16, 16, 8, 8, 8, 8, 16, 16, 16, 16, 8, 8, 8, 8, /* 0xB0 - 0xBF */
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* 0xC0 - 0xCF */
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* 0xD0 - 0xDF */
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* 0xE0 - 0xEF */
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 /* 0xF0 - 0xFF */
};
public static readonly int[] PrefixCB = new int[]
{
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8, /* 0x00 - 0x0F */
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8, /* 0x10 - 0x1F */
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8, /* 0x20 - 0x2F */
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8, /* 0x30 - 0x3F */
8, 8, 8, 8, 8, 8, 12, 8, 8, 8, 8, 8, 8, 8, 12, 8, /* 0x40 - 0x4F */
8, 8, 8, 8, 8, 8, 12, 8, 8, 8, 8, 8, 8, 8, 12, 8, /* 0x50 - 0x5F */
8, 8, 8, 8, 8, 8, 12, 8, 8, 8, 8, 8, 8, 8, 12, 8, /* 0x60 - 0x6F */
8, 8, 8, 8, 8, 8, 12, 8, 8, 8, 8, 8, 8, 8, 12, 8, /* 0x70 - 0x7F */
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8, /* 0x80 - 0x8F */
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8, /* 0x90 - 0x9F */
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8, /* 0xA0 - 0xAF */
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8, /* 0xB0 - 0xBF */
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8, /* 0xC0 - 0xCF */
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8, /* 0xD0 - 0xDF */
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8, /* 0xE0 - 0xEF */
8, 8, 8, 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 8, 15, 8 /* 0xF0 - 0xFF */
};
public static readonly int[] PrefixDDFD = new int[]
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, /* 0x00 - 0x0F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1F */
0, 14, 20, 10, 0, 0, 0, 0, 0, 15, 20, 10, 0, 0, 0, 0, /* 0x20 - 0x2F */
0, 0, 0, 0, 23, 23, 19, 0, 0, 15, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3F */
0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 0, /* 0x40 - 0x4F */
0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 0, /* 0x50 - 0x5F */
0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 0, /* 0x60 - 0x6F */
19, 19, 19, 19, 19, 19, 0, 19, 0, 0, 0, 0, 0, 0, 19, 0, /* 0x70 - 0x7F */
0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 0, /* 0x80 - 0x8F */
0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 0, /* 0x90 - 0x9F */
0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 0, /* 0xA0 - 0xAF */
0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 0, /* 0xB0 - 0xBF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC0 - 0xCF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD0 - 0xDF */
0, 14, 0, 23, 0, 15, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, /* 0xE0 - 0xEF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0 /* 0xF0 - 0xFF */
};
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 3c40dfcb38d98fe45a313cee0df21449

View File

@ -0,0 +1,485 @@
using System.Linq;
namespace Essgee.Emulation.CPU
{
public partial class Z80A
{
// TODO: add mnemonics for undocumented opcodes
static readonly string[] opcodeMnemonicNoPrefix = new string[]
{
"NOP", "LD BC, 0x{0:X4}", "LD (BC), A", "INC BC", "INC B", "DEC B", "LD B, 0x{0:X2}", "RLCA", /* 0x00 */
"EX AF, AF'", "ADD HL, BC", "LD A, (BC)", "DEC BC", "INC C", "DEC C", "LD C, 0x{0:X2}", "RRCA", /* 0x08 */
"DJNZ 0x{0:X2}", "LD DE, 0x{0:X4}", "LD (DE), A", "INC DE", "INC D", "DEC D", "LD D, 0x{0:X2}", "RLA", /* 0x10 */
"JR 0x{0:X2}", "ADD HL, DE", "LD A, (DE)", "DEC DE", "INC E", "DEC E", "LD E, 0x{0:X2}", "RRA", /* 0x18 */
"JR NZ, 0x{0:X2}", "LD HL, 0x{0:X4}", "LD (0x{0:X4}), HL", "INC HL", "INC H", "DEC H", "LD H, 0x{0:X2}", "DAA", /* 0x20 */
"JR Z, 0x{0:X2}", "ADD HL, HL", "LD HL, (0x{0:X4})", "DEC HL", "INC L", "DEC L", "LD L, 0x{0:X2}", "CPL", /* 0x28 */
"JR NC, 0x{0:X2}", "LD SP, 0x{0:X4}", "LD (0x{0:X4}), A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL), 0x{0:X2}", "SCF", /* 0x30 */
"JR C, 0x{0:X2}", "ADD HL, SP", "LD A, (0x{0:X4})", "DEC SP", "INC A", "DEC A", "LD A, 0x{0:X2}", "CCF", /* 0x38 */
"LD B, B", "LD B, C", "LD B, D", "LD B, E", "LD B, H", "LD B, L", "LD B, (HL)", "LD B, A", /* 0x40 */
"LD C, B", "LD C, C", "LD C, D", "LD C, E", "LD C, H", "LD C, L", "LD C, (HL)", "LD C, A", /* 0x48 */
"LD D, B", "LD D, C", "LD D, D", "LD D, E", "LD D, H", "LD D, L", "LD D, (HL)", "LD D, A", /* 0x50 */
"LD E, B", "LD E, C", "LD E, D", "LD E, E", "LD E, H", "LD E, L", "LD E, (HL)", "LD E, A", /* 0x58 */
"LD H, B", "LD H, C", "LD H, D", "LD H, E", "LD H, H", "LD H, L", "LD H, (HL)", "LD H, A", /* 0x60 */
"LD L, B", "LD L, C", "LD L, D", "LD L, E", "LD L, H", "LD L, L", "LD L, (HL)", "LD L, A", /* 0x68 */
"LD (HL), B", "LD (HL), C", "LD (HL), D", "LD (HL), E", "LD (HL), H", "LD (HL), L", "HALT", "LD (HL), A", /* 0x70 */
"LD A, B", "LD A, C", "LD A, D", "LD A, E", "LD A, H", "LD A, L", "LD A, (HL)", "LD A, A", /* 0x78 */
"ADD A, B", "ADD A, C", "ADD A, D", "ADD A, E", "ADD A, H", "ADD A, L", "ADD A, (HL)", "ADD A, A", /* 0x80 */
"ADC A, B", "ADC A, C", "ADC A, D", "ADC A, E", "ADC A, H", "ADC A, L", "ADC A, (HL)", "ADC A, A", /* 0x88 */
"SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A", /* 0x90 */
"SBC B", "SBC C", "SBC D", "SBC E", "SBC H", "SBC L", "SBC (HL)", "SBC A", /* 0x98 */
"AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A", /* 0xA0 */
"XOR B", "XOR C", "XOR D", "XOR E", "XOR H", "XOR L", "XOR (HL)", "XOR A", /* 0xA8 */
"OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A", /* 0xA0 */
"CP B", "CP C", "CP D", "CP E", "CP H", "CP L", "CP (HL)", "CP A", /* 0xB8 */
"RET NZ", "POP BC", "JP NZ, 0x{0:X4}", "JP 0x{0:X4}", "CALL NZ, 0x{0:X4}", "PUSH BC", "ADD A, 0x{0:X2}", "RST 00", /* 0xC0 */
"RET Z", "RET", "JP Z, 0x{0:X4}", string.Empty, "CALL Z, 0x{0:X4}", "CALL 0x{0:X4}", "ADC A, 0x{0:X2}", "RST 08", /* 0xC8 */
"RET NC", "POP DE", "JP NC, 0x{0:X4}", "OUT 0x{0:X2}, A", "CALL NC, 0x{0:X4}", "PUSH DE", "SUB 0x{0:X2}", "RST 10", /* 0xD0 */
"RET C", "EXX", "JP C, 0x{0:X4}", "IN A, 0x{0:X2}", "CALL C, 0x{0:X4}", string.Empty, "SBC 0x{0:X2}", "RST 18", /* 0xD8 */
"RET PO", "POP HL", "JP PO, 0x{0:X4}", "EX (SP), HL", "CALL PO, 0x{0:X4}", "PUSH HL", "AND 0x{0:X2}", "RST 20", /* 0xE0 */
"RET PE", "JP (HL)", "JP PE, 0x{0:X4}", "EX DE, HL", "CALL PE, 0x{0:X4}", string.Empty, "XOR 0x{0:X2}", "RST 28", /* 0xE8 */
"RET P", "POP AF", "JP P, 0x{0:X4}", "DI", "CALL P, 0x{0:X4}", "PUSH AF", "OR 0x{0:X2}", "RST 30", /* 0xF0 */
"RET M", "LD SP, HL", "JP M, 0x{0:X4}", "EI", "CALL M, 0x{0:X4}", string.Empty, "CP 0x{0:X2}", "RST 38" /* 0xF0 */
};
static readonly int[] opcodeLengthNoPrefix = new int[]
{
1, 3, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,
2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1,
2, 3, 3, 1, 1, 1, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1,
2, 3, 3, 1, 1, 1, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 3, 3, 3, 1, 2, 1, 1, 1, 3, -1, 3, 3, 2, 1,
1, 1, 3, 2, 3, 1, 2, 1, 1, 1, 3, 2, 3, -1, 2, 1,
1, 1, 3, 1, 3, 1, 2, 1, 1, 1, 3, 1, 3, -1, 2, 1,
1, 1, 3, 1, 3, 1, 2, 1, 1, 1, 3, 1, 3, -1, 2, 1,
};
static readonly string[] opcodeMnemonicPrefixED = new string[]
{
".DB 0xED, 0x00", ".DB 0xED, 0x01", ".DB 0xED, 0x02", ".DB 0xED, 0x03", ".DB 0xED, 0x04", ".DB 0xED, 0x05", ".DB 0xED, 0x06", ".DB 0xED, 0x07", /* 0x00 */
".DB 0xED, 0x08", ".DB 0xED, 0x09", ".DB 0xED, 0x0A", ".DB 0xED, 0x0B", ".DB 0xED, 0x0C", ".DB 0xED, 0x0D", ".DB 0xED, 0x0E", ".DB 0xED, 0x0F", /* 0x08 */
".DB 0xED, 0x10", ".DB 0xED, 0x11", ".DB 0xED, 0x12", ".DB 0xED, 0x13", ".DB 0xED, 0x14", ".DB 0xED, 0x15", ".DB 0xED, 0x16", ".DB 0xED, 0x17", /* 0x10 */
".DB 0xED, 0x18", ".DB 0xED, 0x19", ".DB 0xED, 0x1A", ".DB 0xED, 0x1B", ".DB 0xED, 0x1C", ".DB 0xED, 0x1D", ".DB 0xED, 0x1E", ".DB 0xED, 0x1F", /* 0x18 */
".DB 0xED, 0x20", ".DB 0xED, 0x21", ".DB 0xED, 0x22", ".DB 0xED, 0x23", ".DB 0xED, 0x24", ".DB 0xED, 0x25", ".DB 0xED, 0x26", ".DB 0xED, 0x27", /* 0x20 */
".DB 0xED, 0x28", ".DB 0xED, 0x29", ".DB 0xED, 0x2A", ".DB 0xED, 0x2B", ".DB 0xED, 0x2C", ".DB 0xED, 0x2D", ".DB 0xED, 0x2E", ".DB 0xED, 0x2F", /* 0x28 */
".DB 0xED, 0x30", ".DB 0xED, 0x31", ".DB 0xED, 0x32", ".DB 0xED, 0x33", ".DB 0xED, 0x34", ".DB 0xED, 0x35", ".DB 0xED, 0x36", ".DB 0xED, 0x37", /* 0x30 */
".DB 0xED, 0x38", ".DB 0xED, 0x39", ".DB 0xED, 0x3A", ".DB 0xED, 0x3B", ".DB 0xED, 0x3C", ".DB 0xED, 0x3D", ".DB 0xED, 0x3E", ".DB 0xED, 0x3F", /* 0x38 */
"IN B, (C)", "OUT (C), B", "SBC HL, BC", "LD (0x{0:X4}), BC", "NEG", "RETN", "IM 0", "LD I, A", /* 0x40 */
"IN C, (C)", "OUT (C), C", "ADC HL, BC", "LD BC, (0x{0:X4})", ".DB 0xED, 0x4C", "RETI", ".DB 0xED, 0x4E", "LD R, A", /* 0x48 */
"IN D, (C)", "OUT (C), D", "SBC HL, DE", "LD (0x{0:X4}), DE", ".DB 0xED, 0x54", ".DB 0xED, 0x55", "IM 1", "LD A, I", /* 0x50 */
"IN E, (C)", "OUT (C), E", "ADC HL, DE", "LD DE, (0x{0:X4})", ".DB 0xED, 0x5C", ".DB 0xED, 0x5D", "IM 2", "LD A, R", /* 0x58 */
"IN H, (C)", "OUT (C), H", "SBC HL, HL", ".DB 0xED, 0x63", ".DB 0xED, 0x64", ".DB 0xED, 0x65", ".DB 0xED, 0x66", "RRD", /* 0x60 */
"IN L, (C)", "OUT (C), L", "ADC HL, HL", ".DB 0xED, 0x6B", ".DB 0xED, 0x6C", ".DB 0xED, 0x6D", ".DB 0xED, 0x6E", "RLD", /* 0x68 */
".DB 0xED, 0x70", ".DB 0xED, 0x71", "SBC HL, SP", "LD (0x{0:X4}), SP", ".DB 0xED, 0x74", ".DB 0xED, 0x75", ".DB 0xED, 0x76", ".DB 0xED, 0x77", /* 0x70 */
"IN A, (C)", "OUT (C), A", "ADC HL, SP", "LD SP, (0x{0:X4})", ".DB 0xED, 0x7C", ".DB 0xED, 0x7D", ".DB 0xED, 0x7E", ".DB 0xED, 0x7F", /* 0x78 */
".DB 0xED, 0x80", ".DB 0xED, 0x81", ".DB 0xED, 0x82", ".DB 0xED, 0x83", ".DB 0xED, 0x84", ".DB 0xED, 0x85", ".DB 0xED, 0x86", ".DB 0xED, 0x87", /* 0x80 */
".DB 0xED, 0x88", ".DB 0xED, 0x89", ".DB 0xED, 0x8A", ".DB 0xED, 0x8B", ".DB 0xED, 0x8C", ".DB 0xED, 0x8D", ".DB 0xED, 0x8E", ".DB 0xED, 0x8F", /* 0x88 */
".DB 0xED, 0x90", ".DB 0xED, 0x91", ".DB 0xED, 0x92", ".DB 0xED, 0x93", ".DB 0xED, 0x94", ".DB 0xED, 0x95", ".DB 0xED, 0x96", ".DB 0xED, 0x97", /* 0x90 */
".DB 0xED, 0x98", ".DB 0xED, 0x99", ".DB 0xED, 0x9A", ".DB 0xED, 0x9B", ".DB 0xED, 0x9C", ".DB 0xED, 0x9D", ".DB 0xED, 0x9E", ".DB 0xED, 0x9F", /* 0x98 */
"LDI", "CPI", "INI", "OUTI", ".DB 0xED, 0xA4", ".DB 0xED, 0xA5", ".DB 0xED, 0xA6", ".DB 0xED, 0xA7", /* 0xA0 */
"LDD", "CPD", "IND", "OUTD", ".DB 0xED, 0xAC", ".DB 0xED, 0xAD", ".DB 0xED, 0xAE", ".DB 0xED, 0xAF", /* 0xA8 */
"LDIR", "CPIR", "INIR", "OTIR", ".DB 0xED, 0xB4", ".DB 0xED, 0xB5", ".DB 0xED, 0xB6", ".DB 0xED, 0xB7", /* 0xB0 */
"LDDR", "CPDR", "INDR", "OTDR", ".DB 0xED, 0xBC", ".DB 0xED, 0xBD", ".DB 0xED, 0xBE", ".DB 0xED, 0xBF", /* 0xB8 */
".DB 0xED, 0xC0", ".DB 0xED, 0xC1", ".DB 0xED, 0xC2", ".DB 0xED, 0xC3", ".DB 0xED, 0xC4", ".DB 0xED, 0xC5", ".DB 0xED, 0xC6", ".DB 0xED, 0xC7", /* 0xC0 */
".DB 0xED, 0xC8", ".DB 0xED, 0xC9", ".DB 0xED, 0xCA", ".DB 0xED, 0xCB", ".DB 0xED, 0xCC", ".DB 0xED, 0xCD", ".DB 0xED, 0xCE", ".DB 0xED, 0xCF", /* 0xC8 */
".DB 0xED, 0xD0", ".DB 0xED, 0xD1", ".DB 0xED, 0xD2", ".DB 0xED, 0xD3", ".DB 0xED, 0xD4", ".DB 0xED, 0xD5", ".DB 0xED, 0xD6", ".DB 0xED, 0xD7", /* 0xD0 */
".DB 0xED, 0xD8", ".DB 0xED, 0xD9", ".DB 0xED, 0xDA", ".DB 0xED, 0xDB", ".DB 0xED, 0xDC", ".DB 0xED, 0xDD", ".DB 0xED, 0xDE", ".DB 0xED, 0xDF", /* 0xD8 */
".DB 0xED, 0xE0", ".DB 0xED, 0xE1", ".DB 0xED, 0xE2", ".DB 0xED, 0xE3", ".DB 0xED, 0xE4", ".DB 0xED, 0xE5", ".DB 0xED, 0xE6", ".DB 0xED, 0xE7", /* 0xE0 */
".DB 0xED, 0xE8", ".DB 0xED, 0xE9", ".DB 0xED, 0xEA", ".DB 0xED, 0xEB", ".DB 0xED, 0xEC", ".DB 0xED, 0xED", ".DB 0xED, 0xEE", ".DB 0xED, 0xEF", /* 0xE8 */
".DB 0xED, 0xF0", ".DB 0xED, 0xF1", ".DB 0xED, 0xF2", ".DB 0xED, 0xF3", ".DB 0xED, 0xF4", ".DB 0xED, 0xF5", ".DB 0xED, 0xF6", ".DB 0xED, 0xF7", /* 0xF0 */
".DB 0xED, 0xF8", ".DB 0xED, 0xF9", ".DB 0xED, 0xFA", ".DB 0xED, 0xFB", ".DB 0xED, 0xFC", ".DB 0xED, 0xFD", ".DB 0xED, 0xFE", ".DB 0xED, 0xFF" /* 0xF8 */
};
static readonly int[] opcodeLengthPrefixED = new int[]
{
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2,
2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
};
static readonly string[] opcodeMnemonicPrefixCB = new string[]
{
"RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A", /* 0x00 */
"RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (HL)", "RRC A", /* 0x08 */
"RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A", /* 0x10 */
"RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (HL)", "RR A", /* 0x18 */
"SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A", /* 0x20 */
"SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (HL)", "SRA A", /* 0x28 */
"SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (HL)", "SLL A", /* 0x30 */
"SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A", /* 0x38 */
"BIT 0, B", "BIT 0, C", "BIT 0, D", "BIT 0, E", "BIT 0, H", "BIT 0, L", "BIT 0, (HL)", "BIT 0, A", /* 0x40 */
"BIT 1, B", "BIT 1, C", "BIT 1, D", "BIT 1, E", "BIT 1, H", "BIT 1, L", "BIT 1, (HL)", "BIT 1, A", /* 0x48 */
"BIT 2, B", "BIT 2, C", "BIT 2, D", "BIT 2, E", "BIT 2, H", "BIT 2, L", "BIT 2, (HL)", "BIT 2, A", /* 0x50 */
"BIT 3, B", "BIT 3, C", "BIT 3, D", "BIT 3, E", "BIT 3, H", "BIT 3, L", "BIT 3, (HL)", "BIT 3, A", /* 0x58 */
"BIT 4, B", "BIT 4, C", "BIT 4, D", "BIT 4, E", "BIT 4, H", "BIT 4, L", "BIT 4, (HL)", "BIT 4, A", /* 0x60 */
"BIT 5, B", "BIT 5, C", "BIT 5, D", "BIT 5, E", "BIT 5, H", "BIT 5, L", "BIT 5, (HL)", "BIT 5, A", /* 0x68 */
"BIT 6, B", "BIT 6, C", "BIT 6, D", "BIT 6, E", "BIT 6, H", "BIT 6, L", "BIT 6, (HL)", "BIT 6, A", /* 0x70 */
"BIT 7, B", "BIT 7, C", "BIT 7, D", "BIT 7, E", "BIT 7, H", "BIT 7, L", "BIT 7, (HL)", "BIT 7, A", /* 0x78 */
"RES 0, B", "RES 0, C", "RES 0, D", "RES 0, E", "RES 0, H", "RES 0, L", "RES 0, (HL)", "RES 0, A", /* 0x80 */
"RES 1, B", "RES 1, C", "RES 1, D", "RES 1, E", "RES 1, H", "RES 1, L", "RES 1, (HL)", "RES 1, A", /* 0x88 */
"RES 2, B", "RES 2, C", "RES 2, D", "RES 2, E", "RES 2, H", "RES 2, L", "RES 2, (HL)", "RES 2, A", /* 0x90 */
"RES 3, B", "RES 3, C", "RES 3, D", "RES 3, E", "RES 3, H", "RES 3, L", "RES 3, (HL)", "RES 3, A", /* 0x98 */
"RES 4, B", "RES 4, C", "RES 4, D", "RES 4, E", "RES 4, H", "RES 4, L", "RES 4, (HL)", "RES 4, A", /* 0xA0 */
"RES 5, B", "RES 5, C", "RES 5, D", "RES 5, E", "RES 5, H", "RES 5, L", "RES 5, (HL)", "RES 5, A", /* 0xA8 */
"RES 6, B", "RES 6, C", "RES 6, D", "RES 6, E", "RES 6, H", "RES 6, L", "RES 6, (HL)", "RES 6, A", /* 0xB0 */
"RES 7, B", "RES 7, C", "RES 7, D", "RES 7, E", "RES 7, H", "RES 7, L", "RES 7, (HL)", "RES 7, A", /* 0xB8 */
"SET 0, B", "SET 0, C", "SET 0, D", "SET 0, E", "SET 0, H", "SET 0, L", "SET 0, (HL)", "SET 0, A", /* 0xC0 */
"SET 1, B", "SET 1, C", "SET 1, D", "SET 1, E", "SET 1, H", "SET 1, L", "SET 1, (HL)", "SET 1, A", /* 0xC8 */
"SET 2, B", "SET 2, C", "SET 2, D", "SET 2, E", "SET 2, H", "SET 2, L", "SET 2, (HL)", "SET 2, A", /* 0xD0 */
"SET 3, B", "SET 3, C", "SET 3, D", "SET 3, E", "SET 3, H", "SET 3, L", "SET 3, (HL)", "SET 3, A", /* 0xD8 */
"SET 4, B", "SET 4, C", "SET 4, D", "SET 4, E", "SET 4, H", "SET 4, L", "SET 4, (HL)", "SET 4, A", /* 0xE0 */
"SET 5, B", "SET 5, C", "SET 5, D", "SET 5, E", "SET 5, H", "SET 5, L", "SET 5, (HL)", "SET 5, A", /* 0xE8 */
"SET 6, B", "SET 6, C", "SET 6, D", "SET 6, E", "SET 6, H", "SET 6, L", "SET 6, (HL)", "SET 6, A", /* 0xF0 */
"SET 7, B", "SET 7, C", "SET 7, D", "SET 7, E", "SET 7, H", "SET 7, L", "SET 7, (HL)", "SET 7, A" /* 0xF8 */
};
static readonly int[] opcodeLength_CB = new int[]
{
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
};
static readonly string[] opcodeMnemonicPrefixDD = new string[]
{
".DB 0xDD, 0x00", ".DB 0xDD, 0x01", ".DB 0xDD, 0x02", ".DB 0xDD, 0x03", ".DB 0xDD, 0x04", ".DB 0xDD, 0x05", ".DB 0xDD, 0x06", ".DB 0xDD, 0x07", /* 0x00 */
".DB 0xDD, 0x08", "ADD IX, BC", ".DB 0xDD, 0x0A", ".DB 0xDD, 0x0B", ".DB 0xDD, 0x0C", ".DB 0xDD, 0x0D", ".DB 0xDD, 0x0E", ".DB 0xDD, 0x0F", /* 0x08 */
".DB 0xDD, 0x10", ".DB 0xDD, 0x11", ".DB 0xDD, 0x12", ".DB 0xDD, 0x13", ".DB 0xDD, 0x14", ".DB 0xDD, 0x15", ".DB 0xDD, 0x16", ".DB 0xDD, 0x17", /* 0x10 */
".DB 0xDD, 0x18", "ADD IX, DE", ".DB 0xDD, 0x1A", ".DB 0xDD, 0x1B", ".DB 0xDD, 0x1C", ".DB 0xDD, 0x1D", ".DB 0xDD, 0x1E", ".DB 0xDD, 0x1F", /* 0x18 */
".DB 0xDD, 0x20", "LD IX, 0x{0:X4}", "LD (0x{0:X4}), IX", "INC IX", "INC IXH", "DEC IXH", "LD IXH, 0x{0:X2}", ".DB 0xDD, 0x27", /* 0x20 */
".DB 0xDD, 0x28", "ADD IX, IX", "LD IX, (0x{0:X4})", "DEC IX", "INC IXL", "DEC IXL", "LD IXL, 0x{0:X2}", ".DB 0xDD, 0x2F", /* 0x28 */
".DB 0xDD, 0x30", ".DB 0xDD, 0x31", ".DB 0xDD, 0x32", ".DB 0xDD, 0x33", "INC (IX+0x{0:X2})", "DEC (IX+0x{0:X2})", "LD (IX+0x{0:X2}), 0x{0:X2}", ".DB 0xDD, 0x37", /* 0x30 */
".DB 0xDD, 0x38", "ADD IX, SP", ".DB 0xDD, 0x3A", ".DB 0xDD, 0x3B", ".DB 0xDD, 0x3C", ".DB 0xDD, 0x3D", ".DB 0xDD, 0x3E", ".DB 0xDD, 0x3F", /* 0x38 */
".DB 0xDD, 0x40", ".DB 0xDD, 0x41", ".DB 0xDD, 0x42", ".DB 0xDD, 0x43", ".DB 0xDD, 0x44", ".DB 0xDD, 0x45", "LD B, (IX+0x{0:X2})", ".DB 0xDD, 0x47", /* 0x40 */
".DB 0xDD, 0x48", ".DB 0xDD, 0x49", ".DB 0xDD, 0x4A", ".DB 0xDD, 0x4B", ".DB 0xDD, 0x4C", ".DB 0xDD, 0x4D", "LD C, (IX+0x{0:X2})", ".DB 0xDD, 0x4F", /* 0x48 */
".DB 0xDD, 0x50", ".DB 0xDD, 0x51", ".DB 0xDD, 0x52", ".DB 0xDD, 0x53", ".DB 0xDD, 0x54", ".DB 0xDD, 0x55", "LD D, (IX+0x{0:X2})", ".DB 0xDD, 0x57", /* 0x50 */
".DB 0xDD, 0x58", ".DB 0xDD, 0x59", ".DB 0xDD, 0x5A", ".DB 0xDD, 0x5B", ".DB 0xDD, 0x5C", ".DB 0xDD, 0x5D", "LD E, (IX+0x{0:X2})", ".DB 0xDD, 0x5F", /* 0x58 */
".DB 0xDD, 0x60", ".DB 0xDD, 0x61", ".DB 0xDD, 0x62", ".DB 0xDD, 0x63", ".DB 0xDD, 0x64", ".DB 0xDD, 0x65", "LD H, (IX+0x{0:X2})", ".DB 0xDD, 0x67", /* 0x60 */
".DB 0xDD, 0x68", ".DB 0xDD, 0x69", ".DB 0xDD, 0x6A", ".DB 0xDD, 0x6B", ".DB 0xDD, 0x6C", ".DB 0xDD, 0x6D", "LD L, (IX+0x{0:X2})", ".DB 0xDD, 0x6F", /* 0x68 */
"LD (IX+0x{0:X2}), B", "LD (IX+0x{0:X2}), C", "LD (IX+0x{0:X2}), D", "LD (IX+0x{0:X2}), E", "LD (IX+0x{0:X2}), H", "LD (IX+0x{0:X2}), L", ".DB 0xDD, 0x76", "LD (IX+0x{0:X2}), A", /* 0x70 */
".DB 0xDD, 0x78", ".DB 0xDD, 0x79", ".DB 0xDD, 0x7A", ".DB 0xDD, 0x7B", ".DB 0xDD, 0x7C", ".DB 0xDD, 0x7D", "LD A, (IX+0x{0:X2})", ".DB 0xDD, 0x7F", /* 0x78 */
".DB 0xDD, 0x80", ".DB 0xDD, 0x81", ".DB 0xDD, 0x82", ".DB 0xDD, 0x83", ".DB 0xDD, 0x84", ".DB 0xDD, 0x85", "ADD A, (IX+0x{0:X2})", ".DB 0xDD, 0x87", /* 0x80 */
".DB 0xDD, 0x88", ".DB 0xDD, 0x89", ".DB 0xDD, 0x8A", ".DB 0xDD, 0x8B", ".DB 0xDD, 0x8C", ".DB 0xDD, 0x8D", "ADC A, (IX+0x{0:X2})", ".DB 0xDD, 0x8F", /* 0x88 */
".DB 0xDD, 0x90", ".DB 0xDD, 0x91", ".DB 0xDD, 0x92", ".DB 0xDD, 0x93", ".DB 0xDD, 0x94", ".DB 0xDD, 0x95", "SUB (IX+0x{0:X2})", ".DB 0xDD, 0x97", /* 0x90 */
".DB 0xDD, 0x98", ".DB 0xDD, 0x99", ".DB 0xDD, 0x9A", ".DB 0xDD, 0x9B", ".DB 0xDD, 0x9C", ".DB 0xDD, 0x9D", "SBC (IX+0x{0:X2})", ".DB 0xDD, 0x9F", /* 0x98 */
".DB 0xDD, 0xA0", ".DB 0xDD, 0xA1", ".DB 0xDD, 0xA2", ".DB 0xDD, 0xA3", ".DB 0xDD, 0xA4", ".DB 0xDD, 0xA5", "AND (IX+0x{0:X2})", ".DB 0xDD, 0xA7", /* 0xA0 */
".DB 0xDD, 0xA8", ".DB 0xDD, 0xA9", ".DB 0xDD, 0xAA", ".DB 0xDD, 0xAB", ".DB 0xDD, 0xAC", ".DB 0xDD, 0xAD", "XOR (IX+0x{0:X2})", ".DB 0xDD, 0xAF", /* 0xA8 */
".DB 0xDD, 0xB0", ".DB 0xDD, 0xB1", ".DB 0xDD, 0xB2", ".DB 0xDD, 0xB3", ".DB 0xDD, 0xB4", ".DB 0xDD, 0xB5", "OR (IX+0x{0:X2})", ".DB 0xDD, 0xB7", /* 0xB0 */
".DB 0xDD, 0xB8", ".DB 0xDD, 0xB9", ".DB 0xDD, 0xBA", ".DB 0xDD, 0xBB", ".DB 0xDD, 0xBC", ".DB 0xDD, 0xBD", "CP (IX+0x{0:X2})", ".DB 0xDD, 0xBF", /* 0xB8 */
".DB 0xDD, 0xC0", ".DB 0xDD, 0xC1", ".DB 0xDD, 0xC2", ".DB 0xDD, 0xC3", ".DB 0xDD, 0xC4", ".DB 0xDD, 0xC5", ".DB 0xDD, 0xC6", ".DB 0xDD, 0xC7", /* 0xC0 */
".DB 0xDD, 0xC8", ".DB 0xDD, 0xC9", ".DB 0xDD, 0xCA", string.Empty, ".DB 0xDD, 0xCC", ".DB 0xDD, 0xCD", ".DB 0xDD, 0xCE", ".DB 0xDD, 0xCF", /* 0xC8 */
".DB 0xDD, 0xD0", ".DB 0xDD, 0xD1", ".DB 0xDD, 0xD2", ".DB 0xDD, 0xD3", ".DB 0xDD, 0xD4", ".DB 0xDD, 0xD5", ".DB 0xDD, 0xD6", ".DB 0xDD, 0xD7", /* 0xD0 */
".DB 0xDD, 0xD8", ".DB 0xDD, 0xD9", ".DB 0xDD, 0xDA", ".DB 0xDD, 0xDB", ".DB 0xDD, 0xDC", ".DB 0xDD, 0xDD", ".DB 0xDD, 0xDE", ".DB 0xDD, 0xDF", /* 0xD8 */
".DB 0xED, 0xE0", "POP IX", ".DB 0xED, 0xE2", "EX (SP), IX", ".DB 0xED, 0xE4", "PUSH IX", ".DB 0xED, 0xE6", ".DB 0xED, 0xE7", /* 0xE0 */
".DB 0xED, 0xE8", "JP (IX)", ".DB 0xED, 0xEA", ".DB 0xED, 0xEB", ".DB 0xED, 0xEC", ".DB 0xED, 0xED", ".DB 0xED, 0xEE", ".DB 0xED, 0xEF", /* 0xE8 */
".DB 0xFD, 0xF0", ".DB 0xFD, 0xF1", ".DB 0xFD, 0xF2", ".DB 0xFD, 0xF3", ".DB 0xFD, 0xF4", ".DB 0xFD, 0xF5", ".DB 0xFD, 0xF6", ".DB 0xFD, 0xF7", /* 0xF0 */
".DB 0xFD, 0xF8", "LD SP, IX", ".DB 0xFD, 0xFA", ".DB 0xFD, 0xFB", ".DB 0xFD, 0xFC", ".DB 0xFD, 0xFD", ".DB 0xFD, 0xFE", ".DB 0xFD, 0xFF" /* 0xF8 */
};
static readonly string[] opcodeMnemonicPrefixFD = new string[]
{
".DB 0xFD, 0x00", ".DB 0xFD, 0x01", ".DB 0xFD, 0x02", ".DB 0xFD, 0x03", ".DB 0xFD, 0x04", ".DB 0xFD, 0x05", ".DB 0xFD, 0x06", ".DB 0xFD, 0x07", /* 0x00 */
".DB 0xFD, 0x08", "ADD IY, BC", ".DB 0xFD, 0x0A", ".DB 0xFD, 0x0B", ".DB 0xFD, 0x0C", ".DB 0xFD, 0x0D", ".DB 0xFD, 0x0E", ".DB 0xFD, 0x0F", /* 0x08 */
".DB 0xFD, 0x10", ".DB 0xFD, 0x11", ".DB 0xFD, 0x12", ".DB 0xFD, 0x13", ".DB 0xFD, 0x14", ".DB 0xFD, 0x15", ".DB 0xFD, 0x16", ".DB 0xFD, 0x17", /* 0x10 */
".DB 0xFD, 0x18", "ADD IY, DE", ".DB 0xFD, 0x1A", ".DB 0xFD, 0x1B", ".DB 0xFD, 0x1C", ".DB 0xFD, 0x1D", ".DB 0xFD, 0x1E", ".DB 0xFD, 0x1F", /* 0x18 */
".DB 0xFD, 0x20", "LD IY, 0x{0:X4}", "LD (0x{0:X4}), IY", "INC IY", ".DB 0xFD, 0x24", ".DB 0xFD, 0x25", ".DB 0xFD, 0x26", ".DB 0xFD, 0x27", /* 0x20 */
".DB 0xFD, 0x28", "ADD IY, IY", "LD IY, (0x{0:X4})", "DEC IY", ".DB 0xFD, 0x2C", ".DB 0xFD, 0x2D", ".DB 0xFD, 0x2E", ".DB 0xFD, 0x2F", /* 0x28 */
".DB 0xFD, 0x30", ".DB 0xFD, 0x31", ".DB 0xFD, 0x32", ".DB 0xFD, 0x33", "INC (IY+0x{0:X2})", "DEC (IY+0x{0:X2})", "LD (IY+0x{0:X2}), 0x{0:X2}", ".DB 0xFD, 0x37", /* 0x30 */
".DB 0xFD, 0x38", "ADD IY, SP", ".DB 0xFD, 0x3A", ".DB 0xFD, 0x3B", ".DB 0xFD, 0x3C", ".DB 0xFD, 0x3D", ".DB 0xFD, 0x3E", ".DB 0xFD, 0x3F", /* 0x38 */
".DB 0xFD, 0x40", ".DB 0xFD, 0x41", ".DB 0xFD, 0x42", ".DB 0xFD, 0x43", ".DB 0xFD, 0x44", ".DB 0xFD, 0x45", "LD B, (IY+0x{0:X2})", ".DB 0xFD, 0x47", /* 0x40 */
".DB 0xFD, 0x48", ".DB 0xFD, 0x49", ".DB 0xFD, 0x4A", ".DB 0xFD, 0x4B", ".DB 0xFD, 0x4C", ".DB 0xFD, 0x4D", "LD C, (IY+0x{0:X2})", ".DB 0xFD, 0x4F", /* 0x48 */
".DB 0xFD, 0x50", ".DB 0xFD, 0x51", ".DB 0xFD, 0x52", ".DB 0xFD, 0x53", ".DB 0xFD, 0x54", ".DB 0xFD, 0x55", "LD D, (IY+0x{0:X2})", ".DB 0xFD, 0x57", /* 0x50 */
".DB 0xFD, 0x58", ".DB 0xFD, 0x59", ".DB 0xFD, 0x5A", ".DB 0xFD, 0x5B", ".DB 0xFD, 0x5C", ".DB 0xFD, 0x5D", "LD E, (IY+0x{0:X2})", ".DB 0xFD, 0x5F", /* 0x58 */
".DB 0xFD, 0x60", ".DB 0xFD, 0x61", ".DB 0xFD, 0x62", ".DB 0xFD, 0x63", ".DB 0xFD, 0x64", ".DB 0xFD, 0x65", "LD H, (IY+0x{0:X2})", ".DB 0xFD, 0x67", /* 0x60 */
".DB 0xFD, 0x68", ".DB 0xFD, 0x69", ".DB 0xFD, 0x6A", ".DB 0xFD, 0x6B", ".DB 0xFD, 0x6C", ".DB 0xFD, 0x6D", "LD L, (IY+0x{0:X2})", ".DB 0xFD, 0x6F", /* 0x68 */
"LD (IY+0x{0:X2}), B", "LD (IY+0x{0:X2}), C", "LD (IY+0x{0:X2}), D", "LD (IY+0x{0:X2}), E", "LD (IY+0x{0:X2}), H", "LD (IY+0x{0:X2}), L", ".DB 0xFD, 0x76", "LD (IY+0x{0:X2}), A", /* 0x70 */
".DB 0xFD, 0x78", ".DB 0xFD, 0x79", ".DB 0xFD, 0x7A", ".DB 0xFD, 0x7B", ".DB 0xFD, 0x7C", ".DB 0xFD, 0x7D", "LD A, (IY+0x{0:X2})", ".DB 0xFD, 0x7F", /* 0x78 */
".DB 0xFD, 0x80", ".DB 0xFD, 0x81", ".DB 0xFD, 0x82", ".DB 0xFD, 0x83", ".DB 0xFD, 0x84", ".DB 0xFD, 0x85", "ADD A, (IY+0x{0:X2})", ".DB 0xFD, 0x87", /* 0x80 */
".DB 0xFD, 0x88", ".DB 0xFD, 0x89", ".DB 0xFD, 0x8A", ".DB 0xFD, 0x8B", ".DB 0xFD, 0x8C", ".DB 0xFD, 0x8D", "ADC A, (IY+0x{0:X2})", ".DB 0xFD, 0x8F", /* 0x88 */
".DB 0xFD, 0x90", ".DB 0xFD, 0x91", ".DB 0xFD, 0x92", ".DB 0xFD, 0x93", ".DB 0xFD, 0x94", ".DB 0xFD, 0x95", "SUB (IY+0x{0:X2})", ".DB 0xFD, 0x97", /* 0x90 */
".DB 0xFD, 0x98", ".DB 0xFD, 0x99", ".DB 0xFD, 0x9A", ".DB 0xFD, 0x9B", ".DB 0xFD, 0x9C", ".DB 0xFD, 0x9D", "SBC (IY+0x{0:X2})", ".DB 0xFD, 0x9F", /* 0x98 */
".DB 0xFD, 0xA0", ".DB 0xFD, 0xA1", ".DB 0xFD, 0xA2", ".DB 0xFD, 0xA3", ".DB 0xFD, 0xA4", ".DB 0xFD, 0xA5", "AND (IY+0x{0:X2})", ".DB 0xFD, 0xA7", /* 0xA0 */
".DB 0xFD, 0xA8", ".DB 0xFD, 0xA9", ".DB 0xFD, 0xAA", ".DB 0xFD, 0xAB", ".DB 0xFD, 0xAC", ".DB 0xFD, 0xAD", "XOR (IY+0x{0:X2})", ".DB 0xFD, 0xAF", /* 0xA8 */
".DB 0xFD, 0xB0", ".DB 0xFD, 0xB1", ".DB 0xFD, 0xB2", ".DB 0xFD, 0xB3", ".DB 0xFD, 0xB4", ".DB 0xFD, 0xB5", "OR (IY+0x{0:X2})", ".DB 0xFD, 0xB7", /* 0xB0 */
".DB 0xFD, 0xB8", ".DB 0xFD, 0xB9", ".DB 0xFD, 0xBA", ".DB 0xFD, 0xBB", ".DB 0xFD, 0xBC", ".DB 0xFD, 0xBD", "CP (IY+0x{0:X2})", ".DB 0xFD, 0xBF", /* 0xB8 */
".DB 0xFD, 0xC0", ".DB 0xFD, 0xC1", ".DB 0xFD, 0xC2", ".DB 0xFD, 0xC3", ".DB 0xFD, 0xC4", ".DB 0xFD, 0xC5", ".DB 0xFD, 0xC6", ".DB 0xFD, 0xC7", /* 0xC0 */
".DB 0xFD, 0xC8", ".DB 0xFD, 0xC9", ".DB 0xFD, 0xCA", string.Empty, ".DB 0xFD, 0xCC", ".DB 0xFD, 0xCD", ".DB 0xFD, 0xCE", ".DB 0xFD, 0xCF", /* 0xC8 */
".DB 0xFD, 0xD0", ".DB 0xFD, 0xD1", ".DB 0xFD, 0xD2", ".DB 0xFD, 0xD3", ".DB 0xFD, 0xD4", ".DB 0xFD, 0xD5", ".DB 0xFD, 0xD6", ".DB 0xFD, 0xD7", /* 0xD0 */
".DB 0xFD, 0xD8", ".DB 0xFD, 0xD9", ".DB 0xFD, 0xDA", ".DB 0xFD, 0xDB", ".DB 0xFD, 0xDC", ".DB 0xFD, 0xFD", ".DB 0xFD, 0xDE", ".DB 0xFD, 0xDF", /* 0xD8 */
".DB 0xED, 0xE0", "POP IY", ".DB 0xED, 0xE2", "EX (SP), IY", ".DB 0xED, 0xE4", "PUSH IY", ".DB 0xED, 0xE6", ".DB 0xED, 0xE7", /* 0xE0 */
".DB 0xED, 0xE8", "JP (IY)", ".DB 0xED, 0xEA", ".DB 0xED, 0xEB", ".DB 0xED, 0xEC", ".DB 0xED, 0xED", ".DB 0xED, 0xEE", ".DB 0xED, 0xEF", /* 0xE8 */
".DB 0xFD, 0xF0", ".DB 0xFD, 0xF1", ".DB 0xFD, 0xF2", ".DB 0xFD, 0xF3", ".DB 0xFD, 0xF4", ".DB 0xFD, 0xF5", ".DB 0xFD, 0xF6", ".DB 0xFD, 0xF7", /* 0xF0 */
".DB 0xFD, 0xF8", "LD SP, IY", ".DB 0xFD, 0xFA", ".DB 0xFD, 0xFB", ".DB 0xFD, 0xFC", ".DB 0xFD, 0xFD", ".DB 0xFD, 0xFE", ".DB 0xFD, 0xFF" /* 0xF8 */
};
static readonly string[] opcodeMnemonicPrefixDDCB = new string[]
{
".DB 0xDD, 0xCB, 0x00", ".DB 0xDD, 0xCB, 0x01", ".DB 0xDD, 0xCB, 0x02", ".DB 0xDD, 0xCB, 0x03", ".DB 0xDD, 0xCB, 0x04", ".DB 0xDD, 0xCB, 0x05", "RLC (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0x07", /* 0x00 */
".DB 0xDD, 0xCB, 0x08", ".DB 0xDD, 0xCB, 0x09", ".DB 0xDD, 0xCB, 0x0A", ".DB 0xDD, 0xCB, 0x0B", ".DB 0xDD, 0xCB, 0x0C", ".DB 0xDD, 0xCB, 0x0D", "RRC (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0x0F", /* 0x08 */
".DB 0xDD, 0xCB, 0x10", ".DB 0xDD, 0xCB, 0x11", ".DB 0xDD, 0xCB, 0x12", ".DB 0xDD, 0xCB, 0x13", ".DB 0xDD, 0xCB, 0x14", ".DB 0xDD, 0xCB, 0x15", "RL (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0x17", /* 0x10 */
".DB 0xDD, 0xCB, 0x18", ".DB 0xDD, 0xCB, 0x19", ".DB 0xDD, 0xCB, 0x1A", ".DB 0xDD, 0xCB, 0x1B", ".DB 0xDD, 0xCB, 0x1C", ".DB 0xDD, 0xCB, 0x1D", "RR (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0x1F", /* 0x18 */
".DB 0xDD, 0xCB, 0x20", ".DB 0xDD, 0xCB, 0x21", ".DB 0xDD, 0xCB, 0x22", ".DB 0xDD, 0xCB, 0x23", ".DB 0xDD, 0xCB, 0x24", ".DB 0xDD, 0xCB, 0x25", "SLA (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0x27", /* 0x20 */
".DB 0xDD, 0xCB, 0x28", ".DB 0xDD, 0xCB, 0x29", ".DB 0xDD, 0xCB, 0x2A", ".DB 0xDD, 0xCB, 0x2B", ".DB 0xDD, 0xCB, 0x2C", ".DB 0xDD, 0xCB, 0x2D", "SRA (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0x2F", /* 0x28 */
".DB 0xDD, 0xCB, 0x30", ".DB 0xDD, 0xCB, 0x31", ".DB 0xDD, 0xCB, 0x32", ".DB 0xDD, 0xCB, 0x33", ".DB 0xDD, 0xCB, 0x34", ".DB 0xDD, 0xCB, 0x35", "SLL (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0x37", /* 0x30 */
".DB 0xDD, 0xCB, 0x38", ".DB 0xDD, 0xCB, 0x39", ".DB 0xDD, 0xCB, 0x3A", ".DB 0xDD, 0xCB, 0x3B", ".DB 0xDD, 0xCB, 0x3C", ".DB 0xDD, 0xCB, 0x3D", "SRL (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0x3F", /* 0x38 */
".DB 0xDD, 0xCB, 0x40", ".DB 0xDD, 0xCB, 0x41", ".DB 0xDD, 0xCB, 0x42", ".DB 0xDD, 0xCB, 0x43", ".DB 0xDD, 0xCB, 0x44", ".DB 0xDD, 0xCB, 0x45", "BIT 0, (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0x47", /* 0x40 */
".DB 0xDD, 0xCB, 0x48", ".DB 0xDD, 0xCB, 0x49", ".DB 0xDD, 0xCB, 0x4A", ".DB 0xDD, 0xCB, 0x4B", ".DB 0xDD, 0xCB, 0x4C", ".DB 0xDD, 0xCB, 0x4D", "BIT 1, (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0x4F", /* 0x48 */
".DB 0xDD, 0xCB, 0x50", ".DB 0xDD, 0xCB, 0x51", ".DB 0xDD, 0xCB, 0x52", ".DB 0xDD, 0xCB, 0x53", ".DB 0xDD, 0xCB, 0x54", ".DB 0xDD, 0xCB, 0x55", "BIT 2, (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0x57", /* 0x50 */
".DB 0xDD, 0xCB, 0x58", ".DB 0xDD, 0xCB, 0x59", ".DB 0xDD, 0xCB, 0x5A", ".DB 0xDD, 0xCB, 0x5B", ".DB 0xDD, 0xCB, 0x5C", ".DB 0xDD, 0xCB, 0x5D", "BIT 3, (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0x5F", /* 0x58 */
".DB 0xDD, 0xCB, 0x60", ".DB 0xDD, 0xCB, 0x61", ".DB 0xDD, 0xCB, 0x62", ".DB 0xDD, 0xCB, 0x63", ".DB 0xDD, 0xCB, 0x64", ".DB 0xDD, 0xCB, 0x65", "BIT 4, (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0x67", /* 0x60 */
".DB 0xDD, 0xCB, 0x68", ".DB 0xDD, 0xCB, 0x69", ".DB 0xDD, 0xCB, 0x6A", ".DB 0xDD, 0xCB, 0x6B", ".DB 0xDD, 0xCB, 0x6C", ".DB 0xDD, 0xCB, 0x6D", "BIT 5, (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0x6F", /* 0x68 */
".DB 0xDD, 0xCB, 0x70", ".DB 0xDD, 0xCB, 0x71", ".DB 0xDD, 0xCB, 0x72", ".DB 0xDD, 0xCB, 0x73", ".DB 0xDD, 0xCB, 0x74", ".DB 0xDD, 0xCB, 0x75", "BIT 6, (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0x77", /* 0x70 */
".DB 0xDD, 0xCB, 0x78", ".DB 0xDD, 0xCB, 0x79", ".DB 0xDD, 0xCB, 0x7A", ".DB 0xDD, 0xCB, 0x7B", ".DB 0xDD, 0xCB, 0x7C", ".DB 0xDD, 0xCB, 0x7D", "BIT 7, (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0x7F", /* 0x78 */
".DB 0xDD, 0xCB, 0x80", ".DB 0xDD, 0xCB, 0x81", ".DB 0xDD, 0xCB, 0x82", ".DB 0xDD, 0xCB, 0x83", ".DB 0xDD, 0xCB, 0x84", ".DB 0xDD, 0xCB, 0x85", "RES 0, (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0x87", /* 0x80 */
".DB 0xDD, 0xCB, 0x88", ".DB 0xDD, 0xCB, 0x89", ".DB 0xDD, 0xCB, 0x8A", ".DB 0xDD, 0xCB, 0x8B", ".DB 0xDD, 0xCB, 0x8C", ".DB 0xDD, 0xCB, 0x8D", "RES 1, (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0x8F", /* 0x88 */
".DB 0xDD, 0xCB, 0x90", ".DB 0xDD, 0xCB, 0x91", ".DB 0xDD, 0xCB, 0x92", ".DB 0xDD, 0xCB, 0x93", ".DB 0xDD, 0xCB, 0x94", ".DB 0xDD, 0xCB, 0x95", "RES 2, (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0x97", /* 0x90 */
".DB 0xDD, 0xCB, 0x98", ".DB 0xDD, 0xCB, 0x99", ".DB 0xDD, 0xCB, 0x9A", ".DB 0xDD, 0xCB, 0x9B", ".DB 0xDD, 0xCB, 0x9C", ".DB 0xDD, 0xCB, 0x9D", "RES 3, (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0x9F", /* 0x98 */
".DB 0xDD, 0xCB, 0xA0", ".DB 0xDD, 0xCB, 0xA1", ".DB 0xDD, 0xCB, 0xA2", ".DB 0xDD, 0xCB, 0xA3", ".DB 0xDD, 0xCB, 0xA4", ".DB 0xDD, 0xCB, 0xA5", "RES 4, (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0xA7", /* 0xA0 */
".DB 0xDD, 0xCB, 0xA8", ".DB 0xDD, 0xCB, 0xA9", ".DB 0xDD, 0xCB, 0xAA", ".DB 0xDD, 0xCB, 0xAB", ".DB 0xDD, 0xCB, 0xAC", ".DB 0xDD, 0xCB, 0xAD", "RES 5, (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0xAF", /* 0xA8 */
".DB 0xDD, 0xCB, 0xB0", ".DB 0xDD, 0xCB, 0xB1", ".DB 0xDD, 0xCB, 0xB2", ".DB 0xDD, 0xCB, 0xB3", ".DB 0xDD, 0xCB, 0xB4", ".DB 0xDD, 0xCB, 0xB5", "RES 6, (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0xB7", /* 0xB0 */
".DB 0xDD, 0xCB, 0xB8", ".DB 0xDD, 0xCB, 0xB9", ".DB 0xDD, 0xCB, 0xBA", ".DB 0xDD, 0xCB, 0xBB", ".DB 0xDD, 0xCB, 0xBC", ".DB 0xDD, 0xCB, 0xBD", "RES 7, (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0xBF", /* 0xB8 */
".DB 0xDD, 0xCB, 0xC0", ".DB 0xDD, 0xCB, 0xC1", ".DB 0xDD, 0xCB, 0xC2", ".DB 0xDD, 0xCB, 0xC3", ".DB 0xDD, 0xCB, 0xC4", ".DB 0xDD, 0xCB, 0xC5", "SET 0, (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0xC7", /* 0xC0 */
".DB 0xDD, 0xCB, 0xC8", ".DB 0xDD, 0xCB, 0xC9", ".DB 0xDD, 0xCB, 0xCA", ".DB 0xDD, 0xCB, 0xCB", ".DB 0xDD, 0xCB, 0xCC", ".DB 0xDD, 0xCB, 0xCD", "SET 1, (IX+0x{0:X2})", ".DB 0xDD, 0xCB, 0xCF", /* 0xC8 */
".DB 0xDD, 0xDB, 0xD0", ".DB 0xDD, 0xDB, 0xD1", ".DB 0xDD, 0xDB, 0xD2", ".DB 0xDD, 0xDB, 0xD3", ".DB 0xDD, 0xDB, 0xD4", ".DB 0xDD, 0xDB, 0xD5", "SET 2, (IX+0x{0:X2})", ".DB 0xDD, 0xDB, 0xD7", /* 0xD0 */
".DB 0xDD, 0xDB, 0xD8", ".DB 0xDD, 0xDB, 0xD9", ".DB 0xDD, 0xDB, 0xDA", ".DB 0xDD, 0xDB, 0xDB", ".DB 0xDD, 0xDB, 0xDC", ".DB 0xDD, 0xDB, 0xDD", "SET 3, (IX+0x{0:X2})", ".DB 0xDD, 0xDB, 0xDF", /* 0xD8 */
".DB 0xDD, 0xEB, 0xE0", ".DB 0xDD, 0xEB, 0xE1", ".DB 0xDD, 0xEB, 0xE2", ".DB 0xDD, 0xEB, 0xE3", ".DB 0xDD, 0xEB, 0xE4", ".DB 0xDD, 0xEB, 0xE5", "SET 4, (IX+0x{0:X2})", ".DB 0xDD, 0xEB, 0xE7", /* 0xE0 */
".DB 0xDD, 0xEB, 0xE8", ".DB 0xDD, 0xEB, 0xE9", ".DB 0xDD, 0xEB, 0xEA", ".DB 0xDD, 0xEB, 0xEB", ".DB 0xDD, 0xEB, 0xEC", ".DB 0xDD, 0xEB, 0xED", "SET 5, (IX+0x{0:X2})", ".DB 0xDD, 0xEB, 0xEF", /* 0xE8 */
".DB 0xDD, 0xFB, 0xF0", ".DB 0xDD, 0xFB, 0xF1", ".DB 0xDD, 0xFB, 0xF2", ".DB 0xDD, 0xFB, 0xF3", ".DB 0xDD, 0xFB, 0xF4", ".DB 0xDD, 0xFB, 0xF5", "SET 6, (IX+0x{0:X2})", ".DB 0xDD, 0xFB, 0xF7", /* 0xF0 */
".DB 0xDD, 0xFB, 0xF8", ".DB 0xDD, 0xFB, 0xF9", ".DB 0xDD, 0xFB, 0xFA", ".DB 0xDD, 0xFB, 0xFB", ".DB 0xDD, 0xFB, 0xFC", ".DB 0xDD, 0xFB, 0xFD", "SET 7, (IX+0x{0:X2})", ".DB 0xDD, 0xFB, 0xFF" /* 0xF8 */
};
static readonly string[] opcodeMnemonicPrefixFDCB = new string[]
{
".DB 0xFD, 0xCB, 0x00", ".DB 0xFD, 0xCB, 0x01", ".DB 0xFD, 0xCB, 0x02", ".DB 0xFD, 0xCB, 0x03", ".DB 0xFD, 0xCB, 0x04", ".DB 0xFD, 0xCB, 0x05", "RLC (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0x07", /* 0x00 */
".DB 0xFD, 0xCB, 0x08", ".DB 0xFD, 0xCB, 0x09", ".DB 0xFD, 0xCB, 0x0A", ".DB 0xFD, 0xCB, 0x0B", ".DB 0xFD, 0xCB, 0x0C", ".DB 0xFD, 0xCB, 0x0D", "RRC (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0x0F", /* 0x08 */
".DB 0xFD, 0xCB, 0x10", ".DB 0xFD, 0xCB, 0x11", ".DB 0xFD, 0xCB, 0x12", ".DB 0xFD, 0xCB, 0x13", ".DB 0xFD, 0xCB, 0x14", ".DB 0xFD, 0xCB, 0x15", "RL (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0x17", /* 0x10 */
".DB 0xFD, 0xCB, 0x18", ".DB 0xFD, 0xCB, 0x19", ".DB 0xFD, 0xCB, 0x1A", ".DB 0xFD, 0xCB, 0x1B", ".DB 0xFD, 0xCB, 0x1C", ".DB 0xFD, 0xCB, 0x1D", "RR (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0x1F", /* 0x18 */
".DB 0xFD, 0xCB, 0x20", ".DB 0xFD, 0xCB, 0x21", ".DB 0xFD, 0xCB, 0x22", ".DB 0xFD, 0xCB, 0x23", ".DB 0xFD, 0xCB, 0x24", ".DB 0xFD, 0xCB, 0x25", "SLA (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0x27", /* 0x20 */
".DB 0xFD, 0xCB, 0x28", ".DB 0xFD, 0xCB, 0x29", ".DB 0xFD, 0xCB, 0x2A", ".DB 0xFD, 0xCB, 0x2B", ".DB 0xFD, 0xCB, 0x2C", ".DB 0xFD, 0xCB, 0x2D", "SRA (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0x2F", /* 0x28 */
".DB 0xFD, 0xCB, 0x30", ".DB 0xFD, 0xCB, 0x31", ".DB 0xFD, 0xCB, 0x32", ".DB 0xFD, 0xCB, 0x33", ".DB 0xFD, 0xCB, 0x34", ".DB 0xFD, 0xCB, 0x35", ".DB 0xFD, 0xCB, 0x36", ".DB 0xFD, 0xCB, 0x37", /* 0x30 */
".DB 0xFD, 0xCB, 0x38", ".DB 0xFD, 0xCB, 0x39", ".DB 0xFD, 0xCB, 0x3A", ".DB 0xFD, 0xCB, 0x3B", ".DB 0xFD, 0xCB, 0x3C", ".DB 0xFD, 0xCB, 0x3D", "SRL (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0x3F", /* 0x38 */
".DB 0xFD, 0xCB, 0x40", ".DB 0xFD, 0xCB, 0x41", ".DB 0xFD, 0xCB, 0x42", ".DB 0xFD, 0xCB, 0x43", ".DB 0xFD, 0xCB, 0x44", ".DB 0xFD, 0xCB, 0x45", "BIT 0, (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0x47", /* 0x40 */
".DB 0xFD, 0xCB, 0x48", ".DB 0xFD, 0xCB, 0x49", ".DB 0xFD, 0xCB, 0x4A", ".DB 0xFD, 0xCB, 0x4B", ".DB 0xFD, 0xCB, 0x4C", ".DB 0xFD, 0xCB, 0x4D", "BIT 1, (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0x4F", /* 0x48 */
".DB 0xFD, 0xCB, 0x50", ".DB 0xFD, 0xCB, 0x51", ".DB 0xFD, 0xCB, 0x52", ".DB 0xFD, 0xCB, 0x53", ".DB 0xFD, 0xCB, 0x54", ".DB 0xFD, 0xCB, 0x55", "BIT 2, (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0x57", /* 0x50 */
".DB 0xFD, 0xCB, 0x58", ".DB 0xFD, 0xCB, 0x59", ".DB 0xFD, 0xCB, 0x5A", ".DB 0xFD, 0xCB, 0x5B", ".DB 0xFD, 0xCB, 0x5C", ".DB 0xFD, 0xCB, 0x5D", "BIT 3, (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0x5F", /* 0x58 */
".DB 0xFD, 0xCB, 0x60", ".DB 0xFD, 0xCB, 0x61", ".DB 0xFD, 0xCB, 0x62", ".DB 0xFD, 0xCB, 0x63", ".DB 0xFD, 0xCB, 0x64", ".DB 0xFD, 0xCB, 0x65", "BIT 4, (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0x67", /* 0x60 */
".DB 0xFD, 0xCB, 0x68", ".DB 0xFD, 0xCB, 0x69", ".DB 0xFD, 0xCB, 0x6A", ".DB 0xFD, 0xCB, 0x6B", ".DB 0xFD, 0xCB, 0x6C", ".DB 0xFD, 0xCB, 0x6D", "BIT 5, (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0x6F", /* 0x68 */
".DB 0xFD, 0xCB, 0x70", ".DB 0xFD, 0xCB, 0x71", ".DB 0xFD, 0xCB, 0x72", ".DB 0xFD, 0xCB, 0x73", ".DB 0xFD, 0xCB, 0x74", ".DB 0xFD, 0xCB, 0x75", "BIT 6, (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0x77", /* 0x70 */
".DB 0xFD, 0xCB, 0x78", ".DB 0xFD, 0xCB, 0x79", ".DB 0xFD, 0xCB, 0x7A", ".DB 0xFD, 0xCB, 0x7B", ".DB 0xFD, 0xCB, 0x7C", ".DB 0xFD, 0xCB, 0x7D", "BIT 7, (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0x7F", /* 0x78 */
".DB 0xFD, 0xCB, 0x80", ".DB 0xFD, 0xCB, 0x81", ".DB 0xFD, 0xCB, 0x82", ".DB 0xFD, 0xCB, 0x83", ".DB 0xFD, 0xCB, 0x84", ".DB 0xFD, 0xCB, 0x85", "RES 0, (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0x87", /* 0x80 */
".DB 0xFD, 0xCB, 0x88", ".DB 0xFD, 0xCB, 0x89", ".DB 0xFD, 0xCB, 0x8A", ".DB 0xFD, 0xCB, 0x8B", ".DB 0xFD, 0xCB, 0x8C", ".DB 0xFD, 0xCB, 0x8D", "RES 1, (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0x8F", /* 0x88 */
".DB 0xFD, 0xCB, 0x90", ".DB 0xFD, 0xCB, 0x91", ".DB 0xFD, 0xCB, 0x92", ".DB 0xFD, 0xCB, 0x93", ".DB 0xFD, 0xCB, 0x94", ".DB 0xFD, 0xCB, 0x95", "RES 2, (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0x97", /* 0x90 */
".DB 0xFD, 0xCB, 0x98", ".DB 0xFD, 0xCB, 0x99", ".DB 0xFD, 0xCB, 0x9A", ".DB 0xFD, 0xCB, 0x9B", ".DB 0xFD, 0xCB, 0x9C", ".DB 0xFD, 0xCB, 0x9D", "RES 3, (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0x9F", /* 0x98 */
".DB 0xFD, 0xCB, 0xA0", ".DB 0xFD, 0xCB, 0xA1", ".DB 0xFD, 0xCB, 0xA2", ".DB 0xFD, 0xCB, 0xA3", ".DB 0xFD, 0xCB, 0xA4", ".DB 0xFD, 0xCB, 0xA5", "RES 4, (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0xA7", /* 0xA0 */
".DB 0xFD, 0xCB, 0xA8", ".DB 0xFD, 0xCB, 0xA9", ".DB 0xFD, 0xCB, 0xAA", ".DB 0xFD, 0xCB, 0xAB", ".DB 0xFD, 0xCB, 0xAC", ".DB 0xFD, 0xCB, 0xAD", "RES 5, (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0xAF", /* 0xA8 */
".DB 0xFD, 0xCB, 0xB0", ".DB 0xFD, 0xCB, 0xB1", ".DB 0xFD, 0xCB, 0xB2", ".DB 0xFD, 0xCB, 0xB3", ".DB 0xFD, 0xCB, 0xB4", ".DB 0xFD, 0xCB, 0xB5", "RES 6, (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0xB7", /* 0xB0 */
".DB 0xFD, 0xCB, 0xB8", ".DB 0xFD, 0xCB, 0xB9", ".DB 0xFD, 0xCB, 0xBA", ".DB 0xFD, 0xCB, 0xBB", ".DB 0xFD, 0xCB, 0xBC", ".DB 0xFD, 0xCB, 0xBD", "RES 7, (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0xBF", /* 0xB8 */
".DB 0xFD, 0xCB, 0xC0", ".DB 0xFD, 0xCB, 0xC1", ".DB 0xFD, 0xCB, 0xC2", ".DB 0xFD, 0xCB, 0xC3", ".DB 0xFD, 0xCB, 0xC4", ".DB 0xFD, 0xCB, 0xC5", "SET 0, (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0xC7", /* 0xC0 */
".DB 0xFD, 0xCB, 0xC8", ".DB 0xFD, 0xCB, 0xC9", ".DB 0xFD, 0xCB, 0xCA", ".DB 0xFD, 0xCB, 0xCB", ".DB 0xFD, 0xCB, 0xCC", ".DB 0xFD, 0xCB, 0xCD", "SET 1, (IX+0x{0:X2})", ".DB 0xFD, 0xCB, 0xCF", /* 0xC8 */
".DB 0xFD, 0xDB, 0xD0", ".DB 0xFD, 0xDB, 0xD1", ".DB 0xFD, 0xDB, 0xD2", ".DB 0xFD, 0xDB, 0xD3", ".DB 0xFD, 0xDB, 0xD4", ".DB 0xFD, 0xDB, 0xD5", "SET 2, (IX+0x{0:X2})", ".DB 0xFD, 0xDB, 0xD7", /* 0xD0 */
".DB 0xFD, 0xDB, 0xD8", ".DB 0xFD, 0xDB, 0xD9", ".DB 0xFD, 0xDB, 0xDA", ".DB 0xFD, 0xDB, 0xDB", ".DB 0xFD, 0xDB, 0xDC", ".DB 0xFD, 0xDB, 0xFD", "SET 3, (IX+0x{0:X2})", ".DB 0xFD, 0xDB, 0xDF", /* 0xD8 */
".DB 0xFD, 0xEB, 0xE0", ".DB 0xFD, 0xEB, 0xE1", ".DB 0xFD, 0xEB, 0xE2", ".DB 0xFD, 0xEB, 0xE3", ".DB 0xFD, 0xEB, 0xE4", ".DB 0xFD, 0xEB, 0xE5", "SET 4, (IX+0x{0:X2})", ".DB 0xFD, 0xEB, 0xE7", /* 0xE0 */
".DB 0xFD, 0xEB, 0xE8", ".DB 0xFD, 0xEB, 0xE9", ".DB 0xFD, 0xEB, 0xEA", ".DB 0xFD, 0xEB, 0xEB", ".DB 0xFD, 0xEB, 0xEC", ".DB 0xFD, 0xEB, 0xED", "SET 5, (IX+0x{0:X2})", ".DB 0xFD, 0xEB, 0xEF", /* 0xE8 */
".DB 0xFD, 0xFB, 0xF0", ".DB 0xFD, 0xFB, 0xF1", ".DB 0xFD, 0xFB, 0xF2", ".DB 0xFD, 0xFB, 0xF3", ".DB 0xFD, 0xFB, 0xF4", ".DB 0xFD, 0xFB, 0xF5", "SET 6, (IX+0x{0:X2})", ".DB 0xFD, 0xFB, 0xF7", /* 0xF0 */
".DB 0xFD, 0xFB, 0xF8", ".DB 0xFD, 0xFB, 0xF9", ".DB 0xFD, 0xFB, 0xFA", ".DB 0xFD, 0xFB, 0xFB", ".DB 0xFD, 0xFB, 0xFC", ".DB 0xFD, 0xFB, 0xFD", "SET 7, (IX+0x{0:X2})", ".DB 0xFD, 0xFB, 0xFF" /* 0xF8 */
};
static readonly int[] opcodeLengthPrefixDDFD = new int[]
{
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 4, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2,
2, 2, 2, 2, 3, 3, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
3, 3, 3, 3, 3, 3, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2,
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
};
static readonly int[] opcodeLengthPrefixDDFDCB = new int[]
{
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
};
public static string PrintRegisters(Z80A cpu)
{
return string.Format("AF:{0:X4} BC:{1:X4} DE:{2:X4} HL:{3:X4} IX:{4:X4} IY:{5:X4} SP:{6:X4}", cpu.af.Word, cpu.bc.Word, cpu.de.Word, cpu.hl.Word, cpu.ix.Word, cpu.iy.Word, cpu.sp);
}
public static string PrintFlags(Z80A cpu)
{
return string.Format("[{7}{6}{5}{4}{3}{2}{1}{0}]",
cpu.IsFlagSet(Flags.Carry) ? "C" : "-",
cpu.IsFlagSet(Flags.Subtract) ? "N" : "-",
cpu.IsFlagSet(Flags.ParityOrOverflow) ? "P" : "-",
cpu.IsFlagSet(Flags.UnusedBitX) ? "X" : "-",
cpu.IsFlagSet(Flags.HalfCarry) ? "H" : "-",
cpu.IsFlagSet(Flags.UnusedBitY) ? "Y" : "-",
cpu.IsFlagSet(Flags.Zero) ? "Z" : "-",
cpu.IsFlagSet(Flags.Sign) ? "S" : "-");
}
public static string PrintInterrupt(Z80A cpu)
{
return string.Format("[IM{0} {1} {2} {3}]", cpu.im, (cpu.iff1 ? "EI" : "DI"), (cpu.halt ? "HLT" : "---"), (cpu.intState == InterruptState.Assert ? "ASR" : "---"));
}
public static string DisassembleOpcode(Z80A cpu, ushort address)
{
byte[] opcode = DisassembleGetOpcodeBytes(cpu, address);
return string.Format("0x{0:X4} | {1} | {2}", address, DisassembleMakeByteString(cpu, opcode).PadRight(15), DisassembleMakeMnemonicString(cpu, opcode));
}
public static byte[] DisassembleGetOpcodeBytes(Z80A cpu, ushort address)
{
byte[] opcode = new byte[5];
for (int i = 0; i < opcode.Length; i++)
opcode[i] = (address + i <= 0xFFFF ? cpu.ReadMemory8((ushort)(address + i)) : (byte)0);
return opcode;
}
public static int DisassembleGetOpcodeLen(Z80A cpu, byte[] opcode)
{
switch (opcode[0])
{
case 0xCB: return opcodeLength_CB[opcode[1]];
case 0xED: return opcodeLengthPrefixED[opcode[1]];
case 0xDD:
case 0xFD:
if (opcode[1] == 0xCB)
return opcodeLengthPrefixDDFDCB[opcode[3]];
else
return opcodeLengthPrefixDDFD[opcode[1]];
default: return opcodeLengthNoPrefix[opcode[0]];
}
}
public static string DisassembleMakeByteString(Z80A cpu, byte[] opcode)
{
return string.Join(" ", opcode.Select(x => string.Format("{0:X2}", x)).Take(DisassembleGetOpcodeLen(cpu, opcode)));
}
public static string DisassembleMakeMnemonicString(Z80A cpu, byte[] opcode)
{
int len = DisassembleGetOpcodeLen(cpu, opcode);
int start = 0;
string[] mnemonics = opcodeMnemonicNoPrefix;
bool isDDFDCB = false;
switch (opcode[0])
{
case 0xCB: start = 1; mnemonics = opcodeMnemonicPrefixCB; break;
case 0xED: start = 1; mnemonics = opcodeMnemonicPrefixED; break;
case 0xDD:
if (opcode[1] == 0xCB)
{
mnemonics = opcodeMnemonicPrefixDDCB;
isDDFDCB = true;
}
else
{
start = 1;
mnemonics = opcodeMnemonicPrefixDD;
}
break;
case 0xFD:
if (opcode[1] == 0xCB)
{
mnemonics = opcodeMnemonicPrefixFDCB;
isDDFDCB = true;
}
else
{
start = 1;
mnemonics = opcodeMnemonicPrefixFD;
}
break;
}
if (mnemonics == null) return "(unimplemented)";
if (!isDDFDCB)
{
switch (len - start)
{
case 1: return mnemonics[opcode[start]];
case 2: return string.Format(mnemonics[opcode[start]], opcode[start + 1]);
case 3: return string.Format(mnemonics[opcode[start]], (opcode[start + 2] << 8 | opcode[start + 1]));
default: return string.Empty;
}
}
else
{
return string.Format(mnemonics[opcode[3]], opcode[2]);
}
}
private string MakeUnimplementedOpcodeString(string prefix, ushort address)
{
byte[] opcode = DisassembleGetOpcodeBytes(this, address);
return string.Format("Unimplemented {0}opcode {1} ({2})", (prefix != string.Empty ? prefix + " " : prefix), DisassembleMakeByteString(this, opcode), DisassembleMakeMnemonicString(this, opcode));
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9fa152db63418e74ab7f359175172290

View File

@ -0,0 +1,283 @@
using static Essgee.Emulation.Utilities;
namespace Essgee.Emulation.CPU
{
public partial class Z80A
{
static SimpleOpcodeDelegate[] opcodesNoPrefix = new SimpleOpcodeDelegate[]
{
/* 0x00 */
new SimpleOpcodeDelegate((c) => { /* NOP */ }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate16(ref c.bc.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.bc.Word, c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.Increment16(ref c.bc.Word); }),
new SimpleOpcodeDelegate((c) => { c.Increment8(ref c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.Decrement8(ref c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate8(ref c.bc.High, false); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeftAccumulatorCircular(); }),
new SimpleOpcodeDelegate((c) => { c.ExchangeRegisters16(ref c.af, ref c.af_); }),
new SimpleOpcodeDelegate((c) => { c.Add16(ref c.hl, c.bc.Word, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterFromMemory8(ref c.af.High, c.bc.Word, false); }),
new SimpleOpcodeDelegate((c) => { c.Decrement16(ref c.bc.Word); }),
new SimpleOpcodeDelegate((c) => { c.Increment8(ref c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.Decrement8(ref c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate8(ref c.bc.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.RotateRightAccumulatorCircular(); }),
/* 0x10 */
new SimpleOpcodeDelegate((c) => { c.DecrementJumpNonZero(); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate16(ref c.de.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.de.Word, c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.Increment16(ref c.de.Word); }),
new SimpleOpcodeDelegate((c) => { c.Increment8(ref c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.Decrement8(ref c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate8(ref c.de.High, false); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeftAccumulator(); }),
new SimpleOpcodeDelegate((c) => { c.Jump8(); }),
new SimpleOpcodeDelegate((c) => { c.Add16(ref c.hl, c.de.Word, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterFromMemory8(ref c.af.High, c.de.Word, false); }),
new SimpleOpcodeDelegate((c) => { c.Decrement16(ref c.de.Word); }),
new SimpleOpcodeDelegate((c) => { c.Increment8(ref c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.Decrement8(ref c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate8(ref c.de.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.RotateRightAccumulator(); }),
/* 0x20 */
new SimpleOpcodeDelegate((c) => { c.JumpConditional8(!c.IsFlagSet(Flags.Zero)); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate16(ref c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory16(c.ReadMemory16(c.pc), c.hl.Word); c.pc += 2; }),
new SimpleOpcodeDelegate((c) => { c.Increment16(ref c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.Increment8(ref c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.Decrement8(ref c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate8(ref c.hl.High, false); }),
new SimpleOpcodeDelegate((c) => { c.DecimalAdjustAccumulator(); }),
new SimpleOpcodeDelegate((c) => { c.JumpConditional8(c.IsFlagSet(Flags.Zero)); }),
new SimpleOpcodeDelegate((c) => { c.Add16(ref c.hl, c.hl.Word, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister16(ref c.hl.Word, c.ReadMemory16(c.ReadMemory16(c.pc))); c.pc += 2; }),
new SimpleOpcodeDelegate((c) => { c.Decrement16(ref c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.Increment8(ref c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.Decrement8(ref c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate8(ref c.hl.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.af.High ^= 0xFF; c.SetFlag(Flags.Subtract | Flags.HalfCarry); c.SetClearFlagConditional(Flags.UnusedBitY, IsBitSet(c.af.High, 5)); c.SetClearFlagConditional(Flags.UnusedBitX, IsBitSet(c.af.High, 3)); }),
/* 0x30 */
new SimpleOpcodeDelegate((c) => { c.JumpConditional8(!c.IsFlagSet(Flags.Carry)); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate16(ref c.sp); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.ReadMemory16(c.pc), c.af.High); c.pc += 2; }),
new SimpleOpcodeDelegate((c) => { c.Increment16(ref c.sp); }),
new SimpleOpcodeDelegate((c) => { c.IncrementMemory8(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.DecrementMemory8(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.hl.Word, c.ReadMemory8(c.pc++)); }),
new SimpleOpcodeDelegate((c) => { c.SetFlag(Flags.Carry); c.ClearFlag(Flags.Subtract | Flags.HalfCarry); c.SetClearFlagConditional(Flags.UnusedBitY, IsBitSet(c.af.High, 5)); c.SetClearFlagConditional(Flags.UnusedBitX, IsBitSet(c.af.High, 3)); }),
new SimpleOpcodeDelegate((c) => { c.JumpConditional8(c.IsFlagSet(Flags.Carry)); }),
new SimpleOpcodeDelegate((c) => { c.Add16(ref c.hl, c.sp, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterFromMemory8(ref c.af.High, c.ReadMemory16(c.pc), false); c.pc += 2; }),
new SimpleOpcodeDelegate((c) => { c.Decrement16(ref c.sp); }),
new SimpleOpcodeDelegate((c) => { c.Increment8(ref c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.Decrement8(ref c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegisterImmediate8(ref c.af.High, false); }),
new SimpleOpcodeDelegate((c) => { c.SetClearFlagConditional(Flags.HalfCarry, c.IsFlagSet(Flags.Carry)); c.SetClearFlagConditional(Flags.Carry, !c.IsFlagSet(Flags.Carry)); c.ClearFlag(Flags.Subtract); c.SetClearFlagConditional(Flags.UnusedBitY, IsBitSet(c.af.High, 5)); c.SetClearFlagConditional(Flags.UnusedBitX, IsBitSet(c.af.High, 3)); }),
/* 0x40 */
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.High, c.bc.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.High, c.bc.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.High, c.de.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.High, c.de.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.High, c.hl.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.High, c.hl.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.bc.High = c.ReadMemory8(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.High, c.af.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.Low, c.bc.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.Low, c.bc.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.Low, c.de.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.Low, c.de.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.Low, c.hl.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.Low, c.hl.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.bc.Low = c.ReadMemory8(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.bc.Low, c.af.High, false); }),
/* 0x50 */
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.High, c.bc.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.High, c.bc.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.High, c.de.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.High, c.de.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.High, c.hl.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.High, c.hl.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.de.High = c.ReadMemory8(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.High, c.af.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.Low, c.bc.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.Low, c.bc.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.Low, c.de.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.Low, c.de.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.Low, c.hl.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.Low, c.hl.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.de.Low = c.ReadMemory8(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.de.Low, c.af.High, false); }),
/* 0x60 */
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.High, c.bc.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.High, c.bc.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.High, c.de.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.High, c.de.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.High, c.hl.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.High, c.hl.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.hl.High = c.ReadMemory8(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.High, c.af.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.Low, c.bc.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.Low, c.bc.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.Low, c.de.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.Low, c.de.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.Low, c.hl.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.Low, c.hl.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.hl.Low = c.ReadMemory8(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.hl.Low, c.af.High, false); }),
/* 0x70 */
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.hl.Word, c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.hl.Word, c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.hl.Word, c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.hl.Word, c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.hl.Word, c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.hl.Word, c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.EnterHaltState(); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory8(c.hl.Word, c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.af.High, c.bc.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.af.High, c.bc.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.af.High, c.de.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.af.High, c.de.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.af.High, c.hl.High, false); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.af.High, c.hl.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.af.High = c.ReadMemory8(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.af.High, c.af.High, false); }),
/* 0x80 */
new SimpleOpcodeDelegate((c) => { c.Add8(c.bc.High, false); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.bc.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.de.High, false); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.de.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.hl.High, false); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.hl.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.ReadMemory8(c.hl.Word), false); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.af.High, false); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.bc.High, true); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.bc.Low, true); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.de.High, true); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.de.Low, true); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.hl.High, true); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.hl.Low, true); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.ReadMemory8(c.hl.Word), true); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.af.High, true); }),
/* 0x90 */
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.bc.High, false); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.bc.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.de.High, false); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.de.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.hl.High, false); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.hl.Low, false); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.ReadMemory8(c.hl.Word), false); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.af.High, false); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.bc.High, true); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.bc.Low, true); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.de.High, true); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.de.Low, true); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.hl.High, true); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.hl.Low, true); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.ReadMemory8(c.hl.Word), true); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.af.High, true); }),
/* 0xA0 */
new SimpleOpcodeDelegate((c) => { c.And8(c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.And8(c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.And8(c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.And8(c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.And8(c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.And8(c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.And8(c.ReadMemory8(c.hl.Word)); }),
new SimpleOpcodeDelegate((c) => { c.And8(c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.Xor8(c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.Xor8(c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.Xor8(c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.Xor8(c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.Xor8(c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.Xor8(c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.Xor8(c.ReadMemory8(c.hl.Word)); }),
new SimpleOpcodeDelegate((c) => { c.Xor8(c.af.High); }),
/* 0xB0 */
new SimpleOpcodeDelegate((c) => { c.Or8(c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.Or8(c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.Or8(c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.Or8(c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.Or8(c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.Or8(c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.Or8(c.ReadMemory8(c.hl.Word)); }),
new SimpleOpcodeDelegate((c) => { c.Or8(c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.Cp8(c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.Cp8(c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.Cp8(c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.Cp8(c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.Cp8(c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.Cp8(c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.Cp8(c.ReadMemory8(c.hl.Word)); }),
new SimpleOpcodeDelegate((c) => { c.Cp8(c.af.High); }),
/* 0xC0 */
new SimpleOpcodeDelegate((c) => { c.ReturnConditional(!c.IsFlagSet(Flags.Zero)); }),
new SimpleOpcodeDelegate((c) => { c.Pop(ref c.bc); }),
new SimpleOpcodeDelegate((c) => { c.JumpConditional16(!c.IsFlagSet(Flags.Zero)); }),
new SimpleOpcodeDelegate((c) => { c.JumpConditional16(true); }),
new SimpleOpcodeDelegate((c) => { c.CallConditional16(!c.IsFlagSet(Flags.Zero)); }),
new SimpleOpcodeDelegate((c) => { c.Push(c.bc); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.ReadMemory8(c.pc++), false); }),
new SimpleOpcodeDelegate((c) => { c.Restart(0x0000); }),
new SimpleOpcodeDelegate((c) => { c.ReturnConditional(c.IsFlagSet(Flags.Zero)); }),
new SimpleOpcodeDelegate((c) => { c.Return(); }),
new SimpleOpcodeDelegate((c) => { c.JumpConditional16(c.IsFlagSet(Flags.Zero)); }),
new SimpleOpcodeDelegate((c) => { /* CB - handled elsewhere */ }),
new SimpleOpcodeDelegate((c) => { c.CallConditional16(c.IsFlagSet(Flags.Zero)); }),
new SimpleOpcodeDelegate((c) => { c.Call16(); }),
new SimpleOpcodeDelegate((c) => { c.Add8(c.ReadMemory8(c.pc++), true); }),
new SimpleOpcodeDelegate((c) => { c.Restart(0x0008); }),
/* 0xD0 */
new SimpleOpcodeDelegate((c) => { c.ReturnConditional(!c.IsFlagSet(Flags.Carry)); }),
new SimpleOpcodeDelegate((c) => { c.Pop(ref c.de); }),
new SimpleOpcodeDelegate((c) => { c.JumpConditional16(!c.IsFlagSet(Flags.Carry)); }),
new SimpleOpcodeDelegate((c) => { c.WritePort(c.ReadMemory8(c.pc++), c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.CallConditional16(!c.IsFlagSet(Flags.Carry)); }),
new SimpleOpcodeDelegate((c) => { c.Push(c.de); }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.ReadMemory8(c.pc++), false); }),
new SimpleOpcodeDelegate((c) => { c.Restart(0x0010); }),
new SimpleOpcodeDelegate((c) => { c.ReturnConditional(c.IsFlagSet(Flags.Carry)); }),
new SimpleOpcodeDelegate((c) => { c.ExchangeRegisters16(ref c.bc, ref c.bc_); c.ExchangeRegisters16(ref c.de, ref c.de_); c.ExchangeRegisters16(ref c.hl, ref c.hl_); }),
new SimpleOpcodeDelegate((c) => { c.JumpConditional16(c.IsFlagSet(Flags.Carry)); }),
new SimpleOpcodeDelegate((c) => { c.af.High = c.ReadPort(c.ReadMemory8(c.pc++)); }),
new SimpleOpcodeDelegate((c) => { c.CallConditional16(c.IsFlagSet(Flags.Carry)); }),
new SimpleOpcodeDelegate((c) => { /* DD - handled elsewhere */ }),
new SimpleOpcodeDelegate((c) => { c.Subtract8(c.ReadMemory8(c.pc++), true); }),
new SimpleOpcodeDelegate((c) => { c.Restart(0x0018); }),
/* 0xE0 */
new SimpleOpcodeDelegate((c) => { c.ReturnConditional(!c.IsFlagSet(Flags.ParityOrOverflow)); }),
new SimpleOpcodeDelegate((c) => { c.Pop(ref c.hl); }),
new SimpleOpcodeDelegate((c) => { c.JumpConditional16(!c.IsFlagSet(Flags.ParityOrOverflow)); }),
new SimpleOpcodeDelegate((c) => { c.ExchangeStackRegister16(ref c.hl); }),
new SimpleOpcodeDelegate((c) => { c.CallConditional16(!c.IsFlagSet(Flags.ParityOrOverflow)); }),
new SimpleOpcodeDelegate((c) => { c.Push(c.hl); }),
new SimpleOpcodeDelegate((c) => { c.And8(c.ReadMemory8(c.pc++)); }),
new SimpleOpcodeDelegate((c) => { c.Restart(0x0020); }),
new SimpleOpcodeDelegate((c) => { c.ReturnConditional(c.IsFlagSet(Flags.ParityOrOverflow)); }),
new SimpleOpcodeDelegate((c) => { c.pc = c.hl.Word; }),
new SimpleOpcodeDelegate((c) => { c.JumpConditional16(c.IsFlagSet(Flags.ParityOrOverflow)); }),
new SimpleOpcodeDelegate((c) => { c.ExchangeRegisters16(ref c.de, ref c.hl); }),
new SimpleOpcodeDelegate((c) => { c.CallConditional16(c.IsFlagSet(Flags.ParityOrOverflow)); }),
new SimpleOpcodeDelegate((c) => { /* ED - handled elsewhere */ }),
new SimpleOpcodeDelegate((c) => { c.Xor8(c.ReadMemory8(c.pc++)); }),
new SimpleOpcodeDelegate((c) => { c.Restart(0x0028); }),
/* 0xF0 */
new SimpleOpcodeDelegate((c) => { c.ReturnConditional(!c.IsFlagSet(Flags.Sign)); }),
new SimpleOpcodeDelegate((c) => { c.Pop(ref c.af); }),
new SimpleOpcodeDelegate((c) => { c.JumpConditional16(!c.IsFlagSet(Flags.Sign)); }),
new SimpleOpcodeDelegate((c) => { c.iff1 = c.iff2 = false; }),
new SimpleOpcodeDelegate((c) => { c.CallConditional16(!c.IsFlagSet(Flags.Sign)); }),
new SimpleOpcodeDelegate((c) => { c.Push(c.af); }),
new SimpleOpcodeDelegate((c) => { c.Or8(c.ReadMemory8(c.pc++)); }),
new SimpleOpcodeDelegate((c) => { c.Restart(0x0030); }),
new SimpleOpcodeDelegate((c) => { c.ReturnConditional(c.IsFlagSet(Flags.Sign)); }),
new SimpleOpcodeDelegate((c) => { c.sp = c.hl.Word; }),
new SimpleOpcodeDelegate((c) => { c.JumpConditional16(c.IsFlagSet(Flags.Sign)); }),
new SimpleOpcodeDelegate((c) => { c.eiDelay = true; }),
new SimpleOpcodeDelegate((c) => { c.CallConditional16(c.IsFlagSet(Flags.Sign)); }),
new SimpleOpcodeDelegate((c) => { /* FD - handled elsewhere */ }),
new SimpleOpcodeDelegate((c) => { c.Cp8(c.ReadMemory8(c.pc++)); }),
new SimpleOpcodeDelegate((c) => { c.Restart(0x0038); })
};
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a8c690c6cf2d024418c1412af53e453f

View File

@ -0,0 +1,281 @@
namespace Essgee.Emulation.CPU
{
public partial class Z80A
{
static SimpleOpcodeDelegate[] opcodesPrefixCB = new SimpleOpcodeDelegate[]
{
/* 0x00 */
new SimpleOpcodeDelegate((c) => { c.RotateLeftCircular(ref c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeftCircular(ref c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeftCircular(ref c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeftCircular(ref c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeftCircular(ref c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeftCircular(ref c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeftCircular(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeftCircular(ref c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateRightCircular(ref c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateRightCircular(ref c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateRightCircular(ref c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateRightCircular(ref c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateRightCircular(ref c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateRightCircular(ref c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateRightCircular(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.RotateRightCircular(ref c.af.High); }),
/* 0x10 */
new SimpleOpcodeDelegate((c) => { c.RotateLeft(ref c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeft(ref c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeft(ref c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeft(ref c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeft(ref c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeft(ref c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeft(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.RotateLeft(ref c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateRight(ref c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateRight(ref c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateRight(ref c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateRight(ref c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateRight(ref c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.RotateRight(ref c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.RotateRight(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.RotateRight(ref c.af.High); }),
/* 0x20 */
new SimpleOpcodeDelegate((c) => { c.ShiftLeftArithmetic(ref c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftArithmetic(ref c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftArithmetic(ref c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftArithmetic(ref c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftArithmetic(ref c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftArithmetic(ref c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftArithmetic(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftArithmetic(ref c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightArithmetic(ref c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightArithmetic(ref c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightArithmetic(ref c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightArithmetic(ref c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightArithmetic(ref c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightArithmetic(ref c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightArithmetic(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightArithmetic(ref c.af.High); }),
/* 0x30 */
new SimpleOpcodeDelegate((c) => { c.ShiftLeftLogical(ref c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftLogical(ref c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftLogical(ref c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftLogical(ref c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftLogical(ref c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftLogical(ref c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftLogical(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.ShiftLeftLogical(ref c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightLogical(ref c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightLogical(ref c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightLogical(ref c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightLogical(ref c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightLogical(ref c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightLogical(ref c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightLogical(c.hl.Word); }),
new SimpleOpcodeDelegate((c) => { c.ShiftRightLogical(ref c.af.High); }),
/* 0x40 */
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.Low, 0); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.Low, 0); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Low, 0); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Word, 0); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.af.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.High, 1); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.Low, 1); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.High, 1); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.Low, 1); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.High, 1); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Low, 1); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Word, 1); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.af.High, 1); }),
/* 0x50 */
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.Low, 2); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.Low, 2); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Low, 2); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Word, 2); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.af.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.High, 3); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.Low, 3); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.High, 3); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.Low, 3); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.High, 3); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Low, 3); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Word, 3); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.af.High, 3); }),
/* 0x60 */
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.Low, 4); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.Low, 4); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Low, 4); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Word, 4); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.af.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.High, 5); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.Low, 5); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.High, 5); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.Low, 5); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.High, 5); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Low, 5); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Word, 5); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.af.High, 5); }),
/* 0x70 */
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.Low, 6); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.Low, 6); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Low, 6); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Word, 6); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.af.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.High, 7); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.bc.Low, 7); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.High, 7); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.de.Low, 7); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.High, 7); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Low, 7); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.hl.Word, 7); }),
new SimpleOpcodeDelegate((c) => { c.TestBit(c.af.High, 7); }),
/* 0x80 */
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.Low, 0); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.Low, 0); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.Low, 0); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(c.hl.Word, 0); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.af.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.High, 1); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.Low, 1); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.High, 1); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.Low, 1); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.High, 1); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.Low, 1); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(c.hl.Word, 1); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.af.High, 1); }),
/* 0x90 */
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.Low, 2); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.Low, 2); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.Low, 2); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(c.hl.Word, 2); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.af.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.High, 3); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.Low, 3); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.High, 3); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.Low, 3); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.High, 3); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.Low, 3); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(c.hl.Word, 3); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.af.High, 3); }),
/* 0xA0 */
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.Low, 4); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.Low, 4); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.Low, 4); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(c.hl.Word, 4); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.af.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.High, 5); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.Low, 5); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.High, 5); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.Low, 5); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.High, 5); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.Low, 5); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(c.hl.Word, 5); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.af.High, 5); }),
/* 0xB0 */
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.Low, 6); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.Low, 6); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.Low, 6); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(c.hl.Word, 6); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.af.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.High, 7); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.bc.Low, 7); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.High, 7); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.de.Low, 7); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.High, 7); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.hl.Low, 7); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(c.hl.Word, 7); }),
new SimpleOpcodeDelegate((c) => { c.ResetBit(ref c.af.High, 7); }),
/* 0xC0 */
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.Low, 0); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.Low, 0); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.Low, 0); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(c.hl.Word, 0); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.af.High, 0); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.High, 1); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.Low, 1); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.High, 1); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.Low, 1); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.High, 1); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.Low, 1); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(c.hl.Word, 1); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.af.High, 1); }),
/* 0xD0 */
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.Low, 2); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.Low, 2); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.Low, 2); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(c.hl.Word, 2); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.af.High, 2); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.High, 3); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.Low, 3); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.High, 3); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.Low, 3); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.High, 3); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.Low, 3); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(c.hl.Word, 3); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.af.High, 3); }),
/* 0xE0 */
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.Low, 4); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.Low, 4); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.Low, 4); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(c.hl.Word, 4); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.af.High, 4); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.High, 5); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.Low, 5); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.High, 5); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.Low, 5); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.High, 5); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.Low, 5); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(c.hl.Word, 5); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.af.High, 5); }),
/* 0xF0 */
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.Low, 6); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.Low, 6); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.Low, 6); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(c.hl.Word, 6); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.af.High, 6); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.High, 7); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.bc.Low, 7); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.High, 7); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.de.Low, 7); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.High, 7); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.hl.Low, 7); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(c.hl.Word, 7); }),
new SimpleOpcodeDelegate((c) => { c.SetBit(ref c.af.High, 7); }),
};
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1eaf728772256b548a5dd0f76aac95a8

View File

@ -0,0 +1,281 @@
namespace Essgee.Emulation.CPU
{
public partial class Z80A
{
static DDFDOpcodeDelegate[] opcodesPrefixDDFD = new DDFDOpcodeDelegate[]
{
/* 0x00 */
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { /* NOP */ }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegisterImmediate16(ref c.bc.Word); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadMemory8(c.bc.Word, c.af.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Increment16(ref c.bc.Word); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Increment8(ref c.bc.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Decrement8(ref c.bc.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegisterImmediate8(ref c.bc.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.RotateLeftAccumulatorCircular(); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.ExchangeRegisters16(ref c.af, ref c.af_); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add16(ref r, c.bc.Word, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegisterFromMemory8(ref c.af.High, c.bc.Word, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Decrement16(ref c.bc.Word); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Increment8(ref c.bc.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Decrement8(ref c.bc.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegisterImmediate8(ref c.bc.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.RotateRightAccumulatorCircular(); }),
/* 0x10 */
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.DecrementJumpNonZero(); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegisterImmediate16(ref c.de.Word); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadMemory8(c.de.Word, c.af.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Increment16(ref c.de.Word); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Increment8(ref c.de.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Decrement8(ref c.de.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegisterImmediate8(ref c.de.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.RotateLeftAccumulator(); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Jump8(); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add16(ref r, c.de.Word, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegisterFromMemory8(ref c.af.High, c.de.Word, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Decrement16(ref c.de.Word); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Increment8(ref c.de.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Decrement8(ref c.de.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegisterImmediate8(ref c.de.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.RotateRightAccumulator(); }),
/* 0x20 */
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.JumpConditional8(!c.IsFlagSet(Flags.Zero)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegisterImmediate16(ref r.Word); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadMemory16(c.ReadMemory16(c.pc), r.Word); c.pc += 2; }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Increment16(ref r.Word); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Increment8(ref r.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Decrement8(ref r.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { r.High = c.ReadMemory8(c.pc++); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.DecimalAdjustAccumulator(); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.JumpConditional8(c.IsFlagSet(Flags.Zero)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add16(ref r, r.Word, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister16(ref r.Word, c.ReadMemory16(c.ReadMemory16(c.pc))); c.pc += 2; }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Decrement16(ref r.Word); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Increment8(ref r.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Decrement8(ref r.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { r.Low = c.ReadMemory8(c.pc++); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.af.High ^= 0xFF; c.SetFlag(Flags.Subtract | Flags.HalfCarry); }),
/* 0x30 */
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.JumpConditional8(!c.IsFlagSet(Flags.Carry)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegisterImmediate16(ref c.sp); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadMemory8(c.ReadMemory16(c.pc), c.af.High); c.pc += 2; }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Increment16(ref c.sp); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.IncrementMemory8(c.CalculateIXIYAddress(r)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.DecrementMemory8(c.CalculateIXIYAddress(r)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadMemory8(c.CalculateIXIYAddress(r), c.ReadMemory8(c.pc++)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.SetFlag(Flags.Carry); c.ClearFlag(Flags.Subtract | Flags.HalfCarry); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.JumpConditional8(c.IsFlagSet(Flags.Carry)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add16(ref r, c.sp, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegisterFromMemory8(ref c.af.High, c.ReadMemory16(c.pc), false); c.pc += 2; }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Decrement16(ref c.sp); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Increment8(ref c.af.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Decrement8(ref c.af.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegisterImmediate8(ref c.af.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.ClearFlag(Flags.Subtract); c.SetClearFlagConditional(Flags.Carry, !c.IsFlagSet(Flags.Carry)); }),
/* 0x40 */
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.bc.High, c.bc.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.bc.High, c.bc.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.bc.High, c.de.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.bc.High, c.de.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.bc.High, r.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.bc.High, r.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.bc.High = c.ReadMemory8(c.CalculateIXIYAddress(r)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.bc.High, c.af.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.bc.Low, c.bc.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.bc.Low, c.bc.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.bc.Low, c.de.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.bc.Low, c.de.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.bc.Low, r.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.bc.Low, r.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.bc.Low = c.ReadMemory8(c.CalculateIXIYAddress(r)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.bc.Low, c.af.High, false); }),
/* 0x50 */
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.de.High, c.bc.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.de.High, c.bc.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.de.High, c.de.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.de.High, c.de.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.de.High, r.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.de.High, r.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.de.High = c.ReadMemory8(c.CalculateIXIYAddress(r)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.de.High, c.af.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.de.Low, c.bc.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.de.Low, c.bc.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.de.Low, c.de.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.de.Low, c.de.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.de.Low, r.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.de.Low, r.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.de.Low = c.ReadMemory8(c.CalculateIXIYAddress(r)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.de.Low, c.af.High, false); }),
/* 0x60 */
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref r.High, c.bc.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref r.High, c.bc.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref r.High, c.de.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref r.High, c.de.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref r.High, r.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref r.High, r.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.hl.High = c.ReadMemory8(c.CalculateIXIYAddress(r)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref r.High, c.af.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref r.Low, c.bc.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref r.Low, c.bc.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref r.Low, c.de.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref r.Low, c.de.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref r.Low, r.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref r.Low, r.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.hl.Low = c.ReadMemory8(c.CalculateIXIYAddress(r)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref r.Low, c.af.High, false); }),
/* 0x70 */
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadMemory8(c.CalculateIXIYAddress(r), c.bc.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadMemory8(c.CalculateIXIYAddress(r), c.bc.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadMemory8(c.CalculateIXIYAddress(r), c.de.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadMemory8(c.CalculateIXIYAddress(r), c.de.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadMemory8(c.CalculateIXIYAddress(r), c.hl.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadMemory8(c.CalculateIXIYAddress(r), c.hl.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.EnterHaltState(); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadMemory8(c.CalculateIXIYAddress(r), c.af.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.af.High, c.bc.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.af.High, c.bc.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.af.High, c.de.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.af.High, c.de.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.af.High, r.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.af.High, r.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.af.High = c.ReadMemory8(c.CalculateIXIYAddress(r)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.LoadRegister8(ref c.af.High, c.af.High, false); }),
/* 0x80 */
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add8(c.bc.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add8(c.bc.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add8(c.de.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add8(c.de.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add8(r.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add8(r.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add8(c.ReadMemory8(c.CalculateIXIYAddress(r)), false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add8(c.af.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add8(c.bc.High, true); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add8(c.bc.Low, true); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add8(c.de.High, true); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add8(c.de.Low, true); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add8(r.High, true); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add8(r.Low, true); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add8(c.ReadMemory8(c.CalculateIXIYAddress(r)), true); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add8(c.af.High, true); }),
/* 0x90 */
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Subtract8(c.bc.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Subtract8(c.bc.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Subtract8(c.de.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Subtract8(c.de.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Subtract8(r.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Subtract8(r.Low, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Subtract8(c.ReadMemory8(c.CalculateIXIYAddress(r)), false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Subtract8(c.af.High, false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Subtract8(c.bc.High, true); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Subtract8(c.bc.Low, true); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Subtract8(c.de.High, true); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Subtract8(c.de.Low, true); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Subtract8(r.High, true); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Subtract8(r.Low, true); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Subtract8(c.ReadMemory8(c.CalculateIXIYAddress(r)), true); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Subtract8(c.af.High, true); }),
/* 0xA0 */
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.And8(c.bc.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.And8(c.bc.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.And8(c.de.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.And8(c.de.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.And8(r.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.And8(r.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.And8(c.ReadMemory8(c.CalculateIXIYAddress(r))); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.And8(c.af.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Xor8(c.bc.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Xor8(c.bc.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Xor8(c.de.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Xor8(c.de.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Xor8(r.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Xor8(r.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Xor8(c.ReadMemory8(c.CalculateIXIYAddress(r))); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Xor8(c.af.High); }),
/* 0xB0 */
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Or8(c.bc.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Or8(c.bc.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Or8(c.de.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Or8(c.de.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Or8(r.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Or8(r.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Or8(c.ReadMemory8(c.CalculateIXIYAddress(r))); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Or8(c.af.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Cp8(c.bc.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Cp8(c.bc.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Cp8(c.de.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Cp8(c.de.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Cp8(r.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Cp8(r.Low); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Cp8(c.ReadMemory8(c.CalculateIXIYAddress(r))); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Cp8(c.af.High); }),
/* 0xC0 */
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.ReturnConditional(!c.IsFlagSet(Flags.Zero)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Pop(ref c.bc); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.JumpConditional16(!c.IsFlagSet(Flags.Zero)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.JumpConditional16(true); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.CallConditional16(!c.IsFlagSet(Flags.Zero)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Push(c.bc); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add8(c.ReadMemory8(c.pc++), false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Restart(0x0000); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.ReturnConditional(c.IsFlagSet(Flags.Zero)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Return(); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.JumpConditional16(c.IsFlagSet(Flags.Zero)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.ExecuteOpDDFDCB(c.ReadMemory8((ushort)(c.pc + 1)), ref r); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.CallConditional16(c.IsFlagSet(Flags.Zero)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Call16(); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Add8(c.ReadMemory8(c.pc++), true); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Restart(0x0008); }),
/* 0xD0 */
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.ReturnConditional(!c.IsFlagSet(Flags.Carry)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Pop(ref c.de); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.JumpConditional16(!c.IsFlagSet(Flags.Carry)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.WritePort(c.ReadMemory8(c.pc++), c.af.High); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.CallConditional16(!c.IsFlagSet(Flags.Carry)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Push(c.de); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Subtract8(c.ReadMemory8(c.pc++), false); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Restart(0x0010); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.ReturnConditional(c.IsFlagSet(Flags.Carry)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.ExchangeRegisters16(ref c.bc, ref c.bc_); c.ExchangeRegisters16(ref c.de, ref c.de_); c.ExchangeRegisters16(ref c.hl, ref c.hl_); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.JumpConditional16(c.IsFlagSet(Flags.Carry)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.af.High = c.ReadPort(c.ReadMemory8(c.pc++)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.CallConditional16(c.IsFlagSet(Flags.Carry)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { /* DD - treat as NOP */ }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Subtract8(c.ReadMemory8(c.pc++), true); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Restart(0x0018); }),
/* 0xE0 */
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.ReturnConditional(!c.IsFlagSet(Flags.ParityOrOverflow)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Pop(ref r); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.JumpConditional16(!c.IsFlagSet(Flags.ParityOrOverflow)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.ExchangeStackRegister16(ref r); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.CallConditional16(!c.IsFlagSet(Flags.ParityOrOverflow)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Push(r); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.And8(c.ReadMemory8(c.pc++)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Restart(0x0020); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.ReturnConditional(c.IsFlagSet(Flags.ParityOrOverflow)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.pc = r.Word; }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.JumpConditional16(c.IsFlagSet(Flags.ParityOrOverflow)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.ExchangeRegisters16(ref c.de, ref c.hl); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.CallConditional16(c.IsFlagSet(Flags.ParityOrOverflow)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { /* ED - treat as NOP */ }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Xor8(c.ReadMemory8(c.pc++)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Restart(0x0028); }),
/* 0xF0 */
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.ReturnConditional(!c.IsFlagSet(Flags.Sign)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Pop(ref c.af); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.JumpConditional16(!c.IsFlagSet(Flags.Sign)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.iff1 = c.iff2 = false; }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.CallConditional16(!c.IsFlagSet(Flags.Sign)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Push(c.af); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Or8(c.ReadMemory8(c.pc++)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Restart(0x0030); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.ReturnConditional(c.IsFlagSet(Flags.Sign)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.sp = r.Word; }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.JumpConditional16(c.IsFlagSet(Flags.Sign)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.eiDelay = true; }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.CallConditional16(c.IsFlagSet(Flags.Sign)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { /* FD - treat as NOP */ }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Cp8(c.ReadMemory8(c.pc++)); }),
new DDFDOpcodeDelegate((Z80A c, ref Register r) => { c.Restart(0x0038); })
};
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 59243a6d2ecd14d41816ff23fd5204cb

View File

@ -0,0 +1,281 @@
namespace Essgee.Emulation.CPU
{
public partial class Z80A
{
static DDFDCBOpcodeDelegate[] opcodesPrefixDDFDCB = new DDFDCBOpcodeDelegate[]
{
/* 0x00 */
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.RotateLeftCircular(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.RotateLeftCircular(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.RotateLeftCircular(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.RotateLeftCircular(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.RotateLeftCircular(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.RotateLeftCircular(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.RotateLeftCircular(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.RotateLeftCircular(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.RotateRightCircular(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.RotateRightCircular(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.RotateRightCircular(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.RotateRightCircular(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.RotateRightCircular(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.RotateRightCircular(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.RotateRightCircular(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.RotateRightCircular(address); }),
/* 0x10 */
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.RotateLeft(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.RotateLeft(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.RotateLeft(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.RotateLeft(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.RotateLeft(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.RotateLeft(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.RotateLeft(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.RotateLeft(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.RotateRight(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.RotateRight(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.RotateRight(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.RotateRight(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.RotateRight(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.RotateRight(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.RotateRight(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.RotateRight(address); }),
/* 0x20 */
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.ShiftLeftArithmetic(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.ShiftLeftArithmetic(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.ShiftLeftArithmetic(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.ShiftLeftArithmetic(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.ShiftLeftArithmetic(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.ShiftLeftArithmetic(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.ShiftLeftArithmetic(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.ShiftLeftArithmetic(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.ShiftRightArithmetic(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.ShiftRightArithmetic(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.ShiftRightArithmetic(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.ShiftRightArithmetic(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.ShiftRightArithmetic(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.ShiftRightArithmetic(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.ShiftRightArithmetic(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.ShiftRightArithmetic(address); }),
/* 0x30 */
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.ShiftLeftLogical(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.ShiftLeftLogical(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.ShiftLeftLogical(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.ShiftLeftLogical(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.ShiftLeftLogical(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.ShiftLeftLogical(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.ShiftLeftLogical(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.ShiftLeftLogical(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.ShiftRightLogical(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.ShiftRightLogical(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.ShiftRightLogical(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.ShiftRightLogical(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.ShiftRightLogical(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.ShiftRightLogical(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.ShiftRightLogical(address); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.ShiftRightLogical(address); }),
/* 0x40 */
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 1); }),
/* 0x50 */
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 3); }),
/* 0x60 */
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 5); }),
/* 0x70 */
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.TestBit(address, 7); }),
/* 0x80 */
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.ResetBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.ResetBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.ResetBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.ResetBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.ResetBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.ResetBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.ResetBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.ResetBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.ResetBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.ResetBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.ResetBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.ResetBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.ResetBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.ResetBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.ResetBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.ResetBit(address, 1); }),
/* 0x90 */
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.ResetBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.ResetBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.ResetBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.ResetBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.ResetBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.ResetBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.ResetBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.ResetBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.ResetBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.ResetBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.ResetBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.ResetBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.ResetBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.ResetBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.ResetBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.ResetBit(address, 3); }),
/* 0xA0 */
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.ResetBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.ResetBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.ResetBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.ResetBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.ResetBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.ResetBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.ResetBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.ResetBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.ResetBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.ResetBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.ResetBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.ResetBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.ResetBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.ResetBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.ResetBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.ResetBit(address, 5); }),
/* 0xB0 */
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.ResetBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.ResetBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.ResetBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.ResetBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.ResetBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.ResetBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.ResetBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.ResetBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.ResetBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.ResetBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.ResetBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.ResetBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.ResetBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.ResetBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.ResetBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.ResetBit(address, 7); }),
/* 0xC0 */
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.SetBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.SetBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.SetBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.SetBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.SetBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.SetBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.SetBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.SetBit(address, 0); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.SetBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.SetBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.SetBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.SetBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.SetBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.SetBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.SetBit(address, 1); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.SetBit(address, 1); }),
/* 0xD0 */
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.SetBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.SetBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.SetBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.SetBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.SetBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.SetBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.SetBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.SetBit(address, 2); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.SetBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.SetBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.SetBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.SetBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.SetBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.SetBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.SetBit(address, 3); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.SetBit(address, 3); }),
/* 0xE0 */
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.SetBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.SetBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.SetBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.SetBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.SetBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.SetBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.SetBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.SetBit(address, 4); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.SetBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.SetBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.SetBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.SetBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.SetBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.SetBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.SetBit(address, 5); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.SetBit(address, 5); }),
/* 0xF0 */
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.SetBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.SetBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.SetBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.SetBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.SetBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.SetBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.SetBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.SetBit(address, 6); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.High = c.SetBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.bc.Low = c.SetBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.High = c.SetBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.de.Low = c.SetBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.High = c.SetBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.hl.Low = c.SetBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.SetBit(address, 7); }),
new DDFDCBOpcodeDelegate((Z80A c, ref Register r, ushort address) => { c.af.High = c.SetBit(address, 7); }),
};
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9f1c07a0773a3a94486e1d50ed7552cb

View File

@ -0,0 +1,281 @@
namespace Essgee.Emulation.CPU
{
public partial class Z80A
{
static SimpleOpcodeDelegate[] opcodesPrefixED = new SimpleOpcodeDelegate[]
{
/* 0x00 */
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
/* 0x10 */
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
/* 0x20 */
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
/* 0x30 */
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
/* 0x40 */
new SimpleOpcodeDelegate((c) => { c.PortInput(ref c.bc.High, c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.WritePort(c.bc.Low, c.bc.High); }),
new SimpleOpcodeDelegate((c) => { c.Subtract16(ref c.hl, c.bc.Word, true); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory16(c.ReadMemory16(c.pc), c.bc.Word); c.pc += 2; }),
new SimpleOpcodeDelegate((c) => { c.Negate(); }),
new SimpleOpcodeDelegate((c) => { c.iff1 = c.iff2; c.Return(); }),
new SimpleOpcodeDelegate((c) => { c.im = 0; }),
new SimpleOpcodeDelegate((c) => { c.i = c.af.High; }),
new SimpleOpcodeDelegate((c) => { c.PortInput(ref c.bc.Low, c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.WritePort(c.bc.Low, c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.Add16(ref c.hl, c.bc.Word, true); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister16(ref c.bc.Word, c.ReadMemory16(c.ReadMemory16(c.pc))); c.pc += 2; }),
new SimpleOpcodeDelegate((c) => { c.Negate(); }),
new SimpleOpcodeDelegate((c) => { c.Return(); c.iff1 = c.iff2; }),
new SimpleOpcodeDelegate((c) => { c.im = 0; }),
new SimpleOpcodeDelegate((c) => { c.r = c.af.High; }),
/* 0x50 */
new SimpleOpcodeDelegate((c) => { c.PortInput(ref c.de.High, c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.WritePort(c.bc.Low, c.de.High); }),
new SimpleOpcodeDelegate((c) => { c.Subtract16(ref c.hl, c.de.Word, true); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory16(c.ReadMemory16(c.pc), c.de.Word); c.pc += 2; }),
new SimpleOpcodeDelegate((c) => { c.Negate(); }),
new SimpleOpcodeDelegate((c) => { c.iff1 = c.iff2; c.Return(); }),
new SimpleOpcodeDelegate((c) => { c.im = 1; }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.af.High, c.i, true); }),
new SimpleOpcodeDelegate((c) => { c.PortInput(ref c.de.Low, c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.WritePort(c.bc.Low, c.de.Low); }),
new SimpleOpcodeDelegate((c) => { c.Add16(ref c.hl, c.de.Word, true); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister16(ref c.de.Word, c.ReadMemory16(c.ReadMemory16(c.pc))); c.pc += 2; }),
new SimpleOpcodeDelegate((c) => { c.Negate(); }),
new SimpleOpcodeDelegate((c) => { c.iff1 = c.iff2; c.Return(); }),
new SimpleOpcodeDelegate((c) => { c.im = 2; }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister8(ref c.af.High, c.r, true); }),
/* 0x60 */
new SimpleOpcodeDelegate((c) => { c.PortInput(ref c.hl.High, c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.WritePort(c.bc.Low, c.hl.High); }),
new SimpleOpcodeDelegate((c) => { c.Subtract16(ref c.hl, c.hl.Word, true); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory16(c.ReadMemory16(c.pc), c.hl.Word); c.pc += 2; }),
new SimpleOpcodeDelegate((c) => { c.Negate(); }),
new SimpleOpcodeDelegate((c) => { c.iff1 = c.iff2; c.Return(); }),
new SimpleOpcodeDelegate((c) => { c.im = 0; }),
new SimpleOpcodeDelegate((c) => { c.RotateRight4B(); }),
new SimpleOpcodeDelegate((c) => { c.PortInput(ref c.hl.Low, c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.WritePort(c.bc.Low, c.hl.Low); }),
new SimpleOpcodeDelegate((c) => { c.Add16(ref c.hl, c.hl.Word, true); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister16(ref c.hl.Word, c.ReadMemory16(c.ReadMemory16(c.pc))); c.pc += 2; }),
new SimpleOpcodeDelegate((c) => { c.Negate(); }),
new SimpleOpcodeDelegate((c) => { c.iff1 = c.iff2; c.Return(); }),
new SimpleOpcodeDelegate((c) => { c.im = 0; }),
new SimpleOpcodeDelegate((c) => { c.RotateLeft4B(); }),
/* 0x70 */
new SimpleOpcodeDelegate((c) => { c.PortInputFlagsOnly(c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.WritePort(c.bc.Low, 0x00); }),
new SimpleOpcodeDelegate((c) => { c.Subtract16(ref c.hl, c.sp, true); }),
new SimpleOpcodeDelegate((c) => { c.LoadMemory16(c.ReadMemory16(c.pc), c.sp); c.pc += 2; }),
new SimpleOpcodeDelegate((c) => { c.Negate(); }),
new SimpleOpcodeDelegate((c) => { c.iff1 = c.iff2; c.Return(); }),
new SimpleOpcodeDelegate((c) => { c.im = 1; }),
new SimpleOpcodeDelegate((c) => { /* NOP */ }),
new SimpleOpcodeDelegate((c) => { c.PortInput(ref c.af.High, c.bc.Low); }),
new SimpleOpcodeDelegate((c) => { c.WritePort(c.bc.Low, c.af.High); }),
new SimpleOpcodeDelegate((c) => { c.Add16(ref c.hl, c.sp, true); }),
new SimpleOpcodeDelegate((c) => { c.LoadRegister16(ref c.sp, c.ReadMemory16(c.ReadMemory16(c.pc))); c.pc += 2; }),
new SimpleOpcodeDelegate((c) => { c.Negate(); }),
new SimpleOpcodeDelegate((c) => { c.iff1 = c.iff2; c.Return(); }),
new SimpleOpcodeDelegate((c) => { c.im = 2; }),
new SimpleOpcodeDelegate((c) => { /* NOP */ }),
/* 0x80 */
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
/* 0x90 */
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
/* 0xA0 */
new SimpleOpcodeDelegate((c) => { c.LoadIncrement(); }),
new SimpleOpcodeDelegate((c) => { c.CompareIncrement(); }),
new SimpleOpcodeDelegate((c) => { c.PortInputIncrement(); }),
new SimpleOpcodeDelegate((c) => { c.PortOutputIncrement(); }),
new SimpleOpcodeDelegate((c) => { /* A4 - nothing */ }),
new SimpleOpcodeDelegate((c) => { /* A5 - nothing */ }),
new SimpleOpcodeDelegate((c) => { /* A6 - nothing */ }),
new SimpleOpcodeDelegate((c) => { /* A7 - nothing */ }),
new SimpleOpcodeDelegate((c) => { c.LoadDecrement(); }),
new SimpleOpcodeDelegate((c) => { c.CompareDecrement(); }),
new SimpleOpcodeDelegate((c) => { c.PortInputDecrement(); }),
new SimpleOpcodeDelegate((c) => { c.PortOutputDecrement(); }),
new SimpleOpcodeDelegate((c) => { /* AC - nothing */ }),
new SimpleOpcodeDelegate((c) => { /* AD - nothing */ }),
new SimpleOpcodeDelegate((c) => { /* AE - nothing */ }),
new SimpleOpcodeDelegate((c) => { /* AF - nothing */ }),
/* 0xB0 */
new SimpleOpcodeDelegate((c) => { c.LoadIncrementRepeat(); }),
new SimpleOpcodeDelegate((c) => { c.CompareIncrementRepeat(); }),
new SimpleOpcodeDelegate((c) => { c.PortInputIncrementRepeat(); }),
new SimpleOpcodeDelegate((c) => { c.PortOutputIncrementRepeat(); }),
new SimpleOpcodeDelegate((c) => { /* B4 - nothing */ }),
new SimpleOpcodeDelegate((c) => { /* B5 - nothing */ }),
new SimpleOpcodeDelegate((c) => { /* B6 - nothing */ }),
new SimpleOpcodeDelegate((c) => { /* B7 - nothing */ }),
new SimpleOpcodeDelegate((c) => { c.LoadDecrementRepeat(); }),
new SimpleOpcodeDelegate((c) => { c.CompareDecrementRepeat(); }),
new SimpleOpcodeDelegate((c) => { c.PortInputDecrementRepeat(); }),
new SimpleOpcodeDelegate((c) => { c.PortOutputDecrementRepeat(); }),
new SimpleOpcodeDelegate((c) => { /* BC - nothing */ }),
new SimpleOpcodeDelegate((c) => { /* BD - nothing */ }),
new SimpleOpcodeDelegate((c) => { /* BE - nothing */ }),
new SimpleOpcodeDelegate((c) => { /* BF - nothing */ }),
/* 0xC0 */
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
/* 0xD0 */
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
/* 0xE0 */
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
/* 0xF0 */
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ }),
new SimpleOpcodeDelegate((c) => { /* NOP (2x) */ })
};
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 5a8dae171d8e67546b93ab06aafbcb53

View File

@ -0,0 +1,25 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Essgee.Emulation.CPU
{
public partial class Z80A
{
[DebuggerDisplay("{Word}")]
[StructLayout(LayoutKind.Explicit)]
[Serializable]
public struct Register
{
[NonSerialized]
[FieldOffset(0)]
public byte Low;
[NonSerialized]
[FieldOffset(1)]
public byte High;
[FieldOffset(0)]
public ushort Word;
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 09764bf46e9451741a9fa2016022c5ea

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 02ea1ee0691d94f4ba12b23ecea75623

View File

@ -0,0 +1,78 @@
using Essgee.Emulation.Machines;
using Essgee.Exceptions;
using Essgee.Utilities;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
namespace Essgee.Emulation
{
public static class CartridgeLoader
{
static Dictionary<string, Type> fileExtensionSystemDictionary;
static CartridgeLoader()
{
fileExtensionSystemDictionary = new Dictionary<string, Type>();
foreach (var machineType in Assembly.GetExecutingAssembly().GetTypes().Where(x => typeof(IMachine).IsAssignableFrom(x) && !x.IsInterface).OrderBy(x => x.GetCustomAttribute<MachineIndexAttribute>()?.Index))
{
if (machineType == null) continue;
var instance = (IMachine)Activator.CreateInstance(machineType);
foreach (var extension in instance.FileFilter.Extension.Split(';'))
fileExtensionSystemDictionary.Add(extension, machineType);
}
}
public static (Type, byte[]) Load(string fileName, string fileType)
{
Type machineType = null;
byte[] romData = null;
if (!File.Exists(fileName))
throw new CartridgeLoaderException($"{fileType} file not found.");
try
{
var fileExtension = Path.GetExtension(fileName);
if (fileExtension == ".zip")
{
using (var zip = ZipFile.Open(fileName, ZipArchiveMode.Read))
{
foreach (var entry in zip.Entries)
{
var entryExtension = Path.GetExtension(entry.Name);
if (fileExtensionSystemDictionary.ContainsKey(entryExtension))
{
machineType = fileExtensionSystemDictionary[entryExtension];
using (var stream = entry.Open())
{
romData = new byte[entry.Length];
stream.Read(romData, 0, romData.Length);
}
break;
}
}
}
}
else if (fileExtensionSystemDictionary.ContainsKey(fileExtension))
{
machineType = fileExtensionSystemDictionary[fileExtension];
romData = File.ReadAllBytes(fileName);
}
}
catch (Exception ex) when (!AppEnvironment.DebugMode)
{
throw new CartridgeLoaderException("File load error", ex);
}
if (machineType == null)
throw new CartridgeLoaderException($"File could not be recognized as {fileType}.");
return (machineType, romData);
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f1b72196f7ea1bf41b9b580316878200

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fd37849c4f2dfbb4fa2e82cdc6fc36e3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3f9cb94bc81a41e45a844926b14f89eb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,78 @@
using System;
namespace Essgee.Emulation.Cartridges.Coleco
{
public class ColecoCartridge : ICartridge
{
// TODO: http://atariage.com/forums/topic/210168-colecovision-bank-switching/ ?
byte[] romData;
public ColecoCartridge(int romSize, int ramSize)
{
romData = new byte[romSize];
}
public void LoadRom(byte[] data)
{
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
}
public void LoadRam(byte[] data)
{
//
}
public byte[] GetRomData()
{
return romData;
}
public byte[] GetRamData()
{
return null;
}
public bool IsRamSaveNeeded()
{
return false;
}
public ushort GetLowerBound()
{
return 0x0000;
}
public ushort GetUpperBound()
{
return (ushort)(romData.Length - 1);
}
public void Step(int clockCyclesInStep)
{
/* Nothing to do */
}
public byte Read(ushort address)
{
if (address <= 0x1FFF)
{
/* BIOS */
return romData[address & 0x1FFF];
}
else
{
/* Cartridge */
address -= 0x8000;
if (address >= romData.Length) address -= (ushort)romData.Length;
return romData[address];
}
}
public void Write(ushort address, byte value)
{
/* Cannot write to cartridge */
return;
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9d70811b8aea410499364dc0485491e3

View File

@ -0,0 +1,20 @@
namespace Essgee.Emulation.Cartridges
{
public interface ICartridge
{
void LoadRom(byte[] data);
void LoadRam(byte[] data);
byte[] GetRomData();
byte[] GetRamData();
bool IsRamSaveNeeded();
ushort GetLowerBound();
ushort GetUpperBound();
void Step(int clockCyclesInStep);
byte Read(ushort address);
void Write(ushort address, byte value);
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 69d4af746d98c1b4ab29d5be6b2d9f2d

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3eb99a6b5fa5ea348b79aa6dfc080f12
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,421 @@
using System;
using System.ComponentModel;
using System.Linq;
namespace Essgee.Emulation.Cartridges.Nintendo
{
/* Image processing, etc. based on https://github.com/AntonioND/gbcam-rev-engineer/blob/master/doc/gb_camera_doc_v1_1_1.pdf */
public class GBCameraCartridge : IGameBoyCartridge
{
const int camSensorExtraLines = 8;
const int camSensorWidth = 128;
const int camSensorHeight = 112 + camSensorExtraLines;
const int camWidth = 128;
const int camHeight = 112;
static readonly float[] edgeRatioLookUpTable = new float[] { 0.50f, 0.75f, 1.00f, 1.25f, 2.00f, 3.00f, 4.00f, 5.00f };
public enum ImageSources
{
[Description("Random Noise")]
Noise,
[Description("Image File")]
File
}
ImageSources imageSourceType;
//Bitmap scaledImage;
readonly int[,] webcamOutput, camRetinaOutput;
readonly byte[,,] tileBuffer;
byte[] romData, ramData;
bool hasBattery;
byte romBank, ramBank;
bool ramEnable;
readonly byte[] camRegisters;
bool camSelected;
int cameraCycles, camClocksLeft;
public GBCameraCartridge(int romSize, int ramSize)
{
imageSourceType = ImageSources.Noise;
//scaledImage = new Bitmap(camSensorWidth, camSensorHeight);
webcamOutput = new int[camSensorWidth, camSensorHeight];
camRetinaOutput = new int[camSensorWidth, camSensorHeight];
tileBuffer = new byte[14, 16, 16];
romData = new byte[romSize];
ramData = new byte[ramSize];
romBank = 1;
ramBank = 0;
ramEnable = false;
camRegisters = new byte[0x80]; // 0x36 used
camSelected = false;
hasBattery = false;
}
public void LoadRom(byte[] data)
{
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
}
public void LoadRam(byte[] data)
{
Buffer.BlockCopy(data, 0, ramData, 0, Math.Min(data.Length, ramData.Length));
}
public byte[] GetRomData()
{
return romData;
}
public byte[] GetRamData()
{
return ramData;
}
public bool IsRamSaveNeeded()
{
return hasBattery;
}
public ushort GetLowerBound()
{
return 0x0000;
}
public ushort GetUpperBound()
{
return 0x7FFF;
}
public void SetCartridgeConfig(bool battery, bool rtc, bool rumble)
{
hasBattery = battery;
}
public void SetImageSource(ImageSources source, string filename)
{
imageSourceType = source;
if (imageSourceType == ImageSources.File)
{
//TODO imageSourceType == ImageSources.File
//using (var tempImage = new Bitmap(filename))
//{
// using (var g = System.Drawing.Graphics.FromImage(scaledImage))
// {
// var ratio = Math.Min(tempImage.Width / (float)camSensorWidth, tempImage.Height / (float)camSensorHeight);
// var srcWidth = (int)(camSensorWidth * ratio);
// var srcHeight = (int)(camSensorHeight * ratio);
// var srcX = (tempImage.Width - srcWidth) / 2;
// var srcY = (tempImage.Height - srcHeight) / 2;
// var scaledRect = new Rectangle(0, 0, camSensorWidth, camSensorHeight);
// g.FillRectangle(Brushes.White, scaledRect);
// g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
// g.DrawImage(tempImage, scaledRect, new Rectangle(srcX, srcY, srcWidth, srcHeight), GraphicsUnit.Pixel);
// }
//}
//for (var x = 0; x < camSensorWidth; x++)
// for (var y = 0; y < camSensorHeight; y++)
// webcamOutput[x, y] = (int)(scaledImage.GetPixel(x, y).GetBrightness() * 255);
}
}
public void Step(int clockCyclesInStep)
{
cameraCycles += clockCyclesInStep;
if (cameraCycles >= camClocksLeft)
{
camRegisters[0x00] &= 0xFE;
cameraCycles = 0;
}
}
public byte Read(ushort address)
{
if (address >= 0x0000 && address <= 0x3FFF)
{
return romData[address & 0x3FFF];
}
else if (address >= 0x4000 && address <= 0x7FFF)
{
return romData[(romBank << 14) | (address & 0x3FFF)];
}
else if (address >= 0xA000 && address <= 0xBFFF)
{
if (!camSelected)
{
if ((camRegisters[0x00] & 0b1) == 0)
return ramData[(ramBank << 13) | (address & 0x1FFF)];
else
return 0xFF;
}
else
{
var reg = (byte)(address & 0x7F);
if (reg == 0x00)
return (byte)(camRegisters[reg] & 0x07);
else
return 0xFF;
}
}
else
return 0xFF;
}
public void Write(ushort address, byte value)
{
if (address >= 0x0000 && address <= 0x1FFF)
{
ramEnable = (value & 0x0F) == 0x0A;
}
else if (address >= 0x2000 && address <= 0x3FFF)
{
romBank = (byte)((romBank & 0xC0) | (value & 0x3F));
romBank &= (byte)((romData.Length >> 14) - 1);
if ((romBank & 0x3F) == 0x00) romBank |= 0x01;
}
else if (address >= 0x4000 && address <= 0x5FFF)
{
if ((value & 0x10) != 0)
{
camSelected = true;
}
else
{
camSelected = false;
ramBank = (byte)(value & 0x0F);
}
}
else if (address >= 0xA000 && address <= 0xBFFF)
{
if (!camSelected)
{
if (ramEnable)
ramData[(ramBank << 13) | (address & 0x1FFF)] = value;
}
else
{
var reg = (byte)(address & 0x7F);
if (reg == 0x00 && (value & 0b1) != 0)
GenerateImage();
camRegisters[reg] = value;
}
}
}
private int Clamp(int value, int min, int max)
{
if (value < min) value = min;
else if (value > max) value = max;
return value;
}
private void GenerateImage()
{
/* Get configuration -- register 0 */
var pBits = 0;
var mBits = 0;
switch ((camRegisters[0x00] >> 1) & 0b11)
{
case 0: pBits = 0x00; mBits = 0x01; break;
case 1: pBits = 0x01; mBits = 0x00; break;
case 2:
case 3: pBits = 0x01; mBits = 0x02; break;
}
/* Register 1 */
var nBit = ((camRegisters[0x01] >> 7) & 0b1) != 0;
var vhBits = (camRegisters[0x01] >> 5) & 0b11;
/* Registers 2 and 3 */
var exposureBits = camRegisters[0x02] << 8 | camRegisters[0x03];
/* Register 4 */
var edgeAlpha = edgeRatioLookUpTable[(camRegisters[0x04] >> 4) & 0b111];
var e3Bit = ((camRegisters[0x04] >> 7) & 0b1) != 0;
var iBit = ((camRegisters[0x04] >> 3) & 0b1) != 0;
/* Calculate timings */
camClocksLeft = 4 * (32446 + (nBit ? 0 : 512) + 16 * exposureBits);
/* Clear tile buffer */
for (var j = 0; j < 14; j++)
for (var i = 0; i < 16; i++)
for (var k = 0; k < 16; k++)
tileBuffer[j, i, k] = 0x00;
/* Sensor handling */
/* Copy webcam buffer to sensor buffer, apply color correction & exposure time */
for (var i = 0; i < camSensorWidth; i++)
{
for (var j = 0; j < camSensorHeight; j++)
{
var value = 0;
switch (imageSourceType)
{
case ImageSources.File: value = webcamOutput[i, j]; break;
case ImageSources.Noise: value = EmuStandInfo.Random.Next(255); break;
}
value = (value * exposureBits) / 0x0300;
value = 128 + (((value - 128) * 1) / 8);
camRetinaOutput[i, j] = Clamp(value, 0, 255);
/* Invert */
if (iBit)
camRetinaOutput[i, j] = 255 - camRetinaOutput[i, j];
/* Make signed */
camRetinaOutput[i, j] = camRetinaOutput[i, j] - 128;
}
}
var tempBuffer = new int[camSensorWidth, camSensorHeight];
var filteringMode = (nBit ? 8 : 0) | (vhBits << 1) | (e3Bit ? 1 : 0);
switch (filteringMode)
{
case 0x00:
/* 1-D filtering */
for (var i = 0; i < camSensorWidth; i++)
for (var j = 0; j < camSensorHeight; j++)
tempBuffer[i, j] = camRetinaOutput[i, j];
for (var i = 0; i < camSensorWidth; i++)
{
for (var j = 0; j < camSensorHeight; j++)
{
var ms = tempBuffer[i, Math.Min(j + 1, camSensorHeight - 1)];
var px = tempBuffer[i, j];
var value = 0;
if ((pBits & 0b01) != 0) value += px;
if ((pBits & 0b10) != 0) value += ms;
if ((mBits & 0b01) != 0) value -= px;
if ((mBits & 0b10) != 0) value -= ms;
camRetinaOutput[i, j] = Clamp(value, -128, 127);
}
}
break;
case 0x02:
/* 1-D filtering + Horiz. enhancement : P + {2P-(MW+ME)} * alpha */
for (var i = 0; i < camSensorWidth; i++)
{
for (var j = 0; j < camSensorHeight; j++)
{
var mw = camRetinaOutput[Math.Max(0, i - 1), j];
var me = camRetinaOutput[Math.Min(i + 1, camSensorWidth - 1), j];
var px = camRetinaOutput[i, j];
tempBuffer[i, j] = Clamp((int)(px + ((2 * px - mw - me) * edgeAlpha)), 0, 255);
}
}
for (var i = 0; i < camSensorWidth; i++)
{
for (var j = 0; j < camSensorHeight; j++)
{
var ms = tempBuffer[i, Math.Min(j + 1, camSensorHeight - 1)];
var px = tempBuffer[i, j];
var value = 0;
if ((pBits & 0b01) != 0) value += px;
if ((pBits & 0b10) != 0) value += ms;
if ((mBits & 0b01) != 0) value -= px;
if ((mBits & 0b10) != 0) value -= ms;
camRetinaOutput[i, j] = Clamp(value, -128, 127);
}
}
break;
case 0x0E:
/* 2D enhancement : P + {4P-(MN+MS+ME+MW)} * alpha */
for (var i = 0; i < camSensorWidth; i++)
{
for (var j = 0; j < camSensorHeight; j++)
{
var ms = camRetinaOutput[i, Math.Min(j + 1, camSensorHeight - 1)];
var mn = camRetinaOutput[i, Math.Max(0, j - 1)];
var mw = camRetinaOutput[Math.Max(0, i - 1), j];
var me = camRetinaOutput[Math.Min(i + 1, camSensorWidth - 1), j];
var px = camRetinaOutput[i, j];
tempBuffer[i, j] = Clamp((int)(px + ((4 * px - mw - me - mn - ms) * edgeAlpha)), -128, 127);
}
}
for (var i = 0; i < camSensorWidth; i++)
for (var j = 0; j < camSensorHeight; j++)
camRetinaOutput[i, j] = tempBuffer[i, j];
break;
case 0x01:
/* Unknown, always same color; sensor datasheet does not document this, maybe a bug? */
for (var i = 0; i < camSensorWidth; i++)
for (var j = 0; j < camSensorHeight; j++)
camRetinaOutput[i, j] = 0;
break;
default:
/* Unknown; write to log if enabled */
if (AppEnvironment.EnableLogger)
{
EssgeeLogger.WriteLine($"Unsupported GB Camera mode 0x{filteringMode:X2}");
EssgeeLogger.WriteLine(string.Join(" ", camRegisters.Take(6).Select(x => $"0x{x:X2}")));
}
break;
}
/* Make unsigned */
for (var i = 0; i < camSensorWidth; i++)
for (var j = 0; j < camSensorHeight; j++)
camRetinaOutput[i, j] = camRetinaOutput[i, j] + 128;
/* Convert output to GB tiles */
for (var i = 0; i < camWidth; i++)
{
for (var j = 0; j < camHeight; j++)
{
var sensorValue = camRetinaOutput[i, j + (camSensorExtraLines / 2)];
var matrixOffset = 0x06 + ((j % 4) * 12) + ((i % 4) * 3);
var c = (byte)0;
if (sensorValue < camRegisters[matrixOffset + 0]) c = 3;
else if (sensorValue < camRegisters[matrixOffset + 1]) c = 2;
else if (sensorValue < camRegisters[matrixOffset + 2]) c = 1;
else c = 0;
if ((c & 1) != 0) tileBuffer[j >> 3, i >> 3, ((j & 7) * 2) + 0] |= (byte)(1 << (7 - (7 & i)));
if ((c & 2) != 0) tileBuffer[j >> 3, i >> 3, ((j & 7) * 2) + 1] |= (byte)(1 << (7 - (7 & i)));
}
}
/* Copy tiles to cartridge RAM */
int outputOffset = 0x100;
for (var j = 0; j < 14; j++)
for (var i = 0; i < 16; i++)
for (var k = 0; k < 16; k++)
ramData[outputOffset++] = tileBuffer[j, i, k];
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 3887c3ff437835449bdf694c3e812afa

View File

@ -0,0 +1,7 @@
namespace Essgee.Emulation.Cartridges.Nintendo
{
public interface IGameBoyCartridge : ICartridge
{
void SetCartridgeConfig(bool battery, bool rtc, bool rumble);
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8f215e1ba8582ab42b21a0dae809cb6e

View File

@ -0,0 +1,132 @@
using System;
namespace Essgee.Emulation.Cartridges.Nintendo
{
public class MBC1Cartridge : IGameBoyCartridge
{
byte[] romData, ramData;
bool hasBattery;
byte romBank, ramBank;
bool ramEnable;
byte bankingMode;
public MBC1Cartridge(int romSize, int ramSize)
{
romData = new byte[romSize];
ramData = new byte[ramSize];
romBank = 1;
ramBank = 0;
ramEnable = false;
bankingMode = 0;
hasBattery = false;
}
public void LoadRom(byte[] data)
{
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
}
public void LoadRam(byte[] data)
{
Buffer.BlockCopy(data, 0, ramData, 0, Math.Min(data.Length, ramData.Length));
}
public byte[] GetRomData()
{
return romData;
}
public byte[] GetRamData()
{
return ramData;
}
public bool IsRamSaveNeeded()
{
return hasBattery;
}
public ushort GetLowerBound()
{
return 0x0000;
}
public ushort GetUpperBound()
{
return 0x7FFF;
}
public void SetCartridgeConfig(bool battery, bool rtc, bool rumble)
{
hasBattery = battery;
}
public void Step(int clockCyclesInStep)
{
/* Nothing to do */
}
public byte Read(ushort address)
{
if (address >= 0x0000 && address <= 0x3FFF)
{
return romData[address & 0x3FFF];
}
else if (address >= 0x4000 && address <= 0x7FFF)
{
return romData[(romBank << 14) | (address & 0x3FFF)];
}
else if (address >= 0xA000 && address <= 0xBFFF)
{
if (ramEnable && ramData.Length != 0)
return ramData[(ramBank << 13) | (address & 0x1FFF)];
else
return 0xFF;
}
else
return 0xFF;
}
public void Write(ushort address, byte value)
{
if (address >= 0x0000 && address <= 0x1FFF)
{
ramEnable = (value & 0x0F) == 0x0A;
}
else if (address >= 0x2000 && address <= 0x3FFF)
{
romBank = (byte)((romBank & 0xE0) | (value & 0x1F));
romBank &= (byte)((romData.Length >> 14) - 1);
if ((romBank & 0x1F) == 0x00) romBank |= 0x01;
}
else if (address >= 0x4000 && address <= 0x5FFF)
{
if (bankingMode == 0)
{
romBank = (byte)((romBank & 0x9F) | ((value & 0x03) << 5));
romBank &= (byte)((romData.Length >> 14) - 1);
if ((romBank & 0x1F) == 0x00) romBank |= 0x01;
}
else
{
ramBank = (byte)(value & 0x03);
}
}
else if (address >= 0x6000 && address <= 0x7FFF)
{
bankingMode = (byte)(value & 0b1);
}
else if (address >= 0xA000 && address <= 0xBFFF)
{
if (ramEnable && ramData.Length != 0)
ramData[(ramBank << 13) | (address & 0x1FFF)] = value;
}
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9e0eda098544f8e4aa894031f92b2b57

View File

@ -0,0 +1,123 @@
using System;
namespace Essgee.Emulation.Cartridges.Nintendo
{
public class MBC2Cartridge : IGameBoyCartridge
{
byte[] romData, ramData;
bool hasBattery;
byte romBank;
bool ramEnable;
public MBC2Cartridge(int romSize, int ramSize)
{
romData = new byte[romSize];
ramData = new byte[ramSize];
romBank = 1;
ramEnable = false;
hasBattery = false;
}
public void LoadRom(byte[] data)
{
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
}
public void LoadRam(byte[] data)
{
Buffer.BlockCopy(data, 0, ramData, 0, Math.Min(data.Length, ramData.Length));
}
public byte[] GetRomData()
{
return romData;
}
public byte[] GetRamData()
{
return ramData;
}
public bool IsRamSaveNeeded()
{
return hasBattery;
}
public ushort GetLowerBound()
{
return 0x0000;
}
public ushort GetUpperBound()
{
return 0x7FFF;
}
public void SetCartridgeConfig(bool battery, bool rtc, bool rumble)
{
hasBattery = battery;
}
public void Step(int clockCyclesInStep)
{
/* Nothing to do */
}
public byte Read(ushort address)
{
if (address >= 0x0000 && address <= 0x3FFF)
{
return romData[address & 0x3FFF];
}
else if (address >= 0x4000 && address <= 0x7FFF)
{
return romData[(romBank << 14) | (address & 0x3FFF)];
}
else if (address >= 0xA000 && address <= 0xA1FF)
{
if (ramEnable)
{
var ramOffset = (address >> 1) & 0x00FF;
var valueShift = (address & 0x01) << 2;
return (byte)((ramData[ramOffset] >> valueShift) & 0x0F);
}
else
return 0xFF;
}
else
return 0xFF;
}
public void Write(ushort address, byte value)
{
if (address >= 0x0000 && address <= 0x1FFF)
{
if ((address & 0x0100) == 0)
ramEnable = (value & 0x0F) == 0x0A;
}
else if (address >= 0x2000 && address <= 0x3FFF)
{
if ((address & 0x0100) != 0)
{
romBank = (byte)((romBank & 0xF0) | (value & 0x0F));
romBank &= (byte)((romData.Length >> 14) - 1);
if ((romBank & 0x0F) == 0x00) romBank |= 0x01;
}
}
else if (address >= 0xA000 && address <= 0xA1FF)
{
if (ramEnable)
{
var ramOffset = (address >> 1) & 0x00FF;
var valueShift = (address & 0x01) << 2;
ramData[ramOffset] = (byte)((ramData[ramOffset] & (0x0F << (valueShift ^ 0x04))) | (value << valueShift));
}
}
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b5795dc3ee1b33746a64186a778e2bd6

View File

@ -0,0 +1,261 @@
using System;
using System.Linq;
namespace Essgee.Emulation.Cartridges.Nintendo
{
public class MBC3Cartridge : IGameBoyCartridge
{
// https://thomas.spurden.name/gameboy/#mbc3-real-time-clock-rtc
public class RTC
{
public const int NumRegisters = 0x05;
public byte[] BaseRegisters { get; private set; }
public byte[] LatchedRegisters { get; private set; }
public DateTime BaseTime { get; set; }
public bool IsSelected { get; set; }
public byte SelectedRegister { get; set; }
public bool IsLatched { get; set; }
public RTC()
{
BaseRegisters = new byte[NumRegisters];
LatchedRegisters = new byte[NumRegisters];
BaseTime = DateTime.Now;
IsSelected = false;
SelectedRegister = 0;
IsLatched = false;
}
public void FromSaveData(byte[] ramData)
{
var rtcOffset = ramData.Length - 0x30;
// Time
BaseRegisters[0x00] = ramData[rtcOffset + 0];
BaseRegisters[0x01] = ramData[rtcOffset + 4];
BaseRegisters[0x02] = ramData[rtcOffset + 8];
BaseRegisters[0x03] = ramData[rtcOffset + 12];
BaseRegisters[0x04] = ramData[rtcOffset + 16];
// Latched time
LatchedRegisters[0x00] = ramData[rtcOffset + 20];
LatchedRegisters[0x01] = ramData[rtcOffset + 24];
LatchedRegisters[0x02] = ramData[rtcOffset + 28];
LatchedRegisters[0x03] = ramData[rtcOffset + 32];
LatchedRegisters[0x04] = ramData[rtcOffset + 36];
// Timestamp
BaseTime = DateTimeOffset.FromUnixTimeSeconds((long)BitConverter.ToUInt64(ramData, rtcOffset + 40)).UtcDateTime;
}
public byte[] ToSaveData()
{
var appendData = new byte[0x30];
// Time
appendData[0] = BaseRegisters[0x00];
appendData[4] = BaseRegisters[0x01];
appendData[8] = BaseRegisters[0x02];
appendData[12] = BaseRegisters[0x03];
appendData[16] = BaseRegisters[0x04];
// Latched time
appendData[20] = LatchedRegisters[0x00];
appendData[24] = LatchedRegisters[0x01];
appendData[28] = LatchedRegisters[0x02];
appendData[32] = LatchedRegisters[0x03];
appendData[36] = LatchedRegisters[0x04];
// Timestamp
var timestamp = BitConverter.GetBytes(((DateTimeOffset)BaseTime).ToUnixTimeSeconds());
for (var i = 0; i < timestamp.Length; i++) appendData[40 + i] = timestamp[i];
return appendData;
}
public void Update()
{
// GOLD,38695,3000 == 00931
var currentTime = DateTime.Now;
var newTime = currentTime;
if (((BaseRegisters[0x04] >> 6) & 0b1) == 0 && currentTime > BaseTime)
newTime.Add(currentTime - BaseTime);
newTime.AddSeconds(BaseRegisters[0x00]);
newTime.AddMinutes(BaseRegisters[0x01]);
newTime.AddHours(BaseRegisters[0x02]);
newTime.AddDays(BaseRegisters[0x03]);
newTime.AddDays((BaseRegisters[0x04] & 0b1) << 8);
BaseRegisters[0x00] = (byte)newTime.Second;
BaseRegisters[0x01] = (byte)newTime.Minute;
BaseRegisters[0x02] = (byte)newTime.Hour;
BaseRegisters[0x03] = (byte)(newTime.Day & 0xFF);
BaseRegisters[0x04] = (byte)((BaseRegisters[0x04] & 0xFE) | ((newTime.Day >> 8) & 0b1) | ((newTime.Day >> 8) & 0b1) << 7);
BaseTime = currentTime;
}
}
byte[] romData, ramData;
bool hasBattery, hasRTC;
byte romBank, ramBank;
bool ramEnable;
RTC rtc;
public MBC3Cartridge(int romSize, int ramSize)
{
romData = new byte[romSize];
ramData = new byte[ramSize];
hasBattery = false;
hasRTC = false;
romBank = 1;
ramBank = 0;
ramEnable = false;
rtc = new RTC();
}
public void LoadRom(byte[] data)
{
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
}
public void LoadRam(byte[] data)
{
/* Has appended RTC state data? */
if ((data.Length & 0x30) == 0x30) rtc.FromSaveData(data);
Buffer.BlockCopy(data, 0, ramData, 0, Math.Min(data.Length, ramData.Length));
}
public byte[] GetRomData()
{
return romData;
}
public byte[] GetRamData()
{
if (hasRTC)
return ramData.Concat(rtc.ToSaveData()).ToArray();
else
return ramData;
}
public bool IsRamSaveNeeded()
{
return hasBattery;
}
public ushort GetLowerBound()
{
return 0x0000;
}
public ushort GetUpperBound()
{
return 0x7FFF;
}
public void SetCartridgeConfig(bool battery, bool rtc, bool rumble)
{
hasBattery = battery;
hasRTC = rtc;
}
public void Step(int clockCyclesInStep)
{
/* Nothing to do */
}
public byte Read(ushort address)
{
if (address >= 0x0000 && address <= 0x3FFF)
{
return romData[address & 0x3FFF];
}
else if (address >= 0x4000 && address <= 0x7FFF)
{
return romData[(romBank << 14) | (address & 0x3FFF)];
}
else if (address >= 0xA000 && address <= 0xBFFF)
{
if (rtc.IsSelected)
{
if (rtc.IsLatched)
return rtc.LatchedRegisters[rtc.SelectedRegister];
else
return rtc.BaseRegisters[rtc.SelectedRegister];
}
else if (ramEnable)
return ramData[(ramBank << 13) | (address & 0x1FFF)];
else
return 0xFF;
}
else
return 0xFF;
}
public void Write(ushort address, byte value)
{
if (address >= 0x0000 && address <= 0x1FFF)
{
ramEnable = (value & 0x0F) == 0x0A;
}
else if (address >= 0x2000 && address <= 0x3FFF)
{
romBank = (byte)((romBank & 0x80) | (value & 0x7F));
romBank &= (byte)((romData.Length >> 14) - 1);
if (romBank == 0x00) romBank = 0x01;
}
else if (address >= 0x4000 && address <= 0x5FFF)
{
if (value >= 0x00 && value <= 0x07)
{
rtc.IsSelected = false;
ramBank = (byte)(value & 0x07);
}
else if (value >= 0x08 && value <= 0x0C)
{
rtc.IsSelected = true;
rtc.SelectedRegister = (byte)(value - 0x08);
}
}
else if (address >= 0x6000 && address <= 0x7FFF)
{
if (value == 0x00 && rtc.IsLatched)
rtc.IsLatched = false;
else if (value == 0x01 && !rtc.IsLatched)
{
rtc.Update();
for (var i = 0; i < RTC.NumRegisters; i++)
rtc.LatchedRegisters[i] = rtc.BaseRegisters[i];
rtc.IsLatched = true;
}
}
else if (address >= 0xA000 && address <= 0xBFFF)
{
if (rtc.IsSelected)
{
rtc.Update();
rtc.BaseRegisters[rtc.SelectedRegister] = value;
}
else if (ramEnable)
ramData[(ramBank << 13) | (address & 0x1FFF)] = value;
}
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 739832bbd2b7ce54e8658790d0d1b4ae

View File

@ -0,0 +1,137 @@
using System;
namespace Essgee.Emulation.Cartridges.Nintendo
{
// TODO: rumble?
public class MBC5Cartridge : IGameBoyCartridge
{
public event EventHandler<EventArgs> EnableRumble;
protected virtual void OnEnableRumble(EventArgs e) { EnableRumble?.Invoke(this, EventArgs.Empty); }
byte[] romData, ramData;
bool hasBattery, hasRumble;
ushort romBank;
byte ramBank;
bool ramEnable;
public MBC5Cartridge(int romSize, int ramSize)
{
romData = new byte[romSize];
ramData = new byte[ramSize];
romBank = 1;
ramBank = 0;
ramEnable = false;
hasBattery = false;
hasRumble = false;
}
public void LoadRom(byte[] data)
{
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
}
public void LoadRam(byte[] data)
{
Buffer.BlockCopy(data, 0, ramData, 0, Math.Min(data.Length, ramData.Length));
}
public byte[] GetRomData()
{
return romData;
}
public byte[] GetRamData()
{
return ramData;
}
public bool IsRamSaveNeeded()
{
return hasBattery;
}
public ushort GetLowerBound()
{
return 0x0000;
}
public ushort GetUpperBound()
{
return 0x7FFF;
}
public void SetCartridgeConfig(bool battery, bool rtc, bool rumble)
{
hasBattery = battery;
hasRumble = rumble;
}
public void Step(int clockCyclesInStep)
{
/* Nothing to do */
}
public byte Read(ushort address)
{
if (address >= 0x0000 && address <= 0x3FFF)
{
return romData[address & 0x3FFF];
}
else if (address >= 0x4000 && address <= 0x7FFF)
{
return romData[(romBank << 14) | (address & 0x3FFF)];
}
else if (address >= 0xA000 && address <= 0xBFFF)
{
if (ramEnable && ramData.Length != 0)
return ramData[(ramBank << 13) | (address & 0x1FFF)];
else
return 0xFF;
}
else
return 0xFF;
}
public void Write(ushort address, byte value)
{
if (address >= 0x0000 && address <= 0x1FFF)
{
ramEnable = (value & 0x0F) == 0x0A;
}
else if (address >= 0x2000 && address <= 0x2FFF)
{
romBank = (ushort)((romBank & 0x0100) | value);
romBank &= (ushort)((romData.Length >> 14) - 1);
}
else if (address >= 0x3000 && address <= 0x3FFF)
{
romBank = (ushort)((romBank & 0x00FF) | ((value & 0x01) << 8));
romBank &= (ushort)((romData.Length >> 14) - 1);
}
else if (address >= 0x4000 && address <= 0x5FFF)
{
if (hasRumble)
{
if ((value & 0x08) == 0x08) OnEnableRumble(EventArgs.Empty);
ramBank = (byte)(value & 0x07);
ramBank %= (byte)(ramData.Length >> 13);
}
else
{
ramBank = (byte)(value & 0x0F);
ramBank %= (byte)(ramData.Length >> 13);
}
}
else if (address >= 0xA000 && address <= 0xBFFF)
{
if (ramEnable && ramData.Length != 0)
ramData[(ramBank << 13) | (address & 0x1FFF)] = value;
}
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f083c0cfa9c1cf54ba90f19320c53c16

View File

@ -0,0 +1,77 @@
using System;
namespace Essgee.Emulation.Cartridges.Nintendo
{
public class NoMapperCartridge : IGameBoyCartridge
{
byte[] romData, ramData;
bool hasBattery;
public NoMapperCartridge(int romSize, int ramSize)
{
romData = new byte[romSize];
ramData = new byte[ramSize];
}
public void LoadRom(byte[] data)
{
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
}
public void LoadRam(byte[] data)
{
Buffer.BlockCopy(data, 0, ramData, 0, Math.Min(data.Length, ramData.Length));
}
public byte[] GetRomData()
{
return romData;
}
public byte[] GetRamData()
{
return ramData;
}
public bool IsRamSaveNeeded()
{
return hasBattery;
}
public ushort GetLowerBound()
{
return 0x0000;
}
public ushort GetUpperBound()
{
return 0x7FFF;
}
public void Step(int clockCyclesInStep)
{
/* Nothing to do */
}
public void SetCartridgeConfig(bool battery, bool rtc, bool rumble)
{
hasBattery = battery;
}
public byte Read(ushort address)
{
if (address >= 0x0000 && address <= 0x7FFF)
return romData[address & 0x7FFF];
else if (address >= 0xA000 && address <= 0xBFFF)
return ramData[address & 0x1FFF];
else
return 0xFF;
}
public void Write(ushort address, byte value)
{
if (address >= 0xA000 && address <= 0xBFFF)
ramData[address & 0x1FFF] = value;
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 90768449a6b38a440b08bb61118b37b7

View File

@ -0,0 +1,101 @@
using Essgee.Exceptions;
using System;
namespace Essgee.Emulation.Cartridges.Nintendo
{
public static class SpecializedLoader
{
public static IGameBoyCartridge CreateCartridgeInstance(byte[] romData, byte[] ramData, Type mapperType)
{
var romSize = -1;
switch (romData[0x0148])
{
case 0x00: romSize = 32 * 1024; break;
case 0x01: romSize = 64 * 1024; break;
case 0x02: romSize = 128 * 1024; break;
case 0x03: romSize = 256 * 1024; break;
case 0x04: romSize = 512 * 1024; break;
case 0x05: romSize = 1024 * 1024; break;
case 0x06: romSize = 2048 * 1024; break;
case 0x07: romSize = 4096 * 1024; break;
case 0x08: romSize = 8192 * 1024; break;
case 0x52: romSize = 1152 * 1024; break;
case 0x53: romSize = 1280 * 1024; break;
case 0x54: romSize = 1536 * 1024; break;
default: romSize = romData.Length; break;
}
var ramSize = -1;
switch (romData[0x0149])
{
case 0x00: ramSize = 0 * 1024; break;
case 0x01: ramSize = 2 * 1024; break;
case 0x02: ramSize = 8 * 1024; break;
case 0x03: ramSize = 32 * 1024; break;
case 0x04: ramSize = 128 * 1024; break;
case 0x05: ramSize = 64 * 1024; break;
default: ramSize = 0; break;
}
/* NOTES:
* MBC2 internal RAM is not given in header, 512*4b == 256 bytes
* GB Camera internal RAM ~seems~ to not be given in header? 128 kbytes
*/
var mapperTypeFromHeader = typeof(NoMapperCartridge);
var hasBattery = false;
var hasRtc = false;
var hasRumble = false;
switch (romData[0x0147])
{
case 0x00: mapperType = typeof(NoMapperCartridge); break;
case 0x01: mapperType = typeof(MBC1Cartridge); break;
case 0x02: mapperType = typeof(MBC1Cartridge); break;
case 0x03: mapperType = typeof(MBC1Cartridge); hasBattery = true; break;
case 0x05: mapperType = typeof(MBC2Cartridge); ramSize = 0x100; break;
case 0x06: mapperType = typeof(MBC2Cartridge); ramSize = 0x100; hasBattery = true; break;
case 0x08: mapperType = typeof(NoMapperCartridge); break;
case 0x09: mapperType = typeof(NoMapperCartridge); hasBattery = true; break;
// 0B-0D, MMM01
case 0x0F: mapperType = typeof(MBC3Cartridge); hasBattery = true; hasRtc = true; break;
case 0x10: mapperType = typeof(MBC3Cartridge); hasBattery = true; hasRtc = true; break;
case 0x11: mapperType = typeof(MBC3Cartridge); break;
case 0x12: mapperType = typeof(MBC3Cartridge); break;
case 0x13: mapperType = typeof(MBC3Cartridge); hasBattery = true; break;
case 0x19: mapperType = typeof(MBC5Cartridge); break;
case 0x1A: mapperType = typeof(MBC5Cartridge); break;
case 0x1B: mapperType = typeof(MBC5Cartridge); hasBattery = true; break;
case 0x1C: mapperType = typeof(MBC5Cartridge); hasRumble = true; break;
case 0x1D: mapperType = typeof(MBC5Cartridge); hasRumble = true; break;
case 0x1E: mapperType = typeof(MBC5Cartridge); hasBattery = true; hasRumble = true; break;
// 20, MBC6
// 22, MBC7
case 0xFC: mapperType = typeof(GBCameraCartridge); ramSize = 128 * 1024; break;
// FD, BANDAI TAMA5
// FE, HuC3
// FF, HuC1
default: throw new EmulationException($"Unimplemented cartridge type 0x{romData[0x0147]:X2}");
}
if (mapperType == null)
mapperType = mapperTypeFromHeader;
if (romSize != romData.Length)
{
var romSizePadded = 1;
while (romSizePadded < romData.Length) romSizePadded <<= 1;
romSize = Math.Max(romSizePadded, romData.Length);
}
var cartridge = (IGameBoyCartridge)Activator.CreateInstance(mapperType, new object[] { romSize, ramSize });
cartridge.LoadRom(romData);
cartridge.LoadRam(ramData);
cartridge.SetCartridgeConfig(hasBattery, hasRtc, hasRumble);
return cartridge;
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 40e53d5096e06264a829b803422f047e

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ce378fe5a7c0ff14e8ffd0ad6c86ac65
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,120 @@
using Essgee.Exceptions;
using Essgee.Utilities;
using System;
namespace Essgee.Emulation.Cartridges.Sega
{
public class CodemastersCartridge : ICartridge
{
byte[] romData;
[StateRequired]
byte[] ramData;
[StateRequired]
readonly byte[] pagingRegisters;
[StateRequired]
readonly byte bankMask;
[StateRequired]
bool isRamEnabled;
public CodemastersCartridge(int romSize, int ramSize)
{
pagingRegisters = new byte[3];
pagingRegisters[0] = 0x00;
pagingRegisters[1] = 0x01;
pagingRegisters[2] = 0x02;
romData = new byte[romSize];
ramData = new byte[ramSize];
bankMask = (byte)((romData.Length >> 14) - 1);
isRamEnabled = false;
}
public void LoadRom(byte[] data)
{
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
}
public void LoadRam(byte[] data)
{
Buffer.BlockCopy(data, 0, ramData, 0, Math.Min(data.Length, ramData.Length));
}
public byte[] GetRomData()
{
return romData;
}
public byte[] GetRamData()
{
return ramData;
}
public bool IsRamSaveNeeded()
{
return false;
}
public ushort GetLowerBound()
{
return 0x0000;
}
public ushort GetUpperBound()
{
return 0xBFFF;
}
public void Step(int clockCyclesInStep)
{
/* Nothing to do */
}
public byte Read(ushort address)
{
switch (address & 0xC000)
{
case 0x0000:
return romData[((pagingRegisters[0] << 14) | (address & 0x3FFF))];
case 0x4000:
return romData[((pagingRegisters[1] << 14) | (address & 0x3FFF))];
case 0x8000:
if (isRamEnabled && (address >= 0xA000 && address <= 0xBFFF))
return ramData[address & 0x1FFF];
else
return romData[((pagingRegisters[2] << 14) | (address & 0x3FFF))];
default:
throw new EmulationException(string.Format("Codemasters mapper: Cannot read from cartridge address 0x{0:X4}", address));
}
}
public void Write(ushort address, byte value)
{
switch (address)
{
case 0x0000:
pagingRegisters[0] = (byte)(value & bankMask);
break;
case 0x4000:
pagingRegisters[1] = (byte)(value & bankMask);
isRamEnabled = ((value & 0x80) == 0x80);
break;
case 0x8000:
pagingRegisters[2] = (byte)(value & bankMask);
break;
}
if (isRamEnabled && ((address & 0xF000) == 0xA000 || (address & 0xF000) == 0xB000))
ramData[address & 0x1FFF] = value;
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f7cca9db8813d3c45a1ce0cfb7792b71

View File

@ -0,0 +1,91 @@
using Essgee.Exceptions;
using Essgee.Utilities;
using System;
namespace Essgee.Emulation.Cartridges.Sega
{
public class KoreanMSX8kMapperCartridge : ICartridge
{
byte[] romData;
[StateRequired]
readonly byte[] pagingRegisters;
[StateRequired]
byte bankMask;
public KoreanMSX8kMapperCartridge(int romSize, int ramSize)
{
pagingRegisters = new byte[4];
romData = new byte[romSize];
}
public void LoadRom(byte[] data)
{
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
var romSizeRounded = 1;
while (romSizeRounded < romData.Length) romSizeRounded <<= 1;
bankMask = (byte)((romSizeRounded >> 13) - 1);
}
public void LoadRam(byte[] data)
{
//
}
public byte[] GetRomData()
{
return romData;
}
public byte[] GetRamData()
{
return null;
}
public bool IsRamSaveNeeded()
{
return false;
}
public ushort GetLowerBound()
{
return 0x0000;
}
public ushort GetUpperBound()
{
return 0xBFFF;
}
public void Step(int clockCyclesInStep)
{
/* Nothing to do */
}
public byte Read(ushort address)
{
switch (address & 0xE000)
{
case 0x0000: return romData[(0x00 << 13) | (address & 0x1FFF)];
case 0x2000: return romData[(0x01 << 13) | (address & 0x1FFF)];
case 0x4000: return romData[(pagingRegisters[2] << 13) | (address & 0x1FFF)];
case 0x6000: return romData[(pagingRegisters[3] << 13) | (address & 0x1FFF)];
case 0x8000: return romData[(pagingRegisters[0] << 13) | (address & 0x1FFF)];
case 0xA000: return romData[(pagingRegisters[1] << 13) | (address & 0x1FFF)];
default: throw new EmulationException(string.Format("Korean MSX 8k mapper: Cannot read from cartridge address 0x{0:X4}", address));
}
}
public void Write(ushort address, byte value)
{
if (address >= 0x0000 && address <= 0x0003)
{
pagingRegisters[address & 0x0003] = (byte)(value & bankMask);
}
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ec1ba102183679945bca01f524bb1868

View File

@ -0,0 +1,94 @@
using Essgee.Exceptions;
using Essgee.Utilities;
using System;
namespace Essgee.Emulation.Cartridges.Sega
{
public class KoreanMapperCartridge : ICartridge
{
byte[] romData;
[StateRequired]
byte bankMask, pagingRegister;
public KoreanMapperCartridge(int romSize, int ramSize)
{
pagingRegister = 0x02;
romData = new byte[romSize];
}
public void LoadRom(byte[] data)
{
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
var romSizeRounded = 1;
while (romSizeRounded < romData.Length) romSizeRounded <<= 1;
bankMask = (byte)((romSizeRounded >> 14) - 1);
}
public void LoadRam(byte[] data)
{
//
}
public byte[] GetRomData()
{
return romData;
}
public byte[] GetRamData()
{
return null;
}
public bool IsRamSaveNeeded()
{
return false;
}
public ushort GetLowerBound()
{
return 0x0000;
}
public ushort GetUpperBound()
{
return 0xBFFF;
}
public void Step(int clockCyclesInStep)
{
/* Nothing to do */
}
public byte Read(ushort address)
{
switch (address & 0xC000)
{
case 0x0000:
return romData[address & 0x3FFF];
case 0x4000:
return romData[(0x01 << 14) | (address & 0x3FFF)];
case 0x8000:
return romData[((pagingRegister << 14) | (address & 0x3FFF))];
default:
throw new EmulationException(string.Format("Korean mapper: Cannot read from cartridge address 0x{0:X4}", address));
}
}
public void Write(ushort address, byte value)
{
switch (address)
{
case 0xA000:
pagingRegister = (byte)(value & bankMask);
break;
}
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 510ae156eb8cf4e4fb7c5fa573062f07

Some files were not shown because too many files have changed in this diff Show More