Fix typos in ChangeLogs; fix dates in copyright notices
[deliverable/binutils-gdb.git] / opcodes / tic80-dis.c
1 /* Print TI TMS320C80 (MVP) instructions
2 Copyright 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
3
4 This file is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18 #include <stdio.h>
19
20 #include "sysdep.h"
21 #include "opcode/tic80.h"
22 #include "dis-asm.h"
23
24 static int length;
25
26 static void print_operand_bitnum PARAMS ((struct disassemble_info *, long));
27 static void print_operand_condition_code PARAMS ((struct disassemble_info *, long));
28 static void print_operand_control_register PARAMS ((struct disassemble_info *, long));
29 static void print_operand_float PARAMS ((struct disassemble_info *, long));
30 static void print_operand_integer PARAMS ((struct disassemble_info *, long));
31 static void print_operand PARAMS ((struct disassemble_info *, long, unsigned long,
32 const struct tic80_operand *, bfd_vma));
33 static int print_one_instruction PARAMS ((struct disassemble_info *, bfd_vma,
34 unsigned long, const struct tic80_opcode *));
35 static int print_instruction PARAMS ((struct disassemble_info *, bfd_vma, unsigned long,
36 const struct tic80_opcode *));
37 static int fill_instruction PARAMS ((struct disassemble_info *, bfd_vma,
38 unsigned long *));
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.
44 Larger numbers are probably better printed as hex values. */
45
46 static void
47 print_operand_integer (info, value)
48 struct disassemble_info *info;
49 long value;
50 {
51 if ((value > 9999 || value < -9999))
52 {
53 (*info->fprintf_func) (info->stream, "%#lx", value);
54 }
55 else
56 {
57 (*info->fprintf_func) (info->stream, "%ld", value);
58 }
59 }
60 \f
61 /* FIXME: depends upon sizeof (long) == sizeof (float) and
62 also upon host floating point format matching target
63 floating point format. */
64
65 static void
66 print_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;
73 (*info->fprintf_func) (info->stream, "%g", fval.f);
74 }
75 \f
76 static void
77 print_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 {
86 (*info->fprintf_func) (info->stream, "%s", tmp);
87 }
88 else
89 {
90 (*info->fprintf_func) (info->stream, "%#lx", value);
91 }
92 }
93 \f
94 static void
95 print_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 {
104 (*info->fprintf_func) (info->stream, "%s", tmp);
105 }
106 else
107 {
108 (*info->fprintf_func) (info->stream, "%ld", value);
109 }
110 }
111 \f
112 static void
113 print_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 {
124 (*info->fprintf_func) (info->stream, "%s", tmp);
125 }
126 else
127 {
128 (*info->fprintf_func) (info->stream, "%ld", bitnum);
129 }
130 }
131 \f
132 /* Print the operand as directed by the flags. */
133
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)))
137
138 static void
139 print_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 {
146 if ((operand->flags & TIC80_OPERAND_GPR) != 0)
147 {
148 (*info->fprintf_func) (info->stream, "r%ld", value);
149 if (M_SI (insn, operand) || M_LI (insn, operand))
150 {
151 (*info->fprintf_func) (info->stream, ":m");
152 }
153 }
154 else if ((operand->flags & TIC80_OPERAND_FPA) != 0)
155 {
156 (*info->fprintf_func) (info->stream, "a%ld", value);
157 }
158 else if ((operand->flags & TIC80_OPERAND_PCREL) != 0)
159 {
160 (*info->print_address_func) (memaddr + 4 * value, info);
161 }
162 else if ((operand->flags & TIC80_OPERAND_BASEREL) != 0)
163 {
164 (*info->print_address_func) (value, info);
165 }
166 else if ((operand->flags & TIC80_OPERAND_BITNUM) != 0)
167 {
168 print_operand_bitnum (info, value);
169 }
170 else if ((operand->flags & TIC80_OPERAND_CC) != 0)
171 {
172 print_operand_condition_code (info, value);
173 }
174 else if ((operand->flags & TIC80_OPERAND_CR) != 0)
175 {
176 print_operand_control_register (info, value);
177 }
178 else if ((operand->flags & TIC80_OPERAND_FLOAT) != 0)
179 {
180 print_operand_float (info, value);
181 }
182 else if ((operand->flags & TIC80_OPERAND_BITFIELD))
183 {
184 (*info->fprintf_func) (info->stream, "%#lx", value);
185 }
186 else
187 {
188 print_operand_integer (info, value);
189 }
190
191 /* If this is a scaled operand, then print the modifier. */
192
193 if (R_SCALED (insn, operand))
194 {
195 (*info->fprintf_func) (info->stream, ":s");
196 }
197 }
198 \f
199 /* We have chosen an opcode table entry. */
200
201 static int
202 print_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
214 (*info->fprintf_func) (info->stream, "%-10s", opcode->name);
215
216 for (opindex = opcode->operands; *opindex != 0; opindex++)
217 {
218 operand = tic80_operands + *opindex;
219
220 /* Extract the value from the instruction. */
221 if (operand->extract)
222 {
223 value = (*operand->extract) (insn, (int *) NULL);
224 }
225 else if (operand->bits == 32)
226 {
227 status = fill_instruction (info, memaddr, (unsigned long *) &value);
228 if (status == -1)
229 {
230 return (status);
231 }
232 }
233 else
234 {
235 value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
236 if ((operand->flags & TIC80_OPERAND_SIGNED) != 0
237 && (value & (1 << (operand->bits - 1))) != 0)
238 {
239 value -= 1 << operand->bits;
240 }
241 }
242
243 /* If this operand is enclosed in parenthesis, then print
244 the open paren, otherwise just print the regular comma
245 separator, except for the first operand. */
246
247 if ((operand->flags & TIC80_OPERAND_PARENS) == 0)
248 {
249 close_paren = 0;
250 if (opindex != opcode->operands)
251 {
252 (*info->fprintf_func) (info->stream, ",");
253 }
254 }
255 else
256 {
257 close_paren = 1;
258 (*info->fprintf_func) (info->stream, "(");
259 }
260
261 print_operand (info, value, insn, operand, memaddr);
262
263 /* If we printed an open paren before printing this operand, close
264 it now. The flag gets reset on each loop. */
265
266 if (close_paren)
267 {
268 (*info->fprintf_func) (info->stream, ")");
269 }
270 }
271 return (length);
272 }
273 \f
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
278 two valid instructions will have non-zero in both. */
279
280 #define TWO_INSN(insn) ((((insn) & (0x1F << 27)) != 0) && (((insn) & (0x1F << 22)) != 0))
281
282 static int
283 print_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
296 about it until other TIc80 support is finished. */
297
298 opcode_end = tic80_opcodes + tic80_num_opcodes;
299 for (opcode = tic80_opcodes; opcode < opcode_end; opcode++)
300 {
301 if ((insn & opcode->mask) == opcode->opcode &&
302 opcode != vec_opcode)
303 {
304 break;
305 }
306 }
307
308 if (opcode == opcode_end)
309 {
310 /* No match found, just print the bits as a .word directive. */
311 (*info->fprintf_func) (info->stream, ".word %#08lx", insn);
312 }
313 else
314 {
315 /* Match found, decode the instruction. */
316 length = print_one_instruction (info, memaddr, insn, opcode);
317 if (opcode->flags & TIC80_VECTOR && vec_opcode == NULL && TWO_INSN (insn))
318 {
319 /* There is another instruction to print from the same opcode.
320 Print the separator and then find and print the other
321 instruction. */
322 (*info->fprintf_func) (info->stream, " || ");
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
331 passed the address. Return 0 on success, -1 on error. */
332
333 static int
334 fill_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
342 /* Get the bits for the next 32 bit word and put in buffer. */
343
344 status = (*info->read_memory_func) (memaddr + length, buffer, 4, info);
345 if (status != 0)
346 {
347 (*info->memory_error_func) (status, memaddr, info);
348 return (-1);
349 }
350
351 /* Read was successful, so increment count of bytes read and convert
352 the bits into internal format. */
353
354 length += 4;
355 if (info->endian == BFD_ENDIAN_LITTLE)
356 {
357 *insnp = bfd_getl32 (buffer);
358 }
359 else if (info->endian == BFD_ENDIAN_BIG)
360 {
361 *insnp = bfd_getb32 (buffer);
362 }
363 else
364 {
365 /* FIXME: Should probably just default to one or the other. */
366 abort ();
367 }
368 return (0);
369 }
370 \f
371 int
372 print_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.06355 seconds and 5 git commands to generate.