1/* Disassembly routines for TMS320C30 architecture
2   Copyright (C) 1998-2017 Free Software Foundation, Inc.
3   Contributed by Steven Haworth (steve@pm.cse.rmit.edu.au)
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 "dis-asm.h"
26#include "opcode/tic30.h"
27
28#define NORMAL_INSN   1
29#define PARALLEL_INSN 2
30
31/* Gets the type of instruction based on the top 2 or 3 bits of the
32   instruction word.  */
33#define GET_TYPE(insn) (insn & 0x80000000 ? insn & 0xC0000000 : insn & 0xE0000000)
34
35/* Instruction types.  */
36#define TWO_OPERAND_1 0x00000000
37#define TWO_OPERAND_2 0x40000000
38#define THREE_OPERAND 0x20000000
39#define PAR_STORE     0xC0000000
40#define MUL_ADDS      0x80000000
41#define BRANCHES      0x60000000
42
43/* Specific instruction id bits.  */
44#define NORMAL_IDEN    0x1F800000
45#define PAR_STORE_IDEN 0x3E000000
46#define MUL_ADD_IDEN   0x2C000000
47#define BR_IMM_IDEN    0x1F000000
48#define BR_COND_IDEN   0x1C3F0000
49
50/* Addressing modes.  */
51#define AM_REGISTER 0x00000000
52#define AM_DIRECT   0x00200000
53#define AM_INDIRECT 0x00400000
54#define AM_IMM      0x00600000
55
56#define P_FIELD 0x03000000
57
58#define REG_AR0 0x08
59#define LDP_INSN 0x08700000
60
61/* TMS320C30 program counter for current instruction.  */
62static unsigned int _pc;
63
64struct instruction
65{
66  int type;
67  insn_template *tm;
68  partemplate *ptm;
69};
70
71static int
72get_tic30_instruction (unsigned long insn_word, struct instruction *insn)
73{
74  switch (GET_TYPE (insn_word))
75    {
76    case TWO_OPERAND_1:
77    case TWO_OPERAND_2:
78    case THREE_OPERAND:
79      insn->type = NORMAL_INSN;
80      {
81	insn_template *current_optab = (insn_template *) tic30_optab;
82
83	for (; current_optab < tic30_optab_end; current_optab++)
84	  {
85	    if (GET_TYPE (current_optab->base_opcode) == GET_TYPE (insn_word))
86	      {
87		if (current_optab->operands == 0)
88		  {
89		    if (current_optab->base_opcode == insn_word)
90		      {
91			insn->tm = current_optab;
92			break;
93		      }
94		  }
95		else if ((current_optab->base_opcode & NORMAL_IDEN) == (insn_word & NORMAL_IDEN))
96		  {
97		    insn->tm = current_optab;
98		    break;
99		  }
100	      }
101	  }
102      }
103      break;
104
105    case PAR_STORE:
106      insn->type = PARALLEL_INSN;
107      {
108	partemplate *current_optab = (partemplate *) tic30_paroptab;
109
110	for (; current_optab < tic30_paroptab_end; current_optab++)
111	  {
112	    if (GET_TYPE (current_optab->base_opcode) == GET_TYPE (insn_word))
113	      {
114		if ((current_optab->base_opcode & PAR_STORE_IDEN)
115		    == (insn_word & PAR_STORE_IDEN))
116		  {
117		    insn->ptm = current_optab;
118		    break;
119		  }
120	      }
121	  }
122      }
123      break;
124
125    case MUL_ADDS:
126      insn->type = PARALLEL_INSN;
127      {
128	partemplate *current_optab = (partemplate *) tic30_paroptab;
129
130	for (; current_optab < tic30_paroptab_end; current_optab++)
131	  {
132	    if (GET_TYPE (current_optab->base_opcode) == GET_TYPE (insn_word))
133	      {
134		if ((current_optab->base_opcode & MUL_ADD_IDEN)
135		    == (insn_word & MUL_ADD_IDEN))
136		  {
137		    insn->ptm = current_optab;
138		    break;
139		  }
140	      }
141	  }
142      }
143      break;
144
145    case BRANCHES:
146      insn->type = NORMAL_INSN;
147      {
148	insn_template *current_optab = (insn_template *) tic30_optab;
149
150	for (; current_optab < tic30_optab_end; current_optab++)
151	  {
152	    if (GET_TYPE (current_optab->base_opcode) == GET_TYPE (insn_word))
153	      {
154		if (current_optab->operand_types[0] & Imm24)
155		  {
156		    if ((current_optab->base_opcode & BR_IMM_IDEN)
157			== (insn_word & BR_IMM_IDEN))
158		      {
159			insn->tm = current_optab;
160			break;
161		      }
162		  }
163		else if (current_optab->operands > 0)
164		  {
165		    if ((current_optab->base_opcode & BR_COND_IDEN)
166			== (insn_word & BR_COND_IDEN))
167		      {
168			insn->tm = current_optab;
169			break;
170		      }
171		  }
172		else
173		  {
174		    if ((current_optab->base_opcode & (BR_COND_IDEN | 0x00800000))
175			== (insn_word & (BR_COND_IDEN | 0x00800000)))
176		      {
177			insn->tm = current_optab;
178			break;
179		      }
180		  }
181	      }
182	  }
183      }
184      break;
185    default:
186      return 0;
187    }
188  return 1;
189}
190
191static int
192get_register_operand (unsigned char fragment, char *buffer)
193{
194  const reg *current_reg = tic30_regtab;
195
196  if (buffer == NULL)
197    return 0;
198  for (; current_reg < tic30_regtab_end; current_reg++)
199    {
200      if ((fragment & 0x1F) == current_reg->opcode)
201	{
202	  strcpy (buffer, current_reg->name);
203	  return 1;
204	}
205    }
206  return 0;
207}
208
209static int
210get_indirect_operand (unsigned short fragment,
211		      int size,
212		      char *buffer)
213{
214  unsigned char mod;
215  unsigned arnum;
216  unsigned char disp;
217
218  if (buffer == NULL)
219    return 0;
220  /* Determine which bits identify the sections of the indirect
221     operand based on the size in bytes.  */
222  switch (size)
223    {
224    case 1:
225      mod = (fragment & 0x00F8) >> 3;
226      arnum = (fragment & 0x0007);
227      disp = 0;
228      break;
229    case 2:
230      mod = (fragment & 0xF800) >> 11;
231      arnum = (fragment & 0x0700) >> 8;
232      disp = (fragment & 0x00FF);
233      break;
234    default:
235      return 0;
236    }
237  {
238    const ind_addr_type *current_ind = tic30_indaddr_tab;
239
240    for (; current_ind < tic30_indaddrtab_end; current_ind++)
241      {
242	if (current_ind->modfield == mod)
243	  {
244	    if (current_ind->displacement == IMPLIED_DISP && size == 2)
245	      continue;
246
247	    else
248	      {
249		size_t i, len;
250		int bufcnt;
251
252		len = strlen (current_ind->syntax);
253		for (i = 0, bufcnt = 0; i < len; i++, bufcnt++)
254		  {
255		    buffer[bufcnt] = current_ind->syntax[i];
256		    if (buffer[bufcnt - 1] == 'a' && buffer[bufcnt] == 'r')
257		      buffer[++bufcnt] = arnum + '0';
258		    if (buffer[bufcnt] == '('
259			&& current_ind->displacement == DISP_REQUIRED)
260		      {
261			sprintf (&buffer[bufcnt + 1], "%u", disp);
262			bufcnt += strlen (&buffer[bufcnt + 1]);
263		      }
264		  }
265		buffer[bufcnt + 1] = '\0';
266		break;
267	      }
268	  }
269      }
270  }
271  return 1;
272}
273
274static int
275cnvt_tmsfloat_ieee (unsigned long tmsfloat, int size, float *ieeefloat)
276{
277  unsigned long exponent, sign, mant;
278  union
279  {
280    unsigned long l;
281    float f;
282  } val;
283
284  if (size == 2)
285    {
286      if ((tmsfloat & 0x0000F000) == 0x00008000)
287	tmsfloat = 0x80000000;
288      else
289	{
290	  tmsfloat <<= 16;
291	  tmsfloat = (long) tmsfloat >> 4;
292	}
293    }
294  exponent = tmsfloat & 0xFF000000;
295  if (exponent == 0x80000000)
296    {
297      *ieeefloat = 0.0;
298      return 1;
299    }
300  exponent += 0x7F000000;
301  sign = (tmsfloat & 0x00800000) << 8;
302  mant = tmsfloat & 0x007FFFFF;
303  if (exponent == 0xFF000000)
304    {
305      if (mant == 0)
306	*ieeefloat = ERANGE;
307#ifdef HUGE_VALF
308      if (sign == 0)
309	*ieeefloat = HUGE_VALF;
310      else
311	*ieeefloat = -HUGE_VALF;
312#else
313      if (sign == 0)
314	*ieeefloat = 1.0 / 0.0;
315      else
316	*ieeefloat = -1.0 / 0.0;
317#endif
318      return 1;
319    }
320  exponent >>= 1;
321  if (sign)
322    {
323      mant = (~mant) & 0x007FFFFF;
324      mant += 1;
325      exponent += mant & 0x00800000;
326      exponent &= 0x7F800000;
327      mant &= 0x007FFFFF;
328    }
329  if (tmsfloat == 0x80000000)
330    sign = mant = exponent = 0;
331  tmsfloat = sign | exponent | mant;
332  val.l = tmsfloat;
333  *ieeefloat = val.f;
334  return 1;
335}
336
337static int
338print_two_operand (disassemble_info *info,
339		   unsigned long insn_word,
340		   struct instruction *insn)
341{
342  char name[12];
343  char operand[2][13] =
344  {
345    {0},
346    {0}
347  };
348  float f_number;
349
350  if (insn->tm == NULL)
351    return 0;
352  strcpy (name, insn->tm->name);
353  if (insn->tm->opcode_modifier == AddressMode)
354    {
355      int src_op, dest_op;
356      /* Determine whether instruction is a store or a normal instruction.  */
357      if ((insn->tm->operand_types[1] & (Direct | Indirect))
358	  == (Direct | Indirect))
359	{
360	  src_op = 1;
361	  dest_op = 0;
362	}
363      else
364	{
365	  src_op = 0;
366	  dest_op = 1;
367	}
368      /* Get the destination register.  */
369      if (insn->tm->operands == 2)
370	get_register_operand ((insn_word & 0x001F0000) >> 16, operand[dest_op]);
371      /* Get the source operand based on addressing mode.  */
372      switch (insn_word & AddressMode)
373	{
374	case AM_REGISTER:
375	  /* Check for the NOP instruction before getting the operand.  */
376	  if ((insn->tm->operand_types[0] & NotReq) == 0)
377	    get_register_operand ((insn_word & 0x0000001F), operand[src_op]);
378	  break;
379	case AM_DIRECT:
380	  sprintf (operand[src_op], "@0x%lX", (insn_word & 0x0000FFFF));
381	  break;
382	case AM_INDIRECT:
383	  get_indirect_operand ((insn_word & 0x0000FFFF), 2, operand[src_op]);
384	  break;
385	case AM_IMM:
386	  /* Get the value of the immediate operand based on variable type.  */
387	  switch (insn->tm->imm_arg_type)
388	    {
389	    case Imm_Float:
390	      cnvt_tmsfloat_ieee ((insn_word & 0x0000FFFF), 2, &f_number);
391	      sprintf (operand[src_op], "%2.2f", f_number);
392	      break;
393	    case Imm_SInt:
394	      sprintf (operand[src_op], "%d", (short) (insn_word & 0x0000FFFF));
395	      break;
396	    case Imm_UInt:
397	      sprintf (operand[src_op], "%lu", (insn_word & 0x0000FFFF));
398	      break;
399	    default:
400	      return 0;
401	    }
402	  /* Handle special case for LDP instruction.  */
403	  if ((insn_word & 0xFFFFFF00) == LDP_INSN)
404	    {
405	      strcpy (name, "ldp");
406	      sprintf (operand[0], "0x%06lX", (insn_word & 0x000000FF) << 16);
407	      operand[1][0] = '\0';
408	    }
409	}
410    }
411  /* Handle case for stack and rotate instructions.  */
412  else if (insn->tm->operands == 1)
413    {
414      if (insn->tm->opcode_modifier == StackOp)
415	get_register_operand ((insn_word & 0x001F0000) >> 16, operand[0]);
416    }
417  /* Output instruction to stream.  */
418  info->fprintf_func (info->stream, "   %s %s%c%s", name,
419		      operand[0][0] ? operand[0] : "",
420		      operand[1][0] ? ',' : ' ',
421		      operand[1][0] ? operand[1] : "");
422  return 1;
423}
424
425static int
426print_three_operand (disassemble_info *info,
427		     unsigned long insn_word,
428		     struct instruction *insn)
429{
430  char operand[3][13] =
431  {
432    {0},
433    {0},
434    {0}
435  };
436
437  if (insn->tm == NULL)
438    return 0;
439  switch (insn_word & AddressMode)
440    {
441    case AM_REGISTER:
442      get_register_operand ((insn_word & 0x000000FF), operand[0]);
443      get_register_operand ((insn_word & 0x0000FF00) >> 8, operand[1]);
444      break;
445    case AM_DIRECT:
446      get_register_operand ((insn_word & 0x000000FF), operand[0]);
447      get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1]);
448      break;
449    case AM_INDIRECT:
450      get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0]);
451      get_register_operand ((insn_word & 0x0000FF00) >> 8, operand[1]);
452      break;
453    case AM_IMM:
454      get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0]);
455      get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1]);
456      break;
457    default:
458      return 0;
459    }
460  if (insn->tm->operands == 3)
461    get_register_operand ((insn_word & 0x001F0000) >> 16, operand[2]);
462  info->fprintf_func (info->stream, "   %s %s,%s%c%s", insn->tm->name,
463		      operand[0], operand[1],
464		      operand[2][0] ? ',' : ' ',
465		      operand[2][0] ? operand[2] : "");
466  return 1;
467}
468
469static int
470print_par_insn (disassemble_info *info,
471		unsigned long insn_word,
472		struct instruction *insn)
473{
474  size_t i, len;
475  char *name1, *name2;
476  char operand[2][3][13] =
477  {
478    {
479      {0},
480      {0},
481      {0}
482    },
483    {
484      {0},
485      {0},
486      {0}
487    }
488  };
489
490  if (insn->ptm == NULL)
491    return 0;
492  /* Parse out the names of each of the parallel instructions from the
493     q_insn1_insn2 format.  */
494  name1 = (char *) strdup (insn->ptm->name + 2);
495  name2 = "";
496  len = strlen (name1);
497  for (i = 0; i < len; i++)
498    {
499      if (name1[i] == '_')
500	{
501	  name2 = &name1[i + 1];
502	  name1[i] = '\0';
503	  break;
504	}
505    }
506  /* Get the operands of the instruction based on the operand order.  */
507  switch (insn->ptm->oporder)
508    {
509    case OO_4op1:
510      get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][0]);
511      get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][1]);
512      get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]);
513      get_register_operand ((insn_word >> 22) & 0x07, operand[0][1]);
514      break;
515    case OO_4op2:
516      get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][0]);
517      get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][0]);
518      get_register_operand ((insn_word >> 19) & 0x07, operand[1][1]);
519      get_register_operand ((insn_word >> 22) & 0x07, operand[0][1]);
520      break;
521    case OO_4op3:
522      get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][1]);
523      get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][1]);
524      get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]);
525      get_register_operand ((insn_word >> 22) & 0x07, operand[0][0]);
526      break;
527    case OO_5op1:
528      get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][0]);
529      get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][1]);
530      get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]);
531      get_register_operand ((insn_word >> 19) & 0x07, operand[0][1]);
532      get_register_operand ((insn_word >> 22) & 0x07, operand[0][2]);
533      break;
534    case OO_5op2:
535      get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][1]);
536      get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][1]);
537      get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]);
538      get_register_operand ((insn_word >> 19) & 0x07, operand[0][0]);
539      get_register_operand ((insn_word >> 22) & 0x07, operand[0][2]);
540      break;
541    case OO_PField:
542      if (insn_word & 0x00800000)
543	get_register_operand (0x01, operand[0][2]);
544      else
545	get_register_operand (0x00, operand[0][2]);
546      if (insn_word & 0x00400000)
547	get_register_operand (0x03, operand[1][2]);
548      else
549	get_register_operand (0x02, operand[1][2]);
550      switch (insn_word & P_FIELD)
551	{
552	case 0x00000000:
553	  get_indirect_operand ((insn_word & 0x000000FF), 1, operand[0][1]);
554	  get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[0][0]);
555	  get_register_operand ((insn_word >> 16) & 0x07, operand[1][1]);
556	  get_register_operand ((insn_word >> 19) & 0x07, operand[1][0]);
557	  break;
558	case 0x01000000:
559	  get_indirect_operand ((insn_word & 0x000000FF), 1, operand[1][0]);
560	  get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[0][0]);
561	  get_register_operand ((insn_word >> 16) & 0x07, operand[1][1]);
562	  get_register_operand ((insn_word >> 19) & 0x07, operand[0][1]);
563	  break;
564	case 0x02000000:
565	  get_indirect_operand ((insn_word & 0x000000FF), 1, operand[1][1]);
566	  get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[1][0]);
567	  get_register_operand ((insn_word >> 16) & 0x07, operand[0][1]);
568	  get_register_operand ((insn_word >> 19) & 0x07, operand[0][0]);
569	  break;
570	case 0x03000000:
571	  get_indirect_operand ((insn_word & 0x000000FF), 1, operand[1][1]);
572	  get_indirect_operand ((insn_word & 0x0000FF00) >> 8, 1, operand[0][0]);
573	  get_register_operand ((insn_word >> 16) & 0x07, operand[1][0]);
574	  get_register_operand ((insn_word >> 19) & 0x07, operand[0][1]);
575	  break;
576	}
577      break;
578    default:
579      return 0;
580    }
581  info->fprintf_func (info->stream, "   %s %s,%s%c%s", name1,
582		      operand[0][0], operand[0][1],
583		      operand[0][2][0] ? ',' : ' ',
584		      operand[0][2][0] ? operand[0][2] : "");
585  info->fprintf_func (info->stream, "\n\t\t\t|| %s %s,%s%c%s", name2,
586		      operand[1][0], operand[1][1],
587		      operand[1][2][0] ? ',' : ' ',
588		      operand[1][2][0] ? operand[1][2] : "");
589  free (name1);
590  return 1;
591}
592
593static int
594print_branch (disassemble_info *info,
595	      unsigned long insn_word,
596	      struct instruction *insn)
597{
598  char operand[2][13] =
599  {
600    {0},
601    {0}
602  };
603  unsigned long address;
604  int print_label = 0;
605
606  if (insn->tm == NULL)
607    return 0;
608  /* Get the operands for 24-bit immediate jumps.  */
609  if (insn->tm->operand_types[0] & Imm24)
610    {
611      address = insn_word & 0x00FFFFFF;
612      sprintf (operand[0], "0x%lX", address);
613      print_label = 1;
614    }
615  /* Get the operand for the trap instruction.  */
616  else if (insn->tm->operand_types[0] & IVector)
617    {
618      address = insn_word & 0x0000001F;
619      sprintf (operand[0], "0x%lX", address);
620    }
621  else
622    {
623      address = insn_word & 0x0000FFFF;
624      /* Get the operands for the DB instructions.  */
625      if (insn->tm->operands == 2)
626	{
627	  get_register_operand (((insn_word & 0x01C00000) >> 22) + REG_AR0, operand[0]);
628	  if (insn_word & PCRel)
629	    {
630	      sprintf (operand[1], "%d", (short) address);
631	      print_label = 1;
632	    }
633	  else
634	    get_register_operand (insn_word & 0x0000001F, operand[1]);
635	}
636      /* Get the operands for the standard branches.  */
637      else if (insn->tm->operands == 1)
638	{
639	  if (insn_word & PCRel)
640	    {
641	      address = (short) address;
642	      sprintf (operand[0], "%ld", address);
643	      print_label = 1;
644	    }
645	  else
646	    get_register_operand (insn_word & 0x0000001F, operand[0]);
647	}
648    }
649  info->fprintf_func (info->stream, "   %s %s%c%s", insn->tm->name,
650		      operand[0][0] ? operand[0] : "",
651		      operand[1][0] ? ',' : ' ',
652		      operand[1][0] ? operand[1] : "");
653  /* Print destination of branch in relation to current symbol.  */
654  if (print_label && info->symbols)
655    {
656      asymbol *sym = *info->symbols;
657
658      if ((insn->tm->opcode_modifier == PCRel) && (insn_word & PCRel))
659	{
660	  address = (_pc + 1 + (short) address) - ((sym->section->vma + sym->value) / 4);
661	  /* Check for delayed instruction, if so adjust destination.  */
662	  if (insn_word & 0x00200000)
663	    address += 2;
664	}
665      else
666	{
667	  address -= ((sym->section->vma + sym->value) / 4);
668	}
669      if (address == 0)
670	info->fprintf_func (info->stream, " <%s>", sym->name);
671      else
672	info->fprintf_func (info->stream, " <%s %c %lu>", sym->name,
673			    ((short) address < 0) ? '-' : '+',
674			    address);
675    }
676  return 1;
677}
678
679int
680print_insn_tic30 (bfd_vma pc, disassemble_info *info)
681{
682  unsigned long insn_word;
683  struct instruction insn = { 0, NULL, NULL };
684  bfd_vma bufaddr = pc - info->buffer_vma;
685
686  /* Obtain the current instruction word from the buffer.  */
687  insn_word = (*(info->buffer + bufaddr) << 24) | (*(info->buffer + bufaddr + 1) << 16) |
688    (*(info->buffer + bufaddr + 2) << 8) | *(info->buffer + bufaddr + 3);
689  _pc = pc / 4;
690  /* Get the instruction refered to by the current instruction word
691     and print it out based on its type.  */
692  if (!get_tic30_instruction (insn_word, &insn))
693    return -1;
694  switch (GET_TYPE (insn_word))
695    {
696    case TWO_OPERAND_1:
697    case TWO_OPERAND_2:
698      if (!print_two_operand (info, insn_word, &insn))
699	return -1;
700      break;
701    case THREE_OPERAND:
702      if (!print_three_operand (info, insn_word, &insn))
703	return -1;
704      break;
705    case PAR_STORE:
706    case MUL_ADDS:
707      if (!print_par_insn (info, insn_word, &insn))
708	return -1;
709      break;
710    case BRANCHES:
711      if (!print_branch (info, insn_word, &insn))
712	return -1;
713      break;
714    }
715  return 4;
716}
717