More portability patches. Include sysdep.h everywhere.
[external/binutils.git] / opcodes / tic80-dis.c
1 /* Print TI TMS320C80 (MVP) instructions
2    Copyright 1996, 1997, 1998, 1999 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
40 \f
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. */
46
47 static void
48 print_operand_integer (info, value)
49      struct disassemble_info *info;
50      long value;
51 {
52   if ((value > 9999 || value < -9999))
53     {
54       (*info -> fprintf_func) (info -> stream, "%#lx", value);
55     }
56   else
57     {
58       (*info -> fprintf_func) (info -> stream, "%ld", value);
59     }
60 }
61
62 \f
63 /* FIXME: depends upon sizeof (long) == sizeof (float) and
64    also upon host floating point format matching target
65    floating point format. */
66
67 static void
68 print_operand_float (info, value)
69      struct disassemble_info *info;
70      long value;
71 {
72   union { float f; long l; } fval;
73
74   fval.l = value;
75   (*info -> fprintf_func) (info -> stream, "%g", fval.f);
76 }
77
78 \f
79 static void
80 print_operand_control_register (info, value)
81      struct disassemble_info *info;
82      long value;
83 {
84   const char *tmp;
85
86   tmp = tic80_value_to_symbol (value, TIC80_OPERAND_CR);
87   if (tmp != NULL)
88     {
89       (*info -> fprintf_func) (info -> stream, "%s", tmp);
90     }
91   else
92     {
93       (*info -> fprintf_func) (info -> stream, "%#lx", value);
94     }
95 }
96
97 \f
98 static void
99 print_operand_condition_code (info, value)
100      struct disassemble_info *info;
101      long value;
102 {
103   const char *tmp;
104
105   tmp = tic80_value_to_symbol (value, TIC80_OPERAND_CC);
106   if (tmp != NULL)
107     {
108       (*info -> fprintf_func) (info -> stream, "%s", tmp);
109     }
110   else
111     {
112       (*info -> fprintf_func) (info -> stream, "%ld", value);
113     }
114 }
115
116 \f
117 static void
118 print_operand_bitnum (info, value)
119      struct disassemble_info *info;
120      long value;
121 {
122   int bitnum;
123   const char *tmp;
124
125   bitnum = ~value & 0x1F;
126   tmp = tic80_value_to_symbol (bitnum, TIC80_OPERAND_BITNUM);
127   if (tmp != NULL)
128     {
129       (*info -> fprintf_func) (info -> stream, "%s", tmp);
130     }
131   else
132     {
133       (*info -> fprintf_func) (info -> stream, "%ld", bitnum);
134     }
135 }
136
137 \f
138 /* Print the operand as directed by the flags.  */
139
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)))
143
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;
151 {
152   if ((operand -> flags & TIC80_OPERAND_GPR) != 0)
153     {
154       (*info -> fprintf_func) (info -> stream, "r%ld", value);
155       if (M_SI (insn, operand) || M_LI (insn, operand))
156         {
157           (*info -> fprintf_func) (info -> stream, ":m");
158         }
159     }
160   else if ((operand -> flags & TIC80_OPERAND_FPA) != 0)
161     {
162       (*info -> fprintf_func) (info -> stream, "a%ld", value);
163     }
164   else if ((operand -> flags & TIC80_OPERAND_PCREL) != 0)
165     {
166       (*info -> print_address_func) (memaddr + 4 * value, info);
167     }
168   else if ((operand -> flags & TIC80_OPERAND_BASEREL) != 0)
169     {
170       (*info -> print_address_func) (value, info);
171     }
172   else if ((operand -> flags & TIC80_OPERAND_BITNUM) != 0)
173     {
174       print_operand_bitnum (info, value);
175     }
176   else if ((operand -> flags & TIC80_OPERAND_CC) != 0)
177     {
178       print_operand_condition_code (info, value);
179     }
180   else if ((operand -> flags & TIC80_OPERAND_CR) != 0)
181     {
182       print_operand_control_register (info, value);
183     }
184   else if ((operand -> flags & TIC80_OPERAND_FLOAT) != 0)
185     {
186       print_operand_float (info, value);
187     }
188   else if ((operand -> flags & TIC80_OPERAND_BITFIELD))
189     {
190       (*info -> fprintf_func) (info -> stream, "%#lx", value);
191     }
192   else
193     {
194       print_operand_integer (info, value);
195     }
196
197   /* If this is a scaled operand, then print the modifier */
198
199   if (R_SCALED (insn, operand))
200     {
201       (*info -> fprintf_func) (info -> stream, ":s");
202     }
203 }
204
205 \f
206 /* We have chosen an opcode table entry */
207
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;
214 {
215   const struct tic80_operand *operand;
216   long value;
217   int status;
218   const unsigned char *opindex;
219   int close_paren;
220
221   (*info -> fprintf_func) (info -> stream, "%-10s", opcode -> name);
222
223   for (opindex = opcode -> operands; *opindex != 0; opindex++)
224     {
225       operand = tic80_operands + *opindex;
226
227       /* Extract the value from the instruction.  */
228       if (operand -> extract)
229         {
230           value = (*operand -> extract) (insn, (int *) NULL);
231         }
232       else if (operand -> bits == 32)
233         {
234           status = fill_instruction (info, memaddr, (unsigned long *) &value);
235           if (status == -1)
236             {
237               return (status);
238             }
239         }
240       else
241         {
242           value = (insn >> operand -> shift) & ((1 << operand -> bits) - 1);
243           if ((operand -> flags & TIC80_OPERAND_SIGNED) != 0
244               && (value & (1 << (operand -> bits - 1))) != 0)
245             {
246               value -= 1 << operand -> bits;
247             }
248         }
249
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. */
253
254       if ((operand -> flags & TIC80_OPERAND_PARENS) == 0)
255         {
256           close_paren = 0;
257           if (opindex != opcode -> operands)
258             {
259               (*info -> fprintf_func) (info -> stream, ",");
260             }
261         }
262       else
263         {
264           close_paren = 1;
265           (*info -> fprintf_func) (info -> stream, "(");
266         }
267
268       print_operand (info, value, insn, operand, memaddr);
269
270       /* If we printed an open paren before printing this operand, close
271          it now. The flag gets reset on each loop. */
272
273       if (close_paren)
274         {
275           (*info -> fprintf_func) (info -> stream, ")");
276         }
277     }
278   return (length);
279 }
280
281 \f
282
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 */
288
289 #define TWO_INSN(insn) ((((insn) & (0x1F << 27)) != 0) && (((insn) & (0x1F << 22)) != 0))
290
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;
297 {
298   const struct tic80_opcode *opcode;
299   const struct tic80_opcode *opcode_end;
300
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. */
306
307   opcode_end = tic80_opcodes + tic80_num_opcodes;
308   for (opcode = tic80_opcodes; opcode < opcode_end; opcode++)
309     {
310       if ((insn & opcode -> mask) == opcode -> opcode &&
311           opcode != vec_opcode)
312         {
313           break;
314         }
315     }
316
317   if (opcode == opcode_end)
318     {
319       /* No match found, just print the bits as a .word directive */
320       (*info -> fprintf_func) (info -> stream, ".word %#08lx", insn);
321     }
322   else
323     {
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))
327         {
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);
333         }
334     }
335   return (length);
336 }
337
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. */
341
342 static int
343 fill_instruction (info, memaddr, insnp)
344      struct disassemble_info *info;
345      bfd_vma memaddr;
346      unsigned long *insnp;
347 {
348   bfd_byte buffer[4];
349   int status;
350
351   /* Get the bits for the next 32 bit word and put in buffer */
352
353   status = (*info -> read_memory_func) (memaddr + length, buffer, 4, info);
354   if (status != 0)
355     {
356       (*info -> memory_error_func) (status, memaddr, info);
357       return (-1);
358     }
359
360   /* Read was successful, so increment count of bytes read and convert
361      the bits into internal format. */
362      
363   length += 4;
364   if (info -> endian == BFD_ENDIAN_LITTLE)
365     {
366       *insnp = bfd_getl32 (buffer);
367     }
368   else if (info -> endian == BFD_ENDIAN_BIG)
369     {
370       *insnp = bfd_getb32 (buffer);
371     }
372   else
373     {
374       /* FIXME: Should probably just default to one or the other */
375       abort ();
376     }
377   return (0);
378 }
379
380 \f
381 int 
382 print_insn_tic80 (memaddr, info)
383      bfd_vma memaddr;
384      struct disassemble_info *info;
385 {
386   unsigned long insn;
387   int status;
388
389   length = 0;
390   info->bytes_per_line = 8;
391   status = fill_instruction (info, memaddr, &insn);
392   if (status != -1)
393     {
394       status = print_instruction (info, memaddr, insn, NULL);
395     }
396   return (status);
397 }