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