gas/
[deliverable/binutils-gdb.git] / gas / config / tc-m68hc11.c
index 751bb49b8d4970eade553534d271ad9e1528cea2..ec349b60c4b31c872ef14623e15782f4c5845073 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-m68hc11.c -- Assembler code for the Motorola 68HC11 & 68HC12.
-   Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
    Written by Stephane Carrez (stcarrez@nerim.fr)
 
    This file is part of GAS, the GNU Assembler.
@@ -19,7 +19,6 @@
    the Free Software Foundation, 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <stdio.h>
 #include "as.h"
 #include "safe-ctype.h"
 #include "subsegs.h"
@@ -375,8 +374,9 @@ md_show_usage (stream)
 {
   get_default_target ();
   fprintf (stream, _("\
-Motorola 68HC11/68HC12 options:\n\
-  -m68hc11 | -m68hc12     specify the processor [default %s]\n\
+Motorola 68HC11/68HC12/68HCS12 options:\n\
+  -m68hc11 | -m68hc12 |\n\
+  -m68hcs12               specify the processor [default %s]\n\
   -mshort                 use 16-bit int ABI (default)\n\
   -mlong                  use 32-bit int ABI\n\
   -mshort-double          use 32-bit double ABI\n\
@@ -503,6 +503,8 @@ md_parse_option (c, arg)
        current_architecture = cpu6811;
       else if (strcasecmp (arg, "68hc12") == 0)
        current_architecture = cpu6812;
+      else if (strcasecmp (arg, "68hcs12") == 0)
+       current_architecture = cpu6812 | cpu6812s;
       else
        as_bad (_("Option `%s' is not recognized."), arg);
       break;
@@ -987,6 +989,8 @@ register_name ()
 
   return reg_number;
 }
+#define M6811_OP_CALL_ADDR    0x00800000
+#define M6811_OP_PAGE_ADDR    0x04000000
 
 /* Parse a string of operands and return an array of expressions.
 
@@ -1052,6 +1056,24 @@ get_operand (oper, which, opmode)
          p += 3;
          mode |= M6811_OP_LOW_ADDR;
        }
+      /* %page modifier is used to obtain only the page number
+         of the address of a function.  */
+      else if (strncmp (p, "%page", 5) == 0)
+       {
+         p += 5;
+         mode |= M6811_OP_PAGE_ADDR;
+       }
+
+      /* %addr modifier is used to obtain the physical address part
+         of the function (16-bit).  For 68HC12 the function will be
+         mapped in the 16K window at 0x8000 and the value will be
+         within that window (although the function address may not fit
+         in 16-bit).  See bfd/elf32-m68hc12.c for the translation.  */
+      else if (strncmp (p, "%addr", 5) == 0)
+       {
+         p += 5;
+         mode |= M6811_OP_CALL_ADDR;
+       }
     }
   else if (*p == '.' && (p[1] == '+' || p[1] == '-'))
     {
@@ -1084,6 +1106,12 @@ get_operand (oper, which, opmode)
       as_bad (_("Spurious `,' or bad indirect register addressing mode."));
       return -1;
     }
+  /* Handle 68HC12 page specification in 'call foo,%page(bar)'.  */
+  else if ((opmode & M6812_OP_PAGE) && strncmp (p, "%page", 5) == 0)
+    {
+      p += 5;
+      mode = M6811_OP_PAGE_ADDR | M6812_OP_PAGE | M6811_OP_IND16;
+    }
   input_line_pointer = p;
 
   if (mode == M6811_OP_NONE || mode == M6812_OP_D_IDX)
@@ -1420,16 +1448,24 @@ fixup8 (oper, mode, opmode)
        }
       else
        {
-         /* Now create an 8-bit fixup.  If there was some %hi or %lo
-            modifier, generate the reloc accordingly.  */
-         fix_new_exp (frag_now, f - frag_now->fr_literal, 1,
-                      oper, FALSE,
-                      ((opmode & M6811_OP_HIGH_ADDR)
-                       ? BFD_RELOC_M68HC11_HI8
-                       : ((opmode & M6811_OP_LOW_ADDR)
-                          ? BFD_RELOC_M68HC11_LO8
-                           : ((mode & M6812_OP_PAGE)
-                              ? BFD_RELOC_M68HC11_PAGE : BFD_RELOC_8))));
+         fixS *fixp;
+          int reloc;
+
+         /* Now create an 8-bit fixup.  If there was some %hi, %lo
+            or %page modifier, generate the reloc accordingly.  */
+          if (opmode & M6811_OP_HIGH_ADDR)
+            reloc = BFD_RELOC_M68HC11_HI8;
+          else if (opmode & M6811_OP_LOW_ADDR)
+            reloc = BFD_RELOC_M68HC11_LO8;
+          else if (opmode & M6811_OP_PAGE_ADDR)
+            reloc = BFD_RELOC_M68HC11_PAGE;
+          else
+            reloc = BFD_RELOC_8;
+
+         fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 1,
+                              oper, FALSE, reloc);
+          if (reloc != BFD_RELOC_8)
+            fixp->fx_no_overflow = 1;
        }
       number_to_chars_bigendian (f, 0, 1);
     }
@@ -1463,18 +1499,27 @@ fixup16 (oper, mode, opmode)
   else if (oper->X_op != O_register)
     {
       fixS *fixp;
+      int reloc;
+
+      if ((opmode & M6811_OP_CALL_ADDR) && (mode & M6811_OP_IMM16))
+        reloc = BFD_RELOC_M68HC11_LO16;
+      else if (mode & M6812_OP_JUMP_REL16)
+        reloc = BFD_RELOC_16_PCREL;
+      else if (mode & M6812_OP_PAGE)
+        reloc = BFD_RELOC_M68HC11_LO16;
+      else
+        reloc = BFD_RELOC_16;
 
       /* Now create a 16-bit fixup.  */
       fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 2,
                          oper,
-                         (mode & M6812_OP_JUMP_REL16 ? TRUE : FALSE),
-                         (mode & M6812_OP_JUMP_REL16
-                          ? BFD_RELOC_16_PCREL
-                           : (mode & M6812_OP_PAGE)
-                           ? BFD_RELOC_M68HC11_LO16 : BFD_RELOC_16));
+                         reloc == BFD_RELOC_16_PCREL,
+                          reloc);
       number_to_chars_bigendian (f, 0, 2);
-      if (mode & M6812_OP_JUMP_REL16)
+      if (reloc == BFD_RELOC_16_PCREL)
        fixp->fx_pcrel_adjust = 2;
+      if (reloc == BFD_RELOC_M68HC11_LO16)
+        fixp->fx_no_overflow = 1;
     }
   else
     {
@@ -2403,6 +2448,11 @@ find_opcode (opc, operands, nb_operands)
       if (i >= opc->min_operands)
        {
          opcode = find (opc, operands, i);
+
+          /* Another special case for 'call foo,page' instructions.
+             Since we support 'call foo' and 'call foo,page' we must look
+             if the optional page specification is present otherwise we will
+             assemble immediately and treat the page spec as garbage.  */
           if (opcode && !(opcode->format & M6812_OP_PAGE))
              return opcode;
 
@@ -2994,7 +3044,9 @@ md_estimate_size_before_relax (fragP, segment)
   if (RELAX_LENGTH (fragP->fr_subtype) == STATE_UNDF)
     {
       if (S_GET_SEGMENT (fragP->fr_symbol) != segment
-         || !relaxable_symbol (fragP->fr_symbol))
+         || !relaxable_symbol (fragP->fr_symbol)
+          || (segment != absolute_section
+              && RELAX_STATE (fragP->fr_subtype) == STATE_INDEXED_OFFSET))
        {
          /* Non-relaxable cases.  */
          int old_fr_fix;
@@ -3185,18 +3237,10 @@ int
 tc_m68hc11_force_relocation (fixP)
      fixS * fixP;
 {
-  switch (fixP->fx_r_type)
-    {
-    case BFD_RELOC_VTABLE_INHERIT:
-    case BFD_RELOC_VTABLE_ENTRY:
-    case BFD_RELOC_M68HC11_RL_GROUP:
-      return 1;
-
-    default:
-      break;
-    }
+  if (fixP->fx_r_type == BFD_RELOC_M68HC11_RL_GROUP)
+    return 1;
 
-  return S_FORCE_RELOC (fixP->fx_addsy);
+  return generic_force_reloc (fixP);
 }
 
 /* Here we decide which fixups can be adjusted to make them relative
@@ -3213,14 +3257,19 @@ tc_m68hc11_fix_adjustable (fixP)
       /* For the linker relaxation to work correctly, these relocs
          need to be on the symbol itself.  */
     case BFD_RELOC_16:
-    case BFD_RELOC_LO16:
     case BFD_RELOC_M68HC11_RL_JUMP:
     case BFD_RELOC_M68HC11_RL_GROUP:
     case BFD_RELOC_VTABLE_INHERIT:
     case BFD_RELOC_VTABLE_ENTRY:
+    case BFD_RELOC_32:
+
+      /* The memory bank addressing translation also needs the original
+         symbol.  */
+    case BFD_RELOC_M68HC11_LO16:
+    case BFD_RELOC_M68HC11_PAGE:
+    case BFD_RELOC_M68HC11_24:
       return 0;
 
-    case BFD_RELOC_32:
     default:
       return 1;
     }
@@ -3332,6 +3381,8 @@ md_apply_fix3 (fixP, valP, seg)
 void
 m68hc11_elf_final_processing ()
 {
+  if (current_architecture & cpu6812s)
+    elf_flags |= EF_M68HCS12_MACH;
   elf_elfheader (stdoutput)->e_flags &= ~EF_M68HC11_ABI;
   elf_elfheader (stdoutput)->e_flags |= elf_flags;
 }
This page took 0.025773 seconds and 4 git commands to generate.