2012-05-06 Arnold Metselaar <arnold_m@operamail.com>
authorArnold Metselaar <arnold.metselaar@planet.nl>
Sun, 6 May 2012 09:49:21 +0000 (09:49 +0000)
committerArnold Metselaar <arnold.metselaar@planet.nl>
Sun, 6 May 2012 09:49:21 +0000 (09:49 +0000)
* config/tc-z80.h(md_register_arithmetic): Define as 0.
* config/tc-z80.c(md_begin): Store register names in symbol table, prevents usage as ordinary symbol.
* config/tc-z80.c(contains_register): New function.
* config/tc-z80.c(parse_exp2): Removed.
* config/tc-z80.c(parse_exp_not_indexed): New function.
* config/tc-z80.c(parse_exp): Add code to recogize indexed addressing after parsing.
* config/tc-z80.c(emit_byte, emit_word): Use contains_register.
* config/tc-z80.c(emit_jp): Use parse_exp_not_indexed, simplify condition for jump to register.
* config/tc-z80.c(emit_call, emit_jr, emit_ex, emit_rst): Use parse_exp_not_indexed.

gas/ChangeLog
gas/config/tc-z80.c
gas/config/tc-z80.h

index b199a17415fa1e7982ae49f7f8728adf9659004a..949978243e7e9aee925d2e7495fe261e6759d511 100644 (file)
@@ -1,3 +1,15 @@
+2012-05-06  Arnold Metselaar <arnold_m@operamail.com>
+
+       * config/tc-z80.h(md_register_arithmetic): Define as 0.
+       * config/tc-z80.c(md_begin): Store register names in symbol table, prevents usage as ordinary symbol.
+       * config/tc-z80.c(contains_register): New function.
+       * config/tc-z80.c(parse_exp2): Removed.
+       * config/tc-z80.c(parse_exp_not_indexed): New function.
+       * config/tc-z80.c(parse_exp): Add code to recogize indexed addressing after parsing.
+       * config/tc-z80.c(emit_byte, emit_word): Use contains_register.
+       * config/tc-z80.c(emit_jp): Use parse_exp_not_indexed, simplify condition for jump to register.
+       * config/tc-z80.c(emit_call, emit_jr, emit_ex, emit_rst): Use parse_exp_not_indexed.
+
 2012-05-05  Alan Modra  <amodra@gmail.com>
 
        * ecoff.c: Replace all uses of bfd_abs_section, bfd_com_section,
index 06f8aaa0215cee6d1ee80cf29bfdc06682493832..d93c155d4fb331b5ac2c9be00e37f9931cc9817d 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-z80.c -- Assemble code for the Zilog Z80 and ASCII R800
-   Copyright 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+   Copyright 2005, 2006, 2007, 2008, 2009, 2012 Free Software Foundation, Inc.
    Contributed by Arnold Metselaar <arnold_m@operamail.com>
 
    This file is part of GAS, the GNU Assembler.
@@ -161,12 +161,93 @@ Default: -z80 -ignore-undocument-instructions -warn-unportable-instructions.\n")
 
 static symbolS * zero;
 
+struct reg_entry
+{
+  char* name;
+  int number;
+};
+#define R_STACKABLE (0x80)
+#define R_ARITH     (0x40)
+#define R_IX        (0x20)
+#define R_IY        (0x10)
+#define R_INDEX     (R_IX | R_IY)
+
+#define REG_A (7)
+#define REG_B (0)
+#define REG_C (1)
+#define REG_D (2)
+#define REG_E (3)
+#define REG_H (4)
+#define REG_L (5)
+#define REG_F (6 | 8)
+#define REG_I (9)
+#define REG_R (10)
+
+#define REG_AF (3 | R_STACKABLE)
+#define REG_BC (0 | R_STACKABLE | R_ARITH)
+#define REG_DE (1 | R_STACKABLE | R_ARITH)
+#define REG_HL (2 | R_STACKABLE | R_ARITH)
+#define REG_IX (REG_HL | R_IX)
+#define REG_IY (REG_HL | R_IY)
+#define REG_SP (3 | R_ARITH)
+
+static const struct reg_entry regtable[] =
+{
+  {"a",  REG_A },
+  {"af", REG_AF },
+  {"b",  REG_B },
+  {"bc", REG_BC },
+  {"c",  REG_C },
+  {"d",  REG_D },
+  {"de", REG_DE },
+  {"e",  REG_E },
+  {"f",  REG_F },
+  {"h",  REG_H },
+  {"hl", REG_HL },
+  {"i",  REG_I },
+  {"ix", REG_IX },
+  {"ixh",REG_H | R_IX },
+  {"ixl",REG_L | R_IX },
+  {"iy", REG_IY },
+  {"iyh",REG_H | R_IY },
+  {"iyl",REG_L | R_IY },
+  {"l",  REG_L },
+  {"r",  REG_R },
+  {"sp", REG_SP },
+} ;
+
+#define BUFLEN 8 /* Large enough for any keyword.  */
+
 void
 md_begin (void)
 {
-  expressionS nul;
+  expressionS nul, reg;
   char * p;
+  unsigned int i, j, k;
+  char buf[BUFLEN];
 
+  reg.X_op = O_register;
+  reg.X_md = 0;
+  reg.X_add_symbol = reg.X_op_symbol = 0;
+  for ( i = 0 ; i < ARRAY_SIZE ( regtable ) ; ++i )
+    {
+      reg.X_add_number = regtable[i].number;
+      k = strlen ( regtable[i].name );
+      buf[k] = 0;
+      if ( k+1 < BUFLEN )
+        {
+          for ( j = ( 1<<k ) ; j ; --j )
+            {
+              for ( k = 0 ; regtable[i].name[k] ; ++k )
+                {
+                  buf[k] = ( j & ( 1<<k ) ) ? TOUPPER ( regtable[i].name[k] ) : regtable[i].name[k];
+                }
+              symbolS * psym = symbol_find_or_make(buf);
+             S_SET_SEGMENT(psym, reg_section);
+             symbol_set_value_expression(psym, &reg);
+            }
+        }
+    }
   p = input_line_pointer;
   input_line_pointer = "0";
   nul.X_md=0;
@@ -343,63 +424,9 @@ key_cmp (const void * a, const void * b)
   return strcmp (str_a, str_b);
 }
 
-#define BUFLEN 8 /* Large enough for any keyword.  */
-
 char buf[BUFLEN];
 const char *key = buf;
 
-#define R_STACKABLE (0x80)
-#define R_ARITH     (0x40)
-#define R_IX        (0x20)
-#define R_IY        (0x10)
-#define R_INDEX     (R_IX | R_IY)
-
-#define REG_A (7)
-#define REG_B (0)
-#define REG_C (1)
-#define REG_D (2)
-#define REG_E (3)
-#define REG_H (4)
-#define REG_L (5)
-#define REG_F (6 | 8)
-#define REG_I (9)
-#define REG_R (10)
-
-#define REG_AF (3 | R_STACKABLE)
-#define REG_BC (0 | R_STACKABLE | R_ARITH)
-#define REG_DE (1 | R_STACKABLE | R_ARITH)
-#define REG_HL (2 | R_STACKABLE | R_ARITH)
-#define REG_SP (3 | R_ARITH)
-
-static const struct reg_entry
-{
-  char* name;
-  int number;
-} regtable[] =
-{
-  {"a",  REG_A },
-  {"af", REG_AF },
-  {"b",  REG_B },
-  {"bc", REG_BC },
-  {"c",  REG_C },
-  {"d",  REG_D },
-  {"de", REG_DE },
-  {"e",  REG_E },
-  {"f",  REG_F },
-  {"h",  REG_H },
-  {"hl", REG_HL },
-  {"i",  REG_I },
-  {"ix", REG_HL | R_IX },
-  {"ixh",REG_H | R_IX },
-  {"ixl",REG_L | R_IX },
-  {"iy", REG_HL | R_IY },
-  {"iyh",REG_H | R_IY },
-  {"iyl",REG_L | R_IY },
-  {"l",  REG_L },
-  {"r",  REG_R },
-  {"sp", REG_SP },
-} ;
-
 /* Prevent an error on a line from also generating
    a "junk at end of line" error message.  */
 static char err_flag;
@@ -496,88 +523,90 @@ is_indir (const char *s)
   return indir;
 }
 
-/* Parse general expression.  */
+/* Check whether a symbol involves a register.  */
+static int 
+contains_register(symbolS *sym)
+{
+  if (sym)
+  {
+    expressionS * ex = symbol_get_value_expression(sym);
+    return (O_register == ex->X_op) 
+      || (ex->X_add_symbol && contains_register(ex->X_add_symbol)) 
+      || (ex->X_op_symbol && contains_register(ex->X_op_symbol));
+  }
+  else
+    return 0;
+}
+
+/* Parse general expression, not loooking for indexed adressing.  */
 static const char *
-parse_exp2 (const char *s, expressionS *op, segT *pseg)
+parse_exp_not_indexed (const char *s, expressionS *op)
 {
   const char *p;
   int indir;
-  int i;
-  const struct reg_entry * regp;
-  expressionS offset;
+  segT dummy;
 
   p = skip_space (s);
   op->X_md = indir = is_indir (p);
-  if (indir)
-    p = skip_space (p + 1);
-
-  for (i = 0; i < BUFLEN; ++i)
-    {
-      if (!ISALPHA (p[i])) /* Register names consist of letters only.  */
-       break;
-      buf[i] = TOLOWER (p[i]);
-    }
-
-  if ((i < BUFLEN) && ((p[i] == 0) || (strchr (")+-, \t", p[i]))))
+  input_line_pointer = (char*) s ;
+  dummy = expression (op);
+  switch (op->X_op)
     {
-      buf[i] = 0;
-      regp = bsearch (& key, regtable, ARRAY_SIZE (regtable),
-                     sizeof (regtable[0]), key_cmp);
-      if (regp)
-       {
-         *pseg = reg_section;
-         op->X_add_symbol = op->X_op_symbol = 0;
-         op->X_add_number = regp->number;
-         op->X_op = O_register;
-         p += strlen (regp->name);
-         p = skip_space (p);
-         if (indir)
-           {
-             if (*p == ')')
-               ++p;
-             if ((regp->number & R_INDEX) && (regp->number & R_ARITH))
-               {
-                 op->X_op = O_md1;
-
-                 if  ((*p == '+') || (*p == '-'))
-                   {
-                     input_line_pointer = (char*) p;
-                     expression (& offset);
-                     p = skip_space (input_line_pointer);
-                     if (*p != ')')
-                       error (_("bad offset expression syntax"));
-                     else
-                       ++ p;
-                     op->X_add_symbol = make_expr_symbol (& offset);
-                     return p;
-                   }
-
-                 /* We treat (i[xy]) as (i[xy]+0), which is how it will
-                    end up anyway, unless we're processing jp (i[xy]).  */
-                 op->X_add_symbol = zero;
-               }
-           }
-         p = skip_space (p);
-
-         if ((*p == 0) || (*p == ','))
-           return p;
-       }
+    case O_absent:
+      error (_("missing operand"));
+      break;
+    case O_illegal:
+      error (_("bad expression syntax"));
+      break;
     }
-  /* Not an argument involving a register; use the generic parser.  */
-  input_line_pointer = (char*) s ;
-  *pseg = expression (op);
-  if (op->X_op == O_absent)
-    error (_("missing operand"));
-  if (op->X_op == O_illegal)
-    error (_("bad expression syntax"));
   return input_line_pointer;
 }
 
+/* Parse expression, change operator to O_md1 for indexed addressing*/
 static const char *
 parse_exp (const char *s, expressionS *op)
 {
-  segT dummy;
-  return parse_exp2 (s, op, & dummy);
+  const char* res = parse_exp_not_indexed (s, op);
+  switch (op->X_op)
+    {
+    case O_add:
+    case O_subtract:
+      if (op->X_md && (O_register == symbol_get_value_expression(op->X_add_symbol)->X_op))
+        {
+         int rnum = symbol_get_value_expression(op->X_add_symbol)->X_add_number;
+         if ( ((REG_IX != rnum) && (REG_IY != rnum)) || contains_register(op->X_op_symbol) )
+           {
+             ill_op();
+           }
+         else
+           {
+             if (O_subtract == op->X_op)
+               {
+                 expressionS minus;
+                 minus.X_op = O_uminus;
+                 minus.X_add_number = 0;
+                 minus.X_add_symbol = op->X_op_symbol;
+                 minus.X_op_symbol = 0;
+                 op->X_op_symbol = make_expr_symbol(&minus);
+                 op->X_op = O_add;
+               }
+             symbol_get_value_expression(op->X_op_symbol)->X_add_number += op->X_add_number;
+             op->X_add_number = rnum;
+             op->X_add_symbol = op->X_op_symbol;
+             op->X_op_symbol = 0;
+             op->X_op = O_md1;
+           }
+       }
+      break;
+    case O_register:
+      if ( op->X_md && ((REG_IX == op->X_add_number)||(REG_IY == op->X_add_number)) )
+        {
+         op->X_add_symbol = zero;
+         op->X_op = O_md1;
+       }
+       break;
+    }
+  return res;
 }
 
 /* Condition codes, including some synonyms provided by HiTech zas.  */
@@ -680,7 +709,11 @@ emit_byte (expressionS * val, bfd_reloc_code_real_type r_type)
 
   p = frag_more (1);
   *p = val->X_add_number;
-  if ((r_type == BFD_RELOC_8_PCREL) && (val->X_op == O_constant))
+  if ( contains_register(val->X_add_symbol) || contains_register(val->X_op_symbol) )
+    {
+      ill_op();
+    }
+  else if ((r_type == BFD_RELOC_8_PCREL) && (val->X_op == O_constant))
     {
       as_bad (_("cannot make a relative jump to an absolute location"));
     }
@@ -712,7 +745,9 @@ emit_word (expressionS * val)
 
   p = frag_more (2);
   if (   (val->X_op == O_register)
-      || (val->X_op == O_md1))
+      || (val->X_op == O_md1)
+      || contains_register(val->X_add_symbol)
+      || contains_register(val->X_op_symbol) )
     ill_op ();
   else
     {
@@ -888,7 +923,7 @@ emit_call (char prefix ATTRIBUTE_UNUSED, char opcode, const char * args)
   expressionS addr;
   const char *p;  char *q;
 
-  p = parse_exp (args, &addr);
+  p = parse_exp_not_indexed (args, &addr);
   if (addr.X_md)
     ill_op ();
   else
@@ -936,7 +971,7 @@ emit_jr (char prefix ATTRIBUTE_UNUSED, char opcode, const char * args)
   const char *p;
   char *q;
 
-  p = parse_exp (args, &addr);
+  p = parse_exp_not_indexed (args, &addr);
   if (addr.X_md)
     ill_op ();
   else
@@ -956,14 +991,11 @@ emit_jp (char prefix, char opcode, const char * args)
   char *q;
   int rnum;
 
-  p = parse_exp (args, & addr);
+  p = parse_exp_not_indexed (args, & addr);
   if (addr.X_md)
     {
       rnum = addr.X_add_number;
-      if ((addr.X_op == O_register && (rnum & ~R_INDEX) == REG_HL)
-        /* An operand (i[xy]) would have been rewritten to (i[xy]+0)
-            in parse_exp ().  */
-         || (addr.X_op == O_md1 && addr.X_add_symbol == zero))
+      if ((O_register == addr.X_op) && (REG_HL == (rnum & ~R_INDEX)))
        {
          q = frag_more ((rnum & R_INDEX) ? 2 : 1);
          if (rnum & R_INDEX)
@@ -1217,7 +1249,7 @@ emit_ex (char prefix_in ATTRIBUTE_UNUSED,
   const char * p;
   char prefix, opcode;
 
-  p = parse_exp (args, &op);
+  p = parse_exp_not_indexed (args, &op);
   p = skip_space (p);
   if (*p++ != ',')
     {
@@ -1377,7 +1409,7 @@ emit_rst (char prefix ATTRIBUTE_UNUSED, char opcode, const char * args)
   const char *p;
   char *q;
 
-  p = parse_exp (args, &addr);
+  p = parse_exp_not_indexed (args, &addr);
   if (addr.X_op != O_constant)
     {
       error ("rst needs constant address");
index a78b593c5de3ecfe02b4a79491f281147f6cb870..48428a9745e3f2f39514fc23e65413e4ac303b4f 100644 (file)
@@ -1,5 +1,5 @@
 /* this is tc-z80.h
-   Copyright 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright 2005, 2006, 2007, 2012 Free Software Foundation, Inc.
 
    Contributed by Arnold Metselaar <arnold_m@operamail.com>
 
@@ -102,4 +102,8 @@ extern void z80_cons_fix_new (fragS *, int, int, expressionS *);
    P2VAR to the truncated power of two of sizes up to eight bytes.  */
 #define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR) (P2VAR) = 0
 
+/* It does not make any sense to perform arithmetic on the numbers 
+   we use to identify registers.  */
+#define md_register_arithmetic 0
+
 #endif