diff --git a/AxibugEmuOnline.Client/Assets/MyNes.Core/MyNesMain.cs b/AxibugEmuOnline.Client/Assets/MyNes.Core/MyNesMain.cs index ce9df46..19a7d77 100644 --- a/AxibugEmuOnline.Client/Assets/MyNes.Core/MyNesMain.cs +++ b/AxibugEmuOnline.Client/Assets/MyNes.Core/MyNesMain.cs @@ -1,337 +1,231 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Reflection; namespace MyNes.Core { public class MyNesMain { - public static EmuSettings EmuSettings { get; private set; } + public static EmuSettings EmuSettings { get; private set; } + public static RendererSettings RendererSettings { get; private set; } + public static IFileManager FileManager { get; private set; } + public static string WorkingFolder { get; private set; } - public static RendererSettings RendererSettings { get; private set; } + internal static List Boards { get; private set; } - public static string AppPath { get; private set; } + public static IVideoProvider VideoProvider { get; private set; } - public static string WorkingFolder { get; private set; } + public static IAudioProvider AudioProvider { get; private set; } - internal static List Boards { get; private set; } + public static WaveRecorder WaveRecorder { get; private set; } - public static List VideoProviders { get; private set; } + public static void Initialize(IFileManager fileManager) + { + Tracer.WriteLine("Initializing My Nes Core ...."); + FileManager = fileManager; + WorkingFolder = fileManager.GetWorkingFolderPath(); + Tracer.WriteLine("Loading emu settings ..."); + EmuSettings = new EmuSettings(Path.Combine(WorkingFolder, "emusettings.ini")); + EmuSettings.LoadSettings(); + Tracer.WriteLine("Emu settings loaded successfully."); + Tracer.WriteLine("Loading renderer settings ..."); + RendererSettings = new RendererSettings(Path.Combine(WorkingFolder, "renderersettings.ini")); + RendererSettings.LoadSettings(); + Tracer.WriteLine("Renderer settings loaded successfully."); + Tracer.WriteLine("Locating boards and providers ..."); + WaveRecorder = new WaveRecorder(); + Boards = new List(); - public static List AudioProviders { get; private set; } + var allTypes = AppDomain.CurrentDomain + .GetAssemblies() + .SelectMany(ass => ass.GetTypes()); - public static IVideoProvider VideoProvider { get; private set; } + foreach (var type in allTypes) + { + if (type.IsSubclassOf(typeof(Board)) && !type.IsAbstract) + { + Board board = Activator.CreateInstance(type) as Board; + Boards.Add(board); + Tracer.WriteLine("Board added: " + board.Name + " [ Mapper " + board.MapperNumber + "]"); + } + else if (VideoProvider == null && typeof(IVideoProvider).IsAssignableFrom(type) && !type.IsAbstract) + { + IVideoProvider videoProvider = Activator.CreateInstance(type) as IVideoProvider; + VideoProvider = videoProvider; + Tracer.WriteLine("Video provider setuped: " + videoProvider.Name + " [" + videoProvider.ID + "]"); + } + else if (typeof(IAudioProvider).IsAssignableFrom(type) && !type.IsAbstract) + { + IAudioProvider audioProvider = Activator.CreateInstance(type) as IAudioProvider; + AudioProvider = audioProvider; + Tracer.WriteLine("Audio provider setuped: " + audioProvider.Name + " [" + audioProvider.ID + "]"); + } + } - public static IAudioProvider AudioProvider { get; private set; } + Tracer.WriteInformation("Done."); + Tracer.WriteInformation("Total of " + Boards.Count + " board found."); + SetVideoProvider(); + SetAudioProvider(); + SetRenderingMethods(); - public static WaveRecorder WaveRecorder { get; private set; } + NesEmu.Initialize(); + } - public static void Initialize(bool setupRenderers) - { - Tracer.WriteLine("Initializing My Nes Core ...."); - AppPath = Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]); - if (AppPath == "") - { - AppPath = Path.GetFullPath(".\\"); - } - WorkingFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "MyNes"); - Directory.CreateDirectory(WorkingFolder); - Tracer.WriteLine("Loading emu settings ..."); - EmuSettings = new EmuSettings(Path.Combine(WorkingFolder, "emusettings.ini")); - EmuSettings.LoadSettings(); - Tracer.WriteLine("Emu settings loaded successfully."); - Tracer.WriteLine("Loading renderer settings ..."); - RendererSettings = new RendererSettings(Path.Combine(WorkingFolder, "renderersettings.ini")); - RendererSettings.LoadSettings(); - Tracer.WriteLine("Renderer settings loaded successfully."); - Tracer.WriteLine("Locating boards and providers ..."); - WaveRecorder = new WaveRecorder(); - Boards = new List(); - VideoProviders = new List(); - AudioProviders = new List(); - string[] files = Directory.GetFiles(Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]), "*", SearchOption.AllDirectories); - foreach (string text in files) - { - try - { - if (!(Path.GetExtension(text).ToLower() == ".exe") && !(Path.GetExtension(text).ToLower() == ".dll")) - { - continue; - } - Tracer.WriteLine("Reading assembly: " + text); - Assembly assembly = Assembly.LoadFile(text); - if (!(assembly != null)) - { - continue; - } - Type[] types = assembly.GetTypes(); - foreach (Type type in types) - { - if (type.IsSubclassOf(typeof(Board)) && !type.IsAbstract) - { - Board board = Activator.CreateInstance(type) as Board; - Boards.Add(board); - Tracer.WriteLine("Board added: " + board.Name + " [ Mapper " + board.MapperNumber + "]"); - } - else if (type.GetInterface("MyNes.Core.IVideoProvider") != null) - { - IVideoProvider videoProvider = Activator.CreateInstance(type) as IVideoProvider; - VideoProviders.Add(videoProvider); - Tracer.WriteLine("Video provider added: " + videoProvider.Name + " [" + videoProvider.ID + "]"); - } - else if (type.GetInterface("MyNes.Core.IAudioProvider") != null) - { - IAudioProvider audioProvider = Activator.CreateInstance(type) as IAudioProvider; - AudioProviders.Add(audioProvider); - Tracer.WriteLine("Audio provider added: " + audioProvider.Name + " [" + audioProvider.ID + "]"); - } - } - } - catch (Exception ex) - { - Tracer.WriteLine("ERROR: " + ex.ToString()); - } - } - Tracer.WriteInformation("Done."); - Tracer.WriteInformation("Total of " + Boards.Count + " board found."); - Tracer.WriteInformation("Total of " + VideoProviders.Count + " video provider found."); - Tracer.WriteInformation("Total of " + AudioProviders.Count + " audio provider found."); - if (setupRenderers) - { - SetVideoProvider(); - SetAudioProvider(); - SetRenderingMethods(); - } - NesEmu.Initialize(); - } + public static void Shutdown() + { + if (NesEmu.ON) + { + NesEmu.ShutDown(); + } + if (VideoProvider != null) + { + VideoProvider.ShutDown(); + } + if (AudioProvider != null) + { + AudioProvider.ShutDown(); + } + Tracer.WriteLine("Saving settings ..."); + EmuSettings.SaveSettings(); + RendererSettings.SaveSettings(); + Tracer.WriteLine("Settings saved successfully."); + Tracer.WriteLine("Exiting My Nes."); + } - public static void Shutdown() - { - if (NesEmu.ON) - { - NesEmu.ShutDown(); - } - if (VideoProvider != null) - { - VideoProvider.ShutDown(); - } - if (AudioProvider != null) - { - AudioProvider.ShutDown(); - } - Tracer.WriteLine("Saving settings ..."); - EmuSettings.SaveSettings(); - RendererSettings.SaveSettings(); - Tracer.WriteLine("Settings saved successfully."); - Tracer.WriteLine("Exiting My Nes."); - } + internal static bool IsBoardExist(int mapper) + { + foreach (Board board in Boards) + { + if (board.MapperNumber == mapper) + { + return true; + } + } + return false; + } - internal static bool IsBoardExist(int mapper) - { - foreach (Board board in Boards) - { - if (board.MapperNumber == mapper) - { - return true; - } - } - return false; - } + internal static Board GetBoard(int mapper) + { + foreach (Board board in Boards) + { + if (board.MapperNumber == mapper) + { + return board; + } + } + return null; + } - internal static Board GetBoard(int mapper) - { - foreach (Board board in Boards) - { - if (board.MapperNumber == mapper) - { - return board; - } - } - return null; - } + public static void MakeWorkingFolder() + { + WorkingFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "MyNes"); + Directory.CreateDirectory(WorkingFolder); + } - public static void MakeWorkingFolder() - { - WorkingFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "MyNes"); - Directory.CreateDirectory(WorkingFolder); - } + public static BoardInfoObject[] GetBoardsList(bool includeUnsupportedMappers) + { + List list = new List(); + if (includeUnsupportedMappers) + { + for (int i = 0; i < 256; i++) + { + bool flag = false; + foreach (Board board in Boards) + { + if (board.MapperNumber == i) + { + BoardInfoObject boardInfoObject = new BoardInfoObject(); + boardInfoObject.Name = board.Name; + boardInfoObject.MapperNumber = board.MapperNumber; + boardInfoObject.IsSupported = true; + boardInfoObject.HasIssues = board.HasIssues; + boardInfoObject.Issues = board.Issues; + list.Add(boardInfoObject); + flag = true; + break; + } + } + if (!flag) + { + BoardInfoObject boardInfoObject2 = new BoardInfoObject(); + boardInfoObject2.Name = "N/A"; + boardInfoObject2.MapperNumber = i; + boardInfoObject2.IsSupported = false; + boardInfoObject2.HasIssues = false; + boardInfoObject2.Issues = ""; + list.Add(boardInfoObject2); + } + } + } + else + { + foreach (Board board2 in Boards) + { + if (board2.MapperNumber >= 0) + { + BoardInfoObject boardInfoObject3 = new BoardInfoObject(); + boardInfoObject3.Name = board2.Name; + boardInfoObject3.MapperNumber = board2.MapperNumber; + boardInfoObject3.IsSupported = true; + boardInfoObject3.HasIssues = board2.HasIssues; + boardInfoObject3.Issues = board2.Issues; + list.Add(boardInfoObject3); + } + } + } + return list.ToArray(); + } - public static BoardInfoObject[] GetBoardsList(bool includeUnsupportedMappers) - { - List list = new List(); - if (includeUnsupportedMappers) - { - for (int i = 0; i < 256; i++) - { - bool flag = false; - foreach (Board board in Boards) - { - if (board.MapperNumber == i) - { - BoardInfoObject boardInfoObject = new BoardInfoObject(); - boardInfoObject.Name = board.Name; - boardInfoObject.MapperNumber = board.MapperNumber; - boardInfoObject.IsSupported = true; - boardInfoObject.HasIssues = board.HasIssues; - boardInfoObject.Issues = board.Issues; - list.Add(boardInfoObject); - flag = true; - break; - } - } - if (!flag) - { - BoardInfoObject boardInfoObject2 = new BoardInfoObject(); - boardInfoObject2.Name = "N/A"; - boardInfoObject2.MapperNumber = i; - boardInfoObject2.IsSupported = false; - boardInfoObject2.HasIssues = false; - boardInfoObject2.Issues = ""; - list.Add(boardInfoObject2); - } - } - } - else - { - foreach (Board board2 in Boards) - { - if (board2.MapperNumber >= 0) - { - BoardInfoObject boardInfoObject3 = new BoardInfoObject(); - boardInfoObject3.Name = board2.Name; - boardInfoObject3.MapperNumber = board2.MapperNumber; - boardInfoObject3.IsSupported = true; - boardInfoObject3.HasIssues = board2.HasIssues; - boardInfoObject3.Issues = board2.Issues; - list.Add(boardInfoObject3); - } - } - } - return list.ToArray(); - } + static void SetVideoProvider() + { + if (VideoProvider != null) VideoProvider.Initialize(); + else Tracer.WriteError("VideoProvider is null"); + } - public static IVideoProvider GetVideoProvider(string id) - { - foreach (IVideoProvider videoProvider in VideoProviders) - { - if (videoProvider.ID == id) - { - return videoProvider; - } - } - return null; - } + static void SetAudioProvider() + { + Tracer.WriteLine("Looking for the audio provider that set in the settings..."); + if (AudioProvider != null) AudioProvider.Initialize(); + else Tracer.WriteError("AudioProvider is null"); + } - public static IAudioProvider GetAudioProvider(string id) - { - foreach (IAudioProvider audioProvider in AudioProviders) - { - if (audioProvider.ID == id) - { - return audioProvider; - } - } - return null; - } + static void SetRenderingMethods() + { + if (VideoProvider != null && AudioProvider != null) + { + NesEmu.SetupRenderingMethods(VideoProvider.SubmitFrame, AudioProvider.SubmitSamples, AudioProvider.TogglePause, AudioProvider.GetIsPlaying); + } + else + { + Tracer.WriteError("ERROR: unable to setup rendering methods, one (or both) of the providers is not set (video and/or audio provider)"); + } + } - public static void SetVideoProvider() - { - Tracer.WriteLine("Looking for the video provider that set in the settings..."); - VideoProvider = GetVideoProvider(RendererSettings.Video_ProviderID); - if (VideoProvider == null) - { - Tracer.WriteError("ERROR: cannot find the video provider that set in the settings"); - Tracer.WriteWarning("Deciding video provider"); - if (VideoProviders.Count > 0) - { - RendererSettings.Video_ProviderID = VideoProviders[0].ID; - VideoProvider = VideoProviders[0]; - if (VideoProvider != null) - { - Tracer.WriteInformation("Video provider set to " + VideoProvider.Name + " [" + VideoProvider.ID + "]"); - VideoProvider.Initialize(); - } - else - { - Tracer.WriteError("ERROR: cannot set video provider."); - } - } - else - { - Tracer.WriteError("ERROR: cannot set video provider, no video providers located."); - } - } - else - { - Tracer.WriteInformation("Video provider set to " + VideoProvider.Name + " [" + VideoProvider.ID + "]"); - VideoProvider.Initialize(); - } - } - - public static void SetAudioProvider() - { - Tracer.WriteLine("Looking for the audio provider that set in the settings..."); - AudioProvider = GetAudioProvider(RendererSettings.Audio_ProviderID); - if (AudioProvider == null) - { - Tracer.WriteError("ERROR: cannot find the audio provider that set in the settings"); - Tracer.WriteWarning("Deciding audio provider"); - if (AudioProviders.Count > 0) - { - RendererSettings.Audio_ProviderID = AudioProviders[0].ID; - AudioProvider = AudioProviders[0]; - if (AudioProvider != null) - { - Tracer.WriteInformation("Audio provider set to " + AudioProvider.Name + " [" + AudioProvider.ID + "]"); - AudioProvider.Initialize(); - } - else - { - Tracer.WriteError("ERROR: cannot set audio provider."); - } - } - else - { - Tracer.WriteError("ERROR: cannot set audio provider, no audio providers located."); - } - } - else - { - Tracer.WriteInformation("Audio provider set to " + AudioProvider.Name + " [" + AudioProvider.ID + "]"); - AudioProvider.Initialize(); - } - } - - public static void SetRenderingMethods() - { - if (VideoProvider != null && AudioProvider != null) - { - NesEmu.SetupRenderingMethods(VideoProvider.SubmitFrame, AudioProvider.SubmitSamples, AudioProvider.TogglePause, AudioProvider.GetIsPlaying); - } - else - { - Tracer.WriteError("ERROR: unable to setup rendering methods, one (or both) of the providers is not set (video and/or audio provider)"); - } - } - - public static void RecordWave() - { - if (NesEmu.ON && NesEmu.SoundEnabled) - { - string text = Path.Combine(EmuSettings.WavesFolder, Path.GetFileNameWithoutExtension(NesEmu.CurrentFilePath) + ".wav"); - int num = 0; - while (File.Exists(text)) - { - text = Path.Combine(EmuSettings.WavesFolder, Path.GetFileNameWithoutExtension(NesEmu.CurrentFilePath) + "_" + num + ".wav"); - num++; - } - WaveRecorder.Record(text, 1, 16, RendererSettings.Audio_Frequency); - } - else if (VideoProvider != null) - { - VideoProvider.WriteErrorNotification("Cannot record sound when the emu is off/sound is not enabled.", instant: false); - } - } + public static void RecordWave() + { + if (NesEmu.ON && NesEmu.SoundEnabled) + { + string text = Path.Combine(EmuSettings.WavesFolder, Path.GetFileNameWithoutExtension(NesEmu.CurrentFilePath) + ".wav"); + int num = 0; + while (File.Exists(text)) + { + text = Path.Combine(EmuSettings.WavesFolder, Path.GetFileNameWithoutExtension(NesEmu.CurrentFilePath) + "_" + num + ".wav"); + num++; + } + WaveRecorder.Record(text, 1, 16, RendererSettings.Audio_Frequency); + } + else if (VideoProvider != null) + { + VideoProvider.WriteErrorNotification("Cannot record sound when the emu is off/sound is not enabled.", instant: false); + } + } + } + public interface IFileManager + { + string GetWorkingFolderPath(); + public Stream OpenDatabaseFile(); + public Stream OpenPaletteFile(); } } diff --git a/AxibugEmuOnline.Client/Assets/MyNes.Core/NesCartDatabase.cs b/AxibugEmuOnline.Client/Assets/MyNes.Core/NesCartDatabase.cs index 8fa4b3f..16a2642 100644 --- a/AxibugEmuOnline.Client/Assets/MyNes.Core/NesCartDatabase.cs +++ b/AxibugEmuOnline.Client/Assets/MyNes.Core/NesCartDatabase.cs @@ -6,325 +6,322 @@ namespace MyNes.Core { public class NesCartDatabase { - private static List _databaseRoms = new List(); + private static List _databaseRoms = new List(); - public static string DBVersion = ""; + public static string DBVersion = ""; - public static string DBConformance = ""; + public static string DBConformance = ""; - public static string DBAgent = ""; + public static string DBAgent = ""; - public static string DBAuthor = ""; + public static string DBAuthor = ""; - public static string DBTimeStamp = ""; + public static string DBTimeStamp = ""; - public static bool Ready = false; + public static bool Ready = false; - public static List DatabaseRoms => _databaseRoms; + public static List DatabaseRoms => _databaseRoms; - public static void LoadDatabase(string fileName, out bool success) - { - success = false; - Ready = false; - if (!File.Exists(fileName)) - { - return; - } - _databaseRoms.Clear(); - Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read); - XmlReaderSettings xmlReaderSettings = new XmlReaderSettings(); - xmlReaderSettings.DtdProcessing = DtdProcessing.Ignore; - xmlReaderSettings.IgnoreWhitespace = true; - XmlReader xmlReader = XmlReader.Create(stream, xmlReaderSettings); - NesCartDatabaseGameInfo nesCartDatabaseGameInfo = default(NesCartDatabaseGameInfo); - nesCartDatabaseGameInfo.Cartridges = new List(); - nesCartDatabaseGameInfo.Game_AltName = ""; - nesCartDatabaseGameInfo.Game_Catalog = ""; - nesCartDatabaseGameInfo.Game_Class = ""; - nesCartDatabaseGameInfo.Game_Developer = ""; - nesCartDatabaseGameInfo.Game_Name = ""; - nesCartDatabaseGameInfo.Game_Players = ""; - nesCartDatabaseGameInfo.Game_Publisher = ""; - nesCartDatabaseGameInfo.Game_Region = ""; - nesCartDatabaseGameInfo.Game_ReleaseDate = ""; - while (xmlReader.Read()) - { - if ((xmlReader.Name == "xml") & xmlReader.IsStartElement()) - { - if (xmlReader.MoveToAttribute("version")) - { - DBVersion = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("conformance")) - { - DBConformance = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("agent")) - { - DBAgent = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("author")) - { - DBAuthor = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("timestamp")) - { - DBTimeStamp = xmlReader.Value; - } - } - else - { - if (!((xmlReader.Name == "game") & xmlReader.IsStartElement())) - { - continue; - } - nesCartDatabaseGameInfo = default(NesCartDatabaseGameInfo); - if (xmlReader.MoveToAttribute("name")) - { - nesCartDatabaseGameInfo.Game_Name = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("altname")) - { - nesCartDatabaseGameInfo.Game_AltName = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("class")) - { - nesCartDatabaseGameInfo.Game_Class = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("catalog")) - { - nesCartDatabaseGameInfo.Game_Catalog = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("publisher")) - { - nesCartDatabaseGameInfo.Game_Publisher = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("developer")) - { - nesCartDatabaseGameInfo.Game_Developer = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("region")) - { - nesCartDatabaseGameInfo.Game_Region = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("players")) - { - nesCartDatabaseGameInfo.Game_Players = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("date")) - { - nesCartDatabaseGameInfo.Game_ReleaseDate = xmlReader.Value; - } - NesCartDatabaseCartridgeInfo nesCartDatabaseCartridgeInfo = new NesCartDatabaseCartridgeInfo(); - nesCartDatabaseCartridgeInfo.PAD_h = ""; - nesCartDatabaseCartridgeInfo.PAD_v = ""; - nesCartDatabaseCartridgeInfo.PRG_crc = ""; - nesCartDatabaseCartridgeInfo.PRG_name = ""; - nesCartDatabaseCartridgeInfo.PRG_sha1 = ""; - nesCartDatabaseCartridgeInfo.PRG_size = ""; - nesCartDatabaseCartridgeInfo.chip_type = new List(); - nesCartDatabaseCartridgeInfo.CHR_crc = ""; - nesCartDatabaseCartridgeInfo.CHR_name = ""; - nesCartDatabaseCartridgeInfo.CHR_sha1 = ""; - nesCartDatabaseCartridgeInfo.CHR_size = ""; - nesCartDatabaseCartridgeInfo.CIC_type = ""; - nesCartDatabaseCartridgeInfo.Board_Mapper = ""; - nesCartDatabaseCartridgeInfo.Board_Pcb = ""; - nesCartDatabaseCartridgeInfo.Board_Type = ""; - nesCartDatabaseCartridgeInfo.VRAM_sizes = new List(); - nesCartDatabaseCartridgeInfo.WRAMBanks = new List(); - while (xmlReader.Read()) - { - if ((xmlReader.Name == "game") & !xmlReader.IsStartElement()) - { - _databaseRoms.Add(nesCartDatabaseGameInfo); - break; - } - if ((xmlReader.Name == "cartridge") & xmlReader.IsStartElement()) - { - if (nesCartDatabaseGameInfo.Cartridges == null) - { - nesCartDatabaseGameInfo.Cartridges = new List(); - } - nesCartDatabaseCartridgeInfo = new NesCartDatabaseCartridgeInfo(); - nesCartDatabaseCartridgeInfo.PAD_h = ""; - nesCartDatabaseCartridgeInfo.PAD_v = ""; - nesCartDatabaseCartridgeInfo.PRG_crc = ""; - nesCartDatabaseCartridgeInfo.PRG_name = ""; - nesCartDatabaseCartridgeInfo.PRG_sha1 = ""; - nesCartDatabaseCartridgeInfo.PRG_size = ""; - nesCartDatabaseCartridgeInfo.chip_type = new List(); - nesCartDatabaseCartridgeInfo.CHR_crc = ""; - nesCartDatabaseCartridgeInfo.CHR_name = ""; - nesCartDatabaseCartridgeInfo.CHR_sha1 = ""; - nesCartDatabaseCartridgeInfo.CHR_size = ""; - nesCartDatabaseCartridgeInfo.CIC_type = ""; - nesCartDatabaseCartridgeInfo.Board_Mapper = ""; - nesCartDatabaseCartridgeInfo.Board_Pcb = ""; - nesCartDatabaseCartridgeInfo.Board_Type = ""; - nesCartDatabaseCartridgeInfo.VRAM_sizes = new List(); - nesCartDatabaseCartridgeInfo.WRAMBanks = new List(); - if (xmlReader.MoveToAttribute("system")) - { - nesCartDatabaseCartridgeInfo.System = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("crc")) - { - nesCartDatabaseCartridgeInfo.CRC = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("sha1")) - { - nesCartDatabaseCartridgeInfo.SHA1 = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("dump")) - { - nesCartDatabaseCartridgeInfo.Dump = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("dumper")) - { - nesCartDatabaseCartridgeInfo.Dumper = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("datedumped")) - { - nesCartDatabaseCartridgeInfo.DateDumped = xmlReader.Value; - } - } - else if ((xmlReader.Name == "cartridge") & !xmlReader.IsStartElement()) - { - nesCartDatabaseGameInfo.Cartridges.Add(nesCartDatabaseCartridgeInfo); - } - else if ((xmlReader.Name == "board") & xmlReader.IsStartElement()) - { - if (xmlReader.MoveToAttribute("type")) - { - nesCartDatabaseCartridgeInfo.Board_Type = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("pcb")) - { - nesCartDatabaseCartridgeInfo.Board_Pcb = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("mapper")) - { - nesCartDatabaseCartridgeInfo.Board_Mapper = xmlReader.Value; - } - } - else if ((xmlReader.Name == "prg") & xmlReader.IsStartElement()) - { - if (xmlReader.MoveToAttribute("name")) - { - nesCartDatabaseCartridgeInfo.PRG_name = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("size")) - { - nesCartDatabaseCartridgeInfo.PRG_size = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("crc")) - { - nesCartDatabaseCartridgeInfo.PRG_crc = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("sha1")) - { - nesCartDatabaseCartridgeInfo.PRG_sha1 = xmlReader.Value; - } - } - else if ((xmlReader.Name == "chr") & xmlReader.IsStartElement()) - { - if (xmlReader.MoveToAttribute("name")) - { - nesCartDatabaseCartridgeInfo.CHR_name = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("size")) - { - nesCartDatabaseCartridgeInfo.CHR_size = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("crc")) - { - nesCartDatabaseCartridgeInfo.CHR_crc = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("sha1")) - { - nesCartDatabaseCartridgeInfo.CHR_sha1 = xmlReader.Value; - } - } - else if ((xmlReader.Name == "vram") & xmlReader.IsStartElement()) - { - if (xmlReader.MoveToAttribute("size")) - { - nesCartDatabaseCartridgeInfo.VRAM_sizes.Add(xmlReader.Value); - } - } - else if ((xmlReader.Name == "wram") & xmlReader.IsStartElement()) - { - string sIZE = ""; - bool bATTERY = false; - int result = 0; - if (xmlReader.MoveToAttribute("size")) - { - sIZE = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("battery")) - { - bATTERY = xmlReader.Value == "1"; - } - if (xmlReader.MoveToAttribute("id")) - { - int.TryParse(xmlReader.Value, out result); - } - nesCartDatabaseCartridgeInfo.WRAMBanks.Add(new SRAMBankInfo(result, sIZE, bATTERY)); - } - else if ((xmlReader.Name == "chip") & xmlReader.IsStartElement()) - { - if (xmlReader.MoveToAttribute("type")) - { - if (nesCartDatabaseCartridgeInfo.chip_type == null) - { - nesCartDatabaseCartridgeInfo.chip_type = new List(); - } - nesCartDatabaseCartridgeInfo.chip_type.Add(xmlReader.Value); - } - } - else if ((xmlReader.Name == "cic") & xmlReader.IsStartElement()) - { - if (xmlReader.MoveToAttribute("type")) - { - nesCartDatabaseCartridgeInfo.CIC_type = xmlReader.Value; - } - } - else if ((xmlReader.Name == "pad") & xmlReader.IsStartElement()) - { - if (xmlReader.MoveToAttribute("h")) - { - nesCartDatabaseCartridgeInfo.PAD_h = xmlReader.Value; - } - if (xmlReader.MoveToAttribute("v")) - { - nesCartDatabaseCartridgeInfo.PAD_v = xmlReader.Value; - } - } - } - } - } - Ready = true; - success = true; - xmlReader.Close(); - stream.Close(); - } + public static void LoadDatabase(out bool success) + { + success = false; + Ready = false; + _databaseRoms.Clear(); - public static NesCartDatabaseGameInfo Find(string Cart_sha1, out bool found) - { - found = false; - foreach (NesCartDatabaseGameInfo databaseRom in _databaseRoms) - { - foreach (NesCartDatabaseCartridgeInfo cartridge in databaseRom.Cartridges) - { - if (cartridge.SHA1.ToLower() == Cart_sha1.ToLower()) - { - found = true; - return databaseRom; - } - } - } - return default(NesCartDatabaseGameInfo); - } + var stream = MyNesMain.FileManager.OpenDatabaseFile(); + XmlReaderSettings xmlReaderSettings = new XmlReaderSettings(); + xmlReaderSettings.DtdProcessing = DtdProcessing.Ignore; + xmlReaderSettings.IgnoreWhitespace = true; + XmlReader xmlReader = XmlReader.Create(stream, xmlReaderSettings); + NesCartDatabaseGameInfo nesCartDatabaseGameInfo = default(NesCartDatabaseGameInfo); + nesCartDatabaseGameInfo.Cartridges = new List(); + nesCartDatabaseGameInfo.Game_AltName = ""; + nesCartDatabaseGameInfo.Game_Catalog = ""; + nesCartDatabaseGameInfo.Game_Class = ""; + nesCartDatabaseGameInfo.Game_Developer = ""; + nesCartDatabaseGameInfo.Game_Name = ""; + nesCartDatabaseGameInfo.Game_Players = ""; + nesCartDatabaseGameInfo.Game_Publisher = ""; + nesCartDatabaseGameInfo.Game_Region = ""; + nesCartDatabaseGameInfo.Game_ReleaseDate = ""; + while (xmlReader.Read()) + { + if ((xmlReader.Name == "xml") & xmlReader.IsStartElement()) + { + if (xmlReader.MoveToAttribute("version")) + { + DBVersion = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("conformance")) + { + DBConformance = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("agent")) + { + DBAgent = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("author")) + { + DBAuthor = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("timestamp")) + { + DBTimeStamp = xmlReader.Value; + } + } + else + { + if (!((xmlReader.Name == "game") & xmlReader.IsStartElement())) + { + continue; + } + nesCartDatabaseGameInfo = default(NesCartDatabaseGameInfo); + if (xmlReader.MoveToAttribute("name")) + { + nesCartDatabaseGameInfo.Game_Name = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("altname")) + { + nesCartDatabaseGameInfo.Game_AltName = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("class")) + { + nesCartDatabaseGameInfo.Game_Class = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("catalog")) + { + nesCartDatabaseGameInfo.Game_Catalog = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("publisher")) + { + nesCartDatabaseGameInfo.Game_Publisher = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("developer")) + { + nesCartDatabaseGameInfo.Game_Developer = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("region")) + { + nesCartDatabaseGameInfo.Game_Region = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("players")) + { + nesCartDatabaseGameInfo.Game_Players = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("date")) + { + nesCartDatabaseGameInfo.Game_ReleaseDate = xmlReader.Value; + } + NesCartDatabaseCartridgeInfo nesCartDatabaseCartridgeInfo = new NesCartDatabaseCartridgeInfo(); + nesCartDatabaseCartridgeInfo.PAD_h = ""; + nesCartDatabaseCartridgeInfo.PAD_v = ""; + nesCartDatabaseCartridgeInfo.PRG_crc = ""; + nesCartDatabaseCartridgeInfo.PRG_name = ""; + nesCartDatabaseCartridgeInfo.PRG_sha1 = ""; + nesCartDatabaseCartridgeInfo.PRG_size = ""; + nesCartDatabaseCartridgeInfo.chip_type = new List(); + nesCartDatabaseCartridgeInfo.CHR_crc = ""; + nesCartDatabaseCartridgeInfo.CHR_name = ""; + nesCartDatabaseCartridgeInfo.CHR_sha1 = ""; + nesCartDatabaseCartridgeInfo.CHR_size = ""; + nesCartDatabaseCartridgeInfo.CIC_type = ""; + nesCartDatabaseCartridgeInfo.Board_Mapper = ""; + nesCartDatabaseCartridgeInfo.Board_Pcb = ""; + nesCartDatabaseCartridgeInfo.Board_Type = ""; + nesCartDatabaseCartridgeInfo.VRAM_sizes = new List(); + nesCartDatabaseCartridgeInfo.WRAMBanks = new List(); + while (xmlReader.Read()) + { + if ((xmlReader.Name == "game") & !xmlReader.IsStartElement()) + { + _databaseRoms.Add(nesCartDatabaseGameInfo); + break; + } + if ((xmlReader.Name == "cartridge") & xmlReader.IsStartElement()) + { + if (nesCartDatabaseGameInfo.Cartridges == null) + { + nesCartDatabaseGameInfo.Cartridges = new List(); + } + nesCartDatabaseCartridgeInfo = new NesCartDatabaseCartridgeInfo(); + nesCartDatabaseCartridgeInfo.PAD_h = ""; + nesCartDatabaseCartridgeInfo.PAD_v = ""; + nesCartDatabaseCartridgeInfo.PRG_crc = ""; + nesCartDatabaseCartridgeInfo.PRG_name = ""; + nesCartDatabaseCartridgeInfo.PRG_sha1 = ""; + nesCartDatabaseCartridgeInfo.PRG_size = ""; + nesCartDatabaseCartridgeInfo.chip_type = new List(); + nesCartDatabaseCartridgeInfo.CHR_crc = ""; + nesCartDatabaseCartridgeInfo.CHR_name = ""; + nesCartDatabaseCartridgeInfo.CHR_sha1 = ""; + nesCartDatabaseCartridgeInfo.CHR_size = ""; + nesCartDatabaseCartridgeInfo.CIC_type = ""; + nesCartDatabaseCartridgeInfo.Board_Mapper = ""; + nesCartDatabaseCartridgeInfo.Board_Pcb = ""; + nesCartDatabaseCartridgeInfo.Board_Type = ""; + nesCartDatabaseCartridgeInfo.VRAM_sizes = new List(); + nesCartDatabaseCartridgeInfo.WRAMBanks = new List(); + if (xmlReader.MoveToAttribute("system")) + { + nesCartDatabaseCartridgeInfo.System = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("crc")) + { + nesCartDatabaseCartridgeInfo.CRC = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("sha1")) + { + nesCartDatabaseCartridgeInfo.SHA1 = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("dump")) + { + nesCartDatabaseCartridgeInfo.Dump = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("dumper")) + { + nesCartDatabaseCartridgeInfo.Dumper = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("datedumped")) + { + nesCartDatabaseCartridgeInfo.DateDumped = xmlReader.Value; + } + } + else if ((xmlReader.Name == "cartridge") & !xmlReader.IsStartElement()) + { + nesCartDatabaseGameInfo.Cartridges.Add(nesCartDatabaseCartridgeInfo); + } + else if ((xmlReader.Name == "board") & xmlReader.IsStartElement()) + { + if (xmlReader.MoveToAttribute("type")) + { + nesCartDatabaseCartridgeInfo.Board_Type = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("pcb")) + { + nesCartDatabaseCartridgeInfo.Board_Pcb = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("mapper")) + { + nesCartDatabaseCartridgeInfo.Board_Mapper = xmlReader.Value; + } + } + else if ((xmlReader.Name == "prg") & xmlReader.IsStartElement()) + { + if (xmlReader.MoveToAttribute("name")) + { + nesCartDatabaseCartridgeInfo.PRG_name = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("size")) + { + nesCartDatabaseCartridgeInfo.PRG_size = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("crc")) + { + nesCartDatabaseCartridgeInfo.PRG_crc = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("sha1")) + { + nesCartDatabaseCartridgeInfo.PRG_sha1 = xmlReader.Value; + } + } + else if ((xmlReader.Name == "chr") & xmlReader.IsStartElement()) + { + if (xmlReader.MoveToAttribute("name")) + { + nesCartDatabaseCartridgeInfo.CHR_name = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("size")) + { + nesCartDatabaseCartridgeInfo.CHR_size = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("crc")) + { + nesCartDatabaseCartridgeInfo.CHR_crc = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("sha1")) + { + nesCartDatabaseCartridgeInfo.CHR_sha1 = xmlReader.Value; + } + } + else if ((xmlReader.Name == "vram") & xmlReader.IsStartElement()) + { + if (xmlReader.MoveToAttribute("size")) + { + nesCartDatabaseCartridgeInfo.VRAM_sizes.Add(xmlReader.Value); + } + } + else if ((xmlReader.Name == "wram") & xmlReader.IsStartElement()) + { + string sIZE = ""; + bool bATTERY = false; + int result = 0; + if (xmlReader.MoveToAttribute("size")) + { + sIZE = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("battery")) + { + bATTERY = xmlReader.Value == "1"; + } + if (xmlReader.MoveToAttribute("id")) + { + int.TryParse(xmlReader.Value, out result); + } + nesCartDatabaseCartridgeInfo.WRAMBanks.Add(new SRAMBankInfo(result, sIZE, bATTERY)); + } + else if ((xmlReader.Name == "chip") & xmlReader.IsStartElement()) + { + if (xmlReader.MoveToAttribute("type")) + { + if (nesCartDatabaseCartridgeInfo.chip_type == null) + { + nesCartDatabaseCartridgeInfo.chip_type = new List(); + } + nesCartDatabaseCartridgeInfo.chip_type.Add(xmlReader.Value); + } + } + else if ((xmlReader.Name == "cic") & xmlReader.IsStartElement()) + { + if (xmlReader.MoveToAttribute("type")) + { + nesCartDatabaseCartridgeInfo.CIC_type = xmlReader.Value; + } + } + else if ((xmlReader.Name == "pad") & xmlReader.IsStartElement()) + { + if (xmlReader.MoveToAttribute("h")) + { + nesCartDatabaseCartridgeInfo.PAD_h = xmlReader.Value; + } + if (xmlReader.MoveToAttribute("v")) + { + nesCartDatabaseCartridgeInfo.PAD_v = xmlReader.Value; + } + } + } + } + } + Ready = true; + success = true; + xmlReader.Close(); + stream.Close(); + } + + public static NesCartDatabaseGameInfo Find(string Cart_sha1, out bool found) + { + found = false; + foreach (NesCartDatabaseGameInfo databaseRom in _databaseRoms) + { + foreach (NesCartDatabaseCartridgeInfo cartridge in databaseRom.Cartridges) + { + if (cartridge.SHA1.ToLower() == Cart_sha1.ToLower()) + { + found = true; + return databaseRom; + } + } + } + return default(NesCartDatabaseGameInfo); + } } } diff --git a/AxibugEmuOnline.Client/Assets/MyNes.Core/NesEmu.cs b/AxibugEmuOnline.Client/Assets/MyNes.Core/NesEmu.cs index cc18111..fbfeb96 100644 --- a/AxibugEmuOnline.Client/Assets/MyNes.Core/NesEmu.cs +++ b/AxibugEmuOnline.Client/Assets/MyNes.Core/NesEmu.cs @@ -10,5804 +10,5798 @@ namespace MyNes.Core { public class NesEmu { - [StructLayout(LayoutKind.Explicit)] - private struct CPURegister - { - [FieldOffset(0)] - internal byte l; + [StructLayout(LayoutKind.Explicit)] + private struct CPURegister + { + [FieldOffset(0)] + internal byte l; - [FieldOffset(1)] - internal byte h; + [FieldOffset(1)] + internal byte h; - [FieldOffset(0)] - internal ushort v; - } + [FieldOffset(0)] + internal ushort v; + } - private enum RequestMode - { - None, - HardReset, - SoftReset, - LoadState, - SaveState, - TakeSnapshot - } + private enum RequestMode + { + None, + HardReset, + SoftReset, + LoadState, + SaveState, + TakeSnapshot + } - private static int[][] dmc_freq_table = new int[3][] - { - new int[16] - { - 428, 380, 340, 320, 286, 254, 226, 214, 190, 160, - 142, 128, 106, 84, 72, 54 - }, - new int[16] - { - 398, 354, 316, 298, 276, 236, 210, 198, 176, 148, - 132, 118, 98, 78, 66, 50 - }, - new int[16] - { - 428, 380, 340, 320, 286, 254, 226, 214, 190, 160, - 142, 128, 106, 84, 72, 54 - } - }; + private static int[][] dmc_freq_table = new int[3][] + { + new int[16] + { + 428, 380, 340, 320, 286, 254, 226, 214, 190, 160, + 142, 128, 106, 84, 72, 54 + }, + new int[16] + { + 398, 354, 316, 298, 276, 236, 210, 198, 176, 148, + 132, 118, 98, 78, 66, 50 + }, + new int[16] + { + 428, 380, 340, 320, 286, 254, 226, 214, 190, 160, + 142, 128, 106, 84, 72, 54 + } + }; - private static int dmc_output_a; + private static int dmc_output_a; - private static int dmc_output; + private static int dmc_output; - private static int dmc_period_devider; + private static int dmc_period_devider; - private static bool dmc_irq_enabled; + private static bool dmc_irq_enabled; - private static bool dmc_loop_flag; + private static bool dmc_loop_flag; - private static byte dmc_rate_index; + private static byte dmc_rate_index; - private static ushort dmc_addr_refresh; + private static ushort dmc_addr_refresh; - private static int dmc_size_refresh; + private static int dmc_size_refresh; - private static bool dmc_dmaEnabled; + private static bool dmc_dmaEnabled; - private static byte dmc_dmaByte; + private static byte dmc_dmaByte; - private static int dmc_dmaBits; + private static int dmc_dmaBits; - private static bool dmc_bufferFull; + private static bool dmc_bufferFull; - private static byte dmc_dmaBuffer; + private static byte dmc_dmaBuffer; - private static int dmc_dmaSize; + private static int dmc_dmaSize; - private static ushort dmc_dmaAddr; + private static ushort dmc_dmaAddr; - private static ushort[][] nos_freq_table = new ushort[3][] - { - new ushort[16] - { - 4, 8, 16, 32, 64, 96, 128, 160, 202, 254, - 380, 508, 762, 1016, 2034, 4068 - }, - new ushort[16] - { - 4, 7, 14, 30, 60, 88, 118, 148, 188, 236, - 354, 472, 708, 944, 1890, 3778 - }, - new ushort[16] - { - 4, 8, 16, 32, 64, 96, 128, 160, 202, 254, - 380, 508, 762, 1016, 2034, 4068 - } - }; + private static ushort[][] nos_freq_table = new ushort[3][] + { + new ushort[16] + { + 4, 8, 16, 32, 64, 96, 128, 160, 202, 254, + 380, 508, 762, 1016, 2034, 4068 + }, + new ushort[16] + { + 4, 7, 14, 30, 60, 88, 118, 148, 188, 236, + 354, 472, 708, 944, 1890, 3778 + }, + new ushort[16] + { + 4, 8, 16, 32, 64, 96, 128, 160, 202, 254, + 380, 508, 762, 1016, 2034, 4068 + } + }; - private static bool nos_length_halt; + private static bool nos_length_halt; - private static bool nos_constant_volume_envelope; + private static bool nos_constant_volume_envelope; - private static byte nos_volume_devider_period; + private static byte nos_volume_devider_period; - private static ushort nos_timer; + private static ushort nos_timer; - private static bool nos_mode; + private static bool nos_mode; - private static int nos_period_devider; + private static int nos_period_devider; - private static bool nos_length_enabled; + private static bool nos_length_enabled; - private static int nos_length_counter; + private static int nos_length_counter; - private static bool nos_envelope_start_flag; + private static bool nos_envelope_start_flag; - private static byte nos_envelope_devider; + private static byte nos_envelope_devider; - private static byte nos_envelope_decay_level_counter; + private static byte nos_envelope_decay_level_counter; - private static byte nos_envelope; + private static byte nos_envelope; - private static int nos_output; + private static int nos_output; - private static int nos_shift_reg; + private static int nos_shift_reg; - private static int nos_feedback; + private static int nos_feedback; - private static bool nos_ignore_reload; + private static bool nos_ignore_reload; - private static byte[][] sq_duty_cycle_sequences = new byte[4][] - { - new byte[8] { 0, 0, 0, 0, 0, 0, 0, 1 }, - new byte[8] { 0, 0, 0, 0, 0, 0, 1, 1 }, - new byte[8] { 0, 0, 0, 0, 1, 1, 1, 1 }, - new byte[8] { 1, 1, 1, 1, 1, 1, 0, 0 } - }; + private static byte[][] sq_duty_cycle_sequences = new byte[4][] + { + new byte[8] { 0, 0, 0, 0, 0, 0, 0, 1 }, + new byte[8] { 0, 0, 0, 0, 0, 0, 1, 1 }, + new byte[8] { 0, 0, 0, 0, 1, 1, 1, 1 }, + new byte[8] { 1, 1, 1, 1, 1, 1, 0, 0 } + }; - private static byte[] sq_duration_table = new byte[32] - { - 10, 254, 20, 2, 40, 4, 80, 6, 160, 8, - 60, 10, 14, 12, 26, 14, 12, 16, 24, 18, - 48, 20, 96, 22, 192, 24, 72, 26, 16, 28, - 32, 30 - }; + private static byte[] sq_duration_table = new byte[32] + { + 10, 254, 20, 2, 40, 4, 80, 6, 160, 8, + 60, 10, 14, 12, 26, 14, 12, 16, 24, 18, + 48, 20, 96, 22, 192, 24, 72, 26, 16, 28, + 32, 30 + }; - private static byte sq1_duty_cycle; + private static byte sq1_duty_cycle; - private static bool sq1_length_halt; + private static bool sq1_length_halt; - private static bool sq1_constant_volume_envelope; + private static bool sq1_constant_volume_envelope; - private static byte sq1_volume_devider_period; + private static byte sq1_volume_devider_period; - private static bool sq1_sweep_enable; + private static bool sq1_sweep_enable; - private static byte sq1_sweep_devider_period; + private static byte sq1_sweep_devider_period; - private static bool sq1_sweep_negate; + private static bool sq1_sweep_negate; - private static byte sq1_sweep_shift_count; + private static byte sq1_sweep_shift_count; - private static int sq1_timer; + private static int sq1_timer; - private static int sq1_period_devider; + private static int sq1_period_devider; - private static byte sq1_seqencer; + private static byte sq1_seqencer; - private static bool sq1_length_enabled; + private static bool sq1_length_enabled; - private static int sq1_length_counter; + private static int sq1_length_counter; - private static bool sq1_envelope_start_flag; + private static bool sq1_envelope_start_flag; - private static byte sq1_envelope_devider; + private static byte sq1_envelope_devider; - private static byte sq1_envelope_decay_level_counter; + private static byte sq1_envelope_decay_level_counter; - private static byte sq1_envelope; + private static byte sq1_envelope; - private static int sq1_sweep_counter; + private static int sq1_sweep_counter; - private static bool sq1_sweep_reload; + private static bool sq1_sweep_reload; - private static int sq1_sweep_change; + private static int sq1_sweep_change; - private static bool sq1_valid_freq; + private static bool sq1_valid_freq; - private static int sq1_output; + private static int sq1_output; - private static bool sq1_ignore_reload; + private static bool sq1_ignore_reload; - private static byte[] trl_step_seq = new byte[32] - { - 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, - 5, 4, 3, 2, 1, 0, 0, 1, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15 - }; + private static byte[] trl_step_seq = new byte[32] + { + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, + 5, 4, 3, 2, 1, 0, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15 + }; - private static bool trl_liner_control_flag; + private static bool trl_liner_control_flag; - private static byte trl_liner_control_reload; + private static byte trl_liner_control_reload; - private static ushort trl_timer; + private static ushort trl_timer; - private static bool trl_length_enabled; + private static bool trl_length_enabled; - private static byte trl_length_counter; + private static byte trl_length_counter; - private static bool trl_liner_control_reload_flag; + private static bool trl_liner_control_reload_flag; - private static byte trl_liner_counter; + private static byte trl_liner_counter; - private static int trl_output; + private static int trl_output; - private static int trl_period_devider; + private static int trl_period_devider; - private static int trl_step; + private static int trl_step; - private static bool trl_ignore_reload; + private static bool trl_ignore_reload; - private static byte apu_reg_io_db; + private static byte apu_reg_io_db; - private static byte apu_reg_io_addr; + private static byte apu_reg_io_addr; - private static bool apu_reg_access_happened; + private static bool apu_reg_access_happened; - private static bool apu_reg_access_w; + private static bool apu_reg_access_w; - private static Action[] apu_reg_update_func; + private static Action[] apu_reg_update_func; - private static Action[] apu_reg_read_func; + private static Action[] apu_reg_read_func; - private static Action[] apu_reg_write_func; + private static Action[] apu_reg_write_func; - private static Action apu_update_playback_func; + private static Action apu_update_playback_func; - private static bool apu_odd_cycle; + private static bool apu_odd_cycle; - private static bool apu_irq_enabled; + private static bool apu_irq_enabled; - private static bool apu_irq_flag; + private static bool apu_irq_flag; - private static bool apu_irq_do_it; + private static bool apu_irq_do_it; - internal static bool apu_irq_delta_occur; + internal static bool apu_irq_delta_occur; - private static bool apu_seq_mode; + private static bool apu_seq_mode; - private static int apu_ferq_f; + private static int apu_ferq_f; - private static int apu_ferq_l; + private static int apu_ferq_l; - private static int apu_ferq_e; + private static int apu_ferq_e; - private static int apu_cycle_f; + private static int apu_cycle_f; - private static int apu_cycle_f_t; + private static int apu_cycle_f_t; - private static int apu_cycle_e; + private static int apu_cycle_e; - private static int apu_cycle_l; + private static int apu_cycle_l; - private static bool apu_odd_l; + private static bool apu_odd_l; - private static bool apu_check_irq; + private static bool apu_check_irq; - private static bool apu_do_env; + private static bool apu_do_env; - private static bool apu_do_length; + private static bool apu_do_length; - public static bool SoundEnabled; + public static bool SoundEnabled; - public static double audio_playback_amplitude = 1.5; + public static double audio_playback_amplitude = 1.5; - public static int audio_playback_peek_limit = 124; + public static int audio_playback_peek_limit = 124; - private static bool audio_playback_dac_initialized; + private static bool audio_playback_dac_initialized; - public static int cpu_speed; + public static int cpu_speed; - private static short[] audio_samples; + private static short[] audio_samples; - private static int audio_w_pos; + private static int audio_w_pos; - private static int audio_samples_added; + private static int audio_samples_added; - internal static int audio_samples_count; + internal static int audio_samples_count; - private static int[][][][][] mix_table; + private static int[][][][][] mix_table; - private static double audio_x; + private static double audio_x; - private static double audio_y; + private static double audio_y; - private static double audio_y_av; + private static double audio_y_av; - private static double audio_y_timer; + private static double audio_y_timer; - public static double audio_timer_ratio = 40.0; + public static double audio_timer_ratio = 40.0; - private static double audio_timer; + private static double audio_timer; - private static SoundLowPassFilter audio_low_pass_filter_14K; + private static SoundLowPassFilter audio_low_pass_filter_14K; - private static SoundHighPassFilter audio_high_pass_filter_90; + private static SoundHighPassFilter audio_high_pass_filter_90; - private static SoundHighPassFilter audio_high_pass_filter_440; + private static SoundHighPassFilter audio_high_pass_filter_440; - private static SoundDCBlockerFilter audio_dc_blocker_filter; + private static SoundDCBlockerFilter audio_dc_blocker_filter; - private static bool audio_sq1_outputable; + private static bool audio_sq1_outputable; - private static bool audio_sq2_outputable; + private static bool audio_sq2_outputable; - private static bool audio_nos_outputable; + private static bool audio_nos_outputable; - private static bool audio_trl_outputable; + private static bool audio_trl_outputable; - private static bool audio_dmc_outputable; + private static bool audio_dmc_outputable; - private static bool audio_signal_outputed; + private static bool audio_signal_outputed; - private static bool apu_use_external_sound; + private static bool apu_use_external_sound; - private static CPURegister cpu_reg_pc; + private static CPURegister cpu_reg_pc; - private static CPURegister cpu_reg_sp; + private static CPURegister cpu_reg_sp; - private static CPURegister cpu_reg_ea; + private static CPURegister cpu_reg_ea; - private static byte cpu_reg_a; + private static byte cpu_reg_a; - private static byte cpu_reg_x; + private static byte cpu_reg_x; - private static byte cpu_reg_y; + private static byte cpu_reg_y; - private static bool cpu_flag_n; + private static bool cpu_flag_n; - private static bool cpu_flag_v; + private static bool cpu_flag_v; - private static bool cpu_flag_d; + private static bool cpu_flag_d; - private static bool cpu_flag_i; + private static bool cpu_flag_i; - private static bool cpu_flag_z; + private static bool cpu_flag_z; - private static bool cpu_flag_c; + private static bool cpu_flag_c; - private static byte cpu_m; + private static byte cpu_m; - private static byte cpu_opcode; + private static byte cpu_opcode; - private static byte cpu_byte_temp; + private static byte cpu_byte_temp; - private static int cpu_int_temp; + private static int cpu_int_temp; - private static int cpu_int_temp1; + private static int cpu_int_temp1; - private static byte cpu_dummy; + private static byte cpu_dummy; - private static bool cpu_bool_tmp; + private static bool cpu_bool_tmp; - private static CPURegister temp_add; + private static CPURegister temp_add; - private static bool CPU_IRQ_PIN; + private static bool CPU_IRQ_PIN; - private static bool CPU_NMI_PIN; + private static bool CPU_NMI_PIN; - private static bool cpu_suspend_nmi; + private static bool cpu_suspend_nmi; - private static bool cpu_suspend_irq; + private static bool cpu_suspend_irq; - private static Action[] cpu_addressings; + private static Action[] cpu_addressings; - private static Action[] cpu_instructions; + private static Action[] cpu_instructions; - private static int dma_DMCDMAWaitCycles; + private static int dma_DMCDMAWaitCycles; - private static int dma_OAMDMAWaitCycles; + private static int dma_OAMDMAWaitCycles; - private static bool dma_isOamDma; + private static bool dma_isOamDma; - private static int dma_oamdma_i; + private static int dma_oamdma_i; - private static bool dma_DMCOn; + private static bool dma_DMCOn; - private static bool dma_OAMOn; + private static bool dma_OAMOn; - private static bool dma_DMC_occurring; + private static bool dma_DMC_occurring; - private static bool dma_OAM_occurring; + private static bool dma_OAM_occurring; - private static int dma_OAMFinishCounter; + private static int dma_OAMFinishCounter; - private static ushort dma_Oamaddress; + private static ushort dma_Oamaddress; - private static int dma_OAMCYCLE; + private static int dma_OAMCYCLE; - private static byte dma_latch; + private static byte dma_latch; - private static byte dma_dummy; + private static byte dma_dummy; - private static ushort reg_2004; + private static ushort reg_2004; - internal static int IRQFlags = 0; + internal static int IRQFlags = 0; - private static bool PPU_NMI_Current; + private static bool PPU_NMI_Current; - private static bool PPU_NMI_Old; + private static bool PPU_NMI_Old; - private const int IRQ_APU = 1; + private const int IRQ_APU = 1; - internal const int IRQ_DMC = 2; + internal const int IRQ_DMC = 2; - internal const int IRQ_BOARD = 8; + internal const int IRQ_BOARD = 8; - private static ushort InterruptVector; + private static ushort InterruptVector; - private static byte[] mem_wram; + private static byte[] mem_wram; - internal static Board mem_board; + internal static Board mem_board; - private static MemReadAccess[] mem_read_accesses; + private static MemReadAccess[] mem_read_accesses; - private static MemWriteAccess[] mem_write_accesses; + private static MemWriteAccess[] mem_write_accesses; - private static bool BUS_RW; + private static bool BUS_RW; - private static ushort BUS_ADDRESS; + private static ushort BUS_ADDRESS; - private static string SRAMFileName; + private static string SRAMFileName; - public static string GMFileName; + public static string GMFileName; - private static int PORT0; + private static int PORT0; - private static int PORT1; + private static int PORT1; - private static int inputStrobe; + private static int inputStrobe; - private static IJoypadConnecter joypad1; + private static IJoypadConnecter joypad1; - private static IJoypadConnecter joypad2; + private static IJoypadConnecter joypad2; - private static IJoypadConnecter joypad3; + private static IJoypadConnecter joypad3; - private static IJoypadConnecter joypad4; + private static IJoypadConnecter joypad4; - private static IShortcutsHandler shortucts; + private static IShortcutsHandler shortucts; - public static bool IsFourPlayers; + public static bool IsFourPlayers; - private static byte[] reverseLookup = new byte[256] - { - 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, - 80, 208, 48, 176, 112, 240, 8, 136, 72, 200, - 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, - 120, 248, 4, 132, 68, 196, 36, 164, 100, 228, - 20, 148, 84, 212, 52, 180, 116, 244, 12, 140, - 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, - 60, 188, 124, 252, 2, 130, 66, 194, 34, 162, - 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, - 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, - 90, 218, 58, 186, 122, 250, 6, 134, 70, 198, - 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, - 118, 246, 14, 142, 78, 206, 46, 174, 110, 238, - 30, 158, 94, 222, 62, 190, 126, 254, 1, 129, - 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, - 49, 177, 113, 241, 9, 137, 73, 201, 41, 169, - 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, - 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, - 85, 213, 53, 181, 117, 245, 13, 141, 77, 205, - 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, - 125, 253, 3, 131, 67, 195, 35, 163, 99, 227, - 19, 147, 83, 211, 51, 179, 115, 243, 11, 139, - 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, - 59, 187, 123, 251, 7, 135, 71, 199, 39, 167, - 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, - 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, - 95, 223, 63, 191, 127, 255 - }; + private static byte[] reverseLookup = new byte[256] + { + 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, + 80, 208, 48, 176, 112, 240, 8, 136, 72, 200, + 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, + 120, 248, 4, 132, 68, 196, 36, 164, 100, 228, + 20, 148, 84, 212, 52, 180, 116, 244, 12, 140, + 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, + 60, 188, 124, 252, 2, 130, 66, 194, 34, 162, + 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, + 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, + 90, 218, 58, 186, 122, 250, 6, 134, 70, 198, + 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, + 118, 246, 14, 142, 78, 206, 46, 174, 110, 238, + 30, 158, 94, 222, 62, 190, 126, 254, 1, 129, + 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, + 49, 177, 113, 241, 9, 137, 73, 201, 41, 169, + 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, + 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, + 85, 213, 53, 181, 117, 245, 13, 141, 77, 205, + 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, + 125, 253, 3, 131, 67, 195, 35, 163, 99, 227, + 19, 147, 83, 211, 51, 179, 115, 243, 11, 139, + 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, + 59, 187, 123, 251, 7, 135, 71, 199, 39, 167, + 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, + 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, + 95, 223, 63, 191, 127, 255 + }; - private static Action[] ppu_v_clocks; + private static Action[] ppu_v_clocks; - private static Action[] ppu_h_clocks; + private static Action[] ppu_h_clocks; - private static Action[] ppu_bkg_fetches; + private static Action[] ppu_bkg_fetches; - private static Action[] ppu_spr_fetches; + private static Action[] ppu_spr_fetches; - private static Action[] ppu_oam_phases; + private static Action[] ppu_oam_phases; - private static int[] ppu_bkg_pixels; + private static int[] ppu_bkg_pixels; - private static int[] ppu_spr_pixels; + private static int[] ppu_spr_pixels; - private static int[] ppu_screen_pixels; + private static int[] ppu_screen_pixels; - private static int[] ppu_palette; + private static int[] ppu_palette; - private static int ppu_clock_h; + private static int ppu_clock_h; - internal static ushort ppu_clock_v; + internal static ushort ppu_clock_v; - private static ushort ppu_clock_vblank_start; + private static ushort ppu_clock_vblank_start; - private static ushort ppu_clock_vblank_end; + private static ushort ppu_clock_vblank_end; - private static bool ppu_use_odd_cycle; + private static bool ppu_use_odd_cycle; - private static bool ppu_use_odd_swap; + private static bool ppu_use_odd_swap; - private static bool ppu_odd_swap_done; + private static bool ppu_odd_swap_done; - private static bool ppu_is_nmi_time; + private static bool ppu_is_nmi_time; - private static bool ppu_frame_finished; + private static bool ppu_frame_finished; - private static byte[] ppu_oam_bank; + private static byte[] ppu_oam_bank; - private static byte[] ppu_oam_bank_secondary; + private static byte[] ppu_oam_bank_secondary; - private static byte[] ppu_palette_bank; + private static byte[] ppu_palette_bank; - private static byte ppu_reg_io_db; + private static byte ppu_reg_io_db; - private static byte ppu_reg_io_addr; + private static byte ppu_reg_io_addr; - private static bool ppu_reg_access_happened; + private static bool ppu_reg_access_happened; - private static bool ppu_reg_access_w; + private static bool ppu_reg_access_w; - private static Action[] ppu_reg_update_func; + private static Action[] ppu_reg_update_func; - private static Action[] ppu_reg_read_func; + private static Action[] ppu_reg_read_func; - private static byte ppu_reg_2000_vram_address_increament; + private static byte ppu_reg_2000_vram_address_increament; - private static ushort ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites; + private static ushort ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites; - private static ushort ppu_reg_2000_background_pattern_table_address; + private static ushort ppu_reg_2000_background_pattern_table_address; - internal static byte ppu_reg_2000_Sprite_size; + internal static byte ppu_reg_2000_Sprite_size; - private static bool ppu_reg_2000_VBI; + private static bool ppu_reg_2000_VBI; - private static bool ppu_reg_2001_show_background_in_leftmost_8_pixels_of_screen; + private static bool ppu_reg_2001_show_background_in_leftmost_8_pixels_of_screen; - private static bool ppu_reg_2001_show_sprites_in_leftmost_8_pixels_of_screen; + private static bool ppu_reg_2001_show_sprites_in_leftmost_8_pixels_of_screen; - private static bool ppu_reg_2001_show_background; + private static bool ppu_reg_2001_show_background; - private static bool ppu_reg_2001_show_sprites; + private static bool ppu_reg_2001_show_sprites; - private static int ppu_reg_2001_grayscale; + private static int ppu_reg_2001_grayscale; - private static int ppu_reg_2001_emphasis; + private static int ppu_reg_2001_emphasis; - private static bool ppu_reg_2002_SpriteOverflow; + private static bool ppu_reg_2002_SpriteOverflow; - private static bool ppu_reg_2002_Sprite0Hit; + private static bool ppu_reg_2002_Sprite0Hit; - private static bool ppu_reg_2002_VblankStartedFlag; + private static bool ppu_reg_2002_VblankStartedFlag; - private static byte ppu_reg_2003_oam_addr; + private static byte ppu_reg_2003_oam_addr; - private static ushort ppu_vram_addr; + private static ushort ppu_vram_addr; - private static byte ppu_vram_data; + private static byte ppu_vram_data; - private static ushort ppu_vram_addr_temp; + private static ushort ppu_vram_addr_temp; - private static ushort ppu_vram_addr_access_temp; + private static ushort ppu_vram_addr_access_temp; - private static bool ppu_vram_flip_flop; + private static bool ppu_vram_flip_flop; - private static byte ppu_vram_finex; + private static byte ppu_vram_finex; - private static ushort ppu_bkgfetch_nt_addr; + private static ushort ppu_bkgfetch_nt_addr; - private static byte ppu_bkgfetch_nt_data; + private static byte ppu_bkgfetch_nt_data; - private static ushort ppu_bkgfetch_at_addr; + private static ushort ppu_bkgfetch_at_addr; - private static byte ppu_bkgfetch_at_data; + private static byte ppu_bkgfetch_at_data; - private static ushort ppu_bkgfetch_lb_addr; + private static ushort ppu_bkgfetch_lb_addr; - private static byte ppu_bkgfetch_lb_data; + private static byte ppu_bkgfetch_lb_data; - private static ushort ppu_bkgfetch_hb_addr; + private static ushort ppu_bkgfetch_hb_addr; - private static byte ppu_bkgfetch_hb_data; + private static byte ppu_bkgfetch_hb_data; - private static int ppu_sprfetch_slot; + private static int ppu_sprfetch_slot; - private static byte ppu_sprfetch_y_data; + private static byte ppu_sprfetch_y_data; - private static byte ppu_sprfetch_t_data; + private static byte ppu_sprfetch_t_data; - private static byte ppu_sprfetch_at_data; + private static byte ppu_sprfetch_at_data; - private static byte ppu_sprfetch_x_data; + private static byte ppu_sprfetch_x_data; - private static ushort ppu_sprfetch_lb_addr; + private static ushort ppu_sprfetch_lb_addr; - private static byte ppu_sprfetch_lb_data; + private static byte ppu_sprfetch_lb_data; - private static ushort ppu_sprfetch_hb_addr; + private static ushort ppu_sprfetch_hb_addr; - private static byte ppu_sprfetch_hb_data; + private static byte ppu_sprfetch_hb_data; - internal static bool ppu_is_sprfetch; + internal static bool ppu_is_sprfetch; - private static int ppu_bkg_render_i; + private static int ppu_bkg_render_i; - private static int ppu_bkg_render_pos; + private static int ppu_bkg_render_pos; - private static int ppu_bkg_render_tmp_val; + private static int ppu_bkg_render_tmp_val; - private static int ppu_bkg_current_pixel; + private static int ppu_bkg_current_pixel; - private static int ppu_spr_current_pixel; + private static int ppu_spr_current_pixel; - private static int ppu_current_pixel; + private static int ppu_current_pixel; - private static int ppu_render_x; + private static int ppu_render_x; - private static int ppu_render_y; + private static int ppu_render_y; - private static byte ppu_oamev_n; + private static byte ppu_oamev_n; - private static byte ppu_oamev_m; + private static byte ppu_oamev_m; - private static bool ppu_oamev_compare; + private static bool ppu_oamev_compare; - private static byte ppu_oamev_slot; + private static byte ppu_oamev_slot; - private static byte ppu_fetch_data; + private static byte ppu_fetch_data; - private static byte ppu_phase_index; + private static byte ppu_phase_index; - private static bool ppu_sprite0_should_hit; + private static bool ppu_sprite0_should_hit; - private static int ppu_temp_comparator; + private static int ppu_temp_comparator; - public static bool ON; + public static bool ON; - public static bool PAUSED; + public static bool PAUSED; - public static bool isPaused; + public static bool isPaused; - public static string CurrentFilePath; + public static string CurrentFilePath; - public static bool FrameLimiterEnabled; + public static bool FrameLimiterEnabled; - private static Thread mainThread; + private static Thread mainThread; - private static double fps_time_last; + private static double fps_time_last; - private static double fps_time_start; + private static double fps_time_start; - private static double fps_time_token; + private static double fps_time_token; - private static double fps_time_dead; + private static double fps_time_dead; - private static double fps_time_period; + private static double fps_time_period; - private static double fps_time_frame_time; + private static double fps_time_frame_time; - private static double emu_time_target_fps = 60.0; + private static double emu_time_target_fps = 60.0; - private static bool emu_frame_clocking_mode; + private static bool emu_frame_clocking_mode; - private static bool emu_frame_done; + private static bool emu_frame_done; - private static bool render_initialized; + private static bool render_initialized; - private static RenderVideoFrame render_video; + private static RenderVideoFrame render_video; - private static RenderAudioSamples render_audio; + private static RenderAudioSamples render_audio; - private static TogglePause render_audio_toggle_pause; + private static TogglePause render_audio_toggle_pause; - private static GetIsPlaying render_audio_get_is_playing; + private static GetIsPlaying render_audio_get_is_playing; - private static bool render_audio_is_playing; + private static bool render_audio_is_playing; - public static EmuRegion Region; + public static EmuRegion Region; - private static int SystemIndex; + private static int SystemIndex; - private static RequestMode emu_request_mode = RequestMode.None; + private static RequestMode emu_request_mode = RequestMode.None; - public static bool FrameSkipEnabled; + public static bool FrameSkipEnabled; - public static int FrameSkipInterval; + public static int FrameSkipInterval; - private static int FrameSkipCounter; + private static int FrameSkipCounter; - private static byte sq2_duty_cycle; + private static byte sq2_duty_cycle; - private static bool sq2_length_halt; + private static bool sq2_length_halt; - private static bool sq2_constant_volume_envelope; + private static bool sq2_constant_volume_envelope; - private static byte sq2_volume_devider_period; + private static byte sq2_volume_devider_period; - private static bool sq2_sweep_enable; + private static bool sq2_sweep_enable; - private static byte sq2_sweep_devider_period; + private static byte sq2_sweep_devider_period; - private static bool sq2_sweep_negate; + private static bool sq2_sweep_negate; - private static byte sq2_sweep_shift_count; + private static byte sq2_sweep_shift_count; - private static int sq2_timer; + private static int sq2_timer; - private static int sq2_period_devider; + private static int sq2_period_devider; - private static byte sq2_seqencer; + private static byte sq2_seqencer; - private static bool sq2_length_enabled; + private static bool sq2_length_enabled; - private static int sq2_length_counter; + private static int sq2_length_counter; - private static bool sq2_envelope_start_flag; + private static bool sq2_envelope_start_flag; - private static byte sq2_envelope_devider; + private static byte sq2_envelope_devider; - private static byte sq2_envelope_decay_level_counter; + private static byte sq2_envelope_decay_level_counter; - private static byte sq2_envelope; + private static byte sq2_envelope; - private static int sq2_sweep_counter; + private static int sq2_sweep_counter; - private static bool sq2_sweep_reload; + private static bool sq2_sweep_reload; - private static int sq2_sweep_change; + private static int sq2_sweep_change; - private static bool sq2_valid_freq; + private static bool sq2_valid_freq; - private static int sq2_output; + private static int sq2_output; - private static bool sq2_ignore_reload; + private static bool sq2_ignore_reload; - private static byte register_p - { - get - { - return (byte)((cpu_flag_n ? 128u : 0u) | (cpu_flag_v ? 64u : 0u) | (cpu_flag_d ? 8u : 0u) | (cpu_flag_i ? 4u : 0u) | (cpu_flag_z ? 2u : 0u) | (cpu_flag_c ? 1u : 0u) | 0x20u); - } - set - { - cpu_flag_n = (value & 0x80) != 0; - cpu_flag_v = (value & 0x40) != 0; - cpu_flag_d = (value & 8) != 0; - cpu_flag_i = (value & 4) != 0; - cpu_flag_z = (value & 2) != 0; - cpu_flag_c = (value & 1) != 0; - } - } + private static byte register_p + { + get + { + return (byte)((cpu_flag_n ? 128u : 0u) | (cpu_flag_v ? 64u : 0u) | (cpu_flag_d ? 8u : 0u) | (cpu_flag_i ? 4u : 0u) | (cpu_flag_z ? 2u : 0u) | (cpu_flag_c ? 1u : 0u) | 0x20u); + } + set + { + cpu_flag_n = (value & 0x80) != 0; + cpu_flag_v = (value & 0x40) != 0; + cpu_flag_d = (value & 8) != 0; + cpu_flag_i = (value & 4) != 0; + cpu_flag_z = (value & 2) != 0; + cpu_flag_c = (value & 1) != 0; + } + } - public static GameGenieCode[] GameGenieCodes - { - get - { - if (mem_board != null) - { - return mem_board.GameGenieCodes; - } - return null; - } - } - - public static bool IsGameGenieActive - { - get - { - if (mem_board != null) - { - return mem_board.IsGameGenieActive; - } - return false; - } - set - { - if (mem_board != null) - { - mem_board.IsGameGenieActive = value; - } - } - } - - public static bool IsGameFoundOnDB - { - get - { - if (mem_board != null) - { - return mem_board.IsGameFoundOnDB; - } - return false; - } - } - - public static NesCartDatabaseGameInfo GameInfo - { - get - { - if (mem_board != null) - { - return mem_board.GameInfo; - } - return NesCartDatabaseGameInfo.Empty; - } - } - - public static NesCartDatabaseCartridgeInfo GameCartInfo - { - get - { - if (mem_board != null) - { - return mem_board.GameCartInfo; - } - return new NesCartDatabaseCartridgeInfo(); - } - } - - public static string SHA1 => mem_board.SHA1; - - public static event EventHandler EmuShutdown; - - private static void DMCHardReset() - { - dmc_output_a = 0; - dmc_output = 0; - dmc_period_devider = 0; - dmc_loop_flag = false; - dmc_rate_index = 0; - dmc_irq_enabled = false; - dmc_dmaAddr = 49152; - dmc_addr_refresh = 49152; - dmc_size_refresh = 0; - dmc_dmaBits = 1; - dmc_dmaByte = 1; - dmc_period_devider = 0; - dmc_dmaEnabled = false; - dmc_bufferFull = false; - dmc_dmaSize = 0; - } - - private static void DMCSoftReset() - { - DMCHardReset(); - } - - private static void DMCClock() - { - dmc_period_devider--; - if (dmc_period_devider > 0) - { - return; - } - dmc_period_devider = dmc_freq_table[SystemIndex][dmc_rate_index]; - if (dmc_dmaEnabled) - { - if (((uint)dmc_dmaByte & (true ? 1u : 0u)) != 0) - { - if (dmc_output_a <= 125) - { - dmc_output_a += 2; - } - } - else if (dmc_output_a >= 2) - { - dmc_output_a -= 2; - } - dmc_dmaByte >>= 1; - } - dmc_dmaBits--; - if (dmc_dmaBits == 0) - { - dmc_dmaBits = 8; - if (dmc_bufferFull) - { - dmc_bufferFull = false; - dmc_dmaEnabled = true; - dmc_dmaByte = dmc_dmaBuffer; - if (dmc_dmaSize > 0) - { - AssertDMCDMA(); - } - } - else - { - dmc_dmaEnabled = false; - } - } - if (audio_dmc_outputable) - { - dmc_output = dmc_output_a; - } - audio_signal_outputed = true; - } - - private static void DMCDoDMA() - { - dmc_bufferFull = true; - Read(ref dmc_dmaAddr, out dmc_dmaBuffer); - if (dmc_dmaAddr == ushort.MaxValue) - { - dmc_dmaAddr = 32768; - } - else - { - dmc_dmaAddr++; - } - if (dmc_dmaSize > 0) - { - dmc_dmaSize--; - } - if (dmc_dmaSize == 0) - { - if (dmc_loop_flag) - { - dmc_dmaSize = dmc_size_refresh; - dmc_dmaAddr = dmc_addr_refresh; - } - else if (dmc_irq_enabled) - { - IRQFlags |= 2; - apu_irq_delta_occur = true; - } - } - } - - private static void APUOnRegister4010() - { - if (apu_reg_access_w) - { - dmc_irq_enabled = (apu_reg_io_db & 0x80) != 0; - dmc_loop_flag = (apu_reg_io_db & 0x40) != 0; - if (!dmc_irq_enabled) - { - apu_irq_delta_occur = false; - IRQFlags &= -3; - } - dmc_rate_index = (byte)(apu_reg_io_db & 0xFu); - } - } - - private static void APUOnRegister4011() - { - if (apu_reg_access_w) - { - dmc_output_a = (byte)(apu_reg_io_db & 0x7F); - } - } - - private static void APUOnRegister4012() - { - if (apu_reg_access_w) - { - dmc_addr_refresh = (ushort)((uint)(apu_reg_io_db << 6) | 0xC000u); - } - } - - private static void APUOnRegister4013() - { - if (apu_reg_access_w) - { - dmc_size_refresh = (apu_reg_io_db << 4) | 1; - } - } - - private static void DMCOn4015() - { - apu_irq_delta_occur = false; - IRQFlags &= -3; - } - - private static void DMCRead4015() - { - if (dmc_dmaSize > 0) - { - apu_reg_io_db = (byte)((apu_reg_io_db & 0xEFu) | 0x10u); - } - } - - private static void DMCWriteState(ref BinaryWriter bin) - { - bin.Write(dmc_output_a); - bin.Write(dmc_output); - bin.Write(dmc_period_devider); - bin.Write(dmc_irq_enabled); - bin.Write(dmc_loop_flag); - bin.Write(dmc_rate_index); - bin.Write(dmc_addr_refresh); - bin.Write(dmc_size_refresh); - bin.Write(dmc_dmaEnabled); - bin.Write(dmc_dmaByte); - bin.Write(dmc_dmaBits); - bin.Write(dmc_bufferFull); - bin.Write(dmc_dmaBuffer); - bin.Write(dmc_dmaSize); - bin.Write(dmc_dmaAddr); - } - - private static void DMCReadState(ref BinaryReader bin) - { - dmc_output_a = bin.ReadInt32(); - dmc_output = bin.ReadInt32(); - dmc_period_devider = bin.ReadInt32(); - dmc_irq_enabled = bin.ReadBoolean(); - dmc_loop_flag = bin.ReadBoolean(); - dmc_rate_index = bin.ReadByte(); - dmc_addr_refresh = bin.ReadUInt16(); - dmc_size_refresh = bin.ReadInt32(); - dmc_dmaEnabled = bin.ReadBoolean(); - dmc_dmaByte = bin.ReadByte(); - dmc_dmaBits = bin.ReadInt32(); - dmc_bufferFull = bin.ReadBoolean(); - dmc_dmaBuffer = bin.ReadByte(); - dmc_dmaSize = bin.ReadInt32(); - dmc_dmaAddr = bin.ReadUInt16(); - } - - private static void NOSHardReset() - { - nos_length_halt = false; - nos_constant_volume_envelope = false; - nos_volume_devider_period = 0; - nos_shift_reg = 1; - nos_timer = 0; - nos_mode = false; - nos_period_devider = 0; - nos_length_enabled = false; - nos_length_counter = 0; - nos_envelope_start_flag = false; - nos_envelope_devider = 0; - nos_envelope_decay_level_counter = 0; - nos_envelope = 0; - nos_output = 0; - nos_feedback = 0; - nos_ignore_reload = false; - } - - private static void NOSSoftReset() - { - NOSHardReset(); - } - - private static void NOSClock() - { - nos_period_devider--; - if (nos_period_devider > 0) - { - return; - } - nos_period_devider = nos_timer; - if (nos_mode) - { - nos_feedback = ((nos_shift_reg >> 6) & 1) ^ (nos_shift_reg & 1); - } - else - { - nos_feedback = ((nos_shift_reg >> 1) & 1) ^ (nos_shift_reg & 1); - } - nos_shift_reg >>= 1; - nos_shift_reg = (nos_shift_reg & 0x3FFF) | ((nos_feedback & 1) << 14); - if (nos_length_counter > 0 && (nos_shift_reg & 1) == 0) - { - if (audio_nos_outputable) - { - nos_output = nos_envelope; - } - } - else - { - nos_output = 0; - } - audio_signal_outputed = true; - } - - private static void NOSClockLength() - { - if (nos_length_counter > 0 && !nos_length_halt) - { - nos_length_counter--; - if (apu_reg_access_happened && apu_reg_io_addr == 15 && apu_reg_access_w) - { - nos_ignore_reload = true; - } - } - } - - private static void NOSClockEnvelope() - { - if (nos_envelope_start_flag) - { - nos_envelope_start_flag = false; - nos_envelope_decay_level_counter = 15; - nos_envelope_devider = (byte)(nos_volume_devider_period + 1); - } - else if (nos_envelope_devider > 0) - { - nos_envelope_devider--; - } - else - { - nos_envelope_devider = (byte)(nos_volume_devider_period + 1); - if (nos_envelope_decay_level_counter > 0) - { - nos_envelope_decay_level_counter--; - } - else if (nos_length_halt) - { - nos_envelope_decay_level_counter = 15; - } - } - nos_envelope = (nos_constant_volume_envelope ? nos_volume_devider_period : nos_envelope_decay_level_counter); - } - - private static void APUOnRegister400C() - { - if (apu_reg_access_w) - { - nos_volume_devider_period = (byte)(apu_reg_io_db & 0xFu); - nos_length_halt = (apu_reg_io_db & 0x20) != 0; - nos_constant_volume_envelope = (apu_reg_io_db & 0x10) != 0; - nos_envelope = (nos_constant_volume_envelope ? nos_volume_devider_period : nos_envelope_decay_level_counter); - } - } - - private static void APUOnRegister400D() - { - } - - private static void APUOnRegister400E() - { - if (apu_reg_access_w) - { - nos_timer = (ushort)(nos_freq_table[SystemIndex][apu_reg_io_db & 0xF] / 2); - nos_mode = (apu_reg_io_db & 0x80) == 128; - } - } - - private static void APUOnRegister400F() - { - if (apu_reg_access_w) - { - if (nos_length_enabled && !nos_ignore_reload) - { - nos_length_counter = sq_duration_table[apu_reg_io_db >> 3]; - } - if (nos_ignore_reload) - { - nos_ignore_reload = false; - } - nos_envelope_start_flag = true; - } - } - - private static void NOSOn4015() - { - nos_length_enabled = (apu_reg_io_db & 8) != 0; - if (!nos_length_enabled) - { - nos_length_counter = 0; - } - } - - private static void NOSRead4015() - { - if (nos_length_counter > 0) - { - apu_reg_io_db = (byte)((apu_reg_io_db & 0xF7u) | 8u); - } - } - - private static void NOSWriteState(ref BinaryWriter bin) - { - bin.Write(nos_length_halt); - bin.Write(nos_constant_volume_envelope); - bin.Write(nos_volume_devider_period); - bin.Write(nos_timer); - bin.Write(nos_mode); - bin.Write(nos_period_devider); - bin.Write(nos_length_enabled); - bin.Write(nos_length_counter); - bin.Write(nos_envelope_start_flag); - bin.Write(nos_envelope_devider); - bin.Write(nos_envelope_decay_level_counter); - bin.Write(nos_envelope); - bin.Write(nos_output); - bin.Write(nos_shift_reg); - bin.Write(nos_feedback); - bin.Write(nos_ignore_reload); - } - - private static void NOSReadState(ref BinaryReader bin) - { - nos_length_halt = bin.ReadBoolean(); - nos_constant_volume_envelope = bin.ReadBoolean(); - nos_volume_devider_period = bin.ReadByte(); - nos_timer = bin.ReadUInt16(); - nos_mode = bin.ReadBoolean(); - nos_period_devider = bin.ReadInt32(); - nos_length_enabled = bin.ReadBoolean(); - nos_length_counter = bin.ReadInt32(); - nos_envelope_start_flag = bin.ReadBoolean(); - nos_envelope_devider = bin.ReadByte(); - nos_envelope_decay_level_counter = bin.ReadByte(); - nos_envelope = bin.ReadByte(); - nos_output = bin.ReadInt32(); - nos_shift_reg = bin.ReadInt32(); - nos_feedback = bin.ReadInt32(); - nos_ignore_reload = bin.ReadBoolean(); - } - - private static void SQ1HardReset() - { - sq1_duty_cycle = 0; - sq1_length_halt = false; - sq1_constant_volume_envelope = false; - sq1_volume_devider_period = 0; - sq1_sweep_enable = false; - sq1_sweep_devider_period = 0; - sq1_sweep_negate = false; - sq1_sweep_shift_count = 0; - sq1_timer = 0; - sq1_period_devider = 0; - sq1_seqencer = 0; - sq1_length_enabled = false; - sq1_length_counter = 0; - sq1_envelope_start_flag = false; - sq1_envelope_devider = 0; - sq1_envelope_decay_level_counter = 0; - sq1_envelope = 0; - sq1_sweep_counter = 0; - sq1_sweep_reload = false; - sq1_sweep_change = 0; - sq1_valid_freq = false; - sq1_output = 0; - sq1_ignore_reload = false; - } - - private static void SQ1SoftReset() - { - SQ1HardReset(); - } - - private static void SQ1Clock() - { - sq1_period_devider--; - if (sq1_period_devider > 0) - { - return; - } - sq1_period_devider = sq1_timer + 1; - sq1_seqencer = (byte)((uint)(sq1_seqencer + 1) & 7u); - if (sq1_length_counter > 0 && sq1_valid_freq) - { - if (audio_sq1_outputable) - { - sq1_output = sq_duty_cycle_sequences[sq1_duty_cycle][sq1_seqencer] * sq1_envelope; - } - } - else - { - sq1_output = 0; - } - audio_signal_outputed = true; - } - - private static void SQ1ClockLength() - { - if (sq1_length_counter > 0 && !sq1_length_halt) - { - sq1_length_counter--; - if (apu_reg_access_happened && apu_reg_io_addr == 3 && apu_reg_access_w) - { - sq1_ignore_reload = true; - } - } - sq1_sweep_counter--; - if (sq1_sweep_counter == 0) - { - sq1_sweep_counter = sq1_sweep_devider_period + 1; - if (sq1_sweep_enable && sq1_sweep_shift_count > 0 && sq1_valid_freq) - { - sq1_sweep_change = sq1_timer >> (int)sq1_sweep_shift_count; - sq1_timer += (sq1_sweep_negate ? (~sq1_sweep_change) : sq1_sweep_change); - SQ1CalculateValidFreq(); - } - } - if (sq1_sweep_reload) - { - sq1_sweep_counter = sq1_sweep_devider_period + 1; - sq1_sweep_reload = false; - } - } - - private static void SQ1ClockEnvelope() - { - if (sq1_envelope_start_flag) - { - sq1_envelope_start_flag = false; - sq1_envelope_decay_level_counter = 15; - sq1_envelope_devider = (byte)(sq1_volume_devider_period + 1); - } - else if (sq1_envelope_devider > 0) - { - sq1_envelope_devider--; - } - else - { - sq1_envelope_devider = (byte)(sq1_volume_devider_period + 1); - if (sq1_envelope_decay_level_counter > 0) - { - sq1_envelope_decay_level_counter--; - } - else if (sq1_length_halt) - { - sq1_envelope_decay_level_counter = 15; - } - } - sq1_envelope = (sq1_constant_volume_envelope ? sq1_volume_devider_period : sq1_envelope_decay_level_counter); - } - - private static void APUOnRegister4000() - { - if (apu_reg_access_w) - { - sq1_duty_cycle = (byte)((apu_reg_io_db & 0xC0) >> 6); - sq1_volume_devider_period = (byte)(apu_reg_io_db & 0xFu); - sq1_length_halt = (apu_reg_io_db & 0x20) != 0; - sq1_constant_volume_envelope = (apu_reg_io_db & 0x10) != 0; - sq1_envelope = (sq1_constant_volume_envelope ? sq1_volume_devider_period : sq1_envelope_decay_level_counter); - } - } - - private static void APUOnRegister4001() - { - if (apu_reg_access_w) - { - sq1_sweep_enable = (apu_reg_io_db & 0x80) == 128; - sq1_sweep_devider_period = (byte)((uint)(apu_reg_io_db >> 4) & 7u); - sq1_sweep_negate = (apu_reg_io_db & 8) == 8; - sq1_sweep_shift_count = (byte)(apu_reg_io_db & 7u); - sq1_sweep_reload = true; - SQ1CalculateValidFreq(); - } - } - - private static void APUOnRegister4002() - { - if (apu_reg_access_w) - { - sq1_timer = (sq1_timer & 0xFF00) | apu_reg_io_db; - SQ1CalculateValidFreq(); - } - } - - private static void APUOnRegister4003() - { - if (apu_reg_access_w) - { - sq1_timer = (sq1_timer & 0xFF) | ((apu_reg_io_db & 7) << 8); - if (sq1_length_enabled && !sq1_ignore_reload) - { - sq1_length_counter = sq_duration_table[apu_reg_io_db >> 3]; - } - if (sq1_ignore_reload) - { - sq1_ignore_reload = false; - } - sq1_seqencer = 0; - sq1_envelope_start_flag = true; - SQ1CalculateValidFreq(); - } - } - - private static void SQ1On4015() - { - sq1_length_enabled = (apu_reg_io_db & 1) != 0; - if (!sq1_length_enabled) - { - sq1_length_counter = 0; - } - } - - private static void SQ1Read4015() - { - if (sq1_length_counter > 0) - { - apu_reg_io_db = (byte)((apu_reg_io_db & 0xFEu) | 1u); - } - } - - private static void SQ1CalculateValidFreq() - { - sq1_valid_freq = sq1_timer >= 8 && (sq1_sweep_negate || ((sq1_timer + (sq1_timer >> (int)sq1_sweep_shift_count)) & 0x800) == 0); - } - - private static void SQ1WriteState(ref BinaryWriter bin) - { - bin.Write(sq1_duty_cycle); - bin.Write(sq1_length_halt); - bin.Write(sq1_constant_volume_envelope); - bin.Write(sq1_volume_devider_period); - bin.Write(sq1_sweep_enable); - bin.Write(sq1_sweep_devider_period); - bin.Write(sq1_sweep_negate); - bin.Write(sq1_sweep_shift_count); - bin.Write(sq1_timer); - bin.Write(sq1_period_devider); - bin.Write(sq1_seqencer); - bin.Write(sq1_length_enabled); - bin.Write(sq1_length_counter); - bin.Write(sq1_envelope_start_flag); - bin.Write(sq1_envelope_devider); - bin.Write(sq1_envelope_decay_level_counter); - bin.Write(sq1_envelope); - bin.Write(sq1_sweep_counter); - bin.Write(sq1_sweep_reload); - bin.Write(sq1_sweep_change); - bin.Write(sq1_valid_freq); - bin.Write(sq1_output); - bin.Write(sq1_ignore_reload); - } - - private static void SQ1ReadState(ref BinaryReader bin) - { - sq1_duty_cycle = bin.ReadByte(); - sq1_length_halt = bin.ReadBoolean(); - sq1_constant_volume_envelope = bin.ReadBoolean(); - sq1_volume_devider_period = bin.ReadByte(); - sq1_sweep_enable = bin.ReadBoolean(); - sq1_sweep_devider_period = bin.ReadByte(); - sq1_sweep_negate = bin.ReadBoolean(); - sq1_sweep_shift_count = bin.ReadByte(); - sq1_timer = bin.ReadInt32(); - sq1_period_devider = bin.ReadInt32(); - sq1_seqencer = bin.ReadByte(); - sq1_length_enabled = bin.ReadBoolean(); - sq1_length_counter = bin.ReadInt32(); - sq1_envelope_start_flag = bin.ReadBoolean(); - sq1_envelope_devider = bin.ReadByte(); - sq1_envelope_decay_level_counter = bin.ReadByte(); - sq1_envelope = bin.ReadByte(); - sq1_sweep_counter = bin.ReadInt32(); - sq1_sweep_reload = bin.ReadBoolean(); - sq1_sweep_change = bin.ReadInt32(); - sq1_valid_freq = bin.ReadBoolean(); - sq1_output = bin.ReadInt32(); - sq1_ignore_reload = bin.ReadBoolean(); - } - - private static void TRLHardReset() - { - trl_liner_control_flag = false; - trl_liner_control_reload = 0; - trl_timer = 0; - trl_length_enabled = false; - trl_length_counter = 0; - trl_liner_control_reload_flag = false; - trl_liner_counter = 0; - trl_output = 0; - trl_period_devider = 0; - trl_step = 0; - trl_ignore_reload = false; - } - - private static void TRLSoftReset() - { - TRLHardReset(); - } - - private static void TRLClock() - { - trl_period_devider--; - if (trl_period_devider > 0) - { - return; - } - trl_period_devider = trl_timer + 1; - if (trl_length_counter > 0 && trl_liner_counter > 0 && trl_timer >= 4) - { - trl_step++; - trl_step &= 31; - if (audio_trl_outputable) - { - trl_output = trl_step_seq[trl_step]; - } - } - audio_signal_outputed = true; - } - - private static void TRLClockLength() - { - if (trl_length_counter > 0 && !trl_liner_control_flag) - { - trl_length_counter--; - if (apu_reg_access_happened && apu_reg_io_addr == 11 && apu_reg_access_w) - { - trl_ignore_reload = true; - } - } - } - - private static void TRLClockEnvelope() - { - if (trl_liner_control_reload_flag) - { - trl_liner_counter = trl_liner_control_reload; - } - else if (trl_liner_counter > 0) - { - trl_liner_counter--; - } - if (!trl_liner_control_flag) - { - trl_liner_control_reload_flag = false; - } - } - - private static void APUOnRegister4008() - { - if (apu_reg_access_w) - { - trl_liner_control_flag = (apu_reg_io_db & 0x80) == 128; - trl_liner_control_reload = (byte)(apu_reg_io_db & 0x7Fu); - } - } - - private static void APUOnRegister4009() - { - } - - private static void APUOnRegister400A() - { - if (apu_reg_access_w) - { - trl_timer = (ushort)((trl_timer & 0x7F00u) | apu_reg_io_db); - } - } - - private static void APUOnRegister400B() - { - if (apu_reg_access_w) - { - trl_timer = (ushort)((trl_timer & 0xFFu) | (uint)((apu_reg_io_db & 7) << 8)); - if (trl_length_enabled && !trl_ignore_reload) - { - trl_length_counter = sq_duration_table[apu_reg_io_db >> 3]; - } - if (trl_ignore_reload) - { - trl_ignore_reload = false; - } - trl_liner_control_reload_flag = true; - } - } - - private static void TRLOn4015() - { - trl_length_enabled = (apu_reg_io_db & 4) != 0; - if (!trl_length_enabled) - { - trl_length_counter = 0; - } - } - - private static void TRLRead4015() - { - if (trl_length_counter > 0) - { - apu_reg_io_db = (byte)((apu_reg_io_db & 0xFBu) | 4u); - } - } - - private static void TRLWriteState(ref BinaryWriter bin) - { - bin.Write(trl_liner_control_flag); - bin.Write(trl_liner_control_reload); - bin.Write(trl_timer); - bin.Write(trl_length_enabled); - bin.Write(trl_length_counter); - bin.Write(trl_liner_control_reload_flag); - bin.Write(trl_liner_counter); - bin.Write(trl_output); - bin.Write(trl_period_devider); - bin.Write(trl_step); - bin.Write(trl_ignore_reload); - } - - private static void TRLReadState(ref BinaryReader bin) - { - trl_liner_control_flag = bin.ReadBoolean(); - trl_liner_control_reload = bin.ReadByte(); - trl_timer = bin.ReadUInt16(); - trl_length_enabled = bin.ReadBoolean(); - trl_length_counter = bin.ReadByte(); - trl_liner_control_reload_flag = bin.ReadBoolean(); - trl_liner_counter = bin.ReadByte(); - trl_output = bin.ReadInt32(); - trl_period_devider = bin.ReadInt32(); - trl_step = bin.ReadInt32(); - trl_ignore_reload = bin.ReadBoolean(); - } - - private static void APUInitialize() - { - apu_reg_update_func = new Action[32]; - apu_reg_read_func = new Action[32]; - apu_reg_write_func = new Action[32]; - for (int i = 0; i < 32; i++) - { - apu_reg_update_func[i] = APUBlankAccess; - apu_reg_read_func[i] = APUBlankAccess; - apu_reg_write_func[i] = APUBlankAccess; - } - apu_reg_update_func[0] = APUOnRegister4000; - apu_reg_update_func[1] = APUOnRegister4001; - apu_reg_update_func[2] = APUOnRegister4002; - apu_reg_update_func[3] = APUOnRegister4003; - apu_reg_update_func[4] = APUOnRegister4004; - apu_reg_update_func[5] = APUOnRegister4005; - apu_reg_update_func[6] = APUOnRegister4006; - apu_reg_update_func[7] = APUOnRegister4007; - apu_reg_update_func[8] = APUOnRegister4008; - apu_reg_update_func[9] = APUOnRegister4009; - apu_reg_update_func[10] = APUOnRegister400A; - apu_reg_update_func[11] = APUOnRegister400B; - apu_reg_update_func[12] = APUOnRegister400C; - apu_reg_update_func[13] = APUOnRegister400D; - apu_reg_update_func[14] = APUOnRegister400E; - apu_reg_update_func[15] = APUOnRegister400F; - apu_reg_update_func[16] = APUOnRegister4010; - apu_reg_update_func[17] = APUOnRegister4011; - apu_reg_update_func[18] = APUOnRegister4012; - apu_reg_update_func[19] = APUOnRegister4013; - apu_reg_update_func[21] = APUOnRegister4015; - apu_reg_update_func[22] = APUOnRegister4016; - apu_reg_update_func[23] = APUOnRegister4017; - apu_reg_read_func[21] = APURead4015; - apu_reg_read_func[22] = APURead4016; - apu_reg_read_func[23] = APURead4017; - apu_reg_write_func[20] = APUWrite4014; - apu_reg_write_func[21] = APUWrite4015; - audio_low_pass_filter_14K = new SoundLowPassFilter(0.00815686); - audio_high_pass_filter_90 = new SoundHighPassFilter(0.999835); - audio_high_pass_filter_440 = new SoundHighPassFilter(0.996039); - audio_dc_blocker_filter = new SoundDCBlockerFilter(0.995); - apu_update_playback_func = APUUpdatePlaybackWithFilters; - } - - public static void ApplyAudioSettings(bool all = true) - { - SoundEnabled = MyNesMain.RendererSettings.Audio_SoundEnabled; - audio_sq1_outputable = MyNesMain.RendererSettings.Audio_ChannelEnabled_SQ1; - audio_sq2_outputable = MyNesMain.RendererSettings.Audio_ChannelEnabled_SQ2; - audio_nos_outputable = MyNesMain.RendererSettings.Audio_ChannelEnabled_NOZ; - audio_trl_outputable = MyNesMain.RendererSettings.Audio_ChannelEnabled_TRL; - audio_dmc_outputable = MyNesMain.RendererSettings.Audio_ChannelEnabled_DMC; - if (apu_use_external_sound) - { - mem_board.APUApplyChannelsSettings(); - } - if (all) - { - CalculateAudioPlaybackValues(); - } - } - - private static void APUHardReset() - { - apu_reg_io_db = 0; - apu_reg_io_addr = 0; - apu_reg_access_happened = false; - apu_reg_access_w = false; - apu_seq_mode = false; - apu_odd_cycle = true; - apu_cycle_f_t = 0; - apu_cycle_e = 4; - apu_cycle_f = 4; - apu_cycle_l = 4; - apu_odd_l = false; - apu_check_irq = false; - apu_do_env = false; - apu_do_length = false; - switch (Region) - { - case EmuRegion.NTSC: - cpu_speed = 1789773; - apu_ferq_f = 14914; - apu_ferq_e = 3728; - apu_ferq_l = 7456; - break; - case EmuRegion.PALB: - cpu_speed = 1662607; - apu_ferq_f = 14914; - apu_ferq_e = 3728; - apu_ferq_l = 7456; - break; - case EmuRegion.DENDY: - cpu_speed = 1773448; - apu_ferq_f = 14914; - apu_ferq_e = 3728; - apu_ferq_l = 7456; - break; - } - Tracer.WriteLine("NES: cpu speed = " + cpu_speed); - SQ1HardReset(); - SQ2HardReset(); - NOSHardReset(); - DMCHardReset(); - TRLHardReset(); - apu_irq_enabled = true; - apu_irq_flag = false; - reg_2004 = 8196; - CalculateAudioPlaybackValues(); - apu_use_external_sound = mem_board.enable_external_sound; - if (apu_use_external_sound) - { - Tracer.WriteInformation("External sound channels has been enabled on apu."); - } - } - - private static void APUSoftReset() - { - apu_reg_io_db = 0; - apu_reg_io_addr = 0; - apu_reg_access_happened = false; - apu_reg_access_w = false; - apu_seq_mode = false; - apu_odd_cycle = false; - apu_cycle_f_t = 0; - apu_cycle_e = 4; - apu_cycle_f = 4; - apu_cycle_l = 4; - apu_odd_l = false; - apu_check_irq = false; - apu_do_env = false; - apu_do_length = false; - apu_irq_enabled = true; - apu_irq_flag = false; - SQ1SoftReset(); - SQ2SoftReset(); - TRLSoftReset(); - NOSSoftReset(); - DMCSoftReset(); - } - - private static void APUIORead(ref ushort addr, out byte value) - { - if (addr >= 16416) - { - mem_board.ReadEX(ref addr, out value); - return; - } - apu_reg_io_addr = (byte)(addr & 0x1Fu); - apu_reg_access_happened = true; - apu_reg_access_w = false; - apu_reg_read_func[apu_reg_io_addr](); - value = apu_reg_io_db; - } - - private static void APUIOWrite(ref ushort addr, ref byte value) - { - if (addr >= 16416) - { - mem_board.WriteEX(ref addr, ref value); - return; - } - apu_reg_io_addr = (byte)(addr & 0x1Fu); - apu_reg_io_db = value; - apu_reg_access_w = true; - apu_reg_access_happened = true; - apu_reg_write_func[apu_reg_io_addr](); - } - - private static void APUBlankAccess() - { - } - - private static void APUWrite4014() - { - dma_Oamaddress = (ushort)(apu_reg_io_db << 8); - AssertOAMDMA(); - } - - private static void APUWrite4015() - { - if ((apu_reg_io_db & 0x10u) != 0) - { - if (dmc_dmaSize == 0) - { - dmc_dmaSize = dmc_size_refresh; - dmc_dmaAddr = dmc_addr_refresh; - } - } - else - { - dmc_dmaSize = 0; - } - if (!dmc_bufferFull && dmc_dmaSize > 0) - { - AssertDMCDMA(); - } - } - - private static void APUOnRegister4015() - { - if (apu_reg_access_w) - { - SQ1On4015(); - SQ2On4015(); - NOSOn4015(); - TRLOn4015(); - DMCOn4015(); - } - else - { - apu_irq_flag = false; - IRQFlags &= -2; - } - } - - private static void APUOnRegister4016() - { - if (!apu_reg_access_w) - { - return; - } - if (inputStrobe > (apu_reg_io_db & 1)) - { - if (IsFourPlayers) - { - PORT0 = (joypad3.GetData() << 8) | joypad1.GetData() | 0x1010000; - PORT1 = (joypad4.GetData() << 8) | joypad2.GetData() | 0x2020000; - } - else - { - PORT0 = joypad1.GetData() | 0x1010100; - PORT1 = joypad2.GetData() | 0x2020200; - } - } - inputStrobe = apu_reg_io_db & 1; - } - - private static void APUOnRegister4017() - { - if (apu_reg_access_w) - { - apu_seq_mode = (apu_reg_io_db & 0x80) != 0; - apu_irq_enabled = (apu_reg_io_db & 0x40) == 0; - apu_cycle_e = -1; - apu_cycle_l = -1; - apu_cycle_f = -1; - apu_odd_l = false; - apu_do_length = apu_seq_mode; - apu_do_env = apu_seq_mode; - apu_check_irq = false; - if (!apu_irq_enabled) - { - apu_irq_flag = false; - IRQFlags &= -2; - } - } - } - - private static void APURead4015() - { - apu_reg_io_db &= 32; - SQ1Read4015(); - SQ2Read4015(); - NOSRead4015(); - TRLRead4015(); - DMCRead4015(); - if (apu_irq_flag) - { - apu_reg_io_db = (byte)((apu_reg_io_db & 0xBFu) | 0x40u); - } - if (apu_irq_delta_occur) - { - apu_reg_io_db = (byte)((apu_reg_io_db & 0x7Fu) | 0x80u); - } - } - - private static void APURead4016() - { - apu_reg_io_db = (byte)((uint)PORT0 & 1u); - PORT0 >>= 1; - } - - private static void APURead4017() - { - apu_reg_io_db = (byte)((uint)PORT1 & 1u); - PORT1 >>= 1; - } - - private static void APUClock() - { - apu_odd_cycle = !apu_odd_cycle; - if (apu_do_env) - { - APUClockEnvelope(); - } - if (apu_do_length) - { - APUClockDuration(); - } - if (apu_odd_cycle) - { - apu_cycle_f++; - if (apu_cycle_f >= apu_ferq_f) - { - apu_cycle_f = -1; - apu_check_irq = true; - apu_cycle_f_t = 3; - } - apu_cycle_e++; - if (apu_cycle_e >= apu_ferq_e) - { - apu_cycle_e = -1; - if (apu_check_irq) - { - if (!apu_seq_mode) - { - apu_do_env = true; - } - else - { - apu_cycle_e = 4; - } - } - else - { - apu_do_env = true; - } - } - apu_cycle_l++; - if (apu_cycle_l >= apu_ferq_l) - { - apu_odd_l = !apu_odd_l; - apu_cycle_l = (apu_odd_l ? (-2) : (-1)); - if (apu_check_irq && apu_seq_mode) - { - apu_cycle_l = 3730; - apu_odd_l = true; - } - else - { - apu_do_length = true; - } - } - SQ1Clock(); - SQ2Clock(); - NOSClock(); - if (apu_use_external_sound) - { - mem_board.OnAPUClock(); - } - if (apu_reg_access_happened) - { - apu_reg_access_happened = false; - apu_reg_update_func[apu_reg_io_addr](); - } - } - TRLClock(); - DMCClock(); - if (apu_check_irq) - { - if (!apu_seq_mode) - { - APUCheckIRQ(); - } - apu_cycle_f_t--; - if (apu_cycle_f_t == 0) - { - apu_check_irq = false; - } - } - if (apu_use_external_sound) - { - mem_board.OnAPUClockSingle(); - } - apu_update_playback_func(); - } - - private static void APUClockDuration() - { - SQ1ClockLength(); - SQ2ClockLength(); - NOSClockLength(); - TRLClockLength(); - if (apu_use_external_sound) - { - mem_board.OnAPUClockDuration(); - } - apu_do_length = false; - } - - private static void APUClockEnvelope() - { - SQ1ClockEnvelope(); - SQ2ClockEnvelope(); - NOSClockEnvelope(); - TRLClockEnvelope(); - if (apu_use_external_sound) - { - mem_board.OnAPUClockEnvelope(); - } - apu_do_env = false; - } - - private static void APUCheckIRQ() - { - if (apu_irq_enabled) - { - apu_irq_flag = true; - } - if (apu_irq_flag) - { - IRQFlags |= 1; - } - } - - private static void CalculateAudioPlaybackValues() - { - audio_timer_ratio = (double)cpu_speed / (double)MyNesMain.RendererSettings.Audio_Frequency; - audio_playback_peek_limit = MyNesMain.RendererSettings.Audio_InternalPeekLimit; - audio_samples_count = MyNesMain.RendererSettings.Audio_InternalSamplesCount; - audio_playback_amplitude = MyNesMain.RendererSettings.Audio_PlaybackAmplitude; - audio_samples = new short[audio_samples_count]; - audio_w_pos = 0; - audio_samples_added = 0; - audio_timer = 0.0; - audio_x = (audio_y = 0.0); - Tracer.WriteLine("AUDIO: frequency = " + MyNesMain.RendererSettings.Audio_Frequency); - Tracer.WriteLine("AUDIO: timer ratio = " + audio_timer_ratio); - Tracer.WriteLine("AUDIO: internal samples count = " + audio_samples_count); - Tracer.WriteLine("AUDIO: amplitude = " + audio_playback_amplitude); - if (MyNesMain.RendererSettings.Audio_EnableFilters) - { - apu_update_playback_func = APUUpdatePlaybackWithFilters; - audio_low_pass_filter_14K = new SoundLowPassFilter(SoundLowPassFilter.GetK((double)cpu_speed / 14000.0, 14000.0)); - audio_high_pass_filter_90 = new SoundHighPassFilter(SoundHighPassFilter.GetK((double)cpu_speed / 90.0, 90.0)); - audio_high_pass_filter_440 = new SoundHighPassFilter(SoundHighPassFilter.GetK((double)cpu_speed / 440.0, 440.0)); - } - else - { - apu_update_playback_func = APUUpdatePlaybackWithoutFilters; - } - InitializeDACTables(force_intitialize: false); - } - - public static void InitializeDACTables(bool force_intitialize) - { - if (audio_playback_dac_initialized && !force_intitialize) - { - return; - } - int[] array = new int[5]; - mix_table = new int[16][][][][]; - for (int i = 0; i < 16; i++) - { - mix_table[i] = new int[16][][][]; - for (int j = 0; j < 16; j++) - { - mix_table[i][j] = new int[16][][]; - for (int k = 0; k < 16; k++) - { - mix_table[i][j][k] = new int[16][]; - for (int l = 0; l < 16; l++) - { - mix_table[i][j][k][l] = new int[128]; - for (int m = 0; m < 128; m++) - { - if (MyNesMain.RendererSettings.Audio_UseDefaultMixer) - { - double num = 95.88 / (8128.0 / (double)(i + j) + 100.0); - double num2 = 159.79 / (1.0 / ((double)k / 8227.0 + (double)l / 12241.0 + (double)m / 22638.0) + 100.0); - mix_table[i][j][k][l][m] = (int)Math.Ceiling((num + num2) * audio_playback_amplitude); - continue; - } - GetPrec(i, 255, 2048, out array[0]); - GetPrec(j, 255, 2048, out array[1]); - GetPrec(l, 255, 2048, out array[2]); - GetPrec(k, 255, 2048, out array[3]); - GetPrec(m, 255, 2048, out array[4]); - array[4] /= 2; - int num3 = array[0] + array[1] + array[2] + array[3] + array[4]; - num3 /= 5; - mix_table[i][j][k][l][m] = num3; - } - } - } - } - } - audio_playback_dac_initialized = true; - } - - private static void APUUpdatePlaybackWithFilters() - { - if (!SoundEnabled) - { - return; - } - audio_x = mix_table[sq1_output][sq2_output][trl_output][nos_output][dmc_output]; - if (apu_use_external_sound) - { - audio_x = (audio_x + mem_board.APUGetSample() * audio_playback_amplitude) / 2.0; - } - audio_high_pass_filter_90.DoFiltering(audio_x, out audio_y); - audio_high_pass_filter_440.DoFiltering(audio_y, out audio_y); - audio_low_pass_filter_14K.DoFiltering(audio_y, out audio_y); - audio_y_av += audio_y; - audio_y_timer += 1.0; - audio_timer += 1.0; - if (!(audio_timer >= audio_timer_ratio)) - { - return; - } - if (audio_y_timer > 0.0) - { - audio_y = audio_y_av / audio_y_timer; - } - else - { - audio_y = 0.0; - } - audio_y_av = 0.0; - audio_y_timer = 0.0; - audio_timer -= audio_timer_ratio; - if (audio_w_pos < audio_samples_count) - { - if (audio_y > (double)audio_playback_peek_limit) - { - audio_y = audio_playback_peek_limit; - } - if (audio_y < (double)(-audio_playback_peek_limit)) - { - audio_y = -audio_playback_peek_limit; - } - audio_samples[audio_w_pos] = (short)audio_y; - if (MyNesMain.WaveRecorder.IsRecording) - { - MyNesMain.WaveRecorder.AddSample((short)audio_y); - } - audio_w_pos++; - audio_samples_added++; - } - audio_y = 0.0; - } - - private static void APUUpdatePlaybackWithoutFilters() - { - if (!SoundEnabled) - { - return; - } - audio_y = mix_table[sq1_output][sq2_output][trl_output][nos_output][dmc_output] / 2; - if (apu_use_external_sound) - { - audio_y = (audio_y + mem_board.APUGetSample() * audio_playback_amplitude) / 2.0; - } - audio_y_av += audio_y; - audio_y_timer += 1.0; - audio_timer += 1.0; - if (!(audio_timer >= audio_timer_ratio)) - { - return; - } - if (audio_y_timer > 0.0) - { - audio_y = audio_y_av / audio_y_timer; - } - else - { - audio_y = 0.0; - } - audio_y_av = 0.0; - audio_y_timer = 0.0; - audio_timer -= audio_timer_ratio; - if (audio_w_pos < audio_samples_count) - { - if (audio_y > (double)audio_playback_peek_limit) - { - audio_y = audio_playback_peek_limit; - } - if (audio_y < (double)(-audio_playback_peek_limit)) - { - audio_y = -audio_playback_peek_limit; - } - audio_samples[audio_w_pos] = (short)audio_y; - if (MyNesMain.WaveRecorder.IsRecording) - { - MyNesMain.WaveRecorder.AddSample((short)audio_y); - } - audio_w_pos++; - audio_samples_added++; - } - audio_y = 0.0; - } - - private static void GetPrec(int inVal, int inMax, int outMax, out int val) - { - val = outMax * inVal / inMax; - } - - private static void APUWriteState(ref BinaryWriter bin) - { - bin.Write(apu_reg_io_db); - bin.Write(apu_reg_io_addr); - bin.Write(apu_reg_access_happened); - bin.Write(apu_reg_access_w); - bin.Write(apu_odd_cycle); - bin.Write(apu_irq_enabled); - bin.Write(apu_irq_flag); - bin.Write(apu_irq_delta_occur); - bin.Write(apu_seq_mode); - bin.Write(apu_ferq_f); - bin.Write(apu_ferq_l); - bin.Write(apu_ferq_e); - bin.Write(apu_cycle_f); - bin.Write(apu_cycle_e); - bin.Write(apu_cycle_l); - bin.Write(apu_odd_l); - bin.Write(apu_cycle_f_t); - bin.Write(apu_check_irq); - bin.Write(apu_do_env); - bin.Write(apu_do_length); - SQ1WriteState(ref bin); - SQ2WriteState(ref bin); - NOSWriteState(ref bin); - TRLWriteState(ref bin); - DMCWriteState(ref bin); - } - - private static void APUReadState(ref BinaryReader bin) - { - apu_reg_io_db = bin.ReadByte(); - apu_reg_io_addr = bin.ReadByte(); - apu_reg_access_happened = bin.ReadBoolean(); - apu_reg_access_w = bin.ReadBoolean(); - apu_odd_cycle = bin.ReadBoolean(); - apu_irq_enabled = bin.ReadBoolean(); - apu_irq_flag = bin.ReadBoolean(); - apu_irq_delta_occur = bin.ReadBoolean(); - apu_seq_mode = bin.ReadBoolean(); - apu_ferq_f = bin.ReadInt32(); - apu_ferq_l = bin.ReadInt32(); - apu_ferq_e = bin.ReadInt32(); - apu_cycle_f = bin.ReadInt32(); - apu_cycle_e = bin.ReadInt32(); - apu_cycle_l = bin.ReadInt32(); - apu_odd_l = bin.ReadBoolean(); - apu_cycle_f_t = bin.ReadInt32(); - apu_check_irq = bin.ReadBoolean(); - apu_do_env = bin.ReadBoolean(); - apu_do_length = bin.ReadBoolean(); - SQ1ReadState(ref bin); - SQ2ReadState(ref bin); - NOSReadState(ref bin); - TRLReadState(ref bin); - DMCReadState(ref bin); - } - - private static byte register_pb() - { - return (byte)((cpu_flag_n ? 128u : 0u) | (cpu_flag_v ? 64u : 0u) | (cpu_flag_d ? 8u : 0u) | (cpu_flag_i ? 4u : 0u) | (cpu_flag_z ? 2u : 0u) | (cpu_flag_c ? 1u : 0u) | 0x30u); - } - - private static void CPUInitialize() - { - cpu_addressings = new Action[256] - { - Imp____, IndX_R_, ImA____, IndX_W_, Zpg_R__, Zpg_R__, Zpg_RW_, Zpg_W__, ImA____, Imm____, - ImA____, Imm____, Abs_R__, Abs_R__, Abs_RW_, Abs_W__, Imp____, IndY_R_, Imp____, IndY_W_, - ZpgX_R_, ZpgX_R_, ZpgX_RW, ZpgX_W_, ImA____, AbsY_R_, ImA____, AbsY_W_, AbsX_R_, AbsX_R_, - AbsX_RW, AbsX_W_, Imp____, IndX_R_, ImA____, IndX_W_, Zpg_R__, Zpg_R__, Zpg_RW_, Zpg_W__, - ImA____, Imm____, ImA____, Imm____, Abs_R__, Abs_R__, Abs_RW_, Abs_W__, Imp____, IndY_R_, - Imp____, IndY_W_, ZpgX_R_, ZpgX_R_, ZpgX_RW, ZpgX_W_, ImA____, AbsY_R_, ImA____, AbsY_W_, - AbsX_R_, AbsX_R_, AbsX_RW, AbsX_W_, ImA____, IndX_R_, ImA____, IndX_W_, Zpg_R__, Zpg_R__, - Zpg_RW_, Zpg_W__, ImA____, Imm____, ImA____, Imm____, Abs_W__, Abs_R__, Abs_RW_, Abs_W__, - Imp____, IndY_R_, Imp____, IndY_W_, ZpgX_R_, ZpgX_R_, ZpgX_RW, ZpgX_W_, ImA____, AbsY_R_, - ImA____, AbsY_W_, AbsX_R_, AbsX_R_, AbsX_RW, AbsX_W_, ImA____, IndX_R_, ImA____, IndX_W_, - Zpg_R__, Zpg_R__, Zpg_RW_, Zpg_W__, ImA____, Imm____, ImA____, Imm____, Imp____, Abs_R__, - Abs_RW_, Abs_W__, Imp____, IndY_R_, Imp____, IndY_W_, ZpgX_R_, ZpgX_R_, ZpgX_RW, ZpgX_W_, - ImA____, AbsY_R_, ImA____, AbsY_W_, AbsX_R_, AbsX_R_, AbsX_RW, AbsX_W_, Imm____, IndX_W_, - Imm____, IndX_W_, Zpg_W__, Zpg_W__, Zpg_W__, Zpg_W__, ImA____, Imm____, ImA____, Imm____, - Abs_W__, Abs_W__, Abs_W__, Abs_W__, Imp____, IndY_W_, Imp____, IndY_W_, ZpgX_W_, ZpgX_W_, - ZpgY_W_, ZpgY_W_, ImA____, AbsY_W_, ImA____, AbsY_W_, Abs_W__, AbsX_W_, Abs_W__, AbsY_W_, - Imm____, IndX_R_, Imm____, IndX_R_, Zpg_R__, Zpg_R__, Zpg_R__, Zpg_R__, ImA____, Imm____, - ImA____, Imm____, Abs_R__, Abs_R__, Abs_R__, Abs_R__, Imp____, IndY_R_, Imp____, IndY_R_, - ZpgX_R_, ZpgX_R_, ZpgY_R_, ZpgY_R_, ImA____, AbsY_R_, ImA____, AbsY_R_, AbsX_R_, AbsX_R_, - AbsY_R_, AbsY_R_, Imm____, IndX_R_, Imm____, IndX_R_, Zpg_R__, Zpg_R__, Zpg_RW_, Zpg_R__, - ImA____, Imm____, ImA____, Imm____, Abs_R__, Abs_R__, Abs_RW_, Abs_R__, Imp____, IndY_R_, - Imp____, IndY_RW, ZpgX_R_, ZpgX_R_, ZpgX_RW, ZpgX_RW, ImA____, AbsY_R_, ImA____, AbsY_RW, - AbsX_R_, AbsX_R_, AbsX_RW, AbsX_RW, Imm____, IndX_R_, Imm____, IndX_W_, Zpg_R__, Zpg_R__, - Zpg_RW_, Zpg_W__, ImA____, Imm____, ImA____, Imm____, Abs_R__, Abs_R__, Abs_RW_, Abs_W__, - Imp____, IndY_R_, Imp____, IndY_W_, ZpgX_R_, ZpgX_R_, ZpgX_RW, ZpgX_W_, ImA____, AbsY_R_, - ImA____, AbsY_W_, AbsX_R_, AbsX_R_, AbsX_RW, AbsX_W_ - }; - cpu_instructions = new Action[256] - { - BRK__, ORA__, NOP__, SLO__, NOP__, ORA__, ASL_M, SLO__, PHP__, ORA__, - ASL_A, ANC__, NOP__, ORA__, ASL_M, SLO__, BPL__, ORA__, NOP__, SLO__, - NOP__, ORA__, ASL_M, SLO__, CLC__, ORA__, NOP__, SLO__, NOP__, ORA__, - ASL_M, SLO__, JSR__, AND__, NOP__, RLA__, BIT__, AND__, ROL_M, RLA__, - PLP__, AND__, ROL_A, ANC__, BIT__, AND__, ROL_M, RLA__, BMI__, AND__, - NOP__, RLA__, NOP__, AND__, ROL_M, RLA__, SEC__, AND__, NOP__, RLA__, - NOP__, AND__, ROL_M, RLA__, RTI__, EOR__, NOP__, SRE__, NOP__, EOR__, - LSR_M, SRE__, PHA__, EOR__, LSR_A, ALR__, JMP__, EOR__, LSR_M, SRE__, - BVC__, EOR__, NOP__, SRE__, NOP__, EOR__, LSR_M, SRE__, CLI__, EOR__, - NOP__, SRE__, NOP__, EOR__, LSR_M, SRE__, RTS__, ADC__, NOP__, RRA__, - NOP__, ADC__, ROR_M, RRA__, PLA__, ADC__, ROR_A, ARR__, JMP_I, ADC__, - ROR_M, RRA__, BVS__, ADC__, NOP__, RRA__, NOP__, ADC__, ROR_M, RRA__, - SEI__, ADC__, NOP__, RRA__, NOP__, ADC__, ROR_M, RRA__, NOP__, STA__, - NOP__, SAX__, STY__, STA__, STX__, SAX__, DEY__, NOP__, TXA__, XAA__, - STY__, STA__, STX__, SAX__, BCC__, STA__, NOP__, AHX__, STY__, STA__, - STX__, SAX__, TYA__, STA__, TXS__, XAS__, SHY__, STA__, SHX__, AHX__, - LDY__, LDA__, LDX__, LAX__, LDY__, LDA__, LDX__, LAX__, TAY__, LDA__, - TAX__, LAX__, LDY__, LDA__, LDX__, LAX__, BCS__, LDA__, NOP__, LAX__, - LDY__, LDA__, LDX__, LAX__, CLV__, LDA__, TSX__, LAR__, LDY__, LDA__, - LDX__, LAX__, CPY__, CMP__, NOP__, DCP__, CPY__, CMP__, DEC__, DCP__, - INY__, CMP__, DEX__, AXS__, CPY__, CMP__, DEC__, DCP__, BNE__, CMP__, - NOP__, DCP__, NOP__, CMP__, DEC__, DCP__, CLD__, CMP__, NOP__, DCP__, - NOP__, CMP__, DEC__, DCP__, CPX__, SBC__, NOP__, ISC__, CPX__, SBC__, - INC__, ISC__, INX__, SBC__, NOP__, SBC__, CPX__, SBC__, INC__, ISC__, - BEQ__, SBC__, NOP__, ISC__, NOP__, SBC__, INC__, ISC__, SED__, SBC__, - NOP__, ISC__, NOP__, SBC__, INC__, ISC__ - }; - } - - private static void CPUClock() - { - Read(ref cpu_reg_pc.v, out cpu_opcode); - cpu_reg_pc.v++; - cpu_addressings[cpu_opcode](); - cpu_instructions[cpu_opcode](); - if (CPU_IRQ_PIN || CPU_NMI_PIN) - { - Read(ref cpu_reg_pc.v, out cpu_dummy); - Read(ref cpu_reg_pc.v, out cpu_dummy); - Interrupt(); - } - } - - private static void CPUHardReset() - { - cpu_reg_a = 0; - cpu_reg_x = 0; - cpu_reg_y = 0; - cpu_reg_sp.l = 253; - cpu_reg_sp.h = 1; - ushort addr = 65532; - mem_board.ReadPRG(ref addr, out cpu_reg_pc.l); - addr++; - mem_board.ReadPRG(ref addr, out cpu_reg_pc.h); - register_p = 0; - cpu_flag_i = true; - cpu_reg_ea.v = 0; - cpu_opcode = 0; - CPU_IRQ_PIN = false; - CPU_NMI_PIN = false; - cpu_suspend_nmi = false; - cpu_suspend_irq = false; - IRQFlags = 0; - } - - private static void CPUSoftReset() - { - cpu_flag_i = true; - cpu_reg_sp.v -= 3; - ushort addr = 65532; - Read(ref addr, out cpu_reg_pc.l); - addr++; - Read(ref addr, out cpu_reg_pc.h); - } - - private static void Imp____() - { - } - - private static void IndX_R_() - { - temp_add.h = 0; - Read(ref cpu_reg_pc.v, out temp_add.l); - cpu_reg_pc.v++; - Read(ref temp_add.v, out cpu_dummy); - temp_add.l += cpu_reg_x; - Read(ref temp_add.v, out cpu_reg_ea.l); - temp_add.l++; - Read(ref temp_add.v, out cpu_reg_ea.h); - Read(ref cpu_reg_ea.v, out cpu_m); - } - - private static void IndX_W_() - { - temp_add.h = 0; - Read(ref cpu_reg_pc.v, out temp_add.l); - cpu_reg_pc.v++; - Read(ref temp_add.v, out cpu_dummy); - temp_add.l += cpu_reg_x; - Read(ref temp_add.v, out cpu_reg_ea.l); - temp_add.l++; - Read(ref temp_add.v, out cpu_reg_ea.h); - } - - private static void IndX_RW() - { - temp_add.h = 0; - Read(ref cpu_reg_pc.v, out temp_add.l); - cpu_reg_pc.v++; - Read(ref temp_add.v, out cpu_dummy); - temp_add.l += cpu_reg_x; - Read(ref temp_add.v, out cpu_reg_ea.l); - temp_add.l++; - Read(ref temp_add.v, out cpu_reg_ea.h); - Read(ref cpu_reg_ea.v, out cpu_m); - } - - private static void IndY_R_() - { - temp_add.h = 0; - Read(ref cpu_reg_pc.v, out temp_add.l); - cpu_reg_pc.v++; - Read(ref temp_add.v, out cpu_reg_ea.l); - temp_add.l++; - Read(ref temp_add.v, out cpu_reg_ea.h); - cpu_reg_ea.l += cpu_reg_y; - Read(ref cpu_reg_ea.v, out cpu_m); - if (cpu_reg_ea.l < cpu_reg_y) - { - cpu_reg_ea.h++; - Read(ref cpu_reg_ea.v, out cpu_m); - } - } - - private static void IndY_W_() - { - temp_add.h = 0; - Read(ref cpu_reg_pc.v, out temp_add.l); - cpu_reg_pc.v++; - Read(ref temp_add.v, out cpu_reg_ea.l); - temp_add.l++; - Read(ref temp_add.v, out cpu_reg_ea.h); - cpu_reg_ea.l += cpu_reg_y; - Read(ref cpu_reg_ea.v, out cpu_m); - if (cpu_reg_ea.l < cpu_reg_y) - { - cpu_reg_ea.h++; - } - } - - private static void IndY_RW() - { - temp_add.h = 0; - Read(ref cpu_reg_pc.v, out temp_add.l); - cpu_reg_pc.v++; - Read(ref temp_add.v, out cpu_reg_ea.l); - temp_add.l++; - Read(ref temp_add.v, out cpu_reg_ea.h); - cpu_reg_ea.l += cpu_reg_y; - Read(ref cpu_reg_ea.v, out cpu_dummy); - if (cpu_reg_ea.l < cpu_reg_y) - { - cpu_reg_ea.h++; - } - Read(ref cpu_reg_ea.v, out cpu_m); - } - - private static void Zpg_R__() - { - cpu_reg_ea.h = 0; - Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); - cpu_reg_pc.v++; - Read(ref cpu_reg_ea.v, out cpu_m); - } - - private static void Zpg_W__() - { - cpu_reg_ea.h = 0; - Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); - cpu_reg_pc.v++; - } - - private static void Zpg_RW_() - { - cpu_reg_ea.h = 0; - Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); - cpu_reg_pc.v++; - Read(ref cpu_reg_ea.v, out cpu_m); - } - - private static void ZpgX_R_() - { - cpu_reg_ea.h = 0; - Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); - cpu_reg_pc.v++; - Read(ref cpu_reg_ea.v, out cpu_dummy); - cpu_reg_ea.l += cpu_reg_x; - Read(ref cpu_reg_ea.v, out cpu_m); - } - - private static void ZpgX_W_() - { - cpu_reg_ea.h = 0; - Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); - cpu_reg_pc.v++; - Read(ref cpu_reg_ea.v, out cpu_dummy); - cpu_reg_ea.l += cpu_reg_x; - } - - private static void ZpgX_RW() - { - cpu_reg_ea.h = 0; - Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); - cpu_reg_pc.v++; - Read(ref cpu_reg_ea.v, out cpu_dummy); - cpu_reg_ea.l += cpu_reg_x; - Read(ref cpu_reg_ea.v, out cpu_m); - } - - private static void ZpgY_R_() - { - cpu_reg_ea.h = 0; - Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); - cpu_reg_pc.v++; - Read(ref cpu_reg_ea.v, out cpu_dummy); - cpu_reg_ea.l += cpu_reg_y; - Read(ref cpu_reg_ea.v, out cpu_m); - } - - private static void ZpgY_W_() - { - cpu_reg_ea.h = 0; - Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); - cpu_reg_pc.v++; - Read(ref cpu_reg_ea.v, out cpu_dummy); - cpu_reg_ea.l += cpu_reg_y; - } - - private static void ZpgY_RW() - { - cpu_reg_ea.h = 0; - Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); - cpu_reg_pc.v++; - Read(ref cpu_reg_ea.v, out cpu_dummy); - cpu_reg_ea.l += cpu_reg_y; - Read(ref cpu_reg_ea.v, out cpu_m); - } - - private static void Imm____() - { - Read(ref cpu_reg_pc.v, out cpu_m); - cpu_reg_pc.v++; - } - - private static void ImA____() - { - Read(ref cpu_reg_pc.v, out cpu_dummy); - } - - private static void Abs_R__() - { - Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); - cpu_reg_pc.v++; - Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); - cpu_reg_pc.v++; - Read(ref cpu_reg_ea.v, out cpu_m); - } - - private static void Abs_W__() - { - Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); - cpu_reg_pc.v++; - Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); - cpu_reg_pc.v++; - } - - private static void Abs_RW_() - { - Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); - cpu_reg_pc.v++; - Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); - cpu_reg_pc.v++; - Read(ref cpu_reg_ea.v, out cpu_m); - } - - private static void AbsX_R_() - { - Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); - cpu_reg_pc.v++; - Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); - cpu_reg_pc.v++; - cpu_reg_ea.l += cpu_reg_x; - Read(ref cpu_reg_ea.v, out cpu_m); - if (cpu_reg_ea.l < cpu_reg_x) - { - cpu_reg_ea.h++; - Read(ref cpu_reg_ea.v, out cpu_m); - } - } - - private static void AbsX_W_() - { - Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); - cpu_reg_pc.v++; - Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); - cpu_reg_pc.v++; - cpu_reg_ea.l += cpu_reg_x; - Read(ref cpu_reg_ea.v, out cpu_m); - if (cpu_reg_ea.l < cpu_reg_x) - { - cpu_reg_ea.h++; - } - } - - private static void AbsX_RW() - { - Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); - cpu_reg_pc.v++; - Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); - cpu_reg_pc.v++; - cpu_reg_ea.l += cpu_reg_x; - Read(ref cpu_reg_ea.v, out cpu_dummy); - if (cpu_reg_ea.l < cpu_reg_x) - { - cpu_reg_ea.h++; - } - Read(ref cpu_reg_ea.v, out cpu_m); - } - - private static void AbsY_R_() - { - Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); - cpu_reg_pc.v++; - Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); - cpu_reg_pc.v++; - cpu_reg_ea.l += cpu_reg_y; - Read(ref cpu_reg_ea.v, out cpu_m); - if (cpu_reg_ea.l < cpu_reg_y) - { - cpu_reg_ea.h++; - Read(ref cpu_reg_ea.v, out cpu_m); - } - } - - private static void AbsY_W_() - { - Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); - cpu_reg_pc.v++; - Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); - cpu_reg_pc.v++; - cpu_reg_ea.l += cpu_reg_y; - Read(ref cpu_reg_ea.v, out cpu_m); - if (cpu_reg_ea.l < cpu_reg_y) - { - cpu_reg_ea.h++; - } - } - - private static void AbsY_RW() - { - Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); - cpu_reg_pc.v++; - Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); - cpu_reg_pc.v++; - cpu_reg_ea.l += cpu_reg_y; - Read(ref cpu_reg_ea.v, out cpu_m); - if (cpu_reg_ea.l < cpu_reg_y) - { - cpu_reg_ea.h++; - } - Read(ref cpu_reg_ea.v, out cpu_m); - } - - private static void Interrupt() - { - Push(ref cpu_reg_pc.h); - Push(ref cpu_reg_pc.l); - cpu_dummy = ((cpu_opcode == 0) ? register_pb() : register_p); - Push(ref cpu_dummy); - temp_add.v = InterruptVector; - cpu_suspend_nmi = true; - cpu_flag_i = true; - CPU_NMI_PIN = false; - Read(ref temp_add.v, out cpu_reg_pc.l); - temp_add.v++; - Read(ref temp_add.v, out cpu_reg_pc.h); - cpu_suspend_nmi = false; - } - - private static void Branch(ref bool condition) - { - Read(ref cpu_reg_pc.v, out cpu_byte_temp); - cpu_reg_pc.v++; - if (!condition) - { - return; - } - cpu_suspend_irq = true; - Read(ref cpu_reg_pc.v, out cpu_dummy); - cpu_reg_pc.l += cpu_byte_temp; - cpu_suspend_irq = false; - if (cpu_byte_temp >= 128) - { - if (cpu_reg_pc.l >= cpu_byte_temp) - { - Read(ref cpu_reg_pc.v, out cpu_dummy); - cpu_reg_pc.h--; - } - } - else if (cpu_reg_pc.l < cpu_byte_temp) - { - Read(ref cpu_reg_pc.v, out cpu_dummy); - cpu_reg_pc.h++; - } - } - - private static void Push(ref byte val) - { - Write(ref cpu_reg_sp.v, ref val); - cpu_reg_sp.l--; - } - - private static void Pull(out byte val) - { - cpu_reg_sp.l++; - Read(ref cpu_reg_sp.v, out val); - } - - private static void ADC__() - { - cpu_int_temp = cpu_reg_a + cpu_m + (cpu_flag_c ? 1 : 0); - cpu_flag_v = ((cpu_int_temp ^ cpu_reg_a) & (cpu_int_temp ^ cpu_m) & 0x80) != 0; - cpu_flag_n = (cpu_int_temp & 0x80) != 0; - cpu_flag_z = (cpu_int_temp & 0xFF) == 0; - cpu_flag_c = cpu_int_temp >> 8 != 0; - cpu_reg_a = (byte)((uint)cpu_int_temp & 0xFFu); - } - - private static void AHX__() - { - cpu_byte_temp = (byte)((uint)(cpu_reg_a & cpu_reg_x) & 7u); - Write(ref cpu_reg_ea.v, ref cpu_byte_temp); - } - - private static void ALR__() - { - cpu_reg_a &= cpu_m; - cpu_flag_c = (cpu_reg_a & 1) != 0; - cpu_reg_a >>= 1; - cpu_flag_n = (cpu_reg_a & 0x80) != 0; - cpu_flag_z = cpu_reg_a == 0; - } - - private static void ANC__() - { - cpu_reg_a &= cpu_m; - cpu_flag_n = (cpu_reg_a & 0x80) != 0; - cpu_flag_z = cpu_reg_a == 0; - cpu_flag_c = (cpu_reg_a & 0x80) != 0; - } - - private static void AND__() - { - cpu_reg_a &= cpu_m; - cpu_flag_n = (cpu_reg_a & 0x80) == 128; - cpu_flag_z = cpu_reg_a == 0; - } - - private static void ARR__() - { - cpu_reg_a = (byte)((uint)((cpu_m & cpu_reg_a) >> 1) | (cpu_flag_c ? 128u : 0u)); - cpu_flag_z = (cpu_reg_a & 0xFF) == 0; - cpu_flag_n = (cpu_reg_a & 0x80) != 0; - cpu_flag_c = (cpu_reg_a & 0x40) != 0; - cpu_flag_v = (((cpu_reg_a << 1) ^ cpu_reg_a) & 0x40) != 0; - } - - private static void AXS__() - { - cpu_int_temp = (cpu_reg_a & cpu_reg_x) - cpu_m; - cpu_flag_n = (cpu_int_temp & 0x80) != 0; - cpu_flag_z = (cpu_int_temp & 0xFF) == 0; - cpu_flag_c = ~cpu_int_temp >> 8 != 0; - cpu_reg_x = (byte)((uint)cpu_int_temp & 0xFFu); - } - - private static void ASL_M() - { - cpu_flag_c = (cpu_m & 0x80) == 128; - Write(ref cpu_reg_ea.v, ref cpu_m); - cpu_m = (byte)((uint)(cpu_m << 1) & 0xFEu); - Write(ref cpu_reg_ea.v, ref cpu_m); - cpu_flag_n = (cpu_m & 0x80) == 128; - cpu_flag_z = cpu_m == 0; - } - - private static void ASL_A() - { - cpu_flag_c = (cpu_reg_a & 0x80) == 128; - cpu_reg_a = (byte)((uint)(cpu_reg_a << 1) & 0xFEu); - cpu_flag_n = (cpu_reg_a & 0x80) == 128; - cpu_flag_z = cpu_reg_a == 0; - } - - private static void BCC__() - { - cpu_bool_tmp = !cpu_flag_c; - Branch(ref cpu_bool_tmp); - } - - private static void BCS__() - { - Branch(ref cpu_flag_c); - } - - private static void BEQ__() - { - Branch(ref cpu_flag_z); - } - - private static void BIT__() - { - cpu_flag_n = (cpu_m & 0x80) != 0; - cpu_flag_v = (cpu_m & 0x40) != 0; - cpu_flag_z = (cpu_m & cpu_reg_a) == 0; - } - - private static void BRK__() - { - Read(ref cpu_reg_pc.v, out cpu_dummy); - cpu_reg_pc.v++; - Interrupt(); - } - - private static void BPL__() - { - cpu_bool_tmp = !cpu_flag_n; - Branch(ref cpu_bool_tmp); - } - - private static void BNE__() - { - cpu_bool_tmp = !cpu_flag_z; - Branch(ref cpu_bool_tmp); - } - - private static void BMI__() - { - Branch(ref cpu_flag_n); - } - - private static void BVC__() - { - cpu_bool_tmp = !cpu_flag_v; - Branch(ref cpu_bool_tmp); - } - - private static void BVS__() - { - Branch(ref cpu_flag_v); - } - - private static void SED__() - { - cpu_flag_d = true; - } - - private static void CLC__() - { - cpu_flag_c = false; - } - - private static void CLD__() - { - cpu_flag_d = false; - } - - private static void CLV__() - { - cpu_flag_v = false; - } - - private static void CMP__() - { - cpu_int_temp = cpu_reg_a - cpu_m; - cpu_flag_n = (cpu_int_temp & 0x80) == 128; - cpu_flag_c = cpu_reg_a >= cpu_m; - cpu_flag_z = cpu_int_temp == 0; - } - - private static void CPX__() - { - cpu_int_temp = cpu_reg_x - cpu_m; - cpu_flag_n = (cpu_int_temp & 0x80) == 128; - cpu_flag_c = cpu_reg_x >= cpu_m; - cpu_flag_z = cpu_int_temp == 0; - } - - private static void CPY__() - { - cpu_int_temp = cpu_reg_y - cpu_m; - cpu_flag_n = (cpu_int_temp & 0x80) == 128; - cpu_flag_c = cpu_reg_y >= cpu_m; - cpu_flag_z = cpu_int_temp == 0; - } - - private static void CLI__() - { - cpu_flag_i = false; - } - - private static void DCP__() - { - Write(ref cpu_reg_ea.v, ref cpu_m); - cpu_m--; - Write(ref cpu_reg_ea.v, ref cpu_m); - cpu_int_temp = cpu_reg_a - cpu_m; - cpu_flag_n = (cpu_int_temp & 0x80) != 0; - cpu_flag_z = cpu_int_temp == 0; - cpu_flag_c = ~cpu_int_temp >> 8 != 0; - } - - private static void DEC__() - { - Write(ref cpu_reg_ea.v, ref cpu_m); - cpu_m--; - Write(ref cpu_reg_ea.v, ref cpu_m); - cpu_flag_n = (cpu_m & 0x80) == 128; - cpu_flag_z = cpu_m == 0; - } - - private static void DEY__() - { - cpu_reg_y--; - cpu_flag_z = cpu_reg_y == 0; - cpu_flag_n = (cpu_reg_y & 0x80) == 128; - } - - private static void DEX__() - { - cpu_reg_x--; - cpu_flag_z = cpu_reg_x == 0; - cpu_flag_n = (cpu_reg_x & 0x80) == 128; - } - - private static void EOR__() - { - cpu_reg_a ^= cpu_m; - cpu_flag_n = (cpu_reg_a & 0x80) == 128; - cpu_flag_z = cpu_reg_a == 0; - } - - private static void INC__() - { - Write(ref cpu_reg_ea.v, ref cpu_m); - cpu_m++; - Write(ref cpu_reg_ea.v, ref cpu_m); - cpu_flag_n = (cpu_m & 0x80) == 128; - cpu_flag_z = cpu_m == 0; - } - - private static void INX__() - { - cpu_reg_x++; - cpu_flag_z = cpu_reg_x == 0; - cpu_flag_n = (cpu_reg_x & 0x80) == 128; - } - - private static void INY__() - { - cpu_reg_y++; - cpu_flag_n = (cpu_reg_y & 0x80) == 128; - cpu_flag_z = cpu_reg_y == 0; - } - - private static void ISC__() - { - Read(ref cpu_reg_ea.v, out cpu_byte_temp); - Write(ref cpu_reg_ea.v, ref cpu_byte_temp); - cpu_byte_temp++; - Write(ref cpu_reg_ea.v, ref cpu_byte_temp); - cpu_int_temp = cpu_byte_temp ^ 0xFF; - cpu_int_temp1 = cpu_reg_a + cpu_int_temp + (cpu_flag_c ? 1 : 0); - cpu_flag_n = (cpu_int_temp1 & 0x80) != 0; - cpu_flag_v = ((cpu_int_temp1 ^ cpu_reg_a) & (cpu_int_temp1 ^ cpu_int_temp) & 0x80) != 0; - cpu_flag_z = (cpu_int_temp1 & 0xFF) == 0; - cpu_flag_c = cpu_int_temp1 >> 8 != 0; - cpu_reg_a = (byte)((uint)cpu_int_temp1 & 0xFFu); - } - - private static void JMP__() - { - cpu_reg_pc.v = cpu_reg_ea.v; - } - - private static void JMP_I() - { - Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); - cpu_reg_pc.v++; - Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); - Read(ref cpu_reg_ea.v, out cpu_reg_pc.l); - cpu_reg_ea.l++; - Read(ref cpu_reg_ea.v, out cpu_reg_pc.h); - } - - private static void JSR__() - { - Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); - cpu_reg_pc.v++; - Write(ref cpu_reg_sp.v, ref cpu_reg_ea.l); - Push(ref cpu_reg_pc.h); - Push(ref cpu_reg_pc.l); - Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); - cpu_reg_pc.v = cpu_reg_ea.v; - } - - private static void LAR__() - { - cpu_reg_sp.l &= cpu_m; - cpu_reg_a = cpu_reg_sp.l; - cpu_reg_x = cpu_reg_sp.l; - cpu_flag_n = (cpu_reg_sp.l & 0x80) != 0; - cpu_flag_z = (cpu_reg_sp.l & 0xFF) == 0; - } - - private static void LAX__() - { - cpu_reg_x = (cpu_reg_a = cpu_m); - cpu_flag_n = (cpu_reg_x & 0x80) != 0; - cpu_flag_z = (cpu_reg_x & 0xFF) == 0; - } - - private static void LDA__() - { - cpu_reg_a = cpu_m; - cpu_flag_n = (cpu_reg_a & 0x80) == 128; - cpu_flag_z = cpu_reg_a == 0; - } - - private static void LDX__() - { - cpu_reg_x = cpu_m; - cpu_flag_n = (cpu_reg_x & 0x80) == 128; - cpu_flag_z = cpu_reg_x == 0; - } - - private static void LDY__() - { - cpu_reg_y = cpu_m; - cpu_flag_n = (cpu_reg_y & 0x80) == 128; - cpu_flag_z = cpu_reg_y == 0; - } - - private static void LSR_A() - { - cpu_flag_c = (cpu_reg_a & 1) == 1; - cpu_reg_a >>= 1; - cpu_flag_z = cpu_reg_a == 0; - cpu_flag_n = (cpu_reg_a & 0x80) != 0; - } - - private static void LSR_M() - { - cpu_flag_c = (cpu_m & 1) == 1; - Write(ref cpu_reg_ea.v, ref cpu_m); - cpu_m >>= 1; - Write(ref cpu_reg_ea.v, ref cpu_m); - cpu_flag_z = cpu_m == 0; - cpu_flag_n = (cpu_m & 0x80) != 0; - } - - private static void NOP__() - { - } - - private static void ORA__() - { - cpu_reg_a |= cpu_m; - cpu_flag_n = (cpu_reg_a & 0x80) == 128; - cpu_flag_z = cpu_reg_a == 0; - } - - private static void PHA__() - { - Push(ref cpu_reg_a); - } - - private static void PHP__() - { - cpu_dummy = register_pb(); - Push(ref cpu_dummy); - } - - private static void PLA__() - { - Read(ref cpu_reg_sp.v, out cpu_dummy); - Pull(out cpu_reg_a); - cpu_flag_n = (cpu_reg_a & 0x80) == 128; - cpu_flag_z = cpu_reg_a == 0; - } - - private static void PLP__() - { - Read(ref cpu_reg_sp.v, out cpu_dummy); - Pull(out cpu_dummy); - register_p = cpu_dummy; - } - - private static void RLA__() - { - Read(ref cpu_reg_ea.v, out cpu_byte_temp); - Write(ref cpu_reg_ea.v, ref cpu_byte_temp); - cpu_dummy = (byte)((uint)(cpu_byte_temp << 1) | (cpu_flag_c ? 1u : 0u)); - Write(ref cpu_reg_ea.v, ref cpu_dummy); - cpu_flag_n = (cpu_dummy & 0x80) != 0; - cpu_flag_z = (cpu_dummy & 0xFF) == 0; - cpu_flag_c = (cpu_byte_temp & 0x80) != 0; - cpu_reg_a &= cpu_dummy; - cpu_flag_n = (cpu_reg_a & 0x80) != 0; - cpu_flag_z = (cpu_reg_a & 0xFF) == 0; - } - - private static void ROL_A() - { - cpu_byte_temp = (byte)((uint)(cpu_reg_a << 1) | (cpu_flag_c ? 1u : 0u)); - cpu_flag_n = (cpu_byte_temp & 0x80) != 0; - cpu_flag_z = (cpu_byte_temp & 0xFF) == 0; - cpu_flag_c = (cpu_reg_a & 0x80) != 0; - cpu_reg_a = cpu_byte_temp; - } - - private static void ROL_M() - { - Write(ref cpu_reg_ea.v, ref cpu_m); - cpu_byte_temp = (byte)((uint)(cpu_m << 1) | (cpu_flag_c ? 1u : 0u)); - Write(ref cpu_reg_ea.v, ref cpu_byte_temp); - cpu_flag_n = (cpu_byte_temp & 0x80) != 0; - cpu_flag_z = (cpu_byte_temp & 0xFF) == 0; - cpu_flag_c = (cpu_m & 0x80) != 0; - } - - private static void ROR_A() - { - cpu_byte_temp = (byte)((uint)(cpu_reg_a >> 1) | (cpu_flag_c ? 128u : 0u)); - cpu_flag_n = (cpu_byte_temp & 0x80) != 0; - cpu_flag_z = (cpu_byte_temp & 0xFF) == 0; - cpu_flag_c = (cpu_reg_a & 1) != 0; - cpu_reg_a = cpu_byte_temp; - } - - private static void ROR_M() - { - Write(ref cpu_reg_ea.v, ref cpu_m); - cpu_byte_temp = (byte)((uint)(cpu_m >> 1) | (cpu_flag_c ? 128u : 0u)); - Write(ref cpu_reg_ea.v, ref cpu_byte_temp); - cpu_flag_n = (cpu_byte_temp & 0x80) != 0; - cpu_flag_z = (cpu_byte_temp & 0xFF) == 0; - cpu_flag_c = (cpu_m & 1) != 0; - } - - private static void RRA__() - { - Read(ref cpu_reg_ea.v, out cpu_byte_temp); - Write(ref cpu_reg_ea.v, ref cpu_byte_temp); - cpu_dummy = (byte)((uint)(cpu_byte_temp >> 1) | (cpu_flag_c ? 128u : 0u)); - Write(ref cpu_reg_ea.v, ref cpu_dummy); - cpu_flag_n = (cpu_dummy & 0x80) != 0; - cpu_flag_z = (cpu_dummy & 0xFF) == 0; - cpu_flag_c = (cpu_byte_temp & 1) != 0; - cpu_byte_temp = cpu_dummy; - cpu_int_temp = cpu_reg_a + cpu_byte_temp + (cpu_flag_c ? 1 : 0); - cpu_flag_n = (cpu_int_temp & 0x80) != 0; - cpu_flag_v = ((cpu_int_temp ^ cpu_reg_a) & (cpu_int_temp ^ cpu_byte_temp) & 0x80) != 0; - cpu_flag_z = (cpu_int_temp & 0xFF) == 0; - cpu_flag_c = cpu_int_temp >> 8 != 0; - cpu_reg_a = (byte)cpu_int_temp; - } - - private static void RTI__() - { - Read(ref cpu_reg_sp.v, out cpu_dummy); - Pull(out cpu_dummy); - register_p = cpu_dummy; - Pull(out cpu_reg_pc.l); - Pull(out cpu_reg_pc.h); - } - - private static void RTS__() - { - Read(ref cpu_reg_sp.v, out cpu_dummy); - Pull(out cpu_reg_pc.l); - Pull(out cpu_reg_pc.h); - cpu_reg_pc.v++; - Read(ref cpu_reg_pc.v, out cpu_dummy); - } - - private static void SAX__() - { - cpu_dummy = (byte)(cpu_reg_x & cpu_reg_a); - Write(ref cpu_reg_ea.v, ref cpu_dummy); - } - - private static void SBC__() - { - cpu_m ^= byte.MaxValue; - cpu_int_temp = cpu_reg_a + cpu_m + (cpu_flag_c ? 1 : 0); - cpu_flag_n = (cpu_int_temp & 0x80) != 0; - cpu_flag_v = ((cpu_int_temp ^ cpu_reg_a) & (cpu_int_temp ^ cpu_m) & 0x80) != 0; - cpu_flag_z = (cpu_int_temp & 0xFF) == 0; - cpu_flag_c = cpu_int_temp >> 8 != 0; - cpu_reg_a = (byte)cpu_int_temp; - } - - private static void SEC__() - { - cpu_flag_c = true; - } - - private static void SEI__() - { - cpu_flag_i = true; - } - - private static void SHX__() - { - cpu_byte_temp = (byte)(cpu_reg_x & (cpu_reg_ea.h + 1)); - Read(ref cpu_reg_ea.v, out cpu_dummy); - cpu_reg_ea.l += cpu_reg_y; - if (cpu_reg_ea.l < cpu_reg_y) - { - cpu_reg_ea.h = cpu_byte_temp; - } - Write(ref cpu_reg_ea.v, ref cpu_byte_temp); - } - - private static void SHY__() - { - cpu_byte_temp = (byte)(cpu_reg_y & (cpu_reg_ea.h + 1)); - Read(ref cpu_reg_ea.v, out cpu_dummy); - cpu_reg_ea.l += cpu_reg_x; - if (cpu_reg_ea.l < cpu_reg_x) - { - cpu_reg_ea.h = cpu_byte_temp; - } - Write(ref cpu_reg_ea.v, ref cpu_byte_temp); - } - - private static void SLO__() - { - Read(ref cpu_reg_ea.v, out cpu_byte_temp); - cpu_flag_c = (cpu_byte_temp & 0x80) != 0; - Write(ref cpu_reg_ea.v, ref cpu_byte_temp); - cpu_byte_temp <<= 1; - Write(ref cpu_reg_ea.v, ref cpu_byte_temp); - cpu_flag_n = (cpu_byte_temp & 0x80) != 0; - cpu_flag_z = (cpu_byte_temp & 0xFF) == 0; - cpu_reg_a |= cpu_byte_temp; - cpu_flag_n = (cpu_reg_a & 0x80) != 0; - cpu_flag_z = (cpu_reg_a & 0xFF) == 0; - } - - private static void SRE__() - { - Read(ref cpu_reg_ea.v, out cpu_byte_temp); - cpu_flag_c = (cpu_byte_temp & 1) != 0; - Write(ref cpu_reg_ea.v, ref cpu_byte_temp); - cpu_byte_temp >>= 1; - Write(ref cpu_reg_ea.v, ref cpu_byte_temp); - cpu_flag_n = (cpu_byte_temp & 0x80) != 0; - cpu_flag_z = (cpu_byte_temp & 0xFF) == 0; - cpu_reg_a ^= cpu_byte_temp; - cpu_flag_n = (cpu_reg_a & 0x80) != 0; - cpu_flag_z = (cpu_reg_a & 0xFF) == 0; - } - - private static void STA__() - { - Write(ref cpu_reg_ea.v, ref cpu_reg_a); - } - - private static void STX__() - { - Write(ref cpu_reg_ea.v, ref cpu_reg_x); - } - - private static void STY__() - { - Write(ref cpu_reg_ea.v, ref cpu_reg_y); - } - - private static void TAX__() - { - cpu_reg_x = cpu_reg_a; - cpu_flag_n = (cpu_reg_x & 0x80) == 128; - cpu_flag_z = cpu_reg_x == 0; - } - - private static void TAY__() - { - cpu_reg_y = cpu_reg_a; - cpu_flag_n = (cpu_reg_y & 0x80) == 128; - cpu_flag_z = cpu_reg_y == 0; - } - - private static void TSX__() - { - cpu_reg_x = cpu_reg_sp.l; - cpu_flag_n = (cpu_reg_x & 0x80) != 0; - cpu_flag_z = cpu_reg_x == 0; - } - - private static void TXA__() - { - cpu_reg_a = cpu_reg_x; - cpu_flag_n = (cpu_reg_a & 0x80) == 128; - cpu_flag_z = cpu_reg_a == 0; - } - - private static void TXS__() - { - cpu_reg_sp.l = cpu_reg_x; - } - - private static void TYA__() - { - cpu_reg_a = cpu_reg_y; - cpu_flag_n = (cpu_reg_a & 0x80) == 128; - cpu_flag_z = cpu_reg_a == 0; - } - - private static void XAA__() - { - cpu_reg_a = (byte)(cpu_reg_x & cpu_m); - cpu_flag_n = (cpu_reg_a & 0x80) != 0; - cpu_flag_z = (cpu_reg_a & 0xFF) == 0; - } - - private static void XAS__() - { - cpu_reg_sp.l = (byte)(cpu_reg_a & cpu_reg_x); - Write(ref cpu_reg_ea.v, ref cpu_reg_sp.l); - } - - private static void CPUWriteState(ref BinaryWriter bin) - { - bin.Write(cpu_reg_pc.v); - bin.Write(cpu_reg_sp.v); - bin.Write(cpu_reg_ea.v); - bin.Write(cpu_reg_a); - bin.Write(cpu_reg_x); - bin.Write(cpu_reg_y); - bin.Write(cpu_flag_n); - bin.Write(cpu_flag_v); - bin.Write(cpu_flag_d); - bin.Write(cpu_flag_i); - bin.Write(cpu_flag_z); - bin.Write(cpu_flag_c); - bin.Write(cpu_m); - bin.Write(cpu_opcode); - bin.Write(cpu_byte_temp); - bin.Write(cpu_int_temp); - bin.Write(cpu_int_temp1); - bin.Write(cpu_dummy); - bin.Write(cpu_bool_tmp); - bin.Write(temp_add.v); - bin.Write(CPU_IRQ_PIN); - bin.Write(CPU_NMI_PIN); - bin.Write(cpu_suspend_nmi); - bin.Write(cpu_suspend_irq); - } - - private static void CPUReadState(ref BinaryReader bin) - { - cpu_reg_pc.v = bin.ReadUInt16(); - cpu_reg_sp.v = bin.ReadUInt16(); - cpu_reg_ea.v = bin.ReadUInt16(); - cpu_reg_a = bin.ReadByte(); - cpu_reg_x = bin.ReadByte(); - cpu_reg_y = bin.ReadByte(); - cpu_flag_n = bin.ReadBoolean(); - cpu_flag_v = bin.ReadBoolean(); - cpu_flag_d = bin.ReadBoolean(); - cpu_flag_i = bin.ReadBoolean(); - cpu_flag_z = bin.ReadBoolean(); - cpu_flag_c = bin.ReadBoolean(); - cpu_m = bin.ReadByte(); - cpu_opcode = bin.ReadByte(); - cpu_byte_temp = bin.ReadByte(); - cpu_int_temp = bin.ReadInt32(); - cpu_int_temp1 = bin.ReadInt32(); - cpu_dummy = bin.ReadByte(); - cpu_bool_tmp = bin.ReadBoolean(); - temp_add.v = bin.ReadUInt16(); - CPU_IRQ_PIN = bin.ReadBoolean(); - CPU_NMI_PIN = bin.ReadBoolean(); - cpu_suspend_nmi = bin.ReadBoolean(); - cpu_suspend_irq = bin.ReadBoolean(); - } - - private static void DMAHardReset() - { - dma_DMCDMAWaitCycles = 0; - dma_OAMDMAWaitCycles = 0; - dma_isOamDma = false; - dma_oamdma_i = 0; - dma_DMCOn = false; - dma_OAMOn = false; - dma_DMC_occurring = false; - dma_OAM_occurring = false; - dma_OAMFinishCounter = 0; - dma_Oamaddress = 0; - dma_OAMCYCLE = 0; - dma_latch = 0; - reg_2004 = 8196; - } - - private static void DMASoftReset() - { - dma_DMCDMAWaitCycles = 0; - dma_OAMDMAWaitCycles = 0; - dma_isOamDma = false; - dma_oamdma_i = 0; - dma_DMCOn = false; - dma_OAMOn = false; - dma_DMC_occurring = false; - dma_OAM_occurring = false; - dma_OAMFinishCounter = 0; - dma_Oamaddress = 0; - dma_OAMCYCLE = 0; - dma_latch = 0; - } - - internal static void AssertDMCDMA() - { - if (dma_OAM_occurring) - { - if (dma_OAMCYCLE < 508) - { - dma_DMCDMAWaitCycles = (BUS_RW ? 1 : 0); - } - else - { - dma_DMCDMAWaitCycles = 4 - (512 - dma_OAMCYCLE); - } - } - else - { - if (dma_DMC_occurring) - { - return; - } - dma_DMCDMAWaitCycles = (BUS_RW ? 3 : 2); - if (dma_OAMFinishCounter == 3) - { - dma_DMCDMAWaitCycles++; - } - } - dma_isOamDma = false; - dma_DMCOn = true; - } - - private static void AssertOAMDMA() - { - if (!dma_OAM_occurring) - { - dma_OAMDMAWaitCycles = (apu_odd_cycle ? 1 : 2); - dma_isOamDma = true; - dma_OAMOn = true; - } - } - - private static void DMAClock() - { - if (dma_OAMFinishCounter > 0) - { - dma_OAMFinishCounter--; - } - if (!BUS_RW) - { - if (dma_DMCDMAWaitCycles > 0) - { - dma_DMCDMAWaitCycles--; - } - if (dma_OAMDMAWaitCycles > 0) - { - dma_OAMDMAWaitCycles--; - } - return; - } - if (dma_DMCOn) - { - dma_DMC_occurring = true; - dma_DMCOn = false; - if (dma_DMCDMAWaitCycles > 0) - { - if (BUS_ADDRESS == 16406 || BUS_ADDRESS == 16407) - { - Read(ref BUS_ADDRESS, out dma_dummy); - dma_DMCDMAWaitCycles--; - while (dma_DMCDMAWaitCycles > 0) - { - EmuClockComponents(); - dma_DMCDMAWaitCycles--; - } - } - else - { - if (dma_DMCDMAWaitCycles > 0) - { - EmuClockComponents(); - dma_DMCDMAWaitCycles--; - } - while (dma_DMCDMAWaitCycles > 0) - { - Read(ref BUS_ADDRESS, out dma_dummy); - dma_DMCDMAWaitCycles--; - } - } - } - DMCDoDMA(); - dma_DMC_occurring = false; - } - if (!dma_OAMOn) - { - return; - } - dma_OAM_occurring = true; - dma_OAMOn = false; - if (dma_OAMDMAWaitCycles > 0) - { - if (BUS_ADDRESS == 16406 || BUS_ADDRESS == 16407) - { - Read(ref BUS_ADDRESS, out dma_dummy); - dma_OAMDMAWaitCycles--; - while (dma_OAMDMAWaitCycles > 0) - { - EmuClockComponents(); - dma_OAMDMAWaitCycles--; - } - } - else - { - if (dma_OAMDMAWaitCycles > 0) - { - EmuClockComponents(); - dma_OAMDMAWaitCycles--; - } - while (dma_OAMDMAWaitCycles > 0) - { - Read(ref BUS_ADDRESS, out dma_dummy); - dma_OAMDMAWaitCycles--; - } - } - } - dma_OAMCYCLE = 0; - for (dma_oamdma_i = 0; dma_oamdma_i < 256; dma_oamdma_i++) - { - Read(ref dma_Oamaddress, out dma_latch); - dma_OAMCYCLE++; - Write(ref reg_2004, ref dma_latch); - dma_OAMCYCLE++; - dma_Oamaddress = (ushort)(++dma_Oamaddress & 0xFFFFu); - } - dma_OAMCYCLE = 0; - dma_OAMFinishCounter = 5; - dma_OAM_occurring = false; - } - - private static void DMAWriteState(ref BinaryWriter bin) - { - bin.Write(dma_DMCDMAWaitCycles); - bin.Write(dma_OAMDMAWaitCycles); - bin.Write(dma_isOamDma); - bin.Write(dma_oamdma_i); - bin.Write(dma_DMCOn); - bin.Write(dma_OAMOn); - bin.Write(dma_DMC_occurring); - bin.Write(dma_OAM_occurring); - bin.Write(dma_OAMFinishCounter); - bin.Write(dma_Oamaddress); - bin.Write(dma_OAMCYCLE); - bin.Write(dma_latch); - bin.Write(dma_dummy); - } - - private static void DMAReadState(ref BinaryReader bin) - { - dma_DMCDMAWaitCycles = bin.ReadInt32(); - dma_OAMDMAWaitCycles = bin.ReadInt32(); - dma_isOamDma = bin.ReadBoolean(); - dma_oamdma_i = bin.ReadInt32(); - dma_DMCOn = bin.ReadBoolean(); - dma_OAMOn = bin.ReadBoolean(); - dma_DMC_occurring = bin.ReadBoolean(); - dma_OAM_occurring = bin.ReadBoolean(); - dma_OAMFinishCounter = bin.ReadInt32(); - dma_Oamaddress = bin.ReadUInt16(); - dma_OAMCYCLE = bin.ReadInt32(); - dma_latch = bin.ReadByte(); - dma_dummy = bin.ReadByte(); - } - - private static void PollInterruptStatus() - { - if (!cpu_suspend_nmi) - { - if (PPU_NMI_Current & !PPU_NMI_Old) - { - CPU_NMI_PIN = true; - } - PPU_NMI_Old = (PPU_NMI_Current = false); - } - if (!cpu_suspend_irq) - { - CPU_IRQ_PIN = !cpu_flag_i && IRQFlags != 0; - } - if (CPU_NMI_PIN) - { - InterruptVector = 65530; - } - else - { - InterruptVector = 65534; - } - } - - private static void InterruptsWriteState(ref BinaryWriter bin) - { - bin.Write(IRQFlags); - bin.Write(PPU_NMI_Current); - bin.Write(PPU_NMI_Old); - bin.Write(InterruptVector); - } - - private static void InterruptsReadState(ref BinaryReader bin) - { - IRQFlags = bin.ReadInt32(); - PPU_NMI_Current = bin.ReadBoolean(); - PPU_NMI_Old = bin.ReadBoolean(); - InterruptVector = bin.ReadUInt16(); - } - - public static void SetupGameGenie(bool IsGameGenieActive, GameGenieCode[] GameGenieCodes) - { - if (mem_board != null) - { - mem_board.SetupGameGenie(IsGameGenieActive, GameGenieCodes); - } - } - - private static void MEMInitialize(IRom rom) - { - Tracer.WriteLine("Looking for mapper # " + rom.MapperNumber + "...."); - if (MyNesMain.IsBoardExist(rom.MapperNumber)) - { - Tracer.WriteLine("Mapper # " + rom.MapperNumber + " located, assigning..."); - mem_board = MyNesMain.GetBoard(rom.MapperNumber); - Tracer.WriteInformation("Mapper # " + rom.MapperNumber + " assigned successfully."); - if (mem_board.HasIssues) - { - Tracer.WriteWarning(MNInterfaceLanguage.Mapper + " # " + mem_board.MapperNumber + " [" + mem_board.Name + "] " + MNInterfaceLanguage.Message_Error17); - MyNesMain.VideoProvider.WriteWarningNotification(MNInterfaceLanguage.Mapper + " # " + mem_board.MapperNumber + " [" + mem_board.Name + "] " + MNInterfaceLanguage.Message_Error17, instant: false); - } - } - else - { - Tracer.WriteError("Mapper # " + rom.MapperNumber + " IS NOT LOCATED, mapper is not supported or unable to find it."); - MyNesMain.VideoProvider.WriteErrorNotification(MNInterfaceLanguage.Mapper + " # " + rom.MapperNumber + " " + MNInterfaceLanguage.Message_Error14, instant: false); - mem_board = MyNesMain.GetBoard(0); - Tracer.WriteWarning("Mapper # 0 [NROM] will be used instead, assigned successfully."); - MyNesMain.VideoProvider.WriteErrorNotification(MNInterfaceLanguage.Mapper + " # 0 [NROM] " + MNInterfaceLanguage.Message_Error15, instant: false); - } - mem_read_accesses = new MemReadAccess[65536]; - mem_write_accesses = new MemWriteAccess[65536]; - MEMMap(MEMReadWRAM, new ushort[2] { 0, 4096 }); - MEMMap(MEMWriteWRAM, new ushort[2] { 0, 4096 }); - MEMMap(PPUIORead, new ushort[2] { 8192, 12288 }); - MEMMap(PPUIOWrite, new ushort[2] { 8192, 12288 }); - MEMMap(APUIORead, new ushort[1] { 16384 }); - MEMMap(APUIOWrite, new ushort[1] { 16384 }); - MEMMap(mem_board.ReadEX, new ushort[1] { 20480 }); - MEMMap(mem_board.WriteEX, new ushort[1] { 20480 }); - MEMMap(mem_board.ReadSRM, new ushort[2] { 24576, 28672 }); - MEMMap(mem_board.WriteSRM, new ushort[2] { 24576, 28672 }); - MEMMap(mem_board.ReadPRG, new ushort[8] { 32768, 36864, 40960, 45056, 49152, 53248, 57344, 61440 }); - MEMMap(mem_board.WritePRG, new ushort[8] { 32768, 36864, 40960, 45056, 49152, 53248, 57344, 61440 }); - mem_board.Initialize(rom); - mem_wram = new byte[2048]; - } - - private static void MEMHardReset() - { - mem_wram = new byte[2048]; - mem_wram[8] = 247; - mem_wram[9] = 239; - mem_wram[10] = 223; - mem_wram[15] = 191; - Tracer.WriteLine("Reading SRAM ..."); - SRAMFileName = Path.Combine(MyNesMain.EmuSettings.SRAMFolder, Path.GetFileNameWithoutExtension(CurrentFilePath) + ".srm"); - if (File.Exists(SRAMFileName)) - { - FileStream fileStream = new FileStream(SRAMFileName, FileMode.Open, FileAccess.Read); - byte[] array = new byte[fileStream.Length]; - fileStream.Read(array, 0, array.Length); - fileStream.Flush(); - fileStream.Close(); - byte[] outData = new byte[0]; - ZlipWrapper.DecompressData(array, out outData); - mem_board.LoadSRAM(outData); - Tracer.WriteLine("SRAM read successfully."); - } - else - { - Tracer.WriteLine("SRAM file not found; rom has no SRAM or file not exist."); - } - ReloadGameGenieCodes(); - mem_board.HardReset(); - } - - public static void ReloadGameGenieCodes() - { - Tracer.WriteLine("Reading game genie codes (if available)...."); - GMFileName = Path.Combine(MyNesMain.EmuSettings.GameGenieFolder, Path.GetFileNameWithoutExtension(CurrentFilePath) + ".txt"); - mem_board.GameGenieCodes = new GameGenieCode[0]; - if (File.Exists(GMFileName)) - { - XmlReaderSettings xmlReaderSettings = new XmlReaderSettings(); - xmlReaderSettings.DtdProcessing = DtdProcessing.Ignore; - xmlReaderSettings.IgnoreWhitespace = true; - XmlReader xmlReader = XmlReader.Create(GMFileName, xmlReaderSettings); - xmlReader.Read(); - xmlReader.Read(); - if (xmlReader.Name != "MyNesGameGenieCodesList") - { - xmlReader.Close(); - return; - } - GameGenie gameGenie = new GameGenie(); - List list = new List(); - while (xmlReader.Read()) - { - if (xmlReader.Name == "Code") - { - GameGenieCode item = default(GameGenieCode); - item.Enabled = true; - xmlReader.MoveToAttribute("code"); - item.Name = xmlReader.Value.ToString(); - if (item.Name.Length == 6) - { - item.Address = gameGenie.GetGGAddress(gameGenie.GetCodeAsHEX(item.Name), 6) | 0x8000; - item.Value = gameGenie.GetGGValue(gameGenie.GetCodeAsHEX(item.Name), 6); - item.IsCompare = false; - } - else - { - item.Address = gameGenie.GetGGAddress(gameGenie.GetCodeAsHEX(item.Name), 8) | 0x8000; - item.Value = gameGenie.GetGGValue(gameGenie.GetCodeAsHEX(item.Name), 8); - item.Compare = gameGenie.GetGGCompareValue(gameGenie.GetCodeAsHEX(item.Name)); - item.IsCompare = true; - } - list.Add(item); - } - } - xmlReader.Close(); - if (list.Count > 0) - { - mem_board.GameGenieCodes = list.ToArray(); - Tracer.WriteInformation("Game Genie codes loaded successfully, total of " + list.Count); - } - else - { - Tracer.WriteError("There is no Game Genie code in the file to load."); - } - } - else - { - Tracer.WriteWarning("No Game Genie file found for this game."); - } - } - - private static void MEMMap(MemReadAccess readAccess, ushort[] addresses) - { - for (int i = 0; i < addresses.Length; i++) - { - mem_read_accesses[(addresses[i] & 0xF000) >> 12] = readAccess; - } - } - - private static void MEMMap(MemWriteAccess writeAccess, ushort[] addresses) - { - for (int i = 0; i < addresses.Length; i++) - { - mem_write_accesses[(addresses[i] & 0xF000) >> 12] = writeAccess; - } - } - - private static void MEMReadWRAM(ref ushort addr, out byte value) - { - value = mem_wram[addr & 0x7FF]; - } - - private static void MEMWriteWRAM(ref ushort addr, ref byte value) - { - mem_wram[addr & 0x7FF] = value; - } - - internal static void Read(ref ushort addr, out byte value) - { - BUS_RW = true; - BUS_ADDRESS = addr; - EmuClockComponents(); - mem_read_accesses[(addr & 0xF000) >> 12](ref addr, out value); - } - - private static void Write(ref ushort addr, ref byte value) - { - BUS_RW = false; - BUS_ADDRESS = addr; - EmuClockComponents(); - mem_write_accesses[(addr & 0xF000) >> 12](ref addr, ref value); - } - - internal static void SaveSRAM() - { - if (mem_board != null && MyNesMain.EmuSettings.SaveSRAMAtEmuShutdown && mem_board.SRAMSaveRequired) - { - Tracer.WriteLine("Saving SRAM ..."); - byte[] outData = new byte[0]; - ZlipWrapper.CompressData(mem_board.GetSRAMBuffer(), out outData); - FileStream fileStream = new FileStream(SRAMFileName, FileMode.Create, FileAccess.Write); - fileStream.Write(outData, 0, outData.Length); - fileStream.Flush(); - fileStream.Close(); - Tracer.WriteLine("SRAM saved successfully."); - } - } - - private static void MEMWriteState(ref BinaryWriter bin) - { - mem_board.WriteStateData(ref bin); - bin.Write(mem_wram); - bin.Write(BUS_RW); - bin.Write(BUS_ADDRESS); - } - - private static void MEMReadState(ref BinaryReader bin) - { - mem_board.ReadStateData(ref bin); - bin.Read(mem_wram, 0, mem_wram.Length); - BUS_RW = bin.ReadBoolean(); - BUS_ADDRESS = bin.ReadUInt16(); - } - - private static void PORTSInitialize() - { - if (joypad1 == null) - { - joypad1 = new BlankJoypad(); - } - if (joypad2 == null) - { - joypad2 = new BlankJoypad(); - } - if (joypad3 == null) - { - joypad3 = new BlankJoypad(); - } - if (joypad4 == null) - { - joypad4 = new BlankJoypad(); - } - if (shortucts == null) - { - shortucts = new BlankShortuctsHandler(); - } - } - - public static void SetupShortcutsHandler(IShortcutsHandler hh) - { - shortucts = hh; - } - - public static void SetupControllers(IJoypadConnecter joy1, IJoypadConnecter joy2, IJoypadConnecter joy3, IJoypadConnecter joy4) - { - joypad1 = joy1; - joypad2 = joy2; - joypad3 = joy3; - joypad4 = joy4; - } - - public static void SetupVSUnisystemDIP(IVSUnisystemDIPConnecter uni) - { - } - - public static void SetupControllersP1(IJoypadConnecter joy) - { - joypad1 = joy; - } - - public static void SetupControllersP2(IJoypadConnecter joy) - { - joypad2 = joy; - } - - public static void SetupControllersP3(IJoypadConnecter joy) - { - joypad3 = joy; - } - - public static void SetupControllersP4(IJoypadConnecter joy) - { - joypad4 = joy; - } - - public static void DestroyJoypads() - { - if (joypad1 == null) - { - joypad1 = new BlankJoypad(); - } - else - { - joypad1.Destroy(); - } - if (joypad2 == null) - { - joypad2 = new BlankJoypad(); - } - else - { - joypad1.Destroy(); - } - if (joypad3 == null) - { - joypad3 = new BlankJoypad(); - } - else - { - joypad1.Destroy(); - } - if (joypad4 == null) - { - joypad4 = new BlankJoypad(); - } - else - { - joypad1.Destroy(); - } - } - - private static void PORTWriteState(ref BinaryWriter bin) - { - bin.Write(PORT0); - bin.Write(PORT1); - bin.Write(inputStrobe); - } - - private static void PORTReadState(ref BinaryReader bin) - { - PORT0 = bin.ReadInt32(); - PORT1 = bin.ReadInt32(); - inputStrobe = bin.ReadInt32(); - } - - public static void SetupPalette(int[] pal) - { - ppu_palette = pal; - } - - private static void PPUInitialize() - { - ppu_reg_update_func = new Action[8] { PPUOnRegister2000, PPUOnRegister2001, PPUOnRegister2002, PPUOnRegister2003, PPUOnRegister2004, PPUOnRegister2005, PPUOnRegister2006, PPUOnRegister2007 }; - ppu_reg_read_func = new Action[8] { PPURead2000, PPURead2001, PPURead2002, PPURead2003, PPURead2004, PPURead2005, PPURead2006, PPURead2007 }; - ppu_bkg_fetches = new Action[8] { PPUBKFetch0, PPUBKFetch1, PPUBKFetch2, PPUBKFetch3, PPUBKFetch4, PPUBKFetch5, PPUBKFetch6, PPUBKFetch7 }; - ppu_spr_fetches = new Action[8] { PPUBKFetch0, PPUBKFetch1, PPUBKFetch2, PPUBKFetch3, PPUSPRFetch0, PPUSPRFetch1, PPUSPRFetch2, PPUSPRFetch3 }; - ppu_oam_phases = new Action[9] { PPUOamPhase0, PPUOamPhase1, PPUOamPhase2, PPUOamPhase3, PPUOamPhase4, PPUOamPhase5, PPUOamPhase6, PPUOamPhase7, PPUOamPhase8 }; - ppu_h_clocks = new Action[341]; - ppu_h_clocks[0] = PPUHClock_000_Idle; - for (int i = 1; i < 257; i++) - { - ppu_h_clocks[i] = PPUHClock_1_256_BKGClocks; - } - for (int j = 257; j < 321; j++) - { - ppu_h_clocks[j] = PPUHClock_257_320_SPRClocks; - } - for (int k = 321; k < 337; k++) - { - ppu_h_clocks[k] = PPUHClock_321_336_DUMClocks; - } - for (int l = 337; l < 341; l++) - { - ppu_h_clocks[l] = PPUHClock_337_340_DUMClocks; - } - ppu_v_clocks = new Action[320]; - for (int m = 0; m < 240; m++) - { - ppu_v_clocks[m] = PPUScanlineRender; - } - ppu_v_clocks[240] = PPUScanlineVBLANK; - ppu_oam_bank = new byte[256]; - ppu_oam_bank_secondary = new byte[32]; - ppu_palette_bank = new byte[32]; - ppu_bkg_pixels = new int[512]; - ppu_spr_pixels = new int[512]; - ppu_screen_pixels = new int[61440]; - ppu_palette = NTSCPaletteGenerator.GeneratePalette(); - } - - private static void PPUHardReset() - { - ppu_reg_2001_grayscale = 243; - switch (Region) - { - case EmuRegion.NTSC: - ppu_clock_vblank_start = 241; - ppu_clock_vblank_end = 261; - ppu_use_odd_cycle = true; - break; - case EmuRegion.PALB: - ppu_clock_vblank_start = 241; - ppu_clock_vblank_end = 311; - ppu_use_odd_cycle = false; - break; - case EmuRegion.DENDY: - { - ppu_clock_vblank_start = 291; - ppu_clock_vblank_end = 311; - for (int i = 241; i <= 290; i++) - { - ppu_v_clocks[i] = PPUScanlineVBLANK; - } - ppu_use_odd_cycle = false; - break; - } - } - ppu_v_clocks[ppu_clock_vblank_start] = PPUScanlineVBLANKStart; - for (int j = ppu_clock_vblank_start + 1; j <= ppu_clock_vblank_end - 1; j++) - { - ppu_v_clocks[j] = PPUScanlineVBLANK; - } - ppu_v_clocks[ppu_clock_vblank_end] = PPUScanlineVBLANKEnd; - ppu_oam_bank = new byte[256]; - ppu_oam_bank_secondary = new byte[32]; - PPUOamReset(); - ppu_palette_bank = new byte[32] - { - 9, 1, 0, 1, 0, 2, 2, 13, 8, 16, - 8, 36, 0, 0, 4, 44, 9, 1, 52, 3, - 0, 4, 0, 20, 8, 58, 0, 2, 0, 32, - 44, 8 - }; - ppu_reg_io_db = 0; - ppu_reg_io_addr = 0; - ppu_reg_access_happened = false; - ppu_reg_access_w = false; - ppu_reg_2000_vram_address_increament = 1; - ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites = 0; - ppu_reg_2000_background_pattern_table_address = 0; - ppu_reg_2000_Sprite_size = 0; - ppu_reg_2000_VBI = false; - ppu_reg_2001_show_background_in_leftmost_8_pixels_of_screen = false; - ppu_reg_2001_show_sprites_in_leftmost_8_pixels_of_screen = false; - ppu_reg_2001_show_background = false; - ppu_reg_2001_show_sprites = false; - ppu_reg_2001_grayscale = 63; - ppu_reg_2001_emphasis = 0; - ppu_reg_2002_SpriteOverflow = false; - ppu_reg_2002_Sprite0Hit = false; - ppu_reg_2002_VblankStartedFlag = false; - ppu_reg_2003_oam_addr = 0; - ppu_is_sprfetch = false; - ppu_use_odd_swap = false; - ppu_clock_h = 0; - ppu_clock_v = 0; - } - - private static void PPUClock() - { - mem_board.OnPPUClock(); - ppu_v_clocks[ppu_clock_v](); - ppu_clock_h++; - if (ppu_clock_h >= 341) - { - mem_board.OnPPUScanlineTick(); - if (ppu_clock_v == ppu_clock_vblank_end) - { - ppu_clock_v = 0; - ppu_frame_finished = true; - } - else - { - ppu_clock_v++; - } - ppu_clock_h -= 341; - } - if (ppu_reg_access_happened) - { - ppu_reg_access_happened = false; - ppu_reg_update_func[ppu_reg_io_addr](); - } - } - - public static int GetPixel(int x, int y) - { - return ppu_screen_pixels[y * 256 + x]; - } - - private static void PPUScanlineRender() - { - ppu_h_clocks[ppu_clock_h](); - } - - private static void PPUScanlineVBLANKStart() - { - ppu_is_nmi_time = (ppu_clock_h >= 1) & (ppu_clock_h <= 3); - if (ppu_is_nmi_time) - { - if (ppu_clock_h == 1) - { - ppu_reg_2002_VblankStartedFlag = true; - } - PPU_NMI_Current = ppu_reg_2002_VblankStartedFlag & ppu_reg_2000_VBI; - } - } - - private static void PPUScanlineVBLANKEnd() - { - ppu_is_nmi_time = (ppu_clock_h >= 1) & (ppu_clock_h <= 3); - if (ppu_clock_h == 1) - { - ppu_reg_2002_Sprite0Hit = false; - ppu_reg_2002_VblankStartedFlag = false; - ppu_reg_2002_SpriteOverflow = false; - } - PPUScanlineRender(); - if (ppu_use_odd_cycle && ppu_clock_h == 339) - { - ppu_use_odd_swap = !ppu_use_odd_swap; - if (!ppu_use_odd_swap & (ppu_reg_2001_show_background || ppu_reg_2001_show_sprites)) - { - ppu_odd_swap_done = true; - ppu_clock_h++; - } - } - } - - private static void PPUScanlineVBLANK() - { - } - - private static void PPUHClock_000_Idle() - { - if (ppu_odd_swap_done) - { - ppu_bkg_fetches[1](); - ppu_odd_swap_done = false; - } - } - - private static void PPUHClock_1_256_BKGClocks() - { - if (ppu_reg_2001_show_background || ppu_reg_2001_show_sprites) - { - if (ppu_clock_v != ppu_clock_vblank_end) - { - if (ppu_clock_h > 0 && ppu_clock_h < 65) - { - ppu_oam_bank_secondary[(ppu_clock_h - 1) & 0x1F] = byte.MaxValue; - } - else - { - if (ppu_clock_h == 65) - { - PPUOamReset(); - } - if (((ppu_clock_h - 1) & 1) == 0) - { - PPUOamEvFetch(); - } - else - { - ppu_oam_phases[ppu_phase_index](); - } - if (ppu_clock_h == 256) - { - PPUOamClear(); - } - } - } - ppu_bkg_fetches[(ppu_clock_h - 1) & 7](); - if (ppu_clock_v < 240) - { - RenderPixel(); - } - } - else - { - if (ppu_clock_v >= 240) - { - return; - } - if ((ppu_vram_addr & 0x3F00) == 16128) - { - if ((ppu_vram_addr & 3) == 0) - { - ppu_screen_pixels[ppu_clock_h - 1 + ppu_clock_v * 256] = ppu_palette[(ppu_palette_bank[ppu_vram_addr & 0xC] & ppu_reg_2001_grayscale) | ppu_reg_2001_emphasis]; - } - else - { - ppu_screen_pixels[ppu_clock_h - 1 + ppu_clock_v * 256] = ppu_palette[(ppu_palette_bank[ppu_vram_addr & 0x1F] & ppu_reg_2001_grayscale) | ppu_reg_2001_emphasis]; - } - } - else - { - ppu_screen_pixels[ppu_clock_h - 1 + ppu_clock_v * 256] = ppu_palette[(ppu_palette_bank[0] & ppu_reg_2001_grayscale) | ppu_reg_2001_emphasis]; - } - } - } - - private static void PPUHClock_257_320_SPRClocks() - { - if (ppu_reg_2001_show_background || ppu_reg_2001_show_sprites) - { - ppu_spr_fetches[(ppu_clock_h - 1) & 7](); - if (ppu_clock_h == 257) - { - ppu_vram_addr = (ushort)((ppu_vram_addr & 0x7BE0u) | (ppu_vram_addr_temp & 0x41Fu)); - } - if (ppu_clock_v == ppu_clock_vblank_end && ppu_clock_h >= 280 && ppu_clock_h <= 304) - { - ppu_vram_addr = (ushort)((ppu_vram_addr & 0x41Fu) | (ppu_vram_addr_temp & 0x7BE0u)); - } - } - } - - private static void PPUHClock_321_336_DUMClocks() - { - if (ppu_reg_2001_show_background || ppu_reg_2001_show_sprites) - { - ppu_bkg_fetches[(ppu_clock_h - 1) & 7](); - } - } - - private static void PPUHClock_337_340_DUMClocks() - { - if (ppu_reg_2001_show_background || ppu_reg_2001_show_sprites) - { - ppu_bkg_fetches[(ppu_clock_h - 1) & 1](); - } - } - - private static void PPUBKFetch0() - { - ppu_bkgfetch_nt_addr = (ushort)(0x2000u | (ppu_vram_addr & 0xFFFu)); - mem_board.OnPPUAddressUpdate(ref ppu_bkgfetch_nt_addr); - } - - private static void PPUBKFetch1() - { - mem_board.ReadNMT(ref ppu_bkgfetch_nt_addr, out ppu_bkgfetch_nt_data); - } - - private static void PPUBKFetch2() - { - ppu_bkgfetch_at_addr = (ushort)(0x23C0u | (ppu_vram_addr & 0xC00u) | ((uint)(ppu_vram_addr >> 4) & 0x38u) | ((uint)(ppu_vram_addr >> 2) & 7u)); - mem_board.OnPPUAddressUpdate(ref ppu_bkgfetch_at_addr); - } - - private static void PPUBKFetch3() - { - mem_board.ReadNMT(ref ppu_bkgfetch_at_addr, out ppu_bkgfetch_at_data); - ppu_bkgfetch_at_data = (byte)(ppu_bkgfetch_at_data >> (((ppu_vram_addr >> 4) & 4) | (ppu_vram_addr & 2))); - } - - private static void PPUBKFetch4() - { - ppu_bkgfetch_lb_addr = (ushort)((uint)(ppu_reg_2000_background_pattern_table_address | (ppu_bkgfetch_nt_data << 4)) | ((uint)(ppu_vram_addr >> 12) & 7u)); - mem_board.OnPPUAddressUpdate(ref ppu_bkgfetch_lb_addr); - } - - private static void PPUBKFetch5() - { - mem_board.ReadCHR(ref ppu_bkgfetch_lb_addr, out ppu_bkgfetch_lb_data); - } - - private static void PPUBKFetch6() - { - ppu_bkgfetch_hb_addr = (ushort)((uint)(ppu_reg_2000_background_pattern_table_address | (ppu_bkgfetch_nt_data << 4)) | 8u | ((uint)(ppu_vram_addr >> 12) & 7u)); - mem_board.OnPPUAddressUpdate(ref ppu_bkgfetch_hb_addr); - } - - private static void PPUBKFetch7() - { - mem_board.ReadCHR(ref ppu_bkgfetch_hb_addr, out ppu_bkgfetch_hb_data); - ppu_bkg_render_pos = ppu_clock_h + 8; - ppu_bkg_render_pos %= 336; - if (ppu_clock_h == 256) - { - if ((ppu_vram_addr & 0x7000) != 28672) - { - ppu_vram_addr += 4096; - } - else - { - ppu_vram_addr ^= 28672; - switch (ppu_vram_addr & 0x3E0) - { - case 928: - ppu_vram_addr ^= 2976; - break; - case 992: - ppu_vram_addr ^= 992; - break; - default: - ppu_vram_addr += 32; - break; - } - } - } - else if ((ppu_vram_addr & 0x1F) == 31) - { - ppu_vram_addr ^= 1055; - } - else - { - ppu_vram_addr++; - } - for (ppu_bkg_render_i = 0; ppu_bkg_render_i < 8; ppu_bkg_render_i++) - { - ppu_bkg_render_tmp_val = ((ppu_bkgfetch_at_data << 2) & 0xC) | ((ppu_bkgfetch_lb_data >> 7) & 1) | ((ppu_bkgfetch_hb_data >> 6) & 2); - ppu_bkg_pixels[ppu_bkg_render_i + ppu_bkg_render_pos] = ppu_bkg_render_tmp_val; - ppu_bkgfetch_lb_data <<= 1; - ppu_bkgfetch_hb_data <<= 1; - } - } - - private static void PPUSPRFetch0() - { - ppu_sprfetch_slot = (ppu_clock_h - 1 >> 3) & 7; - ppu_sprfetch_slot = 7 - ppu_sprfetch_slot; - ppu_sprfetch_y_data = ppu_oam_bank_secondary[ppu_sprfetch_slot * 4]; - ppu_sprfetch_t_data = ppu_oam_bank_secondary[ppu_sprfetch_slot * 4 + 1]; - ppu_sprfetch_at_data = ppu_oam_bank_secondary[ppu_sprfetch_slot * 4 + 2]; - ppu_sprfetch_x_data = ppu_oam_bank_secondary[ppu_sprfetch_slot * 4 + 3]; - ppu_temp_comparator = (ppu_clock_v - ppu_sprfetch_y_data) ^ (((ppu_sprfetch_at_data & 0x80u) != 0) ? 15 : 0); - if (ppu_reg_2000_Sprite_size == 16) - { - ppu_sprfetch_lb_addr = (ushort)(((uint)(ppu_sprfetch_t_data << 12) & 0x1000u) | ((uint)(ppu_sprfetch_t_data << 4) & 0xFE0u) | ((uint)(ppu_temp_comparator << 1) & 0x10u) | ((uint)ppu_temp_comparator & 7u)); - } - else - { - ppu_sprfetch_lb_addr = (ushort)((uint)(ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites | (ppu_sprfetch_t_data << 4)) | ((uint)ppu_temp_comparator & 7u)); - } - mem_board.OnPPUAddressUpdate(ref ppu_sprfetch_lb_addr); - } - - private static void PPUSPRFetch1() - { - ppu_is_sprfetch = true; - mem_board.ReadCHR(ref ppu_sprfetch_lb_addr, out ppu_sprfetch_lb_data); - ppu_is_sprfetch = false; - if ((ppu_sprfetch_at_data & 0x40u) != 0) - { - ppu_sprfetch_lb_data = reverseLookup[ppu_sprfetch_lb_data]; - } - } - - private static void PPUSPRFetch2() - { - ppu_sprfetch_hb_addr = (ushort)(ppu_sprfetch_lb_addr | 8u); - mem_board.OnPPUAddressUpdate(ref ppu_sprfetch_hb_addr); - } - - private static void PPUSPRFetch3() - { - ppu_is_sprfetch = true; - mem_board.ReadCHR(ref ppu_sprfetch_hb_addr, out ppu_sprfetch_hb_data); - ppu_is_sprfetch = false; - if ((ppu_sprfetch_at_data & 0x40u) != 0) - { - ppu_sprfetch_hb_data = reverseLookup[ppu_sprfetch_hb_data]; - } - if (ppu_sprfetch_x_data == byte.MaxValue) - { - return; - } - for (ppu_bkg_render_i = 0; ppu_bkg_render_i < 8; ppu_bkg_render_i++) - { - if (ppu_sprfetch_x_data < byte.MaxValue) - { - ppu_bkg_render_tmp_val = ((ppu_sprfetch_at_data << 2) & 0xC) | ((ppu_sprfetch_lb_data >> 7) & 1) | ((ppu_sprfetch_hb_data >> 6) & 2); - if (((uint)ppu_bkg_render_tmp_val & 3u) != 0) - { - ppu_spr_pixels[ppu_sprfetch_x_data] = ppu_bkg_render_tmp_val; - if (ppu_sprfetch_slot == 0 && ppu_sprite0_should_hit) - { - ppu_spr_pixels[ppu_sprfetch_x_data] |= 16384; - } - if ((ppu_sprfetch_at_data & 0x20) == 0) - { - ppu_spr_pixels[ppu_sprfetch_x_data] |= 32768; - } - } - ppu_sprfetch_lb_data <<= 1; - ppu_sprfetch_hb_data <<= 1; - ppu_sprfetch_x_data++; - } - } - } - - private static void PPUOamReset() - { - ppu_oamev_n = 0; - ppu_oamev_m = 0; - ppu_oamev_slot = 0; - ppu_phase_index = 0; - ppu_sprite0_should_hit = false; - } - - private static void PPUOamClear() - { - for (int i = 0; i < ppu_spr_pixels.Length; i++) - { - ppu_spr_pixels[i] = 0; - } - } - - private static void PPUOamEvFetch() - { - ppu_fetch_data = ppu_oam_bank[ppu_oamev_n * 4 + ppu_oamev_m]; - } - - private static void PPUOamPhase0() - { - ppu_oamev_compare = ppu_clock_v >= ppu_fetch_data && ppu_clock_v < ppu_fetch_data + ppu_reg_2000_Sprite_size; - if (ppu_oamev_compare) - { - ppu_oam_bank_secondary[ppu_oamev_slot * 4] = ppu_fetch_data; - ppu_oamev_m = 1; - ppu_phase_index++; - if (ppu_oamev_n == 0) - { - ppu_sprite0_should_hit = true; - } - } - else - { - ppu_oamev_m = 0; - ppu_oamev_n++; - if (ppu_oamev_n == 64) - { - ppu_oamev_n = 0; - ppu_phase_index = 8; - } - } - } - - private static void PPUOamPhase1() - { - ppu_oam_bank_secondary[ppu_oamev_slot * 4 + ppu_oamev_m] = ppu_fetch_data; - ppu_oamev_m = 2; - ppu_phase_index++; - } - - private static void PPUOamPhase2() - { - ppu_oam_bank_secondary[ppu_oamev_slot * 4 + ppu_oamev_m] = ppu_fetch_data; - ppu_oamev_m = 3; - ppu_phase_index++; - } - - private static void PPUOamPhase3() - { - ppu_oam_bank_secondary[ppu_oamev_slot * 4 + ppu_oamev_m] = ppu_fetch_data; - ppu_oamev_m = 0; - ppu_oamev_n++; - ppu_oamev_slot++; - if (ppu_oamev_n == 64) - { - ppu_oamev_n = 0; - ppu_phase_index = 8; - } - else if (ppu_oamev_slot < 8) - { - ppu_phase_index = 0; - } - else if (ppu_oamev_slot == 8) - { - ppu_phase_index = 4; - } - } - - private static void PPUOamPhase4() - { - ppu_oamev_compare = ppu_clock_v >= ppu_fetch_data && ppu_clock_v < ppu_fetch_data + ppu_reg_2000_Sprite_size; - if (ppu_oamev_compare) - { - ppu_oamev_m = 1; - ppu_phase_index++; - ppu_reg_2002_SpriteOverflow = true; - return; - } - ppu_oamev_m++; - if (ppu_oamev_m == 4) - { - ppu_oamev_m = 0; - } - ppu_oamev_n++; - if (ppu_oamev_n == 64) - { - ppu_oamev_n = 0; - ppu_phase_index = 8; - } - else - { - ppu_phase_index = 4; - } - } - - private static void PPUOamPhase5() - { - ppu_oamev_m = 2; - ppu_phase_index++; - } - - private static void PPUOamPhase6() - { - ppu_oamev_m = 3; - ppu_phase_index++; - } - - private static void PPUOamPhase7() - { - ppu_oamev_m = 0; - ppu_oamev_n++; - if (ppu_oamev_n == 64) - { - ppu_oamev_n = 0; - } - ppu_phase_index = 8; - } - - private static void PPUOamPhase8() - { - ppu_oamev_n++; - if (ppu_oamev_n >= 64) - { - ppu_oamev_n = 0; - } - } - - private static void RenderPixel() - { - if (ppu_clock_v == ppu_clock_vblank_end) - { - return; - } - ppu_render_x = ppu_clock_h - 1; - ppu_render_y = ppu_clock_v * 256; - if (ppu_render_x < 8) - { - if (ppu_reg_2001_show_background_in_leftmost_8_pixels_of_screen) - { - ppu_bkg_current_pixel = 0x3F00 | ppu_bkg_pixels[ppu_render_x + ppu_vram_finex]; - } - else - { - ppu_bkg_current_pixel = 16128; - } - if (ppu_reg_2001_show_sprites_in_leftmost_8_pixels_of_screen) - { - ppu_spr_current_pixel = 0x3F10 | ppu_spr_pixels[ppu_render_x]; - } - else - { - ppu_spr_current_pixel = 16144; - } - } - else - { - if (!ppu_reg_2001_show_background) - { - ppu_bkg_current_pixel = 16128; - } - else - { - ppu_bkg_current_pixel = 0x3F00 | ppu_bkg_pixels[ppu_render_x + ppu_vram_finex]; - } - if (!ppu_reg_2001_show_sprites || ppu_clock_v == 0) - { - ppu_spr_current_pixel = 16144; - } - else - { - ppu_spr_current_pixel = 0x3F10 | ppu_spr_pixels[ppu_render_x]; - } - } - ppu_current_pixel = 0; - if (((uint)ppu_spr_current_pixel & 0x8000u) != 0) - { - ppu_current_pixel = ppu_spr_current_pixel; - } - else - { - ppu_current_pixel = ppu_bkg_current_pixel; - } - if ((ppu_bkg_current_pixel & 3) == 0) - { - ppu_current_pixel = ppu_spr_current_pixel; - } - else if ((ppu_spr_current_pixel & 3) == 0) - { - ppu_current_pixel = ppu_bkg_current_pixel; - } - else if (((uint)ppu_spr_pixels[ppu_render_x] & 0x4000u) != 0) - { - ppu_reg_2002_Sprite0Hit = true; - } - if ((ppu_current_pixel & 3) == 0) - { - ppu_screen_pixels[ppu_render_x + ppu_render_y] = ppu_palette[(ppu_palette_bank[ppu_current_pixel & 0xC] & ppu_reg_2001_grayscale) | ppu_reg_2001_emphasis]; - } - else - { - ppu_screen_pixels[ppu_render_x + ppu_render_y] = ppu_palette[(ppu_palette_bank[ppu_current_pixel & 0x1F] & ppu_reg_2001_grayscale) | ppu_reg_2001_emphasis]; - } - } - - private static void PPUIORead(ref ushort addr, out byte value) - { - ppu_reg_io_addr = (byte)(addr & 7u); - ppu_reg_access_happened = true; - ppu_reg_access_w = false; - ppu_reg_read_func[ppu_reg_io_addr](); - value = ppu_reg_io_db; - } - - private static void PPUIOWrite(ref ushort addr, ref byte value) - { - ppu_reg_io_addr = (byte)(addr & 7u); - ppu_reg_io_db = value; - ppu_reg_access_w = true; - ppu_reg_access_happened = true; - } - - private static void PPUOnRegister2000() - { - if (ppu_reg_access_w) - { - ppu_vram_addr_temp = (ushort)((ppu_vram_addr_temp & 0x73FFu) | (uint)((ppu_reg_io_db & 3) << 10)); - if ((ppu_reg_io_db & 4u) != 0) - { - ppu_reg_2000_vram_address_increament = 32; - } - else - { - ppu_reg_2000_vram_address_increament = 1; - } - if ((ppu_reg_io_db & 8u) != 0) - { - ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites = 4096; - } - else - { - ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites = 0; - } - if ((ppu_reg_io_db & 0x10u) != 0) - { - ppu_reg_2000_background_pattern_table_address = 4096; - } - else - { - ppu_reg_2000_background_pattern_table_address = 0; - } - if ((ppu_reg_io_db & 0x20u) != 0) - { - ppu_reg_2000_Sprite_size = 16; - } - else - { - ppu_reg_2000_Sprite_size = 8; - } - if (!ppu_reg_2000_VBI && (ppu_reg_io_db & 0x80u) != 0 && ppu_reg_2002_VblankStartedFlag) - { - PPU_NMI_Current = true; - } - ppu_reg_2000_VBI = (ppu_reg_io_db & 0x80) != 0; - if (!ppu_reg_2000_VBI && ppu_is_nmi_time) - { - PPU_NMI_Current = false; - } - } - } - - private static void PPUOnRegister2001() - { - if (ppu_reg_access_w) - { - ppu_reg_2001_show_background_in_leftmost_8_pixels_of_screen = (ppu_reg_io_db & 2) != 0; - ppu_reg_2001_show_sprites_in_leftmost_8_pixels_of_screen = (ppu_reg_io_db & 4) != 0; - ppu_reg_2001_show_background = (ppu_reg_io_db & 8) != 0; - ppu_reg_2001_show_sprites = (ppu_reg_io_db & 0x10) != 0; - ppu_reg_2001_grayscale = ((((uint)ppu_reg_io_db & (true ? 1u : 0u)) != 0) ? 48 : 63); - ppu_reg_2001_emphasis = (ppu_reg_io_db & 0xE0) << 1; - } - } - - private static void PPUOnRegister2002() - { - if (!ppu_reg_access_w) - { - ppu_vram_flip_flop = false; - ppu_reg_2002_VblankStartedFlag = false; - if (ppu_clock_v == ppu_clock_vblank_start) - { - PPU_NMI_Current = ppu_reg_2002_VblankStartedFlag & ppu_reg_2000_VBI; - } - } - } - - private static void PPUOnRegister2003() - { - if (ppu_reg_access_w) - { - ppu_reg_2003_oam_addr = ppu_reg_io_db; - } - } - - private static void PPUOnRegister2004() - { - if (ppu_reg_access_w) - { - if (ppu_clock_v < 240 && IsRenderingOn()) - { - ppu_reg_io_db = byte.MaxValue; - } - if ((ppu_reg_2003_oam_addr & 3) == 2) - { - ppu_reg_io_db &= 227; - } - ppu_oam_bank[ppu_reg_2003_oam_addr] = ppu_reg_io_db; - ppu_reg_2003_oam_addr = (byte)((uint)(ppu_reg_2003_oam_addr + 1) & 0xFFu); - } - } - - private static void PPUOnRegister2005() - { - if (ppu_reg_access_w) - { - if (!ppu_vram_flip_flop) - { - ppu_vram_addr_temp = (ushort)((ppu_vram_addr_temp & 0x7FE0u) | (uint)((ppu_reg_io_db & 0xF8) >> 3)); - ppu_vram_finex = (byte)(ppu_reg_io_db & 7u); - } - else - { - ppu_vram_addr_temp = (ushort)((ppu_vram_addr_temp & 0xC1Fu) | (uint)((ppu_reg_io_db & 7) << 12) | (uint)((ppu_reg_io_db & 0xF8) << 2)); - } - ppu_vram_flip_flop = !ppu_vram_flip_flop; - } - } - - private static void PPUOnRegister2006() - { - if (ppu_reg_access_w) - { - if (!ppu_vram_flip_flop) - { - ppu_vram_addr_temp = (ushort)((ppu_vram_addr_temp & 0xFFu) | (uint)((ppu_reg_io_db & 0x3F) << 8)); - } - else - { - ppu_vram_addr_temp = (ushort)((ppu_vram_addr_temp & 0x7F00u) | ppu_reg_io_db); - ppu_vram_addr = ppu_vram_addr_temp; - mem_board.OnPPUAddressUpdate(ref ppu_vram_addr); - } - ppu_vram_flip_flop = !ppu_vram_flip_flop; - } - } - - private static void PPUOnRegister2007() - { - if (ppu_reg_access_w) - { - ppu_vram_addr_access_temp = (ushort)(ppu_vram_addr & 0x3FFFu); - if (ppu_vram_addr_access_temp < 8192) - { - mem_board.WriteCHR(ref ppu_vram_addr_access_temp, ref ppu_reg_io_db); - } - else if (ppu_vram_addr_access_temp < 16128) - { - mem_board.WriteNMT(ref ppu_vram_addr_access_temp, ref ppu_reg_io_db); - } - else if ((ppu_vram_addr_access_temp & 3u) != 0) - { - ppu_palette_bank[ppu_vram_addr_access_temp & 0x1F] = ppu_reg_io_db; - } - else - { - ppu_palette_bank[ppu_vram_addr_access_temp & 0xC] = ppu_reg_io_db; - } - } - else - { - if ((ppu_vram_addr & 0x3F00) == 16128) - { - ppu_vram_addr_access_temp = (ushort)(ppu_vram_addr & 0x2FFFu); - } - else - { - ppu_vram_addr_access_temp = (ushort)(ppu_vram_addr & 0x3FFFu); - } - if (ppu_vram_addr_access_temp < 8192) - { - mem_board.ReadCHR(ref ppu_vram_addr_access_temp, out ppu_vram_data); - } - else if (ppu_vram_addr_access_temp < 16128) - { - mem_board.ReadNMT(ref ppu_vram_addr_access_temp, out ppu_vram_data); - } - } - ppu_vram_addr = (ushort)((uint)(ppu_vram_addr + ppu_reg_2000_vram_address_increament) & 0x7FFFu); - mem_board.OnPPUAddressUpdate(ref ppu_vram_addr); - } - - private static void PPURead2000() - { - } - - private static void PPURead2001() - { - } - - private static void PPURead2002() - { - ppu_reg_io_db = (byte)((ppu_reg_io_db & 0xDFu) | (ppu_reg_2002_SpriteOverflow ? 32u : 0u)); - ppu_reg_io_db = (byte)((ppu_reg_io_db & 0xBFu) | (ppu_reg_2002_Sprite0Hit ? 64u : 0u)); - ppu_reg_io_db = (byte)((ppu_reg_io_db & 0x7Fu) | (ppu_reg_2002_VblankStartedFlag ? 128u : 0u)); - } - - private static void PPURead2003() - { - } - - private static void PPURead2004() - { - ppu_reg_io_db = ppu_oam_bank[ppu_reg_2003_oam_addr]; - if (ppu_clock_v < 240 && IsRenderingOn()) - { - if (ppu_clock_h < 64) - { - ppu_reg_io_db = byte.MaxValue; - } - else if (ppu_clock_h < 192) - { - ppu_reg_io_db = ppu_oam_bank[(ppu_clock_h - 64 << 1) & 0xFC]; - } - else if (ppu_clock_h < 256) - { - ppu_reg_io_db = (((ppu_clock_h & 1) == 1) ? ppu_oam_bank[252] : ppu_oam_bank[(ppu_clock_h - 192 << 1) & 0xFC]); - } - else if (ppu_clock_h < 320) - { - ppu_reg_io_db = byte.MaxValue; - } - else - { - ppu_reg_io_db = ppu_oam_bank[0]; - } - } - } - - private static void PPURead2005() - { - } - - private static void PPURead2006() - { - } - - private static void PPURead2007() - { - ppu_vram_addr_access_temp = (ushort)(ppu_vram_addr & 0x3FFFu); - if (ppu_vram_addr_access_temp < 16128) - { - ppu_reg_io_db = ppu_vram_data; - } - else if ((ppu_vram_addr_access_temp & 3u) != 0) - { - ppu_reg_io_db = ppu_palette_bank[ppu_vram_addr_access_temp & 0x1F]; - } - else - { - ppu_reg_io_db = ppu_palette_bank[ppu_vram_addr_access_temp & 0xC]; - } - } - - internal static bool IsRenderingOn() - { - if (!ppu_reg_2001_show_background) - { - return ppu_reg_2001_show_sprites; - } - return true; - } - - internal static bool IsInRender() - { - if (ppu_clock_v >= 240) - { - return ppu_clock_v == ppu_clock_vblank_end; - } - return true; - } - - private static void PPUWriteState(ref BinaryWriter bin) - { - bin.Write(ppu_clock_h); - bin.Write(ppu_clock_v); - bin.Write(ppu_clock_vblank_start); - bin.Write(ppu_clock_vblank_end); - bin.Write(ppu_use_odd_cycle); - bin.Write(ppu_use_odd_swap); - bin.Write(ppu_is_nmi_time); - bin.Write(ppu_frame_finished); - bin.Write(ppu_oam_bank); - bin.Write(ppu_oam_bank_secondary); - bin.Write(ppu_palette_bank); - bin.Write(ppu_reg_io_db); - bin.Write(ppu_reg_io_addr); - bin.Write(ppu_reg_access_happened); - bin.Write(ppu_reg_access_w); - bin.Write(ppu_reg_2000_vram_address_increament); - bin.Write(ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites); - bin.Write(ppu_reg_2000_background_pattern_table_address); - bin.Write(ppu_reg_2000_Sprite_size); - bin.Write(ppu_reg_2000_VBI); - bin.Write(ppu_reg_2001_show_background_in_leftmost_8_pixels_of_screen); - bin.Write(ppu_reg_2001_show_sprites_in_leftmost_8_pixels_of_screen); - bin.Write(ppu_reg_2001_show_background); - bin.Write(ppu_reg_2001_show_sprites); - bin.Write(ppu_reg_2001_grayscale); - bin.Write(ppu_reg_2001_emphasis); - bin.Write(ppu_reg_2002_SpriteOverflow); - bin.Write(ppu_reg_2002_Sprite0Hit); - bin.Write(ppu_reg_2002_VblankStartedFlag); - bin.Write(ppu_reg_2003_oam_addr); - bin.Write(ppu_vram_addr); - bin.Write(ppu_vram_data); - bin.Write(ppu_vram_addr_temp); - bin.Write(ppu_vram_addr_access_temp); - bin.Write(ppu_vram_flip_flop); - bin.Write(ppu_vram_finex); - bin.Write(ppu_bkgfetch_nt_addr); - bin.Write(ppu_bkgfetch_nt_data); - bin.Write(ppu_bkgfetch_at_addr); - bin.Write(ppu_bkgfetch_at_data); - bin.Write(ppu_bkgfetch_lb_addr); - bin.Write(ppu_bkgfetch_lb_data); - bin.Write(ppu_bkgfetch_hb_addr); - bin.Write(ppu_bkgfetch_hb_data); - bin.Write(ppu_sprfetch_slot); - bin.Write(ppu_sprfetch_y_data); - bin.Write(ppu_sprfetch_t_data); - bin.Write(ppu_sprfetch_at_data); - bin.Write(ppu_sprfetch_x_data); - bin.Write(ppu_sprfetch_lb_addr); - bin.Write(ppu_sprfetch_lb_data); - bin.Write(ppu_sprfetch_hb_addr); - bin.Write(ppu_sprfetch_hb_data); - bin.Write(ppu_bkg_render_i); - bin.Write(ppu_bkg_render_pos); - bin.Write(ppu_bkg_render_tmp_val); - bin.Write(ppu_bkg_current_pixel); - bin.Write(ppu_spr_current_pixel); - bin.Write(ppu_current_pixel); - bin.Write(ppu_render_x); - bin.Write(0); - bin.Write(ppu_oamev_n); - bin.Write(ppu_oamev_m); - bin.Write(ppu_oamev_compare); - bin.Write(ppu_oamev_slot); - bin.Write(ppu_fetch_data); - bin.Write(ppu_phase_index); - bin.Write(ppu_sprite0_should_hit); - } - - private static void PPUReadState(ref BinaryReader bin) - { - ppu_clock_h = bin.ReadInt32(); - ppu_clock_v = bin.ReadUInt16(); - ppu_clock_vblank_start = bin.ReadUInt16(); - ppu_clock_vblank_end = bin.ReadUInt16(); - ppu_use_odd_cycle = bin.ReadBoolean(); - ppu_use_odd_swap = bin.ReadBoolean(); - ppu_is_nmi_time = bin.ReadBoolean(); - ppu_frame_finished = bin.ReadBoolean(); - bin.Read(ppu_oam_bank, 0, ppu_oam_bank.Length); - bin.Read(ppu_oam_bank_secondary, 0, ppu_oam_bank_secondary.Length); - bin.Read(ppu_palette_bank, 0, ppu_palette_bank.Length); - ppu_reg_io_db = bin.ReadByte(); - ppu_reg_io_addr = bin.ReadByte(); - ppu_reg_access_happened = bin.ReadBoolean(); - ppu_reg_access_w = bin.ReadBoolean(); - ppu_reg_2000_vram_address_increament = bin.ReadByte(); - ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites = bin.ReadUInt16(); - ppu_reg_2000_background_pattern_table_address = bin.ReadUInt16(); - ppu_reg_2000_Sprite_size = bin.ReadByte(); - ppu_reg_2000_VBI = bin.ReadBoolean(); - ppu_reg_2001_show_background_in_leftmost_8_pixels_of_screen = bin.ReadBoolean(); - ppu_reg_2001_show_sprites_in_leftmost_8_pixels_of_screen = bin.ReadBoolean(); - ppu_reg_2001_show_background = bin.ReadBoolean(); - ppu_reg_2001_show_sprites = bin.ReadBoolean(); - ppu_reg_2001_grayscale = bin.ReadInt32(); - ppu_reg_2001_emphasis = bin.ReadInt32(); - ppu_reg_2002_SpriteOverflow = bin.ReadBoolean(); - ppu_reg_2002_Sprite0Hit = bin.ReadBoolean(); - ppu_reg_2002_VblankStartedFlag = bin.ReadBoolean(); - ppu_reg_2003_oam_addr = bin.ReadByte(); - ppu_vram_addr = bin.ReadUInt16(); - ppu_vram_data = bin.ReadByte(); - ppu_vram_addr_temp = bin.ReadUInt16(); - ppu_vram_addr_access_temp = bin.ReadUInt16(); - ppu_vram_flip_flop = bin.ReadBoolean(); - ppu_vram_finex = bin.ReadByte(); - ppu_bkgfetch_nt_addr = bin.ReadUInt16(); - ppu_bkgfetch_nt_data = bin.ReadByte(); - ppu_bkgfetch_at_addr = bin.ReadUInt16(); - ppu_bkgfetch_at_data = bin.ReadByte(); - ppu_bkgfetch_lb_addr = bin.ReadUInt16(); - ppu_bkgfetch_lb_data = bin.ReadByte(); - ppu_bkgfetch_hb_addr = bin.ReadUInt16(); - ppu_bkgfetch_hb_data = bin.ReadByte(); - ppu_sprfetch_slot = bin.ReadInt32(); - ppu_sprfetch_y_data = bin.ReadByte(); - ppu_sprfetch_t_data = bin.ReadByte(); - ppu_sprfetch_at_data = bin.ReadByte(); - ppu_sprfetch_x_data = bin.ReadByte(); - ppu_sprfetch_lb_addr = bin.ReadUInt16(); - ppu_sprfetch_lb_data = bin.ReadByte(); - ppu_sprfetch_hb_addr = bin.ReadUInt16(); - ppu_sprfetch_hb_data = bin.ReadByte(); - ppu_bkg_render_i = bin.ReadInt32(); - ppu_bkg_render_pos = bin.ReadInt32(); - ppu_bkg_render_tmp_val = bin.ReadInt32(); - ppu_bkg_current_pixel = bin.ReadInt32(); - ppu_spr_current_pixel = bin.ReadInt32(); - ppu_current_pixel = bin.ReadInt32(); - ppu_render_x = bin.ReadInt32(); - bin.ReadInt32(); - ppu_oamev_n = bin.ReadByte(); - ppu_oamev_m = bin.ReadByte(); - ppu_oamev_compare = bin.ReadBoolean(); - ppu_oamev_slot = bin.ReadByte(); - ppu_fetch_data = bin.ReadByte(); - ppu_phase_index = bin.ReadByte(); - ppu_sprite0_should_hit = bin.ReadBoolean(); - } - - internal static void CheckGame(string fileName, out bool valid) - { - string text = Path.GetExtension(fileName).ToLower(); - if (text != null && text == ".nes") - { - Tracer.WriteLine("Checking INES header ..."); - INes nes = new INes(); - nes.Load(fileName, loadDumps: false); - valid = nes.IsValid; - Tracer.WriteLine("INES header is valid."); - } - else - { - Tracer.WriteWarning("File format is not supported. Format: " + Path.GetExtension(fileName)); - valid = false; - } - } - - internal static void Initialize() - { - Tracer.WriteLine("Loading database file ..."); - string text = Path.Combine(MyNesMain.AppPath, "database.xml"); - if (File.Exists(text)) - { - bool success = false; - NesCartDatabase.LoadDatabase(text, out success); - if (success) - { - Tracer.WriteInformation("Nes Cart database file loaded successfully."); - } - else - { - Tracer.WriteError("Error loading Nes Cart database file."); - } - } - else - { - Tracer.WriteWarning("Nes Cart database file cannot be located at " + text); - } - FrameLimiterEnabled = true; - CPUInitialize(); - PPUInitialize(); - APUInitialize(); - PORTSInitialize(); - } - - internal static void SetupRenderingMethods(RenderVideoFrame renderVideo, RenderAudioSamples renderAudio, TogglePause renderTogglePause, GetIsPlaying renderGetIsPlaying) - { - render_initialized = false; - render_video = renderVideo; - render_audio = renderAudio; - render_audio_toggle_pause = renderTogglePause; - render_audio_get_is_playing = renderGetIsPlaying; - render_initialized = render_video != null && render_audio != null && render_audio_toggle_pause != null && render_audio_get_is_playing != null; - if (render_initialized) - { - Tracer.WriteInformation("Renderer methods initialized successfully."); - return; - } - Tracer.WriteError("ERROR RENDERER INITIALIZING !!"); - Tracer.WriteError("Faild to initialize the renderers methods. Please use the method 'SetupRenderingMethods' to initialize the renderers methods before you can run the emulation."); - } - - public static void LoadGame(string fileName, out bool success, bool useThread) - { - if (!render_initialized) - { - Tracer.WriteError("NO RENDERER INITIALIZED !! EMU CANNOT BE INTIALIZED WITHOUT A RENDERER !!"); - Tracer.WriteError("Please use the method 'SetupRenderingMethods' to initialize the renderers methods before you can run the emulation."); - success = false; - return; - } - string text = Path.GetExtension(fileName).ToLower(); - if (text != null && text == ".nes") - { - Tracer.WriteLine("Checking INES header ..."); - INes nes = new INes(); - nes.Load(fileName, loadDumps: true); - if (nes.IsValid) - { - emu_request_mode = RequestMode.None; - CurrentFilePath = fileName; - if (ON) - { - ShutDown(); - } - Tracer.WriteLine("INES header is valid, loading game ..."); - ApplyRegionSetting(); - MEMInitialize(nes); - ApplyAudioSettings(); - ApplyFrameSkipSettings(); - ApplyPaletteSetting(); - PORTSInitialize(); - hardReset(); - Tracer.WriteLine("EMU is ready."); - success = true; - emu_frame_clocking_mode = !useThread; - ON = true; - PAUSED = false; - if (useThread) - { - Tracer.WriteLine("Running in a thread ... using custom frame limiter."); - FrameLimiterEnabled = true; - mainThread = new Thread(EmuClock); - mainThread.Start(); - } - MyNesMain.VideoProvider.SignalToggle(started: true); - MyNesMain.AudioProvider.SignalToggle(started: true); - } - else - { - success = false; - } - } - else - { - success = false; - } - } - - public static void HardReset() - { - PAUSED = true; - emu_request_mode = RequestMode.HardReset; - } - - private static void hardReset() - { - if (MyNesMain.WaveRecorder.IsRecording) - { - MyNesMain.WaveRecorder.Stop(); - } - render_audio_toggle_pause(paused: true); - switch (Region) - { - case EmuRegion.NTSC: - emu_time_target_fps = 60.0988; - break; - case EmuRegion.PALB: - case EmuRegion.DENDY: - emu_time_target_fps = 50.0; - break; - } - fps_time_period = 1.0 / emu_time_target_fps; - MEMHardReset(); - CPUHardReset(); - PPUHardReset(); - APUHardReset(); - DMAHardReset(); - render_audio_toggle_pause(paused: false); - MyNesMain.VideoProvider.WriteWarningNotification(MNInterfaceLanguage.Message_HardReset, instant: false); - } - - public static void SoftReset() - { - PAUSED = true; - emu_request_mode = RequestMode.SoftReset; - } - - private static void softReset() - { - CPUSoftReset(); - APUSoftReset(); - MyNesMain.VideoProvider.WriteWarningNotification(MNInterfaceLanguage.Message_SoftReset, instant: false); - } - - public static void SaveState() - { - PAUSED = true; - emu_request_mode = RequestMode.SaveState; - } - - public static void LoadState() - { - PAUSED = true; - emu_request_mode = RequestMode.LoadState; - } - - internal static void TakeSnapshot() - { - PAUSED = true; - emu_request_mode = RequestMode.TakeSnapshot; - } - - public static void ShutDown() - { - MyNesMain.VideoProvider.SignalToggle(started: false); - MyNesMain.AudioProvider.SignalToggle(started: false); - if (MyNesMain.WaveRecorder.IsRecording) - { - MyNesMain.WaveRecorder.Stop(); - } - render_audio_get_is_playing(out render_audio_is_playing); - if (render_audio_is_playing) - { - render_audio_toggle_pause(paused: true); - } - Tracer.WriteLine("Shutting down the emulation core..."); - ON = false; - if (mainThread != null) - { - Tracer.WriteLine("Aborting thread .."); - while (mainThread.IsAlive) - { - } - mainThread.Abort(); - mainThread = null; - } - SaveSRAM(); - Tracer.WriteInformation("Emulation core shutdown successfully."); - NesEmu.EmuShutdown?.Invoke(null, new EventArgs()); - } - - internal static void EMUClockFrame() - { - emu_frame_done = false; - while (!emu_frame_done && ON) - { - if (!PAUSED) - { - CPUClock(); - } - else - { - Thread.Sleep(100); - } - } - } - - private static void EmuClock() - { - while (ON) - { - if (!PAUSED) - { - CPUClock(); - if (ppu_frame_finished) - { - FrameFinished(); - } - continue; - } - render_audio_get_is_playing(out render_audio_is_playing); - if (render_audio_is_playing) - { - render_audio_toggle_pause(paused: true); - } - Thread.Sleep(100); - shortucts.Update(); - switch (emu_request_mode) - { - case RequestMode.HardReset: - hardReset(); - PAUSED = false; - emu_request_mode = RequestMode.None; - break; - case RequestMode.SoftReset: - softReset(); - PAUSED = false; - emu_request_mode = RequestMode.None; - break; - case RequestMode.SaveState: - StateHandler.SaveState(); - PAUSED = false; - emu_request_mode = RequestMode.None; - break; - case RequestMode.LoadState: - StateHandler.LoadState(); - PAUSED = false; - emu_request_mode = RequestMode.None; - break; - case RequestMode.TakeSnapshot: - MyNesMain.VideoProvider.TakeSnapshot(); - PAUSED = false; - emu_request_mode = RequestMode.None; - break; - } - isPaused = true; - } - } - - internal static void EmuClockComponents() - { - PPUClock(); - PollInterruptStatus(); - PPUClock(); - PPUClock(); - APUClock(); - DMAClock(); - mem_board.OnCPUClock(); - } - - internal static void ApplyFrameSkipSettings() - { - FrameSkipEnabled = MyNesMain.RendererSettings.FrameSkipEnabled; - FrameSkipInterval = MyNesMain.RendererSettings.FrameSkipInterval; - } - - private static void FrameFinished() - { - if (!FrameSkipEnabled) - { - render_video(ref ppu_screen_pixels); - } - else - { - FrameSkipCounter++; - if (FrameSkipCounter >= FrameSkipInterval) - { - render_video(ref ppu_screen_pixels); - FrameSkipCounter = 0; - } - } - isPaused = false; - ppu_frame_finished = false; - emu_frame_done = true; - joypad1.Update(); - joypad2.Update(); - if (IsFourPlayers) - { - joypad3.Update(); - joypad4.Update(); - } - shortucts.Update(); - if (SoundEnabled) - { - render_audio_get_is_playing(out render_audio_is_playing); - if (!render_audio_is_playing) - { - render_audio_toggle_pause(paused: false); - } - render_audio(ref audio_samples, ref audio_samples_added); - audio_w_pos = 0; - audio_samples_added = 0; - audio_timer = 0.0; - } - fps_time_token = GetTime() - fps_time_start; - if (FrameLimiterEnabled) - { - if (fps_time_token > 0.0) - { - fps_time_dead = fps_time_period - fps_time_token; - if (fps_time_dead > 0.0) - { - Thread.Sleep((int)Math.Floor(fps_time_dead * 1000.0)); - fps_time_dead = GetTime() - fps_time_start; - while (fps_time_period - fps_time_dead > 0.0) - { - fps_time_dead = GetTime() - fps_time_start; - } - } - } - fps_time_last = GetTime(); - fps_time_frame_time = fps_time_last - fps_time_start; - } - fps_time_start = GetTime(); - } - - private static double GetTime() - { - return (double)Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; - } - - public static void GetSpeedValues(out double frame_time, out double immediate_frame_time) - { - frame_time = fps_time_token; - immediate_frame_time = fps_time_frame_time; - } - - public static void SetFramePeriod(ref double period) - { - fps_time_period = period; - } - - public static void ApplyRegionSetting() - { - switch ((RegionSetting)MyNesMain.EmuSettings.RegionSetting) - { - case RegionSetting.AUTO: - Tracer.WriteLine("REGION = AUTO"); - Region = EmuRegion.NTSC; - if (CurrentFilePath.Contains("(E)")) - { - Region = EmuRegion.PALB; - } - Tracer.WriteLine("REGION SELECTED: " + Region); - break; - case RegionSetting.ForceNTSC: - Tracer.WriteLine("REGION: FORCE NTSC"); - Region = EmuRegion.NTSC; - break; - case RegionSetting.ForcePALB: - Tracer.WriteLine("REGION: FORCE PALB"); - Region = EmuRegion.PALB; - break; - case RegionSetting.ForceDENDY: - Tracer.WriteLine("REGION: FORCE DENDY"); - Region = EmuRegion.DENDY; - break; - } - SystemIndex = (int)Region; - } - - public static void ApplyPaletteSetting() - { - Tracer.WriteLine("Loading palette generators values from settings..."); - NTSCPaletteGenerator.brightness = MyNesMain.RendererSettings.Palette_NTSC_brightness; - NTSCPaletteGenerator.contrast = MyNesMain.RendererSettings.Palette_NTSC_contrast; - NTSCPaletteGenerator.gamma = MyNesMain.RendererSettings.Palette_NTSC_gamma; - NTSCPaletteGenerator.hue_tweak = MyNesMain.RendererSettings.Palette_NTSC_hue_tweak; - NTSCPaletteGenerator.saturation = MyNesMain.RendererSettings.Palette_NTSC_saturation; - PALBPaletteGenerator.brightness = MyNesMain.RendererSettings.Palette_PALB_brightness; - PALBPaletteGenerator.contrast = MyNesMain.RendererSettings.Palette_PALB_contrast; - PALBPaletteGenerator.gamma = MyNesMain.RendererSettings.Palette_PALB_gamma; - PALBPaletteGenerator.hue_tweak = MyNesMain.RendererSettings.Palette_PALB_hue_tweak; - PALBPaletteGenerator.saturation = MyNesMain.RendererSettings.Palette_PALB_saturation; - Tracer.WriteLine("Setting up palette ...."); - switch ((PaletteSelectSetting)MyNesMain.RendererSettings.Palette_PaletteSetting) - { - case PaletteSelectSetting.AUTO: - Tracer.WriteLine("Palette set to auto detect depending on region."); - switch (Region) - { - case EmuRegion.NTSC: - SetupPalette(NTSCPaletteGenerator.GeneratePalette()); - Tracer.WriteLine("Region is NTSC, Palette set from NTSC generator."); - break; - case EmuRegion.PALB: - case EmuRegion.DENDY: - SetupPalette(PALBPaletteGenerator.GeneratePalette()); - Tracer.WriteLine("Region is PALB/DENDY, Palette set from PALB generator."); - break; - } - break; - case PaletteSelectSetting.ForceNTSC: - Tracer.WriteLine("Palette set to always use NTSC palette generator."); - SetupPalette(NTSCPaletteGenerator.GeneratePalette()); - Tracer.WriteLine("Palette set from NTSC generator."); - break; - case PaletteSelectSetting.ForcePALB: - Tracer.WriteLine("Palette set to always use PALB palette generator."); - SetupPalette(NTSCPaletteGenerator.GeneratePalette()); - Tracer.WriteLine("Palette set from PALB generator."); - break; - case PaletteSelectSetting.File: - { - Tracer.WriteLine("Palette set to load from file."); - string fullPath = Path.GetFullPath(MyNesMain.RendererSettings.Palette_CurrentPaletteFilePath); - if (File.Exists(fullPath)) - { - PaletteFileWrapper.LoadFile(fullPath, out var palette); - SetupPalette(palette); - Tracer.WriteLine("Palette set from file: " + fullPath); - break; - } - Tracer.WriteError("Palette file: " + fullPath + " is not exist. Setting up palette from generators."); - switch (Region) - { - case EmuRegion.NTSC: - SetupPalette(NTSCPaletteGenerator.GeneratePalette()); - Tracer.WriteLine("Region is NTSC, Palette set from NTSC generator."); - break; - case EmuRegion.PALB: - case EmuRegion.DENDY: - SetupPalette(PALBPaletteGenerator.GeneratePalette()); - Tracer.WriteLine("Region is PALB/DENDY, Palette set from PALB generator."); - break; - } - break; - } - } - } - - internal static void WriteStateData(ref BinaryWriter bin) - { - APUWriteState(ref bin); - CPUWriteState(ref bin); - DMAWriteState(ref bin); - InterruptsWriteState(ref bin); - MEMWriteState(ref bin); - PORTWriteState(ref bin); - PPUWriteState(ref bin); - } - - internal static void ReadStateData(ref BinaryReader bin) - { - APUReadState(ref bin); - CPUReadState(ref bin); - DMAReadState(ref bin); - InterruptsReadState(ref bin); - MEMReadState(ref bin); - PORTReadState(ref bin); - PPUReadState(ref bin); - } - - private static void SQ2HardReset() - { - sq2_duty_cycle = 0; - sq2_length_halt = false; - sq2_constant_volume_envelope = false; - sq2_volume_devider_period = 0; - sq2_sweep_enable = false; - sq2_sweep_devider_period = 0; - sq2_sweep_negate = false; - sq2_sweep_shift_count = 0; - sq2_timer = 0; - sq2_period_devider = 0; - sq2_seqencer = 0; - sq2_length_enabled = false; - sq2_length_counter = 0; - sq2_envelope_start_flag = false; - sq2_envelope_devider = 0; - sq2_envelope_decay_level_counter = 0; - sq2_envelope = 0; - sq2_sweep_counter = 0; - sq2_sweep_reload = false; - sq2_sweep_change = 0; - sq2_valid_freq = false; - sq2_output = 0; - sq2_ignore_reload = false; - } - - private static void SQ2SoftReset() - { - SQ2HardReset(); - } - - private static void SQ2Clock() - { - sq2_period_devider--; - if (sq2_period_devider > 0) - { - return; - } - sq2_period_devider = sq2_timer + 1; - sq2_seqencer = (byte)((uint)(sq2_seqencer + 1) & 7u); - if (sq2_length_counter > 0 && sq2_valid_freq) - { - if (audio_sq2_outputable) - { - sq2_output = sq_duty_cycle_sequences[sq2_duty_cycle][sq2_seqencer] * sq2_envelope; - } - } - else - { - sq2_output = 0; - } - audio_signal_outputed = true; - } - - private static void SQ2ClockLength() - { - if (sq2_length_counter > 0 && !sq2_length_halt) - { - sq2_length_counter--; - if (apu_reg_access_happened && apu_reg_io_addr == 7 && apu_reg_access_w) - { - sq2_ignore_reload = true; - } - } - sq2_sweep_counter--; - if (sq2_sweep_counter == 0) - { - sq2_sweep_counter = sq2_sweep_devider_period + 1; - if (sq2_sweep_enable && sq2_sweep_shift_count > 0 && sq2_valid_freq) - { - sq2_sweep_change = sq2_timer >> (int)sq2_sweep_shift_count; - sq2_timer += (sq2_sweep_negate ? (-sq2_sweep_change) : sq2_sweep_change); - SQ2CalculateValidFreq(); - } - } - else if (sq2_sweep_reload) - { - sq2_sweep_counter = sq2_sweep_devider_period + 1; - sq2_sweep_reload = false; - } - } - - private static void SQ2ClockEnvelope() - { - if (sq2_envelope_start_flag) - { - sq2_envelope_start_flag = false; - sq2_envelope_decay_level_counter = 15; - sq2_envelope_devider = (byte)(sq2_volume_devider_period + 1); - } - else if (sq2_envelope_devider > 0) - { - sq2_envelope_devider--; - } - else - { - sq2_envelope_devider = (byte)(sq2_volume_devider_period + 1); - if (sq2_envelope_decay_level_counter > 0) - { - sq2_envelope_decay_level_counter--; - } - else if (sq2_length_halt) - { - sq2_envelope_decay_level_counter = 15; - } - } - sq2_envelope = (sq2_constant_volume_envelope ? sq2_volume_devider_period : sq2_envelope_decay_level_counter); - } - - private static void APUOnRegister4004() - { - if (apu_reg_access_w) - { - sq2_duty_cycle = (byte)((apu_reg_io_db & 0xC0) >> 6); - sq2_volume_devider_period = (byte)(apu_reg_io_db & 0xFu); - sq2_length_halt = (apu_reg_io_db & 0x20) != 0; - sq2_constant_volume_envelope = (apu_reg_io_db & 0x10) != 0; - sq2_envelope = (sq2_constant_volume_envelope ? sq2_volume_devider_period : sq2_envelope_decay_level_counter); - } - } - - private static void APUOnRegister4005() - { - if (apu_reg_access_w) - { - sq2_sweep_enable = (apu_reg_io_db & 0x80) == 128; - sq2_sweep_devider_period = (byte)((uint)(apu_reg_io_db >> 4) & 7u); - sq2_sweep_negate = (apu_reg_io_db & 8) == 8; - sq2_sweep_shift_count = (byte)(apu_reg_io_db & 7u); - sq2_sweep_reload = true; - SQ2CalculateValidFreq(); - } - } - - private static void APUOnRegister4006() - { - if (apu_reg_access_w) - { - sq2_timer = (sq2_timer & 0xFF00) | apu_reg_io_db; - SQ2CalculateValidFreq(); - } - } - - private static void APUOnRegister4007() - { - if (apu_reg_access_w) - { - sq2_timer = (sq2_timer & 0xFF) | ((apu_reg_io_db & 7) << 8); - if (sq2_length_enabled && !sq2_ignore_reload) - { - sq2_length_counter = sq_duration_table[apu_reg_io_db >> 3]; - } - if (sq2_ignore_reload) - { - sq2_ignore_reload = false; - } - sq2_seqencer = 0; - sq2_envelope_start_flag = true; - SQ2CalculateValidFreq(); - } - } - - private static void SQ2On4015() - { - sq2_length_enabled = (apu_reg_io_db & 2) != 0; - if (!sq2_length_enabled) - { - sq2_length_counter = 0; - } - } - - private static void SQ2Read4015() - { - if (sq2_length_counter > 0) - { - apu_reg_io_db = (byte)((apu_reg_io_db & 0xFDu) | 2u); - } - } - - private static void SQ2CalculateValidFreq() - { - sq2_valid_freq = sq2_timer >= 8 && (sq2_sweep_negate || ((sq2_timer + (sq2_timer >> (int)sq2_sweep_shift_count)) & 0x800) == 0); - } - - private static void SQ2WriteState(ref BinaryWriter bin) - { - bin.Write(sq2_duty_cycle); - bin.Write(sq2_length_halt); - bin.Write(sq2_constant_volume_envelope); - bin.Write(sq2_volume_devider_period); - bin.Write(sq2_sweep_enable); - bin.Write(sq2_sweep_devider_period); - bin.Write(sq2_sweep_negate); - bin.Write(sq2_sweep_shift_count); - bin.Write(sq2_timer); - bin.Write(sq2_period_devider); - bin.Write(sq2_seqencer); - bin.Write(sq2_length_enabled); - bin.Write(sq2_length_counter); - bin.Write(sq2_envelope_start_flag); - bin.Write(sq2_envelope_devider); - bin.Write(sq2_envelope_decay_level_counter); - bin.Write(sq2_envelope); - bin.Write(sq2_sweep_counter); - bin.Write(sq2_sweep_reload); - bin.Write(sq2_sweep_change); - bin.Write(sq2_valid_freq); - bin.Write(sq2_output); - bin.Write(sq2_ignore_reload); - } - - private static void SQ2ReadState(ref BinaryReader bin) - { - sq2_duty_cycle = bin.ReadByte(); - sq2_length_halt = bin.ReadBoolean(); - sq2_constant_volume_envelope = bin.ReadBoolean(); - sq2_volume_devider_period = bin.ReadByte(); - sq2_sweep_enable = bin.ReadBoolean(); - sq2_sweep_devider_period = bin.ReadByte(); - sq2_sweep_negate = bin.ReadBoolean(); - sq2_sweep_shift_count = bin.ReadByte(); - sq2_timer = bin.ReadInt32(); - sq2_period_devider = bin.ReadInt32(); - sq2_seqencer = bin.ReadByte(); - sq2_length_enabled = bin.ReadBoolean(); - sq2_length_counter = bin.ReadInt32(); - sq2_envelope_start_flag = bin.ReadBoolean(); - sq2_envelope_devider = bin.ReadByte(); - sq2_envelope_decay_level_counter = bin.ReadByte(); - sq2_envelope = bin.ReadByte(); - sq2_sweep_counter = bin.ReadInt32(); - sq2_sweep_reload = bin.ReadBoolean(); - sq2_sweep_change = bin.ReadInt32(); - sq2_valid_freq = bin.ReadBoolean(); - sq2_output = bin.ReadInt32(); - sq2_ignore_reload = bin.ReadBoolean(); - } + public static GameGenieCode[] GameGenieCodes + { + get + { + if (mem_board != null) + { + return mem_board.GameGenieCodes; + } + return null; + } + } + + public static bool IsGameGenieActive + { + get + { + if (mem_board != null) + { + return mem_board.IsGameGenieActive; + } + return false; + } + set + { + if (mem_board != null) + { + mem_board.IsGameGenieActive = value; + } + } + } + + public static bool IsGameFoundOnDB + { + get + { + if (mem_board != null) + { + return mem_board.IsGameFoundOnDB; + } + return false; + } + } + + public static NesCartDatabaseGameInfo GameInfo + { + get + { + if (mem_board != null) + { + return mem_board.GameInfo; + } + return NesCartDatabaseGameInfo.Empty; + } + } + + public static NesCartDatabaseCartridgeInfo GameCartInfo + { + get + { + if (mem_board != null) + { + return mem_board.GameCartInfo; + } + return new NesCartDatabaseCartridgeInfo(); + } + } + + public static string SHA1 => mem_board.SHA1; + + public static event EventHandler EmuShutdown; + + private static void DMCHardReset() + { + dmc_output_a = 0; + dmc_output = 0; + dmc_period_devider = 0; + dmc_loop_flag = false; + dmc_rate_index = 0; + dmc_irq_enabled = false; + dmc_dmaAddr = 49152; + dmc_addr_refresh = 49152; + dmc_size_refresh = 0; + dmc_dmaBits = 1; + dmc_dmaByte = 1; + dmc_period_devider = 0; + dmc_dmaEnabled = false; + dmc_bufferFull = false; + dmc_dmaSize = 0; + } + + private static void DMCSoftReset() + { + DMCHardReset(); + } + + private static void DMCClock() + { + dmc_period_devider--; + if (dmc_period_devider > 0) + { + return; + } + dmc_period_devider = dmc_freq_table[SystemIndex][dmc_rate_index]; + if (dmc_dmaEnabled) + { + if (((uint)dmc_dmaByte & (true ? 1u : 0u)) != 0) + { + if (dmc_output_a <= 125) + { + dmc_output_a += 2; + } + } + else if (dmc_output_a >= 2) + { + dmc_output_a -= 2; + } + dmc_dmaByte >>= 1; + } + dmc_dmaBits--; + if (dmc_dmaBits == 0) + { + dmc_dmaBits = 8; + if (dmc_bufferFull) + { + dmc_bufferFull = false; + dmc_dmaEnabled = true; + dmc_dmaByte = dmc_dmaBuffer; + if (dmc_dmaSize > 0) + { + AssertDMCDMA(); + } + } + else + { + dmc_dmaEnabled = false; + } + } + if (audio_dmc_outputable) + { + dmc_output = dmc_output_a; + } + audio_signal_outputed = true; + } + + private static void DMCDoDMA() + { + dmc_bufferFull = true; + Read(ref dmc_dmaAddr, out dmc_dmaBuffer); + if (dmc_dmaAddr == ushort.MaxValue) + { + dmc_dmaAddr = 32768; + } + else + { + dmc_dmaAddr++; + } + if (dmc_dmaSize > 0) + { + dmc_dmaSize--; + } + if (dmc_dmaSize == 0) + { + if (dmc_loop_flag) + { + dmc_dmaSize = dmc_size_refresh; + dmc_dmaAddr = dmc_addr_refresh; + } + else if (dmc_irq_enabled) + { + IRQFlags |= 2; + apu_irq_delta_occur = true; + } + } + } + + private static void APUOnRegister4010() + { + if (apu_reg_access_w) + { + dmc_irq_enabled = (apu_reg_io_db & 0x80) != 0; + dmc_loop_flag = (apu_reg_io_db & 0x40) != 0; + if (!dmc_irq_enabled) + { + apu_irq_delta_occur = false; + IRQFlags &= -3; + } + dmc_rate_index = (byte)(apu_reg_io_db & 0xFu); + } + } + + private static void APUOnRegister4011() + { + if (apu_reg_access_w) + { + dmc_output_a = (byte)(apu_reg_io_db & 0x7F); + } + } + + private static void APUOnRegister4012() + { + if (apu_reg_access_w) + { + dmc_addr_refresh = (ushort)((uint)(apu_reg_io_db << 6) | 0xC000u); + } + } + + private static void APUOnRegister4013() + { + if (apu_reg_access_w) + { + dmc_size_refresh = (apu_reg_io_db << 4) | 1; + } + } + + private static void DMCOn4015() + { + apu_irq_delta_occur = false; + IRQFlags &= -3; + } + + private static void DMCRead4015() + { + if (dmc_dmaSize > 0) + { + apu_reg_io_db = (byte)((apu_reg_io_db & 0xEFu) | 0x10u); + } + } + + private static void DMCWriteState(ref BinaryWriter bin) + { + bin.Write(dmc_output_a); + bin.Write(dmc_output); + bin.Write(dmc_period_devider); + bin.Write(dmc_irq_enabled); + bin.Write(dmc_loop_flag); + bin.Write(dmc_rate_index); + bin.Write(dmc_addr_refresh); + bin.Write(dmc_size_refresh); + bin.Write(dmc_dmaEnabled); + bin.Write(dmc_dmaByte); + bin.Write(dmc_dmaBits); + bin.Write(dmc_bufferFull); + bin.Write(dmc_dmaBuffer); + bin.Write(dmc_dmaSize); + bin.Write(dmc_dmaAddr); + } + + private static void DMCReadState(ref BinaryReader bin) + { + dmc_output_a = bin.ReadInt32(); + dmc_output = bin.ReadInt32(); + dmc_period_devider = bin.ReadInt32(); + dmc_irq_enabled = bin.ReadBoolean(); + dmc_loop_flag = bin.ReadBoolean(); + dmc_rate_index = bin.ReadByte(); + dmc_addr_refresh = bin.ReadUInt16(); + dmc_size_refresh = bin.ReadInt32(); + dmc_dmaEnabled = bin.ReadBoolean(); + dmc_dmaByte = bin.ReadByte(); + dmc_dmaBits = bin.ReadInt32(); + dmc_bufferFull = bin.ReadBoolean(); + dmc_dmaBuffer = bin.ReadByte(); + dmc_dmaSize = bin.ReadInt32(); + dmc_dmaAddr = bin.ReadUInt16(); + } + + private static void NOSHardReset() + { + nos_length_halt = false; + nos_constant_volume_envelope = false; + nos_volume_devider_period = 0; + nos_shift_reg = 1; + nos_timer = 0; + nos_mode = false; + nos_period_devider = 0; + nos_length_enabled = false; + nos_length_counter = 0; + nos_envelope_start_flag = false; + nos_envelope_devider = 0; + nos_envelope_decay_level_counter = 0; + nos_envelope = 0; + nos_output = 0; + nos_feedback = 0; + nos_ignore_reload = false; + } + + private static void NOSSoftReset() + { + NOSHardReset(); + } + + private static void NOSClock() + { + nos_period_devider--; + if (nos_period_devider > 0) + { + return; + } + nos_period_devider = nos_timer; + if (nos_mode) + { + nos_feedback = ((nos_shift_reg >> 6) & 1) ^ (nos_shift_reg & 1); + } + else + { + nos_feedback = ((nos_shift_reg >> 1) & 1) ^ (nos_shift_reg & 1); + } + nos_shift_reg >>= 1; + nos_shift_reg = (nos_shift_reg & 0x3FFF) | ((nos_feedback & 1) << 14); + if (nos_length_counter > 0 && (nos_shift_reg & 1) == 0) + { + if (audio_nos_outputable) + { + nos_output = nos_envelope; + } + } + else + { + nos_output = 0; + } + audio_signal_outputed = true; + } + + private static void NOSClockLength() + { + if (nos_length_counter > 0 && !nos_length_halt) + { + nos_length_counter--; + if (apu_reg_access_happened && apu_reg_io_addr == 15 && apu_reg_access_w) + { + nos_ignore_reload = true; + } + } + } + + private static void NOSClockEnvelope() + { + if (nos_envelope_start_flag) + { + nos_envelope_start_flag = false; + nos_envelope_decay_level_counter = 15; + nos_envelope_devider = (byte)(nos_volume_devider_period + 1); + } + else if (nos_envelope_devider > 0) + { + nos_envelope_devider--; + } + else + { + nos_envelope_devider = (byte)(nos_volume_devider_period + 1); + if (nos_envelope_decay_level_counter > 0) + { + nos_envelope_decay_level_counter--; + } + else if (nos_length_halt) + { + nos_envelope_decay_level_counter = 15; + } + } + nos_envelope = (nos_constant_volume_envelope ? nos_volume_devider_period : nos_envelope_decay_level_counter); + } + + private static void APUOnRegister400C() + { + if (apu_reg_access_w) + { + nos_volume_devider_period = (byte)(apu_reg_io_db & 0xFu); + nos_length_halt = (apu_reg_io_db & 0x20) != 0; + nos_constant_volume_envelope = (apu_reg_io_db & 0x10) != 0; + nos_envelope = (nos_constant_volume_envelope ? nos_volume_devider_period : nos_envelope_decay_level_counter); + } + } + + private static void APUOnRegister400D() + { + } + + private static void APUOnRegister400E() + { + if (apu_reg_access_w) + { + nos_timer = (ushort)(nos_freq_table[SystemIndex][apu_reg_io_db & 0xF] / 2); + nos_mode = (apu_reg_io_db & 0x80) == 128; + } + } + + private static void APUOnRegister400F() + { + if (apu_reg_access_w) + { + if (nos_length_enabled && !nos_ignore_reload) + { + nos_length_counter = sq_duration_table[apu_reg_io_db >> 3]; + } + if (nos_ignore_reload) + { + nos_ignore_reload = false; + } + nos_envelope_start_flag = true; + } + } + + private static void NOSOn4015() + { + nos_length_enabled = (apu_reg_io_db & 8) != 0; + if (!nos_length_enabled) + { + nos_length_counter = 0; + } + } + + private static void NOSRead4015() + { + if (nos_length_counter > 0) + { + apu_reg_io_db = (byte)((apu_reg_io_db & 0xF7u) | 8u); + } + } + + private static void NOSWriteState(ref BinaryWriter bin) + { + bin.Write(nos_length_halt); + bin.Write(nos_constant_volume_envelope); + bin.Write(nos_volume_devider_period); + bin.Write(nos_timer); + bin.Write(nos_mode); + bin.Write(nos_period_devider); + bin.Write(nos_length_enabled); + bin.Write(nos_length_counter); + bin.Write(nos_envelope_start_flag); + bin.Write(nos_envelope_devider); + bin.Write(nos_envelope_decay_level_counter); + bin.Write(nos_envelope); + bin.Write(nos_output); + bin.Write(nos_shift_reg); + bin.Write(nos_feedback); + bin.Write(nos_ignore_reload); + } + + private static void NOSReadState(ref BinaryReader bin) + { + nos_length_halt = bin.ReadBoolean(); + nos_constant_volume_envelope = bin.ReadBoolean(); + nos_volume_devider_period = bin.ReadByte(); + nos_timer = bin.ReadUInt16(); + nos_mode = bin.ReadBoolean(); + nos_period_devider = bin.ReadInt32(); + nos_length_enabled = bin.ReadBoolean(); + nos_length_counter = bin.ReadInt32(); + nos_envelope_start_flag = bin.ReadBoolean(); + nos_envelope_devider = bin.ReadByte(); + nos_envelope_decay_level_counter = bin.ReadByte(); + nos_envelope = bin.ReadByte(); + nos_output = bin.ReadInt32(); + nos_shift_reg = bin.ReadInt32(); + nos_feedback = bin.ReadInt32(); + nos_ignore_reload = bin.ReadBoolean(); + } + + private static void SQ1HardReset() + { + sq1_duty_cycle = 0; + sq1_length_halt = false; + sq1_constant_volume_envelope = false; + sq1_volume_devider_period = 0; + sq1_sweep_enable = false; + sq1_sweep_devider_period = 0; + sq1_sweep_negate = false; + sq1_sweep_shift_count = 0; + sq1_timer = 0; + sq1_period_devider = 0; + sq1_seqencer = 0; + sq1_length_enabled = false; + sq1_length_counter = 0; + sq1_envelope_start_flag = false; + sq1_envelope_devider = 0; + sq1_envelope_decay_level_counter = 0; + sq1_envelope = 0; + sq1_sweep_counter = 0; + sq1_sweep_reload = false; + sq1_sweep_change = 0; + sq1_valid_freq = false; + sq1_output = 0; + sq1_ignore_reload = false; + } + + private static void SQ1SoftReset() + { + SQ1HardReset(); + } + + private static void SQ1Clock() + { + sq1_period_devider--; + if (sq1_period_devider > 0) + { + return; + } + sq1_period_devider = sq1_timer + 1; + sq1_seqencer = (byte)((uint)(sq1_seqencer + 1) & 7u); + if (sq1_length_counter > 0 && sq1_valid_freq) + { + if (audio_sq1_outputable) + { + sq1_output = sq_duty_cycle_sequences[sq1_duty_cycle][sq1_seqencer] * sq1_envelope; + } + } + else + { + sq1_output = 0; + } + audio_signal_outputed = true; + } + + private static void SQ1ClockLength() + { + if (sq1_length_counter > 0 && !sq1_length_halt) + { + sq1_length_counter--; + if (apu_reg_access_happened && apu_reg_io_addr == 3 && apu_reg_access_w) + { + sq1_ignore_reload = true; + } + } + sq1_sweep_counter--; + if (sq1_sweep_counter == 0) + { + sq1_sweep_counter = sq1_sweep_devider_period + 1; + if (sq1_sweep_enable && sq1_sweep_shift_count > 0 && sq1_valid_freq) + { + sq1_sweep_change = sq1_timer >> (int)sq1_sweep_shift_count; + sq1_timer += (sq1_sweep_negate ? (~sq1_sweep_change) : sq1_sweep_change); + SQ1CalculateValidFreq(); + } + } + if (sq1_sweep_reload) + { + sq1_sweep_counter = sq1_sweep_devider_period + 1; + sq1_sweep_reload = false; + } + } + + private static void SQ1ClockEnvelope() + { + if (sq1_envelope_start_flag) + { + sq1_envelope_start_flag = false; + sq1_envelope_decay_level_counter = 15; + sq1_envelope_devider = (byte)(sq1_volume_devider_period + 1); + } + else if (sq1_envelope_devider > 0) + { + sq1_envelope_devider--; + } + else + { + sq1_envelope_devider = (byte)(sq1_volume_devider_period + 1); + if (sq1_envelope_decay_level_counter > 0) + { + sq1_envelope_decay_level_counter--; + } + else if (sq1_length_halt) + { + sq1_envelope_decay_level_counter = 15; + } + } + sq1_envelope = (sq1_constant_volume_envelope ? sq1_volume_devider_period : sq1_envelope_decay_level_counter); + } + + private static void APUOnRegister4000() + { + if (apu_reg_access_w) + { + sq1_duty_cycle = (byte)((apu_reg_io_db & 0xC0) >> 6); + sq1_volume_devider_period = (byte)(apu_reg_io_db & 0xFu); + sq1_length_halt = (apu_reg_io_db & 0x20) != 0; + sq1_constant_volume_envelope = (apu_reg_io_db & 0x10) != 0; + sq1_envelope = (sq1_constant_volume_envelope ? sq1_volume_devider_period : sq1_envelope_decay_level_counter); + } + } + + private static void APUOnRegister4001() + { + if (apu_reg_access_w) + { + sq1_sweep_enable = (apu_reg_io_db & 0x80) == 128; + sq1_sweep_devider_period = (byte)((uint)(apu_reg_io_db >> 4) & 7u); + sq1_sweep_negate = (apu_reg_io_db & 8) == 8; + sq1_sweep_shift_count = (byte)(apu_reg_io_db & 7u); + sq1_sweep_reload = true; + SQ1CalculateValidFreq(); + } + } + + private static void APUOnRegister4002() + { + if (apu_reg_access_w) + { + sq1_timer = (sq1_timer & 0xFF00) | apu_reg_io_db; + SQ1CalculateValidFreq(); + } + } + + private static void APUOnRegister4003() + { + if (apu_reg_access_w) + { + sq1_timer = (sq1_timer & 0xFF) | ((apu_reg_io_db & 7) << 8); + if (sq1_length_enabled && !sq1_ignore_reload) + { + sq1_length_counter = sq_duration_table[apu_reg_io_db >> 3]; + } + if (sq1_ignore_reload) + { + sq1_ignore_reload = false; + } + sq1_seqencer = 0; + sq1_envelope_start_flag = true; + SQ1CalculateValidFreq(); + } + } + + private static void SQ1On4015() + { + sq1_length_enabled = (apu_reg_io_db & 1) != 0; + if (!sq1_length_enabled) + { + sq1_length_counter = 0; + } + } + + private static void SQ1Read4015() + { + if (sq1_length_counter > 0) + { + apu_reg_io_db = (byte)((apu_reg_io_db & 0xFEu) | 1u); + } + } + + private static void SQ1CalculateValidFreq() + { + sq1_valid_freq = sq1_timer >= 8 && (sq1_sweep_negate || ((sq1_timer + (sq1_timer >> (int)sq1_sweep_shift_count)) & 0x800) == 0); + } + + private static void SQ1WriteState(ref BinaryWriter bin) + { + bin.Write(sq1_duty_cycle); + bin.Write(sq1_length_halt); + bin.Write(sq1_constant_volume_envelope); + bin.Write(sq1_volume_devider_period); + bin.Write(sq1_sweep_enable); + bin.Write(sq1_sweep_devider_period); + bin.Write(sq1_sweep_negate); + bin.Write(sq1_sweep_shift_count); + bin.Write(sq1_timer); + bin.Write(sq1_period_devider); + bin.Write(sq1_seqencer); + bin.Write(sq1_length_enabled); + bin.Write(sq1_length_counter); + bin.Write(sq1_envelope_start_flag); + bin.Write(sq1_envelope_devider); + bin.Write(sq1_envelope_decay_level_counter); + bin.Write(sq1_envelope); + bin.Write(sq1_sweep_counter); + bin.Write(sq1_sweep_reload); + bin.Write(sq1_sweep_change); + bin.Write(sq1_valid_freq); + bin.Write(sq1_output); + bin.Write(sq1_ignore_reload); + } + + private static void SQ1ReadState(ref BinaryReader bin) + { + sq1_duty_cycle = bin.ReadByte(); + sq1_length_halt = bin.ReadBoolean(); + sq1_constant_volume_envelope = bin.ReadBoolean(); + sq1_volume_devider_period = bin.ReadByte(); + sq1_sweep_enable = bin.ReadBoolean(); + sq1_sweep_devider_period = bin.ReadByte(); + sq1_sweep_negate = bin.ReadBoolean(); + sq1_sweep_shift_count = bin.ReadByte(); + sq1_timer = bin.ReadInt32(); + sq1_period_devider = bin.ReadInt32(); + sq1_seqencer = bin.ReadByte(); + sq1_length_enabled = bin.ReadBoolean(); + sq1_length_counter = bin.ReadInt32(); + sq1_envelope_start_flag = bin.ReadBoolean(); + sq1_envelope_devider = bin.ReadByte(); + sq1_envelope_decay_level_counter = bin.ReadByte(); + sq1_envelope = bin.ReadByte(); + sq1_sweep_counter = bin.ReadInt32(); + sq1_sweep_reload = bin.ReadBoolean(); + sq1_sweep_change = bin.ReadInt32(); + sq1_valid_freq = bin.ReadBoolean(); + sq1_output = bin.ReadInt32(); + sq1_ignore_reload = bin.ReadBoolean(); + } + + private static void TRLHardReset() + { + trl_liner_control_flag = false; + trl_liner_control_reload = 0; + trl_timer = 0; + trl_length_enabled = false; + trl_length_counter = 0; + trl_liner_control_reload_flag = false; + trl_liner_counter = 0; + trl_output = 0; + trl_period_devider = 0; + trl_step = 0; + trl_ignore_reload = false; + } + + private static void TRLSoftReset() + { + TRLHardReset(); + } + + private static void TRLClock() + { + trl_period_devider--; + if (trl_period_devider > 0) + { + return; + } + trl_period_devider = trl_timer + 1; + if (trl_length_counter > 0 && trl_liner_counter > 0 && trl_timer >= 4) + { + trl_step++; + trl_step &= 31; + if (audio_trl_outputable) + { + trl_output = trl_step_seq[trl_step]; + } + } + audio_signal_outputed = true; + } + + private static void TRLClockLength() + { + if (trl_length_counter > 0 && !trl_liner_control_flag) + { + trl_length_counter--; + if (apu_reg_access_happened && apu_reg_io_addr == 11 && apu_reg_access_w) + { + trl_ignore_reload = true; + } + } + } + + private static void TRLClockEnvelope() + { + if (trl_liner_control_reload_flag) + { + trl_liner_counter = trl_liner_control_reload; + } + else if (trl_liner_counter > 0) + { + trl_liner_counter--; + } + if (!trl_liner_control_flag) + { + trl_liner_control_reload_flag = false; + } + } + + private static void APUOnRegister4008() + { + if (apu_reg_access_w) + { + trl_liner_control_flag = (apu_reg_io_db & 0x80) == 128; + trl_liner_control_reload = (byte)(apu_reg_io_db & 0x7Fu); + } + } + + private static void APUOnRegister4009() + { + } + + private static void APUOnRegister400A() + { + if (apu_reg_access_w) + { + trl_timer = (ushort)((trl_timer & 0x7F00u) | apu_reg_io_db); + } + } + + private static void APUOnRegister400B() + { + if (apu_reg_access_w) + { + trl_timer = (ushort)((trl_timer & 0xFFu) | (uint)((apu_reg_io_db & 7) << 8)); + if (trl_length_enabled && !trl_ignore_reload) + { + trl_length_counter = sq_duration_table[apu_reg_io_db >> 3]; + } + if (trl_ignore_reload) + { + trl_ignore_reload = false; + } + trl_liner_control_reload_flag = true; + } + } + + private static void TRLOn4015() + { + trl_length_enabled = (apu_reg_io_db & 4) != 0; + if (!trl_length_enabled) + { + trl_length_counter = 0; + } + } + + private static void TRLRead4015() + { + if (trl_length_counter > 0) + { + apu_reg_io_db = (byte)((apu_reg_io_db & 0xFBu) | 4u); + } + } + + private static void TRLWriteState(ref BinaryWriter bin) + { + bin.Write(trl_liner_control_flag); + bin.Write(trl_liner_control_reload); + bin.Write(trl_timer); + bin.Write(trl_length_enabled); + bin.Write(trl_length_counter); + bin.Write(trl_liner_control_reload_flag); + bin.Write(trl_liner_counter); + bin.Write(trl_output); + bin.Write(trl_period_devider); + bin.Write(trl_step); + bin.Write(trl_ignore_reload); + } + + private static void TRLReadState(ref BinaryReader bin) + { + trl_liner_control_flag = bin.ReadBoolean(); + trl_liner_control_reload = bin.ReadByte(); + trl_timer = bin.ReadUInt16(); + trl_length_enabled = bin.ReadBoolean(); + trl_length_counter = bin.ReadByte(); + trl_liner_control_reload_flag = bin.ReadBoolean(); + trl_liner_counter = bin.ReadByte(); + trl_output = bin.ReadInt32(); + trl_period_devider = bin.ReadInt32(); + trl_step = bin.ReadInt32(); + trl_ignore_reload = bin.ReadBoolean(); + } + + private static void APUInitialize() + { + apu_reg_update_func = new Action[32]; + apu_reg_read_func = new Action[32]; + apu_reg_write_func = new Action[32]; + for (int i = 0; i < 32; i++) + { + apu_reg_update_func[i] = APUBlankAccess; + apu_reg_read_func[i] = APUBlankAccess; + apu_reg_write_func[i] = APUBlankAccess; + } + apu_reg_update_func[0] = APUOnRegister4000; + apu_reg_update_func[1] = APUOnRegister4001; + apu_reg_update_func[2] = APUOnRegister4002; + apu_reg_update_func[3] = APUOnRegister4003; + apu_reg_update_func[4] = APUOnRegister4004; + apu_reg_update_func[5] = APUOnRegister4005; + apu_reg_update_func[6] = APUOnRegister4006; + apu_reg_update_func[7] = APUOnRegister4007; + apu_reg_update_func[8] = APUOnRegister4008; + apu_reg_update_func[9] = APUOnRegister4009; + apu_reg_update_func[10] = APUOnRegister400A; + apu_reg_update_func[11] = APUOnRegister400B; + apu_reg_update_func[12] = APUOnRegister400C; + apu_reg_update_func[13] = APUOnRegister400D; + apu_reg_update_func[14] = APUOnRegister400E; + apu_reg_update_func[15] = APUOnRegister400F; + apu_reg_update_func[16] = APUOnRegister4010; + apu_reg_update_func[17] = APUOnRegister4011; + apu_reg_update_func[18] = APUOnRegister4012; + apu_reg_update_func[19] = APUOnRegister4013; + apu_reg_update_func[21] = APUOnRegister4015; + apu_reg_update_func[22] = APUOnRegister4016; + apu_reg_update_func[23] = APUOnRegister4017; + apu_reg_read_func[21] = APURead4015; + apu_reg_read_func[22] = APURead4016; + apu_reg_read_func[23] = APURead4017; + apu_reg_write_func[20] = APUWrite4014; + apu_reg_write_func[21] = APUWrite4015; + audio_low_pass_filter_14K = new SoundLowPassFilter(0.00815686); + audio_high_pass_filter_90 = new SoundHighPassFilter(0.999835); + audio_high_pass_filter_440 = new SoundHighPassFilter(0.996039); + audio_dc_blocker_filter = new SoundDCBlockerFilter(0.995); + apu_update_playback_func = APUUpdatePlaybackWithFilters; + } + + public static void ApplyAudioSettings(bool all = true) + { + SoundEnabled = MyNesMain.RendererSettings.Audio_SoundEnabled; + audio_sq1_outputable = MyNesMain.RendererSettings.Audio_ChannelEnabled_SQ1; + audio_sq2_outputable = MyNesMain.RendererSettings.Audio_ChannelEnabled_SQ2; + audio_nos_outputable = MyNesMain.RendererSettings.Audio_ChannelEnabled_NOZ; + audio_trl_outputable = MyNesMain.RendererSettings.Audio_ChannelEnabled_TRL; + audio_dmc_outputable = MyNesMain.RendererSettings.Audio_ChannelEnabled_DMC; + if (apu_use_external_sound) + { + mem_board.APUApplyChannelsSettings(); + } + if (all) + { + CalculateAudioPlaybackValues(); + } + } + + private static void APUHardReset() + { + apu_reg_io_db = 0; + apu_reg_io_addr = 0; + apu_reg_access_happened = false; + apu_reg_access_w = false; + apu_seq_mode = false; + apu_odd_cycle = true; + apu_cycle_f_t = 0; + apu_cycle_e = 4; + apu_cycle_f = 4; + apu_cycle_l = 4; + apu_odd_l = false; + apu_check_irq = false; + apu_do_env = false; + apu_do_length = false; + switch (Region) + { + case EmuRegion.NTSC: + cpu_speed = 1789773; + apu_ferq_f = 14914; + apu_ferq_e = 3728; + apu_ferq_l = 7456; + break; + case EmuRegion.PALB: + cpu_speed = 1662607; + apu_ferq_f = 14914; + apu_ferq_e = 3728; + apu_ferq_l = 7456; + break; + case EmuRegion.DENDY: + cpu_speed = 1773448; + apu_ferq_f = 14914; + apu_ferq_e = 3728; + apu_ferq_l = 7456; + break; + } + Tracer.WriteLine("NES: cpu speed = " + cpu_speed); + SQ1HardReset(); + SQ2HardReset(); + NOSHardReset(); + DMCHardReset(); + TRLHardReset(); + apu_irq_enabled = true; + apu_irq_flag = false; + reg_2004 = 8196; + CalculateAudioPlaybackValues(); + apu_use_external_sound = mem_board.enable_external_sound; + if (apu_use_external_sound) + { + Tracer.WriteInformation("External sound channels has been enabled on apu."); + } + } + + private static void APUSoftReset() + { + apu_reg_io_db = 0; + apu_reg_io_addr = 0; + apu_reg_access_happened = false; + apu_reg_access_w = false; + apu_seq_mode = false; + apu_odd_cycle = false; + apu_cycle_f_t = 0; + apu_cycle_e = 4; + apu_cycle_f = 4; + apu_cycle_l = 4; + apu_odd_l = false; + apu_check_irq = false; + apu_do_env = false; + apu_do_length = false; + apu_irq_enabled = true; + apu_irq_flag = false; + SQ1SoftReset(); + SQ2SoftReset(); + TRLSoftReset(); + NOSSoftReset(); + DMCSoftReset(); + } + + private static void APUIORead(ref ushort addr, out byte value) + { + if (addr >= 16416) + { + mem_board.ReadEX(ref addr, out value); + return; + } + apu_reg_io_addr = (byte)(addr & 0x1Fu); + apu_reg_access_happened = true; + apu_reg_access_w = false; + apu_reg_read_func[apu_reg_io_addr](); + value = apu_reg_io_db; + } + + private static void APUIOWrite(ref ushort addr, ref byte value) + { + if (addr >= 16416) + { + mem_board.WriteEX(ref addr, ref value); + return; + } + apu_reg_io_addr = (byte)(addr & 0x1Fu); + apu_reg_io_db = value; + apu_reg_access_w = true; + apu_reg_access_happened = true; + apu_reg_write_func[apu_reg_io_addr](); + } + + private static void APUBlankAccess() + { + } + + private static void APUWrite4014() + { + dma_Oamaddress = (ushort)(apu_reg_io_db << 8); + AssertOAMDMA(); + } + + private static void APUWrite4015() + { + if ((apu_reg_io_db & 0x10u) != 0) + { + if (dmc_dmaSize == 0) + { + dmc_dmaSize = dmc_size_refresh; + dmc_dmaAddr = dmc_addr_refresh; + } + } + else + { + dmc_dmaSize = 0; + } + if (!dmc_bufferFull && dmc_dmaSize > 0) + { + AssertDMCDMA(); + } + } + + private static void APUOnRegister4015() + { + if (apu_reg_access_w) + { + SQ1On4015(); + SQ2On4015(); + NOSOn4015(); + TRLOn4015(); + DMCOn4015(); + } + else + { + apu_irq_flag = false; + IRQFlags &= -2; + } + } + + private static void APUOnRegister4016() + { + if (!apu_reg_access_w) + { + return; + } + if (inputStrobe > (apu_reg_io_db & 1)) + { + if (IsFourPlayers) + { + PORT0 = (joypad3.GetData() << 8) | joypad1.GetData() | 0x1010000; + PORT1 = (joypad4.GetData() << 8) | joypad2.GetData() | 0x2020000; + } + else + { + PORT0 = joypad1.GetData() | 0x1010100; + PORT1 = joypad2.GetData() | 0x2020200; + } + } + inputStrobe = apu_reg_io_db & 1; + } + + private static void APUOnRegister4017() + { + if (apu_reg_access_w) + { + apu_seq_mode = (apu_reg_io_db & 0x80) != 0; + apu_irq_enabled = (apu_reg_io_db & 0x40) == 0; + apu_cycle_e = -1; + apu_cycle_l = -1; + apu_cycle_f = -1; + apu_odd_l = false; + apu_do_length = apu_seq_mode; + apu_do_env = apu_seq_mode; + apu_check_irq = false; + if (!apu_irq_enabled) + { + apu_irq_flag = false; + IRQFlags &= -2; + } + } + } + + private static void APURead4015() + { + apu_reg_io_db &= 32; + SQ1Read4015(); + SQ2Read4015(); + NOSRead4015(); + TRLRead4015(); + DMCRead4015(); + if (apu_irq_flag) + { + apu_reg_io_db = (byte)((apu_reg_io_db & 0xBFu) | 0x40u); + } + if (apu_irq_delta_occur) + { + apu_reg_io_db = (byte)((apu_reg_io_db & 0x7Fu) | 0x80u); + } + } + + private static void APURead4016() + { + apu_reg_io_db = (byte)((uint)PORT0 & 1u); + PORT0 >>= 1; + } + + private static void APURead4017() + { + apu_reg_io_db = (byte)((uint)PORT1 & 1u); + PORT1 >>= 1; + } + + private static void APUClock() + { + apu_odd_cycle = !apu_odd_cycle; + if (apu_do_env) + { + APUClockEnvelope(); + } + if (apu_do_length) + { + APUClockDuration(); + } + if (apu_odd_cycle) + { + apu_cycle_f++; + if (apu_cycle_f >= apu_ferq_f) + { + apu_cycle_f = -1; + apu_check_irq = true; + apu_cycle_f_t = 3; + } + apu_cycle_e++; + if (apu_cycle_e >= apu_ferq_e) + { + apu_cycle_e = -1; + if (apu_check_irq) + { + if (!apu_seq_mode) + { + apu_do_env = true; + } + else + { + apu_cycle_e = 4; + } + } + else + { + apu_do_env = true; + } + } + apu_cycle_l++; + if (apu_cycle_l >= apu_ferq_l) + { + apu_odd_l = !apu_odd_l; + apu_cycle_l = (apu_odd_l ? (-2) : (-1)); + if (apu_check_irq && apu_seq_mode) + { + apu_cycle_l = 3730; + apu_odd_l = true; + } + else + { + apu_do_length = true; + } + } + SQ1Clock(); + SQ2Clock(); + NOSClock(); + if (apu_use_external_sound) + { + mem_board.OnAPUClock(); + } + if (apu_reg_access_happened) + { + apu_reg_access_happened = false; + apu_reg_update_func[apu_reg_io_addr](); + } + } + TRLClock(); + DMCClock(); + if (apu_check_irq) + { + if (!apu_seq_mode) + { + APUCheckIRQ(); + } + apu_cycle_f_t--; + if (apu_cycle_f_t == 0) + { + apu_check_irq = false; + } + } + if (apu_use_external_sound) + { + mem_board.OnAPUClockSingle(); + } + apu_update_playback_func(); + } + + private static void APUClockDuration() + { + SQ1ClockLength(); + SQ2ClockLength(); + NOSClockLength(); + TRLClockLength(); + if (apu_use_external_sound) + { + mem_board.OnAPUClockDuration(); + } + apu_do_length = false; + } + + private static void APUClockEnvelope() + { + SQ1ClockEnvelope(); + SQ2ClockEnvelope(); + NOSClockEnvelope(); + TRLClockEnvelope(); + if (apu_use_external_sound) + { + mem_board.OnAPUClockEnvelope(); + } + apu_do_env = false; + } + + private static void APUCheckIRQ() + { + if (apu_irq_enabled) + { + apu_irq_flag = true; + } + if (apu_irq_flag) + { + IRQFlags |= 1; + } + } + + private static void CalculateAudioPlaybackValues() + { + audio_timer_ratio = (double)cpu_speed / (double)MyNesMain.RendererSettings.Audio_Frequency; + audio_playback_peek_limit = MyNesMain.RendererSettings.Audio_InternalPeekLimit; + audio_samples_count = MyNesMain.RendererSettings.Audio_InternalSamplesCount; + audio_playback_amplitude = MyNesMain.RendererSettings.Audio_PlaybackAmplitude; + audio_samples = new short[audio_samples_count]; + audio_w_pos = 0; + audio_samples_added = 0; + audio_timer = 0.0; + audio_x = (audio_y = 0.0); + Tracer.WriteLine("AUDIO: frequency = " + MyNesMain.RendererSettings.Audio_Frequency); + Tracer.WriteLine("AUDIO: timer ratio = " + audio_timer_ratio); + Tracer.WriteLine("AUDIO: internal samples count = " + audio_samples_count); + Tracer.WriteLine("AUDIO: amplitude = " + audio_playback_amplitude); + if (MyNesMain.RendererSettings.Audio_EnableFilters) + { + apu_update_playback_func = APUUpdatePlaybackWithFilters; + audio_low_pass_filter_14K = new SoundLowPassFilter(SoundLowPassFilter.GetK((double)cpu_speed / 14000.0, 14000.0)); + audio_high_pass_filter_90 = new SoundHighPassFilter(SoundHighPassFilter.GetK((double)cpu_speed / 90.0, 90.0)); + audio_high_pass_filter_440 = new SoundHighPassFilter(SoundHighPassFilter.GetK((double)cpu_speed / 440.0, 440.0)); + } + else + { + apu_update_playback_func = APUUpdatePlaybackWithoutFilters; + } + InitializeDACTables(force_intitialize: false); + } + + public static void InitializeDACTables(bool force_intitialize) + { + if (audio_playback_dac_initialized && !force_intitialize) + { + return; + } + int[] array = new int[5]; + mix_table = new int[16][][][][]; + for (int i = 0; i < 16; i++) + { + mix_table[i] = new int[16][][][]; + for (int j = 0; j < 16; j++) + { + mix_table[i][j] = new int[16][][]; + for (int k = 0; k < 16; k++) + { + mix_table[i][j][k] = new int[16][]; + for (int l = 0; l < 16; l++) + { + mix_table[i][j][k][l] = new int[128]; + for (int m = 0; m < 128; m++) + { + if (MyNesMain.RendererSettings.Audio_UseDefaultMixer) + { + double num = 95.88 / (8128.0 / (double)(i + j) + 100.0); + double num2 = 159.79 / (1.0 / ((double)k / 8227.0 + (double)l / 12241.0 + (double)m / 22638.0) + 100.0); + mix_table[i][j][k][l][m] = (int)Math.Ceiling((num + num2) * audio_playback_amplitude); + continue; + } + GetPrec(i, 255, 2048, out array[0]); + GetPrec(j, 255, 2048, out array[1]); + GetPrec(l, 255, 2048, out array[2]); + GetPrec(k, 255, 2048, out array[3]); + GetPrec(m, 255, 2048, out array[4]); + array[4] /= 2; + int num3 = array[0] + array[1] + array[2] + array[3] + array[4]; + num3 /= 5; + mix_table[i][j][k][l][m] = num3; + } + } + } + } + } + audio_playback_dac_initialized = true; + } + + private static void APUUpdatePlaybackWithFilters() + { + if (!SoundEnabled) + { + return; + } + audio_x = mix_table[sq1_output][sq2_output][trl_output][nos_output][dmc_output]; + if (apu_use_external_sound) + { + audio_x = (audio_x + mem_board.APUGetSample() * audio_playback_amplitude) / 2.0; + } + audio_high_pass_filter_90.DoFiltering(audio_x, out audio_y); + audio_high_pass_filter_440.DoFiltering(audio_y, out audio_y); + audio_low_pass_filter_14K.DoFiltering(audio_y, out audio_y); + audio_y_av += audio_y; + audio_y_timer += 1.0; + audio_timer += 1.0; + if (!(audio_timer >= audio_timer_ratio)) + { + return; + } + if (audio_y_timer > 0.0) + { + audio_y = audio_y_av / audio_y_timer; + } + else + { + audio_y = 0.0; + } + audio_y_av = 0.0; + audio_y_timer = 0.0; + audio_timer -= audio_timer_ratio; + if (audio_w_pos < audio_samples_count) + { + if (audio_y > (double)audio_playback_peek_limit) + { + audio_y = audio_playback_peek_limit; + } + if (audio_y < (double)(-audio_playback_peek_limit)) + { + audio_y = -audio_playback_peek_limit; + } + audio_samples[audio_w_pos] = (short)audio_y; + if (MyNesMain.WaveRecorder.IsRecording) + { + MyNesMain.WaveRecorder.AddSample((short)audio_y); + } + audio_w_pos++; + audio_samples_added++; + } + audio_y = 0.0; + } + + private static void APUUpdatePlaybackWithoutFilters() + { + if (!SoundEnabled) + { + return; + } + audio_y = mix_table[sq1_output][sq2_output][trl_output][nos_output][dmc_output] / 2; + if (apu_use_external_sound) + { + audio_y = (audio_y + mem_board.APUGetSample() * audio_playback_amplitude) / 2.0; + } + audio_y_av += audio_y; + audio_y_timer += 1.0; + audio_timer += 1.0; + if (!(audio_timer >= audio_timer_ratio)) + { + return; + } + if (audio_y_timer > 0.0) + { + audio_y = audio_y_av / audio_y_timer; + } + else + { + audio_y = 0.0; + } + audio_y_av = 0.0; + audio_y_timer = 0.0; + audio_timer -= audio_timer_ratio; + if (audio_w_pos < audio_samples_count) + { + if (audio_y > (double)audio_playback_peek_limit) + { + audio_y = audio_playback_peek_limit; + } + if (audio_y < (double)(-audio_playback_peek_limit)) + { + audio_y = -audio_playback_peek_limit; + } + audio_samples[audio_w_pos] = (short)audio_y; + if (MyNesMain.WaveRecorder.IsRecording) + { + MyNesMain.WaveRecorder.AddSample((short)audio_y); + } + audio_w_pos++; + audio_samples_added++; + } + audio_y = 0.0; + } + + private static void GetPrec(int inVal, int inMax, int outMax, out int val) + { + val = outMax * inVal / inMax; + } + + private static void APUWriteState(ref BinaryWriter bin) + { + bin.Write(apu_reg_io_db); + bin.Write(apu_reg_io_addr); + bin.Write(apu_reg_access_happened); + bin.Write(apu_reg_access_w); + bin.Write(apu_odd_cycle); + bin.Write(apu_irq_enabled); + bin.Write(apu_irq_flag); + bin.Write(apu_irq_delta_occur); + bin.Write(apu_seq_mode); + bin.Write(apu_ferq_f); + bin.Write(apu_ferq_l); + bin.Write(apu_ferq_e); + bin.Write(apu_cycle_f); + bin.Write(apu_cycle_e); + bin.Write(apu_cycle_l); + bin.Write(apu_odd_l); + bin.Write(apu_cycle_f_t); + bin.Write(apu_check_irq); + bin.Write(apu_do_env); + bin.Write(apu_do_length); + SQ1WriteState(ref bin); + SQ2WriteState(ref bin); + NOSWriteState(ref bin); + TRLWriteState(ref bin); + DMCWriteState(ref bin); + } + + private static void APUReadState(ref BinaryReader bin) + { + apu_reg_io_db = bin.ReadByte(); + apu_reg_io_addr = bin.ReadByte(); + apu_reg_access_happened = bin.ReadBoolean(); + apu_reg_access_w = bin.ReadBoolean(); + apu_odd_cycle = bin.ReadBoolean(); + apu_irq_enabled = bin.ReadBoolean(); + apu_irq_flag = bin.ReadBoolean(); + apu_irq_delta_occur = bin.ReadBoolean(); + apu_seq_mode = bin.ReadBoolean(); + apu_ferq_f = bin.ReadInt32(); + apu_ferq_l = bin.ReadInt32(); + apu_ferq_e = bin.ReadInt32(); + apu_cycle_f = bin.ReadInt32(); + apu_cycle_e = bin.ReadInt32(); + apu_cycle_l = bin.ReadInt32(); + apu_odd_l = bin.ReadBoolean(); + apu_cycle_f_t = bin.ReadInt32(); + apu_check_irq = bin.ReadBoolean(); + apu_do_env = bin.ReadBoolean(); + apu_do_length = bin.ReadBoolean(); + SQ1ReadState(ref bin); + SQ2ReadState(ref bin); + NOSReadState(ref bin); + TRLReadState(ref bin); + DMCReadState(ref bin); + } + + private static byte register_pb() + { + return (byte)((cpu_flag_n ? 128u : 0u) | (cpu_flag_v ? 64u : 0u) | (cpu_flag_d ? 8u : 0u) | (cpu_flag_i ? 4u : 0u) | (cpu_flag_z ? 2u : 0u) | (cpu_flag_c ? 1u : 0u) | 0x30u); + } + + private static void CPUInitialize() + { + cpu_addressings = new Action[256] + { + Imp____, IndX_R_, ImA____, IndX_W_, Zpg_R__, Zpg_R__, Zpg_RW_, Zpg_W__, ImA____, Imm____, + ImA____, Imm____, Abs_R__, Abs_R__, Abs_RW_, Abs_W__, Imp____, IndY_R_, Imp____, IndY_W_, + ZpgX_R_, ZpgX_R_, ZpgX_RW, ZpgX_W_, ImA____, AbsY_R_, ImA____, AbsY_W_, AbsX_R_, AbsX_R_, + AbsX_RW, AbsX_W_, Imp____, IndX_R_, ImA____, IndX_W_, Zpg_R__, Zpg_R__, Zpg_RW_, Zpg_W__, + ImA____, Imm____, ImA____, Imm____, Abs_R__, Abs_R__, Abs_RW_, Abs_W__, Imp____, IndY_R_, + Imp____, IndY_W_, ZpgX_R_, ZpgX_R_, ZpgX_RW, ZpgX_W_, ImA____, AbsY_R_, ImA____, AbsY_W_, + AbsX_R_, AbsX_R_, AbsX_RW, AbsX_W_, ImA____, IndX_R_, ImA____, IndX_W_, Zpg_R__, Zpg_R__, + Zpg_RW_, Zpg_W__, ImA____, Imm____, ImA____, Imm____, Abs_W__, Abs_R__, Abs_RW_, Abs_W__, + Imp____, IndY_R_, Imp____, IndY_W_, ZpgX_R_, ZpgX_R_, ZpgX_RW, ZpgX_W_, ImA____, AbsY_R_, + ImA____, AbsY_W_, AbsX_R_, AbsX_R_, AbsX_RW, AbsX_W_, ImA____, IndX_R_, ImA____, IndX_W_, + Zpg_R__, Zpg_R__, Zpg_RW_, Zpg_W__, ImA____, Imm____, ImA____, Imm____, Imp____, Abs_R__, + Abs_RW_, Abs_W__, Imp____, IndY_R_, Imp____, IndY_W_, ZpgX_R_, ZpgX_R_, ZpgX_RW, ZpgX_W_, + ImA____, AbsY_R_, ImA____, AbsY_W_, AbsX_R_, AbsX_R_, AbsX_RW, AbsX_W_, Imm____, IndX_W_, + Imm____, IndX_W_, Zpg_W__, Zpg_W__, Zpg_W__, Zpg_W__, ImA____, Imm____, ImA____, Imm____, + Abs_W__, Abs_W__, Abs_W__, Abs_W__, Imp____, IndY_W_, Imp____, IndY_W_, ZpgX_W_, ZpgX_W_, + ZpgY_W_, ZpgY_W_, ImA____, AbsY_W_, ImA____, AbsY_W_, Abs_W__, AbsX_W_, Abs_W__, AbsY_W_, + Imm____, IndX_R_, Imm____, IndX_R_, Zpg_R__, Zpg_R__, Zpg_R__, Zpg_R__, ImA____, Imm____, + ImA____, Imm____, Abs_R__, Abs_R__, Abs_R__, Abs_R__, Imp____, IndY_R_, Imp____, IndY_R_, + ZpgX_R_, ZpgX_R_, ZpgY_R_, ZpgY_R_, ImA____, AbsY_R_, ImA____, AbsY_R_, AbsX_R_, AbsX_R_, + AbsY_R_, AbsY_R_, Imm____, IndX_R_, Imm____, IndX_R_, Zpg_R__, Zpg_R__, Zpg_RW_, Zpg_R__, + ImA____, Imm____, ImA____, Imm____, Abs_R__, Abs_R__, Abs_RW_, Abs_R__, Imp____, IndY_R_, + Imp____, IndY_RW, ZpgX_R_, ZpgX_R_, ZpgX_RW, ZpgX_RW, ImA____, AbsY_R_, ImA____, AbsY_RW, + AbsX_R_, AbsX_R_, AbsX_RW, AbsX_RW, Imm____, IndX_R_, Imm____, IndX_W_, Zpg_R__, Zpg_R__, + Zpg_RW_, Zpg_W__, ImA____, Imm____, ImA____, Imm____, Abs_R__, Abs_R__, Abs_RW_, Abs_W__, + Imp____, IndY_R_, Imp____, IndY_W_, ZpgX_R_, ZpgX_R_, ZpgX_RW, ZpgX_W_, ImA____, AbsY_R_, + ImA____, AbsY_W_, AbsX_R_, AbsX_R_, AbsX_RW, AbsX_W_ + }; + cpu_instructions = new Action[256] + { + BRK__, ORA__, NOP__, SLO__, NOP__, ORA__, ASL_M, SLO__, PHP__, ORA__, + ASL_A, ANC__, NOP__, ORA__, ASL_M, SLO__, BPL__, ORA__, NOP__, SLO__, + NOP__, ORA__, ASL_M, SLO__, CLC__, ORA__, NOP__, SLO__, NOP__, ORA__, + ASL_M, SLO__, JSR__, AND__, NOP__, RLA__, BIT__, AND__, ROL_M, RLA__, + PLP__, AND__, ROL_A, ANC__, BIT__, AND__, ROL_M, RLA__, BMI__, AND__, + NOP__, RLA__, NOP__, AND__, ROL_M, RLA__, SEC__, AND__, NOP__, RLA__, + NOP__, AND__, ROL_M, RLA__, RTI__, EOR__, NOP__, SRE__, NOP__, EOR__, + LSR_M, SRE__, PHA__, EOR__, LSR_A, ALR__, JMP__, EOR__, LSR_M, SRE__, + BVC__, EOR__, NOP__, SRE__, NOP__, EOR__, LSR_M, SRE__, CLI__, EOR__, + NOP__, SRE__, NOP__, EOR__, LSR_M, SRE__, RTS__, ADC__, NOP__, RRA__, + NOP__, ADC__, ROR_M, RRA__, PLA__, ADC__, ROR_A, ARR__, JMP_I, ADC__, + ROR_M, RRA__, BVS__, ADC__, NOP__, RRA__, NOP__, ADC__, ROR_M, RRA__, + SEI__, ADC__, NOP__, RRA__, NOP__, ADC__, ROR_M, RRA__, NOP__, STA__, + NOP__, SAX__, STY__, STA__, STX__, SAX__, DEY__, NOP__, TXA__, XAA__, + STY__, STA__, STX__, SAX__, BCC__, STA__, NOP__, AHX__, STY__, STA__, + STX__, SAX__, TYA__, STA__, TXS__, XAS__, SHY__, STA__, SHX__, AHX__, + LDY__, LDA__, LDX__, LAX__, LDY__, LDA__, LDX__, LAX__, TAY__, LDA__, + TAX__, LAX__, LDY__, LDA__, LDX__, LAX__, BCS__, LDA__, NOP__, LAX__, + LDY__, LDA__, LDX__, LAX__, CLV__, LDA__, TSX__, LAR__, LDY__, LDA__, + LDX__, LAX__, CPY__, CMP__, NOP__, DCP__, CPY__, CMP__, DEC__, DCP__, + INY__, CMP__, DEX__, AXS__, CPY__, CMP__, DEC__, DCP__, BNE__, CMP__, + NOP__, DCP__, NOP__, CMP__, DEC__, DCP__, CLD__, CMP__, NOP__, DCP__, + NOP__, CMP__, DEC__, DCP__, CPX__, SBC__, NOP__, ISC__, CPX__, SBC__, + INC__, ISC__, INX__, SBC__, NOP__, SBC__, CPX__, SBC__, INC__, ISC__, + BEQ__, SBC__, NOP__, ISC__, NOP__, SBC__, INC__, ISC__, SED__, SBC__, + NOP__, ISC__, NOP__, SBC__, INC__, ISC__ + }; + } + + private static void CPUClock() + { + Read(ref cpu_reg_pc.v, out cpu_opcode); + cpu_reg_pc.v++; + cpu_addressings[cpu_opcode](); + cpu_instructions[cpu_opcode](); + if (CPU_IRQ_PIN || CPU_NMI_PIN) + { + Read(ref cpu_reg_pc.v, out cpu_dummy); + Read(ref cpu_reg_pc.v, out cpu_dummy); + Interrupt(); + } + } + + private static void CPUHardReset() + { + cpu_reg_a = 0; + cpu_reg_x = 0; + cpu_reg_y = 0; + cpu_reg_sp.l = 253; + cpu_reg_sp.h = 1; + ushort addr = 65532; + mem_board.ReadPRG(ref addr, out cpu_reg_pc.l); + addr++; + mem_board.ReadPRG(ref addr, out cpu_reg_pc.h); + register_p = 0; + cpu_flag_i = true; + cpu_reg_ea.v = 0; + cpu_opcode = 0; + CPU_IRQ_PIN = false; + CPU_NMI_PIN = false; + cpu_suspend_nmi = false; + cpu_suspend_irq = false; + IRQFlags = 0; + } + + private static void CPUSoftReset() + { + cpu_flag_i = true; + cpu_reg_sp.v -= 3; + ushort addr = 65532; + Read(ref addr, out cpu_reg_pc.l); + addr++; + Read(ref addr, out cpu_reg_pc.h); + } + + private static void Imp____() + { + } + + private static void IndX_R_() + { + temp_add.h = 0; + Read(ref cpu_reg_pc.v, out temp_add.l); + cpu_reg_pc.v++; + Read(ref temp_add.v, out cpu_dummy); + temp_add.l += cpu_reg_x; + Read(ref temp_add.v, out cpu_reg_ea.l); + temp_add.l++; + Read(ref temp_add.v, out cpu_reg_ea.h); + Read(ref cpu_reg_ea.v, out cpu_m); + } + + private static void IndX_W_() + { + temp_add.h = 0; + Read(ref cpu_reg_pc.v, out temp_add.l); + cpu_reg_pc.v++; + Read(ref temp_add.v, out cpu_dummy); + temp_add.l += cpu_reg_x; + Read(ref temp_add.v, out cpu_reg_ea.l); + temp_add.l++; + Read(ref temp_add.v, out cpu_reg_ea.h); + } + + private static void IndX_RW() + { + temp_add.h = 0; + Read(ref cpu_reg_pc.v, out temp_add.l); + cpu_reg_pc.v++; + Read(ref temp_add.v, out cpu_dummy); + temp_add.l += cpu_reg_x; + Read(ref temp_add.v, out cpu_reg_ea.l); + temp_add.l++; + Read(ref temp_add.v, out cpu_reg_ea.h); + Read(ref cpu_reg_ea.v, out cpu_m); + } + + private static void IndY_R_() + { + temp_add.h = 0; + Read(ref cpu_reg_pc.v, out temp_add.l); + cpu_reg_pc.v++; + Read(ref temp_add.v, out cpu_reg_ea.l); + temp_add.l++; + Read(ref temp_add.v, out cpu_reg_ea.h); + cpu_reg_ea.l += cpu_reg_y; + Read(ref cpu_reg_ea.v, out cpu_m); + if (cpu_reg_ea.l < cpu_reg_y) + { + cpu_reg_ea.h++; + Read(ref cpu_reg_ea.v, out cpu_m); + } + } + + private static void IndY_W_() + { + temp_add.h = 0; + Read(ref cpu_reg_pc.v, out temp_add.l); + cpu_reg_pc.v++; + Read(ref temp_add.v, out cpu_reg_ea.l); + temp_add.l++; + Read(ref temp_add.v, out cpu_reg_ea.h); + cpu_reg_ea.l += cpu_reg_y; + Read(ref cpu_reg_ea.v, out cpu_m); + if (cpu_reg_ea.l < cpu_reg_y) + { + cpu_reg_ea.h++; + } + } + + private static void IndY_RW() + { + temp_add.h = 0; + Read(ref cpu_reg_pc.v, out temp_add.l); + cpu_reg_pc.v++; + Read(ref temp_add.v, out cpu_reg_ea.l); + temp_add.l++; + Read(ref temp_add.v, out cpu_reg_ea.h); + cpu_reg_ea.l += cpu_reg_y; + Read(ref cpu_reg_ea.v, out cpu_dummy); + if (cpu_reg_ea.l < cpu_reg_y) + { + cpu_reg_ea.h++; + } + Read(ref cpu_reg_ea.v, out cpu_m); + } + + private static void Zpg_R__() + { + cpu_reg_ea.h = 0; + Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); + cpu_reg_pc.v++; + Read(ref cpu_reg_ea.v, out cpu_m); + } + + private static void Zpg_W__() + { + cpu_reg_ea.h = 0; + Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); + cpu_reg_pc.v++; + } + + private static void Zpg_RW_() + { + cpu_reg_ea.h = 0; + Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); + cpu_reg_pc.v++; + Read(ref cpu_reg_ea.v, out cpu_m); + } + + private static void ZpgX_R_() + { + cpu_reg_ea.h = 0; + Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); + cpu_reg_pc.v++; + Read(ref cpu_reg_ea.v, out cpu_dummy); + cpu_reg_ea.l += cpu_reg_x; + Read(ref cpu_reg_ea.v, out cpu_m); + } + + private static void ZpgX_W_() + { + cpu_reg_ea.h = 0; + Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); + cpu_reg_pc.v++; + Read(ref cpu_reg_ea.v, out cpu_dummy); + cpu_reg_ea.l += cpu_reg_x; + } + + private static void ZpgX_RW() + { + cpu_reg_ea.h = 0; + Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); + cpu_reg_pc.v++; + Read(ref cpu_reg_ea.v, out cpu_dummy); + cpu_reg_ea.l += cpu_reg_x; + Read(ref cpu_reg_ea.v, out cpu_m); + } + + private static void ZpgY_R_() + { + cpu_reg_ea.h = 0; + Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); + cpu_reg_pc.v++; + Read(ref cpu_reg_ea.v, out cpu_dummy); + cpu_reg_ea.l += cpu_reg_y; + Read(ref cpu_reg_ea.v, out cpu_m); + } + + private static void ZpgY_W_() + { + cpu_reg_ea.h = 0; + Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); + cpu_reg_pc.v++; + Read(ref cpu_reg_ea.v, out cpu_dummy); + cpu_reg_ea.l += cpu_reg_y; + } + + private static void ZpgY_RW() + { + cpu_reg_ea.h = 0; + Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); + cpu_reg_pc.v++; + Read(ref cpu_reg_ea.v, out cpu_dummy); + cpu_reg_ea.l += cpu_reg_y; + Read(ref cpu_reg_ea.v, out cpu_m); + } + + private static void Imm____() + { + Read(ref cpu_reg_pc.v, out cpu_m); + cpu_reg_pc.v++; + } + + private static void ImA____() + { + Read(ref cpu_reg_pc.v, out cpu_dummy); + } + + private static void Abs_R__() + { + Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); + cpu_reg_pc.v++; + Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); + cpu_reg_pc.v++; + Read(ref cpu_reg_ea.v, out cpu_m); + } + + private static void Abs_W__() + { + Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); + cpu_reg_pc.v++; + Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); + cpu_reg_pc.v++; + } + + private static void Abs_RW_() + { + Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); + cpu_reg_pc.v++; + Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); + cpu_reg_pc.v++; + Read(ref cpu_reg_ea.v, out cpu_m); + } + + private static void AbsX_R_() + { + Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); + cpu_reg_pc.v++; + Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); + cpu_reg_pc.v++; + cpu_reg_ea.l += cpu_reg_x; + Read(ref cpu_reg_ea.v, out cpu_m); + if (cpu_reg_ea.l < cpu_reg_x) + { + cpu_reg_ea.h++; + Read(ref cpu_reg_ea.v, out cpu_m); + } + } + + private static void AbsX_W_() + { + Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); + cpu_reg_pc.v++; + Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); + cpu_reg_pc.v++; + cpu_reg_ea.l += cpu_reg_x; + Read(ref cpu_reg_ea.v, out cpu_m); + if (cpu_reg_ea.l < cpu_reg_x) + { + cpu_reg_ea.h++; + } + } + + private static void AbsX_RW() + { + Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); + cpu_reg_pc.v++; + Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); + cpu_reg_pc.v++; + cpu_reg_ea.l += cpu_reg_x; + Read(ref cpu_reg_ea.v, out cpu_dummy); + if (cpu_reg_ea.l < cpu_reg_x) + { + cpu_reg_ea.h++; + } + Read(ref cpu_reg_ea.v, out cpu_m); + } + + private static void AbsY_R_() + { + Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); + cpu_reg_pc.v++; + Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); + cpu_reg_pc.v++; + cpu_reg_ea.l += cpu_reg_y; + Read(ref cpu_reg_ea.v, out cpu_m); + if (cpu_reg_ea.l < cpu_reg_y) + { + cpu_reg_ea.h++; + Read(ref cpu_reg_ea.v, out cpu_m); + } + } + + private static void AbsY_W_() + { + Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); + cpu_reg_pc.v++; + Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); + cpu_reg_pc.v++; + cpu_reg_ea.l += cpu_reg_y; + Read(ref cpu_reg_ea.v, out cpu_m); + if (cpu_reg_ea.l < cpu_reg_y) + { + cpu_reg_ea.h++; + } + } + + private static void AbsY_RW() + { + Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); + cpu_reg_pc.v++; + Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); + cpu_reg_pc.v++; + cpu_reg_ea.l += cpu_reg_y; + Read(ref cpu_reg_ea.v, out cpu_m); + if (cpu_reg_ea.l < cpu_reg_y) + { + cpu_reg_ea.h++; + } + Read(ref cpu_reg_ea.v, out cpu_m); + } + + private static void Interrupt() + { + Push(ref cpu_reg_pc.h); + Push(ref cpu_reg_pc.l); + cpu_dummy = ((cpu_opcode == 0) ? register_pb() : register_p); + Push(ref cpu_dummy); + temp_add.v = InterruptVector; + cpu_suspend_nmi = true; + cpu_flag_i = true; + CPU_NMI_PIN = false; + Read(ref temp_add.v, out cpu_reg_pc.l); + temp_add.v++; + Read(ref temp_add.v, out cpu_reg_pc.h); + cpu_suspend_nmi = false; + } + + private static void Branch(ref bool condition) + { + Read(ref cpu_reg_pc.v, out cpu_byte_temp); + cpu_reg_pc.v++; + if (!condition) + { + return; + } + cpu_suspend_irq = true; + Read(ref cpu_reg_pc.v, out cpu_dummy); + cpu_reg_pc.l += cpu_byte_temp; + cpu_suspend_irq = false; + if (cpu_byte_temp >= 128) + { + if (cpu_reg_pc.l >= cpu_byte_temp) + { + Read(ref cpu_reg_pc.v, out cpu_dummy); + cpu_reg_pc.h--; + } + } + else if (cpu_reg_pc.l < cpu_byte_temp) + { + Read(ref cpu_reg_pc.v, out cpu_dummy); + cpu_reg_pc.h++; + } + } + + private static void Push(ref byte val) + { + Write(ref cpu_reg_sp.v, ref val); + cpu_reg_sp.l--; + } + + private static void Pull(out byte val) + { + cpu_reg_sp.l++; + Read(ref cpu_reg_sp.v, out val); + } + + private static void ADC__() + { + cpu_int_temp = cpu_reg_a + cpu_m + (cpu_flag_c ? 1 : 0); + cpu_flag_v = ((cpu_int_temp ^ cpu_reg_a) & (cpu_int_temp ^ cpu_m) & 0x80) != 0; + cpu_flag_n = (cpu_int_temp & 0x80) != 0; + cpu_flag_z = (cpu_int_temp & 0xFF) == 0; + cpu_flag_c = cpu_int_temp >> 8 != 0; + cpu_reg_a = (byte)((uint)cpu_int_temp & 0xFFu); + } + + private static void AHX__() + { + cpu_byte_temp = (byte)((uint)(cpu_reg_a & cpu_reg_x) & 7u); + Write(ref cpu_reg_ea.v, ref cpu_byte_temp); + } + + private static void ALR__() + { + cpu_reg_a &= cpu_m; + cpu_flag_c = (cpu_reg_a & 1) != 0; + cpu_reg_a >>= 1; + cpu_flag_n = (cpu_reg_a & 0x80) != 0; + cpu_flag_z = cpu_reg_a == 0; + } + + private static void ANC__() + { + cpu_reg_a &= cpu_m; + cpu_flag_n = (cpu_reg_a & 0x80) != 0; + cpu_flag_z = cpu_reg_a == 0; + cpu_flag_c = (cpu_reg_a & 0x80) != 0; + } + + private static void AND__() + { + cpu_reg_a &= cpu_m; + cpu_flag_n = (cpu_reg_a & 0x80) == 128; + cpu_flag_z = cpu_reg_a == 0; + } + + private static void ARR__() + { + cpu_reg_a = (byte)((uint)((cpu_m & cpu_reg_a) >> 1) | (cpu_flag_c ? 128u : 0u)); + cpu_flag_z = (cpu_reg_a & 0xFF) == 0; + cpu_flag_n = (cpu_reg_a & 0x80) != 0; + cpu_flag_c = (cpu_reg_a & 0x40) != 0; + cpu_flag_v = (((cpu_reg_a << 1) ^ cpu_reg_a) & 0x40) != 0; + } + + private static void AXS__() + { + cpu_int_temp = (cpu_reg_a & cpu_reg_x) - cpu_m; + cpu_flag_n = (cpu_int_temp & 0x80) != 0; + cpu_flag_z = (cpu_int_temp & 0xFF) == 0; + cpu_flag_c = ~cpu_int_temp >> 8 != 0; + cpu_reg_x = (byte)((uint)cpu_int_temp & 0xFFu); + } + + private static void ASL_M() + { + cpu_flag_c = (cpu_m & 0x80) == 128; + Write(ref cpu_reg_ea.v, ref cpu_m); + cpu_m = (byte)((uint)(cpu_m << 1) & 0xFEu); + Write(ref cpu_reg_ea.v, ref cpu_m); + cpu_flag_n = (cpu_m & 0x80) == 128; + cpu_flag_z = cpu_m == 0; + } + + private static void ASL_A() + { + cpu_flag_c = (cpu_reg_a & 0x80) == 128; + cpu_reg_a = (byte)((uint)(cpu_reg_a << 1) & 0xFEu); + cpu_flag_n = (cpu_reg_a & 0x80) == 128; + cpu_flag_z = cpu_reg_a == 0; + } + + private static void BCC__() + { + cpu_bool_tmp = !cpu_flag_c; + Branch(ref cpu_bool_tmp); + } + + private static void BCS__() + { + Branch(ref cpu_flag_c); + } + + private static void BEQ__() + { + Branch(ref cpu_flag_z); + } + + private static void BIT__() + { + cpu_flag_n = (cpu_m & 0x80) != 0; + cpu_flag_v = (cpu_m & 0x40) != 0; + cpu_flag_z = (cpu_m & cpu_reg_a) == 0; + } + + private static void BRK__() + { + Read(ref cpu_reg_pc.v, out cpu_dummy); + cpu_reg_pc.v++; + Interrupt(); + } + + private static void BPL__() + { + cpu_bool_tmp = !cpu_flag_n; + Branch(ref cpu_bool_tmp); + } + + private static void BNE__() + { + cpu_bool_tmp = !cpu_flag_z; + Branch(ref cpu_bool_tmp); + } + + private static void BMI__() + { + Branch(ref cpu_flag_n); + } + + private static void BVC__() + { + cpu_bool_tmp = !cpu_flag_v; + Branch(ref cpu_bool_tmp); + } + + private static void BVS__() + { + Branch(ref cpu_flag_v); + } + + private static void SED__() + { + cpu_flag_d = true; + } + + private static void CLC__() + { + cpu_flag_c = false; + } + + private static void CLD__() + { + cpu_flag_d = false; + } + + private static void CLV__() + { + cpu_flag_v = false; + } + + private static void CMP__() + { + cpu_int_temp = cpu_reg_a - cpu_m; + cpu_flag_n = (cpu_int_temp & 0x80) == 128; + cpu_flag_c = cpu_reg_a >= cpu_m; + cpu_flag_z = cpu_int_temp == 0; + } + + private static void CPX__() + { + cpu_int_temp = cpu_reg_x - cpu_m; + cpu_flag_n = (cpu_int_temp & 0x80) == 128; + cpu_flag_c = cpu_reg_x >= cpu_m; + cpu_flag_z = cpu_int_temp == 0; + } + + private static void CPY__() + { + cpu_int_temp = cpu_reg_y - cpu_m; + cpu_flag_n = (cpu_int_temp & 0x80) == 128; + cpu_flag_c = cpu_reg_y >= cpu_m; + cpu_flag_z = cpu_int_temp == 0; + } + + private static void CLI__() + { + cpu_flag_i = false; + } + + private static void DCP__() + { + Write(ref cpu_reg_ea.v, ref cpu_m); + cpu_m--; + Write(ref cpu_reg_ea.v, ref cpu_m); + cpu_int_temp = cpu_reg_a - cpu_m; + cpu_flag_n = (cpu_int_temp & 0x80) != 0; + cpu_flag_z = cpu_int_temp == 0; + cpu_flag_c = ~cpu_int_temp >> 8 != 0; + } + + private static void DEC__() + { + Write(ref cpu_reg_ea.v, ref cpu_m); + cpu_m--; + Write(ref cpu_reg_ea.v, ref cpu_m); + cpu_flag_n = (cpu_m & 0x80) == 128; + cpu_flag_z = cpu_m == 0; + } + + private static void DEY__() + { + cpu_reg_y--; + cpu_flag_z = cpu_reg_y == 0; + cpu_flag_n = (cpu_reg_y & 0x80) == 128; + } + + private static void DEX__() + { + cpu_reg_x--; + cpu_flag_z = cpu_reg_x == 0; + cpu_flag_n = (cpu_reg_x & 0x80) == 128; + } + + private static void EOR__() + { + cpu_reg_a ^= cpu_m; + cpu_flag_n = (cpu_reg_a & 0x80) == 128; + cpu_flag_z = cpu_reg_a == 0; + } + + private static void INC__() + { + Write(ref cpu_reg_ea.v, ref cpu_m); + cpu_m++; + Write(ref cpu_reg_ea.v, ref cpu_m); + cpu_flag_n = (cpu_m & 0x80) == 128; + cpu_flag_z = cpu_m == 0; + } + + private static void INX__() + { + cpu_reg_x++; + cpu_flag_z = cpu_reg_x == 0; + cpu_flag_n = (cpu_reg_x & 0x80) == 128; + } + + private static void INY__() + { + cpu_reg_y++; + cpu_flag_n = (cpu_reg_y & 0x80) == 128; + cpu_flag_z = cpu_reg_y == 0; + } + + private static void ISC__() + { + Read(ref cpu_reg_ea.v, out cpu_byte_temp); + Write(ref cpu_reg_ea.v, ref cpu_byte_temp); + cpu_byte_temp++; + Write(ref cpu_reg_ea.v, ref cpu_byte_temp); + cpu_int_temp = cpu_byte_temp ^ 0xFF; + cpu_int_temp1 = cpu_reg_a + cpu_int_temp + (cpu_flag_c ? 1 : 0); + cpu_flag_n = (cpu_int_temp1 & 0x80) != 0; + cpu_flag_v = ((cpu_int_temp1 ^ cpu_reg_a) & (cpu_int_temp1 ^ cpu_int_temp) & 0x80) != 0; + cpu_flag_z = (cpu_int_temp1 & 0xFF) == 0; + cpu_flag_c = cpu_int_temp1 >> 8 != 0; + cpu_reg_a = (byte)((uint)cpu_int_temp1 & 0xFFu); + } + + private static void JMP__() + { + cpu_reg_pc.v = cpu_reg_ea.v; + } + + private static void JMP_I() + { + Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); + cpu_reg_pc.v++; + Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); + Read(ref cpu_reg_ea.v, out cpu_reg_pc.l); + cpu_reg_ea.l++; + Read(ref cpu_reg_ea.v, out cpu_reg_pc.h); + } + + private static void JSR__() + { + Read(ref cpu_reg_pc.v, out cpu_reg_ea.l); + cpu_reg_pc.v++; + Write(ref cpu_reg_sp.v, ref cpu_reg_ea.l); + Push(ref cpu_reg_pc.h); + Push(ref cpu_reg_pc.l); + Read(ref cpu_reg_pc.v, out cpu_reg_ea.h); + cpu_reg_pc.v = cpu_reg_ea.v; + } + + private static void LAR__() + { + cpu_reg_sp.l &= cpu_m; + cpu_reg_a = cpu_reg_sp.l; + cpu_reg_x = cpu_reg_sp.l; + cpu_flag_n = (cpu_reg_sp.l & 0x80) != 0; + cpu_flag_z = (cpu_reg_sp.l & 0xFF) == 0; + } + + private static void LAX__() + { + cpu_reg_x = (cpu_reg_a = cpu_m); + cpu_flag_n = (cpu_reg_x & 0x80) != 0; + cpu_flag_z = (cpu_reg_x & 0xFF) == 0; + } + + private static void LDA__() + { + cpu_reg_a = cpu_m; + cpu_flag_n = (cpu_reg_a & 0x80) == 128; + cpu_flag_z = cpu_reg_a == 0; + } + + private static void LDX__() + { + cpu_reg_x = cpu_m; + cpu_flag_n = (cpu_reg_x & 0x80) == 128; + cpu_flag_z = cpu_reg_x == 0; + } + + private static void LDY__() + { + cpu_reg_y = cpu_m; + cpu_flag_n = (cpu_reg_y & 0x80) == 128; + cpu_flag_z = cpu_reg_y == 0; + } + + private static void LSR_A() + { + cpu_flag_c = (cpu_reg_a & 1) == 1; + cpu_reg_a >>= 1; + cpu_flag_z = cpu_reg_a == 0; + cpu_flag_n = (cpu_reg_a & 0x80) != 0; + } + + private static void LSR_M() + { + cpu_flag_c = (cpu_m & 1) == 1; + Write(ref cpu_reg_ea.v, ref cpu_m); + cpu_m >>= 1; + Write(ref cpu_reg_ea.v, ref cpu_m); + cpu_flag_z = cpu_m == 0; + cpu_flag_n = (cpu_m & 0x80) != 0; + } + + private static void NOP__() + { + } + + private static void ORA__() + { + cpu_reg_a |= cpu_m; + cpu_flag_n = (cpu_reg_a & 0x80) == 128; + cpu_flag_z = cpu_reg_a == 0; + } + + private static void PHA__() + { + Push(ref cpu_reg_a); + } + + private static void PHP__() + { + cpu_dummy = register_pb(); + Push(ref cpu_dummy); + } + + private static void PLA__() + { + Read(ref cpu_reg_sp.v, out cpu_dummy); + Pull(out cpu_reg_a); + cpu_flag_n = (cpu_reg_a & 0x80) == 128; + cpu_flag_z = cpu_reg_a == 0; + } + + private static void PLP__() + { + Read(ref cpu_reg_sp.v, out cpu_dummy); + Pull(out cpu_dummy); + register_p = cpu_dummy; + } + + private static void RLA__() + { + Read(ref cpu_reg_ea.v, out cpu_byte_temp); + Write(ref cpu_reg_ea.v, ref cpu_byte_temp); + cpu_dummy = (byte)((uint)(cpu_byte_temp << 1) | (cpu_flag_c ? 1u : 0u)); + Write(ref cpu_reg_ea.v, ref cpu_dummy); + cpu_flag_n = (cpu_dummy & 0x80) != 0; + cpu_flag_z = (cpu_dummy & 0xFF) == 0; + cpu_flag_c = (cpu_byte_temp & 0x80) != 0; + cpu_reg_a &= cpu_dummy; + cpu_flag_n = (cpu_reg_a & 0x80) != 0; + cpu_flag_z = (cpu_reg_a & 0xFF) == 0; + } + + private static void ROL_A() + { + cpu_byte_temp = (byte)((uint)(cpu_reg_a << 1) | (cpu_flag_c ? 1u : 0u)); + cpu_flag_n = (cpu_byte_temp & 0x80) != 0; + cpu_flag_z = (cpu_byte_temp & 0xFF) == 0; + cpu_flag_c = (cpu_reg_a & 0x80) != 0; + cpu_reg_a = cpu_byte_temp; + } + + private static void ROL_M() + { + Write(ref cpu_reg_ea.v, ref cpu_m); + cpu_byte_temp = (byte)((uint)(cpu_m << 1) | (cpu_flag_c ? 1u : 0u)); + Write(ref cpu_reg_ea.v, ref cpu_byte_temp); + cpu_flag_n = (cpu_byte_temp & 0x80) != 0; + cpu_flag_z = (cpu_byte_temp & 0xFF) == 0; + cpu_flag_c = (cpu_m & 0x80) != 0; + } + + private static void ROR_A() + { + cpu_byte_temp = (byte)((uint)(cpu_reg_a >> 1) | (cpu_flag_c ? 128u : 0u)); + cpu_flag_n = (cpu_byte_temp & 0x80) != 0; + cpu_flag_z = (cpu_byte_temp & 0xFF) == 0; + cpu_flag_c = (cpu_reg_a & 1) != 0; + cpu_reg_a = cpu_byte_temp; + } + + private static void ROR_M() + { + Write(ref cpu_reg_ea.v, ref cpu_m); + cpu_byte_temp = (byte)((uint)(cpu_m >> 1) | (cpu_flag_c ? 128u : 0u)); + Write(ref cpu_reg_ea.v, ref cpu_byte_temp); + cpu_flag_n = (cpu_byte_temp & 0x80) != 0; + cpu_flag_z = (cpu_byte_temp & 0xFF) == 0; + cpu_flag_c = (cpu_m & 1) != 0; + } + + private static void RRA__() + { + Read(ref cpu_reg_ea.v, out cpu_byte_temp); + Write(ref cpu_reg_ea.v, ref cpu_byte_temp); + cpu_dummy = (byte)((uint)(cpu_byte_temp >> 1) | (cpu_flag_c ? 128u : 0u)); + Write(ref cpu_reg_ea.v, ref cpu_dummy); + cpu_flag_n = (cpu_dummy & 0x80) != 0; + cpu_flag_z = (cpu_dummy & 0xFF) == 0; + cpu_flag_c = (cpu_byte_temp & 1) != 0; + cpu_byte_temp = cpu_dummy; + cpu_int_temp = cpu_reg_a + cpu_byte_temp + (cpu_flag_c ? 1 : 0); + cpu_flag_n = (cpu_int_temp & 0x80) != 0; + cpu_flag_v = ((cpu_int_temp ^ cpu_reg_a) & (cpu_int_temp ^ cpu_byte_temp) & 0x80) != 0; + cpu_flag_z = (cpu_int_temp & 0xFF) == 0; + cpu_flag_c = cpu_int_temp >> 8 != 0; + cpu_reg_a = (byte)cpu_int_temp; + } + + private static void RTI__() + { + Read(ref cpu_reg_sp.v, out cpu_dummy); + Pull(out cpu_dummy); + register_p = cpu_dummy; + Pull(out cpu_reg_pc.l); + Pull(out cpu_reg_pc.h); + } + + private static void RTS__() + { + Read(ref cpu_reg_sp.v, out cpu_dummy); + Pull(out cpu_reg_pc.l); + Pull(out cpu_reg_pc.h); + cpu_reg_pc.v++; + Read(ref cpu_reg_pc.v, out cpu_dummy); + } + + private static void SAX__() + { + cpu_dummy = (byte)(cpu_reg_x & cpu_reg_a); + Write(ref cpu_reg_ea.v, ref cpu_dummy); + } + + private static void SBC__() + { + cpu_m ^= byte.MaxValue; + cpu_int_temp = cpu_reg_a + cpu_m + (cpu_flag_c ? 1 : 0); + cpu_flag_n = (cpu_int_temp & 0x80) != 0; + cpu_flag_v = ((cpu_int_temp ^ cpu_reg_a) & (cpu_int_temp ^ cpu_m) & 0x80) != 0; + cpu_flag_z = (cpu_int_temp & 0xFF) == 0; + cpu_flag_c = cpu_int_temp >> 8 != 0; + cpu_reg_a = (byte)cpu_int_temp; + } + + private static void SEC__() + { + cpu_flag_c = true; + } + + private static void SEI__() + { + cpu_flag_i = true; + } + + private static void SHX__() + { + cpu_byte_temp = (byte)(cpu_reg_x & (cpu_reg_ea.h + 1)); + Read(ref cpu_reg_ea.v, out cpu_dummy); + cpu_reg_ea.l += cpu_reg_y; + if (cpu_reg_ea.l < cpu_reg_y) + { + cpu_reg_ea.h = cpu_byte_temp; + } + Write(ref cpu_reg_ea.v, ref cpu_byte_temp); + } + + private static void SHY__() + { + cpu_byte_temp = (byte)(cpu_reg_y & (cpu_reg_ea.h + 1)); + Read(ref cpu_reg_ea.v, out cpu_dummy); + cpu_reg_ea.l += cpu_reg_x; + if (cpu_reg_ea.l < cpu_reg_x) + { + cpu_reg_ea.h = cpu_byte_temp; + } + Write(ref cpu_reg_ea.v, ref cpu_byte_temp); + } + + private static void SLO__() + { + Read(ref cpu_reg_ea.v, out cpu_byte_temp); + cpu_flag_c = (cpu_byte_temp & 0x80) != 0; + Write(ref cpu_reg_ea.v, ref cpu_byte_temp); + cpu_byte_temp <<= 1; + Write(ref cpu_reg_ea.v, ref cpu_byte_temp); + cpu_flag_n = (cpu_byte_temp & 0x80) != 0; + cpu_flag_z = (cpu_byte_temp & 0xFF) == 0; + cpu_reg_a |= cpu_byte_temp; + cpu_flag_n = (cpu_reg_a & 0x80) != 0; + cpu_flag_z = (cpu_reg_a & 0xFF) == 0; + } + + private static void SRE__() + { + Read(ref cpu_reg_ea.v, out cpu_byte_temp); + cpu_flag_c = (cpu_byte_temp & 1) != 0; + Write(ref cpu_reg_ea.v, ref cpu_byte_temp); + cpu_byte_temp >>= 1; + Write(ref cpu_reg_ea.v, ref cpu_byte_temp); + cpu_flag_n = (cpu_byte_temp & 0x80) != 0; + cpu_flag_z = (cpu_byte_temp & 0xFF) == 0; + cpu_reg_a ^= cpu_byte_temp; + cpu_flag_n = (cpu_reg_a & 0x80) != 0; + cpu_flag_z = (cpu_reg_a & 0xFF) == 0; + } + + private static void STA__() + { + Write(ref cpu_reg_ea.v, ref cpu_reg_a); + } + + private static void STX__() + { + Write(ref cpu_reg_ea.v, ref cpu_reg_x); + } + + private static void STY__() + { + Write(ref cpu_reg_ea.v, ref cpu_reg_y); + } + + private static void TAX__() + { + cpu_reg_x = cpu_reg_a; + cpu_flag_n = (cpu_reg_x & 0x80) == 128; + cpu_flag_z = cpu_reg_x == 0; + } + + private static void TAY__() + { + cpu_reg_y = cpu_reg_a; + cpu_flag_n = (cpu_reg_y & 0x80) == 128; + cpu_flag_z = cpu_reg_y == 0; + } + + private static void TSX__() + { + cpu_reg_x = cpu_reg_sp.l; + cpu_flag_n = (cpu_reg_x & 0x80) != 0; + cpu_flag_z = cpu_reg_x == 0; + } + + private static void TXA__() + { + cpu_reg_a = cpu_reg_x; + cpu_flag_n = (cpu_reg_a & 0x80) == 128; + cpu_flag_z = cpu_reg_a == 0; + } + + private static void TXS__() + { + cpu_reg_sp.l = cpu_reg_x; + } + + private static void TYA__() + { + cpu_reg_a = cpu_reg_y; + cpu_flag_n = (cpu_reg_a & 0x80) == 128; + cpu_flag_z = cpu_reg_a == 0; + } + + private static void XAA__() + { + cpu_reg_a = (byte)(cpu_reg_x & cpu_m); + cpu_flag_n = (cpu_reg_a & 0x80) != 0; + cpu_flag_z = (cpu_reg_a & 0xFF) == 0; + } + + private static void XAS__() + { + cpu_reg_sp.l = (byte)(cpu_reg_a & cpu_reg_x); + Write(ref cpu_reg_ea.v, ref cpu_reg_sp.l); + } + + private static void CPUWriteState(ref BinaryWriter bin) + { + bin.Write(cpu_reg_pc.v); + bin.Write(cpu_reg_sp.v); + bin.Write(cpu_reg_ea.v); + bin.Write(cpu_reg_a); + bin.Write(cpu_reg_x); + bin.Write(cpu_reg_y); + bin.Write(cpu_flag_n); + bin.Write(cpu_flag_v); + bin.Write(cpu_flag_d); + bin.Write(cpu_flag_i); + bin.Write(cpu_flag_z); + bin.Write(cpu_flag_c); + bin.Write(cpu_m); + bin.Write(cpu_opcode); + bin.Write(cpu_byte_temp); + bin.Write(cpu_int_temp); + bin.Write(cpu_int_temp1); + bin.Write(cpu_dummy); + bin.Write(cpu_bool_tmp); + bin.Write(temp_add.v); + bin.Write(CPU_IRQ_PIN); + bin.Write(CPU_NMI_PIN); + bin.Write(cpu_suspend_nmi); + bin.Write(cpu_suspend_irq); + } + + private static void CPUReadState(ref BinaryReader bin) + { + cpu_reg_pc.v = bin.ReadUInt16(); + cpu_reg_sp.v = bin.ReadUInt16(); + cpu_reg_ea.v = bin.ReadUInt16(); + cpu_reg_a = bin.ReadByte(); + cpu_reg_x = bin.ReadByte(); + cpu_reg_y = bin.ReadByte(); + cpu_flag_n = bin.ReadBoolean(); + cpu_flag_v = bin.ReadBoolean(); + cpu_flag_d = bin.ReadBoolean(); + cpu_flag_i = bin.ReadBoolean(); + cpu_flag_z = bin.ReadBoolean(); + cpu_flag_c = bin.ReadBoolean(); + cpu_m = bin.ReadByte(); + cpu_opcode = bin.ReadByte(); + cpu_byte_temp = bin.ReadByte(); + cpu_int_temp = bin.ReadInt32(); + cpu_int_temp1 = bin.ReadInt32(); + cpu_dummy = bin.ReadByte(); + cpu_bool_tmp = bin.ReadBoolean(); + temp_add.v = bin.ReadUInt16(); + CPU_IRQ_PIN = bin.ReadBoolean(); + CPU_NMI_PIN = bin.ReadBoolean(); + cpu_suspend_nmi = bin.ReadBoolean(); + cpu_suspend_irq = bin.ReadBoolean(); + } + + private static void DMAHardReset() + { + dma_DMCDMAWaitCycles = 0; + dma_OAMDMAWaitCycles = 0; + dma_isOamDma = false; + dma_oamdma_i = 0; + dma_DMCOn = false; + dma_OAMOn = false; + dma_DMC_occurring = false; + dma_OAM_occurring = false; + dma_OAMFinishCounter = 0; + dma_Oamaddress = 0; + dma_OAMCYCLE = 0; + dma_latch = 0; + reg_2004 = 8196; + } + + private static void DMASoftReset() + { + dma_DMCDMAWaitCycles = 0; + dma_OAMDMAWaitCycles = 0; + dma_isOamDma = false; + dma_oamdma_i = 0; + dma_DMCOn = false; + dma_OAMOn = false; + dma_DMC_occurring = false; + dma_OAM_occurring = false; + dma_OAMFinishCounter = 0; + dma_Oamaddress = 0; + dma_OAMCYCLE = 0; + dma_latch = 0; + } + + internal static void AssertDMCDMA() + { + if (dma_OAM_occurring) + { + if (dma_OAMCYCLE < 508) + { + dma_DMCDMAWaitCycles = (BUS_RW ? 1 : 0); + } + else + { + dma_DMCDMAWaitCycles = 4 - (512 - dma_OAMCYCLE); + } + } + else + { + if (dma_DMC_occurring) + { + return; + } + dma_DMCDMAWaitCycles = (BUS_RW ? 3 : 2); + if (dma_OAMFinishCounter == 3) + { + dma_DMCDMAWaitCycles++; + } + } + dma_isOamDma = false; + dma_DMCOn = true; + } + + private static void AssertOAMDMA() + { + if (!dma_OAM_occurring) + { + dma_OAMDMAWaitCycles = (apu_odd_cycle ? 1 : 2); + dma_isOamDma = true; + dma_OAMOn = true; + } + } + + private static void DMAClock() + { + if (dma_OAMFinishCounter > 0) + { + dma_OAMFinishCounter--; + } + if (!BUS_RW) + { + if (dma_DMCDMAWaitCycles > 0) + { + dma_DMCDMAWaitCycles--; + } + if (dma_OAMDMAWaitCycles > 0) + { + dma_OAMDMAWaitCycles--; + } + return; + } + if (dma_DMCOn) + { + dma_DMC_occurring = true; + dma_DMCOn = false; + if (dma_DMCDMAWaitCycles > 0) + { + if (BUS_ADDRESS == 16406 || BUS_ADDRESS == 16407) + { + Read(ref BUS_ADDRESS, out dma_dummy); + dma_DMCDMAWaitCycles--; + while (dma_DMCDMAWaitCycles > 0) + { + EmuClockComponents(); + dma_DMCDMAWaitCycles--; + } + } + else + { + if (dma_DMCDMAWaitCycles > 0) + { + EmuClockComponents(); + dma_DMCDMAWaitCycles--; + } + while (dma_DMCDMAWaitCycles > 0) + { + Read(ref BUS_ADDRESS, out dma_dummy); + dma_DMCDMAWaitCycles--; + } + } + } + DMCDoDMA(); + dma_DMC_occurring = false; + } + if (!dma_OAMOn) + { + return; + } + dma_OAM_occurring = true; + dma_OAMOn = false; + if (dma_OAMDMAWaitCycles > 0) + { + if (BUS_ADDRESS == 16406 || BUS_ADDRESS == 16407) + { + Read(ref BUS_ADDRESS, out dma_dummy); + dma_OAMDMAWaitCycles--; + while (dma_OAMDMAWaitCycles > 0) + { + EmuClockComponents(); + dma_OAMDMAWaitCycles--; + } + } + else + { + if (dma_OAMDMAWaitCycles > 0) + { + EmuClockComponents(); + dma_OAMDMAWaitCycles--; + } + while (dma_OAMDMAWaitCycles > 0) + { + Read(ref BUS_ADDRESS, out dma_dummy); + dma_OAMDMAWaitCycles--; + } + } + } + dma_OAMCYCLE = 0; + for (dma_oamdma_i = 0; dma_oamdma_i < 256; dma_oamdma_i++) + { + Read(ref dma_Oamaddress, out dma_latch); + dma_OAMCYCLE++; + Write(ref reg_2004, ref dma_latch); + dma_OAMCYCLE++; + dma_Oamaddress = (ushort)(++dma_Oamaddress & 0xFFFFu); + } + dma_OAMCYCLE = 0; + dma_OAMFinishCounter = 5; + dma_OAM_occurring = false; + } + + private static void DMAWriteState(ref BinaryWriter bin) + { + bin.Write(dma_DMCDMAWaitCycles); + bin.Write(dma_OAMDMAWaitCycles); + bin.Write(dma_isOamDma); + bin.Write(dma_oamdma_i); + bin.Write(dma_DMCOn); + bin.Write(dma_OAMOn); + bin.Write(dma_DMC_occurring); + bin.Write(dma_OAM_occurring); + bin.Write(dma_OAMFinishCounter); + bin.Write(dma_Oamaddress); + bin.Write(dma_OAMCYCLE); + bin.Write(dma_latch); + bin.Write(dma_dummy); + } + + private static void DMAReadState(ref BinaryReader bin) + { + dma_DMCDMAWaitCycles = bin.ReadInt32(); + dma_OAMDMAWaitCycles = bin.ReadInt32(); + dma_isOamDma = bin.ReadBoolean(); + dma_oamdma_i = bin.ReadInt32(); + dma_DMCOn = bin.ReadBoolean(); + dma_OAMOn = bin.ReadBoolean(); + dma_DMC_occurring = bin.ReadBoolean(); + dma_OAM_occurring = bin.ReadBoolean(); + dma_OAMFinishCounter = bin.ReadInt32(); + dma_Oamaddress = bin.ReadUInt16(); + dma_OAMCYCLE = bin.ReadInt32(); + dma_latch = bin.ReadByte(); + dma_dummy = bin.ReadByte(); + } + + private static void PollInterruptStatus() + { + if (!cpu_suspend_nmi) + { + if (PPU_NMI_Current & !PPU_NMI_Old) + { + CPU_NMI_PIN = true; + } + PPU_NMI_Old = (PPU_NMI_Current = false); + } + if (!cpu_suspend_irq) + { + CPU_IRQ_PIN = !cpu_flag_i && IRQFlags != 0; + } + if (CPU_NMI_PIN) + { + InterruptVector = 65530; + } + else + { + InterruptVector = 65534; + } + } + + private static void InterruptsWriteState(ref BinaryWriter bin) + { + bin.Write(IRQFlags); + bin.Write(PPU_NMI_Current); + bin.Write(PPU_NMI_Old); + bin.Write(InterruptVector); + } + + private static void InterruptsReadState(ref BinaryReader bin) + { + IRQFlags = bin.ReadInt32(); + PPU_NMI_Current = bin.ReadBoolean(); + PPU_NMI_Old = bin.ReadBoolean(); + InterruptVector = bin.ReadUInt16(); + } + + public static void SetupGameGenie(bool IsGameGenieActive, GameGenieCode[] GameGenieCodes) + { + if (mem_board != null) + { + mem_board.SetupGameGenie(IsGameGenieActive, GameGenieCodes); + } + } + + private static void MEMInitialize(IRom rom) + { + Tracer.WriteLine("Looking for mapper # " + rom.MapperNumber + "...."); + if (MyNesMain.IsBoardExist(rom.MapperNumber)) + { + Tracer.WriteLine("Mapper # " + rom.MapperNumber + " located, assigning..."); + mem_board = MyNesMain.GetBoard(rom.MapperNumber); + Tracer.WriteInformation("Mapper # " + rom.MapperNumber + " assigned successfully."); + if (mem_board.HasIssues) + { + Tracer.WriteWarning(MNInterfaceLanguage.Mapper + " # " + mem_board.MapperNumber + " [" + mem_board.Name + "] " + MNInterfaceLanguage.Message_Error17); + MyNesMain.VideoProvider.WriteWarningNotification(MNInterfaceLanguage.Mapper + " # " + mem_board.MapperNumber + " [" + mem_board.Name + "] " + MNInterfaceLanguage.Message_Error17, instant: false); + } + } + else + { + Tracer.WriteError("Mapper # " + rom.MapperNumber + " IS NOT LOCATED, mapper is not supported or unable to find it."); + MyNesMain.VideoProvider.WriteErrorNotification(MNInterfaceLanguage.Mapper + " # " + rom.MapperNumber + " " + MNInterfaceLanguage.Message_Error14, instant: false); + mem_board = MyNesMain.GetBoard(0); + Tracer.WriteWarning("Mapper # 0 [NROM] will be used instead, assigned successfully."); + MyNesMain.VideoProvider.WriteErrorNotification(MNInterfaceLanguage.Mapper + " # 0 [NROM] " + MNInterfaceLanguage.Message_Error15, instant: false); + } + mem_read_accesses = new MemReadAccess[65536]; + mem_write_accesses = new MemWriteAccess[65536]; + MEMMap(MEMReadWRAM, new ushort[2] { 0, 4096 }); + MEMMap(MEMWriteWRAM, new ushort[2] { 0, 4096 }); + MEMMap(PPUIORead, new ushort[2] { 8192, 12288 }); + MEMMap(PPUIOWrite, new ushort[2] { 8192, 12288 }); + MEMMap(APUIORead, new ushort[1] { 16384 }); + MEMMap(APUIOWrite, new ushort[1] { 16384 }); + MEMMap(mem_board.ReadEX, new ushort[1] { 20480 }); + MEMMap(mem_board.WriteEX, new ushort[1] { 20480 }); + MEMMap(mem_board.ReadSRM, new ushort[2] { 24576, 28672 }); + MEMMap(mem_board.WriteSRM, new ushort[2] { 24576, 28672 }); + MEMMap(mem_board.ReadPRG, new ushort[8] { 32768, 36864, 40960, 45056, 49152, 53248, 57344, 61440 }); + MEMMap(mem_board.WritePRG, new ushort[8] { 32768, 36864, 40960, 45056, 49152, 53248, 57344, 61440 }); + mem_board.Initialize(rom); + mem_wram = new byte[2048]; + } + + private static void MEMHardReset() + { + mem_wram = new byte[2048]; + mem_wram[8] = 247; + mem_wram[9] = 239; + mem_wram[10] = 223; + mem_wram[15] = 191; + Tracer.WriteLine("Reading SRAM ..."); + SRAMFileName = Path.Combine(MyNesMain.EmuSettings.SRAMFolder, Path.GetFileNameWithoutExtension(CurrentFilePath) + ".srm"); + if (File.Exists(SRAMFileName)) + { + FileStream fileStream = new FileStream(SRAMFileName, FileMode.Open, FileAccess.Read); + byte[] array = new byte[fileStream.Length]; + fileStream.Read(array, 0, array.Length); + fileStream.Flush(); + fileStream.Close(); + byte[] outData = new byte[0]; + ZlipWrapper.DecompressData(array, out outData); + mem_board.LoadSRAM(outData); + Tracer.WriteLine("SRAM read successfully."); + } + else + { + Tracer.WriteLine("SRAM file not found; rom has no SRAM or file not exist."); + } + ReloadGameGenieCodes(); + mem_board.HardReset(); + } + + public static void ReloadGameGenieCodes() + { + Tracer.WriteLine("Reading game genie codes (if available)...."); + GMFileName = Path.Combine(MyNesMain.EmuSettings.GameGenieFolder, Path.GetFileNameWithoutExtension(CurrentFilePath) + ".txt"); + mem_board.GameGenieCodes = new GameGenieCode[0]; + if (File.Exists(GMFileName)) + { + XmlReaderSettings xmlReaderSettings = new XmlReaderSettings(); + xmlReaderSettings.DtdProcessing = DtdProcessing.Ignore; + xmlReaderSettings.IgnoreWhitespace = true; + XmlReader xmlReader = XmlReader.Create(GMFileName, xmlReaderSettings); + xmlReader.Read(); + xmlReader.Read(); + if (xmlReader.Name != "MyNesGameGenieCodesList") + { + xmlReader.Close(); + return; + } + GameGenie gameGenie = new GameGenie(); + List list = new List(); + while (xmlReader.Read()) + { + if (xmlReader.Name == "Code") + { + GameGenieCode item = default(GameGenieCode); + item.Enabled = true; + xmlReader.MoveToAttribute("code"); + item.Name = xmlReader.Value.ToString(); + if (item.Name.Length == 6) + { + item.Address = gameGenie.GetGGAddress(gameGenie.GetCodeAsHEX(item.Name), 6) | 0x8000; + item.Value = gameGenie.GetGGValue(gameGenie.GetCodeAsHEX(item.Name), 6); + item.IsCompare = false; + } + else + { + item.Address = gameGenie.GetGGAddress(gameGenie.GetCodeAsHEX(item.Name), 8) | 0x8000; + item.Value = gameGenie.GetGGValue(gameGenie.GetCodeAsHEX(item.Name), 8); + item.Compare = gameGenie.GetGGCompareValue(gameGenie.GetCodeAsHEX(item.Name)); + item.IsCompare = true; + } + list.Add(item); + } + } + xmlReader.Close(); + if (list.Count > 0) + { + mem_board.GameGenieCodes = list.ToArray(); + Tracer.WriteInformation("Game Genie codes loaded successfully, total of " + list.Count); + } + else + { + Tracer.WriteError("There is no Game Genie code in the file to load."); + } + } + else + { + Tracer.WriteWarning("No Game Genie file found for this game."); + } + } + + private static void MEMMap(MemReadAccess readAccess, ushort[] addresses) + { + for (int i = 0; i < addresses.Length; i++) + { + mem_read_accesses[(addresses[i] & 0xF000) >> 12] = readAccess; + } + } + + private static void MEMMap(MemWriteAccess writeAccess, ushort[] addresses) + { + for (int i = 0; i < addresses.Length; i++) + { + mem_write_accesses[(addresses[i] & 0xF000) >> 12] = writeAccess; + } + } + + private static void MEMReadWRAM(ref ushort addr, out byte value) + { + value = mem_wram[addr & 0x7FF]; + } + + private static void MEMWriteWRAM(ref ushort addr, ref byte value) + { + mem_wram[addr & 0x7FF] = value; + } + + internal static void Read(ref ushort addr, out byte value) + { + BUS_RW = true; + BUS_ADDRESS = addr; + EmuClockComponents(); + mem_read_accesses[(addr & 0xF000) >> 12](ref addr, out value); + } + + private static void Write(ref ushort addr, ref byte value) + { + BUS_RW = false; + BUS_ADDRESS = addr; + EmuClockComponents(); + mem_write_accesses[(addr & 0xF000) >> 12](ref addr, ref value); + } + + internal static void SaveSRAM() + { + if (mem_board != null && MyNesMain.EmuSettings.SaveSRAMAtEmuShutdown && mem_board.SRAMSaveRequired) + { + Tracer.WriteLine("Saving SRAM ..."); + byte[] outData = new byte[0]; + ZlipWrapper.CompressData(mem_board.GetSRAMBuffer(), out outData); + FileStream fileStream = new FileStream(SRAMFileName, FileMode.Create, FileAccess.Write); + fileStream.Write(outData, 0, outData.Length); + fileStream.Flush(); + fileStream.Close(); + Tracer.WriteLine("SRAM saved successfully."); + } + } + + private static void MEMWriteState(ref BinaryWriter bin) + { + mem_board.WriteStateData(ref bin); + bin.Write(mem_wram); + bin.Write(BUS_RW); + bin.Write(BUS_ADDRESS); + } + + private static void MEMReadState(ref BinaryReader bin) + { + mem_board.ReadStateData(ref bin); + bin.Read(mem_wram, 0, mem_wram.Length); + BUS_RW = bin.ReadBoolean(); + BUS_ADDRESS = bin.ReadUInt16(); + } + + private static void PORTSInitialize() + { + if (joypad1 == null) + { + joypad1 = new BlankJoypad(); + } + if (joypad2 == null) + { + joypad2 = new BlankJoypad(); + } + if (joypad3 == null) + { + joypad3 = new BlankJoypad(); + } + if (joypad4 == null) + { + joypad4 = new BlankJoypad(); + } + if (shortucts == null) + { + shortucts = new BlankShortuctsHandler(); + } + } + + public static void SetupShortcutsHandler(IShortcutsHandler hh) + { + shortucts = hh; + } + + public static void SetupControllers(IJoypadConnecter joy1, IJoypadConnecter joy2, IJoypadConnecter joy3, IJoypadConnecter joy4) + { + joypad1 = joy1; + joypad2 = joy2; + joypad3 = joy3; + joypad4 = joy4; + } + + public static void SetupVSUnisystemDIP(IVSUnisystemDIPConnecter uni) + { + } + + public static void SetupControllersP1(IJoypadConnecter joy) + { + joypad1 = joy; + } + + public static void SetupControllersP2(IJoypadConnecter joy) + { + joypad2 = joy; + } + + public static void SetupControllersP3(IJoypadConnecter joy) + { + joypad3 = joy; + } + + public static void SetupControllersP4(IJoypadConnecter joy) + { + joypad4 = joy; + } + + public static void DestroyJoypads() + { + if (joypad1 == null) + { + joypad1 = new BlankJoypad(); + } + else + { + joypad1.Destroy(); + } + if (joypad2 == null) + { + joypad2 = new BlankJoypad(); + } + else + { + joypad1.Destroy(); + } + if (joypad3 == null) + { + joypad3 = new BlankJoypad(); + } + else + { + joypad1.Destroy(); + } + if (joypad4 == null) + { + joypad4 = new BlankJoypad(); + } + else + { + joypad1.Destroy(); + } + } + + private static void PORTWriteState(ref BinaryWriter bin) + { + bin.Write(PORT0); + bin.Write(PORT1); + bin.Write(inputStrobe); + } + + private static void PORTReadState(ref BinaryReader bin) + { + PORT0 = bin.ReadInt32(); + PORT1 = bin.ReadInt32(); + inputStrobe = bin.ReadInt32(); + } + + public static void SetupPalette(int[] pal) + { + ppu_palette = pal; + } + + private static void PPUInitialize() + { + ppu_reg_update_func = new Action[8] { PPUOnRegister2000, PPUOnRegister2001, PPUOnRegister2002, PPUOnRegister2003, PPUOnRegister2004, PPUOnRegister2005, PPUOnRegister2006, PPUOnRegister2007 }; + ppu_reg_read_func = new Action[8] { PPURead2000, PPURead2001, PPURead2002, PPURead2003, PPURead2004, PPURead2005, PPURead2006, PPURead2007 }; + ppu_bkg_fetches = new Action[8] { PPUBKFetch0, PPUBKFetch1, PPUBKFetch2, PPUBKFetch3, PPUBKFetch4, PPUBKFetch5, PPUBKFetch6, PPUBKFetch7 }; + ppu_spr_fetches = new Action[8] { PPUBKFetch0, PPUBKFetch1, PPUBKFetch2, PPUBKFetch3, PPUSPRFetch0, PPUSPRFetch1, PPUSPRFetch2, PPUSPRFetch3 }; + ppu_oam_phases = new Action[9] { PPUOamPhase0, PPUOamPhase1, PPUOamPhase2, PPUOamPhase3, PPUOamPhase4, PPUOamPhase5, PPUOamPhase6, PPUOamPhase7, PPUOamPhase8 }; + ppu_h_clocks = new Action[341]; + ppu_h_clocks[0] = PPUHClock_000_Idle; + for (int i = 1; i < 257; i++) + { + ppu_h_clocks[i] = PPUHClock_1_256_BKGClocks; + } + for (int j = 257; j < 321; j++) + { + ppu_h_clocks[j] = PPUHClock_257_320_SPRClocks; + } + for (int k = 321; k < 337; k++) + { + ppu_h_clocks[k] = PPUHClock_321_336_DUMClocks; + } + for (int l = 337; l < 341; l++) + { + ppu_h_clocks[l] = PPUHClock_337_340_DUMClocks; + } + ppu_v_clocks = new Action[320]; + for (int m = 0; m < 240; m++) + { + ppu_v_clocks[m] = PPUScanlineRender; + } + ppu_v_clocks[240] = PPUScanlineVBLANK; + ppu_oam_bank = new byte[256]; + ppu_oam_bank_secondary = new byte[32]; + ppu_palette_bank = new byte[32]; + ppu_bkg_pixels = new int[512]; + ppu_spr_pixels = new int[512]; + ppu_screen_pixels = new int[61440]; + ppu_palette = NTSCPaletteGenerator.GeneratePalette(); + } + + private static void PPUHardReset() + { + ppu_reg_2001_grayscale = 243; + switch (Region) + { + case EmuRegion.NTSC: + ppu_clock_vblank_start = 241; + ppu_clock_vblank_end = 261; + ppu_use_odd_cycle = true; + break; + case EmuRegion.PALB: + ppu_clock_vblank_start = 241; + ppu_clock_vblank_end = 311; + ppu_use_odd_cycle = false; + break; + case EmuRegion.DENDY: + { + ppu_clock_vblank_start = 291; + ppu_clock_vblank_end = 311; + for (int i = 241; i <= 290; i++) + { + ppu_v_clocks[i] = PPUScanlineVBLANK; + } + ppu_use_odd_cycle = false; + break; + } + } + ppu_v_clocks[ppu_clock_vblank_start] = PPUScanlineVBLANKStart; + for (int j = ppu_clock_vblank_start + 1; j <= ppu_clock_vblank_end - 1; j++) + { + ppu_v_clocks[j] = PPUScanlineVBLANK; + } + ppu_v_clocks[ppu_clock_vblank_end] = PPUScanlineVBLANKEnd; + ppu_oam_bank = new byte[256]; + ppu_oam_bank_secondary = new byte[32]; + PPUOamReset(); + ppu_palette_bank = new byte[32] + { + 9, 1, 0, 1, 0, 2, 2, 13, 8, 16, + 8, 36, 0, 0, 4, 44, 9, 1, 52, 3, + 0, 4, 0, 20, 8, 58, 0, 2, 0, 32, + 44, 8 + }; + ppu_reg_io_db = 0; + ppu_reg_io_addr = 0; + ppu_reg_access_happened = false; + ppu_reg_access_w = false; + ppu_reg_2000_vram_address_increament = 1; + ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites = 0; + ppu_reg_2000_background_pattern_table_address = 0; + ppu_reg_2000_Sprite_size = 0; + ppu_reg_2000_VBI = false; + ppu_reg_2001_show_background_in_leftmost_8_pixels_of_screen = false; + ppu_reg_2001_show_sprites_in_leftmost_8_pixels_of_screen = false; + ppu_reg_2001_show_background = false; + ppu_reg_2001_show_sprites = false; + ppu_reg_2001_grayscale = 63; + ppu_reg_2001_emphasis = 0; + ppu_reg_2002_SpriteOverflow = false; + ppu_reg_2002_Sprite0Hit = false; + ppu_reg_2002_VblankStartedFlag = false; + ppu_reg_2003_oam_addr = 0; + ppu_is_sprfetch = false; + ppu_use_odd_swap = false; + ppu_clock_h = 0; + ppu_clock_v = 0; + } + + private static void PPUClock() + { + mem_board.OnPPUClock(); + ppu_v_clocks[ppu_clock_v](); + ppu_clock_h++; + if (ppu_clock_h >= 341) + { + mem_board.OnPPUScanlineTick(); + if (ppu_clock_v == ppu_clock_vblank_end) + { + ppu_clock_v = 0; + ppu_frame_finished = true; + } + else + { + ppu_clock_v++; + } + ppu_clock_h -= 341; + } + if (ppu_reg_access_happened) + { + ppu_reg_access_happened = false; + ppu_reg_update_func[ppu_reg_io_addr](); + } + } + + public static int GetPixel(int x, int y) + { + return ppu_screen_pixels[y * 256 + x]; + } + + private static void PPUScanlineRender() + { + ppu_h_clocks[ppu_clock_h](); + } + + private static void PPUScanlineVBLANKStart() + { + ppu_is_nmi_time = (ppu_clock_h >= 1) & (ppu_clock_h <= 3); + if (ppu_is_nmi_time) + { + if (ppu_clock_h == 1) + { + ppu_reg_2002_VblankStartedFlag = true; + } + PPU_NMI_Current = ppu_reg_2002_VblankStartedFlag & ppu_reg_2000_VBI; + } + } + + private static void PPUScanlineVBLANKEnd() + { + ppu_is_nmi_time = (ppu_clock_h >= 1) & (ppu_clock_h <= 3); + if (ppu_clock_h == 1) + { + ppu_reg_2002_Sprite0Hit = false; + ppu_reg_2002_VblankStartedFlag = false; + ppu_reg_2002_SpriteOverflow = false; + } + PPUScanlineRender(); + if (ppu_use_odd_cycle && ppu_clock_h == 339) + { + ppu_use_odd_swap = !ppu_use_odd_swap; + if (!ppu_use_odd_swap & (ppu_reg_2001_show_background || ppu_reg_2001_show_sprites)) + { + ppu_odd_swap_done = true; + ppu_clock_h++; + } + } + } + + private static void PPUScanlineVBLANK() + { + } + + private static void PPUHClock_000_Idle() + { + if (ppu_odd_swap_done) + { + ppu_bkg_fetches[1](); + ppu_odd_swap_done = false; + } + } + + private static void PPUHClock_1_256_BKGClocks() + { + if (ppu_reg_2001_show_background || ppu_reg_2001_show_sprites) + { + if (ppu_clock_v != ppu_clock_vblank_end) + { + if (ppu_clock_h > 0 && ppu_clock_h < 65) + { + ppu_oam_bank_secondary[(ppu_clock_h - 1) & 0x1F] = byte.MaxValue; + } + else + { + if (ppu_clock_h == 65) + { + PPUOamReset(); + } + if (((ppu_clock_h - 1) & 1) == 0) + { + PPUOamEvFetch(); + } + else + { + ppu_oam_phases[ppu_phase_index](); + } + if (ppu_clock_h == 256) + { + PPUOamClear(); + } + } + } + ppu_bkg_fetches[(ppu_clock_h - 1) & 7](); + if (ppu_clock_v < 240) + { + RenderPixel(); + } + } + else + { + if (ppu_clock_v >= 240) + { + return; + } + if ((ppu_vram_addr & 0x3F00) == 16128) + { + if ((ppu_vram_addr & 3) == 0) + { + ppu_screen_pixels[ppu_clock_h - 1 + ppu_clock_v * 256] = ppu_palette[(ppu_palette_bank[ppu_vram_addr & 0xC] & ppu_reg_2001_grayscale) | ppu_reg_2001_emphasis]; + } + else + { + ppu_screen_pixels[ppu_clock_h - 1 + ppu_clock_v * 256] = ppu_palette[(ppu_palette_bank[ppu_vram_addr & 0x1F] & ppu_reg_2001_grayscale) | ppu_reg_2001_emphasis]; + } + } + else + { + ppu_screen_pixels[ppu_clock_h - 1 + ppu_clock_v * 256] = ppu_palette[(ppu_palette_bank[0] & ppu_reg_2001_grayscale) | ppu_reg_2001_emphasis]; + } + } + } + + private static void PPUHClock_257_320_SPRClocks() + { + if (ppu_reg_2001_show_background || ppu_reg_2001_show_sprites) + { + ppu_spr_fetches[(ppu_clock_h - 1) & 7](); + if (ppu_clock_h == 257) + { + ppu_vram_addr = (ushort)((ppu_vram_addr & 0x7BE0u) | (ppu_vram_addr_temp & 0x41Fu)); + } + if (ppu_clock_v == ppu_clock_vblank_end && ppu_clock_h >= 280 && ppu_clock_h <= 304) + { + ppu_vram_addr = (ushort)((ppu_vram_addr & 0x41Fu) | (ppu_vram_addr_temp & 0x7BE0u)); + } + } + } + + private static void PPUHClock_321_336_DUMClocks() + { + if (ppu_reg_2001_show_background || ppu_reg_2001_show_sprites) + { + ppu_bkg_fetches[(ppu_clock_h - 1) & 7](); + } + } + + private static void PPUHClock_337_340_DUMClocks() + { + if (ppu_reg_2001_show_background || ppu_reg_2001_show_sprites) + { + ppu_bkg_fetches[(ppu_clock_h - 1) & 1](); + } + } + + private static void PPUBKFetch0() + { + ppu_bkgfetch_nt_addr = (ushort)(0x2000u | (ppu_vram_addr & 0xFFFu)); + mem_board.OnPPUAddressUpdate(ref ppu_bkgfetch_nt_addr); + } + + private static void PPUBKFetch1() + { + mem_board.ReadNMT(ref ppu_bkgfetch_nt_addr, out ppu_bkgfetch_nt_data); + } + + private static void PPUBKFetch2() + { + ppu_bkgfetch_at_addr = (ushort)(0x23C0u | (ppu_vram_addr & 0xC00u) | ((uint)(ppu_vram_addr >> 4) & 0x38u) | ((uint)(ppu_vram_addr >> 2) & 7u)); + mem_board.OnPPUAddressUpdate(ref ppu_bkgfetch_at_addr); + } + + private static void PPUBKFetch3() + { + mem_board.ReadNMT(ref ppu_bkgfetch_at_addr, out ppu_bkgfetch_at_data); + ppu_bkgfetch_at_data = (byte)(ppu_bkgfetch_at_data >> (((ppu_vram_addr >> 4) & 4) | (ppu_vram_addr & 2))); + } + + private static void PPUBKFetch4() + { + ppu_bkgfetch_lb_addr = (ushort)((uint)(ppu_reg_2000_background_pattern_table_address | (ppu_bkgfetch_nt_data << 4)) | ((uint)(ppu_vram_addr >> 12) & 7u)); + mem_board.OnPPUAddressUpdate(ref ppu_bkgfetch_lb_addr); + } + + private static void PPUBKFetch5() + { + mem_board.ReadCHR(ref ppu_bkgfetch_lb_addr, out ppu_bkgfetch_lb_data); + } + + private static void PPUBKFetch6() + { + ppu_bkgfetch_hb_addr = (ushort)((uint)(ppu_reg_2000_background_pattern_table_address | (ppu_bkgfetch_nt_data << 4)) | 8u | ((uint)(ppu_vram_addr >> 12) & 7u)); + mem_board.OnPPUAddressUpdate(ref ppu_bkgfetch_hb_addr); + } + + private static void PPUBKFetch7() + { + mem_board.ReadCHR(ref ppu_bkgfetch_hb_addr, out ppu_bkgfetch_hb_data); + ppu_bkg_render_pos = ppu_clock_h + 8; + ppu_bkg_render_pos %= 336; + if (ppu_clock_h == 256) + { + if ((ppu_vram_addr & 0x7000) != 28672) + { + ppu_vram_addr += 4096; + } + else + { + ppu_vram_addr ^= 28672; + switch (ppu_vram_addr & 0x3E0) + { + case 928: + ppu_vram_addr ^= 2976; + break; + case 992: + ppu_vram_addr ^= 992; + break; + default: + ppu_vram_addr += 32; + break; + } + } + } + else if ((ppu_vram_addr & 0x1F) == 31) + { + ppu_vram_addr ^= 1055; + } + else + { + ppu_vram_addr++; + } + for (ppu_bkg_render_i = 0; ppu_bkg_render_i < 8; ppu_bkg_render_i++) + { + ppu_bkg_render_tmp_val = ((ppu_bkgfetch_at_data << 2) & 0xC) | ((ppu_bkgfetch_lb_data >> 7) & 1) | ((ppu_bkgfetch_hb_data >> 6) & 2); + ppu_bkg_pixels[ppu_bkg_render_i + ppu_bkg_render_pos] = ppu_bkg_render_tmp_val; + ppu_bkgfetch_lb_data <<= 1; + ppu_bkgfetch_hb_data <<= 1; + } + } + + private static void PPUSPRFetch0() + { + ppu_sprfetch_slot = (ppu_clock_h - 1 >> 3) & 7; + ppu_sprfetch_slot = 7 - ppu_sprfetch_slot; + ppu_sprfetch_y_data = ppu_oam_bank_secondary[ppu_sprfetch_slot * 4]; + ppu_sprfetch_t_data = ppu_oam_bank_secondary[ppu_sprfetch_slot * 4 + 1]; + ppu_sprfetch_at_data = ppu_oam_bank_secondary[ppu_sprfetch_slot * 4 + 2]; + ppu_sprfetch_x_data = ppu_oam_bank_secondary[ppu_sprfetch_slot * 4 + 3]; + ppu_temp_comparator = (ppu_clock_v - ppu_sprfetch_y_data) ^ (((ppu_sprfetch_at_data & 0x80u) != 0) ? 15 : 0); + if (ppu_reg_2000_Sprite_size == 16) + { + ppu_sprfetch_lb_addr = (ushort)(((uint)(ppu_sprfetch_t_data << 12) & 0x1000u) | ((uint)(ppu_sprfetch_t_data << 4) & 0xFE0u) | ((uint)(ppu_temp_comparator << 1) & 0x10u) | ((uint)ppu_temp_comparator & 7u)); + } + else + { + ppu_sprfetch_lb_addr = (ushort)((uint)(ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites | (ppu_sprfetch_t_data << 4)) | ((uint)ppu_temp_comparator & 7u)); + } + mem_board.OnPPUAddressUpdate(ref ppu_sprfetch_lb_addr); + } + + private static void PPUSPRFetch1() + { + ppu_is_sprfetch = true; + mem_board.ReadCHR(ref ppu_sprfetch_lb_addr, out ppu_sprfetch_lb_data); + ppu_is_sprfetch = false; + if ((ppu_sprfetch_at_data & 0x40u) != 0) + { + ppu_sprfetch_lb_data = reverseLookup[ppu_sprfetch_lb_data]; + } + } + + private static void PPUSPRFetch2() + { + ppu_sprfetch_hb_addr = (ushort)(ppu_sprfetch_lb_addr | 8u); + mem_board.OnPPUAddressUpdate(ref ppu_sprfetch_hb_addr); + } + + private static void PPUSPRFetch3() + { + ppu_is_sprfetch = true; + mem_board.ReadCHR(ref ppu_sprfetch_hb_addr, out ppu_sprfetch_hb_data); + ppu_is_sprfetch = false; + if ((ppu_sprfetch_at_data & 0x40u) != 0) + { + ppu_sprfetch_hb_data = reverseLookup[ppu_sprfetch_hb_data]; + } + if (ppu_sprfetch_x_data == byte.MaxValue) + { + return; + } + for (ppu_bkg_render_i = 0; ppu_bkg_render_i < 8; ppu_bkg_render_i++) + { + if (ppu_sprfetch_x_data < byte.MaxValue) + { + ppu_bkg_render_tmp_val = ((ppu_sprfetch_at_data << 2) & 0xC) | ((ppu_sprfetch_lb_data >> 7) & 1) | ((ppu_sprfetch_hb_data >> 6) & 2); + if (((uint)ppu_bkg_render_tmp_val & 3u) != 0) + { + ppu_spr_pixels[ppu_sprfetch_x_data] = ppu_bkg_render_tmp_val; + if (ppu_sprfetch_slot == 0 && ppu_sprite0_should_hit) + { + ppu_spr_pixels[ppu_sprfetch_x_data] |= 16384; + } + if ((ppu_sprfetch_at_data & 0x20) == 0) + { + ppu_spr_pixels[ppu_sprfetch_x_data] |= 32768; + } + } + ppu_sprfetch_lb_data <<= 1; + ppu_sprfetch_hb_data <<= 1; + ppu_sprfetch_x_data++; + } + } + } + + private static void PPUOamReset() + { + ppu_oamev_n = 0; + ppu_oamev_m = 0; + ppu_oamev_slot = 0; + ppu_phase_index = 0; + ppu_sprite0_should_hit = false; + } + + private static void PPUOamClear() + { + for (int i = 0; i < ppu_spr_pixels.Length; i++) + { + ppu_spr_pixels[i] = 0; + } + } + + private static void PPUOamEvFetch() + { + ppu_fetch_data = ppu_oam_bank[ppu_oamev_n * 4 + ppu_oamev_m]; + } + + private static void PPUOamPhase0() + { + ppu_oamev_compare = ppu_clock_v >= ppu_fetch_data && ppu_clock_v < ppu_fetch_data + ppu_reg_2000_Sprite_size; + if (ppu_oamev_compare) + { + ppu_oam_bank_secondary[ppu_oamev_slot * 4] = ppu_fetch_data; + ppu_oamev_m = 1; + ppu_phase_index++; + if (ppu_oamev_n == 0) + { + ppu_sprite0_should_hit = true; + } + } + else + { + ppu_oamev_m = 0; + ppu_oamev_n++; + if (ppu_oamev_n == 64) + { + ppu_oamev_n = 0; + ppu_phase_index = 8; + } + } + } + + private static void PPUOamPhase1() + { + ppu_oam_bank_secondary[ppu_oamev_slot * 4 + ppu_oamev_m] = ppu_fetch_data; + ppu_oamev_m = 2; + ppu_phase_index++; + } + + private static void PPUOamPhase2() + { + ppu_oam_bank_secondary[ppu_oamev_slot * 4 + ppu_oamev_m] = ppu_fetch_data; + ppu_oamev_m = 3; + ppu_phase_index++; + } + + private static void PPUOamPhase3() + { + ppu_oam_bank_secondary[ppu_oamev_slot * 4 + ppu_oamev_m] = ppu_fetch_data; + ppu_oamev_m = 0; + ppu_oamev_n++; + ppu_oamev_slot++; + if (ppu_oamev_n == 64) + { + ppu_oamev_n = 0; + ppu_phase_index = 8; + } + else if (ppu_oamev_slot < 8) + { + ppu_phase_index = 0; + } + else if (ppu_oamev_slot == 8) + { + ppu_phase_index = 4; + } + } + + private static void PPUOamPhase4() + { + ppu_oamev_compare = ppu_clock_v >= ppu_fetch_data && ppu_clock_v < ppu_fetch_data + ppu_reg_2000_Sprite_size; + if (ppu_oamev_compare) + { + ppu_oamev_m = 1; + ppu_phase_index++; + ppu_reg_2002_SpriteOverflow = true; + return; + } + ppu_oamev_m++; + if (ppu_oamev_m == 4) + { + ppu_oamev_m = 0; + } + ppu_oamev_n++; + if (ppu_oamev_n == 64) + { + ppu_oamev_n = 0; + ppu_phase_index = 8; + } + else + { + ppu_phase_index = 4; + } + } + + private static void PPUOamPhase5() + { + ppu_oamev_m = 2; + ppu_phase_index++; + } + + private static void PPUOamPhase6() + { + ppu_oamev_m = 3; + ppu_phase_index++; + } + + private static void PPUOamPhase7() + { + ppu_oamev_m = 0; + ppu_oamev_n++; + if (ppu_oamev_n == 64) + { + ppu_oamev_n = 0; + } + ppu_phase_index = 8; + } + + private static void PPUOamPhase8() + { + ppu_oamev_n++; + if (ppu_oamev_n >= 64) + { + ppu_oamev_n = 0; + } + } + + private static void RenderPixel() + { + if (ppu_clock_v == ppu_clock_vblank_end) + { + return; + } + ppu_render_x = ppu_clock_h - 1; + ppu_render_y = ppu_clock_v * 256; + if (ppu_render_x < 8) + { + if (ppu_reg_2001_show_background_in_leftmost_8_pixels_of_screen) + { + ppu_bkg_current_pixel = 0x3F00 | ppu_bkg_pixels[ppu_render_x + ppu_vram_finex]; + } + else + { + ppu_bkg_current_pixel = 16128; + } + if (ppu_reg_2001_show_sprites_in_leftmost_8_pixels_of_screen) + { + ppu_spr_current_pixel = 0x3F10 | ppu_spr_pixels[ppu_render_x]; + } + else + { + ppu_spr_current_pixel = 16144; + } + } + else + { + if (!ppu_reg_2001_show_background) + { + ppu_bkg_current_pixel = 16128; + } + else + { + ppu_bkg_current_pixel = 0x3F00 | ppu_bkg_pixels[ppu_render_x + ppu_vram_finex]; + } + if (!ppu_reg_2001_show_sprites || ppu_clock_v == 0) + { + ppu_spr_current_pixel = 16144; + } + else + { + ppu_spr_current_pixel = 0x3F10 | ppu_spr_pixels[ppu_render_x]; + } + } + ppu_current_pixel = 0; + if (((uint)ppu_spr_current_pixel & 0x8000u) != 0) + { + ppu_current_pixel = ppu_spr_current_pixel; + } + else + { + ppu_current_pixel = ppu_bkg_current_pixel; + } + if ((ppu_bkg_current_pixel & 3) == 0) + { + ppu_current_pixel = ppu_spr_current_pixel; + } + else if ((ppu_spr_current_pixel & 3) == 0) + { + ppu_current_pixel = ppu_bkg_current_pixel; + } + else if (((uint)ppu_spr_pixels[ppu_render_x] & 0x4000u) != 0) + { + ppu_reg_2002_Sprite0Hit = true; + } + if ((ppu_current_pixel & 3) == 0) + { + ppu_screen_pixels[ppu_render_x + ppu_render_y] = ppu_palette[(ppu_palette_bank[ppu_current_pixel & 0xC] & ppu_reg_2001_grayscale) | ppu_reg_2001_emphasis]; + } + else + { + ppu_screen_pixels[ppu_render_x + ppu_render_y] = ppu_palette[(ppu_palette_bank[ppu_current_pixel & 0x1F] & ppu_reg_2001_grayscale) | ppu_reg_2001_emphasis]; + } + } + + private static void PPUIORead(ref ushort addr, out byte value) + { + ppu_reg_io_addr = (byte)(addr & 7u); + ppu_reg_access_happened = true; + ppu_reg_access_w = false; + ppu_reg_read_func[ppu_reg_io_addr](); + value = ppu_reg_io_db; + } + + private static void PPUIOWrite(ref ushort addr, ref byte value) + { + ppu_reg_io_addr = (byte)(addr & 7u); + ppu_reg_io_db = value; + ppu_reg_access_w = true; + ppu_reg_access_happened = true; + } + + private static void PPUOnRegister2000() + { + if (ppu_reg_access_w) + { + ppu_vram_addr_temp = (ushort)((ppu_vram_addr_temp & 0x73FFu) | (uint)((ppu_reg_io_db & 3) << 10)); + if ((ppu_reg_io_db & 4u) != 0) + { + ppu_reg_2000_vram_address_increament = 32; + } + else + { + ppu_reg_2000_vram_address_increament = 1; + } + if ((ppu_reg_io_db & 8u) != 0) + { + ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites = 4096; + } + else + { + ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites = 0; + } + if ((ppu_reg_io_db & 0x10u) != 0) + { + ppu_reg_2000_background_pattern_table_address = 4096; + } + else + { + ppu_reg_2000_background_pattern_table_address = 0; + } + if ((ppu_reg_io_db & 0x20u) != 0) + { + ppu_reg_2000_Sprite_size = 16; + } + else + { + ppu_reg_2000_Sprite_size = 8; + } + if (!ppu_reg_2000_VBI && (ppu_reg_io_db & 0x80u) != 0 && ppu_reg_2002_VblankStartedFlag) + { + PPU_NMI_Current = true; + } + ppu_reg_2000_VBI = (ppu_reg_io_db & 0x80) != 0; + if (!ppu_reg_2000_VBI && ppu_is_nmi_time) + { + PPU_NMI_Current = false; + } + } + } + + private static void PPUOnRegister2001() + { + if (ppu_reg_access_w) + { + ppu_reg_2001_show_background_in_leftmost_8_pixels_of_screen = (ppu_reg_io_db & 2) != 0; + ppu_reg_2001_show_sprites_in_leftmost_8_pixels_of_screen = (ppu_reg_io_db & 4) != 0; + ppu_reg_2001_show_background = (ppu_reg_io_db & 8) != 0; + ppu_reg_2001_show_sprites = (ppu_reg_io_db & 0x10) != 0; + ppu_reg_2001_grayscale = ((((uint)ppu_reg_io_db & (true ? 1u : 0u)) != 0) ? 48 : 63); + ppu_reg_2001_emphasis = (ppu_reg_io_db & 0xE0) << 1; + } + } + + private static void PPUOnRegister2002() + { + if (!ppu_reg_access_w) + { + ppu_vram_flip_flop = false; + ppu_reg_2002_VblankStartedFlag = false; + if (ppu_clock_v == ppu_clock_vblank_start) + { + PPU_NMI_Current = ppu_reg_2002_VblankStartedFlag & ppu_reg_2000_VBI; + } + } + } + + private static void PPUOnRegister2003() + { + if (ppu_reg_access_w) + { + ppu_reg_2003_oam_addr = ppu_reg_io_db; + } + } + + private static void PPUOnRegister2004() + { + if (ppu_reg_access_w) + { + if (ppu_clock_v < 240 && IsRenderingOn()) + { + ppu_reg_io_db = byte.MaxValue; + } + if ((ppu_reg_2003_oam_addr & 3) == 2) + { + ppu_reg_io_db &= 227; + } + ppu_oam_bank[ppu_reg_2003_oam_addr] = ppu_reg_io_db; + ppu_reg_2003_oam_addr = (byte)((uint)(ppu_reg_2003_oam_addr + 1) & 0xFFu); + } + } + + private static void PPUOnRegister2005() + { + if (ppu_reg_access_w) + { + if (!ppu_vram_flip_flop) + { + ppu_vram_addr_temp = (ushort)((ppu_vram_addr_temp & 0x7FE0u) | (uint)((ppu_reg_io_db & 0xF8) >> 3)); + ppu_vram_finex = (byte)(ppu_reg_io_db & 7u); + } + else + { + ppu_vram_addr_temp = (ushort)((ppu_vram_addr_temp & 0xC1Fu) | (uint)((ppu_reg_io_db & 7) << 12) | (uint)((ppu_reg_io_db & 0xF8) << 2)); + } + ppu_vram_flip_flop = !ppu_vram_flip_flop; + } + } + + private static void PPUOnRegister2006() + { + if (ppu_reg_access_w) + { + if (!ppu_vram_flip_flop) + { + ppu_vram_addr_temp = (ushort)((ppu_vram_addr_temp & 0xFFu) | (uint)((ppu_reg_io_db & 0x3F) << 8)); + } + else + { + ppu_vram_addr_temp = (ushort)((ppu_vram_addr_temp & 0x7F00u) | ppu_reg_io_db); + ppu_vram_addr = ppu_vram_addr_temp; + mem_board.OnPPUAddressUpdate(ref ppu_vram_addr); + } + ppu_vram_flip_flop = !ppu_vram_flip_flop; + } + } + + private static void PPUOnRegister2007() + { + if (ppu_reg_access_w) + { + ppu_vram_addr_access_temp = (ushort)(ppu_vram_addr & 0x3FFFu); + if (ppu_vram_addr_access_temp < 8192) + { + mem_board.WriteCHR(ref ppu_vram_addr_access_temp, ref ppu_reg_io_db); + } + else if (ppu_vram_addr_access_temp < 16128) + { + mem_board.WriteNMT(ref ppu_vram_addr_access_temp, ref ppu_reg_io_db); + } + else if ((ppu_vram_addr_access_temp & 3u) != 0) + { + ppu_palette_bank[ppu_vram_addr_access_temp & 0x1F] = ppu_reg_io_db; + } + else + { + ppu_palette_bank[ppu_vram_addr_access_temp & 0xC] = ppu_reg_io_db; + } + } + else + { + if ((ppu_vram_addr & 0x3F00) == 16128) + { + ppu_vram_addr_access_temp = (ushort)(ppu_vram_addr & 0x2FFFu); + } + else + { + ppu_vram_addr_access_temp = (ushort)(ppu_vram_addr & 0x3FFFu); + } + if (ppu_vram_addr_access_temp < 8192) + { + mem_board.ReadCHR(ref ppu_vram_addr_access_temp, out ppu_vram_data); + } + else if (ppu_vram_addr_access_temp < 16128) + { + mem_board.ReadNMT(ref ppu_vram_addr_access_temp, out ppu_vram_data); + } + } + ppu_vram_addr = (ushort)((uint)(ppu_vram_addr + ppu_reg_2000_vram_address_increament) & 0x7FFFu); + mem_board.OnPPUAddressUpdate(ref ppu_vram_addr); + } + + private static void PPURead2000() + { + } + + private static void PPURead2001() + { + } + + private static void PPURead2002() + { + ppu_reg_io_db = (byte)((ppu_reg_io_db & 0xDFu) | (ppu_reg_2002_SpriteOverflow ? 32u : 0u)); + ppu_reg_io_db = (byte)((ppu_reg_io_db & 0xBFu) | (ppu_reg_2002_Sprite0Hit ? 64u : 0u)); + ppu_reg_io_db = (byte)((ppu_reg_io_db & 0x7Fu) | (ppu_reg_2002_VblankStartedFlag ? 128u : 0u)); + } + + private static void PPURead2003() + { + } + + private static void PPURead2004() + { + ppu_reg_io_db = ppu_oam_bank[ppu_reg_2003_oam_addr]; + if (ppu_clock_v < 240 && IsRenderingOn()) + { + if (ppu_clock_h < 64) + { + ppu_reg_io_db = byte.MaxValue; + } + else if (ppu_clock_h < 192) + { + ppu_reg_io_db = ppu_oam_bank[(ppu_clock_h - 64 << 1) & 0xFC]; + } + else if (ppu_clock_h < 256) + { + ppu_reg_io_db = (((ppu_clock_h & 1) == 1) ? ppu_oam_bank[252] : ppu_oam_bank[(ppu_clock_h - 192 << 1) & 0xFC]); + } + else if (ppu_clock_h < 320) + { + ppu_reg_io_db = byte.MaxValue; + } + else + { + ppu_reg_io_db = ppu_oam_bank[0]; + } + } + } + + private static void PPURead2005() + { + } + + private static void PPURead2006() + { + } + + private static void PPURead2007() + { + ppu_vram_addr_access_temp = (ushort)(ppu_vram_addr & 0x3FFFu); + if (ppu_vram_addr_access_temp < 16128) + { + ppu_reg_io_db = ppu_vram_data; + } + else if ((ppu_vram_addr_access_temp & 3u) != 0) + { + ppu_reg_io_db = ppu_palette_bank[ppu_vram_addr_access_temp & 0x1F]; + } + else + { + ppu_reg_io_db = ppu_palette_bank[ppu_vram_addr_access_temp & 0xC]; + } + } + + internal static bool IsRenderingOn() + { + if (!ppu_reg_2001_show_background) + { + return ppu_reg_2001_show_sprites; + } + return true; + } + + internal static bool IsInRender() + { + if (ppu_clock_v >= 240) + { + return ppu_clock_v == ppu_clock_vblank_end; + } + return true; + } + + private static void PPUWriteState(ref BinaryWriter bin) + { + bin.Write(ppu_clock_h); + bin.Write(ppu_clock_v); + bin.Write(ppu_clock_vblank_start); + bin.Write(ppu_clock_vblank_end); + bin.Write(ppu_use_odd_cycle); + bin.Write(ppu_use_odd_swap); + bin.Write(ppu_is_nmi_time); + bin.Write(ppu_frame_finished); + bin.Write(ppu_oam_bank); + bin.Write(ppu_oam_bank_secondary); + bin.Write(ppu_palette_bank); + bin.Write(ppu_reg_io_db); + bin.Write(ppu_reg_io_addr); + bin.Write(ppu_reg_access_happened); + bin.Write(ppu_reg_access_w); + bin.Write(ppu_reg_2000_vram_address_increament); + bin.Write(ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites); + bin.Write(ppu_reg_2000_background_pattern_table_address); + bin.Write(ppu_reg_2000_Sprite_size); + bin.Write(ppu_reg_2000_VBI); + bin.Write(ppu_reg_2001_show_background_in_leftmost_8_pixels_of_screen); + bin.Write(ppu_reg_2001_show_sprites_in_leftmost_8_pixels_of_screen); + bin.Write(ppu_reg_2001_show_background); + bin.Write(ppu_reg_2001_show_sprites); + bin.Write(ppu_reg_2001_grayscale); + bin.Write(ppu_reg_2001_emphasis); + bin.Write(ppu_reg_2002_SpriteOverflow); + bin.Write(ppu_reg_2002_Sprite0Hit); + bin.Write(ppu_reg_2002_VblankStartedFlag); + bin.Write(ppu_reg_2003_oam_addr); + bin.Write(ppu_vram_addr); + bin.Write(ppu_vram_data); + bin.Write(ppu_vram_addr_temp); + bin.Write(ppu_vram_addr_access_temp); + bin.Write(ppu_vram_flip_flop); + bin.Write(ppu_vram_finex); + bin.Write(ppu_bkgfetch_nt_addr); + bin.Write(ppu_bkgfetch_nt_data); + bin.Write(ppu_bkgfetch_at_addr); + bin.Write(ppu_bkgfetch_at_data); + bin.Write(ppu_bkgfetch_lb_addr); + bin.Write(ppu_bkgfetch_lb_data); + bin.Write(ppu_bkgfetch_hb_addr); + bin.Write(ppu_bkgfetch_hb_data); + bin.Write(ppu_sprfetch_slot); + bin.Write(ppu_sprfetch_y_data); + bin.Write(ppu_sprfetch_t_data); + bin.Write(ppu_sprfetch_at_data); + bin.Write(ppu_sprfetch_x_data); + bin.Write(ppu_sprfetch_lb_addr); + bin.Write(ppu_sprfetch_lb_data); + bin.Write(ppu_sprfetch_hb_addr); + bin.Write(ppu_sprfetch_hb_data); + bin.Write(ppu_bkg_render_i); + bin.Write(ppu_bkg_render_pos); + bin.Write(ppu_bkg_render_tmp_val); + bin.Write(ppu_bkg_current_pixel); + bin.Write(ppu_spr_current_pixel); + bin.Write(ppu_current_pixel); + bin.Write(ppu_render_x); + bin.Write(0); + bin.Write(ppu_oamev_n); + bin.Write(ppu_oamev_m); + bin.Write(ppu_oamev_compare); + bin.Write(ppu_oamev_slot); + bin.Write(ppu_fetch_data); + bin.Write(ppu_phase_index); + bin.Write(ppu_sprite0_should_hit); + } + + private static void PPUReadState(ref BinaryReader bin) + { + ppu_clock_h = bin.ReadInt32(); + ppu_clock_v = bin.ReadUInt16(); + ppu_clock_vblank_start = bin.ReadUInt16(); + ppu_clock_vblank_end = bin.ReadUInt16(); + ppu_use_odd_cycle = bin.ReadBoolean(); + ppu_use_odd_swap = bin.ReadBoolean(); + ppu_is_nmi_time = bin.ReadBoolean(); + ppu_frame_finished = bin.ReadBoolean(); + bin.Read(ppu_oam_bank, 0, ppu_oam_bank.Length); + bin.Read(ppu_oam_bank_secondary, 0, ppu_oam_bank_secondary.Length); + bin.Read(ppu_palette_bank, 0, ppu_palette_bank.Length); + ppu_reg_io_db = bin.ReadByte(); + ppu_reg_io_addr = bin.ReadByte(); + ppu_reg_access_happened = bin.ReadBoolean(); + ppu_reg_access_w = bin.ReadBoolean(); + ppu_reg_2000_vram_address_increament = bin.ReadByte(); + ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites = bin.ReadUInt16(); + ppu_reg_2000_background_pattern_table_address = bin.ReadUInt16(); + ppu_reg_2000_Sprite_size = bin.ReadByte(); + ppu_reg_2000_VBI = bin.ReadBoolean(); + ppu_reg_2001_show_background_in_leftmost_8_pixels_of_screen = bin.ReadBoolean(); + ppu_reg_2001_show_sprites_in_leftmost_8_pixels_of_screen = bin.ReadBoolean(); + ppu_reg_2001_show_background = bin.ReadBoolean(); + ppu_reg_2001_show_sprites = bin.ReadBoolean(); + ppu_reg_2001_grayscale = bin.ReadInt32(); + ppu_reg_2001_emphasis = bin.ReadInt32(); + ppu_reg_2002_SpriteOverflow = bin.ReadBoolean(); + ppu_reg_2002_Sprite0Hit = bin.ReadBoolean(); + ppu_reg_2002_VblankStartedFlag = bin.ReadBoolean(); + ppu_reg_2003_oam_addr = bin.ReadByte(); + ppu_vram_addr = bin.ReadUInt16(); + ppu_vram_data = bin.ReadByte(); + ppu_vram_addr_temp = bin.ReadUInt16(); + ppu_vram_addr_access_temp = bin.ReadUInt16(); + ppu_vram_flip_flop = bin.ReadBoolean(); + ppu_vram_finex = bin.ReadByte(); + ppu_bkgfetch_nt_addr = bin.ReadUInt16(); + ppu_bkgfetch_nt_data = bin.ReadByte(); + ppu_bkgfetch_at_addr = bin.ReadUInt16(); + ppu_bkgfetch_at_data = bin.ReadByte(); + ppu_bkgfetch_lb_addr = bin.ReadUInt16(); + ppu_bkgfetch_lb_data = bin.ReadByte(); + ppu_bkgfetch_hb_addr = bin.ReadUInt16(); + ppu_bkgfetch_hb_data = bin.ReadByte(); + ppu_sprfetch_slot = bin.ReadInt32(); + ppu_sprfetch_y_data = bin.ReadByte(); + ppu_sprfetch_t_data = bin.ReadByte(); + ppu_sprfetch_at_data = bin.ReadByte(); + ppu_sprfetch_x_data = bin.ReadByte(); + ppu_sprfetch_lb_addr = bin.ReadUInt16(); + ppu_sprfetch_lb_data = bin.ReadByte(); + ppu_sprfetch_hb_addr = bin.ReadUInt16(); + ppu_sprfetch_hb_data = bin.ReadByte(); + ppu_bkg_render_i = bin.ReadInt32(); + ppu_bkg_render_pos = bin.ReadInt32(); + ppu_bkg_render_tmp_val = bin.ReadInt32(); + ppu_bkg_current_pixel = bin.ReadInt32(); + ppu_spr_current_pixel = bin.ReadInt32(); + ppu_current_pixel = bin.ReadInt32(); + ppu_render_x = bin.ReadInt32(); + bin.ReadInt32(); + ppu_oamev_n = bin.ReadByte(); + ppu_oamev_m = bin.ReadByte(); + ppu_oamev_compare = bin.ReadBoolean(); + ppu_oamev_slot = bin.ReadByte(); + ppu_fetch_data = bin.ReadByte(); + ppu_phase_index = bin.ReadByte(); + ppu_sprite0_should_hit = bin.ReadBoolean(); + } + + internal static void CheckGame(string fileName, out bool valid) + { + string text = Path.GetExtension(fileName).ToLower(); + if (text != null && text == ".nes") + { + Tracer.WriteLine("Checking INES header ..."); + INes nes = new INes(); + nes.Load(fileName, loadDumps: false); + valid = nes.IsValid; + Tracer.WriteLine("INES header is valid."); + } + else + { + Tracer.WriteWarning("File format is not supported. Format: " + Path.GetExtension(fileName)); + valid = false; + } + } + + internal static void Initialize() + { + Tracer.WriteLine("Loading database file ..."); + NesCartDatabase.LoadDatabase(out bool success); + + if (success) + { + Tracer.WriteInformation("Nes Cart database file loaded successfully."); + } + else + { + Tracer.WriteError("Error loading Nes Cart database file."); + } + + FrameLimiterEnabled = true; + CPUInitialize(); + PPUInitialize(); + APUInitialize(); + PORTSInitialize(); + } + + internal static void SetupRenderingMethods(RenderVideoFrame renderVideo, RenderAudioSamples renderAudio, TogglePause renderTogglePause, GetIsPlaying renderGetIsPlaying) + { + render_initialized = false; + render_video = renderVideo; + render_audio = renderAudio; + render_audio_toggle_pause = renderTogglePause; + render_audio_get_is_playing = renderGetIsPlaying; + render_initialized = render_video != null && render_audio != null && render_audio_toggle_pause != null && render_audio_get_is_playing != null; + if (render_initialized) + { + Tracer.WriteInformation("Renderer methods initialized successfully."); + return; + } + Tracer.WriteError("ERROR RENDERER INITIALIZING !!"); + Tracer.WriteError("Faild to initialize the renderers methods. Please use the method 'SetupRenderingMethods' to initialize the renderers methods before you can run the emulation."); + } + + public static void LoadGame(string fileName, out bool success, bool useThread) + { + if (!render_initialized) + { + Tracer.WriteError("NO RENDERER INITIALIZED !! EMU CANNOT BE INTIALIZED WITHOUT A RENDERER !!"); + Tracer.WriteError("Please use the method 'SetupRenderingMethods' to initialize the renderers methods before you can run the emulation."); + success = false; + return; + } + string text = Path.GetExtension(fileName).ToLower(); + if (text != null && text == ".nes") + { + Tracer.WriteLine("Checking INES header ..."); + INes nes = new INes(); + nes.Load(fileName, loadDumps: true); + if (nes.IsValid) + { + emu_request_mode = RequestMode.None; + CurrentFilePath = fileName; + if (ON) + { + ShutDown(); + } + Tracer.WriteLine("INES header is valid, loading game ..."); + ApplyRegionSetting(); + MEMInitialize(nes); + ApplyAudioSettings(); + ApplyFrameSkipSettings(); + ApplyPaletteSetting(); + PORTSInitialize(); + hardReset(); + Tracer.WriteLine("EMU is ready."); + success = true; + emu_frame_clocking_mode = !useThread; + ON = true; + PAUSED = false; + if (useThread) + { + Tracer.WriteLine("Running in a thread ... using custom frame limiter."); + FrameLimiterEnabled = true; + mainThread = new Thread(EmuClock); + mainThread.Start(); + } + MyNesMain.VideoProvider.SignalToggle(started: true); + MyNesMain.AudioProvider.SignalToggle(started: true); + } + else + { + success = false; + } + } + else + { + success = false; + } + } + + public static void HardReset() + { + PAUSED = true; + emu_request_mode = RequestMode.HardReset; + } + + private static void hardReset() + { + if (MyNesMain.WaveRecorder.IsRecording) + { + MyNesMain.WaveRecorder.Stop(); + } + render_audio_toggle_pause(paused: true); + switch (Region) + { + case EmuRegion.NTSC: + emu_time_target_fps = 60.0988; + break; + case EmuRegion.PALB: + case EmuRegion.DENDY: + emu_time_target_fps = 50.0; + break; + } + fps_time_period = 1.0 / emu_time_target_fps; + MEMHardReset(); + CPUHardReset(); + PPUHardReset(); + APUHardReset(); + DMAHardReset(); + render_audio_toggle_pause(paused: false); + MyNesMain.VideoProvider.WriteWarningNotification(MNInterfaceLanguage.Message_HardReset, instant: false); + } + + public static void SoftReset() + { + PAUSED = true; + emu_request_mode = RequestMode.SoftReset; + } + + private static void softReset() + { + CPUSoftReset(); + APUSoftReset(); + MyNesMain.VideoProvider.WriteWarningNotification(MNInterfaceLanguage.Message_SoftReset, instant: false); + } + + public static void SaveState() + { + PAUSED = true; + emu_request_mode = RequestMode.SaveState; + } + + public static void LoadState() + { + PAUSED = true; + emu_request_mode = RequestMode.LoadState; + } + + internal static void TakeSnapshot() + { + PAUSED = true; + emu_request_mode = RequestMode.TakeSnapshot; + } + + public static void ShutDown() + { + MyNesMain.VideoProvider.SignalToggle(started: false); + MyNesMain.AudioProvider.SignalToggle(started: false); + if (MyNesMain.WaveRecorder.IsRecording) + { + MyNesMain.WaveRecorder.Stop(); + } + render_audio_get_is_playing(out render_audio_is_playing); + if (render_audio_is_playing) + { + render_audio_toggle_pause(paused: true); + } + Tracer.WriteLine("Shutting down the emulation core..."); + ON = false; + if (mainThread != null) + { + Tracer.WriteLine("Aborting thread .."); + while (mainThread.IsAlive) + { + } + mainThread.Abort(); + mainThread = null; + } + SaveSRAM(); + Tracer.WriteInformation("Emulation core shutdown successfully."); + NesEmu.EmuShutdown?.Invoke(null, new EventArgs()); + } + + internal static void EMUClockFrame() + { + emu_frame_done = false; + while (!emu_frame_done && ON) + { + if (!PAUSED) + { + CPUClock(); + } + else + { + Thread.Sleep(100); + } + } + } + + private static void EmuClock() + { + while (ON) + { + if (!PAUSED) + { + CPUClock(); + if (ppu_frame_finished) + { + FrameFinished(); + } + continue; + } + render_audio_get_is_playing(out render_audio_is_playing); + if (render_audio_is_playing) + { + render_audio_toggle_pause(paused: true); + } + Thread.Sleep(100); + shortucts.Update(); + switch (emu_request_mode) + { + case RequestMode.HardReset: + hardReset(); + PAUSED = false; + emu_request_mode = RequestMode.None; + break; + case RequestMode.SoftReset: + softReset(); + PAUSED = false; + emu_request_mode = RequestMode.None; + break; + case RequestMode.SaveState: + StateHandler.SaveState(); + PAUSED = false; + emu_request_mode = RequestMode.None; + break; + case RequestMode.LoadState: + StateHandler.LoadState(); + PAUSED = false; + emu_request_mode = RequestMode.None; + break; + case RequestMode.TakeSnapshot: + MyNesMain.VideoProvider.TakeSnapshot(); + PAUSED = false; + emu_request_mode = RequestMode.None; + break; + } + isPaused = true; + } + } + + internal static void EmuClockComponents() + { + PPUClock(); + PollInterruptStatus(); + PPUClock(); + PPUClock(); + APUClock(); + DMAClock(); + mem_board.OnCPUClock(); + } + + internal static void ApplyFrameSkipSettings() + { + FrameSkipEnabled = MyNesMain.RendererSettings.FrameSkipEnabled; + FrameSkipInterval = MyNesMain.RendererSettings.FrameSkipInterval; + } + + private static void FrameFinished() + { + if (!FrameSkipEnabled) + { + render_video(ref ppu_screen_pixels); + } + else + { + FrameSkipCounter++; + if (FrameSkipCounter >= FrameSkipInterval) + { + render_video(ref ppu_screen_pixels); + FrameSkipCounter = 0; + } + } + isPaused = false; + ppu_frame_finished = false; + emu_frame_done = true; + joypad1.Update(); + joypad2.Update(); + if (IsFourPlayers) + { + joypad3.Update(); + joypad4.Update(); + } + shortucts.Update(); + if (SoundEnabled) + { + render_audio_get_is_playing(out render_audio_is_playing); + if (!render_audio_is_playing) + { + render_audio_toggle_pause(paused: false); + } + render_audio(ref audio_samples, ref audio_samples_added); + audio_w_pos = 0; + audio_samples_added = 0; + audio_timer = 0.0; + } + fps_time_token = GetTime() - fps_time_start; + if (FrameLimiterEnabled) + { + if (fps_time_token > 0.0) + { + fps_time_dead = fps_time_period - fps_time_token; + if (fps_time_dead > 0.0) + { + Thread.Sleep((int)Math.Floor(fps_time_dead * 1000.0)); + fps_time_dead = GetTime() - fps_time_start; + while (fps_time_period - fps_time_dead > 0.0) + { + fps_time_dead = GetTime() - fps_time_start; + } + } + } + fps_time_last = GetTime(); + fps_time_frame_time = fps_time_last - fps_time_start; + } + fps_time_start = GetTime(); + } + + private static double GetTime() + { + return (double)Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; + } + + public static void GetSpeedValues(out double frame_time, out double immediate_frame_time) + { + frame_time = fps_time_token; + immediate_frame_time = fps_time_frame_time; + } + + public static void SetFramePeriod(ref double period) + { + fps_time_period = period; + } + + public static void ApplyRegionSetting() + { + switch ((RegionSetting)MyNesMain.EmuSettings.RegionSetting) + { + case RegionSetting.AUTO: + Tracer.WriteLine("REGION = AUTO"); + Region = EmuRegion.NTSC; + if (CurrentFilePath.Contains("(E)")) + { + Region = EmuRegion.PALB; + } + Tracer.WriteLine("REGION SELECTED: " + Region); + break; + case RegionSetting.ForceNTSC: + Tracer.WriteLine("REGION: FORCE NTSC"); + Region = EmuRegion.NTSC; + break; + case RegionSetting.ForcePALB: + Tracer.WriteLine("REGION: FORCE PALB"); + Region = EmuRegion.PALB; + break; + case RegionSetting.ForceDENDY: + Tracer.WriteLine("REGION: FORCE DENDY"); + Region = EmuRegion.DENDY; + break; + } + SystemIndex = (int)Region; + } + + public static void ApplyPaletteSetting() + { + Tracer.WriteLine("Loading palette generators values from settings..."); + NTSCPaletteGenerator.brightness = MyNesMain.RendererSettings.Palette_NTSC_brightness; + NTSCPaletteGenerator.contrast = MyNesMain.RendererSettings.Palette_NTSC_contrast; + NTSCPaletteGenerator.gamma = MyNesMain.RendererSettings.Palette_NTSC_gamma; + NTSCPaletteGenerator.hue_tweak = MyNesMain.RendererSettings.Palette_NTSC_hue_tweak; + NTSCPaletteGenerator.saturation = MyNesMain.RendererSettings.Palette_NTSC_saturation; + PALBPaletteGenerator.brightness = MyNesMain.RendererSettings.Palette_PALB_brightness; + PALBPaletteGenerator.contrast = MyNesMain.RendererSettings.Palette_PALB_contrast; + PALBPaletteGenerator.gamma = MyNesMain.RendererSettings.Palette_PALB_gamma; + PALBPaletteGenerator.hue_tweak = MyNesMain.RendererSettings.Palette_PALB_hue_tweak; + PALBPaletteGenerator.saturation = MyNesMain.RendererSettings.Palette_PALB_saturation; + Tracer.WriteLine("Setting up palette ...."); + switch ((PaletteSelectSetting)MyNesMain.RendererSettings.Palette_PaletteSetting) + { + case PaletteSelectSetting.AUTO: + Tracer.WriteLine("Palette set to auto detect depending on region."); + switch (Region) + { + case EmuRegion.NTSC: + SetupPalette(NTSCPaletteGenerator.GeneratePalette()); + Tracer.WriteLine("Region is NTSC, Palette set from NTSC generator."); + break; + case EmuRegion.PALB: + case EmuRegion.DENDY: + SetupPalette(PALBPaletteGenerator.GeneratePalette()); + Tracer.WriteLine("Region is PALB/DENDY, Palette set from PALB generator."); + break; + } + break; + case PaletteSelectSetting.ForceNTSC: + Tracer.WriteLine("Palette set to always use NTSC palette generator."); + SetupPalette(NTSCPaletteGenerator.GeneratePalette()); + Tracer.WriteLine("Palette set from NTSC generator."); + break; + case PaletteSelectSetting.ForcePALB: + Tracer.WriteLine("Palette set to always use PALB palette generator."); + SetupPalette(NTSCPaletteGenerator.GeneratePalette()); + Tracer.WriteLine("Palette set from PALB generator."); + break; + case PaletteSelectSetting.File: + { + Tracer.WriteLine("Palette set to load from file."); + + var paletteFileStream = MyNesMain.FileManager.OpenPaletteFile(); + if (paletteFileStream != null) + { + PaletteFileWrapper.LoadFile(paletteFileStream, out var palette); + SetupPalette(palette); + Tracer.WriteLine("Palette set from file"); + break; + } + Tracer.WriteError("Palette from file is not exist is not exist. Setting up palette from generators."); + switch (Region) + { + case EmuRegion.NTSC: + SetupPalette(NTSCPaletteGenerator.GeneratePalette()); + Tracer.WriteLine("Region is NTSC, Palette set from NTSC generator."); + break; + case EmuRegion.PALB: + case EmuRegion.DENDY: + SetupPalette(PALBPaletteGenerator.GeneratePalette()); + Tracer.WriteLine("Region is PALB/DENDY, Palette set from PALB generator."); + break; + } + break; + } + } + } + + internal static void WriteStateData(ref BinaryWriter bin) + { + APUWriteState(ref bin); + CPUWriteState(ref bin); + DMAWriteState(ref bin); + InterruptsWriteState(ref bin); + MEMWriteState(ref bin); + PORTWriteState(ref bin); + PPUWriteState(ref bin); + } + + internal static void ReadStateData(ref BinaryReader bin) + { + APUReadState(ref bin); + CPUReadState(ref bin); + DMAReadState(ref bin); + InterruptsReadState(ref bin); + MEMReadState(ref bin); + PORTReadState(ref bin); + PPUReadState(ref bin); + } + + private static void SQ2HardReset() + { + sq2_duty_cycle = 0; + sq2_length_halt = false; + sq2_constant_volume_envelope = false; + sq2_volume_devider_period = 0; + sq2_sweep_enable = false; + sq2_sweep_devider_period = 0; + sq2_sweep_negate = false; + sq2_sweep_shift_count = 0; + sq2_timer = 0; + sq2_period_devider = 0; + sq2_seqencer = 0; + sq2_length_enabled = false; + sq2_length_counter = 0; + sq2_envelope_start_flag = false; + sq2_envelope_devider = 0; + sq2_envelope_decay_level_counter = 0; + sq2_envelope = 0; + sq2_sweep_counter = 0; + sq2_sweep_reload = false; + sq2_sweep_change = 0; + sq2_valid_freq = false; + sq2_output = 0; + sq2_ignore_reload = false; + } + + private static void SQ2SoftReset() + { + SQ2HardReset(); + } + + private static void SQ2Clock() + { + sq2_period_devider--; + if (sq2_period_devider > 0) + { + return; + } + sq2_period_devider = sq2_timer + 1; + sq2_seqencer = (byte)((uint)(sq2_seqencer + 1) & 7u); + if (sq2_length_counter > 0 && sq2_valid_freq) + { + if (audio_sq2_outputable) + { + sq2_output = sq_duty_cycle_sequences[sq2_duty_cycle][sq2_seqencer] * sq2_envelope; + } + } + else + { + sq2_output = 0; + } + audio_signal_outputed = true; + } + + private static void SQ2ClockLength() + { + if (sq2_length_counter > 0 && !sq2_length_halt) + { + sq2_length_counter--; + if (apu_reg_access_happened && apu_reg_io_addr == 7 && apu_reg_access_w) + { + sq2_ignore_reload = true; + } + } + sq2_sweep_counter--; + if (sq2_sweep_counter == 0) + { + sq2_sweep_counter = sq2_sweep_devider_period + 1; + if (sq2_sweep_enable && sq2_sweep_shift_count > 0 && sq2_valid_freq) + { + sq2_sweep_change = sq2_timer >> (int)sq2_sweep_shift_count; + sq2_timer += (sq2_sweep_negate ? (-sq2_sweep_change) : sq2_sweep_change); + SQ2CalculateValidFreq(); + } + } + else if (sq2_sweep_reload) + { + sq2_sweep_counter = sq2_sweep_devider_period + 1; + sq2_sweep_reload = false; + } + } + + private static void SQ2ClockEnvelope() + { + if (sq2_envelope_start_flag) + { + sq2_envelope_start_flag = false; + sq2_envelope_decay_level_counter = 15; + sq2_envelope_devider = (byte)(sq2_volume_devider_period + 1); + } + else if (sq2_envelope_devider > 0) + { + sq2_envelope_devider--; + } + else + { + sq2_envelope_devider = (byte)(sq2_volume_devider_period + 1); + if (sq2_envelope_decay_level_counter > 0) + { + sq2_envelope_decay_level_counter--; + } + else if (sq2_length_halt) + { + sq2_envelope_decay_level_counter = 15; + } + } + sq2_envelope = (sq2_constant_volume_envelope ? sq2_volume_devider_period : sq2_envelope_decay_level_counter); + } + + private static void APUOnRegister4004() + { + if (apu_reg_access_w) + { + sq2_duty_cycle = (byte)((apu_reg_io_db & 0xC0) >> 6); + sq2_volume_devider_period = (byte)(apu_reg_io_db & 0xFu); + sq2_length_halt = (apu_reg_io_db & 0x20) != 0; + sq2_constant_volume_envelope = (apu_reg_io_db & 0x10) != 0; + sq2_envelope = (sq2_constant_volume_envelope ? sq2_volume_devider_period : sq2_envelope_decay_level_counter); + } + } + + private static void APUOnRegister4005() + { + if (apu_reg_access_w) + { + sq2_sweep_enable = (apu_reg_io_db & 0x80) == 128; + sq2_sweep_devider_period = (byte)((uint)(apu_reg_io_db >> 4) & 7u); + sq2_sweep_negate = (apu_reg_io_db & 8) == 8; + sq2_sweep_shift_count = (byte)(apu_reg_io_db & 7u); + sq2_sweep_reload = true; + SQ2CalculateValidFreq(); + } + } + + private static void APUOnRegister4006() + { + if (apu_reg_access_w) + { + sq2_timer = (sq2_timer & 0xFF00) | apu_reg_io_db; + SQ2CalculateValidFreq(); + } + } + + private static void APUOnRegister4007() + { + if (apu_reg_access_w) + { + sq2_timer = (sq2_timer & 0xFF) | ((apu_reg_io_db & 7) << 8); + if (sq2_length_enabled && !sq2_ignore_reload) + { + sq2_length_counter = sq_duration_table[apu_reg_io_db >> 3]; + } + if (sq2_ignore_reload) + { + sq2_ignore_reload = false; + } + sq2_seqencer = 0; + sq2_envelope_start_flag = true; + SQ2CalculateValidFreq(); + } + } + + private static void SQ2On4015() + { + sq2_length_enabled = (apu_reg_io_db & 2) != 0; + if (!sq2_length_enabled) + { + sq2_length_counter = 0; + } + } + + private static void SQ2Read4015() + { + if (sq2_length_counter > 0) + { + apu_reg_io_db = (byte)((apu_reg_io_db & 0xFDu) | 2u); + } + } + + private static void SQ2CalculateValidFreq() + { + sq2_valid_freq = sq2_timer >= 8 && (sq2_sweep_negate || ((sq2_timer + (sq2_timer >> (int)sq2_sweep_shift_count)) & 0x800) == 0); + } + + private static void SQ2WriteState(ref BinaryWriter bin) + { + bin.Write(sq2_duty_cycle); + bin.Write(sq2_length_halt); + bin.Write(sq2_constant_volume_envelope); + bin.Write(sq2_volume_devider_period); + bin.Write(sq2_sweep_enable); + bin.Write(sq2_sweep_devider_period); + bin.Write(sq2_sweep_negate); + bin.Write(sq2_sweep_shift_count); + bin.Write(sq2_timer); + bin.Write(sq2_period_devider); + bin.Write(sq2_seqencer); + bin.Write(sq2_length_enabled); + bin.Write(sq2_length_counter); + bin.Write(sq2_envelope_start_flag); + bin.Write(sq2_envelope_devider); + bin.Write(sq2_envelope_decay_level_counter); + bin.Write(sq2_envelope); + bin.Write(sq2_sweep_counter); + bin.Write(sq2_sweep_reload); + bin.Write(sq2_sweep_change); + bin.Write(sq2_valid_freq); + bin.Write(sq2_output); + bin.Write(sq2_ignore_reload); + } + + private static void SQ2ReadState(ref BinaryReader bin) + { + sq2_duty_cycle = bin.ReadByte(); + sq2_length_halt = bin.ReadBoolean(); + sq2_constant_volume_envelope = bin.ReadBoolean(); + sq2_volume_devider_period = bin.ReadByte(); + sq2_sweep_enable = bin.ReadBoolean(); + sq2_sweep_devider_period = bin.ReadByte(); + sq2_sweep_negate = bin.ReadBoolean(); + sq2_sweep_shift_count = bin.ReadByte(); + sq2_timer = bin.ReadInt32(); + sq2_period_devider = bin.ReadInt32(); + sq2_seqencer = bin.ReadByte(); + sq2_length_enabled = bin.ReadBoolean(); + sq2_length_counter = bin.ReadInt32(); + sq2_envelope_start_flag = bin.ReadBoolean(); + sq2_envelope_devider = bin.ReadByte(); + sq2_envelope_decay_level_counter = bin.ReadByte(); + sq2_envelope = bin.ReadByte(); + sq2_sweep_counter = bin.ReadInt32(); + sq2_sweep_reload = bin.ReadBoolean(); + sq2_sweep_change = bin.ReadInt32(); + sq2_valid_freq = bin.ReadBoolean(); + sq2_output = bin.ReadInt32(); + sq2_ignore_reload = bin.ReadBoolean(); + } } } diff --git a/AxibugEmuOnline.Client/Assets/MyNes.Core/PaletteFileWrapper.cs b/AxibugEmuOnline.Client/Assets/MyNes.Core/PaletteFileWrapper.cs index 988662f..1a59074 100644 --- a/AxibugEmuOnline.Client/Assets/MyNes.Core/PaletteFileWrapper.cs +++ b/AxibugEmuOnline.Client/Assets/MyNes.Core/PaletteFileWrapper.cs @@ -5,9 +5,9 @@ namespace MyNes.Core { public class PaletteFileWrapper { - public static bool LoadFile(string file, out int[] palette) + public static bool LoadFile(Stream fileStream, out int[] palette) { - Stream stream = new FileStream(file, FileMode.Open, FileAccess.Read); + Stream stream = fileStream; if (stream.Length == 192 || stream.Length == 1536) { int[] array = new int[512]; diff --git a/AxibugEmuOnline.Client/Assets/MyNes.Core/RendererSettings.cs b/AxibugEmuOnline.Client/Assets/MyNes.Core/RendererSettings.cs index cf0078e..28e5970 100644 --- a/AxibugEmuOnline.Client/Assets/MyNes.Core/RendererSettings.cs +++ b/AxibugEmuOnline.Client/Assets/MyNes.Core/RendererSettings.cs @@ -96,8 +96,6 @@ namespace MyNes.Core public int Palette_PaletteSetting; - public string Palette_CurrentPaletteFilePath = "default_ntsc.pal"; - public float Palette_NTSC_brightness = 1.075f; public float Palette_NTSC_contrast = 1.016f; @@ -122,15 +120,5 @@ namespace MyNes.Core : base(path) { } - - public override void LoadSettings() - { - base.LoadSettings(); - if (Palette_CurrentPaletteFilePath == "default_ntsc.pal" || Palette_CurrentPaletteFilePath == "" || !File.Exists(Palette_CurrentPaletteFilePath)) - { - Palette_CurrentPaletteFilePath = Path.Combine(MyNesMain.AppPath, "Palettes"); - Palette_CurrentPaletteFilePath = Path.Combine(Palette_CurrentPaletteFilePath, "default_ntsc.pal"); - } - } } } diff --git a/AxibugEmuOnline.Client/Assets/MyNes.Core/Tracer.cs b/AxibugEmuOnline.Client/Assets/MyNes.Core/Tracer.cs index 9fae52e..41c1b17 100644 --- a/AxibugEmuOnline.Client/Assets/MyNes.Core/Tracer.cs +++ b/AxibugEmuOnline.Client/Assets/MyNes.Core/Tracer.cs @@ -23,13 +23,24 @@ namespace MyNes.Core public static void WriteLine(string message, TracerStatus status) { Tracer.EventRaised?.Invoke(null, new TracerEventArgs(message, status)); - Debug.Log(message); + switch (status) + { + case TracerStatus.Error: Debug.LogError(message); break; + case TracerStatus.Infromation: + case TracerStatus.Normal: + Debug.Log(message); + break; + case TracerStatus.Warning: + Debug.LogWarning(message); + break; + } + } public static void WriteLine(string message, string category, TracerStatus status) { Tracer.EventRaised?.Invoke(null, new TracerEventArgs($"{category}: {message}", status)); - Debug.Log($"{category}:{message}"); + WriteLine($"{category}:{message}", status); } public static void WriteError(string message) diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes.meta new file mode 100644 index 0000000..8030677 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e2c2fc792e914ba4da5671edcb233994 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes.meta new file mode 100644 index 0000000..07ccdad --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8e5e5b73f8ff71745806799d6c3a97b6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/ASQ_realityA.pal.txt b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/ASQ_realityA.pal.txt new file mode 100644 index 0000000..8c93587 Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/ASQ_realityA.pal.txt differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/ASQ_realityA.pal.txt.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/ASQ_realityA.pal.txt.meta new file mode 100644 index 0000000..89da682 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/ASQ_realityA.pal.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 66c9b7bb9e78e2149a8c6b884e7814dc +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/ASQ_realityB.pal.txt b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/ASQ_realityB.pal.txt new file mode 100644 index 0000000..1d36d59 Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/ASQ_realityB.pal.txt differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/ASQ_realityB.pal.txt.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/ASQ_realityB.pal.txt.meta new file mode 100644 index 0000000..069a07b --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/ASQ_realityB.pal.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e7c963ec91faede48bdbc4c837d184c1 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/BMF_final2.pal.txt b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/BMF_final2.pal.txt new file mode 100644 index 0000000..01fd716 Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/BMF_final2.pal.txt differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/BMF_final2.pal.txt.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/BMF_final2.pal.txt.meta new file mode 100644 index 0000000..38cbeda --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/BMF_final2.pal.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f90e9c85a73ad3649a73f6b5c66ee21c +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/BMF_final3.pal.txt b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/BMF_final3.pal.txt new file mode 100644 index 0000000..d156011 Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/BMF_final3.pal.txt differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/BMF_final3.pal.txt.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/BMF_final3.pal.txt.meta new file mode 100644 index 0000000..a7b699a --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/BMF_final3.pal.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 79fd9783decf96349b1bbdf3cd49d01e +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/FCEU-13-default_nitsuja.pal.txt b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/FCEU-13-default_nitsuja.pal.txt new file mode 100644 index 0000000..9367073 Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/FCEU-13-default_nitsuja.pal.txt differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/FCEU-13-default_nitsuja.pal.txt.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/FCEU-13-default_nitsuja.pal.txt.meta new file mode 100644 index 0000000..8cf7af1 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/FCEU-13-default_nitsuja.pal.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cffbaa9e5c24d7b4aa3e27fcbe59a880 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/FCEU-15-nitsuja_new.pal.txt b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/FCEU-15-nitsuja_new.pal.txt new file mode 100644 index 0000000..4765e54 Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/FCEU-15-nitsuja_new.pal.txt differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/FCEU-15-nitsuja_new.pal.txt.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/FCEU-15-nitsuja_new.pal.txt.meta new file mode 100644 index 0000000..92e54ec --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/FCEU-15-nitsuja_new.pal.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4a281e2c6edff1f4a8574e1429fef097 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/FCEUX.pal.txt b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/FCEUX.pal.txt new file mode 100644 index 0000000..2b8ea5d Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/FCEUX.pal.txt differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/FCEUX.pal.txt.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/FCEUX.pal.txt.meta new file mode 100644 index 0000000..19fc3a3 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/FCEUX.pal.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: acc05b5c291ed1c4fb812b7be20b8113 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/NTSC.pal.txt b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/NTSC.pal.txt new file mode 100644 index 0000000..e958862 Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/NTSC.pal.txt differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/NTSC.pal.txt.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/NTSC.pal.txt.meta new file mode 100644 index 0000000..49ba5e8 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/NTSC.pal.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: eae5c00585ff5ad4da5ff743aa7cb388 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/PAL.pal.txt b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/PAL.pal.txt new file mode 100644 index 0000000..e958862 Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/PAL.pal.txt differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/PAL.pal.txt.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/PAL.pal.txt.meta new file mode 100644 index 0000000..ec6386f --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/PAL.pal.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: dbea537bf3d26ef469d311366274b854 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/default_ntsc.pal.txt b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/default_ntsc.pal.txt new file mode 100644 index 0000000..e16b0b1 Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/default_ntsc.pal.txt differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/default_ntsc.pal.txt.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/default_ntsc.pal.txt.meta new file mode 100644 index 0000000..2f58f29 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/default_ntsc.pal.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: af0c6ae054b9b8b4eb1e950615e9666d +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/pc10.pal.txt b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/pc10.pal.txt new file mode 100644 index 0000000..d2d3d92 Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/pc10.pal.txt differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/pc10.pal.txt.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/pc10.pal.txt.meta new file mode 100644 index 0000000..8699e1a --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/pc10.pal.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c87310fabe238424d8bc9b8cf5e06a1a +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/pc10emph.pal.txt b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/pc10emph.pal.txt new file mode 100644 index 0000000..8c31437 Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/pc10emph.pal.txt differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/pc10emph.pal.txt.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/pc10emph.pal.txt.meta new file mode 100644 index 0000000..b67bb27 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/pc10emph.pal.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cd2c5883bfccfea41adc9d73a6f509de +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_001.pal.txt b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_001.pal.txt new file mode 100644 index 0000000..0a8c2a7 Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_001.pal.txt differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_001.pal.txt.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_001.pal.txt.meta new file mode 100644 index 0000000..48f7c3b --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_001.pal.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3e8bf825b3645ab47a1e3db5f98d65f0 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_001emph.pal.txt b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_001emph.pal.txt new file mode 100644 index 0000000..cd08b4a Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_001emph.pal.txt differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_001emph.pal.txt.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_001emph.pal.txt.meta new file mode 100644 index 0000000..229e4a0 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_001emph.pal.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ac166adb93cefee48bf472799c28f078 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_002.pal.txt b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_002.pal.txt new file mode 100644 index 0000000..c1226cf Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_002.pal.txt differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_002.pal.txt.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_002.pal.txt.meta new file mode 100644 index 0000000..68faf1b --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_002.pal.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a4866a9e921def74f88bc9c76182d4bf +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_002emph.pal.txt b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_002emph.pal.txt new file mode 100644 index 0000000..6f821c8 Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_002emph.pal.txt differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_002emph.pal.txt.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_002emph.pal.txt.meta new file mode 100644 index 0000000..e027087 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_002emph.pal.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: db03b2f58578ecb4c8af8c69a62cc6e4 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_003.pal.txt b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_003.pal.txt new file mode 100644 index 0000000..b386189 Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_003.pal.txt differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_003.pal.txt.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_003.pal.txt.meta new file mode 100644 index 0000000..53a0ef0 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_003.pal.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ae891fd90c634b64aa8d3bed26c9a130 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_003emph.pal.txt b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_003emph.pal.txt new file mode 100644 index 0000000..aac1004 Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_003emph.pal.txt differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_003emph.pal.txt.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_003emph.pal.txt.meta new file mode 100644 index 0000000..b2f17f7 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_003emph.pal.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9a6da4c0ffb86d749b681f8a9d4403fd +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_004.pal.txt b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_004.pal.txt new file mode 100644 index 0000000..23d44ac Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_004.pal.txt differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_004.pal.txt.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_004.pal.txt.meta new file mode 100644 index 0000000..40b51a0 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_004.pal.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f1d9aa9ac67469d49b197ce086e00b86 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_004emph.pal.txt b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_004emph.pal.txt new file mode 100644 index 0000000..edb82ef Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_004emph.pal.txt differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_004emph.pal.txt.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_004emph.pal.txt.meta new file mode 100644 index 0000000..101d9c0 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/Palettes/vs_004emph.pal.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1dc183e92926f564a90573e275d7b470 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/database.xml b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/database.xml new file mode 100644 index 0000000..39c4861 Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/database.xml differ diff --git a/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/database.xml.meta b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/database.xml.meta new file mode 100644 index 0000000..92e6266 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Resources/NesCoreRes/database.xml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c53b7ab773a22634bbe5c6a1ac794f54 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Resources/Texture/RenderTexture.renderTexture b/AxibugEmuOnline.Client/Assets/Resources/Texture/RenderTexture.renderTexture index 99ddfbc..dc799d3 100644 --- a/AxibugEmuOnline.Client/Assets/Resources/Texture/RenderTexture.renderTexture +++ b/AxibugEmuOnline.Client/Assets/Resources/Texture/RenderTexture.renderTexture @@ -26,6 +26,7 @@ RenderTexture: m_UseDynamicScale: 0 m_BindMS: 0 m_EnableCompatibleFormat: 1 + m_EnableRandomWrite: 0 m_TextureSettings: serializedVersion: 2 m_FilterMode: 1 diff --git a/AxibugEmuOnline.Client/Assets/Scene/EmuTest.unity b/AxibugEmuOnline.Client/Assets/Scene/EmuTest.unity index a1bf93d..378b7f0 100644 --- a/AxibugEmuOnline.Client/Assets/Scene/EmuTest.unity +++ b/AxibugEmuOnline.Client/Assets/Scene/EmuTest.unity @@ -151,7 +151,8 @@ Transform: m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 - m_Children: [] + m_Children: + - {fileID: 786008058} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &258485948 @@ -166,6 +167,9 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ac8cd27a180bf3e489b2ca27c821bffe, type: 3} m_Name: m_EditorClassIdentifier: + DrawImage: {fileID: 730321751} + DO: {fileID: 1379369700} + Fps: {fileID: 1680039028} --- !u!1 &708549044 GameObject: m_ObjectHideFlags: 0 @@ -260,6 +264,182 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &730321748 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 730321749} + - component: {fileID: 730321752} + - component: {fileID: 730321751} + m_Layer: 5 + m_Name: video + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &730321749 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 730321748} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: -1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 786008058} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &730321751 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 730321748} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Texture: {fileID: 0} + m_UVRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 +--- !u!222 &730321752 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 730321748} + m_CullTransparentMesh: 1 +--- !u!1 &786008057 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 786008058} + - component: {fileID: 786008061} + - component: {fileID: 786008060} + - component: {fileID: 786008059} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &786008058 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 786008057} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 730321749} + - {fileID: 1680039031} + - {fileID: 1379369698} + m_Father: {fileID: 258485947} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!114 &786008059 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 786008057} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &786008060 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 786008057} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &786008061 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 786008057} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_VertexColorAlwaysGammaSpace: 0 + m_AdditionalShaderChannelsFlag: 0 + m_UpdateRectTransformForStandalone: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 --- !u!1 &1232273651 GameObject: m_ObjectHideFlags: 0 @@ -352,6 +532,314 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1359344831 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1359344834} + - component: {fileID: 1359344833} + - component: {fileID: 1359344832} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1359344832 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1359344831} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_SendPointerHoverToParent: 1 + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &1359344833 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1359344831} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &1359344834 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1359344831} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1379369697 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1379369698} + - component: {fileID: 1379369699} + - component: {fileID: 1379369700} + m_Layer: 5 + m_Name: Audio + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1379369698 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1379369697} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: -1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 786008058} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!82 &1379369699 +AudioSource: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1379369697} + m_Enabled: 1 + serializedVersion: 4 + OutputAudioMixerGroup: {fileID: 0} + m_audioClip: {fileID: 0} + m_PlayOnAwake: 1 + m_Volume: 1 + m_Pitch: 1 + Loop: 0 + Mute: 0 + Spatialize: 0 + SpatializePostEffects: 0 + Priority: 128 + DopplerLevel: 1 + MinDistance: 1 + MaxDistance: 500 + Pan2D: 0 + rolloffMode: 0 + BypassEffects: 0 + BypassListenerEffects: 0 + BypassReverbZones: 0 + rolloffCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + panLevelCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + spreadCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + reverbZoneMixCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 +--- !u!114 &1379369700 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1379369697} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f25db9f5a7339c34f94e6e978be38c82, type: 3} + m_Name: + m_EditorClassIdentifier: + Gain: 0.05 +--- !u!1 &1680039027 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1680039031} + - component: {fileID: 1680039030} + - component: {fileID: 1680039028} + - component: {fileID: 1680039029} + m_Layer: 5 + m_Name: fps + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1680039028 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1680039027} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 12324234 +--- !u!114 &1680039029 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1680039027} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalFit: 2 + m_VerticalFit: 2 +--- !u!222 &1680039030 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1680039027} + m_CullTransparentMesh: 1 +--- !u!224 &1680039031 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1680039027} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 786008058} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 1, y: 0} --- !u!1660057539 &9223372036854775807 SceneRoots: m_ObjectHideFlags: 0 @@ -359,3 +847,4 @@ SceneRoots: - {fileID: 1232273654} - {fileID: 708549046} - {fileID: 258485947} + - {fileID: 1359344834} diff --git a/AxibugEmuOnline.Client/Assets/Script/Emu/AudioProvider.cs b/AxibugEmuOnline.Client/Assets/Script/Emu/AudioProvider.cs new file mode 100644 index 0000000..9024a83 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Script/Emu/AudioProvider.cs @@ -0,0 +1,72 @@ +using MyNes.Core; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEditor.PackageManager.UI; +using UnityEngine; +using UnityEngine.Profiling; + +namespace AxibugEmuOnline.Client +{ + public class AudioProvider : IAudioProvider + { + public string Name => nameof(AudioProvider); + + public string ID => Name.GetHashCode().ToString(); + + public bool AllowBufferChange => true; + + public bool AllowFrequencyChange => true; + + private bool m_isPlaying; + private int samples_added; + + private Queue<(float[], int)> queues = new Queue<(float[], int)>(); + public void Initialize() + { + } + + public void SubmitSamples(ref short[] buffer, ref int samples_a) + { + NesCoreProxy.Instance.DO.Play(buffer.Take(samples_a).SelectMany(s => toBytes(s)).ToArray()); + } + + public byte[] toBytes(short value) + { + byte[] temp = new byte[2]; + //temp[0] = (byte)(value >> 8); + temp[0] = temp[1] = (byte)((uint)value & 0xFFu); + + return temp; + } + + public void TogglePause(bool paused) + { + m_isPlaying = !paused; + } + + public void GetIsPlaying(out bool playing) + { + playing = m_isPlaying; + } + + + + public void ShutDown() + { + } + + public void Reset() + { + } + + public void SignalToggle(bool started) + { + } + + public void SetVolume(int Vol) + { + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/Script/Emu/WINSettings.cs.meta b/AxibugEmuOnline.Client/Assets/Script/Emu/AudioProvider.cs.meta similarity index 83% rename from AxibugEmuOnline.Client/Assets/Script/Emu/WINSettings.cs.meta rename to AxibugEmuOnline.Client/Assets/Script/Emu/AudioProvider.cs.meta index 49f210d..8a0fe31 100644 --- a/AxibugEmuOnline.Client/Assets/Script/Emu/WINSettings.cs.meta +++ b/AxibugEmuOnline.Client/Assets/Script/Emu/AudioProvider.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: ed2bba3664d14d840a5ed2847926614c +guid: 765129d4fad76714191795975893ea9c MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/AxibugEmuOnline.Client/Assets/Script/Emu/DefaultAudioOutput.cs b/AxibugEmuOnline.Client/Assets/Script/Emu/DefaultAudioOutput.cs new file mode 100644 index 0000000..6174481 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Script/Emu/DefaultAudioOutput.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Generic; +using System.IO; +using UnityEngine; + + +[RequireComponent(typeof(AudioSource))] +public class DefaultAudioOutput : MonoBehaviour +{ + public float Gain = 0.05f; + + private int _samplesAvailable; + private PipeStream _pipeStream; + private byte[] _buffer; + + void Awake() + { + // Get Unity Buffer size + int bufferLength = 0, numBuffers = 0; + AudioSettings.GetDSPBufferSize(out bufferLength, out numBuffers); + _samplesAvailable = bufferLength; + + // Prepare our buffer + _pipeStream = new PipeStream(); + _pipeStream.MaxBufferLength = _samplesAvailable * 2 * 2; + _buffer = new byte[_samplesAvailable * 2]; + } + + + List waveBytes = new List(); + void OnAudioFilterRead(float[] data, int channels) + { + // This method is not called if you don't own Unity PRO. + + if (_buffer.Length != data.Length) + { + Debug.Log("Does DSPBufferSize or speakerMode changed? Audio disabled."); + return; + } + + int r = _pipeStream.Read(_buffer, 0, data.Length); + for (int i = 0; i < r; ++i) + { + var normalize = (sbyte)(_buffer[i]) / 127f; + data[i] = Gain * normalize; + waveBytes.Add(_buffer[i]); + } + } + + private void OnDestroy() + { + File.WriteAllBytes("e:/wav.wav", waveBytes.ToArray()); + } + + public int GetOutputSampleRate() + { + return AudioSettings.outputSampleRate; + } + + public int GetSamplesAvailable() + { + return _samplesAvailable; + } + + public void Play(byte[] data) + { + _pipeStream.Write(data, 0, data.Length); + } + + private class PipeStream : Stream + { + private readonly Queue _buffer = new Queue(); + private long _maxBufferLength = 8192; + + public long MaxBufferLength + { + get { return _maxBufferLength; } + set { _maxBufferLength = value; } + } + + public new void Dispose() + { + _buffer.Clear(); + } + + public override void Flush() + { + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (offset != 0) + throw new NotImplementedException("Offsets with value of non-zero are not supported"); + if (buffer == null) + throw new ArgumentException("Buffer is null"); + if (offset + count > buffer.Length) + throw new ArgumentException("The sum of offset and count is greater than the buffer length. "); + if (offset < 0 || count < 0) + throw new ArgumentOutOfRangeException("offset", "offset or count is negative."); + + if (count == 0) + return 0; + + int readLength = 0; + + lock (_buffer) + { + // fill the read buffer + for (; readLength < count && Length > 0; readLength++) + { + buffer[readLength] = _buffer.Dequeue(); + } + } + + return readLength; + } + + private bool ReadAvailable(int count) + { + return (Length >= count); + } + + public override void Write(byte[] buffer, int offset, int count) + { + if (buffer == null) + throw new ArgumentException("Buffer is null"); + if (offset + count > buffer.Length) + throw new ArgumentException("The sum of offset and count is greater than the buffer length. "); + if (offset < 0 || count < 0) + throw new ArgumentOutOfRangeException("offset", "offset or count is negative."); + if (count == 0) + return; + + lock (_buffer) + { + while (Length >= _maxBufferLength) + return; + + // queue up the buffer data + foreach (byte b in buffer) + { + _buffer.Enqueue(b); + } + } + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override long Length + { + get { return _buffer.Count; } + } + + public override long Position + { + get { return 0; } + set { throw new NotImplementedException(); } + } + } + +} \ No newline at end of file diff --git a/AxibugEmuOnline.Client/Assets/Script/Emu/DefaultAudioOutput.cs.meta b/AxibugEmuOnline.Client/Assets/Script/Emu/DefaultAudioOutput.cs.meta new file mode 100644 index 0000000..f171a66 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Script/Emu/DefaultAudioOutput.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f25db9f5a7339c34f94e6e978be38c82 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Script/Emu/UguiVideoProvider.cs b/AxibugEmuOnline.Client/Assets/Script/Emu/UguiVideoProvider.cs new file mode 100644 index 0000000..1b33e3d --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Script/Emu/UguiVideoProvider.cs @@ -0,0 +1,111 @@ +using MyNes.Core; +using System; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; + +namespace AxibugEmuOnline.Client +{ + public class UguiVideoProvider : IVideoProvider + { + public string Name => "Unity UI Video"; + + public string ID => nameof(UguiVideoProvider).GetHashCode().ToString(); + + private int[] m_texRawBuffer = new int[256 * 240]; + private Texture2D m_rawBufferWarper = new Texture2D(256, 240); + private RawImage m_image; + private RenderTexture m_drawRT; + + public void Initialize() + { + m_image = NesCoreProxy.Instance.DrawImage; + m_image.texture = RenderTexture.GetTemporary(256, 240, 0, UnityEngine.Experimental.Rendering.GraphicsFormat.B8G8R8A8_UNorm); + } + + public Color GetColor(uint value) + { + var r = 0xFF0000 & value; + r >>= 16; + var b = 0xFF & value; + var g = 0xFF00 & value; + g >>= 8; + var color = new Color(r / 255f, g / 255f, b / 255f); + return color; + } + + public void Draw() + { + var colors = m_texRawBuffer.Select(w => GetColor((uint)w)).ToArray(); + m_rawBufferWarper.SetPixels(colors); + m_rawBufferWarper.Apply(); + Graphics.Blit(m_rawBufferWarper, m_image.texture as RenderTexture); + } + + public void WriteErrorNotification(string message, bool instant) + { + + } + + public void WriteInfoNotification(string message, bool instant) + { + + } + + public void WriteWarningNotification(string message, bool instant) + { + } + + public void TakeSnapshotAs(string path, string format) + { + + } + + public void TakeSnapshot() + { + + } + + public void ShutDown() + { + } + + public void SignalToggle(bool started) + { + } + + public void SubmitFrame(ref int[] buffer) + { + Array.Copy(buffer, m_texRawBuffer, m_texRawBuffer.Length); + } + + public void ResizeBegin() + { + } + + public void ResizeEnd() + { + } + + public void ApplyRegionChanges() + { + } + + public void Resume() + { + } + + public void ToggleAspectRatio(bool keep_aspect) + { + } + + public void ToggleFPS(bool show_fps) + { + } + + public void ApplyFilter() + { + } + + } +} diff --git a/AxibugEmuOnline.Client/Assets/Script/Emu/UguiVideoProvider.cs.meta b/AxibugEmuOnline.Client/Assets/Script/Emu/UguiVideoProvider.cs.meta new file mode 100644 index 0000000..249242e --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Script/Emu/UguiVideoProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f2632911774df3c488ec24b39651c4de +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Script/Emu/WINSettings.cs b/AxibugEmuOnline.Client/Assets/Script/Emu/WINSettings.cs deleted file mode 100644 index e1f5ade..0000000 --- a/AxibugEmuOnline.Client/Assets/Script/Emu/WINSettings.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System.Reflection; -using MyNes.Core; - -namespace AxibugEmuOnline.Client -{ - public class WINSettings : ISettings - { - public string App_Version = ""; - - public int Win_Location_X = 10; - - public int Win_Location_Y = 10; - - public int Win_Size_W = 768; - - public int Win_Size_H = 743; - - public bool Win_StartInFullscreen; - - public string[] Misc_RecentFiles = new string[0]; - - public bool PauseEmuWhenFocusLost = true; - - public bool ShowGettingStarted = true; - - public string InterfaceLanguage = "English"; - - public bool ShutdowOnEscapePress = true; - - public bool LoadStateOpenRecent; - - public string Database_FilePath = ""; - - public string[] Database_FoldersSnapshots; - - public string[] Database_FoldersCovers; - - public string[] Database_FoldersInfos; - - public string[] Database_FoldersScanned; - - public bool LauncherRememberLastSelection = true; - - public int LauncherLatestSelection; - - public int LauncherLocationX = 10; - - public int LauncherLocationY = 10; - - public int LauncherSizeW = 1480; - - public int LauncherSizeH = 920; - - public int LauncherSpliter1 = 807; - - public int LauncherSpliter2 = 420; - - public int LauncherSpliter3 = 308; - - public int LauncherSpliter4 = 271; - - public bool LauncherAutoMinimize = true; - - public bool LauncherAutoCycleImagesInGameTab = true; - - public bool LauncherShowAyAppStart; - - public int SnapsView_ImageMode = 1; - - public bool SnapsView_ShowBar = true; - - public bool SnapsView_ShowStatus = true; - - public bool SnapsView_AutoCycle = true; - - public int CoversView_ImageMode = 1; - - public bool CoversView_ShowBar = true; - - public bool CoversView_ShowStatus = true; - - public bool CoversView_AutoCycle = true; - - public WINSettings(string path) - : base(path) - { - } - - public override void LoadSettings() - { - base.LoadSettings(); - if (App_Version != Assembly.GetExecutingAssembly().GetName().Version.ToString()) - { - ShowGettingStarted = true; - App_Version = Assembly.GetExecutingAssembly().GetName().Version.ToString(); - } - } - } - -} \ No newline at end of file diff --git a/AxibugEmuOnline.Client/Assets/Script/Manager/AppEmu.cs b/AxibugEmuOnline.Client/Assets/Script/Manager/AppEmu.cs index a43b083..21c8606 100644 --- a/AxibugEmuOnline.Client/Assets/Script/Manager/AppEmu.cs +++ b/AxibugEmuOnline.Client/Assets/Script/Manager/AppEmu.cs @@ -1,22 +1,55 @@ using MyNes.Core; -using Palmmedia.ReportGenerator.Core; -using SevenZip; -using System; -using System.Collections.Generic; -using System.ComponentModel; using System.IO; -using System.Threading; +using UnityEngine; namespace AxibugEmuOnline.Client.Manager { - public class AppEmu - { + public class AppEmu : IFileManager + { + public UguiVideoProvider UguiVideo { get; private set; } + public AudioProvider Audio { get; private set; } + public void Init() { - MyNesMain.Initialize(setupRenderers: false); - MyNesMain.SetVideoProvider(); - MyNesMain.SetAudioProvider(); - MyNesMain.SetRenderingMethods(); - } + MyNesMain.Initialize(this); + NesEmu.LoadGame("E:/rzg4.nes", out var successed, true); + UguiVideo = MyNesMain.VideoProvider as UguiVideoProvider; + Audio = MyNesMain.AudioProvider as AudioProvider; + + var fps_nes_missle = 1.0 / 59.0; + NesEmu.SetFramePeriod(ref fps_nes_missle); + } + + public void Update() + { + UguiVideo.Draw(); + + double t = Time.deltaTime; + NesEmu.SetFramePeriod(ref t); + } + + public void Dispose() + { + MyNesMain.Shutdown(); + } + + public Stream OpenDatabaseFile() + { + var databaseFile = Resources.Load("NesCoreRes/database"); + MemoryStream ms = new MemoryStream(databaseFile.bytes); + return ms; + } + + public Stream OpenPaletteFile() + { + var defaultPalett = Resources.Load("NesCoreRes/Palettes/default_ntsc.pal"); + MemoryStream ms = new MemoryStream(defaultPalett.bytes); + return ms; + } + + public string GetWorkingFolderPath() + { + return $"{Application.persistentDataPath}/MyNes"; + } } } diff --git a/AxibugEmuOnline.Client/Assets/Script/NesCoreProxy.cs b/AxibugEmuOnline.Client/Assets/Script/NesCoreProxy.cs index eae78a3..0692edb 100644 --- a/AxibugEmuOnline.Client/Assets/Script/NesCoreProxy.cs +++ b/AxibugEmuOnline.Client/Assets/Script/NesCoreProxy.cs @@ -1,17 +1,36 @@ using AxibugEmuOnline.Client.Manager; -using System.Collections; -using System.Collections.Generic; +using MyNes.Core; +using System.IO; using UnityEngine; +using UnityEngine.UI; namespace AxibugEmuOnline.Client { public class NesCoreProxy : MonoBehaviour { + public static NesCoreProxy Instance { get; private set; } + + public RawImage DrawImage; + public DefaultAudioOutput DO; + public Text Fps; + private AppEmu m_appEnum = new AppEmu(); private void Start() { + Instance = this; m_appEnum.Init(); } + + private void Update() + { + m_appEnum.Update(); + } + + private void OnDestroy() + { + Instance = null; + m_appEnum.Dispose(); + } } } diff --git a/AxibugEmuOnline.Client/ProjectSettings/SceneTemplateSettings.json b/AxibugEmuOnline.Client/ProjectSettings/SceneTemplateSettings.json new file mode 100644 index 0000000..5e97f83 --- /dev/null +++ b/AxibugEmuOnline.Client/ProjectSettings/SceneTemplateSettings.json @@ -0,0 +1,121 @@ +{ + "templatePinStates": [], + "dependencyTypeInfos": [ + { + "userAdded": false, + "type": "UnityEngine.AnimationClip", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.Animations.AnimatorController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.AnimatorOverrideController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.Audio.AudioMixerController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.ComputeShader", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Cubemap", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.GameObject", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.LightingDataAsset", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.LightingSettings", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Material", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.MonoScript", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicMaterial", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicsMaterial2D", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessProfile", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessResources", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.VolumeProfile", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.SceneAsset", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Shader", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.ShaderVariantCollection", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Texture", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Texture2D", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Timeline.TimelineAsset", + "defaultInstantiationMode": 0 + } + ], + "defaultDependencyTypeInfo": { + "userAdded": false, + "type": "", + "defaultInstantiationMode": 1 + }, + "newSceneOverride": 0 +} \ No newline at end of file