rpix86 - Blog
Dec 29th, 2013 - rpix86 version 0.14 released!
This version has only a couple of game-specific fixes, as I have not worked all that much on rpix86 during my Xmas vacation. The fixes are the following:
- Fixed Flashback screen resolution problem. This was quite similar to the BC Racers
screen resolution problem, except that Flashback goes to 256x224 resolution, and uses VGA Mode-X
graphics mode instead of the MCGA mode used in BC Racers. Thus I needed to make a change that
was very similar to the change I made for BC Racers, but this time to a different blitting routine.
- Fixed Flashback Sound Blaster detection. The game did not set the Sound Blaster sample playing speed at all (which left the speed at zero), so the game never got an IRQ at the end of the playing buffer. Thus the game failed to detect the presence of the Sound Blaster card. I fixed my SB reset routine to set the default 22kHz sample playing speed, and this allowed Flashback to detect the Sound Blaster card properly.
- Added game-specific hack for Lemmings AdLib detection. The game used a short delay loop waiting for the AdLib 80ms timer to tick, but this delay loop was so short that it took less than 80ms to run, and thus the game failed to detect the presence of an AdLib card. The fix was actually a pretty nasty hack, I simply check that if the running executable is called "VGALEMMI.EXE", I change the length of the AdLib tick to be practically zero instead of the default 80ms. This allows Lemmings to detect the AdLib card (as long as you select the VGA graphics mode when starting Lemmings).
I also spent some time debugging the horizontal scrolling problem in Commander Keen 1, but this is quite a difficult issue to solve. The problem is caused by synchronization issues between these five events:
- The game setting the VGA Start Address register, which will take effect only after the next vertical retrace period.
- The game setting the VGA pixel panning register, which will take effect immediately.
- The game updating the screen contents between the vertical refresh periods.
- rpix86 blitting the screen contents immediately after the actual hardware vertical sync has happened (gles_swap()).
- rpix86 reporting the current vertical sync state to the game.
The biggest problem here is that the game needs to know the exact moment when the screen becomes active after the vertical sync period, but sadly that is the exact time when the game thread is not running! The Linux operating system runs the graphics blitting thread immediately after the hardware screen vertical refresh has happened and the gles_swap() call has updated the screen contents. So there is no way to run the game thread exactly when the game thread would need to run for the scrolling to be smooth. Faking the vertical sync end to happen at some other time works fine in many games, but not in games that need to do something exactly at this time.
Fixing this properly would need some completely different approach to the problem. DOSBox does all the timing internally with no regard to the actual physical screen refresh, but I don't want to go that route. I will continue looking into this problem in the future, but I don't know yet when or whether I will get it fixed.
Dec 15th, 2013 - rpix86 version 0.13 released!
I introduced a rather annoying bug in the previous version, so I decided to release this new version today. However, I have also made some architectural changes to this version, so it is possible that I again introduced some new bugs. This is why I decided to still have the old 0.11 version available for download as the "previous" version. It should not have any major bugs, so you may revert to it if you have problems with this version.
Here are the changes in this version:
-
Fixed arrow (cursor) key handling, which got broken in 0.12 version when I added the Curses library header. I had not noticed that both the Curses library and the Linux input headers define the same key macros (like KEY_LEFT). I fixed this by moving the Curses header file include after the normal console keyboard input routine, so that the header file affects only the console key emulation routines. This small change seemed to fix that problem, so that I did not need to move the routine to a separate source file (which would have been the other possible fix).
-
Changed the interrupt handling system to use Linux asynchronous signals instead of separate threads. I had emulated the timer IRQ by launching a new thread which only wakes up at the current emulated timer IRQ speed interval, and sets a variable that tells the main thread to start handling an IRQ. Since the Linux thread context switch runs at 1000 times a second, the highest IRQ speed that this system can handle (in theory) is around 1000Hz. However, some games play Sound Blaster Direct DAC audio, meaning that they only generate one audio sample during each IRQ timer tick. This type of audio sets the timer IRQ to run at over 10kHz, and it obviously was not possible to emulate such a system using a separate thread.
The new system sets up a Linux interval timer (alarm) to run at the requested timer IRQ frequency. The main thread gets interrupted at the speed of the interval timer, and this signal handlers sets the same variable that the separate thread used to set. To avoid race conditions I also changed all my other IRQ routines (like the Sound Blaster, keyboard, mouse and serial IRQs) to use async signals. I originally created this system for my zerox86 emulator, as the Linux kernel on that platform only ran the context switch at 250Hz, which was not sufficient for many games.
-
Improved SB Direct DAC handling and SB detection routine emulation for Ishar: Legend of the Fortress. Major part of this improvement was due to the new interrupt handling system, but I also noticed that the game occasionally fails to detect Sound Blaster and attempts to play digitized music using the PC Speaker. This is not supported in rpix86 at all yet, so the result was just some horrible screeching sounds. The game uses a hardcoded loop to wait for SB IRQ to happen, and at times this loop ran completely before the thread context switch had a chance to run the SB audio emulation. I made rpix86 detect this type of SB detection system, and have it spend 8 milliseconds simply waiting for the SB thread to run before continuing. This made the SB detection work more reliably in Ishar.
The Direct DAC audio quality is still pretty horrible, but there is not all that much that can be done about that. There will always be a bad audio glitch during the screen blitting, as the main thread that should generate the audio will not run during that time. So, expect heavy glitching at least 60 times per second in this type of audio.
-
Fixed screen resolution of the BC Racers game. This game first goes to normal MCGA 320x200 256-color mode, and then programs the CRTC registers to resize the screen to 288x224 pixels. I improved my MCGA mode screen blitting to recognize this nonstandard screen size and adjust the OpenGL ES texture handling accordingly.
-
Implemented some more special keys for the experimental terminal emulation. Some Alt and Ctrl key combinations should now work, same as most function keys. This code still needs work and many keys are still not correctly supported.
I will continue working on the other problematic games that you have reported to me either directly or via the Raspberry Pi forum rpix86 thread. Hopefully I will get a few more problems fixed again in the next version. Let me know of any problems you encounter in this version, and thanks again for your interest in rpix86!
Dec 8th, 2013 - rpix86 version 0.12 released!
Okay, after several months, here is finally a new version of rpix86! Here is a list of the changes in this version:
- Unified codebase between the ax86 and rpix86 versions of my emulators. The Raspberry Pi -specific features are handled using compile defines, otherwise the emulation code is exactly the same in both versions.
- Implemented an option to run rpix86 without needing 4DOS.COM, by launching a game directly from the command line. This is done simply by giving the full path to the DOS exe or com file as a command line parameter to rpix86. The full path is needed because rpix86 needs to emulate the logical DOS path where the executable is started from.
- Implemented FPU (floating point unit) support. This is only implemented when running in 32-bit protected mode (using dos4gw, for example). All the games I have encountered that need FPU opcodes (for example the X-COM series games) only use FPU opcodes when in protected mode.
- Implemented experimental screen output and keyboard input code for running rpix86 in a terminal window. Note that only text mode is supported, and not all keyboard keys work as expected. This code uses the curses library for input and output.
- Implemented various game-specific fixes: REP MOVSD to Mode-X VRAM, 32-bit INSB opcode, DOS INT 21h AH=67h (set number of files) call, 486-only opcode BSWAP.
Most of my time since the last blog post has gone into the new project I am working on. You can read more about that project from my ax86 blog page. I decided to release a new version of rpix86 mostly because I unified my emulator code base, and that brought the FPU emulation also to rpix86, among with various other fixes. I also experimented a bit with running rpix86 via a terminal connection, but that code is far from finished.
It is also possible that I introduced some serious bugs into this version, so feel free to use your current version if you encounter any problems with this version. Let me know of any such problems, though, so that I can attempt to fix the issues in the next version. Thank you again for your interest in rpix86!
Sep 15th, 2013 - rpix86 progress
As I mentioned at the end of my previous blog post, I am working on a new project and thus do not have much time to work on rpix86 (or zerox86). However, just before I released the previous version of rpix86, I was asked on the rpix86 forum thread whether I had any plans to make rpix86 run on a terminal window. At that time I did not have such plans, but I immediately thought that this might be something interesting that I would like to try. Thus, while mostly working on my new project, I have also made some experiments with running rpix86 using the Curses library for screen output.
My text mode screen handling has always used a "dirty buffer" approach. That is, I have a hidden buffer of the same size as the text screen (normally 80x25), and at around 60 times a second I check which characters have changed, and then only draw the fonts of those changed characters on the actual graphics screen. I thought that this approach would work fine also with the Curses library, as I would only need to draw (send via the terminal line) the changed characters. Indeed, this seemed to work fine, and I was able to get some screen output pretty easily.
After I got the basic DOS prompt screen showing, instead of working on keyboard input, I decided to add support for launching a certain exe directly. I wanted to test what happens with all those block drawing characters used by Norton Sysinfo, for example. Studying the Curses programming guides, I saw that you can use an Alternate Character Set to draw some simple block graphics characters. Thus I worked on that a little bit as well, until I got the lines looking reasonably nice on the Sysinfo screen. I also added color support, so that the end result is not far off the original. Here below is a screen copy of me running rpix86 on my Raspberry Pi using the putty terminal program from my Windows PC. Ignore the two cursor images, I don't yet handle hiding the cursor nor disabling the text mode mouse cursor properly.
Next step would be to add keyboard input, and also some warning message to be shown whenever the DOS screen goes to graphics mode, as that can not be used when in a terminal window. It will take me some time before I can release the next version, though, as most of my time goes to the new project I am working on. But, it is quite possible that the next version of rpix86 allows you to actually run it on a terminal window. :-)
Sep 1st, 2013 - rpix86 version 0.11 released!
This version does not have that many changes as I have still been focusing on the zerox86 version. Actually I think the biggest change in this version is that I changed the automatic 4DOS.COM download to fetch the program from my web pages, as it seems that the JP Software site is not working properly at the moment. This is just to help new users install and use rpix86.
The only other noteworthy change is that I fixed the garbled graphics problems in the CNC milling software NSW.EXE. The cause of this problem was quite interesting. The game goes to VGA 640x480 16-color mode (for which the BIOS graphics mode byte value is 0x12), but then almost immediately sets the BIOS graphics mode byte to 0x06 using the following code:
1993:00003E63 1E push ds 1993:00003E64 33C0 xor ax,ax 1993:00003E66 8ED8 mov ds,ax 1993:00003E68 BB4904 mov bx,0449 ; DS:BX = 0:0x0449 = BIOS graphics mode byte address 1993:00003E6B 8A27 mov ah,[bx] ; Get current BIOS graphics mode byte into AH 1993:00003E6D B006 mov al,06 ; AL = 0x06 (CGA 640x200 2-color graphics mode byte) 1993:00003E6F 8807 mov [bx],al ; Set current BIOS graphics mode byte from AL 1993:00003E71 1F pop dsI have used the BIOS graphics mode byte in a C language switch statement to easily determine which screen blitting function to use, as I have separate functions for each color depth. When the program changed the BIOS graphics mode byte, it made rpix86 switch to using the 2-color screen copy routine, even though the actual graphics mode in use was still the 16-color VGA mode.
I fixed this by coding a small hack into the 0x06 case statement, so that it checks also the vertical screen size, and if that is 480 lines, uses the 16-color VGA 640x480 screen copy routine. This seemed to fix all the symptoms, but this is a bit of a nasty hack in the code.
I just got a new project that I need to spend my free time on, so it looks like it will take some more time before I have time to look into the problem games that you have reported. Sorry about that, but sometimes things like this happen. I will get back to improving both rpix86 and zerox86 as soon as I get the other project finished.
July 21st, 2013 - rpix86 version 0.10 released!
Here is a list of the changes in this version:
Added support for the second serial port COM2. Originally I had used the IRQ3 line (which COM2 uses) for mouse emulation, so before I could start working on the actual COM2 support I needed to change the mouse emulation. I had used IRQ12 for PS/2 pointer device emulation, and in this version I made IRQ12 to handle the emulation of both, depending on whether the DOS software uses INT33 (serial mouse) or INT15 (PS/2 mouse) routines. This may cause some problems in the mouse emulation in case the new system does not handle all situations properly.
The way the new support for multiple serial ports work is that you can give several -s? parameters on the command line. The first one will be emulated as COM1, and the second one as COM2. In theory it would be possible to emulate two more COM ports as well, but this is not implemented yet. Let me know if you need me to add support for COM3 and COM4.
Implemented 32-bit version of opcode 0x9A (CALL FAR). This was used by BC Racers game. It is a bit strange that no other game or software has so far used the immediate far call, but it looks like most games either call near routines or call far routines via a jump table instead of hard-coded addresses. In any case, this allowed BC Racers to start up.
I also fixed another problem in BC Racers, it seems to use the standard VGA graphics mode, but it sets the horizontal screen size (pitch) to a non-standard value. I fixed this simply so that the active area looks correct, but I did not change the actual screen width that gets shown. You may need to give the CLR command, or start the game with a batch file that sets echo off to clear the screen before starting the game. This would get rid of some extra garbage on the right side of the game screen.
BC Racers also ettempted to use an undocumented Sound Blaster command 0xE7, which I now silently ignore.
Sid Meyer's Covert Action game used EGA features in a way that assumed the graphics mode change to have reset the EGA registers in a certain way. I noticed that such a reset was missing in my code, and I implemented that. This got rid of the graphics glitches when selecting menu items. This may have caused also problems running different EGA games after one other, as the graphics registers were not reset properly between the games.
I also fixed a hang in Syndicate intro. This was caused by a somewhat strange code in the game. It goes through all interrupt vectors, looking for two adjacent vectors that point to the same routine. In rpix86 I have coded every interrupt vector to point to it's own location, which is how I keep track of unimplemented interrupts that games may need. The Syndicate intro did not handle a situation where such vectors were not found, and kept looping trying to find those vectors. I fixed this by zeroing the couple of vectors where the game begins looking for such (as I noticed that those vectors are zeroed in DOSBox). I have no idea what the game uses these vectors for, though.
After I fixed the intro hang in Syndicate I spent some time trying to debug the crash in the beginning of the actual game. It crashes because the protected mode descriptor table contains an invalid descriptor. This however is caused by the game for some reason clearing a single byte from the descriptor, thus actively making it invalid. So, the actual cause is probably somewhere around the code that writes this invalid zero byte to the decriptor, but since fixing this requires me to debug and understand the actual game code, I have not yet had sufficient time to do this. I will try to continue this during the following weeks.
I have also some other games to test and debug, thanks for letting me know of the bugs you find! Some problems are reasonably easy to fix, but some will take quite a lot of debugging to determine the root cause of the problem, so it is quite difficult to estimate how long will it take me to fix a certain game. I am also still on vacation and have had some other plans for spending my vacation besides working on rpix86, so that will also make the progress slower.
Thanks again for your interest in rpix86!
July 7th, 2013 - rpix86 version 0.09 released!
Okay, yet another new version of rpix86! In this version I have mainly worked on improving the Sound Blaster emulation, and I have also worked with one user who is experimenting with interfacing a Raspberry Pi to a milling machine by running a YADRO software within rpix86. Here is a list of the changes in this version:
- Fixed the secondary timer functionality. I had the timer modes mixed up, which caused far too long delays in some situations. This is what caused the bad delays in Alone in the Dark when enabling AdLib music. The game uses the secondary timer to delay a little while between sending AdLib commands (because the actual AdLib hardware needed a delay of at least 23 microseconds before the next command could be sent). This delay was orders of magnitude too long in rpix86.
- Fixed Sound Blaster digital audio problems in NHL '94. The screeching static sounds in that game were caused by the game giving Sound Blaster command to play 0x10000 (65536) samples, but programming the DMA channel to only send 0x100 (256) samples and then loop back to the beginning. My SoundBlaster code only used the length given in the Sound Blaster command (because usually both lengths are programmed to the same value). I fixed this so that it only plays the 256-sample buffer, and the digital audio began to sound pretty much correct. It still has some clicks and distortion, and the problem where you may need to start the game again after it drops to DOS still remain.
- I also implemented the missing Sound Blaster command 0xD4 (continue DMA command), which fixed the missing Sound Blaster audio in Warcraft.
- I also found and fixed still one problem in text mode cursor behaviour. I had not handled the higher bits of the cursor size variable properly. Setting the cursor start scanline to anything over 31 should always hide the cursor regardless of the ending scanline value.
- In the previous version I had fixed the UK keyboard hash key behaviour in X Window environment, but at the same time I had broken the backslash key. This is now fixed in this version.
- I also implemented a JPE/JPO special opcode handling for DDISP.EXE program of the YADRO package. The program uses these opcodes in the higher mathematical functions.
Next, I will continue debugging the problem games and programs, like the NHL '94 dropping to DOS on the first run, the QBASIC palette problems, and I also just got a report that Syndicate does not run in rpix86, so I will try to investigate that as well. Let me know of any games and other software that does not run in rpix86, I will try to take a look and see if they can be made to run. Thanks again for your interest in rpix86!
June 30th, 2013 - rpix86 version 0.08 released!
Improvements in the new version
It has been a while since I last worked on rpix86, as I have been focusing on getting the GCW0 version done. However I am now a little bit stuck with the GCW0 version (or rather, the things I need to do to it next are rather boring), so I decided to work this week on the rpix86 for a change. This was my last working week before my summer vacation, so I did not have all that much time to work on it. Thus, there are no major new features, mainly just a few minor fixes.
- First, I fixed the text mode cursor problem where there were sometimes extra cursor images left on the screen. This happened at least in Norton SYSINFO. This was caused by the software setting the cursor start scanline to a large value, like 63, with the ending scanline being the default 7. This should skip the cursor drawing completely, but my routine always drew at least one scanline of the cursor, which was wrong.
- Next, I worked on getting NHL '94 running, as it was mentioned on the Raspberry Pi forum as not running correctly. I implemented a special handling for a JPO opcode, and also a version of storing data into Mode-X graphics memory using a REP STOSB operation where the indices are decreasing. There are still some problems in NHL '94, especially with SoundBlaster audio. Also it seems to drop back to DOS at first startup, but starts correctly when starting it again.
- I have also been working on getting QBASIC running, as it has also needed some special handling of JPO and JPE opcodes. Back in May I managed to implement those opcodes for it, but then ran into a problem where the whole screen just went black when a BASIC program was started. Now I debugged that problem and found out that it sets the text mode palette using VGA palette routines, which I did not properly support in text mode. I made some changes and got it to work better, but it still does some incorrect palette adjustments. I will attempt to fix these better in the upcoming versions.
- While debugging the QBASIC palette problem I noticed that rpix86 did not reset the active screen page properly when switching from graphics to text mode, so I fixed that. This probably did not cause any visible problems, though.
- One sharp-eyed user of rpix86 had also noticed that while Caps Lock is active, pressing shift and Q, W, E, R or T keys produced the same capital letters as pressing them without shift. This was caused by a problem in my DOS key translation table. This same problem exists in the Art of Assembly documentation that I used as a source for my routines. This problem is now fixed in this version of rpix86.
- I also got a report that when running rpix86 in the X Window environment and using a UK keyboard, the hash key (#) did not work but instead got logged as an unmapped key. Since X sends already mapped keycodes to rpix86, it is somewhat difficult to reverse the mapping to get the actual hardware scancode that rpix86 needs. This is made more complicated because of the various language-specific keyboard layouts in existence. In DSx86 I only supported US keyboard, but that is not sufficient in rpix86. I have now adjusted the key-to-scancode mapping in rpix86, so hopefully at least the UK keyboard is now properly supported. You will still need to run "KEYB UK" command within rpix86 to get the proper key mappings, as the key emulation in rpix86 will always use US key mapping by default.
- Finally today I adjusted the emulated AdLib timers to actually use the hardware clock and thus get more accurate results. I did this in hopes that it will improve the AdLib detection routine behaviour in some games that currently do not detect the AdLib presense. This seemed to help at least in Commander Keen 7: Keen Dreams game.
Unfinished features I have been working on
In addition to the changes mentioned above, there are some additional changes that however are not yet finished and/or properly tested. Back in May I got a request to add support for accessing the Raspberry Pi GPIO ports from within rpix86. This seemed like an interesting idea, and as the person who requested this was a programmer and was willing to create some code that would help me in integrating this, I made a special version of rpix86 for him to test. The documentation for this feature is still missing and it requires a third-party shared library to be present, so this is still somewhat of a work-in-progress.
I have also debugged the Sound Blaster and AdLib problems in NHL '94 and Commander Keen 7, but those will still need more debugging. Same with the QBASIC palette problems I mentioned above.
Hopefully I did not break anything with this new version. Some of the changes I made I have only tested in a couple of games, so let me know if some game that used to work fails in this version. Thanks for your continued interest in rpix86!
June 2nd, 2013 - GCW Zero porting work continues
Nothing new on the rpix86 front, sorry. I am still busy getting the GCW0 version zerox86 running. I just added a proper web site for zerox86, it can be found at http://zerox86.patrickaalto.com in case you are interested in my progress with that version.
May 19th, 2013 - GCW Zero porting work continues
During the past couple of weeks I have focused on getting the GCW-Zero port zerox86 of my emulator running. I have not worked much on rpix86, although I have done some small preliminary work for additional hardware support. I plan to look into supporting GPIO access and possibly USB-parallel port device access. I haven't yet finished either code, so I have no new version to release yet. I plan to still continue working on the zerox86 a bit further before getting back to enhancing rpix86 as well.
May 5th, 2013 - GCW Zero port started
During the past week I have not worked much on rpix86, as I got my new GCW Zero "engineering sample" game console. I began porting my DSTwo version to that device, and that has taken pretty much all of my free time for the past week. I plan to continue working on this during the following week as well, so my work on rpix86 is on a small break until I get something running in the GCW0 as well.
Working on GCW Zero is interesting because it uses a processor that has a MIPS32r2 architecture. This Release 2 version of the architecture brings a couple of very powerful and useful new opcodes to the MIPS ASM language, namely EXT and INS. I can use these new opcodes in quite a few places in my code to speed up the emulation, so I am very interested to see how fast zerox86 (current working name of the project) will run on the device.
I began my porting project by first porting my unit test program. I then began changing the code to use the new EXT and INS opcodes where possible. After a few changes I run the unit test program to make sure I don't break anything, and then continue making the changes. Since I use the unit test program from the special 386-enabled DSx386 version, I have also needed to fix some incompatibilities between the unit test program and my old DS2x86 sources. The current status is that opcodes 0x00..0x0E work fine, and I am working on the 386-specific 0x0F group opcodes, mainly fixing those incompatibilities.
Apr 28th, 2013 - rpix86 v0.07 released!
Improvements in the new version
This version does not have any new features, it has just various small fixes and improvements, mainly affecting certain games. Here is a list of the changes:
- Fixed a potential crash when a game moves the cursor far outside the screen area.
- Implemented a dummy OUT 82,AL operation (Alone In The Dark).
- Improved SB IRQ behaviour for short DMA buffers (Alone in the Dark).
- Implemented a missing REP MOVSW Mode-X to RAM operation (Ween - The Prophecy).
- Fixed a bug in REP MOVSW RAM to Mode-X operation (Ween - The Prophecy).
- Implemented reading from DMA page register (Super Frog).
- Implemented USE16 version of Mode-X REP STOSD opcode (Super Frog).
- Implemented USE32 version of REP INSB opcode (Super Frog).
- Implemented USE32 version of REP OUTSB opcode (Super Frog).
- Added JPE special handling for "Super Frog".
Further detail about the changes
In the beginning of last week I got some error logs from rpix86 forum user Vanfanel, containing problems in games Alone in the Dark, Ween - The Prophecy and Super Frog. I began by troubleshooting Alone in the Dark, as I already had that game and it works fine in DSx86. However, as soon as I started it in rpix86, the whole rpix86 crashed with a segmentation fault. I could not even get an error debug log, which I thought was a bit strange.
Being able to run my emulator on top of a real operating system has the advantage that I can attach the GDB debugger to it from a different shell session, and I can then have GDB tell me exactly where the program crashes. With DSx86 and DS2x86 these problems have been much harder to track down, as they will simply hang the whole system in similar situations. In this case the debugger showed that rpix86 tried to draw the text mode blinking cursor outside of the memory block I had allocated for the text mode screen. I calculate the cursor position based on the row and column values, but had not limited those in any way. So if a game decides to hide the cursor by moving it to row 255 for example, my code simply tried to draw it there, even though the text mode only has at most 50 rows, and normally only 25. I added an out of bounds check and skipped the cursor drawing if the address is out of bounds, and this got rid of the crash.
After this small fix I got the exact same rpix86dbg.log error report from Alone in the Dark as what Vanfanel had reported to me. This was caused by the game trying to setup Sound Blaster with DMA channel 3 instead of the DMA channel 1 (which it actually uses in rpix86). I added a dummy handler for that DMA channel, but this only caused rpix86 to crash again with a segmentation fault. I again debugged this problem, and found out that the game executed code at the end of the RAM area (which was full of zeroes) and continued beyond the end of the RAM area! Obviously something much more serious was going on.
I do have various conditional debug defines in my cpu emulation sources, just for these kinds of problems. I enabled the "do not run zero code" and the "trace all opcodes" flags, and ran the game again. I found out that the game attempted to execute code at address FFEF:0008 forwards, and there it ran into zero code. After some more debugging I noticed that it jumps to that address when it tries to call the DOS INT 21h interrupt, and sure enough, some code had overwritten the int 21h vector to point to that invalid address!
I also have a memory watch feature built into rpix86, so I added a watch for the int21h vector address, and found out the code where it gets overwritten. It took me quite a while longer to understand what was going on, as I noticed that the root cause for the memory overwrite problems was that the game first allocates all available DOS memory, loads and executes another program, and after it exits the game again tries to allocate all available memory (of which there is none at this point), does not check whether the allocation succeeds and then proceeds to loading another program into memory that has not been allocated! This loading then obviously corrupts memory from all sorts of locations, including that int 21h address.
Since the game does work in DSx86, I began debugging it there and comparing the behaviour with what happens in rpix86. After considerable time I noticed that the first program that gets loaded is actually a Sound Blaster driver, and it exits with an error code if it can not determine the IRQ number for the Sound Blaster. It occurred to me that I had not run the Alone in the Dark hardware configuration option in rpix86. When I ran that, it detected only "Sound Blaster (no DMA)", even though it should have also detected "Sound Blaster (DMA)". Using the no DMA configuration allowed the game to start, though, but the audio was very bad.
So, obviously the problem was related to the game not detecting the SB IRQ number. After some more debugging I realized that the game does not set the playing frequency at all, and in rpix86 it gets left at zero, which will then never cause an IRQ to happen. In DSx86 I had (by chance) handled this situation better, and I copied the same handling to rpix86. This finally allowed the game to detect the proper Sound Blaster (DMA) audio device. The game does still not run very well, though. It has some weird slowdowns, so that it actually runs faster in DSx86! I have not yet managed to determine what causes these slowdowns, it looks like some sort of a timing issue.
The next game I debugged was the Ween - The Prophecy. It used a couple of somewhat more rare VGA Mode-X block moves, which I had not yet implemented in the code I had ported over from DSx86 and converted to be compatible with protected mode. I implemented these operations, and this allowed Ween to start up and proceed to the actual game fine.
Next I downloaded and tested Super Frog. The first problem was simple, it attempted to read from the Sound Blaster DMA page register, which I just had not implemented yet. After I implemented this, it proceeded to the next problem, where it attempted to clear the Mode-X graphics screen using a 16-bit REP MOVSD block operation. I had only implemented the 32-bit version which is usually used by protected mode games, but for some reason Super Frog wanted to use the 16-bit version even when it ran in 32-bit protected mode. This was pretty easy to implement, though.
After that problem Super Frog stopped into protected mode REP INSB port operation, which it used to read the VGA palette register values, and immediately after that into the corresponding REP OUTSB operation used to set the VGA palette register values. These were also easy to implement.
Finally the game stopped into a JPE opcode, in a code that was exactly like the routine mentioned in the Simply FPU tutorial for reducing an angle within the allowable range of ±263 radians. That is, the game obviously uses a lot of floating point operations, which are currently simply handled as a no operation in rpix86. At this point I assumed that this game can not be made to run in current rpix86, but I decided to code support for this specific algorithm anyways.
After this fix, to my surprise, the game did start up and did seem to work. I don't know how to play that game so I don't know whether it uses floating point operations during the game so that it will be unplayable, but I will leave that to you to test. :-)
I also spent a little time testing X-Wing, which seemed to work without problems, and also the horizontal pan jitter problem in Commander Keen 1. This jitter problem is difficult to solve, and I could not figure out a way to improve it in this version yet.
New web site features
Last week I also got a request to add a donate button to my rpix86 pages. Thus, I added one at the bottom of the main page. This is not a request for you to donate anything, but there is now a button for that purpose if for some reason you absolutely want to donate. :-)
Also, big thanks to Ben Garrett, who created a very informative tutorial for rpix86 installation and usage. The tutorial also gives a short history lesson about what DOS is, so check it out! I added a link to the tutorial also to my FAQ page.
In other news...
Last week I also got contacted by the people behind the new gaming console Game Consoles Worldwide Zero, or GCW-Zero for short. They would like me to port my x86 emulator also to their new device, and this is something that I find quite interesting. The device is powered by an Ingenic JZ4770 CPU running at 1GHz, so it is quite a bit more powerful than the 360MHz JZ4740 that is in the DSTwo flash cart for which I developed the DS2x86 version of my emulator. However, both of those processors use the MIPS32 architecture, so it should be relatively easy for me to port my DS2x86 code (which is 95% MIPS32 ASM) over to work on GCW-Zero.
I have already done some preliminary porting tests, and there are some issues that I need to solve to be able to run my emulator under an operating system, but these issues are reasonably similar to what I had to do when porting DSx86 over to rpix86. What this means, though, is that it looks like my finishing my Android port will get pushed back, as I am currently more interested in working on GCW-Zero than on my continuing the ax86 version. But who knows, possibly I can use some new features (that are coded in C language) in both of them!
Anyways, thanks again for your interest in my emulators! Have a nice 1st of May!
Apr 21st, 2013 - rpix86 v0.06 released!
This new version has the following fixes and enhancements:
-
New serial port emulation support, with rpix86 now forwarding data between emulated serial port COM1 and a USB-to-serial device connected to your Raspberry Pi. This new support might work also with the GPIO UART connection, but this is completely untested. Note that you will need to give the new -s[NUM] parameter to rpix86 when you launch it to enable serial port support. For example, if your device is connected to /dev/ttyUSB0, you would give parameter -s0. There is a special parameter -sA, which attempts to use the /dev/ttyAMA0 GPIO UART device.
Note that I have only tested this serial port emulation with the Telix communications program talking to my old modem, so it may or may not work with other serial port programs and serial devices. Let me know if you have problems with it, I can then try to improve the support.
Changed the -w and -h parameters to not force 4:3 aspect ratio. In prior versions you could change the screen size using those parameters, but rpix86 always attempted to keep 4:3 aspect ratio (as used in practically all monitors during the DOS era). If you do not give those parameters rpix86 will still attempt to keep 4:3 aspect ratio. Note that you can also combine the overscan parameters with the screen size parameters, to get the rpix86 window to be pretty much whatever aspect ratio and located anywhere within your physical screen area.
I also added a simple dialog window to show up when launching rpix86 inside the X Window environment, when rpix86 can not find 4DOS.COM. Previously rpix86 would just quit without showing anything in this situation. This feature is mainly to avoid frustration with new users (who don't RTFM :-) failing to launch rpix86 for the first time.
Now rpix86 will show the above dialog, and wait for the user to press either Y or N. The dialog will show the directory that will be used as the C: root, so if that is wrong you can just press N and adjust your launch directory or rpix86 parameters.
If you press Y, rpix86 will download 4DOS.COM to the directory shown, and then attempt to launch the actual main window. For some reason this seems to often fail with a "BadMatch" error message, so you may need to restart rpix86 manually.
-
Added an icon to rpix86 application when running in X Window. The icon is shown also in the title bar of the above 4DOS question dialog.
-
Added also the current version number to the X Window title bar.
-
Enhanced the keyboard and mouse reading system, so that it will not slow down the actual emulation quite as much as before. I also added the joystick and serial port reading to the same system, so all of those are now handled somewhat more efficiently. I hope I didn't break anything when making this change.
Here below is again a screen copy that shows a couple of the new enhancements: New rpix86 icon in the title bar, showing the version number in the X Window title, and running Telix in rpix86. The Telix window shows the result of giving a command AT\S to my old modem, connected to my Raspberry Pi with a Prolific PL2303 USB to RS-232 adapter.
Thanks again for your interest in rpix86, I hope you find the improvements in this new version useful!
Apr 14th, 2013 - rpix86 has a logo!
First off, rpix86 now has a logo image! Big thanks to UnfocusedBrain (http://UnfocusedBrain.com/) for creating a cool image for rpix86! I immediately liked the idea when I saw the image he had created, as I think it nicely combines the Raspberry Pi theme with the x86 text. I now use small versions of that image as the favicon of these pages, and in the rpix86 executable when running under X Window graphical environment. I also used the image in the new Raspberry Pi Store BoxArt image. Here below is the official rpix86 logo in all its glory, as used in the BoxArt image:
I have not managed to get nearly as much work done on rpix86 this past week as I did during my vacation week. During workdays I don't have much time to work on my hobby projects. I did however acquire some new hardware which I can use when coding new features and testing them. I got a Roland MT-32 sound module from eBay, and an USB to RS-232 converter cable. I used to have a Roland LAPC-1 sound card back in 1991, but I swapped it for a Roland SCC-1 in 1992. Even though the new card was in some ways better, I have pretty much been regretting this switch ever since. I still have the SCC-1 card, but I don't have any PCs with ISA card slots so I can not use it any more. I thought it might now be time to re-acquire a MT-32, I can use it when testing the MIDI support in rpix86, and I also have some old MIDI compositions that were made for MT-32 and don't sound correct on any other MIDI device.
I got the USB to RS-232 device in order to code serial port emulation into rpix86. This is the most often requested missing feature, so I thought I would try to add that next. This is what I am currently working on. I found an old modem in my closet, and I am first trying to get communications between rpix86 and that modem working. I am using an old DOS communications program Telix to test the communications. I used that program back in the early 90's to call various BBS systems. Launching up Telix in rpix86 brought back a lot of memories from those old times. :-)
I am hoping to get the serial port support done by the next weekend, but it might take longer. In any case, thank you again for your interest in rpix86!
Apr 7th, 2013 - rpix86 v0.05 released!
Okay, after working on rpix86 for the whole of my vacation week, I feel that I have managed to get quite a lot of work done on it. It was nice to be able to focus on it for a full week, especially as I had a good list of interesting new features that I wanted to implement. I am going to explain the new features and other fixes with a bit more detail this time, so let's get on with it.
1. EGA palette handling fix
In the previous 0.04 version I made some minor performance enhancements to the 16-color graphics modes palette handling. The change was so minor that I did not even think to run my small test.com x86 program that simply loops through all the supported graphics modes and prints some characters and lines with different colors. If I had run it, I would have noticed immediately that my small fix actually broke the 16-color palette handling! Sorry about this, I think in the future I need to always run this test program before the release, and it might be a good idea to always have the previous version available for download in addition to the just released version. So if the latest version breaks something, you can try running the previous one. In any case, now the palette problems are fixed in this version.
2. Hardware mouse cursor emulation
The next major feature is the addition of a hardware mouse cursor. Perhaps "hardware" is somewhat of a wrong term as back in the VGA days the cursor was usually drawn by the mouse driver instead of actual hardware, but I use the term to make a distinction between a (software) mouse cursor that the game itself draws, and a (hardware) mouse cursor that gets drawn simply by calling the int 33h mouse function "Show mouse cursor". My test.com tester program uses the hardware mouse cursor in all the different graphics modes, so it was a good test bench also for this work.
I wanted to see if I can use actual hardware (the OpenGL ES engine) in Raspberry Pi to draw the mouse cursor, my problem was just that I am still really unfamiliar with the OpenGL ES techniques and only barely understand how the vertex and fragment shaders work. However, I thought that attempting to make a mouse cursor for rpix86 would be a good learning experience, and thus I began working on it. I started with a simple OpenGL ES triangle tutorial, trying to get a white triangle visible on top of the actual background texture showing the PC screen. After I got that working, I began enhancing it by adding a texture to contain the actual mouse cursor shape. It took me some googling to get the alpha channel working properly, and then a lot of trial and error to get everything showing in the correct orientation. After some more studying I realized that I could perhaps have the vertex shader do all the position and scaling adjustments so that I don't need to do that in code. I was pretty happy with the end result, the vertex shader now shows the mouse cursor in the correct location and takes into account the current mouse cursor shape hot spot locations etc.
The current vertex shader code looks like the following, in case you are interested. The mouse cursor size is based on a 640x400 screen size, and it will then get proportionally larger when zooming the PC screen to larger displays.
static const char* mouse_vertex_shader = "attribute vec2 a_position; \n" "attribute vec2 a_texcoord; \n" "varying mediump vec2 v_texcoord; \n" "uniform ivec2 u_mouse_xy; // Mouse (x,y) position \n" "uniform ivec2 u_max_xy; // Max mouse coords (screen size) \n" "uniform ivec2 u_hot_xy; // Mouse hot spot position \n" "void main() \n" "{ \n" " // Adjust the mouse coordinates by the screen size. \n" " float x = float(u_mouse_xy.x)/float(u_max_xy.x)*2.0 - 1.0; \n" " float y = float(u_mouse_xy.y)/float(u_max_xy.y)*2.0 - 1.0; \n" " // Adjust the mouse hot spot position by the cursor size. \n" " x = x - float(u_hot_xy.x - 16)/640.0; \n" " y = y - float(u_hot_xy.y - 16)/400.0; \n" " // Adjust the vertex position by the mouse position. \n" " vec2 p = vec2(a_position.x + x, a_position.y - y); \n" " v_texcoord = a_texcoord; \n" " gl_Position = vec4( p, 0.1, 1.0 ); \n" "} \n";I also need to have code that converts the mouse cursor shape (given to the mouse driver using int 33h commands) to a texture. That conversion (which happens very rarely) is done with the following code. The name of the routine is from the DSx86 version where I used a hardware sprite to draw the mouse.
static u32 mouseTexture[16][16]; // RGBA values void CursorToSprite(u16 *mask) { // Convert from input 16 bits per 16 rows screen and cursor masks // to 16x16 matrix of RGBA values. int x, y; for (y = 0; y < 16; y++) { for (x=0; x < 16; x++) { if (mask[y+16]&(1<<(15-x))) // cursor pixel set = white mouseTexture[x][y] = 0xFFFFFFFF; else if (mask[y]&(1<<(15-x))) // screen pixel set = transparent mouseTexture[x][y] = 0; else // Both pixels clear = black mouseTexture[x][y] = 0xFF000000; } } }
3. Overscan adjustment support
I had also received reports that rpix86 does not handle screen overscan properly. Especially when using a PAL TV output, part of the rpix86 DOS screen is in the overscan area and thus not visible. This of course makes using rpix86 pretty difficult. I had assumed that setting the overscan values in the /boot/config.txt would affect all software, but it seems to affect only the console and X Window screens.
I decided to add support for reading the /boot/config.txt overscan values, and in addition I thought it might be a good idea to have command line parameters to allow still further overscan adjustment. Thus I added the following new command line parameters to this version of rpix86:
-olLEFT where LEFT is the amount of overscan on the left border. If not given, defaults to /boot/config.txt overscan_left value. -orRIGHT where RIGHT is the amount of overscan on the right border. If not given, defaults to /boot/config.txt overscan_right value. -otTOP where TOP is the amount of overscan on the top border. If not given, defaults to /boot/config.txt overscan_top value. -obBOTTOM where BOTTOM is the amount of overscan on the bottom border. If not given, defaults to /boot/config.txt overscan_bottom value.The current values are written to stdout (if they differ from zero) when rpix86 starts, so you can check that the correct values get used, and change them when starting rpix86 if necessary.
4. Support for running rpix86 in X Window environment
I also have been wanting to try adding support for running rpix86 inside the X Window graphical environment for some time now. Since many people run their Raspberry Pi "headless" without any screen or input devices connected, it would be nice if also those users could run rpix86. Of course rpix86 will run much slower when in the X Window environment, but there is a lot of old DOS software that is not performance critical and thus would run fine.
I started by googling for general information about coding for the X Window system (which was yet another completely new area for me). I found an interesting forum thread started by teh_orp, and example code in github by a forum member shirro. As the thread and code are both a bit dated already, I am not sure if this is the best way to do this, but I decided to give this approach a try. It looked like it did not require many changes to my existing OpenGL ES code, so I began adding the required changes. After a few hours of work I already had rpix86 showing up in a window (the picture was upside down, but that just needed some adjustments to the code).
I used a WinVNC connection from my Windows XP development PC to my Raspberry Pi to test this. At this point the keyboard and mouse reading still used the /dev/event files, and I knew I had to change them to use the X Window event system when running in X Window, otherwise it would not work via WinVNC and similar remote desktop connections.
I had coded touchpad mouse support into DSx86, which works by detecting the touch position on the screen and then converting these coordinates to the mouse position. I tested how the X Window mouse coordinates behave, and it looked like I can use this system pretty much as-is. The X Window mouse movement events give coordinates in pixels relative to the left top corner of the window, just like the mouse coordinates should work. This will work fine as long as the game does not use its own scaling system, which sadly many games do. Such games will most likely not be usable from within the X Window environment (thus I consider the X Window support in rpix86 to still be in the "experimental" state).
Adding keyboard support also introduced new problems. I could not find proper keycodes from the key press and key release events. Running rpix86 via VNC, and from the X window started from the console, had different keycodes for the same keys, so I knew that I can not use the keycode directly. After mapping the keycode to a KeySym value the result was (mostly) similar, but the problem was that I have a Finnish keyboard layout and rpix86 expects to get raw US keycodes, which it can then give the KEYB DOS program to convert. I haven't yet found a proper way to get the raw keycode (unaffected by the keyboard language) from the KeySym that the X Window returns. Thus some keys might not work or give incorrect keys when running rpix86 in X Window environment. It might help if you set the X Window keyboard mapping to US with a command setxkbmap us in the LXTerminal window before starting rpix86.
5. Option to run rpix86 without audio
When testing rpix86 in X Window via VNC, I realized that it might be somewhat useless to run the audio emulation if your Raspberry Pi is completely headless, with no I/O capability besides the ethernet connection. So I added a new command line option, -a2, which skips the audio emulation thread startup and thus plays no audio. This option will make rpix86 run around 10% faster, perhaps even more if a game uses both AdLib and SoundBlaster audio.
6. Added support for running "Chess Genius 3" DOS version
After releasing version 0.04 I got a rpix86dbg.log crash log from running Chess Genius 3 by Richard Lang DOS version in rpix86. From the log I could see that the game uses jpo (Jump if Parity Odd) opcode. This is a problem in rpix86, as my CPU emulation core does not support the Parity flag natively. Whenever a game uses either JPO or JPE (Jump if Parity Even) opcodes, rpix86 will quit with an error log unless I have coded specific support for this situation.
The game-specific support for Parity flag in rpix86 works by examining the previous opcodes whenever the JPO/JPE opcode is encountered. The specific code snippet in Chess Genius 3 had the following opcodes:
1AF0:3980 A818 test al,18 1AF0:3982 7505 jne 3989 ($+5) 1AF0:3984 31BFB001 xor [bx+01B0],di 1AF0:3988 C3 ret 1AF0:3989 7B0D jpo 3998 ($+d)That is, the game tests the AL register for value 0x18, and if either of those two bits are set, it jumps to address 0x3989 where it tests whether the parity is odd (meaning that only one of those bits are set), in which case it jumps to address 0x3998. To support this in rpix86, I need to know what was the operation that was supposed to set the parity flag, calculate the result of this operation, determine the resulting parity flag value, and then either jump or not jump depending on the result. The problem is that I don't keep track of which opcodes have been executed and in what order before encountering the JPO/JPE opcodes.
In the above situation it is not very difficult to determine the correct parity flag value. I can test that the opcode bytes before the JPO opcode are those 0xA8, 0x18, 0x75, 0x05, 0x31, 0xBF, 0xB0, 0x01, 0xC3, in which case I know the correct parity flag can be calculated by anding the AL register with 0x18, and counting the number of resulting bits. There is by the way a neat ARM ASM trick for calculating the parity of a register, created by FluBBa.
The problem in the case of Chess Genius 3 was that this was not the only location where it used JPO/JPE opcodes. Every time I fixed one location and tried to run the game in rpix86, it soon stopped in the next location and so on. After adding about a dozen or so special cases, I noticed that the code segment seems to stay the same, so I decided to disassemble this whole code segment and look for JPO and JPE opcodes from the disassembled result.
I found out that the game had 36 different locations in the code where it used the JPE opcode, and 35 places with JPO opcode, used in a variety of ways. There were even a couple of pretty difficult problems, for example in this code:
1AF0:58C6 A809 test al,09 1AF0:58C8 B004 mov al,04 1AF0:58CA 7A02 jpe 58CE ($+2)The code tests the AL value, then stores something else into AL, and then jumps based on the parity result of the test. When rpix86 encounters the JPE opcode, it has no way of knowing what AL value was used in the test, because the value had already been overwritten! I needed to add code to store the TEST AL,imm8 opcode (0xA8) result into memory, in order to use this later in the JPE opcode. This will marginally slow down the handling of that opcode, but luckily that is not the most commonly used opcode, and simply writing a byte to memory (into stack area, actually) should not slow anything down noticeably.
I have been letting the game run a match (computer versus computer) for a long time and it does not seem to encounter any problems, so hopefully the game will now work properly in this 0.05 version.
This image used with permission from Richard Lang, the author of Chess Genius 3.
Above is a single screen copy that nicely presents several of the enhancements in this version. I took it on my Windows XP PC, running the X Window environment via a WinVNC connection to my Raspberry Pi. It shows that it is now possible to run rpix86 inside the X Window environment, even if you run your Raspberry Pi headless. The game that I am running in rpix86 is Chess Genius 3 by Richard Lang, which uses the hardware mouse cursor (shown over the "Commands" menu item) and a lot of JPO/JPE opcode special support.
7. Other JPE/JPO opcode support fixes
When adding the JPO/JPE opcode support for Chess Genius 3, I noticed that I had not ported the existing special support properly from DSx86 version to the rpix86 version. I fixed the problems in the existing support, which affected all the following games. If you have encountered weird problems in these games, they might work better in this version. Some of the names only show the executable name, as those are based on DSx86 crash logs so I have not known the actual game name:
- Amazing Spiderman
- Batman Returns
- Bubble Ghost
- BUBBOB
- CALGAMES
- F29 Retaliator
- GWBASIC
- Micro Machines 3
- STARGATE
- Super Solvers: Challenge of the Ancient Empires
- The Incredible Machine
- TOUTRUN
- Turbo Science
8. Help request
If you are graphically inclined, I could use your help with rpix86. I would like to have a rpix86-specific favicon for these web pages, and I think that rpix86 could also have its own icon, which could be used when running it in X Window environment. Also, the "box art" image that I have in the Raspberry Pi store for rpix86 is pretty horrible. If you have an idea for an icon, and/or interest in creating one, please let me know! If/when I decide to use your icon/image, I will certainly credit you on these pages. Thanks! As an example, this is what the DSx86 icon and the favicon for the DSx86 pages look like:
Again, thank you for your interest in rpix86, and please let me know of any bugs you encounter in this new version!
Mar 31st, 2013 - rpix86 v0.04 released!
Version 0.04 information
In case you are not interested in reading my whole blog post, here first is the most important information about the changes in this new version:
- Added support for 80x50 text mode. This is used by some of my old MIDI software, and also by Little Big Adventure setup program.
- Added support for USB analog joysticks (and foot pedals). Like in the old DOS days, up to 4 buttons and 4 analog channels are supported.
- Added emulation of Roland MPU-401 MIDI ports in "dumb UART" mode. All the MIDI commands are sent to /dev/midi1 device, so if you have a General MIDI synth connected to your RPi using an USB MIDI dongle, you should now get proper MIDI music out of your DOS games.
- Stripped out the debug symbol information from the executable, as that decreased the size of rpix86 to less than half of what it was.
Sudden jump in interest for rpix86
After I released version 0.03, I began working on the Android version of my emulator, as it looked like my new rpix86 release did not generate much interest (I received no emails nor any forum messages about it for the first two days after the release). I managed to create a download system for 4DOS.COM into my Android version as well. I am still relatively new to Android programming, so I was pretty proud of myself for getting this working after spending just a few hours of work on it.
Then suddenly on Tuesday evening I got several emails concerning rpix86, and also the Raspberry Pi forum thread seemed to suddenly have more views and replies than before. The same thing continued on Wednesday. On Thursday I then checked the web statistics of my rpix86 subdomain, and at first glance I thought there was some sort of a statistics error or hacking attempt going on. The normal traffic of about 50 visits per day had suddenly jumped to over 3000 visits per day!
After checking the "connected from" list of web sites, I realized that the statistics were probably correct, rpix86 had been mentioned on the Hack A Day site, and there had been over a thousand hits per day from that article alone to my web pages! No wonder the general interest had suddenly increased!
rpix86 and DOSBox relationship
In the comments of that Hack-a-day post there are some outright accusations of rpix86 being a *significant* ripoff of DOSBox. Even though everyone who reads these blog posts of mine will be able to immediately dismiss such accusations as untrue, I feel like it might be a good idea for me to address them here anyways. You can perhaps imagine that after working almost 4 years bulding my emulation core from the ground up opcode by opcode, it is pretty annoying having someone dismiss it offhand as a simple copy of some other software.
As a proof that rpix86 is a ripoff of DOSBox, one commenter has found three (3) functions that have the same names in rpix86 as in DOSBox: DasmI386, DasmLastOperandSize and op386map1. The author conveniently fails to mention that the remaining 56600 or so (based on the output of listing the symbol table of rpix86 and counting the resulting number of lines) functions in rpix86 have no counterpart in DOSbox. I would not consider 0.005 per cent similarity to be in any sense *significant*, but perhaps that is a matter of opinion.
The other issue that the author brings up is a possible GPL violation. Since I use the same names in my disassembler routine (which by the way is never executed during the normal run of rpix86, it is only used if/when rpix86 crashes) and the code seems to be very similar, the author thinks this is obviously a GPL violation. However, the debug_disasm.cpp source module in DOSBox is based on earlier work done by Robin Hilliard, which was released under Apache License (which does not force derivative works to be released as open source). His original source code is available for example here. Both DOSBox and my disassembler routines are based on this original implementation, I named my routines similarly to DOSBox simply to keep track of the bug fixes done by the DOSBox people, which I also might need to do to my version of the code. This was pretty much the first code I made into DSx86 back in the summer of 2009, and it has only had a few minor bug fixes and changes done to it after that time.
You would be hard pressed to find any other similarities between rpix86 and DOSBox, as I have made sure not to violate any licenses, and have sourced information from many other sources besides DOSBox. For example my DOS int21h emulation routines are much more closely related to FreeDOS than to DOSBox, as I used FreeDOS as an example when coding all those routines, not DOSBox.
If you are interested in the main architectural differences between my rpix86 and DOSBox, you might be interested in checking out the history of my emulation core. The roots of my emulator are explained in my earliest DSx86 blog posts, so if you are interested feel free to read them (from the bottom up if you wish to read them in chronological order):
- See here for DSx86 blog entries from July-December 2012.
- See here for DSx86 blog entries from January-June 2012.
- See here for DSx86 blog entries from July-December 2011.
- See here for DSx86 blog entries from January-June 2011.
- See here for DSx86 blog entries from July-December 2010.
- See here for DSx86 blog entries from January-June 2010.
- See here for DSx86 blog entries from 2009.
MIDI support
Last week I got an email asking whether rpix86 would support MIDI, specifically running an old DOS MIDI sequencer program. I had not thought about this possibility at all, until this email message. I began to think about this, and realized that it should not be all that difficult to have rpix86 emulate a Roland MPU-401, and then send and receive all MIDI messages to/from the /dev/midi1 device. Since I already had an EDIROL UM-1EX USB MIDI interface and still have my old Akai X-7000 Sampling Keyboard (from around 1989), it looked like I actually have everything I need to code and test support for MIDI! Well, everything except a powered USB hub, which I then purchased on my way home from work.
I then hunted for some software to use for testing, and remembered my own old MidiTracker from 1991, which I used to play MOD files via MIDI using my Akai sampler. When testing it I realized I did not yet have 80x50 text mode support in rpix86, so before I could start working on the MIDI support I needed to code support for that text mode. My MidiTracker (same as my old LineWars II game) only used the "dumb UART" mode of the Roland MPU-401, so I started by coding support for that. After some coding I managed to get both MTRACKER and LW2 to detect a Roland MPU-401 MIDI interface in rpix86, and send the MIDI notes all the way to my Akai sampler. My MTRACKER should be able to also send the MOD samples to my sampler, but for some reason this does not seem to work. The sampler never acknowledges the received MIDI SYSEX header, and I have not yet found out the problem. This should not affect any of you rpix86 users, though, so fixing this is a low priority. If you are interested in MidiTracker, it is available here as MTRACKER.ZIP. The zip contains also documentation and full source code.
Currently rpix86 only supports the "dumb UART" mode, so if a game or other software attempts to program the MIDI interface into intelligent mode, you will get various "Unsupported MPU-401 command" messages into stdout. This just means that the game will probably fail to play MIDI output.
I also found my old CH 568 CombatStick USB joystick from a closet, and now with an USB hub I was able to connect that to my Raspberry Pi as well, so I decided to code also joystick support into rpix86.
Future work
I am on vacation for the whole of next week, so I hope to work on rpix86 (and also on ax86) during that time. I hope to continue with the MIDI support, by adding the "intelligent" MPU mode support. I have also been requested to add support for running rpix86 in the X window environment, so I will perhaps look into that possibility as well. In addition there are various bugs that are waiting for fixing.
As always, thanks for your interest in rpix86, and let me know of all the bugs you find and any enhancement ideas you might have!
Mar 24th, 2013 - rpix86 v0.03 released!
Okay, yet another version of rpix86 is now available! During the previous week I first debugged some issues with the Logitech K400 wireless mouse/keyboard combo USB device, with the help of a Raspberry Pi forum user Jessie. Big thanks for the help! I noticed that my event file detection and handling routines did not properly handle the situation where the same event file sends both keyboard and mouse events. I made some changes to the routines, in addition to adding the event file number overriding parameters in the previous 0.02 version. After some iterations we managed to get the event system working properly in rpix86. After that I then implemented some other changes and missing features. The complete list of changes is here:
- Improved support for combined keyboard/mouse USB devices (for example Logitech K400).
- Fixed a problem in Mode-X STOSD opcode (fixes "Settlers" black screen).
- Implemented read from file directly to EGA VRAM ("Heimdall").
- Fixed SB command DSP_RESET to stop auto-init DMA play ("Doom").
I also decided to have rpix86.zip available for download directly from my web pages here (see the Downloads page), so that you don't need to get it from the Raspberry Pi Store if you prefer a direct download. You can of course still get it from the store, if you prefer that method.
Next I think it is time for me to work on the ax86 version for a while. You can of course still send me bug reports and enhancement requests for rpix86, especially since over 95% of the code is shared between ax86 and rpix86. If a game misbehaves on one of them, it will almost certainly misbehave also in the other version, so all game-specific enhancements and fixes will affect both emulators.
Thanks again for your interest in rpix86!
Mar 17th, 2013 - rpix86 v0.02 released!
This is a quick update to rpix86, fixing a couple of problems that have been reported to me. The included fixes are the following:
- Implemented INT2F AH=AD (KEYB installation check)
interrupt handling, so that KEYB.EXE from FreeDOS can be used in rpix86 to
enable support for international keyboards. You can download both KEYB.EXE and
KEYBOARD.SYS from FreeDOS files,
put them into the rpix86 emulation root directory, and add a line to your 4START.BTM
file to automatically load the correct keyboard layout at startup. For example,
I use the Finnish (SUomi) keyboard layout, as the following screen copy shows.
Note that rpix86 does not (yet) support loading such programs into high memory, so you should only load the KEYB.EXE at startup if you really need it. Since it will take some kilobytes from the low 640KB memory, there is a small risk that some games might run out of memory and fail to start when KEYB.EXE is loaded. - Implemented a missing EGA REP MOVSW string opcode version for Bard's Tale.
- Added two new command line parameters, -k and -m, to override the default keyboard and mouse event file detection in rpix86. By default rpix86 scans your /dev/input/by-id directory, looking for link files that contain either event-kbd or event-mouse in their name, and uses these files for keyboard and mouse event handling. If for some reason this detection fails and rpix86 quits with a message that you need to run it as root, you can try overriding this detection by giving it the event file numbers as parameters. For example, if you know that your keyboard event file is /dev/input/event1 and your mouse event file is /dev/input/event0, you can start rpix86 with parameters ./rpix86 -k1 -m0 to use those event files.
Thanks for the error logs and messages on the Raspberry Pi forum rpix86 thread, and thanks for taking the time to test rpix86! I hope to keep improving it for a while yet, based on your reports.
Mar 15th, 2013 - rpix86 v0.01 released!
Just a quick note, rpix86 is now available for download from the Raspberry Pi Store, in the "In Progress" section. Feel free to download and test it, and please report the bugs you find, so that I can improve it in the future! Thanks for your interest in rpix86!
Mar 10th, 2013 - rpix86 is ready for first release!
The last week was spent adding features needed for the public release of rpix86. The first step was to add command line parameters for things that might need user setup, like which audio output to use and where to put the C:\ root directory. If you start rpix86 with an invalid parameter (like ./rpix86 -?), it will show usage info, which at the moment looks like the following:
Usage: rpix86 [options] Possible options are: -aAUDIO where AUDIO is the audio device number, 0 = HDMI, 1 = Analog. If not given, defaults to 1 = Analog. -dPATH where PATH is full path to the emulated C:\ root directory. If not given, defaults to the current working directory. -fFILTER where FILTER is 1 when using filtered texture scaling, 0 if not. If not given, defaults to 1 = use texture filtering. -hHEIGHT where HEIGHT is the wanted screen height in pixels. If not given, defaults to the physical screen height. -wWIDTH where WIDTH is the wanted screen width in pixels. If not given, defaults to the physical screen width.
I also added echoing the command line parameters (or the default values) to stdout when rpix86 starts, which in my development machine shows the following values:
./rpix86 -a1 -d/home/pi/rpix86 -f1 -w1600 -h1200
The next step was to collect all the major still missing features into my Raspberry Pi Store product page, so that potential users have some idea about things that might not work in rpix86. Here is a list of the major problems I am currently aware of:
- rpix86 does not support x86 parity flag or auxiliary carry flag. There is some special code in rpix86 to enable running some games that use these flags, but some games simply can not be emulated because of this.
- Virtual memory is not supported. This means that Windows will not run in rpix86, nor any protected mode game that uses virtual memory. Adding virtual memory support would seriously slow down the emulation, which is pretty slow even as it is.
- Floating point opcodes are currently not supported, but this support will improve in future versions.
- Only files and directories conforming to the DOS 8.3 naming scheme are supported. No long file name support.
- Hardware mouse cursor is still missing in graphics modes. Many games use their own mouse cursor, which does work, though.
There are probably quite a few other bugs and missing features as well. If/when rpix86 encounters an unsupported situation, it will write a "crash log" into a file called rpix86dbg.log in the emulated C:\ root directory. If you send me such a crash log, I might be able to fix the issue in the upcoming versions.
I have uploaded rpix86 to Raspberry Pi Store Community Approval Process last Thursday for an "In Progress" approval, so hopefully it will get approved soon so you can download it and test it for yourself. See my download page for the download link to the Raspberry Pi store. I can also grant a private license to you if you have a Raspberry Pi Store username, so that you can test it even before it passes the approval process. You just need to let me know your username so that I can grant you a license.
Mar 3rd, 2013 - rpix86 progress
For the last week I have been working on the Sound Blaster emulation, for both rpix86 and ax86. Last Saturday I had managed to get the simple one-shot DMA digital audio working, and I then spent both Sunday and Monday trying to get the auto-init version working. I used Doom to test that, as it uses a 4096-sample buffer with an IRQ request after every 128 samples. Since it plays audio at 11.1kHz while I mix and play the audio (in both rpix86 and ax86) at 32kHz sample rate, those 128 input samples will create around 370 output samples. As I am playing the audio using two 2048-sample buffers, I needed to split the buffer filling in my audio thread so that the game has time to handle the emulated Sound Blaster IRQ and generate new samples several times during my playing of a single 2048-sample buffer. This was pretty difficult to get working correctly, as the sample creation and playing are both very time-critical functions that need to be scheduled properly to not cause any audio dropouts.
In the end I managed to get the auto-init digital audio working using a system where I generate 256 output samples at a time, and then use usleep() in the audio thread to let the main thread generate new samples that the audio thread will then play after it wakes up from the sleep. I also tested this with both 128 samples and 512 samples instead of the 256 samples, but the first one caused even more severe performance hit to the overall emulation speed, and the latter in turn caused very noticeable intermittent audio dropouts.
On Tuesday I then began working on the ADPCM audio playing routines. To test these I used Duke Nukem 2, which is a nice test bench as it uses all three different ADPCM formats (4-bit, 2-bit and also 2.6-bit). It took me several days to get this working, as I (foolishly, it turned out) based the code on the functions I had created for the old (pre-transfer-system-change) DS2x86. When testing them I realized that the algorithm I used there was seriously incorrect. When adjusting for the sample rate differences while playing ADPCM samples, it is of course NOT correct to interpolate over the original ADPCM-encoded values! I need to decoded the ADPCM samples to a separate buffer first, and only then interpolate over these decoded samples, to not cause additional artifacts to the audio. It took me up to Saturday to get the fixed routines working.
On Saturday I also implemented a system into rpix86 to automatically download 4DOS.COM if it is missing. This will help people not familiar with my DSx86 to get started with rpix86. I can not bundle 4DOS.COM into the rpix86.zip file as I do not have the rights to distribute it. Since 4DOS.COM is freeware I think there is no problem for me to add a download feature for it into rpix86 and ax86, though.
I began my work on rpix86 today by first implementing PC Speaker audio features (which was relatively easy after figuring out the proper frequency conversion value) and then worked on the one remaining SoundBlaster audio feature, direct 8-bit DAC output. I used Jill of the Jungle (which plays direct DAC audio at 6kHz for audio effects) to test this. Currently it sort of works, but the audio quality is very poor and glitchy. Since direct DAC audio is very timing-critical (it uses a timer that generates and IRQ at over 6000 times per second, where each timer IRQ generates just a single audio sample) it is not well suited to a multitasking operating system, I doubt this type of audio will ever sound very good in rpix86 or ax86. Luckily not very many games use that technique.
Today I also worked a bit on my Raspberry Pi Store page for rpix86, I even tested uploading the software there (it is not yet available for download). I think I will be able to release some sort of a work-in-progress version after I just add some more configuration options and such. Currently rpix86 is hardcoded to show graphics on the HDMI display and play audio using the analog headphone output (which is my current setup). I plan to have command line parameters to show the screen on either HDMI or the analog output, and similarly to play audio either via HDMI or analog output. Then I just need to add some usage info, describe the known problems and missing features, and then rpix86 might be ready for the first release! Could be as soon as by next weekend. :-)
Feb 17th, 2013 - rpix86 progress
The last week was spent working on getting rpix86 to the same level as where ax86 currently is. I began the week by changing the CGA and EGA graphics blitting routines to also use the new OpenGL ES2 palette handling system. Since both the CGA and EGA (and also some Mode-X versions) use non-contiguous graphics memory organisation, I decided to still use a separate 256-color off-screen buffer which is then given to the glTexSubImage2D OpenGL routine as input. In the MCGA and SVGA 256-color modes I can use the emulated 0xA000 segment VRAM directly as input for the texture subimage routine, and I also added a system where I can build the texture from two subimages for cases where the Mode-X version uses a LineCounter to split the screen into two areas (like for example in my LineWars II game).
After the graphics modes were implemented I decided to add a screen capture system (so that I can add some pretty pictures to these blog posts, and also to have some screen copies on the Raspberry Pi Store when I eventually release rpix86 there). Here is the first screen capture I took, from the Norton Sysinfo CPU performance test page. The "80486, 53MHz" estimation is based on the division opcode speed, so it does not give a proper overall performance estimate. The performance bar is a better indicator as it actually runs various opcodes using a timer. The speed is around a 80386 40MHz machine, which translates to a 80486 20MHz machine. So not especially fast as my DS2x86 running on a MIPS processor at 396MHz is about as fast. I suspect the Linux operating system itself causes quite a performance hit (in addition to my having to emulate almost everything on a single CPU, while in DS2x86 I was able to divide the emulation chores between 3 separate CPUs).
After I got the screen capture working, I decided to redo my AdLib emulation to be a bit faster. In DSx86 my AdLib routine always calculates all the samples for all the 9 AdLib channels even when the channels are not active. This was not a problem in DSx86, as I used the otherwise idle ARM7 secondary processor to run this emulation. However in rpix86 and ax86 I need to use the main CPU also for the audio emulation, so it would be better to have it use as few CPU cycles as possible. I implemented a simple cycle counter to count the cycles spent in my AdLib emulation, and ran it first without any changes. I used the Silpheed game to test my changes, mainly just because it has pretty nice AdLib music. :-)
The original algorithm used 734.000 CPU cycles to mix and calculate 2048 samples for all 9 channels when no channel was playing audio, and up to 1.000.000 CPU cycles in Silpheed. Each channel consists of two "slots" which both produce a sample, but the first slot is usually used as a phase modulation for the second slot, instead of directly generating audio. So each sample for each slot takes about 27 CPU cycles to create. This number includes also the initial buffer clearing and all envelope and modulation handling, as I put my cycle counting routines around the whole AdLib emulation subroutine.
After some experimentation I found out a way to skip the channels that are not currently active. This is not quite as trivial as it sounds, as there is no "active" flag for the channels. If the virtual "key" (as in a piano key) is turned off, the sound will slowly fade based on the release envelope, so I can not just check whether a key is on and skip a channel if not. Also, if the slot is used as a phase modulation input for the second slot, turning this modulation off too early generates incorrect sound. I used a combination of key off, envelope phase and current volume to determine when it is safe to skip a slot. I managed to get the CPU usage down to 60.500 cycles when no channels are playing, and to around 470.000 cycles in Silpheed. It is not very common that all 18 slots are actually generating sound at any one time during a song, so this slot skipping will help the performance also during music playing.
The next step was to add mouse support, which turned out to be quite easy for rpix86. I haven't yet implemented this in ax86, where I need to use the touch screen system for mouse emulation. In rpix86 I can simply use the real mouse input. Next I will continue working on the still missing features, like floating point support, various graphics operations that are still missing, etc. Here below is a screen capture from Little Big Adventure which I just got working. There are still some small palette problems in it, which I will need to study more closely.
Feb 10th, 2013 - rpix86 progress
During the past week I have continued working on rpix86, to get it up to the same level as where my ax86 currently is at. Here is a sort of a timeline for last week, the improvements and other things I have managed to get implemented.
- First, I found a very interesting technique by a Raspberry Pi forum member Andrey for using the OpenGL ES hardware vertex and fragment shaders to perform the palette lookup table handling in hardware from the Raspberry Pi forum Atari 800 emulator thread. I spent a couple of days converting this code to plain C (as I am not very familiar with C++ and prefer to work with C) and changing it to work in my rpix86 environment. The converted code is available here as gles_video.c in case you are interested in it. This speeds up the graphics rendering considerably especially in the 256-color modes. I still need to do some changes to my code to have it handle all the Mode-X variations and such, but in any case this was a very useful technique!
- I also joined the Raspberry Pi forums myself, and created a thread for rpix86 there. So, if you have questions about rpix86 that might interest other future users, feel free to post on that thread!
- Next, I spent some time to get cycle counting working on my Raspberry Pi. I found a
blog post
explaining the required steps, but sadly the kernel module that was included was not compatible
with the kernel that my Raspberry Pi uses. However, it turned out that simply using a hex editor
to change the vermagic string in the module to match the kernel one allowed the module to load.
I'm sure hacking the module like this is something that should not be done, but hey, it works! :-)
I also noticed that the blog post does not mention that by default the counters are disabled,
so you need to enable them with:
.global ccnt_enable ccnt_enable: mov r0, #1 @ Enable all counters mcr p15, 0, r0, c15, c12, 0 bx lr
After I got the cycle counters working, I implemented the same profiler features into rpix86 as what I used in DSx86. I ran Doom several times to determine the slowest opcodes, and it turned out that most time is spent in a simple opcode 0x8A (mov reg8,r/m8). It looks like Doom uses a lot of SIB (Scaled Index Byte) versions of that opcode, and my SIB byte handling is not very optimal. I have been trying to figure out ways to improve that, but so far have not been able to come up with anything noticeably faster. - After getting tired of playing with the profiler, I decided to look into audio support, namely porting the AdLib audio support to Raspberry Pi. I just an hour ago managed to get this working, and it looks like the audio latency is much better in RPi than what it is on the OpenSL system I use on Android. However, adding even AdLib audio to Doom made it again run considerably slower than before.
- The next step is to change the EGA (16-color) modes to work with the new OpenGL ES rendering technique, and after that rpix86 is pretty much at the same level as ax86.
Feb 3rd, 2013 - rpix86 started!
On last Thursday I decided to order a Raspberry Pi computer, as I have been toying with the idea of porting DSx86 to it as well as to Android. It arrived on Friday, and I could not resist the temptation to start working on it immediately. Thus I began to experiment with porting my current ax86 version to it. The Friday evening was spent in an attempt to create my own Makefile system to compile ax86 (or rpix86 as I decided to call it), but after miserable failures and considerable frustration (it turns out I am really NOT a Makefile guru!) I decided to copy the Makefile system from Nintendo DS DevKitARM pretty much as-is, as it seems to work nicely and I am familiar with it. Using that I got practically all the code to compile on Friday, but the hardware-specific stuff was still missing, so it did not actually run yet.
I continued this work on Saturday, and finally by Saturday evening I was able to get 4DOS to start up inside rpix86 on a Raspberry Pi! I still don't have any input (like keyboard) support on the Raspberry Pi side, so I just added a frame counter that exits the program after a few seconds, but still it was nice to see that I can use pretty much the same code for both Android and Raspberry Pi. From now on I think I will work on those two versions side by side, as I added some compile defines to places where I need to do things differently between those two, and most of those places are in a single source code module which contains the native interface.
It also looks like I will be able to do some development things (like using a cycle counter to help me optimize some routines) more easily on the Raspberry Pi than on Android. Eventually I will probably want to add some processor-specific optimizations to my code, so that will cause differences between the versions (since RPi has ARMv6 and modern Android devices have ARMv7 processors), but for now I can work on both at the same time.
Next I will probably spend some more time on the Raspberry Pi side to get it at the same level with the Android version (namely to get keyboard and AdLib support working), after that I need to add mouse support and floating point support to both, as those are the things that currently limit the number of games I can test on ax86/rpix86. Then I will need to add SoundBlaster digital audio support, implement the missing graphics features, and so on, so there is still quite a bit of work ahead before the eventual public release.