diff options
Diffstat (limited to 'src/NDSCart.h')
-rw-r--r-- | src/NDSCart.h | 230 |
1 files changed, 130 insertions, 100 deletions
diff --git a/src/NDSCart.h b/src/NDSCart.h index 24f9f9e..43bf1fc 100644 --- a/src/NDSCart.h +++ b/src/NDSCart.h @@ -22,7 +22,7 @@ #include <array> #include <string> #include <memory> -#include <array> +#include <variant> #include "types.h" #include "Savestate.h" @@ -49,14 +49,32 @@ enum CartType class NDSCartSlot; +/// Arguments used to create and populate an NDS cart of unknown type. +/// Different carts take different subsets of these arguments, +/// but we won't know which ones to use +/// until we parse the header at runtime. +struct NDSCartArgs +{ + /// The arguments used to load a homebrew SD card image. + /// If \c nullopt, then the cart will not have an SD card. + /// Ignored for retail ROMs. + std::optional<FATStorageArgs> SDCard = std::nullopt; + + /// Save RAM to load into the cartridge. + /// If \c nullopt, then the cart's SRAM buffer will be empty. + /// Ignored for homebrew ROMs. + std::optional<std::pair<std::unique_ptr<u8[]>, u32>> SRAM = std::nullopt; +}; + // CartCommon -- base code shared by all cart types class CartCommon { public: - CartCommon(u8* rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams); + CartCommon(const u8* rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams, CartType type); + CartCommon(std::unique_ptr<u8[]>&& rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams, CartType type); virtual ~CartCommon(); - virtual u32 Type() const = 0; + [[nodiscard]] u32 Type() const { return CartType; }; [[nodiscard]] u32 Checksum() const; virtual void Reset(); @@ -64,16 +82,16 @@ public: virtual void DoSavestate(Savestate* file); - virtual void SetupSave(u32 type); - virtual void LoadSave(const u8* savedata, u32 savelen); virtual int ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, u8* cmd, u8* data, u32 len); virtual void ROMCommandFinish(u8* cmd, u8* data, u32 len); virtual u8 SPIWrite(u8 val, u32 pos, bool last); - virtual u8* GetSaveMemory() const; - virtual u32 GetSaveMemoryLength() const; + virtual u8* GetSaveMemory() { return nullptr; } + virtual const u8* GetSaveMemory() const { return nullptr; } + virtual u32 GetSaveMemoryLength() const { return 0; } + virtual void SetSaveMemory(const u8* savedata, u32 savelen) {}; [[nodiscard]] const NDSHeader& GetHeader() const { return Header; } [[nodiscard]] NDSHeader& GetHeader() { return Header; } @@ -82,48 +100,65 @@ public: [[nodiscard]] const NDSBanner* Banner() const; [[nodiscard]] const ROMListEntry& GetROMParams() const { return ROMParams; }; [[nodiscard]] u32 ID() const { return ChipID; } - [[nodiscard]] const u8* GetROM() const { return ROM; } + [[nodiscard]] const u8* GetROM() const { return ROM.get(); } [[nodiscard]] u32 GetROMLength() const { return ROMLength; } protected: void ReadROM(u32 addr, u32 len, u8* data, u32 offset); - u8* ROM; - u32 ROMLength; - u32 ChipID; - bool IsDSi; - bool DSiMode; - u32 DSiBase; + std::unique_ptr<u8[]> ROM = nullptr; + u32 ROMLength = 0; + u32 ChipID = 0; + bool IsDSi = false; + bool DSiMode = false; + u32 DSiBase = 0; - u32 CmdEncMode; - u32 DataEncMode; + u32 CmdEncMode = 0; + u32 DataEncMode = 0; // Kept separate from the ROM data so we can decrypt the modcrypt area // without touching the overall ROM data - NDSHeader Header; - ROMListEntry ROMParams; + NDSHeader Header {}; + ROMListEntry ROMParams {}; + const melonDS::NDSCart::CartType CartType = Default; }; // CartRetail -- regular retail cart (ROM, SPI SRAM) class CartRetail : public CartCommon { public: - CartRetail(u8* rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams); - virtual ~CartRetail() override; + CartRetail( + const u8* rom, + u32 len, + u32 chipid, + bool badDSiDump, + ROMListEntry romparams, + std::unique_ptr<u8[]>&& sram, + u32 sramlen, + melonDS::NDSCart::CartType type = CartType::Retail + ); + CartRetail( + std::unique_ptr<u8[]>&& rom, + u32 len, u32 chipid, + bool badDSiDump, + ROMListEntry romparams, + std::unique_ptr<u8[]>&& sram, + u32 sramlen, + melonDS::NDSCart::CartType type = CartType::Retail + ); + ~CartRetail() override; - virtual u32 Type() const override { return CartType::Retail; } - - virtual void Reset() override; + void Reset() override; - virtual void DoSavestate(Savestate* file) override; + void DoSavestate(Savestate* file) override; - virtual void SetupSave(u32 type) override; - virtual void LoadSave(const u8* savedata, u32 savelen) override; + void SetSaveMemory(const u8* savedata, u32 savelen) override; - virtual int ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, u8* cmd, u8* data, u32 len) override; + int ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, u8* cmd, u8* data, u32 len) override; - virtual u8 SPIWrite(u8 val, u32 pos, bool last) override; + u8 SPIWrite(u8 val, u32 pos, bool last) override; - virtual u8* GetSaveMemory() const override; - virtual u32 GetSaveMemoryLength() const override; + u8* GetSaveMemory() override { return SRAM.get(); } + const u8* GetSaveMemory() const override { return SRAM.get(); } + u32 GetSaveMemoryLength() const override { return SRAMLength; } protected: void ReadROM_B7(u32 addr, u32 len, u8* data, u32 offset); @@ -132,30 +167,29 @@ protected: u8 SRAMWrite_EEPROM(u8 val, u32 pos, bool last); u8 SRAMWrite_FLASH(u8 val, u32 pos, bool last); - u8* SRAM; - u32 SRAMLength; - u32 SRAMType; + std::unique_ptr<u8[]> SRAM = nullptr; + u32 SRAMLength = 0; + u32 SRAMType = 0; - u8 SRAMCmd; - u32 SRAMAddr; - u32 SRAMFirstAddr; - u8 SRAMStatus; + u8 SRAMCmd = 0; + u32 SRAMAddr = 0; + u32 SRAMFirstAddr = 0; + u8 SRAMStatus = 0; }; // CartRetailNAND -- retail cart with NAND SRAM (WarioWare DIY, Jam with the Band, ...) class CartRetailNAND : public CartRetail { public: - CartRetailNAND(u8* rom, u32 len, u32 chipid, ROMListEntry romparams); + CartRetailNAND(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr<u8[]>&& sram, u32 sramlen); + CartRetailNAND(std::unique_ptr<u8[]>&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr<u8[]>&& sram, u32 sramlen); ~CartRetailNAND() override; - virtual u32 Type() const override { return CartType::RetailNAND; } - void Reset() override; void DoSavestate(Savestate* file) override; - void LoadSave(const u8* savedata, u32 savelen) override; + void SetSaveMemory(const u8* savedata, u32 savelen) override; int ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, u8* cmd, u8* data, u32 len) override; void ROMCommandFinish(u8* cmd, u8* data, u32 len) override; @@ -165,22 +199,21 @@ public: private: void BuildSRAMID(); - u32 SRAMBase; - u32 SRAMWindow; + u32 SRAMBase = 0; + u32 SRAMWindow = 0; - u8 SRAMWriteBuffer[0x800]; - u32 SRAMWritePos; + u8 SRAMWriteBuffer[0x800] {}; + u32 SRAMWritePos = 0; }; // CartRetailIR -- SPI IR device and SRAM class CartRetailIR : public CartRetail { public: - CartRetailIR(u8* rom, u32 len, u32 chipid, u32 irversion, bool badDSiDump, ROMListEntry romparams); + CartRetailIR(const u8* rom, u32 len, u32 chipid, u32 irversion, bool badDSiDump, ROMListEntry romparams, std::unique_ptr<u8[]>&& sram, u32 sramlen); + CartRetailIR(std::unique_ptr<u8[]>&& rom, u32 len, u32 chipid, u32 irversion, bool badDSiDump, ROMListEntry romparams, std::unique_ptr<u8[]>&& sram, u32 sramlen); ~CartRetailIR() override; - virtual u32 Type() const override { return CartType::RetailIR; } - void Reset() override; void DoSavestate(Savestate* file) override; @@ -188,23 +221,18 @@ public: u8 SPIWrite(u8 val, u32 pos, bool last) override; private: - u32 IRVersion; - u8 IRCmd; + u32 IRVersion = 0; + u8 IRCmd = 0; }; // CartRetailBT - Pok�mon Typing Adventure (SPI BT controller) class CartRetailBT : public CartRetail { public: - CartRetailBT(u8* rom, u32 len, u32 chipid, ROMListEntry romparams); + CartRetailBT(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr<u8[]>&& sram, u32 sramlen); + CartRetailBT(std::unique_ptr<u8[]>&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr<u8[]>&& sram, u32 sramlen); ~CartRetailBT() override; - virtual u32 Type() const override { return CartType::RetailBT; } - - void Reset() override; - - void DoSavestate(Savestate* file) override; - u8 SPIWrite(u8 val, u32 pos, bool last) override; }; @@ -212,32 +240,38 @@ public: class CartHomebrew : public CartCommon { public: - CartHomebrew(u8* rom, u32 len, u32 chipid, ROMListEntry romparams); + CartHomebrew(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional<FATStorage>&& sdcard = std::nullopt); + CartHomebrew(std::unique_ptr<u8[]>&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional<FATStorage>&& sdcard = std::nullopt); ~CartHomebrew() override; - virtual u32 Type() const override { return CartType::Homebrew; } - void Reset() override; void SetupDirectBoot(const std::string& romname, NDS& nds) override; - void DoSavestate(Savestate* file) override; - int ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, u8* cmd, u8* data, u32 len) override; void ROMCommandFinish(u8* cmd, u8* data, u32 len) override; + [[nodiscard]] const std::optional<FATStorage>& GetSDCard() const noexcept { return SD; } + void SetSDCard(FATStorage&& sdcard) noexcept { SD = std::move(sdcard); } + void SetSDCard(std::optional<FATStorage>&& sdcard) noexcept + { + SD = std::move(sdcard); + sdcard = std::nullopt; + // moving from an optional doesn't set it to nullopt, + // it just leaves behind an optional with a moved-from value + } + private: void ApplyDLDIPatchAt(u8* binary, u32 dldioffset, const u8* patch, u32 patchlen, bool readonly); void ApplyDLDIPatch(const u8* patch, u32 patchlen, bool readonly); void ReadROM_B7(u32 addr, u32 len, u8* data, u32 offset); - FATStorage* SD; - bool ReadOnly; + std::optional<FATStorage> SD {}; }; class NDSCartSlot { public: - NDSCartSlot(melonDS::NDS& nds) noexcept; + explicit NDSCartSlot(melonDS::NDS& nds, std::unique_ptr<CartCommon>&& rom = nullptr) noexcept; ~NDSCartSlot() noexcept; void Reset() noexcept; void ResetCart() noexcept; @@ -252,25 +286,16 @@ public: /// If the provided cart is not valid, /// then the currently-loaded ROM will not be ejected. /// - /// @param cart Movable reference to the cart. - /// @returns \c true if the cart was successfully loaded, - /// \c false otherwise. + /// @param cart Movable reference to the cart, + /// or \c nullptr to eject the cart. /// @post If the cart was successfully loaded, /// then \c cart will be \c nullptr /// and \c Cart will contain the object that \c cart previously pointed to. /// Otherwise, \c cart and \c Cart will be both be unchanged. - bool InsertROM(std::unique_ptr<CartCommon>&& cart) noexcept; - - /// Parses a ROM image and loads it into the emulator. - /// This function is equivalent to calling ::ParseROM() and ::InsertROM() in sequence. - /// @param romdata Pointer to the ROM image. - /// The cart emulator maintains its own copy of this data, - /// so the caller is free to discard this data after calling this function. - /// @param romlen The length of the ROM image, in bytes. - /// @returns \c true if the ROM image was successfully loaded, - /// \c false if not. - bool LoadROM(const u8* romdata, u32 romlen) noexcept; - void LoadSave(const u8* savedata, u32 savelen) noexcept; + 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 SetupDirectBoot(const std::string& romname) noexcept; /// This function is intended to allow frontends to save and load SRAM @@ -282,11 +307,15 @@ public: /// @returns Pointer to this cart's SRAM if a cart is loaded and supports SRAM, otherwise \c nullptr. [[nodiscard]] const u8* GetSaveMemory() const noexcept { return Cart ? Cart->GetSaveMemory() : nullptr; } [[nodiscard]] u8* GetSaveMemory() noexcept { return Cart ? Cart->GetSaveMemory() : nullptr; } + 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; } - void EjectCart() noexcept; + + /// @return The cart that was in the slot before it was ejected, + /// or \c nullptr if the slot was already empty. + std::unique_ptr<CartCommon> EjectCart() noexcept; u32 ReadROMData() noexcept; void WriteROMData(u32 val) noexcept; void WriteSPICnt(u16 val) noexcept; @@ -294,9 +323,6 @@ public: [[nodiscard]] u8 ReadSPIData() const noexcept; void WriteSPIData(u8 val) noexcept; - [[nodiscard]] CartCommon* GetCart() noexcept { return Cart.get(); } - [[nodiscard]] const CartCommon* GetCart() const noexcept { return Cart.get(); } - [[nodiscard]] u8 GetROMCommand(u8 index) const noexcept { return ROMCommand[index]; } void SetROMCommand(u8 index, u8 val) noexcept { ROMCommand[index] = val; } @@ -306,27 +332,27 @@ public: private: friend class CartCommon; melonDS::NDS& NDS; - u16 SPICnt {}; - u32 ROMCnt {}; + u16 SPICnt = 0; + u32 ROMCnt = 0; std::array<u8, 8> ROMCommand {}; - u8 SPIData; - u32 SPIDataPos; - bool SPIHold; + u8 SPIData = 0; + u32 SPIDataPos = 0; + bool SPIHold = false; - u32 ROMData; + u32 ROMData = 0; - std::array<u8, 0x4000> TransferData; - u32 TransferPos; - u32 TransferLen; - u32 TransferDir; - std::array<u8, 8> TransferCmd; + std::array<u8, 0x4000> TransferData {}; + u32 TransferPos = 0; + u32 TransferLen = 0; + u32 TransferDir = 0; + std::array<u8, 8> TransferCmd {}; - std::unique_ptr<CartCommon> Cart; + std::unique_ptr<CartCommon> Cart = nullptr; - std::array<u32, 0x412> Key1_KeyBuf; + std::array<u32, 0x412> Key1_KeyBuf {}; - u64 Key2_X; - u64 Key2_Y; + u64 Key2_X = 0; + u64 Key2_Y = 0; void Key1_Encrypt(u32* data) noexcept; void Key1_Decrypt(u32* data) noexcept; @@ -346,9 +372,13 @@ private: /// 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. +/// @param sdcard The arguments to use for initializing the SD card. +/// Ignored if the parsed ROM is not homebrew. +/// If not given, the cart will not have an SD card. /// @returns A \c NDSCart::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(const u8* romdata, u32 romlen, std::optional<NDSCartArgs>&& args = std::nullopt); +std::unique_ptr<CartCommon> ParseROM(std::unique_ptr<u8[]>&& romdata, u32 romlen, std::optional<NDSCartArgs>&& args = std::nullopt); } #endif |