gas/
[deliverable/binutils-gdb.git] / opcodes / tic80-dis.c
CommitLineData
252b5132 1/* Print TI TMS320C80 (MVP) instructions
060d22b0 2 Copyright 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
252b5132
RH
3
4This file is free software; you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation; either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
f4321104 16Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
252b5132
RH
17
18#include <stdio.h>
19
0d8dfecf 20#include "sysdep.h"
252b5132
RH
21#include "opcode/tic80.h"
22#include "dis-asm.h"
23
24static int length;
25
26static void print_operand_bitnum PARAMS ((struct disassemble_info *, long));
27static void print_operand_condition_code PARAMS ((struct disassemble_info *, long));
28static void print_operand_control_register PARAMS ((struct disassemble_info *, long));
29static void print_operand_float PARAMS ((struct disassemble_info *, long));
30static void print_operand_integer PARAMS ((struct disassemble_info *, long));
31static void print_operand PARAMS ((struct disassemble_info *, long, unsigned long,
32 const struct tic80_operand *, bfd_vma));
33static int print_one_instruction PARAMS ((struct disassemble_info *, bfd_vma,
34 unsigned long, const struct tic80_opcode *));
35static int print_instruction PARAMS ((struct disassemble_info *, bfd_vma, unsigned long,
36 const struct tic80_opcode *));
37static int fill_instruction PARAMS ((struct disassemble_info *, bfd_vma,
38 unsigned long *));
252b5132
RH
39\f
40/* Print an integer operand. Try to be somewhat smart about the
41 format by assuming that small positive or negative integers are
42 probably loop increment values, structure offsets, or similar
43 values that are more meaningful printed as signed decimal values.
c6d805e0 44 Larger numbers are probably better printed as hex values. */
252b5132
RH
45
46static void
47print_operand_integer (info, value)
48 struct disassemble_info *info;
49 long value;
50{
51 if ((value > 9999 || value < -9999))
52 {
c6d805e0 53 (*info->fprintf_func) (info->stream, "%#lx", value);
252b5132
RH
54 }
55 else
56 {
c6d805e0 57 (*info->fprintf_func) (info->stream, "%ld", value);
252b5132
RH
58 }
59}
252b5132
RH
60\f
61/* FIXME: depends upon sizeof (long) == sizeof (float) and
62 also upon host floating point format matching target
c6d805e0 63 floating point format. */
252b5132
RH
64
65static void
66print_operand_float (info, value)
67 struct disassemble_info *info;
68 long value;
69{
70 union { float f; long l; } fval;
71
72 fval.l = value;
c6d805e0 73 (*info->fprintf_func) (info->stream, "%g", fval.f);
252b5132 74}
252b5132
RH
75\f
76static void
77print_operand_control_register (info, value)
78 struct disassemble_info *info;
79 long value;
80{
81 const char *tmp;
82
83 tmp = tic80_value_to_symbol (value, TIC80_OPERAND_CR);
84 if (tmp != NULL)
85 {
c6d805e0 86 (*info->fprintf_func) (info->stream, "%s", tmp);
252b5132
RH
87 }
88 else
89 {
c6d805e0 90 (*info->fprintf_func) (info->stream, "%#lx", value);
252b5132
RH
91 }
92}
252b5132
RH
93\f
94static void
95print_operand_condition_code (info, value)
96 struct disassemble_info *info;
97 long value;
98{
99 const char *tmp;
100
101 tmp = tic80_value_to_symbol (value, TIC80_OPERAND_CC);
102 if (tmp != NULL)
103 {
c6d805e0 104 (*info->fprintf_func) (info->stream, "%s", tmp);
252b5132
RH
105 }
106 else
107 {
c6d805e0 108 (*info->fprintf_func) (info->stream, "%ld", value);
252b5132
RH
109 }
110}
252b5132
RH
111\f
112static void
113print_operand_bitnum (info, value)
114 struct disassemble_info *info;
115 long value;
116{
117 int bitnum;
118 const char *tmp;
119
120 bitnum = ~value & 0x1F;
121 tmp = tic80_value_to_symbol (bitnum, TIC80_OPERAND_BITNUM);
122 if (tmp != NULL)
123 {
c6d805e0 124 (*info->fprintf_func) (info->stream, "%s", tmp);
252b5132
RH
125 }
126 else
127 {
c6d805e0 128 (*info->fprintf_func) (info->stream, "%ld", bitnum);
252b5132
RH
129 }
130}
252b5132
RH
131\f
132/* Print the operand as directed by the flags. */
133
c6d805e0
KH
134#define M_SI(insn,op) ((((op)->flags & TIC80_OPERAND_M_SI) != 0) && ((insn) & (1 << 17)))
135#define M_LI(insn,op) ((((op)->flags & TIC80_OPERAND_M_LI) != 0) && ((insn) & (1 << 15)))
136#define R_SCALED(insn,op) ((((op)->flags & TIC80_OPERAND_SCALED) != 0) && ((insn) & (1 << 11)))
252b5132
RH
137
138static void
139print_operand (info, value, insn, operand, memaddr)
140 struct disassemble_info *info;
141 long value;
142 unsigned long insn;
143 const struct tic80_operand *operand;
144 bfd_vma memaddr;
145{
c6d805e0 146 if ((operand->flags & TIC80_OPERAND_GPR) != 0)
252b5132 147 {
c6d805e0 148 (*info->fprintf_func) (info->stream, "r%ld", value);
252b5132
RH
149 if (M_SI (insn, operand) || M_LI (insn, operand))
150 {
c6d805e0 151 (*info->fprintf_func) (info->stream, ":m");
252b5132
RH
152 }
153 }
c6d805e0 154 else if ((operand->flags & TIC80_OPERAND_FPA) != 0)
252b5132 155 {
c6d805e0 156 (*info->fprintf_func) (info->stream, "a%ld", value);
252b5132 157 }
c6d805e0 158 else if ((operand->flags & TIC80_OPERAND_PCREL) != 0)
252b5132 159 {
c6d805e0 160 (*info->print_address_func) (memaddr + 4 * value, info);
252b5132 161 }
c6d805e0 162 else if ((operand->flags & TIC80_OPERAND_BASEREL) != 0)
252b5132 163 {
c6d805e0 164 (*info->print_address_func) (value, info);
252b5132 165 }
c6d805e0 166 else if ((operand->flags & TIC80_OPERAND_BITNUM) != 0)
252b5132
RH
167 {
168 print_operand_bitnum (info, value);
169 }
c6d805e0 170 else if ((operand->flags & TIC80_OPERAND_CC) != 0)
252b5132
RH
171 {
172 print_operand_condition_code (info, value);
173 }
c6d805e0 174 else if ((operand->flags & TIC80_OPERAND_CR) != 0)
252b5132
RH
175 {
176 print_operand_control_register (info, value);
177 }
c6d805e0 178 else if ((operand->flags & TIC80_OPERAND_FLOAT) != 0)
252b5132
RH
179 {
180 print_operand_float (info, value);
181 }
c6d805e0 182 else if ((operand->flags & TIC80_OPERAND_BITFIELD))
252b5132 183 {
c6d805e0 184 (*info->fprintf_func) (info->stream, "%#lx", value);
252b5132
RH
185 }
186 else
187 {
188 print_operand_integer (info, value);
189 }
190
c6d805e0 191 /* If this is a scaled operand, then print the modifier. */
252b5132
RH
192
193 if (R_SCALED (insn, operand))
194 {
c6d805e0 195 (*info->fprintf_func) (info->stream, ":s");
252b5132
RH
196 }
197}
252b5132 198\f
c6d805e0 199/* We have chosen an opcode table entry. */
252b5132
RH
200
201static int
202print_one_instruction (info, memaddr, insn, opcode)
203 struct disassemble_info *info;
204 bfd_vma memaddr;
205 unsigned long insn;
206 const struct tic80_opcode *opcode;
207{
208 const struct tic80_operand *operand;
209 long value;
210 int status;
211 const unsigned char *opindex;
212 int close_paren;
213
c6d805e0 214 (*info->fprintf_func) (info->stream, "%-10s", opcode->name);
252b5132 215
c6d805e0 216 for (opindex = opcode->operands; *opindex != 0; opindex++)
252b5132
RH
217 {
218 operand = tic80_operands + *opindex;
219
220 /* Extract the value from the instruction. */
c6d805e0 221 if (operand->extract)
252b5132 222 {
c6d805e0 223 value = (*operand->extract) (insn, (int *) NULL);
252b5132 224 }
c6d805e0 225 else if (operand->bits == 32)
252b5132
RH
226 {
227 status = fill_instruction (info, memaddr, (unsigned long *) &value);
228 if (status == -1)
229 {
230 return (status);
231 }
232 }
233 else
234 {
c6d805e0
KH
235 value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
236 if ((operand->flags & TIC80_OPERAND_SIGNED) != 0
237 && (value & (1 << (operand->bits - 1))) != 0)
252b5132 238 {
c6d805e0 239 value -= 1 << operand->bits;
252b5132
RH
240 }
241 }
242
243 /* If this operand is enclosed in parenthesis, then print
244 the open paren, otherwise just print the regular comma
c6d805e0 245 separator, except for the first operand. */
252b5132 246
c6d805e0 247 if ((operand->flags & TIC80_OPERAND_PARENS) == 0)
252b5132
RH
248 {
249 close_paren = 0;
c6d805e0 250 if (opindex != opcode->operands)
252b5132 251 {
c6d805e0 252 (*info->fprintf_func) (info->stream, ",");
252b5132
RH
253 }
254 }
255 else
256 {
257 close_paren = 1;
c6d805e0 258 (*info->fprintf_func) (info->stream, "(");
252b5132
RH
259 }
260
261 print_operand (info, value, insn, operand, memaddr);
262
263 /* If we printed an open paren before printing this operand, close
c6d805e0 264 it now. The flag gets reset on each loop. */
252b5132
RH
265
266 if (close_paren)
267 {
c6d805e0 268 (*info->fprintf_func) (info->stream, ")");
252b5132
RH
269 }
270 }
271 return (length);
272}
252b5132 273\f
252b5132
RH
274/* There are no specific bits that tell us for certain whether a vector
275 instruction opcode contains one or two instructions. However since
276 a destination register of r0 is illegal, we can check for nonzero
277 values in both destination register fields. Only opcodes that have
c6d805e0 278 two valid instructions will have non-zero in both. */
252b5132
RH
279
280#define TWO_INSN(insn) ((((insn) & (0x1F << 27)) != 0) && (((insn) & (0x1F << 22)) != 0))
281
282static int
283print_instruction (info, memaddr, insn, vec_opcode)
284 struct disassemble_info *info;
285 bfd_vma memaddr;
286 unsigned long insn;
287 const struct tic80_opcode *vec_opcode;
288{
289 const struct tic80_opcode *opcode;
290 const struct tic80_opcode *opcode_end;
291
292 /* Find the first opcode match in the opcodes table. For vector
293 opcodes (vec_opcode != NULL) find the first match that is not the
294 previously found match. FIXME: there should be faster ways to
295 search (hash table or binary search), but don't worry too much
c6d805e0 296 about it until other TIc80 support is finished. */
252b5132
RH
297
298 opcode_end = tic80_opcodes + tic80_num_opcodes;
299 for (opcode = tic80_opcodes; opcode < opcode_end; opcode++)
300 {
c6d805e0 301 if ((insn & opcode->mask) == opcode->opcode &&
252b5132
RH
302 opcode != vec_opcode)
303 {
304 break;
305 }
306 }
307
308 if (opcode == opcode_end)
309 {
c6d805e0
KH
310 /* No match found, just print the bits as a .word directive. */
311 (*info->fprintf_func) (info->stream, ".word %#08lx", insn);
252b5132
RH
312 }
313 else
314 {
315 /* Match found, decode the instruction. */
316 length = print_one_instruction (info, memaddr, insn, opcode);
c6d805e0 317 if (opcode->flags & TIC80_VECTOR && vec_opcode == NULL && TWO_INSN (insn))
252b5132
RH
318 {
319 /* There is another instruction to print from the same opcode.
320 Print the separator and then find and print the other
c6d805e0
KH
321 instruction. */
322 (*info->fprintf_func) (info->stream, " || ");
252b5132
RH
323 length = print_instruction (info, memaddr, insn, opcode);
324 }
325 }
326 return (length);
327}
328
329/* Get the next 32 bit word from the instruction stream and convert it
330 into internal format in the unsigned long INSN, for which we are
c6d805e0 331 passed the address. Return 0 on success, -1 on error. */
252b5132
RH
332
333static int
334fill_instruction (info, memaddr, insnp)
335 struct disassemble_info *info;
336 bfd_vma memaddr;
337 unsigned long *insnp;
338{
339 bfd_byte buffer[4];
340 int status;
341
c6d805e0 342 /* Get the bits for the next 32 bit word and put in buffer. */
252b5132 343
c6d805e0 344 status = (*info->read_memory_func) (memaddr + length, buffer, 4, info);
252b5132
RH
345 if (status != 0)
346 {
c6d805e0 347 (*info->memory_error_func) (status, memaddr, info);
252b5132
RH
348 return (-1);
349 }
350
351 /* Read was successful, so increment count of bytes read and convert
c6d805e0
KH
352 the bits into internal format. */
353
252b5132 354 length += 4;
c6d805e0 355 if (info->endian == BFD_ENDIAN_LITTLE)
252b5132
RH
356 {
357 *insnp = bfd_getl32 (buffer);
358 }
c6d805e0 359 else if (info->endian == BFD_ENDIAN_BIG)
252b5132
RH
360 {
361 *insnp = bfd_getb32 (buffer);
362 }
363 else
364 {
c6d805e0 365 /* FIXME: Should probably just default to one or the other. */
252b5132
RH
366 abort ();
367 }
368 return (0);
369}
252b5132 370\f
c6d805e0 371int
252b5132
RH
372print_insn_tic80 (memaddr, info)
373 bfd_vma memaddr;
374 struct disassemble_info *info;
375{
376 unsigned long insn;
377 int status;
378
379 length = 0;
380 info->bytes_per_line = 8;
381 status = fill_instruction (info, memaddr, &insn);
382 if (status != -1)
383 {
384 status = print_instruction (info, memaddr, insn, NULL);
385 }
386 return (status);
387}
This page took 0.377022 seconds and 4 git commands to generate.