* tic80-dis.c (print_insn_tic80): Broke excessively long
[deliverable/binutils-gdb.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 }
This page took 0.082216 seconds and 5 git commands to generate.