1ede78133Schristos /* DO NOT EDIT! -*- buffer-read-only: t -*- vi:set ro: */
275fd0b74Schristos /* Disassembler interface for targets using CGEN. -*- C -*-
375fd0b74Schristos CGEN: Cpu tools GENerator
475fd0b74Schristos
575fd0b74Schristos THIS FILE IS MACHINE GENERATED WITH CGEN.
675fd0b74Schristos - the resultant file is machine generated, cgen-dis.in isn't
775fd0b74Schristos
8*e992f068Schristos Copyright (C) 1996-2022 Free Software Foundation, Inc.
975fd0b74Schristos
1075fd0b74Schristos This file is part of libopcodes.
1175fd0b74Schristos
1275fd0b74Schristos This library is free software; you can redistribute it and/or modify
1375fd0b74Schristos it under the terms of the GNU General Public License as published by
1475fd0b74Schristos the Free Software Foundation; either version 3, or (at your option)
1575fd0b74Schristos any later version.
1675fd0b74Schristos
1775fd0b74Schristos It is distributed in the hope that it will be useful, but WITHOUT
1875fd0b74Schristos ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1975fd0b74Schristos or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
2075fd0b74Schristos License for more details.
2175fd0b74Schristos
2275fd0b74Schristos You should have received a copy of the GNU General Public License
2375fd0b74Schristos along with this program; if not, write to the Free Software Foundation, Inc.,
2475fd0b74Schristos 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
2575fd0b74Schristos
2675fd0b74Schristos /* ??? Eventually more and more of this stuff can go to cpu-independent files.
2775fd0b74Schristos Keep that in mind. */
2875fd0b74Schristos
2975fd0b74Schristos #include "sysdep.h"
3075fd0b74Schristos #include <stdio.h>
3175fd0b74Schristos #include "ansidecl.h"
32ede78133Schristos #include "disassemble.h"
3375fd0b74Schristos #include "bfd.h"
3475fd0b74Schristos #include "symcat.h"
3575fd0b74Schristos #include "libiberty.h"
3675fd0b74Schristos #include "epiphany-desc.h"
3775fd0b74Schristos #include "epiphany-opc.h"
3875fd0b74Schristos #include "opintl.h"
3975fd0b74Schristos
4075fd0b74Schristos /* Default text to print if an instruction isn't recognized. */
4175fd0b74Schristos #define UNKNOWN_INSN_MSG _("*unknown*")
4275fd0b74Schristos
4375fd0b74Schristos static void print_normal
4475fd0b74Schristos (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
4575fd0b74Schristos static void print_address
4675fd0b74Schristos (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED;
4775fd0b74Schristos static void print_keyword
4875fd0b74Schristos (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED;
4975fd0b74Schristos static void print_insn_normal
5075fd0b74Schristos (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
5175fd0b74Schristos static int print_insn
5275fd0b74Schristos (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, unsigned);
5375fd0b74Schristos static int default_print_insn
5475fd0b74Schristos (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED;
5575fd0b74Schristos static int read_insn
5675fd0b74Schristos (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *,
5775fd0b74Schristos unsigned long *);
5875fd0b74Schristos
5975fd0b74Schristos /* -- disassembler routines inserted here. */
6075fd0b74Schristos
6175fd0b74Schristos /* -- dis.c */
6275fd0b74Schristos
6375fd0b74Schristos #define CGEN_PRINT_INSN epiphany_print_insn
6475fd0b74Schristos
6575fd0b74Schristos static int
epiphany_print_insn(CGEN_CPU_DESC cd,bfd_vma pc,disassemble_info * info)6675fd0b74Schristos epiphany_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
6775fd0b74Schristos {
6875fd0b74Schristos bfd_byte buf[CGEN_MAX_INSN_SIZE];
6975fd0b74Schristos int buflen;
7075fd0b74Schristos int status;
7175fd0b74Schristos
7275fd0b74Schristos info->bytes_per_chunk = 2;
7375fd0b74Schristos info->bytes_per_line = 4;
7475fd0b74Schristos
7575fd0b74Schristos /* Attempt to read the base part of the insn. */
7675fd0b74Schristos buflen = cd->base_insn_bitsize / 8;
7775fd0b74Schristos status = (*info->read_memory_func) (pc, buf, buflen, info);
7875fd0b74Schristos
7975fd0b74Schristos /* Try again with the minimum part, if min < base. */
8075fd0b74Schristos if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
8175fd0b74Schristos {
8275fd0b74Schristos buflen = cd->min_insn_bitsize / 8;
8375fd0b74Schristos status = (*info->read_memory_func) (pc, buf, buflen, info);
8475fd0b74Schristos }
8575fd0b74Schristos
8675fd0b74Schristos if (status != 0)
8775fd0b74Schristos {
8875fd0b74Schristos (*info->memory_error_func) (status, pc, info);
8975fd0b74Schristos return -1;
9075fd0b74Schristos }
9175fd0b74Schristos
9275fd0b74Schristos return print_insn (cd, pc, info, buf, buflen);
9375fd0b74Schristos }
9475fd0b74Schristos
9575fd0b74Schristos
9675fd0b74Schristos static void
print_postindex(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,long value,unsigned int attrs ATTRIBUTE_UNUSED,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)9775fd0b74Schristos print_postindex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
9875fd0b74Schristos void * dis_info,
9975fd0b74Schristos long value,
10075fd0b74Schristos unsigned int attrs ATTRIBUTE_UNUSED,
10175fd0b74Schristos bfd_vma pc ATTRIBUTE_UNUSED,
10275fd0b74Schristos int length ATTRIBUTE_UNUSED)
10375fd0b74Schristos {
10475fd0b74Schristos disassemble_info *info = (disassemble_info *) dis_info;
10575fd0b74Schristos (*info->fprintf_func) (info->stream, value ? "-" : "+");
10675fd0b74Schristos }
10775fd0b74Schristos
10875fd0b74Schristos static void
print_simm_not_reg(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,long value,unsigned int attrs ATTRIBUTE_UNUSED,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)10975fd0b74Schristos print_simm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
11075fd0b74Schristos void * dis_info,
11175fd0b74Schristos long value,
11275fd0b74Schristos unsigned int attrs ATTRIBUTE_UNUSED,
11375fd0b74Schristos bfd_vma pc ATTRIBUTE_UNUSED,
11475fd0b74Schristos int length ATTRIBUTE_UNUSED)
11575fd0b74Schristos {
11675fd0b74Schristos print_address (cd, dis_info, value, attrs, pc, length);
11775fd0b74Schristos }
11875fd0b74Schristos
11975fd0b74Schristos static void
print_uimm_not_reg(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,unsigned long value,unsigned int attrs ATTRIBUTE_UNUSED,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)12075fd0b74Schristos print_uimm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
12175fd0b74Schristos void * dis_info,
12275fd0b74Schristos unsigned long value,
12375fd0b74Schristos unsigned int attrs ATTRIBUTE_UNUSED,
12475fd0b74Schristos bfd_vma pc ATTRIBUTE_UNUSED,
12575fd0b74Schristos int length ATTRIBUTE_UNUSED)
12675fd0b74Schristos {
12775fd0b74Schristos disassemble_info *info = (disassemble_info *)dis_info;
12875fd0b74Schristos
12975fd0b74Schristos if (value & 0x800)
13075fd0b74Schristos (*info->fprintf_func) (info->stream, "-");
13175fd0b74Schristos
13275fd0b74Schristos value &= 0x7ff;
13375fd0b74Schristos print_address (cd, dis_info, value, attrs, pc, length);
13475fd0b74Schristos }
13575fd0b74Schristos
13675fd0b74Schristos
13775fd0b74Schristos /* -- */
13875fd0b74Schristos
13975fd0b74Schristos void epiphany_cgen_print_operand
140*e992f068Schristos (CGEN_CPU_DESC, int, void *, CGEN_FIELDS *, void const *, bfd_vma, int);
14175fd0b74Schristos
14275fd0b74Schristos /* Main entry point for printing operands.
14375fd0b74Schristos XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
14475fd0b74Schristos of dis-asm.h on cgen.h.
14575fd0b74Schristos
14675fd0b74Schristos This function is basically just a big switch statement. Earlier versions
14775fd0b74Schristos used tables to look up the function to use, but
14875fd0b74Schristos - if the table contains both assembler and disassembler functions then
14975fd0b74Schristos the disassembler contains much of the assembler and vice-versa,
15075fd0b74Schristos - there's a lot of inlining possibilities as things grow,
15175fd0b74Schristos - using a switch statement avoids the function call overhead.
15275fd0b74Schristos
15375fd0b74Schristos This function could be moved into `print_insn_normal', but keeping it
15475fd0b74Schristos separate makes clear the interface between `print_insn_normal' and each of
15575fd0b74Schristos the handlers. */
15675fd0b74Schristos
15775fd0b74Schristos void
epiphany_cgen_print_operand(CGEN_CPU_DESC cd,int opindex,void * xinfo,CGEN_FIELDS * fields,void const * attrs ATTRIBUTE_UNUSED,bfd_vma pc,int length)15875fd0b74Schristos epiphany_cgen_print_operand (CGEN_CPU_DESC cd,
15975fd0b74Schristos int opindex,
16075fd0b74Schristos void * xinfo,
16175fd0b74Schristos CGEN_FIELDS *fields,
16275fd0b74Schristos void const *attrs ATTRIBUTE_UNUSED,
16375fd0b74Schristos bfd_vma pc,
16475fd0b74Schristos int length)
16575fd0b74Schristos {
16675fd0b74Schristos disassemble_info *info = (disassemble_info *) xinfo;
16775fd0b74Schristos
16875fd0b74Schristos switch (opindex)
16975fd0b74Schristos {
17075fd0b74Schristos case EPIPHANY_OPERAND_DIRECTION :
17175fd0b74Schristos print_postindex (cd, info, fields->f_addsubx, 0, pc, length);
17275fd0b74Schristos break;
17375fd0b74Schristos case EPIPHANY_OPERAND_DISP11 :
17475fd0b74Schristos print_uimm_not_reg (cd, info, fields->f_disp11, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
17575fd0b74Schristos break;
17675fd0b74Schristos case EPIPHANY_OPERAND_DISP3 :
17775fd0b74Schristos print_normal (cd, info, fields->f_disp3, 0, pc, length);
17875fd0b74Schristos break;
17975fd0b74Schristos case EPIPHANY_OPERAND_DPMI :
18075fd0b74Schristos print_postindex (cd, info, fields->f_subd, 0, pc, length);
18175fd0b74Schristos break;
18275fd0b74Schristos case EPIPHANY_OPERAND_FRD :
18375fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rd, 0);
18475fd0b74Schristos break;
18575fd0b74Schristos case EPIPHANY_OPERAND_FRD6 :
18675fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rd6, 0|(1<<CGEN_OPERAND_VIRTUAL));
18775fd0b74Schristos break;
18875fd0b74Schristos case EPIPHANY_OPERAND_FRM :
18975fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rm, 0);
19075fd0b74Schristos break;
19175fd0b74Schristos case EPIPHANY_OPERAND_FRM6 :
19275fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rm6, 0|(1<<CGEN_OPERAND_VIRTUAL));
19375fd0b74Schristos break;
19475fd0b74Schristos case EPIPHANY_OPERAND_FRN :
19575fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rn, 0);
19675fd0b74Schristos break;
19775fd0b74Schristos case EPIPHANY_OPERAND_FRN6 :
19875fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rn6, 0|(1<<CGEN_OPERAND_VIRTUAL));
19975fd0b74Schristos break;
20075fd0b74Schristos case EPIPHANY_OPERAND_IMM16 :
20175fd0b74Schristos print_address (cd, info, fields->f_imm16, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
20275fd0b74Schristos break;
20375fd0b74Schristos case EPIPHANY_OPERAND_IMM8 :
20475fd0b74Schristos print_address (cd, info, fields->f_imm8, 0|(1<<CGEN_OPERAND_RELAX), pc, length);
20575fd0b74Schristos break;
20675fd0b74Schristos case EPIPHANY_OPERAND_RD :
20775fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rd, 0);
20875fd0b74Schristos break;
20975fd0b74Schristos case EPIPHANY_OPERAND_RD6 :
21075fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rd6, 0|(1<<CGEN_OPERAND_VIRTUAL));
21175fd0b74Schristos break;
21275fd0b74Schristos case EPIPHANY_OPERAND_RM :
21375fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rm, 0);
21475fd0b74Schristos break;
21575fd0b74Schristos case EPIPHANY_OPERAND_RM6 :
21675fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rm6, 0|(1<<CGEN_OPERAND_VIRTUAL));
21775fd0b74Schristos break;
21875fd0b74Schristos case EPIPHANY_OPERAND_RN :
21975fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rn, 0);
22075fd0b74Schristos break;
22175fd0b74Schristos case EPIPHANY_OPERAND_RN6 :
22275fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rn6, 0|(1<<CGEN_OPERAND_VIRTUAL));
22375fd0b74Schristos break;
22475fd0b74Schristos case EPIPHANY_OPERAND_SD :
22575fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_cr_names, fields->f_sd, 0);
22675fd0b74Schristos break;
22775fd0b74Schristos case EPIPHANY_OPERAND_SD6 :
22875fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_cr_names, fields->f_sd6, 0|(1<<CGEN_OPERAND_VIRTUAL));
22975fd0b74Schristos break;
23075fd0b74Schristos case EPIPHANY_OPERAND_SDDMA :
23175fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_crdma_names, fields->f_sd6, 0|(1<<CGEN_OPERAND_VIRTUAL));
23275fd0b74Schristos break;
23375fd0b74Schristos case EPIPHANY_OPERAND_SDMEM :
23475fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_crmem_names, fields->f_sd6, 0|(1<<CGEN_OPERAND_VIRTUAL));
23575fd0b74Schristos break;
23675fd0b74Schristos case EPIPHANY_OPERAND_SDMESH :
23775fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_crmesh_names, fields->f_sd6, 0|(1<<CGEN_OPERAND_VIRTUAL));
23875fd0b74Schristos break;
23975fd0b74Schristos case EPIPHANY_OPERAND_SHIFT :
24075fd0b74Schristos print_normal (cd, info, fields->f_shift, 0, pc, length);
24175fd0b74Schristos break;
24275fd0b74Schristos case EPIPHANY_OPERAND_SIMM11 :
24375fd0b74Schristos print_simm_not_reg (cd, info, fields->f_sdisp11, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
24475fd0b74Schristos break;
24575fd0b74Schristos case EPIPHANY_OPERAND_SIMM24 :
24675fd0b74Schristos print_address (cd, info, fields->f_simm24, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
24775fd0b74Schristos break;
24875fd0b74Schristos case EPIPHANY_OPERAND_SIMM3 :
24975fd0b74Schristos print_simm_not_reg (cd, info, fields->f_sdisp3, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_RELAX), pc, length);
25075fd0b74Schristos break;
25175fd0b74Schristos case EPIPHANY_OPERAND_SIMM8 :
25275fd0b74Schristos print_address (cd, info, fields->f_simm8, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
25375fd0b74Schristos break;
25475fd0b74Schristos case EPIPHANY_OPERAND_SN :
25575fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_cr_names, fields->f_sn, 0);
25675fd0b74Schristos break;
25775fd0b74Schristos case EPIPHANY_OPERAND_SN6 :
25875fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_cr_names, fields->f_sn6, 0|(1<<CGEN_OPERAND_VIRTUAL));
25975fd0b74Schristos break;
26075fd0b74Schristos case EPIPHANY_OPERAND_SNDMA :
26175fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_crdma_names, fields->f_sn6, 0|(1<<CGEN_OPERAND_VIRTUAL));
26275fd0b74Schristos break;
26375fd0b74Schristos case EPIPHANY_OPERAND_SNMEM :
26475fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_crmem_names, fields->f_sn6, 0|(1<<CGEN_OPERAND_VIRTUAL));
26575fd0b74Schristos break;
26675fd0b74Schristos case EPIPHANY_OPERAND_SNMESH :
26775fd0b74Schristos print_keyword (cd, info, & epiphany_cgen_opval_crmesh_names, fields->f_sn6, 0|(1<<CGEN_OPERAND_VIRTUAL));
26875fd0b74Schristos break;
26975fd0b74Schristos case EPIPHANY_OPERAND_SWI_NUM :
27075fd0b74Schristos print_uimm_not_reg (cd, info, fields->f_trap_num, 0, pc, length);
27175fd0b74Schristos break;
27275fd0b74Schristos case EPIPHANY_OPERAND_TRAPNUM6 :
27375fd0b74Schristos print_normal (cd, info, fields->f_trap_num, 0, pc, length);
27475fd0b74Schristos break;
27575fd0b74Schristos
27675fd0b74Schristos default :
27775fd0b74Schristos /* xgettext:c-format */
278ede78133Schristos opcodes_error_handler
279ede78133Schristos (_("internal error: unrecognized field %d while printing insn"),
28075fd0b74Schristos opindex);
28175fd0b74Schristos abort ();
28275fd0b74Schristos }
28375fd0b74Schristos }
28475fd0b74Schristos
28575fd0b74Schristos cgen_print_fn * const epiphany_cgen_print_handlers[] =
28675fd0b74Schristos {
28775fd0b74Schristos print_insn_normal,
28875fd0b74Schristos };
28975fd0b74Schristos
29075fd0b74Schristos
29175fd0b74Schristos void
epiphany_cgen_init_dis(CGEN_CPU_DESC cd)29275fd0b74Schristos epiphany_cgen_init_dis (CGEN_CPU_DESC cd)
29375fd0b74Schristos {
29475fd0b74Schristos epiphany_cgen_init_opcode_table (cd);
29575fd0b74Schristos epiphany_cgen_init_ibld_table (cd);
29675fd0b74Schristos cd->print_handlers = & epiphany_cgen_print_handlers[0];
29775fd0b74Schristos cd->print_operand = epiphany_cgen_print_operand;
29875fd0b74Schristos }
29975fd0b74Schristos
30075fd0b74Schristos
30175fd0b74Schristos /* Default print handler. */
30275fd0b74Schristos
30375fd0b74Schristos static void
print_normal(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,long value,unsigned int attrs,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)30475fd0b74Schristos print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
30575fd0b74Schristos void *dis_info,
30675fd0b74Schristos long value,
30775fd0b74Schristos unsigned int attrs,
30875fd0b74Schristos bfd_vma pc ATTRIBUTE_UNUSED,
30975fd0b74Schristos int length ATTRIBUTE_UNUSED)
31075fd0b74Schristos {
31175fd0b74Schristos disassemble_info *info = (disassemble_info *) dis_info;
31275fd0b74Schristos
31375fd0b74Schristos /* Print the operand as directed by the attributes. */
31475fd0b74Schristos if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
31575fd0b74Schristos ; /* nothing to do */
31675fd0b74Schristos else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
31775fd0b74Schristos (*info->fprintf_func) (info->stream, "%ld", value);
31875fd0b74Schristos else
31975fd0b74Schristos (*info->fprintf_func) (info->stream, "0x%lx", value);
32075fd0b74Schristos }
32175fd0b74Schristos
32275fd0b74Schristos /* Default address handler. */
32375fd0b74Schristos
32475fd0b74Schristos static void
print_address(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,bfd_vma value,unsigned int attrs,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)32575fd0b74Schristos print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
32675fd0b74Schristos void *dis_info,
32775fd0b74Schristos bfd_vma value,
32875fd0b74Schristos unsigned int attrs,
32975fd0b74Schristos bfd_vma pc ATTRIBUTE_UNUSED,
33075fd0b74Schristos int length ATTRIBUTE_UNUSED)
33175fd0b74Schristos {
33275fd0b74Schristos disassemble_info *info = (disassemble_info *) dis_info;
33375fd0b74Schristos
33475fd0b74Schristos /* Print the operand as directed by the attributes. */
33575fd0b74Schristos if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
33675fd0b74Schristos ; /* Nothing to do. */
33775fd0b74Schristos else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
33875fd0b74Schristos (*info->print_address_func) (value, info);
33975fd0b74Schristos else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
34075fd0b74Schristos (*info->print_address_func) (value, info);
34175fd0b74Schristos else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
34275fd0b74Schristos (*info->fprintf_func) (info->stream, "%ld", (long) value);
34375fd0b74Schristos else
34475fd0b74Schristos (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
34575fd0b74Schristos }
34675fd0b74Schristos
34775fd0b74Schristos /* Keyword print handler. */
34875fd0b74Schristos
34975fd0b74Schristos static void
print_keyword(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,CGEN_KEYWORD * keyword_table,long value,unsigned int attrs ATTRIBUTE_UNUSED)35075fd0b74Schristos print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
35175fd0b74Schristos void *dis_info,
35275fd0b74Schristos CGEN_KEYWORD *keyword_table,
35375fd0b74Schristos long value,
35475fd0b74Schristos unsigned int attrs ATTRIBUTE_UNUSED)
35575fd0b74Schristos {
35675fd0b74Schristos disassemble_info *info = (disassemble_info *) dis_info;
35775fd0b74Schristos const CGEN_KEYWORD_ENTRY *ke;
35875fd0b74Schristos
35975fd0b74Schristos ke = cgen_keyword_lookup_value (keyword_table, value);
36075fd0b74Schristos if (ke != NULL)
36175fd0b74Schristos (*info->fprintf_func) (info->stream, "%s", ke->name);
36275fd0b74Schristos else
36375fd0b74Schristos (*info->fprintf_func) (info->stream, "???");
36475fd0b74Schristos }
36575fd0b74Schristos
36675fd0b74Schristos /* Default insn printer.
36775fd0b74Schristos
36875fd0b74Schristos DIS_INFO is defined as `void *' so the disassembler needn't know anything
36975fd0b74Schristos about disassemble_info. */
37075fd0b74Schristos
37175fd0b74Schristos static void
print_insn_normal(CGEN_CPU_DESC cd,void * dis_info,const CGEN_INSN * insn,CGEN_FIELDS * fields,bfd_vma pc,int length)37275fd0b74Schristos print_insn_normal (CGEN_CPU_DESC cd,
37375fd0b74Schristos void *dis_info,
37475fd0b74Schristos const CGEN_INSN *insn,
37575fd0b74Schristos CGEN_FIELDS *fields,
37675fd0b74Schristos bfd_vma pc,
37775fd0b74Schristos int length)
37875fd0b74Schristos {
37975fd0b74Schristos const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
38075fd0b74Schristos disassemble_info *info = (disassemble_info *) dis_info;
38175fd0b74Schristos const CGEN_SYNTAX_CHAR_TYPE *syn;
38275fd0b74Schristos
38375fd0b74Schristos CGEN_INIT_PRINT (cd);
38475fd0b74Schristos
38575fd0b74Schristos for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
38675fd0b74Schristos {
38775fd0b74Schristos if (CGEN_SYNTAX_MNEMONIC_P (*syn))
38875fd0b74Schristos {
38975fd0b74Schristos (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
39075fd0b74Schristos continue;
39175fd0b74Schristos }
39275fd0b74Schristos if (CGEN_SYNTAX_CHAR_P (*syn))
39375fd0b74Schristos {
39475fd0b74Schristos (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
39575fd0b74Schristos continue;
39675fd0b74Schristos }
39775fd0b74Schristos
39875fd0b74Schristos /* We have an operand. */
39975fd0b74Schristos epiphany_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
40075fd0b74Schristos fields, CGEN_INSN_ATTRS (insn), pc, length);
40175fd0b74Schristos }
40275fd0b74Schristos }
40375fd0b74Schristos
40475fd0b74Schristos /* Subroutine of print_insn. Reads an insn into the given buffers and updates
40575fd0b74Schristos the extract info.
40675fd0b74Schristos Returns 0 if all is well, non-zero otherwise. */
40775fd0b74Schristos
40875fd0b74Schristos static int
read_insn(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,bfd_vma pc,disassemble_info * info,bfd_byte * buf,int buflen,CGEN_EXTRACT_INFO * ex_info,unsigned long * insn_value)40975fd0b74Schristos read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
41075fd0b74Schristos bfd_vma pc,
41175fd0b74Schristos disassemble_info *info,
41275fd0b74Schristos bfd_byte *buf,
41375fd0b74Schristos int buflen,
41475fd0b74Schristos CGEN_EXTRACT_INFO *ex_info,
41575fd0b74Schristos unsigned long *insn_value)
41675fd0b74Schristos {
41775fd0b74Schristos int status = (*info->read_memory_func) (pc, buf, buflen, info);
41875fd0b74Schristos
41975fd0b74Schristos if (status != 0)
42075fd0b74Schristos {
42175fd0b74Schristos (*info->memory_error_func) (status, pc, info);
42275fd0b74Schristos return -1;
42375fd0b74Schristos }
42475fd0b74Schristos
42575fd0b74Schristos ex_info->dis_info = info;
42675fd0b74Schristos ex_info->valid = (1 << buflen) - 1;
42775fd0b74Schristos ex_info->insn_bytes = buf;
42875fd0b74Schristos
42975fd0b74Schristos *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
43075fd0b74Schristos return 0;
43175fd0b74Schristos }
43275fd0b74Schristos
43375fd0b74Schristos /* Utility to print an insn.
43475fd0b74Schristos BUF is the base part of the insn, target byte order, BUFLEN bytes long.
43575fd0b74Schristos The result is the size of the insn in bytes or zero for an unknown insn
43675fd0b74Schristos or -1 if an error occurs fetching data (memory_error_func will have
43775fd0b74Schristos been called). */
43875fd0b74Schristos
43975fd0b74Schristos static int
print_insn(CGEN_CPU_DESC cd,bfd_vma pc,disassemble_info * info,bfd_byte * buf,unsigned int buflen)44075fd0b74Schristos print_insn (CGEN_CPU_DESC cd,
44175fd0b74Schristos bfd_vma pc,
44275fd0b74Schristos disassemble_info *info,
44375fd0b74Schristos bfd_byte *buf,
44475fd0b74Schristos unsigned int buflen)
44575fd0b74Schristos {
44675fd0b74Schristos CGEN_INSN_INT insn_value;
44775fd0b74Schristos const CGEN_INSN_LIST *insn_list;
44875fd0b74Schristos CGEN_EXTRACT_INFO ex_info;
44975fd0b74Schristos int basesize;
45075fd0b74Schristos
45175fd0b74Schristos /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
45275fd0b74Schristos basesize = cd->base_insn_bitsize < buflen * 8 ?
45375fd0b74Schristos cd->base_insn_bitsize : buflen * 8;
454*e992f068Schristos insn_value = cgen_get_insn_value (cd, buf, basesize, cd->insn_endian);
45575fd0b74Schristos
45675fd0b74Schristos
45775fd0b74Schristos /* Fill in ex_info fields like read_insn would. Don't actually call
45875fd0b74Schristos read_insn, since the incoming buffer is already read (and possibly
45975fd0b74Schristos modified a la m32r). */
46075fd0b74Schristos ex_info.valid = (1 << buflen) - 1;
46175fd0b74Schristos ex_info.dis_info = info;
46275fd0b74Schristos ex_info.insn_bytes = buf;
46375fd0b74Schristos
46475fd0b74Schristos /* The instructions are stored in hash lists.
46575fd0b74Schristos Pick the first one and keep trying until we find the right one. */
46675fd0b74Schristos
46775fd0b74Schristos insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
46875fd0b74Schristos while (insn_list != NULL)
46975fd0b74Schristos {
47075fd0b74Schristos const CGEN_INSN *insn = insn_list->insn;
47175fd0b74Schristos CGEN_FIELDS fields;
47275fd0b74Schristos int length;
47375fd0b74Schristos unsigned long insn_value_cropped;
47475fd0b74Schristos
47575fd0b74Schristos #ifdef CGEN_VALIDATE_INSN_SUPPORTED
47675fd0b74Schristos /* Not needed as insn shouldn't be in hash lists if not supported. */
47775fd0b74Schristos /* Supported by this cpu? */
47875fd0b74Schristos if (! epiphany_cgen_insn_supported (cd, insn))
47975fd0b74Schristos {
48075fd0b74Schristos insn_list = CGEN_DIS_NEXT_INSN (insn_list);
48175fd0b74Schristos continue;
48275fd0b74Schristos }
48375fd0b74Schristos #endif
48475fd0b74Schristos
48575fd0b74Schristos /* Basic bit mask must be correct. */
48675fd0b74Schristos /* ??? May wish to allow target to defer this check until the extract
48775fd0b74Schristos handler. */
48875fd0b74Schristos
48975fd0b74Schristos /* Base size may exceed this instruction's size. Extract the
49075fd0b74Schristos relevant part from the buffer. */
49175fd0b74Schristos if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
49275fd0b74Schristos (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
49375fd0b74Schristos insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
49475fd0b74Schristos info->endian == BFD_ENDIAN_BIG);
49575fd0b74Schristos else
49675fd0b74Schristos insn_value_cropped = insn_value;
49775fd0b74Schristos
49875fd0b74Schristos if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
49975fd0b74Schristos == CGEN_INSN_BASE_VALUE (insn))
50075fd0b74Schristos {
50175fd0b74Schristos /* Printing is handled in two passes. The first pass parses the
50275fd0b74Schristos machine insn and extracts the fields. The second pass prints
50375fd0b74Schristos them. */
50475fd0b74Schristos
50575fd0b74Schristos /* Make sure the entire insn is loaded into insn_value, if it
50675fd0b74Schristos can fit. */
50775fd0b74Schristos if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
50875fd0b74Schristos (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
50975fd0b74Schristos {
51075fd0b74Schristos unsigned long full_insn_value;
51175fd0b74Schristos int rc = read_insn (cd, pc, info, buf,
51275fd0b74Schristos CGEN_INSN_BITSIZE (insn) / 8,
51375fd0b74Schristos & ex_info, & full_insn_value);
51475fd0b74Schristos if (rc != 0)
51575fd0b74Schristos return rc;
51675fd0b74Schristos length = CGEN_EXTRACT_FN (cd, insn)
51775fd0b74Schristos (cd, insn, &ex_info, full_insn_value, &fields, pc);
51875fd0b74Schristos }
51975fd0b74Schristos else
52075fd0b74Schristos length = CGEN_EXTRACT_FN (cd, insn)
52175fd0b74Schristos (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
52275fd0b74Schristos
52375fd0b74Schristos /* Length < 0 -> error. */
52475fd0b74Schristos if (length < 0)
52575fd0b74Schristos return length;
52675fd0b74Schristos if (length > 0)
52775fd0b74Schristos {
52875fd0b74Schristos CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
52975fd0b74Schristos /* Length is in bits, result is in bytes. */
53075fd0b74Schristos return length / 8;
53175fd0b74Schristos }
53275fd0b74Schristos }
53375fd0b74Schristos
53475fd0b74Schristos insn_list = CGEN_DIS_NEXT_INSN (insn_list);
53575fd0b74Schristos }
53675fd0b74Schristos
53775fd0b74Schristos return 0;
53875fd0b74Schristos }
53975fd0b74Schristos
54075fd0b74Schristos /* Default value for CGEN_PRINT_INSN.
54175fd0b74Schristos The result is the size of the insn in bytes or zero for an unknown insn
54275fd0b74Schristos or -1 if an error occured fetching bytes. */
54375fd0b74Schristos
54475fd0b74Schristos #ifndef CGEN_PRINT_INSN
54575fd0b74Schristos #define CGEN_PRINT_INSN default_print_insn
54675fd0b74Schristos #endif
54775fd0b74Schristos
54875fd0b74Schristos static int
default_print_insn(CGEN_CPU_DESC cd,bfd_vma pc,disassemble_info * info)54975fd0b74Schristos default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
55075fd0b74Schristos {
55175fd0b74Schristos bfd_byte buf[CGEN_MAX_INSN_SIZE];
55275fd0b74Schristos int buflen;
55375fd0b74Schristos int status;
55475fd0b74Schristos
55575fd0b74Schristos /* Attempt to read the base part of the insn. */
55675fd0b74Schristos buflen = cd->base_insn_bitsize / 8;
55775fd0b74Schristos status = (*info->read_memory_func) (pc, buf, buflen, info);
55875fd0b74Schristos
55975fd0b74Schristos /* Try again with the minimum part, if min < base. */
56075fd0b74Schristos if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
56175fd0b74Schristos {
56275fd0b74Schristos buflen = cd->min_insn_bitsize / 8;
56375fd0b74Schristos status = (*info->read_memory_func) (pc, buf, buflen, info);
56475fd0b74Schristos }
56575fd0b74Schristos
56675fd0b74Schristos if (status != 0)
56775fd0b74Schristos {
56875fd0b74Schristos (*info->memory_error_func) (status, pc, info);
56975fd0b74Schristos return -1;
57075fd0b74Schristos }
57175fd0b74Schristos
57275fd0b74Schristos return print_insn (cd, pc, info, buf, buflen);
57375fd0b74Schristos }
57475fd0b74Schristos
57575fd0b74Schristos /* Main entry point.
57675fd0b74Schristos Print one instruction from PC on INFO->STREAM.
57775fd0b74Schristos Return the size of the instruction (in bytes). */
57875fd0b74Schristos
57975fd0b74Schristos typedef struct cpu_desc_list
58075fd0b74Schristos {
58175fd0b74Schristos struct cpu_desc_list *next;
58275fd0b74Schristos CGEN_BITSET *isa;
58375fd0b74Schristos int mach;
58475fd0b74Schristos int endian;
585*e992f068Schristos int insn_endian;
58675fd0b74Schristos CGEN_CPU_DESC cd;
58775fd0b74Schristos } cpu_desc_list;
58875fd0b74Schristos
58975fd0b74Schristos int
print_insn_epiphany(bfd_vma pc,disassemble_info * info)59075fd0b74Schristos print_insn_epiphany (bfd_vma pc, disassemble_info *info)
59175fd0b74Schristos {
59275fd0b74Schristos static cpu_desc_list *cd_list = 0;
59375fd0b74Schristos cpu_desc_list *cl = 0;
59475fd0b74Schristos static CGEN_CPU_DESC cd = 0;
59575fd0b74Schristos static CGEN_BITSET *prev_isa;
59675fd0b74Schristos static int prev_mach;
59775fd0b74Schristos static int prev_endian;
598*e992f068Schristos static int prev_insn_endian;
59975fd0b74Schristos int length;
60075fd0b74Schristos CGEN_BITSET *isa;
60175fd0b74Schristos int mach;
60275fd0b74Schristos int endian = (info->endian == BFD_ENDIAN_BIG
60375fd0b74Schristos ? CGEN_ENDIAN_BIG
60475fd0b74Schristos : CGEN_ENDIAN_LITTLE);
605*e992f068Schristos int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
606*e992f068Schristos ? CGEN_ENDIAN_BIG
607*e992f068Schristos : CGEN_ENDIAN_LITTLE);
60875fd0b74Schristos enum bfd_architecture arch;
60975fd0b74Schristos
61075fd0b74Schristos /* ??? gdb will set mach but leave the architecture as "unknown" */
61175fd0b74Schristos #ifndef CGEN_BFD_ARCH
61275fd0b74Schristos #define CGEN_BFD_ARCH bfd_arch_epiphany
61375fd0b74Schristos #endif
61475fd0b74Schristos arch = info->arch;
61575fd0b74Schristos if (arch == bfd_arch_unknown)
61675fd0b74Schristos arch = CGEN_BFD_ARCH;
61775fd0b74Schristos
61875fd0b74Schristos /* There's no standard way to compute the machine or isa number
61975fd0b74Schristos so we leave it to the target. */
62075fd0b74Schristos #ifdef CGEN_COMPUTE_MACH
62175fd0b74Schristos mach = CGEN_COMPUTE_MACH (info);
62275fd0b74Schristos #else
62375fd0b74Schristos mach = info->mach;
62475fd0b74Schristos #endif
62575fd0b74Schristos
62675fd0b74Schristos #ifdef CGEN_COMPUTE_ISA
62775fd0b74Schristos {
62875fd0b74Schristos static CGEN_BITSET *permanent_isa;
62975fd0b74Schristos
63075fd0b74Schristos if (!permanent_isa)
63175fd0b74Schristos permanent_isa = cgen_bitset_create (MAX_ISAS);
63275fd0b74Schristos isa = permanent_isa;
63375fd0b74Schristos cgen_bitset_clear (isa);
63475fd0b74Schristos cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
63575fd0b74Schristos }
63675fd0b74Schristos #else
637012573ebSchristos isa = info->private_data;
63875fd0b74Schristos #endif
63975fd0b74Schristos
64075fd0b74Schristos /* If we've switched cpu's, try to find a handle we've used before */
64175fd0b74Schristos if (cd
64275fd0b74Schristos && (cgen_bitset_compare (isa, prev_isa) != 0
64375fd0b74Schristos || mach != prev_mach
64475fd0b74Schristos || endian != prev_endian))
64575fd0b74Schristos {
64675fd0b74Schristos cd = 0;
64775fd0b74Schristos for (cl = cd_list; cl; cl = cl->next)
64875fd0b74Schristos {
64975fd0b74Schristos if (cgen_bitset_compare (cl->isa, isa) == 0 &&
65075fd0b74Schristos cl->mach == mach &&
65175fd0b74Schristos cl->endian == endian)
65275fd0b74Schristos {
65375fd0b74Schristos cd = cl->cd;
65475fd0b74Schristos prev_isa = cd->isas;
65575fd0b74Schristos break;
65675fd0b74Schristos }
65775fd0b74Schristos }
65875fd0b74Schristos }
65975fd0b74Schristos
66075fd0b74Schristos /* If we haven't initialized yet, initialize the opcode table. */
66175fd0b74Schristos if (! cd)
66275fd0b74Schristos {
66375fd0b74Schristos const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
66475fd0b74Schristos const char *mach_name;
66575fd0b74Schristos
66675fd0b74Schristos if (!arch_type)
66775fd0b74Schristos abort ();
66875fd0b74Schristos mach_name = arch_type->printable_name;
66975fd0b74Schristos
67075fd0b74Schristos prev_isa = cgen_bitset_copy (isa);
67175fd0b74Schristos prev_mach = mach;
67275fd0b74Schristos prev_endian = endian;
673*e992f068Schristos prev_insn_endian = insn_endian;
67475fd0b74Schristos cd = epiphany_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
67575fd0b74Schristos CGEN_CPU_OPEN_BFDMACH, mach_name,
67675fd0b74Schristos CGEN_CPU_OPEN_ENDIAN, prev_endian,
677*e992f068Schristos CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
67875fd0b74Schristos CGEN_CPU_OPEN_END);
67975fd0b74Schristos if (!cd)
68075fd0b74Schristos abort ();
68175fd0b74Schristos
68275fd0b74Schristos /* Save this away for future reference. */
68375fd0b74Schristos cl = xmalloc (sizeof (struct cpu_desc_list));
68475fd0b74Schristos cl->cd = cd;
68575fd0b74Schristos cl->isa = prev_isa;
68675fd0b74Schristos cl->mach = mach;
68775fd0b74Schristos cl->endian = endian;
68875fd0b74Schristos cl->next = cd_list;
68975fd0b74Schristos cd_list = cl;
69075fd0b74Schristos
69175fd0b74Schristos epiphany_cgen_init_dis (cd);
69275fd0b74Schristos }
69375fd0b74Schristos
69475fd0b74Schristos /* We try to have as much common code as possible.
69575fd0b74Schristos But at this point some targets need to take over. */
69675fd0b74Schristos /* ??? Some targets may need a hook elsewhere. Try to avoid this,
69775fd0b74Schristos but if not possible try to move this hook elsewhere rather than
69875fd0b74Schristos have two hooks. */
69975fd0b74Schristos length = CGEN_PRINT_INSN (cd, pc, info);
70075fd0b74Schristos if (length > 0)
70175fd0b74Schristos return length;
70275fd0b74Schristos if (length < 0)
70375fd0b74Schristos return -1;
70475fd0b74Schristos
70575fd0b74Schristos (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
70675fd0b74Schristos return cd->default_insn_bitsize / 8;
70775fd0b74Schristos }
708