Some refactoring. Added support for some load/store instructions.

This commit is contained in:
S Gopal Rajagopal 2014-09-15 20:04:09 +05:30
parent 1be5222e66
commit f5188cdb32
4 changed files with 1997 additions and 1310 deletions

View file

@ -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

View file

@ -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

View file

@ -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);
} }