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