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