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