1 /* Print TI TMS320C80 (MVP) instructions
2 Copyright 1996, 1997 Free Software Foundation, Inc.
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.
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.
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. */
21 #include "opcode/tic80.h"
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
,
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. */
48 print_operand_integer (info
, value
)
49 struct disassemble_info
*info
;
52 if ((value
> 9999 || value
< -9999))
54 (*info
-> fprintf_func
) (info
-> stream
, "%#lx", value
);
58 (*info
-> fprintf_func
) (info
-> stream
, "%ld", value
);
63 /* FIXME: depends upon sizeof (long) == sizeof (float) and
64 also upon host floating point format matching target
65 floating point format. */
68 print_operand_float (info
, value
)
69 struct disassemble_info
*info
;
72 union { float f
; long l
; } fval
;
75 (*info
-> fprintf_func
) (info
-> stream
, "%g", fval
.f
);
80 print_operand_control_register (info
, value
)
81 struct disassemble_info
*info
;
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;
152 (*info
-> fprintf_func
) (info
-> stream
, "%s", tmp
);
156 (*info
-> fprintf_func
) (info
-> stream
, "%#lx", value
);
162 print_operand_condition_code (info
, value
)
163 struct disassemble_info
*info
;
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"
172 if (value
< (sizeof (syms
) / sizeof (syms
[0])))
174 /* Found a value within range */
175 (*info
-> fprintf_func
) (info
-> stream
, "%s", syms
[value
]);
179 /* Not in range, just print as decimal digit. */
180 (*info
-> fprintf_func
) (info
-> stream
, "%ld", value
);
186 print_operand_bitnum (info
, value
)
187 struct disassemble_info
*info
;
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"
199 bitnum
= ~value
& 0x1F;
200 if (bitnum
< (sizeof (syms
) / sizeof (syms
[0])))
202 /* Found a value within range */
203 (*info
-> fprintf_func
) (info
-> stream
, "%s", syms
[bitnum
]);
207 /* Not in range, just print as bit number */
208 (*info
-> fprintf_func
) (info
-> stream
, "%ld", bitnum
);
213 /* Print the operand as directed by the flags. */
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)))
220 print_operand (info
, value
, insn
, operand
, memaddr
)
221 struct disassemble_info
*info
;
224 const struct tic80_operand
*operand
;
227 if ((operand
-> flags
& TIC80_OPERAND_GPR
) != 0)
229 (*info
-> fprintf_func
) (info
-> stream
, "r%ld", value
);
230 if (M_SI (insn
, operand
) || M_LI (insn
, operand
))
232 (*info
-> fprintf_func
) (info
-> stream
, ":m");
235 else if ((operand
-> flags
& TIC80_OPERAND_FPA
) != 0)
237 (*info
-> fprintf_func
) (info
-> stream
, "a%ld", value
);
239 else if ((operand
-> flags
& TIC80_OPERAND_PCREL
) != 0)
241 (*info
-> print_address_func
) (memaddr
+ 4 * value
, info
);
243 else if ((operand
-> flags
& TIC80_OPERAND_BASEREL
) != 0)
245 (*info
-> print_address_func
) (value
, info
);
247 else if ((operand
-> flags
& TIC80_OPERAND_BITNUM
) != 0)
249 print_operand_bitnum (info
, value
);
251 else if ((operand
-> flags
& TIC80_OPERAND_CC
) != 0)
253 print_operand_condition_code (info
, value
);
255 else if ((operand
-> flags
& TIC80_OPERAND_CR
) != 0)
257 print_operand_control_register (info
, value
);
259 else if ((operand
-> flags
& TIC80_OPERAND_FLOAT
) != 0)
261 print_operand_float (info
, value
);
263 else if ((operand
-> flags
& TIC80_OPERAND_BITFIELD
))
265 (*info
-> fprintf_func
) (info
-> stream
, "%#lx", value
);
269 print_operand_integer (info
, value
);
272 /* If this is a scaled operand, then print the modifier */
274 if (R_SCALED (insn
, operand
))
276 (*info
-> fprintf_func
) (info
-> stream
, ":s");
281 /* We have chosen an opcode table entry */
284 print_one_instruction (info
, memaddr
, insn
, opcode
)
285 struct disassemble_info
*info
;
288 const struct tic80_opcode
*opcode
;
290 const struct tic80_operand
*operand
;
293 const unsigned char *opindex
;
297 (*info
-> fprintf_func
) (info
-> stream
, "%-10s", opcode
-> name
);
299 for (opindex
= opcode
-> operands
; *opindex
!= 0; opindex
++)
301 operand
= tic80_operands
+ *opindex
;
303 /* Extract the value from the instruction. */
304 if (operand
-> extract
)
306 value
= (*operand
-> extract
) (insn
, (int *) NULL
);
308 else if (operand
-> bits
== 32)
310 status
= fill_instruction (info
, memaddr
, (unsigned long *) &value
);
318 value
= (insn
>> operand
-> shift
) & ((1 << operand
-> bits
) - 1);
319 if ((operand
-> flags
& TIC80_OPERAND_SIGNED
) != 0
320 && (value
& (1 << (operand
-> bits
- 1))) != 0)
322 value
-= 1 << operand
-> bits
;
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. */
330 if ((operand
-> flags
& TIC80_OPERAND_PARENS
) == 0)
333 if (opindex
!= opcode
-> operands
)
335 (*info
-> fprintf_func
) (info
-> stream
, ",");
341 (*info
-> fprintf_func
) (info
-> stream
, "(");
344 print_operand (info
, value
, insn
, operand
, memaddr
);
346 /* If we printed an open paren before printing this operand, close
347 it now. The flag gets reset on each loop. */
351 (*info
-> fprintf_func
) (info
-> stream
, ")");
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 */
365 #define TWO_INSN(insn) ((((insn) & (0x1F << 27)) != 0) && (((insn) & (0x1F << 22)) != 0))
368 print_instruction (info
, memaddr
, insn
, vec_opcode
)
369 struct disassemble_info
*info
;
372 const struct tic80_opcode
*vec_opcode
;
374 const struct tic80_opcode
*opcode
;
375 const struct tic80_opcode
*opcode_end
;
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. */
383 opcode_end
= tic80_opcodes
+ tic80_num_opcodes
;
384 for (opcode
= tic80_opcodes
; opcode
< opcode_end
; opcode
++)
386 if ((insn
& opcode
-> mask
) == opcode
-> opcode
&&
387 opcode
!= vec_opcode
)
393 if (opcode
== opcode_end
)
395 /* No match found, just print the bits as a .word directive */
396 (*info
-> fprintf_func
) (info
-> stream
, ".word %#08lx", insn
);
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
))
404 /* There is another instruction to print from the same opcode.
405 Print the separator and then find and print the other
407 (*info
-> fprintf_func
) (info
-> stream
, " || ");
408 length
= print_instruction (info
, memaddr
, insn
, opcode
);
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. */
419 fill_instruction (info
, memaddr
, insnp
)
420 struct disassemble_info
*info
;
422 unsigned long *insnp
;
427 /* Get the bits for the next 32 bit word and put in buffer */
429 status
= (*info
-> read_memory_func
) (memaddr
+ length
, buffer
, 4, info
);
432 (*info
-> memory_error_func
) (status
, memaddr
, info
);
436 /* Read was successful, so increment count of bytes read and convert
437 the bits into internal format. */
440 if (info
-> endian
== BFD_ENDIAN_LITTLE
)
442 *insnp
= bfd_getl32 (buffer
);
444 else if (info
-> endian
== BFD_ENDIAN_BIG
)
446 *insnp
= bfd_getb32 (buffer
);
450 /* FIXME: Should probably just default to one or the other */
458 print_insn_tic80 (memaddr
, info
)
460 struct disassemble_info
*info
;
466 status
= fill_instruction (info
, memaddr
, &insn
);
469 status
= print_instruction (info
, memaddr
, insn
, NULL
);