]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - opcodes/csky-dis.c
Automatic date update in version.in
[thirdparty/binutils-gdb.git] / opcodes / csky-dis.c
CommitLineData
b8891f8d 1/* C-SKY disassembler.
fd67aa11 2 Copyright (C) 1988-2024 Free Software Foundation, Inc.
b8891f8d
AJ
3 Contributed by C-SKY Microsystems and Mentor Graphics.
4
5 This file is part of the GNU opcodes library.
6
7 This library is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 It is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20 MA 02110-1301, USA. */
21
22#include "sysdep.h"
23#include "config.h"
24#include <stdio.h>
3dfb1b6d 25#include <stdint.h>
0861f561 26#include <elf/csky.h>
b8891f8d
AJ
27#include "disassemble.h"
28#include "elf-bfd.h"
29#include "opcode/csky.h"
30#include "libiberty.h"
31#include "csky-opc.h"
32#include "floatformat.h"
33
34#define CSKY_INST_TYPE unsigned long
35#define HAS_SUB_OPERAND (unsigned int)0xffffffff
0861f561 36#define CSKY_DEFAULT_ISA 0xffffffff
b8891f8d
AJ
37
38enum sym_type
39{
40 CUR_TEXT,
41 CUR_DATA
42};
43
44struct csky_dis_info
45{
46 /* Mem to disassemble. */
47 bfd_vma mem;
48 /* Disassemble info. */
49 disassemble_info *info;
50 /* Opcode information. */
51 struct csky_opcode_info const *opinfo;
0e3c1eeb 52 uint64_t isa;
b8891f8d
AJ
53 /* The value of operand to show. */
54 int value;
55 /* Whether to look up/print a symbol name. */
56 int need_output_symbol;
57} dis_info;
58
59
60enum sym_type last_type;
61int last_map_sym = 1;
62bfd_vma last_map_addr = 0;
afdcafe8 63int using_abi = 0;
b8891f8d
AJ
64
65/* Only for objdump tool. */
66#define INIT_MACH_FLAG 0xffffffff
67#define BINARY_MACH_FLAG 0x0
68
69static unsigned int mach_flag = INIT_MACH_FLAG;
70
71static void
72print_insn_data (bfd_vma pc ATTRIBUTE_UNUSED,
73 struct disassemble_info *info,
74 long given)
75{
76 switch (info->bytes_per_chunk)
77 {
78 case 1:
79 info->fprintf_func (info->stream, ".byte\t0x%02lx", given);
80 break;
81 case 2:
82 info->fprintf_func (info->stream, ".short\t0x%04lx", given);
83 break;
84 case 4:
85 info->fprintf_func (info->stream, ".long\t0x%08lx", given);
86 break;
87 default:
88 abort ();
89 }
90}
91
92static int
93get_sym_code_type (struct disassemble_info *info,
94 int n,
95 enum sym_type *sym_type)
96{
97 const char *name;
98 name = bfd_asymbol_name (info->symtab[n]);
99 if (name[0] == '$' && (name[1] == 't' || name[1] == 'd')
100 && (name[2] == 0 || name[2] == '.'))
101 {
102 *sym_type = ((name[1] == 't') ? CUR_TEXT : CUR_DATA);
78933a4a 103 return true;
b8891f8d 104 }
78933a4a 105 return false;
b8891f8d
AJ
106}
107
108static int
109csky_get_operand_mask (struct operand const *oprnd)
110{
111 int mask = 0;
112 if (oprnd->mask == HAS_SUB_OPERAND)
113 {
114 struct soperand *sop = (struct soperand *)oprnd;
115 mask |= csky_get_operand_mask (&sop->subs[0]);
116 mask |= csky_get_operand_mask (&sop->subs[1]);
117 return mask;
118 }
119 return oprnd->mask;
120}
121
122static int
123csky_get_mask (struct csky_opcode_info const *pinfo)
124{
125 int i = 0;
126 int mask = 0;
127 /* List type. */
128 if (pinfo->operand_num == -1)
129 mask |= csky_get_operand_mask (&pinfo->oprnd.oprnds[i]);
130 else
131 for (; i < pinfo->operand_num; i++)
132 mask |= csky_get_operand_mask (&pinfo->oprnd.oprnds[i]);
133
134 mask = ~mask;
135 return mask;
136}
137
138static unsigned int
139csky_chars_to_number (unsigned char * buf, int n)
140{
b8891f8d 141 int i;
1ee3542c 142 unsigned int val = 0;
b8891f8d
AJ
143
144 if (dis_info.info->endian == BFD_ENDIAN_BIG)
b8891f8d 145 for (i = 0; i < n; i++)
967354c3 146 val = val << 8 | buf[i];
d93bba9e
AM
147 else
148 for (i = n - 1; i >= 0; i--)
967354c3 149 val = val << 8 | buf[i];
b8891f8d
AJ
150 return val;
151}
152
153static struct csky_opcode const *g_opcodeP;
154
155static struct csky_opcode const *
156csky_find_inst_info (struct csky_opcode_info const **pinfo,
157 CSKY_INST_TYPE inst, int length)
158{
159 int i;
160 unsigned int mask;
161 struct csky_opcode const *p;
162
163 p = g_opcodeP;
164 while (p->mnemonic)
165 {
0861f561
CQ
166 if (!(p->isa_flag16 & dis_info.isa)
167 && !(p->isa_flag32 & dis_info.isa))
531c73a3
CQ
168 {
169 p++;
170 continue;
171 }
172
b8891f8d
AJ
173 /* Get the opcode mask. */
174 for (i = 0; i < OP_TABLE_NUM; i++)
175 if (length == 2)
176 {
177 mask = csky_get_mask (&p->op16[i]);
178 if (mask != 0 && (inst & mask) == p->op16[i].opcode)
179 {
180 *pinfo = &p->op16[i];
181 g_opcodeP = p;
182 return p;
183 }
184 }
185 else if (length == 4)
186 {
187 mask = csky_get_mask (&p->op32[i]);
188 if (mask != 0
189 && ((unsigned long)(inst & mask)
190 == (unsigned long)p->op32[i].opcode))
191 {
192 *pinfo = &p->op32[i];
193 g_opcodeP = p;
194 return p;
195 }
196 }
197 p++;
198 }
199
200 return NULL;
201}
202
78933a4a 203static bool
b8891f8d
AJ
204is_extern_symbol (struct disassemble_info *info, int addr)
205{
206 unsigned int rel_count = 0;
207
208 if (info->section == NULL)
209 return 0;
210 if ((info->section->flags & SEC_RELOC) != 0) /* Fit .o file. */
211 {
212 struct reloc_cache_entry *pt = info->section->relocation;
213 for (; rel_count < info->section->reloc_count; rel_count++, pt++)
214 if ((long unsigned int)addr == pt->address)
78933a4a
AM
215 return true;
216 return false;
b8891f8d 217 }
78933a4a 218 return false;
b8891f8d
AJ
219}
220
221
222/* Suppress printing of mapping symbols emitted by the assembler to mark
223 the beginning of code and data sequences. */
224
78933a4a 225bool
b8891f8d
AJ
226csky_symbol_is_valid (asymbol *sym,
227 struct disassemble_info *info ATTRIBUTE_UNUSED)
228{
229 const char *name;
230
231 if (sym == NULL)
78933a4a 232 return false;
b8891f8d
AJ
233 name = bfd_asymbol_name (sym);
234 return name && *name != '$';
235}
236
237disassembler_ftype
238csky_get_disassembler (bfd *abfd)
239{
0861f561
CQ
240 obj_attribute *attr;
241 const char *sec_name = NULL;
16089f32 242 if (!abfd || bfd_get_flavour (abfd) != bfd_target_elf_flavour)
c568ac5f
AB
243 dis_info.isa = CSKY_DEFAULT_ISA;
244 else
0861f561 245 {
c568ac5f
AB
246 mach_flag = elf_elfheader (abfd)->e_flags;
247
248 sec_name = get_elf_backend_data (abfd)->obj_attrs_section;
249 /* Skip any input that hasn't attribute section.
250 This enables to link object files without attribute section with
251 any others. */
252 if (bfd_get_section_by_name (abfd, sec_name) != NULL)
253 {
254 attr = elf_known_obj_attributes_proc (abfd);
255 dis_info.isa = attr[Tag_CSKY_ISA_EXT_FLAGS].i;
256 dis_info.isa <<= 32;
257 dis_info.isa |= attr[Tag_CSKY_ISA_FLAGS].i;
258 }
259 else
260 dis_info.isa = CSKY_DEFAULT_ISA;
0861f561 261 }
0861f561
CQ
262
263 return print_insn_csky;
b8891f8d
AJ
264}
265
afdcafe8
CQ
266/* Parse the string of disassembler options. */
267static void
268parse_csky_dis_options (const char *opts_in)
269{
270 char *opts = xstrdup (opts_in);
271 char *opt = opts;
272 char *opt_end = opts;
273
274 for (; opt_end != NULL; opt = opt_end + 1)
275 {
276 if ((opt_end = strchr (opt, ',')) != NULL)
277 *opt_end = 0;
278 if (strcmp (opt, "abi-names") == 0)
279 using_abi = 1;
280 else
281 fprintf (stderr,
282 "unrecognized disassembler option: %s", opt);
283 }
284}
285
286/* Get general register name. */
287static const char *
288get_gr_name (int regno)
289{
0be2fe67 290 return csky_get_general_reg_name (mach_flag, regno, using_abi);
afdcafe8
CQ
291}
292
293/* Get control register name. */
294static const char *
295get_cr_name (unsigned int regno, int bank)
296{
0be2fe67 297 return csky_get_control_reg_name (mach_flag, bank, regno, using_abi);
afdcafe8
CQ
298}
299
b8891f8d
AJ
300static int
301csky_output_operand (char *str, struct operand const *oprnd,
302 CSKY_INST_TYPE inst, int reloc ATTRIBUTE_UNUSED)
303{
304 int ret = 0;;
305 int bit = 0;
306 int result = 0;
307 bfd_vma value;
308 int mask = oprnd->mask;
309 int max = 0;
310 char buf[128];
311
312 /* Get operand value with mask. */
313 value = inst & mask;
314 for (; mask; mask >>= 1, value >>=1)
315 if (mask & 0x1)
316 {
317 result |= ((value & 0x1) << bit);
318 max |= (1 << bit);
319 bit++;
320 }
321 value = result;
322
323 /* Here is general instructions that have no reloc. */
324 switch (oprnd->type)
325 {
326 case OPRND_TYPE_CTRLREG:
afdcafe8
CQ
327 if (IS_CSKY_V1(mach_flag) && ((value & 0x1f) == 0x1f))
328 return -1;
329 strcat (str, get_cr_name((value & 0x1f), (value >> 5)));
330 break;
b8891f8d
AJ
331 case OPRND_TYPE_DUMMY_REG:
332 mask = dis_info.opinfo->oprnd.oprnds[0].mask;
333 value = inst & mask;
334 for (; mask; mask >>= 1, value >>=1)
335 if (mask & 0x1)
336 {
337 result |= ((value & 0x1) << bit);
338 bit++;
339 }
340 value = result;
afdcafe8 341 strcat (str, get_gr_name (value));
b8891f8d
AJ
342 break;
343 case OPRND_TYPE_GREG0_7:
344 case OPRND_TYPE_GREG0_15:
345 case OPRND_TYPE_GREG16_31:
346 case OPRND_TYPE_REGnsplr:
347 case OPRND_TYPE_AREG:
afdcafe8 348 strcat (str, get_gr_name (value));
b8891f8d
AJ
349 break;
350 case OPRND_TYPE_CPREG:
afdcafe8
CQ
351 sprintf (buf, "cpr%d", (int)value);
352 strcat (str, buf);
b8891f8d
AJ
353 break;
354 case OPRND_TYPE_FREG:
355 sprintf (buf, "fr%d", (int)value);
356 strcat (str, buf);
357 break;
358 case OPRND_TYPE_VREG:
e2e82b11 359 dis_info.value = value;
b8891f8d
AJ
360 sprintf (buf, "vr%d", (int)value);
361 strcat (str, buf);
362 break;
363 case OPRND_TYPE_CPCREG:
afdcafe8
CQ
364 sprintf (buf, "cpcr%d", (int)value);
365 strcat (str, buf);
b8891f8d
AJ
366 break;
367 case OPRND_TYPE_CPIDX:
afdcafe8
CQ
368 sprintf (buf, "cp%d", (int)value);
369 strcat (str, buf);
b8891f8d
AJ
370 break;
371 case OPRND_TYPE_IMM2b_JMPIX:
372 value = (value + 2) << 3;
373 sprintf (buf, "%d", (int)value);
374 strcat (str, buf);
375 break;
376 case OPRND_TYPE_IMM_LDST:
377 case OPRND_TYPE_IMM_FLDST:
378 value <<= oprnd->shift;
379 sprintf (buf, "0x%x", (unsigned int)value);
380 strcat (str, buf);
381 break;
382 case OPRND_TYPE_IMM7b_LS2:
383 case OPRND_TYPE_IMM8b_LS2:
384 sprintf (buf, "%d", (int)(value << 2));
385 strcat (str, buf);
386 ret = 0;
387 break;
388 case OPRND_TYPE_IMM5b_BMASKI:
389 if ((value != 0) && (value > 31 || value < 8))
390 {
391 ret = -1;
392 break;
393 }
394 sprintf (buf, "%d", (int)value);
395 strcat (str, buf);
396 ret = 0;
397 break;
398 case OPRND_TYPE_IMM5b_1_31:
399 if (value > 31 || value < 1)
400 {
401 ret = -1;
402 break;
403 }
404 sprintf (buf, "%d", (int)value);
405 strcat (str, buf);
406 ret = 0;
407 break;
408 case OPRND_TYPE_IMM5b_7_31:
409 if (value > 31 || value < 7)
410 {
411 ret = -1;
412 break;
413 }
414 sprintf (buf, "%d", (int)value);
415 strcat (str, buf);
416 ret = 0;
417 break;
039dac29
CQ
418 case OPRND_TYPE_IMM5b_VSH:
419 {
420 char num[128];
421 value = ((value & 0x1) << 4) | (value >> 1);
422 sprintf (num, "%d", (int)value);
423 strcat (str, num);
424 ret = 0;
425 break;
426 }
b8891f8d
AJ
427 case OPRND_TYPE_MSB2SIZE:
428 case OPRND_TYPE_LSB2SIZE:
429 {
430 static int size;
431 if (oprnd->type == OPRND_TYPE_MSB2SIZE)
432 size = value;
433 else
434 {
435 str[strlen (str) - 2] = '\0';
436 sprintf (buf, "%d, %d", (int)(size + value), (int)value);
437 strcat (str, buf);
438 }
439 break;
440 }
441 case OPRND_TYPE_IMM1b:
442 case OPRND_TYPE_IMM2b:
443 case OPRND_TYPE_IMM4b:
444 case OPRND_TYPE_IMM5b:
afdcafe8 445 case OPRND_TYPE_IMM5b_LS:
b8891f8d
AJ
446 case OPRND_TYPE_IMM7b:
447 case OPRND_TYPE_IMM8b:
448 case OPRND_TYPE_IMM12b:
449 case OPRND_TYPE_IMM15b:
450 case OPRND_TYPE_IMM16b:
451 case OPRND_TYPE_IMM16b_MOVIH:
452 case OPRND_TYPE_IMM16b_ORI:
453 sprintf (buf, "%d", (int)value);
454 strcat (str, buf);
455 ret = 0;
456 break;
457 case OPRND_TYPE_OFF8b:
458 case OPRND_TYPE_OFF16b:
459 {
460 unsigned char ibytes[4];
461 int shift = oprnd->shift;
462 int status;
463 unsigned int mem_val;
464
465 dis_info.info->stop_vma = 0;
466
467 value = ((dis_info.mem + (value << shift)
468 + ((IS_CSKY_V1 (mach_flag)) ? 2 : 0))
469 & 0xfffffffc);
470 status = dis_info.info->read_memory_func (value, ibytes, 4,
471 dis_info.info);
472 if (status != 0)
473 {
474 dis_info.info->memory_error_func (status, dis_info.mem,
475 dis_info.info);
476 return -1;
477 }
478 mem_val = csky_chars_to_number (ibytes, 4);
479 /* Remove [] around literal value to match ABI syntax. */
480 sprintf (buf, "0x%X", mem_val);
481 strcat (str, buf);
482 /* For jmpi/jsri, we'll try to get a symbol for the target. */
483 if (dis_info.info->print_address_func && mem_val != 0)
484 {
485 dis_info.value = mem_val;
486 dis_info.need_output_symbol = 1;
487 }
488 else
489 {
490 sprintf (buf, "\t// from address pool at 0x%x",
491 (unsigned int)value);
492 strcat (str, buf);
493 }
494 break;
495 }
496 case OPRND_TYPE_BLOOP_OFF4b:
497 case OPRND_TYPE_BLOOP_OFF12b:
498 case OPRND_TYPE_OFF11b:
499 case OPRND_TYPE_OFF16b_LSL1:
500 case OPRND_TYPE_IMM_OFF18b:
501 case OPRND_TYPE_OFF26b:
502 {
503 int shift = oprnd->shift;
504 if (value & ((max >> 1) + 1))
505 value |= ~max;
506 if (is_extern_symbol (dis_info.info, dis_info.mem))
507 value = 0;
508 else if (IS_CSKY_V1 (mach_flag))
509 value = dis_info.mem + 2 + (value << shift);
510 else
511 value = dis_info.mem + (value << shift);
512 dis_info.need_output_symbol = 1;
513 dis_info.value= value;
514 sprintf (buf, "0x%x", (unsigned int)value);
515 strcat (str, buf);
516 break;
517 }
518 case OPRND_TYPE_CONSTANT:
519 case OPRND_TYPE_FCONSTANT:
520 {
521 int shift = oprnd->shift;
5cdf86d3 522 bfd_byte ibytes[8];
b8891f8d
AJ
523 int status;
524 bfd_vma addr;
525 int nbytes;
526
527 dis_info.info->stop_vma = 0;
528 value <<= shift;
529
530 if (IS_CSKY_V1 (mach_flag))
531 addr = (dis_info.mem + 2 + value) & 0xfffffffc;
532 else
533 addr = (dis_info.mem + value) & 0xfffffffc;
534
535 if (oprnd->type == OPRND_TYPE_FCONSTANT
536 && dis_info.opinfo->opcode != CSKYV2_INST_FLRW)
537 nbytes = 8;
538 else
539 nbytes = 4;
540
5cdf86d3 541 status = dis_info.info->read_memory_func (addr, ibytes,
b8891f8d
AJ
542 nbytes, dis_info.info);
543 if (status != 0)
544 /* Address out of bounds. -> lrw rx, [pc, 0ffset]. */
545 sprintf (buf, "[pc, %d]\t// from address pool at %x", (int)value,
546 (unsigned int)addr);
5cdf86d3 547 else if (oprnd->type == OPRND_TYPE_FCONSTANT)
b8891f8d
AJ
548 {
549 double f;
550
551 if (dis_info.opinfo->opcode == CSKYV2_INST_FLRW)
552 /* flrws. */
553 floatformat_to_double ((dis_info.info->endian == BFD_ENDIAN_BIG
554 ? &floatformat_ieee_single_big
555 : &floatformat_ieee_single_little),
556 ibytes, &f);
557 else
558 floatformat_to_double ((dis_info.info->endian == BFD_ENDIAN_BIG
559 ? &floatformat_ieee_double_big
560 : &floatformat_ieee_double_little),
561 ibytes, &f);
1374be23 562 sprintf (buf, "%.7g", f);
b8891f8d
AJ
563 }
564 else
565 {
5cdf86d3 566 dis_info.value = addr;
b8891f8d 567 dis_info.need_output_symbol = 1;
5cdf86d3
AM
568 value = csky_chars_to_number (ibytes, 4);
569 sprintf (buf, "0x%x", (unsigned int) value);
b8891f8d
AJ
570 }
571
572 strcat (str, buf);
573 break;
574 }
575 case OPRND_TYPE_ELRW_CONSTANT:
576 {
577 int shift = oprnd->shift;
578 char ibytes[4];
579 int status;
580 bfd_vma addr;
581 dis_info.info->stop_vma = 0;
582
583 value = 0x80 + ((~value) & 0x7f);
584
585 value = value << shift;
586 addr = (dis_info.mem + value) & 0xfffffffc;
587
588 status = dis_info.info->read_memory_func (addr, (bfd_byte *)ibytes,
589 4, dis_info.info);
590 if (status != 0)
591 /* Address out of bounds. -> lrw rx, [pc, 0ffset]. */
592 sprintf (buf, "[pc, %d]\t// from address pool at %x", (int) value,
593 (unsigned int)addr);
594 else
595 {
596 dis_info.value = addr;
597 value = csky_chars_to_number ((unsigned char *)ibytes, 4);
598 dis_info.need_output_symbol = 1;
599 sprintf (buf, "0x%x", (unsigned int)value);
600 }
601
602 strcat (str, buf);
603 break;
604 }
605 case OPRND_TYPE_SFLOAT:
606 case OPRND_TYPE_DFLOAT:
607 {
608 /* This is for fmovis/fmovid, which have an internal 13-bit
609 encoding that they convert to single/double precision
610 (respectively). We'll convert the 13-bit encoding to an IEEE
611 double and then to host double format to print it.
612 Sign bit: bit 20.
613 4-bit exponent: bits 19:16, biased by 11.
614 8-bit mantissa: split between 24:21 and 7:4. */
615 uint64_t imm4;
616 uint64_t imm8;
617 uint64_t dbnum;
618 unsigned char valbytes[8];
619 double fvalue;
620
621 imm4 = ((inst >> 16) & 0xf);
622 imm4 = (uint64_t)(1023 - (imm4 - 11)) << 52;
623
624 imm8 = (uint64_t)((inst >> 4) & 0xf) << 44;
625 imm8 |= (uint64_t)((inst >> 21) & 0xf) << 48;
626
627 dbnum = (uint64_t)((inst >> 20) & 1) << 63;
628 dbnum |= imm4 | imm8;
629
630 /* Do this a byte at a time so we don't have to
631 worry about the host's endianness. */
632 valbytes[0] = dbnum & 0xff;
633 valbytes[1] = (dbnum >> 8) & 0xff;
634 valbytes[2] = (dbnum >> 16) & 0xff;
635 valbytes[3] = (dbnum >> 24) & 0xff;
636 valbytes[4] = (dbnum >> 32) & 0xff;
637 valbytes[5] = (dbnum >> 40) & 0xff;
638 valbytes[6] = (dbnum >> 48) & 0xff;
639 valbytes[7] = (dbnum >> 56) & 0xff;
640
641 floatformat_to_double (&floatformat_ieee_double_little, valbytes,
642 &fvalue);
643
1374be23 644 sprintf (buf, "%.7g", fvalue);
b8891f8d 645 strcat (str, buf);
1feede9b
CQ
646 break;
647 }
648 case OPRND_TYPE_HFLOAT_FMOVI:
649 case OPRND_TYPE_SFLOAT_FMOVI:
650 {
651 int imm4;
652 int imm8;
653 imm4 = ((inst >> 16) & 0xf);
654 imm4 = (138 - imm4) << 23;
655
656 imm8 = ((inst >> 8) & 0x3);
657 imm8 |= (((inst >> 20) & 0x3f) << 2);
658 imm8 <<= 15;
659
660 value = ((inst >> 5) & 1) << 31;
661 value |= imm4 | imm8;
662
663 imm4 = 138 - (imm4 >> 23);
664 imm8 >>= 15;
665 if ((inst >> 5) & 1)
666 {
667 imm8 = 0 - imm8;
668 }
669
670 float f = 0;
671 memcpy (&f, &value, sizeof (float));
1374be23 672 sprintf (buf, "%.7g\t// imm9:%4d, imm4:%2d", f, imm8, imm4);
23bef3fe 673 strcat (str, buf);
525a0aa3 674
1feede9b
CQ
675 break;
676 }
677
678 case OPRND_TYPE_DFLOAT_FMOVI:
679 {
680 uint64_t imm4;
681 uint64_t imm8;
682 uint64_t dvalue;
683 imm4 = ((inst >> 16) & 0xf);
684 imm4 = (1034 - imm4) << 52;
685
686 imm8 = ((inst >> 8) & 0x3);
687 imm8 |= (((inst >> 20) & 0x3f) << 2);
688 imm8 <<= 44;
689
690 dvalue = (((uint64_t)inst >> 5) & 1) << 63;
691 dvalue |= imm4 | imm8;
692
693 imm4 = 1034 - (imm4 >> 52);
694 imm8 >>= 44;
695 if (inst >> 5)
696 {
697 imm8 = 0 - imm8;
698 }
699 double d = 0;
700 memcpy (&d, &dvalue, sizeof (double));
1374be23 701 sprintf (buf, "%.7g\t// imm9:%4ld, imm4:%2ld", d, (long) imm8, (long) imm4);
23bef3fe 702 strcat (str, buf);
525a0aa3 703
b8891f8d
AJ
704 break;
705 }
706 case OPRND_TYPE_LABEL_WITH_BRACKET:
707 sprintf (buf, "[0x%x]", (unsigned int)value);
708 strcat (str, buf);
709 strcat (str, "\t// the offset is based on .data");
710 break;
711 case OPRND_TYPE_OIMM3b:
712 case OPRND_TYPE_OIMM4b:
713 case OPRND_TYPE_OIMM5b:
714 case OPRND_TYPE_OIMM5b_IDLY:
715 case OPRND_TYPE_OIMM8b:
716 case OPRND_TYPE_OIMM12b:
717 case OPRND_TYPE_OIMM16b:
718 case OPRND_TYPE_OIMM18b:
719 value += 1;
720 sprintf (buf, "%d", (int)value);
721 strcat (str, buf);
722 break;
723 case OPRND_TYPE_OIMM5b_BMASKI:
724 if (value > 32 || value < 16)
725 {
726 ret = -1;
727 break;
728 }
729 sprintf (buf, "%d", (int)(value + 1));
730 strcat (str, buf);
731 ret = 0;
732 break;
733 case OPRND_TYPE_FREGLIST_DASH:
734 if (IS_CSKY_V2 (mach_flag))
735 {
1feede9b
CQ
736 int vrx = 0;
737 int vry = 0;
738 if (dis_info.isa & CSKY_ISA_FLOAT_7E60
739 && (strstr (str, "fstm") != NULL
740 || strstr (str, "fldm") != NULL))
741 {
742 vrx = value & 0x1f;
743 vry = vrx + (value >> 5);
744 }
745 else
746 {
747 vrx = value & 0xf;
748 vry = vrx + (value >> 4);
749 }
b8891f8d
AJ
750 sprintf (buf, "fr%d-fr%d", vrx, vry);
751 strcat (str, buf);
752 }
753 break;
754 case OPRND_TYPE_REGLIST_DASH:
755 if (IS_CSKY_V1 (mach_flag))
756 {
afdcafe8
CQ
757 sprintf (buf, "%s-r15", get_gr_name (value));
758 strcat (str, buf);
b8891f8d
AJ
759 }
760 else
761 {
afdcafe8
CQ
762 if ((value & 0x1f) + (value >> 5) > 31)
763 {
764 ret = -1;
765 break;
766 }
767 strcat (str, get_gr_name ((value >> 5)));
b8891f8d 768 strcat (str, "-");
afdcafe8 769 strcat (str, get_gr_name ((value & 0x1f) + (value >> 5)));
b8891f8d
AJ
770 }
771 break;
772 case OPRND_TYPE_PSR_BITS_LIST:
773 {
774 struct psrbit const *bits;
78933a4a 775 int first_oprnd = true;
b8891f8d
AJ
776 int i = 0;
777 if (IS_CSKY_V1 (mach_flag))
778 {
779 if (value == 0)
780 {
781 strcat (str, "af");
782 break;
783 }
784 bits = cskyv1_psr_bits;
785 }
786 else
787 bits = cskyv2_psr_bits;
788 while (value != 0 && bits[i].name != NULL)
789 {
790 if (value & bits[i].value)
791 {
792 if (!first_oprnd)
793 strcat (str, ", ");
794 strcat (str, bits[i].name);
795 value &= ~bits[i].value;
78933a4a 796 first_oprnd = false;
b8891f8d
AJ
797 }
798 i++;
799 }
800 break;
801 }
802 case OPRND_TYPE_REGbsp:
803 if (IS_CSKY_V1 (mach_flag))
afdcafe8 804 sprintf(buf, "(%s)", get_gr_name (0));
b8891f8d 805 else
afdcafe8
CQ
806 sprintf(buf, "(%s)", get_gr_name (14));
807 strcat (str, buf);
b8891f8d
AJ
808 break;
809 case OPRND_TYPE_REGsp:
810 if (IS_CSKY_V1 (mach_flag))
afdcafe8 811 strcat (str, get_gr_name (0));
b8891f8d 812 else
afdcafe8 813 strcat (str, get_gr_name (14));
b8891f8d
AJ
814 break;
815 case OPRND_TYPE_REGnr4_r7:
816 case OPRND_TYPE_AREG_WITH_BRACKET:
afdcafe8
CQ
817 strcat (str, "(");
818 strcat (str, get_gr_name (value));
819 strcat (str, ")");
b8891f8d
AJ
820 break;
821 case OPRND_TYPE_AREG_WITH_LSHIFT:
afdcafe8 822 strcat (str, get_gr_name (value >> 5));
b8891f8d
AJ
823 strcat (str, " << ");
824 if ((value & 0x1f) == 0x1)
825 strcat (str, "0");
826 else if ((value & 0x1f) == 0x2)
827 strcat (str, "1");
828 else if ((value & 0x1f) == 0x4)
829 strcat (str, "2");
830 else if ((value & 0x1f) == 0x8)
831 strcat (str, "3");
832 break;
833 case OPRND_TYPE_AREG_WITH_LSHIFT_FPU:
afdcafe8 834 strcat (str, get_gr_name (value >> 2));
b8891f8d
AJ
835 strcat (str, " << ");
836 if ((value & 0x3) == 0x0)
837 strcat (str, "0");
838 else if ((value & 0x3) == 0x1)
839 strcat (str, "1");
840 else if ((value & 0x3) == 0x2)
841 strcat (str, "2");
842 else if ((value & 0x3) == 0x3)
843 strcat (str, "3");
844 break;
039dac29 845 case OPRND_TYPE_VREG_WITH_INDEX:
b8891f8d
AJ
846 {
847 unsigned freg_val = value & 0xf;
848 unsigned index_val = (value >> 4) & 0xf;
849 sprintf (buf, "vr%d[%d]", freg_val, index_val);
850 strcat(str, buf);
851 break;
852 }
039dac29
CQ
853 case OPRND_TYPE_FREG_WITH_INDEX:
854 {
855 unsigned freg_val = value & 0xf;
856 unsigned index_val = (value >> 4) & 0xf;
857 sprintf (buf, "fr%d[%d]", freg_val, index_val);
858 strcat(str, buf);
859 break;
860 }
b8891f8d
AJ
861 case OPRND_TYPE_REGr4_r7:
862 if (IS_CSKY_V1 (mach_flag))
011a045a
AB
863 {
864 sprintf (buf, "%s-%s", get_gr_name (4), get_gr_name (7));
865 strcat (str, buf);
866 }
b8891f8d
AJ
867 break;
868 case OPRND_TYPE_CONST1:
869 strcat (str, "1");
870 break;
871 case OPRND_TYPE_REG_r1a:
872 case OPRND_TYPE_REG_r1b:
afdcafe8 873 strcat (str, get_gr_name (1));
b8891f8d
AJ
874 break;
875 case OPRND_TYPE_REG_r28:
afdcafe8 876 strcat (str, get_gr_name (28));
b8891f8d
AJ
877 break;
878 case OPRND_TYPE_REGLIST_DASH_COMMA:
879 /* 16-bit reglist. */
880 if (value & 0xf)
881 {
afdcafe8 882 strcat (str, get_gr_name (4));
b8891f8d
AJ
883 if ((value & 0xf) > 1)
884 {
885 strcat (str, "-");
afdcafe8 886 strcat (str, get_gr_name ((value & 0xf) + 3));
b8891f8d
AJ
887 }
888 if (value & ~0xf)
889 strcat (str, ", ");
890 }
891 if (value & 0x10)
892 {
893 /* r15. */
afdcafe8 894 strcat (str, get_gr_name (15));
b8891f8d
AJ
895 if (value & ~0x1f)
896 strcat (str, ", ");
897 }
898 if (dis_info.opinfo->oprnd.oprnds[0].mask != OPRND_MASK_0_4)
899 {
900 /* 32bits reglist. */
901 value >>= 5;
902 if (value & 0x3)
903 {
afdcafe8 904 strcat (str, get_gr_name (16));
b8891f8d
AJ
905 if ((value & 0x7) > 1)
906 {
907 strcat (str, "-");
afdcafe8 908 strcat (str, get_gr_name ((value & 0x7) + 15));
b8891f8d
AJ
909 }
910 if (value & ~0x7)
911 strcat (str, ", ");
912 }
913 if (value & 0x8)
914 /* r15. */
afdcafe8 915 strcat (str, get_gr_name (28));
b8891f8d
AJ
916 }
917 break;
918 case OPRND_TYPE_UNCOND10b:
919 case OPRND_TYPE_UNCOND16b:
920 case OPRND_TYPE_COND10b:
921 case OPRND_TYPE_COND16b:
922 {
923 int shift = oprnd->shift;
924
925 if (value & ((max >> 1) + 1))
926 value |= ~max;
927 if (is_extern_symbol (dis_info.info, dis_info.mem))
928 value = 0;
929 else
930 value = dis_info.mem + (value << shift);
931 sprintf (buf, "0x%x", (unsigned int)value);
932 strcat (str, buf);
933 dis_info.need_output_symbol = 1;
934 dis_info.value = value;
935 }
936 break;
937
938 default:
939 ret = -1;
940 break;
941 }
942 return ret;
943}
944
945static int
946csky_print_operand (char *str, struct operand const *oprnd,
947 CSKY_INST_TYPE inst, int reloc)
948{
949 int ret = -1;
950 char *lc = "";
951 char *rc = "";
952 if (oprnd->mask == HAS_SUB_OPERAND)
953 {
954 struct soperand *sop = (struct soperand *)oprnd;
955 if (oprnd->type == OPRND_TYPE_BRACKET)
956 {
957 lc = "(";
958 rc = ")";
959 }
960 else if (oprnd->type == OPRND_TYPE_ABRACKET)
961 {
962 lc = "<";
963 rc = ">";
964 }
965 strcat (str, lc);
966 ret = csky_print_operand (str, &sop->subs[0], inst, reloc);
967 if (ret)
968 return ret;
969 strcat (str, ", ");
970 ret = csky_print_operand (str, &sop->subs[1], inst, reloc);
971 strcat (str, rc);
972 return ret;
973 }
974 return csky_output_operand (str, oprnd, inst, reloc);
975}
976
977static int
978csky_print_operands (char *str, struct csky_opcode_info const *pinfo,
979 struct disassemble_info *info, CSKY_INST_TYPE inst,
980 int reloc)
981{
982 int i = 0;
983 int ret = 0;
984 if (pinfo->operand_num)
985 strcat (str, " \t");
986 if (pinfo->operand_num == -1)
987 {
988 ret = csky_print_operand (str, &pinfo->oprnd.oprnds[i], inst, reloc);
989 if (ret)
990 return ret;
991 }
992 else
993 for (; i < pinfo->operand_num; i++)
994 {
995 if (i != 0)
996 strcat (str, ", ");
997 ret = csky_print_operand (str, &pinfo->oprnd.oprnds[i], inst, reloc);
998 if (ret)
999 return ret;
1000 }
1001 info->fprintf_func (info->stream, "%s", str);
1002 if (dis_info.need_output_symbol)
1003 {
1004 info->fprintf_func (info->stream, "\t// ");
1005 info->print_address_func (dis_info.value, dis_info.info);
1006 }
1007 return 0;
1008}
1009
1010static void
1011number_to_chars_littleendian (char *buf, CSKY_INST_TYPE val, int n)
1012{
1013 if (n <= 0)
1014 abort ();
1015 while (n--)
1016 {
1017 *buf++ = val & 0xff;
1018 val >>= 8;
1019 }
1020}
1021
1022#define CSKY_READ_DATA() \
1023{ \
1024 status = info->read_memory_func (memaddr, buf, 2, info); \
1025 if (status) \
1026 { \
1027 info->memory_error_func (status, memaddr, info); \
1028 return -1; \
1029 } \
1030 if (info->endian == BFD_ENDIAN_BIG) \
1031 inst |= (buf[0] << 8) | buf[1]; \
1032 else if (info->endian == BFD_ENDIAN_LITTLE) \
1033 inst |= (buf[1] << 8) | buf[0]; \
1034 else \
1035 abort(); \
1036 info->bytes_per_chunk += 2; \
1037 memaddr += 2; \
1038}
1039
1040int
1041print_insn_csky (bfd_vma memaddr, struct disassemble_info *info)
1042{
1043 unsigned char buf[4];
1044 CSKY_INST_TYPE inst = 0;
1045 int status;
1046 char str[256];
caf4537a 1047 unsigned long given;
78933a4a 1048 int is_data = false;
b8891f8d
AJ
1049 void (*printer) (bfd_vma, struct disassemble_info *, long);
1050 unsigned int size = 4;
1051
1052 memset (str, 0, sizeof (str));
1053 info->bytes_per_chunk = 0;
1054 info->bytes_per_chunk = 0;
1055 dis_info.mem = memaddr;
1056 dis_info.info = info;
1057 dis_info.need_output_symbol = 0;
afdcafe8
CQ
1058
1059 if (info->disassembler_options)
1060 {
1061 parse_csky_dis_options (info->disassembler_options);
1062 info->disassembler_options = NULL;
1063 }
1064
b8891f8d
AJ
1065 if (mach_flag != INIT_MACH_FLAG && mach_flag != BINARY_MACH_FLAG)
1066 info->mach = mach_flag;
1067 else if (mach_flag == INIT_MACH_FLAG)
0861f561
CQ
1068 {
1069 mach_flag = info->mach;
1070 dis_info.isa = CSKY_DEFAULT_ISA;
1071 }
b8891f8d
AJ
1072
1073 if (mach_flag == BINARY_MACH_FLAG && info->endian == BFD_ENDIAN_UNKNOWN)
0861f561
CQ
1074 {
1075 info->endian = BFD_ENDIAN_LITTLE;
1076 dis_info.isa = CSKY_DEFAULT_ISA;
1077 }
b8891f8d
AJ
1078
1079 /* First check the full symtab for a mapping symbol, even if there
1080 are no usable non-mapping symbols for this address. */
1081 if (info->symtab_size != 0
1082 && bfd_asymbol_flavour (*info->symtab) == bfd_target_elf_flavour)
1083 {
1084 bfd_vma addr;
1085 int n;
1086 int last_sym = -1;
1087 enum sym_type type = CUR_TEXT;
1088
1089 if (memaddr <= last_map_addr)
1090 last_map_sym = -1;
1091 /* Start scanning at the start of the function, or wherever
1092 we finished last time. */
1093 n = 0;
1094 if (n < last_map_sym)
1095 n = last_map_sym;
1096
1097 /* Scan up to the location being disassembled. */
1098 for (; n < info->symtab_size; n++)
1099 {
1100 addr = bfd_asymbol_value (info->symtab[n]);
1101 if (addr > memaddr)
1102 break;
1103 if ((info->section == NULL
1104 || info->section == info->symtab[n]->section)
1105 && get_sym_code_type (info, n, &type))
1106 last_sym = n;
1107 }
1108 last_map_sym = last_sym;
1109 last_type = type;
1110 is_data = (last_type == CUR_DATA);
1111 if (is_data)
1112 {
1113 size = 4 - ( memaddr & 3);
1114 for (n = last_sym + 1; n < info->symtab_size; n++)
1115 {
1116 addr = bfd_asymbol_value (info->symtab[n]);
1117 if (addr > memaddr)
1118 {
1119 if (addr - memaddr < size)
1120 size = addr - memaddr;
1121 break;
1122 }
1123 }
1124 /* If the next symbol is after three bytes, we need to
1125 print only part of the data, so that we can use either
1126 .byte or .short. */
1127 if (size == 3)
1128 size = (memaddr & 1) ? 1 : 2;
1129 }
1130 }
1131 info->bytes_per_line = 4;
1132
1133 if (is_data)
1134 {
1135 int i;
1136
1137 /* Size was already set above. */
1138 info->bytes_per_chunk = size;
1139 printer = print_insn_data;
1140
1141 status = info->read_memory_func (memaddr, (bfd_byte *) buf, size, info);
1142 given = 0;
1143 if (info->endian == BFD_ENDIAN_LITTLE)
1144 for (i = size - 1; i >= 0; i--)
1145 given = buf[i] | (given << 8);
1146 else
1147 for (i = 0; i < (int) size; i++)
1148 given = buf[i] | (given << 8);
1149
1150 printer (memaddr, info, given);
1151 return info->bytes_per_chunk;
1152 }
1153
1154 /* Handle instructions. */
1155 CSKY_READ_DATA();
1156 if ((inst & 0xc000) == 0xc000 && IS_CSKY_V2 (mach_flag))
1157 {
1158 /* It's a 32-bit instruction. */
1159 inst <<= 16;
1160 CSKY_READ_DATA();
1161 if (info->buffer && (info->endian == BFD_ENDIAN_LITTLE))
1162 {
1163 char* src = (char *)(info->buffer
1164 + ((memaddr - 4 - info->buffer_vma)
1165 * info->octets_per_byte));
1166 if (info->endian == BFD_ENDIAN_LITTLE)
1167 number_to_chars_littleendian (src, inst, 4);
1168 }
1169 }
1170
1171 if (IS_CSKY_V1 (mach_flag))
1172 g_opcodeP = csky_v1_opcodes;
1173 else
1174 g_opcodeP = csky_v2_opcodes;
1175
1176 do
1177 {
1178 struct csky_opcode const *op;
1179 struct csky_opcode_info const *pinfo = NULL;
1180 int reloc;
1181
1182 memset (str, 0, sizeof (str));
1183 op = csky_find_inst_info (&pinfo, inst, info->bytes_per_chunk);
1184 if (!op)
1185 {
1186 if (IS_CSKY_V1 (mach_flag))
1187 info->fprintf_func (info->stream, ".short: 0x%04x",
1188 (unsigned short)inst);
1189 else
1190 info->fprintf_func (info->stream, ".long: 0x%08x",
1191 (unsigned int)inst);
1192 return info->bytes_per_chunk;
1193 }
1194
1195 if (info->bytes_per_chunk == 2)
1196 reloc = op->reloc16;
1197 else
1198 reloc = op->reloc32;
1199 dis_info.opinfo = pinfo;
1200 strcat (str, op->mnemonic);
1201
1202 if (csky_print_operands (str, pinfo, info, inst, reloc))
1203 g_opcodeP++;
1204 else
1205 break;
1206 } while (1);
1207
1208 return info->bytes_per_chunk;
1209}