arm_disassembler.c 104 KB
Newer Older
1
2
3
4
/***************************************************************************
 *   Copyright (C) 2006 by Dominic Rath                                    *
 *   Dominic.Rath@gmx.de                                                   *
 *                                                                         *
5
6
 *   Copyright (C) 2009 by David Brownell                                  *
 *                                                                         *
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
22
23
24
25
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

zwelch's avatar
zwelch committed
26
#include "target.h"
27
#include "arm_disassembler.h"
28
#include <helper/log.h>
29
30


31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/*
 * This disassembler supports two main functions for OpenOCD:
 *
 *  - Various "disassemble" commands.  OpenOCD can serve as a
 *    machine-language debugger, without help from GDB.
 *
 *  - Single stepping.  Not all ARM cores support hardware single
 *    stepping.  To work without that support, the debugger must
 *    be able to decode instructions to find out where to put a
 *    "next instruction" breakpoint.
 *
 * In addition, interpretation of ETM trace data needs some of the
 * decoding mechanisms.
 *
 * At this writing (September 2009) neither function is complete.
 *
 *  - ARM decoding
 *     * Old-style syntax (not UAL) is generally used
 *     * VFP instructions are not understood (ARMv5 and later)
 *       except as coprocessor 10/11 operations
 *     * Most ARM instructions through ARMv6 are decoded, but some
 *       of the post-ARMv4 opcodes may not be handled yet
David Brownell's avatar
David Brownell committed
53
 *		CPS, SDIV, UDIV, LDREX*, STREX*, QASX, ...
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
 *     * NEON instructions are not understood (ARMv7-A)
 *
 *  - Thumb/Thumb2 decoding
 *     * UAL syntax should be consistently used
 *     * Any Thumb2 instructions used in Cortex-M3 (ARMv7-M) should
 *       be handled properly.  Accordingly, so should the subset
 *       used in Cortex-M0/M1; and "original" 16-bit Thumb from
 *       ARMv4T and ARMv5T.
 *     * Conditional effects of Thumb2 "IT" (if-then) instructions
 *       are not handled:  the affected instructions are not shown
 *       with their now-conditional suffixes.
 *     * Some ARMv6 and ARMv7-M Thumb2 instructions may not be
 *       handled (minimally for coprocessor access).
 *     * SIMD instructions, and some other Thumb2 instructions
 *       from ARMv7-A, are not understood.
 *
 *  - ThumbEE decoding
 *     * As a Thumb2 variant, the Thumb2 comments (above) apply.
 *     * Opcodes changed by ThumbEE mode are not handled; these
 *       instructions wrongly decode as LDM and STM.
 *
 *  - Jazelle decoding ...  no support whatsoever for Jazelle mode
 *    or decoding.  ARM encourages use of the more generic ThumbEE
 *    mode, instead of Jazelle mode, in current chips.
 *
 *  - Single-step/emulation ... spotty support, which is only weakly
 *    tested.  Thumb2 is not supported.  (Arguably a full simulator
 *    is not needed to support just single stepping.  Recognizing
 *    branch vs non-branch instructions suffices, except when the
 *    instruction faults and triggers a synchronous exception which
 *    can be intercepted using other means.)
 *
 * ARM DDI 0406B "ARM Architecture Reference Manual, ARM v7-A and
 * ARM v7-R edition" gives the most complete coverage of the various
 * generations of ARM instructions.  At this writing it is publicly
 * accessible to anyone willing to create an account at the ARM
 * web site; see http://www.arm.com/documentation/ for information.
 *
 * ARM DDI 0403C "ARMv7-M Architecture Reference Manual" provides
 * more details relevant to the Thumb2-only processors (such as
 * the Cortex-M implementations).
 */

97
98
/* textual represenation of the condition field */
/* ALways (default) is ommitted (empty string) */
99
static const char *arm_condition_strings[] =
100
101
102
103
104
{
	"EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
};

/* make up for C's missing ROR */
105
static uint32_t ror(uint32_t value, int places)
106
107
{
	return (value >> places) | (value << (32 - places));
108
109
}

110
111
112
113
114
115
116
117
118
119
static int evaluate_unknown(uint32_t opcode,
		uint32_t address, struct arm_instruction *instruction)
{
	instruction->type = ARM_UNDEFINED_INSTRUCTION;
	snprintf(instruction->text, 128,
			"0x%8.8" PRIx32 "\t0x%8.8" PRIx32
			"\tUNDEFINED INSTRUCTION", address, opcode);
	return ERROR_OK;
}

120
static int evaluate_pld(uint32_t opcode,
121
		uint32_t address, struct arm_instruction *instruction)
122
123
{
	/* PLD */
124
	if ((opcode & 0x0d70f000) == 0x0550f000)
125
126
	{
		instruction->type = ARM_PLD;
127

duane's avatar
duane committed
128
		snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD ...TODO...", address, opcode);
129

130
131
		return ERROR_OK;
	}
132
133
134
135
136
137
138
	return evaluate_unknown(opcode, address, instruction);
}

static int evaluate_srs(uint32_t opcode,
		uint32_t address, struct arm_instruction *instruction)
{
	const char *wback = (opcode & (1 << 21)) ? "!" : "";
139
	const char *mode = "";
140
141
142
143
144
145
146
147
148
149
150
151
152
153

	switch ((opcode >> 23) & 0x3) {
	case 0:
		mode = "DA";
		break;
	case 1:
		/* "IA" is default */
		break;
	case 2:
		mode = "DB";
		break;
	case 3:
		mode = "IB";
		break;
154
	}
155

156
157
158
159
160
161
	switch (opcode & 0x0e500000) {
	case 0x08400000:
		snprintf(instruction->text, 128, "0x%8.8" PRIx32
				"\t0x%8.8" PRIx32
				"\tSRS%s\tSP%s, #%d",
				address, opcode,
David Brownell's avatar
David Brownell committed
162
163
				mode, wback,
				(unsigned)(opcode & 0x1f));
164
165
166
167
168
169
		break;
	case 0x08100000:
		snprintf(instruction->text, 128, "0x%8.8" PRIx32
				"\t0x%8.8" PRIx32
				"\tRFE%s\tr%d%s",
				address, opcode,
David Brownell's avatar
David Brownell committed
170
171
				mode,
				(unsigned)((opcode >> 16) & 0xf), wback);
172
173
174
175
176
		break;
	default:
		return evaluate_unknown(opcode, address, instruction);
	}
	return ERROR_OK;
177
178
}

179
static int evaluate_swi(uint32_t opcode,
180
		uint32_t address, struct arm_instruction *instruction)
181
182
{
	instruction->type = ARM_SWI;
183

zwelch's avatar
zwelch committed
184
185
186
	snprintf(instruction->text, 128,
			"0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSVC %#6.6" PRIx32,
			address, opcode, (opcode & 0xffffff));
187

188
189
190
	return ERROR_OK;
}

191
static int evaluate_blx_imm(uint32_t opcode,
192
		uint32_t address, struct arm_instruction *instruction)
193
194
{
	int offset;
195
196
	uint32_t immediate;
	uint32_t target_address;
197

198
199
	instruction->type = ARM_BLX;
	immediate = opcode & 0x00ffffff;
200

201
202
203
204
205
	/* sign extend 24-bit immediate */
	if (immediate & 0x00800000)
		offset = 0xff000000 | immediate;
	else
		offset = immediate;
206

207
208
	/* shift two bits left */
	offset <<= 2;
209

210
211
212
	/* odd/event halfword */
	if (opcode & 0x01000000)
		offset |= 0x2;
213

214
	target_address = address + 8 + offset;
215

duane's avatar
duane committed
216
	snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBLX 0x%8.8" PRIx32 "", address, opcode, target_address);
217

218
219
	instruction->info.b_bl_bx_blx.reg_operand = -1;
	instruction->info.b_bl_bx_blx.target_address = target_address;
220

221
222
223
	return ERROR_OK;
}

224
static int evaluate_b_bl(uint32_t opcode,
225
		uint32_t address, struct arm_instruction *instruction)
226
{
227
	uint8_t L;
228
	uint32_t immediate;
229
	int offset;
230
	uint32_t target_address;
231

232
233
	immediate = opcode & 0x00ffffff;
	L = (opcode & 0x01000000) >> 24;
234

235
236
237
238
239
	/* sign extend 24-bit immediate */
	if (immediate & 0x00800000)
		offset = 0xff000000 | immediate;
	else
		offset = immediate;
240

241
242
	/* shift two bits left */
	offset <<= 2;
243

244
	target_address = address + 8 + offset;
245
246
247
248
249

	if (L)
		instruction->type = ARM_BL;
	else
		instruction->type = ARM_B;
250

duane's avatar
duane committed
251
	snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tB%s%s 0x%8.8" PRIx32 , address, opcode,
252
			 (L) ? "L" : "", COND(opcode), target_address);
253

254
255
	instruction->info.b_bl_bx_blx.reg_operand = -1;
	instruction->info.b_bl_bx_blx.target_address = target_address;
256

257
258
259
260
261
	return ERROR_OK;
}

/* Coprocessor load/store and double register transfers */
/* both normal and extended instruction space (condition field b1111) */
262
static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode,
263
		uint32_t address, struct arm_instruction *instruction)
264
{
265
	uint8_t cp_num = (opcode & 0xf00) >> 8;
266

267
268
269
	/* MCRR or MRRC */
	if (((opcode & 0x0ff00000) == 0x0c400000) || ((opcode & 0x0ff00000) == 0x0c400000))
	{
270
		uint8_t cp_opcode, Rd, Rn, CRm;
271
		char *mnemonic;
272

273
274
275
276
		cp_opcode = (opcode & 0xf0) >> 4;
		Rd = (opcode & 0xf000) >> 12;
		Rn = (opcode & 0xf0000) >> 16;
		CRm = (opcode & 0xf);
277

278
279
280
281
282
		/* MCRR */
		if ((opcode & 0x0ff00000) == 0x0c400000)
		{
			instruction->type = ARM_MCRR;
			mnemonic = "MCRR";
283
284
		} else if ((opcode & 0x0ff00000) == 0x0c500000) {
			/* MRRC */
285
286
			instruction->type = ARM_MRRC;
			mnemonic = "MRRC";
287
288
289
		} else {
			LOG_ERROR("Unknown instruction");
			return ERROR_FAIL;
290
		}
291

292
293
294
295
296
297
298
		snprintf(instruction->text, 128,
				"0x%8.8" PRIx32 "\t0x%8.8" PRIx32
				"\t%s%s%s p%i, %x, r%i, r%i, c%i",
				 address, opcode, mnemonic,
				((opcode & 0xf0000000) == 0xf0000000)
						? "2" : COND(opcode),
				 COND(opcode), cp_num, cp_opcode, Rd, Rn, CRm);
299
300
301
	}
	else /* LDC or STC */
	{
302
		uint8_t CRd, Rn, offset;
303
		uint8_t U;
304
305
		char *mnemonic;
		char addressing_mode[32];
306

307
308
		CRd = (opcode & 0xf000) >> 12;
		Rn = (opcode & 0xf0000) >> 16;
309
		offset = (opcode & 0xff) << 2;
310

311
312
313
314
315
316
317
318
319
320
321
		/* load/store */
		if (opcode & 0x00100000)
		{
			instruction->type = ARM_LDC;
			mnemonic = "LDC";
		}
		else
		{
			instruction->type = ARM_STC;
			mnemonic = "STC";
		}
322

323
		U = (opcode & 0x00800000) >> 23;
324

325
		/* addressing modes */
326
327
328
329
330
331
332
333
334
		if ((opcode & 0x01200000) == 0x01000000) /* offset */
			snprintf(addressing_mode, 32, "[r%i, #%s%d]",
					Rn, U ? "" : "-", offset);
		else if ((opcode & 0x01200000) == 0x01200000) /* pre-indexed */
			snprintf(addressing_mode, 32, "[r%i, #%s%d]!",
					Rn, U ? "" : "-", offset);
		else if ((opcode & 0x01200000) == 0x00200000) /* post-indexed */
			snprintf(addressing_mode, 32, "[r%i], #%s%d",
					Rn, U ? "" : "-", offset);
335
		else if ((opcode & 0x01200000) == 0x00000000) /* unindexed */
336
337
			snprintf(addressing_mode, 32, "[r%i], {%d}",
					Rn, offset >> 2);
338

339
340
341
342
343
344
345
346
		snprintf(instruction->text, 128, "0x%8.8" PRIx32
				"\t0x%8.8" PRIx32
				"\t%s%s%s p%i, c%i, %s",
				address, opcode, mnemonic,
				((opcode & 0xf0000000) == 0xf0000000)
						? "2" : COND(opcode),
				(opcode & (1 << 22)) ? "L" : "",
				cp_num, CRd, addressing_mode);
347
	}
348

349
350
351
352
353
354
	return ERROR_OK;
}

/* Coprocessor data processing instructions */
/* Coprocessor register transfer instructions */
/* both normal and extended instruction space (condition field b1111) */
355
static int evaluate_cdp_mcr_mrc(uint32_t opcode,
356
		uint32_t address, struct arm_instruction *instruction)
357
{
358
	const char *cond;
359
	char* mnemonic;
360
	uint8_t cp_num, opcode_1, CRd_Rd, CRn, CRm, opcode_2;
361

362
363
364
365
366
367
	cond = ((opcode & 0xf0000000) == 0xf0000000) ? "2" : COND(opcode);
	cp_num = (opcode & 0xf00) >> 8;
	CRd_Rd = (opcode & 0xf000) >> 12;
	CRn = (opcode & 0xf0000) >> 16;
	CRm = (opcode & 0xf);
	opcode_2 = (opcode & 0xe0) >> 5;
368

369
370
371
372
373
374
375
376
377
378
379
380
381
	/* CDP or MRC/MCR */
	if (opcode & 0x00000010) /* bit 4 set -> MRC/MCR */
	{
		if (opcode & 0x00100000) /* bit 20 set -> MRC */
		{
			instruction->type = ARM_MRC;
			mnemonic = "MRC";
		}
		else /* bit 20 not set -> MCR */
		{
			instruction->type = ARM_MCR;
			mnemonic = "MCR";
		}
382

383
		opcode_1 = (opcode & 0x00e00000) >> 21;
384

duane's avatar
duane committed
385
		snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s p%i, 0x%2.2x, r%i, c%i, c%i, 0x%2.2x",
386
387
388
389
390
391
392
				 address, opcode, mnemonic, cond,
				 cp_num, opcode_1, CRd_Rd, CRn, CRm, opcode_2);
	}
	else /* bit 4 not set -> CDP */
	{
		instruction->type = ARM_CDP;
		mnemonic = "CDP";
393

394
		opcode_1 = (opcode & 0x00f00000) >> 20;
395

duane's avatar
duane committed
396
		snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s p%i, 0x%2.2x, c%i, c%i, c%i, 0x%2.2x",
397
398
399
				 address, opcode, mnemonic, cond,
				 cp_num, opcode_1, CRd_Rd, CRn, CRm, opcode_2);
	}
400

401
402
403
404
	return ERROR_OK;
}

/* Load/store instructions */
405
static int evaluate_load_store(uint32_t opcode,
406
		uint32_t address, struct arm_instruction *instruction)
407
{
408
409
	uint8_t I, P, U, B, W, L;
	uint8_t Rn, Rd;
410
411
412
	char *operation; /* "LDR" or "STR" */
	char *suffix; /* "", "B", "T", "BT" */
	char offset[32];
413

414
415
416
417
418
419
420
	/* examine flags */
	I = (opcode & 0x02000000) >> 25;
	P = (opcode & 0x01000000) >> 24;
	U = (opcode & 0x00800000) >> 23;
	B = (opcode & 0x00400000) >> 22;
	W = (opcode & 0x00200000) >> 21;
	L = (opcode & 0x00100000) >> 20;
421

422
423
	/* target register */
	Rd = (opcode & 0xf000) >> 12;
424

425
426
	/* base register */
	Rn = (opcode & 0xf0000) >> 16;
427

428
429
430
431
	instruction->info.load_store.Rd = Rd;
	instruction->info.load_store.Rn = Rn;
	instruction->info.load_store.U = U;

432
433
434
435
436
	/* determine operation */
	if (L)
		operation = "LDR";
	else
		operation = "STR";
437

438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
	/* determine instruction type and suffix */
	if (B)
	{
		if ((P == 0) && (W == 1))
		{
			if (L)
				instruction->type = ARM_LDRBT;
			else
				instruction->type = ARM_STRBT;
			suffix = "BT";
		}
		else
		{
			if (L)
				instruction->type = ARM_LDRB;
			else
				instruction->type = ARM_STRB;
			suffix = "B";
		}
	}
	else
	{
		if ((P == 0) && (W == 1))
		{
			if (L)
				instruction->type = ARM_LDRT;
			else
				instruction->type = ARM_STRT;
			suffix = "T";
		}
		else
		{
			if (L)
				instruction->type = ARM_LDR;
			else
				instruction->type = ARM_STR;
			suffix = "";
		}
	}
477

478
479
	if (!I) /* #+-<offset_12> */
	{
480
		uint32_t offset_12 = (opcode & 0xfff);
481
		if (offset_12)
duane's avatar
duane committed
482
			snprintf(offset, 32, ", #%s0x%" PRIx32 "", (U) ? "" : "-", offset_12);
483
		else
ntfreak's avatar
ntfreak committed
484
			snprintf(offset, 32, "%s", "");
485

486
487
		instruction->info.load_store.offset_mode = 0;
		instruction->info.load_store.offset.offset = offset_12;
488
489
490
	}
	else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
	{
491
492
		uint8_t shift_imm, shift;
		uint8_t Rm;
493

494
495
496
		shift_imm = (opcode & 0xf80) >> 7;
		shift = (opcode & 0x60) >> 5;
		Rm = (opcode & 0xf);
497

498
499
500
		/* LSR encodes a shift by 32 bit as 0x0 */
		if ((shift == 0x1) && (shift_imm == 0x0))
			shift_imm = 0x20;
501

502
503
504
505
506
507
508
		/* ASR encodes a shift by 32 bit as 0x0 */
		if ((shift == 0x2) && (shift_imm == 0x0))
			shift_imm = 0x20;

		/* ROR by 32 bit is actually a RRX */
		if ((shift == 0x3) && (shift_imm == 0x0))
			shift = 0x4;
509

510
511
512
513
514
		instruction->info.load_store.offset_mode = 1;
		instruction->info.load_store.offset.reg.Rm = Rm;
		instruction->info.load_store.offset.reg.shift = shift;
		instruction->info.load_store.offset.reg.shift_imm = shift_imm;

515
516
		if ((shift_imm == 0x0) && (shift == 0x0)) /* +-<Rm> */
		{
517
			snprintf(offset, 32, ", %sr%i", (U) ? "" : "-", Rm);
518
519
520
		}
		else /* +-<Rm>, <Shift>, #<shift_imm> */
		{
521
			switch (shift)
522
			{
523
				case 0x0: /* LSL */
524
					snprintf(offset, 32, ", %sr%i, LSL #0x%x", (U) ? "" : "-", Rm, shift_imm);
525
526
					break;
				case 0x1: /* LSR */
527
					snprintf(offset, 32, ", %sr%i, LSR #0x%x", (U) ? "" : "-", Rm, shift_imm);
528
529
					break;
				case 0x2: /* ASR */
530
					snprintf(offset, 32, ", %sr%i, ASR #0x%x", (U) ? "" : "-", Rm, shift_imm);
531
532
					break;
				case 0x3: /* ROR */
533
					snprintf(offset, 32, ", %sr%i, ROR #0x%x", (U) ? "" : "-", Rm, shift_imm);
534
535
					break;
				case 0x4: /* RRX */
536
					snprintf(offset, 32, ", %sr%i, RRX", (U) ? "" : "-", Rm);
537
					break;
538
539
540
			}
		}
	}
541

542
543
544
545
	if (P == 1)
	{
		if (W == 0) /* offset */
		{
duane's avatar
duane committed
546
			snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i%s]",
547
548
					 address, opcode, operation, COND(opcode), suffix,
					 Rd, Rn, offset);
549

550
			instruction->info.load_store.index_mode = 0;
551
552
553
		}
		else /* pre-indexed */
		{
duane's avatar
duane committed
554
			snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i%s]!",
555
556
					 address, opcode, operation, COND(opcode), suffix,
					 Rd, Rn, offset);
557

558
			instruction->info.load_store.index_mode = 1;
559
560
561
562
		}
	}
	else /* post-indexed */
	{
duane's avatar
duane committed
563
		snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i]%s",
564
565
				 address, opcode, operation, COND(opcode), suffix,
				 Rd, Rn, offset);
566

567
		instruction->info.load_store.index_mode = 2;
568
	}
569

570
571
572
	return ERROR_OK;
}

573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
static int evaluate_extend(uint32_t opcode, uint32_t address, char *cp)
{
	unsigned rm = (opcode >> 0) & 0xf;
	unsigned rd = (opcode >> 12) & 0xf;
	unsigned rn = (opcode >> 16) & 0xf;
	char *type, *rot;

	switch ((opcode >> 24) & 0x3) {
	case 0:
		type = "B16";
		break;
	case 1:
		sprintf(cp, "UNDEFINED");
		return ARM_UNDEFINED_INSTRUCTION;
	case 2:
		type = "B";
		break;
590
	default:
591
592
593
594
595
596
597
598
599
600
601
602
603
604
		type = "H";
		break;
	}

	switch ((opcode >> 10) & 0x3) {
	case 0:
		rot = "";
		break;
	case 1:
		rot = ", ROR #8";
		break;
	case 2:
		rot = ", ROR #16";
		break;
605
	default:
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
		rot = ", ROR #24";
		break;
	}

	if (rn == 0xf) {
		sprintf(cp, "%cXT%s%s\tr%d, r%d%s",
				(opcode & (1 << 22)) ? 'U' : 'S',
				type, COND(opcode),
				rd, rm, rot);
		return ARM_MOV;
	} else {
		sprintf(cp, "%cXTA%s%s\tr%d, r%d, r%d%s",
				(opcode & (1 << 22)) ? 'U' : 'S',
				type, COND(opcode),
				rd, rn, rm, rot);
		return ARM_ADD;
	}
}

static int evaluate_p_add_sub(uint32_t opcode, uint32_t address, char *cp)
{
	char *prefix;
	char *op;
	int type;

	switch ((opcode >> 20) & 0x7) {
	case 1:
		prefix = "S";
		break;
	case 2:
		prefix = "Q";
		break;
	case 3:
		prefix = "SH";
		break;
	case 5:
		prefix = "U";
		break;
	case 6:
		prefix = "UQ";
		break;
	case 7:
		prefix = "UH";
		break;
	default:
		goto undef;
	}

	switch ((opcode >> 5) & 0x7) {
	case 0:
		op = "ADD16";
		type = ARM_ADD;
		break;
	case 1:
		op = "ADDSUBX";
		type = ARM_ADD;
		break;
	case 2:
		op = "SUBADDX";
		type = ARM_SUB;
		break;
	case 3:
		op = "SUB16";
		type = ARM_SUB;
		break;
	case 4:
		op = "ADD8";
		type = ARM_ADD;
		break;
	case 7:
		op = "SUB8";
		type = ARM_SUB;
		break;
	default:
		goto undef;
	}

	sprintf(cp, "%s%s%s\tr%d, r%d, r%d", prefix, op, COND(opcode),
			(int) (opcode >> 12) & 0xf,
			(int) (opcode >> 16) & 0xf,
			(int) (opcode >> 0) & 0xf);
	return type;

undef:
	/* these opcodes might be used someday */
	sprintf(cp, "UNDEFINED");
	return ARM_UNDEFINED_INSTRUCTION;
}

/* ARMv6 and later support "media" instructions (includes SIMD) */
static int evaluate_media(uint32_t opcode, uint32_t address,
697
		struct arm_instruction *instruction)
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
{
	char *cp = instruction->text;
	char *mnemonic = NULL;

	sprintf(cp,
		"0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t",
		address, opcode);
	cp = strchr(cp, 0);

	/* parallel add/subtract */
	if ((opcode & 0x01800000) == 0x00000000) {
		instruction->type = evaluate_p_add_sub(opcode, address, cp);
		return ERROR_OK;
	}

	/* halfword pack */
	if ((opcode & 0x01f00020) == 0x00800000) {
		char *type, *shift;
		unsigned imm = (unsigned) (opcode >> 7) & 0x1f;

		if (opcode & (1 << 6)) {
			type = "TB";
			shift = "ASR";
			if (imm == 0)
				imm = 32;
		} else {
			type = "BT";
			shift = "LSL";
		}
		sprintf(cp, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
			type, COND(opcode),
			(int) (opcode >> 12) & 0xf,
			(int) (opcode >> 16) & 0xf,
			(int) (opcode >> 0) & 0xf,
			shift, imm);
		return ERROR_OK;
	}

	/* word saturate */
	if ((opcode & 0x01a00020) == 0x00a00000) {
		char *shift;
		unsigned imm = (unsigned) (opcode >> 7) & 0x1f;

		if (opcode & (1 << 6)) {
			shift = "ASR";
			if (imm == 0)
				imm = 32;
		} else {
			shift = "LSL";
		}

		sprintf(cp, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
			(opcode & (1 << 22)) ? 'U' : 'S',
			COND(opcode),
			(int) (opcode >> 12) & 0xf,
			(int) (opcode >> 16) & 0x1f,
			(int) (opcode >> 0) & 0xf,
			shift, imm);
		return ERROR_OK;
	}

	/* sign extension */
	if ((opcode & 0x018000f0) == 0x00800070) {
		instruction->type = evaluate_extend(opcode, address, cp);
		return ERROR_OK;
	}

	/* multiplies */
	if ((opcode & 0x01f00080) == 0x01000000) {
		unsigned rn = (opcode >> 12) & 0xf;

		if (rn != 0xf)
			sprintf(cp, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
				(opcode & (1 << 6)) ? 'S' : 'A',
				(opcode & (1 << 5)) ? "X" : "",
				COND(opcode),
				(int) (opcode >> 16) & 0xf,
				(int) (opcode >> 0) & 0xf,
				(int) (opcode >> 8) & 0xf,
				rn);
		else
			sprintf(cp, "SMU%cD%s%s\tr%d, r%d, r%d",
				(opcode & (1 << 6)) ? 'S' : 'A',
				(opcode & (1 << 5)) ? "X" : "",
				COND(opcode),
				(int) (opcode >> 16) & 0xf,
				(int) (opcode >> 0) & 0xf,
				(int) (opcode >> 8) & 0xf);
		return ERROR_OK;
	}
	if ((opcode & 0x01f00000) == 0x01400000) {
		sprintf(cp, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
			(opcode & (1 << 6)) ? 'S' : 'A',
			(opcode & (1 << 5)) ? "X" : "",
			COND(opcode),
			(int) (opcode >> 12) & 0xf,
			(int) (opcode >> 16) & 0xf,
			(int) (opcode >> 0) & 0xf,
			(int) (opcode >> 8) & 0xf);
		return ERROR_OK;
	}
	if ((opcode & 0x01f00000) == 0x01500000) {
		unsigned rn = (opcode >> 12) & 0xf;

		switch (opcode & 0xc0) {
		case 3:
			if (rn == 0xf)
				goto undef;
			/* FALL THROUGH */
		case 0:
			break;
		default:
			goto undef;
		}

		if (rn != 0xf)
			sprintf(cp, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
				(opcode & (1 << 6)) ? 'S' : 'A',
				(opcode & (1 << 5)) ? "R" : "",
				COND(opcode),
				(int) (opcode >> 16) & 0xf,
				(int) (opcode >> 0) & 0xf,
				(int) (opcode >> 8) & 0xf,
				rn);
		else
			sprintf(cp, "SMMUL%s%s\tr%d, r%d, r%d",
				(opcode & (1 << 5)) ? "R" : "",
				COND(opcode),
				(int) (opcode >> 16) & 0xf,
				(int) (opcode >> 0) & 0xf,
				(int) (opcode >> 8) & 0xf);
		return ERROR_OK;
	}


	/* simple matches against the remaining decode bits */
	switch (opcode & 0x01f000f0) {
	case 0x00a00030:
	case 0x00e00030:
		/* parallel halfword saturate */
		sprintf(cp, "%cSAT16%s\tr%d, #%d, r%d",
			(opcode & (1 << 22)) ? 'U' : 'S',
			COND(opcode),
			(int) (opcode >> 12) & 0xf,
			(int) (opcode >> 16) & 0xf,
			(int) (opcode >> 0) & 0xf);
		return ERROR_OK;
	case 0x00b00030:
		mnemonic = "REV";
		break;
	case 0x00b000b0:
		mnemonic = "REV16";
		break;
	case 0x00f000b0:
		mnemonic = "REVSH";
		break;
	case 0x008000b0:
		/* select bytes */
		sprintf(cp, "SEL%s\tr%d, r%d, r%d", COND(opcode),
			(int) (opcode >> 12) & 0xf,
			(int) (opcode >> 16) & 0xf,
			(int) (opcode >> 0) & 0xf);
		return ERROR_OK;
	case 0x01800010:
		/* unsigned sum of absolute differences */
		if (((opcode >> 12) & 0xf) == 0xf)
			sprintf(cp, "USAD8%s\tr%d, r%d, r%d", COND(opcode),
				(int) (opcode >> 16) & 0xf,
				(int) (opcode >> 0) & 0xf,
				(int) (opcode >> 8) & 0xf);
		else
			sprintf(cp, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode),
				(int) (opcode >> 16) & 0xf,
				(int) (opcode >> 0) & 0xf,
				(int) (opcode >> 8) & 0xf,
				(int) (opcode >> 12) & 0xf);
		return ERROR_OK;
	}
	if (mnemonic) {
		unsigned rm = (opcode >> 0) & 0xf;
		unsigned rd = (opcode >> 12) & 0xf;

		sprintf(cp, "%s%s\tr%d, r%d", mnemonic, COND(opcode), rm, rd);
		return ERROR_OK;
	}

undef:
	/* these opcodes might be used someday */
	sprintf(cp, "UNDEFINED");
	return ERROR_OK;
}

890
/* Miscellaneous load/store instructions */
891
static int evaluate_misc_load_store(uint32_t opcode,
892
		uint32_t address, struct arm_instruction *instruction)
893
{
894
895
	uint8_t P, U, I, W, L, S, H;
	uint8_t Rn, Rd;
896
897
898
	char *operation; /* "LDR" or "STR" */
	char *suffix; /* "H", "SB", "SH", "D" */
	char offset[32];
899

900
901
902
903
904
905
906
907
	/* examine flags */
	P = (opcode & 0x01000000) >> 24;
	U = (opcode & 0x00800000) >> 23;
	I = (opcode & 0x00400000) >> 22;
	W = (opcode & 0x00200000) >> 21;
	L = (opcode & 0x00100000) >> 20;
	S = (opcode & 0x00000040) >> 6;
	H = (opcode & 0x00000020) >> 5;
908

909
910
	/* target register */
	Rd = (opcode & 0xf000) >> 12;
911

912
913
	/* base register */
	Rn = (opcode & 0xf0000) >> 16;
914

915
916
917
	instruction->info.load_store.Rd = Rd;
	instruction->info.load_store.Rn = Rn;
	instruction->info.load_store.U = U;
918

919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
	/* determine instruction type and suffix */
	if (S) /* signed */
	{
		if (L) /* load */
		{
			if (H)
			{
				operation = "LDR";
				instruction->type = ARM_LDRSH;
				suffix = "SH";
			}
			else
			{
				operation = "LDR";
				instruction->type = ARM_LDRSB;
				suffix = "SB";
			}
		}
		else /* there are no signed stores, so this is used to encode double-register load/stores */
		{
			suffix = "D";
			if (H)
			{
				operation = "STR";
				instruction->type = ARM_STRD;
			}
			else
			{
				operation = "LDR";
				instruction->type = ARM_LDRD;
			}
		}
	}
	else /* unsigned */
	{
		suffix = "H";
		if (L) /* load */
		{
			operation = "LDR";
			instruction->type = ARM_LDRH;
		}
		else /* store */
		{
			operation = "STR";
			instruction->type = ARM_STRH;
		}
	}
966

967
968
	if (I) /* Immediate offset/index (#+-<offset_8>)*/
	{
969
		uint32_t offset_8 = ((opcode & 0xf00) >> 4) | (opcode & 0xf);
duane's avatar
duane committed
970
		snprintf(offset, 32, "#%s0x%" PRIx32 "", (U) ? "" : "-", offset_8);
971

972
973
		instruction->info.load_store.offset_mode = 0;
		instruction->info.load_store.offset.offset = offset_8;
974
975
976
	}
	else /* Register offset/index (+-<Rm>) */
	{
977
		uint8_t Rm;
978
979
		Rm = (opcode & 0xf);
		snprintf(offset, 32, "%sr%i", (U) ? "" : "-", Rm);
980

981
982
983
984
		instruction->info.load_store.offset_mode = 1;
		instruction->info.load_store.offset.reg.Rm = Rm;
		instruction->info.load_store.offset.reg.shift = 0x0;
		instruction->info.load_store.offset.reg.shift_imm = 0x0;
985
	}
986

987
988
989
990
	if (P == 1)
	{
		if (W == 0) /* offset */
		{
duane's avatar
duane committed
991
			snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i, %s]",
992
993
					 address, opcode, operation, COND(opcode), suffix,
					 Rd, Rn, offset);
994

995
			instruction->info.load_store.index_mode = 0;
996
997
998
		}
		else /* pre-indexed */
		{
duane's avatar
duane committed
999
			snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i, %s]!",
1000
1001
					 address, opcode, operation, COND(opcode), suffix,
					 Rd, Rn, offset);
1002

1003
			instruction->info.load_store.index_mode = 1;
1004
1005
1006
1007
		}
	}
	else /* post-indexed */
	{
duane's avatar
duane committed
1008
		snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i], %s",
1009
1010
				 address, opcode, operation, COND(opcode), suffix,
				 Rd, Rn, offset);
1011

1012
		instruction->info.load_store.index_mode = 2;
1013
	}
1014

1015
1016
1017
1018
	return ERROR_OK;
}

/* Load/store multiples instructions */
1019
static int evaluate_ldm_stm(uint32_t opcode,
1020
		uint32_t address, struct arm_instruction *instruction)
1021
{
1022
	uint8_t P, U, S, W, L, Rn;
1023
	uint32_t register_list;
1024
1025
1026
1027
1028
1029
	char *addressing_mode;
	char *mnemonic;
	char reg_list[69];
	char *reg_list_p;
	int i;
	int first_reg = 1;
1030

1031
1032
1033
1034
1035
1036
1037
	P = (opcode & 0x01000000) >> 24;
	U = (opcode & 0x00800000) >> 23;
	S = (opcode & 0x00400000) >> 22;
	W = (opcode & 0x00200000) >> 21;
	L = (opcode & 0x00100000) >> 20;
	register_list = (opcode & 0xffff);
	Rn = (opcode & 0xf0000) >> 16;
1038

1039
1040
1041
1042
	instruction->info.load_store_multiple.Rn = Rn;
	instruction->info.load_store_multiple.register_list = register_list;
	instruction->info.load_store_multiple.S = S;
	instruction->info.load_store_multiple.W = W;
1043

1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
	if (L)
	{
		instruction->type = ARM_LDM;
		mnemonic = "LDM";
	}
	else
	{
		instruction->type = ARM_STM;
		mnemonic = "STM";
	}
1054

1055
1056
1057
	if (P)
	{
		if (U)
1058
1059
		{
			instruction->info.load_store_multiple.addressing_mode = 1;
1060
			addressing_mode = "IB";
1061
		}
1062
		else
1063
1064
		{
			instruction->info.load_store_multiple.addressing_mode = 3;
1065
			addressing_mode = "DB";
1066
		}
1067
1068
1069
1070
	}
	else
	{
		if (U)
1071
1072
		{
			instruction->info.load_store_multiple.addressing_mode = 0;
zwelch's avatar
zwelch committed
1073
1074
			/* "IA" is the default in UAL syntax */
			addressing_mode = "";
1075
		}
1076
		else
1077
1078
		{
			instruction->info.load_store_multiple.addressing_mode = 2;
1079
			addressing_mode = "DA";
1080
		}
1081
	}
1082

1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
	reg_list_p = reg_list;
	for (i = 0; i <= 15; i++)
	{
		if ((register_list >> i) & 1)
		{
			if (first_reg)
			{
				first_reg = 0;
				reg_list_p += snprintf(reg_list_p, (reg_list + 69 - reg_list_p), "r%i", i);
			}
			else
			{
				reg_list_p += snprintf(reg_list_p, (reg_list + 69 - reg_list_p), ", r%i", i);
			}
		}
	}
1099

1100
1101
1102
1103
1104
	snprintf(instruction->text, 128,
			"0x%8.8" PRIx32 "\t0x%8.8" PRIx32
			"\t%s%s%s r%i%s, {%s}%s",
			 address, opcode,
			 mnemonic, addressing_mode, COND(opcode),
1105
			 Rn, (W) ? "!" : "", reg_list, (S) ? "^" : "");
1106

1107
1108
1109
1110
	return ERROR_OK;
}

/* Multiplies, extra load/stores */
1111
static int evaluate_mul_and_extra_ld_st(uint32_t opcode,
1112
		uint32_t address, struct arm_instruction *instruction)
1113
1114
1115
1116
1117
1118
1119
{
	/* Multiply (accumulate) (long) and Swap/swap byte */
	if ((opcode & 0x000000f0) == 0x00000090)
	{
		/* Multiply (accumulate) */
		if ((opcode & 0x0f800000) == 0x00000000)
		{
1120
			uint8_t Rm, Rs, Rn, Rd, S;
1121
1122
1123
1124
1125
			Rm = opcode & 0xf;
			Rs = (opcode & 0xf00) >> 8;
			Rn = (opcode & 0xf000) >> 12;
			Rd = (opcode & 0xf0000) >> 16;
			S = (opcode & 0x00100000) >> 20;
1126

1127
1128
1129
1130
			/* examine A bit (accumulate) */
			if (opcode & 0x00200000)
			{
				instruction->type = ARM_MLA;
duane's avatar
duane committed
1131
				snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMLA%s%s r%i, r%i, r%i, r%i",
1132
1133
1134
1135
1136
						address, opcode, COND(opcode), (S) ? "S" : "", Rd, Rm, Rs, Rn);
			}
			else
			{
				instruction->type = ARM_MUL;
duane's avatar
duane committed
1137
				snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMUL%s%s r%i, r%i, r%i",
1138
1139
						 address, opcode, COND(opcode), (S) ? "S" : "", Rd, Rm, Rs);
			}
1140

1141
1142
			return ERROR_OK;
		}
1143

1144
1145
1146
		/* Multiply (accumulate) long */
		if ((opcode & 0x0f800000) == 0x00800000)
		{
1147
			char* mnemonic = NULL;
1148
			uint8_t Rm, Rs, RdHi, RdLow, S;
1149
1150
1151
1152
1153
			Rm = opcode & 0xf;
			Rs = (opcode & 0xf00) >> 8;
			RdHi = (opcode & 0xf000) >> 12;
			RdLow = (opcode & 0xf0000) >> 16;
			S = (opcode & 0x00100000) >> 20;
1154

1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
			switch ((opcode & 0x00600000) >> 21)
			{
				case 0x0:
					instruction->type = ARM_UMULL;
					mnemonic = "UMULL";
					break;
				case 0x1:
					instruction->type = ARM_UMLAL;
					mnemonic = "UMLAL";
					break;
				case 0x2:
					instruction->type = ARM_SMULL;
					mnemonic = "SMULL";
					break;
				case 0x3:
					instruction->type = ARM_SMLAL;
					mnemonic = "SMLAL";
					break;
			}
1174

duane's avatar
duane committed
1175
			snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, r%i, r%i, r%i",
1176
1177
						address, opcode, mnemonic, COND(opcode), (S) ? "S" : "",
						RdLow, RdHi, Rm, Rs);
1178

1179
1180
			return ERROR_OK;
		}
1181

1182
1183
1184
		/* Swap/swap byte */
		if ((opcode & 0x0f800000) == 0x01000000)
		{
1185
			uint8_t Rm, Rd, Rn;
1186
1187
1188
			Rm = opcode & 0xf;
			Rd = (opcode & 0xf000) >> 12;
			Rn = (opcode & 0xf0000) >> 16;
1189

1190
1191
			/* examine B flag */
			instruction->type = (opcode & 0x00400000) ? ARM_SWPB : ARM_SWP;
1192

duane's avatar
duane committed
1193
			snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s r%i, r%i, [r%i]",
1194
1195
1196
					 address, opcode, (opcode & 0x00400000) ? "SWPB" : "SWP", COND(opcode), Rd, Rm, Rn);
			return ERROR_OK;
		}
1197

1198
	}
1199

1200
1201
1202
	return evaluate_misc_load_store(opcode, address, instruction);
}

1203
static int evaluate_mrs_msr(uint32_t opcode,
1204
		uint32_t address, struct arm_instruction *instruction)
1205
1206
1207
{
	int R = (opcode & 0x00400000) >> 22;
	char *PSR = (R) ? "SPSR" : "CPSR";
1208

1209
1210
1211
1212
	/* Move register to status register (MSR) */
	if (opcode & 0x00200000)
	{
		instruction->type = ARM_MSR;
1213

1214
1215
1216
		/* immediate variant */
		if (opcode & 0x02000000)
		{
1217
1218
			uint8_t immediate = (opcode & 0xff);
			uint8_t rotate = (opcode & 0xf00);
1219

duane's avatar
duane committed
1220
			snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32 ,
1221
1222
1223
1224
1225
1226
					 address, opcode, COND(opcode), PSR,
					 (opcode & 0x10000) ? "c" : "",
					 (opcode & 0x20000) ? "x" : "",
					 (opcode & 0x40000) ? "s" : "",
					 (opcode & 0x80000) ? "f" : "",
					 ror(immediate, (rotate * 2))
1227
);
1228
1229
1230
		}
		else /* register variant */
		{
1231
			uint8_t Rm = opcode & 0xf;
duane's avatar
duane committed
1232
			snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMSR%s %s_%s%s%s%s, r%i",
1233
1234
1235
1236
1237
1238
					 address, opcode, COND(opcode), PSR,
					 (opcode & 0x10000) ? "c" : "",
					 (opcode & 0x20000) ? "x" : "",
					 (opcode & 0x40000) ? "s" : "",
					 (opcode & 0x80000) ? "f" : "",
					 Rm
1239
);
1240
		}
1241

1242
1243
1244
	}
	else /* Move status register to register (MRS) */
	{
1245
		uint8_t Rd;
1246

1247
1248
		instruction->type = ARM_MRS;
		Rd = (opcode & 0x0000f000) >> 12;
1249

duane's avatar
duane committed
1250
		snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMRS%s r%i, %s",
1251
1252
				 address, opcode, COND(opcode), Rd, PSR);
	}
1253

1254
1255
1256
1257
	return ERROR_OK;
}

/* Miscellaneous instructions */