2003-06-05 Michael Snyder <msnyder@redhat.com>
authorMichael Snyder <msnyder@vmware.com>
Thu, 5 Jun 2003 18:53:35 +0000 (18:53 +0000)
committerMichael Snyder <msnyder@vmware.com>
Thu, 5 Jun 2003 18:53:35 +0000 (18:53 +0000)
* config/tc-h8sx.c (get_specific): Distinguish h8h from h8s ops.
(build_bytes): Ditto.

2003-06-05  Richard Sandiford  <rsandifo@redhat.com>

* config/tc-h8sx.c (DMODE): Remove.
(colonmod24): Don't choose a default if the operand is a 16-bit
constant integer.
(fix_operand_size): New function.
(md_assemble): Use it to choose between @(d:2, ERn) and @(d:16,ERn).
Adjust @(d:2,ERn) operands before choosing the specific opcodes.

gas/ChangeLog
gas/config/tc-h8300.c

index 4807f18..0f3833e 100644 (file)
@@ -1,3 +1,17 @@
+2003-06-05  Michael Snyder  <msnyder@redhat.com>
+
+       * config/tc-h8sx.c (get_specific): Distinguish h8h from h8s ops.
+       (build_bytes): Ditto.
+
+2003-06-05  Richard Sandiford  <rsandifo@redhat.com>
+
+       * config/tc-h8sx.c (DMODE): Remove.
+       (colonmod24): Don't choose a default if the operand is a 16-bit
+       constant integer.
+       (fix_operand_size): New function.
+       (md_assemble): Use it to choose between @(d:2, ERn) and @(d:16,ERn).
+       Adjust @(d:2,ERn) operands before choosing the specific opcodes.
+
 2003-06-05  Michal Ludvig  <mludvig@suse.cz>
 
        * dw2gencfi.c (cfi_add_CFA_insn, cfi_add_CFA_insn_reg)
index dccd9f8..794a509 100644 (file)
@@ -58,7 +58,6 @@ int Nmode;
 int SXmode;
 
 #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.  */
@@ -320,6 +319,7 @@ struct h8_op
 };
 
 static void clever_message PARAMS ((const struct h8_instruction *, struct h8_op *));
+static void fix_operand_size PARAMS ((struct h8_op *, int));
 static void build_bytes    PARAMS ((const struct h8_instruction *, struct h8_op *));
 static void do_a_fix_imm   PARAMS ((int, int, struct h8_op *, int));
 static void check_operand  PARAMS ((struct h8_op *, unsigned int, char *));
@@ -536,7 +536,8 @@ colonmod24 (op, src)
 
   if (!mode)
     {
-      /* Choose a default mode.  */
+      /* If the operand is a 16-bit constant integer, leave fix_operand_size
+        to calculate its size.  Otherwise choose a default here.  */
       if (op->exp.X_add_number < -32768
          || op->exp.X_add_number > 32767)
        {
@@ -548,8 +549,6 @@ colonmod24 (op, src)
       else if (op->exp.X_add_symbol
               || op->exp.X_op_symbol)
        mode = DSYMMODE;
-      else
-       mode = DMODE;
     }
 
   op->mode |= mode;
@@ -1316,6 +1315,7 @@ get_specific (instruction, operands, size)
       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))
@@ -1524,9 +1524,20 @@ build_bytes (this_try, operand)
   char *p = asnibbles;
   int high, low;
 
-  if (!(this_try->opcode->available == AV_H8 || Hmode))
+  if (!Hmode && this_try->opcode->available != AV_H8)
     as_warn (_("Opcode `%s' with these operand types not available in H8/300 mode"),
             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)
     {
@@ -1857,6 +1868,56 @@ clever_message (instruction, operand)
   as_bad (_("invalid operands"));
 }
 
+
+/* Adjust OPERAND's value and size given that it is accessing a field
+   of SIZE bytes.
+
+   This function handles the choice between @(d:2,ERn) and @(d:16,ERn)
+   when no size is explicitly given.  It also scales down the assembly-level
+   displacement in an @(d:2,ERn) operand.  */
+
+static void
+fix_operand_size (operand, size)
+     struct h8_op *operand;
+     int size;
+{
+  if ((operand->mode & MODE) == DISP)
+    {
+      /* If the user didn't specify an operand width, see if we
+        can use @(d:2,ERn).  */
+      if (SXmode
+         && (operand->mode & SIZE) == 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 the operand needs a size but doesn't have one yet, it must be
+     a 16-bit integer (see colonmod24).  */
+  if ((operand->mode & SIZE) == 0)
+    switch (operand->mode & MODE)
+      {
+      case DISP:
+      case INDEXB:
+      case INDEXW:
+      case INDEXL:
+      case ABS:
+       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.  */
@@ -1948,69 +2009,57 @@ md_assemble (str)
          break;
        }
     }
-  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;
-      clever_message (prev_instruction, operand);
-
-      return;
-    }
-
-  /* This is the earliest point at which we can do this:
-     any DISP2 operands need to be fixed-up according to 
-     the size of the operation.  */
-  /* MOVA is a whole different set of rules...  */
   if (OP_KIND (instruction->opcode->how) == O_MOVAB ||
       OP_KIND (instruction->opcode->how) == O_MOVAW ||
       OP_KIND (instruction->opcode->how) == O_MOVAL)
     {
-      if ((operand[1].mode & MODE) == DISP &&
-         (operand[1].mode & SIZE) == L_2)
-       switch (operand[0].mode & MODE) {
+      switch (operand[0].mode & MODE)
+       {
        case INDEXB:
        default:
+         fix_operand_size (&operand[1], 1);
          break;
        case INDEXW:
-         if (operand[1].exp.X_add_number % 2)
-           as_warn (_("operand/size mis-match"));
-         operand[1].exp.X_add_number /= 2;
+         fix_operand_size (&operand[1], 2);
          break;
        case INDEXL:
-         if (operand[1].exp.X_add_number % 4)
-           as_warn (_("operand/size mis-match"));
-         operand[1].exp.X_add_number /= 4;
+         fix_operand_size (&operand[1], 4);
          break;
        }
     }
   else
     {
-      for (i = 0; i < instruction->noperands; i++)
-       if ((operand[i].mode & MODE) == DISP &&
-           (operand[i].mode & SIZE) == L_2)
-         switch (size) {
+      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:
-           if (operand[i].exp.X_add_number % 2)
-             as_warn (_("operand/size mis-match"));
-           operand[i].exp.X_add_number /= 2;
+           fix_operand_size (&operand[i], 2);
            break;
          case SL:
-           if (operand[i].exp.X_add_number % 4)
-             as_warn (_("operand/size mis-match"));
-           operand[i].exp.X_add_number /= 4;
+           fix_operand_size (&operand[i], 4);
            break;
          }
     }
 
+  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;
+      clever_message (prev_instruction, operand);
+
+      return;
+    }
+
   build_bytes (instruction, operand);
 
 #ifdef BFD_ASSEMBLER