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