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
New horizons
I'm starting a new emulation-related project. For now, I won't say much at all about it, because I don't even know how far it will get...

Mostly, my brain needs the novelty.

But also, this may prove useful for melonDS. For example, figuring out coding styles and organization structures I like, that could address the shortcomings of melonDS.

I have to be honest, the melonDS codebase isn't in a good state. Not a state I like.

It feels like I've alienated myself (and others too) from melonDS, with all the refactoring.

There needs to be a cleaner directory structure, with subdirectories for specific parts of the core, rather than dumping everything into the src directory. You might notice I had started doing that with some of the new features (like for example DSP HLE).

The code itself needs to be cleaned up significantly, and kept consistent.

The frontend is a mess. I had begun cleaning it up, splitting specific functions to their own code files, and so on, but it's still far from being at a point where I like it.

There's the fact those tasks are just daunting. It feels demotivating to have to deal with a messy codebase, but so does trying to clean it up on the flight, when you lack an adequate plan.

... read more
blarg
I'm still alive.

Main reason for the lack of updates is, well, same old. Job taking up a lot of time. Emotional work taking up a bunch of the remaining time.

Desire for new projects, too. "Hey, this looks like an interesting problem, let's solve it!" - that's my brain in a nutshell.

Maybe a different emulator?

-

As far as melonDS is concerned, I'm most likely going to leave it aside until November. I'll hopefully be able to take a decision.

I atleast know what I don't want: I don't want to just abandon melonDS and leave it to whoever. At this point, it's a bit like a brand name, melonDS has a reputation within the scene... If it were to be picked up by the wrong kind of people, that could destroy its reputation.

But then again, that's life. Emulator projects come and go, like everything else.

We have DualSOUP, Jakly's attempt at cycle-accurate DS emulation. By its essence, it's already going beyond the structural limitations of melonDS. So, a very interesting project. There's potential to push the limits of DS emulation. And if it succeeds, it might even motivate a rewrite of melonDS to overcome the aforementioned structural limitations.

... read more
Motivation, motivation...
Yeah, I haven't been great at this. I told myself I would work on 2D filters, since it's one of the last things to do... then I ran into a bit of a wall: I need my filters to have alpha support, but the filter shaders I can find don't support it. I would need to spend some time figuring out how they work and how I can add that in based on other references (there is code for xBRZ or HQX filters with alpha support, but not in the form of shaders).

And I, well, didn't feel the desire to continue...

Maybe it's the nature of software development in itself. Unless you're working on a smaller, simpler project, you're never really done, and especially not with a project like melonDS. What started as a way to pass time has become a full commitment, in a way.

By comparison, my job has been a lot simpler, and better suited to my brain too. When you set out to repair something, it's a project with a clear end. Most of what I deal with is also fairly simple, but sometimes there are more complicated cases, requiring more time and research. For example, those HMI lamp ballasts I'm working on: they are quite complex. This has been an ongoing project for a while now.

Maybe it's the fact that the project still largely rests on my shoulders. While bigger projects like Dolphin or PCSX2 may have a bigger team and more of a workflow in place, things aren't really like that here...

I'll just quote Generic, because he put it well:
[18:55]Generìc "Yes, we can!": I think I stated this before, but how I see it melonDS never went through the professionalisation many other projects went through
[18:58]Generìc "Yes, we can!": just look at other projects (even with just a single maintainer) setting milestones, systematically "triaging" issues and so on
[19:00]Generìc "Yes, we can!": also tests
[19:01]Generìc "Yes, we can!": and throuroughly adoption of new fangled C++ features
[19:03]Generìc "Yes, we can!": if it wasn't for Nadia putting so much effort into the build system through the whole time, the codeblocks project file would still be the way to build melonDS

I feel bad about having so many issues, pull requests, etc, staying open and rotting in the backlog. At the same time, I just don't have the brain power to review every single PR alone.

And to make matters worse, now we have people submitting AI-generated code, which is problematic from several standpoints: code quality (AI tends to make a mess and not really understand what it's doing, and someone who's using AI isn't likely to understand those things any better), plagiarism, the usual ethical and environmental problems with AI too...

I like the idea of open source, but for a project of this caliber, it feels that we should have more of a system in place, with a bigger team, clearer roles... a proper organization.

One where different people with different skillsets and preferences can complement eachother. For example, while I enjoy researching the DS hardware, or figuring out why a game isn't working as it should, stuff like build systems can quickly feel very frustrating to me. As Generic put it, if it weren't for Nadia handling that work, we might not have nightly builds today, for example.

... read more
Bit of plans
As far as melonDS is concerned, my last work was all about CPU timings... and I couldn't yet find an elegant way to handle them. I had some kind of caching in mind, but it's still less than ideal. Code fetch timings could be cached, but data fetch timings aren't really predictable, and there are other mechanics coming into play. What I had in mind was a sort of graph system, but I don't know how well it would work in practice.

This will be for later though.

I didn't foresee how much time and energy starting this job would take me. Things are starting to even out now. Same story for my psyche, things are falling into place, but there's still work...

Anyway.

Plans.

I will try to finish the work I was doing with the new OpenGL renderer. It was mostly dealing with things like VRAM streaming, and adding a "Golden Sun hack".

I could also try and see if I can build something for 2D layer filtering, but I might postpone that.

When I'm satisfied with what I have, I'll release melonDS 1.2.

Sound good?
Expect slowdown
A bit of a status update since the last post...

"I've been taking a bit of a break from melonDS lately... mental health reasons, a silly side project, the usual stuff."

More of the same stuff, but add to it that I've been getting started in this new job.

While it's been nice to have time to myself in order to deal with mental health matters, unemployment gets old after a while, so I was eager to finally start this job.

If you remember, I've had a foretaste of it back in December, too. I've seen my ADHD self thrive in that setting. The job is largely about repairing A/V equipment. This feels like a much better fit for my brain than a regular developer job. I like to code, but that's not all I do: I also like to build, repair things, and in general, understand how systems work (or design them). I consider code to be much of the same, but it's all inside a computer instead of being a physical object, so it lacks the "doing things with my hands" aspect.

A related example here: last year, I repaired buttons on a vacuum tube radio as part of a larger project. This is the kind of small project where I have a blast: using my brain to figure out a solution, actually implementing it with my hands, doing my best to adapt to how things actually work out... It makes me feel alive like nothing else.

But I digress. The flip side of this is that the longer work day and commute time leave me with less time at home. On the other hand, this job is a particular arrangement where I'll be working half of the year, which will definitely give me time for my personal projects, including melonDS. Just, won't be now. The first work period is going to be 6 months.

-

This also means having to balance work and mental health.

... read more
A bit of a status update
I've been taking a bit of a break from melonDS lately... mental health reasons, a silly side project, the usual stuff.

Regardless, I've been rethinking my plans for melonDS.


I think I might postpone the timing work to melonDS 1.3. It's bigger than anticipated. I want to address some other issues, most notably finishing the new OpenGL renderer, and release melonDS 1.2. There's also some codebase cleanup I want to do.


Regarding the timing work, it's going to take some planning, and possibly a larger rework.

As I've said, the ARM7 is simple enough. Things are pretty much sequential, and the only extra complexity comes from main RAM burst termination delays.

The ARM9 is where it gets hard. We deal with mechanics like cache streaming, write buffering, ability to keep running code while the bus is in use... All sorts of mechanics which highlight the limits in melonDS's current model.


For example, take the LDM and STM instructions. They do multiple consecutive memory accesses in a row. They're commonly used to push registers to the stack and pop them back, or to quickly clear or copy large blocks of memory.

There are several issues arising from this. Depending on the base address, a LDM/STM instruction might cross the boundary between two memory regions, or two MPU regions on the ARM9. STM, when accessing I/O registers, might also cause a bus stall between two memory writes (for example, if it starts a DMA transfer...).

melonDS was built on top of a plain old interpreter. We read one instruction word from memory, we use a lookup table to figure out what we should do, we do it, then we move on to the next instruction, and so on. This model treats individual instructions as atomic: there is no way to account for all possibilities with LDM and STM, for example. Or atleast, not easily.

... read more
New demo: Emulator Examination
Emulator Examination is a DS demo which has been released recently, and has been programmed by PoroCYon.

I figured this would be an opportunity to write about something other than CPU timings for once! But first, a video of this demo, comparing the hardware results against melonDS.



This demo bends the DS hardware in creative ways. You can read PoroCYon's writeup here, but I figured I would write about my perspective too.

First of all, this is a DSi demo, which limits the opportunities for emulator comparison. As of now, melonDS and NO$GBA are the only emulators with some degree of DSi support. The demo will still run on a DS, but you'll be limited to the first test, since this one isn't DSi-exclusive.

Now, let's see what we got here.


First, we have an eyesight test. At first, I had no real idea what was going on here. Basically, the PPU mode is changed in the middle of a scanline, which causes very specific glitches.

The interesting part is that this mirrors how hardware reverse-engineering works: doing unintended things with the hardware, observing the results and figuring out the logic behind them, can offer insight into how the hardware works beneath the surface. It can also confuse you to shit (hi, 3D GPU).

However, this effect is unlikely to ever work correctly in melonDS. Emulating it requires understanding and accurately modelling how the PPU works at a cycle level, while melonDS employs a scanline-based renderer. And since no games out there try to modify PPU registers during a scanline, there are no provisions for supporting that.

... read more
The timings saga, ep 2
At this point, this might as well be its own little saga... albeit not as exciting as the local multiplayer one, atleast on the surface. What is exciting, though, is the possibility to deal with timing issues once and for all.

Maybe not. We can't get it 100% perfect without cycle accuracy. But we can get as close as possible, and then see how much leeway we have. It should be easier to figure this out with a more correct model. When your timing model is fundamentally inaccurate, you can tweak the numbers, but that's a game of whack-a-mole: it fixes some bugs and causes other bugs. This is what the "Enable Advanced Bus-level Timings" option in DeSmuME does. The cache timing constants in melonDS, if they could be modified by the end user, would yield similar results.

Fun fact, melonDS's current timing model is flawed. Due to a few bugs, it doesn't even work as intended. But even if it did, it would still be inaccurate.

DesperateProgrammer's cache PR, aka PR #1955, is a pretty solid base for cache emulation. I think it's a good sign that it alone has showed promising results, despite being based on the same fundamentally flawed timing model.

Anyway, enough talking. Let's see where we're at today.


So far, I'm mostly done with ARM7 timings. I've been collecting timing numbers, figuring out the logic behind those with Jakly's help (thanks there!), and implementing it. In my timing tests, melonDS yields the same numbers as hardware, so that's nice. It feels pretty satisfying when you figure out the logic and everything clicks into place.

I still need to doublecheck everything, and do actual real-world timing tests, to make sure I have everything right.

However, as far as CPU timings are concerned, the ARM7 is only the appetizer.

The timing model is fairly simple. The ARM7 doesn't have internal memory and only has one bus, and everything runs at the same frequency, so most timings are fairly straightforward.

... read more
Actual status update on timings
As promised.

Timings work is underway. I'm mostly done collecting numbers, minus stuff like CP15 operations and any special cases that might crop up. I started fixing up ARM7 timings.

Thing is, timings work isn't always easy. Collecting timing numbers is one thing, understanding the logic behind them is another thing entirely. Geometry engine timings, which I've worked on years ago, are a prime example of this: when you submit a display list to the geometry engine, the total execution time isn't simply the sum of each command's execution time. The reason for this is that the geometry engine has a pipeline: it can execute certain commands in parallel. It took me a lot of testing and number collecting to understand the logic behind it.

If the geometry engine, a simple 3D command processor, is already like that, you can imagine what a full-fledged CPU is going to be like. This is why CPU timings are an area of melonDS that has been more or less neglected for so long.

On the flip side, the DS isn't like older consoles such as the GameBoy or the NES, where games might rely on very precise timings in order to get the best out of the system's limited power, and they might crash if a certain event occurs 2 cycles too late. On the DS, from what I've seen, it's more about timings at the macro level, ie. how long a bigger operation takes. For example, consider a DMA transfer to copy a screen-sized bitmap, that is, 24576 words. A difference of 1 cycle in the initial DMA setup time doesn't matter, but a difference of 1 cycle per word transferred quickly adds up. Like here.


So, what are ARM7 timings like?

The ARM7 has a 3-stage pipeline, which means it can execute an instruction while decoding the next one and fetching the one after. So, for a lot of instructions, the execution time is capped by the access time for the memory region we're executing from. Some instructions may need more cycles to execute. Load and store instructions are also particular, since they access memory.

Different memory regions have different access times, depending on their data bus width and the type of memory access. Most of the available memory regions are integrated into the DS SoC, so they can be accessed in one cycle. VRAM has a 16-bit bus, so 32-bit accesses are broken into two 16-bit accesses and take two cycles.

External memory, however, has its own rules. There is a notion of nonsequential and sequential accesses. Basically, the memory being accessed may require a setup time for an initial access, but may be able to chain subsequent accesses in a faster way. The ARM7 makes use of this when fetching code: as long as a given instruction doesn't require extra cycles, the next one may be fetched in a sequential memory access, resulting in faster execution. Instructions like LDM and STM, which can load or store several words in a row, also make use of this.

... read more
New direction for melonDS
[POST IS AN APRIL FOOLS JOKE]

It has appeared to us that after nearly 10 years of development, we are still very far from having a perfect DS emulator... thus, something has to be done. After all, you can't keep doing the same thing and expect different results, can you?

So we have been looking at those AI coding assistants.

We have seen Windows 11, and how the use of AI has helped turn it into a truly reliable, performant and user-friendly OS. We were originally doubtful about AI, as we always are towards any new technology, but we have to admit, it's pretty good.

So I first gave it a try.

I told Claude about the issues I was currently facing in melonDS, the timings work, and how difficult it all is. Claude offered a solution that at first seemed quite unorthodox, but actually makes a whole lot of sense.

After all, timing issues exist because timings exist. If you remove timings, no timing issues! That's pretty smart.

I offered to let Claude remove all timings from melonDS. It isn't perfect yet, but I observe that most problematic games are now running to some extent. I'm fairly confident that with more refining, we can solve the issue of timings once and for all.

The downside is that getting rid of timings basically means melonDS will be running everything as fast as possible, which requires quite a strong CPU. But not too strong, or your games will be running too fast. I haven't yet figured out how to make the framerate limiter work smoothly with timing-less emulation, but once again I'm confident Claude will come up with a genius solution.

... read more