|Home | Downloads | Screenshots | Forums | Source code | RSS|
DS emulator, sorta
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, ...)
• RTC, microphone, lid close/open
• Joystick support
• Various display position/sizing/rotation modes
• (WIP) Wifi: local multiplayer, online connectivity
• and more are planned!
If you're running into trouble: Howto/FAQ
If you're feeling generous: melonDS Patreon
melonDS status, and plans for the future
Jun 2nd 2018, by Arisotura
I figured I would write this, to give you an idea of melonDS's current status, what has been done and what remains to do.
To reply to the comments on the previous post: melonDS is already open-source, and it has always been. You will find the source code on Github. You can do whatever you want with it, as long as you are respecting the GPL.
So, here's a quick list of how things are and what needs to be done, from the top of my head. Searching the codebase for TODO/FIXME/HACK will find all the items.
All the instructions supported by the ARM7 and ARM9 are implemented.
ARM9-only instructions are enforced, altough this may be incomplete. It's unclear how some of them behave on the ARM7: some throw undefined instruction exceptions, but some seem to do nothing or behave like another instruction.
Cycle counting is rather crude and likely to be wrong for the more complex ARM9. Speaking of, the MPU and cache still have to be implemented (hopefully without killing performance). The first would allow emulating some game/homebrew crashes that happen on hardware, the second would be a requirement for reasonably accurate timings.
All DMA types are implemented, with reasonably accurate timings and operation. Running DMA and ARM9 simultaneously (possible under specific conditions) isn't implemented.
Timers might need checking/rework?
Memory map is accurate, including things like overlapping VRAM banks.
ROM/SPI transfers are emulated with proper delays, and should function like their hardware counterparts, minus some uncovered details (see all-caps printf() calls).
ARM9-side div/sqrt are emulated with delays.
All features are implemented. Even the rarely used 'main memory display FIFO'.
OBJ mosaic may be wrong, especially with rotated/scaled sprites.
DISPCNT latching is missing. Other registers may be latched, that hasn't been researched much yet.
VRAM access timings aren't implemented.
Most features are implemented.
The geometry engine is emulated mostly accurately. Polygon/vertex limits are enforced. Culling and clipping haven't been researched closely and may produce results different from hardware.
GXFIFO overflow isn't implemented properly (should incur penalty for ARM9 and presumably ARM7).
Misc things like effects of invalid operations (incomplete polygons etc) may not be implemented.
The rendering engine is emulated with much more accuracy than needed for your average game. Much research went into figuring out how the rasterizer works. melonDS is not pixel-perfect but close. Pointless besides for passing aging cart tests.
Antialiasing over shadow pixels is glitched.
The scanline cache is not emulated (requires figuring out rasterizer timings, including VRAM access and all).
Capture addition and source selection are missing (have yet to find something that uses them).
Other than that, the mixer is complete and emulated with sample accuracy.
Memory access timing isn't emulated, however buffering mechanisms (FIFO) are implemented.
Much of wifi still has to be researched.
The current implementation allows some form of local multiplayer (and connecting to the internet with proper support), but communication errors aren't properly reported, which results in bad things. So far my attempts at fixing that only made things worse.
Wifi is subpar compared to the rest of the emulator :P
With that in mind, where do we go next?
I'm not sure about attempting to continue the JIT. Considering I went for accuracy, preserving it at a reasonable level with a JIT is going to prove tricky, even moreso when you're emulating two simultaneous CPUs and a bunch of extra hardware. Make it too accurate and the synchronization overhead negates any speed benefits from the JIT, but going too far in the other direction will inevitably break games.
DSi emulation is another of the possible avenues. There's not a lot of DSiware to play, and even less cartridge games, but regardless, there are things to be done there.
Or I might go and emulate something entirely new for me? N64? Dreamcast? Xbox?
|11 comments (last by Casgaro) | Post a comment|
May 13th 2018, by Arisotura
You probably have noticed it, things are going down.
It's been 5 months since the last release.
What do we have that would be worthy of a 0.7?
The JIT? I started working on it, and... lost motivation.
DLDI? Same story. I hackishly added some commands so it can access a FAT image, and lost motivation to take it any further. For example, accessing the actual host filesystem instead of having to use an image file.
I have pretty much lost motivation. The context I find myself in these days doesn't help, either. I'm mostly just... bouncing between places and having trouble getting really settled.
So for now, melonDS is on hiatus.
I feel bad for those who are still donating to the project. If you are, well... do whatever you want, but consider that melonDS isn't going to see progress for a good while, if not ever.
|20 comments (last by poudink) | Post a comment|
Long time no see
Apr 25th 2018, by Arisotura
Things have been pretty busy real life wise. Apologies for the lack of updates regarding melonDS.
You might know how things went lately. I started coding a JIT recompiler for melonDS, then... lost motivation. Oh well.
Instead, I figured I would work on other things. Like, y'know, homebrew. melonDS runs commercial games all neatly and all, but its homebrew support is still subpar.
For one, DLDI support is one of the things I intend to work on. And not just granting filesystem access to homebrew, but actually attempting to emulate one of those flashcarts. It'd be amusing if melonDS could run a flashcart firmware. Not very practical or useful when you can load your ROM directly, but it'd be a cool feat. Besides, it's something the DS can do, so melonDS should also be able to do it.
Even that aside, there are some technically challenging homebrew games. A prime example would be Dirbaio's Fireworlds which pushes the system to its limits (and is also a cool game, try it).
Dirbaio recently put together a NitroFS build of Fireworlds, so that it can run on emulators that don't support DLDI. To give you an idea:
• NO$GBA: crashes after intro
• DeSmuME: runs okay, but no music (console complains about zero-length channels, likely related)
• medusa: crashes when loading level select menu
• dasShiny: gets stuck on NitroFS init
A quick test revealed that it didn't run on melonDS, but it was a rather silly issue (it tried accessing IPCSYNC via 32-bit reads/writes, which melonDS didn't handle). Dirbaio fixed it in a PR, which means Fireworlds finally runs... but not perfectly, heh.
Fireworlds seems to do some weird partial rendering to reduce the 3D engine load (noting that the most extreme levels do cause lagging-3D-engine glitches on the DS), and using display capture to mix together all the parts, or something like that. But it doesn't work right on melonDS and results in some flickering.
So there's atleast that to fix. That aside, the game seems to run quite well. But hey, it's nice to have technically interesting homebrew like this.
Fun side fact: Fireworlds has code to detect emulators, and it doesn't detect melonDS or medusa :)
Soo... there we go!
|7 comments (last by its_notjack) | Post a comment|
Network support: in the works
Jan 24th 2018, by Arisotura
You might have seen this thread.
Network support was achieved, but it was roughly equivalent to that of DeSmuME.
Currently, the network interface used by libpcap is hardcoded, I haven't added a UI for this yet.
There is also a disadvantage to this: it only works if your computer is connected via ethernet. It also requires promiscuous mode, which might be a problem in some situations.
I am working on a workaround to this, that allows networking without promiscuous mode. It will have to be tested extensively, but so far I got promising results.
|18 comments (last by not_A_staple) | Post a comment|
Jan 16th 2018, by Arisotura
What an original title.
Regardless, it's the case again. Real life is... still a bitch.
I need to change my phone plan, because while it was fine when I mostly used home internet, it sucks big time for more nomad uses. It's one of those plans that completely block internet access once you reach the data cap. So I'm going to switch to a plan with more data and that throttles speed instead of outright blocking. But in the meantime, I'm having trouble getting internet access.
As far as melonDS is concerned, I'm not quite sure what to try.
I have been trying to address the wifi stability issues, without much success. I have been doing a bunch of research on the multiplay communication thing and how it handles errors, thinking that properly handling those would make for a more stable connection (as opposed to always reporting success even when some data didn't make it through).
But so far, it has largely been a failure. At best, my attempts fixed nothing, and they generally made things worse.
I don't understand what it's expecting, so for now I'm putting this on the back burner.
Upscaling is a possibility, but as explained in a previous post, it's not all easy and nice. It'll also require writing a hardware renderer first, which could be a fun challenge.
There are quite a few tricks we can pull with modern OpenGL to emulate the DS GPU as accurately as possible. Obviously it would never get perfect, but we can get close.
Savestates are another avenue. Nothing really interesting though, it's mostly matters of properly saving and restoring all the emulator state. But it'd be one of the 'popular request' items.
In the less 'popular request' zone, what do we have? Bluetooth keyboard support for that Pokémon typing game. It'd be a fun little RE project, but it would only end up benefitting one game. Kind of an emulation white whale.
|14 comments (last by hyarsan / Flooder) | Post a comment|
Dec 16th 2017, by Arisotura
As promised, the quick fix release is out. There are a few other goodies too.
|9 comments (last by BlookyDJ) | Post a comment|
Dec 8th 2017, by Arisotura
I just realized that there are some bugs with the menu options pertaining to screen layout/etc, esp with how the checkmarks are initially placed. There will be a quick fix release to address this.
|3 comments (last by Rin Tohsaka) | Post a comment|
Dec 7th 2017, by Arisotura
I'm lazy, and there are little visual changes, so I will reuse those screenshots.
So what's new in melonDS 0.6? Little emulation wise, a bit more UI wise.
First of all, I want to thank the artists who have been (and are still) drawing all sorts of rad icons for melonDS. For 0.7, I will pick the one I like the best (and it won't be easy, heh). Thing is, I want to put the icon in the melonDS windows, and I will need to add support to libui. Which also means embedding the icons in some portable format, because each OS does its own thing when it comes to window icons.
Emulation wise, the big thing is the sound fix I talked about in a previous blog post. I already went in detail over this, but, long story short, surround works now. And sound emulation is more accurate, that can only be good.
There. The rest is meaningless shenanigans.
UI wise, you get fancy display modes now. Those were also discussed in a previous blog post, so no big surprise there.
The only thing that was added is a toggle for linear filtering, for those who like pixels.
The rest is, well, little bug fixes. Under Windows, you can now load ROMs with non-ASCII characters in their paths. As a side note, under Linux and OSX, fopen() can take UTF8 paths, but Windows requires a separate codepath because herpderp. fopen() can only take ASCII, for anything outside of that you need to use the Windows-only _wfopen() which takes wide-char strings. In the end, the code is a bit ugly, but it works.
That's about it for this release. But stay tuned, 0.7 should bring in some Christmas fun.
|8 comments (last by Soralis) | Post a comment|
Another of those long-due fixes
Nov 11th 2017, by Arisotura
The sound core is fixed, or mostly.
If you've been playing with melonDS, you may have noticed that effects like surround generally didn't work, and that whenever they worked, they resulted in crappy sound. Resetting or loading different games would also give different results.
So I've been addressing all that junk.
The randomness was easily fixed -- the write position for capture units wasn't being reset properly, so whenever the capture unit was started, it would start writing wherever it was previously left. Not really a good thing.
The rest was trickier though.
The DS sound controller provides 16 channels that can play a few types of audio, and 2 capture units that can capture sound output and write it to memory.
Several games provide different audio modes, typically headphones/stereo/surround. In those games, the audio output isn't directly sent to the speakers, but it is sent to the capture units. The game then alters it as it wishes, and two special channels (1 and 3) are used to send the final output to the speakers.
The mechanism is generally used for the aforementioned audio modes, but some games take it further -- Golden Sun: Dark Dawn goes as far as using it to play its sound effects.
While the mechanism (which we will name "surround setup") may sound simple, getting it to work is actually tricky.
It has been known for a while why it didn't work in melonDS: capture and channel 1/3 playback were done in the wrong order. However, putting them in the right order resulted in distorted, tinny sound. So I just kept it in the wrong order and ignored it.
When you start a sound channel on the DS, it doesn't start playing immediately, there is a delay of a few samples. However, capture units start immediately.
The surround setup starts the capture units and their associated output channels at the same time, and gives them the same memory address. The idea is that, since channels are processed before capture units, the output channel reads sound data before the capture unit writes new data, and the distance is the largest possible, as to give the game enough time to apply effects to it.
However, the channel starts with a delay, which means it's lagging behind a little. In the case of melonDS, as the mixer processed 16 samples per run, the output channels would get bits of freshly captured data mixed in with the older data as a result of this. You guess how this goes.
Reducing the number of samples per run to 2 or 1 got rid of the audio distortion, but surround didn't work at all since the channels would only get freshly captured data.
Removing the channel start delay fixed the problem, but obviously it's not proper emulation.
The killer detail is that when the sound controller needs to access memory, it doesn't do so directly, but uses a buffering mechanism (FIFO) for each channel and capture unit. GBAtek mentions their existence, but... that's all.
The FIFOs need to be emulated for surround to work properly.
Which means that I had to do hardware tests to figure out how it works. There are probably still missing details.
Channel FIFOs can hold 8 words (32 bytes) of data. They are filled in chunks of 4 words when needed. An interesting detail is that when starting a channel, two chunks are buffered. Then it seems that a new chunk is buffered every time the FIFO runs less than half full.
Capture unit FIFOs are simple write buffers that hold 4 words. They are flushed to memory either when they're full of when the end of the capture length is reached (regardless of whether the capture loops).
So after implementing the whole FIFO thing, we can finally say that a bunch of sound issues are fixed! Surround works, sound effects in Golden Sun: Dark Dawn work too, some crackling that appeared in Rayman RR2 is gone, etc...
|16 comments (last by swagmaster6969696969) | Post a comment|
How far we have gone, and where we are going next
Nov 9th 2017, by Arisotura
melonDS has been going for one year now.
Well, the repo was opened in May 2016, but the real work started in November 2016.
I didn't really know what I was in for, but hey, I wanted to have fun making something new. There wasn't much else in terms of goals, other than the famous goal of successfully emulating local wifi.
Of course, getting an emulator project going is initally a gruelling task, as it takes quite a bit of work before you can get interesting results. In the case of the DS, as I went with the goal of emulating the BIOS boot procedure, there was quite a lot to be done before the firmware would try to display things. In the case of melonDS, it took about 2.5 months to get there, but I don't consider it a good idea to look at durations. I was unemployed at the time (or rather, waiting to start that job), I'm a lazy fuck, and a couple vicious CPU bugs got in the way.
The first release of melonDS was a mere curiosity. It was inferior to the existing emulators. But that didn't matter, it was out there for the curious, and I was having fun with that project. The next releases would deliver quality.
The 3D renderer was my first attempt at a polygon rasterizer. I initially fumbled getting things like perspective correction working, but gradually gained more understanding of the process. Conducted tests to try understanding how the actual GPU did things and which shortcuts it took. And it has been an interesting ride.
I guess it turned out okay. This renderer has become the most accurate among all DS emulators. I thought, since the 2D renderer is going to be pixel-perfect, why not make 3D pixel-perfect too? I'm not there yet though, but the renderer is more than good enough for most games. Not good enough for the aging cart tests (which demand perfection to the pixel), but I put that on hold for a while.
On the other hand, the renderer code evolved as I discovered things, and is probably not as clean as it could be. In long term, it could benefit from a rewrite.
And this shit has been going on for one year now. Time flies, it's crazy.
melonDS became something serious. Not only does it have a pretty solid emulator core, it even does things no other emulator does. Be it very niche things like properly emulating the mainmem display FIFO, or emulating enough of the wifi system for local multiplayer to be possible.
Of course, it's not perfect.
Local wifi suffers from data loss every now and then, and some games just refuse to connect at all.
CPU timings are still grossly inaccurate. It's a shitty zone, especially on the ARM9, where the caches can affect performance radically. There are basically two unappealing choices: emulating the whole MPU/cache system (you can figure the impact on emulator performance), or guessing the timings in a grossly inaccurate fashion.
Sound has its lot of issues too, and I have yet to figure those out. Surround modes don't work well, when they work at all (generally they don't work). There are a couple issues with sound quality, one coming from bad emulation and one coming from the fact that the frontend doesn't do any resampling -- it picks the output frequency the closest to the core's sampling rate, and hopes things will go right. And, in the DS, sound mixing and sampling is driven by the system clock, which results in a non-integer output frequency.
And, most notably, the UI is still pretty lacking in functionality. I intend to keep melonDS lightweight and straightforward, but regardless, some features can't hurt. This is being worked on since 0.5, but at a slow-ish pace.
Real life has caught up to me. I had a job, but it ended two months ago, and I need to find something else. There are also other projects I've been rather busy into, lowering the amount of time I spend on the internet.
And... things I recently discovered about myself. Actions I want to take in that regard, but nothing is going to be easy.
So, even if the pace has slowed down, melonDS isn't dying.
Here's a glimpse of what's being worked on:
Rotation, for that occasional game that asks you to hold your DS sideways.
But there are also fancy screen dispositions:
• Natural: screens are arranged as they are on a DS.
• Vertical: screens are stacked on top of eachother (regardless of rotation).
• Horizontal: screens are placed next to eachother, top screen first.
Different sizing modes are provided too:
• Even: the screens are given the same size.
• Emphasize top: the bottom screen is kept at native resolution, the top screen is given all the remaining space.
• Emphasize bottom: vice-versa.
• Auto: emphasizes the screen which receives 3D graphics (typically the most important one), works well in NSMB for example. If 3D is displayed on both screens, behaves the same as Even.
There are still details to iron out, but so far those display settings are working rather well, and I like how they turned out.
Later on (probably after 0.6 at this rate), I want to work on non-local wifi, and some other things. For example, emulating the DS browser in melonDS and getting it to browse this site would be a cool feat. Can't tell how well it would do these days though, that browser was already subpar when it was released :P
There is also that Pokémon cart, which interests me. There are not a whole lot of players waiting to play that game, I guess, but it's interesting from a technical standpoint. The cart contains a Broadcom controller that seems to be quite capable, atleast enough to replace typical backup memory entirely. I just received a DS cart slot, so I'll be able to mess with it.
I am also very interested in that GBA-slot camera addon, but it's elusive as fuck. There is one game that comes with it (supposedly another game is compatible, but when I ordered that game, I received it without a camera), but when I search for it, all I can find is the DSi version. I need the DS version, the DSi version uses the DSi's builtin camera and thus doesn't come with the camera addon.
So, if you happen to have that camera addon, or know where I can get one... I am very interested.
Upscaling would be another thing to work on, according to popular demand.
This will need a new renderer, likely using OpenGL or a separate well-optimized software renderer. This is a bit of an issue.
On one hand, the current 3D renderer is meant to be accurate, and by that, I mean replicating the hardware's low-level behavior. The GPU is pretty much tailored for the DS, so I'm not positive that such a renderer can be made to render at higher resolutions and give good results. Not to mention the speed impact from that: rendering at 2x IR requires filling 4 times more pixels, and so on. The growth of performance requirement is quadratic.
Besides, people who want upscaling will generally want improved graphics. Texture filtering and maybe texture upscaling, for example. Or actual antialiasing (as opposed to the faked edge antialiasing the DS does). Which the current renderer will not support, because the DS doesn't do that.
It would make sense to implement these improvements in a hardware renderer. And also be less costy.
However, don't forget that the DS GPU is quirky. Some things would be difficult, or even impossible, to emulate correctly with OpenGL. One of them is how the DS keeps track of polygon IDs per pixel, but does so separately for opaque and translucent pixels. Those affect rendering of translucent and shadow polygons, and edge marking. Replicating the whole behavior in OpenGL would require a 16-bit stencil buffer, which is way atypical. Or maybe some cool trickery.
Which reminds me of blargSNES and its hardware renderer. While all the trickery we had pulled to render SNES graphics on the 3DS GPU was definitely cool, it took its toll on performance.
Sure, the average computer GPU is ways more powerful than the 3DS, but... yeah.
There is also the bit where the DS happily mixes 2D and 3D.
Old consoles featured 2D tile engines. Newer consoles feature 3D GPUs. The DS is inbetween, and... features both. A unique situation.
Situation which gives us the following problem: if we upscale 3D graphics, what should we do to 2D graphics?
And the answer pretty much depends on what the game draws. Something like NSMB could use a xBR filter, for example. But these filters don't work well on more complex graphics.
There is also the whole issue that the 2D renderer in melonDS is scanline-based. I have a good idea to implement upscaling in a non-intrusive way, but it will be an issue as far as filters are concerned. The 2D layers are added to the final framebuffer as they're rendered (rendering them separately would be slower). So, while the 3D layer is rendered separately and can have shit done to it, this doesn't apply to the 2D layers.
So most likely the 2D layers would just not be filtered at all.
Which reminds me of display capture, which allows to write rendered graphics to VRAM. Captured images have to be at the internal resolution. Those can also be modified by software before being displayed.
Which is less than ideal. For example, display capture can be used to display 3D graphics on both screens. While one screen will be rendering a 3D frame, the other will be rendering a captured version of its previous frame. The captured 3D frame is already degraded from 18-bit color to 15-bit due to how the hardware works. Throw upscaling in the mix and the captured 3D frame ends up being a downscaled version of the upscaled 3D frame, which would be re-upscaled with no filtering as it's displayed by the 2D engine. The quality loss would likely be visible and result in some bad flickering.
There would be ways to get around it, but it's neither trivial nor error-proof (see above-- the captured frame can very well be modified by software. There are also several ways a captured frame can be displayed, some games use large sprites).
The best solution in this kind of situation would be to disable upscaling entirely.
Oh well. Time will tell where this goes.
|14 comments (last by hello) | Post a comment|