blob: bf984415f5fb495a5810db9626a33ddd5024e2bf [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 Chen93070472011-02-04 23:02:47 +000028// A8.6.50
29// Valid return values are {1, 2, 3, 4}, with 0 signifying an error condition.
30static unsigned short CountITSize(unsigned ITMask) {
31 // First count the trailing zeros of the IT mask.
32 unsigned TZ = llvm::CountTrailingZeros_32(ITMask);
33 if (TZ > 3)
34 {
35 printf("Encoding error: IT Mask '0000'\n");
36 return 0;
37 }
38 return (4 - TZ);
39}
40
41// Init ITState. Note that at least one bit is always 1 in mask.
42bool ITSession::InitIT(unsigned short bits7_0)
43{
44 ITCounter = CountITSize(Bits32(bits7_0, 3, 0));
45 if (ITCounter == 0)
46 return false;
47
48 // A8.6.50 IT
49 unsigned short FirstCond = Bits32(bits7_0, 7, 4);
50 if (FirstCond == 0xF)
51 {
52 printf("Encoding error: IT FirstCond '1111'\n");
53 return false;
54 }
55 if (FirstCond == 0xE && ITCounter != 1)
56 {
57 printf("Encoding error: IT FirstCond '1110' && Mask != '1000'\n");
58 return false;
59 }
60
61 ITState = bits7_0;
62 return true;
63}
64
65// Update ITState if necessary.
66void ITSession::ITAdvance()
67{
68 assert(ITCounter);
69 --ITCounter;
70 if (ITCounter == 0)
71 ITState = 0;
72 else
73 {
74 unsigned short NewITState4_0 = Bits32(ITState, 4, 0) << 1;
75 SetBits32(ITState, 4, 0, NewITState4_0);
76 }
77}
78
79// Return true if we're inside an IT Block.
80bool ITSession::InITBlock()
81{
82 return ITCounter != 0;
83}
84
Johnny Chenc315f862011-02-05 00:46:10 +000085// Return true if we're the last instruction inside an IT Block.
86bool ITSession::LastInITBlock()
87{
88 return ITCounter == 1;
89}
90
Johnny Chen93070472011-02-04 23:02:47 +000091// Get condition bits for the current thumb instruction.
92uint32_t ITSession::GetCond()
93{
Johnny Chenc315f862011-02-05 00:46:10 +000094 if (InITBlock())
95 return Bits32(ITState, 7, 4);
96 else
97 return COND_AL;
Johnny Chen93070472011-02-04 23:02:47 +000098}
99
Greg Clayton64c84432011-01-21 22:02:52 +0000100// ARM constants used during decoding
101#define REG_RD 0
102#define LDM_REGLIST 1
103#define PC_REG 15
104#define PC_REGLIST_BIT 0x8000
105
Johnny Chen251af6a2011-01-21 22:47:25 +0000106#define ARMv4 (1u << 0)
Greg Clayton64c84432011-01-21 22:02:52 +0000107#define ARMv4T (1u << 1)
108#define ARMv5T (1u << 2)
109#define ARMv5TE (1u << 3)
110#define ARMv5TEJ (1u << 4)
Johnny Chen251af6a2011-01-21 22:47:25 +0000111#define ARMv6 (1u << 5)
Greg Clayton64c84432011-01-21 22:02:52 +0000112#define ARMv6K (1u << 6)
113#define ARMv6T2 (1u << 7)
Johnny Chen251af6a2011-01-21 22:47:25 +0000114#define ARMv7 (1u << 8)
Johnny Chen60c0d622011-01-25 23:49:39 +0000115#define ARMv8 (1u << 9)
Greg Clayton64c84432011-01-21 22:02:52 +0000116#define ARMvAll (0xffffffffu)
117
Johnny Chen9b8d7832011-02-02 01:13:56 +0000118#define ARMV4T_ABOVE (ARMv4T|ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv8)
119#define ARMV5_ABOVE (ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv8)
120#define ARMV6T2_ABOVE (ARMv6T2|ARMv7|ARMv8)
Greg Clayton64c84432011-01-21 22:02:52 +0000121
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000122void
123EmulateInstructionARM::Initialize ()
Johnny Chen7dc60e12011-01-24 19:46:32 +0000124{
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000125}
Johnny Chen7dc60e12011-01-24 19:46:32 +0000126
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000127void
128EmulateInstructionARM::Terminate ()
Greg Clayton64c84432011-01-21 22:02:52 +0000129{
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000130}
131
Johnny Chen08c25e82011-01-31 18:02:28 +0000132// Push Multiple Registers stores multiple registers to the stack, storing to
133// consecutive memory locations ending just below the address in SP, and updates
134// SP to point to the start of the stored data.
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000135bool
136EmulateInstructionARM::EmulatePush (ARMEncoding encoding)
Greg Clayton64c84432011-01-21 22:02:52 +0000137{
138#if 0
139 // ARM pseudo code...
140 if (ConditionPassed())
141 {
142 EncodingSpecificOperations();
143 NullCheckIfThumbEE(13);
144 address = SP - 4*BitCount(registers);
145
146 for (i = 0 to 14)
147 {
148 if (registers<i> == ’1’)
149 {
150 if i == 13 && i != LowestSetBit(registers) // Only possible for encoding A1
151 MemA[address,4] = bits(32) UNKNOWN;
152 else
153 MemA[address,4] = R[i];
154 address = address + 4;
155 }
156 }
157
158 if (registers<15> == ’1’) // Only possible for encoding A1 or A2
159 MemA[address,4] = PCStoreValue();
160
161 SP = SP - 4*BitCount(registers);
162 }
163#endif
164
165 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000166 const uint32_t opcode = OpcodeAsUnsigned (&success);
Greg Clayton64c84432011-01-21 22:02:52 +0000167 if (!success)
168 return false;
169
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000170 if (ConditionPassed())
Greg Clayton64c84432011-01-21 22:02:52 +0000171 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000172 const uint32_t addr_byte_size = GetAddressByteSize();
173 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Greg Clayton64c84432011-01-21 22:02:52 +0000174 if (!success)
175 return false;
Johnny Chen3c75c762011-01-22 00:47:08 +0000176 uint32_t registers = 0;
Johnny Chen91d99862011-01-25 19:07:04 +0000177 uint32_t Rt; // the source register
Johnny Chen3c75c762011-01-22 00:47:08 +0000178 switch (encoding) {
Johnny Chenaedde1c2011-01-24 20:38:45 +0000179 case eEncodingT1:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000180 registers = Bits32(opcode, 7, 0);
Johnny Chenaedde1c2011-01-24 20:38:45 +0000181 // The M bit represents LR.
Johnny Chen108d5aa2011-01-26 01:00:55 +0000182 if (Bits32(opcode, 8, 8))
Johnny Chenef85e912011-01-31 23:07:40 +0000183 registers |= (1u << 14);
Johnny Chenaedde1c2011-01-24 20:38:45 +0000184 // if BitCount(registers) < 1 then UNPREDICTABLE;
185 if (BitCount(registers) < 1)
186 return false;
187 break;
Johnny Chen7dc60e12011-01-24 19:46:32 +0000188 case eEncodingT2:
189 // Ignore bits 15 & 13.
Johnny Chen108d5aa2011-01-26 01:00:55 +0000190 registers = Bits32(opcode, 15, 0) & ~0xa000;
Johnny Chen7dc60e12011-01-24 19:46:32 +0000191 // if BitCount(registers) < 2 then UNPREDICTABLE;
192 if (BitCount(registers) < 2)
193 return false;
194 break;
195 case eEncodingT3:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000196 Rt = Bits32(opcode, 15, 12);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000197 // if BadReg(t) then UNPREDICTABLE;
Johnny Chen91d99862011-01-25 19:07:04 +0000198 if (BadReg(Rt))
Johnny Chen7dc60e12011-01-24 19:46:32 +0000199 return false;
Johnny Chen91d99862011-01-25 19:07:04 +0000200 registers = (1u << Rt);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000201 break;
Johnny Chen3c75c762011-01-22 00:47:08 +0000202 case eEncodingA1:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000203 registers = Bits32(opcode, 15, 0);
Johnny Chena33d4842011-01-24 22:25:48 +0000204 // Instead of return false, let's handle the following case as well,
205 // which amounts to pushing one reg onto the full descending stacks.
206 // if BitCount(register_list) < 2 then SEE STMDB / STMFD;
Johnny Chen3c75c762011-01-22 00:47:08 +0000207 break;
208 case eEncodingA2:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000209 Rt = Bits32(opcode, 15, 12);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000210 // if t == 13 then UNPREDICTABLE;
Johnny Chen91d99862011-01-25 19:07:04 +0000211 if (Rt == dwarf_sp)
Johnny Chen3c75c762011-01-22 00:47:08 +0000212 return false;
Johnny Chen91d99862011-01-25 19:07:04 +0000213 registers = (1u << Rt);
Johnny Chen3c75c762011-01-22 00:47:08 +0000214 break;
Johnny Chence1ca772011-01-25 01:13:00 +0000215 default:
216 return false;
Johnny Chen3c75c762011-01-22 00:47:08 +0000217 }
Johnny Chence1ca772011-01-25 01:13:00 +0000218 addr_t sp_offset = addr_byte_size * BitCount (registers);
Greg Clayton64c84432011-01-21 22:02:52 +0000219 addr_t addr = sp - sp_offset;
220 uint32_t i;
221
222 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
223 for (i=0; i<15; ++i)
224 {
Johnny Chen7c1bf922011-02-08 23:49:37 +0000225 if (BitIsSet (registers, i))
Greg Clayton64c84432011-01-21 22:02:52 +0000226 {
227 context.arg1 = dwarf_r0 + i; // arg1 in the context is the DWARF register number
228 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000229 uint32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
Greg Clayton64c84432011-01-21 22:02:52 +0000230 if (!success)
231 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000232 if (!WriteMemoryUnsigned (context, addr, reg_value, addr_byte_size))
Greg Clayton64c84432011-01-21 22:02:52 +0000233 return false;
234 addr += addr_byte_size;
235 }
236 }
237
Johnny Chen7c1bf922011-02-08 23:49:37 +0000238 if (BitIsSet (registers, 15))
Greg Clayton64c84432011-01-21 22:02:52 +0000239 {
240 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
Johnny Chen3c75c762011-01-22 00:47:08 +0000241 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000242 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Greg Clayton64c84432011-01-21 22:02:52 +0000243 if (!success)
244 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000245 if (!WriteMemoryUnsigned (context, addr, pc + 8, addr_byte_size))
Greg Clayton64c84432011-01-21 22:02:52 +0000246 return false;
247 }
248
249 context.type = EmulateInstruction::eContextAdjustStackPointer;
250 context.arg0 = eRegisterKindGeneric;
251 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +0000252 context.arg2 = -sp_offset;
Greg Clayton64c84432011-01-21 22:02:52 +0000253
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000254 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
Greg Clayton64c84432011-01-21 22:02:52 +0000255 return false;
256 }
257 return true;
258}
259
Johnny Chenef85e912011-01-31 23:07:40 +0000260// Pop Multiple Registers loads multiple registers from the stack, loading from
261// consecutive memory locations staring at the address in SP, and updates
262// SP to point just above the loaded data.
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000263bool
264EmulateInstructionARM::EmulatePop (ARMEncoding encoding)
Johnny Chenef85e912011-01-31 23:07:40 +0000265{
266#if 0
267 // ARM pseudo code...
268 if (ConditionPassed())
269 {
270 EncodingSpecificOperations(); NullCheckIfThumbEE(13);
271 address = SP;
272 for i = 0 to 14
273 if registers<i> == ‘1’ then
274 R[i} = if UnalignedAllowed then MemU[address,4] else MemA[address,4]; address = address + 4;
275 if registers<15> == ‘1’ then
276 if UnalignedAllowed then
277 LoadWritePC(MemU[address,4]);
278 else
279 LoadWritePC(MemA[address,4]);
280 if registers<13> == ‘0’ then SP = SP + 4*BitCount(registers);
281 if registers<13> == ‘1’ then SP = bits(32) UNKNOWN;
282 }
283#endif
284
285 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000286 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chenef85e912011-01-31 23:07:40 +0000287 if (!success)
288 return false;
289
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000290 if (ConditionPassed())
Johnny Chenef85e912011-01-31 23:07:40 +0000291 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000292 const uint32_t addr_byte_size = GetAddressByteSize();
293 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chenef85e912011-01-31 23:07:40 +0000294 if (!success)
295 return false;
296 uint32_t registers = 0;
297 uint32_t Rt; // the destination register
298 switch (encoding) {
299 case eEncodingT1:
300 registers = Bits32(opcode, 7, 0);
301 // The P bit represents PC.
302 if (Bits32(opcode, 8, 8))
303 registers |= (1u << 15);
304 // if BitCount(registers) < 1 then UNPREDICTABLE;
305 if (BitCount(registers) < 1)
306 return false;
307 break;
308 case eEncodingT2:
309 // Ignore bit 13.
310 registers = Bits32(opcode, 15, 0) & ~0x2000;
311 // if BitCount(registers) < 2 || (P == '1' && M == '1') then UNPREDICTABLE;
312 if (BitCount(registers) < 2 || (Bits32(opcode, 15, 15) && Bits32(opcode, 14, 14)))
313 return false;
314 break;
315 case eEncodingT3:
316 Rt = Bits32(opcode, 15, 12);
317 // if t == 13 || (t == 15 && InITBlock() && !LastInITBlock()) then UNPREDICTABLE;
318 if (Rt == dwarf_sp)
319 return false;
320 registers = (1u << Rt);
321 break;
322 case eEncodingA1:
323 registers = Bits32(opcode, 15, 0);
324 // Instead of return false, let's handle the following case as well,
325 // which amounts to popping one reg from the full descending stacks.
326 // if BitCount(register_list) < 2 then SEE LDM / LDMIA / LDMFD;
327
328 // if registers<13> == ‘1’ && ArchVersion() >= 7 then UNPREDICTABLE;
329 if (Bits32(opcode, 13, 13))
330 return false;
331 break;
332 case eEncodingA2:
333 Rt = Bits32(opcode, 15, 12);
334 // if t == 13 then UNPREDICTABLE;
335 if (Rt == dwarf_sp)
336 return false;
337 registers = (1u << Rt);
338 break;
339 default:
340 return false;
341 }
342 addr_t sp_offset = addr_byte_size * BitCount (registers);
343 addr_t addr = sp;
344 uint32_t i, data;
345
346 EmulateInstruction::Context context = { EmulateInstruction::eContextPopRegisterOffStack, eRegisterKindDWARF, 0, 0 };
347 for (i=0; i<15; ++i)
348 {
Johnny Chen7c1bf922011-02-08 23:49:37 +0000349 if (BitIsSet (registers, i))
Johnny Chenef85e912011-01-31 23:07:40 +0000350 {
351 context.arg1 = dwarf_r0 + i; // arg1 in the context is the DWARF register number
352 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000353 data = ReadMemoryUnsigned(context, addr, 4, 0, &success);
Johnny Chenef85e912011-01-31 23:07:40 +0000354 if (!success)
355 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000356 if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, context.arg1, data))
Johnny Chenef85e912011-01-31 23:07:40 +0000357 return false;
358 addr += addr_byte_size;
359 }
360 }
361
Johnny Chen7c1bf922011-02-08 23:49:37 +0000362 if (BitIsSet (registers, 15))
Johnny Chenef85e912011-01-31 23:07:40 +0000363 {
364 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
365 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000366 data = ReadMemoryUnsigned(context, addr, 4, 0, &success);
Johnny Chenef85e912011-01-31 23:07:40 +0000367 if (!success)
368 return false;
Johnny Chenf3eaacf2011-02-09 19:30:49 +0000369 // In ARMv5T and above, this is an interworking branch.
370 if (!LoadWritePC(context, data))
Johnny Chenef85e912011-01-31 23:07:40 +0000371 return false;
372 addr += addr_byte_size;
373 }
374
375 context.type = EmulateInstruction::eContextAdjustStackPointer;
376 context.arg0 = eRegisterKindGeneric;
377 context.arg1 = LLDB_REGNUM_GENERIC_SP;
378 context.arg2 = sp_offset;
379
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000380 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp + sp_offset))
Johnny Chenef85e912011-01-31 23:07:40 +0000381 return false;
382 }
383 return true;
384}
385
Johnny Chen5b442b72011-01-27 19:34:30 +0000386// Set r7 or ip to point to saved value residing within the stack.
Johnny Chenbcec3af2011-01-27 01:26:19 +0000387// ADD (SP plus immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000388bool
389EmulateInstructionARM::EmulateAddRdSPImmediate (ARMEncoding encoding)
Johnny Chenbcec3af2011-01-27 01:26:19 +0000390{
391#if 0
392 // ARM pseudo code...
393 if (ConditionPassed())
394 {
395 EncodingSpecificOperations();
396 (result, carry, overflow) = AddWithCarry(SP, imm32, ‘0’);
397 if d == 15 then
398 ALUWritePC(result); // setflags is always FALSE here
399 else
400 R[d] = result;
401 if setflags then
402 APSR.N = result<31>;
403 APSR.Z = IsZeroBit(result);
404 APSR.C = carry;
405 APSR.V = overflow;
406 }
407#endif
408
409 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000410 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chenbcec3af2011-01-27 01:26:19 +0000411 if (!success)
412 return false;
413
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000414 if (ConditionPassed())
Johnny Chenbcec3af2011-01-27 01:26:19 +0000415 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000416 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chenbcec3af2011-01-27 01:26:19 +0000417 if (!success)
418 return false;
419 uint32_t Rd; // the destination register
420 uint32_t imm32;
421 switch (encoding) {
422 case eEncodingT1:
423 Rd = 7;
424 imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32)
425 break;
426 case eEncodingA1:
427 Rd = Bits32(opcode, 15, 12);
428 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
429 break;
430 default:
431 return false;
432 }
433 addr_t sp_offset = imm32;
434 addr_t addr = sp + sp_offset; // a pointer to the stack area
435
436 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
437 eRegisterKindGeneric,
438 LLDB_REGNUM_GENERIC_SP,
439 sp_offset };
440
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000441 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, addr))
Johnny Chenbcec3af2011-01-27 01:26:19 +0000442 return false;
443 }
444 return true;
445}
446
Johnny Chen2ccad832011-01-28 19:57:25 +0000447// Set r7 or ip to the current stack pointer.
448// MOV (register)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000449bool
450EmulateInstructionARM::EmulateMovRdSP (ARMEncoding encoding)
Johnny Chen2ccad832011-01-28 19:57:25 +0000451{
452#if 0
453 // ARM pseudo code...
454 if (ConditionPassed())
455 {
456 EncodingSpecificOperations();
457 result = R[m];
458 if d == 15 then
459 ALUWritePC(result); // setflags is always FALSE here
460 else
461 R[d] = result;
462 if setflags then
463 APSR.N = result<31>;
464 APSR.Z = IsZeroBit(result);
465 // APSR.C unchanged
466 // APSR.V unchanged
467 }
468#endif
469
470 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000471 //const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen1c13b622011-01-29 00:11:15 +0000472 //if (!success)
473 // return false;
Johnny Chen2ccad832011-01-28 19:57:25 +0000474
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000475 if (ConditionPassed())
Johnny Chen2ccad832011-01-28 19:57:25 +0000476 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000477 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen2ccad832011-01-28 19:57:25 +0000478 if (!success)
479 return false;
480 uint32_t Rd; // the destination register
481 switch (encoding) {
482 case eEncodingT1:
483 Rd = 7;
484 break;
485 case eEncodingA1:
486 Rd = 12;
487 break;
488 default:
489 return false;
490 }
491 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
492 eRegisterKindGeneric,
493 LLDB_REGNUM_GENERIC_SP,
494 0 };
495
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000496 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, sp))
Johnny Chen2ccad832011-01-28 19:57:25 +0000497 return false;
498 }
499 return true;
500}
501
Johnny Chen1c13b622011-01-29 00:11:15 +0000502// Move from high register (r8-r15) to low register (r0-r7).
503// MOV (register)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000504bool
505EmulateInstructionARM::EmulateMovLowHigh (ARMEncoding encoding)
Johnny Chen1c13b622011-01-29 00:11:15 +0000506{
Johnny Chen338bf542011-02-10 19:29:03 +0000507 return EmulateMovRdRm (encoding);
508}
509
510// Move from register to register.
511// MOV (register)
512bool
513EmulateInstructionARM::EmulateMovRdRm (ARMEncoding encoding)
514{
Johnny Chen1c13b622011-01-29 00:11:15 +0000515#if 0
516 // ARM pseudo code...
517 if (ConditionPassed())
518 {
519 EncodingSpecificOperations();
520 result = R[m];
521 if d == 15 then
522 ALUWritePC(result); // setflags is always FALSE here
523 else
524 R[d] = result;
525 if setflags then
526 APSR.N = result<31>;
527 APSR.Z = IsZeroBit(result);
528 // APSR.C unchanged
529 // APSR.V unchanged
530 }
531#endif
532
533 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000534 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen1c13b622011-01-29 00:11:15 +0000535 if (!success)
536 return false;
537
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000538 if (ConditionPassed())
Johnny Chen1c13b622011-01-29 00:11:15 +0000539 {
540 uint32_t Rm; // the source register
541 uint32_t Rd; // the destination register
Johnny Chen338bf542011-02-10 19:29:03 +0000542 bool setflags;
Johnny Chen1c13b622011-01-29 00:11:15 +0000543 switch (encoding) {
544 case eEncodingT1:
545 Rm = Bits32(opcode, 6, 3);
Johnny Chen338bf542011-02-10 19:29:03 +0000546 Rd = Bits32(opcode, 7, 7) << 3 | Bits32(opcode, 2, 1);
547 setflags = false;
548 break;
549 case eEncodingT2:
550 Rm = Bits32(opcode, 5, 3);
551 Rd = Bits32(opcode, 2, 1);
552 setflags = true;
Johnny Chen1c13b622011-01-29 00:11:15 +0000553 break;
554 default:
555 return false;
556 }
Johnny Chen338bf542011-02-10 19:29:03 +0000557 uint32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
Johnny Chen1c13b622011-01-29 00:11:15 +0000558 if (!success)
559 return false;
560
561 // The context specifies that Rm is to be moved into Rd.
562 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
563 eRegisterKindDWARF,
564 dwarf_r0 + Rm,
565 0 };
566
Johnny Chen338bf542011-02-10 19:29:03 +0000567 if (Rd == 15)
568 {
569 if (!ALUWritePC (context, reg_value))
570 return false;
571 }
572 else
573 {
574 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, reg_value))
575 return false;
576 if (setflags)
577 {
578 m_new_inst_cpsr = m_inst_cpsr;
579 SetBits32(m_new_inst_cpsr, CPSR_N, Bits32(reg_value, CPSR_N));
580 SetBits32(m_new_inst_cpsr, CPSR_Z, reg_value == 0 ? 1 : 0);
581 if (m_new_inst_cpsr != m_inst_cpsr)
582 {
583 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
584 return false;
585 }
586 }
587 }
Johnny Chen1c13b622011-01-29 00:11:15 +0000588 }
589 return true;
590}
591
Johnny Chen788e0552011-01-27 22:52:23 +0000592// PC relative immediate load into register, possibly followed by ADD (SP plus register).
593// LDR (literal)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000594bool
595EmulateInstructionARM::EmulateLDRRdPCRelative (ARMEncoding encoding)
Johnny Chen788e0552011-01-27 22:52:23 +0000596{
597#if 0
598 // ARM pseudo code...
599 if (ConditionPassed())
600 {
601 EncodingSpecificOperations(); NullCheckIfThumbEE(15);
602 base = Align(PC,4);
603 address = if add then (base + imm32) else (base - imm32);
604 data = MemU[address,4];
605 if t == 15 then
606 if address<1:0> == ‘00’ then LoadWritePC(data); else UNPREDICTABLE;
607 elsif UnalignedSupport() || address<1:0> = ‘00’ then
608 R[t] = data;
609 else // Can only apply before ARMv7
610 if CurrentInstrSet() == InstrSet_ARM then
611 R[t] = ROR(data, 8*UInt(address<1:0>));
612 else
613 R[t] = bits(32) UNKNOWN;
614 }
615#endif
616
617 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000618 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen788e0552011-01-27 22:52:23 +0000619 if (!success)
620 return false;
621
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000622 if (ConditionPassed())
Johnny Chen788e0552011-01-27 22:52:23 +0000623 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000624 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Johnny Chen788e0552011-01-27 22:52:23 +0000625 if (!success)
626 return false;
Johnny Chen809742e2011-01-28 00:32:27 +0000627
628 // PC relative immediate load context
629 EmulateInstruction::Context context = {EmulateInstruction::eContextRegisterPlusOffset,
630 eRegisterKindGeneric,
631 LLDB_REGNUM_GENERIC_PC,
632 0};
Johnny Chen788e0552011-01-27 22:52:23 +0000633 uint32_t Rd; // the destination register
634 uint32_t imm32; // immediate offset from the PC
635 addr_t addr; // the PC relative address
636 uint32_t data; // the literal data value from the PC relative load
637 switch (encoding) {
638 case eEncodingT1:
639 Rd = Bits32(opcode, 10, 8);
640 imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32);
641 addr = pc + 4 + imm32;
Johnny Chen809742e2011-01-28 00:32:27 +0000642 context.arg2 = 4 + imm32;
Johnny Chen788e0552011-01-27 22:52:23 +0000643 break;
644 default:
645 return false;
646 }
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000647 data = ReadMemoryUnsigned(context, addr, 4, 0, &success);
Johnny Chen788e0552011-01-27 22:52:23 +0000648 if (!success)
Johnny Chen809742e2011-01-28 00:32:27 +0000649 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000650 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, data))
Johnny Chen788e0552011-01-27 22:52:23 +0000651 return false;
652 }
653 return true;
654}
655
Johnny Chen5b442b72011-01-27 19:34:30 +0000656// An add operation to adjust the SP.
Johnny Chenfdd179e2011-01-31 20:09:28 +0000657// ADD (SP plus immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000658bool
659EmulateInstructionARM::EmulateAddSPImmediate (ARMEncoding encoding)
Johnny Chenfdd179e2011-01-31 20:09:28 +0000660{
661#if 0
662 // ARM pseudo code...
663 if (ConditionPassed())
664 {
665 EncodingSpecificOperations();
666 (result, carry, overflow) = AddWithCarry(SP, imm32, ‘0’);
667 if d == 15 then // Can only occur for ARM encoding
668 ALUWritePC(result); // setflags is always FALSE here
669 else
670 R[d] = result;
671 if setflags then
672 APSR.N = result<31>;
673 APSR.Z = IsZeroBit(result);
674 APSR.C = carry;
675 APSR.V = overflow;
676 }
677#endif
678
679 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000680 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chenfdd179e2011-01-31 20:09:28 +0000681 if (!success)
682 return false;
683
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000684 if (ConditionPassed())
Johnny Chenfdd179e2011-01-31 20:09:28 +0000685 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000686 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chenfdd179e2011-01-31 20:09:28 +0000687 if (!success)
688 return false;
689 uint32_t imm32; // the immediate operand
690 switch (encoding) {
691 case eEncodingT2:
692 imm32 = ThumbImmScaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
693 break;
694 default:
695 return false;
696 }
697 addr_t sp_offset = imm32;
698 addr_t addr = sp + sp_offset; // the adjusted stack pointer value
699
700 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
701 eRegisterKindGeneric,
702 LLDB_REGNUM_GENERIC_SP,
703 sp_offset };
704
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000705 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
Johnny Chenfdd179e2011-01-31 20:09:28 +0000706 return false;
707 }
708 return true;
709}
710
711// An add operation to adjust the SP.
Johnny Chen5b442b72011-01-27 19:34:30 +0000712// ADD (SP plus register)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000713bool
714EmulateInstructionARM::EmulateAddSPRm (ARMEncoding encoding)
Johnny Chen5b442b72011-01-27 19:34:30 +0000715{
716#if 0
717 // ARM pseudo code...
718 if (ConditionPassed())
719 {
720 EncodingSpecificOperations();
721 shifted = Shift(R[m], shift_t, shift_n, APSR.C);
722 (result, carry, overflow) = AddWithCarry(SP, shifted, ‘0’);
723 if d == 15 then
724 ALUWritePC(result); // setflags is always FALSE here
725 else
726 R[d] = result;
727 if setflags then
728 APSR.N = result<31>;
729 APSR.Z = IsZeroBit(result);
730 APSR.C = carry;
731 APSR.V = overflow;
732 }
733#endif
734
735 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000736 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen5b442b72011-01-27 19:34:30 +0000737 if (!success)
738 return false;
739
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000740 if (ConditionPassed())
Johnny Chen5b442b72011-01-27 19:34:30 +0000741 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000742 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen5b442b72011-01-27 19:34:30 +0000743 if (!success)
744 return false;
745 uint32_t Rm; // the second operand
746 switch (encoding) {
747 case eEncodingT2:
748 Rm = Bits32(opcode, 6, 3);
749 break;
750 default:
751 return false;
752 }
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000753 int32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
Johnny Chen5b442b72011-01-27 19:34:30 +0000754 if (!success)
755 return false;
756
757 addr_t addr = (int32_t)sp + reg_value; // the adjusted stack pointer value
758
759 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
760 eRegisterKindGeneric,
761 LLDB_REGNUM_GENERIC_SP,
762 reg_value };
763
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000764 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
Johnny Chen5b442b72011-01-27 19:34:30 +0000765 return false;
766 }
767 return true;
768}
769
Johnny Chen9b8d7832011-02-02 01:13:56 +0000770// Branch with Link and Exchange Instruction Sets (immediate) calls a subroutine
771// at a PC-relative address, and changes instruction set from ARM to Thumb, or
772// from Thumb to ARM.
773// BLX (immediate)
774bool
775EmulateInstructionARM::EmulateBLXImmediate (ARMEncoding encoding)
776{
777#if 0
778 // ARM pseudo code...
779 if (ConditionPassed())
780 {
781 EncodingSpecificOperations();
782 if CurrentInstrSet() == InstrSet_ARM then
783 LR = PC - 4;
784 else
785 LR = PC<31:1> : '1';
786 if targetInstrSet == InstrSet_ARM then
787 targetAddress = Align(PC,4) + imm32;
788 else
789 targetAddress = PC + imm32;
790 SelectInstrSet(targetInstrSet);
791 BranchWritePC(targetAddress);
792 }
793#endif
794
795 bool success = false;
796 const uint32_t opcode = OpcodeAsUnsigned (&success);
797 if (!success)
798 return false;
799
800 if (ConditionPassed())
801 {
802 EmulateInstruction::Context context = { EmulateInstruction::eContextRelativeBranchImmediate, 0, 0, 0};
803 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Johnny Chen9b8d7832011-02-02 01:13:56 +0000804 if (!success)
805 return false;
Johnny Chen53ebab72011-02-08 23:21:57 +0000806 addr_t lr; // next instruction address
807 addr_t target; // target address
Johnny Chen9b8d7832011-02-02 01:13:56 +0000808 int32_t imm32; // PC-relative offset
809 switch (encoding) {
Johnny Chend6c13f02011-02-08 20:36:34 +0000810 case eEncodingT1:
811 {
812 lr = (pc + 4) | 1u; // return address
813 uint32_t S = Bits32(opcode, 26, 26);
814 uint32_t imm10 = Bits32(opcode, 25, 16);
815 uint32_t J1 = Bits32(opcode, 13, 13);
816 uint32_t J2 = Bits32(opcode, 11, 11);
817 uint32_t imm11 = Bits32(opcode, 10, 0);
818 uint32_t I1 = !(J1 ^ S);
819 uint32_t I2 = !(J2 ^ S);
Johnny Chen53ebab72011-02-08 23:21:57 +0000820 uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
Johnny Chend6c13f02011-02-08 20:36:34 +0000821 imm32 = llvm::SignExtend32<25>(imm25);
822 target = pc + 4 + imm32;
823 context.arg1 = 4 + imm32; // signed offset
824 context.arg2 = eModeThumb; // target instruction set
825 break;
826 }
Johnny Chen9b8d7832011-02-02 01:13:56 +0000827 case eEncodingT2:
828 {
829 lr = (pc + 4) | 1u; // return address
830 uint32_t S = Bits32(opcode, 26, 26);
831 uint32_t imm10H = Bits32(opcode, 25, 16);
832 uint32_t J1 = Bits32(opcode, 13, 13);
833 uint32_t J2 = Bits32(opcode, 11, 11);
834 uint32_t imm10L = Bits32(opcode, 10, 1);
835 uint32_t I1 = !(J1 ^ S);
836 uint32_t I2 = !(J2 ^ S);
Johnny Chen53ebab72011-02-08 23:21:57 +0000837 uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10H << 12) | (imm10L << 2);
Johnny Chen9b8d7832011-02-02 01:13:56 +0000838 imm32 = llvm::SignExtend32<25>(imm25);
Johnny Chend6c13f02011-02-08 20:36:34 +0000839 target = Align(pc + 4, 4) + imm32;
840 context.arg1 = 4 + imm32; // signed offset
841 context.arg2 = eModeARM; // target instruction set
Johnny Chen9b8d7832011-02-02 01:13:56 +0000842 break;
843 }
Johnny Chenc47d0ca2011-02-08 18:58:31 +0000844 case eEncodingA1:
845 lr = pc + 4; // return address
846 imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2);
Johnny Chend6c13f02011-02-08 20:36:34 +0000847 target = Align(pc + 8, 4) + imm32;
848 context.arg1 = 8 + imm32; // signed offset
849 context.arg2 = eModeARM; // target instruction set
Johnny Chenc47d0ca2011-02-08 18:58:31 +0000850 break;
Johnny Chen9b8d7832011-02-02 01:13:56 +0000851 case eEncodingA2:
852 lr = pc + 4; // return address
853 imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2 | Bits32(opcode, 24, 24) << 1);
854 target = pc + 8 + imm32;
Johnny Chen9ee056b2011-02-08 00:06:35 +0000855 context.arg1 = 8 + imm32; // signed offset
856 context.arg2 = eModeThumb; // target instruction set
Johnny Chen9b8d7832011-02-02 01:13:56 +0000857 break;
858 default:
859 return false;
860 }
861 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
862 return false;
Johnny Chen9ee056b2011-02-08 00:06:35 +0000863 if (!BranchWritePC(context, target))
Johnny Chen9b8d7832011-02-02 01:13:56 +0000864 return false;
865 }
866 return true;
867}
868
869// Branch with Link and Exchange (register) calls a subroutine at an address and
870// instruction set specified by a register.
871// BLX (register)
872bool
873EmulateInstructionARM::EmulateBLXRm (ARMEncoding encoding)
874{
875#if 0
876 // ARM pseudo code...
877 if (ConditionPassed())
878 {
879 EncodingSpecificOperations();
880 target = R[m];
881 if CurrentInstrSet() == InstrSet_ARM then
882 next_instr_addr = PC - 4;
883 LR = next_instr_addr;
884 else
885 next_instr_addr = PC - 2;
886 LR = next_instr_addr<31:1> : ‘1’;
887 BXWritePC(target);
888 }
889#endif
890
891 bool success = false;
892 const uint32_t opcode = OpcodeAsUnsigned (&success);
893 if (!success)
894 return false;
895
896 if (ConditionPassed())
897 {
898 EmulateInstruction::Context context = { EmulateInstruction::eContextAbsoluteBranchRegister, 0, 0, 0};
899 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
900 addr_t lr; // next instruction address
901 addr_t target; // target address
902 if (!success)
903 return false;
904 uint32_t Rm; // the register with the target address
905 switch (encoding) {
906 case eEncodingT1:
907 lr = (pc + 2) | 1u; // return address
908 Rm = Bits32(opcode, 6, 3);
909 // if m == 15 then UNPREDICTABLE;
910 if (Rm == 15)
911 return false;
912 target = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
913 break;
914 case eEncodingA1:
915 lr = pc + 4; // return address
916 Rm = Bits32(opcode, 3, 0);
917 // if m == 15 then UNPREDICTABLE;
918 if (Rm == 15)
919 return false;
920 target = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
Johnny Chenb77be412011-02-04 00:40:18 +0000921 break;
Johnny Chen9b8d7832011-02-02 01:13:56 +0000922 default:
923 return false;
924 }
Johnny Chen9b8d7832011-02-02 01:13:56 +0000925 context.arg0 = eRegisterKindDWARF;
926 context.arg1 = dwarf_r0 + Rm;
Johnny Chen9b8d7832011-02-02 01:13:56 +0000927 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
928 return false;
Johnny Chen9ee056b2011-02-08 00:06:35 +0000929 if (!BXWritePC(context, target))
Johnny Chen9b8d7832011-02-02 01:13:56 +0000930 return false;
931 }
932 return true;
933}
934
Johnny Chen0d0148e2011-01-28 02:26:08 +0000935// Set r7 to point to some ip offset.
936// SUB (immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000937bool
938EmulateInstructionARM::EmulateSubR7IPImmediate (ARMEncoding encoding)
Johnny Chen0d0148e2011-01-28 02:26:08 +0000939{
940#if 0
941 // ARM pseudo code...
942 if (ConditionPassed())
943 {
944 EncodingSpecificOperations();
945 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), ‘1’);
946 if d == 15 then // Can only occur for ARM encoding
947 ALUWritePC(result); // setflags is always FALSE here
948 else
949 R[d] = result;
950 if setflags then
951 APSR.N = result<31>;
952 APSR.Z = IsZeroBit(result);
953 APSR.C = carry;
954 APSR.V = overflow;
955 }
956#endif
957
958 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000959 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen0d0148e2011-01-28 02:26:08 +0000960 if (!success)
961 return false;
962
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000963 if (ConditionPassed())
Johnny Chen0d0148e2011-01-28 02:26:08 +0000964 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000965 const addr_t ip = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r12, 0, &success);
Johnny Chen0d0148e2011-01-28 02:26:08 +0000966 if (!success)
967 return false;
968 uint32_t imm32;
969 switch (encoding) {
970 case eEncodingA1:
971 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
972 break;
973 default:
974 return false;
975 }
976 addr_t ip_offset = imm32;
977 addr_t addr = ip - ip_offset; // the adjusted ip value
978
979 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
980 eRegisterKindDWARF,
981 dwarf_r12,
982 -ip_offset };
983
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000984 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r7, addr))
Johnny Chen0d0148e2011-01-28 02:26:08 +0000985 return false;
986 }
987 return true;
988}
989
990// Set ip to point to some stack offset.
991// SUB (SP minus immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000992bool
993EmulateInstructionARM::EmulateSubIPSPImmediate (ARMEncoding encoding)
Johnny Chen0d0148e2011-01-28 02:26:08 +0000994{
995#if 0
996 // ARM pseudo code...
997 if (ConditionPassed())
998 {
999 EncodingSpecificOperations();
1000 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), ‘1’);
1001 if d == 15 then // Can only occur for ARM encoding
1002 ALUWritePC(result); // setflags is always FALSE here
1003 else
1004 R[d] = result;
1005 if setflags then
1006 APSR.N = result<31>;
1007 APSR.Z = IsZeroBit(result);
1008 APSR.C = carry;
1009 APSR.V = overflow;
1010 }
1011#endif
1012
1013 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001014 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen0d0148e2011-01-28 02:26:08 +00001015 if (!success)
1016 return false;
1017
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001018 if (ConditionPassed())
Johnny Chen0d0148e2011-01-28 02:26:08 +00001019 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001020 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen0d0148e2011-01-28 02:26:08 +00001021 if (!success)
1022 return false;
1023 uint32_t imm32;
1024 switch (encoding) {
1025 case eEncodingA1:
1026 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
1027 break;
1028 default:
1029 return false;
1030 }
1031 addr_t sp_offset = imm32;
1032 addr_t addr = sp - sp_offset; // the adjusted stack pointer value
1033
1034 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
1035 eRegisterKindGeneric,
1036 LLDB_REGNUM_GENERIC_SP,
1037 -sp_offset };
1038
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001039 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r12, addr))
Johnny Chen0d0148e2011-01-28 02:26:08 +00001040 return false;
1041 }
1042 return true;
1043}
1044
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001045// A sub operation to adjust the SP -- allocate space for local storage.
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001046bool
1047EmulateInstructionARM::EmulateSubSPImmdiate (ARMEncoding encoding)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001048{
1049#if 0
1050 // ARM pseudo code...
1051 if (ConditionPassed())
1052 {
1053 EncodingSpecificOperations();
1054 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), ‘1’);
1055 if d == 15 then // Can only occur for ARM encoding
Johnny Chen799dfd02011-01-26 23:14:33 +00001056 ALUWritePC(result); // setflags is always FALSE here
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001057 else
1058 R[d] = result;
1059 if setflags then
1060 APSR.N = result<31>;
1061 APSR.Z = IsZeroBit(result);
1062 APSR.C = carry;
1063 APSR.V = overflow;
1064 }
1065#endif
1066
1067 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001068 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001069 if (!success)
1070 return false;
1071
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001072 if (ConditionPassed())
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001073 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001074 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001075 if (!success)
1076 return false;
1077 uint32_t imm32;
1078 switch (encoding) {
Johnny Chene4455022011-01-26 00:08:59 +00001079 case eEncodingT1:
1080 imm32 = ThumbImmScaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
Johnny Chen60c0d622011-01-25 23:49:39 +00001081 case eEncodingT2:
1082 imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
1083 break;
1084 case eEncodingT3:
1085 imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32)
1086 break;
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001087 case eEncodingA1:
Johnny Chen60c0d622011-01-25 23:49:39 +00001088 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001089 break;
1090 default:
1091 return false;
1092 }
1093 addr_t sp_offset = imm32;
1094 addr_t addr = sp - sp_offset; // the adjusted stack pointer value
1095
1096 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
1097 eRegisterKindGeneric,
1098 LLDB_REGNUM_GENERIC_SP,
Johnny Chen5b442b72011-01-27 19:34:30 +00001099 -sp_offset };
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001100
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001101 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001102 return false;
1103 }
1104 return true;
1105}
1106
Johnny Chen08c25e82011-01-31 18:02:28 +00001107// A store operation to the stack that also updates the SP.
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001108bool
1109EmulateInstructionARM::EmulateSTRRtSP (ARMEncoding encoding)
Johnny Chence1ca772011-01-25 01:13:00 +00001110{
1111#if 0
1112 // ARM pseudo code...
1113 if (ConditionPassed())
1114 {
1115 EncodingSpecificOperations();
1116 offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
1117 address = if index then offset_addr else R[n];
1118 MemU[address,4] = if t == 15 then PCStoreValue() else R[t];
1119 if wback then R[n] = offset_addr;
1120 }
1121#endif
1122
1123 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001124 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chence1ca772011-01-25 01:13:00 +00001125 if (!success)
1126 return false;
1127
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001128 if (ConditionPassed())
Johnny Chence1ca772011-01-25 01:13:00 +00001129 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001130 const uint32_t addr_byte_size = GetAddressByteSize();
1131 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chence1ca772011-01-25 01:13:00 +00001132 if (!success)
1133 return false;
Johnny Chen91d99862011-01-25 19:07:04 +00001134 uint32_t Rt; // the source register
Johnny Chence1ca772011-01-25 01:13:00 +00001135 uint32_t imm12;
1136 switch (encoding) {
1137 case eEncodingA1:
Johnny Chen108d5aa2011-01-26 01:00:55 +00001138 Rt = Bits32(opcode, 15, 12);
1139 imm12 = Bits32(opcode, 11, 0);
Johnny Chence1ca772011-01-25 01:13:00 +00001140 break;
1141 default:
1142 return false;
1143 }
1144 addr_t sp_offset = imm12;
1145 addr_t addr = sp - sp_offset;
1146
1147 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
Johnny Chen91d99862011-01-25 19:07:04 +00001148 if (Rt != 15)
Johnny Chence1ca772011-01-25 01:13:00 +00001149 {
Johnny Chen91d99862011-01-25 19:07:04 +00001150 context.arg1 = dwarf_r0 + Rt; // arg1 in the context is the DWARF register number
1151 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001152 uint32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
Johnny Chence1ca772011-01-25 01:13:00 +00001153 if (!success)
1154 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001155 if (!WriteMemoryUnsigned (context, addr, reg_value, addr_byte_size))
Johnny Chence1ca772011-01-25 01:13:00 +00001156 return false;
1157 }
1158 else
1159 {
1160 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
1161 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001162 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Johnny Chence1ca772011-01-25 01:13:00 +00001163 if (!success)
1164 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001165 if (!WriteMemoryUnsigned (context, addr, pc + 8, addr_byte_size))
Johnny Chence1ca772011-01-25 01:13:00 +00001166 return false;
1167 }
1168
1169 context.type = EmulateInstruction::eContextAdjustStackPointer;
1170 context.arg0 = eRegisterKindGeneric;
1171 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +00001172 context.arg2 = -sp_offset;
Johnny Chence1ca772011-01-25 01:13:00 +00001173
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001174 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
Johnny Chence1ca772011-01-25 01:13:00 +00001175 return false;
1176 }
1177 return true;
1178}
1179
Johnny Chen08c25e82011-01-31 18:02:28 +00001180// Vector Push stores multiple extension registers to the stack.
1181// It also updates SP to point to the start of the stored data.
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001182bool
1183EmulateInstructionARM::EmulateVPUSH (ARMEncoding encoding)
Johnny Chen799dfd02011-01-26 23:14:33 +00001184{
1185#if 0
1186 // ARM pseudo code...
1187 if (ConditionPassed())
1188 {
1189 EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13);
1190 address = SP - imm32;
1191 SP = SP - imm32;
1192 if single_regs then
1193 for r = 0 to regs-1
1194 MemA[address,4] = S[d+r]; address = address+4;
1195 else
1196 for r = 0 to regs-1
1197 // Store as two word-aligned words in the correct order for current endianness.
1198 MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>;
1199 MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>;
1200 address = address+8;
1201 }
1202#endif
1203
1204 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001205 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen799dfd02011-01-26 23:14:33 +00001206 if (!success)
1207 return false;
1208
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001209 if (ConditionPassed())
Johnny Chen799dfd02011-01-26 23:14:33 +00001210 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001211 const uint32_t addr_byte_size = GetAddressByteSize();
1212 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen799dfd02011-01-26 23:14:33 +00001213 if (!success)
1214 return false;
1215 bool single_regs;
Johnny Chen587a0a42011-02-01 18:35:28 +00001216 uint32_t d; // UInt(D:Vd) or UInt(Vd:D) starting register
Johnny Chen799dfd02011-01-26 23:14:33 +00001217 uint32_t imm32; // stack offset
1218 uint32_t regs; // number of registers
1219 switch (encoding) {
1220 case eEncodingT1:
1221 case eEncodingA1:
1222 single_regs = false;
Johnny Chen587a0a42011-02-01 18:35:28 +00001223 d = Bits32(opcode, 22, 22) << 4 | Bits32(opcode, 15, 12);
Johnny Chen799dfd02011-01-26 23:14:33 +00001224 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1225 // If UInt(imm8) is odd, see "FSTMX".
1226 regs = Bits32(opcode, 7, 0) / 2;
1227 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1228 if (regs == 0 || regs > 16 || (d + regs) > 32)
1229 return false;
1230 break;
1231 case eEncodingT2:
1232 case eEncodingA2:
1233 single_regs = true;
1234 d = Bits32(opcode, 15, 12) << 1 | Bits32(opcode, 22, 22);
1235 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1236 regs = Bits32(opcode, 7, 0);
1237 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1238 if (regs == 0 || regs > 16 || (d + regs) > 32)
1239 return false;
1240 break;
1241 default:
1242 return false;
1243 }
1244 uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
1245 uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2;
1246 addr_t sp_offset = imm32;
1247 addr_t addr = sp - sp_offset;
1248 uint32_t i;
1249
1250 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
1251 for (i=d; i<regs; ++i)
1252 {
1253 context.arg1 = start_reg + i; // arg1 in the context is the DWARF register number
1254 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
1255 // uint64_t to accommodate 64-bit registers.
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001256 uint64_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
Johnny Chen799dfd02011-01-26 23:14:33 +00001257 if (!success)
1258 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001259 if (!WriteMemoryUnsigned (context, addr, reg_value, reg_byte_size))
Johnny Chen799dfd02011-01-26 23:14:33 +00001260 return false;
1261 addr += reg_byte_size;
1262 }
1263
1264 context.type = EmulateInstruction::eContextAdjustStackPointer;
1265 context.arg0 = eRegisterKindGeneric;
1266 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +00001267 context.arg2 = -sp_offset;
Johnny Chen799dfd02011-01-26 23:14:33 +00001268
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001269 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
Johnny Chen799dfd02011-01-26 23:14:33 +00001270 return false;
1271 }
1272 return true;
1273}
1274
Johnny Chen587a0a42011-02-01 18:35:28 +00001275// Vector Pop loads multiple extension registers from the stack.
1276// It also updates SP to point just above the loaded data.
1277bool
1278EmulateInstructionARM::EmulateVPOP (ARMEncoding encoding)
1279{
1280#if 0
1281 // ARM pseudo code...
1282 if (ConditionPassed())
1283 {
1284 EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13);
1285 address = SP;
1286 SP = SP + imm32;
1287 if single_regs then
1288 for r = 0 to regs-1
1289 S[d+r] = MemA[address,4]; address = address+4;
1290 else
1291 for r = 0 to regs-1
1292 word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8;
1293 // Combine the word-aligned words in the correct order for current endianness.
1294 D[d+r] = if BigEndian() then word1:word2 else word2:word1;
1295 }
1296#endif
1297
1298 bool success = false;
1299 const uint32_t opcode = OpcodeAsUnsigned (&success);
1300 if (!success)
1301 return false;
1302
1303 if (ConditionPassed())
1304 {
1305 const uint32_t addr_byte_size = GetAddressByteSize();
1306 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
1307 if (!success)
1308 return false;
1309 bool single_regs;
1310 uint32_t d; // UInt(D:Vd) or UInt(Vd:D) starting register
1311 uint32_t imm32; // stack offset
1312 uint32_t regs; // number of registers
1313 switch (encoding) {
1314 case eEncodingT1:
1315 case eEncodingA1:
1316 single_regs = false;
1317 d = Bits32(opcode, 22, 22) << 4 | Bits32(opcode, 15, 12);
1318 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1319 // If UInt(imm8) is odd, see "FLDMX".
1320 regs = Bits32(opcode, 7, 0) / 2;
1321 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1322 if (regs == 0 || regs > 16 || (d + regs) > 32)
1323 return false;
1324 break;
1325 case eEncodingT2:
1326 case eEncodingA2:
1327 single_regs = true;
1328 d = Bits32(opcode, 15, 12) << 1 | Bits32(opcode, 22, 22);
1329 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1330 regs = Bits32(opcode, 7, 0);
1331 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1332 if (regs == 0 || regs > 16 || (d + regs) > 32)
1333 return false;
1334 break;
1335 default:
1336 return false;
1337 }
1338 uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
1339 uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2;
1340 addr_t sp_offset = imm32;
1341 addr_t addr = sp;
1342 uint32_t i;
1343 uint64_t data; // uint64_t to accomodate 64-bit registers.
1344
1345 EmulateInstruction::Context context = { EmulateInstruction::eContextPopRegisterOffStack, eRegisterKindDWARF, 0, 0 };
1346 for (i=d; i<regs; ++i)
1347 {
1348 context.arg1 = start_reg + i; // arg1 in the context is the DWARF register number
1349 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
1350 data = ReadMemoryUnsigned(context, addr, reg_byte_size, 0, &success);
1351 if (!success)
1352 return false;
1353 if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, context.arg1, data))
1354 return false;
1355 addr += reg_byte_size;
1356 }
1357
1358 context.type = EmulateInstruction::eContextAdjustStackPointer;
1359 context.arg0 = eRegisterKindGeneric;
1360 context.arg1 = LLDB_REGNUM_GENERIC_SP;
1361 context.arg2 = sp_offset;
1362
1363 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp + sp_offset))
1364 return false;
1365 }
1366 return true;
1367}
1368
Johnny Chenb77be412011-02-04 00:40:18 +00001369// SVC (previously SWI)
1370bool
1371EmulateInstructionARM::EmulateSVC (ARMEncoding encoding)
1372{
1373#if 0
1374 // ARM pseudo code...
1375 if (ConditionPassed())
1376 {
1377 EncodingSpecificOperations();
1378 CallSupervisor();
1379 }
1380#endif
1381
1382 bool success = false;
1383 const uint32_t opcode = OpcodeAsUnsigned (&success);
1384 if (!success)
1385 return false;
1386
1387 if (ConditionPassed())
1388 {
1389 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1390 addr_t lr; // next instruction address
1391 if (!success)
1392 return false;
1393 uint32_t imm32; // the immediate constant
1394 uint32_t mode; // ARM or Thumb mode
1395 switch (encoding) {
1396 case eEncodingT1:
1397 lr = (pc + 2) | 1u; // return address
1398 imm32 = Bits32(opcode, 7, 0);
1399 mode = eModeThumb;
1400 break;
1401 case eEncodingA1:
1402 lr = pc + 4; // return address
1403 imm32 = Bits32(opcode, 23, 0);
1404 mode = eModeARM;
1405 break;
1406 default:
1407 return false;
1408 }
1409 EmulateInstruction::Context context = { EmulateInstruction::eContextSupervisorCall, mode, imm32, 0};
1410 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
1411 return false;
1412 }
1413 return true;
1414}
1415
Johnny Chenc315f862011-02-05 00:46:10 +00001416// If Then makes up to four following instructions (the IT block) conditional.
1417bool
1418EmulateInstructionARM::EmulateIT (ARMEncoding encoding)
1419{
1420#if 0
1421 // ARM pseudo code...
1422 EncodingSpecificOperations();
1423 ITSTATE.IT<7:0> = firstcond:mask;
1424#endif
1425
1426 bool success = false;
1427 const uint32_t opcode = OpcodeAsUnsigned (&success);
1428 if (!success)
1429 return false;
1430
1431 m_it_session.InitIT(Bits32(opcode, 7, 0));
1432 return true;
1433}
1434
Johnny Chen3b620b32011-02-07 20:11:47 +00001435// Branch causes a branch to a target address.
1436bool
1437EmulateInstructionARM::EmulateB (ARMEncoding encoding)
1438{
1439#if 0
1440 // ARM pseudo code...
1441 if (ConditionPassed())
1442 {
1443 EncodingSpecificOperations();
1444 BranchWritePC(PC + imm32);
1445 }
1446#endif
1447
1448 bool success = false;
1449 const uint32_t opcode = OpcodeAsUnsigned (&success);
1450 if (!success)
1451 return false;
1452
Johnny Chen9ee056b2011-02-08 00:06:35 +00001453 if (ConditionPassed())
1454 {
1455 EmulateInstruction::Context context = { EmulateInstruction::eContextRelativeBranchImmediate, 0, 0, 0};
1456 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001457 if (!success)
1458 return false;
Johnny Chen53ebab72011-02-08 23:21:57 +00001459 addr_t target; // target address
Johnny Chen9ee056b2011-02-08 00:06:35 +00001460 int32_t imm32; // PC-relative offset
1461 switch (encoding) {
1462 case eEncodingT1:
1463 // The 'cond' field is handled in EmulateInstructionARM::CurrentCond().
1464 imm32 = llvm::SignExtend32<9>(Bits32(opcode, 7, 0) << 1);
1465 target = pc + 4 + imm32;
1466 context.arg1 = 4 + imm32; // signed offset
1467 context.arg2 = eModeThumb; // target instruction set
1468 break;
1469 case eEncodingT2:
1470 imm32 = llvm::SignExtend32<12>(Bits32(opcode, 10, 0));
1471 target = pc + 4 + imm32;
1472 context.arg1 = 4 + imm32; // signed offset
1473 context.arg2 = eModeThumb; // target instruction set
1474 break;
1475 case eEncodingT3:
1476 // The 'cond' field is handled in EmulateInstructionARM::CurrentCond().
1477 {
1478 uint32_t S = Bits32(opcode, 26, 26);
1479 uint32_t imm6 = Bits32(opcode, 21, 16);
1480 uint32_t J1 = Bits32(opcode, 13, 13);
1481 uint32_t J2 = Bits32(opcode, 11, 11);
1482 uint32_t imm11 = Bits32(opcode, 10, 0);
Johnny Chen53ebab72011-02-08 23:21:57 +00001483 uint32_t imm21 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001484 imm32 = llvm::SignExtend32<21>(imm21);
1485 target = pc + 4 + imm32;
1486 context.arg1 = eModeThumb; // target instruction set
1487 context.arg2 = 4 + imm32; // signed offset
1488 break;
1489 }
1490 case eEncodingT4:
1491 {
1492 uint32_t S = Bits32(opcode, 26, 26);
1493 uint32_t imm10 = Bits32(opcode, 25, 16);
1494 uint32_t J1 = Bits32(opcode, 13, 13);
1495 uint32_t J2 = Bits32(opcode, 11, 11);
1496 uint32_t imm11 = Bits32(opcode, 10, 0);
1497 uint32_t I1 = !(J1 ^ S);
1498 uint32_t I2 = !(J2 ^ S);
Johnny Chen53ebab72011-02-08 23:21:57 +00001499 uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001500 imm32 = llvm::SignExtend32<25>(imm25);
1501 target = pc + 4 + imm32;
1502 context.arg1 = eModeThumb; // target instruction set
1503 context.arg2 = 4 + imm32; // signed offset
1504 break;
1505 }
1506 case eEncodingA1:
1507 imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2);
1508 target = pc + 8 + imm32;
1509 context.arg1 = eModeARM; // target instruction set
1510 context.arg2 = 8 + imm32; // signed offset
1511 break;
1512 default:
1513 return false;
1514 }
1515 if (!BranchWritePC(context, target))
1516 return false;
1517 }
1518 return true;
Johnny Chen3b620b32011-02-07 20:11:47 +00001519}
1520
Johnny Chen53ebab72011-02-08 23:21:57 +00001521// Compare and Branch on Nonzero and Compare and Branch on Zero compare the value in a register with
1522// zero and conditionally branch forward a constant value. They do not affect the condition flags.
1523// CBNZ, CBZ
1524bool
1525EmulateInstructionARM::EmulateCB (ARMEncoding encoding)
1526{
1527#if 0
1528 // ARM pseudo code...
1529 EncodingSpecificOperations();
1530 if nonzero ^ IsZero(R[n]) then
1531 BranchWritePC(PC + imm32);
1532#endif
1533
1534 bool success = false;
1535 const uint32_t opcode = OpcodeAsUnsigned (&success);
1536 if (!success)
1537 return false;
1538
1539 // Read the register value from the operand register Rn.
1540 uint32_t reg_val = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Bits32(opcode, 2, 0), 0, &success);
1541 if (!success)
1542 return false;
1543
1544 EmulateInstruction::Context context = { EmulateInstruction::eContextRelativeBranchImmediate, 0, 0, 0};
1545 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1546 if (!success)
1547 return false;
1548
1549 addr_t target; // target address
1550 uint32_t imm32; // PC-relative offset to branch forward
1551 bool nonzero;
1552 switch (encoding) {
1553 case eEncodingT1:
1554 imm32 = Bits32(opcode, 9, 9) << 6 | Bits32(opcode, 7, 3) << 1;
1555 nonzero = BitIsSet(opcode, 11);
1556 target = pc + 4 + imm32;
1557 context.arg1 = 4 + imm32; // signed offset
1558 context.arg2 = eModeThumb; // target instruction set
1559 break;
1560 default:
1561 return false;
1562 }
1563 if (nonzero ^ (reg_val == 0))
1564 if (!BranchWritePC(context, target))
1565 return false;
1566
1567 return true;
1568}
1569
Johnny Chen26863dc2011-02-09 23:43:29 +00001570// ADD <Rdn>, <Rm>
1571// where <Rdn> the destination register is also the first operand register
1572// and <Rm> is the second operand register.
1573bool
1574EmulateInstructionARM::EmulateAddRdnRm (ARMEncoding encoding)
1575{
1576#if 0
1577 // ARM pseudo code...
1578 if ConditionPassed() then
1579 EncodingSpecificOperations();
1580 shifted = Shift(R[m], shift_t, shift_n, APSR.C);
1581 (result, carry, overflow) = AddWithCarry(R[n], shifted, '0');
1582 if d == 15 then
1583 ALUWritePC(result); // setflags is always FALSE here
1584 else
1585 R[d] = result;
1586 if setflags then
1587 APSR.N = result<31>;
1588 APSR.Z = IsZeroBit(result);
1589 APSR.C = carry;
1590 APSR.V = overflow;
1591#endif
1592
1593 bool success = false;
1594 const uint32_t opcode = OpcodeAsUnsigned (&success);
1595 if (!success)
1596 return false;
1597
1598 if (ConditionPassed())
1599 {
1600 uint32_t Rd, Rn, Rm;
1601 //bool setflags = false;
1602 switch (encoding)
1603 {
1604 case eEncodingT2:
1605 // setflags = FALSE
1606 Rd = Rn = Bits32(opcode, 7, 7) << 3 | Bits32(opcode, 2, 0);
1607 Rm = Bits32(opcode, 6, 3);
1608 if (Rn == 15 && Rm == 15)
1609 return false;
1610 break;
1611 default:
1612 return false;
1613 }
1614
1615 int32_t result, val1, val2;
1616 // Read the first operand.
1617 if (Rn == 15)
1618 val1 = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1619 else
1620 val1 = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success);
1621 if (!success)
1622 return false;
1623
1624 // Read the second operand.
1625 if (Rm == 15)
1626 val2 = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1627 else
1628 val2 = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
1629 if (!success)
1630 return false;
1631
1632 result = val1 + val2;
1633 EmulateInstruction::Context context = { EmulateInstruction::eContextImmediate,
1634 result,
1635 0,
1636 0 };
1637
1638 if (Rd == 15)
1639 {
1640 if (!ALUWritePC (context, result))
1641 return false;
1642 }
1643 else
1644 {
1645 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, result))
1646 return false;
1647 }
1648 }
1649 return true;
1650}
1651
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001652// LDM loads multiple registers from consecutive memory locations, using an
1653// address from a base register. Optionally the addres just above the highest of those locations
1654// can be written back to the base register.
1655bool
1656EmulateInstructionARM::EmulateLDM (ARMEncoding encoding)
1657{
1658#if 0
1659 // ARM pseudo code...
1660 if ConditionPassed()
1661 EncodingSpecificOperations(); NullCheckIfThumbEE (n);
1662 address = R[n];
1663
1664 for i = 0 to 14
1665 if registers<i> == '1' then
1666 R[i] = MemA[address, 4]; address = address + 4;
1667 if registers<15> == '1' then
1668 LoadWritePC (MemA[address, 4]);
1669
1670 if wback && registers<n> == '0' then R[n] = R[n] + 4 * BitCount (registers);
1671 if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
1672
1673#endif
1674
1675 bool success = false;
1676 const uint32_t opcode = OpcodeAsUnsigned (&success);
1677 if (!success)
1678 return false;
1679
1680 if (ConditionPassed())
1681 {
1682 uint32_t n;
1683 uint32_t registers = 0;
1684 bool wback;
1685 const uint32_t addr_byte_size = GetAddressByteSize();
1686 switch (encoding)
1687 {
1688 case eEncodingT1:
1689 n = Bits32 (opcode, 10, 8);
1690 registers = Bits32 (opcode, 7, 0);
1691 wback = BitIsClear (registers, n);
1692 // if BitCount(registers) < 1 then UNPREDICTABLE;
1693 if (BitCount(registers) < 1)
1694 return false;
1695 break;
1696 case eEncodingT2:
1697 n = Bits32 (opcode, 19, 16);
1698 registers = Bits32 (opcode, 15, 0);
1699 wback = BitIsSet (opcode, 21);
1700 if ((n == 15)
1701 || (BitCount (registers) < 2)
1702 || (BitIsSet (opcode, 14) && BitIsSet (opcode, 15)))
1703 return false;
1704 if (BitIsSet (registers, 15)
1705 && m_it_session.InITBlock()
1706 && !m_it_session.LastInITBlock())
1707 return false;
1708 if (wback
1709 && BitIsSet (registers, n))
1710 return false;
1711 break;
1712 case eEncodingA1:
1713 n = Bits32 (opcode, 19, 16);
1714 registers = Bits32 (opcode, 15, 0);
1715 wback = BitIsSet (opcode, 21);
1716 if ((n == 15)
1717 || (BitCount (registers) < 1))
1718 return false;
1719 break;
1720 default:
1721 return false;
1722 }
1723
1724 int32_t offset = 0;
1725 const addr_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
1726 if (!success)
1727 return false;
Caroline Tice85aab332011-02-08 23:56:10 +00001728
1729 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
1730 eRegisterKindDWARF,
1731 dwarf_r0 + n,
1732 offset };
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001733
1734 for (int i = 0; i < 14; ++i)
1735 {
1736 if (BitIsSet (registers, i))
1737 {
Caroline Tice85aab332011-02-08 23:56:10 +00001738 context.type = EmulateInstruction::eContextRegisterPlusOffset;
1739 context.arg2 = offset;
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001740 if (wback && (n == 13)) // Pop Instruction
1741 context.type = EmulateInstruction::eContextPopRegisterOffStack;
1742
1743 // R[i] = MemA [address, 4]; address = address + 4;
1744 uint32_t data = ReadMemoryUnsigned (context, base_address + offset, addr_byte_size, 0, &success);
1745 if (!success)
1746 return false;
1747
1748 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
1749 return false;
1750
1751 offset += addr_byte_size;
1752 }
1753 }
1754
1755 if (BitIsSet (registers, 15))
1756 {
1757 //LoadWritePC (MemA [address, 4]);
Caroline Tice85aab332011-02-08 23:56:10 +00001758 context.type = EmulateInstruction::eContextRegisterPlusOffset;
1759 context.arg2 = offset;
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001760 uint32_t data = ReadMemoryUnsigned (context, base_address + offset, addr_byte_size, 0, &success);
1761 if (!success)
1762 return false;
Johnny Chene62b50d2011-02-09 22:02:17 +00001763 // In ARMv5T and above, this is an interworking branch.
1764 if (!LoadWritePC(context, data))
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001765 return false;
1766 }
1767
1768 if (wback && BitIsClear (registers, n))
1769 {
1770 addr_t offset = addr_byte_size * BitCount (registers);
Caroline Tice85aab332011-02-08 23:56:10 +00001771 context.type = EmulateInstruction::eContextRegisterPlusOffset;
1772 context.arg2 = offset;
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001773
1774 // R[n] = R[n] + 4 * BitCount (registers)
1775 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, base_address + offset))
1776 return false;
1777 }
1778 if (wback && BitIsSet (registers, n))
1779 // R[n] bits(32) UNKNOWN;
1780 return false; //I'm not convinced this is the right thing to do here...
1781 }
1782 return true;
1783}
1784
Caroline Tice0b29e242011-02-08 23:16:02 +00001785bool
1786EmulateInstructionARM::EmulateLDMDB (ARMEncoding encoding)
1787{
1788#if 0
1789 // ARM pseudo code...
1790 if ConditionPassed() then
1791 EncodingSpecificOperations(); NullCheckIfThumbEE(n);
1792 address = R[n] - 4*BitCount(registers);
1793
1794 for i = 0 to 14
1795 if registers<i> == ’1’ then
1796 R[i] = MemA[address,4]; address = address + 4;
1797 if registers<15> == ’1’ then
1798 LoadWritePC(MemA[address,4]);
1799
1800 if wback && registers<n> == ’0’ then R[n] = R[n] - 4*BitCount(registers);
1801 if wback && registers<n> == ’1’ then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
1802#endif
1803
1804 bool success = false;
1805 const uint32_t opcode = OpcodeAsUnsigned (&success);
1806 if (!success)
1807 return false;
1808
1809 if (ConditionPassed())
1810 {
1811 uint32_t n;
1812 uint32_t registers = 0;
1813 bool wback;
1814 const uint32_t addr_byte_size = GetAddressByteSize();
1815 switch (encoding)
1816 {
1817 case eEncodingT1:
1818 // n = UInt(Rn); registers = P:M:’0’:register_list; wback = (W == ’1’);
1819 n = Bits32 (opcode, 19, 16);
1820 registers = Bits32 (opcode, 15, 0);
1821 wback = BitIsSet (opcode, 21);
1822
1823 // if n == 15 || BitCount(registers) < 2 || (P == ’1’ && M == ’1’) then UNPREDICTABLE;
1824 if ((n == 15)
1825 || (BitCount (registers) < 2)
1826 || (BitIsSet (opcode, 14) && BitIsSet (opcode, 15)))
1827 return false;
1828
1829 // if registers<15> == ’1’ && InITBlock() && !LastInITBlock() then UNPREDICTABLE;
1830 if (BitIsSet (registers, 15)
1831 && m_it_session.InITBlock()
1832 && !m_it_session.LastInITBlock())
1833 return false;
1834
1835 // if wback && registers<n> == ’1’ then UNPREDICTABLE;
1836 if (wback && BitIsSet (registers, n))
1837 return false;
1838
1839 break;
1840
1841 case eEncodingA1:
1842 // n = UInt(Rn); registers = register_list; wback = (W == ’1’);
1843 n = Bits32 (opcode, 19, 16);
1844 registers = Bits32 (opcode, 15, 0);
1845 wback = BitIsSet (opcode, 21);
1846
1847 // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
1848 if ((n == 15) || (BitCount (registers) < 1))
1849 return false;
1850
1851 break;
1852
1853 default:
1854 return false;
1855 }
1856
1857 int32_t offset = 0;
1858 addr_t address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success)
1859 - (addr_byte_size * BitCount (registers));
Caroline Tice85aab332011-02-08 23:56:10 +00001860 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
1861 eRegisterKindDWARF,
1862 dwarf_r0 + n,
1863 offset };
Caroline Tice0b29e242011-02-08 23:16:02 +00001864
1865 for (int i = 0; i < 14; ++i)
1866 {
1867 if (BitIsSet (registers, i))
1868 {
1869 // R[i] = MemA[address,4]; address = address + 4;
Caroline Tice85aab332011-02-08 23:56:10 +00001870 context.arg2 = offset;
Caroline Tice0b29e242011-02-08 23:16:02 +00001871 uint32_t data = ReadMemoryUnsigned (context, address + offset, addr_byte_size, 0, &success);
1872 if (!success)
1873 return false;
1874
1875 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
1876 return false;
1877
1878 offset += addr_byte_size;
1879 }
1880 }
1881
1882 // if registers<15> == ’1’ then
1883 // LoadWritePC(MemA[address,4]);
1884 if (BitIsSet (registers, 15))
1885 {
Caroline Tice85aab332011-02-08 23:56:10 +00001886 context.arg2 = offset;
Caroline Tice0b29e242011-02-08 23:16:02 +00001887 uint32_t data = ReadMemoryUnsigned (context, address + offset, addr_byte_size, 0, &success);
1888 if (!success)
1889 return false;
Johnny Chene62b50d2011-02-09 22:02:17 +00001890 // In ARMv5T and above, this is an interworking branch.
1891 if (!LoadWritePC(context, data))
Caroline Tice0b29e242011-02-08 23:16:02 +00001892 return false;
1893 }
1894
1895 // if wback && registers<n> == ’0’ then R[n] = R[n] - 4*BitCount(registers);
1896 if (wback && BitIsClear (registers, n))
1897 {
Caroline Tice85aab332011-02-08 23:56:10 +00001898 context.arg2 = offset;
Caroline Tice0b29e242011-02-08 23:16:02 +00001899 addr_t addr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
1900 if (!success)
1901 return false;
1902 addr = addr - (addr_byte_size * BitCount (registers));
1903 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr))
1904 return false;
1905 }
1906
1907 // if wback && registers<n> == ’1’ then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
1908 if (wback && BitIsSet (registers, n))
1909 return false; // I'm not sure this is right; how do I set R[n] to bits(32) UNKNOWN.
1910 }
1911 return true;
1912}
Caroline Tice85aab332011-02-08 23:56:10 +00001913
1914bool
1915EmulateInstructionARM::EmulateLDMIB (ARMEncoding encoding)
1916{
1917#if 0
1918 if ConditionPassed() then
1919 EncodingSpecificOperations();
1920 address = R[n] + 4;
1921
1922 for i = 0 to 14
1923 if registers<i> == ’1’ then
1924 R[i] = MemA[address,4]; address = address + 4;
1925 if registers<15> == ’1’ then
1926 LoadWritePC(MemA[address,4]);
1927
1928 if wback && registers<n> == ’0’ then R[n] = R[n] + 4*BitCount(registers);
1929 if wback && registers<n> == ’1’ then R[n] = bits(32) UNKNOWN;
1930#endif
1931
1932 bool success = false;
1933 const uint32_t opcode = OpcodeAsUnsigned (&success);
1934 if (!success)
1935 return false;
1936
1937 if (ConditionPassed())
1938 {
1939 uint32_t n;
1940 uint32_t registers = 0;
1941 bool wback;
1942 const uint32_t addr_byte_size = GetAddressByteSize();
1943 switch (encoding)
1944 {
1945 case eEncodingA1:
1946 // n = UInt(Rn); registers = register_list; wback = (W == ’1’);
1947 n = Bits32 (opcode, 19, 16);
1948 registers = Bits32 (opcode, 15, 0);
1949 wback = BitIsSet (opcode, 21);
1950
1951 // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
1952 if ((n == 15) || (BitCount (registers) < 1))
1953 return false;
1954
1955 break;
1956 default:
1957 return false;
1958 }
1959 // address = R[n] + 4;
1960
1961 int32_t offset = 0;
1962 addr_t address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success) + addr_byte_size;
1963
1964 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
1965 eRegisterKindDWARF,
1966 dwarf_r0 + n,
1967 offset };
1968
1969 for (int i = 0; i < 14; ++i)
1970 {
1971 if (BitIsSet (registers, i))
1972 {
1973 // R[i] = MemA[address,4]; address = address + 4;
1974
1975 context.arg2 = offset;
1976 uint32_t data = ReadMemoryUnsigned (context, address + offset, addr_byte_size, 0, &success);
1977 if (!success)
1978 return false;
1979
1980 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
1981 return false;
1982
1983 offset += addr_byte_size;
1984 }
1985 }
1986
1987 // if registers<15> == ’1’ then
1988 // LoadWritePC(MemA[address,4]);
1989 if (BitIsSet (registers, 15))
1990 {
1991 context.arg2 = offset;
1992 uint32_t data = ReadMemoryUnsigned (context, address + offset, addr_byte_size, 0, &success);
1993 if (!success)
1994 return false;
Johnny Chene62b50d2011-02-09 22:02:17 +00001995 // In ARMv5T and above, this is an interworking branch.
1996 if (!LoadWritePC(context, data))
Caroline Tice85aab332011-02-08 23:56:10 +00001997 return false;
1998 }
1999
2000 // if wback && registers<n> == ’0’ then R[n] = R[n] + 4*BitCount(registers);
2001 if (wback && BitIsClear (registers, n))
2002 {
2003 context.arg2 = offset;
2004 addr_t addr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
2005 if (!success)
2006 return false;
2007 addr = addr + (addr_byte_size * BitCount (registers));
2008 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr))
2009 return false;
2010 }
2011
2012 // if wback && registers<n> == ’1’ then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
2013 if (wback && BitIsSet (registers, n))
2014 return false; // I'm not sure this is right; how do I set R[n] to bits(32) UNKNOWN.
2015 }
2016 return true;
2017}
Caroline Tice0b29e242011-02-08 23:16:02 +00002018
Johnny Chenef21b592011-02-10 01:52:38 +00002019// Load Register (immediate) calculates an address from a base register value and
2020// an immediate offset, loads a word from memory, and writes to a register.
2021// LDR (immediate, Thumb)
2022bool
2023EmulateInstructionARM::EmulateLDRRtRnImm (ARMEncoding encoding)
2024{
2025#if 0
2026 // ARM pseudo code...
2027 if (ConditionPassed())
2028 {
2029 EncodingSpecificOperations(); NullCheckIfThumbEE(15);
2030 offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
2031 address = if index then offset_addr else R[n];
2032 data = MemU[address,4];
2033 if wback then R[n] = offset_addr;
2034 if t == 15 then
2035 if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
2036 elsif UnalignedSupport() || address<1:0> = '00' then
2037 R[t] = data;
2038 else R[t] = bits(32) UNKNOWN; // Can only apply before ARMv7
2039 }
2040#endif
2041
2042 bool success = false;
2043 const uint32_t opcode = OpcodeAsUnsigned (&success);
2044 if (!success)
2045 return false;
2046
2047 if (ConditionPassed())
2048 {
2049 uint32_t Rt; // the destination register
2050 uint32_t Rn; // the base register
2051 uint32_t imm32; // the immediate offset used to form the address
2052 addr_t offset_addr; // the offset address
2053 addr_t address; // the calculated address
2054 uint32_t data; // the literal data value from memory load
2055 bool add, index, wback;
2056 switch (encoding) {
2057 case eEncodingT1:
2058 Rt = Bits32(opcode, 5, 3);
2059 Rn = Bits32(opcode, 2, 0);
2060 imm32 = Bits32(opcode, 10, 6) << 2; // imm32 = ZeroExtend(imm5:'00', 32);
2061 // index = TRUE; add = TRUE; wback = FALSE
2062 add = true;
2063 index = true;
2064 wback = false;
2065 break;
2066 default:
2067 return false;
2068 }
2069 uint32_t base = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success);
2070 if (!success)
2071 return false;
2072 if (add)
2073 offset_addr = base + imm32;
2074 else
2075 offset_addr = base - imm32;
2076
2077 address = (index ? offset_addr : base);
2078
2079 if (wback)
2080 {
2081 EmulateInstruction::Context ctx = { EmulateInstruction::eContextRegisterPlusOffset,
2082 eRegisterKindDWARF,
2083 dwarf_r0 + Rn,
2084 (int32_t) (offset_addr - base)};
2085 if (!WriteRegisterUnsigned (ctx, eRegisterKindDWARF, dwarf_r0 + Rn, offset_addr))
2086 return false;
2087 }
2088
2089 // Prepare to write to the Rt register.
2090 EmulateInstruction::Context context = {EmulateInstruction::eContextImmediate,
2091 0,
2092 0,
2093 0};
2094
2095 // Read memory from the address.
2096 data = ReadMemoryUnsigned(context, address, 4, 0, &success);
2097 if (!success)
2098 return false;
2099 context.arg0 = data;
2100
2101 if (Rt == 15)
2102 {
2103 if (Bits32(address, 1, 0) == 0)
2104 {
2105 if (!LoadWritePC(context, data))
2106 return false;
2107 }
2108 else
2109 return false;
2110 }
2111 else if (UnalignedSupport() || Bits32(address, 1, 0) == 0)
2112 {
2113 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rt, data))
2114 return false;
2115 }
2116 else
2117 return false;
2118 }
2119 return true;
2120}
2121
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002122EmulateInstructionARM::ARMOpcode*
2123EmulateInstructionARM::GetARMOpcodeForInstruction (const uint32_t opcode)
Greg Clayton64c84432011-01-21 22:02:52 +00002124{
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002125 static ARMOpcode
2126 g_arm_opcodes[] =
2127 {
2128 //----------------------------------------------------------------------
2129 // Prologue instructions
2130 //----------------------------------------------------------------------
Johnny Chenfdd179e2011-01-31 20:09:28 +00002131
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002132 // push register(s)
Johnny Chenc28a76d2011-02-01 18:51:48 +00002133 { 0x0fff0000, 0x092d0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulatePush, "push <registers>" },
2134 { 0x0fff0fff, 0x052d0004, ARMvAll, eEncodingA2, eSize32, &EmulateInstructionARM::EmulatePush, "push <register>" },
Johnny Chenbcec3af2011-01-27 01:26:19 +00002135
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002136 // set r7 to point to a stack offset
Johnny Chenc28a76d2011-02-01 18:51:48 +00002137 { 0x0ffff000, 0x028d7000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateAddRdSPImmediate, "add r7, sp, #<const>" },
2138 { 0x0ffff000, 0x024c7000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSubR7IPImmediate, "sub r7, ip, #<const>"},
Johnny Chene7cf4202011-02-10 18:13:23 +00002139 // copy the stack pointer to ip
Johnny Chenc28a76d2011-02-01 18:51:48 +00002140 { 0x0fffffff, 0x01a0c00d, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateMovRdSP, "mov ip, sp" },
2141 { 0x0ffff000, 0x028dc000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateAddRdSPImmediate, "add ip, sp, #<const>" },
2142 { 0x0ffff000, 0x024dc000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSubIPSPImmediate, "sub ip, sp, #<const>"},
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00002143
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002144 // adjust the stack pointer
Johnny Chenc28a76d2011-02-01 18:51:48 +00002145 { 0x0ffff000, 0x024dd000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSubSPImmdiate, "sub sp, sp, #<const>"},
Johnny Chence1ca772011-01-25 01:13:00 +00002146
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002147 // push one register
2148 // if Rn == '1101' && imm12 == '000000000100' then SEE PUSH;
Johnny Chenc28a76d2011-02-01 18:51:48 +00002149 { 0x0fff0000, 0x052d0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSTRRtSP, "str Rt, [sp, #-imm12]!" },
Johnny Chen799dfd02011-01-26 23:14:33 +00002150
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002151 // vector push consecutive extension register(s)
Johnny Chen9b8d7832011-02-02 01:13:56 +00002152 { 0x0fbf0f00, 0x0d2d0b00, ARMV6T2_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"},
2153 { 0x0fbf0f00, 0x0d2d0a00, ARMV6T2_ABOVE, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"},
Johnny Chenef85e912011-01-31 23:07:40 +00002154
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002155 //----------------------------------------------------------------------
Johnny Chen587a0a42011-02-01 18:35:28 +00002156 // Epilogue instructions
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002157 //----------------------------------------------------------------------
Johnny Chenef85e912011-01-31 23:07:40 +00002158
Johnny Chen9b8d7832011-02-02 01:13:56 +00002159 // To resolve ambiguity, "blx <label>" should come before "bl <label>".
2160 { 0xfe000000, 0xfa000000, ARMV5_ABOVE, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
2161 { 0x0f000000, 0x0b000000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"},
2162 { 0x0ffffff0, 0x012fff30, ARMV5_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
Johnny Chenc28a76d2011-02-01 18:51:48 +00002163 { 0x0fff0000, 0x08bd0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulatePop, "pop <registers>"},
2164 { 0x0fff0fff, 0x049d0004, ARMvAll, eEncodingA2, eSize32, &EmulateInstructionARM::EmulatePop, "pop <register>"},
Johnny Chen9b8d7832011-02-02 01:13:56 +00002165 { 0x0fbf0f00, 0x0cbd0b00, ARMV6T2_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"},
Johnny Chenb77be412011-02-04 00:40:18 +00002166 { 0x0fbf0f00, 0x0cbd0a00, ARMV6T2_ABOVE, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"},
2167
2168 //----------------------------------------------------------------------
2169 // Supervisor Call (previously Software Interrupt)
2170 //----------------------------------------------------------------------
Johnny Chen3b620b32011-02-07 20:11:47 +00002171 { 0x0f000000, 0x0f000000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSVC, "svc #imm24"},
2172
2173 //----------------------------------------------------------------------
2174 // Branch instructions
2175 //----------------------------------------------------------------------
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002176 { 0x0f000000, 0x0a000000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSVC, "b #imm24"},
Johnny Chenb77be412011-02-04 00:40:18 +00002177
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002178 //----------------------------------------------------------------------
2179 // Load instructions
2180 //----------------------------------------------------------------------
Caroline Tice0b29e242011-02-08 23:16:02 +00002181 { 0x0fd00000, 0x08900000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDM, "ldm<c> <Rn>{!} <registers>" },
Caroline Tice85aab332011-02-08 23:56:10 +00002182 { 0x0fd00000, 0x09100000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDMDB, "ldmdb<c> <Rn>{!} <registers>" },
2183 { 0x0fd00000, 0x09900000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDMIB, "ldmib<c> <Rn<{!} <registers>" }
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002184
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002185 };
2186 static const size_t k_num_arm_opcodes = sizeof(g_arm_opcodes)/sizeof(ARMOpcode);
2187
2188 for (size_t i=0; i<k_num_arm_opcodes; ++i)
2189 {
2190 if ((g_arm_opcodes[i].mask & opcode) == g_arm_opcodes[i].value)
2191 return &g_arm_opcodes[i];
2192 }
2193 return NULL;
2194}
Greg Clayton64c84432011-01-21 22:02:52 +00002195
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002196
2197EmulateInstructionARM::ARMOpcode*
2198EmulateInstructionARM::GetThumbOpcodeForInstruction (const uint32_t opcode)
Johnny Chen347320d2011-01-24 23:40:59 +00002199{
Johnny Chenfdd179e2011-01-31 20:09:28 +00002200
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002201 static ARMOpcode
2202 g_thumb_opcodes[] =
2203 {
2204 //----------------------------------------------------------------------
2205 // Prologue instructions
2206 //----------------------------------------------------------------------
Johnny Chenbcec3af2011-01-27 01:26:19 +00002207
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002208 // push register(s)
Johnny Chenc28a76d2011-02-01 18:51:48 +00002209 { 0xfffffe00, 0x0000b400, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulatePush, "push <registers>" },
Johnny Chend6c13f02011-02-08 20:36:34 +00002210 { 0xffff0000, 0xe92d0000, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulatePush, "push.w <registers>" },
2211 { 0xffff0fff, 0xf84d0d04, ARMV6T2_ABOVE, eEncodingT3, eSize32, &EmulateInstructionARM::EmulatePush, "push.w <register>" },
Johnny Chen788e0552011-01-27 22:52:23 +00002212
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002213 // set r7 to point to a stack offset
Johnny Chenc28a76d2011-02-01 18:51:48 +00002214 { 0xffffff00, 0x0000af00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateAddRdSPImmediate, "add r7, sp, #imm" },
Johnny Chene7cf4202011-02-10 18:13:23 +00002215 // copy the stack pointer to r7
Johnny Chenc28a76d2011-02-01 18:51:48 +00002216 { 0xffffffff, 0x0000466f, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateMovRdSP, "mov r7, sp" },
Johnny Chene7cf4202011-02-10 18:13:23 +00002217 // move from high register to low register (comes after "mov r7, sp" to resolve ambiguity)
2218 { 0xffffffc0, 0x00004640, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateMovLowHigh, "mov r0-r7, r8-r15" },
Johnny Chen60c0d622011-01-25 23:49:39 +00002219
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002220 // PC relative load into register (see also EmulateAddSPRm)
Johnny Chenc28a76d2011-02-01 18:51:48 +00002221 { 0xfffff800, 0x00004800, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateLDRRdPCRelative, "ldr <Rd>, [PC, #imm]"},
Johnny Chen799dfd02011-01-26 23:14:33 +00002222
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002223 // adjust the stack pointer
Johnny Chenc28a76d2011-02-01 18:51:48 +00002224 { 0xffffff87, 0x00004485, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateAddSPRm, "add sp, <Rm>"},
2225 { 0xffffff80, 0x0000b080, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateSubSPImmdiate, "add sp, sp, #imm"},
Johnny Chend6c13f02011-02-08 20:36:34 +00002226 { 0xfbef8f00, 0xf1ad0d00, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateSubSPImmdiate, "sub.w sp, sp, #<const>"},
2227 { 0xfbff8f00, 0xf2ad0d00, ARMV6T2_ABOVE, eEncodingT3, eSize32, &EmulateInstructionARM::EmulateSubSPImmdiate, "subw sp, sp, #imm12"},
Johnny Chenfdd179e2011-01-31 20:09:28 +00002228
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002229 // vector push consecutive extension register(s)
Johnny Chend6c13f02011-02-08 20:36:34 +00002230 { 0xffbf0f00, 0xed2d0b00, ARMV6T2_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"},
2231 { 0xffbf0f00, 0xed2d0a00, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"},
Johnny Chenfdd179e2011-01-31 20:09:28 +00002232
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002233 //----------------------------------------------------------------------
2234 // Epilogue instructions
2235 //----------------------------------------------------------------------
Johnny Chen347320d2011-01-24 23:40:59 +00002236
Johnny Chenc28a76d2011-02-01 18:51:48 +00002237 { 0xffffff80, 0x0000b000, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateAddSPImmediate, "add sp, #imm"},
Johnny Chen9b8d7832011-02-02 01:13:56 +00002238 { 0xffffff87, 0x00004780, ARMV5_ABOVE, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
2239 // J1 == J2 == 1
Johnny Chend6c13f02011-02-08 20:36:34 +00002240 { 0xf800f800, 0xf000f800, ARMV4T_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"},
2241 // J1 == J2 == 1
2242 { 0xf800e800, 0xf000e800, ARMV5_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
Johnny Chenc28a76d2011-02-01 18:51:48 +00002243 { 0xfffffe00, 0x0000bc00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulatePop, "pop <registers>"},
Johnny Chend6c13f02011-02-08 20:36:34 +00002244 { 0xffff0000, 0xe8bd0000, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulatePop, "pop.w <registers>" },
2245 { 0xffff0fff, 0xf85d0d04, ARMV6T2_ABOVE, eEncodingT3, eSize32, &EmulateInstructionARM::EmulatePop, "pop.w <register>" },
2246 { 0xffbf0f00, 0xecbd0b00, ARMV6T2_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"},
2247 { 0xffbf0f00, 0xecbd0a00, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"},
Johnny Chenb77be412011-02-04 00:40:18 +00002248
2249 //----------------------------------------------------------------------
2250 // Supervisor Call (previously Software Interrupt)
2251 //----------------------------------------------------------------------
Johnny Chenc315f862011-02-05 00:46:10 +00002252 { 0xffffff00, 0x0000df00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateSVC, "svc #imm8"},
2253
2254 //----------------------------------------------------------------------
2255 // If Then makes up to four following instructions conditional.
2256 //----------------------------------------------------------------------
Johnny Chen3b620b32011-02-07 20:11:47 +00002257 { 0xffffff00, 0x0000bf00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateIT, "it{<x>{<y>{<z>}}} <firstcond>"},
2258
2259 //----------------------------------------------------------------------
2260 // Branch instructions
2261 //----------------------------------------------------------------------
2262 // To resolve ambiguity, "b<c> #imm8" should come after "svc #imm8".
2263 { 0xfffff000, 0x0000d000, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateB, "b<c> #imm8 (outside IT)"},
2264 { 0xffff8000, 0x0000e000, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateB, "b #imm11 (outside or last in IT)"},
Johnny Chen9ee056b2011-02-08 00:06:35 +00002265 { 0xf800d000, 0xf0008000, ARMV6T2_ABOVE, eEncodingT3, eSize32, &EmulateInstructionARM::EmulateB, "b<c>.w #imm8 (outside IT)"},
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002266 { 0xf800d000, 0xf0009000, ARMV6T2_ABOVE, eEncodingT4, eSize32, &EmulateInstructionARM::EmulateB, "b.w #imm8 (outside or last in IT)"},
Johnny Chen53ebab72011-02-08 23:21:57 +00002267 // compare and branch
2268 { 0xfffff500, 0x0000b100, ARMV6T2_ABOVE, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateCB, "cb{n}z <Rn>, <label>"},
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002269
2270 //----------------------------------------------------------------------
Johnny Chen26863dc2011-02-09 23:43:29 +00002271 // Data-processing instructions
2272 //----------------------------------------------------------------------
2273 // Make sure "add sp, <Rm>" comes before this instruction, so there's no ambiguity decoding the two.
2274 { 0xffffff00, 0x00004400, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateAddRdnRm, "add <Rdn>, <Rm>"},
Johnny Chen338bf542011-02-10 19:29:03 +00002275 // move from high register to high register
2276 { 0xffffff00, 0x00004600, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateMovRdRm, "mov<c> <Rd>, <Rm>"},
2277 // move from low register to low register
2278 { 0xffffffc0, 0x00000000, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateMovRdRm, "movs <Rd>, <Rm>"},
Johnny Chen26863dc2011-02-09 23:43:29 +00002279
2280 //----------------------------------------------------------------------
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002281 // Load instructions
2282 //----------------------------------------------------------------------
2283 { 0xfffff800, 0x0000c800, ARMV4T_ABOVE, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateLDM, "ldm<c> <Rn>{!} <registers>" },
Caroline Tice0b29e242011-02-08 23:16:02 +00002284 { 0xffd02000, 0xe8900000, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateLDM, "ldm<c>.w <Rn>{!} <registers>" },
Johnny Chenef21b592011-02-10 01:52:38 +00002285 { 0xffd00000, 0xe9100000, ARMV6T2_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateLDMDB, "ldmdb<c> <Rn>{!} <registers>" },
2286 { 0xfffff800, 0x00006800, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr<c> <Rt>, [<Rn>{,#imm}]"}
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002287
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002288 };
2289
2290 const size_t k_num_thumb_opcodes = sizeof(g_thumb_opcodes)/sizeof(ARMOpcode);
2291 for (size_t i=0; i<k_num_thumb_opcodes; ++i)
2292 {
2293 if ((g_thumb_opcodes[i].mask & opcode) == g_thumb_opcodes[i].value)
2294 return &g_thumb_opcodes[i];
2295 }
2296 return NULL;
2297}
Greg Clayton64c84432011-01-21 22:02:52 +00002298
Greg Clayton31e2a382011-01-30 20:03:56 +00002299bool
2300EmulateInstructionARM::SetTargetTriple (const ConstString &triple)
2301{
2302 m_arm_isa = 0;
2303 const char *triple_cstr = triple.GetCString();
2304 if (triple_cstr)
2305 {
2306 const char *dash = ::strchr (triple_cstr, '-');
2307 if (dash)
2308 {
2309 std::string arch (triple_cstr, dash);
2310 const char *arch_cstr = arch.c_str();
2311 if (strcasecmp(arch_cstr, "armv4t") == 0)
2312 m_arm_isa = ARMv4T;
2313 else if (strcasecmp(arch_cstr, "armv4") == 0)
2314 m_arm_isa = ARMv4;
2315 else if (strcasecmp(arch_cstr, "armv5tej") == 0)
2316 m_arm_isa = ARMv5TEJ;
2317 else if (strcasecmp(arch_cstr, "armv5te") == 0)
2318 m_arm_isa = ARMv5TE;
2319 else if (strcasecmp(arch_cstr, "armv5t") == 0)
2320 m_arm_isa = ARMv5T;
2321 else if (strcasecmp(arch_cstr, "armv6k") == 0)
2322 m_arm_isa = ARMv6K;
2323 else if (strcasecmp(arch_cstr, "armv6") == 0)
2324 m_arm_isa = ARMv6;
2325 else if (strcasecmp(arch_cstr, "armv6t2") == 0)
2326 m_arm_isa = ARMv6T2;
2327 else if (strcasecmp(arch_cstr, "armv7") == 0)
2328 m_arm_isa = ARMv7;
2329 else if (strcasecmp(arch_cstr, "armv8") == 0)
2330 m_arm_isa = ARMv8;
2331 }
2332 }
2333 return m_arm_isa != 0;
2334}
2335
2336
Greg Clayton64c84432011-01-21 22:02:52 +00002337bool
2338EmulateInstructionARM::ReadInstruction ()
2339{
2340 bool success = false;
2341 m_inst_cpsr = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, 0, &success);
2342 if (success)
2343 {
2344 addr_t pc = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_ADDRESS, &success);
2345 if (success)
2346 {
2347 Context read_inst_context = {eContextReadOpcode, 0, 0};
2348 if (m_inst_cpsr & MASK_CPSR_T)
2349 {
2350 m_inst_mode = eModeThumb;
2351 uint32_t thumb_opcode = ReadMemoryUnsigned(read_inst_context, pc, 2, 0, &success);
2352
2353 if (success)
2354 {
2355 if ((m_inst.opcode.inst16 & 0xe000) != 0xe000 || ((m_inst.opcode.inst16 & 0x1800u) == 0))
2356 {
2357 m_inst.opcode_type = eOpcode16;
2358 m_inst.opcode.inst16 = thumb_opcode;
2359 }
2360 else
2361 {
2362 m_inst.opcode_type = eOpcode32;
2363 m_inst.opcode.inst32 = (thumb_opcode << 16) | ReadMemoryUnsigned(read_inst_context, pc + 2, 2, 0, &success);
2364 }
2365 }
2366 }
2367 else
2368 {
2369 m_inst_mode = eModeARM;
2370 m_inst.opcode_type = eOpcode32;
2371 m_inst.opcode.inst32 = ReadMemoryUnsigned(read_inst_context, pc, 4, 0, &success);
2372 }
2373 }
2374 }
2375 if (!success)
2376 {
2377 m_inst_mode = eModeInvalid;
2378 m_inst_pc = LLDB_INVALID_ADDRESS;
2379 }
2380 return success;
2381}
2382
Johnny Chenee9b1f72011-02-09 01:00:31 +00002383uint32_t
2384EmulateInstructionARM::ArchVersion ()
2385{
2386 return m_arm_isa;
2387}
2388
Greg Clayton64c84432011-01-21 22:02:52 +00002389bool
2390EmulateInstructionARM::ConditionPassed ()
2391{
2392 if (m_inst_cpsr == 0)
2393 return false;
2394
2395 const uint32_t cond = CurrentCond ();
2396
2397 if (cond == UINT32_MAX)
2398 return false;
2399
2400 bool result = false;
2401 switch (UnsignedBits(cond, 3, 1))
2402 {
2403 case 0: result = (m_inst_cpsr & MASK_CPSR_Z) != 0; break;
2404 case 1: result = (m_inst_cpsr & MASK_CPSR_C) != 0; break;
2405 case 2: result = (m_inst_cpsr & MASK_CPSR_N) != 0; break;
2406 case 3: result = (m_inst_cpsr & MASK_CPSR_V) != 0; break;
2407 case 4: result = ((m_inst_cpsr & MASK_CPSR_C) != 0) && ((m_inst_cpsr & MASK_CPSR_Z) == 0); break;
2408 case 5:
2409 {
2410 bool n = (m_inst_cpsr & MASK_CPSR_N);
2411 bool v = (m_inst_cpsr & MASK_CPSR_V);
2412 result = n == v;
2413 }
2414 break;
2415 case 6:
2416 {
2417 bool n = (m_inst_cpsr & MASK_CPSR_N);
2418 bool v = (m_inst_cpsr & MASK_CPSR_V);
2419 result = n == v && ((m_inst_cpsr & MASK_CPSR_Z) == 0);
2420 }
2421 break;
2422 case 7:
2423 result = true;
2424 break;
2425 }
2426
2427 if (cond & 1)
2428 result = !result;
2429 return result;
2430}
2431
Johnny Chen9ee056b2011-02-08 00:06:35 +00002432uint32_t
2433EmulateInstructionARM::CurrentCond ()
2434{
2435 switch (m_inst_mode)
2436 {
2437 default:
2438 case eModeInvalid:
2439 break;
2440
2441 case eModeARM:
2442 return UnsignedBits(m_inst.opcode.inst32, 31, 28);
2443
2444 case eModeThumb:
2445 // For T1 and T3 encodings of the Branch instruction, it returns the 4-bit
2446 // 'cond' field of the encoding.
2447 if (m_inst.opcode_type == eOpcode16 &&
2448 Bits32(m_inst.opcode.inst16, 15, 12) == 0x0d &&
2449 Bits32(m_inst.opcode.inst16, 11, 7) != 0x0f)
2450 {
2451 return Bits32(m_inst.opcode.inst16, 11, 7);
2452 }
2453 else if (m_inst.opcode_type == eOpcode32 &&
2454 Bits32(m_inst.opcode.inst32, 31, 27) == 0x1e &&
2455 Bits32(m_inst.opcode.inst32, 15, 14) == 0x02 &&
2456 Bits32(m_inst.opcode.inst32, 12, 12) == 0x00 &&
2457 Bits32(m_inst.opcode.inst32, 25, 22) <= 0x0d)
2458 {
2459 return Bits32(m_inst.opcode.inst32, 25, 22);
2460 }
2461
2462 return m_it_session.GetCond();
2463 }
2464 return UINT32_MAX; // Return invalid value
2465}
2466
Johnny Chen9ee056b2011-02-08 00:06:35 +00002467bool
2468EmulateInstructionARM::BranchWritePC (const Context &context, uint32_t addr)
2469{
2470 addr_t target;
2471
Johnny Chenee9b1f72011-02-09 01:00:31 +00002472 // Check the current instruction set.
2473 if (CurrentInstrSet() == eModeARM)
Johnny Chen9ee056b2011-02-08 00:06:35 +00002474 target = addr & 0xfffffffc;
Johnny Chenee9b1f72011-02-09 01:00:31 +00002475 else
Johnny Chen9ee056b2011-02-08 00:06:35 +00002476 target = addr & 0xfffffffe;
Johnny Chenee9b1f72011-02-09 01:00:31 +00002477
Johnny Chen9ee056b2011-02-08 00:06:35 +00002478 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, target))
Johnny Chen53ebab72011-02-08 23:21:57 +00002479 return false;
2480
2481 return true;
Johnny Chen9ee056b2011-02-08 00:06:35 +00002482}
2483
2484// As a side effect, BXWritePC sets context.arg2 to eModeARM or eModeThumb by inspecting addr.
2485bool
2486EmulateInstructionARM::BXWritePC (Context &context, uint32_t addr)
2487{
2488 addr_t target;
Johnny Chen0f309db2011-02-09 19:11:32 +00002489 // If the CPSR is changed due to switching between ARM and Thumb ISETSTATE,
2490 // we want to record it and issue a WriteRegister callback so the clients
2491 // can track the mode changes accordingly.
2492 bool cpsr_changed = false;
Johnny Chen9ee056b2011-02-08 00:06:35 +00002493
2494 if (BitIsSet(addr, 0))
2495 {
Johnny Chen0f309db2011-02-09 19:11:32 +00002496 if (CurrentInstrSet() != eModeThumb)
2497 {
2498 SelectInstrSet(eModeThumb);
2499 cpsr_changed = true;
2500 }
Johnny Chen9ee056b2011-02-08 00:06:35 +00002501 target = addr & 0xfffffffe;
2502 context.arg2 = eModeThumb;
2503 }
2504 else if (BitIsClear(addr, 1))
2505 {
Johnny Chen0f309db2011-02-09 19:11:32 +00002506 if (CurrentInstrSet() != eModeARM)
2507 {
2508 SelectInstrSet(eModeARM);
2509 cpsr_changed = true;
2510 }
Johnny Chen9ee056b2011-02-08 00:06:35 +00002511 target = addr & 0xfffffffc;
2512 context.arg2 = eModeARM;
2513 }
2514 else
2515 return false; // address<1:0> == '10' => UNPREDICTABLE
2516
Johnny Chen0f309db2011-02-09 19:11:32 +00002517 if (cpsr_changed)
2518 {
Johnny Chen558133b2011-02-09 23:59:17 +00002519 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
Johnny Chen0f309db2011-02-09 19:11:32 +00002520 return false;
2521 }
Johnny Chen9ee056b2011-02-08 00:06:35 +00002522 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, target))
Johnny Chen53ebab72011-02-08 23:21:57 +00002523 return false;
2524
2525 return true;
Johnny Chen9ee056b2011-02-08 00:06:35 +00002526}
Greg Clayton64c84432011-01-21 22:02:52 +00002527
Johnny Chenee9b1f72011-02-09 01:00:31 +00002528// Dispatches to either BXWritePC or BranchWritePC based on architecture versions.
2529bool
2530EmulateInstructionARM::LoadWritePC (Context &context, uint32_t addr)
2531{
2532 if (ArchVersion() >= ARMv5T)
2533 return BXWritePC(context, addr);
2534 else
2535 return BranchWritePC((const Context)context, addr);
2536}
2537
Johnny Chen26863dc2011-02-09 23:43:29 +00002538// Dispatches to either BXWritePC or BranchWritePC based on architecture versions and current instruction set.
2539bool
2540EmulateInstructionARM::ALUWritePC (Context &context, uint32_t addr)
2541{
2542 if (ArchVersion() >= ARMv7 && CurrentInstrSet() == eModeARM)
2543 return BXWritePC(context, addr);
2544 else
2545 return BranchWritePC((const Context)context, addr);
2546}
2547
Johnny Chenee9b1f72011-02-09 01:00:31 +00002548EmulateInstructionARM::Mode
2549EmulateInstructionARM::CurrentInstrSet ()
2550{
2551 return m_inst_mode;
2552}
2553
2554// Set the 'T' bit of our CPSR. The m_inst_mode gets updated when the next
Johnny Chen558133b2011-02-09 23:59:17 +00002555// ReadInstruction() is performed. This function has a side effect of updating
2556// the m_new_inst_cpsr member variable if necessary.
Johnny Chenee9b1f72011-02-09 01:00:31 +00002557bool
2558EmulateInstructionARM::SelectInstrSet (Mode arm_or_thumb)
2559{
Johnny Chen558133b2011-02-09 23:59:17 +00002560 m_new_inst_cpsr = m_inst_cpsr;
Johnny Chenee9b1f72011-02-09 01:00:31 +00002561 switch (arm_or_thumb)
2562 {
2563 default:
2564 return false;
2565 eModeARM:
2566 // Clear the T bit.
Johnny Chen558133b2011-02-09 23:59:17 +00002567 m_new_inst_cpsr &= ~MASK_CPSR_T;
Johnny Chenee9b1f72011-02-09 01:00:31 +00002568 break;
2569 eModeThumb:
2570 // Set the T bit.
Johnny Chen558133b2011-02-09 23:59:17 +00002571 m_new_inst_cpsr |= MASK_CPSR_T;
Johnny Chenee9b1f72011-02-09 01:00:31 +00002572 break;
2573 }
2574 return true;
2575}
2576
Johnny Chenef21b592011-02-10 01:52:38 +00002577// This function returns TRUE if the processor currently provides support for
2578// unaligned memory accesses, or FALSE otherwise. This is always TRUE in ARMv7,
2579// controllable by the SCTLR.U bit in ARMv6, and always FALSE before ARMv6.
2580bool
2581EmulateInstructionARM::UnalignedSupport()
2582{
2583 return (ArchVersion() >= ARMv7);
2584}
2585
Greg Clayton64c84432011-01-21 22:02:52 +00002586bool
2587EmulateInstructionARM::EvaluateInstruction ()
2588{
Johnny Chenc315f862011-02-05 00:46:10 +00002589 // Advance the ITSTATE bits to their values for the next instruction.
2590 if (m_inst_mode == eModeThumb && m_it_session.InITBlock())
2591 m_it_session.ITAdvance();
2592
Greg Clayton64c84432011-01-21 22:02:52 +00002593 return false;
2594}