185815Sobrien/* Instruction building/extraction support for @arch@. -*- C -*-
285815Sobrien
3218822Sdim   THIS FILE IS MACHINE GENERATED WITH CGEN: Cpu tools GENerator.
4218822Sdim   - the resultant file is machine generated, cgen-ibld.in isn't
585815Sobrien
6218822Sdim   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2005, 2006
7218822Sdim   Free Software Foundation, Inc.
885815Sobrien
9218822Sdim   This file is part of the GNU Binutils and GDB, the GNU debugger.
1085815Sobrien
11218822Sdim   This program is free software; you can redistribute it and/or modify
12218822Sdim   it under the terms of the GNU General Public License as published by
13218822Sdim   the Free Software Foundation; either version 2, or (at your option)
14218822Sdim   any later version.
1585815Sobrien
16218822Sdim   This program is distributed in the hope that it will be useful,
17218822Sdim   but WITHOUT ANY WARRANTY; without even the implied warranty of
18218822Sdim   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19218822Sdim   GNU General Public License for more details.
2085815Sobrien
21218822Sdim   You should have received a copy of the GNU General Public License
22218822Sdim   along with this program; if not, write to the Free Software Foundation, Inc.,
23218822Sdim   51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
2485815Sobrien
2585815Sobrien/* ??? Eventually more and more of this stuff can go to cpu-independent files.
2685815Sobrien   Keep that in mind.  */
2785815Sobrien
2885815Sobrien#include "sysdep.h"
2985815Sobrien#include <stdio.h>
3085815Sobrien#include "ansidecl.h"
3185815Sobrien#include "dis-asm.h"
3285815Sobrien#include "bfd.h"
3385815Sobrien#include "symcat.h"
3485815Sobrien#include "@prefix@-desc.h"
3585815Sobrien#include "@prefix@-opc.h"
3685815Sobrien#include "opintl.h"
3789857Sobrien#include "safe-ctype.h"
3885815Sobrien
39218822Sdim#undef  min
4085815Sobrien#define min(a,b) ((a) < (b) ? (a) : (b))
41218822Sdim#undef  max
4285815Sobrien#define max(a,b) ((a) > (b) ? (a) : (b))
4385815Sobrien
4485815Sobrien/* Used by the ifield rtx function.  */
4585815Sobrien#define FLD(f) (fields->f)
4685815Sobrien
4785815Sobrienstatic const char * insert_normal
48130561Sobrien  (CGEN_CPU_DESC, long, unsigned int, unsigned int, unsigned int,
49130561Sobrien   unsigned int, unsigned int, unsigned int, CGEN_INSN_BYTES_PTR);
5085815Sobrienstatic const char * insert_insn_normal
51130561Sobrien  (CGEN_CPU_DESC, const CGEN_INSN *,
52130561Sobrien   CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma);
5385815Sobrienstatic int extract_normal
54130561Sobrien  (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_INT,
55130561Sobrien   unsigned int, unsigned int, unsigned int, unsigned int,
56130561Sobrien   unsigned int, unsigned int, bfd_vma, long *);
5785815Sobrienstatic int extract_insn_normal
58130561Sobrien  (CGEN_CPU_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
59130561Sobrien   CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma);
6089857Sobrien#if CGEN_INT_INSN_P
6185815Sobrienstatic void put_insn_int_value
62130561Sobrien  (CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT);
6389857Sobrien#endif
6489857Sobrien#if ! CGEN_INT_INSN_P
6589857Sobrienstatic CGEN_INLINE void insert_1
66130561Sobrien  (CGEN_CPU_DESC, unsigned long, int, int, int, unsigned char *);
6789857Sobrienstatic CGEN_INLINE int fill_cache
68130561Sobrien  (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *,  int, int, bfd_vma);
6989857Sobrienstatic CGEN_INLINE long extract_1
70130561Sobrien  (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, int, unsigned char *, bfd_vma);
7189857Sobrien#endif
7285815Sobrien
7385815Sobrien/* Operand insertion.  */
7485815Sobrien
7585815Sobrien#if ! CGEN_INT_INSN_P
7685815Sobrien
7785815Sobrien/* Subroutine of insert_normal.  */
7885815Sobrien
7985815Sobrienstatic CGEN_INLINE void
80130561Sobrieninsert_1 (CGEN_CPU_DESC cd,
81130561Sobrien	  unsigned long value,
82130561Sobrien	  int start,
83130561Sobrien	  int length,
84130561Sobrien	  int word_length,
85130561Sobrien	  unsigned char *bufp)
8685815Sobrien{
8785815Sobrien  unsigned long x,mask;
8885815Sobrien  int shift;
8985815Sobrien
9089857Sobrien  x = cgen_get_insn_value (cd, bufp, word_length);
9185815Sobrien
9285815Sobrien  /* Written this way to avoid undefined behaviour.  */
9385815Sobrien  mask = (((1L << (length - 1)) - 1) << 1) | 1;
9485815Sobrien  if (CGEN_INSN_LSB0_P)
9585815Sobrien    shift = (start + 1) - length;
9685815Sobrien  else
9785815Sobrien    shift = (word_length - (start + length));
9885815Sobrien  x = (x & ~(mask << shift)) | ((value & mask) << shift);
9985815Sobrien
10089857Sobrien  cgen_put_insn_value (cd, bufp, word_length, (bfd_vma) x);
10185815Sobrien}
10285815Sobrien
10385815Sobrien#endif /* ! CGEN_INT_INSN_P */
10485815Sobrien
10585815Sobrien/* Default insertion routine.
10685815Sobrien
10785815Sobrien   ATTRS is a mask of the boolean attributes.
10885815Sobrien   WORD_OFFSET is the offset in bits from the start of the insn of the value.
10985815Sobrien   WORD_LENGTH is the length of the word in bits in which the value resides.
11085815Sobrien   START is the starting bit number in the word, architecture origin.
11185815Sobrien   LENGTH is the length of VALUE in bits.
11285815Sobrien   TOTAL_LENGTH is the total length of the insn in bits.
11385815Sobrien
11485815Sobrien   The result is an error message or NULL if success.  */
11585815Sobrien
11685815Sobrien/* ??? This duplicates functionality with bfd's howto table and
11785815Sobrien   bfd_install_relocation.  */
11885815Sobrien/* ??? This doesn't handle bfd_vma's.  Create another function when
11985815Sobrien   necessary.  */
12085815Sobrien
12185815Sobrienstatic const char *
122130561Sobrieninsert_normal (CGEN_CPU_DESC cd,
123130561Sobrien	       long value,
124130561Sobrien	       unsigned int attrs,
125130561Sobrien	       unsigned int word_offset,
126130561Sobrien	       unsigned int start,
127130561Sobrien	       unsigned int length,
128130561Sobrien	       unsigned int word_length,
129130561Sobrien	       unsigned int total_length,
130130561Sobrien	       CGEN_INSN_BYTES_PTR buffer)
13185815Sobrien{
13285815Sobrien  static char errbuf[100];
13385815Sobrien  /* Written this way to avoid undefined behaviour.  */
13485815Sobrien  unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
13585815Sobrien
13685815Sobrien  /* If LENGTH is zero, this operand doesn't contribute to the value.  */
13785815Sobrien  if (length == 0)
13885815Sobrien    return NULL;
13985815Sobrien
14085815Sobrien  if (word_length > 32)
14185815Sobrien    abort ();
14285815Sobrien
14385815Sobrien  /* For architectures with insns smaller than the base-insn-bitsize,
14485815Sobrien     word_length may be too big.  */
14585815Sobrien  if (cd->min_insn_bitsize < cd->base_insn_bitsize)
14685815Sobrien    {
14785815Sobrien      if (word_offset == 0
14885815Sobrien	  && word_length > total_length)
14985815Sobrien	word_length = total_length;
15085815Sobrien    }
15185815Sobrien
15285815Sobrien  /* Ensure VALUE will fit.  */
15389857Sobrien  if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGN_OPT))
15485815Sobrien    {
15589857Sobrien      long minval = - (1L << (length - 1));
15685815Sobrien      unsigned long maxval = mask;
15785815Sobrien      
15889857Sobrien      if ((value > 0 && (unsigned long) value > maxval)
15989857Sobrien	  || value < minval)
16089857Sobrien	{
16189857Sobrien	  /* xgettext:c-format */
16289857Sobrien	  sprintf (errbuf,
16389857Sobrien		   _("operand out of range (%ld not between %ld and %lu)"),
16489857Sobrien		   value, minval, maxval);
16589857Sobrien	  return errbuf;
16689857Sobrien	}
16789857Sobrien    }
16889857Sobrien  else if (! CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED))
16989857Sobrien    {
17089857Sobrien      unsigned long maxval = mask;
171218822Sdim      unsigned long val = (unsigned long) value;
172218822Sdim
173218822Sdim      /* For hosts with a word size > 32 check to see if value has been sign
174218822Sdim	 extended beyond 32 bits.  If so then ignore these higher sign bits
175218822Sdim	 as the user is attempting to store a 32-bit signed value into an
176218822Sdim	 unsigned 32-bit field which is allowed.  */
177218822Sdim      if (sizeof (unsigned long) > 4 && ((value >> 32) == -1))
178218822Sdim	val &= 0xFFFFFFFF;
179218822Sdim
180218822Sdim      if (val > maxval)
18185815Sobrien	{
18285815Sobrien	  /* xgettext:c-format */
18385815Sobrien	  sprintf (errbuf,
184218822Sdim		   _("operand out of range (0x%lx not between 0 and 0x%lx)"),
185218822Sdim		   val, maxval);
18685815Sobrien	  return errbuf;
18785815Sobrien	}
18885815Sobrien    }
18985815Sobrien  else
19085815Sobrien    {
19185815Sobrien      if (! cgen_signed_overflow_ok_p (cd))
19285815Sobrien	{
19385815Sobrien	  long minval = - (1L << (length - 1));
19485815Sobrien	  long maxval =   (1L << (length - 1)) - 1;
19585815Sobrien	  
19685815Sobrien	  if (value < minval || value > maxval)
19785815Sobrien	    {
19885815Sobrien	      sprintf
19985815Sobrien		/* xgettext:c-format */
20085815Sobrien		(errbuf, _("operand out of range (%ld not between %ld and %ld)"),
20185815Sobrien		 value, minval, maxval);
20285815Sobrien	      return errbuf;
20385815Sobrien	    }
20485815Sobrien	}
20585815Sobrien    }
20685815Sobrien
20785815Sobrien#if CGEN_INT_INSN_P
20885815Sobrien
20985815Sobrien  {
21085815Sobrien    int shift;
21185815Sobrien
21285815Sobrien    if (CGEN_INSN_LSB0_P)
21385815Sobrien      shift = (word_offset + start + 1) - length;
21485815Sobrien    else
21585815Sobrien      shift = total_length - (word_offset + start + length);
21685815Sobrien    *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
21785815Sobrien  }
21885815Sobrien
21985815Sobrien#else /* ! CGEN_INT_INSN_P */
22085815Sobrien
22185815Sobrien  {
22285815Sobrien    unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
22385815Sobrien
22485815Sobrien    insert_1 (cd, value, start, length, word_length, bufp);
22585815Sobrien  }
22685815Sobrien
22785815Sobrien#endif /* ! CGEN_INT_INSN_P */
22885815Sobrien
22985815Sobrien  return NULL;
23085815Sobrien}
23185815Sobrien
23285815Sobrien/* Default insn builder (insert handler).
23389857Sobrien   The instruction is recorded in CGEN_INT_INSN_P byte order (meaning
23489857Sobrien   that if CGEN_INSN_BYTES_PTR is an int * and thus, the value is
23589857Sobrien   recorded in host byte order, otherwise BUFFER is an array of bytes
23689857Sobrien   and the value is recorded in target byte order).
23785815Sobrien   The result is an error message or NULL if success.  */
23885815Sobrien
23985815Sobrienstatic const char *
240130561Sobrieninsert_insn_normal (CGEN_CPU_DESC cd,
241130561Sobrien		    const CGEN_INSN * insn,
242130561Sobrien		    CGEN_FIELDS * fields,
243130561Sobrien		    CGEN_INSN_BYTES_PTR buffer,
244130561Sobrien		    bfd_vma pc)
24585815Sobrien{
24685815Sobrien  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
24785815Sobrien  unsigned long value;
24885815Sobrien  const CGEN_SYNTAX_CHAR_TYPE * syn;
24985815Sobrien
25085815Sobrien  CGEN_INIT_INSERT (cd);
25185815Sobrien  value = CGEN_INSN_BASE_VALUE (insn);
25285815Sobrien
25385815Sobrien  /* If we're recording insns as numbers (rather than a string of bytes),
25485815Sobrien     target byte order handling is deferred until later.  */
25585815Sobrien
25685815Sobrien#if CGEN_INT_INSN_P
25785815Sobrien
25885815Sobrien  put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
25985815Sobrien		      CGEN_FIELDS_BITSIZE (fields), value);
26085815Sobrien
26185815Sobrien#else
26285815Sobrien
26389857Sobrien  cgen_put_insn_value (cd, buffer, min ((unsigned) cd->base_insn_bitsize,
26489857Sobrien					(unsigned) CGEN_FIELDS_BITSIZE (fields)),
26585815Sobrien		       value);
26685815Sobrien
26785815Sobrien#endif /* ! CGEN_INT_INSN_P */
26885815Sobrien
26985815Sobrien  /* ??? It would be better to scan the format's fields.
27085815Sobrien     Still need to be able to insert a value based on the operand though;
27185815Sobrien     e.g. storing a branch displacement that got resolved later.
27285815Sobrien     Needs more thought first.  */
27385815Sobrien
27485815Sobrien  for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
27585815Sobrien    {
27685815Sobrien      const char *errmsg;
27785815Sobrien
27885815Sobrien      if (CGEN_SYNTAX_CHAR_P (* syn))
27985815Sobrien	continue;
28085815Sobrien
28185815Sobrien      errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
28285815Sobrien				       fields, buffer, pc);
28385815Sobrien      if (errmsg)
28485815Sobrien	return errmsg;
28585815Sobrien    }
28685815Sobrien
28785815Sobrien  return NULL;
28885815Sobrien}
28985815Sobrien
29089857Sobrien#if CGEN_INT_INSN_P
29185815Sobrien/* Cover function to store an insn value into an integral insn.  Must go here
292218822Sdim   because it needs <prefix>-desc.h for CGEN_INT_INSN_P.  */
29385815Sobrien
29485815Sobrienstatic void
295130561Sobrienput_insn_int_value (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
296130561Sobrien		    CGEN_INSN_BYTES_PTR buf,
297130561Sobrien		    int length,
298130561Sobrien		    int insn_length,
299130561Sobrien		    CGEN_INSN_INT value)
30085815Sobrien{
30185815Sobrien  /* For architectures with insns smaller than the base-insn-bitsize,
30285815Sobrien     length may be too big.  */
30385815Sobrien  if (length > insn_length)
30485815Sobrien    *buf = value;
30585815Sobrien  else
30685815Sobrien    {
30785815Sobrien      int shift = insn_length - length;
30885815Sobrien      /* Written this way to avoid undefined behaviour.  */
30985815Sobrien      CGEN_INSN_INT mask = (((1L << (length - 1)) - 1) << 1) | 1;
310218822Sdim
31185815Sobrien      *buf = (*buf & ~(mask << shift)) | ((value & mask) << shift);
31285815Sobrien    }
31385815Sobrien}
31489857Sobrien#endif
31585815Sobrien
31685815Sobrien/* Operand extraction.  */
31785815Sobrien
31885815Sobrien#if ! CGEN_INT_INSN_P
31985815Sobrien
32085815Sobrien/* Subroutine of extract_normal.
32185815Sobrien   Ensure sufficient bytes are cached in EX_INFO.
32285815Sobrien   OFFSET is the offset in bytes from the start of the insn of the value.
32385815Sobrien   BYTES is the length of the needed value.
32485815Sobrien   Returns 1 for success, 0 for failure.  */
32585815Sobrien
32685815Sobrienstatic CGEN_INLINE int
327130561Sobrienfill_cache (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
328130561Sobrien	    CGEN_EXTRACT_INFO *ex_info,
329130561Sobrien	    int offset,
330130561Sobrien	    int bytes,
331130561Sobrien	    bfd_vma pc)
33285815Sobrien{
33385815Sobrien  /* It's doubtful that the middle part has already been fetched so
33485815Sobrien     we don't optimize that case.  kiss.  */
33589857Sobrien  unsigned int mask;
33685815Sobrien  disassemble_info *info = (disassemble_info *) ex_info->dis_info;
33785815Sobrien
33885815Sobrien  /* First do a quick check.  */
33985815Sobrien  mask = (1 << bytes) - 1;
34085815Sobrien  if (((ex_info->valid >> offset) & mask) == mask)
34185815Sobrien    return 1;
34285815Sobrien
34385815Sobrien  /* Search for the first byte we need to read.  */
34485815Sobrien  for (mask = 1 << offset; bytes > 0; --bytes, ++offset, mask <<= 1)
34585815Sobrien    if (! (mask & ex_info->valid))
34685815Sobrien      break;
34785815Sobrien
34885815Sobrien  if (bytes)
34985815Sobrien    {
35085815Sobrien      int status;
35185815Sobrien
35285815Sobrien      pc += offset;
35385815Sobrien      status = (*info->read_memory_func)
35485815Sobrien	(pc, ex_info->insn_bytes + offset, bytes, info);
35585815Sobrien
35685815Sobrien      if (status != 0)
35785815Sobrien	{
35885815Sobrien	  (*info->memory_error_func) (status, pc, info);
35985815Sobrien	  return 0;
36085815Sobrien	}
36185815Sobrien
36285815Sobrien      ex_info->valid |= ((1 << bytes) - 1) << offset;
36385815Sobrien    }
36485815Sobrien
36585815Sobrien  return 1;
36685815Sobrien}
36785815Sobrien
36885815Sobrien/* Subroutine of extract_normal.  */
36985815Sobrien
37085815Sobrienstatic CGEN_INLINE long
371130561Sobrienextract_1 (CGEN_CPU_DESC cd,
372130561Sobrien	   CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
373130561Sobrien	   int start,
374130561Sobrien	   int length,
375130561Sobrien	   int word_length,
376130561Sobrien	   unsigned char *bufp,
377130561Sobrien	   bfd_vma pc ATTRIBUTE_UNUSED)
37885815Sobrien{
37985815Sobrien  unsigned long x;
38085815Sobrien  int shift;
381218822Sdim
38289857Sobrien  x = cgen_get_insn_value (cd, bufp, word_length);
38385815Sobrien
38485815Sobrien  if (CGEN_INSN_LSB0_P)
38585815Sobrien    shift = (start + 1) - length;
38685815Sobrien  else
38785815Sobrien    shift = (word_length - (start + length));
38885815Sobrien  return x >> shift;
38985815Sobrien}
39085815Sobrien
39185815Sobrien#endif /* ! CGEN_INT_INSN_P */
39285815Sobrien
39385815Sobrien/* Default extraction routine.
39485815Sobrien
39585815Sobrien   INSN_VALUE is the first base_insn_bitsize bits of the insn in host order,
39685815Sobrien   or sometimes less for cases like the m32r where the base insn size is 32
39785815Sobrien   but some insns are 16 bits.
39885815Sobrien   ATTRS is a mask of the boolean attributes.  We only need `SIGNED',
39985815Sobrien   but for generality we take a bitmask of all of them.
40085815Sobrien   WORD_OFFSET is the offset in bits from the start of the insn of the value.
40185815Sobrien   WORD_LENGTH is the length of the word in bits in which the value resides.
40285815Sobrien   START is the starting bit number in the word, architecture origin.
40385815Sobrien   LENGTH is the length of VALUE in bits.
40485815Sobrien   TOTAL_LENGTH is the total length of the insn in bits.
40585815Sobrien
40685815Sobrien   Returns 1 for success, 0 for failure.  */
40785815Sobrien
40885815Sobrien/* ??? The return code isn't properly used.  wip.  */
40985815Sobrien
41085815Sobrien/* ??? This doesn't handle bfd_vma's.  Create another function when
41185815Sobrien   necessary.  */
41285815Sobrien
41385815Sobrienstatic int
414130561Sobrienextract_normal (CGEN_CPU_DESC cd,
41585815Sobrien#if ! CGEN_INT_INSN_P
416130561Sobrien		CGEN_EXTRACT_INFO *ex_info,
41785815Sobrien#else
418130561Sobrien		CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
41985815Sobrien#endif
420130561Sobrien		CGEN_INSN_INT insn_value,
421130561Sobrien		unsigned int attrs,
422130561Sobrien		unsigned int word_offset,
423130561Sobrien		unsigned int start,
424130561Sobrien		unsigned int length,
425130561Sobrien		unsigned int word_length,
426130561Sobrien		unsigned int total_length,
42785815Sobrien#if ! CGEN_INT_INSN_P
428130561Sobrien		bfd_vma pc,
42985815Sobrien#else
430130561Sobrien		bfd_vma pc ATTRIBUTE_UNUSED,
43185815Sobrien#endif
432130561Sobrien		long *valuep)
43385815Sobrien{
43489857Sobrien  long value, mask;
43585815Sobrien
43685815Sobrien  /* If LENGTH is zero, this operand doesn't contribute to the value
43785815Sobrien     so give it a standard value of zero.  */
43885815Sobrien  if (length == 0)
43985815Sobrien    {
44085815Sobrien      *valuep = 0;
44185815Sobrien      return 1;
44285815Sobrien    }
44385815Sobrien
44485815Sobrien  if (word_length > 32)
44585815Sobrien    abort ();
44685815Sobrien
44785815Sobrien  /* For architectures with insns smaller than the insn-base-bitsize,
44885815Sobrien     word_length may be too big.  */
44985815Sobrien  if (cd->min_insn_bitsize < cd->base_insn_bitsize)
45085815Sobrien    {
451218822Sdim      if (word_offset + word_length > total_length)
452218822Sdim	word_length = total_length - word_offset;
45385815Sobrien    }
45485815Sobrien
45589857Sobrien  /* Does the value reside in INSN_VALUE, and at the right alignment?  */
45685815Sobrien
45789857Sobrien  if (CGEN_INT_INSN_P || (word_offset == 0 && word_length == total_length))
45885815Sobrien    {
45985815Sobrien      if (CGEN_INSN_LSB0_P)
46085815Sobrien	value = insn_value >> ((word_offset + start + 1) - length);
46185815Sobrien      else
46285815Sobrien	value = insn_value >> (total_length - ( word_offset + start + length));
46385815Sobrien    }
46485815Sobrien
46585815Sobrien#if ! CGEN_INT_INSN_P
46685815Sobrien
46785815Sobrien  else
46885815Sobrien    {
46985815Sobrien      unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
47085815Sobrien
47185815Sobrien      if (word_length > 32)
47285815Sobrien	abort ();
47385815Sobrien
47485815Sobrien      if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
47585815Sobrien	return 0;
47685815Sobrien
47785815Sobrien      value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
47885815Sobrien    }
47985815Sobrien
48085815Sobrien#endif /* ! CGEN_INT_INSN_P */
48185815Sobrien
48285815Sobrien  /* Written this way to avoid undefined behaviour.  */
48385815Sobrien  mask = (((1L << (length - 1)) - 1) << 1) | 1;
48485815Sobrien
48585815Sobrien  value &= mask;
48685815Sobrien  /* sign extend? */
48785815Sobrien  if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
48885815Sobrien      && (value & (1L << (length - 1))))
48985815Sobrien    value |= ~mask;
49085815Sobrien
49185815Sobrien  *valuep = value;
49285815Sobrien
49385815Sobrien  return 1;
49485815Sobrien}
49585815Sobrien
49685815Sobrien/* Default insn extractor.
49785815Sobrien
49885815Sobrien   INSN_VALUE is the first base_insn_bitsize bits, translated to host order.
49985815Sobrien   The extracted fields are stored in FIELDS.
50085815Sobrien   EX_INFO is used to handle reading variable length insns.
50185815Sobrien   Return the length of the insn in bits, or 0 if no match,
50285815Sobrien   or -1 if an error occurs fetching data (memory_error_func will have
50385815Sobrien   been called).  */
50485815Sobrien
50585815Sobrienstatic int
506130561Sobrienextract_insn_normal (CGEN_CPU_DESC cd,
507130561Sobrien		     const CGEN_INSN *insn,
508130561Sobrien		     CGEN_EXTRACT_INFO *ex_info,
509130561Sobrien		     CGEN_INSN_INT insn_value,
510130561Sobrien		     CGEN_FIELDS *fields,
511130561Sobrien		     bfd_vma pc)
51285815Sobrien{
51385815Sobrien  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
51485815Sobrien  const CGEN_SYNTAX_CHAR_TYPE *syn;
51585815Sobrien
51685815Sobrien  CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
51785815Sobrien
51885815Sobrien  CGEN_INIT_EXTRACT (cd);
51985815Sobrien
52085815Sobrien  for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
52185815Sobrien    {
52285815Sobrien      int length;
52385815Sobrien
52485815Sobrien      if (CGEN_SYNTAX_CHAR_P (*syn))
52585815Sobrien	continue;
52685815Sobrien
52785815Sobrien      length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
52885815Sobrien					ex_info, insn_value, fields, pc);
52985815Sobrien      if (length <= 0)
53085815Sobrien	return length;
53185815Sobrien    }
53285815Sobrien
53385815Sobrien  /* We recognized and successfully extracted this insn.  */
53485815Sobrien  return CGEN_INSN_BITSIZE (insn);
53585815Sobrien}
53685815Sobrien
537218822Sdim/* Machine generated code added here.  */
538