|
| Home | Downloads | Screenshots | Forums | Source code | RSS | Donate |
| Register | Log in |
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 |
| Pages:1234567···25 |
|
New demo: Emulator Examination Apr 12th 2026, by Arisotura |
|
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 |
| 3 comments (last by Tris) | Post a comment |
|
The timings saga, ep 2 Apr 9th 2026, by Arisotura |
|
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 |
| 7 comments (last by Arisotura) | Post a comment |
|
Actual status update on timings Apr 2nd 2026, by Arisotura |
|
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 |
| 6 comments (last by marion iggers) | Post a comment |
|
New direction for melonDS Apr 1st 2026, by Arisotura |
|
[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 |
| 6 comments (last by bob7210) | Post a comment |
|
Chronicles of Timings: Tales of Destruction Mar 16th 2026, by Arisotura |
|
Ah, timings. The infamous Horseman of Timings. This post is going to be about a decision I'm taking for melonDS, but first, I'll write about my recent research regarding two old timing issues. I found it very interesting to dig into those games and figure out how they work. 1. Corrupted FMV audio in Over The Hedge - Hammy Goes Nuts Basically, you start a game, and you have a bit of a video introducing the plot of the game... except the audio is covered in high-pitched beeps and loud screeching. I first found that the game runs a video/audio decoder on the ARM9, which appears to have been largely written in ASM. The audio decoder writes its output in main RAM, where it gets sent to the audio hardware. The way it works is interesting. The audio buffer size is calculated based on the length of the audio track, the audio frequency, and other parameters. In this case, the length is 30 blocks, one block being 128 samples. Then, the decoder is run until the buffer is filled to a certain point (23 blocks). At this point, audio playback is started. The ARM7 also starts a periodic alarm which will notify the ARM9 every time one block worth of audio has been played. The alarm notification is used to run the audio decoder when needed. However, the audio decoder works in terms of bigger chunks: one chunk typically contains 6 blocks worth of audio. So the decoder attempts to process that many blocks in one go, but it stops processing new blocks when the output buffer is full. The catch is that, as far as I can tell, when blocks are skipped, there is no logic to compensate for that. The next time the audio decoder runs, it will start working on the next chunk no matter what. Since the decoding process relies not only on the current input but also the previous output, skipping blocks breaks it. And that's what is happening on melonDS. In this situation, the ARM9 needs to run slowly enough that it doesn't get too far ahead of audio playback, and doesn't fill the output buffer entirely. ... read more |
| 6 comments (last by dreamsyntax) | Post a comment |
|
Fixes, and future of melonDS Mar 8th 2026, by Arisotura |
|
Things have been difficult lately, mental health wise. However, despite this, we're still on a pretty good upward trend on that front. Anyway, I mentioned the cartridge interface in the previous post, so I've been doing an accuracy-oriented revamp of this. I've already been through the technical details, so instead, I'll post about the outcome of this. This fixes the freeze in Surviving High School, and likely other DSiWare titles. This also fixes Rabbids Go Home: in DS mode, the antipiracy no longer kicks in, so the game Just Works(tm). Also, turns out this game skips the antipiracy check when running on a DSi, so that's why it was working fine in DSi mode. I've had reports that this also fixes the crash in The World Ends With You, so that's great. I've also been able to figure out why several games crash in DSi mode. Namely, games that aren't DSi-enhanced, but were built against recent SDK. The code for reading the ROM retrieves the correct value for the ROMCTRL register from the ROM header, at 0x027FFE60. When running on a DSi, that address is adjusted to 0x02FFFE60, to account for the larger main RAM. Technically, 0x02FFFE60 would also work on the DS, due to mirroring; however, since it's not within any MPU region, trying to access it causes a data abort. The issue was due to missing support for the SCFG access registers. Those registers allow to block access to specific DSi I/O ranges, which serves to implement DS backwards compatibility or restrict access to specific hardware components (for example, blocking cartridge games from accessing the NAND). In this case, games read SCFG_A9ROM and determine that they're running in DSi mode if the value is non-zero, but if access to SCFG registers is disabled, the value will be zero. This brings me to ideas I have in mind for melonDS, and the direction things are going to go. ... read more |
| 18 comments (last by Arisotura) | Post a comment |
|
The DS cartridge interface: endless fun Feb 28th 2026, by Arisotura |
|
Depending on your definition of fun, of course. This is a bit of a pace change from all the recent OpenGL stuff: this is going to be some hardware infodumping slash juicy technical post. It all started with this bug report: Bug: Surviving High School (DSiWare) not booting. Basically, this DSi game gets stuck on a black screen. This bug report piqued my interest, and oh boy, I had no idea what kind of rabbit hole it would be. I first started by doing what I do in order to troubleshoot emulation bugs: track where each CPU is hanging around at, dump RAM, throw it into IDAPro. This gives me an idea what the game is doing, and hopefully provides a lead on the bug. Another possibility is to try modifying the cache timing constants to probe for a timing bug, but this made no difference here. In this situation, the ARM9 was running an idle loop, but the ARM7 was stuck in an endless loop. Backtracking from this, I found that the game was reading the cartridge's chip ID, comparing it against the value stored at 0x02FFFC00, and panicking because the two were different. This code isn't atypical for a DS game... But... wait?! This game is a DSiWare title! There is no cartridge here. No idea why it's reading the cartridge chip ID. Maybe the game was intended to be released in physical form? But in this case, the chip ID stored at 0x02FFFC00 is zero. When no cartridge is inserted, melonDS returns 0xFFFFFFFF instead of zero, hence one part of the bug. Changing melonDS to return zero when no cartridge is inserted would fix the bug, but only when there's indeed no cartridge. If there's one, it will fail. This is because when booting a DSiWare title, the DSi menu forcefully powers off the cartridge if there's one inserted. melonDS doesn't emulate this bit. ... read more |
| 18 comments (last by Chris Jones) | Post a comment |
|
Little status update Feb 14th 2026, by Arisotura |
|
So yeah, it's been a while since the new OpenGL renderer was merged in... Haven't been very active with melonDS since then. I've mostly been taking a well-deserved break from all this intensive coding. Real life is catching up, too. Mental health stuff. Things coming up that I have to take care of. Add a minor Hytale addiction to the mix, and... yeah. I'm going to post a few notes about the future of melonDS at large. First, I've been toying with a Golden Sun hack for the OpenGL renderer. (click for full-size version) Flicker-free hi-res. When I had first attempted it, there was some flickering, which was caused by color conversion issues that have since been fixed, so I figured I could give it another try. It is a gross hack, but a nice proof of concept regardless. It doesn't address the performance issue (which will need a separate fix), but it fixes up the upscaling issue by replicating what Golden Sun does in a high-level manner. ... read more |
| 14 comments (last by mr. Odégard) | Post a comment |
|
blackmagic3 merged! Jan 31st 2026, by Arisotura |
|
After much testing and bugfixing, the blackmagic3 branch has finally been merged. This means that the new OpenGL renderer is now available in the nightly builds. Our plan is to let it cool down and potentially fix more issues before actually releasing melonDS 1.2. So we encourage you to test out this new renderer and report any issues you might observe with it. There are issues we're already aware of, and for which I'm working on a fix. For example, FMVs that rely on VRAM streaming, or Golden Sun. There may be tearing and/or poor performance for now. I have ideas to help alleviate this, but it'll take some work. There may also be issues that are inherent to the classic OpenGL 3D renderer, so if you think you've encountered a bug, please verify against melonDS 1.1. If you run into any problem, we encourage you to open an issue on Github, or post on the forums. The comment section on this blog isn't a great place for reporting bugs. Either way, have fun! |
| 16 comments (last by JstDen) | Post a comment |
|
Golden Sun: Dark Destruction Jan 26th 2026, by Arisotura |
|
It's no secret that every game console to be emulated will have its set of particularly difficult games. Much like Dolphin with the Disney Trio of Destruction, we also have our own gems. Be it games that push the hardware to its limits in smart and unique ways, or that just like to do things in atypical ways, or just games that are so poorly coded that they run by sheer luck. Most notably: Golden Sun: Dark Dawn. This game is infamous for giving DS emulators a lot of trouble. It does things such as running its own threading system (which maxes out the ARM9), abusing surround mode to mix in sound effects, and so on. I bring this up because it's been reported that my new OpenGL renderer struggles with this branch. Most notably, it runs really slow and the screens flicker. Since the blackmagic3 branch is mostly finished, and I'm letting it cool down before merging it, I thought, hey, why not write a post about this? It's likely that I will try to fix Golden Sun atleast enough to make it playable, but that will be after blackmagic3 is merged. So, what does Golden Sun do that is so hard? It renders 3D graphics to both screens. Except it does so in an atypical way. If you run Golden Sun in melonDS 1.1, you find out that upscaling just "doesn't work". The screens are always low-res. Interestingly, in this scenario, DeSmuME suffers from melonDS syndrome: the screens constantly flicker between the upscaled graphics and their low-res versions. NO$GBA also absolutely hates what this game is doing. So what is going on there? Normally, when you do dual-screen 3D on the DS, you need to reserve VRAM banks C and D for display capture. You need those banks specifically because they're the only banks that can be mapped to the sub 2D engine and that are big enough to hold a 256x192 direct color bitmap. You need to alternate them because you cannot use a VRAM bank for BG layers or sprites and capture to it at the same time, due to the way VRAM mapping works. ... read more |
| 5 comments (last by Arisotura) | Post a comment |
| Pages:1234567···25 |
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: