hook up clear NAND flag and dsiware saveram support
do various cleanups enforce clear NAND flag for movie recording and retroachievements hardcore mode
This commit is contained in:
parent
8ce2aac868
commit
6284c98d72
|
@ -5,6 +5,7 @@ using System.Linq;
|
|||
using BizHawk.Client.Common;
|
||||
using BizHawk.Emulation.Cores.Atari.Atari2600;
|
||||
using BizHawk.Emulation.Cores.Computers.MSX;
|
||||
using BizHawk.Emulation.Cores.Consoles.Nintendo.NDS;
|
||||
using BizHawk.Emulation.Cores.Consoles.O2Hawk;
|
||||
using BizHawk.Emulation.Cores.Consoles.Sega.gpgx;
|
||||
using BizHawk.Emulation.Cores.Nintendo.BSNES;
|
||||
|
@ -136,6 +137,15 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
break;
|
||||
}
|
||||
case NDS { IsDSi: true } nds:
|
||||
{
|
||||
var ss = nds.GetSyncSettings();
|
||||
if (!ss.ClearNAND)
|
||||
{
|
||||
HandleHardcoreModeDisable("Disabling DSi NAND clear in hardcore mode is not allowed.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (CoreGraphicsLayers.TryGetValue(Emu.GetType(), out var layers))
|
||||
{
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
USE_REAL_BIOS = 0x01,
|
||||
SKIP_FIRMWARE = 0x02,
|
||||
GBA_CART_PRESENT = 0x04,
|
||||
RESERVED_FLAG = 0x08,
|
||||
CLEAR_NAND = 0x08,
|
||||
FIRMWARE_OVERRIDE = 0x10,
|
||||
IS_DSI = 0x20,
|
||||
LOAD_DSIWARE = 0x40,
|
||||
|
@ -98,6 +98,15 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
[BizImport(CC)]
|
||||
public abstract bool SaveRamIsDirty();
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void ImportDSiWareSavs(uint titleId);
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void ExportDSiWareSavs(uint titleId);
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void DSiWareSavsLength(uint titleId, out int publicSavSize, out int privateSavSize, out int bannerSavSize);
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void GetRegs(uint[] regs);
|
||||
|
||||
|
|
|
@ -5,18 +5,18 @@ using BizHawk.Emulation.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
||||
{
|
||||
partial class NDS : IDebuggable
|
||||
public partial class NDS : IDebuggable
|
||||
{
|
||||
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
|
||||
{
|
||||
uint[] regs = new uint[2 * 16];
|
||||
var regs = new uint[2 * 16];
|
||||
_core.GetRegs(regs);
|
||||
|
||||
var ret = new Dictionary<string, RegisterValue>();
|
||||
for (int i = 0; i < 2; i++)
|
||||
for (var i = 0; i < 2; i++)
|
||||
{
|
||||
int ncpu = i == 0 ? 9 : 7;
|
||||
for (int j = 0; j < 16; j++)
|
||||
var ncpu = i == 0 ? 9 : 7;
|
||||
for (var j = 0; j < 16; j++)
|
||||
{
|
||||
ret["ARM" + ncpu + " r" + j] = regs[i * 16 + j];
|
||||
}
|
||||
|
@ -30,13 +30,13 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
{
|
||||
throw new InvalidOperationException("Wrong String Length???");
|
||||
}
|
||||
int ncpu = int.Parse(register.Substring(3, 1));
|
||||
if (ncpu != 9 && ncpu != 7)
|
||||
var ncpu = int.Parse(register.Substring(3, 1));
|
||||
if (ncpu is not (9 or 7))
|
||||
{
|
||||
throw new InvalidOperationException("Invalid CPU???");
|
||||
}
|
||||
int index = int.Parse(register.Substring(6, register.Length - 6));
|
||||
if (index < 0 || index > 15)
|
||||
var index = int.Parse(register.Substring(6, register.Length - 6));
|
||||
if (index is < 0 or > 15)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid Reg Index???");
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
LibMelonDS.MemoryCallback CreateCallback(MemoryCallbackFlags flags, Func<bool> getHasCBOfType)
|
||||
{
|
||||
var rawFlags = (uint)flags;
|
||||
return (address) =>
|
||||
return address =>
|
||||
{
|
||||
if (getHasCBOfType())
|
||||
{
|
||||
|
|
|
@ -1,28 +1,68 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
||||
{
|
||||
partial class NDS : ISaveRam
|
||||
public partial class NDS : ISaveRam
|
||||
{
|
||||
public new bool SaveRamModified => _core.SaveRamIsDirty();
|
||||
public new bool SaveRamModified => IsDSiWare || _core.SaveRamIsDirty();
|
||||
|
||||
public new byte[] CloneSaveRam()
|
||||
{
|
||||
int length = _core.GetSaveRamLength();
|
||||
if (IsDSiWare)
|
||||
{
|
||||
_core.DSiWareSavsLength(DSiTitleId.Lower, out var publicSavSize, out var privateSavSize, out var bannerSavSize);
|
||||
if (publicSavSize + privateSavSize + bannerSavSize == 0) return null;
|
||||
_exe.AddTransientFile(Array.Empty<byte>(), "public.sav");
|
||||
_exe.AddTransientFile(Array.Empty<byte>(), "private.sav");
|
||||
_exe.AddTransientFile(Array.Empty<byte>(), "banner.sav");
|
||||
_core.ExportDSiWareSavs(DSiTitleId.Lower);
|
||||
var publicSav = _exe.RemoveTransientFile("public.sav");
|
||||
var privateSav = _exe.RemoveTransientFile("private.sav");
|
||||
var bannerSav = _exe.RemoveTransientFile("banner.sav");
|
||||
if (publicSav.Length != publicSavSize || privateSav.Length != privateSavSize ||
|
||||
bannerSav.Length != bannerSavSize)
|
||||
{
|
||||
throw new InvalidOperationException("Unexpected size difference in DSiWare sav files!");
|
||||
}
|
||||
var ret = new byte[publicSavSize + privateSavSize + bannerSavSize];
|
||||
publicSav.AsSpan().CopyTo(ret.AsSpan().Slice(0, publicSavSize));
|
||||
privateSav.AsSpan().CopyTo(ret.AsSpan().Slice(publicSavSize, privateSavSize));
|
||||
bannerSav.AsSpan().CopyTo(ret.AsSpan().Slice(publicSavSize + privateSavSize, bannerSavSize));
|
||||
return ret;
|
||||
}
|
||||
|
||||
var length = _core.GetSaveRamLength();
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
byte[] ret = new byte[length];
|
||||
var ret = new byte[length];
|
||||
_core.GetSaveRam(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return new byte[0];
|
||||
return null;
|
||||
}
|
||||
|
||||
public new void StoreSaveRam(byte[] data)
|
||||
{
|
||||
if (data.Length > 0)
|
||||
if (IsDSiWare)
|
||||
{
|
||||
_core.DSiWareSavsLength(DSiTitleId.Lower, out var publicSavSize, out var privateSavSize, out var bannerSavSize);
|
||||
if (data.Length == publicSavSize + privateSavSize + bannerSavSize)
|
||||
{
|
||||
if (publicSavSize > 0) _exe.AddReadonlyFile(data.AsSpan().Slice(0, publicSavSize).ToArray(), "public.sav");
|
||||
if (privateSavSize > 0) _exe.AddReadonlyFile(data.AsSpan().Slice(publicSavSize, privateSavSize).ToArray(), "private.sav");
|
||||
if (bannerSavSize > 0) _exe.AddReadonlyFile(data.AsSpan().Slice(publicSavSize + privateSavSize, bannerSavSize).ToArray(), "banner.sav");
|
||||
_core.ImportDSiWareSavs(DSiTitleId.Lower);
|
||||
if (publicSavSize > 0) _exe.RemoveReadonlyFile("public.sav");
|
||||
if (privateSavSize > 0) _exe.RemoveReadonlyFile("private.sav");
|
||||
if (bannerSavSize > 0) _exe.RemoveReadonlyFile("banner.sav");
|
||||
}
|
||||
}
|
||||
else if (data.Length > 0)
|
||||
{
|
||||
_core.PutSaveRam(data, (uint)data.Length);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ using Newtonsoft.Json;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
||||
{
|
||||
partial class NDS : ISettable<NDS.NDSSettings, NDS.NDSSyncSettings>
|
||||
public partial class NDS : ISettable<NDS.NDSSettings, NDS.NDSSyncSettings>
|
||||
{
|
||||
private NDSSettings _settings;
|
||||
private NDSSyncSettings _syncSettings;
|
||||
|
@ -153,7 +153,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
public bool UseRealTime { get; set; }
|
||||
|
||||
[DisplayName("DSi Mode")]
|
||||
[Description("If true, DSi mode will be used.")]
|
||||
[Description("If true, DSi mode will be used. Forced true if a DSiWare rom is detected.")]
|
||||
[DefaultValue(false)]
|
||||
public bool UseDSi { get; set; }
|
||||
|
||||
|
@ -169,9 +169,14 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
|
||||
[DisplayName("Firmware Override")]
|
||||
[Description("If true, the firmware settings will be overriden by provided settings. Forced true when recording a movie.")]
|
||||
[DefaultValue(false)]
|
||||
[DefaultValue(true)]
|
||||
public bool FirmwareOverride { get; set; }
|
||||
|
||||
[DisplayName("Clear NAND")]
|
||||
[Description("If true, the DSi NAND will have all its titles cleared. Forced true when recording a movie.")]
|
||||
[DefaultValue(true)]
|
||||
public bool ClearNAND { get; set; }
|
||||
|
||||
public enum StartUp : int
|
||||
{
|
||||
[Display(Name = "Auto Boot")]
|
||||
|
|
|
@ -5,14 +5,14 @@ using BizHawk.Emulation.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
||||
{
|
||||
partial class NDS
|
||||
public partial class NDS
|
||||
{
|
||||
private ITraceable Tracer { get; }
|
||||
private readonly LibMelonDS.TraceCallback _tracecb;
|
||||
|
||||
private unsafe void MakeTrace(LibMelonDS.TraceMask type, uint opcode, IntPtr r, IntPtr disasm, uint cyclesOff)
|
||||
{
|
||||
string cpu = type switch
|
||||
var cpu = type switch
|
||||
{
|
||||
LibMelonDS.TraceMask.ARM7_THUMB => "ARM7 (Thumb)",
|
||||
LibMelonDS.TraceMask.ARM7_ARM => "ARM7",
|
||||
|
@ -21,33 +21,16 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
_ => throw new InvalidOperationException("Invalid CPU Mode???"),
|
||||
};
|
||||
|
||||
uint* regs = (uint*)r;
|
||||
var regs = (uint*)r;
|
||||
|
||||
bool isthumb = type is LibMelonDS.TraceMask.ARM7_THUMB or LibMelonDS.TraceMask.ARM9_THUMB;
|
||||
uint opaddr = regs[15] - (isthumb ? 4u : 8u); // handle prefetch
|
||||
var isthumb = type is LibMelonDS.TraceMask.ARM7_THUMB or LibMelonDS.TraceMask.ARM9_THUMB;
|
||||
var opaddr = regs![15] - (isthumb ? 4u : 8u); // handle prefetch
|
||||
|
||||
Tracer.Put(new(
|
||||
disassembly: string.Format("{0:x8}: {1:x8} ", opaddr, opcode).PadRight(12) + Marshal.PtrToStringAnsi(disasm).PadRight(36),
|
||||
registerInfo: string.Format(
|
||||
"r0:{0:x8} r1:{1:x8} r2:{2:x8} r3:{3:x8} r4:{4:x8} r5:{5:x8} r6:{6:x8} r7:{7:x8} r8:{8:x8} r9:{9:x8} r10:{10:x8} r11:{11:x8} r12:{12:x8} SP:{13:x8} LR:{14:x8} PC:{15:x8} Cy:{16} {17}",
|
||||
regs[0],
|
||||
regs[1],
|
||||
regs[2],
|
||||
regs[3],
|
||||
regs[4],
|
||||
regs[5],
|
||||
regs[6],
|
||||
regs[7],
|
||||
regs[8],
|
||||
regs[9],
|
||||
regs[10],
|
||||
regs[11],
|
||||
regs[12],
|
||||
regs[13],
|
||||
regs[14],
|
||||
regs[15],
|
||||
CycleCount + cyclesOff,
|
||||
cpu)));
|
||||
disassembly: $"{opaddr:x8}: {opcode:x8} ".PadRight(12) + Marshal.PtrToStringAnsi(disasm)!.PadRight(36),
|
||||
registerInfo: $"r0:{regs[0]:x8} r1:{regs[1]:x8} r2:{regs[2]:x8} r3:{regs[3]:x8} r4:{regs[4]:x8} r5:{regs[5]:x8} " +
|
||||
$"r6:{regs[6]:x8} r7:{regs[7]:x8} r8:{regs[8]:x8} r9:{regs[9]:x8} r10:{regs[10]:x8} r11:{regs[11]:x8} " +
|
||||
$"r12:{regs[12]:x8} SP:{regs[13]:x8} LR:{regs[14]:x8} PC:{regs[15]:x8} Cy:{CycleCount + cyclesOff} {cpu}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ using BizHawk.Emulation.Cores.Waterbox;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
||||
{
|
||||
[PortedCore(CoreNames.MelonDS, "Arisotura", "0.9.4", "http://melonds.kuribo64.net/")]
|
||||
[PortedCore(CoreNames.MelonDS, "Arisotura", "0.9.5", "https://melonds.kuribo64.net/")]
|
||||
[ServiceNotApplicable(new[] { typeof(IDriveLight), typeof(IRegionable) })]
|
||||
public partial class NDS : WaterboxCore
|
||||
{
|
||||
|
@ -22,7 +22,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
|
||||
[CoreConstructor(VSystemID.Raw.NDS)]
|
||||
public NDS(CoreLoadParameters<NDSSettings, NDSSyncSettings> lp)
|
||||
: base(lp.Comm, new Configuration
|
||||
: base(lp.Comm, new()
|
||||
{
|
||||
DefaultWidth = 256,
|
||||
DefaultHeight = 384,
|
||||
|
@ -34,28 +34,29 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
SystemId = VSystemID.Raw.NDS,
|
||||
})
|
||||
{
|
||||
_syncSettings = lp.SyncSettings ?? new NDSSyncSettings();
|
||||
_settings = lp.Settings ?? new NDSSettings();
|
||||
_syncSettings = lp.SyncSettings ?? new();
|
||||
_settings = lp.Settings ?? new();
|
||||
|
||||
IsDSi = _syncSettings.UseDSi;
|
||||
|
||||
var roms = lp.Roms.Select(r => r.RomData).ToList();
|
||||
|
||||
DSiTitleId = GetDSiTitleId(roms[0]);
|
||||
IsDSi |= IsDSiWare;
|
||||
|
||||
if (roms.Count > (IsDSi ? 1 : 3))
|
||||
{
|
||||
throw new InvalidOperationException("Wrong number of ROMs!");
|
||||
}
|
||||
|
||||
IsDSiWare = IsDSi && RomIsWare(roms[0]);
|
||||
|
||||
bool gbacartpresent = roms.Count > 1;
|
||||
bool gbasrampresent = roms.Count == 3;
|
||||
var gbacartpresent = roms.Count > 1;
|
||||
var gbasrampresent = roms.Count == 3;
|
||||
|
||||
InitMemoryCallbacks();
|
||||
_tracecb = MakeTrace;
|
||||
_threadstartcb = ThreadStartCallback;
|
||||
|
||||
_core = PreInit<LibMelonDS>(new WaterboxOptions
|
||||
_core = PreInit<LibMelonDS>(new()
|
||||
{
|
||||
Filename = "melonDS.wbx",
|
||||
SbrkHeapSizeKB = 2 * 1024,
|
||||
|
@ -91,13 +92,13 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
? CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("NDS", "firmwarei"))
|
||||
: CoreComm.CoreFileProvider.GetFirmware(new("NDS", "firmware"));
|
||||
|
||||
var tmd = IsDSi && IsDSiWare
|
||||
? GetTMDData(roms[0])
|
||||
var tmd = IsDSiWare
|
||||
? GetTMDData(DSiTitleId.Full)
|
||||
: null;
|
||||
|
||||
bool skipfw = _syncSettings.SkipFirmware || !_syncSettings.UseRealBIOS || fw == null;
|
||||
var skipfw = _syncSettings.SkipFirmware || !_syncSettings.UseRealBIOS || fw == null;
|
||||
|
||||
LibMelonDS.LoadFlags loadFlags = LibMelonDS.LoadFlags.NONE;
|
||||
var loadFlags = LibMelonDS.LoadFlags.NONE;
|
||||
|
||||
if (_syncSettings.UseRealBIOS || IsDSi)
|
||||
loadFlags |= LibMelonDS.LoadFlags.USE_REAL_BIOS;
|
||||
|
@ -105,11 +106,13 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
loadFlags |= LibMelonDS.LoadFlags.SKIP_FIRMWARE;
|
||||
if (gbacartpresent)
|
||||
loadFlags |= LibMelonDS.LoadFlags.GBA_CART_PRESENT;
|
||||
if (IsDSi && (_syncSettings.ClearNAND || lp.DeterministicEmulationRequested))
|
||||
loadFlags |= LibMelonDS.LoadFlags.CLEAR_NAND; // TODO: need a way to send through multiple DSiWare titles at once for this approach
|
||||
if (fw is null || _syncSettings.FirmwareOverride || lp.DeterministicEmulationRequested)
|
||||
loadFlags |= LibMelonDS.LoadFlags.FIRMWARE_OVERRIDE;
|
||||
if (IsDSi)
|
||||
loadFlags |= LibMelonDS.LoadFlags.IS_DSI;
|
||||
if (IsDSi && IsDSiWare)
|
||||
if (IsDSiWare)
|
||||
loadFlags |= LibMelonDS.LoadFlags.LOAD_DSIWARE;
|
||||
if (_syncSettings.ThreadedRendering)
|
||||
loadFlags |= LibMelonDS.LoadFlags.THREADED_RENDERING;
|
||||
|
@ -122,7 +125,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
fwSettings.FirmwareBirthdayMonth = _syncSettings.FirmwareBirthdayMonth;
|
||||
fwSettings.FirmwareBirthdayDay = _syncSettings.FirmwareBirthdayDay;
|
||||
fwSettings.FirmwareFavouriteColour = _syncSettings.FirmwareFavouriteColour;
|
||||
var message = _syncSettings.FirmwareMessage.Length != 0 ? Encoding.UTF8.GetBytes(_syncSettings.FirmwareMessage) : new byte[1] { 0 };
|
||||
var message = _syncSettings.FirmwareMessage.Length != 0 ? Encoding.UTF8.GetBytes(_syncSettings.FirmwareMessage) : new byte[1];
|
||||
fwSettings.FirmwareMessageLength = message.Length;
|
||||
|
||||
var loadData = new LibMelonDS.LoadData
|
||||
|
@ -217,27 +220,21 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
_serviceProvider.Register(Tracer);
|
||||
}
|
||||
|
||||
private static bool RomIsWare(byte[] file)
|
||||
{
|
||||
uint lowerWareTitleId = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
lowerWareTitleId <<= 8;
|
||||
lowerWareTitleId |= file[0x237 - i];
|
||||
}
|
||||
return lowerWareTitleId == 0x00030004;
|
||||
}
|
||||
|
||||
private static byte[] GetTMDData(byte[] ware)
|
||||
private static (ulong Full, uint Upper, uint Lower) GetDSiTitleId(byte[] file)
|
||||
{
|
||||
ulong titleId = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
titleId <<= 8;
|
||||
titleId |= ware[0x237 - i];
|
||||
titleId |= file[0x237 - i];
|
||||
}
|
||||
return (titleId, (uint)(titleId >> 32), (uint)(titleId & 0xFFFFFFFFU));
|
||||
}
|
||||
|
||||
private static byte[] GetTMDData(ulong titleId)
|
||||
{
|
||||
using var zip = new ZipArchive(Zstd.DecompressZstdStream(new MemoryStream(Resources.TMDS.Value)), ZipArchiveMode.Read, false);
|
||||
using var tmd = zip.GetEntry($"{titleId:x16}.tmd")?.Open() ?? throw new Exception($"Cannot find TMD for title ID {titleId:x16}, please report");
|
||||
using var tmd = zip.GetEntry($"{titleId:x16}.tmd")?.Open() ?? throw new($"Cannot find TMD for title ID {titleId:x16}, please report");
|
||||
var ret = new byte[tmd.Length];
|
||||
tmd.Read(ret, 0, (int)tmd.Length);
|
||||
return ret;
|
||||
|
@ -246,7 +243,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
// todo: wire this up w/ frontend
|
||||
public byte[] GetNAND()
|
||||
{
|
||||
int length = _core.GetNANDSize();
|
||||
var length = _core.GetNANDSize();
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
|
@ -255,12 +252,14 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
return ret;
|
||||
}
|
||||
|
||||
return new byte[0];
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool IsDSi { get; }
|
||||
|
||||
public bool IsDSiWare { get; }
|
||||
public bool IsDSiWare => DSiTitleId.Upper == 0x00030004;
|
||||
|
||||
private (ulong Full, uint Upper, uint Lower) DSiTitleId { get; }
|
||||
|
||||
public override ControllerDefinition ControllerDefinition => NDSController;
|
||||
|
||||
|
@ -275,7 +274,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
.AddAxis("GBA Light Sensor", 0.RangeTo(10), 0)
|
||||
.MakeImmutable();
|
||||
|
||||
private LibMelonDS.Buttons GetButtons(IController c)
|
||||
private static LibMelonDS.Buttons GetButtons(IController c)
|
||||
{
|
||||
LibMelonDS.Buttons b = 0;
|
||||
if (c.IsPressed("Up"))
|
||||
|
|
|
@ -43,14 +43,14 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
if (Cpu.Length == 14)
|
||||
{
|
||||
addr &= ~1u;
|
||||
uint op = m.PeekByte(addr) | (uint)m.PeekByte(addr + 1) << 8;
|
||||
var op = m.PeekByte(addr) | (uint)m.PeekByte(addr + 1) << 8;
|
||||
_core.GetDisassembly(type, op, ret);
|
||||
length = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr &= ~3u;
|
||||
uint op = m.PeekByte(addr)
|
||||
var op = m.PeekByte(addr)
|
||||
| (uint)m.PeekByte(addr + 1) << 8
|
||||
| (uint)m.PeekByte(addr + 2) << 16
|
||||
| (uint)m.PeekByte(addr + 3) << 24;
|
||||
|
|
|
@ -21,8 +21,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
comm.ShowMessage("Hacked firmware detected! Firmware might not work!");
|
||||
return false;
|
||||
}
|
||||
int fwMask = fw.Length - 1;
|
||||
string badCrc16s = "";
|
||||
var fwMask = fw.Length - 1;
|
||||
var badCrc16s = string.Empty;
|
||||
if (!VerifyCrc16(fw, 0x2C, (fw[0x2C + 1] << 8) | fw[0x2C], 0x0000, 0x2A))
|
||||
{
|
||||
badCrc16s += " Wifi ";
|
||||
|
@ -58,12 +58,12 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
|
||||
public static void SanitizeFw(byte[] fw)
|
||||
{
|
||||
int fwMask = fw.Length - 1;
|
||||
int[] apstart = new int[3] { 0x07FA00 & fwMask, 0x07FB00 & fwMask, 0x07FC00 & fwMask };
|
||||
var fwMask = fw.Length - 1;
|
||||
var apstart = new int[3] { 0x07FA00 & fwMask, 0x07FB00 & fwMask, 0x07FC00 & fwMask };
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
for (int j = 0; j < 0x100; j++)
|
||||
for (var j = 0; j < 0x100; j++)
|
||||
{
|
||||
fw[apstart[i] + j] = 0;
|
||||
}
|
||||
|
@ -78,21 +78,21 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
// F8 98 C1 E6 CC 5D 92 E1 85 8C 96
|
||||
// different mac address
|
||||
// 18 90 15 E9 7C 1D F1 E1 85 74 02
|
||||
byte[] macdependentbytes = new byte[11] { 0xF8, 0x98, 0xC1, 0xE6, 0xCC, 0x9D, 0xBE, 0xE1, 0x85, 0x71, 0x5F };
|
||||
var macdependentbytes = new byte[11] { 0xF8, 0x98, 0xC1, 0xE6, 0xCC, 0x9D, 0xBE, 0xE1, 0x85, 0x71, 0x5F };
|
||||
|
||||
int apoffset = 0xF5;
|
||||
var apoffset = 0xF5;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
for (var i = 0; i < 2; i++)
|
||||
{
|
||||
for (int j = 0; j < 11; j++)
|
||||
for (var j = 0; j < 11; j++)
|
||||
{
|
||||
fw[apstart[i] + apoffset + j] = macdependentbytes[j];
|
||||
}
|
||||
}
|
||||
|
||||
int ffoffset = 0xE7;
|
||||
var ffoffset = 0xE7;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
fw[apstart[i] + ffoffset] = 0xFF;
|
||||
}
|
||||
|
@ -101,9 +101,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
fw[apstart[2] + 0xFE] = 0x0A;
|
||||
fw[apstart[2] + 0xFF] = 0xF0;
|
||||
|
||||
int[] usersettings = new int[2] { 0x7FE00 & fwMask, 0x7FF00 & fwMask };
|
||||
var usersettings = new int[2] { 0x7FE00 & fwMask, 0x7FF00 & fwMask };
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
for (var i = 0; i < 2; i++)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
|
@ -136,11 +136,11 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
{
|
||||
var poly = new ushort[8] { 0xC0C1, 0xC181, 0xC301, 0xC601, 0xCC01, 0xD801, 0xF001, 0xA001 };
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
for (var i = 0; i < len; i++)
|
||||
{
|
||||
seed ^= data[i];
|
||||
|
||||
for (int j = 0; j < 8; j++)
|
||||
for (var j = 0; j < 8; j++)
|
||||
{
|
||||
if ((seed & 0x1) != 0)
|
||||
{
|
||||
|
@ -159,10 +159,10 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
|
||||
private static unsafe bool VerifyCrc16(byte[] fw, int startaddr, int len, int seed, int crcaddr)
|
||||
{
|
||||
ushort storedCrc16 = (ushort)((fw[crcaddr + 1] << 8) | fw[crcaddr]);
|
||||
var storedCrc16 = (ushort)((fw[crcaddr + 1] << 8) | fw[crcaddr]);
|
||||
fixed (byte* start = &fw[startaddr])
|
||||
{
|
||||
ushort actualCrc16 = Crc16(start, len, seed);
|
||||
var actualCrc16 = Crc16(start, len, seed);
|
||||
return storedCrc16 == actualCrc16;
|
||||
}
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
[DllImport("libfwunpack", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void FreeDecryptedFirmware(IntPtr decryptedFw);
|
||||
|
||||
private static string[] goodhashes = new string[]
|
||||
private static readonly string[] goodhashes =
|
||||
{
|
||||
"D83861C66796665A9777B4E9078E9CC8EB13D880", // MACP nds (one of v1-v4), supposedly the most common
|
||||
"F87038265D24677419FE0AF9EED63B4CE1378CC9", // MACg nds (v5)
|
||||
|
@ -182,23 +182,22 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
|
|||
|
||||
private static bool CheckDecryptedCodeChecksum(byte[] fw, CoreComm comm)
|
||||
{
|
||||
if (!GetDecryptedFirmware(fw, fw.Length, out IntPtr decryptedfw, out int decrypedfwlen))
|
||||
if (!GetDecryptedFirmware(fw, fw.Length, out var decryptedfw, out var decrypedfwlen))
|
||||
{
|
||||
comm.ShowMessage("Firmware could not be decryped for verification! This firmware might be not work!");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
||||
var DecryptedFirmware = new byte[decrypedfwlen];
|
||||
Marshal.Copy(decryptedfw, DecryptedFirmware, 0, decrypedfwlen);
|
||||
FreeDecryptedFirmware(decryptedfw);
|
||||
var hash = SHA1Checksum.ComputeDigestHex(DecryptedFirmware);
|
||||
if (hash != goodhashes[0] && hash != goodhashes[1] && hash != goodhashes[2])
|
||||
{
|
||||
byte[] DecryptedFirmware = new byte[decrypedfwlen];
|
||||
Marshal.Copy(decryptedfw, DecryptedFirmware, 0, decrypedfwlen);
|
||||
FreeDecryptedFirmware(decryptedfw);
|
||||
var hash = SHA1Checksum.ComputeDigestHex(DecryptedFirmware);
|
||||
if (hash != goodhashes[0] && hash != goodhashes[1] && hash != goodhashes[2])
|
||||
{
|
||||
comm.ShowMessage("Potentially bad firmware dump! Decrypted hash " + hash + " does not match known good dumps.");
|
||||
return false;
|
||||
}
|
||||
comm.ShowMessage("Potentially bad firmware dump! Decrypted hash " + hash + " does not match known good dumps.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue