Add support for NDS devkit (8MB) and 3DS (32MB) MainRAM configurations

This commit is contained in:
shinyquagsire23 2025-07-18 15:36:17 -06:00
parent f8b4871900
commit b17e38ba81
10 changed files with 156 additions and 18 deletions

View File

@ -1038,6 +1038,12 @@ bool ARMJIT_Memory::GetMirrorLocation(int region, u32 num, u32 addr, u32& memory
}
return false;
case memregion_MainRAM:
// 0x02xxxxxx region is limited to 16MiB
if (addr < 0x0C000000) {
mirrorStart = addr & ~(NDS.MainRAMMask & 0xFFFFFF);
mirrorSize = (NDS.MainRAMMask & 0xFFFFFF) + 1;
return true;
}
mirrorStart = addr & ~NDS.MainRAMMask;
mirrorSize = NDS.MainRAMMask + 1;
return true;
@ -1283,6 +1289,8 @@ int ARMJIT_Memory::ClassifyAddress9(u32 addr) const noexcept
return memregion_VRAM;
case 0x0C000000:
return (NDS.ConsoleType==1) ? memregion_MainRAM : memregion_Other;
case 0x0D000000:
return (NDS.ConsoleType==1 && NDS.MainRAMMask>=0x1FFFFFF) ? memregion_MainRAM : memregion_Other;
default:
return memregion_Other;
}
@ -1341,6 +1349,9 @@ int ARMJIT_Memory::ClassifyAddress7(u32 addr) const noexcept
case 0x0C000000:
case 0x0C800000:
return (NDS.ConsoleType==1) ? memregion_MainRAM : memregion_Other;
case 0x0D000000:
case 0x0D800000:
return (NDS.ConsoleType==1 && NDS.MainRAMMask>=0x1FFFFFF) ? memregion_MainRAM : memregion_Other;
default:
return memregion_Other;
}

View File

@ -89,7 +89,7 @@ const u32 NDMAModes[] =
}*/
DSi::DSi(DSiArgs&& args, void* userdata) noexcept :
NDS(std::move(args), 1, userdata),
NDS(std::move(args), 1, 0, userdata),
NDMAs {
DSi_NDMA(0, 0, *this),
DSi_NDMA(0, 1, *this),
@ -1278,15 +1278,18 @@ void DSi::ApplyNewRAMSize(u32 size)
switch (size)
{
case 0:
case 1:
case 1: // TODO(shinyquagsire23): Is 1 actually 8MiB (NDS devkit)?
MainRAMMask = 0x3FFFFF;
Log(LogLevel::Debug, "RAM: 4MB\n");
break;
case 2:
case 3: // TODO: debug console w/ 32MB?
case 2: // Retail 16MiB
MainRAMMask = 0xFFFFFF;
Log(LogLevel::Debug, "RAM: 16MB\n");
break;
case 3: // Debug/3DS 32MiB
MainRAMMask = 0x1FFFFFF;
Log(LogLevel::Debug, "RAM: 32MB\n");
break;
}
}
@ -1367,6 +1370,12 @@ u8 DSi::ARM9Read8(u32 addr)
case 0x0C000000:
return *(u8*)&MainRAM[addr & MainRAMMask];
case 0x0D000000:
// open-bus behavior
if (MainRAMPresent<=0x1000000 && MainRAMMask>=0x1FFFFFF) {
break;
}
return *(u8*)&MainRAM[addr & MainRAMMask];
}
return NDS::ARM9Read8(addr);
@ -1418,6 +1427,12 @@ u16 DSi::ARM9Read16(u32 addr)
case 0x0C000000:
return *(u16*)&MainRAM[addr & MainRAMMask];
case 0x0D000000:
// open-bus behavior
if (MainRAMPresent<=0x1000000 && MainRAMMask>=0x1FFFFFF) {
break;
}
return *(u16*)&MainRAM[addr & MainRAMMask];
}
return NDS::ARM9Read16(addr);
@ -1474,6 +1489,12 @@ u32 DSi::ARM9Read32(u32 addr)
case 0x0C000000:
return *(u32*)&MainRAM[addr & MainRAMMask];
case 0x0D000000:
// open-bus behavior
if (MainRAMPresent<=0x1000000 && MainRAMMask>=0x1FFFFFF) {
break;
}
return *(u32*)&MainRAM[addr & MainRAMMask];
}
return NDS::ARM9Read32(addr);
@ -1569,6 +1590,14 @@ void DSi::ARM9Write8(u32 addr, u8 val)
JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_MainRAM>(addr);
*(u8*)&MainRAM[addr & MainRAMMask] = val;
return;
case 0x0D000000:
// open-bus behavior
if (MainRAMPresent<=0x1000000 && MainRAMMask>=0x1FFFFFF) {
break;
}
JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_MainRAM>(addr);
*(u8*)&MainRAM[addr & MainRAMMask] = val;
return;
}
return NDS::ARM9Write8(addr, val);
@ -1654,6 +1683,14 @@ void DSi::ARM9Write16(u32 addr, u16 val)
JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_MainRAM>(addr);
*(u16*)&MainRAM[addr & MainRAMMask] = val;
return;
case 0x0D000000:
// open-bus behavior
if (MainRAMPresent<=0x1000000 && MainRAMMask>=0x1FFFFFF) {
break;
}
JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_MainRAM>(addr);
*(u16*)&MainRAM[addr & MainRAMMask] = val;
return;
}
return NDS::ARM9Write16(addr, val);
@ -1739,6 +1776,15 @@ void DSi::ARM9Write32(u32 addr, u32 val)
JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_MainRAM>(addr);
*(u32*)&MainRAM[addr & MainRAMMask] = val;
return;
case 0x0D000000:
// open-bus behavior
if (MainRAMPresent<=0x1000000 && MainRAMMask>=0x1FFFFFF) {
break;
}
JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_MainRAM>(addr);
*(u32*)&MainRAM[addr & MainRAMMask] = val;
return;
}
return NDS::ARM9Write32(addr, val);
@ -1754,6 +1800,16 @@ bool DSi::ARM9GetMemRegion(u32 addr, bool write, MemRegion* region)
region->Mem = MainRAM;
region->Mask = MainRAMMask;
return true;
case 0x0D000000:
// open-bus behavior
if (MainRAMPresent<=0x1000000 && MainRAMMask>=0x1FFFFFF) {
region->Mem = NULL;
return false;
}
region->Mem = MainRAM;
region->Mask = MainRAMMask;
return true;
}
if ((addr & 0xFFFF0000) == 0xFFFF0000 && !write)
@ -1835,6 +1891,13 @@ u8 DSi::ARM7Read8(u32 addr)
case 0x0C000000:
case 0x0C800000:
return *(u8*)&MainRAM[addr & MainRAMMask];
case 0x0D000000:
case 0x0D800000:
// open-bus behavior
if (MainRAMPresent<=0x1000000 && MainRAMMask>=0x1FFFFFF) {
break;
}
return *(u8*)&MainRAM[addr & MainRAMMask];
}
return NDS::ARM7Read8(addr);
@ -1894,7 +1957,14 @@ u16 DSi::ARM7Read16(u32 addr)
case 0x0C000000:
case 0x0C800000:
return *(u16*)&MainRAM[addr & MainRAMMask];
return *(u16*)&MainRAM[addr & NDS::MainRAMMask];
case 0x0D000000:
case 0x0D800000:
// open-bus behavior
if (NDS::MainRAMPresent<=0x1000000 && NDS::MainRAMMask>=0x1FFFFFF) {
break;
}
return *(u16*)&MainRAM[addr & NDS::MainRAMMask];
}
return NDS::ARM7Read16(addr);
@ -1954,6 +2024,13 @@ u32 DSi::ARM7Read32(u32 addr)
case 0x0C000000:
case 0x0C800000:
return *(u32*)&NDS::MainRAM[addr & NDS::MainRAMMask];
case 0x0D000000:
case 0x0D800000:
// open-bus behavior
if (NDS::MainRAMPresent<=0x1000000 && NDS::MainRAMMask>=0x1FFFFFF) {
break;
}
return *(u32*)&NDS::MainRAM[addr & NDS::MainRAMMask];
}
return NDS::ARM7Read32(addr);
@ -2042,6 +2119,15 @@ void DSi::ARM7Write8(u32 addr, u8 val)
JIT.CheckAndInvalidate<1, ARMJIT_Memory::memregion_MainRAM>(addr);
*(u8*)&NDS::MainRAM[addr & NDS::MainRAMMask] = val;
return;
case 0x0D000000:
case 0x0D800000:
// open-bus behavior
if (NDS::MainRAMPresent<=0x1000000 && NDS::MainRAMMask>=0x1FFFFFF) {
break;
}
JIT.CheckAndInvalidate<1, ARMJIT_Memory::memregion_MainRAM>(addr);
*(u8*)&NDS::MainRAM[addr & NDS::MainRAMMask] = val;
return;
}
return NDS::ARM7Write8(addr, val);
@ -2132,6 +2218,15 @@ void DSi::ARM7Write16(u32 addr, u16 val)
JIT.CheckAndInvalidate<1, ARMJIT_Memory::memregion_MainRAM>(addr);
*(u16*)&NDS::MainRAM[addr & NDS::MainRAMMask] = val;
return;
case 0x0D000000:
case 0x0D800000:
// open-bus behavior
if (NDS::MainRAMPresent<=0x1000000 && NDS::MainRAMMask>=0x1FFFFFF) {
break;
}
JIT.CheckAndInvalidate<1, ARMJIT_Memory::memregion_MainRAM>(addr);
*(u16*)&NDS::MainRAM[addr & NDS::MainRAMMask] = val;
return;
}
return NDS::ARM7Write16(addr, val);
@ -2222,6 +2317,15 @@ void DSi::ARM7Write32(u32 addr, u32 val)
JIT.CheckAndInvalidate<1, ARMJIT_Memory::memregion_MainRAM>(addr);
*(u32*)&NDS::MainRAM[addr & NDS::MainRAMMask] = val;
return;
case 0x0D000000:
case 0x0D800000:
// open-bus behavior
if (NDS::MainRAMPresent<=0x1000000 && NDS::MainRAMMask>=0x1FFFFFF) {
break;
}
JIT.CheckAndInvalidate<1, ARMJIT_Memory::memregion_MainRAM>(addr);
*(u32*)&NDS::MainRAM[addr & NDS::MainRAMMask] = val;
return;
}
return NDS::ARM7Write32(addr, val);
@ -2239,6 +2343,15 @@ bool DSi::ARM7GetMemRegion(u32 addr, bool write, MemRegion* region)
region->Mem = NDS::MainRAM;
region->Mask = NDS::MainRAMMask;
return true;
case 0x0D000000:
case 0x0D800000:
// open-bus behavior
if (NDS::MainRAMPresent<=0x1000000 && NDS::MainRAMMask>=0x1FFFFFF) {
break;
}
region->Mem = NDS::MainRAM;
region->Mask = NDS::MainRAMMask;
return true;
}
// BIOS. ARM7 PC has to be within range.

View File

@ -23,7 +23,8 @@
namespace melonDS
{
constexpr u32 MainRAMMaxSize = 0x1000000;
constexpr u32 MainRAMPrimaryMappingMaxSize = 0x1000000;
constexpr u32 MainRAMMaxSize = 0x2000000;
constexpr u32 SharedWRAMSize = 0x8000;
constexpr u32 ARM7WRAMSize = 0x10000;
constexpr u32 NWRAMSize = 0x40000;

View File

@ -87,8 +87,9 @@ NDS::NDS() noexcept :
{
}
NDS::NDS(NDSArgs&& args, int type, void* userdata) noexcept :
NDS::NDS(NDSArgs&& args, int type, int debugbc, void* userdata) noexcept :
ConsoleType(type),
DebugBoardConfig(debugbc),
UserData(userdata),
ARM7BIOS(*args.ARM7BIOS),
ARM9BIOS(*args.ARM9BIOS),
@ -446,12 +447,14 @@ void NDS::Reset()
// BIOS files are now loaded by the frontend
ARM9ClockShift = 2;
MainRAMMask = 0xFFFFFF;
MainRAMMask = DebugBoardConfig ? 0x1FFFFFF : 0x1FFFFFF; // Intentional default
MainRAMPresent = DebugBoardConfig ? 0x2000000 : 0x1000000; // 32MiB and 16MiB
}
else
{
ARM9ClockShift = 1;
MainRAMMask = 0x3FFFFF;
MainRAMMask = DebugBoardConfig ? 0x7FFFFF : 0x3FFFFF;
MainRAMPresent = DebugBoardConfig ? 0x800000 : 0x400000; // 8MiB and 4MiB
}
// has to be called before InitTimings
// otherwise some PU settings are completely

View File

@ -249,6 +249,7 @@ public: // TODO: Encapsulate the rest of these members
void* UserData;
int ConsoleType;
int DebugBoardConfig;
int CurCPU;
SchedEvent SchedList[Event_MAX] {};
@ -293,8 +294,7 @@ public: // TODO: Encapsulate the rest of these members
u8* MainRAM;
u32 MainRAMMask;
const u32 MainRAMMaxSize = 0x1000000;
u32 MainRAMPresent;
const u32 SharedWRAMSize = 0x8000;
u8* SharedWRAM;
@ -547,7 +547,7 @@ private:
u32 RunFrame();
public:
NDS(NDSArgs&& args, void* userdata = nullptr) noexcept : NDS(std::move(args), 0, userdata) {}
NDS(NDSArgs&& args, void* userdata = nullptr) noexcept : NDS(std::move(args), 0, 0, userdata) {}
NDS() noexcept;
virtual ~NDS() noexcept;
NDS(const NDS&) = delete;
@ -557,7 +557,7 @@ public:
static thread_local NDS* Current;
protected:
explicit NDS(NDSArgs&& args, int type, void* userdata) noexcept;
explicit NDS(NDSArgs&& args, int type, int debugbc, void* userdata) noexcept;
virtual void DoSavestateExtra(Savestate* file) {}
};

View File

@ -77,6 +77,7 @@ DefaultList<int> DefaultInts =
RangeList IntRanges =
{
{"Emu.ConsoleType", {0, 1}},
{"Emu.DebugBoardConfig", {0, 1}},
{"3D.Renderer", {0, renderer3D_Max-1}},
{"Screen.VSyncInterval", {1, 20}},
{"3D.GL.ScaleFactor", {1, 16}},

View File

@ -70,6 +70,7 @@ EmuInstance::EmuInstance(int inst) : deleting(false),
localCfg(Config::GetLocalTable(inst))
{
consoleType = globalCfg.GetInt("Emu.ConsoleType");
debugBoardConfig = globalCfg.GetInt("Emu.DebugBoardConfig");
ndsSave = nullptr;
cartType = -1;
@ -1240,6 +1241,7 @@ bool EmuInstance::updateConsole() noexcept
{
// update the console type
consoleType = globalCfg.GetInt("Emu.ConsoleType");
debugBoardConfig = globalCfg.GetInt("Emu.DebugBoardConfig");
// Let's get the cart we want to use;
// if we want to keep the cart, we'll eject it from the existing console first.
@ -1353,7 +1355,7 @@ bool EmuInstance::updateConsole() noexcept
}
renderLock.lock();
if ((!nds) || (consoleType != nds->ConsoleType))
if ((!nds) || (consoleType != nds->ConsoleType) || (debugBoardConfig != nds->DebugBoardConfig))
{
if (nds)
{
@ -1366,6 +1368,7 @@ bool EmuInstance::updateConsole() noexcept
else
nds = new NDS(std::move(ndsargs), this);
nds->DebugBoardConfig = debugBoardConfig;
nds->Reset();
loadRTCData();
//emuThread->updateVideoRenderer(); // not actually needed?

View File

@ -88,6 +88,7 @@ public:
int getInstanceID() { return instanceID; }
int getConsoleType() { return consoleType; }
int getDebugBoardConfig() { return debugBoardConfig; }
EmuThread* getEmuThread() { return emuThread; }
melonDS::NDS* getNDS() { return nds; }
@ -264,6 +265,7 @@ private:
Config::Table localCfg;
int consoleType;
int debugBoardConfig;
melonDS::NDS* nds;
int cartType;

View File

@ -72,8 +72,10 @@ EmuSettingsDialog::EmuSettingsDialog(QWidget* parent) : QDialog(parent), ui(new
ui->txtDSiNANDPath->setText(cfg.GetQString("DSi.NANDPath"));
ui->cbxConsoleType->addItem("DS");
ui->cbxConsoleType->addItem("DS devkit (experimental)");
ui->cbxConsoleType->addItem("DSi (experimental)");
ui->cbxConsoleType->setCurrentIndex(cfg.GetInt("Emu.ConsoleType"));
ui->cbxConsoleType->addItem("3DS (experimental)");
ui->cbxConsoleType->setCurrentIndex((cfg.GetInt("Emu.ConsoleType")<<1)+cfg.GetInt("Emu.DebugBoardConfig"));
ui->chkDirectBoot->setChecked(cfg.GetBool("Emu.DirectBoot"));
@ -297,7 +299,8 @@ void EmuSettingsDialog::done(int r)
instcfg.SetBool("Gdb.ARM9.BreakOnStartup", ui->cbGdbBOSA9->isChecked());
#endif
cfg.SetInt("Emu.ConsoleType", ui->cbxConsoleType->currentIndex());
cfg.SetInt("Emu.ConsoleType", ui->cbxConsoleType->currentIndex()>>1);
cfg.SetInt("Emu.DebugBoardConfig", ui->cbxConsoleType->currentIndex()&1);
cfg.SetBool("Emu.DirectBoot", ui->chkDirectBoot->isChecked());
Config::Save();

View File

@ -242,14 +242,15 @@ void RAMSearchThread::run()
if (SearchMode == ramInfoSTh_SearchAll || RowDataVector->size() == 0)
{
// First search mode
for (u32 addr = 0x02000000; SearchRunning && addr < 0x02000000+MainRAMMaxSize; addr += SearchByteType)
// TODO: 3DS/devit 32MiB
for (u32 addr = 0x02000000; SearchRunning && addr < 0x02000000+MainRAMPrimaryMappingMaxSize; addr += SearchByteType)
{
const s32& value = GetMainRAMValue(*Dialog->emuInstance->getNDS(), addr, SearchByteType);
RowDataVector->push_back({ addr, value, value });
// A solution to prevent to call too many slot.
u32 newProgress = (int)((addr-0x02000000) / (MainRAMMaxSize-1.0f) * 100);
u32 newProgress = (int)((addr-0x02000000) / (MainRAMPrimaryMappingMaxSize-1.0f) * 100);
if (progress < newProgress)
{
progress = newProgress;