MFF_NO_RETURN flag introduced

This commit is contained in:
Nekotekina 2015-05-29 01:49:50 +03:00
parent a70d305806
commit b84d831d8f
4 changed files with 129 additions and 74 deletions

View File

@ -2004,19 +2004,10 @@ void Compiler::BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) {
}
void Compiler::HACK(u32 index) {
if (index & EIF_SAVE_RTOC) {
auto addr_i64 = (Value *)m_ir_builder->getInt64(0x28);
auto ra_i64 = GetGpr(1);
addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64);
WriteMemory(addr_i64, GetGpr(2, 64));
}
Call<void>("execute_ppu_func_by_index", &execute_ppu_func_by_index, m_state.args[CompileTaskState::Args::State], m_ir_builder->getInt32(index & ~EIF_FLAGS));
if (index & EIF_PERFORM_BLR) {
auto lr_i64 = GetLr();
lr_i64 = m_ir_builder->CreateAnd(lr_i64, ~0x3ULL);
auto lr_i32 = m_ir_builder->CreateTrunc(lr_i64, m_ir_builder->getInt32Ty());
CreateBranch(nullptr, lr_i32, false, true);
Call<void>("execute_ppu_func_by_index", &execute_ppu_func_by_index, m_state.args[CompileTaskState::Args::State], m_ir_builder->getInt32(index & EIF_USE_BRANCH ? index : index & ~EIF_PERFORM_BLR));
if (index & EIF_PERFORM_BLR || index & EIF_USE_BRANCH) {
auto lr_i32 = index & EIF_USE_BRANCH ? GetPc() : m_ir_builder->CreateTrunc(m_ir_builder->CreateAnd(GetLr(), ~0x3ULL), m_ir_builder->getInt32Ty());
CreateBranch(nullptr, lr_i32, false, (index & EIF_USE_BRANCH) == 0);
}
// copied from Compiler::SC()
//auto ret_i1 = Call<bool>("PollStatus", m_poll_status_function, m_state.args[CompileTaskState::Args::State]);
@ -6089,9 +6080,10 @@ BranchType ppu_recompiler_llvm::GetBranchTypeFromInstruction(u32 instruction) {
} else if (field2 == 528) {
type = lk ? BranchType::FunctionCall : BranchType::LocalBranch;
}
} else if (field1 == 1 && (instruction & EIF_PERFORM_BLR)) {
type = BranchType::Return;
} else if (field1 == 1 && (instruction & EIF_PERFORM_BLR)) { // classify HACK instruction
type = instruction & EIF_USE_BRANCH ? BranchType::FunctionCall : BranchType::Return;
} else if (field1 == 1 && (instruction & EIF_USE_BRANCH)) {
type = BranchType::LocalBranch;
}
return type;
}

View File

@ -15,9 +15,19 @@ std::vector<StaticFunc> g_ppu_func_subs;
u32 add_ppu_func(ModuleFunc func)
{
if (g_ppu_func_list.empty())
{
// prevent relocations if the array growths, must be sizeof(ModuleFunc) * 0x8000 ~~ about 1 MB of memory
g_ppu_func_list.reserve(0x8000);
}
for (auto& f : g_ppu_func_list)
{
assert(f.id != func.id);
if (f.id == func.id)
{
// TODO: if NIDs overlap or if the same function is added twice
assert(!"add_ppu_func(): NID already exists");
}
}
g_ppu_func_list.push_back(func);
@ -93,15 +103,56 @@ void execute_ppu_func_by_index(PPUThread& CPU, u32 index)
{
if (auto func = get_ppu_func_by_index(index))
{
auto old_last_syscall = CPU.m_last_syscall;
CPU.m_last_syscall = func->id;
// save RTOC if necessary
if (index & EIF_SAVE_RTOC)
{
// save RTOC if necessary
vm::write64(vm::cast(CPU.GPR[1] + 0x28), CPU.GPR[2]);
}
// save old syscall/NID value
auto old_last_syscall = CPU.m_last_syscall;
// branch directly to the LLE function
if (index & EIF_USE_BRANCH)
{
// for example, FastCall2 can't work with functions which do user level context switch
if (old_last_syscall)
{
throw "Unfortunately, this function cannot be called from the callback.";
}
if (!func->lle_func)
{
throw "Wrong usage: LLE function not set.";
}
if (func->flags & MFF_FORCED_HLE)
{
throw "Wrong usage: Forced HLE enabled.";
}
if (Ini.HLELogging.GetValue())
{
LOG_NOTICE(HLE, "Branch to LLE function: %s", SysCalls::GetFuncName(func->id));
}
if (index & EIF_PERFORM_BLR)
{
throw "TODO: Branch with link";
// CPU.LR = CPU.PC + 4;
}
const auto data = vm::get_ptr<be_t<u32>>(func->lle_func.addr());
CPU.SetBranch(data[0]);
CPU.GPR[2] = data[1]; // set rtoc
return;
}
// change current syscall/NID value
CPU.m_last_syscall = func->id;
if (func->lle_func && !(func->flags & MFF_FORCED_HLE))
{
// call LLE function if available
@ -427,6 +478,15 @@ bool patch_ppu_import(u32 addr, u32 index)
using namespace PPU_instr;
if (index >= g_ppu_func_list.size())
{
return false;
}
const u32 imm = (g_ppu_func_list[index].flags & MFF_NO_RETURN) && !(g_ppu_func_list[index].flags & MFF_FORCED_HLE)
? index | EIF_USE_BRANCH
: index | EIF_PERFORM_BLR;
// check different patterns:
if (vm::check_addr(addr, 32) &&
@ -439,7 +499,7 @@ bool patch_ppu_import(u32 addr, u32 index)
data[6] == MTCTR(r0) &&
data[7] == BCTR())
{
vm::write32(addr, HACK(index | EIF_SAVE_RTOC | EIF_PERFORM_BLR));
vm::write32(addr, HACK(imm | EIF_SAVE_RTOC));
return true;
}
@ -467,7 +527,7 @@ bool patch_ppu_import(u32 addr, u32 index)
sub[0xd] == MTLR(r0) &&
sub[0xe] == BLR())
{
vm::write32(addr, HACK(index | EIF_PERFORM_BLR));
vm::write32(addr, HACK(imm));
return true;
}
}
@ -490,7 +550,7 @@ bool patch_ppu_import(u32 addr, u32 index)
data[0xe] == MTLR(r0) &&
data[0xf] == BLR())
{
vm::write32(addr, HACK(index | EIF_PERFORM_BLR));
vm::write32(addr, HACK(imm));
return true;
}
@ -511,7 +571,7 @@ bool patch_ppu_import(u32 addr, u32 index)
data[0xd] == MTLR(r0) &&
data[0xe] == BLR())
{
vm::write32(addr, HACK(index | EIF_PERFORM_BLR));
vm::write32(addr, HACK(imm));
return true;
}
@ -531,7 +591,7 @@ bool patch_ppu_import(u32 addr, u32 index)
data[0xc] == LD(r2, r1, 0x28) &&
data[0xd] == BLR())
{
vm::write32(addr, HACK(index | EIF_PERFORM_BLR));
vm::write32(addr, HACK(imm));
return true;
}

View File

@ -9,6 +9,7 @@ class Module;
enum : u32
{
MFF_FORCED_HLE = (1 << 0), // always call HLE function
MFF_NO_RETURN = (1 << 1), // uses EIF_USE_BRANCH flag with LLE, ignored with MFF_FORCED_HLE
};
// flags passed with index
@ -16,8 +17,9 @@ enum : u32
{
EIF_SAVE_RTOC = (1 << 25), // save RTOC in [SP+0x28] before calling HLE/LLE function
EIF_PERFORM_BLR = (1 << 24), // do BLR after calling HLE/LLE function
EIF_USE_BRANCH = (1 << 23), // do only branch, LLE must be set, last_syscall must be zero
EIF_FLAGS = 0x3000000, // all flags
EIF_FLAGS = 0x3800000, // all flags
};
struct ModuleFunc
@ -121,6 +123,7 @@ bool patch_ppu_import(u32 addr, u32 index);
#define REG_FUNC(module, name) add_ppu_func(ModuleFunc(get_function_id(#name), 0, &module, #name, bind_func(name)))
#define REG_FUNC_FH(module, name) add_ppu_func(ModuleFunc(get_function_id(#name), MFF_FORCED_HLE, &module, #name, bind_func(name)))
#define REG_FUNC_NR(module, name) add_ppu_func(ModuleFunc(get_function_id(#name), MFF_NO_RETURN, &module, #name, bind_func(name)))
#define REG_UNNAMED(module, nid) add_ppu_func(ModuleFunc(0x##nid, 0, &module, "_nid_"#nid, bind_func(_nid_##nid)))

View File

@ -293,57 +293,57 @@ int cellFiberPpuUtilWorkerControlInitializeWithAttribute()
Module cellFiber("cellFiber", []()
{
REG_FUNC(cellFiber, _cellFiberPpuInitialize);
REG_FUNC_NR(cellFiber, _cellFiberPpuInitialize);
REG_FUNC(cellFiber, _cellFiberPpuSchedulerAttributeInitialize);
REG_FUNC(cellFiber, cellFiberPpuInitializeScheduler);
REG_FUNC(cellFiber, cellFiberPpuFinalizeScheduler);
REG_FUNC(cellFiber, cellFiberPpuRunFibers);
REG_FUNC(cellFiber, cellFiberPpuCheckFlags);
REG_FUNC(cellFiber, cellFiberPpuHasRunnableFiber);
REG_FUNC_NR(cellFiber, _cellFiberPpuSchedulerAttributeInitialize);
REG_FUNC_NR(cellFiber, cellFiberPpuInitializeScheduler);
REG_FUNC_NR(cellFiber, cellFiberPpuFinalizeScheduler);
REG_FUNC_NR(cellFiber, cellFiberPpuRunFibers);
REG_FUNC_NR(cellFiber, cellFiberPpuCheckFlags);
REG_FUNC_NR(cellFiber, cellFiberPpuHasRunnableFiber);
REG_FUNC(cellFiber, _cellFiberPpuAttributeInitialize);
REG_FUNC(cellFiber, cellFiberPpuCreateFiber);
REG_FUNC(cellFiber, cellFiberPpuExit);
REG_FUNC(cellFiber, cellFiberPpuYield);
REG_FUNC(cellFiber, cellFiberPpuJoinFiber);
REG_FUNC(cellFiber, cellFiberPpuSelf);
REG_FUNC(cellFiber, cellFiberPpuSendSignal);
REG_FUNC(cellFiber, cellFiberPpuWaitSignal);
REG_FUNC(cellFiber, cellFiberPpuWaitFlag);
REG_FUNC(cellFiber, cellFiberPpuGetScheduler);
REG_FUNC(cellFiber, cellFiberPpuSetPriority);
REG_FUNC(cellFiber, cellFiberPpuCheckStackLimit);
REG_FUNC_NR(cellFiber, _cellFiberPpuAttributeInitialize);
REG_FUNC_NR(cellFiber, cellFiberPpuCreateFiber);
REG_FUNC_NR(cellFiber, cellFiberPpuExit);
REG_FUNC_NR(cellFiber, cellFiberPpuYield);
REG_FUNC_NR(cellFiber, cellFiberPpuJoinFiber);
REG_FUNC_NR(cellFiber, cellFiberPpuSelf);
REG_FUNC_NR(cellFiber, cellFiberPpuSendSignal);
REG_FUNC_NR(cellFiber, cellFiberPpuWaitSignal);
REG_FUNC_NR(cellFiber, cellFiberPpuWaitFlag);
REG_FUNC_NR(cellFiber, cellFiberPpuGetScheduler);
REG_FUNC_NR(cellFiber, cellFiberPpuSetPriority);
REG_FUNC_NR(cellFiber, cellFiberPpuCheckStackLimit);
REG_FUNC(cellFiber, _cellFiberPpuContextAttributeInitialize);
REG_FUNC(cellFiber, cellFiberPpuContextInitialize);
REG_FUNC(cellFiber, cellFiberPpuContextFinalize);
REG_FUNC(cellFiber, cellFiberPpuContextRun);
REG_FUNC(cellFiber, cellFiberPpuContextSwitch);
REG_FUNC(cellFiber, cellFiberPpuContextSelf);
REG_FUNC(cellFiber, cellFiberPpuContextReturnToThread);
REG_FUNC(cellFiber, cellFiberPpuContextCheckStackLimit);
REG_FUNC_NR(cellFiber, _cellFiberPpuContextAttributeInitialize);
REG_FUNC_NR(cellFiber, cellFiberPpuContextInitialize);
REG_FUNC_NR(cellFiber, cellFiberPpuContextFinalize);
REG_FUNC_NR(cellFiber, cellFiberPpuContextRun);
REG_FUNC_NR(cellFiber, cellFiberPpuContextSwitch);
REG_FUNC_NR(cellFiber, cellFiberPpuContextSelf);
REG_FUNC_NR(cellFiber, cellFiberPpuContextReturnToThread);
REG_FUNC_NR(cellFiber, cellFiberPpuContextCheckStackLimit);
REG_FUNC(cellFiber, cellFiberPpuContextRunScheduler);
REG_FUNC(cellFiber, cellFiberPpuContextEnterScheduler);
REG_FUNC_NR(cellFiber, cellFiberPpuContextRunScheduler);
REG_FUNC_NR(cellFiber, cellFiberPpuContextEnterScheduler);
REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceInitialize);
REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceFinalize);
REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceStart);
REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceStop);
REG_FUNC_NR(cellFiber, cellFiberPpuSchedulerTraceInitialize);
REG_FUNC_NR(cellFiber, cellFiberPpuSchedulerTraceFinalize);
REG_FUNC_NR(cellFiber, cellFiberPpuSchedulerTraceStart);
REG_FUNC_NR(cellFiber, cellFiberPpuSchedulerTraceStop);
REG_FUNC(cellFiber, _cellFiberPpuUtilWorkerControlAttributeInitialize);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlRunFibers);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlInitialize);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlSetPollingMode);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlJoinFiber);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlDisconnectEventQueue);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlSendSignal);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlConnectEventQueueToSpurs);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlFinalize);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlWakeup);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlCreateFiber);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlShutdown);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlCheckFlags);
REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlInitializeWithAttribute);
REG_FUNC_NR(cellFiber, _cellFiberPpuUtilWorkerControlAttributeInitialize);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlRunFibers);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlInitialize);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlSetPollingMode);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlJoinFiber);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlDisconnectEventQueue);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlSendSignal);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlConnectEventQueueToSpurs);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlFinalize);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlWakeup);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlCreateFiber);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlShutdown);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlCheckFlags);
REG_FUNC_NR(cellFiber, cellFiberPpuUtilWorkerControlInitializeWithAttribute);
});