For the last week I have continued working on the paging features for DS2x86. This time I have managed to make some visible progress, as Descent 2 Demo goes to graphics mode properly, and at times I can even reach up to the main menu! However, this happens only in about once every six attempts or so, in other cases it crashes with a failure in some internal sanity checks I have in my protected mode opcodes. I believe these crashes are mostly due to the (silly) game not keeping the stack pointer doubleword-aligned, which makes the stack access occasionally needing to read a doubleword from two separate 4K pages, which is not yet supported. The frequency of this happening depends on the timing of the hardware timer interrupts etc, so it rarely happens in the same place.

So, the next step is to improve the data accesses, first for the stack opcodes and then for all the other opcodes, to also handle the possible page discontinuity properly. I have already handled this discontinuity in some opcodes, like the REP MOVSD string handler, but it is still missing from a lot of other opcodes. The CS:EIP handling code that I described in the previous blog post seems to work properly at the moment, so I can focus on the data access from now on.

Since checking for page discontinuity is a rather slow operation, I have been toying with the idea of attempting to use the hardware (the MIPS processor memory management unit) in some way to help with the virtual memory implementation. I only yesterday thought about this, and tried to test what the current hardware TLB contains. It seems to not contain anything sensible, which probably means that the TLB feature of the hardware is not actually used by the DSTwo SDK. It seems that all the memory accesses are to the 0x80000000 memory area, which the MIPS32 documentation describe as "Kernel Unmapped" area. Unmapped here means that the TLB hardware is not needed, the memory is mapped directly to the beginning of the physical memory. The virtual memory area between 0x00000000 and 0x7FFFFFFF is called "User Mapped", so that would use the TLB hardware to map virtual addresses to physical RAM (and accessing it currently always generates a "TLB miss" exception since the TLB table values are all invalid). It would be neat if I could use the TLB to map the first 16 megabytes (virtual addresses 0x00000000 - 0x00FFFFFF) directly to my emulated DOS RAM area using the TLB, as in that case the hardware would do the memory translation and I could get rid of my EMSPages mapping table!

This direct mapping would be quite simple if the game does not use virtual memory (or even EMS memory) and uses MCGA graphics, as then I could set up a single TLB entry mapping all 16MB of RAM at virtual addresses 0x00000000 - 0x00FFFFFF to my emulated RAM area. However, as soon as EMS memory or EGA or Mode-X graphics are needed, things get more complicated. In this situation I could divide the area into 16KB pages, but since the TLB table in MIPS32 only has 64 entries, that could map only the first 1MB of RAM. Nice for real mode programs, but for protected mode I would need to handle the hardware TLB misses with a fast exception handler (the documentation tells that the TLB miss exception uses a different vector to the common exception handling vector, and I have not been able to determine from the DSTwo SDK where this special exception handler should be). Even more difficult will be the situation with virtual memory, as only the addresses below 0x80000000 can be virtualized, the addresses above that would simply fail horribly when the game will access my emulator code instead of the emulated data or code. So, I am not yet sure whether it is worth it to look into this possibility further, but it is an intriguing idea.