change the type of some fields to bfd_reloc_code_real_type
[deliverable/binutils-gdb.git] / gas / config / tc-z80.c
index 28f69b1d54bac6fc6a2c938b3024e2aaae755800..dcc74f6ed58a60c310551ebd27926fe143fe87bc 100644 (file)
@@ -1,12 +1,12 @@
 /* tc-z80.c -- Assemble code for the Zilog Z80 and ASCII R800
-   Copyright 2005 Free Software Foundation, Inc.
+   Copyright (C) 2005-2016 Free Software Foundation, Inc.
    Contributed by Arnold Metselaar <arnold_m@operamail.com>
 
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
    02110-1301, USA.  */
 
 #include "as.h"
-#include "listing.h"
-#include "bfd.h"
 #include "safe-ctype.h"
 #include "subsegs.h"
-#include "symbols.h"
-#include "libiberty.h"
 
 /* Exported constants.  */
 const char comment_chars[] = ";\0";
@@ -85,7 +81,7 @@ static int ins_err = INS_R800;
 static int ins_used = INS_Z80;
 
 int
-md_parse_option (int c, char* arg ATTRIBUTE_UNUSED)
+md_parse_option (int c, const char* arg ATTRIBUTE_UNUSED)
 {
   switch (c)
     {
@@ -165,14 +161,95 @@ Default: -z80 -ignore-undocument-instructions -warn-unportable-instructions.\n")
 
 static symbolS * zero;
 
+struct reg_entry
+{
+  const 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";
+  input_line_pointer = (char *) "0";
   nul.X_md=0;
   expression (& nul);
   input_line_pointer = p;
@@ -210,16 +287,6 @@ z80_md_end (void)
   bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach_type);
 }
 
-/* Port specific features.  */
-const pseudo_typeS md_pseudo_table[] =
-{
-  { "defs",  s_space, 1}, /* Synonym for ds on some assemblers.  */
-  { "ds",    s_space, 1}, /* Fill with bytes rather than words.  */
-  { "psect", obj_coff_section, 0}, /* TODO: Translate attributes.  */
-  { "set", 0, 0},              /* Real instruction on z80.  */
-  { NULL, 0, 0 }
-} ;
-
 static const char *
 skip_space (const char *s)
 {
@@ -262,47 +329,49 @@ z80_start_line_hook (void)
          break;
        }
     }
-  /* Check for <label>[:] (EQU|DEFL) <value>.  */
+  /* Check for <label>[:] [.](EQU|DEFL) <value>.  */
   if (is_name_beginner (*input_line_pointer))
     {
+      char *name;
       char c, *rest, *line_start;
       int len;
 
       line_start = input_line_pointer;
-      LISTING_NEWLINE ();
       if (ignore_input ())
        return 0;
 
-      c = get_symbol_end ();
+      c = get_symbol_name (&name);
       rest = input_line_pointer + 1;
 
       if (*rest == ':')
        ++rest;
       if (*rest == ' ' || *rest == '\t')
        ++rest;
+      if (*rest == '.')
+       ++rest;
       if (strncasecmp (rest, "EQU", 3) == 0)
        len = 3;
       else if (strncasecmp (rest, "DEFL", 4) == 0)
        len = 4;
       else
        len = 0;
-      if (len && (rest[len] == ' ' || rest[len] == '\t'))
+      if (len && (!ISALPHA(rest[len]) ) )
        {
          /* Handle assignment here.  */
-         input_line_pointer = rest + len;
          if (line_start[-1] == '\n')
-           bump_line_counters ();
-         /* Most Z80 assemblers require the first definition of a
-             label to use "EQU" and redefinitions to have "DEFL".
-             That does not fit the way GNU as deals with labels, so
-             GNU as is more permissive.  */
-         equals (line_start, TRUE);
+           {
+             bump_line_counters ();
+             LISTING_NEWLINE ();
+           }
+         input_line_pointer = rest + len - 1;
+         /* Allow redefining with "DEFL" (len == 4), but not with "EQU".  */
+         equals (name, len == 4);
          return 1;
        }
       else
        {
          /* Restore line and pointer.  */
-         *input_line_pointer = c;
+         (void) restore_line_pointer (c);
          input_line_pointer = line_start;
        }
     }
@@ -315,7 +384,7 @@ md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
   return NULL;
 }
 
-char *
+const char *
 md_atof (int type ATTRIBUTE_UNUSED, char *litP ATTRIBUTE_UNUSED,
         int *sizeP ATTRIBUTE_UNUSED)
 {
@@ -339,9 +408,9 @@ typedef const char * (asfunc)(char, char, const char*);
 
 typedef struct _table_t
 {
-  char* name;
-  char prefix;
-  char opcode;
+  const char* name;
+  unsigned char prefix;
+  unsigned char opcode;
   asfunc * fp;
 } table_t;
 
@@ -356,63 +425,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;
@@ -420,7 +435,7 @@ static char err_flag;
 static void
 error (const char * message)
 {
-  as_bad (message);
+  as_bad ("%s", message);
   err_flag = 1;
 }
 
@@ -447,13 +462,13 @@ wrong_mach (int ins_type)
       p = "instruction only works R800";
       break;
     default:
-      p = 0; /* Not reachables.  */
+      p = 0; /* Not reachable.  */
     }
 
   if (ins_type & ins_err)
     error (_(p));
   else
-    as_warn (_(p));
+    as_warn ("%s", _(p));
 }
 
 static void
@@ -464,70 +479,6 @@ check_mach (int ins_type)
   ins_used |= ins_type;
 }
 
-/* This function tries to subtract two symbols, the generic code does
-   that too, but this function tries harder.
-   The behaviour of this function is not altered by extra
-   fragmentations caused by the code to produce listings.  */
-int
-z80_optimize_expr (expressionS *resultP, operatorT left_op,
-                  expressionS *right)
-{
-  int res, swap, som;
-  fragS *lfrag, *rfrag, *cur;
-
-  res = 0;
-  if (left_op == O_subtract
-      && right->X_op == O_symbol
-      && resultP->X_op == O_symbol)
-    {
-      lfrag = symbol_get_frag (resultP->X_add_symbol);
-      rfrag = symbol_get_frag (right->X_add_symbol);
-
-      if (S_GET_SEGMENT (right->X_add_symbol) !=  undefined_section
-         && (S_GET_SEGMENT (right->X_add_symbol)
-             == S_GET_SEGMENT (resultP->X_add_symbol)))
-       {
-         for (swap = 0; (res == 0) && (swap < 2); ++swap)
-           {
-             if (swap)
-               {
-                 cur = lfrag;
-                 lfrag = rfrag;
-                 rfrag = cur;
-               }
-             else
-               cur = rfrag;
-
-             /* Now som == cur->fr_address - rfrag->address, except
-                the latter may not have been computed yet.  */
-             for (som = 0; cur && cur != lfrag; cur = cur->fr_next)
-               {
-                 if (cur->fr_type == rs_fill) /* Is the size fized?  */
-                   som += cur->fr_fix+cur->fr_offset*cur->fr_var;
-                 else
-                   break;
-               }
-
-             if  (cur == lfrag)
-               {
-                 resultP->X_add_number -= right->X_add_number;
-                 resultP->X_add_number
-                   += (S_GET_VALUE (resultP->X_add_symbol)
-                       - S_GET_VALUE (right->X_add_symbol));
-                 som -= lfrag->fr_address - rfrag->fr_address;
-                 /* Correct the result if the fr_address
-                    fields are not computed yet.  */
-                 resultP->X_add_number += (swap ? -som : som);
-                 resultP->X_op = O_constant;
-                 resultP->X_add_symbol = 0;
-                 res = 1;
-               }
-           }
-       }
-    }
-  return res;
-}
-
 /* Check whether an expression is indirect.  */
 static int
 is_indir (const char *s)
@@ -573,88 +524,93 @@ 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;
 
   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 ;
+  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;
+    default:
+      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;
+    default:
+      break;
+    }
+  return res;
 }
 
 /* Condition codes, including some synonyms provided by HiTech zas.  */
@@ -728,16 +684,43 @@ emit_insn (char prefix, char opcode, const char * args)
   return args;
 }
 
+void z80_cons_fix_new (fragS *frag_p, int offset, int nbytes, expressionS *exp)
+{
+  bfd_reloc_code_real_type r[4] =
+    {
+      BFD_RELOC_8,
+      BFD_RELOC_16,
+      BFD_RELOC_24,
+      BFD_RELOC_32
+    };
+
+  if (nbytes < 1 || nbytes > 4)
+    {
+      as_bad (_("unsupported BFD relocation size %u"), nbytes);
+    }
+  else
+    {
+      fix_new_exp (frag_p, offset, nbytes, exp, 0, r[nbytes-1]);
+    }
+}
+
 static void
 emit_byte (expressionS * val, bfd_reloc_code_real_type r_type)
 {
   char *p;
   int lo, hi;
-  fixS * fixp;
 
   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"));
+    }
+  else if (val->X_op == O_constant)
     {
       lo = -128;
       hi = (BFD_RELOC_8 == r_type) ? 255 : 127;
@@ -752,8 +735,8 @@ emit_byte (expressionS * val, bfd_reloc_code_real_type r_type)
     }
   else
     {
-      fixp = fix_new_exp (frag_now, p - frag_now->fr_literal, 1, val,
-                         (r_type == BFD_RELOC_8_PCREL) ? TRUE : FALSE, r_type);
+      fix_new_exp (frag_now, p - frag_now->fr_literal, 1, val,
+                  (r_type == BFD_RELOC_8_PCREL) ? TRUE : FALSE, r_type);
       /* FIXME : Process constant offsets immediately.  */
     }
 }
@@ -765,7 +748,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
     {
@@ -822,8 +807,12 @@ emit_mx (char prefix, char opcode, int shift, expressionS * arg)
       q = frag_more (2);
       *q++ = (rnum & R_IX) ? 0xDD : 0xFD;
       *q = (prefix) ? prefix : (opcode + (6 << shift));
-      emit_byte (symbol_get_value_expression (arg->X_add_symbol),
-                BFD_RELOC_Z80_DISP8);
+      {
+       expressionS offset = *arg;
+       offset.X_op = O_symbol;
+       offset.X_add_number = 0;
+       emit_byte (&offset, BFD_RELOC_Z80_DISP8);
+      }
       if (prefix)
        {
          q = frag_more (1);
@@ -937,7 +926,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
@@ -985,7 +974,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
@@ -1005,14 +994,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)
@@ -1115,7 +1101,7 @@ emit_adc (char prefix, char opcode, const char * args)
   p = parse_exp (args, &term);
   if (*p++ != ',')
     {
-      error (_("bad intruction syntax"));
+      error (_("bad instruction syntax"));
       return p;
     }
 
@@ -1158,7 +1144,7 @@ emit_add (char prefix, char opcode, const char * args)
   p = parse_exp (args, &term);
   if (*p++ != ',')
     {
-      error (_("bad intruction syntax"));
+      error (_("bad instruction syntax"));
       return p;
     }
 
@@ -1202,7 +1188,7 @@ emit_bit (char prefix, char opcode, const char * args)
 
   p = parse_exp (args, &b);
   if (*p++ != ',')
-    error (_("bad intruction syntax"));
+    error (_("bad instruction syntax"));
 
   bn = b.X_add_number;
   if ((!b.X_md)
@@ -1266,7 +1252,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++ != ',')
     {
@@ -1322,7 +1308,7 @@ emit_in (char prefix ATTRIBUTE_UNUSED, char opcode ATTRIBUTE_UNUSED,
   p = parse_exp (args, &reg);
   if (*p++ != ',')
     {
-      error (_("bad intruction syntax"));
+      error (_("bad instruction syntax"));
       return p;
     }
 
@@ -1376,7 +1362,7 @@ emit_out (char prefix ATTRIBUTE_UNUSED, char opcode ATTRIBUTE_UNUSED,
   p = parse_exp (args, & port);
   if (*p++ != ',')
     {
-      error (_("bad intruction syntax"));
+      error (_("bad instruction syntax"));
       return p;
     }
   p = parse_exp (p, &reg);
@@ -1426,7 +1412,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");
@@ -1519,7 +1505,7 @@ emit_ldreg (int dest, expressionS * src)
          && (src->X_add_number == REG_BC || src->X_add_number == REG_DE))
        {
          q = frag_more (1);
-         *q = 0x0A + ((dest & 1) << 4);
+         *q = 0x0A + ((src->X_add_number & 1) << 4);
          break;
        }
 
@@ -1599,7 +1585,7 @@ emit_ldreg (int dest, expressionS * src)
       /* Fall through.  */
     case REG_BC:
     case REG_DE:
-      if (src->X_op == O_register || src->X_op != O_md1)
+      if (src->X_op == O_register || src->X_op == O_md1)
        ill_op ();
       q = frag_more (src->X_md ? 2 : 1);
       if (src->X_md)
@@ -1645,14 +1631,19 @@ emit_ld (char prefix_in ATTRIBUTE_UNUSED, char opcode_in ATTRIBUTE_UNUSED,
 
   p = parse_exp (args, &dst);
   if (*p++ != ',')
-    error (_("bad intruction syntax"));
+    error (_("bad instruction syntax"));
   p = parse_exp (p, &src);
 
   switch (dst.X_op)
     {
     case O_md1:
-      emit_ldxhl ((dst.X_add_number & R_IX) ? 0xDD : 0xFD, 0x70,
-                 &src, symbol_get_value_expression (dst.X_add_symbol));
+      {
+        expressionS dst_offset = dst;
+       dst_offset.X_op = O_symbol;
+       dst_offset.X_add_number = 0;
+       emit_ldxhl ((dst.X_add_number & R_IX) ? 0xDD : 0xFD, 0x70,
+                   &src, &dst_offset);
+      }
       break;
 
     case O_register:
@@ -1712,38 +1703,33 @@ emit_ld (char prefix_in ATTRIBUTE_UNUSED, char opcode_in ATTRIBUTE_UNUSED,
   return p;
 }
 
-static const char *
-emit_data (char prefix ATTRIBUTE_UNUSED, char opcode, const char * args)
+static void
+emit_data (int size ATTRIBUTE_UNUSED)
 {
   const char *p, *q;
   char *u, quote;
   int cnt;
   expressionS exp;
 
-  p = skip_space (args);
-  if (!*p)
-    error (_("missing operand"));
+  if (is_it_end_of_statement ())
+    {
+      demand_empty_rest_of_line ();
+      return;
+    }
+  p = skip_space (input_line_pointer);
 
-  while (*p)
+  do
     {
       if (*p == '\"' || *p == '\'')
        {
-         if (opcode == 1)
-           {
-             for (quote = *p, q = ++p, cnt = 0; *p && quote != *p; ++p, ++cnt)
-               ;
-             u = frag_more (cnt);
-             memcpy (u, q, cnt);
-             if (!*p)
-               as_warn (_("unterminated string"));
-             else
-               p = skip_space (p+1);
-           }
-         else
-           {
-             ill_op ();
-             break;
-           }
+           for (quote = *p, q = ++p, cnt = 0; *p && quote != *p; ++p, ++cnt)
+             ;
+           u = frag_more (cnt);
+           memcpy (u, q, cnt);
+           if (!*p)
+             as_warn (_("unterminated string"));
+           else
+             p = skip_space (p+1);
        }
       else
        {
@@ -1755,21 +1741,12 @@ emit_data (char prefix ATTRIBUTE_UNUSED, char opcode, const char * args)
            }
          if (exp.X_md)
            as_warn (_("parentheses ignored"));
-         if (opcode == 1)
-           emit_byte (&exp, BFD_RELOC_8);
-         else
-           emit_word (&exp);
+         emit_byte (&exp, BFD_RELOC_8);
          p = skip_space (p);
        }
-      if (*p)
-       {
-         if (*p != ',')
-           as_warn (_("missing ','"));
-         else
-           ++p;
-       }
     }
-  return p;
+  while (*p++ == ',') ;
+  input_line_pointer = (char *)(p-1);
 }
 
 static const char *
@@ -1838,6 +1815,24 @@ emit_muluw (char prefix ATTRIBUTE_UNUSED, char opcode, const char * args)
   return p;
 }
 
+/* Port specific pseudo ops.  */
+const pseudo_typeS md_pseudo_table[] =
+{
+  { "db" , emit_data, 1},
+  { "d24", cons, 3},
+  { "d32", cons, 4},
+  { "def24", cons, 3},
+  { "def32", cons, 4},
+  { "defb", emit_data, 1},
+  { "defs", s_space, 1}, /* Synonym for ds on some assemblers.  */
+  { "defw", cons, 2},
+  { "ds",   s_space, 1}, /* Fill with bytes rather than words.  */
+  { "dw", cons, 2},
+  { "psect", obj_coff_section, 0}, /* TODO: Translate attributes.  */
+  { "set", 0, 0},              /* Real instruction on z80.  */
+  { NULL, 0, 0 }
+} ;
+
 static table_t instab[] =
 {
   { "adc",  0x88, 0x4A, emit_adc },
@@ -1853,13 +1848,9 @@ static table_t instab[] =
   { "cpir", 0xED, 0xB1, emit_insn },
   { "cpl",  0x00, 0x2F, emit_insn },
   { "daa",  0x00, 0x27, emit_insn },
-  { "db",   0x00, 0x01, emit_data },
   { "dec",  0x0B, 0x05, emit_incdec },
-  { "defb", 0x00, 0x01, emit_data },
-  { "defw", 0x00, 0x02, emit_data },
   { "di",   0x00, 0xF3, emit_insn },
   { "djnz", 0x00, 0x10, emit_jr },
-  { "dw",   0x00, 0x02, emit_data },
   { "ei",   0x00, 0xFB, emit_insn },
   { "ex",   0x00, 0x00, emit_ex},
   { "exx",  0x00, 0xD9, emit_insn },
@@ -1931,25 +1922,32 @@ md_assemble (char* str)
   for (i = 0; (i < BUFLEN) && (ISALPHA (*p));)
     buf[i++] = TOLOWER (*p++);
 
-  if ((i == BUFLEN)
-      || ((*p) && (!ISSPACE (*p))))
-    as_bad (_("illegal instruction '%s'"), buf);
-
-  buf[i] = 0;
-  p = skip_space (p);
-  key = buf;
-
-  insp = bsearch (&key, instab, ARRAY_SIZE (instab),
-                 sizeof (instab[0]), key_cmp);
-  if (!insp)
-    as_bad (_("illegal instruction '%s'"), buf);
+  if (i == BUFLEN)
+    {
+      buf[BUFLEN-3] = buf[BUFLEN-2] = '.'; /* Mark opcode as abbreviated.  */
+      buf[BUFLEN-1] = 0;
+      as_bad (_("Unknown instruction '%s'"), buf);
+    }
+  else if ((*p) && (!ISSPACE (*p)))
+    as_bad (_("syntax error"));
   else
     {
-      p = insp->fp (insp->prefix, insp->opcode, p);
+      buf[i] = 0;
       p = skip_space (p);
-      if ((!err_flag) && *p)
-       as_bad (_("junk at end of line, first unrecognized character is `%c'"),
-               *p);
+      key = buf;
+
+      insp = bsearch (&key, instab, ARRAY_SIZE (instab),
+                   sizeof (instab[0]), key_cmp);
+      if (!insp)
+       as_bad (_("Unknown instruction '%s'"), buf);
+      else
+       {
+         p = insp->fp (insp->prefix, insp->opcode, p);
+         p = skip_space (p);
+       if ((!err_flag) && *p)
+         as_bad (_("junk at end of line, first unrecognized character is `%c'"),
+                 *p);
+       }
     }
   input_line_pointer = old_ptr;
 }
@@ -1958,7 +1956,7 @@ void
 md_apply_fix (fixS * fixP, valueT* valP, segT seg ATTRIBUTE_UNUSED)
 {
   long val = * (long *) valP;
-  char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+  char *p_lit = fixP->fx_where + fixP->fx_frag->fr_literal;
 
   switch (fixP->fx_r_type)
     {
@@ -1974,7 +1972,7 @@ md_apply_fix (fixS * fixP, valueT* valP, segT seg ATTRIBUTE_UNUSED)
          if (!fixP->fx_no_overflow)
             as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("relative jump out of range"));
-         *buf++ = val;
+         *p_lit++ = val;
           fixP->fx_done = 1;
         }
       break;
@@ -1991,7 +1989,7 @@ md_apply_fix (fixS * fixP, valueT* valP, segT seg ATTRIBUTE_UNUSED)
          if (!fixP->fx_no_overflow)
             as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("index offset  out of range"));
-         *buf++ = val;
+         *p_lit++ = val;
           fixP->fx_done = 1;
         }
       break;
@@ -1999,23 +1997,34 @@ md_apply_fix (fixS * fixP, valueT* valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_8:
       if (val > 255 || val < -128)
        as_warn_where (fixP->fx_file, fixP->fx_line, _("overflow"));
-      *buf++ = val;
+      *p_lit++ = val;
+      fixP->fx_no_overflow = 1;
       if (fixP->fx_addsy == NULL)
        fixP->fx_done = 1;
       break;
 
     case BFD_RELOC_16:
-      *buf++ = val;
-      *buf++ = (val >> 8);
+      *p_lit++ = val;
+      *p_lit++ = (val >> 8);
+      fixP->fx_no_overflow = 1;
       if (fixP->fx_addsy == NULL)
        fixP->fx_done = 1;
       break;
 
-    case BFD_RELOC_32: /* .Long may produce this.  */
-      *buf++ = val;
-      *buf++ = (val >> 8);
-      *buf++ = (val >> 16);
-      *buf++ = (val >> 24);
+    case BFD_RELOC_24: /* Def24 may produce this.  */
+      *p_lit++ = val;
+      *p_lit++ = (val >> 8);
+      *p_lit++ = (val >> 16);
+      fixP->fx_no_overflow = 1;
+      if (fixP->fx_addsy == NULL)
+       fixP->fx_done = 1;
+      break;
+
+    case BFD_RELOC_32: /* Def32 and .long may produce this.  */
+      *p_lit++ = val;
+      *p_lit++ = (val >> 8);
+      *p_lit++ = (val >> 16);
+      *p_lit++ = (val >> 24);
       if (fixP->fx_addsy == NULL)
        fixP->fx_done = 1;
       break;
@@ -2049,8 +2058,8 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED , fixS *fixp)
       return NULL;
     }
 
-  reloc               = xmalloc (sizeof (arelent));
-  reloc->sym_ptr_ptr  = xmalloc (sizeof (asymbol *));
+  reloc               = XNEW (arelent);
+  reloc->sym_ptr_ptr  = XNEW (asymbol *);
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   reloc->address      = fixp->fx_frag->fr_address + fixp->fx_where;
   reloc->howto        = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
@@ -2058,4 +2067,3 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED , fixS *fixp)
 
   return reloc;
 }
-
This page took 0.035497 seconds and 4 git commands to generate.