SMS - break up services into separate files
This commit is contained in:
parent
44dc9518cf
commit
4460055da3
|
@ -818,7 +818,7 @@
|
||||||
<DependentUpon>GPGX.cs</DependentUpon>
|
<DependentUpon>GPGX.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Consoles\Sega\gpgx\GPGX.ITraceable.cs">
|
<Compile Include="Consoles\Sega\gpgx\GPGX.ITraceable.cs">
|
||||||
<DependentUpon>GPGX.cs</DependentUpon>
|
<DependentUpon>GPGX.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Consoles\Sega\gpgx\GPGX.IVideoProvider.cs">
|
<Compile Include="Consoles\Sega\gpgx\GPGX.IVideoProvider.cs">
|
||||||
<DependentUpon>GPGX.cs</DependentUpon>
|
<DependentUpon>GPGX.cs</DependentUpon>
|
||||||
|
@ -846,8 +846,15 @@
|
||||||
<Compile Include="Consoles\Sega\Saturn\Yabause.IStatable.cs">
|
<Compile Include="Consoles\Sega\Saturn\Yabause.IStatable.cs">
|
||||||
<DependentUpon>Yabause.cs</DependentUpon>
|
<DependentUpon>Yabause.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Consoles\Sega\SMS\CDL_SMS.cs" />
|
<Compile Include="Consoles\Sega\SMS\SMS.ICodeDataLogger.cs" />
|
||||||
|
<Compile Include="Consoles\Sega\SMS\SMS.IDebuggable.cs" />
|
||||||
|
<Compile Include="Consoles\Sega\SMS\SMS.IEmulator.cs" />
|
||||||
|
<Compile Include="Consoles\Sega\SMS\SMS.IInputPollable.cs" />
|
||||||
|
<Compile Include="Consoles\Sega\SMS\SMS.IMemoryDomains.cs" />
|
||||||
<Compile Include="Consoles\Sega\SMS\SMS.Input.cs" />
|
<Compile Include="Consoles\Sega\SMS\SMS.Input.cs" />
|
||||||
|
<Compile Include="Consoles\Sega\SMS\SMS.ISaveRam.cs" />
|
||||||
|
<Compile Include="Consoles\Sega\SMS\SMS.ISettable.cs" />
|
||||||
|
<Compile Include="Consoles\Sega\SMS\SMS.IStatable.cs" />
|
||||||
<Compile Include="Consoles\Sega\SMS\TerebiOekaki.cs" />
|
<Compile Include="Consoles\Sega\SMS\TerebiOekaki.cs" />
|
||||||
<Compile Include="Consoles\Sega\SMS\MemoryMap.Korea.cs" />
|
<Compile Include="Consoles\Sega\SMS\MemoryMap.Korea.cs" />
|
||||||
<Compile Include="Consoles\Sega\SMS\MemoryMap.ExtRam.cs" />
|
<Compile Include="Consoles\Sega\SMS\MemoryMap.ExtRam.cs" />
|
||||||
|
|
|
@ -4,9 +4,51 @@ using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
{
|
{
|
||||||
partial class SMS
|
public sealed partial class SMS : ICodeDataLogger
|
||||||
{
|
{
|
||||||
enum CDLog_AddrType
|
public void SetCDL(CodeDataLog cdl)
|
||||||
|
{
|
||||||
|
CDL = cdl;
|
||||||
|
if (cdl == null)
|
||||||
|
{
|
||||||
|
Cpu.ReadMemory = ReadMemory;
|
||||||
|
Cpu.WriteMemory = WriteMemory;
|
||||||
|
Cpu.FetchMemory = FetchMemory_StubThunk;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Cpu.ReadMemory = ReadMemory_CDL;
|
||||||
|
Cpu.WriteMemory = WriteMemory;
|
||||||
|
Cpu.FetchMemory = FetchMemory_CDL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NewCDL(CodeDataLog cdl)
|
||||||
|
{
|
||||||
|
cdl["ROM"] = new byte[MemoryDomains["ROM"].Size];
|
||||||
|
cdl["Main RAM"] = new byte[MemoryDomains["Main RAM"].Size];
|
||||||
|
|
||||||
|
if (MemoryDomains.Has("Save RAM"))
|
||||||
|
{
|
||||||
|
cdl["Save RAM"] = new byte[MemoryDomains["Save RAM"].Size];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MemoryDomains.Has("Cart (Volatile) RAM"))
|
||||||
|
{
|
||||||
|
cdl["Cart (Volatile) RAM"] = new byte[MemoryDomains["Cart (Volatile) RAM"].Size];
|
||||||
|
}
|
||||||
|
|
||||||
|
cdl.SubType = "SMS";
|
||||||
|
cdl.SubVer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[FeatureNotImplemented]
|
||||||
|
public void DisassembleCDL(Stream s, CodeDataLog cdl)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum CDLog_AddrType
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
ROM,
|
ROM,
|
||||||
|
@ -16,24 +58,24 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum CDLog_Flags
|
private enum CDLog_Flags
|
||||||
{
|
{
|
||||||
ExecFirst = 0x01,
|
ExecFirst = 0x01,
|
||||||
ExecOperand = 0x02,
|
ExecOperand = 0x02,
|
||||||
Data = 0x04
|
Data = 0x04
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CDLog_MapResults
|
private struct CDLog_MapResults
|
||||||
{
|
{
|
||||||
public CDLog_AddrType Type;
|
public CDLog_AddrType Type;
|
||||||
public int Address;
|
public int Address;
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate CDLog_MapResults MapMemoryDelegate(ushort addr, bool write);
|
private delegate CDLog_MapResults MapMemoryDelegate(ushort addr, bool write);
|
||||||
|
private MapMemoryDelegate MapMemory;
|
||||||
|
private CodeDataLog CDL;
|
||||||
|
|
||||||
MapMemoryDelegate MapMemory;
|
private void RunCDL(ushort address, CDLog_Flags flags)
|
||||||
|
|
||||||
void RunCDL(ushort address, CDLog_Flags flags)
|
|
||||||
{
|
{
|
||||||
if (MapMemory != null)
|
if (MapMemory != null)
|
||||||
{
|
{
|
||||||
|
@ -52,7 +94,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A wrapper for FetchMemory which inserts CDL logic
|
/// A wrapper for FetchMemory which inserts CDL logic
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte FetchMemory_CDL(ushort address, bool first)
|
private byte FetchMemory_CDL(ushort address, bool first)
|
||||||
{
|
{
|
||||||
RunCDL(address, first ? CDLog_Flags.ExecFirst : CDLog_Flags.ExecOperand);
|
RunCDL(address, first ? CDLog_Flags.ExecFirst : CDLog_Flags.ExecOperand);
|
||||||
return ReadMemory(address);
|
return ReadMemory(address);
|
||||||
|
@ -61,47 +103,10 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A wrapper for ReadMemory which inserts CDL logic
|
/// A wrapper for ReadMemory which inserts CDL logic
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte ReadMemory_CDL(ushort address)
|
private byte ReadMemory_CDL(ushort address)
|
||||||
{
|
{
|
||||||
RunCDL(address, CDLog_Flags.Data);
|
RunCDL(address, CDLog_Flags.Data);
|
||||||
return ReadMemory(address);
|
return ReadMemory(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ICodeDataLogger.SetCDL(CodeDataLog cdl)
|
|
||||||
{
|
|
||||||
CDL = cdl;
|
|
||||||
if (cdl == null)
|
|
||||||
{
|
|
||||||
Cpu.ReadMemory = ReadMemory;
|
|
||||||
Cpu.WriteMemory = WriteMemory;
|
|
||||||
Cpu.FetchMemory = FetchMemory_StubThunk;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Cpu.ReadMemory = ReadMemory_CDL;
|
|
||||||
Cpu.WriteMemory = WriteMemory;
|
|
||||||
Cpu.FetchMemory = FetchMemory_CDL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ICodeDataLogger.NewCDL(CodeDataLog cdl)
|
|
||||||
{
|
|
||||||
cdl["ROM"] = new byte[memoryDomains["ROM"].Size];
|
|
||||||
cdl["Main RAM"] = new byte[memoryDomains["Main RAM"].Size];
|
|
||||||
|
|
||||||
if (memoryDomains.Has("Save RAM"))
|
|
||||||
cdl["Save RAM"] = new byte[memoryDomains["Save RAM"].Size];
|
|
||||||
|
|
||||||
if (memoryDomains.Has("Cart (Volatile) RAM"))
|
|
||||||
cdl["Cart (Volatile) RAM"] = new byte[memoryDomains["Cart (Volatile) RAM"].Size];
|
|
||||||
|
|
||||||
cdl.SubType = "SMS";
|
|
||||||
cdl.SubVer = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//not supported
|
|
||||||
void ICodeDataLogger.DisassembleCDL(Stream s, CodeDataLog cdl) { }
|
|
||||||
|
|
||||||
CodeDataLog CDL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using BizHawk.Common.NumberExtensions;
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
|
{
|
||||||
|
public sealed partial class SMS : IDebuggable
|
||||||
|
{
|
||||||
|
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
|
||||||
|
{
|
||||||
|
return new Dictionary<string, RegisterValue>
|
||||||
|
{
|
||||||
|
{ "A", Cpu.RegisterA },
|
||||||
|
{ "AF", Cpu.RegisterAF },
|
||||||
|
{ "B", Cpu.RegisterB },
|
||||||
|
{ "BC", Cpu.RegisterBC },
|
||||||
|
{ "C", Cpu.RegisterC },
|
||||||
|
{ "D", Cpu.RegisterD },
|
||||||
|
{ "DE", Cpu.RegisterDE },
|
||||||
|
{ "E", Cpu.RegisterE },
|
||||||
|
{ "F", Cpu.RegisterF },
|
||||||
|
{ "H", Cpu.RegisterH },
|
||||||
|
{ "HL", Cpu.RegisterHL },
|
||||||
|
{ "I", Cpu.RegisterI },
|
||||||
|
{ "IX", Cpu.RegisterIX },
|
||||||
|
{ "IY", Cpu.RegisterIY },
|
||||||
|
{ "L", Cpu.RegisterL },
|
||||||
|
{ "PC", Cpu.RegisterPC },
|
||||||
|
{ "R", Cpu.RegisterR },
|
||||||
|
{ "Shadow AF", Cpu.RegisterShadowAF },
|
||||||
|
{ "Shadow BC", Cpu.RegisterShadowBC },
|
||||||
|
{ "Shadow DE", Cpu.RegisterShadowDE },
|
||||||
|
{ "Shadow HL", Cpu.RegisterShadowHL },
|
||||||
|
{ "SP", Cpu.RegisterSP },
|
||||||
|
{ "Flag C", Cpu.RegisterF.Bit(0) },
|
||||||
|
{ "Flag N", Cpu.RegisterF.Bit(1) },
|
||||||
|
{ "Flag P/V", Cpu.RegisterF.Bit(2) },
|
||||||
|
{ "Flag 3rd", Cpu.RegisterF.Bit(3) },
|
||||||
|
{ "Flag H", Cpu.RegisterF.Bit(4) },
|
||||||
|
{ "Flag 5th", Cpu.RegisterF.Bit(5) },
|
||||||
|
{ "Flag Z", Cpu.RegisterF.Bit(6) },
|
||||||
|
{ "Flag S", Cpu.RegisterF.Bit(7) },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetCpuRegister(string register, int value)
|
||||||
|
{
|
||||||
|
switch (register)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
case "A":
|
||||||
|
Cpu.RegisterA = (byte)value;
|
||||||
|
break;
|
||||||
|
case "AF":
|
||||||
|
Cpu.RegisterAF = (byte)value;
|
||||||
|
break;
|
||||||
|
case "B":
|
||||||
|
Cpu.RegisterB = (byte)value;
|
||||||
|
break;
|
||||||
|
case "BC":
|
||||||
|
Cpu.RegisterBC = (byte)value;
|
||||||
|
break;
|
||||||
|
case "C":
|
||||||
|
Cpu.RegisterC = (byte)value;
|
||||||
|
break;
|
||||||
|
case "D":
|
||||||
|
Cpu.RegisterD = (byte)value;
|
||||||
|
break;
|
||||||
|
case "DE":
|
||||||
|
Cpu.RegisterDE = (byte)value;
|
||||||
|
break;
|
||||||
|
case "E":
|
||||||
|
Cpu.RegisterE = (byte)value;
|
||||||
|
break;
|
||||||
|
case "F":
|
||||||
|
Cpu.RegisterF = (byte)value;
|
||||||
|
break;
|
||||||
|
case "H":
|
||||||
|
Cpu.RegisterH = (byte)value;
|
||||||
|
break;
|
||||||
|
case "HL":
|
||||||
|
Cpu.RegisterHL = (byte)value;
|
||||||
|
break;
|
||||||
|
case "I":
|
||||||
|
Cpu.RegisterI = (byte)value;
|
||||||
|
break;
|
||||||
|
case "IX":
|
||||||
|
Cpu.RegisterIX = (byte)value;
|
||||||
|
break;
|
||||||
|
case "IY":
|
||||||
|
Cpu.RegisterIY = (byte)value;
|
||||||
|
break;
|
||||||
|
case "L":
|
||||||
|
Cpu.RegisterL = (byte)value;
|
||||||
|
break;
|
||||||
|
case "PC":
|
||||||
|
Cpu.RegisterPC = (ushort)value;
|
||||||
|
break;
|
||||||
|
case "R":
|
||||||
|
Cpu.RegisterR = (byte)value;
|
||||||
|
break;
|
||||||
|
case "Shadow AF":
|
||||||
|
Cpu.RegisterShadowAF = (byte)value;
|
||||||
|
break;
|
||||||
|
case "Shadow BC":
|
||||||
|
Cpu.RegisterShadowBC = (byte)value;
|
||||||
|
break;
|
||||||
|
case "Shadow DE":
|
||||||
|
Cpu.RegisterShadowDE = (byte)value;
|
||||||
|
break;
|
||||||
|
case "Shadow HL":
|
||||||
|
Cpu.RegisterShadowHL = (byte)value;
|
||||||
|
break;
|
||||||
|
case "SP":
|
||||||
|
Cpu.RegisterSP = (byte)value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanStep(StepType type) { return false; }
|
||||||
|
|
||||||
|
public IMemoryCallbackSystem MemoryCallbacks { get; private set; }
|
||||||
|
|
||||||
|
[FeatureNotImplemented]
|
||||||
|
public void Step(StepType type)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
|
{
|
||||||
|
public sealed partial class SMS : IEmulator
|
||||||
|
{
|
||||||
|
public IEmulatorServiceProvider ServiceProvider { get; private set; }
|
||||||
|
|
||||||
|
public ISoundProvider SoundProvider
|
||||||
|
{
|
||||||
|
get { return ActiveSoundProvider; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public ISyncSoundProvider SyncSoundProvider
|
||||||
|
{
|
||||||
|
get { return new FakeSyncSound(ActiveSoundProvider, 735); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool StartAsyncSound()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EndAsyncSound() { }
|
||||||
|
|
||||||
|
public ControllerDefinition ControllerDefinition
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (IsGameGear)
|
||||||
|
{
|
||||||
|
return GGController;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SmsController;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IController Controller { get; set; }
|
||||||
|
|
||||||
|
public void FrameAdvance(bool render, bool rendersound)
|
||||||
|
{
|
||||||
|
_lagged = true;
|
||||||
|
Frame++;
|
||||||
|
PSG.BeginFrame(Cpu.TotalExecutedCycles);
|
||||||
|
Cpu.Debug = Tracer.Enabled;
|
||||||
|
if (!IsGameGear)
|
||||||
|
{
|
||||||
|
PSG.StereoPanning = Settings.ForceStereoSeparation ? ForceStereoByte : (byte)0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Cpu.Debug && Cpu.Logger == null) // TODO, lets not do this on each frame. But lets refactor CoreComm/CoreComm first
|
||||||
|
{
|
||||||
|
Cpu.Logger = (s) => Tracer.Put(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsGameGear == false)
|
||||||
|
{
|
||||||
|
Cpu.NonMaskableInterrupt = Controller["Pause"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsGame3D && Settings.Fix3D)
|
||||||
|
{
|
||||||
|
Vdp.ExecFrame((Frame & 1) == 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Vdp.ExecFrame(render);
|
||||||
|
}
|
||||||
|
|
||||||
|
PSG.EndFrame(Cpu.TotalExecutedCycles);
|
||||||
|
if (_lagged)
|
||||||
|
{
|
||||||
|
_lagCount++;
|
||||||
|
_isLag = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_isLag = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string SystemId { get { return "SMS"; } }
|
||||||
|
|
||||||
|
public bool DeterministicEmulation { get { return true; } }
|
||||||
|
|
||||||
|
public string BoardName { get { return null; } }
|
||||||
|
|
||||||
|
public void ResetCounters()
|
||||||
|
{
|
||||||
|
Frame = 0;
|
||||||
|
_lagCount = 0;
|
||||||
|
_isLag = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CoreComm CoreComm { get; private set; }
|
||||||
|
|
||||||
|
public void Dispose() { }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
|
{
|
||||||
|
public sealed partial class SMS : IInputPollable
|
||||||
|
{
|
||||||
|
public int LagCount
|
||||||
|
{
|
||||||
|
get { return _lagCount; }
|
||||||
|
set { _lagCount = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsLagFrame
|
||||||
|
{
|
||||||
|
get { return _isLag; }
|
||||||
|
set { _isLag = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IInputCallbackSystem InputCallbacks { get; private set; }
|
||||||
|
|
||||||
|
private int _lagCount = 0;
|
||||||
|
private bool _lagged = true;
|
||||||
|
private bool _isLag = false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
|
{
|
||||||
|
public sealed partial class SMS
|
||||||
|
{
|
||||||
|
private MemoryDomainList MemoryDomains;
|
||||||
|
|
||||||
|
void SetupMemoryDomains()
|
||||||
|
{
|
||||||
|
var domains = new List<MemoryDomain>(3);
|
||||||
|
var MainMemoryDomain = new MemoryDomain("Main RAM", SystemRam.Length, MemoryDomain.Endian.Little,
|
||||||
|
addr => SystemRam[addr],
|
||||||
|
(addr, value) => SystemRam[addr] = value);
|
||||||
|
var VRamDomain = new MemoryDomain("Video RAM", Vdp.VRAM.Length, MemoryDomain.Endian.Little,
|
||||||
|
addr => Vdp.VRAM[addr],
|
||||||
|
(addr, value) => Vdp.VRAM[addr] = value);
|
||||||
|
|
||||||
|
var ROMDomain = new MemoryDomain("ROM", RomData.Length, MemoryDomain.Endian.Little,
|
||||||
|
addr => RomData[addr],
|
||||||
|
(addr, value) => RomData[addr] = value);
|
||||||
|
|
||||||
|
var SystemBusDomain = new MemoryDomain("System Bus", 0x10000, MemoryDomain.Endian.Little,
|
||||||
|
(addr) =>
|
||||||
|
{
|
||||||
|
if (addr < 0 || addr >= 65536)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Cpu.ReadMemory((ushort)addr);
|
||||||
|
},
|
||||||
|
(addr, value) =>
|
||||||
|
{
|
||||||
|
if (addr < 0 || addr >= 65536)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Cpu.WriteMemory((ushort)addr, value);
|
||||||
|
});
|
||||||
|
|
||||||
|
domains.Add(MainMemoryDomain);
|
||||||
|
domains.Add(VRamDomain);
|
||||||
|
domains.Add(ROMDomain);
|
||||||
|
domains.Add(SystemBusDomain);
|
||||||
|
|
||||||
|
if (SaveRAM != null)
|
||||||
|
{
|
||||||
|
var SaveRamDomain = new MemoryDomain("Save RAM", SaveRAM.Length, MemoryDomain.Endian.Little,
|
||||||
|
addr => SaveRAM[addr],
|
||||||
|
(addr, value) => { SaveRAM[addr] = value; SaveRamModified = true; });
|
||||||
|
domains.Add(SaveRamDomain);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ExtRam != null)
|
||||||
|
{
|
||||||
|
var ExtRamDomain = new MemoryDomain("Cart (Volatile) RAM", ExtRam.Length, MemoryDomain.Endian.Little,
|
||||||
|
addr => ExtRam[addr],
|
||||||
|
(addr, value) => { ExtRam[addr] = value; });
|
||||||
|
domains.Add(ExtRamDomain);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryDomains = new MemoryDomainList(domains);
|
||||||
|
(ServiceProvider as BasicServiceProvider).Register<IMemoryDomains>(MemoryDomains);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
|
{
|
||||||
|
public sealed partial class SMS : ISaveRam
|
||||||
|
{
|
||||||
|
public byte[] CloneSaveRam()
|
||||||
|
{
|
||||||
|
if (SaveRAM != null)
|
||||||
|
{
|
||||||
|
return (byte[])SaveRAM.Clone();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StoreSaveRam(byte[] data)
|
||||||
|
{
|
||||||
|
if (SaveRAM != null)
|
||||||
|
{
|
||||||
|
Array.Copy(data, SaveRAM, data.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SaveRamModified { get; private set; }
|
||||||
|
|
||||||
|
private byte[] SaveRAM;
|
||||||
|
private byte SaveRamBank;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
|
{
|
||||||
|
public sealed partial class SMS : ISettable<SMS.SMSSettings, SMS.SMSSyncSettings>
|
||||||
|
{
|
||||||
|
public SMSSettings GetSettings()
|
||||||
|
{
|
||||||
|
return Settings.Clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SMSSyncSettings GetSyncSettings()
|
||||||
|
{
|
||||||
|
return SyncSettings.Clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool PutSettings(SMSSettings o)
|
||||||
|
{
|
||||||
|
bool ret = SMSSettings.RebootNeeded(Settings, o);
|
||||||
|
Settings = o;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool PutSyncSettings(SMSSyncSettings o)
|
||||||
|
{
|
||||||
|
bool ret = SMSSyncSettings.RebootNeeded(SyncSettings, o);
|
||||||
|
SyncSettings = o;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal SMSSettings Settings { get; private set; }
|
||||||
|
internal SMSSyncSettings SyncSettings { get; private set; }
|
||||||
|
|
||||||
|
public class SMSSettings
|
||||||
|
{
|
||||||
|
// Game settings
|
||||||
|
public bool ForceStereoSeparation = false;
|
||||||
|
public bool SpriteLimit = false;
|
||||||
|
public bool Fix3D = true;
|
||||||
|
|
||||||
|
// GG settings
|
||||||
|
public bool ShowClippedRegions = false;
|
||||||
|
public bool HighlightActiveDisplayRegion = false;
|
||||||
|
|
||||||
|
// graphics settings
|
||||||
|
public bool DispBG = true;
|
||||||
|
public bool DispOBJ = true;
|
||||||
|
|
||||||
|
public SMSSettings Clone()
|
||||||
|
{
|
||||||
|
return (SMSSettings)MemberwiseClone();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool RebootNeeded(SMSSettings x, SMSSettings y)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SMSSyncSettings
|
||||||
|
{
|
||||||
|
public bool EnableFM = true;
|
||||||
|
public bool AllowOverlock = false;
|
||||||
|
public bool UseBIOS = false;
|
||||||
|
public string ConsoleRegion = "Export";
|
||||||
|
public string DisplayType = "NTSC";
|
||||||
|
|
||||||
|
public SMSSyncSettings Clone()
|
||||||
|
{
|
||||||
|
return (SMSSyncSettings)MemberwiseClone();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool RebootNeeded(SMSSyncSettings x, SMSSyncSettings y)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
x.EnableFM != y.EnableFM ||
|
||||||
|
x.AllowOverlock != y.AllowOverlock ||
|
||||||
|
x.UseBIOS != y.UseBIOS ||
|
||||||
|
x.ConsoleRegion != y.ConsoleRegion ||
|
||||||
|
x.DisplayType != y.DisplayType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
using BizHawk.Common;
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
|
{
|
||||||
|
public sealed partial class SMS : IStatable
|
||||||
|
{
|
||||||
|
public bool BinarySaveStatesPreferred
|
||||||
|
{
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveStateBinary(BinaryWriter bw)
|
||||||
|
{
|
||||||
|
SyncState(Serializer.CreateBinaryWriter(bw));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadStateBinary(BinaryReader br)
|
||||||
|
{
|
||||||
|
SyncState(Serializer.CreateBinaryReader(br));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveStateText(TextWriter tw)
|
||||||
|
{
|
||||||
|
SyncState(Serializer.CreateTextWriter(tw));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadStateText(TextReader tr)
|
||||||
|
{
|
||||||
|
SyncState(Serializer.CreateTextReader(tr));
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] SaveStateBinary()
|
||||||
|
{
|
||||||
|
if (_stateBuffer == null)
|
||||||
|
{
|
||||||
|
var stream = new MemoryStream();
|
||||||
|
var writer = new BinaryWriter(stream);
|
||||||
|
SaveStateBinary(writer);
|
||||||
|
_stateBuffer = stream.ToArray();
|
||||||
|
writer.Close();
|
||||||
|
return _stateBuffer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var stream = new MemoryStream(_stateBuffer);
|
||||||
|
var writer = new BinaryWriter(stream);
|
||||||
|
SaveStateBinary(writer);
|
||||||
|
writer.Close();
|
||||||
|
return _stateBuffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] _stateBuffer;
|
||||||
|
|
||||||
|
private void SyncState(Serializer ser)
|
||||||
|
{
|
||||||
|
ser.BeginSection("SMS");
|
||||||
|
Cpu.SyncState(ser);
|
||||||
|
Vdp.SyncState(ser);
|
||||||
|
PSG.SyncState(ser);
|
||||||
|
ser.Sync("RAM", ref SystemRam, false);
|
||||||
|
ser.Sync("RomBank0", ref RomBank0);
|
||||||
|
ser.Sync("RomBank1", ref RomBank1);
|
||||||
|
ser.Sync("RomBank2", ref RomBank2);
|
||||||
|
ser.Sync("RomBank3", ref RomBank3);
|
||||||
|
ser.Sync("Port01", ref Port01);
|
||||||
|
ser.Sync("Port02", ref Port02);
|
||||||
|
ser.Sync("Port3E", ref Port3E);
|
||||||
|
ser.Sync("Port3F", ref Port3F);
|
||||||
|
|
||||||
|
if (SaveRAM != null)
|
||||||
|
{
|
||||||
|
ser.Sync("SaveRAM", ref SaveRAM, false);
|
||||||
|
ser.Sync("SaveRamBank", ref SaveRamBank);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ExtRam != null)
|
||||||
|
{
|
||||||
|
ser.Sync("ExtRAM", ref ExtRam, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasYM2413)
|
||||||
|
{
|
||||||
|
YM2413.SyncState(ser);
|
||||||
|
}
|
||||||
|
|
||||||
|
ser.Sync("Frame", ref frame);
|
||||||
|
ser.Sync("LagCount", ref _lagCount);
|
||||||
|
ser.Sync("IsLag", ref _isLag);
|
||||||
|
|
||||||
|
ser.EndSection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,25 +25,10 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public ControllerDefinition ControllerDefinition
|
private byte ReadControls1()
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (IsGameGear)
|
|
||||||
{
|
|
||||||
return GGController;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SmsController;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IController Controller { get; set; }
|
|
||||||
|
|
||||||
byte ReadControls1()
|
|
||||||
{
|
{
|
||||||
InputCallbacks.Call();
|
InputCallbacks.Call();
|
||||||
lagged = false;
|
_lagged = false;
|
||||||
byte value = 0xFF;
|
byte value = 0xFF;
|
||||||
|
|
||||||
if (Controller["P1 Up"]) value &= 0xFE;
|
if (Controller["P1 Up"]) value &= 0xFE;
|
||||||
|
@ -59,10 +44,10 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte ReadControls2()
|
private byte ReadControls2()
|
||||||
{
|
{
|
||||||
InputCallbacks.Call();
|
InputCallbacks.Call();
|
||||||
lagged = false;
|
_lagged = false;
|
||||||
byte value = 0xFF;
|
byte value = 0xFF;
|
||||||
|
|
||||||
if (Controller["P2 Left"]) value &= 0xFE;
|
if (Controller["P2 Left"]) value &= 0xFE;
|
||||||
|
@ -74,7 +59,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
|
|
||||||
if ((Port3F & 0x0F) == 5)
|
if ((Port3F & 0x0F) == 5)
|
||||||
{
|
{
|
||||||
if (region == "Japan")
|
if (_region == "Japan")
|
||||||
{
|
{
|
||||||
value &= 0x3F;
|
value &= 0x3F;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
using BizHawk.Common;
|
|
||||||
using BizHawk.Common.NumberExtensions;
|
|
||||||
using BizHawk.Common.StringExtensions;
|
using BizHawk.Common.StringExtensions;
|
||||||
|
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
using BizHawk.Emulation.Common.Components;
|
using BizHawk.Emulation.Common.Components;
|
||||||
using BizHawk.Emulation.Cores.Components.Z80;
|
using BizHawk.Emulation.Cores.Components.Z80;
|
||||||
|
@ -32,68 +28,39 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
IDebuggable, ISettable<SMS.SMSSettings, SMS.SMSSyncSettings>, ICodeDataLogger
|
IDebuggable, ISettable<SMS.SMSSettings, SMS.SMSSyncSettings>, ICodeDataLogger
|
||||||
{
|
{
|
||||||
// Constants
|
// Constants
|
||||||
public const int BankSize = 16384;
|
private const int BankSize = 16384;
|
||||||
|
|
||||||
// ROM
|
// ROM
|
||||||
public byte[] RomData;
|
private byte[] RomData;
|
||||||
public byte RomBank0, RomBank1, RomBank2, RomBank3;
|
private byte RomBank0, RomBank1, RomBank2, RomBank3;
|
||||||
public byte RomBanks;
|
private byte RomBanks;
|
||||||
|
private byte[] BiosRom;
|
||||||
// SaveRAM
|
|
||||||
public byte[] SaveRAM;
|
|
||||||
public byte SaveRamBank;
|
|
||||||
|
|
||||||
public byte[] BiosRom;
|
|
||||||
|
|
||||||
public byte[] CloneSaveRam()
|
|
||||||
{
|
|
||||||
if (SaveRAM != null)
|
|
||||||
return (byte[])SaveRAM.Clone();
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
public void StoreSaveRam(byte[] data)
|
|
||||||
{
|
|
||||||
if (SaveRAM != null)
|
|
||||||
Array.Copy(data, SaveRAM, data.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SaveRamModified { get; private set; }
|
|
||||||
|
|
||||||
// Machine resources
|
// Machine resources
|
||||||
public Z80A Cpu;
|
private Z80A Cpu;
|
||||||
public byte[] SystemRam;
|
private byte[] SystemRam;
|
||||||
public VDP Vdp;
|
public VDP Vdp;
|
||||||
public SN76489 PSG;
|
private SN76489 PSG;
|
||||||
public YM2413 YM2413;
|
private YM2413 YM2413;
|
||||||
public SoundMixer SoundMixer;
|
private SoundMixer SoundMixer;
|
||||||
public bool IsGameGear = false;
|
public bool IsGameGear { get; set; }
|
||||||
public bool IsSG1000 = false;
|
public bool IsSG1000 { get; set; }
|
||||||
|
|
||||||
public bool HasYM2413 = false;
|
private bool HasYM2413 = false;
|
||||||
|
|
||||||
int frame = 0;
|
private int frame = 0;
|
||||||
int lagCount = 0;
|
|
||||||
bool lagged = true;
|
|
||||||
bool isLag = false;
|
|
||||||
public int Frame { get { return frame; } set { frame = value; } }
|
public int Frame { get { return frame; } set { frame = value; } }
|
||||||
public int LagCount { get { return lagCount; } set { lagCount = value; } }
|
|
||||||
public bool IsLagFrame { get { return isLag; } set { isLag = value; } }
|
|
||||||
|
|
||||||
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
|
private byte Port01 = 0xFF;
|
||||||
public IInputCallbackSystem InputCallbacks { get { return _inputCallbacks; } }
|
private byte Port02 = 0xFF;
|
||||||
public IMemoryCallbackSystem MemoryCallbacks { get; private set; }
|
private byte Port3E = 0xAF;
|
||||||
|
private byte Port3F = 0xFF;
|
||||||
|
|
||||||
byte Port01 = 0xFF;
|
private byte ForceStereoByte = 0xAD;
|
||||||
byte Port02 = 0xFF;
|
private bool IsGame3D = false;
|
||||||
byte Port3E = 0xAF;
|
|
||||||
byte Port3F = 0xFF;
|
|
||||||
|
|
||||||
byte ForceStereoByte = 0xAD;
|
|
||||||
bool IsGame3D = false;
|
|
||||||
|
|
||||||
public DisplayType Region { get; set; }
|
public DisplayType Region { get; set; }
|
||||||
public bool DeterministicEmulation { get { return true; } }
|
|
||||||
|
|
||||||
[CoreConstructor("SMS", "SG", "GG")]
|
[CoreConstructor("SMS", "SG", "GG")]
|
||||||
public SMS(CoreComm comm, GameInfo game, byte[] rom, object settings, object syncSettings)
|
public SMS(CoreComm comm, GameInfo game, byte[] rom, object settings, object syncSettings)
|
||||||
|
@ -217,16 +184,15 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
//this manages the linkage between the cpu and mapper callbacks so it needs running before bootup is complete
|
//this manages the linkage between the cpu and mapper callbacks so it needs running before bootup is complete
|
||||||
((ICodeDataLogger)this).SetCDL(null);
|
((ICodeDataLogger)this).SetCDL(null);
|
||||||
|
|
||||||
|
InputCallbacks = new InputCallbackSystem();
|
||||||
|
|
||||||
Tracer = new TraceBuffer { Header = Cpu.TraceHeader };
|
Tracer = new TraceBuffer { Header = Cpu.TraceHeader };
|
||||||
|
|
||||||
var serviceProvider = ServiceProvider as BasicServiceProvider;
|
var serviceProvider = ServiceProvider as BasicServiceProvider;
|
||||||
serviceProvider.Register<ITraceable>(Tracer);
|
serviceProvider.Register<ITraceable>(Tracer);
|
||||||
serviceProvider.Register<IDisassemblable>(new Disassembler());
|
serviceProvider.Register<IDisassemblable>(new Disassembler());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEmulatorServiceProvider ServiceProvider { get; private set; }
|
|
||||||
|
|
||||||
private ITraceable Tracer { get; set; }
|
private ITraceable Tracer { get; set; }
|
||||||
|
|
||||||
string DetermineRegion(string gameRegion)
|
string DetermineRegion(string gameRegion)
|
||||||
|
@ -246,7 +212,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
return "Japan";
|
return "Japan";
|
||||||
}
|
}
|
||||||
|
|
||||||
DisplayType DetermineDisplayType(string display, string region)
|
private DisplayType DetermineDisplayType(string display, string region)
|
||||||
{
|
{
|
||||||
if (display == "NTSC") return DisplayType.NTSC;
|
if (display == "NTSC") return DisplayType.NTSC;
|
||||||
if (display == "PAL") return DisplayType.PAL;
|
if (display == "PAL") return DisplayType.PAL;
|
||||||
|
@ -254,32 +220,25 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
return DisplayType.NTSC;
|
return DisplayType.NTSC;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResetCounters()
|
|
||||||
{
|
|
||||||
Frame = 0;
|
|
||||||
lagCount = 0;
|
|
||||||
isLag = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The ReadMemory callback for the mapper
|
/// The ReadMemory callback for the mapper
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Func<ushort, byte> ReadMemory;
|
private Func<ushort, byte> ReadMemory;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The WriteMemory callback for the wrapper
|
/// The WriteMemory callback for the wrapper
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Action<ushort, byte> WriteMemory;
|
private Action<ushort, byte> WriteMemory;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A dummy FetchMemory that simply reads the memory
|
/// A dummy FetchMemory that simply reads the memory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte FetchMemory_StubThunk(ushort address, bool first)
|
private byte FetchMemory_StubThunk(ushort address, bool first)
|
||||||
{
|
{
|
||||||
return ReadMemory(address);
|
return ReadMemory(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte ReadPort(ushort port)
|
private byte ReadPort(ushort port)
|
||||||
{
|
{
|
||||||
port &= 0xFF;
|
port &= 0xFF;
|
||||||
if (port < 0x40) // General IO ports
|
if (port < 0x40) // General IO ports
|
||||||
|
@ -322,7 +281,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WritePort(ushort port, byte value)
|
private void WritePort(ushort port, byte value)
|
||||||
{
|
{
|
||||||
port &= 0xFF;
|
port &= 0xFF;
|
||||||
if (port < 0x40) // general IO ports
|
if (port < 0x40) // general IO ports
|
||||||
|
@ -350,357 +309,23 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
else if (port == 0xF2 && HasYM2413) YM2413.DetectionValue = value;
|
else if (port == 0xF2 && HasYM2413) YM2413.DetectionValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FrameAdvance(bool render, bool rendersound)
|
private ISoundProvider ActiveSoundProvider;
|
||||||
|
|
||||||
|
private string _region;
|
||||||
|
private string RegionStr
|
||||||
{
|
{
|
||||||
lagged = true;
|
get { return _region; }
|
||||||
Frame++;
|
|
||||||
PSG.BeginFrame(Cpu.TotalExecutedCycles);
|
|
||||||
Cpu.Debug = Tracer.Enabled;
|
|
||||||
if (!IsGameGear)
|
|
||||||
PSG.StereoPanning = Settings.ForceStereoSeparation ? ForceStereoByte : (byte) 0xFF;
|
|
||||||
|
|
||||||
if (Cpu.Debug && Cpu.Logger == null) // TODO, lets not do this on each frame. But lets refactor CoreComm/CoreComm first
|
|
||||||
Cpu.Logger = (s) => Tracer.Put(s);
|
|
||||||
|
|
||||||
if (IsGameGear == false)
|
|
||||||
Cpu.NonMaskableInterrupt = Controller["Pause"];
|
|
||||||
|
|
||||||
if (IsGame3D && Settings.Fix3D)
|
|
||||||
Vdp.ExecFrame((Frame & 1) == 0);
|
|
||||||
else
|
|
||||||
Vdp.ExecFrame(render);
|
|
||||||
|
|
||||||
PSG.EndFrame(Cpu.TotalExecutedCycles);
|
|
||||||
if (lagged)
|
|
||||||
{
|
|
||||||
lagCount++;
|
|
||||||
isLag = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
isLag = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool BinarySaveStatesPreferred { get { return false; } }
|
|
||||||
public void SaveStateBinary(BinaryWriter bw) { SyncState(Serializer.CreateBinaryWriter(bw)); }
|
|
||||||
public void LoadStateBinary(BinaryReader br) { SyncState(Serializer.CreateBinaryReader(br)); }
|
|
||||||
public void SaveStateText(TextWriter tw) { SyncState(Serializer.CreateTextWriter(tw)); }
|
|
||||||
public void LoadStateText(TextReader tr) { SyncState(Serializer.CreateTextReader(tr)); }
|
|
||||||
|
|
||||||
void SyncState(Serializer ser)
|
|
||||||
{
|
|
||||||
ser.BeginSection("SMS");
|
|
||||||
Cpu.SyncState(ser);
|
|
||||||
Vdp.SyncState(ser);
|
|
||||||
PSG.SyncState(ser);
|
|
||||||
ser.Sync("RAM", ref SystemRam, false);
|
|
||||||
ser.Sync("RomBank0", ref RomBank0);
|
|
||||||
ser.Sync("RomBank1", ref RomBank1);
|
|
||||||
ser.Sync("RomBank2", ref RomBank2);
|
|
||||||
ser.Sync("RomBank3", ref RomBank3);
|
|
||||||
ser.Sync("Port01", ref Port01);
|
|
||||||
ser.Sync("Port02", ref Port02);
|
|
||||||
ser.Sync("Port3E", ref Port3E);
|
|
||||||
ser.Sync("Port3F", ref Port3F);
|
|
||||||
|
|
||||||
if (SaveRAM != null)
|
|
||||||
{
|
|
||||||
ser.Sync("SaveRAM", ref SaveRAM, false);
|
|
||||||
ser.Sync("SaveRamBank", ref SaveRamBank);
|
|
||||||
}
|
|
||||||
if (ExtRam != null)
|
|
||||||
ser.Sync("ExtRAM", ref ExtRam, true);
|
|
||||||
if (HasYM2413)
|
|
||||||
YM2413.SyncState(ser);
|
|
||||||
|
|
||||||
ser.Sync("Frame", ref frame);
|
|
||||||
ser.Sync("LagCount", ref lagCount);
|
|
||||||
ser.Sync("IsLag", ref isLag);
|
|
||||||
|
|
||||||
ser.EndSection();
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] stateBuffer;
|
|
||||||
public byte[] SaveStateBinary()
|
|
||||||
{
|
|
||||||
if (stateBuffer == null)
|
|
||||||
{
|
|
||||||
var stream = new MemoryStream();
|
|
||||||
var writer = new BinaryWriter(stream);
|
|
||||||
SaveStateBinary(writer);
|
|
||||||
stateBuffer = stream.ToArray();
|
|
||||||
writer.Close();
|
|
||||||
return stateBuffer;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var stream = new MemoryStream(stateBuffer);
|
|
||||||
var writer = new BinaryWriter(stream);
|
|
||||||
SaveStateBinary(writer);
|
|
||||||
writer.Close();
|
|
||||||
return stateBuffer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public CoreComm CoreComm { get; private set; }
|
|
||||||
|
|
||||||
ISoundProvider ActiveSoundProvider;
|
|
||||||
public ISoundProvider SoundProvider { get { return ActiveSoundProvider; } }
|
|
||||||
public ISyncSoundProvider SyncSoundProvider { get { return new FakeSyncSound(ActiveSoundProvider, 735); } }
|
|
||||||
public bool StartAsyncSound() { return true; }
|
|
||||||
public void EndAsyncSound() { }
|
|
||||||
|
|
||||||
public string SystemId { get { return "SMS"; } }
|
|
||||||
|
|
||||||
public string BoardName { get { return null; } }
|
|
||||||
|
|
||||||
string region;
|
|
||||||
public string RegionStr
|
|
||||||
{
|
|
||||||
get { return region; }
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value.NotIn(validRegions))
|
if (value.NotIn(validRegions))
|
||||||
|
{
|
||||||
throw new Exception("Passed value " + value + " is not a valid region!");
|
throw new Exception("Passed value " + value + " is not a valid region!");
|
||||||
region = value;
|
}
|
||||||
|
|
||||||
|
_region = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly string[] validRegions = { "Export", "Japan", "Auto" };
|
private readonly string[] validRegions = { "Export", "Japan", "Auto" };
|
||||||
|
|
||||||
MemoryDomainList memoryDomains;
|
|
||||||
|
|
||||||
void SetupMemoryDomains()
|
|
||||||
{
|
|
||||||
var domains = new List<MemoryDomain>(3);
|
|
||||||
var MainMemoryDomain = new MemoryDomain("Main RAM", SystemRam.Length, MemoryDomain.Endian.Little,
|
|
||||||
addr => SystemRam[addr],
|
|
||||||
(addr, value) => SystemRam[addr] = value);
|
|
||||||
var VRamDomain = new MemoryDomain("Video RAM", Vdp.VRAM.Length, MemoryDomain.Endian.Little,
|
|
||||||
addr => Vdp.VRAM[addr],
|
|
||||||
(addr, value) => Vdp.VRAM[addr] = value);
|
|
||||||
|
|
||||||
var ROMDomain = new MemoryDomain("ROM", RomData.Length, MemoryDomain.Endian.Little,
|
|
||||||
addr => RomData[addr],
|
|
||||||
(addr, value) => RomData[addr] = value);
|
|
||||||
|
|
||||||
var SystemBusDomain = new MemoryDomain("System Bus", 0x10000, MemoryDomain.Endian.Little,
|
|
||||||
(addr) =>
|
|
||||||
{
|
|
||||||
if (addr < 0 || addr >= 65536)
|
|
||||||
throw new ArgumentOutOfRangeException();
|
|
||||||
return Cpu.ReadMemory((ushort)addr);
|
|
||||||
},
|
|
||||||
(addr, value) =>
|
|
||||||
{
|
|
||||||
if (addr < 0 || addr >= 65536)
|
|
||||||
throw new ArgumentOutOfRangeException();
|
|
||||||
Cpu.WriteMemory((ushort)addr, value);
|
|
||||||
});
|
|
||||||
|
|
||||||
domains.Add(MainMemoryDomain);
|
|
||||||
domains.Add(VRamDomain);
|
|
||||||
domains.Add(ROMDomain);
|
|
||||||
domains.Add(SystemBusDomain);
|
|
||||||
|
|
||||||
if (SaveRAM != null)
|
|
||||||
{
|
|
||||||
var SaveRamDomain = new MemoryDomain("Save RAM", SaveRAM.Length, MemoryDomain.Endian.Little,
|
|
||||||
addr => SaveRAM[addr],
|
|
||||||
(addr, value) => { SaveRAM[addr] = value; SaveRamModified = true; });
|
|
||||||
domains.Add(SaveRamDomain);
|
|
||||||
}
|
|
||||||
if (ExtRam != null)
|
|
||||||
{
|
|
||||||
var ExtRamDomain = new MemoryDomain("Cart (Volatile) RAM", ExtRam.Length, MemoryDomain.Endian.Little,
|
|
||||||
addr => ExtRam[addr],
|
|
||||||
(addr, value) => { ExtRam[addr] = value; });
|
|
||||||
domains.Add(ExtRamDomain);
|
|
||||||
}
|
|
||||||
memoryDomains = new MemoryDomainList(domains);
|
|
||||||
(ServiceProvider as BasicServiceProvider).Register<IMemoryDomains>(memoryDomains);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
|
|
||||||
{
|
|
||||||
return new Dictionary<string, RegisterValue>
|
|
||||||
{
|
|
||||||
{ "A", Cpu.RegisterA },
|
|
||||||
{ "AF", Cpu.RegisterAF },
|
|
||||||
{ "B", Cpu.RegisterB },
|
|
||||||
{ "BC", Cpu.RegisterBC },
|
|
||||||
{ "C", Cpu.RegisterC },
|
|
||||||
{ "D", Cpu.RegisterD },
|
|
||||||
{ "DE", Cpu.RegisterDE },
|
|
||||||
{ "E", Cpu.RegisterE },
|
|
||||||
{ "F", Cpu.RegisterF },
|
|
||||||
{ "H", Cpu.RegisterH },
|
|
||||||
{ "HL", Cpu.RegisterHL },
|
|
||||||
{ "I", Cpu.RegisterI },
|
|
||||||
{ "IX", Cpu.RegisterIX },
|
|
||||||
{ "IY", Cpu.RegisterIY },
|
|
||||||
{ "L", Cpu.RegisterL },
|
|
||||||
{ "PC", Cpu.RegisterPC },
|
|
||||||
{ "R", Cpu.RegisterR },
|
|
||||||
{ "Shadow AF", Cpu.RegisterShadowAF },
|
|
||||||
{ "Shadow BC", Cpu.RegisterShadowBC },
|
|
||||||
{ "Shadow DE", Cpu.RegisterShadowDE },
|
|
||||||
{ "Shadow HL", Cpu.RegisterShadowHL },
|
|
||||||
{ "SP", Cpu.RegisterSP },
|
|
||||||
{ "Flag C", Cpu.RegisterF.Bit(0) },
|
|
||||||
{ "Flag N", Cpu.RegisterF.Bit(1) },
|
|
||||||
{ "Flag P/V", Cpu.RegisterF.Bit(2) },
|
|
||||||
{ "Flag 3rd", Cpu.RegisterF.Bit(3) },
|
|
||||||
{ "Flag H", Cpu.RegisterF.Bit(4) },
|
|
||||||
{ "Flag 5th", Cpu.RegisterF.Bit(5) },
|
|
||||||
{ "Flag Z", Cpu.RegisterF.Bit(6) },
|
|
||||||
{ "Flag S", Cpu.RegisterF.Bit(7) },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetCpuRegister(string register, int value)
|
|
||||||
{
|
|
||||||
switch (register)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
case "A":
|
|
||||||
Cpu.RegisterA = (byte)value;
|
|
||||||
break;
|
|
||||||
case "AF":
|
|
||||||
Cpu.RegisterAF = (byte)value;
|
|
||||||
break;
|
|
||||||
case "B":
|
|
||||||
Cpu.RegisterB = (byte)value;
|
|
||||||
break;
|
|
||||||
case "BC":
|
|
||||||
Cpu.RegisterBC = (byte)value;
|
|
||||||
break;
|
|
||||||
case "C":
|
|
||||||
Cpu.RegisterC = (byte)value;
|
|
||||||
break;
|
|
||||||
case "D":
|
|
||||||
Cpu.RegisterD = (byte)value;
|
|
||||||
break;
|
|
||||||
case "DE":
|
|
||||||
Cpu.RegisterDE = (byte)value;
|
|
||||||
break;
|
|
||||||
case "E":
|
|
||||||
Cpu.RegisterE = (byte)value;
|
|
||||||
break;
|
|
||||||
case "F":
|
|
||||||
Cpu.RegisterF = (byte)value;
|
|
||||||
break;
|
|
||||||
case "H":
|
|
||||||
Cpu.RegisterH = (byte)value;
|
|
||||||
break;
|
|
||||||
case "HL":
|
|
||||||
Cpu.RegisterHL = (byte)value;
|
|
||||||
break;
|
|
||||||
case "I":
|
|
||||||
Cpu.RegisterI = (byte)value;
|
|
||||||
break;
|
|
||||||
case "IX":
|
|
||||||
Cpu.RegisterIX = (byte)value;
|
|
||||||
break;
|
|
||||||
case "IY":
|
|
||||||
Cpu.RegisterIY = (byte)value;
|
|
||||||
break;
|
|
||||||
case "L":
|
|
||||||
Cpu.RegisterL = (byte)value;
|
|
||||||
break;
|
|
||||||
case "PC":
|
|
||||||
Cpu.RegisterPC = (ushort)value;
|
|
||||||
break;
|
|
||||||
case "R":
|
|
||||||
Cpu.RegisterR = (byte)value;
|
|
||||||
break;
|
|
||||||
case "Shadow AF":
|
|
||||||
Cpu.RegisterShadowAF = (byte)value;
|
|
||||||
break;
|
|
||||||
case "Shadow BC":
|
|
||||||
Cpu.RegisterShadowBC = (byte)value;
|
|
||||||
break;
|
|
||||||
case "Shadow DE":
|
|
||||||
Cpu.RegisterShadowDE = (byte)value;
|
|
||||||
break;
|
|
||||||
case "Shadow HL":
|
|
||||||
Cpu.RegisterShadowHL = (byte)value;
|
|
||||||
break;
|
|
||||||
case "SP":
|
|
||||||
Cpu.RegisterSP = (byte)value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanStep(StepType type) { return false; }
|
|
||||||
|
|
||||||
[FeatureNotImplemented]
|
|
||||||
public void Step(StepType type) { throw new NotImplementedException(); }
|
|
||||||
|
|
||||||
public void Dispose() { }
|
|
||||||
|
|
||||||
public SMSSettings GetSettings() { return Settings.Clone(); }
|
|
||||||
public SMSSyncSettings GetSyncSettings() { return SyncSettings.Clone(); }
|
|
||||||
public bool PutSettings(SMSSettings o)
|
|
||||||
{
|
|
||||||
bool ret = SMSSettings.RebootNeeded(Settings, o);
|
|
||||||
Settings = o;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
public bool PutSyncSettings(SMSSyncSettings o)
|
|
||||||
{
|
|
||||||
bool ret = SMSSyncSettings.RebootNeeded(SyncSettings, o);
|
|
||||||
SyncSettings = o;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SMSSettings Settings;
|
|
||||||
public SMSSyncSettings SyncSettings;
|
|
||||||
|
|
||||||
public class SMSSettings
|
|
||||||
{
|
|
||||||
// Game settings
|
|
||||||
public bool ForceStereoSeparation = false;
|
|
||||||
public bool SpriteLimit = false;
|
|
||||||
public bool Fix3D = true;
|
|
||||||
// GG settings
|
|
||||||
public bool ShowClippedRegions = false;
|
|
||||||
public bool HighlightActiveDisplayRegion = false;
|
|
||||||
// graphics settings
|
|
||||||
public bool DispBG = true;
|
|
||||||
public bool DispOBJ = true;
|
|
||||||
|
|
||||||
public SMSSettings Clone()
|
|
||||||
{
|
|
||||||
return (SMSSettings)MemberwiseClone();
|
|
||||||
}
|
|
||||||
public static bool RebootNeeded(SMSSettings x, SMSSettings y)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SMSSyncSettings
|
|
||||||
{
|
|
||||||
public bool EnableFM = true;
|
|
||||||
public bool AllowOverlock = false;
|
|
||||||
public bool UseBIOS = false;
|
|
||||||
public string ConsoleRegion = "Export";
|
|
||||||
public string DisplayType = "NTSC";
|
|
||||||
|
|
||||||
public SMSSyncSettings Clone()
|
|
||||||
{
|
|
||||||
return (SMSSyncSettings)MemberwiseClone();
|
|
||||||
}
|
|
||||||
public static bool RebootNeeded(SMSSyncSettings x, SMSSyncSettings y)
|
|
||||||
{
|
|
||||||
return
|
|
||||||
x.EnableFM != y.EnableFM ||
|
|
||||||
x.AllowOverlock != y.AllowOverlock ||
|
|
||||||
x.UseBIOS != y.UseBIOS ||
|
|
||||||
x.ConsoleRegion != y.ConsoleRegion ||
|
|
||||||
x.DisplayType != y.DisplayType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue