/* tc-pdp11.c - pdp11-specific -
- Copyright (C) 2001 Free Software Foundation, Inc.
+ Copyright 2001, 2002 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
*/
#include "as.h"
+#include "safe-ctype.h"
#include "opcode/pdp11.h"
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
/* 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 },
}
/* 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;
}
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
return str;
}
-static char
-mklower (char c)
-{
- if (isupper (c))
- return tolower (c);
- return c;
-}
-
static char *
parse_reg (char *str, struct pdp11_code *operand)
{
str = skip_whitespace (str);
- if (mklower (*str) == 'r')
+ if (TOLOWER (*str) == 'r')
{
str++;
switch (*str)
}
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 ||
switch (*str)
{
case '0': case '1': case '2': case '3':
+ case '4': case '5':
operand->code = *str - '0';
str++;
break;
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)
{
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 == '.')
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)
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;
}
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 == '*')
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)
{
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;
&insn.reloc.exp, insn.reloc.pc_rel, insn.reloc.type);
}
#else
- as_warn ("Unknown instruction");
+ as_bad (_("Unknown instruction '%s'"), str);
#endif
return;
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:
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)
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)
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)
{
}
-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)
return 0;
}
-CONST char *md_shortopts = "m:";
+const char *md_shortopts = "m:";
struct option md_longopts[] =
{
{ NULL, no_argument, NULL, 0 }
};
-size_t md_longopts_size = sizeof(md_longopts);
+size_t md_longopts_size = sizeof (md_longopts);
/*
* md_parse_option
struct
{
- CONST char *pattern;
+ const char *pattern;
int opt;
- CONST char *description;
+ const char *description;
} options;
static struct options extension_opts[] =
struct
{
- CONST char *title;
+ const char *title;
struct options *opts;
int num;
} all_opts[] =
int
fprint_opt (stream, pattern)
FILE *stream;
- CONST char *pattern;
+ const char *pattern;
{
int n;
*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)