head	1.1;
branch	1.1.1;
access;
symbols
	netbsd-11-0-RC4:1.1.1.5
	netbsd-11-0-RC3:1.1.1.5
	gdb-17-1:1.1.1.5
	netbsd-11-0-RC2:1.1.1.5
	netbsd-11-0-RC1:1.1.1.5
	gdb-16-3:1.1.1.5
	perseant-exfatfs-base-20250801:1.1.1.5
	netbsd-11:1.1.1.5.0.2
	netbsd-11-base:1.1.1.5
	netbsd-10-1-RELEASE:1.1.1.3
	gdb-15-1:1.1.1.5
	perseant-exfatfs-base-20240630:1.1.1.4
	perseant-exfatfs:1.1.1.4.0.2
	perseant-exfatfs-base:1.1.1.4
	netbsd-8-3-RELEASE:1.1.1.1
	netbsd-9-4-RELEASE:1.1.1.2
	netbsd-10-0-RELEASE:1.1.1.3
	netbsd-10-0-RC6:1.1.1.3
	netbsd-10-0-RC5:1.1.1.3
	netbsd-10-0-RC4:1.1.1.3
	netbsd-10-0-RC3:1.1.1.3
	netbsd-10-0-RC2:1.1.1.3
	netbsd-10-0-RC1:1.1.1.3
	gdb-13-2:1.1.1.4
	netbsd-10:1.1.1.3.0.6
	netbsd-10-base:1.1.1.3
	netbsd-9-3-RELEASE:1.1.1.2
	cjep_sun2x-base1:1.1.1.3
	cjep_sun2x:1.1.1.3.0.4
	cjep_sun2x-base:1.1.1.3
	cjep_staticlib_x-base1:1.1.1.3
	netbsd-9-2-RELEASE:1.1.1.2
	cjep_staticlib_x:1.1.1.3.0.2
	cjep_staticlib_x-base:1.1.1.3
	netbsd-9-1-RELEASE:1.1.1.2
	GDB-11-0-50-20200914-git:1.1.1.3
	phil-wifi-20200421:1.1.1.2
	phil-wifi-20200411:1.1.1.2
	is-mlppp:1.1.1.2.0.8
	is-mlppp-base:1.1.1.2
	phil-wifi-20200406:1.1.1.2
	netbsd-8-2-RELEASE:1.1.1.1
	netbsd-9-0-RELEASE:1.1.1.2
	netbsd-9-0-RC2:1.1.1.2
	netbsd-9-0-RC1:1.1.1.2
	phil-wifi-20191119:1.1.1.2
	netbsd-9:1.1.1.2.0.6
	netbsd-9-base:1.1.1.2
	phil-wifi-20190609:1.1.1.2
	netbsd-8-1-RELEASE:1.1.1.1
	gdb-8-3:1.1.1.2
	netbsd-8-1-RC1:1.1.1.1
	pgoyette-compat-merge-20190127:1.1.1.2
	pgoyette-compat-20190127:1.1.1.2
	pgoyette-compat-20190118:1.1.1.2
	pgoyette-compat-1226:1.1.1.2
	pgoyette-compat-1126:1.1.1.2
	pgoyette-compat-1020:1.1.1.2
	pgoyette-compat-0930:1.1.1.2
	pgoyette-compat-0906:1.1.1.2
	netbsd-7-2-RELEASE:1.1.1.1
	pgoyette-compat-0728:1.1.1.2
	netbsd-8-0-RELEASE:1.1.1.1
	phil-wifi:1.1.1.2.0.4
	phil-wifi-base:1.1.1.2
	pgoyette-compat-0625:1.1.1.2
	netbsd-8-0-RC2:1.1.1.1
	pgoyette-compat-0521:1.1.1.2
	pgoyette-compat-0502:1.1.1.2
	pgoyette-compat-0422:1.1.1.2
	netbsd-8-0-RC1:1.1.1.1
	pgoyette-compat-0415:1.1.1.2
	pgoyette-compat-0407:1.1.1.2
	pgoyette-compat-0330:1.1.1.2
	pgoyette-compat-0322:1.1.1.2
	pgoyette-compat-0315:1.1.1.2
	netbsd-7-1-2-RELEASE:1.1.1.1
	pgoyette-compat:1.1.1.2.0.2
	pgoyette-compat-base:1.1.1.2
	netbsd-7-1-1-RELEASE:1.1.1.1
	gdb-8-0-1:1.1.1.2
	matt-nb8-mediatek:1.1.1.1.0.26
	matt-nb8-mediatek-base:1.1.1.1
	perseant-stdc-iso10646:1.1.1.1.0.24
	perseant-stdc-iso10646-base:1.1.1.1
	netbsd-8:1.1.1.1.0.22
	netbsd-8-base:1.1.1.1
	prg-localcount2-base3:1.1.1.1
	prg-localcount2-base2:1.1.1.1
	prg-localcount2-base1:1.1.1.1
	prg-localcount2:1.1.1.1.0.20
	prg-localcount2-base:1.1.1.1
	pgoyette-localcount-20170426:1.1.1.1
	bouyer-socketcan-base1:1.1.1.1
	pgoyette-localcount-20170320:1.1.1.1
	netbsd-7-1:1.1.1.1.0.18
	netbsd-7-1-RELEASE:1.1.1.1
	netbsd-7-1-RC2:1.1.1.1
	netbsd-7-nhusb-base-20170116:1.1.1.1
	bouyer-socketcan:1.1.1.1.0.16
	bouyer-socketcan-base:1.1.1.1
	pgoyette-localcount-20170107:1.1.1.1
	netbsd-7-1-RC1:1.1.1.1
	pgoyette-localcount-20161104:1.1.1.1
	netbsd-7-0-2-RELEASE:1.1.1.1
	gdb-7-12:1.1.1.1
	localcount-20160914:1.1.1.1
	netbsd-7-nhusb:1.1.1.1.0.14
	netbsd-7-nhusb-base:1.1.1.1
	pgoyette-localcount-20160806:1.1.1.1
	pgoyette-localcount-20160726:1.1.1.1
	pgoyette-localcount:1.1.1.1.0.12
	pgoyette-localcount-base:1.1.1.1
	netbsd-7-0-1-RELEASE:1.1.1.1
	gdb-7-10-1:1.1.1.1
	netbsd-7-0:1.1.1.1.0.10
	netbsd-7-0-RELEASE:1.1.1.1
	gdb-7-9-1:1.1.1.1
	netbsd-7-0-RC3:1.1.1.1
	netbsd-7-0-RC2:1.1.1.1
	netbsd-7-0-RC1:1.1.1.1
	tls-maxphys-base:1.1.1.1
	tls-maxphys:1.1.1.1.0.8
	netbsd-7:1.1.1.1.0.6
	netbsd-7-base:1.1.1.1
	gdb-7-7-1:1.1.1.1
	yamt-pagecache:1.1.1.1.0.4
	yamt-pagecache-base9:1.1.1.1
	tls-earlyentropy:1.1.1.1.0.2
	tls-earlyentropy-base:1.1.1.1
	riastradh-xf86-video-intel-2-7-1-pre-2-21-15:1.1.1.1
	riastradh-drm2-base3:1.1.1.1
	gdb-7-6-1:1.1.1.1
	FSF:1.1.1;
locks; strict;
comment	@# @;


1.1
date	2013.10.03.15.44.18;	author christos;	state Exp;
branches
	1.1.1.1;
next	;
commitid	m91IYDmHTME7wR7x;

1.1.1.1
date	2013.10.03.15.44.18;	author christos;	state Exp;
branches
	1.1.1.1.4.1
	1.1.1.1.8.1;
next	1.1.1.2;
commitid	m91IYDmHTME7wR7x;

1.1.1.2
date	2017.11.28.18.17.58;	author christos;	state Exp;
branches;
next	1.1.1.3;
commitid	rE0LxHFEMFCrCPgA;

1.1.1.3
date	2020.09.15.01.42.15;	author christos;	state Exp;
branches;
next	1.1.1.4;
commitid	N511ReXja24bg5oC;

1.1.1.4
date	2023.07.30.22.44.40;	author christos;	state Exp;
branches
	1.1.1.4.2.1;
next	1.1.1.5;
commitid	HEIv4Prd74m1wSyE;

1.1.1.5
date	2024.08.12.21.37.49;	author christos;	state Exp;
branches;
next	;
commitid	dWD83H91pFit0AlF;

1.1.1.1.4.1
date	2013.10.03.15.44.18;	author yamt;	state dead;
branches;
next	1.1.1.1.4.2;
commitid	SRuOnF9k1i4dcyBx;

1.1.1.1.4.2
date	2014.05.22.16.00.32;	author yamt;	state Exp;
branches;
next	;
commitid	SRuOnF9k1i4dcyBx;

1.1.1.1.8.1
date	2013.10.03.15.44.18;	author tls;	state dead;
branches;
next	1.1.1.1.8.2;
commitid	jTnpym9Qu0o4R1Nx;

1.1.1.1.8.2
date	2014.08.19.23.58.39;	author tls;	state Exp;
branches;
next	;
commitid	jTnpym9Qu0o4R1Nx;

1.1.1.4.2.1
date	2025.08.02.05.26.39;	author perseant;	state Exp;
branches;
next	;
commitid	23j6GFaDws3O875G;


desc
@@


1.1
log
@Initial revision
@
text
@/* MeP opcode support.  -*- C -*-
   Copyright 2011 Free Software Foundation, Inc.

   Contributed by Red Hat Inc;

   This file is part of the GNU Binutils.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   MA 02110-1301, USA.  */

/* -- opc.h */

#undef  CGEN_DIS_HASH_SIZE
#define CGEN_DIS_HASH_SIZE 1

#undef  CGEN_DIS_HASH
#define CGEN_DIS_HASH(buffer, insn) 0

#define CGEN_VERBOSE_ASSEMBLER_ERRORS

typedef struct
{
  char * name;
  int    config_enum;
  unsigned cpu_flag;
  int    big_endian;
  int    vliw_bits;
  CGEN_ATTR_VALUE_BITSET_TYPE cop16_isa;
  CGEN_ATTR_VALUE_BITSET_TYPE cop32_isa;
  CGEN_ATTR_VALUE_BITSET_TYPE cop48_isa;
  CGEN_ATTR_VALUE_BITSET_TYPE cop64_isa;
  CGEN_ATTR_VALUE_BITSET_TYPE cop_isa;
  CGEN_ATTR_VALUE_BITSET_TYPE core_isa;
  unsigned int option_mask;
} mep_config_map_struct;

extern mep_config_map_struct mep_config_map[];
extern int mep_config_index;

extern void init_mep_all_core_isas_mask (void);
extern void init_mep_all_cop_isas_mask  (void);
extern CGEN_ATTR_VALUE_BITSET_TYPE mep_cop_isa  (void);

#define MEP_CONFIG     (mep_config_map[mep_config_index].config_enum)
#define MEP_CPU        (mep_config_map[mep_config_index].cpu_flag)
#define MEP_OMASK      (mep_config_map[mep_config_index].option_mask)
#define MEP_VLIW       (mep_config_map[mep_config_index].vliw_bits > 0)
#define MEP_VLIW32     (mep_config_map[mep_config_index].vliw_bits == 32)
#define MEP_VLIW64     (mep_config_map[mep_config_index].vliw_bits == 64)
#define MEP_COP16_ISA  (mep_config_map[mep_config_index].cop16_isa)
#define MEP_COP32_ISA  (mep_config_map[mep_config_index].cop32_isa)
#define MEP_COP48_ISA  (mep_config_map[mep_config_index].cop48_isa)
#define MEP_COP64_ISA  (mep_config_map[mep_config_index].cop64_isa)
#define MEP_COP_ISA    (mep_config_map[mep_config_index].cop_isa)
#define MEP_CORE_ISA   (mep_config_map[mep_config_index].core_isa)

/* begin-cop-ip-supported-defines */
#define MEP_IVC2_SUPPORTED 1
/* end-cop-ip-supported-defines */

extern int mep_insn_supported_by_isa (const CGEN_INSN *, CGEN_ATTR_VALUE_BITSET_TYPE *);

/* A mask for all ISAs executed by the core.  */
#define MEP_ALL_CORE_ISAS_MASK mep_all_core_isas_mask
extern CGEN_ATTR_VALUE_BITSET_TYPE mep_all_core_isas_mask;

#define MEP_INSN_CORE_P(insn) ( \
  init_mep_all_core_isas_mask (), \
  mep_insn_supported_by_isa (insn, & MEP_ALL_CORE_ISAS_MASK) \
)

/* A mask for all ISAs executed by a VLIW coprocessor.  */
#define MEP_ALL_COP_ISAS_MASK mep_all_cop_isas_mask 
extern CGEN_ATTR_VALUE_BITSET_TYPE mep_all_cop_isas_mask;

#define MEP_INSN_COP_P(insn) ( \
  init_mep_all_cop_isas_mask (), \
  mep_insn_supported_by_isa (insn, & MEP_ALL_COP_ISAS_MASK) \
)

extern int mep_cgen_insn_supported (CGEN_CPU_DESC, const CGEN_INSN *);
extern int mep_cgen_insn_supported_asm (CGEN_CPU_DESC, const CGEN_INSN *);

/* -- asm.c */

#include "elf/mep.h"

#define CGEN_VALIDATE_INSN_SUPPORTED
#define mep_cgen_insn_supported mep_cgen_insn_supported_asm

       const char * parse_csrn       (CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *);
       const char * parse_tpreg      (CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *);
       const char * parse_spreg      (CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *);
       const char * parse_mep_align  (CGEN_CPU_DESC, const char **, enum cgen_operand_type, long *);
       const char * parse_mep_alignu (CGEN_CPU_DESC, const char **, enum cgen_operand_type, unsigned long *);
static const char * parse_signed16   (CGEN_CPU_DESC, const char **, int, long *);
static const char * parse_signed16_range   (CGEN_CPU_DESC, const char **, int, long *) ATTRIBUTE_UNUSED;
static const char * parse_unsigned16 (CGEN_CPU_DESC, const char **, int, unsigned long *);
static const char * parse_unsigned16_range (CGEN_CPU_DESC, const char **, int, unsigned long *) ATTRIBUTE_UNUSED;
static const char * parse_lo16       (CGEN_CPU_DESC, const char **, int, long *, long);
static const char * parse_unsigned7  (CGEN_CPU_DESC, const char **, enum cgen_operand_type, unsigned long *);
static const char * parse_zero       (CGEN_CPU_DESC, const char **, int, long *);

const char *
parse_csrn (CGEN_CPU_DESC cd, const char **strp,
	    CGEN_KEYWORD *keyword_table, long *field)
{
  const char *err;
  unsigned long value;

  err = cgen_parse_keyword (cd, strp, keyword_table, field);
  if (!err)
    return NULL;

  err = cgen_parse_unsigned_integer (cd, strp, MEP_OPERAND_CSRN_IDX, & value);
  if (err)
    return err;
  *field = value;
  return NULL;
}

/* begin-cop-ip-parse-handlers */
static const char *
parse_ivc2_cr (CGEN_CPU_DESC,
	const char **,
	CGEN_KEYWORD *,
	long *) ATTRIBUTE_UNUSED;
static const char *
parse_ivc2_cr (CGEN_CPU_DESC cd,
	const char **strp,
	CGEN_KEYWORD *keyword_table  ATTRIBUTE_UNUSED,
	long *field)
{
  return cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_cr_ivc2, field);
}
static const char *
parse_ivc2_ccr (CGEN_CPU_DESC,
	const char **,
	CGEN_KEYWORD *,
	long *) ATTRIBUTE_UNUSED;
static const char *
parse_ivc2_ccr (CGEN_CPU_DESC cd,
	const char **strp,
	CGEN_KEYWORD *keyword_table  ATTRIBUTE_UNUSED,
	long *field)
{
  return cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_ccr_ivc2, field);
}
/* end-cop-ip-parse-handlers */

const char *
parse_tpreg (CGEN_CPU_DESC cd, const char ** strp,
	     CGEN_KEYWORD *keyword_table, long *field)
{
  const char *err;

  err = cgen_parse_keyword (cd, strp, keyword_table, field);
  if (err)
    return err;
  if (*field != 13)
    return _("Only $tp or $13 allowed for this opcode");
  return NULL;
}

const char *
parse_spreg (CGEN_CPU_DESC cd, const char ** strp,
	     CGEN_KEYWORD *keyword_table, long *field)
{
  const char *err;

  err = cgen_parse_keyword (cd, strp, keyword_table, field);
  if (err)
    return err;
  if (*field != 15)
    return _("Only $sp or $15 allowed for this opcode");
  return NULL;
}

const char *
parse_mep_align (CGEN_CPU_DESC cd, const char ** strp,
		 enum cgen_operand_type type, long *field)
{
  long lsbs = 0;
  const char *err;

  switch (type)
    {
    case MEP_OPERAND_PCREL8A2:
    case MEP_OPERAND_PCREL12A2:
    case MEP_OPERAND_PCREL17A2:
    case MEP_OPERAND_PCREL24A2:
      err = cgen_parse_signed_integer   (cd, strp, type, field);
      break;
    case MEP_OPERAND_PCABS24A2:
    case MEP_OPERAND_UDISP7:
    case MEP_OPERAND_UDISP7A2:
    case MEP_OPERAND_UDISP7A4:
    case MEP_OPERAND_UIMM7A4:
    case MEP_OPERAND_ADDR24A4:
      err = cgen_parse_unsigned_integer (cd, strp, type, (unsigned long *) field);
      break;
    default:
      abort();
    }
  if (err)
    return err;
  switch (type)
    {
    case MEP_OPERAND_UDISP7:
      lsbs = 0;
      break;
    case MEP_OPERAND_PCREL8A2:
    case MEP_OPERAND_PCREL12A2:
    case MEP_OPERAND_PCREL17A2:
    case MEP_OPERAND_PCREL24A2:
    case MEP_OPERAND_PCABS24A2:
    case MEP_OPERAND_UDISP7A2:
      lsbs = *field & 1;
      break;
    case MEP_OPERAND_UDISP7A4:
    case MEP_OPERAND_UIMM7A4:
    case MEP_OPERAND_ADDR24A4:
      lsbs = *field & 3;
      break;
      lsbs = *field & 7;
      break;
    default:
      /* Safe assumption?  */
      abort ();
    }
  if (lsbs)
    return "Value is not aligned enough";
  return NULL;
}

const char *
parse_mep_alignu (CGEN_CPU_DESC cd, const char ** strp,
		 enum cgen_operand_type type, unsigned long *field)
{
  return parse_mep_align (cd, strp, type, (long *) field);
}


/* Handle %lo(), %tpoff(), %sdaoff(), %hi(), and other signed
   constants in a signed context.  */

static const char *
parse_signed16 (CGEN_CPU_DESC cd,
		const char **strp,
		int opindex,
		long *valuep)
{
  return parse_lo16 (cd, strp, opindex, valuep, 1);
}

static const char *
parse_lo16 (CGEN_CPU_DESC cd,
	    const char **strp,
	    int opindex,
	    long *valuep,
	    long signedp)
{
  const char *errmsg;
  enum cgen_parse_operand_result result_type;
  bfd_vma value;

  if (strncasecmp (*strp, "%lo(", 4) == 0)
    {
      *strp += 4;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_LOW16,
				   & result_type, & value);
      if (**strp != ')')
	return _("missing `)'");
      ++*strp;
      if (errmsg == NULL
	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
	value &= 0xffff;
      if (signedp)
	*valuep = (long)(short) value;
      else
	*valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%hi(", 4) == 0)
    {
      *strp += 4;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_HI16S,
				   & result_type, & value);
      if (**strp != ')')
	return _("missing `)'");
      ++*strp;
      if (errmsg == NULL
	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
	value = (value + 0x8000) >> 16;
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%uhi(", 5) == 0)
    {
      *strp += 5;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_HI16U,
				   & result_type, & value);
      if (**strp != ')')
	return _("missing `)'");
      ++*strp;
      if (errmsg == NULL
	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
	value = value >> 16;
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%sdaoff(", 8) == 0)
    {
      *strp += 8;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_GPREL,
				   NULL, & value);
      if (**strp != ')')
	return _("missing `)'");
      ++*strp;
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%tpoff(", 7) == 0)
    {
      *strp += 7;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_TPREL,
				   NULL, & value);
      if (**strp != ')')
	return _("missing `)'");
      ++*strp;
      *valuep = value;
      return errmsg;
    }

  if (**strp == '%')
    return _("invalid %function() here");

  return cgen_parse_signed_integer (cd, strp, opindex, valuep);
}

static const char *
parse_unsigned16 (CGEN_CPU_DESC cd,
		  const char **strp,
		  int opindex,
		  unsigned long *valuep)
{
  return parse_lo16 (cd, strp, opindex, (long *) valuep, 0);
}

static const char *
parse_signed16_range (CGEN_CPU_DESC cd,
		      const char **strp,
		      int opindex,
		      signed long *valuep)
{
  const char *errmsg = 0;
  signed long value;

  errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value);
  if (errmsg)
    return errmsg;

  if (value < -32768 || value > 32767)
    return _("Immediate is out of range -32768 to 32767");

  *valuep = value;
  return 0;
}

static const char *
parse_unsigned16_range (CGEN_CPU_DESC cd,
			const char **strp,
			int opindex,
			unsigned long *valuep)
{
  const char *errmsg = 0;
  unsigned long value;

  errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, & value);
  if (errmsg)
    return errmsg;

  if (value > 65535)
    return _("Immediate is out of range 0 to 65535");

  *valuep = value;
  return 0;
}

/* A special case of parse_signed16 which accepts only the value zero.  */

static const char *
parse_zero (CGEN_CPU_DESC cd, const char **strp, int opindex, long *valuep)
{
  const char *errmsg;
  enum cgen_parse_operand_result result_type;
  bfd_vma value;

  /*fprintf(stderr, "dj: signed parse opindex `%s'\n", *strp);*/

  /* Prevent ($ry) from being attempted as an expression on 'sw $rx,($ry)'.
     It will fail and cause ry to be listed as an undefined symbol in the
     listing.  */
  if (strncmp (*strp, "($", 2) == 0)
    return "not zero"; /* any string will do -- will never be seen.  */

  if (strncasecmp (*strp, "%lo(", 4) == 0)
    {
      *strp += 4;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_LOW16,
				   &result_type, &value);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      if (errmsg == NULL
	  && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
	return "not zero"; /* any string will do -- will never be seen.  */
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%hi(", 4) == 0)
    {
      *strp += 4;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_HI16S,
				   &result_type, &value);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      if (errmsg == NULL
	  && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
	return "not zero"; /* any string will do -- will never be seen.  */
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%uhi(", 5) == 0)
    {
      *strp += 5;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_HI16U,
				   &result_type, &value);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      if (errmsg == NULL
	  && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
	return "not zero"; /* any string will do -- will never be seen.  */
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%sdaoff(", 8) == 0)
    {
      *strp += 8;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_GPREL,
				   &result_type, &value);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      if (errmsg == NULL
	  && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
	return "not zero"; /* any string will do -- will never be seen.  */
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%tpoff(", 7) == 0)
    {
      *strp += 7;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_TPREL,
				   &result_type, &value);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      if (errmsg == NULL
	  && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
	return "not zero"; /* any string will do -- will never be seen.  */
      *valuep = value;
      return errmsg;
    }

  if (**strp == '%')
    return "invalid %function() here";

  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_NONE,
			       &result_type, &value);
  if (errmsg == NULL
      && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
    return "not zero"; /* any string will do -- will never be seen.  */

  return errmsg;
}

static const char *
parse_unsigned7 (CGEN_CPU_DESC cd, const char **strp,
		 enum cgen_operand_type opindex, unsigned long *valuep)
{
  const char *errmsg;
  bfd_vma value;

  /* fprintf(stderr, "dj: unsigned7 parse `%s'\n", *strp); */

  if (strncasecmp (*strp, "%tpoff(", 7) == 0)
    {
      int reloc;
      *strp += 7;
      switch (opindex)
	{
	case MEP_OPERAND_UDISP7:
	  reloc = BFD_RELOC_MEP_TPREL7;
	  break;
	case MEP_OPERAND_UDISP7A2:
	  reloc = BFD_RELOC_MEP_TPREL7A2;
	  break;
	case MEP_OPERAND_UDISP7A4:
	  reloc = BFD_RELOC_MEP_TPREL7A4;
	  break;
	default:
	  /* Safe assumption?  */
	  abort (); 
	}
      errmsg = cgen_parse_address (cd, strp, opindex, reloc,
				   NULL, &value);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      *valuep = value;
      return errmsg;
    }

  if (**strp == '%')
    return _("invalid %function() here");

  return parse_mep_alignu (cd, strp, opindex, valuep);
}

static ATTRIBUTE_UNUSED const char *
parse_cdisp10 (CGEN_CPU_DESC cd,
	       const char **strp,
	       int opindex,
	       long *valuep)
{
  const char *errmsg = 0;
  signed long value;
  long have_zero = 0;
  int wide = 0;
  int alignment;

  switch (opindex)
    {
    case MEP_OPERAND_CDISP10A4:
      alignment = 2;
      break;
    case MEP_OPERAND_CDISP10A2:
      alignment = 1;
      break;
    case MEP_OPERAND_CDISP10:
    default:
      alignment = 0;
      break;
    }

  if ((MEP_CPU & EF_MEP_CPU_MASK) == EF_MEP_CPU_C5)
    wide = 1;

  if (strncmp (*strp, "0x0", 3) == 0 
      || (**strp == '0' && *(*strp + 1) != 'x'))
    have_zero = 1;

  errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value);
  if (errmsg)
    return errmsg;

  if (wide)
    {
      if (value < -512 || value > 511)
	return _("Immediate is out of range -512 to 511");
    }
  else
    {
      if (value < -128 || value > 127)
	return _("Immediate is out of range -128 to 127");
    }

  if (value & ((1<<alignment)-1))
    return _("Value is not aligned enough");

  /* If this field may require a relocation then use larger dsp16.  */
  if (! have_zero && value == 0)
    return (wide ? _("Immediate is out of range -512 to 511")
	    : _("Immediate is out of range -128 to 127"));

  *valuep = value;
  return 0;
}

/* BEGIN LIGHTWEIGHT MACRO PROCESSOR.  */

#define MAXARGS 9

typedef struct
{
  char *name;
  char *expansion;
}  macro;

typedef struct
{
  const char *start;
  int len;
} arg;

macro macros[] =
{
  { "sizeof", "(`1.end + (- `1))"},
  { "startof", "(`1 | 0)" },
  { "align4", "(`1&(~3))"},
/*{ "hi", "(((`1+0x8000)>>16) & 0xffff)" },  */
/*{ "lo", "(`1 & 0xffff)" },  */
/*{ "sdaoff", "((`1-__sdabase) & 0x7f)"},  */
/*{ "tpoff", "((`1-__tpbase) & 0x7f)"},  */
  { 0,0 }
};

static char  * expand_string    (const char *, int);

static const char *
mep_cgen_expand_macros_and_parse_operand
  (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);

static char *
str_append (char *dest, const char *input, int len)
{  
  char *new_dest;
  int oldlen;

  if (len == 0)
    return dest;
  /* printf("str_append: <<%s>>, <<%s>>, %d\n", dest, input, len); */
  oldlen = (dest ? strlen(dest) : 0);
  new_dest = realloc (dest, oldlen + len + 1);
  memset (new_dest + oldlen, 0, len + 1);
  return strncat (new_dest, input, len);
}

static macro *
lookup_macro (const char *name)
{
  macro *m;

  for (m = macros; m->name; ++m)
    if (strncmp (m->name, name, strlen(m->name)) == 0)
      return m;

  return 0;
}

static char *
expand_macro (arg *args, int narg, macro *mac)
{
  char *result = 0, *rescanned_result = 0;
  char *e = mac->expansion;
  char *mark = e;
  int mac_arg = 0;

  /*  printf("expanding macro %s with %d args\n", mac->name, narg + 1); */
  while (*e)
    {
      if (*e == '`' && 
	  (*e+1) && 
	  ((*(e + 1) - '1') <= MAXARGS) &&
	  ((*(e + 1) - '1') <= narg))
	{
	  result = str_append (result, mark, e - mark);
	  mac_arg = (*(e + 1) - '1');
	  /* printf("replacing `%d with %s\n", mac_arg+1, args[mac_arg].start); */
	  result = str_append (result, args[mac_arg].start, args[mac_arg].len);
	  ++e;
	  mark = e+1;
	}
      ++e;
    }

  if (mark != e)
    result = str_append (result, mark, e - mark);

  if (result)
    {
      rescanned_result = expand_string (result, 0);
      free (result);
      return rescanned_result;
    }
  else 
    return result;
}

#define IN_TEXT 0
#define IN_ARGS 1

static char *
expand_string (const char *in, int first_only)
{
  int num_expansions = 0;
  int depth = 0;
  int narg = -1;
  arg args[MAXARGS];
  int state = IN_TEXT;
  const char *mark = in;
  macro *pmacro = NULL;
  char *expansion = 0;
  char *result = 0;

  while (*in)
    {
      switch (state)
	{
	case IN_TEXT:
	  if (*in == '%' && *(in + 1) && (!first_only || num_expansions == 0)) 
	    {	      
	      pmacro = lookup_macro (in + 1);
	      if (pmacro)
		{
		  /* printf("entering state %d at '%s'...\n", state, in); */
		  result = str_append (result, mark, in - mark);
		  mark = in;
		  in += 1 + strlen (pmacro->name);
		  while (*in == ' ') ++in;
		  if (*in != '(')
		    {
		      state = IN_TEXT;		      
		      pmacro = NULL;
		    }
		  else
		    {
		      state = IN_ARGS;
		      narg = 0;
		      args[narg].start = in + 1;
		      args[narg].len = 0;
		      mark = in + 1;	      		      
		    }
		}
	    }
	  break;
	case IN_ARGS:
	  if (depth == 0)
	    {
	      switch (*in)
		{
		case ',':
		  narg++;
		  args[narg].start = (in + 1);
		  args[narg].len = 0;
		  break;
		case ')':
		  state = IN_TEXT;
		  /* printf("entering state %d at '%s'...\n", state, in); */
		  if (pmacro)
		    {
		      expansion = 0;
		      expansion = expand_macro (args, narg, pmacro);
		      num_expansions++;
		      if (expansion)
			{
			  result = str_append (result, expansion, strlen (expansion));
			  free (expansion);
			}
		    }
		  else
		    {
		      result = str_append (result, mark, in - mark);
		    }
		  pmacro = NULL;
		  mark = in + 1;
		  break;
		case '(':
		  depth++;
		default:
		  args[narg].len++;
		  break;		  
		}
	    } 
	  else
	    {
	      if (*in == ')')
		depth--;
	      if (narg > -1)
		args[narg].len++;
	    }
	  
	}
      ++in;
    }
  
  if (mark != in)
    result = str_append (result, mark, in - mark);
  
  return result;
}

#undef IN_ARGS
#undef IN_TEXT
#undef MAXARGS


/* END LIGHTWEIGHT MACRO PROCESSOR.  */

const char * mep_cgen_parse_operand
  (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);

const char *
mep_cgen_expand_macros_and_parse_operand (CGEN_CPU_DESC cd, int opindex,
					  const char ** strp_in, CGEN_FIELDS * fields)
{
  const char * errmsg = NULL;
  char *str = 0, *hold = 0;
  const char **strp = 0;

  /* Set up a new pointer to macro-expanded string.  */
  str = expand_string (*strp_in, 1);
  /* fprintf (stderr, " expanded <<%s>> to <<%s>>\n", *strp_in, str); */

  hold = str;
  strp = (const char **)(&str);

  errmsg = mep_cgen_parse_operand (cd, opindex, strp, fields);

  /* Now work out the advance.  */
  if (strlen (str) == 0)
    *strp_in += strlen (*strp_in);

  else
    {
      if (strstr (*strp_in, str))
	/* A macro-expansion was pulled off the front.  */
	*strp_in = strstr (*strp_in, str);  
      else
	/* A non-macro-expansion was pulled off the front.  */
	*strp_in += (str - hold); 
    }

  if (hold)
    free (hold);

  return errmsg;
}

#define CGEN_ASM_INIT_HOOK (cd->parse_operand = mep_cgen_expand_macros_and_parse_operand); 

/* -- dis.c */

#include "elf/mep.h"
#include "elf-bfd.h"

#define CGEN_VALIDATE_INSN_SUPPORTED

static void print_tpreg (CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned int);
static void print_spreg (CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned int);

static void
print_tpreg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, PTR dis_info,
	     CGEN_KEYWORD *table ATTRIBUTE_UNUSED, long val ATTRIBUTE_UNUSED,
	     unsigned int flags ATTRIBUTE_UNUSED)
{
  disassemble_info *info = (disassemble_info *) dis_info;

  (*info->fprintf_func) (info->stream, "$tp");
}

static void
print_spreg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, PTR dis_info, 
	     CGEN_KEYWORD *table ATTRIBUTE_UNUSED, long val ATTRIBUTE_UNUSED,
	     unsigned int flags ATTRIBUTE_UNUSED)
{
  disassemble_info *info = (disassemble_info *) dis_info;

  (*info->fprintf_func) (info->stream, "$sp");
}

/* begin-cop-ip-print-handlers */
static void
print_ivc2_cr (CGEN_CPU_DESC,
	void *,
	CGEN_KEYWORD *,
	long,
	unsigned int) ATTRIBUTE_UNUSED;
static void
print_ivc2_cr (CGEN_CPU_DESC cd,
	void *dis_info,
	CGEN_KEYWORD *keyword_table ATTRIBUTE_UNUSED,
	long value,
	unsigned int attrs)
{
  print_keyword (cd, dis_info, & mep_cgen_opval_h_cr_ivc2, value, attrs);
}
static void
print_ivc2_ccr (CGEN_CPU_DESC,
	void *,
	CGEN_KEYWORD *,
	long,
	unsigned int) ATTRIBUTE_UNUSED;
static void
print_ivc2_ccr (CGEN_CPU_DESC cd,
	void *dis_info,
	CGEN_KEYWORD *keyword_table ATTRIBUTE_UNUSED,
	long value,
	unsigned int attrs)
{
  print_keyword (cd, dis_info, & mep_cgen_opval_h_ccr_ivc2, value, attrs);
}
/* end-cop-ip-print-handlers */

/************************************************************\
*********************** Experimental *************************
\************************************************************/

#undef  CGEN_PRINT_INSN
#define CGEN_PRINT_INSN mep_print_insn

static int
mep_print_vliw_insns (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info,
		      bfd_byte *buf, int corelength, int copro1length,
		      int copro2length ATTRIBUTE_UNUSED)
{
  int i;
  int status = 0;
  /* char insnbuf[CGEN_MAX_INSN_SIZE]; */
  bfd_byte insnbuf[64];

  /* If corelength > 0 then there is a core insn present. It
     will be at the beginning of the buffer.  After printing
     the core insn, we need to print the + on the next line.  */
  if (corelength > 0)
    {
      int my_status = 0;
	 
      for (i = 0; i < corelength; i++ )
	insnbuf[i] = buf[i];
      cd->isas = & MEP_CORE_ISA;
	 
      my_status = print_insn (cd, pc, info, insnbuf, corelength);
      if (my_status != corelength)
	{
	  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
	  my_status = corelength;
	}
      status += my_status;

      /* Print the + to indicate that the following copro insn is   */
      /* part of a vliw group.                                      */
      if (copro1length > 0)
	(*info->fprintf_func) (info->stream, " + "); 
    }

  /* Now all that is left to be processed is the coprocessor insns
     In vliw mode, there will always be one.  Its positioning will
     be from byte corelength to byte corelength+copro1length -1.
     No need to check for existence.   Also, the first vliw insn,
     will, as spec'd, always be at least as long as the core insn
     so we don't need to flush the buffer.  */
  if (copro1length > 0)
    {
      int my_status = 0;
	 
      for (i = corelength; i < corelength + copro1length; i++ )
	insnbuf[i - corelength] = buf[i];

      switch (copro1length)
	{
	case 0:
	  break;
	case 2:
	  cd->isas = & MEP_COP16_ISA;
	  break;
	case 4:
	  cd->isas = & MEP_COP32_ISA;
	  break;
	case 6:
	  cd->isas = & MEP_COP48_ISA;
	  break;
	case 8:
	  cd->isas = & MEP_COP64_ISA;
	  break; 
	default:
	  /* Shouldn't be anything but 16,32,48,64.  */
	  break;
	}

      my_status = print_insn (cd, pc, info, insnbuf, copro1length);

      if (my_status != copro1length)
	{
	  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
	  my_status = copro1length;
	}
      status += my_status;
    }

#if 0
  /* Now we need to process the second copro insn if it exists. We
     have no guarantee that the second copro insn will be longer
     than the first, so we have to flush the buffer if we are have
     a second copro insn to process.  If present, this insn will
     be in the position from byte corelength+copro1length to byte
     corelength+copro1length+copro2length-1 (which better equal 8
     or else we're in big trouble.  */
  if (copro2length > 0)
    {
      int my_status = 0;

      for (i = 0; i < 64 ; i++)
	insnbuf[i] = 0;

      for (i = corelength + copro1length; i < 64; i++)
	insnbuf[i - (corelength + copro1length)] = buf[i];
      
      switch (copro2length)
	{
	case 2:
	  cd->isas = 1 << ISA_EXT_COP1_16;
	  break;
	case 4:
	  cd->isas = 1 << ISA_EXT_COP1_32;
	  break;
	case 6:
	  cd->isas = 1 << ISA_EXT_COP1_48;
	  break;
	case 8:
	  cd->isas = 1 << ISA_EXT_COP1_64; 
	  break;
	default:
	  /* Shouldn't be anything but 16,32,48,64.  */
	  break;
	}

      my_status = print_insn (cd, pc, info, insnbuf, copro2length);

      if (my_status != copro2length)
	{
	  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
	  my_status = copro2length;
	}

      status += my_status;
    }
#endif

  /* Status should now be the number of bytes that were printed
     which should be 4 for VLIW32 mode and 64 for VLIW64 mode.  */

  if ((!MEP_VLIW64 && (status != 4)) || (MEP_VLIW64 && (status != 8)))
    return -1;
  else
    return status;
}

/* The two functions mep_examine_vliw[32,64]_insns are used find out 
   which vliw combinaion (16 bit core with 48 bit copro, 32 bit core 
   with 32 bit copro, etc.) is present.  Later on, when internally   
   parallel coprocessors are handled, only these functions should    
   need to be changed.                                               

   At this time only the following combinations are supported: 
   
   VLIW32 Mode:
   16 bit core insn (core) and 16 bit coprocessor insn (cop1)
   32 bit core insn (core)
   32 bit coprocessor insn (cop1)
   Note: As of this time, I do not believe we have enough information
         to distinguish a 32 bit core insn from a 32 bit cop insn. Also,
         no 16 bit coprocessor insns have been specified.  

   VLIW64 Mode:
   16 bit core insn (core) and 48 bit coprocessor insn (cop1)
   32 bit core insn (core) and 32 bit coprocessor insn (cop1)
   64 bit coprocessor insn (cop1)
  
   The framework for an internally parallel coprocessor is also
   present (2nd coprocessor insn is cop2), but at this time it 
   is not used.  This only appears to be valid in VLIW64 mode.  */

static int
mep_examine_vliw32_insns (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
{
  int status;
  int buflength;
  int corebuflength;
  int cop1buflength;
  int cop2buflength;
  bfd_byte buf[CGEN_MAX_INSN_SIZE];  
  char indicator16[1];
  char indicatorcop32[2]; 

  /* At this time we're not supporting internally parallel coprocessors,
     so cop2buflength will always be 0.  */
  cop2buflength = 0;

  /* Read in 32 bits.  */
  buflength = 4; /* VLIW insn spans 4 bytes.  */
  status = (*info->read_memory_func) (pc, buf, buflength, info);

  if (status != 0)
    {
      (*info->memory_error_func) (status, pc, info);
      return -1;
    }

  /* Put the big endian representation of the bytes to be examined
     in the temporary buffers for examination.  */

  if (info->endian == BFD_ENDIAN_BIG)
    {
      indicator16[0] = buf[0];
      indicatorcop32[0] = buf[0];
      indicatorcop32[1] = buf[1];
    }
  else
    {
      indicator16[0] = buf[1];
      indicatorcop32[0] = buf[1];
      indicatorcop32[1] = buf[0];
    }

  /* If the two high order bits are 00, 01 or 10, we have a 16 bit
     core insn and a 48 bit copro insn.  */

  if ((indicator16[0] & 0x80) && (indicator16[0] & 0x40))
    {
      if ((indicatorcop32[0] & 0xf0) == 0xf0 && (indicatorcop32[1] & 0x07) == 0x07)
	{
          /* We have a 32 bit copro insn.  */
          corebuflength = 0;
	  /* All 4 4ytes are one copro insn. */
          cop1buflength = 4;
	}
      else
	{
          /* We have a 32 bit core.  */
          corebuflength = 4;
          cop1buflength = 0;
	}
    }
  else
    {
      /* We have a 16 bit core insn and a 16 bit copro insn.  */
      corebuflength = 2;
      cop1buflength = 2;
    }

  /* Now we have the distrubution set.  Print them out.  */
  status = mep_print_vliw_insns (cd, pc, info, buf, corebuflength,
				 cop1buflength, cop2buflength);

  return status;
}

static int
mep_examine_vliw64_insns (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
{
  int status;
  int buflength;
  int corebuflength;
  int cop1buflength;
  int cop2buflength;
  bfd_byte buf[CGEN_MAX_INSN_SIZE];
  char indicator16[1];
  char indicator64[4];

  /* At this time we're not supporting internally parallel
     coprocessors, so cop2buflength will always be 0.  */
  cop2buflength = 0;

  /* Read in 64 bits.  */
  buflength = 8; /* VLIW insn spans 8 bytes.  */
  status = (*info->read_memory_func) (pc, buf, buflength, info);

  if (status != 0)
    {
      (*info->memory_error_func) (status, pc, info);
      return -1;
    }

  /* We have all 64 bits in the buffer now.  We have to figure out
     what combination of instruction sizes are present.  The two
     high order bits will indicate whether or not we have a 16 bit
     core insn or not.  If not, then we have to look at the 7,8th
     bytes to tell whether we have 64 bit copro insn or a 32 bit
     core insn with a 32 bit copro insn.  Endianness will make a
     difference here.  */

  /* Put the big endian representation of the bytes to be examined
     in the temporary buffers for examination.  */

  /* indicator16[0] = buf[0];  */
  if (info->endian == BFD_ENDIAN_BIG)
    {
      indicator16[0] = buf[0];
      indicator64[0] = buf[0];
      indicator64[1] = buf[1];
      indicator64[2] = buf[2];
      indicator64[3] = buf[3];
    }
  else
    {
      indicator16[0] = buf[1];
      indicator64[0] = buf[1];
      indicator64[1] = buf[0];
      indicator64[2] = buf[3];
      indicator64[3] = buf[2];
    }

  /* If the two high order bits are 00, 01 or 10, we have a 16 bit
     core insn and a 48 bit copro insn.  */

  if ((indicator16[0] & 0x80) && (indicator16[0] & 0x40))
    {
      if ((indicator64[0] & 0xf0) == 0xf0 && (indicator64[1] & 0x07) == 0x07
	  && ((indicator64[2] & 0xfe) != 0xf0 || (indicator64[3] & 0xf4) != 0))
	{
          /* We have a 64 bit copro insn.  */
          corebuflength = 0;
	  /* All 8 bytes are one copro insn.  */
          cop1buflength = 8;
	}
      else
	{
          /* We have a 32 bit core insn and a 32 bit copro insn.  */
          corebuflength = 4;
          cop1buflength = 4;
	}
    }
  else
    {
      /* We have a 16 bit core insn and a 48 bit copro insn.  */
      corebuflength = 2;
      cop1buflength = 6;
    }

  /* Now we have the distrubution set.  Print them out. */
  status = mep_print_vliw_insns (cd, pc, info, buf, corebuflength,
				 cop1buflength, cop2buflength);

  return status;
}

#ifdef MEP_IVC2_SUPPORTED

static int
print_slot_insn (CGEN_CPU_DESC cd,
		 bfd_vma pc,
		 disassemble_info *info,
		 SLOTS_ATTR slot,
		 bfd_byte *buf)
{
  const CGEN_INSN_LIST *insn_list;
  CGEN_INSN_INT insn_value;
  CGEN_EXTRACT_INFO ex_info;

  insn_value = cgen_get_insn_value (cd, buf, 32);

  /* Fill in ex_info fields like read_insn would.  Don't actually call
     read_insn, since the incoming buffer is already read (and possibly
     modified a la m32r).  */
  ex_info.valid = (1 << 8) - 1;
  ex_info.dis_info = info;
  ex_info.insn_bytes = buf;

  /* The instructions are stored in hash lists.
     Pick the first one and keep trying until we find the right one.  */

  insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
  while (insn_list != NULL)
    {
      const CGEN_INSN *insn = insn_list->insn;
      CGEN_FIELDS fields;
      int length;

      if ((CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_CONFIG)
	   && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_CONFIG) != MEP_CONFIG)
	  || ! (CGEN_ATTR_CGEN_INSN_SLOTS_VALUE (CGEN_INSN_ATTRS (insn)) & (1 << slot)))
        {
          insn_list = CGEN_DIS_NEXT_INSN (insn_list);
	  continue;
        }

      if ((insn_value & CGEN_INSN_BASE_MASK (insn))
	  == CGEN_INSN_BASE_VALUE (insn))
	{
	  /* Printing is handled in two passes.  The first pass parses the
	     machine insn and extracts the fields.  The second pass prints
	     them.  */

	  length = CGEN_EXTRACT_FN (cd, insn)
	    (cd, insn, &ex_info, insn_value, &fields, pc);

	  /* Length < 0 -> error.  */
	  if (length < 0)
	    return length;
	  if (length > 0)
	    {
	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
	      /* Length is in bits, result is in bytes.  */
	      return length / 8;
	    }
	}

      insn_list = CGEN_DIS_NEXT_INSN (insn_list);
    }

  if (slot == SLOTS_P0S)
    (*info->fprintf_func) (info->stream, "*unknown-p0s*");
  else if (slot == SLOTS_P0)
    (*info->fprintf_func) (info->stream, "*unknown-p0*");
  else if (slot == SLOTS_P1)
    (*info->fprintf_func) (info->stream, "*unknown-p1*");
  else if (slot == SLOTS_C3)
    (*info->fprintf_func) (info->stream, "*unknown-c3*");
  return 0;
}

static int
mep_examine_ivc2_insns (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, bfd_vma pc ATTRIBUTE_UNUSED, disassemble_info *info ATTRIBUTE_UNUSED)
{
  int status;
  int buflength;
  bfd_byte buf[8];
  bfd_byte insn[8];
  int e;

  /* Read in 64 bits.  */
  buflength = 8; /* VLIW insn spans 8 bytes.  */
  status = (*info->read_memory_func) (pc, buf, buflength, info);

  if (status != 0)
    {
      (*info->memory_error_func) (status, pc, info);
      return -1;
    }

  if (info->endian == BFD_ENDIAN_LITTLE)
    e = 1;
  else
    e = 0;

  if (((unsigned char)buf[0^e] & 0xf0) < 0xc0)
    {
      /*      <--00--><--11--><--22--><--33--><--44--><--55--><--66--><--77--> */
      /* V1   [-----core-----][--------p0s-------][------------p1------------] */

      print_insn (cd, pc, info, buf, 2);

      insn[0^e] = 0;
      insn[1^e] = buf[2^e];
      insn[2^e] = buf[3^e];
      insn[3^e] = buf[4^e] & 0xf0;
      (*info->fprintf_func) (info->stream, " + ");
      print_slot_insn (cd, pc, info, SLOTS_P0S, insn);

      insn[0^e] = buf[4^e] << 4 | buf[5^e] >> 4;
      insn[1^e] = buf[5^e] << 4 | buf[6^e] >> 4;
      insn[2^e] = buf[6^e] << 4 | buf[7^e] >> 4;
      insn[3^e] = buf[7^e] << 4;
      (*info->fprintf_func) (info->stream, " + ");
      print_slot_insn (cd, pc, info, SLOTS_P1, insn);
    }
  else if ((buf[0^e] & 0xf0) == 0xf0 && (buf[1^e] & 0x0f) == 0x07)
    {
      /*      <--00--><--11--><--22--><--33--><--44--><--55--><--66--><--77--> */
      /* V3   1111[--p0--]0111[--------p0--------][------------p1------------] */
      /*                                          00000000111111112222222233333333 */

      insn[0^e] = buf[0^e] << 4 | buf[1^e] >> 4;
      insn[1^e] = buf[2^e];
      insn[2^e] = buf[3^e];
      insn[3^e] = buf[4^e] & 0xf0;
      print_slot_insn (cd, pc, info, SLOTS_P0, insn);

      insn[0^e] = buf[4^e] << 4 | buf[5^e] >> 4;
      insn[1^e] = buf[5^e] << 4 | buf[6^e] >> 4;
      insn[2^e] = buf[6^e] << 4 | buf[7^e] >> 4;
      insn[3^e] = buf[7^e] << 4;
      (*info->fprintf_func) (info->stream, " + ");
      print_slot_insn (cd, pc, info, SLOTS_P1, insn);
    }
  else
    {
      /*      <--00--><--11--><--22--><--33--><--44--><--55--><--66--><--77--> */
      /* V2   [-------------core-------------]xxxx[------------p1------------] */
      print_insn (cd, pc, info, buf, 4);

      insn[0^e] = buf[4^e] << 4 | buf[5^e] >> 4;
      insn[1^e] = buf[5^e] << 4 | buf[6^e] >> 4;
      insn[2^e] = buf[6^e] << 4 | buf[7^e] >> 4;
      insn[3^e] = buf[7^e] << 4;
      (*info->fprintf_func) (info->stream, " + ");
      print_slot_insn (cd, pc, info, SLOTS_P1, insn);
    }

  return 8;
}

#endif /* MEP_IVC2_SUPPORTED */

/* This is a hack.  SID calls this to update the disassembler as the
   CPU changes modes.  */
static int mep_ivc2_disassemble_p = 0;
static int mep_ivc2_vliw_disassemble_p = 0;

void
mep_print_insn_set_ivc2_mode (int ivc2_p, int vliw_p, int cfg_idx);
void
mep_print_insn_set_ivc2_mode (int ivc2_p, int vliw_p, int cfg_idx)
{
  mep_ivc2_disassemble_p = ivc2_p;
  mep_ivc2_vliw_disassemble_p = vliw_p;
  mep_config_index = cfg_idx;
}

static int
mep_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
{
  int status;
  int cop_type;
  int ivc2 = 0;
  static CGEN_ATTR_VALUE_BITSET_TYPE *ivc2_core_isa = NULL;

  if (ivc2_core_isa == NULL)
    {
      /* IVC2 has some core-only coprocessor instructions.  We
	 use COP32 to flag those, and COP64 for the VLIW ones,
	 since they have the same names.  */
      ivc2_core_isa = cgen_bitset_create (MAX_ISAS);
    }

  /* Extract and adapt to configuration number, if available. */
  if (info->section && info->section->owner)
    {
      bfd *abfd = info->section->owner;
      mep_config_index = abfd->tdata.elf_obj_data->elf_header->e_flags & EF_MEP_INDEX_MASK;
      /* This instantly redefines MEP_CONFIG, MEP_OMASK, .... MEP_VLIW64 */

      cop_type = abfd->tdata.elf_obj_data->elf_header->e_flags & EF_MEP_COP_MASK;
      if (cop_type == EF_MEP_COP_IVC2)
	ivc2 = 1;
    }

  /* Picking the right ISA bitmask for the current context is tricky.  */
  if (info->section)
    {
      if (info->section->flags & SEC_MEP_VLIW)
	{
#ifdef MEP_IVC2_SUPPORTED
	  if (ivc2)
	    {
	      /* ivc2 has its own way of selecting its functions.  */
	      cd->isas = & MEP_CORE_ISA;
	      status = mep_examine_ivc2_insns (cd, pc, info);
	    }
	  else
#endif
	    /* Are we in 32 or 64 bit vliw mode?  */
	    if (MEP_VLIW64)
	      status = mep_examine_vliw64_insns (cd, pc, info);
	    else
	      status = mep_examine_vliw32_insns (cd, pc, info);
	  /* Both the above branches set their own isa bitmasks.  */
	}
      else
	{
	  if (ivc2)
	    {
	      cgen_bitset_clear (ivc2_core_isa);
	      cgen_bitset_union (ivc2_core_isa, &MEP_CORE_ISA, ivc2_core_isa);
	      cgen_bitset_union (ivc2_core_isa, &MEP_COP32_ISA, ivc2_core_isa);
	      cd->isas = ivc2_core_isa;
	    }
	  else
	    cd->isas = & MEP_CORE_ISA;
	  status = default_print_insn (cd, pc, info);
	}
    }
  else /* sid or gdb */
    {
#ifdef MEP_IVC2_SUPPORTED
      if (mep_ivc2_disassemble_p)
	{
	  if (mep_ivc2_vliw_disassemble_p)
	    {
	      cd->isas = & MEP_CORE_ISA;
	      status = mep_examine_ivc2_insns (cd, pc, info);
	      return status;
	    }
	  else
	    {
	      if (ivc2)
		cd->isas = ivc2_core_isa;
	    }
	}
#endif

      status = default_print_insn (cd, pc, info);
    }

  return status;
}


/* -- opc.c */
#include "elf/mep.h"

/* A mask for all ISAs executed by the core. */
CGEN_ATTR_VALUE_BITSET_TYPE mep_all_core_isas_mask = {0, 0};

void
init_mep_all_core_isas_mask (void)
{
  if (mep_all_core_isas_mask.length != 0)
    return;
  cgen_bitset_init (& mep_all_core_isas_mask, ISA_MAX);
  cgen_bitset_set (& mep_all_core_isas_mask, ISA_MEP);
  /* begin-all-core-isas */
  cgen_bitset_add (& mep_all_core_isas_mask, ISA_EXT_CORE1);
  /* end-all-core-isas */
}

CGEN_ATTR_VALUE_BITSET_TYPE mep_all_cop_isas_mask = {0, 0};

void
init_mep_all_cop_isas_mask (void)
{
  if (mep_all_cop_isas_mask.length != 0)
    return;
  cgen_bitset_init (& mep_all_cop_isas_mask, ISA_MAX);
  /* begin-all-cop-isas */
  cgen_bitset_add (& mep_all_cop_isas_mask, ISA_EXT_COP1_16);
  cgen_bitset_add (& mep_all_cop_isas_mask, ISA_EXT_COP1_32);
  cgen_bitset_add (& mep_all_cop_isas_mask, ISA_EXT_COP1_48);
  cgen_bitset_add (& mep_all_cop_isas_mask, ISA_EXT_COP1_64);
  /* end-all-cop-isas */
}

int
mep_insn_supported_by_isa (const CGEN_INSN *insn, CGEN_ATTR_VALUE_BITSET_TYPE *isa_mask)
{
  CGEN_BITSET insn_isas = CGEN_INSN_BITSET_ATTR_VALUE (insn, CGEN_INSN_ISA);
  return cgen_bitset_intersect_p (& insn_isas, isa_mask);
}

#define OPTION_MASK \
	( (1 << CGEN_INSN_OPTIONAL_BIT_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_MUL_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_DIV_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_DEBUG_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_LDZ_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_ABS_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_AVE_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_MINMAX_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_CLIP_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_SAT_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_UCI_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_DSP_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_CP_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_CP64_INSN) )


mep_config_map_struct mep_config_map[] =
{
  /* config-map-start */
  /* Default entry: first module, with all options enabled. */
  { "", 0,  EF_MEP_COP_IVC2 | EF_MEP_CPU_C5,0, 64, { 1, "\x20" }, { 1, "\x10" }, { 1, "\x8" }, { 1, "\x4" }, { 1, "\x3c" }, { 1, "\xc0" }, OPTION_MASK | (1 << CGEN_INSN_OPTIONAL_DSP_INSN) | (1 << CGEN_INSN_OPTIONAL_UCI_INSN) },
  { "default", CONFIG_DEFAULT, EF_MEP_COP_IVC2 | EF_MEP_CPU_C5, 0, 64, { 1, "\x20" }, { 1, "\x10" }, { 1, "\x8" }, { 1, "\x4" }, { 1, "\x3c" }, { 1, "\xc0" },
	  0
	| (1 << CGEN_INSN_OPTIONAL_CP_INSN)
	| (1 << CGEN_INSN_OPTIONAL_CP64_INSN)
	| (1 << CGEN_INSN_OPTIONAL_MUL_INSN)
	| (1 << CGEN_INSN_OPTIONAL_DIV_INSN)
	| (1 << CGEN_INSN_OPTIONAL_BIT_INSN)
	| (1 << CGEN_INSN_OPTIONAL_LDZ_INSN)
	| (1 << CGEN_INSN_OPTIONAL_ABS_INSN)
	| (1 << CGEN_INSN_OPTIONAL_AVE_INSN)
	| (1 << CGEN_INSN_OPTIONAL_MINMAX_INSN)
	| (1 << CGEN_INSN_OPTIONAL_CLIP_INSN)
	| (1 << CGEN_INSN_OPTIONAL_SAT_INSN) },
  /* config-map-end */
  { 0, 0, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0 }
};

int mep_config_index = 0;

static int
check_configured_mach (int machs)
{
  /* All base insns are supported.  */
  int mach = 1 << MACH_BASE;
  switch (MEP_CPU & EF_MEP_CPU_MASK)
    {
    case EF_MEP_CPU_C2:
    case EF_MEP_CPU_C3:
      mach |= (1 << MACH_MEP);
      break;
    case EF_MEP_CPU_H1:
      mach |= (1 << MACH_H1);
      break;
    case EF_MEP_CPU_C5:
      mach |= (1 << MACH_MEP);
      mach |= (1 << MACH_C5);
      break;
    default:
      break;
    }
  return machs & mach;
}

int
mep_cgen_insn_supported (CGEN_CPU_DESC cd, const CGEN_INSN *insn)
{
  int iconfig = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_CONFIG);
  int machs = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_MACH);
  CGEN_BITSET isas = CGEN_INSN_BITSET_ATTR_VALUE (insn, CGEN_INSN_ISA);
  int ok1;
  int ok2;
  int ok3;

  /* If the insn has an option bit set that we don't want,
     reject it.  */
  if (CGEN_INSN_ATTRS (insn)->bool_ & OPTION_MASK & ~MEP_OMASK)
    return 0;

  /* If attributes are absent, assume no restriction. */
  if (machs == 0)
    machs = ~0;

  ok1 = ((machs & cd->machs) && cgen_bitset_intersect_p (& isas, cd->isas));
  /* If the insn is config-specific, make sure it matches.  */
  ok2 =  (iconfig == 0 || iconfig == MEP_CONFIG);
  /* Make sure the insn is supported by the configured mach  */
  ok3 = check_configured_mach (machs);

  return (ok1 && ok2 && ok3);
}

int
mep_cgen_insn_supported_asm (CGEN_CPU_DESC cd, const CGEN_INSN *insn)
{
#ifdef MEP_IVC2_SUPPORTED
  /* If we're assembling VLIW packets, ignore the 12-bit BSR as we
     can't relax that.  The 24-bit BSR is matched instead.  */
  if (insn->base->num == MEP_INSN_BSR12
      && cgen_bitset_contains (cd->isas, ISA_EXT_COP1_64))
    return 0;
#endif

  return mep_cgen_insn_supported (cd, insn);
}
@


1.1.1.1
log
@Import gdb 7.6.1
News from: http://sourceware.org/gdb/news:

August 30th, 2013: GDB 7.6.1 Released!
The latest version of GDB, version 7.6.1, is available for download.

This is a minor corrective release over GDB 7.6, fixing the following issues:

PR tdep/15420 (Cannot debug threaded programs on newer versions of x86-solaris - Solaris 10, Update 10 or later)
PR remote/15455 (QTro remote packet broken)
PR build/15476 (Build failure due to incomplete enum type in utils.h)
PR server/15594 (tls support in 64x32 x86 gdbserver doesn't extend address to 64 bit)
PR server/15075 (dprintf inteferes with "next")
PR server/15434 (dprintf uses a synchronous 'continue' even in non-stop mode)
PR tui/14880 (In split register layouts, up results in assertion failure in value.c)
PR c++/15519 (GDB 7.6 is 94x slower than GDB 7.5.1 using a certain core file)
PR gdb/15837 (GDB prints entry values for local variables)
PR gdb/15415 (gdb resolves symbolic links when passing argv[0])
PR cli/15603 (CTRL-C can no longer interrupt inferior)
PR gdb/15604 (gdbserver socket leak 7.5 regression)
April 26th, 2013: GDB 7.6 Released!
The latest version of GDB, version 7.6, is available for download.

Changes in this release include:

New native configurations (ARM AArch64 GNU/Linux, FreeBSD/powerpc, 86_64/Cygwin and Tilera TILE-Gx GNU/Linux)
New target configurations (ARM AArch64, ARM AArch64 GNU/Linux, Lynx 178 PowerPC, x86_64/Cygwin, and Tilera TILE-Gx GNU/Linux)
Support for the "mini debuginfo" section, .gnu_debugdata
The C++ ABI now defaults to the GNU v3 ABI
More Python scripting improvements
Some GDB/MI improvements
New configure options, new commands, and options
New remote packets
A new "target record-btrace" has been added while the "target record" command has been renamed to "target record-full"
See the NEWS file for a more complete and detailed list of what this release includes.
March 12th, 2013: GDB 7.6 branch created
The GDB 7.6 branch (gdb_7_6-branch) has been created. To check out a copy of the branch use:

cvs -d :pserver:anoncvs@@sourceware.org:/cvs/src co -r gdb_7_6-branch gdb
November 29th, 2012: GDB 7.5.1 Released!
The latest version of GDB, version 7.5.1, is available for download.

This is a minor corrective release over GDB 7.5, fixing the following issues:

An "Attempt to dereference a generic pointer" errors (-var-create).
Backtrace problems on x32 (PR backtrace/14646).
next/step/finish problems on x32 (PR gdb/14647).
A "malformed linespec error: unexpected keyword, [...]" error (PR breakpoints/14643).
GDB crash while stepping through powerpc (32bits) code.
A failed assertion in linux_ptrace_test_ret_to_nx.
A "!frame_id_inlined_p (frame_id)" failed assertion.
A "No more reverse-execution history." error during reverse "next" execution (PR 14548).
Incomplete command descriptions in "apropos" output.
PR gdb/14494 (a GDB crash difficult to characterize).
Various build warnings.
August 17th, 2012: GDB 7.5 Released!
The latest version of GDB, version 7.5, is available for download.

Changes in this release include:

Go language support.
New targets (x32 ABI, microMIPS, Renesas RL78, HP OpenVMS ia64).
More Python scripting improvements.
SDT (Static Defined Tracing) probes support with SystemTap probes.
GDBserver improvements (stdio connections, target-side evaluation of breakpoint conditions, remote protocol improvements).
Other miscellaneous improvements (ability to stop when a shared library is loaded/unloaded, dynamic printf, etc).
Reverse debugging on ARM.
The binary "gdbtui" has been abandoned and can no longer be built. Use "gdb -tui" instead.
See the NEWS file for a more complete and detailed list of what this release includes.
July 17th, 2012: GDB 7.5 branch created
The GDB 7.5 branch (gdb_7_5-branch) has been created. To check out a copy of the branch use:

cvs -d :pserver:anoncvs@@sourceware.org:/cvs/src co -r gdb_7_5-branch gdb
April 26th, 2012: GDB 7.4.1 Released!
The latest version of GDB, version 7.4.1, is available for download.

This is a minor corrective release over GDB 7.4, fixing the following issues:

[GDB/MI] Error when resuming program execution in all-stop mode ("Cannot execute this command without a live selected thread").
[Pascal] Polluted display of class methods parameters.
[target remote] Errror when connecting to remote target where disconnected tracing is in effect.
[AVX] Float and ymm* register values not available.
[GDB] Crash when using the "finish" command.
[build] makeinfo should not be required to build GDB.
January 24th, 2012: GDB 7.4 Released!
The latest version of GDB, version 7.4, is available for download.

Changes in this release include:

Many Python scripting improvements
Better support for ambiguous linespecs
Masked watchpoints
Tracepoint support improvements
Support for Texas Instruments TMS320C6x (tic6x-*-*)
A Renesas RL78 simulator (rl78-*-elf)
Some minor Remote protocol extensions and GDB/MI changes
See the NEWS file for a more complete and detailed list of what this release includes. Note that the gdbtui binary is deprecated, starting with GDB 7.5. Use "gdb -tui" instead.
January 9, 2012: Extensibility support using Guile
GDB ought to support extensibility using Guile, the GNU extensibility package (an implementation of Scheme). We are looking for people to write the code to interface the two. Please write to gdb-patches AT sourceware DOT org if you are interested.

December 13, 2011: GDB 7.4 branch created
The GDB 7.4 branch (gdb_7_4-branch) has been created. To check out a copy of the branch use:

cvs -d :pserver:anoncvs@@sourceware.org:/cvs/src co -r gdb_7_4-branch gdb
September 30, 2011: Release Mistakes in GDB Versions 6.0 - 7.3
A mistake has been detected in the release tar files for all GDB releases from version 6.0 to version 7.3 (included). The mistake has been corrected, and the FSF issued the following announcements:

Making up for a release mistake in GDB versions 6.0 - 6.6
Making up for a release mistake in GDB versions 6.7 - 7.3
@
text
@@


1.1.1.2
log
@Import gdb-8.0.1
@
text
@a792 1
		  /* Fall through.  */
@


1.1.1.3
log
@Import head of gdb as of 2020-09-14 requested by Kamil

2020-07-24  Aaron Merey  <amerey@@redhat.com>

	* configure: Rebuild.
	* configure.ac: Remove AC_DEBUGINFOD.

2020-07-04  Nick Clifton  <nickc@@redhat.com>

	Binutils 2.35 branch created.

2020-04-21  Stephen Casner  <casner@@acm.org>

	PR 25830
	* configure.ac (noconfigdirs): Exclude gdb & gprof for pdp11.
	* configure: Rebuild.

2020-03-12  Tom Tromey  <tom@@tromey.com>

	* Makefile.in: Rebuild.
	* Makefile.def (gdbserver): Depend on gdbsupport.

2020-03-12  Tom Tromey  <tom@@tromey.com>

	* Makefile.in: Rebuild.
	* Makefile.def (gdbsupport): Don't depend on bfd.

2020-03-12  Tom Tromey  <tom@@tromey.com>

	* Makefile.in: Rebuild.
	* Makefile.def (gdbsupport): Depend on intl.

2020-02-17  Tom Tromey  <tom@@tromey.com>

	* configure: Rebuild.
	* configure.ac (configdirs): Add gnulib and gdbsupport when building
	gdbserver.

2020-02-14  Tom Tromey  <tom@@tromey.com>

	* Makefile.in: Rebuild.
	* Makefile.def: Make gdbserver require gnulib and libiberty.

2020-02-07  Tom Tromey  <tom@@tromey.com>
	    Pedro Alves  <palves@@redhat.com>

	* src-release.sh (GDB_SUPPORT_DIRS): Add gdbserver.
	* gdbserver: New directory, moved from gdb/gdbserver.
	* configure.ac (host_tools): Add gdbserver.
	Only build gdbserver on certain systems.
	* Makefile.in, configure: Rebuild.
	* Makefile.def (host_modules, dependencies): Add gdbserver.
	* MAINTAINERS: Add gdbserver.

2020-01-28  Sergio Durigan Junior  <sergiodj@@redhat.com>

	* src-release.sh (getver): Look for gdbsupport's
	create-version.sh script at the current directory if tool is
	"gdb".

2020-01-19  Simon Marchi  <simon.marchi@@polymtl.ca>

	* remote-sim.c (gdbsim_target::wait): Return
	sim_data->remote_sim_ptid instead of inferior_ptid.

2020-01-18  Nick Clifton  <nickc@@redhat.com>

	Binutils 2.34 branch created.

2020-01-18  Nick Clifton  <nickc@@redhat.com>

	Synchronize top level configure files with master version:

	2020-01-01  Ben Elliston  <bje@@gnu.org>

	* config.guess: Update copyright years.
	* config.sub: Likewise.

	2019-12-21  Ben Elliston  <bje@@gnu.org>

	* config.guess (set_cc_for_build): Prevent multiple calls by
	checking if $tmp is already set. We can't check CC_FOR_BUILD as
	the user may set it externally. Thanks to Torbjörn Granlund for
	the bug report.

	2019-12-21  Torbjörn Granlund  <tg@@gmplib.org>

	* config.guess (alpha:Linux:*:*): Guard against missing
	/proc/cpuinfo by redirecting standard error to /dev/null.

	2019-09-12  Daniel Bittman  <danielbittman1@@gmail.com>

	* config.guess (*:Twizzler:*:*): New.
	* config.sub (-twizzler*): New.

	2019-07-24  Ben Elliston  <bje@@gnu.org>

	* config.guess (mips:OSF1:*.*): Whitespace cleanup.

	2019-06-30  Ben Elliston  <bje@@gnu.org>

	* config.sub (case $os): Match nsk* and powerunix. Don't later
	match nsk* and set os=nsk which removes the OS version number.

	2019-06-30  Ben Elliston  <bje@@gnu.org>

	* config.sub: Recognise os108*.

	2019-06-26  Ben Elliston  <bje@@gnu.org>

	* config.sub (hp300): Set $os to hpux.

	2019-06-26  Ben Elliston  <bje@@gnu.org>

	* config.sub (vsta): Move into alphabetical order.

	2019-06-10  Ben Elliston  <bje@@gnu.org>

	* config.guess (*:OS108:*:*): Recognise new OS.

	2019-05-28  Ben Elliston  <bje@@gnu.org>

	* config.guess (*:Darwin:*:*): Run xcode-select to determine if a
	system compiler is installed. If not, do not run set_cc_for_build,
	as the default cc will open a dialog box asking to install
	Xcode. If no C compiler is available, guess based on uname -p and
	uname -m.

	2019-05-28  Ben Elliston  <bje@@gnu.org>

	* config.guess (*:Darwin:*:*): Simplify UNAME_PROCESSOR.

2020-01-17  Simon Marchi  <simon.marchi@@efficios.com>

	* Makefile.def: Add dependencies of all-gdbsupport on all-bfd.
	* Makefile.in: Re-generate.

2020-01-14  Tom Tromey  <tom@@tromey.com>

	* src-release.sh (GDB_SUPPORT_DIRS): Add gdbsupport.
	* MAINTAINERS: Add gdbsupport.
	* configure: Rebuild.
	* configure.ac (configdirs): Add gdbsupport.
	* gdbsupport: New directory, move from gdb/gdbsupport.
	* Makefile.def (host_modules, dependencies): Add gnulib.
	* Makefile.in: Rebuild.

2020-01-09  Aaron Merey  <amerey@@redhat.com>

        * config/debuginfod.m4: New file. Add macro AC_DEBUGINFOD. Adds
        new configure option --with-debuginfod.
        * configure: Regenerate.
        * configure.ac: Call AC_DEBUGINFOD.

2019-12-26  Christian Biesinger  <cbiesinger@@google.com>

	* .gitignore: Add perf.data and perf.data.old.

2019-10-17  Sergio Durigan Junior  <sergiodj@@redhat.com>

	* src-release.sh (GDB_SUPPORT_DIRS): Add libctf.

2019-10-17  Alan Modra  <amodra@@gmail.com>

	PR 29
	* src-release.sh (getver): Replace "head -1" with "head -n 1".

2019-07-30  Nick Alcock  <nick.alcock@@oracle.com>

	* Makefile.def (host_modules): libctf is no longer no_install.
	* Makefile.in: Regenerated.

2019-07-13  Nick Alcock  <nick.alcock@@oracle.com>

	* Makefile.def (dependencies): all-ld depends on all-libctf.
	* Makefile.in: Regenerated.

2019-09-09  Phil Blundell  <pb@@pbcl.net>

	binutils 2.33 branch created

2019-08-19  Tom Tromey  <tom@@tromey.com>

	* configure: Rebuild.
	* configure.ac: Add --with-static-standard-libraries.

2019-08-09  Nick Clifton  <nickc@@redhat.com>

	* libiberty: Sync with gcc.  Bring in:
	2019-08-08  Martin Liska  <mliska@@suse.cz>

	PR bootstrap/91352
	* lrealpath.c (is_valid_fd): New function.

	2019-07-24  Martin Liska  <mliska@@suse.cz>

	PR lto/91228
	* simple-object-elf.c (simple_object_elf_copy_lto_debug_sections):
	Find first '\0' starting from gnu_lto + 1.

	2019-07-12  Ren Kimura  <rkx1209dev@@gmail.com>

	* simple-object-elf.c (simple_object_elf_match): Check zero value shstrndx.
	This fixes a Bug 90924.

	2019-07-22  Martin Liska  <mliska@@suse.cz>

	* simple-object-elf.c (simple_object_elf_copy_lto_debug_sections):
	Do not search for gnu_lto_v1, but search for first '\0'.

	2019-07-18  Eduard-Mihai Burtescu  <eddyb@@lyken.rs>

	* cplus-dem.c: Include rust-demangle.h.
	* rust-demangle.c: Include rust-demangle.h.
	* rust-demangle.h: New file.

	2019-05-31  Michael Forney  <mforney@@mforney.org>

	* cp-demangle.c: Don't define CP_DYNAMIC_ARRAYS if __STDC_NO_VLA__
	is non-zero.

	2019-04-30  Ben L  <bobsayshilol@@live.co.uk>

	* d-demangle.c (dlang_parse_assocarray): Correctly handle error result.
	* testsuite/d-demangle-expected: Add testcase.

	* d-demangle.c (dlang_parse_tuple): Correctly handle error result.
	* testsuite/d-demangle-expected: Add testcase.

	* d-demangle.c (dlang_parse_structlit): Correctly handle error result.
	* testsuite/d-demangle-expected: Add testcase.

	* d-demangle.c (dlang_parse_arrayliteral): Correctly handle error result.
	* testsuite/d-demangle-expected: Add testcase.

	* d-demangle.c (dlang_parse_integer): Fix stack underflow.
	* testsuite/d-demangle-expected: Add testcase.

	* cp-demangle (d_print_comp_inner): Guard against a NULL 'typed_name'.
	* testsuite/demangle-expected: Add testcase.

	* cp-demangle.c (d_encoding): Guard against NULL return values from
	d_right (dc).
	* testsuite/demangle-expected: Add testcase.

	2019-04-29  Ben L  <bobsayshilol@@live.co.uk>

	* cp-demangle.c (d_expression_1): Don't peek ahead unless the current
	char is valid.
	* testsuite/demangle-expected: Add testcase.

	2019-04-10  Nick Clifton  <nickc@@redhat.com>

	PR 89394
	* cp-demangle.c (cplus_demangle_fill_name): Reject negative
	lengths.
	(d_count_templates_scopes): Replace num_templates and num_scopes
	parameters with a struct d_print_info pointer parameter.  Adjust
	body of the function accordingly.  Add recursion counter and check
	that the recursion limit is not reached.
	(d_print_init): Pass dpi parameter to d_count_templates_scopes.
	Reset recursion counter afterwards, unless the recursion limit was
	reached.

2019-07-13  Joel Brobecker  <brobecker@@adacore.com>

	* src-release (getver): If $tool/gdbsupport/create-version.sh
	exists, use that to determine the version number.

2019-06-21  Andreas Schwab  <schwab@@linux-m68k.org>

	* src-release.sh (GDB_SUPPORT_DIRS): Add gnulib.

2019-06-14  Tom Tromey  <tom@@tromey.com>

	* MAINTAINERS: Add gnulib.
	* gnulib: New directory, move from gdb/gnulib.
	* configure.ac (host_libs): Add gnulib.
	* configure: Rebuild.
	* Makefile.def (host_modules, dependencies): Add gnulib.
	* Makefile.in: Rebuild.

2019-06-03  Nick Clifton  <nickc@@redhat.com>

	Revert:
	2019-05-29  Nick Clifton  <nickc@@redhat.com>

	* configure.ac (noconfigdirs): Add libctf if the target does not use
	the ELF file format.
	* configure: Regenerate.

2019-05-29  Nick Clifton  <nickc@@redhat.com>

	* src-release.sh (do_proto_toplev): Add libctf to list of
	directories that can be disabled.

2019-05-29  Nick Clifton  <nickc@@redhat.com>

	* configure.ac (noconfigdirs): Add libctf if the target does not use
	the ELF file format.
	* configure: Regenerate.

2019-05-28  Nick Alcock  <nick.alcock@@oracle.com>

	* Makefile.def (dependencies): configure-libctf depends on all-bfd
	and all its deps.
	* Makefile.in: Regenerated.

2019-05-28  Nick Alcock  <nick.alcock@@oracle.com>

	* MAINTAINERS: Add libctf.

2019-05-28  Nick Alcock  <nick.alcock@@oracle.com>

	* Makefile.def (host_modules): Add libctf.
	* Makefile.def (dependencies): Likewise.
	libctf depends on zlib, libiberty, and bfd.
	* Makefile.in: Regenerated.
	* configure.ac (host_libs): Add libctf.
	* configure: Regenerated.

2019-05-23  Jose E. Marchesi  <jose.marchesi@@oracle.com>

	* config.guess: Synchronize with config project master sources.
	* config.sub: Likewise.
	* readline/support/config.guess: Likewise.
	* readline/support/config.sub: Likewise.

2019-04-10  Nick Clifton  <nickc@@redhat.com>

	* libiberty: Sync with gcc.  Bring in:
	2019-04-10  Nick Clifton  <nickc@@redhat.com>

	PR 89394
	* cp-demangle.c (cplus_demangle_fill_name): Reject negative
	lengths.
	(d_count_templates_scopes): Replace num_templates and num_scopes
	parameters with a struct d_print_info pointer parameter.  Adjust
	body of the function accordingly.  Add recursion counter and check
	that the recursion limit is not reached.
	(d_print_init): Pass dpi parameter to d_count_templates_scopes.
	Reset recursion counter afterwards, unless the recursion limit was
	reached.

2018-06-24  Nick Clifton  <nickc@@redhat.com>

	2.32 branch created.

2019-01-14  Rainer Orth  <ro@@CeBiTec.Uni-Bielefeld.DE>

	Merge from GCC:
	PR target/88535
	* config.guess: Import upstream version 2019-01-03.
	* config.sub: Import upstream version 2019-01-01.

2019-01-10  Nick Clifton  <nickc@@redhat.com>

	* libiberty: Sync with gcc.  Bring in:
	2019-01-09  Sandra Loosemore  <sandra@@codesourcery.com>

	PR other/16615

	* cp-demangle.c: Mechanically replace "can not" with "cannot".
	* floatformat.c: Likewise.
	* strerror.c: Likewise.

	2018-12-22  Jason Merrill  <jason@@redhat.com>

	Remove support for demangling GCC 2.x era mangling schemes.
	* cplus-dem.c: Remove cplus_mangle_opname, cplus_demangle_opname,
	internal_cplus_demangle, and all subroutines.
	(libiberty_demanglers): Remove entries for ancient GNU (pre-3.0),
	Lucid, ARM, HP, and EDG demangling styles.
	(cplus_demangle): Remove 'work' variable.  Don't call
	internal_cplus_demangle.

2019-01-03  Дилян Палаузов  <dilyan.palauzov@@aegee.org>

	* configure.ac: Don't configure readline if --with-system-readline is
	used.
	* configure: Re-generate.
@
text
@d858 2
a859 1
  free (hold);
d1275 1
a1275 1
  insn_value = cgen_get_insn_value (cd, buf, 32, cd->insn_endian);
@


1.1.1.4
log
@Import gdb-13.2 over gdb-11.0.50

May 27th, 2023: GDB 13.2 Released!
The latest version of GDB, version 13.2, is available for download.

This is a minor corrective release over GDB 13.1, fixing the following issues:

PR testsuite/30158 (rustc testsuite fails with 13.1, apparently
		    worked before with trunk 20230114 on i686-linux-gnu and
		    powerpc64le-linux-gnu)
PR gdb/30214 (GDB 13.1 does not compile on FreeBSD 13.1)
PR gdb/30240 ((linux/aarch) thread.c:86: internal-error: inferior_thread:
              Assertion `current_thread_ != nullptr' failed)
PR gdb/30249 ([13 regression] hookpost-extended-remote will not work)
PR exp/30271 (Addresses of static thread_local fields are badly
              calculated sometimes)
PR symtab/30357 (Segmentation fault for the 'start' command)
PR symtab/30369 ([gdb/symtab] False match issue in
skip_prologue_using_linetable)

PR gdb/30423 (Build failures with clang 16)
PR build/30450 (Build failure (linux-low.cc:5393:45: error: expected
		':' before ')' token) with musl-1.2.4)

See the NEWS file for a more complete and detailed list of what this release
 includes.

Feb 19th, 2023: GDB 13.1 Released!

The latest version of GDB, version 13.1, is available for download.
This version of GDB includes the following changes and enhancements:
Support for the following new targets has been added in both GDB and GDBserver:
GNU/Linux/LoongArch (gdbserver) loongarch*-*-linux*
GNU/Linux/CSKY (gdbserver) csky*-*linux*
The Windows native target now supports target async.
FreeBSD:
Arm and AArch64: Support for Thread Local Storage (TLS) variables
Hardware watchpoint support on AArch64 FreeBSD
Floating-point support has now been added on LoongArch GNU/Linux.
New commands:
set print nibbles [on|off]
show print nibbles

This controls whether the 'print/t' command will display binary
values in groups of four bits, known as "nibbles". The default is
'off'.

Various styling-related commands. See the gdb/NEWS file for more details.
Various maintenance commands. These are normally aimed at GDB
experts or developers. See the gdb/NEWS file for more details.

Python API improvements:
New Python API for instruction disassembly.

The new attribute 'locations' of gdb.Breakpoint returns a list of
gdb.BreakpointLocation objects specifying the locations where the
breakpoint is inserted into the debuggee.
New Python type gdb.BreakpointLocation.
New function gdb.format_address(ADDRESS, PROGSPACE, ARCHITECTURE)
that formats ADDRESS as 'address '
New function gdb.current_language that returns the name of the
current language. Unlike gdb.parameter('language'), this will never
return 'auto'.
New function gdb.print_options that returns a dictionary of the
prevailing print options, in the form accepted by gdb.Value.format_string.
New method gdb.Frame.language that returns the name of the frame's language.
gdb.Value.format_string now uses the format provided by 'print',
if it is called during a 'print' or other similar operation.
gdb.Value.format_string now accepts the 'summary' keyword. This
can be used to request a shorter representation of a value, the
way that 'set print frame-arguments scalars' does.
The gdb.register_window_type method now restricts the set of
acceptable window names. The first character of a window's name
must start with a character in the set [a-zA-Z], every subsequent
character of a window's name must be in the set [-_.a-zA-Z0-9].
` GDB/MI changes:  MI version 1 is deprecated, and will be removed
in GDB 14.  The async record stating the stopped reason 'breakpoint-hit'
now contains an optional field locno.

Miscellaneous improvements:
gdb now supports zstd compressed debug sections (ELFCOMPRESS_ZSTD) for ELF.
New convenience variable $_inferior_thread_count contains the number
of live threads in the current inferior.
New convenience variables $_hit_bpnum and $_hit_locno, set to the
breakpoint number and the breakpoint location number of the breakpoint
last hit.
The "info breakpoints" now displays enabled breakpoint locations
of disabled breakpoints as in the "y-" state.
The format of 'disassemble /r' and 'record instruction-history /r'
has changed to match the layout of GNU objdump when disassembling.

A new format "/b" has been introduce to provide the old behavior of "/r".
The TUI no longer styles the source and assembly code highlighted
by the current position indicator by default. You can however
re-enable styling using the new "set style tui-current-position"
command.
It is now possible to use the "document" command to document
user-defined commands.
Support for memory tag data for AArch64 MTE.
Support Removal notices:
DBX mode has been removed.
Support for building against Python version 2 has been removed. It
is now only possible to build GDB against Python 3.
Support for the following commands has been removed:

set debug aix-solib on|off
show debug aix-solib
set debug solib-frv on|off
show debug solib-frv

Use the "set/show debug solib" commands instead.
See the NEWS file for a more complete and detailed list of what
this release includes.

Dec 18th, 2022: GDB 13 branch created
The GDB 13 branch (gdb-13-branch) has been created. To check out
a copy of the branch use:

git clone --branch gdb-13-branch https://sourceware.org/git/binutils-gdb.git
May 1st, 2022: GDB 12.1 Released!
The latest version of GDB, version 12.1, is available for download.

This version of GDB includes the following changes and enhancements:

New support for the following native configuration:
GNU/Linux/OpenRISC or1k*-*-linux*
New support for the following targets:
GNU/Linux/LoongArch loongarch*-*-linux*
New GDBserver support on the following configuration:
GNU/Linux/OpenRISC or1k*-*-linux*
Support for the following target has been removed:
S+core score-*-*
Multithreaded symbol loading is now enabled by default

Deprecation Notices:
GDB 12 is the last release of GDB that will support building against Python 2
DBX mode is deprecated, and will be removed in GDB 13
GDB/MI changes:
The '-add-inferior' with no option flags now inherits the connection
of the current inferior, this restores the behaviour of GDB as it
was prior to GDB 10.
The '-add-inferior' command now accepts a '--no-connection' option,
which causes the new inferior to start without a connection.

Python API enhancements:
It is now possible to add GDB/MI commands implemented in Python
New function gdb.Architecture.integer_type()
New gdb.events.gdb_exiting event
New 'gdb.events.connection_removed' event registry
New gdb.TargetConnection object
New gdb.Inferior.connection property
New read-only attribute gdb.InferiorThread.details
New gdb.RemoteTargetConnection.send_packet method
New read-only attributes gdb.Type.is_scalar and gdb.Type.is_signed
The gdb.Value.format_string method now takes a 'styling' argument
Various new function in the "gdb" module
Miscellaneous:
The FreeBSD native target now supports async mode

Improved C++ template support
Support for disabling source highlighting through GNU of the Pygments
library instead.
The "print" command has been changed so as to print floating-point
values with a base-modifying formats such as "/x" to display the
underlying bytes of the value in the desired base.
The "clone-inferior" command now ensures that the TTY, CMD and ARGS
settings are copied from the original inferior to the new one. All
modifications to the environment variables done using the 'set
environment' or 'unset environment' commands are also copied to
the new inferior.
Various new commands have been introduced
See the NEWS file for a more complete and detailed list of what
this release includes.

Mar 20th, 2022: GDB 12 branch created
The GDB 12 branch (gdb-12-branch) has been created. To check out a copy of the branch use:

git clone --branch gdb-12-branch https://sourceware.org/git/binutils-gdb.git
January 16th, 2022: GDB 11.2 Released!
The latest version of GDB, version 11.2, is available for download.

This is a minor corrective release over GDB 11.1, fixing the following issues:

PR sim/28302 (gdb fails to build with glibc 2.34)
PR build/28318 (std::thread support configure check does not use CXX_DIALECT)
PR gdb/28405 (arm-none-eabi: internal-error: ptid_t
	      remote_target::select_thread_for_ambiguous_stop_reply(const
	      target_waitstatus*): Assertion `first_resumed_thread != nullptr'
	      failed)
PR tui/28483 ([gdb/tui] breakpoint creation not displayed)
PR build/28555 (uclibc compile failure since commit
		4655f8509fd44e6efabefa373650d9982ff37fd6)
PR rust/28637 (Rust characters will be encoded using DW_ATE_UTF)
PR gdb/28758 (GDB 11 doesn't work correctly on binaries with a
              SHT_RELR (.relr.dyn) section)
PR gdb/28785 (Support SHT_RELR (.relr.dyn) section)
See the NEWS file for a more complete and detailed list of what
this release includes.

September 13th, 2021: GDB 11.1 Released!
The latest version of GDB, version 11.1, is available for download.

This version of GDB includes the following changes and enhancements:

Support for ARM Symbian (arm*-*-symbianelf*) has been removed.
Building GDB now requires GMP (The GNU Multiple Precision Arithmetic Library).
New command-line options "--early-init-command" (or "-eix") and
"--early-init-eval-command" (or "-eiex")

GDB/MI Changes:
New --qualified option for the '-break-insert' and '-dprintf-insert' commands.
New --force-condition option for the '-break-insert' and
'-dprintf-insert' commands.
New --force option for the '-break-condition' command.
The '-file-list-exec-source-files' now accepts an optional regular
expression to filter the source files included in the result.
The results from '-file-list-exec-source-files' now include a
'debug-fully-read' field to indicate if the corresponding source's
debugging information has been partially read (false) or has been
fully read (true).

TUI Improvements:
Mouse actions are now supported. The mouse wheel scrolls the
appropriate window.  Key combinations that do not have a specific
action on the focused window are now passed to GDB.

Python enhancements:
Inferior objects now contain a read-only 'connection_num' attribute
that gives the connection number as seen in 'info connections' and
'info inferiors'.
New method gdb.Frame.level() which returns the stack level of the frame object.
New method gdb.PendingFrame.level() which returns the stack level
of the frame object.
When hitting a catchpoint, the Python API will now emit a
gdb.BreakpointEvent rather than a gdb.StopEvent. The gdb.Breakpoint
attached to the event will have type BP_CATCHPOINT.
Python TUI windows can now receive mouse click events. If the Window
object implements the click method, it is called for each mouse
click event in this window.  New setting "python ignore-environment
on|off"; if "on", causes GDB's builtin Python to ignore any
environment variable that would otherwise affect how Python behaves
(needs to be set during "early initialization" (see above).  New
setting "python dont-write-bytecode auto|on|off".

Guile API enhancements:
Improved support for rvalue reference values.
New procedures for obtaining value variants: value-reference-value,
value-rvalue-reference-value and value-const-value.
New "qMemTags" and "QMemTags" remote protocol packets (associated
with Memory Tagging).
GDB will now look for the .gdbinit file in a config directory before
looking for ~/.gdbinit. The file is searched for in the following
locations: $XDG_CONFIG_HOME/gdb/gdbinit, $HOME/.config/gdb/gdbinit,
$HOME/.gdbinit. On Apple hosts the search order is instead:
$HOME/Library/Preferences/gdb/gdbinit, $HOME/.gdbinit.  The "break
[...] if CONDITION" command no longer returns an error when the
condition is invalid at one or more locations. Instead, if the
condition is valid at one or more locations, the locations where
the condition is not valid are disabled.
The behavior of the "condition" command is changed to match the
new behavior of the "break" command.

Support for general memory tagging functionality (currently limited
to AArch64 MTE)

Core file debugging now supported for x86_64 Cygwin programs.
New "org.gnu.gdb.riscv.vector" feature for RISC-V targets.
GDB now supports fixed point types which are described in DWARF as
base types with a fixed-point encoding. Additionally, support for
the DW_AT_GNU_numerator and DW_AT_GNU_denominator has also been
added.

Miscellaneous:
New "startup-quietly on|off" setting; when "on", behaves the same
as passing the "-silent" option on the command line.
New "print type hex on|off" setting; when 'on', the 'ptype' command
uses hexadecimal notation to print sizes and offsets of struct
members. When 'off', decimal notation is used.
The "inferior" command, when run without argument, prints information
about the current inferior.
The "ptype" command now supports "/x" and "/d", affecting the base
used to print sizes and offsets.
The output of the "info source" has been restructured.
New "style version foreground | background | intensity" commands
to control the styling of the GDB version number.
Various debug and maintenance commands (mostly useful for the GDB
developers) See the NEWS file for a more complete and detailed list
of what this release includes.
@
text
@d629 1
a629 1
static macro const macros[] =
d662 1
a662 1
static const macro *
d665 1
a665 1
  const macro *m;
d675 1
a675 1
expand_macro (arg *args, int narg, const macro *mac)
d725 1
a725 1
  const macro *pmacro = NULL;
d872 3
d876 1
a876 1
print_tpreg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, void *dis_info,
d886 1
a886 1
print_spreg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, void *dis_info,
d1454 2
a1455 4
      if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
	{
	  mep_config_index = abfd->tdata.elf_obj_data->elf_header->e_flags & EF_MEP_INDEX_MASK;
	  /* This instantly redefines MEP_CONFIG, MEP_OMASK, .... MEP_VLIW64 */
d1457 3
a1459 4
	  cop_type = abfd->tdata.elf_obj_data->elf_header->e_flags & EF_MEP_COP_MASK;
	  if (cop_type == EF_MEP_COP_IVC2)
	    ivc2 = 1;
	}
@


1.1.1.4.2.1
log
@Sync with HEAD
@
text
@d85 1
a85 1
#define MEP_ALL_COP_ISAS_MASK mep_all_cop_isas_mask
a351 1
    /* xgettext:no-c-format */
d536 1
a536 1
	  abort ();
a547 1
    /* xgettext:no-c-format */
d582 1
a582 1
  if (strncmp (*strp, "0x0", 3) == 0
d649 1
a649 1
{
d685 4
a688 4
      if (*e == '`'
	  && (*e+1)
	  && ((*(e + 1) - '1') <= MAXARGS)
	  && ((*(e + 1) - '1') <= narg))
d709 1
a709 1
  else
d734 2
a735 2
	  if (*in == '%' && *(in + 1) && (!first_only || num_expansions == 0))
	    {
d746 1
a746 1
		      state = IN_TEXT;
d755 1
a755 1
		      mark = in + 1;
d796 1
a796 1
		  break;
d798 1
a798 1
	    }
d806 1
d810 1
a810 1

d813 1
a813 1

d852 1
a852 1
	*strp_in = strstr (*strp_in, str);
d855 1
a855 1
	*strp_in += (str - hold);
d863 1
a863 1
#define CGEN_ASM_INIT_HOOK (cd->parse_operand = mep_cgen_expand_macros_and_parse_operand);
d948 1
a948 1

d952 1
a952 1

d961 2
a962 2
      /* Print the + to indicate that the following copro insn is
	 part of a vliw group.  */
d964 1
a964 1
	(*info->fprintf_func) (info->stream, " + ");
d976 1
a976 1

d995 1
a995 1
	  break;
d1028 1
a1028 1

d1041 1
a1041 1
	  cd->isas = 1 << ISA_EXT_COP1_64;
d1069 5
a1073 7
/* The two functions mep_examine_vliw[32,64]_insns are used find out
   which vliw combinaion (16 bit core with 48 bit copro, 32 bit core
   with 32 bit copro, etc.) is present.  Later on, when internally
   parallel coprocessors are handled, only these functions should
   need to be changed.

   At this time only the following combinations are supported:
d1075 2
d1083 1
a1083 1
         no 16 bit coprocessor insns have been specified.
d1089 1
a1089 1

d1091 1
a1091 1
   present (2nd coprocessor insn is cop2), but at this time it
d1102 1
a1102 1
  bfd_byte buf[CGEN_MAX_INSN_SIZE];
d1104 1
a1104 1
  char indicatorcop32[2];
d1143 2
a1144 2
	  /* We have a 32 bit copro insn.  */
	  corebuflength = 0;
d1146 1
a1146 1
	  cop1buflength = 4;
d1150 3
a1152 3
	  /* We have a 32 bit core.  */
	  corebuflength = 4;
	  cop1buflength = 0;
d1232 2
a1233 2
	  /* We have a 64 bit copro insn.  */
	  corebuflength = 0;
d1235 1
a1235 1
	  cop1buflength = 8;
d1239 3
a1241 3
	  /* We have a 32 bit core insn and a 32 bit copro insn.  */
	  corebuflength = 4;
	  cop1buflength = 4;
d1293 2
a1294 2
	{
	  insn_list = CGEN_DIS_NEXT_INSN (insn_list);
d1296 1
a1296 1
	}
a1455 14
	  /* mep_config_map is a variable sized array, so we do not know how big it is.
	     The only safe way to check the index therefore is to iterate over the array.
	     We do know that the last entry is all null.  */
	  int i;
	  for (i = 0; i <= mep_config_index; i++)
	    if (mep_config_map[i].name == NULL)
	      break;

	  if (i < mep_config_index)
	    {
	      opcodes_error_handler (_("illegal MEP INDEX setting '%x' in ELF header e_flags field"), mep_config_index);
	      mep_config_index = 0;
	    }

@


1.1.1.5
log
@Import gdb-15.1, previous was 13.2

ChangeLog:

2024-03-20  Simon Marchi  <simon.marchi@@efficios.com>

	* .pre-commit-config.yaml: Bump black hook to 24.3.0

2024-03-20  Simon Marchi  <simon.marchi@@efficios.com>

	* .pre-commit-config.yaml: New.

2024-03-14  Simon Marchi  <simon.marchi@@efficios.com>

	* Makefile.def: Add configure-gdbserver and all-gdbserver
	dependencies on all-libiconv.
	* Makefile.in: Re-generate.

2024-01-15  Nick Clifton  <nickc@@redhat.com>

	* 2.42 branch point.

2023-11-15  Arsen Arsenović  <arsen@@aarsen.me>

	* intl: Remove directory.  Replaced with out-of-tree GNU
	gettext.
	* .gitignore: Add '/gettext*'.
	* configure.ac (host_libs): Replace intl with gettext.
	(hbaseargs, bbaseargs, baseargs): Split baseargs into
	{h,b}baseargs.
	(skip_barg): New flag.  Skips appending current flag to
	bbaseargs.
	<library exemptions>: Exempt --with-libintl-{type,prefix} from
	target and build machine argument passing.
	* configure: Regenerate.
	* Makefile.def (host_modules): Replace intl module with gettext
	module.
	(configure-ld): Depend on configure-gettext.
	* Makefile.in: Regenerate.
	* src-release.sh: Remove references to the intl/ directory.

2023-07-03  Nick Clifton  <nickc@@redhat.com>

	2.41 Branch Point.

2023-06-26  Nick Clifton  <nickc@@redhat.com>

	* Import these updates to the config scripts

	commit 4ad4bb7c30aca1e705448ba8d51a210bbd47bb52
	Author: Paul Eggert <eggert@@cs.ucla.edu>
	Date:   Fri Jun 23 09:55:10 2023 -0700

		Quote 'like this', not `like this'.

	commit 63acb96f92473ceb5e21d873d7c0aee266b3d6d3
	Author: Paul Eggert <eggert@@cs.ucla.edu>
	Date:   Sat Jan 21 00:15:01 2023 -0600

		Fix config.sub spelling typo for "athlon"

	commit 4ce12a5c9125cedc0d0ba584444a6865396923ec
	Author: Dmitry V. Levin <ldv@@altlinux.org>
	Date:   Sun Jan 1 08:00:00 2023 +0000

		Update copyright years

	commit c397e2c040bce50bcdccb131f90115ba7e8bfc19
	Author: Arsen Arsenovi <arsen@@aarsen.me>
	Date:   Sat Sep 17 23:34:48 2022 +0200

		config.sub: add linux-mlibc targets

	commit 9f9f9b0b13197269848c76e3e057a3ed0680b4bf
	Author: Arsen Arsenovi <arsen@@aarsen.me>
	Date:   Sat Sep 17 23:34:47 2022 +0200

		config.guess: support running on Managarm systems

	commit 87e6687749da7bb2ab158a79fa83721c19ed9246
	Author: Arsen Arsenovi <arsen@@aarsen.me>
	Date:   Sat Sep 17 23:34:46 2022 +0200

		config.sub: add managarm-{mlibc,kernel} targets

	commit 20403c5701973a4cbd7e0b4bbeb627fcd424a0f1
	Author: Xiaotian Wu <wuxiaotian@@loongson.cn>
	Date:   Mon Aug 1 16:05:29 2022 +0800

		Remove loongarchx32

	commit 02ba26b218d3d3db6c56e014655faf463cefa983
	Author: Alexander von Gluck IV <kallisti5@@unixzen.com>
	Date:   Wed May 25 15:43:13 2022 -0500

		config.guess: Update Haiku guesses

	commit f56a7140386d08a531bcfd444d632b28c61a6329
	Author: Bruno Haible <bruno@@clisp.org>
	Date:   Sun May 8 19:08:08 2022 +0200

		config.guess (x86_64:Linux:*:*): Detect 32-bit ABI.

2023-04-20  Nick Clifton  <nickc@@redhat.com>

	* SECURITY.txt: New file.
	* src-release.sh (DEVO_SUPPORT): Add SECURITY.txt.

2022-12-31  Nick Clifton  <nickc@@redhat.com>

	* 2.40 binutils branch created.
@
text
@d85 1
a85 1
#define MEP_ALL_COP_ISAS_MASK mep_all_cop_isas_mask
a351 1
    /* xgettext:no-c-format */
d536 1
a536 1
	  abort ();
a547 1
    /* xgettext:no-c-format */
d582 1
a582 1
  if (strncmp (*strp, "0x0", 3) == 0
d649 1
a649 1
{
d685 4
a688 4
      if (*e == '`'
	  && (*e+1)
	  && ((*(e + 1) - '1') <= MAXARGS)
	  && ((*(e + 1) - '1') <= narg))
d709 1
a709 1
  else
d734 2
a735 2
	  if (*in == '%' && *(in + 1) && (!first_only || num_expansions == 0))
	    {
d746 1
a746 1
		      state = IN_TEXT;
d755 1
a755 1
		      mark = in + 1;
d796 1
a796 1
		  break;
d798 1
a798 1
	    }
d806 1
d810 1
a810 1

d813 1
a813 1

d852 1
a852 1
	*strp_in = strstr (*strp_in, str);
d855 1
a855 1
	*strp_in += (str - hold);
d863 1
a863 1
#define CGEN_ASM_INIT_HOOK (cd->parse_operand = mep_cgen_expand_macros_and_parse_operand);
d948 1
a948 1

d952 1
a952 1

d961 2
a962 2
      /* Print the + to indicate that the following copro insn is
	 part of a vliw group.  */
d964 1
a964 1
	(*info->fprintf_func) (info->stream, " + ");
d976 1
a976 1

d995 1
a995 1
	  break;
d1028 1
a1028 1

d1041 1
a1041 1
	  cd->isas = 1 << ISA_EXT_COP1_64;
d1069 5
a1073 7
/* The two functions mep_examine_vliw[32,64]_insns are used find out
   which vliw combinaion (16 bit core with 48 bit copro, 32 bit core
   with 32 bit copro, etc.) is present.  Later on, when internally
   parallel coprocessors are handled, only these functions should
   need to be changed.

   At this time only the following combinations are supported:
d1075 2
d1083 1
a1083 1
         no 16 bit coprocessor insns have been specified.
d1089 1
a1089 1

d1091 1
a1091 1
   present (2nd coprocessor insn is cop2), but at this time it
d1102 1
a1102 1
  bfd_byte buf[CGEN_MAX_INSN_SIZE];
d1104 1
a1104 1
  char indicatorcop32[2];
d1143 2
a1144 2
	  /* We have a 32 bit copro insn.  */
	  corebuflength = 0;
d1146 1
a1146 1
	  cop1buflength = 4;
d1150 3
a1152 3
	  /* We have a 32 bit core.  */
	  corebuflength = 4;
	  cop1buflength = 0;
d1232 2
a1233 2
	  /* We have a 64 bit copro insn.  */
	  corebuflength = 0;
d1235 1
a1235 1
	  cop1buflength = 8;
d1239 3
a1241 3
	  /* We have a 32 bit core insn and a 32 bit copro insn.  */
	  corebuflength = 4;
	  cop1buflength = 4;
d1293 2
a1294 2
	{
	  insn_list = CGEN_DIS_NEXT_INSN (insn_list);
d1296 1
a1296 1
	}
a1455 14
	  /* mep_config_map is a variable sized array, so we do not know how big it is.
	     The only safe way to check the index therefore is to iterate over the array.
	     We do know that the last entry is all null.  */
	  int i;
	  for (i = 0; i <= mep_config_index; i++)
	    if (mep_config_map[i].name == NULL)
	      break;

	  if (i < mep_config_index)
	    {
	      opcodes_error_handler (_("illegal MEP INDEX setting '%x' in ELF header e_flags field"), mep_config_index);
	      mep_config_index = 0;
	    }

@


1.1.1.1.8.1
log
@file mep.opc was added on branch tls-maxphys on 2014-08-19 23:58:39 +0000
@
text
@d1 1669
@


1.1.1.1.8.2
log
@Rebase to HEAD as of a few days ago.
@
text
@a0 1669
/* MeP opcode support.  -*- C -*-
   Copyright 2011 Free Software Foundation, Inc.

   Contributed by Red Hat Inc;

   This file is part of the GNU Binutils.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   MA 02110-1301, USA.  */

/* -- opc.h */

#undef  CGEN_DIS_HASH_SIZE
#define CGEN_DIS_HASH_SIZE 1

#undef  CGEN_DIS_HASH
#define CGEN_DIS_HASH(buffer, insn) 0

#define CGEN_VERBOSE_ASSEMBLER_ERRORS

typedef struct
{
  char * name;
  int    config_enum;
  unsigned cpu_flag;
  int    big_endian;
  int    vliw_bits;
  CGEN_ATTR_VALUE_BITSET_TYPE cop16_isa;
  CGEN_ATTR_VALUE_BITSET_TYPE cop32_isa;
  CGEN_ATTR_VALUE_BITSET_TYPE cop48_isa;
  CGEN_ATTR_VALUE_BITSET_TYPE cop64_isa;
  CGEN_ATTR_VALUE_BITSET_TYPE cop_isa;
  CGEN_ATTR_VALUE_BITSET_TYPE core_isa;
  unsigned int option_mask;
} mep_config_map_struct;

extern mep_config_map_struct mep_config_map[];
extern int mep_config_index;

extern void init_mep_all_core_isas_mask (void);
extern void init_mep_all_cop_isas_mask  (void);
extern CGEN_ATTR_VALUE_BITSET_TYPE mep_cop_isa  (void);

#define MEP_CONFIG     (mep_config_map[mep_config_index].config_enum)
#define MEP_CPU        (mep_config_map[mep_config_index].cpu_flag)
#define MEP_OMASK      (mep_config_map[mep_config_index].option_mask)
#define MEP_VLIW       (mep_config_map[mep_config_index].vliw_bits > 0)
#define MEP_VLIW32     (mep_config_map[mep_config_index].vliw_bits == 32)
#define MEP_VLIW64     (mep_config_map[mep_config_index].vliw_bits == 64)
#define MEP_COP16_ISA  (mep_config_map[mep_config_index].cop16_isa)
#define MEP_COP32_ISA  (mep_config_map[mep_config_index].cop32_isa)
#define MEP_COP48_ISA  (mep_config_map[mep_config_index].cop48_isa)
#define MEP_COP64_ISA  (mep_config_map[mep_config_index].cop64_isa)
#define MEP_COP_ISA    (mep_config_map[mep_config_index].cop_isa)
#define MEP_CORE_ISA   (mep_config_map[mep_config_index].core_isa)

/* begin-cop-ip-supported-defines */
#define MEP_IVC2_SUPPORTED 1
/* end-cop-ip-supported-defines */

extern int mep_insn_supported_by_isa (const CGEN_INSN *, CGEN_ATTR_VALUE_BITSET_TYPE *);

/* A mask for all ISAs executed by the core.  */
#define MEP_ALL_CORE_ISAS_MASK mep_all_core_isas_mask
extern CGEN_ATTR_VALUE_BITSET_TYPE mep_all_core_isas_mask;

#define MEP_INSN_CORE_P(insn) ( \
  init_mep_all_core_isas_mask (), \
  mep_insn_supported_by_isa (insn, & MEP_ALL_CORE_ISAS_MASK) \
)

/* A mask for all ISAs executed by a VLIW coprocessor.  */
#define MEP_ALL_COP_ISAS_MASK mep_all_cop_isas_mask 
extern CGEN_ATTR_VALUE_BITSET_TYPE mep_all_cop_isas_mask;

#define MEP_INSN_COP_P(insn) ( \
  init_mep_all_cop_isas_mask (), \
  mep_insn_supported_by_isa (insn, & MEP_ALL_COP_ISAS_MASK) \
)

extern int mep_cgen_insn_supported (CGEN_CPU_DESC, const CGEN_INSN *);
extern int mep_cgen_insn_supported_asm (CGEN_CPU_DESC, const CGEN_INSN *);

/* -- asm.c */

#include "elf/mep.h"

#define CGEN_VALIDATE_INSN_SUPPORTED
#define mep_cgen_insn_supported mep_cgen_insn_supported_asm

       const char * parse_csrn       (CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *);
       const char * parse_tpreg      (CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *);
       const char * parse_spreg      (CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *);
       const char * parse_mep_align  (CGEN_CPU_DESC, const char **, enum cgen_operand_type, long *);
       const char * parse_mep_alignu (CGEN_CPU_DESC, const char **, enum cgen_operand_type, unsigned long *);
static const char * parse_signed16   (CGEN_CPU_DESC, const char **, int, long *);
static const char * parse_signed16_range   (CGEN_CPU_DESC, const char **, int, long *) ATTRIBUTE_UNUSED;
static const char * parse_unsigned16 (CGEN_CPU_DESC, const char **, int, unsigned long *);
static const char * parse_unsigned16_range (CGEN_CPU_DESC, const char **, int, unsigned long *) ATTRIBUTE_UNUSED;
static const char * parse_lo16       (CGEN_CPU_DESC, const char **, int, long *, long);
static const char * parse_unsigned7  (CGEN_CPU_DESC, const char **, enum cgen_operand_type, unsigned long *);
static const char * parse_zero       (CGEN_CPU_DESC, const char **, int, long *);

const char *
parse_csrn (CGEN_CPU_DESC cd, const char **strp,
	    CGEN_KEYWORD *keyword_table, long *field)
{
  const char *err;
  unsigned long value;

  err = cgen_parse_keyword (cd, strp, keyword_table, field);
  if (!err)
    return NULL;

  err = cgen_parse_unsigned_integer (cd, strp, MEP_OPERAND_CSRN_IDX, & value);
  if (err)
    return err;
  *field = value;
  return NULL;
}

/* begin-cop-ip-parse-handlers */
static const char *
parse_ivc2_cr (CGEN_CPU_DESC,
	const char **,
	CGEN_KEYWORD *,
	long *) ATTRIBUTE_UNUSED;
static const char *
parse_ivc2_cr (CGEN_CPU_DESC cd,
	const char **strp,
	CGEN_KEYWORD *keyword_table  ATTRIBUTE_UNUSED,
	long *field)
{
  return cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_cr_ivc2, field);
}
static const char *
parse_ivc2_ccr (CGEN_CPU_DESC,
	const char **,
	CGEN_KEYWORD *,
	long *) ATTRIBUTE_UNUSED;
static const char *
parse_ivc2_ccr (CGEN_CPU_DESC cd,
	const char **strp,
	CGEN_KEYWORD *keyword_table  ATTRIBUTE_UNUSED,
	long *field)
{
  return cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_ccr_ivc2, field);
}
/* end-cop-ip-parse-handlers */

const char *
parse_tpreg (CGEN_CPU_DESC cd, const char ** strp,
	     CGEN_KEYWORD *keyword_table, long *field)
{
  const char *err;

  err = cgen_parse_keyword (cd, strp, keyword_table, field);
  if (err)
    return err;
  if (*field != 13)
    return _("Only $tp or $13 allowed for this opcode");
  return NULL;
}

const char *
parse_spreg (CGEN_CPU_DESC cd, const char ** strp,
	     CGEN_KEYWORD *keyword_table, long *field)
{
  const char *err;

  err = cgen_parse_keyword (cd, strp, keyword_table, field);
  if (err)
    return err;
  if (*field != 15)
    return _("Only $sp or $15 allowed for this opcode");
  return NULL;
}

const char *
parse_mep_align (CGEN_CPU_DESC cd, const char ** strp,
		 enum cgen_operand_type type, long *field)
{
  long lsbs = 0;
  const char *err;

  switch (type)
    {
    case MEP_OPERAND_PCREL8A2:
    case MEP_OPERAND_PCREL12A2:
    case MEP_OPERAND_PCREL17A2:
    case MEP_OPERAND_PCREL24A2:
      err = cgen_parse_signed_integer   (cd, strp, type, field);
      break;
    case MEP_OPERAND_PCABS24A2:
    case MEP_OPERAND_UDISP7:
    case MEP_OPERAND_UDISP7A2:
    case MEP_OPERAND_UDISP7A4:
    case MEP_OPERAND_UIMM7A4:
    case MEP_OPERAND_ADDR24A4:
      err = cgen_parse_unsigned_integer (cd, strp, type, (unsigned long *) field);
      break;
    default:
      abort();
    }
  if (err)
    return err;
  switch (type)
    {
    case MEP_OPERAND_UDISP7:
      lsbs = 0;
      break;
    case MEP_OPERAND_PCREL8A2:
    case MEP_OPERAND_PCREL12A2:
    case MEP_OPERAND_PCREL17A2:
    case MEP_OPERAND_PCREL24A2:
    case MEP_OPERAND_PCABS24A2:
    case MEP_OPERAND_UDISP7A2:
      lsbs = *field & 1;
      break;
    case MEP_OPERAND_UDISP7A4:
    case MEP_OPERAND_UIMM7A4:
    case MEP_OPERAND_ADDR24A4:
      lsbs = *field & 3;
      break;
      lsbs = *field & 7;
      break;
    default:
      /* Safe assumption?  */
      abort ();
    }
  if (lsbs)
    return "Value is not aligned enough";
  return NULL;
}

const char *
parse_mep_alignu (CGEN_CPU_DESC cd, const char ** strp,
		 enum cgen_operand_type type, unsigned long *field)
{
  return parse_mep_align (cd, strp, type, (long *) field);
}


/* Handle %lo(), %tpoff(), %sdaoff(), %hi(), and other signed
   constants in a signed context.  */

static const char *
parse_signed16 (CGEN_CPU_DESC cd,
		const char **strp,
		int opindex,
		long *valuep)
{
  return parse_lo16 (cd, strp, opindex, valuep, 1);
}

static const char *
parse_lo16 (CGEN_CPU_DESC cd,
	    const char **strp,
	    int opindex,
	    long *valuep,
	    long signedp)
{
  const char *errmsg;
  enum cgen_parse_operand_result result_type;
  bfd_vma value;

  if (strncasecmp (*strp, "%lo(", 4) == 0)
    {
      *strp += 4;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_LOW16,
				   & result_type, & value);
      if (**strp != ')')
	return _("missing `)'");
      ++*strp;
      if (errmsg == NULL
	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
	value &= 0xffff;
      if (signedp)
	*valuep = (long)(short) value;
      else
	*valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%hi(", 4) == 0)
    {
      *strp += 4;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_HI16S,
				   & result_type, & value);
      if (**strp != ')')
	return _("missing `)'");
      ++*strp;
      if (errmsg == NULL
	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
	value = (value + 0x8000) >> 16;
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%uhi(", 5) == 0)
    {
      *strp += 5;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_HI16U,
				   & result_type, & value);
      if (**strp != ')')
	return _("missing `)'");
      ++*strp;
      if (errmsg == NULL
	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
	value = value >> 16;
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%sdaoff(", 8) == 0)
    {
      *strp += 8;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_GPREL,
				   NULL, & value);
      if (**strp != ')')
	return _("missing `)'");
      ++*strp;
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%tpoff(", 7) == 0)
    {
      *strp += 7;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_TPREL,
				   NULL, & value);
      if (**strp != ')')
	return _("missing `)'");
      ++*strp;
      *valuep = value;
      return errmsg;
    }

  if (**strp == '%')
    return _("invalid %function() here");

  return cgen_parse_signed_integer (cd, strp, opindex, valuep);
}

static const char *
parse_unsigned16 (CGEN_CPU_DESC cd,
		  const char **strp,
		  int opindex,
		  unsigned long *valuep)
{
  return parse_lo16 (cd, strp, opindex, (long *) valuep, 0);
}

static const char *
parse_signed16_range (CGEN_CPU_DESC cd,
		      const char **strp,
		      int opindex,
		      signed long *valuep)
{
  const char *errmsg = 0;
  signed long value;

  errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value);
  if (errmsg)
    return errmsg;

  if (value < -32768 || value > 32767)
    return _("Immediate is out of range -32768 to 32767");

  *valuep = value;
  return 0;
}

static const char *
parse_unsigned16_range (CGEN_CPU_DESC cd,
			const char **strp,
			int opindex,
			unsigned long *valuep)
{
  const char *errmsg = 0;
  unsigned long value;

  errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, & value);
  if (errmsg)
    return errmsg;

  if (value > 65535)
    return _("Immediate is out of range 0 to 65535");

  *valuep = value;
  return 0;
}

/* A special case of parse_signed16 which accepts only the value zero.  */

static const char *
parse_zero (CGEN_CPU_DESC cd, const char **strp, int opindex, long *valuep)
{
  const char *errmsg;
  enum cgen_parse_operand_result result_type;
  bfd_vma value;

  /*fprintf(stderr, "dj: signed parse opindex `%s'\n", *strp);*/

  /* Prevent ($ry) from being attempted as an expression on 'sw $rx,($ry)'.
     It will fail and cause ry to be listed as an undefined symbol in the
     listing.  */
  if (strncmp (*strp, "($", 2) == 0)
    return "not zero"; /* any string will do -- will never be seen.  */

  if (strncasecmp (*strp, "%lo(", 4) == 0)
    {
      *strp += 4;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_LOW16,
				   &result_type, &value);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      if (errmsg == NULL
	  && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
	return "not zero"; /* any string will do -- will never be seen.  */
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%hi(", 4) == 0)
    {
      *strp += 4;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_HI16S,
				   &result_type, &value);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      if (errmsg == NULL
	  && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
	return "not zero"; /* any string will do -- will never be seen.  */
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%uhi(", 5) == 0)
    {
      *strp += 5;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_HI16U,
				   &result_type, &value);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      if (errmsg == NULL
	  && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
	return "not zero"; /* any string will do -- will never be seen.  */
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%sdaoff(", 8) == 0)
    {
      *strp += 8;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_GPREL,
				   &result_type, &value);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      if (errmsg == NULL
	  && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
	return "not zero"; /* any string will do -- will never be seen.  */
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%tpoff(", 7) == 0)
    {
      *strp += 7;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_TPREL,
				   &result_type, &value);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      if (errmsg == NULL
	  && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
	return "not zero"; /* any string will do -- will never be seen.  */
      *valuep = value;
      return errmsg;
    }

  if (**strp == '%')
    return "invalid %function() here";

  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_NONE,
			       &result_type, &value);
  if (errmsg == NULL
      && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
    return "not zero"; /* any string will do -- will never be seen.  */

  return errmsg;
}

static const char *
parse_unsigned7 (CGEN_CPU_DESC cd, const char **strp,
		 enum cgen_operand_type opindex, unsigned long *valuep)
{
  const char *errmsg;
  bfd_vma value;

  /* fprintf(stderr, "dj: unsigned7 parse `%s'\n", *strp); */

  if (strncasecmp (*strp, "%tpoff(", 7) == 0)
    {
      int reloc;
      *strp += 7;
      switch (opindex)
	{
	case MEP_OPERAND_UDISP7:
	  reloc = BFD_RELOC_MEP_TPREL7;
	  break;
	case MEP_OPERAND_UDISP7A2:
	  reloc = BFD_RELOC_MEP_TPREL7A2;
	  break;
	case MEP_OPERAND_UDISP7A4:
	  reloc = BFD_RELOC_MEP_TPREL7A4;
	  break;
	default:
	  /* Safe assumption?  */
	  abort (); 
	}
      errmsg = cgen_parse_address (cd, strp, opindex, reloc,
				   NULL, &value);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      *valuep = value;
      return errmsg;
    }

  if (**strp == '%')
    return _("invalid %function() here");

  return parse_mep_alignu (cd, strp, opindex, valuep);
}

static ATTRIBUTE_UNUSED const char *
parse_cdisp10 (CGEN_CPU_DESC cd,
	       const char **strp,
	       int opindex,
	       long *valuep)
{
  const char *errmsg = 0;
  signed long value;
  long have_zero = 0;
  int wide = 0;
  int alignment;

  switch (opindex)
    {
    case MEP_OPERAND_CDISP10A4:
      alignment = 2;
      break;
    case MEP_OPERAND_CDISP10A2:
      alignment = 1;
      break;
    case MEP_OPERAND_CDISP10:
    default:
      alignment = 0;
      break;
    }

  if ((MEP_CPU & EF_MEP_CPU_MASK) == EF_MEP_CPU_C5)
    wide = 1;

  if (strncmp (*strp, "0x0", 3) == 0 
      || (**strp == '0' && *(*strp + 1) != 'x'))
    have_zero = 1;

  errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value);
  if (errmsg)
    return errmsg;

  if (wide)
    {
      if (value < -512 || value > 511)
	return _("Immediate is out of range -512 to 511");
    }
  else
    {
      if (value < -128 || value > 127)
	return _("Immediate is out of range -128 to 127");
    }

  if (value & ((1<<alignment)-1))
    return _("Value is not aligned enough");

  /* If this field may require a relocation then use larger dsp16.  */
  if (! have_zero && value == 0)
    return (wide ? _("Immediate is out of range -512 to 511")
	    : _("Immediate is out of range -128 to 127"));

  *valuep = value;
  return 0;
}

/* BEGIN LIGHTWEIGHT MACRO PROCESSOR.  */

#define MAXARGS 9

typedef struct
{
  char *name;
  char *expansion;
}  macro;

typedef struct
{
  const char *start;
  int len;
} arg;

macro macros[] =
{
  { "sizeof", "(`1.end + (- `1))"},
  { "startof", "(`1 | 0)" },
  { "align4", "(`1&(~3))"},
/*{ "hi", "(((`1+0x8000)>>16) & 0xffff)" },  */
/*{ "lo", "(`1 & 0xffff)" },  */
/*{ "sdaoff", "((`1-__sdabase) & 0x7f)"},  */
/*{ "tpoff", "((`1-__tpbase) & 0x7f)"},  */
  { 0,0 }
};

static char  * expand_string    (const char *, int);

static const char *
mep_cgen_expand_macros_and_parse_operand
  (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);

static char *
str_append (char *dest, const char *input, int len)
{  
  char *new_dest;
  int oldlen;

  if (len == 0)
    return dest;
  /* printf("str_append: <<%s>>, <<%s>>, %d\n", dest, input, len); */
  oldlen = (dest ? strlen(dest) : 0);
  new_dest = realloc (dest, oldlen + len + 1);
  memset (new_dest + oldlen, 0, len + 1);
  return strncat (new_dest, input, len);
}

static macro *
lookup_macro (const char *name)
{
  macro *m;

  for (m = macros; m->name; ++m)
    if (strncmp (m->name, name, strlen(m->name)) == 0)
      return m;

  return 0;
}

static char *
expand_macro (arg *args, int narg, macro *mac)
{
  char *result = 0, *rescanned_result = 0;
  char *e = mac->expansion;
  char *mark = e;
  int mac_arg = 0;

  /*  printf("expanding macro %s with %d args\n", mac->name, narg + 1); */
  while (*e)
    {
      if (*e == '`' && 
	  (*e+1) && 
	  ((*(e + 1) - '1') <= MAXARGS) &&
	  ((*(e + 1) - '1') <= narg))
	{
	  result = str_append (result, mark, e - mark);
	  mac_arg = (*(e + 1) - '1');
	  /* printf("replacing `%d with %s\n", mac_arg+1, args[mac_arg].start); */
	  result = str_append (result, args[mac_arg].start, args[mac_arg].len);
	  ++e;
	  mark = e+1;
	}
      ++e;
    }

  if (mark != e)
    result = str_append (result, mark, e - mark);

  if (result)
    {
      rescanned_result = expand_string (result, 0);
      free (result);
      return rescanned_result;
    }
  else 
    return result;
}

#define IN_TEXT 0
#define IN_ARGS 1

static char *
expand_string (const char *in, int first_only)
{
  int num_expansions = 0;
  int depth = 0;
  int narg = -1;
  arg args[MAXARGS];
  int state = IN_TEXT;
  const char *mark = in;
  macro *pmacro = NULL;
  char *expansion = 0;
  char *result = 0;

  while (*in)
    {
      switch (state)
	{
	case IN_TEXT:
	  if (*in == '%' && *(in + 1) && (!first_only || num_expansions == 0)) 
	    {	      
	      pmacro = lookup_macro (in + 1);
	      if (pmacro)
		{
		  /* printf("entering state %d at '%s'...\n", state, in); */
		  result = str_append (result, mark, in - mark);
		  mark = in;
		  in += 1 + strlen (pmacro->name);
		  while (*in == ' ') ++in;
		  if (*in != '(')
		    {
		      state = IN_TEXT;		      
		      pmacro = NULL;
		    }
		  else
		    {
		      state = IN_ARGS;
		      narg = 0;
		      args[narg].start = in + 1;
		      args[narg].len = 0;
		      mark = in + 1;	      		      
		    }
		}
	    }
	  break;
	case IN_ARGS:
	  if (depth == 0)
	    {
	      switch (*in)
		{
		case ',':
		  narg++;
		  args[narg].start = (in + 1);
		  args[narg].len = 0;
		  break;
		case ')':
		  state = IN_TEXT;
		  /* printf("entering state %d at '%s'...\n", state, in); */
		  if (pmacro)
		    {
		      expansion = 0;
		      expansion = expand_macro (args, narg, pmacro);
		      num_expansions++;
		      if (expansion)
			{
			  result = str_append (result, expansion, strlen (expansion));
			  free (expansion);
			}
		    }
		  else
		    {
		      result = str_append (result, mark, in - mark);
		    }
		  pmacro = NULL;
		  mark = in + 1;
		  break;
		case '(':
		  depth++;
		default:
		  args[narg].len++;
		  break;		  
		}
	    } 
	  else
	    {
	      if (*in == ')')
		depth--;
	      if (narg > -1)
		args[narg].len++;
	    }
	  
	}
      ++in;
    }
  
  if (mark != in)
    result = str_append (result, mark, in - mark);
  
  return result;
}

#undef IN_ARGS
#undef IN_TEXT
#undef MAXARGS


/* END LIGHTWEIGHT MACRO PROCESSOR.  */

const char * mep_cgen_parse_operand
  (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);

const char *
mep_cgen_expand_macros_and_parse_operand (CGEN_CPU_DESC cd, int opindex,
					  const char ** strp_in, CGEN_FIELDS * fields)
{
  const char * errmsg = NULL;
  char *str = 0, *hold = 0;
  const char **strp = 0;

  /* Set up a new pointer to macro-expanded string.  */
  str = expand_string (*strp_in, 1);
  /* fprintf (stderr, " expanded <<%s>> to <<%s>>\n", *strp_in, str); */

  hold = str;
  strp = (const char **)(&str);

  errmsg = mep_cgen_parse_operand (cd, opindex, strp, fields);

  /* Now work out the advance.  */
  if (strlen (str) == 0)
    *strp_in += strlen (*strp_in);

  else
    {
      if (strstr (*strp_in, str))
	/* A macro-expansion was pulled off the front.  */
	*strp_in = strstr (*strp_in, str);  
      else
	/* A non-macro-expansion was pulled off the front.  */
	*strp_in += (str - hold); 
    }

  if (hold)
    free (hold);

  return errmsg;
}

#define CGEN_ASM_INIT_HOOK (cd->parse_operand = mep_cgen_expand_macros_and_parse_operand); 

/* -- dis.c */

#include "elf/mep.h"
#include "elf-bfd.h"

#define CGEN_VALIDATE_INSN_SUPPORTED

static void print_tpreg (CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned int);
static void print_spreg (CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned int);

static void
print_tpreg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, PTR dis_info,
	     CGEN_KEYWORD *table ATTRIBUTE_UNUSED, long val ATTRIBUTE_UNUSED,
	     unsigned int flags ATTRIBUTE_UNUSED)
{
  disassemble_info *info = (disassemble_info *) dis_info;

  (*info->fprintf_func) (info->stream, "$tp");
}

static void
print_spreg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, PTR dis_info, 
	     CGEN_KEYWORD *table ATTRIBUTE_UNUSED, long val ATTRIBUTE_UNUSED,
	     unsigned int flags ATTRIBUTE_UNUSED)
{
  disassemble_info *info = (disassemble_info *) dis_info;

  (*info->fprintf_func) (info->stream, "$sp");
}

/* begin-cop-ip-print-handlers */
static void
print_ivc2_cr (CGEN_CPU_DESC,
	void *,
	CGEN_KEYWORD *,
	long,
	unsigned int) ATTRIBUTE_UNUSED;
static void
print_ivc2_cr (CGEN_CPU_DESC cd,
	void *dis_info,
	CGEN_KEYWORD *keyword_table ATTRIBUTE_UNUSED,
	long value,
	unsigned int attrs)
{
  print_keyword (cd, dis_info, & mep_cgen_opval_h_cr_ivc2, value, attrs);
}
static void
print_ivc2_ccr (CGEN_CPU_DESC,
	void *,
	CGEN_KEYWORD *,
	long,
	unsigned int) ATTRIBUTE_UNUSED;
static void
print_ivc2_ccr (CGEN_CPU_DESC cd,
	void *dis_info,
	CGEN_KEYWORD *keyword_table ATTRIBUTE_UNUSED,
	long value,
	unsigned int attrs)
{
  print_keyword (cd, dis_info, & mep_cgen_opval_h_ccr_ivc2, value, attrs);
}
/* end-cop-ip-print-handlers */

/************************************************************\
*********************** Experimental *************************
\************************************************************/

#undef  CGEN_PRINT_INSN
#define CGEN_PRINT_INSN mep_print_insn

static int
mep_print_vliw_insns (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info,
		      bfd_byte *buf, int corelength, int copro1length,
		      int copro2length ATTRIBUTE_UNUSED)
{
  int i;
  int status = 0;
  /* char insnbuf[CGEN_MAX_INSN_SIZE]; */
  bfd_byte insnbuf[64];

  /* If corelength > 0 then there is a core insn present. It
     will be at the beginning of the buffer.  After printing
     the core insn, we need to print the + on the next line.  */
  if (corelength > 0)
    {
      int my_status = 0;
	 
      for (i = 0; i < corelength; i++ )
	insnbuf[i] = buf[i];
      cd->isas = & MEP_CORE_ISA;
	 
      my_status = print_insn (cd, pc, info, insnbuf, corelength);
      if (my_status != corelength)
	{
	  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
	  my_status = corelength;
	}
      status += my_status;

      /* Print the + to indicate that the following copro insn is   */
      /* part of a vliw group.                                      */
      if (copro1length > 0)
	(*info->fprintf_func) (info->stream, " + "); 
    }

  /* Now all that is left to be processed is the coprocessor insns
     In vliw mode, there will always be one.  Its positioning will
     be from byte corelength to byte corelength+copro1length -1.
     No need to check for existence.   Also, the first vliw insn,
     will, as spec'd, always be at least as long as the core insn
     so we don't need to flush the buffer.  */
  if (copro1length > 0)
    {
      int my_status = 0;
	 
      for (i = corelength; i < corelength + copro1length; i++ )
	insnbuf[i - corelength] = buf[i];

      switch (copro1length)
	{
	case 0:
	  break;
	case 2:
	  cd->isas = & MEP_COP16_ISA;
	  break;
	case 4:
	  cd->isas = & MEP_COP32_ISA;
	  break;
	case 6:
	  cd->isas = & MEP_COP48_ISA;
	  break;
	case 8:
	  cd->isas = & MEP_COP64_ISA;
	  break; 
	default:
	  /* Shouldn't be anything but 16,32,48,64.  */
	  break;
	}

      my_status = print_insn (cd, pc, info, insnbuf, copro1length);

      if (my_status != copro1length)
	{
	  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
	  my_status = copro1length;
	}
      status += my_status;
    }

#if 0
  /* Now we need to process the second copro insn if it exists. We
     have no guarantee that the second copro insn will be longer
     than the first, so we have to flush the buffer if we are have
     a second copro insn to process.  If present, this insn will
     be in the position from byte corelength+copro1length to byte
     corelength+copro1length+copro2length-1 (which better equal 8
     or else we're in big trouble.  */
  if (copro2length > 0)
    {
      int my_status = 0;

      for (i = 0; i < 64 ; i++)
	insnbuf[i] = 0;

      for (i = corelength + copro1length; i < 64; i++)
	insnbuf[i - (corelength + copro1length)] = buf[i];
      
      switch (copro2length)
	{
	case 2:
	  cd->isas = 1 << ISA_EXT_COP1_16;
	  break;
	case 4:
	  cd->isas = 1 << ISA_EXT_COP1_32;
	  break;
	case 6:
	  cd->isas = 1 << ISA_EXT_COP1_48;
	  break;
	case 8:
	  cd->isas = 1 << ISA_EXT_COP1_64; 
	  break;
	default:
	  /* Shouldn't be anything but 16,32,48,64.  */
	  break;
	}

      my_status = print_insn (cd, pc, info, insnbuf, copro2length);

      if (my_status != copro2length)
	{
	  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
	  my_status = copro2length;
	}

      status += my_status;
    }
#endif

  /* Status should now be the number of bytes that were printed
     which should be 4 for VLIW32 mode and 64 for VLIW64 mode.  */

  if ((!MEP_VLIW64 && (status != 4)) || (MEP_VLIW64 && (status != 8)))
    return -1;
  else
    return status;
}

/* The two functions mep_examine_vliw[32,64]_insns are used find out 
   which vliw combinaion (16 bit core with 48 bit copro, 32 bit core 
   with 32 bit copro, etc.) is present.  Later on, when internally   
   parallel coprocessors are handled, only these functions should    
   need to be changed.                                               

   At this time only the following combinations are supported: 
   
   VLIW32 Mode:
   16 bit core insn (core) and 16 bit coprocessor insn (cop1)
   32 bit core insn (core)
   32 bit coprocessor insn (cop1)
   Note: As of this time, I do not believe we have enough information
         to distinguish a 32 bit core insn from a 32 bit cop insn. Also,
         no 16 bit coprocessor insns have been specified.  

   VLIW64 Mode:
   16 bit core insn (core) and 48 bit coprocessor insn (cop1)
   32 bit core insn (core) and 32 bit coprocessor insn (cop1)
   64 bit coprocessor insn (cop1)
  
   The framework for an internally parallel coprocessor is also
   present (2nd coprocessor insn is cop2), but at this time it 
   is not used.  This only appears to be valid in VLIW64 mode.  */

static int
mep_examine_vliw32_insns (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
{
  int status;
  int buflength;
  int corebuflength;
  int cop1buflength;
  int cop2buflength;
  bfd_byte buf[CGEN_MAX_INSN_SIZE];  
  char indicator16[1];
  char indicatorcop32[2]; 

  /* At this time we're not supporting internally parallel coprocessors,
     so cop2buflength will always be 0.  */
  cop2buflength = 0;

  /* Read in 32 bits.  */
  buflength = 4; /* VLIW insn spans 4 bytes.  */
  status = (*info->read_memory_func) (pc, buf, buflength, info);

  if (status != 0)
    {
      (*info->memory_error_func) (status, pc, info);
      return -1;
    }

  /* Put the big endian representation of the bytes to be examined
     in the temporary buffers for examination.  */

  if (info->endian == BFD_ENDIAN_BIG)
    {
      indicator16[0] = buf[0];
      indicatorcop32[0] = buf[0];
      indicatorcop32[1] = buf[1];
    }
  else
    {
      indicator16[0] = buf[1];
      indicatorcop32[0] = buf[1];
      indicatorcop32[1] = buf[0];
    }

  /* If the two high order bits are 00, 01 or 10, we have a 16 bit
     core insn and a 48 bit copro insn.  */

  if ((indicator16[0] & 0x80) && (indicator16[0] & 0x40))
    {
      if ((indicatorcop32[0] & 0xf0) == 0xf0 && (indicatorcop32[1] & 0x07) == 0x07)
	{
          /* We have a 32 bit copro insn.  */
          corebuflength = 0;
	  /* All 4 4ytes are one copro insn. */
          cop1buflength = 4;
	}
      else
	{
          /* We have a 32 bit core.  */
          corebuflength = 4;
          cop1buflength = 0;
	}
    }
  else
    {
      /* We have a 16 bit core insn and a 16 bit copro insn.  */
      corebuflength = 2;
      cop1buflength = 2;
    }

  /* Now we have the distrubution set.  Print them out.  */
  status = mep_print_vliw_insns (cd, pc, info, buf, corebuflength,
				 cop1buflength, cop2buflength);

  return status;
}

static int
mep_examine_vliw64_insns (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
{
  int status;
  int buflength;
  int corebuflength;
  int cop1buflength;
  int cop2buflength;
  bfd_byte buf[CGEN_MAX_INSN_SIZE];
  char indicator16[1];
  char indicator64[4];

  /* At this time we're not supporting internally parallel
     coprocessors, so cop2buflength will always be 0.  */
  cop2buflength = 0;

  /* Read in 64 bits.  */
  buflength = 8; /* VLIW insn spans 8 bytes.  */
  status = (*info->read_memory_func) (pc, buf, buflength, info);

  if (status != 0)
    {
      (*info->memory_error_func) (status, pc, info);
      return -1;
    }

  /* We have all 64 bits in the buffer now.  We have to figure out
     what combination of instruction sizes are present.  The two
     high order bits will indicate whether or not we have a 16 bit
     core insn or not.  If not, then we have to look at the 7,8th
     bytes to tell whether we have 64 bit copro insn or a 32 bit
     core insn with a 32 bit copro insn.  Endianness will make a
     difference here.  */

  /* Put the big endian representation of the bytes to be examined
     in the temporary buffers for examination.  */

  /* indicator16[0] = buf[0];  */
  if (info->endian == BFD_ENDIAN_BIG)
    {
      indicator16[0] = buf[0];
      indicator64[0] = buf[0];
      indicator64[1] = buf[1];
      indicator64[2] = buf[2];
      indicator64[3] = buf[3];
    }
  else
    {
      indicator16[0] = buf[1];
      indicator64[0] = buf[1];
      indicator64[1] = buf[0];
      indicator64[2] = buf[3];
      indicator64[3] = buf[2];
    }

  /* If the two high order bits are 00, 01 or 10, we have a 16 bit
     core insn and a 48 bit copro insn.  */

  if ((indicator16[0] & 0x80) && (indicator16[0] & 0x40))
    {
      if ((indicator64[0] & 0xf0) == 0xf0 && (indicator64[1] & 0x07) == 0x07
	  && ((indicator64[2] & 0xfe) != 0xf0 || (indicator64[3] & 0xf4) != 0))
	{
          /* We have a 64 bit copro insn.  */
          corebuflength = 0;
	  /* All 8 bytes are one copro insn.  */
          cop1buflength = 8;
	}
      else
	{
          /* We have a 32 bit core insn and a 32 bit copro insn.  */
          corebuflength = 4;
          cop1buflength = 4;
	}
    }
  else
    {
      /* We have a 16 bit core insn and a 48 bit copro insn.  */
      corebuflength = 2;
      cop1buflength = 6;
    }

  /* Now we have the distrubution set.  Print them out. */
  status = mep_print_vliw_insns (cd, pc, info, buf, corebuflength,
				 cop1buflength, cop2buflength);

  return status;
}

#ifdef MEP_IVC2_SUPPORTED

static int
print_slot_insn (CGEN_CPU_DESC cd,
		 bfd_vma pc,
		 disassemble_info *info,
		 SLOTS_ATTR slot,
		 bfd_byte *buf)
{
  const CGEN_INSN_LIST *insn_list;
  CGEN_INSN_INT insn_value;
  CGEN_EXTRACT_INFO ex_info;

  insn_value = cgen_get_insn_value (cd, buf, 32);

  /* Fill in ex_info fields like read_insn would.  Don't actually call
     read_insn, since the incoming buffer is already read (and possibly
     modified a la m32r).  */
  ex_info.valid = (1 << 8) - 1;
  ex_info.dis_info = info;
  ex_info.insn_bytes = buf;

  /* The instructions are stored in hash lists.
     Pick the first one and keep trying until we find the right one.  */

  insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
  while (insn_list != NULL)
    {
      const CGEN_INSN *insn = insn_list->insn;
      CGEN_FIELDS fields;
      int length;

      if ((CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_CONFIG)
	   && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_CONFIG) != MEP_CONFIG)
	  || ! (CGEN_ATTR_CGEN_INSN_SLOTS_VALUE (CGEN_INSN_ATTRS (insn)) & (1 << slot)))
        {
          insn_list = CGEN_DIS_NEXT_INSN (insn_list);
	  continue;
        }

      if ((insn_value & CGEN_INSN_BASE_MASK (insn))
	  == CGEN_INSN_BASE_VALUE (insn))
	{
	  /* Printing is handled in two passes.  The first pass parses the
	     machine insn and extracts the fields.  The second pass prints
	     them.  */

	  length = CGEN_EXTRACT_FN (cd, insn)
	    (cd, insn, &ex_info, insn_value, &fields, pc);

	  /* Length < 0 -> error.  */
	  if (length < 0)
	    return length;
	  if (length > 0)
	    {
	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
	      /* Length is in bits, result is in bytes.  */
	      return length / 8;
	    }
	}

      insn_list = CGEN_DIS_NEXT_INSN (insn_list);
    }

  if (slot == SLOTS_P0S)
    (*info->fprintf_func) (info->stream, "*unknown-p0s*");
  else if (slot == SLOTS_P0)
    (*info->fprintf_func) (info->stream, "*unknown-p0*");
  else if (slot == SLOTS_P1)
    (*info->fprintf_func) (info->stream, "*unknown-p1*");
  else if (slot == SLOTS_C3)
    (*info->fprintf_func) (info->stream, "*unknown-c3*");
  return 0;
}

static int
mep_examine_ivc2_insns (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, bfd_vma pc ATTRIBUTE_UNUSED, disassemble_info *info ATTRIBUTE_UNUSED)
{
  int status;
  int buflength;
  bfd_byte buf[8];
  bfd_byte insn[8];
  int e;

  /* Read in 64 bits.  */
  buflength = 8; /* VLIW insn spans 8 bytes.  */
  status = (*info->read_memory_func) (pc, buf, buflength, info);

  if (status != 0)
    {
      (*info->memory_error_func) (status, pc, info);
      return -1;
    }

  if (info->endian == BFD_ENDIAN_LITTLE)
    e = 1;
  else
    e = 0;

  if (((unsigned char)buf[0^e] & 0xf0) < 0xc0)
    {
      /*      <--00--><--11--><--22--><--33--><--44--><--55--><--66--><--77--> */
      /* V1   [-----core-----][--------p0s-------][------------p1------------] */

      print_insn (cd, pc, info, buf, 2);

      insn[0^e] = 0;
      insn[1^e] = buf[2^e];
      insn[2^e] = buf[3^e];
      insn[3^e] = buf[4^e] & 0xf0;
      (*info->fprintf_func) (info->stream, " + ");
      print_slot_insn (cd, pc, info, SLOTS_P0S, insn);

      insn[0^e] = buf[4^e] << 4 | buf[5^e] >> 4;
      insn[1^e] = buf[5^e] << 4 | buf[6^e] >> 4;
      insn[2^e] = buf[6^e] << 4 | buf[7^e] >> 4;
      insn[3^e] = buf[7^e] << 4;
      (*info->fprintf_func) (info->stream, " + ");
      print_slot_insn (cd, pc, info, SLOTS_P1, insn);
    }
  else if ((buf[0^e] & 0xf0) == 0xf0 && (buf[1^e] & 0x0f) == 0x07)
    {
      /*      <--00--><--11--><--22--><--33--><--44--><--55--><--66--><--77--> */
      /* V3   1111[--p0--]0111[--------p0--------][------------p1------------] */
      /*                                          00000000111111112222222233333333 */

      insn[0^e] = buf[0^e] << 4 | buf[1^e] >> 4;
      insn[1^e] = buf[2^e];
      insn[2^e] = buf[3^e];
      insn[3^e] = buf[4^e] & 0xf0;
      print_slot_insn (cd, pc, info, SLOTS_P0, insn);

      insn[0^e] = buf[4^e] << 4 | buf[5^e] >> 4;
      insn[1^e] = buf[5^e] << 4 | buf[6^e] >> 4;
      insn[2^e] = buf[6^e] << 4 | buf[7^e] >> 4;
      insn[3^e] = buf[7^e] << 4;
      (*info->fprintf_func) (info->stream, " + ");
      print_slot_insn (cd, pc, info, SLOTS_P1, insn);
    }
  else
    {
      /*      <--00--><--11--><--22--><--33--><--44--><--55--><--66--><--77--> */
      /* V2   [-------------core-------------]xxxx[------------p1------------] */
      print_insn (cd, pc, info, buf, 4);

      insn[0^e] = buf[4^e] << 4 | buf[5^e] >> 4;
      insn[1^e] = buf[5^e] << 4 | buf[6^e] >> 4;
      insn[2^e] = buf[6^e] << 4 | buf[7^e] >> 4;
      insn[3^e] = buf[7^e] << 4;
      (*info->fprintf_func) (info->stream, " + ");
      print_slot_insn (cd, pc, info, SLOTS_P1, insn);
    }

  return 8;
}

#endif /* MEP_IVC2_SUPPORTED */

/* This is a hack.  SID calls this to update the disassembler as the
   CPU changes modes.  */
static int mep_ivc2_disassemble_p = 0;
static int mep_ivc2_vliw_disassemble_p = 0;

void
mep_print_insn_set_ivc2_mode (int ivc2_p, int vliw_p, int cfg_idx);
void
mep_print_insn_set_ivc2_mode (int ivc2_p, int vliw_p, int cfg_idx)
{
  mep_ivc2_disassemble_p = ivc2_p;
  mep_ivc2_vliw_disassemble_p = vliw_p;
  mep_config_index = cfg_idx;
}

static int
mep_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
{
  int status;
  int cop_type;
  int ivc2 = 0;
  static CGEN_ATTR_VALUE_BITSET_TYPE *ivc2_core_isa = NULL;

  if (ivc2_core_isa == NULL)
    {
      /* IVC2 has some core-only coprocessor instructions.  We
	 use COP32 to flag those, and COP64 for the VLIW ones,
	 since they have the same names.  */
      ivc2_core_isa = cgen_bitset_create (MAX_ISAS);
    }

  /* Extract and adapt to configuration number, if available. */
  if (info->section && info->section->owner)
    {
      bfd *abfd = info->section->owner;
      mep_config_index = abfd->tdata.elf_obj_data->elf_header->e_flags & EF_MEP_INDEX_MASK;
      /* This instantly redefines MEP_CONFIG, MEP_OMASK, .... MEP_VLIW64 */

      cop_type = abfd->tdata.elf_obj_data->elf_header->e_flags & EF_MEP_COP_MASK;
      if (cop_type == EF_MEP_COP_IVC2)
	ivc2 = 1;
    }

  /* Picking the right ISA bitmask for the current context is tricky.  */
  if (info->section)
    {
      if (info->section->flags & SEC_MEP_VLIW)
	{
#ifdef MEP_IVC2_SUPPORTED
	  if (ivc2)
	    {
	      /* ivc2 has its own way of selecting its functions.  */
	      cd->isas = & MEP_CORE_ISA;
	      status = mep_examine_ivc2_insns (cd, pc, info);
	    }
	  else
#endif
	    /* Are we in 32 or 64 bit vliw mode?  */
	    if (MEP_VLIW64)
	      status = mep_examine_vliw64_insns (cd, pc, info);
	    else
	      status = mep_examine_vliw32_insns (cd, pc, info);
	  /* Both the above branches set their own isa bitmasks.  */
	}
      else
	{
	  if (ivc2)
	    {
	      cgen_bitset_clear (ivc2_core_isa);
	      cgen_bitset_union (ivc2_core_isa, &MEP_CORE_ISA, ivc2_core_isa);
	      cgen_bitset_union (ivc2_core_isa, &MEP_COP32_ISA, ivc2_core_isa);
	      cd->isas = ivc2_core_isa;
	    }
	  else
	    cd->isas = & MEP_CORE_ISA;
	  status = default_print_insn (cd, pc, info);
	}
    }
  else /* sid or gdb */
    {
#ifdef MEP_IVC2_SUPPORTED
      if (mep_ivc2_disassemble_p)
	{
	  if (mep_ivc2_vliw_disassemble_p)
	    {
	      cd->isas = & MEP_CORE_ISA;
	      status = mep_examine_ivc2_insns (cd, pc, info);
	      return status;
	    }
	  else
	    {
	      if (ivc2)
		cd->isas = ivc2_core_isa;
	    }
	}
#endif

      status = default_print_insn (cd, pc, info);
    }

  return status;
}


/* -- opc.c */
#include "elf/mep.h"

/* A mask for all ISAs executed by the core. */
CGEN_ATTR_VALUE_BITSET_TYPE mep_all_core_isas_mask = {0, 0};

void
init_mep_all_core_isas_mask (void)
{
  if (mep_all_core_isas_mask.length != 0)
    return;
  cgen_bitset_init (& mep_all_core_isas_mask, ISA_MAX);
  cgen_bitset_set (& mep_all_core_isas_mask, ISA_MEP);
  /* begin-all-core-isas */
  cgen_bitset_add (& mep_all_core_isas_mask, ISA_EXT_CORE1);
  /* end-all-core-isas */
}

CGEN_ATTR_VALUE_BITSET_TYPE mep_all_cop_isas_mask = {0, 0};

void
init_mep_all_cop_isas_mask (void)
{
  if (mep_all_cop_isas_mask.length != 0)
    return;
  cgen_bitset_init (& mep_all_cop_isas_mask, ISA_MAX);
  /* begin-all-cop-isas */
  cgen_bitset_add (& mep_all_cop_isas_mask, ISA_EXT_COP1_16);
  cgen_bitset_add (& mep_all_cop_isas_mask, ISA_EXT_COP1_32);
  cgen_bitset_add (& mep_all_cop_isas_mask, ISA_EXT_COP1_48);
  cgen_bitset_add (& mep_all_cop_isas_mask, ISA_EXT_COP1_64);
  /* end-all-cop-isas */
}

int
mep_insn_supported_by_isa (const CGEN_INSN *insn, CGEN_ATTR_VALUE_BITSET_TYPE *isa_mask)
{
  CGEN_BITSET insn_isas = CGEN_INSN_BITSET_ATTR_VALUE (insn, CGEN_INSN_ISA);
  return cgen_bitset_intersect_p (& insn_isas, isa_mask);
}

#define OPTION_MASK \
	( (1 << CGEN_INSN_OPTIONAL_BIT_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_MUL_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_DIV_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_DEBUG_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_LDZ_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_ABS_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_AVE_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_MINMAX_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_CLIP_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_SAT_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_UCI_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_DSP_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_CP_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_CP64_INSN) )


mep_config_map_struct mep_config_map[] =
{
  /* config-map-start */
  /* Default entry: first module, with all options enabled. */
  { "", 0,  EF_MEP_COP_IVC2 | EF_MEP_CPU_C5,0, 64, { 1, "\x20" }, { 1, "\x10" }, { 1, "\x8" }, { 1, "\x4" }, { 1, "\x3c" }, { 1, "\xc0" }, OPTION_MASK | (1 << CGEN_INSN_OPTIONAL_DSP_INSN) | (1 << CGEN_INSN_OPTIONAL_UCI_INSN) },
  { "default", CONFIG_DEFAULT, EF_MEP_COP_IVC2 | EF_MEP_CPU_C5, 0, 64, { 1, "\x20" }, { 1, "\x10" }, { 1, "\x8" }, { 1, "\x4" }, { 1, "\x3c" }, { 1, "\xc0" },
	  0
	| (1 << CGEN_INSN_OPTIONAL_CP_INSN)
	| (1 << CGEN_INSN_OPTIONAL_CP64_INSN)
	| (1 << CGEN_INSN_OPTIONAL_MUL_INSN)
	| (1 << CGEN_INSN_OPTIONAL_DIV_INSN)
	| (1 << CGEN_INSN_OPTIONAL_BIT_INSN)
	| (1 << CGEN_INSN_OPTIONAL_LDZ_INSN)
	| (1 << CGEN_INSN_OPTIONAL_ABS_INSN)
	| (1 << CGEN_INSN_OPTIONAL_AVE_INSN)
	| (1 << CGEN_INSN_OPTIONAL_MINMAX_INSN)
	| (1 << CGEN_INSN_OPTIONAL_CLIP_INSN)
	| (1 << CGEN_INSN_OPTIONAL_SAT_INSN) },
  /* config-map-end */
  { 0, 0, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0 }
};

int mep_config_index = 0;

static int
check_configured_mach (int machs)
{
  /* All base insns are supported.  */
  int mach = 1 << MACH_BASE;
  switch (MEP_CPU & EF_MEP_CPU_MASK)
    {
    case EF_MEP_CPU_C2:
    case EF_MEP_CPU_C3:
      mach |= (1 << MACH_MEP);
      break;
    case EF_MEP_CPU_H1:
      mach |= (1 << MACH_H1);
      break;
    case EF_MEP_CPU_C5:
      mach |= (1 << MACH_MEP);
      mach |= (1 << MACH_C5);
      break;
    default:
      break;
    }
  return machs & mach;
}

int
mep_cgen_insn_supported (CGEN_CPU_DESC cd, const CGEN_INSN *insn)
{
  int iconfig = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_CONFIG);
  int machs = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_MACH);
  CGEN_BITSET isas = CGEN_INSN_BITSET_ATTR_VALUE (insn, CGEN_INSN_ISA);
  int ok1;
  int ok2;
  int ok3;

  /* If the insn has an option bit set that we don't want,
     reject it.  */
  if (CGEN_INSN_ATTRS (insn)->bool_ & OPTION_MASK & ~MEP_OMASK)
    return 0;

  /* If attributes are absent, assume no restriction. */
  if (machs == 0)
    machs = ~0;

  ok1 = ((machs & cd->machs) && cgen_bitset_intersect_p (& isas, cd->isas));
  /* If the insn is config-specific, make sure it matches.  */
  ok2 =  (iconfig == 0 || iconfig == MEP_CONFIG);
  /* Make sure the insn is supported by the configured mach  */
  ok3 = check_configured_mach (machs);

  return (ok1 && ok2 && ok3);
}

int
mep_cgen_insn_supported_asm (CGEN_CPU_DESC cd, const CGEN_INSN *insn)
{
#ifdef MEP_IVC2_SUPPORTED
  /* If we're assembling VLIW packets, ignore the 12-bit BSR as we
     can't relax that.  The 24-bit BSR is matched instead.  */
  if (insn->base->num == MEP_INSN_BSR12
      && cgen_bitset_contains (cd->isas, ISA_EXT_COP1_64))
    return 0;
#endif

  return mep_cgen_insn_supported (cd, insn);
}
@


1.1.1.1.4.1
log
@file mep.opc was added on branch yamt-pagecache on 2014-05-22 16:00:32 +0000
@
text
@d1 1669
@


1.1.1.1.4.2
log
@sync with head.

for a reference, the tree before this commit was tagged
as yamt-pagecache-tag8.

this commit was splitted into small chunks to avoid
a limitation of cvs.  ("Protocol error: too many arguments")
@
text
@a0 1669
/* MeP opcode support.  -*- C -*-
   Copyright 2011 Free Software Foundation, Inc.

   Contributed by Red Hat Inc;

   This file is part of the GNU Binutils.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   MA 02110-1301, USA.  */

/* -- opc.h */

#undef  CGEN_DIS_HASH_SIZE
#define CGEN_DIS_HASH_SIZE 1

#undef  CGEN_DIS_HASH
#define CGEN_DIS_HASH(buffer, insn) 0

#define CGEN_VERBOSE_ASSEMBLER_ERRORS

typedef struct
{
  char * name;
  int    config_enum;
  unsigned cpu_flag;
  int    big_endian;
  int    vliw_bits;
  CGEN_ATTR_VALUE_BITSET_TYPE cop16_isa;
  CGEN_ATTR_VALUE_BITSET_TYPE cop32_isa;
  CGEN_ATTR_VALUE_BITSET_TYPE cop48_isa;
  CGEN_ATTR_VALUE_BITSET_TYPE cop64_isa;
  CGEN_ATTR_VALUE_BITSET_TYPE cop_isa;
  CGEN_ATTR_VALUE_BITSET_TYPE core_isa;
  unsigned int option_mask;
} mep_config_map_struct;

extern mep_config_map_struct mep_config_map[];
extern int mep_config_index;

extern void init_mep_all_core_isas_mask (void);
extern void init_mep_all_cop_isas_mask  (void);
extern CGEN_ATTR_VALUE_BITSET_TYPE mep_cop_isa  (void);

#define MEP_CONFIG     (mep_config_map[mep_config_index].config_enum)
#define MEP_CPU        (mep_config_map[mep_config_index].cpu_flag)
#define MEP_OMASK      (mep_config_map[mep_config_index].option_mask)
#define MEP_VLIW       (mep_config_map[mep_config_index].vliw_bits > 0)
#define MEP_VLIW32     (mep_config_map[mep_config_index].vliw_bits == 32)
#define MEP_VLIW64     (mep_config_map[mep_config_index].vliw_bits == 64)
#define MEP_COP16_ISA  (mep_config_map[mep_config_index].cop16_isa)
#define MEP_COP32_ISA  (mep_config_map[mep_config_index].cop32_isa)
#define MEP_COP48_ISA  (mep_config_map[mep_config_index].cop48_isa)
#define MEP_COP64_ISA  (mep_config_map[mep_config_index].cop64_isa)
#define MEP_COP_ISA    (mep_config_map[mep_config_index].cop_isa)
#define MEP_CORE_ISA   (mep_config_map[mep_config_index].core_isa)

/* begin-cop-ip-supported-defines */
#define MEP_IVC2_SUPPORTED 1
/* end-cop-ip-supported-defines */

extern int mep_insn_supported_by_isa (const CGEN_INSN *, CGEN_ATTR_VALUE_BITSET_TYPE *);

/* A mask for all ISAs executed by the core.  */
#define MEP_ALL_CORE_ISAS_MASK mep_all_core_isas_mask
extern CGEN_ATTR_VALUE_BITSET_TYPE mep_all_core_isas_mask;

#define MEP_INSN_CORE_P(insn) ( \
  init_mep_all_core_isas_mask (), \
  mep_insn_supported_by_isa (insn, & MEP_ALL_CORE_ISAS_MASK) \
)

/* A mask for all ISAs executed by a VLIW coprocessor.  */
#define MEP_ALL_COP_ISAS_MASK mep_all_cop_isas_mask 
extern CGEN_ATTR_VALUE_BITSET_TYPE mep_all_cop_isas_mask;

#define MEP_INSN_COP_P(insn) ( \
  init_mep_all_cop_isas_mask (), \
  mep_insn_supported_by_isa (insn, & MEP_ALL_COP_ISAS_MASK) \
)

extern int mep_cgen_insn_supported (CGEN_CPU_DESC, const CGEN_INSN *);
extern int mep_cgen_insn_supported_asm (CGEN_CPU_DESC, const CGEN_INSN *);

/* -- asm.c */

#include "elf/mep.h"

#define CGEN_VALIDATE_INSN_SUPPORTED
#define mep_cgen_insn_supported mep_cgen_insn_supported_asm

       const char * parse_csrn       (CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *);
       const char * parse_tpreg      (CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *);
       const char * parse_spreg      (CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *);
       const char * parse_mep_align  (CGEN_CPU_DESC, const char **, enum cgen_operand_type, long *);
       const char * parse_mep_alignu (CGEN_CPU_DESC, const char **, enum cgen_operand_type, unsigned long *);
static const char * parse_signed16   (CGEN_CPU_DESC, const char **, int, long *);
static const char * parse_signed16_range   (CGEN_CPU_DESC, const char **, int, long *) ATTRIBUTE_UNUSED;
static const char * parse_unsigned16 (CGEN_CPU_DESC, const char **, int, unsigned long *);
static const char * parse_unsigned16_range (CGEN_CPU_DESC, const char **, int, unsigned long *) ATTRIBUTE_UNUSED;
static const char * parse_lo16       (CGEN_CPU_DESC, const char **, int, long *, long);
static const char * parse_unsigned7  (CGEN_CPU_DESC, const char **, enum cgen_operand_type, unsigned long *);
static const char * parse_zero       (CGEN_CPU_DESC, const char **, int, long *);

const char *
parse_csrn (CGEN_CPU_DESC cd, const char **strp,
	    CGEN_KEYWORD *keyword_table, long *field)
{
  const char *err;
  unsigned long value;

  err = cgen_parse_keyword (cd, strp, keyword_table, field);
  if (!err)
    return NULL;

  err = cgen_parse_unsigned_integer (cd, strp, MEP_OPERAND_CSRN_IDX, & value);
  if (err)
    return err;
  *field = value;
  return NULL;
}

/* begin-cop-ip-parse-handlers */
static const char *
parse_ivc2_cr (CGEN_CPU_DESC,
	const char **,
	CGEN_KEYWORD *,
	long *) ATTRIBUTE_UNUSED;
static const char *
parse_ivc2_cr (CGEN_CPU_DESC cd,
	const char **strp,
	CGEN_KEYWORD *keyword_table  ATTRIBUTE_UNUSED,
	long *field)
{
  return cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_cr_ivc2, field);
}
static const char *
parse_ivc2_ccr (CGEN_CPU_DESC,
	const char **,
	CGEN_KEYWORD *,
	long *) ATTRIBUTE_UNUSED;
static const char *
parse_ivc2_ccr (CGEN_CPU_DESC cd,
	const char **strp,
	CGEN_KEYWORD *keyword_table  ATTRIBUTE_UNUSED,
	long *field)
{
  return cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_ccr_ivc2, field);
}
/* end-cop-ip-parse-handlers */

const char *
parse_tpreg (CGEN_CPU_DESC cd, const char ** strp,
	     CGEN_KEYWORD *keyword_table, long *field)
{
  const char *err;

  err = cgen_parse_keyword (cd, strp, keyword_table, field);
  if (err)
    return err;
  if (*field != 13)
    return _("Only $tp or $13 allowed for this opcode");
  return NULL;
}

const char *
parse_spreg (CGEN_CPU_DESC cd, const char ** strp,
	     CGEN_KEYWORD *keyword_table, long *field)
{
  const char *err;

  err = cgen_parse_keyword (cd, strp, keyword_table, field);
  if (err)
    return err;
  if (*field != 15)
    return _("Only $sp or $15 allowed for this opcode");
  return NULL;
}

const char *
parse_mep_align (CGEN_CPU_DESC cd, const char ** strp,
		 enum cgen_operand_type type, long *field)
{
  long lsbs = 0;
  const char *err;

  switch (type)
    {
    case MEP_OPERAND_PCREL8A2:
    case MEP_OPERAND_PCREL12A2:
    case MEP_OPERAND_PCREL17A2:
    case MEP_OPERAND_PCREL24A2:
      err = cgen_parse_signed_integer   (cd, strp, type, field);
      break;
    case MEP_OPERAND_PCABS24A2:
    case MEP_OPERAND_UDISP7:
    case MEP_OPERAND_UDISP7A2:
    case MEP_OPERAND_UDISP7A4:
    case MEP_OPERAND_UIMM7A4:
    case MEP_OPERAND_ADDR24A4:
      err = cgen_parse_unsigned_integer (cd, strp, type, (unsigned long *) field);
      break;
    default:
      abort();
    }
  if (err)
    return err;
  switch (type)
    {
    case MEP_OPERAND_UDISP7:
      lsbs = 0;
      break;
    case MEP_OPERAND_PCREL8A2:
    case MEP_OPERAND_PCREL12A2:
    case MEP_OPERAND_PCREL17A2:
    case MEP_OPERAND_PCREL24A2:
    case MEP_OPERAND_PCABS24A2:
    case MEP_OPERAND_UDISP7A2:
      lsbs = *field & 1;
      break;
    case MEP_OPERAND_UDISP7A4:
    case MEP_OPERAND_UIMM7A4:
    case MEP_OPERAND_ADDR24A4:
      lsbs = *field & 3;
      break;
      lsbs = *field & 7;
      break;
    default:
      /* Safe assumption?  */
      abort ();
    }
  if (lsbs)
    return "Value is not aligned enough";
  return NULL;
}

const char *
parse_mep_alignu (CGEN_CPU_DESC cd, const char ** strp,
		 enum cgen_operand_type type, unsigned long *field)
{
  return parse_mep_align (cd, strp, type, (long *) field);
}


/* Handle %lo(), %tpoff(), %sdaoff(), %hi(), and other signed
   constants in a signed context.  */

static const char *
parse_signed16 (CGEN_CPU_DESC cd,
		const char **strp,
		int opindex,
		long *valuep)
{
  return parse_lo16 (cd, strp, opindex, valuep, 1);
}

static const char *
parse_lo16 (CGEN_CPU_DESC cd,
	    const char **strp,
	    int opindex,
	    long *valuep,
	    long signedp)
{
  const char *errmsg;
  enum cgen_parse_operand_result result_type;
  bfd_vma value;

  if (strncasecmp (*strp, "%lo(", 4) == 0)
    {
      *strp += 4;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_LOW16,
				   & result_type, & value);
      if (**strp != ')')
	return _("missing `)'");
      ++*strp;
      if (errmsg == NULL
	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
	value &= 0xffff;
      if (signedp)
	*valuep = (long)(short) value;
      else
	*valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%hi(", 4) == 0)
    {
      *strp += 4;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_HI16S,
				   & result_type, & value);
      if (**strp != ')')
	return _("missing `)'");
      ++*strp;
      if (errmsg == NULL
	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
	value = (value + 0x8000) >> 16;
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%uhi(", 5) == 0)
    {
      *strp += 5;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_HI16U,
				   & result_type, & value);
      if (**strp != ')')
	return _("missing `)'");
      ++*strp;
      if (errmsg == NULL
	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
	value = value >> 16;
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%sdaoff(", 8) == 0)
    {
      *strp += 8;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_GPREL,
				   NULL, & value);
      if (**strp != ')')
	return _("missing `)'");
      ++*strp;
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%tpoff(", 7) == 0)
    {
      *strp += 7;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_TPREL,
				   NULL, & value);
      if (**strp != ')')
	return _("missing `)'");
      ++*strp;
      *valuep = value;
      return errmsg;
    }

  if (**strp == '%')
    return _("invalid %function() here");

  return cgen_parse_signed_integer (cd, strp, opindex, valuep);
}

static const char *
parse_unsigned16 (CGEN_CPU_DESC cd,
		  const char **strp,
		  int opindex,
		  unsigned long *valuep)
{
  return parse_lo16 (cd, strp, opindex, (long *) valuep, 0);
}

static const char *
parse_signed16_range (CGEN_CPU_DESC cd,
		      const char **strp,
		      int opindex,
		      signed long *valuep)
{
  const char *errmsg = 0;
  signed long value;

  errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value);
  if (errmsg)
    return errmsg;

  if (value < -32768 || value > 32767)
    return _("Immediate is out of range -32768 to 32767");

  *valuep = value;
  return 0;
}

static const char *
parse_unsigned16_range (CGEN_CPU_DESC cd,
			const char **strp,
			int opindex,
			unsigned long *valuep)
{
  const char *errmsg = 0;
  unsigned long value;

  errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, & value);
  if (errmsg)
    return errmsg;

  if (value > 65535)
    return _("Immediate is out of range 0 to 65535");

  *valuep = value;
  return 0;
}

/* A special case of parse_signed16 which accepts only the value zero.  */

static const char *
parse_zero (CGEN_CPU_DESC cd, const char **strp, int opindex, long *valuep)
{
  const char *errmsg;
  enum cgen_parse_operand_result result_type;
  bfd_vma value;

  /*fprintf(stderr, "dj: signed parse opindex `%s'\n", *strp);*/

  /* Prevent ($ry) from being attempted as an expression on 'sw $rx,($ry)'.
     It will fail and cause ry to be listed as an undefined symbol in the
     listing.  */
  if (strncmp (*strp, "($", 2) == 0)
    return "not zero"; /* any string will do -- will never be seen.  */

  if (strncasecmp (*strp, "%lo(", 4) == 0)
    {
      *strp += 4;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_LOW16,
				   &result_type, &value);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      if (errmsg == NULL
	  && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
	return "not zero"; /* any string will do -- will never be seen.  */
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%hi(", 4) == 0)
    {
      *strp += 4;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_HI16S,
				   &result_type, &value);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      if (errmsg == NULL
	  && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
	return "not zero"; /* any string will do -- will never be seen.  */
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%uhi(", 5) == 0)
    {
      *strp += 5;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_HI16U,
				   &result_type, &value);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      if (errmsg == NULL
	  && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
	return "not zero"; /* any string will do -- will never be seen.  */
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%sdaoff(", 8) == 0)
    {
      *strp += 8;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_GPREL,
				   &result_type, &value);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      if (errmsg == NULL
	  && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
	return "not zero"; /* any string will do -- will never be seen.  */
      *valuep = value;
      return errmsg;
    }

  if (strncasecmp (*strp, "%tpoff(", 7) == 0)
    {
      *strp += 7;
      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_TPREL,
				   &result_type, &value);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      if (errmsg == NULL
	  && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
	return "not zero"; /* any string will do -- will never be seen.  */
      *valuep = value;
      return errmsg;
    }

  if (**strp == '%')
    return "invalid %function() here";

  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_NONE,
			       &result_type, &value);
  if (errmsg == NULL
      && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0))
    return "not zero"; /* any string will do -- will never be seen.  */

  return errmsg;
}

static const char *
parse_unsigned7 (CGEN_CPU_DESC cd, const char **strp,
		 enum cgen_operand_type opindex, unsigned long *valuep)
{
  const char *errmsg;
  bfd_vma value;

  /* fprintf(stderr, "dj: unsigned7 parse `%s'\n", *strp); */

  if (strncasecmp (*strp, "%tpoff(", 7) == 0)
    {
      int reloc;
      *strp += 7;
      switch (opindex)
	{
	case MEP_OPERAND_UDISP7:
	  reloc = BFD_RELOC_MEP_TPREL7;
	  break;
	case MEP_OPERAND_UDISP7A2:
	  reloc = BFD_RELOC_MEP_TPREL7A2;
	  break;
	case MEP_OPERAND_UDISP7A4:
	  reloc = BFD_RELOC_MEP_TPREL7A4;
	  break;
	default:
	  /* Safe assumption?  */
	  abort (); 
	}
      errmsg = cgen_parse_address (cd, strp, opindex, reloc,
				   NULL, &value);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      *valuep = value;
      return errmsg;
    }

  if (**strp == '%')
    return _("invalid %function() here");

  return parse_mep_alignu (cd, strp, opindex, valuep);
}

static ATTRIBUTE_UNUSED const char *
parse_cdisp10 (CGEN_CPU_DESC cd,
	       const char **strp,
	       int opindex,
	       long *valuep)
{
  const char *errmsg = 0;
  signed long value;
  long have_zero = 0;
  int wide = 0;
  int alignment;

  switch (opindex)
    {
    case MEP_OPERAND_CDISP10A4:
      alignment = 2;
      break;
    case MEP_OPERAND_CDISP10A2:
      alignment = 1;
      break;
    case MEP_OPERAND_CDISP10:
    default:
      alignment = 0;
      break;
    }

  if ((MEP_CPU & EF_MEP_CPU_MASK) == EF_MEP_CPU_C5)
    wide = 1;

  if (strncmp (*strp, "0x0", 3) == 0 
      || (**strp == '0' && *(*strp + 1) != 'x'))
    have_zero = 1;

  errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value);
  if (errmsg)
    return errmsg;

  if (wide)
    {
      if (value < -512 || value > 511)
	return _("Immediate is out of range -512 to 511");
    }
  else
    {
      if (value < -128 || value > 127)
	return _("Immediate is out of range -128 to 127");
    }

  if (value & ((1<<alignment)-1))
    return _("Value is not aligned enough");

  /* If this field may require a relocation then use larger dsp16.  */
  if (! have_zero && value == 0)
    return (wide ? _("Immediate is out of range -512 to 511")
	    : _("Immediate is out of range -128 to 127"));

  *valuep = value;
  return 0;
}

/* BEGIN LIGHTWEIGHT MACRO PROCESSOR.  */

#define MAXARGS 9

typedef struct
{
  char *name;
  char *expansion;
}  macro;

typedef struct
{
  const char *start;
  int len;
} arg;

macro macros[] =
{
  { "sizeof", "(`1.end + (- `1))"},
  { "startof", "(`1 | 0)" },
  { "align4", "(`1&(~3))"},
/*{ "hi", "(((`1+0x8000)>>16) & 0xffff)" },  */
/*{ "lo", "(`1 & 0xffff)" },  */
/*{ "sdaoff", "((`1-__sdabase) & 0x7f)"},  */
/*{ "tpoff", "((`1-__tpbase) & 0x7f)"},  */
  { 0,0 }
};

static char  * expand_string    (const char *, int);

static const char *
mep_cgen_expand_macros_and_parse_operand
  (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);

static char *
str_append (char *dest, const char *input, int len)
{  
  char *new_dest;
  int oldlen;

  if (len == 0)
    return dest;
  /* printf("str_append: <<%s>>, <<%s>>, %d\n", dest, input, len); */
  oldlen = (dest ? strlen(dest) : 0);
  new_dest = realloc (dest, oldlen + len + 1);
  memset (new_dest + oldlen, 0, len + 1);
  return strncat (new_dest, input, len);
}

static macro *
lookup_macro (const char *name)
{
  macro *m;

  for (m = macros; m->name; ++m)
    if (strncmp (m->name, name, strlen(m->name)) == 0)
      return m;

  return 0;
}

static char *
expand_macro (arg *args, int narg, macro *mac)
{
  char *result = 0, *rescanned_result = 0;
  char *e = mac->expansion;
  char *mark = e;
  int mac_arg = 0;

  /*  printf("expanding macro %s with %d args\n", mac->name, narg + 1); */
  while (*e)
    {
      if (*e == '`' && 
	  (*e+1) && 
	  ((*(e + 1) - '1') <= MAXARGS) &&
	  ((*(e + 1) - '1') <= narg))
	{
	  result = str_append (result, mark, e - mark);
	  mac_arg = (*(e + 1) - '1');
	  /* printf("replacing `%d with %s\n", mac_arg+1, args[mac_arg].start); */
	  result = str_append (result, args[mac_arg].start, args[mac_arg].len);
	  ++e;
	  mark = e+1;
	}
      ++e;
    }

  if (mark != e)
    result = str_append (result, mark, e - mark);

  if (result)
    {
      rescanned_result = expand_string (result, 0);
      free (result);
      return rescanned_result;
    }
  else 
    return result;
}

#define IN_TEXT 0
#define IN_ARGS 1

static char *
expand_string (const char *in, int first_only)
{
  int num_expansions = 0;
  int depth = 0;
  int narg = -1;
  arg args[MAXARGS];
  int state = IN_TEXT;
  const char *mark = in;
  macro *pmacro = NULL;
  char *expansion = 0;
  char *result = 0;

  while (*in)
    {
      switch (state)
	{
	case IN_TEXT:
	  if (*in == '%' && *(in + 1) && (!first_only || num_expansions == 0)) 
	    {	      
	      pmacro = lookup_macro (in + 1);
	      if (pmacro)
		{
		  /* printf("entering state %d at '%s'...\n", state, in); */
		  result = str_append (result, mark, in - mark);
		  mark = in;
		  in += 1 + strlen (pmacro->name);
		  while (*in == ' ') ++in;
		  if (*in != '(')
		    {
		      state = IN_TEXT;		      
		      pmacro = NULL;
		    }
		  else
		    {
		      state = IN_ARGS;
		      narg = 0;
		      args[narg].start = in + 1;
		      args[narg].len = 0;
		      mark = in + 1;	      		      
		    }
		}
	    }
	  break;
	case IN_ARGS:
	  if (depth == 0)
	    {
	      switch (*in)
		{
		case ',':
		  narg++;
		  args[narg].start = (in + 1);
		  args[narg].len = 0;
		  break;
		case ')':
		  state = IN_TEXT;
		  /* printf("entering state %d at '%s'...\n", state, in); */
		  if (pmacro)
		    {
		      expansion = 0;
		      expansion = expand_macro (args, narg, pmacro);
		      num_expansions++;
		      if (expansion)
			{
			  result = str_append (result, expansion, strlen (expansion));
			  free (expansion);
			}
		    }
		  else
		    {
		      result = str_append (result, mark, in - mark);
		    }
		  pmacro = NULL;
		  mark = in + 1;
		  break;
		case '(':
		  depth++;
		default:
		  args[narg].len++;
		  break;		  
		}
	    } 
	  else
	    {
	      if (*in == ')')
		depth--;
	      if (narg > -1)
		args[narg].len++;
	    }
	  
	}
      ++in;
    }
  
  if (mark != in)
    result = str_append (result, mark, in - mark);
  
  return result;
}

#undef IN_ARGS
#undef IN_TEXT
#undef MAXARGS


/* END LIGHTWEIGHT MACRO PROCESSOR.  */

const char * mep_cgen_parse_operand
  (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);

const char *
mep_cgen_expand_macros_and_parse_operand (CGEN_CPU_DESC cd, int opindex,
					  const char ** strp_in, CGEN_FIELDS * fields)
{
  const char * errmsg = NULL;
  char *str = 0, *hold = 0;
  const char **strp = 0;

  /* Set up a new pointer to macro-expanded string.  */
  str = expand_string (*strp_in, 1);
  /* fprintf (stderr, " expanded <<%s>> to <<%s>>\n", *strp_in, str); */

  hold = str;
  strp = (const char **)(&str);

  errmsg = mep_cgen_parse_operand (cd, opindex, strp, fields);

  /* Now work out the advance.  */
  if (strlen (str) == 0)
    *strp_in += strlen (*strp_in);

  else
    {
      if (strstr (*strp_in, str))
	/* A macro-expansion was pulled off the front.  */
	*strp_in = strstr (*strp_in, str);  
      else
	/* A non-macro-expansion was pulled off the front.  */
	*strp_in += (str - hold); 
    }

  if (hold)
    free (hold);

  return errmsg;
}

#define CGEN_ASM_INIT_HOOK (cd->parse_operand = mep_cgen_expand_macros_and_parse_operand); 

/* -- dis.c */

#include "elf/mep.h"
#include "elf-bfd.h"

#define CGEN_VALIDATE_INSN_SUPPORTED

static void print_tpreg (CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned int);
static void print_spreg (CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned int);

static void
print_tpreg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, PTR dis_info,
	     CGEN_KEYWORD *table ATTRIBUTE_UNUSED, long val ATTRIBUTE_UNUSED,
	     unsigned int flags ATTRIBUTE_UNUSED)
{
  disassemble_info *info = (disassemble_info *) dis_info;

  (*info->fprintf_func) (info->stream, "$tp");
}

static void
print_spreg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, PTR dis_info, 
	     CGEN_KEYWORD *table ATTRIBUTE_UNUSED, long val ATTRIBUTE_UNUSED,
	     unsigned int flags ATTRIBUTE_UNUSED)
{
  disassemble_info *info = (disassemble_info *) dis_info;

  (*info->fprintf_func) (info->stream, "$sp");
}

/* begin-cop-ip-print-handlers */
static void
print_ivc2_cr (CGEN_CPU_DESC,
	void *,
	CGEN_KEYWORD *,
	long,
	unsigned int) ATTRIBUTE_UNUSED;
static void
print_ivc2_cr (CGEN_CPU_DESC cd,
	void *dis_info,
	CGEN_KEYWORD *keyword_table ATTRIBUTE_UNUSED,
	long value,
	unsigned int attrs)
{
  print_keyword (cd, dis_info, & mep_cgen_opval_h_cr_ivc2, value, attrs);
}
static void
print_ivc2_ccr (CGEN_CPU_DESC,
	void *,
	CGEN_KEYWORD *,
	long,
	unsigned int) ATTRIBUTE_UNUSED;
static void
print_ivc2_ccr (CGEN_CPU_DESC cd,
	void *dis_info,
	CGEN_KEYWORD *keyword_table ATTRIBUTE_UNUSED,
	long value,
	unsigned int attrs)
{
  print_keyword (cd, dis_info, & mep_cgen_opval_h_ccr_ivc2, value, attrs);
}
/* end-cop-ip-print-handlers */

/************************************************************\
*********************** Experimental *************************
\************************************************************/

#undef  CGEN_PRINT_INSN
#define CGEN_PRINT_INSN mep_print_insn

static int
mep_print_vliw_insns (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info,
		      bfd_byte *buf, int corelength, int copro1length,
		      int copro2length ATTRIBUTE_UNUSED)
{
  int i;
  int status = 0;
  /* char insnbuf[CGEN_MAX_INSN_SIZE]; */
  bfd_byte insnbuf[64];

  /* If corelength > 0 then there is a core insn present. It
     will be at the beginning of the buffer.  After printing
     the core insn, we need to print the + on the next line.  */
  if (corelength > 0)
    {
      int my_status = 0;
	 
      for (i = 0; i < corelength; i++ )
	insnbuf[i] = buf[i];
      cd->isas = & MEP_CORE_ISA;
	 
      my_status = print_insn (cd, pc, info, insnbuf, corelength);
      if (my_status != corelength)
	{
	  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
	  my_status = corelength;
	}
      status += my_status;

      /* Print the + to indicate that the following copro insn is   */
      /* part of a vliw group.                                      */
      if (copro1length > 0)
	(*info->fprintf_func) (info->stream, " + "); 
    }

  /* Now all that is left to be processed is the coprocessor insns
     In vliw mode, there will always be one.  Its positioning will
     be from byte corelength to byte corelength+copro1length -1.
     No need to check for existence.   Also, the first vliw insn,
     will, as spec'd, always be at least as long as the core insn
     so we don't need to flush the buffer.  */
  if (copro1length > 0)
    {
      int my_status = 0;
	 
      for (i = corelength; i < corelength + copro1length; i++ )
	insnbuf[i - corelength] = buf[i];

      switch (copro1length)
	{
	case 0:
	  break;
	case 2:
	  cd->isas = & MEP_COP16_ISA;
	  break;
	case 4:
	  cd->isas = & MEP_COP32_ISA;
	  break;
	case 6:
	  cd->isas = & MEP_COP48_ISA;
	  break;
	case 8:
	  cd->isas = & MEP_COP64_ISA;
	  break; 
	default:
	  /* Shouldn't be anything but 16,32,48,64.  */
	  break;
	}

      my_status = print_insn (cd, pc, info, insnbuf, copro1length);

      if (my_status != copro1length)
	{
	  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
	  my_status = copro1length;
	}
      status += my_status;
    }

#if 0
  /* Now we need to process the second copro insn if it exists. We
     have no guarantee that the second copro insn will be longer
     than the first, so we have to flush the buffer if we are have
     a second copro insn to process.  If present, this insn will
     be in the position from byte corelength+copro1length to byte
     corelength+copro1length+copro2length-1 (which better equal 8
     or else we're in big trouble.  */
  if (copro2length > 0)
    {
      int my_status = 0;

      for (i = 0; i < 64 ; i++)
	insnbuf[i] = 0;

      for (i = corelength + copro1length; i < 64; i++)
	insnbuf[i - (corelength + copro1length)] = buf[i];
      
      switch (copro2length)
	{
	case 2:
	  cd->isas = 1 << ISA_EXT_COP1_16;
	  break;
	case 4:
	  cd->isas = 1 << ISA_EXT_COP1_32;
	  break;
	case 6:
	  cd->isas = 1 << ISA_EXT_COP1_48;
	  break;
	case 8:
	  cd->isas = 1 << ISA_EXT_COP1_64; 
	  break;
	default:
	  /* Shouldn't be anything but 16,32,48,64.  */
	  break;
	}

      my_status = print_insn (cd, pc, info, insnbuf, copro2length);

      if (my_status != copro2length)
	{
	  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
	  my_status = copro2length;
	}

      status += my_status;
    }
#endif

  /* Status should now be the number of bytes that were printed
     which should be 4 for VLIW32 mode and 64 for VLIW64 mode.  */

  if ((!MEP_VLIW64 && (status != 4)) || (MEP_VLIW64 && (status != 8)))
    return -1;
  else
    return status;
}

/* The two functions mep_examine_vliw[32,64]_insns are used find out 
   which vliw combinaion (16 bit core with 48 bit copro, 32 bit core 
   with 32 bit copro, etc.) is present.  Later on, when internally   
   parallel coprocessors are handled, only these functions should    
   need to be changed.                                               

   At this time only the following combinations are supported: 
   
   VLIW32 Mode:
   16 bit core insn (core) and 16 bit coprocessor insn (cop1)
   32 bit core insn (core)
   32 bit coprocessor insn (cop1)
   Note: As of this time, I do not believe we have enough information
         to distinguish a 32 bit core insn from a 32 bit cop insn. Also,
         no 16 bit coprocessor insns have been specified.  

   VLIW64 Mode:
   16 bit core insn (core) and 48 bit coprocessor insn (cop1)
   32 bit core insn (core) and 32 bit coprocessor insn (cop1)
   64 bit coprocessor insn (cop1)
  
   The framework for an internally parallel coprocessor is also
   present (2nd coprocessor insn is cop2), but at this time it 
   is not used.  This only appears to be valid in VLIW64 mode.  */

static int
mep_examine_vliw32_insns (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
{
  int status;
  int buflength;
  int corebuflength;
  int cop1buflength;
  int cop2buflength;
  bfd_byte buf[CGEN_MAX_INSN_SIZE];  
  char indicator16[1];
  char indicatorcop32[2]; 

  /* At this time we're not supporting internally parallel coprocessors,
     so cop2buflength will always be 0.  */
  cop2buflength = 0;

  /* Read in 32 bits.  */
  buflength = 4; /* VLIW insn spans 4 bytes.  */
  status = (*info->read_memory_func) (pc, buf, buflength, info);

  if (status != 0)
    {
      (*info->memory_error_func) (status, pc, info);
      return -1;
    }

  /* Put the big endian representation of the bytes to be examined
     in the temporary buffers for examination.  */

  if (info->endian == BFD_ENDIAN_BIG)
    {
      indicator16[0] = buf[0];
      indicatorcop32[0] = buf[0];
      indicatorcop32[1] = buf[1];
    }
  else
    {
      indicator16[0] = buf[1];
      indicatorcop32[0] = buf[1];
      indicatorcop32[1] = buf[0];
    }

  /* If the two high order bits are 00, 01 or 10, we have a 16 bit
     core insn and a 48 bit copro insn.  */

  if ((indicator16[0] & 0x80) && (indicator16[0] & 0x40))
    {
      if ((indicatorcop32[0] & 0xf0) == 0xf0 && (indicatorcop32[1] & 0x07) == 0x07)
	{
          /* We have a 32 bit copro insn.  */
          corebuflength = 0;
	  /* All 4 4ytes are one copro insn. */
          cop1buflength = 4;
	}
      else
	{
          /* We have a 32 bit core.  */
          corebuflength = 4;
          cop1buflength = 0;
	}
    }
  else
    {
      /* We have a 16 bit core insn and a 16 bit copro insn.  */
      corebuflength = 2;
      cop1buflength = 2;
    }

  /* Now we have the distrubution set.  Print them out.  */
  status = mep_print_vliw_insns (cd, pc, info, buf, corebuflength,
				 cop1buflength, cop2buflength);

  return status;
}

static int
mep_examine_vliw64_insns (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
{
  int status;
  int buflength;
  int corebuflength;
  int cop1buflength;
  int cop2buflength;
  bfd_byte buf[CGEN_MAX_INSN_SIZE];
  char indicator16[1];
  char indicator64[4];

  /* At this time we're not supporting internally parallel
     coprocessors, so cop2buflength will always be 0.  */
  cop2buflength = 0;

  /* Read in 64 bits.  */
  buflength = 8; /* VLIW insn spans 8 bytes.  */
  status = (*info->read_memory_func) (pc, buf, buflength, info);

  if (status != 0)
    {
      (*info->memory_error_func) (status, pc, info);
      return -1;
    }

  /* We have all 64 bits in the buffer now.  We have to figure out
     what combination of instruction sizes are present.  The two
     high order bits will indicate whether or not we have a 16 bit
     core insn or not.  If not, then we have to look at the 7,8th
     bytes to tell whether we have 64 bit copro insn or a 32 bit
     core insn with a 32 bit copro insn.  Endianness will make a
     difference here.  */

  /* Put the big endian representation of the bytes to be examined
     in the temporary buffers for examination.  */

  /* indicator16[0] = buf[0];  */
  if (info->endian == BFD_ENDIAN_BIG)
    {
      indicator16[0] = buf[0];
      indicator64[0] = buf[0];
      indicator64[1] = buf[1];
      indicator64[2] = buf[2];
      indicator64[3] = buf[3];
    }
  else
    {
      indicator16[0] = buf[1];
      indicator64[0] = buf[1];
      indicator64[1] = buf[0];
      indicator64[2] = buf[3];
      indicator64[3] = buf[2];
    }

  /* If the two high order bits are 00, 01 or 10, we have a 16 bit
     core insn and a 48 bit copro insn.  */

  if ((indicator16[0] & 0x80) && (indicator16[0] & 0x40))
    {
      if ((indicator64[0] & 0xf0) == 0xf0 && (indicator64[1] & 0x07) == 0x07
	  && ((indicator64[2] & 0xfe) != 0xf0 || (indicator64[3] & 0xf4) != 0))
	{
          /* We have a 64 bit copro insn.  */
          corebuflength = 0;
	  /* All 8 bytes are one copro insn.  */
          cop1buflength = 8;
	}
      else
	{
          /* We have a 32 bit core insn and a 32 bit copro insn.  */
          corebuflength = 4;
          cop1buflength = 4;
	}
    }
  else
    {
      /* We have a 16 bit core insn and a 48 bit copro insn.  */
      corebuflength = 2;
      cop1buflength = 6;
    }

  /* Now we have the distrubution set.  Print them out. */
  status = mep_print_vliw_insns (cd, pc, info, buf, corebuflength,
				 cop1buflength, cop2buflength);

  return status;
}

#ifdef MEP_IVC2_SUPPORTED

static int
print_slot_insn (CGEN_CPU_DESC cd,
		 bfd_vma pc,
		 disassemble_info *info,
		 SLOTS_ATTR slot,
		 bfd_byte *buf)
{
  const CGEN_INSN_LIST *insn_list;
  CGEN_INSN_INT insn_value;
  CGEN_EXTRACT_INFO ex_info;

  insn_value = cgen_get_insn_value (cd, buf, 32);

  /* Fill in ex_info fields like read_insn would.  Don't actually call
     read_insn, since the incoming buffer is already read (and possibly
     modified a la m32r).  */
  ex_info.valid = (1 << 8) - 1;
  ex_info.dis_info = info;
  ex_info.insn_bytes = buf;

  /* The instructions are stored in hash lists.
     Pick the first one and keep trying until we find the right one.  */

  insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
  while (insn_list != NULL)
    {
      const CGEN_INSN *insn = insn_list->insn;
      CGEN_FIELDS fields;
      int length;

      if ((CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_CONFIG)
	   && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_CONFIG) != MEP_CONFIG)
	  || ! (CGEN_ATTR_CGEN_INSN_SLOTS_VALUE (CGEN_INSN_ATTRS (insn)) & (1 << slot)))
        {
          insn_list = CGEN_DIS_NEXT_INSN (insn_list);
	  continue;
        }

      if ((insn_value & CGEN_INSN_BASE_MASK (insn))
	  == CGEN_INSN_BASE_VALUE (insn))
	{
	  /* Printing is handled in two passes.  The first pass parses the
	     machine insn and extracts the fields.  The second pass prints
	     them.  */

	  length = CGEN_EXTRACT_FN (cd, insn)
	    (cd, insn, &ex_info, insn_value, &fields, pc);

	  /* Length < 0 -> error.  */
	  if (length < 0)
	    return length;
	  if (length > 0)
	    {
	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
	      /* Length is in bits, result is in bytes.  */
	      return length / 8;
	    }
	}

      insn_list = CGEN_DIS_NEXT_INSN (insn_list);
    }

  if (slot == SLOTS_P0S)
    (*info->fprintf_func) (info->stream, "*unknown-p0s*");
  else if (slot == SLOTS_P0)
    (*info->fprintf_func) (info->stream, "*unknown-p0*");
  else if (slot == SLOTS_P1)
    (*info->fprintf_func) (info->stream, "*unknown-p1*");
  else if (slot == SLOTS_C3)
    (*info->fprintf_func) (info->stream, "*unknown-c3*");
  return 0;
}

static int
mep_examine_ivc2_insns (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, bfd_vma pc ATTRIBUTE_UNUSED, disassemble_info *info ATTRIBUTE_UNUSED)
{
  int status;
  int buflength;
  bfd_byte buf[8];
  bfd_byte insn[8];
  int e;

  /* Read in 64 bits.  */
  buflength = 8; /* VLIW insn spans 8 bytes.  */
  status = (*info->read_memory_func) (pc, buf, buflength, info);

  if (status != 0)
    {
      (*info->memory_error_func) (status, pc, info);
      return -1;
    }

  if (info->endian == BFD_ENDIAN_LITTLE)
    e = 1;
  else
    e = 0;

  if (((unsigned char)buf[0^e] & 0xf0) < 0xc0)
    {
      /*      <--00--><--11--><--22--><--33--><--44--><--55--><--66--><--77--> */
      /* V1   [-----core-----][--------p0s-------][------------p1------------] */

      print_insn (cd, pc, info, buf, 2);

      insn[0^e] = 0;
      insn[1^e] = buf[2^e];
      insn[2^e] = buf[3^e];
      insn[3^e] = buf[4^e] & 0xf0;
      (*info->fprintf_func) (info->stream, " + ");
      print_slot_insn (cd, pc, info, SLOTS_P0S, insn);

      insn[0^e] = buf[4^e] << 4 | buf[5^e] >> 4;
      insn[1^e] = buf[5^e] << 4 | buf[6^e] >> 4;
      insn[2^e] = buf[6^e] << 4 | buf[7^e] >> 4;
      insn[3^e] = buf[7^e] << 4;
      (*info->fprintf_func) (info->stream, " + ");
      print_slot_insn (cd, pc, info, SLOTS_P1, insn);
    }
  else if ((buf[0^e] & 0xf0) == 0xf0 && (buf[1^e] & 0x0f) == 0x07)
    {
      /*      <--00--><--11--><--22--><--33--><--44--><--55--><--66--><--77--> */
      /* V3   1111[--p0--]0111[--------p0--------][------------p1------------] */
      /*                                          00000000111111112222222233333333 */

      insn[0^e] = buf[0^e] << 4 | buf[1^e] >> 4;
      insn[1^e] = buf[2^e];
      insn[2^e] = buf[3^e];
      insn[3^e] = buf[4^e] & 0xf0;
      print_slot_insn (cd, pc, info, SLOTS_P0, insn);

      insn[0^e] = buf[4^e] << 4 | buf[5^e] >> 4;
      insn[1^e] = buf[5^e] << 4 | buf[6^e] >> 4;
      insn[2^e] = buf[6^e] << 4 | buf[7^e] >> 4;
      insn[3^e] = buf[7^e] << 4;
      (*info->fprintf_func) (info->stream, " + ");
      print_slot_insn (cd, pc, info, SLOTS_P1, insn);
    }
  else
    {
      /*      <--00--><--11--><--22--><--33--><--44--><--55--><--66--><--77--> */
      /* V2   [-------------core-------------]xxxx[------------p1------------] */
      print_insn (cd, pc, info, buf, 4);

      insn[0^e] = buf[4^e] << 4 | buf[5^e] >> 4;
      insn[1^e] = buf[5^e] << 4 | buf[6^e] >> 4;
      insn[2^e] = buf[6^e] << 4 | buf[7^e] >> 4;
      insn[3^e] = buf[7^e] << 4;
      (*info->fprintf_func) (info->stream, " + ");
      print_slot_insn (cd, pc, info, SLOTS_P1, insn);
    }

  return 8;
}

#endif /* MEP_IVC2_SUPPORTED */

/* This is a hack.  SID calls this to update the disassembler as the
   CPU changes modes.  */
static int mep_ivc2_disassemble_p = 0;
static int mep_ivc2_vliw_disassemble_p = 0;

void
mep_print_insn_set_ivc2_mode (int ivc2_p, int vliw_p, int cfg_idx);
void
mep_print_insn_set_ivc2_mode (int ivc2_p, int vliw_p, int cfg_idx)
{
  mep_ivc2_disassemble_p = ivc2_p;
  mep_ivc2_vliw_disassemble_p = vliw_p;
  mep_config_index = cfg_idx;
}

static int
mep_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
{
  int status;
  int cop_type;
  int ivc2 = 0;
  static CGEN_ATTR_VALUE_BITSET_TYPE *ivc2_core_isa = NULL;

  if (ivc2_core_isa == NULL)
    {
      /* IVC2 has some core-only coprocessor instructions.  We
	 use COP32 to flag those, and COP64 for the VLIW ones,
	 since they have the same names.  */
      ivc2_core_isa = cgen_bitset_create (MAX_ISAS);
    }

  /* Extract and adapt to configuration number, if available. */
  if (info->section && info->section->owner)
    {
      bfd *abfd = info->section->owner;
      mep_config_index = abfd->tdata.elf_obj_data->elf_header->e_flags & EF_MEP_INDEX_MASK;
      /* This instantly redefines MEP_CONFIG, MEP_OMASK, .... MEP_VLIW64 */

      cop_type = abfd->tdata.elf_obj_data->elf_header->e_flags & EF_MEP_COP_MASK;
      if (cop_type == EF_MEP_COP_IVC2)
	ivc2 = 1;
    }

  /* Picking the right ISA bitmask for the current context is tricky.  */
  if (info->section)
    {
      if (info->section->flags & SEC_MEP_VLIW)
	{
#ifdef MEP_IVC2_SUPPORTED
	  if (ivc2)
	    {
	      /* ivc2 has its own way of selecting its functions.  */
	      cd->isas = & MEP_CORE_ISA;
	      status = mep_examine_ivc2_insns (cd, pc, info);
	    }
	  else
#endif
	    /* Are we in 32 or 64 bit vliw mode?  */
	    if (MEP_VLIW64)
	      status = mep_examine_vliw64_insns (cd, pc, info);
	    else
	      status = mep_examine_vliw32_insns (cd, pc, info);
	  /* Both the above branches set their own isa bitmasks.  */
	}
      else
	{
	  if (ivc2)
	    {
	      cgen_bitset_clear (ivc2_core_isa);
	      cgen_bitset_union (ivc2_core_isa, &MEP_CORE_ISA, ivc2_core_isa);
	      cgen_bitset_union (ivc2_core_isa, &MEP_COP32_ISA, ivc2_core_isa);
	      cd->isas = ivc2_core_isa;
	    }
	  else
	    cd->isas = & MEP_CORE_ISA;
	  status = default_print_insn (cd, pc, info);
	}
    }
  else /* sid or gdb */
    {
#ifdef MEP_IVC2_SUPPORTED
      if (mep_ivc2_disassemble_p)
	{
	  if (mep_ivc2_vliw_disassemble_p)
	    {
	      cd->isas = & MEP_CORE_ISA;
	      status = mep_examine_ivc2_insns (cd, pc, info);
	      return status;
	    }
	  else
	    {
	      if (ivc2)
		cd->isas = ivc2_core_isa;
	    }
	}
#endif

      status = default_print_insn (cd, pc, info);
    }

  return status;
}


/* -- opc.c */
#include "elf/mep.h"

/* A mask for all ISAs executed by the core. */
CGEN_ATTR_VALUE_BITSET_TYPE mep_all_core_isas_mask = {0, 0};

void
init_mep_all_core_isas_mask (void)
{
  if (mep_all_core_isas_mask.length != 0)
    return;
  cgen_bitset_init (& mep_all_core_isas_mask, ISA_MAX);
  cgen_bitset_set (& mep_all_core_isas_mask, ISA_MEP);
  /* begin-all-core-isas */
  cgen_bitset_add (& mep_all_core_isas_mask, ISA_EXT_CORE1);
  /* end-all-core-isas */
}

CGEN_ATTR_VALUE_BITSET_TYPE mep_all_cop_isas_mask = {0, 0};

void
init_mep_all_cop_isas_mask (void)
{
  if (mep_all_cop_isas_mask.length != 0)
    return;
  cgen_bitset_init (& mep_all_cop_isas_mask, ISA_MAX);
  /* begin-all-cop-isas */
  cgen_bitset_add (& mep_all_cop_isas_mask, ISA_EXT_COP1_16);
  cgen_bitset_add (& mep_all_cop_isas_mask, ISA_EXT_COP1_32);
  cgen_bitset_add (& mep_all_cop_isas_mask, ISA_EXT_COP1_48);
  cgen_bitset_add (& mep_all_cop_isas_mask, ISA_EXT_COP1_64);
  /* end-all-cop-isas */
}

int
mep_insn_supported_by_isa (const CGEN_INSN *insn, CGEN_ATTR_VALUE_BITSET_TYPE *isa_mask)
{
  CGEN_BITSET insn_isas = CGEN_INSN_BITSET_ATTR_VALUE (insn, CGEN_INSN_ISA);
  return cgen_bitset_intersect_p (& insn_isas, isa_mask);
}

#define OPTION_MASK \
	( (1 << CGEN_INSN_OPTIONAL_BIT_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_MUL_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_DIV_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_DEBUG_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_LDZ_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_ABS_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_AVE_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_MINMAX_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_CLIP_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_SAT_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_UCI_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_DSP_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_CP_INSN) \
	| (1 << CGEN_INSN_OPTIONAL_CP64_INSN) )


mep_config_map_struct mep_config_map[] =
{
  /* config-map-start */
  /* Default entry: first module, with all options enabled. */
  { "", 0,  EF_MEP_COP_IVC2 | EF_MEP_CPU_C5,0, 64, { 1, "\x20" }, { 1, "\x10" }, { 1, "\x8" }, { 1, "\x4" }, { 1, "\x3c" }, { 1, "\xc0" }, OPTION_MASK | (1 << CGEN_INSN_OPTIONAL_DSP_INSN) | (1 << CGEN_INSN_OPTIONAL_UCI_INSN) },
  { "default", CONFIG_DEFAULT, EF_MEP_COP_IVC2 | EF_MEP_CPU_C5, 0, 64, { 1, "\x20" }, { 1, "\x10" }, { 1, "\x8" }, { 1, "\x4" }, { 1, "\x3c" }, { 1, "\xc0" },
	  0
	| (1 << CGEN_INSN_OPTIONAL_CP_INSN)
	| (1 << CGEN_INSN_OPTIONAL_CP64_INSN)
	| (1 << CGEN_INSN_OPTIONAL_MUL_INSN)
	| (1 << CGEN_INSN_OPTIONAL_DIV_INSN)
	| (1 << CGEN_INSN_OPTIONAL_BIT_INSN)
	| (1 << CGEN_INSN_OPTIONAL_LDZ_INSN)
	| (1 << CGEN_INSN_OPTIONAL_ABS_INSN)
	| (1 << CGEN_INSN_OPTIONAL_AVE_INSN)
	| (1 << CGEN_INSN_OPTIONAL_MINMAX_INSN)
	| (1 << CGEN_INSN_OPTIONAL_CLIP_INSN)
	| (1 << CGEN_INSN_OPTIONAL_SAT_INSN) },
  /* config-map-end */
  { 0, 0, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0 }
};

int mep_config_index = 0;

static int
check_configured_mach (int machs)
{
  /* All base insns are supported.  */
  int mach = 1 << MACH_BASE;
  switch (MEP_CPU & EF_MEP_CPU_MASK)
    {
    case EF_MEP_CPU_C2:
    case EF_MEP_CPU_C3:
      mach |= (1 << MACH_MEP);
      break;
    case EF_MEP_CPU_H1:
      mach |= (1 << MACH_H1);
      break;
    case EF_MEP_CPU_C5:
      mach |= (1 << MACH_MEP);
      mach |= (1 << MACH_C5);
      break;
    default:
      break;
    }
  return machs & mach;
}

int
mep_cgen_insn_supported (CGEN_CPU_DESC cd, const CGEN_INSN *insn)
{
  int iconfig = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_CONFIG);
  int machs = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_MACH);
  CGEN_BITSET isas = CGEN_INSN_BITSET_ATTR_VALUE (insn, CGEN_INSN_ISA);
  int ok1;
  int ok2;
  int ok3;

  /* If the insn has an option bit set that we don't want,
     reject it.  */
  if (CGEN_INSN_ATTRS (insn)->bool_ & OPTION_MASK & ~MEP_OMASK)
    return 0;

  /* If attributes are absent, assume no restriction. */
  if (machs == 0)
    machs = ~0;

  ok1 = ((machs & cd->machs) && cgen_bitset_intersect_p (& isas, cd->isas));
  /* If the insn is config-specific, make sure it matches.  */
  ok2 =  (iconfig == 0 || iconfig == MEP_CONFIG);
  /* Make sure the insn is supported by the configured mach  */
  ok3 = check_configured_mach (machs);

  return (ok1 && ok2 && ok3);
}

int
mep_cgen_insn_supported_asm (CGEN_CPU_DESC cd, const CGEN_INSN *insn)
{
#ifdef MEP_IVC2_SUPPORTED
  /* If we're assembling VLIW packets, ignore the 12-bit BSR as we
     can't relax that.  The 24-bit BSR is matched instead.  */
  if (insn->base->num == MEP_INSN_BSR12
      && cgen_bitset_contains (cd->isas, ISA_EXT_COP1_64))
    return 0;
#endif

  return mep_cgen_insn_supported (cd, insn);
}
@


