diff --git a/Source/Core/Core/Src/GeckoCode.cpp b/Source/Core/Core/Src/GeckoCode.cpp index 590f56980c..85d8c65a17 100644 --- a/Source/Core/Core/Src/GeckoCode.cpp +++ b/Source/Core/Core/Src/GeckoCode.cpp @@ -61,6 +61,9 @@ static Common::CriticalSection active_codes_lock; static GeckoCode::Code *codes_start = NULL, *current_code = NULL; static const GeckoCode::Code *codes_end = NULL; +// asm codes used for CT6 CST1 +static std::map > inserted_asm_codes; + // Functions for each code type bool RamWriteAndFill(); bool RegularIf(); @@ -91,6 +94,8 @@ void SetActiveCodes(const std::vector& gcodes) } active_codes_lock.Leave(); + + inserted_asm_codes.clear(); } bool RunGeckoCode(GeckoCode& gecko_code) @@ -163,6 +168,10 @@ bool RunActiveCodes() return true; } +const std::map >& GetInsertedAsmCodes() { + return inserted_asm_codes; +} + // CT0: Direct ram write/fill // COMPLETE, maybe bool RamWriteAndFill() @@ -817,9 +826,30 @@ bool AsmSwitchRange() // CST1 : Insert ASM code in the game case 0x1 : - // TODO: - return false; - break; + { + const int number_of_codes = code.data; + std::vector& asm_code = inserted_asm_codes[code.GetAddress()]; + if (asm_code.empty()) { + for (int index = 0; index < number_of_codes; ++index) { + // Reserved for padding + if (current_code[index + 1].address != 0x60000000) { + asm_code.push_back(current_code[index + 1].address); + } + + // Reserved for b instruction + if (current_code[index + 1].data != 0x00000000) { + asm_code.push_back(current_code[index + 1].data); + } + } + } + + // Though the next code starts at current_code+number_of_codes+1, + // we add only number_of_codes. It is because the for statemet in + // RunGeckoCode() increments current_code. + current_code += number_of_codes; + + break; + } // CST3 : Create a branch case 0x3 : diff --git a/Source/Core/Core/Src/GeckoCode.h b/Source/Core/Core/Src/GeckoCode.h index af8c17e6a2..f99cb45c38 100644 --- a/Source/Core/Core/Src/GeckoCode.h +++ b/Source/Core/Core/Src/GeckoCode.h @@ -66,6 +66,7 @@ namespace Gecko void SetActiveCodes(const std::vector& gcodes); bool RunActiveCodes(); + const std::map >& GetInsertedAsmCodes(); } // namespace Gecko diff --git a/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp b/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp index bb94789588..a7374de23d 100644 --- a/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp +++ b/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp @@ -25,6 +25,7 @@ #include "SignatureDB.h" #include "PPCAnalyst.h" #include "../ConfigManager.h" +#include "../GeckoCode.h" // Analyzes PowerPC code in memory to find functions // After running, for each function we will know what functions it calls @@ -327,17 +328,60 @@ u32 Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, u32 returnAddress = 0; + // Used for Gecko CST1 code. (See GeckoCode/GeckoCode.h) + // We use std::queue but it is not so slow + // because cst1_instructions does not allocate memory so many times. + std::queue cst1_instructions; + const std::map >& inserted_asm_codes = + Gecko::GetInsertedAsmCodes(); + // Do analysis of the code, look for dependencies etc int numSystemInstructions = 0; for (int i = 0; i < maxsize; i++) - { - UGeckoInstruction inst = Memory::Read_Opcode_JIT(address); + { + UGeckoInstruction inst; + + if (!cst1_instructions.empty()) + { + // If the Gecko CST1 instruction queue is not empty, + // we comsume the first instruction. + inst = UGeckoInstruction(cst1_instructions.front()); + cst1_instructions.pop(); + address -= 4; + + } + else + { + // If the address is the insertion point of Gecko CST1 code, + // we push the code into the instruction queue and + // consume the first instruction. + std::map >::const_iterator it = + inserted_asm_codes.find(address); + if (it != inserted_asm_codes.end()) + { + const std::vector& codes = it->second; + for (std::vector::const_iterator it = codes.begin(), + itEnd = codes.end(); it != itEnd; ++it) + { + cst1_instructions.push(*it); + } + inst = UGeckoInstruction(cst1_instructions.front()); + cst1_instructions.pop(); + + } + else + { + inst = Memory::Read_Opcode_JIT(address); + } + } + if (inst.hex != 0) { num_inst++; memset(&code[i], 0, sizeof(CodeOp)); GekkoOPInfo *opinfo = GetOpInfo(inst); code[i].opinfo = opinfo; + // FIXME: code[i].address may not be correct due to CST1 code. code[i].address = address; code[i].inst = inst; code[i].branchTo = -1;