pdp11 target patches: gas

Paul Koning pkoning@equallogic.com
Mon Mar 4 13:20:00 GMT 2002


This corrects a number of problems in GAS for pdp11, primarily to
correctly handle references to the floating point registers in FP ops.

2002-03-04  Paul Koning  <pkoning@equallogic.com>

	* tc-pdp11.c  Use VAX float format support for PDP-11 target.
	(parse_ac5) new function for parsing float regs in float operand.
	(parse_expression) remove attempt to make literals be octal.
	(parse_op_no_deferred) support float literals.
	(parse_op) reject attempts to refer to float regs.
	(parse_fop) new function, like parse_op but for float operand.
	(md_assemble) add cases to parse float operands.  Also fix 
	IMM3, IMM6, IMM8 cases to pick up the operand from the right spot.

Index: gas/config/tc-pdp11.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-pdp11.c,v
retrieving revision 1.6
diff -u -b -B -r1.6 tc-pdp11.c
--- tc-pdp11.c	2001/11/15 21:28:58	1.6
+++ tc-pdp11.c	2002/03/04 15:46:53
@@ -33,6 +33,9 @@
 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
 
@@ -85,7 +88,7 @@
 /* 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);
@@ -298,7 +301,7 @@
 }
 
 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 ||
@@ -310,6 +313,7 @@
       switch (*str)
 	{
 	case '0': case '1': case '2': case '3':
+        case '4': case '5':
 	  operand->code = *str - '0';
 	  str++;
 	  break;
@@ -328,6 +332,19 @@
 }
 
 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)
 {
   char *save_input_line_pointer;
@@ -348,6 +365,15 @@
 
   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 == '.')
@@ -362,13 +388,15 @@
 	  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)
@@ -412,6 +440,19 @@
 	  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;
@@ -504,13 +545,9 @@
 }
 
 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 == '*')
@@ -527,6 +564,46 @@
 }
 
 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)
 {
   str = skip_whitespace (str);
@@ -585,7 +662,7 @@
 		       &insn.reloc.exp, insn.reloc.pc_rel, insn.reloc.type);
       }
 #else
-      as_warn ("Unknown instruction");
+      as_bad (_("Unknown instruction '%s'"), str);
 #endif
 
       return;
@@ -627,31 +704,36 @@
       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:
@@ -693,6 +775,15 @@
 	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)
@@ -731,6 +822,44 @@
       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)
@@ -748,6 +877,25 @@
       insn.code |= op1.code;
       if (op1.additional)
 	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:



More information about the Binutils mailing list