Update ARC instruction data-base.
[deliverable/binutils-gdb.git] / opcodes / arc-dis.c
CommitLineData
252b5132 1/* Instruction printing code for the ARC.
6f2750fe 2 Copyright (C) 1994-2016 Free Software Foundation, Inc.
886a2506
NC
3
4 Contributed by Claudiu Zissulescu (claziss@synopsys.com)
252b5132 5
9b201bb5
NC
6 This file is part of libopcodes.
7
8 This library is free software; you can redistribute it and/or modify
0d2bcfaf 9 it under the terms of the GNU General Public License as published by
9b201bb5
NC
10 the Free Software Foundation; either version 3, or (at your option)
11 any later version.
252b5132 12
9b201bb5
NC
13 It is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
252b5132 17
0d2bcfaf
NC
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
47b0e7ad
NC
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 MA 02110-1301, USA. */
252b5132 22
5eb3690e 23#include "sysdep.h"
886a2506
NC
24#include <stdio.h>
25#include <assert.h>
252b5132
RH
26#include "dis-asm.h"
27#include "opcode/arc.h"
0d2bcfaf
NC
28#include "arc-dis.h"
29#include "arc-ext.h"
252b5132 30
252b5132 31
886a2506 32/* Globals variables. */
82b829a7 33
886a2506 34static const char * const regnames[64] =
47b0e7ad 35{
886a2506
NC
36 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
37 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
38 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
39 "r24", "r25", "gp", "fp", "sp", "ilink", "r30", "blink",
40
41 "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
42 "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",
43 "r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55",
44 "r56", "r57", "ACCL", "ACCH", "lp_count", "rezerved", "LIMM", "pcl"
45};
46
47/* Macros section. */
48
49#ifdef DEBUG
50# define pr_debug(fmt, args...) fprintf (stderr, fmt, ##args)
51#else
52# define pr_debug(fmt, args...)
53#endif
54
55#define ARRANGE_ENDIAN(info, buf) \
56 (info->endian == BFD_ENDIAN_LITTLE ? bfd_getm32 (bfd_getl32 (buf)) \
57 : bfd_getb32 (buf))
58
59#define BITS(word,s,e) (((word) << (sizeof (word) * 8 - 1 - e)) >> \
60 (s + (sizeof (word) * 8 - 1 - e)))
279a96ca 61#define OPCODE(word) (BITS ((word), 27, 31))
252b5132 62
886a2506 63#define OPCODE_AC(word) (BITS ((word), 11, 15))
252b5132 64
886a2506 65/* Functions implementation. */
252b5132 66
886a2506
NC
67static bfd_vma
68bfd_getm32 (unsigned int data)
0d2bcfaf 69{
886a2506 70 bfd_vma value = 0;
0d2bcfaf 71
886a2506
NC
72 value = ((data & 0xff00) | (data & 0xff)) << 16;
73 value |= ((data & 0xff0000) | (data & 0xff000000)) >> 16;
74 return value;
0d2bcfaf
NC
75}
76
886a2506
NC
77static int
78special_flag_p (const char *opname,
79 const char *flgname)
0d2bcfaf 80{
886a2506 81 const struct arc_flag_special *flg_spec;
886a2506 82 unsigned i, j, flgidx;
0d2bcfaf 83
886a2506 84 for (i = 0; i < arc_num_flag_special; i++)
252b5132 85 {
886a2506 86 flg_spec = &arc_flag_special_cases[i];
279a96ca 87
24b368f8 88 if (strcmp (opname, flg_spec->name))
886a2506 89 continue;
279a96ca 90
886a2506
NC
91 /* Found potential special case instruction. */
92 for (j=0;; ++j)
0d2bcfaf 93 {
886a2506
NC
94 flgidx = flg_spec->flags[j];
95 if (flgidx == 0)
96 break; /* End of the array. */
0d2bcfaf 97
886a2506
NC
98 if (strcmp (flgname, arc_flag_operands[flgidx].name) == 0)
99 return 1;
252b5132 100 }
0d2bcfaf 101 }
886a2506 102 return 0;
0d2bcfaf 103}
252b5132 104
b99747ae
CZ
105/* Find proper format for the given opcode. */
106static const struct arc_opcode *
107find_format (const struct arc_opcode *arc_table,
108 unsigned *insn, int insnLen,
109 unsigned isa_mask)
110{
111 unsigned int i = 0;
112 const struct arc_opcode *opcode = NULL;
113 const unsigned char *opidx;
114 const unsigned char *flgidx;
115
116 do {
117 bfd_boolean invalid = FALSE;
118
119 opcode = &arc_table[i++];
120
121 if (ARC_SHORT (opcode->mask) && (insnLen == 2))
122 {
123 if (OPCODE_AC (opcode->opcode) != OPCODE_AC (insn[0]))
124 continue;
125 }
126 else if (!ARC_SHORT (opcode->mask) && (insnLen == 4))
127 {
128 if (OPCODE (opcode->opcode) != OPCODE (insn[0]))
129 continue;
130 }
131 else
132 continue;
133
134 if ((insn[0] ^ opcode->opcode) & opcode->mask)
135 continue;
136
137 if (!(opcode->cpu & isa_mask))
138 continue;
139
140 /* Possible candidate, check the operands. */
141 for (opidx = opcode->operands; *opidx; opidx++)
142 {
143 int value;
144 const struct arc_operand *operand = &arc_operands[*opidx];
145
146 if (operand->flags & ARC_OPERAND_FAKE)
147 continue;
148
149 if (operand->extract)
150 value = (*operand->extract) (insn[0], &invalid);
151 else
152 value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
153
154 /* Check for LIMM indicator. If it is there, then make sure
155 we pick the right format. */
156 if (operand->flags & ARC_OPERAND_IR
157 && !(operand->flags & ARC_OPERAND_LIMM))
158 {
159 if ((value == 0x3E && insnLen == 4)
160 || (value == 0x1E && insnLen == 2))
161 {
162 invalid = TRUE;
163 break;
164 }
165 }
166 }
167
168 /* Check the flags. */
169 for (flgidx = opcode->flags; *flgidx; flgidx++)
170 {
171 /* Get a valid flag class. */
172 const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
173 const unsigned *flgopridx;
174 int foundA = 0, foundB = 0;
175
176 for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
177 {
178 const struct arc_flag_operand *flg_operand =
179 &arc_flag_operands[*flgopridx];
180 unsigned int value;
181
182 value = (insn[0] >> flg_operand->shift)
183 & ((1 << flg_operand->bits) - 1);
184 if (value == flg_operand->code)
185 foundA = 1;
186 if (value)
187 foundB = 1;
188 }
189 if (!foundA && foundB)
190 {
191 invalid = TRUE;
192 break;
193 }
194 }
195
196 if (invalid)
197 continue;
198
199 /* The instruction is valid. */
200 return opcode;
201 } while (opcode->mask);
202
203 return NULL;
204}
205
886a2506 206/* Disassemble ARC instructions. */
0d2bcfaf 207
886a2506
NC
208static int
209print_insn_arc (bfd_vma memaddr,
210 struct disassemble_info *info)
0d2bcfaf 211{
886a2506
NC
212 bfd_byte buffer[4];
213 unsigned int lowbyte, highbyte;
214 int status;
886a2506 215 int insnLen = 0;
3f94e60d
NC
216 unsigned insn[2] = { 0, 0 };
217 unsigned isa_mask;
886a2506
NC
218 const unsigned char *opidx;
219 const unsigned char *flgidx;
220 const struct arc_opcode *opcode;
b99747ae 221 const extInstruction_t *einsn;
886a2506
NC
222 bfd_boolean need_comma;
223 bfd_boolean open_braket;
24b368f8 224 int size;
0d2bcfaf 225
886a2506
NC
226 lowbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 1 : 0);
227 highbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 0 : 1);
0d2bcfaf 228
886a2506
NC
229 switch (info->mach)
230 {
8699fc3e
AB
231 case bfd_mach_arc_nps400:
232 isa_mask = ARC_OPCODE_ARC700 | ARC_OPCODE_NPS400;
233 break;
234
886a2506
NC
235 case bfd_mach_arc_arc700:
236 isa_mask = ARC_OPCODE_ARC700;
237 break;
0d2bcfaf 238
886a2506
NC
239 case bfd_mach_arc_arc600:
240 isa_mask = ARC_OPCODE_ARC600;
241 break;
0d2bcfaf 242
886a2506
NC
243 case bfd_mach_arc_arcv2:
244 default:
245 isa_mask = ARC_OPCODE_ARCv2HS | ARC_OPCODE_ARCv2EM;
246 break;
0d2bcfaf
NC
247 }
248
24b368f8
CZ
249 /* This variable may be set by the instruction decoder. It suggests
250 the number of bytes objdump should display on a single line. If
251 the instruction decoder sets this, it should always set it to
252 the same value in order to get reasonable looking output. */
253
254 info->bytes_per_line = 8;
255
256 /* In the next lines, we set two info variables control the way
257 objdump displays the raw data. For example, if bytes_per_line is
258 8 and bytes_per_chunk is 4, the output will look like this:
259 00: 00000000 00000000
260 with the chunks displayed according to "display_endian". */
261
262 if (info->section
263 && !(info->section->flags & SEC_CODE))
264 {
265 /* This is not a CODE section. */
266 switch (info->section->size)
267 {
268 case 1:
269 case 2:
270 case 4:
271 size = info->section->size;
272 break;
273 default:
274 size = (info->section->size & 0x01) ? 1 : 4;
275 break;
276 }
277 info->bytes_per_chunk = 1;
278 info->display_endian = info->endian;
279 }
280 else
281 {
282 size = 2;
283 info->bytes_per_chunk = 2;
284 info->display_endian = info->endian;
285 }
286
886a2506 287 /* Read the insn into a host word. */
24b368f8 288 status = (*info->read_memory_func) (memaddr, buffer, size, info);
886a2506 289 if (status != 0)
0d2bcfaf 290 {
886a2506
NC
291 (*info->memory_error_func) (status, memaddr, info);
292 return -1;
0d2bcfaf
NC
293 }
294
886a2506
NC
295 if (info->section
296 && !(info->section->flags & SEC_CODE))
0d2bcfaf 297 {
24b368f8
CZ
298 /* Data section. */
299 unsigned long data;
300
301 data = bfd_get_bits (buffer, size * 8,
302 info->display_endian == BFD_ENDIAN_BIG);
303 switch (size)
0d2bcfaf 304 {
24b368f8
CZ
305 case 1:
306 (*info->fprintf_func) (info->stream, ".byte\t0x%02lx", data);
307 break;
308 case 2:
309 (*info->fprintf_func) (info->stream, ".short\t0x%04lx", data);
310 break;
311 case 4:
312 (*info->fprintf_func) (info->stream, ".word\t0x%08lx", data);
313 break;
314 default:
315 abort ();
0d2bcfaf 316 }
24b368f8 317 return size;
886a2506 318 }
279a96ca 319
b99747ae 320 if ((((buffer[lowbyte] & 0xf8) > 0x38)
886a2506
NC
321 && ((buffer[lowbyte] & 0xf8) != 0x48))
322 || ((info->mach == bfd_mach_arc_arcv2)
323 && ((buffer[lowbyte] & 0xF8) == 0x48)) /* FIXME! ugly. */
324 )
325 {
326 /* This is a short instruction. */
327 insnLen = 2;
328 insn[0] = (buffer[lowbyte] << 8) | buffer[highbyte];
329 }
330 else
331 {
332 insnLen = 4;
333
334 /* This is a long instruction: Read the remaning 2 bytes. */
335 status = (*info->read_memory_func) (memaddr + 2, &buffer[2], 2, info);
336 if (status != 0)
0d2bcfaf 337 {
886a2506
NC
338 (*info->memory_error_func) (status, memaddr + 2, info);
339 return -1;
0d2bcfaf 340 }
886a2506
NC
341 insn[0] = ARRANGE_ENDIAN (info, buffer);
342 }
343
886a2506
NC
344 /* Set some defaults for the insn info. */
345 info->insn_info_valid = 1;
346 info->branch_delay_insns = 0;
347 info->data_size = 0;
348 info->insn_type = dis_nonbranch;
349 info->target = 0;
350 info->target2 = 0;
351
352 /* FIXME to be moved in dissasemble_init_for_target. */
353 info->disassembler_needs_relocs = TRUE;
354
355 /* Find the first match in the opcode table. */
b99747ae 356 opcode = find_format (arc_opcodes, insn, insnLen, isa_mask);
886a2506 357
b99747ae
CZ
358 if (!opcode)
359 {
360 /* No instruction found. Try the extensions. */
361 einsn = arcExtMap_insn (OPCODE (insn[0]), insn[0]);
362 if (einsn)
0d2bcfaf 363 {
b99747ae
CZ
364 const char *errmsg = NULL;
365 opcode = arcExtMap_genOpcode (einsn, isa_mask, &errmsg);
366 if (opcode == NULL)
252b5132 367 {
b99747ae
CZ
368 (*info->fprintf_func) (info->stream,
369 "An error occured while "
370 "generating the extension instruction "
371 "operations");
372 return -1;
252b5132 373 }
252b5132 374
b99747ae
CZ
375 opcode = find_format (opcode, insn, insnLen, isa_mask);
376 assert (opcode != NULL);
377 }
378 else
0d2bcfaf 379 {
b99747ae
CZ
380 if (insnLen == 2)
381 (*info->fprintf_func) (info->stream, ".long %#04x", insn[0]);
382 else
383 (*info->fprintf_func) (info->stream, ".long %#08x", insn[0]);
886a2506 384
b99747ae
CZ
385 info->insn_type = dis_noninsn;
386 return insnLen;
0d2bcfaf 387 }
886a2506 388 }
279a96ca 389
886a2506
NC
390 /* Print the mnemonic. */
391 (*info->fprintf_func) (info->stream, "%s", opcode->name);
392
393 /* Preselect the insn class. */
394 switch (opcode->class)
395 {
396 case BRANCH:
397 case JUMP:
398 if (!strncmp (opcode->name, "bl", 2)
399 || !strncmp (opcode->name, "jl", 2))
400 info->insn_type = dis_jsr;
279a96ca 401 else
886a2506
NC
402 info->insn_type = dis_branch;
403 break;
404 case MEMORY:
405 info->insn_type = dis_dref; /* FIXME! DB indicates mov as memory! */
0d2bcfaf 406 break;
0d2bcfaf 407 default:
886a2506 408 info->insn_type = dis_nonbranch;
0d2bcfaf
NC
409 break;
410 }
279a96ca 411
886a2506 412 pr_debug ("%s: 0x%08x\n", opcode->name, opcode->opcode);
279a96ca 413
886a2506
NC
414 /* Now extract and print the flags. */
415 for (flgidx = opcode->flags; *flgidx; flgidx++)
0d2bcfaf 416 {
886a2506
NC
417 /* Get a valid flag class. */
418 const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
419 const unsigned *flgopridx;
279a96ca 420
886a2506 421 for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
0d2bcfaf 422 {
886a2506
NC
423 const struct arc_flag_operand *flg_operand = &arc_flag_operands[*flgopridx];
424 unsigned int value;
279a96ca 425
886a2506
NC
426 if (!flg_operand->favail)
427 continue;
279a96ca 428
886a2506
NC
429 value = (insn[0] >> flg_operand->shift) & ((1 << flg_operand->bits) - 1);
430 if (value == flg_operand->code)
431 {
432 /* FIXME!: print correctly nt/t flag. */
433 if (!special_flag_p (opcode->name, flg_operand->name))
434 (*info->fprintf_func) (info->stream, ".");
435 else if (info->insn_type == dis_dref)
436 {
437 switch (flg_operand->name[0])
438 {
439 case 'b':
440 info->data_size = 1;
441 break;
442 case 'h':
443 case 'w':
444 info->data_size = 2;
445 break;
446 default:
447 info->data_size = 4;
448 break;
449 }
450 }
451 (*info->fprintf_func) (info->stream, "%s", flg_operand->name);
452 }
279a96ca 453
886a2506
NC
454 if (flg_operand->name[0] == 'd'
455 && flg_operand->name[1] == 0)
456 info->branch_delay_insns = 1;
279a96ca 457 }
886a2506 458 }
279a96ca 459
886a2506
NC
460 if (opcode->operands[0] != 0)
461 (*info->fprintf_func) (info->stream, "\t");
279a96ca 462
886a2506
NC
463 need_comma = FALSE;
464 open_braket = FALSE;
279a96ca 465
886a2506
NC
466 /* Now extract and print the operands. */
467 for (opidx = opcode->operands; *opidx; opidx++)
468 {
469 const struct arc_operand *operand = &arc_operands[*opidx];
470 int value;
279a96ca 471
886a2506 472 if (open_braket && (operand->flags & ARC_OPERAND_BRAKET))
0d2bcfaf 473 {
886a2506
NC
474 (*info->fprintf_func) (info->stream, "]");
475 open_braket = FALSE;
476 continue;
0d2bcfaf 477 }
279a96ca 478
886a2506
NC
479 /* Only take input from real operands. */
480 if ((operand->flags & ARC_OPERAND_FAKE)
481 && !(operand->flags & ARC_OPERAND_BRAKET))
482 continue;
279a96ca 483
886a2506
NC
484 if (operand->extract)
485 value = (*operand->extract) (insn[0], (int *) NULL);
0d2bcfaf 486 else
0d2bcfaf 487 {
886a2506 488 if (operand->flags & ARC_OPERAND_ALIGNED32)
0d2bcfaf 489 {
886a2506
NC
490 value = (insn[0] >> operand->shift)
491 & ((1 << (operand->bits - 2)) - 1);
492 value = value << 2;
252b5132 493 }
252b5132 494 else
886a2506
NC
495 {
496 value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
497 }
498 if (operand->flags & ARC_OPERAND_SIGNED)
499 {
500 int signbit = 1 << (operand->bits - 1);
501 value = (value ^ signbit) - signbit;
502 }
252b5132 503 }
279a96ca 504
886a2506
NC
505 if (operand->flags & ARC_OPERAND_IGNORE
506 && (operand->flags & ARC_OPERAND_IR
507 && value == -1))
508 continue;
279a96ca 509
886a2506
NC
510 if (need_comma)
511 (*info->fprintf_func) (info->stream, ",");
279a96ca 512
886a2506 513 if (!open_braket && (operand->flags & ARC_OPERAND_BRAKET))
0d2bcfaf 514 {
886a2506
NC
515 (*info->fprintf_func) (info->stream, "[");
516 open_braket = TRUE;
517 need_comma = FALSE;
518 continue;
0d2bcfaf 519 }
886a2506
NC
520
521 /* Read the limm operand, if required. */
522 if (operand->flags & ARC_OPERAND_LIMM
523 && !(operand->flags & ARC_OPERAND_DUPLICATE))
0d2bcfaf 524 {
886a2506
NC
525 status = (*info->read_memory_func) (memaddr + insnLen, buffer,
526 4, info);
527 if (status != 0)
0d2bcfaf 528 {
886a2506
NC
529 (*info->memory_error_func) (status, memaddr + insnLen, info);
530 return -1;
0d2bcfaf 531 }
886a2506 532 insn[1] = ARRANGE_ENDIAN (info, buffer);
0d2bcfaf 533 }
279a96ca 534
886a2506
NC
535 /* Print the operand as directed by the flags. */
536 if (operand->flags & ARC_OPERAND_IR)
537 {
538 assert (value >=0 && value < 64);
539 (*info->fprintf_func) (info->stream, "%s", regnames[value]);
540 if (operand->flags & ARC_OPERAND_TRUNCATE)
541 (*info->fprintf_func) (info->stream, "%s", regnames[value+1]);
542 }
543 else if (operand->flags & ARC_OPERAND_LIMM)
544 {
545 (*info->fprintf_func) (info->stream, "%#x", insn[1]);
546 if (info->insn_type == dis_branch
547 || info->insn_type == dis_jsr)
548 info->target = (bfd_vma) insn[1];
549 }
550 else if (operand->flags & ARC_OPERAND_PCREL)
551 {
552 /* PCL relative. */
553 if (info->flags & INSN_HAS_RELOC)
554 memaddr = 0;
555 (*info->print_address_func) ((memaddr & ~3) + value, info);
279a96ca 556
886a2506
NC
557 info->target = (bfd_vma) (memaddr & ~3) + value;
558 }
559 else if (operand->flags & ARC_OPERAND_SIGNED)
560 (*info->fprintf_func) (info->stream, "%d", value);
561 else
562 if (operand->flags & ARC_OPERAND_TRUNCATE
563 && !(operand->flags & ARC_OPERAND_ALIGNED32)
564 && !(operand->flags & ARC_OPERAND_ALIGNED16)
565 && value > 0 && value <= 14)
566 (*info->fprintf_func) (info->stream, "r13-%s",
567 regnames[13 + value - 1]);
568 else
569 (*info->fprintf_func) (info->stream, "%#x", value);
570
571 need_comma = TRUE;
572
573 /* Adjust insn len. */
574 if (operand->flags & ARC_OPERAND_LIMM
575 && !(operand->flags & ARC_OPERAND_DUPLICATE))
576 insnLen += 4;
252b5132 577 }
279a96ca 578
886a2506 579 return insnLen;
252b5132
RH
580}
581
47b0e7ad 582
886a2506
NC
583disassembler_ftype
584arc_get_disassembler (bfd *abfd)
252b5132 585{
886a2506
NC
586 /* Read the extenssion insns and registers, if any. */
587 build_ARC_extmap (abfd);
b99747ae 588#ifdef DEBUG
886a2506 589 dump_ARC_extmap ();
b99747ae 590#endif
252b5132 591
886a2506 592 return print_insn_arc;
252b5132
RH
593}
594
886a2506 595/* Disassemble ARC instructions. Used by debugger. */
47b0e7ad 596
886a2506
NC
597struct arcDisState
598arcAnalyzeInstr (bfd_vma memaddr,
599 struct disassemble_info *info)
0d2bcfaf 600{
886a2506
NC
601 struct arcDisState ret;
602 memset (&ret, 0, sizeof (struct arcDisState));
603
604 ret.instructionLen = print_insn_arc (memaddr, info);
605
606#if 0
607 ret.words[0] = insn[0];
608 ret.words[1] = insn[1];
609 ret._this = &ret;
610 ret.coreRegName = _coreRegName;
611 ret.auxRegName = _auxRegName;
612 ret.condCodeName = _condCodeName;
613 ret.instName = _instName;
614#endif
47b0e7ad 615
886a2506 616 return ret;
0d2bcfaf
NC
617}
618
886a2506
NC
619/* Local variables:
620 eval: (c-set-style "gnu")
621 indent-tabs-mode: t
622 End: */
This page took 0.739751 seconds and 4 git commands to generate.