|
| Home | Downloads | Screenshots | Forums | Source code | RSS | Donate |
| Register | Log in |
| < The DS cartridge interface: endless funChronicles of Timings: Tales of Destruction > |
|
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. When making my changes to cartridge emulation, I ran into an issue with cart DMA transfers, which broke atleast one game. It's fixed now, but it highlights shortcomings in the way DMA triggers are done in melonDS. That code wasn't great in the first place, and it was modelled after DS DMA. Then when DSi support was added, the required support for NDMA was duct-taped to the existing system. It does the job, but it's not great. It also highlights some suboptimal practices: using magic numbers instead of enums, for example. It tends to make the code harder to read. Since we're talking about the codebase, it's no secret that I'm not a fan of how it has evolved in some aspects. The big 1.0 refactor has exacerbated some of those issues, as making the codebase support something it wasn't originally meant for (running multiple DS instances within one process) required a major overhaul. For example: originally, some components in melonDS were modelled as C++ classes when they needed to be instantiated more than once (for example, the 2D renderers). The rest were simple namespaces. But suddenly, everything had to be remodelled as a class. We ran into issues due to the naming convention used in melonDS. So we're going to fix that by making changes to the naming convention. This is something that can be done progressively, since unlike the 1.0 refactor, it doesn't leave the codebase in a broken state until it's complete. However, it's going to have implications for people who have currently open pull requests. This change will definitely take some planning. I also want to use proper enums and make the code more readable, as I said. I also want to organize the source directory better, which I've already been doing: for example, I put the DSP HLE modules in their own subdirectory, I also did the same to the various NDS cartridge implementations, ... This sort of stuff isn't very exciting to the end user, but to us, it can make a big difference - making the codebase easier to read, easier to maintain, and overall more pleasant to work with. Some areas of the codebase kind of kill my motivation when I have to touch them. I also have other things in mind for melonDS. For example, I'm brainstorming ideas to make DSi emulation a smoother experience. We're at a point where we could remove the "experimental" disclaimer that's on it, but there's still a lot to do. Since the NAND is mostly a FAT volume, I'd like to experiment with syncing that to a folder, like we do for DLDI and such. I want to experiment with such things as bigger NAND images, a smoother process for launching DSiWare titles, and so on. I'm even pondering what it would take to build a NAND from scratch, and ideas like a custom DSi menu. Launching things is something that could use an overhaul in general. On the DS, games can only ever be launched through the cartridge interface, so melonDS was built around this. However, on the DSi, they can also be loaded from the NAND (DSiWare), or even from the SD card (homebrew, CFW, ...). melonDS still doesn't really offer good support for this. Which brings me to the UI. I have some ideas in mind for a more flexible configuration system. Currently, melonDS applies the same configuration to every game you run, and it's becoming apparent that it's too limited for the various possibilities the DS offers. One idea is a game list interface, like Dolphin or PCSX2. The main concern with such an UI would be how to make it work well when our minimum window size is 256x384. But such an interface could offer a way to set up per-game configuration, cheats and such, all which are kind of cumbersome to do with the current UI. Another possibility could be profiles: whether those would be emulator-wide or per-game, I don't know yet, but they could be a way to support loading different settings, different save files, and so on. We could even support custom screen layouts, stuff like rendering two melonDS instances within one window simulating split-screen multiplayer, etc... We could also try to implement Retroachievements in a nice way with such an interface, seeing as that feature is popular request. Many ideas, but it takes time to code any of this. So I don't know how far we'll get. Oh, and, the OpenGL renderer. I've been taking a break from that stuff, but I want to try to add filtering before the 1.2 release. Last thing I want to talk about: timings. I want to try to address the known timing issues in some way. The problem is mostly when CPU timings are involved. With things like cartridge transfer timings, it's generally not that hard once you understand the logic behind the timings, and model it decently accurately. CPU timings, on the other hand, are something else entirely: they rely on a lot of different factors. In the DS, you have the ARM9 caches, shared main RAM, various ways the ARM9 itself can save a few cycles here and there... Fully modelling the complexity of CPU timings would require cycle-accurate emulation. melonDS is not cycle-accurate, and was never built for that. However, Jakly is attempting cycle-accurate DS emulation in DualSOUP. I'm definitely interested to see whether cycle-accurate DS emulation can be achieved at playable speeds with current hardware, so I'm following this project with great interest. The melonDS approach so far is to figure out the underlying logic and try to get close - because if you don't understand that logic, then any attempts you make end up in a game of whack-a-mole. I remember trying to understand the logic behind ARM9 timings, but realizing the sheer complexity, and not really getting anywhere. However, one thing we can do is add in instruction cache emulation. There have been attempts at this and they seem to fix some issues, like for example the DSi Sound App. Why specifically the instruction cache? The ARM9 has two caches: an instruction cache and a data cache. The former is used when fetching program code, and the latter is used when accessing data in memory. Emulating the instruction cache is actually feasible with little to no performance loss, because instruction fetches are very predictable: they're sequential unless a branch is taken. Thus, it's possible to only check the cache upon cache line boundaries and branches, and assume that every other fetch is a cache hit. Emulating the data cache is worse for performance because data fetches are unpredictable, so every memory access needs to be checked against the cache. So I think this is worth considering for melonDS 1.2. That's about it for now. Have fun! |
| 18 comments have been posted. |
| < The DS cartridge interface: endless funChronicles of Timings: Tales of Destruction > |
| Pages:12 |
|
Neozekiel says: Mar 15th 2026 |
|
Thank you very much for your hard work ! I've been wanting to replay my childhood games and Melon has been a blessing for me. I hope your mental health keeps getting better, take time for yourself and take care :) |
|
IntriguingTiles says: Mar 21st 2026 |
|
> I'm even pondering what it would take to build a NAND from scratch I've built a tool that does just that, it's mostly straightforward: make a system update request, download and install each title, encrypt tickets, build filesystem partitions, and build the final NAND. Unfortunately, Nintendo's CDN lacks some components necessary for building a complete NAND, like stage2 and TWLFontTable.dat, but perhaps open replacements could be developed to solve this. See https://github.com/IntriguingTiles/dsi-nand-gen. |
|
Arisotura says: Mar 23rd 2026 |
|
thanks all for your replies! IntriguingTiles: yeah, I did look a bit at it in the past and came to a similar conclusion... stage2 could prolly be reimplemented. I don't know about the font file, sure we can make a replacement, but the file is signed... |
| Pages:12 |