blob: 4d968700cacaf5980f73f89be0f8559aec7bb650 [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
153 uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
154
155 if (!success)
156 return false;
157
158 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data))
159 return false;
160
161 return true;
162}
163
Johnny Chen08c25e82011-01-31 18:02:28 +0000164// Push Multiple Registers stores multiple registers to the stack, storing to
165// consecutive memory locations ending just below the address in SP, and updates
166// SP to point to the start of the stored data.
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000167bool
168EmulateInstructionARM::EmulatePush (ARMEncoding encoding)
Greg Clayton64c84432011-01-21 22:02:52 +0000169{
170#if 0
171 // ARM pseudo code...
172 if (ConditionPassed())
173 {
174 EncodingSpecificOperations();
175 NullCheckIfThumbEE(13);
176 address = SP - 4*BitCount(registers);
177
178 for (i = 0 to 14)
179 {
180 if (registers<i> == ’1’)
181 {
182 if i == 13 && i != LowestSetBit(registers) // Only possible for encoding A1
183 MemA[address,4] = bits(32) UNKNOWN;
184 else
185 MemA[address,4] = R[i];
186 address = address + 4;
187 }
188 }
189
190 if (registers<15> == ’1’) // Only possible for encoding A1 or A2
191 MemA[address,4] = PCStoreValue();
192
193 SP = SP - 4*BitCount(registers);
194 }
195#endif
196
197 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000198 const uint32_t opcode = OpcodeAsUnsigned (&success);
Greg Clayton64c84432011-01-21 22:02:52 +0000199 if (!success)
200 return false;
201
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000202 if (ConditionPassed())
Greg Clayton64c84432011-01-21 22:02:52 +0000203 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000204 const uint32_t addr_byte_size = GetAddressByteSize();
205 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Greg Clayton64c84432011-01-21 22:02:52 +0000206 if (!success)
207 return false;
Johnny Chen3c75c762011-01-22 00:47:08 +0000208 uint32_t registers = 0;
Johnny Chen91d99862011-01-25 19:07:04 +0000209 uint32_t Rt; // the source register
Johnny Chen3c75c762011-01-22 00:47:08 +0000210 switch (encoding) {
Johnny Chenaedde1c2011-01-24 20:38:45 +0000211 case eEncodingT1:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000212 registers = Bits32(opcode, 7, 0);
Johnny Chenaedde1c2011-01-24 20:38:45 +0000213 // The M bit represents LR.
Johnny Chenbd599902011-02-10 21:39:01 +0000214 if (Bit32(opcode, 8))
Johnny Chenef85e912011-01-31 23:07:40 +0000215 registers |= (1u << 14);
Johnny Chenaedde1c2011-01-24 20:38:45 +0000216 // if BitCount(registers) < 1 then UNPREDICTABLE;
217 if (BitCount(registers) < 1)
218 return false;
219 break;
Johnny Chen7dc60e12011-01-24 19:46:32 +0000220 case eEncodingT2:
221 // Ignore bits 15 & 13.
Johnny Chen108d5aa2011-01-26 01:00:55 +0000222 registers = Bits32(opcode, 15, 0) & ~0xa000;
Johnny Chen7dc60e12011-01-24 19:46:32 +0000223 // if BitCount(registers) < 2 then UNPREDICTABLE;
224 if (BitCount(registers) < 2)
225 return false;
226 break;
227 case eEncodingT3:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000228 Rt = Bits32(opcode, 15, 12);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000229 // if BadReg(t) then UNPREDICTABLE;
Johnny Chen91d99862011-01-25 19:07:04 +0000230 if (BadReg(Rt))
Johnny Chen7dc60e12011-01-24 19:46:32 +0000231 return false;
Johnny Chen91d99862011-01-25 19:07:04 +0000232 registers = (1u << Rt);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000233 break;
Johnny Chen3c75c762011-01-22 00:47:08 +0000234 case eEncodingA1:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000235 registers = Bits32(opcode, 15, 0);
Johnny Chena33d4842011-01-24 22:25:48 +0000236 // Instead of return false, let's handle the following case as well,
237 // which amounts to pushing one reg onto the full descending stacks.
238 // if BitCount(register_list) < 2 then SEE STMDB / STMFD;
Johnny Chen3c75c762011-01-22 00:47:08 +0000239 break;
240 case eEncodingA2:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000241 Rt = Bits32(opcode, 15, 12);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000242 // if t == 13 then UNPREDICTABLE;
Johnny Chen91d99862011-01-25 19:07:04 +0000243 if (Rt == dwarf_sp)
Johnny Chen3c75c762011-01-22 00:47:08 +0000244 return false;
Johnny Chen91d99862011-01-25 19:07:04 +0000245 registers = (1u << Rt);
Johnny Chen3c75c762011-01-22 00:47:08 +0000246 break;
Johnny Chence1ca772011-01-25 01:13:00 +0000247 default:
248 return false;
Johnny Chen3c75c762011-01-22 00:47:08 +0000249 }
Johnny Chence1ca772011-01-25 01:13:00 +0000250 addr_t sp_offset = addr_byte_size * BitCount (registers);
Greg Clayton64c84432011-01-21 22:02:52 +0000251 addr_t addr = sp - sp_offset;
252 uint32_t i;
253
254 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
255 for (i=0; i<15; ++i)
256 {
Johnny Chen7c1bf922011-02-08 23:49:37 +0000257 if (BitIsSet (registers, i))
Greg Clayton64c84432011-01-21 22:02:52 +0000258 {
259 context.arg1 = dwarf_r0 + i; // arg1 in the context is the DWARF register number
260 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000261 uint32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
Greg Clayton64c84432011-01-21 22:02:52 +0000262 if (!success)
263 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000264 if (!WriteMemoryUnsigned (context, addr, reg_value, addr_byte_size))
Greg Clayton64c84432011-01-21 22:02:52 +0000265 return false;
266 addr += addr_byte_size;
267 }
268 }
269
Johnny Chen7c1bf922011-02-08 23:49:37 +0000270 if (BitIsSet (registers, 15))
Greg Clayton64c84432011-01-21 22:02:52 +0000271 {
272 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
Johnny Chen3c75c762011-01-22 00:47:08 +0000273 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000274 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Greg Clayton64c84432011-01-21 22:02:52 +0000275 if (!success)
276 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000277 if (!WriteMemoryUnsigned (context, addr, pc + 8, addr_byte_size))
Greg Clayton64c84432011-01-21 22:02:52 +0000278 return false;
279 }
280
281 context.type = EmulateInstruction::eContextAdjustStackPointer;
282 context.arg0 = eRegisterKindGeneric;
283 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +0000284 context.arg2 = -sp_offset;
Greg Clayton64c84432011-01-21 22:02:52 +0000285
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000286 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
Greg Clayton64c84432011-01-21 22:02:52 +0000287 return false;
288 }
289 return true;
290}
291
Johnny Chenef85e912011-01-31 23:07:40 +0000292// Pop Multiple Registers loads multiple registers from the stack, loading from
293// consecutive memory locations staring at the address in SP, and updates
294// SP to point just above the loaded data.
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000295bool
296EmulateInstructionARM::EmulatePop (ARMEncoding encoding)
Johnny Chenef85e912011-01-31 23:07:40 +0000297{
298#if 0
299 // ARM pseudo code...
300 if (ConditionPassed())
301 {
302 EncodingSpecificOperations(); NullCheckIfThumbEE(13);
303 address = SP;
304 for i = 0 to 14
305 if registers<i> == ‘1’ then
306 R[i} = if UnalignedAllowed then MemU[address,4] else MemA[address,4]; address = address + 4;
307 if registers<15> == ‘1’ then
308 if UnalignedAllowed then
309 LoadWritePC(MemU[address,4]);
310 else
311 LoadWritePC(MemA[address,4]);
312 if registers<13> == ‘0’ then SP = SP + 4*BitCount(registers);
313 if registers<13> == ‘1’ then SP = bits(32) UNKNOWN;
314 }
315#endif
316
317 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000318 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chenef85e912011-01-31 23:07:40 +0000319 if (!success)
320 return false;
321
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000322 if (ConditionPassed())
Johnny Chenef85e912011-01-31 23:07:40 +0000323 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000324 const uint32_t addr_byte_size = GetAddressByteSize();
325 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chenef85e912011-01-31 23:07:40 +0000326 if (!success)
327 return false;
328 uint32_t registers = 0;
329 uint32_t Rt; // the destination register
330 switch (encoding) {
331 case eEncodingT1:
332 registers = Bits32(opcode, 7, 0);
333 // The P bit represents PC.
Johnny Chenbd599902011-02-10 21:39:01 +0000334 if (Bit32(opcode, 8))
Johnny Chenef85e912011-01-31 23:07:40 +0000335 registers |= (1u << 15);
336 // if BitCount(registers) < 1 then UNPREDICTABLE;
337 if (BitCount(registers) < 1)
338 return false;
339 break;
340 case eEncodingT2:
341 // Ignore bit 13.
342 registers = Bits32(opcode, 15, 0) & ~0x2000;
343 // if BitCount(registers) < 2 || (P == '1' && M == '1') then UNPREDICTABLE;
Johnny Chenbd599902011-02-10 21:39:01 +0000344 if (BitCount(registers) < 2 || (Bit32(opcode, 15) && Bit32(opcode, 14)))
Johnny Chenef85e912011-01-31 23:07:40 +0000345 return false;
346 break;
347 case eEncodingT3:
348 Rt = Bits32(opcode, 15, 12);
349 // if t == 13 || (t == 15 && InITBlock() && !LastInITBlock()) then UNPREDICTABLE;
350 if (Rt == dwarf_sp)
351 return false;
352 registers = (1u << Rt);
353 break;
354 case eEncodingA1:
355 registers = Bits32(opcode, 15, 0);
356 // Instead of return false, let's handle the following case as well,
357 // which amounts to popping one reg from the full descending stacks.
358 // if BitCount(register_list) < 2 then SEE LDM / LDMIA / LDMFD;
359
360 // if registers<13> == ‘1’ && ArchVersion() >= 7 then UNPREDICTABLE;
Johnny Chenbd599902011-02-10 21:39:01 +0000361 if (Bit32(opcode, 13) && ArchVersion() >= ARMv7)
Johnny Chenef85e912011-01-31 23:07:40 +0000362 return false;
363 break;
364 case eEncodingA2:
365 Rt = Bits32(opcode, 15, 12);
366 // if t == 13 then UNPREDICTABLE;
367 if (Rt == dwarf_sp)
368 return false;
369 registers = (1u << Rt);
370 break;
371 default:
372 return false;
373 }
374 addr_t sp_offset = addr_byte_size * BitCount (registers);
375 addr_t addr = sp;
376 uint32_t i, data;
377
378 EmulateInstruction::Context context = { EmulateInstruction::eContextPopRegisterOffStack, eRegisterKindDWARF, 0, 0 };
379 for (i=0; i<15; ++i)
380 {
Johnny Chen7c1bf922011-02-08 23:49:37 +0000381 if (BitIsSet (registers, i))
Johnny Chenef85e912011-01-31 23:07:40 +0000382 {
383 context.arg1 = dwarf_r0 + i; // arg1 in the context is the DWARF register number
384 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000385 data = ReadMemoryUnsigned(context, addr, 4, 0, &success);
Johnny Chenef85e912011-01-31 23:07:40 +0000386 if (!success)
387 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000388 if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, context.arg1, data))
Johnny Chenef85e912011-01-31 23:07:40 +0000389 return false;
390 addr += addr_byte_size;
391 }
392 }
393
Johnny Chen7c1bf922011-02-08 23:49:37 +0000394 if (BitIsSet (registers, 15))
Johnny Chenef85e912011-01-31 23:07:40 +0000395 {
396 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
397 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000398 data = ReadMemoryUnsigned(context, addr, 4, 0, &success);
Johnny Chenef85e912011-01-31 23:07:40 +0000399 if (!success)
400 return false;
Johnny Chenf3eaacf2011-02-09 19:30:49 +0000401 // In ARMv5T and above, this is an interworking branch.
402 if (!LoadWritePC(context, data))
Johnny Chenef85e912011-01-31 23:07:40 +0000403 return false;
404 addr += addr_byte_size;
405 }
406
407 context.type = EmulateInstruction::eContextAdjustStackPointer;
408 context.arg0 = eRegisterKindGeneric;
409 context.arg1 = LLDB_REGNUM_GENERIC_SP;
410 context.arg2 = sp_offset;
411
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000412 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp + sp_offset))
Johnny Chenef85e912011-01-31 23:07:40 +0000413 return false;
414 }
415 return true;
416}
417
Johnny Chen5b442b72011-01-27 19:34:30 +0000418// Set r7 or ip to point to saved value residing within the stack.
Johnny Chenbcec3af2011-01-27 01:26:19 +0000419// ADD (SP plus immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000420bool
421EmulateInstructionARM::EmulateAddRdSPImmediate (ARMEncoding encoding)
Johnny Chenbcec3af2011-01-27 01:26:19 +0000422{
423#if 0
424 // ARM pseudo code...
425 if (ConditionPassed())
426 {
427 EncodingSpecificOperations();
428 (result, carry, overflow) = AddWithCarry(SP, imm32, ‘0’);
429 if d == 15 then
430 ALUWritePC(result); // setflags is always FALSE here
431 else
432 R[d] = result;
433 if setflags then
434 APSR.N = result<31>;
435 APSR.Z = IsZeroBit(result);
436 APSR.C = carry;
437 APSR.V = overflow;
438 }
439#endif
440
441 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000442 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chenbcec3af2011-01-27 01:26:19 +0000443 if (!success)
444 return false;
445
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000446 if (ConditionPassed())
Johnny Chenbcec3af2011-01-27 01:26:19 +0000447 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000448 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chenbcec3af2011-01-27 01:26:19 +0000449 if (!success)
450 return false;
451 uint32_t Rd; // the destination register
452 uint32_t imm32;
453 switch (encoding) {
454 case eEncodingT1:
455 Rd = 7;
456 imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32)
457 break;
458 case eEncodingA1:
459 Rd = Bits32(opcode, 15, 12);
460 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
461 break;
462 default:
463 return false;
464 }
465 addr_t sp_offset = imm32;
466 addr_t addr = sp + sp_offset; // a pointer to the stack area
467
468 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
469 eRegisterKindGeneric,
470 LLDB_REGNUM_GENERIC_SP,
471 sp_offset };
472
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000473 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, addr))
Johnny Chenbcec3af2011-01-27 01:26:19 +0000474 return false;
475 }
476 return true;
477}
478
Johnny Chen2ccad832011-01-28 19:57:25 +0000479// Set r7 or ip to the current stack pointer.
480// MOV (register)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000481bool
482EmulateInstructionARM::EmulateMovRdSP (ARMEncoding encoding)
Johnny Chen2ccad832011-01-28 19:57:25 +0000483{
484#if 0
485 // ARM pseudo code...
486 if (ConditionPassed())
487 {
488 EncodingSpecificOperations();
489 result = R[m];
490 if d == 15 then
491 ALUWritePC(result); // setflags is always FALSE here
492 else
493 R[d] = result;
494 if setflags then
495 APSR.N = result<31>;
496 APSR.Z = IsZeroBit(result);
497 // APSR.C unchanged
498 // APSR.V unchanged
499 }
500#endif
501
502 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000503 //const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen1c13b622011-01-29 00:11:15 +0000504 //if (!success)
505 // return false;
Johnny Chen2ccad832011-01-28 19:57:25 +0000506
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000507 if (ConditionPassed())
Johnny Chen2ccad832011-01-28 19:57:25 +0000508 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000509 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen2ccad832011-01-28 19:57:25 +0000510 if (!success)
511 return false;
512 uint32_t Rd; // the destination register
513 switch (encoding) {
514 case eEncodingT1:
515 Rd = 7;
516 break;
517 case eEncodingA1:
518 Rd = 12;
519 break;
520 default:
521 return false;
522 }
523 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
524 eRegisterKindGeneric,
525 LLDB_REGNUM_GENERIC_SP,
526 0 };
527
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000528 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, sp))
Johnny Chen2ccad832011-01-28 19:57:25 +0000529 return false;
530 }
531 return true;
532}
533
Johnny Chen1c13b622011-01-29 00:11:15 +0000534// Move from high register (r8-r15) to low register (r0-r7).
535// MOV (register)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000536bool
537EmulateInstructionARM::EmulateMovLowHigh (ARMEncoding encoding)
Johnny Chen1c13b622011-01-29 00:11:15 +0000538{
Johnny Chen338bf542011-02-10 19:29:03 +0000539 return EmulateMovRdRm (encoding);
540}
541
542// Move from register to register.
543// MOV (register)
544bool
545EmulateInstructionARM::EmulateMovRdRm (ARMEncoding encoding)
546{
Johnny Chen1c13b622011-01-29 00:11:15 +0000547#if 0
548 // ARM pseudo code...
549 if (ConditionPassed())
550 {
551 EncodingSpecificOperations();
552 result = R[m];
553 if d == 15 then
554 ALUWritePC(result); // setflags is always FALSE here
555 else
556 R[d] = result;
557 if setflags then
558 APSR.N = result<31>;
559 APSR.Z = IsZeroBit(result);
560 // APSR.C unchanged
561 // APSR.V unchanged
562 }
563#endif
564
565 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000566 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen1c13b622011-01-29 00:11:15 +0000567 if (!success)
568 return false;
569
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000570 if (ConditionPassed())
Johnny Chen1c13b622011-01-29 00:11:15 +0000571 {
572 uint32_t Rm; // the source register
573 uint32_t Rd; // the destination register
Johnny Chen338bf542011-02-10 19:29:03 +0000574 bool setflags;
Johnny Chen1c13b622011-01-29 00:11:15 +0000575 switch (encoding) {
576 case eEncodingT1:
577 Rm = Bits32(opcode, 6, 3);
Johnny Chenbd599902011-02-10 21:39:01 +0000578 Rd = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 1);
Johnny Chen338bf542011-02-10 19:29:03 +0000579 setflags = false;
580 break;
581 case eEncodingT2:
582 Rm = Bits32(opcode, 5, 3);
583 Rd = Bits32(opcode, 2, 1);
584 setflags = true;
Johnny Chen1c13b622011-01-29 00:11:15 +0000585 break;
586 default:
587 return false;
588 }
Johnny Chen338bf542011-02-10 19:29:03 +0000589 uint32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
Johnny Chen1c13b622011-01-29 00:11:15 +0000590 if (!success)
591 return false;
592
593 // The context specifies that Rm is to be moved into Rd.
594 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
595 eRegisterKindDWARF,
596 dwarf_r0 + Rm,
597 0 };
598
Johnny Chen338bf542011-02-10 19:29:03 +0000599 if (Rd == 15)
600 {
601 if (!ALUWritePC (context, reg_value))
602 return false;
603 }
604 else
605 {
606 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, reg_value))
607 return false;
608 if (setflags)
609 {
610 m_new_inst_cpsr = m_inst_cpsr;
Johnny Chenbd599902011-02-10 21:39:01 +0000611 SetBit32(m_new_inst_cpsr, CPSR_N, Bit32(reg_value, CPSR_N));
612 SetBit32(m_new_inst_cpsr, CPSR_Z, reg_value == 0 ? 1 : 0);
Johnny Chen338bf542011-02-10 19:29:03 +0000613 if (m_new_inst_cpsr != m_inst_cpsr)
614 {
615 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
616 return false;
617 }
618 }
619 }
Johnny Chen1c13b622011-01-29 00:11:15 +0000620 }
621 return true;
622}
623
Johnny Chen788e0552011-01-27 22:52:23 +0000624// PC relative immediate load into register, possibly followed by ADD (SP plus register).
625// LDR (literal)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000626bool
627EmulateInstructionARM::EmulateLDRRdPCRelative (ARMEncoding encoding)
Johnny Chen788e0552011-01-27 22:52:23 +0000628{
629#if 0
630 // ARM pseudo code...
631 if (ConditionPassed())
632 {
633 EncodingSpecificOperations(); NullCheckIfThumbEE(15);
634 base = Align(PC,4);
635 address = if add then (base + imm32) else (base - imm32);
636 data = MemU[address,4];
637 if t == 15 then
638 if address<1:0> == ‘00’ then LoadWritePC(data); else UNPREDICTABLE;
639 elsif UnalignedSupport() || address<1:0> = ‘00’ then
640 R[t] = data;
641 else // Can only apply before ARMv7
642 if CurrentInstrSet() == InstrSet_ARM then
643 R[t] = ROR(data, 8*UInt(address<1:0>));
644 else
645 R[t] = bits(32) UNKNOWN;
646 }
647#endif
648
649 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000650 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen788e0552011-01-27 22:52:23 +0000651 if (!success)
652 return false;
653
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000654 if (ConditionPassed())
Johnny Chen788e0552011-01-27 22:52:23 +0000655 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000656 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Johnny Chen788e0552011-01-27 22:52:23 +0000657 if (!success)
658 return false;
Johnny Chen809742e2011-01-28 00:32:27 +0000659
660 // PC relative immediate load context
661 EmulateInstruction::Context context = {EmulateInstruction::eContextRegisterPlusOffset,
662 eRegisterKindGeneric,
663 LLDB_REGNUM_GENERIC_PC,
664 0};
Johnny Chen788e0552011-01-27 22:52:23 +0000665 uint32_t Rd; // the destination register
666 uint32_t imm32; // immediate offset from the PC
667 addr_t addr; // the PC relative address
668 uint32_t data; // the literal data value from the PC relative load
669 switch (encoding) {
670 case eEncodingT1:
671 Rd = Bits32(opcode, 10, 8);
672 imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32);
673 addr = pc + 4 + imm32;
Johnny Chen809742e2011-01-28 00:32:27 +0000674 context.arg2 = 4 + imm32;
Johnny Chen788e0552011-01-27 22:52:23 +0000675 break;
676 default:
677 return false;
678 }
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000679 data = ReadMemoryUnsigned(context, addr, 4, 0, &success);
Johnny Chen788e0552011-01-27 22:52:23 +0000680 if (!success)
Johnny Chen809742e2011-01-28 00:32:27 +0000681 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000682 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, data))
Johnny Chen788e0552011-01-27 22:52:23 +0000683 return false;
684 }
685 return true;
686}
687
Johnny Chen5b442b72011-01-27 19:34:30 +0000688// An add operation to adjust the SP.
Johnny Chenfdd179e2011-01-31 20:09:28 +0000689// ADD (SP plus immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000690bool
691EmulateInstructionARM::EmulateAddSPImmediate (ARMEncoding encoding)
Johnny Chenfdd179e2011-01-31 20:09:28 +0000692{
693#if 0
694 // ARM pseudo code...
695 if (ConditionPassed())
696 {
697 EncodingSpecificOperations();
698 (result, carry, overflow) = AddWithCarry(SP, imm32, ‘0’);
699 if d == 15 then // Can only occur for ARM encoding
700 ALUWritePC(result); // setflags is always FALSE here
701 else
702 R[d] = result;
703 if setflags then
704 APSR.N = result<31>;
705 APSR.Z = IsZeroBit(result);
706 APSR.C = carry;
707 APSR.V = overflow;
708 }
709#endif
710
711 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000712 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chenfdd179e2011-01-31 20:09:28 +0000713 if (!success)
714 return false;
715
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000716 if (ConditionPassed())
Johnny Chenfdd179e2011-01-31 20:09:28 +0000717 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000718 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chenfdd179e2011-01-31 20:09:28 +0000719 if (!success)
720 return false;
721 uint32_t imm32; // the immediate operand
722 switch (encoding) {
723 case eEncodingT2:
724 imm32 = ThumbImmScaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
725 break;
726 default:
727 return false;
728 }
729 addr_t sp_offset = imm32;
730 addr_t addr = sp + sp_offset; // the adjusted stack pointer value
731
732 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
733 eRegisterKindGeneric,
734 LLDB_REGNUM_GENERIC_SP,
735 sp_offset };
736
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000737 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
Johnny Chenfdd179e2011-01-31 20:09:28 +0000738 return false;
739 }
740 return true;
741}
742
743// An add operation to adjust the SP.
Johnny Chen5b442b72011-01-27 19:34:30 +0000744// ADD (SP plus register)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000745bool
746EmulateInstructionARM::EmulateAddSPRm (ARMEncoding encoding)
Johnny Chen5b442b72011-01-27 19:34:30 +0000747{
748#if 0
749 // ARM pseudo code...
750 if (ConditionPassed())
751 {
752 EncodingSpecificOperations();
753 shifted = Shift(R[m], shift_t, shift_n, APSR.C);
754 (result, carry, overflow) = AddWithCarry(SP, shifted, ‘0’);
755 if d == 15 then
756 ALUWritePC(result); // setflags is always FALSE here
757 else
758 R[d] = result;
759 if setflags then
760 APSR.N = result<31>;
761 APSR.Z = IsZeroBit(result);
762 APSR.C = carry;
763 APSR.V = overflow;
764 }
765#endif
766
767 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000768 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen5b442b72011-01-27 19:34:30 +0000769 if (!success)
770 return false;
771
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000772 if (ConditionPassed())
Johnny Chen5b442b72011-01-27 19:34:30 +0000773 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000774 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen5b442b72011-01-27 19:34:30 +0000775 if (!success)
776 return false;
777 uint32_t Rm; // the second operand
778 switch (encoding) {
779 case eEncodingT2:
780 Rm = Bits32(opcode, 6, 3);
781 break;
782 default:
783 return false;
784 }
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000785 int32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
Johnny Chen5b442b72011-01-27 19:34:30 +0000786 if (!success)
787 return false;
788
789 addr_t addr = (int32_t)sp + reg_value; // the adjusted stack pointer value
790
791 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
792 eRegisterKindGeneric,
793 LLDB_REGNUM_GENERIC_SP,
794 reg_value };
795
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000796 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
Johnny Chen5b442b72011-01-27 19:34:30 +0000797 return false;
798 }
799 return true;
800}
801
Johnny Chen9b8d7832011-02-02 01:13:56 +0000802// Branch with Link and Exchange Instruction Sets (immediate) calls a subroutine
803// at a PC-relative address, and changes instruction set from ARM to Thumb, or
804// from Thumb to ARM.
805// BLX (immediate)
806bool
807EmulateInstructionARM::EmulateBLXImmediate (ARMEncoding encoding)
808{
809#if 0
810 // ARM pseudo code...
811 if (ConditionPassed())
812 {
813 EncodingSpecificOperations();
814 if CurrentInstrSet() == InstrSet_ARM then
815 LR = PC - 4;
816 else
817 LR = PC<31:1> : '1';
818 if targetInstrSet == InstrSet_ARM then
819 targetAddress = Align(PC,4) + imm32;
820 else
821 targetAddress = PC + imm32;
822 SelectInstrSet(targetInstrSet);
823 BranchWritePC(targetAddress);
824 }
825#endif
826
827 bool success = false;
828 const uint32_t opcode = OpcodeAsUnsigned (&success);
829 if (!success)
830 return false;
831
832 if (ConditionPassed())
833 {
834 EmulateInstruction::Context context = { EmulateInstruction::eContextRelativeBranchImmediate, 0, 0, 0};
835 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Johnny Chen9b8d7832011-02-02 01:13:56 +0000836 if (!success)
837 return false;
Johnny Chen53ebab72011-02-08 23:21:57 +0000838 addr_t lr; // next instruction address
839 addr_t target; // target address
Johnny Chen9b8d7832011-02-02 01:13:56 +0000840 int32_t imm32; // PC-relative offset
841 switch (encoding) {
Johnny Chend6c13f02011-02-08 20:36:34 +0000842 case eEncodingT1:
843 {
844 lr = (pc + 4) | 1u; // return address
Johnny Chenbd599902011-02-10 21:39:01 +0000845 uint32_t S = Bit32(opcode, 26);
Johnny Chend6c13f02011-02-08 20:36:34 +0000846 uint32_t imm10 = Bits32(opcode, 25, 16);
Johnny Chenbd599902011-02-10 21:39:01 +0000847 uint32_t J1 = Bit32(opcode, 13);
848 uint32_t J2 = Bit32(opcode, 11);
Johnny Chend6c13f02011-02-08 20:36:34 +0000849 uint32_t imm11 = Bits32(opcode, 10, 0);
850 uint32_t I1 = !(J1 ^ S);
851 uint32_t I2 = !(J2 ^ S);
Johnny Chen53ebab72011-02-08 23:21:57 +0000852 uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
Johnny Chend6c13f02011-02-08 20:36:34 +0000853 imm32 = llvm::SignExtend32<25>(imm25);
854 target = pc + 4 + imm32;
855 context.arg1 = 4 + imm32; // signed offset
856 context.arg2 = eModeThumb; // target instruction set
857 break;
858 }
Johnny Chen9b8d7832011-02-02 01:13:56 +0000859 case eEncodingT2:
860 {
861 lr = (pc + 4) | 1u; // return address
Johnny Chenbd599902011-02-10 21:39:01 +0000862 uint32_t S = Bit32(opcode, 26);
Johnny Chen9b8d7832011-02-02 01:13:56 +0000863 uint32_t imm10H = Bits32(opcode, 25, 16);
Johnny Chenbd599902011-02-10 21:39:01 +0000864 uint32_t J1 = Bit32(opcode, 13);
865 uint32_t J2 = Bit32(opcode, 11);
Johnny Chen9b8d7832011-02-02 01:13:56 +0000866 uint32_t imm10L = Bits32(opcode, 10, 1);
867 uint32_t I1 = !(J1 ^ S);
868 uint32_t I2 = !(J2 ^ S);
Johnny Chen53ebab72011-02-08 23:21:57 +0000869 uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10H << 12) | (imm10L << 2);
Johnny Chen9b8d7832011-02-02 01:13:56 +0000870 imm32 = llvm::SignExtend32<25>(imm25);
Johnny Chend6c13f02011-02-08 20:36:34 +0000871 target = Align(pc + 4, 4) + imm32;
872 context.arg1 = 4 + imm32; // signed offset
873 context.arg2 = eModeARM; // target instruction set
Johnny Chen9b8d7832011-02-02 01:13:56 +0000874 break;
875 }
Johnny Chenc47d0ca2011-02-08 18:58:31 +0000876 case eEncodingA1:
877 lr = pc + 4; // return address
878 imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2);
Johnny Chend6c13f02011-02-08 20:36:34 +0000879 target = Align(pc + 8, 4) + imm32;
880 context.arg1 = 8 + imm32; // signed offset
881 context.arg2 = eModeARM; // target instruction set
Johnny Chenc47d0ca2011-02-08 18:58:31 +0000882 break;
Johnny Chen9b8d7832011-02-02 01:13:56 +0000883 case eEncodingA2:
884 lr = pc + 4; // return address
885 imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2 | Bits32(opcode, 24, 24) << 1);
886 target = pc + 8 + imm32;
Johnny Chen9ee056b2011-02-08 00:06:35 +0000887 context.arg1 = 8 + imm32; // signed offset
888 context.arg2 = eModeThumb; // target instruction set
Johnny Chen9b8d7832011-02-02 01:13:56 +0000889 break;
890 default:
891 return false;
892 }
893 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
894 return false;
Johnny Chen9ee056b2011-02-08 00:06:35 +0000895 if (!BranchWritePC(context, target))
Johnny Chen9b8d7832011-02-02 01:13:56 +0000896 return false;
897 }
898 return true;
899}
900
901// Branch with Link and Exchange (register) calls a subroutine at an address and
902// instruction set specified by a register.
903// BLX (register)
904bool
905EmulateInstructionARM::EmulateBLXRm (ARMEncoding encoding)
906{
907#if 0
908 // ARM pseudo code...
909 if (ConditionPassed())
910 {
911 EncodingSpecificOperations();
912 target = R[m];
913 if CurrentInstrSet() == InstrSet_ARM then
914 next_instr_addr = PC - 4;
915 LR = next_instr_addr;
916 else
917 next_instr_addr = PC - 2;
918 LR = next_instr_addr<31:1> : ‘1’;
919 BXWritePC(target);
920 }
921#endif
922
923 bool success = false;
924 const uint32_t opcode = OpcodeAsUnsigned (&success);
925 if (!success)
926 return false;
927
928 if (ConditionPassed())
929 {
930 EmulateInstruction::Context context = { EmulateInstruction::eContextAbsoluteBranchRegister, 0, 0, 0};
931 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
932 addr_t lr; // next instruction address
933 addr_t target; // target address
934 if (!success)
935 return false;
936 uint32_t Rm; // the register with the target address
937 switch (encoding) {
938 case eEncodingT1:
939 lr = (pc + 2) | 1u; // return address
940 Rm = Bits32(opcode, 6, 3);
941 // if m == 15 then UNPREDICTABLE;
942 if (Rm == 15)
943 return false;
944 target = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
945 break;
946 case eEncodingA1:
947 lr = pc + 4; // return address
948 Rm = Bits32(opcode, 3, 0);
949 // if m == 15 then UNPREDICTABLE;
950 if (Rm == 15)
951 return false;
952 target = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
Johnny Chenb77be412011-02-04 00:40:18 +0000953 break;
Johnny Chen9b8d7832011-02-02 01:13:56 +0000954 default:
955 return false;
956 }
Johnny Chen9b8d7832011-02-02 01:13:56 +0000957 context.arg0 = eRegisterKindDWARF;
958 context.arg1 = dwarf_r0 + Rm;
Johnny Chen9b8d7832011-02-02 01:13:56 +0000959 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
960 return false;
Johnny Chen9ee056b2011-02-08 00:06:35 +0000961 if (!BXWritePC(context, target))
Johnny Chen9b8d7832011-02-02 01:13:56 +0000962 return false;
963 }
964 return true;
965}
966
Johnny Chen0d0148e2011-01-28 02:26:08 +0000967// Set r7 to point to some ip offset.
968// SUB (immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000969bool
970EmulateInstructionARM::EmulateSubR7IPImmediate (ARMEncoding encoding)
Johnny Chen0d0148e2011-01-28 02:26:08 +0000971{
972#if 0
973 // ARM pseudo code...
974 if (ConditionPassed())
975 {
976 EncodingSpecificOperations();
977 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), ‘1’);
978 if d == 15 then // Can only occur for ARM encoding
979 ALUWritePC(result); // setflags is always FALSE here
980 else
981 R[d] = result;
982 if setflags then
983 APSR.N = result<31>;
984 APSR.Z = IsZeroBit(result);
985 APSR.C = carry;
986 APSR.V = overflow;
987 }
988#endif
989
990 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000991 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen0d0148e2011-01-28 02:26:08 +0000992 if (!success)
993 return false;
994
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000995 if (ConditionPassed())
Johnny Chen0d0148e2011-01-28 02:26:08 +0000996 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000997 const addr_t ip = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r12, 0, &success);
Johnny Chen0d0148e2011-01-28 02:26:08 +0000998 if (!success)
999 return false;
1000 uint32_t imm32;
1001 switch (encoding) {
1002 case eEncodingA1:
1003 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
1004 break;
1005 default:
1006 return false;
1007 }
1008 addr_t ip_offset = imm32;
1009 addr_t addr = ip - ip_offset; // the adjusted ip value
1010
1011 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
1012 eRegisterKindDWARF,
1013 dwarf_r12,
1014 -ip_offset };
1015
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001016 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r7, addr))
Johnny Chen0d0148e2011-01-28 02:26:08 +00001017 return false;
1018 }
1019 return true;
1020}
1021
1022// Set ip to point to some stack offset.
1023// SUB (SP minus immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001024bool
1025EmulateInstructionARM::EmulateSubIPSPImmediate (ARMEncoding encoding)
Johnny Chen0d0148e2011-01-28 02:26:08 +00001026{
1027#if 0
1028 // ARM pseudo code...
1029 if (ConditionPassed())
1030 {
1031 EncodingSpecificOperations();
1032 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), ‘1’);
1033 if d == 15 then // Can only occur for ARM encoding
1034 ALUWritePC(result); // setflags is always FALSE here
1035 else
1036 R[d] = result;
1037 if setflags then
1038 APSR.N = result<31>;
1039 APSR.Z = IsZeroBit(result);
1040 APSR.C = carry;
1041 APSR.V = overflow;
1042 }
1043#endif
1044
1045 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001046 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen0d0148e2011-01-28 02:26:08 +00001047 if (!success)
1048 return false;
1049
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001050 if (ConditionPassed())
Johnny Chen0d0148e2011-01-28 02:26:08 +00001051 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001052 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen0d0148e2011-01-28 02:26:08 +00001053 if (!success)
1054 return false;
1055 uint32_t imm32;
1056 switch (encoding) {
1057 case eEncodingA1:
1058 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
1059 break;
1060 default:
1061 return false;
1062 }
1063 addr_t sp_offset = imm32;
1064 addr_t addr = sp - sp_offset; // the adjusted stack pointer value
1065
1066 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
1067 eRegisterKindGeneric,
1068 LLDB_REGNUM_GENERIC_SP,
1069 -sp_offset };
1070
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001071 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r12, addr))
Johnny Chen0d0148e2011-01-28 02:26:08 +00001072 return false;
1073 }
1074 return true;
1075}
1076
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001077// A sub operation to adjust the SP -- allocate space for local storage.
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001078bool
1079EmulateInstructionARM::EmulateSubSPImmdiate (ARMEncoding encoding)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001080{
1081#if 0
1082 // ARM pseudo code...
1083 if (ConditionPassed())
1084 {
1085 EncodingSpecificOperations();
1086 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), ‘1’);
1087 if d == 15 then // Can only occur for ARM encoding
Johnny Chen799dfd02011-01-26 23:14:33 +00001088 ALUWritePC(result); // setflags is always FALSE here
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001089 else
1090 R[d] = result;
1091 if setflags then
1092 APSR.N = result<31>;
1093 APSR.Z = IsZeroBit(result);
1094 APSR.C = carry;
1095 APSR.V = overflow;
1096 }
1097#endif
1098
1099 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001100 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001101 if (!success)
1102 return false;
1103
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001104 if (ConditionPassed())
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001105 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001106 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001107 if (!success)
1108 return false;
1109 uint32_t imm32;
1110 switch (encoding) {
Johnny Chene4455022011-01-26 00:08:59 +00001111 case eEncodingT1:
1112 imm32 = ThumbImmScaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
Johnny Chen60c0d622011-01-25 23:49:39 +00001113 case eEncodingT2:
1114 imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
1115 break;
1116 case eEncodingT3:
1117 imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32)
1118 break;
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001119 case eEncodingA1:
Johnny Chen60c0d622011-01-25 23:49:39 +00001120 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001121 break;
1122 default:
1123 return false;
1124 }
1125 addr_t sp_offset = imm32;
1126 addr_t addr = sp - sp_offset; // the adjusted stack pointer value
1127
1128 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
1129 eRegisterKindGeneric,
1130 LLDB_REGNUM_GENERIC_SP,
Johnny Chen5b442b72011-01-27 19:34:30 +00001131 -sp_offset };
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001132
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001133 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001134 return false;
1135 }
1136 return true;
1137}
1138
Johnny Chen08c25e82011-01-31 18:02:28 +00001139// A store operation to the stack that also updates the SP.
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001140bool
1141EmulateInstructionARM::EmulateSTRRtSP (ARMEncoding encoding)
Johnny Chence1ca772011-01-25 01:13:00 +00001142{
1143#if 0
1144 // ARM pseudo code...
1145 if (ConditionPassed())
1146 {
1147 EncodingSpecificOperations();
1148 offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
1149 address = if index then offset_addr else R[n];
1150 MemU[address,4] = if t == 15 then PCStoreValue() else R[t];
1151 if wback then R[n] = offset_addr;
1152 }
1153#endif
1154
1155 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001156 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chence1ca772011-01-25 01:13:00 +00001157 if (!success)
1158 return false;
1159
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001160 if (ConditionPassed())
Johnny Chence1ca772011-01-25 01:13:00 +00001161 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001162 const uint32_t addr_byte_size = GetAddressByteSize();
1163 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chence1ca772011-01-25 01:13:00 +00001164 if (!success)
1165 return false;
Johnny Chen91d99862011-01-25 19:07:04 +00001166 uint32_t Rt; // the source register
Johnny Chence1ca772011-01-25 01:13:00 +00001167 uint32_t imm12;
1168 switch (encoding) {
1169 case eEncodingA1:
Johnny Chen108d5aa2011-01-26 01:00:55 +00001170 Rt = Bits32(opcode, 15, 12);
1171 imm12 = Bits32(opcode, 11, 0);
Johnny Chence1ca772011-01-25 01:13:00 +00001172 break;
1173 default:
1174 return false;
1175 }
1176 addr_t sp_offset = imm12;
1177 addr_t addr = sp - sp_offset;
1178
1179 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
Johnny Chen91d99862011-01-25 19:07:04 +00001180 if (Rt != 15)
Johnny Chence1ca772011-01-25 01:13:00 +00001181 {
Johnny Chen91d99862011-01-25 19:07:04 +00001182 context.arg1 = dwarf_r0 + Rt; // arg1 in the context is the DWARF register number
1183 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001184 uint32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
Johnny Chence1ca772011-01-25 01:13:00 +00001185 if (!success)
1186 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001187 if (!WriteMemoryUnsigned (context, addr, reg_value, addr_byte_size))
Johnny Chence1ca772011-01-25 01:13:00 +00001188 return false;
1189 }
1190 else
1191 {
1192 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
1193 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001194 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Johnny Chence1ca772011-01-25 01:13:00 +00001195 if (!success)
1196 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001197 if (!WriteMemoryUnsigned (context, addr, pc + 8, addr_byte_size))
Johnny Chence1ca772011-01-25 01:13:00 +00001198 return false;
1199 }
1200
1201 context.type = EmulateInstruction::eContextAdjustStackPointer;
1202 context.arg0 = eRegisterKindGeneric;
1203 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +00001204 context.arg2 = -sp_offset;
Johnny Chence1ca772011-01-25 01:13:00 +00001205
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001206 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
Johnny Chence1ca772011-01-25 01:13:00 +00001207 return false;
1208 }
1209 return true;
1210}
1211
Johnny Chen08c25e82011-01-31 18:02:28 +00001212// Vector Push stores multiple extension registers to the stack.
1213// It also updates SP to point to the start of the stored data.
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001214bool
1215EmulateInstructionARM::EmulateVPUSH (ARMEncoding encoding)
Johnny Chen799dfd02011-01-26 23:14:33 +00001216{
1217#if 0
1218 // ARM pseudo code...
1219 if (ConditionPassed())
1220 {
1221 EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13);
1222 address = SP - imm32;
1223 SP = SP - imm32;
1224 if single_regs then
1225 for r = 0 to regs-1
1226 MemA[address,4] = S[d+r]; address = address+4;
1227 else
1228 for r = 0 to regs-1
1229 // Store as two word-aligned words in the correct order for current endianness.
1230 MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>;
1231 MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>;
1232 address = address+8;
1233 }
1234#endif
1235
1236 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001237 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen799dfd02011-01-26 23:14:33 +00001238 if (!success)
1239 return false;
1240
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001241 if (ConditionPassed())
Johnny Chen799dfd02011-01-26 23:14:33 +00001242 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001243 const uint32_t addr_byte_size = GetAddressByteSize();
1244 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen799dfd02011-01-26 23:14:33 +00001245 if (!success)
1246 return false;
1247 bool single_regs;
Johnny Chen587a0a42011-02-01 18:35:28 +00001248 uint32_t d; // UInt(D:Vd) or UInt(Vd:D) starting register
Johnny Chen799dfd02011-01-26 23:14:33 +00001249 uint32_t imm32; // stack offset
1250 uint32_t regs; // number of registers
1251 switch (encoding) {
1252 case eEncodingT1:
1253 case eEncodingA1:
1254 single_regs = false;
Johnny Chenbd599902011-02-10 21:39:01 +00001255 d = Bit32(opcode, 22) << 4 | Bits32(opcode, 15, 12);
Johnny Chen799dfd02011-01-26 23:14:33 +00001256 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1257 // If UInt(imm8) is odd, see "FSTMX".
1258 regs = Bits32(opcode, 7, 0) / 2;
1259 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1260 if (regs == 0 || regs > 16 || (d + regs) > 32)
1261 return false;
1262 break;
1263 case eEncodingT2:
1264 case eEncodingA2:
1265 single_regs = true;
Johnny Chenbd599902011-02-10 21:39:01 +00001266 d = Bits32(opcode, 15, 12) << 1 | Bit32(opcode, 22);
Johnny Chen799dfd02011-01-26 23:14:33 +00001267 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1268 regs = Bits32(opcode, 7, 0);
1269 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1270 if (regs == 0 || regs > 16 || (d + regs) > 32)
1271 return false;
1272 break;
1273 default:
1274 return false;
1275 }
1276 uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
1277 uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2;
1278 addr_t sp_offset = imm32;
1279 addr_t addr = sp - sp_offset;
1280 uint32_t i;
1281
1282 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
1283 for (i=d; i<regs; ++i)
1284 {
1285 context.arg1 = start_reg + i; // arg1 in the context is the DWARF register number
1286 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
1287 // uint64_t to accommodate 64-bit registers.
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001288 uint64_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
Johnny Chen799dfd02011-01-26 23:14:33 +00001289 if (!success)
1290 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001291 if (!WriteMemoryUnsigned (context, addr, reg_value, reg_byte_size))
Johnny Chen799dfd02011-01-26 23:14:33 +00001292 return false;
1293 addr += reg_byte_size;
1294 }
1295
1296 context.type = EmulateInstruction::eContextAdjustStackPointer;
1297 context.arg0 = eRegisterKindGeneric;
1298 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +00001299 context.arg2 = -sp_offset;
Johnny Chen799dfd02011-01-26 23:14:33 +00001300
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001301 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
Johnny Chen799dfd02011-01-26 23:14:33 +00001302 return false;
1303 }
1304 return true;
1305}
1306
Johnny Chen587a0a42011-02-01 18:35:28 +00001307// Vector Pop loads multiple extension registers from the stack.
1308// It also updates SP to point just above the loaded data.
1309bool
1310EmulateInstructionARM::EmulateVPOP (ARMEncoding encoding)
1311{
1312#if 0
1313 // ARM pseudo code...
1314 if (ConditionPassed())
1315 {
1316 EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13);
1317 address = SP;
1318 SP = SP + imm32;
1319 if single_regs then
1320 for r = 0 to regs-1
1321 S[d+r] = MemA[address,4]; address = address+4;
1322 else
1323 for r = 0 to regs-1
1324 word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8;
1325 // Combine the word-aligned words in the correct order for current endianness.
1326 D[d+r] = if BigEndian() then word1:word2 else word2:word1;
1327 }
1328#endif
1329
1330 bool success = false;
1331 const uint32_t opcode = OpcodeAsUnsigned (&success);
1332 if (!success)
1333 return false;
1334
1335 if (ConditionPassed())
1336 {
1337 const uint32_t addr_byte_size = GetAddressByteSize();
1338 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
1339 if (!success)
1340 return false;
1341 bool single_regs;
1342 uint32_t d; // UInt(D:Vd) or UInt(Vd:D) starting register
1343 uint32_t imm32; // stack offset
1344 uint32_t regs; // number of registers
1345 switch (encoding) {
1346 case eEncodingT1:
1347 case eEncodingA1:
1348 single_regs = false;
Johnny Chenbd599902011-02-10 21:39:01 +00001349 d = Bit32(opcode, 22) << 4 | Bits32(opcode, 15, 12);
Johnny Chen587a0a42011-02-01 18:35:28 +00001350 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1351 // If UInt(imm8) is odd, see "FLDMX".
1352 regs = Bits32(opcode, 7, 0) / 2;
1353 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1354 if (regs == 0 || regs > 16 || (d + regs) > 32)
1355 return false;
1356 break;
1357 case eEncodingT2:
1358 case eEncodingA2:
1359 single_regs = true;
Johnny Chenbd599902011-02-10 21:39:01 +00001360 d = Bits32(opcode, 15, 12) << 1 | Bit32(opcode, 22);
Johnny Chen587a0a42011-02-01 18:35:28 +00001361 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1362 regs = Bits32(opcode, 7, 0);
1363 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1364 if (regs == 0 || regs > 16 || (d + regs) > 32)
1365 return false;
1366 break;
1367 default:
1368 return false;
1369 }
1370 uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
1371 uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2;
1372 addr_t sp_offset = imm32;
1373 addr_t addr = sp;
1374 uint32_t i;
1375 uint64_t data; // uint64_t to accomodate 64-bit registers.
1376
1377 EmulateInstruction::Context context = { EmulateInstruction::eContextPopRegisterOffStack, eRegisterKindDWARF, 0, 0 };
1378 for (i=d; i<regs; ++i)
1379 {
1380 context.arg1 = start_reg + i; // arg1 in the context is the DWARF register number
1381 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
1382 data = ReadMemoryUnsigned(context, addr, reg_byte_size, 0, &success);
1383 if (!success)
1384 return false;
1385 if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, context.arg1, data))
1386 return false;
1387 addr += reg_byte_size;
1388 }
1389
1390 context.type = EmulateInstruction::eContextAdjustStackPointer;
1391 context.arg0 = eRegisterKindGeneric;
1392 context.arg1 = LLDB_REGNUM_GENERIC_SP;
1393 context.arg2 = sp_offset;
1394
1395 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp + sp_offset))
1396 return false;
1397 }
1398 return true;
1399}
1400
Johnny Chenb77be412011-02-04 00:40:18 +00001401// SVC (previously SWI)
1402bool
1403EmulateInstructionARM::EmulateSVC (ARMEncoding encoding)
1404{
1405#if 0
1406 // ARM pseudo code...
1407 if (ConditionPassed())
1408 {
1409 EncodingSpecificOperations();
1410 CallSupervisor();
1411 }
1412#endif
1413
1414 bool success = false;
1415 const uint32_t opcode = OpcodeAsUnsigned (&success);
1416 if (!success)
1417 return false;
1418
1419 if (ConditionPassed())
1420 {
1421 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1422 addr_t lr; // next instruction address
1423 if (!success)
1424 return false;
1425 uint32_t imm32; // the immediate constant
1426 uint32_t mode; // ARM or Thumb mode
1427 switch (encoding) {
1428 case eEncodingT1:
1429 lr = (pc + 2) | 1u; // return address
1430 imm32 = Bits32(opcode, 7, 0);
1431 mode = eModeThumb;
1432 break;
1433 case eEncodingA1:
1434 lr = pc + 4; // return address
1435 imm32 = Bits32(opcode, 23, 0);
1436 mode = eModeARM;
1437 break;
1438 default:
1439 return false;
1440 }
1441 EmulateInstruction::Context context = { EmulateInstruction::eContextSupervisorCall, mode, imm32, 0};
1442 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
1443 return false;
1444 }
1445 return true;
1446}
1447
Johnny Chenc315f862011-02-05 00:46:10 +00001448// If Then makes up to four following instructions (the IT block) conditional.
1449bool
1450EmulateInstructionARM::EmulateIT (ARMEncoding encoding)
1451{
1452#if 0
1453 // ARM pseudo code...
1454 EncodingSpecificOperations();
1455 ITSTATE.IT<7:0> = firstcond:mask;
1456#endif
1457
1458 bool success = false;
1459 const uint32_t opcode = OpcodeAsUnsigned (&success);
1460 if (!success)
1461 return false;
1462
1463 m_it_session.InitIT(Bits32(opcode, 7, 0));
1464 return true;
1465}
1466
Johnny Chen3b620b32011-02-07 20:11:47 +00001467// Branch causes a branch to a target address.
1468bool
1469EmulateInstructionARM::EmulateB (ARMEncoding encoding)
1470{
1471#if 0
1472 // ARM pseudo code...
1473 if (ConditionPassed())
1474 {
1475 EncodingSpecificOperations();
1476 BranchWritePC(PC + imm32);
1477 }
1478#endif
1479
1480 bool success = false;
1481 const uint32_t opcode = OpcodeAsUnsigned (&success);
1482 if (!success)
1483 return false;
1484
Johnny Chen9ee056b2011-02-08 00:06:35 +00001485 if (ConditionPassed())
1486 {
1487 EmulateInstruction::Context context = { EmulateInstruction::eContextRelativeBranchImmediate, 0, 0, 0};
1488 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001489 if (!success)
1490 return false;
Johnny Chen53ebab72011-02-08 23:21:57 +00001491 addr_t target; // target address
Johnny Chen9ee056b2011-02-08 00:06:35 +00001492 int32_t imm32; // PC-relative offset
1493 switch (encoding) {
1494 case eEncodingT1:
1495 // The 'cond' field is handled in EmulateInstructionARM::CurrentCond().
1496 imm32 = llvm::SignExtend32<9>(Bits32(opcode, 7, 0) << 1);
1497 target = pc + 4 + imm32;
1498 context.arg1 = 4 + imm32; // signed offset
1499 context.arg2 = eModeThumb; // target instruction set
1500 break;
1501 case eEncodingT2:
1502 imm32 = llvm::SignExtend32<12>(Bits32(opcode, 10, 0));
1503 target = pc + 4 + imm32;
1504 context.arg1 = 4 + imm32; // signed offset
1505 context.arg2 = eModeThumb; // target instruction set
1506 break;
1507 case eEncodingT3:
1508 // The 'cond' field is handled in EmulateInstructionARM::CurrentCond().
1509 {
Johnny Chenbd599902011-02-10 21:39:01 +00001510 uint32_t S = Bit32(opcode, 26);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001511 uint32_t imm6 = Bits32(opcode, 21, 16);
Johnny Chenbd599902011-02-10 21:39:01 +00001512 uint32_t J1 = Bit32(opcode, 13);
1513 uint32_t J2 = Bit32(opcode, 11);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001514 uint32_t imm11 = Bits32(opcode, 10, 0);
Johnny Chen53ebab72011-02-08 23:21:57 +00001515 uint32_t imm21 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001516 imm32 = llvm::SignExtend32<21>(imm21);
1517 target = pc + 4 + imm32;
1518 context.arg1 = eModeThumb; // target instruction set
1519 context.arg2 = 4 + imm32; // signed offset
1520 break;
1521 }
1522 case eEncodingT4:
1523 {
Johnny Chenbd599902011-02-10 21:39:01 +00001524 uint32_t S = Bit32(opcode, 26);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001525 uint32_t imm10 = Bits32(opcode, 25, 16);
Johnny Chenbd599902011-02-10 21:39:01 +00001526 uint32_t J1 = Bit32(opcode, 13);
1527 uint32_t J2 = Bit32(opcode, 11);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001528 uint32_t imm11 = Bits32(opcode, 10, 0);
1529 uint32_t I1 = !(J1 ^ S);
1530 uint32_t I2 = !(J2 ^ S);
Johnny Chen53ebab72011-02-08 23:21:57 +00001531 uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001532 imm32 = llvm::SignExtend32<25>(imm25);
1533 target = pc + 4 + imm32;
1534 context.arg1 = eModeThumb; // target instruction set
1535 context.arg2 = 4 + imm32; // signed offset
1536 break;
1537 }
1538 case eEncodingA1:
1539 imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2);
1540 target = pc + 8 + imm32;
1541 context.arg1 = eModeARM; // target instruction set
1542 context.arg2 = 8 + imm32; // signed offset
1543 break;
1544 default:
1545 return false;
1546 }
1547 if (!BranchWritePC(context, target))
1548 return false;
1549 }
1550 return true;
Johnny Chen3b620b32011-02-07 20:11:47 +00001551}
1552
Johnny Chen53ebab72011-02-08 23:21:57 +00001553// Compare and Branch on Nonzero and Compare and Branch on Zero compare the value in a register with
1554// zero and conditionally branch forward a constant value. They do not affect the condition flags.
1555// CBNZ, CBZ
1556bool
1557EmulateInstructionARM::EmulateCB (ARMEncoding encoding)
1558{
1559#if 0
1560 // ARM pseudo code...
1561 EncodingSpecificOperations();
1562 if nonzero ^ IsZero(R[n]) then
1563 BranchWritePC(PC + imm32);
1564#endif
1565
1566 bool success = false;
1567 const uint32_t opcode = OpcodeAsUnsigned (&success);
1568 if (!success)
1569 return false;
1570
1571 // Read the register value from the operand register Rn.
1572 uint32_t reg_val = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Bits32(opcode, 2, 0), 0, &success);
1573 if (!success)
1574 return false;
1575
1576 EmulateInstruction::Context context = { EmulateInstruction::eContextRelativeBranchImmediate, 0, 0, 0};
1577 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1578 if (!success)
1579 return false;
1580
1581 addr_t target; // target address
1582 uint32_t imm32; // PC-relative offset to branch forward
1583 bool nonzero;
1584 switch (encoding) {
1585 case eEncodingT1:
Johnny Chenbd599902011-02-10 21:39:01 +00001586 imm32 = Bit32(opcode, 9) << 6 | Bits32(opcode, 7, 3) << 1;
Johnny Chen53ebab72011-02-08 23:21:57 +00001587 nonzero = BitIsSet(opcode, 11);
1588 target = pc + 4 + imm32;
1589 context.arg1 = 4 + imm32; // signed offset
1590 context.arg2 = eModeThumb; // target instruction set
1591 break;
1592 default:
1593 return false;
1594 }
1595 if (nonzero ^ (reg_val == 0))
1596 if (!BranchWritePC(context, target))
1597 return false;
1598
1599 return true;
1600}
1601
Johnny Chen26863dc2011-02-09 23:43:29 +00001602// ADD <Rdn>, <Rm>
1603// where <Rdn> the destination register is also the first operand register
1604// and <Rm> is the second operand register.
1605bool
1606EmulateInstructionARM::EmulateAddRdnRm (ARMEncoding encoding)
1607{
1608#if 0
1609 // ARM pseudo code...
1610 if ConditionPassed() then
1611 EncodingSpecificOperations();
1612 shifted = Shift(R[m], shift_t, shift_n, APSR.C);
1613 (result, carry, overflow) = AddWithCarry(R[n], shifted, '0');
1614 if d == 15 then
1615 ALUWritePC(result); // setflags is always FALSE here
1616 else
1617 R[d] = result;
1618 if setflags then
1619 APSR.N = result<31>;
1620 APSR.Z = IsZeroBit(result);
1621 APSR.C = carry;
1622 APSR.V = overflow;
1623#endif
1624
1625 bool success = false;
1626 const uint32_t opcode = OpcodeAsUnsigned (&success);
1627 if (!success)
1628 return false;
1629
1630 if (ConditionPassed())
1631 {
1632 uint32_t Rd, Rn, Rm;
1633 //bool setflags = false;
1634 switch (encoding)
1635 {
1636 case eEncodingT2:
1637 // setflags = FALSE
Johnny Chenbd599902011-02-10 21:39:01 +00001638 Rd = Rn = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0);
Johnny Chen26863dc2011-02-09 23:43:29 +00001639 Rm = Bits32(opcode, 6, 3);
1640 if (Rn == 15 && Rm == 15)
1641 return false;
1642 break;
1643 default:
1644 return false;
1645 }
1646
1647 int32_t result, val1, val2;
1648 // Read the first operand.
1649 if (Rn == 15)
1650 val1 = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1651 else
1652 val1 = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success);
1653 if (!success)
1654 return false;
1655
1656 // Read the second operand.
1657 if (Rm == 15)
1658 val2 = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1659 else
1660 val2 = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
1661 if (!success)
1662 return false;
1663
1664 result = val1 + val2;
1665 EmulateInstruction::Context context = { EmulateInstruction::eContextImmediate,
1666 result,
1667 0,
1668 0 };
1669
1670 if (Rd == 15)
1671 {
1672 if (!ALUWritePC (context, result))
1673 return false;
1674 }
1675 else
1676 {
1677 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, result))
1678 return false;
1679 }
1680 }
1681 return true;
1682}
1683
Johnny Chend4dc4442011-02-11 02:02:56 +00001684bool
1685EmulateInstructionARM::EmulateCmpRnImm (ARMEncoding encoding)
1686{
1687#if 0
1688 // ARM pseudo code...
1689 if ConditionPassed() then
1690 EncodingSpecificOperations();
1691 (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1');
1692 APSR.N = result<31>;
1693 APSR.Z = IsZeroBit(result);
1694 APSR.C = carry;
1695 APSR.V = overflow;
1696#endif
1697
1698 bool success = false;
1699 const uint32_t opcode = OpcodeAsUnsigned (&success);
1700 if (!success)
1701 return false;
1702
1703 uint32_t Rn; // the first operand
1704 uint32_t imm32; // the immediate value to be compared with
1705 switch (encoding) {
1706 case eEncodingT1:
1707 Rn = Bits32(opcode, 10, 8);
1708 imm32 = Bits32(opcode, 7, 0);
1709 break;
1710 default:
1711 return false;
1712 }
1713 // Read the register value from the operand register Rn.
1714 uint32_t reg_val = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success);
1715 if (!success)
1716 return false;
1717
1718 EmulateInstruction::Context context = { EmulateInstruction::eContextImmediate, 0, 0, 0};
1719 AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1);
1720 m_new_inst_cpsr = m_inst_cpsr;
1721 SetBit32(m_new_inst_cpsr, CPSR_N, Bit32(res.result, CPSR_N));
1722 SetBit32(m_new_inst_cpsr, CPSR_Z, res.result == 0 ? 1 : 0);
1723 SetBit32(m_new_inst_cpsr, CPSR_C, res.carry_out);
1724 SetBit32(m_new_inst_cpsr, CPSR_V, res.overflow);
1725 if (m_new_inst_cpsr != m_inst_cpsr)
1726 {
1727 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
1728 return false;
1729 }
1730 return true;
1731}
1732
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001733// LDM loads multiple registers from consecutive memory locations, using an
Caroline Tice713c2662011-02-11 17:59:55 +00001734// address from a base register. Optionally the address just above the highest of those locations
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001735// can be written back to the base register.
1736bool
1737EmulateInstructionARM::EmulateLDM (ARMEncoding encoding)
1738{
1739#if 0
1740 // ARM pseudo code...
1741 if ConditionPassed()
1742 EncodingSpecificOperations(); NullCheckIfThumbEE (n);
1743 address = R[n];
1744
1745 for i = 0 to 14
1746 if registers<i> == '1' then
1747 R[i] = MemA[address, 4]; address = address + 4;
1748 if registers<15> == '1' then
1749 LoadWritePC (MemA[address, 4]);
1750
1751 if wback && registers<n> == '0' then R[n] = R[n] + 4 * BitCount (registers);
1752 if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
1753
1754#endif
1755
1756 bool success = false;
1757 const uint32_t opcode = OpcodeAsUnsigned (&success);
1758 if (!success)
1759 return false;
1760
1761 if (ConditionPassed())
1762 {
1763 uint32_t n;
1764 uint32_t registers = 0;
1765 bool wback;
1766 const uint32_t addr_byte_size = GetAddressByteSize();
1767 switch (encoding)
1768 {
1769 case eEncodingT1:
1770 n = Bits32 (opcode, 10, 8);
1771 registers = Bits32 (opcode, 7, 0);
1772 wback = BitIsClear (registers, n);
1773 // if BitCount(registers) < 1 then UNPREDICTABLE;
1774 if (BitCount(registers) < 1)
1775 return false;
1776 break;
1777 case eEncodingT2:
1778 n = Bits32 (opcode, 19, 16);
1779 registers = Bits32 (opcode, 15, 0);
1780 wback = BitIsSet (opcode, 21);
1781 if ((n == 15)
1782 || (BitCount (registers) < 2)
1783 || (BitIsSet (opcode, 14) && BitIsSet (opcode, 15)))
1784 return false;
1785 if (BitIsSet (registers, 15)
1786 && m_it_session.InITBlock()
1787 && !m_it_session.LastInITBlock())
1788 return false;
1789 if (wback
1790 && BitIsSet (registers, n))
1791 return false;
1792 break;
1793 case eEncodingA1:
1794 n = Bits32 (opcode, 19, 16);
1795 registers = Bits32 (opcode, 15, 0);
1796 wback = BitIsSet (opcode, 21);
1797 if ((n == 15)
1798 || (BitCount (registers) < 1))
1799 return false;
1800 break;
1801 default:
1802 return false;
1803 }
1804
1805 int32_t offset = 0;
1806 const addr_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
1807 if (!success)
1808 return false;
Caroline Tice85aab332011-02-08 23:56:10 +00001809
1810 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
1811 eRegisterKindDWARF,
1812 dwarf_r0 + n,
1813 offset };
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001814
1815 for (int i = 0; i < 14; ++i)
1816 {
1817 if (BitIsSet (registers, i))
1818 {
Caroline Tice85aab332011-02-08 23:56:10 +00001819 context.type = EmulateInstruction::eContextRegisterPlusOffset;
1820 context.arg2 = offset;
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001821 if (wback && (n == 13)) // Pop Instruction
1822 context.type = EmulateInstruction::eContextPopRegisterOffStack;
1823
1824 // R[i] = MemA [address, 4]; address = address + 4;
1825 uint32_t data = ReadMemoryUnsigned (context, base_address + offset, addr_byte_size, 0, &success);
1826 if (!success)
1827 return false;
1828
1829 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
1830 return false;
1831
1832 offset += addr_byte_size;
1833 }
1834 }
1835
1836 if (BitIsSet (registers, 15))
1837 {
1838 //LoadWritePC (MemA [address, 4]);
Caroline Tice85aab332011-02-08 23:56:10 +00001839 context.type = EmulateInstruction::eContextRegisterPlusOffset;
1840 context.arg2 = offset;
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001841 uint32_t data = ReadMemoryUnsigned (context, base_address + offset, addr_byte_size, 0, &success);
1842 if (!success)
1843 return false;
Johnny Chene62b50d2011-02-09 22:02:17 +00001844 // In ARMv5T and above, this is an interworking branch.
1845 if (!LoadWritePC(context, data))
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001846 return false;
1847 }
1848
1849 if (wback && BitIsClear (registers, n))
1850 {
1851 addr_t offset = addr_byte_size * BitCount (registers);
Caroline Tice85aab332011-02-08 23:56:10 +00001852 context.type = EmulateInstruction::eContextRegisterPlusOffset;
1853 context.arg2 = offset;
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001854
1855 // R[n] = R[n] + 4 * BitCount (registers)
1856 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, base_address + offset))
1857 return false;
1858 }
1859 if (wback && BitIsSet (registers, n))
1860 // R[n] bits(32) UNKNOWN;
Caroline Tice713c2662011-02-11 17:59:55 +00001861 return WriteBits32Unknown (n);
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001862 }
1863 return true;
1864}
Caroline Tice713c2662011-02-11 17:59:55 +00001865
1866// LDMDA loads multiple registers from consecutive memory locations using an address from a base registers.
1867// The consecutive memorty locations end at this address and the address just below the lowest of those locations
1868// can optionally be written back tot he base registers.
1869bool
1870EmulateInstructionARM::EmulateLDMDA (ARMEncoding encoding)
1871{
1872#if 0
1873 // ARM pseudo code...
1874 if ConditionPassed() then
1875 EncodingSpecificOperations();
1876 address = R[n] - 4*BitCount(registers) + 4;
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001877
Caroline Tice713c2662011-02-11 17:59:55 +00001878 for i = 0 to 14
1879 if registers<i> == ’1’ then
1880 R[i] = MemA[address,4]; address = address + 4;
1881
1882 if registers<15> == ’1’ then
1883 LoadWritePC(MemA[address,4]);
1884
1885 if wback && registers<n> == ’0’ then R[n] = R[n] - 4*BitCount(registers);
1886 if wback && registers<n> == ’1’ then R[n] = bits(32) UNKNOWN;
1887#endif
1888
1889 bool success = false;
1890 const uint32_t opcode = OpcodeAsUnsigned (&success);
1891 if (!success)
1892 return false;
1893
1894 if (ConditionPassed())
1895 {
1896 uint32_t n;
1897 uint32_t registers = 0;
1898 bool wback;
1899 const uint32_t addr_byte_size = GetAddressByteSize();
1900
1901 // EncodingSpecificOperations();
1902 switch (encoding)
1903 {
1904 case eEncodingA1:
1905 // n = UInt(Rn); registers = register_list; wback = (W == ’1’);
1906 n = Bits32 (opcode, 19, 16);
1907 registers = Bits32 (opcode, 15, 0);
1908 wback = BitIsSet (opcode, 21);
1909
1910 // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
1911 if ((n == 15) || (BitCount (registers) < 1))
1912 return false;
1913
1914 break;
1915
1916 default:
1917 return false;
1918 }
1919 // address = R[n] - 4*BitCount(registers) + 4;
1920
1921 int32_t offset = 0;
1922 addr_t address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
1923
1924 if (!success)
1925 return false;
1926
1927 address = address - (addr_byte_size * BitCount (registers)) + addr_byte_size;
1928
1929 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
1930 eRegisterKindDWARF,
1931 dwarf_r0 + n,
1932 offset };
1933
1934 // for i = 0 to 14
1935 for (int i = 0; i < 14; ++i)
1936 {
1937 // if registers<i> == ’1’ then
1938 if (BitIsSet (registers, i))
1939 {
1940 // R[i] = MemA[address,4]; address = address + 4;
1941 context.arg2 = offset;
1942 uint32_t data = ReadMemoryUnsigned (context, address + offset, addr_byte_size, 0, &success);
1943 if (!success)
1944 return false;
1945 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
1946 return false;
1947 offset += addr_byte_size;
1948 }
1949 }
1950
1951 // if registers<15> == ’1’ then
1952 // LoadWritePC(MemA[address,4]);
1953 if (BitIsSet (registers, 15))
1954 {
1955 context.arg2 = offset;
1956 uint32_t data = ReadMemoryUnsigned (context, address + offset, addr_byte_size, 0, &success);
1957 if (!success)
1958 return false;
1959 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, data))
1960 return false;
1961 }
1962
1963 // if wback && registers<n> == ’0’ then R[n] = R[n] - 4*BitCount(registers);
1964 if (wback && BitIsClear (registers, n))
1965 {
1966 context.arg2 = offset;
1967 addr_t addr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
1968 if (!success)
1969 return false;
1970 addr = addr - (addr_byte_size * BitCount (registers));
1971 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr))
1972 return false;
1973 }
1974
1975 // if wback && registers<n> == ’1’ then R[n] = bits(32) UNKNOWN;
1976 if (wback && BitIsSet (registers, n))
1977 return WriteBits32Unknown (n);
1978 }
1979 return true;
1980}
1981
1982// LDMDB loads multiple registers from consecutive memory locations using an address from a base register. The
1983// consecutive memory lcoations end just below this address, and the address of the lowest of those locations can
1984// be optionally written back to the base register.
Caroline Tice0b29e242011-02-08 23:16:02 +00001985bool
1986EmulateInstructionARM::EmulateLDMDB (ARMEncoding encoding)
1987{
1988#if 0
1989 // ARM pseudo code...
1990 if ConditionPassed() then
1991 EncodingSpecificOperations(); NullCheckIfThumbEE(n);
1992 address = R[n] - 4*BitCount(registers);
1993
1994 for i = 0 to 14
1995 if registers<i> == ’1’ then
1996 R[i] = MemA[address,4]; address = address + 4;
1997 if registers<15> == ’1’ then
1998 LoadWritePC(MemA[address,4]);
1999
2000 if wback && registers<n> == ’0’ then R[n] = R[n] - 4*BitCount(registers);
2001 if wback && registers<n> == ’1’ then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
2002#endif
2003
2004 bool success = false;
2005 const uint32_t opcode = OpcodeAsUnsigned (&success);
2006 if (!success)
2007 return false;
2008
2009 if (ConditionPassed())
2010 {
2011 uint32_t n;
2012 uint32_t registers = 0;
2013 bool wback;
2014 const uint32_t addr_byte_size = GetAddressByteSize();
2015 switch (encoding)
2016 {
2017 case eEncodingT1:
2018 // n = UInt(Rn); registers = P:M:’0’:register_list; wback = (W == ’1’);
2019 n = Bits32 (opcode, 19, 16);
2020 registers = Bits32 (opcode, 15, 0);
2021 wback = BitIsSet (opcode, 21);
2022
2023 // if n == 15 || BitCount(registers) < 2 || (P == ’1’ && M == ’1’) then UNPREDICTABLE;
2024 if ((n == 15)
2025 || (BitCount (registers) < 2)
2026 || (BitIsSet (opcode, 14) && BitIsSet (opcode, 15)))
2027 return false;
2028
2029 // if registers<15> == ’1’ && InITBlock() && !LastInITBlock() then UNPREDICTABLE;
2030 if (BitIsSet (registers, 15)
2031 && m_it_session.InITBlock()
2032 && !m_it_session.LastInITBlock())
2033 return false;
2034
2035 // if wback && registers<n> == ’1’ then UNPREDICTABLE;
2036 if (wback && BitIsSet (registers, n))
2037 return false;
2038
2039 break;
2040
2041 case eEncodingA1:
2042 // n = UInt(Rn); registers = register_list; wback = (W == ’1’);
2043 n = Bits32 (opcode, 19, 16);
2044 registers = Bits32 (opcode, 15, 0);
2045 wback = BitIsSet (opcode, 21);
2046
2047 // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
2048 if ((n == 15) || (BitCount (registers) < 1))
2049 return false;
2050
2051 break;
2052
2053 default:
2054 return false;
2055 }
2056
Caroline Tice713c2662011-02-11 17:59:55 +00002057 // address = R[n] - 4*BitCount(registers);
2058
Caroline Tice0b29e242011-02-08 23:16:02 +00002059 int32_t offset = 0;
Caroline Tice713c2662011-02-11 17:59:55 +00002060 addr_t address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
2061
2062 if (!success)
2063 return false;
2064
2065 address = address - (addr_byte_size * BitCount (registers));
Caroline Tice85aab332011-02-08 23:56:10 +00002066 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
2067 eRegisterKindDWARF,
2068 dwarf_r0 + n,
2069 offset };
Caroline Tice0b29e242011-02-08 23:16:02 +00002070
2071 for (int i = 0; i < 14; ++i)
2072 {
2073 if (BitIsSet (registers, i))
2074 {
2075 // R[i] = MemA[address,4]; address = address + 4;
Caroline Tice85aab332011-02-08 23:56:10 +00002076 context.arg2 = offset;
Caroline Tice0b29e242011-02-08 23:16:02 +00002077 uint32_t data = ReadMemoryUnsigned (context, address + offset, addr_byte_size, 0, &success);
2078 if (!success)
2079 return false;
2080
2081 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
2082 return false;
2083
2084 offset += addr_byte_size;
2085 }
2086 }
2087
2088 // if registers<15> == ’1’ then
2089 // LoadWritePC(MemA[address,4]);
2090 if (BitIsSet (registers, 15))
2091 {
Caroline Tice85aab332011-02-08 23:56:10 +00002092 context.arg2 = offset;
Caroline Tice0b29e242011-02-08 23:16:02 +00002093 uint32_t data = ReadMemoryUnsigned (context, address + offset, addr_byte_size, 0, &success);
2094 if (!success)
2095 return false;
Johnny Chene62b50d2011-02-09 22:02:17 +00002096 // In ARMv5T and above, this is an interworking branch.
2097 if (!LoadWritePC(context, data))
Caroline Tice0b29e242011-02-08 23:16:02 +00002098 return false;
2099 }
2100
2101 // if wback && registers<n> == ’0’ then R[n] = R[n] - 4*BitCount(registers);
2102 if (wback && BitIsClear (registers, n))
2103 {
Caroline Tice85aab332011-02-08 23:56:10 +00002104 context.arg2 = offset;
Caroline Tice0b29e242011-02-08 23:16:02 +00002105 addr_t addr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
2106 if (!success)
2107 return false;
2108 addr = addr - (addr_byte_size * BitCount (registers));
2109 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr))
2110 return false;
2111 }
2112
2113 // if wback && registers<n> == ’1’ then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
2114 if (wback && BitIsSet (registers, n))
Caroline Tice713c2662011-02-11 17:59:55 +00002115 return WriteBits32Unknown (n);
Caroline Tice0b29e242011-02-08 23:16:02 +00002116 }
2117 return true;
2118}
Caroline Tice85aab332011-02-08 23:56:10 +00002119
Caroline Tice713c2662011-02-11 17:59:55 +00002120// LDMIB loads multiple registers from consecutive memory locations using an address from a base register. The
2121// consecutive memory locations start just above this address, and thea ddress of the last of those locations can
2122// optinoally be written back to the base register.
Caroline Tice85aab332011-02-08 23:56:10 +00002123bool
2124EmulateInstructionARM::EmulateLDMIB (ARMEncoding encoding)
2125{
2126#if 0
2127 if ConditionPassed() then
2128 EncodingSpecificOperations();
2129 address = R[n] + 4;
2130
2131 for i = 0 to 14
2132 if registers<i> == ’1’ then
2133 R[i] = MemA[address,4]; address = address + 4;
2134 if registers<15> == ’1’ then
2135 LoadWritePC(MemA[address,4]);
2136
2137 if wback && registers<n> == ’0’ then R[n] = R[n] + 4*BitCount(registers);
2138 if wback && registers<n> == ’1’ then R[n] = bits(32) UNKNOWN;
2139#endif
2140
2141 bool success = false;
2142 const uint32_t opcode = OpcodeAsUnsigned (&success);
2143 if (!success)
2144 return false;
2145
2146 if (ConditionPassed())
2147 {
2148 uint32_t n;
2149 uint32_t registers = 0;
2150 bool wback;
2151 const uint32_t addr_byte_size = GetAddressByteSize();
2152 switch (encoding)
2153 {
2154 case eEncodingA1:
2155 // n = UInt(Rn); registers = register_list; wback = (W == ’1’);
2156 n = Bits32 (opcode, 19, 16);
2157 registers = Bits32 (opcode, 15, 0);
2158 wback = BitIsSet (opcode, 21);
2159
2160 // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
2161 if ((n == 15) || (BitCount (registers) < 1))
2162 return false;
2163
2164 break;
2165 default:
2166 return false;
2167 }
2168 // address = R[n] + 4;
2169
2170 int32_t offset = 0;
Caroline Tice713c2662011-02-11 17:59:55 +00002171 addr_t address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
2172
2173 if (!success)
2174 return false;
2175
2176 address = address + addr_byte_size;
Caroline Tice85aab332011-02-08 23:56:10 +00002177
2178 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
2179 eRegisterKindDWARF,
2180 dwarf_r0 + n,
2181 offset };
2182
2183 for (int i = 0; i < 14; ++i)
2184 {
2185 if (BitIsSet (registers, i))
2186 {
2187 // R[i] = MemA[address,4]; address = address + 4;
2188
2189 context.arg2 = offset;
2190 uint32_t data = ReadMemoryUnsigned (context, address + offset, addr_byte_size, 0, &success);
2191 if (!success)
2192 return false;
2193
2194 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
2195 return false;
2196
2197 offset += addr_byte_size;
2198 }
2199 }
2200
2201 // if registers<15> == ’1’ then
2202 // LoadWritePC(MemA[address,4]);
2203 if (BitIsSet (registers, 15))
2204 {
2205 context.arg2 = offset;
2206 uint32_t data = ReadMemoryUnsigned (context, address + offset, addr_byte_size, 0, &success);
2207 if (!success)
2208 return false;
Johnny Chene62b50d2011-02-09 22:02:17 +00002209 // In ARMv5T and above, this is an interworking branch.
2210 if (!LoadWritePC(context, data))
Caroline Tice85aab332011-02-08 23:56:10 +00002211 return false;
2212 }
2213
2214 // if wback && registers<n> == ’0’ then R[n] = R[n] + 4*BitCount(registers);
2215 if (wback && BitIsClear (registers, n))
2216 {
2217 context.arg2 = offset;
2218 addr_t addr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
2219 if (!success)
2220 return false;
2221 addr = addr + (addr_byte_size * BitCount (registers));
2222 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr))
2223 return false;
2224 }
2225
2226 // if wback && registers<n> == ’1’ then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
2227 if (wback && BitIsSet (registers, n))
Caroline Tice713c2662011-02-11 17:59:55 +00002228 return WriteBits32Unknown (n);
Caroline Tice85aab332011-02-08 23:56:10 +00002229 }
2230 return true;
2231}
Caroline Tice0b29e242011-02-08 23:16:02 +00002232
Johnny Chenef21b592011-02-10 01:52:38 +00002233// Load Register (immediate) calculates an address from a base register value and
2234// an immediate offset, loads a word from memory, and writes to a register.
2235// LDR (immediate, Thumb)
2236bool
2237EmulateInstructionARM::EmulateLDRRtRnImm (ARMEncoding encoding)
2238{
2239#if 0
2240 // ARM pseudo code...
2241 if (ConditionPassed())
2242 {
2243 EncodingSpecificOperations(); NullCheckIfThumbEE(15);
2244 offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
2245 address = if index then offset_addr else R[n];
2246 data = MemU[address,4];
2247 if wback then R[n] = offset_addr;
2248 if t == 15 then
2249 if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
2250 elsif UnalignedSupport() || address<1:0> = '00' then
2251 R[t] = data;
2252 else R[t] = bits(32) UNKNOWN; // Can only apply before ARMv7
2253 }
2254#endif
2255
2256 bool success = false;
2257 const uint32_t opcode = OpcodeAsUnsigned (&success);
2258 if (!success)
2259 return false;
2260
2261 if (ConditionPassed())
2262 {
2263 uint32_t Rt; // the destination register
2264 uint32_t Rn; // the base register
2265 uint32_t imm32; // the immediate offset used to form the address
2266 addr_t offset_addr; // the offset address
2267 addr_t address; // the calculated address
2268 uint32_t data; // the literal data value from memory load
2269 bool add, index, wback;
2270 switch (encoding) {
2271 case eEncodingT1:
2272 Rt = Bits32(opcode, 5, 3);
2273 Rn = Bits32(opcode, 2, 0);
2274 imm32 = Bits32(opcode, 10, 6) << 2; // imm32 = ZeroExtend(imm5:'00', 32);
2275 // index = TRUE; add = TRUE; wback = FALSE
2276 add = true;
2277 index = true;
2278 wback = false;
2279 break;
2280 default:
2281 return false;
2282 }
2283 uint32_t base = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success);
2284 if (!success)
2285 return false;
2286 if (add)
2287 offset_addr = base + imm32;
2288 else
2289 offset_addr = base - imm32;
2290
2291 address = (index ? offset_addr : base);
2292
2293 if (wback)
2294 {
2295 EmulateInstruction::Context ctx = { EmulateInstruction::eContextRegisterPlusOffset,
2296 eRegisterKindDWARF,
2297 dwarf_r0 + Rn,
2298 (int32_t) (offset_addr - base)};
2299 if (!WriteRegisterUnsigned (ctx, eRegisterKindDWARF, dwarf_r0 + Rn, offset_addr))
2300 return false;
2301 }
2302
2303 // Prepare to write to the Rt register.
2304 EmulateInstruction::Context context = {EmulateInstruction::eContextImmediate,
2305 0,
2306 0,
2307 0};
2308
2309 // Read memory from the address.
2310 data = ReadMemoryUnsigned(context, address, 4, 0, &success);
2311 if (!success)
2312 return false;
2313 context.arg0 = data;
2314
2315 if (Rt == 15)
2316 {
2317 if (Bits32(address, 1, 0) == 0)
2318 {
2319 if (!LoadWritePC(context, data))
2320 return false;
2321 }
2322 else
2323 return false;
2324 }
2325 else if (UnalignedSupport() || Bits32(address, 1, 0) == 0)
2326 {
2327 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rt, data))
2328 return false;
2329 }
2330 else
2331 return false;
2332 }
2333 return true;
2334}
2335
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002336EmulateInstructionARM::ARMOpcode*
2337EmulateInstructionARM::GetARMOpcodeForInstruction (const uint32_t opcode)
Greg Clayton64c84432011-01-21 22:02:52 +00002338{
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002339 static ARMOpcode
2340 g_arm_opcodes[] =
2341 {
2342 //----------------------------------------------------------------------
2343 // Prologue instructions
2344 //----------------------------------------------------------------------
Johnny Chenfdd179e2011-01-31 20:09:28 +00002345
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002346 // push register(s)
Johnny Chenc28a76d2011-02-01 18:51:48 +00002347 { 0x0fff0000, 0x092d0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulatePush, "push <registers>" },
2348 { 0x0fff0fff, 0x052d0004, ARMvAll, eEncodingA2, eSize32, &EmulateInstructionARM::EmulatePush, "push <register>" },
Johnny Chenbcec3af2011-01-27 01:26:19 +00002349
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002350 // set r7 to point to a stack offset
Johnny Chenc28a76d2011-02-01 18:51:48 +00002351 { 0x0ffff000, 0x028d7000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateAddRdSPImmediate, "add r7, sp, #<const>" },
2352 { 0x0ffff000, 0x024c7000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSubR7IPImmediate, "sub r7, ip, #<const>"},
Johnny Chene7cf4202011-02-10 18:13:23 +00002353 // copy the stack pointer to ip
Johnny Chenc28a76d2011-02-01 18:51:48 +00002354 { 0x0fffffff, 0x01a0c00d, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateMovRdSP, "mov ip, sp" },
2355 { 0x0ffff000, 0x028dc000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateAddRdSPImmediate, "add ip, sp, #<const>" },
2356 { 0x0ffff000, 0x024dc000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSubIPSPImmediate, "sub ip, sp, #<const>"},
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00002357
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002358 // adjust the stack pointer
Johnny Chenc28a76d2011-02-01 18:51:48 +00002359 { 0x0ffff000, 0x024dd000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSubSPImmdiate, "sub sp, sp, #<const>"},
Johnny Chence1ca772011-01-25 01:13:00 +00002360
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002361 // push one register
2362 // if Rn == '1101' && imm12 == '000000000100' then SEE PUSH;
Johnny Chenc28a76d2011-02-01 18:51:48 +00002363 { 0x0fff0000, 0x052d0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSTRRtSP, "str Rt, [sp, #-imm12]!" },
Johnny Chen799dfd02011-01-26 23:14:33 +00002364
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002365 // vector push consecutive extension register(s)
Johnny Chen9b8d7832011-02-02 01:13:56 +00002366 { 0x0fbf0f00, 0x0d2d0b00, ARMV6T2_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"},
2367 { 0x0fbf0f00, 0x0d2d0a00, ARMV6T2_ABOVE, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"},
Johnny Chenef85e912011-01-31 23:07:40 +00002368
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002369 //----------------------------------------------------------------------
Johnny Chen587a0a42011-02-01 18:35:28 +00002370 // Epilogue instructions
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002371 //----------------------------------------------------------------------
Johnny Chenef85e912011-01-31 23:07:40 +00002372
Johnny Chen9b8d7832011-02-02 01:13:56 +00002373 // To resolve ambiguity, "blx <label>" should come before "bl <label>".
2374 { 0xfe000000, 0xfa000000, ARMV5_ABOVE, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
2375 { 0x0f000000, 0x0b000000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"},
2376 { 0x0ffffff0, 0x012fff30, ARMV5_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
Johnny Chenc28a76d2011-02-01 18:51:48 +00002377 { 0x0fff0000, 0x08bd0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulatePop, "pop <registers>"},
2378 { 0x0fff0fff, 0x049d0004, ARMvAll, eEncodingA2, eSize32, &EmulateInstructionARM::EmulatePop, "pop <register>"},
Johnny Chen9b8d7832011-02-02 01:13:56 +00002379 { 0x0fbf0f00, 0x0cbd0b00, ARMV6T2_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"},
Johnny Chenb77be412011-02-04 00:40:18 +00002380 { 0x0fbf0f00, 0x0cbd0a00, ARMV6T2_ABOVE, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"},
2381
2382 //----------------------------------------------------------------------
2383 // Supervisor Call (previously Software Interrupt)
2384 //----------------------------------------------------------------------
Johnny Chen3b620b32011-02-07 20:11:47 +00002385 { 0x0f000000, 0x0f000000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSVC, "svc #imm24"},
2386
2387 //----------------------------------------------------------------------
2388 // Branch instructions
2389 //----------------------------------------------------------------------
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002390 { 0x0f000000, 0x0a000000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSVC, "b #imm24"},
Johnny Chenb77be412011-02-04 00:40:18 +00002391
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002392 //----------------------------------------------------------------------
2393 // Load instructions
2394 //----------------------------------------------------------------------
Caroline Tice0b29e242011-02-08 23:16:02 +00002395 { 0x0fd00000, 0x08900000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDM, "ldm<c> <Rn>{!} <registers>" },
Caroline Tice713c2662011-02-11 17:59:55 +00002396 { 0x0fd00000, 0x08100000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDMDA, "ldmda<c> <Rn>{!} <registers>" },
Caroline Tice85aab332011-02-08 23:56:10 +00002397 { 0x0fd00000, 0x09100000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDMDB, "ldmdb<c> <Rn>{!} <registers>" },
2398 { 0x0fd00000, 0x09900000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDMIB, "ldmib<c> <Rn<{!} <registers>" }
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002399
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002400 };
2401 static const size_t k_num_arm_opcodes = sizeof(g_arm_opcodes)/sizeof(ARMOpcode);
2402
2403 for (size_t i=0; i<k_num_arm_opcodes; ++i)
2404 {
2405 if ((g_arm_opcodes[i].mask & opcode) == g_arm_opcodes[i].value)
2406 return &g_arm_opcodes[i];
2407 }
2408 return NULL;
2409}
Greg Clayton64c84432011-01-21 22:02:52 +00002410
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002411
2412EmulateInstructionARM::ARMOpcode*
2413EmulateInstructionARM::GetThumbOpcodeForInstruction (const uint32_t opcode)
Johnny Chen347320d2011-01-24 23:40:59 +00002414{
Johnny Chenfdd179e2011-01-31 20:09:28 +00002415
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002416 static ARMOpcode
2417 g_thumb_opcodes[] =
2418 {
2419 //----------------------------------------------------------------------
2420 // Prologue instructions
2421 //----------------------------------------------------------------------
Johnny Chenbcec3af2011-01-27 01:26:19 +00002422
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002423 // push register(s)
Johnny Chenc28a76d2011-02-01 18:51:48 +00002424 { 0xfffffe00, 0x0000b400, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulatePush, "push <registers>" },
Johnny Chend6c13f02011-02-08 20:36:34 +00002425 { 0xffff0000, 0xe92d0000, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulatePush, "push.w <registers>" },
2426 { 0xffff0fff, 0xf84d0d04, ARMV6T2_ABOVE, eEncodingT3, eSize32, &EmulateInstructionARM::EmulatePush, "push.w <register>" },
Johnny Chen788e0552011-01-27 22:52:23 +00002427
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002428 // set r7 to point to a stack offset
Johnny Chenc28a76d2011-02-01 18:51:48 +00002429 { 0xffffff00, 0x0000af00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateAddRdSPImmediate, "add r7, sp, #imm" },
Johnny Chene7cf4202011-02-10 18:13:23 +00002430 // copy the stack pointer to r7
Johnny Chenc28a76d2011-02-01 18:51:48 +00002431 { 0xffffffff, 0x0000466f, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateMovRdSP, "mov r7, sp" },
Johnny Chene7cf4202011-02-10 18:13:23 +00002432 // move from high register to low register (comes after "mov r7, sp" to resolve ambiguity)
2433 { 0xffffffc0, 0x00004640, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateMovLowHigh, "mov r0-r7, r8-r15" },
Johnny Chen60c0d622011-01-25 23:49:39 +00002434
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002435 // PC relative load into register (see also EmulateAddSPRm)
Johnny Chenc28a76d2011-02-01 18:51:48 +00002436 { 0xfffff800, 0x00004800, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateLDRRdPCRelative, "ldr <Rd>, [PC, #imm]"},
Johnny Chen799dfd02011-01-26 23:14:33 +00002437
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002438 // adjust the stack pointer
Johnny Chenc28a76d2011-02-01 18:51:48 +00002439 { 0xffffff87, 0x00004485, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateAddSPRm, "add sp, <Rm>"},
2440 { 0xffffff80, 0x0000b080, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateSubSPImmdiate, "add sp, sp, #imm"},
Johnny Chend6c13f02011-02-08 20:36:34 +00002441 { 0xfbef8f00, 0xf1ad0d00, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateSubSPImmdiate, "sub.w sp, sp, #<const>"},
2442 { 0xfbff8f00, 0xf2ad0d00, ARMV6T2_ABOVE, eEncodingT3, eSize32, &EmulateInstructionARM::EmulateSubSPImmdiate, "subw sp, sp, #imm12"},
Johnny Chenfdd179e2011-01-31 20:09:28 +00002443
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002444 // vector push consecutive extension register(s)
Johnny Chend6c13f02011-02-08 20:36:34 +00002445 { 0xffbf0f00, 0xed2d0b00, ARMV6T2_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"},
2446 { 0xffbf0f00, 0xed2d0a00, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"},
Johnny Chenfdd179e2011-01-31 20:09:28 +00002447
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002448 //----------------------------------------------------------------------
2449 // Epilogue instructions
2450 //----------------------------------------------------------------------
Johnny Chen347320d2011-01-24 23:40:59 +00002451
Johnny Chenc28a76d2011-02-01 18:51:48 +00002452 { 0xffffff80, 0x0000b000, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateAddSPImmediate, "add sp, #imm"},
Johnny Chen9b8d7832011-02-02 01:13:56 +00002453 { 0xffffff87, 0x00004780, ARMV5_ABOVE, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
2454 // J1 == J2 == 1
Johnny Chend6c13f02011-02-08 20:36:34 +00002455 { 0xf800f800, 0xf000f800, ARMV4T_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"},
2456 // J1 == J2 == 1
2457 { 0xf800e800, 0xf000e800, ARMV5_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
Johnny Chenc28a76d2011-02-01 18:51:48 +00002458 { 0xfffffe00, 0x0000bc00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulatePop, "pop <registers>"},
Johnny Chend6c13f02011-02-08 20:36:34 +00002459 { 0xffff0000, 0xe8bd0000, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulatePop, "pop.w <registers>" },
2460 { 0xffff0fff, 0xf85d0d04, ARMV6T2_ABOVE, eEncodingT3, eSize32, &EmulateInstructionARM::EmulatePop, "pop.w <register>" },
2461 { 0xffbf0f00, 0xecbd0b00, ARMV6T2_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"},
2462 { 0xffbf0f00, 0xecbd0a00, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"},
Johnny Chenb77be412011-02-04 00:40:18 +00002463
2464 //----------------------------------------------------------------------
2465 // Supervisor Call (previously Software Interrupt)
2466 //----------------------------------------------------------------------
Johnny Chenc315f862011-02-05 00:46:10 +00002467 { 0xffffff00, 0x0000df00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateSVC, "svc #imm8"},
2468
2469 //----------------------------------------------------------------------
2470 // If Then makes up to four following instructions conditional.
2471 //----------------------------------------------------------------------
Johnny Chen3b620b32011-02-07 20:11:47 +00002472 { 0xffffff00, 0x0000bf00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateIT, "it{<x>{<y>{<z>}}} <firstcond>"},
2473
2474 //----------------------------------------------------------------------
2475 // Branch instructions
2476 //----------------------------------------------------------------------
2477 // To resolve ambiguity, "b<c> #imm8" should come after "svc #imm8".
2478 { 0xfffff000, 0x0000d000, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateB, "b<c> #imm8 (outside IT)"},
2479 { 0xffff8000, 0x0000e000, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateB, "b #imm11 (outside or last in IT)"},
Johnny Chen9ee056b2011-02-08 00:06:35 +00002480 { 0xf800d000, 0xf0008000, ARMV6T2_ABOVE, eEncodingT3, eSize32, &EmulateInstructionARM::EmulateB, "b<c>.w #imm8 (outside IT)"},
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002481 { 0xf800d000, 0xf0009000, ARMV6T2_ABOVE, eEncodingT4, eSize32, &EmulateInstructionARM::EmulateB, "b.w #imm8 (outside or last in IT)"},
Johnny Chen53ebab72011-02-08 23:21:57 +00002482 // compare and branch
2483 { 0xfffff500, 0x0000b100, ARMV6T2_ABOVE, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateCB, "cb{n}z <Rn>, <label>"},
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002484
2485 //----------------------------------------------------------------------
Johnny Chen26863dc2011-02-09 23:43:29 +00002486 // Data-processing instructions
2487 //----------------------------------------------------------------------
2488 // Make sure "add sp, <Rm>" comes before this instruction, so there's no ambiguity decoding the two.
2489 { 0xffffff00, 0x00004400, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateAddRdnRm, "add <Rdn>, <Rm>"},
Johnny Chen338bf542011-02-10 19:29:03 +00002490 // move from high register to high register
2491 { 0xffffff00, 0x00004600, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateMovRdRm, "mov<c> <Rd>, <Rm>"},
2492 // move from low register to low register
2493 { 0xffffffc0, 0x00000000, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateMovRdRm, "movs <Rd>, <Rm>"},
Johnny Chend4dc4442011-02-11 02:02:56 +00002494 // compare a register with immediate
2495 { 0xfffff800, 0x00002800, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateCmpRnImm, "cmp<c> <Rn>, #imm8"},
Johnny Chen26863dc2011-02-09 23:43:29 +00002496
2497 //----------------------------------------------------------------------
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002498 // Load instructions
2499 //----------------------------------------------------------------------
2500 { 0xfffff800, 0x0000c800, ARMV4T_ABOVE, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateLDM, "ldm<c> <Rn>{!} <registers>" },
Caroline Tice0b29e242011-02-08 23:16:02 +00002501 { 0xffd02000, 0xe8900000, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateLDM, "ldm<c>.w <Rn>{!} <registers>" },
Johnny Chenef21b592011-02-10 01:52:38 +00002502 { 0xffd00000, 0xe9100000, ARMV6T2_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateLDMDB, "ldmdb<c> <Rn>{!} <registers>" },
2503 { 0xfffff800, 0x00006800, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr<c> <Rt>, [<Rn>{,#imm}]"}
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002504
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002505 };
2506
2507 const size_t k_num_thumb_opcodes = sizeof(g_thumb_opcodes)/sizeof(ARMOpcode);
2508 for (size_t i=0; i<k_num_thumb_opcodes; ++i)
2509 {
2510 if ((g_thumb_opcodes[i].mask & opcode) == g_thumb_opcodes[i].value)
2511 return &g_thumb_opcodes[i];
2512 }
2513 return NULL;
2514}
Greg Clayton64c84432011-01-21 22:02:52 +00002515
Greg Clayton31e2a382011-01-30 20:03:56 +00002516bool
2517EmulateInstructionARM::SetTargetTriple (const ConstString &triple)
2518{
2519 m_arm_isa = 0;
2520 const char *triple_cstr = triple.GetCString();
2521 if (triple_cstr)
2522 {
2523 const char *dash = ::strchr (triple_cstr, '-');
2524 if (dash)
2525 {
2526 std::string arch (triple_cstr, dash);
2527 const char *arch_cstr = arch.c_str();
2528 if (strcasecmp(arch_cstr, "armv4t") == 0)
2529 m_arm_isa = ARMv4T;
2530 else if (strcasecmp(arch_cstr, "armv4") == 0)
2531 m_arm_isa = ARMv4;
2532 else if (strcasecmp(arch_cstr, "armv5tej") == 0)
2533 m_arm_isa = ARMv5TEJ;
2534 else if (strcasecmp(arch_cstr, "armv5te") == 0)
2535 m_arm_isa = ARMv5TE;
2536 else if (strcasecmp(arch_cstr, "armv5t") == 0)
2537 m_arm_isa = ARMv5T;
2538 else if (strcasecmp(arch_cstr, "armv6k") == 0)
2539 m_arm_isa = ARMv6K;
2540 else if (strcasecmp(arch_cstr, "armv6") == 0)
2541 m_arm_isa = ARMv6;
2542 else if (strcasecmp(arch_cstr, "armv6t2") == 0)
2543 m_arm_isa = ARMv6T2;
2544 else if (strcasecmp(arch_cstr, "armv7") == 0)
2545 m_arm_isa = ARMv7;
2546 else if (strcasecmp(arch_cstr, "armv8") == 0)
2547 m_arm_isa = ARMv8;
2548 }
2549 }
2550 return m_arm_isa != 0;
2551}
2552
2553
Greg Clayton64c84432011-01-21 22:02:52 +00002554bool
2555EmulateInstructionARM::ReadInstruction ()
2556{
2557 bool success = false;
2558 m_inst_cpsr = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, 0, &success);
2559 if (success)
2560 {
2561 addr_t pc = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_ADDRESS, &success);
2562 if (success)
2563 {
2564 Context read_inst_context = {eContextReadOpcode, 0, 0};
2565 if (m_inst_cpsr & MASK_CPSR_T)
2566 {
2567 m_inst_mode = eModeThumb;
2568 uint32_t thumb_opcode = ReadMemoryUnsigned(read_inst_context, pc, 2, 0, &success);
2569
2570 if (success)
2571 {
2572 if ((m_inst.opcode.inst16 & 0xe000) != 0xe000 || ((m_inst.opcode.inst16 & 0x1800u) == 0))
2573 {
2574 m_inst.opcode_type = eOpcode16;
2575 m_inst.opcode.inst16 = thumb_opcode;
2576 }
2577 else
2578 {
2579 m_inst.opcode_type = eOpcode32;
2580 m_inst.opcode.inst32 = (thumb_opcode << 16) | ReadMemoryUnsigned(read_inst_context, pc + 2, 2, 0, &success);
2581 }
2582 }
2583 }
2584 else
2585 {
2586 m_inst_mode = eModeARM;
2587 m_inst.opcode_type = eOpcode32;
2588 m_inst.opcode.inst32 = ReadMemoryUnsigned(read_inst_context, pc, 4, 0, &success);
2589 }
2590 }
2591 }
2592 if (!success)
2593 {
2594 m_inst_mode = eModeInvalid;
2595 m_inst_pc = LLDB_INVALID_ADDRESS;
2596 }
2597 return success;
2598}
2599
Johnny Chenee9b1f72011-02-09 01:00:31 +00002600uint32_t
2601EmulateInstructionARM::ArchVersion ()
2602{
2603 return m_arm_isa;
2604}
2605
Greg Clayton64c84432011-01-21 22:02:52 +00002606bool
2607EmulateInstructionARM::ConditionPassed ()
2608{
2609 if (m_inst_cpsr == 0)
2610 return false;
2611
2612 const uint32_t cond = CurrentCond ();
2613
2614 if (cond == UINT32_MAX)
2615 return false;
2616
2617 bool result = false;
2618 switch (UnsignedBits(cond, 3, 1))
2619 {
2620 case 0: result = (m_inst_cpsr & MASK_CPSR_Z) != 0; break;
2621 case 1: result = (m_inst_cpsr & MASK_CPSR_C) != 0; break;
2622 case 2: result = (m_inst_cpsr & MASK_CPSR_N) != 0; break;
2623 case 3: result = (m_inst_cpsr & MASK_CPSR_V) != 0; break;
2624 case 4: result = ((m_inst_cpsr & MASK_CPSR_C) != 0) && ((m_inst_cpsr & MASK_CPSR_Z) == 0); break;
2625 case 5:
2626 {
2627 bool n = (m_inst_cpsr & MASK_CPSR_N);
2628 bool v = (m_inst_cpsr & MASK_CPSR_V);
2629 result = n == v;
2630 }
2631 break;
2632 case 6:
2633 {
2634 bool n = (m_inst_cpsr & MASK_CPSR_N);
2635 bool v = (m_inst_cpsr & MASK_CPSR_V);
2636 result = n == v && ((m_inst_cpsr & MASK_CPSR_Z) == 0);
2637 }
2638 break;
2639 case 7:
2640 result = true;
2641 break;
2642 }
2643
2644 if (cond & 1)
2645 result = !result;
2646 return result;
2647}
2648
Johnny Chen9ee056b2011-02-08 00:06:35 +00002649uint32_t
2650EmulateInstructionARM::CurrentCond ()
2651{
2652 switch (m_inst_mode)
2653 {
2654 default:
2655 case eModeInvalid:
2656 break;
2657
2658 case eModeARM:
2659 return UnsignedBits(m_inst.opcode.inst32, 31, 28);
2660
2661 case eModeThumb:
2662 // For T1 and T3 encodings of the Branch instruction, it returns the 4-bit
2663 // 'cond' field of the encoding.
2664 if (m_inst.opcode_type == eOpcode16 &&
2665 Bits32(m_inst.opcode.inst16, 15, 12) == 0x0d &&
2666 Bits32(m_inst.opcode.inst16, 11, 7) != 0x0f)
2667 {
2668 return Bits32(m_inst.opcode.inst16, 11, 7);
2669 }
2670 else if (m_inst.opcode_type == eOpcode32 &&
2671 Bits32(m_inst.opcode.inst32, 31, 27) == 0x1e &&
2672 Bits32(m_inst.opcode.inst32, 15, 14) == 0x02 &&
2673 Bits32(m_inst.opcode.inst32, 12, 12) == 0x00 &&
2674 Bits32(m_inst.opcode.inst32, 25, 22) <= 0x0d)
2675 {
2676 return Bits32(m_inst.opcode.inst32, 25, 22);
2677 }
2678
2679 return m_it_session.GetCond();
2680 }
2681 return UINT32_MAX; // Return invalid value
2682}
2683
Johnny Chen9ee056b2011-02-08 00:06:35 +00002684bool
2685EmulateInstructionARM::BranchWritePC (const Context &context, uint32_t addr)
2686{
2687 addr_t target;
2688
Johnny Chenee9b1f72011-02-09 01:00:31 +00002689 // Check the current instruction set.
2690 if (CurrentInstrSet() == eModeARM)
Johnny Chen9ee056b2011-02-08 00:06:35 +00002691 target = addr & 0xfffffffc;
Johnny Chenee9b1f72011-02-09 01:00:31 +00002692 else
Johnny Chen9ee056b2011-02-08 00:06:35 +00002693 target = addr & 0xfffffffe;
Johnny Chenee9b1f72011-02-09 01:00:31 +00002694
Johnny Chen9ee056b2011-02-08 00:06:35 +00002695 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, target))
Johnny Chen53ebab72011-02-08 23:21:57 +00002696 return false;
2697
2698 return true;
Johnny Chen9ee056b2011-02-08 00:06:35 +00002699}
2700
2701// As a side effect, BXWritePC sets context.arg2 to eModeARM or eModeThumb by inspecting addr.
2702bool
2703EmulateInstructionARM::BXWritePC (Context &context, uint32_t addr)
2704{
2705 addr_t target;
Johnny Chen0f309db2011-02-09 19:11:32 +00002706 // If the CPSR is changed due to switching between ARM and Thumb ISETSTATE,
2707 // we want to record it and issue a WriteRegister callback so the clients
2708 // can track the mode changes accordingly.
2709 bool cpsr_changed = false;
Johnny Chen9ee056b2011-02-08 00:06:35 +00002710
2711 if (BitIsSet(addr, 0))
2712 {
Johnny Chen0f309db2011-02-09 19:11:32 +00002713 if (CurrentInstrSet() != eModeThumb)
2714 {
2715 SelectInstrSet(eModeThumb);
2716 cpsr_changed = true;
2717 }
Johnny Chen9ee056b2011-02-08 00:06:35 +00002718 target = addr & 0xfffffffe;
2719 context.arg2 = eModeThumb;
2720 }
2721 else if (BitIsClear(addr, 1))
2722 {
Johnny Chen0f309db2011-02-09 19:11:32 +00002723 if (CurrentInstrSet() != eModeARM)
2724 {
2725 SelectInstrSet(eModeARM);
2726 cpsr_changed = true;
2727 }
Johnny Chen9ee056b2011-02-08 00:06:35 +00002728 target = addr & 0xfffffffc;
2729 context.arg2 = eModeARM;
2730 }
2731 else
2732 return false; // address<1:0> == '10' => UNPREDICTABLE
2733
Johnny Chen0f309db2011-02-09 19:11:32 +00002734 if (cpsr_changed)
2735 {
Johnny Chen558133b2011-02-09 23:59:17 +00002736 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
Johnny Chen0f309db2011-02-09 19:11:32 +00002737 return false;
2738 }
Johnny Chen9ee056b2011-02-08 00:06:35 +00002739 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, target))
Johnny Chen53ebab72011-02-08 23:21:57 +00002740 return false;
2741
2742 return true;
Johnny Chen9ee056b2011-02-08 00:06:35 +00002743}
Greg Clayton64c84432011-01-21 22:02:52 +00002744
Johnny Chenee9b1f72011-02-09 01:00:31 +00002745// Dispatches to either BXWritePC or BranchWritePC based on architecture versions.
2746bool
2747EmulateInstructionARM::LoadWritePC (Context &context, uint32_t addr)
2748{
2749 if (ArchVersion() >= ARMv5T)
2750 return BXWritePC(context, addr);
2751 else
2752 return BranchWritePC((const Context)context, addr);
2753}
2754
Johnny Chen26863dc2011-02-09 23:43:29 +00002755// Dispatches to either BXWritePC or BranchWritePC based on architecture versions and current instruction set.
2756bool
2757EmulateInstructionARM::ALUWritePC (Context &context, uint32_t addr)
2758{
2759 if (ArchVersion() >= ARMv7 && CurrentInstrSet() == eModeARM)
2760 return BXWritePC(context, addr);
2761 else
2762 return BranchWritePC((const Context)context, addr);
2763}
2764
Johnny Chenee9b1f72011-02-09 01:00:31 +00002765EmulateInstructionARM::Mode
2766EmulateInstructionARM::CurrentInstrSet ()
2767{
2768 return m_inst_mode;
2769}
2770
2771// Set the 'T' bit of our CPSR. The m_inst_mode gets updated when the next
Johnny Chen558133b2011-02-09 23:59:17 +00002772// ReadInstruction() is performed. This function has a side effect of updating
2773// the m_new_inst_cpsr member variable if necessary.
Johnny Chenee9b1f72011-02-09 01:00:31 +00002774bool
2775EmulateInstructionARM::SelectInstrSet (Mode arm_or_thumb)
2776{
Johnny Chen558133b2011-02-09 23:59:17 +00002777 m_new_inst_cpsr = m_inst_cpsr;
Johnny Chenee9b1f72011-02-09 01:00:31 +00002778 switch (arm_or_thumb)
2779 {
2780 default:
2781 return false;
2782 eModeARM:
2783 // Clear the T bit.
Johnny Chen558133b2011-02-09 23:59:17 +00002784 m_new_inst_cpsr &= ~MASK_CPSR_T;
Johnny Chenee9b1f72011-02-09 01:00:31 +00002785 break;
2786 eModeThumb:
2787 // Set the T bit.
Johnny Chen558133b2011-02-09 23:59:17 +00002788 m_new_inst_cpsr |= MASK_CPSR_T;
Johnny Chenee9b1f72011-02-09 01:00:31 +00002789 break;
2790 }
2791 return true;
2792}
2793
Johnny Chenef21b592011-02-10 01:52:38 +00002794// This function returns TRUE if the processor currently provides support for
2795// unaligned memory accesses, or FALSE otherwise. This is always TRUE in ARMv7,
2796// controllable by the SCTLR.U bit in ARMv6, and always FALSE before ARMv6.
2797bool
2798EmulateInstructionARM::UnalignedSupport()
2799{
2800 return (ArchVersion() >= ARMv7);
2801}
2802
Johnny Chenbf6ad172011-02-11 01:29:53 +00002803// The main addition and subtraction instructions can produce status information
2804// about both unsigned carry and signed overflow conditions. This status
2805// information can be used to synthesize multi-word additions and subtractions.
2806EmulateInstructionARM::AddWithCarryResult
2807EmulateInstructionARM::AddWithCarry (uint32_t x, uint32_t y, uint8_t carry_in)
2808{
2809 uint32_t result;
2810 uint8_t carry_out;
2811 uint8_t overflow;
2812
2813 uint64_t unsigned_sum = x + y + carry_in;
2814 int64_t signed_sum = (int32_t)x + (int32_t)y + (int32_t)carry_in;
2815
2816 result = UnsignedBits(unsigned_sum, 31, 0);
2817 carry_out = (result == unsigned_sum ? 0 : 1);
2818 overflow = ((int32_t)result == signed_sum ? 0 : 1);
2819
2820 AddWithCarryResult res = { result, carry_out, overflow };
2821 return res;
2822}
2823
Greg Clayton64c84432011-01-21 22:02:52 +00002824bool
2825EmulateInstructionARM::EvaluateInstruction ()
2826{
Johnny Chenc315f862011-02-05 00:46:10 +00002827 // Advance the ITSTATE bits to their values for the next instruction.
2828 if (m_inst_mode == eModeThumb && m_it_session.InITBlock())
2829 m_it_session.ITAdvance();
2830
Greg Clayton64c84432011-01-21 22:02:52 +00002831 return false;
2832}