Add missing changelogs for previous commits.
[binutils-gdb.git] / opcodes / tic80-dis.c
blob3bb05c053ab1f101e9926c5fdea3af8444321127
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)
9 any later version.
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. */
21 #include "sysdep.h"
22 #include <stdio.h>
23 #include "opcode/tic80.h"
24 #include "disassemble.h"
26 static int length;
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. */
34 static void
35 print_operand_integer (struct disassemble_info *info, long value)
37 if ((value > 9999 || value < -9999))
38 (*info->fprintf_func) (info->stream, "%#lx", value);
39 else
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. */
47 static void
48 print_operand_float (struct disassemble_info *info, long value)
50 union { float f; long l; } fval;
52 fval.l = value;
53 (*info->fprintf_func) (info->stream, "%g", fval.f);
56 static void
57 print_operand_control_register (struct disassemble_info *info, long value)
59 const char *tmp;
61 tmp = tic80_value_to_symbol (value, TIC80_OPERAND_CR);
62 if (tmp != NULL)
63 (*info->fprintf_func) (info->stream, "%s", tmp);
64 else
65 (*info->fprintf_func) (info->stream, "%#lx", value);
68 static void
69 print_operand_condition_code (struct disassemble_info *info, long value)
71 const char *tmp;
73 tmp = tic80_value_to_symbol (value, TIC80_OPERAND_CC);
74 if (tmp != NULL)
75 (*info->fprintf_func) (info->stream, "%s", tmp);
76 else
77 (*info->fprintf_func) (info->stream, "%ld", value);
80 static void
81 print_operand_bitnum (struct disassemble_info *info, long value)
83 int bitnum;
84 const char *tmp;
86 bitnum = ~value & 0x1F;
87 tmp = tic80_value_to_symbol (bitnum, TIC80_OPERAND_BITNUM);
88 if (tmp != NULL)
89 (*info->fprintf_func) (info->stream, "%s", tmp);
90 else
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)))
100 static void
101 print_operand (struct disassemble_info *info,
102 long value,
103 unsigned long insn,
104 const struct tic80_operand *operand,
105 bfd_vma memaddr)
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);
139 else
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. */
151 static int
152 fill_instruction (struct disassemble_info *info,
153 bfd_vma memaddr,
154 unsigned long *insnp)
156 bfd_byte buffer[4];
157 int status;
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);
161 if (status != 0)
163 (*info->memory_error_func) (status, memaddr, info);
164 return -1;
167 /* Read was successful, so increment count of bytes read and convert
168 the bits into internal format. */
170 length += 4;
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);
177 else
178 /* FIXME: Should probably just default to one or the other. */
179 abort ();
181 return 0;
184 /* We have chosen an opcode table entry. */
186 static int
187 print_one_instruction (struct disassemble_info *info,
188 bfd_vma memaddr,
189 unsigned long insn,
190 const struct tic80_opcode *opcode)
192 const struct tic80_operand *operand;
193 long value;
194 int status;
195 const unsigned char *opindex;
196 int close_paren;
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);
211 if (status == -1)
212 return status;
214 else
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)
228 close_paren = 0;
229 if (opindex != opcode->operands)
230 (*info->fprintf_func) (info->stream, ",");
232 else
234 close_paren = 1;
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. */
242 if (close_paren)
243 (*info->fprintf_func) (info->stream, ")");
246 return length;
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))
257 static int
258 print_instruction (struct disassemble_info *info,
259 bfd_vma memaddr,
260 unsigned long insn,
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)
277 break;
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);
285 else
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
293 instruction. */
294 (*info->fprintf_func) (info->stream, " || ");
295 length = print_instruction (info, memaddr, insn, opcode);
299 return length;
303 print_insn_tic80 (bfd_vma memaddr, struct disassemble_info *info)
305 unsigned long insn;
306 int status;
308 length = 0;
309 info->bytes_per_line = 8;
310 status = fill_instruction (info, memaddr, &insn);
311 if (status != -1)
312 status = print_instruction (info, memaddr, insn, NULL);
314 return status;