blob: e118603f7b81ca8b6e93bd33fb41e1a9a16f702b [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
Greg Claytonf29a08f2011-02-09 17:41:27 +000013#include "Plugins/Process/Utility/ARMDefines.h"
14#include "Plugins/Process/Utility/ARMUtils.h"
15#include "Utility/ARM_DWARF_Registers.h"
16
Johnny Chen9b8d7832011-02-02 01:13:56 +000017#include "llvm/Support/MathExtras.h" // for SignExtend32 template function
Johnny Chen93070472011-02-04 23:02:47 +000018 // and CountTrailingZeros_32 function
Greg Clayton64c84432011-01-21 22:02:52 +000019
20using namespace lldb;
21using namespace lldb_private;
22
Johnny Chend6c13f02011-02-08 20:36:34 +000023static inline uint32_t Align(uint32_t val, uint32_t alignment)
24{
25 return alignment * (val / alignment);
26}
27
Johnny Chen0e00af22011-02-10 19:40:42 +000028//----------------------------------------------------------------------
29//
30// ITSession implementation
31//
32//----------------------------------------------------------------------
33
Johnny Chen93070472011-02-04 23:02:47 +000034// A8.6.50
35// Valid return values are {1, 2, 3, 4}, with 0 signifying an error condition.
36static unsigned short CountITSize(unsigned ITMask) {
37 // First count the trailing zeros of the IT mask.
38 unsigned TZ = llvm::CountTrailingZeros_32(ITMask);
39 if (TZ > 3)
40 {
41 printf("Encoding error: IT Mask '0000'\n");
42 return 0;
43 }
44 return (4 - TZ);
45}
46
47// Init ITState. Note that at least one bit is always 1 in mask.
48bool ITSession::InitIT(unsigned short bits7_0)
49{
50 ITCounter = CountITSize(Bits32(bits7_0, 3, 0));
51 if (ITCounter == 0)
52 return false;
53
54 // A8.6.50 IT
55 unsigned short FirstCond = Bits32(bits7_0, 7, 4);
56 if (FirstCond == 0xF)
57 {
58 printf("Encoding error: IT FirstCond '1111'\n");
59 return false;
60 }
61 if (FirstCond == 0xE && ITCounter != 1)
62 {
63 printf("Encoding error: IT FirstCond '1110' && Mask != '1000'\n");
64 return false;
65 }
66
67 ITState = bits7_0;
68 return true;
69}
70
71// Update ITState if necessary.
72void ITSession::ITAdvance()
73{
74 assert(ITCounter);
75 --ITCounter;
76 if (ITCounter == 0)
77 ITState = 0;
78 else
79 {
80 unsigned short NewITState4_0 = Bits32(ITState, 4, 0) << 1;
81 SetBits32(ITState, 4, 0, NewITState4_0);
82 }
83}
84
85// Return true if we're inside an IT Block.
86bool ITSession::InITBlock()
87{
88 return ITCounter != 0;
89}
90
Johnny Chenc315f862011-02-05 00:46:10 +000091// Return true if we're the last instruction inside an IT Block.
92bool ITSession::LastInITBlock()
93{
94 return ITCounter == 1;
95}
96
Johnny Chen93070472011-02-04 23:02:47 +000097// Get condition bits for the current thumb instruction.
98uint32_t ITSession::GetCond()
99{
Johnny Chenc315f862011-02-05 00:46:10 +0000100 if (InITBlock())
101 return Bits32(ITState, 7, 4);
102 else
103 return COND_AL;
Johnny Chen93070472011-02-04 23:02:47 +0000104}
105
Greg Clayton64c84432011-01-21 22:02:52 +0000106// ARM constants used during decoding
107#define REG_RD 0
108#define LDM_REGLIST 1
109#define PC_REG 15
110#define PC_REGLIST_BIT 0x8000
111
Johnny Chen251af6a2011-01-21 22:47:25 +0000112#define ARMv4 (1u << 0)
Greg Clayton64c84432011-01-21 22:02:52 +0000113#define ARMv4T (1u << 1)
114#define ARMv5T (1u << 2)
115#define ARMv5TE (1u << 3)
116#define ARMv5TEJ (1u << 4)
Johnny Chen251af6a2011-01-21 22:47:25 +0000117#define ARMv6 (1u << 5)
Greg Clayton64c84432011-01-21 22:02:52 +0000118#define ARMv6K (1u << 6)
119#define ARMv6T2 (1u << 7)
Johnny Chen251af6a2011-01-21 22:47:25 +0000120#define ARMv7 (1u << 8)
Johnny Chen60c0d622011-01-25 23:49:39 +0000121#define ARMv8 (1u << 9)
Greg Clayton64c84432011-01-21 22:02:52 +0000122#define ARMvAll (0xffffffffu)
123
Johnny Chen9b8d7832011-02-02 01:13:56 +0000124#define ARMV4T_ABOVE (ARMv4T|ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv8)
125#define ARMV5_ABOVE (ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv8)
126#define ARMV6T2_ABOVE (ARMv6T2|ARMv7|ARMv8)
Greg Clayton64c84432011-01-21 22:02:52 +0000127
Johnny Chen0e00af22011-02-10 19:40:42 +0000128//----------------------------------------------------------------------
129//
130// EmulateInstructionARM implementation
131//
132//----------------------------------------------------------------------
133
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000134void
135EmulateInstructionARM::Initialize ()
Johnny Chen7dc60e12011-01-24 19:46:32 +0000136{
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000137}
Johnny Chen7dc60e12011-01-24 19:46:32 +0000138
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000139void
140EmulateInstructionARM::Terminate ()
Greg Clayton64c84432011-01-21 22:02:52 +0000141{
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000142}
143
Caroline Tice713c2662011-02-11 17:59:55 +0000144// Write "bits (32) UNKNOWN" to register n. Helper function for many ARM instructions.
145bool
146EmulateInstructionARM::WriteBits32Unknown (int n)
147{
148 EmulateInstruction::Context context = { EmulateInstruction::eContextWriteRegisterRandomBits,
149 eRegisterKindDWARF,
150 dwarf_r0 + n,
151 0 };
152
Johnny Chen62ff6f52011-02-11 18:11:22 +0000153 bool success;
Caroline Tice713c2662011-02-11 17:59:55 +0000154 uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
155
156 if (!success)
157 return false;
158
159 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data))
160 return false;
161
162 return true;
163}
164
Johnny Chen08c25e82011-01-31 18:02:28 +0000165// Push Multiple Registers stores multiple registers to the stack, storing to
166// consecutive memory locations ending just below the address in SP, and updates
167// SP to point to the start of the stored data.
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000168bool
169EmulateInstructionARM::EmulatePush (ARMEncoding encoding)
Greg Clayton64c84432011-01-21 22:02:52 +0000170{
171#if 0
172 // ARM pseudo code...
173 if (ConditionPassed())
174 {
175 EncodingSpecificOperations();
176 NullCheckIfThumbEE(13);
177 address = SP - 4*BitCount(registers);
178
179 for (i = 0 to 14)
180 {
181 if (registers<i> == ’1’)
182 {
183 if i == 13 && i != LowestSetBit(registers) // Only possible for encoding A1
184 MemA[address,4] = bits(32) UNKNOWN;
185 else
186 MemA[address,4] = R[i];
187 address = address + 4;
188 }
189 }
190
191 if (registers<15> == ’1’) // Only possible for encoding A1 or A2
192 MemA[address,4] = PCStoreValue();
193
194 SP = SP - 4*BitCount(registers);
195 }
196#endif
197
198 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000199 const uint32_t opcode = OpcodeAsUnsigned (&success);
Greg Clayton64c84432011-01-21 22:02:52 +0000200 if (!success)
201 return false;
202
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000203 if (ConditionPassed())
Greg Clayton64c84432011-01-21 22:02:52 +0000204 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000205 const uint32_t addr_byte_size = GetAddressByteSize();
206 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Greg Clayton64c84432011-01-21 22:02:52 +0000207 if (!success)
208 return false;
Johnny Chen3c75c762011-01-22 00:47:08 +0000209 uint32_t registers = 0;
Johnny Chen91d99862011-01-25 19:07:04 +0000210 uint32_t Rt; // the source register
Johnny Chen3c75c762011-01-22 00:47:08 +0000211 switch (encoding) {
Johnny Chenaedde1c2011-01-24 20:38:45 +0000212 case eEncodingT1:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000213 registers = Bits32(opcode, 7, 0);
Johnny Chenaedde1c2011-01-24 20:38:45 +0000214 // The M bit represents LR.
Johnny Chenbd599902011-02-10 21:39:01 +0000215 if (Bit32(opcode, 8))
Johnny Chenef85e912011-01-31 23:07:40 +0000216 registers |= (1u << 14);
Johnny Chenaedde1c2011-01-24 20:38:45 +0000217 // if BitCount(registers) < 1 then UNPREDICTABLE;
218 if (BitCount(registers) < 1)
219 return false;
220 break;
Johnny Chen7dc60e12011-01-24 19:46:32 +0000221 case eEncodingT2:
222 // Ignore bits 15 & 13.
Johnny Chen108d5aa2011-01-26 01:00:55 +0000223 registers = Bits32(opcode, 15, 0) & ~0xa000;
Johnny Chen7dc60e12011-01-24 19:46:32 +0000224 // if BitCount(registers) < 2 then UNPREDICTABLE;
225 if (BitCount(registers) < 2)
226 return false;
227 break;
228 case eEncodingT3:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000229 Rt = Bits32(opcode, 15, 12);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000230 // if BadReg(t) then UNPREDICTABLE;
Johnny Chen91d99862011-01-25 19:07:04 +0000231 if (BadReg(Rt))
Johnny Chen7dc60e12011-01-24 19:46:32 +0000232 return false;
Johnny Chen91d99862011-01-25 19:07:04 +0000233 registers = (1u << Rt);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000234 break;
Johnny Chen3c75c762011-01-22 00:47:08 +0000235 case eEncodingA1:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000236 registers = Bits32(opcode, 15, 0);
Johnny Chena33d4842011-01-24 22:25:48 +0000237 // Instead of return false, let's handle the following case as well,
238 // which amounts to pushing one reg onto the full descending stacks.
239 // if BitCount(register_list) < 2 then SEE STMDB / STMFD;
Johnny Chen3c75c762011-01-22 00:47:08 +0000240 break;
241 case eEncodingA2:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000242 Rt = Bits32(opcode, 15, 12);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000243 // if t == 13 then UNPREDICTABLE;
Johnny Chen91d99862011-01-25 19:07:04 +0000244 if (Rt == dwarf_sp)
Johnny Chen3c75c762011-01-22 00:47:08 +0000245 return false;
Johnny Chen91d99862011-01-25 19:07:04 +0000246 registers = (1u << Rt);
Johnny Chen3c75c762011-01-22 00:47:08 +0000247 break;
Johnny Chence1ca772011-01-25 01:13:00 +0000248 default:
249 return false;
Johnny Chen3c75c762011-01-22 00:47:08 +0000250 }
Johnny Chence1ca772011-01-25 01:13:00 +0000251 addr_t sp_offset = addr_byte_size * BitCount (registers);
Greg Clayton64c84432011-01-21 22:02:52 +0000252 addr_t addr = sp - sp_offset;
253 uint32_t i;
254
255 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
256 for (i=0; i<15; ++i)
257 {
Johnny Chen7c1bf922011-02-08 23:49:37 +0000258 if (BitIsSet (registers, i))
Greg Clayton64c84432011-01-21 22:02:52 +0000259 {
260 context.arg1 = dwarf_r0 + i; // arg1 in the context is the DWARF register number
261 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000262 uint32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
Greg Clayton64c84432011-01-21 22:02:52 +0000263 if (!success)
264 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000265 if (!WriteMemoryUnsigned (context, addr, reg_value, addr_byte_size))
Greg Clayton64c84432011-01-21 22:02:52 +0000266 return false;
267 addr += addr_byte_size;
268 }
269 }
270
Johnny Chen7c1bf922011-02-08 23:49:37 +0000271 if (BitIsSet (registers, 15))
Greg Clayton64c84432011-01-21 22:02:52 +0000272 {
273 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
Johnny Chen3c75c762011-01-22 00:47:08 +0000274 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000275 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Greg Clayton64c84432011-01-21 22:02:52 +0000276 if (!success)
277 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000278 if (!WriteMemoryUnsigned (context, addr, pc + 8, addr_byte_size))
Greg Clayton64c84432011-01-21 22:02:52 +0000279 return false;
280 }
281
282 context.type = EmulateInstruction::eContextAdjustStackPointer;
283 context.arg0 = eRegisterKindGeneric;
284 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +0000285 context.arg2 = -sp_offset;
Greg Clayton64c84432011-01-21 22:02:52 +0000286
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000287 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
Greg Clayton64c84432011-01-21 22:02:52 +0000288 return false;
289 }
290 return true;
291}
292
Johnny Chenef85e912011-01-31 23:07:40 +0000293// Pop Multiple Registers loads multiple registers from the stack, loading from
294// consecutive memory locations staring at the address in SP, and updates
295// SP to point just above the loaded data.
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000296bool
297EmulateInstructionARM::EmulatePop (ARMEncoding encoding)
Johnny Chenef85e912011-01-31 23:07:40 +0000298{
299#if 0
300 // ARM pseudo code...
301 if (ConditionPassed())
302 {
303 EncodingSpecificOperations(); NullCheckIfThumbEE(13);
304 address = SP;
305 for i = 0 to 14
306 if registers<i> == ‘1’ then
307 R[i} = if UnalignedAllowed then MemU[address,4] else MemA[address,4]; address = address + 4;
308 if registers<15> == ‘1’ then
309 if UnalignedAllowed then
310 LoadWritePC(MemU[address,4]);
311 else
312 LoadWritePC(MemA[address,4]);
313 if registers<13> == ‘0’ then SP = SP + 4*BitCount(registers);
314 if registers<13> == ‘1’ then SP = bits(32) UNKNOWN;
315 }
316#endif
317
318 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000319 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chenef85e912011-01-31 23:07:40 +0000320 if (!success)
321 return false;
322
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000323 if (ConditionPassed())
Johnny Chenef85e912011-01-31 23:07:40 +0000324 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000325 const uint32_t addr_byte_size = GetAddressByteSize();
326 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chenef85e912011-01-31 23:07:40 +0000327 if (!success)
328 return false;
329 uint32_t registers = 0;
330 uint32_t Rt; // the destination register
331 switch (encoding) {
332 case eEncodingT1:
333 registers = Bits32(opcode, 7, 0);
334 // The P bit represents PC.
Johnny Chenbd599902011-02-10 21:39:01 +0000335 if (Bit32(opcode, 8))
Johnny Chenef85e912011-01-31 23:07:40 +0000336 registers |= (1u << 15);
337 // if BitCount(registers) < 1 then UNPREDICTABLE;
338 if (BitCount(registers) < 1)
339 return false;
340 break;
341 case eEncodingT2:
342 // Ignore bit 13.
343 registers = Bits32(opcode, 15, 0) & ~0x2000;
344 // if BitCount(registers) < 2 || (P == '1' && M == '1') then UNPREDICTABLE;
Johnny Chenbd599902011-02-10 21:39:01 +0000345 if (BitCount(registers) < 2 || (Bit32(opcode, 15) && Bit32(opcode, 14)))
Johnny Chenef85e912011-01-31 23:07:40 +0000346 return false;
347 break;
348 case eEncodingT3:
349 Rt = Bits32(opcode, 15, 12);
350 // if t == 13 || (t == 15 && InITBlock() && !LastInITBlock()) then UNPREDICTABLE;
351 if (Rt == dwarf_sp)
352 return false;
353 registers = (1u << Rt);
354 break;
355 case eEncodingA1:
356 registers = Bits32(opcode, 15, 0);
357 // Instead of return false, let's handle the following case as well,
358 // which amounts to popping one reg from the full descending stacks.
359 // if BitCount(register_list) < 2 then SEE LDM / LDMIA / LDMFD;
360
361 // if registers<13> == ‘1’ && ArchVersion() >= 7 then UNPREDICTABLE;
Johnny Chenbd599902011-02-10 21:39:01 +0000362 if (Bit32(opcode, 13) && ArchVersion() >= ARMv7)
Johnny Chenef85e912011-01-31 23:07:40 +0000363 return false;
364 break;
365 case eEncodingA2:
366 Rt = Bits32(opcode, 15, 12);
367 // if t == 13 then UNPREDICTABLE;
368 if (Rt == dwarf_sp)
369 return false;
370 registers = (1u << Rt);
371 break;
372 default:
373 return false;
374 }
375 addr_t sp_offset = addr_byte_size * BitCount (registers);
376 addr_t addr = sp;
377 uint32_t i, data;
378
379 EmulateInstruction::Context context = { EmulateInstruction::eContextPopRegisterOffStack, eRegisterKindDWARF, 0, 0 };
380 for (i=0; i<15; ++i)
381 {
Johnny Chen7c1bf922011-02-08 23:49:37 +0000382 if (BitIsSet (registers, i))
Johnny Chenef85e912011-01-31 23:07:40 +0000383 {
384 context.arg1 = dwarf_r0 + i; // arg1 in the context is the DWARF register number
385 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000386 data = ReadMemoryUnsigned(context, addr, 4, 0, &success);
Johnny Chenef85e912011-01-31 23:07:40 +0000387 if (!success)
388 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000389 if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, context.arg1, data))
Johnny Chenef85e912011-01-31 23:07:40 +0000390 return false;
391 addr += addr_byte_size;
392 }
393 }
394
Johnny Chen7c1bf922011-02-08 23:49:37 +0000395 if (BitIsSet (registers, 15))
Johnny Chenef85e912011-01-31 23:07:40 +0000396 {
397 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
398 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000399 data = ReadMemoryUnsigned(context, addr, 4, 0, &success);
Johnny Chenef85e912011-01-31 23:07:40 +0000400 if (!success)
401 return false;
Johnny Chenf3eaacf2011-02-09 19:30:49 +0000402 // In ARMv5T and above, this is an interworking branch.
403 if (!LoadWritePC(context, data))
Johnny Chenef85e912011-01-31 23:07:40 +0000404 return false;
405 addr += addr_byte_size;
406 }
407
408 context.type = EmulateInstruction::eContextAdjustStackPointer;
409 context.arg0 = eRegisterKindGeneric;
410 context.arg1 = LLDB_REGNUM_GENERIC_SP;
411 context.arg2 = sp_offset;
412
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000413 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp + sp_offset))
Johnny Chenef85e912011-01-31 23:07:40 +0000414 return false;
415 }
416 return true;
417}
418
Johnny Chen5b442b72011-01-27 19:34:30 +0000419// Set r7 or ip to point to saved value residing within the stack.
Johnny Chenbcec3af2011-01-27 01:26:19 +0000420// ADD (SP plus immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000421bool
422EmulateInstructionARM::EmulateAddRdSPImmediate (ARMEncoding encoding)
Johnny Chenbcec3af2011-01-27 01:26:19 +0000423{
424#if 0
425 // ARM pseudo code...
426 if (ConditionPassed())
427 {
428 EncodingSpecificOperations();
429 (result, carry, overflow) = AddWithCarry(SP, imm32, ‘0’);
430 if d == 15 then
431 ALUWritePC(result); // setflags is always FALSE here
432 else
433 R[d] = result;
434 if setflags then
435 APSR.N = result<31>;
436 APSR.Z = IsZeroBit(result);
437 APSR.C = carry;
438 APSR.V = overflow;
439 }
440#endif
441
442 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000443 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chenbcec3af2011-01-27 01:26:19 +0000444 if (!success)
445 return false;
446
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000447 if (ConditionPassed())
Johnny Chenbcec3af2011-01-27 01:26:19 +0000448 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000449 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chenbcec3af2011-01-27 01:26:19 +0000450 if (!success)
451 return false;
452 uint32_t Rd; // the destination register
453 uint32_t imm32;
454 switch (encoding) {
455 case eEncodingT1:
456 Rd = 7;
457 imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32)
458 break;
459 case eEncodingA1:
460 Rd = Bits32(opcode, 15, 12);
461 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
462 break;
463 default:
464 return false;
465 }
466 addr_t sp_offset = imm32;
467 addr_t addr = sp + sp_offset; // a pointer to the stack area
468
469 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
470 eRegisterKindGeneric,
471 LLDB_REGNUM_GENERIC_SP,
472 sp_offset };
473
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000474 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, addr))
Johnny Chenbcec3af2011-01-27 01:26:19 +0000475 return false;
476 }
477 return true;
478}
479
Johnny Chen2ccad832011-01-28 19:57:25 +0000480// Set r7 or ip to the current stack pointer.
481// MOV (register)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000482bool
483EmulateInstructionARM::EmulateMovRdSP (ARMEncoding encoding)
Johnny Chen2ccad832011-01-28 19:57:25 +0000484{
485#if 0
486 // ARM pseudo code...
487 if (ConditionPassed())
488 {
489 EncodingSpecificOperations();
490 result = R[m];
491 if d == 15 then
492 ALUWritePC(result); // setflags is always FALSE here
493 else
494 R[d] = result;
495 if setflags then
496 APSR.N = result<31>;
497 APSR.Z = IsZeroBit(result);
498 // APSR.C unchanged
499 // APSR.V unchanged
500 }
501#endif
502
503 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000504 //const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen1c13b622011-01-29 00:11:15 +0000505 //if (!success)
506 // return false;
Johnny Chen2ccad832011-01-28 19:57:25 +0000507
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000508 if (ConditionPassed())
Johnny Chen2ccad832011-01-28 19:57:25 +0000509 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000510 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen2ccad832011-01-28 19:57:25 +0000511 if (!success)
512 return false;
513 uint32_t Rd; // the destination register
514 switch (encoding) {
515 case eEncodingT1:
516 Rd = 7;
517 break;
518 case eEncodingA1:
519 Rd = 12;
520 break;
521 default:
522 return false;
523 }
524 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
525 eRegisterKindGeneric,
526 LLDB_REGNUM_GENERIC_SP,
527 0 };
528
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000529 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, sp))
Johnny Chen2ccad832011-01-28 19:57:25 +0000530 return false;
531 }
532 return true;
533}
534
Johnny Chen1c13b622011-01-29 00:11:15 +0000535// Move from high register (r8-r15) to low register (r0-r7).
536// MOV (register)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000537bool
538EmulateInstructionARM::EmulateMovLowHigh (ARMEncoding encoding)
Johnny Chen1c13b622011-01-29 00:11:15 +0000539{
Johnny Chen338bf542011-02-10 19:29:03 +0000540 return EmulateMovRdRm (encoding);
541}
542
543// Move from register to register.
544// MOV (register)
545bool
546EmulateInstructionARM::EmulateMovRdRm (ARMEncoding encoding)
547{
Johnny Chen1c13b622011-01-29 00:11:15 +0000548#if 0
549 // ARM pseudo code...
550 if (ConditionPassed())
551 {
552 EncodingSpecificOperations();
553 result = R[m];
554 if d == 15 then
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 unchanged
562 // APSR.V unchanged
563 }
564#endif
565
566 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000567 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen1c13b622011-01-29 00:11:15 +0000568 if (!success)
569 return false;
570
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000571 if (ConditionPassed())
Johnny Chen1c13b622011-01-29 00:11:15 +0000572 {
573 uint32_t Rm; // the source register
574 uint32_t Rd; // the destination register
Johnny Chen338bf542011-02-10 19:29:03 +0000575 bool setflags;
Johnny Chen1c13b622011-01-29 00:11:15 +0000576 switch (encoding) {
577 case eEncodingT1:
578 Rm = Bits32(opcode, 6, 3);
Johnny Chenbd599902011-02-10 21:39:01 +0000579 Rd = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 1);
Johnny Chen338bf542011-02-10 19:29:03 +0000580 setflags = false;
581 break;
582 case eEncodingT2:
583 Rm = Bits32(opcode, 5, 3);
584 Rd = Bits32(opcode, 2, 1);
585 setflags = true;
Johnny Chen1c13b622011-01-29 00:11:15 +0000586 break;
587 default:
588 return false;
589 }
Johnny Chen338bf542011-02-10 19:29:03 +0000590 uint32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
Johnny Chen1c13b622011-01-29 00:11:15 +0000591 if (!success)
592 return false;
593
594 // The context specifies that Rm is to be moved into Rd.
595 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
596 eRegisterKindDWARF,
597 dwarf_r0 + Rm,
598 0 };
599
Johnny Chen338bf542011-02-10 19:29:03 +0000600 if (Rd == 15)
601 {
602 if (!ALUWritePC (context, reg_value))
603 return false;
604 }
605 else
606 {
607 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, reg_value))
608 return false;
609 if (setflags)
610 {
611 m_new_inst_cpsr = m_inst_cpsr;
Johnny Chenbd599902011-02-10 21:39:01 +0000612 SetBit32(m_new_inst_cpsr, CPSR_N, Bit32(reg_value, CPSR_N));
613 SetBit32(m_new_inst_cpsr, CPSR_Z, reg_value == 0 ? 1 : 0);
Johnny Chen338bf542011-02-10 19:29:03 +0000614 if (m_new_inst_cpsr != m_inst_cpsr)
615 {
616 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
617 return false;
618 }
619 }
620 }
Johnny Chen1c13b622011-01-29 00:11:15 +0000621 }
622 return true;
623}
624
Johnny Chen788e0552011-01-27 22:52:23 +0000625// PC relative immediate load into register, possibly followed by ADD (SP plus register).
626// LDR (literal)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000627bool
Johnny Chenc9de9102011-02-11 19:12:30 +0000628EmulateInstructionARM::EmulateLDRRtPCRelative (ARMEncoding encoding)
Johnny Chen788e0552011-01-27 22:52:23 +0000629{
630#if 0
631 // ARM pseudo code...
632 if (ConditionPassed())
633 {
634 EncodingSpecificOperations(); NullCheckIfThumbEE(15);
635 base = Align(PC,4);
636 address = if add then (base + imm32) else (base - imm32);
637 data = MemU[address,4];
638 if t == 15 then
639 if address<1:0> == ‘00’ then LoadWritePC(data); else UNPREDICTABLE;
640 elsif UnalignedSupport() || address<1:0> = ‘00’ then
641 R[t] = data;
642 else // Can only apply before ARMv7
643 if CurrentInstrSet() == InstrSet_ARM then
644 R[t] = ROR(data, 8*UInt(address<1:0>));
645 else
646 R[t] = bits(32) UNKNOWN;
647 }
648#endif
649
650 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000651 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen788e0552011-01-27 22:52:23 +0000652 if (!success)
653 return false;
654
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000655 if (ConditionPassed())
Johnny Chen788e0552011-01-27 22:52:23 +0000656 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000657 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Johnny Chen788e0552011-01-27 22:52:23 +0000658 if (!success)
659 return false;
Johnny Chen809742e2011-01-28 00:32:27 +0000660
661 // PC relative immediate load context
662 EmulateInstruction::Context context = {EmulateInstruction::eContextRegisterPlusOffset,
663 eRegisterKindGeneric,
664 LLDB_REGNUM_GENERIC_PC,
665 0};
Johnny Chenc9de9102011-02-11 19:12:30 +0000666 uint32_t Rt; // the destination register
Johnny Chen788e0552011-01-27 22:52:23 +0000667 uint32_t imm32; // immediate offset from the PC
Johnny Chenc9de9102011-02-11 19:12:30 +0000668 bool add; // +imm32 or -imm32?
669 addr_t base; // the base address
670 addr_t address; // the PC relative address
Johnny Chen788e0552011-01-27 22:52:23 +0000671 uint32_t data; // the literal data value from the PC relative load
672 switch (encoding) {
673 case eEncodingT1:
Johnny Chenc9de9102011-02-11 19:12:30 +0000674 Rt = Bits32(opcode, 10, 8);
Johnny Chen788e0552011-01-27 22:52:23 +0000675 imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32);
Johnny Chenc9de9102011-02-11 19:12:30 +0000676 add = true;
677 base = Align(pc + 4, 4);
678 context.arg2 = 4 + imm32;
679 break;
680 case eEncodingT2:
681 Rt = Bits32(opcode, 15, 12);
682 imm32 = Bits32(opcode, 11, 0) << 2; // imm32 = ZeroExtend(imm12, 32);
683 add = BitIsSet(opcode, 23);
684 if (Rt == 15
685 && m_it_session.InITBlock()
686 && !m_it_session.LastInITBlock())
687 return false;
688 base = Align(pc + 4, 4);
Johnny Chen809742e2011-01-28 00:32:27 +0000689 context.arg2 = 4 + imm32;
Johnny Chen788e0552011-01-27 22:52:23 +0000690 break;
691 default:
692 return false;
693 }
Johnny Chenc9de9102011-02-11 19:12:30 +0000694
695 if (add)
696 address = base + imm32;
697 else
698 address = base - imm32;
699 data = ReadMemoryUnsigned(context, address, 4, 0, &success);
Johnny Chen788e0552011-01-27 22:52:23 +0000700 if (!success)
Johnny Chen809742e2011-01-28 00:32:27 +0000701 return false;
Johnny Chenc9de9102011-02-11 19:12:30 +0000702
703 if (Rt == 15)
704 {
705 if (Bits32(address, 1, 0) == 0)
706 {
707 // In ARMv5T and above, this is an interworking branch.
708 if (!LoadWritePC(context, data))
709 return false;
710 }
711 else
712 return false;
713 }
714 else if (UnalignedSupport() || Bits32(address, 1, 0) == 0)
715 {
716 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rt, data))
717 return false;
718 }
719 else // We don't handle ARM for now.
720 return false;
721
722 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rt, data))
Johnny Chen788e0552011-01-27 22:52:23 +0000723 return false;
724 }
725 return true;
726}
727
Johnny Chen5b442b72011-01-27 19:34:30 +0000728// An add operation to adjust the SP.
Johnny Chenfdd179e2011-01-31 20:09:28 +0000729// ADD (SP plus immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000730bool
731EmulateInstructionARM::EmulateAddSPImmediate (ARMEncoding encoding)
Johnny Chenfdd179e2011-01-31 20:09:28 +0000732{
733#if 0
734 // ARM pseudo code...
735 if (ConditionPassed())
736 {
737 EncodingSpecificOperations();
738 (result, carry, overflow) = AddWithCarry(SP, imm32, ‘0’);
739 if d == 15 then // Can only occur for ARM encoding
740 ALUWritePC(result); // setflags is always FALSE here
741 else
742 R[d] = result;
743 if setflags then
744 APSR.N = result<31>;
745 APSR.Z = IsZeroBit(result);
746 APSR.C = carry;
747 APSR.V = overflow;
748 }
749#endif
750
751 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000752 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chenfdd179e2011-01-31 20:09:28 +0000753 if (!success)
754 return false;
755
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000756 if (ConditionPassed())
Johnny Chenfdd179e2011-01-31 20:09:28 +0000757 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000758 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chenfdd179e2011-01-31 20:09:28 +0000759 if (!success)
760 return false;
761 uint32_t imm32; // the immediate operand
762 switch (encoding) {
763 case eEncodingT2:
764 imm32 = ThumbImmScaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
765 break;
766 default:
767 return false;
768 }
769 addr_t sp_offset = imm32;
770 addr_t addr = sp + sp_offset; // the adjusted stack pointer value
771
772 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
773 eRegisterKindGeneric,
774 LLDB_REGNUM_GENERIC_SP,
775 sp_offset };
776
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000777 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
Johnny Chenfdd179e2011-01-31 20:09:28 +0000778 return false;
779 }
780 return true;
781}
782
783// An add operation to adjust the SP.
Johnny Chen5b442b72011-01-27 19:34:30 +0000784// ADD (SP plus register)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000785bool
786EmulateInstructionARM::EmulateAddSPRm (ARMEncoding encoding)
Johnny Chen5b442b72011-01-27 19:34:30 +0000787{
788#if 0
789 // ARM pseudo code...
790 if (ConditionPassed())
791 {
792 EncodingSpecificOperations();
793 shifted = Shift(R[m], shift_t, shift_n, APSR.C);
794 (result, carry, overflow) = AddWithCarry(SP, shifted, ‘0’);
795 if d == 15 then
796 ALUWritePC(result); // setflags is always FALSE here
797 else
798 R[d] = result;
799 if setflags then
800 APSR.N = result<31>;
801 APSR.Z = IsZeroBit(result);
802 APSR.C = carry;
803 APSR.V = overflow;
804 }
805#endif
806
807 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000808 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen5b442b72011-01-27 19:34:30 +0000809 if (!success)
810 return false;
811
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000812 if (ConditionPassed())
Johnny Chen5b442b72011-01-27 19:34:30 +0000813 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000814 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen5b442b72011-01-27 19:34:30 +0000815 if (!success)
816 return false;
817 uint32_t Rm; // the second operand
818 switch (encoding) {
819 case eEncodingT2:
820 Rm = Bits32(opcode, 6, 3);
821 break;
822 default:
823 return false;
824 }
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000825 int32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
Johnny Chen5b442b72011-01-27 19:34:30 +0000826 if (!success)
827 return false;
828
829 addr_t addr = (int32_t)sp + reg_value; // the adjusted stack pointer value
830
831 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
832 eRegisterKindGeneric,
833 LLDB_REGNUM_GENERIC_SP,
834 reg_value };
835
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000836 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
Johnny Chen5b442b72011-01-27 19:34:30 +0000837 return false;
838 }
839 return true;
840}
841
Johnny Chen9b8d7832011-02-02 01:13:56 +0000842// Branch with Link and Exchange Instruction Sets (immediate) calls a subroutine
843// at a PC-relative address, and changes instruction set from ARM to Thumb, or
844// from Thumb to ARM.
845// BLX (immediate)
846bool
847EmulateInstructionARM::EmulateBLXImmediate (ARMEncoding encoding)
848{
849#if 0
850 // ARM pseudo code...
851 if (ConditionPassed())
852 {
853 EncodingSpecificOperations();
854 if CurrentInstrSet() == InstrSet_ARM then
855 LR = PC - 4;
856 else
857 LR = PC<31:1> : '1';
858 if targetInstrSet == InstrSet_ARM then
859 targetAddress = Align(PC,4) + imm32;
860 else
861 targetAddress = PC + imm32;
862 SelectInstrSet(targetInstrSet);
863 BranchWritePC(targetAddress);
864 }
865#endif
866
867 bool success = false;
868 const uint32_t opcode = OpcodeAsUnsigned (&success);
869 if (!success)
870 return false;
871
872 if (ConditionPassed())
873 {
874 EmulateInstruction::Context context = { EmulateInstruction::eContextRelativeBranchImmediate, 0, 0, 0};
875 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Johnny Chen9b8d7832011-02-02 01:13:56 +0000876 if (!success)
877 return false;
Johnny Chen53ebab72011-02-08 23:21:57 +0000878 addr_t lr; // next instruction address
879 addr_t target; // target address
Johnny Chen9b8d7832011-02-02 01:13:56 +0000880 int32_t imm32; // PC-relative offset
881 switch (encoding) {
Johnny Chend6c13f02011-02-08 20:36:34 +0000882 case eEncodingT1:
883 {
884 lr = (pc + 4) | 1u; // return address
Johnny Chenbd599902011-02-10 21:39:01 +0000885 uint32_t S = Bit32(opcode, 26);
Johnny Chend6c13f02011-02-08 20:36:34 +0000886 uint32_t imm10 = Bits32(opcode, 25, 16);
Johnny Chenbd599902011-02-10 21:39:01 +0000887 uint32_t J1 = Bit32(opcode, 13);
888 uint32_t J2 = Bit32(opcode, 11);
Johnny Chend6c13f02011-02-08 20:36:34 +0000889 uint32_t imm11 = Bits32(opcode, 10, 0);
890 uint32_t I1 = !(J1 ^ S);
891 uint32_t I2 = !(J2 ^ S);
Johnny Chen53ebab72011-02-08 23:21:57 +0000892 uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
Johnny Chend6c13f02011-02-08 20:36:34 +0000893 imm32 = llvm::SignExtend32<25>(imm25);
894 target = pc + 4 + imm32;
895 context.arg1 = 4 + imm32; // signed offset
896 context.arg2 = eModeThumb; // target instruction set
897 break;
898 }
Johnny Chen9b8d7832011-02-02 01:13:56 +0000899 case eEncodingT2:
900 {
901 lr = (pc + 4) | 1u; // return address
Johnny Chenbd599902011-02-10 21:39:01 +0000902 uint32_t S = Bit32(opcode, 26);
Johnny Chen9b8d7832011-02-02 01:13:56 +0000903 uint32_t imm10H = Bits32(opcode, 25, 16);
Johnny Chenbd599902011-02-10 21:39:01 +0000904 uint32_t J1 = Bit32(opcode, 13);
905 uint32_t J2 = Bit32(opcode, 11);
Johnny Chen9b8d7832011-02-02 01:13:56 +0000906 uint32_t imm10L = Bits32(opcode, 10, 1);
907 uint32_t I1 = !(J1 ^ S);
908 uint32_t I2 = !(J2 ^ S);
Johnny Chen53ebab72011-02-08 23:21:57 +0000909 uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10H << 12) | (imm10L << 2);
Johnny Chen9b8d7832011-02-02 01:13:56 +0000910 imm32 = llvm::SignExtend32<25>(imm25);
Johnny Chend6c13f02011-02-08 20:36:34 +0000911 target = Align(pc + 4, 4) + imm32;
912 context.arg1 = 4 + imm32; // signed offset
913 context.arg2 = eModeARM; // target instruction set
Johnny Chen9b8d7832011-02-02 01:13:56 +0000914 break;
915 }
Johnny Chenc47d0ca2011-02-08 18:58:31 +0000916 case eEncodingA1:
917 lr = pc + 4; // return address
918 imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2);
Johnny Chend6c13f02011-02-08 20:36:34 +0000919 target = Align(pc + 8, 4) + imm32;
920 context.arg1 = 8 + imm32; // signed offset
921 context.arg2 = eModeARM; // target instruction set
Johnny Chenc47d0ca2011-02-08 18:58:31 +0000922 break;
Johnny Chen9b8d7832011-02-02 01:13:56 +0000923 case eEncodingA2:
924 lr = pc + 4; // return address
925 imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2 | Bits32(opcode, 24, 24) << 1);
926 target = pc + 8 + imm32;
Johnny Chen9ee056b2011-02-08 00:06:35 +0000927 context.arg1 = 8 + imm32; // signed offset
928 context.arg2 = eModeThumb; // target instruction set
Johnny Chen9b8d7832011-02-02 01:13:56 +0000929 break;
930 default:
931 return false;
932 }
933 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
934 return false;
Johnny Chen9ee056b2011-02-08 00:06:35 +0000935 if (!BranchWritePC(context, target))
Johnny Chen9b8d7832011-02-02 01:13:56 +0000936 return false;
937 }
938 return true;
939}
940
941// Branch with Link and Exchange (register) calls a subroutine at an address and
942// instruction set specified by a register.
943// BLX (register)
944bool
945EmulateInstructionARM::EmulateBLXRm (ARMEncoding encoding)
946{
947#if 0
948 // ARM pseudo code...
949 if (ConditionPassed())
950 {
951 EncodingSpecificOperations();
952 target = R[m];
953 if CurrentInstrSet() == InstrSet_ARM then
954 next_instr_addr = PC - 4;
955 LR = next_instr_addr;
956 else
957 next_instr_addr = PC - 2;
958 LR = next_instr_addr<31:1> : ‘1’;
959 BXWritePC(target);
960 }
961#endif
962
963 bool success = false;
964 const uint32_t opcode = OpcodeAsUnsigned (&success);
965 if (!success)
966 return false;
967
968 if (ConditionPassed())
969 {
970 EmulateInstruction::Context context = { EmulateInstruction::eContextAbsoluteBranchRegister, 0, 0, 0};
971 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
972 addr_t lr; // next instruction address
973 addr_t target; // target address
974 if (!success)
975 return false;
976 uint32_t Rm; // the register with the target address
977 switch (encoding) {
978 case eEncodingT1:
979 lr = (pc + 2) | 1u; // return address
980 Rm = Bits32(opcode, 6, 3);
981 // if m == 15 then UNPREDICTABLE;
982 if (Rm == 15)
983 return false;
984 target = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
985 break;
986 case eEncodingA1:
987 lr = pc + 4; // return address
988 Rm = Bits32(opcode, 3, 0);
989 // if m == 15 then UNPREDICTABLE;
990 if (Rm == 15)
991 return false;
992 target = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
Johnny Chenb77be412011-02-04 00:40:18 +0000993 break;
Johnny Chen9b8d7832011-02-02 01:13:56 +0000994 default:
995 return false;
996 }
Johnny Chen9b8d7832011-02-02 01:13:56 +0000997 context.arg0 = eRegisterKindDWARF;
998 context.arg1 = dwarf_r0 + Rm;
Johnny Chen9b8d7832011-02-02 01:13:56 +0000999 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
1000 return false;
Johnny Chen9ee056b2011-02-08 00:06:35 +00001001 if (!BXWritePC(context, target))
Johnny Chen9b8d7832011-02-02 01:13:56 +00001002 return false;
1003 }
1004 return true;
1005}
1006
Johnny Chen0d0148e2011-01-28 02:26:08 +00001007// Set r7 to point to some ip offset.
1008// SUB (immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001009bool
1010EmulateInstructionARM::EmulateSubR7IPImmediate (ARMEncoding encoding)
Johnny Chen0d0148e2011-01-28 02:26:08 +00001011{
1012#if 0
1013 // ARM pseudo code...
1014 if (ConditionPassed())
1015 {
1016 EncodingSpecificOperations();
1017 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), ‘1’);
1018 if d == 15 then // Can only occur for ARM encoding
1019 ALUWritePC(result); // setflags is always FALSE here
1020 else
1021 R[d] = result;
1022 if setflags then
1023 APSR.N = result<31>;
1024 APSR.Z = IsZeroBit(result);
1025 APSR.C = carry;
1026 APSR.V = overflow;
1027 }
1028#endif
1029
1030 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001031 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen0d0148e2011-01-28 02:26:08 +00001032 if (!success)
1033 return false;
1034
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001035 if (ConditionPassed())
Johnny Chen0d0148e2011-01-28 02:26:08 +00001036 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001037 const addr_t ip = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r12, 0, &success);
Johnny Chen0d0148e2011-01-28 02:26:08 +00001038 if (!success)
1039 return false;
1040 uint32_t imm32;
1041 switch (encoding) {
1042 case eEncodingA1:
1043 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
1044 break;
1045 default:
1046 return false;
1047 }
1048 addr_t ip_offset = imm32;
1049 addr_t addr = ip - ip_offset; // the adjusted ip value
1050
1051 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
1052 eRegisterKindDWARF,
1053 dwarf_r12,
1054 -ip_offset };
1055
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001056 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r7, addr))
Johnny Chen0d0148e2011-01-28 02:26:08 +00001057 return false;
1058 }
1059 return true;
1060}
1061
1062// Set ip to point to some stack offset.
1063// SUB (SP minus immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001064bool
1065EmulateInstructionARM::EmulateSubIPSPImmediate (ARMEncoding encoding)
Johnny Chen0d0148e2011-01-28 02:26:08 +00001066{
1067#if 0
1068 // ARM pseudo code...
1069 if (ConditionPassed())
1070 {
1071 EncodingSpecificOperations();
1072 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), ‘1’);
1073 if d == 15 then // Can only occur for ARM encoding
1074 ALUWritePC(result); // setflags is always FALSE here
1075 else
1076 R[d] = result;
1077 if setflags then
1078 APSR.N = result<31>;
1079 APSR.Z = IsZeroBit(result);
1080 APSR.C = carry;
1081 APSR.V = overflow;
1082 }
1083#endif
1084
1085 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001086 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen0d0148e2011-01-28 02:26:08 +00001087 if (!success)
1088 return false;
1089
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001090 if (ConditionPassed())
Johnny Chen0d0148e2011-01-28 02:26:08 +00001091 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001092 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen0d0148e2011-01-28 02:26:08 +00001093 if (!success)
1094 return false;
1095 uint32_t imm32;
1096 switch (encoding) {
1097 case eEncodingA1:
1098 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
1099 break;
1100 default:
1101 return false;
1102 }
1103 addr_t sp_offset = imm32;
1104 addr_t addr = sp - sp_offset; // the adjusted stack pointer value
1105
1106 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
1107 eRegisterKindGeneric,
1108 LLDB_REGNUM_GENERIC_SP,
1109 -sp_offset };
1110
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001111 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r12, addr))
Johnny Chen0d0148e2011-01-28 02:26:08 +00001112 return false;
1113 }
1114 return true;
1115}
1116
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001117// A sub operation to adjust the SP -- allocate space for local storage.
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001118bool
1119EmulateInstructionARM::EmulateSubSPImmdiate (ARMEncoding encoding)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001120{
1121#if 0
1122 // ARM pseudo code...
1123 if (ConditionPassed())
1124 {
1125 EncodingSpecificOperations();
1126 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), ‘1’);
1127 if d == 15 then // Can only occur for ARM encoding
Johnny Chen799dfd02011-01-26 23:14:33 +00001128 ALUWritePC(result); // setflags is always FALSE here
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001129 else
1130 R[d] = result;
1131 if setflags then
1132 APSR.N = result<31>;
1133 APSR.Z = IsZeroBit(result);
1134 APSR.C = carry;
1135 APSR.V = overflow;
1136 }
1137#endif
1138
1139 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001140 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001141 if (!success)
1142 return false;
1143
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001144 if (ConditionPassed())
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001145 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001146 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001147 if (!success)
1148 return false;
1149 uint32_t imm32;
1150 switch (encoding) {
Johnny Chene4455022011-01-26 00:08:59 +00001151 case eEncodingT1:
1152 imm32 = ThumbImmScaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
Johnny Chen60c0d622011-01-25 23:49:39 +00001153 case eEncodingT2:
1154 imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
1155 break;
1156 case eEncodingT3:
1157 imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32)
1158 break;
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001159 case eEncodingA1:
Johnny Chen60c0d622011-01-25 23:49:39 +00001160 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001161 break;
1162 default:
1163 return false;
1164 }
1165 addr_t sp_offset = imm32;
1166 addr_t addr = sp - sp_offset; // the adjusted stack pointer value
1167
1168 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
1169 eRegisterKindGeneric,
1170 LLDB_REGNUM_GENERIC_SP,
Johnny Chen5b442b72011-01-27 19:34:30 +00001171 -sp_offset };
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001172
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001173 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001174 return false;
1175 }
1176 return true;
1177}
1178
Johnny Chen08c25e82011-01-31 18:02:28 +00001179// A store operation to the stack that also updates the SP.
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001180bool
1181EmulateInstructionARM::EmulateSTRRtSP (ARMEncoding encoding)
Johnny Chence1ca772011-01-25 01:13:00 +00001182{
1183#if 0
1184 // ARM pseudo code...
1185 if (ConditionPassed())
1186 {
1187 EncodingSpecificOperations();
1188 offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
1189 address = if index then offset_addr else R[n];
1190 MemU[address,4] = if t == 15 then PCStoreValue() else R[t];
1191 if wback then R[n] = offset_addr;
1192 }
1193#endif
1194
1195 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001196 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chence1ca772011-01-25 01:13:00 +00001197 if (!success)
1198 return false;
1199
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001200 if (ConditionPassed())
Johnny Chence1ca772011-01-25 01:13:00 +00001201 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001202 const uint32_t addr_byte_size = GetAddressByteSize();
1203 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chence1ca772011-01-25 01:13:00 +00001204 if (!success)
1205 return false;
Johnny Chen91d99862011-01-25 19:07:04 +00001206 uint32_t Rt; // the source register
Johnny Chence1ca772011-01-25 01:13:00 +00001207 uint32_t imm12;
1208 switch (encoding) {
1209 case eEncodingA1:
Johnny Chen108d5aa2011-01-26 01:00:55 +00001210 Rt = Bits32(opcode, 15, 12);
1211 imm12 = Bits32(opcode, 11, 0);
Johnny Chence1ca772011-01-25 01:13:00 +00001212 break;
1213 default:
1214 return false;
1215 }
1216 addr_t sp_offset = imm12;
1217 addr_t addr = sp - sp_offset;
1218
1219 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
Johnny Chen91d99862011-01-25 19:07:04 +00001220 if (Rt != 15)
Johnny Chence1ca772011-01-25 01:13:00 +00001221 {
Johnny Chen91d99862011-01-25 19:07:04 +00001222 context.arg1 = dwarf_r0 + Rt; // arg1 in the context is the DWARF register number
1223 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001224 uint32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
Johnny Chence1ca772011-01-25 01:13:00 +00001225 if (!success)
1226 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001227 if (!WriteMemoryUnsigned (context, addr, reg_value, addr_byte_size))
Johnny Chence1ca772011-01-25 01:13:00 +00001228 return false;
1229 }
1230 else
1231 {
1232 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
1233 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001234 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Johnny Chence1ca772011-01-25 01:13:00 +00001235 if (!success)
1236 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001237 if (!WriteMemoryUnsigned (context, addr, pc + 8, addr_byte_size))
Johnny Chence1ca772011-01-25 01:13:00 +00001238 return false;
1239 }
1240
1241 context.type = EmulateInstruction::eContextAdjustStackPointer;
1242 context.arg0 = eRegisterKindGeneric;
1243 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +00001244 context.arg2 = -sp_offset;
Johnny Chence1ca772011-01-25 01:13:00 +00001245
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001246 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
Johnny Chence1ca772011-01-25 01:13:00 +00001247 return false;
1248 }
1249 return true;
1250}
1251
Johnny Chen08c25e82011-01-31 18:02:28 +00001252// Vector Push stores multiple extension registers to the stack.
1253// It also updates SP to point to the start of the stored data.
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001254bool
1255EmulateInstructionARM::EmulateVPUSH (ARMEncoding encoding)
Johnny Chen799dfd02011-01-26 23:14:33 +00001256{
1257#if 0
1258 // ARM pseudo code...
1259 if (ConditionPassed())
1260 {
1261 EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13);
1262 address = SP - imm32;
1263 SP = SP - imm32;
1264 if single_regs then
1265 for r = 0 to regs-1
1266 MemA[address,4] = S[d+r]; address = address+4;
1267 else
1268 for r = 0 to regs-1
1269 // Store as two word-aligned words in the correct order for current endianness.
1270 MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>;
1271 MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>;
1272 address = address+8;
1273 }
1274#endif
1275
1276 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001277 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen799dfd02011-01-26 23:14:33 +00001278 if (!success)
1279 return false;
1280
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001281 if (ConditionPassed())
Johnny Chen799dfd02011-01-26 23:14:33 +00001282 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001283 const uint32_t addr_byte_size = GetAddressByteSize();
1284 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen799dfd02011-01-26 23:14:33 +00001285 if (!success)
1286 return false;
1287 bool single_regs;
Johnny Chen587a0a42011-02-01 18:35:28 +00001288 uint32_t d; // UInt(D:Vd) or UInt(Vd:D) starting register
Johnny Chen799dfd02011-01-26 23:14:33 +00001289 uint32_t imm32; // stack offset
1290 uint32_t regs; // number of registers
1291 switch (encoding) {
1292 case eEncodingT1:
1293 case eEncodingA1:
1294 single_regs = false;
Johnny Chenbd599902011-02-10 21:39:01 +00001295 d = Bit32(opcode, 22) << 4 | Bits32(opcode, 15, 12);
Johnny Chen799dfd02011-01-26 23:14:33 +00001296 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1297 // If UInt(imm8) is odd, see "FSTMX".
1298 regs = Bits32(opcode, 7, 0) / 2;
1299 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1300 if (regs == 0 || regs > 16 || (d + regs) > 32)
1301 return false;
1302 break;
1303 case eEncodingT2:
1304 case eEncodingA2:
1305 single_regs = true;
Johnny Chenbd599902011-02-10 21:39:01 +00001306 d = Bits32(opcode, 15, 12) << 1 | Bit32(opcode, 22);
Johnny Chen799dfd02011-01-26 23:14:33 +00001307 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1308 regs = Bits32(opcode, 7, 0);
1309 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1310 if (regs == 0 || regs > 16 || (d + regs) > 32)
1311 return false;
1312 break;
1313 default:
1314 return false;
1315 }
1316 uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
1317 uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2;
1318 addr_t sp_offset = imm32;
1319 addr_t addr = sp - sp_offset;
1320 uint32_t i;
1321
1322 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
1323 for (i=d; i<regs; ++i)
1324 {
1325 context.arg1 = start_reg + i; // arg1 in the context is the DWARF register number
1326 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
1327 // uint64_t to accommodate 64-bit registers.
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001328 uint64_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
Johnny Chen799dfd02011-01-26 23:14:33 +00001329 if (!success)
1330 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001331 if (!WriteMemoryUnsigned (context, addr, reg_value, reg_byte_size))
Johnny Chen799dfd02011-01-26 23:14:33 +00001332 return false;
1333 addr += reg_byte_size;
1334 }
1335
1336 context.type = EmulateInstruction::eContextAdjustStackPointer;
1337 context.arg0 = eRegisterKindGeneric;
1338 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +00001339 context.arg2 = -sp_offset;
Johnny Chen799dfd02011-01-26 23:14:33 +00001340
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001341 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
Johnny Chen799dfd02011-01-26 23:14:33 +00001342 return false;
1343 }
1344 return true;
1345}
1346
Johnny Chen587a0a42011-02-01 18:35:28 +00001347// Vector Pop loads multiple extension registers from the stack.
1348// It also updates SP to point just above the loaded data.
1349bool
1350EmulateInstructionARM::EmulateVPOP (ARMEncoding encoding)
1351{
1352#if 0
1353 // ARM pseudo code...
1354 if (ConditionPassed())
1355 {
1356 EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13);
1357 address = SP;
1358 SP = SP + imm32;
1359 if single_regs then
1360 for r = 0 to regs-1
1361 S[d+r] = MemA[address,4]; address = address+4;
1362 else
1363 for r = 0 to regs-1
1364 word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8;
1365 // Combine the word-aligned words in the correct order for current endianness.
1366 D[d+r] = if BigEndian() then word1:word2 else word2:word1;
1367 }
1368#endif
1369
1370 bool success = false;
1371 const uint32_t opcode = OpcodeAsUnsigned (&success);
1372 if (!success)
1373 return false;
1374
1375 if (ConditionPassed())
1376 {
1377 const uint32_t addr_byte_size = GetAddressByteSize();
1378 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
1379 if (!success)
1380 return false;
1381 bool single_regs;
1382 uint32_t d; // UInt(D:Vd) or UInt(Vd:D) starting register
1383 uint32_t imm32; // stack offset
1384 uint32_t regs; // number of registers
1385 switch (encoding) {
1386 case eEncodingT1:
1387 case eEncodingA1:
1388 single_regs = false;
Johnny Chenbd599902011-02-10 21:39:01 +00001389 d = Bit32(opcode, 22) << 4 | Bits32(opcode, 15, 12);
Johnny Chen587a0a42011-02-01 18:35:28 +00001390 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1391 // If UInt(imm8) is odd, see "FLDMX".
1392 regs = Bits32(opcode, 7, 0) / 2;
1393 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1394 if (regs == 0 || regs > 16 || (d + regs) > 32)
1395 return false;
1396 break;
1397 case eEncodingT2:
1398 case eEncodingA2:
1399 single_regs = true;
Johnny Chenbd599902011-02-10 21:39:01 +00001400 d = Bits32(opcode, 15, 12) << 1 | Bit32(opcode, 22);
Johnny Chen587a0a42011-02-01 18:35:28 +00001401 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1402 regs = Bits32(opcode, 7, 0);
1403 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1404 if (regs == 0 || regs > 16 || (d + regs) > 32)
1405 return false;
1406 break;
1407 default:
1408 return false;
1409 }
1410 uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
1411 uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2;
1412 addr_t sp_offset = imm32;
1413 addr_t addr = sp;
1414 uint32_t i;
1415 uint64_t data; // uint64_t to accomodate 64-bit registers.
1416
1417 EmulateInstruction::Context context = { EmulateInstruction::eContextPopRegisterOffStack, eRegisterKindDWARF, 0, 0 };
1418 for (i=d; i<regs; ++i)
1419 {
1420 context.arg1 = start_reg + i; // arg1 in the context is the DWARF register number
1421 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
1422 data = ReadMemoryUnsigned(context, addr, reg_byte_size, 0, &success);
1423 if (!success)
1424 return false;
1425 if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, context.arg1, data))
1426 return false;
1427 addr += reg_byte_size;
1428 }
1429
1430 context.type = EmulateInstruction::eContextAdjustStackPointer;
1431 context.arg0 = eRegisterKindGeneric;
1432 context.arg1 = LLDB_REGNUM_GENERIC_SP;
1433 context.arg2 = sp_offset;
1434
1435 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp + sp_offset))
1436 return false;
1437 }
1438 return true;
1439}
1440
Johnny Chenb77be412011-02-04 00:40:18 +00001441// SVC (previously SWI)
1442bool
1443EmulateInstructionARM::EmulateSVC (ARMEncoding encoding)
1444{
1445#if 0
1446 // ARM pseudo code...
1447 if (ConditionPassed())
1448 {
1449 EncodingSpecificOperations();
1450 CallSupervisor();
1451 }
1452#endif
1453
1454 bool success = false;
1455 const uint32_t opcode = OpcodeAsUnsigned (&success);
1456 if (!success)
1457 return false;
1458
1459 if (ConditionPassed())
1460 {
1461 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1462 addr_t lr; // next instruction address
1463 if (!success)
1464 return false;
1465 uint32_t imm32; // the immediate constant
1466 uint32_t mode; // ARM or Thumb mode
1467 switch (encoding) {
1468 case eEncodingT1:
1469 lr = (pc + 2) | 1u; // return address
1470 imm32 = Bits32(opcode, 7, 0);
1471 mode = eModeThumb;
1472 break;
1473 case eEncodingA1:
1474 lr = pc + 4; // return address
1475 imm32 = Bits32(opcode, 23, 0);
1476 mode = eModeARM;
1477 break;
1478 default:
1479 return false;
1480 }
1481 EmulateInstruction::Context context = { EmulateInstruction::eContextSupervisorCall, mode, imm32, 0};
1482 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
1483 return false;
1484 }
1485 return true;
1486}
1487
Johnny Chenc315f862011-02-05 00:46:10 +00001488// If Then makes up to four following instructions (the IT block) conditional.
1489bool
1490EmulateInstructionARM::EmulateIT (ARMEncoding encoding)
1491{
1492#if 0
1493 // ARM pseudo code...
1494 EncodingSpecificOperations();
1495 ITSTATE.IT<7:0> = firstcond:mask;
1496#endif
1497
1498 bool success = false;
1499 const uint32_t opcode = OpcodeAsUnsigned (&success);
1500 if (!success)
1501 return false;
1502
1503 m_it_session.InitIT(Bits32(opcode, 7, 0));
1504 return true;
1505}
1506
Johnny Chen3b620b32011-02-07 20:11:47 +00001507// Branch causes a branch to a target address.
1508bool
1509EmulateInstructionARM::EmulateB (ARMEncoding encoding)
1510{
1511#if 0
1512 // ARM pseudo code...
1513 if (ConditionPassed())
1514 {
1515 EncodingSpecificOperations();
1516 BranchWritePC(PC + imm32);
1517 }
1518#endif
1519
1520 bool success = false;
1521 const uint32_t opcode = OpcodeAsUnsigned (&success);
1522 if (!success)
1523 return false;
1524
Johnny Chen9ee056b2011-02-08 00:06:35 +00001525 if (ConditionPassed())
1526 {
1527 EmulateInstruction::Context context = { EmulateInstruction::eContextRelativeBranchImmediate, 0, 0, 0};
1528 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001529 if (!success)
1530 return false;
Johnny Chen53ebab72011-02-08 23:21:57 +00001531 addr_t target; // target address
Johnny Chen9ee056b2011-02-08 00:06:35 +00001532 int32_t imm32; // PC-relative offset
1533 switch (encoding) {
1534 case eEncodingT1:
1535 // The 'cond' field is handled in EmulateInstructionARM::CurrentCond().
1536 imm32 = llvm::SignExtend32<9>(Bits32(opcode, 7, 0) << 1);
1537 target = pc + 4 + imm32;
1538 context.arg1 = 4 + imm32; // signed offset
1539 context.arg2 = eModeThumb; // target instruction set
1540 break;
1541 case eEncodingT2:
1542 imm32 = llvm::SignExtend32<12>(Bits32(opcode, 10, 0));
1543 target = pc + 4 + imm32;
1544 context.arg1 = 4 + imm32; // signed offset
1545 context.arg2 = eModeThumb; // target instruction set
1546 break;
1547 case eEncodingT3:
1548 // The 'cond' field is handled in EmulateInstructionARM::CurrentCond().
1549 {
Johnny Chenbd599902011-02-10 21:39:01 +00001550 uint32_t S = Bit32(opcode, 26);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001551 uint32_t imm6 = Bits32(opcode, 21, 16);
Johnny Chenbd599902011-02-10 21:39:01 +00001552 uint32_t J1 = Bit32(opcode, 13);
1553 uint32_t J2 = Bit32(opcode, 11);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001554 uint32_t imm11 = Bits32(opcode, 10, 0);
Johnny Chen53ebab72011-02-08 23:21:57 +00001555 uint32_t imm21 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001556 imm32 = llvm::SignExtend32<21>(imm21);
1557 target = pc + 4 + imm32;
1558 context.arg1 = eModeThumb; // target instruction set
1559 context.arg2 = 4 + imm32; // signed offset
1560 break;
1561 }
1562 case eEncodingT4:
1563 {
Johnny Chenbd599902011-02-10 21:39:01 +00001564 uint32_t S = Bit32(opcode, 26);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001565 uint32_t imm10 = Bits32(opcode, 25, 16);
Johnny Chenbd599902011-02-10 21:39:01 +00001566 uint32_t J1 = Bit32(opcode, 13);
1567 uint32_t J2 = Bit32(opcode, 11);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001568 uint32_t imm11 = Bits32(opcode, 10, 0);
1569 uint32_t I1 = !(J1 ^ S);
1570 uint32_t I2 = !(J2 ^ S);
Johnny Chen53ebab72011-02-08 23:21:57 +00001571 uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001572 imm32 = llvm::SignExtend32<25>(imm25);
1573 target = pc + 4 + imm32;
1574 context.arg1 = eModeThumb; // target instruction set
1575 context.arg2 = 4 + imm32; // signed offset
1576 break;
1577 }
1578 case eEncodingA1:
1579 imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2);
1580 target = pc + 8 + imm32;
1581 context.arg1 = eModeARM; // target instruction set
1582 context.arg2 = 8 + imm32; // signed offset
1583 break;
1584 default:
1585 return false;
1586 }
1587 if (!BranchWritePC(context, target))
1588 return false;
1589 }
1590 return true;
Johnny Chen3b620b32011-02-07 20:11:47 +00001591}
1592
Johnny Chen53ebab72011-02-08 23:21:57 +00001593// Compare and Branch on Nonzero and Compare and Branch on Zero compare the value in a register with
1594// zero and conditionally branch forward a constant value. They do not affect the condition flags.
1595// CBNZ, CBZ
1596bool
1597EmulateInstructionARM::EmulateCB (ARMEncoding encoding)
1598{
1599#if 0
1600 // ARM pseudo code...
1601 EncodingSpecificOperations();
1602 if nonzero ^ IsZero(R[n]) then
1603 BranchWritePC(PC + imm32);
1604#endif
1605
1606 bool success = false;
1607 const uint32_t opcode = OpcodeAsUnsigned (&success);
1608 if (!success)
1609 return false;
1610
1611 // Read the register value from the operand register Rn.
1612 uint32_t reg_val = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Bits32(opcode, 2, 0), 0, &success);
1613 if (!success)
1614 return false;
1615
1616 EmulateInstruction::Context context = { EmulateInstruction::eContextRelativeBranchImmediate, 0, 0, 0};
1617 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1618 if (!success)
1619 return false;
1620
1621 addr_t target; // target address
1622 uint32_t imm32; // PC-relative offset to branch forward
1623 bool nonzero;
1624 switch (encoding) {
1625 case eEncodingT1:
Johnny Chenbd599902011-02-10 21:39:01 +00001626 imm32 = Bit32(opcode, 9) << 6 | Bits32(opcode, 7, 3) << 1;
Johnny Chen53ebab72011-02-08 23:21:57 +00001627 nonzero = BitIsSet(opcode, 11);
1628 target = pc + 4 + imm32;
1629 context.arg1 = 4 + imm32; // signed offset
1630 context.arg2 = eModeThumb; // target instruction set
1631 break;
1632 default:
1633 return false;
1634 }
1635 if (nonzero ^ (reg_val == 0))
1636 if (!BranchWritePC(context, target))
1637 return false;
1638
1639 return true;
1640}
1641
Johnny Chen26863dc2011-02-09 23:43:29 +00001642// ADD <Rdn>, <Rm>
1643// where <Rdn> the destination register is also the first operand register
1644// and <Rm> is the second operand register.
1645bool
1646EmulateInstructionARM::EmulateAddRdnRm (ARMEncoding encoding)
1647{
1648#if 0
1649 // ARM pseudo code...
1650 if ConditionPassed() then
1651 EncodingSpecificOperations();
1652 shifted = Shift(R[m], shift_t, shift_n, APSR.C);
1653 (result, carry, overflow) = AddWithCarry(R[n], shifted, '0');
1654 if d == 15 then
1655 ALUWritePC(result); // setflags is always FALSE here
1656 else
1657 R[d] = result;
1658 if setflags then
1659 APSR.N = result<31>;
1660 APSR.Z = IsZeroBit(result);
1661 APSR.C = carry;
1662 APSR.V = overflow;
1663#endif
1664
1665 bool success = false;
1666 const uint32_t opcode = OpcodeAsUnsigned (&success);
1667 if (!success)
1668 return false;
1669
1670 if (ConditionPassed())
1671 {
1672 uint32_t Rd, Rn, Rm;
1673 //bool setflags = false;
1674 switch (encoding)
1675 {
1676 case eEncodingT2:
1677 // setflags = FALSE
Johnny Chenbd599902011-02-10 21:39:01 +00001678 Rd = Rn = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0);
Johnny Chen26863dc2011-02-09 23:43:29 +00001679 Rm = Bits32(opcode, 6, 3);
1680 if (Rn == 15 && Rm == 15)
1681 return false;
1682 break;
1683 default:
1684 return false;
1685 }
1686
1687 int32_t result, val1, val2;
1688 // Read the first operand.
1689 if (Rn == 15)
1690 val1 = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1691 else
1692 val1 = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success);
1693 if (!success)
1694 return false;
1695
1696 // Read the second operand.
1697 if (Rm == 15)
1698 val2 = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1699 else
1700 val2 = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
1701 if (!success)
1702 return false;
1703
1704 result = val1 + val2;
1705 EmulateInstruction::Context context = { EmulateInstruction::eContextImmediate,
1706 result,
1707 0,
1708 0 };
1709
1710 if (Rd == 15)
1711 {
1712 if (!ALUWritePC (context, result))
1713 return false;
1714 }
1715 else
1716 {
1717 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, result))
1718 return false;
1719 }
1720 }
1721 return true;
1722}
1723
Johnny Chene4a4d302011-02-11 21:53:58 +00001724// CMP (immediate)
Johnny Chend4dc4442011-02-11 02:02:56 +00001725bool
1726EmulateInstructionARM::EmulateCmpRnImm (ARMEncoding encoding)
1727{
1728#if 0
1729 // ARM pseudo code...
1730 if ConditionPassed() then
1731 EncodingSpecificOperations();
1732 (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1');
1733 APSR.N = result<31>;
1734 APSR.Z = IsZeroBit(result);
1735 APSR.C = carry;
1736 APSR.V = overflow;
1737#endif
1738
1739 bool success = false;
1740 const uint32_t opcode = OpcodeAsUnsigned (&success);
1741 if (!success)
1742 return false;
1743
1744 uint32_t Rn; // the first operand
1745 uint32_t imm32; // the immediate value to be compared with
1746 switch (encoding) {
1747 case eEncodingT1:
1748 Rn = Bits32(opcode, 10, 8);
1749 imm32 = Bits32(opcode, 7, 0);
1750 break;
1751 default:
1752 return false;
1753 }
1754 // Read the register value from the operand register Rn.
1755 uint32_t reg_val = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success);
1756 if (!success)
1757 return false;
1758
1759 EmulateInstruction::Context context = { EmulateInstruction::eContextImmediate, 0, 0, 0};
1760 AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1);
1761 m_new_inst_cpsr = m_inst_cpsr;
1762 SetBit32(m_new_inst_cpsr, CPSR_N, Bit32(res.result, CPSR_N));
1763 SetBit32(m_new_inst_cpsr, CPSR_Z, res.result == 0 ? 1 : 0);
1764 SetBit32(m_new_inst_cpsr, CPSR_C, res.carry_out);
1765 SetBit32(m_new_inst_cpsr, CPSR_V, res.overflow);
1766 if (m_new_inst_cpsr != m_inst_cpsr)
1767 {
1768 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
1769 return false;
1770 }
1771 return true;
1772}
1773
Johnny Chene4a4d302011-02-11 21:53:58 +00001774// CMP (register)
1775bool
1776EmulateInstructionARM::EmulateCmpRnRm (ARMEncoding encoding)
1777{
1778#if 0
1779 // ARM pseudo code...
1780 if ConditionPassed() then
1781 EncodingSpecificOperations();
1782 shifted = Shift(R[m], shift_t, shift_n, APSR.C);
1783 (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), '1');
1784 APSR.N = result<31>;
1785 APSR.Z = IsZeroBit(result);
1786 APSR.C = carry;
1787 APSR.V = overflow;
1788#endif
1789
1790 bool success = false;
1791 const uint32_t opcode = OpcodeAsUnsigned (&success);
1792 if (!success)
1793 return false;
1794
1795 uint32_t Rn; // the first operand
1796 uint32_t Rm; // the second operand
1797 switch (encoding) {
1798 case eEncodingT1:
1799 Rn = Bits32(opcode, 2, 0);
1800 Rm = Bits32(opcode, 5, 3);
1801 break;
1802 case eEncodingT2:
1803 Rn = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0);
1804 Rm = Bits32(opcode, 6, 3);
1805 if (Rn < 8 && Rm < 8)
1806 return false;
1807 if (Rn == 15 || Rm == 15)
1808 return false;
1809 break;
1810 default:
1811 return false;
1812 }
1813 // Read the register value from register Rn.
1814 uint32_t reg_val1 = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success);
1815 if (!success)
1816 return false;
1817 // Read the register value from register Rm.
1818 // The register value is not being shifted since we don't handle ARM for now.
1819 uint32_t reg_val2 = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
1820 if (!success)
1821 return false;
1822
1823 EmulateInstruction::Context context = { EmulateInstruction::eContextImmediate, 0, 0, 0};
1824 AddWithCarryResult res = AddWithCarry(reg_val1, reg_val2, 1);
1825 m_new_inst_cpsr = m_inst_cpsr;
1826 SetBit32(m_new_inst_cpsr, CPSR_N, Bit32(res.result, CPSR_N));
1827 SetBit32(m_new_inst_cpsr, CPSR_Z, res.result == 0 ? 1 : 0);
1828 SetBit32(m_new_inst_cpsr, CPSR_C, res.carry_out);
1829 SetBit32(m_new_inst_cpsr, CPSR_V, res.overflow);
1830 if (m_new_inst_cpsr != m_inst_cpsr)
1831 {
1832 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
1833 return false;
1834 }
1835 return true;
1836}
1837
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001838// LDM loads multiple registers from consecutive memory locations, using an
Caroline Tice713c2662011-02-11 17:59:55 +00001839// address from a base register. Optionally the address just above the highest of those locations
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001840// can be written back to the base register.
1841bool
1842EmulateInstructionARM::EmulateLDM (ARMEncoding encoding)
1843{
1844#if 0
1845 // ARM pseudo code...
1846 if ConditionPassed()
1847 EncodingSpecificOperations(); NullCheckIfThumbEE (n);
1848 address = R[n];
1849
1850 for i = 0 to 14
1851 if registers<i> == '1' then
1852 R[i] = MemA[address, 4]; address = address + 4;
1853 if registers<15> == '1' then
1854 LoadWritePC (MemA[address, 4]);
1855
1856 if wback && registers<n> == '0' then R[n] = R[n] + 4 * BitCount (registers);
1857 if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
1858
1859#endif
1860
1861 bool success = false;
1862 const uint32_t opcode = OpcodeAsUnsigned (&success);
1863 if (!success)
1864 return false;
1865
1866 if (ConditionPassed())
1867 {
1868 uint32_t n;
1869 uint32_t registers = 0;
1870 bool wback;
1871 const uint32_t addr_byte_size = GetAddressByteSize();
1872 switch (encoding)
1873 {
1874 case eEncodingT1:
1875 n = Bits32 (opcode, 10, 8);
1876 registers = Bits32 (opcode, 7, 0);
1877 wback = BitIsClear (registers, n);
1878 // if BitCount(registers) < 1 then UNPREDICTABLE;
1879 if (BitCount(registers) < 1)
1880 return false;
1881 break;
1882 case eEncodingT2:
1883 n = Bits32 (opcode, 19, 16);
1884 registers = Bits32 (opcode, 15, 0);
1885 wback = BitIsSet (opcode, 21);
1886 if ((n == 15)
1887 || (BitCount (registers) < 2)
1888 || (BitIsSet (opcode, 14) && BitIsSet (opcode, 15)))
1889 return false;
1890 if (BitIsSet (registers, 15)
1891 && m_it_session.InITBlock()
1892 && !m_it_session.LastInITBlock())
1893 return false;
1894 if (wback
1895 && BitIsSet (registers, n))
1896 return false;
1897 break;
1898 case eEncodingA1:
1899 n = Bits32 (opcode, 19, 16);
1900 registers = Bits32 (opcode, 15, 0);
1901 wback = BitIsSet (opcode, 21);
1902 if ((n == 15)
1903 || (BitCount (registers) < 1))
1904 return false;
1905 break;
1906 default:
1907 return false;
1908 }
1909
1910 int32_t offset = 0;
1911 const addr_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
1912 if (!success)
1913 return false;
Caroline Tice85aab332011-02-08 23:56:10 +00001914
1915 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
1916 eRegisterKindDWARF,
1917 dwarf_r0 + n,
1918 offset };
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001919
1920 for (int i = 0; i < 14; ++i)
1921 {
1922 if (BitIsSet (registers, i))
1923 {
Caroline Tice85aab332011-02-08 23:56:10 +00001924 context.type = EmulateInstruction::eContextRegisterPlusOffset;
1925 context.arg2 = offset;
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001926 if (wback && (n == 13)) // Pop Instruction
1927 context.type = EmulateInstruction::eContextPopRegisterOffStack;
1928
1929 // R[i] = MemA [address, 4]; address = address + 4;
1930 uint32_t data = ReadMemoryUnsigned (context, base_address + offset, addr_byte_size, 0, &success);
1931 if (!success)
1932 return false;
1933
1934 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
1935 return false;
1936
1937 offset += addr_byte_size;
1938 }
1939 }
1940
1941 if (BitIsSet (registers, 15))
1942 {
1943 //LoadWritePC (MemA [address, 4]);
Caroline Tice85aab332011-02-08 23:56:10 +00001944 context.type = EmulateInstruction::eContextRegisterPlusOffset;
1945 context.arg2 = offset;
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001946 uint32_t data = ReadMemoryUnsigned (context, base_address + offset, addr_byte_size, 0, &success);
1947 if (!success)
1948 return false;
Johnny Chene62b50d2011-02-09 22:02:17 +00001949 // In ARMv5T and above, this is an interworking branch.
1950 if (!LoadWritePC(context, data))
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001951 return false;
1952 }
1953
1954 if (wback && BitIsClear (registers, n))
1955 {
1956 addr_t offset = addr_byte_size * BitCount (registers);
Caroline Tice85aab332011-02-08 23:56:10 +00001957 context.type = EmulateInstruction::eContextRegisterPlusOffset;
1958 context.arg2 = offset;
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001959
1960 // R[n] = R[n] + 4 * BitCount (registers)
1961 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, base_address + offset))
1962 return false;
1963 }
1964 if (wback && BitIsSet (registers, n))
1965 // R[n] bits(32) UNKNOWN;
Caroline Tice713c2662011-02-11 17:59:55 +00001966 return WriteBits32Unknown (n);
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001967 }
1968 return true;
1969}
Caroline Tice713c2662011-02-11 17:59:55 +00001970
1971// LDMDA loads multiple registers from consecutive memory locations using an address from a base registers.
1972// The consecutive memorty locations end at this address and the address just below the lowest of those locations
1973// can optionally be written back tot he base registers.
1974bool
1975EmulateInstructionARM::EmulateLDMDA (ARMEncoding encoding)
1976{
1977#if 0
1978 // ARM pseudo code...
1979 if ConditionPassed() then
1980 EncodingSpecificOperations();
1981 address = R[n] - 4*BitCount(registers) + 4;
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001982
Caroline Tice713c2662011-02-11 17:59:55 +00001983 for i = 0 to 14
1984 if registers<i> == ’1’ then
1985 R[i] = MemA[address,4]; address = address + 4;
1986
1987 if registers<15> == ’1’ then
1988 LoadWritePC(MemA[address,4]);
1989
1990 if wback && registers<n> == ’0’ then R[n] = R[n] - 4*BitCount(registers);
1991 if wback && registers<n> == ’1’ then R[n] = bits(32) UNKNOWN;
1992#endif
1993
1994 bool success = false;
1995 const uint32_t opcode = OpcodeAsUnsigned (&success);
1996 if (!success)
1997 return false;
1998
1999 if (ConditionPassed())
2000 {
2001 uint32_t n;
2002 uint32_t registers = 0;
2003 bool wback;
2004 const uint32_t addr_byte_size = GetAddressByteSize();
2005
2006 // EncodingSpecificOperations();
2007 switch (encoding)
2008 {
2009 case eEncodingA1:
2010 // n = UInt(Rn); registers = register_list; wback = (W == ’1’);
2011 n = Bits32 (opcode, 19, 16);
2012 registers = Bits32 (opcode, 15, 0);
2013 wback = BitIsSet (opcode, 21);
2014
2015 // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
2016 if ((n == 15) || (BitCount (registers) < 1))
2017 return false;
2018
2019 break;
2020
2021 default:
2022 return false;
2023 }
2024 // address = R[n] - 4*BitCount(registers) + 4;
2025
2026 int32_t offset = 0;
2027 addr_t address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
2028
2029 if (!success)
2030 return false;
2031
2032 address = address - (addr_byte_size * BitCount (registers)) + addr_byte_size;
2033
2034 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
2035 eRegisterKindDWARF,
2036 dwarf_r0 + n,
2037 offset };
2038
2039 // for i = 0 to 14
2040 for (int i = 0; i < 14; ++i)
2041 {
2042 // if registers<i> == ’1’ then
2043 if (BitIsSet (registers, i))
2044 {
2045 // R[i] = MemA[address,4]; address = address + 4;
2046 context.arg2 = offset;
2047 uint32_t data = ReadMemoryUnsigned (context, address + offset, addr_byte_size, 0, &success);
2048 if (!success)
2049 return false;
2050 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
2051 return false;
2052 offset += addr_byte_size;
2053 }
2054 }
2055
2056 // if registers<15> == ’1’ then
2057 // LoadWritePC(MemA[address,4]);
2058 if (BitIsSet (registers, 15))
2059 {
2060 context.arg2 = offset;
2061 uint32_t data = ReadMemoryUnsigned (context, address + offset, addr_byte_size, 0, &success);
2062 if (!success)
2063 return false;
Johnny Chen44c10f02011-02-11 19:37:03 +00002064 // In ARMv5T and above, this is an interworking branch.
2065 if (!LoadWritePC(context, data))
Caroline Tice713c2662011-02-11 17:59:55 +00002066 return false;
2067 }
2068
2069 // if wback && registers<n> == ’0’ then R[n] = R[n] - 4*BitCount(registers);
2070 if (wback && BitIsClear (registers, n))
2071 {
2072 context.arg2 = offset;
2073 addr_t addr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
2074 if (!success)
2075 return false;
2076 addr = addr - (addr_byte_size * BitCount (registers));
2077 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr))
2078 return false;
2079 }
2080
2081 // if wback && registers<n> == ’1’ then R[n] = bits(32) UNKNOWN;
2082 if (wback && BitIsSet (registers, n))
2083 return WriteBits32Unknown (n);
2084 }
2085 return true;
2086}
2087
2088// LDMDB loads multiple registers from consecutive memory locations using an address from a base register. The
2089// consecutive memory lcoations end just below this address, and the address of the lowest of those locations can
2090// be optionally written back to the base register.
Caroline Tice0b29e242011-02-08 23:16:02 +00002091bool
2092EmulateInstructionARM::EmulateLDMDB (ARMEncoding encoding)
2093{
2094#if 0
2095 // ARM pseudo code...
2096 if ConditionPassed() then
2097 EncodingSpecificOperations(); NullCheckIfThumbEE(n);
2098 address = R[n] - 4*BitCount(registers);
2099
2100 for i = 0 to 14
2101 if registers<i> == ’1’ then
2102 R[i] = MemA[address,4]; address = address + 4;
2103 if registers<15> == ’1’ then
2104 LoadWritePC(MemA[address,4]);
2105
2106 if wback && registers<n> == ’0’ then R[n] = R[n] - 4*BitCount(registers);
2107 if wback && registers<n> == ’1’ then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
2108#endif
2109
2110 bool success = false;
2111 const uint32_t opcode = OpcodeAsUnsigned (&success);
2112 if (!success)
2113 return false;
2114
2115 if (ConditionPassed())
2116 {
2117 uint32_t n;
2118 uint32_t registers = 0;
2119 bool wback;
2120 const uint32_t addr_byte_size = GetAddressByteSize();
2121 switch (encoding)
2122 {
2123 case eEncodingT1:
2124 // n = UInt(Rn); registers = P:M:’0’:register_list; wback = (W == ’1’);
2125 n = Bits32 (opcode, 19, 16);
2126 registers = Bits32 (opcode, 15, 0);
2127 wback = BitIsSet (opcode, 21);
2128
2129 // if n == 15 || BitCount(registers) < 2 || (P == ’1’ && M == ’1’) then UNPREDICTABLE;
2130 if ((n == 15)
2131 || (BitCount (registers) < 2)
2132 || (BitIsSet (opcode, 14) && BitIsSet (opcode, 15)))
2133 return false;
2134
2135 // if registers<15> == ’1’ && InITBlock() && !LastInITBlock() then UNPREDICTABLE;
2136 if (BitIsSet (registers, 15)
2137 && m_it_session.InITBlock()
2138 && !m_it_session.LastInITBlock())
2139 return false;
2140
2141 // if wback && registers<n> == ’1’ then UNPREDICTABLE;
2142 if (wback && BitIsSet (registers, n))
2143 return false;
2144
2145 break;
2146
2147 case eEncodingA1:
2148 // n = UInt(Rn); registers = register_list; wback = (W == ’1’);
2149 n = Bits32 (opcode, 19, 16);
2150 registers = Bits32 (opcode, 15, 0);
2151 wback = BitIsSet (opcode, 21);
2152
2153 // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
2154 if ((n == 15) || (BitCount (registers) < 1))
2155 return false;
2156
2157 break;
2158
2159 default:
2160 return false;
2161 }
2162
Caroline Tice713c2662011-02-11 17:59:55 +00002163 // address = R[n] - 4*BitCount(registers);
2164
Caroline Tice0b29e242011-02-08 23:16:02 +00002165 int32_t offset = 0;
Caroline Tice713c2662011-02-11 17:59:55 +00002166 addr_t address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
2167
2168 if (!success)
2169 return false;
2170
2171 address = address - (addr_byte_size * BitCount (registers));
Caroline Tice85aab332011-02-08 23:56:10 +00002172 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
2173 eRegisterKindDWARF,
2174 dwarf_r0 + n,
2175 offset };
Caroline Tice0b29e242011-02-08 23:16:02 +00002176
2177 for (int i = 0; i < 14; ++i)
2178 {
2179 if (BitIsSet (registers, i))
2180 {
2181 // R[i] = MemA[address,4]; address = address + 4;
Caroline Tice85aab332011-02-08 23:56:10 +00002182 context.arg2 = offset;
Caroline Tice0b29e242011-02-08 23:16:02 +00002183 uint32_t data = ReadMemoryUnsigned (context, address + offset, addr_byte_size, 0, &success);
2184 if (!success)
2185 return false;
2186
2187 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
2188 return false;
2189
2190 offset += addr_byte_size;
2191 }
2192 }
2193
2194 // if registers<15> == ’1’ then
2195 // LoadWritePC(MemA[address,4]);
2196 if (BitIsSet (registers, 15))
2197 {
Caroline Tice85aab332011-02-08 23:56:10 +00002198 context.arg2 = offset;
Caroline Tice0b29e242011-02-08 23:16:02 +00002199 uint32_t data = ReadMemoryUnsigned (context, address + offset, addr_byte_size, 0, &success);
2200 if (!success)
2201 return false;
Johnny Chene62b50d2011-02-09 22:02:17 +00002202 // In ARMv5T and above, this is an interworking branch.
2203 if (!LoadWritePC(context, data))
Caroline Tice0b29e242011-02-08 23:16:02 +00002204 return false;
2205 }
2206
2207 // if wback && registers<n> == ’0’ then R[n] = R[n] - 4*BitCount(registers);
2208 if (wback && BitIsClear (registers, n))
2209 {
Caroline Tice85aab332011-02-08 23:56:10 +00002210 context.arg2 = offset;
Caroline Tice0b29e242011-02-08 23:16:02 +00002211 addr_t addr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
2212 if (!success)
2213 return false;
2214 addr = addr - (addr_byte_size * BitCount (registers));
2215 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr))
2216 return false;
2217 }
2218
2219 // if wback && registers<n> == ’1’ then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
2220 if (wback && BitIsSet (registers, n))
Caroline Tice713c2662011-02-11 17:59:55 +00002221 return WriteBits32Unknown (n);
Caroline Tice0b29e242011-02-08 23:16:02 +00002222 }
2223 return true;
2224}
Caroline Tice85aab332011-02-08 23:56:10 +00002225
Caroline Tice713c2662011-02-11 17:59:55 +00002226// LDMIB loads multiple registers from consecutive memory locations using an address from a base register. The
2227// consecutive memory locations start just above this address, and thea ddress of the last of those locations can
2228// optinoally be written back to the base register.
Caroline Tice85aab332011-02-08 23:56:10 +00002229bool
2230EmulateInstructionARM::EmulateLDMIB (ARMEncoding encoding)
2231{
2232#if 0
2233 if ConditionPassed() then
2234 EncodingSpecificOperations();
2235 address = R[n] + 4;
2236
2237 for i = 0 to 14
2238 if registers<i> == ’1’ then
2239 R[i] = MemA[address,4]; address = address + 4;
2240 if registers<15> == ’1’ then
2241 LoadWritePC(MemA[address,4]);
2242
2243 if wback && registers<n> == ’0’ then R[n] = R[n] + 4*BitCount(registers);
2244 if wback && registers<n> == ’1’ then R[n] = bits(32) UNKNOWN;
2245#endif
2246
2247 bool success = false;
2248 const uint32_t opcode = OpcodeAsUnsigned (&success);
2249 if (!success)
2250 return false;
2251
2252 if (ConditionPassed())
2253 {
2254 uint32_t n;
2255 uint32_t registers = 0;
2256 bool wback;
2257 const uint32_t addr_byte_size = GetAddressByteSize();
2258 switch (encoding)
2259 {
2260 case eEncodingA1:
2261 // n = UInt(Rn); registers = register_list; wback = (W == ’1’);
2262 n = Bits32 (opcode, 19, 16);
2263 registers = Bits32 (opcode, 15, 0);
2264 wback = BitIsSet (opcode, 21);
2265
2266 // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
2267 if ((n == 15) || (BitCount (registers) < 1))
2268 return false;
2269
2270 break;
2271 default:
2272 return false;
2273 }
2274 // address = R[n] + 4;
2275
2276 int32_t offset = 0;
Caroline Tice713c2662011-02-11 17:59:55 +00002277 addr_t address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
2278
2279 if (!success)
2280 return false;
2281
2282 address = address + addr_byte_size;
Caroline Tice85aab332011-02-08 23:56:10 +00002283
2284 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
2285 eRegisterKindDWARF,
2286 dwarf_r0 + n,
2287 offset };
2288
2289 for (int i = 0; i < 14; ++i)
2290 {
2291 if (BitIsSet (registers, i))
2292 {
2293 // R[i] = MemA[address,4]; address = address + 4;
2294
2295 context.arg2 = offset;
2296 uint32_t data = ReadMemoryUnsigned (context, address + offset, addr_byte_size, 0, &success);
2297 if (!success)
2298 return false;
2299
2300 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
2301 return false;
2302
2303 offset += addr_byte_size;
2304 }
2305 }
2306
2307 // if registers<15> == ’1’ then
2308 // LoadWritePC(MemA[address,4]);
2309 if (BitIsSet (registers, 15))
2310 {
2311 context.arg2 = offset;
2312 uint32_t data = ReadMemoryUnsigned (context, address + offset, addr_byte_size, 0, &success);
2313 if (!success)
2314 return false;
Johnny Chene62b50d2011-02-09 22:02:17 +00002315 // In ARMv5T and above, this is an interworking branch.
2316 if (!LoadWritePC(context, data))
Caroline Tice85aab332011-02-08 23:56:10 +00002317 return false;
2318 }
2319
2320 // if wback && registers<n> == ’0’ then R[n] = R[n] + 4*BitCount(registers);
2321 if (wback && BitIsClear (registers, n))
2322 {
2323 context.arg2 = offset;
2324 addr_t addr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
2325 if (!success)
2326 return false;
2327 addr = addr + (addr_byte_size * BitCount (registers));
2328 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr))
2329 return false;
2330 }
2331
2332 // if wback && registers<n> == ’1’ then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
2333 if (wback && BitIsSet (registers, n))
Caroline Tice713c2662011-02-11 17:59:55 +00002334 return WriteBits32Unknown (n);
Caroline Tice85aab332011-02-08 23:56:10 +00002335 }
2336 return true;
2337}
Caroline Tice0b29e242011-02-08 23:16:02 +00002338
Johnny Chenef21b592011-02-10 01:52:38 +00002339// Load Register (immediate) calculates an address from a base register value and
2340// an immediate offset, loads a word from memory, and writes to a register.
2341// LDR (immediate, Thumb)
2342bool
2343EmulateInstructionARM::EmulateLDRRtRnImm (ARMEncoding encoding)
2344{
2345#if 0
2346 // ARM pseudo code...
2347 if (ConditionPassed())
2348 {
2349 EncodingSpecificOperations(); NullCheckIfThumbEE(15);
2350 offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
2351 address = if index then offset_addr else R[n];
2352 data = MemU[address,4];
2353 if wback then R[n] = offset_addr;
2354 if t == 15 then
2355 if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
2356 elsif UnalignedSupport() || address<1:0> = '00' then
2357 R[t] = data;
2358 else R[t] = bits(32) UNKNOWN; // Can only apply before ARMv7
2359 }
2360#endif
2361
2362 bool success = false;
2363 const uint32_t opcode = OpcodeAsUnsigned (&success);
2364 if (!success)
2365 return false;
2366
2367 if (ConditionPassed())
2368 {
2369 uint32_t Rt; // the destination register
2370 uint32_t Rn; // the base register
2371 uint32_t imm32; // the immediate offset used to form the address
2372 addr_t offset_addr; // the offset address
2373 addr_t address; // the calculated address
2374 uint32_t data; // the literal data value from memory load
2375 bool add, index, wback;
2376 switch (encoding) {
2377 case eEncodingT1:
2378 Rt = Bits32(opcode, 5, 3);
2379 Rn = Bits32(opcode, 2, 0);
2380 imm32 = Bits32(opcode, 10, 6) << 2; // imm32 = ZeroExtend(imm5:'00', 32);
2381 // index = TRUE; add = TRUE; wback = FALSE
2382 add = true;
2383 index = true;
2384 wback = false;
2385 break;
2386 default:
2387 return false;
2388 }
2389 uint32_t base = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success);
2390 if (!success)
2391 return false;
2392 if (add)
2393 offset_addr = base + imm32;
2394 else
2395 offset_addr = base - imm32;
2396
2397 address = (index ? offset_addr : base);
2398
2399 if (wback)
2400 {
2401 EmulateInstruction::Context ctx = { EmulateInstruction::eContextRegisterPlusOffset,
2402 eRegisterKindDWARF,
2403 dwarf_r0 + Rn,
2404 (int32_t) (offset_addr - base)};
2405 if (!WriteRegisterUnsigned (ctx, eRegisterKindDWARF, dwarf_r0 + Rn, offset_addr))
2406 return false;
2407 }
2408
2409 // Prepare to write to the Rt register.
2410 EmulateInstruction::Context context = {EmulateInstruction::eContextImmediate,
2411 0,
2412 0,
2413 0};
2414
2415 // Read memory from the address.
2416 data = ReadMemoryUnsigned(context, address, 4, 0, &success);
2417 if (!success)
2418 return false;
2419 context.arg0 = data;
2420
2421 if (Rt == 15)
2422 {
2423 if (Bits32(address, 1, 0) == 0)
2424 {
2425 if (!LoadWritePC(context, data))
2426 return false;
2427 }
2428 else
2429 return false;
2430 }
2431 else if (UnalignedSupport() || Bits32(address, 1, 0) == 0)
2432 {
2433 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rt, data))
2434 return false;
2435 }
2436 else
2437 return false;
2438 }
2439 return true;
2440}
2441
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002442EmulateInstructionARM::ARMOpcode*
2443EmulateInstructionARM::GetARMOpcodeForInstruction (const uint32_t opcode)
Greg Clayton64c84432011-01-21 22:02:52 +00002444{
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002445 static ARMOpcode
2446 g_arm_opcodes[] =
2447 {
2448 //----------------------------------------------------------------------
2449 // Prologue instructions
2450 //----------------------------------------------------------------------
Johnny Chenfdd179e2011-01-31 20:09:28 +00002451
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002452 // push register(s)
Johnny Chenc28a76d2011-02-01 18:51:48 +00002453 { 0x0fff0000, 0x092d0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulatePush, "push <registers>" },
2454 { 0x0fff0fff, 0x052d0004, ARMvAll, eEncodingA2, eSize32, &EmulateInstructionARM::EmulatePush, "push <register>" },
Johnny Chenbcec3af2011-01-27 01:26:19 +00002455
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002456 // set r7 to point to a stack offset
Johnny Chenc28a76d2011-02-01 18:51:48 +00002457 { 0x0ffff000, 0x028d7000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateAddRdSPImmediate, "add r7, sp, #<const>" },
2458 { 0x0ffff000, 0x024c7000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSubR7IPImmediate, "sub r7, ip, #<const>"},
Johnny Chene7cf4202011-02-10 18:13:23 +00002459 // copy the stack pointer to ip
Johnny Chenc28a76d2011-02-01 18:51:48 +00002460 { 0x0fffffff, 0x01a0c00d, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateMovRdSP, "mov ip, sp" },
2461 { 0x0ffff000, 0x028dc000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateAddRdSPImmediate, "add ip, sp, #<const>" },
2462 { 0x0ffff000, 0x024dc000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSubIPSPImmediate, "sub ip, sp, #<const>"},
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00002463
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002464 // adjust the stack pointer
Johnny Chenc28a76d2011-02-01 18:51:48 +00002465 { 0x0ffff000, 0x024dd000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSubSPImmdiate, "sub sp, sp, #<const>"},
Johnny Chence1ca772011-01-25 01:13:00 +00002466
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002467 // push one register
2468 // if Rn == '1101' && imm12 == '000000000100' then SEE PUSH;
Johnny Chenc28a76d2011-02-01 18:51:48 +00002469 { 0x0fff0000, 0x052d0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSTRRtSP, "str Rt, [sp, #-imm12]!" },
Johnny Chen799dfd02011-01-26 23:14:33 +00002470
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002471 // vector push consecutive extension register(s)
Johnny Chen9b8d7832011-02-02 01:13:56 +00002472 { 0x0fbf0f00, 0x0d2d0b00, ARMV6T2_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"},
2473 { 0x0fbf0f00, 0x0d2d0a00, ARMV6T2_ABOVE, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"},
Johnny Chenef85e912011-01-31 23:07:40 +00002474
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002475 //----------------------------------------------------------------------
Johnny Chen587a0a42011-02-01 18:35:28 +00002476 // Epilogue instructions
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002477 //----------------------------------------------------------------------
Johnny Chenef85e912011-01-31 23:07:40 +00002478
Johnny Chenc28a76d2011-02-01 18:51:48 +00002479 { 0x0fff0000, 0x08bd0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulatePop, "pop <registers>"},
2480 { 0x0fff0fff, 0x049d0004, ARMvAll, eEncodingA2, eSize32, &EmulateInstructionARM::EmulatePop, "pop <register>"},
Johnny Chen9b8d7832011-02-02 01:13:56 +00002481 { 0x0fbf0f00, 0x0cbd0b00, ARMV6T2_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"},
Johnny Chenb77be412011-02-04 00:40:18 +00002482 { 0x0fbf0f00, 0x0cbd0a00, ARMV6T2_ABOVE, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"},
2483
2484 //----------------------------------------------------------------------
2485 // Supervisor Call (previously Software Interrupt)
2486 //----------------------------------------------------------------------
Johnny Chen3b620b32011-02-07 20:11:47 +00002487 { 0x0f000000, 0x0f000000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSVC, "svc #imm24"},
2488
2489 //----------------------------------------------------------------------
2490 // Branch instructions
2491 //----------------------------------------------------------------------
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002492 { 0x0f000000, 0x0a000000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSVC, "b #imm24"},
Johnny Chen383d6292011-02-11 21:23:32 +00002493 // To resolve ambiguity, "blx <label>" should come before "bl <label>".
2494 { 0xfe000000, 0xfa000000, ARMV5_ABOVE, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
2495 { 0x0f000000, 0x0b000000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"},
2496 { 0x0ffffff0, 0x012fff30, ARMV5_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
Johnny Chenb77be412011-02-04 00:40:18 +00002497
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002498 //----------------------------------------------------------------------
2499 // Load instructions
2500 //----------------------------------------------------------------------
Caroline Tice0b29e242011-02-08 23:16:02 +00002501 { 0x0fd00000, 0x08900000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDM, "ldm<c> <Rn>{!} <registers>" },
Caroline Tice713c2662011-02-11 17:59:55 +00002502 { 0x0fd00000, 0x08100000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDMDA, "ldmda<c> <Rn>{!} <registers>" },
Caroline Tice85aab332011-02-08 23:56:10 +00002503 { 0x0fd00000, 0x09100000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDMDB, "ldmdb<c> <Rn>{!} <registers>" },
2504 { 0x0fd00000, 0x09900000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDMIB, "ldmib<c> <Rn<{!} <registers>" }
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002505
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002506 };
2507 static const size_t k_num_arm_opcodes = sizeof(g_arm_opcodes)/sizeof(ARMOpcode);
2508
2509 for (size_t i=0; i<k_num_arm_opcodes; ++i)
2510 {
2511 if ((g_arm_opcodes[i].mask & opcode) == g_arm_opcodes[i].value)
2512 return &g_arm_opcodes[i];
2513 }
2514 return NULL;
2515}
Greg Clayton64c84432011-01-21 22:02:52 +00002516
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002517
2518EmulateInstructionARM::ARMOpcode*
2519EmulateInstructionARM::GetThumbOpcodeForInstruction (const uint32_t opcode)
Johnny Chen347320d2011-01-24 23:40:59 +00002520{
Johnny Chenfdd179e2011-01-31 20:09:28 +00002521
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002522 static ARMOpcode
2523 g_thumb_opcodes[] =
2524 {
2525 //----------------------------------------------------------------------
2526 // Prologue instructions
2527 //----------------------------------------------------------------------
Johnny Chenbcec3af2011-01-27 01:26:19 +00002528
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002529 // push register(s)
Johnny Chenc28a76d2011-02-01 18:51:48 +00002530 { 0xfffffe00, 0x0000b400, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulatePush, "push <registers>" },
Johnny Chend6c13f02011-02-08 20:36:34 +00002531 { 0xffff0000, 0xe92d0000, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulatePush, "push.w <registers>" },
2532 { 0xffff0fff, 0xf84d0d04, ARMV6T2_ABOVE, eEncodingT3, eSize32, &EmulateInstructionARM::EmulatePush, "push.w <register>" },
Johnny Chen788e0552011-01-27 22:52:23 +00002533
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002534 // set r7 to point to a stack offset
Johnny Chenc28a76d2011-02-01 18:51:48 +00002535 { 0xffffff00, 0x0000af00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateAddRdSPImmediate, "add r7, sp, #imm" },
Johnny Chene7cf4202011-02-10 18:13:23 +00002536 // copy the stack pointer to r7
Johnny Chenc28a76d2011-02-01 18:51:48 +00002537 { 0xffffffff, 0x0000466f, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateMovRdSP, "mov r7, sp" },
Johnny Chene7cf4202011-02-10 18:13:23 +00002538 // move from high register to low register (comes after "mov r7, sp" to resolve ambiguity)
2539 { 0xffffffc0, 0x00004640, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateMovLowHigh, "mov r0-r7, r8-r15" },
Johnny Chen60c0d622011-01-25 23:49:39 +00002540
Johnny Chenc9de9102011-02-11 19:12:30 +00002541 // PC-relative load into register (see also EmulateAddSPRm)
2542 { 0xfffff800, 0x00004800, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateLDRRtPCRelative, "ldr <Rt>, [PC, #imm]"},
Johnny Chen799dfd02011-01-26 23:14:33 +00002543
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002544 // adjust the stack pointer
Johnny Chenc28a76d2011-02-01 18:51:48 +00002545 { 0xffffff87, 0x00004485, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateAddSPRm, "add sp, <Rm>"},
2546 { 0xffffff80, 0x0000b080, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateSubSPImmdiate, "add sp, sp, #imm"},
Johnny Chend6c13f02011-02-08 20:36:34 +00002547 { 0xfbef8f00, 0xf1ad0d00, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateSubSPImmdiate, "sub.w sp, sp, #<const>"},
2548 { 0xfbff8f00, 0xf2ad0d00, ARMV6T2_ABOVE, eEncodingT3, eSize32, &EmulateInstructionARM::EmulateSubSPImmdiate, "subw sp, sp, #imm12"},
Johnny Chenfdd179e2011-01-31 20:09:28 +00002549
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002550 // vector push consecutive extension register(s)
Johnny Chend6c13f02011-02-08 20:36:34 +00002551 { 0xffbf0f00, 0xed2d0b00, ARMV6T2_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"},
2552 { 0xffbf0f00, 0xed2d0a00, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"},
Johnny Chenfdd179e2011-01-31 20:09:28 +00002553
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002554 //----------------------------------------------------------------------
2555 // Epilogue instructions
2556 //----------------------------------------------------------------------
Johnny Chen347320d2011-01-24 23:40:59 +00002557
Johnny Chenc28a76d2011-02-01 18:51:48 +00002558 { 0xffffff80, 0x0000b000, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateAddSPImmediate, "add sp, #imm"},
2559 { 0xfffffe00, 0x0000bc00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulatePop, "pop <registers>"},
Johnny Chend6c13f02011-02-08 20:36:34 +00002560 { 0xffff0000, 0xe8bd0000, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulatePop, "pop.w <registers>" },
2561 { 0xffff0fff, 0xf85d0d04, ARMV6T2_ABOVE, eEncodingT3, eSize32, &EmulateInstructionARM::EmulatePop, "pop.w <register>" },
2562 { 0xffbf0f00, 0xecbd0b00, ARMV6T2_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"},
2563 { 0xffbf0f00, 0xecbd0a00, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"},
Johnny Chenb77be412011-02-04 00:40:18 +00002564
2565 //----------------------------------------------------------------------
2566 // Supervisor Call (previously Software Interrupt)
2567 //----------------------------------------------------------------------
Johnny Chenc315f862011-02-05 00:46:10 +00002568 { 0xffffff00, 0x0000df00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateSVC, "svc #imm8"},
2569
2570 //----------------------------------------------------------------------
2571 // If Then makes up to four following instructions conditional.
2572 //----------------------------------------------------------------------
Johnny Chen3b620b32011-02-07 20:11:47 +00002573 { 0xffffff00, 0x0000bf00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateIT, "it{<x>{<y>{<z>}}} <firstcond>"},
2574
2575 //----------------------------------------------------------------------
2576 // Branch instructions
2577 //----------------------------------------------------------------------
2578 // To resolve ambiguity, "b<c> #imm8" should come after "svc #imm8".
2579 { 0xfffff000, 0x0000d000, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateB, "b<c> #imm8 (outside IT)"},
2580 { 0xffff8000, 0x0000e000, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateB, "b #imm11 (outside or last in IT)"},
Johnny Chen9ee056b2011-02-08 00:06:35 +00002581 { 0xf800d000, 0xf0008000, ARMV6T2_ABOVE, eEncodingT3, eSize32, &EmulateInstructionARM::EmulateB, "b<c>.w #imm8 (outside IT)"},
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002582 { 0xf800d000, 0xf0009000, ARMV6T2_ABOVE, eEncodingT4, eSize32, &EmulateInstructionARM::EmulateB, "b.w #imm8 (outside or last in IT)"},
Johnny Chen383d6292011-02-11 21:23:32 +00002583 // J1 == J2 == 1
2584 { 0xf800f800, 0xf000f800, ARMV4T_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"},
2585 // J1 == J2 == 1
2586 { 0xf800e800, 0xf000e800, ARMV5_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
2587 { 0xffffff87, 0x00004780, ARMV5_ABOVE, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
Johnny Chen53ebab72011-02-08 23:21:57 +00002588 // compare and branch
2589 { 0xfffff500, 0x0000b100, ARMV6T2_ABOVE, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateCB, "cb{n}z <Rn>, <label>"},
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002590
2591 //----------------------------------------------------------------------
Johnny Chen26863dc2011-02-09 23:43:29 +00002592 // Data-processing instructions
2593 //----------------------------------------------------------------------
2594 // Make sure "add sp, <Rm>" comes before this instruction, so there's no ambiguity decoding the two.
2595 { 0xffffff00, 0x00004400, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateAddRdnRm, "add <Rdn>, <Rm>"},
Johnny Chen338bf542011-02-10 19:29:03 +00002596 // move from high register to high register
2597 { 0xffffff00, 0x00004600, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateMovRdRm, "mov<c> <Rd>, <Rm>"},
2598 // move from low register to low register
2599 { 0xffffffc0, 0x00000000, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateMovRdRm, "movs <Rd>, <Rm>"},
Johnny Chend4dc4442011-02-11 02:02:56 +00002600 // compare a register with immediate
2601 { 0xfffff800, 0x00002800, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateCmpRnImm, "cmp<c> <Rn>, #imm8"},
Johnny Chene4a4d302011-02-11 21:53:58 +00002602 // compare Rn with Rm (Rn and Rm both from r0-r7)
2603 { 0xffffffc0, 0x00004280, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateCmpRnRm, "cmp<c> <Rn>, <Rm>"},
2604 // compare Rn with Rm (Rn and Rm not both from r0-r7)
2605 { 0xffffff00, 0x00004500, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateCmpRnRm, "cmp<c> <Rn>, <Rm>"},
Johnny Chen26863dc2011-02-09 23:43:29 +00002606
2607 //----------------------------------------------------------------------
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002608 // Load instructions
2609 //----------------------------------------------------------------------
2610 { 0xfffff800, 0x0000c800, ARMV4T_ABOVE, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateLDM, "ldm<c> <Rn>{!} <registers>" },
Caroline Tice0b29e242011-02-08 23:16:02 +00002611 { 0xffd02000, 0xe8900000, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateLDM, "ldm<c>.w <Rn>{!} <registers>" },
Johnny Chenef21b592011-02-10 01:52:38 +00002612 { 0xffd00000, 0xe9100000, ARMV6T2_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateLDMDB, "ldmdb<c> <Rn>{!} <registers>" },
Johnny Chenc9de9102011-02-11 19:12:30 +00002613 { 0xfffff800, 0x00006800, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr<c> <Rt>, [<Rn>{,#imm}]"},
2614 // Thumb2 PC-relative load into register
2615 { 0xff7f0000, 0xf85f0000, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateLDRRtPCRelative, "ldr<c>.w <Rt>, [PC, +/-#imm}]"}
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002616
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002617 };
2618
2619 const size_t k_num_thumb_opcodes = sizeof(g_thumb_opcodes)/sizeof(ARMOpcode);
2620 for (size_t i=0; i<k_num_thumb_opcodes; ++i)
2621 {
2622 if ((g_thumb_opcodes[i].mask & opcode) == g_thumb_opcodes[i].value)
2623 return &g_thumb_opcodes[i];
2624 }
2625 return NULL;
2626}
Greg Clayton64c84432011-01-21 22:02:52 +00002627
Greg Clayton31e2a382011-01-30 20:03:56 +00002628bool
2629EmulateInstructionARM::SetTargetTriple (const ConstString &triple)
2630{
2631 m_arm_isa = 0;
2632 const char *triple_cstr = triple.GetCString();
2633 if (triple_cstr)
2634 {
2635 const char *dash = ::strchr (triple_cstr, '-');
2636 if (dash)
2637 {
2638 std::string arch (triple_cstr, dash);
2639 const char *arch_cstr = arch.c_str();
2640 if (strcasecmp(arch_cstr, "armv4t") == 0)
2641 m_arm_isa = ARMv4T;
2642 else if (strcasecmp(arch_cstr, "armv4") == 0)
2643 m_arm_isa = ARMv4;
2644 else if (strcasecmp(arch_cstr, "armv5tej") == 0)
2645 m_arm_isa = ARMv5TEJ;
2646 else if (strcasecmp(arch_cstr, "armv5te") == 0)
2647 m_arm_isa = ARMv5TE;
2648 else if (strcasecmp(arch_cstr, "armv5t") == 0)
2649 m_arm_isa = ARMv5T;
2650 else if (strcasecmp(arch_cstr, "armv6k") == 0)
2651 m_arm_isa = ARMv6K;
2652 else if (strcasecmp(arch_cstr, "armv6") == 0)
2653 m_arm_isa = ARMv6;
2654 else if (strcasecmp(arch_cstr, "armv6t2") == 0)
2655 m_arm_isa = ARMv6T2;
2656 else if (strcasecmp(arch_cstr, "armv7") == 0)
2657 m_arm_isa = ARMv7;
2658 else if (strcasecmp(arch_cstr, "armv8") == 0)
2659 m_arm_isa = ARMv8;
2660 }
2661 }
2662 return m_arm_isa != 0;
2663}
2664
2665
Greg Clayton64c84432011-01-21 22:02:52 +00002666bool
2667EmulateInstructionARM::ReadInstruction ()
2668{
2669 bool success = false;
2670 m_inst_cpsr = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, 0, &success);
2671 if (success)
2672 {
2673 addr_t pc = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_ADDRESS, &success);
2674 if (success)
2675 {
2676 Context read_inst_context = {eContextReadOpcode, 0, 0};
2677 if (m_inst_cpsr & MASK_CPSR_T)
2678 {
2679 m_inst_mode = eModeThumb;
2680 uint32_t thumb_opcode = ReadMemoryUnsigned(read_inst_context, pc, 2, 0, &success);
2681
2682 if (success)
2683 {
2684 if ((m_inst.opcode.inst16 & 0xe000) != 0xe000 || ((m_inst.opcode.inst16 & 0x1800u) == 0))
2685 {
2686 m_inst.opcode_type = eOpcode16;
2687 m_inst.opcode.inst16 = thumb_opcode;
2688 }
2689 else
2690 {
2691 m_inst.opcode_type = eOpcode32;
2692 m_inst.opcode.inst32 = (thumb_opcode << 16) | ReadMemoryUnsigned(read_inst_context, pc + 2, 2, 0, &success);
2693 }
2694 }
2695 }
2696 else
2697 {
2698 m_inst_mode = eModeARM;
2699 m_inst.opcode_type = eOpcode32;
2700 m_inst.opcode.inst32 = ReadMemoryUnsigned(read_inst_context, pc, 4, 0, &success);
2701 }
2702 }
2703 }
2704 if (!success)
2705 {
2706 m_inst_mode = eModeInvalid;
2707 m_inst_pc = LLDB_INVALID_ADDRESS;
2708 }
2709 return success;
2710}
2711
Johnny Chenee9b1f72011-02-09 01:00:31 +00002712uint32_t
2713EmulateInstructionARM::ArchVersion ()
2714{
2715 return m_arm_isa;
2716}
2717
Greg Clayton64c84432011-01-21 22:02:52 +00002718bool
2719EmulateInstructionARM::ConditionPassed ()
2720{
2721 if (m_inst_cpsr == 0)
2722 return false;
2723
2724 const uint32_t cond = CurrentCond ();
2725
2726 if (cond == UINT32_MAX)
2727 return false;
2728
2729 bool result = false;
2730 switch (UnsignedBits(cond, 3, 1))
2731 {
2732 case 0: result = (m_inst_cpsr & MASK_CPSR_Z) != 0; break;
2733 case 1: result = (m_inst_cpsr & MASK_CPSR_C) != 0; break;
2734 case 2: result = (m_inst_cpsr & MASK_CPSR_N) != 0; break;
2735 case 3: result = (m_inst_cpsr & MASK_CPSR_V) != 0; break;
2736 case 4: result = ((m_inst_cpsr & MASK_CPSR_C) != 0) && ((m_inst_cpsr & MASK_CPSR_Z) == 0); break;
2737 case 5:
2738 {
2739 bool n = (m_inst_cpsr & MASK_CPSR_N);
2740 bool v = (m_inst_cpsr & MASK_CPSR_V);
2741 result = n == v;
2742 }
2743 break;
2744 case 6:
2745 {
2746 bool n = (m_inst_cpsr & MASK_CPSR_N);
2747 bool v = (m_inst_cpsr & MASK_CPSR_V);
2748 result = n == v && ((m_inst_cpsr & MASK_CPSR_Z) == 0);
2749 }
2750 break;
2751 case 7:
2752 result = true;
2753 break;
2754 }
2755
2756 if (cond & 1)
2757 result = !result;
2758 return result;
2759}
2760
Johnny Chen9ee056b2011-02-08 00:06:35 +00002761uint32_t
2762EmulateInstructionARM::CurrentCond ()
2763{
2764 switch (m_inst_mode)
2765 {
2766 default:
2767 case eModeInvalid:
2768 break;
2769
2770 case eModeARM:
2771 return UnsignedBits(m_inst.opcode.inst32, 31, 28);
2772
2773 case eModeThumb:
2774 // For T1 and T3 encodings of the Branch instruction, it returns the 4-bit
2775 // 'cond' field of the encoding.
2776 if (m_inst.opcode_type == eOpcode16 &&
2777 Bits32(m_inst.opcode.inst16, 15, 12) == 0x0d &&
2778 Bits32(m_inst.opcode.inst16, 11, 7) != 0x0f)
2779 {
2780 return Bits32(m_inst.opcode.inst16, 11, 7);
2781 }
2782 else if (m_inst.opcode_type == eOpcode32 &&
2783 Bits32(m_inst.opcode.inst32, 31, 27) == 0x1e &&
2784 Bits32(m_inst.opcode.inst32, 15, 14) == 0x02 &&
2785 Bits32(m_inst.opcode.inst32, 12, 12) == 0x00 &&
2786 Bits32(m_inst.opcode.inst32, 25, 22) <= 0x0d)
2787 {
2788 return Bits32(m_inst.opcode.inst32, 25, 22);
2789 }
2790
2791 return m_it_session.GetCond();
2792 }
2793 return UINT32_MAX; // Return invalid value
2794}
2795
Johnny Chen9ee056b2011-02-08 00:06:35 +00002796bool
2797EmulateInstructionARM::BranchWritePC (const Context &context, uint32_t addr)
2798{
2799 addr_t target;
2800
Johnny Chenee9b1f72011-02-09 01:00:31 +00002801 // Check the current instruction set.
2802 if (CurrentInstrSet() == eModeARM)
Johnny Chen9ee056b2011-02-08 00:06:35 +00002803 target = addr & 0xfffffffc;
Johnny Chenee9b1f72011-02-09 01:00:31 +00002804 else
Johnny Chen9ee056b2011-02-08 00:06:35 +00002805 target = addr & 0xfffffffe;
Johnny Chenee9b1f72011-02-09 01:00:31 +00002806
Johnny Chen9ee056b2011-02-08 00:06:35 +00002807 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, target))
Johnny Chen53ebab72011-02-08 23:21:57 +00002808 return false;
2809
2810 return true;
Johnny Chen9ee056b2011-02-08 00:06:35 +00002811}
2812
2813// As a side effect, BXWritePC sets context.arg2 to eModeARM or eModeThumb by inspecting addr.
2814bool
2815EmulateInstructionARM::BXWritePC (Context &context, uint32_t addr)
2816{
2817 addr_t target;
Johnny Chen0f309db2011-02-09 19:11:32 +00002818 // If the CPSR is changed due to switching between ARM and Thumb ISETSTATE,
2819 // we want to record it and issue a WriteRegister callback so the clients
2820 // can track the mode changes accordingly.
2821 bool cpsr_changed = false;
Johnny Chen9ee056b2011-02-08 00:06:35 +00002822
2823 if (BitIsSet(addr, 0))
2824 {
Johnny Chen0f309db2011-02-09 19:11:32 +00002825 if (CurrentInstrSet() != eModeThumb)
2826 {
2827 SelectInstrSet(eModeThumb);
2828 cpsr_changed = true;
2829 }
Johnny Chen9ee056b2011-02-08 00:06:35 +00002830 target = addr & 0xfffffffe;
2831 context.arg2 = eModeThumb;
2832 }
2833 else if (BitIsClear(addr, 1))
2834 {
Johnny Chen0f309db2011-02-09 19:11:32 +00002835 if (CurrentInstrSet() != eModeARM)
2836 {
2837 SelectInstrSet(eModeARM);
2838 cpsr_changed = true;
2839 }
Johnny Chen9ee056b2011-02-08 00:06:35 +00002840 target = addr & 0xfffffffc;
2841 context.arg2 = eModeARM;
2842 }
2843 else
2844 return false; // address<1:0> == '10' => UNPREDICTABLE
2845
Johnny Chen0f309db2011-02-09 19:11:32 +00002846 if (cpsr_changed)
2847 {
Johnny Chen558133b2011-02-09 23:59:17 +00002848 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
Johnny Chen0f309db2011-02-09 19:11:32 +00002849 return false;
2850 }
Johnny Chen9ee056b2011-02-08 00:06:35 +00002851 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, target))
Johnny Chen53ebab72011-02-08 23:21:57 +00002852 return false;
2853
2854 return true;
Johnny Chen9ee056b2011-02-08 00:06:35 +00002855}
Greg Clayton64c84432011-01-21 22:02:52 +00002856
Johnny Chenee9b1f72011-02-09 01:00:31 +00002857// Dispatches to either BXWritePC or BranchWritePC based on architecture versions.
2858bool
2859EmulateInstructionARM::LoadWritePC (Context &context, uint32_t addr)
2860{
2861 if (ArchVersion() >= ARMv5T)
2862 return BXWritePC(context, addr);
2863 else
2864 return BranchWritePC((const Context)context, addr);
2865}
2866
Johnny Chen26863dc2011-02-09 23:43:29 +00002867// Dispatches to either BXWritePC or BranchWritePC based on architecture versions and current instruction set.
2868bool
2869EmulateInstructionARM::ALUWritePC (Context &context, uint32_t addr)
2870{
2871 if (ArchVersion() >= ARMv7 && CurrentInstrSet() == eModeARM)
2872 return BXWritePC(context, addr);
2873 else
2874 return BranchWritePC((const Context)context, addr);
2875}
2876
Johnny Chenee9b1f72011-02-09 01:00:31 +00002877EmulateInstructionARM::Mode
2878EmulateInstructionARM::CurrentInstrSet ()
2879{
2880 return m_inst_mode;
2881}
2882
2883// Set the 'T' bit of our CPSR. The m_inst_mode gets updated when the next
Johnny Chen558133b2011-02-09 23:59:17 +00002884// ReadInstruction() is performed. This function has a side effect of updating
2885// the m_new_inst_cpsr member variable if necessary.
Johnny Chenee9b1f72011-02-09 01:00:31 +00002886bool
2887EmulateInstructionARM::SelectInstrSet (Mode arm_or_thumb)
2888{
Johnny Chen558133b2011-02-09 23:59:17 +00002889 m_new_inst_cpsr = m_inst_cpsr;
Johnny Chenee9b1f72011-02-09 01:00:31 +00002890 switch (arm_or_thumb)
2891 {
2892 default:
2893 return false;
2894 eModeARM:
2895 // Clear the T bit.
Johnny Chen558133b2011-02-09 23:59:17 +00002896 m_new_inst_cpsr &= ~MASK_CPSR_T;
Johnny Chenee9b1f72011-02-09 01:00:31 +00002897 break;
2898 eModeThumb:
2899 // Set the T bit.
Johnny Chen558133b2011-02-09 23:59:17 +00002900 m_new_inst_cpsr |= MASK_CPSR_T;
Johnny Chenee9b1f72011-02-09 01:00:31 +00002901 break;
2902 }
2903 return true;
2904}
2905
Johnny Chenef21b592011-02-10 01:52:38 +00002906// This function returns TRUE if the processor currently provides support for
2907// unaligned memory accesses, or FALSE otherwise. This is always TRUE in ARMv7,
2908// controllable by the SCTLR.U bit in ARMv6, and always FALSE before ARMv6.
2909bool
2910EmulateInstructionARM::UnalignedSupport()
2911{
2912 return (ArchVersion() >= ARMv7);
2913}
2914
Johnny Chenbf6ad172011-02-11 01:29:53 +00002915// The main addition and subtraction instructions can produce status information
2916// about both unsigned carry and signed overflow conditions. This status
2917// information can be used to synthesize multi-word additions and subtractions.
2918EmulateInstructionARM::AddWithCarryResult
2919EmulateInstructionARM::AddWithCarry (uint32_t x, uint32_t y, uint8_t carry_in)
2920{
2921 uint32_t result;
2922 uint8_t carry_out;
2923 uint8_t overflow;
2924
2925 uint64_t unsigned_sum = x + y + carry_in;
2926 int64_t signed_sum = (int32_t)x + (int32_t)y + (int32_t)carry_in;
2927
2928 result = UnsignedBits(unsigned_sum, 31, 0);
2929 carry_out = (result == unsigned_sum ? 0 : 1);
2930 overflow = ((int32_t)result == signed_sum ? 0 : 1);
2931
2932 AddWithCarryResult res = { result, carry_out, overflow };
2933 return res;
2934}
2935
Greg Clayton64c84432011-01-21 22:02:52 +00002936bool
2937EmulateInstructionARM::EvaluateInstruction ()
2938{
Johnny Chenc315f862011-02-05 00:46:10 +00002939 // Advance the ITSTATE bits to their values for the next instruction.
2940 if (m_inst_mode == eModeThumb && m_it_session.InITBlock())
2941 m_it_session.ITAdvance();
2942
Greg Clayton64c84432011-01-21 22:02:52 +00002943 return false;
2944}