Arm64: fix build with old glibc
[deliverable/binutils-gdb.git] / opcodes / tic80-dis.c
CommitLineData
252b5132 1/* Print TI TMS320C80 (MVP) instructions
82704155 2 Copyright (C) 1996-2019 Free Software Foundation, Inc.
252b5132 3
9b201bb5
NC
4 This file is part of the GNU opcodes library.
5
6 This library is free software; you can redistribute it and/or modify
47b0e7ad 7 it under the terms of the GNU General Public License as published by
9b201bb5
NC
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
252b5132 10
9b201bb5
NC
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.
252b5132 15
47b0e7ad
NC
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. */
252b5132 20
0d8dfecf 21#include "sysdep.h"
df7b86aa 22#include <stdio.h>
252b5132 23#include "opcode/tic80.h"
88c1242d 24#include "disassemble.h"
252b5132
RH
25
26static int length;
252b5132
RH
27\f
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.
c6d805e0 32 Larger numbers are probably better printed as hex values. */
252b5132
RH
33
34static void
47b0e7ad 35print_operand_integer (struct disassemble_info *info, long value)
252b5132
RH
36{
37 if ((value > 9999 || value < -9999))
47b0e7ad 38 (*info->fprintf_func) (info->stream, "%#lx", value);
252b5132 39 else
47b0e7ad 40 (*info->fprintf_func) (info->stream, "%ld", value);
252b5132 41}
252b5132
RH
42\f
43/* FIXME: depends upon sizeof (long) == sizeof (float) and
44 also upon host floating point format matching target
c6d805e0 45 floating point format. */
252b5132
RH
46
47static void
47b0e7ad 48print_operand_float (struct disassemble_info *info, long value)
252b5132
RH
49{
50 union { float f; long l; } fval;
51
52 fval.l = value;
c6d805e0 53 (*info->fprintf_func) (info->stream, "%g", fval.f);
252b5132 54}
47b0e7ad 55
252b5132 56static void
47b0e7ad 57print_operand_control_register (struct disassemble_info *info, long value)
252b5132
RH
58{
59 const char *tmp;
60
61 tmp = tic80_value_to_symbol (value, TIC80_OPERAND_CR);
62 if (tmp != NULL)
47b0e7ad 63 (*info->fprintf_func) (info->stream, "%s", tmp);
252b5132 64 else
47b0e7ad 65 (*info->fprintf_func) (info->stream, "%#lx", value);
252b5132 66}
47b0e7ad 67
252b5132 68static void
47b0e7ad 69print_operand_condition_code (struct disassemble_info *info, long value)
252b5132
RH
70{
71 const char *tmp;
72
73 tmp = tic80_value_to_symbol (value, TIC80_OPERAND_CC);
74 if (tmp != NULL)
47b0e7ad 75 (*info->fprintf_func) (info->stream, "%s", tmp);
252b5132 76 else
47b0e7ad 77 (*info->fprintf_func) (info->stream, "%ld", value);
252b5132 78}
47b0e7ad 79
252b5132 80static void
47b0e7ad 81print_operand_bitnum (struct disassemble_info *info, long value)
252b5132
RH
82{
83 int bitnum;
84 const char *tmp;
85
86 bitnum = ~value & 0x1F;
87 tmp = tic80_value_to_symbol (bitnum, TIC80_OPERAND_BITNUM);
88 if (tmp != NULL)
47b0e7ad 89 (*info->fprintf_func) (info->stream, "%s", tmp);
252b5132 90 else
0fd3a477 91 (*info->fprintf_func) (info->stream, "%d", bitnum);
252b5132 92}
252b5132
RH
93\f
94/* Print the operand as directed by the flags. */
95
c6d805e0
KH
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)))
252b5132
RH
99
100static void
47b0e7ad
NC
101print_operand (struct disassemble_info *info,
102 long value,
103 unsigned long insn,
104 const struct tic80_operand *operand,
105 bfd_vma memaddr)
252b5132 106{
c6d805e0 107 if ((operand->flags & TIC80_OPERAND_GPR) != 0)
252b5132 108 {
c6d805e0 109 (*info->fprintf_func) (info->stream, "r%ld", value);
252b5132
RH
110 if (M_SI (insn, operand) || M_LI (insn, operand))
111 {
c6d805e0 112 (*info->fprintf_func) (info->stream, ":m");
252b5132
RH
113 }
114 }
c6d805e0 115 else if ((operand->flags & TIC80_OPERAND_FPA) != 0)
47b0e7ad
NC
116 (*info->fprintf_func) (info->stream, "a%ld", value);
117
c6d805e0 118 else if ((operand->flags & TIC80_OPERAND_PCREL) != 0)
47b0e7ad
NC
119 (*info->print_address_func) (memaddr + 4 * value, info);
120
c6d805e0 121 else if ((operand->flags & TIC80_OPERAND_BASEREL) != 0)
47b0e7ad
NC
122 (*info->print_address_func) (value, info);
123
c6d805e0 124 else if ((operand->flags & TIC80_OPERAND_BITNUM) != 0)
47b0e7ad
NC
125 print_operand_bitnum (info, value);
126
c6d805e0 127 else if ((operand->flags & TIC80_OPERAND_CC) != 0)
47b0e7ad
NC
128 print_operand_condition_code (info, value);
129
c6d805e0 130 else if ((operand->flags & TIC80_OPERAND_CR) != 0)
47b0e7ad
NC
131 print_operand_control_register (info, value);
132
c6d805e0 133 else if ((operand->flags & TIC80_OPERAND_FLOAT) != 0)
47b0e7ad
NC
134 print_operand_float (info, value);
135
c6d805e0 136 else if ((operand->flags & TIC80_OPERAND_BITFIELD))
47b0e7ad
NC
137 (*info->fprintf_func) (info->stream, "%#lx", value);
138
252b5132 139 else
47b0e7ad 140 print_operand_integer (info, value);
252b5132 141
c6d805e0 142 /* If this is a scaled operand, then print the modifier. */
252b5132 143 if (R_SCALED (insn, operand))
47b0e7ad
NC
144 (*info->fprintf_func) (info->stream, ":s");
145}
146\f
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. */
150
151static int
152fill_instruction (struct disassemble_info *info,
153 bfd_vma memaddr,
154 unsigned long *insnp)
155{
156 bfd_byte buffer[4];
157 int status;
158
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)
252b5132 162 {
47b0e7ad
NC
163 (*info->memory_error_func) (status, memaddr, info);
164 return -1;
252b5132 165 }
47b0e7ad
NC
166
167 /* Read was successful, so increment count of bytes read and convert
168 the bits into internal format. */
169
170 length += 4;
171 if (info->endian == BFD_ENDIAN_LITTLE)
172 *insnp = bfd_getl32 (buffer);
173
174 else if (info->endian == BFD_ENDIAN_BIG)
175 *insnp = bfd_getb32 (buffer);
176
177 else
178 /* FIXME: Should probably just default to one or the other. */
179 abort ();
180
181 return 0;
252b5132 182}
47b0e7ad 183
c6d805e0 184/* We have chosen an opcode table entry. */
252b5132
RH
185
186static int
47b0e7ad
NC
187print_one_instruction (struct disassemble_info *info,
188 bfd_vma memaddr,
189 unsigned long insn,
190 const struct tic80_opcode *opcode)
252b5132
RH
191{
192 const struct tic80_operand *operand;
193 long value;
194 int status;
195 const unsigned char *opindex;
196 int close_paren;
197
c6d805e0 198 (*info->fprintf_func) (info->stream, "%-10s", opcode->name);
252b5132 199
c6d805e0 200 for (opindex = opcode->operands; *opindex != 0; opindex++)
252b5132
RH
201 {
202 operand = tic80_operands + *opindex;
203
204 /* Extract the value from the instruction. */
c6d805e0 205 if (operand->extract)
47b0e7ad
NC
206 value = (*operand->extract) (insn, NULL);
207
c6d805e0 208 else if (operand->bits == 32)
252b5132
RH
209 {
210 status = fill_instruction (info, memaddr, (unsigned long *) &value);
211 if (status == -1)
47b0e7ad 212 return status;
252b5132
RH
213 }
214 else
215 {
c6d805e0 216 value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
47b0e7ad 217
c6d805e0
KH
218 if ((operand->flags & TIC80_OPERAND_SIGNED) != 0
219 && (value & (1 << (operand->bits - 1))) != 0)
47b0e7ad 220 value -= 1 << operand->bits;
252b5132
RH
221 }
222
223 /* If this operand is enclosed in parenthesis, then print
224 the open paren, otherwise just print the regular comma
c6d805e0 225 separator, except for the first operand. */
c6d805e0 226 if ((operand->flags & TIC80_OPERAND_PARENS) == 0)
252b5132
RH
227 {
228 close_paren = 0;
c6d805e0 229 if (opindex != opcode->operands)
47b0e7ad 230 (*info->fprintf_func) (info->stream, ",");
252b5132
RH
231 }
232 else
233 {
234 close_paren = 1;
c6d805e0 235 (*info->fprintf_func) (info->stream, "(");
252b5132
RH
236 }
237
238 print_operand (info, value, insn, operand, memaddr);
239
240 /* If we printed an open paren before printing this operand, close
c6d805e0 241 it now. The flag gets reset on each loop. */
252b5132 242 if (close_paren)
47b0e7ad 243 (*info->fprintf_func) (info->stream, ")");
252b5132 244 }
47b0e7ad
NC
245
246 return length;
252b5132 247}
252b5132 248\f
252b5132
RH
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
c6d805e0 253 two valid instructions will have non-zero in both. */
252b5132
RH
254
255#define TWO_INSN(insn) ((((insn) & (0x1F << 27)) != 0) && (((insn) & (0x1F << 22)) != 0))
256
257static int
47b0e7ad
NC
258print_instruction (struct disassemble_info *info,
259 bfd_vma memaddr,
260 unsigned long insn,
261 const struct tic80_opcode *vec_opcode)
252b5132
RH
262{
263 const struct tic80_opcode *opcode;
264 const struct tic80_opcode *opcode_end;
265
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
c6d805e0 270 about it until other TIc80 support is finished. */
252b5132
RH
271
272 opcode_end = tic80_opcodes + tic80_num_opcodes;
273 for (opcode = tic80_opcodes; opcode < opcode_end; opcode++)
274 {
c6d805e0 275 if ((insn & opcode->mask) == opcode->opcode &&
252b5132 276 opcode != vec_opcode)
47b0e7ad 277 break;
252b5132
RH
278 }
279
280 if (opcode == opcode_end)
281 {
c6d805e0
KH
282 /* No match found, just print the bits as a .word directive. */
283 (*info->fprintf_func) (info->stream, ".word %#08lx", insn);
252b5132
RH
284 }
285 else
286 {
287 /* Match found, decode the instruction. */
288 length = print_one_instruction (info, memaddr, insn, opcode);
c6d805e0 289 if (opcode->flags & TIC80_VECTOR && vec_opcode == NULL && TWO_INSN (insn))
252b5132
RH
290 {
291 /* There is another instruction to print from the same opcode.
292 Print the separator and then find and print the other
c6d805e0
KH
293 instruction. */
294 (*info->fprintf_func) (info->stream, " || ");
252b5132
RH
295 length = print_instruction (info, memaddr, insn, opcode);
296 }
297 }
252b5132 298
47b0e7ad 299 return length;
252b5132 300}
252b5132 301\f
c6d805e0 302int
47b0e7ad 303print_insn_tic80 (bfd_vma memaddr, struct disassemble_info *info)
252b5132
RH
304{
305 unsigned long insn;
306 int status;
307
308 length = 0;
309 info->bytes_per_line = 8;
310 status = fill_instruction (info, memaddr, &insn);
311 if (status != -1)
47b0e7ad
NC
312 status = print_instruction (info, memaddr, insn, NULL);
313
314 return status;
252b5132 315}
This page took 0.935403 seconds and 4 git commands to generate.