(root)/
binutils-2.41/
opcodes/
ip2k-ibld.c
       1  /* DO NOT EDIT!  -*- buffer-read-only: t -*- vi:set ro:  */
       2  /* Instruction building/extraction support for ip2k. -*- C -*-
       3  
       4     THIS FILE IS MACHINE GENERATED WITH CGEN: Cpu tools GENerator.
       5     - the resultant file is machine generated, cgen-ibld.in isn't
       6  
       7     Copyright (C) 1996-2023 Free Software Foundation, Inc.
       8  
       9     This file is part of libopcodes.
      10  
      11     This library is free software; you can redistribute it and/or modify
      12     it under the terms of the GNU General Public License as published by
      13     the Free Software Foundation; either version 3, or (at your option)
      14     any later version.
      15  
      16     It is distributed in the hope that it will be useful, but WITHOUT
      17     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      18     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
      19     License for more details.
      20  
      21     You should have received a copy of the GNU General Public License
      22     along with this program; if not, write to the Free Software Foundation, Inc.,
      23     51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
      24  
      25  /* ??? Eventually more and more of this stuff can go to cpu-independent files.
      26     Keep that in mind.  */
      27  
      28  #include "sysdep.h"
      29  #include <stdio.h>
      30  #include "ansidecl.h"
      31  #include "dis-asm.h"
      32  #include "bfd.h"
      33  #include "symcat.h"
      34  #include "ip2k-desc.h"
      35  #include "ip2k-opc.h"
      36  #include "cgen/basic-modes.h"
      37  #include "opintl.h"
      38  #include "safe-ctype.h"
      39  
      40  #undef  min
      41  #define min(a,b) ((a) < (b) ? (a) : (b))
      42  #undef  max
      43  #define max(a,b) ((a) > (b) ? (a) : (b))
      44  
      45  /* Used by the ifield rtx function.  */
      46  #define FLD(f) (fields->f)
      47  
      48  static const char * insert_normal
      49    (CGEN_CPU_DESC, long, unsigned int, unsigned int, unsigned int,
      50     unsigned int, unsigned int, unsigned int, CGEN_INSN_BYTES_PTR);
      51  static const char * insert_insn_normal
      52    (CGEN_CPU_DESC, const CGEN_INSN *,
      53     CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma);
      54  static int extract_normal
      55    (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_INT,
      56     unsigned int, unsigned int, unsigned int, unsigned int,
      57     unsigned int, unsigned int, bfd_vma, long *);
      58  static int extract_insn_normal
      59    (CGEN_CPU_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
      60     CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma);
      61  #if CGEN_INT_INSN_P
      62  static void put_insn_int_value
      63    (CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT);
      64  #endif
      65  #if ! CGEN_INT_INSN_P
      66  static CGEN_INLINE void insert_1
      67    (CGEN_CPU_DESC, unsigned long, int, int, int, unsigned char *);
      68  static CGEN_INLINE int fill_cache
      69    (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *,  int, int, bfd_vma);
      70  static CGEN_INLINE long extract_1
      71    (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, int, unsigned char *, bfd_vma);
      72  #endif
      73  
      74  /* Operand insertion.  */
      75  
      76  #if ! CGEN_INT_INSN_P
      77  
      78  /* Subroutine of insert_normal.  */
      79  
      80  static CGEN_INLINE void
      81  insert_1 (CGEN_CPU_DESC cd,
      82  	  unsigned long value,
      83  	  int start,
      84  	  int length,
      85  	  int word_length,
      86  	  unsigned char *bufp)
      87  {
      88    unsigned long x, mask;
      89    int shift;
      90  
      91    x = cgen_get_insn_value (cd, bufp, word_length, cd->endian);
      92  
      93    /* Written this way to avoid undefined behaviour.  */
      94    mask = (1UL << (length - 1) << 1) - 1;
      95    if (CGEN_INSN_LSB0_P)
      96      shift = (start + 1) - length;
      97    else
      98      shift = (word_length - (start + length));
      99    x = (x & ~(mask << shift)) | ((value & mask) << shift);
     100  
     101    cgen_put_insn_value (cd, bufp, word_length, (bfd_vma) x, cd->endian);
     102  }
     103  
     104  #endif /* ! CGEN_INT_INSN_P */
     105  
     106  /* Default insertion routine.
     107  
     108     ATTRS is a mask of the boolean attributes.
     109     WORD_OFFSET is the offset in bits from the start of the insn of the value.
     110     WORD_LENGTH is the length of the word in bits in which the value resides.
     111     START is the starting bit number in the word, architecture origin.
     112     LENGTH is the length of VALUE in bits.
     113     TOTAL_LENGTH is the total length of the insn in bits.
     114  
     115     The result is an error message or NULL if success.  */
     116  
     117  /* ??? This duplicates functionality with bfd's howto table and
     118     bfd_install_relocation.  */
     119  /* ??? This doesn't handle bfd_vma's.  Create another function when
     120     necessary.  */
     121  
     122  static const char *
     123  insert_normal (CGEN_CPU_DESC cd,
     124  	       long value,
     125  	       unsigned int attrs,
     126  	       unsigned int word_offset,
     127  	       unsigned int start,
     128  	       unsigned int length,
     129  	       unsigned int word_length,
     130  	       unsigned int total_length,
     131  	       CGEN_INSN_BYTES_PTR buffer)
     132  {
     133    static char errbuf[100];
     134    unsigned long mask;
     135  
     136    /* If LENGTH is zero, this operand doesn't contribute to the value.  */
     137    if (length == 0)
     138      return NULL;
     139  
     140    /* Written this way to avoid undefined behaviour.  */
     141    mask = (1UL << (length - 1) << 1) - 1;
     142  
     143    if (word_length > 8 * sizeof (CGEN_INSN_INT))
     144      abort ();
     145  
     146    /* For architectures with insns smaller than the base-insn-bitsize,
     147       word_length may be too big.  */
     148    if (cd->min_insn_bitsize < cd->base_insn_bitsize)
     149      {
     150        if (word_offset == 0
     151  	  && word_length > total_length)
     152  	word_length = total_length;
     153      }
     154  
     155    /* Ensure VALUE will fit.  */
     156    if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGN_OPT))
     157      {
     158        long minval = - (1UL << (length - 1));
     159        unsigned long maxval = mask;
     160  
     161        if ((value > 0 && (unsigned long) value > maxval)
     162  	  || value < minval)
     163  	{
     164  	  /* xgettext:c-format */
     165  	  sprintf (errbuf,
     166  		   _("operand out of range (%ld not between %ld and %lu)"),
     167  		   value, minval, maxval);
     168  	  return errbuf;
     169  	}
     170      }
     171    else if (! CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED))
     172      {
     173        unsigned long maxval = mask;
     174        unsigned long val = (unsigned long) value;
     175  
     176        /* For hosts with a word size > 32 check to see if value has been sign
     177  	 extended beyond 32 bits.  If so then ignore these higher sign bits
     178  	 as the user is attempting to store a 32-bit signed value into an
     179  	 unsigned 32-bit field which is allowed.  */
     180        if (sizeof (unsigned long) > 4 && ((value >> 32) == -1))
     181  	val &= 0xFFFFFFFF;
     182  
     183        if (val > maxval)
     184  	{
     185  	  /* xgettext:c-format */
     186  	  sprintf (errbuf,
     187  		   _("operand out of range (0x%lx not between 0 and 0x%lx)"),
     188  		   val, maxval);
     189  	  return errbuf;
     190  	}
     191      }
     192    else
     193      {
     194        if (! cgen_signed_overflow_ok_p (cd))
     195  	{
     196  	  long minval = - (1UL << (length - 1));
     197  	  long maxval =   (1UL << (length - 1)) - 1;
     198  
     199  	  if (value < minval || value > maxval)
     200  	    {
     201  	      sprintf
     202  		/* xgettext:c-format */
     203  		(errbuf, _("operand out of range (%ld not between %ld and %ld)"),
     204  		 value, minval, maxval);
     205  	      return errbuf;
     206  	    }
     207  	}
     208      }
     209  
     210  #if CGEN_INT_INSN_P
     211  
     212    {
     213      int shift_within_word, shift_to_word, shift;
     214  
     215      /* How to shift the value to BIT0 of the word.  */
     216      shift_to_word = total_length - (word_offset + word_length);
     217  
     218      /* How to shift the value to the field within the word.  */
     219      if (CGEN_INSN_LSB0_P)
     220        shift_within_word = start + 1 - length;
     221      else
     222        shift_within_word = word_length - start - length;
     223  
     224      /* The total SHIFT, then mask in the value.  */
     225      shift = shift_to_word + shift_within_word;
     226      *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
     227    }
     228  
     229  #else /* ! CGEN_INT_INSN_P */
     230  
     231    {
     232      unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
     233  
     234      insert_1 (cd, value, start, length, word_length, bufp);
     235    }
     236  
     237  #endif /* ! CGEN_INT_INSN_P */
     238  
     239    return NULL;
     240  }
     241  
     242  /* Default insn builder (insert handler).
     243     The instruction is recorded in CGEN_INT_INSN_P byte order (meaning
     244     that if CGEN_INSN_BYTES_PTR is an int * and thus, the value is
     245     recorded in host byte order, otherwise BUFFER is an array of bytes
     246     and the value is recorded in target byte order).
     247     The result is an error message or NULL if success.  */
     248  
     249  static const char *
     250  insert_insn_normal (CGEN_CPU_DESC cd,
     251  		    const CGEN_INSN * insn,
     252  		    CGEN_FIELDS * fields,
     253  		    CGEN_INSN_BYTES_PTR buffer,
     254  		    bfd_vma pc)
     255  {
     256    const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
     257    unsigned long value;
     258    const CGEN_SYNTAX_CHAR_TYPE * syn;
     259  
     260    CGEN_INIT_INSERT (cd);
     261    value = CGEN_INSN_BASE_VALUE (insn);
     262  
     263    /* If we're recording insns as numbers (rather than a string of bytes),
     264       target byte order handling is deferred until later.  */
     265  
     266  #if CGEN_INT_INSN_P
     267  
     268    put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
     269  		      CGEN_FIELDS_BITSIZE (fields), value);
     270  
     271  #else
     272  
     273    cgen_put_insn_value (cd, buffer, min ((unsigned) cd->base_insn_bitsize,
     274                                          (unsigned) CGEN_FIELDS_BITSIZE (fields)),
     275  		       value, cd->insn_endian);
     276  
     277  #endif /* ! CGEN_INT_INSN_P */
     278  
     279    /* ??? It would be better to scan the format's fields.
     280       Still need to be able to insert a value based on the operand though;
     281       e.g. storing a branch displacement that got resolved later.
     282       Needs more thought first.  */
     283  
     284    for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
     285      {
     286        const char *errmsg;
     287  
     288        if (CGEN_SYNTAX_CHAR_P (* syn))
     289  	continue;
     290  
     291        errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
     292  				       fields, buffer, pc);
     293        if (errmsg)
     294  	return errmsg;
     295      }
     296  
     297    return NULL;
     298  }
     299  
     300  #if CGEN_INT_INSN_P
     301  /* Cover function to store an insn value into an integral insn.  Must go here
     302     because it needs <prefix>-desc.h for CGEN_INT_INSN_P.  */
     303  
     304  static void
     305  put_insn_int_value (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     306  		    CGEN_INSN_BYTES_PTR buf,
     307  		    int length,
     308  		    int insn_length,
     309  		    CGEN_INSN_INT value)
     310  {
     311    /* For architectures with insns smaller than the base-insn-bitsize,
     312       length may be too big.  */
     313    if (length > insn_length)
     314      *buf = value;
     315    else
     316      {
     317        int shift = insn_length - length;
     318        /* Written this way to avoid undefined behaviour.  */
     319        CGEN_INSN_INT mask = length == 0 ? 0 : (1UL << (length - 1) << 1) - 1;
     320  
     321        *buf = (*buf & ~(mask << shift)) | ((value & mask) << shift);
     322      }
     323  }
     324  #endif
     325  
     326  /* Operand extraction.  */
     327  
     328  #if ! CGEN_INT_INSN_P
     329  
     330  /* Subroutine of extract_normal.
     331     Ensure sufficient bytes are cached in EX_INFO.
     332     OFFSET is the offset in bytes from the start of the insn of the value.
     333     BYTES is the length of the needed value.
     334     Returns 1 for success, 0 for failure.  */
     335  
     336  static CGEN_INLINE int
     337  fill_cache (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     338  	    CGEN_EXTRACT_INFO *ex_info,
     339  	    int offset,
     340  	    int bytes,
     341  	    bfd_vma pc)
     342  {
     343    /* It's doubtful that the middle part has already been fetched so
     344       we don't optimize that case.  kiss.  */
     345    unsigned int mask;
     346    disassemble_info *info = (disassemble_info *) ex_info->dis_info;
     347  
     348    /* First do a quick check.  */
     349    mask = (1 << bytes) - 1;
     350    if (((ex_info->valid >> offset) & mask) == mask)
     351      return 1;
     352  
     353    /* Search for the first byte we need to read.  */
     354    for (mask = 1 << offset; bytes > 0; --bytes, ++offset, mask <<= 1)
     355      if (! (mask & ex_info->valid))
     356        break;
     357  
     358    if (bytes)
     359      {
     360        int status;
     361  
     362        pc += offset;
     363        status = (*info->read_memory_func)
     364  	(pc, ex_info->insn_bytes + offset, bytes, info);
     365  
     366        if (status != 0)
     367  	{
     368  	  (*info->memory_error_func) (status, pc, info);
     369  	  return 0;
     370  	}
     371  
     372        ex_info->valid |= ((1 << bytes) - 1) << offset;
     373      }
     374  
     375    return 1;
     376  }
     377  
     378  /* Subroutine of extract_normal.  */
     379  
     380  static CGEN_INLINE long
     381  extract_1 (CGEN_CPU_DESC cd,
     382  	   CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
     383  	   int start,
     384  	   int length,
     385  	   int word_length,
     386  	   unsigned char *bufp,
     387  	   bfd_vma pc ATTRIBUTE_UNUSED)
     388  {
     389    unsigned long x;
     390    int shift;
     391  
     392    x = cgen_get_insn_value (cd, bufp, word_length, cd->endian);
     393  
     394    if (CGEN_INSN_LSB0_P)
     395      shift = (start + 1) - length;
     396    else
     397      shift = (word_length - (start + length));
     398    return x >> shift;
     399  }
     400  
     401  #endif /* ! CGEN_INT_INSN_P */
     402  
     403  /* Default extraction routine.
     404  
     405     INSN_VALUE is the first base_insn_bitsize bits of the insn in host order,
     406     or sometimes less for cases like the m32r where the base insn size is 32
     407     but some insns are 16 bits.
     408     ATTRS is a mask of the boolean attributes.  We only need `SIGNED',
     409     but for generality we take a bitmask of all of them.
     410     WORD_OFFSET is the offset in bits from the start of the insn of the value.
     411     WORD_LENGTH is the length of the word in bits in which the value resides.
     412     START is the starting bit number in the word, architecture origin.
     413     LENGTH is the length of VALUE in bits.
     414     TOTAL_LENGTH is the total length of the insn in bits.
     415  
     416     Returns 1 for success, 0 for failure.  */
     417  
     418  /* ??? The return code isn't properly used.  wip.  */
     419  
     420  /* ??? This doesn't handle bfd_vma's.  Create another function when
     421     necessary.  */
     422  
     423  static int
     424  extract_normal (CGEN_CPU_DESC cd,
     425  #if ! CGEN_INT_INSN_P
     426  		CGEN_EXTRACT_INFO *ex_info,
     427  #else
     428  		CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
     429  #endif
     430  		CGEN_INSN_INT insn_value,
     431  		unsigned int attrs,
     432  		unsigned int word_offset,
     433  		unsigned int start,
     434  		unsigned int length,
     435  		unsigned int word_length,
     436  		unsigned int total_length,
     437  #if ! CGEN_INT_INSN_P
     438  		bfd_vma pc,
     439  #else
     440  		bfd_vma pc ATTRIBUTE_UNUSED,
     441  #endif
     442  		long *valuep)
     443  {
     444    long value, mask;
     445  
     446    /* If LENGTH is zero, this operand doesn't contribute to the value
     447       so give it a standard value of zero.  */
     448    if (length == 0)
     449      {
     450        *valuep = 0;
     451        return 1;
     452      }
     453  
     454    if (word_length > 8 * sizeof (CGEN_INSN_INT))
     455      abort ();
     456  
     457    /* For architectures with insns smaller than the insn-base-bitsize,
     458       word_length may be too big.  */
     459    if (cd->min_insn_bitsize < cd->base_insn_bitsize)
     460      {
     461        if (word_offset + word_length > total_length)
     462  	word_length = total_length - word_offset;
     463      }
     464  
     465    /* Does the value reside in INSN_VALUE, and at the right alignment?  */
     466  
     467    if (CGEN_INT_INSN_P || (word_offset == 0 && word_length == total_length))
     468      {
     469        if (CGEN_INSN_LSB0_P)
     470  	value = insn_value >> ((word_offset + start + 1) - length);
     471        else
     472  	value = insn_value >> (total_length - ( word_offset + start + length));
     473      }
     474  
     475  #if ! CGEN_INT_INSN_P
     476  
     477    else
     478      {
     479        unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
     480  
     481        if (word_length > 8 * sizeof (CGEN_INSN_INT))
     482  	abort ();
     483  
     484        if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
     485  	{
     486  	  *valuep = 0;
     487  	  return 0;
     488  	}
     489  
     490        value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
     491      }
     492  
     493  #endif /* ! CGEN_INT_INSN_P */
     494  
     495    /* Written this way to avoid undefined behaviour.  */
     496    mask = (1UL << (length - 1) << 1) - 1;
     497  
     498    value &= mask;
     499    /* sign extend? */
     500    if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
     501        && (value & (1UL << (length - 1))))
     502      value |= ~mask;
     503  
     504    *valuep = value;
     505  
     506    return 1;
     507  }
     508  
     509  /* Default insn extractor.
     510  
     511     INSN_VALUE is the first base_insn_bitsize bits, translated to host order.
     512     The extracted fields are stored in FIELDS.
     513     EX_INFO is used to handle reading variable length insns.
     514     Return the length of the insn in bits, or 0 if no match,
     515     or -1 if an error occurs fetching data (memory_error_func will have
     516     been called).  */
     517  
     518  static int
     519  extract_insn_normal (CGEN_CPU_DESC cd,
     520  		     const CGEN_INSN *insn,
     521  		     CGEN_EXTRACT_INFO *ex_info,
     522  		     CGEN_INSN_INT insn_value,
     523  		     CGEN_FIELDS *fields,
     524  		     bfd_vma pc)
     525  {
     526    const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
     527    const CGEN_SYNTAX_CHAR_TYPE *syn;
     528  
     529    CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
     530  
     531    CGEN_INIT_EXTRACT (cd);
     532  
     533    for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
     534      {
     535        int length;
     536  
     537        if (CGEN_SYNTAX_CHAR_P (*syn))
     538  	continue;
     539  
     540        length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
     541  					ex_info, insn_value, fields, pc);
     542        if (length <= 0)
     543  	return length;
     544      }
     545  
     546    /* We recognized and successfully extracted this insn.  */
     547    return CGEN_INSN_BITSIZE (insn);
     548  }
     549  
     550  /* Machine generated code added here.  */
     551  
     552  const char * ip2k_cgen_insert_operand
     553    (CGEN_CPU_DESC, int, CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma);
     554  
     555  /* Main entry point for operand insertion.
     556  
     557     This function is basically just a big switch statement.  Earlier versions
     558     used tables to look up the function to use, but
     559     - if the table contains both assembler and disassembler functions then
     560       the disassembler contains much of the assembler and vice-versa,
     561     - there's a lot of inlining possibilities as things grow,
     562     - using a switch statement avoids the function call overhead.
     563  
     564     This function could be moved into `parse_insn_normal', but keeping it
     565     separate makes clear the interface between `parse_insn_normal' and each of
     566     the handlers.  It's also needed by GAS to insert operands that couldn't be
     567     resolved during parsing.  */
     568  
     569  const char *
     570  ip2k_cgen_insert_operand (CGEN_CPU_DESC cd,
     571  			     int opindex,
     572  			     CGEN_FIELDS * fields,
     573  			     CGEN_INSN_BYTES_PTR buffer,
     574  			     bfd_vma pc ATTRIBUTE_UNUSED)
     575  {
     576    const char * errmsg = NULL;
     577    unsigned int total_length = CGEN_FIELDS_BITSIZE (fields);
     578  
     579    switch (opindex)
     580      {
     581      case IP2K_OPERAND_ADDR16CJP :
     582        errmsg = insert_normal (cd, fields->f_addr16cjp, 0|(1<<CGEN_IFLD_ABS_ADDR), 0, 12, 13, 16, total_length, buffer);
     583        break;
     584      case IP2K_OPERAND_ADDR16H :
     585        errmsg = insert_normal (cd, fields->f_imm8, 0, 0, 7, 8, 16, total_length, buffer);
     586        break;
     587      case IP2K_OPERAND_ADDR16L :
     588        errmsg = insert_normal (cd, fields->f_imm8, 0, 0, 7, 8, 16, total_length, buffer);
     589        break;
     590      case IP2K_OPERAND_ADDR16P :
     591        errmsg = insert_normal (cd, fields->f_page3, 0, 0, 2, 3, 16, total_length, buffer);
     592        break;
     593      case IP2K_OPERAND_BITNO :
     594        errmsg = insert_normal (cd, fields->f_bitno, 0, 0, 11, 3, 16, total_length, buffer);
     595        break;
     596      case IP2K_OPERAND_CBIT :
     597        break;
     598      case IP2K_OPERAND_DCBIT :
     599        break;
     600      case IP2K_OPERAND_FR :
     601        errmsg = insert_normal (cd, fields->f_reg, 0|(1<<CGEN_IFLD_ABS_ADDR), 0, 8, 9, 16, total_length, buffer);
     602        break;
     603      case IP2K_OPERAND_LIT8 :
     604        errmsg = insert_normal (cd, fields->f_imm8, 0, 0, 7, 8, 16, total_length, buffer);
     605        break;
     606      case IP2K_OPERAND_PABITS :
     607        break;
     608      case IP2K_OPERAND_RETI3 :
     609        errmsg = insert_normal (cd, fields->f_reti3, 0, 0, 2, 3, 16, total_length, buffer);
     610        break;
     611      case IP2K_OPERAND_ZBIT :
     612        break;
     613  
     614      default :
     615        /* xgettext:c-format */
     616        opcodes_error_handler
     617  	(_("internal error: unrecognized field %d while building insn"),
     618  	 opindex);
     619        abort ();
     620    }
     621  
     622    return errmsg;
     623  }
     624  
     625  int ip2k_cgen_extract_operand
     626    (CGEN_CPU_DESC, int, CGEN_EXTRACT_INFO *, CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma);
     627  
     628  /* Main entry point for operand extraction.
     629     The result is <= 0 for error, >0 for success.
     630     ??? Actual values aren't well defined right now.
     631  
     632     This function is basically just a big switch statement.  Earlier versions
     633     used tables to look up the function to use, but
     634     - if the table contains both assembler and disassembler functions then
     635       the disassembler contains much of the assembler and vice-versa,
     636     - there's a lot of inlining possibilities as things grow,
     637     - using a switch statement avoids the function call overhead.
     638  
     639     This function could be moved into `print_insn_normal', but keeping it
     640     separate makes clear the interface between `print_insn_normal' and each of
     641     the handlers.  */
     642  
     643  int
     644  ip2k_cgen_extract_operand (CGEN_CPU_DESC cd,
     645  			     int opindex,
     646  			     CGEN_EXTRACT_INFO *ex_info,
     647  			     CGEN_INSN_INT insn_value,
     648  			     CGEN_FIELDS * fields,
     649  			     bfd_vma pc)
     650  {
     651    /* Assume success (for those operands that are nops).  */
     652    int length = 1;
     653    unsigned int total_length = CGEN_FIELDS_BITSIZE (fields);
     654  
     655    switch (opindex)
     656      {
     657      case IP2K_OPERAND_ADDR16CJP :
     658        length = extract_normal (cd, ex_info, insn_value, 0|(1<<CGEN_IFLD_ABS_ADDR), 0, 12, 13, 16, total_length, pc, & fields->f_addr16cjp);
     659        break;
     660      case IP2K_OPERAND_ADDR16H :
     661        length = extract_normal (cd, ex_info, insn_value, 0, 0, 7, 8, 16, total_length, pc, & fields->f_imm8);
     662        break;
     663      case IP2K_OPERAND_ADDR16L :
     664        length = extract_normal (cd, ex_info, insn_value, 0, 0, 7, 8, 16, total_length, pc, & fields->f_imm8);
     665        break;
     666      case IP2K_OPERAND_ADDR16P :
     667        length = extract_normal (cd, ex_info, insn_value, 0, 0, 2, 3, 16, total_length, pc, & fields->f_page3);
     668        break;
     669      case IP2K_OPERAND_BITNO :
     670        length = extract_normal (cd, ex_info, insn_value, 0, 0, 11, 3, 16, total_length, pc, & fields->f_bitno);
     671        break;
     672      case IP2K_OPERAND_CBIT :
     673        break;
     674      case IP2K_OPERAND_DCBIT :
     675        break;
     676      case IP2K_OPERAND_FR :
     677        length = extract_normal (cd, ex_info, insn_value, 0|(1<<CGEN_IFLD_ABS_ADDR), 0, 8, 9, 16, total_length, pc, & fields->f_reg);
     678        break;
     679      case IP2K_OPERAND_LIT8 :
     680        length = extract_normal (cd, ex_info, insn_value, 0, 0, 7, 8, 16, total_length, pc, & fields->f_imm8);
     681        break;
     682      case IP2K_OPERAND_PABITS :
     683        break;
     684      case IP2K_OPERAND_RETI3 :
     685        length = extract_normal (cd, ex_info, insn_value, 0, 0, 2, 3, 16, total_length, pc, & fields->f_reti3);
     686        break;
     687      case IP2K_OPERAND_ZBIT :
     688        break;
     689  
     690      default :
     691        /* xgettext:c-format */
     692        opcodes_error_handler
     693  	(_("internal error: unrecognized field %d while decoding insn"),
     694  	 opindex);
     695        abort ();
     696      }
     697  
     698    return length;
     699  }
     700  
     701  cgen_insert_fn * const ip2k_cgen_insert_handlers[] =
     702  {
     703    insert_insn_normal,
     704  };
     705  
     706  cgen_extract_fn * const ip2k_cgen_extract_handlers[] =
     707  {
     708    extract_insn_normal,
     709  };
     710  
     711  int ip2k_cgen_get_int_operand     (CGEN_CPU_DESC, int, const CGEN_FIELDS *);
     712  bfd_vma ip2k_cgen_get_vma_operand (CGEN_CPU_DESC, int, const CGEN_FIELDS *);
     713  
     714  /* Getting values from cgen_fields is handled by a collection of functions.
     715     They are distinguished by the type of the VALUE argument they return.
     716     TODO: floating point, inlining support, remove cases where result type
     717     not appropriate.  */
     718  
     719  int
     720  ip2k_cgen_get_int_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     721  			     int opindex,
     722  			     const CGEN_FIELDS * fields)
     723  {
     724    int value;
     725  
     726    switch (opindex)
     727      {
     728      case IP2K_OPERAND_ADDR16CJP :
     729        value = fields->f_addr16cjp;
     730        break;
     731      case IP2K_OPERAND_ADDR16H :
     732        value = fields->f_imm8;
     733        break;
     734      case IP2K_OPERAND_ADDR16L :
     735        value = fields->f_imm8;
     736        break;
     737      case IP2K_OPERAND_ADDR16P :
     738        value = fields->f_page3;
     739        break;
     740      case IP2K_OPERAND_BITNO :
     741        value = fields->f_bitno;
     742        break;
     743      case IP2K_OPERAND_CBIT :
     744        value = 0;
     745        break;
     746      case IP2K_OPERAND_DCBIT :
     747        value = 0;
     748        break;
     749      case IP2K_OPERAND_FR :
     750        value = fields->f_reg;
     751        break;
     752      case IP2K_OPERAND_LIT8 :
     753        value = fields->f_imm8;
     754        break;
     755      case IP2K_OPERAND_PABITS :
     756        value = 0;
     757        break;
     758      case IP2K_OPERAND_RETI3 :
     759        value = fields->f_reti3;
     760        break;
     761      case IP2K_OPERAND_ZBIT :
     762        value = 0;
     763        break;
     764  
     765      default :
     766        /* xgettext:c-format */
     767        opcodes_error_handler
     768  	(_("internal error: unrecognized field %d while getting int operand"),
     769  	 opindex);
     770        abort ();
     771    }
     772  
     773    return value;
     774  }
     775  
     776  bfd_vma
     777  ip2k_cgen_get_vma_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     778  			     int opindex,
     779  			     const CGEN_FIELDS * fields)
     780  {
     781    bfd_vma value;
     782  
     783    switch (opindex)
     784      {
     785      case IP2K_OPERAND_ADDR16CJP :
     786        value = fields->f_addr16cjp;
     787        break;
     788      case IP2K_OPERAND_ADDR16H :
     789        value = fields->f_imm8;
     790        break;
     791      case IP2K_OPERAND_ADDR16L :
     792        value = fields->f_imm8;
     793        break;
     794      case IP2K_OPERAND_ADDR16P :
     795        value = fields->f_page3;
     796        break;
     797      case IP2K_OPERAND_BITNO :
     798        value = fields->f_bitno;
     799        break;
     800      case IP2K_OPERAND_CBIT :
     801        value = 0;
     802        break;
     803      case IP2K_OPERAND_DCBIT :
     804        value = 0;
     805        break;
     806      case IP2K_OPERAND_FR :
     807        value = fields->f_reg;
     808        break;
     809      case IP2K_OPERAND_LIT8 :
     810        value = fields->f_imm8;
     811        break;
     812      case IP2K_OPERAND_PABITS :
     813        value = 0;
     814        break;
     815      case IP2K_OPERAND_RETI3 :
     816        value = fields->f_reti3;
     817        break;
     818      case IP2K_OPERAND_ZBIT :
     819        value = 0;
     820        break;
     821  
     822      default :
     823        /* xgettext:c-format */
     824        opcodes_error_handler
     825  	(_("internal error: unrecognized field %d while getting vma operand"),
     826  	 opindex);
     827        abort ();
     828    }
     829  
     830    return value;
     831  }
     832  
     833  void ip2k_cgen_set_int_operand  (CGEN_CPU_DESC, int, CGEN_FIELDS *, int);
     834  void ip2k_cgen_set_vma_operand  (CGEN_CPU_DESC, int, CGEN_FIELDS *, bfd_vma);
     835  
     836  /* Stuffing values in cgen_fields is handled by a collection of functions.
     837     They are distinguished by the type of the VALUE argument they accept.
     838     TODO: floating point, inlining support, remove cases where argument type
     839     not appropriate.  */
     840  
     841  void
     842  ip2k_cgen_set_int_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     843  			     int opindex,
     844  			     CGEN_FIELDS * fields,
     845  			     int value)
     846  {
     847    switch (opindex)
     848      {
     849      case IP2K_OPERAND_ADDR16CJP :
     850        fields->f_addr16cjp = value;
     851        break;
     852      case IP2K_OPERAND_ADDR16H :
     853        fields->f_imm8 = value;
     854        break;
     855      case IP2K_OPERAND_ADDR16L :
     856        fields->f_imm8 = value;
     857        break;
     858      case IP2K_OPERAND_ADDR16P :
     859        fields->f_page3 = value;
     860        break;
     861      case IP2K_OPERAND_BITNO :
     862        fields->f_bitno = value;
     863        break;
     864      case IP2K_OPERAND_CBIT :
     865        break;
     866      case IP2K_OPERAND_DCBIT :
     867        break;
     868      case IP2K_OPERAND_FR :
     869        fields->f_reg = value;
     870        break;
     871      case IP2K_OPERAND_LIT8 :
     872        fields->f_imm8 = value;
     873        break;
     874      case IP2K_OPERAND_PABITS :
     875        break;
     876      case IP2K_OPERAND_RETI3 :
     877        fields->f_reti3 = value;
     878        break;
     879      case IP2K_OPERAND_ZBIT :
     880        break;
     881  
     882      default :
     883        /* xgettext:c-format */
     884        opcodes_error_handler
     885  	(_("internal error: unrecognized field %d while setting int operand"),
     886  	 opindex);
     887        abort ();
     888    }
     889  }
     890  
     891  void
     892  ip2k_cgen_set_vma_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
     893  			     int opindex,
     894  			     CGEN_FIELDS * fields,
     895  			     bfd_vma value)
     896  {
     897    switch (opindex)
     898      {
     899      case IP2K_OPERAND_ADDR16CJP :
     900        fields->f_addr16cjp = value;
     901        break;
     902      case IP2K_OPERAND_ADDR16H :
     903        fields->f_imm8 = value;
     904        break;
     905      case IP2K_OPERAND_ADDR16L :
     906        fields->f_imm8 = value;
     907        break;
     908      case IP2K_OPERAND_ADDR16P :
     909        fields->f_page3 = value;
     910        break;
     911      case IP2K_OPERAND_BITNO :
     912        fields->f_bitno = value;
     913        break;
     914      case IP2K_OPERAND_CBIT :
     915        break;
     916      case IP2K_OPERAND_DCBIT :
     917        break;
     918      case IP2K_OPERAND_FR :
     919        fields->f_reg = value;
     920        break;
     921      case IP2K_OPERAND_LIT8 :
     922        fields->f_imm8 = value;
     923        break;
     924      case IP2K_OPERAND_PABITS :
     925        break;
     926      case IP2K_OPERAND_RETI3 :
     927        fields->f_reti3 = value;
     928        break;
     929      case IP2K_OPERAND_ZBIT :
     930        break;
     931  
     932      default :
     933        /* xgettext:c-format */
     934        opcodes_error_handler
     935  	(_("internal error: unrecognized field %d while setting vma operand"),
     936  	 opindex);
     937        abort ();
     938    }
     939  }
     940  
     941  /* Function to call before using the instruction builder tables.  */
     942  
     943  void
     944  ip2k_cgen_init_ibld_table (CGEN_CPU_DESC cd)
     945  {
     946    cd->insert_handlers = & ip2k_cgen_insert_handlers[0];
     947    cd->extract_handlers = & ip2k_cgen_extract_handlers[0];
     948  
     949    cd->insert_operand = ip2k_cgen_insert_operand;
     950    cd->extract_operand = ip2k_cgen_extract_operand;
     951  
     952    cd->get_int_operand = ip2k_cgen_get_int_operand;
     953    cd->set_int_operand = ip2k_cgen_set_int_operand;
     954    cd->get_vma_operand = ip2k_cgen_get_vma_operand;
     955    cd->set_vma_operand = ip2k_cgen_set_vma_operand;
     956  }