]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - opcodes/tic4x-dis.c
Automatic date update in version.in
[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
fd67aa11 3 Copyright (C) 2002-2024 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
aad09917 54static unsigned long tic4x_version = 0;
1bd8ae10 55static unsigned int tic4x_dp = 0;
aad09917
AM
56static tic4x_inst_t **optab = NULL;
57static tic4x_inst_t **optab_special = NULL;
58static const char *registernames[REG_TABLE_SIZE];
026df7c5
NC
59
60static int
47b0e7ad 61tic4x_pc_offset (unsigned int op)
026df7c5
NC
62{
63 /* Determine the PC offset for a C[34]x instruction.
64 This could be simplified using some boolean algebra
65 but at the expense of readability. */
66 switch (op >> 24)
67 {
68 case 0x60: /* br */
69 case 0x62: /* call (C4x) */
70 case 0x64: /* rptb (C4x) */
71 return 1;
72 case 0x61: /* brd */
73 case 0x63: /* laj */
74 case 0x65: /* rptbd (C4x) */
75 return 3;
76 case 0x66: /* swi */
77 case 0x67:
78 return 0;
79 default:
80 break;
81 }
47b0e7ad 82
026df7c5
NC
83 switch ((op & 0xffe00000) >> 20)
84 {
85 case 0x6a0: /* bB */
86 case 0x720: /* callB */
87 case 0x740: /* trapB */
88 return 1;
47b0e7ad 89
026df7c5
NC
90 case 0x6a2: /* bBd */
91 case 0x6a6: /* bBat */
92 case 0x6aa: /* bBaf */
93 case 0x722: /* lajB */
94 case 0x748: /* latB */
95 case 0x798: /* rptbd */
96 return 3;
47b0e7ad 97
026df7c5
NC
98 default:
99 break;
100 }
47b0e7ad 101
026df7c5
NC
102 switch ((op & 0xfe200000) >> 20)
103 {
104 case 0x6e0: /* dbB */
105 return 1;
47b0e7ad 106
026df7c5
NC
107 case 0x6e2: /* dbBd */
108 return 3;
47b0e7ad 109
026df7c5
NC
110 default:
111 break;
112 }
47b0e7ad 113
026df7c5
NC
114 return 0;
115}
116
117static int
47b0e7ad 118tic4x_print_char (struct disassemble_info * info, char ch)
026df7c5
NC
119{
120 if (info != NULL)
121 (*info->fprintf_func) (info->stream, "%c", ch);
122 return 1;
123}
124
125static int
f86f5863 126tic4x_print_str (struct disassemble_info *info, const char *str)
026df7c5
NC
127{
128 if (info != NULL)
129 (*info->fprintf_func) (info->stream, "%s", str);
130 return 1;
131}
132
133static int
47b0e7ad 134tic4x_print_register (struct disassemble_info *info, unsigned long regno)
026df7c5 135{
026df7c5 136 unsigned int i;
47b0e7ad 137
aad09917 138 if (registernames[REG_R0] == NULL)
026df7c5 139 {
be33c5dd 140 for (i = 0; i < tic3x_num_registers; i++)
aad09917 141 registernames[tic3x_registers[i].regno] = tic3x_registers[i].name;
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++)
aad09917 147 registernames[tic4x_registers[i].regno] = tic4x_registers[i].name;
026df7c5
NC
148 }
149 }
5496abe1 150 if (regno > (IS_CPU_TIC4X (tic4x_version) ? TIC4X_REG_MAX : TIC3X_REG_MAX))
026df7c5
NC
151 return 0;
152 if (info != NULL)
aad09917 153 (*info->fprintf_func) (info->stream, "%s", registernames[regno]);
026df7c5
NC
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 {
2c5b6e1a 278 condtable = xcalloc (32, sizeof (tic4x_cond_t *));
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 641{
66152f16
AM
642 unsigned int j;
643 unsigned int opcode = inst->opcode >> (32 - TIC4X_HASH_SIZE);
644 unsigned 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 689 tic4x_inst_t *p;
026df7c5 690 int i;
be33c5dd 691 unsigned long tic4x_oplevel;
47b0e7ad 692
aad09917
AM
693 if (tic4x_version != info->mach)
694 {
695 tic4x_version = info->mach;
696 /* Don't stash anything from a previous call using a different
697 machine. */
d96bf37b
AM
698 free (optab);
699 optab = NULL;
700 free (optab_special);
701 optab_special = NULL;
aad09917
AM
702 registernames[REG_R0] = NULL;
703 }
9c87d6c7 704
be33c5dd 705 tic4x_oplevel = (IS_CPU_TIC4X (tic4x_version)) ? OP_C4X : 0;
47b0e7ad
NC
706 tic4x_oplevel |= OP_C3X | OP_LPWR | OP_IDLE2 | OP_ENH;
707
aad09917 708 if (optab == NULL)
026df7c5 709 {
5bc519bf 710 optab = xcalloc ((1 << TIC4X_HASH_SIZE), sizeof (tic4x_inst_t *));
9c87d6c7 711
5bc519bf 712 optab_special = xcalloc (TIC4X_SPESOP_SIZE, sizeof (tic4x_inst_t *));
9c87d6c7 713
026df7c5
NC
714 /* Install opcodes in reverse order so that preferred
715 forms overwrite synonyms. */
be33c5dd 716 for (i = tic4x_num_insts - 1; i >= 0; i--)
aad09917 717 tic4x_hash_opcode (optab, optab_special, &tic4x_insts[i],
47b0e7ad 718 tic4x_oplevel);
9c87d6c7
SS
719
720 /* We now need to remove the insn that are special from the
aad09917
AM
721 "normal" optable, to make the disasm search this extra list
722 for them. */
47b0e7ad 723 for (i = 0; i < TIC4X_SPESOP_SIZE; i++)
aad09917
AM
724 if (optab_special[i] != NULL)
725 optab[optab_special[i]->opcode >> (32 - TIC4X_HASH_SIZE)] = NULL;
026df7c5 726 }
47b0e7ad 727
026df7c5
NC
728 /* See if we can pick up any loading of the DP register... */
729 if ((instruction >> 16) == 0x5070 || (instruction >> 16) == 0x1f70)
be33c5dd 730 tic4x_dp = EXTRU (instruction, 15, 0);
9c87d6c7 731
aad09917 732 p = optab[instruction >> (32 - TIC4X_HASH_SIZE)];
47b0e7ad 733 if (p != NULL)
9c87d6c7 734 {
47b0e7ad 735 if (((instruction & p->opmask) == p->opcode)
aad09917
AM
736 && tic4x_print_op (NULL, instruction, p, pc))
737 tic4x_print_op (info, instruction, p, pc);
9c87d6c7 738 else
aad09917 739 (*info->fprintf_func) (info->stream, "%08lx", instruction);
9c87d6c7 740 }
026df7c5 741 else
9c87d6c7 742 {
be33c5dd 743 for (i = 0; i<TIC4X_SPESOP_SIZE; i++)
aad09917
AM
744 if (optab_special[i] != NULL
745 && optab_special[i]->opcode == instruction)
746 {
747 (*info->fprintf_func)(info->stream, "%s", optab_special[i]->name);
748 break;
749 }
47b0e7ad 750 if (i == TIC4X_SPESOP_SIZE)
aad09917 751 (*info->fprintf_func) (info->stream, "%08lx", instruction);
9c87d6c7 752 }
026df7c5
NC
753
754 /* Return size of insn in words. */
47b0e7ad 755 return 1;
026df7c5
NC
756}
757
758/* The entry point from objdump and gdb. */
759int
47b0e7ad 760print_insn_tic4x (bfd_vma memaddr, struct disassemble_info *info)
026df7c5
NC
761{
762 int status;
763 unsigned long pc;
764 unsigned long op;
765 bfd_byte buffer[4];
47b0e7ad 766
026df7c5
NC
767 status = (*info->read_memory_func) (memaddr, buffer, 4, info);
768 if (status != 0)
769 {
770 (*info->memory_error_func) (status, memaddr, info);
771 return -1;
772 }
47b0e7ad 773
026df7c5
NC
774 pc = memaddr;
775 op = bfd_getl32 (buffer);
776 info->bytes_per_line = 4;
777 info->bytes_per_chunk = 4;
778 info->octets_per_byte = 4;
779 info->display_endian = BFD_ENDIAN_LITTLE;
be33c5dd 780 return tic4x_disassemble (pc, op, info) * 4;
026df7c5 781}