From 5ce82c9406d73e14513f48f0aecad16e536df63d Mon Sep 17 00:00:00 2001 From: "ALIENJACK\\alien" Date: Thu, 29 Aug 2024 17:20:01 +0800 Subject: [PATCH] =?UTF-8?q?NEScore=20StateSave=E6=9C=BA=E5=88=B6=20?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Assets/Script/NesEmulator/NesEmulator.cs | 3 +- .../Script/NesEmulator/VideoProvider.cs | 1 + .../Assets/VirtualNes.Core/APU.cs | 53 +++ .../Assets/VirtualNes.Core/ApuEX/APU_FDS.cs | 49 ++- .../Assets/VirtualNes.Core/ApuEX/APU_FME7.cs | 99 ++++- .../VirtualNes.Core/ApuEX/APU_INTERFACE.cs | 16 +- .../VirtualNes.Core/ApuEX/APU_INTERNAL.cs | 184 ++++++++- .../Assets/VirtualNes.Core/ApuEX/APU_MMC5.cs | 61 ++- .../Assets/VirtualNes.Core/ApuEX/APU_N106.cs | 353 +++++++++--------- .../Assets/VirtualNes.Core/ApuEX/APU_VRC6.cs | 52 ++- .../Assets/VirtualNes.Core/ApuEX/APU_VRC7.cs | 11 + .../Assets/VirtualNes.Core/CPU.cs | 5 + .../VirtualNes.Core/CoreLibs/ByteArrayRef.cs | 5 + .../VirtualNes.Core/CoreLibs/MemoryUtility.cs | 5 + .../VirtualNes.Core/CoreLibs/NESCOMMAND.cs | 23 -- .../Assets/VirtualNes.Core/MMU.cs | 6 +- .../Assets/VirtualNes.Core/NES.cs | 282 ++++++++++++-- .../Assets/VirtualNes.Core/PAD.cs | 66 +++- .../Assets/VirtualNes.Core/State.meta | 8 + .../Assets/VirtualNes.Core/State/BLOCKHDR.cs | 23 ++ .../BLOCKHDR.cs.meta} | 2 +- .../Assets/VirtualNes.Core/State/CTRSTAT.cs | 28 ++ .../VirtualNes.Core/State/CTRSTAT.cs.meta | 11 + .../Assets/VirtualNes.Core/State/DISKDATA.cs | 7 + .../VirtualNes.Core/State/DISKDATA.cs.meta | 11 + .../Assets/VirtualNes.Core/State/EXCTRSTAT.cs | 17 + .../VirtualNes.Core/State/EXCTRSTAT.cs.meta | 11 + .../Assets/VirtualNes.Core/State/FILEHDR2.cs | 32 ++ .../VirtualNes.Core/State/FILEHDR2.cs.meta | 11 + .../Assets/VirtualNes.Core/State/MMCSTAT.cs | 22 ++ .../VirtualNes.Core/State/MMCSTAT.cs.meta | 11 + .../Assets/VirtualNes.Core/State/MMUSTAT.cs | 38 ++ .../VirtualNes.Core/State/MMUSTAT.cs.meta | 11 + .../Assets/VirtualNes.Core/State/RAMSTAT.cs | 38 ++ .../VirtualNes.Core/State/RAMSTAT.cs.meta | 11 + .../Assets/VirtualNes.Core/State/REGSTAT.cs | 96 +++++ .../VirtualNes.Core/State/REGSTAT.cs.meta | 11 + .../Assets/VirtualNes.Core/State/SNDSTAT.cs | 28 ++ .../VirtualNes.Core/State/SNDSTAT.cs.meta | 11 + .../Assets/VirtualNes.Core/State/State.cs | 39 ++ .../VirtualNes.Core/State/State.cs.meta | 11 + .../VirtualNes.Core/State/StateBuffer.cs | 88 +++++ .../VirtualNes.Core/State/StateBuffer.cs.meta | 11 + .../ProjectSettings/ProjectSettings.asset | 2 +- 44 files changed, 1606 insertions(+), 257 deletions(-) delete mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/NESCOMMAND.cs create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State.meta create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/BLOCKHDR.cs rename AxibugEmuOnline.Client/Assets/VirtualNes.Core/{CoreLibs/NESCOMMAND.cs.meta => State/BLOCKHDR.cs.meta} (83%) create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/CTRSTAT.cs create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/CTRSTAT.cs.meta create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/DISKDATA.cs create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/DISKDATA.cs.meta create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/EXCTRSTAT.cs create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/EXCTRSTAT.cs.meta create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/FILEHDR2.cs create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/FILEHDR2.cs.meta create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMCSTAT.cs create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMCSTAT.cs.meta create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMUSTAT.cs create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMUSTAT.cs.meta create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/RAMSTAT.cs create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/RAMSTAT.cs.meta create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/REGSTAT.cs create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/REGSTAT.cs.meta create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/SNDSTAT.cs create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/SNDSTAT.cs.meta create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/State.cs create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/State.cs.meta create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/StateBuffer.cs create mode 100644 AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/StateBuffer.cs.meta diff --git a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.cs b/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.cs index c841f58..02760be 100644 --- a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.cs +++ b/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.cs @@ -8,8 +8,9 @@ using VirtualNes.Core.Debug; namespace AxibugEmuOnline.Client { + public class NesEmulator : MonoBehaviour - { + { public NES NesCore { get; private set; } public VideoProvider VideoProvider; diff --git a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/VideoProvider.cs b/AxibugEmuOnline.Client/Assets/Script/NesEmulator/VideoProvider.cs index 6688bbc..ea8c838 100644 --- a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/VideoProvider.cs +++ b/AxibugEmuOnline.Client/Assets/Script/NesEmulator/VideoProvider.cs @@ -17,6 +17,7 @@ namespace AxibugEmuOnline.Client private int TexBufferSize; private Texture2D pPal; + public void SetDrawData(uint[] screenData, byte[] lineColorMode, int screenWidth, int screenHeight) { if (wrapTex == null) diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/APU.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/APU.cs index a95d338..0aa713b 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/APU.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/APU.cs @@ -1,5 +1,6 @@  using System; +using System.IO; using VirtualNes.Core.Debug; namespace VirtualNes.Core @@ -536,6 +537,58 @@ namespace VirtualNes.Core return data; } + + internal void GetFrameIRQ(ref int Cycle, ref byte Count, ref byte Type, ref byte IRQ, ref byte Occur) + { + @internal.GetFrameIRQ(ref Cycle, ref Count, ref Type, ref IRQ, ref Occur); + } + + internal void SaveState(StateBuffer buffer) + { + // 時間軸を同期させる為Flushする + QueueFlush(); + + @internal.SaveState(buffer); + buffer.Position += (@internal.GetSize() + 15) & (~0x0F); + + // VRC6 + if ((exsound_select & 0x01) != 0) + { + vrc6.SaveState(buffer); + buffer.Position += (vrc6.GetSize() + 15) & (~0x0F); // Padding + } + // VRC7 (not support) + if ((exsound_select & 0x02) != 0) + { + vrc7.SaveState(buffer); + buffer.Position += (vrc7.GetSize() + 15) & (~0x0F); // Padding + } + // FDS + if ((exsound_select & 0x04) != 0) + { + fds.SaveState(buffer); + buffer.Position += (fds.GetSize() + 15) & (~0x0F); // Padding + + } + // MMC5 + if ((exsound_select & 0x08) != 0) + { + mmc5.SaveState(buffer); + buffer.Position += (mmc5.GetSize() + 15) & (~0x0F); // Padding + } + // N106 + if ((exsound_select & 0x10) != 0) + { + n106.SaveState(buffer); + buffer.Position += (n106.GetSize() + 15) & (~0x0F); // Padding + } + // FME7 + if ((exsound_select & 0x20) != 0) + { + fme7.SaveState(buffer); + buffer.Position += (fme7.GetSize() + 15) & (~0x0F); // Padding + } + } } public struct QUEUEDATA diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FDS.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FDS.cs index d67f9c9..88566a0 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FDS.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FDS.cs @@ -1,4 +1,5 @@ using System; +using System.IO; namespace VirtualNes.Core { @@ -403,7 +404,18 @@ namespace VirtualNes.Core return fds.now_freq; } - private class FDSSOUND + public override uint GetSize() + { + return fds.GetSize() + fds_sync.GetSize(); + } + + public override void SaveState(StateBuffer buffer) + { + fds.SaveState(buffer); + fds_sync.SaveState(buffer); + } + + private class FDSSOUND : IStateBufferObject { public byte[] reg = new byte[0x80]; public byte volenv_mode; // Volume Envelope @@ -467,6 +479,41 @@ namespace VirtualNes.Core now_freq = 0; output = 0; } + + public uint GetSize() + { + return 512; + } + + public void SaveState(StateBuffer buffer) + { + buffer.Write(reg); + buffer.Write(volenv_mode); + buffer.Write(volenv_gain); + buffer.Write(volenv_decay); + buffer.Write(volenv_phaseacc); + buffer.Write(swpenv_mode); + buffer.Write(swpenv_gain); + buffer.Write(swpenv_decay); + buffer.Write(swpenv_phaseacc); + buffer.Write(envelope_enable); + buffer.Write(envelope_speed); + buffer.Write(wave_setup); + buffer.Write(master_volume); + buffer.Write(main_wavetable); + buffer.Write(main_enable); + buffer.Write(main_frequency); + buffer.Write(main_addr); + buffer.Write(lfo_wavetable); + buffer.Write(lfo_enable); + buffer.Write(lfo_frequency); + buffer.Write(lfo_addr); + buffer.Write(lfo_phaseacc); + buffer.Write(sweep_bias); + buffer.Write(now_volume); + buffer.Write(now_freq); + buffer.Write(output); + } } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FME7.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FME7.cs index ae0b7e3..c707084 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FME7.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FME7.cs @@ -1,4 +1,5 @@ using System; +using static VirtualNes.Core.APU_FME7; namespace VirtualNes.Core { @@ -91,7 +92,7 @@ namespace VirtualNes.Core byte[][] envelope_table; sbyte[][] envstep_table; - ENVELOPE envelope = new ENVELOPE(); + ENVELOPE envelope; NOISE noise = new NOISE(); CHANNEL[] op = new CHANNEL[3] { new CHANNEL(), new CHANNEL(), new CHANNEL() }; byte address; @@ -117,6 +118,7 @@ namespace VirtualNes.Core envstep_sawtooth, envstep_pulse, envstep_triangle, envstep_pulse, envstep_sawtooth, envstep_pulse, envstep_triangle, envstep_pulse }; + envelope = new ENVELOPE(envelope_table, envstep_table); Reset(APU_CLOCK, 22050); } @@ -133,8 +135,8 @@ namespace VirtualNes.Core item.ZeroMemory(); } - envelope.envtbl = envelope_table[0]; - envelope.envstep = envstep_table[0]; + envelope.envtbl_index = 0; + envelope.envstep_index = 0; noise.noiserange = 1; noise.noiseout = 0xFF; @@ -211,8 +213,8 @@ namespace VirtualNes.Core envelope.freq = INT2FIX(((envelope.reg[1] & 0x0F) << 8) + envelope.reg[0] + 1); break; case 0x0D: - envelope.envtbl = envelope_table[data & 0x0F]; - envelope.envstep = envstep_table[data & 0x0F]; + envelope.envtbl_index = (byte)(data & 0x0F); + envelope.envstep_index = (byte)(data & 0x0F); envelope.envadr = 0; break; } @@ -332,7 +334,22 @@ namespace VirtualNes.Core return ch.output_vol; } - public class ENVELOPE + public override uint GetSize() + { + return (uint)(1 + envelope.GetSize() + noise.GetSize() + op[0].GetSize() * op.Length); + } + + public override void SaveState(StateBuffer buffer) + { + buffer.Write(address); + + envelope.SaveState(buffer); + noise.SaveState(buffer); + foreach (var oneOp in op) + oneOp.SaveState(buffer); + } + + public class ENVELOPE : IStateBufferObject { public byte[] reg = new byte[3]; public byte volume; @@ -341,8 +358,19 @@ namespace VirtualNes.Core public int phaseacc; public int envadr; - public byte[] envtbl; - public sbyte[] envstep; + public byte envtbl_index; + public byte envstep_index; + + byte[][] ref_envtbl; + sbyte[][] ref_envstep; + public byte[] envtbl => ref_envtbl[envtbl_index]; + public sbyte[] envstep => ref_envstep[envstep_index]; + public ENVELOPE(byte[][] envtbl, sbyte[][] envstep) + { + ref_envtbl = envtbl; + ref_envstep = envstep; + } + public void ZeroMemory() { @@ -351,12 +379,28 @@ namespace VirtualNes.Core freq = 0; phaseacc = 0; envadr = 0; - envtbl = null; - envstep = null; + envtbl_index = 0; + envstep_index = 0; + } + + public uint GetSize() + { + return 18; + } + + public void SaveState(StateBuffer buffer) + { + buffer.Write(reg); + buffer.Write(volume); + buffer.Write(freq); + buffer.Write(phaseacc); + buffer.Write(envadr); + buffer.Write(envtbl_index); + buffer.Write(envstep_index); } } - public class NOISE + public class NOISE : IStateBufferObject { public int freq; public int phaseacc; @@ -367,9 +411,22 @@ namespace VirtualNes.Core { freq = 0; phaseacc = 0; noiserange = 0; noiseout = 0; } + + public uint GetSize() + { + return 13; + } + + public void SaveState(StateBuffer buffer) + { + buffer.Write(freq); + buffer.Write(phaseacc); + buffer.Write(noiserange); + buffer.Write(noiseout); + } } - public class CHANNEL + public class CHANNEL : IStateBufferObject { public byte[] reg = new byte[3]; public byte enable; @@ -394,6 +451,24 @@ namespace VirtualNes.Core phaseacc = 0; output_vol = 0; } + + public uint GetSize() + { + return 20; + } + + public void SaveState(StateBuffer buffer) + { + buffer.Write(reg); + buffer.Write(enable); + buffer.Write(env_on); + buffer.Write(noise_on); + buffer.Write(adder); + buffer.Write(volume); + buffer.Write(freq); + buffer.Write(phaseacc); + buffer.Write(output_vol); + } } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERFACE.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERFACE.cs index 391406c..db28ed6 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERFACE.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERFACE.cs @@ -1,6 +1,9 @@ -namespace VirtualNes.Core +using System; +using System.IO; + +namespace VirtualNes.Core { - public abstract class APU_INTERFACE + public abstract class APU_INTERFACE : IStateBufferObject { public const float APU_CLOCK = 1789772.5f; @@ -19,8 +22,7 @@ public virtual void VSync() { } public virtual bool Sync(int cycles) { return false; } public virtual int GetFreq(int channel) { return 0; } - public virtual int GetStateSize() { return 0; } - public virtual void SaveState(byte[] p) { } + public virtual void SaveState(StateBuffer buffer) { } public virtual void LoadState(byte[] p) { } public static int INT2FIX(int x) @@ -32,5 +34,11 @@ { return x >> 16; } + + + public virtual uint GetSize() + { + return 0; + } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERNAL.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERNAL.cs index 6942744..51c8aef 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERNAL.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERNAL.cs @@ -1,5 +1,8 @@ using System; +using System.Collections.Generic; +using System.IO; +using UnityEngine; namespace VirtualNes.Core { @@ -1190,7 +1193,49 @@ namespace VirtualNes.Core break; } } - public class RECTANGLE + + internal void GetFrameIRQ(ref int cycle, ref byte count, ref byte type, ref byte IRQ, ref byte occur) + { + cycle = FrameCycle; + count = (byte)FrameCount; + type = (byte)FrameType; + IRQ = FrameIRQ; + occur = FrameIRQoccur; + } + + public override uint GetSize() + { + return sizeof(byte) + + sizeof(byte) + + sizeof(int) + + sizeof(int) + + sizeof(int) + + sizeof(byte) + + sizeof(byte) + + ch0.GetSize() + + ch1.GetSize() + + ch2.GetSize() + + ch3.GetSize() + + ch4.GetSize(); + } + + public unsafe override void SaveState(StateBuffer p) + { + p.Write(reg4015); + p.Write(sync_reg4015); + p.Write(FrameCycle); + p.Write(FrameCount); + p.Write(FrameType); + p.Write(FrameIRQ); + p.Write(FrameIRQoccur); + ch0.SaveState(p); + ch1.SaveState(p); + ch2.SaveState(p); + ch3.SaveState(p); + ch4.SaveState(p); + } + + public class RECTANGLE : IStateBufferObject { public byte[] reg = new byte[4]; // register @@ -1269,8 +1314,46 @@ namespace VirtualNes.Core dummy2 = 0; sync_len_count = 0; } + + public uint GetSize() + { + return 64; + } + + public void SaveState(StateBuffer buffer) + { + buffer.Write(reg); + buffer.Write(enable); + buffer.Write(holdnote); + buffer.Write(volume); + buffer.Write(complement); + buffer.Write(phaseacc); + buffer.Write(freq); + buffer.Write(freqlimit); + buffer.Write(adder); + buffer.Write(duty); + buffer.Write(len_count); + buffer.Write(nowvolume); + buffer.Write(env_fixed); + buffer.Write(env_decay); + buffer.Write(env_count); + buffer.Write(dummy0); + buffer.Write(env_vol); + buffer.Write(swp_on); + buffer.Write(swp_inc); + buffer.Write(swp_shift); + buffer.Write(swp_decay); + buffer.Write(swp_count); + buffer.Write(dummy1); + buffer.Write(sync_reg); + buffer.Write(sync_output_enable); + buffer.Write(sync_enable); + buffer.Write(sync_holdnote); + buffer.Write(dummy2); + buffer.Write(sync_len_count); + } } - public class TRIANGLE + public class TRIANGLE : IStateBufferObject { public byte[] reg = new byte[4]; @@ -1296,6 +1379,7 @@ namespace VirtualNes.Core public int sync_len_count; public int sync_lin_count; + internal void ZeroMemory() { Array.Clear(reg, 0, reg.Length); @@ -1318,8 +1402,34 @@ namespace VirtualNes.Core sync_len_count = 0; sync_lin_count = 0; } + + public uint GetSize() + { + return 47; + } + + public void SaveState(StateBuffer buffer) + { + buffer.Write(reg); + buffer.Write(enable); + buffer.Write(holdnote); + buffer.Write(counter_start); + buffer.Write(dummy0); + buffer.Write(phaseacc); + buffer.Write(freq); + buffer.Write(len_count); + buffer.Write(lin_count); + buffer.Write(adder); + buffer.Write(nowvolume); + buffer.Write(sync_reg); + buffer.Write(sync_enable); + buffer.Write(sync_holdnote); + buffer.Write(sync_counter_start); + buffer.Write(sync_len_count); + buffer.Write(sync_lin_count); + } } - public class DPCM + public class DPCM : IStateBufferObject { public byte[] reg = new byte[4]; public byte enable; @@ -1343,8 +1453,42 @@ namespace VirtualNes.Core public byte sync_irq_enable; public int sync_cycles, sync_cache_cycles; public int sync_dmalength, sync_cache_dmalength; + + public uint GetSize() + { + return 72; + } + + public void SaveState(StateBuffer buffer) + { + buffer.Write(reg); + buffer.Write(enable); + buffer.Write(looping); + buffer.Write(cur_byte); + buffer.Write(dpcm_value); + buffer.Write(freq); + buffer.Write(phaseacc); + buffer.Write(output); + buffer.Write(address); + buffer.Write(cache_addr); + buffer.Write(dmalength); + buffer.Write(cache_dmalength); + buffer.Write(dpcm_output_real); + buffer.Write(dpcm_output_fake); + buffer.Write(dpcm_output_old); + buffer.Write(dpcm_output_offset); + buffer.Write(sync_reg); + buffer.Write(sync_enable); + buffer.Write(sync_looping); + buffer.Write(sync_irq_gen); + buffer.Write(sync_irq_enable); + buffer.Write(sync_cycles); + buffer.Write(sync_cache_cycles); + buffer.Write(sync_dmalength); + buffer.Write(sync_cache_dmalength); + } } - public class NOISE + public class NOISE : IStateBufferObject { public byte[] reg = new byte[4]; // register @@ -1377,6 +1521,7 @@ namespace VirtualNes.Core public byte dummy1; public int sync_len_count; + internal void ZeroMemory() { Array.Clear(reg, 0, reg.Length); @@ -1406,6 +1551,37 @@ namespace VirtualNes.Core dummy1 = 0; sync_len_count = 0; } + + public uint GetSize() + { + return 52; + } + + public void SaveState(StateBuffer buffer) + { + buffer.Write(reg); + buffer.Write(enable); + buffer.Write(holdnote); + buffer.Write(volume); + buffer.Write(xor_tap); + buffer.Write(shift_reg); + buffer.Write(phaseacc); + buffer.Write(freq); + buffer.Write(len_count); + buffer.Write(nowvolume); + buffer.Write(output); + buffer.Write(env_fixed); + buffer.Write(env_decay); + buffer.Write(env_count); + buffer.Write(dummy0); + buffer.Write(env_vol); + buffer.Write(sync_reg); + buffer.Write(sync_output_enable); + buffer.Write(sync_enable); + buffer.Write(sync_holdnote); + buffer.Write(dummy1); + buffer.Write(sync_len_count); + } } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_MMC5.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_MMC5.cs index d1807d1..f8f5ff0 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_MMC5.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_MMC5.cs @@ -370,7 +370,27 @@ namespace VirtualNes.Core return ch.output_vol; } - public class SYNCRECTANGLE + public override uint GetSize() + { + //3*sizeof(BYTE) + sizeof(ch0) + sizeof(ch1) + sizeof(sch0) + sizeof(sch1); 源代码似乎少了sync_reg5015的大小 + return 3 + ch0.GetSize() + ch1.GetSize() + 1 + sch0.GetSize() + sch1.GetSize(); + } + + public override void SaveState(StateBuffer buffer) + { + buffer.Write(reg5010); + buffer.Write(reg5011); + buffer.Write(reg5015); + + ch0.SaveState(buffer); + ch1.SaveState(buffer); + + buffer.Write(sync_reg5015); + sch0.SaveState(buffer); + sch1.SaveState(buffer); + } + + public class SYNCRECTANGLE : IStateBufferObject { // For sync public byte[] reg = new byte[4]; @@ -387,9 +407,23 @@ namespace VirtualNes.Core Array.Clear(dummy, 0, dummy.Length); vbl_length = 0; } + + public uint GetSize() + { + return 12; + } + + public void SaveState(StateBuffer buffer) + { + buffer.Write(reg); + buffer.Write(enable); + buffer.Write(holdnote); + buffer.Write(dummy); + buffer.Write(vbl_length); + } } - public class RECTANGLE + public class RECTANGLE : IStateBufferObject { public byte[] reg = new byte[4]; public byte enable; @@ -410,6 +444,29 @@ namespace VirtualNes.Core public int adder; public int duty_flip; + + public uint GetSize() + { + return 45; + } + + public void SaveState(StateBuffer buffer) + { + buffer.Write(reg); + buffer.Write(enable); + buffer.Write(vbl_length); + buffer.Write(phaseacc); + buffer.Write(freq); + buffer.Write(output_vol); + buffer.Write(fixed_envelope); + buffer.Write(holdnote); + buffer.Write(volume); + buffer.Write(env_vol); + buffer.Write(env_phase); + buffer.Write(env_decay); + buffer.Write(adder); + buffer.Write(duty_flip); + } } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_N106.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_N106.cs index 197fab7..dadd4c7 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_N106.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_N106.cs @@ -1,101 +1,130 @@ -using RECTANGLE = VirtualNes.Core.APU_VRC6.RECTANGLE; +using Codice.CM.Client.Differences; +using System; +using RECTANGLE = VirtualNes.Core.APU_VRC6.RECTANGLE; using SAWTOOTH = VirtualNes.Core.APU_VRC6.SAWTOOTH; namespace VirtualNes.Core { public class APU_N106 : APU_INTERFACE { - RECTANGLE ch0 = new RECTANGLE(); - RECTANGLE ch1 = new RECTANGLE(); - SAWTOOTH ch2 = new SAWTOOTH(); + CHANNEL[] op = new CHANNEL[8]; + + const int CHANNEL_VOL_SHIFT = 6; float cpu_clock; - int cycle_rate; + uint cycle_rate; + + byte addrinc; + byte address; + byte channel_use; + + byte[] tone = new byte[0x100]; public APU_N106() { - Reset(APU_CLOCK, 22050); + // 仮設定 + cpu_clock = APU_CLOCK; + cycle_rate = (uint)(cpu_clock * 12.0f * (1 << 20) / (45.0f * 22050.0f)); } public override void Reset(float fClock, int nRate) { - ch0.ZeroMemory(); - ch1.ZeroMemory(); - ch2.ZeroMemory(); + for (int i = 0; i < 8; i++) + { + op[i].ZeroMemory(); + op[i].tonelen = 0x10 << 18; + } + + address = 0; + addrinc = 1; + channel_use = 8; Setup(fClock, nRate); + + // TONEの初期化はしない... } public override void Setup(float fClock, int nRate) { cpu_clock = fClock; - cycle_rate = (int)(fClock * 65536.0f / nRate); + cycle_rate = (uint)(cpu_clock * 12.0f * (1 << 20) / (45.0f * nRate)); } public override void Write(ushort addr, byte data) { - switch (addr) + if (addr == 0x4800) { - // VRC6 CH0 rectangle - case 0x9000: - ch0.reg[0] = data; - ch0.gate = (byte)(data & 0x80); - ch0.volume = (byte)(data & 0x0F); - ch0.duty_pos = (byte)((data >> 4) & 0x07); - break; - case 0x9001: - ch0.reg[1] = data; - ch0.freq = INT2FIX((((ch0.reg[2] & 0x0F) << 8) | data) + 1); - break; - case 0x9002: - ch0.reg[2] = data; - ch0.enable = (byte)(data & 0x80); - ch0.freq = INT2FIX((((data & 0x0F) << 8) | ch0.reg[1]) + 1); - break; - // VRC6 CH1 rectangle - case 0xA000: - ch1.reg[0] = data; - ch1.gate = (byte)(data & 0x80); - ch1.volume = (byte)(data & 0x0F); - ch1.duty_pos = (byte)((data >> 4) & 0x07); - break; - case 0xA001: - ch1.reg[1] = data; - ch1.freq = INT2FIX((((ch1.reg[2] & 0x0F) << 8) | data) + 1); - break; - case 0xA002: - ch1.reg[2] = data; - ch1.enable = (byte)(data & 0x80); - ch1.freq = INT2FIX((((data & 0x0F) << 8) | ch1.reg[1]) + 1); - break; - // VRC6 CH2 sawtooth - case 0xB000: - ch2.reg[1] = data; - ch2.phaseaccum = (byte)(data & 0x3F); - break; - case 0xB001: - ch2.reg[1] = data; - ch2.freq = INT2FIX((((ch2.reg[2] & 0x0F) << 8) | data) + 1); - break; - case 0xB002: - ch2.reg[2] = data; - ch2.enable = (byte)(data & 0x80); - ch2.freq = INT2FIX((((data & 0x0F) << 8) | ch2.reg[1]) + 1); - // ch2.adder = 0; // クリアするとノイズの原因になる - // ch2.accum = 0; // クリアするとノイズの原因になる - break; + // tone[address*2+0] = (INT)(data&0x0F); + // tone[address*2+1] = (INT)(data >>4); + tone[address * 2 + 0] = (byte)(data & 0x0F); + tone[address * 2 + 1] = (byte)(data >> 4); + + if (address >= 0x40) + { + int no = (address - 0x40) >> 3; + uint tonelen = 0; + ref CHANNEL ch = ref op[no]; + + switch (address & 7) + { + case 0x00: + ch.freq = (uint)((ch.freq & ~0x000000FF) | data); + break; + case 0x02: + ch.freq = (uint)((ch.freq & ~0x0000FF00) | ((uint)data << 8)); + break; + case 0x04: + ch.freq = (uint)((ch.freq & ~0x00030000) | (((uint)data & 0x03) << 16)); + tonelen = (uint)((0x20 - (data & 0x1c)) << 18); + ch.databuf = (byte)((data & 0x1c) >> 2); + if (ch.tonelen != tonelen) + { + ch.tonelen = tonelen; + ch.phase = 0; + } + break; + case 0x06: + ch.toneadr = data; + break; + case 0x07: + ch.vol = (byte)(data & 0x0f); + ch.volupdate = 0xFF; + if (no == 7) + channel_use = (byte)(((data >> 4) & 0x07) + 1); + break; + } + } + + if (addrinc != 0) + { + address = (byte)((address + 1) & 0x7f); + } } + else if (addr == 0xF800) + { + address = (byte)(data & 0x7F); + addrinc = (byte)(data & 0x80); + } + } + + public override byte Read(ushort addr) + { + // $4800 dummy read!! + if (addr == 0x0000) + { + if (addrinc != 0) + { + address = (byte)((address + 1) & 0x7F); + } + } + + return (byte)(addr >> 8); } public override int Process(int channel) { - switch (channel) + if (channel >= (8 - channel_use) && channel < 8) { - case 0: - return RectangleRender(ch0); - case 1: - return RectangleRender(ch1); - case 2: - return SawtoothRender(ch2); + return ChannelRender(ref op[channel]); } return 0; @@ -103,143 +132,117 @@ namespace VirtualNes.Core public override int GetFreq(int channel) { - if (channel == 0 || channel == 1) + if (channel < 8) { - RECTANGLE ch; - if (channel == 0) ch = ch0; - else ch = ch1; - if (ch.enable == 0 || ch.gate != 0 || ch.volume == 0) + channel &= 7; + if (channel < (8 - channel_use)) return 0; - if (ch.freq < INT2FIX(8)) + + ref CHANNEL ch = ref op[channel & 0x07]; + if (ch.freq == 0 || ch.vol == 0) return 0; - return (int)((256.0f * cpu_clock / (FIX2INT(ch.freq) * 16.0f))); - } - if (channel == 2) - { - SAWTOOTH ch = ch2; - if (ch.enable == 0 || ch.phaseaccum == 0) + int temp = channel_use * (8 - ch.databuf) * 4 * 45; + if (temp == 0) return 0; - if (ch.freq < INT2FIX(8)) - return 0; - return (int)(256.0f * cpu_clock / (FIX2INT(ch.freq) * 14.0f)); + return (int)(256.0 * (double)cpu_clock * 12.0 * ch.freq / ((double)0x40000 * temp)); } return 0; } - int RectangleRender(RECTANGLE ch) + private int ChannelRender(ref CHANNEL ch) { - // Enable? - if (ch.enable == 0) - { - ch.output_vol = 0; - ch.adder = 0; - return ch.output_vol; - } + uint phasespd = (uint)(channel_use << 20); - // Digitized output - if (ch.gate != 0) - { - ch.output_vol = ch.volume << APU_VRC6.RECTANGLE_VOL_SHIFT; - return ch.output_vol; - } - - // 一定以上の周波数は処理しない(無駄) - if (ch.freq < INT2FIX(8)) - { - ch.output_vol = 0; - return ch.output_vol; - } - - ch.phaseacc -= cycle_rate; + ch.phaseacc -= (int)cycle_rate; if (ch.phaseacc >= 0) - return ch.output_vol; - - int output = ch.volume << APU_VRC6.RECTANGLE_VOL_SHIFT; - - if (ch.freq > cycle_rate) { - // add 1 step - ch.phaseacc += ch.freq; - ch.adder = (byte)((ch.adder + 1) & 0x0F); - if (ch.adder <= ch.duty_pos) - ch.output_vol = output; - else - ch.output_vol = -output; - } - else - { - // average calculate - int num_times, total; - num_times = total = 0; - while (ch.phaseacc < 0) + if (ch.volupdate != 0) { - ch.phaseacc += ch.freq; - ch.adder = (byte)((ch.adder + 1) & 0x0F); - if (ch.adder <= ch.duty_pos) - total += output; - else - total += -output; - num_times++; + ch.output = (tone[((ch.phase >> 18) + ch.toneadr) & 0xFF] * ch.vol) << CHANNEL_VOL_SHIFT; + ch.volupdate = 0; } - ch.output_vol = total / num_times; + return ch.output; } - return ch.output_vol; + while (ch.phaseacc < 0) + { + ch.phaseacc += (int)phasespd; + ch.phase += ch.freq; + } + while (ch.tonelen != 0 && (ch.phase >= ch.tonelen)) + { + ch.phase -= ch.tonelen; + } + + ch.output = (tone[((ch.phase >> 18) + ch.toneadr) & 0xFF] * ch.vol) << CHANNEL_VOL_SHIFT; + + return ch.output; } - int SawtoothRender(SAWTOOTH ch) + public override uint GetSize() { - // Digitized output - if (ch.enable == 0) + return (uint)(3 * sizeof(byte) + 8 * op[0].GetSize() + tone.Length); + } + + public override void SaveState(StateBuffer buffer) + { + buffer.Write(addrinc); + buffer.Write(address); + buffer.Write(channel_use); + + foreach (var oneOp in op) + oneOp.SaveState(buffer); + + buffer.Write(tone); + } + + public struct CHANNEL : IStateBufferObject + { + public int phaseacc; + + public uint freq; + public uint phase; + public uint tonelen; + + public int output; + + public byte toneadr; + public byte volupdate; + + public byte vol; + public byte databuf; + + internal void ZeroMemory() { - ch.output_vol = 0; - return ch.output_vol; + phaseacc = 0; + freq = 0; + phase = 0; + tonelen = 0; + output = 0; + toneadr = 0; + volupdate = 0; + vol = 0; + databuf = 0; } - // 一定以上の周波数は処理しない(無駄) - if (ch.freq < INT2FIX(9)) + public uint GetSize() { - return ch.output_vol; + return 4 * 5 + 4; } - ch.phaseacc -= cycle_rate / 2; - if (ch.phaseacc >= 0) - return ch.output_vol; - - if (ch.freq > cycle_rate / 2) + public void SaveState(StateBuffer buffer) { - // add 1 step - ch.phaseacc += ch.freq; - if (++ch.adder >= 7) - { - ch.adder = 0; - ch.accum = 0; - } - ch.accum += ch.phaseaccum; - ch.output_vol = ch.accum << APU_VRC6.SAWTOOTH_VOL_SHIFT; + buffer.Write(phaseacc); + buffer.Write(freq); + buffer.Write(phase); + buffer.Write(tonelen); + buffer.Write(output); + buffer.Write(toneadr); + buffer.Write(volupdate); + buffer.Write(vol); + buffer.Write(databuf); } - else - { - // average calculate - int num_times, total; - num_times = total = 0; - while (ch.phaseacc < 0) - { - ch.phaseacc += ch.freq; - if (++ch.adder >= 7) - { - ch.adder = 0; - ch.accum = 0; - } - ch.accum += ch.phaseaccum; - total += ch.accum << APU_VRC6.SAWTOOTH_VOL_SHIFT; - num_times++; - } - ch.output_vol = (total / num_times); - } - - return ch.output_vol; } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_VRC6.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_VRC6.cs index 1b0845e..cdc442f 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_VRC6.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_VRC6.cs @@ -1,4 +1,5 @@ using System; +using System.IO; namespace VirtualNes.Core { @@ -245,7 +246,18 @@ namespace VirtualNes.Core return ch.output_vol; } - public class RECTANGLE + public override uint GetSize() + { + return ch0.GetSize() + ch1.GetSize() + ch2.GetSize(); + } + public override void SaveState(StateBuffer p) + { + ch0.SaveState(p); + ch1.SaveState(p); + ch2.SaveState(p); + } + + public class RECTANGLE : IStateBufferObject { public byte[] reg = new byte[3]; @@ -274,9 +286,27 @@ namespace VirtualNes.Core adder = 0; duty_pos = 0; } + + public uint GetSize() + { + return 20; + } + + public void SaveState(StateBuffer buffer) + { + buffer.Write(reg); + buffer.Write(enable); + buffer.Write(gate); + buffer.Write(volume); + buffer.Write(phaseacc); + buffer.Write(freq); + buffer.Write(output_vol); + buffer.Write(adder); + buffer.Write(duty_pos); + } } - public class SAWTOOTH + public class SAWTOOTH : IStateBufferObject { public byte[] reg = new byte[3]; @@ -305,6 +335,24 @@ namespace VirtualNes.Core accum = 0; phaseaccum = 0; } + + public uint GetSize() + { + return 20; + } + + public void SaveState(StateBuffer buffer) + { + buffer.Write(reg); + buffer.Write(enable); + buffer.Write(volume); + buffer.Write(phaseacc); + buffer.Write(freq); + buffer.Write(output_vol); + buffer.Write(adder); + buffer.Write(accum); + buffer.Write(phaseaccum); + } } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_VRC7.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_VRC7.cs index 83b2e79..5ffde57 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_VRC7.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_VRC7.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using VirtualNes.Core.Emu2413; namespace VirtualNes.Core @@ -92,5 +93,15 @@ namespace VirtualNes.Core return 0; } + + public override uint GetSize() + { + return 0; + } + + public override void SaveState(StateBuffer buffer) + { + //not impl + } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs index edf83a5..be4fc29 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs @@ -2021,6 +2021,11 @@ namespace VirtualNes.Core { r = R; } + + internal int GetDmaCycles() + { + return DMA_cycles; + } } public enum StatusFlag6502 : int diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/ByteArrayRef.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/ByteArrayRef.cs index 3126a59..c23925c 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/ByteArrayRef.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/ByteArrayRef.cs @@ -53,6 +53,11 @@ namespace VirtualNes.Core } } + public Span Span(int start, int length) + { + return new Span(m_rawArray, start + Offset, length); + } + public static implicit operator ArrayRef(T[] array) { return new ArrayRef(array); diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/MemoryUtility.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/MemoryUtility.cs index eea81c1..1f9b1a1 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/MemoryUtility.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/MemoryUtility.cs @@ -40,5 +40,10 @@ namespace VirtualNes.Core } } } + + public static void memcpy(Array dst, Array src, int length) + { + Array.Copy(src, dst, length); + } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/NESCOMMAND.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/NESCOMMAND.cs deleted file mode 100644 index e6ed2f8..0000000 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/NESCOMMAND.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace VirtualNes.Core -{ - public enum NESCOMMAND - { - NESCMD_NONE = 0, - NESCMD_HWRESET, - NESCMD_SWRESET, - NESCMD_EXCONTROLLER, // Commandparam - NESCMD_DISK_THROTTLE_ON, - NESCMD_DISK_THROTTLE_OFF, - NESCMD_DISK_EJECT, - NESCMD_DISK_0A, - NESCMD_DISK_0B, - NESCMD_DISK_1A, - NESCMD_DISK_1B, - NESCMD_DISK_2A, - NESCMD_DISK_2B, - NESCMD_DISK_3A, - NESCMD_DISK_3B, - - NESCMD_SOUND_MUTE, // CommandParam - } -} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/MMU.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/MMU.cs index 391254c..fbd63ef 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/MMU.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/MMU.cs @@ -60,12 +60,12 @@ namespace VirtualNes public const byte BANKTYPE_CRAM = 0x01; public const byte BANKTYPE_VRAM = 0x80; - // 儈儔乕僞僀僾 + // =ミラータイプ; public const byte VRAM_HMIRROR = 0x00; // Horizontal public const byte VRAM_VMIRROR = 0x01; // Virtical public const byte VRAM_MIRROR4 = 0x02; // All screen - public const byte VRAM_MIRROR4L = 0x03; // PA10 L屌掕 $2000-$23FF偺儈儔乕 - public const byte VRAM_MIRROR4H = 0x04; // PA10 H屌掕 $2400-$27FF偺儈儔乕 + public const byte VRAM_MIRROR4L = 0x03; // PA10 L固定 $2000-$23FFのミラー + public const byte VRAM_MIRROR4H = 0x04; // PA10 H固定 $2400-$27FFのミラー // Frame-IRQ儗僕僗僞($4017) public static int FrameIRQ; diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/NES.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/NES.cs index 391ef68..9ea39ef 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/NES.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/NES.cs @@ -1,7 +1,12 @@ +using Codice.CM.Client.Differences; using System; using System.Collections.Generic; using System.IO; +using System.Runtime.ConstrainedExecution; +using System.Runtime.InteropServices.ComTypes; +using System.Security.Cryptography; using System.Text; +using UnityEngine; using VirtualNes.Core.Debug; namespace VirtualNes.Core @@ -21,7 +26,6 @@ namespace VirtualNes.Core private List m_CheatCode = new List(); private List m_GenieCode = new List(); private bool m_bDiskThrottle; - private int m_CommandRequest; private int m_nSnapNo; private bool m_bNsfPlaying; private bool m_bNsfInit; @@ -173,7 +177,6 @@ namespace VirtualNes.Core Debuger.Log("VirtuaNES - CSharpCore\n"); m_bDiskThrottle = false; - m_CommandRequest = 0; m_nSnapNo = 0; @@ -451,31 +454,6 @@ namespace VirtualNes.Core } } - public void Command(NESCOMMAND cmd) - { - CommandParam(cmd, 0); - } - - public bool CommandParam(NESCOMMAND cmd, int param) - { - switch (cmd) - { - case NESCOMMAND.NESCMD_NONE: break; - case NESCOMMAND.NESCMD_HWRESET: - Reset(); - m_CommandRequest = (int)cmd; - break; - case NESCOMMAND.NESCMD_SWRESET: - SoftReset(); - m_CommandRequest = (int)cmd; - break; - default: - throw new NotImplementedException($"{cmd} not impl right now"); - } - - return true; - } - public void CheatInitial() { m_CheatCode.Clear(); @@ -1673,6 +1651,256 @@ namespace VirtualNes.Core return m_BarcodeOut; } + public State GetState() + { + State state = new State(); + + //HEADER + { + state.HEADER.ID = "VirtuaNES ST"; + state.HEADER.BlockVersion = 0x0200; + + if (rom.GetMapperNo() != 20) + state.HEADER.Ext0 = rom.GetPROM_CRC(); + else + { + state.HEADER.Ext0 = rom.GetGameID(); + state.HEADER.Ext1 = (ushort)rom.GetMakerID(); + state.HEADER.Ext2 = (ushort)rom.GetDiskNo(); + } + } + + //REGISTER STATE + { + state.regBLOCK.ID = "REG DATA"; + state.regBLOCK.BlockVersion = 0x0210; + state.regBLOCK.BlockSize = state.reg.GetSize(); + + R6502 R = null; + cpu.GetContext(ref R); + + state.reg.cpureg.PC = R.PC; + state.reg.cpureg.A = R.A; + state.reg.cpureg.X = R.X; + state.reg.cpureg.Y = R.Y; + state.reg.cpureg.S = R.S; + state.reg.cpureg.P = R.P; + state.reg.cpureg.I = R.INT_pending; + + int cycles = 0; + apu.GetFrameIRQ(ref cycles, + ref state.reg.cpureg.FrameIRQ_count, + ref state.reg.cpureg.FrameIRQ_type, + ref state.reg.cpureg.FrameIRQ, + ref state.reg.cpureg.FrameIRQ_occur); + state.reg.cpureg.FrameIRQ_cycles = cycles; // դINTʞ飨 + + state.reg.cpureg.DMA_cycles = cpu.GetDmaCycles(); + state.reg.cpureg.emul_cycles = emul_cycles; + state.reg.cpureg.base_cycles = base_cycles; + + // SAVE PPU STATE + state.reg.ppureg.reg0 = MMU.PPUREG[0]; + state.reg.ppureg.reg1 = MMU.PPUREG[1]; + state.reg.ppureg.reg2 = MMU.PPUREG[2]; + state.reg.ppureg.reg3 = MMU.PPUREG[3]; + state.reg.ppureg.reg7 = MMU.PPU7_Temp; + state.reg.ppureg.loopy_t = MMU.loopy_t; + state.reg.ppureg.loopy_v = MMU.loopy_v; + state.reg.ppureg.loopy_x = MMU.loopy_x; + state.reg.ppureg.toggle56 = MMU.PPU56Toggle; + } + + //RAM STATE + { + state.ram = RAMSTAT.GetDefault(); + uint size = 0; + + // SAVE RAM STATE + MemoryUtility.memcpy(state.ram.RAM, MMU.RAM, state.ram.RAM.Length); + MemoryUtility.memcpy(state.ram.BGPAL, MMU.BGPAL, state.ram.BGPAL.Length); + MemoryUtility.memcpy(state.ram.SPPAL, MMU.SPPAL, state.ram.SPPAL.Length); + MemoryUtility.memcpy(state.ram.SPRAM, MMU.SPRAM, state.ram.SPRAM.Length); + + // S-RAM STATE(ʹ/δʹäv餺ڤХ`֤) + if (rom.IsSAVERAM()) + { + size = (uint)SAVERAM_SIZE; + } + + // Create Header + state.ramBLOCK.ID = "RAM DATA"; + state.ramBLOCK.BlockVersion = 0x0100; + state.ramBLOCK.BlockSize = size + state.ram.GetSize(); + + if (rom.IsSAVERAM()) + { + state.WRAM = new byte[SAVERAM_SIZE]; + Array.Copy(MMU.WRAM, state.WRAM, SAVERAM_SIZE); + } + } + + //BANK STATE + { + state.mmu = MMUSTAT.GetDefault(); + uint size = 0; + + // SAVE CPU MEMORY BANK DATA + // BANK0,1,2ϥХ󥯥`֤vSʤ + // VirtuaNES0.30 + // Х󥯣SRAMʹäv餺` + for (int i = 3; i < 8; i++) + { + state.mmu.CPU_MEM_TYPE[i] = MMU.CPU_MEM_TYPE[i]; + state.mmu.CPU_MEM_PAGE[i] = (ushort)MMU.CPU_MEM_PAGE[i]; + + if (MMU.CPU_MEM_TYPE[i] == MMU.BANKTYPE_RAM + || MMU.CPU_MEM_TYPE[i] == MMU.BANKTYPE_DRAM) + { + size += 8 * 1024; // 8K BANK + } + } + + // SAVE VRAM MEMORY DATA + for (int i = 0; i < 12; i++) + { + state.mmu.PPU_MEM_TYPE[i] = MMU.PPU_MEM_TYPE[i]; + state.mmu.PPU_MEM_PAGE[i] = (ushort)MMU.PPU_MEM_PAGE[i]; + } + size += 4 * 1024; // 1K BANK x 4 (VRAM) + + for (int i = 0; i < 8; i++) + { + state.mmu.CRAM_USED[i] = MMU.CRAM_USED[i]; + if (MMU.CRAM_USED[i] != 0) + { + size += 4 * 1024; // 4K BANK + } + } + + // Create Header + state.mmuBLOCK.ID = "MMU DATA"; + state.mmuBLOCK.BlockVersion = 0x0200; + state.mmuBLOCK.BlockSize = size + state.mmu.GetSize(); + + state.CPU_MEM_BANK = new List(); + // WRITE CPU RAM MEMORY BANK + for (int i = 3; i < 8; i++) + { + if (state.mmu.CPU_MEM_TYPE[i] != MMU.BANKTYPE_ROM) + { + state.CPU_MEM_BANK.AddRange(MMU.CPU_MEM_BANK[i].Span(0, 8 * 1024).ToArray()); + } + } + + // WRITE VRAM MEMORY(4K֤٤ƕz) + state.VRAM = new byte[4 * 1024]; + Array.Copy(MMU.VRAM, state.VRAM, state.VRAM.Length); + + state.CRAM = new List(); + // WRITE CRAM MEMORY + for (int i = 0; i < 8; i++) + { + if (MMU.CRAM_USED[i] != 0) + { + var bytes = new byte[4 * 1024]; + Array.Copy(MMU.CRAM, 0x1000 * i, bytes, 0, bytes.Length); + state.CRAM.AddRange(bytes); + } + } + } + + // MMC STATE + { + state.mmc = MMCSTAT.GetDefault(); + + // Create Header + state.mmcBLOCK.ID = "MMC DATA"; + state.mmcBLOCK.BlockVersion = 0x0100; + state.mmcBLOCK.BlockSize = state.mmc.GetSize(); + + if (mapper.IsStateSave()) + { + mapper.SaveState(state.mmc.mmcdata); + } + } + + //CONTROLLER STATE + { + // Create Header + state.ctrBLOCK.ID = "CTR DATA"; + state.ctrBLOCK.BlockVersion = 0x0100; + state.ctrBLOCK.BlockSize = state.ctr.GetSize(); + + state.ctr.pad1bit = pad.pad1bit; + state.ctr.pad2bit = pad.pad2bit; + state.ctr.pad3bit = pad.pad3bit; + state.ctr.pad4bit = pad.pad4bit; + state.ctr.strobe = (byte)(pad.GetStrobe() ? 0xFF : 0); + } + + //SND STATE + { + state.snd = SNDSTAT.GetDefault(); + + // Create Header + state.sndBLOCK.ID = "SND DATA"; + state.sndBLOCK.BlockVersion = 0x0100; + state.sndBLOCK.BlockSize = state.snd.GetSize(); + + StateBuffer buffer = new StateBuffer(); + apu.SaveState(buffer); + Array.Copy(buffer.Data.ToArray(), state.snd.snddata, buffer.Data.Count); + } + + // DISKIMAGE STATE + if (rom.GetMapperNo() == 20) + { + var lpDisk = rom.GetPROM(); + var lpWrite = rom.GetDISK(); + int DiskSize = 16 + 65500 * rom.GetDiskNo(); + + + // `򥫥 + for (int i = 16; i < DiskSize; i++) + { + if (lpWrite[i] != 0) + state.dsk.DifferentSize++; + } + + state.dskBLOCK.ID = "DISKDATA"; + state.dskBLOCK.BlockVersion = 0x0210; + state.dskBLOCK.BlockSize = 0; + + for (int i = 16; i < DiskSize; i++) + { + if (lpWrite[i] != 0) + { + state.dskdata = (uint)(i & 0x00FFFFFF); + state.dskdata |= ((uint)lpDisk[i] & 0xFF) << 24; + } + } + } + + // EXCTR STATE + if (pad.GetExController() != 0) + { + state.exctrBLOCK.ID = "EXCTRDAT"; + state.exctrBLOCK.BlockVersion = 0x0100; + state.exctrBLOCK.BlockSize = state.exctr.GetSize(); + + // Some excontrollers will default 0 + state.exctr.data = pad.GetSyncExData(); + } + + return state; + } + + public void LoadState(State state) + { + + } + public enum IRQMETHOD { IRQ_HSYNC = 0, IRQ_CLOCK = 1 diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PAD.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PAD.cs index 836e44c..f418d58 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PAD.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PAD.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using Codice.CM.Client.Differences; +using System; +using System.Collections.Generic; namespace VirtualNes.Core { @@ -507,6 +509,68 @@ namespace VirtualNes.Core { return excontroller_select; } + + internal bool GetStrobe() + { + return bStrobe; + } + + internal uint GetSyncExData() + { + uint data = 0; + + switch ((EXCONTROLLER)excontroller_select) + { + case EXCONTROLLER.EXCONTROLLER_ZAPPER: + case EXCONTROLLER.EXCONTROLLER_PADDLE: + case EXCONTROLLER.EXCONTROLLER_SPACESHADOWGUN: + case EXCONTROLLER.EXCONTROLLER_OEKAKIDS_TABLET: + case EXCONTROLLER.EXCONTROLLER_VSZAPPER: + { + int x, y; + x = expad.GetSyncData(0); + y = expad.GetSyncData(1); + if (x == -1 || y == -1) + { + data = 0x80000000; + } + else + { + data = (uint)((x & 0xFF) | ((y & 0xFF) << 8)); + } + } + if (excontroller_select != (int)EXCONTROLLER.EXCONTROLLER_SPACESHADOWGUN) + { + if (expad.GetSyncData(2) != 0) + data |= 0x0010000; + } + else + { + data |= (uint)(expad.GetSyncData(2) << 16); + } + break; + case EXCONTROLLER.EXCONTROLLER_CRAZYCLIMBER: + data = (uint)expad.GetSyncData(0); + break; + case EXCONTROLLER.EXCONTROLLER_TOPRIDER: + data = (uint)expad.GetSyncData(0); + break; + case EXCONTROLLER.EXCONTROLLER_FAMILYTRAINER_A: + case EXCONTROLLER.EXCONTROLLER_FAMILYTRAINER_B: + data = (uint)expad.GetSyncData(0); + break; + case EXCONTROLLER.EXCONTROLLER_EXCITINGBOXING: + data = (uint)expad.GetSyncData(0); + break; + case EXCONTROLLER.EXCONTROLLER_MAHJANG: + data = (uint)expad.GetSyncData(0); + break; + + default: + break; + } + return data; + } } public enum VSType diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State.meta b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State.meta new file mode 100644 index 0000000..4afed5a --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 915f7790a5c8e34469efbee412b66d3a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/BLOCKHDR.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/BLOCKHDR.cs new file mode 100644 index 0000000..f9a6a03 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/BLOCKHDR.cs @@ -0,0 +1,23 @@ +namespace VirtualNes.Core +{ + public struct BLOCKHDR : IStateBufferObject + { + public string ID; + public ushort Reserved; + public ushort BlockVersion; + public uint BlockSize; + + public readonly void SaveState(StateBuffer buffer) + { + buffer.Write(ID); + buffer.Write(Reserved); + buffer.Write(BlockVersion); + buffer.Write(BlockSize); + } + + public readonly uint GetSize() + { + return (uint)(ID.Length + sizeof(ushort) + sizeof(ushort) + sizeof(uint)); + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/NESCOMMAND.cs.meta b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/BLOCKHDR.cs.meta similarity index 83% rename from AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/NESCOMMAND.cs.meta rename to AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/BLOCKHDR.cs.meta index db767eb..beaf18e 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/NESCOMMAND.cs.meta +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/BLOCKHDR.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d7e8126382c9728429056ba33afc85eb +guid: 4c00b92c189cbc841a1f8e26749ba6df MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/CTRSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/CTRSTAT.cs new file mode 100644 index 0000000..950610a --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/CTRSTAT.cs @@ -0,0 +1,28 @@ +using Codice.CM.Client.Differences; +using System; + +namespace VirtualNes.Core +{ + public struct CTRSTAT : IStateBufferObject + { + public uint pad1bit; + public uint pad2bit; + public uint pad3bit; + public uint pad4bit; + public byte strobe; + + public readonly uint GetSize() + { + return sizeof(uint) * 4 + sizeof(byte); + } + + public readonly void SaveState(StateBuffer buffer) + { + buffer.Write(pad1bit); + buffer.Write(pad2bit); + buffer.Write(pad3bit); + buffer.Write(pad4bit); + buffer.Write(strobe); + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/CTRSTAT.cs.meta b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/CTRSTAT.cs.meta new file mode 100644 index 0000000..b5613b1 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/CTRSTAT.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be39d1ba53756fc4fa9cbdc7d7fc34a2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/DISKDATA.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/DISKDATA.cs new file mode 100644 index 0000000..9ff4b22 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/DISKDATA.cs @@ -0,0 +1,7 @@ +namespace VirtualNes.Core +{ + public struct DISKDATA + { + public int DifferentSize; + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/DISKDATA.cs.meta b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/DISKDATA.cs.meta new file mode 100644 index 0000000..c576319 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/DISKDATA.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f364c4c9681ea6b4fad0c68f42f9b230 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/EXCTRSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/EXCTRSTAT.cs new file mode 100644 index 0000000..8351127 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/EXCTRSTAT.cs @@ -0,0 +1,17 @@ +namespace VirtualNes.Core +{ + public struct EXCTRSTAT : IStateBufferObject + { + public uint data; + + public readonly uint GetSize() + { + return sizeof(uint); + } + + public readonly void SaveState(StateBuffer buffer) + { + throw new System.NotImplementedException(); + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/EXCTRSTAT.cs.meta b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/EXCTRSTAT.cs.meta new file mode 100644 index 0000000..51cd6ba --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/EXCTRSTAT.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ed6b363609705fd41a70255c4bbc7dd2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/FILEHDR2.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/FILEHDR2.cs new file mode 100644 index 0000000..b8c62fb --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/FILEHDR2.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace VirtualNes.Core +{ + public struct FILEHDR2 : IStateBufferObject + { + public string ID; + /// 2字节 + public ushort BlockVersion; + /// 4字节 + public uint Ext0; + /// 2字节 + public ushort Ext1; + /// 2字节 + public ushort Ext2; + + public void SaveState(StateBuffer buffer) + { + buffer.Write(ID); + buffer.Write(BlockVersion); + buffer.Write(Ext1); + buffer.Write(Ext2); + } + + public uint GetSize() + { + return (uint)(ID.Length + sizeof(ushort) + sizeof(uint) + sizeof(ushort) + sizeof(ushort)); + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/FILEHDR2.cs.meta b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/FILEHDR2.cs.meta new file mode 100644 index 0000000..c673a9c --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/FILEHDR2.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 86729820f1e0c0d4cbd58955e1238fd6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMCSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMCSTAT.cs new file mode 100644 index 0000000..2f5ada0 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMCSTAT.cs @@ -0,0 +1,22 @@ +namespace VirtualNes.Core +{ + public struct MMCSTAT : IStateBufferObject + { + public byte[] mmcdata; + + public static MMCSTAT GetDefault() + { + return new MMCSTAT() { mmcdata = new byte[256] }; + } + + public uint GetSize() + { + return (uint)mmcdata.Length; + } + + public void SaveState(StateBuffer buffer) + { + buffer.Write(mmcdata); + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMCSTAT.cs.meta b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMCSTAT.cs.meta new file mode 100644 index 0000000..5d6157b --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMCSTAT.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 61532b9db0674494099449267f13b2c5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMUSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMUSTAT.cs new file mode 100644 index 0000000..1109c89 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMUSTAT.cs @@ -0,0 +1,38 @@ +namespace VirtualNes.Core +{ + public struct MMUSTAT : IStateBufferObject + { + public byte[] CPU_MEM_TYPE; + public ushort[] CPU_MEM_PAGE; + public byte[] PPU_MEM_TYPE; + public ushort[] PPU_MEM_PAGE; + public byte[] CRAM_USED; + + public static MMUSTAT GetDefault() + { + var res = new MMUSTAT(); + + res.CPU_MEM_TYPE = new byte[8]; + res.CPU_MEM_PAGE = new ushort[8]; + res.PPU_MEM_TYPE = new byte[12]; + res.PPU_MEM_PAGE = new ushort[12]; + res.CRAM_USED = new byte[8]; + + return res; + } + + public uint GetSize() + { + return (uint)(CPU_MEM_TYPE.Length + CPU_MEM_PAGE.Length + PPU_MEM_TYPE.Length + PPU_MEM_PAGE.Length + CRAM_USED.Length); + } + + public void SaveState(StateBuffer buffer) + { + buffer.Write(CPU_MEM_TYPE); + buffer.Write(CPU_MEM_PAGE); + buffer.Write(PPU_MEM_TYPE); + buffer.Write(PPU_MEM_PAGE); + buffer.Write(CRAM_USED); + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMUSTAT.cs.meta b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMUSTAT.cs.meta new file mode 100644 index 0000000..8e91228 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMUSTAT.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bae9e1d800e0de741b04ec6979bc086f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/RAMSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/RAMSTAT.cs new file mode 100644 index 0000000..f6eec9e --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/RAMSTAT.cs @@ -0,0 +1,38 @@ + +namespace VirtualNes.Core +{ + public struct RAMSTAT : IStateBufferObject + { + /// Internal NES RAM + public byte[] RAM; + /// BG Palette + public byte[] BGPAL; + /// SP Palette + public byte[] SPPAL; + /// Sprite RAM + public byte[] SPRAM; + + public static RAMSTAT GetDefault() + { + var res = new RAMSTAT(); + res.RAM = new byte[2 * 1024]; + res.BGPAL = new byte[16]; + res.SPPAL = new byte[16]; + res.SPRAM = new byte[256]; + return res; + } + + public readonly uint GetSize() + { + return (uint)(RAM.Length + BGPAL.Length + SPPAL.Length + SPRAM.Length); + } + + public readonly void SaveState(StateBuffer buffer) + { + buffer.Write(RAM); + buffer.Write(BGPAL); + buffer.Write(SPPAL); + buffer.Write(SPRAM); + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/RAMSTAT.cs.meta b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/RAMSTAT.cs.meta new file mode 100644 index 0000000..e110163 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/RAMSTAT.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1acd6e5360be08b4e88b477d7983aa1d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/REGSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/REGSTAT.cs new file mode 100644 index 0000000..52ce17d --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/REGSTAT.cs @@ -0,0 +1,96 @@ +namespace VirtualNes.Core +{ + public struct REGSTAT : IStateBufferObject + { + public CPUSTAT cpureg; + public PPUSTAT ppureg; + + public void SaveState(StateBuffer buffer) + { + cpureg.SaveState(buffer); + ppureg.SaveState(buffer); + } + + public uint GetSize() + { + return cpureg.GetSize() + ppureg.GetSize(); + } + } + + public struct CPUSTAT : IStateBufferObject + { + public ushort PC; + public byte A; + public byte X; + public byte Y; + public byte S; + public byte P; + public byte I; // Interrupt pending flag + + public byte FrameIRQ; + public byte FrameIRQ_occur; + public byte FrameIRQ_count; + public byte FrameIRQ_type; + public int FrameIRQ_cycles; + public int DMA_cycles; + + public long emul_cycles; + public long base_cycles; + + public readonly uint GetSize() + { + return 32; + } + + public readonly void SaveState(StateBuffer buffer) + { + buffer.Write(PC); + buffer.Write(A); + buffer.Write(X); + buffer.Write(Y); + buffer.Write(S); + buffer.Write(P); + buffer.Write(I); + buffer.Write(FrameIRQ); + buffer.Write(FrameIRQ_occur); + buffer.Write(FrameIRQ_count); + buffer.Write(FrameIRQ_type); + buffer.Write(FrameIRQ_cycles); + buffer.Write(DMA_cycles); + buffer.Write(emul_cycles); + buffer.Write(base_cycles); + } + } + + public struct PPUSTAT : IStateBufferObject + { + public byte reg0; + public byte reg1; + public byte reg2; + public byte reg3; + public byte reg7; + public byte toggle56; + + public ushort loopy_t; + public ushort loopy_v; + public ushort loopy_x; + + public readonly uint GetSize() + { + return 12; + } + + public readonly void SaveState(StateBuffer buffer) + { + buffer.Write(reg0); + buffer.Write(reg1); + buffer.Write(reg2); + buffer.Write(reg3); + buffer.Write(reg7); + buffer.Write(toggle56); + buffer.Write(loopy_t); + buffer.Write(loopy_v); + buffer.Write(loopy_x); + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/REGSTAT.cs.meta b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/REGSTAT.cs.meta new file mode 100644 index 0000000..3858ea9 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/REGSTAT.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1350a5cfb70265848b3af2a05a2709eb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/SNDSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/SNDSTAT.cs new file mode 100644 index 0000000..38bd9e9 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/SNDSTAT.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace VirtualNes.Core +{ + public struct SNDSTAT : IStateBufferObject + { + public byte[] snddata; + + public static SNDSTAT GetDefault() + { + return new SNDSTAT() { snddata = new byte[0x800] }; + } + + public uint GetSize() + { + return (uint)snddata.Length; + } + + public void SaveState(StateBuffer buffer) + { + buffer.Write(snddata); + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/SNDSTAT.cs.meta b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/SNDSTAT.cs.meta new file mode 100644 index 0000000..ba3e420 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/SNDSTAT.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1906102fbfecacf4a988a89e6d373c10 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/State.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/State.cs new file mode 100644 index 0000000..2edd3fb --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/State.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; + +namespace VirtualNes.Core +{ + public struct State + { + public FILEHDR2 HEADER; + + public BLOCKHDR regBLOCK; + public REGSTAT reg; + + public BLOCKHDR ramBLOCK; + public RAMSTAT ram; + /// Maybe null cause by rom IsSaveRAM() + public byte[] WRAM; + + public BLOCKHDR mmuBLOCK; + public MMUSTAT mmu; + public List CPU_MEM_BANK; + public byte[] VRAM; + public List CRAM; + + public BLOCKHDR mmcBLOCK; + public MMCSTAT mmc; + + public BLOCKHDR ctrBLOCK; + public CTRSTAT ctr; + + public BLOCKHDR sndBLOCK; + public SNDSTAT snd; + + public BLOCKHDR dskBLOCK; + public DISKDATA dsk; + public uint dskdata; + + public BLOCKHDR exctrBLOCK; + public EXCTRSTAT exctr; + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/State.cs.meta b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/State.cs.meta new file mode 100644 index 0000000..723c7b7 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/State.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b685425b0082cf246bf59e849aef0d0b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/StateBuffer.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/StateBuffer.cs new file mode 100644 index 0000000..b5c86f2 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/StateBuffer.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace VirtualNes.Core +{ + public class StateBuffer + { + public List Data = new List(); + + public long Position + { + get => Data.Count - 1; + set + { + var gap = value - Position; + if (gap > 0) + { + Data.AddRange(new byte[gap]); + } + else + { + Data.RemoveRange((int)Position, (int)gap); + } + } + } + + public void Write(byte[] bytes) + { + Data.AddRange(bytes); + } + public void Write(sbyte[] sbytes) + { + foreach(var value in sbytes) + { + Write(value); + } + } + public void Write(byte[] bytes, int length) + { + Data.AddRange(bytes); + } + public void Write(byte value) + { + Data.Add(value); + } + public void Write(ushort[] values) + { + foreach (var value in values) + Write(value); + } + public void Write(int[] values) + { + foreach (var value in values) + Write(value); + } + public void Write(string value) + { + Write(Encoding.ASCII.GetBytes(value)); + } + public void Write(double value) + { + Write(BitConverter.GetBytes(value)); + } + public void Write(ushort value) + { + Write(BitConverter.GetBytes(value)); + } + public void Write(int value) + { + Write(BitConverter.GetBytes(value)); + } + public void Write(sbyte value) + { + Write(value); + } + public void Write(long value) + { + Write(BitConverter.GetBytes(value)); + } + } + + public interface IStateBufferObject + { + uint GetSize(); + void SaveState(StateBuffer buffer); + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/StateBuffer.cs.meta b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/StateBuffer.cs.meta new file mode 100644 index 0000000..595c59d --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/StateBuffer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f215860b2526aa04a819da176e190437 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/ProjectSettings/ProjectSettings.asset b/AxibugEmuOnline.Client/ProjectSettings/ProjectSettings.asset index b5cb201..641bd9f 100644 --- a/AxibugEmuOnline.Client/ProjectSettings/ProjectSettings.asset +++ b/AxibugEmuOnline.Client/ProjectSettings/ProjectSettings.asset @@ -658,7 +658,7 @@ PlayerSettings: additionalCompilerArguments: {} platformArchitecture: {} scriptingBackend: - Android: 1 + Android: 0 Standalone: 1 il2cppCompilerConfiguration: {} managedStrippingLevel: {}