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
• (WIP) GBA slot add-ons
• and more are planned!

Download melonDS

If you're running into trouble: Howto/FAQ
Long-due status update
Sorry for the lack of updates lately. Mental health has been rough. Hopefully it's going to get better with the Christmas holidays...

What's new since the last post? I had started working on refactoring the melonDS codebase for the ambitious changes to come. JesseTG mostly finished the work on the core, so that's one big thing out of the way.

The frontend code is now going to need adequate refactoring too. That's, well, more work. We'll get there over the coming days.

On my side, I (finally) ordered a new laptop, so I'm waiting to receive it and set it up before I do more big work on melonDS.

I will need a while to adjust to the new changes that have been done to the melonDS core. It's also likely not perfect, we will likely have to do more work to clean up and harmonize the codebase. But atleast, the biggest part of the work is done.

On the frontend side, we need to add support for multiple different emulator windows. Historically, the frontend was structured around one emu thread and one emu window. The latter provides a means to display the emulator's video output and lets the user interact with the emulator, the former feeds the inputs into the melonDS core, runs it and manages it.

It wouldn't be difficult to spawn multiple emu threads, one per emulated DS. Window management is another deal. We thought we might want to support attaching multiple windows to one emu thread, for example to support displaying each DS screen on a separate window. For netplay purposes, we might also want to support headless instances, that is, running an emu thread with no window attached, no sound output, and inputs received from the network.

This also poses the question of OpenGL context management, all things we will need to look into.

We'll get there. It just... takes time.
Happy birthday melonDS!
Today melonDS is officially 7 years old. To celebrate, like last year, have a new version of the melonDS icon, recolored to the same orange color as 7 itself:

(if you're wondering about these colors: I have synesthesia, that's all)

I'm sorry for the lack of new releases since 0.9.5. It's been one year. That being said, we have big plans for the next release. I'm not going to go in length about these, the previous posts detail the plans well enough.

Just bear in mind that we're currently refactoring the melonDS codebase, so things may get a tad unstable while this is ongoing.

Other than that, it is a bit of a miracle that melonDS has been going for so long, and that after so long we're still around and coming up with ambitious plans. I've had several other personal projects, and none of them made it far past the one-year mark (or I only still work on them in a much more sporadic manner, like blargSNES). So, long live melonDS.

On my side, I quit my antidepressant in September, which went much more smoothly than I imagined. I've had a few bouts of depression since then, but nothing really bad, it's completely incomparable to what it was last year, and it's progressively getting better. I'm hopeful.

I tried Ritalin again, but it seemed to make me depressed after a while, so that's a bummer. I have a few ideas for other possibilities, but in the meantime I'm back to being unmedicated. Since this is how it's been for most of my life, I have coping strategies already, but the low energy part of it kinda sucks.

May 2024 be filled with success.
The RTC rework is done

melonDS has got a fun little dialog for changing the date and time now.

Basically what it does is show you the current date and time of the emulated DS. You can change it to any date and time, or you can reset it back to your computer's date and time.

What you set is saved as an offset in seconds from your computer's time. Every time you launch a game, the computer's time is used as a reference to calculate the emulated DS's time, and then melonDS does its own time counting from this point.

This also means that, unlike the previous behavior, if melonDS runs too slow or too fast, it will affect the passage of time for the emulated game from your perspective. The point is to keep melonDS's time counting accurate from the perspective of the game.

This was also the occasion to rework the RTC emulation itself, because it was quite lacking.

For example, when returning the current time, it would simply return the current hour from 0 to 23, ignoring the AM/PM flag that is also encoded in the hour register. It gets a bit weird, because the way this register works depends on the 12/24-hour setting in status register 1. In 24-hour mode, the register goes from 0 to 23, and the AM/PM flag is automatically based on that. In 12-hour mode, the register goes from 0 to 11, and the AM/PM flag needs to be set properly for things to function.

I was also able to add support for writing to the date/time registers. This means that for example, you can boot the DS firmware and change the time from there, and melonDS's date and time setting will reflect that. Perhaps not very useful, but a nice touch regardless.

... read more
RTC and ambitious plans
Two main things this post will talk about.

The RTC, aka Real-Time Clock. The DS uses a RTC chip to keep track of the current date and time. melonDS has had some RTC emulation since the early days, because it was a requirement to get the firmware to boot, but since then, that RTC emulation has been pretty much barebones. Basically, all it does is return the current system time from the host. While it's good enough for the most basic purposes, it comes with a number of downsides.

For example, we've had several requests from end users about changing the time inside melonDS. Currently, the only way to do that is to change your computer's time. melonDS offers no UI for setting its own time. It is possible to boot into the firmware and use the settings menu there, but melonDS ignores writes to the RTC date/time registers, so it just reverts back to the host system time. Less than ideal.

This is also a problem for netplay. The basic idea behind netplay is that all players run the same emulation, and inputs are synced across them. For this to work, you need to ensure that for all players the emulation starts from the exact same state, and that the inputs are the exact same for everybody. Since games use the RTC to initialize their random number generators, all sides need to start from the exact same time, or they will desync. So the basic, "let's just return the system time" RTC won't do here.

Then there's also the fact that this RTC emulation we have is incomplete. The RTC does more than just keep the current time: it features several 'alarm' settings that can trigger interrupts, for example. libnds uses that feature to do its time counting, so if you run any libnds homebrew in melonDS, it will seem stuck at the same time.

The DS firmware also has an alarm clock feature. While I doubt anybody out there is going to use melonDS as their alarm clock, emulating it would be a nice touch.

Regardless, I started working on the RTC yesterday. The first part is to have the RTC in melonDS do its own time counting. The RTC in the DS is likely controlled by a 32768 Hz clock, as is typical for these things, so I did something similar in melonDS, as it will be a requirement for emulating the alarm interrupt features.

I used the system event scheduler in melonDS for this purpose. It is technically inaccurate, because the scheduler runs on the DS system clock (33.51 MHz), but it provides a reliable way to keep the emulated RTC in sync with the rest of the system. I had to get a bit fancy to correct for the inaccuracy from using the system clock as a base, but nothing bad.

From there, I laid down the basic idea of a clock. Have a bunch of registers for the current date and time, count one second every 32768 RTC ticks, count one minute whenever the second register reaches 60, count one hour whenever the minute register reaches 60, etc... You get the idea. As there's currently no way to tell the melonDS core which time to use on startup, it starts at 01/01/2000 00:00:00, but it does count up properly so far.

... read more
LAN multiplayer: getting there!
As of today:

LAN gameplay between the two computers I have at hand over here.

LAN is actually fairly close to a finished product, now. It's obviously still a bit rough around the edges, may be a tad unstable, but from my testing it has shown to be pretty smooth.

From this point, I encourage anybody who is interested to grab the experimental builds from our Github CI. It's the runs labelled 'season2 test PR'; note that you will need a Github account to download them.

But if you're motivated, please give them some deep testing, abuse them in whatever ways you can think of, and report anything that seems odd to you, in our IRC or Discord or in this thread. We'd like these features to be rock-solid for the 1.0 release.

How to get a LAN game going:

1. On the host machine: open melonDS, then System -> Multiplayer -> Host LAN game. You enter a player name and you're good to go.

2. On client machines: open melonDS, then System -> Multiplayer -> Join LAN game. Enter your player name there, then it should list any existing LAN games. If not, you can always try using the direct connect button.

... read more
LAN multiplayer: in the works
First of all, thank you all for the kind comments to the last post, it means a lot!

Anyway, I've been throwing together a basic interface for LAN multiplayer. It's far from complete, but it's already showing promising results so far.

The issue is that it requires a low enough latency to work well. When connecting my two computers over a crosswired cable, yielding a latency of ~1ms, I had decent success connecting the two sides together. However, when using the regular network (my laptop connects over wifi, while the other computer uses a PLC adapter), latency was all over the place and it was impossible to get a local multiplayer connection going.

This isn't too different from the old socket-based network interface, really. Except that interface performed even worse, because it was really just tossing packets over the network with zero care.

This new LAN mode will function more like typical LAN games: you get a host starting a LAN game, then everyone else connects to the host using their local IP (or their computer's host name). Then you would launch your game and connect to other players like you would on an actual DS.

There's still some more work to be done before this can be called finished, mostly UI work but also other tidbits. I'll keep you informed.
Sorry for the silence lately
I've been merging some pull requests earlier today, and, looking at some of them...

"Wow, has it really been one year?"

I'm sorry about this. It's not that we, melonDS team, don't care about user contributions. We do, and we're grateful for them. However it takes time to review them and make sure they're mergeable.

And while I can't speak for the rest of the team, the way I am doesn't help. I don't really notice the passage of time, anything in the past just feels like it happened ages ago, and it's very easy for me to let myself be carried into a comfortable routine for a long time. As you can imagine, it's a problem for certain daily life things. It also means that I end up postponing some things a lot, when I don't immediately feel like dealing with them and there's no urgency, I end up just thinking that "I'll do it later when I feel like it", let time pass, let routine carry me, and... "wow, has it really been one year?". Things like dealing with pull requests definitely fall into this pattern.

Lately, side effects from meds haven't been helping either. I take ritalin for ADHD, and venlafaxine for depression, and the two don't go together well for me. The latest dose increases (in July) led me to a situation where I had bad side effects: absurdly dry mouth, headaches and light sensitivity, bad sleep (waking up every hour or so), and intense fatigue, entirely negating ritalin's benefits.

I stopped taking ritalin and things quickly got a lot better. Although this also means I'm back to my usual ADHD self, in terms of focus and productivity: I don't really control what my brain focuses on, and it can take a long while to get myself to do things.

I won't try taking ritalin again until I'm off venlafaxine. I'm tapering down that; I get more tired some days but overall it's going well. I think venlafaxine has done its job, I also feel a lot better about myself and the world than even one year ago, so I'm pretty confident I can do this. I also want to go out, meet people, do things (all of which are very good ways to keep depression at bay), but it doesn't help when meds leave me too tired to do much at all. So yeah.

From a coding perspective: I want to attempt getting a proper LAN mode going for melonDS. Although lately my brain has been wanting me to focus on something else: a fun side project adventure that involves DSi DSP programming. It's not directly related to melonDS, but it may end up benefitting the DS/DSi scene either way, so hey. I'd want to talk more about it, if it does pan out, but that'd go on another blog.
Optimizing wifi, take two
I've been thinking about the problem and making another experiment, which seems more successful.

The basic idea is that games send multiplayer data at a generally steady rate and the timings are predictable. When the host sends a CMD frame, generally there won't be anything else being sent (other than replies and ack) until the end of the CMD_COUNT window, unless some clients failed to reply. The only exception to this is when the host sends a beacon frame, but since these are sent at a fixed interval, it's not hard to take them into account.

I had to do a few tweaks to get it reliable in certain situations, but so far it gives quite a substantial speed boost and doesn't seem to impact reliability. We still have to see how this goes -- we might have to make it optional if it causes problems somewhere.

I'm also trying to fix some other problems, namely how in some games you can't connect more than two players. I have a bit of an idea what's going on, but I'll need to work on it more.

We're also thinking of bringing back LAN, but as a proper LAN mode instead of just tossing packets around the network. It may even possible to build something robust around enet. I'll have to give this a try.
Trying to optimize LLE wifi sync...
In the previous post, I mentioned I had an idea to optimize LLE wifi. I've been experimenting, but for now, nothing really conclusive came out of it.

Basically, if you remember your local multiplayer 101, this is how it goes:

The CMD frame isn't sent immediately, there is always a variable delay before. In a real world setting, you'll want to ensure your wifi channel isn't being used before sending stuff, so that's what the delay is. However, the CMD frame and subsequent reply frames use the 802.11 duration field to reserve the needed timeslot for the entire CMD exchange, so that everything can be pretty tight.

Since version 0.9.5, melonDS uses a synchronization mechanism to ensure this works smoothly. It is actually fairly simple: each frame that is sent has a timestamp attached to it, that is used to keep things in sync. Clients may not run ahead of the host -- when they receive a frame from the host, they know how much they need to catch up, when to start actually receiving that frame, and in the case of a CMD frame, how long they can run ahead before waiting for another frame. And the host discards stale reply frames to prevent itself from running too far ahead. All fine and dandy.

However, I observed that local multiplayer exchanges aren't as tight as I thought before. In most games, the host only sends a CMD frame once per video frame (that is, once every ~16.67ms). Pictochat is a bit different -- it does send CMD frames every ~4ms, but it also does that thing where it polls 3 or 4 clients per frame in a rolling order, so it amounts to a pretty similar thing anyway.

This means that in our case, with the current sync mechanism, clients will spend a whole lot of time waiting for a CMD frame, then having to catch up a whole lot while the host is waiting for reply frames. From a performance standpoint, this is far from ideal -- it largely negates the benefits of multi-core CPUs.

I came up with two ways to work around this, and experimented with them, but so far they both have issues.

The first way would be to abuse the pretty generous CMDCOUNT window games use when sending a CMD frame. I thought that in theory it should be possible to send the CMD frame to clients early, and even have the clients send their reply early as soon as possible, and delay the actual emulation of the CMD/reply/ack exchange until the end of the CMDCOUNT window, and thus things would run more smoothly.

... read more
HLE, wifi, netplay: recent developments and ideas
So yeah, I have been pretty silent lately, sorry about it. Been tired, a bit of a depression burst, medication adjustment and stuff, but overall I'm doing well. I've been taking some vacation time, so this helps a lot, too. I've mostly been chilling, bathing, toasting under the Summer sun, pretty standard vacation stuff.

However I've also been able to do some melonDS-related work.

I started implementing wifi in melonHLE. So far, I got to the point that there's some data exchange going on, but the connection isn't working due to a timing problem -- I need to rework when I send data frames and how to keep all the melonDS instances in sync.

It's too early to tell, but if I can get it working, it may be a good base for local multiplayer and netplay on lower-end platforms, as I said before. On one hand, the way wifi works at a high level seems to provide enough leeway that I could get away with somewhat lax sync, and thus better performance. On the other hand, I don't have it working yet.

The current implementation is also a bit of a pile of hacks. I will need to clean it up and implement a bunch of the more minor details. I'm also not very confident that the compatibility rate will be on par with the tried and true LLE approach, but the only way to find out is to try out.

There are still several more general issues that limit melonHLE's general compatibility. While testing some other games, I found out that there are atleast 3 different versions of the sound module, more recent games (like Picross 3D) have a different power management module, and there are games that get stuck due to missing functionality. And that's without even getting into DSi stuff. Ideally, I'd want to index all the ARM7 binary versions out there to have a better idea how viable melonHLE may be.

Regardless, this work will likely prove useful for future melonDS/Dolphin interop. As you may already know, some Wii games are able to connect to a DS to provide extra features. This connection uses the same protocol as DS local multiplayer. On the Wii, the functionality is exposed through an API similar to what DS games use at a high level. Dolphin, being HLE, deals with high-level service calls, while regular LLE melonDS has to emulate the wifi hardware and deal with the 802.11 protocol in all their complexity. So obviously some work will be needed on Dolphin's side in order to make it communicate with melonDS.

Also, while I was brainstorming how to efficiently synchronize melonDS instances in HLE wifi, I had an idea for LLE wifi. I will need to try it out, but if it works, it may drastically loosen up the synchronization requirements for local multiplayer (although the gain will likely depend on how many players are connected).

If any of this pans out, we might be able to bring back the ability to do local multiplayer over LAN (I mean, without using the netplay system). I don't know how well it would work in practice -- I remind you that the current IPC comm layer has a bunch of extra smarts to avoid causing lag by unwarranted blocking, and I'm not confident these can be reliably replicated over the network.

Stay tuned!