2000-05-29 Philip Blundell <philb@gnu.org>
[binutils.git] / opcodes / tic80-dis.c
blob449ce8f7fbac26ee72f145880cf832b58e0ba6d5
1 /* Print TI TMS320C80 (MVP) instructions
2 Copyright 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
4 This file is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 #include <stdio.h>
20 #include "sysdep.h"
21 #include "opcode/tic80.h"
22 #include "dis-asm.h"
24 static int length;
26 static void print_operand_bitnum PARAMS ((struct disassemble_info *, long));
27 static void print_operand_condition_code PARAMS ((struct disassemble_info *, long));
28 static void print_operand_control_register PARAMS ((struct disassemble_info *, long));
29 static void print_operand_float PARAMS ((struct disassemble_info *, long));
30 static void print_operand_integer PARAMS ((struct disassemble_info *, long));
31 static void print_operand PARAMS ((struct disassemble_info *, long, unsigned long,
32 const struct tic80_operand *, bfd_vma));
33 static int print_one_instruction PARAMS ((struct disassemble_info *, bfd_vma,
34 unsigned long, const struct tic80_opcode *));
35 static int print_instruction PARAMS ((struct disassemble_info *, bfd_vma, unsigned long,
36 const struct tic80_opcode *));
37 static int fill_instruction PARAMS ((struct disassemble_info *, bfd_vma,
38 unsigned long *));
41 /* Print an integer operand. Try to be somewhat smart about the
42 format by assuming that small positive or negative integers are
43 probably loop increment values, structure offsets, or similar
44 values that are more meaningful printed as signed decimal values.
45 Larger numbers are probably better printed as hex values. */
47 static void
48 print_operand_integer (info, value)
49 struct disassemble_info *info;
50 long value;
52 if ((value > 9999 || value < -9999))
54 (*info -> fprintf_func) (info -> stream, "%#lx", value);
56 else
58 (*info -> fprintf_func) (info -> stream, "%ld", value);
63 /* FIXME: depends upon sizeof (long) == sizeof (float) and
64 also upon host floating point format matching target
65 floating point format. */
67 static void
68 print_operand_float (info, value)
69 struct disassemble_info *info;
70 long value;
72 union { float f; long l; } fval;
74 fval.l = value;
75 (*info -> fprintf_func) (info -> stream, "%g", fval.f);
79 static void
80 print_operand_control_register (info, value)
81 struct disassemble_info *info;
82 long value;
84 const char *tmp;
86 tmp = tic80_value_to_symbol (value, TIC80_OPERAND_CR);
87 if (tmp != NULL)
89 (*info -> fprintf_func) (info -> stream, "%s", tmp);
91 else
93 (*info -> fprintf_func) (info -> stream, "%#lx", value);
98 static void
99 print_operand_condition_code (info, value)
100 struct disassemble_info *info;
101 long value;
103 const char *tmp;
105 tmp = tic80_value_to_symbol (value, TIC80_OPERAND_CC);
106 if (tmp != NULL)
108 (*info -> fprintf_func) (info -> stream, "%s", tmp);
110 else
112 (*info -> fprintf_func) (info -> stream, "%ld", value);
117 static void
118 print_operand_bitnum (info, value)
119 struct disassemble_info *info;
120 long value;
122 int bitnum;
123 const char *tmp;
125 bitnum = ~value & 0x1F;
126 tmp = tic80_value_to_symbol (bitnum, TIC80_OPERAND_BITNUM);
127 if (tmp != NULL)
129 (*info -> fprintf_func) (info -> stream, "%s", tmp);
131 else
133 (*info -> fprintf_func) (info -> stream, "%ld", bitnum);
138 /* Print the operand as directed by the flags. */
140 #define M_SI(insn,op) ((((op) -> flags & TIC80_OPERAND_M_SI) != 0) && ((insn) & (1 << 17)))
141 #define M_LI(insn,op) ((((op) -> flags & TIC80_OPERAND_M_LI) != 0) && ((insn) & (1 << 15)))
142 #define R_SCALED(insn,op) ((((op) -> flags & TIC80_OPERAND_SCALED) != 0) && ((insn) & (1 << 11)))
144 static void
145 print_operand (info, value, insn, operand, memaddr)
146 struct disassemble_info *info;
147 long value;
148 unsigned long insn;
149 const struct tic80_operand *operand;
150 bfd_vma memaddr;
152 if ((operand -> flags & TIC80_OPERAND_GPR) != 0)
154 (*info -> fprintf_func) (info -> stream, "r%ld", value);
155 if (M_SI (insn, operand) || M_LI (insn, operand))
157 (*info -> fprintf_func) (info -> stream, ":m");
160 else if ((operand -> flags & TIC80_OPERAND_FPA) != 0)
162 (*info -> fprintf_func) (info -> stream, "a%ld", value);
164 else if ((operand -> flags & TIC80_OPERAND_PCREL) != 0)
166 (*info -> print_address_func) (memaddr + 4 * value, info);
168 else if ((operand -> flags & TIC80_OPERAND_BASEREL) != 0)
170 (*info -> print_address_func) (value, info);
172 else if ((operand -> flags & TIC80_OPERAND_BITNUM) != 0)
174 print_operand_bitnum (info, value);
176 else if ((operand -> flags & TIC80_OPERAND_CC) != 0)
178 print_operand_condition_code (info, value);
180 else if ((operand -> flags & TIC80_OPERAND_CR) != 0)
182 print_operand_control_register (info, value);
184 else if ((operand -> flags & TIC80_OPERAND_FLOAT) != 0)
186 print_operand_float (info, value);
188 else if ((operand -> flags & TIC80_OPERAND_BITFIELD))
190 (*info -> fprintf_func) (info -> stream, "%#lx", value);
192 else
194 print_operand_integer (info, value);
197 /* If this is a scaled operand, then print the modifier */
199 if (R_SCALED (insn, operand))
201 (*info -> fprintf_func) (info -> stream, ":s");
206 /* We have chosen an opcode table entry */
208 static int
209 print_one_instruction (info, memaddr, insn, opcode)
210 struct disassemble_info *info;
211 bfd_vma memaddr;
212 unsigned long insn;
213 const struct tic80_opcode *opcode;
215 const struct tic80_operand *operand;
216 long value;
217 int status;
218 const unsigned char *opindex;
219 int close_paren;
221 (*info -> fprintf_func) (info -> stream, "%-10s", opcode -> name);
223 for (opindex = opcode -> operands; *opindex != 0; opindex++)
225 operand = tic80_operands + *opindex;
227 /* Extract the value from the instruction. */
228 if (operand -> extract)
230 value = (*operand -> extract) (insn, (int *) NULL);
232 else if (operand -> bits == 32)
234 status = fill_instruction (info, memaddr, (unsigned long *) &value);
235 if (status == -1)
237 return (status);
240 else
242 value = (insn >> operand -> shift) & ((1 << operand -> bits) - 1);
243 if ((operand -> flags & TIC80_OPERAND_SIGNED) != 0
244 && (value & (1 << (operand -> bits - 1))) != 0)
246 value -= 1 << operand -> bits;
250 /* If this operand is enclosed in parenthesis, then print
251 the open paren, otherwise just print the regular comma
252 separator, except for the first operand. */
254 if ((operand -> flags & TIC80_OPERAND_PARENS) == 0)
256 close_paren = 0;
257 if (opindex != opcode -> operands)
259 (*info -> fprintf_func) (info -> stream, ",");
262 else
264 close_paren = 1;
265 (*info -> fprintf_func) (info -> stream, "(");
268 print_operand (info, value, insn, operand, memaddr);
270 /* If we printed an open paren before printing this operand, close
271 it now. The flag gets reset on each loop. */
273 if (close_paren)
275 (*info -> fprintf_func) (info -> stream, ")");
278 return (length);
283 /* There are no specific bits that tell us for certain whether a vector
284 instruction opcode contains one or two instructions. However since
285 a destination register of r0 is illegal, we can check for nonzero
286 values in both destination register fields. Only opcodes that have
287 two valid instructions will have non-zero in both */
289 #define TWO_INSN(insn) ((((insn) & (0x1F << 27)) != 0) && (((insn) & (0x1F << 22)) != 0))
291 static int
292 print_instruction (info, memaddr, insn, vec_opcode)
293 struct disassemble_info *info;
294 bfd_vma memaddr;
295 unsigned long insn;
296 const struct tic80_opcode *vec_opcode;
298 const struct tic80_opcode *opcode;
299 const struct tic80_opcode *opcode_end;
301 /* Find the first opcode match in the opcodes table. For vector
302 opcodes (vec_opcode != NULL) find the first match that is not the
303 previously found match. FIXME: there should be faster ways to
304 search (hash table or binary search), but don't worry too much
305 about it until other TIc80 support is finished. */
307 opcode_end = tic80_opcodes + tic80_num_opcodes;
308 for (opcode = tic80_opcodes; opcode < opcode_end; opcode++)
310 if ((insn & opcode -> mask) == opcode -> opcode &&
311 opcode != vec_opcode)
313 break;
317 if (opcode == opcode_end)
319 /* No match found, just print the bits as a .word directive */
320 (*info -> fprintf_func) (info -> stream, ".word %#08lx", insn);
322 else
324 /* Match found, decode the instruction. */
325 length = print_one_instruction (info, memaddr, insn, opcode);
326 if (opcode -> flags & TIC80_VECTOR && vec_opcode == NULL && TWO_INSN (insn))
328 /* There is another instruction to print from the same opcode.
329 Print the separator and then find and print the other
330 instruction. */
331 (*info -> fprintf_func) (info -> stream, " || ");
332 length = print_instruction (info, memaddr, insn, opcode);
335 return (length);
338 /* Get the next 32 bit word from the instruction stream and convert it
339 into internal format in the unsigned long INSN, for which we are
340 passed the address. Return 0 on success, -1 on error. */
342 static int
343 fill_instruction (info, memaddr, insnp)
344 struct disassemble_info *info;
345 bfd_vma memaddr;
346 unsigned long *insnp;
348 bfd_byte buffer[4];
349 int status;
351 /* Get the bits for the next 32 bit word and put in buffer */
353 status = (*info -> read_memory_func) (memaddr + length, buffer, 4, info);
354 if (status != 0)
356 (*info -> memory_error_func) (status, memaddr, info);
357 return (-1);
360 /* Read was successful, so increment count of bytes read and convert
361 the bits into internal format. */
363 length += 4;
364 if (info -> endian == BFD_ENDIAN_LITTLE)
366 *insnp = bfd_getl32 (buffer);
368 else if (info -> endian == BFD_ENDIAN_BIG)
370 *insnp = bfd_getb32 (buffer);
372 else
374 /* FIXME: Should probably just default to one or the other */
375 abort ();
377 return (0);
381 int
382 print_insn_tic80 (memaddr, info)
383 bfd_vma memaddr;
384 struct disassemble_info *info;
386 unsigned long insn;
387 int status;
389 length = 0;
390 info->bytes_per_line = 8;
391 status = fill_instruction (info, memaddr, &insn);
392 if (status != -1)
394 status = print_instruction (info, memaddr, insn, NULL);
396 return (status);