* tic80-dis.c (print_insn_tic80): Broke excessively long
[external/binutils.git] / opcodes / tic80-dis.c
1 /* Print TI TMS320C80 (MVP) instructions
2    Copyright 1996, 1997 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 "ansidecl.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   char *tmp;
85
86   switch (value)
87     {
88     case 0:             tmp = "EPC";            break;
89     case 1:             tmp = "EIP";            break;
90     case 2:             tmp = "CONFIG";         break;
91     case 4:             tmp = "INTPEN";         break;
92     case 6:             tmp = "IE";             break;
93     case 8:             tmp = "FPST";           break;
94     case 0xA:           tmp = "PPERROR";        break;
95     case 0xD:           tmp = "PKTREQ";         break;
96     case 0xE:           tmp = "TCOUNT";         break;
97     case 0xF:           tmp = "TSCALE";         break;
98     case 0x10:          tmp = "FLTOP";          break;
99     case 0x11:          tmp = "FLTADR";         break;
100     case 0x12:          tmp = "FLTTAG";         break;
101     case 0x13:          tmp = "FLTDTL";         break;
102     case 0x14:          tmp = "FLTDTH";         break;
103     case 0x20:          tmp = "SYSSTK";         break;
104     case 0x21:          tmp = "SYSTMP";         break;
105     case 0x30:          tmp = "MPC";            break;
106     case 0x31:          tmp = "MIP";            break;
107     case 0x33:          tmp = "ECOMCNTL";       break;
108     case 0x34:          tmp = "ANASTAT";        break;
109     case 0x39:          tmp = "BRK1";           break;
110     case 0x3A:          tmp = "BRK2";           break;
111     case 0x200:         tmp = "ITAG0";          break;
112     case 0x201:         tmp = "ITAG1";          break;
113     case 0x202:         tmp = "ITAG2";          break;
114     case 0x203:         tmp = "ITAG3";          break;
115     case 0x204:         tmp = "ITAG4";          break;
116     case 0x205:         tmp = "ITAG5";          break;
117     case 0x206:         tmp = "ITAG6";          break;
118     case 0x207:         tmp = "ITAG7";          break;
119     case 0x208:         tmp = "ITAG8";          break;
120     case 0x209:         tmp = "ITAG9";          break;
121     case 0x20A:         tmp = "ITAG10";         break;
122     case 0x20B:         tmp = "ITAG11";         break;
123     case 0x20C:         tmp = "ITAG12";         break;
124     case 0x20D:         tmp = "ITAG13";         break;
125     case 0x20E:         tmp = "ITAG14";         break;
126     case 0x20F:         tmp = "ITAG15";         break;
127     case 0x300:         tmp = "ILRU";           break;
128     case 0x400:         tmp = "DTAG0";          break;
129     case 0x401:         tmp = "DTAG1";          break;
130     case 0x402:         tmp = "DTAG2";          break;
131     case 0x403:         tmp = "DTAG3";          break;
132     case 0x404:         tmp = "DTAG4";          break;
133     case 0x405:         tmp = "DTAG5";          break;
134     case 0x406:         tmp = "DTAG6";          break;
135     case 0x407:         tmp = "DTAG7";          break;
136     case 0x408:         tmp = "DTAG8";          break;
137     case 0x409:         tmp = "DTAG9";          break;
138     case 0x40A:         tmp = "DTAG10";         break;
139     case 0x40B:         tmp = "DTAG11";         break;
140     case 0x40C:         tmp = "DTAG12";         break;
141     case 0x40D:         tmp = "DTAG13";         break;
142     case 0x40E:         tmp = "DTAG14";         break;
143     case 0x40F:         tmp = "DTAG15";         break;
144     case 0x500:         tmp = "DLRU";           break;
145     case 0x4000:        tmp = "IN0P";           break;
146     case 0x4001:        tmp = "IN1P";           break;
147     case 0x4002:        tmp = "OUTP";           break;
148     default:            tmp = NULL;             break;
149     }
150   if (tmp != NULL)
151     {
152       (*info -> fprintf_func) (info -> stream, "%s", tmp);
153     }
154   else
155     {
156       (*info -> fprintf_func) (info -> stream, "%#lx", value);
157     }
158 }
159
160 \f
161 static void
162 print_operand_condition_code (info, value)
163      struct disassemble_info *info;
164      long value;
165 {
166   const char *syms[] = {
167     "nev.b", "gt0.b", "eq0.b", "ge0.b", "lt0.b", "ne0.b", "le0.b", "alw.b",
168     "nev.h", "gt0.h", "eq0.h", "ge0.h", "lt0.h", "ne0.h", "le0.h", "alw.h",
169     "nev.w", "gt0.w", "eq0.w", "ge0.w", "lt0.w", "ne0.w", "le0.w", "alw.w"
170   };
171
172   if (value < (sizeof (syms) / sizeof (syms[0])))
173     {
174       /* Found a value within range */
175       (*info -> fprintf_func) (info -> stream, "%s", syms[value]);
176     }
177   else
178     {
179       /* Not in range, just print as decimal digit. */
180       (*info -> fprintf_func) (info -> stream, "%ld", value);
181     }
182 }
183
184 \f
185 static void
186 print_operand_bitnum (info, value)
187      struct disassemble_info *info;
188      long value;
189 {
190   int bitnum;
191   const char *syms[] = {
192     "eq.b", "ne.b", "gt.b", "le.b", "lt.b", "ge.b",
193     "hi.b", "ls.b", "lo.b", "hs.b", "eq.h", "ne.h",
194     "gt.h", "le.h", "lt.h", "ge.h", "hi.h", "ls.h",
195     "lo.h", "hs.h", "eq.w", "ne.w", "gt.w", "le.w",
196     "lt.w", "ge.w", "hi.w", "ls.w", "lo.w", "hs.w"
197   };
198
199   bitnum = ~value & 0x1F;
200   if (bitnum < (sizeof (syms) / sizeof (syms[0])))
201     {
202       /* Found a value within range */
203       (*info -> fprintf_func) (info -> stream, "%s", syms[bitnum]);
204     }
205   else
206     {
207       /* Not in range, just print as bit number */
208       (*info -> fprintf_func) (info -> stream, "%ld", bitnum);
209     }
210 }
211
212 \f
213 /* Print the operand as directed by the flags.  */
214
215 #define M_SI(insn,op) ((((op) -> flags & TIC80_OPERAND_M_SI) != 0) && ((insn) & (1 << 17)))
216 #define M_LI(insn,op) ((((op) -> flags & TIC80_OPERAND_M_LI) != 0) && ((insn) & (1 << 15)))
217 #define R_SCALED(insn,op) ((((op) -> flags & TIC80_OPERAND_SCALED) != 0) && ((insn) & (1 << 11)))
218
219 static void
220 print_operand (info, value, insn, operand, memaddr)
221      struct disassemble_info *info;
222      long value;
223      unsigned long insn;
224      const struct tic80_operand *operand;
225      bfd_vma memaddr;
226 {
227   if ((operand -> flags & TIC80_OPERAND_GPR) != 0)
228     {
229       (*info -> fprintf_func) (info -> stream, "r%ld", value);
230       if (M_SI (insn, operand) || M_LI (insn, operand))
231         {
232           (*info -> fprintf_func) (info -> stream, ":m");
233         }
234     }
235   else if ((operand -> flags & TIC80_OPERAND_FPA) != 0)
236     {
237       (*info -> fprintf_func) (info -> stream, "a%ld", value);
238     }
239   else if ((operand -> flags & TIC80_OPERAND_PCREL) != 0)
240     {
241       (*info -> print_address_func) (memaddr + 4 * value, info);
242     }
243   else if ((operand -> flags & TIC80_OPERAND_BASEREL) != 0)
244     {
245       (*info -> print_address_func) (value, info);
246     }
247   else if ((operand -> flags & TIC80_OPERAND_BITNUM) != 0)
248     {
249       print_operand_bitnum (info, value);
250     }
251   else if ((operand -> flags & TIC80_OPERAND_CC) != 0)
252     {
253       print_operand_condition_code (info, value);
254     }
255   else if ((operand -> flags & TIC80_OPERAND_CR) != 0)
256     {
257       print_operand_control_register (info, value);
258     }
259   else if ((operand -> flags & TIC80_OPERAND_FLOAT) != 0)
260     {
261       print_operand_float (info, value);
262     }
263   else if ((operand -> flags & TIC80_OPERAND_BITFIELD))
264     {
265       (*info -> fprintf_func) (info -> stream, "%#lx", value);
266     }
267   else
268     {
269       print_operand_integer (info, value);
270     }
271
272   /* If this is a scaled operand, then print the modifier */
273
274   if (R_SCALED (insn, operand))
275     {
276       (*info -> fprintf_func) (info -> stream, ":s");
277     }
278 }
279
280 \f
281 /* We have chosen an opcode table entry */
282
283 static int
284 print_one_instruction (info, memaddr, insn, opcode)
285      struct disassemble_info *info;
286      bfd_vma memaddr;
287      unsigned long insn;
288      const struct tic80_opcode *opcode;
289 {
290   const struct tic80_operand *operand;
291   long value;
292   int status;
293   const unsigned char *opindex;
294   bfd_byte buffer[4];
295   int close_paren;
296
297   (*info -> fprintf_func) (info -> stream, "%-10s", opcode -> name);
298
299   for (opindex = opcode -> operands; *opindex != 0; opindex++)
300     {
301       operand = tic80_operands + *opindex;
302
303       /* Extract the value from the instruction.  */
304       if (operand -> extract)
305         {
306           value = (*operand -> extract) (insn, (int *) NULL);
307         }
308       else if (operand -> bits == 32)
309         {
310           status = fill_instruction (info, memaddr, (unsigned long *) &value);
311           if (status == -1)
312             {
313               return (status);
314             }
315         }
316       else
317         {
318           value = (insn >> operand -> shift) & ((1 << operand -> bits) - 1);
319           if ((operand -> flags & TIC80_OPERAND_SIGNED) != 0
320               && (value & (1 << (operand -> bits - 1))) != 0)
321             {
322               value -= 1 << operand -> bits;
323             }
324         }
325
326       /* If this operand is enclosed in parenthesis, then print
327          the open paren, otherwise just print the regular comma
328          separator, except for the first operand. */
329
330       if ((operand -> flags & TIC80_OPERAND_PARENS) == 0)
331         {
332           close_paren = 0;
333           if (opindex != opcode -> operands)
334             {
335               (*info -> fprintf_func) (info -> stream, ",");
336             }
337         }
338       else
339         {
340           close_paren = 1;
341           (*info -> fprintf_func) (info -> stream, "(");
342         }
343
344       print_operand (info, value, insn, operand, memaddr);
345
346       /* If we printed an open paren before printing this operand, close
347          it now. The flag gets reset on each loop. */
348
349       if (close_paren)
350         {
351           (*info -> fprintf_func) (info -> stream, ")");
352         }
353     }
354   return (length);
355 }
356
357 \f
358
359 /* There are no specific bits that tell us for certain whether a vector
360    instruction opcode contains one or two instructions.  However since
361    a destination register of r0 is illegal, we can check for nonzero
362    values in both destination register fields.  Only opcodes that have
363    two valid instructions will have non-zero in both */
364
365 #define TWO_INSN(insn) ((((insn) & (0x1F << 27)) != 0) && (((insn) & (0x1F << 22)) != 0))
366
367 static int
368 print_instruction (info, memaddr, insn, vec_opcode)
369      struct disassemble_info *info;
370      bfd_vma memaddr;
371      unsigned long insn;
372      const struct tic80_opcode *vec_opcode;
373 {
374   const struct tic80_opcode *opcode;
375   const struct tic80_opcode *opcode_end;
376
377   /* Find the first opcode match in the opcodes table.  For vector
378      opcodes (vec_opcode != NULL) find the first match that is not the
379      previously found match.  FIXME: there should be faster ways to
380      search (hash table or binary search), but don't worry too much
381      about it until other TIc80 support is finished. */
382
383   opcode_end = tic80_opcodes + tic80_num_opcodes;
384   for (opcode = tic80_opcodes; opcode < opcode_end; opcode++)
385     {
386       if ((insn & opcode -> mask) == opcode -> opcode &&
387           opcode != vec_opcode)
388         {
389           break;
390         }
391     }
392
393   if (opcode == opcode_end)
394     {
395       /* No match found, just print the bits as a .word directive */
396       (*info -> fprintf_func) (info -> stream, ".word %#08lx", insn);
397     }
398   else
399     {
400       /* Match found, decode the instruction.  */
401       length = print_one_instruction (info, memaddr, insn, opcode);
402       if (opcode -> flags & TIC80_VECTOR && vec_opcode == NULL && TWO_INSN (insn))
403         {
404           /* There is another instruction to print from the same opcode.
405              Print the separator and then find and print the other
406              instruction. */
407           (*info -> fprintf_func) (info -> stream, "   ||   ");
408           length = print_instruction (info, memaddr, insn, opcode);
409         }
410     }
411   return (length);
412 }
413
414 /* Get the next 32 bit word from the instruction stream and convert it
415    into internal format in the unsigned long INSN, for which we are
416    passed the address.  Return 0 on success, -1 on error. */
417
418 static int
419 fill_instruction (info, memaddr, insnp)
420      struct disassemble_info *info;
421      bfd_vma memaddr;
422      unsigned long *insnp;
423 {
424   bfd_byte buffer[4];
425   int status;
426
427   /* Get the bits for the next 32 bit word and put in buffer */
428
429   status = (*info -> read_memory_func) (memaddr + length, buffer, 4, info);
430   if (status != 0)
431     {
432       (*info -> memory_error_func) (status, memaddr, info);
433       return (-1);
434     }
435
436   /* Read was successful, so increment count of bytes read and convert
437      the bits into internal format. */
438      
439   length += 4;
440   if (info -> endian == BFD_ENDIAN_LITTLE)
441     {
442       *insnp = bfd_getl32 (buffer);
443     }
444   else if (info -> endian == BFD_ENDIAN_BIG)
445     {
446       *insnp = bfd_getb32 (buffer);
447     }
448   else
449     {
450       /* FIXME: Should probably just default to one or the other */
451       abort ();
452     }
453   return (0);
454 }
455
456 \f
457 int 
458 print_insn_tic80 (memaddr, info)
459      bfd_vma memaddr;
460      struct disassemble_info *info;
461 {
462   unsigned long insn;
463   int status;
464
465   length = 0;
466   status = fill_instruction (info, memaddr, &insn);
467   if (status != -1)
468     {
469       status = print_instruction (info, memaddr, insn, NULL);
470     }
471   return (status);
472 }