]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - opcodes/arc-dis.c
New ARC implementation.
[thirdparty/binutils-gdb.git] / opcodes / arc-dis.c
CommitLineData
252b5132 1/* Instruction printing code for the ARC.
b90efa5b 2 Copyright (C) 1994-2015 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
AJ
61#define OPCODE(word) (BITS ((word), 27, 31))
62#define FIELDA(word) (BITS ((word), 21, 26))
63#define FIELDB(word) (BITS ((word), 15, 20))
64#define FIELDC(word) (BITS ((word), 9, 14))
252b5132 65
886a2506 66#define OPCODE_AC(word) (BITS ((word), 11, 15))
252b5132 67
886a2506 68/* Functions implementation. */
252b5132 69
886a2506
NC
70static bfd_vma
71bfd_getm32 (unsigned int data)
0d2bcfaf 72{
886a2506 73 bfd_vma value = 0;
0d2bcfaf 74
886a2506
NC
75 value = ((data & 0xff00) | (data & 0xff)) << 16;
76 value |= ((data & 0xff0000) | (data & 0xff000000)) >> 16;
77 return value;
0d2bcfaf
NC
78}
79
886a2506
NC
80static int
81special_flag_p (const char *opname,
82 const char *flgname)
0d2bcfaf 83{
886a2506
NC
84 const struct arc_flag_special *flg_spec;
85 size_t len;
86 unsigned i, j, flgidx;
0d2bcfaf 87
886a2506 88 for (i = 0; i < arc_num_flag_special; i++)
252b5132 89 {
886a2506
NC
90 flg_spec = &arc_flag_special_cases[i];
91 len = strlen (flg_spec->name);
279a96ca 92
886a2506
NC
93 if (strncmp (opname, flg_spec->name, len) != 0)
94 continue;
279a96ca 95
886a2506
NC
96 /* Found potential special case instruction. */
97 for (j=0;; ++j)
0d2bcfaf 98 {
886a2506
NC
99 flgidx = flg_spec->flags[j];
100 if (flgidx == 0)
101 break; /* End of the array. */
0d2bcfaf 102
886a2506
NC
103 if (strcmp (flgname, arc_flag_operands[flgidx].name) == 0)
104 return 1;
252b5132 105 }
0d2bcfaf 106 }
886a2506 107 return 0;
0d2bcfaf 108}
252b5132 109
886a2506 110/* Disassemble ARC instructions. */
0d2bcfaf 111
886a2506
NC
112static int
113print_insn_arc (bfd_vma memaddr,
114 struct disassemble_info *info)
0d2bcfaf 115{
886a2506
NC
116 bfd_byte buffer[4];
117 unsigned int lowbyte, highbyte;
118 int status;
119 unsigned int i;
120 int insnLen = 0;
121 unsigned insn[2], isa_mask;
122 const unsigned char *opidx;
123 const unsigned char *flgidx;
124 const struct arc_opcode *opcode;
125 const char *instrName;
126 int flags;
127 bfd_boolean need_comma;
128 bfd_boolean open_braket;
0d2bcfaf 129
0d2bcfaf 130
886a2506
NC
131 lowbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 1 : 0);
132 highbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 0 : 1);
0d2bcfaf 133
886a2506
NC
134 switch (info->mach)
135 {
136 case bfd_mach_arc_arc700:
137 isa_mask = ARC_OPCODE_ARC700;
138 break;
0d2bcfaf 139
886a2506
NC
140 case bfd_mach_arc_arc600:
141 isa_mask = ARC_OPCODE_ARC600;
142 break;
0d2bcfaf 143
886a2506
NC
144 case bfd_mach_arc_arcv2:
145 default:
146 isa_mask = ARC_OPCODE_ARCv2HS | ARC_OPCODE_ARCv2EM;
147 break;
0d2bcfaf
NC
148 }
149
886a2506
NC
150 /* Read the insn into a host word. */
151 status = (*info->read_memory_func) (memaddr, buffer, 2, info);
152 if (status != 0)
0d2bcfaf 153 {
886a2506
NC
154 (*info->memory_error_func) (status, memaddr, info);
155 return -1;
0d2bcfaf
NC
156 }
157
886a2506
NC
158 if (info->section
159 && !(info->section->flags & SEC_CODE))
0d2bcfaf 160 {
886a2506
NC
161 /* Sort of data section, just print a 32 bit number. */
162 insnLen = 4;
163 status = (*info->read_memory_func) (memaddr + 2, &buffer[2], 2, info);
164 if (status != 0)
0d2bcfaf 165 {
886a2506
NC
166 (*info->memory_error_func) (status, memaddr + 2, info);
167 return -1;
0d2bcfaf 168 }
886a2506
NC
169 insn[0] = ARRANGE_ENDIAN (info, buffer);
170 (*info->fprintf_func) (info->stream, ".long %#08x", insn[0]);
171 return insnLen;
172 }
279a96ca 173
886a2506
NC
174 if ((((buffer[lowbyte] & 0xf8) > 0x38)
175 && ((buffer[lowbyte] & 0xf8) != 0x48))
176 || ((info->mach == bfd_mach_arc_arcv2)
177 && ((buffer[lowbyte] & 0xF8) == 0x48)) /* FIXME! ugly. */
178 )
179 {
180 /* This is a short instruction. */
181 insnLen = 2;
182 insn[0] = (buffer[lowbyte] << 8) | buffer[highbyte];
183 }
184 else
185 {
186 insnLen = 4;
187
188 /* This is a long instruction: Read the remaning 2 bytes. */
189 status = (*info->read_memory_func) (memaddr + 2, &buffer[2], 2, info);
190 if (status != 0)
0d2bcfaf 191 {
886a2506
NC
192 (*info->memory_error_func) (status, memaddr + 2, info);
193 return -1;
0d2bcfaf 194 }
886a2506
NC
195 insn[0] = ARRANGE_ENDIAN (info, buffer);
196 }
197
198 /* This variable may be set by the instruction decoder. It suggests
199 the number of bytes objdump should display on a single line. If
200 the instruction decoder sets this, it should always set it to
201 the same value in order to get reasonable looking output. */
202 info->bytes_per_line = 8;
203
204 /* The next two variables control the way objdump displays the raw data.
205 For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the
206 output will look like this:
207 00: 00000000 00000000
208 with the chunks displayed according to "display_endian". */
209 info->bytes_per_chunk = 2;
210 info->display_endian = info->endian;
211
212 /* Set some defaults for the insn info. */
213 info->insn_info_valid = 1;
214 info->branch_delay_insns = 0;
215 info->data_size = 0;
216 info->insn_type = dis_nonbranch;
217 info->target = 0;
218 info->target2 = 0;
219
220 /* FIXME to be moved in dissasemble_init_for_target. */
221 info->disassembler_needs_relocs = TRUE;
222
223 /* Find the first match in the opcode table. */
224 for (i = 0; i < arc_num_opcodes; i++)
225 {
226 bfd_boolean invalid = FALSE;
227
228 opcode = &arc_opcodes[i];
279a96ca 229
886a2506 230 if (ARC_SHORT (opcode->mask) && (insnLen == 2))
0d2bcfaf 231 {
886a2506
NC
232 if (OPCODE_AC (opcode->opcode) != OPCODE_AC (insn[0]))
233 continue;
0d2bcfaf 234 }
886a2506 235 else if (!ARC_SHORT (opcode->mask) && (insnLen == 4))
0d2bcfaf 236 {
886a2506
NC
237 if (OPCODE (opcode->opcode) != OPCODE (insn[0]))
238 continue;
0d2bcfaf 239 }
886a2506
NC
240 else
241 continue;
242
243 if ((insn[0] ^ opcode->opcode) & opcode->mask)
244 continue;
279a96ca 245
886a2506
NC
246 if (!(opcode->cpu & isa_mask))
247 continue;
248
249 /* Possible candidate, check the operands. */
250 for (opidx = opcode->operands; *opidx; opidx++)
0d2bcfaf 251 {
886a2506
NC
252 int value;
253 const struct arc_operand *operand = &arc_operands[*opidx];
254
255 if (operand->flags & ARC_OPERAND_FAKE)
256 continue;
257
258 if (operand->extract)
259 value = (*operand->extract) (insn[0], &invalid);
260 else
261 value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
262
263 /* Check for LIMM indicator. If it is there, then make sure
264 we pick the right format. */
265 if (operand->flags & ARC_OPERAND_IR
266 && !(operand->flags & ARC_OPERAND_LIMM))
252b5132 267 {
886a2506
NC
268 if ((value == 0x3E && insnLen == 4)
269 || (value == 0x1E && insnLen == 2))
270 {
271 invalid = TRUE;
272 break;
273 }
252b5132 274 }
0d2bcfaf 275 }
252b5132 276
886a2506
NC
277 /* Check the flags. */
278 for (flgidx = opcode->flags; *flgidx; flgidx++)
0d2bcfaf 279 {
886a2506
NC
280 /* Get a valid flag class. */
281 const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
282 const unsigned *flgopridx;
283 int foundA = 0, foundB = 0;
284
285 for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
252b5132 286 {
886a2506
NC
287 const struct arc_flag_operand *flg_operand = &arc_flag_operands[*flgopridx];
288 unsigned int value;
289
290 value = (insn[0] >> flg_operand->shift) & ((1 << flg_operand->bits) - 1);
291 if (value == flg_operand->code)
292 foundA = 1;
293 if (value)
294 foundB = 1;
252b5132 295 }
886a2506 296 if (!foundA && foundB)
252b5132 297 {
886a2506
NC
298 invalid = TRUE;
299 break;
252b5132 300 }
0d2bcfaf 301 }
279a96ca 302
886a2506
NC
303 if (invalid)
304 continue;
252b5132 305
886a2506
NC
306 /* The instruction is valid. */
307 goto found;
308 }
279a96ca 309
886a2506
NC
310 /* No instruction found. Try the extenssions. */
311 instrName = arcExtMap_instName (OPCODE (insn[0]), insn[0], &flags);
312 if (instrName)
313 {
314 opcode = &arc_opcodes[0];
315 (*info->fprintf_func) (info->stream, "%s", instrName);
316 goto print_flags;
317 }
252b5132 318
886a2506
NC
319 if (insnLen == 2)
320 (*info->fprintf_func) (info->stream, ".long %#04x", insn[0]);
321 else
322 (*info->fprintf_func) (info->stream, ".long %#08x", insn[0]);
323
324 info->insn_type = dis_noninsn;
325 return insnLen;
326
327 found:
328 /* Print the mnemonic. */
329 (*info->fprintf_func) (info->stream, "%s", opcode->name);
330
331 /* Preselect the insn class. */
332 switch (opcode->class)
333 {
334 case BRANCH:
335 case JUMP:
336 if (!strncmp (opcode->name, "bl", 2)
337 || !strncmp (opcode->name, "jl", 2))
338 info->insn_type = dis_jsr;
279a96ca 339 else
886a2506
NC
340 info->insn_type = dis_branch;
341 break;
342 case MEMORY:
343 info->insn_type = dis_dref; /* FIXME! DB indicates mov as memory! */
0d2bcfaf 344 break;
0d2bcfaf 345 default:
886a2506 346 info->insn_type = dis_nonbranch;
0d2bcfaf
NC
347 break;
348 }
279a96ca 349
886a2506 350 pr_debug ("%s: 0x%08x\n", opcode->name, opcode->opcode);
279a96ca 351
886a2506
NC
352 print_flags:
353 /* Now extract and print the flags. */
354 for (flgidx = opcode->flags; *flgidx; flgidx++)
0d2bcfaf 355 {
886a2506
NC
356 /* Get a valid flag class. */
357 const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
358 const unsigned *flgopridx;
279a96ca 359
886a2506 360 for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
0d2bcfaf 361 {
886a2506
NC
362 const struct arc_flag_operand *flg_operand = &arc_flag_operands[*flgopridx];
363 unsigned int value;
279a96ca 364
886a2506
NC
365 if (!flg_operand->favail)
366 continue;
279a96ca 367
886a2506
NC
368 value = (insn[0] >> flg_operand->shift) & ((1 << flg_operand->bits) - 1);
369 if (value == flg_operand->code)
370 {
371 /* FIXME!: print correctly nt/t flag. */
372 if (!special_flag_p (opcode->name, flg_operand->name))
373 (*info->fprintf_func) (info->stream, ".");
374 else if (info->insn_type == dis_dref)
375 {
376 switch (flg_operand->name[0])
377 {
378 case 'b':
379 info->data_size = 1;
380 break;
381 case 'h':
382 case 'w':
383 info->data_size = 2;
384 break;
385 default:
386 info->data_size = 4;
387 break;
388 }
389 }
390 (*info->fprintf_func) (info->stream, "%s", flg_operand->name);
391 }
279a96ca 392
886a2506
NC
393 if (flg_operand->name[0] == 'd'
394 && flg_operand->name[1] == 0)
395 info->branch_delay_insns = 1;
279a96ca 396 }
886a2506 397 }
279a96ca 398
886a2506
NC
399 if (opcode->operands[0] != 0)
400 (*info->fprintf_func) (info->stream, "\t");
279a96ca 401
886a2506
NC
402 need_comma = FALSE;
403 open_braket = FALSE;
279a96ca 404
886a2506
NC
405 /* Now extract and print the operands. */
406 for (opidx = opcode->operands; *opidx; opidx++)
407 {
408 const struct arc_operand *operand = &arc_operands[*opidx];
409 int value;
279a96ca 410
886a2506 411 if (open_braket && (operand->flags & ARC_OPERAND_BRAKET))
0d2bcfaf 412 {
886a2506
NC
413 (*info->fprintf_func) (info->stream, "]");
414 open_braket = FALSE;
415 continue;
0d2bcfaf 416 }
279a96ca 417
886a2506
NC
418 /* Only take input from real operands. */
419 if ((operand->flags & ARC_OPERAND_FAKE)
420 && !(operand->flags & ARC_OPERAND_BRAKET))
421 continue;
279a96ca 422
886a2506
NC
423 if (operand->extract)
424 value = (*operand->extract) (insn[0], (int *) NULL);
0d2bcfaf 425 else
0d2bcfaf 426 {
886a2506 427 if (operand->flags & ARC_OPERAND_ALIGNED32)
0d2bcfaf 428 {
886a2506
NC
429 value = (insn[0] >> operand->shift)
430 & ((1 << (operand->bits - 2)) - 1);
431 value = value << 2;
252b5132 432 }
252b5132 433 else
886a2506
NC
434 {
435 value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
436 }
437 if (operand->flags & ARC_OPERAND_SIGNED)
438 {
439 int signbit = 1 << (operand->bits - 1);
440 value = (value ^ signbit) - signbit;
441 }
252b5132 442 }
279a96ca 443
886a2506
NC
444 if (operand->flags & ARC_OPERAND_IGNORE
445 && (operand->flags & ARC_OPERAND_IR
446 && value == -1))
447 continue;
279a96ca 448
886a2506
NC
449 if (need_comma)
450 (*info->fprintf_func) (info->stream, ",");
279a96ca 451
886a2506 452 if (!open_braket && (operand->flags & ARC_OPERAND_BRAKET))
0d2bcfaf 453 {
886a2506
NC
454 (*info->fprintf_func) (info->stream, "[");
455 open_braket = TRUE;
456 need_comma = FALSE;
457 continue;
0d2bcfaf 458 }
886a2506
NC
459
460 /* Read the limm operand, if required. */
461 if (operand->flags & ARC_OPERAND_LIMM
462 && !(operand->flags & ARC_OPERAND_DUPLICATE))
0d2bcfaf 463 {
886a2506
NC
464 status = (*info->read_memory_func) (memaddr + insnLen, buffer,
465 4, info);
466 if (status != 0)
0d2bcfaf 467 {
886a2506
NC
468 (*info->memory_error_func) (status, memaddr + insnLen, info);
469 return -1;
0d2bcfaf 470 }
886a2506 471 insn[1] = ARRANGE_ENDIAN (info, buffer);
0d2bcfaf 472 }
279a96ca 473
886a2506
NC
474 /* Print the operand as directed by the flags. */
475 if (operand->flags & ARC_OPERAND_IR)
476 {
477 assert (value >=0 && value < 64);
478 (*info->fprintf_func) (info->stream, "%s", regnames[value]);
479 if (operand->flags & ARC_OPERAND_TRUNCATE)
480 (*info->fprintf_func) (info->stream, "%s", regnames[value+1]);
481 }
482 else if (operand->flags & ARC_OPERAND_LIMM)
483 {
484 (*info->fprintf_func) (info->stream, "%#x", insn[1]);
485 if (info->insn_type == dis_branch
486 || info->insn_type == dis_jsr)
487 info->target = (bfd_vma) insn[1];
488 }
489 else if (operand->flags & ARC_OPERAND_PCREL)
490 {
491 /* PCL relative. */
492 if (info->flags & INSN_HAS_RELOC)
493 memaddr = 0;
494 (*info->print_address_func) ((memaddr & ~3) + value, info);
279a96ca 495
886a2506
NC
496 info->target = (bfd_vma) (memaddr & ~3) + value;
497 }
498 else if (operand->flags & ARC_OPERAND_SIGNED)
499 (*info->fprintf_func) (info->stream, "%d", value);
500 else
501 if (operand->flags & ARC_OPERAND_TRUNCATE
502 && !(operand->flags & ARC_OPERAND_ALIGNED32)
503 && !(operand->flags & ARC_OPERAND_ALIGNED16)
504 && value > 0 && value <= 14)
505 (*info->fprintf_func) (info->stream, "r13-%s",
506 regnames[13 + value - 1]);
507 else
508 (*info->fprintf_func) (info->stream, "%#x", value);
509
510 need_comma = TRUE;
511
512 /* Adjust insn len. */
513 if (operand->flags & ARC_OPERAND_LIMM
514 && !(operand->flags & ARC_OPERAND_DUPLICATE))
515 insnLen += 4;
252b5132 516 }
279a96ca 517
886a2506 518 return insnLen;
252b5132
RH
519}
520
47b0e7ad 521
886a2506
NC
522disassembler_ftype
523arc_get_disassembler (bfd *abfd)
252b5132 524{
886a2506
NC
525 /* Read the extenssion insns and registers, if any. */
526 build_ARC_extmap (abfd);
527 dump_ARC_extmap ();
252b5132 528
886a2506 529 return print_insn_arc;
252b5132
RH
530}
531
886a2506 532/* Disassemble ARC instructions. Used by debugger. */
47b0e7ad 533
886a2506
NC
534struct arcDisState
535arcAnalyzeInstr (bfd_vma memaddr,
536 struct disassemble_info *info)
0d2bcfaf 537{
886a2506
NC
538 struct arcDisState ret;
539 memset (&ret, 0, sizeof (struct arcDisState));
540
541 ret.instructionLen = print_insn_arc (memaddr, info);
542
543#if 0
544 ret.words[0] = insn[0];
545 ret.words[1] = insn[1];
546 ret._this = &ret;
547 ret.coreRegName = _coreRegName;
548 ret.auxRegName = _auxRegName;
549 ret.condCodeName = _condCodeName;
550 ret.instName = _instName;
551#endif
47b0e7ad 552
886a2506 553 return ret;
0d2bcfaf
NC
554}
555
886a2506
NC
556/* Local variables:
557 eval: (c-set-style "gnu")
558 indent-tabs-mode: t
559 End: */