diff --git a/AxibugEmuOnline.Client/Assets/Script/Manager/AppRoom.cs b/AxibugEmuOnline.Client/Assets/Script/Manager/AppRoom.cs
index 84f08bf2..3e957630 100644
--- a/AxibugEmuOnline.Client/Assets/Script/Manager/AppRoom.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/Manager/AppRoom.cs
@@ -359,7 +359,7 @@ namespace AxibugEmuOnline.Client.Manager
         void RecvHostSyn_RoomFrameAllInputData(byte[] reqData)
         {
             Protobuf_Room_Syn_RoomFrameAllInputData msg = ProtoBufHelper.DeSerizlize<Protobuf_Room_Syn_RoomFrameAllInputData>(reqData);
-            netReplay.InData(new ReplayStep() { FrameStartID = (int)msg.FrameID, InPut = msg.InputData }, (int)msg.ServerFrameID);
+            //netReplay.InData(new ReplayStep() { FrameStartID = (int)msg.FrameID, InPut = msg.InputData }, (int)msg.ServerFrameID);
         }
 
         public void SendScreen(byte[] RenderBuffer)
diff --git a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI.cs b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI.cs
index 6f5810ef..f99d8e88 100644
--- a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI.cs
@@ -5,15 +5,16 @@ namespace AxibugEmuOnline.Client
 {
     public class InGameUI : CommandExecuter
     {
-
         public static InGameUI Instance { get; private set; }
 
         public RomFile RomFile => m_rom;
         public override bool Enable => gameObject.activeInHierarchy;
         private RomFile m_rom;
         private object m_core;
+        private object m_state;
 
-        private InGameUI_SaveState m_saveMenu;
+        private InGameUI_SaveState m_saveStateMenu;
+        private InGameUI_LoadState m_loadStateMenu;
 
         protected override void Awake()
         {
@@ -27,15 +28,47 @@ namespace AxibugEmuOnline.Client
             Instance = null;
         }
 
+        /// <summary>
+        /// ��ȡģ�������Ķ���
+        /// </summary>
+        /// <typeparam name="T">�������������</typeparam>
         public T GetCore<T>() => (T)m_core;
+        /// <summary> ������ٿ��� </summary>
+        public void SaveQuickState(object state)
+        {
+            m_state = state;
+        }
+        /// <summary>
+        /// ��ȡ���ٿ���
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <returns></returns>
+        public bool GetQuickState<T>(out T state)
+        {
+            state = default(T);
+
+            if (m_state is T)
+            {
+                state = (T)m_state;
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+
+        }
 
         public void Show(RomFile currentRom, object core)
         {
-            m_saveMenu = new InGameUI_SaveState(this);
             CommandDispatcher.Instance.RegistController(this);
 
+            m_saveStateMenu = new InGameUI_SaveState(this);
+            m_loadStateMenu = new InGameUI_LoadState(this);
+
             m_rom = currentRom;
             m_core = core;
+
             gameObject.SetActiveEx(true);
         }
 
@@ -43,14 +76,12 @@ namespace AxibugEmuOnline.Client
         {
             CommandDispatcher.Instance.UnRegistController(this);
 
-            m_rom = null;
-            m_core = null;
             gameObject.SetActiveEx(false);
         }
 
         protected override void OnCmdOptionMenu()
         {
-            OptionUI.Instance.Pop(new List<OptionMenu> { m_saveMenu });
+            OptionUI.Instance.Pop(new List<OptionMenu> { m_saveStateMenu, m_loadStateMenu });
         }
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_LoadState.cs b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_LoadState.cs
new file mode 100644
index 00000000..8a4863d0
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_LoadState.cs
@@ -0,0 +1,32 @@
+using AxibugEmuOnline.Client.ClientCore;
+using System.Diagnostics;
+using VirtualNes.Core;
+
+namespace AxibugEmuOnline.Client
+{
+    public class InGameUI_LoadState : ExecuteMenu
+    {
+        private InGameUI m_gameUI;
+
+        public InGameUI_LoadState(InGameUI gameUI) : base("��ȡ����", null)
+        {
+            m_gameUI = gameUI;
+        }
+
+        public override void OnExcute()
+        {
+            Stopwatch sw = Stopwatch.StartNew();
+            switch (m_gameUI.RomFile.Platform)
+            {
+                case EnumPlatform.NES:
+                    if (m_gameUI.GetQuickState<State>(out var quickState))
+                    {
+                        m_gameUI.GetCore<NesEmulator>().NesCore.LoadState(quickState);
+                    }
+                    break;
+            }
+            sw.Stop();
+            App.log.Info($"{m_gameUI.RomFile.Platform}====>���ռ��غ�ʱ:{sw.Elapsed.TotalMilliseconds}ms");
+        }
+    }
+}
diff --git a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_LoadState.cs.meta b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_LoadState.cs.meta
new file mode 100644
index 00000000..f65bbdb1
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_LoadState.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 522140a3272d84a40b1ff91a3ebdb1b0
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_SaveState.cs b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_SaveState.cs
index 3791d53b..4bfc095a 100644
--- a/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_SaveState.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/UI/InGameUI/InGameUI_SaveState.cs
@@ -19,6 +19,7 @@ namespace AxibugEmuOnline.Client
             {
                 case EnumPlatform.NES:
                     var state = m_gameUI.GetCore<NesEmulator>().NesCore.GetState();
+                    m_gameUI.SaveQuickState(state);
                     App.log.Info($"{m_gameUI.RomFile.Platform}===>���մ�С{state.ToBytes().Length}");
                     break;
             }
diff --git a/AxibugEmuOnline.Client/Assets/Script/UI/OptionUI/OptionUI.cs b/AxibugEmuOnline.Client/Assets/Script/UI/OptionUI/OptionUI.cs
index 72135e7c..46fe147c 100644
--- a/AxibugEmuOnline.Client/Assets/Script/UI/OptionUI/OptionUI.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/UI/OptionUI/OptionUI.cs
@@ -168,6 +168,9 @@ namespace AxibugEmuOnline.Client
     {
         public string Name { get; protected set; }
         public Sprite Icon { get; protected set; }
+        public virtual bool Visible => true;
+        public virtual bool Enable => true;
+
         public OptionMenu(string name, Sprite icon = null)
         {
             Name = name;
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/APU.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/APU.cs
index 0aa713b6..fb7e9b50 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/APU.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/APU.cs
@@ -543,6 +543,11 @@ namespace VirtualNes.Core
             @internal.GetFrameIRQ(ref Cycle, ref Count, ref Type, ref IRQ, ref Occur);
         }
 
+        internal void SetFrameIRQ(int Cycle, byte Count, byte Type, byte IRQ, byte Occur)
+        {
+            @internal.SetFrameIRQ(Cycle, Count, Type, IRQ, Occur);
+        }
+
         internal void SaveState(StateBuffer buffer)
         {
             // 時間軸を同期させる為Flushする
@@ -579,7 +584,7 @@ namespace VirtualNes.Core
             // N106
             if ((exsound_select & 0x10) != 0)
             {
-                n106.SaveState(buffer); 
+                n106.SaveState(buffer);
                 buffer.Position += (n106.GetSize() + 15) & (~0x0F);  // Padding
             }
             // FME7
@@ -589,6 +594,49 @@ namespace VirtualNes.Core
                 buffer.Position += (fme7.GetSize() + 15) & (~0x0F);  // Padding
             }
         }
+
+        internal void LoadState(StateReader buffer)
+        {
+            @internal.LoadState(buffer);
+            buffer.Skip((@internal.GetSize() + 15) & (~0x0F));
+
+            // VRC6
+            if ((exsound_select & 0x01) != 0)
+            {
+                vrc6.LoadState(buffer);
+                buffer.Skip((int)((vrc6.GetSize() + 15) & (~0x0F)));  // Padding
+            }
+            // VRC7 (not support)
+            if ((exsound_select & 0x02) != 0)
+            {
+                vrc7.LoadState(buffer);
+                buffer.Skip((vrc7.GetSize() + 15) & (~0x0F));  // Padding
+            }
+            // FDS
+            if ((exsound_select & 0x04) != 0)
+            {
+                fds.LoadState(buffer);
+                buffer.Skip((fds.GetSize() + 15) & (~0x0F));   // Padding
+            }
+            // MMC5
+            if ((exsound_select & 0x08) != 0)
+            {
+                mmc5.LoadState(buffer);
+                buffer.Skip((mmc5.GetSize() + 15) & (~0x0F));  // Padding
+            }
+            // N106
+            if ((exsound_select & 0x10) != 0)
+            {
+                n106.LoadState(buffer);
+                buffer.Skip((n106.GetSize() + 15) & (~0x0F));  // Padding
+            }
+            // FME7
+            if ((exsound_select & 0x20) != 0)
+            {
+                fme7.LoadState(buffer);
+                buffer.Skip((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 88566a05..a6b51765 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FDS.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FDS.cs
@@ -514,6 +514,36 @@ namespace VirtualNes.Core
                 buffer.Write(now_freq);
                 buffer.Write(output);
             }
+
+            public void LoadState(StateReader buffer)
+            {
+                reg = buffer.Read_bytes(0x80);
+                volenv_mode = buffer.Read_byte();
+                volenv_gain = buffer.Read_byte();
+                volenv_decay = buffer.Read_byte();
+                volenv_phaseacc = buffer.Read_double();
+                swpenv_mode = buffer.Read_byte();
+                swpenv_gain = buffer.Read_byte();
+                swpenv_decay = buffer.Read_byte();
+                swpenv_phaseacc = buffer.Read_double();
+                envelope_enable = buffer.Read_byte();
+                envelope_speed = buffer.Read_byte();
+                wave_setup = buffer.Read_byte();
+                master_volume = buffer.Read_int();
+                main_wavetable = buffer.Read_ints(64);
+                main_enable = buffer.Read_byte();
+                main_frequency = buffer.Read_int();
+                main_addr = buffer.Read_int();
+                lfo_wavetable = buffer.Read_bytes(64);
+                lfo_enable = buffer.Read_byte();
+                lfo_frequency = buffer.Read_int();
+                lfo_addr = buffer.Read_int();
+                lfo_phaseacc = buffer.Read_double();
+                sweep_bias = buffer.Read_int();
+                now_volume = buffer.Read_int();
+                now_freq = buffer.Read_int();
+                output = buffer.Read_int();
+            }
         }
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FME7.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FME7.cs
index c7070847..cbe66964 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FME7.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FME7.cs
@@ -398,6 +398,17 @@ namespace VirtualNes.Core
                 buffer.Write(envtbl_index);
                 buffer.Write(envstep_index);
             }
+
+            public void LoadState(StateReader buffer)
+            {
+                reg = buffer.Read_bytes(3);
+                volume = buffer.Read_byte();
+                freq = buffer.Read_int();
+                phaseacc = buffer.Read_int();
+                envadr = buffer.Read_int();
+                envtbl_index = buffer.Read_byte();
+                envstep_index = buffer.Read_byte();
+            }
         }
 
         public class NOISE : IStateBufferObject
@@ -424,6 +435,14 @@ namespace VirtualNes.Core
                 buffer.Write(noiserange);
                 buffer.Write(noiseout);
             }
+
+            public void LoadState(StateReader buffer)
+            {
+                freq = buffer.Read_int();
+                phaseacc = buffer.Read_int();
+                noiserange = buffer.Read_int();
+                noiseout = buffer.Read_byte();
+            }
         }
 
         public class CHANNEL : IStateBufferObject
@@ -469,6 +488,19 @@ namespace VirtualNes.Core
                 buffer.Write(phaseacc);
                 buffer.Write(output_vol);
             }
+
+            public void LoadState(StateReader buffer)
+            {
+                reg = buffer.Read_bytes(3);
+                enable = buffer.Read_byte();
+                env_on = buffer.Read_byte();
+                noise_on = buffer.Read_byte();
+                adder = buffer.Read_byte();
+                volume = buffer.Read_byte();
+                freq = buffer.Read_int();
+                phaseacc = buffer.Read_int();
+                output_vol = buffer.Read_int();
+            }
         }
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERFACE.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERFACE.cs
index db28ed62..49378acf 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERFACE.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERFACE.cs
@@ -23,7 +23,7 @@ namespace VirtualNes.Core
         public virtual bool Sync(int cycles) { return false; }
         public virtual int GetFreq(int channel) { return 0; }
         public virtual void SaveState(StateBuffer buffer) { }
-        public virtual void LoadState(byte[] p) { }
+        public virtual void LoadState(StateReader buffer) { }
 
         public static int INT2FIX(int x)
         {
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERNAL.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERNAL.cs
index 51c8aef8..07d19328 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERNAL.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_INTERNAL.cs
@@ -1203,6 +1203,15 @@ namespace VirtualNes.Core
             occur = FrameIRQoccur;
         }
 
+        internal void SetFrameIRQ(int cycle, byte count, byte type, byte IRQ, byte occur)
+        {
+            FrameCycle = cycle;
+            FrameCount = count;
+            FrameType = type;
+            FrameIRQ = IRQ;
+            FrameIRQoccur = occur;
+        }
+
         public override uint GetSize()
         {
             return sizeof(byte) +
@@ -1219,7 +1228,7 @@ namespace VirtualNes.Core
             ch4.GetSize();
         }
 
-        public unsafe override void SaveState(StateBuffer p)
+        public override void SaveState(StateBuffer p)
         {
             p.Write(reg4015);
             p.Write(sync_reg4015);
@@ -1352,6 +1361,39 @@ namespace VirtualNes.Core
                 buffer.Write(dummy2);
                 buffer.Write(sync_len_count);
             }
+
+            public void LoadState(StateReader buffer)
+            {
+                reg = buffer.Read_bytes(4);
+                enable = buffer.Read_byte();
+                holdnote = buffer.Read_byte();
+                volume = buffer.Read_byte();
+                complement = buffer.Read_byte();
+                phaseacc = buffer.Read_int();
+                freq = buffer.Read_int();
+                freqlimit = buffer.Read_int();
+                adder = buffer.Read_int();
+                duty = buffer.Read_int();
+                len_count = buffer.Read_int();
+                nowvolume = buffer.Read_int();
+                env_fixed = buffer.Read_byte();
+                env_decay = buffer.Read_byte();
+                env_count = buffer.Read_byte();
+                dummy0 = buffer.Read_byte();
+                env_vol = buffer.Read_int();
+                swp_on = buffer.Read_byte();
+                swp_inc = buffer.Read_byte();
+                swp_shift = buffer.Read_byte();
+                swp_decay = buffer.Read_byte();
+                swp_count = buffer.Read_byte();
+                dummy1 = buffer.Read_bytes(3);
+                sync_reg = buffer.Read_bytes(4);
+                sync_output_enable = buffer.Read_byte();
+                sync_enable = buffer.Read_byte();
+                sync_holdnote = buffer.Read_byte();
+                dummy2 = buffer.Read_byte();
+                sync_len_count = buffer.Read_int();
+            }
         }
         public class TRIANGLE : IStateBufferObject
         {
@@ -1428,6 +1470,27 @@ namespace VirtualNes.Core
                 buffer.Write(sync_len_count);
                 buffer.Write(sync_lin_count);
             }
+
+            public void LoadState(StateReader buffer)
+            {
+                reg = buffer.Read_bytes(4);
+                enable = buffer.Read_byte();
+                holdnote = buffer.Read_byte();
+                counter_start = buffer.Read_byte();
+                dummy0 = buffer.Read_byte();
+                phaseacc = buffer.Read_int();
+                freq = buffer.Read_int();
+                len_count = buffer.Read_int();
+                lin_count = buffer.Read_int();
+                adder = buffer.Read_int();
+                nowvolume = buffer.Read_int();
+                sync_reg = buffer.Read_bytes(4);
+                sync_enable = buffer.Read_byte();
+                sync_holdnote = buffer.Read_byte();
+                sync_counter_start = buffer.Read_byte();
+                sync_len_count = buffer.Read_int();
+                sync_lin_count = buffer.Read_int();
+            }
         }
         public class DPCM : IStateBufferObject
         {
@@ -1487,6 +1550,35 @@ namespace VirtualNes.Core
                 buffer.Write(sync_dmalength);
                 buffer.Write(sync_cache_dmalength);
             }
+
+            public void LoadState(StateReader buffer)
+            {
+                reg = buffer.Read_bytes(4);
+                enable = buffer.Read_byte();
+                looping = buffer.Read_byte();
+                cur_byte = buffer.Read_byte();
+                dpcm_value = buffer.Read_byte();
+                freq = buffer.Read_int();
+                phaseacc = buffer.Read_int();
+                output = buffer.Read_int();
+                address = buffer.Read_ushort();
+                cache_addr = buffer.Read_ushort();
+                dmalength = buffer.Read_int();
+                cache_dmalength = buffer.Read_int();
+                dpcm_output_real = buffer.Read_int();
+                dpcm_output_fake = buffer.Read_int();
+                dpcm_output_old = buffer.Read_int();
+                dpcm_output_offset = buffer.Read_int();
+                sync_reg = buffer.Read_bytes(4);
+                sync_enable = buffer.Read_byte();
+                sync_looping = buffer.Read_byte();
+                sync_irq_gen = buffer.Read_byte();
+                sync_irq_enable = buffer.Read_byte();
+                sync_cycles = buffer.Read_int();
+                sync_cache_cycles = buffer.Read_int();
+                sync_dmalength = buffer.Read_int();
+                sync_cache_dmalength = buffer.Read_int();
+            }
         }
         public class NOISE : IStateBufferObject
         {
@@ -1582,6 +1674,32 @@ namespace VirtualNes.Core
                 buffer.Write(dummy1);
                 buffer.Write(sync_len_count);
             }
+
+            public void LoadState(StateReader buffer)
+            {
+                reg = buffer.Read_bytes(4);
+                enable = buffer.Read_byte();
+                holdnote = buffer.Read_byte();
+                volume = buffer.Read_byte();
+                xor_tap = buffer.Read_byte();
+                shift_reg = buffer.Read_int();
+                phaseacc = buffer.Read_int();
+                freq = buffer.Read_int();
+                len_count = buffer.Read_int();
+                nowvolume = buffer.Read_int();
+                output = buffer.Read_int();
+                env_fixed = buffer.Read_byte();
+                env_decay = buffer.Read_byte();
+                env_count = buffer.Read_byte();
+                dummy0 = buffer.Read_byte();
+                env_vol = buffer.Read_int();
+                sync_reg = buffer.Read_bytes(4);
+                sync_output_enable = buffer.Read_byte();
+                sync_enable = buffer.Read_byte();
+                sync_holdnote = buffer.Read_byte();
+                dummy1 = buffer.Read_byte();
+                sync_len_count = buffer.Read_int();
+            }
         }
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_MMC5.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_MMC5.cs
index f8f5ff03..cf5cc896 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_MMC5.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_MMC5.cs
@@ -421,6 +421,15 @@ namespace VirtualNes.Core
                 buffer.Write(dummy);
                 buffer.Write(vbl_length);
             }
+
+            public void LoadState(StateReader buffer)
+            {
+                reg = buffer.Read_bytes(4);
+                enable = buffer.Read_byte();
+                holdnote = buffer.Read_byte();
+                dummy = buffer.Read_bytes(2);
+                vbl_length = buffer.Read_int();
+            }
         }
 
         public class RECTANGLE : IStateBufferObject
@@ -467,6 +476,24 @@ namespace VirtualNes.Core
                 buffer.Write(adder);
                 buffer.Write(duty_flip);
             }
+
+            public void LoadState(StateReader buffer)
+            {
+                reg = buffer.Read_bytes(4);
+                enable = buffer.Read_byte();
+                vbl_length = buffer.Read_int();
+                phaseacc = buffer.Read_int();
+                freq = buffer.Read_int();
+                output_vol = buffer.Read_int();
+                fixed_envelope = buffer.Read_byte();
+                holdnote = buffer.Read_byte();
+                volume = buffer.Read_byte();
+                env_vol = buffer.Read_byte();
+                env_phase = buffer.Read_int();
+                env_decay = buffer.Read_int();
+                adder = buffer.Read_int();
+                duty_flip = buffer.Read_int();
+            }
         }
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_N106.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_N106.cs
index dadd4c7a..f9ea4e6c 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_N106.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_N106.cs
@@ -243,6 +243,19 @@ namespace VirtualNes.Core
                 buffer.Write(vol);
                 buffer.Write(databuf);
             }
+
+            public void LoadState(StateReader buffer)
+            {
+                phaseacc = buffer.Read_int();
+                freq = buffer.Read_uint();
+                phase = buffer.Read_uint();
+                tonelen = buffer.Read_uint();
+                output = buffer.Read_int();
+                toneadr = buffer.Read_byte();
+                volupdate = buffer.Read_byte();
+                vol = buffer.Read_byte();
+                databuf = buffer.Read_byte();
+            }
         }
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_VRC6.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_VRC6.cs
index cdc442f3..04f2f511 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_VRC6.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_VRC6.cs
@@ -304,6 +304,19 @@ namespace VirtualNes.Core
                 buffer.Write(adder);
                 buffer.Write(duty_pos);
             }
+
+            public void LoadState(StateReader buffer)
+            {
+                reg = buffer.Read_bytes(3);
+                enable = buffer.Read_byte();
+                gate = buffer.Read_byte();
+                volume = buffer.Read_byte();
+                phaseacc = buffer.Read_int();
+                freq = buffer.Read_int();
+                output_vol = buffer.Read_int();
+                adder = buffer.Read_byte();
+                duty_pos = buffer.Read_byte();
+            }
         }
 
         public class SAWTOOTH : IStateBufferObject
@@ -353,6 +366,19 @@ namespace VirtualNes.Core
                 buffer.Write(accum);
                 buffer.Write(phaseaccum);
             }
+
+            public void LoadState(StateReader buffer)
+            {
+                reg = buffer.Read_bytes(3);
+                enable = buffer.Read_byte();
+                volume = buffer.Read_byte();
+                phaseacc = buffer.Read_int();
+                freq = buffer.Read_int();
+                output_vol = buffer.Read_int();
+                adder = buffer.Read_byte();
+                accum = buffer.Read_byte();
+                phaseaccum = buffer.Read_byte();
+            }
         }
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs
index be4fc294..a17c7b92 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs
@@ -2022,10 +2022,20 @@ namespace VirtualNes.Core
             r = R;
         }
 
+        internal void SetContext(R6502 r)
+        {
+            R = r;
+        }
+
         internal int GetDmaCycles()
         {
             return DMA_cycles;
         }
+
+        internal void SetDmaCycles(int cycles)
+        {
+            DMA_cycles = 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 c23925c8..7a239152 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 void WriteTo(T[] source, int start, int length)
+        {
+            Array.Copy(source, 0, m_rawArray, Offset + start, length);
+        }
+
         public Span<T> Span(int start, int length)
         {
             return new Span<T>(m_rawArray, start + Offset, length);
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/NES.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/NES.cs
index 9ea39ef7..a66a5631 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/NES.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/NES.cs
@@ -1872,12 +1872,15 @@ namespace VirtualNes.Core
                 state.dskBLOCK.BlockVersion = 0x0210;
                 state.dskBLOCK.BlockSize = 0;
 
+                state.dskdata = new List<uint>();
+
                 for (int i = 16; i < DiskSize; i++)
                 {
                     if (lpWrite[i] != 0)
                     {
-                        state.dskdata = (uint)(i & 0x00FFFFFF);
-                        state.dskdata |= ((uint)lpDisk[i] & 0xFF) << 24;
+                        uint data = (uint)(i & 0x00FFFFFF);
+                        data |= ((uint)lpDisk[i] & 0xFF) << 24;
+                        state.dskdata.Add(data);
                     }
                 }
             }
@@ -1898,7 +1901,191 @@ namespace VirtualNes.Core
 
         public void LoadState(State state)
         {
+            //HEADER
+            {
+                state.HEADER.ID = "VirtuaNES ST";
+                state.HEADER.BlockVersion = 0x0200;
 
+                if (rom.GetMapperNo() != 20)
+                    rom.SetPROM_CRC(state.HEADER.Ext0);
+                else
+                {
+                    rom.SetGameID(state.HEADER.Ext0);
+                    rom.SetMakerID(state.HEADER.Ext1);
+                    rom.SetDiskNo(state.HEADER.Ext2);
+                }
+            }
+
+            //REGISTER STATE
+            {
+                R6502 R = new R6502();
+                R.PC = state.reg.cpureg.PC;
+                R.A = state.reg.cpureg.A;
+                R.X = state.reg.cpureg.X;
+                R.Y = state.reg.cpureg.Y;
+                R.S = state.reg.cpureg.S;
+                R.P = state.reg.cpureg.P;
+                R.INT_pending = state.reg.cpureg.I;
+                cpu.SetContext(R);
+
+                apu.SetFrameIRQ(
+                    state.reg.cpureg.FrameIRQ_cycles,
+                    state.reg.cpureg.FrameIRQ_count,
+                    state.reg.cpureg.FrameIRQ_type,
+                    state.reg.cpureg.FrameIRQ,
+                    state.reg.cpureg.FrameIRQ_occur
+                );
+
+
+                cpu.SetDmaCycles(state.reg.cpureg.DMA_cycles);
+                emul_cycles = state.reg.cpureg.emul_cycles;
+                base_cycles = state.reg.cpureg.base_cycles;
+
+                // LOAD PPU STATE
+                MMU.PPUREG[0] = state.reg.ppureg.reg0;
+                MMU.PPUREG[1] = state.reg.ppureg.reg1;
+                MMU.PPUREG[2] = state.reg.ppureg.reg2;
+                MMU.PPUREG[3] = state.reg.ppureg.reg3;
+                MMU.PPU7_Temp = state.reg.ppureg.reg7;
+                MMU.loopy_t = state.reg.ppureg.loopy_t;
+                MMU.loopy_v = state.reg.ppureg.loopy_v;
+                MMU.loopy_x = state.reg.ppureg.loopy_x;
+                MMU.PPU56Toggle = state.reg.ppureg.toggle56;
+            }
+
+            //RAM STATE
+            {
+                // SAVE RAM STATE
+                MemoryUtility.memcpy(MMU.RAM, state.ram.RAM, state.ram.RAM.Length);
+                MemoryUtility.memcpy(MMU.BGPAL, state.ram.BGPAL, state.ram.BGPAL.Length);
+                MemoryUtility.memcpy(MMU.SPPAL, state.ram.SPPAL, state.ram.SPPAL.Length);
+                MemoryUtility.memcpy(MMU.SPRAM, state.ram.SPRAM, state.ram.SPRAM.Length);
+
+                if (rom.IsSAVERAM())
+                {
+                    Array.Copy(state.WRAM, MMU.WRAM, SAVERAM_SIZE);
+                }
+            }
+
+            //BANK STATE
+            {
+                // SAVE CPU MEMORY BANK DATA
+                // BANK0,1,2�ϥХ󥯥��`�֤��v�S�ʤ�
+                // VirtuaNES0.30����
+                // �Х󥯣���SRAMʹ�ä��v��餺���`��
+                for (int i = 3; i < 8; i++)
+                {
+                    MMU.CPU_MEM_TYPE[i] = state.mmu.CPU_MEM_TYPE[i];
+                    MMU.CPU_MEM_PAGE[i] = state.mmu.CPU_MEM_PAGE[i];
+                }
+
+                // SAVE VRAM MEMORY DATA
+                for (int i = 0; i < 12; i++)
+                {
+                    MMU.PPU_MEM_TYPE[i] = state.mmu.PPU_MEM_TYPE[i];
+                    MMU.PPU_MEM_PAGE[i] = state.mmu.PPU_MEM_PAGE[i];
+                }
+
+                for (int i = 0; i < 8; i++)
+                {
+                    MMU.CRAM_USED[i] = state.mmu.CRAM_USED[i];
+                }
+
+                // WRITE CPU RAM MEMORY BANK
+
+                int stateStep = 0;
+                var stateCPU_MEM_BANK = state.CPU_MEM_BANK.ToArray();
+
+                for (int i = 3; i < 8; i++)
+                {
+                    if (state.mmu.CPU_MEM_TYPE[i] != MMU.BANKTYPE_ROM)
+                    {
+                        var sourceData = new Span<byte>(stateCPU_MEM_BANK, stateStep * 8 * 1024, 8 * 1024);
+                        MMU.CPU_MEM_BANK[i].WriteTo(sourceData.ToArray(), 0, 8 * 1024);
+                        stateStep++;
+                    }
+                }
+
+                Array.Copy(state.VRAM, MMU.VRAM, state.VRAM.Length);
+
+                stateStep = 0;
+                var stateCRAM = state.CRAM.ToArray();
+                // LOAD CRAM MEMORY
+                for (int i = 0; i < 8; i++)
+                {
+                    if (MMU.CRAM_USED[i] != 0)
+                    {
+                        var sourceData = stateCRAM.AsSpan(stateStep * 4 * 1024, 4 * 1024).ToArray();
+                        Array.Copy(sourceData, 0, MMU.CRAM, 0x1000 * i, 4 * 1024);
+                    }
+                }
+            }
+
+            // 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.LoadState(state.mmc.mmcdata);
+                }
+            }
+
+            //CONTROLLER STATE
+            {
+                pad.pad1bit = state.ctr.pad1bit;
+                pad.pad2bit = state.ctr.pad2bit;
+                pad.pad3bit = state.ctr.pad3bit;
+                pad.pad4bit = state.ctr.pad4bit;
+                pad.SetStrobe(state.ctr.strobe == 0 ? false : true);
+            }
+
+            //SND STATE
+            {
+                state.snd = SNDSTAT.GetDefault();
+
+                var buffer = new StateReader(state.snd.snddata);
+                apu.LoadState(buffer);
+            }
+
+            // DISKIMAGE STATE
+            if (rom.GetMapperNo() == 20)
+            {
+                var lpDisk = rom.GetPROM();
+                var lpWrite = rom.GetDISK();
+                int DiskSize = 16 + 65500 * rom.GetDiskNo();
+
+                Array.Clear(lpWrite, 0, DiskSize);
+
+                for (int i = 0; i < state.dsk.DifferentSize; i++)
+                {
+                    var pos = state.dskdata[i];
+                    byte data = (byte)(pos >> 24);
+                    pos &= 0x00FFFFFF;
+
+                    if (pos >= 16 && pos < DiskSize)
+                    {
+                        lpDisk[pos] = data;
+                        lpWrite[pos] = 0xFF;
+                    }
+                }
+            }
+
+            // EXCTR STATE
+            if (pad.GetExController() != 0)
+            {
+                pad.SetSyncExData(state.exctr.data);
+            }
+        }
+
+        internal void SetZapperPos(int x, int y)
+        {
+            ZapperX = x; ZapperY = y;
         }
 
         public enum IRQMETHOD
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PAD.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PAD.cs
index f418d58c..0c4acd7b 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PAD.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/PAD.cs
@@ -515,6 +515,11 @@ namespace VirtualNes.Core
             return bStrobe;
         }
 
+        internal void SetStrobe(bool v)
+        {
+            bStrobe = v;
+        }
+
         internal uint GetSyncExData()
         {
             uint data = 0;
@@ -571,6 +576,63 @@ namespace VirtualNes.Core
             }
             return data;
         }
+        internal void SetSyncExData(uint data)
+        {
+            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;
+                        if ((data & 0x80000000) != 0)
+                        {
+                            x = -1;
+                            y = -1;
+                        }
+                        else
+                        {
+                            x = (int)(data & 0xFF);
+                            y = (int)((data & 0xFF00) >> 8);
+                        }
+                        expad.SetSyncData(0, x);
+                        expad.SetSyncData(1, y);
+                        nes.SetZapperPos(x, y);
+                    }
+                    if (excontroller_select != (int)EXCONTROLLER.EXCONTROLLER_SPACESHADOWGUN)
+                    {
+                        if ((data & 0x0010000) != 0)
+                            expad.SetSyncData(2, 1);
+                        else
+                            expad.SetSyncData(2, 0);
+                    }
+                    else
+                    {
+                        expad.SetSyncData(2, (byte)(data >> 16));
+                    }
+                    break;
+                case EXCONTROLLER.EXCONTROLLER_CRAZYCLIMBER:
+                    expad.SetSyncData(0, (int)data);
+                    break;
+                case EXCONTROLLER.EXCONTROLLER_TOPRIDER:
+                    expad.SetSyncData(0, (int)data);
+                    break;
+                case EXCONTROLLER.EXCONTROLLER_FAMILYTRAINER_A:
+                case EXCONTROLLER.EXCONTROLLER_FAMILYTRAINER_B:
+                    expad.SetSyncData(0, (int)data);
+                    break;
+                case EXCONTROLLER.EXCONTROLLER_EXCITINGBOXING:
+                    expad.SetSyncData(0, (int)data);
+                    break;
+                case EXCONTROLLER.EXCONTROLLER_MAHJANG:
+                    expad.SetSyncData(0, (int)data);
+                    break;
+                default:
+                    break;
+            }
+        }
     }
 
     public enum VSType
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ROM.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ROM.cs
index 9f363910..718c08f0 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ROM.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ROM.cs
@@ -353,16 +353,31 @@ namespace VirtualNes.Core
             return diskno;
         }
 
+        internal void SetDiskNo(int v)
+        {
+            diskno = v;
+        }
+
         internal uint GetGameID()
         {
             return fdsgameID;
         }
 
+        internal void SetGameID(uint id)
+        {
+            fdsgameID = id;
+        }
+
         internal uint GetMakerID()
         {
             return fdsmakerID;
         }
 
+        internal void SetMakerID(uint id)
+        {
+            fdsmakerID = id;
+        }
+
         internal bool IsVSUNISYSTEM()
         {
             return (header.control2 & (byte)EnumRomControlByte2.ROM_VSUNISYSTEM) != 0;
@@ -373,6 +388,11 @@ namespace VirtualNes.Core
             return crc;
         }
 
+        public void SetPROM_CRC(uint v)
+        {
+            crc = v;
+        }
+
         internal byte GetPROM_SIZE()
         {
             return header.PRG_PAGE_SIZE;
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/BLOCKHDR.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/BLOCKHDR.cs
index 71ba330e..f3aafa60 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/BLOCKHDR.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/BLOCKHDR.cs
@@ -3,11 +3,19 @@
     public struct BLOCKHDR : IStateBufferObject
     {
         public readonly bool Valid => !string.IsNullOrEmpty(ID);
+        /// <summary> 总是8个字节 </summary>
         public string ID;
         public ushort Reserved;
         public ushort BlockVersion;
         public uint BlockSize;
 
+
+
+        public readonly uint GetSize()
+        {
+            return (uint)(8 + sizeof(ushort) + sizeof(ushort) + sizeof(uint));
+        }
+
         public readonly void SaveState(StateBuffer buffer)
         {
             if (Valid)
@@ -19,9 +27,12 @@
             }
         }
 
-        public readonly uint GetSize()
+        public void LoadState(StateReader buffer)
         {
-            return (uint)(ID.Length + sizeof(ushort) + sizeof(ushort) + sizeof(uint));
+            ID = buffer.Read_string(8);
+            Reserved = buffer.Read_ushort();
+            BlockVersion = buffer.Read_ushort();
+            BlockSize = buffer.Read_uint();
         }
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/CTRSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/CTRSTAT.cs
index 950610a5..2718c073 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/CTRSTAT.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/CTRSTAT.cs
@@ -24,5 +24,14 @@ namespace VirtualNes.Core
             buffer.Write(pad4bit);
             buffer.Write(strobe);
         }
+
+        public void LoadState(StateReader buffer)
+        {
+            pad1bit = buffer.Read_uint();
+            pad2bit = buffer.Read_uint();
+            pad3bit = buffer.Read_uint();
+            pad4bit = buffer.Read_uint();
+            strobe = buffer.Read_byte();
+        }
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/DISKDATA.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/DISKDATA.cs
index 95e21b60..16b7ae3e 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/DISKDATA.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/DISKDATA.cs
@@ -13,5 +13,10 @@
         {
             buffer.Write(DifferentSize);
         }
+
+        public void LoadState(StateReader buffer)
+        {
+            DifferentSize = buffer.Read_int();
+        }
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/EXCTRSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/EXCTRSTAT.cs
index 469c4141..802a4639 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/EXCTRSTAT.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/EXCTRSTAT.cs
@@ -13,5 +13,10 @@
         {
             buffer.Write(data);
         }
+
+        public void LoadState(StateReader buffer)
+        {
+            data = buffer.Read_uint();
+        }
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/FILEHDR2.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/FILEHDR2.cs
index 46dc2097..c3a451ce 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/FILEHDR2.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/FILEHDR2.cs
@@ -16,6 +16,13 @@ namespace VirtualNes.Core
         /// <summary> 2字节 </summary>
         public ushort Ext2;
 
+
+
+        public readonly uint GetSize()
+        {
+            return (uint)(ID.Length + sizeof(ushort) + sizeof(uint) + sizeof(ushort) + sizeof(ushort));
+        }
+
         public readonly void SaveState(StateBuffer buffer)
         {
             buffer.Write(ID);
@@ -25,9 +32,13 @@ namespace VirtualNes.Core
             buffer.Write(Ext2);
         }
 
-        public readonly uint GetSize()
+        public void LoadState(StateReader buffer)
         {
-            return (uint)(ID.Length + sizeof(ushort) + sizeof(uint) + sizeof(ushort) + sizeof(ushort));
+            ID = buffer.Read_string(12);
+            BlockVersion = buffer.Read_ushort();
+            Ext0 = buffer.Read_uint();
+            Ext1 = buffer.Read_ushort();
+            Ext2 = buffer.Read_ushort();
         }
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMCSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMCSTAT.cs
index 2f5ada01..e23ed911 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMCSTAT.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMCSTAT.cs
@@ -9,14 +9,19 @@
             return new MMCSTAT() { mmcdata = new byte[256] };
         }
 
-        public uint GetSize()
+        public readonly uint GetSize()
         {
-            return (uint)mmcdata.Length;
+            return 256;
         }
 
-        public void SaveState(StateBuffer buffer)
+        public readonly void SaveState(StateBuffer buffer)
         {
             buffer.Write(mmcdata);
         }
+
+        public void LoadState(StateReader buffer)
+        {
+            mmcdata = buffer.Read_bytes(256);
+        }
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMUSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMUSTAT.cs
index 1109c895..88e45e7a 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMUSTAT.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/MMUSTAT.cs
@@ -34,5 +34,14 @@
             buffer.Write(PPU_MEM_PAGE);
             buffer.Write(CRAM_USED);
         }
+
+        public void LoadState(StateReader buffer)
+        {
+            CPU_MEM_TYPE = buffer.Read_bytes(8);
+            CPU_MEM_PAGE = buffer.Read_ushorts(8);
+            PPU_MEM_TYPE = buffer.Read_bytes(12);
+            PPU_MEM_PAGE = buffer.Read_ushorts(12);
+            CRAM_USED = buffer.Read_bytes(8);
+        }
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/RAMSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/RAMSTAT.cs
index f6eec9e6..5d3929b5 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/RAMSTAT.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/RAMSTAT.cs
@@ -34,5 +34,13 @@ namespace VirtualNes.Core
             buffer.Write(SPPAL);
             buffer.Write(SPRAM);
         }
+
+        public void LoadState(StateReader buffer)
+        {
+            RAM = buffer.Read_bytes(2 * 1024);
+            BGPAL = buffer.Read_bytes(16);
+            SPPAL = buffer.Read_bytes(16);
+            SPRAM = buffer.Read_bytes(256);
+        }
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/REGSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/REGSTAT.cs
index 52ce17de..13e0e8d6 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/REGSTAT.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/REGSTAT.cs
@@ -5,15 +5,23 @@
         public CPUSTAT cpureg;
         public PPUSTAT ppureg;
 
-        public void SaveState(StateBuffer buffer)
+
+
+        public readonly uint GetSize()
+        {
+            return cpureg.GetSize() + ppureg.GetSize();
+        }
+
+        public readonly void SaveState(StateBuffer buffer)
         {
             cpureg.SaveState(buffer);
             ppureg.SaveState(buffer);
         }
 
-        public uint GetSize()
+        public void LoadState(StateReader buffer)
         {
-            return cpureg.GetSize() + ppureg.GetSize();
+            cpureg.LoadState(buffer);
+            ppureg.LoadState(buffer);
         }
     }
 
@@ -60,6 +68,25 @@
             buffer.Write(emul_cycles);
             buffer.Write(base_cycles);
         }
+
+        public void LoadState(StateReader buffer)
+        {
+            PC = buffer.Read_ushort();
+            A = buffer.Read_byte();
+            X = buffer.Read_byte();
+            Y = buffer.Read_byte();
+            S = buffer.Read_byte();
+            P = buffer.Read_byte();
+            I = buffer.Read_byte();
+            FrameIRQ = buffer.Read_byte();
+            FrameIRQ_occur = buffer.Read_byte();
+            FrameIRQ_count = buffer.Read_byte();
+            FrameIRQ_type = buffer.Read_byte();
+            FrameIRQ_cycles = buffer.Read_int();
+            DMA_cycles = buffer.Read_int();
+            emul_cycles = buffer.Read_long();
+            base_cycles = buffer.Read_long();
+        }
     }
 
     public struct PPUSTAT : IStateBufferObject
@@ -92,5 +119,18 @@
             buffer.Write(loopy_v);
             buffer.Write(loopy_x);
         }
+
+        public void LoadState(StateReader buffer)
+        {
+            reg0 = buffer.Read_byte();
+            reg1 = buffer.Read_byte();
+            reg2 = buffer.Read_byte();
+            reg3 = buffer.Read_byte();
+            reg7 = buffer.Read_byte();
+            toggle56 = buffer.Read_byte();
+            loopy_t = buffer.Read_ushort();
+            loopy_v = buffer.Read_ushort();
+            loopy_x = buffer.Read_ushort();
+        }
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/SNDSTAT.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/SNDSTAT.cs
index 38bd9e95..9de7b5bd 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/SNDSTAT.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/SNDSTAT.cs
@@ -15,14 +15,19 @@ namespace VirtualNes.Core
             return new SNDSTAT() { snddata = new byte[0x800] };
         }
 
-        public uint GetSize()
+        public readonly uint GetSize()
         {
             return (uint)snddata.Length;
         }
 
-        public void SaveState(StateBuffer buffer)
+        public readonly void SaveState(StateBuffer buffer)
         {
             buffer.Write(snddata);
         }
+
+        public void LoadState(StateReader buffer)
+        {
+            snddata = buffer.Read_bytes(0x800);
+        }
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/State.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/State.cs
index d5d4609f..c9003cb2 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/State.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/State.cs
@@ -31,7 +31,7 @@ namespace VirtualNes.Core
 
         public BLOCKHDR dskBLOCK;
         public DISKDATA dsk;
-        public uint dskdata;
+        public List<uint> dskdata;
 
         public BLOCKHDR exctrBLOCK;
         public EXCTRSTAT exctr;
@@ -87,7 +87,10 @@ namespace VirtualNes.Core
             {
                 dskBLOCK.SaveState(buffer);
                 dsk.SaveState(buffer);
-                buffer.Write(dskdata);
+                foreach (var data in dskdata)
+                {
+                    buffer.Write(data);
+                }
             }
 
             if (exctrBLOCK.Valid)
diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/StateBuffer.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/StateBuffer.cs
index d46ed315..e496cc30 100644
--- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/StateBuffer.cs
+++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/State/StateBuffer.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Text;
 
 namespace VirtualNes.Core
@@ -31,15 +32,11 @@ namespace VirtualNes.Core
         }
         public void Write(sbyte[] sbytes)
         {
-            foreach(var value in 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);
@@ -80,11 +77,134 @@ namespace VirtualNes.Core
         {
             Write(BitConverter.GetBytes(value));
         }
+        public void Write(uint value)
+        {
+            Write(BitConverter.GetBytes(value));
+        }
+    }
+    public class StateReader
+    {
+        private MemoryStream m_dataStream;
+        public StateReader(byte[] bytes)
+        {
+            m_dataStream = new MemoryStream(bytes);
+        }
+
+        public void Skip(uint count)
+        {
+            m_dataStream.Seek(count, SeekOrigin.Current);
+        }
+        public void Skip(long count)
+        {
+            m_dataStream.Seek(count, SeekOrigin.Current);
+        }
+
+        public byte[] Read_bytes(int length)
+        {
+            var result = new byte[length];
+            m_dataStream.Read(result, 0, length);
+            return result;
+        }
+        public sbyte[] Read_sbytes(int length)
+        {
+            var result = new sbyte[length];
+            for (int i = 0; i < length; i++)
+            {
+                result[i] = (sbyte)m_dataStream.ReadByte();
+            }
+
+            return result;
+        }
+
+        public byte Read_byte()
+        {
+            return (byte)m_dataStream.ReadByte();
+        }
+        public ushort[] Read_ushorts(int length)
+        {
+            ushort[] result = new ushort[length];
+            for (int i = 0; i < length; i++)
+            {
+                int byte1 = m_dataStream.ReadByte();
+                int byte2 = m_dataStream.ReadByte();
+
+                result[i] = (ushort)(byte1 << 8 | byte2);
+            }
+
+            return result;
+        }
+        public int[] Read_ints(int length)
+        {
+            int[] result = new int[length];
+            for (int i = 0; i < length; i++)
+            {
+                int byte1 = m_dataStream.ReadByte();
+                int byte2 = m_dataStream.ReadByte();
+                int byte3 = m_dataStream.ReadByte();
+                int byte4 = m_dataStream.ReadByte();
+
+                result[i] = byte1 << 24 | byte2 << 16 | byte3 << 8 | byte4;
+            }
+
+            return result;
+        }
+
+
+        public string Read_string(int length)
+        {
+            var result = Read_bytes(length);
+            return Encoding.ASCII.GetString(result);
+        }
+        public double Read_double()
+        {
+            var result = Read_bytes(4);
+            return BitConverter.ToDouble(result, 0);
+        }
+        public ushort Read_ushort()
+        {
+            var b1 = Read_byte();
+            var b2 = Read_byte();
+            return (ushort)(b1 << 8 | b2);
+        }
+
+        public int Read_int()
+        {
+            var b1 = Read_byte();
+            var b2 = Read_byte();
+            var b3 = Read_byte();
+            var b4 = Read_byte();
+
+            return b1 << 24 | b2 << 16 | b3 << 8 | b4;
+        }
+
+        public sbyte Read_sbyte(sbyte value)
+        {
+            return (sbyte)m_dataStream.ReadByte();
+        }
+        public long Read_long()
+        {
+            var b1 = Read_byte();
+            var b2 = Read_byte();
+            var b3 = Read_byte();
+            var b4 = Read_byte();
+            var b5 = Read_byte();
+            var b6 = Read_byte();
+            var b7 = Read_byte();
+            var b8 = Read_byte();
+
+            return b1 << 56 | b2 << 48 | b3 << 40 | b4 << 32 | b5 << 24 | b6 << 16 | b7 << 8 | b8;
+        }
+
+        public uint Read_uint()
+        {
+            return (uint)Read_int();
+        }
     }
 
     public interface IStateBufferObject
     {
         uint GetSize();
         void SaveState(StateBuffer buffer);
+        void LoadState(StateReader buffer);
     }
 }