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