* tic80-dis.c (print_insn_tic80): Print TIC80_OPERAND_RELATIVE
[external/binutils.git] / opcodes / tic80-dis.c
1 /* Print TI TMS320C80 (MVP) instructions
2    Copyright 1996 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 int 
25 print_insn_tic80 (memaddr, info)
26      bfd_vma memaddr;
27      struct disassemble_info *info;
28 {
29   bfd_byte buffer[4];
30   int status;
31   unsigned long insn[2];
32   const struct tic80_opcode *opcode;
33   const struct tic80_opcode *opcode_end;
34   const unsigned char *opindex;
35   const struct tic80_operand *operand;
36   int need_comma;
37   int need_paren;
38   int length = 4;
39
40   status = (*info->read_memory_func) (memaddr, buffer, 4, info);
41   if (status != 0)
42     {
43       (*info->memory_error_func) (status, memaddr, info);
44       return -1;
45     }
46
47   if (info -> endian == BFD_ENDIAN_LITTLE)
48     {
49       insn[0] = bfd_getl32 (buffer);
50     }
51   else if (info -> endian == BFD_ENDIAN_BIG)
52     {
53       insn[0] = bfd_getb32 (buffer);
54     }
55   else
56     {
57       /* FIXME: Should probably just default to one or the other */
58       abort ();
59     }
60
61   /* Find the first opcode match in the opcodes table.  FIXME: there should
62      be faster ways to find one (hash table or binary search), but don't
63      worry too much about it until other TIc80 support is finished. */
64
65   opcode_end = tic80_opcodes + tic80_num_opcodes;
66   for (opcode = tic80_opcodes; opcode < opcode_end; opcode++)
67     {
68       if ((insn[0] & opcode -> mask) == opcode -> opcode)
69         {
70           break;
71         }
72     }
73
74   if (opcode == opcode_end)
75     {
76       /* No match found, just print the bits as a .word directive */
77       (*info -> fprintf_func) (info -> stream, ".word %#08lx", insn[0]);
78     }
79   else
80     {
81       /* Match found, decode the instruction.  */
82       (*info -> fprintf_func) (info -> stream, "%s", opcode -> name);
83
84       /* Now extract and print the operands. */
85       need_comma = 0;
86       need_paren = 0;
87       if (opcode -> operands[0] != 0)
88         {
89           (*info -> fprintf_func) (info -> stream, "\t");
90         }
91       for (opindex = opcode -> operands; *opindex != 0; opindex++)
92         {
93           long value;
94
95           operand = tic80_operands + *opindex;
96
97           /* Extract the value from the instruction.  */
98           if (operand -> extract)
99             {
100               value = (*operand -> extract) (insn[0], (int *) NULL);
101             }
102           else if (operand -> bits == 32)
103             {
104               status = (*info->read_memory_func) (memaddr + 4, buffer, 4, info);
105               if (status != 0)
106                 {
107                   (*info->memory_error_func) (status, memaddr, info);
108                   return -1;
109                 }
110
111               if (info -> endian == BFD_ENDIAN_LITTLE)
112                 {
113                   insn[1] = bfd_getl32 (buffer);
114                 }
115               else if (info -> endian == BFD_ENDIAN_BIG)
116                 {
117                   insn[1] = bfd_getb32 (buffer);
118                 }
119               value = (long) insn[1];
120               length += 4;
121             }
122           else
123             {
124               value = (insn[0] >> operand -> shift) & ((1 << operand -> bits) - 1);
125               if ((operand -> flags & TIC80_OPERAND_SIGNED) != 0
126                   && (value & (1 << (operand -> bits - 1))) != 0)
127                 value -= 1 << operand -> bits;
128             }
129
130           if (need_comma)
131             {
132               (*info -> fprintf_func) (info -> stream, ",");
133               need_comma = 0;
134             }
135
136           /* Print the operand as directed by the flags.  */
137           if ((operand -> flags & TIC80_OPERAND_GPR) != 0)
138             {
139               (*info -> fprintf_func) (info -> stream, "r%ld", value);
140             }
141           else if ((operand -> flags & TIC80_OPERAND_FPA) != 0)
142             {
143               (*info -> fprintf_func) (info -> stream, "a%ld", value);
144             }
145           else if ((operand -> flags & TIC80_OPERAND_RELATIVE) != 0)
146             {
147               (*info -> print_address_func) (memaddr + 4 * value, info);
148             }
149           else if ((operand -> flags & TIC80_OPERAND_BITNUM) != 0)
150             {
151               char *syms[30] = {
152                 "eq.b", "ne.b", "gt.b", "le.b", "lt.b", "ge.b",
153                 "hi.b", "ls.b", "lo.b", "hs.b", "eq.h", "ne.h",
154                 "gt.h", "le.h", "lt.h", "ge.h", "hi.h", "ls.h",
155                 "lo.h", "hs.h", "eq.w", "ne.w", "gt.w", "le.w",
156                 "lt.w", "ge.w", "hi.w", "ls.w", "lo.w", "hs.w"
157               };
158               int bitnum = ~value & 0x1F;
159
160               if (bitnum < 30)
161                 {
162                   /* Found a value within range */
163                   (*info -> fprintf_func) (info -> stream, "%s", syms[bitnum]);
164                 }
165               else
166                 {
167                   /* Not in range, just print as bit number */
168                   (*info -> fprintf_func) (info -> stream, "%ld", bitnum);
169                 }
170             }
171           else if ((operand -> flags & TIC80_OPERAND_CC) != 0)
172             {
173               char *syms[24] = {
174                 "nev.b", "gt0.b", "eq0.b", "ge0.b", "lt0.b", "ne0.b", "le0.b", "alw.b",
175                 "nev.h", "gt0.h", "eq0.h", "ge0.h", "lt0.h", "ne0.h", "le0.h", "alw.h",
176                 "nev.w", "gt0.w", "eq0.w", "ge0.w", "lt0.w", "ne0.w", "le0.w", "alw.w"
177               };
178               if (value < 24)
179                 {
180                   /* Found a value within range */
181                   (*info -> fprintf_func) (info -> stream, "%s", syms[value]);
182                 }
183               else
184                 {
185                   /* Not in range, just print as decimal digit. */
186                   (*info -> fprintf_func) (info -> stream, "%ld", value);
187                 }
188             }
189           else if ((operand -> flags & TIC80_OPERAND_CR) != 0)
190             {
191               char *tmp;
192               switch (value)
193                 {
194                 case 0:         tmp = "EPC";            break;
195                 case 1:         tmp = "EIP";            break;
196                 case 2:         tmp = "CONFIG";         break;
197                 case 4:         tmp = "INTPEN";         break;
198                 case 6:         tmp = "IE";             break;
199                 case 8:         tmp = "FPST";           break;
200                 case 0xA:       tmp = "PPERROR";        break;
201                 case 0xD:       tmp = "PKTREQ";         break;
202                 case 0xE:       tmp = "TCOUNT";         break;
203                 case 0xF:       tmp = "TSCALE";         break;
204                 case 0x10:      tmp = "FLTOP";          break;
205                 case 0x11:      tmp = "FLTADR";         break;
206                 case 0x12:      tmp = "FLTTAG";         break;
207                 case 0x13:      tmp = "FLTDTL";         break;
208                 case 0x14:      tmp = "FLTDTH";         break;
209                 case 0x20:      tmp = "SYSSTK";         break;
210                 case 0x21:      tmp = "SYSTMP";         break;
211                 case 0x30:      tmp = "MPC";            break;
212                 case 0x31:      tmp = "MIP";            break;
213                 case 0x33:      tmp = "ECOMCNTL";       break;
214                 case 0x34:      tmp = "ANASTAT";        break;
215                 case 0x39:      tmp = "BRK1";           break;
216                 case 0x3A:      tmp = "BRK2";           break;
217                 case 0x200:     tmp = "ITAG0";          break;
218                 case 0x201:     tmp = "ITAG1";          break;
219                 case 0x202:     tmp = "ITAG2";          break;
220                 case 0x203:     tmp = "ITAG3";          break;
221                 case 0x204:     tmp = "ITAG4";          break;
222                 case 0x205:     tmp = "ITAG5";          break;
223                 case 0x206:     tmp = "ITAG6";          break;
224                 case 0x207:     tmp = "ITAG7";          break;
225                 case 0x208:     tmp = "ITAG8";          break;
226                 case 0x209:     tmp = "ITAG9";          break;
227                 case 0x20A:     tmp = "ITAG10";         break;
228                 case 0x20B:     tmp = "ITAG11";         break;
229                 case 0x20C:     tmp = "ITAG12";         break;
230                 case 0x20D:     tmp = "ITAG13";         break;
231                 case 0x20E:     tmp = "ITAG14";         break;
232                 case 0x20F:     tmp = "ITAG15";         break;
233                 case 0x300:     tmp = "ILRU";           break;
234                 case 0x400:     tmp = "DTAG0";          break;
235                 case 0x401:     tmp = "DTAG1";          break;
236                 case 0x402:     tmp = "DTAG2";          break;
237                 case 0x403:     tmp = "DTAG3";          break;
238                 case 0x404:     tmp = "DTAG4";          break;
239                 case 0x405:     tmp = "DTAG5";          break;
240                 case 0x406:     tmp = "DTAG6";          break;
241                 case 0x407:     tmp = "DTAG7";          break;
242                 case 0x408:     tmp = "DTAG8";          break;
243                 case 0x409:     tmp = "DTAG9";          break;
244                 case 0x40A:     tmp = "DTAG10";         break;
245                 case 0x40B:     tmp = "DTAG11";         break;
246                 case 0x40C:     tmp = "DTAG12";         break;
247                 case 0x40D:     tmp = "DTAG13";         break;
248                 case 0x40E:     tmp = "DTAG14";         break;
249                 case 0x40F:     tmp = "DTAG15";         break;
250                 case 0x500:     tmp = "DLRU";           break;
251                 case 0x4000:    tmp = "IN0P";           break;
252                 case 0x4001:    tmp = "IN1P";           break;
253                 case 0x4002:    tmp = "OUTP";           break;
254                 default:        tmp = NULL;             break;
255                 }
256               if (tmp != NULL)
257                 {
258                   (*info -> fprintf_func) (info -> stream, "%s", tmp);
259                 }
260               else
261                 {
262                   (*info -> fprintf_func) (info -> stream, "%#lx", value);
263                 }
264             }
265           else
266             {
267               if ((value > 999 || value < -999)
268                   || operand -> flags & TIC80_OPERAND_BITFIELD)
269                 {
270                   (*info -> fprintf_func) (info -> stream, "%#lx", value);
271                 }
272               else
273                 {
274                   (*info -> fprintf_func) (info -> stream, "%ld", value);
275                 }
276             }
277
278           if (need_paren)
279             {
280               (*info -> fprintf_func) (info -> stream, ")");
281               need_paren = 0;
282             }
283
284           if ((operand -> flags & TIC80_OPERAND_PARENS) == 0)
285             {
286               need_comma = 1;
287             }
288           else
289             {
290               (*info -> fprintf_func) (info -> stream, "(");
291               need_paren = 1;
292             }
293         }
294     }
295
296   return (length);
297 }