This commit was manufactured by cvs2svn to create branch 'binutils-
[external/binutils.git] / gas / config / tc-d10v.c
index a5360a9..8ba4f30 100644 (file)
@@ -1,12 +1,13 @@
 /* tc-d10v.c -- Assembler code for the Mitsubishi D10V
-   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006,
+   2007, 2009, 2010
    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)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
 
    You should have received a copy of the GNU General Public License
    along with GAS; see the file COPYING.  If not, write to
-   the Free Software Foundation, 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   the Free Software Foundation, 51 Franklin Street - Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
 
-#include <stdio.h>
 #include "as.h"
 #include "safe-ctype.h"
 #include "subsegs.h"
 #include "opcode/d10v.h"
 #include "elf/ppc.h"
+#include "dwarf2dbg.h"
 
-const char comment_chars[] = ";";
-const char line_comment_chars[] = "#";
+const char comment_chars[]        = ";";
+const char line_comment_chars[]   = "#";
 const char line_separator_chars[] = "";
-const char *md_shortopts = "O";
-const char EXP_CHARS[] = "eE";
-const char FLT_CHARS[] = "dD";
+const char *md_shortopts          = "O";
+const char EXP_CHARS[]            = "eE";
+const char FLT_CHARS[]            = "dD";
 
 int Optimizing = 0;
 
@@ -42,7 +43,8 @@ int Optimizing = 0;
 #define AT_WORD_RIGHT_SHIFT 2
 
 /* Fixups.  */
-#define MAX_INSN_FIXUPS (5)
+#define MAX_INSN_FIXUPS  5
+
 struct d10v_fixup
 {
   expressionS exp;
@@ -80,40 +82,19 @@ static bfd_boolean flag_warn_suppress_instructionswap;
 static bfd_boolean flag_allow_gstabs_packing = 1;
 
 /* Local functions.  */
-static int reg_name_search PARAMS ((char *name));
-static int register_name PARAMS ((expressionS *expressionP));
-static int check_range PARAMS ((unsigned long num, int bits, int flags));
-static int postfix PARAMS ((char *p));
-static bfd_reloc_code_real_type get_reloc PARAMS ((struct d10v_operand *op));
-static int get_operands PARAMS ((expressionS exp[]));
-static struct d10v_opcode *find_opcode PARAMS ((struct d10v_opcode *opcode, expressionS ops[]));
-static unsigned long build_insn PARAMS ((struct d10v_opcode *opcode, expressionS *opers, unsigned long insn));
-static void write_long PARAMS ((unsigned long insn, Fixups *fx));
-static void write_1_short PARAMS ((struct d10v_opcode *opcode, unsigned long insn, Fixups *fx));
-static int write_2_short PARAMS ((struct d10v_opcode *opcode1, unsigned long insn1,
-                                 struct d10v_opcode *opcode2, unsigned long insn2, packing_type exec_type, Fixups *fx));
-static unsigned long do_assemble PARAMS ((char *str, struct d10v_opcode **opcode));
-static unsigned long d10v_insert_operand PARAMS (( unsigned long insn, int op_type,
-                                                  offsetT value, int left, fixS *fix));
-static int parallel_ok PARAMS ((struct d10v_opcode *opcode1, unsigned long insn1,
-                               struct d10v_opcode *opcode2, unsigned long insn2,
-                               packing_type exec_type));
-
-static void check_resource_conflict PARAMS ((struct d10v_opcode *opcode1,
-                                            unsigned long insn1,
-                                            struct d10v_opcode *opcode2,
-                                            unsigned long insn2));
-
-static symbolS * find_symbol_matching_register PARAMS ((expressionS *));
+
+enum options
+{
+  OPTION_NOWARNSWAP = OPTION_MD_BASE,
+  OPTION_GSTABSPACKING,
+  OPTION_NOGSTABSPACKING
+};
 
 struct option md_longopts[] =
 {
-#define OPTION_NOWARNSWAP (OPTION_MD_BASE)
   {"nowarnswap", no_argument, NULL, OPTION_NOWARNSWAP},
-#define OPTION_GSTABSPACKING (OPTION_MD_BASE + 1)
   {"gstabspacking",  no_argument, NULL, OPTION_GSTABSPACKING},
   {"gstabs-packing", no_argument, NULL, OPTION_GSTABSPACKING},
-#define OPTION_NOGSTABSPACKING (OPTION_MD_BASE + 2)
   {"nogstabspacking",   no_argument, NULL, OPTION_NOGSTABSPACKING},
   {"no-gstabs-packing", no_argument, NULL, OPTION_NOGSTABSPACKING},
   {NULL, no_argument, NULL, 0}
@@ -121,15 +102,6 @@ struct option md_longopts[] =
 
 size_t md_longopts_size = sizeof (md_longopts);
 
-static void d10v_dot_word PARAMS ((int));
-
-/* The target specific pseudo-ops which we support.  */
-const pseudo_typeS md_pseudo_table[] =
-{
-  { "word",    d10v_dot_word,  2 },
-  { NULL,       NULL,           0 }
-};
-
 /* Opcode hash table.  */
 static struct hash_control *d10v_hash;
 
@@ -138,8 +110,7 @@ static struct hash_control *d10v_hash;
    array on success, or -1 on failure.  */
 
 static int
-reg_name_search (name)
-     char *name;
+reg_name_search (char *name)
 {
   int middle, low, high;
   int cmp;
@@ -166,8 +137,7 @@ reg_name_search (name)
    to see if it is a valid register name.  */
 
 static int
-register_name (expressionP)
-     expressionS *expressionP;
+register_name (expressionS *expressionP)
 {
   int reg_number;
   char c, *p = input_line_pointer;
@@ -197,10 +167,7 @@ register_name (expressionP)
 }
 
 static int
-check_range (num, bits, flags)
-     unsigned long num;
-     int bits;
-     int flags;
+check_range (unsigned long num, int bits, int flags)
 {
   long min, max;
   int retval = 0;
@@ -246,8 +213,7 @@ check_range (num, bits, flags)
 }
 
 void
-md_show_usage (stream)
-     FILE *stream;
+md_show_usage (FILE *stream)
 {
   fprintf (stream, _("D10V options:\n\
 -O                      Optimize.  Will do some operations in parallel.\n\
@@ -258,9 +224,7 @@ md_show_usage (stream)
 }
 
 int
-md_parse_option (c, arg)
-     int c;
-     char *arg ATTRIBUTE_UNUSED;
+md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
 {
   switch (c)
     {
@@ -284,75 +248,34 @@ md_parse_option (c, arg)
 }
 
 symbolS *
-md_undefined_symbol (name)
-     char *name ATTRIBUTE_UNUSED;
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
 {
   return 0;
 }
 
-/* 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)
-     int type;
-     char *litP;
-     int *sizeP;
+md_atof (int type, char *litP, int *sizeP)
 {
-  int prec;
-  LITTLENUM_TYPE words[4];
-  char *t;
-  int i;
-
-  switch (type)
-    {
-    case 'f':
-      prec = 2;
-      break;
-    case 'd':
-      prec = 4;
-      break;
-    default:
-      *sizeP = 0;
-      return _("bad call to md_atof");
-    }
-
-  t = atof_ieee (input_line_pointer, type, words);
-  if (t)
-    input_line_pointer = t;
-
-  *sizeP = prec * 2;
-
-  for (i = 0; i < prec; i++)
-    {
-      md_number_to_chars (litP, (valueT) words[i], 2);
-      litP += 2;
-    }
-  return NULL;
+  return ieee_md_atof (type, litP, sizeP, TRUE);
 }
 
 void
-md_convert_frag (abfd, sec, fragP)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     asection *sec ATTRIBUTE_UNUSED;
-     fragS *fragP ATTRIBUTE_UNUSED;
+md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
+                asection *sec ATTRIBUTE_UNUSED,
+                fragS *fragP ATTRIBUTE_UNUSED)
 {
   abort ();
 }
 
 valueT
-md_section_align (seg, addr)
-     asection *seg;
-     valueT addr;
+md_section_align (asection *seg, valueT addr)
 {
   int align = bfd_get_section_alignment (stdoutput, seg);
   return ((addr + (1 << align) - 1) & (-1 << align));
 }
 
 void
-md_begin ()
+md_begin (void)
 {
   char *prev_name = "";
   struct d10v_opcode *opcode;
@@ -381,8 +304,7 @@ md_begin ()
    from an expression.  */
 
 static int
-postfix (p)
-     char *p;
+postfix (char *p)
 {
   while (*p != '-' && *p != '+')
     {
@@ -394,42 +316,40 @@ postfix (p)
   if (*p == '-')
     {
       *p = ' ';
-      return (-1);
+      return -1;
     }
   if (*p == '+')
     {
       *p = ' ';
-      return (1);
+      return 1;
     }
 
-  return (0);
+  return 0;
 }
 
 static bfd_reloc_code_real_type
-get_reloc (op)
-     struct d10v_operand *op;
+get_reloc (struct d10v_operand *op)
 {
   int bits = op->bits;
 
   if (bits <= 4)
-    return (0);
+    return 0;
 
   if (op->flags & OPERAND_ADDR)
     {
       if (bits == 8)
-       return (BFD_RELOC_D10V_10_PCREL_R);
+       return BFD_RELOC_D10V_10_PCREL_R;
       else
-       return (BFD_RELOC_D10V_18_PCREL);
+       return BFD_RELOC_D10V_18_PCREL;
     }
 
-  return (BFD_RELOC_16);
+  return BFD_RELOC_16;
 }
 
 /* Parse a string of operands.  Return an array of expressions.  */
 
 static int
-get_operands (exp)
-     expressionS exp[];
+get_operands (expressionS exp[])
 {
   char *p = input_line_pointer;
   int numops = 0;
@@ -561,16 +481,15 @@ get_operands (exp)
     }
 
   exp[numops].X_op = 0;
-  return (numops);
+  return numops;
 }
 
 static unsigned long
-d10v_insert_operand (insn, op_type, value, left, fix)
-     unsigned long insn;
-     int op_type;
-     offsetT value;
-     int left;
-     fixS *fix;
+d10v_insert_operand (unsigned long insn,
+                    int op_type,
+                    offsetT value,
+                    int left,
+                    fixS *fix)
 {
   int shift, bits;
 
@@ -595,10 +514,9 @@ d10v_insert_operand (insn, op_type, value, left, fix)
    array of operand expressions.  Return the instruction.  */
 
 static unsigned long
-build_insn (opcode, opers, insn)
-     struct d10v_opcode *opcode;
-     expressionS *opers;
-     unsigned long insn;
+build_insn (struct d10v_opcode *opcode,
+           expressionS *opers,
+           unsigned long insn)
 {
   int i, bits, shift, flags, format;
   unsigned long number;
@@ -689,13 +607,12 @@ build_insn (opcode, opers, insn)
 /* Write out a long form instruction.  */
 
 static void
-write_long (insn, fx)
-     unsigned long insn;
-     Fixups *fx;
+write_long (unsigned long insn, Fixups *fx)
 {
   int i, where;
   char *f = frag_more (4);
 
+  dwarf2_emit_insn (4);
   insn |= FM11;
   number_to_chars_bigendian (f, insn, 4);
 
@@ -724,14 +641,14 @@ write_long (insn, fx)
 /* Write out a short form instruction by itself.  */
 
 static void
-write_1_short (opcode, insn, fx)
-     struct d10v_opcode *opcode;
-     unsigned long insn;
-     Fixups *fx;
+write_1_short (struct d10v_opcode *opcode,
+              unsigned long insn,
+              Fixups *fx)
 {
   char *f = frag_more (4);
   int i, where;
 
+  dwarf2_emit_insn (4);
   if (opcode->exec_type & PARONLY)
     as_fatal (_("Instruction must be executed in parallel with another instruction."));
 
@@ -771,210 +688,55 @@ write_1_short (opcode, insn, fx)
   fx->fc = 0;
 }
 
-/* Expects two short instructions.
-   If possible, writes out both as a single packed instruction.
-   Otherwise, writes out the first one, packed with a NOP.
-   Returns number of instructions not written out.  */
+/* Determine if there are any resource conflicts among two manually
+   parallelized instructions.  Some of this was lifted from parallel_ok.  */
 
-static int
-write_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx)
-     struct d10v_opcode *opcode1, *opcode2;
-     unsigned long insn1, insn2;
-     packing_type exec_type;
-     Fixups *fx;
+static void
+check_resource_conflict (struct d10v_opcode *op1,
+                        unsigned long insn1,
+                        struct d10v_opcode *op2,
+                        unsigned long insn2)
 {
-  unsigned long insn;
-  char *f;
-  int i, j, where;
-
-  if ((exec_type != PACK_PARALLEL)
-      && ((opcode1->exec_type & PARONLY) || (opcode2->exec_type & PARONLY)))
-    as_fatal (_("Instruction must be executed in parallel"));
-
-  if ((opcode1->format & LONG_OPCODE) || (opcode2->format & LONG_OPCODE))
-    as_fatal (_("Long instructions may not be combined."));
+  int i, j, flags, mask, shift, regno;
+  unsigned long ins, mod[2];
+  struct d10v_opcode *op;
 
-  switch (exec_type)
+  if ((op1->exec_type & SEQ)
+      || ! ((op1->exec_type & PAR) || (op1->exec_type & PARONLY)))
     {
-    case PACK_UNSPEC:  /* Order not specified.  */
-      if (opcode1->exec_type & ALONE)
-       {
-         /* Case of a short branch on a separate GAS line.  Pack with NOP.  */
-         write_1_short (opcode1, insn1, fx->next);
-         return 1;
-       }
-      if (Optimizing
-         && parallel_ok (opcode1, insn1, opcode2, insn2, exec_type))
-       {
-         /* Parallel.  */
-         if (opcode1->unit == IU)
-           insn = FM00 | (insn2 << 15) | insn1;
-         else if (opcode2->unit == MU)
-           insn = FM00 | (insn2 << 15) | insn1;
-         else
-           insn = FM00 | (insn1 << 15) | insn2;
-       }
-      else if (opcode1->unit == IU)
-       /* Reverse sequential with IU opcode1 on right and done first.  */
-       insn = FM10 | (insn2 << 15) | insn1;
-      else
-       /* Sequential with non-IU opcode1 on left and done first.  */
-       insn = FM01 | (insn1 << 15) | insn2;
-      break;
-
-    case PACK_PARALLEL:
-      if (opcode1->exec_type & SEQ || opcode2->exec_type & SEQ)
-       as_fatal
-         (_("One of these instructions may not be executed in parallel."));
-      if (opcode1->unit == IU)
-       {
-         if (opcode2->unit == IU)
-           as_fatal (_("Two IU instructions may not be executed in parallel"));
-         if (!flag_warn_suppress_instructionswap)
-           as_warn (_("Swapping instruction order"));
-         insn = FM00 | (insn2 << 15) | insn1;
-       }
-      else if (opcode2->unit == MU)
-       {
-         if (opcode1->unit == MU)
-           as_fatal (_("Two MU instructions may not be executed in parallel"));
-         if (!flag_warn_suppress_instructionswap)
-           as_warn (_("Swapping instruction order"));
-         insn = FM00 | (insn2 << 15) | insn1;
-       }
-      else
-       insn = FM00 | (insn1 << 15) | insn2;
-      check_resource_conflict (opcode1, insn1, opcode2, insn2);
-      break;
-
-    case PACK_LEFT_RIGHT:
-      if (opcode1->unit != IU)
-       insn = FM01 | (insn1 << 15) | insn2;
-      else if (opcode2->unit == MU || opcode2->unit == EITHER)
-       {
-         if (!flag_warn_suppress_instructionswap)
-           as_warn (_("Swapping instruction order"));
-         insn = FM10 | (insn2 << 15) | insn1;
-       }
-      else
-       as_fatal (_("IU instruction may not be in the left container"));
-      if (opcode1->exec_type & ALONE)
-       as_warn (_("Instruction in R container is squashed by flow control instruction in L container."));
-      break;
-
-    case PACK_RIGHT_LEFT:
-      if (opcode2->unit != MU)
-       insn = FM10 | (insn1 << 15) | insn2;
-      else if (opcode1->unit == IU || opcode1->unit == EITHER)
-       {
-         if (!flag_warn_suppress_instructionswap)
-           as_warn (_("Swapping instruction order"));
-         insn = FM01 | (insn2 << 15) | insn1;
-       }
-      else
-       as_fatal (_("MU instruction may not be in the right container"));
-      if (opcode2->exec_type & ALONE)
-       as_warn (_("Instruction in R container is squashed by flow control instruction in L container."));
-      break;
-
-    default:
-      as_fatal (_("unknown execution type passed to write_2_short()"));
+      as_warn (_("packing conflict: %s must dispatch sequentially"),
+             op1->name);
+      return;
     }
 
-  f = frag_more (4);
-  number_to_chars_bigendian (f, insn, 4);
-
-  /* Process fixup chains.  fx refers to insn2 when j == 0, and to
-     insn1 when j == 1.  Yes, it's reversed.  */
-
-  for (j = 0; j < 2; j++)
+  if ((op2->exec_type & SEQ)
+      || ! ((op2->exec_type & PAR) || (op2->exec_type & PARONLY)))
     {
-      for (i = 0; i < fx->fc; i++)
-       {
-         if (fx->fix[i].reloc)
-           {
-             where = f - frag_now->fr_literal;
-             if (fx->fix[i].size == 2)
-               where += 2;
-
-             if (fx->fix[i].reloc == BFD_RELOC_D10V_10_PCREL_R
-                 /* A BFD_RELOC_D10V_10_PCREL_R relocation applied to
-                    the instruction in the L container has to be
-                    adjusted to BDF_RELOC_D10V_10_PCREL_L.  When
-                    j==0, we're processing insn2's operands, so we
-                    want to mark the operand if insn2 is *not* in the
-                    R container.  When j==1, we're processing insn1's
-                    operands, so we want to mark the operand if insn2
-                    *is* in the R container.  Note that, if two
-                    instructions are identical, we're never going to
-                    swap them, so the test is safe.  */
-                 && j == ((insn & 0x7fff) == insn2))
-               fx->fix[i].operand |= 1024;
-
-             if (fx->fix[i].reloc == BFD_RELOC_D10V_18)
-               fx->fix[i].operand |= 4096;
-
-             fix_new_exp (frag_now,
-                          where,
-                          fx->fix[i].size,
-                          &(fx->fix[i].exp),
-                          fx->fix[i].pcrel,
-                          fx->fix[i].operand|2048);
-           }
-       }
-      fx->fc = 0;
-      fx = fx->next;
+      as_warn (_("packing conflict: %s must dispatch sequentially"),
+             op2->name);
+      return;
     }
-  return (0);
-}
-
-/* Check 2 instructions and determine if they can be safely
-   executed in parallel.  Return 1 if they can be.  */
-
-static int
-parallel_ok (op1, insn1, op2, insn2, exec_type)
-     struct d10v_opcode *op1, *op2;
-     unsigned long insn1, insn2;
-     packing_type exec_type;
-{
-  int i, j, flags, mask, shift, regno;
-  unsigned long ins, mod[2], used[2];
-  struct d10v_opcode *op;
-
-  if ((op1->exec_type & SEQ) != 0 || (op2->exec_type & SEQ) != 0
-      || (op1->exec_type & PAR) == 0 || (op2->exec_type & PAR) == 0
-      || (op1->unit == BOTH) || (op2->unit == BOTH)
-      || (op1->unit == IU && op2->unit == IU)
-      || (op1->unit == MU && op2->unit == MU))
-    return 0;
 
-  /* If this is auto parallelization, and the first instruction is a
-     branch or should not be packed, then don't parallelize.  */
-  if (exec_type == PACK_UNSPEC
-      && (op1->exec_type & (ALONE | BRANCH)))
-    return 0;
+   /* See if both instructions write to the same resource.
 
-  /* The idea here is to create two sets of bitmasks (mod and used)
-     which indicate which registers are modified or used by each
-     instruction.  The operation can only be done in parallel if
-     instruction 1 and instruction 2 modify different registers, and
-     the first instruction does not modify registers that the second
-     is using (The second instruction can modify registers that the
-     first is using as they are only written back after the first
-     instruction has completed).  Accesses to control registers, PSW,
-     and memory are treated as accesses to a single register.  So if
-     both instructions write memory or if the first instruction writes
-     memory and the second reads, then they cannot be done in
-     parallel.  Likewise, if the first instruction mucks with the psw
-     and the second reads the PSW (which includes C, F0, and F1), then
-     they cannot operate safely in parallel.  */
+      The idea here is to create two sets of bitmasks (mod and used) which
+      indicate which registers are modified or used by each instruction.
+      The operation can only be done in parallel if neither instruction
+      modifies the same register. Accesses to control registers and memory
+      are treated as accesses to a single register. So if both instructions
+      write memory or if the first instruction writes memory and the second
+      reads, then they cannot be done in parallel. We treat reads to the PSW
+      (which includes C, F0, and F1) in isolation. So simultaneously writing
+      C and F0 in two different sub-instructions is permitted.  */
 
   /* The bitmasks (mod and used) look like this (bit 31 = MSB).
      r0-r15      0-15
      a0-a1       16-17
      cr (not psw) 18
-     psw         19
-     mem         20  */
+     psw(other)   19
+     mem         20
+     psw(C flag)  21
+     psw(F0 flag) 22  */
 
   for (j = 0; j < 2; j++)
     {
@@ -988,7 +750,7 @@ parallel_ok (op1, insn1, op2, insn2, exec_type)
          op = op2;
          ins = insn2;
        }
-      mod[j] = used[j] = 0;
+      mod[j] = 0;
       if (op->exec_type & BRANCH_LINK)
        mod[j] |= 1 << 13;
 
@@ -1002,106 +764,114 @@ parallel_ok (op1, insn1, op2, insn2, exec_type)
              regno = (ins >> shift) & mask;
              if (flags & (OPERAND_ACC0 | OPERAND_ACC1))
                regno += 16;
-             else if (flags & OPERAND_CONTROL) /* mvtc or mvfc */
+             else if (flags & OPERAND_CONTROL) /* mvtc or mvfc */
                {
                  if (regno == 0)
                    regno = 19;
                  else
                    regno = 18;
                }
-             else if (flags & (OPERAND_FFLAG | OPERAND_CFLAG))
-               regno = 19;
+             else if (flags & OPERAND_FFLAG)
+               regno = 22;
+             else if (flags & OPERAND_CFLAG)
+               regno = 21;
 
-             if (flags & OPERAND_DEST)
+             if (flags & OPERAND_DEST
+                 /* Auto inc/dec also modifies the register.  */
+                 || (op->operands[i + 1] != 0
+                     && (d10v_operands[op->operands[i + 1]].flags
+                         & (OPERAND_PLUS | OPERAND_MINUS)) != 0))
                {
                  mod[j] |= 1 << regno;
                  if (flags & OPERAND_EVEN)
                    mod[j] |= 1 << (regno + 1);
                }
-             else
-               {
-                 used[j] |= 1 << regno;
-                 if (flags & OPERAND_EVEN)
-                   used[j] |= 1 << (regno + 1);
-
-                 /* Auto inc/dec also modifies the register.  */
-                 if (op->operands[i + 1] != 0
-                     && (d10v_operands[op->operands[i + 1]].flags
-                         & (OPERAND_PLUS | OPERAND_MINUS)) != 0)
-                   mod[j] |= 1 << regno;
-               }
            }
          else if (flags & OPERAND_ATMINUS)
            {
              /* SP implicitly used/modified.  */
              mod[j] |= 1 << 15;
-             used[j] |= 1 << 15;
            }
        }
-      if (op->exec_type & RMEM)
-       used[j] |= 1 << 20;
-      else if (op->exec_type & WMEM)
+
+      if (op->exec_type & WMEM)
        mod[j] |= 1 << 20;
-      else if (op->exec_type & RF0)
-       used[j] |= 1 << 19;
       else if (op->exec_type & WF0)
-       mod[j] |= 1 << 19;
+       mod[j] |= 1 << 22;
       else if (op->exec_type & WCAR)
-       mod[j] |= 1 << 19;
+       mod[j] |= 1 << 21;
+    }
+
+  if ((mod[0] & mod[1]) == 0)
+    return;
+  else
+    {
+      unsigned long x;
+      x = mod[0] & mod[1];
+
+      for (j = 0; j <= 15; j++)
+       if (x & (1 << j))
+         as_warn (_("resource conflict (R%d)"), j);
+      for (j = 16; j <= 17; j++)
+       if (x & (1 << j))
+         as_warn (_("resource conflict (A%d)"), j - 16);
+      if (x & (1 << 19))
+       as_warn (_("resource conflict (PSW)"));
+      if (x & (1 << 21))
+       as_warn (_("resource conflict (C flag)"));
+      if (x & (1 << 22))
+       as_warn (_("resource conflict (F flag)"));
     }
-  if ((mod[0] & mod[1]) == 0 && (mod[0] & used[1]) == 0)
-    return 1;
-  return 0;
 }
 
-/* Determine if there are any resource conflicts among two manually
-   parallelized instructions.  Some of this was lifted from parallel_ok.  */
+/* Check 2 instructions and determine if they can be safely
+   executed in parallel.  Return 1 if they can be.  */
 
-static void
-check_resource_conflict (op1, insn1, op2, insn2)
-     struct d10v_opcode *op1, *op2;
-     unsigned long insn1, insn2;
+static int
+parallel_ok (struct d10v_opcode *op1,
+            unsigned long insn1,
+            struct d10v_opcode *op2,
+            unsigned long insn2,
+            packing_type exec_type)
 {
   int i, j, flags, mask, shift, regno;
-  unsigned long ins, mod[2];
+  unsigned long ins, mod[2], used[2];
   struct d10v_opcode *op;
 
-  if ((op1->exec_type & SEQ)
-      || ! ((op1->exec_type & PAR) || (op1->exec_type & PARONLY)))
-    {
-      as_warn (_("packing conflict: %s must dispatch sequentially"),
-             op1->name);
-      return;
-    }
-
-  if ((op2->exec_type & SEQ)
-      || ! ((op2->exec_type & PAR) || (op2->exec_type & PARONLY)))
-    {
-      as_warn (_("packing conflict: %s must dispatch sequentially"),
-             op2->name);
-      return;
-    }
+  if ((op1->exec_type & SEQ) != 0 || (op2->exec_type & SEQ) != 0
+      || (op1->exec_type & PAR) == 0 || (op2->exec_type & PAR) == 0
+      || (op1->unit == BOTH) || (op2->unit == BOTH)
+      || (op1->unit == IU && op2->unit == IU)
+      || (op1->unit == MU && op2->unit == MU))
+    return 0;
 
-   /* See if both instructions write to the same resource.
+  /* If this is auto parallelization, and the first instruction is a
+     branch or should not be packed, then don't parallelize.  */
+  if (exec_type == PACK_UNSPEC
+      && (op1->exec_type & (ALONE | BRANCH)))
+    return 0;
 
-      The idea here is to create two sets of bitmasks (mod and used) which
-      indicate which registers are modified or used by each instruction.
-      The operation can only be done in parallel if neither instruction
-      modifies the same register. Accesses to control registers and memory
-      are treated as accesses to a single register. So if both instructions
-      write memory or if the first instruction writes memory and the second
-      reads, then they cannot be done in parallel. We treat reads to the PSW
-      (which includes C, F0, and F1) in isolation. So simultaneously writing
-      C and F0 in two different sub-instructions is permitted.  */
+  /* The idea here is to create two sets of bitmasks (mod and used)
+     which indicate which registers are modified or used by each
+     instruction.  The operation can only be done in parallel if
+     instruction 1 and instruction 2 modify different registers, and
+     the first instruction does not modify registers that the second
+     is using (The second instruction can modify registers that the
+     first is using as they are only written back after the first
+     instruction has completed).  Accesses to control registers, PSW,
+     and memory are treated as accesses to a single register.  So if
+     both instructions write memory or if the first instruction writes
+     memory and the second reads, then they cannot be done in
+     parallel.  Likewise, if the first instruction mucks with the psw
+     and the second reads the PSW (which includes C, F0, and F1), then
+     they cannot operate safely in parallel.  */
 
   /* The bitmasks (mod and used) look like this (bit 31 = MSB).
      r0-r15      0-15
      a0-a1       16-17
      cr (not psw) 18
-     psw(other)   19
-     mem         20
-     psw(C flag)  21
-     psw(F0 flag) 22  */
+     psw         19
+     mem         20  */
 
   for (j = 0; j < 2; j++)
     {
@@ -1115,7 +885,7 @@ check_resource_conflict (op1, insn1, op2, insn2)
          op = op2;
          ins = insn2;
        }
-      mod[j] = 0;
+      mod[j] = used[j] = 0;
       if (op->exec_type & BRANCH_LINK)
        mod[j] |= 1 << 13;
 
@@ -1129,235 +899,232 @@ check_resource_conflict (op1, insn1, op2, insn2)
              regno = (ins >> shift) & mask;
              if (flags & (OPERAND_ACC0 | OPERAND_ACC1))
                regno += 16;
-             else if (flags & OPERAND_CONTROL) /* mvtc or mvfc */
+             else if (flags & OPERAND_CONTROL) /* mvtc or mvfc */
                {
                  if (regno == 0)
                    regno = 19;
                  else
                    regno = 18;
                }
-             else if (flags & OPERAND_FFLAG)
-               regno = 22;
-             else if (flags & OPERAND_CFLAG)
-               regno = 21;
+             else if (flags & (OPERAND_FFLAG | OPERAND_CFLAG))
+               regno = 19;
 
-             if (flags & OPERAND_DEST
-                 /* Auto inc/dec also modifies the register.  */
-                 || (op->operands[i + 1] != 0
-                     && (d10v_operands[op->operands[i + 1]].flags
-                         & (OPERAND_PLUS | OPERAND_MINUS)) != 0))
+             if (flags & OPERAND_DEST)
                {
                  mod[j] |= 1 << regno;
                  if (flags & OPERAND_EVEN)
                    mod[j] |= 1 << (regno + 1);
                }
+             else
+               {
+                 used[j] |= 1 << regno;
+                 if (flags & OPERAND_EVEN)
+                   used[j] |= 1 << (regno + 1);
+
+                 /* Auto inc/dec also modifies the register.  */
+                 if (op->operands[i + 1] != 0
+                     && (d10v_operands[op->operands[i + 1]].flags
+                         & (OPERAND_PLUS | OPERAND_MINUS)) != 0)
+                   mod[j] |= 1 << regno;
+               }
            }
          else if (flags & OPERAND_ATMINUS)
            {
              /* SP implicitly used/modified.  */
              mod[j] |= 1 << 15;
+             used[j] |= 1 << 15;
            }
        }
-
-      if (op->exec_type & WMEM)
+      if (op->exec_type & RMEM)
+       used[j] |= 1 << 20;
+      else if (op->exec_type & WMEM)
        mod[j] |= 1 << 20;
+      else if (op->exec_type & RF0)
+       used[j] |= 1 << 19;
       else if (op->exec_type & WF0)
-       mod[j] |= 1 << 22;
+       mod[j] |= 1 << 19;
       else if (op->exec_type & WCAR)
-       mod[j] |= 1 << 21;
-    }
-
-  if ((mod[0] & mod[1]) == 0)
-    return;
-  else
-    {
-      unsigned long x;
-      x = mod[0] & mod[1];
-
-      for (j = 0; j <= 15; j++)
-       if (x & (1 << j))
-         as_warn (_("resource conflict (R%d)"), j);
-      for (j = 16; j <= 17; j++)
-       if (x & (1 << j))
-         as_warn (_("resource conflict (A%d)"), j - 16);
-      if (x & (1 << 19))
-       as_warn (_("resource conflict (PSW)"));
-      if (x & (1 << 21))
-       as_warn (_("resource conflict (C flag)"));
-      if (x & (1 << 22))
-       as_warn (_("resource conflict (F flag)"));
+       mod[j] |= 1 << 19;
     }
+  if ((mod[0] & mod[1]) == 0 && (mod[0] & used[1]) == 0)
+    return 1;
+  return 0;
 }
 
-/* This is the main entry point for the machine-dependent assembler.
-   str points to a machine-dependent instruction.  This function is
-   supposed to emit the frags/bytes it assembles to.  For the D10V, it
-   mostly handles the special VLIW parsing and packing and leaves the
-   difficult stuff to do_assemble().  */
-
-static unsigned long prev_insn;
-static struct d10v_opcode *prev_opcode = 0;
-static subsegT prev_subseg;
-static segT prev_seg = 0;;
+/* Expects two short instructions.
+   If possible, writes out both as a single packed instruction.
+   Otherwise, writes out the first one, packed with a NOP.
+   Returns number of instructions not written out.  */
 
-void
-md_assemble (str)
-     char *str;
+static int
+write_2_short (struct d10v_opcode *opcode1,
+              unsigned long insn1,
+              struct d10v_opcode *opcode2,
+              unsigned long insn2,
+              packing_type exec_type,
+              Fixups *fx)
 {
-  /* etype is saved extype.  For multi-line instructions.  */
+  unsigned long insn;
+  char *f;
+  int i, j, where;
 
-  packing_type extype = PACK_UNSPEC;           /* Parallel, etc.  */
+  if ((exec_type != PACK_PARALLEL)
+      && ((opcode1->exec_type & PARONLY) || (opcode2->exec_type & PARONLY)))
+    as_fatal (_("Instruction must be executed in parallel"));
 
-  struct d10v_opcode *opcode;
-  unsigned long insn;
-  char *str2;
+  if ((opcode1->format & LONG_OPCODE) || (opcode2->format & LONG_OPCODE))
+    as_fatal (_("Long instructions may not be combined."));
 
-  if (etype == PACK_UNSPEC)
+  switch (exec_type)
     {
-      /* Look for the special multiple instruction separators.  */
-      str2 = strstr (str, "||");
-      if (str2)
-       extype = PACK_PARALLEL;
-      else
+    case PACK_UNSPEC:  /* Order not specified.  */
+      if (opcode1->exec_type & ALONE)
        {
-         str2 = strstr (str, "->");
-         if (str2)
-           extype = PACK_LEFT_RIGHT;
+         /* Case of a short branch on a separate GAS line.  Pack with NOP.  */
+         write_1_short (opcode1, insn1, fx->next);
+         return 1;
+       }
+      if (Optimizing
+         && parallel_ok (opcode1, insn1, opcode2, insn2, exec_type))
+       {
+         /* Parallel.  */
+         if (opcode1->unit == IU)
+           insn = FM00 | (insn2 << 15) | insn1;
+         else if (opcode2->unit == MU)
+           insn = FM00 | (insn2 << 15) | insn1;
          else
-           {
-             str2 = strstr (str, "<-");
-             if (str2)
-               extype = PACK_RIGHT_LEFT;
-           }
+           insn = FM00 | (insn1 << 15) | insn2;
        }
+      else if (opcode1->unit == IU)
+       /* Reverse sequential with IU opcode1 on right and done first.  */
+       insn = FM10 | (insn2 << 15) | insn1;
+      else
+       /* Sequential with non-IU opcode1 on left and done first.  */
+       insn = FM01 | (insn1 << 15) | insn2;
+      break;
 
-      /* str2 points to the separator, if there is one.  */
-      if (str2)
+    case PACK_PARALLEL:
+      if (opcode1->exec_type & SEQ || opcode2->exec_type & SEQ)
+       as_fatal
+         (_("One of these instructions may not be executed in parallel."));
+      if (opcode1->unit == IU)
        {
-         *str2 = 0;
-
-         /* If two instructions are present and we already have one saved,
-            then first write out the saved one.  */
-         d10v_cleanup ();
-
-         /* Assemble first instruction and save it.  */
-         prev_insn = do_assemble (str, &prev_opcode);
-         prev_seg = now_seg;
-         prev_subseg = now_subseg;
-         if (prev_insn == (unsigned long) -1)
-           as_fatal (_("can't find opcode "));
-         fixups = fixups->next;
-         str = str2 + 2;
+         if (opcode2->unit == IU)
+           as_fatal (_("Two IU instructions may not be executed in parallel"));
+         if (!flag_warn_suppress_instructionswap)
+           as_warn (_("Swapping instruction order"));
+         insn = FM00 | (insn2 << 15) | insn1;
        }
-    }
-
-  insn = do_assemble (str, &opcode);
-  if (insn == (unsigned long) -1)
-    {
-      if (extype != PACK_UNSPEC)
+      else if (opcode2->unit == MU)
        {
-         etype = extype;
-         return;
+         if (opcode1->unit == MU)
+           as_fatal (_("Two MU instructions may not be executed in parallel"));
+         if (!flag_warn_suppress_instructionswap)
+           as_warn (_("Swapping instruction order"));
+         insn = FM00 | (insn2 << 15) | insn1;
        }
-      as_fatal (_("can't find opcode "));
-    }
-
-  if (etype != PACK_UNSPEC)
-    {
-      extype = etype;
-      etype = PACK_UNSPEC;
-    }
-
-  /* If this is a long instruction, write it and any previous short
-     instruction.  */
-  if (opcode->format & LONG_OPCODE)
-    {
-      if (extype != PACK_UNSPEC)
-       as_fatal (_("Unable to mix instructions as specified"));
-      d10v_cleanup ();
-      write_long (insn, fixups);
-      prev_opcode = NULL;
-      return;
-    }
-
-  if (prev_opcode
-      && prev_seg
-      && ((prev_seg != now_seg) || (prev_subseg != now_subseg)))
-    d10v_cleanup ();
+      else
+       insn = FM00 | (insn1 << 15) | insn2;
+      check_resource_conflict (opcode1, insn1, opcode2, insn2);
+      break;
 
-  if (prev_opcode
-      && (0 == write_2_short (prev_opcode, prev_insn, opcode, insn, extype,
-                             fixups)))
-    {
-      /* No instructions saved.  */
-      prev_opcode = NULL;
-    }
-  else
-    {
-      if (extype != PACK_UNSPEC)
-       as_fatal (_("Unable to mix instructions as specified"));
-      /* Save last instruction so it may be packed on next pass.  */
-      prev_opcode = opcode;
-      prev_insn = insn;
-      prev_seg = now_seg;
-      prev_subseg = now_subseg;
-      fixups = fixups->next;
-    }
-}
+    case PACK_LEFT_RIGHT:
+      if (opcode1->unit != IU)
+       insn = FM01 | (insn1 << 15) | insn2;
+      else if (opcode2->unit == MU || opcode2->unit == EITHER)
+       {
+         if (!flag_warn_suppress_instructionswap)
+           as_warn (_("Swapping instruction order"));
+         insn = FM10 | (insn2 << 15) | insn1;
+       }
+      else
+       as_fatal (_("IU instruction may not be in the left container"));
+      if (opcode1->exec_type & ALONE)
+       as_warn (_("Instruction in R container is squashed by flow control instruction in L container."));
+      break;
 
-/* Assemble a single instruction.
-   Return an opcode, or -1 (an invalid opcode) on error.  */
+    case PACK_RIGHT_LEFT:
+      if (opcode2->unit != MU)
+       insn = FM10 | (insn1 << 15) | insn2;
+      else if (opcode1->unit == IU || opcode1->unit == EITHER)
+       {
+         if (!flag_warn_suppress_instructionswap)
+           as_warn (_("Swapping instruction order"));
+         insn = FM01 | (insn2 << 15) | insn1;
+       }
+      else
+       as_fatal (_("MU instruction may not be in the right container"));
+      if (opcode2->exec_type & ALONE)
+       as_warn (_("Instruction in R container is squashed by flow control instruction in L container."));
+      break;
 
-static unsigned long
-do_assemble (str, opcode)
-     char *str;
-     struct d10v_opcode **opcode;
-{
-  unsigned char *op_start, *op_end;
-  char *save;
-  char name[20];
-  int nlen = 0;
-  expressionS myops[6];
-  unsigned long insn;
+    default:
+      as_fatal (_("unknown execution type passed to write_2_short()"));
+    }
 
-  /* Drop leading whitespace.  */
-  while (*str == ' ')
-    str++;
+  f = frag_more (4);
+  dwarf2_emit_insn (4);
+  number_to_chars_bigendian (f, insn, 4);
 
-  /* Find the opcode end.  */
-  for (op_start = op_end = (unsigned char *) str;
-       *op_end && nlen < 20 && !is_end_of_line[*op_end] && *op_end != ' ';
-       op_end++)
-    {
-      name[nlen] = TOLOWER (op_start[nlen]);
-      nlen++;
-    }
-  name[nlen] = 0;
+  /* Process fixup chains.  fx refers to insn2 when j == 0, and to
+     insn1 when j == 1.  Yes, it's reversed.  */
 
-  if (nlen == 0)
-    return -1;
+  for (j = 0; j < 2; j++)
+    {
+      for (i = 0; i < fx->fc; i++)
+       {
+         if (fx->fix[i].reloc)
+           {
+             where = f - frag_now->fr_literal;
+             if (fx->fix[i].size == 2)
+               where += 2;
 
-  /* Find the first opcode with the proper name.  */
-  *opcode = (struct d10v_opcode *) hash_find (d10v_hash, name);
-  if (*opcode == NULL)
-    as_fatal (_("unknown opcode: %s"), name);
+             if (fx->fix[i].reloc == BFD_RELOC_D10V_10_PCREL_R
+                 /* A BFD_RELOC_D10V_10_PCREL_R relocation applied to
+                    the instruction in the L container has to be
+                    adjusted to BDF_RELOC_D10V_10_PCREL_L.  When
+                    j==0, we're processing insn2's operands, so we
+                    want to mark the operand if insn2 is *not* in the
+                    R container.  When j==1, we're processing insn1's
+                    operands, so we want to mark the operand if insn2
+                    *is* in the R container.  Note that, if two
+                    instructions are identical, we're never going to
+                    swap them, so the test is safe.  */
+                 && j == ((insn & 0x7fff) == insn2))
+               fx->fix[i].operand |= 1024;
 
-  save = input_line_pointer;
-  input_line_pointer = (char *) op_end;
-  *opcode = find_opcode (*opcode, myops);
-  if (*opcode == 0)
-    return -1;
-  input_line_pointer = save;
+             if (fx->fix[i].reloc == BFD_RELOC_D10V_18)
+               fx->fix[i].operand |= 4096;
 
-  insn = build_insn ((*opcode), myops, 0);
-  return (insn);
+             fix_new_exp (frag_now,
+                          where,
+                          fx->fix[i].size,
+                          &(fx->fix[i].exp),
+                          fx->fix[i].pcrel,
+                          fx->fix[i].operand|2048);
+           }
+       }
+      fx->fc = 0;
+      fx = fx->next;
+    }
+  return 0;
 }
 
+/* This is the main entry point for the machine-dependent assembler.
+   str points to a machine-dependent instruction.  This function is
+   supposed to emit the frags/bytes it assembles to.  For the D10V, it
+   mostly handles the special VLIW parsing and packing and leaves the
+   difficult stuff to do_assemble().  */
+
+static unsigned long prev_insn;
+static struct d10v_opcode *prev_opcode = 0;
+static subsegT prev_subseg;
+static segT prev_seg = 0;;
+
 /* Find the symbol which has the same name as the register in exp.  */
 
 static symbolS *
-find_symbol_matching_register (exp)
-     expressionS *exp;
+find_symbol_matching_register (expressionS *exp)
 {
   int i;
 
@@ -1381,9 +1148,7 @@ find_symbol_matching_register (exp)
    the operands to choose the correct opcode.  */
 
 static struct d10v_opcode *
-find_opcode (opcode, myops)
-     struct d10v_opcode *opcode;
-     expressionS myops[];
+find_opcode (struct d10v_opcode *opcode, expressionS myops[])
 {
   int i, match;
   struct d10v_opcode *next_opcode;
@@ -1436,7 +1201,9 @@ find_opcode (opcode, myops)
          for (i = 0; opcode->operands[i + 1]; i++)
            {
              int bits = d10v_operands[next_opcode->operands[opnum]].bits;
-             int flags = d10v_operands[next_opcode->operands[opnum]].flags;
+
+             flags = d10v_operands[next_opcode->operands[opnum]].flags;
+
              if (flags & OPERAND_ADDR)
                bits += 2;
 
@@ -1503,10 +1270,8 @@ find_opcode (opcode, myops)
            opcode = next_opcode;
        }
       else
-       {
-         /* Not a constant, so use a long instruction.  */
-         opcode += 2;
-       }
+       /* Not a constant, so use a long instruction.  */
+       opcode += 2;
     }
 
   match = 0;
@@ -1599,7 +1364,7 @@ find_opcode (opcode, myops)
   if (!match)
     {
       as_bad (_("bad opcode or operands"));
-      return (0);
+      return 0;
     }
 
   /* Check that all registers that are required to be even are.
@@ -1637,17 +1402,61 @@ find_opcode (opcode, myops)
   return opcode;
 }
 
+/* Assemble a single instruction.
+   Return an opcode, or -1 (an invalid opcode) on error.  */
+
+static unsigned long
+do_assemble (char *str, struct d10v_opcode **opcode)
+{
+  unsigned char *op_start, *op_end;
+  char *save;
+  char name[20];
+  int nlen = 0;
+  expressionS myops[6];
+
+  /* Drop leading whitespace.  */
+  while (*str == ' ')
+    str++;
+
+  /* Find the opcode end.  */
+  for (op_start = op_end = (unsigned char *) str;
+       *op_end && !is_end_of_line[*op_end] && *op_end != ' ';
+       op_end++)
+    {
+      name[nlen] = TOLOWER (op_start[nlen]);
+      nlen++;
+      if (nlen == sizeof (name) - 1)
+       break;
+    }
+  name[nlen] = 0;
+
+  if (nlen == 0)
+    return -1;
+
+  /* Find the first opcode with the proper name.  */
+  *opcode = (struct d10v_opcode *) hash_find (d10v_hash, name);
+  if (*opcode == NULL)
+    return -1;
+
+  save = input_line_pointer;
+  input_line_pointer = (char *) op_end;
+  *opcode = find_opcode (*opcode, myops);
+  if (*opcode == 0)
+    return -1;
+  input_line_pointer = save;
+
+  return build_insn ((*opcode), myops, 0);
+}
+
 /* If while processing a fixup, a reloc really needs to be created.
    Then it is done here.  */
 
 arelent *
-tc_gen_reloc (seg, fixp)
-     asection *seg ATTRIBUTE_UNUSED;
-     fixS *fixp;
+tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
 {
   arelent *reloc;
-  reloc = (arelent *) xmalloc (sizeof (arelent));
-  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  reloc = xmalloc (sizeof (arelent));
+  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
@@ -1668,18 +1477,15 @@ tc_gen_reloc (seg, fixp)
 }
 
 int
-md_estimate_size_before_relax (fragp, seg)
-     fragS *fragp ATTRIBUTE_UNUSED;
-     asection *seg ATTRIBUTE_UNUSED;
+md_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED,
+                              asection *seg ATTRIBUTE_UNUSED)
 {
   abort ();
   return 0;
 }
 
 long
-md_pcrel_from_section (fixp, sec)
-     fixS *fixp;
-     segT sec;
+md_pcrel_from_section (fixS *fixp, segT sec)
 {
   if (fixp->fx_addsy != (symbolS *) NULL
       && (!S_IS_DEFINED (fixp->fx_addsy)
@@ -1689,10 +1495,7 @@ md_pcrel_from_section (fixp, sec)
 }
 
 void
-md_apply_fix3 (fixP, valP, seg)
-     fixS *fixP;
-     valueT *valP;
-     segT seg ATTRIBUTE_UNUSED;
+md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 {
   char *where;
   unsigned long insn;
@@ -1741,7 +1544,7 @@ md_apply_fix3 (fixP, valP, seg)
         symbol, then ignore the offset.
          XXX - Do we have to worry about branches to a symbol + offset ?  */
       if (fixP->fx_addsy != NULL
-         && S_IS_EXTERN (fixP->fx_addsy) )
+         && S_IS_EXTERNAL (fixP->fx_addsy) )
         {
           segT fseg = S_GET_SEGMENT (fixP->fx_addsy);
           segment_info_type *segf = seg_info(fseg);
@@ -1804,7 +1607,7 @@ md_apply_fix3 (fixP, valP, seg)
    NOTE: invoked by various macros such as md_cleanup: see.  */
 
 int
-d10v_cleanup ()
+d10v_cleanup (void)
 {
   segT seg;
   subsegT subseg;
@@ -1832,12 +1635,20 @@ d10v_cleanup ()
   return 1;
 }
 
+void
+d10v_frob_label (symbolS *lab)
+{
+  d10v_cleanup ();
+  symbol_set_frag (lab, frag_now);
+  S_SET_VALUE (lab, (valueT) frag_now_fix ());
+  dwarf2_emit_label (lab);
+}
+
 /* Like normal .word, except support @word.
    Clobbers input_line_pointer, checks end-of-line.  */
 
 static void
-d10v_dot_word (dummy)
-     int dummy ATTRIBUTE_UNUSED;
+d10v_dot_word (int dummy ATTRIBUTE_UNUSED)
 {
   expressionS exp;
   char *p;
@@ -1880,8 +1691,7 @@ d10v_dot_word (dummy)
    From expr.c.  */
 
 void
-md_operand (expressionP)
-     expressionS *expressionP;
+md_operand (expressionS *expressionP)
 {
   if (*input_line_pointer == '#' && ! do_not_ignore_hash)
     {
@@ -1891,8 +1701,7 @@ md_operand (expressionP)
 }
 
 bfd_boolean
-d10v_fix_adjustable (fixP)
-     fixS *fixP;
+d10v_fix_adjustable (fixS *fixP)
 {
   /* We need the symbol name for the VTABLE entries.  */
   if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
@@ -1901,3 +1710,112 @@ d10v_fix_adjustable (fixP)
 
   return 1;
 }
+
+/* The target specific pseudo-ops which we support.  */
+const pseudo_typeS md_pseudo_table[] =
+{
+  { "word",    d10v_dot_word,  2 },
+  { NULL,       NULL,           0 }
+};
+
+void
+md_assemble (char *str)
+{
+  /* etype is saved extype.  For multi-line instructions.  */
+  packing_type extype = PACK_UNSPEC;           /* Parallel, etc.  */
+  struct d10v_opcode *opcode;
+  unsigned long insn;
+  char *str2;
+
+  if (etype == PACK_UNSPEC)
+    {
+      /* Look for the special multiple instruction separators.  */
+      str2 = strstr (str, "||");
+      if (str2)
+       extype = PACK_PARALLEL;
+      else
+       {
+         str2 = strstr (str, "->");
+         if (str2)
+           extype = PACK_LEFT_RIGHT;
+         else
+           {
+             str2 = strstr (str, "<-");
+             if (str2)
+               extype = PACK_RIGHT_LEFT;
+           }
+       }
+
+      /* str2 points to the separator, if there is one.  */
+      if (str2)
+       {
+         *str2 = 0;
+
+         /* If two instructions are present and we already have one saved,
+            then first write out the saved one.  */
+         d10v_cleanup ();
+
+         /* Assemble first instruction and save it.  */
+         prev_insn = do_assemble (str, &prev_opcode);
+         prev_seg = now_seg;
+         prev_subseg = now_subseg;
+         if (prev_insn == (unsigned long) -1)
+           as_fatal (_("can't find previous opcode "));
+         fixups = fixups->next;
+         str = str2 + 2;
+       }
+    }
+
+  insn = do_assemble (str, &opcode);
+  if (insn == (unsigned long) -1)
+    {
+      if (extype != PACK_UNSPEC)
+       etype = extype;
+      else
+       as_bad (_("could not assemble: %s"), str);
+      return;
+    }
+
+  if (etype != PACK_UNSPEC)
+    {
+      extype = etype;
+      etype = PACK_UNSPEC;
+    }
+
+  /* If this is a long instruction, write it and any previous short
+     instruction.  */
+  if (opcode->format & LONG_OPCODE)
+    {
+      if (extype != PACK_UNSPEC)
+       as_fatal (_("Unable to mix instructions as specified"));
+      d10v_cleanup ();
+      write_long (insn, fixups);
+      prev_opcode = NULL;
+      return;
+    }
+
+  if (prev_opcode
+      && prev_seg
+      && ((prev_seg != now_seg) || (prev_subseg != now_subseg)))
+    d10v_cleanup ();
+
+  if (prev_opcode
+      && (0 == write_2_short (prev_opcode, prev_insn, opcode, insn, extype,
+                             fixups)))
+    {
+      /* No instructions saved.  */
+      prev_opcode = NULL;
+    }
+  else
+    {
+      if (extype != PACK_UNSPEC)
+       as_fatal (_("Unable to mix instructions as specified"));
+      /* Save last instruction so it may be packed on next pass.  */
+      prev_opcode = opcode;
+      prev_insn = insn;
+      prev_seg = now_seg;
+      prev_subseg = now_subseg;
+      fixups = fixups->next;
+    }
+}
+