* config/tc-m68hc11.c (md_begin): Take into account additional
authorStephane Carrez <stcarrez@nerim.fr>
Tue, 13 Aug 2002 21:38:15 +0000 (21:38 +0000)
committerStephane Carrez <stcarrez@nerim.fr>
Tue, 13 Aug 2002 21:38:15 +0000 (21:38 +0000)
page operand for call instruction.
(print_opcode_format): Likewise.
(check_range): Likewise for page range checking.
(get_operand): Don't skip a possible comma in operands.
(fixup8): Generate BFD_RELOC_M68HC11_PAGE reloc.
(fixup16): Likwise with BFD_RELOC_M68HC11_LO16.
(fixup24): New to handle call reloc.
(build_insn): Handle missing page operand for call instruction.
(find): Likewise.
(md_apply_fix3): Take into account new relocs.
(get_operand): Fix the mode for indexed indirect addressing.
(build_indexed_byte): Fix post index byte for indexed indirect mode.

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

index 7f9a5ac9ee75b7bef8a66847c38f6e40097fe0ea..a8455bedd8464fccaa54d89f14c4770fced5a2d0 100644 (file)
@@ -1,3 +1,19 @@
+2002-08-13  Stephane Carrez  <stcarrez@nerim.fr>
+
+       * config/tc-m68hc11.c (md_begin): Take into account additional
+       page operand for call instruction.
+       (print_opcode_format): Likewise.
+       (check_range): Likewise for page range checking.
+       (get_operand): Don't skip a possible comma in operands.
+       (fixup8): Generate BFD_RELOC_M68HC11_PAGE reloc.
+       (fixup16): Likwise with BFD_RELOC_M68HC11_LO16.
+       (fixup24): New to handle call reloc.
+       (build_insn): Handle missing page operand for call instruction.
+       (find): Likewise.
+       (md_apply_fix3): Take into account new relocs.
+       (get_operand): Fix the mode for indexed indirect addressing.
+       (build_indexed_byte): Fix post index byte for indexed indirect mode.
+
 2002-08-12  Richard Sandiford  <rsandifo@redhat.com>
 
        * config/tc-mips.c (mips_ip): Don't work out the value of
index 8f402691bf5cc072f15c91aaa4e7ba5d957362d0..e50e72871f4b143cc80a3c558d36fc282e2198ca 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-m68hc11.c -- Assembler code for the Motorola 68HC11 & 68HC12.
    Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
-   Written by Stephane Carrez (stcarrez@worldnet.fr)
+   Written by Stephane Carrez (stcarrez@nerim.fr)
 
    This file is part of GAS, the GNU Assembler.
 
@@ -25,6 +25,7 @@
 #include "subsegs.h"
 #include "opcode/m68hc11.h"
 #include "dwarf2dbg.h"
+#include "elf/m68hc11.h"
 
 const char comment_chars[] = ";!";
 const char line_comment_chars[] = "#*";
@@ -163,6 +164,7 @@ static void print_insn_format PARAMS ((char *));
 static int get_operand PARAMS ((operand *, int, long));
 static void fixup8 PARAMS ((expressionS *, int, int));
 static void fixup16 PARAMS ((expressionS *, int, int));
+static void fixup24 PARAMS ((expressionS *, int, int));
 static unsigned char convert_branch PARAMS ((unsigned char));
 static char *m68hc11_new_insn PARAMS ((int));
 static void build_dbranch_insn PARAMS ((struct m68hc11_opcode *,
@@ -529,6 +531,10 @@ cmp_opcode (op1, op2)
   return strcmp (op1->name, op2->name);
 }
 
+#define IS_CALL_SYMBOL(MODE) \
+(((MODE) & (M6812_OP_PAGE|M6811_OP_IND16)) \
+  == ((M6812_OP_PAGE|M6811_OP_IND16)))
+
 /* Initialize the assembler.  Create the opcode hash table
    (sorted on the names) with the M6811 opcode table
    (from opcode library).  */
@@ -613,9 +619,15 @@ md_begin ()
        expect++;
       if (opcodes->format & (M6812_OP_IND16_P2 | M6812_OP_IDX_P2))
        expect++;
+      /* Special case for call instruction.  */
+      if ((opcodes->format & M6812_OP_PAGE)
+          && !(opcodes->format & M6811_OP_IND16))
+        expect++;
 
       if (expect < opc->min_operands)
        opc->min_operands = expect;
+      if (IS_CALL_SYMBOL (opcodes->format))
+         expect++;
       if (expect > opc->max_operands)
        opc->max_operands = expect;
     }
@@ -695,6 +707,15 @@ print_opcode_format (opcode, example)
       p = &p[strlen (p)];
     }
 
+  if (format & M6812_OP_PAGE)
+    {
+      if (example)
+       sprintf (p, ", %d", rand () & 0x0FF);
+      else
+       strcpy (p, ", <page>");
+      p = &p[strlen (p)];
+    }
+
   if (format & M6811_OP_DIRECT)
     {
       if (example)
@@ -900,19 +921,19 @@ register_name ()
 
 /* Parse a string of operands and return an array of expressions.
 
-   Operand              mode[0]         mode[1]       exp[0]       exp[1]
-   #n                   M6811_OP_IMM16  -             O_*
-   *<exp>               M6811_OP_DIRECT -             O_*
-   .{+-}<exp>           M6811_OP_JUMP_REL -           O_*
-   <exp>                M6811_OP_IND16  -             O_*
-   ,r N,r               M6812_OP_IDX    M6812_OP_REG  O_constant   O_register
-   n,-r                 M6812_PRE_DEC   M6812_OP_REG  O_constant   O_register
-   n,+r                 M6812_PRE_INC   " "
-   n,r-                 M6812_POST_DEC  " "
-   n,r+                 M6812_POST_INC  " "
-   A,r B,r D,r          M6811_OP_REG    M6812_OP_REG  O_register   O_register
-   [D,r]                M6811_OP_IDX_2  M6812_OP_REG  O_register   O_register
-   [n,r]                M6811_OP_IDX_1  M6812_OP_REG  O_constant   O_register  */
+   Operand      mode[0]         mode[1]       exp[0]       exp[1]
+   #n           M6811_OP_IMM16  -             O_*
+   *<exp>       M6811_OP_DIRECT -             O_*
+   .{+-}<exp>   M6811_OP_JUMP_REL -           O_*
+   <exp>        M6811_OP_IND16  -             O_*
+   ,r N,r       M6812_OP_IDX    M6812_OP_REG  O_constant   O_register
+   n,-r         M6812_PRE_DEC   M6812_OP_REG  O_constant   O_register
+   n,+r         M6812_PRE_INC   " "
+   n,r-         M6812_POST_DEC  " "
+   n,r+         M6812_POST_INC  " "
+   A,r B,r D,r  M6811_OP_REG    M6812_OP_REG  O_register   O_register
+   [D,r]        M6811_OP_D_IDX  M6812_OP_REG  O_register   O_register
+   [n,r]        M6811_OP_D_IDX_2 M6812_OP_REG  O_constant   O_register  */
 static int
 get_operand (oper, which, opmode)
      operand *oper;
@@ -974,7 +995,7 @@ get_operand (oper, which, opmode)
        as_bad (_("Indirect indexed addressing is not valid for 68HC11."));
 
       p++;
-      mode = M6812_OP_IDX_2;
+      mode = M6812_OP_D_IDX;
       p = skip_whites (p);
     }
   else if (*p == ',')          /* Special handling of ,x and ,y.  */
@@ -996,7 +1017,7 @@ get_operand (oper, which, opmode)
     }
   input_line_pointer = p;
 
-  if (mode == M6811_OP_NONE || mode == M6812_OP_IDX_2)
+  if (mode == M6811_OP_NONE || mode == M6812_OP_D_IDX)
     reg = register_name ();
   else
     reg = REG_NONE;
@@ -1004,7 +1025,7 @@ get_operand (oper, which, opmode)
   if (reg != REG_NONE)
     {
       p = skip_whites (input_line_pointer);
-      if (*p == ']' && mode == M6812_OP_IDX_2)
+      if (*p == ']' && mode == M6812_OP_D_IDX)
        {
          as_bad
            (_("Missing second register or offset for indexed-indirect mode."));
@@ -1015,7 +1036,7 @@ get_operand (oper, which, opmode)
       oper->mode = mode | M6812_OP_REG;
       if (*p != ',')
        {
-         if (mode == M6812_OP_IDX_2)
+         if (mode == M6812_OP_D_IDX)
            {
              as_bad (_("Missing second register for indexed-indirect mode."));
              return -1;
@@ -1029,7 +1050,7 @@ get_operand (oper, which, opmode)
       if (reg != REG_NONE)
        {
          p = skip_whites (input_line_pointer);
-         if (mode == M6812_OP_IDX_2)
+         if (mode == M6812_OP_D_IDX)
            {
              if (*p != ']')
                {
@@ -1037,6 +1058,7 @@ get_operand (oper, which, opmode)
                  return -1;
                }
              p++;
+              oper->mode = M6812_OP_D_IDX;
            }
          input_line_pointer = p;
 
@@ -1089,7 +1111,7 @@ get_operand (oper, which, opmode)
   p = input_line_pointer;
 
   if (mode == M6811_OP_NONE || mode == M6811_OP_DIRECT
-      || mode == M6812_OP_IDX_2)
+      || mode == M6812_OP_D_IDX)
     {
       p = skip_whites (input_line_pointer);
 
@@ -1097,6 +1119,8 @@ get_operand (oper, which, opmode)
        {
          int possible_mode = M6811_OP_NONE;
          char *old_input_line;
+
+         old_input_line = p;
          p++;
 
          /* 68HC12 pre increment or decrement.  */
@@ -1114,7 +1138,6 @@ get_operand (oper, which, opmode)
                }
              p = skip_whites (p);
            }
-         old_input_line = input_line_pointer;
          input_line_pointer = p;
          reg = register_name ();
 
@@ -1150,7 +1173,7 @@ get_operand (oper, which, opmode)
              as_bad (_("Wrong register in register indirect mode."));
              return -1;
            }
-         if (mode == M6812_OP_IDX_2)
+         if (mode == M6812_OP_D_IDX)
            {
              p = skip_whites (input_line_pointer);
              if (*p++ != ']')
@@ -1159,6 +1182,9 @@ get_operand (oper, which, opmode)
                  return -1;
                }
              input_line_pointer = p;
+              oper->reg1 = reg;
+              oper->mode = M6812_OP_D_IDX_2;
+              return 1;
            }
          if (reg != REG_NONE)
            {
@@ -1193,6 +1219,7 @@ get_operand (oper, which, opmode)
              oper->mode = mode;
              return 1;
            }
+          input_line_pointer = old_input_line;
        }
 
       if (mode == M6812_OP_D_IDX_2)
@@ -1236,6 +1263,7 @@ check_range (num, mode)
   if (mode & M6812_OP_JUMP_REL16)
     mode = M6811_OP_IND16;
 
+  mode &= ~M6811_OP_BRANCH;
   switch (mode)
     {
     case M6811_OP_IX:
@@ -1245,6 +1273,7 @@ check_range (num, mode)
 
     case M6811_OP_BITMASK:
     case M6811_OP_IMM8:
+    case M6812_OP_PAGE:
       return (((num & 0xFFFFFF00) == 0) || ((num & 0xFFFFFF00) == 0xFFFFFF00))
        ? 1 : 0;
 
@@ -1252,6 +1281,7 @@ check_range (num, mode)
       return (num >= -128 && num <= 127) ? 1 : 0;
 
     case M6811_OP_IND16:
+    case M6811_OP_IND16 | M6812_OP_PAGE:
     case M6811_OP_IMM16:
       return (((num & 0xFFFF0000) == 0) || ((num & 0xFFFF0000) == 0xFFFF0000))
        ? 1 : 0;
@@ -1328,7 +1358,9 @@ fixup8 (oper, mode, opmode)
                       ((opmode & M6811_OP_HIGH_ADDR)
                        ? BFD_RELOC_M68HC11_HI8
                        : ((opmode & M6811_OP_LOW_ADDR)
-                          ? BFD_RELOC_M68HC11_LO8 : BFD_RELOC_8)));
+                          ? BFD_RELOC_M68HC11_LO8
+                           : ((mode & M6812_OP_PAGE)
+                              ? BFD_RELOC_M68HC11_PAGE : BFD_RELOC_8))));
        }
       number_to_chars_bigendian (f, 0, 1);
     }
@@ -1368,7 +1400,9 @@ fixup16 (oper, mode, opmode)
                          oper,
                          (mode & M6812_OP_JUMP_REL16 ? true : false),
                          (mode & M6812_OP_JUMP_REL16
-                          ? BFD_RELOC_16_PCREL : BFD_RELOC_16));
+                          ? BFD_RELOC_16_PCREL
+                           : (mode & M6812_OP_PAGE)
+                           ? BFD_RELOC_M68HC11_LO16 : BFD_RELOC_16));
       number_to_chars_bigendian (f, 0, 2);
       if (mode & M6812_OP_JUMP_REL16)
        fixp->fx_pcrel_adjust = 2;
@@ -1378,6 +1412,42 @@ fixup16 (oper, mode, opmode)
       as_fatal (_("Operand `%x' not recognized in fixup16."), oper->X_op);
     }
 }
+
+/* Put a 3 byte expression described by 'oper'.  If this expression contains
+   unresolved symbols, generate a 24-bit fixup.  */
+static void
+fixup24 (oper, mode, opmode)
+     expressionS *oper;
+     int mode;
+     int opmode ATTRIBUTE_UNUSED;
+{
+  char *f;
+
+  f = frag_more (3);
+
+  if (oper->X_op == O_constant)
+    {
+      if (!check_range (oper->X_add_number, mode))
+       {
+         as_bad (_("Operand out of 16-bit range: `%ld'."),
+                 oper->X_add_number);
+       }
+      number_to_chars_bigendian (f, oper->X_add_number & 0x0FFFFFF, 3);
+    }
+  else if (oper->X_op != O_register)
+    {
+      fixS *fixp;
+
+      /* Now create a 24-bit fixup.  */
+      fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 2,
+                         oper, false, BFD_RELOC_M68HC11_24);
+      number_to_chars_bigendian (f, 0, 3);
+    }
+  else
+    {
+      as_fatal (_("Operand `%x' not recognized in fixup16."), oper->X_op);
+    }
+}
 \f
 /* 68HC11 and 68HC12 code generation.  */
 
@@ -1703,7 +1773,7 @@ build_indexed_byte (op, format, move_insn)
       return 1;
     }
 
-  if (mode & M6812_OP_IDX)
+  if (mode & (M6812_OP_IDX | M6812_OP_D_IDX_2))
     {
       switch (op->reg1)
        {
@@ -1741,7 +1811,7 @@ build_indexed_byte (op, format, move_insn)
              return -1;
            }
 
-         if (val >= -16 && val <= 15 && !(mode & M6812_OP_IDX_2))
+         if (val >= -16 && val <= 15 && !(mode & M6812_OP_D_IDX_2))
            {
              byte = byte << 6;
              byte |= val & 0x1f;
@@ -1749,7 +1819,7 @@ build_indexed_byte (op, format, move_insn)
              number_to_chars_bigendian (f, byte, 1);
              return 1;
            }
-         else if (val >= -256 && val <= 255 && !(mode & M6812_OP_IDX_2))
+         else if (val >= -256 && val <= 255 && !(mode & M6812_OP_D_IDX_2))
            {
              byte = byte << 3;
              byte |= 0xe0;
@@ -1763,7 +1833,7 @@ build_indexed_byte (op, format, move_insn)
          else
            {
              byte = byte << 3;
-             if (mode & M6812_OP_IDX_2)
+             if (mode & M6812_OP_D_IDX_2)
                byte |= 0xe3;
              else
                byte |= 0xe2;
@@ -1774,7 +1844,15 @@ build_indexed_byte (op, format, move_insn)
              return 3;
            }
        }
-      if (op->reg1 != REG_PC)
+      if (mode & M6812_OP_D_IDX_2)
+        {
+          byte = (byte << 3) | 0xe3;
+          f = frag_more (1);
+          number_to_chars_bigendian (f, byte, 1);
+
+          fixup16 (&op->exp, 0, 0);
+        }
+      else if (op->reg1 != REG_PC)
        {
          byte = (byte << 3) | 0xe2;
          f = frag_more (1);
@@ -1797,9 +1875,9 @@ build_indexed_byte (op, format, move_insn)
       return 3;
     }
 
-  if (mode & M6812_OP_REG)
+  if (mode & (M6812_OP_REG | M6812_OP_D_IDX))
     {
-      if (mode & M6812_OP_IDX_2)
+      if (mode & M6812_OP_D_IDX)
        {
          if (op->reg1 != REG_D)
            as_bad (_("Expecting register D for indexed indirect mode."));
@@ -1954,9 +2032,17 @@ build_insn (opcode, operands, nb_operands)
              operands[i].mode);
       i++;
     }
+  else if (IS_CALL_SYMBOL (format) && nb_operands == 1)
+    {
+      format &= ~M6812_OP_PAGE;
+      fixup24 (&operands[i].exp, format & M6811_OP_IND16,
+              operands[i].mode);
+      i++;
+    }
   else if (format & (M6811_OP_IMM16 | M6811_OP_IND16))
     {
-      fixup16 (&operands[i].exp, format & (M6811_OP_IMM16 | M6811_OP_IND16),
+      fixup16 (&operands[i].exp,
+               format & (M6811_OP_IMM16 | M6811_OP_IND16 | M6812_OP_PAGE),
               operands[i].mode);
       i++;
     }
@@ -1971,7 +2057,8 @@ build_insn (opcode, operands, nb_operands)
       i = 1;
     }
   else if (format &
-          (M6812_OP_IDX | M6812_OP_IDX_2 | M6812_OP_IDX_1 | M6812_OP_D_IDX))
+          (M6812_OP_IDX | M6812_OP_IDX_2 | M6812_OP_IDX_1
+            | M6812_OP_D_IDX | M6812_OP_D_IDX_2))
     {
       build_indexed_byte (&operands[i], format, move_insn);
       i++;
@@ -1994,6 +2081,10 @@ build_insn (opcode, operands, nb_operands)
     {
       fixup16 (&operands[1].exp, M6811_OP_IND16, operands[1].mode);
     }
+  if (format & M6812_OP_PAGE)
+    {
+      fixup8 (&operands[i].exp, M6812_OP_PAGE, operands[i].mode);
+    }
 }
 \f
 /* Opcode identification and operand analysis.  */
@@ -2032,6 +2123,9 @@ find (opc, operands, nb_operands)
        expect++;
       if (opcode->format & (M6812_OP_IND16_P2 | M6812_OP_IDX_P2))
        expect++;
+      if ((opcode->format & M6812_OP_PAGE)
+          && (!IS_CALL_SYMBOL (opcode->format) || nb_operands == 2))
+        expect++;
 
       for (i = 0; expect == nb_operands && i < nb_operands; i++)
        {
@@ -2064,6 +2158,8 @@ find (opc, operands, nb_operands)
            {
              if (i == 0 && (format & M6811_OP_IND16) != 0)
                continue;
+              if (i != 0 && (format & M6812_OP_PAGE) != 0)
+                continue;
              if (i != 0 && (format & M6812_OP_IND16_P2) != 0)
                continue;
              if (i == 0 && (format & M6811_OP_BITMASK))
@@ -2089,9 +2185,6 @@ find (opc, operands, nb_operands)
                  && (format & M6812_OP_IDX)
                  && (operands[i].reg2 != REG_NONE))
                continue;
-             if (i == 0
-                 && (format & M6812_OP_D_IDX))
-               continue;
              if (i == 0
                  && (format & M6812_OP_IDX)
                  && (format & (M6812_OP_IND16_P2 | M6812_OP_IDX_P2)))
@@ -2117,6 +2210,11 @@ find (opc, operands, nb_operands)
              if (i == 1 && format & M6812_OP_IDX_P2)
                continue;
            }
+          if (mode & format & (M6812_OP_D_IDX | M6812_OP_D_IDX_2))
+            {
+              if (i == 0)
+                continue;
+            }
          if (mode & M6812_AUTO_INC_DEC)
            {
              if (i == 0
@@ -2204,7 +2302,10 @@ find_opcode (opc, operands, nb_operands)
       if (i >= opc->min_operands)
        {
          opcode = find (opc, operands, i);
-         if (opcode)
+          if (opcode && !(opcode->format & M6812_OP_PAGE))
+             return opcode;
+
+         if (opcode && *input_line_pointer != ',')
            return opcode;
        }
 
@@ -2779,8 +2880,15 @@ md_apply_fix3 (fixP, valP, seg)
       bfd_putb32 ((bfd_vma) value, (unsigned char *) where);
       break;
 
+    case BFD_RELOC_24:
+    case BFD_RELOC_M68HC11_24:
+      bfd_putb16 ((bfd_vma) (value & 0x0ffff), (unsigned char *) where);
+      ((bfd_byte*) where)[2] = ((value >> 16) & 0x0ff);
+      break;
+
     case BFD_RELOC_16:
     case BFD_RELOC_16_PCREL:
+    case BFD_RELOC_M68HC11_LO16:
       bfd_putb16 ((bfd_vma) value, (unsigned char *) where);
       if (value < -65537 || value > 65535)
        as_bad_where (fixP->fx_file, fixP->fx_line,
@@ -2793,6 +2901,7 @@ md_apply_fix3 (fixP, valP, seg)
 
     case BFD_RELOC_M68HC11_LO8:
     case BFD_RELOC_8:
+    case BFD_RELOC_M68HC11_PAGE:
 #if 0
       bfd_putb8 ((bfd_vma) value, (unsigned char *) where);
 #endif