It was in November last year when I last released a version of the original DSx86, so I wanted to spend some time bringing it closer to the current level of DS2x86. Here is a list of the fixes and improvements I had time to add into it, during the past week:
The new experimental proportional font system was originally implemented by "sverx" a few weeks ago, after we had a discussion about various possibilities to fit the whole 80x25 text mode area into the NDS 256x192 pixel screen. I asked him whether a proportional font would be possible, and he then spent some time experimenting. After looking at the results we agreed that the system might actually work. I have been busy with DS2x86 so I only had time to implement his algorithm into DSx86 this weekend.
- Further "Jitter" mode screen scaling quality improvement.
- Implemented "scasb" opcode EGA VRAM access version (Titus the Fox).
- Implemented INT 6 (illegal opcode) for opcode 0x66 (Titus the Fox).
- Fixed the VideoParameterTable to have correct VGA Misc Register values in text modes.
- Fixed the "Smooth" mode initialization when used in dsx86.ini.
- New experimental proportional font used in 80x25 text "Smooth" mode.
The algorithm divides the horizontal 256 pixels (for 80 characters) into four blocks of 64 pixels (20 characters), and then draws characters from a 4x8 pixel font, using only 3 or even 2 pixels for narrow characters (like a space, 'i' and 'l'), and if that still results in more than 64 pixels, the algorithm forcibly strips some other characters down to 3 pixels as well. Thus, when you type on the command prompt also the previously typed characters may move, and the cursor position is only an approximation.
Here are some examples of the result. The SYSINFO screen looks a bit weird, as the algorithm has had to move the line drawing characters around in an attempt to make the text parts readable. However, even with that problem, the text is far clearer than what the "Scale" or "Jitter" modes will achieve.
I was also requested to look into Titus the Fox, so I implemented a few previously missing features to make it run. However, there are still problems with the palette, so the game does not look quite correct. It does look correct in DS2x86, as there I use separate EGA and VGA mode palettes. In DSx86 I have only a single palette which attempts to work in both modes, and due to the way that game changes the palette registers the result is not quite correct. I plan to look into this problem in the future versions, but it might be a bit tricky to fix without causing problems in other games.
DS2x86 and Little Big Adventure
After releasing the latest DS2x86 version, several games needing VESA SVGA screen mode have managed to at least start up. One of them is Little Big Adventure (LBA). However, there is a problem in the current DS2x86 that makes LBA hang whenever a key is pressed. I spent a little while looking into this problem, and found out that it is caused by DS2x86 not clearing the "Buffer Full" bit in the keyboard status register. The LBA keyboard reading is programmed so that it loops reading the keyboard data register until the "Buffer Full" bit is clear, and thus the game hangs after a key is pressed.
There is a way to hack the game using the DS2x86 inbuilt debugger, so that the game will not hang. Here is the procedure for doing that. Note that the actual values may change a bit depending on the version of LBA you have, so I try to give instructions about how to find the correct address to hack.
Note that this only changes the instance that is running, so the next time you start LBA you need to do this again. However, the next version of DS2x86 has this problem fixed, so if you don't want to experiment or have trouble locating the correct opcode, you only need to wait for a week or so until I get the next DS2x86 version released. DS2x86 progress
- Start LBA on DS2x86, and let it run up to the initial "Little Big Adventure" splash screen.
- Press a key, so that LBA hangs.
- Click on the X button on the top right of the virtual touchpad keyboard, to drop into the debugger. You should get something like the following showing on the bottom screen:
The important things to check here are that the second row shows CPU: PROT, USE32, CPL=0, Paging=0. Also, there should be a row stating DS=0160 ES=0160 SS=0088 CS=0158, and below the "NV UP ..." etc row the number should start with 0015 with 4 numbers or letters folowing.
- If the important values mentioned above are not similar to what you got, simply click on the G (for 'Go') character on the bottom row, and then on the rightmost v character (which is 'Enter') to continue the game, and then try dropping into the debugger again. Note that if you make a mistake and click on the wrong character, you can use the < symbol (for 'Backspace') to erase the last typed character.
- Next, we need to find the location in the code where the game tests for the "Buffer Full" bit. This is done by opcode in al,64 followed by opcode test al,01. In my version of LBA those two opcodes are at addresses 159D76 and 159D78, like this:
To look for those opcodes, let's first check whether your version is the same as mine, so using the bottom row, give the following command: U159D60 and click on the rightmost v. If you can see the in al,64 and test al,01 opcodes in the result, check the address of the test al,01 opcode and add one to it. Note that the addresses are in hexadecimal notation, so the next number after 9 is A, not 10. In my case the address we are interested in is 159D79.
- If you can not see those opcodes in your case, then you need to look for them, starting from where ever you dropped into the debugger. The keyboard reading code in my version of LBA is at addresses 159C81 .. 159D7A, with the location we want being very near the end of that area. So, depending on where you dropped into the debugger in your version of LBA, you should be able to locate those opcodes after a few tries.
- After we have found the opcode, we need to change it. That is done with the E command in the debugger. In my case the full command is E158:159D79 2, that is, we want to change the bit 1 in the test al,01 to 2, so that the opcode will become test al,02. This will always return zero, so the game will continue.
- After giving that command, you may use the U command again to check that the opcode did actually change.
- If the opcode was changed, give the G command (for 'Go'), and now the game should not hang after a key press any more!
I have also done some minor improvements to DS2x86 during the past week. One was that LBA keyboard status bit fix, and I also worked on improving the quality of the scaled SVGA screen modes. I changed the SVGA graphics transfer code to transfer 512x240 pixels instead of the 320x240 pixels per frame. This dropped the maximum framerate down to 38 fps, but since the original code did not quite reach 60 fps either, this has no noticeable effect. However, moving more data allows me to have more pixels on the NDS side to scale, so the scaling quality will improve.
Lastly, I also debugged a SoundBlaster problem in Mortal Kombat. It did play SB sound effects, but they were just screeching instead of proper samples. I found out that the physical RAM address where my SB emulation tried to play the samlples was at the beginning of the emulated RAM area, which meant that the program had given a zero address for the sample memory area! I debugged the game also on DOSBox, and thre I found out that the game detects SoundBlaster by first attempting to use DMA channel 0, checking for a SB IRQ, and if it does not happen, moving on to DMA channel 1 etc. In DS2x86 I only emulate DMA channel 1, but I launched an SB IRQ regardless of the DMA channel in use. Thus the DMA 1 address was left at zero, but the game detected SB at DMA channel 0, and then used that channel within the game as well. I fixed that by skipping SB IRQ launching if the correct DMA channel is not running, and this fixed the SB problems in Mortal Kombat.
I am currently attempting to find the nasty bug that causes both Warcraft 2 and Command & Conquer to crash with an BSOD exception that only shows the beginning of the exception string. It looks like this is caused by something clearing much of the RAM area, so that also the error strings get cleared. I have not been able to find out what causes this, but I'll keep working on this during the next week.