From c8479e60fca7013a0ce87ed61b197a9654ba9246 Mon Sep 17 00:00:00 2001 From: cadmic Date: Wed, 15 May 2024 02:41:52 -0700 Subject: [PATCH] Match cpuFindFunction (#120) --- src/emulator/cpu.c | 441 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 439 insertions(+), 2 deletions(-) diff --git a/src/emulator/cpu.c b/src/emulator/cpu.c index 5be67cb..ab8752d 100644 --- a/src/emulator/cpu.c +++ b/src/emulator/cpu.c @@ -21,10 +21,13 @@ static bool cpuSetTLB(Cpu* pCPU, s32 iEntry); static bool cpuHeapReset(u32* array, s32 count); static bool cpuDMAUpdateFunction(Cpu* pCPU, s32 start, s32 end); static void treeCallerInit(CpuCallerID* block, s32 total); +static bool treeInit(Cpu* pCPU, s32 root_address); static bool treeKill(Cpu* pCPU); static bool treeKillNodes(Cpu* pCPU, CpuFunction* tree); static bool treeAdjustRoot(Cpu* pCPU, s32 new_start, s32 new_end); +static inline bool treeSearch(Cpu* pCPU, s32 target, CpuFunction** node); static bool treeSearchNode(CpuFunction* tree, s32 target, CpuFunction** node); +bool treeInsert(Cpu* pCPU, s32 start, s32 end); static bool treeInsertNode(CpuFunction** tree, s32 start, s32 end, CpuFunction** ppFunction); static bool treeBalance(CpuTreeRoot* root); static bool treeKillReason(Cpu* pCPU, s32* value); @@ -197,13 +200,20 @@ char D_800EC078[] = "tree range (%p - %p)\n"; char D_800EC090[] = "total nodes: %d (tree height: %d %d)\n"; char D_800EC0B8[] = "total memory: %d\n"; +#ifndef NON_MATCHING +// cpuFindFunction void* jtbl_800EC0CC[25] = { &lbl_8003381C, &lbl_80033A68, &lbl_80033A68, &lbl_8003381C, &lbl_8003381C, &lbl_80033A68, &lbl_8003381C, &lbl_8003381C, &lbl_80033A68, &lbl_8003381C, &lbl_8003381C, &lbl_8003381C, &lbl_8003381C, &lbl_8003381C, &lbl_8003381C, &lbl_8003381C, &lbl_8003381C, &lbl_8003381C, &lbl_8003381C, &lbl_8003381C, &lbl_8003381C, &lbl_8003381C, &lbl_8003381C, &lbl_8003381C, &lbl_800337F0, }; +#else +void* jtbl_800EC0CC[25] = {0}; +#endif +#ifndef NON_MATCHING +// cpuFindFunction void* jtbl_800EC130[44] = { &lbl_800334D8, &lbl_800335A0, &lbl_80033564, &lbl_80033A5C, &lbl_80033644, &lbl_80033768, &lbl_80033768, &lbl_80033768, &lbl_80033A5C, &lbl_80033A5C, &lbl_80033A5C, &lbl_80033A5C, &lbl_80033A5C, &lbl_80033A5C, @@ -213,6 +223,9 @@ void* jtbl_800EC130[44] = { &lbl_8003394C, &lbl_80033A5C, &lbl_80033A5C, &lbl_80033A5C, &lbl_80033A5C, &lbl_80033A5C, &lbl_80033A5C, &lbl_80033A5C, &lbl_80033938, }; +#else +void* jtbl_800EC130[44] = {0}; +#endif char D_800EC1E0[] = "_cpuGCN.c"; @@ -5803,7 +5816,419 @@ static inline bool cpuTreeFree(CpuFunction* pFunction) { return false; } +#ifndef NON_MATCHING #pragma GLOBAL_ASM("asm/non_matchings/cpu/cpuFindFunction.s") +#else +bool cpuFindFunction(Cpu* pCPU, s32 theAddress, CpuFunction** tree_node) { + CpuDevice** apDevice; + u8* aiDevice; + u32 opcode; + u8 follow; + u8 valid; + u8 check; + u8 end_flag; + u8 save_restore; + u8 alert; + s32 beginAddress; + s32 cheat_address; + s32 current_address; + s32 temp_address; + s32 branch; + int anAddr[3]; + s32 pad; + + save_restore = false; + alert = false; + cheat_address = 0; + if (pCPU->gTree == NULL) { + check = 0; + pCPU->survivalTimer = 1; + if (!xlHeapTake(&pCPU->gTree, sizeof(CpuTreeRoot))) { + return false; + } + treeInit(pCPU, 0x80150002); + } else { + check = 1; + if (treeSearch(pCPU, theAddress, tree_node)) { + pCPU->pFunctionLast = *tree_node; + return true; + } + } + + anAddr[0] = 0; + anAddr[1] = 0; + anAddr[2] = 0; + aiDevice = pCPU->aiDevice; + apDevice = pCPU->apDevice; + beginAddress = branch = theAddress; + current_address = theAddress; + + do { + CPU_DEVICE_GET32(apDevice, aiDevice, current_address, &opcode); + follow = true; + + if (check == 0) { + if (opcode != 0 && anAddr[0] == 0) { + anAddr[0] = current_address; + } + } else { + if (anAddr[0] == 0) { + anAddr[0] = current_address; + } + } + + valid = true; + end_flag = 0; + + switch ((u8)MIPS_OP(opcode)) { + case 0x00: { // special + switch ((u8)MIPS_FUNCT(opcode)) { + case 0x08: // jr + if (!save_restore && (anAddr[1] == 0 || current_address > anAddr[1]) && + (anAddr[2] == 0 || current_address >= anAddr[2])) { + end_flag = 111; + } + break; + case 0x0D: // break + if ((anAddr[1] == 0 || current_address > anAddr[1]) && + (anAddr[2] == 0 || current_address >= anAddr[2])) { + end_flag = 111; + save_restore = false; + } + break; + default: + valid = SpecialOpcode[MIPS_FUNCT(opcode)]; + break; + } + break; + } + case 0x02: // j + if ((branch = (MIPS_TARGET(opcode) << 2) | (current_address & 0xF0000000)) >= current_address && + branch - current_address <= 0x1000) { + if (anAddr[2] == 0) { + anAddr[2] = branch; + } else if (branch > anAddr[2]) { + anAddr[2] = branch; + } + } + break; + case 0x01: // regimm + switch ((u8)MIPS_RT(opcode)) { + case 0x00: // bltz + case 0x01: // bgez + case 0x02: // bltzl + case 0x03: // bgezl + case 0x10: // bltzal + case 0x11: // bgezal + case 0x12: // bltzall + case 0x13: // bgezall + branch = MIPS_IMM_S16(opcode) * 4; + if (branch < 0) { + if (check == 1 && current_address + branch + 4 < beginAddress) { + anAddr[0] = 0; + anAddr[1] = 0; + anAddr[2] = 0; + beginAddress = current_address + branch + 4; + current_address = current_address + branch + 4; + alert = true; + continue; + } + } else { + if (anAddr[1] == 0) { + anAddr[1] = current_address + branch; + } else if (current_address + branch > anAddr[1]) { + anAddr[1] = current_address + branch; + } + } + break; + default: + valid = RegimmOpcode[MIPS_RT(opcode)]; + break; + } + break; + case 0x04: // beq + case 0x14: // beql + branch = MIPS_IMM_S16(opcode) * 4; + if (branch < 0) { + if (check == 1 && current_address + branch + 4 < beginAddress) { + anAddr[0] = 0; + anAddr[1] = 0; + anAddr[2] = 0; + beginAddress = current_address + branch + 4; + current_address = current_address + branch + 4; + alert = true; + continue; + } + + temp_address = current_address + 8; + CPU_DEVICE_GET32(apDevice, aiDevice, temp_address, &opcode); + if (opcode == 0) { + do { + temp_address += 4; + CPU_DEVICE_GET32(apDevice, aiDevice, temp_address, &opcode); + } while (opcode == 0); + + if (MIPS_OP(opcode) != 0x23) { // lw + current_address = temp_address - 8; + if ((anAddr[1] == 0 || current_address > anAddr[1]) && + (anAddr[2] == 0 || current_address >= anAddr[2])) { + end_flag = 111; + save_restore = false; + } + } else { + current_address = temp_address - 4; + } + } + } else { + if (anAddr[1] == 0) { + anAddr[1] = current_address + branch; + } else if (current_address + branch > anAddr[1]) { + anAddr[1] = current_address + branch; + } + } + break; + case 0x05: // bne + case 0x06: // blez + case 0x07: // bgtz + case 0x15: // bnel + case 0x16: // blezl + case 0x17: // bgtzl + branch = MIPS_IMM_S16(opcode) * 4; + if (branch < 0) { + if (check == 1 && current_address + branch + 4 < beginAddress) { + anAddr[0] = 0; + anAddr[1] = 0; + anAddr[2] = 0; + beginAddress = current_address + branch + 4; + current_address = current_address + branch + 4; + alert = true; + continue; + } + } else { + if (anAddr[1] == 0) { + anAddr[1] = current_address + branch; + } else if (current_address + branch > anAddr[1]) { + anAddr[1] = current_address + branch; + } + } + break; + case 0x10: // cop0 + switch ((u8)MIPS_FUNCT(opcode)) { + case 0x01: // tlbr + case 0x02: // tlbwi + case 0x05: // tlbwr + case 0x08: // tlbp + break; + case 0x18: // eret + if ((anAddr[1] == 0 || current_address > anAddr[1]) && + (anAddr[2] == 0 || current_address >= anAddr[2])) { + end_flag = 222; + save_restore = false; + } + break; + default: + switch ((u8)MIPS_FMT(opcode)) { + case 0x08: + switch (MIPS_FT(opcode)) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + branch = MIPS_IMM_S16(opcode) * 4; + if (branch < 0) { + if (check == 1 && current_address + branch + 4 < beginAddress) { + anAddr[0] = 0; + anAddr[1] = 0; + anAddr[2] = 0; + beginAddress = current_address + branch + 4; + current_address = current_address + branch + 4; + alert = true; + continue; + } + } else { + if (anAddr[1] == 0) { + anAddr[1] = current_address + branch; + } else if (current_address + branch > anAddr[1]) { + anAddr[1] = current_address + branch; + } + } + break; + } + break; + } + break; + } + break; + case 0x11: // cop1 + if (MIPS_FMT(opcode) == 0x08) { + switch ((u8)MIPS_FT(opcode)) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + branch = MIPS_IMM_S16(opcode) * 4; + if (branch < 0) { + if (check == 1 && current_address + branch + 4 < beginAddress) { + anAddr[0] = 0; + anAddr[1] = 0; + anAddr[2] = 0; + beginAddress = current_address + branch + 4; + current_address = current_address + branch + 4; + alert = true; + continue; + } + } else { + if (anAddr[1] == 0) { + anAddr[1] = current_address + branch; + } else if (current_address + branch > anAddr[1]) { + anAddr[1] = current_address + branch; + } + } + break; + } + } + break; + case 0x2B: // sw + if (MIPS_RT(opcode) == 31) { + save_restore = true; + } + break; + case 0x23: // lw + if (MIPS_RT(opcode) == 31) { + save_restore = false; + if (check == 1 && alert) { + current_address = beginAddress; + + while (true) { + CPU_DEVICE_GET32(apDevice, aiDevice, current_address, &opcode); + if (MIPS_OP(opcode) == 0x2B && MIPS_RT(opcode) == 31) { // sw ra, ... + break; + } + current_address -= 4; + } + + do { + current_address -= 4; + CPU_DEVICE_GET32(apDevice, aiDevice, current_address, &opcode); + if (opcode != 0 && treeSearch(pCPU, current_address - 4, tree_node)) { + break; + } + } while (opcode != 0); + + anAddr[0] = 0; + anAddr[1] = 0; + anAddr[2] = 0; + current_address = beginAddress = current_address + 4; + alert = false; + continue; + } + } + break; + default: + valid = Opcode[MIPS_OP(opcode)]; + break; + } + + if (end_flag != 0) { + if (end_flag == 111) { + anAddr[2] = current_address + 4; + current_address += 8; + } else { + anAddr[2] = current_address; + current_address += 4; + } + + if (check == 0) { + if (romTestCode(SYSTEM_ROM(pCPU->pHost), D_8013522C)) { + if (current_address == 0x800BB62C) { + current_address = 0x800BB9B0; + } else if (current_address == 0x800CC010) { + valid = false; + } + } else if (romTestCode(SYSTEM_ROM(pCPU->pHost), D_80135234)) { + if (anAddr[2] == 0x800A9D40) { + anAddr[0] = 0x800A9CF0; + cheat_address = anAddr[0]; + } + } else if (romTestCode(SYSTEM_ROM(pCPU->pHost), D_8013523C)) { + if (current_address == 0x80000470) { + current_address = 0x80000870; + } else if (anAddr[2] == 0x80001248) { + anAddr[2] = 0x80001884; + current_address = 0x80001890; + } + } else if (romTestCode(SYSTEM_ROM(pCPU->pHost), D_80135244)) { + if (current_address == 0x800829CC) { + current_address = 0x80082D60; + } + } else if (romTestCode(SYSTEM_ROM(pCPU->pHost), D_8013524C)) { + if (current_address == 0x8000E1C8) { + if (!treeInsert(pCPU, 0x8007ED94, 0x8007F55C)) { + return false; + } + treeSearch(pCPU, 0x8007ED94, tree_node); + (*tree_node)->timeToLive = 0; + } + } else if (romTestCode(SYSTEM_ROM(pCPU->pHost), D_80135254)) { + if (current_address == 0x8000E1C8) { + if (!treeInsert(pCPU, 0x8007EC54, 0x8007F41C)) { + return false; + } + treeSearch(pCPU, 0x8007EC54, tree_node); + (*tree_node)->timeToLive = 0; + } + } + } + + if (!treeInsert(pCPU, anAddr[0], anAddr[2])) { + return false; + } + + if (cheat_address != 0) { + treeSearch(pCPU, cheat_address, tree_node); + cheat_address = 0; + (*tree_node)->timeToLive = 0; + } + + if (check == 1) { + if (treeSearch(pCPU, theAddress, tree_node)) { + pCPU->pFunctionLast = *tree_node; + return true; + } else { + return false; + } + } + + follow = false; + anAddr[0] = 0; + anAddr[1] = 0; + anAddr[2] = 0; + if (check == 0 && pCPU->gTree->total > 3970) { + valid = false; + } + } + + if (follow) { + current_address += 4; + } + } while (valid); + + if (check == 0) { + treeInsert(pCPU, 0x80000180, 0x8000018C); + treeSearch(pCPU, 0x80000180, tree_node); + (*tree_node)->timeToLive = 0; + + if (treeSearch(pCPU, theAddress, tree_node)) { + pCPU->pFunctionLast = *tree_node; + return true; + } else { + return false; + } + } + + return false; +} +#endif static bool cpuDMAUpdateFunction(Cpu* pCPU, s32 start, s32 end) { CpuTreeRoot* root = pCPU->gTree; @@ -5920,7 +6345,7 @@ static bool treeCallerCheck(Cpu* pCPU, CpuFunction* tree, bool flag, s32 nAddres return true; } -s32 treeInit(Cpu* pCPU, s32 root_address) { +static bool treeInit(Cpu* pCPU, s32 root_address) { CpuTreeRoot* root = pCPU->gTree; if (root == NULL) { @@ -6205,7 +6630,7 @@ static bool treeDeleteNode(Cpu* pCPU, CpuFunction** top, CpuFunction* kill) { return true; } -s32 treeInsert(Cpu* pCPU, s32 start, s32 end) { +bool treeInsert(Cpu* pCPU, s32 start, s32 end) { CpuTreeRoot* root; CpuFunction* current; s32 flag; @@ -6418,6 +6843,18 @@ static bool treeAdjustRoot(Cpu* pCPU, s32 new_start, s32 new_end) { return true; } +static inline bool treeSearch(Cpu* pCPU, s32 target, CpuFunction** node) { + CpuTreeRoot* root = pCPU->gTree; + bool flag; + + if (target < root->root_address) { + flag = treeSearchNode(root->left, target, node); + } else { + flag = treeSearchNode(root->right, target, node); + } + return flag; +} + static bool treeSearchNode(CpuFunction* tree, s32 target, CpuFunction** node) { CpuFunction* current;