aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-pdp11.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2002-03-05 03:10:34 +0000
committerAlan Modra <amodra@gmail.com>2002-03-05 03:10:34 +0000
commitcd3cde86315f5c46e5e828fee1fdda35fd2841f8 (patch)
tree03c4021974c48d228bf8f6af99fd19c8f8ce6198 /gas/config/tc-pdp11.c
parent84dd1cffbfb45e0c053a481bc94ddebe1adb3c04 (diff)
downloadbinutils-cd3cde86315f5c46e5e828fee1fdda35fd2841f8.zip
binutils-cd3cde86315f5c46e5e828fee1fdda35fd2841f8.tar.gz
binutils-cd3cde86315f5c46e5e828fee1fdda35fd2841f8.tar.bz2
* 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.
Diffstat (limited to 'gas/config/tc-pdp11.c')
-rw-r--r--gas/config/tc-pdp11.c176
1 files changed, 162 insertions, 14 deletions
diff --git a/gas/config/tc-pdp11.c b/gas/config/tc-pdp11.c
index 4577d79..0b59554 100644
--- a/gas/config/tc-pdp11.c
+++ b/gas/config/tc-pdp11.c
@@ -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
@@ -85,7 +88,7 @@ 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);
@@ -298,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 ||
@@ -310,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;
@@ -328,6 +332,19 @@ parse_ac (char *str, struct pdp11_code *operand)
}
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 @@ 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 == '.')
@@ -362,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)
@@ -412,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;
@@ -504,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 == '*')
@@ -527,6 +564,46 @@ parse_op (char *str, struct pdp11_code *operand)
}
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 @@ 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;
@@ -627,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:
@@ -693,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)
@@ -731,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)
@@ -750,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)