A32: Implement load stores (immediate)
This commit is contained in:
parent
2aadeec291
commit
25411da838
14 changed files with 411 additions and 122 deletions
|
@ -65,6 +65,8 @@ add_library(dynarmic
|
||||||
frontend/A64/translate/impl/exception_generating.cpp
|
frontend/A64/translate/impl/exception_generating.cpp
|
||||||
frontend/A64/translate/impl/impl.cpp
|
frontend/A64/translate/impl/impl.cpp
|
||||||
frontend/A64/translate/impl/impl.h
|
frontend/A64/translate/impl/impl.h
|
||||||
|
frontend/A64/translate/impl/load_store_load_literal.cpp
|
||||||
|
frontend/A64/translate/impl/load_store_register_immediate.cpp
|
||||||
frontend/A64/translate/translate.cpp
|
frontend/A64/translate/translate.cpp
|
||||||
frontend/A64/translate/translate.h
|
frontend/A64/translate/translate.h
|
||||||
frontend/A64/types.cpp
|
frontend/A64/types.cpp
|
||||||
|
|
|
@ -228,6 +228,70 @@ void A64EmitX64::EmitA64CallSupervisor(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void A64EmitX64::EmitA64ReadMemory8(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
Devirtualize<&A64::UserCallbacks::MemoryRead8>(conf.callbacks).EmitCall(code, [&](Xbyak::Reg64 vaddr) {
|
||||||
|
ASSERT(vaddr == code->ABI_PARAM2);
|
||||||
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
ctx.reg_alloc.HostCall(inst, {}, args[0]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void A64EmitX64::EmitA64ReadMemory16(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
Devirtualize<&A64::UserCallbacks::MemoryRead16>(conf.callbacks).EmitCall(code, [&](Xbyak::Reg64 vaddr) {
|
||||||
|
ASSERT(vaddr == code->ABI_PARAM2);
|
||||||
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
ctx.reg_alloc.HostCall(inst, {}, args[0]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void A64EmitX64::EmitA64ReadMemory32(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
Devirtualize<&A64::UserCallbacks::MemoryRead32>(conf.callbacks).EmitCall(code, [&](Xbyak::Reg64 vaddr) {
|
||||||
|
ASSERT(vaddr == code->ABI_PARAM2);
|
||||||
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
ctx.reg_alloc.HostCall(inst, {}, args[0]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void A64EmitX64::EmitA64ReadMemory64(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
Devirtualize<&A64::UserCallbacks::MemoryRead64>(conf.callbacks).EmitCall(code, [&](Xbyak::Reg64 vaddr) {
|
||||||
|
ASSERT(vaddr == code->ABI_PARAM2);
|
||||||
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
ctx.reg_alloc.HostCall(inst, {}, args[0]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void A64EmitX64::EmitA64WriteMemory8(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
Devirtualize<&A64::UserCallbacks::MemoryWrite8>(conf.callbacks).EmitCall(code, [&](Xbyak::Reg64 vaddr, Xbyak::Reg64 value) {
|
||||||
|
ASSERT(vaddr == code->ABI_PARAM2 && value == code->ABI_PARAM3);
|
||||||
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void A64EmitX64::EmitA64WriteMemory16(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
Devirtualize<&A64::UserCallbacks::MemoryWrite16>(conf.callbacks).EmitCall(code, [&](Xbyak::Reg64 vaddr, Xbyak::Reg64 value) {
|
||||||
|
ASSERT(vaddr == code->ABI_PARAM2 && value == code->ABI_PARAM3);
|
||||||
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void A64EmitX64::EmitA64WriteMemory32(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
Devirtualize<&A64::UserCallbacks::MemoryWrite32>(conf.callbacks).EmitCall(code, [&](Xbyak::Reg64 vaddr, Xbyak::Reg64 value) {
|
||||||
|
ASSERT(vaddr == code->ABI_PARAM2 && value == code->ABI_PARAM3);
|
||||||
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void A64EmitX64::EmitA64WriteMemory64(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
Devirtualize<&A64::UserCallbacks::MemoryWrite64>(conf.callbacks).EmitCall(code, [&](Xbyak::Reg64 vaddr, Xbyak::Reg64 value) {
|
||||||
|
ASSERT(vaddr == code->ABI_PARAM2 && value == code->ABI_PARAM3);
|
||||||
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void A64EmitX64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor) {
|
void A64EmitX64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor) {
|
||||||
code->SwitchMxcsrOnExit();
|
code->SwitchMxcsrOnExit();
|
||||||
Devirtualize<&A64::UserCallbacks::InterpreterFallback>(conf.callbacks).EmitCall(code, [&](Xbyak::Reg64 param1, Xbyak::Reg64 param2) {
|
Devirtualize<&A64::UserCallbacks::InterpreterFallback>(conf.callbacks).EmitCall(code, [&](Xbyak::Reg64 param1, Xbyak::Reg64 param2) {
|
||||||
|
|
|
@ -31,26 +31,26 @@ void SimpleCallback::EmitCall(BlockOfCode* code, std::function<void(Xbyak::Reg64
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArgCallback::EmitCall(BlockOfCode* code, std::function<void()> l) {
|
void ArgCallback::EmitCall(BlockOfCode* code, std::function<void()> l) {
|
||||||
code->mov(code->ABI_PARAM1, arg);
|
|
||||||
l();
|
l();
|
||||||
|
code->mov(code->ABI_PARAM1, arg);
|
||||||
code->CallFunction(fn);
|
code->CallFunction(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArgCallback::EmitCall(BlockOfCode* code, std::function<void(Xbyak::Reg64)> l) {
|
void ArgCallback::EmitCall(BlockOfCode* code, std::function<void(Xbyak::Reg64)> l) {
|
||||||
code->mov(code->ABI_PARAM1, arg);
|
|
||||||
l(code->ABI_PARAM2);
|
l(code->ABI_PARAM2);
|
||||||
|
code->mov(code->ABI_PARAM1, arg);
|
||||||
code->CallFunction(fn);
|
code->CallFunction(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArgCallback::EmitCall(BlockOfCode* code, std::function<void(Xbyak::Reg64, Xbyak::Reg64)> l) {
|
void ArgCallback::EmitCall(BlockOfCode* code, std::function<void(Xbyak::Reg64, Xbyak::Reg64)> l) {
|
||||||
code->mov(code->ABI_PARAM1, arg);
|
|
||||||
l(code->ABI_PARAM2, code->ABI_PARAM3);
|
l(code->ABI_PARAM2, code->ABI_PARAM3);
|
||||||
|
code->mov(code->ABI_PARAM1, arg);
|
||||||
code->CallFunction(fn);
|
code->CallFunction(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArgCallback::EmitCall(BlockOfCode* code, std::function<void(Xbyak::Reg64, Xbyak::Reg64, Xbyak::Reg64)> l) {
|
void ArgCallback::EmitCall(BlockOfCode* code, std::function<void(Xbyak::Reg64, Xbyak::Reg64, Xbyak::Reg64)> l) {
|
||||||
code->mov(code->ABI_PARAM1, arg);
|
|
||||||
l(code->ABI_PARAM2, code->ABI_PARAM3, code->ABI_PARAM4);
|
l(code->ABI_PARAM2, code->ABI_PARAM3, code->ABI_PARAM4);
|
||||||
|
code->mov(code->ABI_PARAM1, arg);
|
||||||
code->CallFunction(fn);
|
code->CallFunction(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -201,10 +201,10 @@ std::vector<Matcher<V>> GetDecodeTable() {
|
||||||
//INST(&V::LDAR, "LDAR", "1-00100011011111111111nnnnnttttt"),
|
//INST(&V::LDAR, "LDAR", "1-00100011011111111111nnnnnttttt"),
|
||||||
|
|
||||||
// Loads and stores - Load register (literal)
|
// Loads and stores - Load register (literal)
|
||||||
//INST(&V::LDR_lit_gen, "LDR (literal)", "0-011000iiiiiiiiiiiiiiiiiiittttt"),
|
INST(&V::LDR_lit_gen, "LDR (literal)", "0z011000iiiiiiiiiiiiiiiiiiittttt"),
|
||||||
|
INST(&V::LDRSW_lit, "LDRSW (literal)", "10011000iiiiiiiiiiiiiiiiiiittttt"),
|
||||||
|
INST(&V::PRFM_lit, "PRFM (literal)", "11011000iiiiiiiiiiiiiiiiiiittttt"),
|
||||||
//INST(&V::LDR_lit_fpsimd, "LDR (literal, SIMD&FP)", "oo011100iiiiiiiiiiiiiiiiiiittttt"),
|
//INST(&V::LDR_lit_fpsimd, "LDR (literal, SIMD&FP)", "oo011100iiiiiiiiiiiiiiiiiiittttt"),
|
||||||
//INST(&V::LDRSW_lit, "LDRSW (literal)", "10011000iiiiiiiiiiiiiiiiiiittttt"),
|
|
||||||
//INST(&V::PRFM_lit, "PRFM (literal)", "11011000iiiiiiiiiiiiiiiiiiittttt"),
|
|
||||||
|
|
||||||
// Loads and stores - Load/Store no-allocate pair
|
// Loads and stores - Load/Store no-allocate pair
|
||||||
//INST(&V::STNP_gen, "STNP", "-010100000iiiiiiiuuuuunnnnnttttt"),
|
//INST(&V::STNP_gen, "STNP", "-010100000iiiiiiiuuuuunnnnnttttt"),
|
||||||
|
@ -230,54 +230,24 @@ std::vector<Matcher<V>> GetDecodeTable() {
|
||||||
//INST(&V::LDPSW_3, "LDPSW", "0110100101iiiiiiiuuuuunnnnnttttt"),
|
//INST(&V::LDPSW_3, "LDPSW", "0110100101iiiiiiiuuuuunnnnnttttt"),
|
||||||
|
|
||||||
// Loads and stores - Load/Store register (unscaled immediate)
|
// Loads and stores - Load/Store register (unscaled immediate)
|
||||||
//INST(&V::STURB, "STURB", "00111000000iiiiiiiii00nnnnnttttt"),
|
INST(&V::STURx_LDURx, "STURx/LDURx", "zz111000oo0iiiiiiiii00nnnnnttttt"),
|
||||||
//INST(&V::LDURB, "LDURB", "00111000010iiiiiiiii00nnnnnttttt"),
|
INST(&V::UnallocatedEncoding, "", "111110001-0---------00----------"),
|
||||||
//INST(&V::LDURSB, "LDURSB", "001110001-0iiiiiiiii00nnnnnttttt"),
|
INST(&V::UnallocatedEncoding, "", "10111000110---------00----------"),
|
||||||
|
//INST(&V::PRFM_imm, "PRFM (immediate)", "1111100110iiiiiiiiiiiinnnnnttttt"),
|
||||||
//INST(&V::STUR_fpsimd, "STUR (SIMD&FP)", "zz111100-00iiiiiiiii00nnnnnttttt"),
|
//INST(&V::STUR_fpsimd, "STUR (SIMD&FP)", "zz111100-00iiiiiiiii00nnnnnttttt"),
|
||||||
//INST(&V::LDUR_fpsimd, "LDUR (SIMD&FP)", "zz111100-10iiiiiiiii00nnnnnttttt"),
|
//INST(&V::LDUR_fpsimd, "LDUR (SIMD&FP)", "zz111100-10iiiiiiiii00nnnnnttttt"),
|
||||||
//INST(&V::STURH, "STURH", "01111000000iiiiiiiii00nnnnnttttt"),
|
|
||||||
//INST(&V::LDURH, "LDURH", "01111000010iiiiiiiii00nnnnnttttt"),
|
|
||||||
//INST(&V::LDURSH, "LDURSH", "011110001-0iiiiiiiii00nnnnnttttt"),
|
|
||||||
//INST(&V::STUR_gen, "STUR", "1-111000000iiiiiiiii00nnnnnttttt"),
|
|
||||||
//INST(&V::LDUR_gen, "LDUR", "1-111000010iiiiiiiii00nnnnnttttt"),
|
|
||||||
//INST(&V::LDURSW, "LDURSW", "10111000100iiiiiiiii00nnnnnttttt"),
|
|
||||||
//INST(&V::PRFUM, "PRFM (unscaled offset)", "11111000100iiiiiiiii00nnnnnttttt"),
|
|
||||||
//INST(&V::PRFM_imm, "PRFM (immediate)", "1111100110iiiiiiiiiiiinnnnnttttt"),
|
|
||||||
|
|
||||||
// Loads and stores - Load/Store register (immediate pre/post-indexed)
|
// Loads and stores - Load/Store register (immediate pre/post-indexed)
|
||||||
//INST(&V::STRB_imm_1, "STRB (immediate)", "00111000000iiiiiiiii01nnnnnttttt"),
|
INST(&V::STRx_LDRx_imm_1, "STRx/LDRx (immediate)", "zz111000oo0iiiiiiiiip1nnnnnttttt"),
|
||||||
//INST(&V::STRB_imm_2, "STRB (immediate)", "00111000000iiiiiiiii11nnnnnttttt"),
|
INST(&V::STRx_LDRx_imm_2, "STRx/LDRx (immediate)", "zz111001ooiiiiiiiiiiiinnnnnttttt"),
|
||||||
//INST(&V::STRB_imm_3, "STRB (immediate)", "0011100100iiiiiiiiiiiinnnnnttttt"),
|
INST(&V::UnallocatedEncoding, "", "111110001-0----------1----------"),
|
||||||
//INST(&V::LDRB_imm_1, "LDRB (immediate)", "00111000010iiiiiiiii01nnnnnttttt"),
|
INST(&V::UnallocatedEncoding, "", "10111000110----------1----------"),
|
||||||
//INST(&V::LDRB_imm_2, "LDRB (immediate)", "00111000010iiiiiiiii11nnnnnttttt"),
|
INST(&V::UnallocatedEncoding, "", "1111100111----------------------"),
|
||||||
//INST(&V::LDRB_imm_3, "LDRB (immediate)", "0011100101iiiiiiiiiiiinnnnnttttt"),
|
INST(&V::UnallocatedEncoding, "", "1011100111----------------------"),
|
||||||
//INST(&V::LDRSB_imm_1, "LDRSB (immediate)", "001110001-0iiiiiiiii01nnnnnttttt"),
|
//INST(&V::STR_imm_fpsimd_1, "STR (immediate, SIMD&FP)", "zz111100-00iiiiiiiiip1nnnnnttttt"),
|
||||||
//INST(&V::LDRSB_imm_2, "LDRSB (immediate)", "001110001-0iiiiiiiii11nnnnnttttt"),
|
//INST(&V::STR_imm_fpsimd_2, "STR (immediate, SIMD&FP)", "zz111101-0iiiiiiiiiiiinnnnnttttt"),
|
||||||
//INST(&V::LDRSB_imm_3, "LDRSB (immediate)", "001110011-iiiiiiiiiiiinnnnnttttt"),
|
//INST(&V::LDR_imm_fpsimd_1, "LDR (immediate, SIMD&FP)", "zz111100-10iiiiiiiiip1nnnnnttttt"),
|
||||||
//INST(&V::STR_imm_fpsimd_1, "STR (immediate, SIMD&FP)", "zz111100-00iiiiiiiii01nnnnnttttt"),
|
//INST(&V::LDR_imm_fpsimd_2, "LDR (immediate, SIMD&FP)", "zz111101-1iiiiiiiiiiiinnnnnttttt"),
|
||||||
//INST(&V::STR_imm_fpsimd_2, "STR (immediate, SIMD&FP)", "zz111100-00iiiiiiiii11nnnnnttttt"),
|
|
||||||
//INST(&V::STR_imm_fpsimd_3, "STR (immediate, SIMD&FP)", "zz111101-0iiiiiiiiiiiinnnnnttttt"),
|
|
||||||
//INST(&V::LDR_imm_fpsimd_1, "LDR (immediate, SIMD&FP)", "zz111100-10iiiiiiiii01nnnnnttttt"),
|
|
||||||
//INST(&V::LDR_imm_fpsimd_2, "LDR (immediate, SIMD&FP)", "zz111100-10iiiiiiiii11nnnnnttttt"),
|
|
||||||
//INST(&V::LDR_imm_fpsimd_3, "LDR (immediate, SIMD&FP)", "zz111101-1iiiiiiiiiiiinnnnnttttt"),
|
|
||||||
//INST(&V::STRH_imm_1, "STRH (immediate)", "01111000000iiiiiiiii01nnnnnttttt"),
|
|
||||||
//INST(&V::STRH_imm_2, "STRH (immediate)", "01111000000iiiiiiiii11nnnnnttttt"),
|
|
||||||
//INST(&V::STRH_imm_3, "STRH (immediate)", "0111100100iiiiiiiiiiiinnnnnttttt"),
|
|
||||||
//INST(&V::LDRH_imm_1, "LDRH (immediate)", "01111000010iiiiiiiii01nnnnnttttt"),
|
|
||||||
//INST(&V::LDRH_imm_2, "LDRH (immediate)", "01111000010iiiiiiiii11nnnnnttttt"),
|
|
||||||
//INST(&V::LDRH_imm_3, "LDRH (immediate)", "0111100101iiiiiiiiiiiinnnnnttttt"),
|
|
||||||
//INST(&V::LDRSH_imm_1, "LDRSH (immediate)", "011110001-0iiiiiiiii01nnnnnttttt"),
|
|
||||||
//INST(&V::LDRSH_imm_2, "LDRSH (immediate)", "011110001-0iiiiiiiii11nnnnnttttt"),
|
|
||||||
//INST(&V::LDRSH_imm_3, "LDRSH (immediate)", "011110011-iiiiiiiiiiiinnnnnttttt"),
|
|
||||||
//INST(&V::STR_imm_gen_1, "STR (immediate)", "1-111000000iiiiiiiii01nnnnnttttt"),
|
|
||||||
//INST(&V::STR_imm_gen_2, "STR (immediate)", "1-111000000iiiiiiiii11nnnnnttttt"),
|
|
||||||
//INST(&V::STR_imm_gen_3, "STR (immediate)", "1-11100100iiiiiiiiiiiinnnnnttttt"),
|
|
||||||
//INST(&V::LDR_imm_gen_1, "LDR (immediate)", "1-111000010iiiiiiiii01nnnnnttttt"),
|
|
||||||
//INST(&V::LDR_imm_gen_2, "LDR (immediate)", "1-111000010iiiiiiiii11nnnnnttttt"),
|
|
||||||
//INST(&V::LDR_imm_gen_3, "LDR (immediate)", "1-11100101iiiiiiiiiiiinnnnnttttt"),
|
|
||||||
//INST(&V::LDRSW_imm_1, "LDRSW (immediate)", "10111000100iiiiiiiii01nnnnnttttt"),
|
|
||||||
//INST(&V::LDRSW_imm_2, "LDRSW (immediate)", "10111000100iiiiiiiii11nnnnnttttt"),
|
|
||||||
//INST(&V::LDRSW_imm_3, "LDRSW (immediate)", "1011100110iiiiiiiiiiiinnnnnttttt"),
|
|
||||||
|
|
||||||
// Loads and stores - Load/Store register (unprivileged)
|
// Loads and stores - Load/Store register (unprivileged)
|
||||||
//INST(&V::STTRB, "STTRB", "00111000000iiiiiiiii10nnnnnttttt"),
|
//INST(&V::STTRB, "STTRB", "00111000000iiiiiiiii10nnnnnttttt"),
|
||||||
|
|
|
@ -38,6 +38,38 @@ void IREmitter::CallSupervisor(u32 imm) {
|
||||||
Inst(Opcode::A64CallSupervisor, Imm32(imm));
|
Inst(Opcode::A64CallSupervisor, Imm32(imm));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IR::U8 IREmitter::ReadMemory8(const IR::U64& vaddr) {
|
||||||
|
return Inst<IR::U8>(Opcode::A64ReadMemory8, vaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
IR::U16 IREmitter::ReadMemory16(const IR::U64& vaddr) {
|
||||||
|
return Inst<IR::U16>(Opcode::A64ReadMemory16, vaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
IR::U32 IREmitter::ReadMemory32(const IR::U64& vaddr) {
|
||||||
|
return Inst<IR::U32>(Opcode::A64ReadMemory32, vaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
IR::U64 IREmitter::ReadMemory64(const IR::U64& vaddr) {
|
||||||
|
return Inst<IR::U64>(Opcode::A64ReadMemory64, vaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IREmitter::WriteMemory8(const IR::U64& vaddr, const IR::U8& value) {
|
||||||
|
Inst(Opcode::A64WriteMemory8, vaddr, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IREmitter::WriteMemory16(const IR::U64& vaddr, const IR::U16& value) {
|
||||||
|
Inst(Opcode::A64WriteMemory16, vaddr, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IREmitter::WriteMemory32(const IR::U64& vaddr, const IR::U32& value) {
|
||||||
|
Inst(Opcode::A64WriteMemory32, vaddr, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IREmitter::WriteMemory64(const IR::U64& vaddr, const IR::U64& value) {
|
||||||
|
Inst(Opcode::A64WriteMemory64, vaddr, value);
|
||||||
|
}
|
||||||
|
|
||||||
IR::U32 IREmitter::GetW(Reg reg) {
|
IR::U32 IREmitter::GetW(Reg reg) {
|
||||||
if (reg == Reg::ZR)
|
if (reg == Reg::ZR)
|
||||||
return Imm32(0);
|
return Imm32(0);
|
||||||
|
|
|
@ -37,6 +37,15 @@ public:
|
||||||
|
|
||||||
void CallSupervisor(u32 imm);
|
void CallSupervisor(u32 imm);
|
||||||
|
|
||||||
|
IR::U8 ReadMemory8(const IR::U64& vaddr);
|
||||||
|
IR::U16 ReadMemory16(const IR::U64& vaddr);
|
||||||
|
IR::U32 ReadMemory32(const IR::U64& vaddr);
|
||||||
|
IR::U64 ReadMemory64(const IR::U64& vaddr);
|
||||||
|
void WriteMemory8(const IR::U64& vaddr, const IR::U8& value);
|
||||||
|
void WriteMemory16(const IR::U64& vaddr, const IR::U16& value);
|
||||||
|
void WriteMemory32(const IR::U64& vaddr, const IR::U32& value);
|
||||||
|
void WriteMemory64(const IR::U64& vaddr, const IR::U64& value);
|
||||||
|
|
||||||
IR::U32 GetW(Reg source_reg);
|
IR::U32 GetW(Reg source_reg);
|
||||||
IR::U64 GetX(Reg source_reg);
|
IR::U64 GetX(Reg source_reg);
|
||||||
IR::U64 GetSP();
|
IR::U64 GetSP();
|
||||||
|
|
|
@ -66,7 +66,7 @@ bool TranslatorVisitor::CBZ(bool sf, Imm<19> imm19, Reg Rt) {
|
||||||
size_t datasize = sf ? 64 : 32;
|
size_t datasize = sf ? 64 : 32;
|
||||||
s64 offset = concatenate(imm19, Imm<2>{0}).SignExtend<s64>();
|
s64 offset = concatenate(imm19, Imm<2>{0}).SignExtend<s64>();
|
||||||
|
|
||||||
auto operand1 = X(datasize, Rt);
|
IR::U32U64 operand1 = X(datasize, Rt);
|
||||||
|
|
||||||
ir.SetCheckBit(ir.IsZero(operand1));
|
ir.SetCheckBit(ir.IsZero(operand1));
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ bool TranslatorVisitor::CBNZ(bool sf, Imm<19> imm19, Reg Rt) {
|
||||||
size_t datasize = sf ? 64 : 32;
|
size_t datasize = sf ? 64 : 32;
|
||||||
s64 offset = concatenate(imm19, Imm<2>{0}).SignExtend<s64>();
|
s64 offset = concatenate(imm19, Imm<2>{0}).SignExtend<s64>();
|
||||||
|
|
||||||
auto operand1 = X(datasize, Rt);
|
IR::U32U64 operand1 = X(datasize, Rt);
|
||||||
|
|
||||||
ir.SetCheckBit(ir.IsZero(operand1));
|
ir.SetCheckBit(ir.IsZero(operand1));
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ bool TranslatorVisitor::ADD_imm(bool sf, Imm<2> shift, Imm<12> imm12, Reg Rn, Re
|
||||||
return ReservedValue();
|
return ReservedValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operand1 = Rn == Reg::SP ? SP(datasize) : X(datasize, Rn);
|
auto operand1 = Rn == Reg::SP ? SP(datasize) : IR::U32U64(X(datasize, Rn));
|
||||||
|
|
||||||
auto result = ir.Add(operand1, I(datasize, imm));
|
auto result = ir.Add(operand1, I(datasize, imm));
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ bool TranslatorVisitor::ADDS_imm(bool sf, Imm<2> shift, Imm<12> imm12, Reg Rn, R
|
||||||
return ReservedValue();
|
return ReservedValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operand1 = Rn == Reg::SP ? SP(datasize) : X(datasize, Rn);
|
auto operand1 = Rn == Reg::SP ? SP(datasize) : IR::U32U64(X(datasize, Rn));
|
||||||
|
|
||||||
auto result = ir.Add(operand1, I(datasize, imm));
|
auto result = ir.Add(operand1, I(datasize, imm));
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ bool TranslatorVisitor::SUB_imm(bool sf, Imm<2> shift, Imm<12> imm12, Reg Rn, Re
|
||||||
return ReservedValue();
|
return ReservedValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operand1 = Rn == Reg::SP ? SP(datasize) : X(datasize, Rn);
|
auto operand1 = Rn == Reg::SP ? SP(datasize) : IR::U32U64(X(datasize, Rn));
|
||||||
|
|
||||||
auto result = ir.Sub(operand1, I(datasize, imm));
|
auto result = ir.Sub(operand1, I(datasize, imm));
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ bool TranslatorVisitor::SUBS_imm(bool sf, Imm<2> shift, Imm<12> imm12, Reg Rn, R
|
||||||
return ReservedValue();
|
return ReservedValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operand1 = Rn == Reg::SP ? SP(datasize) : X(datasize, Rn);
|
auto operand1 = Rn == Reg::SP ? SP(datasize) : IR::U32U64(X(datasize, Rn));
|
||||||
|
|
||||||
auto result = ir.Sub(operand1, I(datasize, imm));
|
auto result = ir.Sub(operand1, I(datasize, imm));
|
||||||
|
|
||||||
|
@ -198,7 +198,7 @@ bool TranslatorVisitor::ADD_ext(bool sf, Reg Rm, Imm<3> option, Imm<3> imm3, Reg
|
||||||
u8 shift = imm3.ZeroExtend<u8>();
|
u8 shift = imm3.ZeroExtend<u8>();
|
||||||
if (shift > 4) return ReservedValue();
|
if (shift > 4) return ReservedValue();
|
||||||
|
|
||||||
auto operand1 = Rn == Reg::SP ? SP(datasize) : X(datasize, Rn);
|
auto operand1 = Rn == Reg::SP ? SP(datasize) : IR::U32U64(X(datasize, Rn));
|
||||||
auto operand2 = ExtendReg(datasize, Rm, option, shift);
|
auto operand2 = ExtendReg(datasize, Rm, option, shift);
|
||||||
|
|
||||||
auto result = ir.Add(operand1, operand2);
|
auto result = ir.Add(operand1, operand2);
|
||||||
|
@ -217,7 +217,7 @@ bool TranslatorVisitor::ADDS_ext(bool sf, Reg Rm, Imm<3> option, Imm<3> imm3, Re
|
||||||
u8 shift = imm3.ZeroExtend<u8>();
|
u8 shift = imm3.ZeroExtend<u8>();
|
||||||
if (shift > 4) return ReservedValue();
|
if (shift > 4) return ReservedValue();
|
||||||
|
|
||||||
auto operand1 = Rn == Reg::SP ? SP(datasize) : X(datasize, Rn);
|
auto operand1 = Rn == Reg::SP ? SP(datasize) : IR::U32U64(X(datasize, Rn));
|
||||||
auto operand2 = ExtendReg(datasize, Rm, option, shift);
|
auto operand2 = ExtendReg(datasize, Rm, option, shift);
|
||||||
|
|
||||||
auto result = ir.Add(operand1, operand2);
|
auto result = ir.Add(operand1, operand2);
|
||||||
|
@ -238,7 +238,7 @@ bool TranslatorVisitor::SUB_ext(bool sf, Reg Rm, Imm<3> option, Imm<3> imm3, Reg
|
||||||
u8 shift = imm3.ZeroExtend<u8>();
|
u8 shift = imm3.ZeroExtend<u8>();
|
||||||
if (shift > 4) return ReservedValue();
|
if (shift > 4) return ReservedValue();
|
||||||
|
|
||||||
auto operand1 = Rn == Reg::SP ? SP(datasize) : X(datasize, Rn);
|
auto operand1 = Rn == Reg::SP ? SP(datasize) : IR::U32U64(X(datasize, Rn));
|
||||||
auto operand2 = ExtendReg(datasize, Rm, option, shift);
|
auto operand2 = ExtendReg(datasize, Rm, option, shift);
|
||||||
|
|
||||||
auto result = ir.Sub(operand1, operand2);
|
auto result = ir.Sub(operand1, operand2);
|
||||||
|
@ -257,7 +257,7 @@ bool TranslatorVisitor::SUBS_ext(bool sf, Reg Rm, Imm<3> option, Imm<3> imm3, Re
|
||||||
u8 shift = imm3.ZeroExtend<u8>();
|
u8 shift = imm3.ZeroExtend<u8>();
|
||||||
if (shift > 4) return ReservedValue();
|
if (shift > 4) return ReservedValue();
|
||||||
|
|
||||||
auto operand1 = Rn == Reg::SP ? SP(datasize) : X(datasize, Rn);
|
auto operand1 = Rn == Reg::SP ? SP(datasize) : IR::U32U64(X(datasize, Rn));
|
||||||
auto operand2 = ExtendReg(datasize, Rm, option, shift);
|
auto operand2 = ExtendReg(datasize, Rm, option, shift);
|
||||||
|
|
||||||
auto result = ir.Sub(operand1, operand2);
|
auto result = ir.Sub(operand1, operand2);
|
||||||
|
@ -276,8 +276,8 @@ bool TranslatorVisitor::SUBS_ext(bool sf, Reg Rm, Imm<3> option, Imm<3> imm3, Re
|
||||||
bool TranslatorVisitor::ADC(bool sf, Reg Rm, Reg Rn, Reg Rd) {
|
bool TranslatorVisitor::ADC(bool sf, Reg Rm, Reg Rn, Reg Rd) {
|
||||||
size_t datasize = sf ? 64 : 32;
|
size_t datasize = sf ? 64 : 32;
|
||||||
|
|
||||||
auto operand1 = X(datasize, Rn);
|
IR::U32U64 operand1 = X(datasize, Rn);
|
||||||
auto operand2 = X(datasize, Rm);
|
IR::U32U64 operand2 = X(datasize, Rm);
|
||||||
|
|
||||||
auto result = ir.AddWithCarry(operand1, operand2, ir.GetCFlag());
|
auto result = ir.AddWithCarry(operand1, operand2, ir.GetCFlag());
|
||||||
|
|
||||||
|
@ -289,8 +289,8 @@ bool TranslatorVisitor::ADC(bool sf, Reg Rm, Reg Rn, Reg Rd) {
|
||||||
bool TranslatorVisitor::ADCS(bool sf, Reg Rm, Reg Rn, Reg Rd) {
|
bool TranslatorVisitor::ADCS(bool sf, Reg Rm, Reg Rn, Reg Rd) {
|
||||||
size_t datasize = sf ? 64 : 32;
|
size_t datasize = sf ? 64 : 32;
|
||||||
|
|
||||||
auto operand1 = X(datasize, Rn);
|
IR::U32U64 operand1 = X(datasize, Rn);
|
||||||
auto operand2 = X(datasize, Rm);
|
IR::U32U64 operand2 = X(datasize, Rm);
|
||||||
|
|
||||||
auto result = ir.AddWithCarry(operand1, operand2, ir.GetCFlag());
|
auto result = ir.AddWithCarry(operand1, operand2, ir.GetCFlag());
|
||||||
|
|
||||||
|
@ -304,8 +304,8 @@ bool TranslatorVisitor::ADCS(bool sf, Reg Rm, Reg Rn, Reg Rd) {
|
||||||
bool TranslatorVisitor::SBC(bool sf, Reg Rm, Reg Rn, Reg Rd) {
|
bool TranslatorVisitor::SBC(bool sf, Reg Rm, Reg Rn, Reg Rd) {
|
||||||
size_t datasize = sf ? 64 : 32;
|
size_t datasize = sf ? 64 : 32;
|
||||||
|
|
||||||
auto operand1 = X(datasize, Rn);
|
IR::U32U64 operand1 = X(datasize, Rn);
|
||||||
auto operand2 = X(datasize, Rm);
|
IR::U32U64 operand2 = X(datasize, Rm);
|
||||||
|
|
||||||
auto result = ir.SubWithCarry(operand1, operand2, ir.GetCFlag());
|
auto result = ir.SubWithCarry(operand1, operand2, ir.GetCFlag());
|
||||||
|
|
||||||
|
@ -317,8 +317,8 @@ bool TranslatorVisitor::SBC(bool sf, Reg Rm, Reg Rn, Reg Rd) {
|
||||||
bool TranslatorVisitor::SBCS(bool sf, Reg Rm, Reg Rn, Reg Rd) {
|
bool TranslatorVisitor::SBCS(bool sf, Reg Rm, Reg Rn, Reg Rd) {
|
||||||
size_t datasize = sf ? 64 : 32;
|
size_t datasize = sf ? 64 : 32;
|
||||||
|
|
||||||
auto operand1 = X(datasize, Rn);
|
IR::U32U64 operand1 = X(datasize, Rn);
|
||||||
auto operand2 = X(datasize, Rm);
|
IR::U32U64 operand2 = X(datasize, Rm);
|
||||||
|
|
||||||
auto result = ir.SubWithCarry(operand1, operand2, ir.GetCFlag());
|
auto result = ir.SubWithCarry(operand1, operand2, ir.GetCFlag());
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,11 @@ bool TranslatorVisitor::ReservedValue() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TranslatorVisitor::UnallocatedEncoding() {
|
||||||
|
ASSERT_MSG(false, "UNALLOCATEDENCODING");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
boost::optional<TranslatorVisitor::BitMasks> TranslatorVisitor::DecodeBitMasks(bool immN, Imm<6> imms, Imm<6> immr, bool immediate) {
|
boost::optional<TranslatorVisitor::BitMasks> TranslatorVisitor::DecodeBitMasks(bool immN, Imm<6> imms, Imm<6> immr, bool immediate) {
|
||||||
int len = Common::HighestSetBit((immN ? 1 << 6 : 0) | (imms.ZeroExtend() ^ 0b111111));
|
int len = Common::HighestSetBit((immN ? 1 << 6 : 0) | (imms.ZeroExtend() ^ 0b111111));
|
||||||
if (len < 1)
|
if (len < 1)
|
||||||
|
@ -61,8 +66,12 @@ IR::U32U64 TranslatorVisitor::I(size_t bitsize, u64 value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::U32U64 TranslatorVisitor::X(size_t bitsize, Reg reg) {
|
IR::UAny TranslatorVisitor::X(size_t bitsize, Reg reg) {
|
||||||
switch (bitsize) {
|
switch (bitsize) {
|
||||||
|
case 8:
|
||||||
|
return ir.LeastSignificantByte(ir.GetW(reg));
|
||||||
|
case 16:
|
||||||
|
return ir.LeastSignificantHalf(ir.GetW(reg));
|
||||||
case 32:
|
case 32:
|
||||||
return ir.GetW(reg);
|
return ir.GetW(reg);
|
||||||
case 64:
|
case 64:
|
||||||
|
@ -111,8 +120,68 @@ void TranslatorVisitor::SP(size_t bitsize, IR::U32U64 value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IR::UAny TranslatorVisitor::Mem(IR::U64 address, size_t bytesize, AccType /*acctype*/) {
|
||||||
|
switch (bytesize) {
|
||||||
|
case 1:
|
||||||
|
return ir.ReadMemory8(address);
|
||||||
|
case 2:
|
||||||
|
return ir.ReadMemory16(address);
|
||||||
|
case 4:
|
||||||
|
return ir.ReadMemory32(address);
|
||||||
|
case 8:
|
||||||
|
return ir.ReadMemory64(address);
|
||||||
|
default:
|
||||||
|
ASSERT_MSG(false, "Invalid bytesize parameter %zu", bytesize);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TranslatorVisitor::Mem(IR::U64 address, size_t bytesize, AccType /*acctype*/, IR::UAny value) {
|
||||||
|
switch (bytesize) {
|
||||||
|
case 1:
|
||||||
|
ir.WriteMemory8(address, value);
|
||||||
|
return;
|
||||||
|
case 2:
|
||||||
|
ir.WriteMemory16(address, value);
|
||||||
|
return;
|
||||||
|
case 4:
|
||||||
|
ir.WriteMemory32(address, value);
|
||||||
|
return;
|
||||||
|
case 8:
|
||||||
|
ir.WriteMemory64(address, value);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
ASSERT_MSG(false, "Invalid bytesize parameter %zu", bytesize);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IR::U32U64 TranslatorVisitor::SignExtend(IR::UAny value, size_t to_size) {
|
||||||
|
switch (to_size) {
|
||||||
|
case 32:
|
||||||
|
return ir.SignExtendToWord(value);
|
||||||
|
case 64:
|
||||||
|
return ir.SignExtendToLong(value);
|
||||||
|
default:
|
||||||
|
ASSERT_MSG(false, "Invalid size parameter %zu", to_size);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IR::U32U64 TranslatorVisitor::ZeroExtend(IR::UAny value, size_t to_size) {
|
||||||
|
switch (to_size) {
|
||||||
|
case 32:
|
||||||
|
return ir.ZeroExtendToWord(value);
|
||||||
|
case 64:
|
||||||
|
return ir.ZeroExtendToLong(value);
|
||||||
|
default:
|
||||||
|
ASSERT_MSG(false, "Invalid size parameter %zu", to_size);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IR::U32U64 TranslatorVisitor::ShiftReg(size_t bitsize, Reg reg, Imm<2> shift, IR::U8 amount) {
|
IR::U32U64 TranslatorVisitor::ShiftReg(size_t bitsize, Reg reg, Imm<2> shift, IR::U8 amount) {
|
||||||
auto result = X(bitsize, reg);
|
IR::U32U64 result = X(bitsize, reg);
|
||||||
switch (shift.ZeroExtend()) {
|
switch (shift.ZeroExtend()) {
|
||||||
case 0b00:
|
case 0b00:
|
||||||
return ir.LogicalShiftLeft(result, amount);
|
return ir.LogicalShiftLeft(result, amount);
|
||||||
|
|
|
@ -16,6 +16,14 @@
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace A64 {
|
namespace A64 {
|
||||||
|
|
||||||
|
enum class AccType {
|
||||||
|
NORMAL, VEC, STREAM, VECSTREAM, ATOMIC, ORDERED, UNPRIV, IFETCH, PTW, DC, IC, AT,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class MemOp {
|
||||||
|
LOAD, STORE, PREFETCH,
|
||||||
|
};
|
||||||
|
|
||||||
struct TranslatorVisitor final {
|
struct TranslatorVisitor final {
|
||||||
using instruction_return_type = bool;
|
using instruction_return_type = bool;
|
||||||
|
|
||||||
|
@ -26,6 +34,7 @@ struct TranslatorVisitor final {
|
||||||
bool InterpretThisInstruction();
|
bool InterpretThisInstruction();
|
||||||
bool UnpredictableInstruction();
|
bool UnpredictableInstruction();
|
||||||
bool ReservedValue();
|
bool ReservedValue();
|
||||||
|
bool UnallocatedEncoding();
|
||||||
|
|
||||||
struct BitMasks {
|
struct BitMasks {
|
||||||
u64 wmask, tmask;
|
u64 wmask, tmask;
|
||||||
|
@ -34,11 +43,16 @@ struct TranslatorVisitor final {
|
||||||
boost::optional<BitMasks> DecodeBitMasks(bool N, Imm<6> immr, Imm<6> imms, bool immediate);
|
boost::optional<BitMasks> DecodeBitMasks(bool N, Imm<6> immr, Imm<6> imms, bool immediate);
|
||||||
|
|
||||||
IR::U32U64 I(size_t bitsize, u64 value);
|
IR::U32U64 I(size_t bitsize, u64 value);
|
||||||
IR::U32U64 X(size_t bitsize, Reg reg);
|
IR::UAny X(size_t bitsize, Reg reg);
|
||||||
void X(size_t bitsize, Reg reg, IR::U32U64 value);
|
void X(size_t bitsize, Reg reg, IR::U32U64 value);
|
||||||
IR::U32U64 SP(size_t bitsize);
|
IR::U32U64 SP(size_t bitsize);
|
||||||
void SP(size_t bitsize, IR::U32U64 value);
|
void SP(size_t bitsize, IR::U32U64 value);
|
||||||
|
|
||||||
|
IR::UAny Mem(IR::U64 address, size_t size, AccType acctype);
|
||||||
|
void Mem(IR::U64 address, size_t size, AccType acctype, IR::UAny value);
|
||||||
|
|
||||||
|
IR::U32U64 SignExtend(IR::UAny value, size_t to_size);
|
||||||
|
IR::U32U64 ZeroExtend(IR::UAny value, size_t to_size);
|
||||||
IR::U32U64 ShiftReg(size_t bitsize, Reg reg, Imm<2> shift, IR::U8 amount);
|
IR::U32U64 ShiftReg(size_t bitsize, Reg reg, Imm<2> shift, IR::U8 amount);
|
||||||
IR::U32U64 ExtendReg(size_t bitsize, Reg reg, Imm<3> option, u8 shift);
|
IR::U32U64 ExtendReg(size_t bitsize, Reg reg, Imm<3> option, u8 shift);
|
||||||
|
|
||||||
|
@ -214,10 +228,10 @@ struct TranslatorVisitor final {
|
||||||
bool LDAR(Reg Rn, Reg Rt);
|
bool LDAR(Reg Rn, Reg Rt);
|
||||||
|
|
||||||
// Loads and stores - Load register (literal)
|
// Loads and stores - Load register (literal)
|
||||||
bool LDR_lit_gen(Imm<19> imm19, Reg Rt);
|
bool LDR_lit_gen(bool opc_0, Imm<19> imm19, Reg Rt);
|
||||||
bool LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt);
|
bool LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt);
|
||||||
bool LDRSW_lit(Imm<19> imm19, Reg Rt);
|
bool LDRSW_lit(Imm<19> imm19, Reg Rt);
|
||||||
bool PRFM_lit(Imm<19> imm19, Reg Rt);
|
bool PRFM_lit(Imm<19> imm19, Imm<5> prfop);
|
||||||
|
|
||||||
// Loads and stores - Load/Store no-allocate pair
|
// Loads and stores - Load/Store no-allocate pair
|
||||||
bool STNP_gen(Imm<7> imm7, Reg Rt2, Reg Rn, Reg Rt);
|
bool STNP_gen(Imm<7> imm7, Reg Rt2, Reg Rn, Reg Rt);
|
||||||
|
@ -242,55 +256,18 @@ struct TranslatorVisitor final {
|
||||||
bool LDPSW_2(Imm<7> imm7, Reg Rt2, Reg Rn, Reg Rt);
|
bool LDPSW_2(Imm<7> imm7, Reg Rt2, Reg Rn, Reg Rt);
|
||||||
bool LDPSW_3(Imm<7> imm7, Reg Rt2, Reg Rn, Reg Rt);
|
bool LDPSW_3(Imm<7> imm7, Reg Rt2, Reg Rn, Reg Rt);
|
||||||
|
|
||||||
// Loads and stores - Load/Store register (unscaled immediate)
|
// Loads and stores - Load/Store register (immediate)
|
||||||
bool STURB(Imm<9> imm9, Reg Rn, Reg Rt);
|
bool load_store_register_immediate(bool wback, bool postindex, size_t scale, u64 offset, Imm<2> size, Imm<2> opc, Reg Rn, Reg Rt);
|
||||||
bool LDURB(Imm<9> imm9, Reg Rn, Reg Rt);
|
bool STRx_LDRx_imm_1(Imm<2> size, Imm<2> opc, Imm<9> imm9, bool not_postindex, Reg Rn, Reg Rt);
|
||||||
bool LDURSB(Imm<9> imm9, Reg Rn, Reg Rt);
|
bool STRx_LDRx_imm_2(Imm<2> size, Imm<2> opc, Imm<12> imm12, Reg Rn, Reg Rt);
|
||||||
|
bool STURx_LDURx(Imm<2> size, Imm<2> opc, Imm<9> imm9, Reg Rn, Reg Rt);
|
||||||
|
bool PRFM_imm(Imm<12> imm12, Reg Rn, Reg Rt);
|
||||||
|
bool STR_imm_fpsimd_1(Imm<2> size, Imm<9> imm9, bool not_postindex, Reg Rn, Vec Vt);
|
||||||
|
bool STR_imm_fpsimd_2(Imm<2> size, Imm<12> imm12, Reg Rn, Vec Vt);
|
||||||
|
bool LDR_imm_fpsimd_1(Imm<2> size, Imm<9> imm9, bool not_postindex, Reg Rn, Vec Vt);
|
||||||
|
bool LDR_imm_fpsimd_2(Imm<2> size, Imm<12> imm12, Reg Rn, Vec Vt);
|
||||||
bool STUR_fpsimd(Imm<2> size, Imm<9> imm9, Reg Rn, Vec Vt);
|
bool STUR_fpsimd(Imm<2> size, Imm<9> imm9, Reg Rn, Vec Vt);
|
||||||
bool LDUR_fpsimd(Imm<2> size, Imm<9> imm9, Reg Rn, Vec Vt);
|
bool LDUR_fpsimd(Imm<2> size, Imm<9> imm9, Reg Rn, Vec Vt);
|
||||||
bool STURH(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool LDURH(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool LDURSH(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool STUR_gen(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool LDUR_gen(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool LDURSW(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool PRFUM(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool PRFM_imm(Imm<12> imm12, Reg Rn, Reg Rt);
|
|
||||||
|
|
||||||
// Loads and stores - Load/Store register (immediate pre/post-indexed)
|
|
||||||
bool STRB_imm_1(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool STRB_imm_2(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool STRB_imm_3(Imm<12> imm12, Reg Rn, Reg Rt);
|
|
||||||
bool LDRB_imm_1(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool LDRB_imm_2(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool LDRB_imm_3(Imm<12> imm12, Reg Rn, Reg Rt);
|
|
||||||
bool LDRSB_imm_1(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool LDRSB_imm_2(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool LDRSB_imm_3(Imm<12> imm12, Reg Rn, Reg Rt);
|
|
||||||
bool STR_imm_fpsimd_1(Imm<2> size, Imm<9> imm9, Reg Rn, Vec Vt);
|
|
||||||
bool STR_imm_fpsimd_2(Imm<2> size, Imm<9> imm9, Reg Rn, Vec Vt);
|
|
||||||
bool STR_imm_fpsimd_3(Imm<2> size, Imm<12> imm12, Reg Rn, Vec Vt);
|
|
||||||
bool LDR_imm_fpsimd_1(Imm<2> size, Imm<9> imm9, Reg Rn, Vec Vt);
|
|
||||||
bool LDR_imm_fpsimd_2(Imm<2> size, Imm<9> imm9, Reg Rn, Vec Vt);
|
|
||||||
bool LDR_imm_fpsimd_3(Imm<2> size, Imm<12> imm12, Reg Rn, Vec Vt);
|
|
||||||
bool STRH_imm_1(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool STRH_imm_2(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool STRH_imm_3(Imm<12> imm12, Reg Rn, Reg Rt);
|
|
||||||
bool LDRH_imm_1(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool LDRH_imm_2(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool LDRH_imm_3(Imm<12> imm12, Reg Rn, Reg Rt);
|
|
||||||
bool LDRSH_imm_1(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool LDRSH_imm_2(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool LDRSH_imm_3(Imm<12> imm12, Reg Rn, Reg Rt);
|
|
||||||
bool STR_imm_gen_1(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool STR_imm_gen_2(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool STR_imm_gen_3(Imm<12> imm12, Reg Rn, Reg Rt);
|
|
||||||
bool LDR_imm_gen_1(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool LDR_imm_gen_2(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool LDR_imm_gen_3(Imm<12> imm12, Reg Rn, Reg Rt);
|
|
||||||
bool LDRSW_imm_1(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool LDRSW_imm_2(Imm<9> imm9, Reg Rn, Reg Rt);
|
|
||||||
bool LDRSW_imm_3(Imm<12> imm12, Reg Rn, Reg Rt);
|
|
||||||
|
|
||||||
// Loads and stores - Load/Store register (unprivileged)
|
// Loads and stores - Load/Store register (unprivileged)
|
||||||
bool STTRB(Imm<9> imm9, Reg Rn, Reg Rt);
|
bool STTRB(Imm<9> imm9, Reg Rn, Reg Rt);
|
||||||
|
|
43
src/frontend/A64/translate/impl/load_store_load_literal.cpp
Normal file
43
src/frontend/A64/translate/impl/load_store_load_literal.cpp
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/* This file is part of the dynarmic project.
|
||||||
|
* Copyright (c) 2018 MerryMage
|
||||||
|
* This software may be used and distributed according to the terms of the GNU
|
||||||
|
* General Public License version 2 or any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "frontend/A64/translate/impl/impl.h"
|
||||||
|
|
||||||
|
namespace Dynarmic {
|
||||||
|
namespace A64 {
|
||||||
|
|
||||||
|
bool TranslatorVisitor::LDR_lit_gen(bool opc_0, Imm<19> imm19, Reg Rt) {
|
||||||
|
size_t size = opc_0 == 0 ? 4 : 8;
|
||||||
|
s64 offset = concatenate(imm19, Imm<2>{0}).SignExtend<s64>();
|
||||||
|
|
||||||
|
u64 address = ir.PC() + offset;
|
||||||
|
|
||||||
|
auto data = Mem(ir.Imm64(address), size, AccType::NORMAL);
|
||||||
|
X(8 * size, Rt, data);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TranslatorVisitor::LDRSW_lit(Imm<19> imm19, Reg Rt) {
|
||||||
|
s64 offset = concatenate(imm19, Imm<2>{0}).SignExtend<s64>();
|
||||||
|
|
||||||
|
u64 address = ir.PC() + offset;
|
||||||
|
|
||||||
|
auto data = Mem(ir.Imm64(address), 4, AccType::NORMAL);
|
||||||
|
X(64, Rt, ir.SignExtendWordToLong(data));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TranslatorVisitor::PRFM_lit(Imm<19> /*imm19*/, Imm<5> /*prfop*/) {
|
||||||
|
// s64 offset = concatenate(imm19, Imm<2>{0}).SignExtend<s64>();
|
||||||
|
// u64 address = ir.PC() + offset;
|
||||||
|
// Prefetch(address, prfop);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace A64
|
||||||
|
} // namespace Dynarmic
|
|
@ -0,0 +1,105 @@
|
||||||
|
/* This file is part of the dynarmic project.
|
||||||
|
* Copyright (c) 2018 MerryMage
|
||||||
|
* This software may be used and distributed according to the terms of the GNU
|
||||||
|
* General Public License version 2 or any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "frontend/A64/translate/impl/impl.h"
|
||||||
|
|
||||||
|
namespace Dynarmic {
|
||||||
|
namespace A64 {
|
||||||
|
|
||||||
|
bool TranslatorVisitor::load_store_register_immediate(bool wback, bool postindex, size_t scale, u64 offset, Imm<2> size, Imm<2> opc, Reg Rn, Reg Rt) {
|
||||||
|
MemOp memop;
|
||||||
|
bool signed_ = false;
|
||||||
|
size_t regsize = 0;
|
||||||
|
|
||||||
|
if (opc.Bit<1>() == 0) {
|
||||||
|
memop = opc.Bit<0>() ? MemOp::LOAD : MemOp::STORE;
|
||||||
|
regsize = size == 0b11 ? 64 : 32;
|
||||||
|
signed_ = false;
|
||||||
|
} else if (size == 0b11) {
|
||||||
|
memop = MemOp::PREFETCH;
|
||||||
|
ASSERT(!opc.Bit<0>());
|
||||||
|
} else {
|
||||||
|
memop = MemOp::LOAD;
|
||||||
|
ASSERT(!(size == 0b10 && opc.Bit<0>() == 1));
|
||||||
|
regsize = opc.Bit<0>() ? 32 : 64;
|
||||||
|
signed_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t datasize = 8 << scale;
|
||||||
|
|
||||||
|
if (memop == MemOp::LOAD && wback && Rn == Rt && Rn != Reg::R31) {
|
||||||
|
return UnpredictableInstruction();
|
||||||
|
}
|
||||||
|
if (memop == MemOp::STORE && wback && Rn == Rt && Rn != Reg::R31) {
|
||||||
|
return UnpredictableInstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Check SP alignment
|
||||||
|
IR::U64 address = Rn == Reg::SP ? IR::U64(SP(64)) : IR::U64(X(64, Rn));
|
||||||
|
|
||||||
|
if (!postindex)
|
||||||
|
address = ir.Add(address, ir.Imm64(offset));
|
||||||
|
|
||||||
|
switch (memop) {
|
||||||
|
case MemOp::STORE: {
|
||||||
|
auto data = X(datasize, Rt);
|
||||||
|
Mem(address, datasize / 8, AccType::NORMAL, data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MemOp::LOAD: {
|
||||||
|
auto data = Mem(address, datasize / 8, AccType::NORMAL);
|
||||||
|
if (signed_)
|
||||||
|
X(regsize, Rt, SignExtend(data, regsize));
|
||||||
|
else
|
||||||
|
X(regsize, Rt, ZeroExtend(data, regsize));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MemOp::PREFETCH:
|
||||||
|
// Prefetch(address, Rt)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wback) {
|
||||||
|
if (postindex)
|
||||||
|
address = ir.Add(address, ir.Imm64(offset));
|
||||||
|
if (Rn == Reg::SP)
|
||||||
|
SP(64, address);
|
||||||
|
else
|
||||||
|
X(64, Rn, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TranslatorVisitor::STRx_LDRx_imm_1(Imm<2> size, Imm<2> opc, Imm<9> imm9, bool not_postindex, Reg Rn, Reg Rt) {
|
||||||
|
const bool wback = true;
|
||||||
|
const bool postindex = !not_postindex;
|
||||||
|
const size_t scale = size.ZeroExtend<size_t>();
|
||||||
|
const u64 offset = imm9.SignExtend<u64>();
|
||||||
|
|
||||||
|
return load_store_register_immediate(wback, postindex, scale, offset, size, opc, Rn, Rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TranslatorVisitor::STRx_LDRx_imm_2(Imm<2> size, Imm<2> opc, Imm<12> imm12, Reg Rn, Reg Rt) {
|
||||||
|
const bool wback = false;
|
||||||
|
const bool postindex = false;
|
||||||
|
const size_t scale = size.ZeroExtend<size_t>();
|
||||||
|
const u64 offset = imm12.ZeroExtend<u64>() << scale;
|
||||||
|
|
||||||
|
return load_store_register_immediate(wback, postindex, scale, offset, size, opc, Rn, Rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TranslatorVisitor::STURx_LDURx(Imm<2> size, Imm<2> opc, Imm<9> imm9, Reg Rn, Reg Rt) {
|
||||||
|
const bool wback = false;
|
||||||
|
const bool postindex = false;
|
||||||
|
const size_t scale = size.ZeroExtend<size_t>();
|
||||||
|
const u64 offset = imm9.SignExtend<u64>();
|
||||||
|
|
||||||
|
return load_store_register_immediate(wback, postindex, scale, offset, size, opc, Rn, Rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace A64
|
||||||
|
} // namespace Dynarmic
|
|
@ -48,6 +48,10 @@ bool Inst::IsSharedMemoryRead() const {
|
||||||
case Opcode::A32ReadMemory16:
|
case Opcode::A32ReadMemory16:
|
||||||
case Opcode::A32ReadMemory32:
|
case Opcode::A32ReadMemory32:
|
||||||
case Opcode::A32ReadMemory64:
|
case Opcode::A32ReadMemory64:
|
||||||
|
case Opcode::A64ReadMemory8:
|
||||||
|
case Opcode::A64ReadMemory16:
|
||||||
|
case Opcode::A64ReadMemory32:
|
||||||
|
case Opcode::A64ReadMemory64:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -61,6 +65,10 @@ bool Inst::IsSharedMemoryWrite() const {
|
||||||
case Opcode::A32WriteMemory16:
|
case Opcode::A32WriteMemory16:
|
||||||
case Opcode::A32WriteMemory32:
|
case Opcode::A32WriteMemory32:
|
||||||
case Opcode::A32WriteMemory64:
|
case Opcode::A32WriteMemory64:
|
||||||
|
case Opcode::A64WriteMemory8:
|
||||||
|
case Opcode::A64WriteMemory16:
|
||||||
|
case Opcode::A64WriteMemory32:
|
||||||
|
case Opcode::A64WriteMemory64:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -180,7 +180,7 @@ OPCODE(FPS32ToSingle, T::F32, T::F32, T::U1
|
||||||
OPCODE(FPU32ToDouble, T::F64, T::F32, T::U1 )
|
OPCODE(FPU32ToDouble, T::F64, T::F32, T::U1 )
|
||||||
OPCODE(FPS32ToDouble, T::F64, T::F32, T::U1 )
|
OPCODE(FPS32ToDouble, T::F64, T::F32, T::U1 )
|
||||||
|
|
||||||
// Memory access
|
// A32 Memory access
|
||||||
A32OPC(ClearExclusive, T::Void, )
|
A32OPC(ClearExclusive, T::Void, )
|
||||||
A32OPC(SetExclusive, T::Void, T::U32, T::U8 )
|
A32OPC(SetExclusive, T::Void, T::U32, T::U8 )
|
||||||
A32OPC(ReadMemory8, T::U8, T::U32 )
|
A32OPC(ReadMemory8, T::U8, T::U32 )
|
||||||
|
@ -196,6 +196,16 @@ A32OPC(ExclusiveWriteMemory16, T::U32, T::U32, T::U16
|
||||||
A32OPC(ExclusiveWriteMemory32, T::U32, T::U32, T::U32 )
|
A32OPC(ExclusiveWriteMemory32, T::U32, T::U32, T::U32 )
|
||||||
A32OPC(ExclusiveWriteMemory64, T::U32, T::U32, T::U32, T::U32 )
|
A32OPC(ExclusiveWriteMemory64, T::U32, T::U32, T::U32, T::U32 )
|
||||||
|
|
||||||
|
// A64 Memory access
|
||||||
|
A64OPC(ReadMemory8, T::U8, T::U64 )
|
||||||
|
A64OPC(ReadMemory16, T::U16, T::U64 )
|
||||||
|
A64OPC(ReadMemory32, T::U32, T::U64 )
|
||||||
|
A64OPC(ReadMemory64, T::U64, T::U64 )
|
||||||
|
A64OPC(WriteMemory8, T::Void, T::U64, T::U8 )
|
||||||
|
A64OPC(WriteMemory16, T::Void, T::U64, T::U16 )
|
||||||
|
A64OPC(WriteMemory32, T::Void, T::U64, T::U32 )
|
||||||
|
A64OPC(WriteMemory64, T::Void, T::U64, T::U64 )
|
||||||
|
|
||||||
// Coprocessor
|
// Coprocessor
|
||||||
A32OPC(CoprocInternalOperation, T::Void, T::CoprocInfo )
|
A32OPC(CoprocInternalOperation, T::Void, T::CoprocInfo )
|
||||||
A32OPC(CoprocSendOneWord, T::Void, T::CoprocInfo, T::U32 )
|
A32OPC(CoprocSendOneWord, T::Void, T::CoprocInfo, T::U32 )
|
||||||
|
|
Loading…
Reference in a new issue