1*3d8817e4Smiod /* Print instructions for the Texas TMS320C[34]X, for GDB and GNU Binutils.
2*3d8817e4Smiod 
3*3d8817e4Smiod    Copyright 2002, 2003, 2005 Free Software Foundation, Inc.
4*3d8817e4Smiod 
5*3d8817e4Smiod    Contributed by Michael P. Hayes (m.hayes@elec.canterbury.ac.nz)
6*3d8817e4Smiod 
7*3d8817e4Smiod    This program is free software; you can redistribute it and/or modify
8*3d8817e4Smiod    it under the terms of the GNU General Public License as published by
9*3d8817e4Smiod    the Free Software Foundation; either version 2 of the License, or
10*3d8817e4Smiod    (at your option) any later version.
11*3d8817e4Smiod 
12*3d8817e4Smiod    This program is distributed in the hope that it will be useful,
13*3d8817e4Smiod    but WITHOUT ANY WARRANTY; without even the implied warranty of
14*3d8817e4Smiod    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*3d8817e4Smiod    GNU General Public License for more details.
16*3d8817e4Smiod 
17*3d8817e4Smiod    You should have received a copy of the GNU General Public License
18*3d8817e4Smiod    along with this program; if not, write to the Free Software
19*3d8817e4Smiod    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20*3d8817e4Smiod    MA 02110-1301, USA.  */
21*3d8817e4Smiod 
22*3d8817e4Smiod #include <math.h>
23*3d8817e4Smiod #include "libiberty.h"
24*3d8817e4Smiod #include "dis-asm.h"
25*3d8817e4Smiod #include "opcode/tic4x.h"
26*3d8817e4Smiod 
27*3d8817e4Smiod #define TIC4X_DEBUG 0
28*3d8817e4Smiod 
29*3d8817e4Smiod #define TIC4X_HASH_SIZE   11   /* 11 (bits) and above should give unique entries.  */
30*3d8817e4Smiod #define TIC4X_SPESOP_SIZE 8    /* Max 8. ops for special instructions.  */
31*3d8817e4Smiod 
32*3d8817e4Smiod typedef enum
33*3d8817e4Smiod {
34*3d8817e4Smiod   IMMED_SINT,
35*3d8817e4Smiod   IMMED_SUINT,
36*3d8817e4Smiod   IMMED_SFLOAT,
37*3d8817e4Smiod   IMMED_INT,
38*3d8817e4Smiod   IMMED_UINT,
39*3d8817e4Smiod   IMMED_FLOAT
40*3d8817e4Smiod }
41*3d8817e4Smiod immed_t;
42*3d8817e4Smiod 
43*3d8817e4Smiod typedef enum
44*3d8817e4Smiod {
45*3d8817e4Smiod   INDIRECT_SHORT,
46*3d8817e4Smiod   INDIRECT_LONG,
47*3d8817e4Smiod   INDIRECT_TIC4X
48*3d8817e4Smiod }
49*3d8817e4Smiod indirect_t;
50*3d8817e4Smiod 
51*3d8817e4Smiod static int tic4x_version = 0;
52*3d8817e4Smiod static int tic4x_dp = 0;
53*3d8817e4Smiod 
54*3d8817e4Smiod static int
tic4x_pc_offset(unsigned int op)55*3d8817e4Smiod tic4x_pc_offset (unsigned int op)
56*3d8817e4Smiod {
57*3d8817e4Smiod   /* Determine the PC offset for a C[34]x instruction.
58*3d8817e4Smiod      This could be simplified using some boolean algebra
59*3d8817e4Smiod      but at the expense of readability.  */
60*3d8817e4Smiod   switch (op >> 24)
61*3d8817e4Smiod     {
62*3d8817e4Smiod     case 0x60:	/* br */
63*3d8817e4Smiod     case 0x62:	/* call  (C4x) */
64*3d8817e4Smiod     case 0x64:	/* rptb  (C4x) */
65*3d8817e4Smiod       return 1;
66*3d8817e4Smiod     case 0x61: 	/* brd */
67*3d8817e4Smiod     case 0x63: 	/* laj */
68*3d8817e4Smiod     case 0x65:	/* rptbd (C4x) */
69*3d8817e4Smiod       return 3;
70*3d8817e4Smiod     case 0x66: 	/* swi */
71*3d8817e4Smiod     case 0x67:
72*3d8817e4Smiod       return 0;
73*3d8817e4Smiod     default:
74*3d8817e4Smiod       break;
75*3d8817e4Smiod     }
76*3d8817e4Smiod 
77*3d8817e4Smiod   switch ((op & 0xffe00000) >> 20)
78*3d8817e4Smiod     {
79*3d8817e4Smiod     case 0x6a0:	/* bB */
80*3d8817e4Smiod     case 0x720: /* callB */
81*3d8817e4Smiod     case 0x740: /* trapB */
82*3d8817e4Smiod       return 1;
83*3d8817e4Smiod 
84*3d8817e4Smiod     case 0x6a2: /* bBd */
85*3d8817e4Smiod     case 0x6a6: /* bBat */
86*3d8817e4Smiod     case 0x6aa: /* bBaf */
87*3d8817e4Smiod     case 0x722:	/* lajB */
88*3d8817e4Smiod     case 0x748: /* latB */
89*3d8817e4Smiod     case 0x798: /* rptbd */
90*3d8817e4Smiod       return 3;
91*3d8817e4Smiod 
92*3d8817e4Smiod     default:
93*3d8817e4Smiod       break;
94*3d8817e4Smiod     }
95*3d8817e4Smiod 
96*3d8817e4Smiod   switch ((op & 0xfe200000) >> 20)
97*3d8817e4Smiod     {
98*3d8817e4Smiod     case 0x6e0:	/* dbB */
99*3d8817e4Smiod       return 1;
100*3d8817e4Smiod 
101*3d8817e4Smiod     case 0x6e2:	/* dbBd */
102*3d8817e4Smiod       return 3;
103*3d8817e4Smiod 
104*3d8817e4Smiod     default:
105*3d8817e4Smiod       break;
106*3d8817e4Smiod     }
107*3d8817e4Smiod 
108*3d8817e4Smiod   return 0;
109*3d8817e4Smiod }
110*3d8817e4Smiod 
111*3d8817e4Smiod static int
tic4x_print_char(struct disassemble_info * info,char ch)112*3d8817e4Smiod tic4x_print_char (struct disassemble_info * info, char ch)
113*3d8817e4Smiod {
114*3d8817e4Smiod   if (info != NULL)
115*3d8817e4Smiod     (*info->fprintf_func) (info->stream, "%c", ch);
116*3d8817e4Smiod   return 1;
117*3d8817e4Smiod }
118*3d8817e4Smiod 
119*3d8817e4Smiod static int
tic4x_print_str(struct disassemble_info * info,char * str)120*3d8817e4Smiod tic4x_print_str (struct disassemble_info *info, char *str)
121*3d8817e4Smiod {
122*3d8817e4Smiod   if (info != NULL)
123*3d8817e4Smiod     (*info->fprintf_func) (info->stream, "%s", str);
124*3d8817e4Smiod   return 1;
125*3d8817e4Smiod }
126*3d8817e4Smiod 
127*3d8817e4Smiod static int
tic4x_print_register(struct disassemble_info * info,unsigned long regno)128*3d8817e4Smiod tic4x_print_register (struct disassemble_info *info, unsigned long regno)
129*3d8817e4Smiod {
130*3d8817e4Smiod   static tic4x_register_t ** registertable = NULL;
131*3d8817e4Smiod   unsigned int i;
132*3d8817e4Smiod 
133*3d8817e4Smiod   if (registertable == NULL)
134*3d8817e4Smiod     {
135*3d8817e4Smiod       registertable = xmalloc (sizeof (tic4x_register_t *) * REG_TABLE_SIZE);
136*3d8817e4Smiod       for (i = 0; i < tic3x_num_registers; i++)
137*3d8817e4Smiod 	registertable[tic3x_registers[i].regno] = (tic4x_register_t *) (tic3x_registers + i);
138*3d8817e4Smiod       if (IS_CPU_TIC4X (tic4x_version))
139*3d8817e4Smiod 	{
140*3d8817e4Smiod 	  /* Add C4x additional registers, overwriting
141*3d8817e4Smiod 	     any C3x registers if necessary.  */
142*3d8817e4Smiod 	  for (i = 0; i < tic4x_num_registers; i++)
143*3d8817e4Smiod 	    registertable[tic4x_registers[i].regno] =
144*3d8817e4Smiod 	      (tic4x_register_t *)(tic4x_registers + i);
145*3d8817e4Smiod 	}
146*3d8817e4Smiod     }
147*3d8817e4Smiod   if ((int) regno > (IS_CPU_TIC4X (tic4x_version) ? TIC4X_REG_MAX : TIC3X_REG_MAX))
148*3d8817e4Smiod     return 0;
149*3d8817e4Smiod   if (info != NULL)
150*3d8817e4Smiod     (*info->fprintf_func) (info->stream, "%s", registertable[regno]->name);
151*3d8817e4Smiod   return 1;
152*3d8817e4Smiod }
153*3d8817e4Smiod 
154*3d8817e4Smiod static int
tic4x_print_addr(struct disassemble_info * info,unsigned long addr)155*3d8817e4Smiod tic4x_print_addr (struct disassemble_info *info, unsigned long addr)
156*3d8817e4Smiod {
157*3d8817e4Smiod   if (info != NULL)
158*3d8817e4Smiod     (*info->print_address_func)(addr, info);
159*3d8817e4Smiod   return 1;
160*3d8817e4Smiod }
161*3d8817e4Smiod 
162*3d8817e4Smiod static int
tic4x_print_relative(struct disassemble_info * info,unsigned long pc,long offset,unsigned long opcode)163*3d8817e4Smiod tic4x_print_relative (struct disassemble_info *info,
164*3d8817e4Smiod 		      unsigned long pc,
165*3d8817e4Smiod 		      long offset,
166*3d8817e4Smiod 		      unsigned long opcode)
167*3d8817e4Smiod {
168*3d8817e4Smiod   return tic4x_print_addr (info, pc + offset + tic4x_pc_offset (opcode));
169*3d8817e4Smiod }
170*3d8817e4Smiod 
171*3d8817e4Smiod static int
tic4x_print_direct(struct disassemble_info * info,unsigned long arg)172*3d8817e4Smiod tic4x_print_direct (struct disassemble_info *info, unsigned long arg)
173*3d8817e4Smiod {
174*3d8817e4Smiod   if (info != NULL)
175*3d8817e4Smiod     {
176*3d8817e4Smiod       (*info->fprintf_func) (info->stream, "@");
177*3d8817e4Smiod       tic4x_print_addr (info, arg + (tic4x_dp << 16));
178*3d8817e4Smiod     }
179*3d8817e4Smiod   return 1;
180*3d8817e4Smiod }
181*3d8817e4Smiod #if 0
182*3d8817e4Smiod /* FIXME: make the floating point stuff not rely on host
183*3d8817e4Smiod    floating point arithmetic.  */
184*3d8817e4Smiod 
185*3d8817e4Smiod static void
186*3d8817e4Smiod tic4x_print_ftoa (unsigned int val, FILE *stream, fprintf_ftype pfunc)
187*3d8817e4Smiod {
188*3d8817e4Smiod   int e;
189*3d8817e4Smiod   int s;
190*3d8817e4Smiod   int f;
191*3d8817e4Smiod   double num = 0.0;
192*3d8817e4Smiod 
193*3d8817e4Smiod   e = EXTRS (val, 31, 24);	/* Exponent.  */
194*3d8817e4Smiod   if (e != -128)
195*3d8817e4Smiod     {
196*3d8817e4Smiod       s = EXTRU (val, 23, 23);	/* Sign bit.  */
197*3d8817e4Smiod       f = EXTRU (val, 22, 0);	/* Mantissa.  */
198*3d8817e4Smiod       if (s)
199*3d8817e4Smiod 	f += -2 * (1 << 23);
200*3d8817e4Smiod       else
201*3d8817e4Smiod 	f += (1 << 23);
202*3d8817e4Smiod       num = f / (double)(1 << 23);
203*3d8817e4Smiod       num = ldexp (num, e);
204*3d8817e4Smiod     }
205*3d8817e4Smiod   (*pfunc)(stream, "%.9g", num);
206*3d8817e4Smiod }
207*3d8817e4Smiod #endif
208*3d8817e4Smiod 
209*3d8817e4Smiod static int
tic4x_print_immed(struct disassemble_info * info,immed_t type,unsigned long arg)210*3d8817e4Smiod tic4x_print_immed (struct disassemble_info *info,
211*3d8817e4Smiod 		   immed_t type,
212*3d8817e4Smiod 		   unsigned long arg)
213*3d8817e4Smiod {
214*3d8817e4Smiod   int s;
215*3d8817e4Smiod   int f;
216*3d8817e4Smiod   int e;
217*3d8817e4Smiod   double num = 0.0;
218*3d8817e4Smiod 
219*3d8817e4Smiod   if (info == NULL)
220*3d8817e4Smiod     return 1;
221*3d8817e4Smiod   switch (type)
222*3d8817e4Smiod     {
223*3d8817e4Smiod     case IMMED_SINT:
224*3d8817e4Smiod     case IMMED_INT:
225*3d8817e4Smiod       (*info->fprintf_func) (info->stream, "%ld", (long) arg);
226*3d8817e4Smiod       break;
227*3d8817e4Smiod 
228*3d8817e4Smiod     case IMMED_SUINT:
229*3d8817e4Smiod     case IMMED_UINT:
230*3d8817e4Smiod       (*info->fprintf_func) (info->stream, "%lu", arg);
231*3d8817e4Smiod       break;
232*3d8817e4Smiod 
233*3d8817e4Smiod     case IMMED_SFLOAT:
234*3d8817e4Smiod       e = EXTRS (arg, 15, 12);
235*3d8817e4Smiod       if (e != -8)
236*3d8817e4Smiod 	{
237*3d8817e4Smiod 	  s = EXTRU (arg, 11, 11);
238*3d8817e4Smiod 	  f = EXTRU (arg, 10, 0);
239*3d8817e4Smiod 	  if (s)
240*3d8817e4Smiod 	    f += -2 * (1 << 11);
241*3d8817e4Smiod 	  else
242*3d8817e4Smiod 	    f += (1 << 11);
243*3d8817e4Smiod 	  num = f / (double)(1 << 11);
244*3d8817e4Smiod 	  num = ldexp (num, e);
245*3d8817e4Smiod 	}
246*3d8817e4Smiod       (*info->fprintf_func) (info->stream, "%f", num);
247*3d8817e4Smiod       break;
248*3d8817e4Smiod     case IMMED_FLOAT:
249*3d8817e4Smiod       e = EXTRS (arg, 31, 24);
250*3d8817e4Smiod       if (e != -128)
251*3d8817e4Smiod 	{
252*3d8817e4Smiod 	  s = EXTRU (arg, 23, 23);
253*3d8817e4Smiod 	  f = EXTRU (arg, 22, 0);
254*3d8817e4Smiod 	  if (s)
255*3d8817e4Smiod 	    f += -2 * (1 << 23);
256*3d8817e4Smiod 	  else
257*3d8817e4Smiod 	    f += (1 << 23);
258*3d8817e4Smiod 	  num = f / (double)(1 << 23);
259*3d8817e4Smiod 	  num = ldexp (num, e);
260*3d8817e4Smiod 	}
261*3d8817e4Smiod       (*info->fprintf_func) (info->stream, "%f", num);
262*3d8817e4Smiod       break;
263*3d8817e4Smiod     }
264*3d8817e4Smiod   return 1;
265*3d8817e4Smiod }
266*3d8817e4Smiod 
267*3d8817e4Smiod static int
tic4x_print_cond(struct disassemble_info * info,unsigned int cond)268*3d8817e4Smiod tic4x_print_cond (struct disassemble_info *info, unsigned int cond)
269*3d8817e4Smiod {
270*3d8817e4Smiod   static tic4x_cond_t **condtable = NULL;
271*3d8817e4Smiod   unsigned int i;
272*3d8817e4Smiod 
273*3d8817e4Smiod   if (condtable == NULL)
274*3d8817e4Smiod     {
275*3d8817e4Smiod       condtable = xmalloc (sizeof (tic4x_cond_t *) * 32);
276*3d8817e4Smiod       for (i = 0; i < tic4x_num_conds; i++)
277*3d8817e4Smiod 	condtable[tic4x_conds[i].cond] = (tic4x_cond_t *)(tic4x_conds + i);
278*3d8817e4Smiod     }
279*3d8817e4Smiod   if (cond > 31 || condtable[cond] == NULL)
280*3d8817e4Smiod     return 0;
281*3d8817e4Smiod   if (info != NULL)
282*3d8817e4Smiod     (*info->fprintf_func) (info->stream, "%s", condtable[cond]->name);
283*3d8817e4Smiod   return 1;
284*3d8817e4Smiod }
285*3d8817e4Smiod 
286*3d8817e4Smiod static int
tic4x_print_indirect(struct disassemble_info * info,indirect_t type,unsigned long arg)287*3d8817e4Smiod tic4x_print_indirect (struct disassemble_info *info,
288*3d8817e4Smiod 		      indirect_t type,
289*3d8817e4Smiod 		      unsigned long arg)
290*3d8817e4Smiod {
291*3d8817e4Smiod   unsigned int aregno;
292*3d8817e4Smiod   unsigned int modn;
293*3d8817e4Smiod   unsigned int disp;
294*3d8817e4Smiod   char *a;
295*3d8817e4Smiod 
296*3d8817e4Smiod   aregno = 0;
297*3d8817e4Smiod   modn = 0;
298*3d8817e4Smiod   disp = 1;
299*3d8817e4Smiod   switch(type)
300*3d8817e4Smiod     {
301*3d8817e4Smiod     case INDIRECT_TIC4X:		/* *+ARn(disp) */
302*3d8817e4Smiod       disp = EXTRU (arg, 7, 3);
303*3d8817e4Smiod       aregno = EXTRU (arg, 2, 0) + REG_AR0;
304*3d8817e4Smiod       modn = 0;
305*3d8817e4Smiod       break;
306*3d8817e4Smiod     case INDIRECT_SHORT:
307*3d8817e4Smiod       disp = 1;
308*3d8817e4Smiod       aregno = EXTRU (arg, 2, 0) + REG_AR0;
309*3d8817e4Smiod       modn = EXTRU (arg, 7, 3);
310*3d8817e4Smiod       break;
311*3d8817e4Smiod     case INDIRECT_LONG:
312*3d8817e4Smiod       disp = EXTRU (arg, 7, 0);
313*3d8817e4Smiod       aregno = EXTRU (arg, 10, 8) + REG_AR0;
314*3d8817e4Smiod       modn = EXTRU (arg, 15, 11);
315*3d8817e4Smiod       if (modn > 7 && disp != 0)
316*3d8817e4Smiod 	return 0;
317*3d8817e4Smiod       break;
318*3d8817e4Smiod     default:
319*3d8817e4Smiod         (*info->fprintf_func)(info->stream, "# internal error: Unknown indirect type %d", type);
320*3d8817e4Smiod         return 0;
321*3d8817e4Smiod     }
322*3d8817e4Smiod   if (modn > TIC3X_MODN_MAX)
323*3d8817e4Smiod     return 0;
324*3d8817e4Smiod   a = tic4x_indirects[modn].name;
325*3d8817e4Smiod   while (*a)
326*3d8817e4Smiod     {
327*3d8817e4Smiod       switch (*a)
328*3d8817e4Smiod 	{
329*3d8817e4Smiod 	case 'a':
330*3d8817e4Smiod 	  tic4x_print_register (info, aregno);
331*3d8817e4Smiod 	  break;
332*3d8817e4Smiod 	case 'd':
333*3d8817e4Smiod 	  tic4x_print_immed (info, IMMED_UINT, disp);
334*3d8817e4Smiod 	  break;
335*3d8817e4Smiod 	case 'y':
336*3d8817e4Smiod 	  tic4x_print_str (info, "ir0");
337*3d8817e4Smiod 	  break;
338*3d8817e4Smiod 	case 'z':
339*3d8817e4Smiod 	  tic4x_print_str (info, "ir1");
340*3d8817e4Smiod 	  break;
341*3d8817e4Smiod 	default:
342*3d8817e4Smiod 	  tic4x_print_char (info, *a);
343*3d8817e4Smiod 	  break;
344*3d8817e4Smiod 	}
345*3d8817e4Smiod       a++;
346*3d8817e4Smiod     }
347*3d8817e4Smiod   return 1;
348*3d8817e4Smiod }
349*3d8817e4Smiod 
350*3d8817e4Smiod static int
tic4x_print_op(struct disassemble_info * info,unsigned long instruction,tic4x_inst_t * p,unsigned long pc)351*3d8817e4Smiod tic4x_print_op (struct disassemble_info *info,
352*3d8817e4Smiod 		unsigned long instruction,
353*3d8817e4Smiod 		tic4x_inst_t *p,
354*3d8817e4Smiod 		unsigned long pc)
355*3d8817e4Smiod {
356*3d8817e4Smiod   int val;
357*3d8817e4Smiod   char *s;
358*3d8817e4Smiod   char *parallel = NULL;
359*3d8817e4Smiod 
360*3d8817e4Smiod   /* Print instruction name.  */
361*3d8817e4Smiod   s = p->name;
362*3d8817e4Smiod   while (*s && parallel == NULL)
363*3d8817e4Smiod     {
364*3d8817e4Smiod       switch (*s)
365*3d8817e4Smiod 	{
366*3d8817e4Smiod 	case 'B':
367*3d8817e4Smiod 	  if (! tic4x_print_cond (info, EXTRU (instruction, 20, 16)))
368*3d8817e4Smiod 	    return 0;
369*3d8817e4Smiod 	  break;
370*3d8817e4Smiod 	case 'C':
371*3d8817e4Smiod 	  if (! tic4x_print_cond (info, EXTRU (instruction, 27, 23)))
372*3d8817e4Smiod 	    return 0;
373*3d8817e4Smiod 	  break;
374*3d8817e4Smiod 	case '_':
375*3d8817e4Smiod 	  parallel = s + 1;	/* Skip past `_' in name.  */
376*3d8817e4Smiod 	  break;
377*3d8817e4Smiod 	default:
378*3d8817e4Smiod 	  tic4x_print_char (info, *s);
379*3d8817e4Smiod 	  break;
380*3d8817e4Smiod 	}
381*3d8817e4Smiod       s++;
382*3d8817e4Smiod     }
383*3d8817e4Smiod 
384*3d8817e4Smiod   /* Print arguments.  */
385*3d8817e4Smiod   s = p->args;
386*3d8817e4Smiod   if (*s)
387*3d8817e4Smiod     tic4x_print_char (info, ' ');
388*3d8817e4Smiod 
389*3d8817e4Smiod   while (*s)
390*3d8817e4Smiod     {
391*3d8817e4Smiod       switch (*s)
392*3d8817e4Smiod 	{
393*3d8817e4Smiod 	case '*': /* Indirect 0--15.  */
394*3d8817e4Smiod 	  if (! tic4x_print_indirect (info, INDIRECT_LONG,
395*3d8817e4Smiod 				      EXTRU (instruction, 15, 0)))
396*3d8817e4Smiod 	    return 0;
397*3d8817e4Smiod 	  break;
398*3d8817e4Smiod 
399*3d8817e4Smiod 	case '#': /* Only used for ldp, ldpk.  */
400*3d8817e4Smiod 	  tic4x_print_immed (info, IMMED_UINT, EXTRU (instruction, 15, 0));
401*3d8817e4Smiod 	  break;
402*3d8817e4Smiod 
403*3d8817e4Smiod 	case '@': /* Direct 0--15.  */
404*3d8817e4Smiod 	  tic4x_print_direct (info, EXTRU (instruction, 15, 0));
405*3d8817e4Smiod 	  break;
406*3d8817e4Smiod 
407*3d8817e4Smiod 	case 'A': /* Address register 24--22.  */
408*3d8817e4Smiod 	  if (! tic4x_print_register (info, EXTRU (instruction, 24, 22) +
409*3d8817e4Smiod 				      REG_AR0))
410*3d8817e4Smiod 	    return 0;
411*3d8817e4Smiod 	  break;
412*3d8817e4Smiod 
413*3d8817e4Smiod 	case 'B': /* 24-bit unsigned int immediate br(d)/call/rptb
414*3d8817e4Smiod 		     address 0--23.  */
415*3d8817e4Smiod 	  if (IS_CPU_TIC4X (tic4x_version))
416*3d8817e4Smiod 	    tic4x_print_relative (info, pc, EXTRS (instruction, 23, 0),
417*3d8817e4Smiod 				  p->opcode);
418*3d8817e4Smiod 	  else
419*3d8817e4Smiod 	    tic4x_print_addr (info, EXTRU (instruction, 23, 0));
420*3d8817e4Smiod 	  break;
421*3d8817e4Smiod 
422*3d8817e4Smiod 	case 'C': /* Indirect (short C4x) 0--7.  */
423*3d8817e4Smiod 	  if (! IS_CPU_TIC4X (tic4x_version))
424*3d8817e4Smiod 	    return 0;
425*3d8817e4Smiod 	  if (! tic4x_print_indirect (info, INDIRECT_TIC4X,
426*3d8817e4Smiod 				      EXTRU (instruction, 7, 0)))
427*3d8817e4Smiod 	    return 0;
428*3d8817e4Smiod 	  break;
429*3d8817e4Smiod 
430*3d8817e4Smiod 	case 'D':
431*3d8817e4Smiod 	  /* Cockup if get here...  */
432*3d8817e4Smiod 	  break;
433*3d8817e4Smiod 
434*3d8817e4Smiod 	case 'E': /* Register 0--7.  */
435*3d8817e4Smiod         case 'e':
436*3d8817e4Smiod 	  if (! tic4x_print_register (info, EXTRU (instruction, 7, 0)))
437*3d8817e4Smiod 	    return 0;
438*3d8817e4Smiod 	  break;
439*3d8817e4Smiod 
440*3d8817e4Smiod 	case 'F': /* 16-bit float immediate 0--15.  */
441*3d8817e4Smiod 	  tic4x_print_immed (info, IMMED_SFLOAT,
442*3d8817e4Smiod 			     EXTRU (instruction, 15, 0));
443*3d8817e4Smiod 	  break;
444*3d8817e4Smiod 
445*3d8817e4Smiod         case 'i': /* Extended indirect 0--7.  */
446*3d8817e4Smiod           if (EXTRU (instruction, 7, 5) == 7)
447*3d8817e4Smiod             {
448*3d8817e4Smiod               if (!tic4x_print_register (info, EXTRU (instruction, 4, 0)))
449*3d8817e4Smiod                 return 0;
450*3d8817e4Smiod               break;
451*3d8817e4Smiod             }
452*3d8817e4Smiod           /* Fallthrough */
453*3d8817e4Smiod 
454*3d8817e4Smiod 	case 'I': /* Indirect (short) 0--7.  */
455*3d8817e4Smiod 	  if (! tic4x_print_indirect (info, INDIRECT_SHORT,
456*3d8817e4Smiod 				      EXTRU (instruction, 7, 0)))
457*3d8817e4Smiod 	    return 0;
458*3d8817e4Smiod 	  break;
459*3d8817e4Smiod 
460*3d8817e4Smiod         case 'j': /* Extended indirect 8--15 */
461*3d8817e4Smiod           if (EXTRU (instruction, 15, 13) == 7)
462*3d8817e4Smiod             {
463*3d8817e4Smiod               if (! tic4x_print_register (info, EXTRU (instruction, 12, 8)))
464*3d8817e4Smiod                 return 0;
465*3d8817e4Smiod               break;
466*3d8817e4Smiod             }
467*3d8817e4Smiod 
468*3d8817e4Smiod 	case 'J': /* Indirect (short) 8--15.  */
469*3d8817e4Smiod 	  if (! tic4x_print_indirect (info, INDIRECT_SHORT,
470*3d8817e4Smiod 				      EXTRU (instruction, 15, 8)))
471*3d8817e4Smiod 	    return 0;
472*3d8817e4Smiod 	  break;
473*3d8817e4Smiod 
474*3d8817e4Smiod 	case 'G': /* Register 8--15.  */
475*3d8817e4Smiod         case 'g':
476*3d8817e4Smiod 	  if (! tic4x_print_register (info, EXTRU (instruction, 15, 8)))
477*3d8817e4Smiod 	    return 0;
478*3d8817e4Smiod 	  break;
479*3d8817e4Smiod 
480*3d8817e4Smiod 	case 'H': /* Register 16--18.  */
481*3d8817e4Smiod 	  if (! tic4x_print_register (info, EXTRU (instruction, 18, 16)))
482*3d8817e4Smiod 	    return 0;
483*3d8817e4Smiod 	  break;
484*3d8817e4Smiod 
485*3d8817e4Smiod 	case 'K': /* Register 19--21.  */
486*3d8817e4Smiod 	  if (! tic4x_print_register (info, EXTRU (instruction, 21, 19)))
487*3d8817e4Smiod 	    return 0;
488*3d8817e4Smiod 	  break;
489*3d8817e4Smiod 
490*3d8817e4Smiod 	case 'L': /* Register 22--24.  */
491*3d8817e4Smiod 	  if (! tic4x_print_register (info, EXTRU (instruction, 24, 22)))
492*3d8817e4Smiod 	    return 0;
493*3d8817e4Smiod 	  break;
494*3d8817e4Smiod 
495*3d8817e4Smiod 	case 'M': /* Register 22--22.  */
496*3d8817e4Smiod 	  tic4x_print_register (info, EXTRU (instruction, 22, 22) + REG_R2);
497*3d8817e4Smiod 	  break;
498*3d8817e4Smiod 
499*3d8817e4Smiod 	case 'N': /* Register 23--23.  */
500*3d8817e4Smiod 	  tic4x_print_register (info, EXTRU (instruction, 23, 23) + REG_R0);
501*3d8817e4Smiod 	  break;
502*3d8817e4Smiod 
503*3d8817e4Smiod 	case 'O': /* Indirect (short C4x) 8--15.  */
504*3d8817e4Smiod 	  if (! IS_CPU_TIC4X (tic4x_version))
505*3d8817e4Smiod 	    return 0;
506*3d8817e4Smiod 	  if (! tic4x_print_indirect (info, INDIRECT_TIC4X,
507*3d8817e4Smiod 				      EXTRU (instruction, 15, 8)))
508*3d8817e4Smiod 	    return 0;
509*3d8817e4Smiod 	  break;
510*3d8817e4Smiod 
511*3d8817e4Smiod 	case 'P': /* Displacement 0--15 (used by Bcond and BcondD).  */
512*3d8817e4Smiod 	  tic4x_print_relative (info, pc, EXTRS (instruction, 15, 0),
513*3d8817e4Smiod 				p->opcode);
514*3d8817e4Smiod 	  break;
515*3d8817e4Smiod 
516*3d8817e4Smiod 	case 'Q': /* Register 0--15.  */
517*3d8817e4Smiod         case 'q':
518*3d8817e4Smiod 	  if (! tic4x_print_register (info, EXTRU (instruction, 15, 0)))
519*3d8817e4Smiod 	    return 0;
520*3d8817e4Smiod 	  break;
521*3d8817e4Smiod 
522*3d8817e4Smiod 	case 'R': /* Register 16--20.  */
523*3d8817e4Smiod         case 'r':
524*3d8817e4Smiod 	  if (! tic4x_print_register (info, EXTRU (instruction, 20, 16)))
525*3d8817e4Smiod 	    return 0;
526*3d8817e4Smiod 	  break;
527*3d8817e4Smiod 
528*3d8817e4Smiod 	case 'S': /* 16-bit signed immediate 0--15.  */
529*3d8817e4Smiod 	  tic4x_print_immed (info, IMMED_SINT,
530*3d8817e4Smiod 			     EXTRS (instruction, 15, 0));
531*3d8817e4Smiod 	  break;
532*3d8817e4Smiod 
533*3d8817e4Smiod 	case 'T': /* 5-bit signed immediate 16--20  (C4x stik).  */
534*3d8817e4Smiod 	  if (! IS_CPU_TIC4X (tic4x_version))
535*3d8817e4Smiod 	    return 0;
536*3d8817e4Smiod 	  if (! tic4x_print_immed (info, IMMED_SUINT,
537*3d8817e4Smiod 				   EXTRU (instruction, 20, 16)))
538*3d8817e4Smiod 	    return 0;
539*3d8817e4Smiod 	  break;
540*3d8817e4Smiod 
541*3d8817e4Smiod 	case 'U': /* 16-bit unsigned int immediate 0--15.  */
542*3d8817e4Smiod 	  tic4x_print_immed (info, IMMED_SUINT, EXTRU (instruction, 15, 0));
543*3d8817e4Smiod 	  break;
544*3d8817e4Smiod 
545*3d8817e4Smiod 	case 'V': /* 5/9-bit unsigned vector 0--4/8.  */
546*3d8817e4Smiod 	  tic4x_print_immed (info, IMMED_SUINT,
547*3d8817e4Smiod 			     IS_CPU_TIC4X (tic4x_version) ?
548*3d8817e4Smiod 			     EXTRU (instruction, 8, 0) :
549*3d8817e4Smiod 			     EXTRU (instruction, 4, 0) & ~0x20);
550*3d8817e4Smiod 	  break;
551*3d8817e4Smiod 
552*3d8817e4Smiod 	case 'W': /* 8-bit signed immediate 0--7.  */
553*3d8817e4Smiod 	  if (! IS_CPU_TIC4X (tic4x_version))
554*3d8817e4Smiod 	    return 0;
555*3d8817e4Smiod 	  tic4x_print_immed (info, IMMED_SINT, EXTRS (instruction, 7, 0));
556*3d8817e4Smiod 	  break;
557*3d8817e4Smiod 
558*3d8817e4Smiod 	case 'X': /* Expansion register 4--0.  */
559*3d8817e4Smiod 	  val = EXTRU (instruction, 4, 0) + REG_IVTP;
560*3d8817e4Smiod 	  if (val < REG_IVTP || val > REG_TVTP)
561*3d8817e4Smiod 	    return 0;
562*3d8817e4Smiod 	  if (! tic4x_print_register (info, val))
563*3d8817e4Smiod 	    return 0;
564*3d8817e4Smiod 	  break;
565*3d8817e4Smiod 
566*3d8817e4Smiod 	case 'Y': /* Address register 16--20.  */
567*3d8817e4Smiod 	  val = EXTRU (instruction, 20, 16);
568*3d8817e4Smiod 	  if (val < REG_AR0 || val > REG_SP)
569*3d8817e4Smiod 	    return 0;
570*3d8817e4Smiod 	  if (! tic4x_print_register (info, val))
571*3d8817e4Smiod 	    return 0;
572*3d8817e4Smiod 	  break;
573*3d8817e4Smiod 
574*3d8817e4Smiod 	case 'Z': /* Expansion register 16--20.  */
575*3d8817e4Smiod 	  val = EXTRU (instruction, 20, 16) + REG_IVTP;
576*3d8817e4Smiod 	  if (val < REG_IVTP || val > REG_TVTP)
577*3d8817e4Smiod 	    return 0;
578*3d8817e4Smiod 	  if (! tic4x_print_register (info, val))
579*3d8817e4Smiod 	    return 0;
580*3d8817e4Smiod 	  break;
581*3d8817e4Smiod 
582*3d8817e4Smiod 	case '|':	/* Parallel instruction.  */
583*3d8817e4Smiod 	  tic4x_print_str (info, " || ");
584*3d8817e4Smiod 	  tic4x_print_str (info, parallel);
585*3d8817e4Smiod 	  tic4x_print_char (info, ' ');
586*3d8817e4Smiod 	  break;
587*3d8817e4Smiod 
588*3d8817e4Smiod 	case ';':
589*3d8817e4Smiod 	  tic4x_print_char (info, ',');
590*3d8817e4Smiod 	  break;
591*3d8817e4Smiod 
592*3d8817e4Smiod 	default:
593*3d8817e4Smiod 	  tic4x_print_char (info, *s);
594*3d8817e4Smiod 	  break;
595*3d8817e4Smiod 	}
596*3d8817e4Smiod       s++;
597*3d8817e4Smiod     }
598*3d8817e4Smiod   return 1;
599*3d8817e4Smiod }
600*3d8817e4Smiod 
601*3d8817e4Smiod static void
tic4x_hash_opcode_special(tic4x_inst_t ** optable_special,const tic4x_inst_t * inst)602*3d8817e4Smiod tic4x_hash_opcode_special (tic4x_inst_t **optable_special,
603*3d8817e4Smiod 			   const tic4x_inst_t *inst)
604*3d8817e4Smiod {
605*3d8817e4Smiod   int i;
606*3d8817e4Smiod 
607*3d8817e4Smiod   for (i = 0;i < TIC4X_SPESOP_SIZE; i++)
608*3d8817e4Smiod     if (optable_special[i] != NULL
609*3d8817e4Smiod         && optable_special[i]->opcode == inst->opcode)
610*3d8817e4Smiod       {
611*3d8817e4Smiod         /* Collision (we have it already) - overwrite.  */
612*3d8817e4Smiod         optable_special[i] = (tic4x_inst_t *) inst;
613*3d8817e4Smiod         return;
614*3d8817e4Smiod       }
615*3d8817e4Smiod 
616*3d8817e4Smiod   for (i = 0; i < TIC4X_SPESOP_SIZE; i++)
617*3d8817e4Smiod     if (optable_special[i] == NULL)
618*3d8817e4Smiod       {
619*3d8817e4Smiod         /* Add the new opcode.  */
620*3d8817e4Smiod         optable_special[i] = (tic4x_inst_t *) inst;
621*3d8817e4Smiod         return;
622*3d8817e4Smiod       }
623*3d8817e4Smiod 
624*3d8817e4Smiod   /* This should never occur. This happens if the number of special
625*3d8817e4Smiod      instructions exceeds TIC4X_SPESOP_SIZE. Please increase the variable
626*3d8817e4Smiod      of this variable */
627*3d8817e4Smiod #if TIC4X_DEBUG
628*3d8817e4Smiod   printf ("optable_special[] is full, please increase TIC4X_SPESOP_SIZE!\n");
629*3d8817e4Smiod #endif
630*3d8817e4Smiod }
631*3d8817e4Smiod 
632*3d8817e4Smiod static void
tic4x_hash_opcode(tic4x_inst_t ** optable,tic4x_inst_t ** optable_special,const tic4x_inst_t * inst,const unsigned long tic4x_oplevel)633*3d8817e4Smiod tic4x_hash_opcode (tic4x_inst_t **optable,
634*3d8817e4Smiod 		   tic4x_inst_t **optable_special,
635*3d8817e4Smiod 		   const tic4x_inst_t *inst,
636*3d8817e4Smiod 		   const unsigned long tic4x_oplevel)
637*3d8817e4Smiod {
638*3d8817e4Smiod   int j;
639*3d8817e4Smiod   int opcode = inst->opcode >> (32 - TIC4X_HASH_SIZE);
640*3d8817e4Smiod   int opmask = inst->opmask >> (32 - TIC4X_HASH_SIZE);
641*3d8817e4Smiod 
642*3d8817e4Smiod   /* Use a TIC4X_HASH_SIZE bit index as a hash index.  We should
643*3d8817e4Smiod      have unique entries so there's no point having a linked list
644*3d8817e4Smiod      for each entry?  */
645*3d8817e4Smiod   for (j = opcode; j < opmask; j++)
646*3d8817e4Smiod     if ((j & opmask) == opcode
647*3d8817e4Smiod          && inst->oplevel & tic4x_oplevel)
648*3d8817e4Smiod       {
649*3d8817e4Smiod #if TIC4X_DEBUG
650*3d8817e4Smiod 	/* We should only have collisions for synonyms like
651*3d8817e4Smiod 	   ldp for ldi.  */
652*3d8817e4Smiod 	if (optable[j] != NULL)
653*3d8817e4Smiod 	  printf ("Collision at index %d, %s and %s\n",
654*3d8817e4Smiod 		  j, optable[j]->name, inst->name);
655*3d8817e4Smiod #endif
656*3d8817e4Smiod         /* Catch those ops that collide with others already inside the
657*3d8817e4Smiod            hash, and have a opmask greater than the one we use in the
658*3d8817e4Smiod            hash. Store them in a special-list, that will handle full
659*3d8817e4Smiod            32-bit INSN, not only the first 11-bit (or so). */
660*3d8817e4Smiod         if (optable[j] != NULL
661*3d8817e4Smiod 	    && inst->opmask & ~(opmask << (32 - TIC4X_HASH_SIZE)))
662*3d8817e4Smiod           {
663*3d8817e4Smiod             /* Add the instruction already on the list.  */
664*3d8817e4Smiod             tic4x_hash_opcode_special (optable_special, optable[j]);
665*3d8817e4Smiod 
666*3d8817e4Smiod             /* Add the new instruction.  */
667*3d8817e4Smiod             tic4x_hash_opcode_special (optable_special, inst);
668*3d8817e4Smiod           }
669*3d8817e4Smiod 
670*3d8817e4Smiod         optable[j] = (tic4x_inst_t *) inst;
671*3d8817e4Smiod       }
672*3d8817e4Smiod }
673*3d8817e4Smiod 
674*3d8817e4Smiod /* Disassemble the instruction in 'instruction'.
675*3d8817e4Smiod    'pc' should be the address of this instruction, it will
676*3d8817e4Smiod    be used to print the target address if this is a relative jump or call
677*3d8817e4Smiod    the disassembled instruction is written to 'info'.
678*3d8817e4Smiod    The function returns the length of this instruction in words.  */
679*3d8817e4Smiod 
680*3d8817e4Smiod static int
tic4x_disassemble(unsigned long pc,unsigned long instruction,struct disassemble_info * info)681*3d8817e4Smiod tic4x_disassemble (unsigned long pc,
682*3d8817e4Smiod 		   unsigned long instruction,
683*3d8817e4Smiod 		   struct disassemble_info *info)
684*3d8817e4Smiod {
685*3d8817e4Smiod   static tic4x_inst_t **optable = NULL;
686*3d8817e4Smiod   static tic4x_inst_t **optable_special = NULL;
687*3d8817e4Smiod   tic4x_inst_t *p;
688*3d8817e4Smiod   int i;
689*3d8817e4Smiod   unsigned long tic4x_oplevel;
690*3d8817e4Smiod 
691*3d8817e4Smiod   tic4x_version = info->mach;
692*3d8817e4Smiod 
693*3d8817e4Smiod   tic4x_oplevel  = (IS_CPU_TIC4X (tic4x_version)) ? OP_C4X : 0;
694*3d8817e4Smiod   tic4x_oplevel |= OP_C3X | OP_LPWR | OP_IDLE2 | OP_ENH;
695*3d8817e4Smiod 
696*3d8817e4Smiod   if (optable == NULL)
697*3d8817e4Smiod     {
698*3d8817e4Smiod       optable = xcalloc (sizeof (tic4x_inst_t *), (1 << TIC4X_HASH_SIZE));
699*3d8817e4Smiod 
700*3d8817e4Smiod       optable_special = xcalloc (sizeof (tic4x_inst_t *), TIC4X_SPESOP_SIZE);
701*3d8817e4Smiod 
702*3d8817e4Smiod       /* Install opcodes in reverse order so that preferred
703*3d8817e4Smiod 	 forms overwrite synonyms.  */
704*3d8817e4Smiod       for (i = tic4x_num_insts - 1; i >= 0; i--)
705*3d8817e4Smiod         tic4x_hash_opcode (optable, optable_special, &tic4x_insts[i],
706*3d8817e4Smiod 			   tic4x_oplevel);
707*3d8817e4Smiod 
708*3d8817e4Smiod       /* We now need to remove the insn that are special from the
709*3d8817e4Smiod          "normal" optable, to make the disasm search this extra list
710*3d8817e4Smiod          for them.  */
711*3d8817e4Smiod       for (i = 0; i < TIC4X_SPESOP_SIZE; i++)
712*3d8817e4Smiod         if (optable_special[i] != NULL)
713*3d8817e4Smiod           optable[optable_special[i]->opcode >> (32 - TIC4X_HASH_SIZE)] = NULL;
714*3d8817e4Smiod     }
715*3d8817e4Smiod 
716*3d8817e4Smiod   /* See if we can pick up any loading of the DP register...  */
717*3d8817e4Smiod   if ((instruction >> 16) == 0x5070 || (instruction >> 16) == 0x1f70)
718*3d8817e4Smiod     tic4x_dp = EXTRU (instruction, 15, 0);
719*3d8817e4Smiod 
720*3d8817e4Smiod   p = optable[instruction >> (32 - TIC4X_HASH_SIZE)];
721*3d8817e4Smiod   if (p != NULL)
722*3d8817e4Smiod     {
723*3d8817e4Smiod       if (((instruction & p->opmask) == p->opcode)
724*3d8817e4Smiod            && tic4x_print_op (NULL, instruction, p, pc))
725*3d8817e4Smiod         tic4x_print_op (info, instruction, p, pc);
726*3d8817e4Smiod       else
727*3d8817e4Smiod         (*info->fprintf_func) (info->stream, "%08lx", instruction);
728*3d8817e4Smiod     }
729*3d8817e4Smiod   else
730*3d8817e4Smiod     {
731*3d8817e4Smiod       for (i = 0; i<TIC4X_SPESOP_SIZE; i++)
732*3d8817e4Smiod         if (optable_special[i] != NULL
733*3d8817e4Smiod             && optable_special[i]->opcode == instruction)
734*3d8817e4Smiod           {
735*3d8817e4Smiod             (*info->fprintf_func)(info->stream, "%s", optable_special[i]->name);
736*3d8817e4Smiod             break;
737*3d8817e4Smiod           }
738*3d8817e4Smiod       if (i == TIC4X_SPESOP_SIZE)
739*3d8817e4Smiod         (*info->fprintf_func) (info->stream, "%08lx", instruction);
740*3d8817e4Smiod     }
741*3d8817e4Smiod 
742*3d8817e4Smiod   /* Return size of insn in words.  */
743*3d8817e4Smiod   return 1;
744*3d8817e4Smiod }
745*3d8817e4Smiod 
746*3d8817e4Smiod /* The entry point from objdump and gdb.  */
747*3d8817e4Smiod int
print_insn_tic4x(bfd_vma memaddr,struct disassemble_info * info)748*3d8817e4Smiod print_insn_tic4x (bfd_vma memaddr, struct disassemble_info *info)
749*3d8817e4Smiod {
750*3d8817e4Smiod   int status;
751*3d8817e4Smiod   unsigned long pc;
752*3d8817e4Smiod   unsigned long op;
753*3d8817e4Smiod   bfd_byte buffer[4];
754*3d8817e4Smiod 
755*3d8817e4Smiod   status = (*info->read_memory_func) (memaddr, buffer, 4, info);
756*3d8817e4Smiod   if (status != 0)
757*3d8817e4Smiod     {
758*3d8817e4Smiod       (*info->memory_error_func) (status, memaddr, info);
759*3d8817e4Smiod       return -1;
760*3d8817e4Smiod     }
761*3d8817e4Smiod 
762*3d8817e4Smiod   pc = memaddr;
763*3d8817e4Smiod   op = bfd_getl32 (buffer);
764*3d8817e4Smiod   info->bytes_per_line = 4;
765*3d8817e4Smiod   info->bytes_per_chunk = 4;
766*3d8817e4Smiod   info->octets_per_byte = 4;
767*3d8817e4Smiod   info->display_endian = BFD_ENDIAN_LITTLE;
768*3d8817e4Smiod   return tic4x_disassemble (pc, op, info) * 4;
769*3d8817e4Smiod }
770