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