Redesigning the cart interface
The kind of change that doesn't immediately mean a lot for end users, but means a lot for us coders (and ultimately means something for end users, too).

Anyway, this tends to show why it's good to think forward when designing your code. That being said, I need to find a balance with this. I tend to either think forward too much and end up paralyzed by questions that don't mean much, or just write code as it comes to my mind.

The cart interface in melonDS was originally built without much consideration for future. If you're wondering, the cart interface is the part of the emulator that lets emulated software access the emulated cartridge, because on the DS the cart isn't just directly mapped to CPU address space like on older consoles. Instead, there are a bunch of commands you can send to the cart to retrieve various parts of the contents, and different encryption protocols securing it up.

As melonDS became capable enough to run commercial software, emulating the cart interface was a must. So NDSCart.cpp was born. The main component is the NDSCart namespace, which originally emulated the cart interface hardware (basically the DS side) and command responses for a generic cart. There is also NDSCart_SRAM, which emulates the on-cart SPI save memory. A tad hacky, but for most games, it did the job.

But, that's the thing, not all DS carts are the same!

There were already some exceptions for homebrew ROMs, which might want to use the cart interface and, depending how old they are, need a more lax implementation of the generic cart protocol. Namely, retail carts don't let you read addresses lower than 0x8000 via the generic data read command (0xB7), because that region contains the ROM header (read via a different command), the Key1 encryption data and the secure area. However, old homebrew ROMs don't have any of that (save for the oldstyle DS header), and have their ARM9 binary start at 0x200. Newer homebrew ROMs are closer to the layout of a retail cart, mostly due to the added DSi support (the DSi header is 0x1000 bytes instead of 0x200), but, since not everybody is here to rebuild their ROMs, we still need to support the older ROMs.

Homebrew aside, there are also different types of retail carts.

A prime example is Pokémon games. The carts are fitted with a IR transceiver, which is accessed via the save-memory SPI bus. In practice, the first byte of a SPI transfer is a command for the IR transceiver. For now, we know that command 0x08 is some ping command that should reply 0xAA, and command 0x00 is the pass-through command, where any further bytes are forwarded to the save memory. Emulating this is required for Pokémon games to be playable at all. In melonDS, these commands were added to the generic save-memory code. A bit of a hack, since this means these would be 'functional' in any game instead of just Pokémon games, but it did the trick.

But there's more. Games like WarioWare DIY, or Jam with the Band, don't even use the save-memory SPI bus. They have save memory, but it's a NAND memory that is accessed via the same bus as the ROM itself, through a set of specific commands.

And then there's Pokémon Typing Adventure, which comes with its own Bluetooth keyboard. The cart is fitted with a fancypants Bluetooth controller that is accessed via the save-memory SPI bus. That controller can even send IRQs to the DS, via the cart interface's IREQ_MC line.

There's probably even more to this, who knows what sorts of obscure stuff has been produced for the DS.

On the GBA side, things aren't much better. The DS can play GBA games, which is probably not something melonDS will emulate in the near future. But there are several other possibilities here too. You have add-ons that plug into the GBA cart slot, like the Rumble Pak or the Guitar Hero grip thing. Some games can even detect that a specific game is inserted in the GBA slot and unlock features when that is the case.

At the time some GBA slot add-on support was added to melonDS, it became evident that we would need a clean interface system for both NDS and GBA carts, or this would become a large mess.

Thus, the cart_refactor branch was born. Nothing terribly exciting for now, just using OOP to build a proper interface system for NDS carts. When this is done, the same will be done to the GBA interface.

Hell, given how things are going with the Azure CI thing, the refactored interfaces might make it into melonDS 0.9.2.
O'Jay says:
Apr 14th 2021
You are in a coding frenzy right now it seems haha, thanks for all the hard work you're putting on the emulator :)
Apr 14th 2021
The new version 0.9.2 is getting CLOSER every time, I hope you never stop working on this project, and surprise us with this brutal and incredible emulator, greetings :D
that guys n64 says:
Apr 15th 2021
i never get tired of reading what you girls/guys come up with :P melon ds has the potential of being the best nds emulator by how thing are going so far :P
Gaia Weylyn says:
May 5th 2021
You know, since you bring up Pokemon and GBA addons, I had a thought.. How feasible would it be to implement pass through of an accompanying save file alongside a rom? For example, several Pokemon NDS titles were able to read the save data of GBA titles and transfer Pokemon forwards, on top of the basic detection feature unlocks you mentioned above.

Sure, in 2021, it's probably much faster and easier to just use a save editor for this.. That said, it'd still be really cool to finally have an emulator capable of preserving the original experience.
Rayyan says:
May 5th 2021
Gaia Weylyn: yes, that exists already as a feature.
Post a comment