blob: 536b08460b952882e9dc6e8f4b5fcc3bb8873bc9 [file] [log] [blame]
Greg Clayton64c84432011-01-21 22:02:52 +00001//===-- EmulateInstructionARM.cpp -------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "EmulateInstructionARM.h"
Greg Clayton8482ded2011-02-01 00:04:43 +000011#include "lldb/Core/ConstString.h"
12
Greg Claytonf29a08f2011-02-09 17:41:27 +000013#include "Plugins/Process/Utility/ARMDefines.h"
14#include "Plugins/Process/Utility/ARMUtils.h"
15#include "Utility/ARM_DWARF_Registers.h"
16
Johnny Chen9b8d7832011-02-02 01:13:56 +000017#include "llvm/Support/MathExtras.h" // for SignExtend32 template function
Johnny Chen93070472011-02-04 23:02:47 +000018 // and CountTrailingZeros_32 function
Greg Clayton64c84432011-01-21 22:02:52 +000019
20using namespace lldb;
21using namespace lldb_private;
22
Johnny Chend6c13f02011-02-08 20:36:34 +000023static inline uint32_t Align(uint32_t val, uint32_t alignment)
24{
25 return alignment * (val / alignment);
26}
27
Johnny Chen0e00af22011-02-10 19:40:42 +000028//----------------------------------------------------------------------
29//
30// ITSession implementation
31//
32//----------------------------------------------------------------------
33
Johnny Chen93070472011-02-04 23:02:47 +000034// A8.6.50
35// Valid return values are {1, 2, 3, 4}, with 0 signifying an error condition.
36static unsigned short CountITSize(unsigned ITMask) {
37 // First count the trailing zeros of the IT mask.
38 unsigned TZ = llvm::CountTrailingZeros_32(ITMask);
39 if (TZ > 3)
40 {
41 printf("Encoding error: IT Mask '0000'\n");
42 return 0;
43 }
44 return (4 - TZ);
45}
46
47// Init ITState. Note that at least one bit is always 1 in mask.
48bool ITSession::InitIT(unsigned short bits7_0)
49{
50 ITCounter = CountITSize(Bits32(bits7_0, 3, 0));
51 if (ITCounter == 0)
52 return false;
53
54 // A8.6.50 IT
55 unsigned short FirstCond = Bits32(bits7_0, 7, 4);
56 if (FirstCond == 0xF)
57 {
58 printf("Encoding error: IT FirstCond '1111'\n");
59 return false;
60 }
61 if (FirstCond == 0xE && ITCounter != 1)
62 {
63 printf("Encoding error: IT FirstCond '1110' && Mask != '1000'\n");
64 return false;
65 }
66
67 ITState = bits7_0;
68 return true;
69}
70
71// Update ITState if necessary.
72void ITSession::ITAdvance()
73{
74 assert(ITCounter);
75 --ITCounter;
76 if (ITCounter == 0)
77 ITState = 0;
78 else
79 {
80 unsigned short NewITState4_0 = Bits32(ITState, 4, 0) << 1;
81 SetBits32(ITState, 4, 0, NewITState4_0);
82 }
83}
84
85// Return true if we're inside an IT Block.
86bool ITSession::InITBlock()
87{
88 return ITCounter != 0;
89}
90
Johnny Chenc315f862011-02-05 00:46:10 +000091// Return true if we're the last instruction inside an IT Block.
92bool ITSession::LastInITBlock()
93{
94 return ITCounter == 1;
95}
96
Johnny Chen93070472011-02-04 23:02:47 +000097// Get condition bits for the current thumb instruction.
98uint32_t ITSession::GetCond()
99{
Johnny Chenc315f862011-02-05 00:46:10 +0000100 if (InITBlock())
101 return Bits32(ITState, 7, 4);
102 else
103 return COND_AL;
Johnny Chen93070472011-02-04 23:02:47 +0000104}
105
Greg Clayton64c84432011-01-21 22:02:52 +0000106// ARM constants used during decoding
107#define REG_RD 0
108#define LDM_REGLIST 1
109#define PC_REG 15
110#define PC_REGLIST_BIT 0x8000
111
Johnny Chen251af6a2011-01-21 22:47:25 +0000112#define ARMv4 (1u << 0)
Greg Clayton64c84432011-01-21 22:02:52 +0000113#define ARMv4T (1u << 1)
114#define ARMv5T (1u << 2)
115#define ARMv5TE (1u << 3)
116#define ARMv5TEJ (1u << 4)
Johnny Chen251af6a2011-01-21 22:47:25 +0000117#define ARMv6 (1u << 5)
Greg Clayton64c84432011-01-21 22:02:52 +0000118#define ARMv6K (1u << 6)
119#define ARMv6T2 (1u << 7)
Johnny Chen251af6a2011-01-21 22:47:25 +0000120#define ARMv7 (1u << 8)
Johnny Chen60c0d622011-01-25 23:49:39 +0000121#define ARMv8 (1u << 9)
Greg Clayton64c84432011-01-21 22:02:52 +0000122#define ARMvAll (0xffffffffu)
123
Johnny Chen9b8d7832011-02-02 01:13:56 +0000124#define ARMV4T_ABOVE (ARMv4T|ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv8)
125#define ARMV5_ABOVE (ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv8)
126#define ARMV6T2_ABOVE (ARMv6T2|ARMv7|ARMv8)
Greg Clayton64c84432011-01-21 22:02:52 +0000127
Johnny Chen0e00af22011-02-10 19:40:42 +0000128//----------------------------------------------------------------------
129//
130// EmulateInstructionARM implementation
131//
132//----------------------------------------------------------------------
133
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000134void
135EmulateInstructionARM::Initialize ()
Johnny Chen7dc60e12011-01-24 19:46:32 +0000136{
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000137}
Johnny Chen7dc60e12011-01-24 19:46:32 +0000138
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000139void
140EmulateInstructionARM::Terminate ()
Greg Clayton64c84432011-01-21 22:02:52 +0000141{
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000142}
143
Johnny Chen08c25e82011-01-31 18:02:28 +0000144// Push Multiple Registers stores multiple registers to the stack, storing to
145// consecutive memory locations ending just below the address in SP, and updates
146// SP to point to the start of the stored data.
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000147bool
148EmulateInstructionARM::EmulatePush (ARMEncoding encoding)
Greg Clayton64c84432011-01-21 22:02:52 +0000149{
150#if 0
151 // ARM pseudo code...
152 if (ConditionPassed())
153 {
154 EncodingSpecificOperations();
155 NullCheckIfThumbEE(13);
156 address = SP - 4*BitCount(registers);
157
158 for (i = 0 to 14)
159 {
160 if (registers<i> == ’1’)
161 {
162 if i == 13 && i != LowestSetBit(registers) // Only possible for encoding A1
163 MemA[address,4] = bits(32) UNKNOWN;
164 else
165 MemA[address,4] = R[i];
166 address = address + 4;
167 }
168 }
169
170 if (registers<15> == ’1’) // Only possible for encoding A1 or A2
171 MemA[address,4] = PCStoreValue();
172
173 SP = SP - 4*BitCount(registers);
174 }
175#endif
176
177 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000178 const uint32_t opcode = OpcodeAsUnsigned (&success);
Greg Clayton64c84432011-01-21 22:02:52 +0000179 if (!success)
180 return false;
181
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000182 if (ConditionPassed())
Greg Clayton64c84432011-01-21 22:02:52 +0000183 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000184 const uint32_t addr_byte_size = GetAddressByteSize();
185 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Greg Clayton64c84432011-01-21 22:02:52 +0000186 if (!success)
187 return false;
Johnny Chen3c75c762011-01-22 00:47:08 +0000188 uint32_t registers = 0;
Johnny Chen91d99862011-01-25 19:07:04 +0000189 uint32_t Rt; // the source register
Johnny Chen3c75c762011-01-22 00:47:08 +0000190 switch (encoding) {
Johnny Chenaedde1c2011-01-24 20:38:45 +0000191 case eEncodingT1:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000192 registers = Bits32(opcode, 7, 0);
Johnny Chenaedde1c2011-01-24 20:38:45 +0000193 // The M bit represents LR.
Johnny Chenbd599902011-02-10 21:39:01 +0000194 if (Bit32(opcode, 8))
Johnny Chenef85e912011-01-31 23:07:40 +0000195 registers |= (1u << 14);
Johnny Chenaedde1c2011-01-24 20:38:45 +0000196 // if BitCount(registers) < 1 then UNPREDICTABLE;
197 if (BitCount(registers) < 1)
198 return false;
199 break;
Johnny Chen7dc60e12011-01-24 19:46:32 +0000200 case eEncodingT2:
201 // Ignore bits 15 & 13.
Johnny Chen108d5aa2011-01-26 01:00:55 +0000202 registers = Bits32(opcode, 15, 0) & ~0xa000;
Johnny Chen7dc60e12011-01-24 19:46:32 +0000203 // if BitCount(registers) < 2 then UNPREDICTABLE;
204 if (BitCount(registers) < 2)
205 return false;
206 break;
207 case eEncodingT3:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000208 Rt = Bits32(opcode, 15, 12);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000209 // if BadReg(t) then UNPREDICTABLE;
Johnny Chen91d99862011-01-25 19:07:04 +0000210 if (BadReg(Rt))
Johnny Chen7dc60e12011-01-24 19:46:32 +0000211 return false;
Johnny Chen91d99862011-01-25 19:07:04 +0000212 registers = (1u << Rt);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000213 break;
Johnny Chen3c75c762011-01-22 00:47:08 +0000214 case eEncodingA1:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000215 registers = Bits32(opcode, 15, 0);
Johnny Chena33d4842011-01-24 22:25:48 +0000216 // Instead of return false, let's handle the following case as well,
217 // which amounts to pushing one reg onto the full descending stacks.
218 // if BitCount(register_list) < 2 then SEE STMDB / STMFD;
Johnny Chen3c75c762011-01-22 00:47:08 +0000219 break;
220 case eEncodingA2:
Johnny Chen108d5aa2011-01-26 01:00:55 +0000221 Rt = Bits32(opcode, 15, 12);
Johnny Chen7dc60e12011-01-24 19:46:32 +0000222 // if t == 13 then UNPREDICTABLE;
Johnny Chen91d99862011-01-25 19:07:04 +0000223 if (Rt == dwarf_sp)
Johnny Chen3c75c762011-01-22 00:47:08 +0000224 return false;
Johnny Chen91d99862011-01-25 19:07:04 +0000225 registers = (1u << Rt);
Johnny Chen3c75c762011-01-22 00:47:08 +0000226 break;
Johnny Chence1ca772011-01-25 01:13:00 +0000227 default:
228 return false;
Johnny Chen3c75c762011-01-22 00:47:08 +0000229 }
Johnny Chence1ca772011-01-25 01:13:00 +0000230 addr_t sp_offset = addr_byte_size * BitCount (registers);
Greg Clayton64c84432011-01-21 22:02:52 +0000231 addr_t addr = sp - sp_offset;
232 uint32_t i;
233
234 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
235 for (i=0; i<15; ++i)
236 {
Johnny Chen7c1bf922011-02-08 23:49:37 +0000237 if (BitIsSet (registers, i))
Greg Clayton64c84432011-01-21 22:02:52 +0000238 {
239 context.arg1 = dwarf_r0 + i; // arg1 in the context is the DWARF register number
240 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000241 uint32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
Greg Clayton64c84432011-01-21 22:02:52 +0000242 if (!success)
243 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000244 if (!WriteMemoryUnsigned (context, addr, reg_value, addr_byte_size))
Greg Clayton64c84432011-01-21 22:02:52 +0000245 return false;
246 addr += addr_byte_size;
247 }
248 }
249
Johnny Chen7c1bf922011-02-08 23:49:37 +0000250 if (BitIsSet (registers, 15))
Greg Clayton64c84432011-01-21 22:02:52 +0000251 {
252 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
Johnny Chen3c75c762011-01-22 00:47:08 +0000253 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000254 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Greg Clayton64c84432011-01-21 22:02:52 +0000255 if (!success)
256 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000257 if (!WriteMemoryUnsigned (context, addr, pc + 8, addr_byte_size))
Greg Clayton64c84432011-01-21 22:02:52 +0000258 return false;
259 }
260
261 context.type = EmulateInstruction::eContextAdjustStackPointer;
262 context.arg0 = eRegisterKindGeneric;
263 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +0000264 context.arg2 = -sp_offset;
Greg Clayton64c84432011-01-21 22:02:52 +0000265
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000266 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
Greg Clayton64c84432011-01-21 22:02:52 +0000267 return false;
268 }
269 return true;
270}
271
Johnny Chenef85e912011-01-31 23:07:40 +0000272// Pop Multiple Registers loads multiple registers from the stack, loading from
273// consecutive memory locations staring at the address in SP, and updates
274// SP to point just above the loaded data.
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000275bool
276EmulateInstructionARM::EmulatePop (ARMEncoding encoding)
Johnny Chenef85e912011-01-31 23:07:40 +0000277{
278#if 0
279 // ARM pseudo code...
280 if (ConditionPassed())
281 {
282 EncodingSpecificOperations(); NullCheckIfThumbEE(13);
283 address = SP;
284 for i = 0 to 14
285 if registers<i> == ‘1’ then
286 R[i} = if UnalignedAllowed then MemU[address,4] else MemA[address,4]; address = address + 4;
287 if registers<15> == ‘1’ then
288 if UnalignedAllowed then
289 LoadWritePC(MemU[address,4]);
290 else
291 LoadWritePC(MemA[address,4]);
292 if registers<13> == ‘0’ then SP = SP + 4*BitCount(registers);
293 if registers<13> == ‘1’ then SP = bits(32) UNKNOWN;
294 }
295#endif
296
297 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000298 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chenef85e912011-01-31 23:07:40 +0000299 if (!success)
300 return false;
301
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000302 if (ConditionPassed())
Johnny Chenef85e912011-01-31 23:07:40 +0000303 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000304 const uint32_t addr_byte_size = GetAddressByteSize();
305 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chenef85e912011-01-31 23:07:40 +0000306 if (!success)
307 return false;
308 uint32_t registers = 0;
309 uint32_t Rt; // the destination register
310 switch (encoding) {
311 case eEncodingT1:
312 registers = Bits32(opcode, 7, 0);
313 // The P bit represents PC.
Johnny Chenbd599902011-02-10 21:39:01 +0000314 if (Bit32(opcode, 8))
Johnny Chenef85e912011-01-31 23:07:40 +0000315 registers |= (1u << 15);
316 // if BitCount(registers) < 1 then UNPREDICTABLE;
317 if (BitCount(registers) < 1)
318 return false;
319 break;
320 case eEncodingT2:
321 // Ignore bit 13.
322 registers = Bits32(opcode, 15, 0) & ~0x2000;
323 // if BitCount(registers) < 2 || (P == '1' && M == '1') then UNPREDICTABLE;
Johnny Chenbd599902011-02-10 21:39:01 +0000324 if (BitCount(registers) < 2 || (Bit32(opcode, 15) && Bit32(opcode, 14)))
Johnny Chenef85e912011-01-31 23:07:40 +0000325 return false;
326 break;
327 case eEncodingT3:
328 Rt = Bits32(opcode, 15, 12);
329 // if t == 13 || (t == 15 && InITBlock() && !LastInITBlock()) then UNPREDICTABLE;
330 if (Rt == dwarf_sp)
331 return false;
332 registers = (1u << Rt);
333 break;
334 case eEncodingA1:
335 registers = Bits32(opcode, 15, 0);
336 // Instead of return false, let's handle the following case as well,
337 // which amounts to popping one reg from the full descending stacks.
338 // if BitCount(register_list) < 2 then SEE LDM / LDMIA / LDMFD;
339
340 // if registers<13> == ‘1’ && ArchVersion() >= 7 then UNPREDICTABLE;
Johnny Chenbd599902011-02-10 21:39:01 +0000341 if (Bit32(opcode, 13) && ArchVersion() >= ARMv7)
Johnny Chenef85e912011-01-31 23:07:40 +0000342 return false;
343 break;
344 case eEncodingA2:
345 Rt = Bits32(opcode, 15, 12);
346 // if t == 13 then UNPREDICTABLE;
347 if (Rt == dwarf_sp)
348 return false;
349 registers = (1u << Rt);
350 break;
351 default:
352 return false;
353 }
354 addr_t sp_offset = addr_byte_size * BitCount (registers);
355 addr_t addr = sp;
356 uint32_t i, data;
357
358 EmulateInstruction::Context context = { EmulateInstruction::eContextPopRegisterOffStack, eRegisterKindDWARF, 0, 0 };
359 for (i=0; i<15; ++i)
360 {
Johnny Chen7c1bf922011-02-08 23:49:37 +0000361 if (BitIsSet (registers, i))
Johnny Chenef85e912011-01-31 23:07:40 +0000362 {
363 context.arg1 = dwarf_r0 + i; // arg1 in the context is the DWARF register number
364 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000365 data = ReadMemoryUnsigned(context, addr, 4, 0, &success);
Johnny Chenef85e912011-01-31 23:07:40 +0000366 if (!success)
367 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000368 if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, context.arg1, data))
Johnny Chenef85e912011-01-31 23:07:40 +0000369 return false;
370 addr += addr_byte_size;
371 }
372 }
373
Johnny Chen7c1bf922011-02-08 23:49:37 +0000374 if (BitIsSet (registers, 15))
Johnny Chenef85e912011-01-31 23:07:40 +0000375 {
376 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
377 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000378 data = ReadMemoryUnsigned(context, addr, 4, 0, &success);
Johnny Chenef85e912011-01-31 23:07:40 +0000379 if (!success)
380 return false;
Johnny Chenf3eaacf2011-02-09 19:30:49 +0000381 // In ARMv5T and above, this is an interworking branch.
382 if (!LoadWritePC(context, data))
Johnny Chenef85e912011-01-31 23:07:40 +0000383 return false;
384 addr += addr_byte_size;
385 }
386
387 context.type = EmulateInstruction::eContextAdjustStackPointer;
388 context.arg0 = eRegisterKindGeneric;
389 context.arg1 = LLDB_REGNUM_GENERIC_SP;
390 context.arg2 = sp_offset;
391
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000392 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp + sp_offset))
Johnny Chenef85e912011-01-31 23:07:40 +0000393 return false;
394 }
395 return true;
396}
397
Johnny Chen5b442b72011-01-27 19:34:30 +0000398// Set r7 or ip to point to saved value residing within the stack.
Johnny Chenbcec3af2011-01-27 01:26:19 +0000399// ADD (SP plus immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000400bool
401EmulateInstructionARM::EmulateAddRdSPImmediate (ARMEncoding encoding)
Johnny Chenbcec3af2011-01-27 01:26:19 +0000402{
403#if 0
404 // ARM pseudo code...
405 if (ConditionPassed())
406 {
407 EncodingSpecificOperations();
408 (result, carry, overflow) = AddWithCarry(SP, imm32, ‘0’);
409 if d == 15 then
410 ALUWritePC(result); // setflags is always FALSE here
411 else
412 R[d] = result;
413 if setflags then
414 APSR.N = result<31>;
415 APSR.Z = IsZeroBit(result);
416 APSR.C = carry;
417 APSR.V = overflow;
418 }
419#endif
420
421 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000422 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chenbcec3af2011-01-27 01:26:19 +0000423 if (!success)
424 return false;
425
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000426 if (ConditionPassed())
Johnny Chenbcec3af2011-01-27 01:26:19 +0000427 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000428 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chenbcec3af2011-01-27 01:26:19 +0000429 if (!success)
430 return false;
431 uint32_t Rd; // the destination register
432 uint32_t imm32;
433 switch (encoding) {
434 case eEncodingT1:
435 Rd = 7;
436 imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32)
437 break;
438 case eEncodingA1:
439 Rd = Bits32(opcode, 15, 12);
440 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
441 break;
442 default:
443 return false;
444 }
445 addr_t sp_offset = imm32;
446 addr_t addr = sp + sp_offset; // a pointer to the stack area
447
448 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
449 eRegisterKindGeneric,
450 LLDB_REGNUM_GENERIC_SP,
451 sp_offset };
452
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000453 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, addr))
Johnny Chenbcec3af2011-01-27 01:26:19 +0000454 return false;
455 }
456 return true;
457}
458
Johnny Chen2ccad832011-01-28 19:57:25 +0000459// Set r7 or ip to the current stack pointer.
460// MOV (register)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000461bool
462EmulateInstructionARM::EmulateMovRdSP (ARMEncoding encoding)
Johnny Chen2ccad832011-01-28 19:57:25 +0000463{
464#if 0
465 // ARM pseudo code...
466 if (ConditionPassed())
467 {
468 EncodingSpecificOperations();
469 result = R[m];
470 if d == 15 then
471 ALUWritePC(result); // setflags is always FALSE here
472 else
473 R[d] = result;
474 if setflags then
475 APSR.N = result<31>;
476 APSR.Z = IsZeroBit(result);
477 // APSR.C unchanged
478 // APSR.V unchanged
479 }
480#endif
481
482 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000483 //const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen1c13b622011-01-29 00:11:15 +0000484 //if (!success)
485 // return false;
Johnny Chen2ccad832011-01-28 19:57:25 +0000486
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000487 if (ConditionPassed())
Johnny Chen2ccad832011-01-28 19:57:25 +0000488 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000489 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen2ccad832011-01-28 19:57:25 +0000490 if (!success)
491 return false;
492 uint32_t Rd; // the destination register
493 switch (encoding) {
494 case eEncodingT1:
495 Rd = 7;
496 break;
497 case eEncodingA1:
498 Rd = 12;
499 break;
500 default:
501 return false;
502 }
503 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
504 eRegisterKindGeneric,
505 LLDB_REGNUM_GENERIC_SP,
506 0 };
507
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000508 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, sp))
Johnny Chen2ccad832011-01-28 19:57:25 +0000509 return false;
510 }
511 return true;
512}
513
Johnny Chen1c13b622011-01-29 00:11:15 +0000514// Move from high register (r8-r15) to low register (r0-r7).
515// MOV (register)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000516bool
517EmulateInstructionARM::EmulateMovLowHigh (ARMEncoding encoding)
Johnny Chen1c13b622011-01-29 00:11:15 +0000518{
Johnny Chen338bf542011-02-10 19:29:03 +0000519 return EmulateMovRdRm (encoding);
520}
521
522// Move from register to register.
523// MOV (register)
524bool
525EmulateInstructionARM::EmulateMovRdRm (ARMEncoding encoding)
526{
Johnny Chen1c13b622011-01-29 00:11:15 +0000527#if 0
528 // ARM pseudo code...
529 if (ConditionPassed())
530 {
531 EncodingSpecificOperations();
532 result = R[m];
533 if d == 15 then
534 ALUWritePC(result); // setflags is always FALSE here
535 else
536 R[d] = result;
537 if setflags then
538 APSR.N = result<31>;
539 APSR.Z = IsZeroBit(result);
540 // APSR.C unchanged
541 // APSR.V unchanged
542 }
543#endif
544
545 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000546 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen1c13b622011-01-29 00:11:15 +0000547 if (!success)
548 return false;
549
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000550 if (ConditionPassed())
Johnny Chen1c13b622011-01-29 00:11:15 +0000551 {
552 uint32_t Rm; // the source register
553 uint32_t Rd; // the destination register
Johnny Chen338bf542011-02-10 19:29:03 +0000554 bool setflags;
Johnny Chen1c13b622011-01-29 00:11:15 +0000555 switch (encoding) {
556 case eEncodingT1:
557 Rm = Bits32(opcode, 6, 3);
Johnny Chenbd599902011-02-10 21:39:01 +0000558 Rd = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 1);
Johnny Chen338bf542011-02-10 19:29:03 +0000559 setflags = false;
560 break;
561 case eEncodingT2:
562 Rm = Bits32(opcode, 5, 3);
563 Rd = Bits32(opcode, 2, 1);
564 setflags = true;
Johnny Chen1c13b622011-01-29 00:11:15 +0000565 break;
566 default:
567 return false;
568 }
Johnny Chen338bf542011-02-10 19:29:03 +0000569 uint32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
Johnny Chen1c13b622011-01-29 00:11:15 +0000570 if (!success)
571 return false;
572
573 // The context specifies that Rm is to be moved into Rd.
574 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
575 eRegisterKindDWARF,
576 dwarf_r0 + Rm,
577 0 };
578
Johnny Chen338bf542011-02-10 19:29:03 +0000579 if (Rd == 15)
580 {
581 if (!ALUWritePC (context, reg_value))
582 return false;
583 }
584 else
585 {
586 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, reg_value))
587 return false;
588 if (setflags)
589 {
590 m_new_inst_cpsr = m_inst_cpsr;
Johnny Chenbd599902011-02-10 21:39:01 +0000591 SetBit32(m_new_inst_cpsr, CPSR_N, Bit32(reg_value, CPSR_N));
592 SetBit32(m_new_inst_cpsr, CPSR_Z, reg_value == 0 ? 1 : 0);
Johnny Chen338bf542011-02-10 19:29:03 +0000593 if (m_new_inst_cpsr != m_inst_cpsr)
594 {
595 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
596 return false;
597 }
598 }
599 }
Johnny Chen1c13b622011-01-29 00:11:15 +0000600 }
601 return true;
602}
603
Johnny Chen788e0552011-01-27 22:52:23 +0000604// PC relative immediate load into register, possibly followed by ADD (SP plus register).
605// LDR (literal)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000606bool
607EmulateInstructionARM::EmulateLDRRdPCRelative (ARMEncoding encoding)
Johnny Chen788e0552011-01-27 22:52:23 +0000608{
609#if 0
610 // ARM pseudo code...
611 if (ConditionPassed())
612 {
613 EncodingSpecificOperations(); NullCheckIfThumbEE(15);
614 base = Align(PC,4);
615 address = if add then (base + imm32) else (base - imm32);
616 data = MemU[address,4];
617 if t == 15 then
618 if address<1:0> == ‘00’ then LoadWritePC(data); else UNPREDICTABLE;
619 elsif UnalignedSupport() || address<1:0> = ‘00’ then
620 R[t] = data;
621 else // Can only apply before ARMv7
622 if CurrentInstrSet() == InstrSet_ARM then
623 R[t] = ROR(data, 8*UInt(address<1:0>));
624 else
625 R[t] = bits(32) UNKNOWN;
626 }
627#endif
628
629 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000630 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen788e0552011-01-27 22:52:23 +0000631 if (!success)
632 return false;
633
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000634 if (ConditionPassed())
Johnny Chen788e0552011-01-27 22:52:23 +0000635 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000636 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Johnny Chen788e0552011-01-27 22:52:23 +0000637 if (!success)
638 return false;
Johnny Chen809742e2011-01-28 00:32:27 +0000639
640 // PC relative immediate load context
641 EmulateInstruction::Context context = {EmulateInstruction::eContextRegisterPlusOffset,
642 eRegisterKindGeneric,
643 LLDB_REGNUM_GENERIC_PC,
644 0};
Johnny Chen788e0552011-01-27 22:52:23 +0000645 uint32_t Rd; // the destination register
646 uint32_t imm32; // immediate offset from the PC
647 addr_t addr; // the PC relative address
648 uint32_t data; // the literal data value from the PC relative load
649 switch (encoding) {
650 case eEncodingT1:
651 Rd = Bits32(opcode, 10, 8);
652 imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32);
653 addr = pc + 4 + imm32;
Johnny Chen809742e2011-01-28 00:32:27 +0000654 context.arg2 = 4 + imm32;
Johnny Chen788e0552011-01-27 22:52:23 +0000655 break;
656 default:
657 return false;
658 }
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000659 data = ReadMemoryUnsigned(context, addr, 4, 0, &success);
Johnny Chen788e0552011-01-27 22:52:23 +0000660 if (!success)
Johnny Chen809742e2011-01-28 00:32:27 +0000661 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000662 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, data))
Johnny Chen788e0552011-01-27 22:52:23 +0000663 return false;
664 }
665 return true;
666}
667
Johnny Chen5b442b72011-01-27 19:34:30 +0000668// An add operation to adjust the SP.
Johnny Chenfdd179e2011-01-31 20:09:28 +0000669// ADD (SP plus immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000670bool
671EmulateInstructionARM::EmulateAddSPImmediate (ARMEncoding encoding)
Johnny Chenfdd179e2011-01-31 20:09:28 +0000672{
673#if 0
674 // ARM pseudo code...
675 if (ConditionPassed())
676 {
677 EncodingSpecificOperations();
678 (result, carry, overflow) = AddWithCarry(SP, imm32, ‘0’);
679 if d == 15 then // Can only occur for ARM encoding
680 ALUWritePC(result); // setflags is always FALSE here
681 else
682 R[d] = result;
683 if setflags then
684 APSR.N = result<31>;
685 APSR.Z = IsZeroBit(result);
686 APSR.C = carry;
687 APSR.V = overflow;
688 }
689#endif
690
691 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000692 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chenfdd179e2011-01-31 20:09:28 +0000693 if (!success)
694 return false;
695
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000696 if (ConditionPassed())
Johnny Chenfdd179e2011-01-31 20:09:28 +0000697 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000698 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chenfdd179e2011-01-31 20:09:28 +0000699 if (!success)
700 return false;
701 uint32_t imm32; // the immediate operand
702 switch (encoding) {
703 case eEncodingT2:
704 imm32 = ThumbImmScaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
705 break;
706 default:
707 return false;
708 }
709 addr_t sp_offset = imm32;
710 addr_t addr = sp + sp_offset; // the adjusted stack pointer value
711
712 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
713 eRegisterKindGeneric,
714 LLDB_REGNUM_GENERIC_SP,
715 sp_offset };
716
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000717 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
Johnny Chenfdd179e2011-01-31 20:09:28 +0000718 return false;
719 }
720 return true;
721}
722
723// An add operation to adjust the SP.
Johnny Chen5b442b72011-01-27 19:34:30 +0000724// ADD (SP plus register)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000725bool
726EmulateInstructionARM::EmulateAddSPRm (ARMEncoding encoding)
Johnny Chen5b442b72011-01-27 19:34:30 +0000727{
728#if 0
729 // ARM pseudo code...
730 if (ConditionPassed())
731 {
732 EncodingSpecificOperations();
733 shifted = Shift(R[m], shift_t, shift_n, APSR.C);
734 (result, carry, overflow) = AddWithCarry(SP, shifted, ‘0’);
735 if d == 15 then
736 ALUWritePC(result); // setflags is always FALSE here
737 else
738 R[d] = result;
739 if setflags then
740 APSR.N = result<31>;
741 APSR.Z = IsZeroBit(result);
742 APSR.C = carry;
743 APSR.V = overflow;
744 }
745#endif
746
747 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000748 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen5b442b72011-01-27 19:34:30 +0000749 if (!success)
750 return false;
751
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000752 if (ConditionPassed())
Johnny Chen5b442b72011-01-27 19:34:30 +0000753 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000754 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen5b442b72011-01-27 19:34:30 +0000755 if (!success)
756 return false;
757 uint32_t Rm; // the second operand
758 switch (encoding) {
759 case eEncodingT2:
760 Rm = Bits32(opcode, 6, 3);
761 break;
762 default:
763 return false;
764 }
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000765 int32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
Johnny Chen5b442b72011-01-27 19:34:30 +0000766 if (!success)
767 return false;
768
769 addr_t addr = (int32_t)sp + reg_value; // the adjusted stack pointer value
770
771 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
772 eRegisterKindGeneric,
773 LLDB_REGNUM_GENERIC_SP,
774 reg_value };
775
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000776 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
Johnny Chen5b442b72011-01-27 19:34:30 +0000777 return false;
778 }
779 return true;
780}
781
Johnny Chen9b8d7832011-02-02 01:13:56 +0000782// Branch with Link and Exchange Instruction Sets (immediate) calls a subroutine
783// at a PC-relative address, and changes instruction set from ARM to Thumb, or
784// from Thumb to ARM.
785// BLX (immediate)
786bool
787EmulateInstructionARM::EmulateBLXImmediate (ARMEncoding encoding)
788{
789#if 0
790 // ARM pseudo code...
791 if (ConditionPassed())
792 {
793 EncodingSpecificOperations();
794 if CurrentInstrSet() == InstrSet_ARM then
795 LR = PC - 4;
796 else
797 LR = PC<31:1> : '1';
798 if targetInstrSet == InstrSet_ARM then
799 targetAddress = Align(PC,4) + imm32;
800 else
801 targetAddress = PC + imm32;
802 SelectInstrSet(targetInstrSet);
803 BranchWritePC(targetAddress);
804 }
805#endif
806
807 bool success = false;
808 const uint32_t opcode = OpcodeAsUnsigned (&success);
809 if (!success)
810 return false;
811
812 if (ConditionPassed())
813 {
814 EmulateInstruction::Context context = { EmulateInstruction::eContextRelativeBranchImmediate, 0, 0, 0};
815 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Johnny Chen9b8d7832011-02-02 01:13:56 +0000816 if (!success)
817 return false;
Johnny Chen53ebab72011-02-08 23:21:57 +0000818 addr_t lr; // next instruction address
819 addr_t target; // target address
Johnny Chen9b8d7832011-02-02 01:13:56 +0000820 int32_t imm32; // PC-relative offset
821 switch (encoding) {
Johnny Chend6c13f02011-02-08 20:36:34 +0000822 case eEncodingT1:
823 {
824 lr = (pc + 4) | 1u; // return address
Johnny Chenbd599902011-02-10 21:39:01 +0000825 uint32_t S = Bit32(opcode, 26);
Johnny Chend6c13f02011-02-08 20:36:34 +0000826 uint32_t imm10 = Bits32(opcode, 25, 16);
Johnny Chenbd599902011-02-10 21:39:01 +0000827 uint32_t J1 = Bit32(opcode, 13);
828 uint32_t J2 = Bit32(opcode, 11);
Johnny Chend6c13f02011-02-08 20:36:34 +0000829 uint32_t imm11 = Bits32(opcode, 10, 0);
830 uint32_t I1 = !(J1 ^ S);
831 uint32_t I2 = !(J2 ^ S);
Johnny Chen53ebab72011-02-08 23:21:57 +0000832 uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
Johnny Chend6c13f02011-02-08 20:36:34 +0000833 imm32 = llvm::SignExtend32<25>(imm25);
834 target = pc + 4 + imm32;
835 context.arg1 = 4 + imm32; // signed offset
836 context.arg2 = eModeThumb; // target instruction set
837 break;
838 }
Johnny Chen9b8d7832011-02-02 01:13:56 +0000839 case eEncodingT2:
840 {
841 lr = (pc + 4) | 1u; // return address
Johnny Chenbd599902011-02-10 21:39:01 +0000842 uint32_t S = Bit32(opcode, 26);
Johnny Chen9b8d7832011-02-02 01:13:56 +0000843 uint32_t imm10H = Bits32(opcode, 25, 16);
Johnny Chenbd599902011-02-10 21:39:01 +0000844 uint32_t J1 = Bit32(opcode, 13);
845 uint32_t J2 = Bit32(opcode, 11);
Johnny Chen9b8d7832011-02-02 01:13:56 +0000846 uint32_t imm10L = Bits32(opcode, 10, 1);
847 uint32_t I1 = !(J1 ^ S);
848 uint32_t I2 = !(J2 ^ S);
Johnny Chen53ebab72011-02-08 23:21:57 +0000849 uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10H << 12) | (imm10L << 2);
Johnny Chen9b8d7832011-02-02 01:13:56 +0000850 imm32 = llvm::SignExtend32<25>(imm25);
Johnny Chend6c13f02011-02-08 20:36:34 +0000851 target = Align(pc + 4, 4) + imm32;
852 context.arg1 = 4 + imm32; // signed offset
853 context.arg2 = eModeARM; // target instruction set
Johnny Chen9b8d7832011-02-02 01:13:56 +0000854 break;
855 }
Johnny Chenc47d0ca2011-02-08 18:58:31 +0000856 case eEncodingA1:
857 lr = pc + 4; // return address
858 imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2);
Johnny Chend6c13f02011-02-08 20:36:34 +0000859 target = Align(pc + 8, 4) + imm32;
860 context.arg1 = 8 + imm32; // signed offset
861 context.arg2 = eModeARM; // target instruction set
Johnny Chenc47d0ca2011-02-08 18:58:31 +0000862 break;
Johnny Chen9b8d7832011-02-02 01:13:56 +0000863 case eEncodingA2:
864 lr = pc + 4; // return address
865 imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2 | Bits32(opcode, 24, 24) << 1);
866 target = pc + 8 + imm32;
Johnny Chen9ee056b2011-02-08 00:06:35 +0000867 context.arg1 = 8 + imm32; // signed offset
868 context.arg2 = eModeThumb; // target instruction set
Johnny Chen9b8d7832011-02-02 01:13:56 +0000869 break;
870 default:
871 return false;
872 }
873 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
874 return false;
Johnny Chen9ee056b2011-02-08 00:06:35 +0000875 if (!BranchWritePC(context, target))
Johnny Chen9b8d7832011-02-02 01:13:56 +0000876 return false;
877 }
878 return true;
879}
880
881// Branch with Link and Exchange (register) calls a subroutine at an address and
882// instruction set specified by a register.
883// BLX (register)
884bool
885EmulateInstructionARM::EmulateBLXRm (ARMEncoding encoding)
886{
887#if 0
888 // ARM pseudo code...
889 if (ConditionPassed())
890 {
891 EncodingSpecificOperations();
892 target = R[m];
893 if CurrentInstrSet() == InstrSet_ARM then
894 next_instr_addr = PC - 4;
895 LR = next_instr_addr;
896 else
897 next_instr_addr = PC - 2;
898 LR = next_instr_addr<31:1> : ‘1’;
899 BXWritePC(target);
900 }
901#endif
902
903 bool success = false;
904 const uint32_t opcode = OpcodeAsUnsigned (&success);
905 if (!success)
906 return false;
907
908 if (ConditionPassed())
909 {
910 EmulateInstruction::Context context = { EmulateInstruction::eContextAbsoluteBranchRegister, 0, 0, 0};
911 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
912 addr_t lr; // next instruction address
913 addr_t target; // target address
914 if (!success)
915 return false;
916 uint32_t Rm; // the register with the target address
917 switch (encoding) {
918 case eEncodingT1:
919 lr = (pc + 2) | 1u; // return address
920 Rm = Bits32(opcode, 6, 3);
921 // if m == 15 then UNPREDICTABLE;
922 if (Rm == 15)
923 return false;
924 target = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
925 break;
926 case eEncodingA1:
927 lr = pc + 4; // return address
928 Rm = Bits32(opcode, 3, 0);
929 // if m == 15 then UNPREDICTABLE;
930 if (Rm == 15)
931 return false;
932 target = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
Johnny Chenb77be412011-02-04 00:40:18 +0000933 break;
Johnny Chen9b8d7832011-02-02 01:13:56 +0000934 default:
935 return false;
936 }
Johnny Chen9b8d7832011-02-02 01:13:56 +0000937 context.arg0 = eRegisterKindDWARF;
938 context.arg1 = dwarf_r0 + Rm;
Johnny Chen9b8d7832011-02-02 01:13:56 +0000939 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
940 return false;
Johnny Chen9ee056b2011-02-08 00:06:35 +0000941 if (!BXWritePC(context, target))
Johnny Chen9b8d7832011-02-02 01:13:56 +0000942 return false;
943 }
944 return true;
945}
946
Johnny Chen0d0148e2011-01-28 02:26:08 +0000947// Set r7 to point to some ip offset.
948// SUB (immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000949bool
950EmulateInstructionARM::EmulateSubR7IPImmediate (ARMEncoding encoding)
Johnny Chen0d0148e2011-01-28 02:26:08 +0000951{
952#if 0
953 // ARM pseudo code...
954 if (ConditionPassed())
955 {
956 EncodingSpecificOperations();
957 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), ‘1’);
958 if d == 15 then // Can only occur for ARM encoding
959 ALUWritePC(result); // setflags is always FALSE here
960 else
961 R[d] = result;
962 if setflags then
963 APSR.N = result<31>;
964 APSR.Z = IsZeroBit(result);
965 APSR.C = carry;
966 APSR.V = overflow;
967 }
968#endif
969
970 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000971 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen0d0148e2011-01-28 02:26:08 +0000972 if (!success)
973 return false;
974
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000975 if (ConditionPassed())
Johnny Chen0d0148e2011-01-28 02:26:08 +0000976 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000977 const addr_t ip = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r12, 0, &success);
Johnny Chen0d0148e2011-01-28 02:26:08 +0000978 if (!success)
979 return false;
980 uint32_t imm32;
981 switch (encoding) {
982 case eEncodingA1:
983 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
984 break;
985 default:
986 return false;
987 }
988 addr_t ip_offset = imm32;
989 addr_t addr = ip - ip_offset; // the adjusted ip value
990
991 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
992 eRegisterKindDWARF,
993 dwarf_r12,
994 -ip_offset };
995
Greg Clayton2b8e8b02011-02-01 00:49:32 +0000996 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r7, addr))
Johnny Chen0d0148e2011-01-28 02:26:08 +0000997 return false;
998 }
999 return true;
1000}
1001
1002// Set ip to point to some stack offset.
1003// SUB (SP minus immediate)
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001004bool
1005EmulateInstructionARM::EmulateSubIPSPImmediate (ARMEncoding encoding)
Johnny Chen0d0148e2011-01-28 02:26:08 +00001006{
1007#if 0
1008 // ARM pseudo code...
1009 if (ConditionPassed())
1010 {
1011 EncodingSpecificOperations();
1012 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), ‘1’);
1013 if d == 15 then // Can only occur for ARM encoding
1014 ALUWritePC(result); // setflags is always FALSE here
1015 else
1016 R[d] = result;
1017 if setflags then
1018 APSR.N = result<31>;
1019 APSR.Z = IsZeroBit(result);
1020 APSR.C = carry;
1021 APSR.V = overflow;
1022 }
1023#endif
1024
1025 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001026 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen0d0148e2011-01-28 02:26:08 +00001027 if (!success)
1028 return false;
1029
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001030 if (ConditionPassed())
Johnny Chen0d0148e2011-01-28 02:26:08 +00001031 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001032 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen0d0148e2011-01-28 02:26:08 +00001033 if (!success)
1034 return false;
1035 uint32_t imm32;
1036 switch (encoding) {
1037 case eEncodingA1:
1038 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
1039 break;
1040 default:
1041 return false;
1042 }
1043 addr_t sp_offset = imm32;
1044 addr_t addr = sp - sp_offset; // the adjusted stack pointer value
1045
1046 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
1047 eRegisterKindGeneric,
1048 LLDB_REGNUM_GENERIC_SP,
1049 -sp_offset };
1050
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001051 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r12, addr))
Johnny Chen0d0148e2011-01-28 02:26:08 +00001052 return false;
1053 }
1054 return true;
1055}
1056
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001057// A sub operation to adjust the SP -- allocate space for local storage.
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001058bool
1059EmulateInstructionARM::EmulateSubSPImmdiate (ARMEncoding encoding)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001060{
1061#if 0
1062 // ARM pseudo code...
1063 if (ConditionPassed())
1064 {
1065 EncodingSpecificOperations();
1066 (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), ‘1’);
1067 if d == 15 then // Can only occur for ARM encoding
Johnny Chen799dfd02011-01-26 23:14:33 +00001068 ALUWritePC(result); // setflags is always FALSE here
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001069 else
1070 R[d] = result;
1071 if setflags then
1072 APSR.N = result<31>;
1073 APSR.Z = IsZeroBit(result);
1074 APSR.C = carry;
1075 APSR.V = overflow;
1076 }
1077#endif
1078
1079 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001080 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001081 if (!success)
1082 return false;
1083
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001084 if (ConditionPassed())
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001085 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001086 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001087 if (!success)
1088 return false;
1089 uint32_t imm32;
1090 switch (encoding) {
Johnny Chene4455022011-01-26 00:08:59 +00001091 case eEncodingT1:
1092 imm32 = ThumbImmScaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
Johnny Chen60c0d622011-01-25 23:49:39 +00001093 case eEncodingT2:
1094 imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
1095 break;
1096 case eEncodingT3:
1097 imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32)
1098 break;
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001099 case eEncodingA1:
Johnny Chen60c0d622011-01-25 23:49:39 +00001100 imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001101 break;
1102 default:
1103 return false;
1104 }
1105 addr_t sp_offset = imm32;
1106 addr_t addr = sp - sp_offset; // the adjusted stack pointer value
1107
1108 EmulateInstruction::Context context = { EmulateInstruction::eContextAdjustStackPointer,
1109 eRegisterKindGeneric,
1110 LLDB_REGNUM_GENERIC_SP,
Johnny Chen5b442b72011-01-27 19:34:30 +00001111 -sp_offset };
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001112
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001113 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00001114 return false;
1115 }
1116 return true;
1117}
1118
Johnny Chen08c25e82011-01-31 18:02:28 +00001119// A store operation to the stack that also updates the SP.
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001120bool
1121EmulateInstructionARM::EmulateSTRRtSP (ARMEncoding encoding)
Johnny Chence1ca772011-01-25 01:13:00 +00001122{
1123#if 0
1124 // ARM pseudo code...
1125 if (ConditionPassed())
1126 {
1127 EncodingSpecificOperations();
1128 offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
1129 address = if index then offset_addr else R[n];
1130 MemU[address,4] = if t == 15 then PCStoreValue() else R[t];
1131 if wback then R[n] = offset_addr;
1132 }
1133#endif
1134
1135 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001136 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chence1ca772011-01-25 01:13:00 +00001137 if (!success)
1138 return false;
1139
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001140 if (ConditionPassed())
Johnny Chence1ca772011-01-25 01:13:00 +00001141 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001142 const uint32_t addr_byte_size = GetAddressByteSize();
1143 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chence1ca772011-01-25 01:13:00 +00001144 if (!success)
1145 return false;
Johnny Chen91d99862011-01-25 19:07:04 +00001146 uint32_t Rt; // the source register
Johnny Chence1ca772011-01-25 01:13:00 +00001147 uint32_t imm12;
1148 switch (encoding) {
1149 case eEncodingA1:
Johnny Chen108d5aa2011-01-26 01:00:55 +00001150 Rt = Bits32(opcode, 15, 12);
1151 imm12 = Bits32(opcode, 11, 0);
Johnny Chence1ca772011-01-25 01:13:00 +00001152 break;
1153 default:
1154 return false;
1155 }
1156 addr_t sp_offset = imm12;
1157 addr_t addr = sp - sp_offset;
1158
1159 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
Johnny Chen91d99862011-01-25 19:07:04 +00001160 if (Rt != 15)
Johnny Chence1ca772011-01-25 01:13:00 +00001161 {
Johnny Chen91d99862011-01-25 19:07:04 +00001162 context.arg1 = dwarf_r0 + Rt; // arg1 in the context is the DWARF register number
1163 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001164 uint32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
Johnny Chence1ca772011-01-25 01:13:00 +00001165 if (!success)
1166 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001167 if (!WriteMemoryUnsigned (context, addr, reg_value, addr_byte_size))
Johnny Chence1ca772011-01-25 01:13:00 +00001168 return false;
1169 }
1170 else
1171 {
1172 context.arg1 = dwarf_pc; // arg1 in the context is the DWARF register number
1173 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001174 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Johnny Chence1ca772011-01-25 01:13:00 +00001175 if (!success)
1176 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001177 if (!WriteMemoryUnsigned (context, addr, pc + 8, addr_byte_size))
Johnny Chence1ca772011-01-25 01:13:00 +00001178 return false;
1179 }
1180
1181 context.type = EmulateInstruction::eContextAdjustStackPointer;
1182 context.arg0 = eRegisterKindGeneric;
1183 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +00001184 context.arg2 = -sp_offset;
Johnny Chence1ca772011-01-25 01:13:00 +00001185
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001186 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
Johnny Chence1ca772011-01-25 01:13:00 +00001187 return false;
1188 }
1189 return true;
1190}
1191
Johnny Chen08c25e82011-01-31 18:02:28 +00001192// Vector Push stores multiple extension registers to the stack.
1193// It also updates SP to point to the start of the stored data.
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001194bool
1195EmulateInstructionARM::EmulateVPUSH (ARMEncoding encoding)
Johnny Chen799dfd02011-01-26 23:14:33 +00001196{
1197#if 0
1198 // ARM pseudo code...
1199 if (ConditionPassed())
1200 {
1201 EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13);
1202 address = SP - imm32;
1203 SP = SP - imm32;
1204 if single_regs then
1205 for r = 0 to regs-1
1206 MemA[address,4] = S[d+r]; address = address+4;
1207 else
1208 for r = 0 to regs-1
1209 // Store as two word-aligned words in the correct order for current endianness.
1210 MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>;
1211 MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>;
1212 address = address+8;
1213 }
1214#endif
1215
1216 bool success = false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001217 const uint32_t opcode = OpcodeAsUnsigned (&success);
Johnny Chen799dfd02011-01-26 23:14:33 +00001218 if (!success)
1219 return false;
1220
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001221 if (ConditionPassed())
Johnny Chen799dfd02011-01-26 23:14:33 +00001222 {
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001223 const uint32_t addr_byte_size = GetAddressByteSize();
1224 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
Johnny Chen799dfd02011-01-26 23:14:33 +00001225 if (!success)
1226 return false;
1227 bool single_regs;
Johnny Chen587a0a42011-02-01 18:35:28 +00001228 uint32_t d; // UInt(D:Vd) or UInt(Vd:D) starting register
Johnny Chen799dfd02011-01-26 23:14:33 +00001229 uint32_t imm32; // stack offset
1230 uint32_t regs; // number of registers
1231 switch (encoding) {
1232 case eEncodingT1:
1233 case eEncodingA1:
1234 single_regs = false;
Johnny Chenbd599902011-02-10 21:39:01 +00001235 d = Bit32(opcode, 22) << 4 | Bits32(opcode, 15, 12);
Johnny Chen799dfd02011-01-26 23:14:33 +00001236 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1237 // If UInt(imm8) is odd, see "FSTMX".
1238 regs = Bits32(opcode, 7, 0) / 2;
1239 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1240 if (regs == 0 || regs > 16 || (d + regs) > 32)
1241 return false;
1242 break;
1243 case eEncodingT2:
1244 case eEncodingA2:
1245 single_regs = true;
Johnny Chenbd599902011-02-10 21:39:01 +00001246 d = Bits32(opcode, 15, 12) << 1 | Bit32(opcode, 22);
Johnny Chen799dfd02011-01-26 23:14:33 +00001247 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1248 regs = Bits32(opcode, 7, 0);
1249 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1250 if (regs == 0 || regs > 16 || (d + regs) > 32)
1251 return false;
1252 break;
1253 default:
1254 return false;
1255 }
1256 uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
1257 uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2;
1258 addr_t sp_offset = imm32;
1259 addr_t addr = sp - sp_offset;
1260 uint32_t i;
1261
1262 EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
1263 for (i=d; i<regs; ++i)
1264 {
1265 context.arg1 = start_reg + i; // arg1 in the context is the DWARF register number
1266 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
1267 // uint64_t to accommodate 64-bit registers.
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001268 uint64_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
Johnny Chen799dfd02011-01-26 23:14:33 +00001269 if (!success)
1270 return false;
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001271 if (!WriteMemoryUnsigned (context, addr, reg_value, reg_byte_size))
Johnny Chen799dfd02011-01-26 23:14:33 +00001272 return false;
1273 addr += reg_byte_size;
1274 }
1275
1276 context.type = EmulateInstruction::eContextAdjustStackPointer;
1277 context.arg0 = eRegisterKindGeneric;
1278 context.arg1 = LLDB_REGNUM_GENERIC_SP;
Johnny Chen5b442b72011-01-27 19:34:30 +00001279 context.arg2 = -sp_offset;
Johnny Chen799dfd02011-01-26 23:14:33 +00001280
Greg Clayton2b8e8b02011-02-01 00:49:32 +00001281 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
Johnny Chen799dfd02011-01-26 23:14:33 +00001282 return false;
1283 }
1284 return true;
1285}
1286
Johnny Chen587a0a42011-02-01 18:35:28 +00001287// Vector Pop loads multiple extension registers from the stack.
1288// It also updates SP to point just above the loaded data.
1289bool
1290EmulateInstructionARM::EmulateVPOP (ARMEncoding encoding)
1291{
1292#if 0
1293 // ARM pseudo code...
1294 if (ConditionPassed())
1295 {
1296 EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13);
1297 address = SP;
1298 SP = SP + imm32;
1299 if single_regs then
1300 for r = 0 to regs-1
1301 S[d+r] = MemA[address,4]; address = address+4;
1302 else
1303 for r = 0 to regs-1
1304 word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8;
1305 // Combine the word-aligned words in the correct order for current endianness.
1306 D[d+r] = if BigEndian() then word1:word2 else word2:word1;
1307 }
1308#endif
1309
1310 bool success = false;
1311 const uint32_t opcode = OpcodeAsUnsigned (&success);
1312 if (!success)
1313 return false;
1314
1315 if (ConditionPassed())
1316 {
1317 const uint32_t addr_byte_size = GetAddressByteSize();
1318 const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
1319 if (!success)
1320 return false;
1321 bool single_regs;
1322 uint32_t d; // UInt(D:Vd) or UInt(Vd:D) starting register
1323 uint32_t imm32; // stack offset
1324 uint32_t regs; // number of registers
1325 switch (encoding) {
1326 case eEncodingT1:
1327 case eEncodingA1:
1328 single_regs = false;
Johnny Chenbd599902011-02-10 21:39:01 +00001329 d = Bit32(opcode, 22) << 4 | Bits32(opcode, 15, 12);
Johnny Chen587a0a42011-02-01 18:35:28 +00001330 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1331 // If UInt(imm8) is odd, see "FLDMX".
1332 regs = Bits32(opcode, 7, 0) / 2;
1333 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1334 if (regs == 0 || regs > 16 || (d + regs) > 32)
1335 return false;
1336 break;
1337 case eEncodingT2:
1338 case eEncodingA2:
1339 single_regs = true;
Johnny Chenbd599902011-02-10 21:39:01 +00001340 d = Bits32(opcode, 15, 12) << 1 | Bit32(opcode, 22);
Johnny Chen587a0a42011-02-01 18:35:28 +00001341 imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
1342 regs = Bits32(opcode, 7, 0);
1343 // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
1344 if (regs == 0 || regs > 16 || (d + regs) > 32)
1345 return false;
1346 break;
1347 default:
1348 return false;
1349 }
1350 uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
1351 uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2;
1352 addr_t sp_offset = imm32;
1353 addr_t addr = sp;
1354 uint32_t i;
1355 uint64_t data; // uint64_t to accomodate 64-bit registers.
1356
1357 EmulateInstruction::Context context = { EmulateInstruction::eContextPopRegisterOffStack, eRegisterKindDWARF, 0, 0 };
1358 for (i=d; i<regs; ++i)
1359 {
1360 context.arg1 = start_reg + i; // arg1 in the context is the DWARF register number
1361 context.arg2 = addr - sp; // arg2 in the context is the stack pointer offset
1362 data = ReadMemoryUnsigned(context, addr, reg_byte_size, 0, &success);
1363 if (!success)
1364 return false;
1365 if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, context.arg1, data))
1366 return false;
1367 addr += reg_byte_size;
1368 }
1369
1370 context.type = EmulateInstruction::eContextAdjustStackPointer;
1371 context.arg0 = eRegisterKindGeneric;
1372 context.arg1 = LLDB_REGNUM_GENERIC_SP;
1373 context.arg2 = sp_offset;
1374
1375 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp + sp_offset))
1376 return false;
1377 }
1378 return true;
1379}
1380
Johnny Chenb77be412011-02-04 00:40:18 +00001381// SVC (previously SWI)
1382bool
1383EmulateInstructionARM::EmulateSVC (ARMEncoding encoding)
1384{
1385#if 0
1386 // ARM pseudo code...
1387 if (ConditionPassed())
1388 {
1389 EncodingSpecificOperations();
1390 CallSupervisor();
1391 }
1392#endif
1393
1394 bool success = false;
1395 const uint32_t opcode = OpcodeAsUnsigned (&success);
1396 if (!success)
1397 return false;
1398
1399 if (ConditionPassed())
1400 {
1401 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1402 addr_t lr; // next instruction address
1403 if (!success)
1404 return false;
1405 uint32_t imm32; // the immediate constant
1406 uint32_t mode; // ARM or Thumb mode
1407 switch (encoding) {
1408 case eEncodingT1:
1409 lr = (pc + 2) | 1u; // return address
1410 imm32 = Bits32(opcode, 7, 0);
1411 mode = eModeThumb;
1412 break;
1413 case eEncodingA1:
1414 lr = pc + 4; // return address
1415 imm32 = Bits32(opcode, 23, 0);
1416 mode = eModeARM;
1417 break;
1418 default:
1419 return false;
1420 }
1421 EmulateInstruction::Context context = { EmulateInstruction::eContextSupervisorCall, mode, imm32, 0};
1422 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
1423 return false;
1424 }
1425 return true;
1426}
1427
Johnny Chenc315f862011-02-05 00:46:10 +00001428// If Then makes up to four following instructions (the IT block) conditional.
1429bool
1430EmulateInstructionARM::EmulateIT (ARMEncoding encoding)
1431{
1432#if 0
1433 // ARM pseudo code...
1434 EncodingSpecificOperations();
1435 ITSTATE.IT<7:0> = firstcond:mask;
1436#endif
1437
1438 bool success = false;
1439 const uint32_t opcode = OpcodeAsUnsigned (&success);
1440 if (!success)
1441 return false;
1442
1443 m_it_session.InitIT(Bits32(opcode, 7, 0));
1444 return true;
1445}
1446
Johnny Chen3b620b32011-02-07 20:11:47 +00001447// Branch causes a branch to a target address.
1448bool
1449EmulateInstructionARM::EmulateB (ARMEncoding encoding)
1450{
1451#if 0
1452 // ARM pseudo code...
1453 if (ConditionPassed())
1454 {
1455 EncodingSpecificOperations();
1456 BranchWritePC(PC + imm32);
1457 }
1458#endif
1459
1460 bool success = false;
1461 const uint32_t opcode = OpcodeAsUnsigned (&success);
1462 if (!success)
1463 return false;
1464
Johnny Chen9ee056b2011-02-08 00:06:35 +00001465 if (ConditionPassed())
1466 {
1467 EmulateInstruction::Context context = { EmulateInstruction::eContextRelativeBranchImmediate, 0, 0, 0};
1468 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001469 if (!success)
1470 return false;
Johnny Chen53ebab72011-02-08 23:21:57 +00001471 addr_t target; // target address
Johnny Chen9ee056b2011-02-08 00:06:35 +00001472 int32_t imm32; // PC-relative offset
1473 switch (encoding) {
1474 case eEncodingT1:
1475 // The 'cond' field is handled in EmulateInstructionARM::CurrentCond().
1476 imm32 = llvm::SignExtend32<9>(Bits32(opcode, 7, 0) << 1);
1477 target = pc + 4 + imm32;
1478 context.arg1 = 4 + imm32; // signed offset
1479 context.arg2 = eModeThumb; // target instruction set
1480 break;
1481 case eEncodingT2:
1482 imm32 = llvm::SignExtend32<12>(Bits32(opcode, 10, 0));
1483 target = pc + 4 + imm32;
1484 context.arg1 = 4 + imm32; // signed offset
1485 context.arg2 = eModeThumb; // target instruction set
1486 break;
1487 case eEncodingT3:
1488 // The 'cond' field is handled in EmulateInstructionARM::CurrentCond().
1489 {
Johnny Chenbd599902011-02-10 21:39:01 +00001490 uint32_t S = Bit32(opcode, 26);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001491 uint32_t imm6 = Bits32(opcode, 21, 16);
Johnny Chenbd599902011-02-10 21:39:01 +00001492 uint32_t J1 = Bit32(opcode, 13);
1493 uint32_t J2 = Bit32(opcode, 11);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001494 uint32_t imm11 = Bits32(opcode, 10, 0);
Johnny Chen53ebab72011-02-08 23:21:57 +00001495 uint32_t imm21 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001496 imm32 = llvm::SignExtend32<21>(imm21);
1497 target = pc + 4 + imm32;
1498 context.arg1 = eModeThumb; // target instruction set
1499 context.arg2 = 4 + imm32; // signed offset
1500 break;
1501 }
1502 case eEncodingT4:
1503 {
Johnny Chenbd599902011-02-10 21:39:01 +00001504 uint32_t S = Bit32(opcode, 26);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001505 uint32_t imm10 = Bits32(opcode, 25, 16);
Johnny Chenbd599902011-02-10 21:39:01 +00001506 uint32_t J1 = Bit32(opcode, 13);
1507 uint32_t J2 = Bit32(opcode, 11);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001508 uint32_t imm11 = Bits32(opcode, 10, 0);
1509 uint32_t I1 = !(J1 ^ S);
1510 uint32_t I2 = !(J2 ^ S);
Johnny Chen53ebab72011-02-08 23:21:57 +00001511 uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
Johnny Chen9ee056b2011-02-08 00:06:35 +00001512 imm32 = llvm::SignExtend32<25>(imm25);
1513 target = pc + 4 + imm32;
1514 context.arg1 = eModeThumb; // target instruction set
1515 context.arg2 = 4 + imm32; // signed offset
1516 break;
1517 }
1518 case eEncodingA1:
1519 imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2);
1520 target = pc + 8 + imm32;
1521 context.arg1 = eModeARM; // target instruction set
1522 context.arg2 = 8 + imm32; // signed offset
1523 break;
1524 default:
1525 return false;
1526 }
1527 if (!BranchWritePC(context, target))
1528 return false;
1529 }
1530 return true;
Johnny Chen3b620b32011-02-07 20:11:47 +00001531}
1532
Johnny Chen53ebab72011-02-08 23:21:57 +00001533// Compare and Branch on Nonzero and Compare and Branch on Zero compare the value in a register with
1534// zero and conditionally branch forward a constant value. They do not affect the condition flags.
1535// CBNZ, CBZ
1536bool
1537EmulateInstructionARM::EmulateCB (ARMEncoding encoding)
1538{
1539#if 0
1540 // ARM pseudo code...
1541 EncodingSpecificOperations();
1542 if nonzero ^ IsZero(R[n]) then
1543 BranchWritePC(PC + imm32);
1544#endif
1545
1546 bool success = false;
1547 const uint32_t opcode = OpcodeAsUnsigned (&success);
1548 if (!success)
1549 return false;
1550
1551 // Read the register value from the operand register Rn.
1552 uint32_t reg_val = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Bits32(opcode, 2, 0), 0, &success);
1553 if (!success)
1554 return false;
1555
1556 EmulateInstruction::Context context = { EmulateInstruction::eContextRelativeBranchImmediate, 0, 0, 0};
1557 const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1558 if (!success)
1559 return false;
1560
1561 addr_t target; // target address
1562 uint32_t imm32; // PC-relative offset to branch forward
1563 bool nonzero;
1564 switch (encoding) {
1565 case eEncodingT1:
Johnny Chenbd599902011-02-10 21:39:01 +00001566 imm32 = Bit32(opcode, 9) << 6 | Bits32(opcode, 7, 3) << 1;
Johnny Chen53ebab72011-02-08 23:21:57 +00001567 nonzero = BitIsSet(opcode, 11);
1568 target = pc + 4 + imm32;
1569 context.arg1 = 4 + imm32; // signed offset
1570 context.arg2 = eModeThumb; // target instruction set
1571 break;
1572 default:
1573 return false;
1574 }
1575 if (nonzero ^ (reg_val == 0))
1576 if (!BranchWritePC(context, target))
1577 return false;
1578
1579 return true;
1580}
1581
Johnny Chen26863dc2011-02-09 23:43:29 +00001582// ADD <Rdn>, <Rm>
1583// where <Rdn> the destination register is also the first operand register
1584// and <Rm> is the second operand register.
1585bool
1586EmulateInstructionARM::EmulateAddRdnRm (ARMEncoding encoding)
1587{
1588#if 0
1589 // ARM pseudo code...
1590 if ConditionPassed() then
1591 EncodingSpecificOperations();
1592 shifted = Shift(R[m], shift_t, shift_n, APSR.C);
1593 (result, carry, overflow) = AddWithCarry(R[n], shifted, '0');
1594 if d == 15 then
1595 ALUWritePC(result); // setflags is always FALSE here
1596 else
1597 R[d] = result;
1598 if setflags then
1599 APSR.N = result<31>;
1600 APSR.Z = IsZeroBit(result);
1601 APSR.C = carry;
1602 APSR.V = overflow;
1603#endif
1604
1605 bool success = false;
1606 const uint32_t opcode = OpcodeAsUnsigned (&success);
1607 if (!success)
1608 return false;
1609
1610 if (ConditionPassed())
1611 {
1612 uint32_t Rd, Rn, Rm;
1613 //bool setflags = false;
1614 switch (encoding)
1615 {
1616 case eEncodingT2:
1617 // setflags = FALSE
Johnny Chenbd599902011-02-10 21:39:01 +00001618 Rd = Rn = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0);
Johnny Chen26863dc2011-02-09 23:43:29 +00001619 Rm = Bits32(opcode, 6, 3);
1620 if (Rn == 15 && Rm == 15)
1621 return false;
1622 break;
1623 default:
1624 return false;
1625 }
1626
1627 int32_t result, val1, val2;
1628 // Read the first operand.
1629 if (Rn == 15)
1630 val1 = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1631 else
1632 val1 = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success);
1633 if (!success)
1634 return false;
1635
1636 // Read the second operand.
1637 if (Rm == 15)
1638 val2 = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
1639 else
1640 val2 = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
1641 if (!success)
1642 return false;
1643
1644 result = val1 + val2;
1645 EmulateInstruction::Context context = { EmulateInstruction::eContextImmediate,
1646 result,
1647 0,
1648 0 };
1649
1650 if (Rd == 15)
1651 {
1652 if (!ALUWritePC (context, result))
1653 return false;
1654 }
1655 else
1656 {
1657 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, result))
1658 return false;
1659 }
1660 }
1661 return true;
1662}
1663
Johnny Chend4dc4442011-02-11 02:02:56 +00001664bool
1665EmulateInstructionARM::EmulateCmpRnImm (ARMEncoding encoding)
1666{
1667#if 0
1668 // ARM pseudo code...
1669 if ConditionPassed() then
1670 EncodingSpecificOperations();
1671 (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1');
1672 APSR.N = result<31>;
1673 APSR.Z = IsZeroBit(result);
1674 APSR.C = carry;
1675 APSR.V = overflow;
1676#endif
1677
1678 bool success = false;
1679 const uint32_t opcode = OpcodeAsUnsigned (&success);
1680 if (!success)
1681 return false;
1682
1683 uint32_t Rn; // the first operand
1684 uint32_t imm32; // the immediate value to be compared with
1685 switch (encoding) {
1686 case eEncodingT1:
1687 Rn = Bits32(opcode, 10, 8);
1688 imm32 = Bits32(opcode, 7, 0);
1689 break;
1690 default:
1691 return false;
1692 }
1693 // Read the register value from the operand register Rn.
1694 uint32_t reg_val = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success);
1695 if (!success)
1696 return false;
1697
1698 EmulateInstruction::Context context = { EmulateInstruction::eContextImmediate, 0, 0, 0};
1699 AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1);
1700 m_new_inst_cpsr = m_inst_cpsr;
1701 SetBit32(m_new_inst_cpsr, CPSR_N, Bit32(res.result, CPSR_N));
1702 SetBit32(m_new_inst_cpsr, CPSR_Z, res.result == 0 ? 1 : 0);
1703 SetBit32(m_new_inst_cpsr, CPSR_C, res.carry_out);
1704 SetBit32(m_new_inst_cpsr, CPSR_V, res.overflow);
1705 if (m_new_inst_cpsr != m_inst_cpsr)
1706 {
1707 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
1708 return false;
1709 }
1710 return true;
1711}
1712
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001713// LDM loads multiple registers from consecutive memory locations, using an
1714// address from a base register. Optionally the addres just above the highest of those locations
1715// can be written back to the base register.
1716bool
1717EmulateInstructionARM::EmulateLDM (ARMEncoding encoding)
1718{
1719#if 0
1720 // ARM pseudo code...
1721 if ConditionPassed()
1722 EncodingSpecificOperations(); NullCheckIfThumbEE (n);
1723 address = R[n];
1724
1725 for i = 0 to 14
1726 if registers<i> == '1' then
1727 R[i] = MemA[address, 4]; address = address + 4;
1728 if registers<15> == '1' then
1729 LoadWritePC (MemA[address, 4]);
1730
1731 if wback && registers<n> == '0' then R[n] = R[n] + 4 * BitCount (registers);
1732 if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
1733
1734#endif
1735
1736 bool success = false;
1737 const uint32_t opcode = OpcodeAsUnsigned (&success);
1738 if (!success)
1739 return false;
1740
1741 if (ConditionPassed())
1742 {
1743 uint32_t n;
1744 uint32_t registers = 0;
1745 bool wback;
1746 const uint32_t addr_byte_size = GetAddressByteSize();
1747 switch (encoding)
1748 {
1749 case eEncodingT1:
1750 n = Bits32 (opcode, 10, 8);
1751 registers = Bits32 (opcode, 7, 0);
1752 wback = BitIsClear (registers, n);
1753 // if BitCount(registers) < 1 then UNPREDICTABLE;
1754 if (BitCount(registers) < 1)
1755 return false;
1756 break;
1757 case eEncodingT2:
1758 n = Bits32 (opcode, 19, 16);
1759 registers = Bits32 (opcode, 15, 0);
1760 wback = BitIsSet (opcode, 21);
1761 if ((n == 15)
1762 || (BitCount (registers) < 2)
1763 || (BitIsSet (opcode, 14) && BitIsSet (opcode, 15)))
1764 return false;
1765 if (BitIsSet (registers, 15)
1766 && m_it_session.InITBlock()
1767 && !m_it_session.LastInITBlock())
1768 return false;
1769 if (wback
1770 && BitIsSet (registers, n))
1771 return false;
1772 break;
1773 case eEncodingA1:
1774 n = Bits32 (opcode, 19, 16);
1775 registers = Bits32 (opcode, 15, 0);
1776 wback = BitIsSet (opcode, 21);
1777 if ((n == 15)
1778 || (BitCount (registers) < 1))
1779 return false;
1780 break;
1781 default:
1782 return false;
1783 }
1784
1785 int32_t offset = 0;
1786 const addr_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
1787 if (!success)
1788 return false;
Caroline Tice85aab332011-02-08 23:56:10 +00001789
1790 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
1791 eRegisterKindDWARF,
1792 dwarf_r0 + n,
1793 offset };
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001794
1795 for (int i = 0; i < 14; ++i)
1796 {
1797 if (BitIsSet (registers, i))
1798 {
Caroline Tice85aab332011-02-08 23:56:10 +00001799 context.type = EmulateInstruction::eContextRegisterPlusOffset;
1800 context.arg2 = offset;
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001801 if (wback && (n == 13)) // Pop Instruction
1802 context.type = EmulateInstruction::eContextPopRegisterOffStack;
1803
1804 // R[i] = MemA [address, 4]; address = address + 4;
1805 uint32_t data = ReadMemoryUnsigned (context, base_address + offset, addr_byte_size, 0, &success);
1806 if (!success)
1807 return false;
1808
1809 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
1810 return false;
1811
1812 offset += addr_byte_size;
1813 }
1814 }
1815
1816 if (BitIsSet (registers, 15))
1817 {
1818 //LoadWritePC (MemA [address, 4]);
Caroline Tice85aab332011-02-08 23:56:10 +00001819 context.type = EmulateInstruction::eContextRegisterPlusOffset;
1820 context.arg2 = offset;
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001821 uint32_t data = ReadMemoryUnsigned (context, base_address + offset, addr_byte_size, 0, &success);
1822 if (!success)
1823 return false;
Johnny Chene62b50d2011-02-09 22:02:17 +00001824 // In ARMv5T and above, this is an interworking branch.
1825 if (!LoadWritePC(context, data))
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001826 return false;
1827 }
1828
1829 if (wback && BitIsClear (registers, n))
1830 {
1831 addr_t offset = addr_byte_size * BitCount (registers);
Caroline Tice85aab332011-02-08 23:56:10 +00001832 context.type = EmulateInstruction::eContextRegisterPlusOffset;
1833 context.arg2 = offset;
Caroline Ticeb9f76c32011-02-08 22:24:38 +00001834
1835 // R[n] = R[n] + 4 * BitCount (registers)
1836 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, base_address + offset))
1837 return false;
1838 }
1839 if (wback && BitIsSet (registers, n))
1840 // R[n] bits(32) UNKNOWN;
1841 return false; //I'm not convinced this is the right thing to do here...
1842 }
1843 return true;
1844}
1845
Caroline Tice0b29e242011-02-08 23:16:02 +00001846bool
1847EmulateInstructionARM::EmulateLDMDB (ARMEncoding encoding)
1848{
1849#if 0
1850 // ARM pseudo code...
1851 if ConditionPassed() then
1852 EncodingSpecificOperations(); NullCheckIfThumbEE(n);
1853 address = R[n] - 4*BitCount(registers);
1854
1855 for i = 0 to 14
1856 if registers<i> == ’1’ then
1857 R[i] = MemA[address,4]; address = address + 4;
1858 if registers<15> == ’1’ then
1859 LoadWritePC(MemA[address,4]);
1860
1861 if wback && registers<n> == ’0’ then R[n] = R[n] - 4*BitCount(registers);
1862 if wback && registers<n> == ’1’ then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
1863#endif
1864
1865 bool success = false;
1866 const uint32_t opcode = OpcodeAsUnsigned (&success);
1867 if (!success)
1868 return false;
1869
1870 if (ConditionPassed())
1871 {
1872 uint32_t n;
1873 uint32_t registers = 0;
1874 bool wback;
1875 const uint32_t addr_byte_size = GetAddressByteSize();
1876 switch (encoding)
1877 {
1878 case eEncodingT1:
1879 // n = UInt(Rn); registers = P:M:’0’:register_list; wback = (W == ’1’);
1880 n = Bits32 (opcode, 19, 16);
1881 registers = Bits32 (opcode, 15, 0);
1882 wback = BitIsSet (opcode, 21);
1883
1884 // if n == 15 || BitCount(registers) < 2 || (P == ’1’ && M == ’1’) then UNPREDICTABLE;
1885 if ((n == 15)
1886 || (BitCount (registers) < 2)
1887 || (BitIsSet (opcode, 14) && BitIsSet (opcode, 15)))
1888 return false;
1889
1890 // if registers<15> == ’1’ && InITBlock() && !LastInITBlock() then UNPREDICTABLE;
1891 if (BitIsSet (registers, 15)
1892 && m_it_session.InITBlock()
1893 && !m_it_session.LastInITBlock())
1894 return false;
1895
1896 // if wback && registers<n> == ’1’ then UNPREDICTABLE;
1897 if (wback && BitIsSet (registers, n))
1898 return false;
1899
1900 break;
1901
1902 case eEncodingA1:
1903 // n = UInt(Rn); registers = register_list; wback = (W == ’1’);
1904 n = Bits32 (opcode, 19, 16);
1905 registers = Bits32 (opcode, 15, 0);
1906 wback = BitIsSet (opcode, 21);
1907
1908 // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
1909 if ((n == 15) || (BitCount (registers) < 1))
1910 return false;
1911
1912 break;
1913
1914 default:
1915 return false;
1916 }
1917
1918 int32_t offset = 0;
1919 addr_t address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success)
1920 - (addr_byte_size * BitCount (registers));
Caroline Tice85aab332011-02-08 23:56:10 +00001921 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
1922 eRegisterKindDWARF,
1923 dwarf_r0 + n,
1924 offset };
Caroline Tice0b29e242011-02-08 23:16:02 +00001925
1926 for (int i = 0; i < 14; ++i)
1927 {
1928 if (BitIsSet (registers, i))
1929 {
1930 // R[i] = MemA[address,4]; address = address + 4;
Caroline Tice85aab332011-02-08 23:56:10 +00001931 context.arg2 = offset;
Caroline Tice0b29e242011-02-08 23:16:02 +00001932 uint32_t data = ReadMemoryUnsigned (context, address + offset, addr_byte_size, 0, &success);
1933 if (!success)
1934 return false;
1935
1936 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
1937 return false;
1938
1939 offset += addr_byte_size;
1940 }
1941 }
1942
1943 // if registers<15> == ’1’ then
1944 // LoadWritePC(MemA[address,4]);
1945 if (BitIsSet (registers, 15))
1946 {
Caroline Tice85aab332011-02-08 23:56:10 +00001947 context.arg2 = offset;
Caroline Tice0b29e242011-02-08 23:16:02 +00001948 uint32_t data = ReadMemoryUnsigned (context, address + offset, addr_byte_size, 0, &success);
1949 if (!success)
1950 return false;
Johnny Chene62b50d2011-02-09 22:02:17 +00001951 // In ARMv5T and above, this is an interworking branch.
1952 if (!LoadWritePC(context, data))
Caroline Tice0b29e242011-02-08 23:16:02 +00001953 return false;
1954 }
1955
1956 // if wback && registers<n> == ’0’ then R[n] = R[n] - 4*BitCount(registers);
1957 if (wback && BitIsClear (registers, n))
1958 {
Caroline Tice85aab332011-02-08 23:56:10 +00001959 context.arg2 = offset;
Caroline Tice0b29e242011-02-08 23:16:02 +00001960 addr_t addr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
1961 if (!success)
1962 return false;
1963 addr = addr - (addr_byte_size * BitCount (registers));
1964 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr))
1965 return false;
1966 }
1967
1968 // if wback && registers<n> == ’1’ then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
1969 if (wback && BitIsSet (registers, n))
1970 return false; // I'm not sure this is right; how do I set R[n] to bits(32) UNKNOWN.
1971 }
1972 return true;
1973}
Caroline Tice85aab332011-02-08 23:56:10 +00001974
1975bool
1976EmulateInstructionARM::EmulateLDMIB (ARMEncoding encoding)
1977{
1978#if 0
1979 if ConditionPassed() then
1980 EncodingSpecificOperations();
1981 address = R[n] + 4;
1982
1983 for i = 0 to 14
1984 if registers<i> == ’1’ then
1985 R[i] = MemA[address,4]; address = address + 4;
1986 if registers<15> == ’1’ then
1987 LoadWritePC(MemA[address,4]);
1988
1989 if wback && registers<n> == ’0’ then R[n] = R[n] + 4*BitCount(registers);
1990 if wback && registers<n> == ’1’ then R[n] = bits(32) UNKNOWN;
1991#endif
1992
1993 bool success = false;
1994 const uint32_t opcode = OpcodeAsUnsigned (&success);
1995 if (!success)
1996 return false;
1997
1998 if (ConditionPassed())
1999 {
2000 uint32_t n;
2001 uint32_t registers = 0;
2002 bool wback;
2003 const uint32_t addr_byte_size = GetAddressByteSize();
2004 switch (encoding)
2005 {
2006 case eEncodingA1:
2007 // n = UInt(Rn); registers = register_list; wback = (W == ’1’);
2008 n = Bits32 (opcode, 19, 16);
2009 registers = Bits32 (opcode, 15, 0);
2010 wback = BitIsSet (opcode, 21);
2011
2012 // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
2013 if ((n == 15) || (BitCount (registers) < 1))
2014 return false;
2015
2016 break;
2017 default:
2018 return false;
2019 }
2020 // address = R[n] + 4;
2021
2022 int32_t offset = 0;
2023 addr_t address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success) + addr_byte_size;
2024
2025 EmulateInstruction::Context context = { EmulateInstruction::eContextRegisterPlusOffset,
2026 eRegisterKindDWARF,
2027 dwarf_r0 + n,
2028 offset };
2029
2030 for (int i = 0; i < 14; ++i)
2031 {
2032 if (BitIsSet (registers, i))
2033 {
2034 // R[i] = MemA[address,4]; address = address + 4;
2035
2036 context.arg2 = offset;
2037 uint32_t data = ReadMemoryUnsigned (context, address + offset, addr_byte_size, 0, &success);
2038 if (!success)
2039 return false;
2040
2041 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
2042 return false;
2043
2044 offset += addr_byte_size;
2045 }
2046 }
2047
2048 // if registers<15> == ’1’ then
2049 // LoadWritePC(MemA[address,4]);
2050 if (BitIsSet (registers, 15))
2051 {
2052 context.arg2 = offset;
2053 uint32_t data = ReadMemoryUnsigned (context, address + offset, addr_byte_size, 0, &success);
2054 if (!success)
2055 return false;
Johnny Chene62b50d2011-02-09 22:02:17 +00002056 // In ARMv5T and above, this is an interworking branch.
2057 if (!LoadWritePC(context, data))
Caroline Tice85aab332011-02-08 23:56:10 +00002058 return false;
2059 }
2060
2061 // if wback && registers<n> == ’0’ then R[n] = R[n] + 4*BitCount(registers);
2062 if (wback && BitIsClear (registers, n))
2063 {
2064 context.arg2 = offset;
2065 addr_t addr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
2066 if (!success)
2067 return false;
2068 addr = addr + (addr_byte_size * BitCount (registers));
2069 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr))
2070 return false;
2071 }
2072
2073 // if wback && registers<n> == ’1’ then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
2074 if (wback && BitIsSet (registers, n))
2075 return false; // I'm not sure this is right; how do I set R[n] to bits(32) UNKNOWN.
2076 }
2077 return true;
2078}
Caroline Tice0b29e242011-02-08 23:16:02 +00002079
Johnny Chenef21b592011-02-10 01:52:38 +00002080// Load Register (immediate) calculates an address from a base register value and
2081// an immediate offset, loads a word from memory, and writes to a register.
2082// LDR (immediate, Thumb)
2083bool
2084EmulateInstructionARM::EmulateLDRRtRnImm (ARMEncoding encoding)
2085{
2086#if 0
2087 // ARM pseudo code...
2088 if (ConditionPassed())
2089 {
2090 EncodingSpecificOperations(); NullCheckIfThumbEE(15);
2091 offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
2092 address = if index then offset_addr else R[n];
2093 data = MemU[address,4];
2094 if wback then R[n] = offset_addr;
2095 if t == 15 then
2096 if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
2097 elsif UnalignedSupport() || address<1:0> = '00' then
2098 R[t] = data;
2099 else R[t] = bits(32) UNKNOWN; // Can only apply before ARMv7
2100 }
2101#endif
2102
2103 bool success = false;
2104 const uint32_t opcode = OpcodeAsUnsigned (&success);
2105 if (!success)
2106 return false;
2107
2108 if (ConditionPassed())
2109 {
2110 uint32_t Rt; // the destination register
2111 uint32_t Rn; // the base register
2112 uint32_t imm32; // the immediate offset used to form the address
2113 addr_t offset_addr; // the offset address
2114 addr_t address; // the calculated address
2115 uint32_t data; // the literal data value from memory load
2116 bool add, index, wback;
2117 switch (encoding) {
2118 case eEncodingT1:
2119 Rt = Bits32(opcode, 5, 3);
2120 Rn = Bits32(opcode, 2, 0);
2121 imm32 = Bits32(opcode, 10, 6) << 2; // imm32 = ZeroExtend(imm5:'00', 32);
2122 // index = TRUE; add = TRUE; wback = FALSE
2123 add = true;
2124 index = true;
2125 wback = false;
2126 break;
2127 default:
2128 return false;
2129 }
2130 uint32_t base = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success);
2131 if (!success)
2132 return false;
2133 if (add)
2134 offset_addr = base + imm32;
2135 else
2136 offset_addr = base - imm32;
2137
2138 address = (index ? offset_addr : base);
2139
2140 if (wback)
2141 {
2142 EmulateInstruction::Context ctx = { EmulateInstruction::eContextRegisterPlusOffset,
2143 eRegisterKindDWARF,
2144 dwarf_r0 + Rn,
2145 (int32_t) (offset_addr - base)};
2146 if (!WriteRegisterUnsigned (ctx, eRegisterKindDWARF, dwarf_r0 + Rn, offset_addr))
2147 return false;
2148 }
2149
2150 // Prepare to write to the Rt register.
2151 EmulateInstruction::Context context = {EmulateInstruction::eContextImmediate,
2152 0,
2153 0,
2154 0};
2155
2156 // Read memory from the address.
2157 data = ReadMemoryUnsigned(context, address, 4, 0, &success);
2158 if (!success)
2159 return false;
2160 context.arg0 = data;
2161
2162 if (Rt == 15)
2163 {
2164 if (Bits32(address, 1, 0) == 0)
2165 {
2166 if (!LoadWritePC(context, data))
2167 return false;
2168 }
2169 else
2170 return false;
2171 }
2172 else if (UnalignedSupport() || Bits32(address, 1, 0) == 0)
2173 {
2174 if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rt, data))
2175 return false;
2176 }
2177 else
2178 return false;
2179 }
2180 return true;
2181}
2182
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002183EmulateInstructionARM::ARMOpcode*
2184EmulateInstructionARM::GetARMOpcodeForInstruction (const uint32_t opcode)
Greg Clayton64c84432011-01-21 22:02:52 +00002185{
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002186 static ARMOpcode
2187 g_arm_opcodes[] =
2188 {
2189 //----------------------------------------------------------------------
2190 // Prologue instructions
2191 //----------------------------------------------------------------------
Johnny Chenfdd179e2011-01-31 20:09:28 +00002192
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002193 // push register(s)
Johnny Chenc28a76d2011-02-01 18:51:48 +00002194 { 0x0fff0000, 0x092d0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulatePush, "push <registers>" },
2195 { 0x0fff0fff, 0x052d0004, ARMvAll, eEncodingA2, eSize32, &EmulateInstructionARM::EmulatePush, "push <register>" },
Johnny Chenbcec3af2011-01-27 01:26:19 +00002196
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002197 // set r7 to point to a stack offset
Johnny Chenc28a76d2011-02-01 18:51:48 +00002198 { 0x0ffff000, 0x028d7000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateAddRdSPImmediate, "add r7, sp, #<const>" },
2199 { 0x0ffff000, 0x024c7000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSubR7IPImmediate, "sub r7, ip, #<const>"},
Johnny Chene7cf4202011-02-10 18:13:23 +00002200 // copy the stack pointer to ip
Johnny Chenc28a76d2011-02-01 18:51:48 +00002201 { 0x0fffffff, 0x01a0c00d, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateMovRdSP, "mov ip, sp" },
2202 { 0x0ffff000, 0x028dc000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateAddRdSPImmediate, "add ip, sp, #<const>" },
2203 { 0x0ffff000, 0x024dc000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSubIPSPImmediate, "sub ip, sp, #<const>"},
Johnny Chen4c0e0bc2011-01-25 22:45:28 +00002204
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002205 // adjust the stack pointer
Johnny Chenc28a76d2011-02-01 18:51:48 +00002206 { 0x0ffff000, 0x024dd000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSubSPImmdiate, "sub sp, sp, #<const>"},
Johnny Chence1ca772011-01-25 01:13:00 +00002207
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002208 // push one register
2209 // if Rn == '1101' && imm12 == '000000000100' then SEE PUSH;
Johnny Chenc28a76d2011-02-01 18:51:48 +00002210 { 0x0fff0000, 0x052d0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSTRRtSP, "str Rt, [sp, #-imm12]!" },
Johnny Chen799dfd02011-01-26 23:14:33 +00002211
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002212 // vector push consecutive extension register(s)
Johnny Chen9b8d7832011-02-02 01:13:56 +00002213 { 0x0fbf0f00, 0x0d2d0b00, ARMV6T2_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"},
2214 { 0x0fbf0f00, 0x0d2d0a00, ARMV6T2_ABOVE, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"},
Johnny Chenef85e912011-01-31 23:07:40 +00002215
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002216 //----------------------------------------------------------------------
Johnny Chen587a0a42011-02-01 18:35:28 +00002217 // Epilogue instructions
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002218 //----------------------------------------------------------------------
Johnny Chenef85e912011-01-31 23:07:40 +00002219
Johnny Chen9b8d7832011-02-02 01:13:56 +00002220 // To resolve ambiguity, "blx <label>" should come before "bl <label>".
2221 { 0xfe000000, 0xfa000000, ARMV5_ABOVE, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
2222 { 0x0f000000, 0x0b000000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"},
2223 { 0x0ffffff0, 0x012fff30, ARMV5_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
Johnny Chenc28a76d2011-02-01 18:51:48 +00002224 { 0x0fff0000, 0x08bd0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulatePop, "pop <registers>"},
2225 { 0x0fff0fff, 0x049d0004, ARMvAll, eEncodingA2, eSize32, &EmulateInstructionARM::EmulatePop, "pop <register>"},
Johnny Chen9b8d7832011-02-02 01:13:56 +00002226 { 0x0fbf0f00, 0x0cbd0b00, ARMV6T2_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"},
Johnny Chenb77be412011-02-04 00:40:18 +00002227 { 0x0fbf0f00, 0x0cbd0a00, ARMV6T2_ABOVE, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"},
2228
2229 //----------------------------------------------------------------------
2230 // Supervisor Call (previously Software Interrupt)
2231 //----------------------------------------------------------------------
Johnny Chen3b620b32011-02-07 20:11:47 +00002232 { 0x0f000000, 0x0f000000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSVC, "svc #imm24"},
2233
2234 //----------------------------------------------------------------------
2235 // Branch instructions
2236 //----------------------------------------------------------------------
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002237 { 0x0f000000, 0x0a000000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSVC, "b #imm24"},
Johnny Chenb77be412011-02-04 00:40:18 +00002238
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002239 //----------------------------------------------------------------------
2240 // Load instructions
2241 //----------------------------------------------------------------------
Caroline Tice0b29e242011-02-08 23:16:02 +00002242 { 0x0fd00000, 0x08900000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDM, "ldm<c> <Rn>{!} <registers>" },
Caroline Tice85aab332011-02-08 23:56:10 +00002243 { 0x0fd00000, 0x09100000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDMDB, "ldmdb<c> <Rn>{!} <registers>" },
2244 { 0x0fd00000, 0x09900000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDMIB, "ldmib<c> <Rn<{!} <registers>" }
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002245
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002246 };
2247 static const size_t k_num_arm_opcodes = sizeof(g_arm_opcodes)/sizeof(ARMOpcode);
2248
2249 for (size_t i=0; i<k_num_arm_opcodes; ++i)
2250 {
2251 if ((g_arm_opcodes[i].mask & opcode) == g_arm_opcodes[i].value)
2252 return &g_arm_opcodes[i];
2253 }
2254 return NULL;
2255}
Greg Clayton64c84432011-01-21 22:02:52 +00002256
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002257
2258EmulateInstructionARM::ARMOpcode*
2259EmulateInstructionARM::GetThumbOpcodeForInstruction (const uint32_t opcode)
Johnny Chen347320d2011-01-24 23:40:59 +00002260{
Johnny Chenfdd179e2011-01-31 20:09:28 +00002261
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002262 static ARMOpcode
2263 g_thumb_opcodes[] =
2264 {
2265 //----------------------------------------------------------------------
2266 // Prologue instructions
2267 //----------------------------------------------------------------------
Johnny Chenbcec3af2011-01-27 01:26:19 +00002268
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002269 // push register(s)
Johnny Chenc28a76d2011-02-01 18:51:48 +00002270 { 0xfffffe00, 0x0000b400, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulatePush, "push <registers>" },
Johnny Chend6c13f02011-02-08 20:36:34 +00002271 { 0xffff0000, 0xe92d0000, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulatePush, "push.w <registers>" },
2272 { 0xffff0fff, 0xf84d0d04, ARMV6T2_ABOVE, eEncodingT3, eSize32, &EmulateInstructionARM::EmulatePush, "push.w <register>" },
Johnny Chen788e0552011-01-27 22:52:23 +00002273
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002274 // set r7 to point to a stack offset
Johnny Chenc28a76d2011-02-01 18:51:48 +00002275 { 0xffffff00, 0x0000af00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateAddRdSPImmediate, "add r7, sp, #imm" },
Johnny Chene7cf4202011-02-10 18:13:23 +00002276 // copy the stack pointer to r7
Johnny Chenc28a76d2011-02-01 18:51:48 +00002277 { 0xffffffff, 0x0000466f, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateMovRdSP, "mov r7, sp" },
Johnny Chene7cf4202011-02-10 18:13:23 +00002278 // move from high register to low register (comes after "mov r7, sp" to resolve ambiguity)
2279 { 0xffffffc0, 0x00004640, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateMovLowHigh, "mov r0-r7, r8-r15" },
Johnny Chen60c0d622011-01-25 23:49:39 +00002280
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002281 // PC relative load into register (see also EmulateAddSPRm)
Johnny Chenc28a76d2011-02-01 18:51:48 +00002282 { 0xfffff800, 0x00004800, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateLDRRdPCRelative, "ldr <Rd>, [PC, #imm]"},
Johnny Chen799dfd02011-01-26 23:14:33 +00002283
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002284 // adjust the stack pointer
Johnny Chenc28a76d2011-02-01 18:51:48 +00002285 { 0xffffff87, 0x00004485, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateAddSPRm, "add sp, <Rm>"},
2286 { 0xffffff80, 0x0000b080, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateSubSPImmdiate, "add sp, sp, #imm"},
Johnny Chend6c13f02011-02-08 20:36:34 +00002287 { 0xfbef8f00, 0xf1ad0d00, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateSubSPImmdiate, "sub.w sp, sp, #<const>"},
2288 { 0xfbff8f00, 0xf2ad0d00, ARMV6T2_ABOVE, eEncodingT3, eSize32, &EmulateInstructionARM::EmulateSubSPImmdiate, "subw sp, sp, #imm12"},
Johnny Chenfdd179e2011-01-31 20:09:28 +00002289
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002290 // vector push consecutive extension register(s)
Johnny Chend6c13f02011-02-08 20:36:34 +00002291 { 0xffbf0f00, 0xed2d0b00, ARMV6T2_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"},
2292 { 0xffbf0f00, 0xed2d0a00, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"},
Johnny Chenfdd179e2011-01-31 20:09:28 +00002293
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002294 //----------------------------------------------------------------------
2295 // Epilogue instructions
2296 //----------------------------------------------------------------------
Johnny Chen347320d2011-01-24 23:40:59 +00002297
Johnny Chenc28a76d2011-02-01 18:51:48 +00002298 { 0xffffff80, 0x0000b000, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateAddSPImmediate, "add sp, #imm"},
Johnny Chen9b8d7832011-02-02 01:13:56 +00002299 { 0xffffff87, 0x00004780, ARMV5_ABOVE, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
2300 // J1 == J2 == 1
Johnny Chend6c13f02011-02-08 20:36:34 +00002301 { 0xf800f800, 0xf000f800, ARMV4T_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"},
2302 // J1 == J2 == 1
2303 { 0xf800e800, 0xf000e800, ARMV5_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
Johnny Chenc28a76d2011-02-01 18:51:48 +00002304 { 0xfffffe00, 0x0000bc00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulatePop, "pop <registers>"},
Johnny Chend6c13f02011-02-08 20:36:34 +00002305 { 0xffff0000, 0xe8bd0000, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulatePop, "pop.w <registers>" },
2306 { 0xffff0fff, 0xf85d0d04, ARMV6T2_ABOVE, eEncodingT3, eSize32, &EmulateInstructionARM::EmulatePop, "pop.w <register>" },
2307 { 0xffbf0f00, 0xecbd0b00, ARMV6T2_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"},
2308 { 0xffbf0f00, 0xecbd0a00, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"},
Johnny Chenb77be412011-02-04 00:40:18 +00002309
2310 //----------------------------------------------------------------------
2311 // Supervisor Call (previously Software Interrupt)
2312 //----------------------------------------------------------------------
Johnny Chenc315f862011-02-05 00:46:10 +00002313 { 0xffffff00, 0x0000df00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateSVC, "svc #imm8"},
2314
2315 //----------------------------------------------------------------------
2316 // If Then makes up to four following instructions conditional.
2317 //----------------------------------------------------------------------
Johnny Chen3b620b32011-02-07 20:11:47 +00002318 { 0xffffff00, 0x0000bf00, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateIT, "it{<x>{<y>{<z>}}} <firstcond>"},
2319
2320 //----------------------------------------------------------------------
2321 // Branch instructions
2322 //----------------------------------------------------------------------
2323 // To resolve ambiguity, "b<c> #imm8" should come after "svc #imm8".
2324 { 0xfffff000, 0x0000d000, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateB, "b<c> #imm8 (outside IT)"},
2325 { 0xffff8000, 0x0000e000, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateB, "b #imm11 (outside or last in IT)"},
Johnny Chen9ee056b2011-02-08 00:06:35 +00002326 { 0xf800d000, 0xf0008000, ARMV6T2_ABOVE, eEncodingT3, eSize32, &EmulateInstructionARM::EmulateB, "b<c>.w #imm8 (outside IT)"},
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002327 { 0xf800d000, 0xf0009000, ARMV6T2_ABOVE, eEncodingT4, eSize32, &EmulateInstructionARM::EmulateB, "b.w #imm8 (outside or last in IT)"},
Johnny Chen53ebab72011-02-08 23:21:57 +00002328 // compare and branch
2329 { 0xfffff500, 0x0000b100, ARMV6T2_ABOVE, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateCB, "cb{n}z <Rn>, <label>"},
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002330
2331 //----------------------------------------------------------------------
Johnny Chen26863dc2011-02-09 23:43:29 +00002332 // Data-processing instructions
2333 //----------------------------------------------------------------------
2334 // Make sure "add sp, <Rm>" comes before this instruction, so there's no ambiguity decoding the two.
2335 { 0xffffff00, 0x00004400, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateAddRdnRm, "add <Rdn>, <Rm>"},
Johnny Chen338bf542011-02-10 19:29:03 +00002336 // move from high register to high register
2337 { 0xffffff00, 0x00004600, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateMovRdRm, "mov<c> <Rd>, <Rm>"},
2338 // move from low register to low register
2339 { 0xffffffc0, 0x00000000, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateMovRdRm, "movs <Rd>, <Rm>"},
Johnny Chend4dc4442011-02-11 02:02:56 +00002340 // compare a register with immediate
2341 { 0xfffff800, 0x00002800, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateCmpRnImm, "cmp<c> <Rn>, #imm8"},
Johnny Chen26863dc2011-02-09 23:43:29 +00002342
2343 //----------------------------------------------------------------------
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002344 // Load instructions
2345 //----------------------------------------------------------------------
2346 { 0xfffff800, 0x0000c800, ARMV4T_ABOVE, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateLDM, "ldm<c> <Rn>{!} <registers>" },
Caroline Tice0b29e242011-02-08 23:16:02 +00002347 { 0xffd02000, 0xe8900000, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateLDM, "ldm<c>.w <Rn>{!} <registers>" },
Johnny Chenef21b592011-02-10 01:52:38 +00002348 { 0xffd00000, 0xe9100000, ARMV6T2_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateLDMDB, "ldmdb<c> <Rn>{!} <registers>" },
2349 { 0xfffff800, 0x00006800, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr<c> <Rt>, [<Rn>{,#imm}]"}
Caroline Ticeb9f76c32011-02-08 22:24:38 +00002350
Greg Clayton2b8e8b02011-02-01 00:49:32 +00002351 };
2352
2353 const size_t k_num_thumb_opcodes = sizeof(g_thumb_opcodes)/sizeof(ARMOpcode);
2354 for (size_t i=0; i<k_num_thumb_opcodes; ++i)
2355 {
2356 if ((g_thumb_opcodes[i].mask & opcode) == g_thumb_opcodes[i].value)
2357 return &g_thumb_opcodes[i];
2358 }
2359 return NULL;
2360}
Greg Clayton64c84432011-01-21 22:02:52 +00002361
Greg Clayton31e2a382011-01-30 20:03:56 +00002362bool
2363EmulateInstructionARM::SetTargetTriple (const ConstString &triple)
2364{
2365 m_arm_isa = 0;
2366 const char *triple_cstr = triple.GetCString();
2367 if (triple_cstr)
2368 {
2369 const char *dash = ::strchr (triple_cstr, '-');
2370 if (dash)
2371 {
2372 std::string arch (triple_cstr, dash);
2373 const char *arch_cstr = arch.c_str();
2374 if (strcasecmp(arch_cstr, "armv4t") == 0)
2375 m_arm_isa = ARMv4T;
2376 else if (strcasecmp(arch_cstr, "armv4") == 0)
2377 m_arm_isa = ARMv4;
2378 else if (strcasecmp(arch_cstr, "armv5tej") == 0)
2379 m_arm_isa = ARMv5TEJ;
2380 else if (strcasecmp(arch_cstr, "armv5te") == 0)
2381 m_arm_isa = ARMv5TE;
2382 else if (strcasecmp(arch_cstr, "armv5t") == 0)
2383 m_arm_isa = ARMv5T;
2384 else if (strcasecmp(arch_cstr, "armv6k") == 0)
2385 m_arm_isa = ARMv6K;
2386 else if (strcasecmp(arch_cstr, "armv6") == 0)
2387 m_arm_isa = ARMv6;
2388 else if (strcasecmp(arch_cstr, "armv6t2") == 0)
2389 m_arm_isa = ARMv6T2;
2390 else if (strcasecmp(arch_cstr, "armv7") == 0)
2391 m_arm_isa = ARMv7;
2392 else if (strcasecmp(arch_cstr, "armv8") == 0)
2393 m_arm_isa = ARMv8;
2394 }
2395 }
2396 return m_arm_isa != 0;
2397}
2398
2399
Greg Clayton64c84432011-01-21 22:02:52 +00002400bool
2401EmulateInstructionARM::ReadInstruction ()
2402{
2403 bool success = false;
2404 m_inst_cpsr = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, 0, &success);
2405 if (success)
2406 {
2407 addr_t pc = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_ADDRESS, &success);
2408 if (success)
2409 {
2410 Context read_inst_context = {eContextReadOpcode, 0, 0};
2411 if (m_inst_cpsr & MASK_CPSR_T)
2412 {
2413 m_inst_mode = eModeThumb;
2414 uint32_t thumb_opcode = ReadMemoryUnsigned(read_inst_context, pc, 2, 0, &success);
2415
2416 if (success)
2417 {
2418 if ((m_inst.opcode.inst16 & 0xe000) != 0xe000 || ((m_inst.opcode.inst16 & 0x1800u) == 0))
2419 {
2420 m_inst.opcode_type = eOpcode16;
2421 m_inst.opcode.inst16 = thumb_opcode;
2422 }
2423 else
2424 {
2425 m_inst.opcode_type = eOpcode32;
2426 m_inst.opcode.inst32 = (thumb_opcode << 16) | ReadMemoryUnsigned(read_inst_context, pc + 2, 2, 0, &success);
2427 }
2428 }
2429 }
2430 else
2431 {
2432 m_inst_mode = eModeARM;
2433 m_inst.opcode_type = eOpcode32;
2434 m_inst.opcode.inst32 = ReadMemoryUnsigned(read_inst_context, pc, 4, 0, &success);
2435 }
2436 }
2437 }
2438 if (!success)
2439 {
2440 m_inst_mode = eModeInvalid;
2441 m_inst_pc = LLDB_INVALID_ADDRESS;
2442 }
2443 return success;
2444}
2445
Johnny Chenee9b1f72011-02-09 01:00:31 +00002446uint32_t
2447EmulateInstructionARM::ArchVersion ()
2448{
2449 return m_arm_isa;
2450}
2451
Greg Clayton64c84432011-01-21 22:02:52 +00002452bool
2453EmulateInstructionARM::ConditionPassed ()
2454{
2455 if (m_inst_cpsr == 0)
2456 return false;
2457
2458 const uint32_t cond = CurrentCond ();
2459
2460 if (cond == UINT32_MAX)
2461 return false;
2462
2463 bool result = false;
2464 switch (UnsignedBits(cond, 3, 1))
2465 {
2466 case 0: result = (m_inst_cpsr & MASK_CPSR_Z) != 0; break;
2467 case 1: result = (m_inst_cpsr & MASK_CPSR_C) != 0; break;
2468 case 2: result = (m_inst_cpsr & MASK_CPSR_N) != 0; break;
2469 case 3: result = (m_inst_cpsr & MASK_CPSR_V) != 0; break;
2470 case 4: result = ((m_inst_cpsr & MASK_CPSR_C) != 0) && ((m_inst_cpsr & MASK_CPSR_Z) == 0); break;
2471 case 5:
2472 {
2473 bool n = (m_inst_cpsr & MASK_CPSR_N);
2474 bool v = (m_inst_cpsr & MASK_CPSR_V);
2475 result = n == v;
2476 }
2477 break;
2478 case 6:
2479 {
2480 bool n = (m_inst_cpsr & MASK_CPSR_N);
2481 bool v = (m_inst_cpsr & MASK_CPSR_V);
2482 result = n == v && ((m_inst_cpsr & MASK_CPSR_Z) == 0);
2483 }
2484 break;
2485 case 7:
2486 result = true;
2487 break;
2488 }
2489
2490 if (cond & 1)
2491 result = !result;
2492 return result;
2493}
2494
Johnny Chen9ee056b2011-02-08 00:06:35 +00002495uint32_t
2496EmulateInstructionARM::CurrentCond ()
2497{
2498 switch (m_inst_mode)
2499 {
2500 default:
2501 case eModeInvalid:
2502 break;
2503
2504 case eModeARM:
2505 return UnsignedBits(m_inst.opcode.inst32, 31, 28);
2506
2507 case eModeThumb:
2508 // For T1 and T3 encodings of the Branch instruction, it returns the 4-bit
2509 // 'cond' field of the encoding.
2510 if (m_inst.opcode_type == eOpcode16 &&
2511 Bits32(m_inst.opcode.inst16, 15, 12) == 0x0d &&
2512 Bits32(m_inst.opcode.inst16, 11, 7) != 0x0f)
2513 {
2514 return Bits32(m_inst.opcode.inst16, 11, 7);
2515 }
2516 else if (m_inst.opcode_type == eOpcode32 &&
2517 Bits32(m_inst.opcode.inst32, 31, 27) == 0x1e &&
2518 Bits32(m_inst.opcode.inst32, 15, 14) == 0x02 &&
2519 Bits32(m_inst.opcode.inst32, 12, 12) == 0x00 &&
2520 Bits32(m_inst.opcode.inst32, 25, 22) <= 0x0d)
2521 {
2522 return Bits32(m_inst.opcode.inst32, 25, 22);
2523 }
2524
2525 return m_it_session.GetCond();
2526 }
2527 return UINT32_MAX; // Return invalid value
2528}
2529
Johnny Chen9ee056b2011-02-08 00:06:35 +00002530bool
2531EmulateInstructionARM::BranchWritePC (const Context &context, uint32_t addr)
2532{
2533 addr_t target;
2534
Johnny Chenee9b1f72011-02-09 01:00:31 +00002535 // Check the current instruction set.
2536 if (CurrentInstrSet() == eModeARM)
Johnny Chen9ee056b2011-02-08 00:06:35 +00002537 target = addr & 0xfffffffc;
Johnny Chenee9b1f72011-02-09 01:00:31 +00002538 else
Johnny Chen9ee056b2011-02-08 00:06:35 +00002539 target = addr & 0xfffffffe;
Johnny Chenee9b1f72011-02-09 01:00:31 +00002540
Johnny Chen9ee056b2011-02-08 00:06:35 +00002541 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, target))
Johnny Chen53ebab72011-02-08 23:21:57 +00002542 return false;
2543
2544 return true;
Johnny Chen9ee056b2011-02-08 00:06:35 +00002545}
2546
2547// As a side effect, BXWritePC sets context.arg2 to eModeARM or eModeThumb by inspecting addr.
2548bool
2549EmulateInstructionARM::BXWritePC (Context &context, uint32_t addr)
2550{
2551 addr_t target;
Johnny Chen0f309db2011-02-09 19:11:32 +00002552 // If the CPSR is changed due to switching between ARM and Thumb ISETSTATE,
2553 // we want to record it and issue a WriteRegister callback so the clients
2554 // can track the mode changes accordingly.
2555 bool cpsr_changed = false;
Johnny Chen9ee056b2011-02-08 00:06:35 +00002556
2557 if (BitIsSet(addr, 0))
2558 {
Johnny Chen0f309db2011-02-09 19:11:32 +00002559 if (CurrentInstrSet() != eModeThumb)
2560 {
2561 SelectInstrSet(eModeThumb);
2562 cpsr_changed = true;
2563 }
Johnny Chen9ee056b2011-02-08 00:06:35 +00002564 target = addr & 0xfffffffe;
2565 context.arg2 = eModeThumb;
2566 }
2567 else if (BitIsClear(addr, 1))
2568 {
Johnny Chen0f309db2011-02-09 19:11:32 +00002569 if (CurrentInstrSet() != eModeARM)
2570 {
2571 SelectInstrSet(eModeARM);
2572 cpsr_changed = true;
2573 }
Johnny Chen9ee056b2011-02-08 00:06:35 +00002574 target = addr & 0xfffffffc;
2575 context.arg2 = eModeARM;
2576 }
2577 else
2578 return false; // address<1:0> == '10' => UNPREDICTABLE
2579
Johnny Chen0f309db2011-02-09 19:11:32 +00002580 if (cpsr_changed)
2581 {
Johnny Chen558133b2011-02-09 23:59:17 +00002582 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
Johnny Chen0f309db2011-02-09 19:11:32 +00002583 return false;
2584 }
Johnny Chen9ee056b2011-02-08 00:06:35 +00002585 if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, target))
Johnny Chen53ebab72011-02-08 23:21:57 +00002586 return false;
2587
2588 return true;
Johnny Chen9ee056b2011-02-08 00:06:35 +00002589}
Greg Clayton64c84432011-01-21 22:02:52 +00002590
Johnny Chenee9b1f72011-02-09 01:00:31 +00002591// Dispatches to either BXWritePC or BranchWritePC based on architecture versions.
2592bool
2593EmulateInstructionARM::LoadWritePC (Context &context, uint32_t addr)
2594{
2595 if (ArchVersion() >= ARMv5T)
2596 return BXWritePC(context, addr);
2597 else
2598 return BranchWritePC((const Context)context, addr);
2599}
2600
Johnny Chen26863dc2011-02-09 23:43:29 +00002601// Dispatches to either BXWritePC or BranchWritePC based on architecture versions and current instruction set.
2602bool
2603EmulateInstructionARM::ALUWritePC (Context &context, uint32_t addr)
2604{
2605 if (ArchVersion() >= ARMv7 && CurrentInstrSet() == eModeARM)
2606 return BXWritePC(context, addr);
2607 else
2608 return BranchWritePC((const Context)context, addr);
2609}
2610
Johnny Chenee9b1f72011-02-09 01:00:31 +00002611EmulateInstructionARM::Mode
2612EmulateInstructionARM::CurrentInstrSet ()
2613{
2614 return m_inst_mode;
2615}
2616
2617// Set the 'T' bit of our CPSR. The m_inst_mode gets updated when the next
Johnny Chen558133b2011-02-09 23:59:17 +00002618// ReadInstruction() is performed. This function has a side effect of updating
2619// the m_new_inst_cpsr member variable if necessary.
Johnny Chenee9b1f72011-02-09 01:00:31 +00002620bool
2621EmulateInstructionARM::SelectInstrSet (Mode arm_or_thumb)
2622{
Johnny Chen558133b2011-02-09 23:59:17 +00002623 m_new_inst_cpsr = m_inst_cpsr;
Johnny Chenee9b1f72011-02-09 01:00:31 +00002624 switch (arm_or_thumb)
2625 {
2626 default:
2627 return false;
2628 eModeARM:
2629 // Clear the T bit.
Johnny Chen558133b2011-02-09 23:59:17 +00002630 m_new_inst_cpsr &= ~MASK_CPSR_T;
Johnny Chenee9b1f72011-02-09 01:00:31 +00002631 break;
2632 eModeThumb:
2633 // Set the T bit.
Johnny Chen558133b2011-02-09 23:59:17 +00002634 m_new_inst_cpsr |= MASK_CPSR_T;
Johnny Chenee9b1f72011-02-09 01:00:31 +00002635 break;
2636 }
2637 return true;
2638}
2639
Johnny Chenef21b592011-02-10 01:52:38 +00002640// This function returns TRUE if the processor currently provides support for
2641// unaligned memory accesses, or FALSE otherwise. This is always TRUE in ARMv7,
2642// controllable by the SCTLR.U bit in ARMv6, and always FALSE before ARMv6.
2643bool
2644EmulateInstructionARM::UnalignedSupport()
2645{
2646 return (ArchVersion() >= ARMv7);
2647}
2648
Johnny Chenbf6ad172011-02-11 01:29:53 +00002649// The main addition and subtraction instructions can produce status information
2650// about both unsigned carry and signed overflow conditions. This status
2651// information can be used to synthesize multi-word additions and subtractions.
2652EmulateInstructionARM::AddWithCarryResult
2653EmulateInstructionARM::AddWithCarry (uint32_t x, uint32_t y, uint8_t carry_in)
2654{
2655 uint32_t result;
2656 uint8_t carry_out;
2657 uint8_t overflow;
2658
2659 uint64_t unsigned_sum = x + y + carry_in;
2660 int64_t signed_sum = (int32_t)x + (int32_t)y + (int32_t)carry_in;
2661
2662 result = UnsignedBits(unsigned_sum, 31, 0);
2663 carry_out = (result == unsigned_sum ? 0 : 1);
2664 overflow = ((int32_t)result == signed_sum ? 0 : 1);
2665
2666 AddWithCarryResult res = { result, carry_out, overflow };
2667 return res;
2668}
2669
Greg Clayton64c84432011-01-21 22:02:52 +00002670bool
2671EmulateInstructionARM::EvaluateInstruction ()
2672{
Johnny Chenc315f862011-02-05 00:46:10 +00002673 // Advance the ITSTATE bits to their values for the next instruction.
2674 if (m_inst_mode == eModeThumb && m_it_session.InITBlock())
2675 m_it_session.ITAdvance();
2676
Greg Clayton64c84432011-01-21 22:02:52 +00002677 return false;
2678}