Back to index

cell-binutils  2.17cvs20070401
tc-crx.c
Go to the documentation of this file.
00001 /* tc-crx.c -- Assembler code for the CRX CPU core.
00002    Copyright 2004 Free Software Foundation, Inc.
00003 
00004    Contributed by Tomer Levi, NSC, Israel.
00005    Originally written for GAS 2.12 by Tomer Levi, NSC, Israel.
00006    Updates, BFDizing, GNUifying and ELF support by Tomer Levi.
00007 
00008    This file is part of GAS, the GNU Assembler.
00009 
00010    GAS is free software; you can redistribute it and/or modify
00011    it under the terms of the GNU General Public License as published by
00012    the Free Software Foundation; either version 2, or (at your option)
00013    any later version.
00014 
00015    GAS is distributed in the hope that it will be useful,
00016    but WITHOUT ANY WARRANTY; without even the implied warranty of
00017    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018    GNU General Public License for more details.
00019 
00020    You should have received a copy of the GNU General Public License
00021    along with GAS; see the file COPYING.  If not, write to the
00022    Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
00023    MA 02110-1301, USA.  */
00024 
00025 #include "as.h"
00026 #include "safe-ctype.h"
00027 #include "dwarf2dbg.h"
00028 #include "opcode/crx.h"
00029 #include "elf/crx.h"
00030 
00031 /* Word is considered here as a 16-bit unsigned short int.  */
00032 #define WORD_SHIFT  16
00033 
00034 /* Register is 4-bit size.  */
00035 #define REG_SIZE   4
00036 
00037 /* Maximum size of a single instruction (in words).  */
00038 #define INSN_MAX_SIZE   3
00039 
00040 /* Maximum bits which may be set in a `mask16' operand.  */
00041 #define MAX_REGS_IN_MASK16  8
00042 
00043 /* Utility macros for string comparison.  */
00044 #define streq(a, b)           (strcmp (a, b) == 0)
00045 #define strneq(a, b, c)       (strncmp (a, b, c) == 0)
00046 
00047 /* Assign a number NUM, shifted by SHIFT bytes, into a location
00048    pointed by index BYTE of array 'output_opcode'.  */
00049 #define CRX_PRINT(BYTE, NUM, SHIFT)   output_opcode[BYTE] |= (NUM << SHIFT)
00050 
00051 /* Operand errors.  */
00052 typedef enum
00053   {
00054     OP_LEGAL = 0,    /* Legal operand.  */
00055     OP_OUT_OF_RANGE, /* Operand not within permitted range.  */
00056     OP_NOT_EVEN,     /* Operand is Odd number, should be even.  */
00057     OP_ILLEGAL_DISPU4,      /* Operand is not within DISPU4 range.  */
00058     OP_ILLEGAL_CST4, /* Operand is not within CST4 range.  */
00059     OP_NOT_UPPER_64KB       /* Operand is not within the upper 64KB 
00060                         (0xFFFF0000-0xFFFFFFFF).  */
00061   }
00062 op_err;
00063 
00064 /* Opcode mnemonics hash table.  */
00065 static struct hash_control *crx_inst_hash;
00066 /* CRX registers hash table.  */
00067 static struct hash_control *reg_hash;
00068 /* CRX coprocessor registers hash table.  */
00069 static struct hash_control *copreg_hash;
00070 /* Current instruction we're assembling.  */
00071 const inst *instruction;
00072 
00073 /* Global variables.  */
00074 
00075 /* Array to hold an instruction encoding.  */
00076 long output_opcode[2];
00077 
00078 /* Nonzero means a relocatable symbol.  */
00079 int relocatable;
00080 
00081 /* A copy of the original instruction (used in error messages).  */
00082 char ins_parse[MAX_INST_LEN];
00083 
00084 /* The current processed argument number.  */
00085 int cur_arg_num;
00086 
00087 /* Generic assembler global variables which must be defined by all targets.  */
00088 
00089 /* Characters which always start a comment.  */
00090 const char comment_chars[] = "#";
00091 
00092 /* Characters which start a comment at the beginning of a line.  */
00093 const char line_comment_chars[] = "#";
00094 
00095 /* This array holds machine specific line separator characters.  */
00096 const char line_separator_chars[] = ";";
00097 
00098 /* Chars that can be used to separate mant from exp in floating point nums.  */
00099 const char EXP_CHARS[] = "eE";
00100 
00101 /* Chars that mean this number is a floating point constant as in 0f12.456  */
00102 const char FLT_CHARS[] = "f'";
00103 
00104 /* Target-specific multicharacter options, not const-declared at usage.  */
00105 const char *md_shortopts = "";
00106 struct option md_longopts[] =
00107 {
00108   {NULL, no_argument, NULL, 0}
00109 };
00110 size_t md_longopts_size = sizeof (md_longopts);
00111 
00112 /* This table describes all the machine specific pseudo-ops
00113    the assembler has to support.  The fields are:
00114    *** Pseudo-op name without dot.
00115    *** Function to call to execute this pseudo-op.
00116    *** Integer arg to pass to the function.  */
00117 
00118 const pseudo_typeS md_pseudo_table[] =
00119 {
00120   /* In CRX machine, align is in bytes (not a ptwo boundary).  */
00121   {"align", s_align_bytes, 0},
00122   {0, 0, 0}
00123 };
00124 
00125 /* CRX relaxation table.  */
00126 const relax_typeS md_relax_table[] =
00127 {
00128   /* bCC  */
00129   {0xfa, -0x100, 2, 1},                   /*  8 */
00130   {0xfffe, -0x10000, 4, 2},        /* 16 */
00131   {0xfffffffe, -0xfffffffe, 6, 0}, /* 32 */
00132 
00133   /* bal  */
00134   {0xfffe, -0x10000, 4, 4},        /* 16 */
00135   {0xfffffffe, -0xfffffffe, 6, 0}, /* 32 */
00136 
00137   /* cmpbr/bcop  */
00138   {0xfe, -0x100, 4, 6},                   /*  8 */
00139   {0xfffffe, -0x1000000, 6, 0}            /* 24 */
00140 };
00141 
00142 static void    reset_vars           (char *);
00143 static reg     get_register         (char *);
00144 static copreg  get_copregister             (char *);
00145 static argtype get_optype           (operand_type);
00146 static int     get_opbits           (operand_type);
00147 static int     get_opflags          (operand_type);
00148 static int     get_number_of_operands   (void);
00149 static void    parse_operand               (char *, ins *);
00150 static int     gettrap                     (char *);
00151 static void    handle_LoadStor             (char *);
00152 static int     get_cinv_parameters      (char *);
00153 static long    getconstant         (long, int);
00154 static op_err  check_range         (long *, int, unsigned int, int);
00155 static int     getreg_image         (reg);
00156 static void    parse_operands              (ins *, char *);
00157 static void    parse_insn           (ins *, char *);
00158 static void    print_operand               (int, int, argument *);
00159 static void    print_constant              (int, int, argument *);
00160 static int     exponent2scale              (int);
00161 static void    mask_reg                    (int, unsigned short *);
00162 static void    process_label_constant   (char *, ins *);
00163 static void    set_operand          (char *, ins *);
00164 static char *  preprocess_reglist       (char *, int *);
00165 static int     assemble_insn               (char *, ins *);
00166 static void    print_insn           (ins *);
00167 static void    warn_if_needed             (ins *);
00168 static int     adjust_if_needed           (ins *);
00169 
00170 /* Return the bit size for a given operand.  */
00171 
00172 static int
00173 get_opbits (operand_type op)
00174 {
00175   if (op < MAX_OPRD)
00176     return crx_optab[op].bit_size;
00177   else
00178     return 0;
00179 }
00180 
00181 /* Return the argument type of a given operand.  */
00182 
00183 static argtype
00184 get_optype (operand_type op)
00185 {
00186   if (op < MAX_OPRD)
00187     return crx_optab[op].arg_type;
00188   else
00189     return nullargs;
00190 }
00191 
00192 /* Return the flags of a given operand.  */
00193 
00194 static int
00195 get_opflags (operand_type op)
00196 {
00197   if (op < MAX_OPRD)
00198     return crx_optab[op].flags;
00199   else
00200     return 0;
00201 }
00202 
00203 /* Get the core processor register 'reg_name'.  */
00204 
00205 static reg
00206 get_register (char *reg_name)
00207 {
00208   const reg_entry *reg;
00209 
00210   reg = (const reg_entry *) hash_find (reg_hash, reg_name);
00211 
00212   if (reg != NULL)
00213     return reg->value.reg_val;
00214   else
00215     return nullregister;
00216 }
00217 
00218 /* Get the coprocessor register 'copreg_name'.  */
00219 
00220 static copreg
00221 get_copregister (char *copreg_name)
00222 {
00223   const reg_entry *copreg;
00224 
00225   copreg = (const reg_entry *) hash_find (copreg_hash, copreg_name);
00226 
00227   if (copreg != NULL)
00228     return copreg->value.copreg_val;
00229   else
00230     return nullcopregister;
00231 }
00232 
00233 /* Round up a section size to the appropriate boundary.  */
00234 
00235 valueT
00236 md_section_align (segT seg, valueT val)
00237 {
00238   /* Round .text section to a multiple of 2.  */
00239   if (seg == text_section)
00240     return (val + 1) & ~1;
00241   return val;
00242 }
00243 
00244 /* Parse an operand that is machine-specific (remove '*').  */
00245 
00246 void
00247 md_operand (expressionS * exp)
00248 {
00249   char c = *input_line_pointer;
00250 
00251   switch (c)
00252     {
00253     case '*':
00254       input_line_pointer++;
00255       expression (exp);
00256       break;
00257     default:
00258       break;
00259     }
00260 }
00261 
00262 /* Reset global variables before parsing a new instruction.  */
00263 
00264 static void
00265 reset_vars (char *op)
00266 {
00267   cur_arg_num = relocatable = 0;
00268   memset (& output_opcode, '\0', sizeof (output_opcode));
00269 
00270   /* Save a copy of the original OP (used in error messages).  */
00271   strncpy (ins_parse, op, sizeof ins_parse - 1);
00272   ins_parse [sizeof ins_parse - 1] = 0;
00273 }
00274 
00275 /* This macro decides whether a particular reloc is an entry in a
00276    switch table.  It is used when relaxing, because the linker needs
00277    to know about all such entries so that it can adjust them if
00278    necessary.  */
00279 
00280 #define SWITCH_TABLE(fix)                          \
00281   (   (fix)->fx_addsy != NULL                             \
00282    && (fix)->fx_subsy != NULL                             \
00283    && S_GET_SEGMENT ((fix)->fx_addsy) ==           \
00284       S_GET_SEGMENT ((fix)->fx_subsy)                     \
00285    && S_GET_SEGMENT (fix->fx_addsy) != undefined_section  \
00286    && (   (fix)->fx_r_type == BFD_RELOC_CRX_NUM8   \
00287        || (fix)->fx_r_type == BFD_RELOC_CRX_NUM16         \
00288        || (fix)->fx_r_type == BFD_RELOC_CRX_NUM32))
00289 
00290 /* See whether we need to force a relocation into the output file.
00291    This is used to force out switch and PC relative relocations when
00292    relaxing.  */
00293 
00294 int
00295 crx_force_relocation (fixS *fix)
00296 {
00297   if (generic_force_reloc (fix) || SWITCH_TABLE (fix))
00298     return 1;
00299 
00300   return 0;
00301 }
00302 
00303 /* Generate a relocation entry for a fixup.  */
00304 
00305 arelent *
00306 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS * fixP)
00307 {
00308   arelent * reloc;
00309 
00310   reloc = xmalloc (sizeof (arelent));
00311   reloc->sym_ptr_ptr  = xmalloc (sizeof (asymbol *));
00312   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
00313   reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
00314   reloc->addend = fixP->fx_offset;
00315 
00316   if (fixP->fx_subsy != NULL)
00317     {
00318       if (SWITCH_TABLE (fixP))
00319        {
00320          /* Keep the current difference in the addend.  */
00321          reloc->addend = (S_GET_VALUE (fixP->fx_addsy)
00322                         - S_GET_VALUE (fixP->fx_subsy) + fixP->fx_offset);
00323 
00324          switch (fixP->fx_r_type)
00325            {
00326            case BFD_RELOC_CRX_NUM8:
00327              fixP->fx_r_type = BFD_RELOC_CRX_SWITCH8;
00328              break;
00329            case BFD_RELOC_CRX_NUM16:
00330              fixP->fx_r_type = BFD_RELOC_CRX_SWITCH16;
00331              break;
00332            case BFD_RELOC_CRX_NUM32:
00333              fixP->fx_r_type = BFD_RELOC_CRX_SWITCH32;
00334              break;
00335            default:
00336              abort ();
00337              break;
00338            }
00339        }
00340       else
00341        {
00342          /* We only resolve difference expressions in the same section.  */
00343          as_bad_where (fixP->fx_file, fixP->fx_line,
00344                      _("can't resolve `%s' {%s section} - `%s' {%s section}"),
00345                      fixP->fx_addsy ? S_GET_NAME (fixP->fx_addsy) : "0",
00346                      segment_name (fixP->fx_addsy
00347                                   ? S_GET_SEGMENT (fixP->fx_addsy)
00348                                   : absolute_section),
00349                      S_GET_NAME (fixP->fx_subsy),
00350                      segment_name (S_GET_SEGMENT (fixP->fx_addsy)));
00351        }
00352     }
00353 
00354   assert ((int) fixP->fx_r_type > 0);
00355   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
00356 
00357   if (reloc->howto == (reloc_howto_type *) NULL)
00358     {
00359       as_bad_where (fixP->fx_file, fixP->fx_line,
00360                   _("internal error: reloc %d (`%s') not supported by object file format"),
00361                   fixP->fx_r_type,
00362                   bfd_get_reloc_code_name (fixP->fx_r_type));
00363       return NULL;
00364     }
00365   assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
00366 
00367   return reloc;
00368 }
00369 
00370 /* Prepare machine-dependent frags for relaxation.  */
00371 
00372 int
00373 md_estimate_size_before_relax (fragS *fragp, asection *seg)
00374 {
00375   /* If symbol is undefined or located in a different section,
00376      select the largest supported relocation.  */
00377   relax_substateT subtype;
00378   relax_substateT rlx_state[] = {0, 2,
00379                              3, 4,
00380                              5, 6};
00381 
00382   for (subtype = 0; subtype < ARRAY_SIZE (rlx_state); subtype += 2)
00383     {
00384       if (fragp->fr_subtype == rlx_state[subtype]
00385          && (!S_IS_DEFINED (fragp->fr_symbol)
00386              || seg != S_GET_SEGMENT (fragp->fr_symbol)))
00387        {
00388          fragp->fr_subtype = rlx_state[subtype + 1];
00389          break;
00390        }
00391     }
00392 
00393   if (fragp->fr_subtype >= ARRAY_SIZE (md_relax_table))
00394     abort ();
00395 
00396   return md_relax_table[fragp->fr_subtype].rlx_length;
00397 }
00398 
00399 void
00400 md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, fragS *fragP)
00401 {
00402   /* 'opcode' points to the start of the instruction, whether
00403      we need to change the instruction's fixed encoding.  */
00404   char *opcode = fragP->fr_literal + fragP->fr_fix;
00405   bfd_reloc_code_real_type reloc;
00406 
00407   subseg_change (sec, 0);
00408 
00409   switch (fragP->fr_subtype)
00410     {
00411     case 0:
00412       reloc = BFD_RELOC_CRX_REL8;
00413       break;
00414     case 1:
00415       *opcode = 0x7e;
00416       reloc = BFD_RELOC_CRX_REL16;
00417       break;
00418     case 2:
00419       *opcode = 0x7f;
00420       reloc = BFD_RELOC_CRX_REL32;
00421       break;
00422     case 3:
00423       reloc = BFD_RELOC_CRX_REL16;
00424       break;
00425     case 4:
00426       *++opcode = 0x31;
00427       reloc = BFD_RELOC_CRX_REL32;
00428       break;
00429     case 5:
00430       reloc = BFD_RELOC_CRX_REL8_CMP;
00431       break;
00432     case 6:
00433       *++opcode = 0x31;
00434       reloc = BFD_RELOC_CRX_REL24;
00435       break;
00436     default:
00437       abort ();
00438       break;
00439     }
00440 
00441     fix_new (fragP, fragP->fr_fix,
00442             bfd_get_reloc_size (bfd_reloc_type_lookup (stdoutput, reloc)),
00443             fragP->fr_symbol, fragP->fr_offset, 1, reloc);
00444     fragP->fr_var = 0;
00445     fragP->fr_fix += md_relax_table[fragP->fr_subtype].rlx_length;
00446 }
00447 
00448 /* Process machine-dependent command line options.  Called once for
00449    each option on the command line that the machine-independent part of
00450    GAS does not understand.  */
00451 
00452 int
00453 md_parse_option (int c ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED)
00454 {
00455   return 0;
00456 }
00457 
00458 /* Machine-dependent usage-output.  */
00459 
00460 void
00461 md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
00462 {
00463   return;
00464 }
00465 
00466 /* Turn a string in input_line_pointer into a floating point constant
00467    of type TYPE, and store the appropriate bytes in *LITP.  The number
00468    of LITTLENUMS emitted is stored in *SIZEP.  An error message is
00469    returned, or NULL on OK.  */
00470 
00471 char *
00472 md_atof (int type, char *litP, int *sizeP)
00473 {
00474   int prec;
00475   LITTLENUM_TYPE words[4];
00476   char *t;
00477   int i;
00478 
00479   switch (type)
00480     {
00481     case 'f':
00482       prec = 2;
00483       break;
00484 
00485     case 'd':
00486       prec = 4;
00487       break;
00488 
00489     default:
00490       *sizeP = 0;
00491       return _("bad call to md_atof");
00492     }
00493 
00494   t = atof_ieee (input_line_pointer, type, words);
00495   if (t)
00496     input_line_pointer = t;
00497 
00498   *sizeP = prec * 2;
00499 
00500   if (! target_big_endian)
00501     {
00502       for (i = prec - 1; i >= 0; i--)
00503        {
00504          md_number_to_chars (litP, (valueT) words[i], 2);
00505          litP += 2;
00506        }
00507     }
00508   else
00509     {
00510       for (i = 0; i < prec; i++)
00511        {
00512          md_number_to_chars (litP, (valueT) words[i], 2);
00513          litP += 2;
00514        }
00515     }
00516 
00517   return NULL;
00518 }
00519 
00520 /* Apply a fixS (fixup of an instruction or data that we didn't have
00521    enough info to complete immediately) to the data in a frag.
00522    Since linkrelax is nonzero and TC_LINKRELAX_FIXUP is defined to disable
00523    relaxation of debug sections, this function is called only when
00524    fixuping relocations of debug sections.  */
00525 
00526 void
00527 md_apply_fix (fixS *fixP, valueT *valP, segT seg)
00528 {
00529   valueT val = * valP;
00530   char *buf = fixP->fx_frag->fr_literal + fixP->fx_where;
00531   fixP->fx_offset = 0;
00532 
00533   switch (fixP->fx_r_type)
00534     {
00535     case BFD_RELOC_CRX_NUM8:
00536       bfd_put_8 (stdoutput, (unsigned char) val, buf);
00537       break;
00538     case BFD_RELOC_CRX_NUM16:
00539       bfd_put_16 (stdoutput, val, buf);
00540       break;
00541     case BFD_RELOC_CRX_NUM32:
00542       bfd_put_32 (stdoutput, val, buf);
00543       break;
00544     default:
00545       /* We shouldn't ever get here because linkrelax is nonzero.  */
00546       abort ();
00547       break;
00548     }
00549 
00550   fixP->fx_done = 0;
00551 
00552   if (fixP->fx_addsy == NULL
00553       && fixP->fx_pcrel == 0)
00554     fixP->fx_done = 1;
00555 
00556   if (fixP->fx_pcrel == 1
00557       && fixP->fx_addsy != NULL
00558       && S_GET_SEGMENT (fixP->fx_addsy) == seg)
00559     fixP->fx_done = 1;
00560 }
00561 
00562 /* The location from which a PC relative jump should be calculated,
00563    given a PC relative reloc.  */
00564 
00565 long
00566 md_pcrel_from (fixS *fixp)
00567 {
00568   return fixp->fx_frag->fr_address + fixp->fx_where;
00569 }
00570 
00571 /* This function is called once, at assembler startup time.  This should
00572    set up all the tables, etc that the MD part of the assembler needs.  */
00573 
00574 void
00575 md_begin (void)
00576 {
00577   const char *hashret = NULL;
00578   int i = 0;
00579 
00580   /* Set up a hash table for the instructions.  */
00581   if ((crx_inst_hash = hash_new ()) == NULL)
00582     as_fatal (_("Virtual memory exhausted"));
00583   
00584   while (crx_instruction[i].mnemonic != NULL)
00585     {
00586       const char *mnemonic = crx_instruction[i].mnemonic;
00587 
00588       hashret = hash_insert (crx_inst_hash, mnemonic,
00589        (PTR) &crx_instruction[i]);
00590 
00591       if (hashret != NULL && *hashret != '\0')
00592        as_fatal (_("Can't hash `%s': %s\n"), crx_instruction[i].mnemonic,
00593                 *hashret == 0 ? _("(unknown reason)") : hashret);
00594 
00595       /* Insert unique names into hash table.  The CRX instruction set
00596         has many identical opcode names that have different opcodes based
00597         on the operands.  This hash table then provides a quick index to
00598         the first opcode with a particular name in the opcode table.  */
00599       do
00600        {
00601          ++i;
00602        }
00603       while (crx_instruction[i].mnemonic != NULL
00604             && streq (crx_instruction[i].mnemonic, mnemonic));
00605     }
00606 
00607   /* Initialize reg_hash hash table.  */
00608   if ((reg_hash = hash_new ()) == NULL)
00609     as_fatal (_("Virtual memory exhausted"));
00610 
00611   {
00612     const reg_entry *regtab;
00613 
00614     for (regtab = crx_regtab;
00615         regtab < (crx_regtab + NUMREGS); regtab++)
00616       {
00617        hashret = hash_insert (reg_hash, regtab->name, (PTR) regtab);
00618        if (hashret)
00619          as_fatal (_("Internal Error:  Can't hash %s: %s"),
00620                   regtab->name,
00621                   hashret);
00622       }
00623   }
00624 
00625   /* Initialize copreg_hash hash table.  */
00626   if ((copreg_hash = hash_new ()) == NULL)
00627     as_fatal (_("Virtual memory exhausted"));
00628 
00629   {
00630     const reg_entry *copregtab;
00631 
00632     for (copregtab = crx_copregtab; copregtab < (crx_copregtab + NUMCOPREGS);
00633         copregtab++)
00634       {
00635        hashret = hash_insert (copreg_hash, copregtab->name, (PTR) copregtab);
00636        if (hashret)
00637          as_fatal (_("Internal Error:  Can't hash %s: %s"),
00638                   copregtab->name,
00639                   hashret);
00640       }
00641   }
00642   /*  Set linkrelax here to avoid fixups in most sections.  */
00643   linkrelax = 1;
00644 }
00645 
00646 /* Process constants (immediate/absolute) 
00647    and labels (jump targets/Memory locations).  */
00648 
00649 static void
00650 process_label_constant (char *str, ins * crx_ins)
00651 {
00652   char *saved_input_line_pointer;
00653   argument *cur_arg = &crx_ins->arg[cur_arg_num];  /* Current argument.  */
00654 
00655   saved_input_line_pointer = input_line_pointer;
00656   input_line_pointer = str;
00657 
00658   expression (&crx_ins->exp);
00659   
00660   switch (crx_ins->exp.X_op)
00661     {
00662     case O_big:
00663     case O_absent:
00664       /* Missing or bad expr becomes absolute 0.  */
00665       as_bad (_("missing or invalid displacement expression `%s' taken as 0"),
00666              str);
00667       crx_ins->exp.X_op = O_constant;
00668       crx_ins->exp.X_add_number = 0;
00669       crx_ins->exp.X_add_symbol = (symbolS *) 0;
00670       crx_ins->exp.X_op_symbol = (symbolS *) 0;
00671       /* Fall through.  */
00672 
00673     case O_constant:
00674       cur_arg->X_op = O_constant;
00675       cur_arg->constant = crx_ins->exp.X_add_number;
00676       break;
00677 
00678     case O_symbol:
00679     case O_subtract:
00680     case O_add:
00681       cur_arg->X_op = O_symbol;
00682       crx_ins->rtype = BFD_RELOC_NONE;
00683       relocatable = 1;
00684 
00685       switch (cur_arg->type)
00686        {
00687        case arg_cr:
00688           if (IS_INSN_TYPE (LD_STOR_INS_INC))
00689            crx_ins->rtype = BFD_RELOC_CRX_REGREL12;
00690           else if (IS_INSN_TYPE (CSTBIT_INS)
00691                  || IS_INSN_TYPE (STOR_IMM_INS))
00692            crx_ins->rtype = BFD_RELOC_CRX_REGREL28;
00693           else
00694            crx_ins->rtype = BFD_RELOC_CRX_REGREL32;
00695          break;
00696 
00697        case arg_idxr:
00698            crx_ins->rtype = BFD_RELOC_CRX_REGREL22;
00699          break;
00700        
00701        case arg_c:
00702           if (IS_INSN_MNEMONIC ("bal") || IS_INSN_TYPE (DCR_BRANCH_INS))
00703            crx_ins->rtype = BFD_RELOC_CRX_REL16;
00704          else if (IS_INSN_TYPE (BRANCH_INS))
00705            crx_ins->rtype = BFD_RELOC_CRX_REL8;
00706           else if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (STOR_IMM_INS)
00707                  || IS_INSN_TYPE (CSTBIT_INS))
00708            crx_ins->rtype = BFD_RELOC_CRX_ABS32;
00709          else if (IS_INSN_TYPE (BRANCH_NEQ_INS))
00710            crx_ins->rtype = BFD_RELOC_CRX_REL4;
00711           else if (IS_INSN_TYPE (CMPBR_INS) || IS_INSN_TYPE (COP_BRANCH_INS))
00712            crx_ins->rtype = BFD_RELOC_CRX_REL8_CMP;
00713          break;
00714        
00715        case arg_ic:
00716           if (IS_INSN_TYPE (ARITH_INS))
00717            crx_ins->rtype = BFD_RELOC_CRX_IMM32;
00718          else if (IS_INSN_TYPE (ARITH_BYTE_INS))
00719            crx_ins->rtype = BFD_RELOC_CRX_IMM16;
00720          break;
00721        default:
00722          break;
00723       }
00724       break;
00725 
00726     default:
00727       cur_arg->X_op = crx_ins->exp.X_op;
00728       break;
00729     }
00730 
00731   input_line_pointer = saved_input_line_pointer;
00732   return;
00733 }
00734 
00735 /* Get the values of the scale to be encoded -
00736    used for the scaled index mode of addressing.  */
00737 
00738 static int
00739 exponent2scale (int val)
00740 {
00741   int exponent;
00742 
00743   /* If 'val' is 0, the following 'for' will be an endless loop.  */
00744   if (val == 0)
00745     return 0;
00746 
00747   for (exponent = 0; (val != 1); val >>= 1, exponent++)
00748     ;
00749 
00750   return exponent;
00751 }
00752 
00753 /* Parsing different types of operands
00754    -> constants                 Immediate/Absolute/Relative numbers
00755    -> Labels             Relocatable symbols
00756    -> (rbase)            Register base
00757    -> disp(rbase)        Register relative
00758    -> disp(rbase)+       Post-increment mode
00759    -> disp(rbase,ridx,scl)  Register index mode  */
00760 
00761 static void
00762 set_operand (char *operand, ins * crx_ins)
00763 {
00764   char *operandS; /* Pointer to start of sub-opearand.  */
00765   char *operandE; /* Pointer to end of sub-opearand.  */
00766   expressionS scale;
00767   int scale_val;
00768   char *input_save, c;
00769   argument *cur_arg = &crx_ins->arg[cur_arg_num]; /* Current argument.  */
00770 
00771   /* Initialize pointers.  */
00772   operandS = operandE = operand;
00773 
00774   switch (cur_arg->type)
00775     {
00776     case arg_sc:    /* Case *+0x18.  */
00777     case arg_ic:    /* Case $0x18.  */
00778       operandS++;
00779     case arg_c:          /* Case 0x18.  */
00780       /* Set constant.  */
00781       process_label_constant (operandS, crx_ins);
00782       
00783       if (cur_arg->type != arg_ic)
00784        cur_arg->type = arg_c;
00785       break;
00786 
00787     case arg_icr:   /* Case $0x18(r1).  */
00788       operandS++;
00789     case arg_cr:    /* Case 0x18(r1).   */
00790       /* Set displacement constant.  */
00791       while (*operandE != '(')
00792        operandE++;
00793       *operandE = '\0';
00794       process_label_constant (operandS, crx_ins);
00795       operandS = operandE;    
00796     case arg_rbase: /* Case (r1).  */
00797       operandS++;
00798       /* Set register base.  */
00799       while (*operandE != ')')
00800        operandE++;
00801       *operandE = '\0';
00802       if ((cur_arg->r = get_register (operandS)) == nullregister)
00803        as_bad (_("Illegal register `%s' in Instruction `%s'"),
00804               operandS, ins_parse);
00805 
00806       if (cur_arg->type != arg_rbase)
00807        cur_arg->type = arg_cr;
00808       break;
00809 
00810     case arg_idxr:
00811       /* Set displacement constant.  */
00812       while (*operandE != '(')
00813        operandE++;
00814       *operandE = '\0';
00815       process_label_constant (operandS, crx_ins);
00816       operandS = ++operandE;
00817       
00818       /* Set register base.  */
00819       while ((*operandE != ',') && (! ISSPACE (*operandE)))
00820        operandE++;
00821       *operandE++ = '\0';
00822       if ((cur_arg->r = get_register (operandS)) == nullregister)
00823        as_bad (_("Illegal register `%s' in Instruction `%s'"),
00824               operandS, ins_parse);
00825 
00826       /* Skip leading white space.  */
00827       while (ISSPACE (*operandE))
00828        operandE++;
00829       operandS = operandE;
00830 
00831       /* Set register index.  */
00832       while ((*operandE != ')') && (*operandE != ','))
00833        operandE++;
00834       c = *operandE;
00835       *operandE++ = '\0';
00836 
00837       if ((cur_arg->i_r = get_register (operandS)) == nullregister)
00838        as_bad (_("Illegal register `%s' in Instruction `%s'"),
00839               operandS, ins_parse);
00840 
00841       /* Skip leading white space.  */
00842       while (ISSPACE (*operandE))
00843        operandE++;
00844       operandS = operandE;
00845 
00846       /* Set the scale.  */
00847       if (c == ')')
00848        cur_arg->scale = 0;
00849       else
00850         {
00851          while (*operandE != ')')
00852            operandE++;
00853          *operandE = '\0';
00854 
00855          /* Preprocess the scale string.  */
00856          input_save = input_line_pointer;
00857          input_line_pointer = operandS;
00858          expression (&scale);
00859          input_line_pointer = input_save;
00860 
00861          scale_val = scale.X_add_number;
00862 
00863          /* Check if the scale value is legal.  */
00864           if (scale_val != 1 && scale_val != 2
00865               && scale_val != 4 && scale_val != 8)
00866            as_bad (_("Illegal Scale - `%d'"), scale_val);
00867 
00868          cur_arg->scale = exponent2scale (scale_val);
00869         }
00870       break;
00871 
00872     default:
00873       break;
00874     }
00875 }
00876 
00877 /* Parse a single operand.
00878    operand - Current operand to parse.
00879    crx_ins - Current assembled instruction.  */
00880 
00881 static void
00882 parse_operand (char *operand, ins * crx_ins)
00883 {
00884   int ret_val;
00885   argument *cur_arg = &crx_ins->arg[cur_arg_num]; /* Current argument.  */
00886 
00887   /* Initialize the type to NULL before parsing.  */
00888   cur_arg->type = nullargs;
00889 
00890   /* Check whether this is a general processor register.  */
00891   if ((ret_val = get_register (operand)) != nullregister)
00892     {
00893       cur_arg->type = arg_r;
00894       cur_arg->r = ret_val;
00895       cur_arg->X_op = O_register;
00896       return;
00897     }
00898 
00899   /* Check whether this is a core [special] coprocessor register.  */
00900   if ((ret_val = get_copregister (operand)) != nullcopregister)
00901     {
00902       cur_arg->type = arg_copr;
00903       if (ret_val >= cs0)
00904        cur_arg->type = arg_copsr;
00905       cur_arg->cr = ret_val;
00906       cur_arg->X_op = O_register;
00907       return;
00908     }
00909 
00910   /* Deal with special characters.  */
00911   switch (operand[0])
00912     {
00913     case '$':
00914       if (strchr (operand, '(') != NULL)
00915        cur_arg->type = arg_icr;
00916       else
00917         cur_arg->type = arg_ic;
00918       goto set_params;
00919       break;
00920 
00921     case '*':
00922       cur_arg->type = arg_sc;
00923       goto set_params;
00924       break;
00925 
00926     case '(':
00927       cur_arg->type = arg_rbase;
00928       goto set_params;
00929       break;
00930 
00931     default:
00932        break;
00933     }
00934       
00935   if (strchr (operand, '(') != NULL)
00936     {
00937       if (strchr (operand, ',') != NULL
00938           && (strchr (operand, ',') > strchr (operand, '(')))
00939            cur_arg->type = arg_idxr;
00940       else
00941        cur_arg->type = arg_cr;
00942     }
00943   else
00944     cur_arg->type = arg_c;
00945   goto set_params;
00946 
00947 /* Parse an operand according to its type.  */
00948 set_params:
00949   cur_arg->constant = 0;
00950   set_operand (operand, crx_ins);
00951 }
00952 
00953 /* Parse the various operands. Each operand is then analyzed to fillup 
00954    the fields in the crx_ins data structure.  */
00955 
00956 static void
00957 parse_operands (ins * crx_ins, char *operands)
00958 {
00959   char *operandS;           /* Operands string.  */
00960   char *operandH, *operandT;   /* Single operand head/tail pointers.  */
00961   int allocated = 0;        /* Indicates a new operands string was allocated.  */
00962   char *operand[MAX_OPERANDS]; /* Separating the operands.  */
00963   int op_num = 0;           /* Current operand number we are parsing.  */
00964   int bracket_flag = 0;            /* Indicates a bracket '(' was found.  */
00965   int sq_bracket_flag = 0;     /* Indicates a square bracket '[' was found.  */
00966 
00967   /* Preprocess the list of registers, if necessary.  */
00968   operandS = operandH = operandT = (INST_HAS_REG_LIST) ?
00969     preprocess_reglist (operands, &allocated) : operands;
00970 
00971   while (*operandT != '\0')
00972     {
00973       if (*operandT == ',' && bracket_flag != 1 && sq_bracket_flag != 1)
00974         {
00975          *operandT++ = '\0';
00976          operand[op_num++] = strdup (operandH);
00977           operandH = operandT;
00978           continue;
00979         }
00980 
00981       if (*operandT == ' ')
00982        as_bad (_("Illegal operands (whitespace): `%s'"), ins_parse);
00983 
00984       if (*operandT == '(')
00985        bracket_flag = 1;
00986       else if (*operandT == '[')
00987        sq_bracket_flag = 1;
00988 
00989       if (*operandT == ')')
00990        {
00991          if (bracket_flag)
00992            bracket_flag = 0;
00993          else
00994            as_fatal (_("Missing matching brackets : `%s'"), ins_parse);
00995        }
00996       else if (*operandT == ']')
00997        {
00998          if (sq_bracket_flag)
00999            sq_bracket_flag = 0;
01000          else
01001            as_fatal (_("Missing matching brackets : `%s'"), ins_parse);
01002        }
01003 
01004       if (bracket_flag == 1 && *operandT == ')')
01005        bracket_flag = 0;
01006       else if (sq_bracket_flag == 1 && *operandT == ']')
01007        sq_bracket_flag = 0;
01008 
01009       operandT++;
01010     }
01011 
01012   /* Adding the last operand.  */
01013   operand[op_num++] = strdup (operandH);
01014   crx_ins->nargs = op_num;
01015 
01016   /* Verifying correct syntax of operands (all brackets should be closed).  */
01017   if (bracket_flag || sq_bracket_flag)
01018     as_fatal (_("Missing matching brackets : `%s'"), ins_parse);
01019 
01020   /* Now we parse each operand separately.  */
01021   for (op_num = 0; op_num < crx_ins->nargs; op_num++)
01022     {
01023       cur_arg_num = op_num;
01024       parse_operand (operand[op_num], crx_ins);
01025       free (operand[op_num]);
01026     }
01027 
01028   if (allocated)
01029     free (operandS);
01030 }
01031 
01032 /* Get the trap index in dispatch table, given its name.
01033    This routine is used by assembling the 'excp' instruction.  */
01034 
01035 static int
01036 gettrap (char *s)
01037 {
01038   const trap_entry *trap;
01039 
01040   for (trap = crx_traps; trap < (crx_traps + NUMTRAPS); trap++)
01041     if (strcasecmp (trap->name, s) == 0)
01042       return trap->entry;
01043 
01044   as_bad (_("Unknown exception: `%s'"), s);
01045   return 0;
01046 }
01047 
01048 /* Post-Increment instructions, as well as Store-Immediate instructions, are a 
01049    sub-group within load/stor instruction groups. 
01050    Therefore, when parsing a Post-Increment/Store-Immediate insn, we have to 
01051    advance the instruction pointer to the start of that sub-group (that is, up 
01052    to the first instruction of that type).
01053    Otherwise, the insn will be mistakenly identified as of type LD_STOR_INS.  */
01054 
01055 static void
01056 handle_LoadStor (char *operands)
01057 {
01058   /* Post-Increment instructions precede Store-Immediate instructions in 
01059      CRX instruction table, hence they are handled before. 
01060      This synchronization should be kept.  */
01061 
01062   /* Assuming Post-Increment insn has the following format :
01063      'MNEMONIC DISP(REG)+, REG' (e.g. 'loadw 12(r5)+, r6').
01064      LD_STOR_INS_INC are the only store insns containing a plus sign (+).  */
01065   if (strstr (operands, ")+") != NULL)
01066     {
01067       while (! IS_INSN_TYPE (LD_STOR_INS_INC))
01068        instruction++;
01069       return;
01070     }
01071 
01072   /* Assuming Store-Immediate insn has the following format :
01073      'MNEMONIC $DISP, ...' (e.g. 'storb $1, 12(r5)').
01074      STOR_IMM_INS are the only store insns containing a dollar sign ($).  */
01075   if (strstr (operands, "$") != NULL)
01076     while (! IS_INSN_TYPE (STOR_IMM_INS))
01077       instruction++;
01078 }
01079 
01080 /* Top level module where instruction parsing starts.
01081    crx_ins - data structure holds some information.
01082    operands - holds the operands part of the whole instruction.  */
01083 
01084 static void
01085 parse_insn (ins *insn, char *operands)
01086 {
01087   int i;
01088 
01089   /* Handle instructions with no operands.  */
01090   for (i = 0; no_op_insn[i] != NULL; i++)
01091   {
01092     if (streq (no_op_insn[i], instruction->mnemonic))
01093     {
01094       insn->nargs = 0;
01095       return;
01096     }
01097   }
01098 
01099   /* Handle 'excp'/'cinv' instructions.  */
01100   if (IS_INSN_MNEMONIC ("excp") || IS_INSN_MNEMONIC ("cinv"))
01101     {
01102       insn->nargs = 1;
01103       insn->arg[0].type = arg_ic;
01104       insn->arg[0].constant = IS_INSN_MNEMONIC ("excp") ?
01105        gettrap (operands) : get_cinv_parameters (operands);
01106       insn->arg[0].X_op = O_constant;
01107       return;
01108     }
01109 
01110   /* Handle load/stor unique instructions before parsing.  */
01111   if (IS_INSN_TYPE (LD_STOR_INS))
01112     handle_LoadStor (operands);
01113 
01114   if (operands != NULL)
01115     parse_operands (insn, operands);
01116 }
01117 
01118 /* Cinv instruction requires special handling.  */
01119 
01120 static int
01121 get_cinv_parameters (char * operand)
01122 {
01123   char *p = operand;
01124   int d_used = 0, i_used = 0, u_used = 0, b_used = 0;
01125 
01126   while (*++p != ']')
01127     {
01128       if (*p == ',' || *p == ' ')
01129        continue;
01130 
01131       if (*p == 'd')
01132        d_used = 1;
01133       else if (*p == 'i')
01134        i_used = 1;
01135       else if (*p == 'u')
01136        u_used = 1;
01137       else if (*p == 'b')
01138        b_used = 1;
01139       else
01140        as_bad (_("Illegal `cinv' parameter: `%c'"), *p);
01141     }
01142 
01143   return ((b_used ? 8 : 0)
01144        + (d_used ? 4 : 0)
01145        + (i_used ? 2 : 0)
01146        + (u_used ? 1 : 0));
01147 }
01148 
01149 /* Retrieve the opcode image of a given register.
01150    If the register is illegal for the current instruction,
01151    issue an error.  */
01152 
01153 static int
01154 getreg_image (reg r)
01155 {
01156   const reg_entry *reg;
01157   char *reg_name;
01158   int is_procreg = 0; /* Nonzero means argument should be processor reg.  */
01159 
01160   if (((IS_INSN_MNEMONIC ("mtpr")) && (cur_arg_num == 1))
01161       || ((IS_INSN_MNEMONIC ("mfpr")) && (cur_arg_num == 0)) )
01162     is_procreg = 1;
01163 
01164   /* Check whether the register is in registers table.  */
01165   if (r < MAX_REG)
01166     reg = &crx_regtab[r];
01167   /* Check whether the register is in coprocessor registers table.  */
01168   else if (r < MAX_COPREG)
01169     reg = &crx_copregtab[r-MAX_REG];
01170   /* Register not found.  */
01171   else
01172     {
01173       as_bad (_("Unknown register: `%d'"), r);
01174       return 0;
01175     }
01176 
01177   reg_name = reg->name;
01178 
01179 /* Issue a error message when register is illegal.  */
01180 #define IMAGE_ERR \
01181   as_bad (_("Illegal register (`%s') in Instruction: `%s'"), \
01182            reg_name, ins_parse);                      \
01183   break;
01184 
01185   switch (reg->type)
01186   {
01187     case CRX_U_REGTYPE:
01188       if (is_procreg || (instruction->flags & USER_REG))
01189        return reg->image;
01190       else
01191        IMAGE_ERR;
01192 
01193     case CRX_CFG_REGTYPE:
01194       if (is_procreg)
01195        return reg->image;
01196       else
01197        IMAGE_ERR;
01198 
01199     case CRX_R_REGTYPE:
01200       if (! is_procreg)
01201        return reg->image;
01202       else
01203        IMAGE_ERR;
01204 
01205     case CRX_C_REGTYPE:
01206     case CRX_CS_REGTYPE:
01207       return reg->image;
01208       break;
01209 
01210     default:
01211       IMAGE_ERR;
01212   }
01213 
01214   return 0;
01215 }
01216 
01217 /* Routine used to represent integer X using NBITS bits.  */
01218 
01219 static long
01220 getconstant (long x, int nbits)
01221 {
01222   /* The following expression avoids overflow if
01223      'nbits' is the number of bits in 'bfd_vma'.  */
01224   return (x & ((((1 << (nbits - 1)) - 1) << 1) | 1));
01225 }
01226 
01227 /* Print a constant value to 'output_opcode':
01228    ARG holds the operand's type and value.
01229    SHIFT represents the location of the operand to be print into.
01230    NBITS determines the size (in bits) of the constant.  */
01231 
01232 static void
01233 print_constant (int nbits, int shift, argument *arg)
01234 {
01235   unsigned long mask = 0;
01236 
01237   long constant = getconstant (arg->constant, nbits);
01238 
01239   switch (nbits)
01240   {
01241     case 32:
01242     case 28:
01243     case 24:
01244     case 22:
01245       /* mask the upper part of the constant, that is, the bits
01246         going to the lowest byte of output_opcode[0].
01247         The upper part of output_opcode[1] is always filled,
01248         therefore it is always masked with 0xFFFF.  */
01249       mask = (1 << (nbits - 16)) - 1;
01250       /* Divide the constant between two consecutive words :
01251                0        1        2        3
01252            +---------+---------+---------+---------+
01253            |        | X X X X | X X X X |     |
01254            +---------+---------+---------+---------+
01255              output_opcode[0]    output_opcode[1]     */
01256 
01257       CRX_PRINT (0, (constant >> WORD_SHIFT) & mask, 0);
01258       CRX_PRINT (1, (constant & 0xFFFF), WORD_SHIFT);
01259       break;
01260 
01261     case 16:
01262     case 12:
01263       /* Special case - in arg_cr, the SHIFT represents the location
01264         of the REGISTER, not the constant, which is itself not shifted.  */
01265       if (arg->type == arg_cr)
01266        {
01267          CRX_PRINT (0, constant,  0);
01268          break;
01269        }
01270 
01271       /* When instruction size is 3 and 'shift' is 16, a 16-bit constant is 
01272         always filling the upper part of output_opcode[1]. If we mistakenly 
01273         write it to output_opcode[0], the constant prefix (that is, 'match')
01274         will be overridden.
01275                0        1        2        3
01276            +---------+---------+---------+---------+
01277            | 'match' |         | X X X X |           |
01278            +---------+---------+---------+---------+
01279              output_opcode[0]    output_opcode[1]     */
01280 
01281       if ((instruction->size > 2) && (shift == WORD_SHIFT))
01282        CRX_PRINT (1, constant, WORD_SHIFT);
01283       else
01284        CRX_PRINT (0, constant, shift);
01285       break;
01286 
01287     default:
01288       CRX_PRINT (0, constant,  shift);
01289       break;
01290   }
01291 }
01292 
01293 /* Print an operand to 'output_opcode', which later on will be
01294    printed to the object file:
01295    ARG holds the operand's type, size and value.
01296    SHIFT represents the printing location of operand.
01297    NBITS determines the size (in bits) of a constant operand.  */
01298 
01299 static void
01300 print_operand (int nbits, int shift, argument *arg)
01301 {
01302   switch (arg->type)
01303     {
01304     case arg_r:
01305       CRX_PRINT (0, getreg_image (arg->r), shift);
01306       break;
01307 
01308     case arg_copr:
01309       if (arg->cr < c0 || arg->cr > c15)
01310        as_bad (_("Illegal Co-processor register in Instruction `%s' "),
01311               ins_parse);
01312       CRX_PRINT (0, getreg_image (arg->cr), shift);
01313       break;
01314 
01315     case arg_copsr:
01316       if (arg->cr < cs0 || arg->cr > cs15)
01317        as_bad (_("Illegal Co-processor special register in Instruction `%s' "),
01318               ins_parse);
01319       CRX_PRINT (0, getreg_image (arg->cr), shift);
01320       break;
01321 
01322     case arg_idxr:
01323       /*    16      12            8    6         0
01324            +--------------------------------+
01325            | r_base | r_idx  | scl|  disp   |
01326            +--------------------------------+      */
01327       CRX_PRINT (0, getreg_image (arg->r), 12);
01328       CRX_PRINT (0, getreg_image (arg->i_r), 8);
01329       CRX_PRINT (0, arg->scale, 6);
01330     case arg_ic:
01331     case arg_c:
01332       print_constant (nbits, shift, arg);
01333       break;
01334 
01335     case arg_rbase:
01336       CRX_PRINT (0, getreg_image (arg->r), shift);
01337       break;
01338 
01339     case arg_cr:
01340       /* case base_cst4.  */
01341       if (instruction->flags & DISPU4MAP)
01342        print_constant (nbits, shift + REG_SIZE, arg);
01343       else
01344        /* rbase_disps<NN> and other such cases.  */
01345        print_constant (nbits, shift, arg);
01346       /* Add the register argument to the output_opcode.  */
01347       CRX_PRINT (0, getreg_image (arg->r), shift);
01348       break;
01349 
01350     default:
01351       break;
01352     }
01353 }
01354 
01355 /* Retrieve the number of operands for the current assembled instruction.  */
01356 
01357 static int
01358 get_number_of_operands (void)
01359 {
01360   int i;
01361 
01362   for (i = 0; instruction->operands[i].op_type && i < MAX_OPERANDS; i++)
01363     ;
01364   return i;
01365 }
01366 
01367 /* Verify that the number NUM can be represented in BITS bits (that is, 
01368    within its permitted range), based on the instruction's FLAGS.  
01369    If UPDATE is nonzero, update the value of NUM if necessary.
01370    Return OP_LEGAL upon success, actual error type upon failure.  */
01371 
01372 static op_err
01373 check_range (long *num, int bits, int unsigned flags, int update)
01374 {
01375   long min, max;
01376   int retval = OP_LEGAL;
01377   int bin;
01378   long upper_64kb = 0xFFFF0000;
01379   long value = *num;
01380 
01381   /* For hosts witah longs bigger than 32-bits make sure that the top 
01382      bits of a 32-bit negative value read in by the parser are set,
01383      so that the correct comparisons are made.  */
01384   if (value & 0x80000000)
01385     value |= (-1L << 31);
01386 
01387   /* Verify operand value is even.  */
01388   if (flags & OP_EVEN)
01389     {
01390       if (value % 2)
01391        return OP_NOT_EVEN;
01392     }
01393 
01394   if (flags & OP_UPPER_64KB)
01395     {
01396       /* Check if value is to be mapped to upper 64 KB memory area.  */
01397       if ((value & upper_64kb) == upper_64kb)
01398        {
01399          value -= upper_64kb;
01400          if (update)
01401            *num = value;
01402        }
01403       else
01404        return OP_NOT_UPPER_64KB;
01405     }
01406 
01407   if (flags & OP_SHIFT)
01408     {
01409       value >>= 1;
01410       if (update)
01411        *num = value;
01412     }
01413   else if (flags & OP_SHIFT_DEC)
01414     {
01415       value = (value >> 1) - 1;
01416       if (update)
01417        *num = value;
01418     }
01419 
01420   if (flags & OP_ESC)
01421     {
01422       /* 0x7e and 0x7f are reserved escape sequences of dispe9.  */
01423       if (value == 0x7e || value == 0x7f)
01424        return OP_OUT_OF_RANGE;
01425     }
01426 
01427   if (flags & OP_DISPU4)
01428     {
01429       int is_dispu4 = 0;
01430 
01431       int mul = (instruction->flags & DISPUB4) ? 1 
01432               : (instruction->flags & DISPUW4) ? 2
01433               : (instruction->flags & DISPUD4) ? 4 : 0;
01434       
01435       for (bin = 0; bin < cst4_maps; bin++)
01436        {
01437          if (value == (mul * bin))
01438            {
01439              is_dispu4 = 1;
01440              if (update)
01441               *num = bin;
01442              break;
01443            }
01444        }
01445       if (!is_dispu4)
01446        retval = OP_ILLEGAL_DISPU4;
01447     }
01448   else if (flags & OP_CST4)
01449     {
01450       int is_cst4 = 0;
01451 
01452       for (bin = 0; bin < cst4_maps; bin++)
01453        {
01454          if (value == cst4_map[bin])
01455            {
01456              is_cst4 = 1;
01457              if (update)
01458               *num = bin;
01459              break;
01460            }
01461        }
01462       if (!is_cst4)
01463        retval = OP_ILLEGAL_CST4;
01464     }
01465   else if (flags & OP_SIGNED)
01466     {
01467       max = (1 << (bits - 1)) - 1;
01468       min = - (1 << (bits - 1));
01469       if ((value > max) || (value < min))
01470        retval = OP_OUT_OF_RANGE;
01471     }
01472   else if (flags & OP_UNSIGNED)
01473     {
01474       max = ((((1 << (bits - 1)) - 1) << 1) | 1);
01475       min = 0;
01476       if (((unsigned long) value > (unsigned long) max) 
01477            || ((unsigned long) value < (unsigned long) min))
01478        retval = OP_OUT_OF_RANGE;
01479     }
01480   return retval;
01481 }
01482 
01483 /* Assemble a single instruction:
01484    INSN is already parsed (that is, all operand values and types are set).
01485    For instruction to be assembled, we need to find an appropriate template in 
01486    the instruction table, meeting the following conditions:
01487     1: Has the same number of operands.
01488     2: Has the same operand types.
01489     3: Each operand size is sufficient to represent the instruction's values.
01490    Returns 1 upon success, 0 upon failure.  */
01491 
01492 static int
01493 assemble_insn (char *mnemonic, ins *insn)
01494 {
01495   /* Type of each operand in the current template.  */
01496   argtype cur_type[MAX_OPERANDS];
01497   /* Size (in bits) of each operand in the current template.  */
01498   unsigned int cur_size[MAX_OPERANDS];
01499   /* Flags of each operand in the current template.  */
01500   unsigned int cur_flags[MAX_OPERANDS];
01501   /* Instruction type to match.  */
01502   unsigned int ins_type;
01503   /* Boolean flag to mark whether a match was found.  */
01504   int match = 0;
01505   int i;
01506   /* Nonzero if an instruction with same number of operands was found.  */
01507   int found_same_number_of_operands = 0;
01508   /* Nonzero if an instruction with same argument types was found.  */
01509   int found_same_argument_types = 0;
01510   /* Nonzero if a constant was found within the required range.  */
01511   int found_const_within_range  = 0;
01512   /* Argument number of an operand with invalid type.  */
01513   int invalid_optype = -1;
01514   /* Argument number of an operand with invalid constant value.  */
01515   int invalid_const  = -1;
01516   /* Operand error (used for issuing various constant error messages).  */
01517   op_err op_error, const_err = OP_LEGAL;
01518 
01519 /* Retrieve data (based on FUNC) for each operand of a given instruction.  */
01520 #define GET_CURRENT_DATA(FUNC, ARRAY)                            \
01521   for (i = 0; i < insn->nargs; i++)                              \
01522     ARRAY[i] = FUNC (instruction->operands[i].op_type)
01523 
01524 #define GET_CURRENT_TYPE    GET_CURRENT_DATA(get_optype, cur_type)
01525 #define GET_CURRENT_SIZE    GET_CURRENT_DATA(get_opbits, cur_size)
01526 #define GET_CURRENT_FLAGS   GET_CURRENT_DATA(get_opflags, cur_flags)
01527 
01528   /* Instruction has no operands -> only copy the constant opcode.   */
01529   if (insn->nargs == 0)
01530     {
01531       output_opcode[0] = BIN (instruction->match, instruction->match_bits);
01532       return 1;
01533     }
01534 
01535   /* In some case, same mnemonic can appear with different instruction types.
01536      For example, 'storb' is supported with 3 different types :
01537      LD_STOR_INS, LD_STOR_INS_INC, STOR_IMM_INS.
01538      We assume that when reaching this point, the instruction type was 
01539      pre-determined. We need to make sure that the type stays the same
01540      during a search for matching instruction.  */
01541   ins_type = CRX_INS_TYPE(instruction->flags);
01542 
01543   while (/* Check that match is still not found.  */
01544         match != 1
01545         /* Check we didn't get to end of table.  */
01546         && instruction->mnemonic != NULL
01547         /* Check that the actual mnemonic is still available.  */
01548         && IS_INSN_MNEMONIC (mnemonic)
01549         /* Check that the instruction type wasn't changed.  */
01550         && IS_INSN_TYPE(ins_type))
01551     {
01552       /* Check whether number of arguments is legal.  */
01553       if (get_number_of_operands () != insn->nargs)
01554        goto next_insn;
01555       found_same_number_of_operands = 1;
01556 
01557       /* Initialize arrays with data of each operand in current template.  */
01558       GET_CURRENT_TYPE;
01559       GET_CURRENT_SIZE;
01560       GET_CURRENT_FLAGS;
01561 
01562       /* Check for type compatibility.  */
01563       for (i = 0; i < insn->nargs; i++)
01564         {
01565          if (cur_type[i] != insn->arg[i].type)
01566            {
01567              if (invalid_optype == -1)
01568               invalid_optype = i + 1;
01569              goto next_insn;
01570            }
01571        }
01572       found_same_argument_types = 1;
01573 
01574       for (i = 0; i < insn->nargs; i++)
01575        {
01576          /* Reverse the operand indices for certain opcodes:
01577             Index 0    -->> 1
01578             Index 1    -->> 0      
01579             Other index  -->> stays the same.  */
01580          int j = instruction->flags & REVERSE_MATCH ? 
01581                 i == 0 ? 1 : 
01582                 i == 1 ? 0 : i : 
01583                 i;
01584 
01585          /* Only check range - don't update the constant's value, since the 
01586             current instruction may not be the last we try to match.  
01587             The constant's value will be updated later, right before printing 
01588             it to the object file.  */
01589          if ((insn->arg[j].X_op == O_constant) 
01590               && (op_error = check_range (&insn->arg[j].constant, cur_size[j], 
01591                                       cur_flags[j], 0)))
01592            {
01593              if (invalid_const == -1)
01594              {
01595               invalid_const = j + 1;
01596               const_err = op_error;
01597              }
01598              goto next_insn;
01599            }
01600          /* For symbols, we make sure the relocation size (which was already 
01601             determined) is sufficient.  */
01602          else if ((insn->arg[j].X_op == O_symbol)
01603                   && ((bfd_reloc_type_lookup (stdoutput, insn->rtype))->bitsize 
01604                       > cur_size[j]))
01605                 goto next_insn;
01606        }
01607       found_const_within_range = 1;
01608 
01609       /* If we got till here -> Full match is found.  */
01610       match = 1;
01611       break;
01612 
01613 /* Try again with next instruction.  */
01614 next_insn:
01615       instruction++;
01616     }
01617 
01618   if (!match)
01619     {
01620       /* We haven't found a match - instruction can't be assembled.  */
01621       if (!found_same_number_of_operands)
01622        as_bad (_("Incorrect number of operands"));
01623       else if (!found_same_argument_types)
01624        as_bad (_("Illegal type of operand (arg %d)"), invalid_optype);
01625       else if (!found_const_within_range)
01626       {
01627        switch (const_err)
01628        {
01629        case OP_OUT_OF_RANGE:
01630          as_bad (_("Operand out of range (arg %d)"), invalid_const);
01631          break;
01632        case OP_NOT_EVEN:
01633          as_bad (_("Operand has odd displacement (arg %d)"), invalid_const);
01634          break;
01635        case OP_ILLEGAL_DISPU4:
01636          as_bad (_("Invalid DISPU4 operand value (arg %d)"), invalid_const);
01637          break;
01638        case OP_ILLEGAL_CST4:
01639          as_bad (_("Invalid CST4 operand value (arg %d)"), invalid_const);
01640          break;
01641        case OP_NOT_UPPER_64KB:
01642          as_bad (_("Operand value is not within upper 64 KB (arg %d)"), 
01643                   invalid_const);
01644          break;
01645        default:
01646          as_bad (_("Illegal operand (arg %d)"), invalid_const);
01647          break;
01648        }
01649       }
01650       
01651       return 0;
01652     }
01653   else
01654     /* Full match - print the encoding to output file.  */
01655     {
01656       /* Make further checkings (such that couldn't be made earlier).
01657         Warn the user if necessary.  */
01658       warn_if_needed (insn);
01659       
01660       /* Check whether we need to adjust the instruction pointer.  */
01661       if (adjust_if_needed (insn))
01662        /* If instruction pointer was adjusted, we need to update 
01663           the size of the current template operands.  */
01664        GET_CURRENT_SIZE;
01665 
01666       for (i = 0; i < insn->nargs; i++)
01667         {
01668          int j = instruction->flags & REVERSE_MATCH ? 
01669                 i == 0 ? 1 : 
01670                 i == 1 ? 0 : i : 
01671                 i;
01672 
01673          /* This time, update constant value before printing it.  */
01674          if ((insn->arg[j].X_op == O_constant) 
01675               && (check_range (&insn->arg[j].constant, cur_size[j], 
01676                             cur_flags[j], 1) != OP_LEGAL))
01677              as_fatal (_("Illegal operand (arg %d)"), j+1);
01678        }
01679 
01680       /* First, copy the instruction's opcode.  */
01681       output_opcode[0] = BIN (instruction->match, instruction->match_bits);
01682 
01683       for (i = 0; i < insn->nargs; i++)
01684         {
01685          cur_arg_num = i;
01686           print_operand (cur_size[i], instruction->operands[i].shift, 
01687                       &insn->arg[i]);
01688         }
01689     }
01690 
01691   return 1;
01692 }
01693 
01694 /* Bunch of error checkings.
01695    The checks are made after a matching instruction was found.  */
01696 
01697 void
01698 warn_if_needed (ins *insn)
01699 {
01700   /* If the post-increment address mode is used and the load/store 
01701      source register is the same as rbase, the result of the 
01702      instruction is undefined.  */
01703   if (IS_INSN_TYPE (LD_STOR_INS_INC))
01704     {
01705       /* Enough to verify that one of the arguments is a simple reg.  */
01706       if ((insn->arg[0].type == arg_r) || (insn->arg[1].type == arg_r))
01707        if (insn->arg[0].r == insn->arg[1].r)
01708          as_bad (_("Same src/dest register is used (`r%d'), result is undefined"), 
01709                  insn->arg[0].r);
01710     }
01711 
01712   /* Some instruction assume the stack pointer as rptr operand.
01713      Issue an error when the register to be loaded is also SP.  */
01714   if (instruction->flags & NO_SP)
01715     {
01716       if (getreg_image (insn->arg[0].r) == getreg_image (sp))
01717        as_bad (_("`%s' has undefined result"), ins_parse);
01718     }
01719 
01720   /* If the rptr register is specified as one of the registers to be loaded, 
01721      the final contents of rptr are undefined. Thus, we issue an error.  */
01722   if (instruction->flags & NO_RPTR)
01723     {
01724       if ((1 << getreg_image (insn->arg[0].r)) & insn->arg[1].constant)
01725        as_bad (_("Same src/dest register is used (`r%d'), result is undefined"), 
01726         getreg_image (insn->arg[0].r));
01727     }
01728 }
01729 
01730 /* In some cases, we need to adjust the instruction pointer although a 
01731    match was already found. Here, we gather all these cases.
01732    Returns 1 if instruction pointer was adjusted, otherwise 0.  */
01733 
01734 int
01735 adjust_if_needed (ins *insn)
01736 {
01737   int ret_value = 0;
01738 
01739   /* Special check for 'addub $0, r0' instruction -
01740      The opcode '0000 0000 0000 0000' is not allowed.  */
01741   if (IS_INSN_MNEMONIC ("addub"))
01742     {
01743       if ((instruction->operands[0].op_type == cst4)
01744          && instruction->operands[1].op_type == regr)
01745         {
01746           if (insn->arg[0].constant == 0 && insn->arg[1].r == r0)
01747            {
01748              instruction++;
01749              ret_value = 1;
01750            }
01751         }
01752     }
01753 
01754   /* Optimization: Omit a zero displacement in bit operations, 
01755      saving 2-byte encoding space (e.g., 'cbitw $8, 0(r1)').  */
01756   if (IS_INSN_TYPE (CSTBIT_INS))
01757     {
01758       if ((instruction->operands[1].op_type == rbase_disps12)
01759           && (insn->arg[1].X_op == O_constant)
01760           && (insn->arg[1].constant == 0))
01761             {
01762               instruction--;
01763              ret_value = 1;
01764             }
01765     }
01766 
01767   return ret_value;
01768 }
01769 
01770 /* Set the appropriate bit for register 'r' in 'mask'.
01771    This indicates that this register is loaded or stored by
01772    the instruction.  */
01773 
01774 static void
01775 mask_reg (int r, unsigned short int *mask)
01776 {
01777   if ((reg)r > (reg)sp)
01778     {
01779       as_bad (_("Invalid Register in Register List"));
01780       return;
01781     }
01782 
01783   *mask |= (1 << r);
01784 }
01785 
01786 /* Preprocess register list - create a 16-bit mask with one bit for each
01787    of the 16 general purpose registers. If a bit is set, it indicates
01788    that this register is loaded or stored by the instruction.  */
01789 
01790 static char *
01791 preprocess_reglist (char *param, int *allocated)
01792 {
01793   char reg_name[MAX_REGNAME_LEN]; /* Current parsed register name.  */
01794   char *regP;                 /* Pointer to 'reg_name' string.  */
01795   int reg_counter = 0;               /* Count number of parsed registers.  */
01796   unsigned short int mask = 0;       /* Mask for 16 general purpose registers.  */
01797   char *new_param;            /* New created operands string.  */
01798   char *paramP = param;              /* Pointer to original opearands string.  */
01799   char maskstring[10];               /* Array to print the mask as a string.  */
01800   int hi_found = 0, lo_found = 0; /* Boolean flags for hi/lo registers.  */
01801   reg r;
01802   copreg cr;
01803 
01804   /* If 'param' is already in form of a number, no need to preprocess.  */
01805   if (strchr (paramP, '{') == NULL)
01806     return param;
01807 
01808   /* Verifying correct syntax of operand.  */
01809   if (strchr (paramP, '}') == NULL)
01810     as_fatal (_("Missing matching brackets : `%s'"), ins_parse);
01811 
01812   while (*paramP++ != '{');
01813 
01814   new_param = (char *)xcalloc (MAX_INST_LEN, sizeof (char));
01815   *allocated = 1;
01816   strncpy (new_param, param, paramP - param - 1);
01817 
01818   while (*paramP != '}')
01819     {
01820       regP = paramP;
01821       memset (&reg_name, '\0', sizeof (reg_name));
01822 
01823       while (ISALNUM (*paramP))
01824        paramP++;
01825 
01826       strncpy (reg_name, regP, paramP - regP);
01827 
01828       /* Coprocessor register c<N>.  */
01829       if (IS_INSN_TYPE (COP_REG_INS))
01830         {
01831           if (((cr = get_copregister (reg_name)) == nullcopregister)
01832              || (crx_copregtab[cr-MAX_REG].type != CRX_C_REGTYPE))
01833            as_fatal (_("Illegal register `%s' in cop-register list"), reg_name);
01834          mask_reg (getreg_image (cr - c0), &mask);
01835         }
01836       /* Coprocessor Special register cs<N>.  */
01837       else if (IS_INSN_TYPE (COPS_REG_INS))
01838         {
01839           if (((cr = get_copregister (reg_name)) == nullcopregister)
01840              || (crx_copregtab[cr-MAX_REG].type != CRX_CS_REGTYPE))
01841            as_fatal (_("Illegal register `%s' in cop-special-register list"), 
01842                     reg_name);
01843          mask_reg (getreg_image (cr - cs0), &mask);
01844         }
01845       /* User register u<N>.  */
01846       else if (instruction->flags & USER_REG)
01847        {
01848          if (streq(reg_name, "uhi"))
01849            {
01850              hi_found = 1;
01851              goto next_inst;
01852            }
01853          else if (streq(reg_name, "ulo"))
01854            {
01855              lo_found = 1;
01856              goto next_inst;
01857            }
01858           else if (((r = get_register (reg_name)) == nullregister)
01859              || (crx_regtab[r].type != CRX_U_REGTYPE))
01860            as_fatal (_("Illegal register `%s' in user register list"), reg_name);
01861          
01862          mask_reg (getreg_image (r - u0), &mask);         
01863        }
01864       /* General purpose register r<N>.  */
01865       else
01866         {
01867          if (streq(reg_name, "hi"))
01868            {
01869              hi_found = 1;
01870              goto next_inst;
01871            }
01872          else if (streq(reg_name, "lo"))
01873            {
01874              lo_found = 1;
01875              goto next_inst;
01876            }
01877           else if (((r = get_register (reg_name)) == nullregister)
01878              || (crx_regtab[r].type != CRX_R_REGTYPE))
01879            as_fatal (_("Illegal register `%s' in register list"), reg_name);
01880 
01881          mask_reg (getreg_image (r - r0), &mask);
01882         }
01883 
01884       if (++reg_counter > MAX_REGS_IN_MASK16)
01885        as_bad (_("Maximum %d bits may be set in `mask16' operand"),
01886               MAX_REGS_IN_MASK16);
01887 
01888 next_inst:
01889       while (!ISALNUM (*paramP) && *paramP != '}')
01890          paramP++;
01891     }
01892 
01893   if (*++paramP != '\0')
01894     as_warn (_("rest of line ignored; first ignored character is `%c'"),
01895             *paramP);
01896 
01897   switch (hi_found + lo_found)
01898     {
01899     case 0:
01900       /* At least one register should be specified.  */
01901       if (mask == 0)
01902        as_bad (_("Illegal `mask16' operand, operation is undefined - `%s'"),
01903               ins_parse);
01904       break;
01905 
01906     case 1:
01907       /* HI can't be specified without LO (and vise-versa).  */
01908       as_bad (_("HI/LO registers should be specified together"));
01909       break;
01910 
01911     case 2:
01912       /* HI/LO registers mustn't be masked with additional registers.  */
01913       if (mask != 0)
01914        as_bad (_("HI/LO registers should be specified without additional registers"));
01915 
01916     default:
01917       break;
01918     }
01919 
01920   sprintf (maskstring, "$0x%x", mask);
01921   strcat (new_param, maskstring);
01922   return new_param;
01923 }
01924 
01925 /* Print the instruction.
01926    Handle also cases where the instruction is relaxable/relocatable.  */
01927 
01928 void
01929 print_insn (ins *insn)
01930 {
01931   unsigned int i, j, insn_size;
01932   char *this_frag;
01933   unsigned short words[4];
01934   int addr_mod;
01935 
01936   /* Arrange the insn encodings in a WORD size array.  */
01937   for (i = 0, j = 0; i < 2; i++)
01938     {
01939       words[j++] = (output_opcode[i] >> 16) & 0xFFFF;
01940       words[j++] = output_opcode[i] & 0xFFFF;
01941     }
01942 
01943   /* Handle relaxtion.  */
01944   if ((instruction->flags & RELAXABLE) && relocatable)
01945     {
01946       int relax_subtype;
01947 
01948       /* Write the maximal instruction size supported.  */
01949       insn_size = INSN_MAX_SIZE;
01950 
01951       /* bCC  */
01952       if (IS_INSN_TYPE (BRANCH_INS))
01953        relax_subtype = 0;
01954       /* bal  */
01955       else if (IS_INSN_TYPE (DCR_BRANCH_INS) || IS_INSN_MNEMONIC ("bal"))
01956        relax_subtype = 3;
01957       /* cmpbr/bcop  */
01958       else if (IS_INSN_TYPE (CMPBR_INS) || IS_INSN_TYPE (COP_BRANCH_INS))
01959        relax_subtype = 5;
01960       else
01961        abort ();
01962 
01963       this_frag = frag_var (rs_machine_dependent, insn_size * 2,
01964                          4, relax_subtype,
01965                          insn->exp.X_add_symbol,
01966                          insn->exp.X_add_number,
01967                          0);
01968     }
01969   else
01970     {
01971       insn_size = instruction->size;
01972       this_frag = frag_more (insn_size * 2);
01973 
01974       /* Handle relocation.  */
01975       if ((relocatable) && (insn->rtype != BFD_RELOC_NONE))
01976        {
01977          reloc_howto_type *reloc_howto;
01978          int size;
01979 
01980          reloc_howto = bfd_reloc_type_lookup (stdoutput, insn->rtype);
01981 
01982          if (!reloc_howto)
01983            abort ();
01984 
01985          size = bfd_get_reloc_size (reloc_howto);
01986 
01987          if (size < 1 || size > 4)
01988            abort ();
01989 
01990          fix_new_exp (frag_now, this_frag - frag_now->fr_literal,
01991                      size, &insn->exp, reloc_howto->pc_relative,
01992                      insn->rtype);
01993        }
01994     }
01995 
01996   /* Verify a 2-byte code alignment.  */
01997   addr_mod = frag_now_fix () & 1;
01998   if (frag_now->has_code && frag_now->insn_addr != addr_mod)
01999     as_bad (_("instruction address is not a multiple of 2"));
02000   frag_now->insn_addr = addr_mod;
02001   frag_now->has_code = 1;
02002 
02003   /* Write the instruction encoding to frag.  */
02004   for (i = 0; i < insn_size; i++)
02005     {
02006       md_number_to_chars (this_frag, (valueT) words[i], 2);
02007       this_frag += 2;
02008     }
02009 }
02010 
02011 /* This is the guts of the machine-dependent assembler.  OP points to a
02012    machine dependent instruction.  This function is supposed to emit
02013    the frags/bytes it assembles to.  */
02014 
02015 void
02016 md_assemble (char *op)
02017 {
02018   ins crx_ins;
02019   char *param;
02020   char c;
02021 
02022   /* Reset global variables for a new instruction.  */
02023   reset_vars (op);
02024 
02025   /* Strip the mnemonic.  */
02026   for (param = op; *param != 0 && !ISSPACE (*param); param++)
02027     ;
02028   c = *param;
02029   *param++ = '\0';
02030 
02031   /* Find the instruction.  */
02032   instruction = (const inst *) hash_find (crx_inst_hash, op);
02033   if (instruction == NULL)
02034     {
02035       as_bad (_("Unknown opcode: `%s'"), op);
02036       return;
02037     }
02038 
02039   /* Tie dwarf2 debug info to the address at the start of the insn.  */
02040   dwarf2_emit_insn (0);
02041 
02042   /* Parse the instruction's operands.  */
02043   parse_insn (&crx_ins, param);
02044 
02045   /* Assemble the instruction - return upon failure.  */
02046   if (assemble_insn (op, &crx_ins) == 0)
02047     return;
02048 
02049   /* Print the instruction.  */
02050   print_insn (&crx_ins);
02051 }