mirror of
https://github.com/Azimer/Apollo64.git
synced 2025-04-02 10:31:54 -04:00
868 lines
No EOL
24 KiB
C++
868 lines
No EOL
24 KiB
C++
|
|
/*
|
|
** r4300i Recompiler, Copyright JaboSoft 1994,2002
|
|
** Liscensed to and modified by Apollo, Copyright Azimer 1997,2002
|
|
**
|
|
** Entry Points:
|
|
** void r4300iCompiler_Execute(void)
|
|
**
|
|
** Revision list
|
|
** - 2001-11-02, initial revision (jabo)
|
|
**
|
|
*/
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include "WinMain.h"
|
|
#include "EmuMain.h"
|
|
#include "CpuMain.h"
|
|
|
|
extern void (*r4300i[0x40])();
|
|
extern void (*special[0x40])();
|
|
extern void (*regimm[0x20])();
|
|
extern void (*MmuSpecial[0x40])();
|
|
extern void (*MmuNormal[0x20])();
|
|
extern void (*FpuCommands[0x40])();
|
|
extern void CheckInterrupts(void);
|
|
|
|
#define R4300I_BLOCK_SIZE 0x1000
|
|
#define R4300I_READOPCODE(x) vr32((x))
|
|
|
|
typedef union {
|
|
DWORD * udwPtr;
|
|
WORD * uwPtr;
|
|
BYTE * ubPtr;
|
|
void * ptr;
|
|
} BUFFER_POINTER;
|
|
|
|
typedef struct {
|
|
union {
|
|
struct {
|
|
unsigned int func:6;
|
|
unsigned int sa:5;
|
|
unsigned int rd:5;
|
|
unsigned int rt:5;
|
|
unsigned int rs:5;
|
|
unsigned int op:6;
|
|
};
|
|
unsigned int UW;
|
|
};
|
|
} R4300I_OPCODE;
|
|
|
|
class r4300iRecompiler {
|
|
|
|
public:
|
|
BUFFER_POINTER X86CodePos;
|
|
R4300I_OPCODE CurrentOpcode;
|
|
DWORD ProgramCounter, BranchCompare, BlockStart;
|
|
|
|
private:
|
|
BUFFER_POINTER X86Code, JumpTable, CheckTable, ParentTable;
|
|
FILE * hStream;
|
|
|
|
public:
|
|
|
|
void SetJumpTableToPos(DWORD location) {
|
|
location &= 0x7FFFFF;
|
|
*(this->JumpTable.udwPtr + (location >> 2)) = (DWORD)this->X86CodePos.ptr;
|
|
}
|
|
|
|
void SetJumpTableEntry(DWORD location, void * CodePtr) {
|
|
location &= 0x7FFFFF;
|
|
*(this->JumpTable.udwPtr + (location >> 2)) = (DWORD)CodePtr;
|
|
}
|
|
|
|
void * GetJumpTableEntry(DWORD location) {
|
|
location &= 0x7FFFFF;
|
|
return (void*)*(this->JumpTable.udwPtr + (location >> 2));
|
|
}
|
|
|
|
void * GetJumpTablePtr(DWORD location) {
|
|
location &= 0x7FFFFF;
|
|
return (void*)(this->JumpTable.udwPtr + (location >> 2));
|
|
/* return (void*)&(this->JumpTable.udwPtr[(location >> 2)]); */
|
|
}
|
|
|
|
void SetCheckValue(DWORD location, DWORD Value) {
|
|
location &= 0x7FFFFF;
|
|
*(this->CheckTable.udwPtr + (location >> 2)) = Value;
|
|
}
|
|
|
|
DWORD GetCheckValue(DWORD location) {
|
|
location &= 0x7FFFFF;
|
|
return *(this->CheckTable.udwPtr + (location >> 2));
|
|
}
|
|
|
|
void SetParentAddress(DWORD Child, DWORD Parent) {
|
|
Child &= 0x7FFFFF;
|
|
*(this->ParentTable.udwPtr + (Child >> 2)) = Parent;
|
|
}
|
|
|
|
DWORD GetParentAddress(DWORD Child) {
|
|
Child &= 0x7FFFFF;
|
|
return *(this->ParentTable.udwPtr + (Child >> 2));
|
|
}
|
|
|
|
DWORD GetParentCheckValue(DWORD Child) {
|
|
Child &= 0x7FFFFF;
|
|
DWORD location = *(this->ParentTable.udwPtr + (Child >> 2));
|
|
location &= 0x7FFFFFF;
|
|
return *(this->CheckTable.udwPtr + (location >> 2));
|
|
}
|
|
|
|
void ResetCode(void) {
|
|
memset(this->JumpTable.ptr, 0, 0x800000);
|
|
memset(this->CheckTable.ptr, 0, 0x800000);
|
|
memset(this->ParentTable.ptr, 0, 0x800000);
|
|
memset(this->X86Code.ptr, 0, 0x1000000);
|
|
|
|
this->X86CodePos.ptr = this->X86Code.ptr;
|
|
}
|
|
|
|
r4300iRecompiler() {
|
|
/*
|
|
* Tables = 8 + 8 + 8 = 24 megs
|
|
* X86Cod = 16
|
|
*/
|
|
this->JumpTable.ptr = VirtualAlloc(NULL, 0x800000, MEM_COMMIT, PAGE_READWRITE);
|
|
this->CheckTable.ptr = VirtualAlloc(NULL, 0x800000, MEM_COMMIT, PAGE_READWRITE);
|
|
this->ParentTable.ptr = VirtualAlloc(NULL, 0x800000, MEM_COMMIT, PAGE_READWRITE);
|
|
this->X86Code.ptr = VirtualAlloc(NULL, 0x1000000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
|
|
|
if (this->JumpTable.ptr == NULL) {
|
|
_asm { int 3 }
|
|
}
|
|
if (this->CheckTable.ptr == NULL) {
|
|
_asm { int 3 }
|
|
}
|
|
if (this->ParentTable.ptr == NULL) {
|
|
_asm { int 3 }
|
|
}
|
|
if (this->X86Code.ptr == NULL) {
|
|
_asm { int 3 }
|
|
}
|
|
this->ResetCode();
|
|
this->hStream = NULL;
|
|
}
|
|
|
|
~r4300iRecompiler() {
|
|
VirtualFree(this->X86Code.ptr, 0, MEM_RELEASE);
|
|
VirtualFree(this->JumpTable.ptr, 0, MEM_RELEASE);
|
|
VirtualFree(this->CheckTable.ptr, 0, MEM_RELEASE);
|
|
VirtualFree(this->ParentTable.ptr, 0, MEM_RELEASE);
|
|
this->X86CodePos.ptr = NULL;
|
|
this->X86Code.ptr = NULL;
|
|
this->JumpTable.ptr = NULL;
|
|
this->CheckTable.ptr = NULL;
|
|
this->ParentTable.ptr = NULL;
|
|
|
|
if (this->hStream != NULL) {
|
|
fclose(this->hStream);
|
|
this->hStream = NULL;
|
|
}
|
|
}
|
|
|
|
void Log(char * Msg, ...);
|
|
};
|
|
|
|
void r4300iRecompiler::Log(char * Message, ...) {
|
|
if (this->hStream == NULL) {
|
|
char Path[256], Dir[256], Drive[10];
|
|
|
|
GetModuleFileName(NULL, Path, sizeof(Path));
|
|
_splitpath(Path, Drive, Dir, 0, 0);
|
|
sprintf(Path, "%s%s%s", Drive, Dir, "RecompileX86Code.log");
|
|
|
|
//if (NULL == (this->hStream = fopen(Path, "a+"))) {
|
|
return;
|
|
//}
|
|
}
|
|
|
|
char Msg[512];
|
|
va_list ap;
|
|
|
|
va_start(ap, Message);
|
|
vsprintf(Msg, Message, ap);
|
|
va_end(ap);
|
|
|
|
fprintf(this->hStream, "%s\n", Msg);
|
|
}
|
|
|
|
r4300iRecompiler Recompiler;
|
|
|
|
/*************************** x86 ***************************/
|
|
|
|
void SetBranch8b(void * JumpByte, void * Destination) {
|
|
/* calculate 32-bit relative offset */
|
|
signed int n = (BYTE*)Destination - ((BYTE*)JumpByte + 1);
|
|
*(BYTE*)(JumpByte) = (BYTE)n;
|
|
}
|
|
|
|
void SetBranch32b(void * JumpByte, void * Destination) {
|
|
*(DWORD*)(JumpByte) = (DWORD)((BYTE*)Destination - (BYTE*)((DWORD*)JumpByte + 1));
|
|
}
|
|
|
|
void MoveConstToVariable (DWORD Const, void * Variable, char * VariableName) {
|
|
Recompiler.Log(" mov [%s], 0x%08X", VariableName, Const);
|
|
*(Recompiler.X86CodePos.uwPtr++) = 0x05C7;
|
|
*(Recompiler.X86CodePos.udwPtr++) = (DWORD)Variable;
|
|
*(Recompiler.X86CodePos.udwPtr++) = Const;
|
|
}
|
|
|
|
void CallFunctionDirect(void * FunctAddress, char * FunctName) {
|
|
Recompiler.Log(" call %s", FunctName);
|
|
*(Recompiler.X86CodePos.ubPtr++) = 0xE8;
|
|
*(Recompiler.X86CodePos.udwPtr++) = (DWORD)FunctAddress-(DWORD)Recompiler.X86CodePos.ptr - 4;
|
|
}
|
|
|
|
void AddConstToVariable (DWORD Const, void * Variable, char * VariableName) {
|
|
Recompiler.Log(" add [%s], 0x%08X", VariableName, Const);
|
|
*(Recompiler.X86CodePos.uwPtr++) = 0x0581;
|
|
*(Recompiler.X86CodePos.udwPtr++) = (DWORD)Variable;
|
|
*(Recompiler.X86CodePos.udwPtr++) = Const;
|
|
}
|
|
|
|
void Ret(void) {
|
|
Recompiler.Log(" ret");
|
|
*(Recompiler.X86CodePos.ubPtr++) = 0xC3;
|
|
}
|
|
|
|
void MoveVariableToEax(void *Variable, char *VariableName) {
|
|
Recompiler.Log(" mov eax, [%s]", VariableName);
|
|
*(Recompiler.X86CodePos.uwPtr++) = 0x058B;
|
|
*(Recompiler.X86CodePos.udwPtr++) = (DWORD)Variable;
|
|
}
|
|
|
|
void MoveEaxToVariable(void * Variable, char * VariableName) {
|
|
Recompiler.Log(" mov dword ptr [%s], eax",VariableName);
|
|
*(Recompiler.X86CodePos.uwPtr++) = 0x0589;
|
|
*(Recompiler.X86CodePos.udwPtr++) = (DWORD)Variable;
|
|
}
|
|
|
|
void CompConstToVariable(DWORD Const, void * Variable, char * VariableName) {
|
|
Recompiler.Log(" cmp dword ptr [%s], 0x%X",VariableName, Const);
|
|
*(Recompiler.X86CodePos.uwPtr++) = 0x3D81;
|
|
*(Recompiler.X86CodePos.udwPtr++) = (DWORD)Variable;
|
|
*(Recompiler.X86CodePos.udwPtr++) = Const;
|
|
}
|
|
|
|
void CompEaxToVariable(void * Variable, char * VariableName) {
|
|
Recompiler.Log(" cmp eax, dword ptr [%s]",VariableName);
|
|
*(Recompiler.X86CodePos.uwPtr++) = 0x053B;
|
|
*(Recompiler.X86CodePos.udwPtr++) = (DWORD)Variable;
|
|
}
|
|
|
|
void CompConstToEax(DWORD Const) {
|
|
Recompiler.Log(" cmp eax, 0x%08X", Const);
|
|
*(Recompiler.X86CodePos.uwPtr++) = 0xF881;
|
|
*(Recompiler.X86CodePos.udwPtr++) = (DWORD)Const;
|
|
}
|
|
|
|
void JeLabel8(char * Label, BYTE Value) {
|
|
Recompiler.Log(" je $%s", Label);
|
|
*(Recompiler.X86CodePos.ubPtr++) = 0x74;
|
|
*(Recompiler.X86CodePos.ubPtr++) = Value;
|
|
}
|
|
|
|
void JneLabel8(char * Label, BYTE Value) {
|
|
Recompiler.Log(" jne $%s", Label);
|
|
*(Recompiler.X86CodePos.ubPtr++) = 0x75;
|
|
*(Recompiler.X86CodePos.ubPtr++) = Value;
|
|
}
|
|
|
|
void JgLabel8(char * Label, BYTE Value) {
|
|
Recompiler.Log(" jle $%s", Label);
|
|
*(Recompiler.X86CodePos.ubPtr++) = 0x7F;
|
|
*(Recompiler.X86CodePos.ubPtr++) = Value;
|
|
}
|
|
|
|
void JumpEax(void) {
|
|
Recompiler.Log(" jmp eax");
|
|
*(Recompiler.X86CodePos.uwPtr++) = 0xe0ff;
|
|
}
|
|
|
|
void JmpIndirectLabel32(char * Label,DWORD location) {
|
|
Recompiler.Log(" jmp dword ptr [%s]", Label);
|
|
*(Recompiler.X86CodePos.uwPtr++) = 0x25ff;
|
|
*(Recompiler.X86CodePos.udwPtr++) = location;
|
|
}
|
|
|
|
/************************** opcodes ************************/
|
|
|
|
void r4300iCompiler_Opcode(void);
|
|
|
|
void r4300i_Compiler_Branch(void * Helper, BOOL Link) {
|
|
DWORD target = Recompiler.ProgramCounter + 4 + ((short)Recompiler.CurrentOpcode.UW << 2);
|
|
BOOL bIsLikely = FALSE;
|
|
BYTE * JumpByte, * JumpByte2;
|
|
|
|
MoveConstToVariable(Recompiler.CurrentOpcode.UW, &sop, "GlobalOpcode");
|
|
CallFunctionDirect(Helper, "BranchHelper");
|
|
|
|
if (Recompiler.CurrentOpcode.op == 0x1) {
|
|
if ((Recompiler.CurrentOpcode.func == 0x2) || (Recompiler.CurrentOpcode.func == 0x3)) {
|
|
bIsLikely = TRUE;
|
|
}
|
|
} else if (Recompiler.CurrentOpcode.op == 0x11) {
|
|
if (Recompiler.CurrentOpcode.rt & 0x2)
|
|
bIsLikely = TRUE;
|
|
} else if (Recompiler.CurrentOpcode.op & 0x10) {
|
|
bIsLikely = TRUE;
|
|
}
|
|
|
|
/* compile delay slot (doesnt check interrupts, neither does interpreter) */
|
|
if (FALSE == bIsLikely) {
|
|
Recompiler.Log("\n (- begin delay slot -)");
|
|
Recompiler.ProgramCounter += 4;
|
|
r4300iCompiler_Opcode();
|
|
Recompiler.ProgramCounter -= 4;
|
|
Recompiler.Log(" (- end delay slot -)\n");
|
|
}
|
|
|
|
CompConstToVariable(TRUE, &Recompiler.BranchCompare, "BranchCompare");
|
|
|
|
JneLabel8("DoNotJump", 0);
|
|
JumpByte = Recompiler.X86CodePos.ubPtr - 1;
|
|
|
|
if (Link == TRUE) {
|
|
DWORD * RegRA = (DWORD*)&CpuRegs[31];
|
|
MoveConstToVariable(Recompiler.ProgramCounter + 8, &RegRA[0], "RA.Lo");
|
|
MoveConstToVariable(0, &RegRA[1], "RA.Hi");
|
|
}
|
|
|
|
if (TRUE == bIsLikely) {
|
|
Recompiler.Log("\n Branch Likely");
|
|
Recompiler.Log("\n (- begin delay slot -)");
|
|
Recompiler.ProgramCounter += 4;
|
|
r4300iCompiler_Opcode();
|
|
Recompiler.ProgramCounter -= 4;
|
|
Recompiler.Log(" (- end delay slot -)\n");
|
|
}
|
|
|
|
if (target >= Recompiler.BlockStart && target < Recompiler.BlockStart + 0x1000) {
|
|
//if (0) {
|
|
MoveVariableToEax(Recompiler.GetJumpTablePtr(target), "JumpRegAddress");
|
|
CompConstToEax(0);
|
|
JneLabel8("ExecuteJump", 0);
|
|
JumpByte2 = Recompiler.X86CodePos.ubPtr - 1;
|
|
|
|
MoveConstToVariable(target, &pc, "PC");
|
|
Ret();
|
|
|
|
Recompiler.Log(" ExecuteJump:");
|
|
SetBranch8b(JumpByte2, Recompiler.X86CodePos.ptr);
|
|
JumpEax();
|
|
} else {
|
|
MoveConstToVariable(target, &pc, "PC");
|
|
Ret();
|
|
}
|
|
|
|
Recompiler.Log(" DoNotJump:");
|
|
SetBranch8b(JumpByte, Recompiler.X86CodePos.ptr);
|
|
|
|
/* delay slot is already done */
|
|
Recompiler.ProgramCounter += 4;
|
|
}
|
|
void r4300i_Compiler_BC1F(void) {
|
|
//0x800889b4
|
|
Recompiler.BranchCompare = !(FpuControl[31] & 0x00800000) ? TRUE : FALSE;
|
|
/* if (Recompiler.BranchCompare == FALSE)
|
|
__asm int 3;*/
|
|
}
|
|
|
|
void r4300i_Compiler_BC1T(void) {
|
|
Recompiler.BranchCompare = (FpuControl[31] & 0x00800000) ? TRUE : FALSE;
|
|
/*if (Recompiler.BranchCompare == TRUE)
|
|
__asm int 3;*/
|
|
}
|
|
|
|
void r4300i_Compiler_BEQ(void) {
|
|
Recompiler.BranchCompare = (CpuRegs[sop.rt] == CpuRegs[sop.rs]) ? TRUE : FALSE;
|
|
}
|
|
|
|
void r4300i_Compiler_BNE(void) {
|
|
Recompiler.BranchCompare = (CpuRegs[sop.rt] != CpuRegs[sop.rs]) ? TRUE : FALSE;
|
|
}
|
|
|
|
void r4300i_Compiler_BLEZ(void) {
|
|
Recompiler.BranchCompare = (((s64)CpuRegs[sop.rs]) <= 0) ? TRUE : FALSE;
|
|
}
|
|
|
|
void r4300i_Compiler_BLTZ(void) {
|
|
Recompiler.BranchCompare = (((s64)CpuRegs[sop.rs]) < 0) ? TRUE : FALSE;
|
|
}
|
|
|
|
void r4300i_Compiler_BGTZ(void) {
|
|
Recompiler.BranchCompare = (((s64)CpuRegs[sop.rs]) > 0) ? TRUE : FALSE;
|
|
}
|
|
|
|
void r4300i_Compiler_BGEZ(void) {
|
|
Recompiler.BranchCompare = (((s64)CpuRegs[sop.rs]) >= 0) ? TRUE : FALSE;
|
|
}
|
|
|
|
void * JumpRegAddress; /* lazy */
|
|
DWORD JumpRegister;
|
|
|
|
void r4300i_Compiler_JumpRegHelper(void) {
|
|
/*
|
|
* mov eax, register
|
|
* push eax
|
|
* call GetJumpTableEntry
|
|
* add esp, 4
|
|
* result = eax
|
|
*/
|
|
JumpRegAddress = Recompiler.GetJumpTableEntry((DWORD)CpuRegs[sop.rs]);
|
|
}
|
|
|
|
void r4300i_Compiler_JumpReg(BOOL Link) {
|
|
BYTE * JumpByte;
|
|
/*
|
|
MoveConstToVariable(Recompiler.CurrentOpcode.UW, &sop, "GlobalOpcode");
|
|
CallFunctionDirect(r4300i_Compiler_JumpRegHelper, "r4300i_Compiler_JumpRegHelper");
|
|
*/
|
|
MoveVariableToEax(&CpuRegs[sop.rs], "CPU_REG[rs]");
|
|
MoveEaxToVariable(&JumpRegister, "JumpRegister");
|
|
|
|
/* compile delay slot (doesnt check interrupts, neither does interpreter) */
|
|
Recompiler.Log("\n (- begin delay slot -)");
|
|
Recompiler.ProgramCounter += 4;
|
|
r4300iCompiler_Opcode();
|
|
Recompiler.ProgramCounter -= 4;
|
|
Recompiler.Log(" (- end delay slot -)\n");
|
|
|
|
if (Link == TRUE) {
|
|
DWORD * RegRA = (DWORD*)&CpuRegs[31];
|
|
MoveConstToVariable(Recompiler.ProgramCounter + 8, &RegRA[0], "RA.Lo");
|
|
MoveConstToVariable(0, &RegRA[1], "RA.Hi");
|
|
}
|
|
|
|
/* cant risk the self mod code */
|
|
if (0) {
|
|
MoveVariableToEax(&JumpRegAddress, "JumpRegAddress");
|
|
CompConstToEax(0);
|
|
JneLabel8("ExecuteJump", 0);
|
|
JumpByte = Recompiler.X86CodePos.ubPtr - 1;
|
|
|
|
MoveVariableToEax(&JumpRegister, "JumpRegister");
|
|
MoveEaxToVariable(&pc, "PC");
|
|
Ret();
|
|
|
|
Recompiler.Log(" ExecuteJump:");
|
|
SetBranch8b(JumpByte, Recompiler.X86CodePos.ptr);
|
|
JumpEax();
|
|
} else {
|
|
MoveVariableToEax(&JumpRegister, "JumpRegister");
|
|
MoveEaxToVariable(&pc, "PC");
|
|
Ret();
|
|
}
|
|
|
|
/* delay slot is already done */
|
|
Recompiler.ProgramCounter += 4;
|
|
}
|
|
|
|
void r4300i_Compiler_Jump(BOOL Link) {
|
|
static void * tempTargetPtr;
|
|
DWORD target = (Recompiler.ProgramCounter & 0xf0000000) + ((Recompiler.CurrentOpcode.UW << 2) & 0x0fffffff);
|
|
|
|
/* compile delay slot (doesnt check interrupts, neither does interpreter) */
|
|
Recompiler.Log("\n (- begin delay slot -)");
|
|
Recompiler.ProgramCounter += 4;
|
|
r4300iCompiler_Opcode();
|
|
Recompiler.ProgramCounter -= 4;
|
|
Recompiler.Log(" (- end delay slot -)\n");
|
|
|
|
if (Link == TRUE) {
|
|
DWORD * RegRA = (DWORD*)&CpuRegs[31];
|
|
MoveConstToVariable(Recompiler.ProgramCounter + 8, &RegRA[0], "RA.Lo");
|
|
MoveConstToVariable(0, &RegRA[1], "RA.Hi");
|
|
}
|
|
|
|
if (target >= Recompiler.BlockStart && target < Recompiler.BlockStart + 0x1000) {
|
|
BYTE * JumpByte;
|
|
|
|
MoveVariableToEax(Recompiler.GetJumpTablePtr(target), "JumpTable");
|
|
CompConstToEax(0);
|
|
JneLabel8("ExecuteJump", 0);
|
|
JumpByte = Recompiler.X86CodePos.ubPtr - 1;
|
|
MoveConstToVariable(target, &pc, "PC");
|
|
Ret();
|
|
|
|
Recompiler.Log(" ExecuteJump:");
|
|
SetBranch8b(JumpByte, Recompiler.X86CodePos.ptr);
|
|
JumpEax();
|
|
} else {
|
|
MoveConstToVariable(target, &pc, "PC");
|
|
Ret();
|
|
}
|
|
|
|
/* delay slot is already done */
|
|
Recompiler.ProgramCounter += 4;
|
|
}
|
|
|
|
void r4300i_Compiler_ERET(void) {
|
|
extern void opERET(void);
|
|
CallFunctionDirect(&opERET,"opERET");
|
|
Ret();
|
|
}
|
|
|
|
/***********************************************************/
|
|
|
|
void r4300iCompiler_UseInterpreter(void) {
|
|
void * Function;
|
|
|
|
switch (Recompiler.CurrentOpcode.op) {
|
|
case 0x00: /* R4300I_SPECIAL */
|
|
Function = special[Recompiler.CurrentOpcode.func];
|
|
break;
|
|
|
|
case 0x01: /* R4300I_REGIMMEDIATE */
|
|
Function = regimm[Recompiler.CurrentOpcode.rt];
|
|
break;
|
|
|
|
case 0x10: /* R4300I_COP0 */
|
|
if (Recompiler.CurrentOpcode.rs == 16) {
|
|
Function = MmuSpecial[Recompiler.CurrentOpcode.func];
|
|
} else {
|
|
Function = MmuNormal[Recompiler.CurrentOpcode.rs];
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Function = r4300i[Recompiler.CurrentOpcode.op];
|
|
break;
|
|
}
|
|
|
|
MoveConstToVariable(Recompiler.CurrentOpcode.UW, &sop, "GlobalOpcode");
|
|
CallFunctionDirect(Function, "r4300iOpcode");
|
|
}
|
|
|
|
extern void OpcodeLookup(DWORD, char *);
|
|
|
|
void r4300iCompiler_Opcode(void) {
|
|
|
|
char Asm[256];
|
|
OpcodeLookup(Recompiler.ProgramCounter, Asm);
|
|
Recompiler.Log("[%08X] %s (X86: %08X)", Recompiler.ProgramCounter, Asm, Recompiler.X86CodePos);
|
|
|
|
Recompiler.CurrentOpcode.UW = R4300I_READOPCODE(Recompiler.ProgramCounter);
|
|
|
|
if (Recompiler.CurrentOpcode.UW == 0x00000000) {
|
|
return;
|
|
}
|
|
|
|
switch (Recompiler.CurrentOpcode.op) {
|
|
case 0x00: /* R4300I_SPECIAL */
|
|
switch (Recompiler.CurrentOpcode.func) {
|
|
case 0x08: r4300i_Compiler_JumpReg(FALSE); break;
|
|
case 0x09: r4300i_Compiler_JumpReg(TRUE); break;
|
|
default:
|
|
Recompiler.Log("");
|
|
r4300iCompiler_UseInterpreter();
|
|
}
|
|
break;
|
|
|
|
case 0x01: /* R4300I_REGIMMEDIATE */
|
|
switch (Recompiler.CurrentOpcode.rt) {
|
|
case 0x00: r4300i_Compiler_Branch(&r4300i_Compiler_BLTZ, FALSE); break;
|
|
case 0x01: r4300i_Compiler_Branch(&r4300i_Compiler_BGEZ, FALSE); break;
|
|
case 0x02: r4300i_Compiler_Branch(&r4300i_Compiler_BLTZ, FALSE); break;
|
|
case 0x03: r4300i_Compiler_Branch(&r4300i_Compiler_BGEZ, FALSE); break;
|
|
case 0x10: r4300i_Compiler_Branch(&r4300i_Compiler_BLTZ, TRUE); break;
|
|
case 0x11: r4300i_Compiler_Branch(&r4300i_Compiler_BGEZ, TRUE); break;
|
|
case 0x12: __asm int 3;//Recompiler.Log("REGIMM_BLTZALL"); break;
|
|
case 0x13: __asm int 3;//Recompiler.Log("REGIMM_BGEZALL"); break;
|
|
|
|
default:
|
|
Recompiler.Log("");
|
|
r4300iCompiler_UseInterpreter();
|
|
}
|
|
break;
|
|
|
|
case 0x02: r4300i_Compiler_Jump(FALSE); break;
|
|
case 0x03: r4300i_Compiler_Jump(TRUE); break;
|
|
case 0x04: r4300i_Compiler_Branch(&r4300i_Compiler_BEQ, FALSE); break;
|
|
case 0x05: r4300i_Compiler_Branch(&r4300i_Compiler_BNE, FALSE); break;
|
|
case 0x06: r4300i_Compiler_Branch(&r4300i_Compiler_BLEZ, FALSE); break;
|
|
case 0x07: r4300i_Compiler_Branch(&r4300i_Compiler_BGTZ, FALSE); break;
|
|
|
|
case 0x10: /* R4300I_COP0 */
|
|
switch (Recompiler.CurrentOpcode.rs) {
|
|
case 0x10:
|
|
switch (Recompiler.CurrentOpcode.func) {
|
|
case 0x18: /* COP0_ERET */
|
|
r4300i_Compiler_ERET();
|
|
break;
|
|
|
|
default:
|
|
Recompiler.Log("");
|
|
r4300iCompiler_UseInterpreter();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Recompiler.Log("");
|
|
r4300iCompiler_UseInterpreter();
|
|
}
|
|
break;
|
|
|
|
case 0x11: /* R4300I_COP1 */
|
|
switch (Recompiler.CurrentOpcode.rs) {
|
|
case 0x08: /* COP1_BRANCH */
|
|
//__asm int 3; // I think this is the problem
|
|
switch (Recompiler.CurrentOpcode.rt & 3){
|
|
case 0x00: r4300i_Compiler_Branch(&r4300i_Compiler_BC1F, FALSE); break;
|
|
case 0x01: r4300i_Compiler_Branch(&r4300i_Compiler_BC1T, FALSE); break;
|
|
case 0x02: r4300i_Compiler_Branch(&r4300i_Compiler_BC1F, FALSE); break;
|
|
case 0x03: r4300i_Compiler_Branch(&r4300i_Compiler_BC1T, FALSE); break;
|
|
|
|
default:
|
|
Recompiler.Log("");
|
|
r4300iCompiler_UseInterpreter();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Recompiler.Log("");
|
|
r4300iCompiler_UseInterpreter();
|
|
}
|
|
break;
|
|
|
|
case 0x14: r4300i_Compiler_Branch(&r4300i_Compiler_BEQ, FALSE); break;
|
|
case 0x15: r4300i_Compiler_Branch(&r4300i_Compiler_BNE, FALSE); break;
|
|
case 0x16: r4300i_Compiler_Branch(&r4300i_Compiler_BLEZ, FALSE); break;
|
|
case 0x17: r4300i_Compiler_Branch(&r4300i_Compiler_BGTZ, FALSE); break;
|
|
|
|
default:
|
|
Recompiler.Log("");
|
|
r4300iCompiler_UseInterpreter();
|
|
}
|
|
}
|
|
|
|
BOOL IsOpcodeBranch(DWORD ProgramCnt) {
|
|
R4300I_OPCODE tmp;
|
|
tmp.UW = R4300I_READOPCODE(ProgramCnt);
|
|
|
|
switch (tmp.op) {
|
|
case 0x00: /* R4300I_SPECIAL */
|
|
switch (tmp.func) {
|
|
case 0x08: /* SPECIAL_JR */
|
|
case 0x09: /* SPECIAL_JALR */
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
case 0x01: /* R4300I_REGIMMEDIATE */
|
|
switch (tmp.rt) {
|
|
case 0x00: /* REGIMM_BLTZ */
|
|
case 0x01: /* REGIMM_BGEZ */
|
|
case 0x02: /* REGIMM_BLTZL */
|
|
case 0x03: /* REGIMM_BGEZL */
|
|
case 0x10: /* REGIMM_BLTZAL */
|
|
case 0x11: /* REGIMM_BGEZAL */
|
|
case 0x12: /* REGIMM_BLTZALL */
|
|
case 0x13: /* REGIMM_BGEZALL */
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
case 0x02: /* R4300I_J */
|
|
case 0x03: /* R4300I_JAL */
|
|
case 0x04: /* R4300I_BEQ */
|
|
case 0x05: /* R4300I_BNE */
|
|
case 0x06: /* R4300I_BLEZ */
|
|
case 0x07: /* R4300I_BGTZ */
|
|
return TRUE;
|
|
|
|
case 0x11: /* R4300I_COP1 */
|
|
switch (tmp.rs) {
|
|
case 0x08: /* COP1_BRANCH */
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
case 0x14: /* R4300I_BEQL */
|
|
case 0x15: /* R4300I_BNEL */
|
|
case 0x16: /* R4300I_BLEZL */
|
|
case 0x17: /* R4300I_BGTZL */
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD r4300iCompiler_CalculateMemoryCheck(DWORD location) {
|
|
DWORD CalculatedValue = 0, Count = 0;
|
|
|
|
for (;;) {
|
|
CalculatedValue ^= R4300I_READOPCODE(location + Count);
|
|
Count += 256;
|
|
|
|
/*
|
|
* blocks may go over the block size limitation if
|
|
* the current instruction is a branch so it can
|
|
* do the delay slot as well, always
|
|
*/
|
|
|
|
if (Count >= R4300I_BLOCK_SIZE && TRUE != IsOpcodeBranch(location + Count)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return CalculatedValue;
|
|
}
|
|
|
|
/*
|
|
* TODO:
|
|
* 1) branches need to be uncheated, very reliable now tho
|
|
* 2) interrupt handling slows us down a great deal
|
|
*/
|
|
|
|
void * r4300iCompiler_CreateBlock(void) {
|
|
static DWORD TestValue = 0;
|
|
static DWORD BlockID = 0;
|
|
|
|
BYTE * JumpByte, * JumpByte2;
|
|
BUFFER_POINTER Block;
|
|
DWORD CheckValue = r4300iCompiler_CalculateMemoryCheck(pc);
|
|
|
|
DWORD BlockEnd = pc + R4300I_BLOCK_SIZE;
|
|
|
|
Recompiler.Log("");
|
|
Recompiler.Log("---------------");
|
|
Recompiler.Log("Block=%i", BlockID++);
|
|
Recompiler.Log("Start=%08X", pc);
|
|
Recompiler.Log("CRC=%08X", CheckValue);
|
|
Recompiler.Log("X86=%08X", Recompiler.X86CodePos);
|
|
Recompiler.Log("---------------");
|
|
|
|
Recompiler.BlockStart = pc;
|
|
|
|
/* setup parent check value */
|
|
Recompiler.SetCheckValue(pc, CheckValue);
|
|
Recompiler.ProgramCounter = pc;
|
|
|
|
for (;;) {
|
|
Block.ptr = Recompiler.GetJumpTableEntry(Recompiler.ProgramCounter);
|
|
if (Block.ptr != NULL) {
|
|
/* link the block up and stop loop */
|
|
Recompiler.Log("ERROR: Linking detected at %08X", Recompiler.ProgramCounter);
|
|
break;
|
|
}
|
|
|
|
Recompiler.SetJumpTableToPos(Recompiler.ProgramCounter);
|
|
|
|
// if (pc==Recompiler.ProgramCounter) {*(Recompiler.X86CodePos.ubPtr++) = 0xCC;}
|
|
|
|
/* give the child opcode the parents index in check values */
|
|
Recompiler.SetParentAddress(Recompiler.ProgramCounter, pc);
|
|
|
|
if (++TestValue == 1 || IsOpcodeBranch(Recompiler.ProgramCounter)) {
|
|
extern int InterruptTime;
|
|
|
|
AddConstToVariable((incrementer * TestValue) * -1, &InterruptTime, "Instruction Count");
|
|
CompConstToVariable(0, &InterruptTime, "InterruptTime");
|
|
JgLabel8("ContinueExecution", 0);
|
|
JumpByte2 = Recompiler.X86CodePos.ubPtr - 1;
|
|
|
|
MoveConstToVariable(Recompiler.ProgramCounter, &pc, "PC");
|
|
CallFunctionDirect(&CheckInterrupts,"CheckInterrupts");
|
|
|
|
CompConstToVariable(Recompiler.ProgramCounter, &pc, "PC");
|
|
JeLabel8("ContinueExecution", 0);
|
|
JumpByte = Recompiler.X86CodePos.ubPtr - 1;
|
|
|
|
Ret();
|
|
|
|
Recompiler.Log(" ContinueExecution:");
|
|
SetBranch8b(JumpByte, Recompiler.X86CodePos.ptr);
|
|
SetBranch8b(JumpByte2, Recompiler.X86CodePos.ptr);
|
|
TestValue = 0;
|
|
}
|
|
|
|
r4300iCompiler_Opcode();
|
|
Recompiler.ProgramCounter += 4;
|
|
|
|
/* AddConstToVariable(incrementer, &instructions, "Instruction Count");
|
|
MoveConstToVariable(Recompiler.ProgramCounter, &pc, "PC");
|
|
CallFunctionDirect(&CheckInterrupts,"CheckInterrupts");
|
|
Ret();
|
|
*/
|
|
if (Recompiler.ProgramCounter >= BlockEnd) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* we cant risk invalidating the selfmod right now */
|
|
/*
|
|
MoveVariableToEax(Recompiler.GetJumpTablePtr(pc + Count), "JumpTable + PC");
|
|
CompConstToEax(0);
|
|
JeLabel8(" InvalidPointer", 0);
|
|
JumpByte = Recompiler.X86CodePos.ubPtr - 1;
|
|
JumpEax();
|
|
SetBranch8b(JumpByte, Recompiler.X86CodePos.ptr);
|
|
Recompiler.Log(" InvalidPointer:");
|
|
*/
|
|
MoveConstToVariable(Recompiler.ProgramCounter, &pc, "pc");
|
|
Ret();
|
|
|
|
return Recompiler.GetJumpTableEntry(pc);
|
|
}
|
|
|
|
BOOL r4300iCompiler_CheckMemory(void) {
|
|
DWORD Parent = Recompiler.GetParentAddress(pc);
|
|
//Recompiler.Log("r4300iCompiler_CheckMemory (%08X, Parent = %08X)", pc, Parent);
|
|
|
|
DWORD CurrentValue = Recompiler.GetParentCheckValue(pc);
|
|
//Recompiler.Log("r4300iCompiler_CheckMemory: %08X (Current)", CurrentValue);
|
|
|
|
DWORD CalculatedValue = r4300iCompiler_CalculateMemoryCheck(Parent);
|
|
//Recompiler.Log("r4300iCompiler_CheckMemory: %08X (Calculated)", CalculatedValue);
|
|
|
|
if (CalculatedValue != CurrentValue) {
|
|
DWORD count = 0;
|
|
//Recompiler.Log("r4300iCompiler_CheckMemory(%08X): %08X != %08X", pc, CalculatedValue, CurrentValue);
|
|
|
|
for (;;) {
|
|
Recompiler.SetJumpTableEntry(pc + count, NULL);
|
|
count += 4;
|
|
|
|
/*
|
|
* delay slot is irrelevant jump table entry is
|
|
* not relevant, it will be a separate block and
|
|
* by default will be recompiled for this one
|
|
*/
|
|
|
|
if (count >= R4300I_BLOCK_SIZE) {
|
|
break;
|
|
}
|
|
}
|
|
return FALSE;
|
|
} else {
|
|
//Recompiler.Log("r4300iCompiler_CheckMemory(%08X): %08X == %08X", pc, CalculatedValue, CurrentValue);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void r4300iCompiler_Execute(void) {
|
|
BUFFER_POINTER Block;
|
|
|
|
Recompiler.Log("r4300iCompiler_Execute(%08X)", pc);
|
|
|
|
while (FALSE == cpuIsReset) {
|
|
Block.ptr = Recompiler.GetJumpTableEntry(pc);
|
|
|
|
if (Block.ptr && FALSE == r4300iCompiler_CheckMemory()) {
|
|
Block.ptr = NULL;
|
|
}
|
|
|
|
if (Block.ptr == NULL) {
|
|
Recompiler.Log("Block.ptr(%08X) == NULL, Calling create", pc);
|
|
Block.ptr = r4300iCompiler_CreateBlock();
|
|
}
|
|
_asm {
|
|
pushad
|
|
call [Block.ptr]
|
|
popad
|
|
}
|
|
}
|
|
} |