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 "ip2k-desc.h"
3775fd0b74Schristos #include "ip2k-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 static void
print_fr(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)6475fd0b74Schristos print_fr (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
6575fd0b74Schristos void * dis_info,
6675fd0b74Schristos long value,
6775fd0b74Schristos unsigned int attrs ATTRIBUTE_UNUSED,
6875fd0b74Schristos bfd_vma pc ATTRIBUTE_UNUSED,
6975fd0b74Schristos int length ATTRIBUTE_UNUSED)
7075fd0b74Schristos {
7175fd0b74Schristos disassemble_info *info = (disassemble_info *) dis_info;
7275fd0b74Schristos const CGEN_KEYWORD_ENTRY *ke;
7375fd0b74Schristos extern CGEN_KEYWORD ip2k_cgen_opval_register_names;
7475fd0b74Schristos long offsettest;
7575fd0b74Schristos long offsetvalue;
7675fd0b74Schristos
7775fd0b74Schristos if (value == 0) /* This is (IP). */
7875fd0b74Schristos {
7975fd0b74Schristos (*info->fprintf_func) (info->stream, "%s", "(IP)");
8075fd0b74Schristos return;
8175fd0b74Schristos }
8275fd0b74Schristos
8375fd0b74Schristos offsettest = value >> 7;
8475fd0b74Schristos offsetvalue = value & 0x7F;
8575fd0b74Schristos
8675fd0b74Schristos /* Check to see if first two bits are 10 -> (DP). */
8775fd0b74Schristos if (offsettest == 2)
8875fd0b74Schristos {
8975fd0b74Schristos if (offsetvalue == 0)
9075fd0b74Schristos (*info->fprintf_func) (info->stream, "%s","(DP)");
9175fd0b74Schristos else
9275fd0b74Schristos (*info->fprintf_func) (info->stream, "$%lx%s", offsetvalue, "(DP)");
9375fd0b74Schristos return;
9475fd0b74Schristos }
9575fd0b74Schristos
9675fd0b74Schristos /* Check to see if first two bits are 11 -> (SP). */
9775fd0b74Schristos if (offsettest == 3)
9875fd0b74Schristos {
9975fd0b74Schristos if (offsetvalue == 0)
10075fd0b74Schristos (*info->fprintf_func) (info->stream, "%s", "(SP)");
10175fd0b74Schristos else
10275fd0b74Schristos (*info->fprintf_func) (info->stream, "$%lx%s", offsetvalue,"(SP)");
10375fd0b74Schristos return;
10475fd0b74Schristos }
10575fd0b74Schristos
10675fd0b74Schristos /* Attempt to print as a register keyword. */
10775fd0b74Schristos ke = cgen_keyword_lookup_value (& ip2k_cgen_opval_register_names, value);
10875fd0b74Schristos
10975fd0b74Schristos if (ke != NULL)
11075fd0b74Schristos (*info->fprintf_func) (info->stream, "%s", ke->name);
11175fd0b74Schristos else
11275fd0b74Schristos /* Print as an address literal. */
11375fd0b74Schristos (*info->fprintf_func) (info->stream, "$%02lx", value);
11475fd0b74Schristos }
11575fd0b74Schristos
11675fd0b74Schristos static void
print_dollarhex(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)11775fd0b74Schristos print_dollarhex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
11875fd0b74Schristos void * dis_info,
11975fd0b74Schristos long value,
12075fd0b74Schristos unsigned int attrs ATTRIBUTE_UNUSED,
12175fd0b74Schristos bfd_vma pc ATTRIBUTE_UNUSED,
12275fd0b74Schristos int length ATTRIBUTE_UNUSED)
12375fd0b74Schristos {
12475fd0b74Schristos disassemble_info *info = (disassemble_info *) dis_info;
12575fd0b74Schristos
12675fd0b74Schristos (*info->fprintf_func) (info->stream, "$%lx", value);
12775fd0b74Schristos }
12875fd0b74Schristos
12975fd0b74Schristos static void
print_dollarhex8(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)13075fd0b74Schristos print_dollarhex8 (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
13175fd0b74Schristos void * dis_info,
13275fd0b74Schristos long value,
13375fd0b74Schristos unsigned int attrs ATTRIBUTE_UNUSED,
13475fd0b74Schristos bfd_vma pc ATTRIBUTE_UNUSED,
13575fd0b74Schristos int length ATTRIBUTE_UNUSED)
13675fd0b74Schristos {
13775fd0b74Schristos disassemble_info *info = (disassemble_info *) dis_info;
13875fd0b74Schristos
13975fd0b74Schristos (*info->fprintf_func) (info->stream, "$%02lx", value);
14075fd0b74Schristos }
14175fd0b74Schristos
14275fd0b74Schristos static void
print_dollarhex_addr16h(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)14375fd0b74Schristos print_dollarhex_addr16h (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
14475fd0b74Schristos void * dis_info,
14575fd0b74Schristos long value,
14675fd0b74Schristos unsigned int attrs ATTRIBUTE_UNUSED,
14775fd0b74Schristos bfd_vma pc ATTRIBUTE_UNUSED,
14875fd0b74Schristos int length ATTRIBUTE_UNUSED)
14975fd0b74Schristos {
15075fd0b74Schristos disassemble_info *info = (disassemble_info *) dis_info;
15175fd0b74Schristos
15275fd0b74Schristos /* This is a loadh instruction. Shift the value to the left
15375fd0b74Schristos by 8 bits so that disassembled code will reassemble properly. */
15475fd0b74Schristos value = ((value << 8) & 0xFF00);
15575fd0b74Schristos
15675fd0b74Schristos (*info->fprintf_func) (info->stream, "$%04lx", value);
15775fd0b74Schristos }
15875fd0b74Schristos
15975fd0b74Schristos static void
print_dollarhex_addr16l(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)16075fd0b74Schristos print_dollarhex_addr16l (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
16175fd0b74Schristos void * dis_info,
16275fd0b74Schristos long value,
16375fd0b74Schristos unsigned int attrs ATTRIBUTE_UNUSED,
16475fd0b74Schristos bfd_vma pc ATTRIBUTE_UNUSED,
16575fd0b74Schristos int length ATTRIBUTE_UNUSED)
16675fd0b74Schristos {
16775fd0b74Schristos disassemble_info *info = (disassemble_info *) dis_info;
16875fd0b74Schristos
16975fd0b74Schristos (*info->fprintf_func) (info->stream, "$%04lx", value);
17075fd0b74Schristos }
17175fd0b74Schristos
17275fd0b74Schristos static void
print_dollarhex_p(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)17375fd0b74Schristos print_dollarhex_p (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
17475fd0b74Schristos void * dis_info,
17575fd0b74Schristos long value,
17675fd0b74Schristos unsigned int attrs ATTRIBUTE_UNUSED,
17775fd0b74Schristos bfd_vma pc ATTRIBUTE_UNUSED,
17875fd0b74Schristos int length ATTRIBUTE_UNUSED)
17975fd0b74Schristos {
18075fd0b74Schristos disassemble_info *info = (disassemble_info *) dis_info;
18175fd0b74Schristos
18275fd0b74Schristos value = ((value << 14) & 0x1C000);
18375fd0b74Schristos ;value = (value & 0x1FFFF);
18475fd0b74Schristos (*info->fprintf_func) (info->stream, "$%05lx", value);
18575fd0b74Schristos }
18675fd0b74Schristos
18775fd0b74Schristos static void
print_dollarhex_cj(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)18875fd0b74Schristos print_dollarhex_cj (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
18975fd0b74Schristos void * dis_info,
19075fd0b74Schristos long value,
19175fd0b74Schristos unsigned int attrs ATTRIBUTE_UNUSED,
19275fd0b74Schristos bfd_vma pc ATTRIBUTE_UNUSED,
19375fd0b74Schristos int length ATTRIBUTE_UNUSED)
19475fd0b74Schristos {
19575fd0b74Schristos disassemble_info *info = (disassemble_info *) dis_info;
19675fd0b74Schristos
19775fd0b74Schristos value = ((value << 1) & 0x1FFFF);
19875fd0b74Schristos (*info->fprintf_func) (info->stream, "$%05lx", value);
19975fd0b74Schristos }
20075fd0b74Schristos
20175fd0b74Schristos static void
print_decimal(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)20275fd0b74Schristos print_decimal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
20375fd0b74Schristos void * dis_info,
20475fd0b74Schristos long value,
20575fd0b74Schristos unsigned int attrs ATTRIBUTE_UNUSED,
20675fd0b74Schristos bfd_vma pc ATTRIBUTE_UNUSED,
20775fd0b74Schristos int length ATTRIBUTE_UNUSED)
20875fd0b74Schristos {
20975fd0b74Schristos disassemble_info *info = (disassemble_info *) dis_info;
21075fd0b74Schristos
21175fd0b74Schristos (*info->fprintf_func) (info->stream, "%ld", value);
21275fd0b74Schristos }
21375fd0b74Schristos
21475fd0b74Schristos
21575fd0b74Schristos
21675fd0b74Schristos /* -- */
21775fd0b74Schristos
21875fd0b74Schristos void ip2k_cgen_print_operand
219*e992f068Schristos (CGEN_CPU_DESC, int, void *, CGEN_FIELDS *, void const *, bfd_vma, int);
22075fd0b74Schristos
22175fd0b74Schristos /* Main entry point for printing operands.
22275fd0b74Schristos XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
22375fd0b74Schristos of dis-asm.h on cgen.h.
22475fd0b74Schristos
22575fd0b74Schristos This function is basically just a big switch statement. Earlier versions
22675fd0b74Schristos used tables to look up the function to use, but
22775fd0b74Schristos - if the table contains both assembler and disassembler functions then
22875fd0b74Schristos the disassembler contains much of the assembler and vice-versa,
22975fd0b74Schristos - there's a lot of inlining possibilities as things grow,
23075fd0b74Schristos - using a switch statement avoids the function call overhead.
23175fd0b74Schristos
23275fd0b74Schristos This function could be moved into `print_insn_normal', but keeping it
23375fd0b74Schristos separate makes clear the interface between `print_insn_normal' and each of
23475fd0b74Schristos the handlers. */
23575fd0b74Schristos
23675fd0b74Schristos void
ip2k_cgen_print_operand(CGEN_CPU_DESC cd,int opindex,void * xinfo,CGEN_FIELDS * fields,void const * attrs ATTRIBUTE_UNUSED,bfd_vma pc,int length)23775fd0b74Schristos ip2k_cgen_print_operand (CGEN_CPU_DESC cd,
23875fd0b74Schristos int opindex,
23975fd0b74Schristos void * xinfo,
24075fd0b74Schristos CGEN_FIELDS *fields,
24175fd0b74Schristos void const *attrs ATTRIBUTE_UNUSED,
24275fd0b74Schristos bfd_vma pc,
24375fd0b74Schristos int length)
24475fd0b74Schristos {
24575fd0b74Schristos disassemble_info *info = (disassemble_info *) xinfo;
24675fd0b74Schristos
24775fd0b74Schristos switch (opindex)
24875fd0b74Schristos {
24975fd0b74Schristos case IP2K_OPERAND_ADDR16CJP :
25075fd0b74Schristos print_dollarhex_cj (cd, info, fields->f_addr16cjp, 0|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
25175fd0b74Schristos break;
25275fd0b74Schristos case IP2K_OPERAND_ADDR16H :
25375fd0b74Schristos print_dollarhex_addr16h (cd, info, fields->f_imm8, 0, pc, length);
25475fd0b74Schristos break;
25575fd0b74Schristos case IP2K_OPERAND_ADDR16L :
25675fd0b74Schristos print_dollarhex_addr16l (cd, info, fields->f_imm8, 0, pc, length);
25775fd0b74Schristos break;
25875fd0b74Schristos case IP2K_OPERAND_ADDR16P :
25975fd0b74Schristos print_dollarhex_p (cd, info, fields->f_page3, 0, pc, length);
26075fd0b74Schristos break;
26175fd0b74Schristos case IP2K_OPERAND_BITNO :
26275fd0b74Schristos print_decimal (cd, info, fields->f_bitno, 0, pc, length);
26375fd0b74Schristos break;
26475fd0b74Schristos case IP2K_OPERAND_CBIT :
26575fd0b74Schristos print_normal (cd, info, 0, 0, pc, length);
26675fd0b74Schristos break;
26775fd0b74Schristos case IP2K_OPERAND_DCBIT :
26875fd0b74Schristos print_normal (cd, info, 0, 0, pc, length);
26975fd0b74Schristos break;
27075fd0b74Schristos case IP2K_OPERAND_FR :
27175fd0b74Schristos print_fr (cd, info, fields->f_reg, 0|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
27275fd0b74Schristos break;
27375fd0b74Schristos case IP2K_OPERAND_LIT8 :
27475fd0b74Schristos print_dollarhex8 (cd, info, fields->f_imm8, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
27575fd0b74Schristos break;
27675fd0b74Schristos case IP2K_OPERAND_PABITS :
27775fd0b74Schristos print_normal (cd, info, 0, 0, pc, length);
27875fd0b74Schristos break;
27975fd0b74Schristos case IP2K_OPERAND_RETI3 :
28075fd0b74Schristos print_dollarhex (cd, info, fields->f_reti3, 0, pc, length);
28175fd0b74Schristos break;
28275fd0b74Schristos case IP2K_OPERAND_ZBIT :
28375fd0b74Schristos print_normal (cd, info, 0, 0, pc, length);
28475fd0b74Schristos break;
28575fd0b74Schristos
28675fd0b74Schristos default :
28775fd0b74Schristos /* xgettext:c-format */
288ede78133Schristos opcodes_error_handler
289ede78133Schristos (_("internal error: unrecognized field %d while printing insn"),
29075fd0b74Schristos opindex);
29175fd0b74Schristos abort ();
29275fd0b74Schristos }
29375fd0b74Schristos }
29475fd0b74Schristos
29575fd0b74Schristos cgen_print_fn * const ip2k_cgen_print_handlers[] =
29675fd0b74Schristos {
29775fd0b74Schristos print_insn_normal,
29875fd0b74Schristos };
29975fd0b74Schristos
30075fd0b74Schristos
30175fd0b74Schristos void
ip2k_cgen_init_dis(CGEN_CPU_DESC cd)30275fd0b74Schristos ip2k_cgen_init_dis (CGEN_CPU_DESC cd)
30375fd0b74Schristos {
30475fd0b74Schristos ip2k_cgen_init_opcode_table (cd);
30575fd0b74Schristos ip2k_cgen_init_ibld_table (cd);
30675fd0b74Schristos cd->print_handlers = & ip2k_cgen_print_handlers[0];
30775fd0b74Schristos cd->print_operand = ip2k_cgen_print_operand;
30875fd0b74Schristos }
30975fd0b74Schristos
31075fd0b74Schristos
31175fd0b74Schristos /* Default print handler. */
31275fd0b74Schristos
31375fd0b74Schristos 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)31475fd0b74Schristos print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
31575fd0b74Schristos void *dis_info,
31675fd0b74Schristos long value,
31775fd0b74Schristos unsigned int attrs,
31875fd0b74Schristos bfd_vma pc ATTRIBUTE_UNUSED,
31975fd0b74Schristos int length ATTRIBUTE_UNUSED)
32075fd0b74Schristos {
32175fd0b74Schristos disassemble_info *info = (disassemble_info *) dis_info;
32275fd0b74Schristos
32375fd0b74Schristos /* Print the operand as directed by the attributes. */
32475fd0b74Schristos if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
32575fd0b74Schristos ; /* nothing to do */
32675fd0b74Schristos else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
32775fd0b74Schristos (*info->fprintf_func) (info->stream, "%ld", value);
32875fd0b74Schristos else
32975fd0b74Schristos (*info->fprintf_func) (info->stream, "0x%lx", value);
33075fd0b74Schristos }
33175fd0b74Schristos
33275fd0b74Schristos /* Default address handler. */
33375fd0b74Schristos
33475fd0b74Schristos 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)33575fd0b74Schristos print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
33675fd0b74Schristos void *dis_info,
33775fd0b74Schristos bfd_vma value,
33875fd0b74Schristos unsigned int attrs,
33975fd0b74Schristos bfd_vma pc ATTRIBUTE_UNUSED,
34075fd0b74Schristos int length ATTRIBUTE_UNUSED)
34175fd0b74Schristos {
34275fd0b74Schristos disassemble_info *info = (disassemble_info *) dis_info;
34375fd0b74Schristos
34475fd0b74Schristos /* Print the operand as directed by the attributes. */
34575fd0b74Schristos if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
34675fd0b74Schristos ; /* Nothing to do. */
34775fd0b74Schristos else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
34875fd0b74Schristos (*info->print_address_func) (value, info);
34975fd0b74Schristos else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
35075fd0b74Schristos (*info->print_address_func) (value, info);
35175fd0b74Schristos else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
35275fd0b74Schristos (*info->fprintf_func) (info->stream, "%ld", (long) value);
35375fd0b74Schristos else
35475fd0b74Schristos (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
35575fd0b74Schristos }
35675fd0b74Schristos
35775fd0b74Schristos /* Keyword print handler. */
35875fd0b74Schristos
35975fd0b74Schristos static void
print_keyword(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,CGEN_KEYWORD * keyword_table,long value,unsigned int attrs ATTRIBUTE_UNUSED)36075fd0b74Schristos print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
36175fd0b74Schristos void *dis_info,
36275fd0b74Schristos CGEN_KEYWORD *keyword_table,
36375fd0b74Schristos long value,
36475fd0b74Schristos unsigned int attrs ATTRIBUTE_UNUSED)
36575fd0b74Schristos {
36675fd0b74Schristos disassemble_info *info = (disassemble_info *) dis_info;
36775fd0b74Schristos const CGEN_KEYWORD_ENTRY *ke;
36875fd0b74Schristos
36975fd0b74Schristos ke = cgen_keyword_lookup_value (keyword_table, value);
37075fd0b74Schristos if (ke != NULL)
37175fd0b74Schristos (*info->fprintf_func) (info->stream, "%s", ke->name);
37275fd0b74Schristos else
37375fd0b74Schristos (*info->fprintf_func) (info->stream, "???");
37475fd0b74Schristos }
37575fd0b74Schristos
37675fd0b74Schristos /* Default insn printer.
37775fd0b74Schristos
37875fd0b74Schristos DIS_INFO is defined as `void *' so the disassembler needn't know anything
37975fd0b74Schristos about disassemble_info. */
38075fd0b74Schristos
38175fd0b74Schristos static void
print_insn_normal(CGEN_CPU_DESC cd,void * dis_info,const CGEN_INSN * insn,CGEN_FIELDS * fields,bfd_vma pc,int length)38275fd0b74Schristos print_insn_normal (CGEN_CPU_DESC cd,
38375fd0b74Schristos void *dis_info,
38475fd0b74Schristos const CGEN_INSN *insn,
38575fd0b74Schristos CGEN_FIELDS *fields,
38675fd0b74Schristos bfd_vma pc,
38775fd0b74Schristos int length)
38875fd0b74Schristos {
38975fd0b74Schristos const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
39075fd0b74Schristos disassemble_info *info = (disassemble_info *) dis_info;
39175fd0b74Schristos const CGEN_SYNTAX_CHAR_TYPE *syn;
39275fd0b74Schristos
39375fd0b74Schristos CGEN_INIT_PRINT (cd);
39475fd0b74Schristos
39575fd0b74Schristos for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
39675fd0b74Schristos {
39775fd0b74Schristos if (CGEN_SYNTAX_MNEMONIC_P (*syn))
39875fd0b74Schristos {
39975fd0b74Schristos (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
40075fd0b74Schristos continue;
40175fd0b74Schristos }
40275fd0b74Schristos if (CGEN_SYNTAX_CHAR_P (*syn))
40375fd0b74Schristos {
40475fd0b74Schristos (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
40575fd0b74Schristos continue;
40675fd0b74Schristos }
40775fd0b74Schristos
40875fd0b74Schristos /* We have an operand. */
40975fd0b74Schristos ip2k_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
41075fd0b74Schristos fields, CGEN_INSN_ATTRS (insn), pc, length);
41175fd0b74Schristos }
41275fd0b74Schristos }
41375fd0b74Schristos
41475fd0b74Schristos /* Subroutine of print_insn. Reads an insn into the given buffers and updates
41575fd0b74Schristos the extract info.
41675fd0b74Schristos Returns 0 if all is well, non-zero otherwise. */
41775fd0b74Schristos
41875fd0b74Schristos 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)41975fd0b74Schristos read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
42075fd0b74Schristos bfd_vma pc,
42175fd0b74Schristos disassemble_info *info,
42275fd0b74Schristos bfd_byte *buf,
42375fd0b74Schristos int buflen,
42475fd0b74Schristos CGEN_EXTRACT_INFO *ex_info,
42575fd0b74Schristos unsigned long *insn_value)
42675fd0b74Schristos {
42775fd0b74Schristos int status = (*info->read_memory_func) (pc, buf, buflen, info);
42875fd0b74Schristos
42975fd0b74Schristos if (status != 0)
43075fd0b74Schristos {
43175fd0b74Schristos (*info->memory_error_func) (status, pc, info);
43275fd0b74Schristos return -1;
43375fd0b74Schristos }
43475fd0b74Schristos
43575fd0b74Schristos ex_info->dis_info = info;
43675fd0b74Schristos ex_info->valid = (1 << buflen) - 1;
43775fd0b74Schristos ex_info->insn_bytes = buf;
43875fd0b74Schristos
43975fd0b74Schristos *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
44075fd0b74Schristos return 0;
44175fd0b74Schristos }
44275fd0b74Schristos
44375fd0b74Schristos /* Utility to print an insn.
44475fd0b74Schristos BUF is the base part of the insn, target byte order, BUFLEN bytes long.
44575fd0b74Schristos The result is the size of the insn in bytes or zero for an unknown insn
44675fd0b74Schristos or -1 if an error occurs fetching data (memory_error_func will have
44775fd0b74Schristos been called). */
44875fd0b74Schristos
44975fd0b74Schristos static int
print_insn(CGEN_CPU_DESC cd,bfd_vma pc,disassemble_info * info,bfd_byte * buf,unsigned int buflen)45075fd0b74Schristos print_insn (CGEN_CPU_DESC cd,
45175fd0b74Schristos bfd_vma pc,
45275fd0b74Schristos disassemble_info *info,
45375fd0b74Schristos bfd_byte *buf,
45475fd0b74Schristos unsigned int buflen)
45575fd0b74Schristos {
45675fd0b74Schristos CGEN_INSN_INT insn_value;
45775fd0b74Schristos const CGEN_INSN_LIST *insn_list;
45875fd0b74Schristos CGEN_EXTRACT_INFO ex_info;
45975fd0b74Schristos int basesize;
46075fd0b74Schristos
46175fd0b74Schristos /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
46275fd0b74Schristos basesize = cd->base_insn_bitsize < buflen * 8 ?
46375fd0b74Schristos cd->base_insn_bitsize : buflen * 8;
464*e992f068Schristos insn_value = cgen_get_insn_value (cd, buf, basesize, cd->insn_endian);
46575fd0b74Schristos
46675fd0b74Schristos
46775fd0b74Schristos /* Fill in ex_info fields like read_insn would. Don't actually call
46875fd0b74Schristos read_insn, since the incoming buffer is already read (and possibly
46975fd0b74Schristos modified a la m32r). */
47075fd0b74Schristos ex_info.valid = (1 << buflen) - 1;
47175fd0b74Schristos ex_info.dis_info = info;
47275fd0b74Schristos ex_info.insn_bytes = buf;
47375fd0b74Schristos
47475fd0b74Schristos /* The instructions are stored in hash lists.
47575fd0b74Schristos Pick the first one and keep trying until we find the right one. */
47675fd0b74Schristos
47775fd0b74Schristos insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
47875fd0b74Schristos while (insn_list != NULL)
47975fd0b74Schristos {
48075fd0b74Schristos const CGEN_INSN *insn = insn_list->insn;
48175fd0b74Schristos CGEN_FIELDS fields;
48275fd0b74Schristos int length;
48375fd0b74Schristos unsigned long insn_value_cropped;
48475fd0b74Schristos
48575fd0b74Schristos #ifdef CGEN_VALIDATE_INSN_SUPPORTED
48675fd0b74Schristos /* Not needed as insn shouldn't be in hash lists if not supported. */
48775fd0b74Schristos /* Supported by this cpu? */
48875fd0b74Schristos if (! ip2k_cgen_insn_supported (cd, insn))
48975fd0b74Schristos {
49075fd0b74Schristos insn_list = CGEN_DIS_NEXT_INSN (insn_list);
49175fd0b74Schristos continue;
49275fd0b74Schristos }
49375fd0b74Schristos #endif
49475fd0b74Schristos
49575fd0b74Schristos /* Basic bit mask must be correct. */
49675fd0b74Schristos /* ??? May wish to allow target to defer this check until the extract
49775fd0b74Schristos handler. */
49875fd0b74Schristos
49975fd0b74Schristos /* Base size may exceed this instruction's size. Extract the
50075fd0b74Schristos relevant part from the buffer. */
50175fd0b74Schristos if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
50275fd0b74Schristos (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
50375fd0b74Schristos insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
50475fd0b74Schristos info->endian == BFD_ENDIAN_BIG);
50575fd0b74Schristos else
50675fd0b74Schristos insn_value_cropped = insn_value;
50775fd0b74Schristos
50875fd0b74Schristos if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
50975fd0b74Schristos == CGEN_INSN_BASE_VALUE (insn))
51075fd0b74Schristos {
51175fd0b74Schristos /* Printing is handled in two passes. The first pass parses the
51275fd0b74Schristos machine insn and extracts the fields. The second pass prints
51375fd0b74Schristos them. */
51475fd0b74Schristos
51575fd0b74Schristos /* Make sure the entire insn is loaded into insn_value, if it
51675fd0b74Schristos can fit. */
51775fd0b74Schristos if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
51875fd0b74Schristos (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
51975fd0b74Schristos {
52075fd0b74Schristos unsigned long full_insn_value;
52175fd0b74Schristos int rc = read_insn (cd, pc, info, buf,
52275fd0b74Schristos CGEN_INSN_BITSIZE (insn) / 8,
52375fd0b74Schristos & ex_info, & full_insn_value);
52475fd0b74Schristos if (rc != 0)
52575fd0b74Schristos return rc;
52675fd0b74Schristos length = CGEN_EXTRACT_FN (cd, insn)
52775fd0b74Schristos (cd, insn, &ex_info, full_insn_value, &fields, pc);
52875fd0b74Schristos }
52975fd0b74Schristos else
53075fd0b74Schristos length = CGEN_EXTRACT_FN (cd, insn)
53175fd0b74Schristos (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
53275fd0b74Schristos
53375fd0b74Schristos /* Length < 0 -> error. */
53475fd0b74Schristos if (length < 0)
53575fd0b74Schristos return length;
53675fd0b74Schristos if (length > 0)
53775fd0b74Schristos {
53875fd0b74Schristos CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
53975fd0b74Schristos /* Length is in bits, result is in bytes. */
54075fd0b74Schristos return length / 8;
54175fd0b74Schristos }
54275fd0b74Schristos }
54375fd0b74Schristos
54475fd0b74Schristos insn_list = CGEN_DIS_NEXT_INSN (insn_list);
54575fd0b74Schristos }
54675fd0b74Schristos
54775fd0b74Schristos return 0;
54875fd0b74Schristos }
54975fd0b74Schristos
55075fd0b74Schristos /* Default value for CGEN_PRINT_INSN.
55175fd0b74Schristos The result is the size of the insn in bytes or zero for an unknown insn
55275fd0b74Schristos or -1 if an error occured fetching bytes. */
55375fd0b74Schristos
55475fd0b74Schristos #ifndef CGEN_PRINT_INSN
55575fd0b74Schristos #define CGEN_PRINT_INSN default_print_insn
55675fd0b74Schristos #endif
55775fd0b74Schristos
55875fd0b74Schristos static int
default_print_insn(CGEN_CPU_DESC cd,bfd_vma pc,disassemble_info * info)55975fd0b74Schristos default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
56075fd0b74Schristos {
56175fd0b74Schristos bfd_byte buf[CGEN_MAX_INSN_SIZE];
56275fd0b74Schristos int buflen;
56375fd0b74Schristos int status;
56475fd0b74Schristos
56575fd0b74Schristos /* Attempt to read the base part of the insn. */
56675fd0b74Schristos buflen = cd->base_insn_bitsize / 8;
56775fd0b74Schristos status = (*info->read_memory_func) (pc, buf, buflen, info);
56875fd0b74Schristos
56975fd0b74Schristos /* Try again with the minimum part, if min < base. */
57075fd0b74Schristos if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
57175fd0b74Schristos {
57275fd0b74Schristos buflen = cd->min_insn_bitsize / 8;
57375fd0b74Schristos status = (*info->read_memory_func) (pc, buf, buflen, info);
57475fd0b74Schristos }
57575fd0b74Schristos
57675fd0b74Schristos if (status != 0)
57775fd0b74Schristos {
57875fd0b74Schristos (*info->memory_error_func) (status, pc, info);
57975fd0b74Schristos return -1;
58075fd0b74Schristos }
58175fd0b74Schristos
58275fd0b74Schristos return print_insn (cd, pc, info, buf, buflen);
58375fd0b74Schristos }
58475fd0b74Schristos
58575fd0b74Schristos /* Main entry point.
58675fd0b74Schristos Print one instruction from PC on INFO->STREAM.
58775fd0b74Schristos Return the size of the instruction (in bytes). */
58875fd0b74Schristos
58975fd0b74Schristos typedef struct cpu_desc_list
59075fd0b74Schristos {
59175fd0b74Schristos struct cpu_desc_list *next;
59275fd0b74Schristos CGEN_BITSET *isa;
59375fd0b74Schristos int mach;
59475fd0b74Schristos int endian;
595*e992f068Schristos int insn_endian;
59675fd0b74Schristos CGEN_CPU_DESC cd;
59775fd0b74Schristos } cpu_desc_list;
59875fd0b74Schristos
59975fd0b74Schristos int
print_insn_ip2k(bfd_vma pc,disassemble_info * info)60075fd0b74Schristos print_insn_ip2k (bfd_vma pc, disassemble_info *info)
60175fd0b74Schristos {
60275fd0b74Schristos static cpu_desc_list *cd_list = 0;
60375fd0b74Schristos cpu_desc_list *cl = 0;
60475fd0b74Schristos static CGEN_CPU_DESC cd = 0;
60575fd0b74Schristos static CGEN_BITSET *prev_isa;
60675fd0b74Schristos static int prev_mach;
60775fd0b74Schristos static int prev_endian;
608*e992f068Schristos static int prev_insn_endian;
60975fd0b74Schristos int length;
61075fd0b74Schristos CGEN_BITSET *isa;
61175fd0b74Schristos int mach;
61275fd0b74Schristos int endian = (info->endian == BFD_ENDIAN_BIG
61375fd0b74Schristos ? CGEN_ENDIAN_BIG
61475fd0b74Schristos : CGEN_ENDIAN_LITTLE);
615*e992f068Schristos int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
616*e992f068Schristos ? CGEN_ENDIAN_BIG
617*e992f068Schristos : CGEN_ENDIAN_LITTLE);
61875fd0b74Schristos enum bfd_architecture arch;
61975fd0b74Schristos
62075fd0b74Schristos /* ??? gdb will set mach but leave the architecture as "unknown" */
62175fd0b74Schristos #ifndef CGEN_BFD_ARCH
62275fd0b74Schristos #define CGEN_BFD_ARCH bfd_arch_ip2k
62375fd0b74Schristos #endif
62475fd0b74Schristos arch = info->arch;
62575fd0b74Schristos if (arch == bfd_arch_unknown)
62675fd0b74Schristos arch = CGEN_BFD_ARCH;
62775fd0b74Schristos
62875fd0b74Schristos /* There's no standard way to compute the machine or isa number
62975fd0b74Schristos so we leave it to the target. */
63075fd0b74Schristos #ifdef CGEN_COMPUTE_MACH
63175fd0b74Schristos mach = CGEN_COMPUTE_MACH (info);
63275fd0b74Schristos #else
63375fd0b74Schristos mach = info->mach;
63475fd0b74Schristos #endif
63575fd0b74Schristos
63675fd0b74Schristos #ifdef CGEN_COMPUTE_ISA
63775fd0b74Schristos {
63875fd0b74Schristos static CGEN_BITSET *permanent_isa;
63975fd0b74Schristos
64075fd0b74Schristos if (!permanent_isa)
64175fd0b74Schristos permanent_isa = cgen_bitset_create (MAX_ISAS);
64275fd0b74Schristos isa = permanent_isa;
64375fd0b74Schristos cgen_bitset_clear (isa);
64475fd0b74Schristos cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
64575fd0b74Schristos }
64675fd0b74Schristos #else
647012573ebSchristos isa = info->private_data;
64875fd0b74Schristos #endif
64975fd0b74Schristos
65075fd0b74Schristos /* If we've switched cpu's, try to find a handle we've used before */
65175fd0b74Schristos if (cd
65275fd0b74Schristos && (cgen_bitset_compare (isa, prev_isa) != 0
65375fd0b74Schristos || mach != prev_mach
65475fd0b74Schristos || endian != prev_endian))
65575fd0b74Schristos {
65675fd0b74Schristos cd = 0;
65775fd0b74Schristos for (cl = cd_list; cl; cl = cl->next)
65875fd0b74Schristos {
65975fd0b74Schristos if (cgen_bitset_compare (cl->isa, isa) == 0 &&
66075fd0b74Schristos cl->mach == mach &&
66175fd0b74Schristos cl->endian == endian)
66275fd0b74Schristos {
66375fd0b74Schristos cd = cl->cd;
66475fd0b74Schristos prev_isa = cd->isas;
66575fd0b74Schristos break;
66675fd0b74Schristos }
66775fd0b74Schristos }
66875fd0b74Schristos }
66975fd0b74Schristos
67075fd0b74Schristos /* If we haven't initialized yet, initialize the opcode table. */
67175fd0b74Schristos if (! cd)
67275fd0b74Schristos {
67375fd0b74Schristos const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
67475fd0b74Schristos const char *mach_name;
67575fd0b74Schristos
67675fd0b74Schristos if (!arch_type)
67775fd0b74Schristos abort ();
67875fd0b74Schristos mach_name = arch_type->printable_name;
67975fd0b74Schristos
68075fd0b74Schristos prev_isa = cgen_bitset_copy (isa);
68175fd0b74Schristos prev_mach = mach;
68275fd0b74Schristos prev_endian = endian;
683*e992f068Schristos prev_insn_endian = insn_endian;
68475fd0b74Schristos cd = ip2k_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
68575fd0b74Schristos CGEN_CPU_OPEN_BFDMACH, mach_name,
68675fd0b74Schristos CGEN_CPU_OPEN_ENDIAN, prev_endian,
687*e992f068Schristos CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
68875fd0b74Schristos CGEN_CPU_OPEN_END);
68975fd0b74Schristos if (!cd)
69075fd0b74Schristos abort ();
69175fd0b74Schristos
69275fd0b74Schristos /* Save this away for future reference. */
69375fd0b74Schristos cl = xmalloc (sizeof (struct cpu_desc_list));
69475fd0b74Schristos cl->cd = cd;
69575fd0b74Schristos cl->isa = prev_isa;
69675fd0b74Schristos cl->mach = mach;
69775fd0b74Schristos cl->endian = endian;
69875fd0b74Schristos cl->next = cd_list;
69975fd0b74Schristos cd_list = cl;
70075fd0b74Schristos
70175fd0b74Schristos ip2k_cgen_init_dis (cd);
70275fd0b74Schristos }
70375fd0b74Schristos
70475fd0b74Schristos /* We try to have as much common code as possible.
70575fd0b74Schristos But at this point some targets need to take over. */
70675fd0b74Schristos /* ??? Some targets may need a hook elsewhere. Try to avoid this,
70775fd0b74Schristos but if not possible try to move this hook elsewhere rather than
70875fd0b74Schristos have two hooks. */
70975fd0b74Schristos length = CGEN_PRINT_INSN (cd, pc, info);
71075fd0b74Schristos if (length > 0)
71175fd0b74Schristos return length;
71275fd0b74Schristos if (length < 0)
71375fd0b74Schristos return -1;
71475fd0b74Schristos
71575fd0b74Schristos (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
71675fd0b74Schristos return cd->default_insn_bitsize / 8;
71775fd0b74Schristos }
718