- the 'help' command now takes an optional argument to display help only on a certain...
[fw/openocd] / src / target / arm_disassembler.c
1 /***************************************************************************
2  *   Copyright (C) 2006 by Dominic Rath                                    *
3  *   Dominic.Rath@gmx.de                                                   *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20 #include "arm_disassembler.h"
21
22 #include "log.h"
23
24 #include <strings.h>
25
26 /* textual represenation of the condition field */
27 /* ALways (default) is ommitted (empty string) */
28 char *arm_condition_strings[] =
29 {
30         "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
31 };
32
33 /* make up for C's missing ROR */
34 u32 ror(u32 value, int places) 
35
36         return (value >> places) | (value << (32 - places)); 
37 }
38
39 int evaluate_pld(u32 opcode, u32 address, arm_instruction_t *instruction)
40 {
41         /* PLD */
42         if ((opcode & 0x0d70f0000) == 0x0550f000)
43         {
44                 instruction->type = ARM_PLD;
45                 
46                 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tPLD ...TODO...", address, opcode);
47                 
48                 return ERROR_OK;
49         }
50         else
51         {
52                 instruction->type = ARM_UNDEFINED_INSTRUCTION;
53                 return ERROR_OK;
54         }
55         
56         ERROR("should never reach this point");
57         return -1;
58 }
59
60 int evaluate_swi(u32 opcode, u32 address, arm_instruction_t *instruction)
61 {
62         instruction->type = ARM_SWI;
63         
64         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tSWI 0x%6.6x", address, opcode, (opcode & 0xffffff));
65         
66         return ERROR_OK;
67 }
68
69 int evaluate_blx_imm(u32 opcode, u32 address, arm_instruction_t *instruction)
70 {
71         int offset;
72         u32 immediate;
73         
74         instruction->type = ARM_BLX;
75         immediate = opcode & 0x00ffffff;
76         
77         /* sign extend 24-bit immediate */
78         if (immediate & 0x00800000)
79                 offset = 0xff000000 | immediate;
80         else
81                 offset = immediate;
82         
83         /* shift two bits left */
84         offset <<= 2;
85         
86         /* odd/event halfword */
87         if (opcode & 0x01000000)
88                 offset |= 0x2;
89         
90         instruction->target_address = address + 8 + offset;
91         
92         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tBLX 0x%8.8x", address, opcode, instruction->target_address);
93         
94         return ERROR_OK;
95 }
96
97 int evaluate_b_bl(u32 opcode, u32 address, arm_instruction_t *instruction)
98 {
99         u8 L;
100         u32 immediate;
101         int offset;
102         
103         immediate = opcode & 0x00ffffff;
104         L = (opcode & 0x01000000) >> 24;
105         
106         /* sign extend 24-bit immediate */
107         if (immediate & 0x00800000)
108                 offset = 0xff000000 | immediate;
109         else
110                 offset = immediate;
111         
112         /* shift two bits left */
113         offset <<= 2;
114         
115         instruction->target_address = address + 8 + offset;
116
117         if (L)
118                 instruction->type = ARM_BL;
119         else
120                 instruction->type = ARM_B;
121         
122         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tB%s%s 0x%8.8x", address, opcode,
123                          (L) ? "L" : "", COND(opcode), instruction->target_address);
124         
125         return ERROR_OK;
126 }
127
128 /* Coprocessor load/store and double register transfers */
129 /* both normal and extended instruction space (condition field b1111) */
130 int evaluate_ldc_stc_mcrr_mrrc(u32 opcode, u32 address, arm_instruction_t *instruction)
131 {
132         u8 cp_num = (opcode & 0xf00) >> 8;
133         
134         /* MCRR or MRRC */
135         if (((opcode & 0x0ff00000) == 0x0c400000) || ((opcode & 0x0ff00000) == 0x0c400000))
136         {
137                 u8 cp_opcode, Rd, Rn, CRm;
138                 char *mnemonic;
139                 
140                 cp_opcode = (opcode & 0xf0) >> 4;
141                 Rd = (opcode & 0xf000) >> 12;
142                 Rn = (opcode & 0xf0000) >> 16;
143                 CRm = (opcode & 0xf);
144                 
145                 /* MCRR */
146                 if ((opcode & 0x0ff00000) == 0x0c400000)
147                 {
148                         instruction->type = ARM_MCRR;
149                         mnemonic = "MCRR";
150                 }
151                 
152                 /* MRRC */
153                 if ((opcode & 0x0ff00000) == 0x0c500000)
154                 {
155                         instruction->type = ARM_MRRC;
156                         mnemonic = "MRRC";
157                 }
158                 
159                 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s p%i, %x, r%i, r%i, c%i",
160                                  address, opcode, mnemonic, COND(opcode), cp_num, cp_opcode, Rd, Rn, CRm);
161         }
162         else /* LDC or STC */
163         {
164                 u8 CRd, Rn, offset;
165                 u8 U, N;
166                 char *mnemonic;
167                 char addressing_mode[32];
168                 
169                 CRd = (opcode & 0xf000) >> 12;
170                 Rn = (opcode & 0xf0000) >> 16;
171                 offset = (opcode & 0xff);
172                 
173                 /* load/store */
174                 if (opcode & 0x00100000)
175                 {
176                         instruction->type = ARM_LDC;
177                         mnemonic = "LDC";
178                 }
179                 else
180                 {
181                         instruction->type = ARM_STC;
182                         mnemonic = "STC";
183                 }
184                 
185                 U = (opcode & 0x00800000) >> 23;
186                 N = (opcode & 0x00400000) >> 22;
187                 
188                 /* addressing modes */
189                 if ((opcode & 0x01200000) == 0x01000000) /* immediate offset */
190                         snprintf(addressing_mode, 32, "[r%i, #%s0x%2.2x*4]", Rn, (U) ? "" : "-", offset);
191                 else if ((opcode & 0x01200000) == 0x01200000) /* immediate pre-indexed */
192                         snprintf(addressing_mode, 32, "[r%i, #%s0x%2.2x*4]!", Rn, (U) ? "" : "-", offset);
193                 else if ((opcode & 0x01200000) == 0x00200000) /* immediate post-indexed */
194                         snprintf(addressing_mode, 32, "[r%i], #%s0x%2.2x*4", Rn, (U) ? "" : "-", offset);
195                 else if ((opcode & 0x01200000) == 0x00000000) /* unindexed */
196                         snprintf(addressing_mode, 32, "[r%i], #0x%2.2x", Rn, offset);
197
198                 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s p%i, c%i, %s",
199                                  address, opcode, mnemonic, ((opcode & 0xf0000000) == 0xf0000000) ? COND(opcode) : "2",
200                                  (N) ? "L" : "",
201                                  cp_num, CRd, addressing_mode);
202         }
203         
204         return ERROR_OK;
205 }
206
207 /* Coprocessor data processing instructions */
208 /* Coprocessor register transfer instructions */
209 /* both normal and extended instruction space (condition field b1111) */
210 int evaluate_cdp_mcr_mrc(u32 opcode, u32 address, arm_instruction_t *instruction)
211 {
212         char* cond;
213         char* mnemonic;
214         u8 cp_num, opcode_1, CRd_Rd, CRn, CRm, opcode_2;
215         
216         cond = ((opcode & 0xf0000000) == 0xf0000000) ? "2" : COND(opcode);
217         cp_num = (opcode & 0xf00) >> 8;
218         CRd_Rd = (opcode & 0xf000) >> 12;
219         CRn = (opcode & 0xf0000) >> 16;
220         CRm = (opcode & 0xf);
221         opcode_2 = (opcode & 0xe0) >> 5;
222         
223         /* CDP or MRC/MCR */
224         if (opcode & 0x00000010) /* bit 4 set -> MRC/MCR */
225         {
226                 if (opcode & 0x00100000) /* bit 20 set -> MRC */
227                 {
228                         instruction->type = ARM_MRC;
229                         mnemonic = "MRC";
230                 }
231                 else /* bit 20 not set -> MCR */
232                 {
233                         instruction->type = ARM_MCR;
234                         mnemonic = "MCR";
235                 }
236                 
237                 opcode_1 = (opcode & 0x00e00000) >> 21;
238                 
239                 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s p%i, 0x%2.2x, r%i, c%i, c%i, 0x%2.2x",
240                                  address, opcode, mnemonic, cond,
241                                  cp_num, opcode_1, CRd_Rd, CRn, CRm, opcode_2);
242         }
243         else /* bit 4 not set -> CDP */
244         {
245                 instruction->type = ARM_CDP;
246                 mnemonic = "CDP";
247                 
248                 opcode_1 = (opcode & 0x00f00000) >> 20;
249                 
250                 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s p%i, 0x%2.2x, c%i, c%i, c%i, 0x%2.2x",
251                                  address, opcode, mnemonic, cond,
252                                  cp_num, opcode_1, CRd_Rd, CRn, CRm, opcode_2);
253         }
254         
255         return ERROR_OK;
256 }
257
258 /* Load/store instructions */
259 int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction)
260 {
261         u8 I, P, U, B, W, L;
262         u8 Rn, Rd;
263         char *operation; /* "LDR" or "STR" */
264         char *suffix; /* "", "B", "T", "BT" */
265         char offset[32];
266         
267         /* examine flags */
268         I = (opcode & 0x02000000) >> 25;
269         P = (opcode & 0x01000000) >> 24;
270         U = (opcode & 0x00800000) >> 23;
271         B = (opcode & 0x00400000) >> 22;
272         W = (opcode & 0x00200000) >> 21;
273         L = (opcode & 0x00100000) >> 20;
274         
275         /* target register */
276         Rd = (opcode & 0xf000) >> 12;
277         
278         /* base register */
279         Rn = (opcode & 0xf0000) >> 16;
280         
281         /* determine operation */
282         if (L)
283                 operation = "LDR";
284         else
285                 operation = "STR";
286         
287         /* determine instruction type and suffix */
288         if (B)
289         {
290                 if ((P == 0) && (W == 1))
291                 {
292                         if (L)
293                                 instruction->type = ARM_LDRBT;
294                         else
295                                 instruction->type = ARM_STRBT;
296                         suffix = "BT";
297                 }
298                 else
299                 {
300                         if (L)
301                                 instruction->type = ARM_LDRB;
302                         else
303                                 instruction->type = ARM_STRB;
304                         suffix = "B";
305                 }
306         }
307         else
308         {
309                 if ((P == 0) && (W == 1))
310                 {
311                         if (L)
312                                 instruction->type = ARM_LDRT;
313                         else
314                                 instruction->type = ARM_STRT;
315                         suffix = "T";
316                 }
317                 else
318                 {
319                         if (L)
320                                 instruction->type = ARM_LDR;
321                         else
322                                 instruction->type = ARM_STR;
323                         suffix = "";
324                 }
325         }
326         
327         if (!I) /* #+-<offset_12> */
328         {
329                 u32 offset_12 = (opcode & 0xfff);
330                 snprintf(offset, 32, "#%s0x%x", (U) ? "" : "-", offset_12);
331         }
332         else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
333         {
334                 u8 shift_imm, shift;
335                 u8 Rm;
336                 
337                 shift_imm = (opcode & 0xf80) >> 7;
338                 shift = (opcode & 0x60) >> 5;
339                 Rm = (opcode & 0xf);
340                 
341                 if ((shift_imm == 0x0) && (shift == 0x0)) /* +-<Rm> */
342                 {
343                         snprintf(offset, 32, "%sr%i", (U) ? "" : "-", Rm);
344                 }
345                 else /* +-<Rm>, <Shift>, #<shift_imm> */
346                 {
347                         if (shift == 0x0) /* LSL */
348                         {
349                                 snprintf(offset, 32, "%sr%i, LSL #0x%x", (U) ? "" : "-", Rm, shift_imm);
350                         }
351                         else if (shift == 0x1) /* LSR */
352                         {
353                                 snprintf(offset, 32, "%sr%i, LSR #0x%x", (U) ? "" : "-", Rm, shift_imm);
354                         }
355                         else if (shift == 0x2) /* ASR */
356                         {
357                                 snprintf(offset, 32, "%sr%i, ASR #0x%x", (U) ? "" : "-", Rm, shift_imm);
358                         }
359                         else if (shift == 0x3) /* ROR or RRX */
360                         {
361                                 if (shift_imm == 0x0) /* RRX */
362                                         snprintf(offset, 32, "%sr%i, RRX", (U) ? "" : "-", Rm);
363                                 else
364                                         snprintf(offset, 32, "%sr%i, ROR #0x%x", (U) ? "" : "-", Rm, shift_imm);
365                         }
366                 }
367         }
368         
369         if (P == 1)
370         {
371                 if (W == 0) /* offset */
372                 {
373                         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]",
374                                          address, opcode, operation, COND(opcode), suffix,
375                                          Rd, Rn, offset);
376                 }
377                 else /* pre-indexed */
378                 {
379                         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]!",
380                                          address, opcode, operation, COND(opcode), suffix,
381                                          Rd, Rn, offset);
382                 }
383         }
384         else /* post-indexed */
385         {
386                 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i], %s",
387                                  address, opcode, operation, COND(opcode), suffix,
388                                  Rd, Rn, offset);
389         }
390         
391         return ERROR_OK;
392 }
393
394 /* Miscellaneous load/store instructions */
395 int evaluate_misc_load_store(u32 opcode, u32 address, arm_instruction_t *instruction)
396 {
397         u8 P, U, I, W, L, S, H;
398         u8 Rn, Rd;
399         char *operation; /* "LDR" or "STR" */
400         char *suffix; /* "H", "SB", "SH", "D" */
401         char offset[32];
402         
403         /* examine flags */
404         P = (opcode & 0x01000000) >> 24;
405         U = (opcode & 0x00800000) >> 23;
406         I = (opcode & 0x00400000) >> 22;
407         W = (opcode & 0x00200000) >> 21;
408         L = (opcode & 0x00100000) >> 20;
409         S = (opcode & 0x00000040) >> 6;
410         H = (opcode & 0x00000020) >> 5;
411         
412         /* target register */
413         Rd = (opcode & 0xf000) >> 12;
414         
415         /* base register */
416         Rn = (opcode & 0xf0000) >> 16;
417         
418         /* determine instruction type and suffix */
419         if (S) /* signed */
420         {
421                 if (L) /* load */
422                 {
423                         if (H)
424                         {
425                                 operation = "LDR";
426                                 instruction->type = ARM_LDRSH;
427                                 suffix = "SH";
428                         }
429                         else
430                         {
431                                 operation = "LDR";
432                                 instruction->type = ARM_LDRSB;
433                                 suffix = "SB";
434                         }
435                 }
436                 else /* there are no signed stores, so this is used to encode double-register load/stores */
437                 {
438                         suffix = "D";
439                         if (H)
440                         {
441                                 operation = "STR";
442                                 instruction->type = ARM_STRD;
443                         }
444                         else
445                         {
446                                 operation = "LDR";
447                                 instruction->type = ARM_LDRD;
448                         }
449                 }
450         }
451         else /* unsigned */
452         {
453                 suffix = "H";
454                 if (L) /* load */
455                 {
456                         operation = "LDR";
457                         instruction->type = ARM_LDRH;
458                 }
459                 else /* store */
460                 {
461                         operation = "STR";
462                         instruction->type = ARM_STRH;
463                 }
464         }
465         
466         if (I) /* Immediate offset/index (#+-<offset_8>)*/
467         {
468                 u32 offset_8 = ((opcode & 0xf00) >> 4) | (opcode & 0xf);
469                 snprintf(offset, 32, "#%s0x%x", (U) ? "" : "-", offset_8);
470         }
471         else /* Register offset/index (+-<Rm>) */
472         {
473                 u8 Rm;
474                 Rm = (opcode & 0xf);
475                 snprintf(offset, 32, "%sr%i", (U) ? "" : "-", Rm);
476         }
477         
478         if (P == 1)
479         {
480                 if (W == 0) /* offset */
481                 {
482                         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]",
483                                          address, opcode, operation, COND(opcode), suffix,
484                                          Rd, Rn, offset);
485                 }
486                 else /* pre-indexed */
487                 {
488                         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]!",
489                                          address, opcode, operation, COND(opcode), suffix,
490                                          Rd, Rn, offset);
491                 }
492         }
493         else /* post-indexed */
494         {
495                 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i], %s",
496                                  address, opcode, operation, COND(opcode), suffix,
497                                  Rd, Rn, offset);
498         }
499         
500         return ERROR_OK;
501 }
502
503 /* Load/store multiples instructions */
504 int evaluate_ldm_stm(u32 opcode, u32 address, arm_instruction_t *instruction)
505 {
506         u8 P, U, S, W, L, Rn;
507         u32 register_list;
508         char *addressing_mode;
509         char *mnemonic;
510         char reg_list[69];
511         char *reg_list_p;
512         int i;
513         int first_reg = 1;
514         
515         P = (opcode & 0x01000000) >> 24;
516         U = (opcode & 0x00800000) >> 23;
517         S = (opcode & 0x00400000) >> 22;
518         W = (opcode & 0x00200000) >> 21;
519         L = (opcode & 0x00100000) >> 20;
520         register_list = (opcode & 0xffff);
521         Rn = (opcode & 0xf0000) >> 16;
522         
523         if (L)
524         {
525                 instruction->type = ARM_LDM;
526                 mnemonic = "LDM";
527         }
528         else
529         {
530                 instruction->type = ARM_STM;
531                 mnemonic = "STM";
532         }
533         
534         if (P)
535         {
536                 if (U)
537                         addressing_mode = "IB";
538                 else
539                         addressing_mode = "DB";
540         }
541         else
542         {
543                 if (U)
544                         addressing_mode = "IA";
545                 else
546                         addressing_mode = "DA";
547         }
548         
549         reg_list_p = reg_list;
550         for (i = 0; i <= 15; i++)
551         {
552                 if ((register_list >> i) & 1)
553                 {
554                         if (first_reg)
555                         {
556                                 first_reg = 0;
557                                 reg_list_p += snprintf(reg_list_p, (reg_list + 69 - reg_list_p), "r%i", i);
558                         }
559                         else
560                         {
561                                 reg_list_p += snprintf(reg_list_p, (reg_list + 69 - reg_list_p), ", r%i", i);
562                         }
563                 }
564         }
565         
566         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i%s, {%s}%s",
567                          address, opcode, mnemonic, COND(opcode), addressing_mode,
568                          Rn, (W) ? "!" : "", reg_list, (S) ? "^" : "");
569         
570         return ERROR_OK;
571 }
572
573 /* Multiplies, extra load/stores */
574 int evaluate_mul_and_extra_ld_st(u32 opcode, u32 address, arm_instruction_t *instruction)
575 {
576         /* Multiply (accumulate) (long) and Swap/swap byte */
577         if ((opcode & 0x000000f0) == 0x00000090)
578         {
579                 /* Multiply (accumulate) */
580                 if ((opcode & 0x0f800000) == 0x00000000)
581                 {
582                         u8 Rm, Rs, Rn, Rd, S;
583                         Rm = opcode & 0xf;
584                         Rs = (opcode & 0xf00) >> 8;
585                         Rn = (opcode & 0xf000) >> 12;
586                         Rd = (opcode & 0xf0000) >> 16;
587                         S = (opcode & 0x00100000) >> 20;
588                         
589                         /* examine A bit (accumulate) */
590                         if (opcode & 0x00200000)
591                         {
592                                 instruction->type = ARM_MLA;
593                                 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tMLA%s%s r%i, r%i, r%i, r%i",
594                                                 address, opcode, COND(opcode), (S) ? "S" : "", Rd, Rm, Rs, Rn);
595                         }
596                         else
597                         {
598                                 instruction->type = ARM_MUL;
599                                 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tMUL%s%s r%i, r%i, r%i",
600                                                  address, opcode, COND(opcode), (S) ? "S" : "", Rd, Rm, Rs);
601                         }
602                         
603                         return ERROR_OK;
604                 }
605                 
606                 /* Multiply (accumulate) long */
607                 if ((opcode & 0x0f800000) == 0x00800000)
608                 {
609                         char* mnemonic;
610                         u8 Rm, Rs, RdHi, RdLow, S;
611                         Rm = opcode & 0xf;
612                         Rs = (opcode & 0xf00) >> 8;
613                         RdHi = (opcode & 0xf000) >> 12;
614                         RdLow = (opcode & 0xf0000) >> 16;
615                         S = (opcode & 0x00100000) >> 20;
616                         
617                         switch ((opcode & 0x00600000) >> 21)
618                         {
619                                 case 0x0:
620                                         instruction->type = ARM_UMULL;
621                                         mnemonic = "UMULL";
622                                         break;
623                                 case 0x1:
624                                         instruction->type = ARM_UMLAL;
625                                         mnemonic = "UMLAL";
626                                         break;
627                                 case 0x2:
628                                         instruction->type = ARM_SMULL;
629                                         mnemonic = "SMULL";
630                                         break;
631                                 case 0x3:
632                                         instruction->type = ARM_SMLAL;
633                                         mnemonic = "SMLAL";
634                                         break;
635                         }
636                         
637                         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, r%i, r%i, r%i",
638                                                 address, opcode, mnemonic, COND(opcode), (S) ? "S" : "",
639                                                 RdLow, RdHi, Rm, Rs);
640                         
641                         return ERROR_OK;
642                 }
643                 
644                 /* Swap/swap byte */
645                 if ((opcode & 0x0f800000) == 0x01000000)
646                 {
647                         u8 Rm, Rd, Rn;
648                         Rm = opcode & 0xf;
649                         Rd = (opcode & 0xf000) >> 12;
650                         Rn = (opcode & 0xf0000) >> 16;
651                         
652                         /* examine B flag */
653                         instruction->type = (opcode & 0x00400000) ? ARM_SWPB : ARM_SWP;
654                         
655                         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, r%i, [r%i]",
656                                          address, opcode, (opcode & 0x00400000) ? "SWPB" : "SWP", COND(opcode), Rd, Rm, Rn);
657                         return ERROR_OK;
658                 }
659                 
660         }
661         
662         return evaluate_misc_load_store(opcode, address, instruction);
663 }
664
665 int evaluate_mrs_msr(u32 opcode, u32 address, arm_instruction_t *instruction)
666 {
667         int R = (opcode & 0x00400000) >> 22;
668         char *PSR = (R) ? "SPSR" : "CPSR";
669                 
670         /* Move register to status register (MSR) */
671         if (opcode & 0x00200000)
672         {
673                 instruction->type = ARM_MSR;
674                         
675                 /* immediate variant */
676                 if (opcode & 0x02000000)
677                 {
678                         u8 immediate = (opcode & 0xff);
679                         u8 rotate = (opcode & 0xf00);
680                         
681                         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tMSR%s %s_%s%s%s%s, 0x%8.8x",
682                                          address, opcode, COND(opcode), PSR,
683                                          (opcode & 0x10000) ? "c" : "",
684                                          (opcode & 0x20000) ? "x" : "",
685                                          (opcode & 0x40000) ? "s" : "",
686                                          (opcode & 0x80000) ? "f" : "",
687                                          ror(immediate, (rotate * 2))
688                                         );
689                 }
690                 else /* register variant */
691                 {
692                         u8 Rm = opcode & 0xf;
693                         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tMSR%s %s_%s%s%s%s, r%i",
694                                          address, opcode, COND(opcode), PSR,
695                                          (opcode & 0x10000) ? "c" : "",
696                                          (opcode & 0x20000) ? "x" : "",
697                                          (opcode & 0x40000) ? "s" : "",
698                                          (opcode & 0x80000) ? "f" : "",
699                                          Rm
700                                         );
701                 }
702                 
703         }
704         else /* Move status register to register (MRS) */
705         {
706                 u8 Rd;
707                 
708                 instruction->type = ARM_MRS;
709                 Rd = (opcode & 0x0000f000) >> 12;
710                         
711                 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tMRS%s r%i, %s",
712                                  address, opcode, COND(opcode), Rd, PSR);
713         }
714         
715         return ERROR_OK;
716 }
717
718 /* Miscellaneous instructions */
719 int evaluate_misc_instr(u32 opcode, u32 address, arm_instruction_t *instruction)
720 {
721         /* MRS/MSR */
722         if ((opcode & 0x000000f0) == 0x00000000)
723         {
724                 evaluate_mrs_msr(opcode, address, instruction);
725         }
726         
727         /* BX */
728         if ((opcode & 0x006000f0) == 0x00200010)
729         {
730                 u8 Rm;
731                 instruction->type = ARM_BX;
732                 Rm = opcode & 0xf;
733                 
734                 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tBX%s r%i",
735                                  address, opcode, COND(opcode), Rm);
736         }
737         
738         /* CLZ */
739         if ((opcode & 0x0060000f0) == 0x00300010)
740         {
741                 u8 Rm, Rd;
742                 instruction->type = ARM_CLZ;
743                 Rm = opcode & 0xf;
744                 Rd = (opcode & 0xf000) >> 12;
745
746                 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tCLZ%s r%i, r%i",
747                                  address, opcode, COND(opcode), Rd, Rm);
748         }
749         
750         /* BLX */
751         if ((opcode & 0x0060000f0) == 0x00200030)
752         {
753                 u8 Rm;
754                 instruction->type = ARM_BLX;
755                 Rm = opcode & 0xf;
756                 
757                 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tBLX%s r%i",
758                                  address, opcode, COND(opcode), Rm);
759         }
760         
761         /* Enhanced DSP add/subtracts */
762         if ((opcode & 0x0000000f0) == 0x00000050)
763         {
764                 u8 Rm, Rd, Rn;
765                 char *mnemonic;
766                 Rm = opcode & 0xf;
767                 Rd = (opcode & 0xf000) >> 12;
768                 Rn = (opcode & 0xf0000) >> 16;
769                 
770                 switch ((opcode & 0x00600000) >> 21)
771                 {
772                         case 0x0:
773                                 instruction->type = ARM_QADD;
774                                 mnemonic = "QADD";
775                                 break;
776                         case 0x1:
777                                 instruction->type = ARM_QSUB;
778                                 mnemonic = "QSUB";
779                                 break;
780                         case 0x2:
781                                 instruction->type = ARM_QDADD;
782                                 mnemonic = "QDADD";
783                                 break;
784                         case 0x3:
785                                 instruction->type = ARM_QDSUB;
786                                 mnemonic = "QDSUB";
787                                 break;
788                 }
789                 
790                 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, r%i, r%i",
791                                  address, opcode, mnemonic, COND(opcode), Rd, Rm, Rn);
792         }
793         
794         /* Software breakpoints */
795         if ((opcode & 0x0000000f0) == 0x00000070)
796         {
797                 u32 immediate;
798                 instruction->type = ARM_BKPT;
799                 immediate = ((opcode & 0x000fff00) >> 4) | (opcode & 0xf);
800                 
801                 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tBKPT 0x%4.4x",
802                                  address, opcode, immediate);   
803         }
804         
805         /* Enhanced DSP multiplies */
806         if ((opcode & 0x000000090) == 0x00000080)
807         {
808                 int x = (opcode & 0x20) >> 5;
809                 int y = (opcode & 0x40) >> 6;
810                 
811                 /* SMLA<x><y> */
812                 if ((opcode & 0x00600000) == 0x00000000)
813                 {
814                         u8 Rd, Rm, Rs, Rn;
815                         instruction->type = ARM_SMLAxy;
816                         Rd = (opcode & 0xf0000) >> 16;
817                         Rm = (opcode & 0xf);
818                         Rs = (opcode & 0xf00) >> 8;
819                         Rn = (opcode & 0xf000) >> 12;
820                         
821                         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tSMLA%s%s%s r%i, r%i, r%i, r%i",
822                                          address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode),
823                                          Rd, Rm, Rs, Rn);
824                 }
825                 
826                 /* SMLAL<x><y> */
827                 if ((opcode & 0x00600000) == 0x00400000)
828                 {
829                         u8 RdLow, RdHi, Rm, Rs;
830                         instruction->type = ARM_SMLAxy;
831                         RdHi = (opcode & 0xf0000) >> 16;
832                         RdLow = (opcode & 0xf000) >> 12;
833                         Rm = (opcode & 0xf);
834                         Rs = (opcode & 0xf00) >> 8;
835                         
836                         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tSMLA%s%s%s r%i, r%i, r%i, r%i",
837                                          address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode),
838                                          RdLow, RdHi, Rm, Rs);
839                 }
840                 
841                 /* SMLAW<y> */
842                 if (((opcode & 0x00600000) == 0x00100000) && (x == 0))
843                 {
844                         u8 Rd, Rm, Rs, Rn;
845                         instruction->type = ARM_SMLAWy;
846                         Rd = (opcode & 0xf0000) >> 16;
847                         Rm = (opcode & 0xf);
848                         Rs = (opcode & 0xf00) >> 8;
849                         Rn = (opcode & 0xf000) >> 12;
850
851                         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tSMLAW%s%s r%i, r%i, r%i, r%i",
852                                          address, opcode, (y) ? "T" : "B", COND(opcode),
853                                          Rd, Rm, Rs, Rn);
854                 }
855                 
856                 /* SMUL<x><y> */
857                 if ((opcode & 0x00600000) == 0x00300000)
858                 {
859                         u8 Rd, Rm, Rs;
860                         instruction->type = ARM_SMULxy;
861                         Rd = (opcode & 0xf0000) >> 16;
862                         Rm = (opcode & 0xf);
863                         Rs = (opcode & 0xf00) >> 8;
864                         
865                         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tSMULW%s%s%s r%i, r%i, r%i",
866                                          address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode),
867                                          Rd, Rm, Rs);
868                 }
869                 
870                 /* SMULW<y> */
871                 if (((opcode & 0x00600000) == 0x00100000) && (x == 1))
872                 {
873                         u8 Rd, Rm, Rs;
874                         instruction->type = ARM_SMULWy;
875                         Rd = (opcode & 0xf0000) >> 16;
876                         Rm = (opcode & 0xf);
877                         Rs = (opcode & 0xf00) >> 8;
878                         
879                         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tSMULW%s%s r%i, r%i, r%i",
880                                          address, opcode, (y) ? "T" : "B", COND(opcode),
881                                          Rd, Rm, Rs);
882                 }
883         }
884         
885         return ERROR_OK;
886 }
887
888 int evaluate_data_proc(u32 opcode, u32 address, arm_instruction_t *instruction)
889 {
890         u8 I, op, S, Rn, Rd;
891         char *mnemonic;
892         char shifter_operand[32];
893         
894         I = (opcode & 0x02000000) >> 25;
895         op = (opcode & 0x01e00000) >> 21;
896         S = (opcode & 0x00100000) >> 20;
897         
898         Rd = (opcode & 0xf000) >> 12;
899         Rn = (opcode & 0xf0000) >> 16;
900         
901         switch (op)
902         {
903                 case 0x0:
904                         instruction->type = ARM_AND;
905                         mnemonic = "AND";
906                         break;
907                 case 0x1:
908                         instruction->type = ARM_EOR;
909                         mnemonic = "EOR";
910                         break;
911                 case 0x2:
912                         instruction->type = ARM_SUB;
913                         mnemonic = "SUB";
914                         break;
915                 case 0x3:
916                         instruction->type = ARM_RSB;
917                         mnemonic = "RSB";
918                         break;
919                 case 0x4:
920                         instruction->type = ARM_ADD;
921                         mnemonic = "ADD";
922                         break;
923                 case 0x5:
924                         instruction->type = ARM_ADC;
925                         mnemonic = "ADC";
926                         break;
927                 case 0x6:
928                         instruction->type = ARM_SBC;
929                         mnemonic = "SBC";
930                         break;
931                 case 0x7:
932                         instruction->type = ARM_RSC;
933                         mnemonic = "RSC";
934                         break;
935                 case 0x8:
936                         instruction->type = ARM_TST;
937                         mnemonic = "TST";
938                         break;
939                 case 0x9:
940                         instruction->type = ARM_TEQ;
941                         mnemonic = "TEQ";
942                         break;
943                 case 0xa:
944                         instruction->type = ARM_CMP;
945                         mnemonic = "CMP";
946                         break;
947                 case 0xb:
948                         instruction->type = ARM_CMN;
949                         mnemonic = "CMN";
950                         break;
951                 case 0xc:
952                         instruction->type = ARM_ORR;
953                         mnemonic = "ORR";
954                         break;
955                 case 0xd:
956                         instruction->type = ARM_MOV;
957                         mnemonic = "MOV";
958                         break;
959                 case 0xe:
960                         instruction->type = ARM_BIC;
961                         mnemonic = "BIC";
962                         break;
963                 case 0xf:
964                         instruction->type = ARM_MVN;
965                         mnemonic = "MVN";
966                         break;
967         }
968         
969         if (I) /* immediate shifter operand (#<immediate>)*/
970         {
971                 u8 immed_8 = opcode & 0xff;
972                 u8 rotate_imm = (opcode & 0xf00) >> 8;
973                 u32 immediate;
974                 
975                 immediate = ror(immed_8, rotate_imm * 2);
976                 
977                 snprintf(shifter_operand, 32, "#0x%x", immediate);
978         }
979         else /* register-based shifter operand */
980         {
981                 u8 shift, Rm;
982                 shift = (opcode & 0x60) >> 5;
983                 Rm = (opcode & 0xf);
984                 
985                 if ((opcode & 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
986                 {
987                         u8 shift_imm;
988                         shift_imm = (opcode & 0xf80) >> 7;
989
990                         
991                         if ((shift_imm == 0x0) && (shift == 0x0))
992                         {
993                                 snprintf(shifter_operand, 32, "r%i", Rm);
994                         }
995                         else
996                         {
997                                 if (shift == 0x0) /* LSL */
998                                 {
999                                         snprintf(shifter_operand, 32, "r%i, LSL #0x%x", Rm, shift_imm);
1000                                 }
1001                                 else if (shift == 0x1) /* LSR */
1002                                 {
1003                                         if (shift_imm == 0x0)
1004                                                 shift_imm = 0x32;
1005                                         snprintf(shifter_operand, 32, "r%i, LSR #0x%x", Rm, shift_imm);
1006                                 }
1007                                 else if (shift == 0x2) /* ASR */
1008                                 {
1009                                         if (shift_imm == 0x0)
1010                                                 shift_imm = 0x32;
1011                                         snprintf(shifter_operand, 32, "r%i, ASR #0x%x", Rm, shift_imm);
1012                                 }
1013                                 else if (shift == 0x3) /* ROR or RRX */
1014                                 {
1015                                         if (shift_imm == 0x0) /* RRX */
1016                                                 snprintf(shifter_operand, 32, "r%i, RRX", Rm);
1017                                         else
1018                                                 snprintf(shifter_operand, 32, "r%i, ROR #0x%x", Rm, shift_imm);
1019                                 }
1020                         }
1021                 }
1022                 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1023                 {
1024                         u8 Rs = (opcode & 0xf00) >> 8;
1025                         
1026                         if (shift == 0x0) /* LSL */
1027                         {
1028                                 snprintf(shifter_operand, 32, "r%i, LSL r%i", Rm, Rs);
1029                         }
1030                         else if (shift == 0x1) /* LSR */
1031                         {
1032                                 snprintf(shifter_operand, 32, "r%i, LSR r%i", Rm, Rs);
1033                         }
1034                         else if (shift == 0x2) /* ASR */
1035                         {
1036                                 snprintf(shifter_operand, 32, "r%i, ASR r%i", Rm, Rs);
1037                         }
1038                         else if (shift == 0x3) /* ROR or RRX */
1039                         {
1040                                 snprintf(shifter_operand, 32, "r%i, ROR r%i", Rm, Rs);
1041                         }
1042                 }
1043         }
1044         
1045         if ((op < 0x8) || (op == 0xc) || (op == 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1046         {
1047                 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, r%i, %s",
1048                                  address, opcode, mnemonic, COND(opcode),
1049                                  (S) ? "S" : "", Rd, Rn, shifter_operand);
1050         }
1051         else if ((op == 0xd) || (op == 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1052         {
1053                 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, %s",
1054                                  address, opcode, mnemonic, COND(opcode),
1055                                  (S) ? "S" : "", Rd, shifter_operand);
1056         }
1057         else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1058         {
1059                 snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, %s",
1060                                  address, opcode, mnemonic, COND(opcode),
1061                                  Rn, shifter_operand);
1062         }
1063         
1064         return ERROR_OK;
1065 }
1066                 
1067 int evaluate_opcode(u32 opcode, u32 address, arm_instruction_t *instruction)
1068 {
1069         /* clear fields, to avoid confusion */
1070         bzero(instruction, sizeof(arm_instruction_t));
1071         instruction->opcode = opcode;
1072         
1073         /* catch opcodes with condition field [31:28] = b1111 */
1074         if ((opcode & 0xf0000000) == 0xf0000000)
1075         {
1076                 /* Undefined instruction (or ARMv5E cache preload PLD) */
1077                 if ((opcode & 0x08000000) == 0x00000000)
1078                         return evaluate_pld(opcode, address, instruction);
1079                 
1080                 /* Undefined instruction */
1081                 if ((opcode & 0x0e000000) == 0x08000000)
1082                 {
1083                         instruction->type = ARM_UNDEFINED_INSTRUCTION;
1084                         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address, opcode);
1085                         return ERROR_OK;
1086                 }
1087                 
1088                 /* Branch and branch with link and change to Thumb */
1089                 if ((opcode & 0x0e000000) == 0x0a000000)
1090                         return evaluate_blx_imm(opcode, address, instruction);
1091                 
1092                 /* Extended coprocessor opcode space (ARMv5 and higher )*/
1093                 /* Coprocessor load/store and double register transfers */
1094                 if ((opcode & 0x0e000000) == 0x0c000000)
1095                         return evaluate_ldc_stc_mcrr_mrrc(opcode, address, instruction);
1096                 
1097                 /* Coprocessor data processing */
1098                 if ((opcode & 0x0f000100) == 0x0c000000)
1099                         return evaluate_cdp_mcr_mrc(opcode, address, instruction);
1100                 
1101                 /* Coprocessor register transfers */
1102                 if ((opcode & 0x0f000010) == 0x0c000010)
1103                         return evaluate_cdp_mcr_mrc(opcode, address, instruction);
1104                 
1105                 /* Undefined instruction */
1106                 if ((opcode & 0x0f000000) == 0x0f000000)
1107                 {
1108                         instruction->type = ARM_UNDEFINED_INSTRUCTION;
1109                         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address, opcode);
1110                         return ERROR_OK;
1111                 }
1112         }
1113         
1114         /* catch opcodes with [27:25] = b000 */
1115         if ((opcode & 0x0e000000) == 0x00000000)
1116         {
1117                 /* Multiplies, extra load/stores */
1118                 if ((opcode & 0x00000090) == 0x00000090)
1119                         return evaluate_mul_and_extra_ld_st(opcode, address, instruction);
1120                 
1121                 /* Miscellaneous instructions */
1122                 if ((opcode & 0x0f900000) == 0x01000000)
1123                         return evaluate_misc_instr(opcode, address, instruction);
1124                 
1125                 return evaluate_data_proc(opcode, address, instruction);
1126         }
1127         
1128         /* catch opcodes with [27:25] = b001 */
1129         if ((opcode & 0x0e000000) == 0x02000000)
1130         {
1131                 /* Undefined instruction */
1132                 if ((opcode & 0x0fb00000) == 0x03000000)
1133                 {
1134                         instruction->type = ARM_UNDEFINED_INSTRUCTION;
1135                         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address, opcode);
1136                         return ERROR_OK;
1137                 }
1138                                 
1139                 /* Move immediate to status register */
1140                 if ((opcode & 0x0fb00000) == 0x03200000)
1141                         return evaluate_mrs_msr(opcode, address, instruction);
1142                 
1143                 return evaluate_data_proc(opcode, address, instruction);
1144
1145         }
1146         
1147         /* catch opcodes with [27:25] = b010 */
1148         if ((opcode & 0x0e000000) == 0x04000000)
1149         {
1150                 /* Load/store immediate offset */
1151                 return evaluate_load_store(opcode, address, instruction);
1152         }
1153         
1154         /* catch opcodes with [27:25] = b011 */
1155         if ((opcode & 0x0e000000) == 0x04000000)
1156         {
1157                 /* Undefined instruction */
1158                 if ((opcode & 0x00000010) == 0x00000010)
1159                 {
1160                         instruction->type = ARM_UNDEFINED_INSTRUCTION;
1161                         snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address, opcode);
1162                         return ERROR_OK;
1163                 }
1164                 
1165                 /* Load/store register offset */
1166                 return evaluate_load_store(opcode, address, instruction);
1167
1168         }
1169         
1170         /* catch opcodes with [27:25] = b100 */
1171         if ((opcode & 0x0e000000) == 0x08000000)
1172         {
1173                 /* Load/store multiple */
1174                 return evaluate_ldm_stm(opcode, address, instruction);
1175         }
1176         
1177         /* catch opcodes with [27:25] = b101 */
1178         if ((opcode & 0x0e000000) == 0x0a000000)
1179         {
1180                 /* Branch and branch with link */
1181                 return evaluate_b_bl(opcode, address, instruction);
1182         }
1183         
1184         /* catch opcodes with [27:25] = b110 */
1185         if ((opcode & 0x0e000000) == 0x0a000000)
1186         {
1187                 /* Coprocessor load/store and double register transfers */
1188                 return evaluate_ldc_stc_mcrr_mrrc(opcode, address, instruction);
1189         }
1190         
1191         /* catch opcodes with [27:25] = b111 */
1192         if ((opcode & 0x0e000000) == 0x0e000000)
1193         {
1194                 /* Software interrupt */
1195                 if ((opcode & 0x0f000000) == 0x0f000000)
1196                         return evaluate_swi(opcode, address, instruction);
1197                 
1198                 /* Coprocessor data processing */
1199                 if ((opcode & 0x0f000010) == 0x0e000000)
1200                         return evaluate_cdp_mcr_mrc(opcode, address, instruction);
1201                 
1202                 /* Coprocessor register transfers */
1203                 if ((opcode & 0x0f000010) == 0x0e000010)
1204                         return evaluate_cdp_mcr_mrc(opcode, address, instruction);
1205         }
1206         
1207         ERROR("should never reach this point");
1208         return -1;
1209 }