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