PCSX2 Documentation/PCSX2 EE Recompiler
WORK IN PROGRESS I think it is about time that I start to contribute to this project ;)
It is a summary of my understanding of the EE recompiler. The idea is to collect the key information on the recompiler. It is interesting as a general info and it would be useful to port/improve it one day.
Global Overview of the EE recompiler
The big step of the recompiler 1/ The recompilation phase of a PC. It will compiled as a block. The block is stored in a buffer called x86Ptr. 2/ The execution phase. Block is executed. 3/ The pause phase. The purpose is to emulate the others HW block (VU, GIF, DMA etc..) In particular EE interrupts are handled here.
Block internal structure:
[code] static R5900LutReserve_RAM* recLutReserve_RAM = NULL; [/code] Main BASEBLOCK array buffer. Each BASEBLOCK contains a function pointer to a x86 generated code. (around 36MB is allocated for recLutReserve_RAM , note there is a waste of ~4MB for the ROM)
The buffer is indirectly accessed through a Lookup table called recLUT [code] static __aligned16 uptr recLUT[_64kb]; [/code] Basically the RAM memory is splitted in 32MB zone. It is more complex for ROM, but boot ROM isn't really important to emulate.
You can get current BASEBLOCK of the PC with the macro [code] PC_GETBLOCK(pc) [/code]
There is also an hardware lut. It cheaply converts a virtual address to the physical address (static TLB)
All those blocks are managed by the BaseBlocks class. [code] static BaseBlocks recBlocks; [/code]
_DynGen_* functions generate dispatcher functions and return a function pointer to the function. Full initialization is done in _DynGen_Dispatchers.
- JITCompile (generated by _DynGen_JITCompile) will
1/ Call recRecompile(cpuRegs.pc) to recompile the current block 2/ Jump to the recompiled block PC_GETBLOCK(cpuRegs.pc)->m_pFnptr()
Basically all BASEBLOCK will contains JITCompile as init address.
- JITCompileInBlock (generated by _DynGen_JITCompileInBlock)
1/ Jump to JITCompile
Basically after the compilation of BLOCK of size N. First BASEBLOCK will contains the x86 address. The remaining N-1 BLOCK will contain JITCompileInBlock.
- DispatcherReg (generated by _DynGen_DispatcherReg) will
1/ Jump to the current block (Note. Stack won't be realigned)
- EnterRecompiledCode (generated by _DynGen_EnterRecompiledCode) will
1/ Setup the base frame pointer 2/ Align the stack pointer 3/ Save edi/esi/ebx on the stack 4/ Simulate a function call? (potentially to help debugger to unwind the stack) 5/ Simulate the stack frame preparation "push ebp, mov ebp, esp" 6/ Save esp, ebp into static variable (for debug check). Code can surely be removed. 7/ Jump to DispatcherReg 8/ Handle the return of DispatcherReg (Leave and restore edi/esi/ebx) 9/ Handle the return of current function (leave and ret)
- ExitRecompiledCode is the return address of DispatcherReg (end of EnterRecompiledCode)
- DispatchBlockDiscard (generated by _DynGen_DispatchBlockDiscard) is a wrapper to the C++ function dyna_block_discard
- DispatchPageReset (generated by _DynGen_DispatchPageReset) is a wrapper to the C++ function dyna_page_reset
The details of the "recompilation" stage Input: the PC (first instruction address) Output: x86 code in a buffer that is ready to be executed.