PDA

View Full Version : DSx86 version 0.39



wraggster
September 26th, 2011, 00:52
via http://dsx86.patrickaalto.com/

DSx86 release notes
This version has only one small fix, the smooth scaling changes I made in the previous version introduced a screen flickering problem when attempting to scroll the smooth-scaled screen. This also happens when the Touch Pad Mouse cursor got near the screen border in modes that do not need scrolling, like in 640x480 mode. This problem was caused by my changing the REG_BG3Y hardware scaling register after the screen blitting function, and as the screen blitting took longer than one VBlank period, this change also occurred at a time when the screen was already active. This register should not be changed during active screen scanning time, or flickering will occur. In this version I moved the setting of this register to before the screen blitting code, so there should not be any flickering any more.

DS2x86 progress
During the last week I have continued working on the paging features. I finally figured out a way to handle the most serious problem I have been having with the paging system, the possible page discontinuity in the code segment that I described in the September 4th blog entry below. The proper method to handle this would be to look up every single byte from the EMSPages[] LUT, but that would really kill the performance (not to mention be a really big task to implement), so I did not want to do that. Instead, I figured out that since I already need to keep the physical and logical memory addresses separate, it would not be a big problem to actually move the problematic code into some completely separate memory area, and handle the discontinuity (that is, generate a continuous code snippet) when copying the code from two separate physical 4K pages!

So I added some (self-modifying) code to my main opcode loop to perform these operations:

If paging is on and the current physical CS:EIP address is near the end of this 4K page ((physical address AND 0xFFF) >= 0xFF0), then jump to a special code that does the following:
If we have already relocated the 32 bytes, jump back to handling the opcode normally.
Check if the next logical 4K page exists in physical memory, and cause a Page Fault if it does not (handling a Page Fault will eventually restart the opcode).
Relocate the 32 bytes around the page border (that is, 16 bytes from the end of the previous 4K page and 16 bytes from the beginning of the next 4K page) into emulated BIOS area at F000:3FF0 - F000:400F (actually it could be anywhere, but this was a nice free already existing space).
Adjust the physical CS:EIP pointer and the physical-to-logical adjustment value so that the code continues executing within this new relocated area.
Self-modify the opcode loop to first call a special code described below.
Continue with the normal handling code.
The opcode loop may be self-modified to jump to a special code which does the following:
Test if we are still at the end of the 4K page ((physical address AND 0xFFF) >= 0xFF0). If we are, jump to continue the opcode handling normally.
Else, re-adjust the physical CS:EIP and the physical-to-logical adjustment value to point to the actual physical RAM address of the 4K page instead of the relocated area.
Self-modify the opcode loop back to using the normal handling code.
Continue with the normal handling code.

With these changes I can still use the quick linear memory access when loading the opcodes and their immediate bytes, and this special code (which is rarther slow) is only executed when we are about to cross a page boundary. Here is an example of one such occurence, this actually causes a Page Fault as the page starting at logical address 0x100EA000 is not loaded into physical RAM when this code gets executed:

...
0268:100E9FF3 E8E39F0000 call 100EDFDB ($+9fe3)
0268:100E9FF8 C705713D131001000000 mov dword [10133D71],00000001
0268:100EA002 B825A00E10 mov eax,100EA025
0268:100EA007 E8358CFFFF call 100E2C41 ($-73cb)
...

As you can see the opcode at address ...FF8 consists of 10 bytes, and it is actually only the last two bytes that are in the next page. In DOSBox the Page Fault happens when it loads the second-but-last byte of this opcode, in DS2x86 the page fault happens already when the code reaches the ...FF3 address (because at that point it needs to relocate the 32 bytes). When this code gets relocated into the F000:3FF0 area, it looks like the following (in the DS2x86 inbuilt debugger):


The call target addresses look different, as they are relative to the current logical IP. The handlers for all the opcodes using relative jumps will need to be aware of the possible relocation, but luckily this needs to be the case even without this relocation trick I use, since the paging itself can relocate the logical addresses within the physical RAM. Also note that only the opcodes at addresses ...FF3 and ...FF8 are actually executed from within this relocated area. When the emulator reaches the opcode at ...002, it uses the second part of my special handling code which goes back to executing the opcodes from their proper physical (and logical) addresses.

The current status with the paging features is that Descent 2 Demo begins to misbehave after Page Fault number 102, and Warcraft 2 runs up to Page Fault number 192. After that they both crash with an invalid Task Switch IRET. My current theory is that the timer interrupt that should play AdLib music interferes with the Page Fault task switches, and that causes the problem. I need to continue debugging this, but I am pretty happy with the progress I have finally been able to achieve with the paging system during the last week.