* config/tc-m68k.c (m68k_abspcadd): New static variable.
authorIan Lance Taylor <ian@airs.com>
Wed, 9 Aug 1995 23:22:13 +0000 (23:22 +0000)
committerIan Lance Taylor <ian@airs.com>
Wed, 9 Aug 1995 23:22:13 +0000 (23:22 +0000)
(m68k_quick): New static variable.
(m68k_rel32): New static variable.
(md_pseudo_table): Add opt and reg.
(m68k_ip): Permit absolute symbols in 'l'/'L' recognition.  Check
m68k_quick in 'M' and 'Q' recognition.  Check m68k_abspcadd in
DISP handling.  Check m68k_rel32 in BASE/POST/PRE handling.
(md_begin): In MRI mode, initialize m68k_abspcadd and m68k_rel32.
In MRI mode, change unsized branch aliases to be variable sized.
(struct opt_action): Define.
(opt_table): Define.
(s_opt): New static function.
(skip_to_comma): New static function.
(opt_chip): New static function.
(opt_list): New static function.
(opt_list_symbols): New static function.
(s_reg): New static function.
* as.h (flag_keep_locals): Change from unsigned char to int.
(flag_no_warnings): Likewise.

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

index 09e0b74284a81d674decc293b81da6a017a6e601..ccdf546d008a57c15dcee459ec1e2dfcc646ff14 100644 (file)
@@ -1,5 +1,35 @@
 Wed Aug  9 10:51:48 1995  Ian Lance Taylor  <ian@cygnus.com>
 
+       * config/tc-m68k.c (m68k_abspcadd): New static variable.
+       (m68k_quick): New static variable.
+       (m68k_rel32): New static variable.
+       (md_pseudo_table): Add opt and reg.
+       (m68k_ip): Permit absolute symbols in 'l'/'L' recognition.  Check
+       m68k_quick in 'M' and 'Q' recognition.  Check m68k_abspcadd in
+       DISP handling.  Check m68k_rel32 in BASE/POST/PRE handling.
+       (md_begin): In MRI mode, initialize m68k_abspcadd and m68k_rel32.
+       In MRI mode, change unsized branch aliases to be variable sized.
+       (struct opt_action): Define.
+       (opt_table): Define.
+       (s_opt): New static function.
+       (skip_to_comma): New static function.
+       (opt_chip): New static function.
+       (opt_list): New static function.
+       (opt_list_symbols): New static function.
+       (s_reg): New static function.
+       * as.h (flag_keep_locals): Change from unsigned char to int.
+       (flag_no_warnings): Likewise.
+
+       * read.c (mri_line_label): Make non-static.
+       (potable): Add nopage, page, plen.
+       (s_org): Error if in MRI mode.
+       * read.h (mri_line_label): Declare.
+       * listing.c (listing_nopage): New function.
+       * listing.h (listing_nopage): Declare.
+
+       * symbols.c (symbol_begin): Set sy_frag of abs_symbol to
+       &zero_address_frag.
+
        * write.c (adjust_reloc_syms): Check that symbol is not NULL
        before checking sy_mri_common.
        (fixup_segment): Likewise.
index 6412a5da0fe90b915faafc96160593521d9f9f9e..3832755e398c22798943b93ef1a8daadc7abbc8a 100644 (file)
@@ -76,6 +76,19 @@ int flag_reg_prefix_optional;
 /* The floating point coprocessor to use by default.  */
 static enum m68k_register m68k_float_copnum = COP1;
 
+/* If this is non-zero, then references to number(%pc) will be taken
+   to refer to number, rather than to %pc + number.  */
+static int m68k_abspcadd;
+
+/* If this is non-zero, then the quick forms of the move, add, and sub
+   instructions are used when possible.  */
+static int m68k_quick = 1;
+
+/* If this is non-zero, then if the size is not specified for a base
+   or outer displacement, the assembler assumes that the size should
+   be 32 bits.  */
+static int m68k_rel32 = 1;
+
 /* Its an arbitrary name:  This means I don't approve of it */
 /* See flames below */
 static struct obstack robyn;
@@ -280,6 +293,8 @@ static void s_proc PARAMS ((int));
 static void mri_chip PARAMS ((void));
 static void s_chip PARAMS ((int));
 static void s_fopt PARAMS ((int));
+static void s_opt PARAMS ((int));
+static void s_reg PARAMS ((int));
 
 static int current_architecture;
 
@@ -410,6 +425,8 @@ CONST pseudo_typeS md_pseudo_table[] =
   {"comline", s_space, 1},
   {"fopt", s_fopt, 0},
   {"mask2", s_ignore, 0},
+  {"opt", s_opt, 0},
+  {"reg", s_reg, 0},
 
   {0, 0, 0}
 };
@@ -1036,6 +1053,14 @@ m68k_ip (instring)
                          opP->mode = REGLST;
                        }
                    }
+                 else if (opP->mode == ABSL
+                          && opP->disp.size == SIZE_UNSPEC
+                          && opP->disp.exp.X_op == O_constant)
+                   {
+                     /* This is what the MRI REG pseudo-op generates.  */
+                     opP->mode = REGLST;
+                     opP->mask = opP->disp.exp.X_add_number;
+                   }
                  else if (opP->mode != REGLST)
                    losing++;
                  else if (s[1] == '8' && (opP->mask & 0x0ffffff) != 0)
@@ -1049,6 +1074,10 @@ m68k_ip (instring)
                    losing++;
                  else if (! expr8 (&opP->disp))
                    losing++;
+                 else if (! m68k_quick
+                          && instring[3] != 'q'
+                          && instring[4] != 'q')
+                   losing++;
                  break;
 
                case 'O':
@@ -1063,6 +1092,11 @@ m68k_ip (instring)
                           || opP->disp.exp.X_add_number < 1
                           || opP->disp.exp.X_add_number > 8)
                    losing++;
+                 else if (! m68k_quick
+                          && (strncmp (instring, "add", 3) == 0
+                              || strncmp (instring, "sub", 3) == 0)
+                          && instring[3] != 'q')
+                   losing++;
                  break;
 
                case 'R':
@@ -1409,6 +1443,20 @@ m68k_ip (instring)
            case DISP:
 
              nextword = get_num (&opP->disp, 80);
+
+             if (opP->reg == PC
+                 && ! isvar (&opP->disp)
+                 && m68k_abspcadd)
+               {
+                 opP->disp.exp.X_op = O_symbol;
+#ifndef BFD_ASSEMBLER
+                 opP->disp.exp.X_add_symbol = &abs_symbol;
+#else
+                 opP->disp.exp.X_add_symbol =
+                   section_symbol (absolute_section);
+#endif
+               }
+
              /* Force into index mode.  Hope this works */
 
              /* We do the first bit for 32-bit displacements, and the
@@ -1621,12 +1669,14 @@ m68k_ip (instring)
              switch (siz1)
                {
                case SIZE_UNSPEC:
-                 if (isvar (&opP->disp) || !issword (baseo))
+                 if (isvar (&opP->disp)
+                     ? m68k_rel32
+                     : ! issword (baseo))
                    {
                      siz1 = SIZE_LONG;
                      nextword |= 0x30;
                    }
-                 else if (baseo == 0)
+                 else if (! isvar (&opP->disp) && baseo == 0)
                    nextword |= 0x10;
                  else
                    {
@@ -1651,12 +1701,14 @@ m68k_ip (instring)
                  switch (siz2)
                    {
                    case SIZE_UNSPEC:
-                     if (isvar (&opP->odisp) || !issword (outro))
+                     if (isvar (&opP->odisp)
+                         ? m68k_rel32
+                         : ! issword (outro))
                        {
                          siz2 = SIZE_LONG;
                          nextword |= 0x3;
                        }
-                     else if (outro == 0)
+                     else if (! isvar (&opP->disp) && outro == 0)
                        nextword |= 0x1;
                      else
                        {
@@ -2842,7 +2894,11 @@ md_begin ()
   register char c;
 
   if (flag_mri)
-    flag_reg_prefix_optional = 1;
+    {
+      flag_reg_prefix_optional = 1;
+      m68k_abspcadd = 1;
+      m68k_rel32 = 0;
+    }
 
   op_hash = hash_new ();
 
@@ -2890,6 +2946,43 @@ md_begin ()
        as_fatal ("Internal Error: Can't hash %s: %s", alias, retval);
     }
 
+  /* In MRI mode, all unsized branches are variable sized.  Normally,
+     they are word sized.  */
+  if (flag_mri)
+    {
+      static struct m68k_opcode_alias mri_aliases[] =
+       {
+         { "bhi",      "jhi", },
+         { "bls",      "jls", },
+         { "bcc",      "jcc", },
+         { "bcs",      "jcs", },
+         { "bne",      "jne", },
+         { "beq",      "jeq", },
+         { "bvc",      "jvc", },
+         { "bvs",      "jvs", },
+         { "bpl",      "jpl", },
+         { "bmi",      "jmi", },
+         { "bge",      "jge", },
+         { "blt",      "jlt", },
+         { "bgt",      "jgt", },
+         { "ble",      "jle", },
+         { "bra",      "jra", },
+         { "bsr",      "jbsr", },
+       };
+
+      for (i = 0; i < sizeof mri_aliases / sizeof mri_aliases[0]; i++)
+       {
+         const char *name = mri_aliases[i].primary;
+         const char *alias = mri_aliases[i].alias;
+         PTR val = hash_find (op_hash, name);
+         if (!val)
+           as_fatal ("Internal Error: Can't find %s in hash table", name);
+         retval = hash_jam (op_hash, alias, val);
+         if (retval)
+           as_fatal ("Internal Error: Can't hash %s: %s", alias, retval);
+       }
+    }
+
   for (i = 0; i < sizeof (mklower_table); i++)
     mklower_table[i] = (isupper (c = (char) i)) ? tolower (c) : c;
 
@@ -4067,6 +4160,278 @@ s_fopt (ignore)
 
   demand_empty_rest_of_line ();
 }
+
+/* The structure used to handle the MRI OPT pseudo-op.  */
+
+struct opt_action
+{
+  /* The name of the option.  */
+  const char *name;
+
+  /* If this is not NULL, just call this function.  The first argument
+     is the ARG field of this structure, the second argument is
+     whether the option was negated.  */
+  void (*pfn) PARAMS ((int arg, int on));
+
+  /* If this is not NULL, and the PFN field is NULL, set the variable
+     this points to.  Set it to the ARG field if the option was not
+     negated, and the NOTARG field otherwise.  */
+  int *pvar;
+
+  /* The value to pass to PFN or to assign to *PVAR.  */
+  int arg;
+
+  /* The value to assign to *PVAR if the option is negated.  If PFN is
+     NULL, and PVAR is not NULL, and ARG and NOTARG are the same, then
+     the option may not be negated.  */
+  int notarg;
+};
+
+/* The table used to handle the MRI OPT pseudo-op.  */
+
+static void skip_to_comma PARAMS ((int, int));
+static void opt_chip PARAMS ((int, int));
+static void opt_list PARAMS ((int, int));
+static void opt_list_symbols PARAMS ((int, int));
+
+static const struct opt_action opt_table[] =
+{
+  { "abspcadd", 0, &m68k_abspcadd, 1, 0 },
+
+  /* We do relaxing, so there is little use for these options.  */
+  { "b", 0, 0, 0, 0 },
+  { "brs", 0, 0, 0, 0 },
+  { "brb", 0, 0, 0, 0 },
+  { "brl", 0, 0, 0, 0 },
+  { "brw", 0, 0, 0, 0 },
+
+  { "c", 0, 0, 0, 0 },
+  { "cex", 0, 0, 0, 0 },
+  { "case", 0, &symbols_case_sensitive, 1, 0 },
+  { "cl", 0, 0, 0, 0 },
+  { "cre", 0, 0, 0, 0 },
+  { "d", 0, &flag_keep_locals, 1, 0 },
+  { "e", 0, 0, 0, 0 },
+  { "f", 0, &flag_short_refs, 1, 0 },
+  { "frs", 0, &flag_short_refs, 1, 0 },
+  { "frl", 0, &flag_short_refs, 0, 1 },
+  { "g", 0, 0, 0, 0 },
+  { "i", 0, 0, 0, 0 },
+  { "m", 0, 0, 0, 0 },
+  { "mex", 0, 0, 0, 0 },
+  { "mc", 0, 0, 0, 0 },
+  { "md", 0, 0, 0, 0 },
+  { "next", skip_to_comma, 0, 0, 0 },
+  { "o", 0, 0, 0, 0 },
+  { "old", 0, 0, 0, 0 },
+  { "op", skip_to_comma, 0, 0, 0 },
+  { "pco", 0, 0, 0, 0 },
+  { "p", opt_chip, 0, 0, 0 },
+  { "pcr", 0, 0, 0, 0 },
+  { "pcs", 0, 0, 0, 0 },
+  { "r", 0, 0, 0, 0 },
+  { "quick", 0, &m68k_quick, 1, 0 },
+  { "rel32", 0, &m68k_rel32, 1, 0 },
+  { "s", opt_list, 0, 0, 0 },
+  { "t", opt_list_symbols, 0, 0, 0 },
+  { "w", 0, &flag_no_warnings, 0, 1 },
+  { "x", 0, 0, 0, 0 }
+};
+
+#define OPTCOUNT (sizeof opt_table / sizeof opt_table[0])
+
+/* The MRI OPT pseudo-op.  */
+
+static void
+s_opt (ignore)
+     int ignore;
+{
+  do
+    {
+      int t;
+      char *s;
+      char c;
+      int i;
+      const struct opt_action *o;
+
+      SKIP_WHITESPACE ();
+
+      t = 1;
+      if (*input_line_pointer == '-')
+       {
+         ++input_line_pointer;
+         t = 0;
+       }
+      else if (strncasecmp (input_line_pointer, "NO", 2) == 0)
+       {
+         input_line_pointer += 2;
+         t = 0;
+       }
+
+      s = input_line_pointer;
+      c = get_symbol_end ();
+
+      for (i = 0, o = opt_table; i < OPTCOUNT; i++, o++)
+       {
+         if (strcasecmp (s, o->name) == 0)
+           {
+             if (o->pfn)
+               {
+                 /* Restore input_line_pointer now in case the option
+                    takes arguments.  */
+                 *input_line_pointer = c;
+                 (*o->pfn) (o->arg, t);
+               }
+             else if (o->pvar != NULL)
+               {
+                 if (! t && o->arg == o->notarg)
+                   as_bad ("option `%s' may not be negated", s);
+                 *input_line_pointer = c;
+                 *o->pvar = t ? o->arg : o->notarg;
+               }
+             break;
+           }
+       }
+      if (i >= OPTCOUNT)
+       {
+         as_bad ("option `%s' not recognized", s);
+         *input_line_pointer = c;
+       }
+    }
+  while (*input_line_pointer++ == ',');
+
+  /* Move back to terminating character.  */
+  --input_line_pointer;
+  demand_empty_rest_of_line ();
+}
+
+/* Skip ahead to a comma.  This is used for OPT options which we do
+   not suppor tand which take arguments.  */
+
+static void
+skip_to_comma (arg, on)
+     int arg;
+     int on;
+{
+  while (*input_line_pointer != ','
+        && ! is_end_of_line[(unsigned char) *input_line_pointer])
+    ++input_line_pointer;
+}
+
+/* Handle the OPT P=chip option.  */
+
+static void
+opt_chip (arg, on)
+     int arg;
+     int on;
+{
+  if (*input_line_pointer != '=')
+    {
+      /* This is just OPT P, which we do not support.  */
+      return;
+    }
+
+  ++input_line_pointer;
+  mri_chip ();
+}
+
+/* Handle the OPT S option.  */
+
+static void
+opt_list (arg, on)
+     int arg;
+     int on;
+{
+  listing_list (on);
+}
+
+/* Handle the OPT T option.  */
+
+static void
+opt_list_symbols (arg, on)
+     int arg;
+     int on;
+{
+  if (on)
+    listing |= LISTING_SYMBOLS;
+  else
+    listing &=~ LISTING_SYMBOLS;
+}
+
+/* Handle the MRI REG pseudo-op.  */
+
+static void
+s_reg (ignore)
+     int ignore;
+{
+  char *s;
+  int c;
+  struct m68k_op op;
+  unsigned long mask;
+
+  if (mri_line_label == NULL)
+    {
+      as_bad ("missing label");
+      ignore_rest_of_line ();
+      return;
+    }
+
+  SKIP_WHITESPACE ();
+
+  s = input_line_pointer;
+  while (isalnum ((unsigned char) *input_line_pointer)
+#ifdef REGISTER_PREFIX
+        || *input_line_pointer == REGISTER_PREFIX
+#endif
+        || *input_line_pointer == '/'
+        || *input_line_pointer == '-')
+    ++input_line_pointer;
+  c = *input_line_pointer;
+  *input_line_pointer = '\0';
+
+  if (m68k_ip_op (s, &op) != 0)
+    {
+      if (op.error == NULL)
+       as_bad ("bad register list");
+      else
+       as_bad ("bad register list: %s", op.error);
+      *input_line_pointer = c;
+      ignore_rest_of_line ();
+      return;
+    }
+
+  *input_line_pointer = c;
+
+  if (op.mode == REGLST)
+    mask = op.mask;
+  else if (op.mode == DREG)
+    mask = 1 << (op.reg - DATA0);
+  else if (op.mode == AREG)
+    mask = 1 << (op.reg - ADDR0 + 8);
+  else if (op.mode == FPREG)
+    mask = 1 << (op.reg - FP0 + 16);
+  else if (op.mode == CONTROL
+          && op.reg == FPI)
+    mask = 1 << 24;
+  else if (op.mode == CONTROL
+          && op.reg == FPS)
+    mask = 1 << 25;
+  else if (op.mode == CONTROL
+          && op.reg == FPC)
+    mask = 1 << 26;
+  else
+    {
+      as_bad ("bad register list");
+      ignore_rest_of_line ();
+      return;
+    }
+
+  S_SET_SEGMENT (mri_line_label, absolute_section);
+  S_SET_VALUE (mri_line_label, mask);
+  mri_line_label->sy_frag = &zero_address_frag;
+
+  demand_empty_rest_of_line ();
+}
 \f
 /*
  * md_parse_option