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