Typo fix in most recent entry.
[binutils.git] / opcodes / tic80-dis.c
blob3089acca7294340c5ac34b881a981845a05c5134
1 /* Print TI TMS320C80 (MVP) instructions
2 Copyright 1996, 1997, 1998, 2000, 2005, 2007 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 <stdio.h>
23 #include "sysdep.h"
24 #include "opcode/tic80.h"
25 #include "dis-asm.h"
27 static int length;
29 /* Print an integer operand. Try to be somewhat smart about the
30 format by assuming that small positive or negative integers are
31 probably loop increment values, structure offsets, or similar
32 values that are more meaningful printed as signed decimal values.
33 Larger numbers are probably better printed as hex values. */
35 static void
36 print_operand_integer (struct disassemble_info *info, long value)
38 if ((value > 9999 || value < -9999))
39 (*info->fprintf_func) (info->stream, "%#lx", value);
40 else
41 (*info->fprintf_func) (info->stream, "%ld", value);
44 /* FIXME: depends upon sizeof (long) == sizeof (float) and
45 also upon host floating point format matching target
46 floating point format. */
48 static void
49 print_operand_float (struct disassemble_info *info, long value)
51 union { float f; long l; } fval;
53 fval.l = value;
54 (*info->fprintf_func) (info->stream, "%g", fval.f);
57 static void
58 print_operand_control_register (struct disassemble_info *info, long value)
60 const char *tmp;
62 tmp = tic80_value_to_symbol (value, TIC80_OPERAND_CR);
63 if (tmp != NULL)
64 (*info->fprintf_func) (info->stream, "%s", tmp);
65 else
66 (*info->fprintf_func) (info->stream, "%#lx", value);
69 static void
70 print_operand_condition_code (struct disassemble_info *info, long value)
72 const char *tmp;
74 tmp = tic80_value_to_symbol (value, TIC80_OPERAND_CC);
75 if (tmp != NULL)
76 (*info->fprintf_func) (info->stream, "%s", tmp);
77 else
78 (*info->fprintf_func) (info->stream, "%ld", value);
81 static void
82 print_operand_bitnum (struct disassemble_info *info, long value)
84 int bitnum;
85 const char *tmp;
87 bitnum = ~value & 0x1F;
88 tmp = tic80_value_to_symbol (bitnum, TIC80_OPERAND_BITNUM);
89 if (tmp != NULL)
90 (*info->fprintf_func) (info->stream, "%s", tmp);
91 else
92 (*info->fprintf_func) (info->stream, "%d", bitnum);
95 /* Print the operand as directed by the flags. */
97 #define M_SI(insn,op) ((((op)->flags & TIC80_OPERAND_M_SI) != 0) && ((insn) & (1 << 17)))
98 #define M_LI(insn,op) ((((op)->flags & TIC80_OPERAND_M_LI) != 0) && ((insn) & (1 << 15)))
99 #define R_SCALED(insn,op) ((((op)->flags & TIC80_OPERAND_SCALED) != 0) && ((insn) & (1 << 11)))
101 static void
102 print_operand (struct disassemble_info *info,
103 long value,
104 unsigned long insn,
105 const struct tic80_operand *operand,
106 bfd_vma memaddr)
108 if ((operand->flags & TIC80_OPERAND_GPR) != 0)
110 (*info->fprintf_func) (info->stream, "r%ld", value);
111 if (M_SI (insn, operand) || M_LI (insn, operand))
113 (*info->fprintf_func) (info->stream, ":m");
116 else if ((operand->flags & TIC80_OPERAND_FPA) != 0)
117 (*info->fprintf_func) (info->stream, "a%ld", value);
119 else if ((operand->flags & TIC80_OPERAND_PCREL) != 0)
120 (*info->print_address_func) (memaddr + 4 * value, info);
122 else if ((operand->flags & TIC80_OPERAND_BASEREL) != 0)
123 (*info->print_address_func) (value, info);
125 else if ((operand->flags & TIC80_OPERAND_BITNUM) != 0)
126 print_operand_bitnum (info, value);
128 else if ((operand->flags & TIC80_OPERAND_CC) != 0)
129 print_operand_condition_code (info, value);
131 else if ((operand->flags & TIC80_OPERAND_CR) != 0)
132 print_operand_control_register (info, value);
134 else if ((operand->flags & TIC80_OPERAND_FLOAT) != 0)
135 print_operand_float (info, value);
137 else if ((operand->flags & TIC80_OPERAND_BITFIELD))
138 (*info->fprintf_func) (info->stream, "%#lx", value);
140 else
141 print_operand_integer (info, value);
143 /* If this is a scaled operand, then print the modifier. */
144 if (R_SCALED (insn, operand))
145 (*info->fprintf_func) (info->stream, ":s");
148 /* Get the next 32 bit word from the instruction stream and convert it
149 into internal format in the unsigned long INSN, for which we are
150 passed the address. Return 0 on success, -1 on error. */
152 static int
153 fill_instruction (struct disassemble_info *info,
154 bfd_vma memaddr,
155 unsigned long *insnp)
157 bfd_byte buffer[4];
158 int status;
160 /* Get the bits for the next 32 bit word and put in buffer. */
161 status = (*info->read_memory_func) (memaddr + length, buffer, 4, info);
162 if (status != 0)
164 (*info->memory_error_func) (status, memaddr, info);
165 return -1;
168 /* Read was successful, so increment count of bytes read and convert
169 the bits into internal format. */
171 length += 4;
172 if (info->endian == BFD_ENDIAN_LITTLE)
173 *insnp = bfd_getl32 (buffer);
175 else if (info->endian == BFD_ENDIAN_BIG)
176 *insnp = bfd_getb32 (buffer);
178 else
179 /* FIXME: Should probably just default to one or the other. */
180 abort ();
182 return 0;
185 /* We have chosen an opcode table entry. */
187 static int
188 print_one_instruction (struct disassemble_info *info,
189 bfd_vma memaddr,
190 unsigned long insn,
191 const struct tic80_opcode *opcode)
193 const struct tic80_operand *operand;
194 long value;
195 int status;
196 const unsigned char *opindex;
197 int close_paren;
199 (*info->fprintf_func) (info->stream, "%-10s", opcode->name);
201 for (opindex = opcode->operands; *opindex != 0; opindex++)
203 operand = tic80_operands + *opindex;
205 /* Extract the value from the instruction. */
206 if (operand->extract)
207 value = (*operand->extract) (insn, NULL);
209 else if (operand->bits == 32)
211 status = fill_instruction (info, memaddr, (unsigned long *) &value);
212 if (status == -1)
213 return status;
215 else
217 value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
219 if ((operand->flags & TIC80_OPERAND_SIGNED) != 0
220 && (value & (1 << (operand->bits - 1))) != 0)
221 value -= 1 << operand->bits;
224 /* If this operand is enclosed in parenthesis, then print
225 the open paren, otherwise just print the regular comma
226 separator, except for the first operand. */
227 if ((operand->flags & TIC80_OPERAND_PARENS) == 0)
229 close_paren = 0;
230 if (opindex != opcode->operands)
231 (*info->fprintf_func) (info->stream, ",");
233 else
235 close_paren = 1;
236 (*info->fprintf_func) (info->stream, "(");
239 print_operand (info, value, insn, operand, memaddr);
241 /* If we printed an open paren before printing this operand, close
242 it now. The flag gets reset on each loop. */
243 if (close_paren)
244 (*info->fprintf_func) (info->stream, ")");
247 return length;
250 /* There are no specific bits that tell us for certain whether a vector
251 instruction opcode contains one or two instructions. However since
252 a destination register of r0 is illegal, we can check for nonzero
253 values in both destination register fields. Only opcodes that have
254 two valid instructions will have non-zero in both. */
256 #define TWO_INSN(insn) ((((insn) & (0x1F << 27)) != 0) && (((insn) & (0x1F << 22)) != 0))
258 static int
259 print_instruction (struct disassemble_info *info,
260 bfd_vma memaddr,
261 unsigned long insn,
262 const struct tic80_opcode *vec_opcode)
264 const struct tic80_opcode *opcode;
265 const struct tic80_opcode *opcode_end;
267 /* Find the first opcode match in the opcodes table. For vector
268 opcodes (vec_opcode != NULL) find the first match that is not the
269 previously found match. FIXME: there should be faster ways to
270 search (hash table or binary search), but don't worry too much
271 about it until other TIc80 support is finished. */
273 opcode_end = tic80_opcodes + tic80_num_opcodes;
274 for (opcode = tic80_opcodes; opcode < opcode_end; opcode++)
276 if ((insn & opcode->mask) == opcode->opcode &&
277 opcode != vec_opcode)
278 break;
281 if (opcode == opcode_end)
283 /* No match found, just print the bits as a .word directive. */
284 (*info->fprintf_func) (info->stream, ".word %#08lx", insn);
286 else
288 /* Match found, decode the instruction. */
289 length = print_one_instruction (info, memaddr, insn, opcode);
290 if (opcode->flags & TIC80_VECTOR && vec_opcode == NULL && TWO_INSN (insn))
292 /* There is another instruction to print from the same opcode.
293 Print the separator and then find and print the other
294 instruction. */
295 (*info->fprintf_func) (info->stream, " || ");
296 length = print_instruction (info, memaddr, insn, opcode);
300 return length;
304 print_insn_tic80 (bfd_vma memaddr, struct disassemble_info *info)
306 unsigned long insn;
307 int status;
309 length = 0;
310 info->bytes_per_line = 8;
311 status = fill_instruction (info, memaddr, &insn);
312 if (status != -1)
313 status = print_instruction (info, memaddr, insn, NULL);
315 return status;