From 46656eccda78a90a2e8a64b7c197c1cc9b8614cd Mon Sep 17 00:00:00 2001 From: Arisotura Date: Mon, 3 Jan 2022 10:05:37 +0100 Subject: [PATCH] proof-of-concept system for GBA slot addons --- src/DSi.cpp | 20 ---- src/GBACart.cpp | 178 ++++++++++++++++++++++++------ src/GBACart.h | 26 ++++- src/NDS.cpp | 7 +- src/NDS.h | 7 ++ src/frontend/Util_ROM.cpp | 8 +- src/frontend/qt_sdl/ROMLoader.cpp | 33 ++++++ src/frontend/qt_sdl/ROMLoader.h | 3 + src/frontend/qt_sdl/main.cpp | 41 ++++--- src/frontend/qt_sdl/main.h | 1 + 10 files changed, 246 insertions(+), 78 deletions(-) diff --git a/src/DSi.cpp b/src/DSi.cpp index 0f8fd943..2d559c26 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -530,9 +530,6 @@ void SoftReset() NDS::MapSharedWRAM(3); - // FIXME!!!!! - //memcpy(NDS::ARM9->ITCM, ITCMInit, 0x8000); - // TODO: does the DSP get reset? NWRAM doesn't, so I'm assuming no // *HOWEVER*, the bootrom (which does get rerun) does remap NWRAM, and thus // the DSP most likely gets reset @@ -548,9 +545,6 @@ void SoftReset() DSi_AES::Reset(); - //NDS::ARM9->JumpTo(BootAddr[0]); - //NDS::ARM7->JumpTo(BootAddr[1]); - SCFG_BIOS = 0x0101; // TODO: should be zero when booting from BIOS SCFG_Clock9 = 0x0187; // CHECKME SCFG_Clock7 = 0x0187; @@ -565,20 +559,6 @@ void SoftReset() // LCD init flag GPU::DispStat[0] |= (1<<6); GPU::DispStat[1] |= (1<<6); - - //for (u32 i = 0; i < 0x3C00; i+=4) - // ARM7Write32(0x03FFC400+i, *(u32*)&ARM7Init[i]); - - u32 eaddr = 0x03FFE6E4; - ARM7Write32(eaddr+0x00, *(u32*)&eMMC_CID[0]); - ARM7Write32(eaddr+0x04, *(u32*)&eMMC_CID[4]); - ARM7Write32(eaddr+0x08, *(u32*)&eMMC_CID[8]); - ARM7Write32(eaddr+0x0C, *(u32*)&eMMC_CID[12]); - ARM7Write16(eaddr+0x2C, 0x0001); - ARM7Write16(eaddr+0x2E, 0x0001); - ARM7Write16(eaddr+0x3C, 0x0100); - ARM7Write16(eaddr+0x3E, 0x40E0); - ARM7Write16(eaddr+0x42, 0x0001); } bool LoadBIOS() diff --git a/src/GBACart.cpp b/src/GBACart.cpp index 7e56c8a4..34e6fb60 100644 --- a/src/GBACart.cpp +++ b/src/GBACart.cpp @@ -18,6 +18,7 @@ #include #include +#include "NDS.h" #include "GBACart.h" #include "CRC32.h" #include "Platform.h" @@ -58,6 +59,10 @@ CartCommon::~CartCommon() { } +void CartCommon::Reset() +{ +} + void CartCommon::DoSavestate(Savestate* file) { file->Section("GBCS"); @@ -107,7 +112,16 @@ CartGame::CartGame(u8* rom, u32 len) : CartCommon() { ROM = rom; ROMLength = len; +} +CartGame::~CartGame() +{ + //if (SRAMFile) fclose(SRAMFile); + if (SRAM) delete[] SRAM; +} + +void CartGame::Reset() +{ memset(&GPIO, 0, sizeof(GPIO)); SRAM = nullptr; @@ -117,12 +131,6 @@ CartGame::CartGame(u8* rom, u32 len) : CartCommon() SRAMFlashState = {}; } -CartGame::~CartGame() -{ - //if (SRAMFile) fclose(SRAMFile); - if (SRAM) delete[] SRAM; -} - void CartGame::DoSavestate(Savestate* file) { CartCommon::DoSavestate(file); @@ -554,16 +562,20 @@ const int CartGameSolarSensor::kLuxLevels[11] = {0, 5, 11, 18, 27, 42, 62, 84, 1 CartGameSolarSensor::CartGameSolarSensor(u8* rom, u32 len) : CartGame(rom, len) { - LightEdge = false; - LightCounter = 0; - LightSample = 0xFF; - LightLevel = 0; } CartGameSolarSensor::~CartGameSolarSensor() { } +void CartGameSolarSensor::Reset() +{ + LightEdge = false; + LightCounter = 0; + LightSample = 0xFF; + LightLevel = 0; +} + void CartGameSolarSensor::DoSavestate(Savestate* file) { CartGame::DoSavestate(file); @@ -618,6 +630,86 @@ void CartGameSolarSensor::ProcessGPIO() } +CartRAMExpansion::CartRAMExpansion() : CartCommon() +{ +} + +CartRAMExpansion::~CartRAMExpansion() +{ +} + +void CartRAMExpansion::Reset() +{ + memset(RAM, 0xFF, sizeof(RAM)); + RAMEnable = 1; +} + +void CartRAMExpansion::DoSavestate(Savestate* file) +{ + CartCommon::DoSavestate(file); + + file->VarArray(RAM, sizeof(RAM)); + file->Var16(&RAMEnable); +} + +u16 CartRAMExpansion::ROMRead(u32 addr) +{ + addr &= 0x01FFFFFF; + + if (addr < 0x01000000) + { + switch (addr) + { + case 0xB0: return 0xFFFF; + case 0xB2: return 0x0000; + case 0xB4: return 0x2400; + case 0xB6: return 0x2424; + case 0xB8: return 0xFFFF; + case 0xBA: return 0xFFFF; + case 0xBC: return 0xFFFF; + case 0xBE: return 0x7FFF; + + case 0x1FFFC: return 0xFFFF; + case 0x1FFFE: return 0x7FFF; + + case 0x240000: return RAMEnable; + case 0x240002: return 0x0000; + } + + return 0xFFFF; + } + else if (addr < 0x01800000) + { + if (!RAMEnable) return 0xFFFF; + + return *(u16*)&RAM[addr & 0x7FFFFF]; + } + + return 0xFFFF; +} + +void CartRAMExpansion::ROMWrite(u32 addr, u16 val) +{ + addr &= 0x01FFFFFF; + + if (addr < 0x01000000) + { + switch (addr) + { + case 0x240000: + RAMEnable = val & 0x0001; + return; + } + } + else if (addr < 0x01800000) + { + if (!RAMEnable) return; + + *(u16*)&RAM[addr & 0x7FFFFF] = val; + } +} + + bool Init() { CartROM = nullptr; @@ -636,30 +728,7 @@ void DeInit() void Reset() { - // Do not reset cartridge ROM. - // Prefer keeping the inserted cartridge on reset. - // This allows resetting a DS game without losing GBA state, - // and resetting to firmware without the slot being emptied. - // The Stop function will clear the cartridge state via Eject(). - - // OpenBusDecay doesn't need to be reset, either, as it will be set - // through NDS::SetGBASlotTimings(). -} - -void Eject() -{ - if (Cart) delete Cart; - Cart = nullptr; - - if (CartROM) delete[] CartROM; - - CartInserted = false; - CartROM = NULL; - CartROMSize = 0; - CartCRC = 0; - CartID = 0; - - Reset(); + if (Cart) Cart->Reset(); } void DoSavestate(Savestate* file) @@ -672,10 +741,10 @@ void DoSavestate(Savestate* file) // since unlike with DS, it's not loaded in advance file->Var32(&CartROMSize); - if (!CartROMSize) // no GBA cartridge state? nothing to do here + if (!CartROMSize) // no GBA cartridge state? nothing to do here (no! FIXME) { // do eject the cartridge if something is inserted - Eject(); + EjectCart(); return; } @@ -760,6 +829,9 @@ bool LoadROM(const u8* romdata, u32 romlen) else Cart = new CartGame(CartROM, CartROMSize); + if (Cart) + Cart->Reset(); + // save //printf("GBA save file: %s\n", sram); @@ -782,6 +854,40 @@ void LoadSave(const u8* savedata, u32 savelen) } } +void LoadAddon(int type) +{ + CartROMSize = 0; + CartROM = nullptr; + CartCRC = 0; + + switch (type) + { + case NDS::GBAAddon_RAMExpansion: + Cart = new CartRAMExpansion(); + break; + + default: + printf("GBACart: !! invalid addon type %d\n", type); + return; + } + + CartInserted = true; +} + +void EjectCart() +{ + if (Cart) delete Cart; + Cart = nullptr; + + if (CartROM) delete[] CartROM; + + CartInserted = false; + CartROM = nullptr; + CartROMSize = 0; + CartCRC = 0; + CartID = 0; +} + /*bool LoadROM(const char* path, const char* sram) { FILE* f = Platform::OpenFile(path, "rb"); diff --git a/src/GBACart.h b/src/GBACart.h index 0f2bf5c1..b5d2ba11 100644 --- a/src/GBACart.h +++ b/src/GBACart.h @@ -31,6 +31,7 @@ class CartCommon public: CartCommon(); virtual ~CartCommon(); + virtual void Reset(); virtual void DoSavestate(Savestate* file); @@ -54,6 +55,7 @@ class CartGame : public CartCommon public: CartGame(u8* rom, u32 len); virtual ~CartGame() override; + virtual void Reset() override; virtual void DoSavestate(Savestate* file) override; @@ -124,6 +126,7 @@ class CartGameSolarSensor : public CartGame public: CartGameSolarSensor(u8* rom, u32 len); virtual ~CartGameSolarSensor() override; + virtual void Reset() override; virtual void DoSavestate(Savestate* file) override; @@ -140,6 +143,24 @@ private: u8 LightLevel; }; +// 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) 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 { @@ -155,13 +176,16 @@ extern u32 CartCRC; bool Init(); void DeInit(); void Reset(); -void Eject(); void DoSavestate(Savestate* file); bool LoadROM(const u8* romdata, u32 romlen); void LoadSave(const u8* savedata, u32 savelen); +void LoadAddon(int type); + +void EjectCart(); + //bool LoadROM(const char* path, const char* sram); //bool LoadROM(const u8* romdata, u32 filelength, const char *sram); //void RelocateSave(const char* path, bool write); diff --git a/src/NDS.cpp b/src/NDS.cpp index 2957cadb..346bcb7d 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -943,13 +943,16 @@ bool LoadGBACart(const u8* romdata, u32 romlen, const u8* savedata, u32 savelen) if (savedata && savelen) GBACart::LoadSave(savedata, savelen); +} - //Running = true; +void LoadGBAAddon(int type) +{ + GBACart::LoadAddon(type); } void EjectGBACart() { - printf("TODO!!!!\n"); + GBACart::EjectCart(); } /*bool LoadROM(const u8* romdata, u32 filelength, const char *sram, bool direct) diff --git a/src/NDS.h b/src/NDS.h index 5906172a..e1576078 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -164,6 +164,12 @@ struct MemRegion u32 Mask; }; +// supported GBA slot addon types +enum +{ + GBAAddon_RAMExpansion = 1, +}; + #ifdef JIT_ENABLED extern bool EnableJIT; #endif @@ -246,6 +252,7 @@ bool NeedsDirectBoot(); void SetupDirectBoot(std::string romname); bool LoadGBACart(const u8* romdata, u32 romlen, const u8* savedata, u32 savelen); +void LoadGBAAddon(int type); void EjectGBACart(); //void RelocateSave(const char* path, bool write); diff --git a/src/frontend/Util_ROM.cpp b/src/frontend/Util_ROM.cpp index 26e513d2..a001ba47 100644 --- a/src/frontend/Util_ROM.cpp +++ b/src/frontend/Util_ROM.cpp @@ -320,7 +320,7 @@ int LoadROM(const u8 *romdata, u32 romlength, const char *archivefilename, const res = SetupDSiNAND(); if (res != Load_OK) return res; - GBACart::Eject(); + //GBACart::Eject(); ROMPath[ROMSlot_GBA] = ""; } else @@ -398,7 +398,7 @@ int LoadROM(const char* file, int slot) res = SetupDSiNAND(); if (res != Load_OK) return res; - GBACart::Eject(); + //GBACart::Eject(); ROMPath[ROMSlot_GBA] = ""; } else @@ -525,7 +525,7 @@ void UnloadROM(int slot) } else if (slot == ROMSlot_GBA) { - GBACart::Eject(); +// GBACart::Eject(); } ROMPath[slot] = ""; @@ -554,7 +554,7 @@ int Reset() res = SetupDSiNAND(); if (res != Load_OK) return res; - GBACart::Eject(); +// GBACart::Eject(); ROMPath[ROMSlot_GBA][0] = '\0'; } else diff --git a/src/frontend/qt_sdl/ROMLoader.cpp b/src/frontend/qt_sdl/ROMLoader.cpp index 789e713d..aeaddbe2 100644 --- a/src/frontend/qt_sdl/ROMLoader.cpp +++ b/src/frontend/qt_sdl/ROMLoader.cpp @@ -44,6 +44,8 @@ std::string BaseROMDir; std::string BaseROMName; std::string BaseAssetName; +int GBACartType; + int LastSep(std::string path) { @@ -256,6 +258,21 @@ QString VerifySetup() } +void Reset() +{ + NDS::SetConsoleType(Config::ConsoleType); + NDS::Reset(); + + if (!BaseROMName.empty()) + { + if (Config::DirectBoot || NDS::NeedsDirectBoot()) + { + NDS::SetupDirectBoot(BaseROMName); + } + } +} + + bool LoadBIOS() { NDS::SetConsoleType(Config::ConsoleType); @@ -413,9 +430,25 @@ QString CartLabel() +void LoadGBAAddon(int type) +{ + NDS::LoadGBAAddon(type); + + GBACartType = type; +} + // PLACEHOLDER QString GBACartLabel() { + switch (GBACartType) + { + case 0: + return "it's a ROM (TODO)"; + + case NDS::GBAAddon_RAMExpansion: + return "Memory expansion"; + } + return "(none)"; } diff --git a/src/frontend/qt_sdl/ROMLoader.h b/src/frontend/qt_sdl/ROMLoader.h index b6c5b58e..723ce815 100644 --- a/src/frontend/qt_sdl/ROMLoader.h +++ b/src/frontend/qt_sdl/ROMLoader.h @@ -28,12 +28,15 @@ namespace ROMLoader { QString VerifySetup(); +void Reset(); bool LoadBIOS(); + bool LoadROM(QStringList filepath, bool reset); void EjectCart(); QString CartLabel(); bool LoadGBAROM(QStringList filepath, bool reset); +void LoadGBAAddon(int type); void EjectGBACart(); QString GBACartLabel(); diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index 46702282..6836a73d 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -1328,14 +1328,17 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) { QMenu* submenu = menu->addMenu("Insert add-on cart"); - actInsertGBAAddon[0] = submenu->addAction("Memory expansion"); + /*actInsertGBAAddon[0] = submenu->addAction("Memory expansion"); actInsertGBAAddon[1] = submenu->addAction("Vibrator Pak"); actInsertGBAAddon[2] = submenu->addAction("Guitar Hero grip"); actInsertGBAAddon[3] = submenu->addAction("Fartslapper"); actInsertGBAAddon[4] = submenu->addAction("Fartslapper Mk. II"); actInsertGBAAddon[5] = submenu->addAction("Ghostbusters ray"); actInsertGBAAddon[6] = submenu->addAction("Fridge Pak"); - actInsertGBAAddon[7] = submenu->addAction("Fazil"); + actInsertGBAAddon[7] = submenu->addAction("Fazil");*/ + actInsertGBAAddon[0] = submenu->addAction("Memory expansion"); + actInsertGBAAddon[0]->setData(QVariant(NDS::GBAAddon_RAMExpansion)); + connect(actInsertGBAAddon[0], &QAction::triggered, this, &MainWindow::onInsertGBAAddon); } actEjectGBACart = menu->addAction("Eject cart"); @@ -2356,6 +2359,23 @@ void MainWindow::onEjectCart() actEjectCart->setEnabled(false); } +void MainWindow::onInsertGBAAddon() +{ + QAction* act = (QAction*)sender(); + int type = act->data().toInt(); + + printf("INSERT: %d\n", type); + + emuThread->emuPause(); + + ROMLoader::LoadGBAAddon(type); + + emuThread->emuUnpause(); + + actCurrentGBACart->setText("GBA slot: " + ROMLoader::GBACartLabel()); + actEjectGBACart->setEnabled(true); +} + void MainWindow::onSaveState() { int slot = ((QAction*)sender())->data().toInt(); @@ -2534,19 +2554,10 @@ void MainWindow::onReset() actUndoStateLoad->setEnabled(false); - int res = Frontend::Reset(); - if (res != Frontend::Load_OK) - { - QMessageBox::critical(this, - "melonDS", - loadErrorStr(res)); - emuThread->emuUnpause(); - } - else - { - OSD::AddMessage(0, "Reset"); - emuThread->emuRun(); - } + ROMLoader::Reset(); + + OSD::AddMessage(0, "Reset"); + emuThread->emuRun(); } void MainWindow::onStop() diff --git a/src/frontend/qt_sdl/main.h b/src/frontend/qt_sdl/main.h index 0f0eee88..6c911599 100644 --- a/src/frontend/qt_sdl/main.h +++ b/src/frontend/qt_sdl/main.h @@ -235,6 +235,7 @@ private slots: void onBootFirmware(); void onInsertCart(); void onEjectCart(); + void onInsertGBAAddon(); void onSaveState(); void onLoadState(); void onUndoStateLoad();