diff options
Diffstat (limited to 'src/NDSCart.cpp')
-rw-r--r-- | src/NDSCart.cpp | 377 |
1 files changed, 157 insertions, 220 deletions
diff --git a/src/NDSCart.cpp b/src/NDSCart.cpp index 95306fc..848c619 100644 --- a/src/NDSCart.cpp +++ b/src/NDSCart.cpp @@ -20,12 +20,12 @@ #include "NDS.h" #include "DSi.h" #include "NDSCart.h" -#include "ARM.h" #include "CRC32.h" #include "Platform.h" #include "ROMList.h" #include "melonDLDI.h" -#include "xxhash/xxhash.h" +#include "FATStorage.h" +#include "Utils.h" namespace melonDS { @@ -43,7 +43,7 @@ enum // SRAM TODO: emulate write delays??? -u32 ByteSwap(u32 val) +constexpr u32 ByteSwap(u32 val) { return (val >> 24) | ((val >> 8) & 0xFF00) | ((val << 8) & 0xFF0000) | (val << 24); } @@ -173,27 +173,29 @@ void NDSCartSlot::Key2_Encrypt(u8* data, u32 len) noexcept } -CartCommon::CartCommon(u8* rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams) +CartCommon::CartCommon(const u8* rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams, melonDS::NDSCart::CartType type) : + CartCommon(CopyToUnique(rom, len), len, chipid, badDSiDump, romparams, type) { - ROM = rom; - ROMLength = len; - ChipID = chipid; - ROMParams = romparams; +} - memcpy(&Header, rom, sizeof(Header)); +CartCommon::CartCommon(std::unique_ptr<u8[]>&& rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams, melonDS::NDSCart::CartType type) : + ROM(std::move(rom)), + ROMLength(len), + ChipID(chipid), + ROMParams(romparams), + CartType(type) +{ + memcpy(&Header, ROM.get(), sizeof(Header)); IsDSi = Header.IsDSi() && !badDSiDump; DSiBase = Header.DSiRegionStart << 19; } -CartCommon::~CartCommon() -{ - delete[] ROM; -} +CartCommon::~CartCommon() = default; u32 CartCommon::Checksum() const { const NDSHeader& header = GetHeader(); - u32 crc = CRC32(ROM, 0x40); + u32 crc = CRC32(ROM.get(), 0x40); crc = CRC32(&ROM[header.ARM9ROMOffset], header.ARM9Size, crc); crc = CRC32(&ROM[header.ARM7ROMOffset], header.ARM7Size, crc); @@ -230,14 +232,6 @@ void CartCommon::DoSavestate(Savestate* file) file->Bool32(&DSiMode); } -void CartCommon::SetupSave(u32 type) -{ -} - -void CartCommon::LoadSave(const u8* savedata, u32 savelen) -{ -} - int CartCommon::ROMCommandStart(NDS& nds, NDSCartSlot& cartslot, u8* cmd, u8* data, u32 len) { if (CmdEncMode == 0) @@ -267,7 +261,7 @@ int CartCommon::ROMCommandStart(NDS& nds, NDSCartSlot& cartslot, u8* cmd, u8* da case 0x3C: CmdEncMode = 1; - cartslot.Key1_InitKeycode(false, *(u32*)&ROM[0xC], 2, 2, nds.ARM7BIOS, sizeof(NDS::ARM7BIOS)); + cartslot.Key1_InitKeycode(false, *(u32*)&ROM[0xC], 2, 2, &nds.ARM7BIOS[0], sizeof(NDS::ARM7BIOS)); DSiMode = false; return 0; @@ -276,7 +270,7 @@ int CartCommon::ROMCommandStart(NDS& nds, NDSCartSlot& cartslot, u8* cmd, u8* da { auto& dsi = static_cast<DSi&>(nds); CmdEncMode = 1; - cartslot.Key1_InitKeycode(true, *(u32*)&ROM[0xC], 1, 2, dsi.ARM7iBIOS, sizeof(DSi::ARM7iBIOS)); + cartslot.Key1_InitKeycode(true, *(u32*)&ROM[0xC], 1, 2, &dsi.ARM7iBIOS[0], sizeof(DSi::ARM7iBIOS)); DSiMode = true; } return 0; @@ -360,23 +354,13 @@ u8 CartCommon::SPIWrite(u8 val, u32 pos, bool last) return 0xFF; } -u8 *CartCommon::GetSaveMemory() const -{ - return nullptr; -} - -u32 CartCommon::GetSaveMemoryLength() const -{ - return 0; -} - void CartCommon::ReadROM(u32 addr, u32 len, u8* data, u32 offset) { if (addr >= ROMLength) return; if ((addr+len) > ROMLength) len = ROMLength - addr; - memcpy(data+offset, ROM+addr, len); + memcpy(data+offset, ROM.get()+addr, len); } const NDSBanner* CartCommon::Banner() const @@ -385,22 +369,64 @@ const NDSBanner* CartCommon::Banner() const size_t bannersize = header.IsDSi() ? 0x23C0 : 0xA40; if (header.BannerOffset >= 0x200 && header.BannerOffset < (ROMLength - bannersize)) { - return reinterpret_cast<const NDSBanner*>(ROM + header.BannerOffset); + return reinterpret_cast<const NDSBanner*>(ROM.get() + header.BannerOffset); } return nullptr; } -CartRetail::CartRetail(u8* rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams) : CartCommon(rom, len, chipid, badDSiDump, romparams) +CartRetail::CartRetail(const u8* rom, u32 len, u32 chipid, bool badDSiDump, ROMListEntry romparams, std::unique_ptr<u8[]>&& sram, u32 sramlen, melonDS::NDSCart::CartType type) : + CartRetail(CopyToUnique(rom, len), len, chipid, badDSiDump, romparams, std::move(sram), sramlen, type) { - SRAM = nullptr; } -CartRetail::~CartRetail() +CartRetail::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) : + CartCommon(std::move(rom), len, chipid, badDSiDump, romparams, type) { - if (SRAM) delete[] SRAM; + u32 savememtype = ROMParams.SaveMemType <= 10 ? ROMParams.SaveMemType : 0; + constexpr int sramlengths[] = + { + 0, + 512, + 8192, 65536, 128*1024, + 256*1024, 512*1024, 1024*1024, + 8192*1024, 16384*1024, 65536*1024 + }; + SRAMLength = sramlengths[savememtype]; + + if (SRAMLength) + { // If this cart should have any save data... + if (sram && sramlen == SRAMLength) + { // If we were given save data that already has the correct length... + SRAM = std::move(sram); + } + else + { // Copy in what we can, truncate the rest. + SRAM = std::make_unique<u8[]>(SRAMLength); + memset(SRAM.get(), 0xFF, SRAMLength); + memcpy(SRAM.get(), sram.get(), std::min(sramlen, SRAMLength)); + } + } + + switch (savememtype) + { + case 1: SRAMType = 1; break; // EEPROM, small + case 2: + case 3: + case 4: SRAMType = 2; break; // EEPROM, regular + case 5: + case 6: + case 7: SRAMType = 3; break; // FLASH + case 8: + case 9: + case 10: SRAMType = 4; break; // NAND + default: SRAMType = 0; break; // ...whatever else + } } +CartRetail::~CartRetail() = default; +// std::unique_ptr cleans up the SRAM and ROM + void CartRetail::Reset() { CartCommon::Reset(); @@ -425,13 +451,11 @@ void CartRetail::DoSavestate(Savestate* file) Log(LogLevel::Warn, "savestate: VERY BAD!!!! SRAM LENGTH DIFFERENT. %d -> %d\n", oldlen, SRAMLength); Log(LogLevel::Warn, "oh well. loading it anyway. adsfgdsf\n"); - if (oldlen) delete[] SRAM; - SRAM = nullptr; - if (SRAMLength) SRAM = new u8[SRAMLength]; + SRAM = SRAMLength ? std::make_unique<u8[]>(SRAMLength) : nullptr; } if (SRAMLength) { - file->VarArray(SRAM, SRAMLength); + file->VarArray(SRAM.get(), SRAMLength); } // SPI status shito @@ -441,53 +465,15 @@ void CartRetail::DoSavestate(Savestate* file) file->Var8(&SRAMStatus); if ((!file->Saving) && SRAM) - Platform::WriteNDSSave(SRAM, SRAMLength, 0, SRAMLength); -} - -void CartRetail::SetupSave(u32 type) -{ - if (SRAM) delete[] SRAM; - SRAM = nullptr; - - if (type > 10) type = 0; - int sramlen[] = - { - 0, - 512, - 8192, 65536, 128*1024, - 256*1024, 512*1024, 1024*1024, - 8192*1024, 16384*1024, 65536*1024 - }; - SRAMLength = sramlen[type]; - - if (SRAMLength) - { - SRAM = new u8[SRAMLength]; - memset(SRAM, 0xFF, SRAMLength); - } - - switch (type) - { - case 1: SRAMType = 1; break; // EEPROM, small - case 2: - case 3: - case 4: SRAMType = 2; break; // EEPROM, regular - case 5: - case 6: - case 7: SRAMType = 3; break; // FLASH - case 8: - case 9: - case 10: SRAMType = 4; break; // NAND - default: SRAMType = 0; break; // ...whatever else - } + Platform::WriteNDSSave(SRAM.get(), SRAMLength, 0, SRAMLength); } -void CartRetail::LoadSave(const u8* savedata, u32 savelen) +void CartRetail::SetSaveMemory(const u8* savedata, u32 savelen) { if (!SRAM) return; u32 len = std::min(savelen, SRAMLength); - memcpy(SRAM, savedata, len); + memcpy(SRAM.get(), savedata, len); Platform::WriteNDSSave(savedata, len, 0, len); } @@ -551,16 +537,6 @@ u8 CartRetail::SPIWrite(u8 val, u32 pos, bool last) } } -u8 *CartRetail::GetSaveMemory() const -{ - return SRAM; -} - -u32 CartRetail::GetSaveMemoryLength() const -{ - return SRAMLength; -} - void CartRetail::ReadROM_B7(u32 addr, u32 len, u8* data, u32 offset) { addr &= (ROMLength-1); @@ -578,7 +554,7 @@ void CartRetail::ReadROM_B7(u32 addr, u32 len, u8* data, u32 offset) addr = 0x8000 + (addr & 0x1FF); } - memcpy(data+offset, ROM+addr, len); + memcpy(data+offset, ROM.get()+addr, len); } u8 CartRetail::SRAMWrite_EEPROMTiny(u8 val, u32 pos, bool last) @@ -613,7 +589,7 @@ u8 CartRetail::SRAMWrite_EEPROMTiny(u8 val, u32 pos, bool last) if (last) { SRAMStatus &= ~(1<<1); - Platform::WriteNDSSave(SRAM, SRAMLength, + Platform::WriteNDSSave(SRAM.get(), SRAMLength, (SRAMFirstAddr + ((SRAMCmd==0x0A)?0x100:0)) & 0x1FF, SRAMAddr-SRAMFirstAddr); } return 0; @@ -677,7 +653,7 @@ u8 CartRetail::SRAMWrite_EEPROM(u8 val, u32 pos, bool last) if (last) { SRAMStatus &= ~(1<<1); - Platform::WriteNDSSave(SRAM, SRAMLength, + Platform::WriteNDSSave(SRAM.get(), SRAMLength, SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr); } return 0; @@ -734,7 +710,7 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last) if (last) { SRAMStatus &= ~(1<<1); - Platform::WriteNDSSave(SRAM, SRAMLength, + Platform::WriteNDSSave(SRAM.get(), SRAMLength, SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr); } return 0; @@ -771,7 +747,7 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last) if (last) { SRAMStatus &= ~(1<<1); - Platform::WriteNDSSave(SRAM, SRAMLength, + Platform::WriteNDSSave(SRAM.get(), SRAMLength, SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr); } return 0; @@ -817,7 +793,7 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last) if (last) { SRAMStatus &= ~(1<<1); - Platform::WriteNDSSave(SRAM, SRAMLength, + Platform::WriteNDSSave(SRAM.get(), SRAMLength, SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr); } return 0; @@ -840,7 +816,7 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last) if (last) { SRAMStatus &= ~(1<<1); - Platform::WriteNDSSave(SRAM, SRAMLength, + Platform::WriteNDSSave(SRAM.get(), SRAMLength, SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr); } return 0; @@ -852,15 +828,19 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last) } } - -CartRetailNAND::CartRetailNAND(u8* rom, u32 len, u32 chipid, ROMListEntry romparams) : CartRetail(rom, len, chipid, false, romparams) +CartRetailNAND::CartRetailNAND(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr<u8[]>&& sram, u32 sramlen) : + CartRetailNAND(CopyToUnique(rom, len), len, chipid, romparams, std::move(sram), sramlen) { } -CartRetailNAND::~CartRetailNAND() +CartRetailNAND::CartRetailNAND(std::unique_ptr<u8[]>&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr<u8[]>&& sram, u32 sramlen) : + CartRetail(std::move(rom), len, chipid, false, romparams, std::move(sram), sramlen, CartType::RetailNAND) { + BuildSRAMID(); } +CartRetailNAND::~CartRetailNAND() = default; + void CartRetailNAND::Reset() { CartRetail::Reset(); @@ -889,9 +869,9 @@ void CartRetailNAND::DoSavestate(Savestate* file) BuildSRAMID(); } -void CartRetailNAND::LoadSave(const u8* savedata, u32 savelen) +void CartRetailNAND::SetSaveMemory(const u8* savedata, u32 savelen) { - CartRetail::LoadSave(savedata, savelen); + CartRetail::SetSaveMemory(savedata, savelen); BuildSRAMID(); } @@ -924,7 +904,7 @@ int CartRetailNAND::ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, u8 if (SRAMLength && SRAMAddr < (SRAMBase+SRAMLength-0x20000)) { memcpy(&SRAM[SRAMAddr - SRAMBase], SRAMWriteBuffer, 0x800); - Platform::WriteNDSSave(SRAM, SRAMLength, SRAMAddr - SRAMBase, 0x800); + Platform::WriteNDSSave(SRAM.get(), SRAMLength, SRAMAddr - SRAMBase, 0x800); } SRAMAddr = 0; @@ -1080,15 +1060,28 @@ void CartRetailNAND::BuildSRAMID() } -CartRetailIR::CartRetailIR(u8* rom, u32 len, u32 chipid, u32 irversion, bool badDSiDump, ROMListEntry romparams) : CartRetail(rom, len, chipid, badDSiDump, romparams) +CartRetailIR::CartRetailIR(const u8* rom, u32 len, u32 chipid, u32 irversion, bool badDSiDump, ROMListEntry romparams, std::unique_ptr<u8[]>&& sram, u32 sramlen) : + CartRetailIR(CopyToUnique(rom, len), len, chipid, irversion, badDSiDump, romparams, std::move(sram), sramlen) { - IRVersion = irversion; } -CartRetailIR::~CartRetailIR() +CartRetailIR::CartRetailIR( + std::unique_ptr<u8[]>&& rom, + u32 len, + u32 chipid, + u32 irversion, + bool badDSiDump, + ROMListEntry romparams, + std::unique_ptr<u8[]>&& sram, + u32 sramlen +) : + CartRetail(std::move(rom), len, chipid, badDSiDump, romparams, std::move(sram), sramlen, CartType::RetailIR), + IRVersion(irversion) { } +CartRetailIR::~CartRetailIR() = default; + void CartRetailIR::Reset() { CartRetail::Reset(); @@ -1125,25 +1118,18 @@ u8 CartRetailIR::SPIWrite(u8 val, u32 pos, bool last) return 0; } - -CartRetailBT::CartRetailBT(u8* rom, u32 len, u32 chipid, ROMListEntry romparams) : CartRetail(rom, len, chipid, false, romparams) +CartRetailBT::CartRetailBT(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr<u8[]>&& sram, u32 sramlen) : + CartRetailBT(CopyToUnique(rom, len), len, chipid, romparams, std::move(sram), sramlen) { - Log(LogLevel::Info,"POKETYPE CART\n"); } -CartRetailBT::~CartRetailBT() +CartRetailBT::CartRetailBT(std::unique_ptr<u8[]>&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::unique_ptr<u8[]>&& sram, u32 sramlen) : + CartRetail(std::move(rom), len, chipid, false, romparams, std::move(sram), sramlen, CartType::RetailBT) { + Log(LogLevel::Info,"POKETYPE CART\n"); } -void CartRetailBT::Reset() -{ - CartRetail::Reset(); -} - -void CartRetailBT::DoSavestate(Savestate* file) -{ - CartRetail::DoSavestate(file); -} +CartRetailBT::~CartRetailBT() = default; u8 CartRetailBT::SPIWrite(u8 val, u32 pos, bool last) { @@ -1159,50 +1145,30 @@ u8 CartRetailBT::SPIWrite(u8 val, u32 pos, bool last) return 0; } - -CartHomebrew::CartHomebrew(u8* rom, u32 len, u32 chipid, ROMListEntry romparams) : CartCommon(rom, len, chipid, false, romparams) +CartHomebrew::CartHomebrew(const u8* rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional<FATStorage>&& sdcard) : + CartHomebrew(CopyToUnique(rom, len), len, chipid, romparams, std::move(sdcard)) { - SD = nullptr; } -CartHomebrew::~CartHomebrew() +CartHomebrew::CartHomebrew(std::unique_ptr<u8[]>&& rom, u32 len, u32 chipid, ROMListEntry romparams, std::optional<FATStorage>&& sdcard) : + CartCommon(std::move(rom), len, chipid, false, romparams, CartType::Homebrew), + SD(std::move(sdcard)) { - if (SD) - { - SD->Close(); - delete SD; - } + sdcard = std::nullopt; + // std::move on optionals usually results in an optional with a moved-from object } +CartHomebrew::~CartHomebrew() = default; +// The SD card is destroyed by the optional's destructor + void CartHomebrew::Reset() { CartCommon::Reset(); - ReadOnly = Platform::GetConfigBool(Platform::DLDI_ReadOnly); - if (SD) { - SD->Close(); - delete SD; + ApplyDLDIPatch(melonDLDI, sizeof(melonDLDI), SD->IsReadOnly()); } - - if (Platform::GetConfigBool(Platform::DLDI_Enable)) - { - std::string folderpath; - if (Platform::GetConfigBool(Platform::DLDI_FolderSync)) - folderpath = Platform::GetConfigString(Platform::DLDI_FolderPath); - else - folderpath = ""; - - ApplyDLDIPatch(melonDLDI, sizeof(melonDLDI), ReadOnly); - SD = new FATStorage(Platform::GetConfigString(Platform::DLDI_ImagePath), - (u64)Platform::GetConfigInt(Platform::DLDI_ImageSize) * 1024 * 1024, - ReadOnly, - folderpath); - SD->Open(); - } - else - SD = nullptr; } void CartHomebrew::SetupDirectBoot(const std::string& romname, NDS& nds) @@ -1213,7 +1179,7 @@ void CartHomebrew::SetupDirectBoot(const std::string& romname, NDS& nds) { // add the ROM to the SD volume - if (!SD->InjectFile(romname, ROM, ROMLength)) + if (!SD->InjectFile(romname, ROM.get(), ROMLength)) return; // setup argv command line @@ -1240,11 +1206,6 @@ void CartHomebrew::SetupDirectBoot(const std::string& romname, NDS& nds) } } -void CartHomebrew::DoSavestate(Savestate* file) -{ - CartCommon::DoSavestate(file); -} - int CartHomebrew::ROMCommandStart(NDS& nds, NDSCart::NDSCartSlot& cartslot, u8* cmd, u8* data, u32 len) { if (CmdEncMode != 2) return CartCommon::ROMCommandStart(nds, cartslot, cmd, data, len); @@ -1293,7 +1254,7 @@ void CartHomebrew::ROMCommandFinish(u8* cmd, u8* data, u32 len) case 0xC1: { u32 sector = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]; - if (SD && (!ReadOnly)) SD->WriteSectors(sector, len>>9, data); + if (SD && !SD->IsReadOnly()) SD->WriteSectors(sector, len>>9, data); } break; @@ -1439,17 +1400,20 @@ void CartHomebrew::ReadROM_B7(u32 addr, u32 len, u8* data, u32 offset) addr &= (ROMLength-1); - memcpy(data+offset, ROM+addr, len); + memcpy(data+offset, ROM.get()+addr, len); } -NDSCartSlot::NDSCartSlot(melonDS::NDS& nds) noexcept : NDS(nds) +NDSCartSlot::NDSCartSlot(melonDS::NDS& nds, std::unique_ptr<CartCommon>&& rom) noexcept : NDS(nds) { NDS.RegisterEventFunc(Event_ROMTransfer, ROMTransfer_PrepareData, MemberEventFunc(NDSCartSlot, ROMPrepareData)); NDS.RegisterEventFunc(Event_ROMTransfer, ROMTransfer_End, MemberEventFunc(NDSCartSlot, ROMEndTransfer)); NDS.RegisterEventFunc(Event_ROMSPITransfer, 0, MemberEventFunc(NDSCartSlot, SPITransferDone)); // All fields are default-constructed because they're listed as such in the class declaration + + if (rom) + SetCart(std::move(rom)); } NDSCartSlot::~NDSCartSlot() noexcept @@ -1569,16 +1533,13 @@ void NDSCartSlot::DecryptSecureArea(u8* out) noexcept memcpy(out, &cartrom[arm9base], 0x800); - Key1_InitKeycode(false, gamecode, 2, 2, NDS.ARM7BIOS, sizeof(NDS::ARM7BIOS)); + Key1_InitKeycode(false, gamecode, 2, 2, &NDS.ARM7BIOS[0], sizeof(NDS::ARM7BIOS)); Key1_Decrypt((u32*)&out[0]); - Key1_InitKeycode(false, gamecode, 3, 2, NDS.ARM7BIOS, sizeof(NDS::ARM7BIOS)); + Key1_InitKeycode(false, gamecode, 3, 2, &NDS.ARM7BIOS[0], sizeof(NDS::ARM7BIOS)); for (u32 i = 0; i < 0x800; i += 8) Key1_Decrypt((u32*)&out[i]); - XXH64_hash_t hash = XXH64(out, 0x800, 0); - Log(LogLevel::Debug, "Secure area post-decryption xxh64 hash: %zx\n", hash); - if (!strncmp((const char*)out, "encryObj", 8)) { Log(LogLevel::Info, "Secure area decryption OK\n"); @@ -1593,7 +1554,12 @@ void NDSCartSlot::DecryptSecureArea(u8* out) noexcept } } -std::unique_ptr<CartCommon> ParseROM(const u8* romdata, u32 romlen) +std::unique_ptr<CartCommon> ParseROM(const u8* romdata, u32 romlen, std::optional<NDSCartArgs>&& args) +{ + return ParseROM(CopyToUnique(romdata, romlen), romlen, std::move(args)); +} + +std::unique_ptr<CartCommon> ParseROM(std::unique_ptr<u8[]>&& romdata, u32 romlen, std::optional<NDSCartArgs>&& args) { if (romdata == nullptr) { @@ -1607,28 +1573,10 @@ std::unique_ptr<CartCommon> ParseROM(const u8* romdata, u32 romlen) return nullptr; } - u32 cartromsize = 0x200; - while (cartromsize < romlen) - cartromsize <<= 1; // ROM size must be a power of 2 - - u8* cartrom = nullptr; - try - { - cartrom = new u8[cartromsize]; - } - catch (const std::bad_alloc& e) - { - Log(LogLevel::Error, "NDSCart: failed to allocate memory for ROM (%d bytes)\n", cartromsize); - - return nullptr; - } - - // copy romdata into cartrom then zero out the remaining space - memcpy(cartrom, romdata, romlen); - memset(cartrom + romlen, 0, cartromsize - romlen); + auto [cartrom, cartromsize] = PadToPowerOf2(std::move(romdata), romlen); NDSHeader header {}; - memcpy(&header, cartrom, sizeof(header)); + memcpy(&header, cartrom.get(), sizeof(header)); bool dsi = header.IsDSi(); bool badDSiDump = false; @@ -1694,30 +1642,24 @@ std::unique_ptr<CartCommon> ParseROM(const u8* romdata, u32 romlen) } std::unique_ptr<CartCommon> cart; + auto [sram, sramlen] = args ? std::move(*args->SRAM) : std::make_pair(nullptr, 0); if (homebrew) - cart = std::make_unique<CartHomebrew>(cartrom, cartromsize, cartid, romparams); + cart = std::make_unique<CartHomebrew>(std::move(cartrom), cartromsize, cartid, romparams, args ? std::move(args->SDCard) : std::nullopt); else if (cartid & 0x08000000) - cart = std::make_unique<CartRetailNAND>(cartrom, cartromsize, cartid, romparams); + cart = std::make_unique<CartRetailNAND>(std::move(cartrom), cartromsize, cartid, romparams, std::move(sram), sramlen); else if (irversion != 0) - cart = std::make_unique<CartRetailIR>(cartrom, cartromsize, cartid, irversion, badDSiDump, romparams); + cart = std::make_unique<CartRetailIR>(std::move(cartrom), cartromsize, cartid, irversion, badDSiDump, romparams, std::move(sram), sramlen); else if ((gamecode & 0xFFFFFF) == 0x505A55) // UZPx - cart = std::make_unique<CartRetailBT>(cartrom, cartromsize, cartid, romparams); + cart = std::make_unique<CartRetailBT>(std::move(cartrom), cartromsize, cartid, romparams, std::move(sram), sramlen); else - cart = std::make_unique<CartRetail>(cartrom, cartromsize, cartid, badDSiDump, romparams); - - if (romparams.SaveMemType > 0) - cart->SetupSave(romparams.SaveMemType); + cart = std::make_unique<CartRetail>(std::move(cartrom), cartromsize, cartid, badDSiDump, romparams, std::move(sram), sramlen); + args = std::nullopt; return cart; } -bool NDSCartSlot::InsertROM(std::unique_ptr<CartCommon>&& cart) noexcept +void NDSCartSlot::SetCart(std::unique_ptr<CartCommon>&& cart) noexcept { - if (!cart) { - Log(LogLevel::Error, "Failed to insert invalid cart; existing cart (if any) was not ejected.\n"); - return false; - } - if (Cart) EjectCart(); @@ -1725,6 +1667,10 @@ bool NDSCartSlot::InsertROM(std::unique_ptr<CartCommon>&& cart) noexcept // and cloning polymorphic objects without knowing the underlying type is annoying. Cart = std::move(cart); + if (!Cart) + // If we're ejecting an existing cart without inserting a new one... + return; + Cart->Reset(); const NDSHeader& header = Cart->GetHeader(); @@ -1739,11 +1685,11 @@ bool NDSCartSlot::InsertROM(std::unique_ptr<CartCommon>&& cart) noexcept strncpy((char*)&cartrom[header.ARM9ROMOffset], "encryObj", 8); - Key1_InitKeycode(false, romparams.GameCode, 3, 2, NDS.ARM7BIOS, sizeof(NDS::ARM7BIOS)); + Key1_InitKeycode(false, romparams.GameCode, 3, 2, &NDS.ARM7BIOS[0], sizeof(NDS::ARM7BIOS)); for (u32 i = 0; i < 0x800; i += 8) Key1_Encrypt((u32*)&cartrom[header.ARM9ROMOffset + i]); - Key1_InitKeycode(false, romparams.GameCode, 2, 2, NDS.ARM7BIOS, sizeof(NDS::ARM7BIOS)); + Key1_InitKeycode(false, romparams.GameCode, 2, 2, &NDS.ARM7BIOS[0], sizeof(NDS::ARM7BIOS)); Key1_Encrypt((u32*)&cartrom[header.ARM9ROMOffset]); Log(LogLevel::Debug, "Re-encrypted cart secure area\n"); @@ -1757,21 +1703,12 @@ bool NDSCartSlot::InsertROM(std::unique_ptr<CartCommon>&& cart) noexcept Log(LogLevel::Info, "Inserted cart with game code: %.4s\n", header.GameCode); Log(LogLevel::Info, "Inserted cart with ID: %08X\n", Cart->ID()); Log(LogLevel::Info, "ROM entry: %08X %08X\n", romparams.ROMSize, romparams.SaveMemType); - - return true; -} - -bool NDSCartSlot::LoadROM(const u8* romdata, u32 romlen) noexcept -{ - std::unique_ptr<CartCommon> cart = ParseROM(romdata, romlen); - - return InsertROM(std::move(cart)); } -void NDSCartSlot::LoadSave(const u8* savedata, u32 savelen) noexcept +void NDSCartSlot::SetSaveMemory(const u8* savedata, u32 savelen) noexcept { if (Cart) - Cart->LoadSave(savedata, savelen); + Cart->SetSaveMemory(savedata, savelen); } void NDSCartSlot::SetupDirectBoot(const std::string& romname) noexcept @@ -1780,15 +1717,15 @@ void NDSCartSlot::SetupDirectBoot(const std::string& romname) noexcept Cart->SetupDirectBoot(romname, NDS); } -void NDSCartSlot::EjectCart() noexcept +std::unique_ptr<CartCommon> NDSCartSlot::EjectCart() noexcept { - if (!Cart) return; + if (!Cart) return nullptr; // ejecting the cart triggers the gamecard IRQ NDS.SetIRQ(0, IRQ_CartIREQMC); NDS.SetIRQ(1, IRQ_CartIREQMC); - Cart = nullptr; + return std::move(Cart); // CHECKME: does an eject imply anything for the ROM/SPI transfer registers? } |