Break up MGBAHawk into separate files
This commit is contained in:
parent
010c04f421
commit
167ed41a51
|
@ -121,7 +121,6 @@ namespace BizHawk.Emulation.Common
|
|||
BitSize = 64;
|
||||
}
|
||||
|
||||
|
||||
public static implicit operator RegisterValue(bool val)
|
||||
{
|
||||
return new RegisterValue(val);
|
||||
|
|
|
@ -479,7 +479,7 @@
|
|||
<DependentUpon>GambatteLink.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\Gameboy\GambatteLink.IEmulator.cs">
|
||||
<DependentUpon>GambatteLink.cs</DependentUpon>
|
||||
<DependentUpon>GambatteLink.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\Gameboy\GambatteLink.IInputPollable.cs">
|
||||
<DependentUpon>GambatteLink.cs</DependentUpon>
|
||||
|
@ -500,7 +500,7 @@
|
|||
<DependentUpon>GambatteLink.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\Gameboy\GamebatteLink.ISoundProvider.cs">
|
||||
<DependentUpon>GambatteLink.cs</DependentUpon>
|
||||
<DependentUpon>GambatteLink.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\Gameboy\GBColors.cs" />
|
||||
<Compile Include="Consoles\Nintendo\Gameboy\GBDisassembler.cs" />
|
||||
|
@ -511,6 +511,30 @@
|
|||
<Compile Include="Consoles\Nintendo\GBA\LibmGBA.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBA\LibVBANext.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBA\MGBAHawk.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBA\MGBAHawk.IDebuggable.cs">
|
||||
<DependentUpon>MGBAHawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\GBA\MGBAHawk.IInputPollable.cs">
|
||||
<DependentUpon>MGBAHawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\GBA\MGBAHawk.IMemoryDomains.cs">
|
||||
<DependentUpon>MGBAHawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\GBA\MGBAHawk.ISaveRam.cs">
|
||||
<DependentUpon>MGBAHawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\GBA\MGBAHawk.ISettable.cs">
|
||||
<DependentUpon>MGBAHawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\GBA\MGBAHawk.ISoundProvider.cs">
|
||||
<DependentUpon>MGBAHawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\GBA\MGBAHawk.IStatable.cs">
|
||||
<DependentUpon>MGBAHawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\GBA\MGBAHawk.IVideoProvider.cs">
|
||||
<DependentUpon>MGBAHawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\GBA\VBANext.cs" />
|
||||
<Compile Include="Consoles\Nintendo\GBA\VBANext.IDebuggable.cs">
|
||||
<DependentUpon>VBANext.cs</DependentUpon>
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
public partial class MGBAHawk : IDebuggable
|
||||
{
|
||||
public IMemoryCallbackSystem MemoryCallbacks
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public int TotalExecutedCycles
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly string[] RegisterNames =
|
||||
{
|
||||
"R0",
|
||||
"R1",
|
||||
"R2",
|
||||
"R3",
|
||||
"R4",
|
||||
"R5",
|
||||
"R6",
|
||||
"R7",
|
||||
"R8",
|
||||
"R9",
|
||||
"R10",
|
||||
"R11",
|
||||
"R12",
|
||||
"R13",
|
||||
"R14",
|
||||
"R15",
|
||||
"CPSR",
|
||||
"SPSR"
|
||||
};
|
||||
|
||||
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
|
||||
{
|
||||
var values = new int[RegisterNames.Length];
|
||||
LibmGBA.BizGetRegisters(_core, values);
|
||||
var ret = new Dictionary<string, RegisterValue>();
|
||||
for (var i = 0; i < RegisterNames.Length; i++)
|
||||
{
|
||||
ret[RegisterNames[i]] = new RegisterValue(values[i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void SetCpuRegister(string register, int value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool CanStep(StepType type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Step(StepType type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
public partial class MGBAHawk : IInputPollable
|
||||
{
|
||||
public int LagCount { get; set; }
|
||||
public bool IsLagFrame { get; set; }
|
||||
|
||||
[FeatureNotImplemented]
|
||||
public IInputCallbackSystem InputCallbacks
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
public partial class MGBAHawk
|
||||
{
|
||||
unsafe byte PeekWRAM(IntPtr xwram, long addr) { return ((byte*)xwram)[addr]; }
|
||||
unsafe void PokeWRAM(IntPtr xwram, long addr, byte value) { ((byte*)xwram)[addr] = value; }
|
||||
|
||||
void WireMemoryDomainPointers()
|
||||
{
|
||||
var s = new LibmGBA.MemoryAreas();
|
||||
LibmGBA.BizGetMemoryAreas(_core, s);
|
||||
|
||||
_iwram.Data = s.iwram;
|
||||
_ewram.Data = s.wram;
|
||||
_bios.Data = s.bios;
|
||||
_palram.Data = s.palram;
|
||||
_vram.Data = s.vram;
|
||||
_oam.Data = s.oam;
|
||||
_rom.Data = s.rom;
|
||||
_sram.Data = s.sram;
|
||||
_sram.SetSize(s.sram_size);
|
||||
|
||||
// special combined ram memory domain
|
||||
|
||||
_cwram.Peek =
|
||||
delegate (long addr)
|
||||
{
|
||||
if (addr < 0 || addr >= (256 + 32) * 1024)
|
||||
throw new IndexOutOfRangeException();
|
||||
if (addr >= 256 * 1024)
|
||||
return PeekWRAM(s.iwram, addr & 32767);
|
||||
else
|
||||
return PeekWRAM(s.wram, addr);
|
||||
};
|
||||
_cwram.Poke =
|
||||
delegate (long addr, byte val)
|
||||
{
|
||||
if (addr < 0 || addr >= (256 + 32) * 1024)
|
||||
throw new IndexOutOfRangeException();
|
||||
if (addr >= 256 * 1024)
|
||||
PokeWRAM(s.iwram, addr & 32767, val);
|
||||
else
|
||||
PokeWRAM(s.wram, addr, val);
|
||||
};
|
||||
|
||||
_gpumem = new GBAGPUMemoryAreas
|
||||
{
|
||||
mmio = s.mmio,
|
||||
oam = s.oam,
|
||||
palram = s.palram,
|
||||
vram = s.vram
|
||||
};
|
||||
}
|
||||
|
||||
private MemoryDomainIntPtr _iwram;
|
||||
private MemoryDomainIntPtr _ewram;
|
||||
private MemoryDomainIntPtr _bios;
|
||||
private MemoryDomainIntPtr _palram;
|
||||
private MemoryDomainIntPtr _vram;
|
||||
private MemoryDomainIntPtr _oam;
|
||||
private MemoryDomainIntPtr _rom;
|
||||
private MemoryDomainIntPtr _sram;
|
||||
private MemoryDomainDelegate _cwram;
|
||||
|
||||
private void CreateMemoryDomains(int romsize)
|
||||
{
|
||||
var LE = MemoryDomain.Endian.Little;
|
||||
|
||||
var mm = new List<MemoryDomain>();
|
||||
mm.Add(_iwram = new MemoryDomainIntPtr("IWRAM", LE, IntPtr.Zero, 32 * 1024, true, 4));
|
||||
mm.Add(_ewram = new MemoryDomainIntPtr("EWRAM", LE, IntPtr.Zero, 256 * 1024, true, 4));
|
||||
mm.Add(_bios = new MemoryDomainIntPtr("BIOS", LE, IntPtr.Zero, 16 * 1024, false, 4));
|
||||
mm.Add(_palram = new MemoryDomainIntPtr("PALRAM", LE, IntPtr.Zero, 1024, true, 4));
|
||||
mm.Add(_vram = new MemoryDomainIntPtr("VRAM", LE, IntPtr.Zero, 96 * 1024, true, 4));
|
||||
mm.Add(_oam = new MemoryDomainIntPtr("OAM", LE, IntPtr.Zero, 1024, true, 4));
|
||||
mm.Add(_rom = new MemoryDomainIntPtr("ROM", LE, IntPtr.Zero, romsize, false, 4));
|
||||
mm.Add(_sram = new MemoryDomainIntPtr("SRAM", LE, IntPtr.Zero, 0, true, 4)); //size will be fixed in wireup
|
||||
mm.Add(_cwram = new MemoryDomainDelegate("Combined WRAM", (256 + 32) * 1024, LE, null, null, 4));
|
||||
|
||||
MemoryDomains = new MemoryDomainList(mm);
|
||||
WireMemoryDomainPointers();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
public partial class MGBAHawk : ISaveRam
|
||||
{
|
||||
public byte[] CloneSaveRam()
|
||||
{
|
||||
int len = LibmGBA.BizGetSaveRam(_core, _saveScratch, _saveScratch.Length);
|
||||
if (len == _saveScratch.Length)
|
||||
throw new InvalidOperationException("Save buffer not long enough");
|
||||
if (len == 0)
|
||||
return null;
|
||||
|
||||
var ret = new byte[len];
|
||||
Array.Copy(_saveScratch, ret, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static byte[] LegacyFix(byte[] saveram)
|
||||
{
|
||||
// at one point vbanext-hawk had a special saveram format which we want to load.
|
||||
var br = new BinaryReader(new MemoryStream(saveram, false));
|
||||
br.ReadBytes(8); // header;
|
||||
int flashSize = br.ReadInt32();
|
||||
int eepromsize = br.ReadInt32();
|
||||
byte[] flash = br.ReadBytes(flashSize);
|
||||
byte[] eeprom = br.ReadBytes(eepromsize);
|
||||
if (flash.Length == 0)
|
||||
return eeprom;
|
||||
else if (eeprom.Length == 0)
|
||||
return flash;
|
||||
else
|
||||
{
|
||||
// well, isn't this a sticky situation!
|
||||
return flash; // woops
|
||||
}
|
||||
}
|
||||
|
||||
public void StoreSaveRam(byte[] data)
|
||||
{
|
||||
if (data.Take(8).SequenceEqual(Encoding.ASCII.GetBytes("GBABATT\0")))
|
||||
{
|
||||
data = LegacyFix(data);
|
||||
}
|
||||
LibmGBA.BizPutSaveRam(_core, data, data.Length);
|
||||
}
|
||||
|
||||
public bool SaveRamModified
|
||||
{
|
||||
get
|
||||
{
|
||||
return LibmGBA.BizGetSaveRam(_core, _saveScratch, _saveScratch.Length) > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
public partial class MGBAHawk : ISettable<MGBAHawk.Settings, MGBAHawk.SyncSettings>
|
||||
{
|
||||
public Settings GetSettings()
|
||||
{
|
||||
return _settings.Clone();
|
||||
}
|
||||
|
||||
public bool PutSettings(Settings o)
|
||||
{
|
||||
LibmGBA.Layers mask = 0;
|
||||
if (o.DisplayBG0) mask |= LibmGBA.Layers.BG0;
|
||||
if (o.DisplayBG1) mask |= LibmGBA.Layers.BG1;
|
||||
if (o.DisplayBG2) mask |= LibmGBA.Layers.BG2;
|
||||
if (o.DisplayBG3) mask |= LibmGBA.Layers.BG3;
|
||||
if (o.DisplayOBJ) mask |= LibmGBA.Layers.OBJ;
|
||||
LibmGBA.BizSetLayerMask(_core, mask);
|
||||
|
||||
LibmGBA.Sounds smask = 0;
|
||||
if (o.PlayCh0) smask |= LibmGBA.Sounds.CH0;
|
||||
if (o.PlayCh1) smask |= LibmGBA.Sounds.CH1;
|
||||
if (o.PlayCh2) smask |= LibmGBA.Sounds.CH2;
|
||||
if (o.PlayCh3) smask |= LibmGBA.Sounds.CH3;
|
||||
if (o.PlayChA) smask |= LibmGBA.Sounds.CHA;
|
||||
if (o.PlayChB) smask |= LibmGBA.Sounds.CHB;
|
||||
LibmGBA.BizSetSoundMask(_core, smask);
|
||||
|
||||
_settings = o;
|
||||
return false;
|
||||
}
|
||||
|
||||
private Settings _settings;
|
||||
|
||||
public class Settings
|
||||
{
|
||||
[DisplayName("Display BG Layer 0")]
|
||||
[DefaultValue(true)]
|
||||
public bool DisplayBG0 { get; set; }
|
||||
[DisplayName("Display BG Layer 1")]
|
||||
[DefaultValue(true)]
|
||||
public bool DisplayBG1 { get; set; }
|
||||
[DisplayName("Display BG Layer 2")]
|
||||
[DefaultValue(true)]
|
||||
public bool DisplayBG2 { get; set; }
|
||||
[DisplayName("Display BG Layer 3")]
|
||||
[DefaultValue(true)]
|
||||
public bool DisplayBG3 { get; set; }
|
||||
[DisplayName("Display Sprite Layer")]
|
||||
[DefaultValue(true)]
|
||||
public bool DisplayOBJ { get; set; }
|
||||
|
||||
[DisplayName("Play Square 1")]
|
||||
[DefaultValue(true)]
|
||||
public bool PlayCh0 { get; set; }
|
||||
[DisplayName("Play Square 2")]
|
||||
[DefaultValue(true)]
|
||||
public bool PlayCh1 { get; set; }
|
||||
[DisplayName("Play Wave")]
|
||||
[DefaultValue(true)]
|
||||
public bool PlayCh2 { get; set; }
|
||||
[DisplayName("Play Noise")]
|
||||
[DefaultValue(true)]
|
||||
public bool PlayCh3 { get; set; }
|
||||
[DisplayName("Play Direct Sound A")]
|
||||
[DefaultValue(true)]
|
||||
public bool PlayChA { get; set; }
|
||||
[DisplayName("Play Direct Sound B")]
|
||||
[DefaultValue(true)]
|
||||
public bool PlayChB { get; set; }
|
||||
|
||||
public Settings Clone()
|
||||
{
|
||||
return (Settings)MemberwiseClone();
|
||||
}
|
||||
|
||||
public Settings()
|
||||
{
|
||||
SettingsUtil.SetDefaultValues(this);
|
||||
}
|
||||
}
|
||||
|
||||
public SyncSettings GetSyncSettings()
|
||||
{
|
||||
return _syncSettings.Clone();
|
||||
}
|
||||
|
||||
public bool PutSyncSettings(SyncSettings o)
|
||||
{
|
||||
bool ret = SyncSettings.NeedsReboot(o, _syncSettings);
|
||||
_syncSettings = o;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private SyncSettings _syncSettings;
|
||||
|
||||
public class SyncSettings
|
||||
{
|
||||
[DisplayName("Skip BIOS")]
|
||||
[Description("Skips the BIOS intro. Not applicable when a BIOS is not provided.")]
|
||||
[DefaultValue(true)]
|
||||
public bool SkipBios { get; set; }
|
||||
|
||||
[DisplayName("RTC Use Real Time")]
|
||||
[Description("Causes the internal clock to reflect your system clock. Only relevant when a game has an RTC chip. Forced to false for movie recording.")]
|
||||
[DefaultValue(true)]
|
||||
public bool RTCUseRealTime { get; set; }
|
||||
|
||||
[DisplayName("RTC Initial Time")]
|
||||
[Description("The initial time of emulation. Only relevant when a game has an RTC chip and \"RTC Use Real Time\" is false.")]
|
||||
[DefaultValue(typeof(DateTime), "2010-01-01")]
|
||||
public DateTime RTCInitialTime { get; set; }
|
||||
|
||||
public SyncSettings()
|
||||
{
|
||||
SettingsUtil.SetDefaultValues(this);
|
||||
}
|
||||
|
||||
public static bool NeedsReboot(SyncSettings x, SyncSettings y)
|
||||
{
|
||||
return !DeepEquality.DeepEquals(x, y);
|
||||
}
|
||||
|
||||
public SyncSettings Clone()
|
||||
{
|
||||
return (SyncSettings)MemberwiseClone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
using System;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
public partial class MGBAHawk : ISoundProvider
|
||||
{
|
||||
private readonly short[] soundbuff = new short[2048];
|
||||
private int nsamp;
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
nsamp = this.nsamp;
|
||||
samples = soundbuff;
|
||||
DiscardSamples();
|
||||
}
|
||||
public void DiscardSamples()
|
||||
{
|
||||
nsamp = 0;
|
||||
}
|
||||
|
||||
public bool CanProvideAsync
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public void SetSyncMode(SyncSoundMode mode)
|
||||
{
|
||||
if (mode == SyncSoundMode.Async)
|
||||
{
|
||||
throw new NotSupportedException("Async mode is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public SyncSoundMode SyncMode
|
||||
{
|
||||
get { return SyncSoundMode.Sync; }
|
||||
}
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
{
|
||||
throw new InvalidOperationException("Async mode is not supported.");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
public partial class MGBAHawk : IStatable
|
||||
{
|
||||
private byte[] _savebuff = new byte[0];
|
||||
private byte[] _savebuff2 = new byte[13];
|
||||
|
||||
public bool BinarySaveStatesPreferred
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public void SaveStateText(TextWriter writer)
|
||||
{
|
||||
var tmp = SaveStateBinary();
|
||||
BizHawk.Common.BufferExtensions.BufferExtensions.SaveAsHexFast(tmp, writer);
|
||||
}
|
||||
public void LoadStateText(TextReader reader)
|
||||
{
|
||||
string hex = reader.ReadLine();
|
||||
byte[] state = new byte[hex.Length / 2];
|
||||
BizHawk.Common.BufferExtensions.BufferExtensions.ReadFromHexFast(state, hex);
|
||||
LoadStateBinary(new BinaryReader(new MemoryStream(state)));
|
||||
}
|
||||
|
||||
private void StartSaveStateBinaryInternal()
|
||||
{
|
||||
IntPtr p = IntPtr.Zero;
|
||||
int size = 0;
|
||||
if (!LibmGBA.BizStartGetState(_core, ref p, ref size))
|
||||
throw new InvalidOperationException("Core failed to save!");
|
||||
if (size != _savebuff.Length)
|
||||
{
|
||||
_savebuff = new byte[size];
|
||||
_savebuff2 = new byte[size + 13];
|
||||
}
|
||||
LibmGBA.BizFinishGetState(p, _savebuff, size);
|
||||
}
|
||||
|
||||
private void FinishSaveStateBinaryInternal(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(_savebuff.Length);
|
||||
writer.Write(_savebuff, 0, _savebuff.Length);
|
||||
|
||||
// other variables
|
||||
writer.Write(IsLagFrame);
|
||||
writer.Write(LagCount);
|
||||
writer.Write(Frame);
|
||||
}
|
||||
|
||||
public void SaveStateBinary(BinaryWriter writer)
|
||||
{
|
||||
StartSaveStateBinaryInternal();
|
||||
FinishSaveStateBinaryInternal(writer);
|
||||
}
|
||||
|
||||
public void LoadStateBinary(BinaryReader reader)
|
||||
{
|
||||
int length = reader.ReadInt32();
|
||||
if (length != _savebuff.Length)
|
||||
{
|
||||
_savebuff = new byte[length];
|
||||
_savebuff2 = new byte[length + 13];
|
||||
}
|
||||
reader.Read(_savebuff, 0, length);
|
||||
if (!LibmGBA.BizPutState(_core, _savebuff, length))
|
||||
throw new InvalidOperationException("Core rejected the savestate!");
|
||||
|
||||
// other variables
|
||||
IsLagFrame = reader.ReadBoolean();
|
||||
LagCount = reader.ReadInt32();
|
||||
Frame = reader.ReadInt32();
|
||||
}
|
||||
|
||||
public byte[] SaveStateBinary()
|
||||
{
|
||||
StartSaveStateBinaryInternal();
|
||||
var ms = new MemoryStream(_savebuff2, true);
|
||||
var bw = new BinaryWriter(ms);
|
||||
FinishSaveStateBinaryInternal(bw);
|
||||
bw.Flush();
|
||||
ms.Close();
|
||||
return _savebuff2;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
public partial class MGBAHawk : IVideoProvider
|
||||
{
|
||||
public int VirtualWidth { get { return 240; } }
|
||||
public int VirtualHeight { get { return 160; } }
|
||||
public int BufferWidth { get { return 240; } }
|
||||
public int BufferHeight { get { return 160; } }
|
||||
public int BackgroundColor
|
||||
{
|
||||
get { return unchecked((int)0xff000000); }
|
||||
}
|
||||
public int[] GetVideoBuffer()
|
||||
{
|
||||
return videobuff;
|
||||
}
|
||||
private readonly int[] videobuff = new int[240 * 160];
|
||||
}
|
||||
}
|
|
@ -1,18 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
[CoreAttributes("mGBA", "endrift", true, true, "0.5.0", "https://mgba.io/", false)]
|
||||
[ServiceNotApplicable(typeof(IDriveLight), typeof(IRegionable))]
|
||||
public class MGBAHawk : IEmulator, IVideoProvider, ISoundProvider, IGBAGPUViewable,
|
||||
public partial class MGBAHawk : IEmulator, IVideoProvider, ISoundProvider, IGBAGPUViewable,
|
||||
ISaveRam, IStatable, IInputPollable, ISettable<MGBAHawk.Settings, MGBAHawk.SyncSettings>,
|
||||
IDebuggable
|
||||
{
|
||||
|
@ -176,145 +169,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
}
|
||||
}
|
||||
|
||||
#region IVideoProvider
|
||||
public int VirtualWidth { get { return 240; } }
|
||||
public int VirtualHeight { get { return 160; } }
|
||||
public int BufferWidth { get { return 240; } }
|
||||
public int BufferHeight { get { return 160; } }
|
||||
public int BackgroundColor
|
||||
{
|
||||
get { return unchecked((int)0xff000000); }
|
||||
}
|
||||
public int[] GetVideoBuffer()
|
||||
{
|
||||
return videobuff;
|
||||
}
|
||||
private readonly int[] videobuff = new int[240 * 160];
|
||||
#endregion
|
||||
|
||||
#region ISoundProvider
|
||||
|
||||
private readonly short[] soundbuff = new short[2048];
|
||||
private int nsamp;
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
nsamp = this.nsamp;
|
||||
samples = soundbuff;
|
||||
DiscardSamples();
|
||||
}
|
||||
public void DiscardSamples()
|
||||
{
|
||||
nsamp = 0;
|
||||
}
|
||||
|
||||
public bool CanProvideAsync
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public void SetSyncMode(SyncSoundMode mode)
|
||||
{
|
||||
if (mode == SyncSoundMode.Async)
|
||||
{
|
||||
throw new NotSupportedException("Async mode is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public SyncSoundMode SyncMode
|
||||
{
|
||||
get { return SyncSoundMode.Sync; }
|
||||
}
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
{
|
||||
throw new InvalidOperationException("Async mode is not supported.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IMemoryDomains
|
||||
|
||||
unsafe byte PeekWRAM(IntPtr xwram, long addr) { return ((byte*)xwram)[addr]; }
|
||||
unsafe void PokeWRAM(IntPtr xwram, long addr, byte value) { ((byte*)xwram)[addr] = value; }
|
||||
|
||||
void WireMemoryDomainPointers()
|
||||
{
|
||||
var s = new LibmGBA.MemoryAreas();
|
||||
LibmGBA.BizGetMemoryAreas(_core, s);
|
||||
|
||||
_iwram.Data = s.iwram;
|
||||
_ewram.Data = s.wram;
|
||||
_bios.Data = s.bios;
|
||||
_palram.Data = s.palram;
|
||||
_vram.Data = s.vram;
|
||||
_oam.Data = s.oam;
|
||||
_rom.Data = s.rom;
|
||||
_sram.Data = s.sram;
|
||||
_sram.SetSize(s.sram_size);
|
||||
|
||||
// special combined ram memory domain
|
||||
|
||||
_cwram.Peek =
|
||||
delegate (long addr)
|
||||
{
|
||||
if (addr < 0 || addr >= (256 + 32) * 1024)
|
||||
throw new IndexOutOfRangeException();
|
||||
if (addr >= 256 * 1024)
|
||||
return PeekWRAM(s.iwram, addr & 32767);
|
||||
else
|
||||
return PeekWRAM(s.wram, addr);
|
||||
};
|
||||
_cwram.Poke =
|
||||
delegate (long addr, byte val)
|
||||
{
|
||||
if (addr < 0 || addr >= (256 + 32) * 1024)
|
||||
throw new IndexOutOfRangeException();
|
||||
if (addr >= 256 * 1024)
|
||||
PokeWRAM(s.iwram, addr & 32767, val);
|
||||
else
|
||||
PokeWRAM(s.wram, addr, val);
|
||||
};
|
||||
|
||||
_gpumem = new GBAGPUMemoryAreas
|
||||
{
|
||||
mmio = s.mmio,
|
||||
oam = s.oam,
|
||||
palram = s.palram,
|
||||
vram = s.vram
|
||||
};
|
||||
}
|
||||
|
||||
private MemoryDomainIntPtr _iwram;
|
||||
private MemoryDomainIntPtr _ewram;
|
||||
private MemoryDomainIntPtr _bios;
|
||||
private MemoryDomainIntPtr _palram;
|
||||
private MemoryDomainIntPtr _vram;
|
||||
private MemoryDomainIntPtr _oam;
|
||||
private MemoryDomainIntPtr _rom;
|
||||
private MemoryDomainIntPtr _sram;
|
||||
private MemoryDomainDelegate _cwram;
|
||||
|
||||
private void CreateMemoryDomains(int romsize)
|
||||
{
|
||||
var LE = MemoryDomain.Endian.Little;
|
||||
|
||||
var mm = new List<MemoryDomain>();
|
||||
mm.Add(_iwram = new MemoryDomainIntPtr("IWRAM", LE, IntPtr.Zero, 32 * 1024, true, 4));
|
||||
mm.Add(_ewram = new MemoryDomainIntPtr("EWRAM", LE, IntPtr.Zero, 256 * 1024, true, 4));
|
||||
mm.Add(_bios = new MemoryDomainIntPtr("BIOS", LE, IntPtr.Zero, 16 * 1024, false, 4));
|
||||
mm.Add(_palram = new MemoryDomainIntPtr("PALRAM", LE, IntPtr.Zero, 1024, true, 4));
|
||||
mm.Add(_vram = new MemoryDomainIntPtr("VRAM", LE, IntPtr.Zero, 96 * 1024, true, 4));
|
||||
mm.Add(_oam = new MemoryDomainIntPtr("OAM", LE, IntPtr.Zero, 1024, true, 4));
|
||||
mm.Add(_rom = new MemoryDomainIntPtr("ROM", LE, IntPtr.Zero, romsize, false, 4));
|
||||
mm.Add(_sram = new MemoryDomainIntPtr("SRAM", LE, IntPtr.Zero, 0, true, 4)); //size will be fixed in wireup
|
||||
mm.Add(_cwram = new MemoryDomainDelegate("Combined WRAM", (256 + 32) * 1024, LE, null, null, 4));
|
||||
|
||||
MemoryDomains = new MemoryDomainList(mm);
|
||||
WireMemoryDomainPointers();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Action _scanlinecb;
|
||||
|
||||
private GBAGPUMemoryAreas _gpumem;
|
||||
|
@ -330,154 +184,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
_scanlinecb = callback;
|
||||
}
|
||||
|
||||
#region ISaveRam
|
||||
|
||||
public byte[] CloneSaveRam()
|
||||
{
|
||||
int len = LibmGBA.BizGetSaveRam(_core, _saveScratch, _saveScratch.Length);
|
||||
if (len == _saveScratch.Length)
|
||||
throw new InvalidOperationException("Save buffer not long enough");
|
||||
if (len == 0)
|
||||
return null;
|
||||
|
||||
var ret = new byte[len];
|
||||
Array.Copy(_saveScratch, ret, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static byte[] LegacyFix(byte[] saveram)
|
||||
{
|
||||
// at one point vbanext-hawk had a special saveram format which we want to load.
|
||||
var br = new BinaryReader(new MemoryStream(saveram, false));
|
||||
br.ReadBytes(8); // header;
|
||||
int flashSize = br.ReadInt32();
|
||||
int eepromsize = br.ReadInt32();
|
||||
byte[] flash = br.ReadBytes(flashSize);
|
||||
byte[] eeprom = br.ReadBytes(eepromsize);
|
||||
if (flash.Length == 0)
|
||||
return eeprom;
|
||||
else if (eeprom.Length == 0)
|
||||
return flash;
|
||||
else
|
||||
{
|
||||
// well, isn't this a sticky situation!
|
||||
return flash; // woops
|
||||
}
|
||||
}
|
||||
|
||||
public void StoreSaveRam(byte[] data)
|
||||
{
|
||||
if (data.Take(8).SequenceEqual(Encoding.ASCII.GetBytes("GBABATT\0")))
|
||||
{
|
||||
data = LegacyFix(data);
|
||||
}
|
||||
LibmGBA.BizPutSaveRam(_core, data, data.Length);
|
||||
}
|
||||
|
||||
public bool SaveRamModified
|
||||
{
|
||||
get
|
||||
{
|
||||
return LibmGBA.BizGetSaveRam(_core, _saveScratch, _saveScratch.Length) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IStatable
|
||||
|
||||
private byte[] _savebuff = new byte[0];
|
||||
private byte[] _savebuff2 = new byte[13];
|
||||
|
||||
public bool BinarySaveStatesPreferred
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public void SaveStateText(TextWriter writer)
|
||||
{
|
||||
var tmp = SaveStateBinary();
|
||||
BizHawk.Common.BufferExtensions.BufferExtensions.SaveAsHexFast(tmp, writer);
|
||||
}
|
||||
public void LoadStateText(TextReader reader)
|
||||
{
|
||||
string hex = reader.ReadLine();
|
||||
byte[] state = new byte[hex.Length / 2];
|
||||
BizHawk.Common.BufferExtensions.BufferExtensions.ReadFromHexFast(state, hex);
|
||||
LoadStateBinary(new BinaryReader(new MemoryStream(state)));
|
||||
}
|
||||
|
||||
private void StartSaveStateBinaryInternal()
|
||||
{
|
||||
IntPtr p = IntPtr.Zero;
|
||||
int size = 0;
|
||||
if (!LibmGBA.BizStartGetState(_core, ref p, ref size))
|
||||
throw new InvalidOperationException("Core failed to save!");
|
||||
if (size != _savebuff.Length)
|
||||
{
|
||||
_savebuff = new byte[size];
|
||||
_savebuff2 = new byte[size + 13];
|
||||
}
|
||||
LibmGBA.BizFinishGetState(p, _savebuff, size);
|
||||
}
|
||||
|
||||
private void FinishSaveStateBinaryInternal(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(_savebuff.Length);
|
||||
writer.Write(_savebuff, 0, _savebuff.Length);
|
||||
|
||||
// other variables
|
||||
writer.Write(IsLagFrame);
|
||||
writer.Write(LagCount);
|
||||
writer.Write(Frame);
|
||||
}
|
||||
|
||||
public void SaveStateBinary(BinaryWriter writer)
|
||||
{
|
||||
StartSaveStateBinaryInternal();
|
||||
FinishSaveStateBinaryInternal(writer);
|
||||
}
|
||||
|
||||
public void LoadStateBinary(BinaryReader reader)
|
||||
{
|
||||
int length = reader.ReadInt32();
|
||||
if (length != _savebuff.Length)
|
||||
{
|
||||
_savebuff = new byte[length];
|
||||
_savebuff2 = new byte[length + 13];
|
||||
}
|
||||
reader.Read(_savebuff, 0, length);
|
||||
if (!LibmGBA.BizPutState(_core, _savebuff, length))
|
||||
throw new InvalidOperationException("Core rejected the savestate!");
|
||||
|
||||
// other variables
|
||||
IsLagFrame = reader.ReadBoolean();
|
||||
LagCount = reader.ReadInt32();
|
||||
Frame = reader.ReadInt32();
|
||||
}
|
||||
|
||||
public byte[] SaveStateBinary()
|
||||
{
|
||||
StartSaveStateBinaryInternal();
|
||||
var ms = new MemoryStream(_savebuff2, true);
|
||||
var bw = new BinaryWriter(ms);
|
||||
FinishSaveStateBinaryInternal(bw);
|
||||
bw.Flush();
|
||||
ms.Close();
|
||||
return _savebuff2;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public int LagCount { get; set; }
|
||||
public bool IsLagFrame { get; set; }
|
||||
|
||||
[FeatureNotImplemented]
|
||||
public IInputCallbackSystem InputCallbacks
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
private long RTCTime()
|
||||
{
|
||||
if (!DeterministicEmulation && _syncSettings.RTCUseRealTime)
|
||||
|
@ -488,203 +194,5 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
long increment = Frame * 4389L >> 18;
|
||||
return basetime + increment;
|
||||
}
|
||||
|
||||
#region ISettable
|
||||
|
||||
public Settings GetSettings()
|
||||
{
|
||||
return _settings.Clone();
|
||||
}
|
||||
|
||||
public bool PutSettings(Settings o)
|
||||
{
|
||||
LibmGBA.Layers mask = 0;
|
||||
if (o.DisplayBG0) mask |= LibmGBA.Layers.BG0;
|
||||
if (o.DisplayBG1) mask |= LibmGBA.Layers.BG1;
|
||||
if (o.DisplayBG2) mask |= LibmGBA.Layers.BG2;
|
||||
if (o.DisplayBG3) mask |= LibmGBA.Layers.BG3;
|
||||
if (o.DisplayOBJ) mask |= LibmGBA.Layers.OBJ;
|
||||
LibmGBA.BizSetLayerMask(_core, mask);
|
||||
|
||||
LibmGBA.Sounds smask = 0;
|
||||
if (o.PlayCh0) smask |= LibmGBA.Sounds.CH0;
|
||||
if (o.PlayCh1) smask |= LibmGBA.Sounds.CH1;
|
||||
if (o.PlayCh2) smask |= LibmGBA.Sounds.CH2;
|
||||
if (o.PlayCh3) smask |= LibmGBA.Sounds.CH3;
|
||||
if (o.PlayChA) smask |= LibmGBA.Sounds.CHA;
|
||||
if (o.PlayChB) smask |= LibmGBA.Sounds.CHB;
|
||||
LibmGBA.BizSetSoundMask(_core, smask);
|
||||
|
||||
_settings = o;
|
||||
return false;
|
||||
}
|
||||
|
||||
private Settings _settings;
|
||||
|
||||
public class Settings
|
||||
{
|
||||
[DisplayName("Display BG Layer 0")]
|
||||
[DefaultValue(true)]
|
||||
public bool DisplayBG0 { get; set; }
|
||||
[DisplayName("Display BG Layer 1")]
|
||||
[DefaultValue(true)]
|
||||
public bool DisplayBG1 { get; set; }
|
||||
[DisplayName("Display BG Layer 2")]
|
||||
[DefaultValue(true)]
|
||||
public bool DisplayBG2 { get; set; }
|
||||
[DisplayName("Display BG Layer 3")]
|
||||
[DefaultValue(true)]
|
||||
public bool DisplayBG3 { get; set; }
|
||||
[DisplayName("Display Sprite Layer")]
|
||||
[DefaultValue(true)]
|
||||
public bool DisplayOBJ { get; set; }
|
||||
|
||||
[DisplayName("Play Square 1")]
|
||||
[DefaultValue(true)]
|
||||
public bool PlayCh0 { get; set; }
|
||||
[DisplayName("Play Square 2")]
|
||||
[DefaultValue(true)]
|
||||
public bool PlayCh1 { get; set; }
|
||||
[DisplayName("Play Wave")]
|
||||
[DefaultValue(true)]
|
||||
public bool PlayCh2 { get; set; }
|
||||
[DisplayName("Play Noise")]
|
||||
[DefaultValue(true)]
|
||||
public bool PlayCh3 { get; set; }
|
||||
[DisplayName("Play Direct Sound A")]
|
||||
[DefaultValue(true)]
|
||||
public bool PlayChA { get; set; }
|
||||
[DisplayName("Play Direct Sound B")]
|
||||
[DefaultValue(true)]
|
||||
public bool PlayChB { get; set; }
|
||||
|
||||
public Settings Clone()
|
||||
{
|
||||
return (Settings)MemberwiseClone();
|
||||
}
|
||||
|
||||
public Settings()
|
||||
{
|
||||
SettingsUtil.SetDefaultValues(this);
|
||||
}
|
||||
}
|
||||
|
||||
public SyncSettings GetSyncSettings()
|
||||
{
|
||||
return _syncSettings.Clone();
|
||||
}
|
||||
|
||||
public bool PutSyncSettings(SyncSettings o)
|
||||
{
|
||||
bool ret = SyncSettings.NeedsReboot(o, _syncSettings);
|
||||
_syncSettings = o;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private SyncSettings _syncSettings;
|
||||
|
||||
public class SyncSettings
|
||||
{
|
||||
[DisplayName("Skip BIOS")]
|
||||
[Description("Skips the BIOS intro. Not applicable when a BIOS is not provided.")]
|
||||
[DefaultValue(true)]
|
||||
public bool SkipBios { get; set; }
|
||||
|
||||
[DisplayName("RTC Use Real Time")]
|
||||
[Description("Causes the internal clock to reflect your system clock. Only relevant when a game has an RTC chip. Forced to false for movie recording.")]
|
||||
[DefaultValue(true)]
|
||||
public bool RTCUseRealTime { get; set; }
|
||||
|
||||
[DisplayName("RTC Initial Time")]
|
||||
[Description("The initial time of emulation. Only relevant when a game has an RTC chip and \"RTC Use Real Time\" is false.")]
|
||||
[DefaultValue(typeof(DateTime), "2010-01-01")]
|
||||
public DateTime RTCInitialTime { get; set; }
|
||||
|
||||
public SyncSettings()
|
||||
{
|
||||
SettingsUtil.SetDefaultValues(this);
|
||||
}
|
||||
|
||||
public static bool NeedsReboot(SyncSettings x, SyncSettings y)
|
||||
{
|
||||
return !DeepEquality.DeepEquals(x, y);
|
||||
}
|
||||
|
||||
public SyncSettings Clone()
|
||||
{
|
||||
return (SyncSettings)MemberwiseClone();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDebuggable
|
||||
|
||||
public IMemoryCallbackSystem MemoryCallbacks
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public int TotalExecutedCycles
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly string[] RegisterNames =
|
||||
{
|
||||
"R0",
|
||||
"R1",
|
||||
"R2",
|
||||
"R3",
|
||||
"R4",
|
||||
"R5",
|
||||
"R6",
|
||||
"R7",
|
||||
"R8",
|
||||
"R9",
|
||||
"R10",
|
||||
"R11",
|
||||
"R12",
|
||||
"R13",
|
||||
"R14",
|
||||
"R15",
|
||||
"CPSR",
|
||||
"SPSR"
|
||||
};
|
||||
|
||||
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
|
||||
{
|
||||
var values = new int[RegisterNames.Length];
|
||||
LibmGBA.BizGetRegisters(_core, values);
|
||||
var ret = new Dictionary<string, RegisterValue>();
|
||||
for (var i = 0; i < RegisterNames.Length; i++)
|
||||
{
|
||||
ret[RegisterNames[i]] = new RegisterValue(values[i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void SetCpuRegister(string register, int value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool CanStep(StepType type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Step(StepType type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IO/@EntryIndexedValue">IO</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IPS/@EntryIndexedValue">IPS</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IRQ/@EntryIndexedValue">IRQ</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MGBA/@EntryIndexedValue">MGBA</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=NES/@EntryIndexedValue">NES</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=NMI/@EntryIndexedValue">NMI</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OBJ/@EntryIndexedValue">OBJ</s:String>
|
||||
|
|
Loading…
Reference in New Issue