From 56bc7825efc2b17ab688ba8f4317a9f97e091e22 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 4 Feb 2018 12:18:57 +0000 Subject: [PATCH] A64: Implement STR{,B,H} (register), LDR{,B,H,SB,SH,SW} (register), PFRM (register) --- src/CMakeLists.txt | 1 + src/frontend/A64/decoder/a64.inc | 12 +-- src/frontend/A64/translate/impl/impl.h | 12 +-- .../load_store_register_register_offset.cpp | 97 +++++++++++++++++++ 4 files changed, 102 insertions(+), 20 deletions(-) create mode 100644 src/frontend/A64/translate/impl/load_store_register_register_offset.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 176613f4..d145c153 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -83,6 +83,7 @@ add_library(dynarmic frontend/A64/translate/impl/load_store_multiple_structures.cpp frontend/A64/translate/impl/load_store_register_immediate.cpp frontend/A64/translate/impl/load_store_register_pair.cpp + frontend/A64/translate/impl/load_store_register_register_offset.cpp frontend/A64/translate/impl/load_store_register_unprivileged.cpp frontend/A64/translate/impl/move_wide.cpp frontend/A64/translate/impl/simd_aes.cpp diff --git a/src/frontend/A64/decoder/a64.inc b/src/frontend/A64/decoder/a64.inc index 38d04440..870c8247 100644 --- a/src/frontend/A64/decoder/a64.inc +++ b/src/frontend/A64/decoder/a64.inc @@ -239,18 +239,10 @@ INST(LDTRSW, "LDTRSW", "10111 //INST(LDAPR, "LDAPR", "1-11100010111111110000nnnnnttttt") // Loads and stores - Load/Store register (register offset) -//INST(STRB_reg, "STRB (register)", "00111000001mmmmmxxxS10nnnnnttttt") -//INST(LDRB_reg, "LDRB (register)", "00111000011mmmmmxxxS10nnnnnttttt") -//INST(LDRSB_reg, "LDRSB (register)", "001110001-1mmmmmxxxS10nnnnnttttt") +INST(STRx_reg, "STRx (register)", "zz111000o01mmmmmxxxS10nnnnnttttt") +INST(LDRx_reg, "LDRx (register)", "zz111000o11mmmmmxxxS10nnnnnttttt") //INST(STR_reg_fpsimd, "STR (register, SIMD&FP)", "zz111100-01mmmmmxxxS10nnnnnttttt") //INST(LDR_reg_fpsimd, "LDR (register, SIMD&FP)", "zz111100-11mmmmmxxxS10nnnnnttttt") -//INST(STRH_reg, "STRH (register)", "01111000001mmmmmxxxS10nnnnnttttt") -//INST(LDRH_reg, "LDRH (register)", "01111000011mmmmmxxxS10nnnnnttttt") -//INST(LDRSH_reg, "LDRSH (register)", "011110001-1mmmmmxxxS10nnnnnttttt") -//INST(STR_reg_gen, "STR (register)", "1-111000001mmmmmxxxS10nnnnnttttt") -//INST(LDR_reg_gen, "LDR (register)", "1-111000011mmmmmxxxS10nnnnnttttt") -//INST(LDRSW_reg, "LDRSW (register)", "10111000101mmmmmxxxS10nnnnnttttt") -//INST(PRFM_reg, "PRFM (register)", "11111000101mmmmmxxxS10nnnnnttttt") // Loads and stores - Load/Store register (pointer authentication) //INST(LDRA, "LDRAA, LDRAB", "11111000MS1iiiiiiiiiW1nnnnnttttt") diff --git a/src/frontend/A64/translate/impl/impl.h b/src/frontend/A64/translate/impl/impl.h index c2d81c7a..43dc4d82 100644 --- a/src/frontend/A64/translate/impl/impl.h +++ b/src/frontend/A64/translate/impl/impl.h @@ -293,18 +293,10 @@ struct TranslatorVisitor final { bool LDAPR(Reg Rn, Reg Rt); // Loads and stores - Load/Store register (register offset) - bool STRB_reg(Reg Rm, Imm<3> option, bool S, Reg Rn, Reg Rt); - bool LDRB_reg(Reg Rm, Imm<3> option, bool S, Reg Rn, Reg Rt); - bool LDRSB_reg(Reg Rm, Imm<3> option, bool S, Reg Rn, Reg Rt); + bool STRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn, Reg Rt); + bool LDRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn, Reg Rt); bool STR_reg_fpsimd(Imm<2> size, Reg Rm, Imm<3> option, bool S, Reg Rn, Vec Vt); bool LDR_reg_fpsimd(Imm<2> size, Reg Rm, Imm<3> option, bool S, Reg Rn, Vec Vt); - bool STRH_reg(Reg Rm, Imm<3> option, bool S, Reg Rn, Reg Rt); - bool LDRH_reg(Reg Rm, Imm<3> option, bool S, Reg Rn, Reg Rt); - bool LDRSH_reg(Reg Rm, Imm<3> option, bool S, Reg Rn, Reg Rt); - bool STR_reg_gen(Reg Rm, Imm<3> option, bool S, Reg Rn, Reg Rt); - bool LDR_reg_gen(Reg Rm, Imm<3> option, bool S, Reg Rn, Reg Rt); - bool LDRSW_reg(Reg Rm, Imm<3> option, bool S, Reg Rn, Reg Rt); - bool PRFM_reg(Reg Rm, Imm<3> option, bool S, Reg Rn, Reg Rt); // Loads and stores - Load/Store register (pointer authentication) bool LDRA(bool M, bool S, Imm<9> imm9, bool W, Reg Rn, Reg Rt); diff --git a/src/frontend/A64/translate/impl/load_store_register_register_offset.cpp b/src/frontend/A64/translate/impl/load_store_register_register_offset.cpp new file mode 100644 index 00000000..08742c58 --- /dev/null +++ b/src/frontend/A64/translate/impl/load_store_register_register_offset.cpp @@ -0,0 +1,97 @@ +/* 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::A64 { + +static bool SharedDecodeAndOperation(TranslatorVisitor& tv, IREmitter& ir, size_t scale, u8 shift, Imm<2> size, Imm<1> opc_1, Imm<1> opc_0, Reg Rm, Imm<3> option, Reg Rn, Reg Rt) { + // Shared Decode + + const AccType acctype = AccType::NORMAL; + MemOp memop; + size_t regsize = 64; + bool signed_ = false; + + if (opc_1 == 0) { + memop = opc_0 == 1 ? MemOp::LOAD : MemOp::STORE; + regsize = size == 0b11 ? 64 : 32; + signed_ = false; + } else if (size == 0b11) { + memop = MemOp::PREFETCH; + if (opc_0 == 1) { + return tv.UnallocatedEncoding(); + } + } else { + memop = MemOp::LOAD; + if (size == 0b10 && opc_0 == 1) { + return tv.UnallocatedEncoding(); + } + regsize = opc_0 == 1 ? 32 : 64; + signed_ = true; + } + + const size_t datasize = 8 << scale; + + // Operation + + const IR::U64 offset = tv.ExtendReg(64, Rm, option, shift); + + IR::U64 address; + if (Rn == Reg::SP) { + // TODO: Check SP alignment + address = tv.SP(64); + } else { + address = tv.X(64, Rn); + } + address = ir.Add(address, offset); + + switch (memop) { + case MemOp::STORE: { + IR::UAny data = tv.X(datasize, Rt); + tv.Mem(address, datasize / 8, acctype, data); + break; + } + case MemOp::LOAD: { + IR::UAny data = tv.Mem(address, datasize / 8, acctype); + if (signed_) { + tv.X(regsize, Rt, tv.SignExtend(data, regsize)); + } else { + tv.X(regsize, Rt, tv.ZeroExtend(data, regsize)); + } + break; + } + case MemOp::PREFETCH: + // TODO: Prefetch + break; + default: + UNREACHABLE(); + } + + return true; +} + +bool TranslatorVisitor::STRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn, Reg Rt) { + const Imm<1> opc_0{0}; + const size_t scale = size.ZeroExtend(); + const u8 shift = S ? static_cast(scale) : 0; + if (!option.Bit<1>()) { + return UnallocatedEncoding(); + } + return SharedDecodeAndOperation(*this, ir, scale, shift, size, opc_1, opc_0, Rm, option, Rn, Rt); +} + +bool TranslatorVisitor::LDRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn, Reg Rt) { + const Imm<1> opc_0{1}; + const size_t scale = size.ZeroExtend(); + const u8 shift = S ? static_cast(scale) : 0; + if (!option.Bit<1>()) { + return UnallocatedEncoding(); + } + return SharedDecodeAndOperation(*this, ir, scale, shift, size, opc_1, opc_0, Rm, option, Rn, Rt); +} + +} // namespace Dynarmic::A64