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