daily update
[binutils.git] / opcodes / tic4x-dis.c
blobeff4ebb8ff1457a36320ee6e514315e2a9267402
1 /* Print instructions for the Texas TMS320C[34]X, for GDB and GNU Binutils.
3 Copyright 2002 Free Software Foundation, Inc.
5 Contributed by Michael P. Hayes (m.hayes@elec.canterbury.ac.nz)
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21 #include <math.h>
22 #include "libiberty.h"
23 #include "dis-asm.h"
24 #include "opcode/tic4x.h"
26 #define C4X_DEBUG 0
28 #define C4X_HASH_SIZE 11 /* 11 and above should give unique entries. */
30 typedef enum
32 IMMED_SINT,
33 IMMED_SUINT,
34 IMMED_SFLOAT,
35 IMMED_INT,
36 IMMED_UINT,
37 IMMED_FLOAT
39 immed_t;
41 typedef enum
43 INDIRECT_SHORT,
44 INDIRECT_LONG,
45 INDIRECT_C4X
47 indirect_t;
49 static int c4x_version = 0;
50 static int c4x_dp = 0;
52 static int
53 c4x_pc_offset (unsigned int op)
55 /* Determine the PC offset for a C[34]x instruction.
56 This could be simplified using some boolean algebra
57 but at the expense of readability. */
58 switch (op >> 24)
60 case 0x60: /* br */
61 case 0x62: /* call (C4x) */
62 case 0x64: /* rptb (C4x) */
63 return 1;
64 case 0x61: /* brd */
65 case 0x63: /* laj */
66 case 0x65: /* rptbd (C4x) */
67 return 3;
68 case 0x66: /* swi */
69 case 0x67:
70 return 0;
71 default:
72 break;
75 switch ((op & 0xffe00000) >> 20)
77 case 0x6a0: /* bB */
78 case 0x720: /* callB */
79 case 0x740: /* trapB */
80 return 1;
82 case 0x6a2: /* bBd */
83 case 0x6a6: /* bBat */
84 case 0x6aa: /* bBaf */
85 case 0x722: /* lajB */
86 case 0x748: /* latB */
87 case 0x798: /* rptbd */
88 return 3;
90 default:
91 break;
94 switch ((op & 0xfe200000) >> 20)
96 case 0x6e0: /* dbB */
97 return 1;
99 case 0x6e2: /* dbBd */
100 return 3;
102 default:
103 break;
106 return 0;
109 static int
110 c4x_print_char (struct disassemble_info * info, char ch)
112 if (info != NULL)
113 (*info->fprintf_func) (info->stream, "%c", ch);
114 return 1;
117 static int
118 c4x_print_str (struct disassemble_info *info, char *str)
120 if (info != NULL)
121 (*info->fprintf_func) (info->stream, "%s", str);
122 return 1;
125 static int
126 c4x_print_register (struct disassemble_info *info,
127 unsigned long regno)
129 static c4x_register_t **registertable = NULL;
130 unsigned int i;
132 if (registertable == NULL)
134 registertable = (c4x_register_t **)
135 xmalloc (sizeof (c4x_register_t *) * REG_TABLE_SIZE);
136 for (i = 0; i < c3x_num_registers; i++)
137 registertable[c3x_registers[i].regno] = (void *)&c3x_registers[i];
138 if (IS_CPU_C4X (c4x_version))
140 /* Add C4x additional registers, overwriting
141 any C3x registers if necessary. */
142 for (i = 0; i < c4x_num_registers; i++)
143 registertable[c4x_registers[i].regno] = (void *)&c4x_registers[i];
146 if ((int) regno > (IS_CPU_C4X (c4x_version) ? C4X_REG_MAX : C3X_REG_MAX))
147 return 0;
148 if (info != NULL)
149 (*info->fprintf_func) (info->stream, "%s", registertable[regno]->name);
150 return 1;
153 static int
154 c4x_print_addr (struct disassemble_info *info,
155 unsigned long addr)
157 if (info != NULL)
158 (*info->print_address_func)(addr, info);
159 return 1;
162 static int
163 c4x_print_relative (struct disassemble_info *info,
164 unsigned long pc,
165 long offset,
166 unsigned long opcode)
168 return c4x_print_addr (info, pc + offset + c4x_pc_offset (opcode));
171 static int
172 c4x_print_direct (struct disassemble_info *info,
173 unsigned long arg)
175 if (info != NULL)
177 (*info->fprintf_func) (info->stream, "@");
178 c4x_print_addr (info, arg + (c4x_dp << 16));
180 return 1;
183 /* FIXME: make the floating point stuff not rely on host
184 floating point arithmetic. */
185 void
186 c4x_print_ftoa (unsigned int val,
187 FILE *stream,
188 int (*pfunc)())
190 int e;
191 int s;
192 int f;
193 double num = 0.0;
195 e = EXTRS (val, 31, 24); /* exponent */
196 if (e != -128)
198 s = EXTRU (val, 23, 23); /* sign bit */
199 f = EXTRU (val, 22, 0); /* mantissa */
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);
207 (*pfunc)(stream, "%.9g", num);
210 static int
211 c4x_print_immed (struct disassemble_info *info,
212 immed_t type,
213 unsigned long arg)
215 int s;
216 int f;
217 int e;
218 double num = 0.0;
220 if (info == NULL)
221 return 1;
222 switch (type)
224 case IMMED_SINT:
225 case IMMED_INT:
226 (*info->fprintf_func) (info->stream, "%d", (long)arg);
227 break;
229 case IMMED_SUINT:
230 case IMMED_UINT:
231 (*info->fprintf_func) (info->stream, "%u", arg);
232 break;
234 case IMMED_SFLOAT:
235 e = EXTRS (arg, 15, 12);
236 if (e != -8)
238 s = EXTRU (arg, 11, 11);
239 f = EXTRU (arg, 10, 0);
240 if (s)
241 f += -2 * (1 << 11);
242 else
243 f += (1 << 11);
244 num = f / (double)(1 << 11);
245 num = ldexp (num, e);
247 (*info->fprintf_func) (info->stream, "%f", num);
248 break;
249 case IMMED_FLOAT:
250 e = EXTRS (arg, 31, 24);
251 if (e != -128)
253 s = EXTRU (arg, 23, 23);
254 f = EXTRU (arg, 22, 0);
255 if (s)
256 f += -2 * (1 << 23);
257 else
258 f += (1 << 23);
259 num = f / (double)(1 << 23);
260 num = ldexp (num, e);
262 (*info->fprintf_func) (info->stream, "%f", num);
263 break;
265 return 1;
268 static int
269 c4x_print_cond (struct disassemble_info *info,
270 unsigned int cond)
272 static c4x_cond_t **condtable = NULL;
273 unsigned int i;
275 if (condtable == NULL)
277 condtable = (c4x_cond_t **)xmalloc (sizeof (c4x_cond_t *) * 32);
278 for (i = 0; i < num_conds; i++)
279 condtable[c4x_conds[i].cond] = (void *)&c4x_conds[i];
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;
288 static int
289 c4x_print_indirect (struct disassemble_info *info,
290 indirect_t type,
291 unsigned long arg)
293 unsigned int aregno;
294 unsigned int modn;
295 unsigned int disp;
296 char *a;
298 aregno = 0;
299 modn = 0;
300 disp = 1;
301 switch(type)
303 case INDIRECT_C4X: /* *+ARn(disp) */
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:
321 abort ();
323 if (modn > C3X_MODN_MAX)
324 return 0;
325 a = c4x_indirects[modn].name;
326 while (*a)
328 switch (*a)
330 case 'a':
331 c4x_print_register (info, aregno);
332 break;
333 case 'd':
334 c4x_print_immed (info, IMMED_UINT, disp);
335 break;
336 case 'y':
337 c4x_print_str (info, "ir0");
338 break;
339 case 'z':
340 c4x_print_str (info, "ir1");
341 break;
342 default:
343 c4x_print_char (info, *a);
344 break;
346 a++;
348 return 1;
351 static int
352 c4x_print_op (struct disassemble_info *info,
353 unsigned long instruction,
354 c4x_inst_t *p, unsigned long pc)
356 int val;
357 char *s;
358 char *parallel = NULL;
360 /* Print instruction name. */
361 s = p->name;
362 while (*s && parallel == NULL)
364 switch (*s)
366 case 'B':
367 if (! c4x_print_cond (info, EXTRU (instruction, 20, 16)))
368 return 0;
369 break;
370 case 'C':
371 if (! c4x_print_cond (info, EXTRU (instruction, 27, 23)))
372 return 0;
373 break;
374 case '_':
375 parallel = s + 1; /* Skip past `_' in name */
376 break;
377 default:
378 c4x_print_char (info, *s);
379 break;
381 s++;
384 /* Print arguments. */
385 s = p->args;
386 if (*s)
387 c4x_print_char (info, ' ');
389 while (*s)
391 switch (*s)
393 case '*': /* indirect 0--15 */
394 if (! c4x_print_indirect (info, INDIRECT_LONG,
395 EXTRU (instruction, 15, 0)))
396 return 0;
397 break;
399 case '#': /* only used for ldp, ldpk */
400 c4x_print_immed (info, IMMED_UINT, EXTRU (instruction, 15, 0));
401 break;
403 case '@': /* direct 0--15 */
404 c4x_print_direct (info, EXTRU (instruction, 15, 0));
405 break;
407 case 'A': /* address register 24--22 */
408 if (! c4x_print_register (info, EXTRU (instruction, 24, 22) +
409 REG_AR0))
410 return 0;
411 break;
413 case 'B': /* 24-bit unsigned int immediate br(d)/call/rptb
414 address 0--23. */
415 if (IS_CPU_C4X (c4x_version))
416 c4x_print_relative (info, pc, EXTRS (instruction, 23, 0),
417 p->opcode);
418 else
419 c4x_print_addr (info, EXTRU (instruction, 23, 0));
420 break;
422 case 'C': /* indirect (short C4x) 0--7 */
423 if (! IS_CPU_C4X (c4x_version))
424 return 0;
425 if (! c4x_print_indirect (info, INDIRECT_C4X,
426 EXTRU (instruction, 7, 0)))
427 return 0;
428 break;
430 case 'D':
431 /* Cockup if get here... */
432 break;
434 case 'E': /* register 0--7 */
435 if (! c4x_print_register (info, EXTRU (instruction, 7, 0)))
436 return 0;
437 break;
439 case 'F': /* 16-bit float immediate 0--15 */
440 c4x_print_immed (info, IMMED_SFLOAT,
441 EXTRU (instruction, 15, 0));
442 break;
444 case 'I': /* indirect (short) 0--7 */
445 if (! c4x_print_indirect (info, INDIRECT_SHORT,
446 EXTRU (instruction, 7, 0)))
447 return 0;
448 break;
450 case 'J': /* indirect (short) 8--15 */
451 if (! c4x_print_indirect (info, INDIRECT_SHORT,
452 EXTRU (instruction, 15, 8)))
453 return 0;
454 break;
456 case 'G': /* register 8--15 */
457 if (! c4x_print_register (info, EXTRU (instruction, 15, 8)))
458 return 0;
459 break;
461 case 'H': /* register 16--18 */
462 if (! c4x_print_register (info, EXTRU (instruction, 18, 16)))
463 return 0;
464 break;
466 case 'K': /* register 19--21 */
467 if (! c4x_print_register (info, EXTRU (instruction, 21, 19)))
468 return 0;
469 break;
471 case 'L': /* register 22--24 */
472 if (! c4x_print_register (info, EXTRU (instruction, 24, 22)))
473 return 0;
474 break;
476 case 'M': /* register 22--22 */
477 c4x_print_register (info, EXTRU (instruction, 22, 22) + REG_R2);
478 break;
480 case 'N': /* register 23--23 */
481 c4x_print_register (info, EXTRU (instruction, 22, 22) + REG_R0);
482 break;
484 case 'O': /* indirect (short C4x) 8--15 */
485 if (! IS_CPU_C4X (c4x_version))
486 return 0;
487 if (! c4x_print_indirect (info, INDIRECT_C4X,
488 EXTRU (instruction, 15, 8)))
489 return 0;
490 break;
492 case 'P': /* displacement 0--15 (used by Bcond and BcondD) */
493 c4x_print_relative (info, pc, EXTRS (instruction, 15, 0),
494 p->opcode);
495 break;
497 case 'Q': /* register 0--15 */
498 if (! c4x_print_register (info, EXTRU (instruction, 15, 0)))
499 return 0;
500 break;
502 case 'R': /* register 16--20 */
503 if (! c4x_print_register (info, EXTRU (instruction, 20, 16)))
504 return 0;
505 break;
507 case 'S': /* 16-bit signed immediate 0--15 */
508 c4x_print_immed (info, IMMED_SINT,
509 EXTRS (instruction, 15, 0));
510 break;
512 case 'T': /* 5-bit signed immediate 16--20 (C4x stik) */
513 if (! IS_CPU_C4X (c4x_version))
514 return 0;
515 if (! c4x_print_immed (info, IMMED_SUINT,
516 EXTRU (instruction, 20, 16)))
517 return 0;
518 break;
520 case 'U': /* 16-bit unsigned int immediate 0--15 */
521 c4x_print_immed (info, IMMED_SUINT, EXTRU (instruction, 15, 0));
522 break;
524 case 'V': /* 5/9-bit unsigned vector 0--4/8 */
525 c4x_print_immed (info, IMMED_SUINT,
526 IS_CPU_C4X (c4x_version) ?
527 EXTRU (instruction, 8, 0) :
528 EXTRU (instruction, 4, 0) & ~0x20);
529 break;
531 case 'W': /* 8-bit signed immediate 0--7 */
532 if (! IS_CPU_C4X (c4x_version))
533 return 0;
534 c4x_print_immed (info, IMMED_SINT, EXTRS (instruction, 7, 0));
535 break;
537 case 'X': /* expansion register 4--0 */
538 val = EXTRU (instruction, 4, 0) + REG_IVTP;
539 if (val < REG_IVTP || val > REG_TVTP)
540 return 0;
541 if (! c4x_print_register (info, val))
542 return 0;
543 break;
545 case 'Y': /* address register 16--20 */
546 val = EXTRU (instruction, 20, 16);
547 if (val < REG_AR0 || val > REG_SP)
548 return 0;
549 if (! c4x_print_register (info, val))
550 return 0;
551 break;
553 case 'Z': /* expansion register 16--20 */
554 val = EXTRU (instruction, 20, 16) + REG_IVTP;
555 if (val < REG_IVTP || val > REG_TVTP)
556 return 0;
557 if (! c4x_print_register (info, val))
558 return 0;
559 break;
561 case '|': /* Parallel instruction */
562 c4x_print_str (info, " || ");
563 c4x_print_str (info, parallel);
564 c4x_print_char (info, ' ');
565 break;
567 case ';':
568 c4x_print_char (info, ',');
569 break;
571 default:
572 c4x_print_char (info, *s);
573 break;
575 s++;
577 return 1;
580 static void
581 c4x_hash_opcode (c4x_inst_t **optable,
582 const c4x_inst_t *inst)
584 int j;
585 int opcode = inst->opcode >> (32 - C4X_HASH_SIZE);
586 int opmask = inst->opmask >> (32 - C4X_HASH_SIZE);
588 /* Use a C4X_HASH_SIZE bit index as a hash index. We should
589 have unique entries so there's no point having a linked list
590 for each entry? */
591 for (j = opcode; j < opmask; j++)
592 if ((j & opmask) == opcode)
594 #if C4X_DEBUG
595 /* We should only have collisions for synonyms like
596 ldp for ldi. */
597 if (optable[j] != NULL)
598 printf("Collision at index %d, %s and %s\n",
599 j, optable[j]->name, inst->name);
600 #endif
601 optable[j] = (void *)inst;
605 /* Disassemble the instruction in 'instruction'.
606 'pc' should be the address of this instruction, it will
607 be used to print the target address if this is a relative jump or call
608 the disassembled instruction is written to 'info'.
609 The function returns the length of this instruction in words. */
611 static int
612 c4x_disassemble (unsigned long pc,
613 unsigned long instruction,
614 struct disassemble_info *info)
616 static c4x_inst_t **optable = NULL;
617 c4x_inst_t *p;
618 int i;
620 c4x_version = info->mach;
622 if (optable == NULL)
624 optable = (c4x_inst_t **)
625 xcalloc (sizeof (c4x_inst_t *), (1 << C4X_HASH_SIZE));
626 /* Install opcodes in reverse order so that preferred
627 forms overwrite synonyms. */
628 for (i = c3x_num_insts - 1; i >= 0; i--)
629 c4x_hash_opcode (optable, &c3x_insts[i]);
630 if (IS_CPU_C4X (c4x_version))
632 for (i = c4x_num_insts - 1; i >= 0; i--)
633 c4x_hash_opcode (optable, &c4x_insts[i]);
637 /* See if we can pick up any loading of the DP register... */
638 if ((instruction >> 16) == 0x5070 || (instruction >> 16) == 0x1f70)
639 c4x_dp = EXTRU (instruction, 15, 0);
641 p = optable[instruction >> (32 - C4X_HASH_SIZE)];
642 if (p != NULL && ((instruction & p->opmask) == p->opcode)
643 && c4x_print_op (NULL, instruction, p, pc))
644 c4x_print_op (info, instruction, p, pc);
645 else
646 (*info->fprintf_func) (info->stream, "%08x", instruction);
648 /* Return size of insn in words. */
649 return 1;
652 /* The entry point from objdump and gdb. */
654 print_insn_tic4x (memaddr, info)
655 bfd_vma memaddr;
656 struct disassemble_info *info;
658 int status;
659 unsigned long pc;
660 unsigned long op;
661 bfd_byte buffer[4];
663 status = (*info->read_memory_func) (memaddr, buffer, 4, info);
664 if (status != 0)
666 (*info->memory_error_func) (status, memaddr, info);
667 return -1;
670 pc = memaddr;
671 op = bfd_getl32 (buffer);
672 info->bytes_per_line = 4;
673 info->bytes_per_chunk = 4;
674 info->octets_per_byte = 4;
675 info->display_endian = BFD_ENDIAN_LITTLE;
676 return c4x_disassemble (pc, op, info) * 4;