mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-26 07:39:56 -06:00

* Remove `FATStorage::Open` and `FATStorage::Close` - That's what the constructor and destructor are for, respectively * Add `FATStorage::IsReadOnly` * Slight cleanup of `FATStorage` - Make it move-constructible and move-assignable - Represent the absence of a sync directory with `std::optional`, not an empty string - Add `FATStorageArgs` for later use * Refactor `CartHomebrew` to accept an optional `FATStorageArgs` - `CartHomebrew` uses it to load an SD card image - Not passing a `FATStorage` directly because we won't know if we need to load the card until we parse the ROM - Store the `FATStorage` inside a `std::optional` instead of a pointer - `CartHomebrew::Reset` no longer reloads the SD card; the frontend needs to set it with the `SetSDCard` method * Close `NANDImage::CurFile` when move-assigning - Whoops * Add `Args.h` - To construct a `NDS` or `DSi` with arguments - Mostly intended for system files * Fix incorrect `final` placement * Refactor how `DSi`'s NAND and SD card are set - Provide them via a `DSiArgs` argument in the constructor - Give `DSi_MMCStorage` ownership of the `NANDImage` or `FATStorage` as needed, and expose getters/setters - Replace `DSi_SDHost::Ports` with a `array<unique_ptr, 2>` to reduce the risk of leaks - Store `DSi_MMCStorage`'s disk images in a `std::variant` - The SD card and NAND image are no longer reset in `Reset()`; the frontend will need to do that itself * Add getters/setters on `DSi` itself for its storage media * Remove newly-unused `Platform::ConfigEntry`s * Use `DSi::SetNAND` in the frontend * Add `EmuThread::NeedToRecreateConsole` * Document `NDSArgs` and give its fields default values * Refactor how system files are loaded upon construction - Pass `NDSArgs&&` into `NDS`'s constructor - Use `std::array` for the emulator's BIOS images and the built-in FreeBIOS, to simplify copying and comparison - Initialize the BIOS, firmware, and SD cards from `NDSArgs` or `DSiArgs` - Add a new default constructor for `NDS` (not `DSi`) that initializes the DS with default system files - Embed `FirmwareMem::Firmware` directly instead of in a `unique_ptr` - `SPIHost` now takes a `Firmware&&` that it forwards to `FirmwareMem` - Add `Firmware` getters/setters plus `const` variants for `NDS`, `Firmware`, and `FirmwareMem` - Simplify installation of firmware * Initialize the DSi BIOS in the constructor - Change `DSi::ARM9iBIOS` and `ARM7iBIOS` to `std::array` * Update the frontend to reflect the core's changes * Remove `DSi_SDHost::CloseHandles` * Pass `nullopt` instead of the empty string when folder sync is off * Deduplicate ROM extraction logic - `LoadGBAROM` and `LoadROM` now delegate to `LoadROMData` - Also use `unique_ptr` instead of `new[]` * Oops, missed some `get()`'s * Move `NDS::IsLoadedARM9BIOSBuiltIn` to the header - So it's likelier to be inlined - Same for the ARM7 version * Remove `NDS::SetConsoleType` * Add `NDS::SetFirmware` * Move `GBACart::SetupSave` to be `protected` - It was only ever used inside the class * Rename `GBACart::LoadSave` to `SetSaveMemory` - Same for the cart slot * Declare `GBACartSlot` as a friend of `GBACart::CartCommon` * Revise `GBACartSlot`'s getters and setters - Rename `InsertROM` and `LoadROM` to `SetCart` - Add a `GetCart` method * Clean up getters and setters for NDS and GBA carts * Clean up how carts are inserted into the slots - Remove setters that operate directly on pointers, to simplify error-handling (use ParseROM instead) - Add overloads for all carts that accept a `const u8*` (to copy the ROM data) and a `unique_ptr<u8[]>` (to move the ROM data) - Store all ROM and RAM data in `unique_ptr` - Default-initialize all fields - Simplify constructors and destructors, inheriting where applicable * Refactor GBA save data insertion - Make `SetupSave` private and non-virtual and move its logic to be in `SetSaveMemory` - Add overloads for setting save data in the constructor - Update the SRAM completely in `SetSaveMemory` * Clean up `NDSCart::CartCommon::SetSaveMemory` - Move its declaration next to the other `SaveMemory` methods - Move its (empty) implementation to the header * Add some comments * Add Utils.cpp and Utils.h * Rename some functions in Utils for clarity * Add `GBACart::ParseROM` and `NDSCart::ParseROM` overloads that accept `unique_ptr<u8[]>` - The `u8*` overloads delegate to these new overloads - Also move `SetupSave` for both kinds of carts to be private non-virtual methods * Finalize the `NDSCart` refactor - Add `NDSCartArgs` to pass to `ParseROM` - Add SRAM arguments for all retail carts - Initialize SRAM inside the constructor - Delegate to other constructors where possible * Replace `ROMManager::NDSSave` and `GBASave` with `unique_ptr` * Make both cart slots return the previously-inserted cart in `EjectCart` - Primarily intended for reusing carts when resetting the console * Make `NDS::EjectCart` return the old cart * Initialize both cart slots with the provided ROM (if any) * Make `NDS::EjectGBACart` return the ejected cart * Clean up some comments in Args.h * Rename `ROMManager::LoadBIOS` to `BootToMenu` - Clarifies the intent * Add `ROMManager::LoadDLDISDCard` * Add a doc comment * Refactor how the `NDS` is created or updated - Rewrite `CreateConsole` to read from `Config` and load system files, but accept carts as arguments - Fail without creating an `NDS` if any required system file doesn't load - Add `UpdateConsole`, which delegates to `CreateConsole` if switching modes or starting the app - Use `std::variant` to indicate whether a cart should be removed, inserted, or reused - Load all system files (plus SD cards) in `UpdateConsole` - Eject the cart and reinsert it into the new console if applicable * Respect some more `Config` settings in the `Load*` functions * Remove `InstallNAND` in favor of `LoadNAND` * Fix some potential bugs in `LoadROMData` * Oops, forgot to delete the definition of `InstallNAND` * Add functions to get `FATStorageArgs` - Not the cards themselves, but to get the arguments you _would_ use to load the cards * Refactor `ROMManager::LoadROM` - Load the ROM and save data before trying to initialize the console * Clean up `ROMManager::Reset` and `BootToMenu` - Let `EmuThread::UpdateConsole` do the heavy lifting * Clean up `LoadGBAROM` * Remove some unused functions * Set the default DSi BIOS to be broken in `DSiArgs` * Respect `Config::DSiFullBIOSBoot` when loading DSi BIOS files * Remove some more unused functions * Remove redundant `virtual` specifiers * Refactor `NDSCart::CartCommon::Type()` to return a member instead of a constant - One less virtual dispatch - The cart type is read in `NDSCartSlot::DoSavestate`, which is a path downstream (due to rewinding) * Remove a hash that I computed for debugging purposes * Make `ByteSwap` `constexpr` * Remove an unused `#include` * Remove unnecessary functions from the NDS carts - Mostly overrides that added nothing * Default-initialize all NDSCart fields * Make `GBACart::Type()` not rely on virtual dispatch - `GBACartSlot::DoSavestate` calls it, and savestates can be a hot path downstream * Don't forget to reset the base class in `CartGameSolarSensor::Reset()` * Remove redundant `virtual` specifiers * Default-initialize some fields in `GBACart` * Fix ROMs not loading from archives in the frontend - Whoops * Change how the `Firmware` member is declared * Forgot an include in Utils.cpp * Rename `FirmwareMem::Firmware` to `FirmwareData` to fix a build error on Linux - One of these days I'll convince you people to let me use `camelCaseMemberNames` * Add `override` to places in `DSi_MMCStorage` that warrant it * Fix firmware saving on the frontend - Remove `GetConfigString` and `ConfigEntry::WifiSettingsPath` while I'm at it * Add a non-const `GetNAND()`
384 lines
11 KiB
C++
384 lines
11 KiB
C++
/*
|
|
Copyright 2016-2023 melonDS team
|
|
|
|
This file is part of melonDS.
|
|
|
|
melonDS is free software: you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free
|
|
Software Foundation, either version 3 of the License, or (at your option)
|
|
any later version.
|
|
|
|
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with melonDS. If not, see http://www.gnu.org/licenses/.
|
|
*/
|
|
|
|
#ifndef PLATFORM_H
|
|
#define PLATFORM_H
|
|
|
|
#include "types.h"
|
|
|
|
#include <functional>
|
|
#include <string>
|
|
|
|
namespace melonDS
|
|
{
|
|
class Firmware;
|
|
|
|
namespace Platform
|
|
{
|
|
|
|
void Init(int argc, char** argv);
|
|
|
|
/**
|
|
* Frees all resources that were allocated in \c Init
|
|
* or by any other \c Platform function.
|
|
*/
|
|
void DeInit();
|
|
|
|
enum StopReason {
|
|
/**
|
|
* The emulator stopped for some unspecified reason.
|
|
* Not necessarily an error.
|
|
*/
|
|
Unknown,
|
|
|
|
/**
|
|
* The emulator stopped due to an external call to \c NDS::Stop,
|
|
* most likely because the user stopped the game manually.
|
|
*/
|
|
External,
|
|
|
|
/**
|
|
* The emulator stopped because it tried to enter GBA mode,
|
|
* which melonDS does not support.
|
|
*/
|
|
GBAModeNotSupported,
|
|
|
|
/**
|
|
* The emulator stopped because of an error in the emulated console,
|
|
* not necessarily because of an error in melonDS.
|
|
*/
|
|
BadExceptionRegion,
|
|
|
|
/**
|
|
* The emulated console shut itself down normally,
|
|
* likely because its system settings were adjusted
|
|
* or its "battery" ran out.
|
|
*/
|
|
PowerOff,
|
|
};
|
|
|
|
/**
|
|
* Signals to the frontend that no more frames should be requested.
|
|
* Frontends should not call this directly;
|
|
* use \c NDS::Stop instead.
|
|
*/
|
|
void SignalStop(StopReason reason);
|
|
|
|
/**
|
|
* @returns The ID of the running melonDS instance if running in local multiplayer mode,
|
|
* or 0 if not.
|
|
*/
|
|
int InstanceID();
|
|
|
|
/**
|
|
* @returns A suffix that should be appended to all instance-specific paths
|
|
* if running in local multiplayer mode,
|
|
* or the empty string if not.
|
|
*/
|
|
std::string InstanceFileSuffix();
|
|
|
|
// configuration values
|
|
|
|
enum ConfigEntry
|
|
{
|
|
#ifdef JIT_ENABLED
|
|
JIT_Enable,
|
|
JIT_MaxBlockSize,
|
|
JIT_LiteralOptimizations,
|
|
JIT_BranchOptimizations,
|
|
JIT_FastMemory,
|
|
#endif
|
|
|
|
ExternalBIOSEnable,
|
|
|
|
Firm_MAC,
|
|
|
|
AudioBitDepth,
|
|
|
|
DSi_FullBIOSBoot,
|
|
|
|
#ifdef GDBSTUB_ENABLED
|
|
GdbEnabled,
|
|
GdbPortARM7,
|
|
GdbPortARM9,
|
|
GdbARM7BreakOnStartup,
|
|
GdbARM9BreakOnStartup,
|
|
#endif
|
|
};
|
|
|
|
int GetConfigInt(ConfigEntry entry);
|
|
bool GetConfigBool(ConfigEntry entry);
|
|
bool GetConfigArray(ConfigEntry entry, void* data);
|
|
|
|
/**
|
|
* Denotes how a file will be opened and accessed.
|
|
* Flags may or may not correspond to the operating system's file API.
|
|
*/
|
|
enum FileMode : unsigned {
|
|
None = 0,
|
|
|
|
/**
|
|
* Opens a file for reading.
|
|
* Either this or \c Write must be set.
|
|
* Similar to \c "r" in \c fopen.
|
|
*/
|
|
Read = 0b00'00'01,
|
|
|
|
/**
|
|
* Opens a file for writing, creating it if it doesn't exist.
|
|
* Will truncate existing files unless \c Preserve is set.
|
|
* Either this or \c Read must be set.
|
|
* Similar to <tt>fopen</tt>'s \c "w" flag.
|
|
*/
|
|
Write = 0b00'00'10,
|
|
|
|
/**
|
|
* Opens an existing file as-is without truncating it.
|
|
* The file may still be created unless \c NoCreate is set.
|
|
* @note This flag has no effect if \c Write is not set.
|
|
*/
|
|
Preserve = 0b00'01'00,
|
|
|
|
/**
|
|
* Do not create the file if it doesn't exist.
|
|
* @note This flag has no effect if \c Write is not set.
|
|
*/
|
|
NoCreate = 0b00'10'00,
|
|
|
|
/**
|
|
* Opens a file in text mode,
|
|
* rather than the default binary mode.
|
|
* Text-mode files may have their line endings converted
|
|
* to match the operating system,
|
|
* and may also be line-buffered.
|
|
*/
|
|
Text = 0b01'00'00,
|
|
|
|
/**
|
|
* Opens a file for reading and writing.
|
|
* Equivalent to <tt>Read | Write</tt>.
|
|
*/
|
|
ReadWrite = Read | Write,
|
|
|
|
/**
|
|
* Opens a file for reading and writing
|
|
* without truncating it or creating a new one.
|
|
* Equivalent to <tt>Read | Write | Preserve | NoCreate</tt>.
|
|
*/
|
|
ReadWriteExisting = Read | Write | Preserve | NoCreate,
|
|
|
|
/**
|
|
* Opens a file for reading in text mode.
|
|
* Equivalent to <tt>Read | Text</tt>.
|
|
*/
|
|
ReadText = Read | Text,
|
|
|
|
/**
|
|
* Opens a file for writing in text mode,
|
|
* creating it if it doesn't exist.
|
|
* Equivalent to <tt>Write | Text</tt>.
|
|
*/
|
|
WriteText = Write | Text,
|
|
};
|
|
|
|
/**
|
|
* Denotes the origin of a seek operation.
|
|
* Similar to \c fseek's \c SEEK_* constants.
|
|
*/
|
|
enum class FileSeekOrigin
|
|
{
|
|
Start,
|
|
Current,
|
|
End,
|
|
};
|
|
|
|
/**
|
|
* Opaque handle for a file object.
|
|
* This can be implemented as a struct defined by the frontend,
|
|
* or as a simple pointer cast.
|
|
* The core will never look inside this struct,
|
|
* but frontends may do so freely.
|
|
*/
|
|
struct FileHandle;
|
|
|
|
// Simple fopen() wrapper that supports UTF8.
|
|
// Can be optionally restricted to only opening a file that already exists.
|
|
FileHandle* OpenFile(const std::string& path, FileMode mode);
|
|
|
|
// opens files local to the emulator (melonDS.ini, BIOS, firmware, ...)
|
|
// For Windows builds, or portable UNIX builds it checks, by order of priority:
|
|
// * current working directory
|
|
// * emulator directory (essentially where the melonDS executable is) if supported
|
|
// * any platform-specific application data directories
|
|
// in create mode, if the file doesn't exist, it will be created in the emulator
|
|
// directory if supported, or in the current directory otherwise
|
|
// For regular UNIX builds, the user's configuration directory is always used.
|
|
FileHandle* OpenLocalFile(const std::string& path, FileMode mode);
|
|
|
|
/// Returns true if the given file exists.
|
|
bool FileExists(const std::string& name);
|
|
bool LocalFileExists(const std::string& name);
|
|
|
|
/** Close a file opened with \c OpenFile.
|
|
* @returns \c true if the file was closed successfully, false otherwise.
|
|
* @post \c file is no longer valid and should not be used.
|
|
* The underlying object may still be allocated (e.g. if the frontend refcounts files),
|
|
* but that's an implementation detail.
|
|
* @see fclose
|
|
*/
|
|
bool CloseFile(FileHandle* file);
|
|
|
|
/// @returns \c true if there is no more data left to read in this file,
|
|
/// \c false if there is still data left to read or if there was an error.
|
|
/// @see feof
|
|
bool IsEndOfFile(FileHandle* file);
|
|
|
|
/// @see fgets
|
|
bool FileReadLine(char* str, int count, FileHandle* file);
|
|
|
|
/// @see fseek
|
|
bool FileSeek(FileHandle* file, s64 offset, FileSeekOrigin origin);
|
|
|
|
/// @see rewind
|
|
void FileRewind(FileHandle* file);
|
|
|
|
/// @see fread
|
|
u64 FileRead(void* data, u64 size, u64 count, FileHandle* file);
|
|
|
|
/// @see fflush
|
|
bool FileFlush(FileHandle* file);
|
|
|
|
/// @see fwrite
|
|
u64 FileWrite(const void* data, u64 size, u64 count, FileHandle* file);
|
|
|
|
/// @see fprintf
|
|
u64 FileWriteFormatted(FileHandle* file, const char* fmt, ...);
|
|
|
|
/// @returns The length of the file in bytes, or 0 if there was an error.
|
|
/// @note If this function checks the length by using \c fseek and \c ftell
|
|
/// (or local equivalents), it must leave the stream position as it was found.
|
|
u64 FileLength(FileHandle* file);
|
|
|
|
enum LogLevel
|
|
{
|
|
Debug,
|
|
Info,
|
|
Warn,
|
|
Error,
|
|
};
|
|
|
|
void Log(LogLevel level, const char* fmt, ...);
|
|
|
|
struct Thread;
|
|
Thread* Thread_Create(std::function<void()> func);
|
|
void Thread_Free(Thread* thread);
|
|
void Thread_Wait(Thread* thread);
|
|
|
|
struct Semaphore;
|
|
Semaphore* Semaphore_Create();
|
|
void Semaphore_Free(Semaphore* sema);
|
|
void Semaphore_Reset(Semaphore* sema);
|
|
void Semaphore_Wait(Semaphore* sema);
|
|
void Semaphore_Post(Semaphore* sema, int count = 1);
|
|
|
|
struct Mutex;
|
|
Mutex* Mutex_Create();
|
|
void Mutex_Free(Mutex* mutex);
|
|
void Mutex_Lock(Mutex* mutex);
|
|
void Mutex_Unlock(Mutex* mutex);
|
|
bool Mutex_TryLock(Mutex* mutex);
|
|
|
|
void Sleep(u64 usecs);
|
|
|
|
|
|
// functions called when the NDS or GBA save files need to be written back to storage
|
|
// savedata and savelen are always the entire save memory buffer and its full length
|
|
// writeoffset and writelen indicate which part of the memory was altered
|
|
void WriteNDSSave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen);
|
|
void WriteGBASave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen);
|
|
|
|
/// Called when the firmware needs to be written back to storage,
|
|
/// after one of the supported write commands finishes execution.
|
|
/// @param firmware The firmware that was just written.
|
|
/// @param writeoffset The offset of the first byte that was written to firmware.
|
|
/// @param writelen The number of bytes that were written to firmware.
|
|
void WriteFirmware(const Firmware& firmware, u32 writeoffset, u32 writelen);
|
|
|
|
// called when the RTC date/time is changed and the frontend might need to take it into account
|
|
void WriteDateTime(int year, int month, int day, int hour, int minute, int second);
|
|
|
|
|
|
// local multiplayer comm interface
|
|
// packet type: DS-style TX header (12 bytes) + original 802.11 frame
|
|
bool MP_Init();
|
|
void MP_DeInit();
|
|
void MP_Begin();
|
|
void MP_End();
|
|
int MP_SendPacket(u8* data, int len, u64 timestamp);
|
|
int MP_RecvPacket(u8* data, u64* timestamp);
|
|
int MP_SendCmd(u8* data, int len, u64 timestamp);
|
|
int MP_SendReply(u8* data, int len, u64 timestamp, u16 aid);
|
|
int MP_SendAck(u8* data, int len, u64 timestamp);
|
|
int MP_RecvHostPacket(u8* data, u64* timestamp);
|
|
u16 MP_RecvReplies(u8* data, u64 timestamp, u16 aidmask);
|
|
|
|
|
|
// LAN comm interface
|
|
// packet type: Ethernet (802.3)
|
|
bool LAN_Init();
|
|
void LAN_DeInit();
|
|
int LAN_SendPacket(u8* data, int len);
|
|
int LAN_RecvPacket(u8* data);
|
|
|
|
|
|
// interface for camera emulation
|
|
// camera numbers:
|
|
// 0 = DSi outer camera
|
|
// 1 = DSi inner camera
|
|
// other values reserved for future camera addon emulation
|
|
void Camera_Start(int num);
|
|
void Camera_Stop(int num);
|
|
void Camera_CaptureFrame(int num, u32* frame, int width, int height, bool yuv);
|
|
|
|
struct DynamicLibrary;
|
|
|
|
/**
|
|
* @param lib The name of the library to load.
|
|
* @return A handle to the loaded library, or \c nullptr if the library could not be loaded.
|
|
*/
|
|
DynamicLibrary* DynamicLibrary_Load(const char* lib);
|
|
|
|
/**
|
|
* Releases a loaded library.
|
|
* Pointers to functions in the library will be invalidated.
|
|
* @param lib The library to unload.
|
|
*/
|
|
void DynamicLibrary_Unload(DynamicLibrary* lib);
|
|
|
|
/**
|
|
* Loads a function from a library.
|
|
* @param lib The library to load the function from.
|
|
* @param name The name of the function to load.
|
|
* @return A pointer to the loaded function, or \c nullptr if the function could not be loaded.
|
|
*/
|
|
void* DynamicLibrary_LoadFunction(DynamicLibrary* lib, const char* name);
|
|
}
|
|
|
|
}
|
|
#endif // PLATFORM_H
|