mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-14 18:58:36 +12:00
Some refactoring. Added support for some load/store instructions.
This commit is contained in:
parent
1be5222e66
commit
f5188cdb32
4 changed files with 1997 additions and 1310 deletions
|
@ -56,7 +56,7 @@ u64 rotr64(const u64 x, const u8 n) { return (x >> n) | (x << (64 - n)); }
|
||||||
|
|
||||||
class PPUInterpreter : public PPUOpcodes
|
class PPUInterpreter : public PPUOpcodes
|
||||||
{
|
{
|
||||||
friend class PPULLVMRecompiler;
|
friend class PPULLVMRecompilerWorker;
|
||||||
private:
|
private:
|
||||||
PPUThread& CPU;
|
PPUThread& CPU;
|
||||||
|
|
||||||
|
@ -2207,7 +2207,7 @@ private:
|
||||||
}
|
}
|
||||||
void ORIS(u32 ra, u32 rs, u32 uimm16)
|
void ORIS(u32 ra, u32 rs, u32 uimm16)
|
||||||
{
|
{
|
||||||
CPU.GPR[ra] = CPU.GPR[rs] | (uimm16 << 16);
|
CPU.GPR[ra] = CPU.GPR[rs] | ((u64)uimm16 << 16);
|
||||||
}
|
}
|
||||||
void XORI(u32 ra, u32 rs, u32 uimm16)
|
void XORI(u32 ra, u32 rs, u32 uimm16)
|
||||||
{
|
{
|
||||||
|
@ -2215,7 +2215,7 @@ private:
|
||||||
}
|
}
|
||||||
void XORIS(u32 ra, u32 rs, u32 uimm16)
|
void XORIS(u32 ra, u32 rs, u32 uimm16)
|
||||||
{
|
{
|
||||||
CPU.GPR[ra] = CPU.GPR[rs] ^ (uimm16 << 16);
|
CPU.GPR[ra] = CPU.GPR[rs] ^ ((u64)uimm16 << 16);
|
||||||
}
|
}
|
||||||
void ANDI_(u32 ra, u32 rs, u32 uimm16)
|
void ANDI_(u32 ra, u32 rs, u32 uimm16)
|
||||||
{
|
{
|
||||||
|
@ -2224,7 +2224,7 @@ private:
|
||||||
}
|
}
|
||||||
void ANDIS_(u32 ra, u32 rs, u32 uimm16)
|
void ANDIS_(u32 ra, u32 rs, u32 uimm16)
|
||||||
{
|
{
|
||||||
CPU.GPR[ra] = CPU.GPR[rs] & (uimm16 << 16);
|
CPU.GPR[ra] = CPU.GPR[rs] & ((u64)uimm16 << 16);
|
||||||
CPU.UpdateCR0<s64>(CPU.GPR[ra]);
|
CPU.UpdateCR0<s64>(CPU.GPR[ra]);
|
||||||
}
|
}
|
||||||
void RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, bool rc)
|
void RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, bool rc)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,21 +13,29 @@
|
||||||
|
|
||||||
struct PPURegState;
|
struct PPURegState;
|
||||||
|
|
||||||
/// LLVM based PPU emulator
|
/// PPU recompiler
|
||||||
class PPULLVMRecompiler : public CPUDecoder, protected PPUOpcodes {
|
class PPULLVMRecompilerWorker : protected PPUOpcodes {
|
||||||
public:
|
public:
|
||||||
PPULLVMRecompiler() = delete;
|
typedef void(*CompiledBlock)(PPUThread * ppu_state, u64 base_address, PPUInterpreter * interpreter);
|
||||||
PPULLVMRecompiler(PPUThread & ppu);
|
|
||||||
|
|
||||||
PPULLVMRecompiler(const PPULLVMRecompiler & other) = delete;
|
PPULLVMRecompilerWorker();
|
||||||
PPULLVMRecompiler(PPULLVMRecompiler && other) = delete;
|
|
||||||
|
|
||||||
virtual ~PPULLVMRecompiler();
|
PPULLVMRecompilerWorker(const PPULLVMRecompilerWorker & other) = delete;
|
||||||
|
PPULLVMRecompilerWorker(PPULLVMRecompilerWorker && other) = delete;
|
||||||
|
|
||||||
PPULLVMRecompiler & operator = (const PPULLVMRecompiler & other) = delete;
|
virtual ~PPULLVMRecompilerWorker();
|
||||||
PPULLVMRecompiler & operator = (PPULLVMRecompiler && other) = delete;
|
|
||||||
|
|
||||||
u8 DecodeMemory(const u64 address) override;
|
PPULLVMRecompilerWorker & operator = (const PPULLVMRecompilerWorker & other) = delete;
|
||||||
|
PPULLVMRecompilerWorker & operator = (PPULLVMRecompilerWorker && other) = delete;
|
||||||
|
|
||||||
|
/// Compile a block of code
|
||||||
|
void Compile(u64 address);
|
||||||
|
|
||||||
|
/// Get a function pointer to a compiled block
|
||||||
|
CompiledBlock GetCompiledBlock(u64 address);
|
||||||
|
|
||||||
|
/// Execute all tests
|
||||||
|
void RunAllTests(PPUThread * ppu_state, u64 base_address, PPUInterpreter * interpreter);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void NULL_OP() override;
|
void NULL_OP() override;
|
||||||
|
@ -431,20 +439,53 @@ protected:
|
||||||
void UNK(const u32 code, const u32 opcode, const u32 gcode) override;
|
void UNK(const u32 code, const u32 opcode, const u32 gcode) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// PPU processor context
|
|
||||||
PPUThread & m_ppu;
|
|
||||||
|
|
||||||
/// PPU instruction decoder
|
/// PPU instruction decoder
|
||||||
PPUDecoder m_decoder;
|
PPUDecoder m_decoder;
|
||||||
|
|
||||||
/// PPU Interpreter
|
/// Map from address to compiled block
|
||||||
PPUInterpreter m_interpreter;
|
std::map<u64, CompiledBlock> m_address_to_compiled_block_map;
|
||||||
|
|
||||||
|
/// LLVM context
|
||||||
|
llvm::LLVMContext * m_llvm_context;
|
||||||
|
|
||||||
|
/// LLVM IR builder
|
||||||
|
llvm::IRBuilder<> * m_ir_builder;
|
||||||
|
|
||||||
|
/// Module to which all generated code is output to
|
||||||
|
llvm::Module * m_module;
|
||||||
|
|
||||||
|
/// JIT execution engine
|
||||||
|
llvm::ExecutionEngine * m_execution_engine;
|
||||||
|
|
||||||
|
/// Disassembler
|
||||||
|
LLVMDisasmContextRef m_disassembler;
|
||||||
|
|
||||||
/// A flag used to detect branch instructions.
|
/// A flag used to detect branch instructions.
|
||||||
/// This is set to false at the start of compilation of a block.
|
/// This is set to false at the start of compilation of a block.
|
||||||
/// When a branch instruction is encountered, this is set to true by the decode function.
|
/// When a branch instruction is encountered, this is set to true by the decode function.
|
||||||
bool m_hit_branch_instruction;
|
bool m_hit_branch_instruction;
|
||||||
|
|
||||||
|
/// The function being compiled
|
||||||
|
llvm::Function * m_function;
|
||||||
|
|
||||||
|
/// Time spent compiling
|
||||||
|
std::chrono::duration<double> m_compilation_time;
|
||||||
|
|
||||||
|
/// Time spent idling
|
||||||
|
std::chrono::duration<double> m_idling_time;
|
||||||
|
|
||||||
|
/// Contains the number of times the interpreter fallback was used
|
||||||
|
std::map<std::string, u64> m_interpreter_fallback_stats;
|
||||||
|
|
||||||
|
/// Get PPU state pointer
|
||||||
|
llvm::Value * GetPPUState();
|
||||||
|
|
||||||
|
/// Get base address
|
||||||
|
llvm::Value * GetBaseAddress();
|
||||||
|
|
||||||
|
/// Get interpreter pointer
|
||||||
|
llvm::Value * GetInterpreter();
|
||||||
|
|
||||||
/// Get a bit
|
/// Get a bit
|
||||||
llvm::Value * GetBit(llvm::Value * val, u32 n);
|
llvm::Value * GetBit(llvm::Value * val, u32 n);
|
||||||
|
|
||||||
|
@ -473,7 +514,7 @@ private:
|
||||||
void SetPc(llvm::Value * val_i64);
|
void SetPc(llvm::Value * val_i64);
|
||||||
|
|
||||||
/// Load GPR
|
/// Load GPR
|
||||||
llvm::Value * GetGpr(u32 r);
|
llvm::Value * GetGpr(u32 r, u32 num_bits = 64);
|
||||||
|
|
||||||
/// Set GPR
|
/// Set GPR
|
||||||
void SetGpr(u32 r, llvm::Value * val_x64);
|
void SetGpr(u32 r, llvm::Value * val_x64);
|
||||||
|
@ -538,77 +579,57 @@ private:
|
||||||
/// Set VR to the specified value
|
/// Set VR to the specified value
|
||||||
void SetVr(u32 vr, llvm::Value * val_x128);
|
void SetVr(u32 vr, llvm::Value * val_x128);
|
||||||
|
|
||||||
|
/// Read from memory
|
||||||
|
llvm::Value * ReadMemory(llvm::Value * addr_i64, u32 bits, bool bswap = true);
|
||||||
|
|
||||||
|
/// Write to memory
|
||||||
|
void WriteMemory(llvm::Value * addr_i64, llvm::Value * val_ix, bool bswap = true);
|
||||||
|
|
||||||
|
/// Call an interpreter function
|
||||||
|
template<class Func, class... Args>
|
||||||
|
llvm::Value * InterpreterCall(const char * name, Func function, Args... args);
|
||||||
|
|
||||||
|
/// Convert a C++ type to an LLVM type
|
||||||
|
template<class T>
|
||||||
|
llvm::Type * CppToLlvmType();
|
||||||
|
|
||||||
|
/// Call a function
|
||||||
|
template<class Func, class... Args>
|
||||||
|
llvm::Value * Call(const char * name, Func function, Args... args);
|
||||||
|
|
||||||
/// Test an instruction against the interpreter
|
/// Test an instruction against the interpreter
|
||||||
template <class PPULLVMRecompilerFn, class PPUInterpreterFn, class... Args>
|
template <class PPULLVMRecompilerFn, class PPUInterpreterFn, class... Args>
|
||||||
void VerifyInstructionAgainstInterpreter(const char * name, PPULLVMRecompilerFn recomp_fn, PPUInterpreterFn interp_fn, PPURegState & input_reg_state, Args... args);
|
void VerifyInstructionAgainstInterpreter(const char * name, PPULLVMRecompilerFn recomp_fn, PPUInterpreterFn interp_fn, PPURegState & input_reg_state, Args... args);
|
||||||
|
|
||||||
/// Excute a test
|
/// Excute a test
|
||||||
void RunTest(const char * name, std::function<void()> test_case, std::function<void()> input, std::function<bool(std::string & msg)> check_result);
|
void RunTest(const char * name, std::function<void()> test_case, std::function<void()> input, std::function<bool(std::string & msg)> check_result);
|
||||||
|
};
|
||||||
|
|
||||||
/// Execute all tests
|
/// A dynarec PPU emulator that uses LLVM as the backend
|
||||||
void RunAllTests();
|
class PPULLVMRecompiler : public CPUDecoder {
|
||||||
|
public:
|
||||||
|
PPULLVMRecompiler(PPUThread & ppu);
|
||||||
|
PPULLVMRecompiler() = delete;
|
||||||
|
|
||||||
/// Call a member function
|
PPULLVMRecompiler(const PPULLVMRecompilerWorker & other) = delete;
|
||||||
template<class F, class C, class... Args>
|
PPULLVMRecompiler(PPULLVMRecompilerWorker && other) = delete;
|
||||||
void ThisCall(const char * name, F function, C * this_ptr, Args... args);
|
|
||||||
|
|
||||||
/// Number of instances
|
virtual ~PPULLVMRecompiler();
|
||||||
static u32 s_num_instances;
|
|
||||||
|
|
||||||
/// Map from address to compiled code
|
PPULLVMRecompiler & operator = (const PPULLVMRecompiler & other) = delete;
|
||||||
static std::map<u64, void *> s_address_to_code_map;
|
PPULLVMRecompiler & operator = (PPULLVMRecompiler && other) = delete;
|
||||||
|
|
||||||
/// Mutex for s_address_to_code_map
|
u8 DecodeMemory(const u64 address);
|
||||||
static std::mutex s_address_to_code_map_mutex;
|
|
||||||
|
|
||||||
/// LLVM mutex
|
private:
|
||||||
static std::mutex s_llvm_mutex;
|
/// PPU processor context
|
||||||
|
PPUThread & m_ppu;
|
||||||
|
|
||||||
/// LLVM context
|
/// PPU Interpreter
|
||||||
static llvm::LLVMContext * s_llvm_context;
|
PPUInterpreter m_interpreter;
|
||||||
|
|
||||||
/// LLVM IR builder
|
/// The actual compiler
|
||||||
static llvm::IRBuilder<> * s_ir_builder;
|
PPULLVMRecompilerWorker m_worker;
|
||||||
|
|
||||||
/// Module to which all generated code is output to
|
|
||||||
static llvm::Module * s_module;
|
|
||||||
|
|
||||||
/// Function in m_module that corresponds to ExecuteThisCall
|
|
||||||
static llvm::Function * s_execute_this_call_fn;
|
|
||||||
|
|
||||||
/// A metadata node for s_execute_this_call_fn that records the function name and args
|
|
||||||
static llvm::MDNode * s_execute_this_call_fn_name_and_args_md_node;
|
|
||||||
|
|
||||||
/// JIT execution engine
|
|
||||||
static llvm::ExecutionEngine * s_execution_engine;
|
|
||||||
|
|
||||||
/// Disassembler
|
|
||||||
static LLVMDisasmContextRef s_disassembler;
|
|
||||||
|
|
||||||
/// The pointer to the PPU state
|
|
||||||
static llvm::Value * s_state_ptr;
|
|
||||||
|
|
||||||
/// Time spent compiling
|
|
||||||
static std::chrono::duration<double> s_compilation_time;
|
|
||||||
|
|
||||||
/// Time spent executing
|
|
||||||
static std::chrono::duration<double> s_execution_time;
|
|
||||||
|
|
||||||
/// Contains the number of times the interpreter was invoked for an instruction
|
|
||||||
static std::map<std::string, u64> s_interpreter_invocation_stats;
|
|
||||||
|
|
||||||
/// List of std::function pointers created by ThisCall()
|
|
||||||
static std::list<std::function<void()> *> s_this_call_ptrs_list;
|
|
||||||
|
|
||||||
/// Execute a this call
|
|
||||||
static void ExecuteThisCall(std::function<void()> * function);
|
|
||||||
|
|
||||||
/// Convert args to a string
|
|
||||||
template<class T, class... Args>
|
|
||||||
static std::string ArgsToString(T arg1, Args... args);
|
|
||||||
|
|
||||||
/// Terminator for ArgsToString(T arg1, Args... args);
|
|
||||||
static std::string ArgsToString();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PPU_LLVM_RECOMPILER_H
|
#endif // PPU_LLVM_RECOMPILER_H
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
#define VERIFY_INSTRUCTION_AGAINST_INTERPRETER(fn, tc, input, ...) \
|
#define VERIFY_INSTRUCTION_AGAINST_INTERPRETER(fn, tc, input, ...) \
|
||||||
VerifyInstructionAgainstInterpreter(fmt::Format("%s.%d", #fn, tc).c_str(), &PPULLVMRecompiler::fn, &PPUInterpreter::fn, input, __VA_ARGS__)
|
VerifyInstructionAgainstInterpreter(fmt::Format("%s.%d", #fn, tc).c_str(), &PPULLVMRecompilerWorker::fn, &PPUInterpreter::fn, input, __VA_ARGS__)
|
||||||
|
|
||||||
#define VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(fn, s, n, ...) { \
|
#define VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(fn, s, n, ...) { \
|
||||||
PPURegState input; \
|
PPURegState input; \
|
||||||
|
@ -155,22 +155,26 @@ struct PPURegState {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static PPUThread * s_ppu_state = nullptr;
|
||||||
|
static u64 s_base_address = 0;
|
||||||
|
static PPUInterpreter * s_interpreter = nullptr;
|
||||||
|
|
||||||
template <class PPULLVMRecompilerFn, class PPUInterpreterFn, class... Args>
|
template <class PPULLVMRecompilerFn, class PPUInterpreterFn, class... Args>
|
||||||
void PPULLVMRecompiler::VerifyInstructionAgainstInterpreter(const char * name, PPULLVMRecompilerFn recomp_fn, PPUInterpreterFn interp_fn, PPURegState & input_reg_state, Args... args) {
|
void PPULLVMRecompilerWorker::VerifyInstructionAgainstInterpreter(const char * name, PPULLVMRecompilerFn recomp_fn, PPUInterpreterFn interp_fn, PPURegState & input_reg_state, Args... args) {
|
||||||
auto test_case = [&]() {
|
auto test_case = [&]() {
|
||||||
(this->*recomp_fn)(args...);
|
(this->*recomp_fn)(args...);
|
||||||
};
|
};
|
||||||
auto input = [&]() {
|
auto input = [&]() {
|
||||||
input_reg_state.Store(m_ppu);
|
input_reg_state.Store(*s_ppu_state);
|
||||||
};
|
};
|
||||||
auto check_result = [&](std::string & msg) {
|
auto check_result = [&](std::string & msg) {
|
||||||
PPURegState recomp_output_reg_state;
|
PPURegState recomp_output_reg_state;
|
||||||
PPURegState interp_output_reg_state;
|
PPURegState interp_output_reg_state;
|
||||||
|
|
||||||
recomp_output_reg_state.Load(m_ppu);
|
recomp_output_reg_state.Load(*s_ppu_state);
|
||||||
input_reg_state.Store(m_ppu);
|
input_reg_state.Store(*s_ppu_state);
|
||||||
(&m_interpreter->*interp_fn)(args...);
|
(s_interpreter->*interp_fn)(args...);
|
||||||
interp_output_reg_state.Load(m_ppu);
|
interp_output_reg_state.Load(*s_ppu_state);
|
||||||
|
|
||||||
if (interp_output_reg_state.ToString() != recomp_output_reg_state.ToString()) {
|
if (interp_output_reg_state.ToString() != recomp_output_reg_state.ToString()) {
|
||||||
msg = std::string("Input register states:\n") + input_reg_state.ToString() +
|
msg = std::string("Input register states:\n") + input_reg_state.ToString() +
|
||||||
|
@ -184,36 +188,48 @@ void PPULLVMRecompiler::VerifyInstructionAgainstInterpreter(const char * name, P
|
||||||
RunTest(name, test_case, input, check_result);
|
RunTest(name, test_case, input, check_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPULLVMRecompiler::RunTest(const char * name, std::function<void()> test_case, std::function<void()> input, std::function<bool(std::string & msg)> check_result) {
|
void PPULLVMRecompilerWorker::RunTest(const char * name, std::function<void()> test_case, std::function<void()> input, std::function<bool(std::string & msg)> check_result) {
|
||||||
// Create the unit test function
|
// Create the unit test function
|
||||||
auto function = cast<Function>(s_module->getOrInsertFunction(name, s_ir_builder->getVoidTy(), s_ir_builder->getInt8Ty()->getPointerTo(), nullptr));
|
m_function = (Function *)m_module->getOrInsertFunction(name, m_ir_builder->getVoidTy(),
|
||||||
s_state_ptr = function->arg_begin();
|
m_ir_builder->getInt8PtrTy() /*ppu_state*/,
|
||||||
s_state_ptr->setName("state");
|
m_ir_builder->getInt64Ty() /*base_addres*/,
|
||||||
|
m_ir_builder->getInt8PtrTy() /*interpreter*/, nullptr);
|
||||||
|
m_function->setCallingConv(CallingConv::X86_64_Win64);
|
||||||
|
auto arg_i = m_function->arg_begin();
|
||||||
|
arg_i->setName("ppu_state");
|
||||||
|
(++arg_i)->setName("base_address");
|
||||||
|
(++arg_i)->setName("interpreter");
|
||||||
|
|
||||||
auto block = BasicBlock::Create(*s_llvm_context, "start", function);
|
auto block = BasicBlock::Create(*m_llvm_context, "start", m_function);
|
||||||
s_ir_builder->SetInsertPoint(block);
|
m_ir_builder->SetInsertPoint(block);
|
||||||
|
|
||||||
test_case();
|
test_case();
|
||||||
|
|
||||||
s_ir_builder->CreateRetVoid();
|
m_ir_builder->CreateRetVoid();
|
||||||
verifyFunction(*function);
|
|
||||||
|
|
||||||
// Print the IR
|
// Print the IR
|
||||||
std::string ir;
|
std::string ir;
|
||||||
raw_string_ostream ir_ostream(ir);
|
raw_string_ostream ir_ostream(ir);
|
||||||
function->print(ir_ostream);
|
m_function->print(ir_ostream);
|
||||||
LOG_NOTICE(PPU, "[UT %s] LLVM IR:%s", name, ir.c_str());
|
LOG_NOTICE(PPU, "[UT %s] LLVM IR:%s", name, ir.c_str());
|
||||||
|
|
||||||
|
std::string verify;
|
||||||
|
raw_string_ostream verify_ostream(verify);
|
||||||
|
if (verifyFunction(*m_function, &verify_ostream)) {
|
||||||
|
LOG_ERROR(PPU, "[UT %s] Verification Failed:%s", name, verify.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Generate the function
|
// Generate the function
|
||||||
MachineCodeInfo mci;
|
MachineCodeInfo mci;
|
||||||
s_execution_engine->runJITOnFunction(function, &mci);
|
m_execution_engine->runJITOnFunction(m_function, &mci);
|
||||||
|
|
||||||
// Disassember the generated function
|
// Disassember the generated function
|
||||||
LOG_NOTICE(PPU, "[UT %s] Disassembly:", name);
|
LOG_NOTICE(PPU, "[UT %s] Disassembly:", name);
|
||||||
for (uint64_t pc = 0; pc < mci.size();) {
|
for (uint64_t pc = 0; pc < mci.size();) {
|
||||||
char str[1024];
|
char str[1024];
|
||||||
|
|
||||||
auto size = LLVMDisasmInstruction(s_disassembler, (uint8_t *)mci.address() + pc, mci.size() - pc, (uint64_t)((uint8_t *)mci.address() + pc), str, sizeof(str));
|
auto size = LLVMDisasmInstruction(m_disassembler, (uint8_t *)mci.address() + pc, mci.size() - pc, (uint64_t)((uint8_t *)mci.address() + pc), str, sizeof(str));
|
||||||
LOG_NOTICE(PPU, "[UT %s] %p: %s.", name, (uint8_t *)mci.address() + pc, str);
|
LOG_NOTICE(PPU, "[UT %s] %p: %s.", name, (uint8_t *)mci.address() + pc, str);
|
||||||
pc += size;
|
pc += size;
|
||||||
}
|
}
|
||||||
|
@ -221,8 +237,12 @@ void PPULLVMRecompiler::RunTest(const char * name, std::function<void()> test_ca
|
||||||
// Run the test
|
// Run the test
|
||||||
input();
|
input();
|
||||||
std::vector<GenericValue> args;
|
std::vector<GenericValue> args;
|
||||||
args.push_back(GenericValue(&m_ppu));
|
args.push_back(GenericValue(s_ppu_state));
|
||||||
s_execution_engine->runFunction(function, args);
|
GenericValue base_address;
|
||||||
|
base_address.IntVal = APInt(64, s_base_address);
|
||||||
|
args.push_back(base_address);
|
||||||
|
args.push_back(GenericValue(s_interpreter));
|
||||||
|
m_execution_engine->runFunction(m_function, args);
|
||||||
|
|
||||||
// Verify results
|
// Verify results
|
||||||
std::string msg;
|
std::string msg;
|
||||||
|
@ -233,13 +253,16 @@ void PPULLVMRecompiler::RunTest(const char * name, std::function<void()> test_ca
|
||||||
LOG_ERROR(PPU, "[UT %s] Test failed. %s", name, msg.c_str());
|
LOG_ERROR(PPU, "[UT %s] Test failed. %s", name, msg.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
s_execution_engine->freeMachineCodeForFunction(function);
|
m_execution_engine->freeMachineCodeForFunction(m_function);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPULLVMRecompiler::RunAllTests() {
|
void PPULLVMRecompilerWorker::RunAllTests(PPUThread * ppu_state, u64 base_address, PPUInterpreter * interpreter) {
|
||||||
std::function<void()> test_case;
|
s_ppu_state = ppu_state;
|
||||||
std::function<void()> input;
|
s_base_address = base_address;
|
||||||
std::function<bool(std::string & msg)> check_result;
|
s_interpreter = interpreter;
|
||||||
|
|
||||||
|
PPURegState initial_state;
|
||||||
|
initial_state.Load(*ppu_state);
|
||||||
|
|
||||||
LOG_NOTICE(PPU, "Running Unit Tests");
|
LOG_NOTICE(PPU, "Running Unit Tests");
|
||||||
|
|
||||||
|
@ -320,4 +343,138 @@ void PPULLVMRecompiler::RunAllTests() {
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VCMPGTUW, 5, 5, 0, 1, 1);
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VCMPGTUW, 5, 5, 0, 1, 1);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VCMPGTUW_, 0, 5, 0, 1, 2);
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VCMPGTUW_, 0, 5, 0, 1, 2);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VCMPGTUW_, 5, 5, 0, 1, 1);
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VCMPGTUW_, 5, 5, 0, 1, 1);
|
||||||
|
// TODO: Rest of the vector instructions
|
||||||
|
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(MULLI, 0, 5, 1, 2, 12345);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(SUBFIC, 0, 5, 1, 2, 12345);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(CMPLI, 0, 5, 1, 0, 7, 12345);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(CMPLI, 5, 5, 1, 1, 7, 12345);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(CMPI, 0, 5, 5, 0, 7, -12345);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(CMPI, 5, 5, 5, 1, 7, -12345);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(ADDIC, 0, 5, 1, 2, 12345);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(ADDIC_, 0, 5, 1, 2, 12345);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(ADDI, 0, 5, 1, 2, 12345);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(ADDI, 5, 5, 0, 2, 12345);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(ADDIS, 0, 5, 1, 2, -12345);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(ADDIS, 5, 5, 0, 2, -12345);
|
||||||
|
// TODO: BC
|
||||||
|
// TODO: SC
|
||||||
|
// TODO: B
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(MCRF, 0, 5, 0, 7);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(MCRF, 5, 5, 6, 2);
|
||||||
|
// TODO: BCLR
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(CRNOR, 0, 5, 0, 7, 3);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(CRANDC, 0, 5, 5, 6, 7);
|
||||||
|
// TODO: ISYNC
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(CRXOR, 0, 5, 7, 7, 7);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(CRNAND, 0, 5, 3, 4, 5);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(CRAND, 0, 5, 1, 2, 3);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(CREQV, 0, 5, 2, 1, 0);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(CRORC, 0, 5, 3, 4, 5);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(CROR, 0, 5, 6, 7, 0);
|
||||||
|
// TODO: BCCTR
|
||||||
|
// TODO: RLWIMI
|
||||||
|
// TODO: RLWINM
|
||||||
|
// TODO: RLWNM
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(ORI, 0, 5, 25, 29, 12345);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(ORIS, 0, 5, 7, 31, -12345);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(XORI, 0, 5, 0, 19, 12345);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(XORIS, 0, 5, 3, 14, -12345);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(ANDI_, 0, 5, 16, 7, 12345);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(ANDIS_, 0, 5, 23, 21, -12345);
|
||||||
|
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(ADD, 0, 5, 7, 8, 9, 0, 0);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(ADD, 5, 5, 21, 22, 23, 0, 1);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(AND, 0, 5, 7, 8, 9, 0);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(AND, 5, 5, 21, 22, 23, 1);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(OR, 0, 5, 7, 8, 9, 0);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(OR, 5, 5, 21, 22, 23, 1);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(XOR, 0, 5, 7, 8, 9, 0);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(XOR, 5, 5, 21, 22, 23, 1);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(CMP, 0, 5, 3, 0, 9, 31);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(CMP, 5, 5, 6, 1, 23, 14);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(CMPL, 0, 5, 3, 0, 9, 31);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(CMPL, 5, 5, 6, 1, 23, 14);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(EXTSB, 0, 5, 3, 5, 0);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(EXTSB, 5, 5, 3, 5, 1);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(EXTSH, 0, 5, 6, 9, 0);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(EXTSH, 5, 5, 6, 9, 1);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(EXTSW, 0, 5, 25, 29, 0);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(EXTSW, 5, 5, 25, 29, 1);
|
||||||
|
|
||||||
|
PPURegState input;
|
||||||
|
input.SetRandom();
|
||||||
|
input.GPR[14] = 10;
|
||||||
|
input.GPR[23] = 0x10000;
|
||||||
|
for (int i = 0; i < 1000; i++) {
|
||||||
|
((u8*)base_address)[i + 0x10000] = (u8)i;
|
||||||
|
}
|
||||||
|
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LBZ, 0, input, 5, 0, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LBZ, 1, input, 5, 14, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LBZU, 0, input, 5, 14, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LBZX, 0, input, 5, 0, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LBZX, 1, input, 5, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LBZUX, 0, input, 5, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHZ, 0, input, 5, 0, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHZ, 1, input, 5, 14, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHZU, 0, input, 5, 14, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHZX, 0, input, 5, 0, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHZX, 1, input, 5, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHZUX, 0, input, 5, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHA, 0, input, 5, 0, 0x100F0);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHA, 1, input, 5, 14, 0x100F0);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHAU, 0, input, 5, 14, 0x100F0);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHAX, 0, input, 5, 0, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHAX, 1, input, 5, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHAUX, 0, input, 5, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHBRX, 0, input, 5, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWZ, 0, input, 5, 0, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWZ, 1, input, 5, 14, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWZU, 0, input, 5, 14, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWZX, 0, input, 5, 0, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWZX, 1, input, 5, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWZUX, 0, input, 5, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWA, 0, input, 5, 0, 0x100F0);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWA, 1, input, 5, 14, 0x100F0);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWAX, 0, input, 5, 0, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWAX, 1, input, 5, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWAUX, 0, input, 5, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWBRX, 0, input, 5, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LD, 0, input, 5, 0, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LD, 1, input, 5, 14, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LDU, 0, input, 5, 14, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LDX, 0, input, 5, 0, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LDX, 1, input, 5, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LDUX, 0, input, 5, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LDBRX, 0, input, 5, 14, 23);
|
||||||
|
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STB, 0, input, 3, 0, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STB, 1, input, 3, 14, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STBU, 0, input, 3, 14, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STBX, 0, input, 3, 0, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STBX, 1, input, 3, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STBUX, 0, input, 3, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STH, 0, input, 3, 0, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STH, 1, input, 3, 14, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STHU, 0, input, 3, 14, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STHX, 0, input, 3, 0, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STHX, 1, input, 3, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STHUX, 0, input, 3, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STHBRX, 0, input, 3, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STW, 0, input, 3, 0, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STW, 1, input, 3, 14, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWU, 0, input, 3, 14, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWX, 0, input, 3, 0, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWX, 1, input, 3, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWUX, 0, input, 3, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWBRX, 0, input, 3, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STD, 0, input, 3, 0, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STD, 1, input, 3, 14, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDU, 0, input, 3, 14, 0x10000);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDX, 0, input, 3, 0, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDX, 1, input, 3, 14, 23);
|
||||||
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDUX, 0, input, 3, 14, 23);
|
||||||
|
|
||||||
|
initial_state.Store(*ppu_state);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue