Melon Cleanups & Updates & Prep For Multithread Rendering Support & Prep For DSi NAND bs (#3174)

* prep for handling multi-threaded renderer in melon, along with some other cleanups

* initial core side support for mt rendering, probably crashes?

* oops

* ok use ref not in

* testing

* poor man's semaphore

* clean this up, hopefully fix a deadlock?

* update submodule

* reduce submodule diff

* cleanup

* hook up thread wait cb

* maybe make shutdown not hardlock?

* oops

* oops

* testing

* testing

* a

* lol

* fuck

* a

* oops

* a

* a

* a

* a

* a

* a

* a

* a

* a

* if false this

* a

* a

* a

* bleh

* a

* update to upstream

* oh right lua
This commit is contained in:
CasualPokePlayer 2022-03-06 00:43:30 -08:00 committed by GitHub
parent 9411e659bb
commit 46c2d6faf1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 304 additions and 176 deletions

Binary file not shown.

View File

@ -41,10 +41,10 @@ namespace BizHawk.Client.Common
public int GetScreenGap()
=> Settings.ScreenGap;
[LuaMethodExample("if ( nds.getaccurateaudiobitrate( ) ) then\r\n\tconsole.log( \"Returns whether the audio bitrate is set to accurate mode\" );\r\nend;")]
[LuaMethod("getaccurateaudiobitrate", "Returns whether the audio bitrate is in accurate mode")]
public bool GetAccurateAudioBitrate()
=> Settings.AccurateAudioBitrate;
[LuaMethodExample("if ( nds.getaudiobitrate( ) ) then\r\n\tconsole.log( \"Returns the audio bitrate setting\" );\r\nend;")]
[LuaMethod("getaudiobitrate", "Returns the audio bitrate setting")]
public string GetAudioBitrate()
=> Settings.AudioBitrate.ToString();
[LuaMethodExample("nds.setscreenlayout( \"Vertical\" );")]
[LuaMethod("setscreenlayout", "Sets which screen layout is active")]
@ -82,12 +82,12 @@ namespace BizHawk.Client.Common
Settings = s;
}
[LuaMethodExample("nds.setaccurateaudiobitrate( true );")]
[LuaMethod("setaccurateaudiobitrate", "Sets whether the audio bitrate is in accurate mode")]
public void SetAccurateAudioBitrate(bool value)
[LuaMethodExample("nds.setaudiobitrate( \"Auto\" );")]
[LuaMethod("setaudiobitrate", "Sets the audio bitrate setting")]
public void SetAudioBitrate(string value)
{
var s = Settings;
s.AccurateAudioBitrate = value;
s.AudioBitrate = (NDS.NDSSettings.AudioBitrateType)Enum.Parse(typeof(NDS.NDSSettings.AudioBitrateType), value, true);
Settings = s;
}
}

View File

@ -47,14 +47,15 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
USE_REAL_BIOS = 0x01,
SKIP_FIRMWARE = 0x02,
GBA_CART_PRESENT = 0x04,
ACCURATE_AUDIO_BITRATE = 0x08,
RESERVED_FLAG = 0x08,
FIRMWARE_OVERRIDE = 0x10,
IS_DSI = 0x20,
LOAD_DSIWARE = 0x40,
THREADED_RENDERING = 0x80,
}
[StructLayout(LayoutKind.Sequential)]
public class LoadData
public struct LoadData
{
public IntPtr DsRomData;
public int DsRomLength;
@ -65,10 +66,11 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
public IntPtr NandData;
public int NandLength;
public IntPtr TmdData;
public NDS.NDSSettings.AudioBitrateType AudioBitrate;
}
[StructLayout(LayoutKind.Sequential)]
public class FirmwareSettings
public struct FirmwareSettings
{
public IntPtr FirmwareUsername; // max 10 length (then terminator)
public int FirmwareUsernameLength;
@ -81,7 +83,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
}
[BizImport(CC)]
public abstract bool Init(LoadFlags flags, LoadData loadData, FirmwareSettings fwSettings);
public abstract bool Init(LoadFlags loadFlags, ref LoadData loadData, ref FirmwareSettings fwSettings);
[BizImport(CC)]
public abstract void PutSaveRam(byte[] data, uint len);
@ -125,5 +127,20 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
[BizImport(CC)]
public abstract void SetTraceCallback(TraceCallback callback);
[BizImport(CC)]
public abstract IntPtr GetFrameThreadProc();
[UnmanagedFunctionPointer(CC)]
public delegate void ThreadWaitCallback();
[BizImport(CC)]
public abstract void SetThreadWaitCallback(ThreadWaitCallback callback);
[BizImport(CC)]
public abstract int GetNANDSize();
[BizImport(CC)]
public abstract void GetNANDData(byte[] buf);
}
}

View File

@ -32,6 +32,13 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
public class NDSSettings
{
#if false
[DisplayName("Threaded Rendering")]
[Description("")]
[DefaultValue(true)]
public bool ThreadedRendering { get; set; }
#endif
[DisplayName("Screen Layout")]
[Description("Adjusts the layout of the screens")]
[DefaultValue(ScreenLayoutKind.Vertical)]
@ -59,10 +66,17 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
set => _screengap = Math.Max(0, Math.Min(128, value));
}
[DisplayName("Accurate Audio Bitrate")]
[Description("If true, the audio bitrate will be set to 10. Otherwise, it will be set to 16.")]
[DefaultValue(true)]
public bool AccurateAudioBitrate { get; set; }
public enum AudioBitrateType : int
{
Auto,
Ten,
Sixteen,
}
[DisplayName("Audio Bitrate")]
[Description("Auto will set the audio bitrate most accurate to the console (10 for DS, 16 for DSi).")]
[DefaultValue(AudioBitrateType.Auto)]
public AudioBitrateType AudioBitrate { get; set; }
public NDSSettings Clone() => MemberwiseClone() as NDSSettings;

View File

@ -3,7 +3,9 @@ using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BizHawk.BizInvoke;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Properties;
@ -52,6 +54,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
InitMemoryCallbacks();
_tracecb = MakeTrace;
_threadwaitcb = ThreadWaitCallback;
_core = PreInit<LibMelonDS>(new WaterboxOptions
{
@ -63,7 +66,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
MmapHeapSizeKB = 1024 * 1024,
SkipCoreConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck),
SkipMemoryConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck),
}, new Delegate[] { _readcb, _writecb, _execcb, _tracecb });
}, new Delegate[] { _readcb, _writecb, _execcb, _tracecb, _threadwaitcb });
var bios7 = IsDSi || _syncSettings.UseRealBIOS
? CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("NDS", "bios7"))
@ -95,22 +98,24 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
bool skipfw = _syncSettings.SkipFirmware || !_syncSettings.UseRealBIOS || fw == null;
LibMelonDS.LoadFlags flags = LibMelonDS.LoadFlags.NONE;
LibMelonDS.LoadFlags loadFlags = LibMelonDS.LoadFlags.NONE;
if (_syncSettings.UseRealBIOS || IsDSi)
flags |= LibMelonDS.LoadFlags.USE_REAL_BIOS;
loadFlags |= LibMelonDS.LoadFlags.USE_REAL_BIOS;
if (skipfw && !IsDSi)
flags |= LibMelonDS.LoadFlags.SKIP_FIRMWARE;
loadFlags |= LibMelonDS.LoadFlags.SKIP_FIRMWARE;
if (gbacartpresent)
flags |= LibMelonDS.LoadFlags.GBA_CART_PRESENT;
if (_settings.AccurateAudioBitrate && !IsDSi) // todo: let users have DS audio bitrate on DSi?
flags |= LibMelonDS.LoadFlags.ACCURATE_AUDIO_BITRATE;
loadFlags |= LibMelonDS.LoadFlags.GBA_CART_PRESENT;
if (_syncSettings.FirmwareOverride || lp.DeterministicEmulationRequested)
flags |= LibMelonDS.LoadFlags.FIRMWARE_OVERRIDE;
loadFlags |= LibMelonDS.LoadFlags.FIRMWARE_OVERRIDE;
if (IsDSi)
flags |= LibMelonDS.LoadFlags.IS_DSI;
loadFlags |= LibMelonDS.LoadFlags.IS_DSI;
if (IsDSi && IsDSiWare)
flags |= LibMelonDS.LoadFlags.LOAD_DSIWARE;
loadFlags |= LibMelonDS.LoadFlags.LOAD_DSIWARE;
#if false
if (_settings.ThreadedRendering)
loadFlags |= LibMelonDS.LoadFlags.THREADED_RENDERING;
#endif
var fwSettings = new LibMelonDS.FirmwareSettings();
var name = Encoding.UTF8.GetBytes(_syncSettings.FirmwareUsername);
@ -129,6 +134,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
GbaRomLength = gbacartpresent ? roms[1].Length : 0,
GbaRamLength = gbasrampresent ? roms[2].Length : 0,
NandLength = nand?.Length ?? 0,
AudioBitrate = _settings.AudioBitrate,
};
if (_syncSettings.UseRealBIOS || IsDSi)
{
@ -174,7 +180,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
loadData.TmdData = (IntPtr)tmdPtr;
fwSettings.FirmwareUsername = (IntPtr)namePtr;
fwSettings.FirmwareMessage = (IntPtr)messagePtr;
if (!_core.Init(flags, loadData, fwSettings))
if (!_core.Init(loadFlags, ref loadData, ref fwSettings))
{
throw new InvalidOperationException("Init returned false!");
}
@ -198,6 +204,14 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
DeterministicEmulation = lp.DeterministicEmulationRequested || (!_syncSettings.UseRealTime);
InitializeRtc(_syncSettings.InitialTime);
_frameThreadPtr = _core.GetFrameThreadProc();
if (_frameThreadPtr != IntPtr.Zero)
{
Console.WriteLine($"Setting up waterbox thread for 0x{_frameThreadPtr:X16}");
_frameThreadStart = CallingConventionAdapters.GetWaterboxUnsafeUnwrapped().GetDelegateForFunctionPointer<Action>(_frameThreadPtr);
_core.SetThreadWaitCallback(_threadwaitcb);
}
_resampler = new SpeexResampler(SpeexResampler.Quality.QUALITY_DEFAULT, 32768, 44100, 32768, 44100, null, this);
_serviceProvider.Register<ISoundProvider>(_resampler);
@ -212,11 +226,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
public override void Dispose()
{
base.Dispose();
if (_resampler != null)
{
_resampler.Dispose();
_resampler = null;
}
_resampler?.Dispose();
_resampler = null;
}
private static bool RomIsWare(byte[] file)
@ -245,6 +256,21 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
return ret;
}
// todo: wire this up w/ frontend
public byte[] GetNAND()
{
int length = _core.GetNANDSize();
if (length > 0)
{
var ret = new byte[length];
_core.GetNANDData(ret);
return ret;
}
return new byte[0];
}
public bool IsDSi { get; }
public bool IsDSiWare { get; }
@ -301,11 +327,16 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
return b;
}
private bool _renderSound;
private readonly IntPtr _frameThreadPtr;
private readonly Action _frameThreadStart;
private Task _frameThreadProcActive;
protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound)
{
_renderSound = rendersound;
if (_frameThreadStart != null && render)
{
_frameThreadProcActive = Task.Run(_frameThreadStart);
}
_core.SetTraceCallback(Tracer.IsEnabled() ? _tracecb : null);
return new LibMelonDS.FrameInfo
{
@ -318,18 +349,20 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS
};
}
protected override void FrameAdvancePost()
private readonly LibMelonDS.ThreadWaitCallback _threadwaitcb;
private void ThreadWaitCallback()
{
// the core SHOULD produce 547 or 548 samples each frame
// however, it seems in some cases (first few frames on power on and lid closed) it doesn't for some reason
// hack around it here
if (_numSamples < 547 && _renderSound)
_frameThreadProcActive?.Wait();
_frameThreadProcActive = null;
}
protected override void LoadStateBinaryInternal(BinaryReader reader)
{
SetMemoryCallbacks();
if (_frameThreadPtr != _core.GetFrameThreadProc())
{
for (int i = _numSamples * 2; i < (547 * 2); i++)
{
_soundBuffer[i] = 0;
}
_numSamples = 547;
throw new InvalidOperationException("_frameThreadPtr mismatch");
}
}

View File

@ -38,10 +38,11 @@ typedef enum
USE_REAL_BIOS = 0x01,
SKIP_FIRMWARE = 0x02,
GBA_CART_PRESENT = 0x04,
ACCURATE_AUDIO_BITRATE = 0x08,
RESERVED_FLAG = 0x08,
FIRMWARE_OVERRIDE = 0x10,
IS_DSI = 0x20,
LOAD_DSIWARE = 0x40,
THREADED_RENDERING = 0x80,
} LoadFlags;
typedef struct
@ -55,6 +56,7 @@ typedef struct
char* NandData;
u32 NandLen;
u8* TmdData;
s32 AudioBitrate;
} LoadData;
typedef struct
@ -70,6 +72,7 @@ typedef struct
} FirmwareSettings;
extern std::stringstream* NANDFilePtr;
extern bool Stopped;
static bool LoadDSiWare(u8* TmdData)
{
@ -95,17 +98,18 @@ static bool LoadDSiWare(u8* TmdData)
return ret;
}
EXPORT bool Init(LoadFlags flags, LoadData* loadData, FirmwareSettings* fwSettings)
EXPORT bool Init(LoadFlags loadFlags, LoadData* loadData, FirmwareSettings* fwSettings)
{
Config::ExternalBIOSEnable = !!(flags & USE_REAL_BIOS);
Config::AudioBitrate = !!(flags & ACCURATE_AUDIO_BITRATE) ? 1 : 2;
Config::FirmwareOverrideSettings = !!(flags & FIRMWARE_OVERRIDE);
biz_skip_fw = !!(flags & SKIP_FIRMWARE);
bool isDsi = !!(flags & IS_DSI);
Config::ExternalBIOSEnable = !!(loadFlags & USE_REAL_BIOS);
Config::AudioBitrate = loadData->AudioBitrate;
Config::FirmwareOverrideSettings = !!(loadFlags & FIRMWARE_OVERRIDE);
biz_skip_fw = !!(loadFlags & SKIP_FIRMWARE);
bool isDsi = !!(loadFlags & IS_DSI);
NDS::SetConsoleType(isDsi);
// time calls are deterministic under wbx, so this will force the mac address to a constant value instead of relying on whatever is in the firmware
// fixme: might want to allow the user to specify mac address?
// edit: upstream has ability to set mac address, most work is in frontend now
srand(time(NULL));
Config::RandomizeMAC = true;
biz_time = 0;
@ -127,7 +131,7 @@ EXPORT bool Init(LoadFlags flags, LoadData* loadData, FirmwareSettings* fwSettin
NANDFilePtr = isDsi ? new std::stringstream(std::string(loadData->NandData, loadData->NandLen), std::ios_base::in | std::ios_base::out | std::ios_base::binary) : nullptr;
if (isDsi && (flags & LOAD_DSIWARE))
if (isDsi && (loadFlags & LOAD_DSIWARE))
{
if (!LoadDSiWare(loadData->TmdData))
return false;
@ -135,20 +139,22 @@ EXPORT bool Init(LoadFlags flags, LoadData* loadData, FirmwareSettings* fwSettin
if (!NDS::Init()) return false;
GPU::InitRenderer(false);
biz_render_settings.Soft_Threaded = !!(loadFlags & THREADED_RENDERING);
GPU::SetRenderSettings(false, biz_render_settings);
NDS::LoadBIOS();
if (!isDsi || !(flags & LOAD_DSIWARE))
if (!isDsi || !(loadFlags & LOAD_DSIWARE))
{
if (!NDS::LoadCart(loadData->DsRomData, loadData->DsRomLen, nullptr, 0))
return false;
}
if (!isDsi && (flags & GBA_CART_PRESENT))
if (!isDsi && (loadFlags & GBA_CART_PRESENT))
{
if (!NDS::LoadGBACart(loadData->GbaRomData, loadData->GbaRomLen, loadData->GbaRamData, loadData->GbaRamLen))
return false;
}
if (biz_skip_fw) NDS::SetupDirectBoot("");
NDS::Start();
Stopped = false;
Config::FirmwareOverrideSettings = false;
return true;
}
@ -164,7 +170,11 @@ EXPORT void PutSaveRam(u8* data, u32 len)
EXPORT void GetSaveRam(u8* data)
{
if (NDSCart::Cart) NDSCart::Cart->GetSaveData(data);
if (NDSCart::Cart)
{
NDSCart::Cart->GetSaveData(data);
NdsSaveRamIsDirty = false;
}
}
EXPORT s32 GetSaveRamLength()
@ -364,6 +374,7 @@ EXPORT void FrameAdvance(MyFrameInfo* f)
NDS::LoadBIOS();
if (biz_skip_fw) NDS::SetupDirectBoot("");
NDS::Start();
Stopped = false;
}
NDS::SetKeyMask(~f->Keys & 0xFFF);
@ -401,22 +412,26 @@ EXPORT void FrameAdvance(MyFrameInfo* f)
biz_time = f->Time;
NDS::RunFrame();
for (int i = 0; i < (256 * 192); i++)
{
f->VideoBuffer[i] = GPU::Framebuffer[GPU::FrontBuffer][0][i];
f->VideoBuffer[(256 * 192) + i] = GPU::Framebuffer[GPU::FrontBuffer][1][i];
}
dynamic_cast<GPU3D::SoftRenderer*>(GPU3D::CurrentRenderer.get())->StopRenderThread();
const u32 SingleScreenSize = 256 * 192;
memcpy(f->VideoBuffer, GPU::Framebuffer[GPU::FrontBuffer][0], SingleScreenSize * sizeof (u32));
memcpy(f->VideoBuffer + SingleScreenSize, GPU::Framebuffer[GPU::FrontBuffer][1], SingleScreenSize * sizeof (u32));
f->Width = 256;
f->Height = 384;
f->Samples = SPU::GetOutputSize() / 2;
SPU::ReadOutput(f->SoundBuffer, f->Samples);
if (f->Samples < 547) // hack
{
memset(f->SoundBuffer + (f->Samples * 2), 0, ((547 * 2) - (f->Samples * 2)) * sizeof (u16));
f->Samples = 547;
}
f->Cycles = NDS::GetSysClockCycles(2);
f->Lagged = NDS::LagFrameFlag;
RunningFrame = false;
}
void (*InputCallback)();
void (*InputCallback)() = nullptr;
EXPORT void SetInputCallback(void (*callback)())
{
@ -438,9 +453,9 @@ EXPORT u32 GetCallbackCycleOffset()
return RunningFrame ? NDS::GetSysClockCycles(2) : 0;
}
void (*ReadCallback)(u32);
void (*WriteCallback)(u32);
void (*ExecuteCallback)(u32);
void (*ReadCallback)(u32) = nullptr;
void (*WriteCallback)(u32) = nullptr;
void (*ExecuteCallback)(u32) = nullptr;
EXPORT void SetMemoryCallback(u32 which, void (*callback)(u32 addr))
{
@ -452,9 +467,46 @@ EXPORT void SetMemoryCallback(u32 which, void (*callback)(u32 addr))
}
}
void (*TraceCallback)(u32, u32*, u32);
void (*TraceCallback)(u32, u32*, u32) = nullptr;
EXPORT void SetTraceCallback(void (*callback)(u32 cpu, u32* regs, u32 opcode))
{
TraceCallback = callback;
}
namespace Platform
{
extern uintptr_t FrameThreadProc;
extern void (*ThreadWaitCallback)();
}
EXPORT uintptr_t GetFrameThreadProc()
{
return Platform::FrameThreadProc;
}
EXPORT void SetThreadWaitCallback(void (*callback)())
{
Platform::ThreadWaitCallback = callback;
}
EXPORT u32 GetNANDSize()
{
if (NANDFilePtr)
{
NANDFilePtr->seekg(0, std::ios::end);
return NANDFilePtr->tellg();
}
return 0;
}
EXPORT void GetNANDData(char* buf)
{
if (NANDFilePtr)
{
u32 sz = GetNANDSize();
NANDFilePtr->seekg(0);
NANDFilePtr->read(buf, sz);
}
}

View File

@ -1,14 +1,13 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>
#include <thread>
#include <mutex>
#include "Platform.h"
#include "BizConfig.h"
bool NdsSaveRamIsDirty = false;
std::stringstream* NANDFilePtr = NULL;
bool Stopped = true;
namespace Platform
{
@ -23,218 +22,231 @@ void DeInit()
void StopEmu()
{
Stopped = true;
}
int GetConfigInt(ConfigEntry entry)
{
const int imgsizes[] = {0, 256, 512, 1024, 2048, 4096};
const int imgsizes[] = {0, 256, 512, 1024, 2048, 4096};
switch (entry)
{
switch (entry)
{
#ifdef JIT_ENABLED
case JIT_MaxBlockSize: return Config::JIT_MaxBlockSize;
case JIT_MaxBlockSize: return Config::JIT_MaxBlockSize;
#endif
case DLDI_ImageSize: return imgsizes[Config::DLDISize];
case DLDI_ImageSize: return imgsizes[Config::DLDISize];
case DSiSD_ImageSize: return imgsizes[Config::DSiSDSize];
case DSiSD_ImageSize: return imgsizes[Config::DSiSDSize];
case Firm_Language: return Config::FirmwareLanguage;
case Firm_BirthdayMonth: return Config::FirmwareBirthdayMonth;
case Firm_BirthdayDay: return Config::FirmwareBirthdayDay;
case Firm_Color: return Config::FirmwareFavouriteColour;
case Firm_Language: return Config::FirmwareLanguage;
case Firm_BirthdayMonth: return Config::FirmwareBirthdayMonth;
case Firm_BirthdayDay: return Config::FirmwareBirthdayDay;
case Firm_Color: return Config::FirmwareFavouriteColour;
case AudioBitrate: return Config::AudioBitrate;
case TimeAtBoot: return Config::TimeAtBoot;
}
case AudioBitrate: return Config::AudioBitrate;
case TimeAtBoot: return Config::TimeAtBoot;
return 0;
default: return 0;
}
}
bool GetConfigBool(ConfigEntry entry)
{
switch (entry)
{
switch (entry)
{
#ifdef JIT_ENABLED
case JIT_Enable: return Config::JIT_Enable != 0;
case JIT_LiteralOptimizations: return Config::JIT_LiteralOptimisations != 0;
case JIT_BranchOptimizations: return Config::JIT_BranchOptimisations != 0;
case JIT_FastMemory: return Config::JIT_FastMemory != 0;
case JIT_Enable: return Config::JIT_Enable != 0;
case JIT_LiteralOptimizations: return Config::JIT_LiteralOptimisations != 0;
case JIT_BranchOptimizations: return Config::JIT_BranchOptimisations != 0;
case JIT_FastMemory: return Config::JIT_FastMemory != 0;
#endif
case ExternalBIOSEnable: return Config::ExternalBIOSEnable != 0;
case ExternalBIOSEnable: return Config::ExternalBIOSEnable != 0;
case DLDI_Enable: return Config::DLDIEnable != 0;
case DLDI_ReadOnly: return Config::DLDIReadOnly != 0;
case DLDI_FolderSync: return Config::DLDIFolderSync != 0;
case DLDI_Enable: return Config::DLDIEnable != 0;
case DLDI_ReadOnly: return Config::DLDIReadOnly != 0;
case DLDI_FolderSync: return Config::DLDIFolderSync != 0;
case DSiSD_Enable: return Config::DSiSDEnable != 0;
case DSiSD_ReadOnly: return Config::DSiSDReadOnly != 0;
case DSiSD_FolderSync: return Config::DSiSDFolderSync != 0;
case DSiSD_Enable: return Config::DSiSDEnable != 0;
case DSiSD_ReadOnly: return Config::DSiSDReadOnly != 0;
case DSiSD_FolderSync: return Config::DSiSDFolderSync != 0;
case Firm_RandomizeMAC: return Config::RandomizeMAC != 0;
case Firm_OverrideSettings: return Config::FirmwareOverrideSettings != 0;
case Firm_RandomizeMAC: return Config::RandomizeMAC != 0;
case Firm_OverrideSettings: return Config::FirmwareOverrideSettings != 0;
case UseRealTime: return Config::UseRealTime != 0;
case FixedBootTime: return Config::FixedBootTime != 0;
}
case UseRealTime: return Config::UseRealTime != 0;
case FixedBootTime: return Config::FixedBootTime != 0;
return false;
default: return false;
}
}
std::string GetConfigString(ConfigEntry entry)
{
switch (entry)
{
case BIOS9Path: return Config::BIOS9Path;
case BIOS7Path: return Config::BIOS7Path;
case FirmwarePath: return Config::FirmwarePath;
switch (entry)
{
case BIOS9Path: return Config::BIOS9Path;
case BIOS7Path: return Config::BIOS7Path;
case FirmwarePath: return Config::FirmwarePath;
case DSi_BIOS9Path: return Config::DSiBIOS9Path;
case DSi_BIOS7Path: return Config::DSiBIOS7Path;
case DSi_FirmwarePath: return Config::DSiFirmwarePath;
case DSi_NANDPath: return Config::DSiNANDPath;
case DSi_BIOS9Path: return Config::DSiBIOS9Path;
case DSi_BIOS7Path: return Config::DSiBIOS7Path;
case DSi_FirmwarePath: return Config::DSiFirmwarePath;
case DSi_NANDPath: return Config::DSiNANDPath;
case DLDI_ImagePath: return Config::DLDISDPath;
case DLDI_FolderPath: return Config::DLDIFolderPath;
case DLDI_ImagePath: return Config::DLDISDPath;
case DLDI_FolderPath: return Config::DLDIFolderPath;
case DSiSD_ImagePath: return Config::DSiSDPath;
case DSiSD_FolderPath: return Config::DSiSDFolderPath;
case DSiSD_ImagePath: return Config::DSiSDPath;
case DSiSD_FolderPath: return Config::DSiSDFolderPath;
case Firm_Username: return Config::FirmwareUsername;
case Firm_Message: return Config::FirmwareMessage;
}
case Firm_Username: return Config::FirmwareUsername;
case Firm_Message: return Config::FirmwareMessage;
return "";
default: return "";
}
}
bool GetConfigArray(ConfigEntry entry, void* data)
{
switch (entry)
{
case Firm_MAC:
{
std::string& mac_in = Config::FirmwareMAC;
u8* mac_out = (u8*)data;
switch (entry)
{
case Firm_MAC:
{
std::string& mac_in = Config::FirmwareMAC;
u8* mac_out = (u8*)data;
int o = 0;
u8 tmp = 0;
for (int i = 0; i < 18; i++)
{
char c = mac_in[i];
if (c == '\0') break;
int o = 0;
u8 tmp = 0;
for (int i = 0; i < 18; i++)
{
char c = mac_in[i];
if (c == '\0') break;
int n;
if (c >= '0' && c <= '9') n = c - '0';
else if (c >= 'a' && c <= 'f') n = c - 'a' + 10;
else if (c >= 'A' && c <= 'F') n = c - 'A' + 10;
else continue;
int n;
if (c >= '0' && c <= '9') n = c - '0';
else if (c >= 'a' && c <= 'f') n = c - 'a' + 10;
else if (c >= 'A' && c <= 'F') n = c - 'A' + 10;
else continue;
if (!(o & 1))
tmp = n;
else
mac_out[o >> 1] = n | (tmp << 4);
if (!(o & 1))
tmp = n;
else
mac_out[o >> 1] = n | (tmp << 4);
o++;
if (o >= 12) return true;
}
}
return false;
}
o++;
if (o >= 12) return true;
}
return false;
}
return false;
default: return false;
}
}
FILE* OpenFile(std::string path, std::string mode, bool mustexist)
{
if (path == Config::DSiNANDPath) return reinterpret_cast<FILE*>(NANDFilePtr);
if (path == Config::DSiNANDPath) return reinterpret_cast<FILE*>(NANDFilePtr);
return fopen(path.c_str(), mode.c_str());
return fopen(path.c_str(), mode.c_str());
}
FILE* OpenLocalFile(std::string path, std::string mode)
{
if (path == Config::DSiNANDPath) return reinterpret_cast<FILE*>(NANDFilePtr);
if (path == Config::DSiNANDPath) return reinterpret_cast<FILE*>(NANDFilePtr);
return fopen(path.c_str(), mode.c_str());
return fopen(path.c_str(), mode.c_str());
}
uintptr_t FrameThreadProc = 0;
std::function<void()> ThreadEntryFunc = nullptr;
void (*ThreadWaitCallback)() = nullptr;
void ThreadEntry()
{
if (!Stopped) ThreadEntryFunc();
}
Thread* Thread_Create(std::function<void()> func)
{
std::thread* t = new std::thread(func);
return (Thread*) t;
ThreadEntryFunc = func;
FrameThreadProc = reinterpret_cast<uintptr_t>(ThreadEntry);
return nullptr;
}
void Thread_Free(Thread* thread)
{
delete (std::thread*) thread;
}
void Thread_Wait(Thread* thread)
{
((std::thread*) thread)->join();
ThreadWaitCallback();
}
Semaphore* Semaphore_Create()
{
sem_t* s = new sem_t;
sem_init(s, 0, 1);
return (Semaphore*) s;
int* s = new int;
*s = 0;
return (Semaphore*)s;
}
void Semaphore_Free(Semaphore* sema)
{
sem_destroy((sem_t*) sema);
delete (sem_t*) sema;
abort();
}
void Semaphore_Reset(Semaphore* sema)
{
while (!sem_trywait((sem_t*) sema)) {};
__atomic_store_n((int*)sema, 0, __ATOMIC_RELAXED);
}
void Semaphore_Wait(Semaphore* sema)
{
sem_wait((sem_t*) sema);
int res;
loop:
res = __atomic_load_n((int*)sema, __ATOMIC_RELAXED);
if (!res) goto loop;
__atomic_sub_fetch((int*)sema, 1, __ATOMIC_RELAXED);
if (__atomic_load_n((int*)sema, __ATOMIC_RELAXED) < 0)
{
__atomic_store_n((int*)sema, 0, __ATOMIC_RELAXED);
}
}
void Semaphore_Post(Semaphore* sema, int count)
{
while (count--) sem_post((sem_t*) sema);
__atomic_add_fetch((int*)sema, (int)count, __ATOMIC_RELAXED);
}
Mutex* Mutex_Create()
{
std::mutex* m = new std::mutex();
return (Mutex*) m;
return nullptr;
}
void Mutex_Free(Mutex* mutex)
{
delete (std::mutex*) mutex;
}
void Mutex_Lock(Mutex* mutex)
{
((std::mutex*) mutex)->lock();
}
void Mutex_Unlock(Mutex* mutex)
{
((std::mutex*) mutex)->unlock();
}
bool Mutex_TryLock(Mutex* mutex)
{
return ((std::mutex*) mutex)->try_lock();
return false;
}
void WriteNDSSave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen)
{
NdsSaveRamIsDirty = true;
NdsSaveRamIsDirty = true;
}
void WriteGBASave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen)
@ -244,7 +256,7 @@ void WriteGBASave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen
bool MP_Init()
{
return false;
return false;
}
void MP_DeInit()
@ -253,17 +265,17 @@ void MP_DeInit()
int MP_SendPacket(u8* data, int len)
{
return 0;
return 0;
}
int MP_RecvPacket(u8* data, bool block)
{
return 0;
return 0;
}
bool LAN_Init()
{
return false;
return false;
}
void LAN_DeInit()
@ -272,12 +284,12 @@ void LAN_DeInit()
int LAN_SendPacket(u8* data, int len)
{
return 0;
return 0;
}
int LAN_RecvPacket(u8* data)
{
return 0;
return 0;
}
void Sleep(u64 usecs)

@ -1 +1 @@
Subproject commit 62806da013724272fc7342c9f8530561939f9a62
Subproject commit 305ebdb866c45ac0e9c3308ecf7b91f2ae79fa1d