// iR3000A.c assembly routines // zerofrog(@gmail.com) .intel_syntax .extern psxRegs .extern psxRecLUT .extern psxRecRecompile .extern b440 .extern b440table #define PS2MEM_BASE_ 0x18000000 // has to match Memory.h #define BLOCKTYPE_STARTPC 4 // startpc offset #define BLOCKTYPE_DELAYSLOT 1 // if bit set, delay slot #define BASEBLOCK_SIZE 2 // in dwords #define PCOFFSET 0x208 #define PSX_MEMMASK 0x5fffffff #ifdef __x86_64__ #define REG_PC %edi #define REG_BLOCK %r12 #define REG_BLOCKd %r12d .extern EEsCycle .globl R3000AExecute R3000AExecute: push %rbx push %rbp push %r12 push %r13 push %r14 push %r15 //while (EEsCycle > 0) { Execute_CheckCycles: cmp dword ptr [EEsCycle], 0 jle Execute_Exit // calc PSX_GETBLOCK // ((BASEBLOCK*)(recLUT[((u32)(x)) >> 16] + (sizeof(BASEBLOCK)/4)*((x) & 0xffff))) mov %eax, dword ptr [psxRegs + PCOFFSET] mov REG_PC, %eax mov REG_BLOCKd, %eax shl %rax, 32 shr %rax, 48 and REG_BLOCK, 0xfffc shl %rax, 3 add %rax, [psxRecLUT] shl REG_BLOCK, 1 add REG_BLOCK, [%rax] mov %r8d, [REG_BLOCK+4] mov %r9d, REG_PC and %r8d, 0x5fffffff and %r9d, 0x5fffffff cmp %r8d, %r9d jne Execute_Recompile mov %edx, [REG_BLOCK] and %rdx, 0xfffffff // pFnptr jnz Execute_Function Execute_Recompile: call psxRecRecompile mov %edx, [REG_BLOCK] and %rdx, 0xfffffff // pFnptr Execute_Function: call %rdx jmp Execute_CheckCycles Execute_Exit: pop %r15 pop %r14 pop %r13 pop %r12 pop %rbp pop %rbx ret // jumped to when invalid psxpc address .globl psxDispatcher psxDispatcher: // EDX contains the current psxpc to jump to, stack contains the jump addr to modify push %rdx // calc PSX_GETBLOCK // ((BASEBLOCK*)(recLUT[((u32)(x)) >> 16] + (sizeof(BASEBLOCK)/4)*((x) & 0xffff))) mov %eax, dword ptr [psxRegs + PCOFFSET] mov REG_PC, %eax mov REG_BLOCKd, %eax shl %rax, 32 shr %rax, 48 and REG_BLOCK, 0xfffc shl %rax, 3 add %rax, [psxRecLUT] shl REG_BLOCK, 1 add REG_BLOCK, [%rax] // check if startpc&PSX_MEMMASK == psxRegs.pc&PSX_MEMMASK mov %eax, REG_PC mov %edx, [REG_BLOCK+BLOCKTYPE_STARTPC] and %eax, PSX_MEMMASK // remove higher bits and %edx, PSX_MEMMASK cmp %eax, %edx je psxDispatcher_CheckPtr // recompile call psxRecRecompile psxDispatcher_CheckPtr: mov REG_BLOCKd, dword ptr [REG_BLOCK] #ifdef _DEBUG test REG_BLOCKd, REG_BLOCKd jnz psxDispatcher_CallFn // throw an exception int 10 psxDispatcher_CallFn: #endif and REG_BLOCK, 0x0fffffff mov %rdx, REG_BLOCK pop %rcx // x86Ptr to mod sub %rdx, %rcx sub %rdx, 4 mov [%rcx], %edx jmp REG_BLOCK .globl psxDispatcherClear psxDispatcherClear: // %EDX contains the current psxpc mov dword ptr [psxRegs + PCOFFSET], %edx mov %eax, %edx // calc PSX_GETBLOCK // ((BASEBLOCK*)(recLUT[((u32)(x)) >> 16] + (sizeof(BASEBLOCK)/4)*((x) & 0xffff))) mov REG_BLOCKd, %edx shl %rax, 32 shr %rax, 48 and REG_BLOCK, 0xfffc shl %rax, 3 add %rax, [psxRecLUT] shl REG_BLOCK, 1 add REG_BLOCK, [%rax] // check if startpc&PSX_MEMMASK == psxRegs.pc&PSX_MEMMASK mov REG_PC, %edx mov %eax, REG_PC mov %edx, [REG_BLOCK+BLOCKTYPE_STARTPC] and %eax, PSX_MEMMASK // remove higher bits and %edx, PSX_MEMMASK cmp %eax, %edx jne psxDispatcherClear_Recompile mov %eax, dword ptr [REG_BLOCK] #ifdef _DEBUG test %eax, %eax jnz psxDispatcherClear_CallFn // throw an exception int 10 psxDispatcherClear_CallFn: #endif and %rax, 0x0fffffff jmp %rax psxDispatcherClear_Recompile: call psxRecRecompile mov %eax, dword ptr [REG_BLOCK] // r15 holds the prev x86 pointer and %rax, 0x0fffffff mov byte ptr [%r15], 0xe9 // jmp32 mov %rdx, %rax sub %rdx, %r15 sub %rdx, 5 mov [%r15+1], %edx jmp %rax // called when jumping to variable psxpc address .globl psxDispatcherReg psxDispatcherReg: //s_pDispatchBlock = PSX_GETBLOCK(psxRegs.pc); mov %eax, dword ptr [psxRegs + PCOFFSET] mov REG_PC, %eax mov REG_BLOCKd, %eax shl %rax, 32 shr %rax, 48 and REG_BLOCK, 0xfffc shl %rax, 3 add %rax, [psxRecLUT] shl REG_BLOCK, 1 add REG_BLOCK, [%rax] // check if startpc == psxRegs.pc cmp REG_PC, dword ptr [REG_BLOCK+BLOCKTYPE_STARTPC] jne psxDispatcherReg_recomp mov REG_BLOCKd, dword ptr [REG_BLOCK] #ifdef _DEBUG test %eax, %eax jnz psxDispatcherReg_CallFn2 // throw an exception int 10 psxDispatcherReg_CallFn2: #endif and REG_BLOCK, 0x0fffffff jmp REG_BLOCK // fnptr psxDispatcherReg_recomp: call psxRecRecompile mov %eax, dword ptr [REG_BLOCK] and %rax, 0x0fffffff jmp %rax // fnprt #else // not x86-64 #define REG_PC %ecx #define REG_BLOCK %esi // jumped to when invalid psxpc address .globl psxDispatcher psxDispatcher: // EDX contains the current psxpc to jump to, stack contains the jump addr to modify push %edx // calc PSX_GETBLOCK // ((BASEBLOCK*)(recLUT[((u32)(x)) >> 16] + (sizeof(BASEBLOCK)/4)*((x) & 0xffff))) mov %eax, dword ptr [psxRegs + PCOFFSET] mov REG_BLOCK, %eax mov REG_PC, %eax shr %eax, 16 and REG_BLOCK, 0xffff shl %eax, 2 add %eax, [psxRecLUT] shl REG_BLOCK, 1 add REG_BLOCK, dword ptr [%eax] // check if startpc&PSX_MEMMASK == psxRegs.pc&PSX_MEMMASK mov %eax, REG_PC mov %edx, [REG_BLOCK+BLOCKTYPE_STARTPC] and %eax, PSX_MEMMASK // remove higher bits and %edx, PSX_MEMMASK cmp %eax, %edx je psxDispatcher_CheckPtr // recompile push REG_BLOCK push REG_PC // psxpc call psxRecRecompile add %esp, 4 // pop old param pop REG_BLOCK psxDispatcher_CheckPtr: mov REG_BLOCK, dword ptr [REG_BLOCK] #ifdef _DEBUG test REG_BLOCK, REG_BLOCK jnz psxDispatcher_CallFn // throw an exception int 10 psxDispatcher_CallFn: #endif and REG_BLOCK, 0x0fffffff mov %edx, REG_BLOCK pop %ecx // x86Ptr to mod sub %edx, %ecx sub %edx, 4 mov dword ptr [%ecx], %edx jmp REG_BLOCK .globl psxDispatcherClear psxDispatcherClear: // %EDX contains the current psxpc mov dword ptr [psxRegs + PCOFFSET], %edx // calc PSX_GETBLOCK // ((BASEBLOCK*)(recLUT[((u32)(x)) >> 16] + (sizeof(BASEBLOCK)/4)*((x) & 0xffff))) mov %eax, %edx mov REG_BLOCK, %edx shr %eax, 16 and REG_BLOCK, 0xffff shl %eax, 2 add %eax, [psxRecLUT] shl REG_BLOCK, 1 add REG_BLOCK, dword ptr [%eax]; // check if startpc&PSX_MEMMASK == psxRegs.pc&PSX_MEMMASK mov %eax, %edx mov REG_PC, %edx mov %edx, [REG_BLOCK+BLOCKTYPE_STARTPC] and %eax, PSX_MEMMASK // remove higher bits and %edx, PSX_MEMMASK cmp %eax, %edx jne psxDispatcherClear_Recompile add %esp, 4 // ignore stack mov %eax, dword ptr [REG_BLOCK] #ifdef _DEBUG test %eax, %eax jnz psxDispatcherClear_CallFn // throw an exception int 10 psxDispatcherClear_CallFn: #endif and %eax, 0x0fffffff jmp %eax psxDispatcherClear_Recompile: push REG_BLOCK push REG_PC call psxRecRecompile add %esp, 4 // pop old param pop REG_BLOCK mov %eax, dword ptr [REG_BLOCK] pop %ecx // old fnptr and %eax, 0x0fffffff mov byte ptr [%ecx], 0xe9 // jmp32 mov %edx, %eax sub %edx, %ecx sub %edx, 5 mov dword ptr [%ecx+1], %edx jmp %eax // called when jumping to variable psxpc address .globl psxDispatcherReg psxDispatcherReg: //s_pDispatchBlock = PSX_GETBLOCK(psxRegs.pc); mov %edx, dword ptr [psxRegs+PCOFFSET] mov %ecx, %edx shr %edx, 14 and %edx, 0xfffffffc add %edx, [psxRecLUT] mov %edx, dword ptr [%edx] mov %eax, %ecx and %eax, 0xfffc // %edx += 2*%eax shl %eax, 1 add %edx, %eax // check if startpc == psxRegs.pc mov %eax, %ecx //and %eax, 0x5fffffff // remove higher bits cmp %eax, dword ptr [%edx+BLOCKTYPE_STARTPC] jne psxDispatcherReg_recomp mov %eax, dword ptr [%edx] #ifdef _DEBUG test %eax, %eax jnz psxDispatcherReg_CallFn2 // throw an exception int 10 psxDispatcherReg_CallFn2: #endif and %eax, 0x0fffffff jmp %eax // fnptr psxDispatcherReg_recomp: sub %esp, 8 mov dword ptr [%esp+4], %edx mov dword ptr [%esp], %ecx call psxRecRecompile mov %edx, dword ptr [%esp+4] add %esp, 8 mov %eax, dword ptr [%edx] and %eax, 0x0fffffff jmp %eax // fnptr #endif