Mon Jan 20 12:48:57 1997 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
[deliverable/binutils-gdb.git] / opcodes / tic80-dis.c
CommitLineData
6357e7f6 1/* Print TI TMS320C80 (MVP) instructions
8fdffbc4 2 Copyright 1996, 1997 Free Software Foundation, Inc.
6357e7f6
FF
3
4This file is free software; you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation; either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
a79d0193
FF
17
18#include <stdio.h>
19
20#include "ansidecl.h"
21#include "opcode/tic80.h"
22#include "dis-asm.h"
23
8fdffbc4 24static int length;
937fe722 25
8fdffbc4
FF
26static void print_operand_bitnum PARAMS ((struct disassemble_info *, long));
27static void print_operand_condition_code PARAMS ((struct disassemble_info *, long));
28static void print_operand_control_register PARAMS ((struct disassemble_info *, long));
29static void print_operand_float PARAMS ((struct disassemble_info *, long));
30static void print_operand_integer PARAMS ((struct disassemble_info *, long));
31static void print_operand PARAMS ((struct disassemble_info *, long, unsigned long,
32 const struct tic80_operand *, bfd_vma));
33static int print_one_instruction PARAMS ((struct disassemble_info *, bfd_vma,
34 unsigned long, const struct tic80_opcode *));
35static int print_instruction PARAMS ((struct disassemble_info *, bfd_vma, unsigned long,
36 const struct tic80_opcode *));
37static 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
47static void
48print_operand_integer (info, value)
a79d0193 49 struct disassemble_info *info;
8fdffbc4 50 long value;
a79d0193 51{
8fdffbc4
FF
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}
872dc6f0 61
8fdffbc4
FF
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
67static void
68print_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
79static void
80print_operand_control_register (info, value)
81 struct disassemble_info *info;
82 long value;
83{
84 char *tmp;
85
86 switch (value)
872dc6f0 87 {
8fdffbc4
FF
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;
872dc6f0 149 }
8fdffbc4
FF
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}
872dc6f0 159
8fdffbc4
FF
160\f
161static void
162print_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])))
872dc6f0 173 {
8fdffbc4
FF
174 /* Found a value within range */
175 (*info -> fprintf_func) (info -> stream, "%s", syms[value]);
872dc6f0 176 }
8fdffbc4
FF
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
185static void
186print_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])))
872dc6f0 201 {
8fdffbc4
FF
202 /* Found a value within range */
203 (*info -> fprintf_func) (info -> stream, "%s", syms[bitnum]);
872dc6f0
FF
204 }
205 else
206 {
8fdffbc4
FF
207 /* Not in range, just print as bit number */
208 (*info -> fprintf_func) (info -> stream, "%ld", bitnum);
872dc6f0 209 }
8fdffbc4 210}
872dc6f0 211
8fdffbc4
FF
212\f
213/* Print the operand as directed by the flags. */
872dc6f0 214
8fdffbc4
FF
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
219static void
220print_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)
872dc6f0 228 {
8fdffbc4
FF
229 (*info -> fprintf_func) (info -> stream, "r%ld", value);
230 if (M_SI (insn, operand) || M_LI (insn, operand))
872dc6f0 231 {
8fdffbc4 232 (*info -> fprintf_func) (info -> stream, ":m");
872dc6f0
FF
233 }
234 }
8fdffbc4 235 else if ((operand -> flags & TIC80_OPERAND_FPA) != 0)
872dc6f0 236 {
8fdffbc4
FF
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);
872dc6f0
FF
266 }
267 else
268 {
8fdffbc4
FF
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
283static int
284print_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);
872dc6f0 298
8fdffbc4
FF
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)
872dc6f0 305 {
8fdffbc4 306 value = (*operand -> extract) (insn, (int *) NULL);
872dc6f0 307 }
8fdffbc4 308 else if (operand -> bits == 32)
872dc6f0 309 {
8fdffbc4
FF
310 status = fill_instruction (info, memaddr, (unsigned long *) &value);
311 if (status == -1)
872dc6f0 312 {
8fdffbc4 313 return (status);
872dc6f0 314 }
8fdffbc4
FF
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)
872dc6f0 321 {
8fdffbc4 322 value -= 1 << operand -> bits;
872dc6f0 323 }
8fdffbc4 324 }
872dc6f0 325
8fdffbc4
FF
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. */
937fe722 329
8fdffbc4
FF
330 if ((operand -> flags & TIC80_OPERAND_PARENS) == 0)
331 {
332 close_paren = 0;
333 if (opindex != opcode -> operands)
937fe722 334 {
8fdffbc4 335 (*info -> fprintf_func) (info -> stream, ",");
872dc6f0 336 }
8fdffbc4
FF
337 }
338 else
339 {
340 close_paren = 1;
341 (*info -> fprintf_func) (info -> stream, "(");
342 }
872dc6f0 343
8fdffbc4 344 print_operand (info, value, insn, operand, memaddr);
937fe722 345
8fdffbc4
FF
346 /* If we printed an open paren before printing this operand, close
347 it now. The flag gets reset on each loop. */
003df617 348
8fdffbc4
FF
349 if (close_paren)
350 {
351 (*info -> fprintf_func) (info -> stream, ")");
352 }
353 }
354 return (length);
355}
872dc6f0 356
8fdffbc4 357\f
50965d0e 358
8fdffbc4
FF
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 */
50965d0e 364
8fdffbc4 365#define TWO_INSN(insn) ((((insn) & (0x1F << 27)) != 0) && (((insn) & (0x1F << 22)) != 0))
872dc6f0 366
8fdffbc4
FF
367static int
368print_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;
872dc6f0
FF
390 }
391 }
392
8fdffbc4
FF
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 }
872dc6f0 411 return (length);
a79d0193 412}
8fdffbc4
FF
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
418static int
419fill_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
457int
458print_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.053058 seconds and 4 git commands to generate.