Merge melonDS master, do massive cleanup/splitup of code

also, get rid of the GBA SRAM hack where it was inserted in ROMs (gross), instead figure out the size and give melonDS a blank save of the correct size
GBA SRAM is also now in SaveRAM
also add in more memory domains (SRAM/ROM/DSi BIOS)
This commit is contained in:
CasualPokePlayer 2023-09-17 00:55:29 -07:00
parent 2fc9f719e5
commit f7786e81b9
21 changed files with 1997 additions and 943 deletions

Binary file not shown.

View File

@ -6,16 +6,6 @@
namespace Config
{
#ifdef JIT_ENABLED
bool JIT_Enable = false;
int JIT_MaxBlockSize = 32;
bool JIT_BranchOptimisations = true;
bool JIT_LiteralOptimisations = true;
bool JIT_FastMemory = true;
#endif
bool ExternalBIOSEnable;
std::string BIOS9Path = "bios9.rom";
std::string BIOS7Path = "bios7.rom";
std::string FirmwarePath = "firmware.bin";
@ -39,20 +29,4 @@ bool DSiSDReadOnly = true;
bool DSiSDFolderSync = false;
std::string DSiSDFolderPath = "";
bool FirmwareOverrideSettings;
std::string FirmwareUsername;
int FirmwareLanguage;
int FirmwareBirthdayMonth;
int FirmwareBirthdayDay;
int FirmwareFavouriteColour;
std::string FirmwareMessage;
std::string FirmwareMAC;
bool RandomizeMAC;
int AudioBitrate;
bool FixedBootTime = true;
bool UseRealTime = false;
int TimeAtBoot = 0;
}

View File

@ -1,60 +0,0 @@
#ifndef CONFIG_H
#define CONFIG_H
#include <string>
namespace Config
{
#ifdef JIT_ENABLED
extern bool JIT_Enable;
extern int JIT_MaxBlockSize;
extern bool JIT_BranchOptimisations;
extern bool JIT_LiteralOptimisations;
extern bool JIT_FastMemory;
#endif
extern bool ExternalBIOSEnable;
extern std::string BIOS9Path;
extern std::string BIOS7Path;
extern std::string FirmwarePath;
extern std::string DSiBIOS9Path;
extern std::string DSiBIOS7Path;
extern std::string DSiFirmwarePath;
extern std::string DSiNANDPath;
extern bool DLDIEnable;
extern std::string DLDISDPath;
extern int DLDISize;
extern bool DLDIReadOnly;
extern bool DLDIFolderSync;
extern std::string DLDIFolderPath;
extern bool DSiSDEnable;
extern std::string DSiSDPath;
extern int DSiSDSize;
extern bool DSiSDReadOnly;
extern bool DSiSDFolderSync;
extern std::string DSiSDFolderPath;
extern bool FirmwareOverrideSettings;
extern std::string FirmwareUsername;
extern int FirmwareLanguage;
extern int FirmwareBirthdayMonth;
extern int FirmwareBirthdayDay;
extern int FirmwareFavouriteColour;
extern std::string FirmwareMessage;
extern std::string FirmwareMAC;
extern bool RandomizeMAC;
extern int AudioBitrate;
extern bool FixedBootTime;
extern bool UseRealTime;
extern int TimeAtBoot;
}
#endif

View File

@ -0,0 +1,267 @@
#include "NDS.h"
#include "NDSCart.h"
#include "GBACart.h"
#include "DSi.h"
#include "ARM.h"
#include "dthumb.h"
#include <waterboxcore.h>
void (*InputCallback)() = nullptr;
ECL_EXPORT void SetInputCallback(void (*callback)())
{
InputCallback = callback;
}
void (*ReadCallback)(u32) = nullptr;
void (*WriteCallback)(u32) = nullptr;
void (*ExecuteCallback)(u32) = nullptr;
ECL_EXPORT void SetMemoryCallback(u32 which, void (*callback)(u32 addr))
{
switch (which)
{
case 0: ReadCallback = callback; break;
case 1: WriteCallback = callback; break;
case 2: ExecuteCallback = callback; break;
}
}
TraceMask_t TraceMask = TRACE_NONE;
static void (*TraceCallback)(TraceMask_t, u32, u32*, char*, u32) = nullptr;
ECL_EXPORT void SetTraceCallback(void (*callback)(TraceMask_t mask, u32 opcode, u32* regs, char* disasm, u32 cyclesOff), TraceMask_t mask)
{
TraceCallback = callback;
TraceMask = callback ? mask : TRACE_NONE;
}
void TraceTrampoline(TraceMask_t type, u32* regs, u32 opcode)
{
static char disasm[DTHUMB_STRING_LENGTH];
memset(disasm, 0, sizeof(disasm));
switch (type)
{
case TRACE_ARM7_THUMB: Disassemble_thumb(opcode, disasm, ARMv4T); break;
case TRACE_ARM7_ARM: Disassemble_arm(opcode, disasm, ARMv4T); break;
case TRACE_ARM9_THUMB: Disassemble_thumb(opcode, disasm, ARMv5TE); break;
case TRACE_ARM9_ARM: Disassemble_arm(opcode, disasm, ARMv5TE); break;
default: __builtin_unreachable();
}
TraceCallback(type, opcode, regs, disasm, NDS::GetSysClockCycles(2));
}
namespace NDS
{
extern ARMv5* ARM9;
extern ARMv4* ARM7;
}
ECL_EXPORT void GetRegs(u32* regs)
{
for (int i = 0; i < 16; i++)
{
*regs++ = NDS::ARM9->R[i];
}
for (int i = 0; i < 16; i++)
{
*regs++ = NDS::ARM7->R[i];
}
}
ECL_EXPORT void SetReg(s32 ncpu, s32 index, s32 val)
{
if (ncpu)
{
NDS::ARM7->R[index] = val;
}
else
{
NDS::ARM9->R[index] = val;
}
}
/* excerpted from gbatek
NDS9 Memory Map
00000000h Instruction TCM (32KB) (not moveable) (mirror-able to 1000000h)
0xxxx000h Data TCM (16KB) (moveable)
02000000h Main Memory (4MB)
03000000h Shared WRAM (0KB, 16KB, or 32KB can be allocated to ARM9)
04000000h ARM9-I/O Ports
05000000h Standard Palettes (2KB) (Engine A BG/OBJ, Engine B BG/OBJ)
06000000h VRAM - Engine A, BG VRAM (max 512KB)
06200000h VRAM - Engine B, BG VRAM (max 128KB)
06400000h VRAM - Engine A, OBJ VRAM (max 256KB)
06600000h VRAM - Engine B, OBJ VRAM (max 128KB)
06800000h VRAM - "LCDC"-allocated (max 656KB)
07000000h OAM (2KB) (Engine A, Engine B)
08000000h GBA Slot ROM (max 32MB)
0A000000h GBA Slot RAM (max 64KB)
FFFF0000h ARM9-BIOS (32KB) (only 3K used)
NDS7 Memory Map
00000000h ARM7-BIOS (16KB)
02000000h Main Memory (4MB)
03000000h Shared WRAM (0KB, 16KB, or 32KB can be allocated to ARM7)
03800000h ARM7-WRAM (64KB)
04000000h ARM7-I/O Ports
04800000h Wireless Communications Wait State 0 (8KB RAM at 4804000h)
04808000h Wireless Communications Wait State 1 (I/O Ports at 4808000h)
06000000h VRAM allocated as Work RAM to ARM7 (max 256K)
08000000h GBA Slot ROM (max 32MB)
0A000000h GBA Slot RAM (max 64KB)
Further Memory (not mapped to ARM9/ARM7 bus)
3D Engine Polygon RAM (52KBx2)
3D Engine Vertex RAM (72KBx2)
Firmware (256KB) (built-in serial flash memory)
GBA-BIOS (16KB) (not used in NDS mode)
NDS Slot ROM (serial 8bit-bus, max 4GB with default protocol)
NDS Slot FLASH/EEPROM/FRAM (serial 1bit-bus)
*/
template<bool arm9>
static bool SafeToPeek(u32 addr)
{
if (arm9)
{
switch (addr)
{
case 0x04000130:
case 0x04000131:
case 0x04000600:
case 0x04000601:
case 0x04000602:
case 0x04000603:
return false;
}
}
else // arm7
{
if (addr >= 0x04800000 && addr <= 0x04810000)
{
if (addr & 1) addr--;
addr &= 0x7FFE;
if (addr == 0x044 || addr == 0x060)
return false;
}
}
return true;
}
static void ARM9Access(u8* buffer, s64 address, s64 count, bool write)
{
if (write)
{
void (*Write)(u32, u8) = NDS::ConsoleType == 1 ? DSi::ARM9Write8 : NDS::ARM9Write8;
while (count--)
{
if (address < NDS::ARM9->ITCMSize)
{
NDS::ARM9->ITCM[address++ & (ITCMPhysicalSize - 1)] = *buffer++;
}
else if ((address & NDS::ARM9->DTCMMask) == NDS::ARM9->DTCMBase)
{
NDS::ARM9->DTCM[address++ & (DTCMPhysicalSize - 1)] = *buffer++;
}
else
{
Write(address++, *buffer++);
}
}
}
else
{
u8 (*Read)(u32) = NDS::ConsoleType == 1 ? DSi::ARM9Read8 : NDS::ARM9Read8;
while (count--)
{
if (address < NDS::ARM9->ITCMSize)
{
*buffer++ = NDS::ARM9->ITCM[address & (ITCMPhysicalSize - 1)];
}
else if ((address & NDS::ARM9->DTCMMask) == NDS::ARM9->DTCMBase)
{
*buffer++ = NDS::ARM9->DTCM[address & (DTCMPhysicalSize - 1)];
}
else
{
*buffer++ = SafeToPeek<true>(address) ? Read(address) : 0;
}
address++;
}
}
}
static void ARM7Access(u8* buffer, s64 address, s64 count, bool write)
{
if (write)
{
void (*Write)(u32, u8) = NDS::ConsoleType == 1 ? DSi::ARM7Write8 : NDS::ARM7Write8;
while (count--)
Write(address++, *buffer++);
}
else
{
u8 (*Read)(u32) = NDS::ConsoleType == 1 ? DSi::ARM7Read8 : NDS::ARM7Read8;
while (count--)
*buffer++ = SafeToPeek<true>(address) ? Read(address) : 0, address++;
}
}
ECL_EXPORT void GetMemoryAreas(MemoryArea *m)
{
int i = 0;
#define ADD_MEMORY_DOMAIN(name, data, size, flags) do \
{ \
m[i].Data = (void*)data; \
m[i].Name = name; \
m[i].Size = size; \
m[i].Flags = flags; \
i++; \
} while (0)
ADD_MEMORY_DOMAIN("Main RAM", NDS::MainRAM, NDS::ConsoleType == 1 ? NDS::MainRAMMaxSize : NDS::MainRAMMaxSize / 4, MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_PRIMARY);
ADD_MEMORY_DOMAIN("Shared WRAM", NDS::SharedWRAM, NDS::SharedWRAMSize, MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE);
ADD_MEMORY_DOMAIN("ARM7 WRAM", NDS::ARM7WRAM, NDS::ARM7WRAMSize, MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE);
if (NDSCart::Cart)
{
ADD_MEMORY_DOMAIN("SRAM", NDSCart::GetSaveMemory(), NDSCart::GetSaveMemoryLength(), MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE);
ADD_MEMORY_DOMAIN("ROM", NDSCart::Cart->GetROM(), NDSCart::Cart->GetROMLength(), MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE);
}
if (GBACart::Cart)
{
ADD_MEMORY_DOMAIN("GBA SRAM", GBACart::GetSaveMemory(), GBACart::GetSaveMemoryLength(), MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE);
ADD_MEMORY_DOMAIN("GBA ROM", GBACart::Cart->GetROM(), GBACart::Cart->GetROMLength(), MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE);
}
ADD_MEMORY_DOMAIN("Instruction TCM", NDS::ARM9->ITCM, ITCMPhysicalSize, MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE);
ADD_MEMORY_DOMAIN("Data TCM", NDS::ARM9->DTCM, DTCMPhysicalSize, MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE);
ADD_MEMORY_DOMAIN("ARM9 BIOS", NDS::ARM9BIOS, sizeof(NDS::ARM9BIOS), MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE);
ADD_MEMORY_DOMAIN("ARM7 BIOS", NDS::ARM7BIOS, sizeof(NDS::ARM7BIOS), MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE);
if (NDS::ConsoleType == 1)
{
ADD_MEMORY_DOMAIN("ARM9i BIOS", DSi::ARM9iBIOS, sizeof(DSi::ARM9iBIOS), MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE);
ADD_MEMORY_DOMAIN("ARM7i BIOS", DSi::ARM7iBIOS, sizeof(DSi::ARM7iBIOS), MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE);
}
ADD_MEMORY_DOMAIN("ARM9 System Bus", ARM9Access, 1ull << 32, MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_FUNCTIONHOOK);
ADD_MEMORY_DOMAIN("ARM7 System Bus", ARM7Access, 1ull << 32, MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_FUNCTIONHOOK);
// fixme: include more shit
}

View File

@ -0,0 +1,214 @@
#include "NDS.h"
#include "DSi_NAND.h"
#include "DSi_TMD.h"
#include "CRC32.h"
#include "BizFileManager.h"
namespace FileManager
{
constexpr u32 DSIWARE_CATEGORY = 0x00030004;
static std::optional<std::pair<std::unique_ptr<u8[]>, size_t>> GetFileData(std::string path)
{
auto file = Platform::OpenFile(path, Platform::FileMode::Read);
if (!file)
{
return std::nullopt;
}
size_t size = Platform::FileLength(file);
auto data = std::make_unique<u8[]>(size);
Platform::FileRewind(file);
Platform::FileRead(data.get(), size, 1, file);
Platform::CloseFile(file);
return std::make_pair(std::move(data), size);
}
const char* InitNAND(bool clearNand, bool dsiWare)
{
auto dsiBios7Path = Platform::GetConfigString(Platform::ConfigEntry::DSi_BIOS7Path);
auto bios7i = Platform::OpenFile(dsiBios7Path, Platform::FileMode::Read);
if (!bios7i)
{
return "Failed to obtain BIOS7i!";
}
u8 es_keyY[16]{};
Platform::FileSeek(bios7i, 0x8308, Platform::FileSeekOrigin::Start);
Platform::FileRead(es_keyY, 16, 1, bios7i);
Platform::CloseFile(bios7i);
if (!DSi_NAND::Init(es_keyY))
{
return "Failed to init DSi NAND!";
}
if (clearNand)
{
std::vector<u32> titlelist;
DSi_NAND::ListTitles(DSIWARE_CATEGORY, titlelist);
for (auto& title : titlelist)
{
DSi_NAND::DeleteTitle(DSIWARE_CATEGORY, title);
}
}
if (dsiWare)
{
auto rom = GetFileData("dsiware.rom");
if (!rom)
{
return "Failed to obtain DSiWare ROM!";
}
auto tmdData = GetFileData("tmd.rom");
if (!tmdData)
{
return "Failed to obtain TMD!";
}
if (tmdData->second != sizeof(DSi_TMD::TitleMetadata))
{
return "TMD is not the correct size!";
}
DSi_TMD::TitleMetadata tmd;
memcpy(&tmd, tmdData->first.get(), sizeof(DSi_TMD::TitleMetadata));
if (!DSi_NAND::ImportTitle(rom->first.get(), rom->second, tmd, false))
{
DSi_NAND::DeInit();
return "Loading DSiWare failed!";
}
}
DSi_NAND::DeInit();
return nullptr;
}
enum class GBASaveType
{
NONE,
SRAM,
EEPROM512,
EEPROM,
FLASH512,
FLASH1M,
};
#include "GBASaveOverrides.h"
static GBASaveType FindGbaSaveType(const u8* gbaRomData, size_t gbaRomSize)
{
u32 crc = CRC32(gbaRomData, gbaRomSize);
if (auto saveOverride = GbaCrcSaveTypeOverrides.find(crc); saveOverride != GbaCrcSaveTypeOverrides.end())
{
return saveOverride->second;
}
if (gbaRomSize >= 0xB0)
{
char gameId[4];
std::memcpy(gameId, &gbaRomData[0xAC], 4);
if (auto saveOverride = GbaGameIdSaveTypeOverrides.find(std::string(gameId, 4)); saveOverride != GbaGameIdSaveTypeOverrides.end())
{
return saveOverride->second;
}
}
if (memmem(gbaRomData, gbaRomSize, "EEPROM_V", strlen("EEPROM_V")))
{
return GBASaveType::EEPROM512;
}
if (memmem(gbaRomData, gbaRomSize, "SRAM_V", strlen("SRAM_V")))
{
return GBASaveType::SRAM;
}
if (memmem(gbaRomData, gbaRomSize, "FLASH_V", strlen("FLASH_V"))
|| memmem(gbaRomData, gbaRomSize, "FLASH512_V", strlen("FLASH512_V")))
{
return GBASaveType::FLASH512;
}
if (memmem(gbaRomData, gbaRomSize, "FLASH1M_V", strlen("FLASH1M_V")))
{
return GBASaveType::FLASH1M;
}
return GBASaveType::NONE;
}
static std::pair<std::unique_ptr<u8[]>, size_t> CreateBlankGbaSram(const u8* gbaRomData, size_t gbaRomSize)
{
auto saveType = FindGbaSaveType(gbaRomData, gbaRomSize);
if (saveType == GBASaveType::NONE)
{
return std::make_pair(nullptr, 0);
}
size_t size;
switch (saveType)
{
case GBASaveType::SRAM:
size = 0x8000;
break;
case GBASaveType::EEPROM512:
size = 0x200;
break;
case GBASaveType::EEPROM:
size = 0x2000;
break;
case GBASaveType::FLASH512:
size = 0x10000;
break;
case GBASaveType::FLASH1M:
size = 0x20000;
break;
default:
__builtin_unreachable();
}
auto data = std::make_unique<u8[]>(size);
memset(data.get(), 0xFF, size);
return std::make_pair(std::move(data), size);
}
const char* InitCarts(bool gba)
{
auto ndsRom = GetFileData("nds.rom");
if (!ndsRom)
{
return "Failed to obtain NDS ROM!";
}
if (!NDS::LoadCart(ndsRom->first.get(), ndsRom->second, nullptr, 0))
{
return "Failed to load NDS ROM!";
}
if (gba)
{
auto gbaRom = GetFileData("gba.rom");
if (!gbaRom)
{
return "Failed to obtain GBA ROM!";
}
auto gbaSram = CreateBlankGbaSram(gbaRom->first.get(), gbaRom->second);
if (!NDS::LoadGBACart(gbaRom->first.get(), gbaRom->second, gbaSram.first.get(), gbaSram.second))
{
return "Failed to load GBA ROM!";
}
}
return nullptr;
}
}

View File

@ -0,0 +1,14 @@
#ifndef BIZFILEMANAGER_H
#define BIZFILEMANAGER_H
#include "types.h"
namespace FileManager
{
const char* InitNAND(bool clearNand, bool dsiWare);
const char* InitCarts(bool gba);
}
#endif

View File

@ -2,412 +2,80 @@
#include "GPU.h"
#include "SPU.h"
#include "RTC.h"
#include "ARM.h"
#include "NDSCart.h"
#include "GBACart.h"
#include "DSi.h"
#include "DSi_NAND.h"
#include "Platform.h"
#include "BizConfig.h"
#include "types.h"
#include "frontend/mic_blow.h"
#include "emulibc.h"
#include "waterboxcore.h"
#include "BizPlatform/BizConfig.h"
#include "BizPlatform/BizFile.h"
#include "BizPlatform/BizLog.h"
#include "BizFileManager.h"
#include <cmath>
#include <algorithm>
#include <time.h>
#include <emulibc.h>
#include <waterboxcore.h>
#include <sstream>
static bool SkipFW;
static time_t CurTime;
constexpr u32 DSIWARE_CATEGORY = 0x00030004;
static GPU::RenderSettings biz_render_settings { false, 1, false };
static bool biz_skip_fw;
static time_t biz_time;
static time_t BizRtcCallback()
struct InitConfig
{
return biz_time;
}
bool SkipFW;
bool HasGBACart;
bool DSi;
bool ClearNAND;
bool LoadDSiWare;
int ThreeDeeRenderer;
GPU::RenderSettings RenderSettings;
};
typedef enum
ECL_EXPORT const char* Init(InitConfig* initConfig,
Platform::ConfigCallbackInterface* configCallbackInterface,
Platform::FileCallbackInterface* fileCallbackInterface,
Platform::LogCallback_t logCallback)
{
NONE = 0x00,
USE_REAL_BIOS = 0x01,
SKIP_FIRMWARE = 0x02,
GBA_CART_PRESENT = 0x04,
CLEAR_NAND = 0x08,
FIRMWARE_OVERRIDE = 0x10,
IS_DSI = 0x20,
LOAD_DSIWARE = 0x40,
THREADED_RENDERING = 0x80,
} LoadFlags;
Platform::SetConfigCallbacks(*configCallbackInterface);
Platform::SetFileCallbacks(*fileCallbackInterface);
Platform::SetLogCallback(logCallback);
typedef struct
{
u8* DsRomData;
u32 DsRomLen;
u8* GbaRomData;
u32 GbaRomLen;
u8* GbaRamData;
u32 GbaRamLen;
char* NandData;
u32 NandLen;
u8* TmdData;
s32 AudioBitrate;
} LoadData;
SkipFW = initConfig->SkipFW;
NDS::SetConsoleType(initConfig->DSi);
typedef struct
{
char* FirmwareUsername; // max 10 length (then terminator)
s32 FirmwareUsernameLength;
s32 FirmwareLanguage;
s32 FirmwareBirthdayMonth;
s32 FirmwareBirthdayDay;
s32 FirmwareFavouriteColour;
char* FirmwareMessage; // max 26 length (then terminator)
s32 FirmwareMessageLength;
} FirmwareSettings;
CurTime = 0;
RTC::RtcCallback = []() { return CurTime; };
extern std::stringstream* NANDFilePtr;
ECL_EXPORT bool Init(LoadFlags loadFlags, LoadData* loadData, FirmwareSettings* fwSettings)
{
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);
biz_time = 0;
RTC::RtcCallback = BizRtcCallback;
if (Config::FirmwareOverrideSettings)
if (initConfig->DSi)
{
std::string fwUsername(fwSettings->FirmwareUsername, fwSettings->FirmwareUsernameLength);
fwUsername += '\0';
Config::FirmwareUsername = fwUsername;
Config::FirmwareLanguage = fwSettings->FirmwareLanguage;
Config::FirmwareBirthdayMonth = fwSettings->FirmwareBirthdayMonth;
Config::FirmwareBirthdayDay = fwSettings->FirmwareBirthdayDay;
Config::FirmwareFavouriteColour = fwSettings->FirmwareFavouriteColour;
std::string fwMessage(fwSettings->FirmwareMessage, fwSettings->FirmwareMessageLength);
fwMessage += '\0';
Config::FirmwareMessage = fwMessage;
Config::FirmwareMAC = "00:09:BF:0E:49:16"; // TODO: Make configurable
if (const char* error = FileManager::InitNAND(initConfig->ClearNAND, initConfig->LoadDSiWare))
{
return error;
}
}
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)
if (!NDS::Init())
{
FILE* bios7i = Platform::OpenLocalFile(Config::DSiBIOS7Path, "rb");
if (!bios7i)
return false;
u8 es_keyY[16];
fseek(bios7i, 0x8308, SEEK_SET);
fread(es_keyY, 16, 1, bios7i);
fclose(bios7i);
if (!DSi_NAND::Init(es_keyY))
return false;
if (loadFlags & CLEAR_NAND)
{
std::vector<u32> titlelist;
DSi_NAND::ListTitles(DSIWARE_CATEGORY, titlelist);
for (auto& title : titlelist)
{
DSi_NAND::DeleteTitle(DSIWARE_CATEGORY, title);
}
}
if (loadFlags & LOAD_DSIWARE)
{
if (!DSi_NAND::ImportTitle("dsiware.rom", loadData->TmdData, false))
{
DSi_NAND::DeInit();
return false;
}
}
DSi_NAND::DeInit();
return "Failed to init core!";
}
if (!NDS::Init()) return false;
GPU::InitRenderer(false);
biz_render_settings.Soft_Threaded = !!(loadFlags & THREADED_RENDERING);
GPU::SetRenderSettings(false, biz_render_settings);
GPU::InitRenderer(initConfig->ThreeDeeRenderer);
GPU::SetRenderSettings(initConfig->ThreeDeeRenderer, initConfig->RenderSettings);
NDS::LoadBIOS();
if (!isDsi || !(loadFlags & LOAD_DSIWARE))
if (!initConfig->LoadDSiWare)
{
if (!NDS::LoadCart(loadData->DsRomData, loadData->DsRomLen, nullptr, 0))
return false;
if (const char* error = FileManager::InitCarts(initConfig->HasGBACart))
{
return error;
}
}
if (!isDsi && (loadFlags & GBA_CART_PRESENT))
if (SkipFW || NDS::NeedsDirectBoot())
{
if (!NDS::LoadGBACart(loadData->GbaRomData, loadData->GbaRomLen, loadData->GbaRamData, loadData->GbaRamLen))
return false;
NDS::SetupDirectBoot("nds.rom");
}
if (biz_skip_fw) NDS::SetupDirectBoot("");
NDS::Start();
Config::FirmwareOverrideSettings = false;
return true;
}
namespace NDSCart { extern CartCommon* Cart; }
extern bool NdsSaveRamIsDirty;
ECL_EXPORT void PutSaveRam(u8* data, u32 len)
{
NDS::LoadSave(data, len);
NdsSaveRamIsDirty = false;
}
ECL_EXPORT void GetSaveRam(u8* data)
{
if (NDSCart::Cart)
{
NDSCart::Cart->GetSaveData(data);
NdsSaveRamIsDirty = false;
}
}
ECL_EXPORT u32 GetSaveRamLength()
{
return NDSCart::Cart ? NDSCart::Cart->GetSaveLen() : 0;
}
ECL_EXPORT bool SaveRamIsDirty()
{
return NdsSaveRamIsDirty;
}
ECL_EXPORT void ImportDSiWareSavs(u32 titleId)
{
if (DSi_NAND::Init(&DSi::ARM7iBIOS[0x8308]))
{
DSi_NAND::ImportTitleData(DSIWARE_CATEGORY, titleId, DSi_NAND::TitleData_PublicSav, "public.sav");
DSi_NAND::ImportTitleData(DSIWARE_CATEGORY, titleId, DSi_NAND::TitleData_PrivateSav, "private.sav");
DSi_NAND::ImportTitleData(DSIWARE_CATEGORY, titleId, DSi_NAND::TitleData_BannerSav, "banner.sav");
DSi_NAND::DeInit();
}
}
ECL_EXPORT void ExportDSiWareSavs(u32 titleId)
{
if (DSi_NAND::Init(&DSi::ARM7iBIOS[0x8308]))
{
DSi_NAND::ExportTitleData(DSIWARE_CATEGORY, titleId, DSi_NAND::TitleData_PublicSav, "public.sav");
DSi_NAND::ExportTitleData(DSIWARE_CATEGORY, titleId, DSi_NAND::TitleData_PrivateSav, "private.sav");
DSi_NAND::ExportTitleData(DSIWARE_CATEGORY, titleId, DSi_NAND::TitleData_BannerSav, "banner.sav");
DSi_NAND::DeInit();
}
}
ECL_EXPORT void DSiWareSavsLength(u32 titleId, u32* publicSavSize, u32* privateSavSize, u32* bannerSavSize)
{
*publicSavSize = *privateSavSize = *bannerSavSize = 0;
if (DSi_NAND::Init(&DSi::ARM7iBIOS[0x8308]))
{
u32 version;
NDSHeader header{};
DSi_NAND::GetTitleInfo(DSIWARE_CATEGORY, titleId, version, &header, nullptr);
*publicSavSize = header.DSiPublicSavSize;
*privateSavSize = header.DSiPrivateSavSize;
*bannerSavSize = (header.AppFlags & 0x04) ? 0x4000 : 0;
DSi_NAND::DeInit();
}
}
/* excerpted from gbatek
NDS9 Memory Map
00000000h Instruction TCM (32KB) (not moveable) (mirror-able to 1000000h)
0xxxx000h Data TCM (16KB) (moveable)
02000000h Main Memory (4MB)
03000000h Shared WRAM (0KB, 16KB, or 32KB can be allocated to ARM9)
04000000h ARM9-I/O Ports
05000000h Standard Palettes (2KB) (Engine A BG/OBJ, Engine B BG/OBJ)
06000000h VRAM - Engine A, BG VRAM (max 512KB)
06200000h VRAM - Engine B, BG VRAM (max 128KB)
06400000h VRAM - Engine A, OBJ VRAM (max 256KB)
06600000h VRAM - Engine B, OBJ VRAM (max 128KB)
06800000h VRAM - "LCDC"-allocated (max 656KB)
07000000h OAM (2KB) (Engine A, Engine B)
08000000h GBA Slot ROM (max 32MB)
0A000000h GBA Slot RAM (max 64KB)
FFFF0000h ARM9-BIOS (32KB) (only 3K used)
NDS7 Memory Map
00000000h ARM7-BIOS (16KB)
02000000h Main Memory (4MB)
03000000h Shared WRAM (0KB, 16KB, or 32KB can be allocated to ARM7)
03800000h ARM7-WRAM (64KB)
04000000h ARM7-I/O Ports
04800000h Wireless Communications Wait State 0 (8KB RAM at 4804000h)
04808000h Wireless Communications Wait State 1 (I/O Ports at 4808000h)
06000000h VRAM allocated as Work RAM to ARM7 (max 256K)
08000000h GBA Slot ROM (max 32MB)
0A000000h GBA Slot RAM (max 64KB)
Further Memory (not mapped to ARM9/ARM7 bus)
3D Engine Polygon RAM (52KBx2)
3D Engine Vertex RAM (72KBx2)
Firmware (256KB) (built-in serial flash memory)
GBA-BIOS (16KB) (not used in NDS mode)
NDS Slot ROM (serial 8bit-bus, max 4GB with default protocol)
NDS Slot FLASH/EEPROM/FRAM (serial 1bit-bus)
*/
template<bool arm9>
static bool SafeToPeek(u32 addr)
{
if (arm9)
{
switch (addr)
{
case 0x04000130:
case 0x04000131:
case 0x04000600:
case 0x04000601:
case 0x04000602:
case 0x04000603:
return false;
}
}
else // arm7
{
if (addr >= 0x04800000 && addr <= 0x04810000)
{
if (addr & 1) addr--;
addr &= 0x7FFE;
if (addr == 0x044 || addr == 0x060)
return false;
}
}
return true;
}
static void ARM9Access(u8* buffer, s64 address, s64 count, bool write)
{
if (write)
{
void (*Write)(u32, u8) = NDS::ConsoleType == 1 ? DSi::ARM9Write8 : NDS::ARM9Write8;
while (count--)
{
if (address < NDS::ARM9->ITCMSize)
{
NDS::ARM9->ITCM[address++ & (ITCMPhysicalSize - 1)] = *buffer++;
}
else if ((address & NDS::ARM9->DTCMMask) == NDS::ARM9->DTCMBase)
{
NDS::ARM9->DTCM[address++ & (DTCMPhysicalSize - 1)] = *buffer++;
}
else
{
Write(address++, *buffer++);
}
}
}
else
{
u8 (*Read)(u32) = NDS::ConsoleType == 1 ? DSi::ARM9Read8 : NDS::ARM9Read8;
while (count--)
{
if (address < NDS::ARM9->ITCMSize)
{
*buffer++ = NDS::ARM9->ITCM[address & (ITCMPhysicalSize - 1)];
}
else if ((address & NDS::ARM9->DTCMMask) == NDS::ARM9->DTCMBase)
{
*buffer++ = NDS::ARM9->DTCM[address & (DTCMPhysicalSize - 1)];
}
else
{
*buffer++ = SafeToPeek<true>(address) ? Read(address) : 0;
}
address++;
}
}
}
static void ARM7Access(u8* buffer, s64 address, s64 count, bool write)
{
if (write)
{
void (*Write)(u32, u8) = NDS::ConsoleType == 1 ? DSi::ARM7Write8 : NDS::ARM7Write8;
while (count--)
Write(address++, *buffer++);
}
else
{
u8 (*Read)(u32) = NDS::ConsoleType == 1 ? DSi::ARM7Read8 : NDS::ARM7Read8;
while (count--)
*buffer++ = SafeToPeek<true>(address) ? Read(address) : 0, address++;
}
}
ECL_EXPORT void GetMemoryAreas(MemoryArea *m)
{
m[0].Data = NDS::MainRAM;
m[0].Name = "Main RAM";
m[0].Size = NDS::MainRAMMaxSize;
m[0].Flags = MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_PRIMARY;
m[1].Data = NDS::SharedWRAM;
m[1].Name = "Shared WRAM";
m[1].Size = NDS::SharedWRAMSize;
m[1].Flags = MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE;
m[2].Data = NDS::ARM7WRAM;
m[2].Name = "ARM7 WRAM";
m[2].Size = NDS::ARM7WRAMSize;
m[2].Flags = MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE;
m[3].Data = NDS::ARM9->ITCM;
m[3].Name = "Instruction TCM";
m[3].Size = ITCMPhysicalSize;
m[3].Flags = MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE;
m[4].Data = NDS::ARM9->DTCM;
m[4].Name = "Data TCM";
m[4].Size = DTCMPhysicalSize;
m[4].Flags = MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE;
m[5].Data = NDS::ARM9BIOS;
m[5].Name = "ARM9 BIOS";
m[5].Size = sizeof NDS::ARM9BIOS;
m[5].Flags = MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE;
m[6].Data = NDS::ARM7BIOS;
m[6].Name = "ARM7 BIOS";
m[6].Size = sizeof NDS::ARM7BIOS;
m[6].Flags = MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE;
m[7].Data = (void*)ARM9Access;
m[7].Name = "ARM9 System Bus";
m[7].Size = 1ull << 32;
m[7].Flags = MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_FUNCTIONHOOK;
m[8].Data = (void*)ARM7Access;
m[8].Name = "ARM7 System Bus";
m[8].Size = 1ull << 32;
m[8].Flags = MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_FUNCTIONHOOK;
// fixme: include more shit
return nullptr;
}
struct MyFrameInfo : public FrameInfo
@ -432,11 +100,11 @@ static int sampPos = 0;
static void MicFeedNoise(s8 vol)
{
int sampLen = sizeof mic_blow / sizeof mic_blow[0];
int sampLen = sizeof(mic_blow) / sizeof (*mic_blow);
for (int i = 0; i < 735; i++)
{
biz_mic_input[i] = std::round(mic_blow[sampPos++] * (vol / 100.0));
biz_mic_input[i] = round(mic_blow[sampPos++] * (vol / 100.0));
if (sampPos >= sampLen) sampPos = 0;
}
}
@ -450,7 +118,11 @@ ECL_EXPORT void FrameAdvance(MyFrameInfo* f)
if (f->Keys & 0x8000)
{
NDS::LoadBIOS();
if (biz_skip_fw) NDS::SetupDirectBoot("");
if (SkipFW || NDS::NeedsDirectBoot())
{
NDS::SetupDirectBoot("nds.rom");
}
NDS::Start();
}
@ -466,12 +138,15 @@ ECL_EXPORT void FrameAdvance(MyFrameInfo* f)
}
if (f->Keys & 0x2000)
{
NDS::SetLidClosed(false);
}
else if (f->Keys & 0x4000)
{
NDS::SetLidClosed(true);
}
MicFeedNoise(f->MicVolume);
NDS::MicInputFrame(biz_mic_input, 735);
int sensor = GBACart::SetInput(0, 1);
@ -479,161 +154,53 @@ ECL_EXPORT void FrameAdvance(MyFrameInfo* f)
{
if (sensor > f->GBALightSensor)
{
while (GBACart::SetInput(0, 1) != f->GBALightSensor) {}
while (GBACart::SetInput(0, 1) != f->GBALightSensor);
}
else if (sensor < f->GBALightSensor)
{
while (GBACart::SetInput(1, 1) != f->GBALightSensor) {}
while (GBACart::SetInput(1, 1) != f->GBALightSensor);
}
}
biz_time = f->Time;
CurTime = f->Time;
NDS::RunFrame();
dynamic_cast<GPU3D::SoftRenderer*>(GPU3D::CurrentRenderer.get())->StopRenderThread();
if (auto softRenderer = dynamic_cast<GPU3D::SoftRenderer*>(GPU3D::CurrentRenderer.get()))
{
softRenderer->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::ReadOutput(f->SoundBuffer);
if (f->Samples < 737) // hack
if (f->Samples == 0) // hack
{
memset(f->SoundBuffer + (f->Samples * 2), 0, ((737 * 2) - (f->Samples * 2)) * sizeof (u16));
memset(f->SoundBuffer, 0, 737 * 2 * sizeof (u16));
f->Samples = 737;
}
f->Cycles = NDS::GetSysClockCycles(2);
f->Lagged = NDS::LagFrameFlag;
// if we want to consider other lag sources, use that lag flag if we haven't unlagged already
if (f->ConsiderAltLag && NDS::LagFrameFlag)
{
f->Lagged = NDS::AltLagFrameFlag;
}
else
{
f->Lagged = NDS::LagFrameFlag;
}
RunningFrame = false;
}
void (*InputCallback)() = nullptr;
ECL_EXPORT void SetInputCallback(void (*callback)())
{
InputCallback = callback;
}
ECL_EXPORT void GetRegs(u32* regs)
{
NDS::GetRegs(regs);
}
ECL_EXPORT void SetReg(s32 ncpu, s32 index, s32 val)
{
NDS::SetReg(ncpu, index, val);
}
ECL_EXPORT u32 GetCallbackCycleOffset()
{
return RunningFrame ? NDS::GetSysClockCycles(2) : 0;
}
void (*ReadCallback)(u32) = nullptr;
void (*WriteCallback)(u32) = nullptr;
void (*ExecuteCallback)(u32) = nullptr;
ECL_EXPORT void SetMemoryCallback(u32 which, void (*callback)(u32 addr))
{
switch (which)
{
case 0: ReadCallback = callback; break;
case 1: WriteCallback = callback; break;
case 2: ExecuteCallback = callback; break;
}
}
TraceMask_t TraceMask = TRACE_NONE;
static void (*TraceCallback)(TraceMask_t, u32, u32*, char*, u32) = nullptr;
#define TRACE_STRING_LENGTH 80
typedef enum {
ARMv4T, //ARM v4, THUMB v1
ARMv5TE, //ARM v5, THUMB v2
ARMv6, //ARM v6, THUMB v3
} ARMARCH; //only 32-bit legacy architectures with THUMB support
extern "C" u32 Disassemble_thumb(u32 code, char str[TRACE_STRING_LENGTH], ARMARCH tv);
extern "C" void Disassemble_arm(u32 code, char str[TRACE_STRING_LENGTH], ARMARCH av);
void TraceTrampoline(TraceMask_t type, u32* regs, u32 opcode)
{
static char disasm[TRACE_STRING_LENGTH];
memset(disasm, 0, sizeof disasm);
switch (type) {
case TRACE_ARM7_THUMB: Disassemble_thumb(opcode, disasm, ARMv4T); break;
case TRACE_ARM7_ARM: Disassemble_arm(opcode, disasm, ARMv4T); break;
case TRACE_ARM9_THUMB: Disassemble_thumb(opcode, disasm, ARMv5TE); break;
case TRACE_ARM9_ARM: Disassemble_arm(opcode, disasm, ARMv5TE); break;
default: __builtin_unreachable();
}
TraceCallback(type, opcode, regs, disasm, NDS::GetSysClockCycles(2));
}
ECL_EXPORT void SetTraceCallback(void (*callback)(TraceMask_t mask, u32 opcode, u32* regs, char* disasm, u32 cyclesOff), TraceMask_t mask)
{
TraceCallback = callback;
TraceMask = callback ? mask : TRACE_NONE;
}
ECL_EXPORT void GetDisassembly(TraceMask_t type, u32 opcode, char* ret)
{
static char disasm[TRACE_STRING_LENGTH];
memset(disasm, 0, sizeof disasm);
switch (type) {
case TRACE_ARM7_THUMB: Disassemble_thumb(opcode, disasm, ARMv4T); break;
case TRACE_ARM7_ARM: Disassemble_arm(opcode, disasm, ARMv4T); break;
case TRACE_ARM9_THUMB: Disassemble_thumb(opcode, disasm, ARMv5TE); break;
case TRACE_ARM9_ARM: Disassemble_arm(opcode, disasm, ARMv5TE); break;
default: __builtin_unreachable();
}
memcpy(ret, disasm, TRACE_STRING_LENGTH);
}
namespace Platform
{
extern uintptr_t FrameThreadProc;
extern void (*ThreadStartCallback)();
}
ECL_EXPORT uintptr_t GetFrameThreadProc()
{
return Platform::FrameThreadProc;
}
ECL_EXPORT void SetThreadStartCallback(void (*callback)())
{
Platform::ThreadStartCallback = callback;
}
ECL_EXPORT u32 GetNANDSize()
{
if (NANDFilePtr)
{
NANDFilePtr->seekg(0, std::ios::end);
return NANDFilePtr->tellg();
}
return 0;
}
ECL_EXPORT void GetNANDData(char* buf)
{
if (NANDFilePtr)
{
u32 sz = GetNANDSize();
NANDFilePtr->seekg(0);
NANDFilePtr->read(buf, sz);
}
}
namespace GPU { void ResetVRAMCache(); }
ECL_EXPORT void ResetCaches()
{
GPU::ResetVRAMCache();
}

View File

@ -1,338 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mutex>
#include "Platform.h"
#include "BizConfig.h"
bool NdsSaveRamIsDirty = false;
std::stringstream* NANDFilePtr = NULL;
namespace Platform
{
void Init(int argc, char** argv)
{
}
void DeInit()
{
}
void StopEmu()
{
}
int InstanceID()
{
return 0;
}
std::string InstanceFileSuffix()
{
return "";
}
int GetConfigInt(ConfigEntry entry)
{
const int imgsizes[] = {0, 256, 512, 1024, 2048, 4096};
switch (entry)
{
#ifdef JIT_ENABLED
case JIT_MaxBlockSize: return Config::JIT_MaxBlockSize;
#endif
case DLDI_ImageSize: return imgsizes[Config::DLDISize];
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 AudioBitrate: return Config::AudioBitrate;
case TimeAtBoot: return Config::TimeAtBoot;
default: return 0;
}
}
bool GetConfigBool(ConfigEntry 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;
#endif
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 DSiSD_Enable: return Config::DSiSDEnable != 0;
case DSiSD_ReadOnly: return Config::DSiSDReadOnly != 0;
case DSiSD_FolderSync: return Config::DSiSDFolderSync != 0;
case Firm_OverrideSettings: return Config::FirmwareOverrideSettings != 0;
case UseRealTime: return Config::UseRealTime != 0;
case FixedBootTime: return Config::FixedBootTime != 0;
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;
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 DSiSD_ImagePath: return Config::DSiSDPath;
case DSiSD_FolderPath: return Config::DSiSDFolderPath;
case Firm_Username: return Config::FirmwareUsername;
case Firm_Message: return Config::FirmwareMessage;
default: return "";
}
}
bool GetConfigArray(ConfigEntry entry, void* 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 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);
o++;
if (o >= 12) return true;
}
return false;
}
default: return false;
}
}
FILE* OpenFile(std::string path, std::string mode, bool mustexist)
{
if (path == Config::DSiNANDPath) return reinterpret_cast<FILE*>(NANDFilePtr);
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);
return fopen(path.c_str(), mode.c_str());
}
uintptr_t FrameThreadProc = 0;
std::function<void()> ThreadEntryFunc = nullptr;
void (*ThreadStartCallback)() = nullptr;
void ThreadEntry()
{
ThreadEntryFunc();
}
Thread* Thread_Create(std::function<void()> func)
{
ThreadEntryFunc = func;
FrameThreadProc = reinterpret_cast<uintptr_t>(ThreadEntry);
return nullptr;
}
void Thread_Free(Thread* thread)
{
}
void Thread_Wait(Thread* thread) // hijacked to act as a thread start, consider this "wait for start of thread"
{
ThreadStartCallback();
}
Semaphore* Semaphore_Create()
{
return nullptr;
}
void Semaphore_Free(Semaphore* sema)
{
}
void Semaphore_Reset(Semaphore* sema)
{
}
void Semaphore_Wait(Semaphore* sema)
{
}
void Semaphore_Post(Semaphore* sema, int count)
{
}
Mutex* Mutex_Create()
{
return nullptr;
}
void Mutex_Free(Mutex* mutex)
{
}
void Mutex_Lock(Mutex* mutex)
{
}
void Mutex_Unlock(Mutex* mutex)
{
}
bool Mutex_TryLock(Mutex* mutex)
{
return false;
}
void WriteNDSSave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen)
{
NdsSaveRamIsDirty = true;
}
void WriteGBASave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen)
{
}
bool MP_Init()
{
return false;
}
void MP_DeInit()
{
}
void MP_Begin()
{
}
void MP_End()
{
}
int MP_SendPacket(u8* data, int len, u64 timestamp)
{
return 0;
}
int MP_RecvPacket(u8* data, u64* timestamp)
{
return 0;
}
int MP_SendCmd(u8* data, int len, u64 timestamp)
{
return 0;
}
int MP_SendReply(u8* data, int len, u64 timestamp, u16 aid)
{
return 0;
}
int MP_SendAck(u8* data, int len, u64 timestamp)
{
return 0;
}
int MP_RecvHostPacket(u8* data, u64* timestamp)
{
return 0;
}
u16 MP_RecvReplies(u8* data, u64 timestamp, u16 aidmask)
{
return 0;
}
bool LAN_Init()
{
return false;
}
void LAN_DeInit()
{
}
int LAN_SendPacket(u8* data, int len)
{
return 0;
}
int LAN_RecvPacket(u8* data)
{
return 0;
}
void Sleep(u64 usecs)
{
}
void Camera_Start(int num)
{
}
void Camera_Stop(int num)
{
}
void Camera_CaptureFrame(int num, u32* frame, int width, int height, bool yuv)
{
// TODO
}
}

View File

@ -0,0 +1,45 @@
#include "BizConfig.h"
#include <emulibc.h>
namespace Platform
{
struct ConfigCallbackInterface
{
bool (*GetBoolean)(ConfigEntry entry);
int (*GetInteger)(ConfigEntry entry);
void (*GetString)(ConfigEntry entry, char* buffer, int bufferSize);
bool (*GetArray)(ConfigEntry entry, void* buffer);
};
ECL_INVISIBLE static ConfigCallbackInterface ConfigCallbacks;
void SetConfigCallbacks(ConfigCallbackInterface& configCallbackInterface)
{
ConfigCallbacks = configCallbackInterface;
}
bool GetConfigBool(ConfigEntry entry)
{
return ConfigCallbacks.GetBoolean(entry);
}
int GetConfigInt(ConfigEntry entry)
{
return ConfigCallbacks.GetInteger(entry);
}
std::string GetConfigString(ConfigEntry entry)
{
char buffer[4096]{};
ConfigCallbacks.GetString(entry, buffer, sizeof(buffer));
return buffer;
}
bool GetConfigArray(ConfigEntry entry, void* data)
{
return ConfigCallbacks.GetArray(entry, data);
}
}

View File

@ -0,0 +1,14 @@
#ifndef BIZCONFIG_H
#define BIZCONFIG_H
#include "Platform.h"
namespace Platform
{
struct ConfigCallbackInterface;
void SetConfigCallbacks(ConfigCallbackInterface& configCallbackInterface);
}
#endif

View File

@ -0,0 +1,280 @@
#include "BizFile.h"
#include <emulibc.h>
#include <stdarg.h>
namespace Platform
{
struct FileCallbackInterface
{
int (*GetLength)(const char* path);
void (*GetData)(const char* path, u8* buffer);
};
ECL_INVISIBLE static FileCallbackInterface FileCallbacks;
void SetFileCallbacks(FileCallbackInterface& fileCallbackInterface)
{
FileCallbacks = fileCallbackInterface;
}
struct FileHandle
{
public:
FileHandle(u8* data_, size_t size_, FileMode mode_)
: data(data_)
, pos(0)
, size(size_)
, mode(mode_)
{
}
bool IsEndOfFile()
{
return pos == size;
}
bool ReadLine(char* str, int count)
{
if (!Readable())
{
return false;
}
if (count < 1)
{
return false;
}
size_t len = std::min(size - pos, (size_t)(count - 1));
u8* end = (u8*)memchr(&data[pos], '\n', len);
len = end ? (end + 1) - &data[pos] : len;
memcpy(str, &data[pos], len);
pos += len;
str[len] = '\0';
return true;
}
bool Seek(s64 offset, FileSeekOrigin origin)
{
size_t newPos;
switch (origin)
{
case FileSeekOrigin::Start:
newPos = offset;
break;
case FileSeekOrigin::Current:
newPos = pos + offset;
break;
case FileSeekOrigin::End:
newPos = size + offset;
break;
default:
return false;
}
if (newPos > size)
{
return false;
}
pos = newPos;
return true;
}
void Rewind()
{
pos = 0;
}
size_t Read(void* data_, u64 count)
{
if (!Readable())
{
return 0;
}
count = std::min(count, (u64)(size - pos));
memcpy(data_, data.get(), count);
pos += count;
return count;
}
size_t Write(const void* data_, u64 count)
{
if (!Writable())
{
return 0;
}
count = std::min(count, (u64)(size - pos));
memcpy(data.get(), data_, count);
pos += count;
return count;
}
size_t Length()
{
return size;
}
private:
std::shared_ptr<u8[]> data;
size_t pos, size;
FileMode mode;
bool Readable()
{
return (mode & FileMode::Read) == FileMode::Read;
}
bool Writable()
{
return (mode & FileMode::Write) == FileMode::Write;
}
};
static std::unordered_map<std::string, std::pair<std::unique_ptr<u8[]>, size_t>> FileBufferCache;
// TODO - I don't like this approach with NAND
// Perhaps instead it would be better to use FileFlush to write to disk
// (guarded by frontend determinism switch, of course)
ECL_EXPORT u32 GetNANDSize()
{
auto path = GetConfigString(ConfigEntry::DSi_NANDPath);
if (auto cache = FileBufferCache.find(path); cache != FileBufferCache.end())
{
return cache->second.second;
}
return 0;
}
ECL_EXPORT void GetNANDData(u8* buf)
{
auto path = GetConfigString(ConfigEntry::DSi_NANDPath);
if (auto cache = FileBufferCache.find(path); cache != FileBufferCache.end())
{
memcpy(buf, cache->second.first.get(), cache->second.second);
}
}
FileHandle* OpenFile(const std::string& path, FileMode mode)
{
if ((mode & FileMode::ReadWrite) == FileMode::None)
{
// something went wrong here
return nullptr;
}
if (auto cache = FileBufferCache.find(path); cache != FileBufferCache.end())
{
return new FileHandle(cache->second.first.get(), cache->second.second, mode);
}
size_t size = FileCallbacks.GetLength(path.c_str());
if (size == 0)
{
return nullptr;
}
auto data = std::make_unique<u8[]>(size);
FileCallbacks.GetData(path.c_str(), data.get());
auto ret = new FileHandle(data.get(), size, mode);
FileBufferCache.emplace(path, std::make_pair(std::move(data), size));
return ret;
}
FileHandle* OpenLocalFile(const std::string& path, FileMode mode)
{
return OpenFile(path, mode);
}
bool FileExists(const std::string& name)
{
if (auto cache = FileBufferCache.find(name); cache != FileBufferCache.end())
{
return true;
}
return FileCallbacks.GetLength(name.c_str()) > 0;
}
bool LocalFileExists(const std::string& name)
{
return FileExists(name);
}
bool CloseFile(FileHandle* file)
{
delete file;
return true;
}
bool IsEndOfFile(FileHandle* file)
{
return file->IsEndOfFile();
}
bool FileReadLine(char* str, int count, FileHandle* file)
{
return file->ReadLine(str, count);
}
bool FileSeek(FileHandle* file, s64 offset, FileSeekOrigin origin)
{
return file->Seek(offset, origin);
}
void FileRewind(FileHandle* file)
{
file->Rewind();
}
u64 FileRead(void* data, u64 size, u64 count, FileHandle* file)
{
return file->Read(data, size * count);
}
bool FileFlush(FileHandle* file)
{
return true;
}
u64 FileWrite(const void* data, u64 size, u64 count, FileHandle* file)
{
return file->Write(data, size * count);
}
u64 FileWriteFormatted(FileHandle* file, const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
size_t bufferSize = vsnprintf(nullptr, 0, fmt, args);
va_end(args);
if ((int)bufferSize < 0)
{
return 0;
}
auto buffer = std::make_unique<char[]>(bufferSize + 1);
va_start(args, fmt);
vsnprintf(buffer.get(), bufferSize + 1, fmt, args);
va_end(args);
return file->Write(buffer.get(), bufferSize);
}
u64 FileLength(FileHandle* file)
{
return file->Length();
}
}

View File

@ -0,0 +1,14 @@
#ifndef BIZFILE_H
#define BIZFILE_H
#include "Platform.h"
namespace Platform
{
struct FileCallbackInterface;
void SetFileCallbacks(FileCallbackInterface& fileCallbackInterface);
}
#endif

View File

@ -0,0 +1,39 @@
#include "BizLog.h"
#include <emulibc.h>
#include <stdarg.h>
namespace Platform
{
ECL_INVISIBLE static LogCallback_t LogCallback;
void SetLogCallback(LogCallback_t logCallback)
{
LogCallback = logCallback;
}
void Log(LogLevel level, const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
size_t bufferSize = vsnprintf(nullptr, 0, fmt, args);
va_end(args);
if ((int)bufferSize < 0)
{
return;
}
auto buffer = std::make_unique<char[]>(bufferSize + 1);
va_start(args, fmt);
vsnprintf(buffer.get(), bufferSize + 1, fmt, args);
va_end(args);
LogCallback(level, buffer.get());
}
}

View File

@ -0,0 +1,14 @@
#ifndef BIZLOG_H
#define BIZLOG_H
#include "Platform.h"
namespace Platform
{
using LogCallback_t = void (*)(LogLevel level, const char* message);
void SetLogCallback(LogCallback_t logCallback);
}
#endif

View File

@ -0,0 +1,173 @@
#include "Platform.h"
namespace Platform
{
void Init(int argc, char** argv)
{
}
void DeInit()
{
}
void SignalStop(StopReason reason)
{
}
int InstanceID()
{
return 0;
}
std::string InstanceFileSuffix()
{
return "";
}
Semaphore* Semaphore_Create()
{
return nullptr;
}
void Semaphore_Free(Semaphore* sema)
{
}
void Semaphore_Reset(Semaphore* sema)
{
}
void Semaphore_Wait(Semaphore* sema)
{
}
void Semaphore_Post(Semaphore* sema, int count)
{
}
Mutex* Mutex_Create()
{
return nullptr;
}
void Mutex_Free(Mutex* mutex)
{
}
void Mutex_Lock(Mutex* mutex)
{
}
void Mutex_Unlock(Mutex* mutex)
{
}
bool Mutex_TryLock(Mutex* mutex)
{
return false;
}
bool MP_Init()
{
return false;
}
void MP_DeInit()
{
}
void MP_Begin()
{
}
void MP_End()
{
}
int MP_SendPacket(u8* data, int len, u64 timestamp)
{
return 0;
}
int MP_RecvPacket(u8* data, u64* timestamp)
{
return 0;
}
int MP_SendCmd(u8* data, int len, u64 timestamp)
{
return 0;
}
int MP_SendReply(u8* data, int len, u64 timestamp, u16 aid)
{
return 0;
}
int MP_SendAck(u8* data, int len, u64 timestamp)
{
return 0;
}
int MP_RecvHostPacket(u8* data, u64* timestamp)
{
return 0;
}
u16 MP_RecvReplies(u8* data, u64 timestamp, u16 aidmask)
{
return 0;
}
bool LAN_Init()
{
return false;
}
void LAN_DeInit()
{
}
int LAN_SendPacket(u8* data, int len)
{
return 0;
}
int LAN_RecvPacket(u8* data)
{
return 0;
}
void Sleep(u64 usecs)
{
}
void Camera_Start(int num)
{
}
void Camera_Stop(int num)
{
}
void Camera_CaptureFrame(int num, u32* frame, int width, int height, bool yuv)
{
// TODO
}
DynamicLibrary* DynamicLibrary_Load(const char* lib)
{
return nullptr;
}
void DynamicLibrary_Unload(DynamicLibrary* lib)
{
}
void* DynamicLibrary_LoadFunction(DynamicLibrary* lib, const char* name)
{
return nullptr;
}
}

View File

@ -0,0 +1,113 @@
#include "NDS.h"
#include "NDSCart.h"
#include "GBACart.h"
#include "DSi.h"
#include "DSi_NAND.h"
#include "Platform.h"
namespace Platform
{
constexpr u32 DSIWARE_CATEGORY = 0x00030004;
static bool NdsSaveRamIsDirty = false;
static bool GbaSaveRamIsDirty = false;
ECL_EXPORT void PutSaveRam(u8* data, u32 len)
{
const u32 ndsSaveLen = NDSCart::GetSaveMemoryLength();
const u32 gbaSaveLen = GBACart::GetSaveMemoryLength();
if (len >= ndsSaveLen)
{
NDS::LoadSave(data, len);
NdsSaveRamIsDirty = false;
data += ndsSaveLen;
len -= ndsSaveLen;
if (gbaSaveLen && len >= gbaSaveLen)
{
GBACart::LoadSave(data, gbaSaveLen);
GbaSaveRamIsDirty = false;
}
}
}
ECL_EXPORT void GetSaveRam(u8* data)
{
const u32 ndsSaveLen = NDSCart::GetSaveMemoryLength();
const u32 gbaSaveLen = GBACart::GetSaveMemoryLength();
if (ndsSaveLen)
{
memcpy(data, NDSCart::GetSaveMemory(), ndsSaveLen);
NdsSaveRamIsDirty = false;
}
if (gbaSaveLen)
{
memcpy(data + ndsSaveLen, GBACart::GetSaveMemory(), gbaSaveLen);
GbaSaveRamIsDirty = false;
}
}
ECL_EXPORT u32 GetSaveRamLength()
{
return NDSCart::GetSaveMemoryLength() + GBACart::GetSaveMemoryLength();
}
ECL_EXPORT bool SaveRamIsDirty()
{
return NdsSaveRamIsDirty || GbaSaveRamIsDirty;
}
ECL_EXPORT void ImportDSiWareSavs(u32 titleId)
{
if (DSi_NAND::Init(&DSi::ARM7iBIOS[0x8308]))
{
DSi_NAND::ImportTitleData(DSIWARE_CATEGORY, titleId, DSi_NAND::TitleData_PublicSav, "public.sav");
DSi_NAND::ImportTitleData(DSIWARE_CATEGORY, titleId, DSi_NAND::TitleData_PrivateSav, "private.sav");
DSi_NAND::ImportTitleData(DSIWARE_CATEGORY, titleId, DSi_NAND::TitleData_BannerSav, "banner.sav");
DSi_NAND::DeInit();
}
}
ECL_EXPORT void ExportDSiWareSavs(u32 titleId)
{
if (DSi_NAND::Init(&DSi::ARM7iBIOS[0x8308]))
{
DSi_NAND::ExportTitleData(DSIWARE_CATEGORY, titleId, DSi_NAND::TitleData_PublicSav, "public.sav");
DSi_NAND::ExportTitleData(DSIWARE_CATEGORY, titleId, DSi_NAND::TitleData_PrivateSav, "private.sav");
DSi_NAND::ExportTitleData(DSIWARE_CATEGORY, titleId, DSi_NAND::TitleData_BannerSav, "banner.sav");
DSi_NAND::DeInit();
}
}
ECL_EXPORT void DSiWareSavsLength(u32 titleId, u32* publicSavSize, u32* privateSavSize, u32* bannerSavSize)
{
*publicSavSize = *privateSavSize = *bannerSavSize = 0;
if (DSi_NAND::Init(&DSi::ARM7iBIOS[0x8308]))
{
u32 version;
NDSHeader header{};
DSi_NAND::GetTitleInfo(DSIWARE_CATEGORY, titleId, version, &header, nullptr);
*publicSavSize = header.DSiPublicSavSize;
*privateSavSize = header.DSiPrivateSavSize;
*bannerSavSize = (header.AppFlags & 0x04) ? 0x4000 : 0;
DSi_NAND::DeInit();
}
}
void WriteNDSSave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen)
{
NdsSaveRamIsDirty = true;
}
void WriteGBASave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen)
{
GbaSaveRamIsDirty = true;
}
}

View File

@ -0,0 +1,44 @@
#include "Platform.h"
#include <emulibc.h>
namespace Platform
{
static uintptr_t FrameThreadProc = 0;
static std::function<void()> ThreadEntryFunc = nullptr;
static void (*ThreadStartCallback)() = nullptr;
ECL_EXPORT uintptr_t GetFrameThreadProc()
{
return FrameThreadProc;
}
ECL_EXPORT void SetThreadStartCallback(void (*callback)())
{
ThreadStartCallback = callback;
}
static void ThreadEntry()
{
ThreadEntryFunc();
}
Thread* Thread_Create(std::function<void()> func)
{
ThreadEntryFunc = func;
FrameThreadProc = reinterpret_cast<uintptr_t>(ThreadEntry);
return nullptr;
}
void Thread_Free(Thread* thread)
{
}
// hijacked to act as a thread start, consider this "wait for start of thread"
void Thread_Wait(Thread* thread)
{
ThreadStartCallback();
}
}

View File

@ -0,0 +1,642 @@
static const std::unordered_map<u32, GBASaveType> GbaCrcSaveTypeOverrides =
{
{ 0xEF365600, GBASaveType::SRAM },
{ 0xE905937F, GBASaveType::FLASH512 },
{ 0x689CAF43, GBASaveType::SRAM },
{ 0x4E0F10FA, GBASaveType::EEPROM },
{ 0x106ED779, GBASaveType::EEPROM },
{ 0x91344285, GBASaveType::SRAM },
{ 0xBA1F514A, GBASaveType::NONE },
{ 0x11870BD9, GBASaveType::SRAM },
{ 0x86A602AB, GBASaveType::NONE },
{ 0x9D5E128C, GBASaveType::SRAM },
{ 0xD05C86BB, GBASaveType::NONE },
{ 0x0D72F2CC, GBASaveType::SRAM },
{ 0xCA9B82DD, GBASaveType::SRAM },
{ 0x28BAA30E, GBASaveType::SRAM },
{ 0x35536183, GBASaveType::SRAM },
{ 0xF5C8D8E8, GBASaveType::SRAM },
{ 0x93B6599E, GBASaveType::SRAM },
{ 0x284E3092, GBASaveType::SRAM },
{ 0xE8156354, GBASaveType::SRAM },
{ 0xD97DBFEC, GBASaveType::SRAM },
{ 0xD0C91F74, GBASaveType::SRAM },
{ 0x3D803E41, GBASaveType::EEPROM },
{ 0x40A48276, GBASaveType::EEPROM },
{ 0x10F9EDA4, GBASaveType::EEPROM },
{ 0x26321120, GBASaveType::EEPROM },
{ 0x2C79C2DE, GBASaveType::EEPROM },
{ 0x639E9D3B, GBASaveType::EEPROM },
{ 0x153F73D1, GBASaveType::NONE },
{ 0xF74C1FA3, GBASaveType::NONE },
{ 0x3F15FEAA, GBASaveType::NONE },
{ 0x3FCAF2D0, GBASaveType::EEPROM },
{ 0x8DD750EF, GBASaveType::EEPROM },
{ 0x2C613DEF, GBASaveType::NONE },
{ 0x285FE485, GBASaveType::EEPROM },
{ 0xB61F99D4, GBASaveType::EEPROM },
{ 0xEEA68C2E, GBASaveType::EEPROM },
{ 0x6E140BFA, GBASaveType::EEPROM },
{ 0x01B4D95E, GBASaveType::EEPROM },
{ 0xF87EA3C3, GBASaveType::EEPROM },
{ 0xE718D850, GBASaveType::EEPROM },
{ 0xBEE3055A, GBASaveType::EEPROM },
{ 0x4EF93D41, GBASaveType::EEPROM },
{ 0x6A5BD4F0, GBASaveType::EEPROM },
{ 0x170CC574, GBASaveType::EEPROM },
{ 0xDFF9A0B1, GBASaveType::NONE },
{ 0x59F208FC, GBASaveType::EEPROM },
{ 0x3524F206, GBASaveType::NONE },
{ 0x50927F3E, GBASaveType::EEPROM },
{ 0xB99D538B, GBASaveType::SRAM },
{ 0xFB67EFBC, GBASaveType::SRAM },
{ 0xC90732D5, GBASaveType::NONE },
{ 0xE144DED2, GBASaveType::EEPROM },
{ 0xE37A0705, GBASaveType::NONE },
{ 0xA519FEB5, GBASaveType::EEPROM },
{ 0xE0E153B7, GBASaveType::SRAM },
{ 0x3A1E789A, GBASaveType::SRAM },
{ 0x88C1B562, GBASaveType::SRAM },
{ 0x247EEB20, GBASaveType::SRAM },
{ 0x379B3248, GBASaveType::SRAM },
{ 0xE0C4FD69, GBASaveType::SRAM },
{ 0x521B3091, GBASaveType::SRAM },
{ 0x125C2E01, GBASaveType::SRAM },
{ 0x5264C730, GBASaveType::SRAM },
{ 0xB789DAC5, GBASaveType::SRAM },
{ 0xC0E9EEBE, GBASaveType::SRAM },
{ 0x60C38E52, GBASaveType::SRAM },
{ 0x91B16892, GBASaveType::SRAM },
{ 0x5F595157, GBASaveType::SRAM },
{ 0x529F06A4, GBASaveType::SRAM },
{ 0x1B8713C7, GBASaveType::SRAM },
{ 0x2A524221, GBASaveType::SRAM },
{ 0x0BA2FD1F, GBASaveType::SRAM },
{ 0xF0C10E72, GBASaveType::SRAM },
{ 0xCD9D8972, GBASaveType::SRAM },
{ 0x335C5855, GBASaveType::SRAM },
{ 0x4A805ED1, GBASaveType::SRAM },
{ 0x93D3B218, GBASaveType::SRAM },
{ 0x9DECC754, GBASaveType::SRAM },
{ 0x1127B83E, GBASaveType::NONE },
{ 0xB4090702, GBASaveType::EEPROM },
{ 0xCE2B48C4, GBASaveType::EEPROM },
{ 0xF8AF3359, GBASaveType::SRAM },
{ 0xD38763E1, GBASaveType::SRAM },
{ 0xB40D6854, GBASaveType::SRAM },
{ 0x8146A270, GBASaveType::SRAM },
{ 0x55CAE46A, GBASaveType::NONE },
{ 0x2C00B4E6, GBASaveType::SRAM },
{ 0xA7A84C31, GBASaveType::EEPROM512 },
{ 0xB107C73D, GBASaveType::EEPROM512 },
{ 0xBA829EAC, GBASaveType::EEPROM512 },
{ 0x14E3EBCC, GBASaveType::EEPROM512 },
{ 0xA934C4EE, GBASaveType::EEPROM },
{ 0xE37CA939, GBASaveType::EEPROM },
{ 0x709B5289, GBASaveType::EEPROM },
{ 0x03294511, GBASaveType::EEPROM512 },
{ 0x9AF01F01, GBASaveType::EEPROM },
{ 0x5F1E5A48, GBASaveType::EEPROM512 },
{ 0x6CD93829, GBASaveType::EEPROM },
{ 0x92FDB8D6, GBASaveType::EEPROM512 },
{ 0xFBFF3F04, GBASaveType::EEPROM },
{ 0xF5801BD8, GBASaveType::EEPROM512 },
{ 0x536669C1, GBASaveType::SRAM },
{ 0xAD17D41E, GBASaveType::SRAM },
{ 0x81462ABA, GBASaveType::SRAM },
{ 0x5A5EF8E3, GBASaveType::SRAM },
{ 0x8EE0ED6F, GBASaveType::SRAM },
{ 0xAC355418, GBASaveType::SRAM },
{ 0x95CCC956, GBASaveType::NONE },
{ 0xF424858F, GBASaveType::NONE },
{ 0x922D805A, GBASaveType::NONE },
{ 0x7960926C, GBASaveType::SRAM },
{ 0x5B8AAA03, GBASaveType::SRAM },
{ 0x25B0B122, GBASaveType::SRAM },
{ 0xC1F2B5EC, GBASaveType::SRAM },
{ 0x872BC075, GBASaveType::NONE },
{ 0x0A517352, GBASaveType::SRAM },
{ 0x7E90CEA2, GBASaveType::SRAM },
{ 0xF1098A5F, GBASaveType::SRAM },
{ 0x85C837AF, GBASaveType::SRAM },
{ 0x257E49F9, GBASaveType::NONE },
{ 0xD1183501, GBASaveType::EEPROM },
{ 0xABAF519C, GBASaveType::EEPROM },
{ 0xA79872FE, GBASaveType::NONE },
{ 0xB3780A4F, GBASaveType::EEPROM },
{ 0x68076B62, GBASaveType::EEPROM },
{ 0x4E63DCE0, GBASaveType::FLASH512 },
{ 0xE6F5BDD5, GBASaveType::FLASH512 },
{ 0xD9F19D76, GBASaveType::SRAM },
{ 0xD125A6BB, GBASaveType::SRAM },
{ 0xC4838CFA, GBASaveType::EEPROM },
{ 0x7EE24793, GBASaveType::EEPROM },
{ 0x41E7180E, GBASaveType::EEPROM },
{ 0xECE42D0E, GBASaveType::EEPROM },
{ 0xFFDA95BE, GBASaveType::EEPROM },
{ 0xB7F022B9, GBASaveType::EEPROM },
{ 0x1D910A62, GBASaveType::EEPROM },
{ 0xF094A4CB, GBASaveType::EEPROM },
{ 0x9CD07025, GBASaveType::EEPROM },
{ 0xBAA4A82B, GBASaveType::EEPROM },
{ 0xC8C889E2, GBASaveType::EEPROM },
{ 0xDEA3B767, GBASaveType::SRAM },
{ 0xA47246AE, GBASaveType::SRAM },
{ 0xD2B431F8, GBASaveType::SRAM },
{ 0x9D76826F, GBASaveType::SRAM },
{ 0x2653401A, GBASaveType::SRAM },
{ 0xB3005195, GBASaveType::SRAM },
{ 0xAA14B198, GBASaveType::EEPROM },
{ 0x195D7EA7, GBASaveType::EEPROM },
{ 0xEBF89B0D, GBASaveType::EEPROM },
{ 0x40958C2C, GBASaveType::EEPROM },
{ 0x304BDFC3, GBASaveType::EEPROM },
{ 0xA0EBB191, GBASaveType::NONE },
{ 0x0E2ACA9E, GBASaveType::EEPROM },
{ 0x526FDFFF, GBASaveType::EEPROM },
{ 0x8EA9AFCC, GBASaveType::EEPROM },
{ 0xCA893BC4, GBASaveType::NONE },
{ 0xEC7869AE, GBASaveType::SRAM },
{ 0x02F51696, GBASaveType::SRAM },
{ 0x9AD45607, GBASaveType::FLASH512 },
{ 0xA646601B, GBASaveType::FLASH512 },
{ 0xFB6C590F, GBASaveType::EEPROM },
{ 0xE368A67A, GBASaveType::SRAM },
{ 0x2912E76E, GBASaveType::FLASH512 },
{ 0x2AD292A4, GBASaveType::FLASH512 },
{ 0x9A704AF8, GBASaveType::FLASH512 },
{ 0xD111CC19, GBASaveType::FLASH512 },
{ 0xAE57B39E, GBASaveType::FLASH512 },
{ 0x6346FD59, GBASaveType::FLASH512 },
{ 0x6CE771A5, GBASaveType::EEPROM },
{ 0xCD2604DD, GBASaveType::EEPROM },
{ 0xE4628D75, GBASaveType::EEPROM },
{ 0x86C4F772, GBASaveType::SRAM },
{ 0x1A1397DE, GBASaveType::SRAM },
{ 0x96B54925, GBASaveType::EEPROM },
{ 0xD047FFDF, GBASaveType::EEPROM },
};
static const std::unordered_map<std::string, GBASaveType> GbaGameIdSaveTypeOverrides =
{
{ "A2GJ", GBASaveType::EEPROM },
{ "A2HJ", GBASaveType::EEPROM },
{ "A2IJ", GBASaveType::EEPROM },
{ "A2JJ", GBASaveType::EEPROM },
{ "A2OJ", GBASaveType::EEPROM },
{ "A2QE", GBASaveType::SRAM },
{ "A2QJ", GBASaveType::SRAM },
{ "A2SE", GBASaveType::EEPROM },
{ "A2SP", GBASaveType::EEPROM },
{ "A2VJ", GBASaveType::EEPROM },
{ "A2YE", GBASaveType::NONE },
{ "A3AC", GBASaveType::EEPROM },
{ "A3DE", GBASaveType::EEPROM512 },
{ "A3DJ", GBASaveType::EEPROM512 },
{ "A3IJ", GBASaveType::EEPROM },
{ "A3NJ", GBASaveType::SRAM },
{ "A3OJ", GBASaveType::SRAM },
{ "A4GE", GBASaveType::EEPROM },
{ "A4GJ", GBASaveType::EEPROM },
{ "A4LJ", GBASaveType::EEPROM },
{ "A4VJ", GBASaveType::SRAM },
{ "A56J", GBASaveType::EEPROM },
{ "A57J", GBASaveType::SRAM },
{ "A59J", GBASaveType::EEPROM },
{ "A5CE", GBASaveType::EEPROM },
{ "A5CP", GBASaveType::EEPROM },
{ "A5SJ", GBASaveType::EEPROM },
{ "A63J", GBASaveType::EEPROM },
{ "A64J", GBASaveType::EEPROM },
{ "A6CJ", GBASaveType::SRAM },
{ "A6GJ", GBASaveType::SRAM },
{ "A6OE", GBASaveType::EEPROM },
{ "A6OJ", GBASaveType::EEPROM },
{ "A6OP", GBASaveType::EEPROM },
{ "A6RE", GBASaveType::SRAM },
{ "A82J", GBASaveType::EEPROM },
{ "A83J", GBASaveType::EEPROM },
{ "A85J", GBASaveType::EEPROM },
{ "A87J", GBASaveType::EEPROM },
{ "A8BS", GBASaveType::EEPROM },
{ "A8LJ", GBASaveType::SRAM },
{ "A8OJ", GBASaveType::EEPROM },
{ "A8RJ", GBASaveType::SRAM },
{ "A8ZJ", GBASaveType::EEPROM },
{ "A9BS", GBASaveType::EEPROM },
{ "A9HJ", GBASaveType::EEPROM },
{ "A9LJ", GBASaveType::SRAM },
{ "A9ME", GBASaveType::SRAM },
{ "A9MP", GBASaveType::SRAM },
{ "A9TJ", GBASaveType::EEPROM },
{ "AA2C", GBASaveType::EEPROM },
{ "AA2E", GBASaveType::EEPROM },
{ "AA2J", GBASaveType::EEPROM },
{ "AA2P", GBASaveType::EEPROM },
{ "AABE", GBASaveType::EEPROM },
{ "AABJ", GBASaveType::SRAM },
{ "AABP", GBASaveType::EEPROM },
{ "AAGJ", GBASaveType::EEPROM },
{ "AALJ", GBASaveType::EEPROM },
{ "AANJ", GBASaveType::SRAM },
{ "AAPJ", GBASaveType::EEPROM },
{ "AASJ", GBASaveType::EEPROM },
{ "AAXJ", GBASaveType::EEPROM },
{ "AB3E", GBASaveType::EEPROM },
{ "AB4E", GBASaveType::EEPROM },
{ "AB4J", GBASaveType::EEPROM },
{ "ABFJ", GBASaveType::SRAM },
{ "ABGJ", GBASaveType::EEPROM },
{ "ABJE", GBASaveType::EEPROM },
{ "ABJP", GBASaveType::EEPROM },
{ "ABPE", GBASaveType::SRAM },
{ "AC4J", GBASaveType::EEPROM },
{ "AC5E", GBASaveType::SRAM },
{ "ACBE", GBASaveType::EEPROM },
{ "ACBJ", GBASaveType::EEPROM },
{ "ACOJ", GBASaveType::EEPROM },
{ "ACTX", GBASaveType::EEPROM },
{ "ACTY", GBASaveType::EEPROM },
{ "AD4P", GBASaveType::SRAM },
{ "ADDJ", GBASaveType::EEPROM },
{ "ADPJ", GBASaveType::EEPROM },
{ "ADQE", GBASaveType::SRAM },
{ "ADQJ", GBASaveType::SRAM },
{ "ADQP", GBASaveType::SRAM },
{ "ADZE", GBASaveType::SRAM },
{ "AEAJ", GBASaveType::SRAM },
{ "AECJ", GBASaveType::SRAM },
{ "AEHJ", GBASaveType::EEPROM },
{ "AEPP", GBASaveType::EEPROM },
{ "AEWJ", GBASaveType::EEPROM },
{ "AF3J", GBASaveType::EEPROM },
{ "AF7J", GBASaveType::EEPROM },
{ "AFNJ", GBASaveType::EEPROM },
{ "AFUJ", GBASaveType::EEPROM },
{ "AG6J", GBASaveType::SRAM },
{ "AG9J", GBASaveType::SRAM },
{ "AGDE", GBASaveType::SRAM },
{ "AGNJ", GBASaveType::EEPROM },
{ "AH3E", GBASaveType::SRAM },
{ "AH3J", GBASaveType::SRAM },
{ "AH3P", GBASaveType::SRAM },
{ "AH5J", GBASaveType::SRAM },
{ "AH7J", GBASaveType::EEPROM },
{ "AHAJ", GBASaveType::EEPROM },
{ "AHHE", GBASaveType::EEPROM },
{ "AHIJ", GBASaveType::EEPROM },
{ "AHKJ", GBASaveType::SRAM },
{ "AHMJ", GBASaveType::EEPROM512 },
{ "AHVJ", GBASaveType::EEPROM },
{ "AHXJ", GBASaveType::EEPROM },
{ "AHZJ", GBASaveType::EEPROM },
{ "AI7J", GBASaveType::EEPROM },
{ "AISP", GBASaveType::EEPROM },
{ "AJ3E", GBASaveType::SRAM },
{ "AJ3P", GBASaveType::SRAM },
{ "AJKJ", GBASaveType::EEPROM },
{ "AJWJ", GBASaveType::EEPROM },
{ "AK7J", GBASaveType::EEPROM },
{ "AKDJ", GBASaveType::SRAM },
{ "AKEJ", GBASaveType::SRAM },
{ "AKGE", GBASaveType::EEPROM },
{ "AKGJ", GBASaveType::EEPROM },
{ "AKGP", GBASaveType::EEPROM },
{ "AKTJ", GBASaveType::EEPROM },
{ "AKVJ", GBASaveType::EEPROM },
{ "AL4E", GBASaveType::SRAM },
{ "AL4J", GBASaveType::SRAM },
{ "ALFE", GBASaveType::EEPROM },
{ "ALFJ", GBASaveType::EEPROM },
{ "ALFP", GBASaveType::EEPROM },
{ "ALJE", GBASaveType::EEPROM },
{ "ALNE", GBASaveType::EEPROM },
{ "ALOE", GBASaveType::EEPROM },
{ "ALOP", GBASaveType::EEPROM },
{ "ALQJ", GBASaveType::SRAM },
{ "ALUE", GBASaveType::EEPROM512 },
{ "AM7J", GBASaveType::SRAM },
{ "AMFE", GBASaveType::SRAM },
{ "AMFJ", GBASaveType::SRAM },
{ "AMGJ", GBASaveType::EEPROM },
{ "AMGP", GBASaveType::EEPROM },
{ "AMHE", GBASaveType::EEPROM },
{ "AMHJ", GBASaveType::EEPROM },
{ "AMHP", GBASaveType::EEPROM },
{ "AMYE", GBASaveType::EEPROM },
{ "AMYJ", GBASaveType::EEPROM },
{ "AMYP", GBASaveType::EEPROM },
{ "AN3E", GBASaveType::EEPROM },
{ "AN3J", GBASaveType::EEPROM },
{ "AN3X", GBASaveType::EEPROM },
{ "AN5J", GBASaveType::EEPROM },
{ "AN7J", GBASaveType::EEPROM },
{ "AN8E", GBASaveType::EEPROM },
{ "AN8J", GBASaveType::EEPROM },
{ "AN8P", GBASaveType::EEPROM },
{ "AN9J", GBASaveType::EEPROM },
{ "ANJE", GBASaveType::EEPROM },
{ "ANLE", GBASaveType::EEPROM },
{ "ANNJ", GBASaveType::EEPROM },
{ "ANOJ", GBASaveType::SRAM },
{ "ANSJ", GBASaveType::EEPROM },
{ "ANTJ", GBASaveType::SRAM },
{ "ANYJ", GBASaveType::SRAM },
{ "AO2J", GBASaveType::EEPROM },
{ "AOPJ", GBASaveType::EEPROM },
{ "AOWE", GBASaveType::EEPROM },
{ "AOWP", GBASaveType::EEPROM },
{ "AP9P", GBASaveType::SRAM },
{ "APNJ", GBASaveType::EEPROM },
{ "APUJ", GBASaveType::EEPROM },
{ "AQ2J", GBASaveType::SRAM },
{ "AQ2P", GBASaveType::SRAM },
{ "AR8E", GBASaveType::EEPROM512 },
{ "ARJJ", GBASaveType::EEPROM },
{ "ARNJ", GBASaveType::EEPROM },
{ "AROP", GBASaveType::EEPROM512 },
{ "ASFJ", GBASaveType::EEPROM },
{ "AT3D", GBASaveType::EEPROM },
{ "AT3E", GBASaveType::EEPROM },
{ "AT3F", GBASaveType::EEPROM },
{ "AT6E", GBASaveType::EEPROM },
{ "ATBJ", GBASaveType::EEPROM },
{ "ATDJ", GBASaveType::SRAM },
{ "ATFP", GBASaveType::EEPROM },
{ "ATYJ", GBASaveType::EEPROM },
{ "ATZJ", GBASaveType::SRAM },
{ "AUCJ", GBASaveType::EEPROM },
{ "AUEJ", GBASaveType::SRAM },
{ "AWIJ", GBASaveType::EEPROM },
{ "AWKJ", GBASaveType::EEPROM },
{ "AWUE", GBASaveType::EEPROM },
{ "AWUP", GBASaveType::EEPROM },
{ "AWXJ", GBASaveType::EEPROM },
{ "AWZJ", GBASaveType::SRAM },
{ "AX2E", GBASaveType::EEPROM },
{ "AX2P", GBASaveType::EEPROM },
{ "AXBJ", GBASaveType::EEPROM },
{ "AY2P", GBASaveType::EEPROM },
{ "AY8E", GBASaveType::SRAM },
{ "AY8J", GBASaveType::SRAM },
{ "AY8P", GBASaveType::SRAM },
{ "AYAJ", GBASaveType::SRAM },
{ "AYCE", GBASaveType::EEPROM },
{ "AYCP", GBASaveType::EEPROM },
{ "AYHE", GBASaveType::EEPROM512 },
{ "AYLE", GBASaveType::SRAM },
{ "AYLJ", GBASaveType::SRAM },
{ "AYMJ", GBASaveType::SRAM },
{ "AYSJ", GBASaveType::EEPROM },
{ "AZ2E", GBASaveType::SRAM },
{ "AZ2J", GBASaveType::SRAM },
{ "AZAJ", GBASaveType::EEPROM },
{ "AZBJ", GBASaveType::EEPROM },
{ "AZLE", GBASaveType::EEPROM },
{ "AZLJ", GBASaveType::EEPROM },
{ "AZLP", GBASaveType::EEPROM },
{ "AZUE", GBASaveType::EEPROM },
{ "AZUJ", GBASaveType::EEPROM },
{ "AZUP", GBASaveType::EEPROM },
{ "B08J", GBASaveType::EEPROM },
{ "B26E", GBASaveType::EEPROM },
{ "B2DE", GBASaveType::EEPROM },
{ "B2DJ", GBASaveType::EEPROM },
{ "B2DP", GBASaveType::EEPROM },
{ "B2KJ", GBASaveType::EEPROM },
{ "B2OJ", GBASaveType::EEPROM },
{ "B2TE", GBASaveType::EEPROM },
{ "B34E", GBASaveType::EEPROM },
{ "B3CJ", GBASaveType::EEPROM },
{ "B3JE", GBASaveType::NONE },
{ "B3JP", GBASaveType::NONE },
{ "B3KJ", GBASaveType::SRAM },
{ "B3PJ", GBASaveType::EEPROM },
{ "B3TJ", GBASaveType::EEPROM },
{ "B3YE", GBASaveType::EEPROM },
{ "B3YP", GBASaveType::EEPROM },
{ "B4GJ", GBASaveType::SRAM },
{ "B4KJ", GBASaveType::EEPROM },
{ "B4LJ", GBASaveType::EEPROM },
{ "B4PJ", GBASaveType::EEPROM },
{ "B4RJ", GBASaveType::EEPROM },
{ "B4SJ", GBASaveType::SRAM },
{ "B52P", GBASaveType::EEPROM },
{ "B53E", GBASaveType::EEPROM },
{ "B54E", GBASaveType::EEPROM },
{ "B5AP", GBASaveType::EEPROM },
{ "B6ME", GBASaveType::EEPROM },
{ "B7ME", GBASaveType::EEPROM },
{ "B8AE", GBASaveType::EEPROM },
{ "B8CE", GBASaveType::SRAM },
{ "B8CJ", GBASaveType::SRAM },
{ "B8CP", GBASaveType::SRAM },
{ "B8SE", GBASaveType::EEPROM },
{ "BAQP", GBASaveType::EEPROM },
{ "BAXJ", GBASaveType::SRAM },
{ "BAZJ", GBASaveType::EEPROM },
{ "BB2E", GBASaveType::EEPROM },
{ "BB2P", GBASaveType::EEPROM },
{ "BBME", GBASaveType::EEPROM },
{ "BBMJ", GBASaveType::EEPROM },
{ "BBYE", GBASaveType::EEPROM },
{ "BBYX", GBASaveType::EEPROM },
{ "BC2J", GBASaveType::EEPROM },
{ "BC2S", GBASaveType::EEPROM },
{ "BCME", GBASaveType::EEPROM },
{ "BCMJ", GBASaveType::EEPROM },
{ "BCSP", GBASaveType::EEPROM },
{ "BDHJ", GBASaveType::SRAM },
{ "BDKJ", GBASaveType::EEPROM },
{ "BDTE", GBASaveType::EEPROM },
{ "BDTJ", GBASaveType::EEPROM },
{ "BDXE", GBASaveType::EEPROM },
{ "BDXJ", GBASaveType::EEPROM },
{ "BDYJ", GBASaveType::SRAM },
{ "BECJ", GBASaveType::EEPROM },
{ "BEFE", GBASaveType::EEPROM },
{ "BEFP", GBASaveType::EEPROM },
{ "BEJJ", GBASaveType::EEPROM },
{ "BENE", GBASaveType::EEPROM },
{ "BENP", GBASaveType::EEPROM },
{ "BEYE", GBASaveType::EEPROM },
{ "BEYP", GBASaveType::EEPROM },
{ "BFCJ", GBASaveType::EEPROM },
{ "BFEE", GBASaveType::EEPROM },
{ "BFEP", GBASaveType::EEPROM },
{ "BFJE", GBASaveType::EEPROM },
{ "BFJJ", GBASaveType::EEPROM },
{ "BFMJ", GBASaveType::EEPROM },
{ "BFQE", GBASaveType::EEPROM },
{ "BFRP", GBASaveType::EEPROM },
{ "BG3E", GBASaveType::EEPROM },
{ "BG8J", GBASaveType::EEPROM },
{ "BGAJ", GBASaveType::EEPROM },
{ "BGBJ", GBASaveType::EEPROM },
{ "BGHJ", GBASaveType::EEPROM },
{ "BGMJ", GBASaveType::EEPROM },
{ "BGNJ", GBASaveType::EEPROM },
{ "BGQE", GBASaveType::EEPROM },
{ "BGXJ", GBASaveType::EEPROM },
{ "BH9E", GBASaveType::EEPROM },
{ "BH9P", GBASaveType::EEPROM },
{ "BH9X", GBASaveType::EEPROM },
{ "BHBE", GBASaveType::EEPROM },
{ "BHBP", GBASaveType::EEPROM },
{ "BHCJ", GBASaveType::EEPROM },
{ "BHFJ", GBASaveType::EEPROM },
{ "BHGE", GBASaveType::EEPROM },
{ "BHGP", GBASaveType::EEPROM },
{ "BHLE", GBASaveType::SRAM },
{ "BHTE", GBASaveType::EEPROM },
{ "BHTJ", GBASaveType::EEPROM },
{ "BHUE", GBASaveType::EEPROM },
{ "BHUP", GBASaveType::EEPROM },
{ "BIMP", GBASaveType::EEPROM },
{ "BIMX", GBASaveType::EEPROM },
{ "BIPJ", GBASaveType::EEPROM },
{ "BISJ", GBASaveType::EEPROM },
{ "BITJ", GBASaveType::EEPROM },
{ "BJPP", GBASaveType::EEPROM },
{ "BK2J", GBASaveType::SRAM },
{ "BK3J", GBASaveType::EEPROM },
{ "BK4J", GBASaveType::SRAM },
{ "BK5J", GBASaveType::SRAM },
{ "BKBJ", GBASaveType::SRAM },
{ "BKCJ", GBASaveType::EEPROM },
{ "BKCS", GBASaveType::EEPROM },
{ "BKEJ", GBASaveType::EEPROM },
{ "BKIJ", GBASaveType::EEPROM },
{ "BKKJ", GBASaveType::EEPROM },
{ "BKME", GBASaveType::EEPROM512 },
{ "BKMJ", GBASaveType::EEPROM512 },
{ "BKMP", GBASaveType::EEPROM512 },
{ "BKOJ", GBASaveType::EEPROM },
{ "BKUJ", GBASaveType::EEPROM },
{ "BKVJ", GBASaveType::EEPROM },
{ "BKZE", GBASaveType::EEPROM },
{ "BKZI", GBASaveType::EEPROM },
{ "BKZS", GBASaveType::EEPROM },
{ "BKZX", GBASaveType::EEPROM },
{ "BL9E", GBASaveType::EEPROM },
{ "BLDP", GBASaveType::EEPROM },
{ "BLDS", GBASaveType::EEPROM },
{ "BLFE", GBASaveType::EEPROM },
{ "BLIJ", GBASaveType::EEPROM },
{ "BLME", GBASaveType::EEPROM },
{ "BLMP", GBASaveType::EEPROM },
{ "BM2J", GBASaveType::EEPROM },
{ "BM9J", GBASaveType::SRAM },
{ "BMDE", GBASaveType::EEPROM },
{ "BMFE", GBASaveType::EEPROM },
{ "BMOJ", GBASaveType::SRAM },
{ "BMPJ", GBASaveType::SRAM },
{ "BMRJ", GBASaveType::EEPROM },
{ "BMWJ", GBASaveType::EEPROM },
{ "BMYJ", GBASaveType::SRAM },
{ "BMZJ", GBASaveType::EEPROM },
{ "BMZP", GBASaveType::EEPROM },
{ "BNBE", GBASaveType::EEPROM },
{ "BNGJ", GBASaveType::SRAM },
{ "BNMJ", GBASaveType::SRAM },
{ "BO2J", GBASaveType::EEPROM },
{ "BO3J", GBASaveType::EEPROM },
{ "BO8K", GBASaveType::EEPROM },
{ "BOBJ", GBASaveType::SRAM },
{ "BOVJ", GBASaveType::EEPROM },
{ "BP3J", GBASaveType::EEPROM },
{ "BPIE", GBASaveType::EEPROM },
{ "BPNJ", GBASaveType::EEPROM },
{ "BPPE", GBASaveType::SRAM },
{ "BPPJ", GBASaveType::SRAM },
{ "BPPP", GBASaveType::SRAM },
{ "BPQJ", GBASaveType::EEPROM },
{ "BPVP", GBASaveType::EEPROM },
{ "BPVX", GBASaveType::EEPROM },
{ "BPVY", GBASaveType::EEPROM },
{ "BQAJ", GBASaveType::EEPROM },
{ "BQBJ", GBASaveType::EEPROM },
{ "BQSJ", GBASaveType::EEPROM },
{ "BQTF", GBASaveType::EEPROM },
{ "BQTP", GBASaveType::EEPROM },
{ "BQTX", GBASaveType::EEPROM },
{ "BQVE", GBASaveType::EEPROM },
{ "BQVP", GBASaveType::EEPROM },
{ "BQVX", GBASaveType::EEPROM },
{ "BQZE", GBASaveType::EEPROM },
{ "BQZP", GBASaveType::EEPROM },
{ "BREE", GBASaveType::SRAM },
{ "BREJ", GBASaveType::SRAM },
{ "BRGE", GBASaveType::EEPROM },
{ "BRIJ", GBASaveType::SRAM },
{ "BRLP", GBASaveType::EEPROM },
{ "BRPJ", GBASaveType::EEPROM },
{ "BS5J", GBASaveType::EEPROM },
{ "BSFJ", GBASaveType::EEPROM },
{ "BSKE", GBASaveType::EEPROM },
{ "BSKJ", GBASaveType::EEPROM },
{ "BT2E", GBASaveType::EEPROM },
{ "BT2P", GBASaveType::EEPROM },
{ "BT3J", GBASaveType::EEPROM },
{ "BT4E", GBASaveType::EEPROM },
{ "BT8E", GBASaveType::EEPROM },
{ "BT8P", GBASaveType::EEPROM },
{ "BTAE", GBASaveType::EEPROM },
{ "BTAJ", GBASaveType::EEPROM },
{ "BTAP", GBASaveType::EEPROM },
{ "BTOE", GBASaveType::EEPROM },
{ "BTVE", GBASaveType::EEPROM },
{ "BTYE", GBASaveType::EEPROM },
{ "BUCE", GBASaveType::EEPROM },
{ "BUFE", GBASaveType::EEPROM },
{ "BUHJ", GBASaveType::EEPROM512 },
{ "BUOE", GBASaveType::EEPROM },
{ "BUOJ", GBASaveType::EEPROM },
{ "BUOP", GBASaveType::EEPROM },
{ "BURE", GBASaveType::EEPROM },
{ "BUZE", GBASaveType::EEPROM },
{ "BVHJ", GBASaveType::SRAM },
{ "BWDJ", GBASaveType::EEPROM },
{ "BWIE", GBASaveType::EEPROM },
{ "BWIP", GBASaveType::EEPROM },
{ "BWOP", GBASaveType::EEPROM },
{ "BWSE", GBASaveType::SRAM },
{ "BWXJ", GBASaveType::EEPROM },
{ "BX4E", GBASaveType::EEPROM },
{ "BX5E", GBASaveType::EEPROM },
{ "BX5P", GBASaveType::EEPROM },
{ "BXFD", GBASaveType::EEPROM },
{ "BXFE", GBASaveType::EEPROM },
{ "BXFP", GBASaveType::EEPROM },
{ "BXKE", GBASaveType::SRAM },
{ "BXKP", GBASaveType::SRAM },
{ "BY6E", GBASaveType::SRAM },
{ "BY6J", GBASaveType::SRAM },
{ "BY6P", GBASaveType::SRAM },
{ "BYDE", GBASaveType::SRAM },
{ "BYDP", GBASaveType::SRAM },
{ "BYPP", GBASaveType::EEPROM },
{ "BYPX", GBASaveType::EEPROM },
{ "BYPY", GBASaveType::EEPROM },
{ "BYSJ", GBASaveType::SRAM },
{ "BYUE", GBASaveType::EEPROM },
{ "BYUJ", GBASaveType::EEPROM },
{ "BYUP", GBASaveType::EEPROM },
{ "BZFJ", GBASaveType::SRAM },
{ "BZME", GBASaveType::EEPROM },
{ "BZMP", GBASaveType::EEPROM },
{ "BZOJ", GBASaveType::EEPROM },
{ "BZWJ", GBASaveType::EEPROM },
{ "FLBJ", GBASaveType::EEPROM },
{ "FMRJ", GBASaveType::EEPROM },
{ "FPTJ", GBASaveType::EEPROM },
{ "MRDK", GBASaveType::FLASH512 },
{ "RARE", GBASaveType::NONE },
{ "U32E", GBASaveType::EEPROM },
{ "U32J", GBASaveType::EEPROM },
{ "U32P", GBASaveType::EEPROM },
{ "U33J", GBASaveType::EEPROM },
{ "U3IE", GBASaveType::EEPROM },
{ "U3IJ", GBASaveType::EEPROM },
{ "U3IP", GBASaveType::EEPROM },
};

View File

@ -4,9 +4,10 @@ CXXFLAGS := -DMELONDS_VERSION="" \
-I./melonDS/src -I./melonDS/src/teakra/include \
-Wall -Wextra -Werror=int-to-pointer-cast \
-Wfatal-errors -Wno-unused-parameter -Wno-unused-variable \
-Wno-unused-but-set-variable -Wno-sign-compare \
-Wno-deprecated-declarations -Wno-missing-braces \
-Wno-bitwise-instead-of-logical -Wno-unused-private-field \
-Wno-unused-but-set-variable -Wno-unused-function \
-Wno-sign-compare -Wno-deprecated-declarations \
-Wno-missing-braces -Wno-bitwise-instead-of-logical \
-Wno-unused-private-field -Wno-logical-op-parentheses \
-fno-strict-aliasing -std=c++17
TARGET = melonDS.wbx
@ -40,6 +41,7 @@ CORE_SRCS = \
GPU3D_Soft.cpp \
NDS.cpp \
NDSCart.cpp \
ROMList.cpp \
RTC.cpp \
Savestate.cpp \
SPI.cpp \
@ -70,14 +72,23 @@ MISC_SRCS = \
xxhash/xxhash.c \
blip_buf/blip_buf.c \
BIZPLATFORM_SRCS = \
BizPlatform/BizConfig.cpp \
BizPlatform/BizFile.cpp \
BizPlatform/BizLog.cpp \
BizPlatform/BizPlatformStubs.cpp \
BizPlatform/BizSaveManager.cpp \
BizPlatform/BizThread.cpp \
SRCS = \
$(addprefix melonDS/src/,$(CORE_SRCS)) \
$(addprefix melonDS/src/teakra/src/,$(TEAKRA_SRCS)) \
$(addprefix melonDS/src/fatfs/,$(FATFS_SRCS)) \
$(addprefix melonDS/src/,$(MISC_SRCS)) \
BizConfig.cpp \
$(BIZPLATFORM_SRCS) \
BizDebugging.cpp \
BizFileManager.cpp \
BizInterface.cpp \
BizPlatform.cpp \
dthumb.c
include ../common.mak

27
waterbox/melon/dthumb.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef DTHUMB_H
#define DTHUMB_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define DTHUMB_STRING_LENGTH 80
// only 32-bit legacy architectures with THUMB support
typedef enum
{
ARMv4T, //ARM v4, THUMB v1
ARMv5TE, //ARM v5, THUMB v2
ARMv6, //ARM v6, THUMB v3
} ARMARCH;
uint32_t Disassemble_thumb(uint32_t code, char str[DTHUMB_STRING_LENGTH], ARMARCH tv);
void Disassemble_arm(uint32_t code, char str[DTHUMB_STRING_LENGTH], ARMARCH av);
#ifdef __cplusplus
}
#endif
#endif

@ -1 +1 @@
Subproject commit a7e1f6a0838c11801228c5695d68428d007648ed
Subproject commit 270f7083caaf477b7ca3456eed9721c3ef239f41