diff options
author | Jesse Talavera <jesse@jesse.tg> | 2023-12-04 11:57:22 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-04 17:57:22 +0100 |
commit | bb42c8b6392e4e99634dc52137d2974781192482 (patch) | |
tree | 6b2de3d553aa331567e7ab0efa89ed841732f943 /src/GBACart.h | |
parent | da8d413ad9e339c40178be18da20aee1435c8cd4 (diff) |
Refactor how save data (including SD cards) is initialized (#1898)
* 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()`
Diffstat (limited to 'src/GBACart.h')
-rw-r--r-- | src/GBACart.h | 546 |
1 files changed, 289 insertions, 257 deletions
diff --git a/src/GBACart.h b/src/GBACart.h index a557089..493bf6b 100644 --- a/src/GBACart.h +++ b/src/GBACart.h @@ -1,257 +1,289 @@ -/*
- 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 GBACART_H
-#define GBACART_H
-
-#include <memory>
-#include "types.h"
-#include "Savestate.h"
-
-namespace melonDS::GBACart
-{
-
-enum CartType
-{
- Default = 0x001,
- Game = 0x101,
- GameSolarSensor = 0x102,
- RAMExpansion = 0x201,
-};
-
-// CartCommon -- base code shared by all cart types
-class CartCommon
-{
-public:
- CartCommon();
- virtual ~CartCommon();
-
- virtual u32 Type() const = 0;
- virtual u32 Checksum() const { return 0; }
-
- virtual void Reset();
-
- virtual void DoSavestate(Savestate* file);
-
- virtual void SetupSave(u32 type);
- virtual void LoadSave(const u8* savedata, u32 savelen);
-
- virtual int SetInput(int num, bool pressed);
-
- virtual u16 ROMRead(u32 addr) const;
- virtual void ROMWrite(u32 addr, u16 val);
-
- virtual u8 SRAMRead(u32 addr);
- virtual void SRAMWrite(u32 addr, u8 val);
-
- [[nodiscard]] virtual const u8* GetROM() const { return nullptr; }
- [[nodiscard]] virtual u32 GetROMLength() const { return 0; }
-
- virtual u8* GetSaveMemory() const;
- virtual u32 GetSaveMemoryLength() const;
-};
-
-// CartGame -- regular retail game cart (ROM, SRAM)
-class CartGame : public CartCommon
-{
-public:
- CartGame(u8* rom, u32 len);
- virtual ~CartGame() override;
-
- virtual u32 Type() const override { return CartType::Game; }
- virtual u32 Checksum() const override;
-
- virtual void Reset() override;
-
- virtual void DoSavestate(Savestate* file) override;
-
- virtual void SetupSave(u32 type) override;
- virtual void LoadSave(const u8* savedata, u32 savelen) override;
-
- virtual u16 ROMRead(u32 addr) const override;
- virtual void ROMWrite(u32 addr, u16 val) override;
-
- virtual u8 SRAMRead(u32 addr) override;
- virtual void SRAMWrite(u32 addr, u8 val) override;
-
- [[nodiscard]] const u8* GetROM() const override { return ROM; }
- [[nodiscard]] u32 GetROMLength() const override { return ROMLength; }
-
- virtual u8* GetSaveMemory() const override;
- virtual u32 GetSaveMemoryLength() const override;
-protected:
- virtual void ProcessGPIO();
-
- u8 SRAMRead_EEPROM(u32 addr);
- void SRAMWrite_EEPROM(u32 addr, u8 val);
- u8 SRAMRead_FLASH(u32 addr);
- void SRAMWrite_FLASH(u32 addr, u8 val);
- u8 SRAMRead_SRAM(u32 addr);
- void SRAMWrite_SRAM(u32 addr, u8 val);
-
- u8* ROM;
- u32 ROMLength;
-
- struct
- {
- u16 data;
- u16 direction;
- u16 control;
-
- } GPIO;
-
- enum SaveType
- {
- S_NULL,
- S_EEPROM4K,
- S_EEPROM64K,
- S_SRAM256K,
- S_FLASH512K,
- S_FLASH1M
- };
-
- // from DeSmuME
- struct
- {
- u8 state;
- u8 cmd;
- u8 device;
- u8 manufacturer;
- u8 bank;
-
- } SRAMFlashState;
-
- u8* SRAM;
- u32 SRAMLength;
- SaveType SRAMType;
-};
-
-// CartGameSolarSensor -- Boktai game cart
-class CartGameSolarSensor : public CartGame
-{
-public:
- CartGameSolarSensor(u8* rom, u32 len);
- virtual ~CartGameSolarSensor() override;
-
- virtual u32 Type() const override { return CartType::GameSolarSensor; }
-
- virtual void Reset() override;
-
- virtual void DoSavestate(Savestate* file) override;
-
- virtual int SetInput(int num, bool pressed) override;
-
-private:
- virtual void ProcessGPIO() override;
-
- static const int kLuxLevels[11];
-
- bool LightEdge;
- u8 LightCounter;
- u8 LightSample;
- u8 LightLevel;
-};
-
-// CartRAMExpansion -- RAM expansion cart (DS browser, ...)
-class CartRAMExpansion : public CartCommon
-{
-public:
- CartRAMExpansion();
- ~CartRAMExpansion() override;
-
- virtual u32 Type() const override { return CartType::RAMExpansion; }
-
- void Reset() override;
-
- void DoSavestate(Savestate* file) override;
-
- u16 ROMRead(u32 addr) const override;
- void ROMWrite(u32 addr, u16 val) override;
-
-private:
- u8 RAM[0x800000];
- u16 RAMEnable;
-};
-
-// possible inputs for GBA carts that might accept user input
-enum
-{
- Input_SolarSensorDown = 0,
- Input_SolarSensorUp,
-};
-
-class GBACartSlot
-{
-public:
- GBACartSlot() noexcept = default;
- ~GBACartSlot() noexcept = default;
- void Reset() noexcept;
- void DoSavestate(Savestate* file) noexcept;
- /// Applies the GBACartData to the emulator state and unloads an existing ROM if any.
- /// Upon successful insertion, \c cart will be nullptr and the global GBACart state
- /// (\c CartROM, CartInserted, etc.) will be updated.
- bool InsertROM(std::unique_ptr<CartCommon>&& cart) noexcept;
- bool LoadROM(const u8* romdata, u32 romlen) noexcept;
- void LoadSave(const u8* savedata, u32 savelen) noexcept;
-
- void LoadAddon(int type) noexcept;
-
- void EjectCart() noexcept;
-
- // TODO: make more flexible, support nonbinary inputs
- int SetInput(int num, bool pressed) noexcept;
-
- void SetOpenBusDecay(u16 val) noexcept { OpenBusDecay = val; }
-
- u16 ROMRead(u32 addr) const noexcept;
- void ROMWrite(u32 addr, u16 val) noexcept;
-
- u8 SRAMRead(u32 addr) noexcept;
- void SRAMWrite(u32 addr, u8 val) noexcept;
-
- /// This function is intended to allow frontends to save and load SRAM
- /// without using melonDS APIs.
- /// Modifying the emulated SRAM for any other reason is strongly discouraged.
- /// The returned pointer may be invalidated if the emulator is reset,
- /// or when a new game is loaded.
- /// Consequently, don't store the returned pointer for any longer than necessary.
- /// @returns Pointer to this cart's SRAM if a cart is loaded and supports SRAM, otherwise \c nullptr.
- [[nodiscard]] u8* GetSaveMemory() noexcept { return Cart ? Cart->GetSaveMemory() : nullptr; }
- [[nodiscard]] const u8* GetSaveMemory() const noexcept { return Cart ? Cart->GetSaveMemory() : nullptr; }
-
- /// @returns The length of the buffer returned by ::GetSaveMemory()
- /// if a cart is loaded and supports SRAM, otherwise zero.
- [[nodiscard]] u32 GetSaveMemoryLength() const noexcept { return Cart ? Cart->GetSaveMemoryLength() : 0; }
-private:
- std::unique_ptr<CartCommon> Cart = nullptr;
- u16 OpenBusDecay = 0;
-};
-
-/// Parses the given ROM data and constructs a \c GBACart::CartCommon subclass
-/// that can be inserted into the emulator or used to extract information about the cart beforehand.
-/// @param romdata The ROM data to parse.
-/// The returned cartridge will contain a copy of this data,
-/// so the caller may deallocate \c romdata after this function returns.
-/// @param romlen The length of the ROM data in bytes.
-/// @returns A \c GBACart::CartCommon object representing the parsed ROM,
-/// or \c nullptr if the ROM data couldn't be parsed.
-std::unique_ptr<CartCommon> ParseROM(const u8* romdata, u32 romlen);
-
-}
-
-#endif // GBACART_H
+/* + 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 GBACART_H +#define GBACART_H + +#include <memory> +#include "types.h" +#include "Savestate.h" + +namespace melonDS::GBACart +{ + +enum CartType +{ + Default = 0x001, + Game = 0x101, + GameSolarSensor = 0x102, + RAMExpansion = 0x201, +}; + +// CartCommon -- base code shared by all cart types +class CartCommon +{ +public: + virtual ~CartCommon() = default; + + [[nodiscard]] u32 Type() const { return CartType; } + virtual u32 Checksum() const { return 0; } + + virtual void Reset(); + + virtual void DoSavestate(Savestate* file); + + virtual int SetInput(int num, bool pressed); + + virtual u16 ROMRead(u32 addr) const; + virtual void ROMWrite(u32 addr, u16 val); + + virtual u8 SRAMRead(u32 addr); + virtual void SRAMWrite(u32 addr, u8 val); + + [[nodiscard]] virtual const u8* GetROM() const { return nullptr; } + [[nodiscard]] virtual u32 GetROMLength() const { return 0; } + + virtual u8* GetSaveMemory() const; + virtual u32 GetSaveMemoryLength() const; + virtual void SetSaveMemory(const u8* savedata, u32 savelen); +protected: + CartCommon(GBACart::CartType type); + friend class GBACartSlot; +private: + GBACart::CartType CartType; +}; + +// CartGame -- regular retail game cart (ROM, SRAM) +class CartGame : public CartCommon +{ +public: + CartGame(const u8* rom, u32 len, const u8* sram, u32 sramlen, GBACart::CartType type = GBACart::CartType::Game); + CartGame(std::unique_ptr<u8[]>&& rom, u32 len, std::unique_ptr<u8[]>&& sram, u32 sramlen, GBACart::CartType type = GBACart::CartType::Game); + ~CartGame() override; + + u32 Checksum() const override; + + void Reset() override; + + void DoSavestate(Savestate* file) override; + + u16 ROMRead(u32 addr) const override; + void ROMWrite(u32 addr, u16 val) override; + + u8 SRAMRead(u32 addr) override; + void SRAMWrite(u32 addr, u8 val) override; + + [[nodiscard]] const u8* GetROM() const override { return ROM.get(); } + [[nodiscard]] u32 GetROMLength() const override { return ROMLength; } + + u8* GetSaveMemory() const override; + u32 GetSaveMemoryLength() const override; + void SetSaveMemory(const u8* savedata, u32 savelen) override; +protected: + virtual void ProcessGPIO(); + + u8 SRAMRead_EEPROM(u32 addr); + void SRAMWrite_EEPROM(u32 addr, u8 val); + u8 SRAMRead_FLASH(u32 addr); + void SRAMWrite_FLASH(u32 addr, u8 val); + u8 SRAMRead_SRAM(u32 addr); + void SRAMWrite_SRAM(u32 addr, u8 val); + + std::unique_ptr<u8[]> ROM; + u32 ROMLength; + + struct + { + u16 data; + u16 direction; + u16 control; + + } GPIO {}; + + enum SaveType + { + S_NULL, + S_EEPROM4K, + S_EEPROM64K, + S_SRAM256K, + S_FLASH512K, + S_FLASH1M + }; + + // from DeSmuME + struct + { + u8 state; + u8 cmd; + u8 device; + u8 manufacturer; + u8 bank; + + } SRAMFlashState {}; + + std::unique_ptr<u8[]> SRAM = nullptr; + u32 SRAMLength = 0; + SaveType SRAMType = S_NULL; +private: + void SetupSave(u32 type); +}; + +// CartGameSolarSensor -- Boktai game cart +class CartGameSolarSensor : public CartGame +{ +public: + CartGameSolarSensor(const u8* rom, u32 len, const u8* sram, u32 sramlen); + CartGameSolarSensor(std::unique_ptr<u8[]>&& rom, u32 len, std::unique_ptr<u8[]>&& sram, u32 sramlen); + + void Reset() override; + + void DoSavestate(Savestate* file) override; + + int SetInput(int num, bool pressed) override; + +protected: + void ProcessGPIO() override; + +private: + static const int kLuxLevels[11]; + + bool LightEdge = false; + u8 LightCounter = 0; + u8 LightSample = 0; + u8 LightLevel = 0; +}; + +// CartRAMExpansion -- RAM expansion cart (DS browser, ...) +class CartRAMExpansion : public CartCommon +{ +public: + CartRAMExpansion(); + ~CartRAMExpansion() override; + + void Reset() override; + + void DoSavestate(Savestate* file) override; + + u16 ROMRead(u32 addr) const override; + void ROMWrite(u32 addr, u16 val) override; + +private: + u8 RAM[0x800000] {}; + u16 RAMEnable = 0; +}; + +// possible inputs for GBA carts that might accept user input +enum +{ + Input_SolarSensorDown = 0, + Input_SolarSensorUp, +}; + +class GBACartSlot +{ +public: + GBACartSlot(std::unique_ptr<CartCommon>&& cart = nullptr) noexcept; + ~GBACartSlot() noexcept = default; + void Reset() noexcept; + void DoSavestate(Savestate* file) noexcept; + + /// Ejects the cart in the GBA slot (if any) + /// and inserts the given one. + /// + /// To insert a cart that does not require ROM data + /// (such as the RAM expansion pack), + /// create it manually with std::make_unique and pass it here. + /// + /// @param cart Movable \c unique_ptr to the GBA cart object. + /// May be \c nullptr, in which case the cart slot remains empty. + /// @post \c cart is \c nullptr and the underlying object + /// is moved into the cart slot. + void SetCart(std::unique_ptr<CartCommon>&& cart) noexcept; + [[nodiscard]] CartCommon* GetCart() noexcept { return Cart.get(); } + [[nodiscard]] const CartCommon* GetCart() const noexcept { return Cart.get(); } + + void LoadAddon(int type) noexcept; + + /// @return The cart that was in the cart slot if any, + /// or \c nullptr if the cart slot was empty. + std::unique_ptr<CartCommon> EjectCart() noexcept; + + // TODO: make more flexible, support nonbinary inputs + int SetInput(int num, bool pressed) noexcept; + + void SetOpenBusDecay(u16 val) noexcept { OpenBusDecay = val; } + + u16 ROMRead(u32 addr) const noexcept; + void ROMWrite(u32 addr, u16 val) noexcept; + + u8 SRAMRead(u32 addr) noexcept; + void SRAMWrite(u32 addr, u8 val) noexcept; + + /// This function is intended to allow frontends to save and load SRAM + /// without using melonDS APIs. + /// Modifying the emulated SRAM for any other reason is strongly discouraged. + /// The returned pointer may be invalidated if the emulator is reset, + /// or when a new game is loaded. + /// Consequently, don't store the returned pointer for any longer than necessary. + /// @returns Pointer to this cart's SRAM if a cart is loaded and supports SRAM, otherwise \c nullptr. + [[nodiscard]] u8* GetSaveMemory() noexcept { return Cart ? Cart->GetSaveMemory() : nullptr; } + [[nodiscard]] const u8* GetSaveMemory() const noexcept { return Cart ? Cart->GetSaveMemory() : nullptr; } + + /// Sets the loaded cart's SRAM. + /// Does nothing if no cart is inserted + /// or the inserted cart doesn't support SRAM. + /// + /// @param savedata Buffer containing the raw contents of the SRAM. + /// The contents of this buffer are copied into the cart slot, + /// so the caller may dispose of it after this method returns. + /// @param savelen The length of the buffer in \c savedata, in bytes. + void SetSaveMemory(const u8* savedata, u32 savelen) noexcept; + + /// @returns The length of the buffer returned by ::GetSaveMemory() + /// if a cart is loaded and supports SRAM, otherwise zero. + [[nodiscard]] u32 GetSaveMemoryLength() const noexcept { return Cart ? Cart->GetSaveMemoryLength() : 0; } +private: + std::unique_ptr<CartCommon> Cart = nullptr; + u16 OpenBusDecay = 0; +}; + +/// Parses the given ROM data and constructs a \c GBACart::CartCommon subclass +/// that can be inserted into the emulator or used to extract information about the cart beforehand. +/// @param romdata The ROM data to parse. +/// The returned cartridge will contain a copy of this data, +/// so the caller may deallocate \c romdata after this function returns. +/// @param romlen The length of the ROM data in bytes. +/// @returns A \c GBACart::CartCommon object representing the parsed ROM, +/// or \c nullptr if the ROM data couldn't be parsed. +std::unique_ptr<CartCommon> ParseROM(const u8* romdata, u32 romlen); +std::unique_ptr<CartCommon> ParseROM(std::unique_ptr<u8[]>&& romdata, u32 romlen); +std::unique_ptr<CartCommon> ParseROM(const u8* romdata, u32 romlen, const u8* sramdata, u32 sramlen); + +/// @param romdata The ROM data to parse. Will be moved-from. +/// @param romlen Length of romdata in bytes. +/// @param sramdata The save data to add to the cart. +/// May be \c nullptr, in which case the cart will have no save data. +/// @param sramlen Length of sramdata in bytes. +/// May be zero, in which case the cart will have no save data. +/// @return Unique pointer to the parsed GBA cart, +/// or \c nullptr if there was an error. +std::unique_ptr<CartCommon> ParseROM(std::unique_ptr<u8[]>&& romdata, u32 romlen, std::unique_ptr<u8[]>&& sramdata, u32 sramlen); + +} + +#endif // GBACART_H |