Skip to content

Commit

Permalink
Add a basic "DSi" mode for homebrew like SM64DSi
Browse files Browse the repository at this point in the history
  • Loading branch information
Hydr8gon committed Oct 23, 2024
1 parent e2c1677 commit 3cf405e
Show file tree
Hide file tree
Showing 12 changed files with 126 additions and 50 deletions.
35 changes: 17 additions & 18 deletions src/cartridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,32 +303,31 @@ void CartridgeNds::directBoot()
loadRomSection(0, 0x170);

// Extract some information about the initial ARM9 code from the header
uint32_t offset9 = U8TO32(rom, 0x20);
uint32_t entryAddr9 = U8TO32(rom, 0x24);
uint32_t ramAddr9 = U8TO32(rom, 0x28);
uint32_t size9 = U8TO32(rom, 0x2C);
LOG("ARM9 code ROM offset: 0x%X\n", offset9);
LOG("ARM9 code entry address: 0x%X\n", entryAddr9);
LOG("ARM9 RAM address: 0x%X\n", ramAddr9);
LOG("ARM9 code size: 0x%X\n", size9);
uint32_t offset9 = U8TO32(rom, 0x20);
core->interpreter[0].entryAddr = U8TO32(rom, 0x24);
uint32_t ramAddr9 = U8TO32(rom, 0x28);
uint32_t size9 = U8TO32(rom, 0x2C);
LOG("ARM9 code ROM offset: 0x%X\n", offset9);
LOG("ARM9 code entry address: 0x%X\n", core->interpreter[0].entryAddr);
LOG("ARM9 RAM address: 0x%X\n", ramAddr9);
LOG("ARM9 code size: 0x%X\n", size9);

// Extract some information about the initial ARM7 code from the header
uint32_t offset7 = U8TO32(rom, 0x30);
uint32_t entryAddr7 = U8TO32(rom, 0x34);
uint32_t ramAddr7 = U8TO32(rom, 0x38);
uint32_t size7 = U8TO32(rom, 0x3C);
LOG("ARM7 code ROM offset: 0x%X\n", offset7);
LOG("ARM7 code entry address: 0x%X\n", entryAddr7);
LOG("ARM7 RAM address: 0x%X\n", ramAddr7);
LOG("ARM7 code size: 0x%X\n", size7);
uint32_t offset7 = U8TO32(rom, 0x30);
core->interpreter[1].entryAddr = U8TO32(rom, 0x34);
uint32_t ramAddr7 = U8TO32(rom, 0x38);
uint32_t size7 = U8TO32(rom, 0x3C);
LOG("ARM7 code ROM offset: 0x%X\n", offset7);
LOG("ARM7 code entry address: 0x%X\n", core->interpreter[1].entryAddr);
LOG("ARM7 RAM address: 0x%X\n", ramAddr7);
LOG("ARM7 code size: 0x%X\n", size7);

// Load the ROM header into memory
for (uint32_t i = 0; i < 0x170; i += 4)
core->memory.write<uint32_t>(0, 0x27FFE00 + i, U8TO32(rom, i));

uint32_t offset;

// Load the initial ARM9 code from file if needed
uint32_t offset;
if (romFile)
{
loadRomSection(offset9, size9);
Expand Down
15 changes: 12 additions & 3 deletions src/core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ Core::Core(std::string ndsRom, std::string gbaRom, int id, int ndsRomFd, int gba
schedule(NDS_SCANLINE355, 355 * 6);
schedule(NDS_SPU_SAMPLE, 512 * 2);

// Update DSi mode now and ignore changes to it later
dsiMode = Settings::dsiMode;
runFunc = dsiMode ? &Interpreter::runDsiFrame : &Interpreter::runNdsFrame;

// Initialize the memory and CPUs
memory.updateMap9(0x00000000, 0xFFFFFFFF);
memory.updateMap7(0x00000000, 0xFFFFFFFF);
Expand Down Expand Up @@ -145,6 +149,7 @@ Core::Core(std::string ndsRom, std::string gbaRom, int id, int ndsRomFd, int gba
void Core::saveState(FILE *file)
{
// Write state data to the file
fwrite(&dsiMode, sizeof(dsiMode), 1, file);
fwrite(&gbaMode, sizeof(gbaMode), 1, file);
fwrite(&globalCycles, sizeof(globalCycles), 1, file);

Expand All @@ -158,6 +163,7 @@ void Core::saveState(FILE *file)
void Core::loadState(FILE *file)
{
// Read state data from the file
fread(&dsiMode, sizeof(dsiMode), 1, file);
fread(&gbaMode, sizeof(gbaMode), 1, file);
fread(&globalCycles, sizeof(globalCycles), 1, file);

Expand All @@ -173,7 +179,7 @@ void Core::loadState(FILE *file)
}

// Update the run function pointer
runFunc = gbaMode ? &Interpreter::runGbaFrame : &Interpreter::runNdsFrame;
runFunc = gbaMode ? &Interpreter::runGbaFrame : (dsiMode ? &Interpreter::runDsiFrame : &Interpreter::runNdsFrame);
}

void Core::resetCycles()
Expand Down Expand Up @@ -221,10 +227,13 @@ void Core::enterGbaMode()

// Disable HLE BIOS if a real one was loaded
if (realGbaBios)
return interpreter[1].setBios(nullptr);
{
interpreter[1].bios = nullptr;
return;
}

// Enable HLE BIOS and boot the GBA ROM directly
interpreter[1].setBios(&bios[2]);
interpreter[1].bios = &bios[2];
interpreter[1].directBoot();
memory.write<uint16_t>(1, 0x4000088, 0x200); // SOUNDBIAS
}
Expand Down
3 changes: 2 additions & 1 deletion src/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,9 @@ class Core
{
public:
int id = 0;
bool gbaMode = false;
int fps = 0;
bool dsiMode = false;
bool gbaMode = false;

ActionReplay actionReplay;
Bios bios[3];
Expand Down
30 changes: 22 additions & 8 deletions src/desktop/noo_frame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ enum FrameEvent
PAUSE,
RESTART,
STOP,
ADD_SYSTEM,
ACTION_REPLAY,
ADD_SYSTEM,
DSI_MODE,
PATH_SETTINGS,
INPUT_BINDINGS,
SCREEN_LAYOUT,
Expand Down Expand Up @@ -70,8 +71,9 @@ EVT_MENU(QUIT, NooFrame::quit)
EVT_MENU(PAUSE, NooFrame::pause)
EVT_MENU(RESTART, NooFrame::restart)
EVT_MENU(STOP, NooFrame::stop)
EVT_MENU(ADD_SYSTEM, NooFrame::addSystem)
EVT_MENU(ACTION_REPLAY, NooFrame::actionReplay)
EVT_MENU(ADD_SYSTEM, NooFrame::addSystem)
EVT_MENU(DSI_MODE, NooFrame::dsiModeToggle)
EVT_MENU(PATH_SETTINGS, NooFrame::pathSettings)
EVT_MENU(INPUT_BINDINGS, NooFrame::inputSettings)
EVT_MENU(SCREEN_LAYOUT, NooFrame::layoutSettings)
Expand Down Expand Up @@ -119,8 +121,13 @@ NooFrame::NooFrame(NooApp *app, int id, std::string path, NooFrame *partner):
systemMenu->Append(RESTART, "&Restart");
systemMenu->Append(STOP, "&Stop");
systemMenu->AppendSeparator();
systemMenu->Append(ADD_SYSTEM, "&Add System");
systemMenu->Append(ACTION_REPLAY, "&Action Replay");
systemMenu->Append(ADD_SYSTEM, "&Add System");
systemMenu->AppendSeparator();
systemMenu->AppendCheckItem(DSI_MODE, "&DSi Homebrew Mode");

// Set the initial System checkbox states
systemMenu->Check(DSI_MODE, Settings::dsiMode);

// Disable some menu items until the core is running
fileMenu->Enable(TRIM_ROM, false);
Expand Down Expand Up @@ -165,7 +172,7 @@ NooFrame::NooFrame(NooApp *app, int id, std::string path, NooFrame *partner):
settingsMenu->AppendSubMenu(threaded3D, "&Threaded 3D");
settingsMenu->AppendCheckItem(HIGH_RES_3D, "&High-Resolution 3D");

// Set the current values of the checkboxes
// Set the initial Settings checkbox states
settingsMenu->Check(DIRECT_BOOT, Settings::directBoot);
settingsMenu->Check(FPS_LIMITER, Settings::fpsLimiter);
settingsMenu->Check(MIC_ENABLE, NooApp::micEnable);
Expand Down Expand Up @@ -664,17 +671,24 @@ void NooFrame::stop(wxCommandEvent &event)
stopCore(true);
}

void NooFrame::actionReplay(wxCommandEvent &event)
{
// Show the AR cheats dialog
CheatDialog cheatDialog(core);
cheatDialog.ShowModal();
}

void NooFrame::addSystem(wxCommandEvent &event)
{
// Create a new emulator instance
app->createFrame();
}

void NooFrame::actionReplay(wxCommandEvent &event)
void NooFrame::dsiModeToggle(wxCommandEvent &event)
{
// Show the AR cheats dialog
CheatDialog cheatDialog(core);
cheatDialog.ShowModal();
// Toggle the DSi homebrew mode setting
Settings::dsiMode = !Settings::dsiMode;
Settings::save();
}

void NooFrame::pathSettings(wxCommandEvent &event)
Expand Down
3 changes: 2 additions & 1 deletion src/desktop/noo_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,9 @@ class NooFrame: public wxFrame
void pause(wxCommandEvent &event);
void restart(wxCommandEvent &event);
void stop(wxCommandEvent &event);
void addSystem(wxCommandEvent &event);
void actionReplay(wxCommandEvent &event);
void addSystem(wxCommandEvent &event);
void dsiModeToggle(wxCommandEvent &event);
void pathSettings(wxCommandEvent &event);
void inputSettings(wxCommandEvent &event);
void layoutSettings(wxCommandEvent &event);
Expand Down
50 changes: 44 additions & 6 deletions src/interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ void Interpreter::saveState(FILE *file)
fwrite(&spsrAbt, sizeof(spsrAbt), 1, file);
fwrite(&spsrIrq, sizeof(spsrIrq), 1, file);
fwrite(&spsrUnd, sizeof(spsrUnd), 1, file);
fwrite(&halted, sizeof(halted), 1, file);
fwrite(&cycles, sizeof(cycles), 1, file);
fwrite(&halted, sizeof(halted), 1, file);
fwrite(&dsiCycle, sizeof(dsiCycle), 1, file);
fwrite(&ime, sizeof(ime), 1, file);
fwrite(&ie, sizeof(ie), 1, file);
fwrite(&irf, sizeof(irf), 1, file);
Expand All @@ -67,8 +68,9 @@ void Interpreter::loadState(FILE *file)
fread(&spsrAbt, sizeof(spsrAbt), 1, file);
fread(&spsrIrq, sizeof(spsrIrq), 1, file);
fread(&spsrUnd, sizeof(spsrUnd), 1, file);
fread(&halted, sizeof(halted), 1, file);
fread(&cycles, sizeof(cycles), 1, file);
fread(&halted, sizeof(halted), 1, file);
fread(&dsiCycle, sizeof(dsiCycle), 1, file);
fread(&ime, sizeof(ime), 1, file);
fread(&ie, sizeof(ie), 1, file);
fread(&irf, sizeof(irf), 1, file);
Expand All @@ -95,7 +97,7 @@ void Interpreter::directBoot()
{
// Prepare to directly boot a ROM
setCpsr(0x000000DF); // System, interrupts off
registersUsr[15] = core->gbaMode ? 0x8000000 : core->memory.read<uint32_t>(arm7, 0x27FFE24 + (arm7 << 4));
registersUsr[15] = core->gbaMode ? 0x8000000 : entryAddr;
registersUsr[14] = registersUsr[15];
registersUsr[12] = registersUsr[15];
registersUsr[13] = arm7 ? (core->gbaMode ? 0x3007F00 : 0x380FD80) : 0x3002F7C;
Expand All @@ -112,10 +114,9 @@ void Interpreter::resetCycles()

void Interpreter::runNdsFrame(Core &core)
{
// Run a frame in NDS mode
Interpreter &arm9 = core.interpreter[0];
Interpreter &arm7 = core.interpreter[1];

// Run a frame in NDS mode
while (core.running.exchange(true))
{
// Run the CPUs until the next scheduled task
Expand Down Expand Up @@ -145,11 +146,48 @@ void Interpreter::runNdsFrame(Core &core)
}
}

void Interpreter::runGbaFrame(Core &core)
void Interpreter::runDsiFrame(Core &core)
{
// Run a frame in DSi mode
Interpreter &arm9 = core.interpreter[0];
Interpreter &arm7 = core.interpreter[1];
while (core.running.exchange(true))
{
// Run the CPUs until the next scheduled task
while (core.events[0].cycles > core.globalCycles)
{
// Run the ARM9 twice as fast as usual
if (!arm9.halted && core.globalCycles >= arm9.cycles)
{
int cycles = arm9.runOpcode() + arm9.dsiCycle;
arm9.cycles = core.globalCycles + (cycles >> 1);
arm9.dsiCycle = (cycles & 0x1);
}

// Run the ARM7 at half the regular speed of the ARM9
if (!arm7.halted && core.globalCycles >= arm7.cycles)
arm7.cycles = core.globalCycles + (arm7.runOpcode() << 1);

// Count cycles up to the next soonest event
core.globalCycles = std::min<uint32_t>((arm9.halted ? -1 : arm9.cycles), (arm7.halted ? -1 : arm7.cycles));
}

// Jump to the next scheduled task
core.globalCycles = core.events[0].cycles;

// Run all tasks that are scheduled now
while (core.events[0].cycles <= core.globalCycles)
{
core.tasks[core.events[0].task]();
core.events.erase(core.events.begin());
}
}
}

void Interpreter::runGbaFrame(Core &core)
{
// Run a frame in GBA mode
Interpreter &arm7 = core.interpreter[1];
while (core.running.exchange(true))
{
// Run the ARM7 until the next scheduled task
Expand Down
11 changes: 6 additions & 5 deletions src/interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ class Bios;
class Interpreter
{
public:
Bios *bios = nullptr;
uint32_t entryAddr = 0;

Interpreter(Core *core, bool arm7);
void saveState(FILE *file);
void loadState(FILE *file);
Expand All @@ -39,6 +42,7 @@ class Interpreter
void resetCycles();

static void runNdsFrame(Core &core);
static void runDsiFrame(Core &core);
static void runGbaFrame(Core &core);

void halt(int bit) { halted |= BIT(bit); }
Expand All @@ -48,8 +52,6 @@ class Interpreter

bool isThumb() { return cpsr & BIT(5); }
uint32_t getPC() { return *registers[15]; }

void setBios(Bios *bios) { this->bios = bios; }
int handleHleIrq();

uint8_t readIme() { return ime; }
Expand All @@ -66,9 +68,7 @@ class Interpreter
Core *core;
bool arm7;

Bios *bios = nullptr;
uint32_t pipeline[2] = {};

uint32_t *registers[32] = {};
uint32_t registersUsr[16] = {};
uint32_t registersFiq[7] = {};
Expand All @@ -80,8 +80,9 @@ class Interpreter
uint32_t cpsr = 0, *spsr = nullptr;
uint32_t spsrFiq = 0, spsrSvc = 0, spsrAbt = 0, spsrIrq = 0, spsrUnd = 0;

uint8_t halted = 0;
uint32_t cycles = 0;
uint8_t halted = 0;
bool dsiCycle = false;

uint8_t ime = 0;
uint32_t ie = 0, irf = 0;
Expand Down
Loading

0 comments on commit 3cf405e

Please sign in to comment.