Happy New Year! I decided to start a new blog page now that the year has changed, so that the single blog page does not grow too big. You can find the previous blog entries using the link at the bottom of this page.

This version has mostly game-specific fixes, but also a new somewhat experimental -f2 filtering option which may improve performance in some games. Here are the details of the fixes:

1. Fixed Crystal Caves hang on title screen
I got a test report asking if the Crystal Caves hang could be fixed, and I was somewhat surprised to hear that rpix86 had such a problem. This game has been working in DSx86 for ages, so it should work fine in rpix86 as well. I began to debug the problem, and noticed that indeed it hangs completely on the title screen. After some digging I found out that the reason it hangs is that the Interrupt Enable CPU flag is not set while the game waits for either timer interrupt or keyboard interrupt. So it never gets either of those interrupts and thus hangs.

The question was then to find out what code clears the Interrupt Enable flag. I added some debug logging to all the code that clears the flag, but that produced tons of output as every interrupt clears the flag for the duration of handling the interrupt. In the end I almost accidentally noticed that the game uses INT 03 (opcode 0xCC) which is a debugger breakpoint interrupt. This has some special handling in my code, and when looking at that code (and comparing it with older code from DSx86) I finally found the problem. In my rpix86 code I pushed the CPU flags with the interrupt flag already cleared, while I should have pushed the flags BEFORE clearing the interrupt flag. Fixing that bug allowed Crystal Caves to run normally. It uses similar code to Commander Keen 1 for horizontal smooth scrolling, though, so the scrolling may be somewhat jittery.

2. Removed unnecessary delay loop from default BIOS keyboard IRQ handler
While debugging Crystal Caves, I noticed that it overrides the BIOS INT 9 keyboard interrupt and checks for the pressed key using input from port 0x60 (the Keyboard Data Port). Input from that port clears the Output Buffer Full bit in the Keyboard Status Port 0x64. However, the game then calls the original BIOS INT 9 handler, which first loops up to 65536 times waiting for the Keyboard Status Port to report that the keyboard buffer is full, before proceding to read the key from port 0x60. This code is based on the actual BIOS of a PC clone, and I hadn't bothered to change that behaviour. (As a curious side note, one of my first PC clones (from around 1985 or so) contained the full printed BIOS source code as an appendix of its manual. That was quite helpful when I coded my own emulated BIOS routines originally for DSx86.)

This waiting for the keyboard status meant that when playing Crystal Caves (and possibly other similar games) there was an unnecessary delay loop of 65536 cycles that happened after every key press. Since I know that the keyboard interrupt in rpix86 only happens after a key is pressed, I removed that delay loop from my emulated BIOS routines.

3. Added experimental -f2 filtering option, for hardware dispmanx scaling
Next I looked into a strange problem in Lemmings where the game runs at more or less normal speed when I run it in a 640x480 window (which I usually do when debugging games in rpix86), but has bad stuttering when it is run full-screen (on my full-HD display). Since nothing in my code except the OpenGL ES drawing routines behave in any way differently depending on the screen size, this seemed quite strange. The OpenGL ES routines should handle all scaling in hardware (or so I thought), but just to be sure I added some timing code around the glTexSubImage2D() call I use to copy the emulated graphics memory to an OpenGL texture. This was the result:

Screen size and filtering Time Max theoretical framerate
640x400 -f0 1.5 ms 667 fps
640x400 -f1 1.5 ms 667 fps
1920x1080 -f0 15 ms 66 fps
1920x1080 -f1 25 ms 40 fps


To my big surprise, this single call took a lot more time when the screen size increased! With texture filtering on (-f1 parameter) it caused rpix86 to not even reach 60fps emulation speed, and even with no texture filtering (-f0) it only left very little time for the actual CPU emulation!

So, it occurred to me that perhaps I should check what happens if I do the size scaling using the dispmanx call instead of OpenGL ES, so that OpenGL can always draw into 640x480 (the maximum VGA resolution that rpix86 supports) screen size. This produced the following timings, so I decided to include this feature as a -f2 filtering mode. Feel free to experiment with this parameter, it may help performance in some situations. The scaling is not as smooth as with the -f1 parameter, though.

Screen size and filtering Time Max theoretical framerate
640x400 -f0 1.5 ms 667 fps
640x400 -f1 1.5 ms 667 fps
640x400 -f2 1.6 ms 625 fps
1920x1080 -f0 15 ms 66 fps
1920x1080 -f1 25 ms 40 fps
1920x1080 -f2 1.6 ms 625 fps


4. Implemented missing CD-ROM call INT2F AH=1501 (X-Wing INSTALL.EXE)
Next I checked why the INSTALL.EXE of X-Wing caused a soft crash in rpix86. I noticed that the game uses a CD-ROM detection method that I had not implemented yet, so I added that code (as a dummy routine, so that the game sees there is no CD-ROM device). This allowed the INSTALL.EXE to show the main selection screen.

5. Fixed DOS Get STDIN Status call to handle enhanced keyboard correctly
However, after getting the INSTALL.EXE main selection screen to show, I could not actually change the selection, as the cursor keys did not seem to work! This also needed some more debugging, until I found out that the game uses the DOS INT21 AH=0B GET STDIN STATUS call to check if a key is available. I had support for that call, but looking at that description I realized that I did not handle the enhanced keys properly. I originally emulated the old 83-key cursor keys in DSx86, and only later switched to enhanced 101/102-key DOS keyboard emulation. At that point I did not fix that DOS call to also handle enhanced key codes correctly. The fix was quite minor, and it made the INSTALL.EXE work properly.

6. Implemented several missing Mode-X opcodes (Aces Over Europe)
Next I tested Aces Over Europe, which had a soft crash when the actual flying should start. There were several VGA Mode-X opcodes that this game uses that have not been used by any other game. It looks like the game actually stores data (like pointers and such) into the VGA graphics memory, and then uses those later when drawing the screen. This is probably some sort of a speed trick, although it actually only slows things down in rpix86 as the graphics memory is slower to handle than normal RAM. In any case, after adding several such new Mode-X opcode handlers the game progressed to the actual flying quite fine.


7. Fixed writing to non-mapped EMS page (bug in Aces Over Europe)
However, after exiting the game back to 4DOS prompt, giving any command in 4DOS caused a soft crash. Obviously something in Aces Over Europe had corrupted memory that belonged to 4DOS.

I used my inbuilt memory watch routine to detect when the 4DOS memory gets corrupt, and noticed that the memory is already corrupt when 4DOS loads the code back from EMS memory. So, I changed the watch address to be inside the physical memory that 4DOS maps into EMS, and then caught the code in Aces Over Europe that writes to this memory. I confirmed in DOSBox that this seems to be a bug in the game, it writes into unmapped EMS memory page. I had been lazy in rpix86 and left unmapped EMS pages to point to the beginning of my EMS memory area, and in this case it meant that the game wrote to memory that belonged to 4DOS.

I did a quick fix to this problem by reserving one EMS page to be the "unmapped" page, so that any game that tries to write to an unmapped page writes safely to this reserved area. This fixed the crash in 4DOS after exiting Aces Over Europe.

Thanks again for your interest in rpix86, let me know of any new bugs you find in this version!

http://rpix86.patrickaalto.com/rblog.html