mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-24 11:51:04 +00:00
Added Thumb rejection. Can run retail games now.
This commit is contained in:
parent
1b87113184
commit
840ab06561
@ -152,7 +152,7 @@ void ModuleGen::GenerateGetBlockAddressFunction()
|
||||
/*
|
||||
entry_basic_block:
|
||||
auto index = (pc - block_address_array_base) / 4;
|
||||
if(index < block_address_array_size)
|
||||
if(((pc & 3) == 0) && index < block_address_array_size)
|
||||
{
|
||||
index_in_bounds_basic_block:
|
||||
return block_address_array[index];
|
||||
@ -169,10 +169,12 @@ void ModuleGen::GenerateGetBlockAddressFunction()
|
||||
auto index_out_of_bounds_basic_block = BasicBlock::Create(getGlobalContext(), "IndexOutOfBounds", get_block_address_function);
|
||||
|
||||
ir_builder->SetInsertPoint(entry_basic_block);
|
||||
auto index = ir_builder->CreateUDiv(pc, ir_builder->getInt32(4));
|
||||
auto index = ir_builder->CreateUDiv(pc, ir_builder->getInt32(4), "", true);
|
||||
index = ir_builder->CreateSub(index, ir_builder->getInt32(block_address_array_base));
|
||||
auto in_bounds_pred = ir_builder->CreateICmpULT(index, ir_builder->getInt32(block_address_array_size));
|
||||
ir_builder->CreateCondBr(in_bounds_pred, index_in_bounds_basic_block, index_out_of_bounds_basic_block);
|
||||
auto arm_pred = ir_builder->CreateICmpEQ(ir_builder->CreateAnd(pc, 3), ir_builder->getInt32(0));
|
||||
auto pred = ir_builder->CreateAnd(in_bounds_pred, arm_pred);
|
||||
ir_builder->CreateCondBr(pred, index_in_bounds_basic_block, index_out_of_bounds_basic_block);
|
||||
|
||||
ir_builder->SetInsertPoint(index_in_bounds_basic_block);
|
||||
Value *gep_values[] = { ir_builder->getInt32(0), index };
|
||||
|
@ -11,21 +11,66 @@ using namespace llvm;
|
||||
|
||||
bool g_enabled = false;
|
||||
bool g_verify = false;
|
||||
ARMul_State *g_state;
|
||||
|
||||
std::unique_ptr<SectionMemoryManager> g_memory_manager;
|
||||
std::unique_ptr<RuntimeDyld> g_dyld;
|
||||
std::unique_ptr<RuntimeDyld::LoadedObjectInfo> g_loaded_object_info;
|
||||
|
||||
void (*g_run_function)();
|
||||
void(*g_run_function)();
|
||||
bool(*g_can_run_function)();
|
||||
|
||||
// Used by the verifier
|
||||
bool (*g_can_run_function)();
|
||||
struct SavedState
|
||||
{
|
||||
SavedState() { }
|
||||
SavedState(const ARMul_State &state)
|
||||
{
|
||||
memcpy(regs, state.Reg, sizeof(regs));
|
||||
memcpy(flags, &state.NFlag, sizeof(flags));
|
||||
t_flag = state.TFlag;
|
||||
}
|
||||
void CopyTo(ARMul_State &state)
|
||||
{
|
||||
memcpy(state.Reg, regs, sizeof(regs));
|
||||
memcpy(&state.NFlag, flags, sizeof(flags));
|
||||
t_flag = state.TFlag;
|
||||
}
|
||||
void SwapWith(ARMul_State &state)
|
||||
{
|
||||
SavedState arm_state = state;
|
||||
std::swap(*this, arm_state);
|
||||
arm_state.CopyTo(state);
|
||||
}
|
||||
void Print()
|
||||
{
|
||||
LOG_ERROR(BinaryTranslator, "%08x %08x %08x %08x %08x %08x %08x %08x",
|
||||
regs[0], regs[1], regs[2], regs[3],
|
||||
regs[4], regs[5], regs[6], regs[7]);
|
||||
LOG_ERROR(BinaryTranslator, "%08x %08x %08x %08x %08x %08x %08x %08x",
|
||||
regs[8], regs[9], regs[10], regs[11],
|
||||
regs[12], regs[13], regs[14], regs[15]);
|
||||
LOG_ERROR(BinaryTranslator, "%01x %01x %01x %01x %01x", flags[0], flags[1], flags[2], flags[3], t_flag);
|
||||
}
|
||||
|
||||
u32 regs[16];
|
||||
u32 flags[4];
|
||||
u32 t_flag;
|
||||
};
|
||||
|
||||
bool operator==(const SavedState& lhs, const SavedState& rhs)
|
||||
{
|
||||
return memcmp(&lhs, &rhs, sizeof(lhs)) == 0;
|
||||
}
|
||||
|
||||
bool operator!=(const SavedState& lhs, const SavedState& rhs)
|
||||
{
|
||||
return memcmp(&lhs, &rhs, sizeof(lhs)) != 0;
|
||||
}
|
||||
|
||||
bool g_have_saved_state; // Whether there is a copied state
|
||||
ARMul_State *g_state;
|
||||
u32 g_regs_copy[16];
|
||||
u32 g_flags_copy[4];
|
||||
u32 g_regs_copy_before[16];
|
||||
u32 g_flags_copy_before[4];
|
||||
SavedState g_state_copy;
|
||||
SavedState g_state_copy_before;
|
||||
|
||||
void BinaryTranslationLoader::Load(FileUtil::IOFile& file)
|
||||
{
|
||||
@ -90,12 +135,35 @@ void BinaryTranslationLoader::SetCpuState(ARMul_State* state)
|
||||
g_state = state;
|
||||
}
|
||||
|
||||
bool BinaryTranslationLoader::CanRun(bool specific_address)
|
||||
{
|
||||
if (!g_enabled) return false;
|
||||
// Thumb not implemented
|
||||
if (g_state->TFlag) return false;
|
||||
if (specific_address)
|
||||
if (!g_can_run_function()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void BinaryTranslationLoader::Run()
|
||||
{
|
||||
// No need to check the PC, Run does it anyway
|
||||
if (!CanRun(false)) return;
|
||||
// If verify is enabled, it will run opcodes
|
||||
if (!g_enabled || g_verify) return;
|
||||
if (g_verify) return;
|
||||
|
||||
RunInternal();
|
||||
}
|
||||
|
||||
void BinaryTranslationLoader::RunInternal()
|
||||
{
|
||||
g_run_function();
|
||||
|
||||
g_state->TFlag = g_state->Reg[15] & 1;
|
||||
if (g_state->TFlag)
|
||||
g_state->Reg[15] &= 0xfffffffe;
|
||||
else
|
||||
g_state->Reg[15] &= 0xfffffffc;
|
||||
}
|
||||
|
||||
void Swap(void *a, void *b, size_t size)
|
||||
@ -108,65 +176,53 @@ void Swap(void *a, void *b, size_t size)
|
||||
}
|
||||
}
|
||||
|
||||
void ShowRegs(u32 *regs, u32 *flags)
|
||||
{
|
||||
LOG_ERROR(BinaryTranslator, "%08x %08x %08x %08x %08x %08x %08x %08x",
|
||||
regs[0], regs[1], regs[2], regs[3],
|
||||
regs[4], regs[5], regs[6], regs[7]);
|
||||
LOG_ERROR(BinaryTranslator, "%08x %08x %08x %08x %08x %08x %08x %08x",
|
||||
regs[8], regs[9], regs[10], regs[11],
|
||||
regs[12], regs[13], regs[14], regs[15]);
|
||||
LOG_ERROR(BinaryTranslator, "%01x %01x %01x %01x", flags[0], flags[1], flags[2], flags[3]);
|
||||
}
|
||||
|
||||
void BinaryTranslationLoader::VerifyCallback()
|
||||
{
|
||||
if (!g_enabled || !g_verify) return;
|
||||
|
||||
// Swap the PC to the old state before checking if it can run
|
||||
std::swap(g_regs_copy[15], g_state->Reg[15]);
|
||||
auto can_run = g_can_run_function();
|
||||
std::swap(g_regs_copy[15], g_state->Reg[15]);
|
||||
// Swap the PC and TFlag to the old state before checking if it can run
|
||||
std::swap(g_state_copy.regs[15], g_state->Reg[15]);
|
||||
std::swap(g_state_copy.t_flag, g_state->TFlag);
|
||||
auto can_run = CanRun(true);
|
||||
std::swap(g_state_copy.regs[15], g_state->Reg[15]);
|
||||
std::swap(g_state_copy.t_flag, g_state->TFlag);
|
||||
|
||||
if (g_have_saved_state && can_run)
|
||||
{
|
||||
// An opcode is finished, simulate it
|
||||
|
||||
// Copy the state before
|
||||
memcpy(g_regs_copy_before, g_regs_copy, sizeof(g_regs_copy));
|
||||
memcpy(g_flags_copy_before, &g_flags_copy, sizeof(g_flags_copy));
|
||||
g_state_copy_before = g_state_copy;
|
||||
|
||||
// Swap to the state before the opcode
|
||||
Swap(g_state->Reg, g_regs_copy, sizeof(g_regs_copy));
|
||||
Swap(&g_state->NFlag, g_flags_copy, sizeof(g_flags_copy));
|
||||
g_state_copy.SwapWith(*g_state);
|
||||
|
||||
// Run the opcode
|
||||
g_run_function();
|
||||
RunInternal();
|
||||
|
||||
// Test
|
||||
if (memcmp(g_state->Reg, g_regs_copy, sizeof(g_regs_copy)) || memcmp(&g_state->NFlag, g_flags_copy, sizeof(g_flags_copy)))
|
||||
auto current_as_saved_state = SavedState(*g_state);
|
||||
if (current_as_saved_state != g_state_copy)
|
||||
{
|
||||
LOG_ERROR(BinaryTranslator, "Verify failed");
|
||||
LOG_ERROR(BinaryTranslator, "Regs Before");
|
||||
ShowRegs(g_regs_copy_before, g_flags_copy_before);
|
||||
g_state_copy_before.Print();
|
||||
LOG_ERROR(BinaryTranslator, "Regs OK");
|
||||
ShowRegs(g_regs_copy, g_flags_copy);
|
||||
g_state_copy.Print();
|
||||
LOG_ERROR(BinaryTranslator, "Regs not OK");
|
||||
ShowRegs(g_state->Reg, &g_state->NFlag);
|
||||
current_as_saved_state.Print();
|
||||
|
||||
// Don't spam
|
||||
g_enabled = false;
|
||||
|
||||
// Make sure it has a valid state to continue to run
|
||||
Swap(g_state->Reg, g_regs_copy, sizeof(g_regs_copy));
|
||||
Swap(&g_state->NFlag, g_flags_copy, sizeof(g_flags_copy));
|
||||
g_state_copy.CopyTo(*g_state);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If this opcode is not translated or there is no saved state, just save the state and continue
|
||||
memcpy(g_regs_copy, g_state->Reg, sizeof(g_regs_copy));
|
||||
memcpy(g_flags_copy, &g_state->NFlag, sizeof(g_flags_copy));
|
||||
g_state_copy = *g_state;
|
||||
|
||||
g_have_saved_state = true;
|
||||
}
|
||||
|
@ -9,7 +9,12 @@ class BinaryTranslationLoader
|
||||
public:
|
||||
static void Load(FileUtil::IOFile& file);
|
||||
static void SetCpuState(ARMul_State *state);
|
||||
// Checks whether the cpu state can be run
|
||||
// If specific_address, checks the specific PC too
|
||||
static bool CanRun(bool specific_address);
|
||||
// Runs the state provided at SetCpuState.
|
||||
static void Run();
|
||||
// Link between Run and VerifyCallback
|
||||
static void RunInternal();
|
||||
static void VerifyCallback();
|
||||
};
|
Loading…
Reference in New Issue
Block a user