1 /* Print TI TMS320C80 (MVP) instructions
2 Copyright 1996, 1997, 1998, 2000, 2005, 2007 Free Software Foundation, Inc.
4 This file is part of the GNU opcodes library.
6 This library is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 It is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
24 #include "opcode/tic80.h"
29 /* Print an integer operand. Try to be somewhat smart about the
30 format by assuming that small positive or negative integers are
31 probably loop increment values, structure offsets, or similar
32 values that are more meaningful printed as signed decimal values.
33 Larger numbers are probably better printed as hex values. */
36 print_operand_integer (struct disassemble_info
*info
, long value
)
38 if ((value
> 9999 || value
< -9999))
39 (*info
->fprintf_func
) (info
->stream
, "%#lx", value
);
41 (*info
->fprintf_func
) (info
->stream
, "%ld", value
);
44 /* FIXME: depends upon sizeof (long) == sizeof (float) and
45 also upon host floating point format matching target
46 floating point format. */
49 print_operand_float (struct disassemble_info
*info
, long value
)
51 union { float f
; long l
; } fval
;
54 (*info
->fprintf_func
) (info
->stream
, "%g", fval
.f
);
58 print_operand_control_register (struct disassemble_info
*info
, long value
)
62 tmp
= tic80_value_to_symbol (value
, TIC80_OPERAND_CR
);
64 (*info
->fprintf_func
) (info
->stream
, "%s", tmp
);
66 (*info
->fprintf_func
) (info
->stream
, "%#lx", value
);
70 print_operand_condition_code (struct disassemble_info
*info
, long value
)
74 tmp
= tic80_value_to_symbol (value
, TIC80_OPERAND_CC
);
76 (*info
->fprintf_func
) (info
->stream
, "%s", tmp
);
78 (*info
->fprintf_func
) (info
->stream
, "%ld", value
);
82 print_operand_bitnum (struct disassemble_info
*info
, long value
)
87 bitnum
= ~value
& 0x1F;
88 tmp
= tic80_value_to_symbol (bitnum
, TIC80_OPERAND_BITNUM
);
90 (*info
->fprintf_func
) (info
->stream
, "%s", tmp
);
92 (*info
->fprintf_func
) (info
->stream
, "%d", bitnum
);
95 /* Print the operand as directed by the flags. */
97 #define M_SI(insn,op) ((((op)->flags & TIC80_OPERAND_M_SI) != 0) && ((insn) & (1 << 17)))
98 #define M_LI(insn,op) ((((op)->flags & TIC80_OPERAND_M_LI) != 0) && ((insn) & (1 << 15)))
99 #define R_SCALED(insn,op) ((((op)->flags & TIC80_OPERAND_SCALED) != 0) && ((insn) & (1 << 11)))
102 print_operand (struct disassemble_info
*info
,
105 const struct tic80_operand
*operand
,
108 if ((operand
->flags
& TIC80_OPERAND_GPR
) != 0)
110 (*info
->fprintf_func
) (info
->stream
, "r%ld", value
);
111 if (M_SI (insn
, operand
) || M_LI (insn
, operand
))
113 (*info
->fprintf_func
) (info
->stream
, ":m");
116 else if ((operand
->flags
& TIC80_OPERAND_FPA
) != 0)
117 (*info
->fprintf_func
) (info
->stream
, "a%ld", value
);
119 else if ((operand
->flags
& TIC80_OPERAND_PCREL
) != 0)
120 (*info
->print_address_func
) (memaddr
+ 4 * value
, info
);
122 else if ((operand
->flags
& TIC80_OPERAND_BASEREL
) != 0)
123 (*info
->print_address_func
) (value
, info
);
125 else if ((operand
->flags
& TIC80_OPERAND_BITNUM
) != 0)
126 print_operand_bitnum (info
, value
);
128 else if ((operand
->flags
& TIC80_OPERAND_CC
) != 0)
129 print_operand_condition_code (info
, value
);
131 else if ((operand
->flags
& TIC80_OPERAND_CR
) != 0)
132 print_operand_control_register (info
, value
);
134 else if ((operand
->flags
& TIC80_OPERAND_FLOAT
) != 0)
135 print_operand_float (info
, value
);
137 else if ((operand
->flags
& TIC80_OPERAND_BITFIELD
))
138 (*info
->fprintf_func
) (info
->stream
, "%#lx", value
);
141 print_operand_integer (info
, value
);
143 /* If this is a scaled operand, then print the modifier. */
144 if (R_SCALED (insn
, operand
))
145 (*info
->fprintf_func
) (info
->stream
, ":s");
148 /* Get the next 32 bit word from the instruction stream and convert it
149 into internal format in the unsigned long INSN, for which we are
150 passed the address. Return 0 on success, -1 on error. */
153 fill_instruction (struct disassemble_info
*info
,
155 unsigned long *insnp
)
160 /* Get the bits for the next 32 bit word and put in buffer. */
161 status
= (*info
->read_memory_func
) (memaddr
+ length
, buffer
, 4, info
);
164 (*info
->memory_error_func
) (status
, memaddr
, info
);
168 /* Read was successful, so increment count of bytes read and convert
169 the bits into internal format. */
172 if (info
->endian
== BFD_ENDIAN_LITTLE
)
173 *insnp
= bfd_getl32 (buffer
);
175 else if (info
->endian
== BFD_ENDIAN_BIG
)
176 *insnp
= bfd_getb32 (buffer
);
179 /* FIXME: Should probably just default to one or the other. */
185 /* We have chosen an opcode table entry. */
188 print_one_instruction (struct disassemble_info
*info
,
191 const struct tic80_opcode
*opcode
)
193 const struct tic80_operand
*operand
;
196 const unsigned char *opindex
;
199 (*info
->fprintf_func
) (info
->stream
, "%-10s", opcode
->name
);
201 for (opindex
= opcode
->operands
; *opindex
!= 0; opindex
++)
203 operand
= tic80_operands
+ *opindex
;
205 /* Extract the value from the instruction. */
206 if (operand
->extract
)
207 value
= (*operand
->extract
) (insn
, NULL
);
209 else if (operand
->bits
== 32)
211 status
= fill_instruction (info
, memaddr
, (unsigned long *) &value
);
217 value
= (insn
>> operand
->shift
) & ((1 << operand
->bits
) - 1);
219 if ((operand
->flags
& TIC80_OPERAND_SIGNED
) != 0
220 && (value
& (1 << (operand
->bits
- 1))) != 0)
221 value
-= 1 << operand
->bits
;
224 /* If this operand is enclosed in parenthesis, then print
225 the open paren, otherwise just print the regular comma
226 separator, except for the first operand. */
227 if ((operand
->flags
& TIC80_OPERAND_PARENS
) == 0)
230 if (opindex
!= opcode
->operands
)
231 (*info
->fprintf_func
) (info
->stream
, ",");
236 (*info
->fprintf_func
) (info
->stream
, "(");
239 print_operand (info
, value
, insn
, operand
, memaddr
);
241 /* If we printed an open paren before printing this operand, close
242 it now. The flag gets reset on each loop. */
244 (*info
->fprintf_func
) (info
->stream
, ")");
250 /* There are no specific bits that tell us for certain whether a vector
251 instruction opcode contains one or two instructions. However since
252 a destination register of r0 is illegal, we can check for nonzero
253 values in both destination register fields. Only opcodes that have
254 two valid instructions will have non-zero in both. */
256 #define TWO_INSN(insn) ((((insn) & (0x1F << 27)) != 0) && (((insn) & (0x1F << 22)) != 0))
259 print_instruction (struct disassemble_info
*info
,
262 const struct tic80_opcode
*vec_opcode
)
264 const struct tic80_opcode
*opcode
;
265 const struct tic80_opcode
*opcode_end
;
267 /* Find the first opcode match in the opcodes table. For vector
268 opcodes (vec_opcode != NULL) find the first match that is not the
269 previously found match. FIXME: there should be faster ways to
270 search (hash table or binary search), but don't worry too much
271 about it until other TIc80 support is finished. */
273 opcode_end
= tic80_opcodes
+ tic80_num_opcodes
;
274 for (opcode
= tic80_opcodes
; opcode
< opcode_end
; opcode
++)
276 if ((insn
& opcode
->mask
) == opcode
->opcode
&&
277 opcode
!= vec_opcode
)
281 if (opcode
== opcode_end
)
283 /* No match found, just print the bits as a .word directive. */
284 (*info
->fprintf_func
) (info
->stream
, ".word %#08lx", insn
);
288 /* Match found, decode the instruction. */
289 length
= print_one_instruction (info
, memaddr
, insn
, opcode
);
290 if (opcode
->flags
& TIC80_VECTOR
&& vec_opcode
== NULL
&& TWO_INSN (insn
))
292 /* There is another instruction to print from the same opcode.
293 Print the separator and then find and print the other
295 (*info
->fprintf_func
) (info
->stream
, " || ");
296 length
= print_instruction (info
, memaddr
, insn
, opcode
);
304 print_insn_tic80 (bfd_vma memaddr
, struct disassemble_info
*info
)
310 info
->bytes_per_line
= 8;
311 status
= fill_instruction (info
, memaddr
, &insn
);
313 status
= print_instruction (info
, memaddr
, insn
, NULL
);