fix definitions of md_create_long_jump, md_create_short_jump,
authorMark Eichin <eichin@cygnus>
Mon, 12 Jul 1993 19:42:32 +0000 (19:42 +0000)
committerMark Eichin <eichin@cygnus>
Mon, 12 Jul 1993 19:42:32 +0000 (19:42 +0000)
md_number_to_chars, and md_section_align to correctly use valueT and addressT

gas/config/tc-h8300.c
gas/config/tc-h8500.c
gas/config/tc-hppa.c [new file with mode: 0644]
gas/config/tc-i386.c
gas/config/tc-i860.c
gas/config/tc-m68k.c
gas/config/tc-ns32k.c
gas/config/tc-sh.c [new file with mode: 0644]
gas/config/tc-tahoe.c
gas/config/tc-vax.c
gas/config/tc-z8k.c

index 316b5c149eebb8e265c2a4b827b9019f822de05b..62aa3fdd77fafb19ca0c66d1d03cf6d392c32ccd 100644 (file)
@@ -1,24 +1,24 @@
 /* tc-h8300.c -- Assemble code for the Hitachi H8/300
    Copyright (C) 1991, 1992 Free Software Foundation.
-   
+
    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)
    any later version.
-   
+
    GAS is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with GAS; see the file COPYING.  If not, write to
    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 
-/* 
+/*
   Written By Steve Chamberlain
   sac@cygnus.com
   */
 #include <stdio.h>
 #include "as.h"
 #include "bfd.h"
+#define DEFINE_TABLE
+#define h8_opcodes ops
 #include "opcode/h8300.h"
 #include <ctype.h>
-#include "listing.h"
 
-char  comment_chars[]  = { ';',0 };
-char line_separator_chars[] = { '$' ,0};
+const char comment_chars[] =
+{';', 0};
+const char line_separator_chars[] =
+{'$', 0};
+const char line_comment_chars[] = "#";
 
 /* This table describes all the machine specific pseudo-ops the assembler
    has to support.  The fields are:
@@ -40,30 +44,56 @@ char line_separator_chars[] = { '$' ,0};
    Integer arg to pass to the function
    */
 
-void cons();
+void cons ();
+
+int Hmode;
+#define PSIZE (Hmode ? L_32 : L_16)
+#define DMODE (L_16)
+#define DSYMMODE (Hmode ? L_24 : L_16)
+int bsize = L_8;               /* default branch displacement */
+
+
+void 
+h8300hmode ()
+{
+  Hmode = 1;
+}
+
+
+void 
+sbranch (size)
+     int size;
+{
+  bsize = size;
+}
 
-const pseudo_typeS md_pseudo_table[] = 
+const pseudo_typeS md_pseudo_table[] =
 {
-{ "int",       cons,           2       },
-{ "data.b",     cons,          1      },
-{ "data.w",     cons,           2      },
-{ "data.l",     cons,          4      },
-{ "form",      listing_psize,  0      },
-{ "heading",   listing_title,  0},
-{ "import",    s_ignore,       0},
-{ "page",      listing_eject,  0},
-{ "program",   s_ignore,       0},
-{ 0,0,0 }
+
+  {"h8300h", h8300hmode, 0},
+  {"sbranch", sbranch, L_8},
+  {"lbranch", sbranch, L_16},
+
+  {"int", cons, 2},
+  {"data.b", cons, 1},
+  {"data.w", cons, 2},
+  {"data.l", cons, 4},
+  {"form", listing_psize, 0},
+  {"heading", listing_title, 0},
+  {"import", s_ignore, 0},
+  {"page", listing_eject, 0},
+  {"program", s_ignore, 0},
+  {0, 0, 0}
 };
 
-int  md_reloc_size ;
+const int md_reloc_size;
 
 const char EXP_CHARS[] = "eE";
 
 /* Chars that mean this number is a floating point constant */
 /* As in 0f12.456 */
 /* or    0d1.2345e12 */
-char FLT_CHARS[] = "rRsSfFdDxXpP";
+const char FLT_CHARS[] = "rRsSfFdDxXpP";
 
 
 const relax_typeS md_relax_table[1];
@@ -71,242 +101,234 @@ const relax_typeS md_relax_table[1];
 
 static struct hash_control *opcode_hash_control;       /* Opcode mnemonics */
 
-
 /*
   This function is called once, at assembler startup time.  This should
   set up all the tables, etc that the MD part of the assembler needs
   */
-#if 0
-/* encode the size and number into the number field
-   xxnnnn
-   00    8 bit
-   01    16 bit
-   10    ccr
-   nnnnreg number
-   */
-#define WORD_REG 0x10
-#define BYTE_REG 0x00
-#define CCR_REG  0x20
-struct reg_entry
-{
-       char *name;
-       char number;
-};
-
-struct reg_entry reg_list[] = { 
-       "r0",WORD_REG +0,
-       "r1",WORD_REG +1,
-       "r2",WORD_REG +2,
-       "r3",WORD_REG +3,
-       "r4",WORD_REG +4,
-       "r5",WORD_REG +5,
-       "r6",WORD_REG +6,
-       "r7",WORD_REG +7,
-       "fp",WORD_REG +6,
-       "sp",WORD_REG +7,
-       "r0h",BYTE_REG + 0,
-       "r0l",BYTE_REG + 1,
-       "r1h",BYTE_REG + 2,
-       "r1l",BYTE_REG + 3,
-       "r2h",BYTE_REG + 4,
-       "r2l",BYTE_REG + 5,
-       "r3h",BYTE_REG + 6,
-       "r3l",BYTE_REG + 7,
-       "r4h",BYTE_REG + 8,
-       "r4l",BYTE_REG + 9,
-       "r5h",BYTE_REG + 10,
-       "r5l",BYTE_REG + 11,
-       "r6h",BYTE_REG + 12,
-       "r6l",BYTE_REG + 13,
-       "r7h",BYTE_REG + 14,
-       "r7l",BYTE_REG + 15,
-       "ccr",CCR_REG,
-       0,0
-    }
-;
 
 
-#endif
+void
+md_begin ()
+{
+  struct h8_opcode *opcode;
+  const struct reg_entry *reg;
+  char prev_buffer[100];
+  int idx = 0;
 
+  opcode_hash_control = hash_new ();
+  prev_buffer[0] = 0;
 
-void md_begin () 
-{
-       struct h8_opcode *opcode;
-       const  struct reg_entry *reg;
-       char prev_buffer[100];
-       int idx = 0;
-       
-       opcode_hash_control = hash_new();
-       prev_buffer[0] = 0;
-       
-       for (opcode = h8_opcodes; opcode->name; opcode++) 
+  for (opcode = h8_opcodes; opcode->name; opcode++)
+    {
+      /* Strip off any . part when inserting the opcode and only enter
+         unique codes into the hash table
+         */
+      char *src = opcode->name;
+      unsigned int len = strlen (src);
+      char *dst = malloc (len + 1);
+      char *buffer = dst;
+
+      opcode->size = 0;
+      while (*src)
+       {
+         if (*src == '.')
            {
-                   /* Strip off any . part when inserting the opcode and only enter
-                      unique codes into the hash table
-                      */
-                   char *src= opcode->name;
-                   unsigned int len = strlen(src);
-                   char *dst = malloc(len+1);
-                   char *buffer = dst;
-                   opcode->size = 0;    
-                   while (*src) {
-                           if (*src == '.') {
-                                   *dst++ = 0;
-                                   src++;
-                                   opcode->size = *src;
-                                   break;
-                           }
-                           *dst++ = *src++;
-                   }
-                   if (strcmp(buffer, prev_buffer)) 
-                       {
-                               hash_insert(opcode_hash_control, buffer, (char *)opcode);
-                               strcpy(prev_buffer, buffer);
-                               idx++;
-                       }
-                   opcode->idx = idx;
-                   
-                   
-                   /* Find the number of operands */
-                   opcode->noperands = 0;
-                   while (opcode->args.nib[opcode->noperands] != E)
-                       opcode->noperands ++;
-                   /* Find the length of the opcode in bytes */
-                   opcode->length =0;
-                   while (opcode->data.nib[opcode->length*2] != E)
-                       opcode->length++;
+             src++;
+             opcode->size = *src;
+             break;
            }
-       
+         *dst++ = *src++;
+       }
+             *dst++ = 0;
+      if (strcmp (buffer, prev_buffer))
+       {
+         hash_insert (opcode_hash_control, buffer, (char *) opcode);
+         strcpy (prev_buffer, buffer);
+         idx++;
+       }
+      opcode->idx = idx;
+
+
+      /* Find the number of operands */
+      opcode->noperands = 0;
+      while (opcode->args.nib[opcode->noperands] != E)
+       opcode->noperands++;
+      /* Find the length of the opcode in bytes */
+      opcode->length = 0;
+      while (opcode->data.nib[opcode->length * 2] != E)
+       opcode->length++;
+    }
+
 }
 
 
-struct h8_exp {
-       char *e_beg;
-       char *e_end;
-       expressionS e_exp;
-};
-struct h8_op 
+struct h8_exp
 {
-       unsigned int dispreg;
-       op_type mode;
-       unsigned reg;
-       expressionS exp;
+  char *e_beg;
+  char *e_end;
+  expressionS e_exp;
 };
+int dispreg;
+int opsize;                    /* Set when a register size is seen */
 
 
+struct h8_op
+{
+  op_type mode;
+  unsigned reg;
+  expressionS exp;
+};
 
 /*
-  parse operands       
+  parse operands
   WREG r0,r1,r2,r3,r4,r5,r6,r7,fp,sp
   r0l,r0h,..r7l,r7h
   @WREG
   @WREG+
   @-WREG
   #const
-  
-  */
 
-op_type r8_sord[] = {RS8, RD8};
-op_type r16_sord[] = {RS16, RD16};
-op_type rind_sord[] = {RSIND, RDIND};
-op_type abs_sord[2] = {ABS16SRC, ABS16DST};
-op_type disp_sord[] = {DISPSRC, DISPDST};
+  */
 
 /* try and parse a reg name, returns number of chars consumed */
-int 
-    DEFUN(parse_reg,(src, mode, reg, dst),
-         char *src AND
-         op_type *mode AND
-         unsigned int *reg AND
-         int dst)
+int
+parse_reg (src, mode, reg, direction)
+     char *src;
+     op_type *mode;
+     unsigned int *reg;
+     int direction;
+
 {
-       if (src[0]  == 's' && src[1] == 'p') 
-           {
-                   *mode = r16_sord[dst];
-                   *reg = 7;
-                   return 2;
-           }
-       if (src[0] == 'c' && src[1] == 'c' && src[2] == 'r') 
-           {
-                   *mode = CCR;
-                   *reg = 0;
-                   return 3;
-           }
-       if (src[0]  == 'f' && src[1] == 'p') 
+  if (src[0] == 's' && src[1] == 'p')
+    {
+      *mode = PSIZE | REG | direction;
+      *reg = 7;
+      return 2;
+    }
+  if (src[0] == 'c' && src[1] == 'c' && src[2] == 'r')
+    {
+      *mode = CCR;
+      *reg = 0;
+      return 3;
+    }
+  if (src[0] == 'f' && src[1] == 'p')
+    {
+      *mode = PSIZE | REG | direction;
+      *reg = 6;
+      return 2;
+    }
+  if (src[0] == 'e'
+      && src[1] == 'r'
+      && src[2] >= '0' && src[2] <= '7')
+    {
+      *mode = L_32 | REG | direction;
+      *reg = src[2] - '0';
+      if (!Hmode)
+       as_warn ("Reg only legal for H8/300-H");
+
+      return 3;
+    }
+  if (src[0] == 'e'
+      && src[1] >= '0' && src[1] <= '7')
+    {
+      *mode = L_16 | REG | direction;
+      *reg = src[1] - '0' + 8;
+      if (!Hmode)
+       as_warn ("Reg only legal for H8/300-H");
+      return 2;
+    }
+
+  if (src[0] == 'r')
+    {
+      if (src[1] >= '0' && src[1] <= '7')
+       {
+         if (src[2] == 'l')
            {
-                   *mode = r16_sord[dst];
-                   *reg = 6;
-                   return 2;
+             *mode = L_8 | REG | direction;
+             *reg = (src[1] - '0') + 8;
+             return 3;
            }
-       if (src[0] == 'r') 
+         if (src[2] == 'h')
            {
-                   if (src[1] >= '0' && src[1] <= '7') 
-                       {
-                               if(src[2] == 'l') 
-                                   {
-                                           *mode = r8_sord[dst];
-                                           *reg = (src[1] - '0') + 8;
-                                           return 3;
-                                   }
-                               if(src[2] == 'h') 
-                                   {
-                                           *mode = r8_sord[dst];
-                                           *reg = (src[1] - '0')  ;
-                                           return 3;
-                                   }
-                               *mode = r16_sord[dst];
-                               *reg = (src[1] - '0');
-                               return 2;
-                       }
+             *mode = L_8 | REG | direction;
+             *reg = (src[1] - '0');
+             return 3;
            }
-       return 0;
+         *mode = L_16 | REG | direction;
+         *reg = (src[1] - '0');
+         return 2;
+       }
+    }
+  return 0;
 }
 
 char *
-    DEFUN(parse_exp,(s, op),
-         char *s AND
-         expressionS *op)
+DEFUN (parse_exp, (s, op),
+       char *s AND
+       expressionS * op)
 {
-       char *save = input_line_pointer;
-       char *new;
-       segT seg;
-       input_line_pointer = s;
-       seg = expr(0,op);
-       new = input_line_pointer;
-       input_line_pointer = save;
-       if (SEG_NORMAL(seg)) 
-           return new;
-       switch (seg) {
-       case SEG_ABSOLUTE:
-       case SEG_UNKNOWN:
-       case SEG_DIFFERENCE:
-       case SEG_BIG:
-       case SEG_REGISTER:
-               return new;
-       case SEG_ABSENT:
-               as_bad("Missing operand");
-               return new;
-       default:
-               as_bad("Don't understand operand of type %s", segment_name (seg));
-               return new;
-       }
+  char *save = input_line_pointer;
+  char *new;
+  segT seg;
+
+  input_line_pointer = s;
+  seg = expr (0, op);
+  new = input_line_pointer;
+  input_line_pointer = save;
+  if (SEG_NORMAL (seg))
+    return new;
+  switch (seg)
+    {
+    case SEG_ABSOLUTE:
+    case SEG_UNKNOWN:
+    case SEG_DIFFERENCE:
+    case SEG_BIG:
+    case SEG_REGISTER:
+      return new;
+    case SEG_ABSENT:
+      as_bad ("Missing operand");
+      return new;
+    default:
+      as_bad ("Don't understand operand of type %s", segment_name (seg));
+      return new;
+    }
 }
 
 static char *
-    DEFUN(skip_colonthing,(ptr),
-         char *ptr)
+skip_colonthing (ptr, exp, mode)
+     char *ptr;
+     expressionS *exp;
+     int *mode;
 {
-       if (*ptr == ':') {
-               ptr++;
-               while (isdigit(*ptr))
-                   ptr++;
-               
+  if (*ptr == ':')
+    {
+      ptr++;
+      if (*ptr == '8')
+       {
+         ptr++;
+         /* ff fill any 8 bit quantity */
+         exp->X_add_number |= 0xff00;
        }
-       return ptr;
+      else
+       {
+         *mode &= ~SIZE;
+         if (*ptr == '2')
+           {
+             *mode |= L_24;
+           }
+         else if (*ptr == '1')
+           {
+             *mode |= L_16;
+           }
+         while (isdigit (*ptr))
+           ptr++;
+       }
+    }
+  return ptr;
 }
 
 /* The many forms of operand:
-   
+
    Rn                  Register direct
    @Rn                 Register indirect
    @(exp[:16], Rn)     Register indirect with displacement
@@ -315,205 +337,280 @@ static char *
    @aa:8                       absolute 8 bit
    @aa:16                      absolute 16 bit
    @aa                 absolute 16 bit
-   
+
    #xx[:size]          immediate data
    @(exp:[8], pc)              pc rel
    @@aa[:8]            memory indirect
-   
+
    */
 
-static void 
-    DEFUN(get_operand,(ptr, op, dst),
-         char **ptr AND 
-         struct h8_op *op AND 
-         unsigned int dst)
+char *
+colonmod24 (op, src)
+     struct h8_op *op;
+     char *src;
+
+{
+  int mode = 0;
+  src = skip_colonthing (src, &op->exp, &mode);
+
+  if (!mode)
+    {
+      /* Choose a default mode */
+      if (op->exp.X_add_number < -32768
+         || op->exp.X_add_number > 32767)
+       {
+         if (Hmode)
+           mode = L_24;
+         else 
+           mode = L_16;
+      }
+      else if (op->exp.X_add_symbol
+              || op->exp.X_subtract_symbol)
+       mode = DSYMMODE;
+      else
+       mode = DMODE;
+    }
+  op->mode |= mode;
+  return src;
+  
+}
+
+
+static void
+get_operand (ptr, op, dst, direction)
+     char **ptr;
+     struct h8_op *op;
+     unsigned int dst;
+
 {
   char *src = *ptr;
   op_type mode;
-  unsigned   int num;
-  unsigned  int len;
+  unsigned int num;
+  unsigned int len;
   unsigned int size;
+
   op->mode = E;
-       
-  len = parse_reg(src, &op->mode, &op->reg, dst);
-  if (len) {
-      *ptr = src + len;
-      return ;
-    }
-       
-  if (*src == '@') 
-  {
-    src++;
-    if (*src == '@') 
+
+  len = parse_reg (src, &op->mode, &op->reg, direction);
+  if (len)
     {
-      src++;
-      src = parse_exp(src,&op->exp);
-      src = skip_colonthing(src);
-                               
-      *ptr = src;
-                               
-      op->mode = MEMIND;
-      return;
-                               
-    }
-                   
-                   
-    if (*src == '-') 
-    {  
-      src++;
-      len = parse_reg(src, &mode, &num, dst);
-      if (len == 0) 
-      {
-       /* Oops, not a reg after all, must be ordinary exp */
-       src--;
-       /* must be a symbol */
-       op->mode = abs_sord[dst];
-       *ptr = skip_colonthing(parse_exp(src, &op->exp));
-                                           
-       return;
-                                           
-                                           
-      }
-                               
-      if (mode != r16_sord[dst]) 
-      {
-       as_bad("@- needs word register");
-      }
-      op->mode = RDDEC;
-      op->reg = num;
       *ptr = src + len;
       return;
     }
-    if (*src == '(' && ')') 
+
+  if (*src == '@')
     {
-      /* Disp */
-      src++;
-      src =      parse_exp(src, &op->exp);
-                               
-      if (*src == ')') 
-      {
-       src++;
-       op->mode = abs_sord[dst];
-       *ptr = src;
-       return;
-      }
-      src = skip_colonthing(src);
-                               
-      if (*src  != ',') 
-      {
-       as_bad("expected @(exp, reg16)");
-       return;
-                                           
-      }
       src++;
-      len = parse_reg(src, &mode, &op->reg, dst);
-      if (len == 0 || mode != r16_sord[dst])
-      {
-       as_bad("expected @(exp, reg16)");
-       return;
-      }
-      op->mode = disp_sord[dst];
-      src += len;
-      src = skip_colonthing(src);
-                               
-      if (*src != ')' && '(') 
-      {
-       as_bad("expected @(exp, reg16)");
-       return;                                     
-      }
-      *ptr = src +1;
-                               
-      return;
-    }
-    len = parse_reg(src, &mode, &num, dst);
-                   
-    if(len) {
-       src += len;
-       if (*src == '+') 
+      if (*src == '@')
+       {
+         src++;
+         src = parse_exp (src, &op->exp);
+
+         src = skip_colonthing (src, &op->exp, &op->mode);
+
+         *ptr = src;
+
+         op->mode = MEMIND;
+         return;
+
+       }
+
+
+      if (*src == '-')
        {
          src++;
-         if (mode != RS16) 
-         {
-           as_bad("@Rn+ needs src word register");
-           return;
-         }
-         op->mode = RSINC;
+         len = parse_reg (src, &mode, &num, direction);
+         if (len == 0)
+           {
+             /* Oops, not a reg after all, must be ordinary exp */
+             src--;
+             /* must be a symbol */
+             op->mode = ABS | PSIZE | direction;
+             *ptr = skip_colonthing (parse_exp (src, &op->exp),
+                                     &op->exp, &op->mode);
+
+             return;
+
+
+           }
+
+
+         if ((mode & SIZE) != PSIZE)
+           as_bad ("Wrong size pointer register for architecture.");
+         op->mode = RDDEC;
+         op->reg = num;
+         *ptr = src + len;
+         return;
+       }
+      if (*src == '(' )
+       {
+         /* Disp */
+         src++;
+
+         /* Start off assuming a 16 bit offset */
+
+
+         src = parse_exp (src, &op->exp);
+
+         src = colonmod24 (op, src);
+
+         if (*src == ')')
+           {
+             src++;
+             op->mode = DISP | direction;
+             *ptr = src;
+             return;
+           }
+
+         if (*src != ',')
+           {
+             as_bad ("expected @(exp, reg16)");
+             return;
+
+           }
+         src++;
+
+         len = parse_reg (src, &mode, &op->reg, direction);
+         if (len == 0 || !(mode & REG))
+           {
+             as_bad ("expected @(exp, reg16)");
+             return;
+           }
+         op->mode |= DISP | direction;
+         dispreg = op->reg;
+         src += len;
+         src = skip_colonthing (src, &op->exp, &op->mode);
+
+         if (*src != ')' && '(')
+           {
+             as_bad ("expected @(exp, reg16)");
+             return;
+           }
+         *ptr = src + 1;
+
+         return;
+       }
+      len = parse_reg (src, &mode, &num, direction);
+
+      if (len)
+       {
+         src += len;
+         if (*src == '+')
+           {
+             src++;
+             if ((mode & SIZE) != PSIZE)
+               as_bad ("Wrong size pointer register for architecture.");
+             op->mode = RSINC;
+             op->reg = num;
+             *ptr = src;
+             return;
+           }
+         if ((mode & SIZE) != PSIZE)
+           as_bad ("Wrong size pointer register for architecture.");
+
+         op->mode = direction | IND | PSIZE;
          op->reg = num;
          *ptr = src;
+
          return;
        }
-       if (mode != r16_sord[dst]) 
+      else
        {
-         as_bad("@Rn needs word register");
+         /* must be a symbol */
+
+         op->mode = ABS | direction;
+         src = parse_exp (src, &op->exp);
+
+         *ptr = colonmod24 (op, src);
+
          return;
-                                       
        }
-       op->mode =rind_sord[dst];
-       op->reg = num;
-       *ptr = src;
-       
-        return;
-      }
-    else 
-    {
-      /* must be a symbol */
-      op->mode = abs_sord[dst];
-      *ptr = skip_colonthing(parse_exp(src, &op->exp));
-                               
-      return;
     }
-  }
-       
-       
-  if (*src == '#') {
+
+
+  if (*src == '#')
+    {
       src++;
-      op->mode = IMM16;
-      src = parse_exp(src, &op->exp);
-      *ptr= skip_colonthing(src);
-               
+      op->mode = IMM;
+      src = parse_exp (src, &op->exp);
+      *ptr = skip_colonthing (src, &op->exp, &op->mode);
+
       return;
     }
-  else {
-      *ptr = parse_exp(src, &op->exp);
-      op->mode = DISP8;
+  else
+    {
+      src = parse_exp (src, &op->exp);
+      /* Trailing ':' size ? */
+      if (*src == ':')
+       {
+         if (src[1] == '1' && src[2] == '6')
+           {
+             op->mode = PCREL | L_16;
+             src += 3;
+           }
+         else if (src[1] == '8')
+           {
+             op->mode = PCREL | L_8;
+             src += 2;
+           }
+         else
+           {
+             as_bad ("expect :8 or :16 here");
+           }
+       }
+      else
+       {
+         op->mode = PCREL | bsize;
+       }
+      *ptr = src;
     }
 }
 
 
 static
-    char *
-    DEFUN(get_operands,(noperands,op_end, operand),
-         unsigned int noperands AND
-         char *op_end AND
-         struct h8_op *operand) 
+char *
+DEFUN (get_operands, (noperands, op_end, operand),
+       unsigned int noperands AND
+       char *op_end AND
+       struct h8_op *operand)
 {
-       char *ptr = op_end;
-       switch (noperands) 
-           {
-           case 0:
-                   operand[0].mode = 0;
-                   operand[1].mode = 0;
-                   break;
-                   
-           case 1:    
-                   ptr++;
-                   get_operand(& ptr, operand +0,0);
-                   operand[1].mode =0;
-                   break;
-                   
-           case 2:
-                   ptr++;
-                   get_operand(& ptr, operand +0,0);
-                   if (*ptr == ',') ptr++;
-                   get_operand(& ptr, operand +1, 1);
-                   break;
-                   
-           default:
-                   abort();    
-           }
-       
-       
-       return ptr;    
+  char *ptr = op_end;
+
+  switch (noperands)
+    {
+    case 0:
+      operand[0].mode = 0;
+      operand[1].mode = 0;
+      break;
+
+    case 1:
+      ptr++;
+      get_operand (&ptr, operand + 0, 0, SRC);
+      if (*ptr == ',')
+       {
+         ptr++;
+         get_operand (&ptr, operand + 1, 1, DST);
+       }
+      else
+       {
+         operand[1].mode = 0;
+       }
+
+      break;
+    case 2:
+      ptr++;
+      get_operand (&ptr, operand + 0, 0, SRC);
+      if (*ptr == ',')
+       ptr++;
+      get_operand (&ptr, operand + 1, 1, DST);
+      break;
+
+    default:
+      abort ();
+    }
+
+
+  return ptr;
 }
 
 /* Passed a pointer to a list of opcodes which use different
@@ -521,481 +618,480 @@ static
    provided
    */
 static
-    struct h8_opcode *
-    DEFUN(get_specific,(opcode,  operands),
-         struct h8_opcode *opcode AND
-         struct     h8_op *operands)
-
+struct h8_opcode *
+get_specific (opcode, operands)
+     struct h8_opcode *opcode;
+     struct h8_op *operands;
 {
-       struct h8_opcode *this_try = opcode ;
-       int found = 0;
-       unsigned int noperands = opcode->noperands;
-       
-       unsigned int dispreg;
-       unsigned int this_index = opcode->idx;
-       while (this_index == opcode->idx && !found) 
+  struct h8_opcode *this_try = opcode;
+  int found = 0;
+
+  unsigned int this_index = opcode->idx;
+
+  while (this_index == opcode->idx && !found)
+    {
+      unsigned int i;
+      found = 1;
+
+      this_try = opcode++;
+      for (i = 0; i < this_try->noperands && found; i++)
+       {
+         op_type op = this_try->args.nib[i];
+         int x = operands[i].mode;
+
+         if ((op & (DISP | REG)) == (DISP | REG)
+             && ((x & DISP | REG) == (DISP | REG)))
            {
-                   unsigned int i;
-                   
-                   this_try  = opcode ++;
-                   for (i = 0; i < noperands; i++) 
-                       {
-                               op_type op = (this_try->args.nib[i]) & ~(B30|B31);
-                               switch (op) 
-                                   {
-                                   case Hex0:
-                                   case Hex1:
-                                   case Hex2:
-                                   case Hex3:
-                                   case Hex4:
-                                   case Hex5:
-                                   case Hex6:
-                                   case Hex7:
-                                   case Hex8:
-                                   case Hex9:
-                                   case HexA:
-                                   case HexB:
-                                   case HexC:
-                                   case HexD:
-                                   case HexE:
-                                   case HexF:
-                                           break;
-                                   case DISPSRC:
-                                   case DISPDST:
-                                           operands[0].dispreg = operands[i].reg; 
-                                   case RD8:
-                                   case RS8:
-                                   case RDIND:
-                                   case RSIND:
-                                   case RD16:
-                                   case RS16:
-                                   case CCR:
-                                   case RSINC:
-                                   case RDDEC:
-                                           if (operands[i].mode != op) goto fail;
-                                           break;
-                                   case KBIT:
-                                   case IMM16:
-                                   case IMM3:
-                                   case IMM8:
-                                           if (operands[i].mode != IMM16) goto fail;
-                                           break;
-                                   case MEMIND:
-                                           if (operands[i].mode != MEMIND) goto fail;
-                                           break;
-                                   case ABS16SRC:
-                                   case ABS8SRC:
-                                   case ABS16OR8SRC:
-                                   case ABS16ORREL8SRC:
-                                           
-                                           if (operands[i].mode != ABS16SRC) goto fail;
-                                           break;
-                                   case ABS16OR8DST:
-                                   case ABS16DST:
-                                   case ABS8DST:
-                                           if (operands[i].mode != ABS16DST) goto fail;
-                                           break;
-                                   }
-                       }
-                   found =1;
-           fail: ;
+             dispreg = operands[i].reg;
            }
-       if (found) 
-           return this_try;
-       else 
-           return 0;
+         else if (op & REG)
+           {
+             if (!(x & REG))
+               found = 0;
+
+             if (x & L_P)
+               {
+                 x = (x & ~L_P) | (Hmode ? L_32 : L_16);
+               }
+             if (op & L_P)
+               {
+                 op = (op & ~L_P) | (Hmode ? L_32 : L_16);
+               }
+
+             opsize = op & SIZE;
+
+             /* The size of the reg is v important */
+             if ((op & SIZE) != (x & SIZE))
+               found = 0;
+           }
+         else if ((op & ABSJMP) && (x & ABS))
+           {
+             operands[i].mode &= ~ABS;
+             operands[i].mode |= ABSJMP;
+             /* But it may not be 24 bits long */
+             if (!Hmode)
+               {
+                 operands[i].mode &= ~SIZE;
+                 operands[i].mode |= L_16;
+               }
+
+
+           }
+         else if ((op & (KBIT | DBIT)) && (x & IMM))
+           {
+             /* This is ok if the immediate value is sensible */
+
+           }
+         else if (op & PCREL)
+           {
+
+             /* The size of the displacement is important */
+             if ((op & SIZE) != (x & SIZE))
+               found = 0;
+
+           }
+         else if ((op & (DISP | IMM | ABS))
+                  && (op & (DISP | IMM | ABS)) == (x & (DISP | IMM | ABS)))
+           {
+             /* Got a diplacement,will fit if no size or same size as try */
+             if ((x & SIZE) != 0
+                 && ((op & SIZE) != (x & SIZE)))
+               found = 0;
+           }
+         else if ((op & ABSMOV) && (x & ABS))
+           {
+             /* Ok */
+           }
+         else if ((op & MODE) != (x & MODE))
+           {
+             found = 0;
+           }
+
+       }
+    }
+  if (found)
+    return this_try;
+  else
+    return 0;
 }
 
 static void
-    DEFUN(check_operand,(operand, width, string),
-         struct h8_op *operand AND
-         unsigned int width AND
-         char *string)
+DEFUN (check_operand, (operand, width, string),
+       struct h8_op *operand AND
+       unsigned int width AND
+       char *string)
 {
-  if (operand->exp.X_add_symbol == 0 
+  if (operand->exp.X_add_symbol == 0
       && operand->exp.X_subtract_symbol == 0)
-  {
-                   
-    /* No symbol involved, let's look at offset, it's dangerous if any of
-       the high bits are not 0 or ff's, find out by oring or anding with
-       the width and seeing if the answer is 0 or all fs*/
-    if ((operand->exp.X_add_number & ~width) != 0 &&
-       (operand->exp.X_add_number | width)!= (~0))
     {
-      as_warn("operand %s0x%x out of range.", string, operand->exp.X_add_number);
+
+      /* No symbol involved, let's look at offset, it's dangerous if any of
+         the high bits are not 0 or ff's, find out by oring or anding with
+         the width and seeing if the answer is 0 or all fs*/
+      if ((operand->exp.X_add_number & ~width) != 0 &&
+         (operand->exp.X_add_number | width) != (~0))
+       {
+         as_warn ("operand %s0x%x out of range.", string, operand->exp.X_add_number);
+       }
     }
-  }
-       
+
+}
+
+static void
+do_a_fix_imm (offset, operand, relaxing)
+     int offset;
+     struct h8_op *operand;
+     int relaxing;
+{
+  int idx;
+  int size;
+  int where;
+
+
+  char *t = operand->mode & IMM ? "#" : "@";
+
+  if (operand->exp.X_add_symbol == 0)
+    {
+      char *bytes = frag_now->fr_literal + offset;
+      switch (operand->mode & SIZE)
+       {
+       case L_3:
+         check_operand (operand, 0x7, t);
+         bytes[0] |= (operand->exp.X_add_number) << 4;
+         break;
+       case L_8:
+         check_operand (operand, 0xff, t);
+         bytes[0] = operand->exp.X_add_number;
+         break;
+       case L_16:
+         check_operand (operand, 0xffff, t);
+         bytes[0] = operand->exp.X_add_number >> 8;
+         bytes[1] = operand->exp.X_add_number >> 0;
+         break;
+       case L_24:
+         check_operand (operand, 0xffffff, t);
+         bytes[0] = operand->exp.X_add_number >> 16;
+         bytes[1] = operand->exp.X_add_number >> 8;
+         bytes[2] = operand->exp.X_add_number >> 0;
+         break;
+
+       case L_32:
+         /* This should be done with bfd */
+         bytes[0] = operand->exp.X_add_number >> 24;
+         bytes[1] = operand->exp.X_add_number >> 16;
+         bytes[2] = operand->exp.X_add_number >> 8;
+         bytes[3] = operand->exp.X_add_number >> 0;
+         break;
+       }
+
+    }
+  else
+    {
+      switch (operand->mode & SIZE)
+       {
+       default:
+         abort ();
+       case L_24:
+         size = 4;
+         where = -1;
+         idx = relaxing ? R_MOVLB1 : R_RELLONG;
+         break;
+
+       case L_32:
+         size = 4;
+         where = 0;
+         idx = R_RELLONG;
+         break;
+       case L_16:
+         size = 2;
+         where = 0;
+         idx = relaxing ? R_MOVB1 : R_RELWORD;
+         break;
+       case L_8:
+         size = 1;
+         where = 0;
+         idx = R_RELBYTE;
+       }
+
+
+      fix_new (frag_now,
+              offset + where,
+              size,
+              operand->exp.X_add_symbol,
+              operand->exp.X_subtract_symbol,
+              (short) (operand->exp.X_add_number),
+              0,
+              idx);
+    }
+
 }
 
 /* Now we know what sort of opcodes it is, lets build the bytes -
  */
-static void 
-    DEFUN (build_bytes,(this_try, operand),
-          struct h8_opcode *this_try AND
-          struct h8_op *operand)
-
+static void
+build_bytes (this_try, operand)
+     struct h8_opcode *this_try;
+     struct h8_op *operand;
 {
-       unsigned int i;
-       
-       char *output = frag_more(this_try->length);
-       char *output_ptr = output;
-       op_type *nibble_ptr = this_try->data.nib;
-       char part;
-       op_type c;
-       char high;
-       int nib;
- top: ;
-       while (*nibble_ptr != E) 
+  unsigned int i;
+
+  char *output = frag_more (this_try->length);
+  char *output_ptr = output;
+  op_type *nibble_ptr = this_try->data.nib;
+  char part;
+  op_type c;
+  char high;
+  unsigned int nibble_count = 0;
+
+  int immat;
+  int nib;
+  char asnibbles[30];
+  char *p = asnibbles;
+
+  if (!(this_try->inbase || Hmode))
+    {
+      as_warn ("Opcode `%s' only available on H8/300-H", this_try->name);
+    }
+
+  while (*nibble_ptr != E)
+    {
+      int d;
+      c = *nibble_ptr++;
+
+      d = (c & DST) != 0;
+
+      if (c < 16)
+       {
+         nib = c;
+       }
+      else
+       {
+
+         if (c & (REG | IND | INC | DEC))
            {
-                   int nibble;
-                   for (nibble = 0; nibble <2; nibble++) 
-                       {
-                               c = *nibble_ptr & ~(B30|B31);
-                               switch (c) 
-                                   {
-                                   default:
-                                           abort();
-                                   case KBIT:
-                                           switch  (operand[0].exp.X_add_number) 
-                                               {
-                                               case 1:
-                                                       nib = 0;
-                                                       break;
-                                               case 2:
-                                                       nib = 8;
-                                                       break;
-                                               default:
-                                                       as_bad("Need #1 or #2 here");
-                                                       break;
-                                               }
-                                           /* stop it making a fix */
-                                           operand[0].mode = 0;
-                                           break;
-                                   case 0:
-                                   case 1:
-                                   case 2: case 3: case 4: case 5: case  6:
-                                   case 7: case 8: case 9: case 10: case 11: 
-                                   case  12: case 13: case 14: case 15:
-                                           nib = c;
-                                           break;
-                                   case DISPREG:
-                                           nib = operand[0].dispreg;
-                                           break;
-                                   case IMM8:
-                                           operand[0].mode = IMM8;
-                                           nib = 0;
-                                           break;
-                                           
-                                   case DISPDST:
-                                           nib = 0;
-                                           break;
-                                   case IMM3: 
-                                           if (operand[0].exp.X_add_symbol == 0) {
-                                                   operand[0].mode = 0; /* stop it making a fix */
-                                                   nib =  (operand[0].exp.X_add_number);
-                                           }
-                                           else as_bad("can't have symbol for bit number");
-                                           if (nib < 0 || nib > 7) 
-                                               {
-                                                       as_bad("Bit number out of range %d", nib);
-                                               }
-                                           
-                                           break;
-                                           
-                                   case ABS16DST:
-                                           nib = 0;
-                                           break;
-                                   case ABS8DST:
-                                           operand[1].mode = ABS8DST;
-                                           nib = 0;
-                                           break;
-                                   case ABS8SRC:
-                                           operand[0].mode = ABS8SRC;
-                                           nib = 0;
-                                           break;
-                                   case ABS16OR8DST:
-                                           operand[1].mode = c;
-                                           
-                                           nib = 0;
-                                           
-                                           break;
-                                           
-                                   case ABS16ORREL8SRC:
-                                           operand[0].mode = c;
-                                           nib=0;
-                                           break;
-                                           
-                                   case ABS16OR8SRC:
-                                           operand[0].mode = ABS16OR8SRC;
-                                           nib = 0;
-                                           break;
-                                   case DISPSRC:                   
-                                           operand[0].mode = ABS16SRC;
-                                           nib = 0;
-                                           break;
-                                           
-                                   case DISP8:
-                                           operand[0].mode = DISP8;
-                                           nib = 0;
-                                           break;
-                                           
-                                   case ABS16SRC:
-                                   case IMM16:
-                                   case IGNORE:
-                                   case MEMIND:
-                                           
-                                           nib=0;
-                                           break;
-                                   case RS8:
-                                   case RS16:
-                                   case RSIND:
-                                   case RSINC:
-                                           nib =  operand[0].reg;
-                                           break;
-                                           
-                                   case RD8:
-                                   case RD16:
-                                   case RDDEC:
-                                   case RDIND:
-                                           nib  = operand[1].reg;
-                                           break;
-                                           
-                                   case E: 
-                                           abort();
-                                           break;
-                                   }
-                               if (*nibble_ptr & B31) {
-                                       nib |=0x8;
-                               }
-                               
-                               if (nibble == 0) {
-                                       *output_ptr = nib << 4;
-                               }
-                               else {
-                                       *output_ptr |= nib;
-                                       output_ptr++;
-                               }
-                               nibble_ptr++;
-                       }
-                   
+             nib = operand[d].reg;
            }
-       
-       /* output any fixes */
-       for (i = 0; i < 2; i++) 
+         else if ((c & DISPREG) == (DISPREG))
            {
-                   switch (operand[i].mode) {
-                   case 0:
-                           break;
-                           
-                   case DISP8:
-                           check_operand(operand+i, 0x7f,"@");
-
-                           if (operand[i].exp.X_add_number & 1) {
-                             as_warn("branch operand has odd offset (%x)\n",
-                                     operand->exp.X_add_number);
-                           }
-                           
-                           fix_new(frag_now,
-                                   output - frag_now->fr_literal + 1, 
-                                   1,
-                                   operand[i].exp.X_add_symbol,
-                                   operand[i].exp.X_subtract_symbol,
-                                   operand[i].exp.X_add_number -1,
-                                   1,
-                                   R_PCRBYTE);
-                           break;
-                   case IMM8:
-                           check_operand(operand+i, 0xff,"#");
-                           /* If there is nothing else going on we can safely
-                              reloc in place */
-                           if (operand[i].exp.X_add_symbol == 0) 
-                               {
-                                       output[1] = operand[i].exp.X_add_number;
-                               }
-                           else 
-                               {
-                                       fix_new(frag_now,
-                                               output - frag_now->fr_literal + 1, 
-                                               1,
-                                               operand[i].exp.X_add_symbol,
-                                               operand[i].exp.X_subtract_symbol,
-                                               operand[i].exp.X_add_number,
-                                               0,
-                                               R_RELBYTE);
-                               }
-                           
-                           break;
-                   case MEMIND:
-                           check_operand(operand+i, 0xff,"@@");
-                           fix_new(frag_now,
-                                   output - frag_now->fr_literal + 1, 
-                                   1,
-                                   operand[i].exp.X_add_symbol,
-                                   operand[i].exp.X_subtract_symbol,
-                                   operand[i].exp.X_add_number,
-                                   0,
-                                   R_RELBYTE);
-                           break;
-                   case ABS8DST:
-                   case ABS8SRC:
-                           check_operand(operand+i, 0xff,"@");
-                           fix_new(frag_now,
-                                   output - frag_now->fr_literal + 1, 
-                                   1,
-                                   operand[i].exp.X_add_symbol,
-                                   operand[i].exp.X_subtract_symbol,
-                                   operand[i].exp.X_add_number,
-                                   0,
-                                   R_RELBYTE);
-                           break;
-                           
-                   case ABS16OR8SRC:           
-                   case ABS16OR8DST:
-                           check_operand(operand+i, 0xffff,"@");
-                           
-                           fix_new(frag_now,
-                                   output - frag_now->fr_literal + 2, 
-                                   2,
-                                   operand[i].exp.X_add_symbol,
-                                   operand[i].exp.X_subtract_symbol,
-                                   operand[i].exp.X_add_number,
-                                   0,
-                                   R_MOVB1);
-                           break;
-                           
-                   case ABS16ORREL8SRC:                
-                           check_operand(operand+i, 0xffff,"@");
-                           if (operand[i].exp.X_add_number & 1) {
-                             as_warn("branch operand has odd offset (%x)\n",
-                                     operand->exp.X_add_number);
-                           }
-                           fix_new(frag_now,
-                                   output - frag_now->fr_literal + 2, 
-                                   2,
-                                   operand[i].exp.X_add_symbol,
-                                   operand[i].exp.X_subtract_symbol,
-                                   operand[i].exp.X_add_number,
-                                   0,
-                                   R_JMP1);
-                           break;
-                           
-                           
-                   case ABS16SRC:
-                   case ABS16DST:
-                   case IMM16:
-                   case DISPSRC:
-                   case DISPDST:
-                           check_operand(operand+i, 0xffff,"@");
-                           if (operand[i].exp.X_add_symbol == 0) 
-                               {
-                                       /* This should be done with bfd */
-                                       output[3] = operand[i].exp.X_add_number & 0xff;   
-                                       output[2] = operand[i].exp.X_add_number >> 8;
-                                       
-                               }
-                           else 
-                               {
-                                       
-                                       fix_new(frag_now,
-                                               output - frag_now->fr_literal + 2, 
-                                               2,
-                                               operand[i].exp.X_add_symbol,
-                                               operand[i].exp.X_subtract_symbol,
-                                               operand[i].exp.X_add_number,
-                                               0,
-                                               R_RELWORD);
-                               }
-                           
-                           break;
-                   case RS8:
-                   case RD8:
-                   case RS16:
-                   case RD16:
-                   case RDDEC: 
-                   case KBIT:
-                   case RSINC:
-                   case RDIND:
-                   case RSIND:
-                   case CCR:
-                           
-                           break;
-                   default:
-                           abort();
-                   }
+             nib = dispreg;
            }
-       
-}
-/*
-  try and give an intelligent error message for common and simple to
-  detect errors
-  */
 
-static void
-    DEFUN(clever_message, (opcode, operand),
-         struct h8_opcode *opcode AND
-         struct h8_op *operand)
-{
-  struct h8_opcode *scan = opcode;
-       
-  /* Find out if there was more than one possible opccode */  
-       
-  if ((opcode+1)->idx != opcode->idx) 
-  {
-    unsigned int argn;
-                   
-    /* Only one opcode of this flavour, try and guess which operand
-       didn't match */
-    for (argn = 0; argn < opcode->noperands; argn++) 
+         else if (c & ABSMOV) 
+           {
+             operand[d].mode &= ~ABS;
+             operand[d].mode |= ABSMOV;
+             immat = nibble_count / 2;
+             nib = 0;
+           }
+         else if (c & (IMM | PCREL | ABS | ABSJMP | DISP ))
+           {
+             operand[d].mode = c;
+             immat = nibble_count / 2;
+             nib = 0;
+           }
+         else if (c & IGNORE)
+           {
+             nib = 0;
+           }
+         else if (c & DBIT)
+           {
+             switch (operand[0].exp.X_add_number)
+               {
+               case 1:
+                 nib = c;
+                 break;
+               case 2:
+                 nib = 0x8 | c;
+                 break;
+               default:
+                 as_bad ("Need #1 or #2 here");
+               }
+           }
+         else if (c & KBIT)
+           {
+             switch (operand[0].exp.X_add_number)
+               {
+               case 1:
+                 nib = 0;
+                 break;
+               case 2:
+                 nib = 8;
+                 break;
+               case 4:
+                 if (!Hmode)
+                   as_warn ("#4 only valid in h8/300 mode.");
+                 nib = 9;
+                 break;
+
+               default:
+                 as_bad ("Need #1 or #2 here");
+                 break;
+               }
+             /* stop it making a fix */
+             operand[0].mode = 0;
+           }
+
+         if (c & B31)
+           {
+             nib |= 0x8;
+           }
+       }
+      nibble_count++;
+
+      *p++ = nib;
+    }
+
+  for (i = 0; i < this_try->length; i++)
+    {
+      output[i] = (asnibbles[i * 2] << 4) | asnibbles[i * 2 + 1];
+    }
+
+  /* output any fixes */
+  for (i = 0; i < 2; i++)
     {
-      switch (opcode->args.nib[argn]) 
-      {
-      case RD16:
-       if (operand[argn].mode != RD16)        
+      int x = operand[i].mode;
+
+      if (x & (IMM | ABS | DISP))
        {
-         as_bad("destination operand must be 16 bit register");          
-         return;
-                                                       
+         do_a_fix_imm (output - frag_now->fr_literal + immat, operand + i,0);
        }
-       break;
-                                           
-      case RS8:
-                                           
-       if (operand[argn].mode != RS8) 
+      else if (x & PCREL)
        {
-         as_bad("source operand must be 8 bit register");
-         return;
+         int size16 = x & L_16;
+         int where = size16 ? 2 : 1;
+         int size = size16 ? 2 : 1;
+         int type = size16 ? R_PCRWORD : R_PCRBYTE;
+
+         check_operand (operand + i, size16 ? 0x7fff : 0x7f, "@");
+
+         if (operand[i].exp.X_add_number & 1)
+           {
+             as_warn ("branch operand has odd offset (%x)\n",
+                      operand->exp.X_add_number);
+           }
+
+         fix_new (frag_now,
+                  output - frag_now->fr_literal + where,
+                  size,
+                  operand[i].exp.X_add_symbol,
+                  operand[i].exp.X_subtract_symbol,
+                  (char) (operand[i].exp.X_add_number - 1),
+                  1,
+                  type);
        }
-       break;
-                                           
-      case ABS16DST:
-       if (operand[argn].mode != ABS16DST) 
+      else if (x & MEMIND)
        {
-         as_bad("destination operand must be 16bit absolute address");
-         return;
+
+         check_operand (operand + i, 0xff, "@@");
+         fix_new (frag_now,
+                  output - frag_now->fr_literal + 1,
+                  1,
+                  operand[i].exp.X_add_symbol,
+                  operand[i].exp.X_subtract_symbol,
+                  operand[i].exp.X_add_number,
+                  0,
+                  R_RELBYTE);
        }
-break;                                     
-      case RD8:
-       if (operand[argn].mode != RD8) 
+
+      else if (x & ABSMOV)
        {
-         as_bad("destination operand must be 8 bit register");  
-       return;
+         /* This mov is either absolute long or thru a memory loc */
+         do_a_fix_imm (output - frag_now->fr_literal + immat, operand + i,1);
        }
-       break;
-       
-                                           
-      case ABS16SRC:
-       if (operand[argn].mode != ABS16SRC) 
+
+      else if (x & ABSJMP)
        {
-         as_bad("source operand must be 16bit absolute address");
-         return;
+         /* This jmp may be a jump or a branch */
+
+         check_operand (operand + i, Hmode ? 0xfffff : 0xffff, "@");
+         if (operand[i].exp.X_add_number & 1)
+           {
+             as_warn ("branch operand has odd offset (%x)\n",
+                      operand->exp.X_add_number);
+           }
+         fix_new (frag_now,
+                  output - frag_now->fr_literal,
+                  4,
+                  operand[i].exp.X_add_symbol,
+                  operand[i].exp.X_subtract_symbol,
+                  (short) (operand[i].exp.X_add_number),
+                  0,
+                  R_JMPL1);
        }
-       break;
-       
-      }
     }
-  }
-  as_bad("invalid operands");
+
+}
+
+/*
+  try and give an intelligent error message for common and simple to
+  detect errors
+  */
+
+static void
+DEFUN (clever_message, (opcode, operand),
+       struct h8_opcode *opcode AND
+       struct h8_op *operand)
+{
+  struct h8_opcode *scan = opcode;
+
+  /* Find out if there was more than one possible opccode */
+
+  if ((opcode + 1)->idx != opcode->idx)
+    {
+      unsigned int argn;
+
+      /* Only one opcode of this flavour, try and guess which operand
+         didn't match */
+      for (argn = 0; argn < opcode->noperands; argn++)
+       {
+         switch (opcode->args.nib[argn])
+           {
+           case RD16:
+             if (operand[argn].mode != RD16)
+               {
+                 as_bad ("destination operand must be 16 bit register");
+                 return;
+
+               }
+             break;
+
+           case RS8:
+
+             if (operand[argn].mode != RS8)
+               {
+                 as_bad ("source operand must be 8 bit register");
+                 return;
+               }
+             break;
+
+           case ABS16DST:
+             if (operand[argn].mode != ABS16DST)
+               {
+                 as_bad ("destination operand must be 16bit absolute address");
+                 return;
+               }
+             break;
+           case RD8:
+             if (operand[argn].mode != RD8)
+               {
+                 as_bad ("destination operand must be 8 bit register");
+                 return;
+               }
+             break;
+
+
+           case ABS16SRC:
+             if (operand[argn].mode != ABS16SRC)
+               {
+                 as_bad ("source operand must be 16bit absolute address");
+                 return;
+               }
+             break;
+
+           }
+       }
+    }
+  as_bad ("invalid operands");
 }
 
 /* This is the guts of the machine-dependent assembler.  STR points to a
@@ -1005,106 +1101,111 @@ break;
 
 
 
-void 
-    DEFUN(md_assemble,(str),
-         char *str)
+void
+DEFUN (md_assemble, (str),
+       char *str)
 {
-       char *op_start;
-       char *op_end;
-       unsigned int i;
-       struct       h8_op operand[2];  
-       struct h8_opcode * opcode;
-       struct h8_opcode * prev_opcode;
-       
-       char *dot = 0;
-       char c;    
-       /* Drop leading whitespace */
-       while (*str == ' ')
-           str++;
-       
-       /* find the op code end */
-       for (op_start = op_end = str;
-            *op_end != 0 && *op_end != ' ';
-            op_end ++) 
-           {
-                   if (*op_end == '.') {
-                           dot = op_end+1;
-                           *op_end = 0;
-                           op_end+=2;
-                           break;
-                   }
-           }
-       
-       ;
-       
-       if (op_end == op_start) 
-           {
-                   as_bad("can't find opcode ");
-           }
-       c = *op_end;
-       
-       *op_end = 0;
-       
-       opcode = (struct h8_opcode *) hash_find(opcode_hash_control,
-                                               op_start);
-       
-       if (opcode == NULL) 
-           {
-                   as_bad("unknown opcode");
-                   return;
-           }
-       
-       
-       input_line_pointer =   get_operands(opcode->noperands, op_end,
-                                           operand);
-       *op_end = c;
-       prev_opcode = opcode;
-       
-       opcode = get_specific(opcode,  operand);
-       
-       if (opcode == 0)  
-           {
-                   /* Couldn't find an opcode which matched the operands */
-                   char *where =frag_more(2);
-                   where[0] = 0x0;
-                   where[1] = 0x0;
-                   clever_message(prev_opcode, operand);
-                   
-                   return;
-           }
-       if (opcode->size && dot) 
-           {
-                   if (opcode->size != *dot) 
-                       {
-                               as_warn("mismatch between opcode size and operand size");
-                       }
-           }
-       
-       build_bytes(opcode, operand);
-       
+  char *op_start;
+  char *op_end;
+  unsigned int i;
+  struct h8_op operand[2];
+  struct h8_opcode *opcode;
+  struct h8_opcode *prev_opcode;
+
+  char *dot = 0;
+  char c;
+
+  /* Drop leading whitespace */
+  while (*str == ' ')
+    str++;
+
+  /* find the op code end */
+  for (op_start = op_end = str;
+       *op_end != 0 && *op_end != ' ';
+       op_end++)
+    {
+      if (*op_end == '.')
+       {
+         dot = op_end + 1;
+         *op_end = 0;
+         op_end += 2;
+         break;
+       }
+    }
+
+  ;
+
+  if (op_end == op_start)
+    {
+      as_bad ("can't find opcode ");
+    }
+  c = *op_end;
+
+  *op_end = 0;
+
+  opcode = (struct h8_opcode *) hash_find (opcode_hash_control,
+                                          op_start);
+
+  if (opcode == NULL)
+    {
+      as_bad ("unknown opcode");
+      return;
+    }
+
+
+  input_line_pointer = get_operands (opcode->noperands, op_end,
+                                    operand);
+  *op_end = c;
+  prev_opcode = opcode;
+
+  opcode = get_specific (opcode, operand);
+
+  if (opcode == 0)
+    {
+      /* Couldn't find an opcode which matched the operands */
+      char *where = frag_more (2);
+
+      where[0] = 0x0;
+      where[1] = 0x0;
+      clever_message (prev_opcode, operand);
+
+      return;
+    }
+  if (opcode->size && dot)
+    {
+      if (opcode->size != *dot)
+       {
+         as_warn ("mismatch between opcode size and operand size");
+       }
+    }
+
+  build_bytes (opcode, operand);
+
 }
 
-void 
-    DEFUN(tc_crawl_symbol_chain, (headers),
-         object_headers *headers)
+void
+DEFUN (tc_crawl_symbol_chain, (headers),
+       object_headers * headers)
 {
-       printf("call to tc_crawl_symbol_chain \n");
+  printf ("call to tc_crawl_symbol_chain \n");
 }
 
-symbolS *DEFUN(md_undefined_symbol,(name),
-              char *name)
+symbolS *
+DEFUN (md_undefined_symbol, (name),
+       char *name)
 {
-       return 0;
+  return 0;
 }
 
-void 
-    DEFUN(tc_headers_hook,(headers),
-         object_headers *headers)
+void
+DEFUN (tc_headers_hook, (headers),
+       object_headers * headers)
 {
-       printf("call to tc_headers_hook \n"); 
+  printf ("call to tc_headers_hook \n");
 }
+
 void
-    DEFUN_VOID(md_end) 
+DEFUN_VOID (md_end)
 {
 }
 
@@ -1117,212 +1218,250 @@ void
    emitted is stored in *sizeP .  An error message is returned, or NULL on OK.
    */
 char *
-    md_atof(type,litP,sizeP)
-char type;
-char *litP;
-int *sizeP;
+md_atof (type, litP, sizeP)
+     char type;
+     char *litP;
+     int *sizeP;
 {
-       int     prec;
-       LITTLENUM_TYPE words[MAX_LITTLENUMS];
-       LITTLENUM_TYPE *wordP;
-       char    *t;
-       char    *atof_ieee();
-       
-       switch(type) {
-       case 'f':
-       case 'F':
-       case 's':
-       case 'S':
-               prec = 2;
-               break;
-               
-       case 'd':
-       case 'D':
-       case 'r':
-       case 'R':
-               prec = 4;
-               break;
-               
-       case 'x':
-       case 'X':
-               prec = 6;
-               break;
-               
-       case 'p':
-       case 'P':
-               prec = 6;
-               break;
-               
-       default:
-               *sizeP=0;
-               return "Bad call to MD_ATOF()";
-       }
-       t=atof_ieee(input_line_pointer,type,words);
-       if(t)
-           input_line_pointer=t;
-       
-       *sizeP=prec * sizeof(LITTLENUM_TYPE);
-       for(wordP=words;prec--;) {
-               md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE));
-               litP+=sizeof(LITTLENUM_TYPE);
-       }
-       return "";      /* Someone should teach Dean about null pointers */
+  int prec;
+  LITTLENUM_TYPE words[MAX_LITTLENUMS];
+  LITTLENUM_TYPE *wordP;
+  char *t;
+  char *atof_ieee ();
+
+  switch (type)
+    {
+    case 'f':
+    case 'F':
+    case 's':
+    case 'S':
+      prec = 2;
+      break;
+
+    case 'd':
+    case 'D':
+    case 'r':
+    case 'R':
+      prec = 4;
+      break;
+
+    case 'x':
+    case 'X':
+      prec = 6;
+      break;
+
+    case 'p':
+    case 'P':
+      prec = 6;
+      break;
+
+    default:
+      *sizeP = 0;
+      return "Bad call to MD_ATOF()";
+    }
+  t = atof_ieee (input_line_pointer, type, words);
+  if (t)
+    input_line_pointer = t;
+
+  *sizeP = prec * sizeof (LITTLENUM_TYPE);
+  for (wordP = words; prec--;)
+    {
+      md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE));
+      litP += sizeof (LITTLENUM_TYPE);
+    }
+  return "";
 }
 
 int
-    md_parse_option(argP, cntP, vecP)
-char **argP;
-int *cntP;
-char ***vecP;
+md_parse_option (argP, cntP, vecP)
+     char **argP;
+     int *cntP;
+     char ***vecP;
 
 {
-       return 0;
-       
+  return 0;
+
 }
 
 int md_short_jump_size;
 
-void tc_aout_fix_to_chars () { printf("call to tc_aout_fix_to_chars \n");
-                              abort(); }
-void md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol)
-char *ptr;
-long from_addr;
-long to_addr;
-fragS *frag;
-symbolS *to_symbol;
+void
+tc_aout_fix_to_chars ()
+{
+  printf ("call to tc_aout_fix_to_chars \n");
+  abort ();
+}
+
+void
+md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
+     char *ptr;
+     addressT from_addr;
+     addressT to_addr;
+     fragS *frag;
+     symbolS *to_symbol;
 {
-       as_fatal("failed sanity check.");
+  as_fatal ("failed sanity check.");
 }
 
 void
-    md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol)
-char *ptr;
-long from_addr, to_addr;
-fragS *frag;
-symbolS *to_symbol;
+md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
+     char *ptr;
+     addressT from_addr, to_addr;
+     fragS *frag;
+     symbolS *to_symbol;
 {
-       as_fatal("failed sanity check.");
+  as_fatal ("failed sanity check.");
 }
 
 void
-    md_convert_frag(headers, fragP)
-object_headers *headers;
-fragS * fragP;
+md_convert_frag (headers, fragP)
+     object_headers *headers;
+     fragS *fragP;
 
-{ printf("call to md_convert_frag \n"); abort(); }
+{
+  printf ("call to md_convert_frag \n");
+  abort ();
+}
 
-long
-    DEFUN(md_section_align,(seg, size),
-         segT seg AND
-         long size)
+valueT
+DEFUN (md_section_align, (seg, size),
+       segT seg AND
+       valueT size)
 {
-       return((size + (1 << section_alignment[(int) seg]) - 1) & (-1 << section_alignment[(int) seg]));
-       
+  return ((size + (1 << section_alignment[(int) seg]) - 1) & (-1 << section_alignment[(int) seg]));
+
 }
 
 void
-    md_apply_fix(fixP, val)
-fixS *fixP;
-long val;
+md_apply_fix (fixP, val)
+     fixS *fixP;
+     long val;
 {
-       char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
-       
-       switch(fixP->fx_size) {
-       case 1:
-               *buf++=val;
-               break;
-       case 2:
-               *buf++=(val>>8);
-               *buf++=val;
-               break;
-       case 4:
-               *buf++=(val>>24);
-               *buf++=(val>>16);
-               *buf++=(val>>8);
-               *buf++=val;
-               break;
-       default:
-               abort();
-               
-       }
+  char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+
+  switch (fixP->fx_size)
+    {
+    case 1:
+      *buf++ = val;
+      break;
+    case 2:
+      *buf++ = (val >> 8);
+      *buf++ = val;
+      break;
+    case 4:
+      *buf++ = (val >> 24);
+      *buf++ = (val >> 16);
+      *buf++ = (val >> 8);
+      *buf++ = val;
+      break;
+    default:
+      abort ();
+
+    }
 }
 
-void DEFUN(md_operand, (expressionP),expressionS *expressionP) 
-{ }
+void
+DEFUN (md_operand, (expressionP), expressionS * expressionP)
+{
+}
 
-int  md_long_jump_size;
+int md_long_jump_size;
 int
-    md_estimate_size_before_relax(fragP, segment_type)
-register fragS *fragP;
-register segT segment_type;
-{ 
-       printf("call tomd_estimate_size_before_relax \n"); abort(); }
+md_estimate_size_before_relax (fragP, segment_type)
+     register fragS *fragP;
+     register segT segment_type;
+{
+  printf ("call tomd_estimate_size_before_relax \n");
+  abort ();
+}
+
 /* Put number into target byte order */
 
-void DEFUN(md_number_to_chars,(ptr, use, nbytes),
-          char *ptr AND
-          long use AND
-          int nbytes)
+void
+DEFUN (md_number_to_chars, (ptr, use, nbytes),
+       char *ptr AND
+       valueT use AND
+       int nbytes)
 {
-       switch (nbytes) {
-       case 4: *ptr++ = (use >> 24) & 0xff;
-       case 3: *ptr++ = (use >> 16) & 0xff;
-       case 2: *ptr++ = (use >> 8) & 0xff;
-       case 1: *ptr++ = (use >> 0) & 0xff;
-               break;
-       default:
-               abort();
-       }
+  switch (nbytes)
+    {
+    case 4:
+      *ptr++ = (use >> 24) & 0xff;
+    case 3:
+      *ptr++ = (use >> 16) & 0xff;
+    case 2:
+      *ptr++ = (use >> 8) & 0xff;
+    case 1:
+      *ptr++ = (use >> 0) & 0xff;
+      break;
+    default:
+      abort ();
+    }
+}
+long
+md_pcrel_from (fixP)
+     fixS *fixP;
+{
+  abort ();
 }
-long md_pcrel_from(fixP) 
-fixS *fixP; { abort(); }
 
-void tc_coff_symbol_emit_hook() { }
+void
+tc_coff_symbol_emit_hook ()
+{
+}
 
 
-void tc_reloc_mangle(fix_ptr, intr, base)
-fixS *fix_ptr;
-struct internal_reloc *intr;
-bfd_vma base;
+void
+tc_reloc_mangle (fix_ptr, intr, base)
+     fixS *fix_ptr;
+     struct internal_reloc *intr;
+     bfd_vma base;
 
 {
-       symbolS *symbol_ptr;
-       
-       symbol_ptr = fix_ptr->fx_addsy;
-       
-       /* If this relocation is attached to a symbol then it's ok
-          to output it */
-       if (fix_ptr->fx_r_type == RELOC_32) {
-               /* cons likes to create reloc32's whatever the size of the reloc..
-                */
-               switch (fix_ptr->fx_size) 
-                   {
-                           
-                   case 2:
-                           intr->r_type = R_RELWORD;
-                           break;
-                   case 1:
-                           intr->r_type = R_RELBYTE;
-                           break;
-                   default:
-                           abort();
-                           
-                   }
-               
-       }
-       else {  
-               intr->r_type = fix_ptr->fx_r_type;
+  symbolS *symbol_ptr;
+
+  symbol_ptr = fix_ptr->fx_addsy;
+
+  /* If this relocation is attached to a symbol then it's ok
+     to output it */
+  if (fix_ptr->fx_r_type == RELOC_32)
+    {
+      /* cons likes to create reloc32's whatever the size of the reloc..
+       */
+      switch (fix_ptr->fx_size)
+       {
+
+       case 2:
+         intr->r_type = R_RELWORD;
+         break;
+       case 1:
+         intr->r_type = R_RELBYTE;
+         break;
+       default:
+         abort ();
+
        }
-       
-       intr->r_vaddr = fix_ptr->fx_frag->fr_address +  fix_ptr->fx_where  +base;
-       intr->r_offset = fix_ptr->fx_offset;
-       
-       if (symbol_ptr)
-           intr->r_symndx = symbol_ptr->sy_number;
-       else
-           intr->r_symndx = -1;
-       
-       
+
+    }
+  else
+    {
+      intr->r_type = fix_ptr->fx_r_type;
+    }
+
+  intr->r_vaddr = fix_ptr->fx_frag->fr_address + fix_ptr->fx_where + base;
+  intr->r_offset = fix_ptr->fx_offset;
+
+  if (symbol_ptr)
+    intr->r_symndx = symbol_ptr->sy_number;
+  else
+    intr->r_symndx = -1;
+
+
+}
+
+tc_coff_sizemachdep ()
+{
+  abort ();
 }
 
 /* end of tc-h8300.c */
index f64a8b64d887076f54a05beb2440008110e2d235..baf4cb36860146b205dd2472737805c9de3c8777 100644 (file)
@@ -1244,8 +1244,8 @@ tc_aout_fix_to_chars ()
 void
 md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
      char *ptr;
-     long from_addr;
-     long to_addr;
+     addressT from_addr;
+     addressT to_addr;
      fragS *frag;
      symbolS *to_symbol;
 {
@@ -1255,7 +1255,7 @@ md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
 void
 md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
      char *ptr;
-     long from_addr, to_addr;
+     addressT from_addr, to_addr;
      fragS *frag;
      symbolS *to_symbol;
 {
@@ -1402,10 +1402,10 @@ md_convert_frag (headers, fragP)
 
 }
 
-long
+valueT
 DEFUN (md_section_align, (seg, size),
        segT seg AND
-       long size)
+       valueT size)
 {
   return ((size + (1 << section_alignment[(int) seg]) - 1) 
          & (-1 << section_alignment[(int) seg]));
@@ -1506,7 +1506,7 @@ md_estimate_size_before_relax (fragP, segment_type)
 void
 md_number_to_chars (ptr, use, nbytes)
      char *ptr;
-     long use;
+     valueT use;
      int nbytes;
 {
   switch (nbytes)
diff --git a/gas/config/tc-hppa.c b/gas/config/tc-hppa.c
new file mode 100644 (file)
index 0000000..581a0bf
--- /dev/null
@@ -0,0 +1,6941 @@
+/* tc-hppa.c -- Assemble for the PA
+   Copyright (C) 1989 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
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GAS is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GAS; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+/*
+   HP PA-RISC support was contributed by the Center for Software Science
+   at the University of Utah.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "as.h"
+#include "subsegs.h"
+
+/* #include "../bfd/libhppa.h" */
+/*
+ * Unwind table and descriptor.
+ */
+
+struct unwind_desc
+  {
+    unsigned int cannot_unwind:1;
+    unsigned int millicode:1;
+    unsigned int millicode_save_rest:1;
+    unsigned int region_desc:2;
+    unsigned int save_sr:2;
+    unsigned int entry_fr:4;   /* number saved */
+    unsigned int entry_gr:5;   /* number saved */
+    unsigned int args_stored:1;
+    unsigned int call_fr:5;
+    unsigned int call_gr:5;
+    unsigned int save_sp:1;
+    unsigned int save_rp:1;
+    unsigned int save_rp_in_frame:1;
+    unsigned int extn_ptr_defined:1;
+    unsigned int cleanup_defined:1;
+
+    unsigned int hpe_interrupt_marker:1;
+    unsigned int hpux_interrupt_marker:1;
+    unsigned int reserved:3;
+    unsigned int frame_size:27;
+  };
+
+typedef struct unwind_desc unwind_descS;
+
+struct unwind_table
+  {
+    unsigned int start_offset; /* starting offset (from SR4) of applicable region */
+    unsigned int end_offset;   /* ending offset (from SR4) of applicable region */
+    unwind_descS descriptor;
+  };
+
+typedef struct unwind_table unwind_tableS;
+
+/*
+ * This structure is used by the .callinfo, .enter, .leave pseudo-ops to
+ * control the entry and exit code they generate. It is also used in
+ * creation of the correct stack unwind descriptors.
+ *
+ * The fields in structure roughly correspond to the arguments available on the
+ * .callinfo pseudo-op.
+ */
+
+struct call_info
+  {
+    int frame;
+    int entry_sr;
+    int makes_calls;
+    int hpux_int;
+    unwind_tableS ci_unwind;   /* the unwind descriptor we are building */
+    symbolS *start_symbol;     /* name of function (used in relocation info) */
+    symbolS *end_symbol;       /* temporary symbol used to mark the */
+    /* end of the function (used in */
+    /* relocation info) */
+    fragS *start_frag;         /* frag associated w/ start of this function */
+    fragS *end_frag;           /* frag associated w/ end of this function */
+    fragS *start_offset_frag;  /* frag for start offset of this descriptor */
+    int start_frag_where;      /* where in start_offset_frag is start_offset */
+    fixS *start_fix;           /* fixup for the start_offset */
+    fragS *end_offset_frag;    /* frag for start offset of this descriptor */
+    int end_frag_where;                /* where in end_offset_frag is end_offset */
+    fixS *end_fix;             /* fixup for the end_offset */
+    struct call_info *ci_next; /* the next call_info structure */
+  };
+
+typedef struct call_info call_infoS;
+
+call_infoS *last_call_info;
+call_infoS *call_info_root;
+call_descS last_call_desc;
+
+/* A structure used during assembly of individual instructions */
+
+struct pa_it
+  {
+    char *error;
+    unsigned long opcode;
+    /* symbol_dictS *nlistp; *//*** used to be:    struct nlist *nlistp; */
+    asymbol *nlistp;
+    expressionS exp;
+    int pcrel;
+    FP_Operand_Format fpof1;   /* Floating Point Operand Format, operand 1 */
+    FP_Operand_Format fpof2;   /* Floating Point Operand Format, operand 2 */
+    /* (used only for class 1 instructions --   */
+    /* the conversion instructions)             */
+#ifdef OBJ_SOM
+    long field_selector;
+    unsigned int reloc;
+    int code;
+    long arg_reloc;
+    unwind_descS unwind;
+#endif
+#ifdef OBJ_ELF
+    elf32_hppa_reloc_type reloc;
+    long field_selector;
+    int format;
+    long arg_reloc;
+    unwind_descS unwind;
+#endif
+  };
+
+extern struct pa_it the_insn;
+
+/* careful, this file includes data *declarations* */
+#include "opcode/hppa.h"
+
+void md_begin ();
+void md_end ();
+void md_number_to_chars ();
+void md_assemble ();
+char *md_atof ();
+void md_convert_frag ();
+void md_create_short_jump ();
+void md_create_long_jump ();
+int md_estimate_size_before_relax ();
+void md_number_to_imm ();
+void md_number_to_disp ();
+void md_number_to_field ();
+void md_ri_to_chars ();
+void emit_relocations ();
+static void pa_ip ();
+
+const relax_typeS md_relax_table[] =
+{0};
+/* handle of the OPCODE hash table */
+static struct hash_control *op_hash = NULL;
+
+int md_short_jump_size = 4;
+int md_long_jump_size = 4;
+
+/* This array holds the chars that always start a comment.  If the
+    pre-processor is disabled, these aren't very useful */
+const char comment_chars[] = ";";      /* JF removed '|' from comment_chars */
+
+const pseudo_typeS
+  md_pseudo_table[] =
+{
+  {"align", s_align_bytes, 0}, /* .align 4 means .align to 4-byte boundary */
+  {"ALIGN", s_align_bytes, 0}, /* .align 4 means .align to 4-byte boundary */
+  {"block", pa_block, 1},
+  {"BLOCK", pa_block, 1},
+  {"blockz", pa_block, 0},
+  {"BLOCKZ", pa_block, 0},
+  {"byte", pa_cons, 1},
+  {"BYTE", pa_cons, 1},
+  {"call", pa_call, 0},
+  {"CALL", pa_call, 0},
+  {"callinfo", pa_callinfo, 0},
+  {"CALLINFO", pa_callinfo, 0},
+  {"code", pa_code, 0},
+  {"CODE", pa_code, 0},
+  {"comm", pa_comm, 0},
+  {"COMM", pa_comm, 0},
+  {"copyright", pa_copyright, 0},
+  {"COPYRIGHT", pa_copyright, 0},
+  {"data", pa_data, 0},
+  {"DATA", pa_data, 0},
+  {"desc", pa_desc, 0},
+  {"DESC", pa_desc, 0},
+  {"double", pa_float_cons, 'd'},
+  {"DOUBLE", pa_float_cons, 'd'},
+  {"end", pa_end, 0},
+  {"END", pa_end, 0},
+  {"enter", pa_enter, 0},
+  {"ENTER", pa_enter, 0},
+  {"entry", pa_entry, 0},
+  {"ENTRY", pa_entry, 0},
+  {"equ", pa_equ, 0},
+  {"EQU", pa_equ, 0},
+  {"exit", pa_exit, 0},
+  {"EXIT", pa_exit, 0},
+  {"export", pa_export, 0},
+  {"EXPORT", pa_export, 0},
+  {"fill", pa_fill, 0},
+  {"FILL", pa_fill, 0},
+  {"float", pa_float_cons, 'f'},
+  {"FLOAT", pa_float_cons, 'f'},
+  {"half", pa_cons, 2},
+  {"HALF", pa_cons, 2},
+  {"import", pa_import, 0},
+  {"IMPORT", pa_import, 0},
+  {"int", pa_cons, 4},
+  {"INT", pa_cons, 4},
+  {"label", pa_label, 0},
+  {"LABEL", pa_label, 0},
+  {"lcomm", pa_lcomm, 0},
+  {"LCOMM", pa_lcomm, 0},
+  {"leave", pa_leave, 0},
+  {"LEAVE", pa_leave, 0},
+  {"long", pa_cons, 4},
+  {"LONG", pa_cons, 4},
+  {"lsym", pa_lsym, 0},
+  {"LSYM", pa_lsym, 0},
+  {"octa", pa_big_cons, 16},
+  {"OCTA", pa_big_cons, 16},
+  {"org", pa_origin, 0},
+  {"ORG", pa_origin, 0},
+  {"origin", pa_origin, 0},
+  {"ORIGIN", pa_origin, 0},
+  {"proc", pa_proc, 0},
+  {"PROC", pa_proc, 0},
+  {"procend", pa_procend, 0},
+  {"PROCEND", pa_procend, 0},
+  {"quad", pa_big_cons, 8},
+  {"QUAD", pa_big_cons, 8},
+  {"reg", pa_equ, 1},          /* very similar to .equ */
+  {"REG", pa_equ, 1},          /* very similar to .equ */
+  {"short", pa_cons, 2},
+  {"SHORT", pa_cons, 2},
+  {"single", pa_float_cons, 'f'},
+  {"SINGLE", pa_float_cons, 'f'},
+  {"space", pa_space, 0},
+  {"SPACE", pa_space, 0},
+  {"spnum", pa_spnum, 0},
+  {"SPNUM", pa_spnum, 0},
+  {"string", pa_stringer, 0},
+  {"STRING", pa_stringer, 0},
+  {"stringz", pa_stringer, 1},
+  {"STRINGZ", pa_stringer, 1},
+  {"subspa", pa_subspace, 0},
+  {"SUBSPA", pa_subspace, 0},
+  {"text", pa_text, 0},
+  {"TEXT", pa_text, 0},
+  {"version", pa_version, 0},
+  {"VERSION", pa_version, 0},
+  {"word", pa_cons, 4},
+  {"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 */
+/* Note that input_file.c hand checks for '#' at the beginning of the
+   first line of the input file.  This is because the compiler outputs
+   #NO_APP at the beginning of its output. */
+/* Also note that '/*' will always start a comment */
+const char line_comment_chars[] = "#";
+
+const char line_separator_chars[] = "!";
+
+/* Chars that can be used to separate mant from exp in floating point nums */
+const char EXP_CHARS[] = "eE";
+
+/* Chars that mean this number is a floating point constant */
+/* As in 0f12.456 */
+/* or    0d1.2345e12 */
+const char FLT_CHARS[] = "rRsSfFdDxXpP";
+
+/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
+   changed in read.c .  Ideally it shouldn't have to know about it at all,
+   but nothing is ideal around here.
+ */
+
+static unsigned char octal[256];
+#ifndef isoctal
+#define isoctal(c)  octal[c]
+#endif
+static unsigned char toHex[256];
+
+struct pa_it set_insn;         /* this structure is defined above */
+
+/* SKV 12/22/92.  Added prev_insn, prev_fix, and initialized the_insn
+   so that we can recognize instruction sequences such as (ldil, ble)
+   and generate the appropriate fixups. */
+
+struct pa_it the_insn =
+{
+  NULL,                                /* error */
+  0,                           /* opcode */
+  NULL,                                /* nlistp */
+  {
+    NULL,                      /* exp.X_add_symbol */
+    NULL,                      /* exp.X_subtract_symbol */
+    0,                         /* exp.X_add_number */
+    NULL                       /* exp.asection */
+  },
+  0,                           /* pcrel */
+  0,                           /* fpof1 */
+  0,                           /* fpof2 */
+  0,                           /* reloc */
+  0,                           /* field_selector */
+  0,                           /* code */
+  0,                           /* arg_reloc */
+  {                            /* unwind */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+  }
+};
+
+#ifdef OBJ_ELF
+
+struct pa_it prev_insn;
+char prev_str[10] = "";
+fixS *prev_fix = NULL;
+fixS *curr_fix = NULL;
+
+#endif /* OBJ_ELF */
+
+#ifdef __STDC__
+void print_insn (struct pa_it *insn);
+#else
+void print_insn ();
+#endif
+char *expr_end;
+
+symbolS *label_symbolP;                /* the last label symbol encountered */
+/* saved here in case a .equ is encountered */
+int label_symbol_defined;
+
+int callinfo_found;            /* T if a .callinfo appeared within the current */
+/*  procedure definition and F otherwise        */
+
+int within_entry_exit;         /* T if the assembler is currently within a     */
+/* .entry/.exit pair and F otherwise            */
+
+int exit_processing_complete;  /* T is the assembler has completed exit */
+/* processing for the current procedure  */
+/* and F otherwise                       */
+
+int within_procedure;          /* T if the assembler is currently within a  */
+/* a procedure definition and F otherwise    */
+
+void ignore_rest_of_line ();   /* a useful function in read.c */
+
+/* default space and subspace dictionaries */
+
+#define GDB_SYMBOLS          GDB_SYMBOLS_SUBSPACE_NAME
+#define GDB_STRINGS          GDB_STRINGS_SUBSPACE_NAME
+
+#if defined(OBJ_ELF)
+struct default_subspace_dict pa_def_subspaces[] =
+{
+  {"$CODE$", 0, 1, 0, 0, 0, 0, 24, 0x2c, 0, 8, 0, 0, ".text", SUBSEG_CODE},
+  {"$DATA$", 0, 1, 0, 0, 0, 0, 24, 0x1f, 0, 8, 1, 1, ".data", SUBSEG_DATA},
+  {"$LIT$", 0, 1, 0, 0, 0, 0, 16, 0x2c, 0, 8, 0, 0, ".text", SUBSEG_LIT},
+  {"$BSS$", 0, 1, 0, 0, 0, 1, 80, 0x1f, 0, 8, 1, 1, ".bss", SUBSEG_BSS},
+  {"$UNWIND$", 0, 1, 0, 0, 0, 0, 64, 0x2c, 0, 4, 0, 0, ".hppa_unwind", SUBSEG_UNWIND},
+  {GDB_STRINGS, 0, 0, 0, 0, 0, 0, 254, 0x1f, 0, 4, 0, 2, ".stabstr", SUBSEG_GDB_STRINGS},
+  {GDB_SYMBOLS, 0, 0, 0, 0, 0, 0, 255, 0x1f, 0, 4, 0, 2, ".stab", SUBSEG_GDB_SYMBOLS},
+  {NULL, 0, 1, 0, 0, 0, 0, 255, 0x1f, 0, 4, 0, 0, 0}
+};
+
+struct default_space_dict pa_def_spaces[] =
+{
+  {"$TEXT$", 0, 1, 0, 0, 8, ASEC_NULL, ".text"},
+  {"$PRIVATE$", 0, 1, 0, 0, 16, ASEC_NULL, ".data"},
+  {GDB_DEBUG_SPACE_NAME, 0, 0, 0, 0, 255, ASEC_NULL, ".stab"},
+  {NULL, 0, 0, 0, 0, 0, ASEC_NULL, NULL}
+};
+#else
+struct default_subspace_dict pa_def_subspaces[] =
+{
+  {"$CODE$", 0, 1, 0, 0, 0, 0, 24, 0x2c, 0, 8, 0, SEG_TEXT, SUBSEG_CODE},
+  {"$DATA$", 0, 1, 0, 0, 0, 0, 24, 0x1f, 0, 8, 1, SEG_DATA, SUBSEG_DATA},
+  {"$LIT$", 0, 1, 0, 0, 0, 0, 16, 0x2c, 0, 8, 0, SEG_TEXT, SUBSEG_LIT},
+  {"$BSS$", 0, 1, 0, 0, 0, 1, 80, 0x1f, 0, 8, 1, SEG_DATA, SUBSEG_BSS},
+  {"$UNWIND$", 0, 1, 0, 0, 0, 0, 64, 0x2c, 0, 4, 0, SEG_TEXT, SUBSEG_UNWIND},
+  {GDB_STRINGS, 0, 0, 0, 0, 0, 0, 254, 0x1f, 0, 4, 0, SEG_GDB, SUBSEG_GDB_STRINGS
+  },
+  {GDB_SYMBOLS, 0, 0, 0, 0, 0, 0, 255, 0x1f, 0, 4, 0, SEG_GDB, SUBSEG_GDB_SYMBOLS
+  },
+  {NULL, 0, 1, 0, 0, 0, 0, 255, 0x1f, 0, 4, 0, SEG_GOOF, 0}
+};
+
+struct default_space_dict pa_def_spaces[] =
+{
+  {"$TEXT$", 0, 1, 0, 0, 8, SEG_TEXT},
+  {"$PRIVATE$", 0, 1, 0, 0, 16, SEG_DATA},
+  {GDB_DEBUG_SPACE_NAME, 0, 0, 0, 0, 255, SEG_GDB},
+  {NULL, 0, 0, 0, 0, 0, SEG_GOOF}
+};
+#endif
+
+#ifdef USG
+#define bcmp(b1,b2,n) memcmp((b1),(b2),(n))
+#define index strchr
+#endif
+
+#ifndef FALSE
+#define FALSE   (0)
+#define TRUE    (!FALSE)
+#endif /* no FALSE yet */
+
+/*
+       Support for keeping track of the most recent label in each
+       space.
+ */
+
+/*
+       PA_PSEUDO_OP_MOVES_PC
+
+       A predicate that returns true if the pseudo-operation or
+       assembly directive results in a movement in the current
+       location.  All instructions cause movement in the current
+       location.
+ */
+
+static const char *movers[] =
+{
+/* these entries from 'static pseudo_typeS potable[]' in pa-read.c */
+  "ascii", "asciz",
+  "byte",
+  "comm",
+  "data", "desc", "double",
+  "fill", "float",
+  "globl",
+  "half",
+  "int",
+  "lcomm", "long", "lsym",
+  "octa", "org",
+  "quad",
+  "short", "single",
+  "text",
+  "word",
+/* these entries from 'pseudo_typeS md_pseudo_table[]' in pa-aux.c */
+  "block", "blockz",
+  "code", "copyright",
+  "equ",
+  "origin",
+  "reg",                       /* very similar to .equ */
+  "string", "stringz",
+  "version",
+  NULL                         /* end sentinel */
+};
+
+int
+pa_pseudo_op_moves_pc (name)
+     char *name;
+{
+  int i = 0;
+  while (movers[i])
+    {
+      if (strcmp (name, movers[i++]) == 0)
+       return 1;
+    }
+
+  return 0;
+}
+
+/*
+       Support for keeping track of the most recent label in each
+       space.
+ */
+
+/* XXX:  NOTE:  label_symbolS is defined in pa.h */
+
+label_symbolS *label_symbols_rootP = NULL;
+
+/*
+       PA_GET_LABEL
+
+       Returns a pointer to the label_symbolS for the current space.
+ */
+
+label_symbolS *
+pa_get_label ()
+{
+  label_symbolS *lssP;
+  space_dict_chainS *now_sdcP = pa_segment_to_space (now_seg);
+
+  for (lssP = label_symbols_rootP; lssP; lssP = lssP->lss_next)
+    {
+      if (now_sdcP == lssP->lss_space && lssP->lss_label)
+       return lssP;
+    }
+
+  return (label_symbolS *) NULL;
+}
+
+/*
+       PA_LABEL_IS_DEFINED
+
+       A predicate to determine whether a useable label is defined in
+       the current space.
+ */
+
+int
+pa_label_is_defined ()
+{
+  return (int) pa_get_label ();
+}
+
+/*
+       PA_DEFINE_LABEL
+
+       Defines a label for the current space.  If one is already defined,
+       this function will replace it with the new label.
+ */
+
+void
+pa_define_label (symbolP)
+     symbolS *symbolP;
+{
+  label_symbolS *lssP = pa_get_label ();
+  space_dict_chainS *now_sdcP = pa_segment_to_space (now_seg);
+
+  if (lssP)
+    {
+      lssP->lss_label = symbolP;
+    }
+  else
+    {
+      lssP = (label_symbolS *) xmalloc (sizeof (label_symbolS));
+      lssP->lss_label = symbolP;
+      lssP->lss_space = now_sdcP;
+      lssP->lss_next = (label_symbolS *) NULL;
+
+      if (label_symbols_rootP)
+       {
+         lssP->lss_next = label_symbols_rootP;
+       }
+      label_symbols_rootP = lssP;
+    }
+}
+
+/*
+       PA_UNDEFINE_LABEL
+
+       Removes a label definition for the current space.
+       If there is no label_symbolS entry, then no action is taken.
+ */
+
+void
+pa_undefine_label ()
+{
+  label_symbolS *lssP;
+  label_symbolS *prevP = (label_symbolS *) NULL;
+  space_dict_chainS *now_sdcP = pa_segment_to_space (now_seg);
+
+  for (lssP = label_symbols_rootP; lssP; lssP = lssP->lss_next)
+    {
+      if (now_sdcP == lssP->lss_space && lssP->lss_label)
+       {
+         if (prevP)
+           prevP->lss_next = lssP->lss_next;
+         else
+           label_symbols_rootP = lssP->lss_next;
+
+         free (lssP);
+         break;
+       }
+      prevP = lssP;
+    }
+}
+
+/* end of label symbol support. */
+
+
+/* An HPPA-specific version of fix_new.  This is required because the HPPA     */
+/* code needs to keep track of some extra stuff.  Each call to fix_new_hppa    */
+/* results in the creation of an instance of an hppa_fixS.  An hppa_fixS       */
+/* stores the extra information along with a pointer to the original fixS.     */
+
+typedef struct hppa_fix_struct
+  {
+    fixS *fx_fixP;
+    int fx_r_field;
+    int fx_r_type;
+    int fx_r_format;
+    long fx_arg_reloc;
+    call_infoS *fx_call_infop;
+    char fx_unwind[8];
+    struct hppa_fix_struct *fx_next;
+  } hppa_fixS;
+
+hppa_fixS *hppa_fix_root = NULL;
+
+void 
+fix_new_hppa (frag, where, size, add_symbol, sub_symbol, offset, pcrel,
+             r_type, r_field, r_format, arg_reloc, unwind_desc)
+     fragS *frag;              /* Which frag? */
+     int where;                        /* Where in that frag? */
+     short int size;           /* 1, 2  or 4 usually. */
+     symbolS *add_symbol;      /* X_add_symbol. */
+     symbolS *sub_symbol;      /* X_subtract_symbol. */
+     long offset;              /* X_add_number. */
+     int pcrel;                        /* TRUE if PC-relative relocation. */
+#ifdef BFD_ASSEMBLER
+     bfd_reloc_code_real_type r_type;  /* Relocation type */
+#else
+     int r_type;               /* Relocation type */
+#endif
+     long r_field;             /* F, R, L, etc */
+     int r_format;             /* 11,12,14,17,21,32, etc */
+     long arg_reloc;
+     char *unwind_desc;
+{
+  fixS *new_fix = fix_new (frag, where, size,
+                          add_symbol, sub_symbol,
+                          offset, pcrel, r_type);
+
+  hppa_fixS *hppa_fix = (hppa_fixS *) obstack_alloc (&notes, sizeof (hppa_fixS));
+
+  hppa_fix->fx_fixP = new_fix;
+  hppa_fix->fx_r_field = r_field;
+  hppa_fix->fx_r_format = r_format;
+  hppa_fix->fx_arg_reloc = arg_reloc;
+  hppa_fix->fx_next = (hppa_fixS *) 0;
+  hppa_fix->fx_call_infop = last_call_info;
+  if (unwind_desc)
+    bcopy (unwind_desc, hppa_fix->fx_unwind, 8);
+
+  if (hppa_fix_root)
+    hppa_fix->fx_next = hppa_fix_root;
+
+  hppa_fix_root = hppa_fix;
+
+  /* SKV 12/22/92.  Added prev_insn, prev_fix, and initialized the_insn
+   so that we can recognize instruction sequences such as (ldil, ble)
+   and generate the appropriate fixups. */
+
+#ifdef OBJ_ELF
+
+  curr_fix = new_fix;
+
+#endif /* OBJ_ELF */
+}
+
+/* Parse a .byte, .word, .long expression for the HPPA.  Called by
+   cons via the TC_PARSE_CONS_EXPRESSION macro.  */
+
+static int hppa_field_selector;
+
+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
+cons_fix_new_hppa (frag, where, size, exp)
+     fragS *frag;              /* Which frag? */
+     int where;                        /* Where in that frag? */
+     int size;                 /* 1, 2  or 4 usually. */
+     expressionS *exp;         /* Expression. */
+{
+  unsigned int reloc_type;
+
+  if (is_DP_relative (*exp))
+    reloc_type = R_HPPA_GOTOFF;
+  else if (is_complex (*exp))
+    reloc_type = R_HPPA_COMPLEX;
+  else
+    reloc_type = R_HPPA;
+
+  if (hppa_field_selector != e_psel && hppa_field_selector != e_fsel)
+    as_warn("Invalid field selector.  Assuming F%%.");
+
+  fix_new_hppa (frag, where, size
+               exp->X_add_symbol,
+               exp->X_subtract_symbol,
+               exp->X_add_number, 0, reloc_type,
+               hppa_field_selector, 32, 0, (char *) 0);
+}
+
+/* Given a FixS, find the hppa_fixS associated with it. */
+hppa_fixS *
+hppa_find_hppa_fix (fix)
+     fixS *fix;
+{
+  hppa_fixS *hfP;
+
+  for (hfP = hppa_fix_root; hfP; hfP = hfP->fx_next)
+    {
+      if (hfP->fx_fixP == fix)
+       return hfP;
+    }
+
+  return (hppa_fixS *) 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.  */
+void
+md_begin ()
+{
+  register char *retval = NULL;
+  int lose = 0;
+  register unsigned int i = 0;
+  void pa_spaces_begin ();     /* forward declaration */
+
+  last_call_info = NULL;
+  call_info_root = NULL;
+
+  pa_spaces_begin ();
+
+  op_hash = hash_new ();
+  if (op_hash == NULL)
+    as_fatal ("Virtual memory exhausted");
+
+  while (i < NUMOPCODES)
+    {
+      const char *name = pa_opcodes[i].name;
+      retval = hash_insert (op_hash, name, &pa_opcodes[i]);
+      if (retval != NULL && *retval != '\0')
+       {
+         as_fatal ("Internal error: can't hash `%s': %s\n",
+                   pa_opcodes[i].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.");
+
+  for (i = '0'; i < '8'; ++i)
+    octal[i] = 1;
+  for (i = '0'; i <= '9'; ++i)
+    toHex[i] = i - '0';
+  for (i = 'a'; i <= 'f'; ++i)
+    toHex[i] = i + 10 - 'a';
+  for (i = 'A'; i <= 'F'; ++i)
+    toHex[i] = i + 10 - 'A';
+
+}
+
+void
+md_end ()
+{
+  return;
+}
+
+void
+md_assemble (str)
+     char *str;
+{
+  char *toP;
+
+  assert (str);
+  pa_ip (str);
+  toP = frag_more (4);
+  /* put out the opcode */
+  md_number_to_chars (toP, the_insn.opcode, 4);
+
+  /* put out the symbol-dependent stuff */
+#if defined ( OBJ_SOM )
+  if (the_insn.reloc != R_NO_RELOCATION)
+    {
+#else
+#if defined ( OBJ_ELF )
+  if (the_insn.reloc != R_HPPA_NONE)
+    {
+#endif
+#endif
+
+#if defined(OBJ_ELF)
+      fix_new_hppa (frag_now,  /* which frag */
+                   (toP - frag_now->fr_literal),       /* where */
+                   4,          /* size */
+                   the_insn.exp.X_add_symbol,
+                   the_insn.exp.X_subtract_symbol,
+                   the_insn.exp.X_add_number,
+                   the_insn.pcrel,
+                   the_insn.reloc,
+                   the_insn.field_selector,
+                   the_insn.format,
+                   the_insn.arg_reloc,
+                   (char *) 0);
+#endif
+#ifdef OBJ_SOM
+      fix_new (frag_now,       /* which frag */
+              (toP - frag_now->fr_literal),    /* where */
+              4,               /* size */
+              the_insn.exp.X_add_symbol,
+              the_insn.exp.X_subtract_symbol,
+              the_insn.exp.X_add_number,
+              the_insn.pcrel,
+              the_insn.reloc,
+              the_insn.field_selector,
+              the_insn.code,
+              the_insn.arg_reloc,
+              (char *) 0);
+#endif
+    }
+
+  /* SKV 12/22/92.  Added prev_insn, prev_fix, and initialized the_insn
+   so that we can recognize instruction sequences such as (ldil, ble)
+   and generate the appropriate fixups. */
+
+#ifdef OBJ_ELF
+
+  prev_insn = the_insn;
+  strncpy (prev_str, str, 10);
+  if (prev_insn.reloc = R_HPPA_NONE)
+    {
+      prev_fix = NULL;
+    }
+  else
+    {
+      prev_fix = curr_fix;
+    }
+
+#endif /* OBJ_ELF */
+}
+
+static void
+pa_ip (str)
+     char *str;
+{
+  char *error_message = "";
+  char *s;
+  const char *args;
+  char c;
+  unsigned long i;
+  struct pa_opcode *insn;
+  char *argsStart;
+  unsigned long opcode;
+  unsigned int mask;
+  int match = FALSE;
+  int comma = 0;
+
+  int reg, reg1, reg2, s2, s3;
+  unsigned int im21, im14, im11, im5;
+  int m, a, uu, f;
+  int cmpltr, nullif, flag;
+  int sfu, cond;
+  char *name;
+  char *p, *save_s;
+
+#ifdef PA_DEBUG
+  fprintf (stderr, "STATEMENT: \"%s\"\n", str);
+#endif
+  for (s = str; isupper (*s) || islower (*s) || (*s >= '0' && *s <= '3'); ++s)
+    ;
+  switch (*s)
+    {
+
+    case '\0':
+      break;
+
+    case ',':
+      comma = 1;
+
+      /*FALLTHROUGH*/
+
+    case ' ':
+      *s++ = '\0';
+      break;
+
+    default:
+      as_bad ("Unknown opcode: `%s'", str);
+      exit (1);
+    }
+
+  save_s = str;
+
+  while (*save_s)
+    {
+      if (isupper (*save_s))
+       *save_s = tolower (*save_s);
+      save_s++;
+    }
+
+  if ((insn = (struct pa_opcode *) hash_find (op_hash, str)) == NULL)
+    {
+      as_bad ("Unknown opcode: `%s'", str);
+      return;
+    }
+  if (comma)
+    {
+      *--s = ',';
+    }
+  argsStart = s;
+  for (;;)
+    {
+      opcode = insn->match;
+      bzero (&the_insn, sizeof (the_insn));
+#if defined( OBJ_SOM )
+      the_insn.reloc = R_NO_RELOCATION;
+#else
+#if defined ( OBJ_ELF )
+      the_insn.reloc = R_HPPA_NONE;
+#endif
+#endif
+      /*
+        * Build the opcode, checking as we go to make
+        * sure that the operands match
+        */
+      for (args = insn->args;; ++args)
+       {
+
+         switch (*args)
+           {
+
+           case '\0':          /* end of args */
+             if (*s == '\0')
+               {
+                 match = TRUE;
+               }
+             break;
+
+           case '+':
+             if (*s == '+')
+               {
+                 ++s;
+                 continue;
+               }
+             if (*s == '-')
+               {
+                 continue;
+               }
+             break;
+
+           case '(':           /* these must match exactly */
+           case ')':
+           case ',':
+           case ' ':
+             if (*s++ == *args)
+               continue;
+             break;
+
+           case 'b':           /* 5 bit register field at 10 */
+           case '^':           /* 5 bit control register field at 10 */
+             reg = pa_parse_number (&s);
+             if (reg < 32 && reg >= 0)
+               {
+                 opcode |= reg << 21;
+                 continue;
+               }
+             break;
+           case 'x':           /* 5 bit register field at 15 */
+             reg = pa_parse_number (&s);
+             if (reg < 32 && reg >= 0)
+               {
+                 opcode |= reg << 16;
+                 continue;
+               }
+             break;
+           case 't':           /* 5 bit register field at 31 */
+             reg = pa_parse_number (&s);
+             if (reg < 32 && reg >= 0)
+               {
+                 opcode |= reg;
+                 continue;
+               }
+             break;
+           case 'T':           /* 5 bit field length at 31 (encoded as 32-T) */
+             /*
+               reg = pa_parse_number(&s);
+              */
+             getAbsoluteExpression (s);
+             if (the_insn.exp.X_seg == &bfd_abs_section)
+               {
+                 reg = the_insn.exp.X_add_number;
+                 if (reg <= 32 && reg > 0)
+                   {
+                     opcode |= 32 - reg;
+                     s = expr_end;
+                     continue;
+                   }
+               }
+             break;
+           case '5':           /* 5 bit immediate at 15 */
+             getAbsoluteExpression (s);
+             /** PJH: The following 2 calls to as_bad() might eventually **/
+             /**      want to end up as as_warn().  **/
+             if (the_insn.exp.X_add_number > 15)
+               {
+                 as_bad ("5 bit immediate > 15. Set to 15",
+                         the_insn.exp.X_add_number);
+                 the_insn.exp.X_add_number = 15;
+               }
+             else if (the_insn.exp.X_add_number < -16)
+               {
+                 as_bad ("5 bit immediate < -16. Set to -16",
+                         the_insn.exp.X_add_number);
+                 the_insn.exp.X_add_number = -16;
+               }
+
+             low_sign_unext (evaluateAbsolute (the_insn.exp, the_insn.field_selector),
+                             5, &im5);
+             opcode |= (im5 << 16);
+             s = expr_end;
+             continue;
+
+           case 's':           /* 2 bit space identifier at 17 */
+             s2 = pa_parse_number (&s);
+             if (s2 < 4 && s2 >= 0)
+               {
+                 opcode |= s2 << 14;
+                 continue;
+               }
+             break;
+           case 'S':           /* 3 bit space identifier at 18 */
+             s3 = pa_parse_number (&s);
+             if (s3 < 8 && s3 >= 0)
+               {
+                 dis_assemble_3 (s3, &s3);
+                 opcode |= s3 << 13;
+                 continue;
+               }
+             break;
+           case 'c':           /* indexed load completer. */
+             uu = 0;
+             m = 0;
+             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", 1) == 0)
+                   uu = 1;
+                 else
+                   as_bad ("Unrecognized Indexed Load Completer...assuming 0");
+                 s++;
+                 i++;
+               }
+             if (i > 2)
+               as_bad ("Illegal Indexed Load Completer Syntax...extras ignored");
+             /* pa_skip(&s); */
+             while (*s == ' ' || *s == '\t')
+               s++;
+
+             opcode |= m << 5;
+             opcode |= uu << 13;
+             continue;
+           case 'C':           /* short load and store completer */
+             a = 0;
+             m = 0;
+             if (*s == ',')
+               {
+                 s++;
+                 if (strncasecmp (s, "ma", 2) == 0)
+                   {
+                     a = 0;
+                     m = 1;
+                   }
+                 else if (strncasecmp (s, "mb", 2) == 0)
+                   {
+                     a = 1;
+                     m = 1;
+                   }
+                 else
+                   as_bad ("Unrecognized Indexed Load Completer...assuming 0");
+                 s += 2;
+               }
+             /* pa_skip(&s); */
+             while (*s == ' ' || *s == '\t')
+               s++;
+             opcode |= m << 5;
+             opcode |= a << 13;
+             continue;
+           case 'Y':           /* Store Bytes Short completer */
+             a = 0;
+             m = 0;
+             i = 0;
+             while (*s == ',' && i < 2)
+               {
+                 s++;
+                 if (strncasecmp (s, "m", 1) == 0)
+                   m = 1;
+                 else if (strncasecmp (s, "b", 1) == 0)
+                   a = 0;
+                 else if (strncasecmp (s, "e", 1) == 0)
+                   a = 1;
+                 else
+                   as_bad ("Unrecognized Store Bytes Short Completer...assuming 0");
+                 s++;
+                 i++;
+               }
+             /**               if ( i >= 2 ) **/
+             if (i > 2)
+               as_bad ("Illegal Store Bytes Short Completer...extras ignored");
+             while (*s == ' ' || *s == '\t')   /* skip to next operand */
+               s++;
+             opcode |= m << 5;
+             opcode |= a << 13;
+             continue;
+           case '<':           /* non-negated compare/subtract conditions. */
+             cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s);
+             if (cmpltr < 0)
+               {
+                 as_bad ("Unrecognized Compare/Subtract Condition: %c", *s);
+                 cmpltr = 0;
+               }
+             opcode |= cmpltr << 13;
+             continue;
+           case '?':           /* negated or non-negated cmp/sub conditions. */
+             /* used only by ``comb'' and ``comib'' pseudo-ops */
+             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 ("Unrecognized Compare/Subtract Condition: %c", *s);
+                     cmpltr = 0;
+                   }
+                 else
+                   {
+                     opcode |= 1 << 27;        /* required opcode change to make
+                                       COMIBT into a COMIBF or a
+                                       COMBT into a COMBF or a
+                                       ADDBT into a ADDBF or a
+                                       ADDIBT into a ADDIBF */
+                   }
+               }
+             opcode |= cmpltr << 13;
+             continue;
+           case '!':           /* negated or non-negated add conditions. */
+             /* used only by ``addb'' and ``addib'' pseudo-ops */
+             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 ("Unrecognized Compare/Subtract Condition: %c", *s);
+                     cmpltr = 0;
+                   }
+                 else
+                   {
+                     opcode |= 1 << 27;        /* required opcode change to make
+                   COMIBT into a COMIBF or a
+                     COMBT into a COMBF or a
+                       ADDBT into a ADDBF or a
+                         ADDIBT into a ADDIBF */
+                   }
+               }
+             opcode |= cmpltr << 13;
+             continue;
+           case 'a':           /* compare/subtract conditions */
+             cmpltr = 0;
+             f = 0;
+             save_s = s;
+             if (*s == ',')
+               {
+                 cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s);
+                 if (cmpltr < 0)
+                   {
+                     f = 1;
+                     s = save_s;
+                     cmpltr = pa_parse_neg_cmpsub_cmpltr (&s);
+                     if (cmpltr < 0)
+                       {
+                         as_bad ("Unrecognized Compare/Subtract Condition");
+                       }
+                   }
+               }
+             opcode |= cmpltr << 13;
+             opcode |= f << 12;
+             continue;
+           case 'd':           /* non-negated add conditions */
+             cmpltr = 0;
+             nullif = 0;
+             flag = 0;
+             if (*s == ',')
+               {
+                 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 (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, "n") == 0)
+                   {
+                     nullif = 1;
+                   }
+                 else if (strcasecmp (name, "tr") == 0)
+                   {
+                     cmpltr = 0;
+                     flag = 1;
+                   }
+                 else if (strcasecmp (name, "<>") == 0)
+                   {
+                     cmpltr = 1;
+                     flag = 1;
+                   }
+                 else if (strcasecmp (name, ">=") == 0)
+                   {
+                     cmpltr = 2;
+                     flag = 1;
+                   }
+                 else if (strcasecmp (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;
+                   }
+                 else
+                   as_bad ("Unrecognized Add Condition: %s", name);
+                 *s = c;
+               }
+             nullif = pa_parse_nullif (&s);
+             opcode |= nullif << 1;
+             opcode |= cmpltr << 13;
+             opcode |= flag << 12;
+             continue;
+           case '&':           /* logical instruction conditions */
+             cmpltr = 0;
+             f = 0;
+             if (*s == ',')
+               {
+                 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 (strcmp (name, "<=") == 0)
+                   {
+                     cmpltr = 3;
+                   }
+                 else if (strcasecmp (name, "od") == 0)
+                   {
+                     cmpltr = 7;
+                   }
+                 else if (strcasecmp (name, "tr") == 0)
+                   {
+                     cmpltr = 0;
+                     f = 1;
+                   }
+                 else if (strcmp (name, "<>") == 0)
+                   {
+                     cmpltr = 1;
+                     f = 1;
+                   }
+                 else if (strcmp (name, ">=") == 0)
+                   {
+                     cmpltr = 2;
+                     f = 1;
+                   }
+                 else if (strcmp (name, ">") == 0)
+                   {
+                     cmpltr = 3;
+                     f = 1;
+                   }
+                 else if (strcasecmp (name, "ev") == 0)
+                   {
+                     cmpltr = 7;
+                     f = 1;
+                   }
+                 else
+                   as_bad ("Unrecognized Logical Instruction Condition: %s", name);
+                 *s = c;
+               }
+             opcode |= cmpltr << 13;
+             opcode |= f << 12;
+             continue;
+           case 'U':           /* unit instruction conditions */
+             cmpltr = 0;
+             f = 0;
+             if (*s == ',')
+               {
+                 s++;
+                 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;
+                     f = 1;
+                     s += 2;
+                   }
+                 else if (strncasecmp (s, "nbz", 3) == 0)
+                   {
+                     cmpltr = 2;
+                     f = 1;
+                     s += 3;
+                   }
+                 else if (strncasecmp (s, "nhz", 3) == 0)
+                   {
+                     cmpltr = 3;
+                     f = 1;
+                     s += 3;
+                   }
+                 else if (strncasecmp (s, "ndc", 3) == 0)
+                   {
+                     cmpltr = 4;
+                     f = 1;
+                     s += 3;
+                   }
+                 else if (strncasecmp (s, "nbc", 3) == 0)
+                   {
+                     cmpltr = 6;
+                     f = 1;
+                     s += 3;
+                   }
+                 else if (strncasecmp (s, "nhc", 3) == 0)
+                   {
+                     cmpltr = 7;
+                     f = 1;
+                     s += 3;
+                   }
+                 else
+                   as_bad ("Unrecognized Logical Instruction Condition: %c", *s);
+               }
+             opcode |= cmpltr << 13;
+             opcode |= f << 12;
+             continue;
+           case '>':           /* shift/extract/deposit conditions. */
+             cmpltr = 0;
+             if (*s == ',')
+               {
+                 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;
+                   }
+                 else
+                   as_bad ("Unrecognized Shift/Extract/Deposit Condition: %s", name);
+                 *s = c;
+               }
+             opcode |= cmpltr << 13;
+             continue;
+           case '~':           /* bvb,bb conditions */
+             cmpltr = 0;
+             if (*s == ',')
+               {
+                 s++;
+                 if (strncmp (s, "<", 1) == 0)
+                   {
+                     cmpltr = 2;
+                     s++;
+                   }
+                 else if (strncmp (s, ">=", 2) == 0)
+                   {
+                     cmpltr = 6;
+                     s += 2;
+                   }
+                 else
+                   as_bad ("Unrecognized Bit Branch Condition: %c", *s);
+               }
+             opcode |= cmpltr << 13;
+             continue;
+           case 'V':           /* 5  bit immediate at 31 */
+             getExpression (s);
+             low_sign_unext (evaluateAbsolute (the_insn.exp, the_insn.field_selector),
+                             5, &im5);
+             opcode |= im5;
+             s = expr_end;
+             continue;
+           case 'r':           /* 5  bit immediate at 31 */
+             /* (unsigned value for the break instruction) */
+             getExpression (s);
+             im5 = evaluateAbsolute (the_insn.exp, the_insn.field_selector);
+             if (im5 > 31 || im5 < 0)
+               {
+                 as_bad ("Operand out of range. Was: %d. Should be [0..31]. Assuming %d.\n", im5, im5 & 0x1f);
+                 im5 = im5 & 0x1f;
+               }
+             opcode |= im5;
+             s = expr_end;
+             continue;
+           case 'R':           /* 5  bit immediate at 15 */
+             /* (unsigned value for the ssm and rsm instruction) */
+             getExpression (s);
+             im5 = evaluateAbsolute (the_insn.exp, the_insn.field_selector);
+             if (im5 > 31 || im5 < 0)
+               {
+                 as_bad ("Operand out of range. Was: %d. Should be [0..31]. Assuming %d.\n", im5, im5 & 0x1f);
+                 im5 = im5 & 0x1f;
+               }
+             opcode |= im5 << 16;
+             s = expr_end;
+             continue;
+           case 'i':           /* 11 bit immediate at 31 */
+#ifdef OBJ_SOM
+             getExpression (s);
+             if (the_insn.exp.X_seg == &bfd_abs_section)
+               {
+                 low_sign_unext (evaluateAbsolute (the_insn.exp, the_insn.field_selector),
+                                 11, &im11);
+                 opcode |= im11;
+               }
+             else
+               {
+                 the_insn.reloc = R_CODE_ONE_SYMBOL;
+                 the_insn.code = 'i';
+                 the_insn.field_selector = the_insn.exp.field_selector;
+               }
+             s = expr_end;
+             continue;
+#else
+             the_insn.field_selector = pa_chk_field_selector (&s);
+             getExpression (s);
+             if (the_insn.exp.X_seg == &bfd_abs_section)
+               {
+                 low_sign_unext (evaluateAbsolute (the_insn.exp, the_insn.field_selector),
+                                 11, &im11);
+                 opcode |= im11;
+               }
+             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 if (is_complex (the_insn.exp))
+                   the_insn.reloc = R_HPPA_COMPLEX;
+                 else
+                   the_insn.reloc = R_HPPA;
+                 the_insn.format = 11;
+               }
+             s = expr_end;
+             continue;
+#endif
+           case 'j':           /* 14 bit immediate at 31 */
+#ifdef OBJ_SOM
+             getExpression (s);
+             if (the_insn.exp.X_seg == &bfd_abs_section)
+               {
+                 low_sign_unext (evaluateAbsolute (the_insn.exp, field_selector),
+                                 14, &im14);
+                 if (the_insn.exp.field_selector == e_rsel)
+                   opcode |= (im14 & 0xfff);
+                 else
+                   opcode |= im14;
+               }
+             else
+               {
+                 the_insn.reloc = R_CODE_ONE_SYMBOL;
+                 the_insn.code = 'j';
+                 the_insn.field_selector = the_insn.exp.field_selector;
+               }
+             s = expr_end;
+             continue;
+#else
+             the_insn.field_selector = pa_chk_field_selector (&s);
+             getExpression (s);
+             if (the_insn.exp.X_seg == &bfd_abs_section)
+               {
+                 low_sign_unext (evaluateAbsolute (the_insn.exp, the_insn.field_selector),
+                                 14, &im14);
+                 if (the_insn.field_selector == e_rsel)
+                   opcode |= (im14 & 0xfff);
+                 else
+                   opcode |= im14;
+               }
+             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 if (is_complex (the_insn.exp))
+                   the_insn.reloc = R_HPPA_COMPLEX;
+                 else
+                   the_insn.reloc = R_HPPA;
+                 the_insn.format = 14;
+               }
+             s = expr_end;
+             continue;
+#endif
+
+           case 'k':           /* 21 bit immediate at 31 */
+#ifdef OBJ_SOM
+             getExpression (s);
+             if (the_insn.exp.X_seg == &bfd_abs_section)
+               {
+                 dis_assemble_21 (evaluateAbsolute (the_insn.exp, the_insn.field_selector),
+                                  &im21);
+                 opcode |= im21;
+               }
+             else
+               {
+                 the_insn.reloc = R_CODE_ONE_SYMBOL;
+                 the_insn.code = 'k';
+                 the_insn.field_selector = the_insn.exp.field_selector;
+               }
+             s = expr_end;
+             continue;
+#else
+             the_insn.field_selector = pa_chk_field_selector (&s);
+             getExpression (s);
+             if (the_insn.exp.X_seg == &bfd_abs_section)
+               {
+                 dis_assemble_21 (evaluateAbsolute (the_insn.exp, the_insn.field_selector),
+                                  &im21);
+                 opcode |= im21;
+               }
+             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 if (is_complex (the_insn.exp))
+                   the_insn.reloc = R_HPPA_COMPLEX;
+                 else
+                   the_insn.reloc = R_HPPA;
+                 the_insn.format = 21;
+               }
+             s = expr_end;
+             continue;
+#endif
+
+           case 'n':           /* nullification for branch instructions */
+             nullif = pa_parse_nullif (&s);
+             opcode |= nullif << 1;
+             continue;
+           case 'w':           /* 12 bit branch displacement */
+#ifdef OBJ_SOM
+             getExpression (s);
+             the_insn.pcrel = 1;
+             if (strcmp (the_insn.exp.X_add_symbol->sy_nlist.n_un.n_name, "L0\001") == 0)
+               {
+                 unsigned int w1, w, result;
+
+                 sign_unext ((the_insn.exp.X_add_number - 8) >> 2, 12, &result);
+                 dis_assemble_12 (result, &w1, &w);
+                 opcode |= ((w1 << 2) | w);
+                 the_insn.exp.X_add_symbol->sy_ref = FALSE;
+               }
+             else
+               {
+                 /* this has to be wrong -- dont know what is right! */
+                 the_insn.reloc = R_PCREL_CALL;
+                 the_insn.code = 'w';
+                 the_insn.field_selector = the_insn.exp.field_selector;
+                 the_insn.arg_reloc = last_call_desc.arg_reloc;
+                 bzero (&last_call_desc, sizeof (call_descS));
+               }
+             s = expr_end;
+             continue;
+#else
+             the_insn.field_selector = pa_chk_field_selector (&s);
+             getExpression (s);
+             the_insn.pcrel = 1;
+             if (strcmp (S_GET_NAME (the_insn.exp.X_add_symbol), "L0\001") == 0)
+               {
+                 unsigned int w1, w, result;
+
+                 sign_unext ((the_insn.exp.X_add_number - 8) >> 2, 12, &result);
+                 dis_assemble_12 (result, &w1, &w);
+                 opcode |= ((w1 << 2) | w);
+                 /* the_insn.exp.X_add_symbol->sy_ref = FALSE; *//* XXX: not sure how to do this in BFD */
+               }
+             else
+               {
+                 if (is_complex (the_insn.exp))
+                   the_insn.reloc = R_HPPA_COMPLEX_PCREL_CALL;
+                 else
+                   the_insn.reloc = R_HPPA_PCREL_CALL;
+                 the_insn.format = 12;
+                 the_insn.arg_reloc = last_call_desc.arg_reloc;
+                 bzero (&last_call_desc, sizeof (call_descS));
+               }
+             s = expr_end;
+             continue;
+#endif
+           case 'W':           /* 17 bit branch displacement */
+#if defined(OBJ_ELF)
+             the_insn.field_selector = pa_chk_field_selector (&s);
+#endif
+             getExpression (s);
+             the_insn.pcrel = 1;
+#ifdef OBJ_SOM
+             if (strcmp (the_insn.exp.X_add_symbol->sy_nlist.n_un.n_name, "L0\001") == 0)
+               {
+                 unsigned int w2, w1, w, result;
+
+                 sign_unext ((the_insn.exp.X_add_number - 8) >> 2, 17, &result);
+                 dis_assemble_17 (result, &w1, &w2, &w);
+                 opcode |= ((w2 << 2) | (w1 << 16) | w);
+                 the_insn.exp.X_add_symbol->sy_ref = FALSE;
+               }
+             else
+               {
+                 /* this has to be wrong -- dont know what is right! */
+                 the_insn.reloc = R_PCREL_CALL;
+                 the_insn.code = 'W';
+                 the_insn.field_selector = the_insn.exp.field_selector;
+                 the_insn.arg_reloc = last_call_desc.arg_reloc;
+                 bzero (&last_call_desc, sizeof (call_descS));
+               }
+#else
+             if (the_insn.exp.X_add_symbol)
+               {
+                 if (strcmp (S_GET_NAME (the_insn.exp.X_add_symbol), "L0\001") == 0)
+                   {
+                     unsigned int w2, w1, w, result;
+
+                     sign_unext ((the_insn.exp.X_add_number - 8) >> 2, 17, &result);
+                     dis_assemble_17 (result, &w1, &w2, &w);
+                     opcode |= ((w2 << 2) | (w1 << 16) | w);
+                   }
+                 else
+                   {
+                     if (is_complex (the_insn.exp))
+                       the_insn.reloc = R_HPPA_COMPLEX_PCREL_CALL;
+                     else
+                       the_insn.reloc = R_HPPA_PCREL_CALL;
+                     the_insn.format = 17;
+                     the_insn.arg_reloc = last_call_desc.arg_reloc;
+                     bzero (&last_call_desc, sizeof (call_descS));
+                   }
+               }
+             else
+               {
+                 unsigned int w2, w1, w, result;
+
+                 sign_unext (the_insn.exp.X_add_number >> 2, 17, &result);
+                 dis_assemble_17 (result, &w1, &w2, &w);
+                 opcode |= ((w2 << 2) | (w1 << 16) | w);
+               }
+#endif
+             s = expr_end;
+             continue;
+           case 'z':           /* 17 bit branch displacement (not pc-relative) */
+#if defined(OBJ_ELF)
+             the_insn.field_selector = pa_chk_field_selector (&s);
+#endif
+             getExpression (s);
+             the_insn.pcrel = 0;
+#ifdef OBJ_SOM
+             if (strcmp (the_insn.exp.X_add_symbol->sy_nlist.n_un.n_name, "L0\001") == 0)
+               {
+                 unsigned int w2, w1, w, result;
+
+                 sign_unext ((the_insn.exp.X_add_number - 8) >> 2, 17, &result);
+                 dis_assemble_17 (result, &w1, &w2, &w);
+                 opcode |= ((w2 << 2) | (w1 << 16) | w);
+                 the_insn.exp.X_add_symbol->sy_ref = FALSE;
+               }
+             else
+               {
+                 /* this has to be wrong -- dont know what is right! */
+                 the_insn.reloc = R_PCREL_CALL;
+                 the_insn.code = 'W';
+                 the_insn.field_selector = the_insn.exp.field_selector;
+                 the_insn.arg_reloc = last_call_desc.arg_reloc;
+                 bzero (&last_call_desc, sizeof (call_descS));
+               }
+#else
+             if (the_insn.exp.X_add_symbol)
+               {
+                 if (strcmp (S_GET_NAME (the_insn.exp.X_add_symbol), "L0\001") == 0)
+                   {
+                     unsigned int w2, w1, w, result;
+
+                     sign_unext ((the_insn.exp.X_add_number - 8) >> 2, 17, &result);
+                     dis_assemble_17 (result, &w1, &w2, &w);
+                     opcode |= ((w2 << 2) | (w1 << 16) | w);
+                   }
+                 else
+                   {
+                     if (is_complex (the_insn.exp))
+                       {
+                         the_insn.reloc = R_HPPA_COMPLEX_ABS_CALL;
+                       }
+                     else
+                       {
+                         the_insn.reloc = R_HPPA_ABS_CALL;
+                       }
+                     /* This could also be part of an instruction sequence of
+                                interest.  If so, check to make sure that the previous
+                                instruction's fixup is appropriate.  (ble, be instructions
+                                 affect the reloc of immediately preceding ldil
+                                 instructions.) */
+                     if (strcasecmp (prev_str, "ldil") == 0 &&
+                         prev_insn.exp.X_add_symbol == the_insn.exp.X_add_symbol &&
+                         prev_insn.exp.X_subtract_symbol == the_insn.exp.X_subtract_symbol &&
+                         prev_insn.exp.X_seg == the_insn.exp.X_seg &&
+                         prev_insn.exp.X_add_number == the_insn.exp.X_add_number &&
+                         prev_fix != NULL)
+                       prev_fix->fx_r_type = the_insn.reloc;
+
+                     the_insn.format = 17;
+                     the_insn.arg_reloc = last_call_desc.arg_reloc;
+                     bzero (&last_call_desc, sizeof (call_descS));
+                   }
+               }
+             else
+               {
+                 unsigned int w2, w1, w, result;
+
+                 sign_unext (the_insn.exp.X_add_number >> 2, 17, &result);
+                 dis_assemble_17 (result, &w1, &w2, &w);
+                 opcode |= ((w2 << 2) | (w1 << 16) | w);
+               }
+#endif
+             s = expr_end;
+             continue;
+           case 'p':           /* 5 bit shift count at 26 (to support SHD instr.) */
+             /* value is encoded in instr. as 31-p where p is   */
+             /* the value scanned here */
+             getExpression (s);
+             if (the_insn.exp.X_seg == &bfd_abs_section)
+               {
+                 opcode |= (((31 - the_insn.exp.X_add_number) & 0x1f) << 5);
+               }
+             s = expr_end;
+             continue;
+           case 'P':           /* 5-bit bit position at 26 */
+             getExpression (s);
+             if (the_insn.exp.X_seg == &bfd_abs_section)
+               {
+                 opcode |= (the_insn.exp.X_add_number & 0x1f) << 5;
+               }
+             s = expr_end;
+             continue;
+           case 'Q':           /* 5  bit immediate at 10 */
+             /* (unsigned bit position value for the bb instruction) */
+             getExpression (s);
+             im5 = evaluateAbsolute (the_insn.exp, the_insn.field_selector);
+             if (im5 > 31 || im5 < 0)
+               {
+                 as_bad ("Operand out of range. Was: %d. Should be [0..31]. Assuming %d.\n", im5, im5 & 0x1f);
+                 im5 = im5 & 0x1f;
+               }
+             opcode |= im5 << 21;
+             s = expr_end;
+             continue;
+           case 'A':           /* 13 bit immediate at 18 (to support BREAK instr.) */
+             getAbsoluteExpression (s);
+             if (the_insn.exp.X_seg == &bfd_abs_section)
+               opcode |= (the_insn.exp.X_add_number & 0x1fff) << 13;
+             s = expr_end;
+             continue;
+           case 'Z':           /* System Control Completer(for LDA, LHA, etc.) */
+             if (*s == ',' && (*(s + 1) == 'm' || *(s + 1) == 'M'))
+               {
+                 m = 1;
+                 s += 2;
+               }
+             else
+               m = 0;
+
+             opcode |= m << 5;
+             while (*s == ' ' || *s == '\t')   /* skip to next operand */
+               s++;
+
+             continue;
+           case 'D':           /* 26 bit immediate at 31 (to support DIAG instr.) */
+             /* the action (and interpretation of this operand is
+                            implementation dependent) */
+#if defined(OBJ_ELF)
+             the_insn.field_selector = pa_chk_field_selector (&s);
+#endif
+             getExpression (s);
+             if (the_insn.exp.X_seg == &bfd_abs_section)
+               {
+                 opcode |= ((evaluateAbsolute (the_insn.exp, the_insn.field_selector) & 0x1ffffff) << 1);
+#ifdef NEW_SOM                 /* XXX what replaces this? */
+                 /* PJH: VERY unsure about the following */
+                 the_insn.field_selector = the_insn.exp.field_selector;
+#endif
+               }
+             else
+               as_bad ("Illegal DIAG operand");
+             s = expr_end;
+             continue;
+           case 'f':           /* 3 bit Special Function Unit (SFU) identifier at 25 */
+             sfu = pa_parse_number (&s);
+             if ((sfu > 7) || (sfu < 0))
+               as_bad ("Illegal SFU identifier: %02x", sfu);
+             opcode |= (sfu & 7) << 6;
+             continue;
+           case 'O':           /* 20 bit SFU op. split between 15 bits at 20
+                          and 5 bits at 31 */
+             getExpression (s);
+             s = expr_end;
+             continue;
+           case 'o':           /* 15 bit Special Function Unit operation at 20 */
+             getExpression (s);
+             s = expr_end;
+             continue;
+           case '2':           /* 22 bit SFU op. split between 17 bits at 20
+                          and 5 bits at 31 */
+             getExpression (s);
+             s = expr_end;
+             continue;
+           case '1':           /* 15 bit SFU op. split between 10 bits at 20
+                          and 5 bits at 31 */
+             getExpression (s);
+             s = expr_end;
+             continue;
+           case '0':           /* 10 bit SFU op. split between 5 bits at 20
+                          and 5 bits at 31 */
+             getExpression (s);
+             s = expr_end;
+             continue;
+           case 'u':           /* 3 bit coprocessor unit identifier at 25 */
+             getExpression (s);
+             s = expr_end;
+             continue;
+           case 'F':           /* Source FP Operand Format Completer (2 bits at 20) */
+             f = pa_parse_fp_format (&s);
+             opcode |= (int) f << 11;
+             the_insn.fpof1 = f;
+             continue;
+           case 'G':           /* Destination FP Operand Format Completer (2 bits at 18) */
+             s--;              /* need to pass the previous comma to pa_parse_fp_format */
+             f = pa_parse_fp_format (&s);
+             opcode |= (int) f << 13;
+             the_insn.fpof2 = f;
+             continue;
+           case 'M':           /* FP Compare Conditions (encoded as 5 bits at 31) */
+             cond = pa_parse_fp_cmp_cond (&s);
+             opcode |= cond;
+             continue;
+
+           case 'v':           /* a 't' type extended to handle L/R register halves. */
+             {
+               struct pa_89_fp_reg_struct result;
+               int status;
+
+               pa_89_parse_number (&s, &result);
+               if (result.number_part < 32 && result.number_part >= 0)
+                 {
+                   opcode |= (result.number_part & 0x1f);
+
+                   /* 0x30 opcodes are FP arithmetic operation opcodes */
+                   /* load/store FP opcodes do not get converted to 0x38 */
+                   /* opcodes like the 0x30 opcodes do */
+                   if (need_89_opcode (&the_insn, &result))
+                     {
+                       if ((opcode & 0xfc000000) == 0x30000000)
+                         {
+                           opcode |= (result.L_R_select & 1) << 6;
+                           opcode |= 1 << 27;
+                         }
+                       else
+                         {
+                           opcode |= (result.L_R_select & 1) << 6;
+                         }
+                     }
+                   continue;
+                 }
+             }
+             break;
+           case 'E':           /* a 'b' type extended to handle L/R register halves. */
+             {
+               struct pa_89_fp_reg_struct result;
+               int status;
+
+               pa_89_parse_number (&s, &result);
+               if (result.number_part < 32 && result.number_part >= 0)
+                 {
+                   opcode |= (result.number_part & 0x1f) << 21;
+                   if (need_89_opcode (&the_insn, &result))
+                     {
+                       opcode |= (result.L_R_select & 1) << 7;
+                       opcode |= 1 << 27;
+                     }
+                   continue;
+                 }
+             }
+             break;
+
+           case 'X':           /* an 'x' type extended to handle L/R register halves. */
+             {
+               struct pa_89_fp_reg_struct result;
+               int status;
+
+
+               pa_89_parse_number (&s, &result);
+               if (result.number_part < 32 && result.number_part >= 0)
+                 {
+                   opcode |= (result.number_part & 0x1f) << 16;
+                   if (need_89_opcode (&the_insn, &result))
+                     {
+                       opcode |= (result.L_R_select & 1) << 12;
+                       opcode |= 1 << 27;
+                     }
+                   continue;
+                 }
+             }
+             break;
+
+           case '4':           /* 5 bit register field at 10
+                                (used in 'fmpyadd' and 'fmpysub') */
+             {
+               struct pa_89_fp_reg_struct result;
+               int status;
+
+               status = pa_89_parse_number (&s, &result);
+               if (result.number_part < 32 && result.number_part >= 0)
+                 {
+                   if (the_insn.fpof1 == SGL)
+                     {
+                       result.number_part &= 0xF;
+                       result.number_part |= (result.L_R_select & 1) << 4;
+                     }
+                   opcode |= result.number_part << 21;
+                   continue;
+                 }
+             }
+             break;
+
+           case '6':           /* 5 bit register field at 15
+                                (used in 'fmpyadd' and 'fmpysub') */
+             {
+               struct pa_89_fp_reg_struct result;
+               int status;
+
+               status = pa_89_parse_number (&s, &result);
+               if (result.number_part < 32 && result.number_part >= 0)
+                 {
+                   if (the_insn.fpof1 == SGL)
+                     {
+                       result.number_part &= 0xF;
+                       result.number_part |= (result.L_R_select & 1) << 4;
+                     }
+                   opcode |= result.number_part << 16;
+                   continue;
+                 }
+             }
+             break;
+
+           case '7':           /* 5 bit register field at 31
+                                (used in 'fmpyadd' and 'fmpysub') */
+             {
+               struct pa_89_fp_reg_struct result;
+               int status;
+
+               status = pa_89_parse_number (&s, &result);
+               if (result.number_part < 32 && result.number_part >= 0)
+                 {
+                   if (the_insn.fpof1 == SGL)
+                     {
+                       result.number_part &= 0xF;
+                       result.number_part |= (result.L_R_select & 1) << 4;
+                     }
+                   opcode |= result.number_part;
+                   continue;
+                 }
+             }
+             break;
+
+           case '8':           /* 5 bit register field at 20
+                                (used in 'fmpyadd' and 'fmpysub') */
+             {
+               struct pa_89_fp_reg_struct result;
+               int status;
+
+               status = pa_89_parse_number (&s, &result);
+               if (result.number_part < 32 && result.number_part >= 0)
+                 {
+                   if (the_insn.fpof1 == SGL)
+                     {
+                       result.number_part &= 0xF;
+                       result.number_part |= (result.L_R_select & 1) << 4;
+                     }
+                   opcode |= result.number_part << 11;
+                   continue;
+                 }
+             }
+             break;
+
+           case '9':           /* 5 bit register field at 25
+                                (used in 'fmpyadd' and 'fmpysub') */
+             {
+               struct pa_89_fp_reg_struct result;
+               int status;
+
+               status = pa_89_parse_number (&s, &result);
+               if (result.number_part < 32 && result.number_part >= 0)
+                 {
+                   if (the_insn.fpof1 == SGL)
+                     {
+                       result.number_part &= 0xF;
+                       result.number_part |= (result.L_R_select & 1) << 4;
+                     }
+                   opcode |= result.number_part << 6;
+                   continue;
+                 }
+             }
+             break;
+
+           case 'H':           /* Floating Point Operand Format at 26 for       */
+             /* 'fmpyadd' and 'fmpysub' (very similar to 'F') */
+             /* bits are switched from other FP Operand       */
+             /* formats. 1=SGL, 1=<none>, 0=DBL               */
+             f = pa_parse_fp_format (&s);
+             switch (f)
+               {
+               case SGL:
+                 opcode |= 0x20;
+               case DBL:
+                 the_insn.fpof1 = f;
+                 continue;
+
+               case QUAD:
+               case ILLEGAL_FMT:
+               default:
+                 as_bad ("Illegal Floating Point Operand Format for this instruction: '%s'", *s);
+               }
+             break;
+
+           default:
+             abort ();
+           }
+         break;
+       }
+    error:
+      if (match == FALSE)
+       {
+         /* Args don't match.  */
+         if (&insn[1] - pa_opcodes < NUMOPCODES
+             && !strcmp (insn->name, insn[1].name))
+           {
+             ++insn;
+             s = argsStart;
+             continue;
+           }
+         else
+           {
+             as_bad ("Illegal operands %s", error_message);
+             return;
+           }
+       }
+      break;
+    }
+
+  the_insn.opcode = opcode;
+
+#ifdef PA_DEBUG
+  if (the_insn.exp.X_add_symbol && the_insn.exp.X_subtract_symbol)
+    print_insn_short (&the_insn);
+  fprintf (stderr, "*********** END OF STATEMENT\n");
+#endif
+
+  return;
+}
+
+/*
+    This is identical to the md_atof in m68k.c.  I think this is right,
+    but I'm not sure.
+
+   Turn a string in input_line_pointer into a floating point constant of type
+   type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
+   emitted is stored in *sizeP .  An error message is returned, or NULL on OK.
+ */
+
+/* Equal to MAX_PRECISION in atof-ieee.c */
+#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;
+  char *atof_ieee ();
+
+  switch (type)
+    {
+
+    case 'f':
+    case 'F':
+    case 's':
+    case 'S':
+      prec = 2;
+      break;
+
+    case 'd':
+    case 'D':
+    case 'r':
+    case 'R':
+      prec = 4;
+      break;
+
+    case 'x':
+    case 'X':
+      prec = 6;
+      break;
+
+    case 'p':
+    case 'P':
+      prec = 6;
+      break;
+
+    default:
+      *sizeP = 0;
+      return "Bad call to MD_ATOF()";
+    }
+  t = atof_ieee (input_line_pointer, type, words);
+  if (t)
+    input_line_pointer = t;
+  *sizeP = prec * sizeof (LITTLENUM_TYPE);
+  for (wordP = words; prec--;)
+    {
+      md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE));
+      litP += sizeof (LITTLENUM_TYPE);
+    }
+  return "";                   /* Someone should teach Dean about null pointers */
+}
+
+/*
+ * Write out big-endian.
+ */
+void
+md_number_to_chars (buf, val, n)
+     char *buf;
+     valueT val;
+     int n;
+{
+
+  switch (n)
+    {
+
+    case 4:
+      *buf++ = val >> 24;
+      *buf++ = val >> 16;
+    case 2:
+      *buf++ = val >> 8;
+    case 1:
+      *buf = val;
+      break;
+
+    default:
+      abort ();
+    }
+  return;
+}
+
+void
+md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
+     char *ptr;
+     addressT from_addr, to_addr;
+     fragS *frag;
+     symbolS *to_symbol;
+{
+  fprintf (stderr, "pa_create_short_jmp\n");
+  abort ();
+}
+
+void
+md_number_to_disp (buf, val, n)
+     char *buf;
+     long val;
+     int n;
+{
+  fprintf (stderr, "md_number_to_disp\n");
+  abort ();
+}
+
+void
+md_number_to_field (buf, val, fix)
+     char *buf;
+     long val;
+     void *fix;
+{
+  fprintf (stderr, "pa_number_to_field\n");
+  abort ();
+}
+
+/* the bit-field entries in the relocation_info struct plays hell
+   with the byte-order problems of cross-assembly.  So as a hack,
+   I added this mach. dependent ri twiddler.  Ugly, but it gets
+   you there. -KWK */
+/* on sparc: first 4 bytes are normal unsigned long address, next three
+   bytes are index, most sig. byte first.  Byte 7 is broken up with
+   bit 7 as external, bits 6 & 5 unused, and the lower
+   five bits as relocation type.  Next 4 bytes are long int addend. */
+/* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com */
+
+#ifdef OBJ_SOM
+void
+md_ri_to_chars (ri_p, ri)
+     struct reloc_info_pa *ri_p, ri;
+{
+  unsigned char the_bytes[sizeof (*ri_p)];
+#if defined(OBJ_SOM) | defined(OBJ_OSFROSE) | defined(OBJ_ELF)
+  /* not sure what, if any, changes are required for new-style cross-assembly */
+#else
+  the_bytes[0] = ((ri.need_data_ref << 7) & 0x80) | ((ri.arg_reloc & 0x03f8) >> 3);
+  the_bytes[1] = ((ri.arg_reloc & 0x07) << 5) | ri.expression_type;
+  the_bytes[2] = ((ri.exec_level << 6) & 0xc0) | ri.fixup_format;
+  the_bytes[3] = ri.fixup_field & 0xff;
+  md_number_to_chars (&the_bytes[4], ri.subspace_offset, sizeof (ri.subspace_offset));
+  md_number_to_chars (&the_bytes[8], ri.symbol_index_one, sizeof (ri.symbol_index_one));
+  md_number_to_chars (&the_bytes[12], ri.symbol_index_two, sizeof (ri.symbol_index_two));
+  md_number_to_chars (&the_bytes[16], ri.fixup_constant, sizeof (ri.fixup_constant));
+
+  /* now put it back where you found it, Junior... */
+  bcopy (the_bytes, (char *) ri_p, sizeof (*ri_p));
+#endif
+
+}
+
+#endif
+
+
+/* Translate internal representation of relocation info to BFD target
+   format.  */
+/* This may need additional work to make sure that SOM support is complete. */
+#ifdef OBJ_ELF
+arelent **
+tc_gen_reloc (section, fixp)
+     asection *section;
+     fixS *fixp;
+{
+  arelent *reloc;
+  hppa_fixS *hppa_fixp = hppa_find_hppa_fix (fixp);
+  bfd_reloc_code_real_type code;
+  static int unwind_reloc_fixp_cnt = 0;
+  static arelent *unwind_reloc_entryP = NULL;
+  static arelent *no_relocs = NULL;
+  arelent **relocs;
+  bfd_reloc_code_real_type **codes;
+  int n_relocs;
+  int i;
+
+  if (fixp->fx_addsy == 0)
+    return &no_relocs;
+  assert (hppa_fixp != 0);
+  assert (section != 0);
+
+  /* unwind section relocations are handled in a special way. */
+  /* The relocations for the .unwind section are originally */
+  /* built in the usual way.  That is, for each unwind table */
+  /* entry there are two relocations:  one for the beginning of */
+  /* the function and one for the end. */
+
+  /* The first time we enter this function we create a */
+  /* relocation of the type R_HPPA_UNWIND_ENTRIES.  The addend */
+  /* of the relocation is initialized to 0.  Each additional */
+  /* pair of times this function is called for the unwind */
+  /* section represents an additional unwind table entry.  Thus, */
+  /* the addend of the relocation should end up to be the number */
+  /* of unwind table entries. */
+  if (strcmp (UNWIND_SECTION_NAME, section->name) == 0)
+    {
+      if (unwind_reloc_entryP == NULL)
+       {
+         reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
+         assert (reloc != 0);
+         unwind_reloc_entryP = reloc;
+         unwind_reloc_fixp_cnt++;
+         unwind_reloc_entryP->address = fixp->fx_frag->fr_address + fixp->fx_where;
+         /* a pointer any function will do.  We only */
+         /* need one to tell us what section the unwind */
+         /* relocations are for. */
+         unwind_reloc_entryP->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+         code = R_HPPA_UNWIND_ENTRIES;
+         unwind_reloc_entryP->howto = bfd_reloc_type_lookup (stdoutput, code);
+         unwind_reloc_entryP->addend = unwind_reloc_fixp_cnt / 2;
+         relocs = (arelent **) bfd_alloc_by_size_t (stdoutput, sizeof (arelent *) * 2);
+         assert (relocs != 0);
+         relocs[0] = unwind_reloc_entryP;
+         relocs[1] = NULL;
+         return relocs;
+       }
+      unwind_reloc_fixp_cnt++;
+      unwind_reloc_entryP->addend = unwind_reloc_fixp_cnt / 2;
+
+      return &no_relocs;
+    }
+
+  reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
+  assert (reloc != 0);
+
+  reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+  /* XXX: might need additional processing here        */
+  /* hppa_elf_gen_reloc_type() is defined in the       */
+  /* ELF/PA BFD back-end                               */
+  codes = hppa_elf_gen_reloc_type (stdoutput,
+                                  fixp->fx_r_type,
+                                  hppa_fixp->fx_r_format,
+                                  hppa_fixp->fx_r_field);
+
+  for (n_relocs = 0; codes[n_relocs]; n_relocs++)
+    ;
+
+  relocs = (arelent **) bfd_alloc_by_size_t (stdoutput, sizeof (arelent *) * n_relocs + 1);
+  assert (relocs != 0);
+
+  reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent) * n_relocs);
+  if (n_relocs > 0)
+    assert (reloc != 0);
+
+  for (i = 0; i < n_relocs; i++)
+    relocs[i] = &reloc[i];
+
+  relocs[n_relocs] = NULL;
+
+  switch (fixp->fx_r_type)
+    {
+    case R_HPPA_COMPLEX:
+    case R_HPPA_COMPLEX_PCREL_CALL:
+    case R_HPPA_COMPLEX_ABS_CALL:
+      assert (n_relocs == 5);
+
+      for (i = 0; i < n_relocs; i++)
+       {
+         reloc[i].sym_ptr_ptr = NULL;
+         reloc[i].address = 0;
+         reloc[i].addend = 0;
+         reloc[i].howto = bfd_reloc_type_lookup (stdoutput, *codes[i]);
+         assert (reloc[i].howto && *codes[i] == reloc[i].howto->type);
+       }
+
+      reloc[0].sym_ptr_ptr = &fixp->fx_addsy->bsym;
+      reloc[1].sym_ptr_ptr = &fixp->fx_subsy->bsym;
+      reloc[4].address = fixp->fx_frag->fr_address + fixp->fx_where;
+
+      if (fixp->fx_r_type == R_HPPA_COMPLEX)
+       reloc[3].addend = fixp->fx_addnumber;
+      else if (fixp->fx_r_type == R_HPPA_COMPLEX_PCREL_CALL ||
+              fixp->fx_r_type == R_HPPA_COMPLEX_ABS_CALL)
+       reloc[1].addend = fixp->fx_addnumber;
+
+      break;
+
+    default:
+      assert (n_relocs == 1);
+
+      code = *codes[0];
+
+      reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+      reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
+      reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+      reloc->addend = 0;       /* default */
+
+      assert (reloc->howto && code == reloc->howto->type);
+
+      /* Now, do any processing that is dependent on the relocation */
+      /* type. */
+      switch (code)
+       {
+       case R_HPPA_PLABEL_32:
+       case R_HPPA_PLABEL_11:
+       case R_HPPA_PLABEL_14:
+       case R_HPPA_PLABEL_L21:
+       case R_HPPA_PLABEL_R11:
+       case R_HPPA_PLABEL_R14:
+         /* For plabel relocations, the addend of the */
+         /* relocation should be either 0 (no static link) or 2 */
+         /* (static link required).    */
+         /* XXX: assume that fx_addnumber contains this */
+         /* information */
+         reloc->addend = fixp->fx_addnumber;
+         break;
+
+       case R_HPPA_ABS_CALL_11:
+       case R_HPPA_ABS_CALL_14:
+       case R_HPPA_ABS_CALL_17:
+       case R_HPPA_ABS_CALL_L21:
+       case R_HPPA_ABS_CALL_R11:
+       case R_HPPA_ABS_CALL_R14:
+       case R_HPPA_ABS_CALL_R17:
+       case R_HPPA_ABS_CALL_LS21:
+       case R_HPPA_ABS_CALL_RS11:
+       case R_HPPA_ABS_CALL_RS14:
+       case R_HPPA_ABS_CALL_RS17:
+       case R_HPPA_ABS_CALL_LD21:
+       case R_HPPA_ABS_CALL_RD11:
+       case R_HPPA_ABS_CALL_RD14:
+       case R_HPPA_ABS_CALL_RD17:
+       case R_HPPA_ABS_CALL_LR21:
+       case R_HPPA_ABS_CALL_RR14:
+       case R_HPPA_ABS_CALL_RR17:
+
+       case R_HPPA_PCREL_CALL_11:
+       case R_HPPA_PCREL_CALL_14:
+       case R_HPPA_PCREL_CALL_17:
+       case R_HPPA_PCREL_CALL_L21:
+       case R_HPPA_PCREL_CALL_R11:
+       case R_HPPA_PCREL_CALL_R14:
+       case R_HPPA_PCREL_CALL_R17:
+       case R_HPPA_PCREL_CALL_LS21:
+       case R_HPPA_PCREL_CALL_RS11:
+       case R_HPPA_PCREL_CALL_RS14:
+       case R_HPPA_PCREL_CALL_RS17:
+       case R_HPPA_PCREL_CALL_LD21:
+       case R_HPPA_PCREL_CALL_RD11:
+       case R_HPPA_PCREL_CALL_RD14:
+       case R_HPPA_PCREL_CALL_RD17:
+       case R_HPPA_PCREL_CALL_LR21:
+       case R_HPPA_PCREL_CALL_RR14:
+       case R_HPPA_PCREL_CALL_RR17:
+         /* constant is stored in the instruction */
+         reloc->addend = ELF32_HPPA_R_ADDEND (hppa_fixp->fx_arg_reloc, 0);
+         break;
+       default:
+         reloc->addend = fixp->fx_addnumber;
+         break;
+       }
+      break;
+    }
+
+  return relocs;
+}
+
+#else
+arelent *
+tc_gen_reloc (section, fixp)
+     asection *section;
+     fixS *fixp;
+{
+  arelent *reloc;
+  hppa_fixS *hppa_fixp = hppa_find_hppa_fix (fixp);
+  bfd_reloc_code_real_type code;
+
+  if (fixp->fx_addsy == 0)
+    return 0;
+  assert (hppa_fixp != 0);
+  assert (section != 0);
+
+  reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
+  assert (reloc != 0);
+
+  reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+  /* XXX: might need additional processing here   */
+  /* hppa_elf_gen_reloc_type() is defined in the  */
+  /* ELF/PA BFD back-end                          */
+  code = hppa_elf_gen_reloc_type (stdoutput,
+                                 fixp->fx_r_type,
+                                 hppa_fixp->fx_r_format,
+                                 hppa_fixp->fx_r_field);
+  reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
+
+  assert (code == reloc->howto->type);
+
+  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+  reloc->addend = 0;           /* default */
+
+  /* Now, do any processing that is dependent on the relocation */
+  /* type. (Is there any?) */
+  switch (code)
+    {
+    default:
+      reloc->addend = fixp->fx_addnumber;
+      break;
+    }
+
+  return reloc;
+}
+
+#endif
+
+void
+md_convert_frag (abfd, sec, fragP)
+     register bfd *abfd;
+     register asection *sec;
+     register fragS *fragP;
+{
+  unsigned int address;
+
+  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;
+       }
+    }
+}
+
+/* Round up a section size to the appropriate boundary. */
+valueT
+md_section_align (segment, size)
+     asection *segment;
+     valueT size;
+{
+  return (size + 7) & ~7;      /* Round all sects to multiple of 8 */
+}                              /* md_section_align() */
+
+void
+md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
+     char *ptr;
+     addressT from_addr, to_addr;
+     fragS *frag;
+     symbolS *to_symbol;
+{
+  fprintf (stderr, "pa_create_long_jump\n");
+  abort ();
+}
+
+int
+/* md_estimate_size_before_relax(fragP, segtype) */
+md_estimate_size_before_relax (fragP, segment)
+     register fragS *fragP;
+     asection *segment;
+{
+  int size;
+
+  size = 0;
+
+  while ((fragP->fr_fix + size) % fragP->fr_offset)
+    size++;
+
+  return size;
+}
+
+int
+md_parse_option (argP, cntP, vecP)
+     char **argP;
+     int *cntP;
+     char ***vecP;
+{
+  return 1;
+}
+
+/* We have no need to default values of symbols. */
+
+/* ARGSUSED */
+symbolS *
+md_undefined_symbol (name)
+     char *name;
+{
+  return 0;
+}                              /*md_undefined_symbol() */
+
+/* Parse an operand that is machine-specific.
+   We just return without modifying the expression if we have nothing
+   to do.  */
+
+/* ARGSUSED */
+void
+md_operand (expressionP)
+     expressionS *expressionP;
+{
+}
+
+/* Apply a fixS to the frags, now that we know the value it ought to
+   hold. */
+
+int 
+apply_field_selector (value, constant, field_selector)
+     long value;
+     long constant;
+     int field_selector;
+{
+  /* hppa_field_adjust() is defined in the HPPA target */
+  return hppa_field_adjust (value, constant, field_selector);
+}
+
+void 
+md_apply_fix_1 (fixP, val)
+     fixS *fixP;
+     long val;
+{
+  char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+  hppa_fixS *hppa_fixP = hppa_find_hppa_fix (fixP);
+  long new_val;
+  long result;
+  unsigned int w1, w2, w;
+  /* The following routine is defined in the ELF/PA back-end   */
+  extern unsigned char hppa_elf_insn2fmt ();
+
+  if (hppa_fixP)
+    {
+      unsigned long buf_wd = bfd_get_32 (stdoutput, buf);
+      unsigned char fmt = hppa_elf_insn2fmt (fixP->fx_r_type, buf_wd);
+
+      assert (fixP->fx_r_type < R_HPPA_UNIMPLEMENTED);
+      assert (fixP->fx_r_type >= R_HPPA_NONE);
+
+      fixP->fx_addnumber = val;        /* Remember value for emit_reloc */
+
+      /* Check if this is an undefined symbol.  No relocation can      */
+      /* possibly be performed in this case.                           */
+
+      if ((fixP->fx_addsy && fixP->fx_addsy->bsym->section == &bfd_und_section)
+         || (fixP->fx_subsy && fixP->fx_subsy->bsym->section == &bfd_und_section))
+       return;
+
+      /* Perform some processing particular to unwind */
+      /* relocations */
+
+      if (hppa_fixP->fx_call_infop
+         && (((fixP == hppa_fixP->fx_call_infop->start_fix)
+              && (fixP->fx_addsy ==
+                  hppa_fixP->fx_call_infop->start_symbol))
+             || ((fixP == hppa_fixP->fx_call_infop->end_fix)
+                 && (fixP->fx_addsy ==
+                     hppa_fixP->fx_call_infop->end_symbol))
+         ))
+       val += fixP->fx_addsy->sy_frag->fr_address;
+
+      switch (fmt)
+       {
+
+       case 14:                /* all the opcodes with the 'j' operand type */
+         new_val = apply_field_selector (val, 0, hppa_fixP->fx_r_field);
+         /* need to check for overflow here */
+
+         /* mask off 14 bits to be changed */
+         /* *(long *)buf = *(long *)buf & 0xffffc000; */
+         bfd_put_32 (stdoutput,
+                     bfd_get_32 (stdoutput, buf) & 0xffffc000,
+                     buf);
+         low_sign_unext (new_val, 14, &result);
+         break;
+
+       case 21:                /* all the opcodes with the 'k' operand type */
+         new_val = apply_field_selector (val, 0, hppa_fixP->fx_r_field);
+         /* need to check for overflow here */
+
+         /* mask off 21 bits to be changed */
+         /* *(long *)buf = *(long *)buf & 0xffe00000; */
+         bfd_put_32 (stdoutput,
+                     bfd_get_32 (stdoutput, buf) & 0xffe00000,
+                     buf);
+         dis_assemble_21 (new_val, &result);
+         break;
+
+       case 11:                /* all the opcodes with the 'i' operand type */
+         new_val = apply_field_selector (val, 0, hppa_fixP->fx_r_field);
+         /* need to check for overflow here */
+
+         /* mask off 11 bits to be changed */
+         /* *(long *)buf = *(long *)buf & 0xffff800; */
+         bfd_put_32 (stdoutput,
+                     bfd_get_32 (stdoutput, buf) & 0xffff800,
+                     buf);
+         low_sign_unext (new_val, 11, &result);
+         break;
+
+       case 12:                /* all the opcodes with the 'w' operand type */
+         new_val = apply_field_selector (val, 0, hppa_fixP->fx_r_field);
+
+         /* mask off 11 bits to be changed */
+         sign_unext ((new_val - 8) >> 2, 12, &result);
+         /* *(long *)buf = *(long *)buf & 0xffffe002; */
+         bfd_put_32 (stdoutput,
+                     bfd_get_32 (stdoutput, buf) & 0xffffe002,
+                     buf);
+
+         dis_assemble_12 (result, &w1, &w);
+         result = ((w1 << 2) | w);
+         break;
+
+       case 17:                /* some of the opcodes with the 'W' operand type */
+         new_val = apply_field_selector (val, 0, hppa_fixP->fx_r_field);
+         /* need to check for overflow here */
+
+         /* mask off 17 bits to be changed */
+         /* *(long *)buf = *(long *)buf & 0xffe0e002; */
+         bfd_put_32 (stdoutput,
+                     bfd_get_32 (stdoutput, buf) & 0xffe0e002,
+                     buf);
+         sign_unext ((new_val - 8) >> 2, 17, &result);
+         dis_assemble_17 (result, &w1, &w2, &w);
+         result = ((w2 << 2) | (w1 << 16) | w);
+         break;
+
+       case 32:
+         new_val = apply_field_selector (val, 0, hppa_fixP->fx_r_field);
+         result = new_val;     /* no transformation on result */
+         /* *(long *)buf = 0; *//* clear out everything */
+         bfd_put_32 (stdoutput, 0, buf);       /* clear out everything */
+         break;
+
+       case 0:
+         return;
+
+       default:
+         as_bad ("bad relocation type/fmt: 0x%02x/0x%02x",
+                 fixP->fx_r_type, fmt);
+         return;
+       }
+      buf[0] |= (result & 0xff000000) >> 24;
+      buf[1] |= (result & 0x00ff0000) >> 16;
+      buf[2] |= (result & 0x0000ff00) >> 8;
+      buf[3] |= result & 0x000000ff;
+      /* We've now adjusted for fx_addnumber, we can */
+      /* forget it now. */
+      fixP->fx_addnumber = 0;
+    }
+  else
+    {
+      printf ("no hppa_fixup entry for this fixup (fixP = 0x%x, type = 0x%x)\n",
+             fixP, fixP->fx_r_type);
+    }
+}                              /* md_apply_fix_1() */
+
+#ifdef BFD_ASSEMBLER
+int
+md_apply_fix (fixP, valp)
+     fixS *fixP;
+     long *valp;
+{
+  md_apply_fix_1 (fixP, *valp);
+  return 1;
+}
+
+#else
+void
+md_apply_fix (fixP, val)
+     fixS *fixP;
+     long val;
+{
+  md_apply_fix_1 (fixP, val);
+}
+
+#endif
+
+/* Exactly what point is a PC-relative offset relative TO?
+   On the PA, they're relative to the address of the offset.
+   (??? Is this right?  FIXME-SOON) */
+long 
+md_pcrel_from (fixP)
+     fixS *fixP;
+{
+  return fixP->fx_where + fixP->fx_frag->fr_address;
+}                              /* md_pcrel_from() */
+
+int 
+is_end_of_statement ()
+{
+  return ((*input_line_pointer == '\n')
+         || (*input_line_pointer == ';')
+         || (*input_line_pointer == '!'));
+}
+
+/* pa-aux.c -- Assembler for the PA - PA-RISC specific support routines */
+
+struct aux_hdr_list *aux_hdr_root = NULL;
+
+int print_errors = 1;
+
+void 
+pa_skip (s)
+     char **s;
+{
+  while (**s == ' ' || **s == '\t')
+    *s = *s + 1;
+}
+
+int 
+pa_parse_number (s)
+     char **s;
+{
+  int num;
+  char *name;
+  char c;
+  symbolS *sym;
+  int status;
+  char *p = *s;
+
+  while (*p == ' ' || *p == '\t')
+    p = p + 1;
+  num = -1;                    /* assume invalid number to begin with */
+  if (isdigit (*p))
+    {
+      num = 0;                 /* now we know it is a number */
+
+      if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X'))
+       {                       /* hex input */
+         p = 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
+       {
+         while (isdigit (*p))
+           {
+             num = num * 10 + *p - '0';
+             ++p;
+           }
+       }
+    }
+  else if (*p == '%')
+    {                          /* could be a pre-defined register */
+      num = 0;
+      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;      /* r28 is ret0 */
+             p++;
+           }
+         else if (!isdigit (*p))
+           as_bad ("Undefined register: '%s'. ASSUMING 0", name);
+         else
+           {
+             do
+               num = num * 10 + *p++ - '0';
+             while (isdigit (*p));
+           }
+       }
+      else
+       {
+         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'. ASSUMING 0", name);
+             else
+               num = -1;
+           }
+         *p = c;
+       }
+    }
+  else
+    {
+      num = 0;
+      name = p;
+      c = *p;
+      while (is_part_of_name (c))
+       {
+         p = p + 1;
+         c = *p;
+       }
+      *p = 0;
+      if ((sym = symbol_find (name)) != NULL)
+       {
+#ifdef OBJ_SOM
+         if (sym->pa_sy_type == ST_ABSOLUTE)
+           {
+             num = sym->pa_sy_value;
+#else
+         if (S_GET_SEGMENT (sym) == &bfd_abs_section)
+           {
+             num = S_GET_VALUE (sym);
+#endif
+           }
+         else
+           {
+             if (print_errors)
+               as_bad ("Non-absolute constant: '%s'. ASSUMING 0", name);
+             else
+               num = -1;
+           }
+       }
+      else
+       {
+         if (print_errors)
+           as_bad ("Undefined absolute constant: '%s'. ASSUMING 0", name);
+         else
+           num = -1;
+       }
+      *p = c;
+    }
+
+  *s = p;
+  return num;
+}
+
+struct pd_reg
+  {
+    char *name;
+    int value;
+  };
+
+/*     List of registers that are pre-defined:
+
+       General Registers:
+
+       Name    Value           Name    Value
+       %r0     0               %r16    16
+       %r1     1               %r17    17
+       %r2     2               %r18    18
+       %r3     3               %r19    19
+       %r4     4               %r20    20
+       %r5     5               %r21    21
+       %r6     6               %r22    22
+       %r7     7               %r23    23
+       %r8     8               %r24    24
+       %r9     9               %r25    25
+       %r10    10              %r26    26
+       %r11    11              %r27    27
+       %r12    12              %r28    28
+       %r13    13              %r29    29
+       %r14    14              %r30    30
+       %r15    15              %r31    31
+
+       Floating-point Registers:
+       [NOTE:  Also includes L and R versions of these (e.g. %fr19L, %fr19R)]
+
+       Name    Value           Name    Value
+       %fr0    0               %fr16   16
+       %fr1    1               %fr17   17
+       %fr2    2               %fr18   18
+       %fr3    3               %fr19   19
+       %fr4    4               %fr20   20
+       %fr5    5               %fr21   21
+       %fr6    6               %fr22   22
+       %fr7    7               %fr23   23
+        %fr8   8               %fr24   24
+       %fr9    9               %fr25   25
+       %fr10   10              %fr26   26
+       %fr11   11              %fr27   27
+       %fr12   12              %fr28   28
+       %fr13   13              %fr29   29
+       %fr14   14              %fr30   30
+       %fr15   15              %fr31   31
+
+       Space Registers:
+
+       Name    Value           Name    Value
+       %sr0    0               %sr4    4
+       %sr1    1               %sr5    5
+       %sr2    2               %sr6    6
+       %sr3    3               %sr7    7
+
+       Control registers and their synonyms:
+
+       Names                   Value
+       %cr0    %rctr           0
+       %cr8    %pidr1          8
+       %cr9    %pidr2          9
+       %cr10   %ccr            10
+       %cr11   %sar            11
+       %cr12   %pidr3          12
+       %cr13   %pidr4          13
+       %cr14   %iva            14
+       %cr15   %eiem           15
+       %cr16   %itmr           16
+       %cr17   %pcsq           17
+       %cr18   %pcoq           18
+       %cr19   %iir            19
+       %cr20   %isr            20
+       %cr21   %ior            21
+       %cr22   %ipsw           22
+       %cr23   %eirr           23
+       %cr24   %tr0 %ppda      24
+       %cr25   %tr1 %hta       25
+       %cr26   %tr2            26
+       %cr27   %tr3            27
+       %cr28   %tr4            28
+       %cr29   %tr5            29
+       %cr30   %tr6            30
+       %cr31   %tr7            31
+
+       Miscellaneous registers and their synonyms:
+
+       Names                   Value
+       %arg0                   26
+       %arg1                   25
+       %arg2                   24
+       %arg3                   23
+       %sp                     30
+       %ret0                   28
+       %ret1                   29
+*/
+
+/* This table is sorted. Suitable for searching by a binary search. */
+
+static struct pd_reg pre_defined_registers[] =
+{
+  {"%arg0", 26},
+  {"%arg1", 25},
+  {"%arg2", 24},
+  {"%arg3", 23},
+  {"%cr0", 0},
+  {"%cr10", 10},
+  {"%cr11", 11},
+  {"%cr12", 12},
+  {"%cr13", 13},
+  {"%cr14", 14},
+  {"%cr15", 15},
+  {"%cr16", 16},
+  {"%cr17", 17},
+  {"%cr18", 18},
+  {"%cr19", 19},
+  {"%cr20", 20},
+  {"%cr21", 21},
+  {"%cr22", 22},
+  {"%cr23", 23},
+  {"%cr24", 24},
+  {"%cr25", 25},
+  {"%cr26", 26},
+  {"%cr27", 27},
+  {"%cr28", 28},
+  {"%cr29", 29},
+  {"%cr30", 30},
+  {"%cr31", 31},
+  {"%cr8", 8},
+  {"%cr9", 9},
+  {"%eiem", 15},
+  {"%eirr", 23},
+  {"%fr0", 0},
+  {"%fr0L", 0},
+  {"%fr0R", 0},
+  {"%fr1", 1},
+  {"%fr10", 10},
+  {"%fr10L", 10},
+  {"%fr10R", 10},
+  {"%fr11", 11},
+  {"%fr11L", 11},
+  {"%fr11R", 11},
+  {"%fr12", 12},
+  {"%fr12L", 12},
+  {"%fr12R", 12},
+  {"%fr13", 13},
+  {"%fr13L", 13},
+  {"%fr13R", 13},
+  {"%fr14", 14},
+  {"%fr14L", 14},
+  {"%fr14R", 14},
+  {"%fr15", 15},
+  {"%fr15L", 15},
+  {"%fr15R", 15},
+  {"%fr16", 16},
+  {"%fr16L", 16},
+  {"%fr16R", 16},
+  {"%fr17", 17},
+  {"%fr17L", 17},
+  {"%fr17R", 17},
+  {"%fr18", 18},
+  {"%fr18L", 18},
+  {"%fr18R", 18},
+  {"%fr19", 19},
+  {"%fr19L", 19},
+  {"%fr19R", 19},
+  {"%fr1L", 1},
+  {"%fr1R", 1},
+  {"%fr2", 2},
+  {"%fr20", 20},
+  {"%fr20L", 20},
+  {"%fr20R", 20},
+  {"%fr21", 21},
+  {"%fr21L", 21},
+  {"%fr21R", 21},
+  {"%fr22", 22},
+  {"%fr22L", 22},
+  {"%fr22R", 22},
+  {"%fr23", 23},
+  {"%fr23L", 23},
+  {"%fr23R", 23},
+  {"%fr24", 24},
+  {"%fr24L", 24},
+  {"%fr24R", 24},
+  {"%fr25", 25},
+  {"%fr25L", 25},
+  {"%fr25R", 25},
+  {"%fr26", 26},
+  {"%fr26L", 26},
+  {"%fr26R", 26},
+  {"%fr27", 27},
+  {"%fr27L", 27},
+  {"%fr27R", 27},
+  {"%fr28", 28},
+  {"%fr28L", 28},
+  {"%fr28R", 28},
+  {"%fr29", 29},
+  {"%fr29L", 29},
+  {"%fr29R", 29},
+  {"%fr2L", 2},
+  {"%fr2R", 2},
+  {"%fr3", 3},
+  {"%fr30", 30},
+  {"%fr30L", 30},
+  {"%fr30R", 30},
+  {"%fr31", 31},
+  {"%fr31L", 31},
+  {"%fr31R", 31},
+  {"%fr3L", 3},
+  {"%fr3R", 3},
+  {"%fr4", 4},
+  {"%fr4L", 4},
+  {"%fr4R", 4},
+  {"%fr5", 5},
+  {"%fr5L", 5},
+  {"%fr5R", 5},
+  {"%fr6", 6},
+  {"%fr6L", 6},
+  {"%fr6R", 6},
+  {"%fr7", 7},
+  {"%fr7L", 7},
+  {"%fr7R", 7},
+  {"%fr8", 8},
+  {"%fr8L", 8},
+  {"%fr8R", 8},
+  {"%fr9", 9},
+  {"%fr9L", 9},
+  {"%fr9R", 9},
+  {"%hta", 25},
+  {"%iir", 19},
+  {"%ior", 21},
+  {"%ipsw", 22},
+  {"%isr", 20},
+  {"%itmr", 16},
+  {"%iva", 14},
+  {"%pcoq", 18},
+  {"%pcsq", 17},
+  {"%pidr1", 8},
+  {"%pidr2", 9},
+  {"%pidr3", 12},
+  {"%pidr4", 13},
+  {"%ppda", 24},
+  {"%r0", 0},
+  {"%r1", 1},
+  {"%r10", 10},
+  {"%r11", 11},
+  {"%r12", 12},
+  {"%r13", 13},
+  {"%r14", 14},
+  {"%r15", 15},
+  {"%r16", 16},
+  {"%r17", 17},
+  {"%r18", 18},
+  {"%r19", 19},
+  {"%r2", 2},
+  {"%r20", 20},
+  {"%r21", 21},
+  {"%r22", 22},
+  {"%r23", 23},
+  {"%r24", 24},
+  {"%r25", 25},
+  {"%r26", 26},
+  {"%r27", 27},
+  {"%r28", 28},
+  {"%r29", 29},
+  {"%r3", 3},
+  {"%r30", 30},
+  {"%r31", 31},
+  {"%r4", 4},
+  {"%r4L", 4},
+  {"%r4R", 4},
+  {"%r5", 5},
+  {"%r5L", 5},
+  {"%r5R", 5},
+  {"%r6", 6},
+  {"%r6L", 6},
+  {"%r6R", 6},
+  {"%r7", 7},
+  {"%r7L", 7},
+  {"%r7R", 7},
+  {"%r8", 8},
+  {"%r8L", 8},
+  {"%r8R", 8},
+  {"%r9", 9},
+  {"%r9L", 9},
+  {"%r9R", 9},
+  {"%rctr", 0},
+  {"%ret0", 28},
+  {"%ret1", 29},
+  {"%sar", 11},
+  {"%sp", 30},
+  {"%sr0", 0},
+  {"%sr1", 1},
+  {"%sr2", 2},
+  {"%sr3", 3},
+  {"%sr4", 4},
+  {"%sr5", 5},
+  {"%sr6", 6},
+  {"%sr7", 7},
+  {"%tr0", 24},
+  {"%tr1", 25},
+  {"%tr2", 26},
+  {"%tr3", 27},
+  {"%tr4", 28},
+  {"%tr5", 29},
+  {"%tr6", 30},
+  {"%tr7", 31}
+};
+
+#define REG_NAME_CNT   (sizeof(pre_defined_registers) / sizeof(struct pd_reg))
+
+int 
+reg_name_search (name)
+     char *name;
+{
+  int x, l, r;
+
+  l = 0;
+  r = REG_NAME_CNT - 1;
+
+  do
+    {
+      x = (l + r) / 2;
+      if (strcasecmp (name, pre_defined_registers[x].name) < 0)
+       r = x - 1;
+      else
+       l = x + 1;
+    }
+  while (!((strcasecmp (name, pre_defined_registers[x].name) == 0) ||
+          (l > r)));
+
+  if (strcasecmp (name, pre_defined_registers[x].name) == 0)
+    return (pre_defined_registers[x].value);
+  else
+    return (-1);
+
+}
+
+int 
+is_pre_defined_register (s)
+     char *s;
+{
+  if (reg_name_search (s) >= 0)
+    return (TRUE);
+  else
+    return (FALSE);
+}
+
+int 
+is_R_select (s)
+     char *s;
+{
+
+  if (*s == 'R' || *s == 'r')
+    return (TRUE);
+  else
+    return (FALSE);
+}
+
+int 
+is_L_select (s)
+     char *s;
+{
+
+  if (*s == 'L' || *s == 'l')
+    return (TRUE);
+  else
+    return (FALSE);
+}
+
+int 
+need_89_opcode (insn, result)
+     struct pa_it *insn;
+     struct pa_89_fp_reg_struct *result;
+{
+  /* if ( result->L_R_select == 1 || insn->fpof1 == DBL || insn->fpof2 == DBL ) */
+  /* if (result->L_R_select == 1 && !(insn->fpof1 == DBL || insn->fpof2 == DBL) ) */
+  if (result->L_R_select == 1 && !(insn->fpof1 == DBL && insn->fpof2 == DBL))
+    /* if ( insn->fpof1 == DBL || insn->fpof2 == DBL ) */
+    return TRUE;
+  else
+    return FALSE;
+}
+
+int
+pa_89_parse_number (s, result)
+     char **s;
+     struct pa_89_fp_reg_struct *result;
+{
+  int num;
+  char *name;
+  char c;
+  symbolS *sym;
+  int status;
+  char *p = *s;
+
+  while (*p == ' ' || *p == '\t')
+    p = p + 1;
+  num = -1;                    /* assume invalid number to begin with */
+  result->number_part = -1;
+  result->L_R_select = -1;
+
+  if (isdigit (*p))
+    {
+      num = 0;                 /* now we know it is a number */
+
+      if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X'))
+       {                       /* hex input */
+         p = 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
+       {
+         while (isdigit (*p))
+           {
+             num = num * 10 + *p - '0';
+             ++p;
+           }
+       }
+
+      result->number_part = num;
+
+      if (is_R_select (p))
+       {
+         result->L_R_select = 1;
+         ++p;
+       }
+      else if (is_L_select (p))
+       {
+         result->L_R_select = 0;
+         ++p;
+       }
+      else
+       result->L_R_select = 0;
+
+    }
+  else if (*p == '%')
+    {                          /* could be a pre-defined register */
+      num = 0;
+      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;      /* r28 is ret0 */
+             p++;
+           }
+         else if (!isdigit (*p))
+           as_bad ("Undefined register: '%s'. ASSUMING 0", name);
+         else
+           {
+             do
+               num = num * 10 + *p++ - '0';
+             while (isdigit (*p));
+           }
+       }
+      else
+       {
+         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'. ASSUMING 0", name);
+             else
+               num = -1;
+           }
+         *p = c;
+       }
+
+      result->number_part = num;
+
+      if (is_R_select (p - 1))
+       result->L_R_select = 1;
+      else if (is_L_select (p - 1))
+       result->L_R_select = 0;
+      else
+       result->L_R_select = 0;
+
+    }
+  else
+    {
+      num = 0;
+      name = p;
+      c = *p;
+      while (is_part_of_name (c))
+       {
+         p = p + 1;
+         c = *p;
+       }
+      *p = 0;
+      if ((sym = symbol_find (name)) != NULL)
+       {
+#ifdef OBJ_SOM
+         if (sym->pa_sy_type == ST_ABSOLUTE)
+           {
+             num = sym->pa_sy_value;
+#else
+         if (S_GET_SEGMENT (sym) == &bfd_abs_section)
+           {
+             num = S_GET_VALUE (sym);
+#endif
+           }
+         else
+           {
+             if (print_errors)
+               as_bad ("Non-absolute constant: '%s'. ASSUMING 0", name);
+             else
+               num = -1;
+           }
+       }
+      else
+       {
+         if (print_errors)
+           as_bad ("Undefined absolute constant: '%s'. ASSUMING 0", name);
+         else
+           num = -1;
+       }
+      *p = c;
+      result->number_part = num;
+
+      if (is_R_select (p - 1))
+       result->L_R_select = 1;
+      else if (is_L_select (p - 1))
+       result->L_R_select = 0;
+      else
+       result->L_R_select = 0;
+
+    }
+
+  *s = p;
+  return num;
+
+}
+
+int 
+pa_parse_fp_cmp_cond (s)
+     char **s;
+{
+  int cond, i;
+  struct possibleS
+    {
+      char *string;
+      int cond;
+    };
+
+  /*
+     This table is sorted by order of the length of the string. This is so we
+     check for <> before we check for <. If we had a <> and checked for < first,
+     we would get a false match.
+   */
+  static struct possibleS poss[] =
+  {
+    {"false?", 0},
+    {"false", 1},
+    {"true?", 30},
+    {"true", 31},
+    {"!<=>", 3},
+    {"!?>=", 8},
+    {"!?<=", 16},
+    {"!<>", 7},
+    {"!>=", 11},
+    {"!?>", 12},
+    {"?<=", 14},
+    {"!<=", 19},
+    {"!?<", 20},
+    {"?>=", 22},
+    {"!?=", 24},
+    {"!=t", 27},
+    {"<=>", 29},
+    {"=t", 5},
+    {"?=", 6},
+    {"?<", 10},
+    {"<=", 13},
+    {"!>", 15},
+    {"?>", 18},
+    {">=", 21},
+    {"!<", 23},
+    {"<>", 25},
+    {"!=", 26},
+    {"!?", 28},
+    {"?", 2},
+    {"=", 4},
+    {"<", 9},
+    {">", 17}
+  };
+
+  cond = 0;
+
+  for (i = 0; i < 32; i++)
+    {
+      if (strncasecmp (*s, poss[i].string, strlen (poss[i].string)) == 0)
+       {
+         cond = poss[i].cond;
+         *s += strlen (poss[i].string);
+         while (**s == ' ' || **s == '\t')
+           *s = *s + 1;
+         return cond;
+       }
+    }
+
+  as_bad ("Illegal FP Compare Condition: %c", **s);
+  return 0;
+}
+
+FP_Operand_Format 
+pa_parse_fp_format (s)
+     char **s;
+{
+  int f;
+
+  f = SGL;
+  if (**s == ',')
+    {
+      *s += 1;
+      if (strncasecmp (*s, "sgl", 3) == 0)
+       {
+         f = SGL;
+         *s += 4;
+       }
+      else if (strncasecmp (*s, "dbl", 3) == 0)
+       {
+         f = DBL;
+         *s += 4;
+       }
+      else if (strncasecmp (*s, "quad", 4) == 0)
+       {
+         f = QUAD;
+         *s += 5;
+       }
+      else
+       {
+         f = ILLEGAL_FMT;
+         as_bad ("Unrecognized FP Operand Format: %3s", *s);
+       }
+    }
+  while (**s == ' ' || **s == '\t' || **s == 0)
+    *s = *s + 1;
+
+  return f;
+}
+
+#if defined(OBJ_ELF)
+int 
+pa_chk_field_selector (str)
+     char **str;
+{
+  int selector;
+  struct selector_entry
+    {
+      char *prefix;
+      int field_selector;
+    };
+  static struct selector_entry selector_table[] =
+  {
+    {"F'", e_fsel},
+    {"F%", e_fsel},
+    {"LS'", e_lssel},
+    {"LS%", e_lssel},
+    {"RS'", e_rssel},
+    {"RS%", e_rssel},
+    {"L'", e_lsel},
+    {"L%", e_lsel},
+    {"R'", e_rsel},
+    {"R%", e_rsel},
+    {"LD'", e_ldsel},
+    {"LD%", e_ldsel},
+    {"RD'", e_rdsel},
+    {"RD%", e_rdsel},
+    {"LR'", e_lrsel},
+    {"LR%", e_lrsel},
+    {"RR'", e_rrsel},
+    {"RR%", e_rrsel},
+    {"P'", e_psel},
+    {"P%", e_psel},
+    {"RP'", e_rpsel},
+    {"RP%", e_rpsel},
+    {"LP'", e_lpsel},
+    {"LP%", e_lpsel},
+    {"T'", e_tsel},
+    {"T%", e_tsel},
+    {"RT'", e_rtsel},
+    {"RT%", e_rtsel},
+    {"LT'", e_ltsel},
+    {"LT%", e_ltsel},
+    {NULL, e_fsel}
+  };
+  struct selector_entry *tableP;
+
+  selector = e_fsel;
+
+  while (**str == ' ' || **str == '\t' || **str == '\n' || **str == '\f')
+    {
+      *str = *str + 1;
+    }
+  for (tableP = selector_table; tableP->prefix; tableP++)
+    {
+      if (strncasecmp (tableP->prefix, *str, strlen (tableP->prefix)) == 0)
+       {
+         *str += strlen (tableP->prefix);
+         selector = tableP->field_selector;
+         break;
+       }
+    }
+  return selector;
+}
+
+int
+getExpression (str)
+     char *str;
+{
+  char *save_in;
+  asection *seg;
+
+  save_in = input_line_pointer;
+  input_line_pointer = str;
+  seg = expression (&the_insn.exp);
+
+  if (!(seg == &bfd_abs_section
+       || seg == &bfd_und_section
+       || seg == text_section
+       || seg == data_section
+       || seg == bss_section
+       || seg == diff_section
+       || seg == big_section
+       || seg == absent_section))
+    {
+      the_insn.error = "bad segment";
+      expr_end = input_line_pointer;
+      input_line_pointer = save_in;
+      return 1;
+    }
+  expr_end = input_line_pointer;
+  input_line_pointer = save_in;
+  return 0;
+}
+
+int
+getAbsoluteExpression (str)
+     char *str;
+{
+  char *save_in;
+  asection *seg;
+
+  save_in = input_line_pointer;
+  input_line_pointer = str;
+  seg = expression (&the_insn.exp);
+
+  if (seg != &bfd_abs_section)
+    {
+      the_insn.error = "segment should be ABSOLUTE";
+      expr_end = input_line_pointer;
+      input_line_pointer = save_in;
+      return 1;
+    }
+  expr_end = input_line_pointer;
+  input_line_pointer = save_in;
+  return 0;
+}
+
+#else
+int
+getExpression (str)
+     char *str;
+{
+  char *save_in;
+  segT seg;
+
+  save_in = input_line_pointer;
+  input_line_pointer = str;
+  switch (seg = expression (&the_insn.exp))
+    {
+
+    case SEG_ABSOLUTE:
+    case SEG_TEXT:
+    case SEG_DATA:
+    case SEG_BSS:
+    case SEG_UNKNOWN:
+    case SEG_DIFFERENCE:
+    case SEG_BIG:
+    case SEG_GDB:
+    case SEG_MILLICODE:
+    case SEG_NONE:
+      break;
+
+    default:
+      the_insn.error = "illegal segment";
+      expr_end = input_line_pointer;
+      input_line_pointer = save_in;
+      return 1;
+    }
+  expr_end = input_line_pointer;
+  input_line_pointer = save_in;
+  return 0;
+}
+
+int
+getAbsoluteExpression (str)
+     char *str;
+{
+  char *save_in;
+  segT seg;
+
+  save_in = input_line_pointer;
+  input_line_pointer = str;
+  switch (seg = expression (&the_insn.exp))
+    {
+
+    case SEG_ABSOLUTE:
+      break;
+
+    default:
+      the_insn.error = "segment should be ABSOLUTE";
+      expr_end = input_line_pointer;
+      input_line_pointer = save_in;
+      return 1;
+    }
+  expr_end = input_line_pointer;
+  input_line_pointer = save_in;
+  return 0;
+}
+
+#endif
+
+int 
+evaluateAbsolute (exp, field_selector)
+     expressionS exp;
+     int field_selector;
+{
+  int value;
+
+  value = exp.X_add_number;
+
+  if (exp.X_add_symbol)
+    {
+      value += S_GET_VALUE (exp.X_add_symbol);
+    }
+  if (exp.X_subtract_symbol)
+    {
+      value -= S_GET_VALUE (exp.X_subtract_symbol);
+    }
+
+  switch (field_selector)
+    {
+    case e_fsel:               /* F  : no change                      */
+      break;
+
+    case e_lssel:              /* LS : if (bit 21) then add 0x800
+                              arithmetic shift right 11 bits */
+      if (value & 0x00000400)
+       value += 0x800;
+      value = (value & 0xfffff800) >> 11;
+      break;
+
+    case e_rssel:              /* RS : Sign extend from bit 21        */
+      if (value & 0x00000400)
+       value |= 0xfffff800;
+      else
+       value &= 0x7ff;
+      break;
+
+    case e_lsel:               /* L  : Arithmetic shift right 11 bits */
+      value = (value & 0xfffff800) >> 11;
+      break;
+
+    case e_rsel:               /* R  : Set bits 0-20 to zero          */
+      value = value & 0x7ff;
+      break;
+
+    case e_ldsel:              /* LD : Add 0x800, arithmetic shift
+                              right 11 bits                  */
+      value += 0x800;
+      value = (value & 0xfffff800) >> 11;
+      break;
+
+    case e_rdsel:              /* RD : Set bits 0-20 to one           */
+      value |= 0xfffff800;
+      break;
+
+    case e_lrsel:              /* LR : L with "rounded" constant      */
+      /* XXX: this isn't right.  Need to add a "rounded" constant */
+      /* XXX: (presumably from X_add_number)                      */
+      value = (value & 0xfffff800) >> 11;
+      break;
+
+    case e_rrsel:              /* RR : R with "rounded" constant      */
+      /* XXX: this isn't right.  Need to add a "rounded" constant */
+      /* XXX: (presumably from X_add_number)                      */
+      value = value & 0x7ff;
+      break;
+
+    default:
+      BAD_CASE (field_selector);
+      break;
+    }
+  return value;
+}
+
+int 
+pa_build_arg_reloc (type_name)
+     char *type_name;
+{
+
+  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 ("Unrecognized argument location: %s\n", type_name);
+
+  return 0;
+}
+
+unsigned int 
+pa_align_arg_reloc (reg, arg_reloc)
+     unsigned int reg;
+     unsigned int arg_reloc;
+{
+  unsigned int new_reloc;
+
+  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 ("Illegal argument description: %d", reg);
+    }
+
+  return new_reloc;
+}
+
+int 
+pa_parse_nullif (s)
+     char **s;
+{
+  int nullif;
+
+  nullif = 0;
+  if (**s == ',')
+    {
+      *s = *s + 1;
+      if (strncasecmp (*s, "n", 1) == 0)
+       nullif = 1;
+      else
+       {
+         as_bad ("Unrecognized Nullification: (%c)", **s);
+         nullif = 0;
+       }
+      *s = *s + 1;
+    }
+  while (**s == ' ' || **s == '\t')
+    *s = *s + 1;
+
+  return nullif;
+}
+
+#if 0
+int 
+pa_parse_nonneg_cmpsub_cmpltr (s)
+     char **s;
+{
+  int cmpltr;
+  char *name;
+  char c;
+
+  cmpltr = -1;
+  /** cmpltr = 0; **/
+  if (**s == ',')
+    {
+      *s += 1;
+      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 (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
+      cmpltr = -1;
+    **/
+      **s = c;
+    }
+  if (cmpltr >= 0)
+    {
+      while (**s == ' ' || **s == '\t')
+       *s = *s + 1;
+    }
+
+  return cmpltr;
+}
+
+#endif
+int 
+pa_parse_nonneg_cmpsub_cmpltr (s)
+     char **s;
+{
+  int cmpltr;
+  char *name;
+  char c;
+
+  cmpltr = 0;
+  if (**s == ',')
+    {
+      *s += 1;
+      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 (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
+       cmpltr = -1;
+      **s = c;
+    }
+  if (cmpltr >= 0)
+    {
+      while (**s == ' ' || **s == '\t')
+       *s = *s + 1;
+    }
+
+  return cmpltr;
+}
+
+int 
+pa_parse_neg_cmpsub_cmpltr (s)
+     char **s;
+{
+  int cmpltr;
+  char *name;
+  char c;
+
+  cmpltr = -1;
+  if (**s == ',')
+    {
+      *s += 1;
+      name = *s;
+      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 (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;
+       }
+      **s = c;
+    }
+  if (cmpltr >= 0)
+    {
+      while (**s == ' ' || **s == '\t')
+       *s = *s + 1;
+    }
+
+  return cmpltr;
+}
+
+int 
+pa_parse_nonneg_add_cmpltr (s)
+     char **s;
+{
+  int cmpltr;
+  char *name;
+  char c;
+
+  cmpltr = -1;
+  if (**s == ',')
+    {
+      *s += 1;
+      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;
+       }
+      **s = c;
+    }
+  if (cmpltr >= 0)
+    {
+      while (**s == ' ' || **s == '\t')
+       *s = *s + 1;
+    }
+
+  return cmpltr;
+}
+
+int 
+pa_parse_neg_add_cmpltr (s)
+     char **s;
+{
+  int cmpltr;
+  char *name;
+  char c;
+
+  cmpltr = -1;
+  if (**s == ',')
+    {
+      *s += 1;
+      name = *s;
+      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 (strcmp (name, "uv") == 0)
+       {
+         cmpltr = 4;
+       }
+      else if (strcmp (name, "vnz") == 0)
+       {
+         cmpltr = 5;
+       }
+      else if (strcasecmp (name, "nsv") == 0)
+       {
+         cmpltr = 6;
+       }
+      else if (strcasecmp (name, "ev") == 0)
+       {
+         cmpltr = 7;
+       }
+      **s = c;
+    }
+  if (cmpltr >= 0)
+    {
+      while (**s == ' ' || **s == '\t')
+       *s = *s + 1;
+    }
+
+  return cmpltr;
+}
+
+void 
+s_seg ()
+{
+
+  if (strncmp (input_line_pointer, "\"text\"", 6) == 0)
+    {
+      input_line_pointer += 6;
+      s_text ();
+      return;
+    }
+  if (strncmp (input_line_pointer, "\"data\"", 6) == 0)
+    {
+      input_line_pointer += 6;
+      s_data ();
+      return;
+    }
+  if (strncmp (input_line_pointer, "\"data1\"", 7) == 0)
+    {
+      input_line_pointer += 7;
+      s_data1 ();
+      return;
+    }
+  as_bad ("Unknown segment type");
+  demand_empty_rest_of_line ();
+  return;
+}
+
+void 
+s_private ()
+{
+  register int temp;
+
+  temp = get_absolute_expression ();
+#ifdef OBJ_SOM
+  subseg_new (SEG_DATA, (subsegT) temp);
+#else
+  subseg_new (".data", (subsegT) temp);
+#endif
+  demand_empty_rest_of_line ();
+}
+
+void 
+s_data1 ()
+{
+#ifdef OBJ_SOM
+  subseg_new (SEG_DATA, 1);
+#else
+  subseg_new (".data", 1);
+#endif
+  demand_empty_rest_of_line ();
+  return;
+}
+
+void 
+s_proc ()
+{
+  extern char is_end_of_line[];
+
+  while (!is_end_of_line[*input_line_pointer])
+    {
+      ++input_line_pointer;
+    }
+  ++input_line_pointer;
+  return;
+}
+
+void 
+pa_block (z)
+     int z;
+{
+  register char *p;
+  register long int temp_fill;
+  register long int temp_size;
+  register int i;
+
+  temp_size = get_absolute_expression ();
+
+  if (z)
+    {                          /* fill with zeroes even if not requested to do so. */
+      temp_fill = 0;           /* HP assembler does this too. */
+    }
+  else
+    {
+      temp_fill = 0;
+    }
+
+  if (temp_size <= 0)
+    {
+      as_bad ("size < 0, .block ignored");
+      temp_size = 0;
+    }
+  p = frag_var (rs_fill,
+               (int) temp_size,
+       (int) temp_size, (relax_substateT) 0, (symbolS *) 0, 1, (char *) 0);
+  bzero (p, (int) temp_size);
+
+  /* convert 2 bytes at a time */
+
+  for (i = 0; i < temp_size; i += 2)
+    {
+      md_number_to_chars (p + i,
+                         temp_fill,
+                         (int) ((temp_size - i) > 2 ? 2 : (temp_size - i)));
+    }
+
+  pa_undefine_label ();
+  demand_empty_rest_of_line ();
+  return;
+}
+
+void 
+pa_call ()
+{
+
+  pa_call_args (&last_call_desc);
+  demand_empty_rest_of_line ();
+  return;
+}
+
+void 
+pa_call_args (call_desc)
+     register call_descS *call_desc;
+{
+  register char *name;
+  register char c;
+  register char *p;
+  register int temp;
+  register unsigned int arg_reloc;
+
+  while (!is_end_of_statement ())
+    {
+      name = input_line_pointer;
+      c = get_symbol_end ();
+      if ((strncasecmp (name, "argw", 4) == 0))
+       {
+         temp = atoi (name + 4);
+         p = input_line_pointer;
+         *p = c;
+         input_line_pointer++;
+         name = input_line_pointer;
+         c = get_symbol_end ();
+         arg_reloc = pa_build_arg_reloc (name);
+         call_desc->arg_reloc |= pa_align_arg_reloc (temp, arg_reloc);
+       }
+      else if ((strncasecmp (name, "rtnval", 6) == 0))
+       {
+         p = input_line_pointer;
+         *p = c;
+         input_line_pointer++;
+         name = input_line_pointer;
+         c = get_symbol_end ();
+         arg_reloc = pa_build_arg_reloc (name);
+         call_desc->arg_reloc |= (arg_reloc & 0x3);
+       }
+      else
+       {
+         as_bad ("Unrecognized .CALL argument: %s", name);
+       }
+      p = input_line_pointer;
+      *p = c;
+      if (!is_end_of_statement ())
+       input_line_pointer++;
+    }
+}
+
+static int
+is_same_frag (frag1P, frag2P)
+     fragS *frag1P;
+     fragS *frag2P;
+{
+
+  if (frag1P == NULL)
+    return (FALSE);
+  else if (frag2P == NULL)
+    return (FALSE);
+  else if (frag1P == frag2P)
+    return (TRUE);
+  else if (frag2P->fr_type == rs_fill && frag2P->fr_fix == 0)
+    is_same_frag (frag1P, frag2P->fr_next);
+  else
+    return (FALSE);
+}
+
+#ifdef OBJ_ELF
+static void
+pa_build_unwind_subspace (call_info)
+     call_infoS *call_info;
+{
+  char *unwindP;
+  asection *seg;
+  asection *save_seg;
+  subsegT subseg, save_subseg;
+  int i;
+  char c;
+  char *p;
+
+  subseg = SUBSEG_UNWIND;
+  seg = bfd_get_section_by_name (stdoutput, UNWIND_SECTION_NAME);
+  if (seg == ASEC_NULL)
+    {
+      seg = bfd_make_section_old_way (stdoutput, UNWIND_SECTION_NAME);
+    }
+  bfd_set_section_flags (stdoutput,
+                        seg,
+                        SEC_READONLY | SEC_ALLOC | SEC_LOAD | SEC_RELOC);
+
+  /* callinfo.frame is in bytes and unwind_desc is in 8 byte units */
+  call_info->ci_unwind.descriptor.frame_size = call_info->frame / 8;
+
+  /* Now, dump the unwind descriptor to the $UNWIND$ subspace. This
+     creates a couple of relocations */
+
+  save_seg = now_seg;
+  save_subseg = now_subseg;
+  subseg_new ((char *) seg->name, subseg);
+  unwindP = (char *) &call_info->ci_unwind;
+
+  p = frag_more (4);
+  call_info->start_offset_frag = frag_now;
+  call_info->start_frag_where = p - frag_now->fr_literal;
+
+  /* relocation info. for start offset of the function */
+
+  fix_new_hppa (frag_now, p - frag_now->fr_literal, 4,
+               call_info->start_symbol, (symbolS *) NULL,
+               0, 0, R_HPPA, e_fsel, 32, 0, (char *) 0);
+
+  /** we need to search for the first relocation involving the start_symbol of **/
+  /** this call_info descriptor **/
+
+  {
+    fixS *fixP;
+
+    call_info->start_fix = seg_info (now_seg)->fix_root;       /* the default */
+    for (fixP = call_info->start_fix; fixP; fixP = fixP->fx_next)
+      {
+       if (fixP->fx_addsy == call_info->start_symbol
+           || fixP->fx_subsy == call_info->start_symbol)
+         {
+           call_info->start_fix = fixP;
+           break;
+         }
+      }
+  }
+
+  p = frag_more (4);
+  call_info->end_offset_frag = frag_now;
+  call_info->end_frag_where = p - frag_now->fr_literal;
+
+  /* relocation info. for end offset of the function */
+
+  fix_new_hppa (frag_now, p - frag_now->fr_literal, 4,
+               call_info->end_symbol, (symbolS *) NULL,
+               0, 0, R_HPPA, e_fsel, 32, 0, (char *) 0);
+
+  /** we need to search for the first relocation involving the start_symbol of **/
+  /** this call_info descriptor **/
+
+  {
+    fixS *fixP;
+
+    call_info->end_fix = seg_info (now_seg)->fix_root; /* the default */
+    for (fixP = call_info->end_fix; fixP; fixP = fixP->fx_next)
+      {
+       if (fixP->fx_addsy == call_info->end_symbol
+           || fixP->fx_subsy == call_info->end_symbol)
+         {
+           call_info->end_fix = fixP;
+           break;
+         }
+      }
+  }
+
+  for (i = 8; i < sizeof (unwind_tableS); i++)
+    {
+      c = *(unwindP + i);
+      {
+       FRAG_APPEND_1_CHAR (c);
+      }
+    }
+
+  subseg_new ((char *) save_seg->name, save_subseg);
+}
+
+#else
+#ifdef OBJ_SOM
+static void
+pa_build_unwind_subspace (call_info)
+     call_infoS *call_info;
+{
+  space_dict_chainS *spaceP;
+  subspace_dict_chainS *subspaceP;
+  char *unwindP;
+  char defined, loadable, code_only, common, dup_common, is_zero, sort;
+  int access, space_index, alignment, quadrant;
+  segT seg, save_seg;
+  subsegT subseg, save_subseg;
+  int i;
+  char c;
+  char *p;
+
+  defined = 1;
+  loadable = 1;
+  code_only = 0;
+  common = 0;
+  dup_common = 0;
+  is_zero = 0;
+  sort = 0x40;
+  access = 0x2c;
+  space_index = 0;
+  alignment = 8;
+  quadrant = 0;
+  subseg = SUBSEG_UNWIND;
+  seg = SEG_TEXT;
+
+  spaceP = pa_segment_to_space (seg);
+
+  if ((subspaceP = is_defined_subspace ("$UNWIND$", SUBSEG_UNWIND)))
+    {
+      update_subspace ("$UNWIND$", defined, loadable, code_only, common, dup_common,
+                   sort, is_zero, access, space_index, alignment, quadrant,
+                      SUBSEG_UNWIND);
+    }
+  else
+    {
+      subspaceP = create_new_subspace (spaceP, "$UNWIND$", defined, loadable, code_only,
+                                 common, dup_common, is_zero, sort, access,
+                                    space_index, alignment, quadrant, seg);
+    }
+
+
+  /* callinfo.frame is in bytes and unwind_desc is in 8 byte units */
+  call_info->ci_unwind.descriptor.frame_size = call_info->frame / 8;
+
+  /* Now, dump the unwind descriptor to the $UNWIND$ subspace. This
+     creates a couple of relocations */
+
+  save_seg = now_seg;
+  save_subseg = now_subseg;
+  subseg_new (seg, subseg);
+  unwindP = (char *) &call_info->ci_unwind;
+
+  p = frag_more (4);
+  call_info->start_offset_frag = frag_now;
+  call_info->start_frag_where = p - frag_now->fr_literal;
+
+  /* relocation info. for start offset of the function */
+
+  fix_new (frag_now, p - frag_now->fr_literal, 4,
+          call_info->start_symbol, (symbolS *) NULL,
+          0, 0, R_DATA_ONE_SYMBOL, e_fsel, 0, 0, (char *) 0);
+
+  /** we need to search for the first relocation involving the start_symbol of **/
+  /** this call_info descriptor **/
+
+  {
+    fixS *fixP;
+
+    call_info->start_fix = seg_info (now_seg)->fix_root;       /* the default */
+    for (fixP = call_info->start_fix; fixP; fixP = fixP->fx_next)
+      {
+       /*
+      if ( ( fixP->fx_addsy == call_info->start_symbol ||
+            fixP->fx_subsy == call_info->start_symbol )
+         &&
+          ( fixP->fx_frag == call_info->start_symbol->sy_frag ) ) {
+       */
+       if ((fixP->fx_addsy == call_info->start_symbol ||
+            fixP->fx_subsy == call_info->start_symbol)
+           &&
+           (is_same_frag (fixP->fx_frag, call_info->start_symbol->sy_frag)))
+         {
+           call_info->start_fix = fixP;
+           break;
+         }
+      }
+  }
+
+  p = frag_more (4);
+  call_info->end_offset_frag = frag_now;
+  call_info->end_frag_where = p - frag_now->fr_literal;
+
+  /* relocation info. for end offset of the function */
+
+  fix_new (frag_now, p - frag_now->fr_literal, 4,
+          call_info->start_symbol, (symbolS *) NULL,
+          0, 0, R_DATA_ONE_SYMBOL, e_fsel, 0, 0, (char *) 0);
+
+  /** we need to search for the first relocation involving the start_symbol of **/
+  /** this call_info descriptor **/
+
+  {
+    fixS *fixP;
+
+    call_info->end_fix = seg_info (now_seg)->fix_root; /* the default */
+    for (fixP = call_info->end_fix; fixP; fixP = fixP->fx_next)
+      {
+       /*
+      if ( ( fixP->fx_addsy == call_info->start_symbol ||
+            fixP->fx_subsy == call_info->start_symbol )
+         &&
+          ( fixP->fx_frag == call_info->start_symbol->sy_frag ) ) {
+       */
+       if ((fixP->fx_addsy == call_info->start_symbol ||
+            fixP->fx_subsy == call_info->start_symbol)
+           &&
+           (is_same_frag (fixP->fx_frag, call_info->start_symbol->sy_frag)))
+         {
+           call_info->end_fix = fixP;
+           break;
+         }
+      }
+  }
+
+  for (i = 8; i < sizeof (unwind_tableS); i++)
+    {
+      c = *(unwindP + i);
+      {
+       FRAG_APPEND_1_CHAR (c);
+      }
+    }
+
+  subseg_new (save_seg, save_subseg);
+
+}
+
+#endif
+#endif
+
+void 
+pa_callinfo ()
+{
+  register char *name;
+  register char c;
+  register char *p;
+  register int temp;
+  register symbolS *symbolP;
+
+  if (!within_procedure)
+    as_bad (".callinfo is not within a procedure definition");
+
+  callinfo_found = TRUE;
+
+  while (!is_end_of_statement ())
+    {
+      name = input_line_pointer;
+      c = get_symbol_end ();
+      if ((strncasecmp (name, "frame", 5) == 0))
+       {
+         p = input_line_pointer;
+         *p = c;
+         input_line_pointer++;
+         temp = get_absolute_expression ();
+         if ((temp & 0x3) != 0)
+           {
+             as_bad ("FRAME parameter must be a multiple of 8: %d\n", temp);
+             temp = 0;
+           }
+         last_call_info->frame = temp;
+       }
+      else if ((strncasecmp (name, "entry_gr", 8) == 0))
+       {
+         p = input_line_pointer;
+         *p = c;
+         input_line_pointer++;
+         temp = get_absolute_expression ();
+         last_call_info->ci_unwind.descriptor.entry_gr = temp;
+       }
+      else if ((strncasecmp (name, "entry_fr", 8) == 0))
+       {
+         p = input_line_pointer;
+         *p = c;
+         input_line_pointer++;
+         temp = get_absolute_expression ();
+         last_call_info->ci_unwind.descriptor.entry_fr = temp;
+       }
+      else if ((strncasecmp (name, "entry_sr", 8) == 0))
+       {
+         p = input_line_pointer;
+         *p = c;
+         input_line_pointer++;
+         temp = get_absolute_expression ();
+         last_call_info->entry_sr = temp;
+       }
+      else if ((strncasecmp (name, "calls", 5) == 0) ||
+              (strncasecmp (name, "caller", 6) == 0))
+       {
+         p = input_line_pointer;
+         *p = c;
+         last_call_info->makes_calls = 1;
+       }
+      else if ((strncasecmp (name, "no_calls", 8) == 0))
+       {
+         p = input_line_pointer;
+         *p = c;
+         last_call_info->makes_calls = 0;
+       }
+      else if ((strncasecmp (name, "save_rp", 7) == 0))
+       {
+         p = input_line_pointer;
+         *p = c;
+         last_call_info->ci_unwind.descriptor.save_rp = 1;
+       }
+      else if ((strncasecmp (name, "save_sp", 7) == 0))
+       {
+         p = input_line_pointer;
+         *p = c;
+         last_call_info->ci_unwind.descriptor.save_sp = 1;
+       }
+      else if ((strncasecmp (name, "no_unwind", 9) == 0))
+       {
+         p = input_line_pointer;
+         *p = c;
+         last_call_info->ci_unwind.descriptor.cannot_unwind = 1;
+       }
+      else if ((strncasecmp (name, "hpux_int", 7) == 0))
+       {
+         p = input_line_pointer;
+         *p = c;
+         last_call_info->hpux_int = 1;
+       }
+      else
+       {
+         as_bad ("Unrecognized .CALLINFO argument: %s", name);
+       }
+      if (!is_end_of_statement ())
+       input_line_pointer++;
+    }
+
+  demand_empty_rest_of_line ();
+  return;
+}
+
+void 
+pa_code ()
+{
+  space_dict_chainS *sdchain;
+
+  if ((sdchain = is_defined_space ("$TEXT$")) == NULL)
+    {
+      sdchain = create_new_space (pa_def_spaces[0].name, pa_def_spaces[0].spnum,
+                       pa_def_spaces[0].loadable, pa_def_spaces[0].defined,
+                           pa_def_spaces[0].private, pa_def_spaces[0].sort,
+                                 1, pa_def_spaces[0].segment);
+    }
+
+  SPACE_DEFINED (sdchain) = 1;
+#ifdef OBJ_SOM
+
+  subseg_new (SEG_TEXT, SUBSEG_CODE);
+#else
+
+  subseg_new (".text", SUBSEG_CODE);
+#endif
+
+  demand_empty_rest_of_line ();
+  return;
+}
+
+/*
+ * This is different than the standard GAS s_comm(). On HP9000/800 machines,
+ * the .comm pseudo-op has the following symtax:
+ *
+ *     <label> .comm <length>
+ *
+ * where <label> is optional and is a symbol whose address will be the start of
+ * a block of memory <length> bytes long. <length> must be an absolute expressio
+n.
+ * <length> bytes will be allocated in the current space and subspace.
+ *
+ */
+
+void
+pa_comm ()
+{
+  register char *p;
+  register int size, i;
+  register symbolS *symbolP;
+  register label_symbolS *label_symbolP = pa_get_label ();
+
+  if (label_symbolP)
+    symbolP = label_symbolP->lss_label;
+  else
+    symbolP = NULL;
+
+  SKIP_WHITESPACE ();
+  if ((size = get_absolute_expression ()) < 0)
+    {
+      as_warn (".COMMon length (%d.) <0! Ignored.", size);
+      ignore_rest_of_line ();
+      return;
+    }
+
+  if (symbolP)
+    {
+#ifdef OBJ_SOM
+      if (symbolP->pa_sy_type == ST_STORAGE &&
+         symbolP->pa_sy_scope == SS_UNSAT)
+       {
+         if (symbolP->pa_sy_value != size)
+           {
+             as_warn ("Length of .comm \"%s\" is already %d. Not changed to %d.",
+                      symbolP->pa_sy_name, symbolP->pa_sy_value, size);
+             return;
+           }
+       }
+      else
+       {
+         symbolP->pa_sy_value = size;
+         symbolP->pa_sy_scope = SS_UNSAT;
+         symbolP->pa_sy_type = ST_STORAGE;
+         symbolP->sy_ref = sym_def;
+       }
+#endif
+#ifdef OBJ_ELF
+      if (S_IS_DEFINED (symbolP) && S_GET_SEGMENT (symbolP) == bss_section)
+       {
+         as_bad ("Ignoring attempt to re-define symbol");
+         ignore_rest_of_line ();
+         return;
+       }
+      if (S_GET_VALUE (symbolP))
+       {
+         if (S_GET_VALUE (symbolP) != size)
+           {
+             as_warn ("Length of .comm \"%s\" is already %d. Not changed to %d.",
+                      S_GET_NAME (symbolP), S_GET_VALUE (symbolP), size);
+             return;
+           }
+       }
+      else
+       {
+         S_SET_VALUE (symbolP, size);
+         S_SET_SEGMENT (symbolP, bss_section);
+         S_SET_EXTERNAL (symbolP);
+       }
+#endif
+    }
+
+
+  demand_empty_rest_of_line ();
+}
+
+void 
+pa_copyright ()
+{
+  register char *name;
+  register char c;
+  register char *p;
+  register int temp;
+  register symbolS *symbolP;
+
+  SKIP_WHITESPACE ();
+  if (*input_line_pointer == '\"')
+    {
+      ++input_line_pointer;    /* -> 1st char of string. */
+      name = input_line_pointer;
+      while ((c = next_char_of_string ()) >= 0)
+       ;
+      c = *input_line_pointer;
+      *input_line_pointer = '\0';
+      *(input_line_pointer - 1) = '\0';
+      {
+#ifdef OBJ_SOM
+#define PREFIX "Copyright "
+#define MIDFIX  ". All rights reserved. No part of this program may be photocopied, reproduced, or transmitted without prior written consent of "
+#define SUFFIX "."
+
+       struct aux_hdr_list *aux_hdr_entry;
+       int len;
+       char *company_name = name;
+       char *date_part;
+
+       date_part = (char *) index (name, ',');
+       if (date_part)
+         {
+           *date_part = 0x00;
+           date_part++;
+         }
+
+       len =
+         strlen (PREFIX) +
+         strlen (MIDFIX) +
+         strlen (SUFFIX) +
+         2 * strlen (name);
+
+       if (date_part)
+         {
+           len += strlen (date_part) + strlen (",");
+         }
+
+       aux_hdr_entry = (struct aux_hdr_list *) malloc (sizeof (struct aux_hdr_list));
+       if (aux_hdr_root)
+         {
+           aux_hdr_entry->ahl_next = aux_hdr_root;
+           aux_hdr_root = aux_hdr_entry;
+         }
+       else
+         {
+           aux_hdr_entry->ahl_next = NULL;
+           aux_hdr_root = aux_hdr_entry;
+         }
+       aux_hdr_entry->type = COPYRIGHT_AUX_ID;
+       aux_hdr_entry->contents.cpy.header_id.append = 1;
+       aux_hdr_entry->contents.cpy.header_id.type = COPYRIGHT_AUX_ID;
+       aux_hdr_entry->contents.cpy.header_id.length = len + sizeof (unsigned int);
+       while (aux_hdr_entry->contents.usr_str.header_id.length % 4)
+         aux_hdr_entry->contents.usr_str.header_id.length += 1;
+
+       aux_hdr_entry->contents.cpy.string_length = len;
+       aux_hdr_entry->contents.cpy.copyright = (char *) (malloc (len + 1));
+       strcpy (aux_hdr_entry->contents.cpy.copyright, PREFIX);
+       strcat (aux_hdr_entry->contents.cpy.copyright, name);
+       if (date_part)
+         {
+           strcat (aux_hdr_entry->contents.cpy.copyright, ",");
+           strcat (aux_hdr_entry->contents.cpy.copyright, date_part);
+         }
+       strcat (aux_hdr_entry->contents.cpy.copyright, MIDFIX);
+       strcat (aux_hdr_entry->contents.cpy.copyright, name);
+       strcat (aux_hdr_entry->contents.cpy.copyright, SUFFIX);
+       aux_hdr_entry->contents.cpy.copyright[len] = NULL;
+#undef PREFIX
+#undef MIDFIX
+#undef SUFFIX
+#endif /* OBJ_SOM */
+      }
+      *input_line_pointer = c;
+    }
+  else
+    {
+      as_bad ("Expected \"-ed string");
+    }
+  pa_undefine_label ();
+  demand_empty_rest_of_line ();
+}
+
+void 
+pa_end ()
+{
+
+  demand_empty_rest_of_line ();
+  return;
+}
+
+void 
+pa_enter ()
+{
+
+  as_bad (".ENTER encountered. gas doesn't generate entry code sequences.");
+  pa_entry ();
+  return;
+}
+
+void 
+pa_entry ()
+{
+  char *where;
+
+  if (!within_procedure)
+    as_bad ("Misplaced .entry. Ignored.");
+  else
+    {
+      if (!callinfo_found)
+       as_bad ("Missing .callinfo.");
+
+      last_call_info->start_frag = frag_now;
+    }
+  demand_empty_rest_of_line ();
+  within_entry_exit = TRUE;
+  where = frag_more (0);
+#ifdef OBJ_SOM
+  fix_new (frag_now, where - frag_now->fr_literal, 0,
+          last_call_info->start_symbol, (symbolS *) NULL, 0, 0,
+     R_ENTRY, e_fsel, 0, 0, (char *) &last_call_info->ci_unwind.descriptor);
+#else
+#ifdef OBJ_ELF
+  /* XXX: no ENTRY relocation for PA ELF.  What do we do instead? */
+#else
+  fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
+               last_call_info->start_symbol, (symbolS *) NULL, 0, 0,
+               R_HPPA_ENTRY, 0, 0, 0,
+               (char *) &last_call_info->ci_unwind.descriptor);
+#endif
+#endif
+  return;
+}
+
+void 
+pa_equ (reg)
+     int reg;
+{
+  register label_symbolS *label_symbolP = pa_get_label ();
+  register symbolS *symbolP;
+
+  if (label_symbolP)
+    {
+      symbolP = label_symbolP->lss_label;
+#ifdef OBJ_SOM
+      symbolP->pa_sy_value = get_absolute_expression ();
+      symbolP->pa_sy_type = ST_ABSOLUTE;
+      symbolP->sy_ref = sym_unref;
+      symbolP->sy_equ = 1;
+#else
+      S_SET_VALUE (symbolP, get_absolute_expression ());
+      S_SET_SEGMENT (symbolP, &bfd_abs_section);
+#endif
+    }
+  else
+    {
+      if (reg)
+       as_bad (".REG must use a label");
+      else
+       as_bad (".EQU must use a label");
+    }
+
+  pa_undefine_label ();
+  demand_empty_rest_of_line ();
+  return;
+}
+
+void 
+process_exit ()
+{
+  char *where;
+
+  where = frag_more (0);
+#ifdef OBJ_SOM
+  fix_new (frag_now, where - frag_now->fr_literal, 0,
+          last_call_info->start_symbol, (symbolS *) NULL, 0,
+          0, R_EXIT, e_fsel, 0, 0, (char *) NULL);
+#endif
+#ifdef OBJ_ELF
+  /* XXX: no EXIT relocation for PA ELF.  All we do is create a */
+  /* temporary symbol marking the end of the function. */
+  {
+    char *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));
+
+       symbolP = symbol_find (name);
+       if (symbolP)
+         as_warn ("Symbol '%s' already defined.", name);
+       else
+         {
+           /* symbol value should be the offset of the */
+           /* last instruction of the function */
+           symbolP = symbol_new (name,
+                                 now_seg,
+           (valueT) (obstack_next_free (&frags) - frag_now->fr_literal - 4),
+                                 frag_now);
+
+           assert (symbolP);
+
+           symbolP->bsym->flags = last_call_info->start_symbol->bsym->flags;
+           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.");
+  }
+#else
+  fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
+               last_call_info->start_symbol, (symbolS *) NULL, 0,
+               0, R_HPPA_EXIT, 0, 0, 0, (char *) NULL);
+#endif
+  last_call_info->end_frag = frag_now;
+
+  pa_build_unwind_subspace (last_call_info);
+
+  exit_processing_complete = TRUE;
+}
+
+void 
+pa_exit ()
+{
+
+  if (!within_procedure)
+    as_bad (".EXIT must appear within a procedure");
+  else
+    {
+      if (!callinfo_found)
+       as_bad ("Missing .callinfo");
+      else
+       {
+         if (!within_entry_exit)
+           as_bad ("No .ENTRY for this .EXIT");
+         else
+           {
+             within_entry_exit = FALSE;
+             process_exit ();
+           }
+       }
+    }
+  demand_empty_rest_of_line ();
+  return;
+}
+
+void 
+pa_export ()
+{
+  register char *name;
+  register char c;
+  register char *p;
+  register int temp;
+  register int regno;
+  register symbolS *symbolP;
+
+  name = input_line_pointer;
+  c = get_symbol_end ();
+  /* just after name is now '\0' */
+
+  if ((symbolP = 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
+    {
+#ifdef OBJ_SOM
+      symbolP->pa_sy_dict.symbol_scope = SS_UNIVERSAL;
+      /* determination of the symbol_type field will have to wait until
+        we know the subspace index (within the object file) of the subspace
+        containing this symbol */
+#else
+      /* S_SET_SEGMENT(symbolP,&bfd_und_section); */
+      S_SET_EXTERNAL (symbolP);
+      /* symbolP->sy_frag = frag_now; */
+#endif
+
+      p = input_line_pointer;
+      *p = c;
+      if (!is_end_of_statement ())
+       {
+         input_line_pointer++;
+         pa_export_args (symbolP);
+       }
+    }
+
+  demand_empty_rest_of_line ();
+  return;
+}
+
+void 
+pa_export_args (symbolP)
+     register symbolS *symbolP;
+{
+  register char *name;
+  register char c;
+  register char *p;
+  register int temp;
+  register unsigned int arg_reloc;
+#ifdef OBJ_ELF
+  elf_symbol_type *esymbolP = (elf_symbol_type *) (symbolP->bsym);
+#endif
+
+  if (strncasecmp (input_line_pointer, "absolute", 8) == 0)
+    {
+      input_line_pointer += 8;
+#ifdef OBJ_SOM
+      symbolP->pa_sy_dict.symbol_type = ST_ABSOLUTE;
+#else
+      S_SET_SEGMENT (symbolP, &bfd_abs_section);
+#endif
+    }
+  else if (strncasecmp (input_line_pointer, "code", 4) == 0)
+    {
+      input_line_pointer += 4;
+#ifdef OBJ_SOM
+      symbolP->pa_sy_dict.symbol_type = ST_CODE;
+#else
+      /* S_SET_SEGMENT(symbolP,text_section); */
+#endif
+    }
+  else if (strncasecmp (input_line_pointer, "data", 4) == 0)
+    {
+      input_line_pointer += 4;
+#ifdef OBJ_SOM
+      symbolP->pa_sy_dict.symbol_type = ST_DATA;
+#else
+      /* S_SET_SEGMENT(symbolP,data_section); */
+#endif
+    }
+  else if ((strncasecmp (input_line_pointer, "entry", 5) == 0))
+    {
+      input_line_pointer += 5;
+#ifdef OBJ_SOM
+      symbolP->pa_sy_dict.symbol_type = ST_ENTRY;
+#else
+      symbolP->bsym->flags |= BSF_FUNCTION;
+#endif
+    }
+  else if (strncasecmp (input_line_pointer, "millicode", 9) == 0)
+    {
+      input_line_pointer += 9;
+#ifdef OBJ_SOM
+      symbolP->pa_sy_dict.symbol_type = ST_MILLICODE;
+#endif
+    }
+  else if (strncasecmp (input_line_pointer, "plabel", 6) == 0)
+    {
+      input_line_pointer += 6;
+#ifdef OBJ_SOM
+      symbolP->pa_sy_dict.symbol_type = ST_PLABEL;
+#endif
+    }
+  else if (strncasecmp (input_line_pointer, "pri_prog", 8) == 0)
+    {
+      input_line_pointer += 8;
+#ifdef OBJ_SOM
+      symbolP->pa_sy_dict.symbol_type = ST_PRI_PROG;
+#endif
+    }
+  else if (strncasecmp (input_line_pointer, "sec_prog", 8) == 0)
+    {
+      input_line_pointer += 8;
+#ifdef OBJ_SOM
+      symbolP->pa_sy_dict.symbol_type = ST_SEC_PROG;
+#endif
+    }
+
+  while (!is_end_of_statement ())
+    {
+      if (*input_line_pointer == ',')
+       input_line_pointer++;
+      name = input_line_pointer;
+      c = get_symbol_end ();
+      if ((strncasecmp (name, "argw", 4) == 0))
+       {
+         p = input_line_pointer;
+         *p = c;
+         input_line_pointer++;
+         temp = atoi (name + 4);
+         name = input_line_pointer;
+         c = get_symbol_end ();
+         arg_reloc = pa_align_arg_reloc (temp, pa_build_arg_reloc (name));
+#ifdef OBJ_SOM
+         symbolP->pa_sy_dict.arg_reloc |= arg_reloc;
+#else
+         esymbolP->tc_data.hppa_arg_reloc |= arg_reloc;
+#endif
+         *input_line_pointer = c;
+       }
+      else if ((strncasecmp (name, "rtnval", 6)) == 0)
+       {
+         p = input_line_pointer;
+         *p = c;
+         input_line_pointer++;
+         name = input_line_pointer;
+         c = get_symbol_end ();
+         arg_reloc = pa_build_arg_reloc (name);
+#ifdef OBJ_SOM
+         symbolP->pa_sy_dict.arg_reloc |= arg_reloc;
+#else
+         esymbolP->tc_data.hppa_arg_reloc |= arg_reloc;
+#endif
+         *input_line_pointer = c;
+       }
+      else if ((strncasecmp (name, "priv_lev", 8)) == 0)
+       {
+         p = input_line_pointer;
+         *p = c;
+         input_line_pointer++;
+         /*** temp = get_absolute_expression (); ***/
+         temp = atoi (input_line_pointer);
+         c = get_symbol_end ();
+         *input_line_pointer = c;
+#ifdef OBJ_SOM
+         symbolP->sy_priv_lev = temp & 3;      /* this is stored in symbol_value later */
+#endif
+       }
+      else
+       {
+         as_bad ("Undefined .EXPORT/.IMPORT argument (ignored): %s", name);
+         p = input_line_pointer;
+         *p = c;
+       }
+      if (!is_end_of_statement ())
+       input_line_pointer++;
+    }
+}
+
+void 
+pa_import ()
+{
+  register char *name;
+  register char c;
+  register char *p;
+  register symbolS *symbolP;
+  register expressionS resultP;        /* Deliver result here. */
+
+  name = input_line_pointer;
+  c = get_symbol_end ();
+  /* just after name is now '\0' */
+
+  symbolP = symbol_find_or_make (name);
+#if defined(OBJ_ELF)
+  /* symbolP->bsym->flags |= BSF_IMPORT; *//* XXX BSF_IMPORT is obsolete */
+#else
+  /* Check to see if this symbol has already been exported (this means its */
+  /* defined locally and the import statement is redundant). */
+  /* If it has not been exported, go ahead and mark this symbol as SS_UNSAT */
+  /* (an unsatisfied external symbol) */
+
+  /* But, if the symbol has already been referenced (sy_ref == TRUE),
+       leave it alone. */
+
+  if (!symbolP->sy_ref)
+    {
+      if (symbolP->pa_sy_dict.symbol_scope != SS_UNIVERSAL)
+       {
+         symbolP->pa_sy_dict.symbol_scope = SS_UNSAT;
+         symbolP->sy_ref = FALSE;
+       }
+    }
+#endif
+
+  p = input_line_pointer;
+  *p = c;
+
+  if (!is_end_of_statement ())
+    {
+      input_line_pointer++;
+
+      pa_export_args (symbolP);
+#ifdef OBJ_ELF
+      /* In ELF, since this is an import, leave the section undefined. */
+      /* S_SET_SEGMENT(symbolP,&bfd_und_section); */
+#endif
+    }
+  else
+    {
+#ifdef OBJ_SOM
+      /* no further arguments, assign a default type according
+              to the current subspace (CODE or DATA) */
+      switch (now_seg)
+       {
+       case SEG_TEXT:
+         symbolP->pa_sy_dict.symbol_type = ST_CODE;
+         break;
+       case SEG_ABSOLUTE:
+         symbolP->pa_sy_dict.symbol_type = ST_ABSOLUTE;
+         break;
+       default:
+         symbolP->pa_sy_dict.symbol_type = ST_DATA;
+       }
+#else
+      /* In ELF, if the section is undefined, then the symbol is undefined */
+      /* Since this is an import, leave the section undefined. */
+      S_SET_SEGMENT (symbolP, &bfd_und_section);
+#endif
+    }
+
+
+  demand_empty_rest_of_line ();
+  return;
+}
+
+void 
+pa_label ()
+{
+  register char *name;
+  register char c;
+  register char *p;
+
+  name = input_line_pointer;
+  c = get_symbol_end ();
+  /* just after name is now '\0' */
+
+  if (strlen (name) > 0)
+    {
+      colon (name);
+      p = input_line_pointer;
+      *p = c;
+    }
+  else
+    {
+      as_warn ("Missing label name on .LABEL");
+    }
+
+  if (!is_end_of_statement ())
+    {
+      as_warn ("extra .LABEL arguments ignored.");
+      ignore_rest_of_line ();
+    }
+  demand_empty_rest_of_line ();
+  return;
+}
+
+void 
+pa_leave ()
+{
+
+  as_bad (".LEAVE encountered. gas doesn't generate exit code sequences.");
+  pa_exit ();
+  return;
+}
+
+void 
+pa_origin ()
+{
+  s_org ();                    /* ORG actually allows another argument (the fill value)
+                    but maybe this is OK? */
+  pa_undefine_label ();
+  return;
+}
+
+void 
+pa_proc ()
+{
+  call_infoS *call_info;
+
+  if (within_procedure)
+    as_fatal ("Nested procedures");
+
+  callinfo_found = FALSE;
+  within_procedure = TRUE;
+  exit_processing_complete = FALSE;
+
+  /* create another call_info structure */
+
+  call_info = (call_infoS *) xmalloc (sizeof (call_infoS));
+
+  if (!call_info)
+    as_fatal ("Cannot allocate unwind descriptor\n");
+
+  bzero (call_info, sizeof (call_infoS));
+
+  call_info->ci_next = NULL;
+
+  if (call_info_root == NULL)
+    {
+      call_info_root = call_info;
+      last_call_info = call_info;
+    }
+  else
+    {
+      last_call_info->ci_next = call_info;
+      last_call_info = call_info;
+    }
+
+  /* set up defaults on call_info structure */
+
+  call_info->ci_unwind.descriptor.cannot_unwind = 0;
+  call_info->ci_unwind.descriptor.region_desc = 1;
+  call_info->entry_sr = ~0;
+  call_info->makes_calls = 1;
+  call_info->hpux_int = 0;
+
+  /* If we got a .PROC pseudo-op, we know that the function is defined
+     locally. Make sure it gets into the symbol table */
+  {
+    label_symbolS *label_symbolP = pa_get_label ();
+
+    if (label_symbolP)
+      {
+       if (label_symbolP->lss_label)
+         {
+#ifdef OBJ_SOM
+           label_symbolP->lss_label->sy_ref |= sym_def;
+#endif
+           last_call_info->start_symbol = label_symbolP->lss_label;
+           label_symbolP->lss_label->bsym->flags |= BSF_FUNCTION;
+         }
+       else
+         as_bad ("Missing function name for .PROC (corrupted label)");
+      }
+    else
+      as_bad ("Missing function name for .PROC");
+  }
+
+  demand_empty_rest_of_line ();
+  return;
+}
+
+void 
+pa_procend ()
+{
+
+  if (!within_procedure)
+    as_bad ("misplaced .procend");
+
+  if (!callinfo_found)
+    as_bad ("Missing .callinfo for this procedure");
+
+  if (within_entry_exit)
+    as_bad ("Missing .EXIT for a .ENTRY");
+
+  if (!exit_processing_complete)
+    process_exit ();
+
+  within_procedure = FALSE;
+  demand_empty_rest_of_line ();
+  return;
+}
+
+space_dict_chainS *
+pa_parse_space_stmt (space_name, create_flag)
+     char *space_name;
+     int create_flag;
+{
+  register char *name;
+  register char c;
+  register char *p;
+  register int temp;
+
+  char *ptemp;
+  int spnum;
+  char loadable;
+  char defined;
+  char private;
+  char sort;
+#ifdef OBJ_SOM
+  segT seg;
+#else
+  asection *seg;
+#endif
+  space_dict_chainS *space;
+
+  /* load default values */
+  spnum = 0;
+  loadable = TRUE;
+  defined = TRUE;
+  private = FALSE;
+  if (strcasecmp (space_name, "$TEXT$") == 0)
+    {
+#ifdef OBJ_SOM
+      seg = SEG_TEXT;
+#else
+      seg = text_section;
+#endif
+      sort = 8;
+    }
+  else
+    {
+#ifdef OBJ_SOM
+      seg = SEG_DATA;
+#else
+      seg = data_section;
+#endif
+      sort = 16;
+    }
+
+  if (!is_end_of_statement ())
+    {
+      print_errors = FALSE;
+      ptemp = input_line_pointer + 1;
+      if ((temp = pa_parse_number (&ptemp)) >= 0)
+       {
+         spnum = temp;
+         input_line_pointer = ptemp;
+       }
+      else
+       {
+         while (!is_end_of_statement ())
+           {
+             input_line_pointer++;
+             name = input_line_pointer;
+             c = get_symbol_end ();
+             if ((strncasecmp (name, "SPNUM", 5) == 0))
+               {
+                 p = input_line_pointer;
+                 *p = c;
+                 input_line_pointer++;
+                 temp = get_absolute_expression ();
+                 spnum = temp;
+               }
+             else if ((strncasecmp (name, "SORT", 4) == 0))
+               {
+                 p = input_line_pointer;
+                 *p = c;
+                 input_line_pointer++;
+                 temp = get_absolute_expression ();
+                 sort = temp;
+               }
+             else if ((strncasecmp (name, "UNLOADABLE", 10) == 0))
+               {
+                 p = input_line_pointer;
+                 *p = c;
+                 loadable = FALSE;
+               }
+             else if ((strncasecmp (name, "NOTDEFINED", 10) == 0))
+               {
+                 p = input_line_pointer;
+                 *p = c;
+                 defined = FALSE;
+               }
+             else if ((strncasecmp (name, "PRIVATE", 7) == 0))
+               {
+                 p = input_line_pointer;
+                 *p = c;
+                 private = TRUE;
+               }
+             else
+               {
+                 as_bad ("Unrecognized .SPACE argument");
+                 p = input_line_pointer;
+                 *p = c;
+               }
+           }
+       }
+      print_errors = TRUE;
+    }
+  if (create_flag)
+    space = create_new_space (space_name, spnum, loadable, defined, private, sort, 1, seg);
+  else
+    {                          /* if no creation of new space, this must be the first */
+      /* occurrence of a built-in space */
+      space = is_defined_space (space_name);
+      SPACE_SPNUM (space) = spnum;
+      SPACE_LOADABLE (space) = loadable & 1;
+      SPACE_DEFINED (space) = defined & 1;
+      SPACE_PRIVATE (space) = private & 1;
+      SPACE_SORT (space) = sort & 0xff;
+      space->sd_defined = 1;
+      space->sd_seg = seg;
+    }
+  return space;
+}
+
+void 
+pa_align_subseg (seg, subseg)
+#ifdef OBJ_SOM
+     segT seg;
+#else
+     asection *seg;
+#endif
+     subsegT subseg;
+{
+  subspace_dict_chainS *now_subspace;
+  int alignment;
+  int shift;
+
+  now_subspace = pa_subsegment_to_subspace (seg, subseg);
+  if (SUBSPACE_ALIGN (now_subspace) == 0)
+    alignment = now_subspace->ssd_last_align;
+  else if (now_subspace->ssd_last_align > SUBSPACE_ALIGN (now_subspace))
+    alignment = now_subspace->ssd_last_align;
+  else
+    alignment = SUBSPACE_ALIGN (now_subspace);
+
+  shift = 0;
+  while ((1 << shift) < alignment)
+    shift++;
+
+  frag_align (shift, 0);
+}
+
+void 
+pa_space ()
+{
+  register char *name;
+  register char c;
+  register char *p;
+  register int temp;
+  register symbolS *symbolP;
+  register space_dict_chainS *sd_chain;
+  char space_name[40];
+
+  if (within_procedure)
+    {
+      as_bad ("Can\'t change spaces within a procedure definition. Ignored");
+      ignore_rest_of_line ();
+    }
+  else
+    {
+      if (strncasecmp (input_line_pointer, "$text$", 6) == 0)
+       {
+         input_line_pointer += 6;
+         sd_chain = is_defined_space ("$TEXT$");
+         if (sd_chain == NULL)
+           sd_chain = pa_parse_space_stmt ("$TEXT$", 1);
+         else if (sd_chain->sd_defined == 0)
+           sd_chain = pa_parse_space_stmt ("$TEXT$", 0);
+
+         current_space = sd_chain;
+         SPACE_DEFINED (current_space) = 1;
+         current_space->sd_defined = 1;
+#ifdef OBJ_SOM
+         if (now_seg != SEG_TEXT)      /* no need to align if we are already there */
+#else
+         if (now_seg != text_section)  /* no need to align if we are already there */
+#endif
+           pa_align_subseg (now_seg, now_subseg);
+
+#ifdef OBJ_SOM
+         subseg_new (SEG_TEXT, sd_chain->sd_last_subseg);
+         current_subspace = pa_subsegment_to_subspace (SEG_TEXT,
+                                                 sd_chain->sd_last_subseg);
+#else
+         subseg_new ((char *) text_section->name, sd_chain->sd_last_subseg);
+         current_subspace = pa_subsegment_to_subspace (text_section,
+                                                 sd_chain->sd_last_subseg);
+#endif
+         demand_empty_rest_of_line ();
+         return;
+       }
+      if (strncasecmp (input_line_pointer, "$private$", 9) == 0)
+       {
+         input_line_pointer += 9;
+         sd_chain = is_defined_space ("$PRIVATE$");
+         if (sd_chain == NULL)
+           sd_chain = pa_parse_space_stmt ("$PRIVATE$", 1);
+         else if (sd_chain->sd_defined == 0)
+           sd_chain = pa_parse_space_stmt ("$PRIVATE$", 0);
+
+         current_space = sd_chain;
+         SPACE_DEFINED (current_space) = 1;
+         current_space->sd_defined = 1;
+#ifdef OBJ_SOM
+         if (now_seg != SEG_DATA)      /* no need to align if we are already there */
+#else
+         if (now_seg != data_section)  /* no need to align if we are already there */
+#endif
+           pa_align_subseg (now_seg, now_subseg);
+#ifdef OBJ_SOM
+         subseg_new (SEG_DATA, sd_chain->sd_last_subseg);
+         current_subspace = pa_subsegment_to_subspace (SEG_DATA,
+                                                 sd_chain->sd_last_subseg);
+#else
+         subseg_new ((char *) data_section->name, sd_chain->sd_last_subseg);
+         current_subspace = pa_subsegment_to_subspace (data_section,
+                                                 sd_chain->sd_last_subseg);
+#endif
+         demand_empty_rest_of_line ();
+         return;
+       }
+      if (strncasecmp (input_line_pointer,
+                 GDB_DEBUG_SPACE_NAME, strlen (GDB_DEBUG_SPACE_NAME)) == 0)
+       {
+         input_line_pointer += strlen (GDB_DEBUG_SPACE_NAME);
+         sd_chain = is_defined_space (GDB_DEBUG_SPACE_NAME);
+         if (sd_chain == NULL)
+           sd_chain = pa_parse_space_stmt (GDB_DEBUG_SPACE_NAME, 1);
+         else if (sd_chain->sd_defined == 0)
+           sd_chain = pa_parse_space_stmt (GDB_DEBUG_SPACE_NAME, 0);
+
+         current_space = sd_chain;
+         SPACE_DEFINED (current_space) = 1;
+         current_space->sd_defined = 1;
+#ifdef OBJ_SOM
+         if (now_seg != SEG_GDB)       /* no need to align if we are already there */
+           pa_align_subseg (now_seg, now_subseg);
+         subseg_new (SEG_GDB, sd_chain->sd_last_subseg);
+         current_subspace = pa_subsegment_to_subspace (SEG_GDB,
+                                                 sd_chain->sd_last_subseg);
+#else
+         if (now_seg != gdb_section)   /* no need to align if we are already there */
+           pa_align_subseg (now_seg, now_subseg);
+         subseg_new ((char *) gdb_section->name, sd_chain->sd_last_subseg);
+         current_subspace = pa_subsegment_to_subspace (gdb_section,
+                                                 sd_chain->sd_last_subseg);
+#endif
+         demand_empty_rest_of_line ();
+         return;
+       }
+
+      /* it could be a space specified by number */
+
+      if ((temp = pa_parse_number (&input_line_pointer)) >= 0)
+       {
+         if (sd_chain = pa_find_space_by_number (temp))
+           {
+             current_space = sd_chain;
+             SPACE_DEFINED (current_space) = 1;
+             current_space->sd_defined = 1;
+             if (now_seg != sd_chain->sd_seg)  /* don't align if we're already there */
+               pa_align_subseg (now_seg, now_subseg);
+#ifdef OBJ_SOM
+             subseg_new (sd_chain->sd_seg, sd_chain->sd_last_subseg);
+#else
+             subseg_new ((char *) sd_chain->sd_seg->name, sd_chain->sd_last_subseg);
+#endif
+             current_subspace = pa_subsegment_to_subspace (sd_chain->sd_seg,
+                                                 sd_chain->sd_last_subseg);
+             demand_empty_rest_of_line ();
+             return;
+           }
+       }
+
+      /* not a number, attempt to create a new space */
+
+      name = input_line_pointer;
+      c = get_symbol_end ();
+      space_name[0] = 0x00;
+      strcpy (space_name, name);
+      *input_line_pointer = c;
+
+      sd_chain = pa_parse_space_stmt (space_name, 1);
+      current_space = sd_chain;
+      SPACE_DEFINED (current_space) = 1;
+      current_space->sd_defined = 1;
+      if (now_seg != sd_chain->sd_seg) /* don't align if we're already there */
+       pa_align_subseg (now_seg, now_subseg);
+#ifdef OBJ_SOM
+      subseg_new (sd_chain->sd_seg, sd_chain->sd_last_subseg);
+#else
+      subseg_new ((char *) sd_chain->sd_seg->name, sd_chain->sd_last_subseg);
+#endif
+      current_subspace = pa_subsegment_to_subspace (sd_chain->sd_seg,
+                                                 sd_chain->sd_last_subseg);
+      demand_empty_rest_of_line ();
+    }
+  return;
+}
+
+void 
+pa_spnum ()
+{
+  register char *name;
+  register char c;
+  register char *p;
+  space_dict_chainS *space;
+
+  name = input_line_pointer;
+  c = get_symbol_end ();
+  space = is_defined_space (name);
+  if (space)
+    {
+      p = frag_more (4);
+      /* put bytes in right order. */
+      md_number_to_chars (p, SPACE_SPNUM (space), 4);
+    }
+  else
+    as_warn ("Undefined space: '%s' Assuming space number = 0.", name);
+
+  *input_line_pointer = c;
+  demand_empty_rest_of_line ();
+  return;
+}
+
+static
+int 
+is_power_of_2 (value)
+     int value;
+{
+  int shift;
+
+  shift = 0;
+  while ((1 << shift) != value && shift < 32)
+    shift++;
+
+  if (shift >= 32)
+    shift = 0;
+  return shift;
+}
+
+void 
+pa_subspace ()
+{
+  register char *name;
+  register char c;
+  register char *p;
+  register int temp;
+  register symbolS *symbolP;
+
+  char loadable, code_only, common, dup_common, zero;
+  char sort;
+  int number;
+  int i;
+  int access;
+  int space_index;
+  int alignment;
+  int quadrant;
+  int subseg;
+  space_dict_chainS *space;
+  subspace_dict_chainS *ssd;
+  subspace_dict_chainS *ssdCh;
+  char *ss_name;
+  int is_power_of_2 ();
+
+  if (within_procedure)
+    {
+      as_bad ("Can\'t change subspaces within a procedure definition. Ignored");
+      ignore_rest_of_line ();
+    }
+  else
+    {
+      name = input_line_pointer;
+      c = get_symbol_end ();
+      space = pa_segment_to_space (now_seg);
+      ssd = is_defined_subspace (name, space->sd_last_subseg);
+
+      ss_name = xmalloc (strlen (name) + 1);
+      strcpy (ss_name, name);
+
+      *input_line_pointer = c;
+
+      /* load default values */
+      sort = 0;
+      access = 0x7f;
+      loadable = 1;
+      common = 0;
+      dup_common = 0;
+      code_only = 0;
+      zero = 0;
+      space_index = ~0;                /* filled in when the .o file is written */
+      alignment = 0;           /* alignment=0 means no ALIGN= appeared on the .SUBSPA */
+      /* pseudo-op. The default will be the largest .ALIGN */
+      /* encountered (or 1 if no .ALIGN is encountered) */
+      quadrant = 0;
+
+      if (ssd)
+       {
+         if (ssd->ssd_defined)
+           {
+#ifdef OBJ_SOM
+             subseg_new (now_seg, ssd->ssd_subseg);
+#else
+             /* subseg_new(now_seg->name,ssd->ssd_subseg); */
+             subseg_new ((char *) ssd->ssd_seg->name, ssd->ssd_subseg);
+#endif
+             if (!is_end_of_statement ())
+               {
+                 as_warn ("Parameters of an existing subspace can\'t be modified");
+               }
+             demand_empty_rest_of_line ();
+             return;
+           }
+         else
+           {
+             ssd->ssd_defined = 1;
+           }
+       }
+      else
+       {
+         /* a new subspace */
+         /* load default values */
+         i = 0;
+         while (pa_def_subspaces[i].name)
+           {
+             if (strcasecmp (pa_def_subspaces[i].name, ss_name) == 0)
+               {
+                 loadable = pa_def_subspaces[i].loadable;
+                 common = pa_def_subspaces[i].common;
+                 dup_common = pa_def_subspaces[i].dup_common;
+                 code_only = pa_def_subspaces[i].code_only;
+                 zero = pa_def_subspaces[i].zero;
+                 space_index = pa_def_subspaces[i].space_index;
+                 /* alignment = pa_def_subspaces[i].alignment; */
+                 alignment = 0;
+                 quadrant = pa_def_subspaces[i].quadrant;
+                 access = pa_def_subspaces[i].access;
+                 sort = pa_def_subspaces[i].sort;
+                 break;
+               }
+             i++;
+           }
+       }
+
+      if (!is_end_of_statement ())
+       {
+         input_line_pointer++;
+         while (!is_end_of_statement ())
+           {
+             name = input_line_pointer;
+             c = get_symbol_end ();
+             if ((strncasecmp (name, "QUAD", 4) == 0))
+               {
+                 *input_line_pointer = c;
+                 input_line_pointer++;
+                 temp = get_absolute_expression ();
+                 quadrant = temp;
+               }
+             else if ((strncasecmp (name, "ALIGN", 5) == 0))
+               {
+                 *input_line_pointer = c;
+                 input_line_pointer++;
+                 temp = get_absolute_expression ();
+                 alignment = temp;
+                 if (!is_power_of_2 (alignment))
+                   {
+                     as_bad ("Alignment must be a power of 2");
+                     alignment = 1;
+                   }
+               }
+             else if ((strncasecmp (name, "ACCESS", 6) == 0))
+               {
+                 *input_line_pointer = c;
+                 input_line_pointer++;
+                 temp = get_absolute_expression ();
+                 access = temp;
+               }
+             else if ((strncasecmp (name, "SORT", 4) == 0))
+               {
+                 *input_line_pointer = c;
+                 input_line_pointer++;
+                 temp = get_absolute_expression ();
+                 sort = temp;
+               }
+             else if ((strncasecmp (name, "CODE_ONLY", 9) == 0))
+               {
+                 *input_line_pointer = c;
+                 code_only = 1;
+               }
+             else if ((strncasecmp (name, "UNLOADABLE", 10) == 0))
+               {
+                 *input_line_pointer = c;
+                 loadable = 0;
+               }
+             else if ((strncasecmp (name, "COMMON", 6) == 0))
+               {
+                 *input_line_pointer = c;
+                 common = 1;
+               }
+             else if ((strncasecmp (name, "DUP_COMM", 8) == 0))
+               {
+                 *input_line_pointer = c;
+                 dup_common = 1;
+               }
+             else if ((strncasecmp (name, "ZERO", 4) == 0))
+               {
+                 *input_line_pointer = c;
+                 zero = 1;
+               }
+             else
+               {
+                 as_bad ("Unrecognized .SUBSPACE argument");
+               }
+             if (!is_end_of_statement ())
+               input_line_pointer++;
+           }
+       }
+      space = pa_segment_to_space (now_seg);
+      if (ssd)
+       {
+         current_subspace = update_subspace (ss_name, 1, loadable, code_only,
+                                    common, dup_common, sort, zero, access,
+                                          space_index, alignment, quadrant,
+                                             ssd->ssd_subseg);
+       }
+      else
+       {
+         current_subspace = create_new_subspace (space, ss_name, 1, loadable, code_only,
+                                            common, dup_common, zero, sort,
+                                            access, space_index, alignment,
+                                                 quadrant, now_seg);
+       }
+      SUBSPACE_SUBSPACE_START (current_subspace) = pa_subspace_start (space, quadrant);
+
+      demand_empty_rest_of_line ();
+#ifdef OBJ_SOM
+      subseg_new (current_subspace->ssd_seg, current_subspace->ssd_subseg);
+#else
+      subseg_new ((char *) current_subspace->ssd_seg->name, current_subspace->ssd_subseg);
+#endif
+    }
+  return;
+}
+
+/* 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 one of two possible        */
+/* ways:                                                               */
+
+/*     1. call_info->start_frag->fr_fix has the size of the fragment.  */
+/*        This approach assumes that the function was built into a     */
+/*        single fragment.  This works for most cases, but might fail. */
+/*        For example, if there was a segment change in the middle of  */
+/*        the function.                                                */
+
+/*     2. The st_size field is the difference in the addresses of the  */
+/*        call_info->start_frag->fr_address field and the fr_address   */
+/*        field of the next fragment with fr_type == rs_fill and       */
+/*        fr_fix != 0.                                                 */
+
+void 
+elf_hppa_final_processing_hook ()
+{
+  extern call_infoS *call_info_root;
+
+  call_infoS *ciP;
+
+  for (ciP = call_info_root; ciP; ciP = ciP->ci_next)
+    {
+      elf_symbol_type *esym = (elf_symbol_type *) ciP->start_symbol->bsym;
+      esym->internal_elf_sym.st_size =
+       ciP->end_symbol->bsym->value
+       - ciP->start_symbol->bsym->value + 4;
+    }
+}
+
+/* pa-spaces.c -- Space/subspace support for the HP PA-RISC version of GAS */
+
+/* for space, subspace, and symbol maintenance on HP 9000 Series 800 */
+
+space_dict_chainS *space_dict_root;
+space_dict_chainS *space_dict_last;
+
+space_dict_chainS *current_space;
+subspace_dict_chainS *current_subspace;
+
+extern symbolS *start_symbol_root;
+extern symbolS *start_symbol_last;
+
+void 
+pa_spaces_begin ()
+{
+  space_dict_chainS *space;
+  int i;
+  subsegT now_subseg = now_subseg;
+
+  space_dict_root = NULL;
+  space_dict_last = NULL;
+
+  start_symbol_root = NULL;
+  start_symbol_last = NULL;
+
+  /* create default space and subspace dictionaries */
+
+  i = 0;
+  while (pa_def_spaces[i].name)
+    {
+      if (pa_def_spaces[i].alias)
+       pa_def_spaces[i].segment = subseg_new (pa_def_spaces[i].alias, 0);
+      else
+       pa_def_spaces[i].segment = bfd_make_section_old_way (stdoutput, pa_def_spaces[i].name);
+
+      create_new_space (pa_def_spaces[i].name, pa_def_spaces[i].spnum,
+                       pa_def_spaces[i].loadable, pa_def_spaces[i].defined,
+                       pa_def_spaces[i].private, pa_def_spaces[i].sort, 0,
+                       pa_def_spaces[i].segment);
+      i++;
+    }
+
+  i = 0;
+  while (pa_def_subspaces[i].name)
+    {
+      space = pa_segment_to_space (pa_def_spaces[pa_def_subspaces[i].def_space_index].segment);
+      if (space)
+       {
+         char *name = pa_def_subspaces[i].alias;
+         if (!name)
+           name = pa_def_subspaces[i].name;
+         create_new_subspace (space, name,
+                              pa_def_subspaces[i].defined,
+                              pa_def_subspaces[i].loadable,
+                 pa_def_subspaces[i].code_only, pa_def_subspaces[i].common,
+                  pa_def_subspaces[i].dup_common, pa_def_subspaces[i].zero,
+                      pa_def_subspaces[i].sort, pa_def_subspaces[i].access,
+                              pa_def_subspaces[i].space_index,
+                              pa_def_subspaces[i].alignment,
+                              pa_def_subspaces[i].quadrant,
+               pa_def_spaces[pa_def_subspaces[i].def_space_index].segment);
+         subseg_new (name, pa_def_subspaces[i].subsegment);
+       }
+      else
+       as_fatal ("Internal error: space missing for subspace \"%s\"\n",
+                 pa_def_subspaces[i].name);
+      i++;
+    }
+}
+
+space_dict_chainS *
+create_new_space (name, spnum, loadable, defined, private, sort, defined_in_file, seg)
+     char *name;
+     int spnum;
+     char loadable;
+     char defined;
+     char private;
+     char sort;
+     char defined_in_file;
+     asection *seg;
+
+{
+  Elf_Internal_Shdr *new_space;
+  space_dict_chainS *chain_entry;
+
+  new_space = (Elf_Internal_Shdr *) xmalloc (sizeof (Elf_Internal_Shdr));
+  if (!new_space)
+    as_fatal ("Out of memory: could not allocate new Elf_Internal_Shdr: %s\n", name);
+
+  /*
+  new_space->space_number = spnum;
+  new_space->is_loadable = loadable & 1;
+  new_space->is_defined = defined & 1;
+  new_space->is_private = private & 1;
+  new_space->sort_key = sort & 0xff;
+
+  new_space->loader_fix_index = ~0;
+  new_space->loader_fix_quantity = 0;
+  new_space->init_pointer_index = ~0;
+  new_space->init_pointer_quantity = 0;
+  new_space->subspace_quantity = 0;
+  */
+
+  chain_entry = (space_dict_chainS *) xmalloc (sizeof (space_dict_chainS));
+  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);
+  strcpy (SPACE_NAME (chain_entry), name);
+
+  chain_entry->sd_entry = new_space;
+  chain_entry->sd_defined = defined_in_file;
+  chain_entry->sd_seg = seg;
+  chain_entry->sd_last_subseg = -1;
+  chain_entry->sd_next = NULL;
+
+  SPACE_SPNUM (chain_entry) = spnum;
+  SPACE_LOADABLE (chain_entry) = loadable & 1;
+  SPACE_DEFINED (chain_entry) = defined & 1;
+  SPACE_PRIVATE (chain_entry) = private & 1;
+  SPACE_SORT (chain_entry) = sort & 0xff;
+
+  /* find spot for the new space based on its sort key */
+
+  if (!space_dict_last)
+    space_dict_last = chain_entry;
+
+  if (space_dict_root == NULL) /* if root is null, it is very easy */
+    space_dict_root = chain_entry;
+  else
+    {
+      space_dict_chainS *sdcP;
+      space_dict_chainS *last_sdcP;
+
+      sdcP = space_dict_root;
+      last_sdcP = NULL;
+
+      while (sdcP)
+       {
+         if (SPACE_SORT (sdcP) < SPACE_SORT (chain_entry))
+           {
+             last_sdcP = sdcP;
+             sdcP = sdcP->sd_next;
+           }
+         else if (SPACE_SORT (sdcP) == SPACE_SORT (chain_entry))
+           {
+             last_sdcP = sdcP;
+             sdcP = sdcP->sd_next;
+           }
+         else if (SPACE_SORT (sdcP) > SPACE_SORT (chain_entry))
+           {
+             break;
+           }
+       }
+
+      if (last_sdcP)
+       {
+         chain_entry->sd_next = sdcP;
+         last_sdcP->sd_next = chain_entry;
+       }
+      else
+       {
+         space_dict_root = chain_entry;
+         chain_entry->sd_next = sdcP;
+       }
+
+      if (chain_entry->sd_next == NULL)
+       space_dict_last = chain_entry;
+    }
+
+  return chain_entry;
+}
+
+subspace_dict_chainS
+* create_new_subspace (space, name, defined, loadable, code_only, common, dup_common,
+              is_zero, sort, access, space_index, alignment, quadrant, seg)
+     space_dict_chainS *space;
+     char *name;
+     char defined, loadable, code_only, common, dup_common, is_zero;
+     char sort;
+     int access;
+     int space_index;
+     int alignment;
+     int quadrant;
+     asection *seg;
+{
+  Elf_Internal_Shdr *new_subspace;
+  subspace_dict_chainS *chain_entry;
+  symbolS *start_symbol;
+
+  new_subspace = (Elf_Internal_Shdr *) xmalloc (sizeof (Elf_Internal_Shdr));
+  if (!new_subspace)
+    as_fatal ("Out of memory: could not allocate new Elf_Internal_Shdr: %s\n",
+             name);
+
+  /*
+  new_subspace->space_index = space_index;
+  new_subspace->fixup_request_index = ~0;
+  */
+
+  chain_entry = (subspace_dict_chainS *) xmalloc (sizeof (subspace_dict_chainS));
+  if (!chain_entry)
+    as_fatal ("Out of memory: could not allocate new subspace chain entry: %s\n", name);
+
+  chain_entry->ssd_entry = new_subspace;
+  SUBSPACE_NAME (chain_entry) = (char *) xmalloc (strlen (name) + 1);
+  strcpy (SUBSPACE_NAME (chain_entry), name);
+
+  SUBSPACE_ACCESS (chain_entry) = access & 0x7f;
+  SUBSPACE_LOADABLE (chain_entry) = loadable & 1;
+  SUBSPACE_COMMON (chain_entry) = common & 1;
+  SUBSPACE_DUP_COMM (chain_entry) = dup_common & 1;
+  SUBSPACE_SORT (chain_entry) = sort & 0xff;
+  SET_SUBSPACE_CODE_ONLY (chain_entry, code_only & 1);
+  SUBSPACE_ALIGN (chain_entry) = alignment & 0xffff;
+  SUBSPACE_QUADRANT (chain_entry) = quadrant & 0x3;
+  SUBSPACE_SUBSPACE_START (chain_entry) = pa_subspace_start (space, quadrant);
+
+  chain_entry->ssd_defined = defined;
+  chain_entry->ssd_space_number = space_index;
+  chain_entry->ssd_subseg = pa_next_subseg (space);
+  chain_entry->ssd_seg = seg;
+  SUBSPACE_ZERO (chain_entry) = is_zero;
+  chain_entry->ssd_last_align = 1;
+  chain_entry->ssd_next = NULL;
+
+  /* find spot for the new subspace based on its sort key */
+
+  if (space->sd_subspaces == NULL)     /* if root is null, it is very easy */
+    space->sd_subspaces = chain_entry;
+  else
+    {
+      subspace_dict_chainS *ssdcP;
+      subspace_dict_chainS *last_ssdcP;
+
+      ssdcP = space->sd_subspaces;
+      last_ssdcP = NULL;
+
+      while (ssdcP)
+       {
+         if (SUBSPACE_SORT (ssdcP) < SUBSPACE_SORT (chain_entry))
+           {
+             last_ssdcP = ssdcP;
+             ssdcP = ssdcP->ssd_next;
+           }
+         else if (SUBSPACE_SORT (ssdcP) == SUBSPACE_SORT (chain_entry))
+           {
+             last_ssdcP = ssdcP;
+             ssdcP = ssdcP->ssd_next;
+           }
+         else if (SUBSPACE_SORT (ssdcP) > SUBSPACE_SORT (chain_entry))
+           {
+             break;
+           }
+       }
+
+      if (last_ssdcP)
+       {
+         chain_entry->ssd_next = ssdcP;
+         last_ssdcP->ssd_next = chain_entry;
+       }
+      else
+       {
+         space->sd_subspaces = chain_entry;
+         chain_entry->ssd_next = ssdcP;
+       }
+    }
+
+  start_symbol = pa_set_start_symbol (seg, space->sd_last_subseg);
+  chain_entry->ssd_start_sym = start_symbol;
+  return chain_entry;
+
+}
+
+subspace_dict_chainS
+* update_subspace (name, defined, loadable, code_only, common, dup_common, sort, zero,
+                  access, space_index, alignment, quadrant, subseg)
+     char *name;
+     char defined, loadable, code_only, common, dup_common, zero;
+     char sort;
+     int access;
+     int space_index;
+     int alignment;
+     int quadrant;
+     subsegT subseg;
+{
+  subspace_dict_chainS *chain_entry;
+  subspace_dict_chainS *is_defined_subspace ();
+
+  if ((chain_entry = is_defined_subspace (name, subseg)))
+    {
+
+      SUBSPACE_ACCESS (chain_entry) = access & 0x7f;
+      SUBSPACE_LOADABLE (chain_entry) = loadable & 1;
+      SUBSPACE_COMMON (chain_entry) = common & 1;
+      SUBSPACE_DUP_COMM (chain_entry) = dup_common & 1;
+      SET_SUBSPACE_CODE_ONLY (chain_entry, code_only & 1);
+      SUBSPACE_SORT (chain_entry) = sort & 0xff;
+      /* chain_entry->ssd_entry->space_index = space_index; */
+      SUBSPACE_ALIGN (chain_entry) = alignment & 0xffff;
+      SUBSPACE_QUADRANT (chain_entry) = quadrant & 0x3;
+
+      chain_entry->ssd_defined = defined;
+      chain_entry->ssd_space_number = space_index;
+      SUBSPACE_ZERO (chain_entry) = zero;
+    }
+  else
+    chain_entry = NULL;
+
+  return chain_entry;
+
+}
+
+space_dict_chainS *
+is_defined_space (name)
+     char *name;
+{
+  space_dict_chainS *spaceCh;
+
+  for (spaceCh = space_dict_root; spaceCh; spaceCh = spaceCh->sd_next)
+    {
+      if (strcmp (SPACE_NAME (spaceCh), name) == 0)
+       {
+         return spaceCh;
+       }
+    }
+
+  return NULL;
+}
+
+space_dict_chainS *
+pa_segment_to_space (seg)
+     asection *seg;
+{
+  space_dict_chainS *spaceCh;
+
+  for (spaceCh = space_dict_root; spaceCh; spaceCh = spaceCh->sd_next)
+    {
+      if (spaceCh->sd_seg == seg)
+       {
+         return spaceCh;
+       }
+    }
+
+  return NULL;
+}
+
+subspace_dict_chainS *
+is_defined_subspace (name, subseg)
+     char *name;
+     subsegT subseg;
+{
+  space_dict_chainS *spaceCh;
+  subspace_dict_chainS *subspCh;
+
+  for (spaceCh = space_dict_root; spaceCh; spaceCh = spaceCh->sd_next)
+    {
+      for (subspCh = spaceCh->sd_subspaces; subspCh; subspCh = subspCh->ssd_next)
+       {
+         /*
+       if ( strcmp(SUBSPACE_NAME(subspCh),name) == 0 &&
+           subspCh->ssd_subseg == subseg ) {
+       */
+         if (strcmp (SUBSPACE_NAME (subspCh), name) == 0)
+           {
+             return subspCh;
+           }
+       }
+    }
+  return NULL;
+}
+
+subspace_dict_chainS *
+pa_subsegment_to_subspace (seg, subseg)
+     asection *seg;
+     subsegT subseg;
+{
+  space_dict_chainS *spaceCh;
+  subspace_dict_chainS *subspCh;
+
+  for (spaceCh = space_dict_root; spaceCh; spaceCh = spaceCh->sd_next)
+    {
+      if (spaceCh->sd_seg == seg)
+       {
+         for (subspCh = spaceCh->sd_subspaces; subspCh; subspCh = subspCh->ssd_next)
+           {
+             if (subspCh->ssd_subseg == (int) subseg)
+               {
+                 return subspCh;
+               }
+           }
+       }
+    }
+
+  return NULL;
+}
+
+space_dict_chainS *
+pa_find_space_by_number (number)
+     int number;
+{
+  space_dict_chainS *spaceCh;
+
+  for (spaceCh = space_dict_root; spaceCh; spaceCh = spaceCh->sd_next)
+    {
+      if (SPACE_SPNUM (spaceCh) == number)
+       {
+         return spaceCh;
+       }
+    }
+
+  return NULL;
+}
+
+unsigned int 
+pa_subspace_start (space, quadrant)
+     space_dict_chainS *space;
+     int quadrant;
+{
+  if ((strcasecmp (SPACE_NAME (space), "$PRIVATE$") == 0) &&
+      quadrant == 1)
+    {
+      return 0x40000000;
+    }
+  else if (space->sd_seg == data_section && quadrant == 1)
+    {                          /* in case name is */
+      /* already converted */
+      /* to a space dict- */
+      /* ionary index */
+      return 0x40000000;
+    }
+  else
+    return 0;
+}
+
+int 
+pa_next_subseg (space)
+     space_dict_chainS *space;
+{
+
+  space->sd_last_subseg++;
+  return space->sd_last_subseg;
+}
+
+int 
+is_last_defined_subspace (ssd)
+     subspace_dict_chainS *ssd;
+{
+
+  for (; ssd; ssd = ssd->ssd_next)
+    {
+      if (ssd->ssd_defined)
+       return FALSE;
+    }
+
+  return TRUE;
+}
+
+symbolS *
+pa_get_start_symbol (seg, subseg)
+     asection *seg;
+     subsegT subseg;
+{
+  symbolS *start_symbol;
+  subspace_dict_chainS *ssd;
+
+  start_symbol = NULL;
+
+  /* each time a new space is created, build a symbol called LS$START_seg_subseg$ */
+  /* where <space-name> is the name of the space */
+  /* the start symbol will be SS_LOCAL and ST_CODE */
+
+  if (seg == bfd_make_section_old_way (stdoutput, ".text") ||
+      seg == bfd_make_section_old_way (stdoutput, ".data") ||
+      seg == bfd_make_section_old_way (stdoutput, GDB_DEBUG_SPACE_NAME))
+    {
+      ssd = pa_subsegment_to_subspace (seg, subseg);
+      if (ssd)
+       {
+         start_symbol = ssd->ssd_start_sym;
+       }
+      else
+       as_fatal ("Internal error: missing subspace for (seg,subseg)=('%s',%d)",
+                 seg->name, subseg);
+    }
+  else
+    as_fatal ("Internal error: attempt to find start symbol for unloadable segment: '%s'",
+             seg->name);
+
+  return start_symbol;
+}
+
+/*
+  Function to define a symbol whose address is the beginning of a subspace.
+  This function assumes the symbol is to be defined for the current subspace.
+ */
+
+symbolS *
+pa_set_start_symbol (seg, subseg)
+     asection *seg;
+     subsegT subseg;
+{
+  symbolS *start_symbol;
+  subspace_dict_chainS *ssd;
+  char *symbol_name;
+
+  symbol_name = (char *) xmalloc (strlen ("LS$START__000000$") + strlen (seg->name) + 1);
+
+  sprintf (symbol_name, "LS$START_%s_%03d$", seg->name, subseg);
+
+  start_symbol
+    = symbol_new (symbol_name, seg, 0, frag_now);      /* XXX: not sure if value s.b. 0 or frag s.b. NULL */
+
+  start_symbol->bsym->flags = BSF_LOCAL;       /* XXX: isn't there a macro defined for this? */
+
+  /* each time a new space is created, build a symbol called LS$START_seg_subseg$ */
+  /* where <space-name> is the name of the space */
+  /* the start symbol will be SS_LOCAL and ST_CODE */
+  /* This function assumes that (seg,subseg) is a new subsegment(subspace) */
+
+  if (seg == bfd_make_section_old_way (stdoutput, ".text") ||
+      seg == bfd_make_section_old_way (stdoutput, ".data") ||
+      seg == bfd_make_section_old_way (stdoutput, GDB_DEBUG_SPACE_NAME))
+    {
+      ssd = pa_subsegment_to_subspace (seg, subseg);
+      if (ssd)
+       {
+         ssd->ssd_start_sym = start_symbol;
+       }
+      else
+       as_fatal ("Internal error: missing subspace for (seg,subseg)=('%s',%d)",
+                 seg, subseg);
+    }
+  else
+    as_fatal ("Internal error: attempt to define start symbol for unloadable segment: '%s'",
+             seg->name);
+
+  return start_symbol;
+}
+
+static unsigned int
+pa_stringer_aux (s)
+     char *s;
+{
+  unsigned int c = *s & CHAR_MASK;
+  switch (c)
+    {
+    case '\"':
+      c = NOT_A_CHAR;
+      break;
+    default:
+      break;
+    }
+  return c;
+}
+
+void
+pa_stringer (append_zero)      /* Worker to do .ascii etc statements. */
+     /* Checks end-of-line. */
+     register int append_zero; /* 0: don't append '\0', else 1 */
+{
+  char *s;
+  unsigned int c;
+  char num_buf[4];
+  int i;
+
+  /* Preprocess the string to handle PA-specific escape sequences.     */
+  /* For example, \xDD where DD is a hexidecimal number should be      */
+  /* changed to \OOO where OOO is an octal number.                     */
+
+  s = input_line_pointer + 1;  /* skip the opening quote */
+
+  while (is_a_char (c = pa_stringer_aux (s++)))
+    {
+      if (c == '\\')
+       {
+         c = *s;
+         switch (c)
+           {
+           case 'x':
+             {
+               unsigned int number;
+               int num_digit;
+               char dg;
+               char *s_start = s;
+
+               s++;            /* get past the 'x' */
+               for (num_digit = 0, number = 0, dg = *s;
+                    num_digit < 2
+                    && (isdigit (dg) || (dg >= 'a' && dg <= 'f')
+                        || (dg >= 'A' && dg <= 'F'));
+                    num_digit++)
+                 {
+                   if (isdigit (dg))
+                     number = number * 16 + dg - '0';
+                   else if (dg >= 'a' && dg <= 'f')
+                     number = number * 16 + dg - 'a' + 10;
+                   else
+                     number = number * 16 + dg - 'A' + 10;
+
+                   s++;
+                   dg = *s;
+                 }
+               if (num_digit > 0)
+                 {
+                   switch (num_digit)
+                     {
+                     case 1:
+                       sprintf (num_buf, "%02o", number);
+                       break;
+                     case 2:
+                       sprintf (num_buf, "%03o", number);
+                       break;
+                     }
+                   for (i = 0; i <= num_digit; i++)
+                     s_start[i] = num_buf[i];
+                 }
+             }
+             break;
+           }
+       }
+    }
+  stringer (append_zero);
+  pa_undefine_label ();
+}
+
+void
+pa_version ()
+{
+#ifdef OBJ_ELF
+  obj_elf_version ();
+#endif
+  pa_undefine_label ();
+}
+
+void
+pa_cons (nbytes)
+     register unsigned int nbytes;     /* 1=.byte, 2=.word, 4=.long */
+{
+  cons (nbytes);
+  pa_undefine_label ();
+}
+
+void
+pa_data ()
+{
+  s_data ();
+  pa_undefine_label ();
+}
+
+void
+pa_desc ()
+{
+
+#ifdef OBJ_ELF
+  obj_elf_desc ();
+#endif
+  pa_undefine_label ();
+}
+
+void
+pa_float_cons (float_type)
+     register int float_type;  /* 'f':.ffloat ... 'F':.float ... */
+{
+  float_cons (float_type);
+  pa_undefine_label ();
+}
+
+void
+pa_fill ()
+{
+  s_fill ();
+  pa_undefine_label ();
+}
+
+void
+pa_lcomm (needs_align)
+     /* 1 if this was a ".bss" directive, which may require a 3rd argument
+       (alignment); 0 if it was an ".lcomm" (2 args only)  */
+     int needs_align;
+{
+  s_lcomm (needs_align);
+  pa_undefine_label ();
+}
+
+void
+pa_lsym ()
+{
+  s_lsym ();
+  pa_undefine_label ();
+}
+
+void
+pa_big_cons (nbytes)
+     register int nbytes;
+{
+  big_cons (nbytes);
+  pa_undefine_label ();
+}
+
+void
+pa_text ()
+{
+  s_text ();
+  pa_undefine_label ();
+}
index a61ccd0766520b7e165c9ed775e088aa9ea49c7f..3774d935c1f219c2e7438a9e92c1842d0af2121d 100644 (file)
@@ -2161,7 +2161,7 @@ const int md_reloc_size = 8;      /* Size of relocation record */
 void
 md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
      char *ptr;
-     valueT from_addr, to_addr;
+     addressT from_addr, to_addr;
      fragS *frag;
      symbolS *to_symbol;
 {
@@ -2175,7 +2175,7 @@ md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
 void
 md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
      char *ptr;
-     valueT from_addr, to_addr;
+     addressT from_addr, to_addr;
      fragS *frag;
      symbolS *to_symbol;
 {
index abd53c82a4339c091f3d5dca2865511fa1c0510a..b103dcb200557655f9919de80e8c53469a726fc4 100644 (file)
@@ -1,18 +1,18 @@
 /* tc-i860.c -- Assemble for the I860
    Copyright (C) 1989, 1992 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
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
-   
+
    GAS is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with GAS; see the file COPYING.  If not, write to
    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "opcode/i860.h"
 
-/* incorporated from i860.h */
-enum reloc_type /* NOTE: three bits max, see struct reloc_info_i860.r_type */
-{
-       NO_RELOC = 0, BRADDR, LOW0, LOW1, LOW2, LOW3, LOW4, SPLIT0, SPLIT1, SPLIT2, RELOC_32,
-};
-
-enum highlow_type       /* NOTE: two bits max, see reloc_info_i860.r_type */
-{
-       NO_SPEC = 0, PAIR, HIGH, HIGHADJ,
-};
-
-struct reloc_info_i860
-{
-       unsigned long r_address;
-       /*
-        * Using bit fields here is a bad idea because the order is not portable. :-(
-        */
-       unsigned int r_symbolnum: 24;
-       unsigned int r_pcrel    : 1;
-       unsigned int r_extern   : 1;
-       /* combining the two field simplifies the argument passing in "new_fix()" */
-       /* and is compatible with the existing Sparc #ifdef's */
-       /* r_type:  highlow_type - bits 5,4; reloc_type - bits 3-0 */
-       unsigned int r_type     : 6;
-       long r_addend;
-};
-
-#define relocation_info reloc_info_i860
-
-
-void md_begin();
-void md_end();
-void md_number_to_chars();
-void md_assemble();
-char *md_atof();
-void md_convert_frag();
-void md_create_short_jump();
-void md_create_long_jump();
-int  md_estimate_size_before_relax();
-void md_number_to_imm();
-void md_number_to_disp();
-void md_number_to_field();
-void md_ri_to_chars();
-static void i860_ip();
-void emit_machine_reloc();
+void md_begin ();
+void md_end ();
+void md_number_to_chars ();
+void md_assemble ();
+char *md_atof ();
+void md_convert_frag ();
+void md_create_short_jump ();
+void md_create_long_jump ();
+int md_estimate_size_before_relax ();
+void md_number_to_imm ();
+void md_number_to_disp ();
+void md_number_to_field ();
+void md_ri_to_chars ();
+static void i860_ip ();
+/* void emit_machine_reloc(); */
 
-int md_reloc_size = sizeof(struct relocation_info);
+const int md_reloc_size = sizeof (struct relocation_info);
 
-void (*md_emit_relocations)() = emit_machine_reloc;
+/* void (*md_emit_relocations)() = emit_machine_reloc; */
 
-const relax_typeS md_relax_table[] = { 0 };
+const relax_typeS md_relax_table[] =
+{0};
 
 /* handle of the OPCODE hash table */
 static struct hash_control *op_hash = NULL;
 
-static void s_dual(), s_enddual();
-static void s_atmp();
+static void s_dual (), s_enddual ();
+static void s_atmp ();
 
 const pseudo_typeS
-    md_pseudo_table[] = {
-           { "dual",       s_dual,     4 },
-           { "enddual",    s_enddual,  4 },
-           { "atmp",       s_atmp,     4 },
-           { NULL,         0,          0 },
-    };
+  md_pseudo_table[] =
+{
+  {"dual", s_dual, 4},
+  {"enddual", s_enddual, 4},
+  {"atmp", s_atmp, 4},
+  {NULL, 0, 0},
+};
 
 int md_short_jump_size = 4;
 int md_long_jump_size = 4;
 
 /* This array holds the chars that always start a comment.  If the
    pre-processor is disabled, these aren't very useful */
-char comment_chars[] = "!/";   /* JF removed '|' from comment_chars */
+const char comment_chars[] = "!/";     /* JF removed '|' from comment_chars */
 
 /* 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'
@@ -101,46 +73,49 @@ char comment_chars[] = "!/";       /* JF removed '|' from comment_chars */
    first line of the input file.  This is because the compiler outputs
    #NO_APP at the beginning of its output. */
 /* Also note that comments like this one will always work. */
-char line_comment_chars[] = "#/";
+const char line_comment_chars[] = "#/";
+
+const char line_separator_chars[] = "";
 
 /* Chars that can be used to separate mant from exp in floating point nums */
-char EXP_CHARS[] = "eE";
+const char EXP_CHARS[] = "eE";
 
 /* Chars that mean this number is a floating point constant */
 /* As in 0f12.456 */
 /* or    0d1.2345e12 */
-char FLT_CHARS[] = "rRsSfFdDxXpP";
+const char FLT_CHARS[] = "rRsSfFdDxXpP";
 
 /* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
    changed in read.c .  Ideally it shouldn't have to know about it at all,
    but nothing is ideal around here.
    */
-int size_reloc_info = sizeof(struct relocation_info);
+int size_reloc_info = sizeof (struct relocation_info);
 
 static unsigned char octal[256];
 #define isoctal(c)  octal[c]
-    static unsigned char toHex[256];
-
-struct i860_it {
-       char    *error;
-       unsigned long opcode;
-       struct nlist *nlistp;
-       expressionS exp;
-       int pcrel;
-       enum expand_type expand;
-       enum highlow_type highlow;
-       enum reloc_type reloc;
-} the_insn;
+static unsigned char toHex[256];
+
+struct i860_it
+  {
+    char *error;
+    unsigned long opcode;
+    struct nlist *nlistp;
+    expressionS exp;
+    int pcrel;
+    enum expand_type expand;
+    enum highlow_type highlow;
+    enum reloc_type reloc;
+  } the_insn;
 
 #if __STDC__ == 1
 
-static void print_insn(struct i860_it *insn);
-static int getExpression(char *str);
+static void print_insn (struct i860_it *insn);
+static int getExpression (char *str);
 
 #else /* not __STDC__ */
 
-static void print_insn();
-static int getExpression();
+static void print_insn ();
+static int getExpression ();
 
 #endif /* not __STDC__ */
 
@@ -149,627 +124,674 @@ static char last_expand;        /* error if expansion after branch */
 
 enum dual
 {
-       DUAL_OFF = 0, DUAL_ON, DUAL_DDOT, DUAL_ONDDOT,
+  DUAL_OFF = 0, DUAL_ON, DUAL_DDOT, DUAL_ONDDOT,
 };
 static enum dual dual_mode = DUAL_OFF; /* dual-instruction mode */
 
 static void
-    s_dual()   /* floating point instructions have dual set */
+s_dual ()                      /* floating point instructions have dual set */
 {
-       dual_mode = DUAL_ON;
+  dual_mode = DUAL_ON;
 }
 
 static void
-    s_enddual()        /* floating point instructions have dual set */
+s_enddual ()                   /* floating point instructions have dual set */
 {
-       dual_mode = DUAL_OFF;
+  dual_mode = DUAL_OFF;
 }
 
-static int atmp = 31; /* temporary register for pseudo's */
+static int atmp = 31;          /* temporary register for pseudo's */
 
 static void
-    s_atmp()
+s_atmp ()
 {
-       register int temp;
-       if (strncmp(input_line_pointer, "sp", 2) == 0) {
-               input_line_pointer += 2;
-               atmp = 2;
-       }
-       else if (strncmp(input_line_pointer, "fp", 2) == 0) {
-               input_line_pointer += 2;
-               atmp = 3;
-       }
-       else if (strncmp(input_line_pointer, "r", 1) == 0) {
-               input_line_pointer += 1;
-               temp = get_absolute_expression();
-               if (temp >= 0 && temp <= 31)
-                   atmp = temp;
-               else
-                   as_bad("Unknown temporary pseudo register");
-       }
-       else {
-               as_bad("Unknown temporary pseudo register");
-       }
-       demand_empty_rest_of_line();
-       return;
+  register int temp;
+  if (strncmp (input_line_pointer, "sp", 2) == 0)
+    {
+      input_line_pointer += 2;
+      atmp = 2;
+    }
+  else if (strncmp (input_line_pointer, "fp", 2) == 0)
+    {
+      input_line_pointer += 2;
+      atmp = 3;
+    }
+  else if (strncmp (input_line_pointer, "r", 1) == 0)
+    {
+      input_line_pointer += 1;
+      temp = get_absolute_expression ();
+      if (temp >= 0 && temp <= 31)
+       atmp = temp;
+      else
+       as_bad ("Unknown temporary pseudo register");
+    }
+  else
+    {
+      as_bad ("Unknown temporary pseudo register");
+    }
+  demand_empty_rest_of_line ();
+  return;
 }
 
 /* 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()
+md_begin ()
 {
-       register char *retval = NULL;
-       int lose = 0;
-       register unsigned int i = 0;
-       
-       op_hash = hash_new();
-       if (op_hash == NULL)
-           as_fatal("Virtual memory exhausted");
-       
-       while (i < NUMOPCODES)
+  register char *retval = NULL;
+  int lose = 0;
+  register unsigned int i = 0;
+
+  op_hash = hash_new ();
+  if (op_hash == NULL)
+    as_fatal ("Virtual memory exhausted");
+
+  while (i < NUMOPCODES)
+    {
+      const char *name = i860_opcodes[i].name;
+      retval = hash_insert (op_hash, name, &i860_opcodes[i]);
+      if (retval != NULL && *retval != '\0')
+       {
+         fprintf (stderr, "internal error: can't hash `%s': %s\n",
+                  i860_opcodes[i].name, retval);
+         lose = 1;
+       }
+      do
+       {
+         if (i860_opcodes[i].match & i860_opcodes[i].lose)
            {
-                   const char *name = i860_opcodes[i].name;
-                   retval = hash_insert(op_hash, name, &i860_opcodes[i]);
-                   if(retval != NULL && *retval != '\0')
-                       {
-                               fprintf (stderr, "internal error: can't hash `%s': %s\n",
-                                        i860_opcodes[i].name, retval);
-                               lose = 1;
-                       }
-                   do
-                       {
-                               if (i860_opcodes[i].match & i860_opcodes[i].lose)
-                                   {
-                                           fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n",
-                                                    i860_opcodes[i].name, i860_opcodes[i].args);
-                                           lose = 1;
-                                   }
-                               ++i;
-                       } while (i < NUMOPCODES
-                                && !strcmp(i860_opcodes[i].name, name));
+             fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n",
+                      i860_opcodes[i].name, i860_opcodes[i].args);
+             lose = 1;
            }
-       
-       if (lose)
-           as_fatal("Broken assembler.  No assembly attempted.");
-       
-       for (i = '0'; i < '8'; ++i)
-           octal[i] = 1;
-       for (i = '0'; i <= '9'; ++i)
-           toHex[i] = i - '0';
-       for (i = 'a'; i <= 'f'; ++i)
-           toHex[i] = i + 10 - 'a';
-       for (i = 'A'; i <= 'F'; ++i)
-           toHex[i] = i + 10 - 'A';
+         ++i;
+       }
+      while (i < NUMOPCODES
+            && !strcmp (i860_opcodes[i].name, name));
+    }
+
+  if (lose)
+    as_fatal ("Broken assembler.  No assembly attempted.");
+
+  for (i = '0'; i < '8'; ++i)
+    octal[i] = 1;
+  for (i = '0'; i <= '9'; ++i)
+    toHex[i] = i - '0';
+  for (i = 'a'; i <= 'f'; ++i)
+    toHex[i] = i + 10 - 'a';
+  for (i = 'A'; i <= 'F'; ++i)
+    toHex[i] = i + 10 - 'A';
 }
 
 void
-    md_end()
+md_end ()
 {
-       return;
+  return;
 }
 
 void
-    md_assemble(str)
-char *str;
+md_assemble (str)
+     char *str;
 {
-       char *toP;
-       int rsd;
-       int no_opcodes = 1;
-       int i;
-       struct i860_it pseudo[3];
-       
-       assert(str);
-       i860_ip(str);
-       
-       /* check for expandable flag to produce pseudo-instructions */
-       if (the_insn.expand != 0 && the_insn.highlow == NO_SPEC) {
-               for (i = 0; i < 3; i++)
-                   pseudo[i] = the_insn;
-               
-               switch (the_insn.expand) {
-                       
-               case E_DELAY:
-                       no_opcodes = 1;
-                       break;
-                       
-               case E_MOV:
-                       if (the_insn.exp.X_add_symbol == NULL &&
-                           the_insn.exp.X_subtract_symbol == NULL &&
-                           (the_insn.exp.X_add_number < (1 << 15) &&
-                            the_insn.exp.X_add_number >= -(1 << 15)))
-                           break;
-                       /* or l%const,r0,ireg_dest */
-                       pseudo[0].opcode = (the_insn.opcode & 0x001f0000) | 0xe4000000;
-                       pseudo[0].highlow = PAIR;
-                       /* orh h%const,ireg_dest,ireg_dest */
-                       pseudo[1].opcode = (the_insn.opcode & 0x03ffffff) | 0xec000000 |
-                           ((the_insn.opcode & 0x001f0000) << 5);
-                       pseudo[1].highlow = HIGH;
-                       no_opcodes = 2;
-                       break;
-                       
-               case E_ADDR:
-                       if (the_insn.exp.X_add_symbol == NULL &&
-                           the_insn.exp.X_subtract_symbol == NULL)
-                           break;
-                       /* orh ha%addr_expr,r0,r31 */
-                       pseudo[0].opcode = 0xec000000 | (atmp<<16);
-                       pseudo[0].highlow = HIGHADJ;
-                       pseudo[0].reloc = LOW0; /* must overwrite */
-                       /* l%addr_expr(r31),ireg_dest */
-                       pseudo[1].opcode = (the_insn.opcode & ~0x003e0000) | (atmp << 21);
-                       pseudo[1].highlow = PAIR;
-                       no_opcodes = 2;
-                       break;
-                       
-               case E_U32:     /* 2nd version emulates Intel as, not doc. */
-                       if (the_insn.exp.X_add_symbol == NULL &&
-                           the_insn.exp.X_subtract_symbol == NULL &&
-                           (the_insn.exp.X_add_number < (1 << 16) &&
-                            the_insn.exp.X_add_number >= 0))
-                           break;
-                       /* $(opcode)h h%const,ireg_src2,ireg_dest
+  char *toP;
+  int rsd;
+  int no_opcodes = 1;
+  int i;
+  struct i860_it pseudo[3];
+
+  assert (str);
+  i860_ip (str);
+
+  /* check for expandable flag to produce pseudo-instructions */
+  if (the_insn.expand != 0 && the_insn.highlow == NO_SPEC)
+    {
+      for (i = 0; i < 3; i++)
+       pseudo[i] = the_insn;
+
+      switch (the_insn.expand)
+       {
+
+       case E_DELAY:
+         no_opcodes = 1;
+         break;
+
+       case E_MOV:
+         if (the_insn.exp.X_add_symbol == NULL &&
+             the_insn.exp.X_subtract_symbol == NULL &&
+             (the_insn.exp.X_add_number < (1 << 15) &&
+              the_insn.exp.X_add_number >= -(1 << 15)))
+           break;
+         /* or l%const,r0,ireg_dest */
+         pseudo[0].opcode = (the_insn.opcode & 0x001f0000) | 0xe4000000;
+         pseudo[0].highlow = PAIR;
+         /* orh h%const,ireg_dest,ireg_dest */
+         pseudo[1].opcode = (the_insn.opcode & 0x03ffffff) | 0xec000000 |
+           ((the_insn.opcode & 0x001f0000) << 5);
+         pseudo[1].highlow = HIGH;
+         no_opcodes = 2;
+         break;
+
+       case E_ADDR:
+         if (the_insn.exp.X_add_symbol == NULL &&
+             the_insn.exp.X_subtract_symbol == NULL)
+           break;
+         /* orh ha%addr_expr,r0,r31 */
+         pseudo[0].opcode = 0xec000000 | (atmp << 16);
+         pseudo[0].highlow = HIGHADJ;
+         pseudo[0].reloc = LOW0;       /* must overwrite */
+         /* l%addr_expr(r31),ireg_dest */
+         pseudo[1].opcode = (the_insn.opcode & ~0x003e0000) | (atmp << 21);
+         pseudo[1].highlow = PAIR;
+         no_opcodes = 2;
+         break;
+
+       case E_U32:             /* 2nd version emulates Intel as, not doc. */
+         if (the_insn.exp.X_add_symbol == NULL &&
+             the_insn.exp.X_subtract_symbol == NULL &&
+             (the_insn.exp.X_add_number < (1 << 16) &&
+              the_insn.exp.X_add_number >= 0))
+           break;
+         /* $(opcode)h h%const,ireg_src2,ireg_dest
                           pseudo[0].opcode = (the_insn.opcode & 0xf3ffffff) | 0x0c000000; */
-                       /* $(opcode)h h%const,ireg_src2,r31 */
-                       pseudo[0].opcode = (the_insn.opcode & 0xf3e0ffff) | 0x0c000000 |
-                           (atmp << 16);
-                       pseudo[0].highlow = HIGH;
-                       /* $(opcode) l%const,ireg_dest,ireg_dest
+         /* $(opcode)h h%const,ireg_src2,r31 */
+         pseudo[0].opcode = (the_insn.opcode & 0xf3e0ffff) | 0x0c000000 |
+           (atmp << 16);
+         pseudo[0].highlow = HIGH;
+         /* $(opcode) l%const,ireg_dest,ireg_dest
                           pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 |
                           ((the_insn.opcode & 0x001f0000) << 5); */
-                       /* $(opcode) l%const,r31,ireg_dest */
-                       pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 |
-                           (atmp << 21);
-                       pseudo[1].highlow = PAIR;
-                       no_opcodes = 2;
-                       break;
-                       
-               case E_AND:     /* 2nd version emulates Intel as, not doc. */
-                       if (the_insn.exp.X_add_symbol == NULL &&
-                           the_insn.exp.X_subtract_symbol == NULL &&
-                           (the_insn.exp.X_add_number < (1 << 16) &&
-                            the_insn.exp.X_add_number >= 0))
-                           break;
-                       /* andnot h%const,ireg_src2,ireg_dest
+         /* $(opcode) l%const,r31,ireg_dest */
+         pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 |
+           (atmp << 21);
+         pseudo[1].highlow = PAIR;
+         no_opcodes = 2;
+         break;
+
+       case E_AND:             /* 2nd version emulates Intel as, not doc. */
+         if (the_insn.exp.X_add_symbol == NULL &&
+             the_insn.exp.X_subtract_symbol == NULL &&
+             (the_insn.exp.X_add_number < (1 << 16) &&
+              the_insn.exp.X_add_number >= 0))
+           break;
+         /* andnot h%const,ireg_src2,ireg_dest
                           pseudo[0].opcode = (the_insn.opcode & 0x03ffffff) | 0xd4000000; */
-                       /* andnot h%const,ireg_src2,r31 */
-                       pseudo[0].opcode = (the_insn.opcode & 0x03e0ffff) | 0xd4000000 |
-                           (atmp << 16);
-                       pseudo[0].highlow = HIGH;
-                       pseudo[0].exp.X_add_number = -1 - the_insn.exp.X_add_number;
-                       /* andnot l%const,ireg_dest,ireg_dest
+         /* andnot h%const,ireg_src2,r31 */
+         pseudo[0].opcode = (the_insn.opcode & 0x03e0ffff) | 0xd4000000 |
+           (atmp << 16);
+         pseudo[0].highlow = HIGH;
+         pseudo[0].exp.X_add_number = -1 - the_insn.exp.X_add_number;
+         /* andnot l%const,ireg_dest,ireg_dest
                           pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 |
                           ((the_insn.opcode & 0x001f0000) << 5); */
-                       /* andnot l%const,r31,ireg_dest */
-                       pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 |
-                           (atmp << 21);
-                       pseudo[1].highlow = PAIR;
-                       pseudo[1].exp.X_add_number = -1 - the_insn.exp.X_add_number;
-                       no_opcodes = 2;
-                       break;
-                       
-               case E_S32:
-                       if (the_insn.exp.X_add_symbol == NULL &&
-                           the_insn.exp.X_subtract_symbol == NULL &&
-                           (the_insn.exp.X_add_number < (1 << 15) &&
-                            the_insn.exp.X_add_number >= -(1 << 15)))
-                           break;
-                       /* orh h%const,r0,r31 */
-                       pseudo[0].opcode = 0xec000000 | (atmp << 16);
-                       pseudo[0].highlow = HIGH;
-                       /* or l%const,r31,r31 */
-                       pseudo[1].opcode = 0xe4000000 | (atmp << 21) | (atmp << 16);
-                       pseudo[1].highlow = PAIR;
-                       /* r31,ireg_src2,ireg_dest */
-                       pseudo[2].opcode = (the_insn.opcode & ~0x0400ffff) | (atmp << 11);
-                       pseudo[2].reloc = NO_RELOC;
-                       no_opcodes = 3;
-                       break;
-                       
-               default:
-                       as_fatal("failed sanity check.");
-               }
-               
-               the_insn = pseudo[0];
-               /* check for expanded opcode after branch or in dual */
-               if (no_opcodes > 1 && last_expand == 1)
-                   as_warn("Expanded opcode after delayed branch: `%s'", str);
-               if (no_opcodes > 1 && dual_mode != DUAL_OFF)
-                   as_warn("Expanded opcode in dual mode: `%s'", str);
+         /* andnot l%const,r31,ireg_dest */
+         pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 |
+           (atmp << 21);
+         pseudo[1].highlow = PAIR;
+         pseudo[1].exp.X_add_number = -1 - the_insn.exp.X_add_number;
+         no_opcodes = 2;
+         break;
+
+       case E_S32:
+         if (the_insn.exp.X_add_symbol == NULL &&
+             the_insn.exp.X_subtract_symbol == NULL &&
+             (the_insn.exp.X_add_number < (1 << 15) &&
+              the_insn.exp.X_add_number >= -(1 << 15)))
+           break;
+         /* orh h%const,r0,r31 */
+         pseudo[0].opcode = 0xec000000 | (atmp << 16);
+         pseudo[0].highlow = HIGH;
+         /* or l%const,r31,r31 */
+         pseudo[1].opcode = 0xe4000000 | (atmp << 21) | (atmp << 16);
+         pseudo[1].highlow = PAIR;
+         /* r31,ireg_src2,ireg_dest */
+         pseudo[2].opcode = (the_insn.opcode & ~0x0400ffff) | (atmp << 11);
+         pseudo[2].reloc = NO_RELOC;
+         no_opcodes = 3;
+         break;
+
+       default:
+         as_fatal ("failed sanity check.");
        }
-       
-       i = 0;
-       do {    /* always produce at least one opcode */
-               toP = frag_more(4);
-               /* put out the opcode */
-               md_number_to_chars(toP, the_insn.opcode, 4);
-               
-               /* check for expanded opcode after branch or in dual */
-               last_expand = the_insn.pcrel;
-               
-               /* put out the symbol-dependent stuff */
-               if (the_insn.reloc != NO_RELOC) {
-                       fix_new(
-                               frag_now,                           /* which frag */
-                               (toP - frag_now->fr_literal), /* where */
-                               4,                                  /* size */
-                               the_insn.exp.X_add_symbol,
-                               the_insn.exp.X_subtract_symbol,
-                               the_insn.exp.X_add_number,
-                               the_insn.pcrel,
-                               /* merge bit fields into one argument */
-                               (int)(((the_insn.highlow & 0x3) << 4) | (the_insn.reloc & 0xf))
-                               );
-               }
-               the_insn = pseudo[++i];
-       } while (--no_opcodes > 0);
-       
+
+      the_insn = pseudo[0];
+      /* check for expanded opcode after branch or in dual */
+      if (no_opcodes > 1 && last_expand == 1)
+       as_warn ("Expanded opcode after delayed branch: `%s'", str);
+      if (no_opcodes > 1 && dual_mode != DUAL_OFF)
+       as_warn ("Expanded opcode in dual mode: `%s'", str);
+    }
+
+  i = 0;
+  do
+    {                          /* always produce at least one opcode */
+      toP = frag_more (4);
+      /* put out the opcode */
+      md_number_to_chars (toP, the_insn.opcode, 4);
+
+      /* check for expanded opcode after branch or in dual */
+      last_expand = the_insn.pcrel;
+
+      /* put out the symbol-dependent stuff */
+      if (the_insn.reloc != NO_RELOC)
+       {
+         fix_new (frag_now,    /* which frag */
+                  (toP - frag_now->fr_literal),        /* where */
+                  4,           /* size */
+                  the_insn.exp.X_add_symbol,
+                  the_insn.exp.X_subtract_symbol,
+                  the_insn.exp.X_add_number,
+                  the_insn.pcrel,
+         /* merge bit fields into one argument */
+         (int) (((the_insn.highlow & 0x3) << 4) | (the_insn.reloc & 0xf)));
+       }
+      the_insn = pseudo[++i];
+    }
+  while (--no_opcodes > 0);
+
 }
 
 static void
-    i860_ip(str)
-char *str;
+i860_ip (str)
+     char *str;
 {
-       char *s;
-       const char *args;
-       char c;
-       unsigned long i;
-       struct i860_opcode *insn;
-       char *argsStart;
-       unsigned long   opcode;
-       unsigned int mask;
-       int match = 0;
-       int comma = 0;
-       
-       
-       for (s = str; islower(*s) || *s == '.' || *s == '3'; ++s)
-           ;
-       switch (*s) {
-               
-       case '\0':
-               break;
-               
-       case ',':
-               comma = 1;
-               
-               /*FALLTHROUGH*/
-               
-       case ' ':
-               *s++ = '\0';
-               break;
-               
-       default:
-               as_bad("Unknown opcode: `%s'", str);
-               exit(1);
-       }
-       
-       if (strncmp(str, "d.", 2) == 0) {       /* check for d. opcode prefix */
-               if (dual_mode == DUAL_ON)
-                   dual_mode = DUAL_ONDDOT;
-               else
-                   dual_mode = DUAL_DDOT;
-               str += 2;
-       }
-       
-       if ((insn = (struct i860_opcode *) hash_find(op_hash, str)) == NULL) {
-               if (dual_mode == DUAL_DDOT || dual_mode == DUAL_ONDDOT)
-                   str -= 2;
-               as_bad("Unknown opcode: `%s'", str);
-               return;
-       }
-       if (comma) {
-               *--s = ',';
-       }
-       argsStart = s;
-       for (;;) {
-               opcode = insn->match;
-               memset(&the_insn, '\0', sizeof(the_insn));
-               the_insn.reloc = NO_RELOC;
-               
-               /*
+  char *s;
+  const char *args;
+  char c;
+  unsigned long i;
+  struct i860_opcode *insn;
+  char *argsStart;
+  unsigned long opcode;
+  unsigned int mask;
+  int match = 0;
+  int comma = 0;
+
+
+  for (s = str; islower (*s) || *s == '.' || *s == '3'; ++s)
+    ;
+  switch (*s)
+    {
+
+    case '\0':
+      break;
+
+    case ',':
+      comma = 1;
+
+      /*FALLTHROUGH*/
+
+    case ' ':
+      *s++ = '\0';
+      break;
+
+    default:
+      as_bad ("Unknown opcode: `%s'", str);
+      exit (1);
+    }
+
+  if (strncmp (str, "d.", 2) == 0)
+    {                          /* check for d. opcode prefix */
+      if (dual_mode == DUAL_ON)
+       dual_mode = DUAL_ONDDOT;
+      else
+       dual_mode = DUAL_DDOT;
+      str += 2;
+    }
+
+  if ((insn = (struct i860_opcode *) hash_find (op_hash, str)) == NULL)
+    {
+      if (dual_mode == DUAL_DDOT || dual_mode == DUAL_ONDDOT)
+       str -= 2;
+      as_bad ("Unknown opcode: `%s'", str);
+      return;
+    }
+  if (comma)
+    {
+      *--s = ',';
+    }
+  argsStart = s;
+  for (;;)
+    {
+      opcode = insn->match;
+      memset (&the_insn, '\0', sizeof (the_insn));
+      the_insn.reloc = NO_RELOC;
+
+      /*
                 * Build the opcode, checking as we go to make
                 * sure that the operands match
                 */
-               for (args = insn->args; ; ++args) {
-                       switch (*args) {
-                               
-                       case '\0':  /* end of args */
-                               if (*s == '\0') {
-                                       match = 1;
-                               }
-                               break;
-                               
-                       case '+':
-                       case '(':   /* these must match exactly */
-                       case ')':
-                       case ',':
-                       case ' ':
-                               if (*s++ == *args)
-                                   continue;
-                               break;
-                               
-                       case '#':   /* must be at least one digit */
-                               if (isdigit(*s++)) {
-                                       while (isdigit(*s)) {
-                                               ++s;
-                                       }
-                                       continue;
-                               }
-                               break;
-                               
-                       case '1':   /* next operand must be a register */
-                       case '2':
-                       case 'd':
-                               switch (*s) {
-                                       
-                               case 'f':   /* frame pointer */
-                                       s++;
-                                       if (*s++ == 'p') {
-                                               mask = 0x3;
-                                               break;
-                                       }
-                                       goto error;
-                                       
-                               case 's':   /* stack pointer */
-                                       s++;
-                                       if (*s++ == 'p') {
-                                               mask= 0x2;
-                                               break;
-                                       }
-                                       goto error;
-                                       
-                               case 'r': /* any register */
-                                       s++;
-                                       if (!isdigit(c = *s++)) {
-                                               goto error;
-                                       }
-                                       if (isdigit(*s)) {
-                                               if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) {
-                                                       goto error;
-                                               }
-                                       } else {
-                                               c -= '0';
-                                       }
-                                       mask= c;
-                                       break;
-                                       
-                               default:        /* not this opcode */
-                                       goto error;
-                               }
-                               /*
+      for (args = insn->args;; ++args)
+       {
+         switch (*args)
+           {
+
+           case '\0':          /* end of args */
+             if (*s == '\0')
+               {
+                 match = 1;
+               }
+             break;
+
+           case '+':
+           case '(':           /* these must match exactly */
+           case ')':
+           case ',':
+           case ' ':
+             if (*s++ == *args)
+               continue;
+             break;
+
+           case '#':           /* must be at least one digit */
+             if (isdigit (*s++))
+               {
+                 while (isdigit (*s))
+                   {
+                     ++s;
+                   }
+                 continue;
+               }
+             break;
+
+           case '1':           /* next operand must be a register */
+           case '2':
+           case 'd':
+             switch (*s)
+               {
+
+               case 'f':       /* frame pointer */
+                 s++;
+                 if (*s++ == 'p')
+                   {
+                     mask = 0x3;
+                     break;
+                   }
+                 goto error;
+
+               case 's':       /* stack pointer */
+                 s++;
+                 if (*s++ == 'p')
+                   {
+                     mask = 0x2;
+                     break;
+                   }
+                 goto error;
+
+               case 'r':       /* any register */
+                 s++;
+                 if (!isdigit (c = *s++))
+                   {
+                     goto error;
+                   }
+                 if (isdigit (*s))
+                   {
+                     if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32)
+                       {
+                         goto error;
+                       }
+                   }
+                 else
+                   {
+                     c -= '0';
+                   }
+                 mask = c;
+                 break;
+
+               default:        /* not this opcode */
+                 goto error;
+               }
+             /*
                                 * Got the register, now figure out where
                                 * it goes in the opcode.
                                 */
-                               switch (*args) {
-                                       
-                               case '1':
-                                       opcode |= mask << 11;
-                                       continue;
-                                       
-                               case '2':
-                                       opcode |= mask << 21;
-                                       continue;
-                                       
-                               case 'd':
-                                       opcode |= mask << 16;
-                                       continue;
-                                       
-                               }
-                               break;
-                               
-                       case 'e':    /* next operand is a floating point register */
-                       case 'f':
-                       case 'g':
-                               if (*s++ == 'f' && isdigit(*s)) {
-                                       mask = *s++;
-                                       if (isdigit(*s)) {
-                                               mask = 10 * (mask - '0') + (*s++ - '0');
-                                               if (mask >= 32) {
-                                                       break;
-                                               }
-                                       } else {
-                                               mask -= '0';
-                                       }
-                                       switch (*args) {
-                                               
-                                       case 'e':
-                                               opcode |= mask << 11;
-                                               continue;
-                                               
-                                       case 'f':
-                                               opcode |= mask << 21;
-                                               continue;
-                                               
-                                       case 'g':
-                                               opcode |= mask << 16;
-                                               if (dual_mode != DUAL_OFF)
-                                                   opcode |= (1 << 9); /* dual mode instruction */
-                                               if (dual_mode == DUAL_DDOT)
-                                                   dual_mode = DUAL_OFF;
-                                               if (dual_mode == DUAL_ONDDOT)
-                                                   dual_mode = DUAL_ON;
-                                               if ((opcode & (1 << 10)) && (mask == ((opcode >> 11) & 0x1f)))
-                                                   as_warn("Fsr1 equals fdest with Pipelining");
-                                               continue;
-                                       }
-                               }
-                               break;
-                               
-                       case 'c': /* next operand must be a control register */
-                               if (strncmp(s, "fir", 3) == 0) {
-                                       opcode |= 0x0 << 21;
-                                       s += 3;
-                                       continue;
-                               }
-                               if (strncmp(s, "psr", 3) == 0) {
-                                       opcode |= 0x1 << 21;
-                                       s += 3;
-                                       continue;
-                               }
-                               if (strncmp(s, "dirbase", 7) == 0) {
-                                       opcode |= 0x2 << 21;
-                                       s += 7;
-                                       continue;
-                               }
-                               if (strncmp(s, "db", 2) == 0) {
-                                       opcode |= 0x3 << 21;
-                                       s += 2;
-                                       continue;
-                               }
-                               if (strncmp(s, "fsr", 3) == 0) {
-                                       opcode |= 0x4 << 21;
-                                       s += 3;
-                                       continue;
-                               }
-                               if (strncmp(s, "epsr", 4) == 0) {
-                                       opcode |= 0x5 << 21;
-                                       s += 4;
-                                       continue;
-                               }
-                               break;
-                               
-                       case '5':   /* 5 bit immediate in src1 */
-                               memset(&the_insn, '\0', sizeof(the_insn));
-                               if ( !getExpression(s)) {
-                                       s = expr_end;
-                                       if (the_insn.exp.X_add_number & ~0x1f)
-                                           as_bad("5-bit immediate too large");
-                                       opcode |= (the_insn.exp.X_add_number & 0x1f) << 11;
-                                       memset(&the_insn, '\0', sizeof(the_insn));
-                                       the_insn.reloc = NO_RELOC;
-                                       continue;
-                               }
-                               break;
-                               
-                       case 'l':   /* 26 bit immediate, relative branch */
-                               the_insn.reloc = BRADDR;
-                               the_insn.pcrel = 1;
-                               goto immediate;
-                               
-                       case 's':   /* 16 bit immediate, split relative branch */
-                               /* upper 5 bits of offset in dest field */
-                               the_insn.pcrel = 1;
-                               the_insn.reloc = SPLIT0;
-                               goto immediate;
-                               
-                       case 'S':   /* 16 bit immediate, split (st), aligned */
-                               if (opcode & (1 << 28))
-                                   if (opcode & 0x1)
-                                       the_insn.reloc = SPLIT2;
-                                   else
-                                       the_insn.reloc = SPLIT1;
-                               else
-                                   the_insn.reloc = SPLIT0;
-                               goto immediate;
-                               
-                       case 'I':   /* 16 bit immediate, aligned */
-                               if (opcode & (1 << 28))
-                                   if (opcode & 0x1)
-                                       the_insn.reloc = LOW2;
-                                   else
-                                       the_insn.reloc = LOW1;
-                               else
-                                   the_insn.reloc = LOW0;
-                               goto immediate;
-                               
-                       case 'i':   /* 16 bit immediate */
-                               the_insn.reloc = LOW0;
-                               
-                               /*FALLTHROUGH*/
-                               
-                       immediate:
-                               if(*s==' ')
-                                   s++;
-                               if (strncmp(s, "ha%", 3) == 0) {
-                                       the_insn.highlow = HIGHADJ;
-                                       s += 3;
-                               } else if (strncmp(s, "h%", 2) == 0) {
-                                       the_insn.highlow = HIGH;
-                                       s += 2;
-                               } else if (strncmp(s, "l%", 2) == 0) {
-                                       the_insn.highlow = PAIR;
-                                       s += 2;
-                               }
-                               the_insn.expand = insn->expand; 
-                               
-                               /* Note that if the getExpression() fails, we will still have
+             switch (*args)
+               {
+
+               case '1':
+                 opcode |= mask << 11;
+                 continue;
+
+               case '2':
+                 opcode |= mask << 21;
+                 continue;
+
+               case 'd':
+                 opcode |= mask << 16;
+                 continue;
+
+               }
+             break;
+
+           case 'e':           /* next operand is a floating point register */
+           case 'f':
+           case 'g':
+             if (*s++ == 'f' && isdigit (*s))
+               {
+                 mask = *s++;
+                 if (isdigit (*s))
+                   {
+                     mask = 10 * (mask - '0') + (*s++ - '0');
+                     if (mask >= 32)
+                       {
+                         break;
+                       }
+                   }
+                 else
+                   {
+                     mask -= '0';
+                   }
+                 switch (*args)
+                   {
+
+                   case 'e':
+                     opcode |= mask << 11;
+                     continue;
+
+                   case 'f':
+                     opcode |= mask << 21;
+                     continue;
+
+                   case 'g':
+                     opcode |= mask << 16;
+                     if (dual_mode != DUAL_OFF)
+                       opcode |= (1 << 9);     /* dual mode instruction */
+                     if (dual_mode == DUAL_DDOT)
+                       dual_mode = DUAL_OFF;
+                     if (dual_mode == DUAL_ONDDOT)
+                       dual_mode = DUAL_ON;
+                     if ((opcode & (1 << 10)) && (mask == ((opcode >> 11) & 0x1f)))
+                       as_warn ("Fsr1 equals fdest with Pipelining");
+                     continue;
+                   }
+               }
+             break;
+
+           case 'c':           /* next operand must be a control register */
+             if (strncmp (s, "fir", 3) == 0)
+               {
+                 opcode |= 0x0 << 21;
+                 s += 3;
+                 continue;
+               }
+             if (strncmp (s, "psr", 3) == 0)
+               {
+                 opcode |= 0x1 << 21;
+                 s += 3;
+                 continue;
+               }
+             if (strncmp (s, "dirbase", 7) == 0)
+               {
+                 opcode |= 0x2 << 21;
+                 s += 7;
+                 continue;
+               }
+             if (strncmp (s, "db", 2) == 0)
+               {
+                 opcode |= 0x3 << 21;
+                 s += 2;
+                 continue;
+               }
+             if (strncmp (s, "fsr", 3) == 0)
+               {
+                 opcode |= 0x4 << 21;
+                 s += 3;
+                 continue;
+               }
+             if (strncmp (s, "epsr", 4) == 0)
+               {
+                 opcode |= 0x5 << 21;
+                 s += 4;
+                 continue;
+               }
+             break;
+
+           case '5':           /* 5 bit immediate in src1 */
+             memset (&the_insn, '\0', sizeof (the_insn));
+             if (!getExpression (s))
+               {
+                 s = expr_end;
+                 if (the_insn.exp.X_add_number & ~0x1f)
+                   as_bad ("5-bit immediate too large");
+                 opcode |= (the_insn.exp.X_add_number & 0x1f) << 11;
+                 memset (&the_insn, '\0', sizeof (the_insn));
+                 the_insn.reloc = NO_RELOC;
+                 continue;
+               }
+             break;
+
+           case 'l':           /* 26 bit immediate, relative branch */
+             the_insn.reloc = BRADDR;
+             the_insn.pcrel = 1;
+             goto immediate;
+
+           case 's':           /* 16 bit immediate, split relative branch */
+             /* upper 5 bits of offset in dest field */
+             the_insn.pcrel = 1;
+             the_insn.reloc = SPLIT0;
+             goto immediate;
+
+           case 'S':           /* 16 bit immediate, split (st), aligned */
+             if (opcode & (1 << 28))
+               if (opcode & 0x1)
+                 the_insn.reloc = SPLIT2;
+               else
+                 the_insn.reloc = SPLIT1;
+             else
+               the_insn.reloc = SPLIT0;
+             goto immediate;
+
+           case 'I':           /* 16 bit immediate, aligned */
+             if (opcode & (1 << 28))
+               if (opcode & 0x1)
+                 the_insn.reloc = LOW2;
+               else
+                 the_insn.reloc = LOW1;
+             else
+               the_insn.reloc = LOW0;
+             goto immediate;
+
+           case 'i':           /* 16 bit immediate */
+             the_insn.reloc = LOW0;
+
+             /*FALLTHROUGH*/
+
+           immediate:
+             if (*s == ' ')
+               s++;
+             if (strncmp (s, "ha%", 3) == 0)
+               {
+                 the_insn.highlow = HIGHADJ;
+                 s += 3;
+               }
+             else if (strncmp (s, "h%", 2) == 0)
+               {
+                 the_insn.highlow = HIGH;
+                 s += 2;
+               }
+             else if (strncmp (s, "l%", 2) == 0)
+               {
+                 the_insn.highlow = PAIR;
+                 s += 2;
+               }
+             the_insn.expand = insn->expand;
+
+             /* Note that if the getExpression() fails, we will still have
                                   created U entries in the symbol table for the 'symbols'
                                   in the input string.  Try not to create U symbols for
                                   registers, etc. */
-                               
-                               if ( !getExpression(s)) {
-                                       s = expr_end;
-                                       continue;
-                               }
-                               break;
-                               
-                       default:
-                               as_fatal("failed sanity check.");
-                       }
-                       break;
+
+             if (!getExpression (s))
+               {
+                 s = expr_end;
+                 continue;
                }
-       error:
-               if (match == 0)
-                   {
-                           /* Args don't match.  */
-                           if (&insn[1] - i860_opcodes < NUMOPCODES
-                               && !strcmp(insn->name, insn[1].name))
-                               {
-                                       ++insn;
-                                       s = argsStart;
-                                       continue;
-                               }
-                           else
-                               {
-                                       as_bad("Illegal operands");
-                                       return;
-                               }
-                   }
-               break;
+             break;
+
+           default:
+             as_fatal ("failed sanity check.");
+           }
+         break;
        }
-       
-       the_insn.opcode = opcode;
-       return;
+    error:
+      if (match == 0)
+       {
+         /* Args don't match.  */
+         if (&insn[1] - i860_opcodes < NUMOPCODES
+             && !strcmp (insn->name, insn[1].name))
+           {
+             ++insn;
+             s = argsStart;
+             continue;
+           }
+         else
+           {
+             as_bad ("Illegal operands");
+             return;
+           }
+       }
+      break;
+    }
+
+  the_insn.opcode = opcode;
+  return;
 }
 
 static int
-    getExpression(str)
-char *str;
+getExpression (str)
+     char *str;
 {
-       char *save_in;
-       segT seg;
-       
-       save_in = input_line_pointer;
-       input_line_pointer = str;
-       switch (seg = expression(&the_insn.exp)) {
-               
-       case SEG_ABSOLUTE:
-       case SEG_TEXT:
-       case SEG_DATA:
-       case SEG_BSS:
-       case SEG_UNKNOWN:
-       case SEG_DIFFERENCE:
-       case SEG_BIG:
-       case SEG_ABSENT:
-               break;
-               
-       default:
-               the_insn.error = "bad segment";
-               expr_end = input_line_pointer;
-               input_line_pointer=save_in;
-               return 1;
-       }
-       expr_end = input_line_pointer;
-       input_line_pointer = save_in;
-       return 0;
+  char *save_in;
+  segT seg;
+
+  save_in = input_line_pointer;
+  input_line_pointer = str;
+  switch (seg = expression (&the_insn.exp))
+    {
+
+    case SEG_ABSOLUTE:
+    case SEG_TEXT:
+    case SEG_DATA:
+    case SEG_BSS:
+    case SEG_UNKNOWN:
+    case SEG_DIFFERENCE:
+    case SEG_BIG:
+    case SEG_ABSENT:
+      break;
+
+    default:
+      the_insn.error = "bad segment";
+      expr_end = input_line_pointer;
+      input_line_pointer = save_in;
+      return 1;
+    }
+  expr_end = input_line_pointer;
+  input_line_pointer = save_in;
+  return 0;
 }
 
 
 /*
   This is identical to the md_atof in m68k.c.  I think this is right,
   but I'm not sure.
-  
+
   Turn a string in input_line_pointer into a floating point constant of type
   type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
   emitted is stored in *sizeP .  An error message is returned, or NULL on OK.
@@ -779,221 +801,225 @@ char *str;
 #define MAX_LITTLENUMS 6
 
 char *
-    md_atof(type,litP,sizeP)
-char type;
-char *litP;
-int *sizeP;
+md_atof (type, litP, sizeP)
+     char type;
+     char *litP;
+     int *sizeP;
 {
-       int     prec;
-       LITTLENUM_TYPE words[MAX_LITTLENUMS];
-       LITTLENUM_TYPE *wordP;
-       char    *t;
-       char    *atof_ieee();
-       
-       switch(type) {
-               
-       case 'f':
-       case 'F':
-       case 's':
-       case 'S':
-               prec = 2;
-               break;
-               
-       case 'd':
-       case 'D':
-       case 'r':
-       case 'R':
-               prec = 4;
-               break;
-               
-       case 'x':
-       case 'X':
-               prec = 6;
-               break;
-               
-       case 'p':
-       case 'P':
-               prec = 6;
-               break;
-               
-       default:
-               *sizeP=0;
-               return "Bad call to MD_ATOF()";
-       }
-       t=atof_ieee(input_line_pointer,type,words);
-       if(t)
-           input_line_pointer=t;
-       *sizeP=prec * sizeof(LITTLENUM_TYPE);
-       for(wordP=words;prec--;) {
-               md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE));
-               litP+=sizeof(LITTLENUM_TYPE);
-       }
-       return "";      /* Someone should teach Dean about null pointers */
+  int prec;
+  LITTLENUM_TYPE words[MAX_LITTLENUMS];
+  LITTLENUM_TYPE *wordP;
+  char *t;
+  char *atof_ieee ();
+
+  switch (type)
+    {
+
+    case 'f':
+    case 'F':
+    case 's':
+    case 'S':
+      prec = 2;
+      break;
+
+    case 'd':
+    case 'D':
+    case 'r':
+    case 'R':
+      prec = 4;
+      break;
+
+    case 'x':
+    case 'X':
+      prec = 6;
+      break;
+
+    case 'p':
+    case 'P':
+      prec = 6;
+      break;
+
+    default:
+      *sizeP = 0;
+      return "Bad call to MD_ATOF()";
+    }
+  t = atof_ieee (input_line_pointer, type, words);
+  if (t)
+    input_line_pointer = t;
+  *sizeP = prec * sizeof (LITTLENUM_TYPE);
+  for (wordP = words; prec--;)
+    {
+      md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE));
+      litP += sizeof (LITTLENUM_TYPE);
+    }
+  return "";                   /* Someone should teach Dean about null pointers */
 }
 
 /*
  * Write out big-endian.
  */
 void
-    md_number_to_chars(buf,val,n)
-char *buf;
-long val;
-int n;
+md_number_to_chars (buf, val, n)
+     char *buf;
+     valueT val;
+     int n;
 {
-       switch(n) {
-               
-       case 4:
-               *buf++ = val >> 24;
-               *buf++ = val >> 16;
-       case 2:
-               *buf++ = val >> 8;
-       case 1:
-               *buf = val;
-               break;
-               
-       default:
-               as_fatal("failed sanity check.");
-       }
-       return;
+  switch (n)
+    {
+
+    case 4:
+      *buf++ = val >> 24;
+      *buf++ = val >> 16;
+    case 2:
+      *buf++ = val >> 8;
+    case 1:
+      *buf = val;
+      break;
+
+    default:
+      as_fatal ("failed sanity check.");
+    }
+  return;
 }
 
-void md_number_to_imm(buf,val,n, fixP)
-char *buf;
-long val;
-int n;
-fixS *fixP;
+void
+md_number_to_imm (buf, val, n, fixP)
+     char *buf;
+     long val;
+     int n;
+     fixS *fixP;
 {
-       enum reloc_type reloc = fixP->fx_r_type & 0xf;
-       enum highlow_type highlow = (fixP->fx_r_type >> 4) & 0x3;
-       
-       assert(buf);
-       assert(n == 4); /* always on i860 */
-       
-       switch(highlow)
-           {
-                   
-           case HIGHADJ:       /* adjusts the high-order 16-bits */
-                   if (val & (1 << 15))
-                       val += (1 << 16);
-                   
-                   /*FALLTHROUGH*/
-                   
-           case HIGH:  /* selects the high-order 16-bits */
-                   val >>= 16;
-                   break;
-                   
-           case PAIR:  /* selects the low-order 16-bits */
-                   val = val & 0xffff;
-                   break;
-                   
-           default:
-                   break;
-           }
-       
-       switch(reloc)
-           {
-                   
-           case BRADDR:        /* br,call,bc,bc.t,bnc,bnc.t w/26-bit immediate */
-                   if (fixP->fx_pcrel != 1)
-                       as_bad("26-bit branch w/o pc relative set: 0x%08x", val);
-                   val >>= 2;  /* align pcrel offset, see manual */
-                   
-                   if (val >= (1 << 25) || val < -(1 << 25))   /* check for overflow */
-                       as_bad("26-bit branch offset overflow: 0x%08x", val);
-                   buf[0] = (buf[0] & 0xfc) | ((val >> 24) & 0x3);
-                   buf[1] = val >> 16;
-                   buf[2] = val >> 8;
-                   buf[3] = val;
-                   break;
-                   
-           case SPLIT2:        /* 16 bit immediate, 4-byte aligned */
-                   if (val & 0x3)
-                       as_bad("16-bit immediate 4-byte alignment error: 0x%08x", val);
-                   val &= ~0x3;        /* 4-byte align value */
-                   /*FALLTHROUGH*/
-           case SPLIT1:        /* 16 bit immediate, 2-byte aligned */
-                   if (val & 0x1)
-                       as_bad("16-bit immediate 2-byte alignment error: 0x%08x", val);
-                   val &= ~0x1;        /* 2-byte align value */
-                   /*FALLTHROUGH*/
-           case SPLIT0:        /* st,bla,bte,btne w/16-bit immediate */
-                   if (fixP->fx_pcrel == 1)
-                       val >>= 2;      /* align pcrel offset, see manual */
-                   /* check for bounds */
-                   if (highlow != PAIR && (val >= (1 << 16) || val < -(1 << 15)))
-                       as_bad("16-bit branch offset overflow: 0x%08x", val);
-                   buf[1] = (buf[1] & ~0x1f) | ((val >> 11) & 0x1f);
-                   buf[2] = (buf[2] & ~0x7) | ((val >> 8) & 0x7);
-                   buf[3] |= val;      /* perserve bottom opcode bits */       
-                   break;
-                   
-           case LOW4:  /* fld,pfld,pst,flush 16-byte aligned */
-                   if (val & 0xf)
-                       as_bad("16-bit immediate 16-byte alignment error: 0x%08x", val);
-                   val &= ~0xf;        /* 16-byte align value */
-                   /*FALLTHROUGH*/
-           case LOW3:  /* fld,pfld,pst,flush 8-byte aligned */
-                   if (val & 0x7)
-                       as_bad("16-bit immediate 8-byte alignment error: 0x%08x", val);
-                   val &= ~0x7;        /* 8-byte align value */
-                   /*FALLTHROUGH*/
-           case LOW2:  /* 16 bit immediate, 4-byte aligned */
-                   if (val & 0x3)
-                       as_bad("16-bit immediate 4-byte alignment error: 0x%08x", val);
-                   val &= ~0x3;        /* 4-byte align value */
-                   /*FALLTHROUGH*/
-           case LOW1:  /* 16 bit immediate, 2-byte aligned */
-                   if (val & 0x1)
-                       as_bad("16-bit immediate 2-byte alignment error: 0x%08x", val);
-                   val &= ~0x1;        /* 2-byte align value */
-                   /*FALLTHROUGH*/
-           case LOW0:  /* 16 bit immediate, byte aligned */
-                   /* check for bounds */
-                   if (highlow != PAIR && (val >= (1 << 16) || val < -(1 << 15)))
-                       as_bad("16-bit immediate overflow: 0x%08x", val);
-                   buf[2] = val >> 8;
-                   buf[3] |= val;      /* perserve bottom opcode bits */       
-                   break;
-                   
-           case NO_RELOC:
-           default:
-                   as_bad("bad relocation type: 0x%02x", reloc);
-                   break;
-           }
-       return;
+  enum reloc_type reloc = fixP->fx_r_type & 0xf;
+  enum highlow_type highlow = (fixP->fx_r_type >> 4) & 0x3;
+
+  assert (buf);
+  assert (n == 4);             /* always on i860 */
+
+  switch (highlow)
+    {
+
+    case HIGHADJ:              /* adjusts the high-order 16-bits */
+      if (val & (1 << 15))
+       val += (1 << 16);
+
+      /*FALLTHROUGH*/
+
+    case HIGH:                 /* selects the high-order 16-bits */
+      val >>= 16;
+      break;
+
+    case PAIR:                 /* selects the low-order 16-bits */
+      val = val & 0xffff;
+      break;
+
+    default:
+      break;
+    }
+
+  switch (reloc)
+    {
+
+    case BRADDR:               /* br,call,bc,bc.t,bnc,bnc.t w/26-bit immediate */
+      if (fixP->fx_pcrel != 1)
+       as_bad ("26-bit branch w/o pc relative set: 0x%08x", val);
+      val >>= 2;               /* align pcrel offset, see manual */
+
+      if (val >= (1 << 25) || val < -(1 << 25))        /* check for overflow */
+       as_bad ("26-bit branch offset overflow: 0x%08x", val);
+      buf[0] = (buf[0] & 0xfc) | ((val >> 24) & 0x3);
+      buf[1] = val >> 16;
+      buf[2] = val >> 8;
+      buf[3] = val;
+      break;
+
+    case SPLIT2:               /* 16 bit immediate, 4-byte aligned */
+      if (val & 0x3)
+       as_bad ("16-bit immediate 4-byte alignment error: 0x%08x", val);
+      val &= ~0x3;             /* 4-byte align value */
+      /*FALLTHROUGH*/
+    case SPLIT1:               /* 16 bit immediate, 2-byte aligned */
+      if (val & 0x1)
+       as_bad ("16-bit immediate 2-byte alignment error: 0x%08x", val);
+      val &= ~0x1;             /* 2-byte align value */
+      /*FALLTHROUGH*/
+    case SPLIT0:               /* st,bla,bte,btne w/16-bit immediate */
+      if (fixP->fx_pcrel == 1)
+       val >>= 2;              /* align pcrel offset, see manual */
+      /* check for bounds */
+      if (highlow != PAIR && (val >= (1 << 16) || val < -(1 << 15)))
+       as_bad ("16-bit branch offset overflow: 0x%08x", val);
+      buf[1] = (buf[1] & ~0x1f) | ((val >> 11) & 0x1f);
+      buf[2] = (buf[2] & ~0x7) | ((val >> 8) & 0x7);
+      buf[3] |= val;           /* perserve bottom opcode bits */
+      break;
+
+    case LOW4:                 /* fld,pfld,pst,flush 16-byte aligned */
+      if (val & 0xf)
+       as_bad ("16-bit immediate 16-byte alignment error: 0x%08x", val);
+      val &= ~0xf;             /* 16-byte align value */
+      /*FALLTHROUGH*/
+    case LOW3:                 /* fld,pfld,pst,flush 8-byte aligned */
+      if (val & 0x7)
+       as_bad ("16-bit immediate 8-byte alignment error: 0x%08x", val);
+      val &= ~0x7;             /* 8-byte align value */
+      /*FALLTHROUGH*/
+    case LOW2:                 /* 16 bit immediate, 4-byte aligned */
+      if (val & 0x3)
+       as_bad ("16-bit immediate 4-byte alignment error: 0x%08x", val);
+      val &= ~0x3;             /* 4-byte align value */
+      /*FALLTHROUGH*/
+    case LOW1:                 /* 16 bit immediate, 2-byte aligned */
+      if (val & 0x1)
+       as_bad ("16-bit immediate 2-byte alignment error: 0x%08x", val);
+      val &= ~0x1;             /* 2-byte align value */
+      /*FALLTHROUGH*/
+    case LOW0:                 /* 16 bit immediate, byte aligned */
+      /* check for bounds */
+      if (highlow != PAIR && (val >= (1 << 16) || val < -(1 << 15)))
+       as_bad ("16-bit immediate overflow: 0x%08x", val);
+      buf[2] = val >> 8;
+      buf[3] |= val;           /* perserve bottom opcode bits */
+      break;
+
+    case NO_RELOC:
+    default:
+      as_bad ("bad relocation type: 0x%02x", reloc);
+      break;
+    }
+  return;
 }
 
 /* should never be called for i860 */
 void
-    md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol)
-char *ptr;
-long from_addr, to_addr;
-fragS *frag;
-symbolS *to_symbol;
+md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
+     char *ptr;
+     addressT from_addr, to_addr;
+     fragS *frag;
+     symbolS *to_symbol;
 {
-       as_fatal("i860_create_short_jmp\n");
+  as_fatal ("i860_create_short_jmp\n");
 }
 
 /* should never be called for i860 */
 void
-    md_number_to_disp(buf,val,n)
-char   *buf;
-long   val;
+md_number_to_disp (buf, val, n)
+     char *buf;
+     long val;
 {
-       as_fatal("md_number_to_disp\n");
+  as_fatal ("md_number_to_disp\n");
 }
 
 /* should never be called for i860 */
 void
-    md_number_to_field(buf,val,fix)
-char *buf;
-long val;
-void *fix;
+md_number_to_field (buf, val, fix)
+     char *buf;
+     long val;
+     void *fix;
 {
-       as_fatal("i860_number_to_field\n");
+  as_fatal ("i860_number_to_field\n");
 }
 
-/* the bit-field entries in the relocation_info struct plays hell 
+/* the bit-field entries in the relocation_info struct plays hell
    with the byte-order problems of cross-assembly.  So as a hack,
    I added this mach. dependent ri twiddler.  Ugly, but it gets
    you there. -KWK */
@@ -1003,170 +1029,250 @@ void *fix;
    relocation type (highlow 5-4).  Next 4 bytes are long addend. */
 /* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com */
 void
-    md_ri_to_chars(ri_p, ri)
-struct relocation_info *ri_p, ri;
+md_ri_to_chars (ri_p, ri)
+     struct relocation_info *ri_p, ri;
 {
 #if 0
-       unsigned char the_bytes[sizeof(*ri_p)];
-       
-       /* this is easy */
-       md_number_to_chars(the_bytes, ri.r_address, sizeof(ri.r_address));
-       /* now the fun stuff */
-       the_bytes[4] = (ri.r_index >> 16) & 0x0ff;
-       the_bytes[5] = (ri.r_index >> 8) & 0x0ff;
-       the_bytes[6] = ri.r_index & 0x0ff;
-       the_bytes[7] = ((ri.r_extern << 7)  & 0x80) | (0 & 0x60) | (ri.r_type & 0x1F);
-       /* Also easy */
-       md_number_to_chars(&the_bytes[8], ri.r_addend, sizeof(ri.r_addend));
-       /* now put it back where you found it, Junior... */
-       memcpy((char *) ri_p, the_bytes, sizeof(*ri_p));
+  unsigned char the_bytes[sizeof (*ri_p)];
+
+  /* this is easy */
+  md_number_to_chars (the_bytes, ri.r_address, sizeof (ri.r_address));
+  /* now the fun stuff */
+  the_bytes[4] = (ri.r_index >> 16) & 0x0ff;
+  the_bytes[5] = (ri.r_index >> 8) & 0x0ff;
+  the_bytes[6] = ri.r_index & 0x0ff;
+  the_bytes[7] = ((ri.r_extern << 7) & 0x80) | (0 & 0x60) | (ri.r_type & 0x1F);
+  /* Also easy */
+  md_number_to_chars (&the_bytes[8], ri.r_addend, sizeof (ri.r_addend));
+  /* now put it back where you found it, Junior... */
+  memcpy ((char *) ri_p, the_bytes, sizeof (*ri_p));
 #endif
 }
 
 /* should never be called for i860 */
 void
-    md_convert_frag(headers, fragP)
-object_headers *headers;
-register fragS *fragP;
+md_convert_frag (headers, fragP)
+     object_headers *headers;
+     register fragS *fragP;
 {
-       as_fatal("i860_convert_frag\n");
+  as_fatal ("i860_convert_frag\n");
 }
 
 /* should never be called for i860 */
 void
-    md_create_long_jump(ptr, from_addr, to_addr, frag, to_symbol)
-char   *ptr;
-long   from_addr,
-    to_addr;
-fragS  *frag;
-symbolS        *to_symbol;
+md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
+     char *ptr;
+     addressT from_addr, to_addr;
+     fragS *frag;
+     symbolS *to_symbol;
 {
-       as_fatal("i860_create_long_jump\n");
+  as_fatal ("i860_create_long_jump\n");
 }
 
 /* should never be called for i860 */
 int
-    md_estimate_size_before_relax(fragP, segtype)
-register fragS *fragP;
-segT segtype;
+md_estimate_size_before_relax (fragP, segtype)
+     register fragS *fragP;
+     segT segtype;
 {
-       as_fatal("i860_estimate_size_before_relax\n");
+  as_fatal ("i860_estimate_size_before_relax\n");
 }
 
 /* for debugging only, must match enum reloc_type */
-static char *Reloc[] = {
-       "NO_RELOC",
-       "BRADDR", 
-       "LOW0", 
-       "LOW1", 
-       "LOW2", 
-       "LOW3", 
-       "LOW4", 
-       "SPLIT0", 
-       "SPLIT1", 
-       "SPLIT2", 
-       "RELOC_32", 
+static char *Reloc[] =
+{
+  "NO_RELOC",
+  "BRADDR",
+  "LOW0",
+  "LOW1",
+  "LOW2",
+  "LOW3",
+  "LOW4",
+  "SPLIT0",
+  "SPLIT1",
+  "SPLIT2",
+  "RELOC_32",
 };
-static char *Highlow[] = {
-       "NO_SPEC",
-       "PAIR", 
-       "HIGH", 
-       "HIGHADJ", 
+static char *Highlow[] =
+{
+  "NO_SPEC",
+  "PAIR",
+  "HIGH",
+  "HIGHADJ",
 };
 static void
-    print_insn(insn)
-struct i860_it *insn;
+print_insn (insn)
+     struct i860_it *insn;
 {
-       if (insn->error) {
-               fprintf(stderr, "ERROR: %s\n");
-       }
-       fprintf(stderr, "opcode=0x%08x\t", insn->opcode);
-       fprintf(stderr, "expand=0x%08x\t", insn->expand);
-       fprintf(stderr, "reloc = %s\t", Reloc[insn->reloc]);
-       fprintf(stderr, "highlow = %s\n", Highlow[insn->highlow]);
-       fprintf(stderr, "exp =  {\n");
-       fprintf(stderr, "\t\tX_add_symbol = %s\n",
-               insn->exp.X_add_symbol ?
-               (S_GET_NAME(insn->exp.X_add_symbol) ? 
-                S_GET_NAME(insn->exp.X_add_symbol) : "???") : "0");
-       fprintf(stderr, "\t\tX_sub_symbol = %s\n",
-               insn->exp.X_subtract_symbol ?
-               (S_GET_NAME(insn->exp.X_subtract_symbol) ? 
-                S_GET_NAME(insn->exp.X_subtract_symbol) : "???") : "0");
-       fprintf(stderr, "\t\tX_add_number = %d\n",
-               insn->exp.X_add_number);
-       fprintf(stderr, "}\n");
-       return;
+  if (insn->error)
+    {
+      fprintf (stderr, "ERROR: %s\n");
+    }
+  fprintf (stderr, "opcode=0x%08x\t", insn->opcode);
+  fprintf (stderr, "expand=0x%08x\t", insn->expand);
+  fprintf (stderr, "reloc = %s\t", Reloc[insn->reloc]);
+  fprintf (stderr, "highlow = %s\n", Highlow[insn->highlow]);
+  fprintf (stderr, "exp =  {\n");
+  fprintf (stderr, "\t\tX_add_symbol = %s\n",
+          insn->exp.X_add_symbol ?
+          (S_GET_NAME (insn->exp.X_add_symbol) ?
+           S_GET_NAME (insn->exp.X_add_symbol) : "???") : "0");
+  fprintf (stderr, "\t\tX_sub_symbol = %s\n",
+          insn->exp.X_subtract_symbol ?
+          (S_GET_NAME (insn->exp.X_subtract_symbol) ?
+           S_GET_NAME (insn->exp.X_subtract_symbol) : "???") : "0");
+  fprintf (stderr, "\t\tX_add_number = %d\n",
+          insn->exp.X_add_number);
+  fprintf (stderr, "}\n");
+  return;
 }
 
 int
-    md_parse_option(argP,cntP,vecP)
-char **argP;
-int *cntP;
-char ***vecP;
+md_parse_option (argP, cntP, vecP)
+     char **argP;
+     int *cntP;
+     char ***vecP;
 {
-       return 1;
+  return 1;
 }
 
+#ifdef comment
 /*
  * I860 relocations are completely different, so it needs
  * this machine dependent routine to emit them.
  */
 void
-    emit_machine_reloc(fixP, segment_address_in_file)
-register fixS *fixP;
-relax_addressT segment_address_in_file;
+emit_machine_reloc (fixP, segment_address_in_file)
+     register fixS *fixP;
+     relax_addressT segment_address_in_file;
 {
-       struct reloc_info_i860 ri;
-       register symbolS *symbolP;
-       extern char *next_object_file_charP;
-       long add_number;
-       
-       memset((char *) &ri, '\0', sizeof(ri));
-       for (; fixP; fixP = fixP->fx_next) {
-               
-               if (fixP->fx_r_type & ~0x3f) {
-                       as_fatal("fixP->fx_r_type = %d\n", fixP->fx_r_type);
-               }
-               ri.r_pcrel = fixP->fx_pcrel;
-               ri.r_type = fixP->fx_r_type;
-               
-               if ((symbolP = fixP->fx_addsy) != NULL) {
-                       ri.r_address = fixP->fx_frag->fr_address +
-                           fixP->fx_where - segment_address_in_file;
-                       if ((symbolP->sy_type & N_TYPE) == N_UNDF) {
-                               ri.r_extern = 1;
-                               ri.r_symbolnum = symbolP->sy_number;
-                       } else {
-                               ri.r_extern = 0;
-                               ri.r_symbolnum = symbolP->sy_type & N_TYPE;
-                       }
-                       if (symbolP && symbolP->sy_frag) {
-                               ri.r_addend = symbolP->sy_frag->fr_address;
-                       }
-                       ri.r_type = fixP->fx_r_type;
-                       if (fixP->fx_pcrel) {
-                               /* preserve actual offset vs. pc + 4 */
-                               ri.r_addend -= (ri.r_address + 4);
-                       } else {
-                               ri.r_addend = fixP->fx_addnumber;
-                       }
-                       
-                       md_ri_to_chars((char *) &ri, ri);
-                       append(&next_object_file_charP, (char *)& ri, sizeof(ri));
-               }
+  struct reloc_info_i860 ri;
+  register symbolS *symbolP;
+  extern char *next_object_file_charP;
+  long add_number;
+
+  memset ((char *) &ri, '\0', sizeof (ri));
+  for (; fixP; fixP = fixP->fx_next)
+    {
+
+      if (fixP->fx_r_type & ~0x3f)
+       {
+         as_fatal ("fixP->fx_r_type = %d\n", fixP->fx_r_type);
        }
-       return;
+      ri.r_pcrel = fixP->fx_pcrel;
+      ri.r_type = fixP->fx_r_type;
+
+      if ((symbolP = fixP->fx_addsy) != NULL)
+       {
+         ri.r_address = fixP->fx_frag->fr_address +
+           fixP->fx_where - segment_address_in_file;
+         if (!S_IS_DEFINED (symbolP))
+           {
+             ri.r_extern = 1;
+             ri.r_symbolnum = symbolP->sy_number;
+           }
+         else
+           {
+             ri.r_extern = 0;
+             ri.r_symbolnum = S_GET_TYPE (symbolP);
+           }
+         if (symbolP && symbolP->sy_frag)
+           {
+             ri.r_addend = symbolP->sy_frag->fr_address;
+           }
+         ri.r_type = fixP->fx_r_type;
+         if (fixP->fx_pcrel)
+           {
+             /* preserve actual offset vs. pc + 4 */
+             ri.r_addend -= (ri.r_address + 4);
+           }
+         else
+           {
+             ri.r_addend = fixP->fx_addnumber;
+           }
+
+         md_ri_to_chars ((char *) &ri, ri);
+         append (&next_object_file_charP, (char *) &ri, sizeof (ri));
+       }
+    }
+  return;
 }
 
-/* Parse an operand that is machine-specific.  
+#endif /* comment */
+
+#ifdef OBJ_AOUT
+
+/* on i860: first 4 bytes are normal unsigned long address, next three
+   bytes are index, most sig. byte first.  Byte 7 is broken up with
+   bit 7 as pcrel, bit 6 as extern, and the lower six bits as
+   relocation type (highlow 5-4).  Next 4 bytes are long addend. */
+
+void
+tc_aout_fix_to_chars (where, fixP, segment_address_in_file)
+     char *where;
+     fixS *fixP;
+     relax_addressT segment_address_in_file;
+{
+  long r_index;
+  long r_extern;
+  long r_addend = 0;
+  long r_address;
+
+  know (fixP->fx_addsy);
+  know (!(fixP->fx_r_type & ~0x3f));
+
+  if (!S_IS_DEFINED (fixP->fx_addsy))
+    {
+      r_extern = 1;
+      r_index = fixP->fx_addsy->sy_number;
+    }
+  else
+    {
+      r_extern = 0;
+      r_index = S_GET_TYPE (fixP->fx_addsy);
+    }
+
+  md_number_to_chars (where,
+                     r_address = fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
+                     4);
+
+  where[4] = (r_index >> 16) & 0x0ff;
+  where[5] = (r_index >> 8) & 0x0ff;
+  where[6] = r_index & 0x0ff;
+  where[7] = (((fixP->fx_pcrel << 7) & 0x80)
+             | ((r_extern << 6) & 0x40)
+             | (fixP->fx_r_type & 0x3F));
+
+  if (fixP->fx_addsy->sy_frag)
+    {
+      r_addend = fixP->fx_addsy->sy_frag->fr_address;
+    }
+
+  if (fixP->fx_pcrel)
+    {
+      /* preserve actual offset vs. pc + 4 */
+      r_addend -= (r_address + 4);
+    }
+  else
+    {
+      r_addend = fixP->fx_addnumber;
+    }
+
+  md_number_to_chars (&where[8], r_addend, 4);
+
+  return;
+}                              /* tc_aout_fix_to_chars() */
+
+#endif /* OBJ_AOUT */
+
+/* Parse an operand that is machine-specific.
    We just return without modifying the expression if we have nothing
    to do.  */
 
 /* ARGSUSED */
 void
-    md_operand (expressionP)
-expressionS *expressionP;
+md_operand (expressionP)
+     expressionS *expressionP;
 {
 }
 
@@ -1174,67 +1280,76 @@ expressionS *expressionP;
 
 /* ARGSUSED */
 symbolS *
-    md_undefined_symbol (name)
-char *name;
+md_undefined_symbol (name)
+     char *name;
 {
-       return 0;
+  return 0;
 }
 
 /* Round up a section size to the appropriate boundary.  */
-long
-    md_section_align (segment, size)
-segT segment;
-long size;
+valueT
+md_section_align (segment, size)
+     segT segment;
+     valueT size;
 {
-       return size;            /* Byte alignment is fine */
+  return size;                 /* Byte alignment is fine */
 }
 
 /* Exactly what point is a PC-relative offset relative TO?
    On the i860, they're relative to the address of the offset, plus
    its size. (??? Is this right?  FIXME-SOON!) */
 long
-    md_pcrel_from (fixP)
-fixS *fixP;
+md_pcrel_from (fixP)
+     fixS *fixP;
 {
-       return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
+  return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
 }
 
 void
-    md_apply_fix(fixP, val)
-fixS *fixP;
-long val;
+md_apply_fix (fixP, val)
+     fixS *fixP;
+     long val;
 {
-       char *place = fixP->fx_where + fixP->fx_frag->fr_literal;
-       
-       if (!fixP->fx_bit_fixP) {
-               
-               switch (fixP->fx_im_disp) {
-               case 0:
-                       fixP->fx_addnumber = val;
-                       md_number_to_imm(place, val, fixP->fx_size, fixP);
-                       break;
-               case 1:
-                       md_number_to_disp (place,
-                                          fixP->fx_pcrel ? val+fixP->fx_pcrel_adjust:val,
-                                          fixP->fx_size);
-                       break;
-               case 2: /* fix requested for .long .word etc */
-                       md_number_to_chars (place, val, fixP->fx_size);
-                       break;
-               default:
-                       as_fatal("Internal error in md_apply_fix() in file \"%s\"", __FILE__);
-               } /* OVE: maybe one ought to put _imm _disp _chars in one md-func */
-       } else {
-               md_number_to_field (place, val, fixP->fx_bit_fixP);
-       }
-       
-       return;
-} /* md_apply_fix() */
+  char *place = fixP->fx_where + fixP->fx_frag->fr_literal;
+
+  /* looks to me like i860 never has bit fixes. Let's see. xoxorich. */
+  know (fixP->fx_bit_fixP == NULL);
+  if (!fixP->fx_bit_fixP)
+    {
+
+      /* also looks like fx_im_disp is always 0.  Let's see.  xoxorich. */
+      know (fixP->fx_im_disp == 0);
+      switch (fixP->fx_im_disp)
+       {
+       case 0:
+         fixP->fx_addnumber = val;
+         md_number_to_imm (place, val, fixP->fx_size, fixP);
+         break;
+       case 1:
+         md_number_to_disp (place,
+                        fixP->fx_pcrel ? val + fixP->fx_pcrel_adjust : val,
+                            fixP->fx_size);
+         break;
+       case 2:         /* fix requested for .long .word etc */
+         md_number_to_chars (place, val, fixP->fx_size);
+         break;
+       default:
+         as_fatal ("Internal error in md_apply_fix() in file \"%s\"", __FILE__);
+       }                       /* OVE: maybe one ought to put _imm _disp _chars in one md-func */
+    }
+  else
+    {
+      md_number_to_field (place, val, fixP->fx_bit_fixP);
+    }
+
+  return;
+}                              /* md_apply_fix() */
 
 /*
  * Local Variables:
  * fill-column: 131
  * comment-column: 0
+ * End:
  */
 
 /* end of tc-i860.c */
index f916fa72ed593a3bfad5c073e4add572dcb7f39e..d176838a29887fce185a075ac34c9825119c68bc 100644 (file)
@@ -3585,7 +3585,8 @@ md_assemble (str)
          current_architecture |= m68881;
        }
       if (!no_68851
-         && (cpu_of_arch (current_architecture) & m68020up) != 0)
+         && (cpu_of_arch (current_architecture) & m68020up) != 0
+         && cpu_of_arch (current_architecture) != m68040)
        {
          current_architecture |= m68851;
        }
@@ -3942,7 +3943,7 @@ md_atof (type, litP, sizeP)
 void
 md_number_to_chars (buf, val, n)
      char *buf;
-     long val;
+     valueT val;
      int n;
 {
   switch (n)
@@ -4535,40 +4536,40 @@ CONST int md_long_jump_size = 6;
 void
 md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
      char *ptr;
-     long from_addr, to_addr;
+     addressT from_addr, to_addr;
      fragS *frag;
      symbolS *to_symbol;
 {
-  long offset;
+  valueT offset;
 
   offset = to_addr - (from_addr + 2);
 
-  md_number_to_chars (ptr, (long) 0x6000, 2);
-  md_number_to_chars (ptr + 2, (long) offset, 2);
+  md_number_to_chars (ptr, (valueT) 0x6000, 2);
+  md_number_to_chars (ptr + 2, (valueT) offset, 2);
 }
 
 void
 md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
      char *ptr;
-     long from_addr, to_addr;
+     addressT from_addr, to_addr;
      fragS *frag;
      symbolS *to_symbol;
 {
-  long offset;
+  valueT offset;
 
   if (cpu_of_arch (current_architecture) < m68020)
     {
       offset = to_addr - S_GET_VALUE (to_symbol);
-      md_number_to_chars (ptr, (long) 0x4EF9, 2);
-      md_number_to_chars (ptr + 2, (long) offset, 4);
+      md_number_to_chars (ptr, (valueT) 0x4EF9, 2);
+      md_number_to_chars (ptr + 2, (valueT) offset, 4);
       fix_new (frag, (ptr + 2) - frag->fr_literal, 4, to_symbol, (symbolS *) 0, (long) 0, 0,
               NO_RELOC);
     }
   else
     {
       offset = to_addr - (from_addr + 2);
-      md_number_to_chars (ptr, (long) 0x60ff, 2);
-      md_number_to_chars (ptr + 2, (long) offset, 4);
+      md_number_to_chars (ptr, (valueT) 0x60ff, 2);
+      md_number_to_chars (ptr + 2, (valueT) offset, 4);
     }
 }
 
@@ -5095,10 +5096,10 @@ md_operand (expressionP)
 }
 
 /* Round up a section size to the appropriate boundary.  */
-long
+valueT
 md_section_align (segment, size)
      segT segment;
-     long size;
+     valueT size;
 {
   return size;                 /* Byte alignment is fine */
 }
index db49ef38032023cd8cf0f0dd1f7eb9adefd1bdea..db0d4f11bc007d18daec0b4b20bd0997e726b961 100644 (file)
 
 #include <stdio.h>
 #include <ctype.h>
-#ifdef USG
-#include <string.h>
-#else
-#include <strings.h>
-#endif
 #include "opcode/ns32k.h"
 
 #include "as.h"
-#include "read.h"
 
 #include "obstack.h"
 
@@ -1536,7 +1530,7 @@ md_atof (type, litP, sizeP)
 void
 md_number_to_chars (buf, value, nbytes)
      char *buf;
-     long value;
+     valueT value;
      int nbytes;
 {
   while (nbytes--)
@@ -1709,12 +1703,11 @@ tc_aout_fix_to_chars (where, fixP, segment_address_in_file)
      relax_addressT segment_address_in_file;
 {
   /*
-        * In: length of relocation (or of address) in chars: 1, 2 or 4.
-        * Out: GNU LD relocation length code: 0, 1, or 2.
-        */
+   * In: length of relocation (or of address) in chars: 1, 2 or 4.
+   * Out: GNU LD relocation length code: 0, 1, or 2.
+   */
 
-  static unsigned char nbytes_r_length[] =
-  {42, 0, 1, 42, 2};
+  static unsigned char nbytes_r_length[] = {42, 0, 1, 42, 2};
   long r_symbolnum;
 
   know (fixP->fx_addsy != NULL);
@@ -1735,9 +1728,7 @@ tc_aout_fix_to_chars (where, fixP, segment_address_in_file)
                       | (long) (fixP->fx_bsr << 28)
                       | (long) (fixP->fx_im_disp << 29)),
                      4);
-
-  return;
-}                              /* tc_aout_fix_to_chars() */
+}
 
 #endif /* OBJ_AOUT */
 
@@ -1977,34 +1968,34 @@ md_estimate_size_before_relax (fragP, segment)
 
 int md_short_jump_size = 3;
 int md_long_jump_size = 5;
-int md_reloc_size = 8;         /* Size of relocation record */
+const int md_reloc_size = 8;   /* Size of relocation record */
 
 void
 md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
      char *ptr;
-     long from_addr, to_addr;
+     addressT from_addr, to_addr;
      fragS *frag;
      symbolS *to_symbol;
 {
-  long offset;
+  valueT offset;
 
   offset = to_addr - from_addr;
-  md_number_to_chars (ptr, (long) 0xEA, 1);
-  md_number_to_disp (ptr + 1, (long) offset, 2);
+  md_number_to_chars (ptr, (valueT) 0xEA, 1);
+  md_number_to_disp (ptr + 1, (valueT) offset, 2);
 }
 
 void
 md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
      char *ptr;
-     long from_addr, to_addr;
+     addressT from_addr, to_addr;
      fragS *frag;
      symbolS *to_symbol;
 {
-  long offset;
+  valueT offset;
 
   offset = to_addr - from_addr;
-  md_number_to_chars (ptr, (long) 0xEA, 2);
-  md_number_to_disp (ptr + 2, (long) offset, 4);
+  md_number_to_chars (ptr, (valueT) 0xEA, 2);
+  md_number_to_disp (ptr + 2, (valueT) offset, 4);
 }
 \f
 /* JF this is a new function to parse machine-dep options */
@@ -2099,6 +2090,20 @@ fix_new_ns32k (frag, where, size, add_symbol, sub_symbol, offset, pcrel,
   fixP->fx_bsr = bsr;
 }                              /* fix_new_ns32k() */
 
+/* This is TC_CONS_FIX_NEW, called by emit_expr in read.c.  */
+
+void
+cons_fix_new_ns32k (frag, where, size, exp)
+     fragS *frag;              /* Which frag? */
+     int where;                        /* Where in that frag? */
+     int size;                 /* 1, 2  or 4 usually. */
+     expressionS *exp;         /* Expression. */
+{
+  fix_new_ns32k (frag, where, size, exp->X_add_symbol,
+                exp->X_subtract_symbol, exp->X_add_number,
+                0, 0, 2, 0, 0);
+}
+
 /* We have no need to default values of symbols.  */
 
 symbolS *
@@ -2120,10 +2125,10 @@ md_operand (expressionP)
 }
 
 /* Round up a section size to the appropriate boundary.  */
-long
+valueT
 md_section_align (segment, size)
      segT segment;
-     long size;
+     valueT size;
 {
   return size;                 /* Byte alignment is fine */
 }
diff --git a/gas/config/tc-sh.c b/gas/config/tc-sh.c
new file mode 100644 (file)
index 0000000..fe6c2a6
--- /dev/null
@@ -0,0 +1,1390 @@
+/* tc-sh.c -- Assemble code for the Hitachi Super-H
+
+   Copyright (C) 1993 Free Software Foundation.
+
+   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)
+   any later version.
+
+   GAS is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GAS; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/*
+  Written By Steve Chamberlain
+  sac@cygnus.com
+  */
+
+#include <stdio.h>
+#include "as.h"
+#include "bfd.h"
+#include "subsegs.h"
+#define DEFINE_TABLE
+#include "../opcodes/sh-opc.h"
+#include <ctype.h>
+
+const char comment_chars[] = "!";
+const char line_separator_chars[] = ";";
+const char line_comment_chars[] = "!";
+
+/* This table describes all the machine specific pseudo-ops the assembler
+   has to support.  The fields are:
+   pseudo-op name without dot
+   function to call to execute this pseudo-op
+   Integer arg to pass to the function
+   */
+
+void cons ();
+void s_align_bytes ();
+
+const pseudo_typeS md_pseudo_table[] =
+{
+  {"int", cons, 4},
+  {"word", cons, 2},
+  {"form", listing_psize, 0},
+  {"heading", listing_title, 0},
+  {"import", s_ignore, 0},
+  {"page", listing_eject, 0},
+  {"program", s_ignore, 0},
+  {0, 0, 0}
+};
+
+/*int md_reloc_size;*/
+
+static int relax;              /* set if -relax seen */
+
+const char EXP_CHARS[] = "eE";
+
+/* Chars that mean this number is a floating point constant */
+/* As in 0f12.456 */
+/* or    0d1.2345e12 */
+const char FLT_CHARS[] = "rRsSfFdDxXpP";
+
+#define C(a,b) ENCODE_RELAX(a,b)
+
+#define JREG 14                        /* Register used as a temp when relaxing */
+#define ENCODE_RELAX(what,length) (((what) << 4) + (length))
+#define GET_WHAT(x) ((x>>4))
+
+/* These are the two types of relaxable instrction */
+#define COND_JUMP 1
+#define UNCOND_JUMP  2
+
+#define UNDEF_DISP 0
+#define COND8  1
+#define COND12 2
+#define COND32 3
+#define UNCOND12 1
+#define UNCOND32 2
+#define UNDEF_WORD_DISP 4
+#define END 5
+
+#define UNCOND12 1
+#define UNCOND32 2
+
+#define COND8_F 254
+#define COND8_M -256
+#define COND8_LENGTH 2
+#define COND12_F (4094 - 4)    /* -4 since there are two extra */
+/* instructions needed */
+#define COND12_M -4096
+#define COND12_LENGTH 6
+#define COND32_F (1<<30)
+#define COND32_M -(1<<30)
+#define COND32_LENGTH 14
+
+#define COND8_RANGE(x) ((x) > COND8_M && (x) < COND8_F)
+#define COND12_RANGE(x) ((x) > COND12_M && (x) < COND12_F)
+
+#define UNCOND12_F 4094
+#define UNCOND12_M -4096
+#define UNCOND12_LENGTH 2
+
+#define UNCOND32_F (1<<30)
+#define UNCOND32_M -(1<<30)
+#define UNCOND32_LENGTH 14
+
+
+const relax_typeS md_relax_table[C (END, 0)];
+
+static struct hash_control *opcode_hash_control;       /* Opcode mnemonics */
+
+/*
+  This function is called once, at assembler startup time.  This should
+  set up all the tables, etc that the MD part of the assembler needs
+  */
+
+void
+md_begin ()
+{
+  sh_opcode_info *opcode;
+  char *prev_name = "";
+
+  opcode_hash_control = hash_new ();
+
+  /* Insert unique names into hash table */
+  for (opcode = sh_table; opcode->name; opcode++)
+    {
+      if (strcmp (prev_name, opcode->name))
+       {
+         prev_name = opcode->name;
+         hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
+       }
+      else
+       {
+         /* Make all the opcodes with the same name point to the same
+          string */
+         opcode->name = prev_name;
+       }
+    }
+
+  /* Initialize the relax table */
+  md_relax_table[C (COND_JUMP, COND8)].rlx_forward = COND8_F;
+  md_relax_table[C (COND_JUMP, COND8)].rlx_backward = COND8_M;
+  md_relax_table[C (COND_JUMP, COND8)].rlx_length = COND8_LENGTH;
+  md_relax_table[C (COND_JUMP, COND8)].rlx_more = C (COND_JUMP, COND12);
+
+  md_relax_table[C (COND_JUMP, COND12)].rlx_forward = COND12_F;
+  md_relax_table[C (COND_JUMP, COND12)].rlx_backward = COND12_M;
+  md_relax_table[C (COND_JUMP, COND12)].rlx_length = COND12_LENGTH;
+  md_relax_table[C (COND_JUMP, COND12)].rlx_more = C (COND_JUMP, COND32);
+
+  md_relax_table[C (COND_JUMP, COND32)].rlx_forward = COND32_F;
+  md_relax_table[C (COND_JUMP, COND32)].rlx_backward = COND32_M;
+  md_relax_table[C (COND_JUMP, COND32)].rlx_length = COND32_LENGTH;
+  md_relax_table[C (COND_JUMP, COND32)].rlx_more = 0;
+
+
+  md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_forward = UNCOND12_F;
+  md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_backward = UNCOND12_M;
+  md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_length = UNCOND12_LENGTH;
+  md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_more = C (UNCOND_JUMP, UNCOND32);
+
+  md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_forward = UNCOND32_F;
+  md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_backward = UNCOND32_M;
+  md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_length = UNCOND32_LENGTH;
+  md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_more = 0;
+
+
+}
+
+static int reg_m;
+static int reg_n;
+static expressionS immediate;  /* absolute expression */
+
+typedef struct
+{
+  sh_arg_type type;
+  int reg;
+}
+
+sh_operand_info;
+
+/* try and parse a reg name, returns number of chars consumed */
+static int
+parse_reg (src, mode, reg)
+     char *src;
+     int *mode;
+     int *reg;
+{
+  if (src[0] == 'r')
+    {
+      if (src[1] == '1')
+       {
+         if (src[2] >= '0' && src[2] <= '5')
+           {
+             *mode = A_REG_N;
+             *reg = 10 + src[2] - '0';
+             return 3;
+           }
+       }
+      if (src[1] >= '0' && src[1] <= '9')
+       {
+         *mode = A_REG_N;
+         *reg = (src[1] - '0');
+         return 2;
+       }
+    }
+
+  if (src[0] == 's' && src[1] == 'r')
+    {
+      *mode = A_SR;
+      return 2;
+    }
+
+  if (src[0] == 's' && src[1] == 'p')
+    {
+      *mode = A_REG_N;
+      *reg = 15;
+      return 2;
+    }
+
+  if (src[0] == 'p' && src[1] == 'r')
+    {
+      *mode = A_PR;
+      return 2;
+    }
+  if (src[0] == 'p' && src[1] == 'c')
+    {
+      *mode = A_DISP_PC;
+      return 2;
+    }
+  if (src[0] == 'g' && src[1] == 'b' && src[2] == 'r')
+    {
+      *mode = A_GBR;
+      return 3;
+    }
+  if (src[0] == 'v' && src[1] == 'b' && src[2] == 'r')
+    {
+      *mode = A_VBR;
+      return 3;
+    }
+
+  if (src[0] == 'm' && src[1] == 'a' && src[2] == 'c')
+    {
+      if (src[3] == 'l')
+       {
+         *mode = A_MACL;
+         return 4;
+       }
+      if (src[3] == 'h')
+       {
+         *mode = A_MACH;
+         return 4;
+       }
+    }
+
+  return 0;
+}
+
+static
+char *
+parse_exp (s)
+     char *s;
+{
+  char *save;
+  char *new;
+  segT seg;
+
+  save = input_line_pointer;
+
+
+  input_line_pointer = s;
+
+  seg = expr (0, &immediate);
+  new = input_line_pointer;
+  input_line_pointer = save;
+  if (SEG_NORMAL (seg))
+    return new;
+  switch (seg)
+    {
+    case SEG_ABSOLUTE:
+    case SEG_UNKNOWN:
+    case SEG_DIFFERENCE:
+    case SEG_BIG:
+    case SEG_REGISTER:
+      return new;
+    case SEG_ABSENT:
+      as_bad ("Missing operand");
+      return new;
+    default:
+      as_bad ("Don't understand operand of type %s", segment_name (seg));
+      return new;
+    }
+}
+
+
+/* The many forms of operand:
+
+   Rn                  Register direct
+   @Rn                 Register indirect
+   @Rn+                        Autoincrement
+   @-Rn                        Autodecrement
+   @(disp:4,Rn)
+   @(disp:8,GBR)
+   @(disp:8,PC)
+
+   @(R0,Rn)
+   @(R0,GBR)
+
+   disp:8
+   disp:12
+   #imm8
+   pr, gbr, vbr, macl, mach
+
+ */
+
+static
+char *
+parse_at (src, op)
+     char *src;
+     sh_operand_info *op;
+{
+  int len;
+  int mode;
+  src++;
+  if (src[0] == '-')
+    {
+      /* Must be predecrement */
+      src++;
+
+      len = parse_reg (src, &mode, &(op->reg));
+      if (mode != A_REG_N)
+       as_bad ("illegal register after @-");
+
+      op->type = A_DEC_N;
+      src += len;
+    }
+  else if (src[0] == '(')
+    {
+      /* Could be @(disp, rn), @(disp, gbr), @(disp, pc),  @(r0, gbr) or
+        @(r0, rn) */
+      src++;
+      len = parse_reg (src, &mode, &(op->reg));
+      if (len && mode == A_REG_N)
+       {
+         src += len;
+         if (op->reg != 0)
+           {
+             as_bad ("must be @(r0,...)");
+           }
+         if (src[0] == ',')
+           src++;
+         /* Now can be rn or gbr */
+         len = parse_reg (src, &mode, &(op->reg));
+         if (mode == A_GBR)
+           {
+             op->type = A_R0_GBR;
+           }
+         else if (mode == A_REG_N)
+           {
+             op->type = A_IND_R0_REG_N;
+           }
+         else
+           {
+             as_bad ("syntax error in @(r0,...)");
+           }
+       }
+      else
+       {
+         /* Must be an @(disp,.. thing) */
+         src = parse_exp (src);
+         if (src[0] == ',')
+           src++;
+         /* Now can be rn, gbr or pc */
+         len = parse_reg (src, &mode, &op->reg);
+         if (len)
+           {
+             if (mode == A_REG_N)
+               {
+                 op->type = A_DISP_REG_N;
+               }
+             else if (mode == A_GBR)
+               {
+                 op->type = A_DISP_GBR;
+               }
+             else if (mode == A_DISP_PC)
+               {
+                 op->type = A_DISP_PC;
+               }
+             else
+               {
+                 as_bad ("syntax error in @(disp,[Rn, gbr, pc])");
+               }
+           }
+         else
+           {
+             as_bad ("syntax error in @(disp,[Rn, gbr, pc])");
+           }
+       }
+      src += len;
+      if (src[0] != ')')
+       as_bad ("expecting )");
+      else
+       src++;
+    }
+  else
+    {
+      src += parse_reg (src, &mode, &(op->reg));
+      if (mode != A_REG_N)
+       {
+         as_bad ("illegal register after @");
+       }
+      if (src[0] == '+')
+       {
+         op->type = A_INC_N;
+         src++;
+       }
+      else
+       {
+         op->type = A_IND_N;
+       }
+    }
+  return src;
+}
+
+static void
+get_operand (ptr, op)
+     char **ptr;
+     sh_operand_info *op;
+{
+  char *src = *ptr;
+  int mode = -1;
+  unsigned int len;
+
+  if (src[0] == '#')
+    {
+      src++;
+      *ptr = parse_exp (src);
+      op->type = A_IMM;
+      return;
+    }
+
+  else if (src[0] == '@')
+    {
+      *ptr = parse_at (src, op);
+      return;
+    }
+  len = parse_reg (src, &mode, &(op->reg));
+  if (len)
+    {
+      *ptr = src + len;
+      op->type = mode;
+      return;
+    }
+  else
+    {
+      /* Not a reg, the only thing left is a displacement */
+      *ptr = parse_exp (src);
+      op->type = A_DISP_PC;
+      return;
+    }
+}
+
+static
+char *
+get_operands (info, args, operand)
+     sh_opcode_info *info;
+     char *args;
+     sh_operand_info *operand;
+
+{
+  char *ptr = args;
+  if (info->arg[0])
+    {
+      ptr++;
+
+      get_operand (&ptr, operand + 0);
+      if (info->arg[1])
+       {
+         if (*ptr == ',')
+           {
+             ptr++;
+           }
+         get_operand (&ptr, operand + 1);
+       }
+      else
+       {
+         operand[1].type = 0;
+       }
+    }
+  else
+    {
+      operand[0].type = 0;
+      operand[1].type = 0;
+    }
+  return ptr;
+}
+
+/* Passed a pointer to a list of opcodes which use different
+   addressing modes, return the opcode which matches the opcodes
+   provided
+   */
+
+static
+sh_opcode_info *
+get_specific (opcode, operands)
+     sh_opcode_info *opcode;
+     sh_operand_info *operands;
+{
+  sh_opcode_info *this_try = opcode;
+  char *name = opcode->name;
+  int arg_to_test = 0;
+  int n = 0;
+  while (opcode->name)
+    {
+      this_try = opcode++;
+      if (this_try->name != name)
+       {
+         /* We've looked so far down the table that we've run out of
+            opcodes with the same name */
+         return 0;
+       }
+      /* look at both operands needed by the opcodes and provided by
+        the user - since an arg test will often fail on the same arg
+        again and again, we'll try and test the last failing arg the
+        first on each opcode try */
+
+      for (n = 0; this_try->arg[n]; n++)
+       {
+         sh_operand_info *user = operands + arg_to_test;
+         sh_arg_type arg = this_try->arg[arg_to_test];
+         switch (arg)
+           {
+           case A_IMM:
+           case A_BDISP12:
+           case A_BDISP8:
+           case A_DISP_GBR:
+           case A_DISP_PC:
+           case A_MACH:
+           case A_PR:
+           case A_MACL:
+             if (user->type != arg)
+               goto fail;
+             break;
+           case A_R0:
+             /* opcode needs r0 */
+             if (user->type != A_REG_N || user->reg != 0)
+               goto fail;
+             break;
+           case A_R0_GBR:
+             if (user->type != A_R0_GBR || user->reg != 0)
+               goto fail;
+             break;
+
+           case A_REG_N:
+           case A_INC_N:
+           case A_DEC_N:
+           case A_IND_N:
+           case A_IND_R0_REG_N:
+           case A_DISP_REG_N:
+             /* Opcode needs rn */
+             if (user->type != arg)
+               goto fail;
+             reg_n = user->reg;
+             break;
+           case A_GBR:
+           case A_SR:
+           case A_VBR:
+             if (user->type != arg)
+               goto fail;
+             break;
+
+           case A_REG_M:
+           case A_INC_M:
+           case A_DEC_M:
+           case A_IND_M:
+           case A_IND_R0_REG_M:
+           case A_DISP_REG_M:
+             /* Opcode needs rn */
+             if (user->type != arg - A_REG_M + A_REG_N)
+               goto fail;
+             reg_m = user->reg;
+             break;
+           default:
+             printf ("unhandled %d\n", arg);
+             goto fail;
+           }
+         /* If we did 0, test 1 next, else 0 */
+         arg_to_test = 1 - arg_to_test;
+       }
+      return this_try;
+    fail:;
+    }
+
+  return 0;
+}
+
+int
+check (operand, low, high)
+     expressionS *operand;
+     int low;
+     int high;
+{
+  if (operand->X_seg != SEG_ABSOLUTE
+      || operand->X_add_number < low
+      || operand->X_add_number > high)
+    {
+      as_bad ("operand must be absolute in range %d..%d", low, high);
+    }
+  return operand->X_add_number;
+}
+
+
+static void
+insert (where, how, pcrel)
+     char *where;
+     int how;
+     int pcrel;
+{
+  fix_new (frag_now,
+          where - frag_now->fr_literal,
+          4,
+          immediate.X_add_symbol,
+          immediate.X_subtract_symbol,
+          immediate.X_add_number,
+          pcrel,
+          how);
+
+}
+
+static void
+build_relax (opcode)
+     sh_opcode_info *opcode;
+{
+  int len;
+  char *p;
+  if (opcode->arg[0] == A_BDISP8)
+    {
+      p = frag_var (rs_machine_dependent,
+                   md_relax_table[C (COND_JUMP, COND32)].rlx_length,
+                   len = md_relax_table[C (COND_JUMP, COND8)].rlx_length,
+                   C (COND_JUMP, 0),
+                   immediate.X_add_symbol,
+                   immediate.X_add_number,
+                   0);
+      p[0] = (opcode->nibbles[0] << 4) | (opcode->nibbles[1]);
+    }
+  else if (opcode->arg[0] == A_BDISP12)
+    {
+      p = frag_var (rs_machine_dependent,
+                   md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_length,
+                len = md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_length,
+                   C (UNCOND_JUMP, 0),
+                   immediate.X_add_symbol,
+                   immediate.X_add_number,
+                   0);
+      p[0] = (opcode->nibbles[0] << 4);
+    }
+
+}
+
+/* Now we know what sort of opcodes it is, lets build the bytes -
+ */
+static void
+build_Mytes (opcode, operand)
+     sh_opcode_info *opcode;
+     sh_operand_info *operand;
+
+{
+  int index;
+  char nbuf[4];
+  char *output = frag_more (2);
+
+  nbuf[0] = 0;
+  nbuf[1] = 0;
+  nbuf[2] = 0;
+  nbuf[3] = 0;
+
+  for (index = 0; index < 4; index++)
+    {
+      sh_nibble_type i = opcode->nibbles[index];
+      if (i < 16)
+       {
+         nbuf[index] = i;
+       }
+      else
+       {
+         switch (i)
+           {
+           case REG_N:
+             nbuf[index] = reg_n;
+             break;
+           case REG_M:
+             nbuf[index] = reg_m;
+             break;
+           case DISP_4:
+             insert (output + 1, R_SH_IMM4, 0);
+             break;
+           case IMM_4BY4:
+             insert (output + 1, R_SH_IMM4BY4, 0);
+             break;
+           case IMM_4BY2:
+             insert (output + 1, R_SH_IMM4BY2, 0);
+             break;
+           case IMM_4:
+             insert (output + 1, R_SH_IMM4, 0);
+             break;
+           case IMM_8BY4:
+             insert (output + 1, R_SH_IMM8BY4, 0);
+             break;
+           case IMM_8BY2:
+             insert (output + 1, R_SH_IMM8BY2, 0);
+             break;
+           case IMM_8:
+             insert (output + 1, R_SH_IMM8, 0);
+             break;
+           case PCRELIMM_8BY4:
+             insert (output + 1, R_SH_PCRELIMM8BY4, 0);
+             break;
+           case PCRELIMM_8BY2:
+             insert (output + 1, R_SH_PCRELIMM8BY2, 0);
+             break;
+           default:
+             printf ("failed for %d\n", i);
+           }
+       }
+    }
+  output[0] = (nbuf[0] << 4) | (nbuf[1]);
+  output[1] = (nbuf[2] << 4) | (nbuf[3]);
+}
+
+/* This is the guts of the machine-dependent assembler.  STR points to a
+   machine dependent instruction.  This function is supposed to emit
+   the frags/bytes it assembles to.
+   */
+
+void
+md_assemble (str)
+     char *str;
+{
+  unsigned char *op_start;
+  unsigned char *op_end;
+  sh_operand_info operand[2];
+  sh_opcode_info *opcode;
+  unsigned char *name;
+
+  int nlen = 0;
+
+  /* Drop leading whitespace */
+  while (*str == ' ')
+    str++;
+
+  /* find the op code end */
+  for (name = op_start = op_end = (unsigned char *) (str);
+       *op_end &&
+       !is_end_of_line[*op_end] && *op_end != ' ';
+       op_end++)
+    {
+      nlen++;
+    }
+  name[nlen] = 0;
+
+  if (op_end == op_start)
+    {
+      as_bad ("can't find opcode ");
+    }
+
+  opcode = (sh_opcode_info *) hash_find (opcode_hash_control, name);
+
+  if (opcode == NULL)
+    {
+      as_bad ("unknown opcode");
+      return;
+    }
+
+  if (opcode->arg[0] == A_BDISP12
+      || opcode->arg[0] == A_BDISP8)
+    {
+      input_line_pointer = parse_exp (op_end + 1);
+      build_relax (opcode);
+    }
+  else
+    {
+      input_line_pointer = get_operands (opcode, op_end, operand);
+
+      opcode = get_specific (opcode, operand);
+
+      if (opcode == 0)
+       {
+         /* Couldn't find an opcode which matched the operands */
+         char *where = frag_more (2);
+
+         where[0] = 0x0;
+         where[1] = 0x0;
+         as_bad ("invalid operands for opcode");
+         return;
+       }
+
+      build_Mytes (opcode, operand);
+    }
+
+}
+
+void
+DEFUN (tc_crawl_symbol_chain, (headers),
+       object_headers * headers)
+{
+  printf ("call to tc_crawl_symbol_chain \n");
+}
+
+symbolS *
+DEFUN (md_undefined_symbol, (name),
+       char *name)
+{
+  return 0;
+}
+
+void
+DEFUN (tc_headers_hook, (headers),
+       object_headers * headers)
+{
+  printf ("call to tc_headers_hook \n");
+}
+
+void
+DEFUN_VOID (md_end)
+{
+}
+
+/* Various routines to kill one day */
+/* Equal to MAX_PRECISION in atof-ieee.c */
+#define MAX_LITTLENUMS 6
+
+/* Turn a string in input_line_pointer into a floating point constant of type
+   type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
+   emitted is stored in *sizeP .  An error message is returned, or NULL on OK.
+   */
+char *
+md_atof (type, litP, sizeP)
+     char type;
+     char *litP;
+     int *sizeP;
+{
+  int prec;
+  LITTLENUM_TYPE words[MAX_LITTLENUMS];
+  LITTLENUM_TYPE *wordP;
+  char *t;
+  char *atof_ieee ();
+
+  switch (type)
+    {
+    case 'f':
+    case 'F':
+    case 's':
+    case 'S':
+      prec = 2;
+      break;
+
+    case 'd':
+    case 'D':
+    case 'r':
+    case 'R':
+      prec = 4;
+      break;
+
+    case 'x':
+    case 'X':
+      prec = 6;
+      break;
+
+    case 'p':
+    case 'P':
+      prec = 6;
+      break;
+
+    default:
+      *sizeP = 0;
+      return "Bad call to MD_NTOF()";
+    }
+  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, (long) (*wordP++), sizeof (LITTLENUM_TYPE));
+      litP += sizeof (LITTLENUM_TYPE);
+    }
+  return "";                   /* Someone should teach Dean about null pointers */
+}
+
+int
+md_parse_option (argP, cntP, vecP)
+     char **argP;
+     int *cntP;
+     char ***vecP;
+
+{
+  if (!strcmp (*argP, "relax"))
+    {
+      relax = 1;
+      **argP = 0;
+    }
+  return 1;
+}
+
+int md_short_jump_size;
+
+void
+tc_Nout_fix_to_chars ()
+{
+  printf ("call to tc_Nout_fix_to_chars \n");
+  abort ();
+}
+
+void
+md_create_short_jump (ptr, from_Nddr, to_Nddr, frag, to_symbol)
+     char *ptr;
+     addressT from_Nddr;
+     addressT to_Nddr;
+     fragS *frag;
+     symbolS *to_symbol;
+{
+  as_fatal ("failed sanity check.");
+}
+
+void
+md_create_long_jump (ptr, from_Nddr, to_Nddr, frag, to_symbol)
+     char *ptr;
+     addressT from_Nddr, to_Nddr;
+     fragS *frag;
+     symbolS *to_symbol;
+{
+  as_fatal ("failed sanity check.");
+}
+
+/*
+called after relaxing, change the frags so they know how big they are
+*/
+void
+md_convert_frag (headers, fragP)
+     object_headers *headers;
+     fragS *fragP;
+
+{
+  unsigned char *buffer = (unsigned char *) (fragP->fr_fix + fragP->fr_literal);
+  int donerelax = 0;
+  int targ_addr = ((fragP->fr_symbol ? S_GET_VALUE (fragP->fr_symbol) : 0) + fragP->fr_offset);
+  switch (fragP->fr_subtype)
+    {
+    case C (COND_JUMP, COND8):
+      {
+       /* Get the address of the end of the instruction */
+       int next_inst = fragP->fr_fix + fragP->fr_address + 2;
+
+       int disp = targ_addr - next_inst - 2;
+       disp /= 2;
+       md_number_to_chars (buffer + 1, disp, 1);
+       fragP->fr_fix += 2;
+       fragP->fr_var = 0;
+      }
+      break;
+
+    case C (UNCOND_JUMP, UNCOND12):
+      {
+       /* Get the address of the end of the instruction */
+       int next_inst = fragP->fr_fix + fragP->fr_address + 2;
+
+       int t;
+       int disp = targ_addr - next_inst - 2;
+
+       disp /= 2;
+       t = buffer[0] & 0xf0;
+       md_number_to_chars (buffer, disp, 2);
+       buffer[0] = (buffer[0] & 0xf) | t;
+       fragP->fr_fix += 2;
+       fragP->fr_var = 0;
+      }
+      break;
+
+    case C (UNCOND_JUMP, UNCOND32):
+    case C (UNCOND_JUMP, UNDEF_WORD_DISP):
+      {
+       /* A jump wont fit in 12 bits, make code which looks like
+          bra foo
+          mov.w @(0, PC), r14
+          .long disp
+          foo: bra @r14
+          */
+
+       int next_inst =
+       fragP->fr_fix + fragP->fr_address + UNCOND32_LENGTH;
+
+       int disp = targ_addr - next_inst;
+       int t = buffer[0] & 0x10;
+
+       disp /= 2;
+
+       buffer[0] = 0xa0;       /* branch over move and disp */
+       buffer[1] = 3;
+       buffer[2] = 0xd0 | JREG;/* Build mov insn */
+       buffer[3] = 0x00;
+
+       buffer[4] = 0;          /* space for 32 bit jump disp */
+       buffer[5] = 0;
+       buffer[6] = 0;
+       buffer[7] = 0;
+
+       buffer[10] = 0x40 | JREG;       /* Build jmp @JREG */
+       buffer[11] = t ? 0xb : 0x2b;
+
+       buffer[12] = 0x20;      /* build nop */
+       buffer[13] = 0x0b;
+
+       /* Make reloc for the long disp */
+       fix_new (fragP,
+                fragP->fr_fix + 4,
+                4,
+                fragP->fr_symbol,
+                0,
+                fragP->fr_offset,
+                0,
+                R_SH_IMM32);
+       fragP->fr_fix += UNCOND32_LENGTH;
+       fragP->fr_var = 0;
+       donerelax = 1;
+
+      }
+      break;
+
+    case C (COND_JUMP, COND12):
+      {
+       /* A bcond won't fit, so turn it into a b!cond; bra disp; nop */
+       int next_inst =
+       fragP->fr_fix + fragP->fr_address + 6;
+
+       int disp = targ_addr - next_inst;
+       disp /= 2;
+       md_number_to_chars (buffer + 2, disp, 2);
+       buffer[0] ^= 0x2;       /* Toggle T/F bit */
+       buffer[1] = 1;          /* branch over jump and nop */
+       buffer[2] = (buffer[2] & 0xf) | 0xa0;   /* Build jump insn */
+       buffer[4] = 0x20;       /* Build nop */
+       buffer[5] = 0x0b;
+       fragP->fr_fix += 6;
+       fragP->fr_var = 0;
+       donerelax = 1;
+      }
+      break;
+
+    case C (COND_JUMP, COND32):
+    case C (COND_JUMP, UNDEF_WORD_DISP):
+      {
+       /* A bcond won't fit and it won't go into a 12 bit
+          displacement either, the code sequence looks like:
+          b!cond foop
+          mov.w @(n, PC), r14
+          jmp  @r14
+          nop
+          .long where
+          foop:
+          */
+
+       int next_inst =
+       fragP->fr_fix + fragP->fr_address + COND32_LENGTH;
+
+       int disp = targ_addr - next_inst;
+       disp /= 2;
+
+       buffer[0] ^= 0x2;       /* Toggle T/F bit */
+#define JREG 14
+       buffer[1] = 5;          /* branch over mov, jump, nop and ptr */
+       buffer[2] = 0xd0 | JREG;/* Build mov insn */
+       buffer[3] = 0x2;
+       buffer[4] = 0x40 | JREG;/* Build jmp @JREG */
+       buffer[5] = 0x0b;
+       buffer[6] = 0x20;       /* build nop */
+       buffer[7] = 0x0b;
+       buffer[8] = 0;          /* space for 32 bit jump disp */
+       buffer[9] = 0;
+       buffer[10] = 0;
+       buffer[11] = 0;
+       buffer[12] = 0;
+       buffer[13] = 0;
+       /* Make reloc for the long disp */
+       fix_new (fragP,
+                fragP->fr_fix + 8,
+                4,
+                fragP->fr_symbol,
+                0,
+                fragP->fr_offset,
+                0,
+                R_SH_IMM32);
+       fragP->fr_fix += COND32_LENGTH;
+       fragP->fr_var = 0;
+       donerelax = 1;
+      }
+      break;
+
+    default:
+      abort ();
+    }
+
+  if (donerelax && !relax)
+    {
+      as_bad ("Offset doesn't fit at 0x%x, trying to get to 0x%x",
+             fragP->fr_address,
+             targ_addr);
+    }
+
+}
+
+valueT
+DEFUN (md_section_align, (seg, size),
+       segT seg AND
+       valueT size)
+{
+  return ((size + (1 << section_alignment[(int) seg]) - 1)
+         & (-1 << section_alignment[(int) seg]));
+
+}
+
+void
+md_apply_fix (fixP, val)
+     fixS *fixP;
+     long val;
+{
+  char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+  int addr = fixP->fx_frag->fr_address + fixP->fx_where;
+  if (fixP->fx_r_type == 0)
+    {
+      fixP->fx_r_type = R_SH_IMM32;
+    }
+
+  switch (fixP->fx_r_type)
+    {
+
+    case R_SH_IMM4:
+      *buf = (*buf & 0xf0) | (val & 0xf);
+      break;
+
+    case R_SH_IMM4BY2:
+      *buf = (*buf & 0xf0) | ((val >> 1) & 0xf);
+      break;
+
+    case R_SH_IMM4BY4:
+      *buf = (*buf & 0xf0) | ((val >> 2) & 0xf);
+      break;
+
+    case R_SH_IMM8BY2:
+      *buf = val >> 1;
+      break;
+
+    case R_SH_IMM8BY4:
+      *buf = val >> 2;
+      break;
+
+    case R_SH_IMM8:
+      *buf++ = val;
+      break;
+
+    case R_SH_PCRELIMM8BY4:
+      addr &= ~1;
+
+      if (val & 0x3)
+       as_warn ("non aligned displacement at %x\n", addr);
+      val -= (addr + 4);
+      val += 3;
+      val /= 4;
+      if (val & ~0xff)
+       as_warn ("pcrel too far at %x\n", addr);
+
+      *buf = val;
+      break;
+
+    case R_SH_PCRELIMM8BY2:
+      addr &= ~1;
+      if (val & 0x1)
+       as_bad ("odd displacement at %x\n", addr);
+      val -= (addr + 4);
+      val++;
+      val /= 2;
+      if (val & ~0xff)
+       as_warn ("pcrel too far at %x\n", addr);
+      *buf = val;
+      break;
+
+    case R_SH_IMM32:
+      *buf++ = val >> 24;
+      *buf++ = val >> 16;
+      *buf++ = val >> 8;
+      *buf++ = val >> 0;
+      break;
+
+    default:
+      abort ();
+    }
+}
+
+void
+DEFUN (md_operand, (expressionP), expressionS * expressionP)
+{
+}
+
+int md_long_jump_size;
+
+/*
+called just before address relaxation, return the length
+by which a fragment must grow to reach it's destination
+*/
+int
+md_estimate_size_before_relax (fragP, segment_type)
+     register fragS *fragP;
+     register segT segment_type;
+{
+  switch (fragP->fr_subtype)
+    {
+    case C (UNCOND_JUMP, UNDEF_DISP):
+      /* used to be a branch to somewhere which was unknown */
+      if (!fragP->fr_symbol)
+       {
+         fragP->fr_subtype = C (UNCOND_JUMP, UNCOND12);
+         fragP->fr_var = md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_length;
+       }
+      else if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
+       {
+         fragP->fr_subtype = C (UNCOND_JUMP, UNCOND12);
+         fragP->fr_var = md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_length;
+       }
+      else
+       {
+         fragP->fr_subtype = C (UNCOND_JUMP, UNDEF_WORD_DISP);
+         fragP->fr_var = md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_length;
+         return md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_length;
+       }
+      break;
+
+    default:
+      abort ();
+    case C (COND_JUMP, UNDEF_DISP):
+      /* used to be a branch to somewhere which was unknown */
+      if (fragP->fr_symbol
+         && S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
+       {
+         /* Got a symbol and it's defined in this segment, become byte
+        sized - maybe it will fix up */
+         fragP->fr_subtype = C (COND_JUMP, COND8);
+         fragP->fr_var = md_relax_table[C (COND_JUMP, COND8)].rlx_length;
+       }
+      else if (fragP->fr_symbol)
+       {
+         /* Its got a segment, but its not ours, so it will always be long */
+         fragP->fr_subtype = C (COND_JUMP, UNDEF_WORD_DISP);
+         fragP->fr_var = md_relax_table[C (COND_JUMP, COND32)].rlx_length;
+         return md_relax_table[C (COND_JUMP, COND32)].rlx_length;
+       }
+      else
+       {
+         /* We know the abs value */
+         fragP->fr_subtype = C (COND_JUMP, COND8);
+         fragP->fr_var = md_relax_table[C (COND_JUMP, COND8)].rlx_length;
+       }
+
+      break;
+    }
+  return fragP->fr_var;
+}
+
+/* Put number into target byte order */
+
+void
+md_number_to_chars (ptr, use, nbytes)
+     char *ptr;
+     valueT use;
+     int nbytes;
+{
+  switch (nbytes)
+    {
+    case 4:
+      *ptr++ = (use >> 24) & 0xff;
+    case 3:
+      *ptr++ = (use >> 16) & 0xff;
+    case 2:
+      *ptr++ = (use >> 8) & 0xff;
+    case 1:
+      *ptr++ = (use >> 0) & 0xff;
+      break;
+    default:
+      abort ();
+    }
+}
+long
+md_pcrel_from (fixP)
+     fixS *fixP;
+
+{
+  int gap = fixP->fx_size + fixP->fx_where +
+  fixP->fx_frag->fr_address;
+  return gap;
+}
+
+void
+tc_coff_symbol_emit_hook ()
+{
+}
+
+short
+tc_coff_fix2rtype (fix_ptr)
+     fixS *fix_ptr;
+{
+  return fix_ptr->fx_r_type;
+}
+
+void
+tc_reloc_mangle (fix_ptr, intr, base)
+     fixS *fix_ptr;
+     struct internal_reloc *intr;
+     bfd_vma base;
+
+{
+  symbolS *symbol_ptr;
+
+  symbol_ptr = fix_ptr->fx_addsy;
+
+  /* If this relocation is attached to a symbol then it's ok
+     to output it */
+  if (fix_ptr->fx_r_type == RELOC_32)
+    {
+      /* cons likes to create reloc32's whatever the size of the reloc..
+       */
+      switch (fix_ptr->fx_size)
+       {
+       case 2:
+         intr->r_type = R_IMM16;
+         break;
+       case 1:
+         intr->r_type = R_IMM8;
+         break;
+       default:
+         abort ();
+       }
+    }
+  else
+    {
+      intr->r_type = fix_ptr->fx_r_type;
+    }
+
+  intr->r_vaddr = fix_ptr->fx_frag->fr_address + fix_ptr->fx_where + base;
+  intr->r_offset = fix_ptr->fx_offset;
+
+  /* Turn the segment of the symbol into an offset.  */
+  if (symbol_ptr)
+    {
+      symbolS *dot;
+
+      dot = segment_info[S_GET_SEGMENT (symbol_ptr)].dot;
+      if (dot)
+       {
+         intr->r_offset += S_GET_VALUE (symbol_ptr);
+         intr->r_symndx = dot->sy_number;
+       }
+      else
+       {
+         intr->r_symndx = symbol_ptr->sy_number;
+       }
+    }
+  else
+    {
+      intr->r_symndx = -1;
+    }
+}
+
+int
+tc_coff_sizemachdep (frag)
+     fragS *frag;
+{
+  return md_relax_table[frag->fr_subtype].rlx_length;
+}
+
+
+/* end of tc-sh.c */
index 689762334ee18aa0c8f700517b7f3a3f273401f8..7bd97b583872669304136d71e62e1391bea991f6 100644 (file)
@@ -455,11 +455,11 @@ md_parse_option (argP, cntP, vecP)
 void                           /* Knows about order of bytes in address. */
 md_number_to_chars (con, value, nbytes)
      char con[];               /* Return 'nbytes' of chars here. */
-     long int value;           /* The value of the bits. */
+     valueT value;             /* The value of the bits. */
      int nbytes;               /* Number of bytes in the output. */
 {
   int n = nbytes;
-  long int v = value;
+  valueT v = value;
 
   con += nbytes - 1;           /* Tahoes is (Bleah!) big endian */
   while (nbytes--)
@@ -595,11 +595,11 @@ const int md_short_jump_size = 3;
 void
 md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
      char *ptr;
-     long from_addr, to_addr;
+     addressT from_addr, to_addr;
      fragS *frag;
      symbolS *to_symbol;
 {
-  long offset;
+  valueT offset;
 
   offset = to_addr - (from_addr + 1);
   *ptr++ = TAHOE_BRW;
@@ -612,11 +612,11 @@ const int md_reloc_size = 8;      /* Size of relocation record */
 void
 md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
      char *ptr;
-     long from_addr, to_addr;
+     addressT from_addr, to_addr;
      fragS *frag;
      symbolS *to_symbol;
 {
-  long offset;
+  valueT offset;
 
   offset = to_addr - (from_addr + 4);
   *ptr++ = TAHOE_JMP;
@@ -2044,10 +2044,10 @@ md_operand (expressionP)
 }                              /* md_operand() */
 
 /* Round up a section size to the appropriate boundary. */
-long 
+valueT
 md_section_align (segment, size)
      segT segment;
-     long size;
+     valueT size;
 {
   return ((size + 7) & ~7);    /* Round all sects to multiple of 8 */
 }                              /* md_section_align() */
index 3d76647c5b933047f24022c0ebb87a94f4b53948..38896ed255ac2adf5883fe071447283f23d7779f 100644 (file)
@@ -289,11 +289,11 @@ md_end ()
 void                           /* Knows about order of bytes in address. */
 md_number_to_chars (con, value, nbytes)
      char con[];               /* Return 'nbytes' of chars here. */
-     long value;               /* The value of the bits. */
+     valueT value;             /* The value of the bits. */
      int nbytes;               /* Number of bytes in the output. */
 {
   int n;
-  long v;
+  valueT v;
 
   n = nbytes;
   v = value;
@@ -3175,11 +3175,11 @@ const int md_reloc_size = 8;    /* Size of relocation record */
 void
 md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
      char *ptr;
-     long from_addr, to_addr;
+     addressT from_addr, to_addr;
      fragS *frag;
      symbolS *to_symbol;
 {
-  long offset;
+  valueT offset;
 
   offset = to_addr - (from_addr + 1);
   *ptr++ = 0x31;
@@ -3189,11 +3189,11 @@ md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
 void
 md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
      char *ptr;
-     long from_addr, to_addr;
+     addressT from_addr, to_addr;
      fragS *frag;
      symbolS *to_symbol;
 {
-  long offset;
+  valueT offset;
 
   offset = to_addr - S_GET_VALUE (to_symbol);
   *ptr++ = 0x17;
@@ -3258,10 +3258,13 @@ md_parse_option (argP, cntP, vecP)
       as_warn ("I don't use an interpass file! -V ignored");
       break;
 
-#ifdef VMS
+#ifdef OBJ_VMS
     case '+':                  /* For g++ */
       break;
 
+    case '1':                  /* For backward compatibility */
+      break;
+               
     case 'h':                  /* No hashing of mixed-case names */
       break;
 
@@ -3298,10 +3301,10 @@ md_operand (expressionP)
 }
 
 /* Round up a section size to the appropriate boundary.  */
-long
+valueT
 md_section_align (segment, size)
      segT segment;
-     long size;
+     valueT size;
 {
   return size;                 /* Byte alignment is fine */
 }
index 44eaeeb0ffcbce0e6abaae43b4469843a3ccd6e3..2fcc3f13a8e826c7b9a104bb2c03594018bcf753 100644 (file)
 #include "../opcodes/z8k-opc.h"
 
 #include "as.h"
-#include "read.h"
 #include "bfd.h"
 #include <ctype.h>
-#include "listing.h"
 
 const char comment_chars[] =
 {'!', 0};
@@ -41,7 +39,7 @@ const char line_comment_chars[] = { '#', 0};
 extern int machine;
 extern int coff_flags;
 int segmented_mode;
-int md_reloc_size;
+const int md_reloc_size;
 
 /* This table describes all the machine specific pseudo-ops the assembler
    has to support.  The fields are:
@@ -1170,8 +1168,8 @@ tc_aout_fix_to_chars ()
 void
 md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
      char *ptr;
-     long from_addr;
-     long to_addr;
+     addressT from_addr;
+     addressT to_addr;
      fragS *frag;
      symbolS *to_symbol;
 {
@@ -1181,7 +1179,7 @@ md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
 void
 md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
      char *ptr;
-     long from_addr, to_addr;
+     addressT from_addr, to_addr;
      fragS *frag;
      symbolS *to_symbol;
 {
@@ -1198,10 +1196,10 @@ md_convert_frag (headers, fragP)
   abort ();
 }
 
-long
+valueT
 DEFUN (md_section_align, (seg, size),
        segT seg AND
-       long size)
+       valueT size)
 {
   return ((size + (1 << section_alignment[(int) seg]) - 1) & (-1 << section_alignment[(int) seg]));
 
@@ -1274,7 +1272,7 @@ md_estimate_size_before_relax (fragP, segment_type)
 void
 DEFUN (md_number_to_chars, (ptr, use, nbytes),
        char *ptr AND
-       long use AND
+       valueT use AND
        int nbytes)
 {
   switch (nbytes)