2000-10-04 Kazu Hirata <kazu@hxi.com>
[external/binutils.git] / opcodes / tic54x-dis.c
1 /* Disassembly routines for TMS320C54X architecture
2    Copyright (C) 1999,2000 Free Software Foundation, Inc.
3    Contributed by Timothy Wall (twall@cygnus.com)
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 Free Software
17    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18    02111-1307, USA.  */
19
20 #include <errno.h>
21 #include <math.h>
22 #include <stdlib.h>
23 #include "sysdep.h"
24 #include "dis-asm.h"
25 #include "opcode/tic54x.h"
26 #include "coff/tic54x.h"
27
28 typedef struct _instruction {
29   int parallel;
30   template *tm;
31   partemplate *ptm;
32 } instruction;
33
34 static int get_insn_size PARAMS ((unsigned short, instruction *));
35 static int get_instruction PARAMS ((disassemble_info *, bfd_vma, 
36                                     unsigned short, instruction *));
37 static int print_instruction PARAMS ((disassemble_info *, bfd_vma, 
38                                       unsigned short, char *, 
39                                       enum optype [], int, int));
40 static int print_parallel_instruction PARAMS ((disassemble_info *, bfd_vma,
41                                                unsigned short, partemplate *,
42                                                int)); 
43 static int sprint_dual_address (disassemble_info *,char [], 
44                                 unsigned short);
45 static int sprint_indirect_address (disassemble_info *,char [], 
46                                     unsigned short);
47 static int sprint_direct_address (disassemble_info *,char [], 
48                                   unsigned short);
49 static int sprint_mmr (disassemble_info *,char [],int);
50 static int sprint_condition (disassemble_info *,char *,unsigned short);
51 static int sprint_cc2 (disassemble_info *,char *,unsigned short);
52
53 int
54 print_insn_tic54x(memaddr, info)
55   bfd_vma memaddr;
56   disassemble_info *info;
57 {
58   bfd_byte opbuf[2]; 
59   unsigned short opcode;
60   int status, size;
61   instruction insn;
62
63   status = (*info->read_memory_func) (memaddr, opbuf, 2, info);
64   if (status != 0)
65   {
66     (*info->memory_error_func)(status, memaddr, info);
67     return -1;
68   }
69
70   opcode = bfd_getl16(opbuf);
71   if (!get_instruction (info, memaddr, opcode, &insn))
72       return -1;
73
74   size = get_insn_size (opcode, &insn);
75   info->bytes_per_line = 2;
76   info->bytes_per_chunk = 2;
77   info->octets_per_byte = 2;
78   info->display_endian = BFD_ENDIAN_LITTLE;
79
80   if (insn.parallel)
81   {
82     if (!print_parallel_instruction (info, memaddr, opcode, insn.ptm, size))
83       return -1;
84   }
85   else
86   {
87     if (!print_instruction (info, memaddr, opcode, 
88                             (char *)insn.tm->name, 
89                             insn.tm->operand_types,
90                             size, (insn.tm->flags & FL_EXT)))
91       return -1;
92   }
93
94   return size*2;
95 }
96
97 static int
98 has_lkaddr(opcode, tm)
99   unsigned short opcode;
100   template *tm;
101 {
102   return IS_LKADDR(opcode) && 
103     (OPTYPE(tm->operand_types[0]) == OP_Smem ||
104      OPTYPE(tm->operand_types[1]) == OP_Smem ||
105      OPTYPE(tm->operand_types[2]) == OP_Smem ||
106      OPTYPE(tm->operand_types[1]) == OP_Sind);
107 }
108
109 /* always returns 1 (whether an insn template was found) since we provide an
110    "unknown instruction" template */
111 static int 
112 get_instruction (info, addr, opcode, insn)
113   disassemble_info *info;
114   bfd_vma addr;
115   unsigned short opcode;
116   instruction *insn;
117 {
118   template * tm;
119   partemplate * ptm;
120
121   insn->parallel = 0;
122   for (tm = (template *)tic54x_optab; tm->name; tm++)
123   {
124     if (tm->opcode == (opcode & tm->mask))
125     {
126       /* a few opcodes span two words */
127       if (tm->flags & FL_EXT)
128         {
129           /* if lk addressing is used, the second half of the opcode gets
130              pushed one word later */
131           bfd_byte opbuf[2];
132           bfd_vma addr2 = addr + 1 + has_lkaddr(opcode, tm);
133           int status = (*info->read_memory_func)(addr2, opbuf, 2, info);
134           if (status == 0)
135             {
136               unsigned short opcode2 = bfd_getl16(opbuf);
137               if (tm->opcode2 == (opcode2 & tm->mask2))
138                 {
139                   insn->tm = tm;
140                   return 1;
141                 }
142             }
143         }
144       else
145         {
146           insn->tm = tm;
147           return 1;
148         }
149     }
150   }
151   for (ptm = (partemplate *)tic54x_paroptab; ptm->name; ptm++)
152   {
153     if (ptm->opcode == (opcode & ptm->mask))
154     {
155       insn->parallel = 1;
156       insn->ptm = ptm;
157       return 1;
158     }
159   }
160
161   insn->tm = (template *)&tic54x_unknown_opcode;
162   return 1;
163 }
164
165 static int 
166 get_insn_size (opcode, insn)
167   unsigned short opcode;
168   instruction *insn;
169 {
170   int size;
171
172   if (insn->parallel)
173     {
174       /* only non-parallel instructions support lk addressing */
175       size = insn->ptm->words;
176     }
177   else
178     {
179       size = insn->tm->words + has_lkaddr(opcode, insn->tm);
180     }
181
182   return size;
183 }
184
185 int
186 print_instruction (info, memaddr, opcode, tm_name, tm_operands, size, ext)
187   disassemble_info *info;
188   bfd_vma memaddr;
189   unsigned short opcode;
190   char *tm_name;
191   enum optype tm_operands[];
192   int size;
193   int ext;
194 {
195   static int n;
196   /* string storage for multiple operands */
197   char operand[4][64] = { {0},{0},{0},{0}, };
198   bfd_byte buf[2];
199   unsigned long opcode2, lkaddr;
200   enum optype src = OP_None;
201   enum optype dst = OP_None;
202   int i, shift;
203   char *comma = "";
204
205   info->fprintf_func (info->stream, "%-7s", tm_name);
206
207   if (size > 1)
208     {
209       int status = (*info->read_memory_func) (memaddr+1, buf, 2, info);
210       if (status != 0)
211         return 0;
212       lkaddr = opcode2 = bfd_getl16(buf);
213       if (size > 2)
214         {
215           status = (*info->read_memory_func) (memaddr+2, buf, 2, info);
216           if (status != 0)
217             return 0;
218           opcode2 = bfd_getl16(buf);
219         }
220     }
221
222   for (i=0;i < MAX_OPERANDS && OPTYPE(tm_operands[i]) != OP_None;i++)
223     {
224       char *next_comma = ",";
225       int optional = (tm_operands[i] & OPT) != 0;
226
227       switch (OPTYPE(tm_operands[i]))
228         {
229         case OP_Xmem:
230           sprint_dual_address (info, operand[i], XMEM(opcode));
231           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
232           break;
233         case OP_Ymem:
234           sprint_dual_address (info, operand[i], YMEM(opcode));
235           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
236           break;
237         case OP_Smem:
238         case OP_Sind:
239         case OP_Lmem:
240           info->fprintf_func (info->stream, "%s", comma);
241           if (INDIRECT(opcode))
242             {
243               if (MOD(opcode) >= 12)
244                 {
245                   bfd_vma addr = lkaddr;
246                   int arf = ARF(opcode);
247                   int mod = MOD(opcode);
248                   if (mod == 15)
249                       info->fprintf_func (info->stream, "*(");
250                   else
251                       info->fprintf_func (info->stream, "*%sar%d(", 
252                                           (mod == 13 || mod == 14 ? "+" : ""),
253                                           arf);
254                   (*(info->print_address_func))((bfd_vma)addr, info);
255                   info->fprintf_func (info->stream, ")%s", 
256                                       mod == 14 ? "%" : "");
257                 }
258               else
259                 {
260                   sprint_indirect_address (info, operand[i], opcode);
261                   info->fprintf_func (info->stream, "%s", operand[i]);
262                 }
263             }
264           else
265           {
266             /* FIXME -- use labels (print_address_func) */
267             /* in order to do this, we need to guess what DP is */
268             sprint_direct_address (info, operand[i], opcode);
269             info->fprintf_func (info->stream, "%s", operand[i]);
270           }
271           break;
272         case OP_dmad:
273           info->fprintf_func (info->stream, "%s", comma);
274           (*(info->print_address_func))((bfd_vma)opcode2, info);
275           break;
276         case OP_xpmad:
277           /* upper 7 bits of address are in the opcode */
278           opcode2 += ((unsigned long)opcode & 0x7F) << 16;
279           /* fall through */
280         case OP_pmad:
281           info->fprintf_func (info->stream, "%s", comma);
282           (*(info->print_address_func))((bfd_vma)opcode2, info);
283           break;
284         case OP_MMRX:
285           sprint_mmr (info, operand[i], MMRX(opcode));
286           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
287           break;
288         case OP_MMRY:
289           sprint_mmr (info, operand[i], MMRY(opcode));
290           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
291           break;
292         case OP_MMR:
293           sprint_mmr (info, operand[i], MMR(opcode));
294           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
295           break;
296         case OP_PA:
297           sprintf (operand[i], "pa%d", (unsigned)opcode2);
298           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
299           break;
300         case OP_SRC:
301           src = SRC(ext ? opcode2 : opcode) ? OP_B : OP_A;
302           sprintf (operand[i], (src == OP_B) ? "b" : "a");
303           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
304           break;
305         case OP_SRC1:
306           src = SRC1(ext ? opcode2 : opcode) ? OP_B : OP_A;
307           sprintf (operand[i], (src == OP_B) ? "b" : "a");
308           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
309           break;
310         case OP_RND:
311           dst = DST(opcode) ? OP_B : OP_A;
312           sprintf (operand[i], (dst == OP_B) ? "a" : "b");
313           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
314           break;
315         case OP_DST:
316           dst = DST(ext ? opcode2 : opcode) ? OP_B : OP_A;
317           if (!optional || dst != src)
318             {
319               sprintf (operand[i], (dst == OP_B) ? "b" : "a");
320               info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
321             }
322           else
323             next_comma = comma;
324           break;
325         case OP_B:
326           sprintf (operand[i], "b");
327           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
328           break;
329         case OP_A:
330           sprintf (operand[i], "a");
331           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
332           break;
333         case OP_ARX:
334           sprintf (operand[i],"ar%d", (int)ARX(opcode));
335           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
336           break;
337         case OP_SHIFT:
338           shift = SHIFT(ext ? opcode2 : opcode);
339           if (!optional || shift != 0)
340             {
341               sprintf (operand[i],"%d", shift);
342               info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
343             }
344           else
345             next_comma = comma;
346           break;
347         case OP_SHFT:
348           shift = SHFT(opcode);
349           if (!optional || shift != 0)
350             {
351               sprintf (operand[i],"%d", (unsigned)shift);
352               info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
353             }
354           else
355             next_comma = comma;
356           break;
357         case OP_lk:
358           sprintf (operand[i],"#%d", (int)(short)opcode2);
359           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
360           break;
361         case OP_T:
362           sprintf (operand[i], "t");
363           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
364           break;
365         case OP_TS:
366           sprintf (operand[i], "ts");
367           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
368           break;
369         case OP_k8:
370           sprintf (operand[i], "%d", (int)((signed char)(opcode & 0xFF)));
371           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
372           break;
373         case OP_16:
374           sprintf (operand[i], "16");
375           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
376           break;
377         case OP_ASM:
378           sprintf (operand[i], "asm");
379           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
380           break;
381         case OP_BITC:
382           sprintf (operand[i], "%d", (int)(opcode & 0xF));
383           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
384           break;
385         case OP_CC:
386           /* put all CC operands in the same operand */
387           sprint_condition (info, operand[i], opcode);
388           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
389           i = MAX_OPERANDS;
390           break;
391         case OP_CC2:
392           sprint_cc2 (info, operand[i], opcode);
393           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
394           break;
395         case OP_CC3:
396         {
397           const char *code[] = { "eq", "lt", "gt", "neq" };
398           sprintf (operand[i], code[CC3(opcode)]);
399           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
400           break;
401         }
402         case OP_123:
403           {
404             int code = (opcode>>8) & 0x3;
405             sprintf (operand[i], "%d", (code == 0) ? 1 : (code == 2) ? 2 : 3);
406             info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
407             break;
408           }
409         case OP_k5:
410           sprintf (operand[i], "#%d", 
411                    (int)(((signed char)opcode & 0x1F) << 3)>>3);
412           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
413           break;
414         case OP_k8u:
415           sprintf (operand[i], "#%d", (unsigned)(opcode & 0xFF));
416           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
417           break;
418         case OP_k3:
419           sprintf (operand[i], "#%d", (int)(opcode & 0x7));
420           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
421           break;
422         case OP_lku:
423           sprintf (operand[i], "#%d", (unsigned)opcode2);
424           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
425           break;
426         case OP_N:
427           n = (opcode >> 9) & 0x1;
428           sprintf (operand[i], "st%d", n);
429           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
430           break;
431         case OP_SBIT:
432         {
433           const char *status0[] = {
434             "0", "1", "2", "3", "4", "5", "6", "7", "8", 
435             "ovb", "ova", "c", "tc", "13", "14", "15"
436           };
437           const char *status1[] = {
438             "0", "1", "2", "3", "4", 
439             "cmpt", "frct", "c16", "sxm", "ovm", "10",
440             "intm", "hm", "xf", "cpl", "braf"
441           };
442           sprintf (operand[i], "%s", 
443                    n ? status1[SBIT(opcode)] : status0[SBIT(opcode)]);
444           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
445           break;
446         }
447         case OP_12:
448           sprintf (operand[i], "%d", (int)((opcode >> 9)&1) + 1);
449           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
450           break;
451         case OP_TRN:
452           sprintf (operand[i], "trn");
453           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
454           break;
455         case OP_DP:
456           sprintf (operand[i], "dp");
457           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
458           break;
459         case OP_k9:
460           /* FIXME-- this is DP, print the original address? */
461           sprintf (operand[i], "#%d", (int)(opcode & 0x1FF));
462           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
463           break;
464         case OP_ARP:
465           sprintf (operand[i], "arp");
466           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
467           break;
468         case OP_031:
469           sprintf (operand[i], "%d", (int)(opcode & 0x1F));
470           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
471           break;
472         default:
473           sprintf (operand[i], "??? (0x%x)", tm_operands[i]);
474           info->fprintf_func (info->stream, "%s%s", comma, operand[i]);
475           break;
476         }
477       comma = next_comma;
478     }
479   return 1;
480 }
481
482 static int
483 print_parallel_instruction (info, memaddr, opcode, ptm, size)
484   disassemble_info *info;
485   bfd_vma memaddr;
486   unsigned short opcode;
487   partemplate *ptm;
488   int size;
489 {
490   print_instruction (info, memaddr, opcode, 
491                      ptm->name, ptm->operand_types, size, 0);
492   info->fprintf_func (info->stream, " || ");
493   return print_instruction (info, memaddr, opcode, 
494                             ptm->parname, ptm->paroperand_types, size, 0);
495 }
496
497 static int
498 sprint_dual_address (info, buf, code)
499   disassemble_info *info;
500   char buf[];
501   unsigned short code;
502 {
503   const char *formats[] = {
504     "*ar%d",
505     "*ar%d-",
506     "*ar%d+",
507     "*ar%d+0%%",
508   };
509   return sprintf (buf, formats[XMOD(code)], XARX(code));
510 }
511
512 static int
513 sprint_indirect_address (info, buf, opcode)
514   disassemble_info *info;
515   char buf[];
516   unsigned short opcode;
517 {
518   const char *formats[] = {
519     "*ar%d",
520     "*ar%d-",
521     "*ar%d+",
522     "*+ar%d",
523     "*ar%d-0B",
524     "*ar%d-0",
525     "*ar%d+0",
526     "*ar%d+0B",
527     "*ar%d-%%",
528     "*ar%d-0%%",
529     "*ar%d+%%",
530     "*ar%d+0%%",
531   };
532   return sprintf (buf, formats[MOD(opcode)], ARF(opcode));
533 }
534
535 static int
536 sprint_direct_address (info, buf, opcode)
537   disassemble_info *info;
538   char buf[];
539   unsigned short opcode;
540 {
541   /* FIXME -- look up relocation if available */
542   return sprintf (buf, "0x??%02x", (int)(opcode & 0x7F));
543 }
544
545 static int
546 sprint_mmr (info, buf, mmr)
547   disassemble_info *info;
548   char buf[];
549   int mmr;
550 {
551   symbol *reg = (symbol *)mmregs;
552   while (reg->name != NULL)
553     {
554       if (mmr == reg->value)
555         {
556           sprintf (buf, "%s", (reg+1)->name);
557           return 1;
558         }
559       ++reg;
560     }
561   sprintf (buf, "MMR(%d)", mmr); /* FIXME -- different targets.  */
562   return 0;
563 }
564
565 static int
566 sprint_cc2 (info, buf, opcode)
567   disassemble_info *info;
568   char *buf;
569   unsigned short opcode;
570 {
571   const char *cc2[] = {
572     "??", "??", "ageq", "alt", "aneq", "aeq", "agt", "aleq",
573     "??", "??", "bgeq", "blt", "bneq", "beq", "bgt", "bleq",
574   };
575   return sprintf (buf, "%s", cc2[opcode & 0xF]);
576 }
577
578 static int
579 sprint_condition (info, buf, opcode)
580   disassemble_info *info;
581   char *buf;
582   unsigned short opcode;
583 {
584   char *start = buf;
585   const char *cmp[] = {
586       "??", "??", "geq", "lt", "neq", "eq", "gt", "leq"
587   };
588   if (opcode & 0x40)
589     {
590       char acc = (opcode & 0x8) ? 'b' : 'a';
591       if (opcode & 0x7)
592           buf += sprintf (buf, "%c%s%s", acc, cmp[(opcode&0x7)],
593                           (opcode&0x20) ? ", " : "");
594       if (opcode & 0x20)
595           buf += sprintf (buf, "%c%s", acc, (opcode&0x10) ? "ov" : "nov");
596     }
597   else if (opcode & 0x3F)
598     {
599       if (opcode & 0x30)
600         buf += sprintf (buf, "%s%s", 
601                         ((opcode & 0x30) == 0x30) ? "tc" : "ntc",
602                         (opcode & 0x0F) ? ", " : "");
603       if (opcode & 0x0C)
604         buf += sprintf (buf, "%s%s", 
605                         ((opcode & 0x0C) == 0x0C) ? "c" : "nc",
606                         (opcode & 0x03) ? ", " : "");
607       if (opcode & 0x03)
608         buf += sprintf (buf, "%s", 
609                         ((opcode & 0x03) == 0x03) ? "bio" : "nbio");
610     }
611   else
612     buf += sprintf (buf, "unc");
613
614   return buf - start;
615 }