2000-05-25 Alexandre Oliva <aoliva@cygnus.com>
authorAlexandre Oliva <aoliva@redhat.com>
Thu, 10 Jul 2003 02:50:00 +0000 (02:50 +0000)
committerAlexandre Oliva <aoliva@redhat.com>
Thu, 10 Jul 2003 02:50:00 +0000 (02:50 +0000)
* config/tc-mn10300.c (mn10300_insert_operand): Negate negative
accumulator's shift.
2000-05-08  Alexandre Oliva  <aoliva@cygnus.com>
* config/tc-mn10300.c (md_relax_table, md_convert_frag,
md_assemble, md_estimate_size_before_relax): Handle fbCC.
2000-04-20  Alexandre Oliva  <aoliva@cygnus.com>
* config/tc-mn10300.c (HAVE_AM33): Redefine in terms of
HAVE_AM33_2.
2000-04-03  Alexandre Oliva  <aoliva@cygnus.com>
* config/tc-mn10300.c (md_pseudo_table): Use AM33_2 constant.
(HAVE_AM33): Match AM33_2 too.
(HAVE_AM33_2): New macro.
(md_assemble): Use it.  Match 2.0 registers only if HAVE_AM33_2.
2000-04-01  Alexandre Oliva  <aoliva@cygnus.com>
* config/tc-mn10300.c (md_pseudo_table): Added `am33_2'.
(float_registers, double_registers): New variables.
(float_register_name, double_register_name): New functions.
(md_assemble): Recognize FP registers.  Implement FMT_D3.
(mn10300_insert_operand): Support FP registers.

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

index 21167d8..d7ee712 100644 (file)
@@ -1,3 +1,26 @@
+2003-07-09  Alexandre Oliva  <aoliva@redhat.com>
+
+       2000-05-25  Alexandre Oliva  <aoliva@cygnus.com>
+       * config/tc-mn10300.c (mn10300_insert_operand): Negate negative
+       accumulator's shift.
+       2000-05-08  Alexandre Oliva  <aoliva@cygnus.com>
+       * config/tc-mn10300.c (md_relax_table, md_convert_frag,
+       md_assemble, md_estimate_size_before_relax): Handle fbCC.
+       2000-04-20  Alexandre Oliva  <aoliva@cygnus.com>
+       * config/tc-mn10300.c (HAVE_AM33): Redefine in terms of
+       HAVE_AM33_2.
+       2000-04-03  Alexandre Oliva  <aoliva@cygnus.com>
+       * config/tc-mn10300.c (md_pseudo_table): Use AM33_2 constant.
+       (HAVE_AM33): Match AM33_2 too.
+       (HAVE_AM33_2): New macro.
+       (md_assemble): Use it.  Match 2.0 registers only if HAVE_AM33_2.
+       2000-04-01  Alexandre Oliva  <aoliva@cygnus.com>
+       * config/tc-mn10300.c (md_pseudo_table): Added `am33_2'.
+       (float_registers, double_registers): New variables.
+       (float_register_name, double_register_name): New functions.
+       (md_assemble): Recognize FP registers.  Implement FMT_D3.
+       (mn10300_insert_operand): Support FP registers.
+
 2003-07-08  Chris Demetriou  <cgd@broadcom.com>
 
        * config/tc-mips.c (mips_validate_fix): Do not warn about branch
index 5595c76..ff2fffa 100644 (file)
@@ -78,6 +78,11 @@ const relax_typeS md_relax_table[] = {
   {0x7fff, -0x8000, 3, 12},
   {0x7fffffff, -0x80000000, 5, 0},
 
+  /* fbCC relaxing  */
+  {0x7f, -0x80, 3, 14},
+  {0x7fff, -0x8000, 6, 15},
+  {0x7fffffff, -0x80000000, 8, 0},
+
 };
 
 /* Local functions.  */
@@ -127,11 +132,13 @@ const pseudo_typeS md_pseudo_table[] =
 {
   { "am30",    set_arch_mach,          AM30 },
   { "am33",    set_arch_mach,          AM33 },
+  { "am33_2",  (void (*) PARAMS ((int))) set_arch_mach, AM33_2 },
   { "mn10300", set_arch_mach,          MN103 },
   {NULL, 0, 0}
 };
 
-#define HAVE_AM33 (current_machine == AM33)
+#define HAVE_AM33_2 (current_machine == AM33_2)
+#define HAVE_AM33 (current_machine == AM33 || HAVE_AM33_2)
 #define HAVE_AM30 (current_machine == AM30)
 
 /* Opcode hash table.  */
@@ -251,6 +258,69 @@ static const struct reg_name other_registers[] =
 #define OTHER_REG_NAME_CNT                             \
   (sizeof (other_registers) / sizeof (struct reg_name))
 
+static const struct reg_name float_registers[] =
+{
+  { "fs0", 0 },
+  { "fs1", 1 },
+  { "fs10", 10 },
+  { "fs11", 11 },
+  { "fs12", 12 },
+  { "fs13", 13 },
+  { "fs14", 14 },
+  { "fs15", 15 },
+  { "fs16", 16 },
+  { "fs17", 17 },
+  { "fs18", 18 },
+  { "fs19", 19 },
+  { "fs2",   2 },
+  { "fs20", 20 },
+  { "fs21", 21 },
+  { "fs22", 22 },
+  { "fs23", 23 },
+  { "fs24", 24 },
+  { "fs25", 25 },
+  { "fs26", 26 },
+  { "fs27", 27 },
+  { "fs28", 28 },
+  { "fs29", 29 },
+  { "fs3",   3 },
+  { "fs30", 30 },
+  { "fs31", 31 },
+  { "fs4",   4 },
+  { "fs5",   5 },
+  { "fs6",   6 },
+  { "fs7",   7 },
+  { "fs8",   8 },
+  { "fs9",   9 },
+};
+
+#define FLOAT_REG_NAME_CNT \
+  (sizeof (float_registers) / sizeof (struct reg_name))
+
+static const struct reg_name double_registers[] =
+{
+  { "fd0",   0 },
+  { "fd10", 10 },
+  { "fd12", 12 },
+  { "fd14", 14 },
+  { "fd16", 16 },
+  { "fd18", 18 },
+  { "fd2",   2 },
+  { "fd20", 20 },
+  { "fd22", 22 },
+  { "fd24", 24 },
+  { "fd26", 26 },
+  { "fd28", 28 },
+  { "fd30", 30 },
+  { "fd4",   4 },
+  { "fd6",   6 },
+  { "fd8",   8 },
+};
+
+#define DOUBLE_REG_NAME_CNT \
+  (sizeof (double_registers) / sizeof (struct reg_name))
+
+
 /* reg_name_search does a binary search of the given register table
    to see if "name" is a valid regiter name.  Returns the register
    number from the array on success, or -1 on failure.  */
@@ -518,6 +588,101 @@ other_register_name (expressionP)
   return FALSE;
 }
 
+static bfd_boolean double_register_name PARAMS ((expressionS *));
+static bfd_boolean float_register_name  PARAMS ((expressionS *));
+
+/* Summary of float_register_name:
+
+   in: Input_line_pointer points to 1st char of operand.
+
+   out: A expressionS.
+       The operand may have been a register: in this case, X_op == O_register,
+       X_add_number is set to the register number, and truth is returned.
+       Input_line_pointer->(next non-blank) char after operand, or is in
+       its original state.  */
+
+static bfd_boolean
+float_register_name (expressionP)
+     expressionS *expressionP;
+{
+  int reg_number;
+  char *name;
+  char *start;
+  char c;
+
+  /* Find the spelling of the operand.  */
+  start = name = input_line_pointer;
+
+  c = get_symbol_end ();
+  reg_number = reg_name_search (float_registers, FLOAT_REG_NAME_CNT, name);
+
+  /* Put back the delimiting char.  */
+  * input_line_pointer = c;
+
+  /* Look to see if it's in the register table.  */
+  if (reg_number >= 0)
+    {
+      expressionP->X_op = O_register;
+      expressionP->X_add_number = reg_number;
+
+      /* Make the rest nice.  */
+      expressionP->X_add_symbol = NULL;
+      expressionP->X_op_symbol = NULL;
+
+      return TRUE;
+    }
+
+  /* Reset the line as if we had not done anything.  */
+  input_line_pointer = start;
+  return FALSE;
+}
+
+/* Summary of double_register_name:
+
+   in: Input_line_pointer points to 1st char of operand.
+
+   out: A expressionS.
+       The operand may have been a register: in this case, X_op == O_register,
+       X_add_number is set to the register number, and truth is returned.
+       Input_line_pointer->(next non-blank) char after operand, or is in
+       its original state.  */
+
+static bfd_boolean
+double_register_name (expressionP)
+     expressionS *expressionP;
+{
+  int reg_number;
+  char *name;
+  char *start;
+  char c;
+
+  /* Find the spelling of the operand.  */
+  start = name = input_line_pointer;
+
+  c = get_symbol_end ();
+  reg_number = reg_name_search (double_registers, DOUBLE_REG_NAME_CNT, name);
+
+  /* Put back the delimiting char.  */
+  * input_line_pointer = c;
+
+  /* Look to see if it's in the register table.  */
+  if (reg_number >= 0)
+    {
+      expressionP->X_op = O_register;
+      expressionP->X_add_number = reg_number;
+
+      /* Make the rest nice.  */
+      expressionP->X_add_symbol = NULL;
+      expressionP->X_op_symbol = NULL;
+
+      return TRUE;
+    }
+
+  /* Reset the line as if we had not done anything.  */
+  input_line_pointer = start;
+  return FALSE;
+}
+
 void
 md_show_usage (stream)
      FILE *stream;
@@ -865,6 +1030,151 @@ md_convert_frag (abfd, sec, fragP)
       fragP->fr_var = 0;
       fragP->fr_fix += 5;
     }
+  else if (fragP->fr_subtype == 13)
+    {
+      fix_new (fragP, fragP->fr_fix + 2, 1, fragP->fr_symbol,
+              fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 3;
+    }
+  else if (fragP->fr_subtype == 14)
+    {
+      /* Reverse the condition of the first branch.  */
+      int offset = fragP->fr_fix;
+      int opcode = fragP->fr_literal[offset + 1] & 0xff;
+
+      switch (opcode)
+       {
+       case 0xd0:
+         opcode = 0xd1;
+         break;
+       case 0xd1:
+         opcode = 0xd0;
+         break;
+       case 0xd2:
+         opcode = 0xdc;
+         break;
+       case 0xd3:
+         opcode = 0xdb;
+         break;
+       case 0xd4:
+         opcode = 0xda;
+         break;
+       case 0xd5:
+         opcode = 0xd9;
+         break;
+       case 0xd6:
+         opcode = 0xd8;
+         break;
+       case 0xd7:
+         opcode = 0xdd;
+         break;
+       case 0xd8:
+         opcode = 0xd6;
+         break;
+       case 0xd9:
+         opcode = 0xd5;
+         break;
+       case 0xda:
+         opcode = 0xd4;
+         break;
+       case 0xdb:
+         opcode = 0xd3;
+         break;
+       case 0xdc:
+         opcode = 0xd2;
+         break;
+       case 0xdd:
+         opcode = 0xd7;
+         break;
+       default:
+         abort ();
+       }
+      fragP->fr_literal[offset + 1] = opcode;
+
+      /* Create a fixup for the reversed conditional branch.  */
+      sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
+      fix_new (fragP, fragP->fr_fix + 2, 1,
+              symbol_new (buf, sec, 0, fragP->fr_next),
+              fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
+
+      /* Now create the unconditional branch + fixup to the
+        final target.  */
+      fragP->fr_literal[offset + 3] = 0xcc;
+      fix_new (fragP, fragP->fr_fix + 4, 2, fragP->fr_symbol,
+              fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 6;
+    }
+  else if (fragP->fr_subtype == 15)
+    {
+      /* Reverse the condition of the first branch.  */
+      int offset = fragP->fr_fix;
+      int opcode = fragP->fr_literal[offset + 1] & 0xff;
+
+      switch (opcode)
+       {
+       case 0xd0:
+         opcode = 0xd1;
+         break;
+       case 0xd1:
+         opcode = 0xd0;
+         break;
+       case 0xd2:
+         opcode = 0xdc;
+         break;
+       case 0xd3:
+         opcode = 0xdb;
+         break;
+       case 0xd4:
+         opcode = 0xda;
+         break;
+       case 0xd5:
+         opcode = 0xd9;
+         break;
+       case 0xd6:
+         opcode = 0xd8;
+         break;
+       case 0xd7:
+         opcode = 0xdd;
+         break;
+       case 0xd8:
+         opcode = 0xd6;
+         break;
+       case 0xd9:
+         opcode = 0xd5;
+         break;
+       case 0xda:
+         opcode = 0xd4;
+         break;
+       case 0xdb:
+         opcode = 0xd3;
+         break;
+       case 0xdc:
+         opcode = 0xd2;
+         break;
+       case 0xdd:
+         opcode = 0xd7;
+         break;
+       default:
+         abort ();
+       }
+      fragP->fr_literal[offset + 1] = opcode;
+
+      /* Create a fixup for the reversed conditional branch.  */
+      sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
+      fix_new (fragP, fragP->fr_fix + 2, 1,
+              symbol_new (buf, sec, 0, fragP->fr_next),
+              fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
+
+      /* Now create the unconditional branch + fixup to the
+        final target.  */
+      fragP->fr_literal[offset + 3] = 0xdc;
+      fix_new (fragP, fragP->fr_fix + 4, 4, fragP->fr_symbol,
+              fragP->fr_offset + 1, 1, BFD_RELOC_32_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 8;
+    }
   else
     abort ();
 }
@@ -965,6 +1275,7 @@ md_assemble (str)
       /* If the instruction is not available on the current machine
         then it can not possibly match.  */
       if (opcode->machine
+         && !(opcode->machine == AM33_2 && HAVE_AM33_2)
          && !(opcode->machine == AM33 && HAVE_AM33)
          && !(opcode->machine == AM30 && HAVE_AM30))
        goto error;
@@ -1059,6 +1370,39 @@ md_assemble (str)
                  goto error;
                }
            }
+         else if (operand->flags & MN10300_OPERAND_FSREG)
+           {
+             if (!float_register_name (&ex))
+               {
+                 input_line_pointer = hold;
+                 str = hold;
+                 goto error;
+               }
+           }
+         else if (operand->flags & MN10300_OPERAND_FDREG)
+           {
+             if (!double_register_name (&ex))
+               {
+                 input_line_pointer = hold;
+                 str = hold;
+                 goto error;
+               }
+           }
+         else if (operand->flags & MN10300_OPERAND_FPCR)
+           {
+             char *start = input_line_pointer;
+             char c = get_symbol_end ();
+
+             if (strcasecmp (start, "fpcr") != 0)
+               {
+                 *input_line_pointer = c;
+                 input_line_pointer = hold;
+                 str = hold;
+                 goto error;
+               }
+             *input_line_pointer = c;
+             goto keep_going;
+           }
          else if (operand->flags & MN10300_OPERAND_USP)
            {
              char *start = input_line_pointer;
@@ -1298,6 +1642,18 @@ md_assemble (str)
              str = hold;
              goto error;
            }
+         else if (HAVE_AM33_2 && float_register_name (&ex))
+           {
+             input_line_pointer = hold;
+             str = hold;
+             goto error;
+           }
+         else if (HAVE_AM33_2 && double_register_name (&ex))
+           {
+             input_line_pointer = hold;
+             str = hold;
+             goto error;
+           }
          else if (*str == ')' || *str == '(')
            {
              input_line_pointer = hold;
@@ -1324,6 +1680,8 @@ md_assemble (str)
                mask = MN10300_OPERAND_DREG | MN10300_OPERAND_AREG;
                if (HAVE_AM33)
                  mask |= MN10300_OPERAND_RREG | MN10300_OPERAND_XRREG;
+               if (HAVE_AM33_2)
+                 mask |= MN10300_OPERAND_FSREG | MN10300_OPERAND_FDREG;
                if ((operand->flags & mask) == 0)
                  {
                    input_line_pointer = hold;
@@ -1491,6 +1849,9 @@ keep_going:
   if (opcode->format == FMT_D2)
     size = 4;
 
+  if (opcode->format == FMT_D3)
+    size = 5;
+
   if (opcode->format == FMT_D4)
     size = 6;
 
@@ -1529,6 +1890,8 @@ keep_going:
       /* jmp  */
       else if (size == 3 && opcode->opcode == 0xcc0000)
        type = 10;
+      else if (size == 3 && (opcode->opcode & 0xfff000) == 0xf8d000)
+       type = 13;
       /* bCC (uncommon cases)  */
       else
        type = 3;
@@ -1635,6 +1998,12 @@ keep_going:
             is really two 8bit immediates.  */
          number_to_chars_bigendian (f, insn, 4);
        }
+      else if (opcode->format == FMT_D3)
+       {
+         number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
+         number_to_chars_littleendian (f + 2, insn & 0xffff, 2);
+         number_to_chars_bigendian (f + 4, extension & 0xff, 1);
+       }
       else if (opcode->format == FMT_D4)
        {
          unsigned long temp = ((insn & 0xffff) << 16) | (extension & 0xffff);
@@ -1897,6 +2266,8 @@ md_estimate_size_before_relax (fragp, seg)
                || seg != S_GET_SEGMENT (fragp->fr_symbol)))
     fragp->fr_subtype = 12;
 
+  if (fragp->fr_subtype == 13)
+    return 3;
   if (fragp->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0]))
     abort ();
 
@@ -2075,6 +2446,51 @@ mn10300_insert_operand (insnp, extensionp, operand, val, file, line, shift)
       *extensionp |= ((val & ((1 << (24 - operand->bits)) - 1))
                      << operand->shift);
     }
+  else if ((operand->flags & (MN10300_OPERAND_FSREG | MN10300_OPERAND_FDREG)))
+    {
+      /* See devo/opcodes/m10300-opc.c just before #define FSM0 for an
+         explanation of these variables.  Note that FMT-implied shifts
+        are not taken into account for FP registers.  */
+      unsigned long mask_low, mask_high;
+      int shl_low, shr_high, shl_high;
+
+      switch (operand->bits)
+       {
+       case 5:
+         /* Handle regular FP registers.  */
+         if (operand->shift >= 0)
+           {
+             /* This is an `m' register.  */
+             shl_low = operand->shift;
+             shl_high = 8 + (8 & shl_low) + (shl_low & 4) / 4;
+           }
+         else
+           {
+             /* This is an `n' register.  */
+             shl_low = -operand->shift;
+             shl_high = shl_low / 4;
+           }
+
+         mask_low = 0x0f;
+         mask_high = 0x10;
+         shr_high = 4;
+         break;
+
+       case 3:
+         /* Handle accumulators.  */
+         shl_low = -operand->shift;
+         shl_high = 0;
+         mask_low = 0x03;
+         mask_high = 0x04;
+         shr_high = 2;
+         break;
+
+       default:
+         abort ();
+       }
+      *insnp |= ((((val & mask_high) >> shr_high) << shl_high)
+                | ((val & mask_low) << shl_low));
+    }
   else if ((operand->flags & MN10300_OPERAND_EXTENDED) == 0)
     {
       *insnp |= (((long) val & ((1 << operand->bits) - 1))