diff --git a/src/frontend/A64/decoder/a64.inc b/src/frontend/A64/decoder/a64.inc index ca54d39d..7dcc8f15 100644 --- a/src/frontend/A64/decoder/a64.inc +++ b/src/frontend/A64/decoder/a64.inc @@ -671,7 +671,7 @@ INST(ADDV, "ADDV", "0Q001 //INST(FMINNMV_2, "FMINNMV", "0Q1011101z110000110010nnnnnddddd") //INST(FMINV_1, "FMINV", "0Q00111010110000111110nnnnnddddd") //INST(FMINV_2, "FMINV", "0Q1011101z110000111110nnnnnddddd") -//INST(UADDLV, "UADDLV", "0Q101110zz110000001110nnnnnddddd") +INST(UADDLV, "UADDLV", "0Q101110zz110000001110nnnnnddddd") //INST(UMAXV, "UMAXV", "0Q101110zz110000101010nnnnnddddd") //INST(UMINV, "UMINV", "0Q101110zz110001101010nnnnnddddd") diff --git a/src/frontend/A64/translate/impl/simd_across_lanes.cpp b/src/frontend/A64/translate/impl/simd_across_lanes.cpp index dc9a0202..b172a1a4 100644 --- a/src/frontend/A64/translate/impl/simd_across_lanes.cpp +++ b/src/frontend/A64/translate/impl/simd_across_lanes.cpp @@ -39,4 +39,35 @@ bool TranslatorVisitor::ADDV(bool Q, Imm<2> size, Vec Vn, Vec Vd) { return true; } +bool TranslatorVisitor::UADDLV(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + if ((size == 0b10 && !Q) || size == 0b11) { + return ReservedValue(); + } + + const size_t esize = 8 << size.ZeroExtend(); + const size_t datasize = Q ? 128 : 64; + const size_t elements = datasize / esize; + + const IR::U128 operand = V(datasize, Vn); + + const auto get_element = [&](IR::U128 vec, size_t element) { + return ir.ZeroExtendToLong(ir.VectorGetElement(esize, vec, element)); + }; + + IR::U64 sum = get_element(operand, 0); + for (size_t i = 1; i < elements; i++) { + sum = ir.Add(sum, get_element(operand, i)); + } + + if (size == 0b00) { + V(datasize, Vd, ir.ZeroExtendToQuad(ir.LeastSignificantHalf(sum))); + } else if (size == 0b01) { + V(datasize, Vd, ir.ZeroExtendToQuad(ir.LeastSignificantWord(sum))); + } else { + V(datasize, Vd, ir.ZeroExtendToQuad(sum)); + } + + return true; +} + } // namespace Dynarmic::A64