Add support to GDB for the Renesas rl78 architecture.
[external/binutils.git] / gas / config / tc-crx.c
index e3145f5..b347d8b 100644 (file)
@@ -1,5 +1,6 @@
 /* tc-crx.c -- Assembler code for the CRX CPU core.
-   Copyright 2004 Free Software Foundation, Inc.
+   Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
 
    Contributed by Tomer Levi, NSC, Israel.
    Originally written for GAS 2.12 by Tomer Levi, NSC, Israel.
@@ -9,7 +10,7 @@
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
@@ -19,8 +20,8 @@
 
    You should have received a copy of the GNU General Public License
    along with GAS; see the file COPYING.  If not, write to the
-   Free Software Foundation, 59 Temple Place - Suite 330, Boston,
-   MA 02111-1307, USA.  */
+   Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
 
 #include "as.h"
 #include "safe-ctype.h"
 #include "opcode/crx.h"
 #include "elf/crx.h"
 
-#include <limits.h>
-
 /* Word is considered here as a 16-bit unsigned short int.  */
-#define WORD_SIZE   16
 #define WORD_SHIFT  16
 
 /* Register is 4-bit size.  */
 /* Maximum bits which may be set in a `mask16' operand.  */
 #define MAX_REGS_IN_MASK16  8
 
-/* Escape to 16-bit immediate.  */
-#define ESC_16  0xE
-/* Escape to 32-bit immediate.  */
-#define ESC_32  0xF
-
 /* Utility macros for string comparison.  */
 #define streq(a, b)           (strcmp (a, b) == 0)
 #define strneq(a, b, c)       (strncmp (a, b, c) == 0)
 
-/* A mask to set n_bits starting from offset offs.  */
-#define SET_BITS_MASK(offs,n_bits)    ((((1 << (n_bits)) - 1) << (offs)))
-/* A mask to clear n_bits starting from offset offs.  */
-#define CLEAR_BITS_MASK(offs,n_bits)  (~(((1 << (n_bits)) - 1) << (offs)))
-
-/* Get the argument type for each operand of a given instruction.  */
-#define GET_ACTUAL_TYPE                                                  \
-  for (i = 0; i < insn->nargs; i++)                              \
-    atyp_act[i] = getarg_type (instruction->operands[i].op_type)
-
-/* Get the size (in bits) for each operand of a given instruction.  */
-#define GET_ACTUAL_SIZE                                                  \
-  for (i = 0; i < insn->nargs; i++)                              \
-    bits_act[i] = getbits (instruction->operands[i].op_type)
-
-/* Non-zero if OP is instruction with no operands.  */
-#define NO_OPERANDS_INST(OP)                     \
-  (streq (OP, "di") || streq (OP, "nop")         \
-   || streq (OP, "retx") || streq (OP, "ei")     \
-   || streq (OP, "wait") || streq (OP, "eiwait"))
-
-/* Print a number NUM, shifted by SHIFT bytes, into a location
+/* Assign a number NUM, shifted by SHIFT bytes, into a location
    pointed by index BYTE of array 'output_opcode'.  */
 #define CRX_PRINT(BYTE, NUM, SHIFT)   output_opcode[BYTE] |= (NUM << SHIFT)
 
+/* Operand errors.  */
+typedef enum
+  {
+    OP_LEGAL = 0,      /* Legal operand.  */
+    OP_OUT_OF_RANGE,   /* Operand not within permitted range.  */
+    OP_NOT_EVEN,       /* Operand is Odd number, should be even.  */
+    OP_ILLEGAL_DISPU4, /* Operand is not within DISPU4 range.  */
+    OP_ILLEGAL_CST4,   /* Operand is not within CST4 range.  */
+    OP_NOT_UPPER_64KB  /* Operand is not within the upper 64KB 
+                          (0xFFFF0000-0xFFFFFFFF).  */
+  }
+op_err;
+
 /* Opcode mnemonics hash table.  */
 static struct hash_control *crx_inst_hash;
 /* CRX registers hash table.  */
@@ -86,22 +71,19 @@ static struct hash_control *copreg_hash;
 /* Current instruction we're assembling.  */
 const inst *instruction;
 
-/* Initialize global variables.  */
+/* Global variables.  */
+
+/* Array to hold an instruction encoding.  */
 long output_opcode[2];
+
 /* Nonzero means a relocatable symbol.  */
 int relocatable;
-/* Nonzero means a constant's bit-size was already set.  */
-int size_was_set;
-/* Nonzero means a negative constant.  */
-int signflag;
-/* Nonzero means a CST4 instruction.  */
-int cst4flag;
+
 /* A copy of the original instruction (used in error messages).  */
 char ins_parse[MAX_INST_LEN];
-/* Nonzero means instruction is represented in post increment mode.  */
-int post_inc_mode;
-/* Holds the current processed argument number.  */
-int processing_arg_number;
+
+/* The current processed argument number.  */
+int cur_arg_num;
 
 /* Generic assembler global variables which must be defined by all targets.  */
 
@@ -141,6 +123,7 @@ const pseudo_typeS md_pseudo_table[] =
   {0, 0, 0}
 };
 
+/* CRX relaxation table.  */
 const relax_typeS md_relax_table[] =
 {
   /* bCC  */
@@ -152,42 +135,43 @@ const relax_typeS md_relax_table[] =
   {0xfffe, -0x10000, 4, 4},            /* 16 */
   {0xfffffffe, -0xfffffffe, 6, 0},     /* 32 */
 
-  /* cmpbr  */
+  /* cmpbr/bcop  */
   {0xfe, -0x100, 4, 6},                        /*  8 */
   {0xfffffe, -0x1000000, 6, 0}         /* 24 */
 };
 
-static void    reset_vars              (char *, ins *);
+static void    reset_vars              (char *);
 static reg     get_register            (char *);
 static copreg  get_copregister         (char *);
-static void    get_number_of_bits       (ins *, int);
-static argtype getarg_type             (operand_type);
-static int     getbits                 (operand_type);
+static argtype get_optype              (operand_type);
+static int     get_opbits              (operand_type);
+static int     get_opflags             (operand_type);
 static int     get_number_of_operands   (void);
-static void    get_operandtype         (char *, int, ins *);
-static int     gettrap                 (char *);
-static void    handle_LoadStor         (char *);
-static int     get_cinv_parameters      (char *);
-static unsigned long getconstant        (unsigned long, int);
+static void    parse_operand           (char *, ins *);
+static int     gettrap                 (const char *);
+static void    handle_LoadStor         (const char *);
+static int     get_cinv_parameters      (const char *);
+static long    getconstant             (long, int);
+static op_err  check_range             (long *, int, unsigned int, int);
 static int     getreg_image            (reg);
 static void    parse_operands          (ins *, char *);
 static void    parse_insn              (ins *, char *);
 static void    print_operand           (int, int, argument *);
 static void    print_constant          (int, int, argument *);
 static int     exponent2scale          (int);
-static void    mask_const              (unsigned long *, int);
 static void    mask_reg                        (int, unsigned short *);
-static int     process_label_constant   (char *, ins *, int);
-static void    set_indexmode_parameters (char *, ins *, int);
-static void    set_cons_rparams                (char *, ins *, int);
+static void    process_label_constant   (char *, ins *);
+static void    set_operand             (char *, ins *);
 static char *  preprocess_reglist       (char *, int *);
 static int     assemble_insn           (char *, ins *);
 static void    print_insn              (ins *);
+static void    warn_if_needed          (ins *);
+static int     adjust_if_needed                (ins *);
 
 /* Return the bit size for a given operand.  */
 
 static int
-getbits (operand_type op)
+get_opbits (operand_type op)
 {
   if (op < MAX_OPRD)
     return crx_optab[op].bit_size;
@@ -198,7 +182,7 @@ getbits (operand_type op)
 /* Return the argument type of a given operand.  */
 
 static argtype
-getarg_type (operand_type op)
+get_optype (operand_type op)
 {
   if (op < MAX_OPRD)
     return crx_optab[op].arg_type;
@@ -206,17 +190,28 @@ getarg_type (operand_type op)
     return nullargs;
 }
 
+/* Return the flags of a given operand.  */
+
+static int
+get_opflags (operand_type op)
+{
+  if (op < MAX_OPRD)
+    return crx_optab[op].flags;
+  else
+    return 0;
+}
+
 /* Get the core processor register 'reg_name'.  */
 
 static reg
 get_register (char *reg_name)
 {
-  const reg_entry *reg;
+  const reg_entry *rreg;
 
-  reg = (const reg_entry *) hash_find (reg_hash, reg_name);
+  rreg = (const reg_entry *) hash_find (reg_hash, reg_name);
 
-  if (reg != NULL)
-    return reg->value.reg_val;
+  if (rreg != NULL)
+    return rreg->value.reg_val;
   else
     return nullregister;
 }
@@ -226,24 +221,16 @@ get_register (char *reg_name)
 static copreg
 get_copregister (char *copreg_name)
 {
-  const reg_entry *copreg;
+  const reg_entry *coreg;
 
-  copreg = (const reg_entry *) hash_find (copreg_hash, copreg_name);
+  coreg = (const reg_entry *) hash_find (copreg_hash, copreg_name);
 
-  if (copreg != NULL)
-    return copreg->value.copreg_val;
+  if (coreg != NULL)
+    return coreg->value.copreg_val;
   else
     return nullcopregister;
 }
 
-/* Mask a constant to the number of bits it is to be mapped to.  */
-
-static void
-mask_const (unsigned long int *t, int size)
-{
-  *t &= (((LONGLONG)1 << size) - 1);
-}
-
 /* Round up a section size to the appropriate boundary.  */
 
 valueT
@@ -276,20 +263,14 @@ md_operand (expressionS * exp)
 /* Reset global variables before parsing a new instruction.  */
 
 static void
-reset_vars (char *op, ins *crx_ins)
+reset_vars (char *op)
 {
-  unsigned int i;
-
-  processing_arg_number = relocatable = size_was_set
-    = signflag = post_inc_mode = cst4flag = 0;
+  cur_arg_num = relocatable = 0;
   memset (& output_opcode, '\0', sizeof (output_opcode));
 
-  /* Memset the 'signflag' field in every argument.  */
-  for (i = 0; i < MAX_OPERANDS; i++)
-    crx_ins->arg[i].signflag = 0;
-
   /* Save a copy of the original OP (used in error messages).  */
-  strcpy (ins_parse, op);
+  strncpy (ins_parse, op, sizeof ins_parse - 1);
+  ins_parse [sizeof ins_parse - 1] = 0;
 }
 
 /* This macro decides whether a particular reloc is an entry in a
@@ -371,7 +352,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS * fixP)
        }
     }
 
-  assert ((int) fixP->fx_r_type > 0);
+  gas_assert ((int) fixP->fx_r_type > 0);
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
 
   if (reloc->howto == (reloc_howto_type *) NULL)
@@ -382,7 +363,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS * fixP)
                    bfd_get_reloc_code_name (fixP->fx_r_type));
       return NULL;
     }
-  assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
+  gas_assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
 
   return reloc;
 }
@@ -483,58 +464,10 @@ md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
   return;
 }
 
-/* Turn a string in input_line_pointer into a floating point constant
-   of type TYPE, and store the appropriate bytes in *LITP.  The number
-   of LITTLENUMS emitted is stored in *SIZEP.  An error message is
-   returned, or NULL on OK.  */
-
 char *
 md_atof (int type, char *litP, int *sizeP)
 {
-  int prec;
-  LITTLENUM_TYPE words[4];
-  char *t;
-  int i;
-
-  switch (type)
-    {
-    case 'f':
-      prec = 2;
-      break;
-
-    case 'd':
-      prec = 4;
-      break;
-
-    default:
-      *sizeP = 0;
-      return _("bad call to md_atof");
-    }
-
-  t = atof_ieee (input_line_pointer, type, words);
-  if (t)
-    input_line_pointer = t;
-
-  *sizeP = prec * 2;
-
-  if (! target_big_endian)
-    {
-      for (i = prec - 1; i >= 0; i--)
-       {
-         md_number_to_chars (litP, (valueT) words[i], 2);
-         litP += 2;
-       }
-    }
-  else
-    {
-      for (i = 0; i < prec; i++)
-       {
-         md_number_to_chars (litP, (valueT) words[i], 2);
-         litP += 2;
-       }
-    }
-
-  return NULL;
+  return ieee_md_atof (type, litP, sizeP, target_big_endian);
 }
 
 /* Apply a fixS (fixup of an instruction or data that we didn't have
@@ -544,7 +477,7 @@ md_atof (int type, char *litP, int *sizeP)
    fixuping relocations of debug sections.  */
 
 void
-md_apply_fix3 (fixS *fixP, valueT *valP, segT seg)
+md_apply_fix (fixS *fixP, valueT *valP, segT seg)
 {
   valueT val = * valP;
   char *buf = fixP->fx_frag->fr_literal + fixP->fx_where;
@@ -598,16 +531,15 @@ md_begin (void)
   int i = 0;
 
   /* Set up a hash table for the instructions.  */
-  crx_inst_hash = hash_new ();
-  if (crx_inst_hash == NULL)
+  if ((crx_inst_hash = hash_new ()) == NULL)
     as_fatal (_("Virtual memory exhausted"));
-
+  
   while (crx_instruction[i].mnemonic != NULL)
     {
       const char *mnemonic = crx_instruction[i].mnemonic;
 
       hashret = hash_insert (crx_inst_hash, mnemonic,
-       (PTR) &crx_instruction[i]);
+                            (void *) &crx_instruction[i]);
 
       if (hashret != NULL && *hashret != '\0')
        as_fatal (_("Can't hash `%s': %s\n"), crx_instruction[i].mnemonic,
@@ -626,7 +558,8 @@ md_begin (void)
     }
 
   /* Initialize reg_hash hash table.  */
-  reg_hash = hash_new ();
+  if ((reg_hash = hash_new ()) == NULL)
+    as_fatal (_("Virtual memory exhausted"));
 
   {
     const reg_entry *regtab;
@@ -634,7 +567,7 @@ md_begin (void)
     for (regtab = crx_regtab;
         regtab < (crx_regtab + NUMREGS); regtab++)
       {
-       hashret = hash_insert (reg_hash, regtab->name, (PTR) regtab);
+       hashret = hash_insert (reg_hash, regtab->name, (void *) regtab);
        if (hashret)
          as_fatal (_("Internal Error:  Can't hash %s: %s"),
                    regtab->name,
@@ -643,7 +576,8 @@ md_begin (void)
   }
 
   /* Initialize copreg_hash hash table.  */
-  copreg_hash = hash_new ();
+  if ((copreg_hash = hash_new ()) == NULL)
+    as_fatal (_("Virtual memory exhausted"));
 
   {
     const reg_entry *copregtab;
@@ -651,7 +585,8 @@ md_begin (void)
     for (copregtab = crx_copregtab; copregtab < (crx_copregtab + NUMCOPREGS);
         copregtab++)
       {
-       hashret = hash_insert (copreg_hash, copregtab->name, (PTR) copregtab);
+       hashret = hash_insert (copreg_hash, copregtab->name,
+                              (void *) copregtab);
        if (hashret)
          as_fatal (_("Internal Error:  Can't hash %s: %s"),
                    copregtab->name,
@@ -662,221 +597,20 @@ md_begin (void)
   linkrelax = 1;
 }
 
-/* Get the number of bits corresponding to a constant -
-   here we check for possible overflow cases.  */
+/* Process constants (immediate/absolute) 
+   and labels (jump targets/Memory locations).  */
 
 static void
-get_number_of_bits (ins * crx_ins, int op_num)
+process_label_constant (char *str, ins * crx_ins)
 {
-  int cnt_bits = 0;
-  unsigned long int temp = crx_ins->arg[op_num].constant;
-  const cst4_entry *cst4_op;
-
-  /* If the constant's size was already set - nothing to do.  */
-  if (size_was_set)
-    return;
-
-  /* Already dealt with negative numbers in process_label_constants.  */
-  while (temp > 0)
-    {
-      temp >>= 1;
-      cnt_bits++;
-    }
-
-  if (IS_INSN_TYPE (ARITH_INS) && !relocatable && !signflag)
-    {
-      if (cnt_bits == 16)
-        {
-          crx_ins->arg[op_num].size = 17;
-          return;
-        }
-    }
-  /* If a signed +ve is represented in 6 bits then we have to represent
-     it in 22 bits in case of the index mode of addressing.  */
-  if (IS_INSN_TYPE (LD_STOR_INS)
-      || IS_INSN_TYPE (LD_STOR_INS_INC)
-      || IS_INSN_TYPE (STOR_IMM_INS)
-      || IS_INSN_TYPE (CSTBIT_INS))
-    {
-      if (!signflag && crx_ins->arg[op_num].type == arg_icr)
-        {
-          if (cnt_bits == 6)
-            {
-              crx_ins->arg[op_num].size = 7;
-              return;
-            }
-          if (cnt_bits == 22)
-           as_bad (_("Offset out of range in Instruction `%s'"), ins_parse);
-        }
-    }
-  /* If a signed +ve is represnted in 16 bits in case of load/stor disp16
-     then change it to 17 bits.
-     If a signed +ve is represnted in 12 bits in post increment instruction
-     increase it to 13 bits.  */
-  if (IS_INSN_TYPE (LD_STOR_INS))
-    {
-      if (!signflag && crx_ins->arg[op_num].type == arg_cr)
-        {
-          if (cnt_bits == 16)
-            {
-              crx_ins->arg[op_num].size = 17;
-              return;
-            }
-          if (cnt_bits == 32)
-           as_bad (_("Offset out of range in Instruction `%s'"), ins_parse);
-        }
-    }
-
-  if (IS_INSN_TYPE (CSTBIT_INS)
-      || IS_INSN_TYPE (LD_STOR_INS_INC)
-      || IS_INSN_TYPE (STOR_IMM_INS))
-    {
-      if (!signflag && crx_ins->arg[op_num].type == arg_cr)
-        {
-          if (cnt_bits == 12)
-            {
-              crx_ins->arg[op_num].size = 13;
-              if (IS_INSN_TYPE (LD_STOR_INS_INC))
-               as_bad (_("Offset out of range in Instruction `%s'"), ins_parse);
-              return;
-            }
-          if (IS_INSN_TYPE (CSTBIT_INS) || IS_INSN_TYPE (STOR_IMM_INS))
-            {
-              if (cnt_bits == 28)
-               as_bad (_("Offset out of range in Instruction `%s'"), ins_parse);
-            }
-
-        }
-    }
-
-  /* Handle negative cst4 mapping for arithmetic/cmp&br operations.  */
-  if (signflag && !relocatable
-      && ((IS_INSN_TYPE (ARITH_INS) || IS_INSN_TYPE (ARITH_BYTE_INS))
-      || ((IS_INSN_TYPE (CMPBR_INS) && op_num == 0))))
-    {
-      for (cst4_op = cst4_map; cst4_op < (cst4_map + cst4_maps); cst4_op++)
-       {
-         if (crx_ins->arg[op_num].constant == (unsigned int)(-cst4_op->value))
-           {
-             crx_ins->arg[op_num].size = 4;
-             crx_ins->arg[op_num].constant = cst4_op->binary;
-             crx_ins->arg[op_num].signflag = 0;
-             return;
-           }
-       }
-    }
-  /* Because of the cst4 mapping -- -1 and -4 already handled above
-     as well as for relocatable cases.  */
-  if (signflag && IS_INSN_TYPE (ARITH_BYTE_INS))
-    {
-      if (!relocatable)
-        {
-          if (crx_ins->arg[op_num].constant <= 0xffff)
-            crx_ins->arg[op_num].size = 16;
-          else
-           /* Setting to 18 so that there is no match.  */
-            crx_ins->arg[op_num].size = 18;
-        }
-      else
-        crx_ins->arg[op_num].size = 16;
-      return;
-    }
-
-  if (signflag && IS_INSN_TYPE (ARITH_INS))
-    {
-      /* For all immediates which can be expressed in less than 16 bits.  */
-      if (crx_ins->arg[op_num].constant <= 0xffff && !relocatable)
-        {
-          crx_ins->arg[op_num].size = 16;
-          return;
-        }
-      /* Either it is relocatable or not representable in 16 bits.  */
-      if (crx_ins->arg[op_num].constant < 0xffffffff || relocatable)
-        {
-          crx_ins->arg[op_num].size = 32;
-          return;
-        }
-      crx_ins->arg[op_num].size = 33;
-      return;
-    }
-  if (signflag && !relocatable)
-    return;
-
-  if (!relocatable)
-    crx_ins->arg[op_num].size = cnt_bits;
-
-  /* Checking for Error Conditions.  */
-  if (IS_INSN_TYPE (ARITH_INS) && !signflag)
-    {
-      if (cnt_bits > 32)
-       as_bad (_("Cannot represent Immediate in %d bits in Instruction `%s'"),
-               cnt_bits, ins_parse);
-    }
-  else if (IS_INSN_TYPE (ARITH_BYTE_INS) && !signflag)
-    {
-      if (cnt_bits > 16)
-       as_bad (_("Cannot represent Immediate in %d bits in Instruction `%s'"),
-               cnt_bits, ins_parse);
-    }
-}
-
-/* Handle the constants -immediate/absolute values and
-   Labels (jump targets/Memory locations).  */
-
-static int
-process_label_constant (char *str, ins * crx_ins, int number)
-{
-  char *save;
-  unsigned long int temp, cnt;
-  const cst4_entry *cst4_op;
-  int is_cst4=0;
-  int constant_val = 0;
-  int cmp_br_type_flag = 0, i;
-  int br_type_flag = 0;
-  save = input_line_pointer;
-  signflag = 0;
-
-  if (str[0] == '-')
-    {
-      signflag = 1;
-      str++;
-    }
-  else if (str[0] == '+')
-    str++;
+  char *saved_input_line_pointer;
+  argument *cur_arg = &crx_ins->arg[cur_arg_num];  /* Current argument.  */
 
-  /* Preprocessing for cmpbr instruction and getting the size flag.  */
-  if (strstr (str, ":s") != NULL && (IS_INSN_TYPE (CMPBR_INS)
-      || IS_INSN_TYPE (COP_BRANCH_INS)))
-    cmp_br_type_flag = 8;
-
-  if (strstr (str, ":l") != NULL && (IS_INSN_TYPE (CMPBR_INS)
-      || IS_INSN_TYPE (COP_BRANCH_INS)))
-    cmp_br_type_flag = 24;
-
-  /* Branch instruction preprocessing.  */
-  if (IS_INSN_TYPE (BRANCH_INS))
-    {
-      if (strstr (str, ":s") != NULL)
-       br_type_flag = 8;
-      else if (strstr (str, ":m") != NULL)
-       br_type_flag = 16;
-      else if (strstr (str, ":l") != NULL)
-       br_type_flag = 32;
-    }
-  /* Making the label cleared for processing removing :lms etc from labels.  */
-  if (cmp_br_type_flag != 0 || br_type_flag != 0)
-    {
-      i = 0;
-      while (str[i] != ':')
-        {
-          i++;
-        }
-      str[i] = '\0';
-    }
+  saved_input_line_pointer = input_line_pointer;
   input_line_pointer = str;
 
   expression (&crx_ins->exp);
-
+  
   switch (crx_ins->exp.X_op)
     {
     case O_big:
@@ -888,334 +622,51 @@ process_label_constant (char *str, ins * crx_ins, int number)
       crx_ins->exp.X_add_number = 0;
       crx_ins->exp.X_add_symbol = (symbolS *) 0;
       crx_ins->exp.X_op_symbol = (symbolS *) 0;
-      break;
+      /* Fall through.  */
 
     case O_constant:
-      crx_ins->arg[number].constant = crx_ins->exp.X_add_number;
-      constant_val = crx_ins->exp.X_add_number;
-      if ((IS_INSN_TYPE (CMPBR_INS) || IS_INSN_TYPE (COP_BRANCH_INS))
-          && number == 2)
-        {
-          LONGLONG temp64 = 0;
-          char ptr;
-          char temp_str[30];
-          unsigned int jump_value = 0;
-          int BR_MASK = 0, BR_SIZE = 0;
-          temp_str[0] = '\0';
-          if (signflag)
-            {
-              temp_str[0] = '-';
-              temp_str[1] = '\0';
-            }
-          strncat (temp_str, str, strlen (str));
-         temp64 = strtoll (temp_str, (char **) &ptr,0);
-
-          if (temp64 % 2 != 0)
-           as_bad (_("Odd Offset in displacement in Instruction `%s'"),
-                   ins_parse);
-
-         /* Determine the branch size.  */
-          jump_value = (unsigned int)temp64 & 0xFFFFFFFF;
-          if (((jump_value & 0xFFFFFF00) == 0xFFFFFF00)
-             || ((jump_value & 0xFFFFFF00) == 0x0))
-            {
-              BR_MASK = 0xFF;
-              BR_SIZE = 8;
-            }
-          else
-            if (((jump_value & 0xFF000000) == 0xFF000000)
-               || ((jump_value & 0xFF000000) == 0x0))
-            {
-              BR_MASK = 0xFFFFFF;
-              BR_SIZE = 24;
-            }
-         jump_value = jump_value >> 1;
-          crx_ins->arg[number].constant = jump_value & BR_MASK;
-          crx_ins->arg[number].size = BR_SIZE;
-         size_was_set = 1;
-          crx_ins->arg[number].signflag = signflag;
-          input_line_pointer = save;
-          return crx_ins->exp.X_op;
-        }
-
-      if (IS_INSN_TYPE (BRANCH_INS)
-         || IS_INSN_MNEMONIC ("bal")
-         || IS_INSN_TYPE (DCR_BRANCH_INS))
-        {
-          LONGLONG temp64 = 0;
-          char ptr;
-          char temp_str[30];
-          unsigned int jump_value = 0;
-          int BR_MASK = 0, BR_SIZE = 0;
-
-          temp_str[0] = '\0';
-          if (signflag)
-            {
-              temp_str[0] = '-';
-              temp_str[1] = '\0';
-            }
-          strncat (temp_str, str, strlen (str));
-         temp64 = strtoll (temp_str, (char **) &ptr,0);
-
-         if (temp64 % 2 != 0)
-           as_bad (_("Odd Offset in displacement in Instruction `%s'"),
-           ins_parse);
-
-         /* Determine the branch size.  */
-          jump_value = (unsigned int)temp64 & 0xFFFFFFFF;
-          if (!IS_INSN_MNEMONIC ("bal") && !IS_INSN_TYPE (DCR_BRANCH_INS)
-             && (((jump_value & 0xFFFFFF00) == 0xFFFFFF00)
-                 || ((jump_value & 0xFFFFFF00) == 0x0)))
-            {
-              BR_MASK = 0xFF;
-              BR_SIZE = 8;
-            }
-          else if (((jump_value & 0xFFFF0000) == 0xFFFF0000)
-                  || ((jump_value & 0xFFFF0000) == 0x0))
-            {
-              BR_MASK = 0xFFFF;
-              BR_SIZE = 16;
-            }
-          else
-            {
-              BR_MASK = 0xFFFFFFFF;
-              BR_SIZE = 32;
-            }
-         jump_value = jump_value >> 1;
-          crx_ins->arg[number].constant = jump_value & BR_MASK;
-          crx_ins->arg[number].size = BR_SIZE;
-         size_was_set = 1;
-          crx_ins->arg[number].signflag = signflag;
-          input_line_pointer = save;
-          return crx_ins->exp.X_op;
-        }
-      /* Fix for movd $0xF12344, r0 -- signflag has to be set.  */
-      if (constant_val < 0 && signflag != 1
-          && !IS_INSN_TYPE (LD_STOR_INS) && !IS_INSN_TYPE (LD_STOR_INS_INC)
-          && !IS_INSN_TYPE (CSTBIT_INS) && !IS_INSN_TYPE (STOR_IMM_INS)
-          && !IS_INSN_TYPE (BRANCH_INS) && !IS_INSN_MNEMONIC ("bal"))
-        {
-          crx_ins->arg[number].constant =
-            ~(crx_ins->arg[number].constant) + 1;
-          signflag = 1;
-        }
-      /* For load/store instruction when the value is in the offset part.  */
-      if (constant_val < 0 && signflag != 1
-          && (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (LD_STOR_INS_INC)
-             || IS_INSN_TYPE (CSTBIT_INS) || IS_INSN_TYPE (STOR_IMM_INS)))
-        {
-          if (crx_ins->arg[number].type == arg_cr
-              || crx_ins->arg[number].type == arg_icr)
-            {
-              crx_ins->arg[number].constant =
-                ~(crx_ins->arg[number].constant) + 1;
-              signflag = 1;
-            }
-        }
-      if (signflag)
-        {
-          /* Signflag in never set in case of load store instructions
-            Mapping in case of only the arithinsn case.  */
-          if ((crx_ins->arg[number].constant != 1
-               && crx_ins->arg[number].constant != 4)
-            || (!IS_INSN_TYPE (ARITH_INS)
-                && !IS_INSN_TYPE (ARITH_BYTE_INS)
-                && !IS_INSN_TYPE (CMPBR_INS)))
-            {
-              /* Counting the number of bits required to represent
-                the constant.  */
-              cnt = 0;
-              temp = crx_ins->arg[number].constant - 1;
-              while (temp > 0)
-                {
-                  temp >>= 1;
-                  cnt++;
-                }
-              crx_ins->arg[number].size = cnt + 1;
-              crx_ins->arg[number].constant =
-                ~(crx_ins->arg[number].constant) + 1;
-              if (IS_INSN_TYPE (ARITH_INS) || IS_INSN_TYPE (ARITH_BYTE_INS))
-                {
-                  char ptr;
-                  LONGLONG temp64;
-
-                 temp64 = strtoull (str, (char **) &ptr, 0);
-                  if (cnt < 4)
-                   crx_ins->arg[number].size = 5;
-
-                  if (IS_INSN_TYPE (ARITH_INS))
-                    {
-                      if (crx_ins->arg[number].size > 32
-                         || (temp64 > ULONG_MAX))
-                       {
-                          if (crx_ins->arg[number].size > 32)
-                           as_bad (_("In Instruction `%s': Immediate size is \
-                                   %lu bits cannot be accomodated"),
-                                   ins_parse, cnt + 1);
-
-                         if (temp64 > ULONG_MAX)
-                           as_bad (_("Value given more than 32 bits in \
-                                   Instruction `%s'"), ins_parse);
-                        }
-                    }
-                  if (IS_INSN_TYPE (ARITH_BYTE_INS))
-                    {
-                      if (crx_ins->arg[number].size > 16
-                         || !((temp64 & 0xFFFF0000) == 0xFFFF0000
-                              || (temp64 & 0xFFFF0000) == 0x0))
-                        {
-                          if (crx_ins->arg[number].size > 16)
-                           as_bad (_("In Instruction `%s': Immediate size is \
-                                   %lu bits cannot be accomodated"),
-                                   ins_parse, cnt + 1);
-
-                         if (!((temp64 & 0xFFFF0000) == 0xFFFF0000
-                               || (temp64 & 0xFFFF0000) == 0x0))
-                           as_bad (_("Value given more than 16 bits in \
-                                   Instruction `%s'"), ins_parse);
-                        }
-                    }
-                }
-              if (IS_INSN_TYPE (LD_STOR_INS) && crx_ins->arg[number].type == arg_cr
-                  && !post_inc_mode)
-                {
-                  /* Cases handled ---
-                    dispub4/dispuw4/dispud4 and for load store dispubwd4
-                    is applicable only.  */
-                  if (crx_ins->arg[number].size <= 4)
-                    crx_ins->arg[number].size = 5;
-                }
-             /* Argument number is checked to distinguish between
-                immediate and displacement in cmpbranch and bcopcond.  */
-              if ((IS_INSN_TYPE (CMPBR_INS) || IS_INSN_TYPE (COP_BRANCH_INS))
-                  && number == 2)
-                {
-                  if (crx_ins->arg[number].size != 32)
-                    crx_ins->arg[number].constant =
-                      crx_ins->arg[number].constant >> 1;
-                }
-
-             mask_const (&crx_ins->arg[number].constant,
-                          (int) crx_ins->arg[number].size);
-            }
-        }
-      else
-        {
-         /* Argument number is checked to distinguish between
-            immediate and displacement in cmpbranch and bcopcond.  */
-          if (((IS_INSN_TYPE (CMPBR_INS) || IS_INSN_TYPE (COP_BRANCH_INS))
-                 && number == 2)
-               || IS_INSN_TYPE (BRANCH_NEQ_INS))
-            {
-              if (IS_INSN_TYPE (BRANCH_NEQ_INS))
-                {
-                  if (crx_ins->arg[number].constant == 0)
-                   as_bad (_("Instruction `%s' has Zero offset"), ins_parse);
-                }
-
-              if (crx_ins->arg[number].constant % 2 != 0)
-               as_bad (_("Instruction `%s' has odd offset"), ins_parse);
-
-              if (IS_INSN_TYPE (BRANCH_NEQ_INS))
-                {
-                  if (crx_ins->arg[number].constant > 32
-                      || crx_ins->arg[number].constant < 2)
-                     as_bad (_("Instruction `%s' has illegal offset (%ld)"),
-                             ins_parse, crx_ins->arg[number].constant);
-
-                 crx_ins->arg[number].constant -= 2;
-                }
-
-              crx_ins->arg[number].constant =
-                crx_ins->arg[number].constant >> 1;
-              get_number_of_bits (crx_ins, number);
-            }
-
-         /* Compare branch argument number zero to be compared -
-            mapped to cst4.  */
-          if (IS_INSN_TYPE (CMPBR_INS) && number == 0)
-            {
-             for (cst4_op = cst4_map; cst4_op < (cst4_map + cst4_maps); cst4_op++)
-               {
-                 if (crx_ins->arg[number].constant == (unsigned int)cst4_op->value)
-                   {
-                     crx_ins->arg[number].constant = cst4_op->binary;
-                     is_cst4 = 1;
-                     break;
-                   }
-               }
-             if (!is_cst4)
-               as_bad (_("Instruction `%s' has invalid imm value as an \
-                         operand"), ins_parse);
-            }
-        }
+      cur_arg->X_op = O_constant;
+      cur_arg->constant = crx_ins->exp.X_add_number;
       break;
 
     case O_symbol:
     case O_subtract:
-      crx_ins->arg[number].constant = 0;
+    case O_add:
+      cur_arg->X_op = O_symbol;
       crx_ins->rtype = BFD_RELOC_NONE;
       relocatable = 1;
 
-      switch (crx_ins->arg[number].type)
+      switch (cur_arg->type)
        {
        case arg_cr:
-          /* Have to consider various cases here --load/stor++[bwd] rbase, reg.  */
           if (IS_INSN_TYPE (LD_STOR_INS_INC))
            crx_ins->rtype = BFD_RELOC_CRX_REGREL12;
           else if (IS_INSN_TYPE (CSTBIT_INS)
                   || IS_INSN_TYPE (STOR_IMM_INS))
-           /* 'stor[bwd] imm' and '[stc]bit[bwd]'.  */
            crx_ins->rtype = BFD_RELOC_CRX_REGREL28;
           else
-           /* General load store instruction.  */
            crx_ins->rtype = BFD_RELOC_CRX_REGREL32;
-           break;
-       case arg_icr:
-         /* Index Mode 22 bits relocation.  */
+         break;
+
+       case arg_idxr:
            crx_ins->rtype = BFD_RELOC_CRX_REGREL22;
          break;
+       
        case arg_c:
-         /* Absolute types.  */
-          /* Case for jumps...dx  types.  */
-          /* For bal.  */
           if (IS_INSN_MNEMONIC ("bal") || IS_INSN_TYPE (DCR_BRANCH_INS))
            crx_ins->rtype = BFD_RELOC_CRX_REL16;
          else if (IS_INSN_TYPE (BRANCH_INS))
-            {
-             crx_ins->rtype = BFD_RELOC_CRX_REL8;
-
-             /* Overriding the above by the br_type_flag set above.  */
-             switch (br_type_flag)
-               {
-               default:
-                 break;
-               case 8:
-                 crx_ins->rtype = BFD_RELOC_CRX_REL8;
-                 break;
-               case 16:
-                 crx_ins->rtype = BFD_RELOC_CRX_REL16;
-                 break;
-               case 32:
-                 crx_ins->rtype = BFD_RELOC_CRX_REL32;
-                 break;
-               }
-            }
+           crx_ins->rtype = BFD_RELOC_CRX_REL8;
           else if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (STOR_IMM_INS)
                   || IS_INSN_TYPE (CSTBIT_INS))
            crx_ins->rtype = BFD_RELOC_CRX_ABS32;
          else if (IS_INSN_TYPE (BRANCH_NEQ_INS))
            crx_ins->rtype = BFD_RELOC_CRX_REL4;
           else if (IS_INSN_TYPE (CMPBR_INS) || IS_INSN_TYPE (COP_BRANCH_INS))
-            {
-              if (cmp_br_type_flag == 24)
-               crx_ins->rtype = BFD_RELOC_CRX_REL24;
-              else
-               crx_ins->rtype = BFD_RELOC_CRX_REL8_CMP;
-            }
+           crx_ins->rtype = BFD_RELOC_CRX_REL8_CMP;
          break;
+       
        case arg_ic:
-       case arg_dc:
           if (IS_INSN_TYPE (ARITH_INS))
            crx_ins->rtype = BFD_RELOC_CRX_IMM32;
          else if (IS_INSN_TYPE (ARITH_BYTE_INS))
@@ -1224,16 +675,15 @@ process_label_constant (char *str, ins * crx_ins, int number)
        default:
          break;
       }
-      crx_ins->arg[number].size = (bfd_reloc_type_lookup (stdoutput, crx_ins->rtype))->bitsize;
       break;
 
     default:
+      cur_arg->X_op = crx_ins->exp.X_op;
       break;
     }
 
-  input_line_pointer = save;
-  crx_ins->arg[number].signflag = signflag;
-  return crx_ins->exp.X_op;
+  input_line_pointer = saved_input_line_pointer;
+  return;
 }
 
 /* Get the values of the scale to be encoded -
@@ -1254,327 +704,208 @@ exponent2scale (int val)
   return exponent;
 }
 
-/* This is used to set the index mode parameters. Used to set the attributes of
-   an indexmode type of operand. op_num is the operand number.  */
+/* Parsing different types of operands
+   -> constants                    Immediate/Absolute/Relative numbers
+   -> Labels               Relocatable symbols
+   -> (rbase)              Register base
+   -> disp(rbase)          Register relative
+   -> disp(rbase)+         Post-increment mode
+   -> disp(rbase,ridx,scl)  Register index mode  */
 
 static void
-set_indexmode_parameters (char *operand, ins * crx_ins, int op_num)
+set_operand (char *operand, ins * crx_ins)
 {
-  char address_str[30];
-  char scale_str[MAX_OPERANDS];
-  int scale_cnt = 0;
-  char reg_name[MAX_REGNAME_LEN];
-  char regindex_name[MAX_REGNAME_LEN];
-  int i = 0;
-  int reg_counter = 0, addr_cnt = 0, temp_int_val = 0;
+  char *operandS; /* Pointer to start of sub-opearand.  */
+  char *operandE; /* Pointer to end of sub-opearand.  */
+  expressionS scale;
+  int scale_val;
+  char *input_save, c;
+  argument *cur_arg = &crx_ins->arg[cur_arg_num]; /* Current argument.  */
+
+  /* Initialize pointers.  */
+  operandS = operandE = operand;
 
-  switch (crx_ins->arg[op_num].type)
+  switch (cur_arg->type)
     {
-    case arg_icr:
-      while (operand[i] != '(')
-        {
-          address_str[addr_cnt++] = operand[i];
-          i++;
-        }
-      address_str[addr_cnt] = '\0';
-      process_label_constant (address_str, crx_ins, op_num);
-      i++;
-      reg_counter = 0;
-      while (operand[i] != ',' && operand[i] != ' ')
-        {
-          reg_name[reg_counter++] = operand[i];
-          i++;
-        }
-      reg_name[reg_counter] = '\0';
-      if ((crx_ins->arg[op_num].r = get_register (reg_name)) == nullregister)
+    case arg_sc:    /* Case *+0x18.  */
+    case arg_ic:    /* Case $0x18.  */
+      operandS++;
+    case arg_c:            /* Case 0x18.  */
+      /* Set constant.  */
+      process_label_constant (operandS, crx_ins);
+      
+      if (cur_arg->type != arg_ic)
+       cur_arg->type = arg_c;
+      break;
+
+    case arg_icr:   /* Case $0x18(r1).  */
+      operandS++;
+    case arg_cr:    /* Case 0x18(r1).   */
+      /* Set displacement constant.  */
+      while (*operandE != '(')
+       operandE++;
+      *operandE = '\0';
+      process_label_constant (operandS, crx_ins);
+      operandS = operandE;    
+    case arg_rbase: /* Case (r1).  */
+      operandS++;
+      /* Set register base.  */
+      while (*operandE != ')')
+       operandE++;
+      *operandE = '\0';
+      if ((cur_arg->r = get_register (operandS)) == nullregister)
        as_bad (_("Illegal register `%s' in Instruction `%s'"),
-               reg_name, ins_parse);
+               operandS, ins_parse);
 
-      i++;
-      while (operand[i] == ' ')
-       i++;
+      if (cur_arg->type != arg_rbase)
+       cur_arg->type = arg_cr;
+      break;
 
-      reg_counter = 0;
-      while (operand[i] != ')' && operand[i] != ',')
-        {
-          regindex_name[reg_counter++] = operand[i];
-          i++;
-        }
-      regindex_name[reg_counter] = '\0';
-      reg_counter = 0;
-      if ((crx_ins->arg[op_num].i_r = get_register (regindex_name))
-           == nullregister)
+    case arg_idxr:
+      /* Set displacement constant.  */
+      while (*operandE != '(')
+       operandE++;
+      *operandE = '\0';
+      process_label_constant (operandS, crx_ins);
+      operandS = ++operandE;
+      
+      /* Set register base.  */
+      while ((*operandE != ',') && (! ISSPACE (*operandE)))
+       operandE++;
+      *operandE++ = '\0';
+      if ((cur_arg->r = get_register (operandS)) == nullregister)
        as_bad (_("Illegal register `%s' in Instruction `%s'"),
-               regindex_name, ins_parse);
+               operandS, ins_parse);
 
-      /* Setting the scale parameters.  */
-      while (operand[i] == ' ')
-       i++;
+      /* Skip leading white space.  */
+      while (ISSPACE (*operandE))
+       operandE++;
+      operandS = operandE;
 
-      if (operand[i] == ')')
-       crx_ins->arg[op_num].scale = 0;
+      /* Set register index.  */
+      while ((*operandE != ')') && (*operandE != ','))
+       operandE++;
+      c = *operandE;
+      *operandE++ = '\0';
+
+      if ((cur_arg->i_r = get_register (operandS)) == nullregister)
+       as_bad (_("Illegal register `%s' in Instruction `%s'"),
+               operandS, ins_parse);
+
+      /* Skip leading white space.  */
+      while (ISSPACE (*operandE))
+       operandE++;
+      operandS = operandE;
+
+      /* Set the scale.  */
+      if (c == ')')
+       cur_arg->scale = 0;
       else
         {
-          if (operand[i] == ',')
-            i++;
+         while (*operandE != ')')
+           operandE++;
+         *operandE = '\0';
 
-          while (operand[i] != ' ' && operand[i] != ')')
-            {
-              scale_str[scale_cnt++] = operand[i];
-              i++;
-            }
+         /* Preprocess the scale string.  */
+         input_save = input_line_pointer;
+         input_line_pointer = operandS;
+         expression (&scale);
+         input_line_pointer = input_save;
 
-          scale_str[scale_cnt] = '\0';
-          /* Preprocess the scale string.  */
-          if (strstr (scale_str, "0x") != NULL
-              || strstr (scale_str, "0X") != NULL)
-            {
-              sscanf (scale_str, "%x", &temp_int_val);
-             memset (&scale_str, '\0', sizeof (scale_str));
-              sprintf (scale_str, "%d", temp_int_val);
-            }
-          /* Preprocess over.  */
-          temp_int_val = atoi (scale_str);
+         scale_val = scale.X_add_number;
 
-          if (temp_int_val != 1 && temp_int_val != 2
-              && temp_int_val != 4 && temp_int_val != 8)
-           as_bad (_("Illegal Scale - `%s'"), scale_str);
+         /* Check if the scale value is legal.  */
+          if (scale_val != 1 && scale_val != 2
+              && scale_val != 4 && scale_val != 8)
+           as_bad (_("Illegal Scale - `%d'"), scale_val);
 
-         crx_ins->arg[op_num].scale = exponent2scale (temp_int_val);
+         cur_arg->scale = exponent2scale (scale_val);
         }
       break;
+
     default:
       break;
     }
 }
 
-/* Parsing the operands of types
-   - constants
-   - rbase -> (register)
-   - offset(rbase)
-   - offset(rbase)+ - post increment mode.  */
+/* Parse a single operand.
+   operand - Current operand to parse.
+   crx_ins - Current assembled instruction.  */
 
 static void
-set_cons_rparams (char *operand, ins * crx_ins, int op_num)
+parse_operand (char *operand, ins * crx_ins)
 {
-  int i = 0, reg_count = 0;
-  char reg_name[MAX_REGNAME_LEN];
-  int change_flag = 0;
+  int ret_val;
+  argument *cur_arg = &crx_ins->arg[cur_arg_num]; /* Current argument.  */
 
-  if (crx_ins->arg[op_num].type == arg_dc)
-    change_flag = 1;
+  /* Initialize the type to NULL before parsing.  */
+  cur_arg->type = nullargs;
 
-  switch (crx_ins->arg[op_num].type)
+  /* Check whether this is a general processor register.  */
+  if ((ret_val = get_register (operand)) != nullregister)
     {
-    case arg_sc: /* Case *+347.  */
-    case arg_dc: /* Case $18.  */
-      i++;
-    case arg_c:/* Case where its a simple constant.  */
-      process_label_constant (operand + i, crx_ins, op_num);
-      crx_ins->arg[op_num].type = arg_c;
-      break;
-    case arg_dcr: /* Case $9(r13).  */
-      operand++;
-    case arg_cr: /* Case 9(r13.   */
-      while (operand[i] != '(')
-       i++;
-      operand[i] = '\0';
-      process_label_constant (operand, crx_ins, op_num);
-      operand[i] = '(';
-      i++;
-      reg_count = 0;
-      while (operand[i] != ')')
-        {
-          reg_name[reg_count] = operand[i];
-          i++;
-          reg_count++;
-        }
-      reg_name[reg_count] = '\0';
-      if ((crx_ins->arg[op_num].r = get_register (reg_name)) == nullregister)
-       as_bad (_("Illegal register `%s' in Instruction `%s'"),
-               reg_name, ins_parse);
-
-      crx_ins->arg[op_num].type = arg_cr;
-      /* Post increment is represented in assembly as offset (register)+.  */
-      if (strstr (operand + i, "+") != NULL)
-       /* There is a plus after the ')'.  */
-       post_inc_mode = 1;
-      break;
-    default:
-      break;
+      cur_arg->type = arg_r;
+      cur_arg->r = ret_val;
+      cur_arg->X_op = O_register;
+      return;
     }
-  if (change_flag == 1)
-    crx_ins->arg[op_num].type = arg_ic;
-}
 
-/* This is used to get the operand attributes -
-   operand  - current operand to be used
-   number - operand number
-   crx_ins - current assembled instruction.  */
-
-static void
-get_operandtype (char *operand, int number, ins * crx_ins)
-{
-  int ret_val;
-  char temp_operand[30];
+  /* Check whether this is a core [special] coprocessor register.  */
+  if ((ret_val = get_copregister (operand)) != nullcopregister)
+    {
+      cur_arg->type = arg_copr;
+      if (ret_val >= cs0)
+       cur_arg->type = arg_copsr;
+      cur_arg->cr = ret_val;
+      cur_arg->X_op = O_register;
+      return;
+    }
 
+  /* Deal with special characters.  */
   switch (operand[0])
     {
-    /* When it is a register.  */
-    case 'r':
-    case 'c':
-    case 'i':
-    case 'u':
-    case 's':
-    case 'p':
-    case 'l':
-    case 'h':
-      /* Check whether this is a general processor register.  */
-      ret_val = get_register (operand);
-      if (ret_val != nullregister)
-        {
-          crx_ins->arg[number].type = arg_r;
-          crx_ins->arg[number].r = ret_val;
-          crx_ins->arg[number].size = REG_SIZE;
-        }
-      else
-        {
-         /* Check whether this is a core [special] coprocessor register.  */
-          ret_val = get_copregister (operand);
-          if (ret_val != nullcopregister)
-            {
-              crx_ins->arg[number].type = arg_copr;
-              if (ret_val >= cs0)
-               crx_ins->arg[number].type = arg_copsr;
-              crx_ins->arg[number].cr = ret_val;
-              crx_ins->arg[number].size = REG_SIZE;
-            }
-          else
-            {
-              if (strchr (operand, '(') != NULL)
-                {
-                  if (strchr (operand, ',') != NULL
-                      && (strchr (operand, ',') > strchr (operand, '(')))
-                    {
-                      crx_ins->arg[number].type = arg_icr;
-                      crx_ins->arg[number].constant = 0;
-                      set_indexmode_parameters (operand, crx_ins, number);
-                      get_number_of_bits (crx_ins, number);
-                      return;
-                    }
-                  else
-                   crx_ins->arg[number].type = arg_cr;
-                }
-              else
-               crx_ins->arg[number].type = arg_c;
-              crx_ins->arg[number].constant = 0;
-              set_cons_rparams (operand, crx_ins, number);
-              get_number_of_bits (crx_ins, number);
-            }
-        }
-      break;
     case '$':
       if (strchr (operand, '(') != NULL)
-       crx_ins->arg[number].type = arg_dcr;
+       cur_arg->type = arg_icr;
       else
-        crx_ins->arg[number].type = arg_dc;
-      crx_ins->arg[number].constant = 0;
-      set_cons_rparams (operand, crx_ins, number);
-      get_number_of_bits (crx_ins, number);
+        cur_arg->type = arg_ic;
+      goto set_params;
       break;
 
-    case '(':
-      /* Augmenting a zero in front of an operand -- won't work for tbit/sbit.  */
-      strcpy (temp_operand, "0");
-      strcat (temp_operand, operand);
-      if (strchr (temp_operand, ',') != NULL
-          && (strchr (temp_operand, ',') > strchr (temp_operand, '(')))
-        {
-          crx_ins->arg[number].type = arg_icr;
-          crx_ins->arg[number].constant = 0;
-          set_indexmode_parameters (temp_operand, crx_ins, number);
-          get_number_of_bits (crx_ins, number);
-          return;
-        }
-      else
-        {
-          crx_ins->arg[number].type = arg_cr;
-          crx_ins->arg[number].constant = 0;
-          set_cons_rparams (temp_operand, crx_ins, number);
-          get_number_of_bits (crx_ins, number);
-          if ((! strneq (instruction->mnemonic, "load", 4))
-              && (! strneq (instruction->mnemonic, "stor", 4)))
-            {
-              crx_ins->arg[number].type = arg_rbase;
-              crx_ins->arg[number].size = REG_SIZE;
-            }
-          return;
-        }
-      break;
     case '*':
-      crx_ins->arg[number].type = arg_sc;
-      crx_ins->arg[number].constant = 0;
-      set_cons_rparams (operand, crx_ins, number);
-      get_number_of_bits (crx_ins, number);
+      cur_arg->type = arg_sc;
+      goto set_params;
       break;
-    case '+':
-    case '-':
-    case '0':
-    case '1':
-    case '2':
-    case '3':
-    case '4':
-    case '5':
-    case '6':
-    case '7':
-    case '8':
-    case '9':
-      if (strchr (operand, '(') != NULL)
-        {
-          if (strchr (operand, ',') != NULL
-              && (strchr (operand, ',') > strchr (operand, '(')))
-            {
-              crx_ins->arg[number].type = arg_icr;
-              crx_ins->arg[number].constant = 0;
-              set_indexmode_parameters (operand, crx_ins, number);
-              get_number_of_bits (crx_ins, number);
-              return;
-            }
-          else
-           crx_ins->arg[number].type = arg_cr;
-        }
-      else
-       crx_ins->arg[number].type = arg_c;
-      crx_ins->arg[number].constant = 0;
-      set_cons_rparams (operand, crx_ins, number);
-      get_number_of_bits (crx_ins, number);
+
+    case '(':
+      cur_arg->type = arg_rbase;
+      goto set_params;
       break;
+
     default:
-      if (strchr (operand, '(') != NULL)
-        {
-          if (strchr (operand, ',') != NULL
-              && (strchr (operand, ',') > strchr (operand, '(')))
-            {
-              crx_ins->arg[number].type = arg_icr;
-              crx_ins->arg[number].constant = 0;
-              set_indexmode_parameters (operand, crx_ins, number);
-              get_number_of_bits (crx_ins, number);
-              return;
-            }
-          else
-           crx_ins->arg[number].type = arg_cr;
-        }
+       break;
+    }
+      
+  if (strchr (operand, '(') != NULL)
+    {
+      if (strchr (operand, ',') != NULL
+          && (strchr (operand, ',') > strchr (operand, '(')))
+           cur_arg->type = arg_idxr;
       else
-       crx_ins->arg[number].type = arg_c;
-      crx_ins->arg[number].constant = 0;
-      set_cons_rparams (operand, crx_ins, number);
-      get_number_of_bits (crx_ins, number);
-      break;
+       cur_arg->type = arg_cr;
     }
+  else
+    cur_arg->type = arg_c;
+  goto set_params;
+
+/* Parse an operand according to its type.  */
+set_params:
+  cur_arg->constant = 0;
+  set_operand (operand, crx_ins);
 }
 
-/* Operands are parsed over here, separated into various operands. Each operand
-   is then analyzed to fillup the fields in the crx_ins data structure.  */
+/* Parse the various operands. Each operand is then analyzed to fillup 
+   the fields in the crx_ins data structure.  */
 
 static void
 parse_operands (ins * crx_ins, char *operands)
@@ -1640,10 +971,11 @@ parse_operands (ins * crx_ins, char *operands)
   if (bracket_flag || sq_bracket_flag)
     as_fatal (_("Missing matching brackets : `%s'"), ins_parse);
 
-  /* Now to recongnize the operand types.  */
+  /* Now we parse each operand separately.  */
   for (op_num = 0; op_num < crx_ins->nargs; op_num++)
     {
-      get_operandtype (operand[op_num], op_num, crx_ins);
+      cur_arg_num = op_num;
+      parse_operand (operand[op_num], crx_ins);
       free (operand[op_num]);
     }
 
@@ -1655,7 +987,7 @@ parse_operands (ins * crx_ins, char *operands)
    This routine is used by assembling the 'excp' instruction.  */
 
 static int
-gettrap (char *s)
+gettrap (const char *s)
 {
   const trap_entry *trap;
 
@@ -1675,20 +1007,27 @@ gettrap (char *s)
    Otherwise, the insn will be mistakenly identified as of type LD_STOR_INS.  */
 
 static void
-handle_LoadStor (char *operands)
+handle_LoadStor (const char *operands)
 {
-  /* Assuming Store-Immediate insn has the following format :
-     'MNEMONIC $DISP, ...' (e.g. 'storb $1, 12(r5)').
-     STOR_IMM_INS are the only store insns containing a dollar sign ($).  */
-  if (strstr (operands, "$") != NULL)
-    while (! IS_INSN_TYPE (STOR_IMM_INS))
-      instruction++;
+  /* Post-Increment instructions precede Store-Immediate instructions in 
+     CRX instruction table, hence they are handled before. 
+     This synchronization should be kept.  */
 
   /* Assuming Post-Increment insn has the following format :
      'MNEMONIC DISP(REG)+, REG' (e.g. 'loadw 12(r5)+, r6').
      LD_STOR_INS_INC are the only store insns containing a plus sign (+).  */
   if (strstr (operands, ")+") != NULL)
-    while (! IS_INSN_TYPE (LD_STOR_INS_INC))
+    {
+      while (! IS_INSN_TYPE (LD_STOR_INS_INC))
+       instruction++;
+      return;
+    }
+
+  /* Assuming Store-Immediate insn has the following format :
+     'MNEMONIC $DISP, ...' (e.g. 'storb $1, 12(r5)').
+     STOR_IMM_INS are the only store insns containing a dollar sign ($).  */
+  if (strstr (operands, "$") != NULL)
+    while (! IS_INSN_TYPE (STOR_IMM_INS))
       instruction++;
 }
 
@@ -1699,14 +1038,26 @@ handle_LoadStor (char *operands)
 static void
 parse_insn (ins *insn, char *operands)
 {
-  /* Handle 'excp'/'cinv' */
+  int i;
+
+  /* Handle instructions with no operands.  */
+  for (i = 0; no_op_insn[i] != NULL; i++)
+  {
+    if (streq (no_op_insn[i], instruction->mnemonic))
+    {
+      insn->nargs = 0;
+      return;
+    }
+  }
+
+  /* Handle 'excp'/'cinv' instructions.  */
   if (IS_INSN_MNEMONIC ("excp") || IS_INSN_MNEMONIC ("cinv"))
     {
       insn->nargs = 1;
       insn->arg[0].type = arg_ic;
-      insn->arg[0].size = 4;
       insn->arg[0].constant = IS_INSN_MNEMONIC ("excp") ?
        gettrap (operands) : get_cinv_parameters (operands);
+      insn->arg[0].X_op = O_constant;
       return;
     }
 
@@ -1721,9 +1072,9 @@ parse_insn (ins *insn, char *operands)
 /* Cinv instruction requires special handling.  */
 
 static int
-get_cinv_parameters (char * operand)
+get_cinv_parameters (const char *operand)
 {
-  char *p = operand;
+  const char *p = operand;
   int d_used = 0, i_used = 0, u_used = 0, b_used = 0;
 
   while (*++p != ']')
@@ -1756,24 +1107,20 @@ get_cinv_parameters (char * operand)
 static int
 getreg_image (reg r)
 {
-  const reg_entry *reg;
+  const reg_entry *rreg;
   char *reg_name;
-  int special_register_flag = 0;
-  int movpr_flag = 0; /* Nonzero means current mnemonic is 'mtpr'/'mfpr' */
-
-  if (IS_INSN_MNEMONIC ("mtpr") || IS_INSN_MNEMONIC ("mfpr"))
-    movpr_flag = 1;
+  int is_procreg = 0; /* Nonzero means argument should be processor reg.  */
 
-  if (((IS_INSN_MNEMONIC ("mtpr")) && (processing_arg_number == 1))
-      || ((IS_INSN_MNEMONIC ("mfpr")) && (processing_arg_number == 0)) )
-    special_register_flag = 1;
+  if (((IS_INSN_MNEMONIC ("mtpr")) && (cur_arg_num == 1))
+      || ((IS_INSN_MNEMONIC ("mfpr")) && (cur_arg_num == 0)) )
+    is_procreg = 1;
 
   /* Check whether the register is in registers table.  */
   if (r < MAX_REG)
-    reg = &crx_regtab[r];
+    rreg = &crx_regtab[r];
   /* Check whether the register is in coprocessor registers table.  */
-  else if (r < MAX_COPREG)
-    reg = &crx_copregtab[r-MAX_REG];
+  else if (r < (int) MAX_COPREG)
+    rreg = &crx_copregtab[r-MAX_REG];
   /* Register not found.  */
   else
     {
@@ -1781,7 +1128,7 @@ getreg_image (reg r)
       return 0;
     }
 
-  reg_name = reg->name;
+  reg_name = rreg->name;
 
 /* Issue a error message when register is illegal.  */
 #define IMAGE_ERR \
@@ -1789,24 +1136,31 @@ getreg_image (reg r)
            reg_name, ins_parse);                            \
   break;
 
-  switch (reg->type)
+  switch (rreg->type)
   {
     case CRX_U_REGTYPE:
+      if (is_procreg || (instruction->flags & USER_REG))
+       return rreg->image;
+      else
+       IMAGE_ERR;
+
     case CRX_CFG_REGTYPE:
-    case CRX_MTPR_REGTYPE:
-      if (movpr_flag && special_register_flag)
-       return reg->image;
+      if (is_procreg)
+       return rreg->image;
       else
        IMAGE_ERR;
 
     case CRX_R_REGTYPE:
-    case CRX_C_REGTYPE:
-    case CRX_CS_REGTYPE:
-      if (!(movpr_flag && special_register_flag))
-       return reg->image;
+      if (! is_procreg)
+       return rreg->image;
       else
        IMAGE_ERR;
 
+    case CRX_C_REGTYPE:
+    case CRX_CS_REGTYPE:
+      return rreg->image;
+      break;
+
     default:
       IMAGE_ERR;
   }
@@ -1814,34 +1168,11 @@ getreg_image (reg r)
   return 0;
 }
 
-/* Routine used to get the binary-string equivalent of a integer constant
-   which currently require currbits to represent itself to be extended to
-   nbits.  */
+/* Routine used to represent integer X using NBITS bits.  */
 
-static unsigned long int
-getconstant (unsigned long int x, int nbits)
+static long
+getconstant (long x, int nbits)
 {
-  int cnt = 0;
-  unsigned long int temp = x;
-
-  while (temp > 0)
-    {
-      temp >>= 1;
-      cnt++;
-    }
-
-  /* Escape sequence to next 16bit immediate.  */
-  if (cnt > nbits)
-    as_bad (_("Value `%ld' truncated to fit `%d' bits in instruction `%s'"),
-           x, cnt, ins_parse);
-  else
-    {
-      if (signflag)
-       x |= SET_BITS_MASK (cnt, nbits - cnt);
-      else
-       x &= CLEAR_BITS_MASK (cnt, nbits - cnt);
-    }
-
   /* The following expression avoids overflow if
      'nbits' is the number of bits in 'bfd_vma'.  */
   return (x & ((((1 << (nbits - 1)) - 1) << 1) | 1));
@@ -1891,9 +1222,17 @@ print_constant (int nbits, int shift, argument *arg)
          break;
        }
 
-      /* When instruction size is 3, a 16-bit constant is always
-        filling the upper part of output_opcode[1].  */
-      if (instruction->size > 2)
+      /* When instruction size is 3 and 'shift' is 16, a 16-bit constant is 
+        always filling the upper part of output_opcode[1]. If we mistakenly 
+        write it to output_opcode[0], the constant prefix (that is, 'match')
+        will be overridden.
+                0         1         2         3
+           +---------+---------+---------+---------+
+           | 'match' |         | X X X X |         |
+           +---------+---------+---------+---------+
+             output_opcode[0]    output_opcode[1]     */
+
+      if ((instruction->size > 2) && (shift == WORD_SHIFT))
        CRX_PRINT (1, constant, WORD_SHIFT);
       else
        CRX_PRINT (0, constant, shift);
@@ -1934,18 +1273,16 @@ print_operand (int nbits, int shift, argument *arg)
       CRX_PRINT (0, getreg_image (arg->cr), shift);
       break;
 
-    case arg_ic:
-      print_constant (nbits, shift, arg);
-      break;
-
-    case arg_icr:
+    case arg_idxr:
       /*    16      12       8    6         0
            +--------------------------------+
-           |  reg   | r_base | scl|  disp   |
+           | r_base | r_idx  | scl|  disp   |
            +--------------------------------+    */
       CRX_PRINT (0, getreg_image (arg->r), 12);
       CRX_PRINT (0, getreg_image (arg->i_r), 8);
       CRX_PRINT (0, arg->scale, 6);
+    case arg_ic:
+    case arg_c:
       print_constant (nbits, shift, arg);
       break;
 
@@ -1955,20 +1292,15 @@ print_operand (int nbits, int shift, argument *arg)
 
     case arg_cr:
       /* case base_cst4.  */
-      if ((instruction->flags & CST4MAP) && cst4flag)
-       output_opcode[0] |= (getconstant (arg->constant, nbits)
-                            << (shift + REG_SIZE));
+      if (instruction->flags & DISPU4MAP)
+       print_constant (nbits, shift + REG_SIZE, arg);
       else
-       /* rbase_dispu<NN> and other such cases.  */
+       /* rbase_disps<NN> and other such cases.  */
        print_constant (nbits, shift, arg);
       /* Add the register argument to the output_opcode.  */
       CRX_PRINT (0, getreg_image (arg->r), shift);
       break;
 
-    case arg_c:
-      print_constant (nbits, shift, arg);
-      break;
-
     default:
       break;
     }
@@ -1986,369 +1318,407 @@ get_number_of_operands (void)
   return i;
 }
 
-/* Assemble a single instruction :
-   Instruction has been parsed and all operand values set appropriately.
-   Algorithm for assembling -
-   For instruction to be assembled:
-    Step 1: Find instruction in the array crx_instruction with same mnemonic.
-    Step 2: Find instruction with same operand types.
-    Step 3: If (size_of_operands) match then done, else increment the
-           array_index and goto Step3.
-    Step 4: Cannot assemble
+/* Verify that the number NUM can be represented in BITS bits (that is, 
+   within its permitted range), based on the instruction's FLAGS.  
+   If UPDATE is nonzero, update the value of NUM if necessary.
+   Return OP_LEGAL upon success, actual error type upon failure.  */
+
+static op_err
+check_range (long *num, int bits, int unsigned flags, int update)
+{
+  long min, max;
+  int retval = OP_LEGAL;
+  int bin;
+  long upper_64kb = 0xFFFF0000;
+  long value = *num;
+
+  /* For hosts witah longs bigger than 32-bits make sure that the top 
+     bits of a 32-bit negative value read in by the parser are set,
+     so that the correct comparisons are made.  */
+  if (value & 0x80000000)
+    value |= (-1L << 31);
+
+  /* Verify operand value is even.  */
+  if (flags & OP_EVEN)
+    {
+      if (value % 2)
+       return OP_NOT_EVEN;
+    }
+
+  if (flags & OP_UPPER_64KB)
+    {
+      /* Check if value is to be mapped to upper 64 KB memory area.  */
+      if ((value & upper_64kb) == upper_64kb)
+       {
+         value -= upper_64kb;
+         if (update)
+           *num = value;
+       }
+      else
+       return OP_NOT_UPPER_64KB;
+    }
+
+  if (flags & OP_SHIFT)
+    {
+      value >>= 1;
+      if (update)
+       *num = value;
+    }
+  else if (flags & OP_SHIFT_DEC)
+    {
+      value = (value >> 1) - 1;
+      if (update)
+       *num = value;
+    }
+
+  if (flags & OP_ESC)
+    {
+      /* 0x7e and 0x7f are reserved escape sequences of dispe9.  */
+      if (value == 0x7e || value == 0x7f)
+       return OP_OUT_OF_RANGE;
+    }
+
+  if (flags & OP_DISPU4)
+    {
+      int is_dispu4 = 0;
+
+      int mul = (instruction->flags & DISPUB4) ? 1 
+               : (instruction->flags & DISPUW4) ? 2
+               : (instruction->flags & DISPUD4) ? 4 : 0;
+      
+      for (bin = 0; bin < cst4_maps; bin++)
+       {
+         if (value == (mul * bin))
+           {
+             is_dispu4 = 1;
+             if (update)
+               *num = bin;
+             break;
+           }
+       }
+      if (!is_dispu4)
+       retval = OP_ILLEGAL_DISPU4;
+    }
+  else if (flags & OP_CST4)
+    {
+      int is_cst4 = 0;
+
+      for (bin = 0; bin < cst4_maps; bin++)
+       {
+         if (value == cst4_map[bin])
+           {
+             is_cst4 = 1;
+             if (update)
+               *num = bin;
+             break;
+           }
+       }
+      if (!is_cst4)
+       retval = OP_ILLEGAL_CST4;
+    }
+  else if (flags & OP_SIGNED)
+    {
+      max = (1 << (bits - 1)) - 1;
+      min = - (1 << (bits - 1));
+      if ((value > max) || (value < min))
+       retval = OP_OUT_OF_RANGE;
+    }
+  else if (flags & OP_UNSIGNED)
+    {
+      max = ((((1 << (bits - 1)) - 1) << 1) | 1);
+      min = 0;
+      if (((unsigned long) value > (unsigned long) max) 
+           || ((unsigned long) value < (unsigned long) min))
+       retval = OP_OUT_OF_RANGE;
+    }
+  return retval;
+}
+
+/* Assemble a single instruction:
+   INSN is already parsed (that is, all operand values and types are set).
+   For instruction to be assembled, we need to find an appropriate template in 
+   the instruction table, meeting the following conditions:
+    1: Has the same number of operands.
+    2: Has the same operand types.
+    3: Each operand size is sufficient to represent the instruction's values.
    Returns 1 upon success, 0 upon failure.  */
 
 static int
 assemble_insn (char *mnemonic, ins *insn)
 {
-  /* Argument type of each operand in the instruction we are looking for.  */
-  argtype atyp[MAX_OPERANDS];
-  /* Argument type of each operand in the current instruction.  */
-  argtype atyp_act[MAX_OPERANDS];
-  /* Size (in bits) of each operand in the instruction we are looking for.  */
-  int bits[MAX_OPERANDS];
-  /* Size (in bits) of each operand in the current instruction.  */
-  int bits_act[MAX_OPERANDS];
-  /* Location (in bits) of each operand in the current instruction.  */
-  int shift_act[MAX_OPERANDS];
+  /* Type of each operand in the current template.  */
+  argtype cur_type[MAX_OPERANDS];
+  /* Size (in bits) of each operand in the current template.  */
+  unsigned int cur_size[MAX_OPERANDS];
+  /* Flags of each operand in the current template.  */
+  unsigned int cur_flags[MAX_OPERANDS];
+  /* Instruction type to match.  */
+  unsigned int ins_type;
+  /* Boolean flag to mark whether a match was found.  */
   int match = 0;
-  int done_flag = 0;
-  int cst4maptype = 0;
-  int changed_already = 0;
-  unsigned int temp_value = 0;
-  int instrtype, i;
-  /* A pointer to the argument's constant value.  */
-  unsigned long int *cons;
-  /* Pointer to loop over all cst4_map entries.  */
-  const cst4_entry *cst4_op;
-
-  /* Instruction has no operands -> copy only the constant opcode.   */
+  int i;
+  /* Nonzero if an instruction with same number of operands was found.  */
+  int found_same_number_of_operands = 0;
+  /* Nonzero if an instruction with same argument types was found.  */
+  int found_same_argument_types = 0;
+  /* Nonzero if a constant was found within the required range.  */
+  int found_const_within_range  = 0;
+  /* Argument number of an operand with invalid type.  */
+  int invalid_optype = -1;
+  /* Argument number of an operand with invalid constant value.  */
+  int invalid_const  = -1;
+  /* Operand error (used for issuing various constant error messages).  */
+  op_err op_error, const_err = OP_LEGAL;
+
+/* Retrieve data (based on FUNC) for each operand of a given instruction.  */
+#define GET_CURRENT_DATA(FUNC, ARRAY)                            \
+  for (i = 0; i < insn->nargs; i++)                              \
+    ARRAY[i] = FUNC (instruction->operands[i].op_type)
+
+#define GET_CURRENT_TYPE    GET_CURRENT_DATA(get_optype, cur_type)
+#define GET_CURRENT_SIZE    GET_CURRENT_DATA(get_opbits, cur_size)
+#define GET_CURRENT_FLAGS   GET_CURRENT_DATA(get_opflags, cur_flags)
+
+  /* Instruction has no operands -> only copy the constant opcode.   */
   if (insn->nargs == 0)
     {
       output_opcode[0] = BIN (instruction->match, instruction->match_bits);
       return 1;
     }
 
-  /* Find instruction with same number of operands.  */
-  while (get_number_of_operands () != insn->nargs
-         && IS_INSN_MNEMONIC (mnemonic))
-    instruction++;
-
-  if (!IS_INSN_MNEMONIC (mnemonic))
-    return 0;
-
-  /* Initialize argument type and size of each given operand.  */
-  for (i = 0; i < insn->nargs; i++)
-    {
-      atyp[i] = insn->arg[i].type;
-      bits[i] = insn->arg[i].size;
-    }
-
-  /* Initialize argument type and size of each operand in current inst.  */
-  GET_ACTUAL_TYPE;
-  GET_ACTUAL_SIZE;
+  /* In some case, same mnemonic can appear with different instruction types.
+     For example, 'storb' is supported with 3 different types :
+     LD_STOR_INS, LD_STOR_INS_INC, STOR_IMM_INS.
+     We assume that when reaching this point, the instruction type was 
+     pre-determined. We need to make sure that the type stays the same
+     during a search for matching instruction.  */
+  ins_type = CRX_INS_TYPE(instruction->flags);
 
-  while (match != 1
+  while (/* Check that match is still not found.  */
+        match != 1
         /* Check we didn't get to end of table.  */
         && instruction->mnemonic != NULL
         /* Check that the actual mnemonic is still available.  */
-        && IS_INSN_MNEMONIC (mnemonic))
+        && IS_INSN_MNEMONIC (mnemonic)
+        /* Check that the instruction type wasn't changed.  */
+        && IS_INSN_TYPE(ins_type))
     {
-      /* Check for argement type compatibility.  */
+      /* Check whether number of arguments is legal.  */
+      if (get_number_of_operands () != insn->nargs)
+       goto next_insn;
+      found_same_number_of_operands = 1;
+
+      /* Initialize arrays with data of each operand in current template.  */
+      GET_CURRENT_TYPE;
+      GET_CURRENT_SIZE;
+      GET_CURRENT_FLAGS;
+
+      /* Check for type compatibility.  */
       for (i = 0; i < insn->nargs; i++)
         {
-          if (atyp_act[i] == atyp[i])
-           done_flag = 1;
-          else
-            {
-              done_flag = 0;
-              break;
-            }
-        }
-      if (done_flag)
-        {
-          /* Check for post inc mode of the current instruction.  */
-          if (post_inc_mode == 1 || IS_INSN_TYPE (LD_STOR_INS_INC))
-            done_flag = (post_inc_mode == IS_INSN_TYPE (LD_STOR_INS_INC));
-        }
-
-      if (done_flag)
-       {
-         for (i = 0; i < insn->nargs; i++)
+         if (cur_type[i] != insn->arg[i].type)
            {
-             if (((instruction->operands[i].op_type == us3)
-                   || (instruction->operands[i].op_type == us4)
-                   || (instruction->operands[i].op_type == us5))
-                 && (insn->arg[i].signflag == 1))
-                 {
-                   done_flag = 0;
-                   break;
-                 }
+             if (invalid_optype == -1)
+               invalid_optype = i + 1;
+             goto next_insn;
            }
        }
+      found_same_argument_types = 1;
 
-      if (done_flag == 0)
-        {
-         /* Try again with next instruction.  */
-          instruction++;
-         GET_ACTUAL_TYPE;
-         GET_ACTUAL_SIZE;
-          continue;
-        }
-      else
-        {
-          /* Check for size compatibility.  */
-          for (i = 0; i < insn->nargs; i++)
-            {
-              if (bits[i] > bits_act[i])
-                {
-                 /* Actual size is too small - try again.  */
-                  done_flag = 0;
-                  instruction++;
-                 GET_ACTUAL_TYPE;
-                 GET_ACTUAL_SIZE;
-                  break;
-                }
-            }
+      for (i = 0; i < insn->nargs; i++)
+       {
+         /* Reverse the operand indices for certain opcodes:
+            Index 0      -->> 1
+            Index 1      -->> 0        
+            Other index  -->> stays the same.  */
+         int j = instruction->flags & REVERSE_MATCH ? 
+                 i == 0 ? 1 : 
+                 i == 1 ? 0 : i : 
+                 i;
+
+         /* Only check range - don't update the constant's value, since the 
+            current instruction may not be the last we try to match.  
+            The constant's value will be updated later, right before printing 
+            it to the object file.  */
+         if ((insn->arg[j].X_op == O_constant) 
+              && (op_error = check_range (&insn->arg[j].constant, cur_size[j], 
+                                          cur_flags[j], 0)))
+           {
+             if (invalid_const == -1)
+             {
+               invalid_const = j + 1;
+               const_err = op_error;
+             }
+             goto next_insn;
+           }
+         /* For symbols, we make sure the relocation size (which was already 
+            determined) is sufficient.  */
+         else if ((insn->arg[j].X_op == O_symbol)
+                   && ((bfd_reloc_type_lookup (stdoutput, insn->rtype))->bitsize 
+                        > cur_size[j]))
+                 goto next_insn;
+       }
+      found_const_within_range = 1;
 
-        }
+      /* If we got till here -> Full match is found.  */
+      match = 1;
+      break;
 
-      if (done_flag == 1)
-        {
-         /* Full match is found.  */
-          match = 1;
-          break;
-        }
+/* Try again with next instruction.  */
+next_insn:
+      instruction++;
     }
 
-  if (match == 0)
-    /* We haven't found a match - instruction can't be assembled.  */
-    return 0;
-  else
-    /* Full match - print the final image.  */
+  if (!match)
     {
-      /* Error checking for Co-Processor instructions : 
-        The internal coprocessor 0 can only accept the 
-        "mtcr" and "mfcr" instructions.  */
-      if (IS_INSN_TYPE (COP_REG_INS) || IS_INSN_TYPE (COPS_REG_INS)
-         || IS_INSN_TYPE (COP_BRANCH_INS))
+      /* We haven't found a match - instruction can't be assembled.  */
+      if (!found_same_number_of_operands)
+       as_bad (_("Incorrect number of operands"));
+      else if (!found_same_argument_types)
+       as_bad (_("Illegal type of operand (arg %d)"), invalid_optype);
+      else if (!found_const_within_range)
+      {
+       switch (const_err)
        {
-         /* The coprocessor id is always the first argument.  */
-         if ((instruction->operands[0].op_type == us4)
-             && (insn->arg[0].constant == 0)
-             && (! IS_INSN_MNEMONIC ("mtcr")
-                 && ! IS_INSN_MNEMONIC ("mfcr")))
-           {
-             as_bad (_("Internal Coprocessor 0 doesn't support instruction `%s'"), 
-                       mnemonic);
-           }
+       case OP_OUT_OF_RANGE:
+         as_bad (_("Operand out of range (arg %d)"), invalid_const);
+         break;
+       case OP_NOT_EVEN:
+         as_bad (_("Operand has odd displacement (arg %d)"), invalid_const);
+         break;
+       case OP_ILLEGAL_DISPU4:
+         as_bad (_("Invalid DISPU4 operand value (arg %d)"), invalid_const);
+         break;
+       case OP_ILLEGAL_CST4:
+         as_bad (_("Invalid CST4 operand value (arg %d)"), invalid_const);
+         break;
+       case OP_NOT_UPPER_64KB:
+         as_bad (_("Operand value is not within upper 64 KB (arg %d)"), 
+                   invalid_const);
+         break;
+       default:
+         as_bad (_("Illegal operand (arg %d)"), invalid_const);
+         break;
        }
-      /* Handle positive constants.  */
-      if (!signflag)
-        {
-          if (IS_INSN_TYPE (LD_STOR_INS) && !relocatable)
-            {
-              /* Get the map type of the instruction.  */
-              instrtype = instruction->flags & REVERSE_MATCH ? 0 : 1;
-             cons = &insn->arg[instrtype].constant;
-              cst4maptype = instruction->flags & CST4MAP;
-
-             switch (cst4maptype)
-               {
-               case DISPUB4:
-                 /* 14 and 15 are reserved escape sequences of dispub4.  */
-                  if (*cons == 14 || *cons == 15)
-                    {
-                      instruction++;
-                     GET_ACTUAL_SIZE;
-                    }
-                 break;
-
-               case DISPUW4:
-                 /* Mapping has to be done.  */
-                 if (*cons <= 15 && *cons % 2 != 0)
-                    {
-                      instruction++;
-                     GET_ACTUAL_SIZE;
-                    }
-                  else if (*cons > 15 && *cons < 27 && *cons % 2 == 0)
-                    {
-                      instruction--;
-                     GET_ACTUAL_SIZE;
-                    }
-                 if (*cons < 27 && *cons % 2 == 0)
-                   *cons /= 2;
-                 break;
-
-               case DISPUD4:
-                  /* Mapping has to be done.  */
-                  if (*cons <= 15 && *cons % 4 != 0)
-                    {
-                      instruction++;
-                     GET_ACTUAL_SIZE;
-                    }
-                  else if (*cons > 15 && *cons < 53 && *cons % 4 == 0)
-                    {
-                      instruction--;
-                     GET_ACTUAL_SIZE;
-                    }
-                 if (*cons < 53 && *cons % 4 == 0)
-                   *cons /= 4;
-                 break;
-               default:
-                 break;
-             }
-            }
-          if ((IS_INSN_TYPE (ARITH_BYTE_INS) || IS_INSN_TYPE (ARITH_INS))
-              && !relocatable)
-            {
-             /* Check whether a cst4 mapping has to be done.  */
-              if ((instruction->operands[0].op_type == cst4
-                   || instruction->operands[0].op_type == i16)
-                 && (instruction->operands[1].op_type == regr))
-                {
-                 /* 'const' equals reserved escape sequences -->>
-                    represent as i16.  */
-                 if (insn->arg[0].constant == ESC_16
-                     || insn->arg[0].constant == ESC_32)
-                   {
-                     instruction++;
-                     GET_ACTUAL_SIZE;
-                   }
-                 else
-                   {
-                     /* Loop over cst4_map entries.  */
-                     for (cst4_op = cst4_map; cst4_op < (cst4_map + cst4_maps);
-                          cst4_op++)
-                       {
-                         /* 'const' equals a binary, which is already mapped
-                            by a different value -->> represent as i16.  */
-                         if (insn->arg[0].constant == (unsigned int)cst4_op->binary
-                             && cst4_op->binary != cst4_op->value)
-                           {
-                             instruction++;
-                             GET_ACTUAL_SIZE;
-                           }
-                         /* 'const' equals a value bigger than 16 -->> map to
-                            its binary and represent as cst4.  */
-                         else if (insn->arg[0].constant == (unsigned int)cst4_op->value
-                                  && insn->arg[0].constant >= 16)
-                           {
-                             instruction--;
-                             insn->arg[0].constant = cst4_op->binary;
-                             GET_ACTUAL_SIZE;
-                           }
-                       }
-                   }
-               }
-             /* Special check for 'addub 0, r0' instruction -
-                The opcode '0000 0000 0000 0000' is not allowed.  */
-              if (IS_INSN_MNEMONIC ("addub"))
-                {
-                  if ((instruction->operands[0].op_type == cst4)
-                     && instruction->operands[1].op_type == regr)
-                    {
-                      if (insn->arg[0].constant == 0 && insn->arg[1].r == r0)
-                       instruction++;
-                    }
-                }
-            }
-          if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (STOR_IMM_INS)
-             || IS_INSN_TYPE (LD_STOR_INS_INC))
-            {
-             instrtype = instruction->flags & REVERSE_MATCH ? 0 : 1;
-              if (instruction->operands[instrtype].op_type == rbase)
-               instruction++;
-            }
-         /* Error checking in case of post-increment instruction.  */
-         if (IS_INSN_TYPE (LD_STOR_INS_INC))
-           {
-             if (!((strneq (instruction->mnemonic, "stor", 4))
-                   && (insn->arg[0].type != arg_r)))
-               if (insn->arg[0].r == insn->arg[1].r)
-                 as_bad (_("Invalid instruction : `%s' Source and Destination register \
-                         same in Post INC mode"), ins_parse);
-           }
-          if (IS_INSN_TYPE (CSTBIT_INS) && !relocatable)
-            {
-              if (instruction->operands[1].op_type == rbase_dispu12)
-                {
-                  if (insn->arg[1].constant == 0)
-                    {
-                      instruction--;
-                     GET_ACTUAL_SIZE;
-                    }
-                }
-            }
-          if ((IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)
-              || IS_INSN_TYPE (STOR_IMM_INS)
-               || IS_INSN_TYPE (LD_STOR_INS_INC)) & !relocatable)
-            {
-             instrtype = instruction->flags & REVERSE_MATCH ? 0 : 1;
-              changed_already = 0;
-              /* Convert 32 bits accesses to 16 bits accesses.  */
-              if (instruction->operands[instrtype].op_type == abs32)
-                {
-                  if ((insn->arg[instrtype].constant & 0xFFFF0000) == 0xFFFF0000)
-                    {
-                      instruction--;
-                      insn->arg[instrtype].constant =
-                        insn->arg[instrtype].constant & 0xFFFF;
-                      insn->arg[instrtype].size = 16;
-                      changed_already = 1;
-                     GET_ACTUAL_SIZE;
-                    }
-                }
-              /* Convert 16 bits accesses to 32 bits accesses.  */
-              if (instruction->operands[instrtype].op_type == abs16
-                  && changed_already != 1)
-                {
-                  instruction++;
-                  insn->arg[instrtype].constant =
-                    insn->arg[instrtype].constant & 0xFFFF;
-                  insn->arg[instrtype].size = 32;
-                 GET_ACTUAL_SIZE;
-                }
-              changed_already = 0;
-            }
-          if (IS_INSN_TYPE (BRANCH_INS) && !relocatable)
-            {
-             /* 0x7e and 0x7f are reserved escape sequences of dispe9.  */
-             if (insn->arg[0].constant == 0x7e || insn->arg[0].constant == 0x7f)
-                {
-                  instruction++;
-                 GET_ACTUAL_SIZE;
-                }
-            }
-        }
+      }
+      
+      return 0;
+    }
+  else
+    /* Full match - print the encoding to output file.  */
+    {
+      /* Make further checkings (such that couldn't be made earlier).
+        Warn the user if necessary.  */
+      warn_if_needed (insn);
+      
+      /* Check whether we need to adjust the instruction pointer.  */
+      if (adjust_if_needed (insn))
+       /* If instruction pointer was adjusted, we need to update 
+          the size of the current template operands.  */
+       GET_CURRENT_SIZE;
 
       for (i = 0; i < insn->nargs; i++)
         {
-          if (instruction->operands[i].op_type == cst4
-              || instruction->operands[i].op_type == rbase_cst4)
-            cst4flag = 1;
-        }
+         int j = instruction->flags & REVERSE_MATCH ? 
+                 i == 0 ? 1 : 
+                 i == 1 ? 0 : i : 
+                 i;
+
+         /* This time, update constant value before printing it.  */
+         if ((insn->arg[j].X_op == O_constant) 
+              && (check_range (&insn->arg[j].constant, cur_size[j], 
+                               cur_flags[j], 1) != OP_LEGAL))
+             as_fatal (_("Illegal operand (arg %d)"), j+1);
+       }
 
       /* First, copy the instruction's opcode.  */
       output_opcode[0] = BIN (instruction->match, instruction->match_bits);
 
-      /* Swap the argument values in case bcop instructions.  */
-      if (IS_INSN_TYPE (COP_BRANCH_INS))
+      for (i = 0; i < insn->nargs; i++)
         {
-          temp_value = insn->arg[0].constant;
-          insn->arg[0].constant = insn->arg[1].constant;
-          insn->arg[1].constant = temp_value;
+         cur_arg_num = i;
+          print_operand (cur_size[i], instruction->operands[i].shift, 
+                        &insn->arg[i]);
         }
+    }
 
-      for (i = 0; i < insn->nargs; i++)
+  return 1;
+}
+
+/* Bunch of error checkings.
+   The checks are made after a matching instruction was found.  */
+
+void
+warn_if_needed (ins *insn)
+{
+  /* If the post-increment address mode is used and the load/store 
+     source register is the same as rbase, the result of the 
+     instruction is undefined.  */
+  if (IS_INSN_TYPE (LD_STOR_INS_INC))
+    {
+      /* Enough to verify that one of the arguments is a simple reg.  */
+      if ((insn->arg[0].type == arg_r) || (insn->arg[1].type == arg_r))
+       if (insn->arg[0].r == insn->arg[1].r)
+         as_bad (_("Same src/dest register is used (`r%d'), result is undefined"), 
+                  insn->arg[0].r);
+    }
+
+  /* Some instruction assume the stack pointer as rptr operand.
+     Issue an error when the register to be loaded is also SP.  */
+  if (instruction->flags & NO_SP)
+    {
+      if (getreg_image (insn->arg[0].r) == getreg_image (sp))
+       as_bad (_("`%s' has undefined result"), ins_parse);
+    }
+
+  /* If the rptr register is specified as one of the registers to be loaded, 
+     the final contents of rptr are undefined. Thus, we issue an error.  */
+  if (instruction->flags & NO_RPTR)
+    {
+      if ((1 << getreg_image (insn->arg[0].r)) & insn->arg[1].constant)
+       as_bad (_("Same src/dest register is used (`r%d'), result is undefined"), 
+        getreg_image (insn->arg[0].r));
+    }
+}
+
+/* In some cases, we need to adjust the instruction pointer although a 
+   match was already found. Here, we gather all these cases.
+   Returns 1 if instruction pointer was adjusted, otherwise 0.  */
+
+int
+adjust_if_needed (ins *insn)
+{
+  int ret_value = 0;
+
+  /* Special check for 'addub $0, r0' instruction -
+     The opcode '0000 0000 0000 0000' is not allowed.  */
+  if (IS_INSN_MNEMONIC ("addub"))
+    {
+      if ((instruction->operands[0].op_type == cst4)
+         && instruction->operands[1].op_type == regr)
         {
-         shift_act[i] = instruction->operands[i].shift;
-          signflag = insn->arg[i].signflag;
-          processing_arg_number = i;
-          print_operand (bits_act[i], shift_act[i], &insn->arg[i]);
+          if (insn->arg[0].constant == 0 && insn->arg[1].r == r0)
+           {
+             instruction++;
+             ret_value = 1;
+           }
         }
     }
 
-  return 1;
+  /* Optimization: Omit a zero displacement in bit operations, 
+     saving 2-byte encoding space (e.g., 'cbitw $8, 0(r1)').  */
+  if (IS_INSN_TYPE (CSTBIT_INS))
+    {
+      if ((instruction->operands[1].op_type == rbase_disps12)
+          && (insn->arg[1].X_op == O_constant)
+          && (insn->arg[1].constant == 0))
+            {
+              instruction--;
+             ret_value = 1;
+            }
+    }
+
+  return ret_value;
 }
 
 /* Set the appropriate bit for register 'r' in 'mask'.
@@ -2381,6 +1751,7 @@ preprocess_reglist (char *param, int *allocated)
   char *new_param;               /* New created operands string.  */
   char *paramP = param;                  /* Pointer to original opearands string.  */
   char maskstring[10];           /* Array to print the mask as a string.  */
+  int hi_found = 0, lo_found = 0; /* Boolean flags for hi/lo registers.  */
   reg r;
   copreg cr;
 
@@ -2411,30 +1782,64 @@ preprocess_reglist (char *param, int *allocated)
       /* Coprocessor register c<N>.  */
       if (IS_INSN_TYPE (COP_REG_INS))
         {
-          if ((cr = get_copregister (reg_name)) == nullcopregister)
-           as_bad (_("Illegal register `%s' in cop-register list"), reg_name);
+          if (((cr = get_copregister (reg_name)) == nullcopregister)
+             || (crx_copregtab[cr-MAX_REG].type != CRX_C_REGTYPE))
+           as_fatal (_("Illegal register `%s' in cop-register list"), reg_name);
          mask_reg (getreg_image (cr - c0), &mask);
         }
       /* Coprocessor Special register cs<N>.  */
       else if (IS_INSN_TYPE (COPS_REG_INS))
         {
-          if ((cr = get_copregister (reg_name)) == nullcopregister)
-           as_bad (_("Illegal register `%s' in cop-special-register list"), 
+          if (((cr = get_copregister (reg_name)) == nullcopregister)
+             || (crx_copregtab[cr-MAX_REG].type != CRX_CS_REGTYPE))
+           as_fatal (_("Illegal register `%s' in cop-special-register list"), 
                      reg_name);
          mask_reg (getreg_image (cr - cs0), &mask);
         }
+      /* User register u<N>.  */
+      else if (instruction->flags & USER_REG)
+       {
+         if (streq(reg_name, "uhi"))
+           {
+             hi_found = 1;
+             goto next_inst;
+           }
+         else if (streq(reg_name, "ulo"))
+           {
+             lo_found = 1;
+             goto next_inst;
+           }
+          else if (((r = get_register (reg_name)) == nullregister)
+             || (crx_regtab[r].type != CRX_U_REGTYPE))
+           as_fatal (_("Illegal register `%s' in user register list"), reg_name);
+         
+         mask_reg (getreg_image (r - u0), &mask);        
+       }
       /* General purpose register r<N>.  */
       else
         {
-          if ((r = get_register (reg_name)) == nullregister)
-           as_bad (_("Illegal register `%s' in register list"), reg_name);
-         mask_reg (getreg_image (r), &mask);
+         if (streq(reg_name, "hi"))
+           {
+             hi_found = 1;
+             goto next_inst;
+           }
+         else if (streq(reg_name, "lo"))
+           {
+             lo_found = 1;
+             goto next_inst;
+           }
+          else if (((r = get_register (reg_name)) == nullregister)
+             || (crx_regtab[r].type != CRX_R_REGTYPE))
+           as_fatal (_("Illegal register `%s' in register list"), reg_name);
+
+         mask_reg (getreg_image (r - r0), &mask);
         }
 
       if (++reg_counter > MAX_REGS_IN_MASK16)
        as_bad (_("Maximum %d bits may be set in `mask16' operand"),
                MAX_REGS_IN_MASK16);
 
+next_inst:
       while (!ISALNUM (*paramP) && *paramP != '}')
          paramP++;
     }
@@ -2443,9 +1848,28 @@ preprocess_reglist (char *param, int *allocated)
     as_warn (_("rest of line ignored; first ignored character is `%c'"),
             *paramP);
 
-  if (mask == 0)
-    as_bad (_("Illegal `mask16' operand, operation is undefined - `%s'"),
-           ins_parse);
+  switch (hi_found + lo_found)
+    {
+    case 0:
+      /* At least one register should be specified.  */
+      if (mask == 0)
+       as_bad (_("Illegal `mask16' operand, operation is undefined - `%s'"),
+               ins_parse);
+      break;
+
+    case 1:
+      /* HI can't be specified without LO (and vise-versa).  */
+      as_bad (_("HI/LO registers should be specified together"));
+      break;
+
+    case 2:
+      /* HI/LO registers mustn't be masked with additional registers.  */
+      if (mask != 0)
+       as_bad (_("HI/LO registers should be specified without additional registers"));
+
+    default:
+      break;
+    }
 
   sprintf (maskstring, "$0x%x", mask);
   strcat (new_param, maskstring);
@@ -2461,6 +1885,7 @@ print_insn (ins *insn)
   unsigned int i, j, insn_size;
   char *this_frag;
   unsigned short words[4];
+  int addr_mod;
 
   /* Arrange the insn encodings in a WORD size array.  */
   for (i = 0, j = 0; i < 2; i++)
@@ -2483,8 +1908,8 @@ print_insn (ins *insn)
       /* bal  */
       else if (IS_INSN_TYPE (DCR_BRANCH_INS) || IS_INSN_MNEMONIC ("bal"))
        relax_subtype = 3;
-      /* cmpbr  */
-      else if (IS_INSN_TYPE (CMPBR_INS))
+      /* cmpbr/bcop  */
+      else if (IS_INSN_TYPE (CMPBR_INS) || IS_INSN_TYPE (COP_BRANCH_INS))
        relax_subtype = 5;
       else
        abort ();
@@ -2522,6 +1947,13 @@ print_insn (ins *insn)
        }
     }
 
+  /* Verify a 2-byte code alignment.  */
+  addr_mod = frag_now_fix () & 1;
+  if (frag_now->has_code && frag_now->insn_addr != addr_mod)
+    as_bad (_("instruction address is not a multiple of 2"));
+  frag_now->insn_addr = addr_mod;
+  frag_now->has_code = 1;
+
   /* Write the instruction encoding to frag.  */
   for (i = 0; i < insn_size; i++)
     {
@@ -2542,7 +1974,7 @@ md_assemble (char *op)
   char c;
 
   /* Reset global variables for a new instruction.  */
-  reset_vars (op, &crx_ins);
+  reset_vars (op);
 
   /* Strip the mnemonic.  */
   for (param = op; *param != 0 && !ISSPACE (*param); param++)
@@ -2555,26 +1987,24 @@ md_assemble (char *op)
   if (instruction == NULL)
     {
       as_bad (_("Unknown opcode: `%s'"), op);
+      param[-1] = c;
       return;
     }
 
   /* Tie dwarf2 debug info to the address at the start of the insn.  */
   dwarf2_emit_insn (0);
 
-  if (NO_OPERANDS_INST (op))
-    /* Handle instructions with no operands.  */
-    crx_ins.nargs = 0;
-  else
-    /* Parse the instruction's operands.  */
-    parse_insn (&crx_ins, param);
+  /* Parse the instruction's operands.  */
+  parse_insn (&crx_ins, param);
 
-  /* Assemble the instruction.  */
+  /* Assemble the instruction - return upon failure.  */
   if (assemble_insn (op, &crx_ins) == 0)
     {
-      as_bad (_("Illegal operands in instruction : `%s'"), ins_parse);
+      param[-1] = c;
       return;
     }
 
   /* Print the instruction.  */
+  param[-1] = c;
   print_insn (&crx_ins);
 }