/* tc-m68k.c -- Assemble for the m68k family
- Copyright (C) 1987, 91, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 91, 92, 93, 94, 95, 96, 1997
+ Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
02111-1307, USA. */
#include <ctype.h>
-#define NO_RELOC 0
#include "as.h"
#include "obstack.h"
+#include "subsegs.h"
#include "opcode/m68k.h"
#include "m68k-parse.h"
-/* This array holds the chars that always start a comment. If the
- pre-processor is disabled, these aren't very useful */
-#ifdef OBJ_ELF
-CONST char comment_chars[] = "|#";
+/* This string holds the chars that always start a comment. If the
+ pre-processor is disabled, these aren't very useful. The macro
+ tc_comment_chars points to this. We use this, rather than the
+ usual comment_chars, so that the --bitwise-or option will work. */
+#if (defined (OBJ_ELF) && ! defined (TE_PSOS) && ! defined (TE_LINUX)) || defined (TE_DELTA)
+const char *m68k_comment_chars = "|#";
#else
-CONST char comment_chars[] = "|";
+const char *m68k_comment_chars = "|";
#endif
/* This array holds the chars that only start a comment at the beginning of
first line of the input file. This is because the compiler outputs
#NO_APP at the beginning of its output. */
/* Also note that comments like this one will always work. */
-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";
/* Are we trying to generate PIC code? If so, absolute references
ought to be made into linkage table references or pc-relative
- references. */
+ references. Not implemented. For ELF there are other means
+ to denote pic relocations. */
int flag_want_pic;
static int flag_short_refs; /* -l option */
int flag_reg_prefix_optional;
#endif
+/* Whether --register-prefix-optional was used on the command line. */
+static int reg_prefix_optional_seen;
+
/* The floating point coprocessor to use by default. */
static enum m68k_register m68k_float_copnum = COP1;
+/* If this is non-zero, then references to number(%pc) will be taken
+ to refer to number, rather than to %pc + number. */
+static int m68k_abspcadd;
+
+/* If this is non-zero, then the quick forms of the move, add, and sub
+ instructions are used when possible. */
+static int m68k_quick = 1;
+
+/* If this is non-zero, then if the size is not specified for a base
+ or outer displacement, the assembler assumes that the size should
+ be 32 bits. */
+static int m68k_rel32 = 1;
+
+/* This is non-zero if m68k_rel32 was set from the command line. */
+static int m68k_rel32_from_cmdline;
+
+/* The default width to use for an index register when using a base
+ displacement. */
+static enum m68k_size m68k_index_width_default = SIZE_LONG;
+
+/* We want to warn if any text labels are misaligned. In order to get
+ the right line number, we need to record the line number for each
+ label. */
+
+struct label_line
+{
+ struct label_line *next;
+ symbolS *label;
+ char *file;
+ unsigned int line;
+ int text;
+};
+
+/* The list of labels. */
+
+static struct label_line *labels;
+
+/* The current label. */
+
+static struct label_line *current_label;
+
/* Its an arbitrary name: This means I don't approve of it */
/* See flames below */
static struct obstack robyn;
USP, VBR, URP, SRP, PCR,
0
};
+static const enum m68k_register mcf5200_control_regs[] = {
+ CACR, TC, ITT0, ITT1, DTT0, DTT1, VBR, ROMBAR,
+ RAMBAR0, RAMBAR1, MBAR,
+ 0
+};
#define cpu32_control_regs m68010_control_regs
static const enum m68k_register *control_regs;
significance of some values (in the branch instruction, for
example). */
int pcrel_fix;
+#ifdef OBJ_ELF
+ /* Whether this expression needs special pic relocation, and if
+ so, which. */
+ enum pic_relocation pic_reloc;
+#endif
}
reloc[5]; /* Five is enough??? */
};
-#define cpu_of_arch(x) ((x) & m68000up)
+#define cpu_of_arch(x) ((x) & (m68000up|mcf5200))
#define float_of_arch(x) ((x) & mfloat)
#define mmu_of_arch(x) ((x) & mmmu)
int pc_rel;
int pc_fix;
{
- the_ins.reloc[the_ins.nrel].n = (((width)=='B')
+ the_ins.reloc[the_ins.nrel].n = ((width == 'B' || width == '3')
? (the_ins.numo*2-1)
: (((width)=='b')
? (the_ins.numo*2+1)
the_ins.reloc[the_ins.nrel].exp = exp->exp;
the_ins.reloc[the_ins.nrel].wid = width;
the_ins.reloc[the_ins.nrel].pcrel_fix = pc_fix;
+#ifdef OBJ_ELF
+ the_ins.reloc[the_ins.nrel].pic_reloc = exp->pic_reloc;
+#endif
the_ins.reloc[the_ins.nrel++].pcrel = pc_rel;
}
static void mri_chip PARAMS ((void));
static void s_chip PARAMS ((int));
static void s_fopt PARAMS ((int));
+static void s_opt PARAMS ((int));
+static void s_reg PARAMS ((int));
+static void s_restore PARAMS ((int));
+static void s_save PARAMS ((int));
+static void s_mri_if PARAMS ((int));
+static void s_mri_else PARAMS ((int));
+static void s_mri_endi PARAMS ((int));
+static void s_mri_break PARAMS ((int));
+static void s_mri_next PARAMS ((int));
+static void s_mri_for PARAMS ((int));
+static void s_mri_endf PARAMS ((int));
+static void s_mri_repeat PARAMS ((int));
+static void s_mri_until PARAMS ((int));
+static void s_mri_while PARAMS ((int));
+static void s_mri_endw PARAMS ((int));
static int current_architecture;
struct m68k_cpu {
unsigned long arch;
const char *name;
+ int alias;
};
static const struct m68k_cpu archs[] = {
- { m68000, "68000" },
- { m68010, "68010" },
- { m68020, "68020" },
- { m68030, "68030" },
- { m68040, "68040" },
- { m68060, "68060" },
- { cpu32, "cpu32" },
- { m68881, "68881" },
- { m68851, "68851" },
+ { m68000, "68000", 0 },
+ { m68010, "68010", 0 },
+ { m68020, "68020", 0 },
+ { m68030, "68030", 0 },
+ { m68040, "68040", 0 },
+ { m68060, "68060", 0 },
+ { cpu32, "cpu32", 0 },
+ { m68881, "68881", 0 },
+ { m68851, "68851", 0 },
+ { mcf5200, "5200", 0 },
/* Aliases (effectively, so far as gas is concerned) for the above
cpus. */
- { m68020, "68k" },
- { m68000, "68302" },
- { m68000, "68008" },
- { m68000, "68ec000" },
- { m68000, "68hc000" },
- { m68000, "68hc001" },
- { m68020, "68ec020" },
- { m68030, "68ec030" },
- { m68040, "68ec040" },
- { cpu32, "68330" },
- { cpu32, "68331" },
- { cpu32, "68332" },
- { cpu32, "68333" },
- { cpu32, "68340" },
- { cpu32, "68360" },
- { m68881, "68882" },
+ { m68020, "68k", 1 },
+ { m68000, "68302", 1 },
+ { m68000, "68008", 1 },
+ { m68000, "68ec000", 1 },
+ { m68000, "68hc000", 1 },
+ { m68000, "68hc001", 1 },
+ { m68020, "68ec020", 1 },
+ { m68030, "68ec030", 1 },
+ { m68040, "68ec040", 1 },
+ { m68060, "68ec060", 1 },
+ { cpu32, "68330", 1 },
+ { cpu32, "68331", 1 },
+ { cpu32, "68332", 1 },
+ { cpu32, "68333", 1 },
+ { cpu32, "68340", 1 },
+ { cpu32, "68360", 1 },
+ { m68881, "68882", 1 },
};
static const int n_archs = sizeof (archs) / sizeof (archs[0]);
function to call to execute this pseudo-op
Integer arg to pass to the function
*/
-CONST pseudo_typeS md_pseudo_table[] =
+const pseudo_typeS md_pseudo_table[] =
{
{"data1", s_data1, 0},
{"data2", s_data2, 0},
{"even", s_even, 0},
{"skip", s_space, 0},
{"proc", s_proc, 0},
-#ifdef TE_SUN3
+#if defined (TE_SUN3) || defined (OBJ_ELF)
{"align", s_align_bytes, 0},
#endif
#ifdef OBJ_ELF
{"swbeg", s_ignore, 0},
#endif
+ {"extend", float_cons, 'x'},
+ {"ldouble", float_cons, 'x'},
/* The following pseudo-ops are supported for MRI compatibility. */
{"chip", s_chip, 0},
{"comline", s_space, 1},
{"fopt", s_fopt, 0},
{"mask2", s_ignore, 0},
+ {"opt", s_opt, 0},
+ {"reg", s_reg, 0},
+ {"restore", s_restore, 0},
+ {"save", s_save, 0},
+
+ {"if", s_mri_if, 0},
+ {"if.b", s_mri_if, 'b'},
+ {"if.w", s_mri_if, 'w'},
+ {"if.l", s_mri_if, 'l'},
+ {"else", s_mri_else, 0},
+ {"else.s", s_mri_else, 's'},
+ {"else.l", s_mri_else, 'l'},
+ {"endi", s_mri_endi, 0},
+ {"break", s_mri_break, 0},
+ {"break.s", s_mri_break, 's'},
+ {"break.l", s_mri_break, 'l'},
+ {"next", s_mri_next, 0},
+ {"next.s", s_mri_next, 's'},
+ {"next.l", s_mri_next, 'l'},
+ {"for", s_mri_for, 0},
+ {"for.b", s_mri_for, 'b'},
+ {"for.w", s_mri_for, 'w'},
+ {"for.l", s_mri_for, 'l'},
+ {"endf", s_mri_endf, 0},
+ {"repeat", s_mri_repeat, 0},
+ {"until", s_mri_until, 0},
+ {"until.b", s_mri_until, 'b'},
+ {"until.w", s_mri_until, 'w'},
+ {"until.l", s_mri_until, 'l'},
+ {"while", s_mri_while, 0},
+ {"while.b", s_mri_while, 'b'},
+ {"while.w", s_mri_while, 'w'},
+ {"while.l", s_mri_while, 'l'},
+ {"endw", s_mri_endw, 0},
{0, 0, 0}
};
{"dsb", s_space, 1},
{"xdef", s_globl, 0},
+#ifdef OBJ_ELF
+ {"align", s_align_bytes, 0},
+#else
{"align", s_align_ptwo, 0},
+#endif
#ifdef M68KCOFF
{"sect", obj_coff_section, 0},
{"section", obj_coff_section, 0},
#define isuword(x) ((x)>=0 && (x)<=65535)
#define isbyte(x) ((x)>= -255 && (x)<=255)
-#define isword(x) ((x)>=-32768 && (x)<=65535)
+#define isword(x) ((x)>=-65536 && (x)<=65535)
#define islong(x) (1)
extern char *input_line_pointer;
tc_coff_fix2rtype (fixP)
fixS *fixP;
{
+ if (fixP->fx_tcbit && fixP->fx_size == 4)
+ return R_RELLONG_NEG;
#ifdef NO_PCREL_RELOCS
know (fixP->fx_pcrel == 0);
return (fixP->fx_size == 1 ? R_RELBYTE
#endif
+#ifdef OBJ_ELF
+
+/* Compute the relocation code for a fixup of SIZE bytes, using pc
+ relative relocation if PCREL is non-zero. PIC says whether a special
+ pic relocation was requested. */
+
+static bfd_reloc_code_real_type get_reloc_code
+ PARAMS ((int, int, enum pic_relocation));
+
+static bfd_reloc_code_real_type
+get_reloc_code (size, pcrel, pic)
+ int size;
+ int pcrel;
+ enum pic_relocation pic;
+{
+ switch (pic)
+ {
+ case pic_got_pcrel:
+ switch (size)
+ {
+ case 1:
+ return BFD_RELOC_8_GOT_PCREL;
+ case 2:
+ return BFD_RELOC_16_GOT_PCREL;
+ case 4:
+ return BFD_RELOC_32_GOT_PCREL;
+ }
+ break;
+
+ case pic_got_off:
+ switch (size)
+ {
+ case 1:
+ return BFD_RELOC_8_GOTOFF;
+ case 2:
+ return BFD_RELOC_16_GOTOFF;
+ case 4:
+ return BFD_RELOC_32_GOTOFF;
+ }
+ break;
+
+ case pic_plt_pcrel:
+ switch (size)
+ {
+ case 1:
+ return BFD_RELOC_8_PLT_PCREL;
+ case 2:
+ return BFD_RELOC_16_PLT_PCREL;
+ case 4:
+ return BFD_RELOC_32_PLT_PCREL;
+ }
+ break;
+
+ case pic_plt_off:
+ switch (size)
+ {
+ case 1:
+ return BFD_RELOC_8_PLTOFF;
+ case 2:
+ return BFD_RELOC_16_PLTOFF;
+ case 4:
+ return BFD_RELOC_32_PLTOFF;
+ }
+ break;
+
+ case pic_none:
+ if (pcrel)
+ {
+ switch (size)
+ {
+ case 1:
+ return BFD_RELOC_8_PCREL;
+ case 2:
+ return BFD_RELOC_16_PCREL;
+ case 4:
+ return BFD_RELOC_32_PCREL;
+ }
+ }
+ else
+ {
+ switch (size)
+ {
+ case 1:
+ return BFD_RELOC_8;
+ case 2:
+ return BFD_RELOC_16;
+ case 4:
+ return BFD_RELOC_32;
+ }
+ }
+ }
+
+ as_bad ("Can not do %d byte %s%srelocation", size,
+ pcrel ? "pc-relative " : "",
+ pic == pic_none ? "" : "pic ");
+ return BFD_RELOC_NONE;
+}
+
+/* Here we decide which fixups can be adjusted to make them relative
+ to the beginning of the section instead of the symbol. Basically
+ we need to make sure that the dynamic relocations are done
+ correctly, so in some cases we force the original symbol to be
+ used. */
+int
+tc_m68k_fix_adjustable (fixP)
+ fixS *fixP;
+{
+ /* Prevent all adjustments to global symbols. */
+ if (S_IS_EXTERNAL (fixP->fx_addsy))
+ return 0;
+
+ /* adjust_reloc_syms doesn't know about the GOT */
+ switch (fixP->fx_r_type)
+ {
+ case BFD_RELOC_8_GOT_PCREL:
+ case BFD_RELOC_16_GOT_PCREL:
+ case BFD_RELOC_32_GOT_PCREL:
+ case BFD_RELOC_8_GOTOFF:
+ case BFD_RELOC_16_GOTOFF:
+ case BFD_RELOC_32_GOTOFF:
+ case BFD_RELOC_8_PLT_PCREL:
+ case BFD_RELOC_16_PLT_PCREL:
+ case BFD_RELOC_32_PLT_PCREL:
+ case BFD_RELOC_8_PLTOFF:
+ case BFD_RELOC_16_PLTOFF:
+ case BFD_RELOC_32_PLTOFF:
+ return 0;
+
+ default:
+ return 1;
+ }
+}
+
+#else /* !OBJ_ELF */
+
+#define get_reloc_code(SIZE,PCREL,OTHER) NO_RELOC
+
+#endif /* OBJ_ELF */
+
#ifdef BFD_ASSEMBLER
arelent *
arelent *reloc;
bfd_reloc_code_real_type code;
-#define F(SZ,PCREL) (((SZ) << 1) + (PCREL))
- switch (F (fixp->fx_size, fixp->fx_pcrel))
+ if (fixp->fx_tcbit)
+ abort ();
+
+ if (fixp->fx_r_type != BFD_RELOC_NONE)
+ {
+ code = fixp->fx_r_type;
+
+ /* Since DIFF_EXPR_OK is defined in tc-m68k.h, it is possible
+ that fixup_segment converted a non-PC relative reloc into a
+ PC relative reloc. In such a case, we need to convert the
+ reloc code. */
+ if (fixp->fx_pcrel)
+ {
+ switch (code)
+ {
+ case BFD_RELOC_8:
+ code = BFD_RELOC_8_PCREL;
+ break;
+ case BFD_RELOC_16:
+ code = BFD_RELOC_16_PCREL;
+ break;
+ case BFD_RELOC_32:
+ code = BFD_RELOC_32_PCREL;
+ break;
+ case BFD_RELOC_8_PCREL:
+ case BFD_RELOC_16_PCREL:
+ case BFD_RELOC_32_PCREL:
+ case BFD_RELOC_8_GOT_PCREL:
+ case BFD_RELOC_16_GOT_PCREL:
+ case BFD_RELOC_32_GOT_PCREL:
+ case BFD_RELOC_8_GOTOFF:
+ case BFD_RELOC_16_GOTOFF:
+ case BFD_RELOC_32_GOTOFF:
+ case BFD_RELOC_8_PLT_PCREL:
+ case BFD_RELOC_16_PLT_PCREL:
+ case BFD_RELOC_32_PLT_PCREL:
+ case BFD_RELOC_8_PLTOFF:
+ case BFD_RELOC_16_PLTOFF:
+ case BFD_RELOC_32_PLTOFF:
+ break;
+ default:
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ "Cannot make %s relocation PC relative",
+ bfd_get_reloc_code_name (code));
+ }
+ }
+ }
+ else
{
+#define F(SZ,PCREL) (((SZ) << 1) + (PCREL))
+ switch (F (fixp->fx_size, fixp->fx_pcrel))
+ {
#define MAP(SZ,PCREL,TYPE) case F(SZ,PCREL): code = (TYPE); break
- MAP (1, 0, BFD_RELOC_8);
- MAP (2, 0, BFD_RELOC_16);
- MAP (4, 0, BFD_RELOC_32);
- MAP (1, 1, BFD_RELOC_8_PCREL);
- MAP (2, 1, BFD_RELOC_16_PCREL);
- MAP (4, 1, BFD_RELOC_32_PCREL);
- default:
- abort ();
+ MAP (1, 0, BFD_RELOC_8);
+ MAP (2, 0, BFD_RELOC_16);
+ MAP (4, 0, BFD_RELOC_32);
+ MAP (1, 1, BFD_RELOC_8_PCREL);
+ MAP (2, 1, BFD_RELOC_16_PCREL);
+ MAP (4, 1, BFD_RELOC_32_PCREL);
+ default:
+ abort ();
+ }
}
+#undef F
+#undef MAP
reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
assert (reloc != 0);
reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+#ifndef OBJ_ELF
if (fixp->fx_pcrel)
reloc->addend = fixp->fx_addnumber;
else
reloc->addend = 0;
+#else
+ if (!fixp->fx_pcrel)
+ reloc->addend = fixp->fx_addnumber;
+ else
+ reloc->addend = (section->vma
+ + (fixp->fx_pcrel_adjust == 64
+ ? -1 : fixp->fx_pcrel_adjust)
+ + fixp->fx_addnumber
+ + md_pcrel_from (fixp));
+#endif
reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
assert (reloc->howto != 0);
return;
}
+ if (flag_mri && opcode->m_opnum == 0)
+ {
+ /* In MRI mode, random garbage is allowed after an instruction
+ which accepts no operands. */
+ the_ins.args = opcode->m_operands;
+ the_ins.numargs = opcode->m_opnum;
+ the_ins.numo = opcode->m_codenum;
+ the_ins.opcode[0] = getone (opcode);
+ the_ins.opcode[1] = gettwo (opcode);
+ return;
+ }
+
for (opP = &the_ins.operands[0]; *p; opP++)
{
p = crack_operand (p, opP);
/* If we didn't get the right number of ops, or we have no
common model with this pattern then reject this pattern. */
+ ok_arch |= opcode->m_arch;
if (opsfound != opcode->m_opnum
|| ((opcode->m_arch & current_architecture) == 0))
- {
- ++losing;
- ok_arch |= opcode->m_arch;
- }
+ ++losing;
else
{
for (s = opcode->m_operands, opP = &the_ins.operands[0];
}
break;
+ case '<':
+ switch (opP->mode)
+ {
+ case DREG:
+ case AREG:
+ case FPREG:
+ case CONTROL:
+ case IMMED:
+ case ADEC:
+ case REGLST:
+ losing++;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case '>':
+ switch (opP->mode)
+ {
+ case DREG:
+ case AREG:
+ case FPREG:
+ case CONTROL:
+ case IMMED:
+ case AINC:
+ case REGLST:
+ losing++;
+ break;
+ case ABSL:
+ break;
+ default:
+ if (opP->reg == PC
+ || opP->reg == ZPC)
+ losing++;
+ break;
+ }
+ break;
+
+ case 'm':
+ switch (opP->mode)
+ {
+ case DREG:
+ case AREG:
+ case AINDR:
+ case AINC:
+ case ADEC:
+ break;
+ default:
+ losing++;
+ }
+ break;
+
+ case 'n':
+ switch (opP->mode)
+ {
+ case DISP:
+ break;
+ default:
+ losing++;
+ }
+ break;
+
+ case 'o':
+ switch (opP->mode)
+ {
+ case BASE:
+ case ABSL:
+ case IMMED:
+ break;
+ default:
+ losing++;
+ }
+ break;
+
+ case 'p':
+ switch (opP->mode)
+ {
+ case DREG:
+ case AREG:
+ case AINDR:
+ case AINC:
+ case ADEC:
+ case DISP:
+ break;
+ default:
+ losing++;
+ }
+ break;
+
case '#':
if (opP->mode != IMMED)
losing++;
else if (s[1] == 'b'
&& ! isvar (&opP->disp)
- && ! expr8 (&opP->disp))
+ && (opP->disp.exp.X_op != O_constant
+ || ! isbyte (opP->disp.exp.X_add_number)))
+ losing++;
+ else if (s[1] == 'B'
+ && ! isvar (&opP->disp)
+ && (opP->disp.exp.X_op != O_constant
+ || ! issbyte (opP->disp.exp.X_add_number)))
losing++;
else if (s[1] == 'w'
&& ! isvar (&opP->disp)
- && ! expr16 (&opP->disp))
+ && (opP->disp.exp.X_op != O_constant
+ || ! isword (opP->disp.exp.X_add_number)))
+ losing++;
+ else if (s[1] == 'W'
+ && ! isvar (&opP->disp)
+ && (opP->disp.exp.X_op != O_constant
+ || ! issword (opP->disp.exp.X_add_number)))
losing++;
break;
if (opP->mode == CONTROL
|| opP->mode == FPREG
|| opP->mode == REGLST
+ || opP->mode == IMMED
|| (opP->mode != ABSL
- && opP->mode != IMMED
&& (opP->reg == PC
|| opP->reg == ZPC)))
losing++;
opP->mode = REGLST;
}
}
+ else if (opP->mode == ABSL
+ && opP->disp.size == SIZE_UNSPEC
+ && opP->disp.exp.X_op == O_constant)
+ {
+ /* This is what the MRI REG pseudo-op generates. */
+ opP->mode = REGLST;
+ opP->mask = opP->disp.exp.X_add_number;
+ }
else if (opP->mode != REGLST)
losing++;
else if (s[1] == '8' && (opP->mask & 0x0ffffff) != 0)
case 'M':
if (opP->mode != IMMED)
losing++;
- else if (! expr8 (&opP->disp))
+ else if (opP->disp.exp.X_op != O_constant
+ || ! issbyte (opP->disp.exp.X_add_number))
+ losing++;
+ else if (! m68k_quick
+ && instring[3] != 'q'
+ && instring[4] != 'q')
losing++;
break;
case 'O':
- if (opP->mode != DREG && opP->mode != IMMED)
+ if (opP->mode != DREG
+ && opP->mode != IMMED
+ && opP->mode != ABSL)
losing++;
break;
case 'Q':
if (opP->mode != IMMED)
losing++;
- else if (! expr8 (&opP->disp)
+ else if (opP->disp.exp.X_op != O_constant
|| opP->disp.exp.X_add_number < 1
|| opP->disp.exp.X_add_number > 8)
losing++;
+ else if (! m68k_quick
+ && (strncmp (instring, "add", 3) == 0
+ || strncmp (instring, "sub", 3) == 0)
+ && instring[3] != 'q')
+ losing++;
break;
case 'R':
case 't':
if (opP->mode != IMMED)
losing++;
- else if (! expr8 (&opP->disp)
+ else if (opP->disp.exp.X_op != O_constant
|| opP->disp.exp.X_add_number < 0
|| opP->disp.exp.X_add_number > 7)
losing++;
|| opP->mode == AREG
|| opP->mode == REGLST)
losing++;
+ /* We should accept immediate operands, but they
+ supposedly have to be quad word, and we don't
+ handle that. I would like to see what a Motorola
+ assembler does before doing something here. */
+ if (opP->mode == IMMED)
+ losing++;
break;
case 'f':
losing++;
break;
- case 'P':
+ case '0':
+ if (opP->mode != CONTROL || opP->reg != TC)
+ losing++;
+ break;
+
+ case '1':
+ if (opP->mode != CONTROL || opP->reg != AC)
+ losing++;
+ break;
+
+ case '2':
if (opP->mode != CONTROL
- || (opP->reg != TC
- && opP->reg != CAL
+ || (opP->reg != CAL
&& opP->reg != VAL
- && opP->reg != SCC
- && opP->reg != AC))
+ && opP->reg != SCC))
losing++;
break;
&& !(ok_arch & current_architecture))
{
char buf[200], *cp;
- int len;
+
strcpy (buf,
"invalid instruction for this architecture; needs ");
cp = buf + strlen (buf);
for (idx = 0; idx < sizeof (archs) / sizeof (archs[0]);
idx++)
{
- if (archs[idx].arch & ok_arch)
+ if ((archs[idx].arch & ok_arch)
+ && ! archs[idx].alias)
{
if (got_one)
{
}
}
}
- len = cp - buf + 1;
- cp = malloc (len);
+ cp = xmalloc (strlen (buf) + 1);
strcpy (cp, buf);
the_ins.error = cp;
}
case '?':
case '/':
case '`':
+ case '<':
+ case '>':
+ case 'm':
+ case 'n':
+ case 'o':
+ case 'p':
#ifndef NO_68851
case '|':
#endif
addword (nextword);
baseo = 0;
break;
+ case 'W':
+ if (!issword (nextword))
+ opP->error = "operand out of range";
+ addword (nextword);
+ baseo = 0;
+ break;
case 'l':
addword (nextword >> 16);
addword (nextword);
case DISP:
nextword = get_num (&opP->disp, 80);
+
+ if (opP->reg == PC
+ && ! isvar (&opP->disp)
+ && m68k_abspcadd)
+ {
+ opP->disp.exp.X_op = O_symbol;
+#ifndef BFD_ASSEMBLER
+ opP->disp.exp.X_add_symbol = &abs_symbol;
+#else
+ opP->disp.exp.X_add_symbol =
+ section_symbol (absolute_section);
+#endif
+ }
+
/* Force into index mode. Hope this works */
/* We do the first bit for 32-bit displacements, and the
&& cpu_of_arch (current_architecture) >= m68020)
|| opP->disp.size == SIZE_LONG)))
{
+ if (cpu_of_arch (current_architecture) < m68020)
+ opP->error =
+ "displacement too large for this architecture; needs 68020 or higher";
if (opP->reg == PC)
tmpreg = 0x3B; /* 7.3 */
else
{
if (opP->reg == PC)
{
-#if 0
- addword (0x0170);
- add_fix ('l', &opP->disp, 1, 2);
- addword (0), addword (0);
-#else
- add_frag (adds (&opP->disp),
- offs (&opP->disp),
- TAB (PCLEA, SZ_UNDEF));
+ if (opP->disp.size == SIZE_LONG
+#ifdef OBJ_ELF
+ /* If the displacement needs pic
+ relocation it cannot be relaxed. */
+ || opP->disp.pic_reloc != pic_none
#endif
- break;
+ )
+ {
+ addword (0x0170);
+ add_fix ('l', &opP->disp, 1, 2);
+ }
+ else
+ {
+ add_frag (adds (&opP->disp),
+ offs (&opP->disp),
+ TAB (PCLEA, SZ_UNDEF));
+ break;
+ }
}
else
{
{
nextword |= (opP->index.reg - DATA) << 12;
- if (opP->index.size == SIZE_UNSPEC
- || opP->index.size == SIZE_LONG)
+ if (opP->index.size == SIZE_LONG
+ || (opP->index.size == SIZE_UNSPEC
+ && m68k_index_width_default == SIZE_LONG))
nextword |= 0x800;
- if (cpu_of_arch (current_architecture) < m68020)
+ if ((opP->index.scale != 1
+ && cpu_of_arch (current_architecture) < m68020)
+ || (opP->index.scale == 8
+ && current_architecture == mcf5200))
{
- if (opP->index.scale != 1)
- {
- opP->error =
- "scale factor invalid on this architecture; needs 68020 or higher";
- }
+ opP->error =
+ "scale factor invalid on this architecture; needs cpu32 or 68020 or higher";
}
switch (opP->index.scale)
else if (siz1 == SIZE_UNSPEC
&& opP->reg == PC
&& isvar (&opP->disp)
- && subs (&opP->disp) == NULL)
+ && subs (&opP->disp) == NULL
+#ifdef OBJ_ELF
+ /* If the displacement needs pic
+ relocation it cannot be relaxed. */
+ && opP->disp.pic_reloc == pic_none
+#endif
+ )
{
+ /* The code in md_convert_frag_1 needs to be
+ able to adjust nextword. Call frag_grow
+ to ensure that we have enough space in
+ the frag obstack to make all the bytes
+ contiguous. */
+ frag_grow (14);
nextword += baseo & 0xff;
addword (nextword);
add_frag (adds (&opP->disp), offs (&opP->disp),
switch (siz1)
{
case SIZE_UNSPEC:
- if (isvar (&opP->disp) || !issword (baseo))
+ if (isvar (&opP->disp)
+ ? m68k_rel32
+ : ! issword (baseo))
{
siz1 = SIZE_LONG;
nextword |= 0x30;
}
- else if (baseo == 0)
+ else if (! isvar (&opP->disp) && baseo == 0)
nextword |= 0x10;
else
{
/* Figure out innner displacement stuff */
if (opP->mode == POST || opP->mode == PRE)
{
+ if (cpu_of_arch (current_architecture) & cpu32)
+ opP->error = "invalid operand mode for this architecture; needs 68020 or higher";
switch (siz2)
{
case SIZE_UNSPEC:
- if (isvar (&opP->odisp) || !issword (outro))
+ if (isvar (&opP->odisp)
+ ? m68k_rel32
+ : ! issword (outro))
{
siz2 = SIZE_LONG;
nextword |= 0x3;
}
- else if (outro == 0)
+ else if (! isvar (&opP->odisp) && outro == 0)
nextword |= 0x1;
else
{
nextword |= 0x3;
break;
}
- if (opP->mode == POST)
+ if (opP->mode == POST
+ && (nextword & 0x40) == 0)
nextword |= 0x04;
}
addword (nextword);
if (isvar (&opP->disp)
&& !subs (&opP->disp)
&& adds (&opP->disp)
- && (S_GET_SEGMENT (adds (&opP->disp)) == text_section)
- && now_seg == text_section
+#ifdef OBJ_ELF
+ /* If the displacement needs pic relocation it
+ cannot be relaxed. */
+ && opP->disp.pic_reloc == pic_none
+#endif
+ && S_GET_SEGMENT (adds (&opP->disp)) == now_seg
&& cpu_of_arch (current_architecture) >= m68020
&& !flag_long_jumps
&& !strchr ("~%&$?", s[0]))
opP->error = "out of range";
insop (tmpreg, opcode);
if (isvar (&opP->disp))
- the_ins.reloc[the_ins.nrel - 1].n = (opcode->m_codenum) * 2;
+ the_ins.reloc[the_ins.nrel - 1].n =
+ (opcode->m_codenum) * 2 + 1;
+ break;
+ case 'B':
+ if (!issbyte (tmpreg))
+ opP->error = "out of range";
+ opcode->m_opcode |= tmpreg;
+ if (isvar (&opP->disp))
+ the_ins.reloc[the_ins.nrel - 1].n = opcode->m_codenum * 2 - 1;
break;
case 'w':
if (!isword (tmpreg))
if (isvar (&opP->disp))
the_ins.reloc[the_ins.nrel - 1].n = (opcode->m_codenum) * 2;
break;
+ case 'W':
+ if (!issword (tmpreg))
+ opP->error = "out of range";
+ insop (tmpreg, opcode);
+ if (isvar (&opP->disp))
+ the_ins.reloc[the_ins.nrel - 1].n = (opcode->m_codenum) * 2;
+ break;
case 'l':
/* Because of the way insop works, we put these two out
backwards. */
switch (s[1])
{
case 'B':
- add_fix ('B', &opP->disp, 1, -1);
+ /* The pc_fix argument winds up in fx_pcrel_adjust,
+ which is a char, and may therefore be unsigned. We
+ want to pass -1, but we pass 64 instead, and convert
+ back in md_pcrel_from. */
+ add_fix ('B', &opP->disp, 1, 64);
break;
case 'W':
add_fix ('w', &opP->disp, 1, 0);
if (subs (&opP->disp)) /* We can't relax it */
goto long_branch;
+#ifdef OBJ_ELF
+ /* If the displacement needs pic relocation it cannot be
+ relaxed. */
+ if (opP->disp.pic_reloc != pic_none)
+ goto long_branch;
+#endif
+
/* This could either be a symbol, or an absolute
address. No matter, the frag hacking will finger it
out. Not quite: it can't switch from BRANCH to
case PCR:
tmpreg = 0x808;
break;
+ case ROMBAR:
+ tmpreg = 0xC00;
+ break;
+ case RAMBAR0:
+ tmpreg = 0xC04;
+ break;
+ case RAMBAR1:
+ tmpreg = 0xC05;
+ break;
+ case MBAR:
+ tmpreg = 0xC0F;
+ break;
default:
abort ();
}
install_operand (s[1], tmpreg);
break;
- case 'P':
+ case '0':
+ case '1':
+ case '2':
switch (opP->reg)
{
case TC:
break;
case 'b':
case 'w':
+ case 'W':
case 'l':
break;
case 'e':
register int parens;
register int c;
register char *beg_str;
+ int inquote = 0;
if (!str)
{
return str;
}
beg_str = str;
- for (parens = 0; *str && (parens > 0 || notend (str)); str++)
+ for (parens = 0; *str && (parens > 0 || inquote || notend (str)); str++)
{
- if (*str == '(')
- parens++;
- else if (*str == ')')
+ if (! inquote)
{
- if (!parens)
- { /* ERROR */
- opP->error = "Extra )";
- return str;
+ if (*str == '(')
+ parens++;
+ else if (*str == ')')
+ {
+ if (!parens)
+ { /* ERROR */
+ opP->error = "Extra )";
+ return str;
+ }
+ --parens;
}
- --parens;
}
+ if (flag_mri && *str == '\'')
+ inquote = ! inquote;
}
if (!*str && parens)
{ /* ERROR */
{ "ccr", CCR },
{ "cc", CCR },
- { "usp", USP },
- { "isp", ISP },
- { "sfc", SFC },
+ /* control registers */
+ { "sfc", SFC }, /* Source Function Code */
{ "sfcr", SFC },
- { "dfc", DFC },
+ { "dfc", DFC }, /* Destination Function Code */
{ "dfcr", DFC },
- { "cacr", CACR },
- { "caar", CAAR },
-
- { "vbr", VBR },
-
- { "msp", MSP },
- { "itt0", ITT0 },
- { "itt1", ITT1 },
- { "dtt0", DTT0 },
- { "dtt1", DTT1 },
- { "mmusr", MMUSR },
- { "tc", TC },
- { "srp", SRP },
- { "urp", URP },
+ { "cacr", CACR }, /* Cache Control Register */
+ { "caar", CAAR }, /* Cache Address Register */
+
+ { "usp", USP }, /* User Stack Pointer */
+ { "vbr", VBR }, /* Vector Base Register */
+ { "msp", MSP }, /* Master Stack Pointer */
+ { "isp", ISP }, /* Interrupt Stack Pointer */
+
+ { "itt0", ITT0 }, /* Instruction Transparent Translation Reg 0 */
+ { "itt1", ITT1 }, /* Instruction Transparent Translation Reg 1 */
+ { "dtt0", DTT0 }, /* Data Transparent Translation Register 0 */
+ { "dtt1", DTT1 }, /* Data Transparent Translation Register 1 */
+
+ /* 68ec040 versions of same */
+ { "iacr0", ITT0 }, /* Instruction Access Control Register 0 */
+ { "iacr1", ITT1 }, /* Instruction Access Control Register 0 */
+ { "dacr0", DTT0 }, /* Data Access Control Register 0 */
+ { "dacr1", DTT1 }, /* Data Access Control Register 0 */
+
+ /* mcf5200 versions of same. The ColdFire programmer's reference
+ manual indicated that the order is 2,3,0,1, but Ken Rose
+ <rose@netcom.com> says that 0,1,2,3 is the correct order. */
+ { "acr0", ITT0 }, /* Access Control Unit 0 */
+ { "acr1", ITT1 }, /* Access Control Unit 1 */
+ { "acr2", DTT0 }, /* Access Control Unit 2 */
+ { "acr3", DTT1 }, /* Access Control Unit 3 */
+
+ { "tc", TC }, /* MMU Translation Control Register */
+ { "tcr", TC },
+
+ { "mmusr", MMUSR }, /* MMU Status Register */
+ { "srp", SRP }, /* User Root Pointer */
+ { "urp", URP }, /* Supervisor Root Pointer */
+
{ "buscr", BUSCR },
{ "pcr", PCR },
+ { "rombar", ROMBAR }, /* ROM Base Address Register */
+ { "rambar0", RAMBAR0 }, /* ROM Base Address Register */
+ { "rambar1", RAMBAR1 }, /* ROM Base Address Register */
+ { "mbar", MBAR }, /* Module Base Address Register */
+ /* end of control registers */
+
{ "ac", AC },
{ "bc", BC },
{ "cal", CAL },
int shorts_this_frag;
fixS *fixP;
- memset ((char *) (&the_ins), '\0', sizeof (the_ins));
+ /* In MRI mode, the instruction and operands are separated by a
+ space. Anything following the operands is a comment. The label
+ has already been removed. */
+ if (flag_mri)
+ {
+ char *s;
+ int fields = 0;
+ int infield = 0;
+ int inquote = 0;
+
+ for (s = str; *s != '\0'; s++)
+ {
+ if ((*s == ' ' || *s == '\t') && ! inquote)
+ {
+ if (infield)
+ {
+ ++fields;
+ if (fields >= 2)
+ {
+ *s = '\0';
+ break;
+ }
+ infield = 0;
+ }
+ }
+ else
+ {
+ if (! infield)
+ infield = 1;
+ if (*s == '\'')
+ inquote = ! inquote;
+ }
+ }
+ }
+
+ memset ((char *) (&the_ins), '\0', sizeof (the_ins));
m68k_ip (str);
er = the_ins.error;
if (!er)
return;
}
+ /* If there is a current label, record that it marks an instruction. */
+ if (current_label != NULL)
+ {
+ current_label->text = 1;
+ current_label = NULL;
+ }
+
if (the_ins.nfrag == 0)
{
/* No frag hacking involved; just put it out */
n = 1;
break;
case '3':
- n = 2;
+ n = 1;
break;
case 'w':
n = 2;
n,
&the_ins.reloc[m].exp,
the_ins.reloc[m].pcrel,
- NO_RELOC);
+ get_reloc_code (n, the_ins.reloc[m].pcrel,
+ the_ins.reloc[m].pic_reloc));
fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix;
+ if (the_ins.reloc[m].wid == 'B')
+ fixP->fx_signed = 1;
}
return;
}
wid,
&the_ins.reloc[m].exp,
the_ins.reloc[m].pcrel,
- NO_RELOC);
+ get_reloc_code (wid, the_ins.reloc[m].pcrel,
+ the_ins.reloc[m].pic_reloc));
fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix;
}
(void) frag_var (rs_machine_dependent, 10, 0,
wid,
&the_ins.reloc[m].exp,
the_ins.reloc[m].pcrel,
- NO_RELOC);
+ get_reloc_code (wid, the_ins.reloc[m].pcrel,
+ the_ins.reloc[m].pic_reloc));
fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix;
}
}
register char c;
if (flag_mri)
- flag_reg_prefix_optional = 1;
+ {
+ flag_reg_prefix_optional = 1;
+ m68k_abspcadd = 1;
+ if (! m68k_rel32_from_cmdline)
+ m68k_rel32 = 0;
+ }
op_hash = hash_new ();
as_fatal ("Internal Error: Can't hash %s: %s", alias, retval);
}
+ /* In MRI mode, all unsized branches are variable sized. Normally,
+ they are word sized. */
+ if (flag_mri)
+ {
+ static struct m68k_opcode_alias mri_aliases[] =
+ {
+ { "bhi", "jhi", },
+ { "bls", "jls", },
+ { "bcc", "jcc", },
+ { "bcs", "jcs", },
+ { "bne", "jne", },
+ { "beq", "jeq", },
+ { "bvc", "jvc", },
+ { "bvs", "jvs", },
+ { "bpl", "jpl", },
+ { "bmi", "jmi", },
+ { "bge", "jge", },
+ { "blt", "jlt", },
+ { "bgt", "jgt", },
+ { "ble", "jle", },
+ { "bra", "jra", },
+ { "bsr", "jbsr", },
+ };
+
+ for (i = 0; i < sizeof mri_aliases / sizeof mri_aliases[0]; i++)
+ {
+ const char *name = mri_aliases[i].primary;
+ const char *alias = mri_aliases[i].alias;
+ PTR val = hash_find (op_hash, name);
+ if (!val)
+ as_fatal ("Internal Error: Can't find %s in hash table", name);
+ retval = hash_jam (op_hash, alias, val);
+ if (retval)
+ as_fatal ("Internal Error: Can't hash %s: %s", alias, retval);
+ }
+ }
+
for (i = 0; i < sizeof (mklower_table); i++)
mklower_table[i] = (isupper (c = (char) i)) ? tolower (c) : c;
*/
alt_notend_table['@'] = 1;
+ /* We need to put digits in alt_notend_table to handle
+ bfextu %d0{24:1},%d0
+ */
+ alt_notend_table['0'] = 1;
+ alt_notend_table['1'] = 1;
+ alt_notend_table['2'] = 1;
+ alt_notend_table['3'] = 1;
+ alt_notend_table['4'] = 1;
+ alt_notend_table['5'] = 1;
+ alt_notend_table['6'] = 1;
+ alt_notend_table['7'] = 1;
+ alt_notend_table['8'] = 1;
+ alt_notend_table['9'] = 1;
+
#ifndef MIT_SYNTAX_ONLY
/* Insert pseudo ops, these have to go into the opcode table since
gas expects pseudo ops to start with a dot */
#endif
init_regtable ();
+
+#ifdef OBJ_ELF
+ record_alignment (text_section, 2);
+ record_alignment (data_section, 2);
+ record_alignment (bss_section, 2);
+#endif
+}
+
+static void
+select_control_regs ()
+{
+ /* Note which set of "movec" control registers is available. */
+ switch (cpu_of_arch (current_architecture))
+ {
+ case m68000:
+ control_regs = m68000_control_regs;
+ break;
+ case m68010:
+ control_regs = m68010_control_regs;
+ break;
+ case m68020:
+ case m68030:
+ control_regs = m68020_control_regs;
+ break;
+ case m68040:
+ control_regs = m68040_control_regs;
+ break;
+ case m68060:
+ control_regs = m68060_control_regs;
+ break;
+ case cpu32:
+ control_regs = cpu32_control_regs;
+ break;
+ case mcf5200:
+ control_regs = mcf5200_control_regs;
+ break;
+ default:
+ abort ();
+ }
}
void
#endif
/* Note which set of "movec" control registers is available. */
- switch (cpu_of_arch (current_architecture))
- {
- case m68000:
- control_regs = m68000_control_regs;
- break;
- case m68010:
- control_regs = m68010_control_regs;
- break;
- case m68020:
- case m68030:
- control_regs = m68020_control_regs;
- break;
- case m68040:
- control_regs = m68040_control_regs;
- break;
- case m68060:
- control_regs = m68060_control_regs;
- break;
- case cpu32:
- control_regs = cpu32_control_regs;
- break;
- default:
- abort ();
- }
+ select_control_regs ();
if (cpu_of_arch (current_architecture) < m68020)
md_relax_table[TAB (PCINDEX, BYTE)].rlx_more = 0;
}
+\f
+/* This is called when a label is defined. */
+
+void
+m68k_frob_label (sym)
+ symbolS *sym;
+{
+ struct label_line *n;
+
+ n = (struct label_line *) xmalloc (sizeof *n);
+ n->next = labels;
+ n->label = sym;
+ as_where (&n->file, &n->line);
+ labels = n;
+ current_label = n;
+}
+
+/* This is called when a value that is not an instruction is emitted. */
+
+void
+m68k_flush_pending_output ()
+{
+ current_label = NULL;
+}
+
+/* This is called at the end of the assembly, when the final value of
+ the label is known. We warn if this is a text symbol aligned at an
+ odd location. */
+
+void
+m68k_frob_symbol (sym)
+ symbolS *sym;
+{
+ if ((S_GET_VALUE (sym) & 1) != 0)
+ {
+ struct label_line *l;
+
+ for (l = labels; l != NULL; l = l->next)
+ {
+ if (l->label == sym)
+ {
+ if (l->text)
+ as_warn_where (l->file, l->line,
+ "text label `%s' aligned to odd boundary",
+ S_GET_NAME (sym));
+ break;
+ }
+ }
+ }
+}
+\f
+/* This is called if we go in or out of MRI mode because of the .mri
+ pseudo-op. */
+
+void
+m68k_mri_mode_change (on)
+ int on;
+{
+ if (on)
+ {
+ if (! flag_reg_prefix_optional)
+ {
+ flag_reg_prefix_optional = 1;
+#ifdef REGISTER_PREFIX
+ init_regtable ();
+#endif
+ }
+ m68k_abspcadd = 1;
+ if (! m68k_rel32_from_cmdline)
+ m68k_rel32 = 0;
+ }
+ else
+ {
+ if (! reg_prefix_optional_seen)
+ {
+#ifdef REGISTER_PREFIX_OPTIONAL
+ flag_reg_prefix_optional = REGISTER_PREFIX_OPTIONAL;
+#else
+ flag_reg_prefix_optional = 0;
+#endif
+#ifdef REGISTER_PREFIX
+ init_regtable ();
+#endif
+ }
+ m68k_abspcadd = 0;
+ if (! m68k_rel32_from_cmdline)
+ m68k_rel32 = 1;
+ }
+}
/* Equal to MAX_PRECISION in atof-ieee.c */
#define MAX_LITTLENUMS 6
else
val &= 0x7fffffff;
+#ifdef OBJ_ELF
+ if (fixP->fx_addsy)
+ {
+ memset (buf, 0, fixP->fx_size);
+ fixP->fx_addnumber = val; /* Remember value for emit_reloc */
+ return;
+ }
+#endif
+
switch (fixP->fx_size)
{
/* The cast to offsetT below are necessary to make code correct for
BAD_CASE (fixP->fx_size);
}
+ /* Fix up a negative reloc. */
+ if (fixP->fx_addsy == NULL && fixP->fx_subsy != NULL)
+ {
+ fixP->fx_addsy = fixP->fx_subsy;
+ fixP->fx_subsy = NULL;
+ fixP->fx_tcbit = 1;
+ }
+
/* For non-pc-relative values, it's conceivable we might get something
like "0xff" for a byte field. So extend the upper part of the range
to accept such numbers. We arbitrarily disallow "-0xff" or "0xff+0xff",
so that we can do any range checking at all. */
- if (!fixP->fx_pcrel)
+ if (! fixP->fx_pcrel && ! fixP->fx_signed)
upper_limit = upper_limit * 2 + 1;
if ((addressT) val > upper_limit
{
fragP->fr_opcode[0] = 0x4E;
fragP->fr_opcode[1] = (char) 0xB9; /* JBSR with ABSL LONG offset */
- subseg_change (text_section, 0); /* @@ */
fix_new (fragP,
fragP->fr_fix,
{
fragP->fr_opcode[0] = 0x4E;
fragP->fr_opcode[1] = (char) 0xF9; /* JMP with ABSL LONG offset */
- subseg_change (text_section, 0); /* @@ */
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
fragP->fr_offset, 0, NO_RELOC);
fragP->fr_fix += 4;
*buffer_address++ = 0x4e; /* put in jmp long (0x4ef9) */
*buffer_address++ = (char) 0xf9;
fragP->fr_fix += 2; /* account for jmp instruction */
- subseg_change (text_section, 0);
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
fragP->fr_offset, 0, NO_RELOC);
fragP->fr_fix += 4;
*buffer_address++ = (char) 0xf9;
fragP->fr_fix += 6; /* account for bra/jmp instructions */
- subseg_change (text_section, 0);
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
fragP->fr_offset, 0, NO_RELOC);
fragP->fr_fix += 4;
/* The thing to do here is force it to ABSOLUTE LONG, since
PCREL is really trying to shorten an ABSOLUTE address anyway */
/* JF FOO This code has not been tested */
- subseg_change (text_section, 0);
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
0, NO_RELOC);
if ((fragP->fr_opcode[1] & 0x3F) != 0x3A)
ext = 0;
break;
case TAB (PCLEA, SHORT):
- subseg_change (text_section, 0);
fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
fragP->fr_opcode[1] &= ~0x3F;
ext = 2;
break;
case TAB (PCLEA, LONG):
- subseg_change (text_section, 0);
fixP = fix_new (fragP, (int) (fragP->fr_fix) + 2, 4, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
fixP->fx_pcrel_adjust = 2;
ext = 0;
break;
case TAB (PCINDEX, SHORT):
- subseg_change (text_section, 0);
disp += 2;
assert (issword (disp));
assert (fragP->fr_fix >= 2);
ext = 2;
break;
case TAB (PCINDEX, LONG):
- subseg_change (text_section, 0);
disp += 2;
fixP = fix_new (fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol,
fragP->fr_offset, (fragP->fr_opcode[1] & 077) == 073,
{
fragP->fr_opcode[0] = 0x4E;
fragP->fr_opcode[1] = (char) 0xB9; /* JBSR with ABSL LONG offset */
- subseg_change (text_section, 0);
fix_new (fragP, fragP->fr_fix, 4,
fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC);
fragP->fr_fix += 4;
{
fragP->fr_opcode[0] = 0x4E;
fragP->fr_opcode[1] = (char) 0xF9; /* JMP with ABSL LONG offset */
- subseg_change (text_section, 0);
fix_new (fragP, fragP->fr_fix, 4,
fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC);
fragP->fr_fix += 4;
buffer_address[0] = 0x4e; /* put in jmp long (0x4ef9) */
buffer_address[1] = (char) 0xf8;
fragP->fr_fix += 2; /* account for jmp instruction */
- subseg_change (text_section, 0);
fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
fragP->fr_offset, 0, NO_RELOC);
fragP->fr_fix += 2;
buffer_address[0] = 0x4e; /* put in jmp long (0x4ef9) */
buffer_address[1] = (char) 0xf9;
fragP->fr_fix += 2; /* account for jmp instruction */
- subseg_change (text_section, 0);
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
fragP->fr_offset, 0, NO_RELOC);
fragP->fr_fix += 4;
buffer_address[4] = 0x4e; /* Put in Jump Word */
buffer_address[5] = (char) 0xf8;
fragP->fr_fix += 6; /* account for bra/jmp instruction */
- subseg_change (text_section, 0);
fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
fragP->fr_offset, 0, NO_RELOC);
fragP->fr_fix += 2;
buffer_address[4] = 0x4e; /* put in jmp long (0x4ef9) */
buffer_address[5] = (char) 0xf9;
fragP->fr_fix += 6; /* account for bra/jmp instruction */
- subseg_change (text_section, 0);
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
fragP->fr_offset, 0, NO_RELOC);
fragP->fr_fix += 4;
{
case TAB (BCC68000, BYTE):
case TAB (ABRANCH, BYTE):
- /* We can't do a short jump to the next instruction,
- so we force word mode. */
- if (fragP->fr_symbol && S_GET_VALUE (fragP->fr_symbol) == 0 &&
- fragP->fr_symbol->sy_frag == fragP->fr_next)
+ /* We can't do a short jump to the next instruction, so in that
+ case we force word mode. At this point S_GET_VALUE should
+ return the offset of the symbol within its frag. If the
+ symbol is at the start of a frag, and it is the next frag
+ with any data in it (usually this is just the next frag, but
+ assembler listings may introduce empty frags), we must use
+ word mode. */
+ if (fragP->fr_symbol && S_GET_VALUE (fragP->fr_symbol) == 0)
{
- fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
- fragP->fr_var += 2;
+ fragS *l;
+
+ for (l = fragP->fr_next;
+ l != fragP->fr_symbol->sy_frag;
+ l = l->fr_next)
+ if (l->fr_fix + l->fr_var != 0)
+ break;
+ if (l == fragP->fr_symbol->sy_frag)
+ {
+ fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
+ fragP->fr_var += 2;
+ }
}
break;
default:
if (!need_pass_2) /* Never make frag if expect extra pass. */
frag_align (temp, (int) temp_fill);
demand_empty_rest_of_line ();
+ record_alignment (now_seg, temp);
}
static void
\f
/* Pseudo-ops handled for MRI compatibility. */
+/* This function returns non-zero if the argument is a conditional
+ pseudo-op. This is called when checking whether a pending
+ alignment is needed. */
+
+int
+m68k_conditional_pseudoop (pop)
+ pseudo_typeS *pop;
+{
+ return (pop->poc_handler == s_mri_if
+ || pop->poc_handler == s_mri_else);
+}
+
/* Handle an MRI style chip specification. */
static void
current_architecture |= m68851;
*input_line_pointer = c;
}
+
+ /* Update info about available control registers. */
+ select_control_regs ();
}
/* The MRI CHIP pseudo-op. */
s_chip (ignore)
int ignore;
{
+ char *stop = NULL;
+ char stopc;
+
+ if (flag_mri)
+ stop = mri_comment_field (&stopc);
mri_chip ();
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
demand_empty_rest_of_line ();
}
demand_empty_rest_of_line ();
}
-\f
-/*
- * md_parse_option
- * Invocation line includes a switch not recognized by the base assembler.
- * See if it's a processor-specific option. These are:
- *
- * -[A]m[c]68000, -[A]m[c]68008, -[A]m[c]68010, -[A]m[c]68020, -[A]m[c]68030, -[A]m[c]68040
- * -[A]m[c]68881, -[A]m[c]68882, -[A]m[c]68851
- * Select the architecture. Instructions or features not
- * supported by the selected architecture cause fatal
- * errors. More than one may be specified. The default is
- * -m68020 -m68851 -m68881. Note that -m68008 is a synonym
- * for -m68000, and -m68882 is a synonym for -m68881.
- * -[A]m[c]no-68851, -[A]m[c]no-68881
- * Don't accept 688?1 instructions. (The "c" is kind of silly,
- * so don't use or document it, but that's the way the parsing
- * works).
- *
- * -pic Indicates PIC.
- * -k Indicates PIC. (Sun 3 only.)
- *
- */
-#ifdef OBJ_ELF
-CONST char *md_shortopts = "lSA:m:kQ:V";
-#else
-CONST char *md_shortopts = "lSA:m:k";
-#endif
+/* The structure used to handle the MRI OPT pseudo-op. */
-struct option md_longopts[] = {
-#define OPTION_PIC (OPTION_MD_BASE)
- {"pic", no_argument, NULL, OPTION_PIC},
-#define OPTION_REGISTER_PREFIX_OPTIONAL (OPTION_MD_BASE + 1)
- {"register-prefix-optional", no_argument, NULL,
- OPTION_REGISTER_PREFIX_OPTIONAL},
- {NULL, no_argument, NULL, 0}
+struct opt_action
+{
+ /* The name of the option. */
+ const char *name;
+
+ /* If this is not NULL, just call this function. The first argument
+ is the ARG field of this structure, the second argument is
+ whether the option was negated. */
+ void (*pfn) PARAMS ((int arg, int on));
+
+ /* If this is not NULL, and the PFN field is NULL, set the variable
+ this points to. Set it to the ARG field if the option was not
+ negated, and the NOTARG field otherwise. */
+ int *pvar;
+
+ /* The value to pass to PFN or to assign to *PVAR. */
+ int arg;
+
+ /* The value to assign to *PVAR if the option is negated. If PFN is
+ NULL, and PVAR is not NULL, and ARG and NOTARG are the same, then
+ the option may not be negated. */
+ int notarg;
};
-size_t md_longopts_size = sizeof(md_longopts);
-int
-md_parse_option (c, arg)
- int c;
- char *arg;
+/* The table used to handle the MRI OPT pseudo-op. */
+
+static void skip_to_comma PARAMS ((int, int));
+static void opt_nest PARAMS ((int, int));
+static void opt_chip PARAMS ((int, int));
+static void opt_list PARAMS ((int, int));
+static void opt_list_symbols PARAMS ((int, int));
+
+static const struct opt_action opt_table[] =
{
- switch (c)
- {
- case 'l': /* -l means keep external to 2 bit offset
- rather than 16 bit one */
- flag_short_refs = 1;
- break;
+ { "abspcadd", 0, &m68k_abspcadd, 1, 0 },
+
+ /* We do relaxing, so there is little use for these options. */
+ { "b", 0, 0, 0, 0 },
+ { "brs", 0, 0, 0, 0 },
+ { "brb", 0, 0, 0, 0 },
+ { "brl", 0, 0, 0, 0 },
+ { "brw", 0, 0, 0, 0 },
+
+ { "c", 0, 0, 0, 0 },
+ { "cex", 0, 0, 0, 0 },
+ { "case", 0, &symbols_case_sensitive, 1, 0 },
+ { "cl", 0, 0, 0, 0 },
+ { "cre", 0, 0, 0, 0 },
+ { "d", 0, &flag_keep_locals, 1, 0 },
+ { "e", 0, 0, 0, 0 },
+ { "f", 0, &flag_short_refs, 1, 0 },
+ { "frs", 0, &flag_short_refs, 1, 0 },
+ { "frl", 0, &flag_short_refs, 0, 1 },
+ { "g", 0, 0, 0, 0 },
+ { "i", 0, 0, 0, 0 },
+ { "m", 0, 0, 0, 0 },
+ { "mex", 0, 0, 0, 0 },
+ { "mc", 0, 0, 0, 0 },
+ { "md", 0, 0, 0, 0 },
+ { "nest", opt_nest, 0, 0, 0 },
+ { "next", skip_to_comma, 0, 0, 0 },
+ { "o", 0, 0, 0, 0 },
+ { "old", 0, 0, 0, 0 },
+ { "op", skip_to_comma, 0, 0, 0 },
+ { "pco", 0, 0, 0, 0 },
+ { "p", opt_chip, 0, 0, 0 },
+ { "pcr", 0, 0, 0, 0 },
+ { "pcs", 0, 0, 0, 0 },
+ { "r", 0, 0, 0, 0 },
+ { "quick", 0, &m68k_quick, 1, 0 },
+ { "rel32", 0, &m68k_rel32, 1, 0 },
+ { "s", opt_list, 0, 0, 0 },
+ { "t", opt_list_symbols, 0, 0, 0 },
+ { "w", 0, &flag_no_warnings, 0, 1 },
+ { "x", 0, 0, 0, 0 }
+};
- case 'S': /* -S means that jbsr's always turn into
- jsr's. */
- flag_long_jumps = 1;
- break;
+#define OPTCOUNT (sizeof opt_table / sizeof opt_table[0])
- case 'A':
- if (*arg == 'm')
- arg++;
- /* intentional fall-through */
- case 'm':
+/* The MRI OPT pseudo-op. */
- if (arg[0] == 'n' && arg[1] == 'o' && arg[2] == '-')
+static void
+s_opt (ignore)
+ int ignore;
+{
+ do
+ {
+ int t;
+ char *s;
+ char c;
+ int i;
+ const struct opt_action *o;
+
+ SKIP_WHITESPACE ();
+
+ t = 1;
+ if (*input_line_pointer == '-')
{
- int i;
- unsigned long arch;
- const char *oarg = arg;
+ ++input_line_pointer;
+ t = 0;
+ }
+ else if (strncasecmp (input_line_pointer, "NO", 2) == 0)
+ {
+ input_line_pointer += 2;
+ t = 0;
+ }
- arg += 3;
- if (*arg == 'm')
+ s = input_line_pointer;
+ c = get_symbol_end ();
+
+ for (i = 0, o = opt_table; i < OPTCOUNT; i++, o++)
+ {
+ if (strcasecmp (s, o->name) == 0)
{
- arg++;
- if (arg[0] == 'c' && arg[1] == '6')
- arg++;
- }
- for (i = 0; i < n_archs; i++)
- if (!strcmp (arg, archs[i].name))
+ if (o->pfn)
+ {
+ /* Restore input_line_pointer now in case the option
+ takes arguments. */
+ *input_line_pointer = c;
+ (*o->pfn) (o->arg, t);
+ }
+ else if (o->pvar != NULL)
+ {
+ if (! t && o->arg == o->notarg)
+ as_bad ("option `%s' may not be negated", s);
+ *input_line_pointer = c;
+ *o->pvar = t ? o->arg : o->notarg;
+ }
+ else
+ *input_line_pointer = c;
break;
- if (i == n_archs)
- {
- unknown:
- as_bad ("unrecognized option `%s'", oarg);
+ }
+ }
+ if (i >= OPTCOUNT)
+ {
+ as_bad ("option `%s' not recognized", s);
+ *input_line_pointer = c;
+ }
+ }
+ while (*input_line_pointer++ == ',');
+
+ /* Move back to terminating character. */
+ --input_line_pointer;
+ demand_empty_rest_of_line ();
+}
+
+/* Skip ahead to a comma. This is used for OPT options which we do
+ not suppor tand which take arguments. */
+
+static void
+skip_to_comma (arg, on)
+ int arg;
+ int on;
+{
+ while (*input_line_pointer != ','
+ && ! is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+}
+
+/* Handle the OPT NEST=depth option. */
+
+static void
+opt_nest (arg, on)
+ int arg;
+ int on;
+{
+ if (*input_line_pointer != '=')
+ {
+ as_bad ("bad format of OPT NEST=depth");
+ return;
+ }
+
+ ++input_line_pointer;
+ max_macro_nest = get_absolute_expression ();
+}
+
+/* Handle the OPT P=chip option. */
+
+static void
+opt_chip (arg, on)
+ int arg;
+ int on;
+{
+ if (*input_line_pointer != '=')
+ {
+ /* This is just OPT P, which we do not support. */
+ return;
+ }
+
+ ++input_line_pointer;
+ mri_chip ();
+}
+
+/* Handle the OPT S option. */
+
+static void
+opt_list (arg, on)
+ int arg;
+ int on;
+{
+ listing_list (on);
+}
+
+/* Handle the OPT T option. */
+
+static void
+opt_list_symbols (arg, on)
+ int arg;
+ int on;
+{
+ if (on)
+ listing |= LISTING_SYMBOLS;
+ else
+ listing &=~ LISTING_SYMBOLS;
+}
+
+/* Handle the MRI REG pseudo-op. */
+
+static void
+s_reg (ignore)
+ int ignore;
+{
+ char *s;
+ int c;
+ struct m68k_op rop;
+ unsigned long mask;
+ char *stop = NULL;
+ char stopc;
+
+ if (line_label == NULL)
+ {
+ as_bad ("missing label");
+ ignore_rest_of_line ();
+ return;
+ }
+
+ if (flag_mri)
+ stop = mri_comment_field (&stopc);
+
+ SKIP_WHITESPACE ();
+
+ s = input_line_pointer;
+ while (isalnum ((unsigned char) *input_line_pointer)
+#ifdef REGISTER_PREFIX
+ || *input_line_pointer == REGISTER_PREFIX
+#endif
+ || *input_line_pointer == '/'
+ || *input_line_pointer == '-')
+ ++input_line_pointer;
+ c = *input_line_pointer;
+ *input_line_pointer = '\0';
+
+ if (m68k_ip_op (s, &rop) != 0)
+ {
+ if (rop.error == NULL)
+ as_bad ("bad register list");
+ else
+ as_bad ("bad register list: %s", rop.error);
+ *input_line_pointer = c;
+ ignore_rest_of_line ();
+ return;
+ }
+
+ *input_line_pointer = c;
+
+ if (rop.mode == REGLST)
+ mask = rop.mask;
+ else if (rop.mode == DREG)
+ mask = 1 << (rop.reg - DATA0);
+ else if (rop.mode == AREG)
+ mask = 1 << (rop.reg - ADDR0 + 8);
+ else if (rop.mode == FPREG)
+ mask = 1 << (rop.reg - FP0 + 16);
+ else if (rop.mode == CONTROL
+ && rop.reg == FPI)
+ mask = 1 << 24;
+ else if (rop.mode == CONTROL
+ && rop.reg == FPS)
+ mask = 1 << 25;
+ else if (rop.mode == CONTROL
+ && rop.reg == FPC)
+ mask = 1 << 26;
+ else
+ {
+ as_bad ("bad register list");
+ ignore_rest_of_line ();
+ return;
+ }
+
+ S_SET_SEGMENT (line_label, absolute_section);
+ S_SET_VALUE (line_label, mask);
+ line_label->sy_frag = &zero_address_frag;
+
+ if (flag_mri)
+ mri_comment_end (stop, stopc);
+
+ demand_empty_rest_of_line ();
+}
+
+/* This structure is used for the MRI SAVE and RESTORE pseudo-ops. */
+
+struct save_opts
+{
+ struct save_opts *next;
+ int abspcadd;
+ int symbols_case_sensitive;
+ int keep_locals;
+ int short_refs;
+ int architecture;
+ int quick;
+ int rel32;
+ int listing;
+ int no_warnings;
+ /* FIXME: We don't save OPT S. */
+};
+
+/* This variable holds the stack of saved options. */
+
+static struct save_opts *save_stack;
+
+/* The MRI SAVE pseudo-op. */
+
+static void
+s_save (ignore)
+ int ignore;
+{
+ struct save_opts *s;
+
+ s = (struct save_opts *) xmalloc (sizeof (struct save_opts));
+ s->abspcadd = m68k_abspcadd;
+ s->symbols_case_sensitive = symbols_case_sensitive;
+ s->keep_locals = flag_keep_locals;
+ s->short_refs = flag_short_refs;
+ s->architecture = current_architecture;
+ s->quick = m68k_quick;
+ s->rel32 = m68k_rel32;
+ s->listing = listing;
+ s->no_warnings = flag_no_warnings;
+
+ s->next = save_stack;
+ save_stack = s;
+
+ demand_empty_rest_of_line ();
+}
+
+/* The MRI RESTORE pseudo-op. */
+
+static void
+s_restore (ignore)
+ int ignore;
+{
+ struct save_opts *s;
+
+ if (save_stack == NULL)
+ {
+ as_bad ("restore without save");
+ ignore_rest_of_line ();
+ return;
+ }
+
+ s = save_stack;
+ save_stack = s->next;
+
+ m68k_abspcadd = s->abspcadd;
+ symbols_case_sensitive = s->symbols_case_sensitive;
+ flag_keep_locals = s->keep_locals;
+ flag_short_refs = s->short_refs;
+ current_architecture = s->architecture;
+ m68k_quick = s->quick;
+ m68k_rel32 = s->rel32;
+ listing = s->listing;
+ flag_no_warnings = s->no_warnings;
+
+ free (s);
+
+ demand_empty_rest_of_line ();
+}
+
+/* Types of MRI structured control directives. */
+
+enum mri_control_type
+{
+ mri_for,
+ mri_if,
+ mri_repeat,
+ mri_while
+};
+
+/* This structure is used to stack the MRI structured control
+ directives. */
+
+struct mri_control_info
+{
+ /* The directive within which this one is enclosed. */
+ struct mri_control_info *outer;
+
+ /* The type of directive. */
+ enum mri_control_type type;
+
+ /* Whether an ELSE has been in an IF. */
+ int else_seen;
+
+ /* The add or sub statement at the end of a FOR. */
+ char *incr;
+
+ /* The label of the top of a FOR or REPEAT loop. */
+ char *top;
+
+ /* The label to jump to for the next iteration, or the else
+ expression of a conditional. */
+ char *next;
+
+ /* The label to jump to to break out of the loop, or the label past
+ the end of a conditional. */
+ char *bottom;
+};
+
+/* The stack of MRI structured control directives. */
+
+static struct mri_control_info *mri_control_stack;
+
+/* The current MRI structured control directive index number, used to
+ generate label names. */
+
+static int mri_control_index;
+
+/* Some function prototypes. */
+
+static char *mri_control_label PARAMS ((void));
+static struct mri_control_info *push_mri_control
+ PARAMS ((enum mri_control_type));
+static void pop_mri_control PARAMS ((void));
+static int parse_mri_condition PARAMS ((int *));
+static int parse_mri_control_operand
+ PARAMS ((int *, char **, char **, char **, char **));
+static int swap_mri_condition PARAMS ((int));
+static int reverse_mri_condition PARAMS ((int));
+static void build_mri_control_operand
+ PARAMS ((int, int, char *, char *, char *, char *, const char *,
+ const char *, int));
+static void parse_mri_control_expression
+ PARAMS ((char *, int, const char *, const char *, int));
+
+/* Generate a new MRI label structured control directive label name. */
+
+static char *
+mri_control_label ()
+{
+ char *n;
+
+ n = (char *) xmalloc (20);
+ sprintf (n, "%smc%d", FAKE_LABEL_NAME, mri_control_index);
+ ++mri_control_index;
+ return n;
+}
+
+/* Create a new MRI structured control directive. */
+
+static struct mri_control_info *
+push_mri_control (type)
+ enum mri_control_type type;
+{
+ struct mri_control_info *n;
+
+ n = (struct mri_control_info *) xmalloc (sizeof (struct mri_control_info));
+
+ n->type = type;
+ n->else_seen = 0;
+ if (type == mri_if || type == mri_while)
+ n->top = NULL;
+ else
+ n->top = mri_control_label ();
+ n->next = mri_control_label ();
+ n->bottom = mri_control_label ();
+
+ n->outer = mri_control_stack;
+ mri_control_stack = n;
+
+ return n;
+}
+
+/* Pop off the stack of MRI structured control directives. */
+
+static void
+pop_mri_control ()
+{
+ struct mri_control_info *n;
+
+ n = mri_control_stack;
+ mri_control_stack = n->outer;
+ if (n->top != NULL)
+ free (n->top);
+ free (n->next);
+ free (n->bottom);
+ free (n);
+}
+
+/* Recognize a condition code in an MRI structured control expression. */
+
+static int
+parse_mri_condition (pcc)
+ int *pcc;
+{
+ char c1, c2;
+
+ know (*input_line_pointer == '<');
+
+ ++input_line_pointer;
+ c1 = *input_line_pointer++;
+ c2 = *input_line_pointer++;
+
+ if (*input_line_pointer != '>')
+ {
+ as_bad ("syntax error in structured control directive");
+ return 0;
+ }
+
+ ++input_line_pointer;
+ SKIP_WHITESPACE ();
+
+ if (isupper (c1))
+ c1 = tolower (c1);
+ if (isupper (c2))
+ c2 = tolower (c2);
+
+ *pcc = (c1 << 8) | c2;
+
+ return 1;
+}
+
+/* Parse a single operand in an MRI structured control expression. */
+
+static int
+parse_mri_control_operand (pcc, leftstart, leftstop, rightstart, rightstop)
+ int *pcc;
+ char **leftstart;
+ char **leftstop;
+ char **rightstart;
+ char **rightstop;
+{
+ char *s;
+
+ SKIP_WHITESPACE ();
+
+ *pcc = -1;
+ *leftstart = NULL;
+ *leftstop = NULL;
+ *rightstart = NULL;
+ *rightstop = NULL;
+
+ if (*input_line_pointer == '<')
+ {
+ /* It's just a condition code. */
+ return parse_mri_condition (pcc);
+ }
+
+ /* Look ahead for the condition code. */
+ for (s = input_line_pointer; *s != '\0'; ++s)
+ {
+ if (*s == '<' && s[1] != '\0' && s[2] != '\0' && s[3] == '>')
+ break;
+ }
+ if (*s == '\0')
+ {
+ as_bad ("missing condition code in structured control directive");
+ return 0;
+ }
+
+ *leftstart = input_line_pointer;
+ *leftstop = s;
+ if (*leftstop > *leftstart
+ && ((*leftstop)[-1] == ' ' || (*leftstop)[-1] == '\t'))
+ --*leftstop;
+
+ input_line_pointer = s;
+ if (! parse_mri_condition (pcc))
+ return 0;
+
+ /* Look ahead for AND or OR or end of line. */
+ for (s = input_line_pointer; *s != '\0'; ++s)
+ {
+ if ((strncasecmp (s, "AND", 3) == 0
+ && (s[3] == '.' || ! is_part_of_name (s[3])))
+ || (strncasecmp (s, "OR", 2) == 0
+ && (s[2] == '.' || ! is_part_of_name (s[2]))))
+ break;
+ }
+
+ *rightstart = input_line_pointer;
+ *rightstop = s;
+ if (*rightstop > *rightstart
+ && ((*rightstop)[-1] == ' ' || (*rightstop)[-1] == '\t'))
+ --*rightstop;
+
+ input_line_pointer = s;
+
+ return 1;
+}
+
+#define MCC(b1, b2) (((b1) << 8) | (b2))
+
+/* Swap the sense of a condition. This changes the condition so that
+ it generates the same result when the operands are swapped. */
+
+static int
+swap_mri_condition (cc)
+ int cc;
+{
+ switch (cc)
+ {
+ case MCC ('h', 'i'): return MCC ('c', 's');
+ case MCC ('l', 's'): return MCC ('c', 'c');
+ case MCC ('c', 'c'): return MCC ('l', 's');
+ case MCC ('c', 's'): return MCC ('h', 'i');
+ case MCC ('p', 'l'): return MCC ('m', 'i');
+ case MCC ('m', 'i'): return MCC ('p', 'l');
+ case MCC ('g', 'e'): return MCC ('l', 'e');
+ case MCC ('l', 't'): return MCC ('g', 't');
+ case MCC ('g', 't'): return MCC ('l', 't');
+ case MCC ('l', 'e'): return MCC ('g', 'e');
+ }
+ return cc;
+}
+
+/* Reverse the sense of a condition. */
+
+static int
+reverse_mri_condition (cc)
+ int cc;
+{
+ switch (cc)
+ {
+ case MCC ('h', 'i'): return MCC ('l', 's');
+ case MCC ('l', 's'): return MCC ('h', 'i');
+ case MCC ('c', 'c'): return MCC ('c', 's');
+ case MCC ('c', 's'): return MCC ('c', 'c');
+ case MCC ('n', 'e'): return MCC ('e', 'q');
+ case MCC ('e', 'q'): return MCC ('n', 'e');
+ case MCC ('v', 'c'): return MCC ('v', 's');
+ case MCC ('v', 's'): return MCC ('v', 'c');
+ case MCC ('p', 'l'): return MCC ('m', 'i');
+ case MCC ('m', 'i'): return MCC ('p', 'l');
+ case MCC ('g', 'e'): return MCC ('l', 't');
+ case MCC ('l', 't'): return MCC ('g', 'e');
+ case MCC ('g', 't'): return MCC ('l', 'e');
+ case MCC ('l', 'e'): return MCC ('g', 't');
+ }
+ return cc;
+}
+
+/* Build an MRI structured control expression. This generates test
+ and branch instructions. It goes to TRUELAB if the condition is
+ true, and to FALSELAB if the condition is false. Exactly one of
+ TRUELAB and FALSELAB will be NULL, meaning to fall through. QUAL
+ is the size qualifier for the expression. EXTENT is the size to
+ use for the branch. */
+
+static void
+build_mri_control_operand (qual, cc, leftstart, leftstop, rightstart,
+ rightstop, truelab, falselab, extent)
+ int qual;
+ int cc;
+ char *leftstart;
+ char *leftstop;
+ char *rightstart;
+ char *rightstop;
+ const char *truelab;
+ const char *falselab;
+ int extent;
+{
+ char *buf;
+ char *s;
+
+ if (leftstart != NULL)
+ {
+ struct m68k_op leftop, rightop;
+ char c;
+
+ /* Swap the compare operands, if necessary, to produce a legal
+ m68k compare instruction. Comparing a register operand with
+ a non-register operand requires the register to be on the
+ right (cmp, cmpa). Comparing an immediate value with
+ anything requires the immediate value to be on the left
+ (cmpi). */
+
+ c = *leftstop;
+ *leftstop = '\0';
+ (void) m68k_ip_op (leftstart, &leftop);
+ *leftstop = c;
+
+ c = *rightstop;
+ *rightstop = '\0';
+ (void) m68k_ip_op (rightstart, &rightop);
+ *rightstop = c;
+
+ if (rightop.mode == IMMED
+ || ((leftop.mode == DREG || leftop.mode == AREG)
+ && (rightop.mode != DREG && rightop.mode != AREG)))
+ {
+ char *temp;
+
+ cc = swap_mri_condition (cc);
+ temp = leftstart;
+ leftstart = rightstart;
+ rightstart = temp;
+ temp = leftstop;
+ leftstop = rightstop;
+ rightstop = temp;
+ }
+ }
+
+ if (truelab == NULL)
+ {
+ cc = reverse_mri_condition (cc);
+ truelab = falselab;
+ }
+
+ if (leftstart != NULL)
+ {
+ buf = (char *) xmalloc (20
+ + (leftstop - leftstart)
+ + (rightstop - rightstart));
+ s = buf;
+ *s++ = 'c';
+ *s++ = 'm';
+ *s++ = 'p';
+ if (qual != '\0')
+ *s++ = qual;
+ *s++ = ' ';
+ memcpy (s, leftstart, leftstop - leftstart);
+ s += leftstop - leftstart;
+ *s++ = ',';
+ memcpy (s, rightstart, rightstop - rightstart);
+ s += rightstop - rightstart;
+ *s = '\0';
+ md_assemble (buf);
+ free (buf);
+ }
+
+ buf = (char *) xmalloc (20 + strlen (truelab));
+ s = buf;
+ *s++ = 'b';
+ *s++ = cc >> 8;
+ *s++ = cc & 0xff;
+ if (extent != '\0')
+ *s++ = extent;
+ *s++ = ' ';
+ strcpy (s, truelab);
+ md_assemble (buf);
+ free (buf);
+}
+
+/* Parse an MRI structured control expression. This generates test
+ and branch instructions. STOP is where the expression ends. It
+ goes to TRUELAB if the condition is true, and to FALSELAB if the
+ condition is false. Exactly one of TRUELAB and FALSELAB will be
+ NULL, meaning to fall through. QUAL is the size qualifier for the
+ expression. EXTENT is the size to use for the branch. */
+
+static void
+parse_mri_control_expression (stop, qual, truelab, falselab, extent)
+ char *stop;
+ int qual;
+ const char *truelab;
+ const char *falselab;
+ int extent;
+{
+ int c;
+ int cc;
+ char *leftstart;
+ char *leftstop;
+ char *rightstart;
+ char *rightstop;
+
+ c = *stop;
+ *stop = '\0';
+
+ if (! parse_mri_control_operand (&cc, &leftstart, &leftstop,
+ &rightstart, &rightstop))
+ {
+ *stop = c;
+ return;
+ }
+
+ if (strncasecmp (input_line_pointer, "AND", 3) == 0)
+ {
+ const char *flab;
+
+ if (falselab != NULL)
+ flab = falselab;
+ else
+ flab = mri_control_label ();
+
+ build_mri_control_operand (qual, cc, leftstart, leftstop, rightstart,
+ rightstop, (const char *) NULL, flab, extent);
+
+ input_line_pointer += 3;
+ if (*input_line_pointer != '.'
+ || input_line_pointer[1] == '\0')
+ qual = '\0';
+ else
+ {
+ qual = input_line_pointer[1];
+ input_line_pointer += 2;
+ }
+
+ if (! parse_mri_control_operand (&cc, &leftstart, &leftstop,
+ &rightstart, &rightstop))
+ {
+ *stop = c;
+ return;
+ }
+
+ build_mri_control_operand (qual, cc, leftstart, leftstop, rightstart,
+ rightstop, truelab, falselab, extent);
+
+ if (falselab == NULL)
+ colon (flab);
+ }
+ else if (strncasecmp (input_line_pointer, "OR", 2) == 0)
+ {
+ const char *tlab;
+
+ if (truelab != NULL)
+ tlab = truelab;
+ else
+ tlab = mri_control_label ();
+
+ build_mri_control_operand (qual, cc, leftstart, leftstop, rightstart,
+ rightstop, tlab, (const char *) NULL, extent);
+
+ input_line_pointer += 2;
+ if (*input_line_pointer != '.'
+ || input_line_pointer[1] == '\0')
+ qual = '\0';
+ else
+ {
+ qual = input_line_pointer[1];
+ input_line_pointer += 2;
+ }
+
+ if (! parse_mri_control_operand (&cc, &leftstart, &leftstop,
+ &rightstart, &rightstop))
+ {
+ *stop = c;
+ return;
+ }
+
+ build_mri_control_operand (qual, cc, leftstart, leftstop, rightstart,
+ rightstop, truelab, falselab, extent);
+
+ if (truelab == NULL)
+ colon (tlab);
+ }
+ else
+ {
+ build_mri_control_operand (qual, cc, leftstart, leftstop, rightstart,
+ rightstop, truelab, falselab, extent);
+ }
+
+ *stop = c;
+ if (input_line_pointer != stop)
+ as_bad ("syntax error in structured control directive");
+}
+
+/* Handle the MRI IF pseudo-op. This may be a structured control
+ directive, or it may be a regular assembler conditional, depending
+ on its operands. */
+
+static void
+s_mri_if (qual)
+ int qual;
+{
+ char *s;
+ int c;
+ struct mri_control_info *n;
+
+ /* A structured control directive must end with THEN with an
+ optional qualifier. */
+ s = input_line_pointer;
+ while (! is_end_of_line[(unsigned char) *s]
+ && (! flag_mri || *s != '*'))
+ ++s;
+ --s;
+ while (s > input_line_pointer && (*s == ' ' || *s == '\t'))
+ --s;
+
+ if (s - input_line_pointer > 1
+ && s[-1] == '.')
+ s -= 2;
+
+ if (s - input_line_pointer < 3
+ || strncasecmp (s - 3, "THEN", 4) != 0)
+ {
+ if (qual != '\0')
+ {
+ as_bad ("missing then");
+ ignore_rest_of_line ();
+ return;
+ }
+
+ /* It's a conditional. */
+ s_if (O_ne);
+ return;
+ }
+
+ /* Since this might be a conditional if, this pseudo-op will be
+ called even if we are supported to be ignoring input. Double
+ check now. Clobber *input_line_pointer so that ignore_input
+ thinks that this is not a special pseudo-op. */
+ c = *input_line_pointer;
+ *input_line_pointer = 0;
+ if (ignore_input ())
+ {
+ *input_line_pointer = c;
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+ demand_empty_rest_of_line ();
+ return;
+ }
+ *input_line_pointer = c;
+
+ n = push_mri_control (mri_if);
+
+ parse_mri_control_expression (s - 3, qual, (const char *) NULL,
+ n->next, s[1] == '.' ? s[2] : '\0');
+
+ if (s[1] == '.')
+ input_line_pointer = s + 3;
+ else
+ input_line_pointer = s + 1;
+
+ if (flag_mri)
+ {
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+ }
+
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI else pseudo-op. If we are currently doing an MRI
+ structured IF, associate the ELSE with the IF. Otherwise, assume
+ it is a conditional else. */
+
+static void
+s_mri_else (qual)
+ int qual;
+{
+ int c;
+ char *buf;
+ char q[2];
+
+ if (qual == '\0'
+ && (mri_control_stack == NULL
+ || mri_control_stack->type != mri_if
+ || mri_control_stack->else_seen))
+ {
+ s_else (0);
+ return;
+ }
+
+ c = *input_line_pointer;
+ *input_line_pointer = 0;
+ if (ignore_input ())
+ {
+ *input_line_pointer = c;
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+ demand_empty_rest_of_line ();
+ return;
+ }
+ *input_line_pointer = c;
+
+ if (mri_control_stack == NULL
+ || mri_control_stack->type != mri_if
+ || mri_control_stack->else_seen)
+ {
+ as_bad ("else without matching if");
+ ignore_rest_of_line ();
+ return;
+ }
+
+ mri_control_stack->else_seen = 1;
+
+ buf = (char *) xmalloc (20 + strlen (mri_control_stack->bottom));
+ q[0] = qual;
+ q[1] = '\0';
+ sprintf (buf, "bra%s %s", q, mri_control_stack->bottom);
+ md_assemble (buf);
+ free (buf);
+
+ colon (mri_control_stack->next);
+
+ if (flag_mri)
+ {
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+ }
+
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI ENDI pseudo-op. */
+
+static void
+s_mri_endi (ignore)
+ int ignore;
+{
+ if (mri_control_stack == NULL
+ || mri_control_stack->type != mri_if)
+ {
+ as_bad ("endi without matching if");
+ ignore_rest_of_line ();
+ return;
+ }
+
+ /* ignore_input will not return true for ENDI, so we don't need to
+ worry about checking it again here. */
+
+ if (! mri_control_stack->else_seen)
+ colon (mri_control_stack->next);
+ colon (mri_control_stack->bottom);
+
+ pop_mri_control ();
+
+ if (flag_mri)
+ {
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+ }
+
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI BREAK pseudo-op. */
+
+static void
+s_mri_break (extent)
+ int extent;
+{
+ struct mri_control_info *n;
+ char *buf;
+ char ex[2];
+
+ n = mri_control_stack;
+ while (n != NULL
+ && n->type != mri_for
+ && n->type != mri_repeat
+ && n->type != mri_while)
+ n = n->outer;
+ if (n == NULL)
+ {
+ as_bad ("break outside of structured loop");
+ ignore_rest_of_line ();
+ return;
+ }
+
+ buf = (char *) xmalloc (20 + strlen (n->bottom));
+ ex[0] = extent;
+ ex[1] = '\0';
+ sprintf (buf, "bra%s %s", ex, n->bottom);
+ md_assemble (buf);
+ free (buf);
+
+ if (flag_mri)
+ {
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+ }
+
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI NEXT pseudo-op. */
+
+static void
+s_mri_next (extent)
+ int extent;
+{
+ struct mri_control_info *n;
+ char *buf;
+ char ex[2];
+
+ n = mri_control_stack;
+ while (n != NULL
+ && n->type != mri_for
+ && n->type != mri_repeat
+ && n->type != mri_while)
+ n = n->outer;
+ if (n == NULL)
+ {
+ as_bad ("next outside of structured loop");
+ ignore_rest_of_line ();
+ return;
+ }
+
+ buf = (char *) xmalloc (20 + strlen (n->next));
+ ex[0] = extent;
+ ex[1] = '\0';
+ sprintf (buf, "bra%s %s", ex, n->next);
+ md_assemble (buf);
+ free (buf);
+
+ if (flag_mri)
+ {
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+ }
+
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI FOR pseudo-op. */
+
+static void
+s_mri_for (qual)
+ int qual;
+{
+ const char *varstart, *varstop;
+ const char *initstart, *initstop;
+ const char *endstart, *endstop;
+ const char *bystart, *bystop;
+ int up;
+ int by;
+ int extent;
+ struct mri_control_info *n;
+ char *buf;
+ char *s;
+ char ex[2];
+
+ /* The syntax is
+ FOR.q var = init { TO | DOWNTO } end [ BY by ] DO.e
+ */
+
+ SKIP_WHITESPACE ();
+ varstart = input_line_pointer;
+
+ /* Look for the '='. */
+ while (! is_end_of_line[(unsigned char) *input_line_pointer]
+ && *input_line_pointer != '=')
+ ++input_line_pointer;
+ if (*input_line_pointer != '=')
+ {
+ as_bad ("missing =");
+ ignore_rest_of_line ();
+ return;
+ }
+
+ varstop = input_line_pointer;
+ if (varstop > varstart
+ && (varstop[-1] == ' ' || varstop[-1] == '\t'))
+ --varstop;
+
+ ++input_line_pointer;
+
+ initstart = input_line_pointer;
+
+ /* Look for TO or DOWNTO. */
+ up = 1;
+ initstop = NULL;
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ {
+ if (strncasecmp (input_line_pointer, "TO", 2) == 0
+ && ! is_part_of_name (input_line_pointer[2]))
+ {
+ initstop = input_line_pointer;
+ input_line_pointer += 2;
+ break;
+ }
+ if (strncasecmp (input_line_pointer, "DOWNTO", 6) == 0
+ && ! is_part_of_name (input_line_pointer[6]))
+ {
+ initstop = input_line_pointer;
+ up = 0;
+ input_line_pointer += 6;
+ break;
+ }
+ ++input_line_pointer;
+ }
+ if (initstop == NULL)
+ {
+ as_bad ("missing to or downto");
+ ignore_rest_of_line ();
+ return;
+ }
+ if (initstop > initstart
+ && (initstop[-1] == ' ' || initstop[-1] == '\t'))
+ --initstop;
+
+ SKIP_WHITESPACE ();
+ endstart = input_line_pointer;
+
+ /* Look for BY or DO. */
+ by = 0;
+ endstop = NULL;
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ {
+ if (strncasecmp (input_line_pointer, "BY", 2) == 0
+ && ! is_part_of_name (input_line_pointer[2]))
+ {
+ endstop = input_line_pointer;
+ by = 1;
+ input_line_pointer += 2;
+ break;
+ }
+ if (strncasecmp (input_line_pointer, "DO", 2) == 0
+ && (input_line_pointer[2] == '.'
+ || ! is_part_of_name (input_line_pointer[2])))
+ {
+ endstop = input_line_pointer;
+ input_line_pointer += 2;
+ break;
+ }
+ ++input_line_pointer;
+ }
+ if (endstop == NULL)
+ {
+ as_bad ("missing do");
+ ignore_rest_of_line ();
+ return;
+ }
+ if (endstop > endstart
+ && (endstop[-1] == ' ' || endstop[-1] == '\t'))
+ --endstop;
+
+ if (! by)
+ {
+ bystart = "#1";
+ bystop = bystart + 2;
+ }
+ else
+ {
+ SKIP_WHITESPACE ();
+ bystart = input_line_pointer;
+
+ /* Look for DO. */
+ bystop = NULL;
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ {
+ if (strncasecmp (input_line_pointer, "DO", 2) == 0
+ && (input_line_pointer[2] == '.'
+ || ! is_part_of_name (input_line_pointer[2])))
+ {
+ bystop = input_line_pointer;
+ input_line_pointer += 2;
+ break;
+ }
+ ++input_line_pointer;
+ }
+ if (bystop == NULL)
+ {
+ as_bad ("missing do");
+ ignore_rest_of_line ();
+ return;
+ }
+ if (bystop > bystart
+ && (bystop[-1] == ' ' || bystop[-1] == '\t'))
+ --bystop;
+ }
+
+ if (*input_line_pointer != '.')
+ extent = '\0';
+ else
+ {
+ extent = input_line_pointer[1];
+ input_line_pointer += 2;
+ }
+
+ /* We have fully parsed the FOR operands. Now build the loop. */
+
+ n = push_mri_control (mri_for);
+
+ buf = (char *) xmalloc (50 + (input_line_pointer - varstart));
+
+ /* move init,var */
+ s = buf;
+ *s++ = 'm';
+ *s++ = 'o';
+ *s++ = 'v';
+ *s++ = 'e';
+ if (qual != '\0')
+ *s++ = qual;
+ *s++ = ' ';
+ memcpy (s, initstart, initstop - initstart);
+ s += initstop - initstart;
+ *s++ = ',';
+ memcpy (s, varstart, varstop - varstart);
+ s += varstop - varstart;
+ *s = '\0';
+ md_assemble (buf);
+
+ colon (n->top);
+
+ /* cmp end,var */
+ s = buf;
+ *s++ = 'c';
+ *s++ = 'm';
+ *s++ = 'p';
+ if (qual != '\0')
+ *s++ = qual;
+ *s++ = ' ';
+ memcpy (s, endstart, endstop - endstart);
+ s += endstop - endstart;
+ *s++ = ',';
+ memcpy (s, varstart, varstop - varstart);
+ s += varstop - varstart;
+ *s = '\0';
+ md_assemble (buf);
+
+ /* bcc bottom */
+ ex[0] = extent;
+ ex[1] = '\0';
+ if (up)
+ sprintf (buf, "blt%s %s", ex, n->bottom);
+ else
+ sprintf (buf, "bgt%s %s", ex, n->bottom);
+ md_assemble (buf);
+
+ /* Put together the add or sub instruction used by ENDF. */
+ s = buf;
+ if (up)
+ strcpy (s, "add");
+ else
+ strcpy (s, "sub");
+ s += 3;
+ if (qual != '\0')
+ *s++ = qual;
+ *s++ = ' ';
+ memcpy (s, bystart, bystop - bystart);
+ s += bystop - bystart;
+ *s++ = ',';
+ memcpy (s, varstart, varstop - varstart);
+ s += varstop - varstart;
+ *s = '\0';
+ n->incr = buf;
+
+ if (flag_mri)
+ {
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+ }
+
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI ENDF pseudo-op. */
+
+static void
+s_mri_endf (ignore)
+ int ignore;
+{
+ if (mri_control_stack == NULL
+ || mri_control_stack->type != mri_for)
+ {
+ as_bad ("endf without for");
+ ignore_rest_of_line ();
+ return;
+ }
+
+ colon (mri_control_stack->next);
+
+ md_assemble (mri_control_stack->incr);
+
+ sprintf (mri_control_stack->incr, "bra %s", mri_control_stack->top);
+ md_assemble (mri_control_stack->incr);
+
+ free (mri_control_stack->incr);
+
+ colon (mri_control_stack->bottom);
+
+ pop_mri_control ();
+
+ if (flag_mri)
+ {
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+ }
+
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI REPEAT pseudo-op. */
+
+static void
+s_mri_repeat (ignore)
+ int ignore;
+{
+ struct mri_control_info *n;
+
+ n = push_mri_control (mri_repeat);
+ colon (n->top);
+ if (flag_mri)
+ {
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+ }
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI UNTIL pseudo-op. */
+
+static void
+s_mri_until (qual)
+ int qual;
+{
+ char *s;
+
+ if (mri_control_stack == NULL
+ || mri_control_stack->type != mri_repeat)
+ {
+ as_bad ("until without repeat");
+ ignore_rest_of_line ();
+ return;
+ }
+
+ colon (mri_control_stack->next);
+
+ for (s = input_line_pointer; ! is_end_of_line[(unsigned char) *s]; s++)
+ ;
+
+ parse_mri_control_expression (s, qual, (const char *) NULL,
+ mri_control_stack->top, '\0');
+
+ colon (mri_control_stack->bottom);
+
+ input_line_pointer = s;
+
+ pop_mri_control ();
+
+ if (flag_mri)
+ {
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+ }
+
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI WHILE pseudo-op. */
+
+static void
+s_mri_while (qual)
+ int qual;
+{
+ char *s;
+
+ struct mri_control_info *n;
+
+ s = input_line_pointer;
+ while (! is_end_of_line[(unsigned char) *s]
+ && (! flag_mri || *s != '*'))
+ s++;
+ --s;
+ while (*s == ' ' || *s == '\t')
+ --s;
+ if (s - input_line_pointer > 1
+ && s[-1] == '.')
+ s -= 2;
+ if (s - input_line_pointer < 2
+ || strncasecmp (s - 1, "DO", 2) != 0)
+ {
+ as_bad ("missing do");
+ ignore_rest_of_line ();
+ return;
+ }
+
+ n = push_mri_control (mri_while);
+
+ colon (n->next);
+
+ parse_mri_control_expression (s - 1, qual, (const char *) NULL, n->bottom,
+ s[1] == '.' ? s[2] : '\0');
+
+ input_line_pointer = s + 1;
+ if (*input_line_pointer == '.')
+ input_line_pointer += 2;
+
+ if (flag_mri)
+ {
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+ }
+
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI ENDW pseudo-op. */
+
+static void
+s_mri_endw (ignore)
+ int ignore;
+{
+ char *buf;
+
+ if (mri_control_stack == NULL
+ || mri_control_stack->type != mri_while)
+ {
+ as_bad ("endw without while");
+ ignore_rest_of_line ();
+ return;
+ }
+
+ buf = (char *) xmalloc (20 + strlen (mri_control_stack->next));
+ sprintf (buf, "bra %s", mri_control_stack->next);
+ md_assemble (buf);
+ free (buf);
+
+ colon (mri_control_stack->bottom);
+
+ pop_mri_control ();
+
+ if (flag_mri)
+ {
+ while (! is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+ }
+
+ demand_empty_rest_of_line ();
+}
+\f
+/*
+ * md_parse_option
+ * Invocation line includes a switch not recognized by the base assembler.
+ * See if it's a processor-specific option. These are:
+ *
+ * -[A]m[c]68000, -[A]m[c]68008, -[A]m[c]68010, -[A]m[c]68020, -[A]m[c]68030, -[A]m[c]68040
+ * -[A]m[c]68881, -[A]m[c]68882, -[A]m[c]68851
+ * Select the architecture. Instructions or features not
+ * supported by the selected architecture cause fatal
+ * errors. More than one may be specified. The default is
+ * -m68020 -m68851 -m68881. Note that -m68008 is a synonym
+ * for -m68000, and -m68882 is a synonym for -m68881.
+ * -[A]m[c]no-68851, -[A]m[c]no-68881
+ * Don't accept 688?1 instructions. (The "c" is kind of silly,
+ * so don't use or document it, but that's the way the parsing
+ * works).
+ *
+ * -pic Indicates PIC.
+ * -k Indicates PIC. (Sun 3 only.)
+ *
+ * --bitwise-or
+ * Permit `|' to be used in expressions.
+ *
+ */
+
+#ifdef OBJ_ELF
+CONST char *md_shortopts = "lSA:m:kQ:V";
+#else
+CONST char *md_shortopts = "lSA:m:k";
+#endif
+
+struct option md_longopts[] = {
+#define OPTION_PIC (OPTION_MD_BASE)
+ {"pic", no_argument, NULL, OPTION_PIC},
+#define OPTION_REGISTER_PREFIX_OPTIONAL (OPTION_MD_BASE + 1)
+ {"register-prefix-optional", no_argument, NULL,
+ OPTION_REGISTER_PREFIX_OPTIONAL},
+#define OPTION_BITWISE_OR (OPTION_MD_BASE + 2)
+ {"bitwise-or", no_argument, NULL, OPTION_BITWISE_OR},
+#define OPTION_BASE_SIZE_DEFAULT_16 (OPTION_MD_BASE + 3)
+ {"base-size-default-16", no_argument, NULL, OPTION_BASE_SIZE_DEFAULT_16},
+#define OPTION_BASE_SIZE_DEFAULT_32 (OPTION_MD_BASE + 4)
+ {"base-size-default-32", no_argument, NULL, OPTION_BASE_SIZE_DEFAULT_32},
+#define OPTION_DISP_SIZE_DEFAULT_16 (OPTION_MD_BASE + 5)
+ {"disp-size-default-16", no_argument, NULL, OPTION_DISP_SIZE_DEFAULT_16},
+#define OPTION_DISP_SIZE_DEFAULT_32 (OPTION_MD_BASE + 6)
+ {"disp-size-default-32", no_argument, NULL, OPTION_DISP_SIZE_DEFAULT_32},
+ {NULL, no_argument, NULL, 0}
+};
+size_t md_longopts_size = sizeof(md_longopts);
+
+int
+md_parse_option (c, arg)
+ int c;
+ char *arg;
+{
+ switch (c)
+ {
+ case 'l': /* -l means keep external to 2 bit offset
+ rather than 16 bit one */
+ flag_short_refs = 1;
+ break;
+
+ case 'S': /* -S means that jbsr's always turn into
+ jsr's. */
+ flag_long_jumps = 1;
+ break;
+
+ case 'A':
+ if (*arg == 'm')
+ arg++;
+ /* intentional fall-through */
+ case 'm':
+
+ if (arg[0] == 'n' && arg[1] == 'o' && arg[2] == '-')
+ {
+ int i;
+ unsigned long arch;
+ const char *oarg = arg;
+
+ arg += 3;
+ if (*arg == 'm')
+ {
+ arg++;
+ if (arg[0] == 'c' && arg[1] == '6')
+ arg++;
+ }
+ for (i = 0; i < n_archs; i++)
+ if (!strcmp (arg, archs[i].name))
+ break;
+ if (i == n_archs)
+ {
+ unknown:
+ as_bad ("unrecognized option `%s'", oarg);
return 0;
}
arch = archs[i].arch;
case OPTION_REGISTER_PREFIX_OPTIONAL:
flag_reg_prefix_optional = 1;
+ reg_prefix_optional_seen = 1;
break;
- case 'Q':
+ /* -V: SVR4 argument to print version ID. */
case 'V':
+ print_version_id ();
+ break;
+
+ /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section
+ should be emitted or not. FIXME: Not implemented. */
+ case 'Q':
+ break;
+
+ case OPTION_BITWISE_OR:
+ {
+ char *n, *t;
+ const char *s;
+
+ n = (char *) xmalloc (strlen (m68k_comment_chars) + 1);
+ t = n;
+ for (s = m68k_comment_chars; *s != '\0'; s++)
+ if (*s != '|')
+ *t++ = *s;
+ *t = '\0';
+ m68k_comment_chars = n;
+ }
+ break;
+
+ case OPTION_BASE_SIZE_DEFAULT_16:
+ m68k_index_width_default = SIZE_WORD;
+ break;
+
+ case OPTION_BASE_SIZE_DEFAULT_32:
+ m68k_index_width_default = SIZE_LONG;
+ break;
+
+ case OPTION_DISP_SIZE_DEFAULT_16:
+ m68k_rel32 = 0;
+ m68k_rel32_from_cmdline = 1;
+ break;
+
+ case OPTION_DISP_SIZE_DEFAULT_32:
+ m68k_rel32 = 1;
+ m68k_rel32_from_cmdline = 1;
break;
default:
-l use 1 word for refs to undefined symbols [default 2]\n\
-m68000 | -m68008 | -m68010 | -m68020 | -m68030 | -m68040 | -m68060\n\
| -m68302 | -m68331 | -m68332 | -m68333 | -m68340 | -m68360\n\
- | -mcpu32\n\
+ | -mcpu32 | -m5200\n\
specify variant of 680X0 architecture [default 68020]\n\
-m68881 | -m68882 | -mno-68881 | -mno-68882\n\
target has/lacks floating-point coprocessor\n\
- [default yes for 68020, 68030, and cpu32]\n\
+ [default yes for 68020, 68030, and cpu32]\n");
+ fprintf(stream, "\
-m68851 | -mno-68851\n\
target has/lacks memory-management unit coprocessor\n\
[default yes for 68020 and up]\n\
-pic, -k generate position independent code\n\
-S turn jbsr into jsr\n\
--register-prefix-optional\n\
- recognize register names without prefix character\n");
+ recognize register names without prefix character\n\
+--bitwise-or do not treat `|' as a comment character\n");
+ fprintf (stream, "\
+--base-size-default-16 base reg without size is 16 bits\n\
+--base-size-default-32 base reg without size is 32 bits (default)\n\
+--disp-size-default-16 displacement with unknown size is 16 bits\n\
+--disp-size-default-32 displacement with unknown size is 32 bits (default)\n");
}
\f
#ifdef TEST2
md_pcrel_from (fixP)
fixS *fixP;
{
- return (fixP->fx_where + fixP->fx_frag->fr_address - fixP->fx_pcrel_adjust);
+ int adjust;
+
+ /* Because fx_pcrel_adjust is a char, and may be unsigned, we store
+ -1 as 64. */
+ adjust = fixP->fx_pcrel_adjust;
+ if (adjust == 64)
+ adjust = -1;
+ return fixP->fx_where + fixP->fx_frag->fr_address - adjust;
}
#ifndef BFD_ASSEMBLER