cgen-dis.in revision 91041
185815Sobrien/* Disassembler interface for targets using CGEN. -*- C -*-
285815Sobrien   CGEN: Cpu tools GENerator
385815Sobrien
485815SobrienTHIS FILE IS MACHINE GENERATED WITH CGEN.
585815Sobrien- the resultant file is machine generated, cgen-dis.in isn't
685815Sobrien
785815SobrienCopyright 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
885815Sobrien
985815SobrienThis file is part of the GNU Binutils and GDB, the GNU debugger.
1085815Sobrien
1185815SobrienThis program is free software; you can redistribute it and/or modify
1285815Sobrienit under the terms of the GNU General Public License as published by
1385815Sobrienthe Free Software Foundation; either version 2, or (at your option)
1485815Sobrienany later version.
1585815Sobrien
1685815SobrienThis program is distributed in the hope that it will be useful,
1785815Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of
1885815SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1985815SobrienGNU General Public License for more details.
2085815Sobrien
2185815SobrienYou should have received a copy of the GNU General Public License
2285815Sobrienalong with this program; if not, write to the Free Software Foundation, Inc.,
2385815Sobrien59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
2485815Sobrien
2585815Sobrien/* ??? Eventually more and more of this stuff can go to cpu-independent files.
2685815Sobrien   Keep that in mind.  */
2785815Sobrien
2885815Sobrien#include "sysdep.h"
2985815Sobrien#include <stdio.h>
3085815Sobrien#include "ansidecl.h"
3185815Sobrien#include "dis-asm.h"
3285815Sobrien#include "bfd.h"
3385815Sobrien#include "symcat.h"
3485815Sobrien#include "@prefix@-desc.h"
3585815Sobrien#include "@prefix@-opc.h"
3685815Sobrien#include "opintl.h"
3785815Sobrien
3885815Sobrien/* Default text to print if an instruction isn't recognized.  */
3985815Sobrien#define UNKNOWN_INSN_MSG _("*unknown*")
4085815Sobrien
4185815Sobrienstatic void print_normal
4285815Sobrien     PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned int, bfd_vma, int));
4385815Sobrienstatic void print_address
4485815Sobrien     PARAMS ((CGEN_CPU_DESC, PTR, bfd_vma, unsigned int, bfd_vma, int));
4585815Sobrienstatic void print_keyword
4685815Sobrien     PARAMS ((CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned int));
4785815Sobrienstatic void print_insn_normal
4885815Sobrien     PARAMS ((CGEN_CPU_DESC, PTR, const CGEN_INSN *, CGEN_FIELDS *,
4985815Sobrien	      bfd_vma, int));
5089857Sobrienstatic int print_insn
5189857Sobrien     PARAMS ((CGEN_CPU_DESC, bfd_vma,  disassemble_info *, char *, unsigned));
5285815Sobrienstatic int default_print_insn
5385815Sobrien     PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *));
5489857Sobrienstatic int read_insn
5589857Sobrien     PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *, char *, int,
5689857Sobrien	      CGEN_EXTRACT_INFO *, unsigned long *));
5785815Sobrien
5885815Sobrien/* -- disassembler routines inserted here */
5985815Sobrien
6085815Sobrien/* Default print handler.  */
6185815Sobrien
6285815Sobrienstatic void
6385815Sobrienprint_normal (cd, dis_info, value, attrs, pc, length)
6485815Sobrien     CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
6585815Sobrien     PTR dis_info;
6685815Sobrien     long value;
6785815Sobrien     unsigned int attrs;
6885815Sobrien     bfd_vma pc ATTRIBUTE_UNUSED;
6985815Sobrien     int length ATTRIBUTE_UNUSED;
7085815Sobrien{
7185815Sobrien  disassemble_info *info = (disassemble_info *) dis_info;
7285815Sobrien
7385815Sobrien#ifdef CGEN_PRINT_NORMAL
7485815Sobrien  CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length);
7585815Sobrien#endif
7685815Sobrien
7785815Sobrien  /* Print the operand as directed by the attributes.  */
7885815Sobrien  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
7985815Sobrien    ; /* nothing to do */
8085815Sobrien  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
8185815Sobrien    (*info->fprintf_func) (info->stream, "%ld", value);
8285815Sobrien  else
8385815Sobrien    (*info->fprintf_func) (info->stream, "0x%lx", value);
8485815Sobrien}
8585815Sobrien
8685815Sobrien/* Default address handler.  */
8785815Sobrien
8885815Sobrienstatic void
8985815Sobrienprint_address (cd, dis_info, value, attrs, pc, length)
9085815Sobrien     CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
9185815Sobrien     PTR dis_info;
9285815Sobrien     bfd_vma value;
9385815Sobrien     unsigned int attrs;
9485815Sobrien     bfd_vma pc ATTRIBUTE_UNUSED;
9585815Sobrien     int length ATTRIBUTE_UNUSED;
9685815Sobrien{
9785815Sobrien  disassemble_info *info = (disassemble_info *) dis_info;
9885815Sobrien
9985815Sobrien#ifdef CGEN_PRINT_ADDRESS
10085815Sobrien  CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length);
10185815Sobrien#endif
10285815Sobrien
10385815Sobrien  /* Print the operand as directed by the attributes.  */
10485815Sobrien  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
10585815Sobrien    ; /* nothing to do */
10685815Sobrien  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
10785815Sobrien    (*info->print_address_func) (value, info);
10885815Sobrien  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
10985815Sobrien    (*info->print_address_func) (value, info);
11085815Sobrien  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
11185815Sobrien    (*info->fprintf_func) (info->stream, "%ld", (long) value);
11285815Sobrien  else
11385815Sobrien    (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
11485815Sobrien}
11585815Sobrien
11685815Sobrien/* Keyword print handler.  */
11785815Sobrien
11885815Sobrienstatic void
11985815Sobrienprint_keyword (cd, dis_info, keyword_table, value, attrs)
12085815Sobrien     CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
12185815Sobrien     PTR dis_info;
12285815Sobrien     CGEN_KEYWORD *keyword_table;
12385815Sobrien     long value;
12485815Sobrien     unsigned int attrs ATTRIBUTE_UNUSED;
12585815Sobrien{
12685815Sobrien  disassemble_info *info = (disassemble_info *) dis_info;
12785815Sobrien  const CGEN_KEYWORD_ENTRY *ke;
12885815Sobrien
12985815Sobrien  ke = cgen_keyword_lookup_value (keyword_table, value);
13085815Sobrien  if (ke != NULL)
13185815Sobrien    (*info->fprintf_func) (info->stream, "%s", ke->name);
13285815Sobrien  else
13385815Sobrien    (*info->fprintf_func) (info->stream, "???");
13485815Sobrien}
13585815Sobrien
13685815Sobrien/* Default insn printer.
13785815Sobrien
13885815Sobrien   DIS_INFO is defined as `PTR' so the disassembler needn't know anything
13985815Sobrien   about disassemble_info.  */
14085815Sobrien
14185815Sobrienstatic void
14285815Sobrienprint_insn_normal (cd, dis_info, insn, fields, pc, length)
14385815Sobrien     CGEN_CPU_DESC cd;
14485815Sobrien     PTR dis_info;
14585815Sobrien     const CGEN_INSN *insn;
14685815Sobrien     CGEN_FIELDS *fields;
14785815Sobrien     bfd_vma pc;
14885815Sobrien     int length;
14985815Sobrien{
15085815Sobrien  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
15185815Sobrien  disassemble_info *info = (disassemble_info *) dis_info;
15285815Sobrien  const CGEN_SYNTAX_CHAR_TYPE *syn;
15385815Sobrien
15485815Sobrien  CGEN_INIT_PRINT (cd);
15585815Sobrien
15685815Sobrien  for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
15785815Sobrien    {
15885815Sobrien      if (CGEN_SYNTAX_MNEMONIC_P (*syn))
15985815Sobrien	{
16085815Sobrien	  (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
16185815Sobrien	  continue;
16285815Sobrien	}
16385815Sobrien      if (CGEN_SYNTAX_CHAR_P (*syn))
16485815Sobrien	{
16585815Sobrien	  (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
16685815Sobrien	  continue;
16785815Sobrien	}
16885815Sobrien
16985815Sobrien      /* We have an operand.  */
17085815Sobrien      @arch@_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
17185815Sobrien				 fields, CGEN_INSN_ATTRS (insn), pc, length);
17285815Sobrien    }
17385815Sobrien}
17485815Sobrien
17585815Sobrien/* Subroutine of print_insn. Reads an insn into the given buffers and updates
17685815Sobrien   the extract info.
17785815Sobrien   Returns 0 if all is well, non-zero otherwise.  */
17889857Sobrien
17985815Sobrienstatic int
18085815Sobrienread_insn (cd, pc, info, buf, buflen, ex_info, insn_value)
18189857Sobrien     CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
18285815Sobrien     bfd_vma pc;
18385815Sobrien     disassemble_info *info;
18485815Sobrien     char *buf;
18585815Sobrien     int buflen;
18685815Sobrien     CGEN_EXTRACT_INFO *ex_info;
18785815Sobrien     unsigned long *insn_value;
18885815Sobrien{
18985815Sobrien  int status = (*info->read_memory_func) (pc, buf, buflen, info);
19085815Sobrien  if (status != 0)
19185815Sobrien    {
19285815Sobrien      (*info->memory_error_func) (status, pc, info);
19385815Sobrien      return -1;
19485815Sobrien    }
19585815Sobrien
19685815Sobrien  ex_info->dis_info = info;
19785815Sobrien  ex_info->valid = (1 << buflen) - 1;
19885815Sobrien  ex_info->insn_bytes = buf;
19985815Sobrien
20085815Sobrien  *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
20185815Sobrien  return 0;
20285815Sobrien}
20385815Sobrien
20485815Sobrien/* Utility to print an insn.
20585815Sobrien   BUF is the base part of the insn, target byte order, BUFLEN bytes long.
20685815Sobrien   The result is the size of the insn in bytes or zero for an unknown insn
20785815Sobrien   or -1 if an error occurs fetching data (memory_error_func will have
20885815Sobrien   been called).  */
20985815Sobrien
21085815Sobrienstatic int
21185815Sobrienprint_insn (cd, pc, info, buf, buflen)
21285815Sobrien     CGEN_CPU_DESC cd;
21385815Sobrien     bfd_vma pc;
21485815Sobrien     disassemble_info *info;
21585815Sobrien     char *buf;
21689857Sobrien     unsigned int buflen;
21785815Sobrien{
21889857Sobrien  CGEN_INSN_INT insn_value;
21985815Sobrien  const CGEN_INSN_LIST *insn_list;
22085815Sobrien  CGEN_EXTRACT_INFO ex_info;
22189857Sobrien  int basesize;
22285815Sobrien
22389857Sobrien  /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
22489857Sobrien  basesize = cd->base_insn_bitsize < buflen * 8 ?
22589857Sobrien                                     cd->base_insn_bitsize : buflen * 8;
22689857Sobrien  insn_value = cgen_get_insn_value (cd, buf, basesize);
22785815Sobrien
22889857Sobrien
22989857Sobrien  /* Fill in ex_info fields like read_insn would.  Don't actually call
23089857Sobrien     read_insn, since the incoming buffer is already read (and possibly
23189857Sobrien     modified a la m32r).  */
23289857Sobrien  ex_info.valid = (1 << buflen) - 1;
23389857Sobrien  ex_info.dis_info = info;
23489857Sobrien  ex_info.insn_bytes = buf;
23589857Sobrien
23685815Sobrien  /* The instructions are stored in hash lists.
23785815Sobrien     Pick the first one and keep trying until we find the right one.  */
23885815Sobrien
23985815Sobrien  insn_list = CGEN_DIS_LOOKUP_INSN (cd, buf, insn_value);
24085815Sobrien  while (insn_list != NULL)
24185815Sobrien    {
24285815Sobrien      const CGEN_INSN *insn = insn_list->insn;
24385815Sobrien      CGEN_FIELDS fields;
24485815Sobrien      int length;
24589857Sobrien      unsigned long insn_value_cropped;
24685815Sobrien
24785815Sobrien#ifdef CGEN_VALIDATE_INSN_SUPPORTED 
24889857Sobrien      /* Not needed as insn shouldn't be in hash lists if not supported.  */
24985815Sobrien      /* Supported by this cpu?  */
25085815Sobrien      if (! @arch@_cgen_insn_supported (cd, insn))
25185815Sobrien        {
25285815Sobrien          insn_list = CGEN_DIS_NEXT_INSN (insn_list);
25385815Sobrien	  continue;
25485815Sobrien        }
25585815Sobrien#endif
25685815Sobrien
25785815Sobrien      /* Basic bit mask must be correct.  */
25885815Sobrien      /* ??? May wish to allow target to defer this check until the extract
25985815Sobrien	 handler.  */
26089857Sobrien
26189857Sobrien      /* Base size may exceed this instruction's size.  Extract the
26289857Sobrien         relevant part from the buffer. */
26389857Sobrien      if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
26489857Sobrien	  (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
26589857Sobrien	insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn), 
26689857Sobrien					   info->endian == BFD_ENDIAN_BIG);
26789857Sobrien      else
26889857Sobrien	insn_value_cropped = insn_value;
26989857Sobrien
27089857Sobrien      if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
27185815Sobrien	  == CGEN_INSN_BASE_VALUE (insn))
27285815Sobrien	{
27385815Sobrien	  /* Printing is handled in two passes.  The first pass parses the
27485815Sobrien	     machine insn and extracts the fields.  The second pass prints
27585815Sobrien	     them.  */
27685815Sobrien
27785815Sobrien	  /* Make sure the entire insn is loaded into insn_value, if it
27885815Sobrien	     can fit.  */
27989857Sobrien	  if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
28089857Sobrien	      (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
28185815Sobrien	    {
28285815Sobrien	      unsigned long full_insn_value;
28385815Sobrien	      int rc = read_insn (cd, pc, info, buf,
28485815Sobrien				  CGEN_INSN_BITSIZE (insn) / 8,
28585815Sobrien				  & ex_info, & full_insn_value);
28685815Sobrien	      if (rc != 0)
28785815Sobrien		return rc;
28885815Sobrien	      length = CGEN_EXTRACT_FN (cd, insn)
28985815Sobrien		(cd, insn, &ex_info, full_insn_value, &fields, pc);
29085815Sobrien	    }
29185815Sobrien	  else
29285815Sobrien	    length = CGEN_EXTRACT_FN (cd, insn)
29389857Sobrien	      (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
29485815Sobrien
29585815Sobrien	  /* length < 0 -> error */
29685815Sobrien	  if (length < 0)
29785815Sobrien	    return length;
29885815Sobrien	  if (length > 0)
29985815Sobrien	    {
30085815Sobrien	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
30185815Sobrien	      /* length is in bits, result is in bytes */
30285815Sobrien	      return length / 8;
30385815Sobrien	    }
30485815Sobrien	}
30585815Sobrien
30685815Sobrien      insn_list = CGEN_DIS_NEXT_INSN (insn_list);
30785815Sobrien    }
30885815Sobrien
30985815Sobrien  return 0;
31085815Sobrien}
31185815Sobrien
31285815Sobrien/* Default value for CGEN_PRINT_INSN.
31385815Sobrien   The result is the size of the insn in bytes or zero for an unknown insn
31485815Sobrien   or -1 if an error occured fetching bytes.  */
31585815Sobrien
31685815Sobrien#ifndef CGEN_PRINT_INSN
31785815Sobrien#define CGEN_PRINT_INSN default_print_insn
31885815Sobrien#endif
31985815Sobrien
32085815Sobrienstatic int
32185815Sobriendefault_print_insn (cd, pc, info)
32285815Sobrien     CGEN_CPU_DESC cd;
32385815Sobrien     bfd_vma pc;
32485815Sobrien     disassemble_info *info;
32585815Sobrien{
32685815Sobrien  char buf[CGEN_MAX_INSN_SIZE];
32789857Sobrien  int buflen;
32885815Sobrien  int status;
32985815Sobrien
33089857Sobrien  /* Attempt to read the base part of the insn.  */
33189857Sobrien  buflen = cd->base_insn_bitsize / 8;
33289857Sobrien  status = (*info->read_memory_func) (pc, buf, buflen, info);
33385815Sobrien
33489857Sobrien  /* Try again with the minimum part, if min < base.  */
33589857Sobrien  if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
33689857Sobrien    {
33789857Sobrien      buflen = cd->min_insn_bitsize / 8;
33889857Sobrien      status = (*info->read_memory_func) (pc, buf, buflen, info);
33989857Sobrien    }
34089857Sobrien
34185815Sobrien  if (status != 0)
34285815Sobrien    {
34385815Sobrien      (*info->memory_error_func) (status, pc, info);
34485815Sobrien      return -1;
34585815Sobrien    }
34685815Sobrien
34789857Sobrien  return print_insn (cd, pc, info, buf, buflen);
34885815Sobrien}
34985815Sobrien
35085815Sobrien/* Main entry point.
35185815Sobrien   Print one instruction from PC on INFO->STREAM.
35285815Sobrien   Return the size of the instruction (in bytes).  */
35385815Sobrien
35485815Sobrienint
35585815Sobrienprint_insn_@arch@ (pc, info)
35685815Sobrien     bfd_vma pc;
35785815Sobrien     disassemble_info *info;
35885815Sobrien{
35985815Sobrien  static CGEN_CPU_DESC cd = 0;
36085815Sobrien  static int prev_isa;
36185815Sobrien  static int prev_mach;
36285815Sobrien  static int prev_endian;
36385815Sobrien  int length;
36485815Sobrien  int isa,mach;
36585815Sobrien  int endian = (info->endian == BFD_ENDIAN_BIG
36685815Sobrien		? CGEN_ENDIAN_BIG
36785815Sobrien		: CGEN_ENDIAN_LITTLE);
36885815Sobrien  enum bfd_architecture arch;
36985815Sobrien
37085815Sobrien  /* ??? gdb will set mach but leave the architecture as "unknown" */
37185815Sobrien#ifndef CGEN_BFD_ARCH
37285815Sobrien#define CGEN_BFD_ARCH bfd_arch_@arch@
37385815Sobrien#endif
37485815Sobrien  arch = info->arch;
37585815Sobrien  if (arch == bfd_arch_unknown)
37685815Sobrien    arch = CGEN_BFD_ARCH;
37789857Sobrien   
37889857Sobrien  /* There's no standard way to compute the machine or isa number
37985815Sobrien     so we leave it to the target.  */
38089857Sobrien#ifdef CGEN_COMPUTE_MACH
38189857Sobrien  mach = CGEN_COMPUTE_MACH (info);
38289857Sobrien#else
38389857Sobrien  mach = info->mach;
38489857Sobrien#endif
38589857Sobrien
38685815Sobrien#ifdef CGEN_COMPUTE_ISA
38785815Sobrien  isa = CGEN_COMPUTE_ISA (info);
38885815Sobrien#else
38991041Sobrien  isa = info->insn_sets;
39085815Sobrien#endif
39185815Sobrien
39285815Sobrien  /* If we've switched cpu's, close the current table and open a new one.  */
39385815Sobrien  if (cd
39485815Sobrien      && (isa != prev_isa
39585815Sobrien	  || mach != prev_mach
39685815Sobrien	  || endian != prev_endian))
39785815Sobrien    {
39885815Sobrien      @arch@_cgen_cpu_close (cd);
39985815Sobrien      cd = 0;
40085815Sobrien    }
40185815Sobrien
40285815Sobrien  /* If we haven't initialized yet, initialize the opcode table.  */
40385815Sobrien  if (! cd)
40485815Sobrien    {
40585815Sobrien      const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
40685815Sobrien      const char *mach_name;
40785815Sobrien
40885815Sobrien      if (!arch_type)
40985815Sobrien	abort ();
41085815Sobrien      mach_name = arch_type->printable_name;
41185815Sobrien
41285815Sobrien      prev_isa = isa;
41385815Sobrien      prev_mach = mach;
41485815Sobrien      prev_endian = endian;
41585815Sobrien      cd = @arch@_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
41685815Sobrien				 CGEN_CPU_OPEN_BFDMACH, mach_name,
41785815Sobrien				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
41885815Sobrien				 CGEN_CPU_OPEN_END);
41985815Sobrien      if (!cd)
42085815Sobrien	abort ();
42185815Sobrien      @arch@_cgen_init_dis (cd);
42285815Sobrien    }
42385815Sobrien
42485815Sobrien  /* We try to have as much common code as possible.
42585815Sobrien     But at this point some targets need to take over.  */
42685815Sobrien  /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
42785815Sobrien     but if not possible try to move this hook elsewhere rather than
42885815Sobrien     have two hooks.  */
42985815Sobrien  length = CGEN_PRINT_INSN (cd, pc, info);
43085815Sobrien  if (length > 0)
43185815Sobrien    return length;
43285815Sobrien  if (length < 0)
43385815Sobrien    return -1;
43485815Sobrien
43585815Sobrien  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
43685815Sobrien  return cd->default_insn_bitsize / 8;
43785815Sobrien}
438