blob: 53a04bb06b70834ffd5d4710db29a993cbd54220 [file] [log] [blame]
Johnny Chen4baf2e32011-01-24 18:24:53 +00001//===-- lldb_ARMUtils.h -----------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef lldb_ARMUtils_h_
11#define lldb_ARMUtils_h_
12
Johnny Chen41a0a152011-02-16 01:27:54 +000013#include "ARMDefines.h"
Johnny Chen108d5aa2011-01-26 01:00:55 +000014#include "InstructionUtils.h"
Johnny Chen0d771a22011-02-15 17:52:22 +000015#include "llvm/Support/MathExtras.h" // for SignExtend64 template function
Johnny Chen108d5aa2011-01-26 01:00:55 +000016
Johnny Chenc3b5bc32011-01-24 19:50:30 +000017// Common utilities for the ARM/Thumb Instruction Set Architecture.
Johnny Chen4baf2e32011-01-24 18:24:53 +000018
19namespace lldb_private {
20
Johnny Chen0d771a22011-02-15 17:52:22 +000021static inline uint32_t DecodeImmShift(const uint32_t type, const uint32_t imm5, ARM_ShifterType &shift_t)
22{
23 switch (type) {
24 default:
25 assert(0 && "Invalid shift type");
26 case 0:
27 shift_t = SRType_LSL;
28 return imm5;
29 case 1:
30 shift_t = SRType_LSR;
31 return (imm5 == 0 ? 32 : imm5);
32 case 2:
33 shift_t = SRType_ASR;
34 return (imm5 == 0 ? 32 : imm5);
35 case 3:
36 if (imm5 == 0)
37 {
38 shift_t = SRType_RRX;
39 return 1;
40 }
41 else
42 {
43 shift_t = SRType_ROR;
44 return imm5;
45 }
46 }
47}
48
Johnny Chen82f16aa2011-02-15 20:10:55 +000049static inline uint32_t DecodeImmShift(const ARM_ShifterType shift_t, const uint32_t imm5)
50{
51 ARM_ShifterType dont_care;
52 return DecodeImmShift(shift_t, imm5, dont_care);
53}
54
Johnny Chen0d771a22011-02-15 17:52:22 +000055static inline ARM_ShifterType DecodeRegShift(const uint32_t type)
56{
57 switch (type) {
58 default:
59 assert(0 && "Invalid shift type");
60 case 0:
61 return SRType_LSL;
62 case 1:
63 return SRType_LSR;
64 case 2:
65 return SRType_ASR;
66 case 3:
67 return SRType_ROR;
68 }
69}
70
71static inline uint32_t LSL_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out)
72{
Johnny Chen0fa98ca2011-02-15 22:21:33 +000073 assert(amount > 0);
74 carry_out = amount <= 32 ? Bit32(value, 32 - amount) : 0;
Johnny Chen0d771a22011-02-15 17:52:22 +000075 return value << amount;
76}
77
78static inline uint32_t LSL(const uint32_t value, const uint32_t amount)
79{
Johnny Chen0fa98ca2011-02-15 22:21:33 +000080 assert(amount >= 0);
Johnny Chen0d771a22011-02-15 17:52:22 +000081 if (amount == 0)
82 return value;
83 uint32_t dont_care;
84 return LSL_C(value, amount, dont_care);
85}
86
87static inline uint32_t LSR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out)
88{
Johnny Chen0fa98ca2011-02-15 22:21:33 +000089 assert(amount > 0);
90 carry_out = amount <= 32 ? Bit32(value, amount - 1) : 0;
Johnny Chen0d771a22011-02-15 17:52:22 +000091 return value >> amount;
92}
93
94static inline uint32_t LSR(const uint32_t value, const uint32_t amount)
95{
Johnny Chen0fa98ca2011-02-15 22:21:33 +000096 assert(amount >= 0);
Johnny Chen0d771a22011-02-15 17:52:22 +000097 if (amount == 0)
98 return value;
99 uint32_t dont_care;
100 return LSR_C(value, amount, dont_care);
101}
102
103static inline uint32_t ASR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out)
104{
105 assert(amount > 0 && amount <= 32);
Johnny Chen0fa98ca2011-02-15 22:21:33 +0000106 bool negative = BitIsSet(value, 31);
107 if (amount <= 32)
108 {
109 carry_out = Bit32(value, amount - 1);
110 int64_t extended = llvm::SignExtend64<32>(value);
111 return UnsignedBits(extended, amount + 31, amount);
112 }
113 else
114 {
115 carry_out = (negative ? 1 : 0);
116 return (negative ? 0xffffffff : 0);
117 }
Johnny Chen0d771a22011-02-15 17:52:22 +0000118}
119
120static inline uint32_t ASR(const uint32_t value, const uint32_t amount)
121{
Johnny Chen0fa98ca2011-02-15 22:21:33 +0000122 assert(amount >= 0);
Johnny Chen0d771a22011-02-15 17:52:22 +0000123 if (amount == 0)
124 return value;
125 uint32_t dont_care;
126 return ASR_C(value, amount, dont_care);
127}
128
129static inline uint32_t ROR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out)
130{
Johnny Chen0fa98ca2011-02-15 22:21:33 +0000131 assert(amount > 0);
132 uint32_t amt = amount % 32;
133 uint32_t result = Rotr32(value, amt);
Johnny Chen0d771a22011-02-15 17:52:22 +0000134 carry_out = Bit32(value, 31);
135 return result;
136}
137
138static inline uint32_t ROR(const uint32_t value, const uint32_t amount)
139{
Johnny Chen0fa98ca2011-02-15 22:21:33 +0000140 assert(amount >= 0);
Johnny Chen0d771a22011-02-15 17:52:22 +0000141 if (amount == 0)
142 return value;
143 uint32_t dont_care;
144 return ROR_C(value, amount, dont_care);
145}
146
147static inline uint32_t RRX_C(const uint32_t value, const uint32_t carry_in, uint32_t &carry_out)
148{
149 carry_out = Bit32(value, 0);
150 return Bit32(carry_in, 0) << 31 | Bits32(value, 31, 1);
151}
152
153static inline uint32_t RRX(const uint32_t value, const uint32_t carry_in)
154{
155 uint32_t dont_care;
156 return RRX_C(value, carry_in, dont_care);
157}
158
159static inline uint32_t Shift_C(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
160 const uint32_t carry_in, uint32_t &carry_out)
161{
162 assert(type != SRType_RRX || amount == 1);
163 if (amount == 0)
164 {
165 carry_out = carry_in;
166 return value;
167 }
168 uint32_t result;
169 switch (type) {
170 case SRType_LSL:
171 result = LSL_C(value, amount, carry_out);
172 break;
173 case SRType_LSR:
174 result = LSR_C(value, amount, carry_out);
175 break;
176 case SRType_ASR:
177 result = ASR_C(value, amount, carry_out);
178 break;
179 case SRType_ROR:
180 result = ROR_C(value, amount, carry_out);
181 break;
182 case SRType_RRX:
183 result = RRX_C(value, amount, carry_out);
184 break;
185 }
186 return result;
187}
188
189static inline uint32_t Shift(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
190 const uint32_t carry_in)
191{
192 // Don't care about carry out in this case.
193 uint32_t dont_care;
194 return Shift_C(value, type, amount, carry_in, dont_care);
195}
196
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000197static inline uint32_t bits(const uint32_t val, const uint32_t msbit, const uint32_t lsbit)
198{
Johnny Chen108d5aa2011-01-26 01:00:55 +0000199 return Bits32(val, msbit, lsbit);
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000200}
201
202static inline uint32_t bit(const uint32_t val, const uint32_t msbit)
203{
204 return bits(val, msbit, msbit);
205}
206
Johnny Chen60c0d622011-01-25 23:49:39 +0000207static uint32_t ror(uint32_t val, uint32_t N, uint32_t shift)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000208{
Johnny Chen60c0d622011-01-25 23:49:39 +0000209 uint32_t m = shift % N;
210 return (val >> m) | (val << (N - m));
211}
212
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000213// (imm32, carry_out) = ARMExpandImm_C(imm12, carry_in)
214static inline uint32_t ARMExpandImm_C(uint32_t val, uint32_t carry_in, uint32_t &carry_out)
215{
216 uint32_t imm32; // the expanded result
217 uint32_t imm = bits(val, 7, 0); // immediate value
218 uint32_t amt = 2 * bits(val, 11, 8); // rotate amount
219 if (amt == 0)
220 {
221 imm32 = imm;
222 carry_out = carry_in;
223 }
224 else
225 {
226 imm32 = ror(imm, 32, amt);
227 carry_out = Bit32(imm32, 31);
228 }
229 return imm32;
230}
231
Johnny Chen60c0d622011-01-25 23:49:39 +0000232static inline uint32_t ARMExpandImm(uint32_t val)
233{
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000234 // 'carry_in' argument to following function call does not affect the imm32 result.
235 uint32_t carry_in = 0;
236 uint32_t carry_out;
237 return ARMExpandImm_C(val, carry_in, carry_out);
238}
239
240// (imm32, carry_out) = ThumbExpandImm_C(imm12, carry_in)
241static inline uint32_t ThumbExpandImm_C(uint32_t val, uint32_t carry_in, uint32_t &carry_out)
242{
Johnny Chen3e9a41c2011-02-14 19:09:36 +0000243 uint32_t imm32; // the expaned result
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000244 const uint32_t i = bit(val, 26);
245 const uint32_t imm3 = bits(val, 14, 12);
246 const uint32_t abcdefgh = bits(val, 7, 0);
247 const uint32_t imm12 = i << 11 | imm3 << 8 | abcdefgh;
248
249 if (bits(imm12, 11, 10) == 0)
250 {
251 switch (bits(imm12, 8, 9)) {
252 case 0:
253 imm32 = abcdefgh;
254 break;
255
256 case 1:
257 imm32 = abcdefgh << 16 | abcdefgh;
258 break;
259
260 case 2:
261 imm32 = abcdefgh << 24 | abcdefgh << 8;
262 break;
263
264 case 3:
265 imm32 = abcdefgh << 24 | abcdefgh << 16 | abcdefgh << 8 | abcdefgh;
266 break;
267 }
268 carry_out = carry_in;
269 }
270 else
271 {
272 const uint32_t unrotated_value = 0x80 | bits(imm12, 6, 0);
273 imm32 = ror(unrotated_value, 32, bits(imm12, 11, 7));
274 carry_out = Bit32(imm32, 31);
275 }
276 return imm32;
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000277}
278
Johnny Chen60c0d622011-01-25 23:49:39 +0000279static inline uint32_t ThumbExpandImm(uint32_t val)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000280{
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000281 // 'carry_in' argument to following function call does not affect the imm32 result.
282 uint32_t carry_in = 0;
283 uint32_t carry_out;
284 return ThumbExpandImm_C(val, carry_in, carry_out);
Johnny Chen60c0d622011-01-25 23:49:39 +0000285}
286
287// imm32 = ZeroExtend(i:imm3:imm8, 32)
288static inline uint32_t ThumbImm12(uint32_t val)
289{
290 const uint32_t i = bit(val, 26);
291 const uint32_t imm3 = bits(val, 14, 12);
292 const uint32_t imm8 = bits(val, 7, 0);
293 const uint32_t imm12 = i << 11 | imm3 << 8 | imm8;
294 return imm12;
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000295}
296
Johnny Chene4455022011-01-26 00:08:59 +0000297// imm32 = ZeroExtend(imm7:'00', 32)
298static inline uint32_t ThumbImmScaled(uint32_t val)
299{
300 const uint32_t imm7 = bits(val, 6, 0);
301 return imm7 * 4;
302}
303
Johnny Chen4baf2e32011-01-24 18:24:53 +0000304// This function performs the check for the register numbers 13 and 15 that are
305// not permitted for many Thumb register specifiers.
306static inline bool BadReg(uint32_t n) { return n == 13 || n == 15; }
307
Johnny Chen4baf2e32011-01-24 18:24:53 +0000308} // namespace lldb_private
309
310#endif // lldb_ARMUtils_h_