blob: 92da92d7893d41f6c9a5f18d368cc869d27327af [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
57static inline ARM_ShifterType DecodeRegShift(const uint32_t type)
58{
59 switch (type) {
60 default:
61 assert(0 && "Invalid shift type");
62 case 0:
63 return SRType_LSL;
64 case 1:
65 return SRType_LSR;
66 case 2:
67 return SRType_ASR;
68 case 3:
69 return SRType_ROR;
70 }
71}
72
73static inline uint32_t LSL_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out)
74{
75 assert(amount > 0 && amount < 32);
76 carry_out = Bit32(value, 32 - amount);
77 return value << amount;
78}
79
80static inline uint32_t LSL(const uint32_t value, const uint32_t amount)
81{
82 assert(amount >= 0 && amount < 32);
83 if (amount == 0)
84 return value;
85 uint32_t dont_care;
86 return LSL_C(value, amount, dont_care);
87}
88
89static inline uint32_t LSR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out)
90{
91 assert(amount > 0 && amount <= 32);
92 carry_out = Bit32(value, amount - 1);
93 return value >> amount;
94}
95
96static inline uint32_t LSR(const uint32_t value, const uint32_t amount)
97{
98 assert(amount >= 0 && amount <= 32);
99 if (amount == 0)
100 return value;
101 uint32_t dont_care;
102 return LSR_C(value, amount, dont_care);
103}
104
105static inline uint32_t ASR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out)
106{
107 assert(amount > 0 && amount <= 32);
108 carry_out = Bit32(value, amount - 1);
109 int64_t extended = llvm::SignExtend64<32>(value);
110 return UnsignedBits(extended, amount + 31, amount);
111}
112
113static inline uint32_t ASR(const uint32_t value, const uint32_t amount)
114{
115 assert(amount >= 0 && amount <= 32);
116 if (amount == 0)
117 return value;
118 uint32_t dont_care;
119 return ASR_C(value, amount, dont_care);
120}
121
122static inline uint32_t ROR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out)
123{
124 assert(amount > 0 && amount < 32);
125 uint32_t result = Rotr32(value, amount);
126 carry_out = Bit32(value, 31);
127 return result;
128}
129
130static inline uint32_t ROR(const uint32_t value, const uint32_t amount)
131{
132 assert(amount >= 0 && amount < 32);
133 if (amount == 0)
134 return value;
135 uint32_t dont_care;
136 return ROR_C(value, amount, dont_care);
137}
138
139static inline uint32_t RRX_C(const uint32_t value, const uint32_t carry_in, uint32_t &carry_out)
140{
141 carry_out = Bit32(value, 0);
142 return Bit32(carry_in, 0) << 31 | Bits32(value, 31, 1);
143}
144
145static inline uint32_t RRX(const uint32_t value, const uint32_t carry_in)
146{
147 uint32_t dont_care;
148 return RRX_C(value, carry_in, dont_care);
149}
150
151static inline uint32_t Shift_C(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
152 const uint32_t carry_in, uint32_t &carry_out)
153{
154 assert(type != SRType_RRX || amount == 1);
155 if (amount == 0)
156 {
157 carry_out = carry_in;
158 return value;
159 }
160 uint32_t result;
161 switch (type) {
162 case SRType_LSL:
163 result = LSL_C(value, amount, carry_out);
164 break;
165 case SRType_LSR:
166 result = LSR_C(value, amount, carry_out);
167 break;
168 case SRType_ASR:
169 result = ASR_C(value, amount, carry_out);
170 break;
171 case SRType_ROR:
172 result = ROR_C(value, amount, carry_out);
173 break;
174 case SRType_RRX:
175 result = RRX_C(value, amount, carry_out);
176 break;
177 }
178 return result;
179}
180
181static inline uint32_t Shift(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
182 const uint32_t carry_in)
183{
184 // Don't care about carry out in this case.
185 uint32_t dont_care;
186 return Shift_C(value, type, amount, carry_in, dont_care);
187}
188
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000189static inline uint32_t bits(const uint32_t val, const uint32_t msbit, const uint32_t lsbit)
190{
Johnny Chen108d5aa2011-01-26 01:00:55 +0000191 return Bits32(val, msbit, lsbit);
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000192}
193
194static inline uint32_t bit(const uint32_t val, const uint32_t msbit)
195{
196 return bits(val, msbit, msbit);
197}
198
Johnny Chen60c0d622011-01-25 23:49:39 +0000199static uint32_t ror(uint32_t val, uint32_t N, uint32_t shift)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000200{
Johnny Chen60c0d622011-01-25 23:49:39 +0000201 uint32_t m = shift % N;
202 return (val >> m) | (val << (N - m));
203}
204
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000205// (imm32, carry_out) = ARMExpandImm_C(imm12, carry_in)
206static inline uint32_t ARMExpandImm_C(uint32_t val, uint32_t carry_in, uint32_t &carry_out)
207{
208 uint32_t imm32; // the expanded result
209 uint32_t imm = bits(val, 7, 0); // immediate value
210 uint32_t amt = 2 * bits(val, 11, 8); // rotate amount
211 if (amt == 0)
212 {
213 imm32 = imm;
214 carry_out = carry_in;
215 }
216 else
217 {
218 imm32 = ror(imm, 32, amt);
219 carry_out = Bit32(imm32, 31);
220 }
221 return imm32;
222}
223
Johnny Chen60c0d622011-01-25 23:49:39 +0000224static inline uint32_t ARMExpandImm(uint32_t val)
225{
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000226 // 'carry_in' argument to following function call does not affect the imm32 result.
227 uint32_t carry_in = 0;
228 uint32_t carry_out;
229 return ARMExpandImm_C(val, carry_in, carry_out);
230}
231
232// (imm32, carry_out) = ThumbExpandImm_C(imm12, carry_in)
233static inline uint32_t ThumbExpandImm_C(uint32_t val, uint32_t carry_in, uint32_t &carry_out)
234{
Johnny Chen3e9a41c2011-02-14 19:09:36 +0000235 uint32_t imm32; // the expaned result
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000236 const uint32_t i = bit(val, 26);
237 const uint32_t imm3 = bits(val, 14, 12);
238 const uint32_t abcdefgh = bits(val, 7, 0);
239 const uint32_t imm12 = i << 11 | imm3 << 8 | abcdefgh;
240
241 if (bits(imm12, 11, 10) == 0)
242 {
243 switch (bits(imm12, 8, 9)) {
244 case 0:
245 imm32 = abcdefgh;
246 break;
247
248 case 1:
249 imm32 = abcdefgh << 16 | abcdefgh;
250 break;
251
252 case 2:
253 imm32 = abcdefgh << 24 | abcdefgh << 8;
254 break;
255
256 case 3:
257 imm32 = abcdefgh << 24 | abcdefgh << 16 | abcdefgh << 8 | abcdefgh;
258 break;
259 }
260 carry_out = carry_in;
261 }
262 else
263 {
264 const uint32_t unrotated_value = 0x80 | bits(imm12, 6, 0);
265 imm32 = ror(unrotated_value, 32, bits(imm12, 11, 7));
266 carry_out = Bit32(imm32, 31);
267 }
268 return imm32;
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000269}
270
Johnny Chen60c0d622011-01-25 23:49:39 +0000271static inline uint32_t ThumbExpandImm(uint32_t val)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000272{
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000273 // 'carry_in' argument to following function call does not affect the imm32 result.
274 uint32_t carry_in = 0;
275 uint32_t carry_out;
276 return ThumbExpandImm_C(val, carry_in, carry_out);
Johnny Chen60c0d622011-01-25 23:49:39 +0000277}
278
279// imm32 = ZeroExtend(i:imm3:imm8, 32)
280static inline uint32_t ThumbImm12(uint32_t val)
281{
282 const uint32_t i = bit(val, 26);
283 const uint32_t imm3 = bits(val, 14, 12);
284 const uint32_t imm8 = bits(val, 7, 0);
285 const uint32_t imm12 = i << 11 | imm3 << 8 | imm8;
286 return imm12;
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000287}
288
Johnny Chene4455022011-01-26 00:08:59 +0000289// imm32 = ZeroExtend(imm7:'00', 32)
290static inline uint32_t ThumbImmScaled(uint32_t val)
291{
292 const uint32_t imm7 = bits(val, 6, 0);
293 return imm7 * 4;
294}
295
Johnny Chen4baf2e32011-01-24 18:24:53 +0000296// This function performs the check for the register numbers 13 and 15 that are
297// not permitted for many Thumb register specifiers.
298static inline bool BadReg(uint32_t n) { return n == 13 || n == 15; }
299
Johnny Chen4baf2e32011-01-24 18:24:53 +0000300} // namespace lldb_private
301
302#endif // lldb_ARMUtils_h_