melonDS RSS The latest news on melonDS. The local multiplayer saga, ep 3 -- by Arisotura Tue, 16 Aug 2022 10:20:30 +0000
However, there is still data loss in the client->host direction, which I need to investigate further.

So I've been doing exactly that. I'm not done yet, because the DS wifi is a rabbit hole, so many little details everywhere and especially in the local-multiplayer specific features.

If you have messed with wifi in melonDS before, you might have seen this message appear in the console:

wifi: !! unusual TXSLOT_CMD bits set C000

What is this about? The value for TXSLOT_CMD has two known parts. Bits 0-11 are the address of the CMD frame, and bit 15 tells whether the CMD slot is enabled. The rest is undocumented as of now.

In this situation, the game is setting bit 14, which prevents the hardware from automatically filling in the CMD frame's sequence number. This feature comes in handy if the host needs to retransmit a CMD frame for whatever reasons (for example, if some clients failed to respond). All in all, nothing too difficult to deal with.

Except implementing it in melonDS worsened the problem of client->host data loss in Pictochat. So I just ignored that feature, which made the transfers work nearly perfectly (albeit with some apparent lag). But you know our standards: that's not correct emulation, and also more likely to lead to other problems.

So I investigated the data flow. There are a few things of note in the Pictochat data flow:

* The host sends a CMD frame every 4 milliseconds. Each frame can be addressed to a maximum of 3 clients. Thus, the host needs 5 frames to poll every possible client. This is probably done to avoid monopolizing the wifi channel too much.

* The client, when receiving a CMD frame not addressed to it, will interact with the unknown hardware registers 0x244 and 0x228. Register 0x244, in this case, seems to be used to inhibit the transfer of a reply frame, which I'm not sure why they do it when no reply would be sent anyway. I don't know what register 0x228 does, I haven't observed any effects in my tests. Over all, this part doesn't seem very important.

* Most of the CMD frames the host sends are long frames, to which the clients respond with long replies. These are used to exchange messages being sent in the chat, for example. However, every once in a while, the host sends a short CMD frame, which clients normally respond with a short reply (heh). Except sometimes the client responds with a long reply instead. This seems to be the cause of the client->host comm hiccups.

While experimenting with MP replies, I (quite accidentally) found out that the hardware will refuse to send a reply frame that is too long: in this case, it behaves as if no reply frame was configured at all, and sends a default empty reply. How does it know if a given reply frame is too long? The CMD frame specifies the time window for replies, simply. It's then trivial to calculate the amount of time needed for a reply frame, based on the preamble settings, the transfer rate and the frame size.

This makes sense, and it's also a crucial detail in the situation above. When the host sends a short CMD frame, the reply time window is also short, so it definitely shouldn't be receiving a long reply.

I made a quick attempt at implementing this in melonDS, which gave imperfect but promising results. I need to implement it properly, which should hopefully solve our data loss issues.

If this does the job, what does that leave us with? There are a bunch of other fun details I found out (here), which are less important but still worth implementing. There are also some issues to iron out in the sync mechanism, and in the end I need to come up with faster IPC so this can run at acceptable speeds.

Stay tuned!]]>
The local multiplayer saga, ep 2 -- by Arisotura Fri, 05 Aug 2022 12:02:12 +0000
We assume here that you're familiar with local multiplayer terms. If you're not: read this.

I introduced a crude synchronization mechanism where the host of a local multiplayer game can instruct clients to stay in sync. When a client connects, the host sends its USCOUNTER (the wifi system's microsecond counter) value to that client, which can then compare that to its own USCOUNTER value: the point a connection is established is considered the reference point, and the client will then wait for the host to allow it to run, so it doesn't get too far ahead or behind.

Thus, the host can enforce sync (and also wait for clients to have caught up) before sending a CMD frame to its clients, thus ensuring that everybody is at the same point at that time. It can then send its CMD frame and allow clients to run ahead for a given amount of time that covers the entire MP exchange process.

The results aren't perfect, but they are somewhat promising.

For example, Pictochat doesn't seem to get stuck trying to send messages. I have only tested with two instances for now, but they seem to stay in sync fine.

However, there is still data loss in the client->host direction, which I need to investigate further.

I suspect there might be issues with ack frames being received too late. I intend to just fake them, to simplify things and reduce the amount of data being transferred. I made a quick attempt at that yesterday, but so far it's not working as intended.

It may also be caused by lacking emulation of the error handling processes in hardware (like automatically resending the CMD frame if some clients failed to respond, for example). I will have to do some more reverse-engineering to determine how that works in detail.

Also, the performance is currently less than optimal. For now I'm focused on getting the communication stable, so I will take care of optimizing later, but I have some ideas for this. Namely, BSD sockets are probably suboptimal for fast IPC. It would likely be faster to use shared memory, or even run multiple emulated DS's inside the same melonDS instance, although the latter would require a large restructuration of the melonDS codebase.

All in all, I'm hopeful we can pull it off.

I'm also going on vacation next week, so I'll have more time to work on it (provided my brain lets me, of course).]]>
Plans for local multiplayer -- by Arisotura Tue, 19 Jul 2022 11:42:07 +0000
Well, I tried looking into the DSi sound app, and found that it crashes due to a NULL access. I tried debugging that, but it seems to be some weird timing problem and I don't know why that crash doesn't happen on hardware. This will need further investigation.

Anyway, local multiplayer.

It's one of the big things to take care of, now. We have been mostly putting it aside over time, favoring various popular requests, quality of life improvements, and fixes to DSi emulation. But we can't keep pushing it away like that. We have decided that improved local multiplayer is a must-have for melonDS 1.0, and we aren't going to keep making 0.9.247 type releases forever.

(besides, 0.9.x releases aren't very pleasant, for the same reason why I don't like $29.99 type prices: 9 is brown)

Anyway, I brainstormed some ideas for reliable local multiplayer. I have already explained before why local multiplayer is so finicky to implement, but the basic story is that we can't just run two melonDS instances and have them hurl packets at eachother and pray that things will work out. You might already know that we keep telling people to disable the framerate limiter if trying local multiplayer, and that's linked to this too.

We need a smarter mechanism for synchronizing melonDS instances taking part in local multiplayer. I have some ideas in mind for this, but I have to see how well they will translate to reality. I'm concerned about the performance implications this could have.

If this is successful, there are other possible quality of life improvements that relate to local multiplayer. For example, how to deal with user input when multiple melonDS instances are running on the same machine? You might want them to have different input mappings, but how do we deal with that without making things too complicated?

The craziest thing to achieve would be netplay, akin to Citra. Well, of course, there is no chance local multiplayer could work over the internet, but there are probably ways around this; we can look into how popular emulators handle netplay.

Oh well, we'll see how this goes, I guess.]]>
Long time no news -- by Arisotura Sat, 28 May 2022 17:30:42 +0000
On my side, it's a mix of the usual, ADHD, depression, ... I realize I have mostly been pushing these issues aside, but ignoring them only works for so long, so I'm in the process of getting professional help.

I also started a new job a few weeks ago, so it takes a while to get into it and all. I hope this will work out, especially as my ADHD is getting in the way there too, and the earliest appointment I could get for a diagnosis is in February 2023.

Oh well.]]>
Opening your eyes to the world -- by Arisotura Sun, 17 Apr 2022 13:54:47 +0000
I was thinking of implementing things like SoundEx and microphone support, but Generic said he was going to implement that, so I'm letting him having fun there. Instead, I went for improving camera emulation. After all, cameras are the main thing DSi-exclusive games make use of, so DSi emulation with no camera support just feels incomplete.

melonDS 0.9.4 already has some very basic camera emulation, but it basically just does the bare minimum to pass the camera init sequence, and then returns a fixed stripe pattern (which is basically just the picture data register returning a fixed value). Nothing exciting.

For example, you can open the DSi camera app and get to the actual camera part of it, but trying to take a picture will result in a system error. Reason for this is that the camera can be set to output at multiple resolutions. It has two modes of operation, named 'preview' and 'capture', which makes sense in applications like digital cameras: preview mode would provide a low-res preview of what the camera sees, that can be displayed on a built-in screen, while capture mode would provide a full-res picture that can be saved. The DSi camera lets you configure two contexts, each with their output resolution, image format, and various other options (for example, flipping the picture...).

So I first had to add support for these modes of operation. I first implemented the registers necessary to handle the camera mode/context switch. But, of course this wasn't enough. The stub in place for picture transfer assumed a resolution of 256x192, but in this case, the resolution is changed to 640x480. This also means that the DSi camera app expects more picture data to come, and it will softlock if there isn't enough data incoming.

This is where my camera test homebrew came in handy. I modified it so that I could do things like switching between the front and back cameras, switch between preview and capture modes, and even use the picture cropping feature to view different areas of the picture in 640x480 mode (as obviously it wouldn't fit onscreen). Doing this let me get a good grasp on how these features were supposed to work.

Then I felt confident implementing all that into melonDS.

This is a preexisting still picture, not actual camera input. But regardless, we have working camera emulation now, and this is half the battle. The other half would be reading picture data from sources like an actual camera, feeding it into the emulator, and integrating all that into the UI.

Taking a picture in the DSi camera app also works, and thanks to the SD folder-sync system, I can easily retrieve the resulting picture. For example, the original file, and the resulting DSi picture.

There is also still a bunch of tidbits to take care of, as far as camera emulation goes. For example, all details and edge cases pertaining to the picture transfer hardware. It's tricky to work with, because from my understanding, picture data is transferred from the camera on a per-scanline basis, but the transfer hardware holds it in a buffer which is limited to 512 words, and it has no idea what resolution the picture is. It just knows to trigger a DMA transfer every N scanlines (N being configured in CAM_CNT), but if these N scanlines amount to more data than the buffer can hold, you're going to get blank lines in your picture.

The DSi cameras themselves also have a looooot of low-level details, many of which don't matter in the case of melonDS. It's like for the DS wifi hardware: we have to deal with these things to some extent because we're doing low-level emulation, and the games/apps we emulate run on the bare metal, but a lot of it isn't useful to our emulator, and in most/all cases a lot of it is initialized to some generic settings and never touched again.

But hey, this looks like a pretty good start. If you're interested, you can check it out in the camera_betterer branch, atleast until we merge it.]]>
melonDS has been acquired by Meta -- by Arisotura Fri, 01 Apr 2022 21:53:41 +0000 EDIT - this post is an April Fools joke (in case that wasn't obvious)

A while ago we had an... unusual visit at the melonDS HQ: Mark Zuckerberg, no less. Zuck stated that he had always been a great fan of emulation, and that he loved our project greatly.

He offered us $324 million for the melonDS company, including both the HQ and the Melon Factory of Kuribo64.

An offer we could hardly refuse. Zuck is a very cool guy, and we greatly enjoyed the time spent in his company at the HQ. Plus, he's good at karaoke, so that will definitely make for some fun nights!

On more practical terms: this means lots of new exciting developments for melonDS.

For example, one of the new ideas is selling NFTs of the best melonDS screenshots. That is an obvious one, but not the only one at all.

There are also many possibilities opened by Metaverse integration: melonDS could be made compatible with game cartridges you would buy in the Metaverse, and you would then get to enjoy your favorite DS classics in VR. Who wouldn't love that?

melonDS will also become smarter, for an enhanced user experience. We are thinking about keeping a database of games, so melonDS can detect which game it is running, and offer ads related to that game. That is a start, but with AI we might be able to take this even further and offer the most relevant ads an emulator has ever offered.

Harnessing the power of a cloud could let us determine for you what the best emulator settings are, so you never ever have to mess with settings again.

There are many more ideas, which you will discover as we progress throughout this. We also have new fresh ideas for this website. Like, seriously, Kuriblog? Acmlmboard? Come on, this is 2022. We need some damn modern, Javascript-powered software, like Discourse for example.

This is going to be a goddamn revolution.

I am going to remain in charge of melonDS, but we will be under Zuck's direction. You will hear more from him soon. Stay tuned!]]>
melonDS 0.9.4 is out! -- by Arisotura Tue, 08 Mar 2022 12:26:58 +0000
It has been numbered this way because 1.0 is going to be a milestone release: we want to get local multiplayer stable for 1.0.

Anyway, what's new in melonDS 0.9.4? A bunch of improvements that should make things easier for the average end user.

Most notably, in DS mode, melonDS no longer requires you to obtain BIOS/firmware files. You can always supply these if you have them around, for a more accurate experience, but if you don't, melonDS will default to using DraStic's FreeBIOS clones. Similarly, a barebones firmware with default configuration data will be generated.

However, for now, DSi mode still requires you to provide BIOS/firmware/NAND dumps. We are studying ways to get around this requirement, but it's going to take us some work.

There is also a new dialog for firmware settings, which allows you to override the firmware settings with your own. This is intended for when using the default internal firmware, but it can also override the settings in an external firmware, and it even works in DSi mode.

DLDI support has also been upgraded: it is now possible to have melonDS generate a SD image for DLDI on its own, and it is also possible to have said SD image synced to a folder on your computer. This means that you can place files in that folder and they will show up in the emulated DLDI SD card, and conversely, any changes made to the emulated SD card will be reflected to the folder on your hard drive.

While this has been tested extensively, we still recommend that you keep a backup of any folder you intend to use with this, just in case. You can also set your DLDI SD card to be read-only if you don't need it to be writable.

All of this is also supported for the DSi SD card in DSi mode.

Support for ARM9 PU exceptions in interpreter mode has been added. For commercial games, this doesn't mean a lot, other than making certain crashes work like on hardware. But this may definitely come in handy for homebrew developers, as that means exception handlers will work as they should.

We have added a much requested feature: custom paths for saves, savestates and cheat files. The default behavior is that melonDS will place these files alongside your ROMs as it has always done, but you can specify paths where you want these files to be placed if you don't want them to pollute your ROM directory.

In the same vein, the File menu has been revamped to hopefully make the process of loading ROMs more intuitive. This post already talks about it in detail, so read it if you have any doubts.

Generic has been working on properly supporting wifi power saving. This is probably not perfect yet, but it should fix the weird issues you can encounter in Pokémon games when communications are enabled.

We also have some new fun features: Github user 2jun0 made a RAM search dialog, which may come in handy to those who want to make cheat codes. Rayyan also made a new dialog for changing the emulated battery level, which may come in handy to homebrew developers and such, and he's been remaking the input config dialog to be all fancy.

And, as usual, there's a bunch of little fixes and additions we aren't covering here, but you can find them all in this release's changelog on the downloads page (or on Github).


melonDS 0.9.4, Windows x64
melonDS 0.9.4, Linux x64
melonDS 0.9.4, Linux ARM64
melonDS 0.9.4, macOS x64
melonDS 0.9.4, macOS ARM64
melonDS 0.9.4, macOS universal]]>
Server move complete! -- by Arisotura Thu, 13 Jan 2022 17:21:37 +0000
Everything seems to be working smoothly now, but let us know asap if anything goes wrong.

There are also some further changes planned, like setting up HTTPS.]]>
Custom path support has been merged -- by Arisotura Sun, 09 Jan 2022 19:07:22 +0000
This also comes with some extra features. For comparison, the File menu in melonDS 0.9.3, and the new File menu:

First of all, the 'Open ROM inside archive' option has been merged with 'Open ROM', to declutter the menu and make things more intuitive. The file picker dialog just lets you pick either a ROM file or an archive, and in the latter case, it asks you which file you want to open from the archive.

When opening a ROM from an archive, the recent ROM menu remembers the archive file but also which ROM you picked inside it. Similarly, you can now pass a ROM inside an archive to the command line, like so:

melonDS path/to/|dupermario.nds

As I wanted to make the GBA ROM/addon feature more obvious, it has been decoupled from the regular 'Open ROM' feature. Previously, you had to open your GBA ROM before opening your NDS ROM, but it wasn't obvious at all that the feature existed or how it worked. Now, the separate menus should make this more obvious.

The way DS ROMs are handled has been revamped in a similar fashion. Basically:

* 'Open ROM' loads a DS ROM and starts running it, resetting emulation if another ROM was loaded previously, basically retaining its existing behavior.

* Under the DS slot section, 'Insert cart' will load a DS ROM, and that's it. Just like inserting a cartridge in a DS. The current cart, if any, will be ejected prior. This makes it possible to hotswap carts while running a game or the DS/DSi menu. Similarly, you guess what 'Eject cart' is for.

* The GBA slot section works in much the same way. You can choose to either insert a ROM cart, mimicking the presence of a GBA game cart for the DS games that can sense that, or insert an add-on cart, like for example the memory expansion cart which the DS browser uses. Note that melonDS does not support running GBA games.

* Resetting emulation does not reload the currently loaded carts (as you would probably expect, but it did that before). Stopping emulation keeps the carts inserted, until they're ejected or something else is loaded.

That should be it for the differences in functionality.

Other than that, a lot of the old ROM handling code has been bulldozed, resulting in code that is much cleaner and easier to deal with. Means nothing for the end user, but it makes life easier for us as well as anyone who wants to port melonDS.

Anyway, we encourage you to provide feedback about these changes! I want the UI to be feature-rich without being too galaxy-brain or unintuitive, and that is challenging at times.]]>
The path to success -- by Arisotura Wed, 22 Dec 2021 15:55:53 +0000
[path settings dialog in the making]

This is what I'm currently working on. It's been a popular request for a while: customizable paths for things like save files, savestates, ... As of now, melonDS takes the easy route and dumps these files alongside the current ROM, but not everybody wants that.

And, well, implementing this whole thing raises a bunch of issues. This is also why it can be difficult for me to get things done: I will try to envision the scope of the task at hand, then begin seeing related things that need to be done, more or less drifting away from the original task, and at the end I have too many ideas and I don't know where to start.

This is one of these occurences. I had tried to make plans of what I wanted for the custom paths feature, but, surprise, the actual implementation is going to be different. The state of the melonDS codebase doesn't help, either, sometimes. I mean, it certainly could be worse, but some parts could definitely use a refactor.

ROM loading is a prime example. When I first built the melonDS core, it was pretty simple, and all it had to do was load a ROM from a given file, load the associated save file, and start emulating. So the original NDSCart::LoadROM() function did just that.

Of course, as melonDS evolved, other concerns arose.

For example, archive support was added. In this case, the ROM isn't accessible as a regular file, instead we get a memory buffer with the ROM's contents. So this means a second NDSCart::LoadROM() function was added, that loads a ROM from a memory buffer. A tad redundant.

Another fun thing is DSi support. On the DS, you can't hotswap cartridges, because there's no hardware support for it, so we didn't have to account for this possibility. However, things are different with the DSi: for example, you can insert and eject carts while in the DSi menu and it detects that. So it's something we need to take in account too. And as of now, melonDS has no provision for ejecting the current cart, nor for loading a new cart without resetting emulation.

And other fun assorted details. Basically, the ROM loading system is due for some refactoring, and I'm working on it. Then, once all this is sorted out, I guess I can actually implement custom paths.

The melonDS team wishes you a merry Christmas and a happy new year and all!]]>