The dynamic recompiler uses a simple register mapping for currently used
registers to reduce memory access for operations. The content of these
registers have to be saved back to the memory region containing the emulated
register bar before they will be remapped or may get damaged by an unsave
operation.
Emulated operations in the amd64 dynamic recompiler tried to avoid the complex
register free'ing operation before an call to a C function by storing the
content of mapped registers to the stack. This implementation is faulty because
* the return address (top most stack position when the dynamic recompiler
started a recompiled block) may get written during the execution of the C
function. The problem is that the return address is moved to another
position when the registers were stored in the stack and therefore the
content of a saved register gets damaged by this write.
* the called C function may want to access the content of an emulated
register. This is done by reading the content of the emulated register bar
in memory. This read will return an outdated value because the new value is
only stored on the stack.
This problem can be avoided without more complicated checks by not saving the
content on the stack and instead unmapping the registers and saving their
content in the emulated register bar.
It is possible that the config parser changes a type of an option from any
other type to string. A string is actually only a pointer to another memory
region storing the string. ConfigSetParameter will try to free the old value in
hope to avoid memory leaks. This is a problem when the pointer shares the same
memory region as the previously stored value. The free(..) will try to free a
different part and create a crash at a later point.
I'm not sure if the implementation is correct, maybe the SP interrupt must be sent anyway and only the DP interrupt is delayed. Also there's still some polygon glitches and 'DIV_S by 0' errors, but at least it kinda works now, and documents what was wrong with it.
- Add all the necessary COP1 unusable checks everywhere. There were some checks which were only on pure interpreter, and some which were only on cached interpreter.
- Add the DIV by zero checks to the interpreter codebase (was only in pure interpreter)
- Minor code fixes
I did some small timing tests and I found no relevant difference between the old and the new pure interpreter implementation. So for now I'll center on fixing things.
I'm not sure if NOTCOMPILED is correct, just because the old code was a bit weird and maybe there was a reason for it.
Also, this adds support for executing code from SP_IMEM (this happens on a PIF boot).
Before last commit, SP_INT ORed sp_status_reg with 0x303 (signal1, signal2, halt, broke), but only set the byte flags for signal2, broke, halt (the line for signal1 was commented). This caused a desync between the status reg and the byteflags. Next time update_SP was called, the register was rebuilt using the flags, so signal1 was unset from the status reg.
This commit does not set the signal1 bit in the sp status reg (which is consistent with the taskdone() function on the HLE RSP and the most likely previous behaviour), but this may change behaviour (for the better).
By the way, last commit also changed the way Project64 TLB entries were written, not sure why. I believe they are written correctly now since I'm writting the same register values that are set in the TLBWI/TLBWR instruction. Anyway, I don't think TLB was working anyway since EntryDefined was never set (now it's always set, so it may still not work). This needs more testing agains PJ64.
The big file size increase should stop now, and maybe some cleanup will make up for it.
In addition, this fixes two other bugs to the PJ64 saving code: A out-of-bounds error when writting zeroes to the FCR1..31 field, and a uninitialized value error when writting the EntryDefined field of the TLB.
So far only the code to read savestates has been modified. There's no error checking yet, but should be easy to add. A test to load a savestate from another endianness has been successful.
There has been a noticeable file size increment, but there's hardly any way to avoid it. I expect to be able to remove some code from other parts of the emulator once this task has been completed and structures can be modified freely.