1 /* This file is part of the dynarmic project.
2 * Copyright (c) 2020 MerryMage
3 * SPDX-License-Identifier: 0BSD
4 */
5
6 #include "common/bit_util.h"
7
8 #include "frontend/A32/translate/impl/translate_arm.h"
9
10 namespace Dynarmic::A32 {
11
asimd_VCLS(bool D,size_t sz,size_t Vd,bool Q,bool M,size_t Vm)12 bool ArmTranslatorVisitor::asimd_VCLS(bool D, size_t sz, size_t Vd, bool Q, bool M, size_t Vm) {
13 if (sz == 0b11) {
14 return UndefinedInstruction();
15 }
16
17 if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vm))) {
18 return UndefinedInstruction();
19 }
20
21 const auto d = ToVector(Q, Vd, D);
22 const auto m = ToVector(Q, Vm, M);
23 const auto result = [this, m, sz] {
24 const auto reg_m = ir.GetVector(m);
25 const size_t esize = 8U << sz;
26 const auto shifted = ir.VectorArithmeticShiftRight(esize, reg_m, static_cast<u8>(esize));
27 const auto xored = ir.VectorEor(reg_m, shifted);
28 const auto clz = ir.VectorCountLeadingZeros(esize, xored);
29 return ir.VectorSub(esize, clz, ir.VectorBroadcast(esize, I(esize, 1)));
30 }();
31
32 ir.SetVector(d, result);
33 return true;
34 }
35
asimd_VCLZ(bool D,size_t sz,size_t Vd,bool Q,bool M,size_t Vm)36 bool ArmTranslatorVisitor::asimd_VCLZ(bool D, size_t sz, size_t Vd, bool Q, bool M, size_t Vm) {
37 if (sz == 0b11) {
38 return UndefinedInstruction();
39 }
40
41 if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vm))) {
42 return UndefinedInstruction();
43 }
44
45 const auto d = ToVector(Q, Vd, D);
46 const auto m = ToVector(Q, Vm, M);
47 const auto result = [this, m, sz] {
48 const auto reg_m = ir.GetVector(m);
49 const size_t esize = 8U << sz;
50
51 return ir.VectorCountLeadingZeros(esize, reg_m);
52 }();
53
54 ir.SetVector(d, result);
55 return true;
56 }
57
asimd_VCNT(bool D,size_t sz,size_t Vd,bool Q,bool M,size_t Vm)58 bool ArmTranslatorVisitor::asimd_VCNT(bool D, size_t sz, size_t Vd, bool Q, bool M, size_t Vm) {
59 if (sz != 0b00) {
60 return UndefinedInstruction();
61 }
62
63 if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vm))) {
64 return UndefinedInstruction();
65 }
66
67 const auto d = ToVector(Q, Vd, D);
68 const auto m = ToVector(Q, Vm, M);
69 const auto reg_m = ir.GetVector(m);
70 const auto result = ir.VectorPopulationCount(reg_m);
71
72 ir.SetVector(d, result);
73 return true;
74 }
75
asimd_VNEG(bool D,size_t sz,size_t Vd,bool F,bool Q,bool M,size_t Vm)76 bool ArmTranslatorVisitor::asimd_VNEG(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) {
77 if (sz == 0b11 || (F && sz != 0b10)) {
78 return UndefinedInstruction();
79 }
80
81 if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vm))) {
82 return UndefinedInstruction();
83 }
84
85 const auto d = ToVector(Q, Vd, D);
86 const auto m = ToVector(Q, Vm, M);
87 const auto result = [this, F, m, sz] {
88 const auto reg_m = ir.GetVector(m);
89
90 if (F) {
91 return ir.FPVectorNeg(32, reg_m);
92 }
93
94 const size_t esize = 8U << sz;
95 return ir.VectorSub(esize, ir.ZeroVector(), reg_m);
96 }();
97
98 ir.SetVector(d, result);
99 return true;
100 }
101
asimd_VSWP(bool D,size_t Vd,bool Q,bool M,size_t Vm)102 bool ArmTranslatorVisitor::asimd_VSWP(bool D, size_t Vd, bool Q, bool M, size_t Vm) {
103 if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vm))) {
104 return UndefinedInstruction();
105 }
106
107 // Swapping the same register results in the same contents.
108 const auto d = ToVector(Q, Vd, D);
109 const auto m = ToVector(Q, Vm, M);
110 if (d == m) {
111 return true;
112 }
113
114 if (Q) {
115 const auto reg_d = ir.GetVector(d);
116 const auto reg_m = ir.GetVector(m);
117
118 ir.SetVector(m, reg_d);
119 ir.SetVector(d, reg_m);
120 } else {
121 const auto reg_d = ir.GetExtendedRegister(d);
122 const auto reg_m = ir.GetExtendedRegister(m);
123
124 ir.SetExtendedRegister(m, reg_d);
125 ir.SetExtendedRegister(d, reg_m);
126 }
127
128 return true;
129 }
130 } // namespace Dynarmic::A32
131