"thread apply 1 -- -" vs "frame apply level 0 -- -"
[deliverable/binutils-gdb.git] / gas / config / tc-h8300.c
index ab9f7337cae55f3f982d7ca1bb586b1306715939..5ddc889a4da885c15345a387af26383d2c31f4e3 100644 (file)
@@ -1,12 +1,11 @@
-/* tc-h8300.c -- Assemble code for the Hitachi H8/300
-   Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 98, 2000
-   Free Software Foundation.
+/* tc-h8300.c -- Assemble code for the Renesas H8/300
+   Copyright (C) 1991-2019 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
    any later version.
 
    GAS is distributed in the hope that it will be useful,
 
    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
 
    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.  */
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
 
 
-/*
-  Written By Steve Chamberlain
-  sac@cygnus.com
-  */
+/* Written By Steve Chamberlain <sac@cygnus.com>.  */
 
 
-#include <stdio.h>
 #include "as.h"
 #include "subsegs.h"
 #include "as.h"
 #include "subsegs.h"
-#include "bfd.h"
+#include "dwarf2dbg.h"
+
 #define DEFINE_TABLE
 #define h8_opcodes ops
 #include "opcode/h8300.h"
 #define DEFINE_TABLE
 #define h8_opcodes ops
 #include "opcode/h8300.h"
-#include <ctype.h>
+#include "safe-ctype.h"
+#include "elf/h8.h"
 
 const char comment_chars[] = ";";
 const char line_comment_chars[] = "#";
 
 const char comment_chars[] = ";";
 const char line_comment_chars[] = "#";
+#ifdef TE_LINUX
+const char line_separator_chars[] = "!";
+#else
 const char line_separator_chars[] = "";
 const char line_separator_chars[] = "";
+#endif
 
 
-/* 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 ();
+static void sbranch (int);
+static void h8300hmode (int);
+static void h8300smode (int);
+static void h8300hnmode (int);
+static void h8300snmode (int);
+static void h8300sxmode (int);
+static void h8300sxnmode (int);
+static void pint (int);
 
 int Hmode;
 int Smode;
 
 int Hmode;
 int Smode;
-#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 */
+int Nmode;
+int SXmode;
 
 
-void
-h8300hmode ()
+static int default_mach = bfd_mach_h8300;
+
+#define PSIZE (Hmode && !Nmode ? L_32 : L_16)
+
+static int bsize = L_8;                /* Default branch displacement.  */
+
+struct h8_instruction
+{
+  int length;
+  int noperands;
+  int idx;
+  int size;
+  const struct h8_opcode *opcode;
+};
+
+static struct h8_instruction *h8_instructions;
+
+static void
+h8300hmode (int arg ATTRIBUTE_UNUSED)
 {
   Hmode = 1;
   Smode = 0;
 {
   Hmode = 1;
   Smode = 0;
+  if (!bfd_set_arch_mach (stdoutput, bfd_arch_h8300, bfd_mach_h8300h))
+    as_warn (_("could not set architecture and machine"));
 }
 
 }
 
-void
-h8300smode ()
+static void
+h8300smode (int arg ATTRIBUTE_UNUSED)
 {
   Smode = 1;
   Hmode = 1;
 {
   Smode = 1;
   Hmode = 1;
+  if (!bfd_set_arch_mach (stdoutput, bfd_arch_h8300, bfd_mach_h8300s))
+    as_warn (_("could not set architecture and machine"));
 }
 
 }
 
-void
-sbranch (size)
-     int size;
+static void
+h8300hnmode (int arg ATTRIBUTE_UNUSED)
+{
+  Hmode = 1;
+  Smode = 0;
+  Nmode = 1;
+  if (!bfd_set_arch_mach (stdoutput, bfd_arch_h8300, bfd_mach_h8300hn))
+    as_warn (_("could not set architecture and machine"));
+}
+
+static void
+h8300snmode (int arg ATTRIBUTE_UNUSED)
+{
+  Smode = 1;
+  Hmode = 1;
+  Nmode = 1;
+  if (!bfd_set_arch_mach (stdoutput, bfd_arch_h8300, bfd_mach_h8300sn))
+    as_warn (_("could not set architecture and machine"));
+}
+
+static void
+h8300sxmode (int arg ATTRIBUTE_UNUSED)
+{
+  Smode = 1;
+  Hmode = 1;
+  SXmode = 1;
+  if (!bfd_set_arch_mach (stdoutput, bfd_arch_h8300, bfd_mach_h8300sx))
+    as_warn (_("could not set architecture and machine"));
+}
+
+static void
+h8300sxnmode (int arg ATTRIBUTE_UNUSED)
+{
+  Smode = 1;
+  Hmode = 1;
+  SXmode = 1;
+  Nmode = 1;
+  if (!bfd_set_arch_mach (stdoutput, bfd_arch_h8300, bfd_mach_h8300sxn))
+    as_warn (_("could not set architecture and machine"));
+}
+
+static void
+sbranch (int size)
 {
   bsize = size;
 }
 
 static void
 {
   bsize = size;
 }
 
 static void
-pint ()
+pint (int arg ATTRIBUTE_UNUSED)
 {
   cons (Hmode ? 4 : 2);
 }
 
 {
   cons (Hmode ? 4 : 2);
 }
 
+/* Like obj_elf_section, but issues a warning for new
+   sections which do not have an attribute specification.  */
+
+static void
+h8300_elf_section (int push)
+{
+  static const char * known_data_sections [] = { ".rodata", ".tdata", ".tbss" };
+  static const char * known_data_prefixes [] = { ".debug", ".zdebug", ".gnu.warning" };
+  char * saved_ilp = input_line_pointer;
+  const char * name;
+
+  name = obj_elf_section_name ();
+  if (name == NULL)
+    return;
+
+  if (* input_line_pointer != ','
+      && bfd_get_section_by_name (stdoutput, name) == NULL)
+    {
+      signed int i;
+
+      /* Ignore this warning for well known data sections.  */
+      for (i = ARRAY_SIZE (known_data_sections); i--;)
+       if (strcmp (name, known_data_sections[i]) == 0)
+         break;
+
+      if (i < 0)
+       for (i = ARRAY_SIZE (known_data_prefixes); i--;)
+         if (strncmp (name, known_data_prefixes[i],
+                      strlen (known_data_prefixes[i])) == 0)
+           break;
+
+      if (i < 0)
+       as_warn (_("new section '%s' defined without attributes - this might cause problems"), name);
+    }
+
+  /* FIXME: We ought to free the memory allocated by obj_elf_section_name()
+     for 'name', but we do not know if it was taken from the obstack, via
+     demand_copy_C_string(), or xmalloc()ed.  */
+  input_line_pointer = saved_ilp;
+  obj_elf_section (push);
+}
+
+/* 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.  */
+
 const pseudo_typeS md_pseudo_table[] =
 {
 const pseudo_typeS md_pseudo_table[] =
 {
-  {"h8300h", h8300hmode, 0},
-  {"h8300s", h8300smode, 0},
+  {"h8300h",  h8300hmode,  0},
+  {"h8300hn", h8300hnmode, 0},
+  {"h8300s",  h8300smode,  0},
+  {"h8300sn", h8300snmode, 0},
+  {"h8300sx", h8300sxmode, 0},
+  {"h8300sxn", h8300sxnmode, 0},
   {"sbranch", sbranch, L_8},
   {"lbranch", sbranch, L_16},
 
   {"sbranch", sbranch, L_8},
   {"lbranch", sbranch, L_16},
 
@@ -93,89 +205,139 @@ const pseudo_typeS md_pseudo_table[] =
   {"data.l", cons, 4},
   {"form", listing_psize, 0},
   {"heading", listing_title, 0},
   {"data.l", cons, 4},
   {"form", listing_psize, 0},
   {"heading", listing_title, 0},
-  {"import", s_ignore, 0},
-  {"page", listing_eject, 0},
+  {"import",  s_ignore, 0},
+  {"page",    listing_eject, 0},
   {"program", s_ignore, 0},
   {"program", s_ignore, 0},
+
+  {"section",   h8300_elf_section, 0},
+  {"section.s", h8300_elf_section, 0},
+  {"sect",      h8300_elf_section, 0},
+  {"sect.s",    h8300_elf_section, 0},
+
   {0, 0, 0}
 };
 
   {0, 0, 0}
 };
 
-const int md_reloc_size;
-
 const 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 */
+/* Chars that mean this number is a floating point constant
+   As in 0f12.456
+   or    0d1.2345e12.  */
 const char FLT_CHARS[] = "rRsSfFdDxXpP";
 
 const char FLT_CHARS[] = "rRsSfFdDxXpP";
 
-static struct hash_control *opcode_hash_control;       /* Opcode mnemonics */
+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.  */
 
 /* 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
 void
-md_begin ()
+md_begin (void)
 {
 {
-  struct h8_opcode *opcode;
+  unsigned int nopcodes;
+  struct h8_opcode *p, *p1;
+  struct h8_instruction *pi;
   char prev_buffer[100];
   int idx = 0;
 
   char prev_buffer[100];
   int idx = 0;
 
+  if (!bfd_set_arch_mach (stdoutput, bfd_arch_h8300, default_mach))
+    as_warn (_("could not set architecture and machine"));
+
   opcode_hash_control = hash_new ();
   prev_buffer[0] = 0;
 
   opcode_hash_control = hash_new ();
   prev_buffer[0] = 0;
 
-  for (opcode = h8_opcodes; opcode->name; opcode++)
+  nopcodes = sizeof (h8_opcodes) / sizeof (struct h8_opcode);
+
+  h8_instructions = XNEWVEC (struct h8_instruction, nopcodes);
+
+  pi = h8_instructions;
+  p1 = h8_opcodes;
+  /* We do a minimum amount of sorting on the opcode table; this is to
+     make it easy to describe the mova instructions without unnecessary
+     code duplication.
+     Sorting only takes place inside blocks of instructions of the form
+     X/Y, so for example mova/b, mova/w and mova/l can be intermixed.  */
+  while (p1)
     {
     {
-      /* 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;
+      struct h8_opcode *first_skipped = 0;
+      int len, cmplen = 0;
+      const char *src = p1->name;
+      char *dst, *buffer;
 
 
-      opcode->size = 0;
+      if (p1->name == 0)
+       break;
+      /* Strip off any . part when inserting the opcode and only enter
+        unique codes into the hash table.  */
+      dst = buffer = XNEWVEC (char, strlen (src) + 1);
       while (*src)
        {
          if (*src == '.')
            {
              src++;
       while (*src)
        {
          if (*src == '.')
            {
              src++;
-             opcode->size = *src;
              break;
            }
              break;
            }
+         if (*src == '/')
+           cmplen = src - p1->name + 1;
          *dst++ = *src++;
        }
          *dst++ = *src++;
        }
-      *dst++ = 0;
-      if (strcmp (buffer, prev_buffer))
+      *dst = 0;
+      len = dst - buffer;
+      if (cmplen == 0)
+       cmplen = len;
+      hash_insert (opcode_hash_control, buffer, (char *) pi);
+      strcpy (prev_buffer, buffer);
+      idx++;
+
+      for (p = p1; p->name; p++)
        {
        {
-         hash_insert (opcode_hash_control, buffer, (char *) opcode);
-         strcpy (prev_buffer, buffer);
-         idx++;
-       }
-      opcode->idx = idx;
+         /* A negative TIME is used to indicate that we've added this opcode
+            already.  */
+         if (p->time == -1)
+           continue;
+         if (strncmp (p->name, buffer, cmplen) != 0
+             || (p->name[cmplen] != '\0' && p->name[cmplen] != '.'
+                 && p->name[cmplen - 1] != '/'))
+           {
+             if (first_skipped == 0)
+               first_skipped = p;
+             break;
+           }
+         if (strncmp (p->name, buffer, len) != 0)
+           {
+             if (first_skipped == 0)
+               first_skipped = p;
+             continue;
+           }
 
 
-      /* Find the number of operands.  */
-      opcode->noperands = 0;
-      while (opcode->args.nib[opcode->noperands] != E)
-       opcode->noperands++;
+         p->time = -1;
+         pi->size = p->name[len] == '.' ? p->name[len + 1] : 0;
+         pi->idx = idx;
 
 
-      /* Find the length of the opcode in bytes.  */
-      opcode->length = 0;
-      while (opcode->data.nib[opcode->length * 2] != E)
-       opcode->length++;
+         /* Find the number of operands.  */
+         pi->noperands = 0;
+         while (pi->noperands < 3 && p->args.nib[pi->noperands] != (op_type) E)
+           pi->noperands++;
+
+         /* Find the length of the opcode in bytes.  */
+         pi->length = 0;
+         while (p->data.nib[pi->length * 2] != (op_type) E)
+           pi->length++;
+
+         pi->opcode = p;
+         pi++;
+       }
+      p1 = first_skipped;
     }
 
     }
 
+  /* Add entry for the NULL vector terminator.  */
+  pi->length = 0;
+  pi->noperands = 0;
+  pi->idx = 0;
+  pi->size = 0;
+  pi->opcode = 0;
+
   linkrelax = 1;
 }
 
   linkrelax = 1;
 }
 
-struct h8_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;
 struct h8_op
 {
   op_type mode;
@@ -183,6 +345,20 @@ struct h8_op
   expressionS exp;
 };
 
   expressionS exp;
 };
 
+static void clever_message (const struct h8_instruction *, struct h8_op *);
+static void fix_operand_size (struct h8_op *, int);
+static void build_bytes (const struct h8_instruction *, struct h8_op *);
+static void do_a_fix_imm (int, int, struct h8_op *, int, const struct h8_instruction *);
+static void check_operand (struct h8_op *, unsigned int, const char *);
+static const struct h8_instruction * get_specific (const struct h8_instruction *, struct h8_op *, int) ;
+static char *get_operands (unsigned, char *, struct h8_op *);
+static void get_operand (char **, struct h8_op *, int);
+static int parse_reg (char *, op_type *, unsigned *, int);
+static char *skip_colonthing (char *, int *);
+static char *parse_exp (char *, struct h8_op *);
+
+static int constant_fits_size_p (struct h8_op *, int, int);
+
 /*
   parse operands
   WREG r0,r1,r2,r3,r4,r5,r6,r7,fp,sp
 /*
   parse operands
   WREG r0,r1,r2,r3,r4,r5,r6,r7,fp,sp
@@ -194,52 +370,72 @@ struct h8_op
   ccr
 */
 
   ccr
 */
 
-/* Try and parse a reg name, returns number of chars consumed.  */
-static int
-parse_reg (src, mode, reg, direction)
-     char *src;
-     op_type *mode;
-     unsigned int *reg;
-     int direction;
+/* Try to parse a reg name.  Return the number of chars consumed.  */
 
 
+static int
+parse_reg (char *src, op_type *mode, unsigned int *reg, int direction)
 {
   char *end;
   int len;
 
 {
   char *end;
   int len;
 
-  /* Cribbed from get_symbol_end.  */
+  /* Cribbed from get_symbol_name.  */
   if (!is_name_beginner (*src) || *src == '\001')
     return 0;
   end = src + 1;
   if (!is_name_beginner (*src) || *src == '\001')
     return 0;
   end = src + 1;
-  while (is_part_of_name (*end) || *end == '\001')
+  while ((is_part_of_name (*end) && *end != '.') || *end == '\001')
     end++;
   len = end - src;
 
     end++;
   len = end - src;
 
-  if (len == 2 && src[0] == 's' && src[1] == 'p')
+  if (len == 2 && TOLOWER (src[0]) == 's' && TOLOWER (src[1]) == 'p')
     {
       *mode = PSIZE | REG | direction;
       *reg = 7;
       return len;
     }
     {
       *mode = PSIZE | REG | direction;
       *reg = 7;
       return len;
     }
-  if (len == 3 && src[0] == 'c' && src[1] == 'c' && src[2] == 'r')
+  if (len == 3 &&
+      TOLOWER (src[0]) == 'c' &&
+      TOLOWER (src[1]) == 'c' &&
+      TOLOWER (src[2]) == 'r')
     {
       *mode = CCR;
       *reg = 0;
       return len;
     }
     {
       *mode = CCR;
       *reg = 0;
       return len;
     }
-  if (len == 3 && src[0] == 'e' && src[1] == 'x' && src[2] == 'r')
+  if (len == 3 &&
+      TOLOWER (src[0]) == 'e' &&
+      TOLOWER (src[1]) == 'x' &&
+      TOLOWER (src[2]) == 'r')
     {
       *mode = EXR;
     {
       *mode = EXR;
-      *reg = 0;
+      *reg = 1;
+      return len;
+    }
+  if (len == 3 &&
+      TOLOWER (src[0]) == 'v' &&
+      TOLOWER (src[1]) == 'b' &&
+      TOLOWER (src[2]) == 'r')
+    {
+      *mode = VBR;
+      *reg = 6;
+      return len;
+    }
+  if (len == 3 &&
+      TOLOWER (src[0]) == 's' &&
+      TOLOWER (src[1]) == 'b' &&
+      TOLOWER (src[2]) == 'r')
+    {
+      *mode = SBR;
+      *reg = 7;
       return len;
     }
       return len;
     }
-  if (len == 2 && src[0] == 'f' && src[1] == 'p')
+  if (len == 2 && TOLOWER (src[0]) == 'f' && TOLOWER (src[1]) == 'p')
     {
       *mode = PSIZE | REG | direction;
       *reg = 6;
       return len;
     }
     {
       *mode = PSIZE | REG | direction;
       *reg = 6;
       return len;
     }
-  if (len == 3 && src[0] == 'e' && src[1] == 'r'
-      && src[2] >= '0' && src[2] <= '7')
+  if (len == 3 && TOLOWER (src[0]) == 'e' && TOLOWER (src[1]) == 'r' &&
+      src[2] >= '0' && src[2] <= '7')
     {
       *mode = L_32 | REG | direction;
       *reg = src[2] - '0';
     {
       *mode = L_32 | REG | direction;
       *reg = src[2] - '0';
@@ -247,7 +443,7 @@ parse_reg (src, mode, reg, direction)
        as_warn (_("Reg not valid for H8/300"));
       return len;
     }
        as_warn (_("Reg not valid for H8/300"));
       return len;
     }
-  if (len == 2 && src[0] == 'e' && src[1] >= '0' && src[1] <= '7')
+  if (len == 2 && TOLOWER (src[0]) == 'e' && src[1] >= '0' && src[1] <= '7')
     {
       *mode = L_16 | REG | direction;
       *reg = src[1] - '0' + 8;
     {
       *mode = L_16 | REG | direction;
       *reg = src[1] - '0' + 8;
@@ -256,17 +452,17 @@ parse_reg (src, mode, reg, direction)
       return len;
     }
 
       return len;
     }
 
-  if (src[0] == 'r')
+  if (TOLOWER (src[0]) == 'r')
     {
       if (src[1] >= '0' && src[1] <= '7')
        {
     {
       if (src[1] >= '0' && src[1] <= '7')
        {
-         if (len == 3 && src[2] == 'l')
+         if (len == 3 && TOLOWER (src[2]) == 'l')
            {
              *mode = L_8 | REG | direction;
              *reg = (src[1] - '0') + 8;
              return len;
            }
            {
              *mode = L_8 | REG | direction;
              *reg = (src[1] - '0') + 8;
              return len;
            }
-         if (len == 3 && src[2] == 'h')
+         if (len == 3 && TOLOWER (src[2]) == 'h')
            {
              *mode = L_8 | REG | direction;
              *reg = (src[1] - '0');
            {
              *mode = L_8 | REG | direction;
              *reg = (src[1] - '0');
@@ -284,59 +480,61 @@ parse_reg (src, mode, reg, direction)
   return 0;
 }
 
   return 0;
 }
 
+
+/* Parse an immediate or address-related constant and store it in OP.
+   If the user also specifies the operand's size, store that size
+   in OP->MODE, otherwise leave it for later code to decide.  */
+
 static char *
 static char *
-parse_exp (s, op)
-     char *s;
-     expressionS *op;
+parse_exp (char *src, struct h8_op *op)
 {
 {
-  char *save = input_line_pointer;
-  char *new;
+  char *save;
 
 
-  input_line_pointer = s;
-  expression (op);
-  if (op->X_op == O_absent)
+  save = input_line_pointer;
+  input_line_pointer = src;
+  expression (&op->exp);
+  if (op->exp.X_op == O_absent)
     as_bad (_("missing operand"));
     as_bad (_("missing operand"));
-  new = input_line_pointer;
+  src = input_line_pointer;
   input_line_pointer = save;
   input_line_pointer = save;
-  return new;
+
+  return skip_colonthing (src, &op->mode);
 }
 
 }
 
+
+/* If SRC starts with an explicit operand size, skip it and store the size
+   in *MODE.  Leave *MODE unchanged otherwise.  */
+
 static char *
 static char *
-skip_colonthing (ptr, exp, mode)
-     char *ptr;
-     expressionS *exp ATTRIBUTE_UNUSED;
-     int *mode;
+skip_colonthing (char *src, int *mode)
 {
 {
-  if (*ptr == ':')
+  if (*src == ':')
     {
     {
-      ptr++;
+      src++;
       *mode &= ~SIZE;
       *mode &= ~SIZE;
-      if (*ptr == '8')
-       {
-         ptr++;
-         /* ff fill any 8 bit quantity */
-         /* exp->X_add_number -= 0x100; */
-         *mode |= L_8;
-       }
+      if (src[0] == '8' && !ISDIGIT (src[1]))
+       *mode |= L_8;
+      else if (src[0] == '2' && !ISDIGIT (src[1]))
+       *mode |= L_2;
+      else if (src[0] == '3' && !ISDIGIT (src[1]))
+       *mode |= L_3;
+      else if (src[0] == '4' && !ISDIGIT (src[1]))
+       *mode |= L_4;
+      else if (src[0] == '5' && !ISDIGIT (src[1]))
+       *mode |= L_5;
+      else if (src[0] == '2' && src[1] == '4' && !ISDIGIT (src[2]))
+       *mode |= L_24;
+      else if (src[0] == '3' && src[1] == '2' && !ISDIGIT (src[2]))
+       *mode |= L_32;
+      else if (src[0] == '1' && src[1] == '6' && !ISDIGIT (src[2]))
+       *mode |= L_16;
       else
       else
-       {
-         if (*ptr == '2')
-           {
-             *mode |= L_24;
-           }
-         else if (*ptr == '3')
-           {
-             *mode |= L_32;
-           }
-         else if (*ptr == '1')
-           {
-             *mode |= L_16;
-           }
-         while (isdigit (*ptr))
-           ptr++;
-       }
+       as_bad (_("invalid operand size requested"));
+
+      while (ISDIGIT (*src))
+       src++;
     }
     }
-  return ptr;
+  return src;
 }
 
 /* The many forms of operand:
 }
 
 /* The many forms of operand:
@@ -352,76 +550,90 @@ skip_colonthing (ptr, exp, mode)
 
    #xx[:size]          immediate data
    @(exp:[8], pc)      pc rel
 
    #xx[:size]          immediate data
    @(exp:[8], pc)      pc rel
-   @@aa[:8]            memory indirect
+   @@aa[:8]            memory indirect.  */
 
 
-   */
+static int
+constant_fits_width_p (struct h8_op *operand, offsetT width)
+{
+  offsetT num;
 
 
-char *
-colonmod24 (op, src)
-     struct h8_op *op;
-     char *src;
+  num = ((operand->exp.X_add_number & 0xffffffff) ^ 0x80000000) - 0x80000000;
+  return (num & ~width) == 0 || (num | width) == ~0;
+}
 
 
+static int
+constant_fits_size_p (struct h8_op *operand, int size, int no_symbols)
 {
 {
-  int mode = 0;
-  src = skip_colonthing (src, &op->exp, &mode);
+  offsetT num;
 
 
-  if (!mode)
+  if (no_symbols
+      && (operand->exp.X_add_symbol != 0 || operand->exp.X_op_symbol != 0))
+    return 0;
+  num = operand->exp.X_add_number & 0xffffffff;
+  switch (size)
     {
     {
-      /* 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_op_symbol)
-       mode = DSYMMODE;
-      else
-       mode = DMODE;
+    case L_2:
+      return (num & ~3) == 0;
+    case L_3:
+      return (num & ~7) == 0;
+    case L_3NZ:
+      return num >= 1 && num < 8;
+    case L_4:
+      return (num & ~15) == 0;
+    case L_5:
+      return num >= 1 && num < 32;
+    case L_8:
+      num = (num ^ 0x80000000) - 0x80000000;
+      return (num & ~0xFF) == 0 || (num | 0x7F) == ~0;
+    case L_8U:
+      return (num & ~0xFF) == 0;
+    case L_16:
+      num = (num ^ 0x80000000) - 0x80000000;
+      return (num & ~0xFFFF) == 0 || (num | 0x7FFF) == ~0;
+    case L_16U:
+      return (num & ~0xFFFF) == 0;
+    case L_32:
+      return 1;
+    default:
+      abort ();
     }
     }
-  op->mode |= mode;
-  return src;
-
 }
 
 static void
 }
 
 static void
-get_operand (ptr, op, dst, direction)
-     char **ptr;
-     struct h8_op *op;
-     unsigned int dst ATTRIBUTE_UNUSED;
-     int direction;
+get_operand (char **ptr, struct h8_op *op, int direction)
 {
   char *src = *ptr;
   op_type mode;
   unsigned int num;
   unsigned int len;
 
 {
   char *src = *ptr;
   op_type mode;
   unsigned int num;
   unsigned int len;
 
-  op->mode = E;
+  op->mode = 0;
+
+  /* Check for '(' and ')' for instructions ldm and stm.  */
+  if (src[0] == '(' && src[8] == ')')
+    ++ src;
 
   /* Gross.  Gross.  ldm and stm have a format not easily handled
      by get_operand.  We deal with it explicitly here.  */
 
   /* Gross.  Gross.  ldm and stm have a format not easily handled
      by get_operand.  We deal with it explicitly here.  */
-  if (src[0] == 'e' && src[1] == 'r' && isdigit (src[2])
-      && src[3] == '-' && src[4] == 'e' && src[5] == 'r' && isdigit (src[6]))
+  if (TOLOWER (src[0]) == 'e' && TOLOWER (src[1]) == 'r' &&
+      ISDIGIT (src[2]) && src[3] == '-' &&
+      TOLOWER (src[4]) == 'e' && TOLOWER (src[5]) == 'r' && ISDIGIT (src[6]))
     {
       int low, high;
 
       low = src[2] - '0';
       high = src[6] - '0';
 
     {
       int low, high;
 
       low = src[2] - '0';
       high = src[6] - '0';
 
-      if (high < low)
-       as_bad (_("Invalid register list for ldm/stm\n"));
-
-      if (low % 2)
-       as_bad (_("Invalid register list for ldm/stm\n"));
-
-      if (high - low > 3)
-       as_bad (_("Invalid register list for ldm/stm\n"));
-
-      if (high - low != 1
-         && low % 4)
+       /* Check register pair's validity as per tech note TN-H8*-193A/E
+         from Renesas for H8S and H8SX hardware manual.  */
+      if (   !(low == 0 && (high == 1 || high == 2 || high == 3))
+          && !(low == 1 && (high == 2 || high == 3 || high == 4) && SXmode)
+          && !(low == 2 && (high == 3 || ((high == 4 || high == 5) && SXmode)))
+          && !(low == 3 && (high == 4 || high == 5 || high == 6) && SXmode)
+          && !(low == 4 && (high == 5 || high == 6))
+          && !(low == 4 && high == 7 && SXmode)
+          && !(low == 5 && (high == 6 || high == 7) && SXmode)
+          && !(low == 6 && high == 7 && SXmode))
        as_bad (_("Invalid register list for ldm/stm\n"));
 
       /* Even sicker.  We encode two registers into op->reg.  One
        as_bad (_("Invalid register list for ldm/stm\n"));
 
       /* Even sicker.  We encode two registers into op->reg.  One
@@ -430,14 +642,47 @@ get_operand (ptr, op, dst, direction)
         so we know this is "very special".  */
       op->reg = 0x80000000 | (high << 8) | low;
       op->mode = REG;
         so we know this is "very special".  */
       op->reg = 0x80000000 | (high << 8) | low;
       op->mode = REG;
-      *ptr = src + 7;
+      if (src[7] == ')')
+       *ptr = src + 8;
+      else
+       *ptr = src + 7;
       return;
     }
 
   len = parse_reg (src, &op->mode, &op->reg, direction);
   if (len)
     {
       return;
     }
 
   len = parse_reg (src, &op->mode, &op->reg, direction);
   if (len)
     {
-      *ptr = src + len;
+      src += len;
+      if (*src == '.')
+       {
+         int size = op->mode & SIZE;
+         switch (src[1])
+           {
+           case 'l': case 'L':
+             if (size != L_32)
+               as_warn (_("mismatch between register and suffix"));
+             op->mode = (op->mode & ~MODE) | LOWREG;
+             break;
+           case 'w': case 'W':
+             if (size != L_32 && size != L_16)
+               as_warn (_("mismatch between register and suffix"));
+             op->mode = (op->mode & ~MODE) | LOWREG;
+             op->mode = (op->mode & ~SIZE) | L_16;
+             break;
+           case 'b': case 'B':
+             op->mode = (op->mode & ~MODE) | LOWREG;
+             if (size != L_32 && size != L_8)
+               as_warn (_("mismatch between register and suffix"));
+             op->mode = (op->mode & ~MODE) | LOWREG;
+             op->mode = (op->mode & ~SIZE) | L_8;
+             break;
+           default:
+             as_warn (_("invalid suffix after register."));
+             break;
+           }
+         src += 2;
+       }
+      *ptr = src;
       return;
     }
 
       return;
     }
 
@@ -446,56 +691,95 @@ get_operand (ptr, op, dst, direction)
       src++;
       if (*src == '@')
        {
       src++;
       if (*src == '@')
        {
-         src++;
-         src = parse_exp (src, &op->exp);
-
-         src = skip_colonthing (src, &op->exp, &op->mode);
-
-         *ptr = src;
-
-         op->mode = MEMIND;
+         *ptr = parse_exp (src + 1, op);
+         if (op->exp.X_add_number >= 0x100)
+           {
+             int divisor = 1;
+
+             op->mode = VECIND;
+             /* FIXME : 2?  or 4?  */
+             if (op->exp.X_add_number >= 0x400)
+               as_bad (_("address too high for vector table jmp/jsr"));
+             else if (op->exp.X_add_number >= 0x200)
+               divisor = 4;
+             else
+               divisor = 2;
+
+             op->exp.X_add_number = op->exp.X_add_number / divisor - 0x80;
+           }
+         else
+           op->mode = MEMIND;
          return;
        }
 
          return;
        }
 
-      if (*src == '-')
+      if (*src == '-' || *src == '+')
        {
        {
-         src++;
-         len = parse_reg (src, &mode, &num, direction);
+         len = parse_reg (src + 1, &mode, &num, direction);
          if (len == 0)
            {
              /* Oops, not a reg after all, must be ordinary exp.  */
          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);
-
+             op->mode = ABS | direction;
+             *ptr = parse_exp (src, op);
              return;
            }
 
              return;
            }
 
-         if ((mode & SIZE) != PSIZE)
+         if (((mode & SIZE) != PSIZE)
+             /* For Normal mode accept 16 bit and 32 bit pointer registers.  */
+             && (!Nmode || ((mode & SIZE) != L_32)))
            as_bad (_("Wrong size pointer register for architecture."));
            as_bad (_("Wrong size pointer register for architecture."));
-         op->mode = RDDEC;
+
+         op->mode = src[0] == '-' ? RDPREDEC : RDPREINC;
          op->reg = num;
          op->reg = num;
-         *ptr = src + len;
+         *ptr = src + 1 + len;
          return;
        }
       if (*src == '(')
        {
          return;
        }
       if (*src == '(')
        {
-         /* Disp.  */
          src++;
 
          src++;
 
-         /* Start off assuming a 16 bit offset.  */
+         /* See if this is @(ERn.x, PC).  */
+         len = parse_reg (src, &mode, &op->reg, direction);
+         if (len != 0 && (mode & MODE) == REG && src[len] == '.')
+           {
+             switch (TOLOWER (src[len + 1]))
+               {
+               case 'b':
+                 mode = PCIDXB | direction;
+                 break;
+               case 'w':
+                 mode = PCIDXW | direction;
+                 break;
+               case 'l':
+                 mode = PCIDXL | direction;
+                 break;
+               default:
+                 mode = 0;
+                 break;
+               }
+             if (mode
+                 && src[len + 2] == ','
+                 && TOLOWER (src[len + 3]) != 'p'
+                 && TOLOWER (src[len + 4]) != 'c'
+                 && src[len + 5] != ')')
+               {
+                 *ptr = src + len + 6;
+                 op->mode |= mode;
+                 return;
+               }
+             /* Fall through into disp case - the grammar is somewhat
+                ambiguous, so we should try whether it's a DISP operand
+                after all ("ER3.L" might be a poorly named label...).  */
+           }
 
 
-         src = parse_exp (src, &op->exp);
+         /* Disp.  */
 
 
-         src = colonmod24 (op, src);
+         /* Start off assuming a 16 bit offset.  */
 
 
+         src = parse_exp (src, op);
          if (*src == ')')
            {
          if (*src == ')')
            {
-             src++;
              op->mode |= ABS | direction;
              op->mode |= ABS | direction;
-             *ptr = src;
+             *ptr = src + 1;
              return;
            }
 
              return;
            }
 
@@ -503,28 +787,45 @@ get_operand (ptr, op, dst, direction)
            {
              as_bad (_("expected @(exp, reg16)"));
              return;
            {
              as_bad (_("expected @(exp, reg16)"));
              return;
-
            }
          src++;
 
          len = parse_reg (src, &mode, &op->reg, direction);
            }
          src++;
 
          len = parse_reg (src, &mode, &op->reg, direction);
-         if (len == 0 || !(mode & REG))
+         if (len == 0 || (mode & MODE) != REG)
            {
              as_bad (_("expected @(exp, reg16)"));
              return;
            }
            {
              as_bad (_("expected @(exp, reg16)"));
              return;
            }
-         op->mode |= DISP | direction;
-         dispreg = op->reg;
          src += len;
          src += len;
-         src = skip_colonthing (src, &op->exp, &op->mode);
+         if (src[0] == '.')
+           {
+             switch (TOLOWER (src[1]))
+               {
+               case 'b':
+                 op->mode |= INDEXB | direction;
+                 break;
+               case 'w':
+                 op->mode |= INDEXW | direction;
+                 break;
+               case 'l':
+                 op->mode |= INDEXL | direction;
+                 break;
+               default:
+                 as_bad (_("expected .L, .W or .B for register in indexed addressing mode"));
+               }
+             src += 2;
+             op->reg &= 7;
+           }
+         else
+           op->mode |= DISP | direction;
+         src = skip_colonthing (src, &op->mode);
 
 
-         if (*src != ')' && '(')
+         if (*src != ')')
            {
              as_bad (_("expected @(exp, reg16)"));
              return;
            }
          *ptr = src + 1;
            {
              as_bad (_("expected @(exp, reg16)"));
              return;
            }
          *ptr = src + 1;
-
          return;
        }
       len = parse_reg (src, &mode, &num, direction);
          return;
        }
       len = parse_reg (src, &mode, &num, direction);
@@ -532,17 +833,21 @@ get_operand (ptr, op, dst, direction)
       if (len)
        {
          src += len;
       if (len)
        {
          src += len;
-         if (*src == '+')
+         if (*src == '+' || *src == '-')
            {
            {
-             src++;
-             if ((mode & SIZE) != PSIZE)
+             if (((mode & SIZE) != PSIZE)
+                 /* For Normal mode accept 16 bit and 32 bit pointer registers.  */
+                 && (!Nmode || ((mode & SIZE) != L_32)))
                as_bad (_("Wrong size pointer register for architecture."));
                as_bad (_("Wrong size pointer register for architecture."));
-             op->mode = RSINC;
+             op->mode = *src == '+' ? RSPOSTINC : RSPOSTDEC;
              op->reg = num;
              op->reg = num;
+             src++;
              *ptr = src;
              return;
            }
              *ptr = src;
              return;
            }
-         if ((mode & SIZE) != PSIZE)
+         if (((mode & SIZE) != PSIZE)
+             /* For Normal mode accept 16 bit and 32 bit pointer registers.  */
+             && (!Nmode || ((mode & SIZE) != L_32)))
            as_bad (_("Wrong size pointer register for architecture."));
 
          op->mode = direction | IND | PSIZE;
            as_bad (_("Wrong size pointer register for architecture."));
 
          op->mode = direction | IND | PSIZE;
@@ -556,229 +861,426 @@ get_operand (ptr, op, dst, direction)
          /* must be a symbol */
 
          op->mode = ABS | direction;
          /* must be a symbol */
 
          op->mode = ABS | direction;
-         src = parse_exp (src, &op->exp);
-
-         *ptr = colonmod24 (op, src);
-
+         *ptr = parse_exp (src, op);
          return;
        }
     }
 
   if (*src == '#')
     {
          return;
        }
     }
 
   if (*src == '#')
     {
-      src++;
       op->mode = IMM;
       op->mode = IMM;
-      src = parse_exp (src, &op->exp);
-      *ptr = skip_colonthing (src, &op->exp, &op->mode);
-
+      *ptr = parse_exp (src + 1, op);
       return;
     }
       return;
     }
-  else if (strncmp (src, "mach", 4) == 0
-          || strncmp (src, "macl", 4) == 0)
+  else if (strncmp (src, "mach", 4) == 0 ||
+          strncmp (src, "macl", 4) == 0 ||
+          strncmp (src, "MACH", 4) == 0 ||
+          strncmp (src, "MACL", 4) == 0)
     {
     {
-      op->reg = src[3] == 'l';
+      op->reg = TOLOWER (src[3]) == 'l';
       op->mode = MACREG;
       *ptr = src + 4;
       return;
     }
   else
     {
       op->mode = MACREG;
       *ptr = src + 4;
       return;
     }
   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;
+      op->mode = PCREL;
+      *ptr = parse_exp (src, op);
     }
 }
 
 static char *
     }
 }
 
 static char *
-get_operands (noperands, op_end, operand)
-     unsigned int noperands;
-     char *op_end;
-     struct h8_op *operand;
+get_operands (unsigned int noperands, char *op_end, struct h8_op *operand)
 {
   char *ptr = op_end;
 
   switch (noperands)
     {
     case 0:
 {
   char *ptr = op_end;
 
   switch (noperands)
     {
     case 0:
-      operand[0].mode = 0;
-      operand[1].mode = 0;
       break;
 
     case 1:
       ptr++;
       break;
 
     case 1:
       ptr++;
-      get_operand (&ptr, operand + 0, 0, SRC);
+      get_operand (&ptr, operand + 0, SRC);
       if (*ptr == ',')
        {
          ptr++;
       if (*ptr == ',')
        {
          ptr++;
-         get_operand (&ptr, operand + 1, 1, DST);
+         get_operand (&ptr, operand + 1, DST);
        }
        }
-      else
+      break;
+
+    case 2:
+      ptr++;
+      get_operand (&ptr, operand + 0, SRC);
+      if (*ptr == ',')
+       ptr++;
+      get_operand (&ptr, operand + 1, DST);
+      break;
+
+    case 3:
+      ptr++;
+      get_operand (&ptr, operand + 0, SRC);
+      if (*ptr == ',')
+       ptr++;
+      get_operand (&ptr, operand + 1, DST);
+      if (*ptr == ',')
+       ptr++;
+      get_operand (&ptr, operand + 2, OP3);
+      break;
+
+    default:
+      abort ();
+    }
+
+  return ptr;
+}
+
+/* MOVA has special requirements.  Rather than adding twice the amount of
+   addressing modes, we simply special case it a bit.  */
+static void
+get_mova_operands (char *op_end, struct h8_op *operand)
+{
+  char *ptr = op_end;
+
+  if (ptr[1] != '@' || ptr[2] != '(')
+    goto error;
+  ptr += 3;
+  operand[0].mode = 0;
+  ptr = parse_exp (ptr, &operand[0]);
+
+  if (*ptr !=',')
+    goto error;
+  ptr++;
+  get_operand (&ptr, operand + 1, DST);
+
+  if (*ptr =='.')
+    {
+      ptr++;
+      switch (*ptr++)
+       {
+       case 'b': case 'B':
+         operand[0].mode = (operand[0].mode & ~MODE) | INDEXB;
+         break;
+       case 'w': case 'W':
+         operand[0].mode = (operand[0].mode & ~MODE) | INDEXW;
+         break;
+       case 'l': case 'L':
+         operand[0].mode = (operand[0].mode & ~MODE) | INDEXL;
+         break;
+       default:
+         goto error;
+       }
+    }
+  else if ((operand[1].mode & MODE) == LOWREG)
+    {
+      switch (operand[1].mode & SIZE)
        {
        {
-         operand[1].mode = 0;
+       case L_8:
+         operand[0].mode = (operand[0].mode & ~MODE) | INDEXB;
+         break;
+       case L_16:
+         operand[0].mode = (operand[0].mode & ~MODE) | INDEXW;
+         break;
+       case L_32:
+         operand[0].mode = (operand[0].mode & ~MODE) | INDEXL;
+         break;
+       default:
+         goto error;
+       }
+    }
+  else
+    goto error;
+
+  if (*ptr++ != ')' || *ptr++ != ',')
+    goto error;
+  get_operand (&ptr, operand + 2, OP3);
+  /* See if we can use the short form of MOVA.  */
+  if (((operand[1].mode & MODE) == REG || (operand[1].mode & MODE) == LOWREG)
+      && (operand[2].mode & MODE) == REG
+      && (operand[1].reg & 7) == (operand[2].reg & 7))
+    {
+      operand[1].mode = operand[2].mode = 0;
+      operand[0].reg = operand[2].reg & 7;
+    }
+  return;
+
+ error:
+  as_bad (_("expected valid addressing mode for mova: \"@(disp, ea.sz),ERn\""));
+}
+
+static void
+get_rtsl_operands (char *ptr, struct h8_op *operand)
+{
+  int mode, len, type = 0;
+  unsigned int num, num2;
+
+  ptr++;
+  if (*ptr == '(')
+    {
+      ptr++;
+      type = 1;
+    }
+  len = parse_reg (ptr, &mode, &num, SRC);
+  if (len == 0 || (mode & MODE) != REG)
+    {
+      as_bad (_("expected register"));
+      return;
+    }
+  ptr += len;
+  if (*ptr == '-')
+    {
+      len = parse_reg (++ptr, &mode, &num2, SRC);
+      if (len == 0 || (mode & MODE) != REG)
+       {
+         as_bad (_("expected register"));
+         return;
+       }
+      ptr += len;
+      /* CONST_xxx are used as placeholders in the opcode table.  */
+      num = num2 - num;
+      if (num > 3)
+       {
+         as_bad (_("invalid register list"));
+         return;
        }
        }
-      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;
+  else
+    num2 = num, num = 0;
+  if (type == 1 && *ptr++ != ')')
+    {
+      as_bad (_("expected closing paren"));
+      return;
+    }
+  operand[0].mode = RS32;
+  operand[1].mode = RD32;
+  operand[0].reg = num;
+  operand[1].reg = num2;
 }
 
 /* Passed a pointer to a list of opcodes which use different
    addressing modes, return the opcode which matches the opcodes
    provided.  */
 }
 
 /* Passed a pointer to a list of opcodes which use different
    addressing modes, return the opcode which matches the opcodes
    provided.  */
-static struct h8_opcode *
-get_specific (opcode, operands, size)
-     struct h8_opcode *opcode;
-     struct h8_op *operands;
-     int size;
+
+static const struct h8_instruction *
+get_specific (const struct h8_instruction *instruction,
+             struct h8_op *operands, int size)
 {
 {
-  struct h8_opcode *this_try = opcode;
+  const struct h8_instruction *this_try = instruction;
+  const struct h8_instruction *found_other = 0, *found_mismatched = 0;
   int found = 0;
   int found = 0;
-
-  unsigned int this_index = opcode->idx;
+  int this_index = instruction->idx;
+  int noperands = 0;
 
   /* There's only one ldm/stm and it's easier to just
      get out quick for them.  */
 
   /* There's only one ldm/stm and it's easier to just
      get out quick for them.  */
-  if (strcmp (opcode->name, "stm.l") == 0
-      || strcmp (opcode->name, "ldm.l") == 0)
+  if (OP_KIND (instruction->opcode->how) == O_LDM
+      || OP_KIND (instruction->opcode->how) == O_STM)
     return this_try;
 
     return this_try;
 
-  while (this_index == opcode->idx && !found)
+  while (noperands < 3 && operands[noperands].mode != 0)
+    noperands++;
+
+  while (this_index == instruction->idx && !found)
     {
     {
-      found = 1;
+      int this_size;
 
 
-      this_try = opcode++;
-      if (this_try->noperands == 0)
-       {
-         int this_size;
+      found = 1;
+      this_try = instruction++;
+      this_size = this_try->opcode->how & SN;
 
 
-         this_size = this_try->how & SN;
-         if (this_size != size && (this_size != SB || size != SN))
-           found = 0;
-       }
-      else
+      if (this_try->noperands != noperands)
+       found = 0;
+      else if (this_try->noperands > 0)
        {
        {
-         unsigned int i;
+         int i;
 
          for (i = 0; i < this_try->noperands && found; i++)
            {
 
          for (i = 0; i < this_try->noperands && found; i++)
            {
-             op_type op = this_try->args.nib[i];
+             op_type op = this_try->opcode->args.nib[i];
+             int op_mode = op & MODE;
+             int op_size = op & SIZE;
              int x = operands[i].mode;
              int x = operands[i].mode;
+             int x_mode = x & MODE;
+             int x_size = x & SIZE;
 
 
-             if ((op & (DISP | REG)) == (DISP | REG)
-                 && ((x & (DISP | REG)) == (DISP | REG)))
+             if (op_mode == LOWREG && (x_mode == REG || x_mode == LOWREG))
                {
                {
-                 dispreg = operands[i].reg;
+                 if ((x_size == L_8 && (operands[i].reg & 8) == 0)
+                     || (x_size == L_16 && (operands[i].reg & 8) == 8))
+                   as_warn (_("can't use high part of register in operand %d"), i);
+
+                 if (x_size != op_size)
+                   found = 0;
                }
                }
-             else if (op & REG)
+             else if (op_mode == REG)
                {
                {
-                 if (!(x & REG))
+                 if (x_mode == LOWREG)
+                   x_mode = REG;
+                 if (x_mode != REG)
                    found = 0;
 
                    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;
+                 if (x_size == L_P)
+                   x_size = (Hmode ? L_32 : L_16);
+                 if (op_size == L_P)
+                   op_size = (Hmode ? L_32 : L_16);
 
                  /* The size of the reg is v important.  */
 
                  /* The size of the reg is v important.  */
-                 if ((op & SIZE) != (x & SIZE))
+                 if (op_size != x_size)
+                   found = 0;
+               }
+             else if (op_mode & CTRL)  /* control register */
+               {
+                 if (!(x_mode & CTRL))
                    found = 0;
                    found = 0;
+
+                 switch (x_mode)
+                   {
+                   case CCR:
+                     if (op_mode != CCR &&
+                         op_mode != CCR_EXR &&
+                         op_mode != CC_EX_VB_SB)
+                       found = 0;
+                     break;
+                   case EXR:
+                     if (op_mode != EXR &&
+                         op_mode != CCR_EXR &&
+                         op_mode != CC_EX_VB_SB)
+                       found = 0;
+                     break;
+                   case MACH:
+                     if (op_mode != MACH &&
+                         op_mode != MACREG)
+                       found = 0;
+                     break;
+                   case MACL:
+                     if (op_mode != MACL &&
+                         op_mode != MACREG)
+                       found = 0;
+                     break;
+                   case VBR:
+                     if (op_mode != VBR &&
+                         op_mode != VBR_SBR &&
+                         op_mode != CC_EX_VB_SB)
+                       found = 0;
+                     break;
+                   case SBR:
+                     if (op_mode != SBR &&
+                         op_mode != VBR_SBR &&
+                         op_mode != CC_EX_VB_SB)
+                       found = 0;
+                     break;
+                   }
                }
                }
-             else if ((op & ABSJMP) && (x & ABS))
+             else if ((op & ABSJMP) && (x_mode == ABS || x_mode == PCREL))
                {
                {
-                 operands[i].mode &= ~ABS;
+                 operands[i].mode &= ~MODE;
                  operands[i].mode |= ABSJMP;
                  /* But it may not be 24 bits long.  */
                  operands[i].mode |= ABSJMP;
                  /* But it may not be 24 bits long.  */
-                 if (!Hmode)
+                 if (x_mode == ABS && !Hmode)
                    {
                      operands[i].mode &= ~SIZE;
                      operands[i].mode |= L_16;
                    }
                    {
                      operands[i].mode &= ~SIZE;
                      operands[i].mode |= L_16;
                    }
+                 if ((operands[i].mode & SIZE) == L_32
+                     && (op_mode & SIZE) != L_32)
+                  found = 0;
                }
                }
-             else if ((op & (KBIT | DBIT)) && (x & IMM))
+             else if (x_mode == IMM && op_mode != IMM)
                {
                {
-                 /* This is ok if the immediate value is sensible.  */
+                 offsetT num = operands[i].exp.X_add_number & 0xffffffff;
+                 if (op_mode == KBIT || op_mode == DBIT)
+                   /* This is ok if the immediate value is sensible.  */;
+                 else if (op_mode == CONST_2)
+                   found = num == 2;
+                 else if (op_mode == CONST_4)
+                   found = num == 4;
+                 else if (op_mode == CONST_8)
+                   found = num == 8;
+                 else if (op_mode == CONST_16)
+                   found = num == 16;
+                 else
+                   found = 0;
                }
                }
-             else if (op & PCREL)
+             else if (op_mode == PCREL && op_mode == x_mode)
                {
                {
+                 /* movsd, bsr/bc and bsr/bs only come in PCREL16 flavour:
+                    If x_size is L_8, promote it.  */
+                 if (OP_KIND (this_try->opcode->how) == O_MOVSD
+                     || OP_KIND (this_try->opcode->how) == O_BSRBC
+                     || OP_KIND (this_try->opcode->how) == O_BSRBS)
+                   if (x_size == L_8)
+                     x_size = L_16;
+
                  /* The size of the displacement is important.  */
                  /* The size of the displacement is important.  */
-                 if ((op & SIZE) != (x & SIZE))
+                 if (op_size != x_size)
                    found = 0;
                }
                    found = 0;
                }
-             else if ((op & (DISP | IMM | ABS))
-                      && (op & (DISP | IMM | ABS)) == (x & (DISP | IMM | ABS)))
+             else if ((op_mode == DISP || op_mode == IMM || op_mode == ABS
+                       || op_mode == INDEXB || op_mode == INDEXW
+                       || op_mode == INDEXL)
+                      && op_mode == x_mode)
                {
                  /* Promote a L_24 to L_32 if it makes us match.  */
                {
                  /* Promote a L_24 to L_32 if it makes us match.  */
-                 if ((x & L_24) && (op & L_32))
+                 if (x_size == L_24 && op_size == L_32)
                    {
                    {
-                     x &= ~L_24;
-                     x |= L_32;
+                     x &= ~SIZE;
+                     x |= x_size = L_32;
                    }
                    }
-                 /* Promote an L8 to L_16 if it makes us match.  */
-                 if (op & ABS && op & L_8 && op & DISP)
-                   {
-                     if (x & L_16)
-                       found = 1;
-                   }
-                 else if ((x & SIZE) != 0
-                          && ((op & SIZE) != (x & SIZE)))
+
+                 if (((x_size == L_16 && op_size == L_16U)
+                      || (x_size == L_8 && op_size == L_8U)
+                      || (x_size == L_3 && op_size == L_3NZ))
+                     /* We're deliberately more permissive for ABS modes.  */
+                     && (op_mode == ABS
+                         || constant_fits_size_p (operands + i, op_size,
+                                                  op & NO_SYMBOLS)))
+                   x_size = op_size;
+
+                 if (x_size != 0 && op_size != x_size)
+                   found = 0;
+                 else if (x_size == 0
+                          && ! constant_fits_size_p (operands + i, op_size,
+                                                     op & NO_SYMBOLS))
                    found = 0;
                }
                    found = 0;
                }
-             else if ((op & MACREG) != (x & MACREG))
-               {
-                 found = 0;
-               }
-             else if ((op & MODE) != (x & MODE))
+             else if (op_mode != x_mode)
                {
                  found = 0;
                }
            }
        }
                {
                  found = 0;
                }
            }
        }
+      if (found)
+       {
+         if ((this_try->opcode->available == AV_H8SX && ! SXmode)
+             || (this_try->opcode->available == AV_H8S && ! Smode)
+             || (this_try->opcode->available == AV_H8H && ! Hmode))
+           found = 0, found_other = this_try;
+         else if (this_size != size && (this_size != SN && size != SN))
+           found_mismatched = this_try, found = 0;
+
+       }
     }
   if (found)
     return this_try;
     }
   if (found)
     return this_try;
-  else
-    return 0;
+  if (found_other)
+    {
+      as_warn (_("Opcode `%s' with these operand types not available in %s mode"),
+              found_other->opcode->name,
+              (! Hmode && ! Smode ? "H8/300"
+               : SXmode ? "H8sx"
+               : Smode ? "H8/300S"
+               : "H8/300H"));
+    }
+  else if (found_mismatched)
+    {
+      as_warn (_("mismatch between opcode size and operand size"));
+      return found_mismatched;
+    }
+  return 0;
 }
 
 static void
 }
 
 static void
-check_operand (operand, width, string)
-     struct h8_op *operand;
-     unsigned int width;
-     char *string;
+check_operand (struct h8_op *operand, unsigned int width, const char *string)
 {
   if (operand->exp.X_add_symbol == 0
       && operand->exp.X_op_symbol == 0)
 {
   if (operand->exp.X_add_symbol == 0
       && operand->exp.X_op_symbol == 0)
@@ -788,8 +1290,7 @@ check_operand (operand, width, string)
         anding with the width and seeing if the answer is 0 or all
         fs.  */
 
         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))
+      if (! constant_fits_width_p (operand, width))
        {
          if (width == 255
              && (operand->exp.X_add_number & 0xff00) == 0xff00)
        {
          if (width == 255
              && (operand->exp.X_add_number & 0xff00) == 0xff00)
@@ -798,6 +1299,14 @@ check_operand (operand, width, string)
                 fit a 16 bit address truncated into an 8 bit address
                 of something like bset.  */
            }
                 fit a 16 bit address truncated into an 8 bit address
                 of something like bset.  */
            }
+         else if (strcmp (string, "@") == 0
+                  && width == 0xffff
+                  && (operand->exp.X_add_number & 0xff8000) == 0xff8000)
+           {
+             /* Just ignore this one - which happens when trying to
+                fit a 24 bit address truncated into a 16 bit address
+                of something like mov.w.  */
+           }
          else
            {
              as_warn (_("operand %s0x%lx out of range."), string,
          else
            {
              as_warn (_("operand %s0x%lx out of range."), string,
@@ -818,55 +1327,75 @@ check_operand (operand, width, string)
      (may relax into an 8bit absolute address).  */
 
 static void
      (may relax into an 8bit absolute address).  */
 
 static void
-do_a_fix_imm (offset, operand, relaxmode)
-     int offset;
-     struct h8_op *operand;
-     int relaxmode;
+do_a_fix_imm (int offset, int nibble, struct h8_op *operand, int relaxmode, const struct h8_instruction *this_try)
 {
   int idx;
   int size;
   int where;
 {
   int idx;
   int size;
   int where;
+  char *bytes = frag_now->fr_literal + offset;
 
 
-  char *t = operand->mode & IMM ? "#" : "@";
+  const char *t = ((operand->mode & MODE) == IMM) ? "#" : "@";
 
   if (operand->exp.X_add_symbol == 0)
     {
 
   if (operand->exp.X_add_symbol == 0)
     {
-      char *bytes = frag_now->fr_literal + offset;
       switch (operand->mode & SIZE)
        {
        case L_2:
          check_operand (operand, 0x3, t);
       switch (operand->mode & SIZE)
        {
        case L_2:
          check_operand (operand, 0x3, t);
-         bytes[0] |= (operand->exp.X_add_number) << 4;
+         bytes[0] |= (operand->exp.X_add_number & 3) << (nibble ? 0 : 4);
          break;
        case L_3:
          break;
        case L_3:
+       case L_3NZ:
          check_operand (operand, 0x7, t);
          check_operand (operand, 0x7, t);
-         bytes[0] |= (operand->exp.X_add_number) << 4;
+         bytes[0] |= (operand->exp.X_add_number & 7) << (nibble ? 0 : 4);
+         break;
+       case L_4:
+         check_operand (operand, 0xF, t);
+         bytes[0] |= (operand->exp.X_add_number & 15) << (nibble ? 0 : 4);
+         break;
+       case L_5:
+         check_operand (operand, 0x1F, t);
+         bytes[0] |= operand->exp.X_add_number & 31;
          break;
        case L_8:
          break;
        case L_8:
+       case L_8U:
          check_operand (operand, 0xff, t);
          check_operand (operand, 0xff, t);
-         bytes[0] = operand->exp.X_add_number;
+         bytes[0] |= operand->exp.X_add_number;
          break;
        case L_16:
          break;
        case L_16:
+       case L_16U:
          check_operand (operand, 0xffff, t);
          check_operand (operand, 0xffff, t);
-         bytes[0] = operand->exp.X_add_number >> 8;
-         bytes[1] = operand->exp.X_add_number >> 0;
+         bytes[0] |= operand->exp.X_add_number >> 8;
+         bytes[1] |= operand->exp.X_add_number >> 0;
+         /* MOVA needs both relocs to relax the second operand properly.  */
+         if (relaxmode != 0
+             && (OP_KIND(this_try->opcode->how) == O_MOVAB
+                 || OP_KIND(this_try->opcode->how) == O_MOVAW
+                 || OP_KIND(this_try->opcode->how) == O_MOVAL))
+           {
+             idx = BFD_RELOC_16;
+             fix_new_exp (frag_now, offset, 2, &operand->exp, 0, idx);
+           }
          break;
        case L_24:
          check_operand (operand, 0xffffff, t);
          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;
+         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.  */
          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;
+         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;
          if (relaxmode != 0)
            {
          if (relaxmode != 0)
            {
-             idx = (relaxmode == 2) ? R_MOV24B1 : R_MOVL1;
+             if ((operand->mode & MODE) == DISP && relaxmode == 1)
+               idx = BFD_RELOC_H8_DISP32A16;
+             else
+               idx = (relaxmode == 2) ? R_MOV24B1 : R_MOVL1;
              fix_new_exp (frag_now, offset, 4, &operand->exp, 0, idx);
            }
          break;
              fix_new_exp (frag_now, offset, 4, &operand->exp, 0, idx);
            }
          break;
@@ -880,7 +1409,9 @@ do_a_fix_imm (offset, operand, relaxmode)
        case L_32:
          size = 4;
          where = (operand->mode & SIZE) == L_24 ? -1 : 0;
        case L_32:
          size = 4;
          where = (operand->mode & SIZE) == L_24 ? -1 : 0;
-         if (relaxmode == 2)
+         if ((operand->mode & MODE) == DISP && relaxmode == 1)
+           idx = BFD_RELOC_H8_DISP32A16;
+         else if (relaxmode == 2)
            idx = R_MOV24B1;
          else if (relaxmode == 1)
            idx = R_MOVL1;
            idx = R_MOV24B1;
          else if (relaxmode == 1)
            idx = R_MOVL1;
@@ -889,7 +1420,9 @@ do_a_fix_imm (offset, operand, relaxmode)
          break;
        default:
          as_bad (_("Can't work out size of operand.\n"));
          break;
        default:
          as_bad (_("Can't work out size of operand.\n"));
+         /* Fall through.  */
        case L_16:
        case L_16:
+       case L_16U:
          size = 2;
          where = 0;
          if (relaxmode == 2)
          size = 2;
          where = 0;
          if (relaxmode == 2)
@@ -898,6 +1431,7 @@ do_a_fix_imm (offset, operand, relaxmode)
            idx = R_RELWORD;
          operand->exp.X_add_number =
            ((operand->exp.X_add_number & 0xffff) ^ 0x8000) - 0x8000;
            idx = R_RELWORD;
          operand->exp.X_add_number =
            ((operand->exp.X_add_number & 0xffff) ^ 0x8000) - 0x8000;
+         operand->exp.X_add_number |= (bytes[0] << 8) | bytes[1];
          break;
        case L_8:
          size = 1;
          break;
        case L_8:
          size = 1;
@@ -905,6 +1439,7 @@ do_a_fix_imm (offset, operand, relaxmode)
          idx = R_RELBYTE;
          operand->exp.X_add_number =
            ((operand->exp.X_add_number & 0xff) ^ 0x80) - 0x80;
          idx = R_RELBYTE;
          operand->exp.X_add_number =
            ((operand->exp.X_add_number & 0xff) ^ 0x80) - 0x80;
+         operand->exp.X_add_number |= bytes[0];
        }
 
       fix_new_exp (frag_now,
        }
 
       fix_new_exp (frag_now,
@@ -917,66 +1452,85 @@ do_a_fix_imm (offset, operand, relaxmode)
 }
 
 /* Now we know what sort of opcodes it is, let's build the bytes.  */
 }
 
 /* Now we know what sort of opcodes it is, let's build the bytes.  */
+
 static void
 static void
-build_bytes (this_try, operand)
-     struct h8_opcode *this_try;
-     struct h8_op *operand;
+build_bytes (const struct h8_instruction *this_try, struct h8_op *operand)
 {
 {
-  unsigned int i;
-
+  int i;
   char *output = frag_more (this_try->length);
   char *output = frag_more (this_try->length);
-  op_type *nibble_ptr = this_try->data.nib;
+  const op_type *nibble_ptr = this_try->opcode->data.nib;
   op_type c;
   unsigned int nibble_count = 0;
   op_type c;
   unsigned int nibble_count = 0;
-  int absat;
-  int immat;
-  int nib;
+  int op_at[3];
+  int nib = 0;
   int movb = 0;
   int movb = 0;
-  char asnibbles[30];
+  char asnibbles[100];
   char *p = asnibbles;
   char *p = asnibbles;
+  int high, low;
 
 
-  if (!(this_try->inbase || Hmode))
+  if (!Hmode && this_try->opcode->available != AV_H8)
     as_warn (_("Opcode `%s' with these operand types not available in H8/300 mode"),
     as_warn (_("Opcode `%s' with these operand types not available in H8/300 mode"),
-            this_try->name);
-
-  while (*nibble_ptr != E)
+            this_try->opcode->name);
+  else if (!Smode
+          && this_try->opcode->available != AV_H8
+          && this_try->opcode->available != AV_H8H)
+    as_warn (_("Opcode `%s' with these operand types not available in H8/300H mode"),
+            this_try->opcode->name);
+  else if (!SXmode
+          && this_try->opcode->available != AV_H8
+          && this_try->opcode->available != AV_H8H
+          && this_try->opcode->available != AV_H8S)
+    as_warn (_("Opcode `%s' with these operand types not available in H8/300S mode"),
+            this_try->opcode->name);
+
+  while (*nibble_ptr != (op_type) E)
     {
       int d;
     {
       int d;
+
+      nib = 0;
       c = *nibble_ptr++;
 
       c = *nibble_ptr++;
 
-      d = (c & (DST | SRC_IN_DST)) != 0;
+      d = (c & OP3) == OP3 ? 2 : (c & DST) == DST ? 1 : 0;
 
       if (c < 16)
 
       if (c < 16)
-       {
-         nib = c;
-       }
+       nib = c;
       else
        {
       else
        {
-         if (c & (REG | IND | INC | DEC))
+         int c2 = c & MODE;
+
+         if (c2 == REG || c2 == LOWREG
+             || c2 == IND || c2 == PREINC || c2 == PREDEC
+             || c2 == POSTINC || c2 == POSTDEC)
            {
              nib = operand[d].reg;
            {
              nib = operand[d].reg;
+             if (c2 == LOWREG)
+               nib &= 7;
            }
            }
+
+         else if (c & CTRL)    /* Control reg operand.  */
+           nib = operand[d].reg;
+
          else if ((c & DISPREG) == (DISPREG))
            {
          else if ((c & DISPREG) == (DISPREG))
            {
-             nib = dispreg;
+             nib = operand[d].reg;
            }
            }
-         else if (c & ABS)
+         else if (c2 == ABS)
            {
              operand[d].mode = c;
            {
              operand[d].mode = c;
-             absat = nibble_count / 2;
+             op_at[d] = nibble_count;
              nib = 0;
            }
              nib = 0;
            }
-         else if (c & (IMM | PCREL | ABS | ABSJMP | DISP))
+         else if (c2 == IMM || c2 == PCREL || c2 == ABS
+                  || (c & ABSJMP) || c2 == DISP)
            {
              operand[d].mode = c;
            {
              operand[d].mode = c;
-             immat = nibble_count / 2;
-             nib = 0;
-           }
-         else if (c & IGNORE)
-           {
+             op_at[d] = nibble_count;
              nib = 0;
            }
              nib = 0;
            }
-         else if (c & DBIT)
+         else if ((c & IGNORE) || (c & DATA))
+           nib = 0;
+
+         else if (c2 == DBIT)
            {
              switch (operand[0].exp.X_add_number)
                {
            {
              switch (operand[0].exp.X_add_number)
                {
@@ -990,7 +1544,7 @@ build_bytes (this_try, operand)
                  as_bad (_("Need #1 or #2 here"));
                }
            }
                  as_bad (_("Need #1 or #2 here"));
                }
            }
-         else if (c & KBIT)
+         else if (c2 == KBIT)
            {
              switch (operand[0].exp.X_add_number)
                {
            {
              switch (operand[0].exp.X_add_number)
                {
@@ -1015,18 +1569,28 @@ build_bytes (this_try, operand)
            }
 
          if (c & MEMRELAX)
            }
 
          if (c & MEMRELAX)
-           {
-             operand[d].mode |= MEMRELAX;
-           }
+           operand[d].mode |= MEMRELAX;
 
          if (c & B31)
 
          if (c & B31)
-           {
-             nib |= 0x8;
-           }
+           nib |= 0x8;
+
+         if (c & B21)
+           nib |= 0x4;
+
+         if (c & B11)
+           nib |= 0x2;
+
+         if (c & B01)
+           nib |= 0x1;
 
 
-         if (c & MACREG)
+         if (c2 == MACREG)
            {
            {
-             nib = 2 + operand[d].reg;
+             if (operand[0].mode == MACREG)
+               /* stmac has mac[hl] as the first operand.  */
+               nib = 2 + operand[0].reg;
+             else
+               /* ldmac has mac[hl] as the second operand.  */
+               nib = 2 + operand[1].reg;
            }
        }
       nibble_count++;
            }
        }
       nibble_count++;
@@ -1036,71 +1600,110 @@ build_bytes (this_try, operand)
 
   /* Disgusting.  Why, oh why didn't someone ask us for advice
      on the assembler format.  */
 
   /* Disgusting.  Why, oh why didn't someone ask us for advice
      on the assembler format.  */
-  if (strcmp (this_try->name, "stm.l") == 0
-      || strcmp (this_try->name, "ldm.l") == 0)
+  if (OP_KIND (this_try->opcode->how) == O_LDM)
     {
     {
-      int high, low;
-      high = (operand[this_try->name[0] == 'l' ? 1 : 0].reg >> 8) & 0xf;
-      low = operand[this_try->name[0] == 'l' ? 1 : 0].reg & 0xf;
-
+      high = (operand[1].reg >> 8) & 0xf;
+      low  = (operand[1].reg) & 0xf;
       asnibbles[2] = high - low;
       asnibbles[2] = high - low;
-      asnibbles[7] = (this_try->name[0] == 'l') ? high : low;
+      asnibbles[7] = high;
     }
     }
-
-  for (i = 0; i < this_try->length; i++)
+  else if (OP_KIND (this_try->opcode->how) == O_STM)
     {
     {
-      output[i] = (asnibbles[i * 2] << 4) | asnibbles[i * 2 + 1];
+      high = (operand[0].reg >> 8) & 0xf;
+      low  = (operand[0].reg) & 0xf;
+      asnibbles[2] = high - low;
+      asnibbles[7] = low;
     }
 
     }
 
-  /* Note if this is a movb instruction -- there's a special relaxation
-     which only applies to them.  */
-  if (strcmp (this_try->name, "mov.b") == 0)
+  for (i = 0; i < this_try->length; i++)
+    output[i] = (asnibbles[i * 2] << 4) | asnibbles[i * 2 + 1];
+
+  /* Note if this is a mov.b or a bit manipulation instruction
+     there is a special relaxation which only applies.  */
+  if (   this_try->opcode->how == O (O_MOV,   SB)
+      || this_try->opcode->how == O (O_BCLR,  SB)
+      || this_try->opcode->how == O (O_BAND,  SB)
+      || this_try->opcode->how == O (O_BIAND, SB)
+      || this_try->opcode->how == O (O_BILD,  SB)
+      || this_try->opcode->how == O (O_BIOR,  SB)
+      || this_try->opcode->how == O (O_BIST,  SB)
+      || this_try->opcode->how == O (O_BIXOR, SB)
+      || this_try->opcode->how == O (O_BLD,   SB)
+      || this_try->opcode->how == O (O_BNOT,  SB)
+      || this_try->opcode->how == O (O_BOR,   SB)
+      || this_try->opcode->how == O (O_BSET,  SB)
+      || this_try->opcode->how == O (O_BST,   SB)
+      || this_try->opcode->how == O (O_BTST,  SB)
+      || this_try->opcode->how == O (O_BXOR,  SB))
     movb = 1;
 
   /* Output any fixes.  */
     movb = 1;
 
   /* Output any fixes.  */
-  for (i = 0; i < 2; i++)
+  for (i = 0; i < this_try->noperands; i++)
     {
       int x = operand[i].mode;
     {
       int x = operand[i].mode;
-
-      if (x & (IMM | DISP))
-       {
-         do_a_fix_imm (output - frag_now->fr_literal + immat,
-                       operand + i, x & MEMRELAX != 0);
-       }
-      else if (x & ABS)
+      int x_mode = x & MODE;
+
+      if (x_mode == IMM || x_mode == DISP)
+       do_a_fix_imm (output - frag_now->fr_literal + op_at[i] / 2,
+                     op_at[i] & 1, operand + i, (x & MEMRELAX) != 0,
+                     this_try);
+      else if (x_mode == ABS)
+       do_a_fix_imm (output - frag_now->fr_literal + op_at[i] / 2,
+                     op_at[i] & 1, operand + i,
+                     (x & MEMRELAX) ? movb + 1 : 0,
+                     this_try);
+
+      else if (x_mode == PCREL)
        {
        {
-         do_a_fix_imm (output - frag_now->fr_literal + absat,
-                       operand + i, x & MEMRELAX ? movb + 1 : 0);
-       }
-      else if (x & PCREL)
-       {
-         int size16 = x & L_16;
-         int where = size16 ? 2 : 1;
+         int size16 = (x & SIZE) == L_16;
          int size = size16 ? 2 : 1;
          int type = size16 ? R_PCRWORD : R_PCRBYTE;
          int size = size16 ? 2 : 1;
          int type = size16 ? R_PCRWORD : R_PCRBYTE;
+         fixS *fixP;
 
          check_operand (operand + i, size16 ? 0x7fff : 0x7f, "@");
 
          if (operand[i].exp.X_add_number & 1)
 
          check_operand (operand + i, size16 ? 0x7fff : 0x7f, "@");
 
          if (operand[i].exp.X_add_number & 1)
+           as_warn (_("branch operand has odd offset (%lx)\n"),
+                    (unsigned long) operand->exp.X_add_number);
+         if (size16)
            {
            {
-             as_warn (_("branch operand has odd offset (%lx)\n"),
-                      (unsigned long) operand->exp.X_add_number);
+             operand[i].exp.X_add_number =
+               ((operand[i].exp.X_add_number & 0xffff) ^ 0x8000) - 0x8000;
+           }
+         else
+           {
+             operand[i].exp.X_add_number =
+               ((operand[i].exp.X_add_number & 0xff) ^ 0x80) - 0x80;
            }
 
            }
 
-         operand[i].exp.X_add_number -= 1;
-         operand[i].exp.X_add_number =
-           ((operand[i].exp.X_add_number & 0xff) ^ 0x80) - 0x80;
-
+         /* For BRA/S.  */
+         if (! size16)
+           operand[i].exp.X_add_number |= output[op_at[i] / 2];
+
+         fixP = fix_new_exp (frag_now,
+                             output - frag_now->fr_literal + op_at[i] / 2,
+                             size,
+                             &operand[i].exp,
+                             1,
+                             type);
+         fixP->fx_signed = 1;
+       }
+      else if (x_mode == MEMIND)
+       {
+         check_operand (operand + i, 0xff, "@@");
          fix_new_exp (frag_now,
          fix_new_exp (frag_now,
-                      output - frag_now->fr_literal + where,
-                      size,
-                      &operand[i].exp,
+                      output - frag_now->fr_literal + 1,
                       1,
                       1,
-                      type);
+                      &operand[i].exp,
+                      0,
+                      R_MEM_INDIRECT);
        }
        }
-      else if (x & MEMIND)
+      else if (x_mode == VECIND)
        {
        {
-         check_operand (operand + i, 0xff, "@@");
+         check_operand (operand + i, 0x7f, "@@");
+         /* FIXME: approximating the effect of "B31" here...
+            This is very hackish, and ought to be done a better way.  */
+         operand[i].exp.X_add_number |= 0x80;
          fix_new_exp (frag_now,
                       output - frag_now->fr_literal + 1,
                       1,
          fix_new_exp (frag_now,
                       output - frag_now->fr_literal + 1,
                       1,
@@ -1110,45 +1713,62 @@ build_bytes (this_try, operand)
        }
       else if (x & ABSJMP)
        {
        }
       else if (x & ABSJMP)
        {
-         /* This jmp may be a jump or a branch.  */
+         int where = 0;
+         bfd_reloc_code_real_type reloc_type = R_JMPL1;
 
 
-         check_operand (operand + i, Hmode ? 0xffffff : 0xffff, "@");
-         if (operand[i].exp.X_add_number & 1)
+         /* To be compatible with the proposed H8 ELF format, we
+            want the relocation's offset to point to the first byte
+            that will be modified, not to the start of the instruction.  */
+
+         if ((operand->mode & SIZE) == L_32)
            {
            {
-             as_warn (_("branch operand has odd offset (%lx)\n"),
-                      (unsigned long) operand->exp.X_add_number);
+             where = 2;
+             reloc_type = R_RELLONG;
            }
            }
+         else
+           where = 1;
+
+         /* This jmp may be a jump or a branch.  */
+
+         check_operand (operand + i,
+                        SXmode ? 0xffffffff : Hmode ? 0xffffff : 0xffff,
+                        "@");
+
+         if (operand[i].exp.X_add_number & 1)
+           as_warn (_("branch operand has odd offset (%lx)\n"),
+                    (unsigned long) operand->exp.X_add_number);
+
          if (!Hmode)
            operand[i].exp.X_add_number =
              ((operand[i].exp.X_add_number & 0xffff) ^ 0x8000) - 0x8000;
          fix_new_exp (frag_now,
          if (!Hmode)
            operand[i].exp.X_add_number =
              ((operand[i].exp.X_add_number & 0xffff) ^ 0x8000) - 0x8000;
          fix_new_exp (frag_now,
-                      output - frag_now->fr_literal,
+                      output - frag_now->fr_literal + where,
                       4,
                       &operand[i].exp,
                       0,
                       4,
                       &operand[i].exp,
                       0,
-                      R_JMPL1);
+                      reloc_type);
        }
     }
 }
 
 /* Try to give an intelligent error message for common and simple to
    detect errors.  */
        }
     }
 }
 
 /* Try to give an intelligent error message for common and simple to
    detect errors.  */
+
 static void
 static void
-clever_message (opcode, operand)
-     struct h8_opcode *opcode;
-     struct h8_op *operand;
+clever_message (const struct h8_instruction *instruction,
+               struct h8_op *operand)
 {
   /* Find out if there was more than one possible opcode.  */
 
 {
   /* Find out if there was more than one possible opcode.  */
 
-  if ((opcode + 1)->idx != opcode->idx)
+  if ((instruction + 1)->idx != instruction->idx)
     {
     {
-      unsigned int argn;
+      int argn;
 
       /* Only one opcode of this flavour, try to guess which operand
          didn't match.  */
 
       /* Only one opcode of this flavour, try to guess which operand
          didn't match.  */
-      for (argn = 0; argn < opcode->noperands; argn++)
+      for (argn = 0; argn < instruction->noperands; argn++)
        {
        {
-         switch (opcode->args.nib[argn])
+         switch (instruction->opcode->args.nib[argn])
            {
            case RD16:
              if (operand[argn].mode != RD16)
            {
            case RD16:
              if (operand[argn].mode != RD16)
@@ -1196,22 +1816,94 @@ clever_message (opcode, operand)
   as_bad (_("invalid operands"));
 }
 
   as_bad (_("invalid operands"));
 }
 
+
+/* If OPERAND is part of an address, adjust its size and value given
+   that it addresses SIZE bytes.
+
+   This function decides how big non-immediate constants are when no
+   size was explicitly given.  It also scales down the assembly-level
+   displacement in an @(d:2,ERn) operand.  */
+
+static void
+fix_operand_size (struct h8_op *operand, int size)
+{
+  if (SXmode && (operand->mode & MODE) == DISP)
+    {
+      /* If the user didn't specify an operand width, see if we
+        can use @(d:2,ERn).  */
+      if ((operand->mode & SIZE) == 0
+         && operand->exp.X_add_symbol == 0
+         && operand->exp.X_op_symbol == 0
+         && (operand->exp.X_add_number == size
+             || operand->exp.X_add_number == size * 2
+             || operand->exp.X_add_number == size * 3))
+       operand->mode |= L_2;
+
+      /* Scale down the displacement in an @(d:2,ERn) operand.
+        X_add_number then contains the desired field value.  */
+      if ((operand->mode & SIZE) == L_2)
+       {
+         if (operand->exp.X_add_number % size != 0)
+           as_warn (_("operand/size mis-match"));
+         operand->exp.X_add_number /= size;
+       }
+    }
+
+  if ((operand->mode & SIZE) == 0)
+    switch (operand->mode & MODE)
+      {
+      case DISP:
+      case INDEXB:
+      case INDEXW:
+      case INDEXL:
+      case ABS:
+       /* Pick a 24-bit address unless we know that a 16-bit address
+          is safe.  get_specific() will relax L_24 into L_32 where
+          necessary.  */
+       if (Hmode
+           && !Nmode
+           && ((((addressT) operand->exp.X_add_number + 0x8000)
+                & 0xffffffff) > 0xffff
+               || operand->exp.X_add_symbol != 0
+               || operand->exp.X_op_symbol != 0))
+         operand->mode |= L_24;
+       else
+         operand->mode |= L_16;
+       break;
+
+      case PCREL:
+       if ((((addressT) operand->exp.X_add_number + 0x80)
+            & 0xffffffff) <= 0xff)
+         {
+           if (operand->exp.X_add_symbol != NULL)
+             operand->mode |= bsize;
+           else
+             operand->mode |= L_8;
+         }
+       else
+         operand->mode |= L_16;
+       break;
+      }
+}
+
+
 /* 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.  */
 /* 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.  */
+
 void
 void
-md_assemble (str)
-     char *str;
+md_assemble (char *str)
 {
   char *op_start;
   char *op_end;
 {
   char *op_start;
   char *op_end;
-  struct h8_op operand[2];
-  struct h8_opcode *opcode;
-  struct h8_opcode *prev_opcode;
+  struct h8_op operand[3];
+  const struct h8_instruction *instruction;
+  const struct h8_instruction *prev_instruction;
 
   char *dot = 0;
 
   char *dot = 0;
+  char *slash = 0;
   char c;
   char c;
-  int size;
+  int size, i;
 
   /* Drop leading whitespace.  */
   while (*str == ' ')
 
   /* Drop leading whitespace.  */
   while (*str == ' ')
@@ -1229,6 +1921,8 @@ md_assemble (str)
          op_end += 2;
          break;
        }
          op_end += 2;
          break;
        }
+      else if (*op_end == '/' && ! slash)
+       slash = op_end;
     }
 
   if (op_end == op_start)
     }
 
   if (op_end == op_start)
@@ -1239,10 +1933,16 @@ md_assemble (str)
 
   *op_end = 0;
 
 
   *op_end = 0;
 
-  opcode = (struct h8_opcode *) hash_find (opcode_hash_control,
-                                          op_start);
+  /* The assembler stops scanning the opcode at slashes, so it fails
+     to make characters following them lower case.  Fix them.  */
+  if (slash)
+    while (*++slash)
+      *slash = TOLOWER (*slash);
+
+  instruction = (const struct h8_instruction *)
+    hash_find (opcode_hash_control, op_start);
 
 
-  if (opcode == NULL)
+  if (instruction == NULL)
     {
       as_bad (_("unknown opcode"));
       return;
     {
       as_bad (_("unknown opcode"));
       return;
@@ -1251,14 +1951,48 @@ md_assemble (str)
   /* We used to set input_line_pointer to the result of get_operands,
      but that is wrong.  Our caller assumes we don't change it.  */
 
   /* We used to set input_line_pointer to the result of get_operands,
      but that is wrong.  Our caller assumes we don't change it.  */
 
-  (void) get_operands (opcode->noperands, op_end, operand);
+  operand[0].mode = 0;
+  operand[1].mode = 0;
+  operand[2].mode = 0;
+
+  if (OP_KIND (instruction->opcode->how) == O_MOVAB
+      || OP_KIND (instruction->opcode->how) == O_MOVAW
+      || OP_KIND (instruction->opcode->how) == O_MOVAL)
+    get_mova_operands (op_end, operand);
+  else if (OP_KIND (instruction->opcode->how) == O_RTEL
+          || OP_KIND (instruction->opcode->how) == O_RTSL)
+    get_rtsl_operands (op_end, operand);
+  else
+    get_operands (instruction->noperands, op_end, operand);
+
   *op_end = c;
   *op_end = c;
-  prev_opcode = opcode;
+  prev_instruction = instruction;
+
+  /* Now we have operands from instruction.
+     Let's check them out for ldm and stm.  */
+  if (OP_KIND (instruction->opcode->how) == O_LDM)
+    {
+      /* The first operand must be @er7+, and the
+        second operand must be a register pair.  */
+      if ((operand[0].mode != RSINC)
+           || (operand[0].reg != 7)
+           || ((operand[1].reg & 0x80000000) == 0))
+       as_bad (_("invalid operand in ldm"));
+    }
+  else if (OP_KIND (instruction->opcode->how) == O_STM)
+    {
+      /* The first operand must be a register pair,
+        and the second operand must be @-er7.  */
+      if (((operand[0].reg & 0x80000000) == 0)
+            || (operand[1].mode != RDDEC)
+            || (operand[1].reg != 7))
+       as_bad (_("invalid operand in stm"));
+    }
 
   size = SN;
   if (dot)
     {
 
   size = SN;
   if (dot)
     {
-      switch (*dot)
+      switch (TOLOWER (*dot))
        {
        case 'b':
          size = SB;
        {
        case 'b':
          size = SB;
@@ -1273,167 +2007,233 @@ md_assemble (str)
          break;
        }
     }
          break;
        }
     }
-  opcode = get_specific (opcode, operand, size);
+  if (OP_KIND (instruction->opcode->how) == O_MOVAB ||
+      OP_KIND (instruction->opcode->how) == O_MOVAW ||
+      OP_KIND (instruction->opcode->how) == O_MOVAL)
+    {
+      switch (operand[0].mode & MODE)
+       {
+       case INDEXB:
+       default:
+         fix_operand_size (&operand[1], 1);
+         break;
+       case INDEXW:
+         fix_operand_size (&operand[1], 2);
+         break;
+       case INDEXL:
+         fix_operand_size (&operand[1], 4);
+         break;
+       }
+    }
+  else
+    {
+      for (i = 0; i < 3 && operand[i].mode != 0; i++)
+       switch (size)
+         {
+         case SN:
+         case SB:
+         default:
+           fix_operand_size (&operand[i], 1);
+           break;
+         case SW:
+           fix_operand_size (&operand[i], 2);
+           break;
+         case SL:
+           fix_operand_size (&operand[i], 4);
+           break;
+         }
+    }
 
 
-  if (opcode == 0)
+  instruction = get_specific (instruction, operand, size);
+
+  if (instruction == 0)
     {
       /* Couldn't find an opcode which matched the operands.  */
       char *where = frag_more (2);
 
       where[0] = 0x0;
       where[1] = 0x0;
     {
       /* 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);
+      clever_message (prev_instruction, operand);
 
       return;
     }
 
       return;
     }
-  if (opcode->size && dot)
-    {
-      if (opcode->size != *dot)
-       {
-         as_warn (_("mismatch between opcode size and operand size"));
-       }
-    }
 
 
-  build_bytes (opcode, operand);
-}
+  build_bytes (instruction, operand);
 
 
-void
-tc_crawl_symbol_chain (headers)
-     object_headers *headers ATTRIBUTE_UNUSED;
-{
-  printf (_("call to tc_crawl_symbol_chain \n"));
+  dwarf2_emit_insn (instruction->length);
 }
 
 symbolS *
 }
 
 symbolS *
-md_undefined_symbol (name)
-     char *name ATTRIBUTE_UNUSED;
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
 {
   return 0;
 }
 
 {
   return 0;
 }
 
-void
-tc_headers_hook (headers)
-     object_headers *headers ATTRIBUTE_UNUSED;
+/* Various routines to kill one day.  */
+
+const char *
+md_atof (int type, char *litP, int *sizeP)
 {
 {
-  printf (_("call to tc_headers_hook \n"));
+  return ieee_md_atof (type, litP, sizeP, TRUE);
 }
 }
+\f
+#define OPTION_H_TICK_HEX      (OPTION_MD_BASE)
+#define OPTION_MACH            (OPTION_MD_BASE+1)
 
 
-/* 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;
+const char *md_shortopts = "";
+struct option md_longopts[] =
 {
 {
-  int prec;
-  LITTLENUM_TYPE words[MAX_LITTLENUMS];
-  LITTLENUM_TYPE *wordP;
-  char *t;
-  char *atof_ieee ();
+  { "h-tick-hex", no_argument,       NULL, OPTION_H_TICK_HEX  },
+  { "mach", required_argument, NULL, OPTION_MACH },
+  {NULL, no_argument, NULL, 0}
+};
 
 
-  switch (type)
-    {
-    case 'f':
-    case 'F':
-    case 's':
-    case 'S':
-      prec = 2;
-      break;
+size_t md_longopts_size = sizeof (md_longopts);
 
 
-    case 'd':
-    case 'D':
-    case 'r':
-    case 'R':
-      prec = 4;
-      break;
+struct mach_func
+{
+  const char *name;
+  void (*func) (void);
+};
 
 
-    case 'x':
-    case 'X':
-      prec = 6;
-      break;
+static void
+mach_h8300h (void)
+{
+  Hmode = 1;
+  Smode = 0;
+  Nmode = 0;
+  SXmode = 0;
+  default_mach = bfd_mach_h8300h;
+}
 
 
-    case 'p':
-    case 'P':
-      prec = 6;
-      break;
+static void
+mach_h8300hn (void)
+{
+  Hmode = 1;
+  Smode = 0;
+  Nmode = 1;
+  SXmode = 0;
+  default_mach = bfd_mach_h8300hn;
+}
 
 
-    default:
-      *sizeP = 0;
-      return _("Bad call to MD_ATOF()");
-    }
-  t = atof_ieee (input_line_pointer, type, words);
-  if (t)
-    input_line_pointer = t;
+static void
+mach_h8300s (void)
+{
+  Hmode = 1;
+  Smode = 1;
+  Nmode = 0;
+  SXmode = 0;
+  default_mach = bfd_mach_h8300s;
+}
 
 
-  *sizeP = prec * sizeof (LITTLENUM_TYPE);
-  for (wordP = words; prec--;)
-    {
-      md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE));
-      litP += sizeof (LITTLENUM_TYPE);
-    }
-  return 0;
+static void
+mach_h8300sn (void)
+{
+  Hmode = 1;
+  Smode = 1;
+  Nmode = 1;
+  SXmode = 0;
+  default_mach = bfd_mach_h8300sn;
 }
 }
-\f
-CONST char *md_shortopts = "";
-struct option md_longopts[] = {
-  {NULL, no_argument, NULL, 0}
-};
 
 
-size_t md_longopts_size = sizeof (md_longopts);
+static void
+mach_h8300sx (void)
+{
+  Hmode = 1;
+  Smode = 1;
+  Nmode = 0;
+  SXmode = 1;
+  default_mach = bfd_mach_h8300sx;
+}
+
+static void
+mach_h8300sxn (void)
+{
+  Hmode = 1;
+  Smode = 1;
+  Nmode = 1;
+  SXmode = 1;
+  default_mach = bfd_mach_h8300sxn;
+}
+
+const struct mach_func mach_table[] =
+{
+  {"h8300h",  mach_h8300h},
+  {"h8300hn", mach_h8300hn},
+  {"h8300s",  mach_h8300s},
+  {"h8300sn", mach_h8300sn},
+  {"h8300sx", mach_h8300sx},
+  {"h8300sxn", mach_h8300sxn}
+};
 
 int
 
 int
-md_parse_option (c, arg)
-     int c ATTRIBUTE_UNUSED;
-     char *arg ATTRIBUTE_UNUSED;
+md_parse_option (int c ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED)
 {
 {
-  return 0;
+  unsigned int i;
+  switch (c)
+    {
+    case OPTION_H_TICK_HEX:
+      enable_h_tick_hex = 1;
+      break;
+    case OPTION_MACH:
+      for (i = 0; i < sizeof(mach_table) / sizeof(struct mach_func); i++)
+       {
+         if (strcasecmp (arg, mach_table[i].name) == 0)
+           {
+             mach_table[i].func();
+             break;
+           }
+       }
+      if (i >= sizeof(mach_table) / sizeof(struct mach_func))
+       as_bad (_("Invalid argument to --mach option: %s"), arg);
+      break;
+    default:
+      return 0;
+    }
+  return 1;
 }
 
 void
 }
 
 void
-md_show_usage (stream)
-     FILE *stream ATTRIBUTE_UNUSED;
+md_show_usage (FILE *stream)
 {
 {
+  fprintf (stream, _(" H8300-specific assembler options:\n"));
+  fprintf (stream, _("\
+  -mach=<name>             Set the H8300 machine type to one of:\n\
+                           h8300h, h8300hn, h8300s, h8300sn, h8300sx, h8300sxn\n"));
+  fprintf (stream, _("\
+  -h-tick-hex              Support H'00 style hex constants\n"));
 }
 \f
 }
 \f
+void tc_aout_fix_to_chars (void);
+
 void
 void
-tc_aout_fix_to_chars ()
+tc_aout_fix_to_chars (void)
 {
   printf (_("call to tc_aout_fix_to_chars \n"));
   abort ();
 }
 
 void
 {
   printf (_("call to tc_aout_fix_to_chars \n"));
   abort ();
 }
 
 void
-md_convert_frag (headers, seg, fragP)
-     object_headers *headers ATTRIBUTE_UNUSED;
-     segT seg ATTRIBUTE_UNUSED;
-     fragS *fragP ATTRIBUTE_UNUSED;
+md_convert_frag (bfd *headers ATTRIBUTE_UNUSED,
+                segT seg ATTRIBUTE_UNUSED,
+                fragS *fragP ATTRIBUTE_UNUSED)
 {
   printf (_("call to md_convert_frag \n"));
   abort ();
 }
 
 valueT
 {
   printf (_("call to md_convert_frag \n"));
   abort ();
 }
 
 valueT
-md_section_align (seg, size)
-     segT seg;
-     valueT size;
+md_section_align (segT segment, valueT size)
 {
 {
-  return ((size + (1 << section_alignment[(int) seg]) - 1)
-         & (-1 << section_alignment[(int) seg]));
+  int align = bfd_get_section_alignment (stdoutput, segment);
+  return ((size + (1 << align) - 1) & (-1U << align));
 }
 
 void
 }
 
 void
-md_apply_fix (fixP, val)
-     fixS *fixP;
-     long val;
+md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 {
   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
 {
   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+  long val = *valP;
 
   switch (fixP->fx_size)
     {
 
   switch (fixP->fx_size)
     {
@@ -1450,96 +2250,82 @@ md_apply_fix (fixP, val)
       *buf++ = (val >> 8);
       *buf++ = val;
       break;
       *buf++ = (val >> 8);
       *buf++ = val;
       break;
+    case 8:
+      /* This can arise when the .quad or .8byte pseudo-ops are used.
+        Returning here (without setting fx_done) will cause the code
+        to attempt to generate a reloc which will then fail with the
+        slightly more helpful error message: "Cannot represent
+        relocation type BFD_RELOC_64".  */
+      return;
     default:
       abort ();
     }
     default:
       abort ();
     }
+
+  if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
+    fixP->fx_done = 1;
 }
 
 int
 }
 
 int
-md_estimate_size_before_relax (fragP, segment_type)
-     register fragS *fragP ATTRIBUTE_UNUSED;
-     register segT segment_type ATTRIBUTE_UNUSED;
+md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED,
+                              segT segment_type ATTRIBUTE_UNUSED)
 {
 {
-  printf (_("call tomd_estimate_size_before_relax \n"));
+  printf (_("call to md_estimate_size_before_relax \n"));
   abort ();
 }
 
 /* Put number into target byte order.  */
 void
   abort ();
 }
 
 /* Put number into target byte order.  */
 void
-md_number_to_chars (ptr, use, nbytes)
-     char *ptr;
-     valueT use;
-     int nbytes;
+md_number_to_chars (char *ptr, valueT use, int nbytes)
 {
   number_to_chars_bigendian (ptr, use, nbytes);
 }
 
 long
 {
   number_to_chars_bigendian (ptr, use, nbytes);
 }
 
 long
-md_pcrel_from (fixP)
-     fixS *fixP ATTRIBUTE_UNUSED;
+md_pcrel_from (fixS *fixp)
 {
 {
-  abort ();
+  as_bad_where (fixp->fx_file, fixp->fx_line,
+               _("Unexpected reference to a symbol in a non-code section"));
+  return 0;
 }
 
 }
 
-void
-tc_reloc_mangle (fix_ptr, intr, base)
-     fixS *fix_ptr;
-     struct internal_reloc *intr;
-     bfd_vma base;
-
+arelent *
+tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
 {
 {
-  symbolS *symbol_ptr;
+  arelent *rel;
+  bfd_reloc_code_real_type r_type;
 
 
-  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 == TC_CONS_RELOC)
+  if (fixp->fx_addsy && fixp->fx_subsy)
     {
     {
-      /* cons likes to create reloc32's whatever the size of the reloc..
-       */
-      switch (fix_ptr->fx_size)
+      if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy))
+         || S_GET_SEGMENT (fixp->fx_addsy) == undefined_section)
        {
        {
-       case 4:
-         intr->r_type = R_RELLONG;
-         break;
-       case 2:
-         intr->r_type = R_RELWORD;
-         break;
-       case 1:
-         intr->r_type = R_RELBYTE;
-         break;
-       default:
-         abort ();
+         as_bad_where (fixp->fx_file, fixp->fx_line,
+                       _("Difference of symbols in different sections is not supported"));
+         return NULL;
        }
     }
        }
     }
-  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)
+  rel = XNEW (arelent);
+  rel->sym_ptr_ptr = XNEW (asymbol *);
+  *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+  rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
+  rel->addend = fixp->fx_offset;
+
+  r_type = fixp->fx_r_type;
+
+#define DEBUG 0
+#if DEBUG
+  fprintf (stderr, "%s\n", bfd_get_reloc_code_name (r_type));
+  fflush (stderr);
+#endif
+  rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
+  if (rel->howto == NULL)
     {
     {
-      if (symbol_ptr->sy_number != -1)
-       intr->r_symndx = symbol_ptr->sy_number;
-      else
-       {
-         symbolS *segsym;
-
-         /* This case arises when a reference is made to `.'.  */
-         segsym = seg_info (S_GET_SEGMENT (symbol_ptr))->dot;
-         if (segsym == NULL)
-           intr->r_symndx = -1;
-         else
-           {
-             intr->r_symndx = segsym->sy_number;
-             intr->r_offset += S_GET_VALUE (symbol_ptr);
-           }
-       }
+      as_bad_where (fixp->fx_file, fixp->fx_line,
+                   _("Cannot represent relocation type %s"),
+                   bfd_get_reloc_code_name (r_type));
+      return NULL;
     }
     }
-  else
-    intr->r_symndx = -1;
+
+  return rel;
 }
 }
This page took 0.100549 seconds and 4 git commands to generate.