1 /* Print TI TMS320C80 (MVP) instructions
2 Copyright 1996, 1997, 1998, 2000, 2005 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., 51 Franklin Street - Fifth Floor, Boston,
17 MA 02110-1301, USA. */
22 #include "opcode/tic80.h"
27 /* Print an integer operand. Try to be somewhat smart about the
28 format by assuming that small positive or negative integers are
29 probably loop increment values, structure offsets, or similar
30 values that are more meaningful printed as signed decimal values.
31 Larger numbers are probably better printed as hex values. */
34 print_operand_integer (struct disassemble_info
*info
, long value
)
36 if ((value
> 9999 || value
< -9999))
37 (*info
->fprintf_func
) (info
->stream
, "%#lx", value
);
39 (*info
->fprintf_func
) (info
->stream
, "%ld", value
);
42 /* FIXME: depends upon sizeof (long) == sizeof (float) and
43 also upon host floating point format matching target
44 floating point format. */
47 print_operand_float (struct disassemble_info
*info
, long value
)
49 union { float f
; long l
; } fval
;
52 (*info
->fprintf_func
) (info
->stream
, "%g", fval
.f
);
56 print_operand_control_register (struct disassemble_info
*info
, long value
)
60 tmp
= tic80_value_to_symbol (value
, TIC80_OPERAND_CR
);
62 (*info
->fprintf_func
) (info
->stream
, "%s", tmp
);
64 (*info
->fprintf_func
) (info
->stream
, "%#lx", value
);
68 print_operand_condition_code (struct disassemble_info
*info
, long value
)
72 tmp
= tic80_value_to_symbol (value
, TIC80_OPERAND_CC
);
74 (*info
->fprintf_func
) (info
->stream
, "%s", tmp
);
76 (*info
->fprintf_func
) (info
->stream
, "%ld", value
);
80 print_operand_bitnum (struct disassemble_info
*info
, long value
)
85 bitnum
= ~value
& 0x1F;
86 tmp
= tic80_value_to_symbol (bitnum
, TIC80_OPERAND_BITNUM
);
88 (*info
->fprintf_func
) (info
->stream
, "%s", tmp
);
90 (*info
->fprintf_func
) (info
->stream
, "%d", bitnum
);
93 /* Print the operand as directed by the flags. */
95 #define M_SI(insn,op) ((((op)->flags & TIC80_OPERAND_M_SI) != 0) && ((insn) & (1 << 17)))
96 #define M_LI(insn,op) ((((op)->flags & TIC80_OPERAND_M_LI) != 0) && ((insn) & (1 << 15)))
97 #define R_SCALED(insn,op) ((((op)->flags & TIC80_OPERAND_SCALED) != 0) && ((insn) & (1 << 11)))
100 print_operand (struct disassemble_info
*info
,
103 const struct tic80_operand
*operand
,
106 if ((operand
->flags
& TIC80_OPERAND_GPR
) != 0)
108 (*info
->fprintf_func
) (info
->stream
, "r%ld", value
);
109 if (M_SI (insn
, operand
) || M_LI (insn
, operand
))
111 (*info
->fprintf_func
) (info
->stream
, ":m");
114 else if ((operand
->flags
& TIC80_OPERAND_FPA
) != 0)
115 (*info
->fprintf_func
) (info
->stream
, "a%ld", value
);
117 else if ((operand
->flags
& TIC80_OPERAND_PCREL
) != 0)
118 (*info
->print_address_func
) (memaddr
+ 4 * value
, info
);
120 else if ((operand
->flags
& TIC80_OPERAND_BASEREL
) != 0)
121 (*info
->print_address_func
) (value
, info
);
123 else if ((operand
->flags
& TIC80_OPERAND_BITNUM
) != 0)
124 print_operand_bitnum (info
, value
);
126 else if ((operand
->flags
& TIC80_OPERAND_CC
) != 0)
127 print_operand_condition_code (info
, value
);
129 else if ((operand
->flags
& TIC80_OPERAND_CR
) != 0)
130 print_operand_control_register (info
, value
);
132 else if ((operand
->flags
& TIC80_OPERAND_FLOAT
) != 0)
133 print_operand_float (info
, value
);
135 else if ((operand
->flags
& TIC80_OPERAND_BITFIELD
))
136 (*info
->fprintf_func
) (info
->stream
, "%#lx", value
);
139 print_operand_integer (info
, value
);
141 /* If this is a scaled operand, then print the modifier. */
142 if (R_SCALED (insn
, operand
))
143 (*info
->fprintf_func
) (info
->stream
, ":s");
146 /* Get the next 32 bit word from the instruction stream and convert it
147 into internal format in the unsigned long INSN, for which we are
148 passed the address. Return 0 on success, -1 on error. */
151 fill_instruction (struct disassemble_info
*info
,
153 unsigned long *insnp
)
158 /* Get the bits for the next 32 bit word and put in buffer. */
159 status
= (*info
->read_memory_func
) (memaddr
+ length
, buffer
, 4, info
);
162 (*info
->memory_error_func
) (status
, memaddr
, info
);
166 /* Read was successful, so increment count of bytes read and convert
167 the bits into internal format. */
170 if (info
->endian
== BFD_ENDIAN_LITTLE
)
171 *insnp
= bfd_getl32 (buffer
);
173 else if (info
->endian
== BFD_ENDIAN_BIG
)
174 *insnp
= bfd_getb32 (buffer
);
177 /* FIXME: Should probably just default to one or the other. */
183 /* We have chosen an opcode table entry. */
186 print_one_instruction (struct disassemble_info
*info
,
189 const struct tic80_opcode
*opcode
)
191 const struct tic80_operand
*operand
;
194 const unsigned char *opindex
;
197 (*info
->fprintf_func
) (info
->stream
, "%-10s", opcode
->name
);
199 for (opindex
= opcode
->operands
; *opindex
!= 0; opindex
++)
201 operand
= tic80_operands
+ *opindex
;
203 /* Extract the value from the instruction. */
204 if (operand
->extract
)
205 value
= (*operand
->extract
) (insn
, NULL
);
207 else if (operand
->bits
== 32)
209 status
= fill_instruction (info
, memaddr
, (unsigned long *) &value
);
215 value
= (insn
>> operand
->shift
) & ((1 << operand
->bits
) - 1);
217 if ((operand
->flags
& TIC80_OPERAND_SIGNED
) != 0
218 && (value
& (1 << (operand
->bits
- 1))) != 0)
219 value
-= 1 << operand
->bits
;
222 /* If this operand is enclosed in parenthesis, then print
223 the open paren, otherwise just print the regular comma
224 separator, except for the first operand. */
225 if ((operand
->flags
& TIC80_OPERAND_PARENS
) == 0)
228 if (opindex
!= opcode
->operands
)
229 (*info
->fprintf_func
) (info
->stream
, ",");
234 (*info
->fprintf_func
) (info
->stream
, "(");
237 print_operand (info
, value
, insn
, operand
, memaddr
);
239 /* If we printed an open paren before printing this operand, close
240 it now. The flag gets reset on each loop. */
242 (*info
->fprintf_func
) (info
->stream
, ")");
248 /* There are no specific bits that tell us for certain whether a vector
249 instruction opcode contains one or two instructions. However since
250 a destination register of r0 is illegal, we can check for nonzero
251 values in both destination register fields. Only opcodes that have
252 two valid instructions will have non-zero in both. */
254 #define TWO_INSN(insn) ((((insn) & (0x1F << 27)) != 0) && (((insn) & (0x1F << 22)) != 0))
257 print_instruction (struct disassemble_info
*info
,
260 const struct tic80_opcode
*vec_opcode
)
262 const struct tic80_opcode
*opcode
;
263 const struct tic80_opcode
*opcode_end
;
265 /* Find the first opcode match in the opcodes table. For vector
266 opcodes (vec_opcode != NULL) find the first match that is not the
267 previously found match. FIXME: there should be faster ways to
268 search (hash table or binary search), but don't worry too much
269 about it until other TIc80 support is finished. */
271 opcode_end
= tic80_opcodes
+ tic80_num_opcodes
;
272 for (opcode
= tic80_opcodes
; opcode
< opcode_end
; opcode
++)
274 if ((insn
& opcode
->mask
) == opcode
->opcode
&&
275 opcode
!= vec_opcode
)
279 if (opcode
== opcode_end
)
281 /* No match found, just print the bits as a .word directive. */
282 (*info
->fprintf_func
) (info
->stream
, ".word %#08lx", insn
);
286 /* Match found, decode the instruction. */
287 length
= print_one_instruction (info
, memaddr
, insn
, opcode
);
288 if (opcode
->flags
& TIC80_VECTOR
&& vec_opcode
== NULL
&& TWO_INSN (insn
))
290 /* There is another instruction to print from the same opcode.
291 Print the separator and then find and print the other
293 (*info
->fprintf_func
) (info
->stream
, " || ");
294 length
= print_instruction (info
, memaddr
, insn
, opcode
);
302 print_insn_tic80 (bfd_vma memaddr
, struct disassemble_info
*info
)
308 info
->bytes_per_line
= 8;
309 status
= fill_instruction (info
, memaddr
, &insn
);
311 status
= print_instruction (info
, memaddr
, insn
, NULL
);