A32: Implement load stores (immediate)

This commit is contained in:
MerryMage 2018-01-10 01:13:23 +00:00
parent 2aadeec291
commit 25411da838
14 changed files with 411 additions and 122 deletions

View file

@ -65,6 +65,8 @@ add_library(dynarmic
frontend/A64/translate/impl/exception_generating.cpp
frontend/A64/translate/impl/impl.cpp
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.h
frontend/A64/types.cpp

View file

@ -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) {
code->SwitchMxcsrOnExit();
Devirtualize<&A64::UserCallbacks::InterpreterFallback>(conf.callbacks).EmitCall(code, [&](Xbyak::Reg64 param1, Xbyak::Reg64 param2) {

View file

@ -31,26 +31,26 @@ void SimpleCallback::EmitCall(BlockOfCode* code, std::function<void(Xbyak::Reg64
}
void ArgCallback::EmitCall(BlockOfCode* code, std::function<void()> l) {
code->mov(code->ABI_PARAM1, arg);
l();
code->mov(code->ABI_PARAM1, arg);
code->CallFunction(fn);
}
void ArgCallback::EmitCall(BlockOfCode* code, std::function<void(Xbyak::Reg64)> l) {
code->mov(code->ABI_PARAM1, arg);
l(code->ABI_PARAM2);
code->mov(code->ABI_PARAM1, arg);
code->CallFunction(fn);
}
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);
code->mov(code->ABI_PARAM1, arg);
code->CallFunction(fn);
}
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);
code->mov(code->ABI_PARAM1, arg);
code->CallFunction(fn);
}

View file

@ -201,10 +201,10 @@ std::vector<Matcher<V>> GetDecodeTable() {
//INST(&V::LDAR, "LDAR", "1-00100011011111111111nnnnnttttt"),
// 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::LDRSW_lit, "LDRSW (literal)", "10011000iiiiiiiiiiiiiiiiiiittttt"),
//INST(&V::PRFM_lit, "PRFM (literal)", "11011000iiiiiiiiiiiiiiiiiiittttt"),
// Loads and stores - Load/Store no-allocate pair
//INST(&V::STNP_gen, "STNP", "-010100000iiiiiiiuuuuunnnnnttttt"),
@ -230,54 +230,24 @@ std::vector<Matcher<V>> GetDecodeTable() {
//INST(&V::LDPSW_3, "LDPSW", "0110100101iiiiiiiuuuuunnnnnttttt"),
// Loads and stores - Load/Store register (unscaled immediate)
//INST(&V::STURB, "STURB", "00111000000iiiiiiiii00nnnnnttttt"),
//INST(&V::LDURB, "LDURB", "00111000010iiiiiiiii00nnnnnttttt"),
//INST(&V::LDURSB, "LDURSB", "001110001-0iiiiiiiii00nnnnnttttt"),
INST(&V::STURx_LDURx, "STURx/LDURx", "zz111000oo0iiiiiiiii00nnnnnttttt"),
INST(&V::UnallocatedEncoding, "", "111110001-0---------00----------"),
INST(&V::UnallocatedEncoding, "", "10111000110---------00----------"),
//INST(&V::PRFM_imm, "PRFM (immediate)", "1111100110iiiiiiiiiiiinnnnnttttt"),
//INST(&V::STUR_fpsimd, "STUR (SIMD&FP)", "zz111100-00iiiiiiiii00nnnnnttttt"),
//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)
//INST(&V::STRB_imm_1, "STRB (immediate)", "00111000000iiiiiiiii01nnnnnttttt"),
//INST(&V::STRB_imm_2, "STRB (immediate)", "00111000000iiiiiiiii11nnnnnttttt"),
//INST(&V::STRB_imm_3, "STRB (immediate)", "0011100100iiiiiiiiiiiinnnnnttttt"),
//INST(&V::LDRB_imm_1, "LDRB (immediate)", "00111000010iiiiiiiii01nnnnnttttt"),
//INST(&V::LDRB_imm_2, "LDRB (immediate)", "00111000010iiiiiiiii11nnnnnttttt"),
//INST(&V::LDRB_imm_3, "LDRB (immediate)", "0011100101iiiiiiiiiiiinnnnnttttt"),
//INST(&V::LDRSB_imm_1, "LDRSB (immediate)", "001110001-0iiiiiiiii01nnnnnttttt"),
//INST(&V::LDRSB_imm_2, "LDRSB (immediate)", "001110001-0iiiiiiiii11nnnnnttttt"),
//INST(&V::LDRSB_imm_3, "LDRSB (immediate)", "001110011-iiiiiiiiiiiinnnnnttttt"),
//INST(&V::STR_imm_fpsimd_1, "STR (immediate, SIMD&FP)", "zz111100-00iiiiiiiii01nnnnnttttt"),
//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"),
INST(&V::STRx_LDRx_imm_1, "STRx/LDRx (immediate)", "zz111000oo0iiiiiiiiip1nnnnnttttt"),
INST(&V::STRx_LDRx_imm_2, "STRx/LDRx (immediate)", "zz111001ooiiiiiiiiiiiinnnnnttttt"),
INST(&V::UnallocatedEncoding, "", "111110001-0----------1----------"),
INST(&V::UnallocatedEncoding, "", "10111000110----------1----------"),
INST(&V::UnallocatedEncoding, "", "1111100111----------------------"),
INST(&V::UnallocatedEncoding, "", "1011100111----------------------"),
//INST(&V::STR_imm_fpsimd_1, "STR (immediate, SIMD&FP)", "zz111100-00iiiiiiiiip1nnnnnttttt"),
//INST(&V::STR_imm_fpsimd_2, "STR (immediate, SIMD&FP)", "zz111101-0iiiiiiiiiiiinnnnnttttt"),
//INST(&V::LDR_imm_fpsimd_1, "LDR (immediate, SIMD&FP)", "zz111100-10iiiiiiiiip1nnnnnttttt"),
//INST(&V::LDR_imm_fpsimd_2, "LDR (immediate, SIMD&FP)", "zz111101-1iiiiiiiiiiiinnnnnttttt"),
// Loads and stores - Load/Store register (unprivileged)
//INST(&V::STTRB, "STTRB", "00111000000iiiiiiiii10nnnnnttttt"),

View file

@ -38,6 +38,38 @@ void IREmitter::CallSupervisor(u32 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) {
if (reg == Reg::ZR)
return Imm32(0);

View file

@ -37,6 +37,15 @@ public:
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::U64 GetX(Reg source_reg);
IR::U64 GetSP();

View file

@ -66,7 +66,7 @@ bool TranslatorVisitor::CBZ(bool sf, Imm<19> imm19, Reg Rt) {
size_t datasize = sf ? 64 : 32;
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));
@ -81,7 +81,7 @@ bool TranslatorVisitor::CBNZ(bool sf, Imm<19> imm19, Reg Rt) {
size_t datasize = sf ? 64 : 32;
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));

View file

@ -24,7 +24,7 @@ bool TranslatorVisitor::ADD_imm(bool sf, Imm<2> shift, Imm<12> imm12, Reg Rn, Re
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));
@ -52,7 +52,7 @@ bool TranslatorVisitor::ADDS_imm(bool sf, Imm<2> shift, Imm<12> imm12, Reg Rn, R
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));
@ -78,7 +78,7 @@ bool TranslatorVisitor::SUB_imm(bool sf, Imm<2> shift, Imm<12> imm12, Reg Rn, Re
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));
@ -106,7 +106,7 @@ bool TranslatorVisitor::SUBS_imm(bool sf, Imm<2> shift, Imm<12> imm12, Reg Rn, R
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));
@ -198,7 +198,7 @@ bool TranslatorVisitor::ADD_ext(bool sf, Reg Rm, Imm<3> option, Imm<3> imm3, Reg
u8 shift = imm3.ZeroExtend<u8>();
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 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>();
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 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>();
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 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>();
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 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) {
size_t datasize = sf ? 64 : 32;
auto operand1 = X(datasize, Rn);
auto operand2 = X(datasize, Rm);
IR::U32U64 operand1 = X(datasize, Rn);
IR::U32U64 operand2 = X(datasize, Rm);
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) {
size_t datasize = sf ? 64 : 32;
auto operand1 = X(datasize, Rn);
auto operand2 = X(datasize, Rm);
IR::U32U64 operand1 = X(datasize, Rn);
IR::U32U64 operand2 = X(datasize, Rm);
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) {
size_t datasize = sf ? 64 : 32;
auto operand1 = X(datasize, Rn);
auto operand2 = X(datasize, Rm);
IR::U32U64 operand1 = X(datasize, Rn);
IR::U32U64 operand2 = X(datasize, Rm);
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) {
size_t datasize = sf ? 64 : 32;
auto operand1 = X(datasize, Rn);
auto operand2 = X(datasize, Rm);
IR::U32U64 operand1 = X(datasize, Rn);
IR::U32U64 operand2 = X(datasize, Rm);
auto result = ir.SubWithCarry(operand1, operand2, ir.GetCFlag());

View file

@ -26,6 +26,11 @@ bool TranslatorVisitor::ReservedValue() {
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) {
int len = Common::HighestSetBit((immN ? 1 << 6 : 0) | (imms.ZeroExtend() ^ 0b111111));
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) {
case 8:
return ir.LeastSignificantByte(ir.GetW(reg));
case 16:
return ir.LeastSignificantHalf(ir.GetW(reg));
case 32:
return ir.GetW(reg);
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) {
auto result = X(bitsize, reg);
IR::U32U64 result = X(bitsize, reg);
switch (shift.ZeroExtend()) {
case 0b00:
return ir.LogicalShiftLeft(result, amount);

View file

@ -16,6 +16,14 @@
namespace Dynarmic {
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 {
using instruction_return_type = bool;
@ -26,6 +34,7 @@ struct TranslatorVisitor final {
bool InterpretThisInstruction();
bool UnpredictableInstruction();
bool ReservedValue();
bool UnallocatedEncoding();
struct BitMasks {
u64 wmask, tmask;
@ -34,11 +43,16 @@ struct TranslatorVisitor final {
boost::optional<BitMasks> DecodeBitMasks(bool N, Imm<6> immr, Imm<6> imms, bool immediate);
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);
IR::U32U64 SP(size_t bitsize);
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 ExtendReg(size_t bitsize, Reg reg, Imm<3> option, u8 shift);
@ -214,10 +228,10 @@ struct TranslatorVisitor final {
bool LDAR(Reg Rn, Reg Rt);
// 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 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
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_3(Imm<7> imm7, Reg Rt2, Reg Rn, Reg Rt);
// Loads and stores - Load/Store register (unscaled immediate)
bool STURB(Imm<9> imm9, Reg Rn, Reg Rt);
bool LDURB(Imm<9> imm9, Reg Rn, Reg Rt);
bool LDURSB(Imm<9> imm9, Reg Rn, Reg Rt);
// Loads and stores - Load/Store register (immediate)
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 STRx_LDRx_imm_1(Imm<2> size, Imm<2> opc, Imm<9> imm9, bool not_postindex, 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 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)
bool STTRB(Imm<9> imm9, Reg Rn, Reg Rt);

View 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

View file

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

View file

@ -48,6 +48,10 @@ bool Inst::IsSharedMemoryRead() const {
case Opcode::A32ReadMemory16:
case Opcode::A32ReadMemory32:
case Opcode::A32ReadMemory64:
case Opcode::A64ReadMemory8:
case Opcode::A64ReadMemory16:
case Opcode::A64ReadMemory32:
case Opcode::A64ReadMemory64:
return true;
default:
@ -61,6 +65,10 @@ bool Inst::IsSharedMemoryWrite() const {
case Opcode::A32WriteMemory16:
case Opcode::A32WriteMemory32:
case Opcode::A32WriteMemory64:
case Opcode::A64WriteMemory8:
case Opcode::A64WriteMemory16:
case Opcode::A64WriteMemory32:
case Opcode::A64WriteMemory64:
return true;
default:

View file

@ -180,7 +180,7 @@ OPCODE(FPS32ToSingle, T::F32, T::F32, T::U1
OPCODE(FPU32ToDouble, T::F64, T::F32, T::U1 )
OPCODE(FPS32ToDouble, T::F64, T::F32, T::U1 )
// Memory access
// A32 Memory access
A32OPC(ClearExclusive, T::Void, )
A32OPC(SetExclusive, T::Void, T::U32, T::U8 )
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(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
A32OPC(CoprocInternalOperation, T::Void, T::CoprocInfo )
A32OPC(CoprocSendOneWord, T::Void, T::CoprocInfo, T::U32 )