* read.c (potable): Add string8, string16, string32 and string64. Add bit size for...
[binutils-gdb.git] / gas / config / tc-hppa.c
index bcf5654ae1ccf63aa784713de4b4556f751b8ae8..996c0027cf5eabb926171f2d6e2d47ab6745f17e 100644 (file)
@@ -1,12 +1,12 @@
 /* tc-hppa.c -- Assemble for the PA
    Copyright 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
 /* tc-hppa.c -- Assemble for the PA
    Copyright 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
    This file is part of GAS, the GNU Assembler.
 
    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,
 /* HP PA-RISC support was contributed by the Center for Software Science
    at the University of Utah.  */
 
 /* HP PA-RISC support was contributed by the Center for Software Science
    at the University of Utah.  */
 
-#include <stdio.h>
-
 #include "as.h"
 #include "safe-ctype.h"
 #include "subsegs.h"
 #include "as.h"
 #include "safe-ctype.h"
 #include "subsegs.h"
+#include "dw2gencfi.h"
 
 #include "bfd/libhppa.h"
 
 
 #include "bfd/libhppa.h"
 
@@ -490,112 +489,42 @@ struct selector_entry
 /* Prototypes for functions local to tc-hppa.c.  */
 
 #ifdef OBJ_SOM
 /* Prototypes for functions local to tc-hppa.c.  */
 
 #ifdef OBJ_SOM
-static void pa_check_current_space_and_subspace PARAMS ((void));
+static void pa_check_current_space_and_subspace (void);
 #endif
 
 #if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
 #endif
 
 #if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
-static void pa_text PARAMS ((int));
-static void pa_data PARAMS ((int));
-static void pa_comm PARAMS ((int));
+static void pa_text (int);
+static void pa_data (int);
+static void pa_comm (int);
 #endif
 #endif
-static fp_operand_format pa_parse_fp_format PARAMS ((char **s));
-static void pa_cons PARAMS ((int));
-static void pa_float_cons PARAMS ((int));
-static void pa_fill PARAMS ((int));
-static void pa_lcomm PARAMS ((int));
-static void pa_lsym PARAMS ((int));
-static void pa_stringer PARAMS ((int));
-static void pa_version PARAMS ((int));
-static int pa_parse_fp_cmp_cond PARAMS ((char **));
-static int get_expression PARAMS ((char *));
-static int pa_get_absolute_expression PARAMS ((struct pa_it *, char **));
-static int evaluate_absolute PARAMS ((struct pa_it *));
-static unsigned int pa_build_arg_reloc PARAMS ((char *));
-static unsigned int pa_align_arg_reloc PARAMS ((unsigned int, unsigned int));
-static int pa_parse_nullif PARAMS ((char **));
-static int pa_parse_nonneg_cmpsub_cmpltr PARAMS ((char **));
-static int pa_parse_neg_cmpsub_cmpltr PARAMS ((char **));
-static int pa_parse_neg_add_cmpltr PARAMS ((char **));
-static int pa_parse_nonneg_add_cmpltr PARAMS ((char **));
-static int pa_parse_cmpb_64_cmpltr PARAMS ((char **));
-static int pa_parse_cmpib_64_cmpltr PARAMS ((char **));
-static int pa_parse_addb_64_cmpltr PARAMS ((char **));
-static void pa_block PARAMS ((int));
-static void pa_brtab PARAMS ((int));
-static void pa_try PARAMS ((int));
-static void pa_call PARAMS ((int));
-static void pa_call_args PARAMS ((struct call_desc *));
-static void pa_callinfo PARAMS ((int));
-static void pa_copyright PARAMS ((int));
-static void pa_end PARAMS ((int));
-static void pa_enter PARAMS ((int));
-static void pa_entry PARAMS ((int));
-static void pa_equ PARAMS ((int));
-static void pa_exit PARAMS ((int));
-static void pa_export PARAMS ((int));
-static void pa_type_args PARAMS ((symbolS *, int));
-static void pa_import PARAMS ((int));
-static void pa_label PARAMS ((int));
-static void pa_leave PARAMS ((int));
-static void pa_level PARAMS ((int));
-static void pa_origin PARAMS ((int));
-static void pa_proc PARAMS ((int));
-static void pa_procend PARAMS ((int));
-static void pa_param PARAMS ((int));
-static void pa_undefine_label PARAMS ((void));
-static int need_pa11_opcode PARAMS ((void));
-static int pa_parse_number PARAMS ((char **, int));
-static label_symbol_struct *pa_get_label PARAMS ((void));
 #ifdef OBJ_SOM
 #ifdef OBJ_SOM
-static int exact_log2 PARAMS ((int));
-static void pa_compiler PARAMS ((int));
-static void pa_align PARAMS ((int));
-static void pa_space PARAMS ((int));
-static void pa_spnum PARAMS ((int));
-static void pa_subspace PARAMS ((int));
-static sd_chain_struct *create_new_space PARAMS ((char *, int, int,
+static int exact_log2 (int);
+static void pa_compiler (int);
+static void pa_align (int);
+static void pa_space (int);
+static void pa_spnum (int);
+static void pa_subspace (int);
+static sd_chain_struct *create_new_space (char *, int, int,
                                                  int, int, int,
                                                  int, int, int,
-                                                 asection *, int));
-static ssd_chain_struct *create_new_subspace PARAMS ((sd_chain_struct *,
+                                                 asection *, int);
+static ssd_chain_struct *create_new_subspace (sd_chain_struct *,
                                                      char *, int, int,
                                                      int, int, int, int,
                                                      int, int, int, int,
                                                      char *, int, int,
                                                      int, int, int, int,
                                                      int, int, int, int,
-                                                     int, asection *));
-static ssd_chain_struct *update_subspace PARAMS ((sd_chain_struct *,
+                                                     int, asection *);
+static ssd_chain_struct *update_subspace (sd_chain_struct *,
                                                  char *, int, int, int,
                                                  int, int, int, int,
                                                  int, int, int, int,
                                                  char *, int, int, int,
                                                  int, int, int, int,
                                                  int, int, int, int,
-                                                 asection *));
-static sd_chain_struct *is_defined_space PARAMS ((char *));
-static ssd_chain_struct *is_defined_subspace PARAMS ((char *));
-static sd_chain_struct *pa_segment_to_space PARAMS ((asection *));
-static ssd_chain_struct *pa_subsegment_to_subspace PARAMS ((asection *,
-                                                           subsegT));
-static sd_chain_struct *pa_find_space_by_number PARAMS ((int));
-static unsigned int pa_subspace_start PARAMS ((sd_chain_struct *, int));
-static sd_chain_struct *pa_parse_space_stmt PARAMS ((char *, int));
-static void pa_spaces_begin PARAMS ((void));
-#endif
-static void pa_ip PARAMS ((char *));
-static void fix_new_hppa PARAMS ((fragS *, int, int, symbolS *,
-                                 offsetT, expressionS *, int,
-                                 bfd_reloc_code_real_type,
-                                 enum hppa_reloc_field_selector_type_alt,
-                                 int, unsigned int, int));
-static int is_end_of_statement PARAMS ((void));
-static int reg_name_search PARAMS ((char *));
-static int pa_chk_field_selector PARAMS ((char **));
-static int is_same_frag PARAMS ((fragS *, fragS *));
-static void process_exit PARAMS ((void));
-static unsigned int pa_stringer_aux PARAMS ((char *));
-static fp_operand_format pa_parse_fp_cnv_format PARAMS ((char **s));
-static int pa_parse_ftest_gfx_completer PARAMS ((char **));
-
-#ifdef OBJ_ELF
-static void hppa_elf_mark_end_of_function PARAMS ((void));
-static void pa_build_unwind_subspace PARAMS ((struct call_info *));
-static void pa_vtable_entry PARAMS ((int));
-static void pa_vtable_inherit  PARAMS ((int));
+                                                 asection *);
+static sd_chain_struct *is_defined_space (char *);
+static ssd_chain_struct *is_defined_subspace (char *);
+static sd_chain_struct *pa_segment_to_space (asection *);
+static ssd_chain_struct *pa_subsegment_to_subspace (asection *,
+                                                           subsegT);
+static sd_chain_struct *pa_find_space_by_number (int);
+static unsigned int pa_subspace_start (sd_chain_struct *, int);
+static sd_chain_struct *pa_parse_space_stmt (char *, int);
 #endif
 
 /* File and globally scoped variable declarations.  */
 #endif
 
 /* File and globally scoped variable declarations.  */
@@ -629,96 +558,6 @@ static struct hash_control *op_hash = NULL;
    as they never appear followed by meaningful whitespace.  */
 const char hppa_symbol_chars[] = "*?=<>";
 
    as they never appear followed by meaningful whitespace.  */
 const char hppa_symbol_chars[] = "*?=<>";
 
-/* Table of pseudo ops for the PA.  FIXME -- how many of these
-   are now redundant with the overall GAS and the object file
-   dependent tables?  */
-const pseudo_typeS md_pseudo_table[] =
-{
-  /* align pseudo-ops on the PA specify the actual alignment requested,
-     not the log2 of the requested alignment.  */
-#ifdef OBJ_SOM
-  {"align", pa_align, 8},
-#endif
-#ifdef OBJ_ELF
-  {"align", s_align_bytes, 8},
-#endif
-  {"begin_brtab", pa_brtab, 1},
-  {"begin_try", pa_try, 1},
-  {"block", pa_block, 1},
-  {"blockz", pa_block, 0},
-  {"byte", pa_cons, 1},
-  {"call", pa_call, 0},
-  {"callinfo", pa_callinfo, 0},
-#if defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD))
-  {"code", obj_elf_text, 0},
-#else
-  {"code", pa_text, 0},
-  {"comm", pa_comm, 0},
-#endif
-#ifdef OBJ_SOM
-  {"compiler", pa_compiler, 0},
-#endif
-  {"copyright", pa_copyright, 0},
-#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
-  {"data", pa_data, 0},
-#endif
-  {"double", pa_float_cons, 'd'},
-  {"dword", pa_cons, 8},
-  {"end", pa_end, 0},
-  {"end_brtab", pa_brtab, 0},
-#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
-  {"end_try", pa_try, 0},
-#endif
-  {"enter", pa_enter, 0},
-  {"entry", pa_entry, 0},
-  {"equ", pa_equ, 0},
-  {"exit", pa_exit, 0},
-  {"export", pa_export, 0},
-  {"fill", pa_fill, 0},
-  {"float", pa_float_cons, 'f'},
-  {"half", pa_cons, 2},
-  {"import", pa_import, 0},
-  {"int", pa_cons, 4},
-  {"label", pa_label, 0},
-  {"lcomm", pa_lcomm, 0},
-  {"leave", pa_leave, 0},
-  {"level", pa_level, 0},
-  {"long", pa_cons, 4},
-  {"lsym", pa_lsym, 0},
-#ifdef OBJ_SOM
-  {"nsubspa", pa_subspace, 1},
-#endif
-  {"octa", pa_cons, 16},
-  {"org", pa_origin, 0},
-  {"origin", pa_origin, 0},
-  {"param", pa_param, 0},
-  {"proc", pa_proc, 0},
-  {"procend", pa_procend, 0},
-  {"quad", pa_cons, 8},
-  {"reg", pa_equ, 1},
-  {"short", pa_cons, 2},
-  {"single", pa_float_cons, 'f'},
-#ifdef OBJ_SOM
-  {"space", pa_space, 0},
-  {"spnum", pa_spnum, 0},
-#endif
-  {"string", pa_stringer, 0},
-  {"stringz", pa_stringer, 1},
-#ifdef OBJ_SOM
-  {"subspa", pa_subspace, 0},
-#endif
-#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
-  {"text", pa_text, 0},
-#endif
-  {"version", pa_version, 0},
-#ifdef OBJ_ELF
-  {"vtable_entry", pa_vtable_entry, 0},
-  {"vtable_inherit", pa_vtable_inherit, 0},
-#endif
-  {"word", pa_cons, 4},
-  {NULL, 0, 0}
-};
-
 /* This array holds the chars that only start a comment at the beginning of
    a line.  If the line seems to have the form '# 123 filename'
    .line and .file directives will appear in the pre-processed output.
 /* This array holds the chars that only start a comment at the beginning of
    a line.  If the line seems to have the form '# 123 filename'
    .line and .file directives will appear in the pre-processed output.
@@ -1215,6 +1054,26 @@ static struct default_space_dict pa_def_spaces[] =
   ((exp).X_op == O_subtract                    \
    && strcmp (S_GET_NAME ((exp).X_op_symbol), "$PIC_pcrel$0") == 0)
 
   ((exp).X_op == O_subtract                    \
    && strcmp (S_GET_NAME ((exp).X_op_symbol), "$PIC_pcrel$0") == 0)
 
+#define is_tls_gdidx(exp)                      \
+  ((exp).X_op == O_subtract                    \
+   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$tls_gdidx$") == 0)
+
+#define is_tls_ldidx(exp)                      \
+  ((exp).X_op == O_subtract                    \
+   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$tls_ldidx$") == 0)
+
+#define is_tls_dtpoff(exp)                     \
+  ((exp).X_op == O_subtract                    \
+   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$tls_dtpoff$") == 0)
+
+#define is_tls_ieoff(exp)                      \
+  ((exp).X_op == O_subtract                    \
+   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$tls_ieoff$") == 0)
+
+#define is_tls_leoff(exp)                      \
+  ((exp).X_op == O_subtract                    \
+   && strcmp (S_GET_NAME ((exp).X_op_symbol), "$tls_leoff$") == 0)
+
 /* We need some complex handling for stabs (sym1 - sym2).  Luckily, we'll
    always be able to reduce the expression to a constant, so we don't
    need real complex handling yet.  */
 /* We need some complex handling for stabs (sym1 - sym2).  Luckily, we'll
    always be able to reduce the expression to a constant, so we don't
    need real complex handling yet.  */
@@ -1227,7 +1086,7 @@ static struct default_space_dict pa_def_spaces[] =
    proc/procend pairs match.  */
 
 void
    proc/procend pairs match.  */
 
 void
-pa_check_eof ()
+pa_check_eof (void)
 {
   if (within_entry_exit)
     as_fatal (_("Missing .exit\n"));
 {
   if (within_entry_exit)
     as_fatal (_("Missing .exit\n"));
@@ -1240,7 +1099,7 @@ pa_check_eof ()
    or NULL if no label_symbol_struct exists for the current space.  */
 
 static label_symbol_struct *
    or NULL if no label_symbol_struct exists for the current space.  */
 
 static label_symbol_struct *
-pa_get_label ()
+pa_get_label (void)
 {
   label_symbol_struct *label_chain;
 
 {
   label_symbol_struct *label_chain;
 
@@ -1265,8 +1124,7 @@ pa_get_label ()
    this function will replace it with the new label.  */
 
 void
    this function will replace it with the new label.  */
 
 void
-pa_define_label (symbol)
-     symbolS *symbol;
+pa_define_label (symbolS *symbol)
 {
   label_symbol_struct *label_chain = pa_get_label ();
 
 {
   label_symbol_struct *label_chain = pa_get_label ();
 
@@ -1275,8 +1133,7 @@ pa_define_label (symbol)
   else
     {
       /* Create a new label entry and add it to the head of the chain.  */
   else
     {
       /* Create a new label entry and add it to the head of the chain.  */
-      label_chain
-       = (label_symbol_struct *) xmalloc (sizeof (label_symbol_struct));
+      label_chain = xmalloc (sizeof (label_symbol_struct));
       label_chain->lss_label = symbol;
 #ifdef OBJ_SOM
       label_chain->lss_space = current_space;
       label_chain->lss_label = symbol;
 #ifdef OBJ_SOM
       label_chain->lss_space = current_space;
@@ -1301,7 +1158,7 @@ pa_define_label (symbol)
    If there is no label_symbol_struct entry, then no action is taken.  */
 
 static void
    If there is no label_symbol_struct entry, then no action is taken.  */
 
 static void
-pa_undefine_label ()
+pa_undefine_label (void)
 {
   label_symbol_struct *label_chain;
   label_symbol_struct *prev_label_chain = NULL;
 {
   label_symbol_struct *label_chain;
   label_symbol_struct *prev_label_chain = NULL;
@@ -1340,25 +1197,21 @@ pa_undefine_label ()
    tc_fix_data field.  */
 
 static void
    tc_fix_data field.  */
 
 static void
-fix_new_hppa (frag, where, size, add_symbol, offset, exp, pcrel,
-             r_type, r_field, r_format, arg_reloc, unwind_bits)
-     fragS *frag;
-     int where;
-     int size;
-     symbolS *add_symbol;
-     offsetT offset;
-     expressionS *exp;
-     int pcrel;
-     bfd_reloc_code_real_type r_type;
-     enum hppa_reloc_field_selector_type_alt r_field;
-     int r_format;
-     unsigned int arg_reloc;
-     int unwind_bits ATTRIBUTE_UNUSED;
+fix_new_hppa (fragS *frag,
+             int where,
+             int size,
+             symbolS *add_symbol,
+             offsetT offset,
+             expressionS *exp,
+             int pcrel,
+             bfd_reloc_code_real_type r_type,
+             enum hppa_reloc_field_selector_type_alt r_field,
+             int r_format,
+             unsigned int arg_reloc,
+             int unwind_bits ATTRIBUTE_UNUSED)
 {
   fixS *new_fix;
 {
   fixS *new_fix;
-
-  struct hppa_fix_struct *hppa_fix = (struct hppa_fix_struct *)
-  obstack_alloc (&notes, sizeof (struct hppa_fix_struct));
+  struct hppa_fix_struct *hppa_fix = obstack_alloc (&notes, sizeof (struct hppa_fix_struct));
 
   if (exp != NULL)
     new_fix = fix_new_exp (frag, where, size, exp, pcrel, r_type);
 
   if (exp != NULL)
     new_fix = fix_new_exp (frag, where, size, exp, pcrel, r_type);
@@ -1380,30 +1233,20 @@ fix_new_hppa (frag, where, size, add_symbol, offset, exp, pcrel,
      it now so as not to confuse write.c.  Ditto for $PIC_pcrel$0.  */
   if (new_fix->fx_subsy
       && (strcmp (S_GET_NAME (new_fix->fx_subsy), "$global$") == 0
      it now so as not to confuse write.c.  Ditto for $PIC_pcrel$0.  */
   if (new_fix->fx_subsy
       && (strcmp (S_GET_NAME (new_fix->fx_subsy), "$global$") == 0
-         || strcmp (S_GET_NAME (new_fix->fx_subsy), "$PIC_pcrel$0") == 0))
+         || strcmp (S_GET_NAME (new_fix->fx_subsy), "$PIC_pcrel$0") == 0
+         || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_gdidx$") == 0
+         || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_ldidx$") == 0
+         || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_dtpoff$") == 0
+         || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_ieoff$") == 0
+         || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_leoff$") == 0))
     new_fix->fx_subsy = NULL;
 }
 
     new_fix->fx_subsy = NULL;
 }
 
-/* Parse a .byte, .word, .long expression for the HPPA.  Called by
-   cons via the TC_PARSE_CONS_EXPRESSION macro.  */
-
-void
-parse_cons_expression_hppa (exp)
-     expressionS *exp;
-{
-  hppa_field_selector = pa_chk_field_selector (&input_line_pointer);
-  expression (exp);
-}
-
 /* This fix_new is called by cons via TC_CONS_FIX_NEW.
    hppa_field_selector is set by the parse_cons_expression_hppa.  */
 
 void
 /* This fix_new is called by cons via TC_CONS_FIX_NEW.
    hppa_field_selector is set by the parse_cons_expression_hppa.  */
 
 void
-cons_fix_new_hppa (frag, where, size, exp)
-     fragS *frag;
-     int where;
-     int size;
-     expressionS *exp;
+cons_fix_new_hppa (fragS *frag, int where, int size, expressionS *exp)
 {
   unsigned int rel_type;
 
 {
   unsigned int rel_type;
 
@@ -1412,6 +1255,18 @@ cons_fix_new_hppa (frag, where, size, exp)
     rel_type = R_HPPA_GOTOFF;
   else if (is_PC_relative (*exp))
     rel_type = R_HPPA_PCREL_CALL;
     rel_type = R_HPPA_GOTOFF;
   else if (is_PC_relative (*exp))
     rel_type = R_HPPA_PCREL_CALL;
+#ifdef OBJ_ELF
+  else if (is_tls_gdidx (*exp))
+    rel_type = R_PARISC_TLS_GD21L;
+  else if (is_tls_ldidx (*exp))
+    rel_type = R_PARISC_TLS_LDM21L;
+  else if (is_tls_dtpoff (*exp))
+    rel_type = R_PARISC_TLS_LDO21L;
+  else if (is_tls_ieoff (*exp))
+    rel_type = R_PARISC_TLS_IE21L;
+  else if (is_tls_leoff (*exp))
+    rel_type = R_PARISC_TLS_LE21L;
+#endif
   else if (is_complex (*exp))
     rel_type = R_HPPA_COMPLEX;
   else
   else if (is_complex (*exp))
     rel_type = R_HPPA_COMPLEX;
   else
@@ -1431,4508 +1286,4518 @@ cons_fix_new_hppa (frag, where, size, exp)
   hppa_field_selector = 0;
 }
 
   hppa_field_selector = 0;
 }
 
-/* This function is called once, at assembler startup time.  It should
-   set up all the tables, etc. that the MD part of the assembler will need.  */
+/* Mark (via expr_end) the end of an expression (I think).  FIXME.  */
 
 
-void
-md_begin ()
+static void
+get_expression (char *str)
 {
 {
-  const char *retval = NULL;
-  int lose = 0;
-  unsigned int i = 0;
-
-  last_call_info = NULL;
-  call_info_root = NULL;
-
-  /* Set the default machine type.  */
-  if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, DEFAULT_LEVEL))
-    as_warn (_("could not set architecture and machine"));
+  char *save_in;
+  asection *seg;
 
 
-  /* Folding of text and data segments fails miserably on the PA.
-     Warn user and disable "-R" option.  */
-  if (flag_readonly_data_in_text)
+  save_in = input_line_pointer;
+  input_line_pointer = str;
+  seg = expression (&the_insn.exp);
+  if (!(seg == absolute_section
+       || seg == undefined_section
+       || SEG_NORMAL (seg)))
     {
     {
-      as_warn (_("-R option not supported on this target."));
-      flag_readonly_data_in_text = 0;
+      as_warn (_("Bad segment in expression."));
+      expr_end = input_line_pointer;
+      input_line_pointer = save_in;
+      return;
     }
     }
+  expr_end = input_line_pointer;
+  input_line_pointer = save_in;
+}
 
 
-#ifdef OBJ_SOM
-  pa_spaces_begin ();
-#endif
+/* Parse a PA nullification completer (,n).  Return nonzero if the
+   completer was found; return zero if no completer was found.  */
 
 
-  op_hash = hash_new ();
+static int
+pa_parse_nullif (char **s)
+{
+  int nullif;
 
 
-  while (i < NUMOPCODES)
+  nullif = 0;
+  if (**s == ',')
     {
     {
-      const char *name = pa_opcodes[i].name;
-      retval = hash_insert (op_hash, name, (struct pa_opcode *) &pa_opcodes[i]);
-      if (retval != NULL && *retval != '\0')
-       {
-         as_fatal (_("Internal error: can't hash `%s': %s\n"), name, retval);
-         lose = 1;
-       }
-      do
+      *s = *s + 1;
+      if (strncasecmp (*s, "n", 1) == 0)
+       nullif = 1;
+      else
        {
        {
-         if ((pa_opcodes[i].match & pa_opcodes[i].mask)
-             != pa_opcodes[i].match)
-           {
-             fprintf (stderr, _("internal error: losing opcode: `%s' \"%s\"\n"),
-                      pa_opcodes[i].name, pa_opcodes[i].args);
-             lose = 1;
-           }
-         ++i;
+         as_bad (_("Invalid Nullification: (%c)"), **s);
+         nullif = 0;
        }
        }
-      while (i < NUMOPCODES && !strcmp (pa_opcodes[i].name, name));
+      *s = *s + 1;
     }
 
     }
 
-  if (lose)
-    as_fatal (_("Broken assembler.  No assembly attempted."));
-
-#ifdef OBJ_SOM
-  /* SOM will change text_section.  To make sure we never put
-     anything into the old one switch to the new one now.  */
-  subseg_set (text_section, 0);
-#endif
-
-#ifdef OBJ_SOM
-  dummy_symbol = symbol_find_or_make ("L$dummy");
-  S_SET_SEGMENT (dummy_symbol, text_section);
-  /* Force the symbol to be converted to a real symbol.  */
-  (void) symbol_get_bfdsym (dummy_symbol);
-#endif
+  return nullif;
 }
 
 }
 
-/* Assemble a single instruction storing it into a frag.  */
-void
-md_assemble (str)
-     char *str;
-{
-  char *to;
+/* 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 or NULL is returned.  */
 
 
-  /* The had better be something to assemble.  */
-  assert (str);
+#define MAX_LITTLENUMS 6
 
 
-  /* If we are within a procedure definition, make sure we've
-     defined a label for the procedure; handle case where the
-     label was defined after the .PROC directive.
+char *
+md_atof (int type, char *litP, int *sizeP)
+{
+  int prec;
+  LITTLENUM_TYPE words[MAX_LITTLENUMS];
+  LITTLENUM_TYPE *wordP;
+  char *t;
 
 
-     Note there's not need to diddle with the segment or fragment
-     for the label symbol in this case.  We have already switched
-     into the new $CODE$ subspace at this point.  */
-  if (within_procedure && last_call_info->start_symbol == NULL)
+  switch (type)
     {
     {
-      label_symbol_struct *label_symbol = pa_get_label ();
 
 
-      if (label_symbol)
-       {
-         if (label_symbol->lss_label)
-           {
-             last_call_info->start_symbol = label_symbol->lss_label;
-             symbol_get_bfdsym (label_symbol->lss_label)->flags
-               |= BSF_FUNCTION;
-#ifdef OBJ_SOM
-             /* Also handle allocation of a fixup to hold the unwind
-                information when the label appears after the proc/procend.  */
-             if (within_entry_exit)
-               {
-                 char *where;
-                 unsigned int u;
+    case 'f':
+    case 'F':
+    case 's':
+    case 'S':
+      prec = 2;
+      break;
 
 
-                 where = frag_more (0);
-                 u = UNWIND_LOW32 (&last_call_info->ci_unwind.descriptor);
-                 fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
-                               NULL, (offsetT) 0, NULL,
-                               0, R_HPPA_ENTRY, e_fsel, 0, 0, u);
-               }
-#endif
-           }
-         else
-           as_bad (_("Missing function name for .PROC (corrupted label chain)"));
-       }
-      else
-       as_bad (_("Missing function name for .PROC"));
-    }
+    case 'd':
+    case 'D':
+    case 'r':
+    case 'R':
+      prec = 4;
+      break;
 
 
-  /* Assemble the instruction.  Results are saved into "the_insn".  */
-  pa_ip (str);
+    case 'x':
+    case 'X':
+      prec = 6;
+      break;
 
 
-  /* Get somewhere to put the assembled instruction.  */
-  to = frag_more (4);
+    case 'p':
+    case 'P':
+      prec = 6;
+      break;
 
 
-  /* Output the opcode.  */
-  md_number_to_chars (to, the_insn.opcode, 4);
+    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 * sizeof (LITTLENUM_TYPE);
+  for (wordP = words; prec--;)
+    {
+      md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE));
+      litP += sizeof (LITTLENUM_TYPE);
+    }
+  return NULL;
+}
 
 
-  /* If necessary output more stuff.  */
-  if (the_insn.reloc != R_HPPA_NONE)
-    fix_new_hppa (frag_now, (to - frag_now->fr_literal), 4, NULL,
-                 (offsetT) 0, &the_insn.exp, the_insn.pcrel,
-                 the_insn.reloc, the_insn.field_selector,
-                 the_insn.format, the_insn.arg_reloc, 0);
+/* Write out big-endian.  */
 
 
-#ifdef OBJ_ELF
-  dwarf2_emit_insn (4);
-#endif
+void
+md_number_to_chars (char *buf, valueT val, int n)
+{
+  number_to_chars_bigendian (buf, val, n);
 }
 
 }
 
-/* Do the real work for assembling a single instruction.  Store results
-   into the global "the_insn" variable.  */
+/* Translate internal representation of relocation info to BFD target
+   format.  */
 
 
-static void
-pa_ip (str)
-     char *str;
+arelent **
+tc_gen_reloc (asection *section, fixS *fixp)
 {
 {
-  char *error_message = "";
-  char *s, c, *argstart, *name, *save_s;
-  const char *args;
-  int match = FALSE;
-  int comma = 0;
-  int cmpltr, nullif, flag, cond, num;
-  unsigned long opcode;
-  struct pa_opcode *insn;
+  arelent *reloc;
+  struct hppa_fix_struct *hppa_fixp;
+  static arelent *no_relocs = NULL;
+  arelent **relocs;
+  reloc_type **codes;
+  reloc_type code;
+  int n_relocs;
+  int i;
 
 
-#ifdef OBJ_SOM
-  /* We must have a valid space and subspace.  */
-  pa_check_current_space_and_subspace ();
-#endif
+  hppa_fixp = (struct hppa_fix_struct *) fixp->tc_fix_data;
+  if (fixp->fx_addsy == 0)
+    return &no_relocs;
 
 
-  /* Convert everything up to the first whitespace character into lower
-     case.  */
-  for (s = str; *s != ' ' && *s != '\t' && *s != '\n' && *s != '\0'; s++)
-    *s = TOLOWER (*s);
+  assert (hppa_fixp != 0);
+  assert (section != 0);
 
 
-  /* Skip to something interesting.  */
-  for (s = str;
-       ISUPPER (*s) || ISLOWER (*s) || (*s >= '0' && *s <= '3');
-       ++s)
+  reloc = xmalloc (sizeof (arelent));
+
+  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+  codes = hppa_gen_reloc_type (stdoutput,
+                              fixp->fx_r_type,
+                              hppa_fixp->fx_r_format,
+                              hppa_fixp->fx_r_field,
+                              fixp->fx_subsy != NULL,
+                              symbol_get_bfdsym (fixp->fx_addsy));
+
+  if (codes == NULL)
+    {
+      as_bad_where (fixp->fx_file, fixp->fx_line, _("Cannot handle fixup"));
+      abort ();
+    }
+
+  for (n_relocs = 0; codes[n_relocs]; n_relocs++)
     ;
 
     ;
 
-  switch (*s)
+  relocs = xmalloc (sizeof (arelent *) * n_relocs + 1);
+  reloc = xmalloc (sizeof (arelent) * n_relocs);
+  for (i = 0; i < n_relocs; i++)
+    relocs[i] = &reloc[i];
+
+  relocs[n_relocs] = NULL;
+
+#ifdef OBJ_ELF
+  switch (fixp->fx_r_type)
     {
     {
+    default:
+      assert (n_relocs == 1);
 
 
-    case '\0':
-      break;
+      code = *codes[0];
 
 
-    case ',':
-      comma = 1;
+      /* Now, do any processing that is dependent on the relocation type.  */
+      switch (code)
+       {
+       case R_PARISC_DLTREL21L:
+       case R_PARISC_DLTREL14R:
+       case R_PARISC_DLTREL14F:
+       case R_PARISC_PLABEL32:
+       case R_PARISC_PLABEL21L:
+       case R_PARISC_PLABEL14R:
+         /* For plabel relocations, the addend of the
+            relocation should be either 0 (no static link) or 2
+            (static link required).  This adjustment is done in
+            bfd/elf32-hppa.c:elf32_hppa_relocate_section.
 
 
-      /*FALLTHROUGH */
+            We also slam a zero addend into the DLT relative relocs;
+            it doesn't make a lot of sense to use any addend since
+            it gets you a different (eg unknown) DLT entry.  */
+         reloc->addend = 0;
+         break;
 
 
-    case ' ':
-      *s++ = '\0';
-      break;
+#ifdef ELF_ARG_RELOC
+       case R_PARISC_PCREL17R:
+       case R_PARISC_PCREL17F:
+       case R_PARISC_PCREL17C:
+       case R_PARISC_DIR17R:
+       case R_PARISC_DIR17F:
+       case R_PARISC_PCREL21L:
+       case R_PARISC_DIR21L:
+         reloc->addend = HPPA_R_ADDEND (hppa_fixp->fx_arg_reloc,
+                                        fixp->fx_offset);
+         break;
+#endif
 
 
-    default:
-      as_bad (_("Unknown opcode: `%s'"), str);
-      return;
-    }
+       case R_PARISC_DIR32:
+         /* Facilitate hand-crafted unwind info.  */
+         if (strcmp (section->name, UNWIND_SECTION_NAME) == 0)
+           code = R_PARISC_SEGREL32;
+         /* Fall thru */
 
 
-  /* Look up the opcode in the has table.  */
-  if ((insn = (struct pa_opcode *) hash_find (op_hash, str)) == NULL)
-    {
-      as_bad ("Unknown opcode: `%s'", str);
-      return;
-    }
+       default:
+         reloc->addend = fixp->fx_offset;
+         break;
+       }
 
 
-  if (comma)
-    {
-      *--s = ',';
+      reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+      *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+      reloc->howto = bfd_reloc_type_lookup (stdoutput,
+                                           (bfd_reloc_code_real_type) code);
+      reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
+      assert (reloc->howto && (unsigned int) code == reloc->howto->type);
+      break;
     }
     }
+#else /* OBJ_SOM */
 
 
-  /* Mark the location where arguments for the instruction start, then
-     start processing them.  */
-  argstart = s;
-  for (;;)
+  /* Walk over reach relocation returned by the BFD backend.  */
+  for (i = 0; i < n_relocs; i++)
     {
     {
-      /* Do some initialization.  */
-      opcode = insn->match;
-      strict = (insn->flags & FLAG_STRICT);
-      memset (&the_insn, 0, sizeof (the_insn));
-
-      the_insn.reloc = R_HPPA_NONE;
+      code = *codes[i];
 
 
-      if (insn->arch >= pa20
-         && bfd_get_mach (stdoutput) < insn->arch)
-       goto failed;
+      relocs[i]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+      *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+      relocs[i]->howto =
+       bfd_reloc_type_lookup (stdoutput,
+                              (bfd_reloc_code_real_type) code);
+      relocs[i]->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
 
-      /* Build the opcode, checking as we go to make
-         sure that the operands match.  */
-      for (args = insn->args;; ++args)
+      switch (code)
        {
        {
-         /* Absorb white space in instruction.  */
-         while (*s == ' ' || *s == '\t')
-           s++;
+       case R_COMP2:
+         /* The only time we ever use a R_COMP2 fixup is for the difference
+            of two symbols.  With that in mind we fill in all four
+            relocs now and break out of the loop.  */
+         assert (i == 1);
+         relocs[0]->sym_ptr_ptr
+           = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
+         relocs[0]->howto
+           = bfd_reloc_type_lookup (stdoutput,
+                                    (bfd_reloc_code_real_type) *codes[0]);
+         relocs[0]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+         relocs[0]->addend = 0;
+         relocs[1]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+         *relocs[1]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+         relocs[1]->howto
+           = bfd_reloc_type_lookup (stdoutput,
+                                    (bfd_reloc_code_real_type) *codes[1]);
+         relocs[1]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+         relocs[1]->addend = 0;
+         relocs[2]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+         *relocs[2]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
+         relocs[2]->howto
+           = bfd_reloc_type_lookup (stdoutput,
+                                    (bfd_reloc_code_real_type) *codes[2]);
+         relocs[2]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+         relocs[2]->addend = 0;
+         relocs[3]->sym_ptr_ptr
+           = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
+         relocs[3]->howto
+           = bfd_reloc_type_lookup (stdoutput,
+                                    (bfd_reloc_code_real_type) *codes[3]);
+         relocs[3]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+         relocs[3]->addend = 0;
+         relocs[4]->sym_ptr_ptr
+           = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
+         relocs[4]->howto
+           = bfd_reloc_type_lookup (stdoutput,
+                                    (bfd_reloc_code_real_type) *codes[4]);
+         relocs[4]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+         relocs[4]->addend = 0;
+         goto done;
+       case R_PCREL_CALL:
+       case R_ABS_CALL:
+         relocs[i]->addend = HPPA_R_ADDEND (hppa_fixp->fx_arg_reloc, 0);
+         break;
 
 
-         switch (*args)
-           {
+       case R_DLT_REL:
+       case R_DATA_PLABEL:
+       case R_CODE_PLABEL:
+         /* For plabel relocations, the addend of the
+            relocation should be either 0 (no static link) or 2
+            (static link required).
 
 
-           /* End of arguments.  */
-           case '\0':
-             if (*s == '\0')
-               match = TRUE;
-             break;
+            FIXME: We always assume no static link!
 
 
-           case '+':
-             if (*s == '+')
-               {
-                 ++s;
-                 continue;
-               }
-             if (*s == '-')
-               continue;
-             break;
+            We also slam a zero addend into the DLT relative relocs;
+            it doesn't make a lot of sense to use any addend since
+            it gets you a different (eg unknown) DLT entry.  */
+         relocs[i]->addend = 0;
+         break;
 
 
-           /* These must match exactly.  */
-           case '(':
-           case ')':
-           case ',':
-           case ' ':
-             if (*s++ == *args)
-               continue;
-             break;
+       case R_N_MODE:
+       case R_S_MODE:
+       case R_D_MODE:
+       case R_R_MODE:
+       case R_FSEL:
+       case R_LSEL:
+       case R_RSEL:
+       case R_BEGIN_BRTAB:
+       case R_END_BRTAB:
+       case R_BEGIN_TRY:
+       case R_N0SEL:
+       case R_N1SEL:
+         /* There is no symbol or addend associated with these fixups.  */
+         relocs[i]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+         *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
+         relocs[i]->addend = 0;
+         break;
 
 
-           /* Handle a 5 bit register or control register field at 10.  */
-           case 'b':
-           case '^':
-             if (!pa_parse_number (&s, 0))
-               break;
-             num = pa_number;
-             CHECK_FIELD (num, 31, 0, 0);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
+       case R_END_TRY:
+       case R_ENTRY:
+       case R_EXIT:
+         /* There is no symbol associated with these fixups.  */
+         relocs[i]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+         *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
+         relocs[i]->addend = fixp->fx_offset;
+         break;
 
 
-           /* Handle %sar or %cr11.  No bits get set, we just verify that it
-              is there.  */
-           case '!':
-             /* Skip whitespace before register.  */
-             while (*s == ' ' || *s == '\t')
-               s = s + 1;
+       default:
+         relocs[i]->addend = fixp->fx_offset;
+       }
+    }
 
 
-             if (!strncasecmp (s, "%sar", 4))
-               {
-                 s += 4;
-                 continue;
-               }
-             else if (!strncasecmp (s, "%cr11", 5))
-               {
-                 s += 5;
-                 continue;
-               }
-             break;
+ done:
+#endif
 
 
-           /* Handle a 5 bit register field at 15.  */
-           case 'x':
-             if (!pa_parse_number (&s, 0))
-               break;
-             num = pa_number;
-             CHECK_FIELD (num, 31, 0, 0);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
+  return relocs;
+}
 
 
-           /* Handle a 5 bit register field at 31.  */
-           case 't':
-             if (!pa_parse_number (&s, 0))
-               break;
-             num = pa_number;
-             CHECK_FIELD (num, 31, 0, 0);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+/* Process any machine dependent frag types.  */
 
 
-           /* Handle a 5 bit register field at 10 and 15.  */
-           case 'a':
-             if (!pa_parse_number (&s, 0))
-               break;
-             num = pa_number;
-             CHECK_FIELD (num, 31, 0, 0);
-             opcode |= num << 16;
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
+void
+md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
+                asection *sec ATTRIBUTE_UNUSED,
+                fragS *fragP)
+{
+  unsigned int address;
 
 
-           /* Handle a 5 bit field length at 31.  */
-           case 'T':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 32, 1, 0);
-             INSERT_FIELD_AND_CONTINUE (opcode, 32 - num, 0);
+  if (fragP->fr_type == rs_machine_dependent)
+    {
+      switch ((int) fragP->fr_subtype)
+       {
+       case 0:
+         fragP->fr_type = rs_fill;
+         know (fragP->fr_var == 1);
+         know (fragP->fr_next);
+         address = fragP->fr_address + fragP->fr_fix;
+         if (address % fragP->fr_offset)
+           {
+             fragP->fr_offset =
+               fragP->fr_next->fr_address
+               - fragP->fr_address
+               - fragP->fr_fix;
+           }
+         else
+           fragP->fr_offset = 0;
+         break;
+       }
+    }
+}
 
 
-           /* Handle a 5 bit immediate at 15.  */
-           case '5':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             /* When in strict mode, we want to just reject this
-                match instead of giving an out of range error.  */
-             CHECK_FIELD (num, 15, -16, strict);
-             num = low_sign_unext (num, 5);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
+/* Round up a section size to the appropriate boundary.  */
 
 
-           /* Handle a 5 bit immediate at 31.  */
-           case 'V':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             /* When in strict mode, we want to just reject this
-                match instead of giving an out of range error.  */
-             CHECK_FIELD (num, 15, -16, strict);
-             num = low_sign_unext (num, 5);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+valueT
+md_section_align (asection *segment, valueT size)
+{
+  int align = bfd_get_section_alignment (stdoutput, segment);
+  int align2 = (1 << align) - 1;
 
 
-           /* Handle an unsigned 5 bit immediate at 31.  */
-           case 'r':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 31, 0, strict);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+  return (size + align2) & ~align2;
+}
 
 
-           /* Handle an unsigned 5 bit immediate at 15.  */
-           case 'R':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 31, 0, strict);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
+/* Return the approximate size of a frag before relaxation has occurred.  */
 
 
-           /* Handle an unsigned 10 bit immediate at 15.  */
-           case 'U':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 1023, 0, strict);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
+int
+md_estimate_size_before_relax (fragS *fragP, asection *segment ATTRIBUTE_UNUSED)
+{
+  int size;
 
 
-           /* Handle a 2 bit space identifier at 17.  */
-           case 's':
-             if (!pa_parse_number (&s, 0))
-               break;
-             num = pa_number;
-             CHECK_FIELD (num, 3, 0, 1);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 14);
+  size = 0;
 
 
-           /* Handle a 3 bit space identifier at 18.  */
-           case 'S':
-             if (!pa_parse_number (&s, 0))
-               break;
-             num = pa_number;
-             CHECK_FIELD (num, 7, 0, 1);
-             opcode |= re_assemble_3 (num);
-             continue;
+  while ((fragP->fr_fix + size) % fragP->fr_offset)
+    size++;
 
 
-           /* Handle all completers.  */
-           case 'c':
-             switch (*++args)
-               {
+  return size;
+}
+\f
+#ifdef OBJ_ELF
+# ifdef WARN_COMMENTS
+const char *md_shortopts = "Vc";
+# else
+const char *md_shortopts = "V";
+# endif
+#else
+# ifdef WARN_COMMENTS
+const char *md_shortopts = "c";
+# else
+const char *md_shortopts = "";
+# endif
+#endif
 
 
-               /* Handle a completer for an indexing load or store.  */
-               case 'X':
-               case 'x':
-                 {
-                   int uu = 0;
-                   int m = 0;
-                   int i = 0;
-                   while (*s == ',' && i < 2)
-                     {
-                       s++;
-                       if (strncasecmp (s, "sm", 2) == 0)
-                         {
-                           uu = 1;
-                           m = 1;
-                           s++;
-                           i++;
-                         }
-                       else if (strncasecmp (s, "m", 1) == 0)
-                         m = 1;
-                       else if ((strncasecmp (s, "s ", 2) == 0)
-                                || (strncasecmp (s, "s,", 2) == 0))
-                         uu = 1;
-                       else if (strict)
-                         {
-                           /* This is a match failure.  */
-                           s--;
-                           break;
-                         }
-                       else
-                         as_bad (_("Invalid Indexed Load Completer."));
-                       s++;
-                       i++;
-                     }
-                   if (i > 2)
-                     as_bad (_("Invalid Indexed Load Completer Syntax."));
-                   opcode |= m << 5;
-                   INSERT_FIELD_AND_CONTINUE (opcode, uu, 13);
-                 }
-
-               /* Handle a short load/store completer.  */
-               case 'M':
-               case 'm':
-               case 'q':
-               case 'J':
-               case 'e':
-                 {
-                   int a = 0;
-                   int m = 0;
-                   if (*s == ',')
-                     {
-                       s++;
-                       if (strncasecmp (s, "ma", 2) == 0)
-                         {
-                           a = 0;
-                           m = 1;
-                           s += 2;
-                         }
-                       else if (strncasecmp (s, "mb", 2) == 0)
-                         {
-                           a = 1;
-                           m = 1;
-                           s += 2;
-                         }
-                       else if (strict)
-                         /* This is a match failure.  */
-                         s--;
-                       else
-                         {
-                           as_bad (_("Invalid Short Load/Store Completer."));
-                           s += 2;
-                         }
-                     }
-                   /* If we did not get a ma/mb completer, then we do not
-                      consider this a positive match for 'ce'.  */
-                   else if (*args == 'e')
-                     break;
+struct option md_longopts[] =
+{
+#ifdef WARN_COMMENTS
+  {"warn-comment", no_argument, NULL, 'c'},
+#endif
+  {NULL, no_argument, NULL, 0}
+};
+size_t md_longopts_size = sizeof (md_longopts);
 
 
-                  /* 'J', 'm', 'M' and 'q' are the same, except for where they
-                      encode the before/after field.  */
-                  if (*args == 'm' || *args == 'M')
-                     {
-                       opcode |= m << 5;
-                       INSERT_FIELD_AND_CONTINUE (opcode, a, 13);
-                     }
-                   else if (*args == 'q')
-                     {
-                       opcode |= m << 3;
-                       INSERT_FIELD_AND_CONTINUE (opcode, a, 2);
-                     }
-                   else if (*args == 'J')
-                     {
-                       /* M bit is explicit in the major opcode.  */
-                       INSERT_FIELD_AND_CONTINUE (opcode, a, 2);
-                     }
-                   else if (*args == 'e')
-                     {
-                       /* Stash the ma/mb flag temporarily in the
-                          instruction.  We will use (and remove it)
-                          later when handling 'J', 'K', '<' & '>'.  */
-                       opcode |= a;
-                       continue;
-                     }
-                 }
+int
+md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
+{
+  switch (c)
+    {
+    default:
+      return 0;
 
 
-               /* Handle a stbys completer.  */
-               case 'A':
-               case 's':
-                 {
-                   int a = 0;
-                   int m = 0;
-                   int i = 0;
-                   while (*s == ',' && i < 2)
-                     {
-                       s++;
-                       if (strncasecmp (s, "m", 1) == 0)
-                         m = 1;
-                       else if ((strncasecmp (s, "b ", 2) == 0)
-                                || (strncasecmp (s, "b,", 2) == 0))
-                         a = 0;
-                       else if (strncasecmp (s, "e", 1) == 0)
-                         a = 1;
-                       /* In strict mode, this is a match failure.  */
-                       else if (strict)
-                         {
-                           s--;
-                           break;
-                         }
-                       else
-                         as_bad (_("Invalid Store Bytes Short Completer"));
-                       s++;
-                       i++;
-                     }
-                   if (i > 2)
-                     as_bad (_("Invalid Store Bytes Short Completer"));
-                   opcode |= m << 5;
-                   INSERT_FIELD_AND_CONTINUE (opcode, a, 13);
-                 }
+#ifdef OBJ_ELF
+    case 'V':
+      print_version_id ();
+      break;
+#endif
+#ifdef WARN_COMMENTS
+    case 'c':
+      warn_comment = 1;
+      break;
+#endif
+    }
 
 
-               /* Handle load cache hint completer.  */
-               case 'c':
-                 cmpltr = 0;
-                 if (!strncmp (s, ",sl", 3))
-                   {
-                     s += 3;
-                     cmpltr = 2;
-                   }
-                 INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 10);
+  return 1;
+}
 
 
-               /* Handle store cache hint completer.  */
-               case 'C':
-                 cmpltr = 0;
-                 if (!strncmp (s, ",sl", 3))
-                   {
-                     s += 3;
-                     cmpltr = 2;
-                   }
-                 else if (!strncmp (s, ",bc", 3))
-                   {
-                     s += 3;
-                     cmpltr = 1;
-                   }
-                 INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 10);
+void
+md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
+{
+#ifdef OBJ_ELF
+  fprintf (stream, _("\
+  -Q                      ignored\n"));
+#endif
+#ifdef WARN_COMMENTS
+  fprintf (stream, _("\
+  -c                      print a warning if a comment is found\n"));
+#endif
+}
+\f
+/* We have no need to default values of symbols.  */
 
 
-               /* Handle load and clear cache hint completer.  */
-               case 'd':
-                 cmpltr = 0;
-                 if (!strncmp (s, ",co", 3))
-                   {
-                     s += 3;
-                     cmpltr = 1;
-                   }
-                 INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 10);
+symbolS *
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
+{
+  return NULL;
+}
 
 
-               /* Handle load ordering completer.  */
-               case 'o':
-                 if (strncmp (s, ",o", 2) != 0)
-                   break;
-                 s += 2;
-                 continue;
+#if defined (OBJ_SOM) || defined (ELF_ARG_RELOC)
+#define nonzero_dibits(x) \
+  ((x) | (((x) & 0x55555555) << 1) | (((x) & 0xAAAAAAAA) >> 1))
+#define arg_reloc_stub_needed(CALLER, CALLEE) \
+  (((CALLER) ^ (CALLEE)) & nonzero_dibits (CALLER) & nonzero_dibits (CALLEE))
+#else
+#define arg_reloc_stub_needed(CALLER, CALLEE) 0
+#endif
 
 
-               /* Handle a branch gate completer.  */
-               case 'g':
-                 if (strncasecmp (s, ",gate", 5) != 0)
-                   break;
-                 s += 5;
-                 continue;
+/* Apply a fixup to an instruction.  */
 
 
-               /* Handle a branch link and push completer.  */
-               case 'p':
-                 if (strncasecmp (s, ",l,push", 7) != 0)
-                   break;
-                 s += 7;
-                 continue;
+void
+md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
+{
+  char *fixpos;
+  struct hppa_fix_struct *hppa_fixP;
+  offsetT new_val;
+  int insn, val, fmt;
 
 
-               /* Handle a branch link completer.  */
-               case 'l':
-                 if (strncasecmp (s, ",l", 2) != 0)
-                   break;
-                 s += 2;
-                 continue;
+  /* SOM uses R_HPPA_ENTRY and R_HPPA_EXIT relocations which can
+     never be "applied" (they are just markers).  Likewise for
+     R_HPPA_BEGIN_BRTAB and R_HPPA_END_BRTAB.  */
+#ifdef OBJ_SOM
+  if (fixP->fx_r_type == R_HPPA_ENTRY
+      || fixP->fx_r_type == R_HPPA_EXIT
+      || fixP->fx_r_type == R_HPPA_BEGIN_BRTAB
+      || fixP->fx_r_type == R_HPPA_END_BRTAB
+      || fixP->fx_r_type == R_HPPA_BEGIN_TRY)
+    return;
 
 
-               /* Handle a branch pop completer.  */
-               case 'P':
-                 if (strncasecmp (s, ",pop", 4) != 0)
-                   break;
-                 s += 4;
-                 continue;
+  /* Disgusting.  We must set fx_offset ourselves -- R_HPPA_END_TRY
+     fixups are considered not adjustable, which in turn causes
+     adjust_reloc_syms to not set fx_offset.  Ugh.  */
+  if (fixP->fx_r_type == R_HPPA_END_TRY)
+    {
+      fixP->fx_offset = * valP;
+      return;
+    }
+#endif
+#ifdef OBJ_ELF
+  if (fixP->fx_r_type == (int) R_PARISC_GNU_VTENTRY
+      || fixP->fx_r_type == (int) R_PARISC_GNU_VTINHERIT)
+    return;
+#endif
 
 
-               /* Handle a local processor completer.  */
-               case 'L':
-                 if (strncasecmp (s, ",l", 2) != 0)
-                   break;
-                 s += 2;
-                 continue;
+  if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
+    fixP->fx_done = 1;
 
 
-               /* Handle a PROBE read/write completer.  */
-               case 'w':
-                 flag = 0;
-                 if (!strncasecmp (s, ",w", 2))
-                   {
-                     flag = 1;
-                     s += 2;
-                   }
-                 else if (!strncasecmp (s, ",r", 2))
-                   {
-                     flag = 0;
-                     s += 2;
-                   }
-
-                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
+  /* There should be a HPPA specific fixup associated with the GAS fixup.  */
+  hppa_fixP = (struct hppa_fix_struct *) fixP->tc_fix_data;
+  if (hppa_fixP == NULL)
+    {
+      as_bad_where (fixP->fx_file, fixP->fx_line,
+                   _("no hppa_fixup entry for fixup type 0x%x"),
+                   fixP->fx_r_type);
+      return;
+    }
 
 
-               /* Handle MFCTL wide completer.  */
-               case 'W':
-                 if (strncasecmp (s, ",w", 2) != 0)
-                   break;
-                 s += 2;
-                 continue;
+  fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
 
 
-               /* Handle an RFI restore completer.  */
-               case 'r':
-                 flag = 0;
-                 if (!strncasecmp (s, ",r", 2))
-                   {
-                     flag = 5;
-                     s += 2;
-                   }
+  if (fixP->fx_size != 4 || hppa_fixP->fx_r_format == 32)
+    {
+      /* Handle constant output. */
+      number_to_chars_bigendian (fixpos, *valP, fixP->fx_size);
+      return;
+    }
 
 
-                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 5);
+  insn = bfd_get_32 (stdoutput, fixpos);
+  fmt = bfd_hppa_insn2fmt (stdoutput, insn);
 
 
-               /* Handle a system control completer.  */
-               case 'Z':
-                 if (*s == ',' && (*(s + 1) == 'm' || *(s + 1) == 'M'))
-                   {
-                     flag = 1;
-                     s += 2;
-                   }
-                 else
-                   flag = 0;
+  /* If there is a symbol associated with this fixup, then it's something
+     which will need a SOM relocation (except for some PC-relative relocs).
+     In such cases we should treat the "val" or "addend" as zero since it
+     will be added in as needed from fx_offset in tc_gen_reloc.  */
+  if ((fixP->fx_addsy != NULL
+       || fixP->fx_r_type == (int) R_HPPA_NONE)
+#ifdef OBJ_SOM
+      && fmt != 32
+#endif
+      )
+    new_val = ((fmt == 12 || fmt == 17 || fmt == 22) ? 8 : 0);
+#ifdef OBJ_SOM
+  /* These field selectors imply that we do not want an addend.  */
+  else if (hppa_fixP->fx_r_field == e_psel
+          || hppa_fixP->fx_r_field == e_rpsel
+          || hppa_fixP->fx_r_field == e_lpsel
+          || hppa_fixP->fx_r_field == e_tsel
+          || hppa_fixP->fx_r_field == e_rtsel
+          || hppa_fixP->fx_r_field == e_ltsel)
+    new_val = ((fmt == 12 || fmt == 17 || fmt == 22) ? 8 : 0);
+#endif
+  else
+    new_val = hppa_field_adjust (* valP, 0, hppa_fixP->fx_r_field);
 
 
-                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 5);
+  /* Handle pc-relative exceptions from above.  */
+  if ((fmt == 12 || fmt == 17 || fmt == 22)
+      && fixP->fx_addsy
+      && fixP->fx_pcrel
+      && !arg_reloc_stub_needed (symbol_arg_reloc_info (fixP->fx_addsy),
+                                hppa_fixP->fx_arg_reloc)
+#ifdef OBJ_ELF
+      && (* valP - 8 + 8192 < 16384
+         || (fmt == 17 && * valP - 8 + 262144 < 524288)
+         || (fmt == 22 && * valP - 8 + 8388608 < 16777216))
+#endif
+#ifdef OBJ_SOM
+      && (* valP - 8 + 262144 < 524288
+         || (fmt == 22 && * valP - 8 + 8388608 < 16777216))
+#endif
+      && !S_IS_EXTERNAL (fixP->fx_addsy)
+      && !S_IS_WEAK (fixP->fx_addsy)
+      && S_GET_SEGMENT (fixP->fx_addsy) == hppa_fixP->segment
+      && !(fixP->fx_subsy
+          && S_GET_SEGMENT (fixP->fx_subsy) != hppa_fixP->segment))
+    {
+      new_val = hppa_field_adjust (* valP, 0, hppa_fixP->fx_r_field);
+    }
 
 
-               /* Handle intermediate/final completer for DCOR.  */
-               case 'i':
-                 flag = 0;
-                 if (!strncasecmp (s, ",i", 2))
-                   {
-                     flag = 1;
-                     s += 2;
-                   }
+  switch (fmt)
+    {
+    case 10:
+      CHECK_FIELD_WHERE (new_val, 8191, -8192,
+                        fixP->fx_file, fixP->fx_line);
+      val = new_val;
 
 
-                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
+      insn = (insn & ~ 0x3ff1) | (((val & 0x1ff8) << 1)
+                                 | ((val & 0x2000) >> 13));
+      break;
+    case -11:
+      CHECK_FIELD_WHERE (new_val, 8191, -8192,
+                        fixP->fx_file, fixP->fx_line);
+      val = new_val;
 
 
-               /* Handle zero/sign extension completer.  */
-               case 'z':
-                 flag = 1;
-                 if (!strncasecmp (s, ",z", 2))
-                   {
-                     flag = 0;
-                     s += 2;
-                   }
+      insn = (insn & ~ 0x3ff9) | (((val & 0x1ffc) << 1)
+                                 | ((val & 0x2000) >> 13));
+      break;
+      /* Handle all opcodes with the 'j' operand type.  */
+    case 14:
+      CHECK_FIELD_WHERE (new_val, 8191, -8192,
+                        fixP->fx_file, fixP->fx_line);
+      val = new_val;
 
 
-                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 10);
+      insn = ((insn & ~ 0x3fff) | low_sign_unext (val, 14));
+      break;
 
 
-               /* Handle add completer.  */
-               case 'a':
-                 flag = 1;
-                 if (!strncasecmp (s, ",l", 2))
-                   {
-                     flag = 2;
-                     s += 2;
-                   }
-                 else if (!strncasecmp (s, ",tsv", 4))
-                   {
-                     flag = 3;
-                     s += 4;
-                   }
+      /* Handle all opcodes with the 'k' operand type.  */
+    case 21:
+      CHECK_FIELD_WHERE (new_val, 1048575, -1048576,
+                        fixP->fx_file, fixP->fx_line);
+      val = new_val;
 
 
-                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 10);
+      insn = (insn & ~ 0x1fffff) | re_assemble_21 (val);
+      break;
 
 
-               /* Handle 64 bit carry for ADD.  */
-               case 'Y':
-                 flag = 0;
-                 if (!strncasecmp (s, ",dc,tsv", 7) ||
-                     !strncasecmp (s, ",tsv,dc", 7))
-                   {
-                     flag = 1;
-                     s += 7;
-                   }
-                 else if (!strncasecmp (s, ",dc", 3))
-                   {
-                     flag = 0;
-                     s += 3;
-                   }
-                 else
-                   break;
+      /* Handle all the opcodes with the 'i' operand type.  */
+    case 11:
+      CHECK_FIELD_WHERE (new_val, 1023, -1024,
+                        fixP->fx_file, fixP->fx_line);
+      val = new_val;
 
 
-                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+      insn = (insn & ~ 0x7ff) | low_sign_unext (val, 11);
+      break;
 
 
-               /* Handle 32 bit carry for ADD.  */
-               case 'y':
-                 flag = 0;
-                 if (!strncasecmp (s, ",c,tsv", 6) ||
-                     !strncasecmp (s, ",tsv,c", 6))
-                   {
-                     flag = 1;
-                     s += 6;
-                   }
-                 else if (!strncasecmp (s, ",c", 2))
-                   {
-                     flag = 0;
-                     s += 2;
-                   }
-                 else
-                   break;
+      /* Handle all the opcodes with the 'w' operand type.  */
+    case 12:
+      CHECK_FIELD_WHERE (new_val - 8, 8191, -8192,
+                        fixP->fx_file, fixP->fx_line);
+      val = new_val - 8;
 
 
-                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+      insn = (insn & ~ 0x1ffd) | re_assemble_12 (val >> 2);
+      break;
 
 
-               /* Handle trap on signed overflow.  */
-               case 'v':
-                 flag = 0;
-                 if (!strncasecmp (s, ",tsv", 4))
-                   {
-                     flag = 1;
-                     s += 4;
-                   }
+      /* Handle some of the opcodes with the 'W' operand type.  */
+    case 17:
+      {
+       offsetT distance = * valP;
 
 
-                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+       /* If this is an absolute branch (ie no link) with an out of
+          range target, then we want to complain.  */
+       if (fixP->fx_r_type == (int) R_HPPA_PCREL_CALL
+           && (insn & 0xffe00000) == 0xe8000000)
+         CHECK_FIELD_WHERE (distance - 8, 262143, -262144,
+                            fixP->fx_file, fixP->fx_line);
 
 
-               /* Handle trap on condition and overflow.  */
-               case 't':
-                 flag = 0;
-                 if (!strncasecmp (s, ",tc,tsv", 7) ||
-                     !strncasecmp (s, ",tsv,tc", 7))
-                   {
-                     flag = 1;
-                     s += 7;
-                   }
-                 else if (!strncasecmp (s, ",tc", 3))
-                   {
-                     flag = 0;
-                     s += 3;
-                   }
-                 else
-                   break;
+       CHECK_FIELD_WHERE (new_val - 8, 262143, -262144,
+                          fixP->fx_file, fixP->fx_line);
+       val = new_val - 8;
 
 
-                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+       insn = (insn & ~ 0x1f1ffd) | re_assemble_17 (val >> 2);
+       break;
+      }
 
 
-               /* Handle 64 bit borrow for SUB.  */
-               case 'B':
-                 flag = 0;
-                 if (!strncasecmp (s, ",db,tsv", 7) ||
-                     !strncasecmp (s, ",tsv,db", 7))
-                   {
-                     flag = 1;
-                     s += 7;
-                   }
-                 else if (!strncasecmp (s, ",db", 3))
-                   {
-                     flag = 0;
-                     s += 3;
-                   }
-                 else
-                   break;
+    case 22:
+      {
+       offsetT distance = * valP;
 
 
-                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+       /* If this is an absolute branch (ie no link) with an out of
+          range target, then we want to complain.  */
+       if (fixP->fx_r_type == (int) R_HPPA_PCREL_CALL
+           && (insn & 0xffe00000) == 0xe8000000)
+         CHECK_FIELD_WHERE (distance - 8, 8388607, -8388608,
+                            fixP->fx_file, fixP->fx_line);
 
 
-               /* Handle 32 bit borrow for SUB.  */
-               case 'b':
-                 flag = 0;
-                 if (!strncasecmp (s, ",b,tsv", 6) ||
-                     !strncasecmp (s, ",tsv,b", 6))
-                   {
-                     flag = 1;
-                     s += 6;
-                   }
-                 else if (!strncasecmp (s, ",b", 2))
-                   {
-                     flag = 0;
-                     s += 2;
-                   }
-                 else
-                   break;
+       CHECK_FIELD_WHERE (new_val - 8, 8388607, -8388608,
+                          fixP->fx_file, fixP->fx_line);
+       val = new_val - 8;
 
 
-                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+       insn = (insn & ~ 0x3ff1ffd) | re_assemble_22 (val >> 2);
+       break;
+      }
 
 
-               /* Handle trap condition completer for UADDCM.  */
-               case 'T':
-                 flag = 0;
-                 if (!strncasecmp (s, ",tc", 3))
-                   {
-                     flag = 1;
-                     s += 3;
-                   }
+    case -10:
+      val = new_val;
+      insn = (insn & ~ 0xfff1) | re_assemble_16 (val & -8);
+      break;
 
 
-                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
+    case -16:
+      val = new_val;
+      insn = (insn & ~ 0xfff9) | re_assemble_16 (val & -4);
+      break;
 
 
-               /* Handle signed/unsigned at 21.  */
-               case 'S':
-                 {
-                   int sign = 1;
-                   if (strncasecmp (s, ",s", 2) == 0)
-                     {
-                       sign = 1;
-                       s += 2;
-                     }
-                   else if (strncasecmp (s, ",u", 2) == 0)
-                     {
-                       sign = 0;
-                       s += 2;
-                     }
+    case 16:
+      val = new_val;
+      insn = (insn & ~ 0xffff) | re_assemble_16 (val);
+      break;
 
 
-                   INSERT_FIELD_AND_CONTINUE (opcode, sign, 10);
-                 }
+    case 32:
+      insn = new_val;
+      break;
 
 
-               /* Handle left/right combination at 17:18.  */
-               case 'h':
-                 if (*s++ == ',')
-                   {
-                     int lr = 0;
-                     if (*s == 'r')
-                       lr = 2;
-                     else if (*s == 'l')
-                       lr = 0;
-                     else
-                       as_bad (_("Invalid left/right combination completer"));
+    default:
+      as_bad_where (fixP->fx_file, fixP->fx_line,
+                   _("Unknown relocation encountered in md_apply_fix."));
+      return;
+    }
 
 
-                     s++;
-                     INSERT_FIELD_AND_CONTINUE (opcode, lr, 13);
-                   }
-                 else
-                   as_bad (_("Invalid left/right combination completer"));
-                 break;
+#ifdef OBJ_ELF
+  switch (fixP->fx_r_type)
+    {
+      case R_PARISC_TLS_GD21L:
+      case R_PARISC_TLS_GD14R:
+      case R_PARISC_TLS_LDM21L:
+      case R_PARISC_TLS_LDM14R:
+      case R_PARISC_TLS_LE21L:
+      case R_PARISC_TLS_LE14R:
+      case R_PARISC_TLS_IE21L:
+      case R_PARISC_TLS_IE14R:
+        if (fixP->fx_addsy)
+         S_SET_THREAD_LOCAL (fixP->fx_addsy);
+       break;
+      default:
+       break;
+    }
+#endif
 
 
-               /* Handle saturation at 24:25.  */
-               case 'H':
-                 {
-                   int sat = 3;
-                   if (strncasecmp (s, ",ss", 3) == 0)
-                     {
-                       sat = 1;
-                       s += 3;
-                     }
-                   else if (strncasecmp (s, ",us", 3) == 0)
-                     {
-                       sat = 0;
-                       s += 3;
-                     }
+  /* Insert the relocation.  */
+  bfd_put_32 (stdoutput, insn, fixpos);
+}
 
 
-                   INSERT_FIELD_AND_CONTINUE (opcode, sat, 6);
-                 }
+/* Exactly what point is a PC-relative offset relative TO?
+   On the PA, they're relative to the address of the offset.  */
 
 
-               /* Handle permutation completer.  */
-               case '*':
-                 if (*s++ == ',')
-                   {
-                     int permloc[4];
-                     int perm = 0;
-                     int i = 0;
-                     permloc[0] = 13;
-                     permloc[1] = 10;
-                     permloc[2] = 8;
-                     permloc[3] = 6;
-                     for (; i < 4; i++)
-                       {
-                         switch (*s++)
-                           {
-                           case '0':
-                             perm = 0;
-                             break;
-                           case '1':
-                             perm = 1;
-                             break;
-                           case '2':
-                             perm = 2;
-                             break;
-                           case '3':
-                             perm = 3;
-                             break;
-                           default:
-                             as_bad (_("Invalid permutation completer"));
-                           }
-                         opcode |= perm << permloc[i];
-                       }
-                     continue;
-                   }
-                 else
-                   as_bad (_("Invalid permutation completer"));
-                 break;
+long
+md_pcrel_from (fixS *fixP)
+{
+  return fixP->fx_where + fixP->fx_frag->fr_address;
+}
 
 
-               default:
-                 abort ();
-               }
-             break;
+/* Return nonzero if the input line pointer is at the end of
+   a statement.  */
 
 
-           /* Handle all conditions.  */
-           case '?':
-             {
-               args++;
-               switch (*args)
-                 {
-                 /* Handle FP compare conditions.  */
-                 case 'f':
-                   cond = pa_parse_fp_cmp_cond (&s);
-                   INSERT_FIELD_AND_CONTINUE (opcode, cond, 0);
+static int
+is_end_of_statement (void)
+{
+  return ((*input_line_pointer == '\n')
+         || (*input_line_pointer == ';')
+         || (*input_line_pointer == '!'));
+}
 
 
-                 /* Handle an add condition.  */
-                 case 'A':
-                 case 'a':
-                   cmpltr = 0;
-                   flag = 0;
-                   if (*s == ',')
-                     {
-                       s++;
+#define REG_NAME_CNT   (sizeof (pre_defined_registers) / sizeof (struct pd_reg))
 
 
-                       /* 64 bit conditions.  */
-                       if (*args == 'A')
-                         {
-                           if (*s == '*')
-                             s++;
-                           else
-                             break;
-                         }
-                       else if (*s == '*')
-                         break;
+/* Given NAME, find the register number associated with that name, return
+   the integer value associated with the given name or -1 on failure.  */
 
 
-                       name = s;
-                       while (*s != ',' && *s != ' ' && *s != '\t')
-                         s += 1;
-                       c = *s;
-                       *s = 0x00;
-                       if (strcmp (name, "=") == 0)
-                         cmpltr = 1;
-                       else if (strcmp (name, "<") == 0)
-                         cmpltr = 2;
-                       else if (strcmp (name, "<=") == 0)
-                         cmpltr = 3;
-                       else if (strcasecmp (name, "nuv") == 0)
-                         cmpltr = 4;
-                       else if (strcasecmp (name, "znv") == 0)
-                         cmpltr = 5;
-                       else if (strcasecmp (name, "sv") == 0)
-                         cmpltr = 6;
-                       else if (strcasecmp (name, "od") == 0)
-                         cmpltr = 7;
-                       else if (strcasecmp (name, "tr") == 0)
-                         {
-                           cmpltr = 0;
-                           flag = 1;
-                         }
-                       else if (strcmp (name, "<>") == 0)
-                         {
-                           cmpltr = 1;
-                           flag = 1;
-                         }
-                       else if (strcmp (name, ">=") == 0)
-                         {
-                           cmpltr = 2;
-                           flag = 1;
-                         }
-                       else if (strcmp (name, ">") == 0)
-                         {
-                           cmpltr = 3;
-                           flag = 1;
-                         }
-                       else if (strcasecmp (name, "uv") == 0)
-                         {
-                           cmpltr = 4;
-                           flag = 1;
-                         }
-                       else if (strcasecmp (name, "vnz") == 0)
-                         {
-                           cmpltr = 5;
-                           flag = 1;
-                         }
-                       else if (strcasecmp (name, "nsv") == 0)
-                         {
-                           cmpltr = 6;
-                           flag = 1;
-                         }
-                       else if (strcasecmp (name, "ev") == 0)
-                         {
-                           cmpltr = 7;
-                           flag = 1;
-                         }
-                       /* ",*" is a valid condition.  */
-                       else if (*args == 'a' || *name)
-                         as_bad (_("Invalid Add Condition: %s"), name);
-                       *s = c;
-                     }
-                   opcode |= cmpltr << 13;
-                   INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
+static int
+reg_name_search (char *name)
+{
+  int middle, low, high;
+  int cmp;
 
 
-                 /* Handle non-negated add and branch condition.  */
-                 case 'd':
-                   cmpltr = pa_parse_nonneg_add_cmpltr (&s);
-                   if (cmpltr < 0)
-                     {
-                       as_bad (_("Invalid Add and Branch Condition"));
-                       cmpltr = 0;
-                     }
-                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+  low = 0;
+  high = REG_NAME_CNT - 1;
 
 
-                 /* Handle 64 bit wide-mode add and branch condition.  */
-                 case 'W':
-                   cmpltr = pa_parse_addb_64_cmpltr (&s);
-                   if (cmpltr < 0)
-                     {
-                       as_bad (_("Invalid Add and Branch Condition"));
-                       cmpltr = 0;
-                     }
-                   else
-                     {
-                       /* Negated condition requires an opcode change.  */
-                       opcode |= (cmpltr & 8) << 24;
-                     }
-                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr & 7, 13);
+  do
+    {
+      middle = (low + high) / 2;
+      cmp = strcasecmp (name, pre_defined_registers[middle].name);
+      if (cmp < 0)
+       high = middle - 1;
+      else if (cmp > 0)
+       low = middle + 1;
+      else
+       return pre_defined_registers[middle].value;
+    }
+  while (low <= high);
 
 
-                 /* Handle a negated or non-negated add and branch
-                    condition.  */
-                 case '@':
-                   save_s = s;
-                   cmpltr = pa_parse_nonneg_add_cmpltr (&s);
-                   if (cmpltr < 0)
-                     {
-                       s = save_s;
-                       cmpltr = pa_parse_neg_add_cmpltr (&s);
-                       if (cmpltr < 0)
-                         {
-                           as_bad (_("Invalid Compare/Subtract Condition"));
-                           cmpltr = 0;
-                         }
-                       else
-                         {
-                           /* Negated condition requires an opcode change.  */
-                           opcode |= 1 << 27;
-                         }
-                     }
-                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+  return -1;
+}
 
 
-                 /* Handle branch on bit conditions.  */
-                 case 'B':
-                 case 'b':
-                   cmpltr = 0;
-                   if (*s == ',')
-                     {
-                       s++;
+/* Read a number from S.  The number might come in one of many forms,
+   the most common will be a hex or decimal constant, but it could be
+   a pre-defined register (Yuk!), or an absolute symbol.
 
 
-                       if (*args == 'B')
-                         {
-                           if (*s == '*')
-                             s++;
-                           else
-                             break;
-                         }
-                       else if (*s == '*')
-                         break;
+   Return 1 on success or 0 on failure.  If STRICT, then a missing
+   register prefix will cause a failure.  The number itself is
+   returned in `pa_number'.
 
 
-                       if (strncmp (s, "<", 1) == 0)
-                         {
-                           cmpltr = 0;
-                           s++;
-                         }
-                       else if (strncmp (s, ">=", 2) == 0)
-                         {
-                           cmpltr = 1;
-                           s += 2;
-                         }
-                       else
-                         as_bad (_("Invalid Bit Branch Condition: %c"), *s);
-                     }
-                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 15);
+   IS_FLOAT indicates that a PA-89 FP register number should be
+   parsed;  A `l' or `r' suffix is checked for if but 2 of IS_FLOAT is
+   not set.
 
 
-                 /* Handle a compare/subtract condition.  */
-                 case 'S':
-                 case 's':
-                   cmpltr = 0;
-                   flag = 0;
-                   if (*s == ',')
-                     {
-                       s++;
+   pa_parse_number can not handle negative constants and will fail
+   horribly if it is passed such a constant.  */
 
 
-                       /* 64 bit conditions.  */
-                       if (*args == 'S')
-                         {
-                           if (*s == '*')
-                             s++;
-                           else
-                             break;
-                         }
-                       else if (*s == '*')
-                         break;
+static int
+pa_parse_number (char **s, int is_float)
+{
+  int num;
+  char *name;
+  char c;
+  symbolS *sym;
+  int status;
+  char *p = *s;
+  bfd_boolean have_prefix;
 
 
-                       name = s;
-                       while (*s != ',' && *s != ' ' && *s != '\t')
-                         s += 1;
-                       c = *s;
-                       *s = 0x00;
-                       if (strcmp (name, "=") == 0)
-                         cmpltr = 1;
-                       else if (strcmp (name, "<") == 0)
-                         cmpltr = 2;
-                       else if (strcmp (name, "<=") == 0)
-                         cmpltr = 3;
-                       else if (strcasecmp (name, "<<") == 0)
-                         cmpltr = 4;
-                       else if (strcasecmp (name, "<<=") == 0)
-                         cmpltr = 5;
-                       else if (strcasecmp (name, "sv") == 0)
-                         cmpltr = 6;
-                       else if (strcasecmp (name, "od") == 0)
-                         cmpltr = 7;
-                       else if (strcasecmp (name, "tr") == 0)
-                         {
-                           cmpltr = 0;
-                           flag = 1;
-                         }
-                       else if (strcmp (name, "<>") == 0)
-                         {
-                           cmpltr = 1;
-                           flag = 1;
-                         }
-                       else if (strcmp (name, ">=") == 0)
-                         {
-                           cmpltr = 2;
-                           flag = 1;
-                         }
-                       else if (strcmp (name, ">") == 0)
-                         {
-                           cmpltr = 3;
-                           flag = 1;
-                         }
-                       else if (strcasecmp (name, ">>=") == 0)
-                         {
-                           cmpltr = 4;
-                           flag = 1;
-                         }
-                       else if (strcasecmp (name, ">>") == 0)
-                         {
-                           cmpltr = 5;
-                           flag = 1;
-                         }
-                       else if (strcasecmp (name, "nsv") == 0)
-                         {
-                           cmpltr = 6;
-                           flag = 1;
-                         }
-                       else if (strcasecmp (name, "ev") == 0)
-                         {
-                           cmpltr = 7;
-                           flag = 1;
-                         }
-                       /* ",*" is a valid condition.  */
-                       else if (*args != 'S' || *name)
-                         as_bad (_("Invalid Compare/Subtract Condition: %s"),
-                                 name);
-                       *s = c;
-                     }
-                   opcode |= cmpltr << 13;
-                   INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
+  /* Skip whitespace before the number.  */
+  while (*p == ' ' || *p == '\t')
+    p = p + 1;
 
 
-                 /* Handle a non-negated compare condition.  */
-                 case 't':
-                   cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s);
-                   if (cmpltr < 0)
-                     {
-                       as_bad (_("Invalid Compare/Subtract Condition"));
-                       cmpltr = 0;
-                     }
-                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+  pa_number = -1;
+  have_prefix = 0;
+  num = 0;
+  if (!strict && ISDIGIT (*p))
+    {
+      /* Looks like a number.  */
 
 
-                 /* Handle a 32 bit compare and branch condition.  */
-                 case 'n':
-                   save_s = s;
-                   cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s);
-                   if (cmpltr < 0)
-                     {
-                       s = save_s;
-                       cmpltr = pa_parse_neg_cmpsub_cmpltr (&s);
-                       if (cmpltr < 0)
-                         {
-                           as_bad (_("Invalid Compare and Branch Condition"));
-                           cmpltr = 0;
-                         }
-                       else
-                         {
-                           /* Negated condition requires an opcode change.  */
-                           opcode |= 1 << 27;
-                         }
-                     }
+      if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X'))
+       {
+         /* The number is specified in hex.  */
+         p += 2;
+         while (ISDIGIT (*p) || ((*p >= 'a') && (*p <= 'f'))
+                || ((*p >= 'A') && (*p <= 'F')))
+           {
+             if (ISDIGIT (*p))
+               num = num * 16 + *p - '0';
+             else if (*p >= 'a' && *p <= 'f')
+               num = num * 16 + *p - 'a' + 10;
+             else
+               num = num * 16 + *p - 'A' + 10;
+             ++p;
+           }
+       }
+      else
+       {
+         /* The number is specified in decimal.  */
+         while (ISDIGIT (*p))
+           {
+             num = num * 10 + *p - '0';
+             ++p;
+           }
+       }
 
 
-                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+      pa_number = num;
 
 
-                 /* Handle a 64 bit compare and branch condition.  */
-                 case 'N':
-                   cmpltr = pa_parse_cmpb_64_cmpltr (&s);
-                   if (cmpltr >= 0)
-                     {
-                       /* Negated condition requires an opcode change.  */
-                       opcode |= (cmpltr & 8) << 26;
-                     }
-                   else
-                     /* Not a 64 bit cond.  Give 32 bit a chance.  */
-                     break;
+      /* Check for a `l' or `r' suffix.  */
+      if (is_float)
+       {
+         pa_number += FP_REG_BASE;
+         if (! (is_float & 2))
+           {
+             if (IS_R_SELECT (p))
+               {
+                 pa_number += FP_REG_RSEL;
+                 ++p;
+               }
+             else if (IS_L_SELECT (p))
+               {
+                 ++p;
+               }
+           }
+       }
+    }
+  else if (*p == '%')
+    {
+      /* The number might be a predefined register.  */
+      have_prefix = 1;
+      name = p;
+      p++;
+      c = *p;
+      /* Tege hack: Special case for general registers as the general
+         code makes a binary search with case translation, and is VERY
+         slow.  */
+      if (c == 'r')
+       {
+         p++;
+         if (*p == 'e' && *(p + 1) == 't'
+             && (*(p + 2) == '0' || *(p + 2) == '1'))
+           {
+             p += 2;
+             num = *p - '0' + 28;
+             p++;
+           }
+         else if (*p == 'p')
+           {
+             num = 2;
+             p++;
+           }
+         else if (!ISDIGIT (*p))
+           {
+             if (print_errors)
+               as_bad (_("Undefined register: '%s'."), name);
+             num = -1;
+           }
+         else
+           {
+             do
+               num = num * 10 + *p++ - '0';
+             while (ISDIGIT (*p));
+           }
+       }
+      else
+       {
+         /* Do a normal register search.  */
+         while (is_part_of_name (c))
+           {
+             p = p + 1;
+             c = *p;
+           }
+         *p = 0;
+         status = reg_name_search (name);
+         if (status >= 0)
+           num = status;
+         else
+           {
+             if (print_errors)
+               as_bad (_("Undefined register: '%s'."), name);
+             num = -1;
+           }
+         *p = c;
+       }
 
 
-                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr & 7, 13);
+      pa_number = num;
+    }
+  else
+    {
+      /* And finally, it could be a symbol in the absolute section which
+         is effectively a constant, or a register alias symbol.  */
+      name = p;
+      c = *p;
+      while (is_part_of_name (c))
+       {
+         p = p + 1;
+         c = *p;
+       }
+      *p = 0;
+      if ((sym = symbol_find (name)) != NULL)
+       {
+         if (S_GET_SEGMENT (sym) == reg_section)
+           {
+             num = S_GET_VALUE (sym);
+             /* Well, we don't really have one, but we do have a
+                register, so...  */
+             have_prefix = TRUE;
+           }
+         else if (S_GET_SEGMENT (sym) == &bfd_abs_section)
+           num = S_GET_VALUE (sym);
+         else if (!strict)
+           {
+             if (print_errors)
+               as_bad (_("Non-absolute symbol: '%s'."), name);
+             num = -1;
+           }
+       }
+      else if (!strict)
+       {
+         /* There is where we'd come for an undefined symbol
+            or for an empty string.  For an empty string we
+            will return zero.  That's a concession made for
+            compatibility with the braindamaged HP assemblers.  */
+         if (*name == 0)
+           num = 0;
+         else
+           {
+             if (print_errors)
+               as_bad (_("Undefined absolute constant: '%s'."), name);
+             num = -1;
+           }
+       }
+      *p = c;
 
 
-                 /* Handle a 64 bit cmpib condition.  */
-                 case 'Q':
-                   cmpltr = pa_parse_cmpib_64_cmpltr (&s);
-                   if (cmpltr < 0)
-                     /* Not a 64 bit cond.  Give 32 bit a chance.  */
-                     break;
+      pa_number = num;
+    }
 
 
-                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+  if (!strict || have_prefix)
+    {
+      *s = p;
+      return 1;
+    }
+  return 0;
+}
 
 
-                   /* Handle a logical instruction condition.  */
-                 case 'L':
-                 case 'l':
-                   cmpltr = 0;
-                   flag = 0;
-                   if (*s == ',')
-                     {
-                       s++;
+/* Return nonzero if the given INSN and L/R information will require
+   a new PA-1.1 opcode.  */
 
 
-                       /* 64 bit conditions.  */
-                       if (*args == 'L')
-                         {
-                           if (*s == '*')
-                             s++;
-                           else
-                             break;
-                         }
-                       else if (*s == '*')
-                         break;
+static int
+need_pa11_opcode (void)
+{
+  if ((pa_number & FP_REG_RSEL) != 0
+      && !(the_insn.fpof1 == DBL && the_insn.fpof2 == DBL))
+    {
+      /* If this instruction is specific to a particular architecture,
+        then set a new architecture.  */
+      if (bfd_get_mach (stdoutput) < pa11)
+       {
+         if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, pa11))
+           as_warn (_("could not update architecture and machine"));
+       }
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
 
 
-                       name = s;
-                       while (*s != ',' && *s != ' ' && *s != '\t')
-                         s += 1;
-                       c = *s;
-                       *s = 0x00;
+/* Parse a condition for a fcmp instruction.  Return the numerical
+   code associated with the condition.  */
 
 
-                       if (strcmp (name, "=") == 0)
-                         cmpltr = 1;
-                       else if (strcmp (name, "<") == 0)
-                         cmpltr = 2;
-                       else if (strcmp (name, "<=") == 0)
-                         cmpltr = 3;
-                       else if (strcasecmp (name, "od") == 0)
-                         cmpltr = 7;
-                       else if (strcasecmp (name, "tr") == 0)
-                         {
-                           cmpltr = 0;
-                           flag = 1;
-                         }
-                       else if (strcmp (name, "<>") == 0)
-                         {
-                           cmpltr = 1;
-                           flag = 1;
-                         }
-                       else if (strcmp (name, ">=") == 0)
-                         {
-                           cmpltr = 2;
-                           flag = 1;
-                         }
-                       else if (strcmp (name, ">") == 0)
-                         {
-                           cmpltr = 3;
-                           flag = 1;
-                         }
-                       else if (strcasecmp (name, "ev") == 0)
-                         {
-                           cmpltr = 7;
-                           flag = 1;
-                         }
-                       /* ",*" is a valid condition.  */
-                       else if (*args != 'L' || *name)
-                         as_bad (_("Invalid Logical Instruction Condition."));
-                       *s = c;
-                     }
-                   opcode |= cmpltr << 13;
-                   INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
-
-                 /* Handle a shift/extract/deposit condition.  */
-                 case 'X':
-                 case 'x':
-                 case 'y':
-                   cmpltr = 0;
-                   if (*s == ',')
-                     {
-                       save_s = s++;
-
-                       /* 64 bit conditions.  */
-                       if (*args == 'X')
-                         {
-                           if (*s == '*')
-                             s++;
-                           else
-                             break;
-                         }
-                       else if (*s == '*')
-                         break;
-
-                       name = s;
-                       while (*s != ',' && *s != ' ' && *s != '\t')
-                         s += 1;
-                       c = *s;
-                       *s = 0x00;
-                       if (strcmp (name, "=") == 0)
-                         cmpltr = 1;
-                       else if (strcmp (name, "<") == 0)
-                         cmpltr = 2;
-                       else if (strcasecmp (name, "od") == 0)
-                         cmpltr = 3;
-                       else if (strcasecmp (name, "tr") == 0)
-                         cmpltr = 4;
-                       else if (strcmp (name, "<>") == 0)
-                         cmpltr = 5;
-                       else if (strcmp (name, ">=") == 0)
-                         cmpltr = 6;
-                       else if (strcasecmp (name, "ev") == 0)
-                         cmpltr = 7;
-                       /* Handle movb,n.  Put things back the way they were.
-                          This includes moving s back to where it started.  */
-                       else if (strcasecmp (name, "n") == 0 && *args == 'y')
-                         {
-                           *s = c;
-                           s = save_s;
-                           continue;
-                         }
-                       /* ",*" is a valid condition.  */
-                       else if (*args != 'X' || *name)
-                         as_bad (_("Invalid Shift/Extract/Deposit Condition."));
-                       *s = c;
-                     }
-                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
-
-                 /* Handle a unit instruction condition.  */
-                 case 'U':
-                 case 'u':
-                   cmpltr = 0;
-                   flag = 0;
-                   if (*s == ',')
-                     {
-                       s++;
+static int
+pa_parse_fp_cmp_cond (char **s)
+{
+  int cond, i;
 
 
-                       /* 64 bit conditions.  */
-                       if (*args == 'U')
-                         {
-                           if (*s == '*')
-                             s++;
-                           else
-                             break;
-                         }
-                       else if (*s == '*')
-                         break;
+  cond = 0;
 
 
-                       if (strncasecmp (s, "sbz", 3) == 0)
-                         {
-                           cmpltr = 2;
-                           s += 3;
-                         }
-                       else if (strncasecmp (s, "shz", 3) == 0)
-                         {
-                           cmpltr = 3;
-                           s += 3;
-                         }
-                       else if (strncasecmp (s, "sdc", 3) == 0)
-                         {
-                           cmpltr = 4;
-                           s += 3;
-                         }
-                       else if (strncasecmp (s, "sbc", 3) == 0)
-                         {
-                           cmpltr = 6;
-                           s += 3;
-                         }
-                       else if (strncasecmp (s, "shc", 3) == 0)
-                         {
-                           cmpltr = 7;
-                           s += 3;
-                         }
-                       else if (strncasecmp (s, "tr", 2) == 0)
-                         {
-                           cmpltr = 0;
-                           flag = 1;
-                           s += 2;
-                         }
-                       else if (strncasecmp (s, "nbz", 3) == 0)
-                         {
-                           cmpltr = 2;
-                           flag = 1;
-                           s += 3;
-                         }
-                       else if (strncasecmp (s, "nhz", 3) == 0)
-                         {
-                           cmpltr = 3;
-                           flag = 1;
-                           s += 3;
-                         }
-                       else if (strncasecmp (s, "ndc", 3) == 0)
-                         {
-                           cmpltr = 4;
-                           flag = 1;
-                           s += 3;
-                         }
-                       else if (strncasecmp (s, "nbc", 3) == 0)
-                         {
-                           cmpltr = 6;
-                           flag = 1;
-                           s += 3;
-                         }
-                       else if (strncasecmp (s, "nhc", 3) == 0)
-                         {
-                           cmpltr = 7;
-                           flag = 1;
-                           s += 3;
-                         }
-                       else if (strncasecmp (s, "swz", 3) == 0)
-                         {
-                           cmpltr = 1;
-                           flag = 0;
-                           s += 3;
-                         }
-                       else if (strncasecmp (s, "swc", 3) == 0)
-                         {
-                           cmpltr = 5;
-                           flag = 0;
-                           s += 3;
-                         }
-                       else if (strncasecmp (s, "nwz", 3) == 0)
-                         {
-                           cmpltr = 1;
-                           flag = 1;
-                           s += 3;
-                         }
-                       else if (strncasecmp (s, "nwc", 3) == 0)
-                         {
-                           cmpltr = 5;
-                           flag = 1;
-                           s += 3;
-                         }
-                       /* ",*" is a valid condition.  */
-                       else if (*args != 'U' || (*s != ' ' && *s != '\t'))
-                         as_bad (_("Invalid Unit Instruction Condition."));
-                     }
-                   opcode |= cmpltr << 13;
-                   INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
+  for (i = 0; i < 32; i++)
+    {
+      if (strncasecmp (*s, fp_cond_map[i].string,
+                      strlen (fp_cond_map[i].string)) == 0)
+       {
+         cond = fp_cond_map[i].cond;
+         *s += strlen (fp_cond_map[i].string);
+         /* If not a complete match, back up the input string and
+            report an error.  */
+         if (**s != ' ' && **s != '\t')
+           {
+             *s -= strlen (fp_cond_map[i].string);
+             break;
+           }
+         while (**s == ' ' || **s == '\t')
+           *s = *s + 1;
+         return cond;
+       }
+    }
 
 
-                 default:
-                   abort ();
-                 }
-               break;
-             }
+  as_bad (_("Invalid FP Compare Condition: %s"), *s);
 
 
-           /* Handle a nullification completer for branch instructions.  */
-           case 'n':
-             nullif = pa_parse_nullif (&s);
-             INSERT_FIELD_AND_CONTINUE (opcode, nullif, 1);
+  /* Advance over the bogus completer.  */
+  while (**s != ',' && **s != ' ' && **s != '\t')
+    *s += 1;
 
 
-           /* Handle a nullification completer for copr and spop insns.  */
-           case 'N':
-             nullif = pa_parse_nullif (&s);
-             INSERT_FIELD_AND_CONTINUE (opcode, nullif, 5);
+  return 0;
+}
 
 
-           /* Handle ,%r2 completer for new syntax branches.  */
-           case 'L':
-             if (*s == ',' && strncasecmp (s + 1, "%r2", 3) == 0)
-               s += 4;
-             else if (*s == ',' && strncasecmp (s + 1, "%rp", 3) == 0)
-               s += 4;
-             else
-               break;
-             continue;
+/* Parse a graphics test complete for ftest.  */
 
 
-           /* Handle 3 bit entry into the fp compare array.   Valid values
-              are 0..6 inclusive.  */
-           case 'h':
-             get_expression (s);
-             s = expr_end;
-             if (the_insn.exp.X_op == O_constant)
-               {
-                 num = evaluate_absolute (&the_insn);
-                 CHECK_FIELD (num, 6, 0, 0);
-                 num++;
-                 INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
-               }
-             else
-               break;
+static int
+pa_parse_ftest_gfx_completer (char **s)
+{
+  int value;
 
 
-           /* Handle 3 bit entry into the fp compare array.   Valid values
-              are 0..6 inclusive.  */
-           case 'm':
-             get_expression (s);
-             if (the_insn.exp.X_op == O_constant)
-               {
-                 s = expr_end;
-                 num = evaluate_absolute (&the_insn);
-                 CHECK_FIELD (num, 6, 0, 0);
-                 num = (num + 1) ^ 1;
-                 INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
-               }
-             else
-               break;
+  value = 0;
+  if (strncasecmp (*s, "acc8", 4) == 0)
+    {
+      value = 5;
+      *s += 4;
+    }
+  else if (strncasecmp (*s, "acc6", 4) == 0)
+    {
+      value = 9;
+      *s += 4;
+    }
+  else if (strncasecmp (*s, "acc4", 4) == 0)
+    {
+      value = 13;
+      *s += 4;
+    }
+  else if (strncasecmp (*s, "acc2", 4) == 0)
+    {
+      value = 17;
+      *s += 4;
+    }
+  else if (strncasecmp (*s, "acc", 3) == 0)
+    {
+      value = 1;
+      *s += 3;
+    }
+  else if (strncasecmp (*s, "rej8", 4) == 0)
+    {
+      value = 6;
+      *s += 4;
+    }
+  else if (strncasecmp (*s, "rej", 3) == 0)
+    {
+      value = 2;
+      *s += 3;
+    }
+  else
+    {
+      value = 0;
+      as_bad (_("Invalid FTEST completer: %s"), *s);
+    }
 
 
-           /* Handle graphics test completers for ftest */
-           case '=':
-             {
-               num = pa_parse_ftest_gfx_completer (&s);
-               INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
-             }
+  return value;
+}
 
 
-           /* Handle a 11 bit immediate at 31.  */
-           case 'i':
-             the_insn.field_selector = pa_chk_field_selector (&s);
-             get_expression (s);
-             s = expr_end;
-             if (the_insn.exp.X_op == O_constant)
-               {
-                 num = evaluate_absolute (&the_insn);
-                 CHECK_FIELD (num, 1023, -1024, 0);
-                 num = low_sign_unext (num, 11);
-                 INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
-               }
-             else
-               {
-                 if (is_DP_relative (the_insn.exp))
-                   the_insn.reloc = R_HPPA_GOTOFF;
-                 else if (is_PC_relative (the_insn.exp))
-                   the_insn.reloc = R_HPPA_PCREL_CALL;
-                 else
-                   the_insn.reloc = R_HPPA;
-                 the_insn.format = 11;
-                 continue;
-               }
+/* Parse an FP operand format completer returning the completer
+   type.  */
 
 
-           /* Handle a 14 bit immediate at 31.  */
-           case 'J':
-             the_insn.field_selector = pa_chk_field_selector (&s);
-             get_expression (s);
-             s = expr_end;
-             if (the_insn.exp.X_op == O_constant)
-               {
-                 int mb;
+static fp_operand_format
+pa_parse_fp_cnv_format (char **s)
+{
+  int format;
 
 
-                 /* XXX the completer stored away tidbits of information
-                    for us to extract.  We need a cleaner way to do this.
-                    Now that we have lots of letters again, it would be
-                    good to rethink this.  */
-                 mb = opcode & 1;
-                 opcode -= mb;
-                 num = evaluate_absolute (&the_insn);
-                 if (mb != (num < 0))
-                   break;
-                 CHECK_FIELD (num, 8191, -8192, 0);
-                 num = low_sign_unext (num, 14);
-                 INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
-               }
-             break;
+  format = SGL;
+  if (**s == ',')
+    {
+      *s += 1;
+      if (strncasecmp (*s, "sgl", 3) == 0)
+       {
+         format = SGL;
+         *s += 4;
+       }
+      else if (strncasecmp (*s, "dbl", 3) == 0)
+       {
+         format = DBL;
+         *s += 4;
+       }
+      else if (strncasecmp (*s, "quad", 4) == 0)
+       {
+         format = QUAD;
+         *s += 5;
+       }
+      else if (strncasecmp (*s, "w", 1) == 0)
+       {
+         format = W;
+         *s += 2;
+       }
+      else if (strncasecmp (*s, "uw", 2) == 0)
+       {
+         format = UW;
+         *s += 3;
+       }
+      else if (strncasecmp (*s, "dw", 2) == 0)
+       {
+         format = DW;
+         *s += 3;
+       }
+      else if (strncasecmp (*s, "udw", 3) == 0)
+       {
+         format = UDW;
+         *s += 4;
+       }
+      else if (strncasecmp (*s, "qw", 2) == 0)
+       {
+         format = QW;
+         *s += 3;
+       }
+      else if (strncasecmp (*s, "uqw", 3) == 0)
+       {
+         format = UQW;
+         *s += 4;
+       }
+      else
+       {
+         format = ILLEGAL_FMT;
+         as_bad (_("Invalid FP Operand Format: %3s"), *s);
+       }
+    }
 
 
-           /* Handle a 14 bit immediate at 31.  */
-           case 'K':
-             the_insn.field_selector = pa_chk_field_selector (&s);
-             get_expression (s);
-             s = expr_end;
-             if (the_insn.exp.X_op == O_constant)
-               {
-                 int mb;
+  return format;
+}
 
 
-                 mb = opcode & 1;
-                 opcode -= mb;
-                 num = evaluate_absolute (&the_insn);
-                 if (mb == (num < 0))
-                   break;
-                 if (num % 4)
-                   break;
-                 CHECK_FIELD (num, 8191, -8192, 0);
-                 num = low_sign_unext (num, 14);
-                 INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
-               }
-             break;
+/* Parse an FP operand format completer returning the completer
+   type.  */
 
 
-           /* Handle a 16 bit immediate at 31.  */
-           case '<':
-             the_insn.field_selector = pa_chk_field_selector (&s);
-             get_expression (s);
-             s = expr_end;
-             if (the_insn.exp.X_op == O_constant)
-               {
-                 int mb;
+static fp_operand_format
+pa_parse_fp_format (char **s)
+{
+  int format;
 
 
-                 mb = opcode & 1;
-                 opcode -= mb;
-                 num = evaluate_absolute (&the_insn);
-                 if (mb != (num < 0))
-                   break;
-                 CHECK_FIELD (num, 32767, -32768, 0);
-                 num = re_assemble_16 (num);
-                 INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
-               }
-             break;
+  format = SGL;
+  if (**s == ',')
+    {
+      *s += 1;
+      if (strncasecmp (*s, "sgl", 3) == 0)
+       {
+         format = SGL;
+         *s += 4;
+       }
+      else if (strncasecmp (*s, "dbl", 3) == 0)
+       {
+         format = DBL;
+         *s += 4;
+       }
+      else if (strncasecmp (*s, "quad", 4) == 0)
+       {
+         format = QUAD;
+         *s += 5;
+       }
+      else
+       {
+         format = ILLEGAL_FMT;
+         as_bad (_("Invalid FP Operand Format: %3s"), *s);
+       }
+    }
 
 
-           /* Handle a 16 bit immediate at 31.  */
-           case '>':
-             the_insn.field_selector = pa_chk_field_selector (&s);
-             get_expression (s);
-             s = expr_end;
-             if (the_insn.exp.X_op == O_constant)
-               {
-                 int mb;
+  return format;
+}
 
 
-                 mb = opcode & 1;
-                 opcode -= mb;
-                 num = evaluate_absolute (&the_insn);
-                 if (mb == (num < 0))
-                   break;
-                 if (num % 4)
-                   break;
-                 CHECK_FIELD (num, 32767, -32768, 0);
-                 num = re_assemble_16 (num);
-                 INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
-               }
-             break;
+/* Convert from a selector string into a selector type.  */
 
 
-           /* Handle 14 bit immediate, shifted left three times.  */
-           case '#':
-             if (bfd_get_mach (stdoutput) != pa20)
-               break;
-             the_insn.field_selector = pa_chk_field_selector (&s);
-             get_expression (s);
-             s = expr_end;
-             if (the_insn.exp.X_op == O_constant)
-               {
-                 num = evaluate_absolute (&the_insn);
-                 if (num & 0x7)
-                   break;
-                 CHECK_FIELD (num, 8191, -8192, 0);
-                 if (num < 0)
-                   opcode |= 1;
-                 num &= 0x1fff;
-                 num >>= 3;
-                 INSERT_FIELD_AND_CONTINUE (opcode, num, 4);
-               }
-             else
-               {
-                 if (is_DP_relative (the_insn.exp))
-                   the_insn.reloc = R_HPPA_GOTOFF;
-                 else if (is_PC_relative (the_insn.exp))
-                   the_insn.reloc = R_HPPA_PCREL_CALL;
-                 else
-                   the_insn.reloc = R_HPPA;
-                 the_insn.format = 14;
-                 continue;
-               }
-             break;
+static int
+pa_chk_field_selector (char **str)
+{
+  int middle, low, high;
+  int cmp;
+  char name[4];
 
 
-           /* Handle 14 bit immediate, shifted left twice.  */
-           case 'd':
-             the_insn.field_selector = pa_chk_field_selector (&s);
-             get_expression (s);
-             s = expr_end;
-             if (the_insn.exp.X_op == O_constant)
-               {
-                 num = evaluate_absolute (&the_insn);
-                 if (num & 0x3)
-                   break;
-                 CHECK_FIELD (num, 8191, -8192, 0);
-                 if (num < 0)
-                   opcode |= 1;
-                 num &= 0x1fff;
-                 num >>= 2;
-                 INSERT_FIELD_AND_CONTINUE (opcode, num, 3);
-               }
-             else
-               {
-                 if (is_DP_relative (the_insn.exp))
-                   the_insn.reloc = R_HPPA_GOTOFF;
-                 else if (is_PC_relative (the_insn.exp))
-                   the_insn.reloc = R_HPPA_PCREL_CALL;
-                 else
-                   the_insn.reloc = R_HPPA;
-                 the_insn.format = 14;
-                 continue;
-               }
+  /* Read past any whitespace.  */
+  /* FIXME: should we read past newlines and formfeeds??? */
+  while (**str == ' ' || **str == '\t' || **str == '\n' || **str == '\f')
+    *str = *str + 1;
 
 
-           /* Handle a 14 bit immediate at 31.  */
-           case 'j':
-             the_insn.field_selector = pa_chk_field_selector (&s);
-             get_expression (s);
-             s = expr_end;
-             if (the_insn.exp.X_op == O_constant)
-               {
-                 num = evaluate_absolute (&the_insn);
-                 CHECK_FIELD (num, 8191, -8192, 0);
-                 num = low_sign_unext (num, 14);
-                 INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
-               }
-             else
-               {
-                 if (is_DP_relative (the_insn.exp))
-                   the_insn.reloc = R_HPPA_GOTOFF;
-                 else if (is_PC_relative (the_insn.exp))
-                   the_insn.reloc = R_HPPA_PCREL_CALL;
-                 else
-                   the_insn.reloc = R_HPPA;
-                 the_insn.format = 14;
-                 continue;
-               }
+  if ((*str)[1] == '\'' || (*str)[1] == '%')
+    name[0] = TOLOWER ((*str)[0]),
+    name[1] = 0;
+  else if ((*str)[2] == '\'' || (*str)[2] == '%')
+    name[0] = TOLOWER ((*str)[0]),
+    name[1] = TOLOWER ((*str)[1]),
+    name[2] = 0;
+  else if ((*str)[3] == '\'' || (*str)[3] == '%')
+    name[0] = TOLOWER ((*str)[0]),
+    name[1] = TOLOWER ((*str)[1]),
+    name[2] = TOLOWER ((*str)[2]),
+    name[3] = 0;
+  else
+    return e_fsel;
 
 
-           /* Handle a 21 bit immediate at 31.  */
-           case 'k':
-             the_insn.field_selector = pa_chk_field_selector (&s);
-             get_expression (s);
-             s = expr_end;
-             if (the_insn.exp.X_op == O_constant)
-               {
-                 num = evaluate_absolute (&the_insn);
-                 CHECK_FIELD (num >> 11, 1048575, -1048576, 0);
-                 opcode |= re_assemble_21 (num);
-                 continue;
-               }
-             else
-               {
-                 if (is_DP_relative (the_insn.exp))
-                   the_insn.reloc = R_HPPA_GOTOFF;
-                 else if (is_PC_relative (the_insn.exp))
-                   the_insn.reloc = R_HPPA_PCREL_CALL;
-                 else
-                   the_insn.reloc = R_HPPA;
-                 the_insn.format = 21;
-                 continue;
-               }
+  low = 0;
+  high = sizeof (selector_table) / sizeof (struct selector_entry) - 1;
 
 
-           /* Handle a 16 bit immediate at 31 (PA 2.0 wide mode only).  */
-           case 'l':
-             the_insn.field_selector = pa_chk_field_selector (&s);
-             get_expression (s);
-             s = expr_end;
-             if (the_insn.exp.X_op == O_constant)
-               {
-                 num = evaluate_absolute (&the_insn);
-                 CHECK_FIELD (num, 32767, -32768, 0);
-                 opcode |= re_assemble_16 (num);
-                 continue;
-               }
-             else
-               {
-                 /* ??? Is this valid for wide mode?  */
-                 if (is_DP_relative (the_insn.exp))
-                   the_insn.reloc = R_HPPA_GOTOFF;
-                 else if (is_PC_relative (the_insn.exp))
-                   the_insn.reloc = R_HPPA_PCREL_CALL;
-                 else
-                   the_insn.reloc = R_HPPA;
-                 the_insn.format = 14;
-                 continue;
-               }
+  do
+    {
+      middle = (low + high) / 2;
+      cmp = strcmp (name, selector_table[middle].prefix);
+      if (cmp < 0)
+       high = middle - 1;
+      else if (cmp > 0)
+       low = middle + 1;
+      else
+       {
+         *str += strlen (name) + 1;
+#ifndef OBJ_SOM
+         if (selector_table[middle].field_selector == e_nsel)
+           return e_fsel;
+#endif
+         return selector_table[middle].field_selector;
+       }
+    }
+  while (low <= high);
 
 
-           /* Handle a word-aligned 16-bit imm. at 31 (PA2.0 wide).  */
-           case 'y':
-             the_insn.field_selector = pa_chk_field_selector (&s);
-             get_expression (s);
-             s = expr_end;
-             if (the_insn.exp.X_op == O_constant)
-               {
-                 num = evaluate_absolute (&the_insn);
-                 CHECK_FIELD (num, 32767, -32768, 0);
-                 CHECK_ALIGN (num, 4, 0);
-                 opcode |= re_assemble_16 (num);
-                 continue;
-               }
-             else
-               {
-                 /* ??? Is this valid for wide mode?  */
-                 if (is_DP_relative (the_insn.exp))
-                   the_insn.reloc = R_HPPA_GOTOFF;
-                 else if (is_PC_relative (the_insn.exp))
-                   the_insn.reloc = R_HPPA_PCREL_CALL;
-                 else
-                   the_insn.reloc = R_HPPA;
-                 the_insn.format = 14;
-                 continue;
-               }
+  return e_fsel;
+}
 
 
-           /* Handle a dword-aligned 16-bit imm. at 31 (PA2.0 wide).  */
-           case '&':
-             the_insn.field_selector = pa_chk_field_selector (&s);
-             get_expression (s);
-             s = expr_end;
-             if (the_insn.exp.X_op == O_constant)
-               {
-                 num = evaluate_absolute (&the_insn);
-                 CHECK_FIELD (num, 32767, -32768, 0);
-                 CHECK_ALIGN (num, 8, 0);
-                 opcode |= re_assemble_16 (num);
-                 continue;
-               }
-             else
-               {
-                 /* ??? Is this valid for wide mode?  */
-                 if (is_DP_relative (the_insn.exp))
-                   the_insn.reloc = R_HPPA_GOTOFF;
-                 else if (is_PC_relative (the_insn.exp))
-                   the_insn.reloc = R_HPPA_PCREL_CALL;
-                 else
-                   the_insn.reloc = R_HPPA;
-                 the_insn.format = 14;
-                 continue;
-               }
+/* Parse a .byte, .word, .long expression for the HPPA.  Called by
+   cons via the TC_PARSE_CONS_EXPRESSION macro.  */
 
 
-           /* Handle a 12 bit branch displacement.  */
-           case 'w':
-             the_insn.field_selector = pa_chk_field_selector (&s);
-             get_expression (s);
-             s = expr_end;
-             the_insn.pcrel = 1;
-             if (!the_insn.exp.X_add_symbol
-                 || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
-                             FAKE_LABEL_NAME))
-               {
-                 num = evaluate_absolute (&the_insn);
-                 if (num % 4)
-                   {
-                     as_bad (_("Branch to unaligned address"));
-                     break;
-                   }
-                 if (the_insn.exp.X_add_symbol)
-                   num -= 8;
-                 CHECK_FIELD (num, 8191, -8192, 0);
-                 opcode |= re_assemble_12 (num >> 2);
-                 continue;
-               }
-             else
-               {
-                 the_insn.reloc = R_HPPA_PCREL_CALL;
-                 the_insn.format = 12;
-                 the_insn.arg_reloc = last_call_desc.arg_reloc;
-                 memset (&last_call_desc, 0, sizeof (struct call_desc));
-                 s = expr_end;
-                 continue;
-               }
+void
+parse_cons_expression_hppa (expressionS *exp)
+{
+  hppa_field_selector = pa_chk_field_selector (&input_line_pointer);
+  expression (exp);
+}
 
 
-           /* Handle a 17 bit branch displacement.  */
-           case 'W':
-             the_insn.field_selector = pa_chk_field_selector (&s);
-             get_expression (s);
-             s = expr_end;
-             the_insn.pcrel = 1;
-             if (!the_insn.exp.X_add_symbol
-                 || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
-                             FAKE_LABEL_NAME))
-               {
-                 num = evaluate_absolute (&the_insn);
-                 if (num % 4)
-                   {
-                     as_bad (_("Branch to unaligned address"));
-                     break;
-                   }
-                 if (the_insn.exp.X_add_symbol)
-                   num -= 8;
-                 CHECK_FIELD (num, 262143, -262144, 0);
-                 opcode |= re_assemble_17 (num >> 2);
-                 continue;
-               }
-             else
-               {
-                 the_insn.reloc = R_HPPA_PCREL_CALL;
-                 the_insn.format = 17;
-                 the_insn.arg_reloc = last_call_desc.arg_reloc;
-                 memset (&last_call_desc, 0, sizeof (struct call_desc));
-                 continue;
-               }
+/* Evaluate an absolute expression EXP which may be modified by
+   the selector FIELD_SELECTOR.  Return the value of the expression.  */
+static int
+evaluate_absolute (struct pa_it *insn)
+{
+  offsetT value;
+  expressionS exp;
+  int field_selector = insn->field_selector;
 
 
-           /* Handle a 22 bit branch displacement.  */
-           case 'X':
-             the_insn.field_selector = pa_chk_field_selector (&s);
-             get_expression (s);
-             s = expr_end;
-             the_insn.pcrel = 1;
-             if (!the_insn.exp.X_add_symbol
-                 || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
-                             FAKE_LABEL_NAME))
-               {
-                 num = evaluate_absolute (&the_insn);
-                 if (num % 4)
-                   {
-                     as_bad (_("Branch to unaligned address"));
-                     break;
-                   }
-                 if (the_insn.exp.X_add_symbol)
-                   num -= 8;
-                 CHECK_FIELD (num, 8388607, -8388608, 0);
-                 opcode |= re_assemble_22 (num >> 2);
-               }
-             else
-               {
-                 the_insn.reloc = R_HPPA_PCREL_CALL;
-                 the_insn.format = 22;
-                 the_insn.arg_reloc = last_call_desc.arg_reloc;
-                 memset (&last_call_desc, 0, sizeof (struct call_desc));
-                 continue;
-               }
+  exp = insn->exp;
+  value = exp.X_add_number;
 
 
-           /* Handle an absolute 17 bit branch target.  */
-           case 'z':
-             the_insn.field_selector = pa_chk_field_selector (&s);
-             get_expression (s);
-             s = expr_end;
-             the_insn.pcrel = 0;
-             if (!the_insn.exp.X_add_symbol
-                 || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
-                             FAKE_LABEL_NAME))
-               {
-                 num = evaluate_absolute (&the_insn);
-                 if (num % 4)
-                   {
-                     as_bad (_("Branch to unaligned address"));
-                     break;
-                   }
-                 if (the_insn.exp.X_add_symbol)
-                   num -= 8;
-                 CHECK_FIELD (num, 262143, -262144, 0);
-                 opcode |= re_assemble_17 (num >> 2);
-                 continue;
-               }
-             else
-               {
-                 the_insn.reloc = R_HPPA_ABS_CALL;
-                 the_insn.format = 17;
-                 the_insn.arg_reloc = last_call_desc.arg_reloc;
-                 memset (&last_call_desc, 0, sizeof (struct call_desc));
-                 continue;
-               }
+  return hppa_field_adjust (0, value, field_selector);
+}
 
 
-           /* Handle '%r1' implicit operand of addil instruction.  */
-           case 'Z':
-             if (*s == ',' && *(s + 1) == '%' && *(s + 3) == '1'
-                 && (*(s + 2) == 'r' || *(s + 2) == 'R'))
-               {
-                 s += 4;
-                 continue;
-               }
-             else
-               break;
+/* Mark (via expr_end) the end of an absolute expression.  FIXME.  */
 
 
-           /* Handle '%sr0,%r31' implicit operand of be,l instruction.  */
-           case 'Y':
-             if (strncasecmp (s, "%sr0,%r31", 9) != 0)
-               break;
-             s += 9;
-             continue;
+static int
+pa_get_absolute_expression (struct pa_it *insn, char **strp)
+{
+  char *save_in;
 
 
-           /* Handle immediate value of 0 for ordered load/store instructions.  */
-           case '@':
-             if (*s != '0')
-               break;
-             s++;
-             continue;
+  insn->field_selector = pa_chk_field_selector (strp);
+  save_in = input_line_pointer;
+  input_line_pointer = *strp;
+  expression (&insn->exp);
+  /* This is not perfect, but is a huge improvement over doing nothing.
 
 
-           /* Handle a 2 bit shift count at 25.  */
-           case '.':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 3, 1, strict);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
+     The PA assembly syntax is ambiguous in a variety of ways.  Consider
+     this string "4 %r5"  Is that the number 4 followed by the register
+     r5, or is that 4 MOD r5?
 
 
-           /* Handle a 4 bit shift count at 25.  */
-           case '*':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 15, 0, strict);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
+     If we get a modulo expression when looking for an absolute, we try
+     again cutting off the input string at the first whitespace character.  */
+  if (insn->exp.X_op == O_modulus)
+    {
+      char *s, c;
+      int retval;
 
 
-           /* Handle a 5 bit shift count at 26.  */
-           case 'p':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 31, 0, strict);
-             INSERT_FIELD_AND_CONTINUE (opcode, 31 - num, 5);
+      input_line_pointer = *strp;
+      s = *strp;
+      while (*s != ',' && *s != ' ' && *s != '\t')
+       s++;
 
 
-           /* Handle a 6 bit shift count at 20,22:26.  */
-           case '~':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 63, 0, strict);
-             num = 63 - num;
-             opcode |= (num & 0x20) << 6;
-             INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 5);
+      c = *s;
+      *s = 0;
 
 
-           /* Handle a 6 bit field length at 23,27:31.  */
-           case '%':
-             flag = 0;
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 64, 1, strict);
-             num--;
-             opcode |= (num & 0x20) << 3;
-             num = 31 - (num & 0x1f);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+      retval = pa_get_absolute_expression (insn, strp);
 
 
-           /* Handle a 6 bit field length at 19,27:31.  */
-           case '|':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 64, 1, strict);
-             num--;
-             opcode |= (num & 0x20) << 7;
-             num = 31 - (num & 0x1f);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+      input_line_pointer = save_in;
+      *s = c;
+      return evaluate_absolute (insn);
+    }
+  /* When in strict mode we have a non-match, fix up the pointers
+     and return to our caller.  */
+  if (insn->exp.X_op != O_constant && strict)
+    {
+      expr_end = input_line_pointer;
+      input_line_pointer = save_in;
+      return 0;
+    }
+  if (insn->exp.X_op != O_constant)
+    {
+      as_bad (_("Bad segment (should be absolute)."));
+      expr_end = input_line_pointer;
+      input_line_pointer = save_in;
+      return 0;
+    }
+  expr_end = input_line_pointer;
+  input_line_pointer = save_in;
+  return evaluate_absolute (insn);
+}
 
 
-           /* Handle a 5 bit bit position at 26.  */
-           case 'P':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 31, 0, strict);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 5);
+/* Given an argument location specification return the associated
+   argument location number.  */
 
 
-           /* Handle a 6 bit bit position at 20,22:26.  */
-           case 'q':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 63, 0, strict);
-             opcode |= (num & 0x20) << 6;
-             INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 5);
+static unsigned int
+pa_build_arg_reloc (char *type_name)
+{
 
 
-           /* Handle a 5 bit immediate at 10 with 'd' as the complement
-              of the high bit of the immediate.  */
-           case 'B':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 63, 0, strict);
-             if (num & 0x20)
-               ;
-             else
-               opcode |= (1 << 13);
-             INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 21);
+  if (strncasecmp (type_name, "no", 2) == 0)
+    return 0;
+  if (strncasecmp (type_name, "gr", 2) == 0)
+    return 1;
+  else if (strncasecmp (type_name, "fr", 2) == 0)
+    return 2;
+  else if (strncasecmp (type_name, "fu", 2) == 0)
+    return 3;
+  else
+    as_bad (_("Invalid argument location: %s\n"), type_name);
 
 
-           /* Handle a 5 bit immediate at 10.  */
-           case 'Q':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 31, 0, strict);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
+  return 0;
+}
 
 
-           /* Handle a 9 bit immediate at 28.  */
-           case '$':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 511, 1, strict);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 3);
+/* Encode and return an argument relocation specification for
+   the given register in the location specified by arg_reloc.  */
 
 
-           /* Handle a 13 bit immediate at 18.  */
-           case 'A':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 8191, 0, strict);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
+static unsigned int
+pa_align_arg_reloc (unsigned int reg, unsigned int arg_reloc)
+{
+  unsigned int new_reloc;
 
 
-           /* Handle a 26 bit immediate at 31.  */
-           case 'D':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 67108863, 0, strict);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+  new_reloc = arg_reloc;
+  switch (reg)
+    {
+    case 0:
+      new_reloc <<= 8;
+      break;
+    case 1:
+      new_reloc <<= 6;
+      break;
+    case 2:
+      new_reloc <<= 4;
+      break;
+    case 3:
+      new_reloc <<= 2;
+      break;
+    default:
+      as_bad (_("Invalid argument description: %d"), reg);
+    }
 
 
-           /* Handle a 3 bit SFU identifier at 25.  */
-           case 'v':
-             if (*s++ != ',')
-               as_bad (_("Invalid SFU identifier"));
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 7, 0, strict);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
+  return new_reloc;
+}
 
 
-           /* Handle a 20 bit SOP field for spop0.  */
-           case 'O':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 1048575, 0, strict);
-             num = (num & 0x1f) | ((num & 0x000fffe0) << 6);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+/* Parse a non-negated compare/subtract completer returning the
+   number (for encoding in instructions) of the given completer.  */
 
 
-           /* Handle a 15bit SOP field for spop1.  */
-           case 'o':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 32767, 0, strict);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 11);
+static int
+pa_parse_nonneg_cmpsub_cmpltr (char **s)
+{
+  int cmpltr;
+  char *name = *s + 1;
+  char c;
+  char *save_s = *s;
+  int nullify = 0;
 
 
-           /* Handle a 10bit SOP field for spop3.  */
-           case '0':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 1023, 0, strict);
-             num = (num & 0x1f) | ((num & 0x000003e0) << 6);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+  cmpltr = 0;
+  if (**s == ',')
+    {
+      *s += 1;
+      while (**s != ',' && **s != ' ' && **s != '\t')
+       *s += 1;
+      c = **s;
+      **s = 0x00;
 
 
-           /* Handle a 15 bit SOP field for spop2.  */
-           case '1':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 32767, 0, strict);
-             num = (num & 0x1f) | ((num & 0x00007fe0) << 6);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+      if (strcmp (name, "=") == 0)
+       {
+         cmpltr = 1;
+       }
+      else if (strcmp (name, "<") == 0)
+       {
+         cmpltr = 2;
+       }
+      else if (strcmp (name, "<=") == 0)
+       {
+         cmpltr = 3;
+       }
+      else if (strcmp (name, "<<") == 0)
+       {
+         cmpltr = 4;
+       }
+      else if (strcmp (name, "<<=") == 0)
+       {
+         cmpltr = 5;
+       }
+      else if (strcasecmp (name, "sv") == 0)
+       {
+         cmpltr = 6;
+       }
+      else if (strcasecmp (name, "od") == 0)
+       {
+         cmpltr = 7;
+       }
+      /* If we have something like addb,n then there is no condition
+         completer.  */
+      else if (strcasecmp (name, "n") == 0)
+       {
+         cmpltr = 0;
+         nullify = 1;
+       }
+      else
+       {
+         cmpltr = -1;
+       }
+      **s = c;
+    }
 
 
-           /* Handle a 3-bit co-processor ID field.  */
-           case 'u':
-             if (*s++ != ',')
-               as_bad (_("Invalid COPR identifier"));
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 7, 0, strict);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
+  /* Reset pointers if this was really a ,n for a branch instruction.  */
+  if (nullify)
+    *s = save_s;
 
 
-           /* Handle a 22bit SOP field for copr.  */
-           case '2':
-             num = pa_get_absolute_expression (&the_insn, &s);
-             if (strict && the_insn.exp.X_op != O_constant)
-               break;
-             s = expr_end;
-             CHECK_FIELD (num, 4194303, 0, strict);
-             num = (num & 0x1f) | ((num & 0x003fffe0) << 4);
-             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+  return cmpltr;
+}
 
 
-           /* Handle a source FP operand format completer.  */
-           case '{':
-             if (*s == ',' && *(s+1) == 't')
-               {
-                 the_insn.trunc = 1;
-                 s += 2;
-               }
-             else
-               the_insn.trunc = 0;
-             flag = pa_parse_fp_cnv_format (&s);
-             the_insn.fpof1 = flag;
-             if (flag == W || flag == UW)
-               flag = SGL;
-             if (flag == DW || flag == UDW)
-               flag = DBL;
-             if (flag == QW || flag == UQW)
-               flag = QUAD;
-             INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+/* Parse a negated compare/subtract completer returning the
+   number (for encoding in instructions) of the given completer.  */
 
 
-           /* Handle a destination FP operand format completer.  */
-           case '_':
-             /* pa_parse_format needs the ',' prefix.  */
-             s--;
-             flag = pa_parse_fp_cnv_format (&s);
-             the_insn.fpof2 = flag;
-             if (flag == W || flag == UW)
-               flag = SGL;
-             if (flag == DW || flag == UDW)
-               flag = DBL;
-             if (flag == QW || flag == UQW)
-               flag = QUAD;
-             opcode |= flag << 13;
-             if (the_insn.fpof1 == SGL
-                 || the_insn.fpof1 == DBL
-                 || the_insn.fpof1 == QUAD)
-               {
-                 if (the_insn.fpof2 == SGL
-                     || the_insn.fpof2 == DBL
-                     || the_insn.fpof2 == QUAD)
-                   flag = 0;
-                 else if (the_insn.fpof2 == W
-                     || the_insn.fpof2 == DW
-                     || the_insn.fpof2 == QW)
-                   flag = 2;
-                 else if (the_insn.fpof2 == UW
-                     || the_insn.fpof2 == UDW
-                     || the_insn.fpof2 == UQW)
-                   flag = 6;
-                 else
-                   abort ();
-               }
-             else if (the_insn.fpof1 == W
-                      || the_insn.fpof1 == DW
-                      || the_insn.fpof1 == QW)
-               {
-                 if (the_insn.fpof2 == SGL
-                     || the_insn.fpof2 == DBL
-                     || the_insn.fpof2 == QUAD)
-                   flag = 1;
-                 else
-                   abort ();
-               }
-             else if (the_insn.fpof1 == UW
-                      || the_insn.fpof1 == UDW
-                      || the_insn.fpof1 == UQW)
-               {
-                 if (the_insn.fpof2 == SGL
-                     || the_insn.fpof2 == DBL
-                     || the_insn.fpof2 == QUAD)
-                   flag = 5;
-                 else
-                   abort ();
-               }
-             flag |= the_insn.trunc;
-             INSERT_FIELD_AND_CONTINUE (opcode, flag, 15);
+static int
+pa_parse_neg_cmpsub_cmpltr (char **s)
+{
+  int cmpltr;
+  char *name = *s + 1;
+  char c;
+  char *save_s = *s;
+  int nullify = 0;
 
 
-           /* Handle a source FP operand format completer.  */
-           case 'F':
-             flag = pa_parse_fp_format (&s);
-             the_insn.fpof1 = flag;
-             INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+  cmpltr = 0;
+  if (**s == ',')
+    {
+      *s += 1;
+      while (**s != ',' && **s != ' ' && **s != '\t')
+       *s += 1;
+      c = **s;
+      **s = 0x00;
 
 
-           /* Handle a destination FP operand format completer.  */
-           case 'G':
-             /* pa_parse_format needs the ',' prefix.  */
-             s--;
-             flag = pa_parse_fp_format (&s);
-             the_insn.fpof2 = flag;
-             INSERT_FIELD_AND_CONTINUE (opcode, flag, 13);
+      if (strcasecmp (name, "tr") == 0)
+       {
+         cmpltr = 0;
+       }
+      else if (strcmp (name, "<>") == 0)
+       {
+         cmpltr = 1;
+       }
+      else if (strcmp (name, ">=") == 0)
+       {
+         cmpltr = 2;
+       }
+      else if (strcmp (name, ">") == 0)
+       {
+         cmpltr = 3;
+       }
+      else if (strcmp (name, ">>=") == 0)
+       {
+         cmpltr = 4;
+       }
+      else if (strcmp (name, ">>") == 0)
+       {
+         cmpltr = 5;
+       }
+      else if (strcasecmp (name, "nsv") == 0)
+       {
+         cmpltr = 6;
+       }
+      else if (strcasecmp (name, "ev") == 0)
+       {
+         cmpltr = 7;
+       }
+      /* If we have something like addb,n then there is no condition
+         completer.  */
+      else if (strcasecmp (name, "n") == 0)
+       {
+         cmpltr = 0;
+         nullify = 1;
+       }
+      else
+       {
+         cmpltr = -1;
+       }
+      **s = c;
+    }
 
 
-           /* Handle a source FP operand format completer at 20.  */
-           case 'I':
-             flag = pa_parse_fp_format (&s);
-             the_insn.fpof1 = flag;
-             INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+  /* Reset pointers if this was really a ,n for a branch instruction.  */
+  if (nullify)
+    *s = save_s;
 
 
-           /* Handle a floating point operand format at 26.
-              Only allows single and double precision.  */
-           case 'H':
-             flag = pa_parse_fp_format (&s);
-             switch (flag)
-               {
-               case SGL:
-                 opcode |= 0x20;
-               case DBL:
-                 the_insn.fpof1 = flag;
-                 continue;
+  return cmpltr;
+}
 
 
-               case QUAD:
-               case ILLEGAL_FMT:
-               default:
-                 as_bad (_("Invalid Floating Point Operand Format."));
-               }
-             break;
+/* Parse a 64 bit compare and branch completer returning the number (for
+   encoding in instructions) of the given completer.
 
 
-           /* Handle all floating point registers.  */
-           case 'f':
-             switch (*++args)
-               {
-               /* Float target register.  */
-               case 't':
-                 if (!pa_parse_number (&s, 3))
-                   break;
-                 num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
-                 CHECK_FIELD (num, 31, 0, 0);
-                 INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+   Nonnegated comparisons are returned as 0-7, negated comparisons are
+   returned as 8-15.  */
 
 
-               /* Float target register with L/R selection.  */
-               case 'T':
-                 {
-                   if (!pa_parse_number (&s, 1))
-                     break;
-                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
-                   CHECK_FIELD (num, 31, 0, 0);
-                   opcode |= num;
+static int
+pa_parse_cmpb_64_cmpltr (char **s)
+{
+  int cmpltr;
+  char *name = *s + 1;
+  char c;
 
 
-                   /* 0x30 opcodes are FP arithmetic operation opcodes
-                      and need to be turned into 0x38 opcodes.  This
-                      is not necessary for loads/stores.  */
-                   if (need_pa11_opcode ()
-                       && ((opcode & 0xfc000000) == 0x30000000))
-                     opcode |= 1 << 27;
+  cmpltr = -1;
+  if (**s == ',')
+    {
+      *s += 1;
+      while (**s != ',' && **s != ' ' && **s != '\t')
+       *s += 1;
+      c = **s;
+      **s = 0x00;
 
 
-                   opcode |= (pa_number & FP_REG_RSEL ? 1 << 6 : 0);
-                   continue;
-                 }
+      if (strcmp (name, "*") == 0)
+       {
+         cmpltr = 0;
+       }
+      else if (strcmp (name, "*=") == 0)
+       {
+         cmpltr = 1;
+       }
+      else if (strcmp (name, "*<") == 0)
+       {
+         cmpltr = 2;
+       }
+      else if (strcmp (name, "*<=") == 0)
+       {
+         cmpltr = 3;
+       }
+      else if (strcmp (name, "*<<") == 0)
+       {
+         cmpltr = 4;
+       }
+      else if (strcmp (name, "*<<=") == 0)
+       {
+         cmpltr = 5;
+       }
+      else if (strcasecmp (name, "*sv") == 0)
+       {
+         cmpltr = 6;
+       }
+      else if (strcasecmp (name, "*od") == 0)
+       {
+         cmpltr = 7;
+       }
+      else if (strcasecmp (name, "*tr") == 0)
+       {
+         cmpltr = 8;
+       }
+      else if (strcmp (name, "*<>") == 0)
+       {
+         cmpltr = 9;
+       }
+      else if (strcmp (name, "*>=") == 0)
+       {
+         cmpltr = 10;
+       }
+      else if (strcmp (name, "*>") == 0)
+       {
+         cmpltr = 11;
+       }
+      else if (strcmp (name, "*>>=") == 0)
+       {
+         cmpltr = 12;
+       }
+      else if (strcmp (name, "*>>") == 0)
+       {
+         cmpltr = 13;
+       }
+      else if (strcasecmp (name, "*nsv") == 0)
+       {
+         cmpltr = 14;
+       }
+      else if (strcasecmp (name, "*ev") == 0)
+       {
+         cmpltr = 15;
+       }
+      else
+       {
+         cmpltr = -1;
+       }
+      **s = c;
+    }
 
 
-               /* Float operand 1.  */
-               case 'a':
-                 {
-                   if (!pa_parse_number (&s, 1))
-                     break;
-                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
-                   CHECK_FIELD (num, 31, 0, 0);
-                   opcode |= num << 21;
-                   if (need_pa11_opcode ())
-                     {
-                       opcode |= (pa_number & FP_REG_RSEL ? 1 << 7 : 0);
-                       opcode |= 1 << 27;
-                     }
-                   continue;
-                 }
-
-               /* Float operand 1 with L/R selection.  */
-               case 'X':
-               case 'A':
-                 {
-                   if (!pa_parse_number (&s, 1))
-                     break;
-                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
-                   CHECK_FIELD (num, 31, 0, 0);
-                   opcode |= num << 21;
-                   opcode |= (pa_number & FP_REG_RSEL ? 1 << 7 : 0);
-                   continue;
-                 }
-
-               /* Float operand 2.  */
-               case 'b':
-                 {
-                   if (!pa_parse_number (&s, 1))
-                     break;
-                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
-                   CHECK_FIELD (num, 31, 0, 0);
-                   opcode |= num << 16;
-                   if (need_pa11_opcode ())
-                     {
-                       opcode |= (pa_number & FP_REG_RSEL ? 1 << 12 : 0);
-                       opcode |= 1 << 27;
-                     }
-                   continue;
-                 }
-
-               /* Float operand 2 with L/R selection.  */
-               case 'B':
-                 {
-                   if (!pa_parse_number (&s, 1))
-                     break;
-                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
-                   CHECK_FIELD (num, 31, 0, 0);
-                   opcode |= num << 16;
-                   opcode |= (pa_number & FP_REG_RSEL ? 1 << 12 : 0);
-                   continue;
-                 }
-
-               /* Float operand 3 for fmpyfadd, fmpynfadd.  */
-               case 'C':
-                 {
-                   if (!pa_parse_number (&s, 1))
-                     break;
-                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
-                   CHECK_FIELD (num, 31, 0, 0);
-                   opcode |= (num & 0x1c) << 11;
-                   opcode |= (num & 0x03) << 9;
-                   opcode |= (pa_number & FP_REG_RSEL ? 1 << 8 : 0);
-                   continue;
-                 }
-
-               /* Float mult operand 1 for fmpyadd, fmpysub */
-               case 'i':
-                 {
-                   if (!pa_parse_number (&s, 1))
-                     break;
-                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
-                   CHECK_FIELD (num, 31, 0, 0);
-                   if (the_insn.fpof1 == SGL)
-                     {
-                       if (num < 16)
-                         {
-                           as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
-                           break;
-                         }
-                       num &= 0xF;
-                       num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
-                     }
-                   INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
-                 }
-
-               /* Float mult operand 2 for fmpyadd, fmpysub */
-               case 'j':
-                 {
-                   if (!pa_parse_number (&s, 1))
-                     break;
-                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
-                   CHECK_FIELD (num, 31, 0, 0);
-                   if (the_insn.fpof1 == SGL)
-                     {
-                       if (num < 16)
-                         {
-                           as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
-                           break;
-                         }
-                       num &= 0xF;
-                       num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
-                     }
-                   INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
-                 }
-
-               /* Float mult target for fmpyadd, fmpysub */
-               case 'k':
-                 {
-                   if (!pa_parse_number (&s, 1))
-                     break;
-                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
-                   CHECK_FIELD (num, 31, 0, 0);
-                   if (the_insn.fpof1 == SGL)
-                     {
-                       if (num < 16)
-                         {
-                           as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
-                           break;
-                         }
-                       num &= 0xF;
-                       num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
-                     }
-                   INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
-                 }
-
-               /* Float add operand 1 for fmpyadd, fmpysub */
-               case 'l':
-                 {
-                   if (!pa_parse_number (&s, 1))
-                     break;
-                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
-                   CHECK_FIELD (num, 31, 0, 0);
-                   if (the_insn.fpof1 == SGL)
-                     {
-                       if (num < 16)
-                         {
-                           as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
-                           break;
-                         }
-                       num &= 0xF;
-                       num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
-                     }
-                   INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
-                 }
-
-               /* Float add target for fmpyadd, fmpysub */
-               case 'm':
-                 {
-                   if (!pa_parse_number (&s, 1))
-                     break;
-                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
-                   CHECK_FIELD (num, 31, 0, 0);
-                   if (the_insn.fpof1 == SGL)
-                     {
-                       if (num < 16)
-                         {
-                           as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
-                           break;
-                         }
-                       num &= 0xF;
-                       num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
-                     }
-                   INSERT_FIELD_AND_CONTINUE (opcode, num, 11);
-                 }
+  return cmpltr;
+}
 
 
-               /* Handle L/R register halves like 'x'.  */
-               case 'E':
-               case 'e':
-                 {
-                   if (!pa_parse_number (&s, 1))
-                     break;
-                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
-                   CHECK_FIELD (num, 31, 0, 0);
-                   opcode |= num << 16;
-                   if (need_pa11_opcode ())
-                     {
-                       opcode |= (pa_number & FP_REG_RSEL ? 1 << 1 : 0);
-                     }
-                   continue;
-                 }
+/* Parse a 64 bit compare immediate and branch completer returning the number
+   (for encoding in instructions) of the given completer.  */
 
 
-               /* Float target register (PA 2.0 wide).  */
-               case 'x':
-                 if (!pa_parse_number (&s, 3))
-                   break;
-                 num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
-                 CHECK_FIELD (num, 31, 0, 0);
-                 INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
+static int
+pa_parse_cmpib_64_cmpltr (char **s)
+{
+  int cmpltr;
+  char *name = *s + 1;
+  char c;
 
 
-               default:
-                 abort ();
-               }
-             break;
+  cmpltr = -1;
+  if (**s == ',')
+    {
+      *s += 1;
+      while (**s != ',' && **s != ' ' && **s != '\t')
+       *s += 1;
+      c = **s;
+      **s = 0x00;
 
 
-           default:
-             abort ();
-           }
-         break;
+      if (strcmp (name, "*<<") == 0)
+       {
+         cmpltr = 0;
        }
        }
-
-      /* If this instruction is specific to a particular architecture,
-        then set a new architecture.  This automatic promotion crud is
-        for compatibility with HP's old assemblers only.  */
-      if (match == TRUE
-         && bfd_get_mach (stdoutput) < insn->arch
-         && !bfd_set_arch_mach (stdoutput, bfd_arch_hppa, insn->arch))
+      else if (strcmp (name, "*=") == 0)
        {
        {
-         as_warn (_("could not update architecture and machine"));
-         match = FALSE;
+         cmpltr = 1;
        }
        }
-
- failed:
-      /* Check if the args matched.  */
-      if (!match)
+      else if (strcmp (name, "*<") == 0)
        {
        {
-         if (&insn[1] - pa_opcodes < (int) NUMOPCODES
-             && !strcmp (insn->name, insn[1].name))
-           {
-             ++insn;
-             s = argstart;
-             continue;
-           }
-         else
-           {
-             as_bad (_("Invalid operands %s"), error_message);
-             return;
-           }
+         cmpltr = 2;
        }
        }
-      break;
-    }
-
-  the_insn.opcode = opcode;
-}
-
-/* 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 or NULL is returned.  */
-
-#define MAX_LITTLENUMS 6
-
-char *
-md_atof (type, litP, sizeP)
-     char type;
-     char *litP;
-     int *sizeP;
-{
-  int prec;
-  LITTLENUM_TYPE words[MAX_LITTLENUMS];
-  LITTLENUM_TYPE *wordP;
-  char *t;
-
-  switch (type)
-    {
-
-    case 'f':
-    case 'F':
-    case 's':
-    case 'S':
-      prec = 2;
-      break;
+      else if (strcmp (name, "*<=") == 0)
+       {
+         cmpltr = 3;
+       }
+      else if (strcmp (name, "*>>=") == 0)
+       {
+         cmpltr = 4;
+       }
+      else if (strcmp (name, "*<>") == 0)
+       {
+         cmpltr = 5;
+       }
+      else if (strcasecmp (name, "*>=") == 0)
+       {
+         cmpltr = 6;
+       }
+      else if (strcasecmp (name, "*>") == 0)
+       {
+         cmpltr = 7;
+       }
+      else
+       {
+         cmpltr = -1;
+       }
+      **s = c;
+    }
 
 
-    case 'd':
-    case 'D':
-    case 'r':
-    case 'R':
-      prec = 4;
-      break;
+  return cmpltr;
+}
 
 
-    case 'x':
-    case 'X':
-      prec = 6;
-      break;
+/* Parse a non-negated addition completer returning the number
+   (for encoding in instructions) of the given completer.  */
 
 
-    case 'p':
-    case 'P':
-      prec = 6;
-      break;
+static int
+pa_parse_nonneg_add_cmpltr (char **s)
+{
+  int cmpltr;
+  char *name = *s + 1;
+  char c;
+  char *save_s = *s;
+  int nullify = 0;
 
 
-    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 * sizeof (LITTLENUM_TYPE);
-  for (wordP = words; prec--;)
+  cmpltr = 0;
+  if (**s == ',')
     {
     {
-      md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE));
-      litP += sizeof (LITTLENUM_TYPE);
+      *s += 1;
+      while (**s != ',' && **s != ' ' && **s != '\t')
+       *s += 1;
+      c = **s;
+      **s = 0x00;
+      if (strcmp (name, "=") == 0)
+       {
+         cmpltr = 1;
+       }
+      else if (strcmp (name, "<") == 0)
+       {
+         cmpltr = 2;
+       }
+      else if (strcmp (name, "<=") == 0)
+       {
+         cmpltr = 3;
+       }
+      else if (strcasecmp (name, "nuv") == 0)
+       {
+         cmpltr = 4;
+       }
+      else if (strcasecmp (name, "znv") == 0)
+       {
+         cmpltr = 5;
+       }
+      else if (strcasecmp (name, "sv") == 0)
+       {
+         cmpltr = 6;
+       }
+      else if (strcasecmp (name, "od") == 0)
+       {
+         cmpltr = 7;
+       }
+      /* If we have something like addb,n then there is no condition
+         completer.  */
+      else if (strcasecmp (name, "n") == 0)
+       {
+         cmpltr = 0;
+         nullify = 1;
+       }
+      else
+       {
+         cmpltr = -1;
+       }
+      **s = c;
     }
     }
-  return NULL;
-}
 
 
-/* Write out big-endian.  */
+  /* Reset pointers if this was really a ,n for a branch instruction.  */
+  if (nullify)
+    *s = save_s;
 
 
-void
-md_number_to_chars (buf, val, n)
-     char *buf;
-     valueT val;
-     int n;
-{
-  number_to_chars_bigendian (buf, val, n);
+  return cmpltr;
 }
 
 }
 
-/* Translate internal representation of relocation info to BFD target
-   format.  */
+/* Parse a negated addition completer returning the number
+   (for encoding in instructions) of the given completer.  */
 
 
-arelent **
-tc_gen_reloc (section, fixp)
-     asection *section;
-     fixS *fixp;
+static int
+pa_parse_neg_add_cmpltr (char **s)
 {
 {
-  arelent *reloc;
-  struct hppa_fix_struct *hppa_fixp;
-  static arelent *no_relocs = NULL;
-  arelent **relocs;
-  reloc_type **codes;
-  reloc_type code;
-  int n_relocs;
-  int i;
-
-  hppa_fixp = (struct hppa_fix_struct *) fixp->tc_fix_data;
-  if (fixp->fx_addsy == 0)
-    return &no_relocs;
-
-  assert (hppa_fixp != 0);
-  assert (section != 0);
-
-  reloc = (arelent *) xmalloc (sizeof (arelent));
-
-  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
-  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
-  codes = hppa_gen_reloc_type (stdoutput,
-                              fixp->fx_r_type,
-                              hppa_fixp->fx_r_format,
-                              hppa_fixp->fx_r_field,
-                              fixp->fx_subsy != NULL,
-                              symbol_get_bfdsym (fixp->fx_addsy));
+  int cmpltr;
+  char *name = *s + 1;
+  char c;
+  char *save_s = *s;
+  int nullify = 0;
 
 
-  if (codes == NULL)
+  cmpltr = 0;
+  if (**s == ',')
     {
     {
-      as_bad_where (fixp->fx_file, fixp->fx_line, _("Cannot handle fixup"));
-      abort ();
+      *s += 1;
+      while (**s != ',' && **s != ' ' && **s != '\t')
+       *s += 1;
+      c = **s;
+      **s = 0x00;
+      if (strcasecmp (name, "tr") == 0)
+       {
+         cmpltr = 0;
+       }
+      else if (strcmp (name, "<>") == 0)
+       {
+         cmpltr = 1;
+       }
+      else if (strcmp (name, ">=") == 0)
+       {
+         cmpltr = 2;
+       }
+      else if (strcmp (name, ">") == 0)
+       {
+         cmpltr = 3;
+       }
+      else if (strcasecmp (name, "uv") == 0)
+       {
+         cmpltr = 4;
+       }
+      else if (strcasecmp (name, "vnz") == 0)
+       {
+         cmpltr = 5;
+       }
+      else if (strcasecmp (name, "nsv") == 0)
+       {
+         cmpltr = 6;
+       }
+      else if (strcasecmp (name, "ev") == 0)
+       {
+         cmpltr = 7;
+       }
+      /* If we have something like addb,n then there is no condition
+         completer.  */
+      else if (strcasecmp (name, "n") == 0)
+       {
+         cmpltr = 0;
+         nullify = 1;
+       }
+      else
+       {
+         cmpltr = -1;
+       }
+      **s = c;
     }
 
     }
 
-  for (n_relocs = 0; codes[n_relocs]; n_relocs++)
-    ;
-
-  relocs = (arelent **) xmalloc (sizeof (arelent *) * n_relocs + 1);
-  reloc = (arelent *) xmalloc (sizeof (arelent) * n_relocs);
-  for (i = 0; i < n_relocs; i++)
-    relocs[i] = &reloc[i];
+  /* Reset pointers if this was really a ,n for a branch instruction.  */
+  if (nullify)
+    *s = save_s;
 
 
-  relocs[n_relocs] = NULL;
+  return cmpltr;
+}
 
 
-#ifdef OBJ_ELF
-  switch (fixp->fx_r_type)
-    {
-    default:
-      assert (n_relocs == 1);
+/* Parse a 64 bit wide mode add and branch completer returning the number (for
+   encoding in instructions) of the given completer.  */
 
 
-      code = *codes[0];
+static int
+pa_parse_addb_64_cmpltr (char **s)
+{
+  int cmpltr;
+  char *name = *s + 1;
+  char c;
+  char *save_s = *s;
+  int nullify = 0;
 
 
-      /* Now, do any processing that is dependent on the relocation type.  */
-      switch (code)
+  cmpltr = 0;
+  if (**s == ',')
+    {
+      *s += 1;
+      while (**s != ',' && **s != ' ' && **s != '\t')
+       *s += 1;
+      c = **s;
+      **s = 0x00;
+      if (strcmp (name, "=") == 0)
        {
        {
-       case R_PARISC_DLTREL21L:
-       case R_PARISC_DLTREL14R:
-       case R_PARISC_DLTREL14F:
-       case R_PARISC_PLABEL32:
-       case R_PARISC_PLABEL21L:
-       case R_PARISC_PLABEL14R:
-         /* For plabel relocations, the addend of the
-            relocation should be either 0 (no static link) or 2
-            (static link required).  This adjustment is done in
-            bfd/elf32-hppa.c:elf32_hppa_relocate_section.
-
-            We also slam a zero addend into the DLT relative relocs;
-            it doesn't make a lot of sense to use any addend since
-            it gets you a different (eg unknown) DLT entry.  */
-         reloc->addend = 0;
-         break;
+         cmpltr = 1;
+       }
+      else if (strcmp (name, "<") == 0)
+       {
+         cmpltr = 2;
+       }
+      else if (strcmp (name, "<=") == 0)
+       {
+         cmpltr = 3;
+       }
+      else if (strcasecmp (name, "nuv") == 0)
+       {
+         cmpltr = 4;
+       }
+      else if (strcasecmp (name, "*=") == 0)
+       {
+         cmpltr = 5;
+       }
+      else if (strcasecmp (name, "*<") == 0)
+       {
+         cmpltr = 6;
+       }
+      else if (strcasecmp (name, "*<=") == 0)
+       {
+         cmpltr = 7;
+       }
+      else if (strcmp (name, "tr") == 0)
+       {
+         cmpltr = 8;
+       }
+      else if (strcmp (name, "<>") == 0)
+       {
+         cmpltr = 9;
+       }
+      else if (strcmp (name, ">=") == 0)
+       {
+         cmpltr = 10;
+       }
+      else if (strcmp (name, ">") == 0)
+       {
+         cmpltr = 11;
+       }
+      else if (strcasecmp (name, "uv") == 0)
+       {
+         cmpltr = 12;
+       }
+      else if (strcasecmp (name, "*<>") == 0)
+       {
+         cmpltr = 13;
+       }
+      else if (strcasecmp (name, "*>=") == 0)
+       {
+         cmpltr = 14;
+       }
+      else if (strcasecmp (name, "*>") == 0)
+       {
+         cmpltr = 15;
+       }
+      /* If we have something like addb,n then there is no condition
+         completer.  */
+      else if (strcasecmp (name, "n") == 0)
+       {
+         cmpltr = 0;
+         nullify = 1;
+       }
+      else
+       {
+         cmpltr = -1;
+       }
+      **s = c;
+    }
 
 
-#ifdef ELF_ARG_RELOC
-       case R_PARISC_PCREL17R:
-       case R_PARISC_PCREL17F:
-       case R_PARISC_PCREL17C:
-       case R_PARISC_DIR17R:
-       case R_PARISC_DIR17F:
-       case R_PARISC_PCREL21L:
-       case R_PARISC_DIR21L:
-         reloc->addend = HPPA_R_ADDEND (hppa_fixp->fx_arg_reloc,
-                                        fixp->fx_offset);
-         break;
-#endif
+  /* Reset pointers if this was really a ,n for a branch instruction.  */
+  if (nullify)
+    *s = save_s;
 
 
-       case R_PARISC_DIR32:
-         /* Facilitate hand-crafted unwind info.  */
-         if (strcmp (section->name, UNWIND_SECTION_NAME) == 0)
-           code = R_PARISC_SEGREL32;
-         /* Fall thru */
+  return cmpltr;
+}
 
 
-       default:
-         reloc->addend = fixp->fx_offset;
-         break;
-       }
+/* Do the real work for assembling a single instruction.  Store results
+   into the global "the_insn" variable.  */
 
 
-      reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
-      *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
-      reloc->howto = bfd_reloc_type_lookup (stdoutput,
-                                           (bfd_reloc_code_real_type) code);
-      reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+static void
+pa_ip (char *str)
+{
+  char *error_message = "";
+  char *s, c, *argstart, *name, *save_s;
+  const char *args;
+  int match = FALSE;
+  int comma = 0;
+  int cmpltr, nullif, flag, cond, num;
+  unsigned long opcode;
+  struct pa_opcode *insn;
 
 
-      assert (reloc->howto && (unsigned int) code == reloc->howto->type);
-      break;
-    }
-#else /* OBJ_SOM */
+#ifdef OBJ_SOM
+  /* We must have a valid space and subspace.  */
+  pa_check_current_space_and_subspace ();
+#endif
 
 
-  /* Walk over reach relocation returned by the BFD backend.  */
-  for (i = 0; i < n_relocs; i++)
-    {
-      code = *codes[i];
+  /* Convert everything up to the first whitespace character into lower
+     case.  */
+  for (s = str; *s != ' ' && *s != '\t' && *s != '\n' && *s != '\0'; s++)
+    *s = TOLOWER (*s);
 
 
-      relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
-      *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
-      relocs[i]->howto =
-       bfd_reloc_type_lookup (stdoutput,
-                              (bfd_reloc_code_real_type) code);
-      relocs[i]->address = fixp->fx_frag->fr_address + fixp->fx_where;
+  /* Skip to something interesting.  */
+  for (s = str;
+       ISUPPER (*s) || ISLOWER (*s) || (*s >= '0' && *s <= '3');
+       ++s)
+    ;
 
 
-      switch (code)
-       {
-       case R_COMP2:
-         /* The only time we ever use a R_COMP2 fixup is for the difference
-            of two symbols.  With that in mind we fill in all four
-            relocs now and break out of the loop.  */
-         assert (i == 1);
-         relocs[0]->sym_ptr_ptr = (asymbol **) &(bfd_abs_symbol);
-         relocs[0]->howto =
-           bfd_reloc_type_lookup (stdoutput,
-                                  (bfd_reloc_code_real_type) *codes[0]);
-         relocs[0]->address = fixp->fx_frag->fr_address + fixp->fx_where;
-         relocs[0]->addend = 0;
-         relocs[1]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
-         *relocs[1]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
-         relocs[1]->howto =
-           bfd_reloc_type_lookup (stdoutput,
-                                  (bfd_reloc_code_real_type) *codes[1]);
-         relocs[1]->address = fixp->fx_frag->fr_address + fixp->fx_where;
-         relocs[1]->addend = 0;
-         relocs[2]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
-         *relocs[2]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
-         relocs[2]->howto =
-           bfd_reloc_type_lookup (stdoutput,
-                                  (bfd_reloc_code_real_type) *codes[2]);
-         relocs[2]->address = fixp->fx_frag->fr_address + fixp->fx_where;
-         relocs[2]->addend = 0;
-         relocs[3]->sym_ptr_ptr = (asymbol **) &(bfd_abs_symbol);
-         relocs[3]->howto =
-           bfd_reloc_type_lookup (stdoutput,
-                                  (bfd_reloc_code_real_type) *codes[3]);
-         relocs[3]->address = fixp->fx_frag->fr_address + fixp->fx_where;
-         relocs[3]->addend = 0;
-         relocs[4]->sym_ptr_ptr = (asymbol **) &(bfd_abs_symbol);
-         relocs[4]->howto =
-           bfd_reloc_type_lookup (stdoutput,
-                                  (bfd_reloc_code_real_type) *codes[4]);
-         relocs[4]->address = fixp->fx_frag->fr_address + fixp->fx_where;
-         relocs[4]->addend = 0;
-         goto done;
-       case R_PCREL_CALL:
-       case R_ABS_CALL:
-         relocs[i]->addend = HPPA_R_ADDEND (hppa_fixp->fx_arg_reloc, 0);
-         break;
+  switch (*s)
+    {
 
 
-       case R_DLT_REL:
-       case R_DATA_PLABEL:
-       case R_CODE_PLABEL:
-         /* For plabel relocations, the addend of the
-            relocation should be either 0 (no static link) or 2
-            (static link required).
+    case '\0':
+      break;
 
 
-            FIXME: We always assume no static link!
+    case ',':
+      comma = 1;
 
 
-            We also slam a zero addend into the DLT relative relocs;
-            it doesn't make a lot of sense to use any addend since
-            it gets you a different (eg unknown) DLT entry.  */
-         relocs[i]->addend = 0;
-         break;
+      /*FALLTHROUGH */
 
 
-       case R_N_MODE:
-       case R_S_MODE:
-       case R_D_MODE:
-       case R_R_MODE:
-       case R_FSEL:
-       case R_LSEL:
-       case R_RSEL:
-       case R_BEGIN_BRTAB:
-       case R_END_BRTAB:
-       case R_BEGIN_TRY:
-       case R_N0SEL:
-       case R_N1SEL:
-         /* There is no symbol or addend associated with these fixups.  */
-         relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
-         *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
-         relocs[i]->addend = 0;
-         break;
+    case ' ':
+      *s++ = '\0';
+      break;
 
 
-       case R_END_TRY:
-       case R_ENTRY:
-       case R_EXIT:
-         /* There is no symbol associated with these fixups.  */
-         relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
-         *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
-         relocs[i]->addend = fixp->fx_offset;
-         break;
+    default:
+      as_bad (_("Unknown opcode: `%s'"), str);
+      return;
+    }
 
 
-       default:
-         relocs[i]->addend = fixp->fx_offset;
-       }
+  /* Look up the opcode in the has table.  */
+  if ((insn = (struct pa_opcode *) hash_find (op_hash, str)) == NULL)
+    {
+      as_bad ("Unknown opcode: `%s'", str);
+      return;
     }
 
     }
 
- done:
-#endif
+  if (comma)
+    *--s = ',';
 
 
-  return relocs;
-}
+  /* Mark the location where arguments for the instruction start, then
+     start processing them.  */
+  argstart = s;
+  for (;;)
+    {
+      /* Do some initialization.  */
+      opcode = insn->match;
+      strict = (insn->flags & FLAG_STRICT);
+      memset (&the_insn, 0, sizeof (the_insn));
 
 
-/* Process any machine dependent frag types.  */
+      the_insn.reloc = R_HPPA_NONE;
 
 
-void
-md_convert_frag (abfd, sec, fragP)
-     register bfd *abfd ATTRIBUTE_UNUSED;
-     register asection *sec ATTRIBUTE_UNUSED;
-     register fragS *fragP;
-{
-  unsigned int address;
+      if (insn->arch >= pa20
+         && bfd_get_mach (stdoutput) < insn->arch)
+       goto failed;
 
 
-  if (fragP->fr_type == rs_machine_dependent)
-    {
-      switch ((int) fragP->fr_subtype)
+      /* Build the opcode, checking as we go to make
+         sure that the operands match.  */
+      for (args = insn->args;; ++args)
        {
        {
-       case 0:
-         fragP->fr_type = rs_fill;
-         know (fragP->fr_var == 1);
-         know (fragP->fr_next);
-         address = fragP->fr_address + fragP->fr_fix;
-         if (address % fragP->fr_offset)
+         /* Absorb white space in instruction.  */
+         while (*s == ' ' || *s == '\t')
+           s++;
+
+         switch (*args)
            {
            {
-             fragP->fr_offset =
-               fragP->fr_next->fr_address
-               - fragP->fr_address
-               - fragP->fr_fix;
-           }
-         else
-           fragP->fr_offset = 0;
-         break;
-       }
-    }
-}
+           /* End of arguments.  */
+           case '\0':
+             if (*s == '\0')
+               match = TRUE;
+             break;
 
 
-/* Round up a section size to the appropriate boundary.  */
+           case '+':
+             if (*s == '+')
+               {
+                 ++s;
+                 continue;
+               }
+             if (*s == '-')
+               continue;
+             break;
 
 
-valueT
-md_section_align (segment, size)
-     asection *segment;
-     valueT size;
-{
-  int align = bfd_get_section_alignment (stdoutput, segment);
-  int align2 = (1 << align) - 1;
+           /* These must match exactly.  */
+           case '(':
+           case ')':
+           case ',':
+           case ' ':
+             if (*s++ == *args)
+               continue;
+             break;
 
 
-  return (size + align2) & ~align2;
-}
+           /* Handle a 5 bit register or control register field at 10.  */
+           case 'b':
+           case '^':
+             if (!pa_parse_number (&s, 0))
+               break;
+             num = pa_number;
+             CHECK_FIELD (num, 31, 0, 0);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
 
 
-/* Return the approximate size of a frag before relaxation has occurred.  */
-int
-md_estimate_size_before_relax (fragP, segment)
-     register fragS *fragP;
-     asection *segment ATTRIBUTE_UNUSED;
-{
-  int size;
+           /* Handle %sar or %cr11.  No bits get set, we just verify that it
+              is there.  */
+           case '!':
+             /* Skip whitespace before register.  */
+             while (*s == ' ' || *s == '\t')
+               s = s + 1;
 
 
-  size = 0;
+             if (!strncasecmp (s, "%sar", 4))
+               {
+                 s += 4;
+                 continue;
+               }
+             else if (!strncasecmp (s, "%cr11", 5))
+               {
+                 s += 5;
+                 continue;
+               }
+             break;
 
 
-  while ((fragP->fr_fix + size) % fragP->fr_offset)
-    size++;
+           /* Handle a 5 bit register field at 15.  */
+           case 'x':
+             if (!pa_parse_number (&s, 0))
+               break;
+             num = pa_number;
+             CHECK_FIELD (num, 31, 0, 0);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
 
 
-  return size;
-}
-\f
-#ifdef OBJ_ELF
-# ifdef WARN_COMMENTS
-const char *md_shortopts = "Vc";
-# else
-const char *md_shortopts = "V";
-# endif
-#else
-# ifdef WARN_COMMENTS
-const char *md_shortopts = "c";
-# else
-const char *md_shortopts = "";
-# endif
-#endif
+           /* Handle a 5 bit register field at 31.  */
+           case 't':
+             if (!pa_parse_number (&s, 0))
+               break;
+             num = pa_number;
+             CHECK_FIELD (num, 31, 0, 0);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
-struct option md_longopts[] = {
-#ifdef WARN_COMMENTS
-  {"warn-comment", no_argument, NULL, 'c'},
-#endif
-  {NULL, no_argument, NULL, 0}
-};
-size_t md_longopts_size = sizeof (md_longopts);
+           /* Handle a 5 bit register field at 10 and 15.  */
+           case 'a':
+             if (!pa_parse_number (&s, 0))
+               break;
+             num = pa_number;
+             CHECK_FIELD (num, 31, 0, 0);
+             opcode |= num << 16;
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
 
 
-int
-md_parse_option (c, arg)
-     int c ATTRIBUTE_UNUSED;
-     char *arg ATTRIBUTE_UNUSED;
-{
-  switch (c)
-    {
-    default:
-      return 0;
+           /* Handle a 5 bit field length at 31.  */
+           case 'T':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 32, 1, 0);
+             INSERT_FIELD_AND_CONTINUE (opcode, 32 - num, 0);
 
 
-#ifdef OBJ_ELF
-    case 'V':
-      print_version_id ();
-      break;
-#endif
-#ifdef WARN_COMMENTS
-    case 'c':
-      warn_comment = 1;
-      break;
-#endif
-    }
+           /* Handle a 5 bit immediate at 15.  */
+           case '5':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             /* When in strict mode, we want to just reject this
+                match instead of giving an out of range error.  */
+             CHECK_FIELD (num, 15, -16, strict);
+             num = low_sign_unext (num, 5);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
 
 
-  return 1;
-}
+           /* Handle a 5 bit immediate at 31.  */
+           case 'V':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             /* When in strict mode, we want to just reject this
+                match instead of giving an out of range error.  */
+             CHECK_FIELD (num, 15, -16, strict);
+             num = low_sign_unext (num, 5);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
-void
-md_show_usage (stream)
-     FILE *stream ATTRIBUTE_UNUSED;
-{
-#ifdef OBJ_ELF
-  fprintf (stream, _("\
-  -Q                      ignored\n"));
-#endif
-#ifdef WARN_COMMENTS
-  fprintf (stream, _("\
-  -c                      print a warning if a comment is found\n"));
-#endif
-}
-\f
-/* We have no need to default values of symbols.  */
+           /* Handle an unsigned 5 bit immediate at 31.  */
+           case 'r':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 31, 0, strict);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
-symbolS *
-md_undefined_symbol (name)
-     char *name ATTRIBUTE_UNUSED;
-{
-  return 0;
-}
+           /* Handle an unsigned 5 bit immediate at 15.  */
+           case 'R':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 31, 0, strict);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
 
 
-#if defined (OBJ_SOM) || defined (ELF_ARG_RELOC)
-#define nonzero_dibits(x) \
-  ((x) | (((x) & 0x55555555) << 1) | (((x) & 0xAAAAAAAA) >> 1))
-#define arg_reloc_stub_needed(CALLER, CALLEE) \
-  (((CALLER) ^ (CALLEE)) & nonzero_dibits (CALLER) & nonzero_dibits (CALLEE))
-#else
-#define arg_reloc_stub_needed(CALLER, CALLEE) 0
-#endif
+           /* Handle an unsigned 10 bit immediate at 15.  */
+           case 'U':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 1023, 0, strict);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
 
 
-/* Apply a fixup to an instruction.  */
+           /* Handle a 2 bit space identifier at 17.  */
+           case 's':
+             if (!pa_parse_number (&s, 0))
+               break;
+             num = pa_number;
+             CHECK_FIELD (num, 3, 0, 1);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 14);
 
 
-void
-md_apply_fix (fixP, valP, seg)
-     fixS *fixP;
-     valueT *valP;
-     segT seg ATTRIBUTE_UNUSED;
-{
-  char *fixpos;
-  struct hppa_fix_struct *hppa_fixP;
-  offsetT new_val;
-  int insn, val, fmt;
+           /* Handle a 3 bit space identifier at 18.  */
+           case 'S':
+             if (!pa_parse_number (&s, 0))
+               break;
+             num = pa_number;
+             CHECK_FIELD (num, 7, 0, 1);
+             opcode |= re_assemble_3 (num);
+             continue;
 
 
-  /* SOM uses R_HPPA_ENTRY and R_HPPA_EXIT relocations which can
-     never be "applied" (they are just markers).  Likewise for
-     R_HPPA_BEGIN_BRTAB and R_HPPA_END_BRTAB.  */
-#ifdef OBJ_SOM
-  if (fixP->fx_r_type == R_HPPA_ENTRY
-      || fixP->fx_r_type == R_HPPA_EXIT
-      || fixP->fx_r_type == R_HPPA_BEGIN_BRTAB
-      || fixP->fx_r_type == R_HPPA_END_BRTAB
-      || fixP->fx_r_type == R_HPPA_BEGIN_TRY)
-    return;
-
-  /* Disgusting.  We must set fx_offset ourselves -- R_HPPA_END_TRY
-     fixups are considered not adjustable, which in turn causes
-     adjust_reloc_syms to not set fx_offset.  Ugh.  */
-  if (fixP->fx_r_type == R_HPPA_END_TRY)
-    {
-      fixP->fx_offset = * valP;
-      return;
-    }
-#endif
-#ifdef OBJ_ELF
-  if (fixP->fx_r_type == (int) R_PARISC_GNU_VTENTRY
-      || fixP->fx_r_type == (int) R_PARISC_GNU_VTINHERIT)
-    return;
-#endif
+           /* Handle all completers.  */
+           case 'c':
+             switch (*++args)
+               {
 
 
-  if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
-    fixP->fx_done = 1;
+               /* Handle a completer for an indexing load or store.  */
+               case 'X':
+               case 'x':
+                 {
+                   int uu = 0;
+                   int m = 0;
+                   int i = 0;
+                   while (*s == ',' && i < 2)
+                     {
+                       s++;
+                       if (strncasecmp (s, "sm", 2) == 0)
+                         {
+                           uu = 1;
+                           m = 1;
+                           s++;
+                           i++;
+                         }
+                       else if (strncasecmp (s, "m", 1) == 0)
+                         m = 1;
+                       else if ((strncasecmp (s, "s ", 2) == 0)
+                                || (strncasecmp (s, "s,", 2) == 0))
+                         uu = 1;
+                       else if (strict)
+                         {
+                           /* This is a match failure.  */
+                           s--;
+                           break;
+                         }
+                       else
+                         as_bad (_("Invalid Indexed Load Completer."));
+                       s++;
+                       i++;
+                     }
+                   if (i > 2)
+                     as_bad (_("Invalid Indexed Load Completer Syntax."));
+                   opcode |= m << 5;
+                   INSERT_FIELD_AND_CONTINUE (opcode, uu, 13);
+                 }
 
 
-  /* There should be a HPPA specific fixup associated with the GAS fixup.  */
-  hppa_fixP = (struct hppa_fix_struct *) fixP->tc_fix_data;
-  if (hppa_fixP == NULL)
-    {
-      as_bad_where (fixP->fx_file, fixP->fx_line,
-                   _("no hppa_fixup entry for fixup type 0x%x"),
-                   fixP->fx_r_type);
-      return;
-    }
+               /* Handle a short load/store completer.  */
+               case 'M':
+               case 'm':
+               case 'q':
+               case 'J':
+               case 'e':
+                 {
+                   int a = 0;
+                   int m = 0;
+                   if (*s == ',')
+                     {
+                       s++;
+                       if (strncasecmp (s, "ma", 2) == 0)
+                         {
+                           a = 0;
+                           m = 1;
+                           s += 2;
+                         }
+                       else if (strncasecmp (s, "mb", 2) == 0)
+                         {
+                           a = 1;
+                           m = 1;
+                           s += 2;
+                         }
+                       else if (strict)
+                         /* This is a match failure.  */
+                         s--;
+                       else
+                         {
+                           as_bad (_("Invalid Short Load/Store Completer."));
+                           s += 2;
+                         }
+                     }
+                   /* If we did not get a ma/mb completer, then we do not
+                      consider this a positive match for 'ce'.  */
+                   else if (*args == 'e')
+                     break;
 
 
-  fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
+                  /* 'J', 'm', 'M' and 'q' are the same, except for where they
+                      encode the before/after field.  */
+                  if (*args == 'm' || *args == 'M')
+                     {
+                       opcode |= m << 5;
+                       INSERT_FIELD_AND_CONTINUE (opcode, a, 13);
+                     }
+                   else if (*args == 'q')
+                     {
+                       opcode |= m << 3;
+                       INSERT_FIELD_AND_CONTINUE (opcode, a, 2);
+                     }
+                   else if (*args == 'J')
+                     {
+                       /* M bit is explicit in the major opcode.  */
+                       INSERT_FIELD_AND_CONTINUE (opcode, a, 2);
+                     }
+                   else if (*args == 'e')
+                     {
+                       /* Stash the ma/mb flag temporarily in the
+                          instruction.  We will use (and remove it)
+                          later when handling 'J', 'K', '<' & '>'.  */
+                       opcode |= a;
+                       continue;
+                     }
+                 }
 
 
-  if (fixP->fx_size != 4 || hppa_fixP->fx_r_format == 32)
-    {
-      /* Handle constant output. */
-      number_to_chars_bigendian (fixpos, *valP, fixP->fx_size);
-      return;
-    }
+               /* Handle a stbys completer.  */
+               case 'A':
+               case 's':
+                 {
+                   int a = 0;
+                   int m = 0;
+                   int i = 0;
+                   while (*s == ',' && i < 2)
+                     {
+                       s++;
+                       if (strncasecmp (s, "m", 1) == 0)
+                         m = 1;
+                       else if ((strncasecmp (s, "b ", 2) == 0)
+                                || (strncasecmp (s, "b,", 2) == 0))
+                         a = 0;
+                       else if (strncasecmp (s, "e", 1) == 0)
+                         a = 1;
+                       /* In strict mode, this is a match failure.  */
+                       else if (strict)
+                         {
+                           s--;
+                           break;
+                         }
+                       else
+                         as_bad (_("Invalid Store Bytes Short Completer"));
+                       s++;
+                       i++;
+                     }
+                   if (i > 2)
+                     as_bad (_("Invalid Store Bytes Short Completer"));
+                   opcode |= m << 5;
+                   INSERT_FIELD_AND_CONTINUE (opcode, a, 13);
+                 }
 
 
-  insn = bfd_get_32 (stdoutput, fixpos);
-  fmt = bfd_hppa_insn2fmt (stdoutput, insn);
+               /* Handle load cache hint completer.  */
+               case 'c':
+                 cmpltr = 0;
+                 if (!strncmp (s, ",sl", 3))
+                   {
+                     s += 3;
+                     cmpltr = 2;
+                   }
+                 INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 10);
 
 
-  /* If there is a symbol associated with this fixup, then it's something
-     which will need a SOM relocation (except for some PC-relative relocs).
-     In such cases we should treat the "val" or "addend" as zero since it
-     will be added in as needed from fx_offset in tc_gen_reloc.  */
-  if ((fixP->fx_addsy != NULL
-       || fixP->fx_r_type == (int) R_HPPA_NONE)
-#ifdef OBJ_SOM
-      && fmt != 32
-#endif
-      )
-    new_val = ((fmt == 12 || fmt == 17 || fmt == 22) ? 8 : 0);
-#ifdef OBJ_SOM
-  /* These field selectors imply that we do not want an addend.  */
-  else if (hppa_fixP->fx_r_field == e_psel
-          || hppa_fixP->fx_r_field == e_rpsel
-          || hppa_fixP->fx_r_field == e_lpsel
-          || hppa_fixP->fx_r_field == e_tsel
-          || hppa_fixP->fx_r_field == e_rtsel
-          || hppa_fixP->fx_r_field == e_ltsel)
-    new_val = ((fmt == 12 || fmt == 17 || fmt == 22) ? 8 : 0);
-#endif
-  else
-    new_val = hppa_field_adjust (* valP, 0, hppa_fixP->fx_r_field);
+               /* Handle store cache hint completer.  */
+               case 'C':
+                 cmpltr = 0;
+                 if (!strncmp (s, ",sl", 3))
+                   {
+                     s += 3;
+                     cmpltr = 2;
+                   }
+                 else if (!strncmp (s, ",bc", 3))
+                   {
+                     s += 3;
+                     cmpltr = 1;
+                   }
+                 INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 10);
 
 
-  /* Handle pc-relative exceptions from above.  */
-  if ((fmt == 12 || fmt == 17 || fmt == 22)
-      && fixP->fx_addsy
-      && fixP->fx_pcrel
-      && !arg_reloc_stub_needed (symbol_arg_reloc_info (fixP->fx_addsy),
-                                hppa_fixP->fx_arg_reloc)
-#ifdef OBJ_ELF
-      && (* valP - 8 + 8192 < 16384
-         || (fmt == 17 && * valP - 8 + 262144 < 524288)
-         || (fmt == 22 && * valP - 8 + 8388608 < 16777216))
-#endif
-#ifdef OBJ_SOM
-      && (* valP - 8 + 262144 < 524288
-         || (fmt == 22 && * valP - 8 + 8388608 < 16777216))
-#endif
-      && !S_IS_EXTERNAL (fixP->fx_addsy)
-      && !S_IS_WEAK (fixP->fx_addsy)
-      && S_GET_SEGMENT (fixP->fx_addsy) == hppa_fixP->segment
-      && !(fixP->fx_subsy
-          && S_GET_SEGMENT (fixP->fx_subsy) != hppa_fixP->segment))
-    {
-      new_val = hppa_field_adjust (* valP, 0, hppa_fixP->fx_r_field);
-    }
+               /* Handle load and clear cache hint completer.  */
+               case 'd':
+                 cmpltr = 0;
+                 if (!strncmp (s, ",co", 3))
+                   {
+                     s += 3;
+                     cmpltr = 1;
+                   }
+                 INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 10);
 
 
-  switch (fmt)
-    {
-    case 10:
-      CHECK_FIELD_WHERE (new_val, 8191, -8192,
-                        fixP->fx_file, fixP->fx_line);
-      val = new_val;
-
-      insn = (insn & ~ 0x3ff1) | (((val & 0x1ff8) << 1)
-                                 | ((val & 0x2000) >> 13));
-      break;
-    case -11:
-      CHECK_FIELD_WHERE (new_val, 8191, -8192,
-                        fixP->fx_file, fixP->fx_line);
-      val = new_val;
+               /* Handle load ordering completer.  */
+               case 'o':
+                 if (strncmp (s, ",o", 2) != 0)
+                   break;
+                 s += 2;
+                 continue;
 
 
-      insn = (insn & ~ 0x3ff9) | (((val & 0x1ffc) << 1)
-                                 | ((val & 0x2000) >> 13));
-      break;
-      /* Handle all opcodes with the 'j' operand type.  */
-    case 14:
-      CHECK_FIELD_WHERE (new_val, 8191, -8192,
-                        fixP->fx_file, fixP->fx_line);
-      val = new_val;
+               /* Handle a branch gate completer.  */
+               case 'g':
+                 if (strncasecmp (s, ",gate", 5) != 0)
+                   break;
+                 s += 5;
+                 continue;
 
 
-      insn = ((insn & ~ 0x3fff) | low_sign_unext (val, 14));
-      break;
+               /* Handle a branch link and push completer.  */
+               case 'p':
+                 if (strncasecmp (s, ",l,push", 7) != 0)
+                   break;
+                 s += 7;
+                 continue;
 
 
-      /* Handle all opcodes with the 'k' operand type.  */
-    case 21:
-      CHECK_FIELD_WHERE (new_val, 1048575, -1048576,
-                        fixP->fx_file, fixP->fx_line);
-      val = new_val;
+               /* Handle a branch link completer.  */
+               case 'l':
+                 if (strncasecmp (s, ",l", 2) != 0)
+                   break;
+                 s += 2;
+                 continue;
 
 
-      insn = (insn & ~ 0x1fffff) | re_assemble_21 (val);
-      break;
+               /* Handle a branch pop completer.  */
+               case 'P':
+                 if (strncasecmp (s, ",pop", 4) != 0)
+                   break;
+                 s += 4;
+                 continue;
 
 
-      /* Handle all the opcodes with the 'i' operand type.  */
-    case 11:
-      CHECK_FIELD_WHERE (new_val, 1023, -1024,
-                        fixP->fx_file, fixP->fx_line);
-      val = new_val;
+               /* Handle a local processor completer.  */
+               case 'L':
+                 if (strncasecmp (s, ",l", 2) != 0)
+                   break;
+                 s += 2;
+                 continue;
 
 
-      insn = (insn & ~ 0x7ff) | low_sign_unext (val, 11);
-      break;
+               /* Handle a PROBE read/write completer.  */
+               case 'w':
+                 flag = 0;
+                 if (!strncasecmp (s, ",w", 2))
+                   {
+                     flag = 1;
+                     s += 2;
+                   }
+                 else if (!strncasecmp (s, ",r", 2))
+                   {
+                     flag = 0;
+                     s += 2;
+                   }
 
 
-      /* Handle all the opcodes with the 'w' operand type.  */
-    case 12:
-      CHECK_FIELD_WHERE (new_val - 8, 8191, -8192,
-                        fixP->fx_file, fixP->fx_line);
-      val = new_val - 8;
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
 
 
-      insn = (insn & ~ 0x1ffd) | re_assemble_12 (val >> 2);
-      break;
+               /* Handle MFCTL wide completer.  */
+               case 'W':
+                 if (strncasecmp (s, ",w", 2) != 0)
+                   break;
+                 s += 2;
+                 continue;
 
 
-      /* Handle some of the opcodes with the 'W' operand type.  */
-    case 17:
-      {
-       offsetT distance = * valP;
+               /* Handle an RFI restore completer.  */
+               case 'r':
+                 flag = 0;
+                 if (!strncasecmp (s, ",r", 2))
+                   {
+                     flag = 5;
+                     s += 2;
+                   }
 
 
-       /* If this is an absolute branch (ie no link) with an out of
-          range target, then we want to complain.  */
-       if (fixP->fx_r_type == (int) R_HPPA_PCREL_CALL
-           && (insn & 0xffe00000) == 0xe8000000)
-         CHECK_FIELD_WHERE (distance - 8, 262143, -262144,
-                            fixP->fx_file, fixP->fx_line);
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 5);
 
 
-       CHECK_FIELD_WHERE (new_val - 8, 262143, -262144,
-                          fixP->fx_file, fixP->fx_line);
-       val = new_val - 8;
+               /* Handle a system control completer.  */
+               case 'Z':
+                 if (*s == ',' && (*(s + 1) == 'm' || *(s + 1) == 'M'))
+                   {
+                     flag = 1;
+                     s += 2;
+                   }
+                 else
+                   flag = 0;
 
 
-       insn = (insn & ~ 0x1f1ffd) | re_assemble_17 (val >> 2);
-       break;
-      }
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 5);
 
 
-    case 22:
-      {
-       offsetT distance = * valP;
+               /* Handle intermediate/final completer for DCOR.  */
+               case 'i':
+                 flag = 0;
+                 if (!strncasecmp (s, ",i", 2))
+                   {
+                     flag = 1;
+                     s += 2;
+                   }
 
 
-       /* If this is an absolute branch (ie no link) with an out of
-          range target, then we want to complain.  */
-       if (fixP->fx_r_type == (int) R_HPPA_PCREL_CALL
-           && (insn & 0xffe00000) == 0xe8000000)
-         CHECK_FIELD_WHERE (distance - 8, 8388607, -8388608,
-                            fixP->fx_file, fixP->fx_line);
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
 
 
-       CHECK_FIELD_WHERE (new_val - 8, 8388607, -8388608,
-                          fixP->fx_file, fixP->fx_line);
-       val = new_val - 8;
+               /* Handle zero/sign extension completer.  */
+               case 'z':
+                 flag = 1;
+                 if (!strncasecmp (s, ",z", 2))
+                   {
+                     flag = 0;
+                     s += 2;
+                   }
 
 
-       insn = (insn & ~ 0x3ff1ffd) | re_assemble_22 (val >> 2);
-       break;
-      }
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 10);
 
 
-    case -10:
-      val = new_val;
-      insn = (insn & ~ 0xfff1) | re_assemble_16 (val & -8);
-      break;
+               /* Handle add completer.  */
+               case 'a':
+                 flag = 1;
+                 if (!strncasecmp (s, ",l", 2))
+                   {
+                     flag = 2;
+                     s += 2;
+                   }
+                 else if (!strncasecmp (s, ",tsv", 4))
+                   {
+                     flag = 3;
+                     s += 4;
+                   }
 
 
-    case -16:
-      val = new_val;
-      insn = (insn & ~ 0xfff9) | re_assemble_16 (val & -4);
-      break;
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 10);
 
 
-    case 16:
-      val = new_val;
-      insn = (insn & ~ 0xffff) | re_assemble_16 (val);
-      break;
+               /* Handle 64 bit carry for ADD.  */
+               case 'Y':
+                 flag = 0;
+                 if (!strncasecmp (s, ",dc,tsv", 7) ||
+                     !strncasecmp (s, ",tsv,dc", 7))
+                   {
+                     flag = 1;
+                     s += 7;
+                   }
+                 else if (!strncasecmp (s, ",dc", 3))
+                   {
+                     flag = 0;
+                     s += 3;
+                   }
+                 else
+                   break;
 
 
-    case 32:
-      insn = new_val;
-      break;
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
 
 
-    default:
-      as_bad_where (fixP->fx_file, fixP->fx_line,
-                   _("Unknown relocation encountered in md_apply_fix."));
-      return;
-    }
+               /* Handle 32 bit carry for ADD.  */
+               case 'y':
+                 flag = 0;
+                 if (!strncasecmp (s, ",c,tsv", 6) ||
+                     !strncasecmp (s, ",tsv,c", 6))
+                   {
+                     flag = 1;
+                     s += 6;
+                   }
+                 else if (!strncasecmp (s, ",c", 2))
+                   {
+                     flag = 0;
+                     s += 2;
+                   }
+                 else
+                   break;
 
 
-  /* Insert the relocation.  */
-  bfd_put_32 (stdoutput, insn, fixpos);
-}
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
 
 
-/* Exactly what point is a PC-relative offset relative TO?
-   On the PA, they're relative to the address of the offset.  */
+               /* Handle trap on signed overflow.  */
+               case 'v':
+                 flag = 0;
+                 if (!strncasecmp (s, ",tsv", 4))
+                   {
+                     flag = 1;
+                     s += 4;
+                   }
 
 
-long
-md_pcrel_from (fixP)
-     fixS *fixP;
-{
-  return fixP->fx_where + fixP->fx_frag->fr_address;
-}
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
 
 
-/* Return nonzero if the input line pointer is at the end of
-   a statement.  */
+               /* Handle trap on condition and overflow.  */
+               case 't':
+                 flag = 0;
+                 if (!strncasecmp (s, ",tc,tsv", 7) ||
+                     !strncasecmp (s, ",tsv,tc", 7))
+                   {
+                     flag = 1;
+                     s += 7;
+                   }
+                 else if (!strncasecmp (s, ",tc", 3))
+                   {
+                     flag = 0;
+                     s += 3;
+                   }
+                 else
+                   break;
 
 
-static int
-is_end_of_statement ()
-{
-  return ((*input_line_pointer == '\n')
-         || (*input_line_pointer == ';')
-         || (*input_line_pointer == '!'));
-}
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
 
 
-/* Read a number from S.  The number might come in one of many forms,
-   the most common will be a hex or decimal constant, but it could be
-   a pre-defined register (Yuk!), or an absolute symbol.
+               /* Handle 64 bit borrow for SUB.  */
+               case 'B':
+                 flag = 0;
+                 if (!strncasecmp (s, ",db,tsv", 7) ||
+                     !strncasecmp (s, ",tsv,db", 7))
+                   {
+                     flag = 1;
+                     s += 7;
+                   }
+                 else if (!strncasecmp (s, ",db", 3))
+                   {
+                     flag = 0;
+                     s += 3;
+                   }
+                 else
+                   break;
 
 
-   Return 1 on success or 0 on failure.  If STRICT, then a missing
-   register prefix will cause a failure.  The number itself is
-   returned in `pa_number'.
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
 
 
-   IS_FLOAT indicates that a PA-89 FP register number should be
-   parsed;  A `l' or `r' suffix is checked for if but 2 of IS_FLOAT is
-   not set.
+               /* Handle 32 bit borrow for SUB.  */
+               case 'b':
+                 flag = 0;
+                 if (!strncasecmp (s, ",b,tsv", 6) ||
+                     !strncasecmp (s, ",tsv,b", 6))
+                   {
+                     flag = 1;
+                     s += 6;
+                   }
+                 else if (!strncasecmp (s, ",b", 2))
+                   {
+                     flag = 0;
+                     s += 2;
+                   }
+                 else
+                   break;
 
 
-   pa_parse_number can not handle negative constants and will fail
-   horribly if it is passed such a constant.  */
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
 
 
-static int
-pa_parse_number (s, is_float)
-     char **s;
-     int is_float;
-{
-  int num;
-  char *name;
-  char c;
-  symbolS *sym;
-  int status;
-  char *p = *s;
-  bfd_boolean have_prefix;
+               /* Handle trap condition completer for UADDCM.  */
+               case 'T':
+                 flag = 0;
+                 if (!strncasecmp (s, ",tc", 3))
+                   {
+                     flag = 1;
+                     s += 3;
+                   }
 
 
-  /* Skip whitespace before the number.  */
-  while (*p == ' ' || *p == '\t')
-    p = p + 1;
+                 INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
 
 
-  pa_number = -1;
-  have_prefix = 0;
-  num = 0;
-  if (!strict && ISDIGIT (*p))
-    {
-      /* Looks like a number.  */
+               /* Handle signed/unsigned at 21.  */
+               case 'S':
+                 {
+                   int sign = 1;
+                   if (strncasecmp (s, ",s", 2) == 0)
+                     {
+                       sign = 1;
+                       s += 2;
+                     }
+                   else if (strncasecmp (s, ",u", 2) == 0)
+                     {
+                       sign = 0;
+                       s += 2;
+                     }
 
 
-      if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X'))
-       {
-         /* The number is specified in hex.  */
-         p += 2;
-         while (ISDIGIT (*p) || ((*p >= 'a') && (*p <= 'f'))
-                || ((*p >= 'A') && (*p <= 'F')))
-           {
-             if (ISDIGIT (*p))
-               num = num * 16 + *p - '0';
-             else if (*p >= 'a' && *p <= 'f')
-               num = num * 16 + *p - 'a' + 10;
-             else
-               num = num * 16 + *p - 'A' + 10;
-             ++p;
-           }
-       }
-      else
-       {
-         /* The number is specified in decimal.  */
-         while (ISDIGIT (*p))
-           {
-             num = num * 10 + *p - '0';
-             ++p;
-           }
-       }
+                   INSERT_FIELD_AND_CONTINUE (opcode, sign, 10);
+                 }
 
 
-      pa_number = num;
+               /* Handle left/right combination at 17:18.  */
+               case 'h':
+                 if (*s++ == ',')
+                   {
+                     int lr = 0;
+                     if (*s == 'r')
+                       lr = 2;
+                     else if (*s == 'l')
+                       lr = 0;
+                     else
+                       as_bad (_("Invalid left/right combination completer"));
 
 
-      /* Check for a `l' or `r' suffix.  */
-      if (is_float)
-       {
-         pa_number += FP_REG_BASE;
-         if (! (is_float & 2))
-           {
-             if (IS_R_SELECT (p))
-               {
-                 pa_number += FP_REG_RSEL;
-                 ++p;
-               }
-             else if (IS_L_SELECT (p))
-               {
-                 ++p;
+                     s++;
+                     INSERT_FIELD_AND_CONTINUE (opcode, lr, 13);
+                   }
+                 else
+                   as_bad (_("Invalid left/right combination completer"));
+                 break;
+
+               /* Handle saturation at 24:25.  */
+               case 'H':
+                 {
+                   int sat = 3;
+                   if (strncasecmp (s, ",ss", 3) == 0)
+                     {
+                       sat = 1;
+                       s += 3;
+                     }
+                   else if (strncasecmp (s, ",us", 3) == 0)
+                     {
+                       sat = 0;
+                       s += 3;
+                     }
+
+                   INSERT_FIELD_AND_CONTINUE (opcode, sat, 6);
+                 }
+
+               /* Handle permutation completer.  */
+               case '*':
+                 if (*s++ == ',')
+                   {
+                     int permloc[4];
+                     int perm = 0;
+                     int i = 0;
+                     permloc[0] = 13;
+                     permloc[1] = 10;
+                     permloc[2] = 8;
+                     permloc[3] = 6;
+                     for (; i < 4; i++)
+                       {
+                         switch (*s++)
+                           {
+                           case '0':
+                             perm = 0;
+                             break;
+                           case '1':
+                             perm = 1;
+                             break;
+                           case '2':
+                             perm = 2;
+                             break;
+                           case '3':
+                             perm = 3;
+                             break;
+                           default:
+                             as_bad (_("Invalid permutation completer"));
+                           }
+                         opcode |= perm << permloc[i];
+                       }
+                     continue;
+                   }
+                 else
+                   as_bad (_("Invalid permutation completer"));
+                 break;
+
+               default:
+                 abort ();
                }
                }
-           }
-       }
-    }
-  else if (*p == '%')
-    {
-      /* The number might be a predefined register.  */
-      have_prefix = 1;
-      name = p;
-      p++;
-      c = *p;
-      /* Tege hack: Special case for general registers as the general
-         code makes a binary search with case translation, and is VERY
-         slow.  */
-      if (c == 'r')
-       {
-         p++;
-         if (*p == 'e' && *(p + 1) == 't'
-             && (*(p + 2) == '0' || *(p + 2) == '1'))
-           {
-             p += 2;
-             num = *p - '0' + 28;
-             p++;
-           }
-         else if (*p == 'p')
-           {
-             num = 2;
-             p++;
-           }
-         else if (!ISDIGIT (*p))
-           {
-             if (print_errors)
-               as_bad (_("Undefined register: '%s'."), name);
-             num = -1;
-           }
-         else
-           {
-             do
-               num = num * 10 + *p++ - '0';
-             while (ISDIGIT (*p));
-           }
-       }
-      else
-       {
-         /* Do a normal register search.  */
-         while (is_part_of_name (c))
-           {
-             p = p + 1;
-             c = *p;
-           }
-         *p = 0;
-         status = reg_name_search (name);
-         if (status >= 0)
-           num = status;
-         else
-           {
-             if (print_errors)
-               as_bad (_("Undefined register: '%s'."), name);
-             num = -1;
-           }
-         *p = c;
-       }
+             break;
 
 
-      pa_number = num;
-    }
-  else
-    {
-      /* And finally, it could be a symbol in the absolute section which
-         is effectively a constant, or a register alias symbol.  */
-      name = p;
-      c = *p;
-      while (is_part_of_name (c))
-       {
-         p = p + 1;
-         c = *p;
-       }
-      *p = 0;
-      if ((sym = symbol_find (name)) != NULL)
-       {
-         if (S_GET_SEGMENT (sym) == reg_section)
-           {
-             num = S_GET_VALUE (sym);
-             /* Well, we don't really have one, but we do have a
-                register, so...  */
-             have_prefix = TRUE;
-           }
-         else if (S_GET_SEGMENT (sym) == &bfd_abs_section)
-           num = S_GET_VALUE (sym);
-         else if (!strict)
-           {
-             if (print_errors)
-               as_bad (_("Non-absolute symbol: '%s'."), name);
-             num = -1;
-           }
-       }
-      else if (!strict)
-       {
-         /* There is where we'd come for an undefined symbol
-            or for an empty string.  For an empty string we
-            will return zero.  That's a concession made for
-            compatibility with the braindamaged HP assemblers.  */
-         if (*name == 0)
-           num = 0;
-         else
-           {
-             if (print_errors)
-               as_bad (_("Undefined absolute constant: '%s'."), name);
-             num = -1;
-           }
-       }
-      *p = c;
+           /* Handle all conditions.  */
+           case '?':
+             {
+               args++;
+               switch (*args)
+                 {
+                 /* Handle FP compare conditions.  */
+                 case 'f':
+                   cond = pa_parse_fp_cmp_cond (&s);
+                   INSERT_FIELD_AND_CONTINUE (opcode, cond, 0);
 
 
-      pa_number = num;
-    }
+                 /* Handle an add condition.  */
+                 case 'A':
+                 case 'a':
+                   cmpltr = 0;
+                   flag = 0;
+                   if (*s == ',')
+                     {
+                       s++;
 
 
-  if (!strict || have_prefix)
-    {
-      *s = p;
-      return 1;
-    }
-  return 0;
-}
+                       /* 64 bit conditions.  */
+                       if (*args == 'A')
+                         {
+                           if (*s == '*')
+                             s++;
+                           else
+                             break;
+                         }
+                       else if (*s == '*')
+                         break;
 
 
-#define REG_NAME_CNT   (sizeof (pre_defined_registers) / sizeof (struct pd_reg))
+                       name = s;
+                       while (*s != ',' && *s != ' ' && *s != '\t')
+                         s += 1;
+                       c = *s;
+                       *s = 0x00;
+                       if (strcmp (name, "=") == 0)
+                         cmpltr = 1;
+                       else if (strcmp (name, "<") == 0)
+                         cmpltr = 2;
+                       else if (strcmp (name, "<=") == 0)
+                         cmpltr = 3;
+                       else if (strcasecmp (name, "nuv") == 0)
+                         cmpltr = 4;
+                       else if (strcasecmp (name, "znv") == 0)
+                         cmpltr = 5;
+                       else if (strcasecmp (name, "sv") == 0)
+                         cmpltr = 6;
+                       else if (strcasecmp (name, "od") == 0)
+                         cmpltr = 7;
+                       else if (strcasecmp (name, "tr") == 0)
+                         {
+                           cmpltr = 0;
+                           flag = 1;
+                         }
+                       else if (strcmp (name, "<>") == 0)
+                         {
+                           cmpltr = 1;
+                           flag = 1;
+                         }
+                       else if (strcmp (name, ">=") == 0)
+                         {
+                           cmpltr = 2;
+                           flag = 1;
+                         }
+                       else if (strcmp (name, ">") == 0)
+                         {
+                           cmpltr = 3;
+                           flag = 1;
+                         }
+                       else if (strcasecmp (name, "uv") == 0)
+                         {
+                           cmpltr = 4;
+                           flag = 1;
+                         }
+                       else if (strcasecmp (name, "vnz") == 0)
+                         {
+                           cmpltr = 5;
+                           flag = 1;
+                         }
+                       else if (strcasecmp (name, "nsv") == 0)
+                         {
+                           cmpltr = 6;
+                           flag = 1;
+                         }
+                       else if (strcasecmp (name, "ev") == 0)
+                         {
+                           cmpltr = 7;
+                           flag = 1;
+                         }
+                       /* ",*" is a valid condition.  */
+                       else if (*args == 'a' || *name)
+                         as_bad (_("Invalid Add Condition: %s"), name);
+                       *s = c;
+                     }
+                   opcode |= cmpltr << 13;
+                   INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
 
 
-/* Given NAME, find the register number associated with that name, return
-   the integer value associated with the given name or -1 on failure.  */
+                 /* Handle non-negated add and branch condition.  */
+                 case 'd':
+                   cmpltr = pa_parse_nonneg_add_cmpltr (&s);
+                   if (cmpltr < 0)
+                     {
+                       as_bad (_("Invalid Add and Branch Condition"));
+                       cmpltr = 0;
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+
+                 /* Handle 64 bit wide-mode add and branch condition.  */
+                 case 'W':
+                   cmpltr = pa_parse_addb_64_cmpltr (&s);
+                   if (cmpltr < 0)
+                     {
+                       as_bad (_("Invalid Add and Branch Condition"));
+                       cmpltr = 0;
+                     }
+                   else
+                     {
+                       /* Negated condition requires an opcode change.  */
+                       opcode |= (cmpltr & 8) << 24;
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr & 7, 13);
+
+                 /* Handle a negated or non-negated add and branch
+                    condition.  */
+                 case '@':
+                   save_s = s;
+                   cmpltr = pa_parse_nonneg_add_cmpltr (&s);
+                   if (cmpltr < 0)
+                     {
+                       s = save_s;
+                       cmpltr = pa_parse_neg_add_cmpltr (&s);
+                       if (cmpltr < 0)
+                         {
+                           as_bad (_("Invalid Compare/Subtract Condition"));
+                           cmpltr = 0;
+                         }
+                       else
+                         {
+                           /* Negated condition requires an opcode change.  */
+                           opcode |= 1 << 27;
+                         }
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
 
 
-static int
-reg_name_search (name)
-     char *name;
-{
-  int middle, low, high;
-  int cmp;
+                 /* Handle branch on bit conditions.  */
+                 case 'B':
+                 case 'b':
+                   cmpltr = 0;
+                   if (*s == ',')
+                     {
+                       s++;
 
 
-  low = 0;
-  high = REG_NAME_CNT - 1;
+                       if (*args == 'B')
+                         {
+                           if (*s == '*')
+                             s++;
+                           else
+                             break;
+                         }
+                       else if (*s == '*')
+                         break;
 
 
-  do
-    {
-      middle = (low + high) / 2;
-      cmp = strcasecmp (name, pre_defined_registers[middle].name);
-      if (cmp < 0)
-       high = middle - 1;
-      else if (cmp > 0)
-       low = middle + 1;
-      else
-       return pre_defined_registers[middle].value;
-    }
-  while (low <= high);
+                       if (strncmp (s, "<", 1) == 0)
+                         {
+                           cmpltr = 0;
+                           s++;
+                         }
+                       else if (strncmp (s, ">=", 2) == 0)
+                         {
+                           cmpltr = 1;
+                           s += 2;
+                         }
+                       else
+                         as_bad (_("Invalid Bit Branch Condition: %c"), *s);
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 15);
 
 
-  return -1;
-}
+                 /* Handle a compare/subtract condition.  */
+                 case 'S':
+                 case 's':
+                   cmpltr = 0;
+                   flag = 0;
+                   if (*s == ',')
+                     {
+                       s++;
 
 
-/* Return nonzero if the given INSN and L/R information will require
-   a new PA-1.1 opcode.  */
+                       /* 64 bit conditions.  */
+                       if (*args == 'S')
+                         {
+                           if (*s == '*')
+                             s++;
+                           else
+                             break;
+                         }
+                       else if (*s == '*')
+                         break;
 
 
-static int
-need_pa11_opcode ()
-{
-  if ((pa_number & FP_REG_RSEL) != 0
-      && !(the_insn.fpof1 == DBL && the_insn.fpof2 == DBL))
-    {
-      /* If this instruction is specific to a particular architecture,
-        then set a new architecture.  */
-      if (bfd_get_mach (stdoutput) < pa11)
-       {
-         if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, pa11))
-           as_warn (_("could not update architecture and machine"));
-       }
-      return TRUE;
-    }
-  else
-    return FALSE;
-}
+                       name = s;
+                       while (*s != ',' && *s != ' ' && *s != '\t')
+                         s += 1;
+                       c = *s;
+                       *s = 0x00;
+                       if (strcmp (name, "=") == 0)
+                         cmpltr = 1;
+                       else if (strcmp (name, "<") == 0)
+                         cmpltr = 2;
+                       else if (strcmp (name, "<=") == 0)
+                         cmpltr = 3;
+                       else if (strcasecmp (name, "<<") == 0)
+                         cmpltr = 4;
+                       else if (strcasecmp (name, "<<=") == 0)
+                         cmpltr = 5;
+                       else if (strcasecmp (name, "sv") == 0)
+                         cmpltr = 6;
+                       else if (strcasecmp (name, "od") == 0)
+                         cmpltr = 7;
+                       else if (strcasecmp (name, "tr") == 0)
+                         {
+                           cmpltr = 0;
+                           flag = 1;
+                         }
+                       else if (strcmp (name, "<>") == 0)
+                         {
+                           cmpltr = 1;
+                           flag = 1;
+                         }
+                       else if (strcmp (name, ">=") == 0)
+                         {
+                           cmpltr = 2;
+                           flag = 1;
+                         }
+                       else if (strcmp (name, ">") == 0)
+                         {
+                           cmpltr = 3;
+                           flag = 1;
+                         }
+                       else if (strcasecmp (name, ">>=") == 0)
+                         {
+                           cmpltr = 4;
+                           flag = 1;
+                         }
+                       else if (strcasecmp (name, ">>") == 0)
+                         {
+                           cmpltr = 5;
+                           flag = 1;
+                         }
+                       else if (strcasecmp (name, "nsv") == 0)
+                         {
+                           cmpltr = 6;
+                           flag = 1;
+                         }
+                       else if (strcasecmp (name, "ev") == 0)
+                         {
+                           cmpltr = 7;
+                           flag = 1;
+                         }
+                       /* ",*" is a valid condition.  */
+                       else if (*args != 'S' || *name)
+                         as_bad (_("Invalid Compare/Subtract Condition: %s"),
+                                 name);
+                       *s = c;
+                     }
+                   opcode |= cmpltr << 13;
+                   INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
 
 
-/* Parse a condition for a fcmp instruction.  Return the numerical
-   code associated with the condition.  */
+                 /* Handle a non-negated compare condition.  */
+                 case 't':
+                   cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s);
+                   if (cmpltr < 0)
+                     {
+                       as_bad (_("Invalid Compare/Subtract Condition"));
+                       cmpltr = 0;
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
 
 
-static int
-pa_parse_fp_cmp_cond (s)
-     char **s;
-{
-  int cond, i;
+                 /* Handle a 32 bit compare and branch condition.  */
+                 case 'n':
+                   save_s = s;
+                   cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s);
+                   if (cmpltr < 0)
+                     {
+                       s = save_s;
+                       cmpltr = pa_parse_neg_cmpsub_cmpltr (&s);
+                       if (cmpltr < 0)
+                         {
+                           as_bad (_("Invalid Compare and Branch Condition"));
+                           cmpltr = 0;
+                         }
+                       else
+                         {
+                           /* Negated condition requires an opcode change.  */
+                           opcode |= 1 << 27;
+                         }
+                     }
 
 
-  cond = 0;
+                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
 
 
-  for (i = 0; i < 32; i++)
-    {
-      if (strncasecmp (*s, fp_cond_map[i].string,
-                      strlen (fp_cond_map[i].string)) == 0)
-       {
-         cond = fp_cond_map[i].cond;
-         *s += strlen (fp_cond_map[i].string);
-         /* If not a complete match, back up the input string and
-            report an error.  */
-         if (**s != ' ' && **s != '\t')
-           {
-             *s -= strlen (fp_cond_map[i].string);
-             break;
-           }
-         while (**s == ' ' || **s == '\t')
-           *s = *s + 1;
-         return cond;
-       }
-    }
+                 /* Handle a 64 bit compare and branch condition.  */
+                 case 'N':
+                   cmpltr = pa_parse_cmpb_64_cmpltr (&s);
+                   if (cmpltr >= 0)
+                     {
+                       /* Negated condition requires an opcode change.  */
+                       opcode |= (cmpltr & 8) << 26;
+                     }
+                   else
+                     /* Not a 64 bit cond.  Give 32 bit a chance.  */
+                     break;
 
 
-  as_bad (_("Invalid FP Compare Condition: %s"), *s);
+                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr & 7, 13);
 
 
-  /* Advance over the bogus completer.  */
-  while (**s != ',' && **s != ' ' && **s != '\t')
-    *s += 1;
+                 /* Handle a 64 bit cmpib condition.  */
+                 case 'Q':
+                   cmpltr = pa_parse_cmpib_64_cmpltr (&s);
+                   if (cmpltr < 0)
+                     /* Not a 64 bit cond.  Give 32 bit a chance.  */
+                     break;
 
 
-  return 0;
-}
+                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
 
 
-/* Parse a graphics test complete for ftest.  */
+                   /* Handle a logical instruction condition.  */
+                 case 'L':
+                 case 'l':
+                   cmpltr = 0;
+                   flag = 0;
+                   if (*s == ',')
+                     {
+                       s++;
 
 
-static int
-pa_parse_ftest_gfx_completer (s)
-     char **s;
-{
-  int value;
+                       /* 64 bit conditions.  */
+                       if (*args == 'L')
+                         {
+                           if (*s == '*')
+                             s++;
+                           else
+                             break;
+                         }
+                       else if (*s == '*')
+                         break;
 
 
-  value = 0;
-  if (strncasecmp (*s, "acc8", 4) == 0)
-    {
-      value = 5;
-      *s += 4;
-    }
-  else if (strncasecmp (*s, "acc6", 4) == 0)
-    {
-      value = 9;
-      *s += 4;
-    }
-  else if (strncasecmp (*s, "acc4", 4) == 0)
-    {
-      value = 13;
-      *s += 4;
-    }
-  else if (strncasecmp (*s, "acc2", 4) == 0)
-    {
-      value = 17;
-      *s += 4;
-    }
-  else if (strncasecmp (*s, "acc", 3) == 0)
-    {
-      value = 1;
-      *s += 3;
-    }
-  else if (strncasecmp (*s, "rej8", 4) == 0)
-    {
-      value = 6;
-      *s += 4;
-    }
-  else if (strncasecmp (*s, "rej", 3) == 0)
-    {
-      value = 2;
-      *s += 3;
-    }
-  else
-    {
-      value = 0;
-      as_bad (_("Invalid FTEST completer: %s"), *s);
-    }
+                       name = s;
+                       while (*s != ',' && *s != ' ' && *s != '\t')
+                         s += 1;
+                       c = *s;
+                       *s = 0x00;
 
 
-  return value;
-}
+                       if (strcmp (name, "=") == 0)
+                         cmpltr = 1;
+                       else if (strcmp (name, "<") == 0)
+                         cmpltr = 2;
+                       else if (strcmp (name, "<=") == 0)
+                         cmpltr = 3;
+                       else if (strcasecmp (name, "od") == 0)
+                         cmpltr = 7;
+                       else if (strcasecmp (name, "tr") == 0)
+                         {
+                           cmpltr = 0;
+                           flag = 1;
+                         }
+                       else if (strcmp (name, "<>") == 0)
+                         {
+                           cmpltr = 1;
+                           flag = 1;
+                         }
+                       else if (strcmp (name, ">=") == 0)
+                         {
+                           cmpltr = 2;
+                           flag = 1;
+                         }
+                       else if (strcmp (name, ">") == 0)
+                         {
+                           cmpltr = 3;
+                           flag = 1;
+                         }
+                       else if (strcasecmp (name, "ev") == 0)
+                         {
+                           cmpltr = 7;
+                           flag = 1;
+                         }
+                       /* ",*" is a valid condition.  */
+                       else if (*args != 'L' || *name)
+                         as_bad (_("Invalid Logical Instruction Condition."));
+                       *s = c;
+                     }
+                   opcode |= cmpltr << 13;
+                   INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
 
 
-/* Parse an FP operand format completer returning the completer
-   type.  */
+                 /* Handle a shift/extract/deposit condition.  */
+                 case 'X':
+                 case 'x':
+                 case 'y':
+                   cmpltr = 0;
+                   if (*s == ',')
+                     {
+                       save_s = s++;
 
 
-static fp_operand_format
-pa_parse_fp_cnv_format (s)
-     char **s;
-{
-  int format;
+                       /* 64 bit conditions.  */
+                       if (*args == 'X')
+                         {
+                           if (*s == '*')
+                             s++;
+                           else
+                             break;
+                         }
+                       else if (*s == '*')
+                         break;
 
 
-  format = SGL;
-  if (**s == ',')
-    {
-      *s += 1;
-      if (strncasecmp (*s, "sgl", 3) == 0)
-       {
-         format = SGL;
-         *s += 4;
-       }
-      else if (strncasecmp (*s, "dbl", 3) == 0)
-       {
-         format = DBL;
-         *s += 4;
-       }
-      else if (strncasecmp (*s, "quad", 4) == 0)
-       {
-         format = QUAD;
-         *s += 5;
-       }
-      else if (strncasecmp (*s, "w", 1) == 0)
-       {
-         format = W;
-         *s += 2;
-       }
-      else if (strncasecmp (*s, "uw", 2) == 0)
-       {
-         format = UW;
-         *s += 3;
-       }
-      else if (strncasecmp (*s, "dw", 2) == 0)
-       {
-         format = DW;
-         *s += 3;
-       }
-      else if (strncasecmp (*s, "udw", 3) == 0)
-       {
-         format = UDW;
-         *s += 4;
-       }
-      else if (strncasecmp (*s, "qw", 2) == 0)
-       {
-         format = QW;
-         *s += 3;
-       }
-      else if (strncasecmp (*s, "uqw", 3) == 0)
-       {
-         format = UQW;
-         *s += 4;
-       }
-      else
-       {
-         format = ILLEGAL_FMT;
-         as_bad (_("Invalid FP Operand Format: %3s"), *s);
-       }
-    }
+                       name = s;
+                       while (*s != ',' && *s != ' ' && *s != '\t')
+                         s += 1;
+                       c = *s;
+                       *s = 0x00;
+                       if (strcmp (name, "=") == 0)
+                         cmpltr = 1;
+                       else if (strcmp (name, "<") == 0)
+                         cmpltr = 2;
+                       else if (strcasecmp (name, "od") == 0)
+                         cmpltr = 3;
+                       else if (strcasecmp (name, "tr") == 0)
+                         cmpltr = 4;
+                       else if (strcmp (name, "<>") == 0)
+                         cmpltr = 5;
+                       else if (strcmp (name, ">=") == 0)
+                         cmpltr = 6;
+                       else if (strcasecmp (name, "ev") == 0)
+                         cmpltr = 7;
+                       /* Handle movb,n.  Put things back the way they were.
+                          This includes moving s back to where it started.  */
+                       else if (strcasecmp (name, "n") == 0 && *args == 'y')
+                         {
+                           *s = c;
+                           s = save_s;
+                           continue;
+                         }
+                       /* ",*" is a valid condition.  */
+                       else if (*args != 'X' || *name)
+                         as_bad (_("Invalid Shift/Extract/Deposit Condition."));
+                       *s = c;
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
 
 
-  return format;
-}
+                 /* Handle a unit instruction condition.  */
+                 case 'U':
+                 case 'u':
+                   cmpltr = 0;
+                   flag = 0;
+                   if (*s == ',')
+                     {
+                       s++;
 
 
-/* Parse an FP operand format completer returning the completer
-   type.  */
+                       /* 64 bit conditions.  */
+                       if (*args == 'U')
+                         {
+                           if (*s == '*')
+                             s++;
+                           else
+                             break;
+                         }
+                       else if (*s == '*')
+                         break;
 
 
-static fp_operand_format
-pa_parse_fp_format (s)
-     char **s;
-{
-  int format;
+                       if (strncasecmp (s, "sbz", 3) == 0)
+                         {
+                           cmpltr = 2;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "shz", 3) == 0)
+                         {
+                           cmpltr = 3;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "sdc", 3) == 0)
+                         {
+                           cmpltr = 4;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "sbc", 3) == 0)
+                         {
+                           cmpltr = 6;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "shc", 3) == 0)
+                         {
+                           cmpltr = 7;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "tr", 2) == 0)
+                         {
+                           cmpltr = 0;
+                           flag = 1;
+                           s += 2;
+                         }
+                       else if (strncasecmp (s, "nbz", 3) == 0)
+                         {
+                           cmpltr = 2;
+                           flag = 1;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "nhz", 3) == 0)
+                         {
+                           cmpltr = 3;
+                           flag = 1;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "ndc", 3) == 0)
+                         {
+                           cmpltr = 4;
+                           flag = 1;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "nbc", 3) == 0)
+                         {
+                           cmpltr = 6;
+                           flag = 1;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "nhc", 3) == 0)
+                         {
+                           cmpltr = 7;
+                           flag = 1;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "swz", 3) == 0)
+                         {
+                           cmpltr = 1;
+                           flag = 0;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "swc", 3) == 0)
+                         {
+                           cmpltr = 5;
+                           flag = 0;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "nwz", 3) == 0)
+                         {
+                           cmpltr = 1;
+                           flag = 1;
+                           s += 3;
+                         }
+                       else if (strncasecmp (s, "nwc", 3) == 0)
+                         {
+                           cmpltr = 5;
+                           flag = 1;
+                           s += 3;
+                         }
+                       /* ",*" is a valid condition.  */
+                       else if (*args != 'U' || (*s != ' ' && *s != '\t'))
+                         as_bad (_("Invalid Unit Instruction Condition."));
+                     }
+                   opcode |= cmpltr << 13;
+                   INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
 
 
-  format = SGL;
-  if (**s == ',')
-    {
-      *s += 1;
-      if (strncasecmp (*s, "sgl", 3) == 0)
-       {
-         format = SGL;
-         *s += 4;
-       }
-      else if (strncasecmp (*s, "dbl", 3) == 0)
-       {
-         format = DBL;
-         *s += 4;
-       }
-      else if (strncasecmp (*s, "quad", 4) == 0)
-       {
-         format = QUAD;
-         *s += 5;
-       }
-      else
-       {
-         format = ILLEGAL_FMT;
-         as_bad (_("Invalid FP Operand Format: %3s"), *s);
-       }
-    }
+                 default:
+                   abort ();
+                 }
+               break;
+             }
 
 
-  return format;
-}
+           /* Handle a nullification completer for branch instructions.  */
+           case 'n':
+             nullif = pa_parse_nullif (&s);
+             INSERT_FIELD_AND_CONTINUE (opcode, nullif, 1);
 
 
-/* Convert from a selector string into a selector type.  */
+           /* Handle a nullification completer for copr and spop insns.  */
+           case 'N':
+             nullif = pa_parse_nullif (&s);
+             INSERT_FIELD_AND_CONTINUE (opcode, nullif, 5);
 
 
-static int
-pa_chk_field_selector (str)
-     char **str;
-{
-  int middle, low, high;
-  int cmp;
-  char name[4];
+           /* Handle ,%r2 completer for new syntax branches.  */
+           case 'L':
+             if (*s == ',' && strncasecmp (s + 1, "%r2", 3) == 0)
+               s += 4;
+             else if (*s == ',' && strncasecmp (s + 1, "%rp", 3) == 0)
+               s += 4;
+             else
+               break;
+             continue;
 
 
-  /* Read past any whitespace.  */
-  /* FIXME: should we read past newlines and formfeeds??? */
-  while (**str == ' ' || **str == '\t' || **str == '\n' || **str == '\f')
-    *str = *str + 1;
+           /* Handle 3 bit entry into the fp compare array.   Valid values
+              are 0..6 inclusive.  */
+           case 'h':
+             get_expression (s);
+             s = expr_end;
+             if (the_insn.exp.X_op == O_constant)
+               {
+                 num = evaluate_absolute (&the_insn);
+                 CHECK_FIELD (num, 6, 0, 0);
+                 num++;
+                 INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
+               }
+             else
+               break;
 
 
-  if ((*str)[1] == '\'' || (*str)[1] == '%')
-    name[0] = TOLOWER ((*str)[0]),
-    name[1] = 0;
-  else if ((*str)[2] == '\'' || (*str)[2] == '%')
-    name[0] = TOLOWER ((*str)[0]),
-    name[1] = TOLOWER ((*str)[1]),
-    name[2] = 0;
-  else if ((*str)[3] == '\'' || (*str)[3] == '%')
-    name[0] = TOLOWER ((*str)[0]),
-    name[1] = TOLOWER ((*str)[1]),
-    name[2] = TOLOWER ((*str)[2]),
-    name[3] = 0;
-  else
-    return e_fsel;
+           /* Handle 3 bit entry into the fp compare array.   Valid values
+              are 0..6 inclusive.  */
+           case 'm':
+             get_expression (s);
+             if (the_insn.exp.X_op == O_constant)
+               {
+                 s = expr_end;
+                 num = evaluate_absolute (&the_insn);
+                 CHECK_FIELD (num, 6, 0, 0);
+                 num = (num + 1) ^ 1;
+                 INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
+               }
+             else
+               break;
 
 
-  low = 0;
-  high = sizeof (selector_table) / sizeof (struct selector_entry) - 1;
+           /* Handle graphics test completers for ftest */
+           case '=':
+             {
+               num = pa_parse_ftest_gfx_completer (&s);
+               INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+             }
 
 
-  do
-    {
-      middle = (low + high) / 2;
-      cmp = strcmp (name, selector_table[middle].prefix);
-      if (cmp < 0)
-       high = middle - 1;
-      else if (cmp > 0)
-       low = middle + 1;
-      else
-       {
-         *str += strlen (name) + 1;
-#ifndef OBJ_SOM
-         if (selector_table[middle].field_selector == e_nsel)
-           return e_fsel;
+           /* Handle a 11 bit immediate at 31.  */
+           case 'i':
+             the_insn.field_selector = pa_chk_field_selector (&s);
+             get_expression (s);
+             s = expr_end;
+             if (the_insn.exp.X_op == O_constant)
+               {
+                 num = evaluate_absolute (&the_insn);
+                 CHECK_FIELD (num, 1023, -1024, 0);
+                 num = low_sign_unext (num, 11);
+                 INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+               }
+             else
+               {
+                 if (is_DP_relative (the_insn.exp))
+                   the_insn.reloc = R_HPPA_GOTOFF;
+                 else if (is_PC_relative (the_insn.exp))
+                   the_insn.reloc = R_HPPA_PCREL_CALL;
+#ifdef OBJ_ELF
+                 else if (is_tls_gdidx (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_GD21L;
+                 else if (is_tls_ldidx (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LDM21L;
+                 else if (is_tls_dtpoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LDO21L;
+                 else if (is_tls_ieoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_IE21L;
+                 else if (is_tls_leoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LE21L;
 #endif
 #endif
-         return selector_table[middle].field_selector;
-       }
-    }
-  while (low <= high);
-
-  return e_fsel;
-}
-
-/* Mark (via expr_end) the end of an expression (I think).  FIXME.  */
+                 else
+                   the_insn.reloc = R_HPPA;
+                 the_insn.format = 11;
+                 continue;
+               }
 
 
-static int
-get_expression (str)
-     char *str;
-{
-  char *save_in;
-  asection *seg;
+           /* Handle a 14 bit immediate at 31.  */
+           case 'J':
+             the_insn.field_selector = pa_chk_field_selector (&s);
+             get_expression (s);
+             s = expr_end;
+             if (the_insn.exp.X_op == O_constant)
+               {
+                 int mb;
 
 
-  save_in = input_line_pointer;
-  input_line_pointer = str;
-  seg = expression (&the_insn.exp);
-  if (!(seg == absolute_section
-       || seg == undefined_section
-       || SEG_NORMAL (seg)))
-    {
-      as_warn (_("Bad segment in expression."));
-      expr_end = input_line_pointer;
-      input_line_pointer = save_in;
-      return 1;
-    }
-  expr_end = input_line_pointer;
-  input_line_pointer = save_in;
-  return 0;
-}
+                 /* XXX the completer stored away tidbits of information
+                    for us to extract.  We need a cleaner way to do this.
+                    Now that we have lots of letters again, it would be
+                    good to rethink this.  */
+                 mb = opcode & 1;
+                 opcode -= mb;
+                 num = evaluate_absolute (&the_insn);
+                 if (mb != (num < 0))
+                   break;
+                 CHECK_FIELD (num, 8191, -8192, 0);
+                 num = low_sign_unext (num, 14);
+                 INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+               }
+             break;
 
 
-/* Mark (via expr_end) the end of an absolute expression.  FIXME.  */
-static int
-pa_get_absolute_expression (insn, strp)
-     struct pa_it *insn;
-     char **strp;
-{
-  char *save_in;
+           /* Handle a 14 bit immediate at 31.  */
+           case 'K':
+             the_insn.field_selector = pa_chk_field_selector (&s);
+             get_expression (s);
+             s = expr_end;
+             if (the_insn.exp.X_op == O_constant)
+               {
+                 int mb;
 
 
-  insn->field_selector = pa_chk_field_selector (strp);
-  save_in = input_line_pointer;
-  input_line_pointer = *strp;
-  expression (&insn->exp);
-  /* This is not perfect, but is a huge improvement over doing nothing.
+                 mb = opcode & 1;
+                 opcode -= mb;
+                 num = evaluate_absolute (&the_insn);
+                 if (mb == (num < 0))
+                   break;
+                 if (num % 4)
+                   break;
+                 CHECK_FIELD (num, 8191, -8192, 0);
+                 num = low_sign_unext (num, 14);
+                 INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+               }
+             break;
 
 
-     The PA assembly syntax is ambiguous in a variety of ways.  Consider
-     this string "4 %r5"  Is that the number 4 followed by the register
-     r5, or is that 4 MOD r5?
+           /* Handle a 16 bit immediate at 31.  */
+           case '<':
+             the_insn.field_selector = pa_chk_field_selector (&s);
+             get_expression (s);
+             s = expr_end;
+             if (the_insn.exp.X_op == O_constant)
+               {
+                 int mb;
 
 
-     If we get a modulo expression when looking for an absolute, we try
-     again cutting off the input string at the first whitespace character.  */
-  if (insn->exp.X_op == O_modulus)
-    {
-      char *s, c;
-      int retval;
+                 mb = opcode & 1;
+                 opcode -= mb;
+                 num = evaluate_absolute (&the_insn);
+                 if (mb != (num < 0))
+                   break;
+                 CHECK_FIELD (num, 32767, -32768, 0);
+                 num = re_assemble_16 (num);
+                 INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+               }
+             break;
 
 
-      input_line_pointer = *strp;
-      s = *strp;
-      while (*s != ',' && *s != ' ' && *s != '\t')
-       s++;
+           /* Handle a 16 bit immediate at 31.  */
+           case '>':
+             the_insn.field_selector = pa_chk_field_selector (&s);
+             get_expression (s);
+             s = expr_end;
+             if (the_insn.exp.X_op == O_constant)
+               {
+                 int mb;
 
 
-      c = *s;
-      *s = 0;
+                 mb = opcode & 1;
+                 opcode -= mb;
+                 num = evaluate_absolute (&the_insn);
+                 if (mb == (num < 0))
+                   break;
+                 if (num % 4)
+                   break;
+                 CHECK_FIELD (num, 32767, -32768, 0);
+                 num = re_assemble_16 (num);
+                 INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+               }
+             break;
 
 
-      retval = pa_get_absolute_expression (insn, strp);
+           /* Handle 14 bit immediate, shifted left three times.  */
+           case '#':
+             if (bfd_get_mach (stdoutput) != pa20)
+               break;
+             the_insn.field_selector = pa_chk_field_selector (&s);
+             get_expression (s);
+             s = expr_end;
+             if (the_insn.exp.X_op == O_constant)
+               {
+                 num = evaluate_absolute (&the_insn);
+                 if (num & 0x7)
+                   break;
+                 CHECK_FIELD (num, 8191, -8192, 0);
+                 if (num < 0)
+                   opcode |= 1;
+                 num &= 0x1fff;
+                 num >>= 3;
+                 INSERT_FIELD_AND_CONTINUE (opcode, num, 4);
+               }
+             else
+               {
+                 if (is_DP_relative (the_insn.exp))
+                   the_insn.reloc = R_HPPA_GOTOFF;
+                 else if (is_PC_relative (the_insn.exp))
+                   the_insn.reloc = R_HPPA_PCREL_CALL;
+#ifdef OBJ_ELF
+                 else if (is_tls_gdidx (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_GD21L;
+                 else if (is_tls_ldidx (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LDM21L;
+                 else if (is_tls_dtpoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LDO21L;
+                 else if (is_tls_ieoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_IE21L;
+                 else if (is_tls_leoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LE21L;
+#endif
+                 else
+                   the_insn.reloc = R_HPPA;
+                 the_insn.format = 14;
+                 continue;
+               }
+             break;
 
 
-      input_line_pointer = save_in;
-      *s = c;
-      return evaluate_absolute (insn);
-    }
-  /* When in strict mode we have a non-match, fix up the pointers
-     and return to our caller.  */
-  if (insn->exp.X_op != O_constant && strict)
-    {
-      expr_end = input_line_pointer;
-      input_line_pointer = save_in;
-      return 0;
-    }
-  if (insn->exp.X_op != O_constant)
-    {
-      as_bad (_("Bad segment (should be absolute)."));
-      expr_end = input_line_pointer;
-      input_line_pointer = save_in;
-      return 0;
-    }
-  expr_end = input_line_pointer;
-  input_line_pointer = save_in;
-  return evaluate_absolute (insn);
-}
+           /* Handle 14 bit immediate, shifted left twice.  */
+           case 'd':
+             the_insn.field_selector = pa_chk_field_selector (&s);
+             get_expression (s);
+             s = expr_end;
+             if (the_insn.exp.X_op == O_constant)
+               {
+                 num = evaluate_absolute (&the_insn);
+                 if (num & 0x3)
+                   break;
+                 CHECK_FIELD (num, 8191, -8192, 0);
+                 if (num < 0)
+                   opcode |= 1;
+                 num &= 0x1fff;
+                 num >>= 2;
+                 INSERT_FIELD_AND_CONTINUE (opcode, num, 3);
+               }
+             else
+               {
+                 if (is_DP_relative (the_insn.exp))
+                   the_insn.reloc = R_HPPA_GOTOFF;
+                 else if (is_PC_relative (the_insn.exp))
+                   the_insn.reloc = R_HPPA_PCREL_CALL;
+#ifdef OBJ_ELF
+                 else if (is_tls_gdidx (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_GD21L;
+                 else if (is_tls_ldidx (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LDM21L;
+                 else if (is_tls_dtpoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LDO21L;
+                 else if (is_tls_ieoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_IE21L;
+                 else if (is_tls_leoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LE21L;
+#endif
+                 else
+                   the_insn.reloc = R_HPPA;
+                 the_insn.format = 14;
+                 continue;
+               }
 
 
-/* Evaluate an absolute expression EXP which may be modified by
-   the selector FIELD_SELECTOR.  Return the value of the expression.  */
-static int
-evaluate_absolute (insn)
-     struct pa_it *insn;
-{
-  offsetT value;
-  expressionS exp;
-  int field_selector = insn->field_selector;
+           /* Handle a 14 bit immediate at 31.  */
+           case 'j':
+             the_insn.field_selector = pa_chk_field_selector (&s);
+             get_expression (s);
+             s = expr_end;
+             if (the_insn.exp.X_op == O_constant)
+               {
+                 num = evaluate_absolute (&the_insn);
+                 CHECK_FIELD (num, 8191, -8192, 0);
+                 num = low_sign_unext (num, 14);
+                 INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+               }
+             else
+               {
+                 if (is_DP_relative (the_insn.exp))
+                   the_insn.reloc = R_HPPA_GOTOFF;
+                 else if (is_PC_relative (the_insn.exp))
+                   the_insn.reloc = R_HPPA_PCREL_CALL;
+#ifdef OBJ_ELF
+                 else if (is_tls_gdidx (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_GD21L;
+                 else if (is_tls_ldidx (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LDM21L;
+                 else if (is_tls_dtpoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LDO21L;
+                 else if (is_tls_ieoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_IE21L;
+                 else if (is_tls_leoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LE21L;
+#endif
+                 else
+                   the_insn.reloc = R_HPPA;
+                 the_insn.format = 14;
+                 continue;
+               }
 
 
-  exp = insn->exp;
-  value = exp.X_add_number;
+           /* Handle a 21 bit immediate at 31.  */
+           case 'k':
+             the_insn.field_selector = pa_chk_field_selector (&s);
+             get_expression (s);
+             s = expr_end;
+             if (the_insn.exp.X_op == O_constant)
+               {
+                 num = evaluate_absolute (&the_insn);
+                 CHECK_FIELD (num >> 11, 1048575, -1048576, 0);
+                 opcode |= re_assemble_21 (num);
+                 continue;
+               }
+             else
+               {
+                 if (is_DP_relative (the_insn.exp))
+                   the_insn.reloc = R_HPPA_GOTOFF;
+                 else if (is_PC_relative (the_insn.exp))
+                   the_insn.reloc = R_HPPA_PCREL_CALL;
+#ifdef OBJ_ELF
+                 else if (is_tls_gdidx (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_GD21L;
+                 else if (is_tls_ldidx (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LDM21L;
+                 else if (is_tls_dtpoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LDO21L;
+                 else if (is_tls_ieoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_IE21L;
+                 else if (is_tls_leoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LE21L;
+#endif
+                 else
+                   the_insn.reloc = R_HPPA;
+                 the_insn.format = 21;
+                 continue;
+               }
+
+           /* Handle a 16 bit immediate at 31 (PA 2.0 wide mode only).  */
+           case 'l':
+             the_insn.field_selector = pa_chk_field_selector (&s);
+             get_expression (s);
+             s = expr_end;
+             if (the_insn.exp.X_op == O_constant)
+               {
+                 num = evaluate_absolute (&the_insn);
+                 CHECK_FIELD (num, 32767, -32768, 0);
+                 opcode |= re_assemble_16 (num);
+                 continue;
+               }
+             else
+               {
+                 /* ??? Is this valid for wide mode?  */
+                 if (is_DP_relative (the_insn.exp))
+                   the_insn.reloc = R_HPPA_GOTOFF;
+                 else if (is_PC_relative (the_insn.exp))
+                   the_insn.reloc = R_HPPA_PCREL_CALL;
+#ifdef OBJ_ELF
+                 else if (is_tls_gdidx (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_GD21L;
+                 else if (is_tls_ldidx (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LDM21L;
+                 else if (is_tls_dtpoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LDO21L;
+                 else if (is_tls_ieoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_IE21L;
+                 else if (is_tls_leoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LE21L;
+#endif
+                 else
+                   the_insn.reloc = R_HPPA;
+                 the_insn.format = 14;
+                 continue;
+               }
 
 
-  return hppa_field_adjust (0, value, field_selector);
-}
+           /* Handle a word-aligned 16-bit imm. at 31 (PA2.0 wide).  */
+           case 'y':
+             the_insn.field_selector = pa_chk_field_selector (&s);
+             get_expression (s);
+             s = expr_end;
+             if (the_insn.exp.X_op == O_constant)
+               {
+                 num = evaluate_absolute (&the_insn);
+                 CHECK_FIELD (num, 32767, -32768, 0);
+                 CHECK_ALIGN (num, 4, 0);
+                 opcode |= re_assemble_16 (num);
+                 continue;
+               }
+             else
+               {
+                 /* ??? Is this valid for wide mode?  */
+                 if (is_DP_relative (the_insn.exp))
+                   the_insn.reloc = R_HPPA_GOTOFF;
+                 else if (is_PC_relative (the_insn.exp))
+                   the_insn.reloc = R_HPPA_PCREL_CALL;
+#ifdef OBJ_ELF
+                 else if (is_tls_gdidx (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_GD21L;
+                 else if (is_tls_ldidx (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LDM21L;
+                 else if (is_tls_dtpoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LDO21L;
+                 else if (is_tls_ieoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_IE21L;
+                 else if (is_tls_leoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LE21L;
+#endif
+                 else
+                   the_insn.reloc = R_HPPA;
+                 the_insn.format = 14;
+                 continue;
+               }
 
 
-/* Given an argument location specification return the associated
-   argument location number.  */
+           /* Handle a dword-aligned 16-bit imm. at 31 (PA2.0 wide).  */
+           case '&':
+             the_insn.field_selector = pa_chk_field_selector (&s);
+             get_expression (s);
+             s = expr_end;
+             if (the_insn.exp.X_op == O_constant)
+               {
+                 num = evaluate_absolute (&the_insn);
+                 CHECK_FIELD (num, 32767, -32768, 0);
+                 CHECK_ALIGN (num, 8, 0);
+                 opcode |= re_assemble_16 (num);
+                 continue;
+               }
+             else
+               {
+                 /* ??? Is this valid for wide mode?  */
+                 if (is_DP_relative (the_insn.exp))
+                   the_insn.reloc = R_HPPA_GOTOFF;
+                 else if (is_PC_relative (the_insn.exp))
+                   the_insn.reloc = R_HPPA_PCREL_CALL;
+#ifdef OBJ_ELF
+                 else if (is_tls_gdidx (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_GD21L;
+                 else if (is_tls_ldidx (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LDM21L;
+                 else if (is_tls_dtpoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LDO21L;
+                 else if (is_tls_ieoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_IE21L;
+                 else if (is_tls_leoff (the_insn.exp))
+                   the_insn.reloc = R_PARISC_TLS_LE21L;
+#endif
+                 else
+                   the_insn.reloc = R_HPPA;
+                 the_insn.format = 14;
+                 continue;
+               }
 
 
-static unsigned int
-pa_build_arg_reloc (type_name)
-     char *type_name;
-{
+           /* Handle a 12 bit branch displacement.  */
+           case 'w':
+             the_insn.field_selector = pa_chk_field_selector (&s);
+             get_expression (s);
+             s = expr_end;
+             the_insn.pcrel = 1;
+             if (!the_insn.exp.X_add_symbol
+                 || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
+                             FAKE_LABEL_NAME))
+               {
+                 num = evaluate_absolute (&the_insn);
+                 if (num % 4)
+                   {
+                     as_bad (_("Branch to unaligned address"));
+                     break;
+                   }
+                 if (the_insn.exp.X_add_symbol)
+                   num -= 8;
+                 CHECK_FIELD (num, 8191, -8192, 0);
+                 opcode |= re_assemble_12 (num >> 2);
+                 continue;
+               }
+             else
+               {
+                 the_insn.reloc = R_HPPA_PCREL_CALL;
+                 the_insn.format = 12;
+                 the_insn.arg_reloc = last_call_desc.arg_reloc;
+                 memset (&last_call_desc, 0, sizeof (struct call_desc));
+                 s = expr_end;
+                 continue;
+               }
 
 
-  if (strncasecmp (type_name, "no", 2) == 0)
-    return 0;
-  if (strncasecmp (type_name, "gr", 2) == 0)
-    return 1;
-  else if (strncasecmp (type_name, "fr", 2) == 0)
-    return 2;
-  else if (strncasecmp (type_name, "fu", 2) == 0)
-    return 3;
-  else
-    as_bad (_("Invalid argument location: %s\n"), type_name);
+           /* Handle a 17 bit branch displacement.  */
+           case 'W':
+             the_insn.field_selector = pa_chk_field_selector (&s);
+             get_expression (s);
+             s = expr_end;
+             the_insn.pcrel = 1;
+             if (!the_insn.exp.X_add_symbol
+                 || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
+                             FAKE_LABEL_NAME))
+               {
+                 num = evaluate_absolute (&the_insn);
+                 if (num % 4)
+                   {
+                     as_bad (_("Branch to unaligned address"));
+                     break;
+                   }
+                 if (the_insn.exp.X_add_symbol)
+                   num -= 8;
+                 CHECK_FIELD (num, 262143, -262144, 0);
+                 opcode |= re_assemble_17 (num >> 2);
+                 continue;
+               }
+             else
+               {
+                 the_insn.reloc = R_HPPA_PCREL_CALL;
+                 the_insn.format = 17;
+                 the_insn.arg_reloc = last_call_desc.arg_reloc;
+                 memset (&last_call_desc, 0, sizeof (struct call_desc));
+                 continue;
+               }
 
 
-  return 0;
-}
+           /* Handle a 22 bit branch displacement.  */
+           case 'X':
+             the_insn.field_selector = pa_chk_field_selector (&s);
+             get_expression (s);
+             s = expr_end;
+             the_insn.pcrel = 1;
+             if (!the_insn.exp.X_add_symbol
+                 || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
+                             FAKE_LABEL_NAME))
+               {
+                 num = evaluate_absolute (&the_insn);
+                 if (num % 4)
+                   {
+                     as_bad (_("Branch to unaligned address"));
+                     break;
+                   }
+                 if (the_insn.exp.X_add_symbol)
+                   num -= 8;
+                 CHECK_FIELD (num, 8388607, -8388608, 0);
+                 opcode |= re_assemble_22 (num >> 2);
+               }
+             else
+               {
+                 the_insn.reloc = R_HPPA_PCREL_CALL;
+                 the_insn.format = 22;
+                 the_insn.arg_reloc = last_call_desc.arg_reloc;
+                 memset (&last_call_desc, 0, sizeof (struct call_desc));
+                 continue;
+               }
 
 
-/* Encode and return an argument relocation specification for
-   the given register in the location specified by arg_reloc.  */
+           /* Handle an absolute 17 bit branch target.  */
+           case 'z':
+             the_insn.field_selector = pa_chk_field_selector (&s);
+             get_expression (s);
+             s = expr_end;
+             the_insn.pcrel = 0;
+             if (!the_insn.exp.X_add_symbol
+                 || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
+                             FAKE_LABEL_NAME))
+               {
+                 num = evaluate_absolute (&the_insn);
+                 if (num % 4)
+                   {
+                     as_bad (_("Branch to unaligned address"));
+                     break;
+                   }
+                 if (the_insn.exp.X_add_symbol)
+                   num -= 8;
+                 CHECK_FIELD (num, 262143, -262144, 0);
+                 opcode |= re_assemble_17 (num >> 2);
+                 continue;
+               }
+             else
+               {
+                 the_insn.reloc = R_HPPA_ABS_CALL;
+                 the_insn.format = 17;
+                 the_insn.arg_reloc = last_call_desc.arg_reloc;
+                 memset (&last_call_desc, 0, sizeof (struct call_desc));
+                 continue;
+               }
 
 
-static unsigned int
-pa_align_arg_reloc (reg, arg_reloc)
-     unsigned int reg;
-     unsigned int arg_reloc;
-{
-  unsigned int new_reloc;
+           /* Handle '%r1' implicit operand of addil instruction.  */
+           case 'Z':
+             if (*s == ',' && *(s + 1) == '%' && *(s + 3) == '1'
+                 && (*(s + 2) == 'r' || *(s + 2) == 'R'))
+               {
+                 s += 4;
+                 continue;
+               }
+             else
+               break;
 
 
-  new_reloc = arg_reloc;
-  switch (reg)
-    {
-    case 0:
-      new_reloc <<= 8;
-      break;
-    case 1:
-      new_reloc <<= 6;
-      break;
-    case 2:
-      new_reloc <<= 4;
-      break;
-    case 3:
-      new_reloc <<= 2;
-      break;
-    default:
-      as_bad (_("Invalid argument description: %d"), reg);
-    }
+           /* Handle '%sr0,%r31' implicit operand of be,l instruction.  */
+           case 'Y':
+             if (strncasecmp (s, "%sr0,%r31", 9) != 0)
+               break;
+             s += 9;
+             continue;
 
 
-  return new_reloc;
-}
+           /* Handle immediate value of 0 for ordered load/store instructions.  */
+           case '@':
+             if (*s != '0')
+               break;
+             s++;
+             continue;
 
 
-/* Parse a PA nullification completer (,n).  Return nonzero if the
-   completer was found; return zero if no completer was found.  */
+           /* Handle a 2 bit shift count at 25.  */
+           case '.':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 3, 1, strict);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
 
 
-static int
-pa_parse_nullif (s)
-     char **s;
-{
-  int nullif;
+           /* Handle a 4 bit shift count at 25.  */
+           case '*':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 15, 0, strict);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
 
 
-  nullif = 0;
-  if (**s == ',')
-    {
-      *s = *s + 1;
-      if (strncasecmp (*s, "n", 1) == 0)
-       nullif = 1;
-      else
-       {
-         as_bad (_("Invalid Nullification: (%c)"), **s);
-         nullif = 0;
-       }
-      *s = *s + 1;
-    }
+           /* Handle a 5 bit shift count at 26.  */
+           case 'p':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 31, 0, strict);
+             INSERT_FIELD_AND_CONTINUE (opcode, 31 - num, 5);
 
 
-  return nullif;
-}
+           /* Handle a 6 bit shift count at 20,22:26.  */
+           case '~':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 63, 0, strict);
+             num = 63 - num;
+             opcode |= (num & 0x20) << 6;
+             INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 5);
 
 
-/* Parse a non-negated compare/subtract completer returning the
-   number (for encoding in instructions) of the given completer.  */
+           /* Handle a 6 bit field length at 23,27:31.  */
+           case '%':
+             flag = 0;
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 64, 1, strict);
+             num--;
+             opcode |= (num & 0x20) << 3;
+             num = 31 - (num & 0x1f);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
-static int
-pa_parse_nonneg_cmpsub_cmpltr (s)
-     char **s;
-{
-  int cmpltr;
-  char *name = *s + 1;
-  char c;
-  char *save_s = *s;
-  int nullify = 0;
+           /* Handle a 6 bit field length at 19,27:31.  */
+           case '|':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 64, 1, strict);
+             num--;
+             opcode |= (num & 0x20) << 7;
+             num = 31 - (num & 0x1f);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
-  cmpltr = 0;
-  if (**s == ',')
-    {
-      *s += 1;
-      while (**s != ',' && **s != ' ' && **s != '\t')
-       *s += 1;
-      c = **s;
-      **s = 0x00;
+           /* Handle a 5 bit bit position at 26.  */
+           case 'P':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 31, 0, strict);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 5);
 
 
-      if (strcmp (name, "=") == 0)
-       {
-         cmpltr = 1;
-       }
-      else if (strcmp (name, "<") == 0)
-       {
-         cmpltr = 2;
-       }
-      else if (strcmp (name, "<=") == 0)
-       {
-         cmpltr = 3;
-       }
-      else if (strcmp (name, "<<") == 0)
-       {
-         cmpltr = 4;
-       }
-      else if (strcmp (name, "<<=") == 0)
-       {
-         cmpltr = 5;
-       }
-      else if (strcasecmp (name, "sv") == 0)
-       {
-         cmpltr = 6;
-       }
-      else if (strcasecmp (name, "od") == 0)
-       {
-         cmpltr = 7;
-       }
-      /* If we have something like addb,n then there is no condition
-         completer.  */
-      else if (strcasecmp (name, "n") == 0)
-       {
-         cmpltr = 0;
-         nullify = 1;
-       }
-      else
-       {
-         cmpltr = -1;
-       }
-      **s = c;
-    }
+           /* Handle a 6 bit bit position at 20,22:26.  */
+           case 'q':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 63, 0, strict);
+             opcode |= (num & 0x20) << 6;
+             INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 5);
 
 
-  /* Reset pointers if this was really a ,n for a branch instruction.  */
-  if (nullify)
-    *s = save_s;
+           /* Handle a 5 bit immediate at 10 with 'd' as the complement
+              of the high bit of the immediate.  */
+           case 'B':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 63, 0, strict);
+             if (num & 0x20)
+               ;
+             else
+               opcode |= (1 << 13);
+             INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 21);
 
 
-  return cmpltr;
-}
+           /* Handle a 5 bit immediate at 10.  */
+           case 'Q':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 31, 0, strict);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
 
 
-/* Parse a negated compare/subtract completer returning the
-   number (for encoding in instructions) of the given completer.  */
+           /* Handle a 9 bit immediate at 28.  */
+           case '$':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 511, 1, strict);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 3);
 
 
-static int
-pa_parse_neg_cmpsub_cmpltr (s)
-     char **s;
-{
-  int cmpltr;
-  char *name = *s + 1;
-  char c;
-  char *save_s = *s;
-  int nullify = 0;
+           /* Handle a 13 bit immediate at 18.  */
+           case 'A':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 8191, 0, strict);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
 
 
-  cmpltr = 0;
-  if (**s == ',')
-    {
-      *s += 1;
-      while (**s != ',' && **s != ' ' && **s != '\t')
-       *s += 1;
-      c = **s;
-      **s = 0x00;
+           /* Handle a 26 bit immediate at 31.  */
+           case 'D':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 67108863, 0, strict);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
-      if (strcasecmp (name, "tr") == 0)
-       {
-         cmpltr = 0;
-       }
-      else if (strcmp (name, "<>") == 0)
-       {
-         cmpltr = 1;
-       }
-      else if (strcmp (name, ">=") == 0)
-       {
-         cmpltr = 2;
-       }
-      else if (strcmp (name, ">") == 0)
-       {
-         cmpltr = 3;
-       }
-      else if (strcmp (name, ">>=") == 0)
-       {
-         cmpltr = 4;
-       }
-      else if (strcmp (name, ">>") == 0)
-       {
-         cmpltr = 5;
-       }
-      else if (strcasecmp (name, "nsv") == 0)
-       {
-         cmpltr = 6;
-       }
-      else if (strcasecmp (name, "ev") == 0)
-       {
-         cmpltr = 7;
-       }
-      /* If we have something like addb,n then there is no condition
-         completer.  */
-      else if (strcasecmp (name, "n") == 0)
-       {
-         cmpltr = 0;
-         nullify = 1;
-       }
-      else
-       {
-         cmpltr = -1;
-       }
-      **s = c;
-    }
+           /* Handle a 3 bit SFU identifier at 25.  */
+           case 'v':
+             if (*s++ != ',')
+               as_bad (_("Invalid SFU identifier"));
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 7, 0, strict);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
 
 
-  /* Reset pointers if this was really a ,n for a branch instruction.  */
-  if (nullify)
-    *s = save_s;
+           /* Handle a 20 bit SOP field for spop0.  */
+           case 'O':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 1048575, 0, strict);
+             num = (num & 0x1f) | ((num & 0x000fffe0) << 6);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
-  return cmpltr;
-}
+           /* Handle a 15bit SOP field for spop1.  */
+           case 'o':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 32767, 0, strict);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 11);
 
 
-/* Parse a 64 bit compare and branch completer returning the number (for
-   encoding in instructions) of the given completer.
+           /* Handle a 10bit SOP field for spop3.  */
+           case '0':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 1023, 0, strict);
+             num = (num & 0x1f) | ((num & 0x000003e0) << 6);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
-   Nonnegated comparisons are returned as 0-7, negated comparisons are
-   returned as 8-15.  */
+           /* Handle a 15 bit SOP field for spop2.  */
+           case '1':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 32767, 0, strict);
+             num = (num & 0x1f) | ((num & 0x00007fe0) << 6);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
-static int
-pa_parse_cmpb_64_cmpltr (s)
-     char **s;
-{
-  int cmpltr;
-  char *name = *s + 1;
-  char c;
+           /* Handle a 3-bit co-processor ID field.  */
+           case 'u':
+             if (*s++ != ',')
+               as_bad (_("Invalid COPR identifier"));
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 7, 0, strict);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
 
 
-  cmpltr = -1;
-  if (**s == ',')
-    {
-      *s += 1;
-      while (**s != ',' && **s != ' ' && **s != '\t')
-       *s += 1;
-      c = **s;
-      **s = 0x00;
+           /* Handle a 22bit SOP field for copr.  */
+           case '2':
+             num = pa_get_absolute_expression (&the_insn, &s);
+             if (strict && the_insn.exp.X_op != O_constant)
+               break;
+             s = expr_end;
+             CHECK_FIELD (num, 4194303, 0, strict);
+             num = (num & 0x1f) | ((num & 0x003fffe0) << 4);
+             INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
-      if (strcmp (name, "*") == 0)
-       {
-         cmpltr = 0;
-       }
-      else if (strcmp (name, "*=") == 0)
-       {
-         cmpltr = 1;
-       }
-      else if (strcmp (name, "*<") == 0)
-       {
-         cmpltr = 2;
-       }
-      else if (strcmp (name, "*<=") == 0)
-       {
-         cmpltr = 3;
-       }
-      else if (strcmp (name, "*<<") == 0)
-       {
-         cmpltr = 4;
-       }
-      else if (strcmp (name, "*<<=") == 0)
-       {
-         cmpltr = 5;
-       }
-      else if (strcasecmp (name, "*sv") == 0)
-       {
-         cmpltr = 6;
-       }
-      else if (strcasecmp (name, "*od") == 0)
-       {
-         cmpltr = 7;
-       }
-      else if (strcasecmp (name, "*tr") == 0)
-       {
-         cmpltr = 8;
-       }
-      else if (strcmp (name, "*<>") == 0)
-       {
-         cmpltr = 9;
-       }
-      else if (strcmp (name, "*>=") == 0)
-       {
-         cmpltr = 10;
-       }
-      else if (strcmp (name, "*>") == 0)
-       {
-         cmpltr = 11;
-       }
-      else if (strcmp (name, "*>>=") == 0)
-       {
-         cmpltr = 12;
-       }
-      else if (strcmp (name, "*>>") == 0)
-       {
-         cmpltr = 13;
-       }
-      else if (strcasecmp (name, "*nsv") == 0)
-       {
-         cmpltr = 14;
-       }
-      else if (strcasecmp (name, "*ev") == 0)
-       {
-         cmpltr = 15;
-       }
-      else
-       {
-         cmpltr = -1;
-       }
-      **s = c;
-    }
+           /* Handle a source FP operand format completer.  */
+           case '{':
+             if (*s == ',' && *(s+1) == 't')
+               {
+                 the_insn.trunc = 1;
+                 s += 2;
+               }
+             else
+               the_insn.trunc = 0;
+             flag = pa_parse_fp_cnv_format (&s);
+             the_insn.fpof1 = flag;
+             if (flag == W || flag == UW)
+               flag = SGL;
+             if (flag == DW || flag == UDW)
+               flag = DBL;
+             if (flag == QW || flag == UQW)
+               flag = QUAD;
+             INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
 
 
-  return cmpltr;
-}
+           /* Handle a destination FP operand format completer.  */
+           case '_':
+             /* pa_parse_format needs the ',' prefix.  */
+             s--;
+             flag = pa_parse_fp_cnv_format (&s);
+             the_insn.fpof2 = flag;
+             if (flag == W || flag == UW)
+               flag = SGL;
+             if (flag == DW || flag == UDW)
+               flag = DBL;
+             if (flag == QW || flag == UQW)
+               flag = QUAD;
+             opcode |= flag << 13;
+             if (the_insn.fpof1 == SGL
+                 || the_insn.fpof1 == DBL
+                 || the_insn.fpof1 == QUAD)
+               {
+                 if (the_insn.fpof2 == SGL
+                     || the_insn.fpof2 == DBL
+                     || the_insn.fpof2 == QUAD)
+                   flag = 0;
+                 else if (the_insn.fpof2 == W
+                     || the_insn.fpof2 == DW
+                     || the_insn.fpof2 == QW)
+                   flag = 2;
+                 else if (the_insn.fpof2 == UW
+                     || the_insn.fpof2 == UDW
+                     || the_insn.fpof2 == UQW)
+                   flag = 6;
+                 else
+                   abort ();
+               }
+             else if (the_insn.fpof1 == W
+                      || the_insn.fpof1 == DW
+                      || the_insn.fpof1 == QW)
+               {
+                 if (the_insn.fpof2 == SGL
+                     || the_insn.fpof2 == DBL
+                     || the_insn.fpof2 == QUAD)
+                   flag = 1;
+                 else
+                   abort ();
+               }
+             else if (the_insn.fpof1 == UW
+                      || the_insn.fpof1 == UDW
+                      || the_insn.fpof1 == UQW)
+               {
+                 if (the_insn.fpof2 == SGL
+                     || the_insn.fpof2 == DBL
+                     || the_insn.fpof2 == QUAD)
+                   flag = 5;
+                 else
+                   abort ();
+               }
+             flag |= the_insn.trunc;
+             INSERT_FIELD_AND_CONTINUE (opcode, flag, 15);
+
+           /* Handle a source FP operand format completer.  */
+           case 'F':
+             flag = pa_parse_fp_format (&s);
+             the_insn.fpof1 = flag;
+             INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+
+           /* Handle a destination FP operand format completer.  */
+           case 'G':
+             /* pa_parse_format needs the ',' prefix.  */
+             s--;
+             flag = pa_parse_fp_format (&s);
+             the_insn.fpof2 = flag;
+             INSERT_FIELD_AND_CONTINUE (opcode, flag, 13);
+
+           /* Handle a source FP operand format completer at 20.  */
+           case 'I':
+             flag = pa_parse_fp_format (&s);
+             the_insn.fpof1 = flag;
+             INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+
+           /* Handle a floating point operand format at 26.
+              Only allows single and double precision.  */
+           case 'H':
+             flag = pa_parse_fp_format (&s);
+             switch (flag)
+               {
+               case SGL:
+                 opcode |= 0x20;
+               case DBL:
+                 the_insn.fpof1 = flag;
+                 continue;
+
+               case QUAD:
+               case ILLEGAL_FMT:
+               default:
+                 as_bad (_("Invalid Floating Point Operand Format."));
+               }
+             break;
 
 
-/* Parse a 64 bit compare immediate and branch completer returning the number
-   (for encoding in instructions) of the given completer.  */
+           /* Handle all floating point registers.  */
+           case 'f':
+             switch (*++args)
+               {
+               /* Float target register.  */
+               case 't':
+                 if (!pa_parse_number (&s, 3))
+                   break;
+                 num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
+                 CHECK_FIELD (num, 31, 0, 0);
+                 INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
 
 
-static int
-pa_parse_cmpib_64_cmpltr (s)
-     char **s;
-{
-  int cmpltr;
-  char *name = *s + 1;
-  char c;
+               /* Float target register with L/R selection.  */
+               case 'T':
+                 {
+                   if (!pa_parse_number (&s, 1))
+                     break;
+                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
+                   CHECK_FIELD (num, 31, 0, 0);
+                   opcode |= num;
 
 
-  cmpltr = -1;
-  if (**s == ',')
-    {
-      *s += 1;
-      while (**s != ',' && **s != ' ' && **s != '\t')
-       *s += 1;
-      c = **s;
-      **s = 0x00;
+                   /* 0x30 opcodes are FP arithmetic operation opcodes
+                      and need to be turned into 0x38 opcodes.  This
+                      is not necessary for loads/stores.  */
+                   if (need_pa11_opcode ()
+                       && ((opcode & 0xfc000000) == 0x30000000))
+                     opcode |= 1 << 27;
 
 
-      if (strcmp (name, "*<<") == 0)
-       {
-         cmpltr = 0;
-       }
-      else if (strcmp (name, "*=") == 0)
-       {
-         cmpltr = 1;
-       }
-      else if (strcmp (name, "*<") == 0)
-       {
-         cmpltr = 2;
-       }
-      else if (strcmp (name, "*<=") == 0)
-       {
-         cmpltr = 3;
-       }
-      else if (strcmp (name, "*>>=") == 0)
-       {
-         cmpltr = 4;
-       }
-      else if (strcmp (name, "*<>") == 0)
-       {
-         cmpltr = 5;
-       }
-      else if (strcasecmp (name, "*>=") == 0)
-       {
-         cmpltr = 6;
-       }
-      else if (strcasecmp (name, "*>") == 0)
-       {
-         cmpltr = 7;
-       }
-      else
-       {
-         cmpltr = -1;
-       }
-      **s = c;
-    }
+                   opcode |= (pa_number & FP_REG_RSEL ? 1 << 6 : 0);
+                   continue;
+                 }
 
 
-  return cmpltr;
-}
+               /* Float operand 1.  */
+               case 'a':
+                 {
+                   if (!pa_parse_number (&s, 1))
+                     break;
+                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
+                   CHECK_FIELD (num, 31, 0, 0);
+                   opcode |= num << 21;
+                   if (need_pa11_opcode ())
+                     {
+                       opcode |= (pa_number & FP_REG_RSEL ? 1 << 7 : 0);
+                       opcode |= 1 << 27;
+                     }
+                   continue;
+                 }
 
 
-/* Parse a non-negated addition completer returning the number
-   (for encoding in instructions) of the given completer.  */
+               /* Float operand 1 with L/R selection.  */
+               case 'X':
+               case 'A':
+                 {
+                   if (!pa_parse_number (&s, 1))
+                     break;
+                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
+                   CHECK_FIELD (num, 31, 0, 0);
+                   opcode |= num << 21;
+                   opcode |= (pa_number & FP_REG_RSEL ? 1 << 7 : 0);
+                   continue;
+                 }
 
 
-static int
-pa_parse_nonneg_add_cmpltr (s)
-     char **s;
-{
-  int cmpltr;
-  char *name = *s + 1;
-  char c;
-  char *save_s = *s;
-  int nullify = 0;
+               /* Float operand 2.  */
+               case 'b':
+                 {
+                   if (!pa_parse_number (&s, 1))
+                     break;
+                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
+                   CHECK_FIELD (num, 31, 0, 0);
+                   opcode |= num << 16;
+                   if (need_pa11_opcode ())
+                     {
+                       opcode |= (pa_number & FP_REG_RSEL ? 1 << 12 : 0);
+                       opcode |= 1 << 27;
+                     }
+                   continue;
+                 }
 
 
-  cmpltr = 0;
-  if (**s == ',')
-    {
-      *s += 1;
-      while (**s != ',' && **s != ' ' && **s != '\t')
-       *s += 1;
-      c = **s;
-      **s = 0x00;
-      if (strcmp (name, "=") == 0)
-       {
-         cmpltr = 1;
-       }
-      else if (strcmp (name, "<") == 0)
-       {
-         cmpltr = 2;
-       }
-      else if (strcmp (name, "<=") == 0)
-       {
-         cmpltr = 3;
-       }
-      else if (strcasecmp (name, "nuv") == 0)
-       {
-         cmpltr = 4;
-       }
-      else if (strcasecmp (name, "znv") == 0)
-       {
-         cmpltr = 5;
-       }
-      else if (strcasecmp (name, "sv") == 0)
-       {
-         cmpltr = 6;
-       }
-      else if (strcasecmp (name, "od") == 0)
-       {
-         cmpltr = 7;
-       }
-      /* If we have something like addb,n then there is no condition
-         completer.  */
-      else if (strcasecmp (name, "n") == 0)
-       {
-         cmpltr = 0;
-         nullify = 1;
-       }
-      else
-       {
-         cmpltr = -1;
-       }
-      **s = c;
-    }
+               /* Float operand 2 with L/R selection.  */
+               case 'B':
+                 {
+                   if (!pa_parse_number (&s, 1))
+                     break;
+                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
+                   CHECK_FIELD (num, 31, 0, 0);
+                   opcode |= num << 16;
+                   opcode |= (pa_number & FP_REG_RSEL ? 1 << 12 : 0);
+                   continue;
+                 }
 
 
-  /* Reset pointers if this was really a ,n for a branch instruction.  */
-  if (nullify)
-    *s = save_s;
+               /* Float operand 3 for fmpyfadd, fmpynfadd.  */
+               case 'C':
+                 {
+                   if (!pa_parse_number (&s, 1))
+                     break;
+                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
+                   CHECK_FIELD (num, 31, 0, 0);
+                   opcode |= (num & 0x1c) << 11;
+                   opcode |= (num & 0x03) << 9;
+                   opcode |= (pa_number & FP_REG_RSEL ? 1 << 8 : 0);
+                   continue;
+                 }
 
 
-  return cmpltr;
-}
+               /* Float mult operand 1 for fmpyadd, fmpysub */
+               case 'i':
+                 {
+                   if (!pa_parse_number (&s, 1))
+                     break;
+                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
+                   CHECK_FIELD (num, 31, 0, 0);
+                   if (the_insn.fpof1 == SGL)
+                     {
+                       if (num < 16)
+                         {
+                           as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
+                           break;
+                         }
+                       num &= 0xF;
+                       num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
+                 }
 
 
-/* Parse a negated addition completer returning the number
-   (for encoding in instructions) of the given completer.  */
+               /* Float mult operand 2 for fmpyadd, fmpysub */
+               case 'j':
+                 {
+                   if (!pa_parse_number (&s, 1))
+                     break;
+                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
+                   CHECK_FIELD (num, 31, 0, 0);
+                   if (the_insn.fpof1 == SGL)
+                     {
+                       if (num < 16)
+                         {
+                           as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
+                           break;
+                         }
+                       num &= 0xF;
+                       num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
+                 }
 
 
-static int
-pa_parse_neg_add_cmpltr (s)
-     char **s;
-{
-  int cmpltr;
-  char *name = *s + 1;
-  char c;
-  char *save_s = *s;
-  int nullify = 0;
+               /* Float mult target for fmpyadd, fmpysub */
+               case 'k':
+                 {
+                   if (!pa_parse_number (&s, 1))
+                     break;
+                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
+                   CHECK_FIELD (num, 31, 0, 0);
+                   if (the_insn.fpof1 == SGL)
+                     {
+                       if (num < 16)
+                         {
+                           as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
+                           break;
+                         }
+                       num &= 0xF;
+                       num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+                 }
 
 
-  cmpltr = 0;
-  if (**s == ',')
-    {
-      *s += 1;
-      while (**s != ',' && **s != ' ' && **s != '\t')
-       *s += 1;
-      c = **s;
-      **s = 0x00;
-      if (strcasecmp (name, "tr") == 0)
-       {
-         cmpltr = 0;
-       }
-      else if (strcmp (name, "<>") == 0)
-       {
-         cmpltr = 1;
-       }
-      else if (strcmp (name, ">=") == 0)
-       {
-         cmpltr = 2;
-       }
-      else if (strcmp (name, ">") == 0)
-       {
-         cmpltr = 3;
-       }
-      else if (strcasecmp (name, "uv") == 0)
-       {
-         cmpltr = 4;
-       }
-      else if (strcasecmp (name, "vnz") == 0)
-       {
-         cmpltr = 5;
-       }
-      else if (strcasecmp (name, "nsv") == 0)
-       {
-         cmpltr = 6;
-       }
-      else if (strcasecmp (name, "ev") == 0)
-       {
-         cmpltr = 7;
-       }
-      /* If we have something like addb,n then there is no condition
-         completer.  */
-      else if (strcasecmp (name, "n") == 0)
-       {
-         cmpltr = 0;
-         nullify = 1;
-       }
-      else
-       {
-         cmpltr = -1;
-       }
-      **s = c;
-    }
+               /* Float add operand 1 for fmpyadd, fmpysub */
+               case 'l':
+                 {
+                   if (!pa_parse_number (&s, 1))
+                     break;
+                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
+                   CHECK_FIELD (num, 31, 0, 0);
+                   if (the_insn.fpof1 == SGL)
+                     {
+                       if (num < 16)
+                         {
+                           as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
+                           break;
+                         }
+                       num &= 0xF;
+                       num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
+                 }
 
 
-  /* Reset pointers if this was really a ,n for a branch instruction.  */
-  if (nullify)
-    *s = save_s;
+               /* Float add target for fmpyadd, fmpysub */
+               case 'm':
+                 {
+                   if (!pa_parse_number (&s, 1))
+                     break;
+                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
+                   CHECK_FIELD (num, 31, 0, 0);
+                   if (the_insn.fpof1 == SGL)
+                     {
+                       if (num < 16)
+                         {
+                           as_bad  (_("Invalid register for single precision fmpyadd or fmpysub"));
+                           break;
+                         }
+                       num &= 0xF;
+                       num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
+                     }
+                   INSERT_FIELD_AND_CONTINUE (opcode, num, 11);
+                 }
 
 
-  return cmpltr;
-}
+               /* Handle L/R register halves like 'x'.  */
+               case 'E':
+               case 'e':
+                 {
+                   if (!pa_parse_number (&s, 1))
+                     break;
+                   num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
+                   CHECK_FIELD (num, 31, 0, 0);
+                   opcode |= num << 16;
+                   if (need_pa11_opcode ())
+                     {
+                       opcode |= (pa_number & FP_REG_RSEL ? 1 << 1 : 0);
+                     }
+                   continue;
+                 }
 
 
-/* Parse a 64 bit wide mode add and branch completer returning the number (for
-   encoding in instructions) of the given completer.  */
+               /* Float target register (PA 2.0 wide).  */
+               case 'x':
+                 if (!pa_parse_number (&s, 3))
+                   break;
+                 num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
+                 CHECK_FIELD (num, 31, 0, 0);
+                 INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
 
 
-static int
-pa_parse_addb_64_cmpltr (s)
-     char **s;
-{
-  int cmpltr;
-  char *name = *s + 1;
-  char c;
-  char *save_s = *s;
-  int nullify = 0;
+               default:
+                 abort ();
+               }
+             break;
 
 
-  cmpltr = 0;
-  if (**s == ',')
-    {
-      *s += 1;
-      while (**s != ',' && **s != ' ' && **s != '\t')
-       *s += 1;
-      c = **s;
-      **s = 0x00;
-      if (strcmp (name, "=") == 0)
-       {
-         cmpltr = 1;
-       }
-      else if (strcmp (name, "<") == 0)
-       {
-         cmpltr = 2;
-       }
-      else if (strcmp (name, "<=") == 0)
-       {
-         cmpltr = 3;
-       }
-      else if (strcasecmp (name, "nuv") == 0)
-       {
-         cmpltr = 4;
-       }
-      else if (strcasecmp (name, "*=") == 0)
-       {
-         cmpltr = 5;
-       }
-      else if (strcasecmp (name, "*<") == 0)
-       {
-         cmpltr = 6;
-       }
-      else if (strcasecmp (name, "*<=") == 0)
-       {
-         cmpltr = 7;
-       }
-      else if (strcmp (name, "tr") == 0)
-       {
-         cmpltr = 8;
-       }
-      else if (strcmp (name, "<>") == 0)
-       {
-         cmpltr = 9;
-       }
-      else if (strcmp (name, ">=") == 0)
-       {
-         cmpltr = 10;
-       }
-      else if (strcmp (name, ">") == 0)
-       {
-         cmpltr = 11;
-       }
-      else if (strcasecmp (name, "uv") == 0)
-       {
-         cmpltr = 12;
-       }
-      else if (strcasecmp (name, "*<>") == 0)
-       {
-         cmpltr = 13;
-       }
-      else if (strcasecmp (name, "*>=") == 0)
-       {
-         cmpltr = 14;
+           default:
+             abort ();
+           }
+         break;
        }
        }
-      else if (strcasecmp (name, "*>") == 0)
+
+      /* If this instruction is specific to a particular architecture,
+        then set a new architecture.  This automatic promotion crud is
+        for compatibility with HP's old assemblers only.  */
+      if (match == TRUE
+         && bfd_get_mach (stdoutput) < insn->arch
+         && !bfd_set_arch_mach (stdoutput, bfd_arch_hppa, insn->arch))
        {
        {
-         cmpltr = 15;
+         as_warn (_("could not update architecture and machine"));
+         match = FALSE;
        }
        }
-      /* If we have something like addb,n then there is no condition
-         completer.  */
-      else if (strcasecmp (name, "n") == 0)
+
+ failed:
+      /* Check if the args matched.  */
+      if (!match)
        {
        {
-         cmpltr = 0;
-         nullify = 1;
+         if (&insn[1] - pa_opcodes < (int) NUMOPCODES
+             && !strcmp (insn->name, insn[1].name))
+           {
+             ++insn;
+             s = argstart;
+             continue;
+           }
+         else
+           {
+             as_bad (_("Invalid operands %s"), error_message);
+             return;
+           }
        }
        }
-      else
+      break;
+    }
+
+  the_insn.opcode = opcode;
+}
+
+/* Assemble a single instruction storing it into a frag.  */
+
+void
+md_assemble (char *str)
+{
+  char *to;
+
+  /* The had better be something to assemble.  */
+  assert (str);
+
+  /* If we are within a procedure definition, make sure we've
+     defined a label for the procedure; handle case where the
+     label was defined after the .PROC directive.
+
+     Note there's not need to diddle with the segment or fragment
+     for the label symbol in this case.  We have already switched
+     into the new $CODE$ subspace at this point.  */
+  if (within_procedure && last_call_info->start_symbol == NULL)
+    {
+      label_symbol_struct *label_symbol = pa_get_label ();
+
+      if (label_symbol)
        {
        {
-         cmpltr = -1;
+         if (label_symbol->lss_label)
+           {
+             last_call_info->start_symbol = label_symbol->lss_label;
+             symbol_get_bfdsym (label_symbol->lss_label)->flags
+               |= BSF_FUNCTION;
+#ifdef OBJ_SOM
+             /* Also handle allocation of a fixup to hold the unwind
+                information when the label appears after the proc/procend.  */
+             if (within_entry_exit)
+               {
+                 char *where;
+                 unsigned int u;
+
+                 where = frag_more (0);
+                 u = UNWIND_LOW32 (&last_call_info->ci_unwind.descriptor);
+                 fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
+                               NULL, (offsetT) 0, NULL,
+                               0, R_HPPA_ENTRY, e_fsel, 0, 0, u);
+               }
+#endif
+           }
+         else
+           as_bad (_("Missing function name for .PROC (corrupted label chain)"));
        }
        }
-      **s = c;
+      else
+       as_bad (_("Missing function name for .PROC"));
     }
 
     }
 
-  /* Reset pointers if this was really a ,n for a branch instruction.  */
-  if (nullify)
-    *s = save_s;
+  /* Assemble the instruction.  Results are saved into "the_insn".  */
+  pa_ip (str);
 
 
-  return cmpltr;
+  /* Get somewhere to put the assembled instruction.  */
+  to = frag_more (4);
+
+  /* Output the opcode.  */
+  md_number_to_chars (to, the_insn.opcode, 4);
+
+  /* If necessary output more stuff.  */
+  if (the_insn.reloc != R_HPPA_NONE)
+    fix_new_hppa (frag_now, (to - frag_now->fr_literal), 4, NULL,
+                 (offsetT) 0, &the_insn.exp, the_insn.pcrel,
+                 the_insn.reloc, the_insn.field_selector,
+                 the_insn.format, the_insn.arg_reloc, 0);
+
+#ifdef OBJ_ELF
+  dwarf2_emit_insn (4);
+#endif
 }
 
 #ifdef OBJ_SOM
 /* Handle an alignment directive.  Special so that we can update the
    alignment of the subspace if necessary.  */
 static void
 }
 
 #ifdef OBJ_SOM
 /* Handle an alignment directive.  Special so that we can update the
    alignment of the subspace if necessary.  */
 static void
-pa_align (bytes)
-     int bytes;
+pa_align (int bytes)
 {
   /* We must have a valid space and subspace.  */
   pa_check_current_space_and_subspace ();
 {
   /* We must have a valid space and subspace.  */
   pa_check_current_space_and_subspace ();
@@ -5950,8 +5815,7 @@ pa_align (bytes)
 /* Handle a .BLOCK type pseudo-op.  */
 
 static void
 /* Handle a .BLOCK type pseudo-op.  */
 
 static void
-pa_block (z)
-     int z ATTRIBUTE_UNUSED;
+pa_block (int z ATTRIBUTE_UNUSED)
 {
   unsigned int temp_size;
 
 {
   unsigned int temp_size;
 
@@ -5981,8 +5845,7 @@ pa_block (z)
 /* Handle a .begin_brtab and .end_brtab pseudo-op.  */
 
 static void
 /* Handle a .begin_brtab and .end_brtab pseudo-op.  */
 
 static void
-pa_brtab (begin)
-     int begin ATTRIBUTE_UNUSED;
+pa_brtab (int begin ATTRIBUTE_UNUSED)
 {
 
 #ifdef OBJ_SOM
 {
 
 #ifdef OBJ_SOM
@@ -6002,8 +5865,7 @@ pa_brtab (begin)
 /* Handle a .begin_try and .end_try pseudo-op.  */
 
 static void
 /* Handle a .begin_try and .end_try pseudo-op.  */
 
 static void
-pa_try (begin)
-     int begin ATTRIBUTE_UNUSED;
+pa_try (int begin ATTRIBUTE_UNUSED)
 {
 #ifdef OBJ_SOM
   expressionS exp;
 {
 #ifdef OBJ_SOM
   expressionS exp;
@@ -6024,29 +5886,11 @@ pa_try (begin)
   demand_empty_rest_of_line ();
 }
 
   demand_empty_rest_of_line ();
 }
 
-/* Handle a .CALL pseudo-op.  This involves storing away information
-   about where arguments are to be found so the linker can detect
-   (and correct) argument location mismatches between caller and callee.  */
-
-static void
-pa_call (unused)
-     int unused ATTRIBUTE_UNUSED;
-{
-#ifdef OBJ_SOM
-  /* We must have a valid space and subspace.  */
-  pa_check_current_space_and_subspace ();
-#endif
-
-  pa_call_args (&last_call_desc);
-  demand_empty_rest_of_line ();
-}
-
 /* Do the dirty work of building a call descriptor which describes
    where the caller placed arguments to a function call.  */
 
 static void
 /* Do the dirty work of building a call descriptor which describes
    where the caller placed arguments to a function call.  */
 
 static void
-pa_call_args (call_desc)
-     struct call_desc *call_desc;
+pa_call_args (struct call_desc *call_desc)
 {
   char *name, c, *p;
   unsigned int temp, arg_reloc;
 {
   char *name, c, *p;
   unsigned int temp, arg_reloc;
@@ -6089,24 +5933,38 @@ pa_call_args (call_desc)
     }
 }
 
     }
 }
 
+/* Handle a .CALL pseudo-op.  This involves storing away information
+   about where arguments are to be found so the linker can detect
+   (and correct) argument location mismatches between caller and callee.  */
+
+static void
+pa_call (int unused ATTRIBUTE_UNUSED)
+{
+#ifdef OBJ_SOM
+  /* We must have a valid space and subspace.  */
+  pa_check_current_space_and_subspace ();
+#endif
+
+  pa_call_args (&last_call_desc);
+  demand_empty_rest_of_line ();
+}
+
 /* Return TRUE if FRAG1 and FRAG2 are the same.  */
 
 /* Return TRUE if FRAG1 and FRAG2 are the same.  */
 
-static int
-is_same_frag (frag1, frag2)
-     fragS *frag1;
-     fragS *frag2;
+static bfd_boolean
+is_same_frag (fragS *frag1, fragS *frag2)
 {
 
   if (frag1 == NULL)
 {
 
   if (frag1 == NULL)
-    return (FALSE);
+    return FALSE;
   else if (frag2 == NULL)
   else if (frag2 == NULL)
-    return (FALSE);
+    return FALSE;
   else if (frag1 == frag2)
   else if (frag1 == frag2)
-    return (TRUE);
+    return TRUE;
   else if (frag2->fr_type == rs_fill && frag2->fr_fix == 0)
     return (is_same_frag (frag1, frag2->fr_next));
   else
   else if (frag2->fr_type == rs_fill && frag2->fr_fix == 0)
     return (is_same_frag (frag1, frag2->fr_next));
   else
-    return (FALSE);
+    return FALSE;
 }
 
 #ifdef OBJ_ELF
 }
 
 #ifdef OBJ_ELF
@@ -6116,8 +5974,7 @@ is_same_frag (frag1, frag2)
    of the unwind spaces.  */
 
 static void
    of the unwind spaces.  */
 
 static void
-pa_build_unwind_subspace (call_info)
-     struct call_info *call_info;
+pa_build_unwind_subspace (struct call_info *call_info)
 {
   asection *seg, *save_seg;
   subsegT save_subseg;
 {
   asection *seg, *save_seg;
   subsegT save_subseg;
@@ -6189,8 +6046,7 @@ pa_build_unwind_subspace (call_info)
    .ENTER and .LEAVE.  */
 
 static void
    .ENTER and .LEAVE.  */
 
 static void
-pa_callinfo (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_callinfo (int unused ATTRIBUTE_UNUSED)
 {
   char *name, c, *p;
   int temp;
 {
   char *name, c, *p;
   int temp;
@@ -6332,9 +6188,9 @@ pa_callinfo (unused)
 #if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
 /* Switch to the text space.  Like s_text, but delete our
    label when finished.  */
 #if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
 /* Switch to the text space.  Like s_text, but delete our
    label when finished.  */
+
 static void
 static void
-pa_text (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_text (int unused ATTRIBUTE_UNUSED)
 {
 #ifdef OBJ_SOM
   current_space = is_defined_space ("$TEXT$");
 {
 #ifdef OBJ_SOM
   current_space = is_defined_space ("$TEXT$");
@@ -6347,9 +6203,9 @@ pa_text (unused)
 }
 
 /* Switch to the data space.  As usual delete our label.  */
 }
 
 /* Switch to the data space.  As usual delete our label.  */
+
 static void
 static void
-pa_data (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_data (int unused ATTRIBUTE_UNUSED)
 {
 #ifdef OBJ_SOM
   current_space = is_defined_space ("$PRIVATE$");
 {
 #ifdef OBJ_SOM
   current_space = is_defined_space ("$PRIVATE$");
@@ -6381,8 +6237,7 @@ pa_data (unused)
    This also makes error detection all but impossible.  */
 
 static void
    This also makes error detection all but impossible.  */
 
 static void
-pa_comm (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_comm (int unused ATTRIBUTE_UNUSED)
 {
   unsigned int size;
   symbolS *symbol;
 {
   unsigned int size;
   symbolS *symbol;
@@ -6415,16 +6270,15 @@ pa_comm (unused)
 /* Process a .END pseudo-op.  */
 
 static void
 /* Process a .END pseudo-op.  */
 
 static void
-pa_end (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_end (int unused ATTRIBUTE_UNUSED)
 {
   demand_empty_rest_of_line ();
 }
 
 /* Process a .ENTER pseudo-op.  This is not supported.  */
 {
   demand_empty_rest_of_line ();
 }
 
 /* Process a .ENTER pseudo-op.  This is not supported.  */
+
 static void
 static void
-pa_enter (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_enter (int unused ATTRIBUTE_UNUSED)
 {
 #ifdef OBJ_SOM
   /* We must have a valid space and subspace.  */
 {
 #ifdef OBJ_SOM
   /* We must have a valid space and subspace.  */
@@ -6437,9 +6291,9 @@ pa_enter (unused)
 
 /* Process a .ENTRY pseudo-op.  .ENTRY marks the beginning of the
    procedure.  */
 
 /* Process a .ENTRY pseudo-op.  .ENTRY marks the beginning of the
    procedure.  */
+
 static void
 static void
-pa_entry (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_entry (int unused ATTRIBUTE_UNUSED)
 {
 #ifdef OBJ_SOM
   /* We must have a valid space and subspace.  */
 {
 #ifdef OBJ_SOM
   /* We must have a valid space and subspace.  */
@@ -6486,10 +6340,9 @@ pa_entry (unused)
 static int fudge_reg_expressions;
 
 int
 static int fudge_reg_expressions;
 
 int
-hppa_force_reg_syms_absolute (resultP, op, rightP)
-     expressionS *resultP;
-     operatorT op ATTRIBUTE_UNUSED;
-     expressionS *rightP;
+hppa_force_reg_syms_absolute (expressionS *resultP,
+                             operatorT op ATTRIBUTE_UNUSED,
+                             expressionS *rightP)
 {
   if (fudge_reg_expressions
       && rightP->X_op == O_register
 {
   if (fudge_reg_expressions
       && rightP->X_op == O_register
@@ -6504,8 +6357,7 @@ hppa_force_reg_syms_absolute (resultP, op, rightP)
 /* Handle a .EQU pseudo-op.  */
 
 static void
 /* Handle a .EQU pseudo-op.  */
 
 static void
-pa_equ (reg)
-     int reg;
+pa_equ (int reg)
 {
   label_symbol_struct *label_symbol = pa_get_label ();
   symbolS *symbol;
 {
   label_symbol_struct *label_symbol = pa_get_label ();
   symbolS *symbol;
@@ -6553,12 +6405,75 @@ pa_equ (reg)
   demand_empty_rest_of_line ();
 }
 
   demand_empty_rest_of_line ();
 }
 
+#ifdef OBJ_ELF
+/* Mark the end of a function so that it's possible to compute
+   the size of the function in elf_hppa_final_processing.  */
+
+static void
+hppa_elf_mark_end_of_function (void)
+{
+  /* ELF does not have EXIT relocations.  All we do is create a
+     temporary symbol marking the end of the function.  */
+  char *name;
+
+  if (last_call_info == NULL || last_call_info->start_symbol == NULL)
+    {
+      /* We have already warned about a missing label,
+        or other problems.  */
+      return;
+    }
+
+  name = xmalloc (strlen ("L$\001end_")
+                 + strlen (S_GET_NAME (last_call_info->start_symbol))
+                 + 1);
+  if (name)
+    {
+      symbolS *symbolP;
+
+      strcpy (name, "L$\001end_");
+      strcat (name, S_GET_NAME (last_call_info->start_symbol));
+
+      /* If we have a .exit followed by a .procend, then the
+        symbol will have already been defined.  */
+      symbolP = symbol_find (name);
+      if (symbolP)
+       {
+         /* The symbol has already been defined!  This can
+            happen if we have a .exit followed by a .procend.
+
+            This is *not* an error.  All we want to do is free
+            the memory we just allocated for the name and continue.  */
+         xfree (name);
+       }
+      else
+       {
+         /* symbol value should be the offset of the
+            last instruction of the function */
+         symbolP = symbol_new (name, now_seg, (valueT) (frag_now_fix () - 4),
+                               frag_now);
+
+         assert (symbolP);
+         S_CLEAR_EXTERNAL (symbolP);
+         symbol_table_insert (symbolP);
+       }
+
+      if (symbolP)
+       last_call_info->end_symbol = symbolP;
+      else
+       as_bad (_("Symbol '%s' could not be created."), name);
+
+    }
+  else
+    as_bad (_("No memory for symbol name."));
+}
+#endif
+
 /* Helper function.  Does processing for the end of a function.  This
    usually involves creating some relocations or building special
    symbols to mark the end of the function.  */
 
 static void
 /* Helper function.  Does processing for the end of a function.  This
    usually involves creating some relocations or building special
    symbols to mark the end of the function.  */
 
 static void
-process_exit ()
+process_exit (void)
 {
   char *where;
 
 {
   char *where;
 
@@ -6590,8 +6505,7 @@ process_exit ()
 /* Process a .EXIT pseudo-op.  */
 
 static void
 /* Process a .EXIT pseudo-op.  */
 
 static void
-pa_exit (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_exit (int unused ATTRIBUTE_UNUSED)
 {
 #ifdef OBJ_SOM
   /* We must have a valid space and subspace.  */
 {
 #ifdef OBJ_SOM
   /* We must have a valid space and subspace.  */
@@ -6618,54 +6532,10 @@ pa_exit (unused)
   demand_empty_rest_of_line ();
 }
 
   demand_empty_rest_of_line ();
 }
 
-/* Process a .EXPORT directive.  This makes functions external
-   and provides information such as argument relocation entries
-   to callers.  */
-
-static void
-pa_export (unused)
-     int unused ATTRIBUTE_UNUSED;
-{
-  char *name, c, *p;
-  symbolS *symbol;
-
-  name = input_line_pointer;
-  c = get_symbol_end ();
-  /* Make sure the given symbol exists.  */
-  if ((symbol = symbol_find_or_make (name)) == NULL)
-    {
-      as_bad (_("Cannot define export symbol: %s\n"), name);
-      p = input_line_pointer;
-      *p = c;
-      input_line_pointer++;
-    }
-  else
-    {
-      /* OK.  Set the external bits and process argument relocations.
-         For the HP, weak and global are not mutually exclusive.
-         S_SET_EXTERNAL will not set BSF_GLOBAL if WEAK is set.
-         Call S_SET_EXTERNAL to get the other processing.  Manually
-         set BSF_GLOBAL when we get back.  */
-      S_SET_EXTERNAL (symbol);
-      symbol_get_bfdsym (symbol)->flags |= BSF_GLOBAL;
-      p = input_line_pointer;
-      *p = c;
-      if (!is_end_of_statement ())
-       {
-         input_line_pointer++;
-         pa_type_args (symbol, 1);
-       }
-    }
-
-  demand_empty_rest_of_line ();
-}
-
 /* Helper function to process arguments to a .EXPORT pseudo-op.  */
 
 static void
 /* Helper function to process arguments to a .EXPORT pseudo-op.  */
 
 static void
-pa_type_args (symbolP, is_export)
-     symbolS *symbolP;
-     int is_export;
+pa_type_args (symbolS *symbolP, int is_export)
 {
   char *name, c, *p;
   unsigned int temp, arg_reloc;
 {
   char *name, c, *p;
   unsigned int temp, arg_reloc;
@@ -6673,7 +6543,6 @@ pa_type_args (symbolP, is_export)
   asymbol *bfdsym = symbol_get_bfdsym (symbolP);
 
   if (strncasecmp (input_line_pointer, "absolute", 8) == 0)
   asymbol *bfdsym = symbol_get_bfdsym (symbolP);
 
   if (strncasecmp (input_line_pointer, "absolute", 8) == 0)
-
     {
       input_line_pointer += 8;
       bfdsym->flags &= ~BSF_FUNCTION;
     {
       input_line_pointer += 8;
       bfdsym->flags &= ~BSF_FUNCTION;
@@ -6813,9 +6682,50 @@ pa_type_args (symbolP, is_export)
          p = input_line_pointer;
          *p = c;
        }
          p = input_line_pointer;
          *p = c;
        }
-      if (!is_end_of_statement ())
-       input_line_pointer++;
+      if (!is_end_of_statement ())
+       input_line_pointer++;
+    }
+}
+
+/* Process a .EXPORT directive.  This makes functions external
+   and provides information such as argument relocation entries
+   to callers.  */
+
+static void
+pa_export (int unused ATTRIBUTE_UNUSED)
+{
+  char *name, c, *p;
+  symbolS *symbol;
+
+  name = input_line_pointer;
+  c = get_symbol_end ();
+  /* Make sure the given symbol exists.  */
+  if ((symbol = symbol_find_or_make (name)) == NULL)
+    {
+      as_bad (_("Cannot define export symbol: %s\n"), name);
+      p = input_line_pointer;
+      *p = c;
+      input_line_pointer++;
+    }
+  else
+    {
+      /* OK.  Set the external bits and process argument relocations.
+         For the HP, weak and global are not mutually exclusive.
+         S_SET_EXTERNAL will not set BSF_GLOBAL if WEAK is set.
+         Call S_SET_EXTERNAL to get the other processing.  Manually
+         set BSF_GLOBAL when we get back.  */
+      S_SET_EXTERNAL (symbol);
+      symbol_get_bfdsym (symbol)->flags |= BSF_GLOBAL;
+      p = input_line_pointer;
+      *p = c;
+      if (!is_end_of_statement ())
+       {
+         input_line_pointer++;
+         pa_type_args (symbol, 1);
+       }
     }
     }
+
+  demand_empty_rest_of_line ();
 }
 
 /* Handle an .IMPORT pseudo-op.  Any symbol referenced in a given
 }
 
 /* Handle an .IMPORT pseudo-op.  Any symbol referenced in a given
@@ -6823,8 +6733,7 @@ pa_type_args (symbolP, is_export)
    explicitly IMPORTED from another.  */
 
 static void
    explicitly IMPORTED from another.  */
 
 static void
-pa_import (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_import (int unused ATTRIBUTE_UNUSED)
 {
   char *name, c, *p;
   symbolS *symbol;
 {
   char *name, c, *p;
   symbolS *symbol;
@@ -6875,8 +6784,7 @@ pa_import (unused)
 /* Handle a .LABEL pseudo-op.  */
 
 static void
 /* Handle a .LABEL pseudo-op.  */
 
 static void
-pa_label (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_label (int unused ATTRIBUTE_UNUSED)
 {
   char *name, c, *p;
 
 {
   char *name, c, *p;
 
@@ -6905,8 +6813,7 @@ pa_label (unused)
 /* Handle a .LEAVE pseudo-op.  This is not supported yet.  */
 
 static void
 /* Handle a .LEAVE pseudo-op.  This is not supported yet.  */
 
 static void
-pa_leave (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_leave (int unused ATTRIBUTE_UNUSED)
 {
 #ifdef OBJ_SOM
   /* We must have a valid space and subspace.  */
 {
 #ifdef OBJ_SOM
   /* We must have a valid space and subspace.  */
@@ -6920,8 +6827,7 @@ pa_leave (unused)
 /* Handle a .LEVEL pseudo-op.  */
 
 static void
 /* Handle a .LEVEL pseudo-op.  */
 
 static void
-pa_level (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_level (int unused ATTRIBUTE_UNUSED)
 {
   char *level;
 
 {
   char *level;
 
@@ -6961,8 +6867,7 @@ pa_level (unused)
 /* Handle a .ORIGIN pseudo-op.  */
 
 static void
 /* Handle a .ORIGIN pseudo-op.  */
 
 static void
-pa_origin (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_origin (int unused ATTRIBUTE_UNUSED)
 {
 #ifdef OBJ_SOM
   /* We must have a valid space and subspace.  */
 {
 #ifdef OBJ_SOM
   /* We must have a valid space and subspace.  */
@@ -6977,8 +6882,7 @@ pa_origin (unused)
    is for static functions.  FIXME.  Should share more code with .EXPORT.  */
 
 static void
    is for static functions.  FIXME.  Should share more code with .EXPORT.  */
 
 static void
-pa_param (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_param (int unused ATTRIBUTE_UNUSED)
 {
   char *name, c, *p;
   symbolS *symbol;
 {
   char *name, c, *p;
   symbolS *symbol;
@@ -7012,8 +6916,7 @@ pa_param (unused)
    of a procedure from a syntactical point of view.  */
 
 static void
    of a procedure from a syntactical point of view.  */
 
 static void
-pa_proc (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_proc (int unused ATTRIBUTE_UNUSED)
 {
   struct call_info *call_info;
 
 {
   struct call_info *call_info;
 
@@ -7030,7 +6933,7 @@ pa_proc (unused)
   within_procedure = TRUE;
 
   /* Create another call_info structure.  */
   within_procedure = TRUE;
 
   /* Create another call_info structure.  */
-  call_info = (struct call_info *) xmalloc (sizeof (struct call_info));
+  call_info = xmalloc (sizeof (struct call_info));
 
   if (!call_info)
     as_fatal (_("Cannot allocate unwind descriptor\n"));
 
   if (!call_info)
     as_fatal (_("Cannot allocate unwind descriptor\n"));
@@ -7082,10 +6985,8 @@ pa_proc (unused)
    appropriate pseudo-ops were found within the procedure.  */
 
 static void
    appropriate pseudo-ops were found within the procedure.  */
 
 static void
-pa_procend (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_procend (int unused ATTRIBUTE_UNUSED)
 {
 {
-
 #ifdef OBJ_SOM
   /* We must have a valid space and subspace.  */
   pa_check_current_space_and_subspace ();
 #ifdef OBJ_SOM
   /* We must have a valid space and subspace.  */
   pa_check_current_space_and_subspace ();
@@ -7157,8 +7058,7 @@ pa_procend (unused)
    return log2 (VALUE).  Else return -1.  */
 
 static int
    return log2 (VALUE).  Else return -1.  */
 
 static int
-exact_log2 (value)
-     int value;
+exact_log2 (int value)
 {
   int shift = 0;
 
 {
   int shift = 0;
 
@@ -7174,7 +7074,7 @@ exact_log2 (value)
 /* Check to make sure we have a valid space and subspace.  */
 
 static void
 /* Check to make sure we have a valid space and subspace.  */
 
 static void
-pa_check_current_space_and_subspace ()
+pa_check_current_space_and_subspace (void)
 {
   if (current_space == NULL)
     as_fatal (_("Not in a space.\n"));
 {
   if (current_space == NULL)
     as_fatal (_("Not in a space.\n"));
@@ -7188,9 +7088,7 @@ pa_check_current_space_and_subspace ()
    by the parameters to the .SPACE directive.  */
 
 static sd_chain_struct *
    by the parameters to the .SPACE directive.  */
 
 static sd_chain_struct *
-pa_parse_space_stmt (space_name, create_flag)
-     char *space_name;
-     int create_flag;
+pa_parse_space_stmt (char *space_name, int create_flag)
 {
   char *name, *ptemp, c;
   char loadable, defined, private, sort;
 {
   char *name, *ptemp, c;
   char loadable, defined, private, sort;
@@ -7198,7 +7096,7 @@ pa_parse_space_stmt (space_name, create_flag)
   asection *seg = NULL;
   sd_chain_struct *space;
 
   asection *seg = NULL;
   sd_chain_struct *space;
 
-  /* load default values */
+  /* Load default values.  */
   spnum = 0;
   sort = 0;
   loadable = TRUE;
   spnum = 0;
   sort = 0;
   loadable = TRUE;
@@ -7310,8 +7208,7 @@ pa_parse_space_stmt (space_name, create_flag)
    given space, creating the new space if necessary.  */
 
 static void
    given space, creating the new space if necessary.  */
 
 static void
-pa_space (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_space (int unused ATTRIBUTE_UNUSED)
 {
   char *name, c, *space_name, *save_s;
   sd_chain_struct *sd_chain;
 {
   char *name, c, *space_name, *save_s;
   sd_chain_struct *sd_chain;
@@ -7430,8 +7327,7 @@ pa_space (unused)
 /* Switch to a new space.  (I think).  FIXME.  */
 
 static void
 /* Switch to a new space.  (I think).  FIXME.  */
 
 static void
-pa_spnum (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_spnum (int unused ATTRIBUTE_UNUSED)
 {
   char *name;
   char c;
 {
   char *name;
   char c;
@@ -7460,8 +7356,7 @@ pa_spnum (unused)
    they're broken up into subroutines.  */
 
 static void
    they're broken up into subroutines.  */
 
 static void
-pa_subspace (create_new)
-     int create_new;
+pa_subspace (int create_new)
 {
   char *name, *ss_name, c;
   char loadable, code_only, comdat, common, dup_common, zero, sort;
 {
   char *name, *ss_name, c;
   char loadable, code_only, comdat, common, dup_common, zero, sort;
@@ -7699,7 +7594,7 @@ pa_subspace (create_new)
 /* Create default space and subspace dictionaries.  */
 
 static void
 /* Create default space and subspace dictionaries.  */
 
 static void
-pa_spaces_begin ()
+pa_spaces_begin (void)
 {
   int i;
 
 {
   int i;
 
@@ -7826,25 +7721,23 @@ pa_spaces_begin ()
    by the given parameters.  */
 
 static sd_chain_struct *
    by the given parameters.  */
 
 static sd_chain_struct *
-create_new_space (name, spnum, loadable, defined, private,
-                 sort, seg, user_defined)
-     char *name;
-     int spnum;
-     int loadable ATTRIBUTE_UNUSED;
-     int defined;
-     int private;
-     int sort;
-     asection *seg;
-     int user_defined;
+create_new_space (char *name,
+                 int spnum,
+                 int loadable ATTRIBUTE_UNUSED,
+                 int defined,
+                 int private,
+                 int sort,
+                 asection *seg,
+                 int user_defined)
 {
   sd_chain_struct *chain_entry;
 
 {
   sd_chain_struct *chain_entry;
 
-  chain_entry = (sd_chain_struct *) xmalloc (sizeof (sd_chain_struct));
+  chain_entry = xmalloc (sizeof (sd_chain_struct));
   if (!chain_entry)
     as_fatal (_("Out of memory: could not allocate new space chain entry: %s\n"),
              name);
 
   if (!chain_entry)
     as_fatal (_("Out of memory: could not allocate new space chain entry: %s\n"),
              name);
 
-  SPACE_NAME (chain_entry) = (char *) xmalloc (strlen (name) + 1);
+  SPACE_NAME (chain_entry) = xmalloc (strlen (name) + 1);
   strcpy (SPACE_NAME (chain_entry), name);
   SPACE_DEFINED (chain_entry) = defined;
   SPACE_USER_DEFINED (chain_entry) = user_defined;
   strcpy (SPACE_NAME (chain_entry), name);
   SPACE_DEFINED (chain_entry) = defined;
   SPACE_USER_DEFINED (chain_entry) = user_defined;
@@ -7910,29 +7803,28 @@ create_new_space (name, spnum, loadable, defined, private,
    order as defined by the SORT entries.  */
 
 static ssd_chain_struct *
    order as defined by the SORT entries.  */
 
 static ssd_chain_struct *
-create_new_subspace (space, name, loadable, code_only, comdat, common,
-                    dup_common, is_zero, sort, access, space_index,
-                    alignment, quadrant, seg)
-     sd_chain_struct *space;
-     char *name;
-     int loadable ATTRIBUTE_UNUSED;
-     int code_only ATTRIBUTE_UNUSED;
-     int comdat, common, dup_common;
-     int is_zero ATTRIBUTE_UNUSED;
-     int sort;
-     int access;
-     int space_index ATTRIBUTE_UNUSED;
-     int alignment ATTRIBUTE_UNUSED;
-     int quadrant;
-     asection *seg;
+create_new_subspace (sd_chain_struct *space,
+                    char *name,
+                    int loadable ATTRIBUTE_UNUSED,
+                    int code_only ATTRIBUTE_UNUSED,
+                    int comdat,
+                    int common,
+                    int dup_common,
+                    int is_zero ATTRIBUTE_UNUSED,
+                    int sort,
+                    int access,
+                    int space_index ATTRIBUTE_UNUSED,
+                    int alignment ATTRIBUTE_UNUSED,
+                    int quadrant,
+                    asection *seg)
 {
   ssd_chain_struct *chain_entry;
 
 {
   ssd_chain_struct *chain_entry;
 
-  chain_entry = (ssd_chain_struct *) xmalloc (sizeof (ssd_chain_struct));
+  chain_entry = xmalloc (sizeof (ssd_chain_struct));
   if (!chain_entry)
     as_fatal (_("Out of memory: could not allocate new subspace chain entry: %s\n"), name);
 
   if (!chain_entry)
     as_fatal (_("Out of memory: could not allocate new subspace chain entry: %s\n"), name);
 
-  SUBSPACE_NAME (chain_entry) = (char *) xmalloc (strlen (name) + 1);
+  SUBSPACE_NAME (chain_entry) = xmalloc (strlen (name) + 1);
   strcpy (SUBSPACE_NAME (chain_entry), name);
 
   /* Initialize subspace_defined.  When we hit a .subspace directive
   strcpy (SUBSPACE_NAME (chain_entry), name);
 
   /* Initialize subspace_defined.  When we hit a .subspace directive
@@ -7986,22 +7878,20 @@ create_new_subspace (space, name, loadable, code_only, comdat, common,
    various arguments.   Return the modified subspace chain entry.  */
 
 static ssd_chain_struct *
    various arguments.   Return the modified subspace chain entry.  */
 
 static ssd_chain_struct *
-update_subspace (space, name, loadable, code_only, comdat, common, dup_common,
-                sort, zero, access, space_index, alignment, quadrant, section)
-     sd_chain_struct *space;
-     char *name;
-     int loadable ATTRIBUTE_UNUSED;
-     int code_only ATTRIBUTE_UNUSED;
-     int comdat;
-     int common;
-     int dup_common;
-     int zero ATTRIBUTE_UNUSED;
-     int sort;
-     int access;
-     int space_index ATTRIBUTE_UNUSED;
-     int alignment ATTRIBUTE_UNUSED;
-     int quadrant;
-     asection *section;
+update_subspace (sd_chain_struct *space,
+                char *name,
+                int loadable ATTRIBUTE_UNUSED,
+                int code_only ATTRIBUTE_UNUSED,
+                int comdat,
+                int common,
+                int dup_common,
+                int sort,
+                int zero ATTRIBUTE_UNUSED,
+                int access,
+                int space_index ATTRIBUTE_UNUSED,
+                int alignment ATTRIBUTE_UNUSED,
+                int quadrant,
+                asection *section)
 {
   ssd_chain_struct *chain_entry;
 
 {
   ssd_chain_struct *chain_entry;
 
@@ -8019,18 +7909,15 @@ update_subspace (space, name, loadable, code_only, comdat, common, dup_common,
    NULL if no such space exists.  */
 
 static sd_chain_struct *
    NULL if no such space exists.  */
 
 static sd_chain_struct *
-is_defined_space (name)
-     char *name;
+is_defined_space (char *name)
 {
   sd_chain_struct *chain_pointer;
 
   for (chain_pointer = space_dict_root;
        chain_pointer;
        chain_pointer = chain_pointer->sd_next)
 {
   sd_chain_struct *chain_pointer;
 
   for (chain_pointer = space_dict_root;
        chain_pointer;
        chain_pointer = chain_pointer->sd_next)
-    {
-      if (strcmp (SPACE_NAME (chain_pointer), name) == 0)
-       return chain_pointer;
-    }
+    if (strcmp (SPACE_NAME (chain_pointer), name) == 0)
+      return chain_pointer;
 
   /* No mapping from segment to space was found.  Return NULL.  */
   return NULL;
 
   /* No mapping from segment to space was found.  Return NULL.  */
   return NULL;
@@ -8043,8 +7930,7 @@ is_defined_space (name)
    so a linear exhaustive search is OK here.  */
 
 static sd_chain_struct *
    so a linear exhaustive search is OK here.  */
 
 static sd_chain_struct *
-pa_segment_to_space (seg)
-     asection *seg;
+pa_segment_to_space (asection *seg)
 {
   sd_chain_struct *space_chain;
 
 {
   sd_chain_struct *space_chain;
 
@@ -8052,10 +7938,8 @@ pa_segment_to_space (seg)
   for (space_chain = space_dict_root;
        space_chain;
        space_chain = space_chain->sd_next)
   for (space_chain = space_dict_root;
        space_chain;
        space_chain = space_chain->sd_next)
-    {
-      if (space_chain->sd_seg == seg)
-       return space_chain;
-    }
+    if (space_chain->sd_seg == seg)
+      return space_chain;
 
   /* Mapping was not found.  Return NULL.  */
   return NULL;
 
   /* Mapping was not found.  Return NULL.  */
   return NULL;
@@ -8068,14 +7952,13 @@ pa_segment_to_space (seg)
    the first (i.e., default) subspace is preferable in most situations.
    For example, it wouldn't be desirable to merge COMDAT data with non
    COMDAT data.
    the first (i.e., default) subspace is preferable in most situations.
    For example, it wouldn't be desirable to merge COMDAT data with non
    COMDAT data.
-    
+
    Uses a linear search through all the spaces and subspaces, this may
    not be appropriate if we ever being placing each function in its
    own subspace.  */
 
 static ssd_chain_struct *
    Uses a linear search through all the spaces and subspaces, this may
    not be appropriate if we ever being placing each function in its
    own subspace.  */
 
 static ssd_chain_struct *
-is_defined_subspace (name)
-     char *name;
+is_defined_subspace (char *name)
 {
   sd_chain_struct *space_chain;
   ssd_chain_struct *subspace_chain;
 {
   sd_chain_struct *space_chain;
   ssd_chain_struct *subspace_chain;
@@ -8105,9 +7988,7 @@ is_defined_subspace (name)
    to become more efficient.  */
 
 static ssd_chain_struct *
    to become more efficient.  */
 
 static ssd_chain_struct *
-pa_subsegment_to_subspace (seg, subseg)
-     asection *seg;
-     subsegT subseg;
+pa_subsegment_to_subspace (asection *seg, subsegT subseg)
 {
   sd_chain_struct *space_chain;
   ssd_chain_struct *subspace_chain;
 {
   sd_chain_struct *space_chain;
   ssd_chain_struct *subspace_chain;
@@ -8139,8 +8020,7 @@ pa_subsegment_to_subspace (seg, subseg)
    that was found or NULL on failure.  */
 
 static sd_chain_struct *
    that was found or NULL on failure.  */
 
 static sd_chain_struct *
-pa_find_space_by_number (number)
-     int number;
+pa_find_space_by_number (int number)
 {
   sd_chain_struct *space_chain;
 
 {
   sd_chain_struct *space_chain;
 
@@ -8160,9 +8040,7 @@ pa_find_space_by_number (number)
    address is unknown then return zero.  */
 
 static unsigned int
    address is unknown then return zero.  */
 
 static unsigned int
-pa_subspace_start (space, quadrant)
-     sd_chain_struct *space;
-     int quadrant;
+pa_subspace_start (sd_chain_struct *space, int quadrant)
 {
   /* FIXME.  Assumes everyone puts read/write data at 0x4000000, this
      is not correct for the PA OSF1 port.  */
 {
   /* FIXME.  Assumes everyone puts read/write data at 0x4000000, this
      is not correct for the PA OSF1 port.  */
@@ -8180,8 +8058,7 @@ pa_subspace_start (space, quadrant)
    a string.  */
 
 static unsigned int
    a string.  */
 
 static unsigned int
-pa_stringer_aux (s)
-     char *s;
+pa_stringer_aux (char *s)
 {
   unsigned int c = *s & CHAR_MASK;
 
 {
   unsigned int c = *s & CHAR_MASK;
 
@@ -8199,8 +8076,7 @@ pa_stringer_aux (s)
 /* Handle a .STRING type pseudo-op.  */
 
 static void
 /* Handle a .STRING type pseudo-op.  */
 
 static void
-pa_stringer (append_zero)
-     int append_zero;
+pa_stringer (int append_zero)
 {
   char *s, num_buf[4];
   unsigned int c;
 {
   char *s, num_buf[4];
   unsigned int c;
@@ -8274,15 +8150,14 @@ pa_stringer (append_zero)
            }
        }
     }
            }
        }
     }
-  stringer (append_zero);
+  stringer (8 + append_zero);
   pa_undefine_label ();
 }
 
 /* Handle a .VERSION pseudo-op.  */
 
 static void
   pa_undefine_label ();
 }
 
 /* Handle a .VERSION pseudo-op.  */
 
 static void
-pa_version (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_version (int unused ATTRIBUTE_UNUSED)
 {
   obj_version (0);
   pa_undefine_label ();
 {
   obj_version (0);
   pa_undefine_label ();
@@ -8293,8 +8168,7 @@ pa_version (unused)
 /* Handle a .COMPILER pseudo-op.  */
 
 static void
 /* Handle a .COMPILER pseudo-op.  */
 
 static void
-pa_compiler (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_compiler (int unused ATTRIBUTE_UNUSED)
 {
   obj_som_compiler (0);
   pa_undefine_label ();
 {
   obj_som_compiler (0);
   pa_undefine_label ();
@@ -8305,8 +8179,7 @@ pa_compiler (unused)
 /* Handle a .COPYRIGHT pseudo-op.  */
 
 static void
 /* Handle a .COPYRIGHT pseudo-op.  */
 
 static void
-pa_copyright (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_copyright (int unused ATTRIBUTE_UNUSED)
 {
   obj_copyright (0);
   pa_undefine_label ();
 {
   obj_copyright (0);
   pa_undefine_label ();
@@ -8316,8 +8189,7 @@ pa_copyright (unused)
    the latest space label.  */
 
 static void
    the latest space label.  */
 
 static void
-pa_cons (nbytes)
-     int nbytes;
+pa_cons (int nbytes)
 {
   cons (nbytes);
   pa_undefine_label ();
 {
   cons (nbytes);
   pa_undefine_label ();
@@ -8326,8 +8198,7 @@ pa_cons (nbytes)
 /* Like float_cons, but we need to undefine our label.  */
 
 static void
 /* Like float_cons, but we need to undefine our label.  */
 
 static void
-pa_float_cons (float_type)
-     int float_type;
+pa_float_cons (int float_type)
 {
   float_cons (float_type);
   pa_undefine_label ();
 {
   float_cons (float_type);
   pa_undefine_label ();
@@ -8336,8 +8207,7 @@ pa_float_cons (float_type)
 /* Like s_fill, but delete our label when finished.  */
 
 static void
 /* Like s_fill, but delete our label when finished.  */
 
 static void
-pa_fill (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_fill (int unused ATTRIBUTE_UNUSED)
 {
 #ifdef OBJ_SOM
   /* We must have a valid space and subspace.  */
 {
 #ifdef OBJ_SOM
   /* We must have a valid space and subspace.  */
@@ -8351,8 +8221,7 @@ pa_fill (unused)
 /* Like lcomm, but delete our label when finished.  */
 
 static void
 /* Like lcomm, but delete our label when finished.  */
 
 static void
-pa_lcomm (needs_align)
-     int needs_align;
+pa_lcomm (int needs_align)
 {
 #ifdef OBJ_SOM
   /* We must have a valid space and subspace.  */
 {
 #ifdef OBJ_SOM
   /* We must have a valid space and subspace.  */
@@ -8366,8 +8235,7 @@ pa_lcomm (needs_align)
 /* Like lsym, but delete our label when finished.  */
 
 static void
 /* Like lsym, but delete our label when finished.  */
 
 static void
-pa_lsym (unused)
-     int unused ATTRIBUTE_UNUSED;
+pa_lsym (int unused ATTRIBUTE_UNUSED)
 {
 #ifdef OBJ_SOM
   /* We must have a valid space and subspace.  */
 {
 #ifdef OBJ_SOM
   /* We must have a valid space and subspace.  */
@@ -8378,6 +8246,79 @@ pa_lsym (unused)
   pa_undefine_label ();
 }
 
   pa_undefine_label ();
 }
 
+/* This function is called once, at assembler startup time.  It should
+   set up all the tables, etc. that the MD part of the assembler will need.  */
+
+void
+md_begin (void)
+{
+  const char *retval = NULL;
+  int lose = 0;
+  unsigned int i = 0;
+
+  last_call_info = NULL;
+  call_info_root = NULL;
+
+  /* Set the default machine type.  */
+  if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, DEFAULT_LEVEL))
+    as_warn (_("could not set architecture and machine"));
+
+  /* Folding of text and data segments fails miserably on the PA.
+     Warn user and disable "-R" option.  */
+  if (flag_readonly_data_in_text)
+    {
+      as_warn (_("-R option not supported on this target."));
+      flag_readonly_data_in_text = 0;
+    }
+
+#ifdef OBJ_SOM
+  pa_spaces_begin ();
+#endif
+
+  op_hash = hash_new ();
+
+  while (i < NUMOPCODES)
+    {
+      const char *name = pa_opcodes[i].name;
+
+      retval = hash_insert (op_hash, name, (struct pa_opcode *) &pa_opcodes[i]);
+      if (retval != NULL && *retval != '\0')
+       {
+         as_fatal (_("Internal error: can't hash `%s': %s\n"), name, retval);
+         lose = 1;
+       }
+
+      do
+       {
+         if ((pa_opcodes[i].match & pa_opcodes[i].mask)
+             != pa_opcodes[i].match)
+           {
+             fprintf (stderr, _("internal error: losing opcode: `%s' \"%s\"\n"),
+                      pa_opcodes[i].name, pa_opcodes[i].args);
+             lose = 1;
+           }
+         ++i;
+       }
+      while (i < NUMOPCODES && !strcmp (pa_opcodes[i].name, name));
+    }
+
+  if (lose)
+    as_fatal (_("Broken assembler.  No assembly attempted."));
+
+#ifdef OBJ_SOM
+  /* SOM will change text_section.  To make sure we never put
+     anything into the old one switch to the new one now.  */
+  subseg_set (text_section, 0);
+#endif
+
+#ifdef OBJ_SOM
+  dummy_symbol = symbol_find_or_make ("L$dummy");
+  S_SET_SEGMENT (dummy_symbol, text_section);
+  /* Force the symbol to be converted to a real symbol.  */
+  (void) symbol_get_bfdsym (dummy_symbol);
+#endif
+}
+
 /* On the PA relocations which involve function symbols must not be
    adjusted.  This so that the linker can know when/how to create argument
    relocation stubs for indirect calls and calls to static functions.
 /* On the PA relocations which involve function symbols must not be
    adjusted.  This so that the linker can know when/how to create argument
    relocation stubs for indirect calls and calls to static functions.
@@ -8396,16 +8337,11 @@ pa_lsym (unused)
    any fixup which creates entries in the DLT (eg they use "T" field
    selectors).
 
    any fixup which creates entries in the DLT (eg they use "T" field
    selectors).
 
-   Reject reductions involving symbols with external scope; such
-   reductions make life a living hell for object file editors.
-
-   FIXME.  Also reject R_HPPA relocations which are 32bits wide in
-   the code space.  The SOM BFD backend doesn't know how to pull the
-   right bits out of an instruction.  */
+   ??? Reject reductions involving symbols with external scope; such
+   reductions make life a living hell for object file editors.  */
 
 int
 
 int
-hppa_fix_adjustable (fixp)
-     fixS *fixp;
+hppa_fix_adjustable (fixS *fixp)
 {
 #ifdef OBJ_ELF
   reloc_type code;
 {
 #ifdef OBJ_ELF
   reloc_type code;
@@ -8414,17 +8350,6 @@ hppa_fix_adjustable (fixp)
 
   hppa_fix = (struct hppa_fix_struct *) fixp->tc_fix_data;
 
 
   hppa_fix = (struct hppa_fix_struct *) fixp->tc_fix_data;
 
-#ifdef OBJ_SOM
-  /* Reject reductions of symbols in 32bit relocs unless they
-     are fake labels.  */
-  if (fixp->fx_r_type == R_HPPA
-      && hppa_fix->fx_r_format == 32
-      && strncmp (S_GET_NAME (fixp->fx_addsy),
-                 FAKE_LABEL_NAME,
-                 strlen (FAKE_LABEL_NAME)))
-    return 0;
-#endif
-
 #ifdef OBJ_ELF
   /* LR/RR selectors are implicitly used for a number of different relocation
      types.  We must ensure that none of these types are adjusted (see below)
 #ifdef OBJ_ELF
   /* LR/RR selectors are implicitly used for a number of different relocation
      types.  We must ensure that none of these types are adjusted (see below)
@@ -8537,8 +8462,7 @@ hppa_fix_adjustable (fixp)
    within GAS.  */
 
 int
    within GAS.  */
 
 int
-hppa_force_relocation (fixp)
-     struct fix *fixp;
+hppa_force_relocation (struct fix *fixp)
 {
   struct hppa_fix_struct *hppa_fixp;
 
 {
   struct hppa_fix_struct *hppa_fixp;
 
@@ -8612,75 +8536,13 @@ hppa_force_relocation (fixp)
 
 /* Now for some ELF specific code.  FIXME.  */
 #ifdef OBJ_ELF
 
 /* Now for some ELF specific code.  FIXME.  */
 #ifdef OBJ_ELF
-/* Mark the end of a function so that it's possible to compute
-   the size of the function in elf_hppa_final_processing.  */
-
-static void
-hppa_elf_mark_end_of_function ()
-{
-  /* ELF does not have EXIT relocations.  All we do is create a
-     temporary symbol marking the end of the function.  */
-  char *name;
-
-  if (last_call_info == NULL || last_call_info->start_symbol == NULL)
-    {
-      /* We have already warned about a missing label,
-        or other problems.  */
-      return;
-    }
-
-  name = (char *) xmalloc (strlen ("L$\001end_")
-                          + strlen (S_GET_NAME (last_call_info->start_symbol))
-                          + 1);
-  if (name)
-    {
-      symbolS *symbolP;
-
-      strcpy (name, "L$\001end_");
-      strcat (name, S_GET_NAME (last_call_info->start_symbol));
-
-      /* If we have a .exit followed by a .procend, then the
-        symbol will have already been defined.  */
-      symbolP = symbol_find (name);
-      if (symbolP)
-       {
-         /* The symbol has already been defined!  This can
-            happen if we have a .exit followed by a .procend.
-
-            This is *not* an error.  All we want to do is free
-            the memory we just allocated for the name and continue.  */
-         xfree (name);
-       }
-      else
-       {
-         /* symbol value should be the offset of the
-            last instruction of the function */
-         symbolP = symbol_new (name, now_seg, (valueT) (frag_now_fix () - 4),
-                               frag_now);
-
-         assert (symbolP);
-         S_CLEAR_EXTERNAL (symbolP);
-         symbol_table_insert (symbolP);
-       }
-
-      if (symbolP)
-       last_call_info->end_symbol = symbolP;
-      else
-       as_bad (_("Symbol '%s' could not be created."), name);
-
-    }
-  else
-    as_bad (_("No memory for symbol name."));
-
-}
-
 /* For ELF, this function serves one purpose:  to setup the st_size
    field of STT_FUNC symbols.  To do this, we need to scan the
    call_info structure list, determining st_size in by taking the
    difference in the address of the beginning/end marker symbols.  */
 
 void
 /* For ELF, this function serves one purpose:  to setup the st_size
    field of STT_FUNC symbols.  To do this, we need to scan the
    call_info structure list, determining st_size in by taking the
    difference in the address of the beginning/end marker symbols.  */
 
 void
-elf_hppa_final_processing ()
+elf_hppa_final_processing (void)
 {
   struct call_info *call_info_pointer;
 
 {
   struct call_info *call_info_pointer;
 
@@ -8698,8 +8560,7 @@ elf_hppa_final_processing ()
 }
 
 static void
 }
 
 static void
-pa_vtable_entry (ignore)
-     int ignore ATTRIBUTE_UNUSED;
+pa_vtable_entry (int ignore ATTRIBUTE_UNUSED)
 {
   struct fix *new_fix;
 
 {
   struct fix *new_fix;
 
@@ -8707,8 +8568,8 @@ pa_vtable_entry (ignore)
 
   if (new_fix)
     {
 
   if (new_fix)
     {
-      struct hppa_fix_struct *hppa_fix = (struct hppa_fix_struct *)
-       obstack_alloc (&notes, sizeof (struct hppa_fix_struct));
+      struct hppa_fix_struct * hppa_fix = obstack_alloc (&notes, sizeof (struct hppa_fix_struct));
+
       hppa_fix->fx_r_type = R_HPPA;
       hppa_fix->fx_r_field = e_fsel;
       hppa_fix->fx_r_format = 32;
       hppa_fix->fx_r_type = R_HPPA;
       hppa_fix->fx_r_field = e_fsel;
       hppa_fix->fx_r_format = 32;
@@ -8720,8 +8581,7 @@ pa_vtable_entry (ignore)
 }
 
 static void
 }
 
 static void
-pa_vtable_inherit (ignore)
-     int ignore ATTRIBUTE_UNUSED;
+pa_vtable_inherit (int ignore ATTRIBUTE_UNUSED)
 {
   struct fix *new_fix;
 
 {
   struct fix *new_fix;
 
@@ -8729,8 +8589,8 @@ pa_vtable_inherit (ignore)
 
   if (new_fix)
     {
 
   if (new_fix)
     {
-      struct hppa_fix_struct *hppa_fix = (struct hppa_fix_struct *)
-       obstack_alloc (&notes, sizeof (struct hppa_fix_struct));
+      struct hppa_fix_struct * hppa_fix = obstack_alloc (&notes, sizeof (struct hppa_fix_struct));
+
       hppa_fix->fx_r_type = R_HPPA;
       hppa_fix->fx_r_field = e_fsel;
       hppa_fix->fx_r_format = 32;
       hppa_fix->fx_r_type = R_HPPA;
       hppa_fix->fx_r_field = e_fsel;
       hppa_fix->fx_r_format = 32;
@@ -8741,3 +8601,135 @@ pa_vtable_inherit (ignore)
     }
 }
 #endif
     }
 }
 #endif
+
+/* Table of pseudo ops for the PA.  FIXME -- how many of these
+   are now redundant with the overall GAS and the object file
+   dependent tables?  */
+const pseudo_typeS md_pseudo_table[] =
+{
+  /* align pseudo-ops on the PA specify the actual alignment requested,
+     not the log2 of the requested alignment.  */
+#ifdef OBJ_SOM
+  {"align", pa_align, 8},
+#endif
+#ifdef OBJ_ELF
+  {"align", s_align_bytes, 8},
+#endif
+  {"begin_brtab", pa_brtab, 1},
+  {"begin_try", pa_try, 1},
+  {"block", pa_block, 1},
+  {"blockz", pa_block, 0},
+  {"byte", pa_cons, 1},
+  {"call", pa_call, 0},
+  {"callinfo", pa_callinfo, 0},
+#if defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD))
+  {"code", obj_elf_text, 0},
+#else
+  {"code", pa_text, 0},
+  {"comm", pa_comm, 0},
+#endif
+#ifdef OBJ_SOM
+  {"compiler", pa_compiler, 0},
+#endif
+  {"copyright", pa_copyright, 0},
+#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
+  {"data", pa_data, 0},
+#endif
+  {"double", pa_float_cons, 'd'},
+  {"dword", pa_cons, 8},
+  {"end", pa_end, 0},
+  {"end_brtab", pa_brtab, 0},
+#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
+  {"end_try", pa_try, 0},
+#endif
+  {"enter", pa_enter, 0},
+  {"entry", pa_entry, 0},
+  {"equ", pa_equ, 0},
+  {"exit", pa_exit, 0},
+  {"export", pa_export, 0},
+  {"fill", pa_fill, 0},
+  {"float", pa_float_cons, 'f'},
+  {"half", pa_cons, 2},
+  {"import", pa_import, 0},
+  {"int", pa_cons, 4},
+  {"label", pa_label, 0},
+  {"lcomm", pa_lcomm, 0},
+  {"leave", pa_leave, 0},
+  {"level", pa_level, 0},
+  {"long", pa_cons, 4},
+  {"lsym", pa_lsym, 0},
+#ifdef OBJ_SOM
+  {"nsubspa", pa_subspace, 1},
+#endif
+  {"octa", pa_cons, 16},
+  {"org", pa_origin, 0},
+  {"origin", pa_origin, 0},
+  {"param", pa_param, 0},
+  {"proc", pa_proc, 0},
+  {"procend", pa_procend, 0},
+  {"quad", pa_cons, 8},
+  {"reg", pa_equ, 1},
+  {"short", pa_cons, 2},
+  {"single", pa_float_cons, 'f'},
+#ifdef OBJ_SOM
+  {"space", pa_space, 0},
+  {"spnum", pa_spnum, 0},
+#endif
+  {"string", pa_stringer, 0},
+  {"stringz", pa_stringer, 1},
+#ifdef OBJ_SOM
+  {"subspa", pa_subspace, 0},
+#endif
+#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
+  {"text", pa_text, 0},
+#endif
+  {"version", pa_version, 0},
+#ifdef OBJ_ELF
+  {"vtable_entry", pa_vtable_entry, 0},
+  {"vtable_inherit", pa_vtable_inherit, 0},
+#endif
+  {"word", pa_cons, 4},
+  {NULL, 0, 0}
+};
+
+#ifdef OBJ_ELF
+void
+hppa_cfi_frame_initial_instructions (void)
+{
+  cfi_add_CFA_def_cfa (30, 0);
+}
+
+int
+hppa_regname_to_dw2regnum (char *regname)
+{
+  unsigned int regnum = -1;
+  unsigned int i;
+  const char *p;
+  char *q;
+  static struct { char *name; int dw2regnum; } regnames[] =
+    {
+      { "sp", 30 }, { "rp", 2 },
+    };
+
+  for (i = 0; i < ARRAY_SIZE (regnames); ++i)
+    if (strcmp (regnames[i].name, regname) == 0)
+      return regnames[i].dw2regnum;
+
+  if (regname[0] == 'r')
+    {
+      p = regname + 1;
+      regnum = strtoul (p, &q, 10);
+      if (p == q || *q || regnum >= 32)
+       return -1;
+    }
+  else if (regname[0] == 'f' && regname[1] == 'r')
+    {
+      p = regname + 2;
+      regnum = strtoul (p, &q, 10);
+      if (p == q || *q || regnum <= 4 || regnum >= 32)
+       return -1;
+      regnum += 32 - 4;
+    }
+  return regnum;
+}
+#endif