mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 18:53:28 +01:00
Some refactoring. Added support for some load/store instructions.
This commit is contained in:
parent
1be5222e66
commit
f5188cdb32
@ -56,7 +56,7 @@ u64 rotr64(const u64 x, const u8 n) { return (x >> n) | (x << (64 - n)); }
|
||||
|
||||
class PPUInterpreter : public PPUOpcodes
|
||||
{
|
||||
friend class PPULLVMRecompiler;
|
||||
friend class PPULLVMRecompilerWorker;
|
||||
private:
|
||||
PPUThread& CPU;
|
||||
|
||||
@ -2207,7 +2207,7 @@ private:
|
||||
}
|
||||
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)
|
||||
{
|
||||
@ -2215,7 +2215,7 @@ private:
|
||||
}
|
||||
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)
|
||||
{
|
||||
@ -2224,7 +2224,7 @@ private:
|
||||
}
|
||||
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]);
|
||||
}
|
||||
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;
|
||||
|
||||
/// LLVM based PPU emulator
|
||||
class PPULLVMRecompiler : public CPUDecoder, protected PPUOpcodes {
|
||||
/// PPU recompiler
|
||||
class PPULLVMRecompilerWorker : protected PPUOpcodes {
|
||||
public:
|
||||
PPULLVMRecompiler() = delete;
|
||||
PPULLVMRecompiler(PPUThread & ppu);
|
||||
typedef void(*CompiledBlock)(PPUThread * ppu_state, u64 base_address, PPUInterpreter * interpreter);
|
||||
|
||||
PPULLVMRecompiler(const PPULLVMRecompiler & other) = delete;
|
||||
PPULLVMRecompiler(PPULLVMRecompiler && other) = delete;
|
||||
PPULLVMRecompilerWorker();
|
||||
|
||||
virtual ~PPULLVMRecompiler();
|
||||
PPULLVMRecompilerWorker(const PPULLVMRecompilerWorker & other) = delete;
|
||||
PPULLVMRecompilerWorker(PPULLVMRecompilerWorker && other) = delete;
|
||||
|
||||
PPULLVMRecompiler & operator = (const PPULLVMRecompiler & other) = delete;
|
||||
PPULLVMRecompiler & operator = (PPULLVMRecompiler && other) = delete;
|
||||
virtual ~PPULLVMRecompilerWorker();
|
||||
|
||||
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:
|
||||
void NULL_OP() override;
|
||||
@ -431,20 +439,53 @@ protected:
|
||||
void UNK(const u32 code, const u32 opcode, const u32 gcode) override;
|
||||
|
||||
private:
|
||||
/// PPU processor context
|
||||
PPUThread & m_ppu;
|
||||
|
||||
/// PPU instruction decoder
|
||||
PPUDecoder m_decoder;
|
||||
|
||||
/// PPU Interpreter
|
||||
PPUInterpreter m_interpreter;
|
||||
/// Map from address to compiled block
|
||||
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.
|
||||
/// 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.
|
||||
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
|
||||
llvm::Value * GetBit(llvm::Value * val, u32 n);
|
||||
|
||||
@ -473,7 +514,7 @@ private:
|
||||
void SetPc(llvm::Value * val_i64);
|
||||
|
||||
/// Load GPR
|
||||
llvm::Value * GetGpr(u32 r);
|
||||
llvm::Value * GetGpr(u32 r, u32 num_bits = 64);
|
||||
|
||||
/// Set GPR
|
||||
void SetGpr(u32 r, llvm::Value * val_x64);
|
||||
@ -538,77 +579,57 @@ private:
|
||||
/// Set VR to the specified value
|
||||
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
|
||||
template <class PPULLVMRecompilerFn, class PPUInterpreterFn, class... Args>
|
||||
void VerifyInstructionAgainstInterpreter(const char * name, PPULLVMRecompilerFn recomp_fn, PPUInterpreterFn interp_fn, PPURegState & input_reg_state, Args... args);
|
||||
|
||||
/// 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);
|
||||
};
|
||||
|
||||
/// Execute all tests
|
||||
void RunAllTests();
|
||||
/// A dynarec PPU emulator that uses LLVM as the backend
|
||||
class PPULLVMRecompiler : public CPUDecoder {
|
||||
public:
|
||||
PPULLVMRecompiler(PPUThread & ppu);
|
||||
PPULLVMRecompiler() = delete;
|
||||
|
||||
/// Call a member function
|
||||
template<class F, class C, class... Args>
|
||||
void ThisCall(const char * name, F function, C * this_ptr, Args... args);
|
||||
PPULLVMRecompiler(const PPULLVMRecompilerWorker & other) = delete;
|
||||
PPULLVMRecompiler(PPULLVMRecompilerWorker && other) = delete;
|
||||
|
||||
/// Number of instances
|
||||
static u32 s_num_instances;
|
||||
virtual ~PPULLVMRecompiler();
|
||||
|
||||
/// Map from address to compiled code
|
||||
static std::map<u64, void *> s_address_to_code_map;
|
||||
PPULLVMRecompiler & operator = (const PPULLVMRecompiler & other) = delete;
|
||||
PPULLVMRecompiler & operator = (PPULLVMRecompiler && other) = delete;
|
||||
|
||||
/// Mutex for s_address_to_code_map
|
||||
static std::mutex s_address_to_code_map_mutex;
|
||||
u8 DecodeMemory(const u64 address);
|
||||
|
||||
/// LLVM mutex
|
||||
static std::mutex s_llvm_mutex;
|
||||
private:
|
||||
/// PPU processor context
|
||||
PPUThread & m_ppu;
|
||||
|
||||
/// LLVM context
|
||||
static llvm::LLVMContext * s_llvm_context;
|
||||
/// PPU Interpreter
|
||||
PPUInterpreter m_interpreter;
|
||||
|
||||
/// LLVM IR builder
|
||||
static llvm::IRBuilder<> * s_ir_builder;
|
||||
|
||||
/// 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();
|
||||
/// The actual compiler
|
||||
PPULLVMRecompilerWorker m_worker;
|
||||
};
|
||||
|
||||
#endif // PPU_LLVM_RECOMPILER_H
|
||||
|
@ -9,7 +9,7 @@
|
||||
using namespace llvm;
|
||||
|
||||
#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, ...) { \
|
||||
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>
|
||||
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 = [&]() {
|
||||
(this->*recomp_fn)(args...);
|
||||
};
|
||||
auto input = [&]() {
|
||||
input_reg_state.Store(m_ppu);
|
||||
input_reg_state.Store(*s_ppu_state);
|
||||
};
|
||||
auto check_result = [&](std::string & msg) {
|
||||
PPURegState recomp_output_reg_state;
|
||||
PPURegState interp_output_reg_state;
|
||||
|
||||
recomp_output_reg_state.Load(m_ppu);
|
||||
input_reg_state.Store(m_ppu);
|
||||
(&m_interpreter->*interp_fn)(args...);
|
||||
interp_output_reg_state.Load(m_ppu);
|
||||
recomp_output_reg_state.Load(*s_ppu_state);
|
||||
input_reg_state.Store(*s_ppu_state);
|
||||
(s_interpreter->*interp_fn)(args...);
|
||||
interp_output_reg_state.Load(*s_ppu_state);
|
||||
|
||||
if (interp_output_reg_state.ToString() != recomp_output_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);
|
||||
}
|
||||
|
||||
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
|
||||
auto function = cast<Function>(s_module->getOrInsertFunction(name, s_ir_builder->getVoidTy(), s_ir_builder->getInt8Ty()->getPointerTo(), nullptr));
|
||||
s_state_ptr = function->arg_begin();
|
||||
s_state_ptr->setName("state");
|
||||
m_function = (Function *)m_module->getOrInsertFunction(name, m_ir_builder->getVoidTy(),
|
||||
m_ir_builder->getInt8PtrTy() /*ppu_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);
|
||||
s_ir_builder->SetInsertPoint(block);
|
||||
auto block = BasicBlock::Create(*m_llvm_context, "start", m_function);
|
||||
m_ir_builder->SetInsertPoint(block);
|
||||
|
||||
test_case();
|
||||
|
||||
s_ir_builder->CreateRetVoid();
|
||||
verifyFunction(*function);
|
||||
m_ir_builder->CreateRetVoid();
|
||||
|
||||
// Print the IR
|
||||
std::string 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());
|
||||
|
||||
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
|
||||
MachineCodeInfo mci;
|
||||
s_execution_engine->runJITOnFunction(function, &mci);
|
||||
m_execution_engine->runJITOnFunction(m_function, &mci);
|
||||
|
||||
// Disassember the generated function
|
||||
LOG_NOTICE(PPU, "[UT %s] Disassembly:", name);
|
||||
for (uint64_t pc = 0; pc < mci.size();) {
|
||||
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);
|
||||
pc += size;
|
||||
}
|
||||
@ -221,8 +237,12 @@ void PPULLVMRecompiler::RunTest(const char * name, std::function<void()> test_ca
|
||||
// Run the test
|
||||
input();
|
||||
std::vector<GenericValue> args;
|
||||
args.push_back(GenericValue(&m_ppu));
|
||||
s_execution_engine->runFunction(function, args);
|
||||
args.push_back(GenericValue(s_ppu_state));
|
||||
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
|
||||
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());
|
||||
}
|
||||
|
||||
s_execution_engine->freeMachineCodeForFunction(function);
|
||||
m_execution_engine->freeMachineCodeForFunction(m_function);
|
||||
}
|
||||
|
||||
void PPULLVMRecompiler::RunAllTests() {
|
||||
std::function<void()> test_case;
|
||||
std::function<void()> input;
|
||||
std::function<bool(std::string & msg)> check_result;
|
||||
void PPULLVMRecompilerWorker::RunAllTests(PPUThread * ppu_state, u64 base_address, PPUInterpreter * interpreter) {
|
||||
s_ppu_state = ppu_state;
|
||||
s_base_address = base_address;
|
||||
s_interpreter = interpreter;
|
||||
|
||||
PPURegState initial_state;
|
||||
initial_state.Load(*ppu_state);
|
||||
|
||||
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_, 0, 5, 0, 1, 2);
|
||||
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…
Reference in New Issue
Block a user