OSDN Git Service

6c72976845e28d88d12ddf95bb1effac5fc517a7
[pf3gnuchains/pf3gnuchains3x.git] / opcodes / tic80-dis.c
1 /* Print TI TMS320C80 (MVP) instructions
2    Copyright 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
3
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.
8
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.
13
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.  */
17
18 #include <stdio.h>
19
20 #include "sysdep.h"
21 #include "opcode/tic80.h"
22 #include "dis-asm.h"
23
24 static int length;
25
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 *));
39 \f
40 /* Print an integer operand.  Try to be somewhat smart about the
41    format by assuming that small positive or negative integers are
42    probably loop increment values, structure offsets, or similar
43    values that are more meaningful printed as signed decimal values.
44    Larger numbers are probably better printed as hex values.  */
45
46 static void
47 print_operand_integer (info, value)
48      struct disassemble_info *info;
49      long value;
50 {
51   if ((value > 9999 || value < -9999))
52     {
53       (*info->fprintf_func) (info->stream, "%#lx", value);
54     }
55   else
56     {
57       (*info->fprintf_func) (info->stream, "%ld", value);
58     }
59 }
60 \f
61 /* FIXME: depends upon sizeof (long) == sizeof (float) and
62    also upon host floating point format matching target
63    floating point format.  */
64
65 static void
66 print_operand_float (info, value)
67      struct disassemble_info *info;
68      long value;
69 {
70   union { float f; long l; } fval;
71
72   fval.l = value;
73   (*info->fprintf_func) (info->stream, "%g", fval.f);
74 }
75 \f
76 static void
77 print_operand_control_register (info, value)
78      struct disassemble_info *info;
79      long value;
80 {
81   const char *tmp;
82
83   tmp = tic80_value_to_symbol (value, TIC80_OPERAND_CR);
84   if (tmp != NULL)
85     {
86       (*info->fprintf_func) (info->stream, "%s", tmp);
87     }
88   else
89     {
90       (*info->fprintf_func) (info->stream, "%#lx", value);
91     }
92 }
93 \f
94 static void
95 print_operand_condition_code (info, value)
96      struct disassemble_info *info;
97      long value;
98 {
99   const char *tmp;
100
101   tmp = tic80_value_to_symbol (value, TIC80_OPERAND_CC);
102   if (tmp != NULL)
103     {
104       (*info->fprintf_func) (info->stream, "%s", tmp);
105     }
106   else
107     {
108       (*info->fprintf_func) (info->stream, "%ld", value);
109     }
110 }
111 \f
112 static void
113 print_operand_bitnum (info, value)
114      struct disassemble_info *info;
115      long value;
116 {
117   int bitnum;
118   const char *tmp;
119
120   bitnum = ~value & 0x1F;
121   tmp = tic80_value_to_symbol (bitnum, TIC80_OPERAND_BITNUM);
122   if (tmp != NULL)
123     {
124       (*info->fprintf_func) (info->stream, "%s", tmp);
125     }
126   else
127     {
128       (*info->fprintf_func) (info->stream, "%ld", bitnum);
129     }
130 }
131 \f
132 /* Print the operand as directed by the flags.  */
133
134 #define M_SI(insn,op) ((((op)->flags & TIC80_OPERAND_M_SI) != 0) && ((insn) & (1 << 17)))
135 #define M_LI(insn,op) ((((op)->flags & TIC80_OPERAND_M_LI) != 0) && ((insn) & (1 << 15)))
136 #define R_SCALED(insn,op) ((((op)->flags & TIC80_OPERAND_SCALED) != 0) && ((insn) & (1 << 11)))
137
138 static void
139 print_operand (info, value, insn, operand, memaddr)
140      struct disassemble_info *info;
141      long value;
142      unsigned long insn;
143      const struct tic80_operand *operand;
144      bfd_vma memaddr;
145 {
146   if ((operand->flags & TIC80_OPERAND_GPR) != 0)
147     {
148       (*info->fprintf_func) (info->stream, "r%ld", value);
149       if (M_SI (insn, operand) || M_LI (insn, operand))
150         {
151           (*info->fprintf_func) (info->stream, ":m");
152         }
153     }
154   else if ((operand->flags & TIC80_OPERAND_FPA) != 0)
155     {
156       (*info->fprintf_func) (info->stream, "a%ld", value);
157     }
158   else if ((operand->flags & TIC80_OPERAND_PCREL) != 0)
159     {
160       (*info->print_address_func) (memaddr + 4 * value, info);
161     }
162   else if ((operand->flags & TIC80_OPERAND_BASEREL) != 0)
163     {
164       (*info->print_address_func) (value, info);
165     }
166   else if ((operand->flags & TIC80_OPERAND_BITNUM) != 0)
167     {
168       print_operand_bitnum (info, value);
169     }
170   else if ((operand->flags & TIC80_OPERAND_CC) != 0)
171     {
172       print_operand_condition_code (info, value);
173     }
174   else if ((operand->flags & TIC80_OPERAND_CR) != 0)
175     {
176       print_operand_control_register (info, value);
177     }
178   else if ((operand->flags & TIC80_OPERAND_FLOAT) != 0)
179     {
180       print_operand_float (info, value);
181     }
182   else if ((operand->flags & TIC80_OPERAND_BITFIELD))
183     {
184       (*info->fprintf_func) (info->stream, "%#lx", value);
185     }
186   else
187     {
188       print_operand_integer (info, value);
189     }
190
191   /* If this is a scaled operand, then print the modifier.  */
192
193   if (R_SCALED (insn, operand))
194     {
195       (*info->fprintf_func) (info->stream, ":s");
196     }
197 }
198 \f
199 /* We have chosen an opcode table entry.  */
200
201 static int
202 print_one_instruction (info, memaddr, insn, opcode)
203      struct disassemble_info *info;
204      bfd_vma memaddr;
205      unsigned long insn;
206      const struct tic80_opcode *opcode;
207 {
208   const struct tic80_operand *operand;
209   long value;
210   int status;
211   const unsigned char *opindex;
212   int close_paren;
213
214   (*info->fprintf_func) (info->stream, "%-10s", opcode->name);
215
216   for (opindex = opcode->operands; *opindex != 0; opindex++)
217     {
218       operand = tic80_operands + *opindex;
219
220       /* Extract the value from the instruction.  */
221       if (operand->extract)
222         {
223           value = (*operand->extract) (insn, (int *) NULL);
224         }
225       else if (operand->bits == 32)
226         {
227           status = fill_instruction (info, memaddr, (unsigned long *) &value);
228           if (status == -1)
229             {
230               return (status);
231             }
232         }
233       else
234         {
235           value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
236           if ((operand->flags & TIC80_OPERAND_SIGNED) != 0
237               && (value & (1 << (operand->bits - 1))) != 0)
238             {
239               value -= 1 << operand->bits;
240             }
241         }
242
243       /* If this operand is enclosed in parenthesis, then print
244          the open paren, otherwise just print the regular comma
245          separator, except for the first operand.  */
246
247       if ((operand->flags & TIC80_OPERAND_PARENS) == 0)
248         {
249           close_paren = 0;
250           if (opindex != opcode->operands)
251             {
252               (*info->fprintf_func) (info->stream, ",");
253             }
254         }
255       else
256         {
257           close_paren = 1;
258           (*info->fprintf_func) (info->stream, "(");
259         }
260
261       print_operand (info, value, insn, operand, memaddr);
262
263       /* If we printed an open paren before printing this operand, close
264          it now. The flag gets reset on each loop.  */
265
266       if (close_paren)
267         {
268           (*info->fprintf_func) (info->stream, ")");
269         }
270     }
271   return (length);
272 }
273 \f
274 /* There are no specific bits that tell us for certain whether a vector
275    instruction opcode contains one or two instructions.  However since
276    a destination register of r0 is illegal, we can check for nonzero
277    values in both destination register fields.  Only opcodes that have
278    two valid instructions will have non-zero in both.  */
279
280 #define TWO_INSN(insn) ((((insn) & (0x1F << 27)) != 0) && (((insn) & (0x1F << 22)) != 0))
281
282 static int
283 print_instruction (info, memaddr, insn, vec_opcode)
284      struct disassemble_info *info;
285      bfd_vma memaddr;
286      unsigned long insn;
287      const struct tic80_opcode *vec_opcode;
288 {
289   const struct tic80_opcode *opcode;
290   const struct tic80_opcode *opcode_end;
291
292   /* Find the first opcode match in the opcodes table.  For vector
293      opcodes (vec_opcode != NULL) find the first match that is not the
294      previously found match.  FIXME: there should be faster ways to
295      search (hash table or binary search), but don't worry too much
296      about it until other TIc80 support is finished.  */
297
298   opcode_end = tic80_opcodes + tic80_num_opcodes;
299   for (opcode = tic80_opcodes; opcode < opcode_end; opcode++)
300     {
301       if ((insn & opcode->mask) == opcode->opcode &&
302           opcode != vec_opcode)
303         {
304           break;
305         }
306     }
307
308   if (opcode == opcode_end)
309     {
310       /* No match found, just print the bits as a .word directive.  */
311       (*info->fprintf_func) (info->stream, ".word %#08lx", insn);
312     }
313   else
314     {
315       /* Match found, decode the instruction.  */
316       length = print_one_instruction (info, memaddr, insn, opcode);
317       if (opcode->flags & TIC80_VECTOR && vec_opcode == NULL && TWO_INSN (insn))
318         {
319           /* There is another instruction to print from the same opcode.
320              Print the separator and then find and print the other
321              instruction.  */
322           (*info->fprintf_func) (info->stream, "   ||   ");
323           length = print_instruction (info, memaddr, insn, opcode);
324         }
325     }
326   return (length);
327 }
328
329 /* Get the next 32 bit word from the instruction stream and convert it
330    into internal format in the unsigned long INSN, for which we are
331    passed the address.  Return 0 on success, -1 on error.  */
332
333 static int
334 fill_instruction (info, memaddr, insnp)
335      struct disassemble_info *info;
336      bfd_vma memaddr;
337      unsigned long *insnp;
338 {
339   bfd_byte buffer[4];
340   int status;
341
342   /* Get the bits for the next 32 bit word and put in buffer.  */
343
344   status = (*info->read_memory_func) (memaddr + length, buffer, 4, info);
345   if (status != 0)
346     {
347       (*info->memory_error_func) (status, memaddr, info);
348       return (-1);
349     }
350
351   /* Read was successful, so increment count of bytes read and convert
352      the bits into internal format.  */
353
354   length += 4;
355   if (info->endian == BFD_ENDIAN_LITTLE)
356     {
357       *insnp = bfd_getl32 (buffer);
358     }
359   else if (info->endian == BFD_ENDIAN_BIG)
360     {
361       *insnp = bfd_getb32 (buffer);
362     }
363   else
364     {
365       /* FIXME: Should probably just default to one or the other.  */
366       abort ();
367     }
368   return (0);
369 }
370 \f
371 int
372 print_insn_tic80 (memaddr, info)
373      bfd_vma memaddr;
374      struct disassemble_info *info;
375 {
376   unsigned long insn;
377   int status;
378
379   length = 0;
380   info->bytes_per_line = 8;
381   status = fill_instruction (info, memaddr, &insn);
382   if (status != -1)
383     {
384       status = print_instruction (info, memaddr, insn, NULL);
385     }
386   return (status);
387 }