blob: a41ef72f6c4ce92c9aa9fb7cb6733319aa71ad47 [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 Chen108d5aa2011-01-26 01:00:55 +000013#include "InstructionUtils.h"
Johnny Chen0d771a22011-02-15 17:52:22 +000014#include "llvm/Support/MathExtras.h" // for SignExtend64 template function
Johnny Chen108d5aa2011-01-26 01:00:55 +000015
Johnny Chenc3b5bc32011-01-24 19:50:30 +000016// Common utilities for the ARM/Thumb Instruction Set Architecture.
Johnny Chen4baf2e32011-01-24 18:24:53 +000017
18namespace lldb_private {
19
Johnny Chen0d771a22011-02-15 17:52:22 +000020typedef enum
21{
22 SRType_LSL,
23 SRType_LSR,
24 SRType_ASR,
25 SRType_ROR,
26 SRType_RRX
27} ARM_ShifterType;
28
29static inline uint32_t DecodeImmShift(const uint32_t type, const uint32_t imm5, ARM_ShifterType &shift_t)
30{
31 switch (type) {
32 default:
33 assert(0 && "Invalid shift type");
34 case 0:
35 shift_t = SRType_LSL;
36 return imm5;
37 case 1:
38 shift_t = SRType_LSR;
39 return (imm5 == 0 ? 32 : imm5);
40 case 2:
41 shift_t = SRType_ASR;
42 return (imm5 == 0 ? 32 : imm5);
43 case 3:
44 if (imm5 == 0)
45 {
46 shift_t = SRType_RRX;
47 return 1;
48 }
49 else
50 {
51 shift_t = SRType_ROR;
52 return imm5;
53 }
54 }
55}
56
Johnny Chen82f16aa2011-02-15 20:10:55 +000057static inline uint32_t DecodeImmShift(const ARM_ShifterType shift_t, const uint32_t imm5)
58{
59 ARM_ShifterType dont_care;
60 return DecodeImmShift(shift_t, imm5, dont_care);
61}
62
Johnny Chen0d771a22011-02-15 17:52:22 +000063static inline ARM_ShifterType DecodeRegShift(const uint32_t type)
64{
65 switch (type) {
66 default:
67 assert(0 && "Invalid shift type");
68 case 0:
69 return SRType_LSL;
70 case 1:
71 return SRType_LSR;
72 case 2:
73 return SRType_ASR;
74 case 3:
75 return SRType_ROR;
76 }
77}
78
79static inline uint32_t LSL_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out)
80{
81 assert(amount > 0 && amount < 32);
82 carry_out = Bit32(value, 32 - amount);
83 return value << amount;
84}
85
86static inline uint32_t LSL(const uint32_t value, const uint32_t amount)
87{
88 assert(amount >= 0 && amount < 32);
89 if (amount == 0)
90 return value;
91 uint32_t dont_care;
92 return LSL_C(value, amount, dont_care);
93}
94
95static inline uint32_t LSR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out)
96{
97 assert(amount > 0 && amount <= 32);
98 carry_out = Bit32(value, amount - 1);
99 return value >> amount;
100}
101
102static inline uint32_t LSR(const uint32_t value, const uint32_t amount)
103{
104 assert(amount >= 0 && amount <= 32);
105 if (amount == 0)
106 return value;
107 uint32_t dont_care;
108 return LSR_C(value, amount, dont_care);
109}
110
111static inline uint32_t ASR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out)
112{
113 assert(amount > 0 && amount <= 32);
114 carry_out = Bit32(value, amount - 1);
115 int64_t extended = llvm::SignExtend64<32>(value);
116 return UnsignedBits(extended, amount + 31, amount);
117}
118
119static inline uint32_t ASR(const uint32_t value, const uint32_t amount)
120{
121 assert(amount >= 0 && amount <= 32);
122 if (amount == 0)
123 return value;
124 uint32_t dont_care;
125 return ASR_C(value, amount, dont_care);
126}
127
128static inline uint32_t ROR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out)
129{
130 assert(amount > 0 && amount < 32);
131 uint32_t result = Rotr32(value, amount);
132 carry_out = Bit32(value, 31);
133 return result;
134}
135
136static inline uint32_t ROR(const uint32_t value, const uint32_t amount)
137{
138 assert(amount >= 0 && amount < 32);
139 if (amount == 0)
140 return value;
141 uint32_t dont_care;
142 return ROR_C(value, amount, dont_care);
143}
144
145static inline uint32_t RRX_C(const uint32_t value, const uint32_t carry_in, uint32_t &carry_out)
146{
147 carry_out = Bit32(value, 0);
148 return Bit32(carry_in, 0) << 31 | Bits32(value, 31, 1);
149}
150
151static inline uint32_t RRX(const uint32_t value, const uint32_t carry_in)
152{
153 uint32_t dont_care;
154 return RRX_C(value, carry_in, dont_care);
155}
156
157static inline uint32_t Shift_C(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
158 const uint32_t carry_in, uint32_t &carry_out)
159{
160 assert(type != SRType_RRX || amount == 1);
161 if (amount == 0)
162 {
163 carry_out = carry_in;
164 return value;
165 }
166 uint32_t result;
167 switch (type) {
168 case SRType_LSL:
169 result = LSL_C(value, amount, carry_out);
170 break;
171 case SRType_LSR:
172 result = LSR_C(value, amount, carry_out);
173 break;
174 case SRType_ASR:
175 result = ASR_C(value, amount, carry_out);
176 break;
177 case SRType_ROR:
178 result = ROR_C(value, amount, carry_out);
179 break;
180 case SRType_RRX:
181 result = RRX_C(value, amount, carry_out);
182 break;
183 }
184 return result;
185}
186
187static inline uint32_t Shift(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
188 const uint32_t carry_in)
189{
190 // Don't care about carry out in this case.
191 uint32_t dont_care;
192 return Shift_C(value, type, amount, carry_in, dont_care);
193}
194
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000195static inline uint32_t bits(const uint32_t val, const uint32_t msbit, const uint32_t lsbit)
196{
Johnny Chen108d5aa2011-01-26 01:00:55 +0000197 return Bits32(val, msbit, lsbit);
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000198}
199
200static inline uint32_t bit(const uint32_t val, const uint32_t msbit)
201{
202 return bits(val, msbit, msbit);
203}
204
Johnny Chen60c0d622011-01-25 23:49:39 +0000205static uint32_t ror(uint32_t val, uint32_t N, uint32_t shift)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000206{
Johnny Chen60c0d622011-01-25 23:49:39 +0000207 uint32_t m = shift % N;
208 return (val >> m) | (val << (N - m));
209}
210
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000211// (imm32, carry_out) = ARMExpandImm_C(imm12, carry_in)
212static inline uint32_t ARMExpandImm_C(uint32_t val, uint32_t carry_in, uint32_t &carry_out)
213{
214 uint32_t imm32; // the expanded result
215 uint32_t imm = bits(val, 7, 0); // immediate value
216 uint32_t amt = 2 * bits(val, 11, 8); // rotate amount
217 if (amt == 0)
218 {
219 imm32 = imm;
220 carry_out = carry_in;
221 }
222 else
223 {
224 imm32 = ror(imm, 32, amt);
225 carry_out = Bit32(imm32, 31);
226 }
227 return imm32;
228}
229
Johnny Chen60c0d622011-01-25 23:49:39 +0000230static inline uint32_t ARMExpandImm(uint32_t val)
231{
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000232 // 'carry_in' argument to following function call does not affect the imm32 result.
233 uint32_t carry_in = 0;
234 uint32_t carry_out;
235 return ARMExpandImm_C(val, carry_in, carry_out);
236}
237
238// (imm32, carry_out) = ThumbExpandImm_C(imm12, carry_in)
239static inline uint32_t ThumbExpandImm_C(uint32_t val, uint32_t carry_in, uint32_t &carry_out)
240{
Johnny Chen3e9a41c2011-02-14 19:09:36 +0000241 uint32_t imm32; // the expaned result
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000242 const uint32_t i = bit(val, 26);
243 const uint32_t imm3 = bits(val, 14, 12);
244 const uint32_t abcdefgh = bits(val, 7, 0);
245 const uint32_t imm12 = i << 11 | imm3 << 8 | abcdefgh;
246
247 if (bits(imm12, 11, 10) == 0)
248 {
249 switch (bits(imm12, 8, 9)) {
250 case 0:
251 imm32 = abcdefgh;
252 break;
253
254 case 1:
255 imm32 = abcdefgh << 16 | abcdefgh;
256 break;
257
258 case 2:
259 imm32 = abcdefgh << 24 | abcdefgh << 8;
260 break;
261
262 case 3:
263 imm32 = abcdefgh << 24 | abcdefgh << 16 | abcdefgh << 8 | abcdefgh;
264 break;
265 }
266 carry_out = carry_in;
267 }
268 else
269 {
270 const uint32_t unrotated_value = 0x80 | bits(imm12, 6, 0);
271 imm32 = ror(unrotated_value, 32, bits(imm12, 11, 7));
272 carry_out = Bit32(imm32, 31);
273 }
274 return imm32;
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000275}
276
Johnny Chen60c0d622011-01-25 23:49:39 +0000277static inline uint32_t ThumbExpandImm(uint32_t val)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000278{
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000279 // 'carry_in' argument to following function call does not affect the imm32 result.
280 uint32_t carry_in = 0;
281 uint32_t carry_out;
282 return ThumbExpandImm_C(val, carry_in, carry_out);
Johnny Chen60c0d622011-01-25 23:49:39 +0000283}
284
285// imm32 = ZeroExtend(i:imm3:imm8, 32)
286static inline uint32_t ThumbImm12(uint32_t val)
287{
288 const uint32_t i = bit(val, 26);
289 const uint32_t imm3 = bits(val, 14, 12);
290 const uint32_t imm8 = bits(val, 7, 0);
291 const uint32_t imm12 = i << 11 | imm3 << 8 | imm8;
292 return imm12;
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000293}
294
Johnny Chene4455022011-01-26 00:08:59 +0000295// imm32 = ZeroExtend(imm7:'00', 32)
296static inline uint32_t ThumbImmScaled(uint32_t val)
297{
298 const uint32_t imm7 = bits(val, 6, 0);
299 return imm7 * 4;
300}
301
Johnny Chen4baf2e32011-01-24 18:24:53 +0000302// This function performs the check for the register numbers 13 and 15 that are
303// not permitted for many Thumb register specifiers.
304static inline bool BadReg(uint32_t n) { return n == 13 || n == 15; }
305
Johnny Chen4baf2e32011-01-24 18:24:53 +0000306} // namespace lldb_private
307
308#endif // lldb_ARMUtils_h_