mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-23 06:10:03 -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()`
217 lines
5.6 KiB
C++
217 lines
5.6 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 DSI_SD_H
|
|
#define DSI_SD_H
|
|
|
|
#include <cstring>
|
|
#include <variant>
|
|
#include "FIFO.h"
|
|
#include "FATStorage.h"
|
|
#include "DSi_NAND.h"
|
|
#include "Savestate.h"
|
|
|
|
namespace melonDS
|
|
{
|
|
class DSi_SDDevice;
|
|
class DSi;
|
|
|
|
using Nothing = std::monostate;
|
|
using DSiStorage = std::variant<std::monostate, FATStorage, DSi_NAND::NANDImage>;
|
|
|
|
class DSi_SDHost
|
|
{
|
|
public:
|
|
/// Creates an SDMMC host.
|
|
DSi_SDHost(melonDS::DSi& dsi, DSi_NAND::NANDImage&& nand, std::optional<FATStorage>&& sdcard = std::nullopt) noexcept;
|
|
|
|
/// Creates an SDIO host
|
|
explicit DSi_SDHost(melonDS::DSi& dsi) noexcept;
|
|
~DSi_SDHost();
|
|
|
|
void Reset();
|
|
|
|
void DoSavestate(Savestate* file);
|
|
|
|
void FinishRX(u32 param);
|
|
void FinishTX(u32 param);
|
|
void SendResponse(u32 val, bool last);
|
|
u32 DataRX(u8* data, u32 len);
|
|
u32 DataTX(u8* data, u32 len);
|
|
u32 GetTransferrableLen(u32 len);
|
|
|
|
void CheckRX();
|
|
void CheckTX();
|
|
bool TXReq;
|
|
|
|
void SetCardIRQ();
|
|
|
|
[[nodiscard]] FATStorage* GetSDCard() noexcept;
|
|
[[nodiscard]] const FATStorage* GetSDCard() const noexcept;
|
|
[[nodiscard]] DSi_NAND::NANDImage* GetNAND() noexcept;
|
|
[[nodiscard]] const DSi_NAND::NANDImage* GetNAND() const noexcept;
|
|
|
|
void SetSDCard(FATStorage&& sdcard) noexcept;
|
|
void SetSDCard(std::optional<FATStorage>&& sdcard) noexcept;
|
|
void SetNAND(DSi_NAND::NANDImage&& nand) noexcept;
|
|
|
|
u16 Read(u32 addr);
|
|
void Write(u32 addr, u16 val);
|
|
u16 ReadFIFO16();
|
|
void WriteFIFO16(u16 val);
|
|
u32 ReadFIFO32();
|
|
void WriteFIFO32(u32 val);
|
|
|
|
void UpdateFIFO32();
|
|
void CheckSwapFIFO();
|
|
|
|
private:
|
|
melonDS::DSi& DSi;
|
|
u32 Num;
|
|
|
|
u16 PortSelect;
|
|
u16 SoftReset;
|
|
u16 SDClock;
|
|
u16 SDOption;
|
|
|
|
u32 IRQStatus; // IF
|
|
u32 IRQMask; // ~IE
|
|
|
|
u16 CardIRQStatus;
|
|
u16 CardIRQMask;
|
|
u16 CardIRQCtl;
|
|
|
|
u16 DataCtl;
|
|
u16 Data32IRQ;
|
|
u32 DataMode; // 0=16bit 1=32bit
|
|
u16 BlockCount16, BlockCount32, BlockCountInternal;
|
|
u16 BlockLen16, BlockLen32;
|
|
u16 StopAction;
|
|
|
|
u16 Command;
|
|
u32 Param;
|
|
u16 ResponseBuffer[8];
|
|
|
|
std::array<std::unique_ptr<DSi_SDDevice>, 2> Ports {};
|
|
|
|
u32 CurFIFO; // FIFO accessible for read/write
|
|
FIFO<u16, 0x100> DataFIFO[2];
|
|
FIFO<u32, 0x80> DataFIFO32;
|
|
|
|
void UpdateData32IRQ();
|
|
void ClearIRQ(u32 irq);
|
|
void SetIRQ(u32 irq);
|
|
void UpdateIRQ(u32 oldmask);
|
|
void UpdateCardIRQ(u16 oldmask);
|
|
};
|
|
|
|
|
|
class DSi_SDDevice
|
|
{
|
|
public:
|
|
DSi_SDDevice(DSi_SDHost* host) { Host = host; IRQ = false; ReadOnly = false; }
|
|
virtual ~DSi_SDDevice() {}
|
|
|
|
virtual void Reset() = 0;
|
|
|
|
virtual void DoSavestate(Savestate* file) = 0;
|
|
|
|
virtual void SendCMD(u8 cmd, u32 param) = 0;
|
|
virtual void ContinueTransfer() = 0;
|
|
|
|
bool IRQ;
|
|
bool ReadOnly;
|
|
|
|
protected:
|
|
DSi_SDHost* Host;
|
|
};
|
|
|
|
|
|
class DSi_MMCStorage : public DSi_SDDevice
|
|
{
|
|
public:
|
|
DSi_MMCStorage(melonDS::DSi& dsi, DSi_SDHost* host, DSi_NAND::NANDImage&& nand) noexcept;
|
|
DSi_MMCStorage(melonDS::DSi& dsi, DSi_SDHost* host, FATStorage&& sdcard) noexcept;
|
|
~DSi_MMCStorage() override;
|
|
|
|
[[nodiscard]] FATStorage* GetSDCard() noexcept { return std::get_if<FATStorage>(&Storage); }
|
|
[[nodiscard]] const FATStorage* GetSDCard() const noexcept { return std::get_if<FATStorage>(&Storage); }
|
|
[[nodiscard]] DSi_NAND::NANDImage* GetNAND() noexcept { return std::get_if<DSi_NAND::NANDImage>(&Storage); }
|
|
[[nodiscard]] const DSi_NAND::NANDImage* GetNAND() const noexcept { return std::get_if<DSi_NAND::NANDImage>(&Storage); }
|
|
|
|
void SetNAND(DSi_NAND::NANDImage&& nand) noexcept { Storage = std::move(nand); }
|
|
void SetSDCard(FATStorage&& sdcard) noexcept { Storage = std::move(sdcard); }
|
|
void SetSDCard(std::optional<FATStorage>&& sdcard) noexcept
|
|
{
|
|
if (sdcard)
|
|
{ // If we're setting a new SD card...
|
|
Storage = std::move(*sdcard);
|
|
sdcard = std::nullopt;
|
|
}
|
|
else
|
|
{
|
|
Storage = Nothing();
|
|
}
|
|
}
|
|
|
|
void SetStorage(DSiStorage&& storage) noexcept
|
|
{
|
|
Storage = std::move(storage);
|
|
storage = Nothing();
|
|
// not sure if a moved-from variant is empty or contains a moved-from object;
|
|
// better to be safe than sorry
|
|
}
|
|
|
|
void Reset() override;
|
|
|
|
void DoSavestate(Savestate* file) override;
|
|
|
|
void SetCID(const u8* cid) { memcpy(CID, cid, sizeof(CID)); }
|
|
|
|
void SendCMD(u8 cmd, u32 param) override;
|
|
void SendACMD(u8 cmd, u32 param);
|
|
|
|
void ContinueTransfer() override;
|
|
|
|
private:
|
|
static constexpr u8 DSiSDCardCID[16] = {0xBD, 0x12, 0x34, 0x56, 0x78, 0x03, 0x4D, 0x30, 0x30, 0x46, 0x50, 0x41, 0x00, 0x00, 0x15, 0x00};
|
|
melonDS::DSi& DSi;
|
|
DSiStorage Storage;
|
|
|
|
u8 CID[16];
|
|
u8 CSD[16];
|
|
|
|
u32 CSR;
|
|
u32 OCR;
|
|
u32 RCA;
|
|
u8 SCR[8];
|
|
u8 SSR[64];
|
|
|
|
u32 BlockSize;
|
|
u64 RWAddress;
|
|
u32 RWCommand;
|
|
|
|
void SetState(u32 state) { CSR &= ~(0xF << 9); CSR |= (state << 9); }
|
|
|
|
u32 ReadBlock(u64 addr);
|
|
u32 WriteBlock(u64 addr);
|
|
};
|
|
|
|
}
|
|
#endif // DSI_SD_H
|