1
0
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:
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
{
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

View File

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

View File

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