Fix overflow detection in the Z80 assembler.
[binutils-gdb.git] / gas / config / tc-crx.c
index 4bd3d18321300b12b0d86316c03cfc84dd64c2a3..d33a0bf076657de368b766dfb93e557175238ad5 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-crx.c -- Assembler code for the CRX CPU core.
 /* tc-crx.c -- Assembler code for the CRX CPU core.
-   Copyright 2004 Free Software Foundation, Inc.
+   Copyright (C) 2004-2021 Free Software Foundation, Inc.
 
    Contributed by Tomer Levi, NSC, Israel.
    Originally written for GAS 2.12 by Tomer Levi, NSC, Israel.
 
    Contributed by Tomer Levi, NSC, Israel.
    Originally written for GAS 2.12 by Tomer Levi, NSC, Israel.
@@ -9,7 +9,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
 
    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,
    any later version.
 
    GAS is distributed in the hope that it will be useful,
 
    You should have received a copy of the GNU General Public License
    along with GAS; see the file COPYING.  If not, write to the
 
    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 "as.h"
+#include <stdint.h>
 #include "safe-ctype.h"
 #include "dwarf2dbg.h"
 #include "opcode/crx.h"
 #include "elf/crx.h"
 
 #include "safe-ctype.h"
 #include "dwarf2dbg.h"
 #include "opcode/crx.h"
 #include "elf/crx.h"
 
-#include <limits.h>
-
 /* Word is considered here as a 16-bit unsigned short int.  */
 /* Word is considered here as a 16-bit unsigned short int.  */
-#define WORD_SIZE   16
 #define WORD_SHIFT  16
 
 /* Register is 4-bit size.  */
 #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
 
 /* 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)
 /* 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'.  */
    pointed by index BYTE of array 'output_opcode'.  */
-#define CRX_PRINT(BYTE, NUM, SHIFT)   output_opcode[BYTE] |= (NUM << SHIFT)
+#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.  */
 
 /* Opcode mnemonics hash table.  */
-static struct hash_control *crx_inst_hash;
+static htab_t crx_inst_hash;
 /* CRX registers hash table.  */
 /* CRX registers hash table.  */
-static struct hash_control *reg_hash;
+static htab_t reg_hash;
 /* CRX coprocessor registers hash table.  */
 /* CRX coprocessor registers hash table.  */
-static struct hash_control *copreg_hash;
+static htab_t copreg_hash;
 /* Current instruction we're assembling.  */
 /* Current instruction we're assembling.  */
-const inst *instruction;
+static const inst *instruction;
+
+/* Global variables.  */
+
+/* Array to hold an instruction encoding.  */
+static long output_opcode[2];
 
 
-/* Initialize global variables.  */
-long output_opcode[2];
 /* Nonzero means a relocatable symbol.  */
 /* 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;
+static int relocatable;
+
 /* A copy of the original instruction (used in error messages).  */
 /* 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;
+static char ins_parse[MAX_INST_LEN];
+
+/* The current processed argument number.  */
+static int cur_arg_num;
 
 /* Generic assembler global variables which must be defined by all targets.  */
 
 
 /* Generic assembler global variables which must be defined by all targets.  */
 
@@ -141,6 +122,7 @@ const pseudo_typeS md_pseudo_table[] =
   {0, 0, 0}
 };
 
   {0, 0, 0}
 };
 
+/* CRX relaxation table.  */
 const relax_typeS md_relax_table[] =
 {
   /* bCC  */
 const relax_typeS md_relax_table[] =
 {
   /* bCC  */
@@ -152,42 +134,20 @@ const relax_typeS md_relax_table[] =
   {0xfffe, -0x10000, 4, 4},            /* 16 */
   {0xfffffffe, -0xfffffffe, 6, 0},     /* 32 */
 
   {0xfffe, -0x10000, 4, 4},            /* 16 */
   {0xfffffffe, -0xfffffffe, 6, 0},     /* 32 */
 
-  /* cmpbr  */
+  /* cmpbr/bcop  */
   {0xfe, -0x100, 4, 6},                        /*  8 */
   {0xfffffe, -0x1000000, 6, 0}         /* 24 */
 };
 
   {0xfe, -0x100, 4, 6},                        /*  8 */
   {0xfffffe, -0x1000000, 6, 0}         /* 24 */
 };
 
-static void    reset_vars              (char *, ins *);
-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 int     get_number_of_operands   (void);
-static void    get_operandtype         (char *, int, ins *);
-static int     gettrap                 (char *);
-static void    handle_pi_insn          (char *);
-static int     get_cinv_parameters      (char *);
-static unsigned long getconstant        (unsigned long, 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 char *  preprocess_reglist       (char *, int *);
-static int     assemble_insn           (char *, ins *);
-static void    print_insn              (ins *);
+static int     get_cinv_parameters     (const char *);
+static char *  preprocess_reglist      (char *, int *);
+static void    warn_if_needed          (ins *);
+static int     adjust_if_needed                (ins *);
 
 /* Return the bit size for a given operand.  */
 
 static int
 
 /* 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;
 {
   if (op < MAX_OPRD)
     return crx_optab[op].bit_size;
@@ -198,7 +158,7 @@ getbits (operand_type op)
 /* Return the argument type of a given operand.  */
 
 static argtype
 /* 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;
 {
   if (op < MAX_OPRD)
     return crx_optab[op].arg_type;
@@ -206,17 +166,28 @@ getarg_type (operand_type op)
     return nullargs;
 }
 
     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)
 {
 /* 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 *) str_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;
 }
   else
     return nullregister;
 }
@@ -226,24 +197,16 @@ get_register (char *reg_name)
 static copreg
 get_copregister (char *copreg_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 *) str_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;
 }
 
   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
 /* Round up a section size to the appropriate boundary.  */
 
 valueT
@@ -276,20 +239,14 @@ md_operand (expressionS * exp)
 /* Reset global variables before parsing a new instruction.  */
 
 static void
 /* 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 (& 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).  */
   /* 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
 }
 
 /* This macro decides whether a particular reloc is an entry in a
@@ -327,8 +284,8 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS * fixP)
 {
   arelent * reloc;
 
 {
   arelent * reloc;
 
-  reloc = xmalloc (sizeof (arelent));
-  reloc->sym_ptr_ptr  = xmalloc (sizeof (asymbol *));
+  reloc = XNEW (arelent);
+  reloc->sym_ptr_ptr  = XNEW (asymbol *);
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
   reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
   reloc->addend = fixP->fx_offset;
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
   reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
   reloc->addend = fixP->fx_offset;
@@ -371,7 +328,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)
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
 
   if (reloc->howto == (reloc_howto_type *) NULL)
@@ -382,7 +339,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS * fixP)
                    bfd_get_reloc_code_name (fixP->fx_r_type));
       return NULL;
     }
                    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;
 }
 
   return reloc;
 }
@@ -421,7 +378,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, fragS *fragP)
 {
   /* 'opcode' points to the start of the instruction, whether
      we need to change the instruction's fixed encoding.  */
 {
   /* 'opcode' points to the start of the instruction, whether
      we need to change the instruction's fixed encoding.  */
-  char *opcode = fragP->fr_literal + fragP->fr_fix;
+  char *opcode = &fragP->fr_literal[0] + fragP->fr_fix;
   bfd_reloc_code_real_type reloc;
 
   subseg_change (sec, 0);
   bfd_reloc_code_real_type reloc;
 
   subseg_change (sec, 0);
@@ -470,7 +427,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, fragS *fragP)
    GAS does not understand.  */
 
 int
    GAS does not understand.  */
 
 int
-md_parse_option (int c ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED)
+md_parse_option (int c ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED)
 {
   return 0;
 }
 {
   return 0;
 }
@@ -483,58 +440,10 @@ md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
   return;
 }
 
   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 *
+const char *
 md_atof (int type, char *litP, int *sizeP)
 {
 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
 }
 
 /* Apply a fixS (fixup of an instruction or data that we didn't have
@@ -544,7 +453,7 @@ md_atof (int type, char *litP, int *sizeP)
    fixuping relocations of debug sections.  */
 
 void
    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;
 {
   valueT val = * valP;
   char *buf = fixP->fx_frag->fr_literal + fixP->fx_where;
@@ -594,24 +503,17 @@ md_pcrel_from (fixS *fixp)
 void
 md_begin (void)
 {
 void
 md_begin (void)
 {
-  const char *hashret = NULL;
   int i = 0;
 
   /* Set up a hash table for the instructions.  */
   int i = 0;
 
   /* Set up a hash table for the instructions.  */
-  crx_inst_hash = hash_new ();
-  if (crx_inst_hash == NULL)
-    as_fatal (_("Virtual memory exhausted"));
+  crx_inst_hash = str_htab_create ();
 
   while (crx_instruction[i].mnemonic != NULL)
     {
       const char *mnemonic = crx_instruction[i].mnemonic;
 
 
   while (crx_instruction[i].mnemonic != NULL)
     {
       const char *mnemonic = crx_instruction[i].mnemonic;
 
-      hashret = hash_insert (crx_inst_hash, mnemonic,
-       (PTR) &crx_instruction[i]);
-
-      if (hashret != NULL && *hashret != '\0')
-       as_fatal (_("Can't hash `%s': %s\n"), crx_instruction[i].mnemonic,
-                 *hashret == 0 ? _("(unknown reason)") : hashret);
+      if (str_hash_insert (crx_inst_hash, mnemonic, &crx_instruction[i], 0))
+       as_fatal (_("duplicate %s"), mnemonic);
 
       /* Insert unique names into hash table.  The CRX instruction set
         has many identical opcode names that have different opcodes based
 
       /* Insert unique names into hash table.  The CRX instruction set
         has many identical opcode names that have different opcodes based
@@ -626,253 +528,40 @@ md_begin (void)
     }
 
   /* Initialize reg_hash hash table.  */
     }
 
   /* Initialize reg_hash hash table.  */
-  reg_hash = hash_new ();
-
+  reg_hash = str_htab_create ();
   {
     const reg_entry *regtab;
 
     for (regtab = crx_regtab;
         regtab < (crx_regtab + NUMREGS); regtab++)
   {
     const reg_entry *regtab;
 
     for (regtab = crx_regtab;
         regtab < (crx_regtab + NUMREGS); regtab++)
-      {
-       hashret = hash_insert (reg_hash, regtab->name, (PTR) regtab);
-       if (hashret)
-         as_fatal (_("Internal Error:  Can't hash %s: %s"),
-                   regtab->name,
-                   hashret);
-      }
+      if (str_hash_insert (reg_hash, regtab->name, regtab, 0) != NULL)
+       as_fatal (_("duplicate %s"), regtab->name);
   }
 
   /* Initialize copreg_hash hash table.  */
   }
 
   /* Initialize copreg_hash hash table.  */
-  copreg_hash = hash_new ();
-
+  copreg_hash = str_htab_create ();
   {
     const reg_entry *copregtab;
 
     for (copregtab = crx_copregtab; copregtab < (crx_copregtab + NUMCOPREGS);
         copregtab++)
   {
     const reg_entry *copregtab;
 
     for (copregtab = crx_copregtab; copregtab < (crx_copregtab + NUMCOPREGS);
         copregtab++)
-      {
-       hashret = hash_insert (copreg_hash, copregtab->name, (PTR) copregtab);
-       if (hashret)
-         as_fatal (_("Internal Error:  Can't hash %s: %s"),
-                   copregtab->name,
-                   hashret);
-      }
+      if (str_hash_insert (copreg_hash, copregtab->name, copregtab, 0) != NULL)
+       as_fatal (_("duplicate %s"), copregtab->name);
   }
   /*  Set linkrelax here to avoid fixups in most sections.  */
   linkrelax = 1;
 }
 
   }
   /*  Set linkrelax here to avoid fixups in most sections.  */
   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
 
 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);
   input_line_pointer = str;
 
   expression (&crx_ins->exp);
@@ -888,352 +577,68 @@ 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;
       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:
 
     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:
       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;
 
       crx_ins->rtype = BFD_RELOC_NONE;
       relocatable = 1;
 
-      switch (crx_ins->arg[number].type)
+      switch (cur_arg->type)
        {
        case arg_cr:
        {
        case arg_cr:
-          /* Have to consider various cases here --load/stor++[bwd] rbase, reg.  */
-          if (IS_INSN_TYPE (LD_STOR_INS_INC))
+         if (IS_INSN_TYPE (LD_STOR_INS_INC))
            crx_ins->rtype = BFD_RELOC_CRX_REGREL12;
            crx_ins->rtype = BFD_RELOC_CRX_REGREL12;
-          else if (IS_INSN_TYPE (CSTBIT_INS)
+         else if (IS_INSN_TYPE (CSTBIT_INS)
                   || IS_INSN_TYPE (STOR_IMM_INS))
                   || IS_INSN_TYPE (STOR_IMM_INS))
-           /* 'stor[bwd] imm' and '[stc]bit[bwd]'.  */
            crx_ins->rtype = BFD_RELOC_CRX_REGREL28;
            crx_ins->rtype = BFD_RELOC_CRX_REGREL28;
-          else
-           /* General load store instruction.  */
+         else
            crx_ins->rtype = BFD_RELOC_CRX_REGREL32;
            crx_ins->rtype = BFD_RELOC_CRX_REGREL32;
-           break;
-       case arg_icr:
-         /* Index Mode 22 bits relocation.  */
-           crx_ins->rtype = BFD_RELOC_CRX_REGREL22;
          break;
          break;
+
+       case arg_idxr:
+         crx_ins->rtype = BFD_RELOC_CRX_REGREL22;
+         break;
+
        case arg_c:
        case arg_c:
-         /* Absolute types.  */
-          /* Case for jumps...dx  types.  */
-          /* For bal.  */
-          if (IS_INSN_MNEMONIC ("bal") || IS_INSN_TYPE (DCR_BRANCH_INS))
+         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_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;
-               }
-            }
-          else if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (STOR_IMM_INS)
+           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;
                   || 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;
-            }
+         else if (IS_INSN_TYPE (CMPBR_INS) || IS_INSN_TYPE (COP_BRANCH_INS))
+           crx_ins->rtype = BFD_RELOC_CRX_REL8_CMP;
          break;
          break;
+
        case arg_ic:
        case arg_ic:
-       case arg_dc:
-          if (IS_INSN_TYPE (ARITH_INS))
+         if (IS_INSN_TYPE (ARITH_INS))
            crx_ins->rtype = BFD_RELOC_CRX_IMM32;
          else if (IS_INSN_TYPE (ARITH_BYTE_INS))
            crx_ins->rtype = BFD_RELOC_CRX_IMM16;
          break;
        default:
          break;
            crx_ins->rtype = BFD_RELOC_CRX_IMM32;
          else if (IS_INSN_TYPE (ARITH_BYTE_INS))
            crx_ins->rtype = BFD_RELOC_CRX_IMM16;
          break;
        default:
          break;
-      }
-      crx_ins->arg[number].size = (bfd_reloc_type_lookup (stdoutput, crx_ins->rtype))->bitsize;
+       }
       break;
 
     default:
       break;
 
     default:
+      cur_arg->X_op = crx_ins->exp.X_op;
       break;
     }
 
       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 -
 }
 
 /* Get the values of the scale to be encoded -
@@ -1254,327 +659,210 @@ exponent2scale (int val)
   return exponent;
 }
 
   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
 
 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-operand.  */
+  char *operandE; /* Pointer to end of sub-operand.  */
+  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)
-       as_bad (_("Illegal register `%s' in Instruction `%s'"),
-               reg_name, ins_parse);
-
-      i++;
-      while (operand[i] == ' ')
-       i++;
-
-      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)
-       as_bad (_("Illegal register `%s' in Instruction `%s'"),
-               regindex_name, ins_parse);
-
-      /* Setting the scale parameters.  */
-      while (operand[i] == ' ')
-       i++;
-
-      if (operand[i] == ')')
-       crx_ins->arg[op_num].scale = 0;
-      else
-        {
-          if (operand[i] == ',')
-            i++;
-
-          while (operand[i] != ' ' && operand[i] != ')')
-            {
-              scale_str[scale_cnt++] = operand[i];
-              i++;
-            }
-
-          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);
-
-          if (temp_int_val != 1 && temp_int_val != 2
-              && temp_int_val != 4 && temp_int_val != 8)
-           as_bad (_("Illegal Scale - `%s'"), scale_str);
-
-         crx_ins->arg[op_num].scale = exponent2scale (temp_int_val);
-        }
+    case arg_sc:    /* Case *+0x18.  */
+    case arg_ic:    /* Case $0x18.  */
+      operandS++;
+      /* Fall through.  */
+    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;
       break;
-    default:
+
+    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;
+      /* Fall through.  */
+    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'"),
+               operandS, ins_parse);
+
+      if (cur_arg->type != arg_rbase)
+       cur_arg->type = arg_cr;
       break;
       break;
-    }
-}
 
 
-/* Parsing the operands of types
-   - constants
-   - rbase -> (register)
-   - offset(rbase)
-   - offset(rbase)+ - post increment mode.  */
+    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'"),
+               operandS, ins_parse);
+
+      /* Skip leading white space.  */
+      while (ISSPACE (*operandE))
+       operandE++;
+      operandS = operandE;
+
+      /* 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
+       {
+         while (*operandE != ')')
+           operandE++;
+         *operandE = '\0';
+
+         /* Preprocess the scale string.  */
+         input_save = input_line_pointer;
+         input_line_pointer = operandS;
+         expression (&scale);
+         input_line_pointer = input_save;
 
 
-static void
-set_cons_rparams (char *operand, ins * crx_ins, int op_num)
-{
-  int i = 0, reg_count = 0;
-  char reg_name[MAX_REGNAME_LEN];
-  int change_flag = 0;
+         scale_val = scale.X_add_number;
 
 
-  if (crx_ins->arg[op_num].type == arg_dc)
-    change_flag = 1;
+         /* 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);
 
 
-  switch (crx_ins->arg[op_num].type)
-    {
-    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;
+         cur_arg->scale = exponent2scale (scale_val);
+       }
       break;
       break;
+
     default:
       break;
     }
     default:
       break;
     }
-  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.  */
+/* Parse a single operand.
+   operand - Current operand to parse.
+   crx_ins - Current assembled instruction.  */
 
 static void
 
 static void
-get_operandtype (char *operand, int number, ins * crx_ins)
+parse_operand (char *operand, ins * crx_ins)
 {
   int ret_val;
 {
   int ret_val;
-  char temp_operand[30];
+  argument *cur_arg = &crx_ins->arg[cur_arg_num]; /* Current argument.  */
+
+  /* Initialize the type to NULL before parsing.  */
+  cur_arg->type = nullargs;
+
+  /* Check whether this is a general processor register.  */
+  if ((ret_val = get_register (operand)) != nullregister)
+    {
+      cur_arg->type = arg_r;
+      cur_arg->r = ret_val;
+      cur_arg->X_op = O_register;
+      return;
+    }
 
 
+  /* 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])
     {
   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)
     case '$':
       if (strchr (operand, '(') != NULL)
-       crx_ins->arg[number].type = arg_dcr;
+       cur_arg->type = arg_icr;
       else
       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;
 
       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 '*':
     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;
       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;
       break;
+
     default:
     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;
-        }
-      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;
     }
       break;
     }
+
+  if (strchr (operand, '(') != NULL)
+    {
+      if (strchr (operand, ',') != NULL
+         && (strchr (operand, ',') > strchr (operand, '(')))
+       cur_arg->type = arg_idxr;
+      else
+       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)
 
 static void
 parse_operands (ins * crx_ins, char *operands)
@@ -1594,12 +882,12 @@ parse_operands (ins * crx_ins, char *operands)
   while (*operandT != '\0')
     {
       if (*operandT == ',' && bracket_flag != 1 && sq_bracket_flag != 1)
   while (*operandT != '\0')
     {
       if (*operandT == ',' && bracket_flag != 1 && sq_bracket_flag != 1)
-        {
+       {
          *operandT++ = '\0';
          operand[op_num++] = strdup (operandH);
          *operandT++ = '\0';
          operand[op_num++] = strdup (operandH);
-          operandH = operandT;
-          continue;
-        }
+         operandH = operandT;
+         continue;
+       }
 
       if (*operandT == ' ')
        as_bad (_("Illegal operands (whitespace): `%s'"), ins_parse);
 
       if (*operandT == ' ')
        as_bad (_("Illegal operands (whitespace): `%s'"), ins_parse);
@@ -1640,10 +928,11 @@ parse_operands (ins * crx_ins, char *operands)
   if (bracket_flag || sq_bracket_flag)
     as_fatal (_("Missing matching brackets : `%s'"), ins_parse);
 
   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++)
     {
   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]);
     }
 
       free (operand[op_num]);
     }
 
@@ -1655,7 +944,7 @@ parse_operands (ins * crx_ins, char *operands)
    This routine is used by assembling the 'excp' instruction.  */
 
 static int
    This routine is used by assembling the 'excp' instruction.  */
 
 static int
-gettrap (char *s)
+gettrap (const char *s)
 {
   const trap_entry *trap;
 
 {
   const trap_entry *trap;
 
@@ -1667,17 +956,35 @@ gettrap (char *s)
   return 0;
 }
 
   return 0;
 }
 
-/* Post-Increment instructions are a sub-group within load/stor instruction
-   groups. Therefore, when parsing a Post-Increment insn, we have to advance
-   the instruction pointer to the start of that sub-group.  */
+/* Post-Increment instructions, as well as Store-Immediate instructions, are a
+   sub-group within load/stor instruction groups.
+   Therefore, when parsing a Post-Increment/Store-Immediate insn, we have to
+   advance the instruction pointer to the start of that sub-group (that is, up
+   to the first instruction of that type).
+   Otherwise, the insn will be mistakenly identified as of type LD_STOR_INS.  */
 
 static void
 
 static void
-handle_pi_insn (char *operands)
+handle_LoadStor (const char *operands)
 {
 {
+  /* 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 :
   /* Assuming Post-Increment insn has the following format :
-     'MNEMONIC DISP(REG)+, REG' (e.g. 'loadw 12(r5)+, r6').  */
+     '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)
   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++;
 }
 
       instruction++;
 }
 
@@ -1688,20 +995,32 @@ handle_pi_insn (char *operands)
 static void
 parse_insn (ins *insn, char *operands)
 {
 static void
 parse_insn (ins *insn, char *operands)
 {
-  /* Handle 'excp'/'cinv' */
+  int i;
+
+  /* Handle instructions with no operands.  */
+  for (i = 0; crx_no_op_insn[i] != NULL; i++)
+  {
+    if (streq (crx_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;
   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].constant = IS_INSN_MNEMONIC ("excp") ?
        gettrap (operands) : get_cinv_parameters (operands);
+      insn->arg[0].X_op = O_constant;
       return;
     }
 
       return;
     }
 
-  /* Handle load/stor post-increment instructions.  */
-  if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (STOR_IMM_INS))
-    handle_pi_insn (operands);
+  /* Handle load/stor unique instructions before parsing.  */
+  if (IS_INSN_TYPE (LD_STOR_INS))
+    handle_LoadStor (operands);
 
   if (operands != NULL)
     parse_operands (insn, operands);
 
   if (operands != NULL)
     parse_operands (insn, operands);
@@ -1710,10 +1029,10 @@ parse_insn (ins *insn, char *operands)
 /* Cinv instruction requires special handling.  */
 
 static int
 /* Cinv instruction requires special handling.  */
 
 static int
-get_cinv_parameters (char * operand)
+get_cinv_parameters (const char *operand)
 {
 {
-  char *p = operand;
-  int d_used = 0, i_used = 0, u_used = 0;
+  const char *p = operand;
+  int d_used = 0, i_used = 0, u_used = 0, b_used = 0;
 
   while (*++p != ']')
     {
 
   while (*++p != ']')
     {
@@ -1726,11 +1045,14 @@ get_cinv_parameters (char * operand)
        i_used = 1;
       else if (*p == 'u')
        u_used = 1;
        i_used = 1;
       else if (*p == 'u')
        u_used = 1;
+      else if (*p == 'b')
+       b_used = 1;
       else
        as_bad (_("Illegal `cinv' parameter: `%c'"), *p);
     }
 
       else
        as_bad (_("Illegal `cinv' parameter: `%c'"), *p);
     }
 
-  return ((d_used ? 4 : 0)
+  return ((b_used ? 8 : 0)
+       + (d_used ? 4 : 0)
        + (i_used ? 2 : 0)
        + (u_used ? 1 : 0));
 }
        + (i_used ? 2 : 0)
        + (u_used ? 1 : 0));
 }
@@ -1740,26 +1062,22 @@ get_cinv_parameters (char * operand)
    issue an error.  */
 
 static int
    issue an error.  */
 
 static int
-getreg_image (reg r)
+getreg_image (int r)
 {
 {
-  const reg_entry *reg;
+  const reg_entry *rreg;
   char *reg_name;
   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)
 
   /* 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.  */
   /* 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
     {
   /* Register not found.  */
   else
     {
@@ -1767,70 +1085,55 @@ getreg_image (reg r)
       return 0;
     }
 
       return 0;
     }
 
-  reg_name = reg->name;
+  reg_name = rreg->name;
 
 /* Issue a error message when register is illegal.  */
 #define IMAGE_ERR \
 
 /* Issue a error message when register is illegal.  */
 #define IMAGE_ERR \
-  as_bad (_("Illegal register (`%s') in Instruction: `%s'"), \
-           reg_name, ins_parse);                            \
-  break;
+  as_bad (_("Illegal register (`%s') in instruction: `%s'"), \
+         reg_name, ins_parse);
 
 
-  switch (reg->type)
+  switch (rreg->type)
   {
     case CRX_U_REGTYPE:
   {
     case CRX_U_REGTYPE:
+      if (is_procreg || (instruction->flags & USER_REG))
+       return rreg->image;
+      else
+       IMAGE_ERR;
+      break;
+
     case CRX_CFG_REGTYPE:
     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;
       else
        IMAGE_ERR;
+      break;
 
     case CRX_R_REGTYPE:
 
     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;
       else
        IMAGE_ERR;
+      break;
+
+    case CRX_C_REGTYPE:
+    case CRX_CS_REGTYPE:
+      return rreg->image;
+      break;
 
     default:
       IMAGE_ERR;
 
     default:
       IMAGE_ERR;
+      break;
   }
 
   return 0;
 }
 
   }
 
   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));
+  return x & ((((1U << (nbits - 1)) - 1) << 1) | 1);
 }
 
 /* Print a constant value to 'output_opcode':
 }
 
 /* Print a constant value to 'output_opcode':
@@ -1842,8 +1145,7 @@ static void
 print_constant (int nbits, int shift, argument *arg)
 {
   unsigned long mask = 0;
 print_constant (int nbits, int shift, argument *arg)
 {
   unsigned long mask = 0;
-
-  long constant = getconstant (arg->constant, nbits);
+  unsigned long constant = getconstant (arg->constant, nbits);
 
   switch (nbits)
   {
 
   switch (nbits)
   {
@@ -1864,7 +1166,7 @@ print_constant (int nbits, int shift, argument *arg)
              output_opcode[0]    output_opcode[1]     */
 
       CRX_PRINT (0, (constant >> WORD_SHIFT) & mask, 0);
              output_opcode[0]    output_opcode[1]     */
 
       CRX_PRINT (0, (constant >> WORD_SHIFT) & mask, 0);
-      CRX_PRINT (1, (constant & 0xFFFF), WORD_SHIFT);
+      CRX_PRINT (1, constant & 0xFFFF, WORD_SHIFT);
       break;
 
     case 16:
       break;
 
     case 16:
@@ -1877,9 +1179,17 @@ print_constant (int nbits, int shift, argument *arg)
          break;
        }
 
          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);
        CRX_PRINT (1, constant, WORD_SHIFT);
       else
        CRX_PRINT (0, constant, shift);
@@ -1908,30 +1218,29 @@ print_operand (int nbits, int shift, argument *arg)
 
     case arg_copr:
       if (arg->cr < c0 || arg->cr > c15)
 
     case arg_copr:
       if (arg->cr < c0 || arg->cr > c15)
-       as_bad (_("Illegal Co-processor register in Instruction `%s' "),
+       as_bad (_("Illegal co-processor register in instruction `%s'"),
                ins_parse);
       CRX_PRINT (0, getreg_image (arg->cr), shift);
       break;
 
     case arg_copsr:
       if (arg->cr < cs0 || arg->cr > cs15)
                ins_parse);
       CRX_PRINT (0, getreg_image (arg->cr), shift);
       break;
 
     case arg_copsr:
       if (arg->cr < cs0 || arg->cr > cs15)
-       as_bad (_("Illegal Co-processor special register in Instruction `%s' "),
+       as_bad (_("Illegal co-processor special register in instruction `%s'"),
                ins_parse);
       CRX_PRINT (0, getreg_image (arg->cr), shift);
       break;
 
                ins_parse);
       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
            +--------------------------------+
       /*    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);
            +--------------------------------+    */
       CRX_PRINT (0, getreg_image (arg->r), 12);
       CRX_PRINT (0, getreg_image (arg->i_r), 8);
       CRX_PRINT (0, arg->scale, 6);
+      /* Fall through.  */
+    case arg_ic:
+    case arg_c:
       print_constant (nbits, shift, arg);
       break;
 
       print_constant (nbits, shift, arg);
       break;
 
@@ -1941,20 +1250,15 @@ print_operand (int nbits, int shift, argument *arg)
 
     case arg_cr:
       /* case base_cst4.  */
 
     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
       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;
 
        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;
     }
     default:
       break;
     }
@@ -1972,340 +1276,407 @@ get_number_of_operands (void)
   return i;
 }
 
   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)
+{
+  uint32_t max;
+  op_err retval = OP_LEGAL;
+  int bin;
+  uint32_t upper_64kb = 0xffff0000;
+  uint32_t value = *num;
+
+  /* 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)
+    {
+      /* All OP_SHIFT args are also OP_SIGNED, so we want to keep the
+        sign.  However, right shift of a signed type with a negative
+        value is implementation defined.  See ISO C 6.5.7.  So we use
+        an unsigned type and sign extend afterwards.  */
+      value >>= 1;
+      value = (value ^ 0x40000000) - 0x40000000;
+      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;
+
+      uint32_t mul = (instruction->flags & DISPUB4 ? 1
+                     : instruction->flags & DISPUW4 ? 2
+                     : instruction->flags & DISPUD4 ? 4
+                     : 0);
+
+      for (bin = 0; bin < crx_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 < crx_cst4_maps; bin++)
+       {
+         if (value == (uint32_t) crx_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;
+      max = max << (bits - 1);
+      value += max;
+      max = ((max - 1) << 1) | 1;
+      if (value > max)
+       retval = OP_OUT_OF_RANGE;
+    }
+  else if (flags & OP_UNSIGNED)
+    {
+      max = 1;
+      max = max << (bits - 1);
+      max = ((max - 1) << 1) | 1;
+      if (value > max)
+       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)
 {
    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 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;
     }
 
   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;
+  /* 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);
 
 
-  /* 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;
-
-  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.  */
         /* 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++)
       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 == 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;
-                }
-            }
-
-        }
-
-      if (done_flag == 1)
-        {
-         /* Full match is found.  */
-          match = 1;
-          break;
-        }
-    }
+       {
+         if (cur_type[i] != insn->arg[i].type)
+           {
+             if (invalid_optype == -1)
+               invalid_optype = i + 1;
+             goto next_insn;
+           }
+       }
+      found_same_argument_types = 1;
 
 
-  if (match == 0)
-    /* We haven't found a match - instruction can't be assembled.  */
-    return 0;
-  else
-    /* Full match - print the final image.  */
-    {
-      /* 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)
+      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 <= 1 ? 1 - 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)
                {
                {
-               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;
-                           }
-                       }
-                   }
+                 invalid_const = j + 1;
+                 const_err = op_error;
                }
                }
-             /* 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))
+             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;
+
+      /* Try again with next instruction.  */
+    next_insn:
+      instruction++;
+    }
+
+  if (!match)
+    {
+      /* 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)
            {
            {
-             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);
+           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;
            }
            }
-          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 checking (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++)
 
       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 <= 1 ? 1 - 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);
 
 
       /* 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))
-        {
-          temp_value = insn->arg[0].constant;
-          insn->arg[0].constant = insn->arg[1].constant;
-          insn->arg[1].constant = temp_value;
-        }
-
       for (i = 0; i < insn->nargs; i++)
       for (i = 0; i < insn->nargs; i++)
-        {
-         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]);
-        }
+       {
+         cur_arg_num = i;
+         print_operand (cur_size[i], instruction->operands[i].shift,
+                        &insn->arg[i]);
+       }
     }
 
   return 1;
 }
 
     }
 
   return 1;
 }
 
+/* Bunch of error checking.
+   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)
+       {
+         if (insn->arg[0].constant == 0 && insn->arg[1].r == r0)
+           {
+             instruction++;
+             ret_value = 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'.
    This indicates that this register is loaded or stored by
    the instruction.  */
 /* Set the appropriate bit for register 'r' in 'mask'.
    This indicates that this register is loaded or stored by
    the instruction.  */
@@ -2315,7 +1686,7 @@ mask_reg (int r, unsigned short int *mask)
 {
   if ((reg)r > (reg)sp)
     {
 {
   if ((reg)r > (reg)sp)
     {
-      as_bad (_("Invalid Register in Register List"));
+      as_bad (_("Invalid register in register list"));
       return;
     }
 
       return;
     }
 
@@ -2334,8 +1705,9 @@ preprocess_reglist (char *param, int *allocated)
   int reg_counter = 0;           /* Count number of parsed registers.  */
   unsigned short int mask = 0;   /* Mask for 16 general purpose registers.  */
   char *new_param;               /* New created operands string.  */
   int reg_counter = 0;           /* Count number of parsed registers.  */
   unsigned short int mask = 0;   /* Mask for 16 general purpose registers.  */
   char *new_param;               /* New created operands string.  */
-  char *paramP = param;                  /* Pointer to original opearands string.  */
+  char *paramP = param;                  /* Pointer to original operands string.  */
   char maskstring[10];           /* Array to print the mask as a 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;
 
   reg r;
   copreg cr;
 
@@ -2349,7 +1721,7 @@ preprocess_reglist (char *param, int *allocated)
 
   while (*paramP++ != '{');
 
 
   while (*paramP++ != '{');
 
-  new_param = (char *)xcalloc (MAX_INST_LEN, sizeof (char));
+  new_param = XCNEWVEC (char, MAX_INST_LEN);
   *allocated = 1;
   strncpy (new_param, param, paramP - param - 1);
 
   *allocated = 1;
   strncpy (new_param, param, paramP - param - 1);
 
@@ -2363,34 +1735,97 @@ preprocess_reglist (char *param, int *allocated)
 
       strncpy (reg_name, regP, paramP - regP);
 
 
       strncpy (reg_name, regP, paramP - regP);
 
+      /* Coprocessor register c<N>.  */
       if (IS_INSN_TYPE (COP_REG_INS))
       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);
          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)
+             || (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
       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);
 
 
       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 != '}')
       while (!ISALNUM (*paramP) && *paramP != '}')
-         paramP++;
+       paramP++;
     }
 
   if (*++paramP != '\0')
     as_warn (_("rest of line ignored; first ignored character is `%c'"),
             *paramP);
 
     }
 
   if (*++paramP != '\0')
     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);
 
   sprintf (maskstring, "$0x%x", mask);
   strcat (new_param, maskstring);
@@ -2400,12 +1835,13 @@ preprocess_reglist (char *param, int *allocated)
 /* Print the instruction.
    Handle also cases where the instruction is relaxable/relocatable.  */
 
 /* Print the instruction.
    Handle also cases where the instruction is relaxable/relocatable.  */
 
-void
+static void
 print_insn (ins *insn)
 {
   unsigned int i, j, insn_size;
   char *this_frag;
   unsigned short words[4];
 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++)
 
   /* Arrange the insn encodings in a WORD size array.  */
   for (i = 0, j = 0; i < 2; i++)
@@ -2414,7 +1850,7 @@ print_insn (ins *insn)
       words[j++] = output_opcode[i] & 0xFFFF;
     }
 
       words[j++] = output_opcode[i] & 0xFFFF;
     }
 
-  /* Handle relaxtion.  */
+  /* Handle relaxation.  */
   if ((instruction->flags & RELAXABLE) && relocatable)
     {
       int relax_subtype;
   if ((instruction->flags & RELAXABLE) && relocatable)
     {
       int relax_subtype;
@@ -2428,8 +1864,8 @@ print_insn (ins *insn)
       /* bal  */
       else if (IS_INSN_TYPE (DCR_BRANCH_INS) || IS_INSN_MNEMONIC ("bal"))
        relax_subtype = 3;
       /* 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 ();
        relax_subtype = 5;
       else
        abort ();
@@ -2467,6 +1903,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++)
     {
   /* Write the instruction encoding to frag.  */
   for (i = 0; i < insn_size; i++)
     {
@@ -2487,7 +1930,7 @@ md_assemble (char *op)
   char c;
 
   /* Reset global variables for a new instruction.  */
   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++)
 
   /* Strip the mnemonic.  */
   for (param = op; *param != 0 && !ISSPACE (*param); param++)
@@ -2496,30 +1939,28 @@ md_assemble (char *op)
   *param++ = '\0';
 
   /* Find the instruction.  */
   *param++ = '\0';
 
   /* Find the instruction.  */
-  instruction = (const inst *) hash_find (crx_inst_hash, op);
+  instruction = (const inst *) str_hash_find (crx_inst_hash, op);
   if (instruction == NULL)
     {
       as_bad (_("Unknown opcode: `%s'"), 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);
 
       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)
     {
   if (assemble_insn (op, &crx_ins) == 0)
     {
-      as_bad (_("Illegal operands in instruction : `%s'"), ins_parse);
+      param[-1] = c;
       return;
     }
 
   /* Print the instruction.  */
       return;
     }
 
   /* Print the instruction.  */
+  param[-1] = c;
   print_insn (&crx_ins);
 }
   print_insn (&crx_ins);
 }