diff --git a/src/frontend/A64/decoder/a64.inc b/src/frontend/A64/decoder/a64.inc index ae85b9e8..3fdb39fa 100644 --- a/src/frontend/A64/decoder/a64.inc +++ b/src/frontend/A64/decoder/a64.inc @@ -515,7 +515,7 @@ INST(USRA_1, "USRA", "01111 // Data Processing - FP and SIMD - SIMD Permute //INST(UZP1, "UZP1", "0Q001110zz0mmmmm000110nnnnnddddd") -//INST(TRN1, "TRN1", "0Q001110zz0mmmmm001010nnnnnddddd") +INST(TRN1, "TRN1", "0Q001110zz0mmmmm001010nnnnnddddd") INST(ZIP1, "ZIP1", "0Q001110zz0mmmmm001110nnnnnddddd") //INST(UZP2, "UZP2", "0Q001110zz0mmmmm010110nnnnnddddd") //INST(TRN2, "TRN2", "0Q001110zz0mmmmm011010nnnnnddddd") diff --git a/src/frontend/A64/translate/impl/simd_permute.cpp b/src/frontend/A64/translate/impl/simd_permute.cpp index 6bea5a30..921b06b1 100644 --- a/src/frontend/A64/translate/impl/simd_permute.cpp +++ b/src/frontend/A64/translate/impl/simd_permute.cpp @@ -8,6 +8,42 @@ namespace Dynarmic::A64 { +bool TranslatorVisitor::TRN1(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + if (!Q && size == 0b11) { + return ReservedValue(); + } + + const size_t datasize = Q ? 128 : 64; + const size_t esize = 8 << size.ZeroExtend(); + + const IR::U128 m = V(datasize, Vm); + const IR::U128 n = V(datasize, Vn); + + const IR::U128 result = [&] { + switch (esize) { + case 8: + case 16: + case 32: { + // Create a mask of elements we care about (e.g. for 8-bit 0x00FF00FF00FF00FF) + const u64 mask_element = Common::Ones(esize); + const u64 mask_value = Common::Replicate(mask_element, esize * 2); + + const IR::U128 mask = ir.VectorBroadcast(64, I(64, mask_value)); + const IR::U128 anded_m = ir.VectorAnd(m, mask); + const IR::U128 anded_n = ir.VectorAnd(n, mask); + return ir.VectorOr(ir.VectorLogicalShiftLeft(esize * 2, anded_m, esize), anded_n); + } + case 64: { + default: + return ir.VectorSetElement(esize, n, 1, ir.VectorGetElement(esize, m, 0)); + } + } + }(); + + V(datasize, Vd, result); + return true; +} + bool TranslatorVisitor::ZIP1(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { if (size == 0b11 && !Q) { return ReservedValue();