diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8eaafb05..bdb69936 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/backend_x64/a64_emit_x64.cpp b/src/backend_x64/a64_emit_x64.cpp index b283c285..31fcab69 100644 --- a/src/backend_x64/a64_emit_x64.cpp +++ b/src/backend_x64/a64_emit_x64.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) { code->SwitchMxcsrOnExit(); Devirtualize<&A64::UserCallbacks::InterpreterFallback>(conf.callbacks).EmitCall(code, [&](Xbyak::Reg64 param1, Xbyak::Reg64 param2) { diff --git a/src/backend_x64/callback.cpp b/src/backend_x64/callback.cpp index cb6a2979..ceab3bb2 100644 --- a/src/backend_x64/callback.cpp +++ b/src/backend_x64/callback.cpp @@ -31,26 +31,26 @@ void SimpleCallback::EmitCall(BlockOfCode* code, std::function l) { - code->mov(code->ABI_PARAM1, arg); l(); + code->mov(code->ABI_PARAM1, arg); code->CallFunction(fn); } void ArgCallback::EmitCall(BlockOfCode* code, std::function 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 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 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); } diff --git a/src/frontend/A64/decoder/a64.h b/src/frontend/A64/decoder/a64.h index 02349c94..ab18a7b2 100644 --- a/src/frontend/A64/decoder/a64.h +++ b/src/frontend/A64/decoder/a64.h @@ -201,10 +201,10 @@ std::vector> 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> 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"), diff --git a/src/frontend/A64/ir_emitter.cpp b/src/frontend/A64/ir_emitter.cpp index 3e389139..3a07bf74 100644 --- a/src/frontend/A64/ir_emitter.cpp +++ b/src/frontend/A64/ir_emitter.cpp @@ -38,6 +38,38 @@ void IREmitter::CallSupervisor(u32 imm) { Inst(Opcode::A64CallSupervisor, Imm32(imm)); } +IR::U8 IREmitter::ReadMemory8(const IR::U64& vaddr) { + return Inst(Opcode::A64ReadMemory8, vaddr); +} + +IR::U16 IREmitter::ReadMemory16(const IR::U64& vaddr) { + return Inst(Opcode::A64ReadMemory16, vaddr); +} + +IR::U32 IREmitter::ReadMemory32(const IR::U64& vaddr) { + return Inst(Opcode::A64ReadMemory32, vaddr); +} + +IR::U64 IREmitter::ReadMemory64(const IR::U64& vaddr) { + return Inst(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); diff --git a/src/frontend/A64/ir_emitter.h b/src/frontend/A64/ir_emitter.h index c99086b6..1111cc04 100644 --- a/src/frontend/A64/ir_emitter.h +++ b/src/frontend/A64/ir_emitter.h @@ -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(); diff --git a/src/frontend/A64/translate/impl/branch.cpp b/src/frontend/A64/translate/impl/branch.cpp index 59cb39ca..c3e89a1f 100644 --- a/src/frontend/A64/translate/impl/branch.cpp +++ b/src/frontend/A64/translate/impl/branch.cpp @@ -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(); - 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(); - auto operand1 = X(datasize, Rt); + IR::U32U64 operand1 = X(datasize, Rt); ir.SetCheckBit(ir.IsZero(operand1)); diff --git a/src/frontend/A64/translate/impl/data_processing_addsub.cpp b/src/frontend/A64/translate/impl/data_processing_addsub.cpp index 18110f80..947b61d8 100644 --- a/src/frontend/A64/translate/impl/data_processing_addsub.cpp +++ b/src/frontend/A64/translate/impl/data_processing_addsub.cpp @@ -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(); 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(); 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(); 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(); 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()); diff --git a/src/frontend/A64/translate/impl/impl.cpp b/src/frontend/A64/translate/impl/impl.cpp index 292bc2fc..0c932803 100644 --- a/src/frontend/A64/translate/impl/impl.cpp +++ b/src/frontend/A64/translate/impl/impl.cpp @@ -26,6 +26,11 @@ bool TranslatorVisitor::ReservedValue() { return false; } +bool TranslatorVisitor::UnallocatedEncoding() { + ASSERT_MSG(false, "UNALLOCATEDENCODING"); + return false; +} + boost::optional 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); diff --git a/src/frontend/A64/translate/impl/impl.h b/src/frontend/A64/translate/impl/impl.h index 81c84d91..9da6b990 100644 --- a/src/frontend/A64/translate/impl/impl.h +++ b/src/frontend/A64/translate/impl/impl.h @@ -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 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); diff --git a/src/frontend/A64/translate/impl/load_store_load_literal.cpp b/src/frontend/A64/translate/impl/load_store_load_literal.cpp new file mode 100644 index 00000000..36f61e5c --- /dev/null +++ b/src/frontend/A64/translate/impl/load_store_load_literal.cpp @@ -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(); + + 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(); + + 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(); + // u64 address = ir.PC() + offset; + // Prefetch(address, prfop); + return true; +} + +} // namespace A64 +} // namespace Dynarmic diff --git a/src/frontend/A64/translate/impl/load_store_register_immediate.cpp b/src/frontend/A64/translate/impl/load_store_register_immediate.cpp new file mode 100644 index 00000000..a0a32baa --- /dev/null +++ b/src/frontend/A64/translate/impl/load_store_register_immediate.cpp @@ -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(); + const u64 offset = imm9.SignExtend(); + + 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(); + const u64 offset = imm12.ZeroExtend() << 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(); + const u64 offset = imm9.SignExtend(); + + return load_store_register_immediate(wback, postindex, scale, offset, size, opc, Rn, Rt); +} + +} // namespace A64 +} // namespace Dynarmic diff --git a/src/frontend/ir/microinstruction.cpp b/src/frontend/ir/microinstruction.cpp index 3476f79d..f1eff458 100644 --- a/src/frontend/ir/microinstruction.cpp +++ b/src/frontend/ir/microinstruction.cpp @@ -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: diff --git a/src/frontend/ir/opcodes.inc b/src/frontend/ir/opcodes.inc index 9e14c411..af5055cf 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -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 )