proof-of-concept system for GBA slot addons

This commit is contained in:
Arisotura
2022-01-03 10:05:37 +01:00
parent cdff61c209
commit 46656eccda
10 changed files with 246 additions and 78 deletions

View File

@ -530,9 +530,6 @@ void SoftReset()
NDS::MapSharedWRAM(3); NDS::MapSharedWRAM(3);
// FIXME!!!!!
//memcpy(NDS::ARM9->ITCM, ITCMInit, 0x8000);
// TODO: does the DSP get reset? NWRAM doesn't, so I'm assuming no // 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 // *HOWEVER*, the bootrom (which does get rerun) does remap NWRAM, and thus
// the DSP most likely gets reset // the DSP most likely gets reset
@ -548,9 +545,6 @@ void SoftReset()
DSi_AES::Reset(); 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_BIOS = 0x0101; // TODO: should be zero when booting from BIOS
SCFG_Clock9 = 0x0187; // CHECKME SCFG_Clock9 = 0x0187; // CHECKME
SCFG_Clock7 = 0x0187; SCFG_Clock7 = 0x0187;
@ -565,20 +559,6 @@ void SoftReset()
// LCD init flag // LCD init flag
GPU::DispStat[0] |= (1<<6); GPU::DispStat[0] |= (1<<6);
GPU::DispStat[1] |= (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() bool LoadBIOS()

View File

@ -18,6 +18,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "NDS.h"
#include "GBACart.h" #include "GBACart.h"
#include "CRC32.h" #include "CRC32.h"
#include "Platform.h" #include "Platform.h"
@ -58,6 +59,10 @@ CartCommon::~CartCommon()
{ {
} }
void CartCommon::Reset()
{
}
void CartCommon::DoSavestate(Savestate* file) void CartCommon::DoSavestate(Savestate* file)
{ {
file->Section("GBCS"); file->Section("GBCS");
@ -107,7 +112,16 @@ CartGame::CartGame(u8* rom, u32 len) : CartCommon()
{ {
ROM = rom; ROM = rom;
ROMLength = len; ROMLength = len;
}
CartGame::~CartGame()
{
//if (SRAMFile) fclose(SRAMFile);
if (SRAM) delete[] SRAM;
}
void CartGame::Reset()
{
memset(&GPIO, 0, sizeof(GPIO)); memset(&GPIO, 0, sizeof(GPIO));
SRAM = nullptr; SRAM = nullptr;
@ -117,12 +131,6 @@ CartGame::CartGame(u8* rom, u32 len) : CartCommon()
SRAMFlashState = {}; SRAMFlashState = {};
} }
CartGame::~CartGame()
{
//if (SRAMFile) fclose(SRAMFile);
if (SRAM) delete[] SRAM;
}
void CartGame::DoSavestate(Savestate* file) void CartGame::DoSavestate(Savestate* file)
{ {
CartCommon::DoSavestate(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) CartGameSolarSensor::CartGameSolarSensor(u8* rom, u32 len) : CartGame(rom, len)
{ {
LightEdge = false;
LightCounter = 0;
LightSample = 0xFF;
LightLevel = 0;
} }
CartGameSolarSensor::~CartGameSolarSensor() CartGameSolarSensor::~CartGameSolarSensor()
{ {
} }
void CartGameSolarSensor::Reset()
{
LightEdge = false;
LightCounter = 0;
LightSample = 0xFF;
LightLevel = 0;
}
void CartGameSolarSensor::DoSavestate(Savestate* file) void CartGameSolarSensor::DoSavestate(Savestate* file)
{ {
CartGame::DoSavestate(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() bool Init()
{ {
CartROM = nullptr; CartROM = nullptr;
@ -636,30 +728,7 @@ void DeInit()
void Reset() void Reset()
{ {
// Do not reset cartridge ROM. if (Cart) Cart->Reset();
// 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();
} }
void DoSavestate(Savestate* file) void DoSavestate(Savestate* file)
@ -672,10 +741,10 @@ void DoSavestate(Savestate* file)
// since unlike with DS, it's not loaded in advance // since unlike with DS, it's not loaded in advance
file->Var32(&CartROMSize); 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 // do eject the cartridge if something is inserted
Eject(); EjectCart();
return; return;
} }
@ -760,6 +829,9 @@ bool LoadROM(const u8* romdata, u32 romlen)
else else
Cart = new CartGame(CartROM, CartROMSize); Cart = new CartGame(CartROM, CartROMSize);
if (Cart)
Cart->Reset();
// save // save
//printf("GBA save file: %s\n", sram); //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) /*bool LoadROM(const char* path, const char* sram)
{ {
FILE* f = Platform::OpenFile(path, "rb"); FILE* f = Platform::OpenFile(path, "rb");

View File

@ -31,6 +31,7 @@ class CartCommon
public: public:
CartCommon(); CartCommon();
virtual ~CartCommon(); virtual ~CartCommon();
virtual void Reset();
virtual void DoSavestate(Savestate* file); virtual void DoSavestate(Savestate* file);
@ -54,6 +55,7 @@ class CartGame : public CartCommon
public: public:
CartGame(u8* rom, u32 len); CartGame(u8* rom, u32 len);
virtual ~CartGame() override; virtual ~CartGame() override;
virtual void Reset() override;
virtual void DoSavestate(Savestate* file) override; virtual void DoSavestate(Savestate* file) override;
@ -124,6 +126,7 @@ class CartGameSolarSensor : public CartGame
public: public:
CartGameSolarSensor(u8* rom, u32 len); CartGameSolarSensor(u8* rom, u32 len);
virtual ~CartGameSolarSensor() override; virtual ~CartGameSolarSensor() override;
virtual void Reset() override;
virtual void DoSavestate(Savestate* file) override; virtual void DoSavestate(Savestate* file) override;
@ -140,6 +143,24 @@ private:
u8 LightLevel; 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 // possible inputs for GBA carts that might accept user input
enum enum
{ {
@ -155,13 +176,16 @@ extern u32 CartCRC;
bool Init(); bool Init();
void DeInit(); void DeInit();
void Reset(); void Reset();
void Eject();
void DoSavestate(Savestate* file); void DoSavestate(Savestate* file);
bool LoadROM(const u8* romdata, u32 romlen); bool LoadROM(const u8* romdata, u32 romlen);
void LoadSave(const u8* savedata, u32 savelen); void LoadSave(const u8* savedata, u32 savelen);
void LoadAddon(int type);
void EjectCart();
//bool LoadROM(const char* path, const char* sram); //bool LoadROM(const char* path, const char* sram);
//bool LoadROM(const u8* romdata, u32 filelength, const char *sram); //bool LoadROM(const u8* romdata, u32 filelength, const char *sram);
//void RelocateSave(const char* path, bool write); //void RelocateSave(const char* path, bool write);

View File

@ -943,13 +943,16 @@ bool LoadGBACart(const u8* romdata, u32 romlen, const u8* savedata, u32 savelen)
if (savedata && savelen) if (savedata && savelen)
GBACart::LoadSave(savedata, savelen); GBACart::LoadSave(savedata, savelen);
}
//Running = true; void LoadGBAAddon(int type)
{
GBACart::LoadAddon(type);
} }
void EjectGBACart() void EjectGBACart()
{ {
printf("TODO!!!!\n"); GBACart::EjectCart();
} }
/*bool LoadROM(const u8* romdata, u32 filelength, const char *sram, bool direct) /*bool LoadROM(const u8* romdata, u32 filelength, const char *sram, bool direct)

View File

@ -164,6 +164,12 @@ struct MemRegion
u32 Mask; u32 Mask;
}; };
// supported GBA slot addon types
enum
{
GBAAddon_RAMExpansion = 1,
};
#ifdef JIT_ENABLED #ifdef JIT_ENABLED
extern bool EnableJIT; extern bool EnableJIT;
#endif #endif
@ -246,6 +252,7 @@ bool NeedsDirectBoot();
void SetupDirectBoot(std::string romname); void SetupDirectBoot(std::string romname);
bool LoadGBACart(const u8* romdata, u32 romlen, const u8* savedata, u32 savelen); bool LoadGBACart(const u8* romdata, u32 romlen, const u8* savedata, u32 savelen);
void LoadGBAAddon(int type);
void EjectGBACart(); void EjectGBACart();
//void RelocateSave(const char* path, bool write); //void RelocateSave(const char* path, bool write);

View File

@ -320,7 +320,7 @@ int LoadROM(const u8 *romdata, u32 romlength, const char *archivefilename, const
res = SetupDSiNAND(); res = SetupDSiNAND();
if (res != Load_OK) return res; if (res != Load_OK) return res;
GBACart::Eject(); //GBACart::Eject();
ROMPath[ROMSlot_GBA] = ""; ROMPath[ROMSlot_GBA] = "";
} }
else else
@ -398,7 +398,7 @@ int LoadROM(const char* file, int slot)
res = SetupDSiNAND(); res = SetupDSiNAND();
if (res != Load_OK) return res; if (res != Load_OK) return res;
GBACart::Eject(); //GBACart::Eject();
ROMPath[ROMSlot_GBA] = ""; ROMPath[ROMSlot_GBA] = "";
} }
else else
@ -525,7 +525,7 @@ void UnloadROM(int slot)
} }
else if (slot == ROMSlot_GBA) else if (slot == ROMSlot_GBA)
{ {
GBACart::Eject(); // GBACart::Eject();
} }
ROMPath[slot] = ""; ROMPath[slot] = "";
@ -554,7 +554,7 @@ int Reset()
res = SetupDSiNAND(); res = SetupDSiNAND();
if (res != Load_OK) return res; if (res != Load_OK) return res;
GBACart::Eject(); // GBACart::Eject();
ROMPath[ROMSlot_GBA][0] = '\0'; ROMPath[ROMSlot_GBA][0] = '\0';
} }
else else

View File

@ -44,6 +44,8 @@ std::string BaseROMDir;
std::string BaseROMName; std::string BaseROMName;
std::string BaseAssetName; std::string BaseAssetName;
int GBACartType;
int LastSep(std::string path) 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() bool LoadBIOS()
{ {
NDS::SetConsoleType(Config::ConsoleType); NDS::SetConsoleType(Config::ConsoleType);
@ -413,9 +430,25 @@ QString CartLabel()
void LoadGBAAddon(int type)
{
NDS::LoadGBAAddon(type);
GBACartType = type;
}
// PLACEHOLDER // PLACEHOLDER
QString GBACartLabel() QString GBACartLabel()
{ {
switch (GBACartType)
{
case 0:
return "it's a ROM (TODO)";
case NDS::GBAAddon_RAMExpansion:
return "Memory expansion";
}
return "(none)"; return "(none)";
} }

View File

@ -28,12 +28,15 @@ namespace ROMLoader
{ {
QString VerifySetup(); QString VerifySetup();
void Reset();
bool LoadBIOS(); bool LoadBIOS();
bool LoadROM(QStringList filepath, bool reset); bool LoadROM(QStringList filepath, bool reset);
void EjectCart(); void EjectCart();
QString CartLabel(); QString CartLabel();
bool LoadGBAROM(QStringList filepath, bool reset); bool LoadGBAROM(QStringList filepath, bool reset);
void LoadGBAAddon(int type);
void EjectGBACart(); void EjectGBACart();
QString GBACartLabel(); QString GBACartLabel();

View File

@ -1328,14 +1328,17 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
{ {
QMenu* submenu = menu->addMenu("Insert add-on cart"); 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[1] = submenu->addAction("Vibrator Pak");
actInsertGBAAddon[2] = submenu->addAction("Guitar Hero grip"); actInsertGBAAddon[2] = submenu->addAction("Guitar Hero grip");
actInsertGBAAddon[3] = submenu->addAction("Fartslapper"); actInsertGBAAddon[3] = submenu->addAction("Fartslapper");
actInsertGBAAddon[4] = submenu->addAction("Fartslapper Mk. II"); actInsertGBAAddon[4] = submenu->addAction("Fartslapper Mk. II");
actInsertGBAAddon[5] = submenu->addAction("Ghostbusters ray"); actInsertGBAAddon[5] = submenu->addAction("Ghostbusters ray");
actInsertGBAAddon[6] = submenu->addAction("Fridge Pak"); 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"); actEjectGBACart = menu->addAction("Eject cart");
@ -2356,6 +2359,23 @@ void MainWindow::onEjectCart()
actEjectCart->setEnabled(false); 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() void MainWindow::onSaveState()
{ {
int slot = ((QAction*)sender())->data().toInt(); int slot = ((QAction*)sender())->data().toInt();
@ -2534,19 +2554,10 @@ void MainWindow::onReset()
actUndoStateLoad->setEnabled(false); actUndoStateLoad->setEnabled(false);
int res = Frontend::Reset(); ROMLoader::Reset();
if (res != Frontend::Load_OK)
{ OSD::AddMessage(0, "Reset");
QMessageBox::critical(this, emuThread->emuRun();
"melonDS",
loadErrorStr(res));
emuThread->emuUnpause();
}
else
{
OSD::AddMessage(0, "Reset");
emuThread->emuRun();
}
} }
void MainWindow::onStop() void MainWindow::onStop()

View File

@ -235,6 +235,7 @@ private slots:
void onBootFirmware(); void onBootFirmware();
void onInsertCart(); void onInsertCart();
void onEjectCart(); void onEjectCart();
void onInsertGBAAddon();
void onSaveState(); void onSaveState();
void onLoadState(); void onLoadState();
void onUndoStateLoad(); void onUndoStateLoad();