1 /* Print TI TMS320C80 (MVP) instructions
2 Copyright (C) 1996-2019 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. */
23 #include "opcode/tic80.h"
24 #include "disassemble.h"
28 /* Print an integer operand. Try to be somewhat smart about the
29 format by assuming that small positive or negative integers are
30 probably loop increment values, structure offsets, or similar
31 values that are more meaningful printed as signed decimal values.
32 Larger numbers are probably better printed as hex values. */
35 print_operand_integer (struct disassemble_info *info, long value)
37 if ((value > 9999 || value < -9999))
38 (*info->fprintf_func) (info->stream, "%#lx", value);
40 (*info->fprintf_func) (info->stream, "%ld", value);
43 /* FIXME: depends upon sizeof (long) == sizeof (float) and
44 also upon host floating point format matching target
45 floating point format. */
48 print_operand_float (struct disassemble_info *info, long value)
50 union { float f; long l; } fval;
53 (*info->fprintf_func) (info->stream, "%g", fval.f);
57 print_operand_control_register (struct disassemble_info *info, long value)
61 tmp = tic80_value_to_symbol (value, TIC80_OPERAND_CR);
63 (*info->fprintf_func) (info->stream, "%s", tmp);
65 (*info->fprintf_func) (info->stream, "%#lx", value);
69 print_operand_condition_code (struct disassemble_info *info, long value)
73 tmp = tic80_value_to_symbol (value, TIC80_OPERAND_CC);
75 (*info->fprintf_func) (info->stream, "%s", tmp);
77 (*info->fprintf_func) (info->stream, "%ld", value);
81 print_operand_bitnum (struct disassemble_info *info, long value)
86 bitnum = ~value & 0x1F;
87 tmp = tic80_value_to_symbol (bitnum, TIC80_OPERAND_BITNUM);
89 (*info->fprintf_func) (info->stream, "%s", tmp);
91 (*info->fprintf_func) (info->stream, "%d", bitnum);
94 /* Print the operand as directed by the flags. */
96 #define M_SI(insn,op) ((((op)->flags & TIC80_OPERAND_M_SI) != 0) && ((insn) & (1 << 17)))
97 #define M_LI(insn,op) ((((op)->flags & TIC80_OPERAND_M_LI) != 0) && ((insn) & (1 << 15)))
98 #define R_SCALED(insn,op) ((((op)->flags & TIC80_OPERAND_SCALED) != 0) && ((insn) & (1 << 11)))
101 print_operand (struct disassemble_info *info,
104 const struct tic80_operand *operand,
107 if ((operand->flags & TIC80_OPERAND_GPR) != 0)
109 (*info->fprintf_func) (info->stream, "r%ld", value);
110 if (M_SI (insn, operand) || M_LI (insn, operand))
112 (*info->fprintf_func) (info->stream, ":m");
115 else if ((operand->flags & TIC80_OPERAND_FPA) != 0)
116 (*info->fprintf_func) (info->stream, "a%ld", value);
118 else if ((operand->flags & TIC80_OPERAND_PCREL) != 0)
119 (*info->print_address_func) (memaddr + 4 * value, info);
121 else if ((operand->flags & TIC80_OPERAND_BASEREL) != 0)
122 (*info->print_address_func) (value, info);
124 else if ((operand->flags & TIC80_OPERAND_BITNUM) != 0)
125 print_operand_bitnum (info, value);
127 else if ((operand->flags & TIC80_OPERAND_CC) != 0)
128 print_operand_condition_code (info, value);
130 else if ((operand->flags & TIC80_OPERAND_CR) != 0)
131 print_operand_control_register (info, value);
133 else if ((operand->flags & TIC80_OPERAND_FLOAT) != 0)
134 print_operand_float (info, value);
136 else if ((operand->flags & TIC80_OPERAND_BITFIELD))
137 (*info->fprintf_func) (info->stream, "%#lx", value);
140 print_operand_integer (info, value);
142 /* If this is a scaled operand, then print the modifier. */
143 if (R_SCALED (insn, operand))
144 (*info->fprintf_func) (info->stream, ":s");
147 /* Get the next 32 bit word from the instruction stream and convert it
148 into internal format in the unsigned long INSN, for which we are
149 passed the address. Return 0 on success, -1 on error. */
152 fill_instruction (struct disassemble_info *info,
154 unsigned long *insnp)
159 /* Get the bits for the next 32 bit word and put in buffer. */
160 status = (*info->read_memory_func) (memaddr + length, buffer, 4, info);
163 (*info->memory_error_func) (status, memaddr, info);
167 /* Read was successful, so increment count of bytes read and convert
168 the bits into internal format. */
171 if (info->endian == BFD_ENDIAN_LITTLE)
172 *insnp = bfd_getl32 (buffer);
174 else if (info->endian == BFD_ENDIAN_BIG)
175 *insnp = bfd_getb32 (buffer);
178 /* FIXME: Should probably just default to one or the other. */
184 /* We have chosen an opcode table entry. */
187 print_one_instruction (struct disassemble_info *info,
190 const struct tic80_opcode *opcode)
192 const struct tic80_operand *operand;
195 const unsigned char *opindex;
198 (*info->fprintf_func) (info->stream, "%-10s", opcode->name);
200 for (opindex = opcode->operands; *opindex != 0; opindex++)
202 operand = tic80_operands + *opindex;
204 /* Extract the value from the instruction. */
205 if (operand->extract)
206 value = (*operand->extract) (insn, NULL);
208 else if (operand->bits == 32)
210 status = fill_instruction (info, memaddr, (unsigned long *) &value);
216 value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
218 if ((operand->flags & TIC80_OPERAND_SIGNED) != 0
219 && (value & (1 << (operand->bits - 1))) != 0)
220 value -= 1 << operand->bits;
223 /* If this operand is enclosed in parenthesis, then print
224 the open paren, otherwise just print the regular comma
225 separator, except for the first operand. */
226 if ((operand->flags & TIC80_OPERAND_PARENS) == 0)
229 if (opindex != opcode->operands)
230 (*info->fprintf_func) (info->stream, ",");
235 (*info->fprintf_func) (info->stream, "(");
238 print_operand (info, value, insn, operand, memaddr);
240 /* If we printed an open paren before printing this operand, close
241 it now. The flag gets reset on each loop. */
243 (*info->fprintf_func) (info->stream, ")");
249 /* There are no specific bits that tell us for certain whether a vector
250 instruction opcode contains one or two instructions. However since
251 a destination register of r0 is illegal, we can check for nonzero
252 values in both destination register fields. Only opcodes that have
253 two valid instructions will have non-zero in both. */
255 #define TWO_INSN(insn) ((((insn) & (0x1F << 27)) != 0) && (((insn) & (0x1F << 22)) != 0))
258 print_instruction (struct disassemble_info *info,
261 const struct tic80_opcode *vec_opcode)
263 const struct tic80_opcode *opcode;
264 const struct tic80_opcode *opcode_end;
266 /* Find the first opcode match in the opcodes table. For vector
267 opcodes (vec_opcode != NULL) find the first match that is not the
268 previously found match. FIXME: there should be faster ways to
269 search (hash table or binary search), but don't worry too much
270 about it until other TIc80 support is finished. */
272 opcode_end = tic80_opcodes + tic80_num_opcodes;
273 for (opcode = tic80_opcodes; opcode < opcode_end; opcode++)
275 if ((insn & opcode->mask) == opcode->opcode &&
276 opcode != vec_opcode)
280 if (opcode == opcode_end)
282 /* No match found, just print the bits as a .word directive. */
283 (*info->fprintf_func) (info->stream, ".word %#08lx", insn);
287 /* Match found, decode the instruction. */
288 length = print_one_instruction (info, memaddr, insn, opcode);
289 if (opcode->flags & TIC80_VECTOR && vec_opcode == NULL && TWO_INSN (insn))
291 /* There is another instruction to print from the same opcode.
292 Print the separator and then find and print the other
294 (*info->fprintf_func) (info->stream, " || ");
295 length = print_instruction (info, memaddr, insn, opcode);
303 print_insn_tic80 (bfd_vma memaddr, struct disassemble_info *info)
309 info->bytes_per_line = 8;
310 status = fill_instruction (info, memaddr, &insn);
312 status = print_instruction (info, memaddr, insn, NULL);