blob: 457cbaa0c9143a38cff39acf94aa79df04df34e2 [file] [log] [blame]
Greg Clayton64c84432011-01-21 22:02:52 +00001//===-- EmulateInstructionARM.cpp -------------------------------*- 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#include "EmulateInstructionARM.h"
Greg Clayton8482ded2011-02-01 00:04:43 +000011#include "lldb/Core/ConstString.h"
12
Johnny Chen8584c922011-01-26 01:18:52 +000013#include "ARMDefines.h"
Johnny Chen4baf2e32011-01-24 18:24:53 +000014#include "ARMUtils.h"
Greg Clayton8482ded2011-02-01 00:04:43 +000015#include "ARM_DWARF_Registers.h"
Johnny Chen9b8d7832011-02-02 01:13:56 +000016#include "llvm/Support/MathExtras.h" // for SignExtend32 template function
Greg Clayton64c84432011-01-21 22:02:52 +000017
18using namespace lldb;
19using namespace lldb_private;
20
21// ARM constants used during decoding
22#define REG_RD 0
23#define LDM_REGLIST 1
24#define PC_REG 15
25#define PC_REGLIST_BIT 0x8000
26
Johnny Chen251af6a2011-01-21 22:47:25 +000027#define ARMv4 (1u << 0)
Greg Clayton64c84432011-01-21 22:02:52 +000028#define ARMv4T (1u << 1)
29#define ARMv5T (1u << 2)
30#define ARMv5TE (1u << 3)
31#define ARMv5TEJ (1u << 4)
Johnny Chen251af6a2011-01-21 22:47:25 +000032#define ARMv6 (1u << 5)
Greg Clayton64c84432011-01-21 22:02:52 +000033#define ARMv6K (1u << 6)
34#define ARMv6T2 (1u << 7)
Johnny Chen251af6a2011-01-21 22:47:25 +000035#define ARMv7 (1u << 8)
Johnny Chen60c0d622011-01-25 23:49:39 +000036#define ARMv8 (1u << 9)
Greg Clayton64c84432011-01-21 22:02:52 +000037#define ARMvAll (0xffffffffu)
38
Johnny Chen9b8d7832011-02-02 01:13:56 +000039#define ARMV4T_ABOVE (ARMv4T|ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv8)
40#define ARMV5_ABOVE (ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv8)
41#define ARMV6T2_ABOVE (ARMv6T2|ARMv7|ARMv8)
Greg Clayton64c84432011-01-21 22:02:52 +000042
Greg Clayton2b8e8b02011-02-01 00:49:32 +000043void
44EmulateInstructionARM::Initialize ()
Johnny Chen7dc60e12011-01-24 19:46:32 +000045{
Greg Clayton2b8e8b02011-02-01 00:49:32 +000046}
Johnny Chen7dc60e12011-01-24 19:46:32 +000047
Greg Clayton2b8e8b02011-02-01 00:49:32 +000048void
49EmulateInstructionARM::Terminate ()
Greg Clayton64c84432011-01-21 22:02:52 +000050{
Greg Clayton2b8e8b02011-02-01 00:49:32 +000051}
52
Greg Clayton64c84432011-01-21 22:02:52 +000053
Johnny Chen08c25e82011-01-31 18:02:28 +000054// Push Multiple Registers stores multiple registers to the stack, storing to
55// consecutive memory locations ending just below the address in SP, and updates
56// SP to point to the start of the stored data.
Greg Clayton2b8e8b02011-02-01 00:49:32 +000057bool
58EmulateInstructionARM::EmulatePush (ARMEncoding encoding)
Greg Clayton64c84432011-01-21 22:02:52 +000059{
60#if 0
61 // ARM pseudo code...
62 if (ConditionPassed())
63 {
64 EncodingSpecificOperations();
65 NullCheckIfThumbEE(13);
66 address = SP - 4*BitCount(registers);
67
68 for (i = 0 to 14)
69 {
70 if (registers<i> == 1’)
71 {
72 if i == 13 && i != LowestSetBit(registers) // Only possible for encoding A1
73 MemA[address,4] = bits(32) UNKNOWN;
74 else
75 MemA[address,4] = R[i];
76 address = address + 4;
77 }
78 }
79
80 if (registers<15> == 1’) // Only possible for encoding A1 or A2
81 MemA[address,4] = PCStoreValue();
82
83 SP = SP - 4*BitCount(registers);
84 }
85#endif
86
87 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +000088 const uint32_t opcode = OpcodeAsUnsigned (&success);
Greg Clayton64c84432011-01-21 22:02:52 +000089 if (!success)
90 return false;
91
Greg Clayton2b8e8b02011-02-01 00:49:32 +000092 if (ConditionPassed())
Greg Clayton64c84432011-01-21 22:02:52 +000093 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +000094 const uint32_t addr_byte_size = GetAddressByteSize();
95 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Greg Clayton64c84432011-01-21 22:02:52 +000096 if (!success)
97 return false;
Johnny Chen3c75c762011-01-22 00:47:08 +000098 uint32_t registers = 0;
Johnny Chen91d99862011-01-25 19:07:04 +000099 uint32_t Rt; // the source register
Johnny Chen3c75c762011-01-22 00:47:08 +0000100 switch (encoding) {
Johnny Chenaedde1c2011-01-24 20:38:45 +0000101 case eEncodingT1:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000102 registers = Bits32(opcode, 7, 0);
Johnny Chenaedde1c2011-01-24 20:38:45 +0000103 // The M bit represents LR.
Johnny Chen108d5aa2011-01-26 01:00:55 +0000104 if (Bits32(opcode, 8, 8))
Johnny Chenef85e912011-01-31 23:07:40 +0000105 registers |= (1u << 14);
Johnny Chenaedde1c2011-01-24 20:38:45 +0000106 // if BitCount(registers) < 1 then UNPREDICTABLE;
107 if (BitCount(registers) < 1)
108 return false;
109 break;
Johnny Chen7dc60e12011-01-24 19:46:32 +0000110 case eEncodingT2:
111 // Ignore bits 15 & 13.
Johnny Chen108d5aa2011-01-26 01:00:55 +0000112 registers = Bits32(opcode, 15, 0) & ~0xa000;
Johnny Chen7dc60e12011-01-24 19:46:32 +0000113 // if BitCount(registers) < 2 then UNPREDICTABLE;
114 if (BitCount(registers) < 2)
115 return false;
116 break;
117 case eEncodingT3:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000118 Rt = Bits32(opcode, 15, 12);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000119 // if BadReg(t) then UNPREDICTABLE;
Johnny Chen91d99862011-01-25 19:07:04 +0000120 if (BadReg(Rt))
Johnny Chen7dc60e12011-01-24 19:46:32 +0000121 return false;
Johnny Chen91d99862011-01-25 19:07:04 +0000122 registers = (1u << Rt);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000123 break;
Johnny Chen3c75c762011-01-22 00:47:08 +0000124 case eEncodingA1:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000125 registers = Bits32(opcode, 15, 0);
Johnny Chena33d4842011-01-24 22:25:48 +0000126 // Instead of return false, let's handle the following case as well,
127 // which amounts to pushing one reg onto the full descending stacks.
128 // if BitCount(register_list) < 2 then SEE STMDB / STMFD;
Johnny Chen3c75c762011-01-22 00:47:08 +0000129 break;
130 case eEncodingA2:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000131 Rt = Bits32(opcode, 15, 12);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000132 // if t == 13 then UNPREDICTABLE;
Johnny Chen91d99862011-01-25 19:07:04 +0000133 if (Rt == dwarf_sp)
Johnny Chen3c75c762011-01-22 00:47:08 +0000134 return false;
Johnny Chen91d99862011-01-25 19:07:04 +0000135 registers = (1u << Rt);
Johnny Chen3c75c762011-01-22 00:47:08 +0000136 break;
Johnny Chence1ca772011-01-25 01:13:00 +0000137 default:
138 return false;
Johnny Chen3c75c762011-01-22 00:47:08 +0000139 }
Johnny Chence1ca772011-01-25 01:13:00 +0000140 addr_t sp_offset = addr_byte_size * BitCount (registers);
Greg Clayton64c84432011-01-21 22:02:52 +0000141 addr_t addr = sp - sp_offset;
142 uint32_t i;
143
144 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
145 for (i=0; i<15; ++i)
146 {
Johnny Chen108d5aa2011-01-26 01:00:55 +0000147 if (BitIsSet (registers, 1u << i))
Greg Clayton64c84432011-01-21 22:02:52 +0000148 {
149 context.arg1 = dwarf_r0 + i; // arg1 in the context is the DWARF register number
150 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000151 uint32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
Greg Clayton64c84432011-01-21 22:02:52 +0000152 if (!success)
153 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000154 if (!WriteMemoryUnsigned (context, addr, reg_value, addr_byte_size))
Greg Clayton64c84432011-01-21 22:02:52 +0000155 return false;
156 addr += addr_byte_size;
157 }
158 }
159
Johnny Chen108d5aa2011-01-26 01:00:55 +0000160 if (BitIsSet (registers, 1u << 15))
Greg Clayton64c84432011-01-21 22:02:52 +0000161 {
162 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
Johnny Chen3c75c762011-01-22 00:47:08 +0000163 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000164 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Greg Clayton64c84432011-01-21 22:02:52 +0000165 if (!success)
166 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000167 if (!WriteMemoryUnsigned (context, addr, pc + 8, addr_byte_size))
Greg Clayton64c84432011-01-21 22:02:52 +0000168 return false;
169 }
170
171 context.type = EmulateInstruction::eContextAdjustStackPointer;
172 context.arg0 = eRegisterKindGeneric;
173 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +0000174 context.arg2 = -sp_offset;
Greg Clayton64c84432011-01-21 22:02:52 +0000175
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000176 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
Greg Clayton64c84432011-01-21 22:02:52 +0000177 return false;
178 }
179 return true;
180}
181
Johnny Chenef85e912011-01-31 23:07:40 +0000182// Pop Multiple Registers loads multiple registers from the stack, loading from
183// consecutive memory locations staring at the address in SP, and updates
184// SP to point just above the loaded data.
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000185bool
186EmulateInstructionARM::EmulatePop (ARMEncoding encoding)
Johnny Chenef85e912011-01-31 23:07:40 +0000187{
188#if 0
189 // ARM pseudo code...
190 if (ConditionPassed())
191 {
192 EncodingSpecificOperations(); NullCheckIfThumbEE(13);
193 address = SP;
194 for i = 0 to 14
195 if registers<i> == 1 then
196 R[i} = if UnalignedAllowed then MemU[address,4] else MemA[address,4]; address = address + 4;
197 if registers<15> == 1 then
198 if UnalignedAllowed then
199 LoadWritePC(MemU[address,4]);
200 else
201 LoadWritePC(MemA[address,4]);
202 if registers<13> == 0 then SP = SP + 4*BitCount(registers);
203 if registers<13> == 1 then SP = bits(32) UNKNOWN;
204 }
205#endif
206
207 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000208 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chenef85e912011-01-31 23:07:40 +0000209 if (!success)
210 return false;
211
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000212 if (ConditionPassed())
Johnny Chenef85e912011-01-31 23:07:40 +0000213 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000214 const uint32_t addr_byte_size = GetAddressByteSize();
215 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chenef85e912011-01-31 23:07:40 +0000216 if (!success)
217 return false;
218 uint32_t registers = 0;
219 uint32_t Rt; // the destination register
220 switch (encoding) {
221 case eEncodingT1:
222 registers = Bits32(opcode, 7, 0);
223 // The P bit represents PC.
224 if (Bits32(opcode, 8, 8))
225 registers |= (1u << 15);
226 // if BitCount(registers) < 1 then UNPREDICTABLE;
227 if (BitCount(registers) < 1)
228 return false;
229 break;
230 case eEncodingT2:
231 // Ignore bit 13.
232 registers = Bits32(opcode, 15, 0) & ~0x2000;
233 // if BitCount(registers) < 2 || (P == '1' && M == '1') then UNPREDICTABLE;
234 if (BitCount(registers) < 2 || (Bits32(opcode, 15, 15) && Bits32(opcode, 14, 14)))
235 return false;
236 break;
237 case eEncodingT3:
238 Rt = Bits32(opcode, 15, 12);
239 // if t == 13 || (t == 15 && InITBlock() && !LastInITBlock()) then UNPREDICTABLE;
240 if (Rt == dwarf_sp)
241 return false;
242 registers = (1u << Rt);
243 break;
244 case eEncodingA1:
245 registers = Bits32(opcode, 15, 0);
246 // Instead of return false, let's handle the following case as well,
247 // which amounts to popping one reg from the full descending stacks.
248 // if BitCount(register_list) < 2 then SEE LDM / LDMIA / LDMFD;
249
250 // if registers<13> == ‘1’ && ArchVersion() >= 7 then UNPREDICTABLE;
251 if (Bits32(opcode, 13, 13))
252 return false;
253 break;
254 case eEncodingA2:
255 Rt = Bits32(opcode, 15, 12);
256 // if t == 13 then UNPREDICTABLE;
257 if (Rt == dwarf_sp)
258 return false;
259 registers = (1u << Rt);
260 break;
261 default:
262 return false;
263 }
264 addr_t sp_offset = addr_byte_size * BitCount (registers);
265 addr_t addr = sp;
266 uint32_t i, data;
267
268 EmulateInstruction::Context context = { EmulateInstruction::eContextPopRegisterOffStack, eRegisterKindDWARF, 0, 0 };
269 for (i=0; i<15; ++i)
270 {
271 if (BitIsSet (registers, 1u << i))
272 {
273 context.arg1 = dwarf_r0 + i; // arg1 in the context is the DWARF register number
274 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000275 data = ReadMemoryUnsigned(context, addr, 4, 0, &success);
Johnny Chenef85e912011-01-31 23:07:40 +0000276 if (!success)
277 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000278 if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, context.arg1, data))
Johnny Chenef85e912011-01-31 23:07:40 +0000279 return false;
280 addr += addr_byte_size;
281 }
282 }
283
284 if (BitIsSet (registers, 1u << 15))
285 {
286 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
287 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000288 data = ReadMemoryUnsigned(context, addr, 4, 0, &success);
Johnny Chenef85e912011-01-31 23:07:40 +0000289 if (!success)
290 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000291 if (!WriteRegisterUnsigned(context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, data))
Johnny Chenef85e912011-01-31 23:07:40 +0000292 return false;
293 addr += addr_byte_size;
294 }
295
296 context.type = EmulateInstruction::eContextAdjustStackPointer;
297 context.arg0 = eRegisterKindGeneric;
298 context.arg1 = LLDB_REGNUM_GENERIC_SP;
299 context.arg2 = sp_offset;
300
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000301 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp + sp_offset))
Johnny Chenef85e912011-01-31 23:07:40 +0000302 return false;
303 }
304 return true;
305}
306
Johnny Chen5b442b72011-01-27 19:34:30 +0000307// Set r7 or ip to point to saved value residing within the stack.
Johnny Chenbcec3af2011-01-27 01:26:19 +0000308// ADD (SP plus immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000309bool
310EmulateInstructionARM::EmulateAddRdSPImmediate (ARMEncoding encoding)
Johnny Chenbcec3af2011-01-27 01:26:19 +0000311{
312#if 0
313 // ARM pseudo code...
314 if (ConditionPassed())
315 {
316 EncodingSpecificOperations();
317 (result, carry, overflow) = AddWithCarry(SP, imm32, 0’);
318 if d == 15 then
319 ALUWritePC(result); // setflags is always FALSE here
320 else
321 R[d] = result;
322 if setflags then
323 APSR.N = result<31>;
324 APSR.Z = IsZeroBit(result);
325 APSR.C = carry;
326 APSR.V = overflow;
327 }
328#endif
329
330 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000331 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chenbcec3af2011-01-27 01:26:19 +0000332 if (!success)
333 return false;
334
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000335 if (ConditionPassed())
Johnny Chenbcec3af2011-01-27 01:26:19 +0000336 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000337 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chenbcec3af2011-01-27 01:26:19 +0000338 if (!success)
339 return false;
340 uint32_t Rd; // the destination register
341 uint32_t imm32;
342 switch (encoding) {
343 case eEncodingT1:
344 Rd = 7;
345 imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32)
346 break;
347 case eEncodingA1:
348 Rd = Bits32(opcode, 15, 12);
349 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
350 break;
351 default:
352 return false;
353 }
354 addr_t sp_offset = imm32;
355 addr_t addr = sp + sp_offset; // a pointer to the stack area
356
357 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
358 eRegisterKindGeneric,
359 LLDB_REGNUM_GENERIC_SP,
360 sp_offset };
361
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000362 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, addr))
Johnny Chenbcec3af2011-01-27 01:26:19 +0000363 return false;
364 }
365 return true;
366}
367
Johnny Chen2ccad832011-01-28 19:57:25 +0000368// Set r7 or ip to the current stack pointer.
369// MOV (register)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000370bool
371EmulateInstructionARM::EmulateMovRdSP (ARMEncoding encoding)
Johnny Chen2ccad832011-01-28 19:57:25 +0000372{
373#if 0
374 // ARM pseudo code...
375 if (ConditionPassed())
376 {
377 EncodingSpecificOperations();
378 result = R[m];
379 if d == 15 then
380 ALUWritePC(result); // setflags is always FALSE here
381 else
382 R[d] = result;
383 if setflags then
384 APSR.N = result<31>;
385 APSR.Z = IsZeroBit(result);
386 // APSR.C unchanged
387 // APSR.V unchanged
388 }
389#endif
390
391 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000392 //const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen1c13b622011-01-29 00:11:15 +0000393 //if (!success)
394 // return false;
Johnny Chen2ccad832011-01-28 19:57:25 +0000395
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000396 if (ConditionPassed())
Johnny Chen2ccad832011-01-28 19:57:25 +0000397 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000398 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen2ccad832011-01-28 19:57:25 +0000399 if (!success)
400 return false;
401 uint32_t Rd; // the destination register
402 switch (encoding) {
403 case eEncodingT1:
404 Rd = 7;
405 break;
406 case eEncodingA1:
407 Rd = 12;
408 break;
409 default:
410 return false;
411 }
412 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
413 eRegisterKindGeneric,
414 LLDB_REGNUM_GENERIC_SP,
415 0 };
416
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000417 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, sp))
Johnny Chen2ccad832011-01-28 19:57:25 +0000418 return false;
419 }
420 return true;
421}
422
Johnny Chen1c13b622011-01-29 00:11:15 +0000423// Move from high register (r8-r15) to low register (r0-r7).
424// MOV (register)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000425bool
426EmulateInstructionARM::EmulateMovLowHigh (ARMEncoding encoding)
Johnny Chen1c13b622011-01-29 00:11:15 +0000427{
428#if 0
429 // ARM pseudo code...
430 if (ConditionPassed())
431 {
432 EncodingSpecificOperations();
433 result = R[m];
434 if d == 15 then
435 ALUWritePC(result); // setflags is always FALSE here
436 else
437 R[d] = result;
438 if setflags then
439 APSR.N = result<31>;
440 APSR.Z = IsZeroBit(result);
441 // APSR.C unchanged
442 // APSR.V unchanged
443 }
444#endif
445
446 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000447 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen1c13b622011-01-29 00:11:15 +0000448 if (!success)
449 return false;
450
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000451 if (ConditionPassed())
Johnny Chen1c13b622011-01-29 00:11:15 +0000452 {
453 uint32_t Rm; // the source register
454 uint32_t Rd; // the destination register
455 switch (encoding) {
456 case eEncodingT1:
457 Rm = Bits32(opcode, 6, 3);
458 Rd = Bits32(opcode, 2, 1); // bits(7) == 0
459 break;
460 default:
461 return false;
462 }
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000463 int32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
Johnny Chen1c13b622011-01-29 00:11:15 +0000464 if (!success)
465 return false;
466
467 // The context specifies that Rm is to be moved into Rd.
468 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
469 eRegisterKindDWARF,
470 dwarf_r0 + Rm,
471 0 };
472
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000473 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, reg_value))
Johnny Chen1c13b622011-01-29 00:11:15 +0000474 return false;
475 }
476 return true;
477}
478
Johnny Chen788e0552011-01-27 22:52:23 +0000479// PC relative immediate load into register, possibly followed by ADD (SP plus register).
480// LDR (literal)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000481bool
482EmulateInstructionARM::EmulateLDRRdPCRelative (ARMEncoding encoding)
Johnny Chen788e0552011-01-27 22:52:23 +0000483{
484#if 0
485 // ARM pseudo code...
486 if (ConditionPassed())
487 {
488 EncodingSpecificOperations(); NullCheckIfThumbEE(15);
489 base = Align(PC,4);
490 address = if add then (base + imm32) else (base - imm32);
491 data = MemU[address,4];
492 if t == 15 then
493 if address<1:0> == 00 then LoadWritePC(data); else UNPREDICTABLE;
494 elsif UnalignedSupport() || address<1:0> = 00 then
495 R[t] = data;
496 else // Can only apply before ARMv7
497 if CurrentInstrSet() == InstrSet_ARM then
498 R[t] = ROR(data, 8*UInt(address<1:0>));
499 else
500 R[t] = bits(32) UNKNOWN;
501 }
502#endif
503
504 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000505 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen788e0552011-01-27 22:52:23 +0000506 if (!success)
507 return false;
508
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000509 if (ConditionPassed())
Johnny Chen788e0552011-01-27 22:52:23 +0000510 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000511 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Johnny Chen788e0552011-01-27 22:52:23 +0000512 if (!success)
513 return false;
Johnny Chen809742e2011-01-28 00:32:27 +0000514
515 // PC relative immediate load context
516 EmulateInstruction::Context context = {EmulateInstruction::eContextRegisterPlusOffset,
517 eRegisterKindGeneric,
518 LLDB_REGNUM_GENERIC_PC,
519 0};
Johnny Chen788e0552011-01-27 22:52:23 +0000520 uint32_t Rd; // the destination register
521 uint32_t imm32; // immediate offset from the PC
522 addr_t addr; // the PC relative address
523 uint32_t data; // the literal data value from the PC relative load
524 switch (encoding) {
525 case eEncodingT1:
526 Rd = Bits32(opcode, 10, 8);
527 imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32);
528 addr = pc + 4 + imm32;
Johnny Chen809742e2011-01-28 00:32:27 +0000529 context.arg2 = 4 + imm32;
Johnny Chen788e0552011-01-27 22:52:23 +0000530 break;
531 default:
532 return false;
533 }
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000534 data = ReadMemoryUnsigned(context, addr, 4, 0, &success);
Johnny Chen788e0552011-01-27 22:52:23 +0000535 if (!success)
Johnny Chen809742e2011-01-28 00:32:27 +0000536 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000537 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, data))
Johnny Chen788e0552011-01-27 22:52:23 +0000538 return false;
539 }
540 return true;
541}
542
Johnny Chen5b442b72011-01-27 19:34:30 +0000543// An add operation to adjust the SP.
Johnny Chenfdd179e2011-01-31 20:09:28 +0000544// ADD (SP plus immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000545bool
546EmulateInstructionARM::EmulateAddSPImmediate (ARMEncoding encoding)
Johnny Chenfdd179e2011-01-31 20:09:28 +0000547{
548#if 0
549 // ARM pseudo code...
550 if (ConditionPassed())
551 {
552 EncodingSpecificOperations();
553 (result, carry, overflow) = AddWithCarry(SP, imm32, 0’);
554 if d == 15 then // Can only occur for ARM encoding
555 ALUWritePC(result); // setflags is always FALSE here
556 else
557 R[d] = result;
558 if setflags then
559 APSR.N = result<31>;
560 APSR.Z = IsZeroBit(result);
561 APSR.C = carry;
562 APSR.V = overflow;
563 }
564#endif
565
566 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000567 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chenfdd179e2011-01-31 20:09:28 +0000568 if (!success)
569 return false;
570
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000571 if (ConditionPassed())
Johnny Chenfdd179e2011-01-31 20:09:28 +0000572 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000573 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chenfdd179e2011-01-31 20:09:28 +0000574 if (!success)
575 return false;
576 uint32_t imm32; // the immediate operand
577 switch (encoding) {
578 case eEncodingT2:
579 imm32 = ThumbImmScaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
580 break;
581 default:
582 return false;
583 }
584 addr_t sp_offset = imm32;
585 addr_t addr = sp + sp_offset; // the adjusted stack pointer value
586
587 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
588 eRegisterKindGeneric,
589 LLDB_REGNUM_GENERIC_SP,
590 sp_offset };
591
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000592 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
Johnny Chenfdd179e2011-01-31 20:09:28 +0000593 return false;
594 }
595 return true;
596}
597
598// An add operation to adjust the SP.
Johnny Chen5b442b72011-01-27 19:34:30 +0000599// ADD (SP plus register)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000600bool
601EmulateInstructionARM::EmulateAddSPRm (ARMEncoding encoding)
Johnny Chen5b442b72011-01-27 19:34:30 +0000602{
603#if 0
604 // ARM pseudo code...
605 if (ConditionPassed())
606 {
607 EncodingSpecificOperations();
608 shifted = Shift(R[m], shift_t, shift_n, APSR.C);
609 (result, carry, overflow) = AddWithCarry(SP, shifted, 0’);
610 if d == 15 then
611 ALUWritePC(result); // setflags is always FALSE here
612 else
613 R[d] = result;
614 if setflags then
615 APSR.N = result<31>;
616 APSR.Z = IsZeroBit(result);
617 APSR.C = carry;
618 APSR.V = overflow;
619 }
620#endif
621
622 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000623 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen5b442b72011-01-27 19:34:30 +0000624 if (!success)
625 return false;
626
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000627 if (ConditionPassed())
Johnny Chen5b442b72011-01-27 19:34:30 +0000628 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000629 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen5b442b72011-01-27 19:34:30 +0000630 if (!success)
631 return false;
632 uint32_t Rm; // the second operand
633 switch (encoding) {
634 case eEncodingT2:
635 Rm = Bits32(opcode, 6, 3);
636 break;
637 default:
638 return false;
639 }
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000640 int32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
Johnny Chen5b442b72011-01-27 19:34:30 +0000641 if (!success)
642 return false;
643
644 addr_t addr = (int32_t)sp + reg_value; // the adjusted stack pointer value
645
646 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
647 eRegisterKindGeneric,
648 LLDB_REGNUM_GENERIC_SP,
649 reg_value };
650
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000651 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
Johnny Chen5b442b72011-01-27 19:34:30 +0000652 return false;
653 }
654 return true;
655}
656
Johnny Chen9b8d7832011-02-02 01:13:56 +0000657// Branch with Link and Exchange Instruction Sets (immediate) calls a subroutine
658// at a PC-relative address, and changes instruction set from ARM to Thumb, or
659// from Thumb to ARM.
660// BLX (immediate)
661bool
662EmulateInstructionARM::EmulateBLXImmediate (ARMEncoding encoding)
663{
664#if 0
665 // ARM pseudo code...
666 if (ConditionPassed())
667 {
668 EncodingSpecificOperations();
669 if CurrentInstrSet() == InstrSet_ARM then
670 LR = PC - 4;
671 else
672 LR = PC<31:1> : '1';
673 if targetInstrSet == InstrSet_ARM then
674 targetAddress = Align(PC,4) + imm32;
675 else
676 targetAddress = PC + imm32;
677 SelectInstrSet(targetInstrSet);
678 BranchWritePC(targetAddress);
679 }
680#endif
681
682 bool success = false;
683 const uint32_t opcode = OpcodeAsUnsigned (&success);
684 if (!success)
685 return false;
686
687 if (ConditionPassed())
688 {
689 EmulateInstruction::Context context = { EmulateInstruction::eContextRelativeBranchImmediate, 0, 0, 0};
690 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
691 addr_t lr; // next instruction address
692 addr_t target; // target address
693 if (!success)
694 return false;
695 int32_t imm32; // PC-relative offset
696 switch (encoding) {
697 case eEncodingT2:
698 {
699 lr = (pc + 4) | 1u; // return address
700 uint32_t S = Bits32(opcode, 26, 26);
701 uint32_t imm10H = Bits32(opcode, 25, 16);
702 uint32_t J1 = Bits32(opcode, 13, 13);
703 uint32_t J2 = Bits32(opcode, 11, 11);
704 uint32_t imm10L = Bits32(opcode, 10, 1);
705 uint32_t I1 = !(J1 ^ S);
706 uint32_t I2 = !(J2 ^ S);
707 uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10H << 12) + (imm10L << 2);
708 imm32 = llvm::SignExtend32<25>(imm25);
709 target = (pc & 0xfffffffc) + 4 + imm32;
710 context.arg1 = eModeARM; // target instruction set
711 context.arg2 = 4 + imm32; // signed offset
712 break;
713 }
714 case eEncodingA2:
715 lr = pc + 4; // return address
716 imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2 | Bits32(opcode, 24, 24) << 1);
717 target = pc + 8 + imm32;
718 context.arg1 = eModeThumb; // target instruction set
719 context.arg2 = 8 + imm32; // signed offset
720 break;
721 default:
722 return false;
723 }
724 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
725 return false;
726 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, target))
727 return false;
728 }
729 return true;
730}
731
732// Branch with Link and Exchange (register) calls a subroutine at an address and
733// instruction set specified by a register.
734// BLX (register)
735bool
736EmulateInstructionARM::EmulateBLXRm (ARMEncoding encoding)
737{
738#if 0
739 // ARM pseudo code...
740 if (ConditionPassed())
741 {
742 EncodingSpecificOperations();
743 target = R[m];
744 if CurrentInstrSet() == InstrSet_ARM then
745 next_instr_addr = PC - 4;
746 LR = next_instr_addr;
747 else
748 next_instr_addr = PC - 2;
749 LR = next_instr_addr<31:1> : 1’;
750 BXWritePC(target);
751 }
752#endif
753
754 bool success = false;
755 const uint32_t opcode = OpcodeAsUnsigned (&success);
756 if (!success)
757 return false;
758
759 if (ConditionPassed())
760 {
761 EmulateInstruction::Context context = { EmulateInstruction::eContextAbsoluteBranchRegister, 0, 0, 0};
762 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
763 addr_t lr; // next instruction address
764 addr_t target; // target address
765 if (!success)
766 return false;
767 uint32_t Rm; // the register with the target address
768 switch (encoding) {
769 case eEncodingT1:
770 lr = (pc + 2) | 1u; // return address
771 Rm = Bits32(opcode, 6, 3);
772 // if m == 15 then UNPREDICTABLE;
773 if (Rm == 15)
774 return false;
775 target = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
776 break;
777 case eEncodingA1:
778 lr = pc + 4; // return address
779 Rm = Bits32(opcode, 3, 0);
780 // if m == 15 then UNPREDICTABLE;
781 if (Rm == 15)
782 return false;
783 target = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
Johnny Chenb77be412011-02-04 00:40:18 +0000784 break;
Johnny Chen9b8d7832011-02-02 01:13:56 +0000785 default:
786 return false;
787 }
788 bool toThumb;
789 if (BitIsSet(target, 0))
790 toThumb = true;
791 else if (BitIsClear(target, 1))
792 toThumb = false;
793 else
794 return false; // address<1:0> == ‘10’ => UNPREDICTABLE
795 context.arg0 = eRegisterKindDWARF;
796 context.arg1 = dwarf_r0 + Rm;
797 context.arg2 = toThumb ? eModeThumb : eModeARM;
798 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
799 return false;
800 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, target))
801 return false;
802 }
803 return true;
804}
805
Johnny Chen0d0148e2011-01-28 02:26:08 +0000806// Set r7 to point to some ip offset.
807// SUB (immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000808bool
809EmulateInstructionARM::EmulateSubR7IPImmediate (ARMEncoding encoding)
Johnny Chen0d0148e2011-01-28 02:26:08 +0000810{
811#if 0
812 // ARM pseudo code...
813 if (ConditionPassed())
814 {
815 EncodingSpecificOperations();
816 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), 1’);
817 if d == 15 then // Can only occur for ARM encoding
818 ALUWritePC(result); // setflags is always FALSE here
819 else
820 R[d] = result;
821 if setflags then
822 APSR.N = result<31>;
823 APSR.Z = IsZeroBit(result);
824 APSR.C = carry;
825 APSR.V = overflow;
826 }
827#endif
828
829 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000830 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen0d0148e2011-01-28 02:26:08 +0000831 if (!success)
832 return false;
833
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000834 if (ConditionPassed())
Johnny Chen0d0148e2011-01-28 02:26:08 +0000835 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000836 const addr_t ip = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r12, 0, &success);
Johnny Chen0d0148e2011-01-28 02:26:08 +0000837 if (!success)
838 return false;
839 uint32_t imm32;
840 switch (encoding) {
841 case eEncodingA1:
842 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
843 break;
844 default:
845 return false;
846 }
847 addr_t ip_offset = imm32;
848 addr_t addr = ip - ip_offset; // the adjusted ip value
849
850 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
851 eRegisterKindDWARF,
852 dwarf_r12,
853 -ip_offset };
854
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000855 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r7, addr))
Johnny Chen0d0148e2011-01-28 02:26:08 +0000856 return false;
857 }
858 return true;
859}
860
861// Set ip to point to some stack offset.
862// SUB (SP minus immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000863bool
864EmulateInstructionARM::EmulateSubIPSPImmediate (ARMEncoding encoding)
Johnny Chen0d0148e2011-01-28 02:26:08 +0000865{
866#if 0
867 // ARM pseudo code...
868 if (ConditionPassed())
869 {
870 EncodingSpecificOperations();
871 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), 1’);
872 if d == 15 then // Can only occur for ARM encoding
873 ALUWritePC(result); // setflags is always FALSE here
874 else
875 R[d] = result;
876 if setflags then
877 APSR.N = result<31>;
878 APSR.Z = IsZeroBit(result);
879 APSR.C = carry;
880 APSR.V = overflow;
881 }
882#endif
883
884 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000885 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen0d0148e2011-01-28 02:26:08 +0000886 if (!success)
887 return false;
888
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000889 if (ConditionPassed())
Johnny Chen0d0148e2011-01-28 02:26:08 +0000890 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000891 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen0d0148e2011-01-28 02:26:08 +0000892 if (!success)
893 return false;
894 uint32_t imm32;
895 switch (encoding) {
896 case eEncodingA1:
897 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
898 break;
899 default:
900 return false;
901 }
902 addr_t sp_offset = imm32;
903 addr_t addr = sp - sp_offset; // the adjusted stack pointer value
904
905 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
906 eRegisterKindGeneric,
907 LLDB_REGNUM_GENERIC_SP,
908 -sp_offset };
909
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000910 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r12, addr))
Johnny Chen0d0148e2011-01-28 02:26:08 +0000911 return false;
912 }
913 return true;
914}
915
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000916// A sub operation to adjust the SP -- allocate space for local storage.
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000917bool
918EmulateInstructionARM::EmulateSubSPImmdiate (ARMEncoding encoding)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000919{
920#if 0
921 // ARM pseudo code...
922 if (ConditionPassed())
923 {
924 EncodingSpecificOperations();
925 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), 1’);
926 if d == 15 then // Can only occur for ARM encoding
Johnny Chen799dfd02011-01-26 23:14:33 +0000927 ALUWritePC(result); // setflags is always FALSE here
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000928 else
929 R[d] = result;
930 if setflags then
931 APSR.N = result<31>;
932 APSR.Z = IsZeroBit(result);
933 APSR.C = carry;
934 APSR.V = overflow;
935 }
936#endif
937
938 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000939 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000940 if (!success)
941 return false;
942
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000943 if (ConditionPassed())
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000944 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000945 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000946 if (!success)
947 return false;
948 uint32_t imm32;
949 switch (encoding) {
Johnny Chene4455022011-01-26 00:08:59 +0000950 case eEncodingT1:
951 imm32 = ThumbImmScaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
Johnny Chen60c0d622011-01-25 23:49:39 +0000952 case eEncodingT2:
953 imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
954 break;
955 case eEncodingT3:
956 imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32)
957 break;
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000958 case eEncodingA1:
Johnny Chen60c0d622011-01-25 23:49:39 +0000959 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000960 break;
961 default:
962 return false;
963 }
964 addr_t sp_offset = imm32;
965 addr_t addr = sp - sp_offset; // the adjusted stack pointer value
966
967 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
968 eRegisterKindGeneric,
969 LLDB_REGNUM_GENERIC_SP,
Johnny Chen5b442b72011-01-27 19:34:30 +0000970 -sp_offset };
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000971
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000972 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000973 return false;
974 }
975 return true;
976}
977
Johnny Chen08c25e82011-01-31 18:02:28 +0000978// A store operation to the stack that also updates the SP.
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000979bool
980EmulateInstructionARM::EmulateSTRRtSP (ARMEncoding encoding)
Johnny Chence1ca772011-01-25 01:13:00 +0000981{
982#if 0
983 // ARM pseudo code...
984 if (ConditionPassed())
985 {
986 EncodingSpecificOperations();
987 offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
988 address = if index then offset_addr else R[n];
989 MemU[address,4] = if t == 15 then PCStoreValue() else R[t];
990 if wback then R[n] = offset_addr;
991 }
992#endif
993
994 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000995 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chence1ca772011-01-25 01:13:00 +0000996 if (!success)
997 return false;
998
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000999 if (ConditionPassed())
Johnny Chence1ca772011-01-25 01:13:00 +00001000 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001001 const uint32_t addr_byte_size = GetAddressByteSize();
1002 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chence1ca772011-01-25 01:13:00 +00001003 if (!success)
1004 return false;
Johnny Chen91d99862011-01-25 19:07:04 +00001005 uint32_t Rt; // the source register
Johnny Chence1ca772011-01-25 01:13:00 +00001006 uint32_t imm12;
1007 switch (encoding) {
1008 case eEncodingA1:
Johnny Chen108d5aa2011-01-26 01:00:55 +00001009 Rt = Bits32(opcode, 15, 12);
1010 imm12 = Bits32(opcode, 11, 0);
Johnny Chence1ca772011-01-25 01:13:00 +00001011 break;
1012 default:
1013 return false;
1014 }
1015 addr_t sp_offset = imm12;
1016 addr_t addr = sp - sp_offset;
1017
1018 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
Johnny Chen91d99862011-01-25 19:07:04 +00001019 if (Rt != 15)
Johnny Chence1ca772011-01-25 01:13:00 +00001020 {
Johnny Chen91d99862011-01-25 19:07:04 +00001021 context.arg1 = dwarf_r0 + Rt; // arg1 in the context is the DWARF register number
1022 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001023 uint32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
Johnny Chence1ca772011-01-25 01:13:00 +00001024 if (!success)
1025 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001026 if (!WriteMemoryUnsigned (context, addr, reg_value, addr_byte_size))
Johnny Chence1ca772011-01-25 01:13:00 +00001027 return false;
1028 }
1029 else
1030 {
1031 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
1032 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001033 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Johnny Chence1ca772011-01-25 01:13:00 +00001034 if (!success)
1035 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001036 if (!WriteMemoryUnsigned (context, addr, pc + 8, addr_byte_size))
Johnny Chence1ca772011-01-25 01:13:00 +00001037 return false;
1038 }
1039
1040 context.type = EmulateInstruction::eContextAdjustStackPointer;
1041 context.arg0 = eRegisterKindGeneric;
1042 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +00001043 context.arg2 = -sp_offset;
Johnny Chence1ca772011-01-25 01:13:00 +00001044
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001045 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
Johnny Chence1ca772011-01-25 01:13:00 +00001046 return false;
1047 }
1048 return true;
1049}
1050
Johnny Chen08c25e82011-01-31 18:02:28 +00001051// Vector Push stores multiple extension registers to the stack.
1052// It also updates SP to point to the start of the stored data.
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001053bool
1054EmulateInstructionARM::EmulateVPUSH (ARMEncoding encoding)
Johnny Chen799dfd02011-01-26 23:14:33 +00001055{
1056#if 0
1057 // ARM pseudo code...
1058 if (ConditionPassed())
1059 {
1060 EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13);
1061 address = SP - imm32;
1062 SP = SP - imm32;
1063 if single_regs then
1064 for r = 0 to regs-1
1065 MemA[address,4] = S[d+r]; address = address+4;
1066 else
1067 for r = 0 to regs-1
1068 // Store as two word-aligned words in the correct order for current endianness.
1069 MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>;
1070 MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>;
1071 address = address+8;
1072 }
1073#endif
1074
1075 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001076 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen799dfd02011-01-26 23:14:33 +00001077 if (!success)
1078 return false;
1079
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001080 if (ConditionPassed())
Johnny Chen799dfd02011-01-26 23:14:33 +00001081 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001082 const uint32_t addr_byte_size = GetAddressByteSize();
1083 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen799dfd02011-01-26 23:14:33 +00001084 if (!success)
1085 return false;
1086 bool single_regs;
Johnny Chen587a0a42011-02-01 18:35:28 +00001087 uint32_t d; // UInt(D:Vd) or UInt(Vd:D) starting register
Johnny Chen799dfd02011-01-26 23:14:33 +00001088 uint32_t imm32; // stack offset
1089 uint32_t regs; // number of registers
1090 switch (encoding) {
1091 case eEncodingT1:
1092 case eEncodingA1:
1093 single_regs = false;
Johnny Chen587a0a42011-02-01 18:35:28 +00001094 d = Bits32(opcode, 22, 22) << 4 | Bits32(opcode, 15, 12);
Johnny Chen799dfd02011-01-26 23:14:33 +00001095 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1096 // If UInt(imm8) is odd, see "FSTMX".
1097 regs = Bits32(opcode, 7, 0) / 2;
1098 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1099 if (regs == 0 || regs > 16 || (d + regs) > 32)
1100 return false;
1101 break;
1102 case eEncodingT2:
1103 case eEncodingA2:
1104 single_regs = true;
1105 d = Bits32(opcode, 15, 12) << 1 | Bits32(opcode, 22, 22);
1106 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1107 regs = Bits32(opcode, 7, 0);
1108 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1109 if (regs == 0 || regs > 16 || (d + regs) > 32)
1110 return false;
1111 break;
1112 default:
1113 return false;
1114 }
1115 uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
1116 uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2;
1117 addr_t sp_offset = imm32;
1118 addr_t addr = sp - sp_offset;
1119 uint32_t i;
1120
1121 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
1122 for (i=d; i<regs; ++i)
1123 {
1124 context.arg1 = start_reg + i; // arg1 in the context is the DWARF register number
1125 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
1126 // uint64_t to accommodate 64-bit registers.
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001127 uint64_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
Johnny Chen799dfd02011-01-26 23:14:33 +00001128 if (!success)
1129 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001130 if (!WriteMemoryUnsigned (context, addr, reg_value, reg_byte_size))
Johnny Chen799dfd02011-01-26 23:14:33 +00001131 return false;
1132 addr += reg_byte_size;
1133 }
1134
1135 context.type = EmulateInstruction::eContextAdjustStackPointer;
1136 context.arg0 = eRegisterKindGeneric;
1137 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +00001138 context.arg2 = -sp_offset;
Johnny Chen799dfd02011-01-26 23:14:33 +00001139
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001140 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
Johnny Chen799dfd02011-01-26 23:14:33 +00001141 return false;
1142 }
1143 return true;
1144}
1145
Johnny Chen587a0a42011-02-01 18:35:28 +00001146// Vector Pop loads multiple extension registers from the stack.
1147// It also updates SP to point just above the loaded data.
1148bool
1149EmulateInstructionARM::EmulateVPOP (ARMEncoding encoding)
1150{
1151#if 0
1152 // ARM pseudo code...
1153 if (ConditionPassed())
1154 {
1155 EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13);
1156 address = SP;
1157 SP = SP + imm32;
1158 if single_regs then
1159 for r = 0 to regs-1
1160 S[d+r] = MemA[address,4]; address = address+4;
1161 else
1162 for r = 0 to regs-1
1163 word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8;
1164 // Combine the word-aligned words in the correct order for current endianness.
1165 D[d+r] = if BigEndian() then word1:word2 else word2:word1;
1166 }
1167#endif
1168
1169 bool success = false;
1170 const uint32_t opcode = OpcodeAsUnsigned (&success);
1171 if (!success)
1172 return false;
1173
1174 if (ConditionPassed())
1175 {
1176 const uint32_t addr_byte_size = GetAddressByteSize();
1177 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
1178 if (!success)
1179 return false;
1180 bool single_regs;
1181 uint32_t d; // UInt(D:Vd) or UInt(Vd:D) starting register
1182 uint32_t imm32; // stack offset
1183 uint32_t regs; // number of registers
1184 switch (encoding) {
1185 case eEncodingT1:
1186 case eEncodingA1:
1187 single_regs = false;
1188 d = Bits32(opcode, 22, 22) << 4 | Bits32(opcode, 15, 12);
1189 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1190 // If UInt(imm8) is odd, see "FLDMX".
1191 regs = Bits32(opcode, 7, 0) / 2;
1192 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1193 if (regs == 0 || regs > 16 || (d + regs) > 32)
1194 return false;
1195 break;
1196 case eEncodingT2:
1197 case eEncodingA2:
1198 single_regs = true;
1199 d = Bits32(opcode, 15, 12) << 1 | Bits32(opcode, 22, 22);
1200 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1201 regs = Bits32(opcode, 7, 0);
1202 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1203 if (regs == 0 || regs > 16 || (d + regs) > 32)
1204 return false;
1205 break;
1206 default:
1207 return false;
1208 }
1209 uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
1210 uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2;
1211 addr_t sp_offset = imm32;
1212 addr_t addr = sp;
1213 uint32_t i;
1214 uint64_t data; // uint64_t to accomodate 64-bit registers.
1215
1216 EmulateInstruction::Context context = { EmulateInstruction::eContextPopRegisterOffStack, eRegisterKindDWARF, 0, 0 };
1217 for (i=d; i<regs; ++i)
1218 {
1219 context.arg1 = start_reg + i; // arg1 in the context is the DWARF register number
1220 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
1221 data = ReadMemoryUnsigned(context, addr, reg_byte_size, 0, &success);
1222 if (!success)
1223 return false;
1224 if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, context.arg1, data))
1225 return false;
1226 addr += reg_byte_size;
1227 }
1228
1229 context.type = EmulateInstruction::eContextAdjustStackPointer;
1230 context.arg0 = eRegisterKindGeneric;
1231 context.arg1 = LLDB_REGNUM_GENERIC_SP;
1232 context.arg2 = sp_offset;
1233
1234 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp + sp_offset))
1235 return false;
1236 }
1237 return true;
1238}
1239
Johnny Chenb77be412011-02-04 00:40:18 +00001240// SVC (previously SWI)
1241bool
1242EmulateInstructionARM::EmulateSVC (ARMEncoding encoding)
1243{
1244#if 0
1245 // ARM pseudo code...
1246 if (ConditionPassed())
1247 {
1248 EncodingSpecificOperations();
1249 CallSupervisor();
1250 }
1251#endif
1252
1253 bool success = false;
1254 const uint32_t opcode = OpcodeAsUnsigned (&success);
1255 if (!success)
1256 return false;
1257
1258 if (ConditionPassed())
1259 {
1260 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1261 addr_t lr; // next instruction address
1262 if (!success)
1263 return false;
1264 uint32_t imm32; // the immediate constant
1265 uint32_t mode; // ARM or Thumb mode
1266 switch (encoding) {
1267 case eEncodingT1:
1268 lr = (pc + 2) | 1u; // return address
1269 imm32 = Bits32(opcode, 7, 0);
1270 mode = eModeThumb;
1271 break;
1272 case eEncodingA1:
1273 lr = pc + 4; // return address
1274 imm32 = Bits32(opcode, 23, 0);
1275 mode = eModeARM;
1276 break;
1277 default:
1278 return false;
1279 }
1280 EmulateInstruction::Context context = { EmulateInstruction::eContextSupervisorCall, mode, imm32, 0};
1281 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
1282 return false;
1283 }
1284 return true;
1285}
1286
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001287EmulateInstructionARM::ARMOpcode*
1288EmulateInstructionARM::GetARMOpcodeForInstruction (const uint32_t opcode)
Greg Clayton64c84432011-01-21 22:02:52 +00001289{
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001290 static ARMOpcode
1291 g_arm_opcodes[] =
1292 {
1293 //----------------------------------------------------------------------
1294 // Prologue instructions
1295 //----------------------------------------------------------------------
Johnny Chenfdd179e2011-01-31 20:09:28 +00001296
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001297 // push register(s)
Johnny Chenc28a76d2011-02-01 18:51:48 +00001298 { 0x0fff0000, 0x092d0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulatePush, "push <registers>" },
1299 { 0x0fff0fff, 0x052d0004, ARMvAll, eEncodingA2, eSize32, &EmulateInstructionARM::EmulatePush, "push <register>" },
Johnny Chenbcec3af2011-01-27 01:26:19 +00001300
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001301 // set r7 to point to a stack offset
Johnny Chenc28a76d2011-02-01 18:51:48 +00001302 { 0x0ffff000, 0x028d7000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateAddRdSPImmediate, "add r7, sp, #<const>" },
1303 { 0x0ffff000, 0x024c7000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSubR7IPImmediate, "sub r7, ip, #<const>"},
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001304 // set ip to point to a stack offset
Johnny Chenc28a76d2011-02-01 18:51:48 +00001305 { 0x0fffffff, 0x01a0c00d, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateMovRdSP, "mov ip, sp" },
1306 { 0x0ffff000, 0x028dc000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateAddRdSPImmediate, "add ip, sp, #<const>" },
1307 { 0x0ffff000, 0x024dc000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSubIPSPImmediate, "sub ip, sp, #<const>"},
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001308
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001309 // adjust the stack pointer
Johnny Chenc28a76d2011-02-01 18:51:48 +00001310 { 0x0ffff000, 0x024dd000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSubSPImmdiate, "sub sp, sp, #<const>"},
Johnny Chence1ca772011-01-25 01:13:00 +00001311
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001312 // push one register
1313 // if Rn == '1101' && imm12 == '000000000100' then SEE PUSH;
Johnny Chenc28a76d2011-02-01 18:51:48 +00001314 { 0x0fff0000, 0x052d0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSTRRtSP, "str Rt, [sp, #-imm12]!" },
Johnny Chen799dfd02011-01-26 23:14:33 +00001315
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001316 // vector push consecutive extension register(s)
Johnny Chen9b8d7832011-02-02 01:13:56 +00001317 { 0x0fbf0f00, 0x0d2d0b00, ARMV6T2_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"},
1318 { 0x0fbf0f00, 0x0d2d0a00, ARMV6T2_ABOVE, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"},
Johnny Chenef85e912011-01-31 23:07:40 +00001319
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001320 //----------------------------------------------------------------------
Johnny Chen587a0a42011-02-01 18:35:28 +00001321 // Epilogue instructions
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001322 //----------------------------------------------------------------------
Johnny Chenef85e912011-01-31 23:07:40 +00001323
Johnny Chen9b8d7832011-02-02 01:13:56 +00001324 // To resolve ambiguity, "blx <label>" should come before "bl <label>".
1325 { 0xfe000000, 0xfa000000, ARMV5_ABOVE, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
1326 { 0x0f000000, 0x0b000000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"},
1327 { 0x0ffffff0, 0x012fff30, ARMV5_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
Johnny Chenc28a76d2011-02-01 18:51:48 +00001328 { 0x0fff0000, 0x08bd0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulatePop, "pop <registers>"},
1329 { 0x0fff0fff, 0x049d0004, ARMvAll, eEncodingA2, eSize32, &EmulateInstructionARM::EmulatePop, "pop <register>"},
Johnny Chen9b8d7832011-02-02 01:13:56 +00001330 { 0x0fbf0f00, 0x0cbd0b00, ARMV6T2_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"},
Johnny Chenb77be412011-02-04 00:40:18 +00001331 { 0x0fbf0f00, 0x0cbd0a00, ARMV6T2_ABOVE, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"},
1332
1333 //----------------------------------------------------------------------
1334 // Supervisor Call (previously Software Interrupt)
1335 //----------------------------------------------------------------------
1336 { 0x0f000000, 0x0f000000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSVC, "svc #imm24"}
1337
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001338 };
1339 static const size_t k_num_arm_opcodes = sizeof(g_arm_opcodes)/sizeof(ARMOpcode);
1340
1341 for (size_t i=0; i<k_num_arm_opcodes; ++i)
1342 {
1343 if ((g_arm_opcodes[i].mask & opcode) == g_arm_opcodes[i].value)
1344 return &g_arm_opcodes[i];
1345 }
1346 return NULL;
1347}
Greg Clayton64c84432011-01-21 22:02:52 +00001348
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001349
1350EmulateInstructionARM::ARMOpcode*
1351EmulateInstructionARM::GetThumbOpcodeForInstruction (const uint32_t opcode)
Johnny Chen347320d2011-01-24 23:40:59 +00001352{
Johnny Chenfdd179e2011-01-31 20:09:28 +00001353
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001354 static ARMOpcode
1355 g_thumb_opcodes[] =
1356 {
1357 //----------------------------------------------------------------------
1358 // Prologue instructions
1359 //----------------------------------------------------------------------
Johnny Chenbcec3af2011-01-27 01:26:19 +00001360
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001361 // push register(s)
Johnny Chenc28a76d2011-02-01 18:51:48 +00001362 { 0xfffffe00, 0x0000b400, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulatePush, "push <registers>" },
1363 { 0xffff0000, 0xe92d0000, ARMv6T2|ARMv7, eEncodingT2, eSize32, &EmulateInstructionARM::EmulatePush, "push.w <registers>" },
1364 { 0xffff0fff, 0xf84d0d04, ARMv6T2|ARMv7, eEncodingT3, eSize32, &EmulateInstructionARM::EmulatePush, "push.w <register>" },
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001365 // move from high register to low register
Johnny Chenc28a76d2011-02-01 18:51:48 +00001366 { 0xffffffc0, 0x00004640, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateMovLowHigh, "mov r0-r7, r8-r15" },
Johnny Chen788e0552011-01-27 22:52:23 +00001367
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001368 // set r7 to point to a stack offset
Johnny Chenc28a76d2011-02-01 18:51:48 +00001369 { 0xffffff00, 0x0000af00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateAddRdSPImmediate, "add r7, sp, #imm" },
1370 { 0xffffffff, 0x0000466f, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateMovRdSP, "mov r7, sp" },
Johnny Chen60c0d622011-01-25 23:49:39 +00001371
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001372 // PC relative load into register (see also EmulateAddSPRm)
Johnny Chenc28a76d2011-02-01 18:51:48 +00001373 { 0xfffff800, 0x00004800, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateLDRRdPCRelative, "ldr <Rd>, [PC, #imm]"},
Johnny Chen799dfd02011-01-26 23:14:33 +00001374
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001375 // adjust the stack pointer
Johnny Chenc28a76d2011-02-01 18:51:48 +00001376 { 0xffffff87, 0x00004485, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateAddSPRm, "add sp, <Rm>"},
1377 { 0xffffff80, 0x0000b080, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateSubSPImmdiate, "add sp, sp, #imm"},
1378 { 0xfbef8f00, 0xf1ad0d00, ARMv6T2|ARMv7, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateSubSPImmdiate, "sub.w sp, sp, #<const>"},
1379 { 0xfbff8f00, 0xf2ad0d00, ARMv6T2|ARMv7, eEncodingT3, eSize32, &EmulateInstructionARM::EmulateSubSPImmdiate, "subw sp, sp, #imm12"},
Johnny Chenfdd179e2011-01-31 20:09:28 +00001380
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001381 // vector push consecutive extension register(s)
Johnny Chenc28a76d2011-02-01 18:51:48 +00001382 { 0xffbf0f00, 0xed2d0b00, ARMv6T2|ARMv7, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"},
1383 { 0xffbf0f00, 0xed2d0a00, ARMv6T2|ARMv7, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"},
Johnny Chenfdd179e2011-01-31 20:09:28 +00001384
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001385 //----------------------------------------------------------------------
1386 // Epilogue instructions
1387 //----------------------------------------------------------------------
Johnny Chen347320d2011-01-24 23:40:59 +00001388
Johnny Chenc28a76d2011-02-01 18:51:48 +00001389 { 0xffffff80, 0x0000b000, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateAddSPImmediate, "add sp, #imm"},
Johnny Chen9b8d7832011-02-02 01:13:56 +00001390 { 0xffffff87, 0x00004780, ARMV5_ABOVE, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
1391 // J1 == J2 == 1
1392 { 0xf800e801, 0xf000e800, ARMV5_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
Johnny Chenc28a76d2011-02-01 18:51:48 +00001393 { 0xfffffe00, 0x0000bc00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulatePop, "pop <registers>"},
1394 { 0xffff0000, 0xe8bd0000, ARMv6T2|ARMv7, eEncodingT2, eSize32, &EmulateInstructionARM::EmulatePop, "pop.w <registers>" },
1395 { 0xffff0fff, 0xf85d0d04, ARMv6T2|ARMv7, eEncodingT3, eSize32, &EmulateInstructionARM::EmulatePop, "pop.w <register>" },
1396 { 0xffbf0f00, 0xecbd0b00, ARMv6T2|ARMv7, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"},
Johnny Chenb77be412011-02-04 00:40:18 +00001397 { 0xffbf0f00, 0xecbd0a00, ARMv6T2|ARMv7, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"},
1398
1399 //----------------------------------------------------------------------
1400 // Supervisor Call (previously Software Interrupt)
1401 //----------------------------------------------------------------------
1402 { 0xffffff00, 0x0000df00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateSVC, "svc #imm8"}
1403
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001404 };
1405
1406 const size_t k_num_thumb_opcodes = sizeof(g_thumb_opcodes)/sizeof(ARMOpcode);
1407 for (size_t i=0; i<k_num_thumb_opcodes; ++i)
1408 {
1409 if ((g_thumb_opcodes[i].mask & opcode) == g_thumb_opcodes[i].value)
1410 return &g_thumb_opcodes[i];
1411 }
1412 return NULL;
1413}
Greg Clayton64c84432011-01-21 22:02:52 +00001414
Greg Clayton31e2a382011-01-30 20:03:56 +00001415bool
1416EmulateInstructionARM::SetTargetTriple (const ConstString &triple)
1417{
1418 m_arm_isa = 0;
1419 const char *triple_cstr = triple.GetCString();
1420 if (triple_cstr)
1421 {
1422 const char *dash = ::strchr (triple_cstr, '-');
1423 if (dash)
1424 {
1425 std::string arch (triple_cstr, dash);
1426 const char *arch_cstr = arch.c_str();
1427 if (strcasecmp(arch_cstr, "armv4t") == 0)
1428 m_arm_isa = ARMv4T;
1429 else if (strcasecmp(arch_cstr, "armv4") == 0)
1430 m_arm_isa = ARMv4;
1431 else if (strcasecmp(arch_cstr, "armv5tej") == 0)
1432 m_arm_isa = ARMv5TEJ;
1433 else if (strcasecmp(arch_cstr, "armv5te") == 0)
1434 m_arm_isa = ARMv5TE;
1435 else if (strcasecmp(arch_cstr, "armv5t") == 0)
1436 m_arm_isa = ARMv5T;
1437 else if (strcasecmp(arch_cstr, "armv6k") == 0)
1438 m_arm_isa = ARMv6K;
1439 else if (strcasecmp(arch_cstr, "armv6") == 0)
1440 m_arm_isa = ARMv6;
1441 else if (strcasecmp(arch_cstr, "armv6t2") == 0)
1442 m_arm_isa = ARMv6T2;
1443 else if (strcasecmp(arch_cstr, "armv7") == 0)
1444 m_arm_isa = ARMv7;
1445 else if (strcasecmp(arch_cstr, "armv8") == 0)
1446 m_arm_isa = ARMv8;
1447 }
1448 }
1449 return m_arm_isa != 0;
1450}
1451
1452
Greg Clayton64c84432011-01-21 22:02:52 +00001453bool
1454EmulateInstructionARM::ReadInstruction ()
1455{
1456 bool success = false;
1457 m_inst_cpsr = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, 0, &success);
1458 if (success)
1459 {
1460 addr_t pc = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_ADDRESS, &success);
1461 if (success)
1462 {
1463 Context read_inst_context = {eContextReadOpcode, 0, 0};
1464 if (m_inst_cpsr & MASK_CPSR_T)
1465 {
1466 m_inst_mode = eModeThumb;
1467 uint32_t thumb_opcode = ReadMemoryUnsigned(read_inst_context, pc, 2, 0, &success);
1468
1469 if (success)
1470 {
1471 if ((m_inst.opcode.inst16 & 0xe000) != 0xe000 || ((m_inst.opcode.inst16 & 0x1800u) == 0))
1472 {
1473 m_inst.opcode_type = eOpcode16;
1474 m_inst.opcode.inst16 = thumb_opcode;
1475 }
1476 else
1477 {
1478 m_inst.opcode_type = eOpcode32;
1479 m_inst.opcode.inst32 = (thumb_opcode << 16) | ReadMemoryUnsigned(read_inst_context, pc + 2, 2, 0, &success);
1480 }
1481 }
1482 }
1483 else
1484 {
1485 m_inst_mode = eModeARM;
1486 m_inst.opcode_type = eOpcode32;
1487 m_inst.opcode.inst32 = ReadMemoryUnsigned(read_inst_context, pc, 4, 0, &success);
1488 }
1489 }
1490 }
1491 if (!success)
1492 {
1493 m_inst_mode = eModeInvalid;
1494 m_inst_pc = LLDB_INVALID_ADDRESS;
1495 }
1496 return success;
1497}
1498
1499uint32_t
1500EmulateInstructionARM::CurrentCond ()
1501{
1502 switch (m_inst_mode)
1503 {
1504 default:
1505 case eModeInvalid:
1506 break;
1507
1508 case eModeARM:
1509 return UnsignedBits(m_inst.opcode.inst32, 31, 28);
1510
1511 case eModeThumb:
1512 return 0x0000000Eu; // Return always for now, we need to handl IT instructions later
1513 }
1514 return UINT32_MAX; // Return invalid value
1515}
1516bool
1517EmulateInstructionARM::ConditionPassed ()
1518{
1519 if (m_inst_cpsr == 0)
1520 return false;
1521
1522 const uint32_t cond = CurrentCond ();
1523
1524 if (cond == UINT32_MAX)
1525 return false;
1526
1527 bool result = false;
1528 switch (UnsignedBits(cond, 3, 1))
1529 {
1530 case 0: result = (m_inst_cpsr & MASK_CPSR_Z) != 0; break;
1531 case 1: result = (m_inst_cpsr & MASK_CPSR_C) != 0; break;
1532 case 2: result = (m_inst_cpsr & MASK_CPSR_N) != 0; break;
1533 case 3: result = (m_inst_cpsr & MASK_CPSR_V) != 0; break;
1534 case 4: result = ((m_inst_cpsr & MASK_CPSR_C) != 0) && ((m_inst_cpsr & MASK_CPSR_Z) == 0); break;
1535 case 5:
1536 {
1537 bool n = (m_inst_cpsr & MASK_CPSR_N);
1538 bool v = (m_inst_cpsr & MASK_CPSR_V);
1539 result = n == v;
1540 }
1541 break;
1542 case 6:
1543 {
1544 bool n = (m_inst_cpsr & MASK_CPSR_N);
1545 bool v = (m_inst_cpsr & MASK_CPSR_V);
1546 result = n == v && ((m_inst_cpsr & MASK_CPSR_Z) == 0);
1547 }
1548 break;
1549 case 7:
1550 result = true;
1551 break;
1552 }
1553
1554 if (cond & 1)
1555 result = !result;
1556 return result;
1557}
1558
1559
1560bool
1561EmulateInstructionARM::EvaluateInstruction ()
1562{
1563 return false;
1564}