Fix region length calculations when regions end with .align padding.
[deliverable/binutils-gdb.git] / gas / config / tc-pdp11.c
index a38a0eab67fc864ca31bd22f3df8874a94009412..92023d130a8005a89bbd5d0476eb669bd9a20a2b 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-pdp11.c - pdp11-specific -
-   Copyright 2001 Free Software Foundation, Inc.
+   Copyright 2001, 2002 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -33,6 +33,9 @@ static int set_option PARAMS ((char *arg));
 static int set_cpu_model PARAMS ((char *arg));
 static int set_machine_model PARAMS ((char *arg));
 
+extern int flonum_gen2vax PARAMS ((char format_letter, FLONUM_TYPE * f,
+                                   LITTLENUM_TYPE * words));
+
 #define TRUE 1
 #define FALSE 0
 
@@ -72,25 +75,25 @@ int asm_option[ASM_OPT_NUM];
 
 /* These chars start a comment anywhere in a source file (except inside
    another comment */
-CONST char comment_chars[] = "#/";
+const char comment_chars[] = "#/";
 
 /* These chars only start a comment at the beginning of a line.  */
-CONST char line_comment_chars[] = "#/";
+const char line_comment_chars[] = "#/";
 
-CONST char line_separator_chars[] = ";";
+const char line_separator_chars[] = ";";
 
 /* Chars that can be used to separate mant from exp in floating point nums */
-CONST char EXP_CHARS[] = "eE";
+const char EXP_CHARS[] = "eE";
 
 /* Chars that mean this number is a floating point constant */
 /* as in 0f123.456 */
 /* or    0H1.234E-12 (see exp chars above) */
-CONST char FLT_CHARS[] = "dDfFgGhH";
+const char FLT_CHARS[] = "dDfF";
 
 void pseudo_even (int);
 void pseudo_bss (int);
 
-CONST pseudo_typeS md_pseudo_table[] =
+const pseudo_typeS md_pseudo_table[] =
 {
   { "bss", pseudo_bss, 0 },
   { "even", pseudo_even, 0 },
@@ -163,15 +166,17 @@ md_number_to_chars (con, value, nbytes)
 }
 
 /* Fix up some data or instructions after we find out the value of a symbol
-   that they reference.  */
+   that they reference.  Knows about order of bytes in address.  */
 
-int                            /* Knows about order of bytes in address.  */
-md_apply_fix (fixP, value)
+void
+md_apply_fix3 (fixP, valP, seg)
      fixS *fixP;
-     valueT *value;
+     valueT * valP;
+     segT seg ATTRIBUTE_UNUSED;
 {
   valueT code;
   valueT mask;
+  valueT val = * valP;
   char *buf;
   int shift;
   int size;
@@ -200,13 +205,15 @@ md_apply_fix (fixP, value)
     }
 
   if (fixP->fx_addsy != NULL)
-    *value += symbol_get_bfdsym (fixP->fx_addsy)->section->vma;
+    val += symbol_get_bfdsym (fixP->fx_addsy)->section->vma;
     /* *value += fixP->fx_addsy->bsym->section->vma; */
 
   code &= ~mask;
-  code |= (*value >> shift) & mask;
+  code |= (val >> shift) & mask;
   number_to_chars_littleendian (buf, code, size);
-  return 0;
+
+  if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
+    fixP->fx_done = 1;
 }
 
 long
@@ -294,7 +301,7 @@ parse_reg (char *str, struct pdp11_code *operand)
 }
 
 static char *
-parse_ac (char *str, struct pdp11_code *operand)
+parse_ac5 (char *str, struct pdp11_code *operand)
 {
   str = skip_whitespace (str);
   if (strncmp (str, "fr", 2) == 0 ||
@@ -306,6 +313,7 @@ parse_ac (char *str, struct pdp11_code *operand)
       switch (*str)
        {
        case '0': case '1': case '2': case '3':
+        case '4': case '5':
          operand->code = *str - '0';
          str++;
          break;
@@ -323,6 +331,19 @@ parse_ac (char *str, struct pdp11_code *operand)
   return str;
 }
 
+static char *
+parse_ac (char *str, struct pdp11_code *operand)
+{
+  str = parse_ac5 (str, operand);
+  if (!operand->error && operand->code > 3)
+    {
+         operand->error = "Bad register name";
+         return str - 3;
+    }
+
+  return str;
+}
+
 static char *
 parse_expression (char *str, struct pdp11_code *operand)
 {
@@ -344,6 +365,15 @@ parse_expression (char *str, struct pdp11_code *operand)
 
   operand->reloc.pc_rel = 0;
 
+#if 0
+  /* FIXME: what follows is broken badly.  You can't deal with differences
+     in radix conventions this way, because of symbolic constants, constant
+     expressions made up of pieces of differing radix, etc.  The only
+     choices are to change ../expr.c to know about pdp11 conventions, or
+     to accept the fact that gas will use consistent conventions that differ
+     from those of traditional pdp11 assemblers.  For now, I've
+     chosen the latter.   paul koning, 12/23/2001
+  */
   if (operand->reloc.exp.X_op == O_constant)
     {
       if (*str == '.')
@@ -358,13 +388,15 @@ parse_expression (char *str, struct pdp11_code *operand)
          operand->reloc.exp.X_add_number = strtol (buf, &end, 8);
        }
     }
-
+#endif
   return str;
 }
 
 static char *
 parse_op_no_deferred (char *str, struct pdp11_code *operand)
 {
+  LITTLENUM_TYPE literal_float[2];
+
   str = skip_whitespace (str);
 
   switch (*str)
@@ -408,6 +440,19 @@ parse_op_no_deferred (char *str, struct pdp11_code *operand)
          operand->reloc.type = BFD_RELOC_16;
          operand->reloc.pc_rel = 0;
          break;
+        case O_big:
+          if (operand->reloc.exp.X_add_number > 0)
+            {
+              operand->error = "Error in expression";
+              break;
+            }
+          /* it's a floating literal...  */
+          know (operand->reloc.exp.X_add_number < 0);
+          flonum_gen2vax ('f', &generic_floating_point_number, literal_float);
+          operand->word = literal_float[0];
+          if (literal_float[1] != 0)
+            as_warn (_("Low order bits truncated in immediate float operand"));
+          break;
        default:
          operand->error = "Error in expression";
          break;
@@ -500,13 +545,9 @@ parse_op_no_deferred (char *str, struct pdp11_code *operand)
 }
 
 static char *
-parse_op (char *str, struct pdp11_code *operand)
+parse_op_noreg (char *str, struct pdp11_code *operand)
 {
   str = skip_whitespace (str);
-
-  str = parse_reg (str, operand);
-  if (!operand->error)
-    return str;
   operand->error = NULL;
 
   if (*str == '@' || *str == '*')
@@ -522,6 +563,46 @@ parse_op (char *str, struct pdp11_code *operand)
   return str;
 }
 
+static char *
+parse_op (char *str, struct pdp11_code *operand)
+{
+  str = skip_whitespace (str);
+
+  str = parse_reg (str, operand);
+  if (!operand->error)
+    return str;
+
+  operand->error = NULL;
+  parse_ac5 (str, operand);
+  if (!operand->error)
+    {
+      operand->error = "Float AC not legal as integer operand";
+      return str;
+    }
+
+  return parse_op_noreg (str, operand);
+}
+
+static char *
+parse_fop (char *str, struct pdp11_code *operand)
+{
+  str = skip_whitespace (str);
+
+  str = parse_ac5 (str, operand);
+  if (!operand->error)
+    return str;
+
+  operand->error = NULL;
+  parse_reg (str, operand);
+  if (!operand->error)
+    {
+      operand->error = "General register not legal as float operand";
+      return str;
+    }
+
+  return parse_op_noreg (str, operand);
+}
+
 static char *
 parse_separator (char *str, int *error)
 {
@@ -536,7 +617,7 @@ void
 md_assemble (instruction_string)
      char *instruction_string;
 {
-  CONST struct pdp11_opcode *op;
+  const struct pdp11_opcode *op;
   struct pdp11_code insn, op1, op2;
   int error;
   int size;
@@ -581,7 +662,7 @@ md_assemble (instruction_string)
                       &insn.reloc.exp, insn.reloc.pc_rel, insn.reloc.type);
       }
 #else
-      as_warn ("Unknown instruction");
+      as_bad (_("Unknown instruction '%s'"), str);
 #endif
 
       return;
@@ -623,31 +704,36 @@ md_assemble (instruction_string)
       str = parse_expression (str, &op1);
       if (op1.error)
        break;
+      if (op1.reloc.exp.X_op != O_constant || op1.reloc.type != BFD_RELOC_NONE)
+       {
+         op1.error = "operand is not an absolute constant";
+         break;
+       }
       switch (op->type)
        {
        case PDP11_OPCODE_IMM3:
-         if (op1.code & ~7)
+         if (op1.reloc.exp.X_add_number & ~7)
            {
              op1.error = "3-bit immediate out of range";
              break;
            }
          break;
        case PDP11_OPCODE_IMM6:
-         if (op1.code & ~0x3f)
+         if (op1.reloc.exp.X_add_number & ~0x3f)
            {
              op1.error = "6-bit immediate out of range";
              break;
            }
          break;
        case PDP11_OPCODE_IMM8:
-         if (op1.code & ~0xff)
+         if (op1.reloc.exp.X_add_number & ~0xff)
            {
              op1.error = "8-bit immediate out of range";
              break;
            }
          break;
        }
-      insn.code |= op1.code;
+      insn.code |= op1.reloc.exp.X_add_number;
       break;
 
     case PDP11_OPCODE_DISPL:
@@ -689,6 +775,15 @@ md_assemble (instruction_string)
        size += 2;
       break;
 
+    case PDP11_OPCODE_FOP:
+      str = parse_fop (str, &op1);
+      if (op1.error)
+       break;
+      insn.code |= op1.code;
+      if (op1.additional)
+       size += 2;
+      break;
+
     case PDP11_OPCODE_REG_OP:
       str = parse_reg (str, &op2);
       if (op2.error)
@@ -727,6 +822,44 @@ md_assemble (instruction_string)
       insn.code |= op2.code << 6;
       break;
 
+    case PDP11_OPCODE_AC_FOP:
+      str = parse_ac (str, &op2);
+      if (op2.error)
+       break;
+      insn.code |= op2.code << 6;
+      str = parse_separator (str, &error);
+      if (error)
+       {
+         op1.error = "Missing ','";
+         break;
+       }
+      str = parse_fop (str, &op1);
+      if (op1.error)
+       break;
+      insn.code |= op1.code;
+      if (op1.additional)
+       size += 2;
+      break;
+
+    case PDP11_OPCODE_FOP_AC:
+      str = parse_fop (str, &op1);
+      if (op1.error)
+       break;
+      insn.code |= op1.code;
+      if (op1.additional)
+       size += 2;
+      str = parse_separator (str, &error);
+      if (error)
+       {
+         op1.error = "Missing ','";
+         break;
+       }
+      str = parse_ac (str, &op2);
+      if (op2.error)
+       break;
+      insn.code |= op2.code << 6;
+      break;
+
     case PDP11_OPCODE_AC_OP:
       str = parse_ac (str, &op2);
       if (op2.error)
@@ -746,6 +879,25 @@ md_assemble (instruction_string)
        size += 2;
       break;
 
+    case PDP11_OPCODE_OP_AC:
+      str = parse_op (str, &op1);
+      if (op1.error)
+       break;
+      insn.code |= op1.code;
+      if (op1.additional)
+       size += 2;
+      str = parse_separator (str, &error);
+      if (error)
+       {
+         op1.error = "Missing ','";
+         break;
+       }
+      str = parse_ac (str, &op2);
+      if (op2.error)
+       break;
+      insn.code |= op2.code << 6;
+      break;
+
     case PDP11_OPCODE_OP_OP:
       str = parse_op (str, &op1);
       if (op1.error)
@@ -867,8 +1019,8 @@ md_convert_frag (headers, seg, fragP)
 {
 }
 
-CONST int md_short_jump_size = 2;
-CONST int md_long_jump_size = 4;
+const int md_short_jump_size = 2;
+const int md_long_jump_size = 4;
 
 void
 md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
@@ -1137,7 +1289,7 @@ set_machine_model (arg)
     return 0;
 }
 
-CONST char *md_shortopts = "m:";
+const char *md_shortopts = "m:";
 
 struct option md_longopts[] =
 {
@@ -1212,9 +1364,9 @@ enum
 
 struct
 {
-  CONST char *pattern;
+  const char *pattern;
   int opt;
-  CONST char *description;
+  const char *description;
 } options;
 
 static struct options extension_opts[] =
@@ -1281,7 +1433,7 @@ static struct options model_opts[] =
 
 struct
 {
-  CONST char *title;
+  const char *title;
   struct options *opts;
   int num;
 } all_opts[] =
@@ -1356,7 +1508,7 @@ parse_match (char *arg, char *pattern)
 int
 fprint_opt (stream, pattern)
      FILE *stream;
-     CONST char *pattern;
+     const char *pattern;
 {
   int n;
 
@@ -1553,7 +1705,7 @@ tc_gen_reloc (section, fixp)
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
-  /* this is taken account for in md_apply_fix() */
+  /* This is taken account for in md_apply_fix3().  */
   reloc->addend = -symbol_get_bfdsym (fixp->fx_addsy)->section->vma;
 
   switch (fixp->fx_r_type)
This page took 0.030819 seconds and 4 git commands to generate.