melonDS aims at providing fast and accurate Nintendo DS emulation. While it is still a work in progress, it has a pretty solid set of features:

• Nearly complete core (CPU, video, audio, ...)
• JIT recompiler for fast emulation
• OpenGL renderer, 3D upscaling
• RTC, microphone, lid close/open
• Joystick support
• Savestates
• Various display position/sizing/rotation modes
• (WIP) Wifi: local multiplayer, online connectivity
• (WIP) DSi emulation
• DLDI
• (WIP) GBA slot add-ons
• and more are planned!







Download melonDS

If you're running into trouble: Howto/FAQ
Custom path support has been merged
As title says.

This also comes with some extra features. For comparison, the File menu in melonDS 0.9.3, and the new File menu:


First of all, the 'Open ROM inside archive' option has been merged with 'Open ROM', to declutter the menu and make things more intuitive. The file picker dialog just lets you pick either a ROM file or an archive, and in the latter case, it asks you which file you want to open from the archive.

When opening a ROM from an archive, the recent ROM menu remembers the archive file but also which ROM you picked inside it. Similarly, you can now pass a ROM inside an archive to the command line, like so:

melonDS path/to/archive.zip|dupermario.nds

As I wanted to make the GBA ROM/addon feature more obvious, it has been decoupled from the regular 'Open ROM' feature. Previously, you had to open your GBA ROM before opening your NDS ROM, but it wasn't obvious at all that the feature existed or how it worked. Now, the separate menus should make this more obvious.

The way DS ROMs are handled has been revamped in a similar fashion. Basically:

* 'Open ROM' loads a DS ROM and starts running it, resetting emulation if another ROM was loaded previously, basically retaining its existing behavior.

* Under the DS slot section, 'Insert cart' will load a DS ROM, and that's it. Just like inserting a cartridge in a DS. The current cart, if any, will be ejected prior. This makes it possible to hotswap carts while running a game or the DS/DSi menu. Similarly, you guess what 'Eject cart' is for.

* The GBA slot section works in much the same way. You can choose to either insert a ROM cart, mimicking the presence of a GBA game cart for the DS games that can sense that, or insert an add-on cart, like for example the memory expansion cart which the DS browser uses. Note that melonDS does not support running GBA games.

... read more
The path to success
You might have seen that pic I posted on Twitter a while back:

[path settings dialog in the making]

This is what I'm currently working on. It's been a popular request for a while: customizable paths for things like save files, savestates, ... As of now, melonDS takes the easy route and dumps these files alongside the current ROM, but not everybody wants that.

And, well, implementing this whole thing raises a bunch of issues. This is also why it can be difficult for me to get things done: I will try to envision the scope of the task at hand, then begin seeing related things that need to be done, more or less drifting away from the original task, and at the end I have too many ideas and I don't know where to start.

This is one of these occurences. I had tried to make plans of what I wanted for the custom paths feature, but, surprise, the actual implementation is going to be different. The state of the melonDS codebase doesn't help, either, sometimes. I mean, it certainly could be worse, but some parts could definitely use a refactor.

ROM loading is a prime example. When I first built the melonDS core, it was pretty simple, and all it had to do was load a ROM from a given file, load the associated save file, and start emulating. So the original NDSCart::LoadROM() function did just that.

Of course, as melonDS evolved, other concerns arose.

For example, archive support was added. In this case, the ROM isn't accessible as a regular file, instead we get a memory buffer with the ROM's contents. So this means a second NDSCart::LoadROM() function was added, that loads a ROM from a memory buffer. A tad redundant.

Another fun thing is DSi support. On the DS, you can't hotswap cartridges, because there's no hardware support for it, so we didn't have to account for this possibility. However, things are different with the DSi: for example, you can insert and eject carts while in the DSi menu and it detects that. So it's something we need to take in account too. And as of now, melonDS has no provision for ejecting the current cart, nor for loading a new cart without resetting emulation.

... read more
Little status update
I hoped to deliver a release around Christmas, but, seeing how things are going, it may not happen.

First of all, I'm having a rough time these days. It's a mix of your typical winter depression and other things, family-related. I'm not going to go over these things in public.

Next, I'm setting up a new server that will eventually replace the server Kuribo64 runs on. More modern, better specs, more secure, all you want. I will keep you informed about this, as there will be a downtime whenever I get round to migrating everything to the new server. There will also be some additions, like proper HTTPS.

Finally, happy birthday Generic! The melonDS HQ will bring you your melon-cake tonight.

-

Even if I'm not posting here, you can follow me on Twitter for smaller melonDS updates (but also a lot of other bullshit). The other team members are also working on cool things, even if they might not be as talkative as me.
New DSi BIOS/NAND/firmware dumper
I have been updating the DSi BIOS dumper, to hopefully make DSi mode more accessible. It is now able to dump all the files you need for DSi emulation: NAND, DS-mode firmware, BIOSes.

This dumper is also a tad smarter: it will warn you if the data required for proper augmented BIOS dumps has been altered. By the way, the dumps should now be correct-- there was a bug in the previous dumper, where some of augmented bits were read from wrong addresses, although these particular bits don't seem to be important.

The NAND is dumped with a 'nocash footer' (small data block holding the eMMC CID and console ID, required for decryption) added at 0xFF800.

The dumper will place the dumped files in a folder named dsidump, rather than dumping them in your SD card's root.

You can get it here: DSi dumper

I will also redesign the downloads page as to feature a tools section with this, among others.
Happy birthday, melonDS!
I'm one day late, oops! Regardless, counting from the first real commit, melonDS is 5 years old. We don't realize, but that's quite a bunch of time. To think, back then, it was just that little project I started for the sake of it. And now, the 'DS emulator, sorta' is turning into something completely serious.

Speaking of, I would have loved to provide a birthday release, but the tight timings and usual factors (real-life shito, ADHD, ...) didn't let this happen for this time. However, depending on how development and testing goes... we will keep you informed, as usual :)

As I said in the last post, we're in the process of making melonDS less obtuse for the average emu user, and while we're at it, there are some more popular-request features we may throw in for the next release. One would be configurable paths for save files and such -- I have some ideas for a clean system for these. I also want to add an interface for modifying user settings, among other fun things.

1.0 may not come in the near future, though. One of the requirements for it is getting local multiplayer stable. melonDS is largely known as 'the wifi emulator', so it's lame that local multiplayer is still this finicky. I have already explained why it's hard to emulate, so instead of going in detail over that, I will simply state that Generic is working on getting it stable. He also working on addressing the shortcomings of our OpenGL renderer, like the lack of proper upscaling in dual-screen 3D scenarios.

I'm also going to give you an occasion to know more about melonDS and the little team behind it!

The melonDS repo was actually created in May 2016. Why did it take until November to see any real work on it? One of the reasons was that I moved out of my parents' home in June that same year. It's been a rocky adventure to say the least, but I don't regret any of it. melonDS, having existed within this timeframe, is also part of this whole adventure of self-discovery for me.

Of course, I also have to thank the rest of the team, and everyone else who got involved, for sticking around and helping make melonDS what it is today. I mean, I have quite a bunch of old projects, and none of them have lasted as long as melonDS has. These projects all fell to my ADHD, and melonDS would likely have met a similar fate without the team and without the emulation community in general. So, thank you all!

Self-discovery can surprise you, in fun or less fun ways. When I moved out, I first thought I was going to lead a normal life, graduate, get girls, all that. Well, so much for that. I would never have predicted what has happened to me, but again, zero regret.

So yeah, I come with all sorts of quirks, fun and less fun. Now, as I'm taking care of the last bits of my transition, there isn't much to say about it anymore, and I have already mentioned ADHD a billion times, so I'm going to mention something more fun:

... read more
Little update on what's going on
I've been wanting to write this post for a while now, but I'm having trouble focusing on it (as usual, I guess :P ). Regardless, I figured I'd just tell you folks about what's cooking in the melonDS HQ.

The focus for the next release is basically on making melonDS less obtuse to the average user. One of the biggest parts of this is removing the requirement for external BIOS and firmware files.

We started the work in that direction by merging some relevant pull requests, making melonDS able to fall back to the DraStic FreeBIOS and a generated firmware for DS mode. There are still some issues we need to take care of in one way or another, namely:

* We need to either force direct boot, or include some small bootloader inside the replacement BIOS/firmware. The easiest route is to force direct boot.

* The original BIOS includes the Blowfish key required to decrypt the secure area in encrypted ROMs. Lacking the key would make it impossible to support encrypted ROMs, but including it is muddy waters from a legal standpoint.

* A notable exception is that some of the encrypted ROMs, like those found in VC titles, contain the data for Blowfish crypto. It could be possible to make melonDS take advantage of it, but not all ROM dumps out there contain that (it's not normally readable in retail cartridges).

All in all, it seems pretty manageable on the DS side. Things get more rocky on the DSi side:

* As the NUS is still online, it is in theory possible to build a DSi NAND from scratch, though it needs to be studied closer. Some of the contents, like font files, would have to be replicated in free variants. The NAND bootloader would not be terribly difficult to replicate.

* There are several more crypto keys found in the DSi BIOS. While it is still possible to load DSi ROMs without requiring any key from the BIOS (provided the secure area is decrypted, which it generally is), I'm not sure about things like DSiWare.

... read more
Sometimes issues are simple... sometimes not
You might have noticed that one of my goals for the 1.0 release is to get DSi mode in melonDS up to par with DS mode. Not just in the sense of running DSi games faithfully: a good reproduction of the DSi environment is also useful to would-be homebrewers.

However, the road to DSi emulation is paved with all sorts of challenges. One example of a fun issue that had been reported a while ago: the DSi menu would freeze after the health/safety screen if any pictures were stored that could be displayed on the top screen. The issue was another unimplemented AES feature, and was fixed in melonDS 0.9.3.

Sometimes I wish all issues were this simple. I felt like looking at another of the known DSi-mode issues: the fact that we currently don't implement the RAM size register in SCFG_EXT9. The RAM size register is mainly used to restrict the accessible main RAM to 4MB before launching a DS game. In theory, not a very difficult thing to implement. In practice, however, there is an issue that kept us from enabling that feature: when it's enabled, the DSi launcher crashes when launching a DS game, while they would otherwise run fine (albeit with the full 16MB RAM instead of the 4MB they might expect).

As explained in GBAtek, nocash ran into the same issue:
SCFG_EXT9.bit14-15 affect the Main RAM mapping on <both> ARM9 and ARM7 side (that, at least AFTER games have been booted, however, there's a special case DURING boot process: For NDS games, the firmware switches to 4MB mode on ARM9 side, whilst ARM7 is still relocating memory from the 16MB area at the same time - unknown how that is working exactly, maybe ARM7 isn't affected by SCFG_EXT9 setting until ARM7 has configured/disabled its own SCFG_EXT7 register).

The basic process of the loader is as follows: the ARM9 syncs with the ARM7 via IPCSYNC, then both CPUs run through lists of memory areas to copy or clear, then the ARM9 changes the main RAM size if required. However, while the ARM7 has a bunch of regions in main RAM to clear, the ARM9 is given empty copy/clear lists, and all it has to do is clear its DTCM, which is quickly done. As a result, the ARM9 changes the main RAM size while the ARM7 is still clearing regions, causing it to overwrite the ARM9's code, and you guess how this goes: kaboom.

Yet, the same code works fine on hardware.

I had already experimented with the RAM size register, to try and find out if there's anything fancy about it, but there's nothing special at all. The RAM size gets changed instantly on both sides, and there's nothing fancy about memory mapping either. Oh and the ARM9 caches are disabled when the loader is running, so they don't come into play here.

So I made a homebrew that reproduced the loader code: same ASM code, same memory regions, same everything. My first tests were to see if there was any kind of secret register altering main RAM mapping somehow, but there was none. Then, another test determined that, infact, on hardware, the RAM size change isn't applied until the ARM7 has cleared all its memory regions.

We then added code to measure how long each side takes to complete its tasks, and it turns out that the ARM9 takes much longer than expected. The ARM9 code is running in main RAM, and the ARM7 has a bunch of main RAM regions to copy and clear: as EXMEMCNT is set to give priority over main RAM to the ARM7, the concurrent accesses are slowing down the ARM9. A lot.

This is some shitty news.

... read more
melonDS 0.9.3 is out!
We bring you melonDS 0.9.3, a tad late, but it comes with a good deal of improvements.

First of all, we fixed touchscreen input, it should now work as expected in all screen modes. We also added support for touchscreen devices (tablets etc).

On the emulation side, we added support for audio interpolation, as an optional emulation improvement. Depending on how good your game's samples are, you may see an improvement in audio quality. There are multiple interpolation types to choose from, so you can see which one you like best.

We also added a setting to optionally degrade the audio output to 10-bit, like the actual DS, for more authentic experience. This goes hand in hand with emulation of the SOUNDBIAS register, too. Emulating this register means nothing for the average game, but it could be used for cool tricks in homebrew. Hell, we even managed to make the DS play a song solely by regularly changing SOUNDBIAS.

There have been several improvements to DSi mode too. Namely, touchscreen calibration is now automatically patched in DSi mode, eliminating the need for a recalibration. It is also possible to boot DSi games and homebrew directly now, although this feature is still experimental. Last but not least, the DSi title manager allows you to easily install your DSiWare titles to your emulated NAND.

A ROM info dialog has also been added under System -> ROM Info.

There's also the usual slew of bugfixes and other little additions, you can check the changelog for the full list.

For the eventual 1.0 release, we also want to make melonDS less obtuse all around: providing user-selectable paths for savefiles and such, BIOS/firmware substitutes atleast for DS mode, less obtuse DLDI support, etc...

Enjoy!


melonDS 0.9.3, Windows x64
melonDS 0.9.3, Linux x64
melonDS 0.9.3, Linux ARM64
melonDS 0.9.3, macOS x64
melonDS 0.9.3, macOS ARM64
melonDS 0.9.3, macOS universal
Buffing up DSi mode
It's no secret that melonDS's DSi mode needs some love, but there are just so many things to do with melonDS.

One of the recurring complaints is that, when running in DSi mode, touchscreen input is off, requiring the user to recalibrate the touchscreen, while this doesn't happen in DS mode.

Reason for that is that on the DS (and DSi), the touchscreen hardware doesn't return pixel coordinates, but raw digitizer readings. Calibration data is then used to convert these readings to pixel coordinates. Every touchscreen digitizer is going to have a slightly different range, which is why users have to calibrate their touchscreen.

melonDS makes up for that in a very simple fashion. It uses its own conversion, basically just multiplying the touchscreen pixel coordinates by 16 to make decent 'raw' coordinates. When booting, melonDS also patches the user's firmware data with its own adequate calibration data, so that no recalibration is required and the touchscreen Just Works(tm). Easy peasy.

However, in DSi mode, it's another story. The old DS firmware data still exists, but the DSi system instead uses user settings files stored in the NAND. Thing is, it's less easy to access the data there: the NAND is mostly a FAT volume with an encryption layer. Not exactly trivial to deal with.

I was shown fatfs, which is basically a lightweight FAT driver. It is meant to be used to access storage media such as SD cards on embedded devices, however it is trivial to make it work on a FAT volume contained within an image file. I wrote code to do that with the DSi NAND, taking care of encryption transparently, and bam, I had a viable base for NAND manipulation.

I then wrote code to access the user settings files inside the NAND, and patch the touchscreen calibration data there. After taking care of all the details like SHA-1 hashes and whatnot, the initial issue was covered: the DSi-mode touchscreen Just Worked(tm), with no recalibration needed, just like its DS-mode counterpart.

With this proof of concept being a success, I took it further:



... read more
Audio interpolation
Apologies for the slow Summer! We don't have air conditioners in the melonDS HQ. The current climate is causing the team to slowly melt.

Anyway, audio interpolation is one of the emulation improvements that have been requested for melonDS. My general policy for emulation improvements is that they should allow for keeping the accurate code paths, and they shouldn't add too much complexity to the code. Audio interpolation is well within these bounds. Actually, I had implemented it in DeSmuME back then, and due to the way DeSmuME's mixer works, it was quickly done.

So I figured I would give it a try in melonDS.

The basic idea behind audio interpolation is to smooth out the audio samples as they're being upsampled. DS games may have downsampled audio to save on space and bandwidth, and the DS mixer doesn't perform any interpolation, which can lead to rough sounding samples. The reason the DS does no interpolation is most likely due to how its mixer hardware works, but obviously as an emulator we can ignore these constraints and do a better job.

It's also noting that, as far as melonDS is concerned, there are two parts we need to take care of: the DS mixer and the audio output.

In the DS, the mixer is driven by the system clock, like nearly everything else. If you ever coded for the DS, you might have wondered why the frequency registers for the audio channels are weird:

40004x8h - NDS7 - SOUNDxTMR - Sound Channel X Timer Register (W)

 Bit0-15  Timer Value, Sample frequency, timerval=-(33513982Hz/2)/freq

The PSG Duty Cycles are composed of eight "samples", and so, the frequency for Rectangular Wave is 1/8th of the selected sample frequency.
For PSG Noise, the noise frequency is equal to the sample frequency.

The SOUNDxTMR registers directly control the channel timers, which are driven at half the system clock. These work like the general purpose timers: they are incremented at half the system clock, and every time they overflow, they are reloaded to the SOUNDxTMR value and the channel advances to the next sample.

... read more