1 /* This file is part of the dynarmic project.
2 * Copyright (c) 2016 MerryMage
3 * SPDX-License-Identifier: 0BSD
4 */
5
6 #include "common/bit_util.h"
7 #include "frontend/A32/translate/impl/translate_arm.h"
8
9 namespace Dynarmic::A32 {
10
11 // BFC<c> <Rd>, #<lsb>, #<width>
arm_BFC(Cond cond,Imm<5> msb,Reg d,Imm<5> lsb)12 bool ArmTranslatorVisitor::arm_BFC(Cond cond, Imm<5> msb, Reg d, Imm<5> lsb) {
13 if (d == Reg::PC) {
14 return UnpredictableInstruction();
15 }
16 if (msb < lsb) {
17 return UnpredictableInstruction();
18 }
19
20 if (!ConditionPassed(cond)) {
21 return true;
22 }
23
24 const u32 lsb_value = lsb.ZeroExtend();
25 const u32 msb_value = msb.ZeroExtend();
26 const u32 mask = ~(Common::Ones<u32>(msb_value - lsb_value + 1) << lsb_value);
27 const IR::U32 operand = ir.GetRegister(d);
28 const IR::U32 result = ir.And(operand, ir.Imm32(mask));
29
30 ir.SetRegister(d, result);
31 return true;
32 }
33
34 // BFI<c> <Rd>, <Rn>, #<lsb>, #<width>
arm_BFI(Cond cond,Imm<5> msb,Reg d,Imm<5> lsb,Reg n)35 bool ArmTranslatorVisitor::arm_BFI(Cond cond, Imm<5> msb, Reg d, Imm<5> lsb, Reg n) {
36 if (d == Reg::PC) {
37 return UnpredictableInstruction();
38 }
39 if (msb < lsb) {
40 return UnpredictableInstruction();
41 }
42
43 if (!ConditionPassed(cond)) {
44 return true;
45 }
46
47 const u32 lsb_value = lsb.ZeroExtend();
48 const u32 msb_value = msb.ZeroExtend();
49 const u32 inclusion_mask = Common::Ones<u32>(msb_value - lsb_value + 1) << lsb_value;
50 const u32 exclusion_mask = ~inclusion_mask;
51 const IR::U32 operand1 = ir.And(ir.GetRegister(d), ir.Imm32(exclusion_mask));
52 const IR::U32 operand2 = ir.And(ir.LogicalShiftLeft(ir.GetRegister(n), ir.Imm8(u8(lsb_value))), ir.Imm32(inclusion_mask));
53 const IR::U32 result = ir.Or(operand1, operand2);
54
55 ir.SetRegister(d, result);
56 return true;
57 }
58
59 // CLZ<c> <Rd>, <Rm>
arm_CLZ(Cond cond,Reg d,Reg m)60 bool ArmTranslatorVisitor::arm_CLZ(Cond cond, Reg d, Reg m) {
61 if (d == Reg::PC || m == Reg::PC) {
62 return UnpredictableInstruction();
63 }
64
65 if (!ConditionPassed(cond)) {
66 return true;
67 }
68
69 ir.SetRegister(d, ir.CountLeadingZeros(ir.GetRegister(m)));
70 return true;
71 }
72
73 // MOVT<c> <Rd>, #<imm16>
arm_MOVT(Cond cond,Imm<4> imm4,Reg d,Imm<12> imm12)74 bool ArmTranslatorVisitor::arm_MOVT(Cond cond, Imm<4> imm4, Reg d, Imm<12> imm12) {
75 if (d == Reg::PC) {
76 return UnpredictableInstruction();
77 }
78
79 if (!ConditionPassed(cond)) {
80 return true;
81 }
82
83 const IR::U32 imm16 = ir.Imm32(concatenate(imm4, imm12).ZeroExtend() << 16);
84 const IR::U32 operand = ir.GetRegister(d);
85 const IR::U32 result = ir.Or(ir.And(operand, ir.Imm32(0x0000FFFFU)), imm16);
86
87 ir.SetRegister(d, result);
88 return true;
89 }
90
arm_MOVW(Cond cond,Imm<4> imm4,Reg d,Imm<12> imm12)91 bool ArmTranslatorVisitor::arm_MOVW(Cond cond, Imm<4> imm4, Reg d, Imm<12> imm12) {
92 if (d == Reg::PC) {
93 return UnpredictableInstruction();
94 }
95
96 if (!ConditionPassed(cond)) {
97 return true;
98 }
99
100 const IR::U32 imm = ir.Imm32(concatenate(imm4, imm12).ZeroExtend());
101
102 ir.SetRegister(d, imm);
103 return true;
104 }
105
106 // SBFX<c> <Rd>, <Rn>, #<lsb>, #<width>
arm_SBFX(Cond cond,Imm<5> widthm1,Reg d,Imm<5> lsb,Reg n)107 bool ArmTranslatorVisitor::arm_SBFX(Cond cond, Imm<5> widthm1, Reg d, Imm<5> lsb, Reg n) {
108 if (d == Reg::PC || n == Reg::PC) {
109 return UnpredictableInstruction();
110 }
111
112 const u32 lsb_value = lsb.ZeroExtend();
113 const u32 widthm1_value = widthm1.ZeroExtend();
114 const u32 msb = lsb_value + widthm1_value;
115 if (msb >= Common::BitSize<u32>()) {
116 return UnpredictableInstruction();
117 }
118
119 if (!ConditionPassed(cond)) {
120 return true;
121 }
122
123 constexpr size_t max_width = Common::BitSize<u32>();
124 const u32 width = widthm1_value + 1;
125 const u8 left_shift_amount = static_cast<u8>(max_width - width - lsb_value);
126 const u8 right_shift_amount = static_cast<u8>(max_width - width);
127 const IR::U32 operand = ir.GetRegister(n);
128 const IR::U32 tmp = ir.LogicalShiftLeft(operand, ir.Imm8(left_shift_amount));
129 const IR::U32 result = ir.ArithmeticShiftRight(tmp, ir.Imm8(right_shift_amount));
130
131 ir.SetRegister(d, result);
132 return true;
133 }
134
135 // SEL<c> <Rd>, <Rn>, <Rm>
arm_SEL(Cond cond,Reg n,Reg d,Reg m)136 bool ArmTranslatorVisitor::arm_SEL(Cond cond, Reg n, Reg d, Reg m) {
137 if (n == Reg::PC || d == Reg::PC || m == Reg::PC) {
138 return UnpredictableInstruction();
139 }
140
141 if (!ConditionPassed(cond)) {
142 return true;
143 }
144
145 const auto to = ir.GetRegister(m);
146 const auto from = ir.GetRegister(n);
147 const auto result = ir.PackedSelect(ir.GetGEFlags(), to, from);
148
149 ir.SetRegister(d, result);
150 return true;
151 }
152
153 // UBFX<c> <Rd>, <Rn>, #<lsb>, #<width>
arm_UBFX(Cond cond,Imm<5> widthm1,Reg d,Imm<5> lsb,Reg n)154 bool ArmTranslatorVisitor::arm_UBFX(Cond cond, Imm<5> widthm1, Reg d, Imm<5> lsb, Reg n) {
155 if (d == Reg::PC || n == Reg::PC) {
156 return UnpredictableInstruction();
157 }
158
159 const u32 lsb_value = lsb.ZeroExtend();
160 const u32 widthm1_value = widthm1.ZeroExtend();
161 const u32 msb = lsb_value + widthm1_value;
162 if (msb >= Common::BitSize<u32>()) {
163 return UnpredictableInstruction();
164 }
165
166 if (!ConditionPassed(cond)) {
167 return true;
168 }
169
170 const IR::U32 operand = ir.GetRegister(n);
171 const IR::U32 mask = ir.Imm32(Common::Ones<u32>(widthm1_value + 1));
172 const IR::U32 result = ir.And(ir.LogicalShiftRight(operand, ir.Imm8(u8(lsb_value))), mask);
173
174 ir.SetRegister(d, result);
175 return true;
176 }
177
178 } // namespace Dynarmic::A32
179