blob: 093fe3bbf85eb757cb99538b4c4f50c5d3efe7e3 [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 Chen7c677ac2011-02-17 17:31:08 +000021static inline uint32_t Align(uint32_t val, uint32_t alignment)
22{
23 return alignment * (val / alignment);
24}
25
Johnny Chen0d771a22011-02-15 17:52:22 +000026static inline uint32_t DecodeImmShift(const uint32_t type, const uint32_t imm5, ARM_ShifterType &shift_t)
27{
28 switch (type) {
29 default:
30 assert(0 && "Invalid shift type");
31 case 0:
32 shift_t = SRType_LSL;
33 return imm5;
34 case 1:
35 shift_t = SRType_LSR;
36 return (imm5 == 0 ? 32 : imm5);
37 case 2:
38 shift_t = SRType_ASR;
39 return (imm5 == 0 ? 32 : imm5);
40 case 3:
41 if (imm5 == 0)
42 {
43 shift_t = SRType_RRX;
44 return 1;
45 }
46 else
47 {
48 shift_t = SRType_ROR;
49 return imm5;
50 }
51 }
52}
53
Johnny Chen3dd06052011-02-22 21:17:52 +000054// A8.6.35 CMP (register) -- Encoding T3
55// Convenience function.
56static inline uint32_t DecodeImmShiftThumb(const uint32_t opcode, ARM_ShifterType &shift_t)
57{
58 return DecodeImmShift(Bits32(opcode, 5, 4), Bits32(opcode, 14, 12)<<2 | Bits32(opcode, 7, 6), shift_t);
59}
60
61// A8.6.35 CMP (register) -- Encoding A1
62// Convenience function.
63static inline uint32_t DecodeImmShiftARM(const uint32_t opcode, ARM_ShifterType &shift_t)
64{
65 return DecodeImmShift(Bits32(opcode, 6, 5), Bits32(opcode, 11, 7), shift_t);
66}
67
Johnny Chen82f16aa2011-02-15 20:10:55 +000068static inline uint32_t DecodeImmShift(const ARM_ShifterType shift_t, const uint32_t imm5)
69{
70 ARM_ShifterType dont_care;
71 return DecodeImmShift(shift_t, imm5, dont_care);
72}
73
Johnny Chen0d771a22011-02-15 17:52:22 +000074static inline ARM_ShifterType DecodeRegShift(const uint32_t type)
75{
76 switch (type) {
77 default:
78 assert(0 && "Invalid shift type");
79 case 0:
80 return SRType_LSL;
81 case 1:
82 return SRType_LSR;
83 case 2:
84 return SRType_ASR;
85 case 3:
86 return SRType_ROR;
87 }
88}
89
90static inline uint32_t LSL_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out)
91{
Johnny Chen0fa98ca2011-02-15 22:21:33 +000092 assert(amount > 0);
93 carry_out = amount <= 32 ? Bit32(value, 32 - amount) : 0;
Johnny Chen0d771a22011-02-15 17:52:22 +000094 return value << amount;
95}
96
97static inline uint32_t LSL(const uint32_t value, const uint32_t amount)
98{
Johnny Chen0fa98ca2011-02-15 22:21:33 +000099 assert(amount >= 0);
Johnny Chen0d771a22011-02-15 17:52:22 +0000100 if (amount == 0)
101 return value;
102 uint32_t dont_care;
103 return LSL_C(value, amount, dont_care);
104}
105
106static inline uint32_t LSR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out)
107{
Johnny Chen0fa98ca2011-02-15 22:21:33 +0000108 assert(amount > 0);
109 carry_out = amount <= 32 ? Bit32(value, amount - 1) : 0;
Johnny Chen0d771a22011-02-15 17:52:22 +0000110 return value >> amount;
111}
112
113static inline uint32_t LSR(const uint32_t value, const uint32_t amount)
114{
Johnny Chen0fa98ca2011-02-15 22:21:33 +0000115 assert(amount >= 0);
Johnny Chen0d771a22011-02-15 17:52:22 +0000116 if (amount == 0)
117 return value;
118 uint32_t dont_care;
119 return LSR_C(value, amount, dont_care);
120}
121
122static inline uint32_t ASR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out)
123{
124 assert(amount > 0 && amount <= 32);
Johnny Chen0fa98ca2011-02-15 22:21:33 +0000125 bool negative = BitIsSet(value, 31);
126 if (amount <= 32)
127 {
128 carry_out = Bit32(value, amount - 1);
129 int64_t extended = llvm::SignExtend64<32>(value);
130 return UnsignedBits(extended, amount + 31, amount);
131 }
132 else
133 {
134 carry_out = (negative ? 1 : 0);
135 return (negative ? 0xffffffff : 0);
136 }
Johnny Chen0d771a22011-02-15 17:52:22 +0000137}
138
139static inline uint32_t ASR(const uint32_t value, const uint32_t amount)
140{
Johnny Chen0fa98ca2011-02-15 22:21:33 +0000141 assert(amount >= 0);
Johnny Chen0d771a22011-02-15 17:52:22 +0000142 if (amount == 0)
143 return value;
144 uint32_t dont_care;
145 return ASR_C(value, amount, dont_care);
146}
147
148static inline uint32_t ROR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out)
149{
Johnny Chen0fa98ca2011-02-15 22:21:33 +0000150 assert(amount > 0);
151 uint32_t amt = amount % 32;
152 uint32_t result = Rotr32(value, amt);
Johnny Chen0d771a22011-02-15 17:52:22 +0000153 carry_out = Bit32(value, 31);
154 return result;
155}
156
157static inline uint32_t ROR(const uint32_t value, const uint32_t amount)
158{
Johnny Chen0fa98ca2011-02-15 22:21:33 +0000159 assert(amount >= 0);
Johnny Chen0d771a22011-02-15 17:52:22 +0000160 if (amount == 0)
161 return value;
162 uint32_t dont_care;
163 return ROR_C(value, amount, dont_care);
164}
165
166static inline uint32_t RRX_C(const uint32_t value, const uint32_t carry_in, uint32_t &carry_out)
167{
168 carry_out = Bit32(value, 0);
169 return Bit32(carry_in, 0) << 31 | Bits32(value, 31, 1);
170}
171
172static inline uint32_t RRX(const uint32_t value, const uint32_t carry_in)
173{
174 uint32_t dont_care;
175 return RRX_C(value, carry_in, dont_care);
176}
177
178static inline uint32_t Shift_C(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
179 const uint32_t carry_in, uint32_t &carry_out)
180{
181 assert(type != SRType_RRX || amount == 1);
182 if (amount == 0)
183 {
184 carry_out = carry_in;
185 return value;
186 }
187 uint32_t result;
188 switch (type) {
189 case SRType_LSL:
190 result = LSL_C(value, amount, carry_out);
191 break;
192 case SRType_LSR:
193 result = LSR_C(value, amount, carry_out);
194 break;
195 case SRType_ASR:
196 result = ASR_C(value, amount, carry_out);
197 break;
198 case SRType_ROR:
199 result = ROR_C(value, amount, carry_out);
200 break;
201 case SRType_RRX:
Johnny Cheneeab4852011-02-16 22:14:44 +0000202 result = RRX_C(value, carry_in, carry_out);
Johnny Chen0d771a22011-02-15 17:52:22 +0000203 break;
204 }
205 return result;
206}
207
208static inline uint32_t Shift(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
209 const uint32_t carry_in)
210{
211 // Don't care about carry out in this case.
212 uint32_t dont_care;
213 return Shift_C(value, type, amount, carry_in, dont_care);
214}
215
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000216static inline uint32_t bits(const uint32_t val, const uint32_t msbit, const uint32_t lsbit)
217{
Johnny Chen108d5aa2011-01-26 01:00:55 +0000218 return Bits32(val, msbit, lsbit);
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000219}
220
221static inline uint32_t bit(const uint32_t val, const uint32_t msbit)
222{
223 return bits(val, msbit, msbit);
224}
225
Johnny Chen60c0d622011-01-25 23:49:39 +0000226static uint32_t ror(uint32_t val, uint32_t N, uint32_t shift)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000227{
Johnny Chen60c0d622011-01-25 23:49:39 +0000228 uint32_t m = shift % N;
229 return (val >> m) | (val << (N - m));
230}
231
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000232// (imm32, carry_out) = ARMExpandImm_C(imm12, carry_in)
Johnny Chen3dd06052011-02-22 21:17:52 +0000233static inline uint32_t ARMExpandImm_C(uint32_t opcode, uint32_t carry_in, uint32_t &carry_out)
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000234{
Johnny Chen3dd06052011-02-22 21:17:52 +0000235 uint32_t imm32; // the expanded result
236 uint32_t imm = bits(opcode, 7, 0); // immediate value
237 uint32_t amt = 2 * bits(opcode, 11, 8); // rotate amount
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000238 if (amt == 0)
239 {
240 imm32 = imm;
241 carry_out = carry_in;
242 }
243 else
244 {
245 imm32 = ror(imm, 32, amt);
246 carry_out = Bit32(imm32, 31);
247 }
248 return imm32;
249}
250
Johnny Chen3dd06052011-02-22 21:17:52 +0000251static inline uint32_t ARMExpandImm(uint32_t opcode)
Johnny Chen60c0d622011-01-25 23:49:39 +0000252{
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000253 // 'carry_in' argument to following function call does not affect the imm32 result.
254 uint32_t carry_in = 0;
255 uint32_t carry_out;
Johnny Chen3dd06052011-02-22 21:17:52 +0000256 return ARMExpandImm_C(opcode, carry_in, carry_out);
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000257}
258
259// (imm32, carry_out) = ThumbExpandImm_C(imm12, carry_in)
Johnny Chen3dd06052011-02-22 21:17:52 +0000260static inline uint32_t ThumbExpandImm_C(uint32_t opcode, uint32_t carry_in, uint32_t &carry_out)
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000261{
Johnny Chen3e9a41c2011-02-14 19:09:36 +0000262 uint32_t imm32; // the expaned result
Johnny Chen3dd06052011-02-22 21:17:52 +0000263 const uint32_t i = bit(opcode, 26);
264 const uint32_t imm3 = bits(opcode, 14, 12);
265 const uint32_t abcdefgh = bits(opcode, 7, 0);
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000266 const uint32_t imm12 = i << 11 | imm3 << 8 | abcdefgh;
267
268 if (bits(imm12, 11, 10) == 0)
269 {
270 switch (bits(imm12, 8, 9)) {
271 case 0:
272 imm32 = abcdefgh;
273 break;
274
275 case 1:
276 imm32 = abcdefgh << 16 | abcdefgh;
277 break;
278
279 case 2:
280 imm32 = abcdefgh << 24 | abcdefgh << 8;
281 break;
282
283 case 3:
284 imm32 = abcdefgh << 24 | abcdefgh << 16 | abcdefgh << 8 | abcdefgh;
285 break;
286 }
287 carry_out = carry_in;
288 }
289 else
290 {
291 const uint32_t unrotated_value = 0x80 | bits(imm12, 6, 0);
292 imm32 = ror(unrotated_value, 32, bits(imm12, 11, 7));
293 carry_out = Bit32(imm32, 31);
294 }
295 return imm32;
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000296}
297
Johnny Chen3dd06052011-02-22 21:17:52 +0000298static inline uint32_t ThumbExpandImm(uint32_t opcode)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000299{
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000300 // 'carry_in' argument to following function call does not affect the imm32 result.
301 uint32_t carry_in = 0;
302 uint32_t carry_out;
Johnny Chen3dd06052011-02-22 21:17:52 +0000303 return ThumbExpandImm_C(opcode, carry_in, carry_out);
Johnny Chen60c0d622011-01-25 23:49:39 +0000304}
305
306// imm32 = ZeroExtend(i:imm3:imm8, 32)
Johnny Chen3dd06052011-02-22 21:17:52 +0000307static inline uint32_t ThumbImm12(uint32_t opcode)
Johnny Chen60c0d622011-01-25 23:49:39 +0000308{
Johnny Chen3dd06052011-02-22 21:17:52 +0000309 const uint32_t i = bit(opcode, 26);
310 const uint32_t imm3 = bits(opcode, 14, 12);
311 const uint32_t imm8 = bits(opcode, 7, 0);
Johnny Chen60c0d622011-01-25 23:49:39 +0000312 const uint32_t imm12 = i << 11 | imm3 << 8 | imm8;
313 return imm12;
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000314}
315
Johnny Chene4455022011-01-26 00:08:59 +0000316// imm32 = ZeroExtend(imm7:'00', 32)
Johnny Chen3dd06052011-02-22 21:17:52 +0000317static inline uint32_t ThumbImmScaled(uint32_t opcode)
Johnny Chene4455022011-01-26 00:08:59 +0000318{
Johnny Chen3dd06052011-02-22 21:17:52 +0000319 const uint32_t imm7 = bits(opcode, 6, 0);
Johnny Chene4455022011-01-26 00:08:59 +0000320 return imm7 * 4;
321}
322
Johnny Chen4baf2e32011-01-24 18:24:53 +0000323// This function performs the check for the register numbers 13 and 15 that are
324// not permitted for many Thumb register specifiers.
325static inline bool BadReg(uint32_t n) { return n == 13 || n == 15; }
326
Johnny Chen4baf2e32011-01-24 18:24:53 +0000327} // namespace lldb_private
328
329#endif // lldb_ARMUtils_h_