DSx86 is a PC emulator for Nintendo DS. It’s purpose is to allow you to run old DOS games on your Nintendo DS game console.
This is mostly a fix version after the somewhat buggy version 0.20. This version includes the finished AdLib emulation, and I fixed the problem introduced in 0.20 with the Direct SB mode where the start of the BIOS F000 segment was overwritten with corrupt data. This version also has a lot more of the opcodes refactored to use the new more robust memory handling, which also means that this version will run slower than the previous version. Norton SysInfo tells that this version runs at 9.9 times original PC, while the version before any of these internal changes ran at 11.5 times original PC. I am still not even half way done with the internal refactoring, so the next version might still be slower, until I get all the refactoring done and can again start optimizing things.
I spent about half my time working on the internal refactoring, and the other half with debugging and testing programs that behaved badly in the previous version. Here is a list of the specific programs I tested and the changes they required, where applicable.
Adventures of Robin Hood needed a better Stack Pointer handling.
Silpheed needed refactored string opcodes, which are now mostly done. The common REP MOVS and REP STOS variants now use the new improved memory access handling, while the less common REP SCAS and REP CMPS, and the really rare REP INS and REP OUTS still use the old method. I also fixed a problem in the internal debugger and a rather nasty bug in the port input emulation that could crash DSx86 completely, both of which happened with Silpheed. It should now run pretty much perfectly, including the complete intro.
SimAnt also needed the refactored string opcodes, but this time for EMS memory handling. I have only played the tutorial game for a little while, but it runs at least that far without problems.
Catacomb gave an “Unsupported INT” call whenever a key was pressed. This was caused by it calling the original BIOS INT9 handler without pushing the flags, so when the INT9 call returned it popped flags from a location in stack that could contain whatever data. The data it popped happened to contain 1 in the bit that went into the CPU Trap Flag. So, the next opcode caused a CPU single step trap, which then caused an unsupported INT call when there was no handler for the single step interrupt. I fixed this problem by turning the Trap Flag back off and ignoring the Single Step interrupt when no handler is present.
Castle Master had stopped working in version 0.15. This was due to my improved Vertical Blank handling. I am still not quite sure why my swapping the Vertical Blank bit hanged Castle Master, but in any case I adjusted the Vertical Blank bit reporting once more. Now it reports Vertical Blank during DS hardware screen scanlines 128..191 (just before the real vertical blank interval). This seemed to still keep the horizontal smooth scrolling in Supaplex, but also allowed Castle Master to run. This fix should also help with the slow palette animation in History Line, and possibly other games.
F29 Retaliator needed quite a few JPE and JPO opcode hacks. It used those opcodes (which are not natively supported by DSx86, so I need to add game-specific code for each game that uses those opcodes) in several locations in the code, so I am still not sure I found and added them all. The game does get in-game fine now, though. Please send me debug logs if you get this game to drop into a debugger with “Unsupported opcode”.
Operation Wolf had an unsupported EGA opcode in the demo game. I refactored this opcode to use the new memory handling, and the demo game seemed to perform fine. I couldn’t figure out how to start the actual game, though, so I’m not sure if this game works properly yet.
Super Solvers: Challenge of the Ancient Empires! also had a problem with it needing a JPO opcode. I added support for this opcode at the start of the “India & China” part of the game, but haven’t tested whether the problems in other parts were fixed by this also. Please send me a debug log if you still get opcode errors in this game.
Windows 3.0. This is perhaps the biggest new application that runs in this version. I had seen a YouTube video of someone testing Windows 3.0 on DSx86, and it seemed to report that “DOS version 3.1 or newer is required”, which did not make much sense when DSx86 reports DOS 5.00 by default. So, I decided to install my old Windows 3.00a floppy disks in DOSBox and see what is going on with it in DSx86. Here is a list of the things I needed to fix to make Windows 3.0 run.
After Windows queried the DOS version (5.00) it proceeded to scan the low memory for a string “CON”. When found, it looked for the three next occurences of this string in memory, and reported “Incorrect DOS version” if all three of these occurences were not at equal distance from each other. A rather peculiar check for a DOS version… Anyways, it found the text “CON” in the System File Table in DSx86, for stdin file handle, and also another instance in the table for stdout, but it didn’t find a third instance, as there was none in DSx86. Well, normally there should be three instances, stdin, stdout and stderr, so I added the missing “CON” file into the System File Table, and Windows 3.0 progressed further.
The next problem was that it ran into a protected-mode opcode, which is not supported in DSx86 as it only emulates a 80186 processor. I tried to start Windows with “WIN /r” command, to force it to go into Real Mode, but that did not help, it still attempted to use the protected mode opcode. I then debugged the code before this opcode, and noticed that Windows 3.0 detects the CPU type it is running on by first shifting a register value 32 bits left. The old 8088/8086 processors did not mask the shift count, so when shifting a 16-bit register 32 bits, the result is always zero. Processors from 80186 onwards mask the shift count to 5 bits, so shifting by 32 bits is the same as shifting by 0 bits, so the original value of the registers stays intact. This was OK in DSx86, the register value stayed intact, so Windows 3.0 noticed it was not running on 8088/8086 processor. Next Windows 3.0 pushed the stack pointer, and checked whether the pushed value was the original stack pointer value. This is where DSx86 did not work as it should. My Turbo Assembler 3.0 Reference Guide states that 8086 pushed the decremented value, while processors from 80286 and up push the original value. It does not mention 80186 processor at all, so I had assumed it works like 80286. Now I found out that 80186 has the same bug as the 8086 processor, it pushes the already decremented value. I changed this, and got Windows 3.0 to load up fine. Hopefully this change does not break any games that might try to detect the processor type and want a 286 or newer processor.
Next I tried to make Windows 3.0 detect a mouse, but it looked like any other options besides PS/2 mouse makes Windows 3.0 go thru the serial ports and try to forcibly detect the mouse type connected to the serial port. So, I decided to look into finally emulating a PS/2 mouse as well. DOSBox was again quite a good reference for this, so after a few tries I got the PS/2 mouse emulation working. I haven’t tested this in any other software besides Windows 3.0, so it might not work properly anywhere else, and there is also a risk that the normal mouse handling does not work any more in games that suddenly see a PS/2 mouse.
I fought for a long time with the touchpad mouse emulation, trying to match the position DSx86 thinks the mouse is at with the position where Windows 3.0 wants to display the mouse cursor. I think the biggest problem is that if the mouse moves more than a certain number of pixels per a single mouse interrupt, the move goes over the Doublespeed Threshold, and Windows 3.0 moves the mouse a double distance. This is pretty hard to take into account when just clicking around the screen, so instead of the Touchpad Mouse I focused on trying to make at least the D-Pad mouse working properly. After several tries and doublespeed threshold adjustments I finally got the D-Pad mouse to stay in sync between Windows and DSx86.
I also got annoyed with the awkwardness of moving the mouse out of the visible screen area in Zoom mode, and then having to scroll the screen, and then continue with the mouse movement, so now the screen scrolls automatically also in D-Pad mode when the cursor goes near the screen border. There is again a risk that this breaks some games, but I trust you will let me know if this happened. 🙂
Anyways, I’m not quite sure how useful Windows 3.0 in Real Mode is, and I also haven’t looked into how to enable EMS support in it (which I believe it should be able to use), but I’ll let you testers experiment with it. I found one program that runs in Windows 3.0 Real Mode, Moontool by John Walker, so I immediately downloaded that and tested it, and indeed it runs fine also in DSx86. The Garbo Windows 3.1 Archives might also have some programs that run also in Windows 3.0, so feel free to test if you are interested.
Future plans
The internal refactoring continues, and as you might have noticed, this version is quite a bit smaller than the previous version. That is due to refactored code no longer requiring separate graphics and normal RAM opcodes, but instead only the memory handlers are separate. So even though the code size gets smaller, more and more “graphics opcodes” get supported by every refactoring change I do. I am looking forward to a point where I can get rid of the separate graphics opcode framework completely, as that will free several kilobytes of ITCM for other more beneficial use.
I also hope to finally look into the mouse emulation improvements during the next couple of weeks. Adding smoother screen scaling could also help some games, but the problem with that is that it takes a lot of CPU cycles, during which time no interrupts are sent to the running x86 program, so especially Direct SB audio would become pretty much unusable. But, I’ll see what I can do about that. There are also many games remaining in the Compatibility Wiki that I should look at, so I don’t think I will run out of things to do in DSx86 for a while yet. 🙂
Thanks again to all of you for your interest in DSx86!