#include "as.h"
#include "safe-ctype.h"
#include "obstack.h"
#include "subsegs.h"
#include "dwarf2dbg.h"
#include "dw2gencfi.h"
#include "opcode/m68k.h"
#include "m68k-parse.h"
#if defined (OBJ_ELF)
#include "elf/m68k.h"
#endif
#ifdef M68KCOFF
#include "obj-coff.h"
#endif
#if defined (TE_SVR4) || defined (TE_DELTA)
const char *m68k_comment_chars = "|#";
#else
const char *m68k_comment_chars = "|";
#endif
const char line_comment_chars[] = "#*";
const char line_separator_chars[] = ";";
const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "rRsSfFdDxXeEpP";
const int md_reloc_size = 8;
int flag_want_pic;
static int flag_short_refs;
static int flag_long_jumps;
static int flag_keep_pcrel;
#ifdef REGISTER_PREFIX_OPTIONAL
int flag_reg_prefix_optional = REGISTER_PREFIX_OPTIONAL;
#else
int flag_reg_prefix_optional;
#endif
static int reg_prefix_optional_seen;
static enum m68k_register m68k_float_copnum = COP1;
static int m68k_abspcadd;
static int m68k_quick = 1;
static int m68k_rel32 = 1;
static int m68k_rel32_from_cmdline;
static enum m68k_size m68k_index_width_default = SIZE_LONG;
struct label_line
{
struct label_line *next;
symbolS *label;
char *file;
unsigned int line;
int text;
};
static struct label_line *labels;
static struct label_line *current_label;
static struct m68k_opcode const ** m68k_sorted_opcodes;
static struct obstack robyn;
struct m68k_incant
{
const char *m_operands;
unsigned long m_opcode;
short m_opnum;
short m_codenum;
int m_arch;
struct m68k_incant *m_next;
};
#define getone(x) ((((x)->m_opcode)>>16)&0xffff)
#define gettwo(x) (((x)->m_opcode)&0xffff)
static const enum m68k_register m68000_control_regs[] = { 0 };
static const enum m68k_register m68010_control_regs[] = {
SFC, DFC, USP, VBR,
0
};
static const enum m68k_register m68020_control_regs[] = {
SFC, DFC, USP, VBR, CACR, CAAR, MSP, ISP,
0
};
static const enum m68k_register m68040_control_regs[] = {
SFC, DFC, CACR, TC, ITT0, ITT1, DTT0, DTT1,
USP, VBR, MSP, ISP, MMUSR, URP, SRP,
0
};
static const enum m68k_register m68060_control_regs[] = {
SFC, DFC, CACR, TC, ITT0, ITT1, DTT0, DTT1, BUSCR,
USP, VBR, URP, SRP, PCR,
0
};
static const enum m68k_register mcf_control_regs[] = {
CACR, TC, ACR0, ACR1, ACR2, ACR3, VBR, ROMBAR,
RAMBAR0, RAMBAR1, MBAR,
0
};
static const enum m68k_register mcf5249_control_regs[] = {
CACR, ACR0, ACR1, VBR, RAMBAR0, RAMBAR1, MBAR, MBAR2,
0
};
static const enum m68k_register mcf528x_control_regs[] = {
CACR, ACR0, ACR1, VBR, FLASHBAR, RAMBAR,
0
};
static const enum m68k_register mcfv4e_control_regs[] = {
CACR, TC, ITT0, ITT1, DTT0, DTT1, BUSCR, VBR, PC, ROMBAR,
ROMBAR1, RAMBAR0, RAMBAR1, MPCR, EDRAMBAR, SECMBAR, MBAR, MBAR0, MBAR1,
PCR1U0, PCR1L0, PCR1U1, PCR1L1, PCR2U0, PCR2L0, PCR2U1, PCR2L1,
PCR3U0, PCR3L0, PCR3U1, PCR3L1,
0
};
#define cpu32_control_regs m68010_control_regs
static const enum m68k_register *control_regs;
struct m68k_it
{
const char *error;
const char *args;
int numargs;
int numo;
short opcode[11];
struct m68k_op operands[6];
int nexp;
struct m68k_exp exprs[4];
int nfrag;
struct
{
int fragoff;
symbolS *fadd;
offsetT foff;
int fragty;
}
fragb[4];
int nrel;
struct
{
int n;
expressionS exp;
char wid;
char pcrel;
int pcrel_fix;
#ifdef OBJ_ELF
enum pic_relocation pic_reloc;
#endif
}
reloc[5];
};
#define cpu_of_arch(x) ((x) & (m68000up | mcfisa_a))
#define float_of_arch(x) ((x) & mfloat)
#define mmu_of_arch(x) ((x) & mmmu)
#define arch_coldfire_p(x) ((x) & mcfisa_a)
#define arch_coldfire_fpu(x) ((x) & cfloat)
#define HAVE_LONG_BRANCH(x) ((x) & (m68020|m68030|m68040|m68060|cpu32|mcfisa_b))
static struct m68k_it the_ins;
#define op(ex) ((ex)->exp.X_op)
#define adds(ex) ((ex)->exp.X_add_symbol)
#define subs(ex) ((ex)->exp.X_op_symbol)
#define offs(ex) ((ex)->exp.X_add_number)
#define addword(w) (the_ins.opcode[the_ins.numo++] = (w))
static void
insop (int w, const struct m68k_incant *opcode)
{
int z;
for (z = the_ins.numo; z > opcode->m_codenum; --z)
the_ins.opcode[z] = the_ins.opcode[z - 1];
for (z = 0; z < the_ins.nrel; z++)
the_ins.reloc[z].n += 2;
for (z = 0; z < the_ins.nfrag; z++)
the_ins.fragb[z].fragoff++;
the_ins.opcode[opcode->m_codenum] = w;
the_ins.numo++;
}
static void
add_fix (int width, struct m68k_exp *exp, int pc_rel, int pc_fix)
{
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.numo * 2));
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
add_frag (symbolS *add, offsetT off, int type)
{
the_ins.fragb[the_ins.nfrag].fragoff = the_ins.numo;
the_ins.fragb[the_ins.nfrag].fadd = add;
the_ins.fragb[the_ins.nfrag].foff = off;
the_ins.fragb[the_ins.nfrag++].fragty = type;
}
#define isvar(ex) \
(op (ex) != O_constant && op (ex) != O_big)
static char *crack_operand (char *str, struct m68k_op *opP);
static int get_num (struct m68k_exp *exp, int ok);
static int reverse_16_bits (int in);
static int reverse_8_bits (int in);
static void install_gen_operand (int mode, int val);
static void install_operand (int mode, int val);
static void s_bss (int);
static void s_data1 (int);
static void s_data2 (int);
static void s_even (int);
static void s_proc (int);
static void s_chip (int);
static void s_fopt (int);
static void s_opt (int);
static void s_reg (int);
static void s_restore (int);
static void s_save (int);
static void s_mri_if (int);
static void s_mri_else (int);
static void s_mri_endi (int);
static void s_mri_break (int);
static void s_mri_next (int);
static void s_mri_for (int);
static void s_mri_endf (int);
static void s_mri_repeat (int);
static void s_mri_until (int);
static void s_mri_while (int);
static void s_mri_endw (int);
static int current_architecture;
static int current_chip;
struct m68k_cpu
{
unsigned long arch;
unsigned long chip;
const char *name;
int alias;
};
static const struct m68k_cpu archs[] =
{
{ m68000, m68000, "68000", 0 },
{ m68010, m68010, "68010", 0 },
{ m68020, m68020, "68020", 0 },
{ m68030, m68030, "68030", 0 },
{ m68040, m68040, "68040", 0 },
{ m68060, m68060, "68060", 0 },
{ cpu32, cpu32, "cpu32", 0 },
{ m68881, m68881, "68881", 0 },
{ m68851, m68851, "68851", 0 },
{ mcfisa_a, mcf5200, "5200", 0 },
{ mcfisa_a|mcfhwdiv|mcfmac, mcf5206e, "5206e", 0 },
{ mcfisa_a|mcfisa_aa|mcfhwdiv|mcfemac|mcfusp, mcf521x, "521x", 0 },
{ mcfisa_a|mcfhwdiv|mcfemac, mcf5249, "5249", 0 },
{ mcfisa_a|mcfisa_aa|mcfhwdiv|mcfemac|mcfusp, mcf528x, "528x", 0 },
{ mcfisa_a|mcfhwdiv|mcfmac, mcf5307, "5307", 0 },
{ mcfisa_a|mcfhwdiv|mcfisa_b|mcfmac, mcf5407, "5407", 0 },
{ mcfisa_a|mcfhwdiv|mcfisa_b|mcfemac|mcfusp|cfloat, mcf5470, "547x", 0 },
{ mcfisa_a|mcfhwdiv|mcfisa_b|mcfemac|mcfusp|cfloat, mcf5480, "548x", 0 },
{ m68020, m68020, "68k", 1 },
{ m68000, m68000, "68008", 1 },
{ m68000, m68000, "68302", 1 },
{ m68000, m68000, "68306", 1 },
{ m68000, m68000, "68307", 1 },
{ m68000, m68000, "68322", 1 },
{ m68000, m68000, "68356", 1 },
{ m68000, m68000, "68ec000", 1 },
{ m68000, m68000, "68hc000", 1 },
{ m68000, m68000, "68hc001", 1 },
{ m68020, m68020, "68ec020", 1 },
{ m68030, m68030, "68ec030", 1 },
{ m68040, m68040, "68ec040", 1 },
{ m68060, m68060, "68ec060", 1 },
{ cpu32, cpu32, "68330", 1 },
{ cpu32, cpu32, "68331", 1 },
{ cpu32, cpu32, "68332", 1 },
{ cpu32, cpu32, "68333", 1 },
{ cpu32, cpu32, "68334", 1 },
{ cpu32, cpu32, "68336", 1 },
{ cpu32, cpu32, "68340", 1 },
{ cpu32, cpu32, "68341", 1 },
{ cpu32, cpu32, "68349", 1 },
{ cpu32, cpu32, "68360", 1 },
{ m68881, m68881, "68882", 1 },
{ mcfisa_a, mcf5200, "5202", 1 },
{ mcfisa_a, mcf5200, "5204", 1 },
{ mcfisa_a, mcf5200, "5206", 1 },
{ mcfisa_a|mcfhwdiv|mcfisa_aa|mcfemac, mcf521x, "5214", 1 },
{ mcfisa_a|mcfhwdiv|mcfisa_aa|mcfemac, mcf521x, "5216", 1 },
{ mcfisa_a|mcfisa_aa|mcfhwdiv|mcfemac, mcf528x, "5280", 1 },
{ mcfisa_a|mcfisa_aa|mcfhwdiv|mcfemac, mcf528x, "5281", 1 },
{ mcfisa_a|mcfisa_aa|mcfhwdiv|mcfemac, mcf528x, "5282", 1 },
{ mcfisa_a|mcfhwdiv|mcfisa_b|mcfmac, mcf5407, "cfv4", 1 },
{ mcfisa_a|mcfhwdiv|mcfisa_b|mcfemac|mcfusp|cfloat, mcf5470, "5470", 1 },
{ mcfisa_a|mcfhwdiv|mcfisa_b|mcfemac|mcfusp|cfloat, mcf5470, "5471", 1 },
{ mcfisa_a|mcfhwdiv|mcfisa_b|mcfemac|mcfusp|cfloat, mcf5470, "5472", 1 },
{ mcfisa_a|mcfhwdiv|mcfisa_b|mcfemac|mcfusp|cfloat, mcf5470, "5473", 1 },
{ mcfisa_a|mcfhwdiv|mcfisa_b|mcfemac|mcfusp|cfloat, mcf5470, "5474", 1 },
{ mcfisa_a|mcfhwdiv|mcfisa_b|mcfemac|mcfusp|cfloat, mcf5470, "5475", 1 },
{ mcfisa_a|mcfhwdiv|mcfisa_b|mcfemac|mcfusp|cfloat, mcf5470, "5480", 1 },
{ mcfisa_a|mcfhwdiv|mcfisa_b|mcfemac|mcfusp|cfloat, mcf5470, "5481", 1 },
{ mcfisa_a|mcfhwdiv|mcfisa_b|mcfemac|mcfusp|cfloat, mcf5470, "5482", 1 },
{ mcfisa_a|mcfhwdiv|mcfisa_b|mcfemac|mcfusp|cfloat, mcf5470, "5483", 1 },
{ mcfisa_a|mcfhwdiv|mcfisa_b|mcfemac|mcfusp|cfloat, mcf5470, "5484", 1 },
{ mcfisa_a|mcfhwdiv|mcfisa_b|mcfemac|mcfusp|cfloat, mcf5470, "5485", 1 },
{ mcfisa_a|mcfhwdiv|mcfisa_b|mcfemac|mcfusp|cfloat, mcf5470, "cfv4e", 1 },
};
static const int n_archs = sizeof (archs) / sizeof (archs[0]);
#define TAB(x,y) (((x) << 2) + (y))
#define TABTYPE(x) ((x) >> 2)
#define BYTE 0
#define SHORT 1
#define LONG 2
#define SZ_UNDEF 3
#define BRANCHBWL 0
#define BRABSJUNC 1
#define BRABSJCOND 2
#define BRANCHBW 3
#define FBRANCH 4
#define DBCCLBR 5
#define DBCCABSJ 6
#define PCREL1632 7
#define PCINDEX 8
#define ABSTOPCREL 9
relax_typeS md_relax_table[] =
{
{ 127, -128, 0, TAB (BRANCHBWL, SHORT) },
{ 32767, -32768, 2, TAB (BRANCHBWL, LONG) },
{ 0, 0, 4, 0 },
{ 1, 1, 0, 0 },
{ 127, -128, 0, TAB (BRABSJUNC, SHORT) },
{ 32767, -32768, 2, TAB (BRABSJUNC, LONG) },
{ 0, 0, 4, 0 },
{ 1, 1, 0, 0 },
{ 127, -128, 0, TAB (BRABSJCOND, SHORT) },
{ 32767, -32768, 2, TAB (BRABSJCOND, LONG) },
{ 0, 0, 6, 0 },
{ 1, 1, 0, 0 },
{ 127, -128, 0, TAB (BRANCHBW, SHORT) },
{ 0, 0, 2, 0 },
{ 1, 1, 0, 0 },
{ 1, 1, 0, 0 },
{ 1, 1, 0, 0 },
{ 32767, -32768, 2, TAB (FBRANCH, LONG) },
{ 0, 0, 4, 0 },
{ 1, 1, 0, 0 },
{ 1, 1, 0, 0 },
{ 32767, -32768, 2, TAB (DBCCLBR, LONG) },
{ 0, 0, 10, 0 },
{ 1, 1, 0, 0 },
{ 1, 1, 0, 0 },
{ 32767, -32768, 2, TAB (DBCCABSJ, LONG) },
{ 0, 0, 10, 0 },
{ 1, 1, 0, 0 },
{ 1, 1, 0, 0 },
{ 32767, -32768, 2, TAB (PCREL1632, LONG) },
{ 0, 0, 6, 0 },
{ 1, 1, 0, 0 },
{ 125, -130, 0, TAB (PCINDEX, SHORT) },
{ 32765, -32770, 2, TAB (PCINDEX, LONG) },
{ 0, 0, 4, 0 },
{ 1, 1, 0, 0 },
{ 1, 1, 0, 0 },
{ 32767, -32768, 2, TAB (ABSTOPCREL, LONG) },
{ 0, 0, 4, 0 },
{ 1, 1, 0, 0 },
};
const pseudo_typeS md_pseudo_table[] =
{
{"data1", s_data1, 0},
{"data2", s_data2, 0},
{"bss", s_bss, 0},
{"even", s_even, 0},
{"skip", s_space, 0},
{"proc", s_proc, 0},
#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'},
{"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}
};
const pseudo_typeS mote_pseudo_table[] =
{
{"dcl", cons, 4},
{"dc", cons, 2},
{"dcw", cons, 2},
{"dcb", cons, 1},
{"dsl", s_space, 4},
{"ds", s_space, 2},
{"dsw", s_space, 2},
{"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},
#endif
{0, 0, 0}
};
#define TRUNC(X) ((valueT) (X) & 0xffffffff)
#define SEXT(X) ((TRUNC (X) ^ 0x80000000) - 0x80000000)
#define issbyte(x) ((valueT) SEXT (x) + 0x80 < 0x100)
#define isubyte(x) ((valueT) TRUNC (x) < 0x100)
#define issword(x) ((valueT) SEXT (x) + 0x8000 < 0x10000)
#define isuword(x) ((valueT) TRUNC (x) < 0x10000)
#define isbyte(x) ((valueT) SEXT (x) + 0xff < 0x1ff)
#define isword(x) ((valueT) SEXT (x) + 0xffff < 0x1ffff)
#define islong(x) (1)
static char notend_table[256];
static char alt_notend_table[256];
#define notend(s) \
(! (notend_table[(unsigned char) *s] \
|| (*s == ':' \
&& alt_notend_table[(unsigned char) s[1]])))
static char *
find_cf_chip (int architecture)
{
static char buf[1024];
int i, j, n_chips, n_alias;
char *cp;
strcpy (buf, " (");
cp = buf + strlen (buf);
for (i = 0, n_chips = 0, n_alias = 0; i < n_archs; ++i)
if (archs[i].arch & architecture)
{
n_chips++;
if (archs[i].alias)
n_alias++;
}
if (n_chips == 0)
as_fatal (_("no matching ColdFire architectures found"));
if (n_alias > 1)
n_chips -= n_alias;
for (i = 0, j = 0; i < n_archs && j < n_chips; ++i)
if (archs[i].arch & architecture)
{
if (j)
{
if ((j == n_chips - 1 && !(n_alias > 1)) || ! n_alias)
{
if (n_chips == 2)
{
strncpy (cp, _(" or "), (sizeof (buf) - (cp - buf)));
cp += strlen (cp);
}
else
{
strncpy (cp, _(", or "), (sizeof (buf) - (cp - buf)));
cp += strlen (cp);
}
}
else
{
strncpy (cp, ", ", (sizeof (buf) - (cp - buf)));
cp += strlen (cp);
}
}
strncpy (cp, archs[i].name, (sizeof (buf) - (cp - buf)));
cp += strlen (cp);
j++;
}
if (n_alias > 1)
{
strncpy (cp, _(", or aliases"), (sizeof (buf) - (cp - buf)));
cp += strlen (cp);
}
strncpy (cp, ")", (sizeof (buf) - (cp - buf)));
return buf;
}
#if defined (M68KCOFF) && !defined (BFD_ASSEMBLER)
#ifdef NO_PCREL_RELOCS
int
make_pcrel_absolute (fixS *fixP, long *add_number)
{
register unsigned char *opcode = fixP->fx_frag->fr_opcode;
if (opcode[0] == 0x60 && opcode[1] == 0xff)
{
if (flag_keep_pcrel)
as_fatal (_("Tried to convert PC relative branch to absolute jump"));
opcode[0] = 0x4e;
opcode[1] = 0xf9;
}
else if (opcode[0] == 0x61 && opcode[1] == 0xff)
{
if (flag_keep_pcrel)
as_fatal (_("Tried to convert PC relative BSR to absolute JSR"));
opcode[0] = 0x4e;
opcode[1] = 0xb9;
}
else
as_fatal (_("Unknown PC relative instruction"));
*add_number -= 4;
return 0;
}
#endif
short
tc_coff_fix2rtype (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
: fixP->fx_size == 2 ? R_DIR16
: R_DIR32);
#else
return (fixP->fx_pcrel
? (fixP->fx_size == 1 ? R_PCRBYTE
: fixP->fx_size == 2 ? R_PCRWORD
: R_PCRLONG)
: (fixP->fx_size == 1 ? R_RELBYTE
: fixP->fx_size == 2 ? R_RELWORD
: R_RELLONG));
#endif
}
#endif
#ifdef OBJ_ELF
#define relaxable_symbol(symbol) \
(!((S_IS_EXTERNAL (symbol) && EXTERN_FORCE_RELOC) \
|| S_IS_WEAK (symbol)))
static bfd_reloc_code_real_type
get_reloc_code (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;
}
}
}
if (pcrel)
{
if (pic == pic_none)
as_bad (_("Can not do %d byte pc-relative relocation"), size);
else
as_bad (_("Can not do %d byte pc-relative pic relocation"), size);
}
else
{
if (pic == pic_none)
as_bad (_("Can not do %d byte relocation"), size);
else
as_bad (_("Can not do %d byte pic relocation"), size);
}
return BFD_RELOC_NONE;
}
int
tc_m68k_fix_adjustable (fixS *fixP)
{
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;
case BFD_RELOC_VTABLE_INHERIT:
case BFD_RELOC_VTABLE_ENTRY:
return 0;
default:
return 1;
}
}
#else
#define get_reloc_code(SIZE,PCREL,OTHER) NO_RELOC
#define relaxable_symbol(symbol) 1
#endif
#ifdef BFD_ASSEMBLER
arelent *
tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
{
arelent *reloc;
bfd_reloc_code_real_type code;
if (fixp->fx_tcbit)
{
if (fixp->fx_addsy)
as_bad_where (fixp->fx_file, fixp->fx_line,
_("Unable to produce reloc against symbol '%s'"),
S_GET_NAME (fixp->fx_addsy));
return NULL;
}
if (fixp->fx_r_type != BFD_RELOC_NONE)
{
code = fixp->fx_r_type;
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 ();
}
}
#undef F
#undef MAP
reloc = (arelent *) xmalloc (sizeof (arelent));
reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
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 & 0xff) ^ 0x80) - 0x80
+ fixp->fx_addnumber
+ md_pcrel_from (fixp));
#endif
reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
assert (reloc->howto != 0);
return reloc;
}
#endif
static struct hash_control *op_hash;
static void
m68k_ip (char *instring)
{
register char *p;
register struct m68k_op *opP;
register const struct m68k_incant *opcode;
register const char *s;
register int tmpreg = 0, baseo = 0, outro = 0, nextword;
char *pdot, *pdotmove;
enum m68k_size siz1, siz2;
char c;
int losing;
int opsfound;
LITTLENUM_TYPE words[6];
LITTLENUM_TYPE *wordp;
unsigned long ok_arch = 0;
if (*instring == ' ')
instring++;
pdot = 0;
for (p = instring; *p != '\0'; p++)
{
if (*p == ' ')
break;
if (*p == '.')
pdot = p;
}
if (p == instring)
{
the_ins.error = _("No operator");
return;
}
if (pdot != NULL)
{
for (pdotmove = pdot; pdotmove < p; pdotmove++)
*pdotmove = pdotmove[1];
p--;
}
c = *p;
*p = '\0';
opcode = (const struct m68k_incant *) hash_find (op_hash, instring);
*p = c;
if (pdot != NULL)
{
for (pdotmove = p; pdotmove > pdot; pdotmove--)
*pdotmove = pdotmove[-1];
*pdot = '.';
++p;
}
if (opcode == NULL)
{
the_ins.error = _("Unknown operator");
return;
}
while (*p == ' ')
++p;
if (opcode->m_operands == 0)
{
char *old = input_line_pointer;
*old = '\n';
input_line_pointer = p;
mote_pseudo_table[opcode->m_opnum].poc_handler
(mote_pseudo_table[opcode->m_opnum].poc_val);
input_line_pointer = old;
*old = 0;
return;
}
if (flag_mri && opcode->m_opnum == 0)
{
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 (opP->error)
{
the_ins.error = opP->error;
return;
}
}
opsfound = opP - &the_ins.operands[0];
if (opcode->m_operands[0] == 'I')
{
int n;
for (n = opsfound; n > 0; --n)
the_ins.operands[n] = the_ins.operands[n - 1];
memset (&the_ins.operands[0], '\0', sizeof (the_ins.operands[0]));
the_ins.operands[0].mode = CONTROL;
the_ins.operands[0].reg = m68k_float_copnum;
opsfound++;
}
for (losing = 0;;)
{
ok_arch |= opcode->m_arch;
if (opsfound != opcode->m_opnum
|| ((opcode->m_arch & current_architecture) == 0))
++losing;
else
{
for (s = opcode->m_operands, opP = &the_ins.operands[0];
*s && !losing;
s += 2, opP++)
{
switch (*s)
{
case '!':
switch (opP->mode)
{
case IMMED:
case DREG:
case AREG:
case FPREG:
case CONTROL:
case AINC:
case ADEC:
case REGLST:
losing++;
break;
default:
break;
}
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:
break;
case DISP:
if (opP->reg == PC || opP->reg == ZPC)
losing++;
break;
default:
losing++;
}
break;
case 'q':
switch (opP->mode)
{
case DREG:
case AINDR:
case AINC:
case ADEC:
break;
case DISP:
if (opP->reg == PC || opP->reg == ZPC)
losing++;
break;
default:
losing++;
break;
}
break;
case 'v':
switch (opP->mode)
{
case DREG:
case AINDR:
case AINC:
case ADEC:
case ABSL:
break;
case DISP:
if (opP->reg == PC || opP->reg == ZPC)
losing++;
break;
default:
losing++;
break;
}
break;
case '#':
if (opP->mode != IMMED)
losing++;
else if (s[1] == 'b'
&& ! isvar (&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)
&& (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;
case '^':
case 'T':
if (opP->mode != IMMED)
losing++;
break;
case '$':
if (opP->mode == AREG
|| opP->mode == CONTROL
|| opP->mode == FPREG
|| opP->mode == IMMED
|| opP->mode == REGLST
|| (opP->mode != ABSL
&& (opP->reg == PC
|| opP->reg == ZPC)))
losing++;
break;
case '%':
if (opP->mode == CONTROL
|| opP->mode == FPREG
|| opP->mode == REGLST
|| opP->mode == IMMED
|| (opP->mode != ABSL
&& (opP->reg == PC
|| opP->reg == ZPC)))
losing++;
break;
case '&':
switch (opP->mode)
{
case DREG:
case AREG:
case FPREG:
case CONTROL:
case IMMED:
case AINC:
case ADEC:
case REGLST:
losing++;
break;
case ABSL:
break;
default:
if (opP->reg == PC
|| opP->reg == ZPC)
losing++;
break;
}
break;
case '*':
if (opP->mode == CONTROL
|| opP->mode == FPREG
|| opP->mode == REGLST)
losing++;
break;
case '+':
if (opP->mode != AINC)
losing++;
break;
case '-':
if (opP->mode != ADEC)
losing++;
break;
case '/':
switch (opP->mode)
{
case AREG:
case CONTROL:
case FPREG:
case AINC:
case ADEC:
case IMMED:
case REGLST:
losing++;
break;
default:
break;
}
break;
case ';':
switch (opP->mode)
{
case AREG:
case CONTROL:
case FPREG:
case REGLST:
losing++;
break;
default:
break;
}
break;
case '?':
switch (opP->mode)
{
case AREG:
case CONTROL:
case FPREG:
case AINC:
case ADEC:
case IMMED:
case REGLST:
losing++;
break;
case ABSL:
break;
default:
if (opP->reg == PC || opP->reg == ZPC)
losing++;
break;
}
break;
case '@':
switch (opP->mode)
{
case AREG:
case CONTROL:
case FPREG:
case IMMED:
case REGLST:
losing++;
break;
default:
break;
}
break;
case '~':
switch (opP->mode)
{
case DREG:
case AREG:
case CONTROL:
case FPREG:
case IMMED:
case REGLST:
losing++;
break;
case ABSL:
break;
default:
if (opP->reg == PC
|| opP->reg == ZPC)
losing++;
break;
}
break;
case '3':
if (opP->mode != CONTROL
|| (opP->reg != TT0 && opP->reg != TT1))
losing++;
break;
case 'A':
if (opP->mode != AREG)
losing++;
break;
case 'a':
if (opP->mode != AINDR)
++losing;
break;
case '4':
if (opP->mode != AINDR && opP->mode != AINC && opP->mode != ADEC
&& (opP->mode != DISP
|| opP->reg < ADDR0
|| opP->reg > ADDR7))
++losing;
break;
case 'B':
if (opP->mode != ABSL
|| (flag_long_jumps
&& strncmp (instring, "jbsr", 4) == 0))
losing++;
break;
case 'b':
switch (opP->mode)
{
case IMMED:
case ABSL:
case AREG:
case FPREG:
case CONTROL:
case POST:
case PRE:
case REGLST:
losing++;
break;
default:
break;
}
break;
case 'C':
if (opP->mode != CONTROL || opP->reg != CCR)
losing++;
break;
case 'd':
if (opP->mode != DISP
|| opP->reg < ADDR0
|| opP->reg > ADDR7)
losing++;
break;
case 'D':
if (opP->mode != DREG)
losing++;
break;
case 'E':
if (opP->reg != ACC)
losing++;
break;
case 'e':
if (opP->reg != ACC && opP->reg != ACC1
&& opP->reg != ACC2 && opP->reg != ACC3)
losing++;
break;
case 'F':
if (opP->mode != FPREG)
losing++;
break;
case 'G':
if (opP->reg != MACSR)
losing++;
break;
case 'g':
if (opP->reg != ACCEXT01 && opP->reg != ACCEXT23)
losing++;
break;
case 'H':
if (opP->reg != MASK)
losing++;
break;
case 'I':
if (opP->mode != CONTROL
|| opP->reg < COP0
|| opP->reg > COP7)
losing++;
break;
case 'i':
if (opP->mode != LSH && opP->mode != RSH)
losing++;
break;
case 'J':
if (opP->mode != CONTROL
|| opP->reg < USP
|| opP->reg > last_movec_reg)
losing++;
else
{
const enum m68k_register *rp;
for (rp = control_regs; *rp; rp++)
if (*rp == opP->reg)
break;
if (*rp == 0)
losing++;
}
break;
case 'k':
if (opP->mode != IMMED)
losing++;
break;
case 'l':
case 'L':
if (opP->mode == DREG
|| opP->mode == AREG
|| opP->mode == FPREG)
{
if (s[1] == '8')
losing++;
else
{
switch (opP->mode)
{
case DREG:
opP->mask = 1 << (opP->reg - DATA0);
break;
case AREG:
opP->mask = 1 << (opP->reg - ADDR0 + 8);
break;
case FPREG:
opP->mask = 1 << (opP->reg - FP0 + 16);
break;
default:
abort ();
}
opP->mode = REGLST;
}
}
else if (opP->mode == CONTROL)
{
if (s[1] != '8')
losing++;
else
{
switch (opP->reg)
{
case FPI:
opP->mask = 1 << 24;
break;
case FPS:
opP->mask = 1 << 25;
break;
case FPC:
opP->mask = 1 << 26;
break;
default:
losing++;
break;
}
opP->mode = REGLST;
}
}
else if (opP->mode != REGLST)
losing++;
else if (s[1] == '8' && (opP->mask & 0x0ffffff) != 0)
losing++;
else if (s[1] == '3' && (opP->mask & 0x7000000) != 0)
losing++;
break;
case 'M':
if (opP->mode != IMMED)
losing++;
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
&& opP->mode != ABSL)
losing++;
break;
case 'Q':
if (opP->mode != IMMED)
losing++;
else if (opP->disp.exp.X_op != O_constant
|| TRUNC (opP->disp.exp.X_add_number) - 1 > 7)
losing++;
else if (! m68k_quick
&& (strncmp (instring, "add", 3) == 0
|| strncmp (instring, "sub", 3) == 0)
&& instring[3] != 'q')
losing++;
break;
case 'R':
if (opP->mode != DREG && opP->mode != AREG)
losing++;
break;
case 'r':
if (opP->mode != AINDR
&& (opP->mode != BASE
|| (opP->reg != 0
&& opP->reg != ZADDR0)
|| opP->disp.exp.X_op != O_absent
|| ((opP->index.reg < DATA0
|| opP->index.reg > DATA7)
&& (opP->index.reg < ADDR0
|| opP->index.reg > ADDR7))
|| opP->index.size != SIZE_UNSPEC
|| opP->index.scale != 1))
losing++;
break;
case 's':
if (opP->mode != CONTROL
|| ! (opP->reg == FPI
|| opP->reg == FPS
|| opP->reg == FPC))
losing++;
break;
case 'S':
if (opP->mode != CONTROL || opP->reg != SR)
losing++;
break;
case 't':
if (opP->mode != IMMED)
losing++;
else if (opP->disp.exp.X_op != O_constant
|| TRUNC (opP->disp.exp.X_add_number) > 7)
losing++;
break;
case 'U':
if (opP->mode != CONTROL || opP->reg != USP)
losing++;
break;
case 'x':
if (opP->mode != IMMED)
losing++;
else if (opP->disp.exp.X_op != O_constant
|| (TRUNC (opP->disp.exp.X_add_number) != 0xffffffff
&& TRUNC (opP->disp.exp.X_add_number) - 1 > 6))
losing++;
break;
#ifndef NO_68851
case '|':
if (opP->mode == CONTROL
|| opP->mode == FPREG
|| opP->mode == DREG
|| opP->mode == AREG
|| opP->mode == REGLST)
losing++;
if (opP->mode == IMMED)
losing++;
break;
case 'f':
if (opP->mode != CONTROL
|| (opP->reg != SFC && opP->reg != DFC))
losing++;
break;
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 != CAL
&& opP->reg != VAL
&& opP->reg != SCC))
losing++;
break;
case 'V':
if (opP->mode != CONTROL
|| opP->reg != VAL)
losing++;
break;
case 'W':
if (opP->mode != CONTROL
|| (opP->reg != DRP
&& opP->reg != SRP
&& opP->reg != CRP))
losing++;
break;
case 'w':
switch (opP->mode)
{
case IMMED:
case ABSL:
case AREG:
case DREG:
case FPREG:
case CONTROL:
case POST:
case PRE:
case REGLST:
losing++;
break;
default:
break;
}
break;
case 'X':
if (opP->mode != CONTROL
|| (!(opP->reg >= BAD && opP->reg <= BAD + 7)
&& !(opP->reg >= BAC && opP->reg <= BAC + 7)))
losing++;
break;
case 'Y':
if (opP->mode != CONTROL || opP->reg != PSR)
losing++;
break;
case 'Z':
if (opP->mode != CONTROL || opP->reg != PCSR)
losing++;
break;
#endif
case 'c':
if (opP->mode != CONTROL
|| (opP->reg != NC
&& opP->reg != IC
&& opP->reg != DC
&& opP->reg != BC))
losing++;
break;
case '_':
if (opP->mode != ABSL)
++losing;
break;
case 'u':
if (opP->reg < DATA0L || opP->reg > ADDR7U)
losing++;
if ((opP->reg >= DATA0L && opP->reg <= DATA7L)
|| (opP->reg >= DATA0U && opP->reg <= DATA7U))
opP->mode = DREG;
else
opP->mode = AREG;
break;
case 'y':
if (!(opP->mode == AINDR
|| (opP->mode == DISP
&& !(opP->reg == PC || opP->reg == ZPC))))
losing++;
break;
case 'z':
if (!(opP->mode == AINDR || opP->mode == DISP))
losing++;
break;
default:
abort ();
}
if (losing)
break;
}
}
if (!losing)
break;
opcode = opcode->m_next;
if (!opcode)
{
if (ok_arch
&& !(ok_arch & current_architecture))
{
char buf[200], *cp;
strncpy (buf,
_("invalid instruction for this architecture; needs "),
sizeof (buf));
cp = buf + strlen (buf);
switch (ok_arch)
{
case mcfisa_a:
strncpy (cp, _("ColdFire ISA_A"),
sizeof (buf) - (cp - buf));
cp += strlen (cp);
strncpy (cp, find_cf_chip (ok_arch),
sizeof (buf) - (cp - buf));
cp += strlen (cp);
break;
case mcfhwdiv:
strncpy (cp, _("ColdFire hardware divide"),
sizeof (buf) - (cp - buf));
cp += strlen (cp);
strncpy (cp, find_cf_chip (ok_arch),
sizeof (buf) - (cp - buf));
cp += strlen (cp);
break;
case mcfisa_aa:
strncpy (cp, _("ColdFire ISA_A+"),
sizeof (buf) - (cp - buf));
cp += strlen (cp);
strncpy (cp, find_cf_chip (ok_arch),
sizeof (buf) - (cp - buf));
cp += strlen (cp);
break;
case mcfisa_b:
strncpy (cp, _("ColdFire ISA_B"),
sizeof (buf) - (cp - buf));
cp += strlen (cp);
strncpy (cp, find_cf_chip (ok_arch),
sizeof (buf) - (cp - buf));
cp += strlen (cp);
break;
case cfloat:
strncpy (cp, _("ColdFire fpu"), sizeof (buf) - (cp - buf));
cp += strlen (cp);
strncpy (cp, find_cf_chip (ok_arch),
sizeof (buf) - (cp - buf));
cp += strlen (cp);
break;
case mfloat:
strcpy (cp, _("fpu (68040, 68060 or 68881/68882)"));
break;
case mmmu:
strcpy (cp, _("mmu (68030 or 68851)"));
break;
case m68020up:
strcpy (cp, _("68020 or higher"));
break;
case m68000up:
strcpy (cp, _("68000 or higher"));
break;
case m68010up:
strcpy (cp, _("68010 or higher"));
break;
default:
{
int got_one = 0, idx;
for (idx = 0; idx < n_archs; idx++)
{
if ((archs[idx].arch & ok_arch)
&& ! archs[idx].alias)
{
if (got_one)
{
strcpy (cp, " or ");
cp += strlen (cp);
}
got_one = 1;
strcpy (cp, archs[idx].name);
cp += strlen (cp);
}
}
}
}
cp = xmalloc (strlen (buf) + 1);
strcpy (cp, buf);
the_ins.error = cp;
}
else
the_ins.error = _("operands mismatch");
return;
}
losing = 0;
}
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);
for (s = the_ins.args, opP = &the_ins.operands[0]; *s; s += 2, opP++)
{
switch (s[0])
{
case '*':
case '~':
case '%':
case ';':
case '@':
case '!':
case '&':
case '$':
case '?':
case '/':
case '<':
case '>':
case 'b':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'v':
case 'w':
case 'y':
case 'z':
case '4':
#ifndef NO_68851
case '|':
#endif
switch (opP->mode)
{
case IMMED:
tmpreg = 0x3c;
if (strchr ("bwl", s[1]))
nextword = get_num (&opP->disp, 90);
else
nextword = get_num (&opP->disp, 0);
if (isvar (&opP->disp))
add_fix (s[1], &opP->disp, 0, 0);
switch (s[1])
{
case 'b':
if (!isbyte (nextword))
opP->error = _("operand out of range");
addword (nextword);
baseo = 0;
break;
case 'w':
if (!isword (nextword))
opP->error = _("operand out of range");
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);
baseo = 0;
break;
case 'f':
baseo = 2;
outro = 8;
break;
case 'F':
baseo = 4;
outro = 11;
break;
case 'x':
baseo = 6;
outro = 15;
break;
case 'p':
baseo = 6;
outro = -1;
break;
default:
abort ();
}
if (!baseo)
break;
if (op (&opP->disp) != O_big)
{
valueT val;
int gencnt;
if (op (&opP->disp) != O_constant)
abort ();
val = (valueT) offs (&opP->disp);
gencnt = 0;
do
{
generic_bignum[gencnt] = (LITTLENUM_TYPE) val;
val >>= LITTLENUM_NUMBER_OF_BITS;
++gencnt;
}
while (val != 0);
offs (&opP->disp) = gencnt;
}
if (offs (&opP->disp) > 0)
{
if (offs (&opP->disp) > baseo)
{
as_warn (_("Bignum too big for %c format; truncated"),
s[1]);
offs (&opP->disp) = baseo;
}
baseo -= offs (&opP->disp);
while (baseo--)
addword (0);
for (wordp = generic_bignum + offs (&opP->disp) - 1;
offs (&opP->disp)--;
--wordp)
addword (*wordp);
break;
}
gen_to_words (words, baseo, (long) outro);
for (wordp = words; baseo--; wordp++)
addword (*wordp);
break;
case DREG:
tmpreg = opP->reg - DATA;
break;
case AREG:
tmpreg = 0x08 + opP->reg - ADDR;
break;
case AINDR:
tmpreg = 0x10 + opP->reg - ADDR;
break;
case ADEC:
tmpreg = 0x20 + opP->reg - ADDR;
break;
case AINC:
tmpreg = 0x18 + opP->reg - ADDR;
break;
case DISP:
nextword = get_num (&opP->disp, 90);
if (! isvar (&opP->disp)
&& (nextword == 0)
&& (opP->disp.size == SIZE_UNSPEC)
&& (opP->reg >= ADDR0)
&& (opP->reg <= ADDR7))
{
tmpreg = 0x10 + opP->reg - ADDR;
break;
}
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
}
if (!issword (nextword)
|| (isvar (&opP->disp)
&& ((opP->disp.size == SIZE_UNSPEC
&& flag_short_refs == 0
&& cpu_of_arch (current_architecture) >= m68020
&& ! arch_coldfire_p (current_architecture))
|| opP->disp.size == SIZE_LONG)))
{
if (cpu_of_arch (current_architecture) < m68020
|| arch_coldfire_p (current_architecture))
opP->error =
_("displacement too large for this architecture; needs 68020 or higher");
if (opP->reg == PC)
tmpreg = 0x3B;
else
tmpreg = 0x30 + opP->reg - ADDR;
if (isvar (&opP->disp))
{
if (opP->reg == PC)
{
if (opP->disp.size == SIZE_LONG
#ifdef OBJ_ELF
|| opP->disp.pic_reloc != pic_none
#endif
)
{
addword (0x0170);
add_fix ('l', &opP->disp, 1, 2);
}
else
{
add_frag (adds (&opP->disp),
SEXT (offs (&opP->disp)),
TAB (PCREL1632, SZ_UNDEF));
break;
}
}
else
{
addword (0x0170);
add_fix ('l', &opP->disp, 0, 0);
}
}
else
addword (0x0170);
addword (nextword >> 16);
}
else
{
if (opP->reg == PC)
tmpreg = 0x3A;
else
tmpreg = 0x28 + opP->reg - ADDR;
if (isvar (&opP->disp))
{
if (opP->reg == PC)
{
add_fix ('w', &opP->disp, 1, 0);
}
else
add_fix ('w', &opP->disp, 0, 0);
}
}
addword (nextword);
break;
case POST:
case PRE:
case BASE:
nextword = 0;
baseo = get_num (&opP->disp, 90);
if (opP->mode == POST || opP->mode == PRE)
outro = get_num (&opP->odisp, 90);
if (opP->reg == PC || opP->reg == ZPC)
{
tmpreg = 0x3b;
if (opP->reg == ZPC)
nextword |= 0x80;
}
else if (opP->reg == 0)
{
nextword |= 0x80;
tmpreg = 0x30;
}
else if (opP->reg >= ZADDR0 && opP->reg <= ZADDR7)
{
nextword |= 0x80;
tmpreg = 0x30 + opP->reg - ZADDR0;
}
else
tmpreg = 0x30 + opP->reg - ADDR;
siz1 = opP->disp.size;
if (opP->mode == POST || opP->mode == PRE)
siz2 = opP->odisp.size;
else
siz2 = SIZE_UNSPEC;
if (opP->index.reg != 0
&& opP->index.reg >= DATA
&& opP->index.reg <= ADDR7)
{
nextword |= (opP->index.reg - DATA) << 12;
if (opP->index.size == SIZE_LONG
|| (opP->index.size == SIZE_UNSPEC
&& m68k_index_width_default == SIZE_LONG))
nextword |= 0x800;
if ((opP->index.scale != 1
&& cpu_of_arch (current_architecture) < m68020)
|| (opP->index.scale == 8
&& (arch_coldfire_p (current_architecture)
&& !arch_coldfire_fpu (current_architecture))))
{
opP->error =
_("scale factor invalid on this architecture; needs cpu32 or 68020 or higher");
}
if (arch_coldfire_p (current_architecture)
&& opP->index.size == SIZE_WORD)
opP->error = _("invalid index size for coldfire");
switch (opP->index.scale)
{
case 1:
break;
case 2:
nextword |= 0x200;
break;
case 4:
nextword |= 0x400;
break;
case 8:
nextword |= 0x600;
break;
default:
abort ();
}
if (opP->mode == BASE
&& ((opP->reg >= ADDR0
&& opP->reg <= ADDR7)
|| opP->reg == PC))
{
if (siz1 == SIZE_BYTE
|| cpu_of_arch (current_architecture) < m68020
|| arch_coldfire_p (current_architecture)
|| (siz1 == SIZE_UNSPEC
&& ! isvar (&opP->disp)
&& issbyte (baseo)))
{
nextword += baseo & 0xff;
addword (nextword);
if (isvar (&opP->disp))
{
if (opP->reg == PC)
add_fix ('B', &opP->disp, 1, 1);
else
add_fix ('B', &opP->disp, 0, 0);
}
else if (siz1 != SIZE_BYTE)
{
if (siz1 != SIZE_UNSPEC)
as_warn (_("Forcing byte displacement"));
if (! issbyte (baseo))
opP->error = _("byte displacement out of range");
}
break;
}
else if (siz1 == SIZE_UNSPEC
&& opP->reg == PC
&& isvar (&opP->disp)
&& subs (&opP->disp) == NULL
#ifdef OBJ_ELF
&& opP->disp.pic_reloc == pic_none
#endif
)
{
frag_grow (14);
nextword += baseo & 0xff;
addword (nextword);
add_frag (adds (&opP->disp),
SEXT (offs (&opP->disp)),
TAB (PCINDEX, SZ_UNDEF));
break;
}
}
}
else
{
nextword |= 0x40;
if (opP->index.reg >= ZDATA0
&& opP->index.reg <= ZDATA7)
nextword |= (opP->index.reg - ZDATA0) << 12;
else if (opP->index.reg >= ZADDR0
|| opP->index.reg <= ZADDR7)
nextword |= (opP->index.reg - ZADDR0 + 8) << 12;
}
if (cpu_of_arch (current_architecture) < m68020
|| arch_coldfire_p (current_architecture))
opP->error =
_("invalid operand mode for this architecture; needs 68020 or higher");
nextword |= 0x100;
switch (siz1)
{
case SIZE_UNSPEC:
if (isvar (&opP->disp)
? m68k_rel32
: ! issword (baseo))
{
siz1 = SIZE_LONG;
nextword |= 0x30;
}
else if (! isvar (&opP->disp) && baseo == 0)
nextword |= 0x10;
else
{
nextword |= 0x20;
siz1 = SIZE_WORD;
}
break;
case SIZE_BYTE:
as_warn (_(":b not permitted; defaulting to :w"));
case SIZE_WORD:
nextword |= 0x20;
break;
case SIZE_LONG:
nextword |= 0x30;
break;
}
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)
? m68k_rel32
: ! issword (outro))
{
siz2 = SIZE_LONG;
nextword |= 0x3;
}
else if (! isvar (&opP->odisp) && outro == 0)
nextword |= 0x1;
else
{
nextword |= 0x2;
siz2 = SIZE_WORD;
}
break;
case 1:
as_warn (_(":b not permitted; defaulting to :w"));
case 2:
nextword |= 0x2;
break;
case 3:
nextword |= 0x3;
break;
}
if (opP->mode == POST
&& (nextword & 0x40) == 0)
nextword |= 0x04;
}
addword (nextword);
if (siz1 != SIZE_UNSPEC && isvar (&opP->disp))
{
if (opP->reg == PC || opP->reg == ZPC)
add_fix (siz1 == SIZE_LONG ? 'l' : 'w', &opP->disp, 1, 2);
else
add_fix (siz1 == SIZE_LONG ? 'l' : 'w', &opP->disp, 0, 0);
}
if (siz1 == SIZE_LONG)
addword (baseo >> 16);
if (siz1 != SIZE_UNSPEC)
addword (baseo);
if (siz2 != SIZE_UNSPEC && isvar (&opP->odisp))
add_fix (siz2 == SIZE_LONG ? 'l' : 'w', &opP->odisp, 0, 0);
if (siz2 == SIZE_LONG)
addword (outro >> 16);
if (siz2 != SIZE_UNSPEC)
addword (outro);
break;
case ABSL:
nextword = get_num (&opP->disp, 90);
switch (opP->disp.size)
{
default:
abort ();
case SIZE_UNSPEC:
if (!isvar (&opP->disp) && issword (offs (&opP->disp)))
{
tmpreg = 0x38;
addword (nextword);
break;
}
if (isvar (&opP->disp)
&& !subs (&opP->disp)
&& adds (&opP->disp)
#ifdef OBJ_ELF
&& opP->disp.pic_reloc == pic_none
#endif
&& !flag_long_jumps
&& !strchr ("~%&$?", s[0]))
{
tmpreg = 0x3A;
add_frag (adds (&opP->disp),
SEXT (offs (&opP->disp)),
TAB (ABSTOPCREL, SZ_UNDEF));
break;
}
case SIZE_LONG:
if (isvar (&opP->disp))
add_fix ('l', &opP->disp, 0, 0);
tmpreg = 0x39;
addword (nextword >> 16);
addword (nextword);
break;
case SIZE_BYTE:
as_bad (_("unsupported byte value; use a different suffix"));
case SIZE_WORD:
if (isvar (&opP->disp))
add_fix ('w', &opP->disp, 0, 0);
tmpreg = 0x38;
addword (nextword);
break;
}
break;
case CONTROL:
case FPREG:
default:
as_bad (_("unknown/incorrect operand"));
}
if (s[0] == '4')
{
if (opP->trailing_ampersand)
tmpreg |= 0x100;
}
install_gen_operand (s[1], tmpreg);
break;
case '#':
case '^':
switch (s[1])
{
case 'j':
tmpreg = 70;
break;
case '8':
tmpreg = 20;
break;
case 'C':
tmpreg = 50;
break;
case '3':
default:
tmpreg = 90;
break;
}
tmpreg = get_num (&opP->disp, tmpreg);
if (isvar (&opP->disp))
add_fix (s[1], &opP->disp, 0, 0);
switch (s[1])
{
case 'b':
if (!isbyte (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 + 1;
break;
case 'B':
if (!issbyte (tmpreg))
opP->error = _("out of range");
the_ins.opcode[the_ins.numo - 1] |= tmpreg & 0xff;
if (isvar (&opP->disp))
the_ins.reloc[the_ins.nrel - 1].n = opcode->m_codenum * 2 - 1;
break;
case 'w':
if (!isword (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 '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':
insop (tmpreg, opcode);
insop (tmpreg >> 16, opcode);
if (isvar (&opP->disp))
the_ins.reloc[the_ins.nrel - 1].n = (opcode->m_codenum) * 2;
break;
case '3':
tmpreg &= 0xFF;
case '8':
case 'C':
case 'j':
install_operand (s[1], tmpreg);
break;
default:
abort ();
}
break;
case '+':
case '-':
case 'A':
case 'a':
install_operand (s[1], opP->reg - ADDR);
break;
case 'B':
tmpreg = get_num (&opP->disp, 90);
switch (s[1])
{
case 'B':
add_fix ('B', &opP->disp, 1, -1);
break;
case 'W':
add_fix ('w', &opP->disp, 1, 0);
addword (0);
break;
case 'L':
long_branch:
if (! HAVE_LONG_BRANCH (current_architecture))
as_warn (_("Can't use long branches on 68000/68010/5200"));
the_ins.opcode[0] |= 0xff;
add_fix ('l', &opP->disp, 1, 0);
addword (0);
addword (0);
break;
case 'g':
if (subs (&opP->disp))
goto long_branch;
#ifdef OBJ_ELF
if (opP->disp.pic_reloc != pic_none)
goto long_branch;
#endif
if (adds (&opP->disp) == 0)
{
if (the_ins.opcode[0] == 0x6000)
the_ins.opcode[0] = 0x4EF9;
else if (the_ins.opcode[0] == 0x6100)
the_ins.opcode[0] = 0x4EB9;
else
{
the_ins.opcode[0] ^= 0x0100;
the_ins.opcode[0] |= 0x0006;
addword (0x4EF9);
}
add_fix ('l', &opP->disp, 0, 0);
addword (0);
addword (0);
break;
}
if (HAVE_LONG_BRANCH (current_architecture))
add_frag (adds (&opP->disp),
SEXT (offs (&opP->disp)),
TAB (BRANCHBWL, SZ_UNDEF));
else if (! flag_keep_pcrel)
{
if ((the_ins.opcode[0] == 0x6000)
|| (the_ins.opcode[0] == 0x6100))
add_frag (adds (&opP->disp),
SEXT (offs (&opP->disp)),
TAB (BRABSJUNC, SZ_UNDEF));
else
add_frag (adds (&opP->disp),
SEXT (offs (&opP->disp)),
TAB (BRABSJCOND, SZ_UNDEF));
}
else
add_frag (adds (&opP->disp),
SEXT (offs (&opP->disp)),
TAB (BRANCHBW, SZ_UNDEF));
break;
case 'w':
if (isvar (&opP->disp))
{
if (((the_ins.opcode[0] & 0xf0f8) == 0x50c8)
&& (HAVE_LONG_BRANCH (current_architecture)
|| (! flag_keep_pcrel)))
{
if (HAVE_LONG_BRANCH (current_architecture))
add_frag (adds (&opP->disp),
SEXT (offs (&opP->disp)),
TAB (DBCCLBR, SZ_UNDEF));
else
add_frag (adds (&opP->disp),
SEXT (offs (&opP->disp)),
TAB (DBCCABSJ, SZ_UNDEF));
break;
}
add_fix ('w', &opP->disp, 1, 0);
}
addword (0);
break;
case 'C':
add_fix ('l', &opP->disp, 1, 0);
addword (0);
addword (0);
break;
case 'c':
if (subs (&opP->disp) || (adds (&opP->disp) == 0))
{
the_ins.opcode[the_ins.numo - 1] |= 0x40;
add_fix ('l', &opP->disp, 1, 0);
addword (0);
addword (0);
}
else
add_frag (adds (&opP->disp),
SEXT (offs (&opP->disp)),
TAB (FBRANCH, SZ_UNDEF));
break;
default:
abort ();
}
break;
case 'C':
break;
case 'd':
install_operand ('s', opP->reg - ADDR);
tmpreg = get_num (&opP->disp, 90);
if (!issword (tmpreg))
{
as_warn (_("Expression out of range, using 0"));
tmpreg = 0;
}
addword (tmpreg);
break;
case 'D':
install_operand (s[1], opP->reg - DATA);
break;
case 'e':
install_operand (s[1], opP->reg - ACC);
break;
case 'E':
break;
case 'F':
install_operand (s[1], opP->reg - FP0);
break;
case 'g':
install_operand (s[1], opP->reg - ACCEXT01);
break;
case 'G':
case 'H':
break;
case 'I':
tmpreg = opP->reg - COP0;
install_operand (s[1], tmpreg);
break;
case 'i':
install_operand (s[1], opP->mode == LSH ? 0x1 : 0x3);
break;
case 'J':
switch (opP->reg)
{
case SFC:
tmpreg = 0x000;
break;
case DFC:
tmpreg = 0x001;
break;
case CACR:
tmpreg = 0x002;
break;
case TC:
tmpreg = 0x003;
break;
case ACR0:
case ITT0:
tmpreg = 0x004;
break;
case ACR1:
case ITT1:
tmpreg = 0x005;
break;
case ACR2:
case DTT0:
tmpreg = 0x006;
break;
case ACR3:
case DTT1:
tmpreg = 0x007;
break;
case BUSCR:
tmpreg = 0x008;
break;
case USP:
tmpreg = 0x800;
break;
case VBR:
tmpreg = 0x801;
break;
case CAAR:
tmpreg = 0x802;
break;
case MSP:
tmpreg = 0x803;
break;
case ISP:
tmpreg = 0x804;
break;
case MMUSR:
tmpreg = 0x805;
break;
case URP:
tmpreg = 0x806;
break;
case SRP:
tmpreg = 0x807;
break;
case PCR:
tmpreg = 0x808;
break;
case ROMBAR:
tmpreg = 0xC00;
break;
case ROMBAR1:
tmpreg = 0xC01;
break;
case FLASHBAR:
case RAMBAR0:
tmpreg = 0xC04;
break;
case RAMBAR:
case RAMBAR1:
tmpreg = 0xC05;
break;
case MPCR:
tmpreg = 0xC0C;
break;
case EDRAMBAR:
tmpreg = 0xC0D;
break;
case MBAR0:
case MBAR2:
case SECMBAR:
tmpreg = 0xC0E;
break;
case MBAR1:
case MBAR:
tmpreg = 0xC0F;
break;
case PCR1U0:
tmpreg = 0xD02;
break;
case PCR1L0:
tmpreg = 0xD03;
break;
case PCR2U0:
tmpreg = 0xD04;
break;
case PCR2L0:
tmpreg = 0xD05;
break;
case PCR3U0:
tmpreg = 0xD06;
break;
case PCR3L0:
tmpreg = 0xD07;
break;
case PCR1L1:
tmpreg = 0xD0A;
break;
case PCR1U1:
tmpreg = 0xD0B;
break;
case PCR2L1:
tmpreg = 0xD0C;
break;
case PCR2U1:
tmpreg = 0xD0D;
break;
case PCR3L1:
tmpreg = 0xD0E;
break;
case PCR3U1:
tmpreg = 0xD0F;
break;
default:
abort ();
}
install_operand (s[1], tmpreg);
break;
case 'k':
tmpreg = get_num (&opP->disp, 55);
install_operand (s[1], tmpreg & 0x7f);
break;
case 'l':
tmpreg = opP->mask;
if (s[1] == 'w')
{
if (tmpreg & 0x7FF0000)
as_bad (_("Floating point register in register list"));
insop (reverse_16_bits (tmpreg), opcode);
}
else
{
if (tmpreg & 0x700FFFF)
as_bad (_("Wrong register in floating-point reglist"));
install_operand (s[1], reverse_8_bits (tmpreg >> 16));
}
break;
case 'L':
tmpreg = opP->mask;
if (s[1] == 'w')
{
if (tmpreg & 0x7FF0000)
as_bad (_("Floating point register in register list"));
insop (tmpreg, opcode);
}
else if (s[1] == '8')
{
if (tmpreg & 0x0FFFFFF)
as_bad (_("incorrect register in reglist"));
install_operand (s[1], tmpreg >> 24);
}
else
{
if (tmpreg & 0x700FFFF)
as_bad (_("wrong register in floating-point reglist"));
else
install_operand (s[1], tmpreg >> 16);
}
break;
case 'M':
install_operand (s[1], get_num (&opP->disp, 60));
break;
case 'O':
tmpreg = ((opP->mode == DREG)
? 0x20 + (int) (opP->reg - DATA)
: (get_num (&opP->disp, 40) & 0x1F));
install_operand (s[1], tmpreg);
break;
case 'Q':
tmpreg = get_num (&opP->disp, 10);
if (tmpreg == 8)
tmpreg = 0;
install_operand (s[1], tmpreg);
break;
case 'R':
install_operand (s[1], opP->reg - DATA);
break;
case 'r':
if (opP->mode == AINDR)
install_operand (s[1], opP->reg - DATA);
else
install_operand (s[1], opP->index.reg - DATA);
break;
case 's':
if (opP->reg == FPI)
tmpreg = 0x1;
else if (opP->reg == FPS)
tmpreg = 0x2;
else if (opP->reg == FPC)
tmpreg = 0x4;
else
abort ();
install_operand (s[1], tmpreg);
break;
case 'S':
break;
case 'T':
install_operand (s[1], get_num (&opP->disp, 30));
break;
case 'U':
break;
case 'c':
switch (opP->reg)
{
case NC:
tmpreg = 0;
break;
case DC:
tmpreg = 1;
break;
case IC:
tmpreg = 2;
break;
case BC:
tmpreg = 3;
break;
default:
as_fatal (_("failed sanity check"));
}
install_operand (s[1], tmpreg);
break;
#ifndef NO_68851
case 'f':
switch (opP->reg)
{
case SFC:
tmpreg = 0;
break;
case DFC:
tmpreg = 1;
break;
default:
abort ();
}
install_operand (s[1], tmpreg);
break;
case '0':
case '1':
case '2':
switch (opP->reg)
{
case TC:
tmpreg = 0;
break;
case CAL:
tmpreg = 4;
break;
case VAL:
tmpreg = 5;
break;
case SCC:
tmpreg = 6;
break;
case AC:
tmpreg = 7;
break;
default:
abort ();
}
install_operand (s[1], tmpreg);
break;
case 'V':
if (opP->reg == VAL)
break;
abort ();
case 'W':
switch (opP->reg)
{
case DRP:
tmpreg = 1;
break;
case SRP:
tmpreg = 2;
break;
case CRP:
tmpreg = 3;
break;
default:
abort ();
}
install_operand (s[1], tmpreg);
break;
case 'X':
switch (opP->reg)
{
case BAD:
case BAD + 1:
case BAD + 2:
case BAD + 3:
case BAD + 4:
case BAD + 5:
case BAD + 6:
case BAD + 7:
tmpreg = (4 << 10) | ((opP->reg - BAD) << 2);
break;
case BAC:
case BAC + 1:
case BAC + 2:
case BAC + 3:
case BAC + 4:
case BAC + 5:
case BAC + 6:
case BAC + 7:
tmpreg = (5 << 10) | ((opP->reg - BAC) << 2);
break;
default:
abort ();
}
install_operand (s[1], tmpreg);
break;
case 'Y':
know (opP->reg == PSR);
break;
case 'Z':
know (opP->reg == PCSR);
break;
#endif
case '3':
switch (opP->reg)
{
case TT0:
tmpreg = 2;
break;
case TT1:
tmpreg = 3;
break;
default:
abort ();
}
install_operand (s[1], tmpreg);
break;
case 't':
tmpreg = get_num (&opP->disp, 20);
install_operand (s[1], tmpreg);
break;
case '_':
if (isvar (&opP->disp))
add_fix ('l', &opP->disp, 0, 0);
tmpreg = get_num (&opP->disp, 90);
addword (tmpreg >> 16);
addword (tmpreg & 0xFFFF);
break;
case 'u':
install_operand (s[1], opP->reg - DATA0L);
opP->reg -= (DATA0L);
opP->reg &= 0x0F;
break;
case 'x':
tmpreg = get_num (&opP->disp, 80);
if (tmpreg == -1)
tmpreg = 0;
install_operand (s[1], tmpreg);
break;
default:
abort ();
}
}
}
static int
reverse_16_bits (int in)
{
int out = 0;
int n;
static int mask[16] =
{
0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000
};
for (n = 0; n < 16; n++)
{
if (in & mask[n])
out |= mask[15 - n];
}
return out;
}
static int
reverse_8_bits (int in)
{
int out = 0;
int n;
static int mask[8] =
{
0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
};
for (n = 0; n < 8; n++)
{
if (in & mask[n])
out |= mask[7 - n];
}
return out;
}
static void
install_operand (int mode, int val)
{
switch (mode)
{
case 's':
the_ins.opcode[0] |= val & 0xFF;
break;
case 'd':
the_ins.opcode[0] |= val << 9;
break;
case '1':
the_ins.opcode[1] |= val << 12;
break;
case '2':
the_ins.opcode[1] |= val << 6;
break;
case '3':
the_ins.opcode[1] |= val;
break;
case '4':
the_ins.opcode[2] |= val << 12;
break;
case '5':
the_ins.opcode[2] |= val << 6;
break;
case '6':
the_ins.numo++;
the_ins.opcode[2] |= val;
break;
case '7':
the_ins.opcode[1] |= val << 7;
break;
case '8':
the_ins.opcode[1] |= val << 10;
break;
#ifndef NO_68851
case '9':
the_ins.opcode[1] |= val << 5;
break;
#endif
case 't':
the_ins.opcode[1] |= (val << 10) | (val << 7);
break;
case 'D':
the_ins.opcode[1] |= (val << 12) | val;
break;
case 'g':
the_ins.opcode[0] |= val = 0xff;
break;
case 'i':
the_ins.opcode[0] |= val << 9;
break;
case 'C':
the_ins.opcode[1] |= val;
break;
case 'j':
the_ins.opcode[1] |= val;
the_ins.numo++;
break;
case 'k':
the_ins.opcode[1] |= val << 4;
break;
case 'b':
case 'w':
case 'W':
case 'l':
break;
case 'e':
the_ins.opcode[0] |= (val << 6);
break;
case 'L':
the_ins.opcode[1] = (val >> 16);
the_ins.opcode[2] = val & 0xffff;
break;
case 'm':
the_ins.opcode[0] |= ((val & 0x8) << (6 - 3));
the_ins.opcode[0] |= ((val & 0x7) << 9);
the_ins.opcode[1] |= ((val & 0x10) << (7 - 4));
break;
case 'n':
the_ins.opcode[0] |= ((val & 0x8) << (6 - 3));
the_ins.opcode[0] |= ((val & 0x7) << 9);
the_ins.opcode[1] |= ((val & 0x10) << (7 - 4));
break;
case 'o':
the_ins.opcode[1] |= val << 12;
the_ins.opcode[1] |= ((val & 0x10) << (7 - 4));
break;
case 'M':
the_ins.opcode[0] |= (val & 0xF);
the_ins.opcode[1] |= ((val & 0x10) << (6 - 4));
break;
case 'N':
the_ins.opcode[1] |= (val & 0xF);
the_ins.opcode[1] |= ((val & 0x10) << (6 - 4));
break;
case 'h':
the_ins.opcode[1] |= ((val != 1) << 10);
break;
case 'F':
the_ins.opcode[0] |= ((val & 0x3) << 9);
break;
case 'f':
the_ins.opcode[0] |= ((val & 0x3) << 0);
break;
case 'G':
the_ins.opcode[0] |= ((~val & 0x1) << 7);
the_ins.opcode[1] |= ((val & 0x2) << (4 - 1));
break;
case 'H':
the_ins.opcode[0] |= ((val & 0x1) << 7);
the_ins.opcode[1] |= ((val & 0x2) << (4 - 1));
break;
case 'I':
the_ins.opcode[1] |= ((val & 0x3) << 9);
break;
case ']':
the_ins.opcode[0] |= (val & 0x1) <<10;
break;
case 'c':
default:
as_fatal (_("failed sanity check."));
}
}
static void
install_gen_operand (int mode, int val)
{
switch (mode)
{
case '/':
the_ins.opcode[0] |= (val & 0x3f);
the_ins.opcode[1] |= (((val & 0x100) >> 8) << 5);
break;
case 's':
the_ins.opcode[0] |= val;
break;
case 'd':
the_ins.opcode[0] |= (val & 0x07) << 9 | (val & 0x38) << 3;
break;
case 'b':
case 'w':
case 'l':
case 'f':
case 'F':
case 'x':
case 'p':
the_ins.opcode[0] |= val;
break;
default:
as_fatal (_("failed sanity check."));
}
}
static char *
crack_operand (char *str, struct m68k_op *opP)
{
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 || inquote || notend (str)); str++)
{
if (! inquote)
{
if (*str == '(')
parens++;
else if (*str == ')')
{
if (!parens)
{
opP->error = _("Extra )");
return str;
}
--parens;
}
}
if (flag_mri && *str == '\'')
inquote = ! inquote;
}
if (!*str && parens)
{
opP->error = _("Missing )");
return str;
}
c = *str;
*str = '\0';
if (m68k_ip_op (beg_str, opP) != 0)
{
*str = c;
return str;
}
*str = c;
if (c == '}')
c = *++str;
if (c)
{
c = *++str;
if (!c)
as_bad (_("Missing operand"));
}
if (opP->mode == CONTROL && (int)opP->reg < 0)
{
opP->mode = REGLST;
opP->mask = ~(int)opP->reg;
opP->reg = 0;
}
return str;
}
static void
insert_reg (const char *regname, int regnum)
{
char buf[100];
int i;
#ifdef REGISTER_PREFIX
if (!flag_reg_prefix_optional)
{
buf[0] = REGISTER_PREFIX;
strcpy (buf + 1, regname);
regname = buf;
}
#endif
symbol_table_insert (symbol_new (regname, reg_section, regnum,
&zero_address_frag));
for (i = 0; regname[i]; i++)
buf[i] = TOUPPER (regname[i]);
buf[i] = '\0';
symbol_table_insert (symbol_new (buf, reg_section, regnum,
&zero_address_frag));
}
struct init_entry
{
const char *name;
int number;
};
static const struct init_entry init_table[] =
{
{ "d0", DATA0 },
{ "d1", DATA1 },
{ "d2", DATA2 },
{ "d3", DATA3 },
{ "d4", DATA4 },
{ "d5", DATA5 },
{ "d6", DATA6 },
{ "d7", DATA7 },
{ "a0", ADDR0 },
{ "a1", ADDR1 },
{ "a2", ADDR2 },
{ "a3", ADDR3 },
{ "a4", ADDR4 },
{ "a5", ADDR5 },
{ "a6", ADDR6 },
{ "fp", ADDR6 },
{ "a7", ADDR7 },
{ "sp", ADDR7 },
{ "ssp", ADDR7 },
{ "fp0", FP0 },
{ "fp1", FP1 },
{ "fp2", FP2 },
{ "fp3", FP3 },
{ "fp4", FP4 },
{ "fp5", FP5 },
{ "fp6", FP6 },
{ "fp7", FP7 },
{ "fpi", FPI },
{ "fpiar", FPI },
{ "fpc", FPI },
{ "fps", FPS },
{ "fpsr", FPS },
{ "fpc", FPC },
{ "fpcr", FPC },
{ "control", FPC },
{ "status", FPS },
{ "iaddr", FPI },
{ "cop0", COP0 },
{ "cop1", COP1 },
{ "cop2", COP2 },
{ "cop3", COP3 },
{ "cop4", COP4 },
{ "cop5", COP5 },
{ "cop6", COP6 },
{ "cop7", COP7 },
{ "pc", PC },
{ "zpc", ZPC },
{ "sr", SR },
{ "ccr", CCR },
{ "cc", CCR },
{ "acc", ACC },
{ "acc0", ACC },
{ "acc1", ACC1 },
{ "acc2", ACC2 },
{ "acc3", ACC3 },
{ "accext01", ACCEXT01 },
{ "accext23", ACCEXT23 },
{ "macsr", MACSR },
{ "mask", MASK },
{ "sfc", SFC },
{ "sfcr", SFC },
{ "dfc", DFC },
{ "dfcr", DFC },
{ "cacr", CACR },
{ "caar", CAAR },
{ "usp", USP },
{ "vbr", VBR },
{ "msp", MSP },
{ "isp", ISP },
{ "itt0", ITT0 },
{ "itt1", ITT1 },
{ "dtt0", DTT0 },
{ "dtt1", DTT1 },
{ "iacr0", ITT0 },
{ "iacr1", ITT1 },
{ "dacr0", DTT0 },
{ "dacr1", DTT1 },
{ "acr0", ACR0 },
{ "acr1", ACR1 },
{ "acr2", ACR2 },
{ "acr3", ACR3 },
{ "tc", TC },
{ "tcr", TC },
{ "mmusr", MMUSR },
{ "srp", SRP },
{ "urp", URP },
{ "buscr", BUSCR },
{ "pcr", PCR },
{ "rombar", ROMBAR },
{ "rambar0", RAMBAR0 },
{ "rambar1", RAMBAR1 },
{ "mbar", MBAR },
{ "mbar0", MBAR0 },
{ "mbar1", MBAR1 },
{ "rombar0", ROMBAR },
{ "rombar1", ROMBAR1 },
{ "mpcr", MPCR },
{ "edrambar", EDRAMBAR },
{ "secmbar", SECMBAR },
{ "asid", TC },
{ "mmubar", BUSCR },
{ "pcr1u0", PCR1U0 },
{ "pcr1l0", PCR1L0 },
{ "pcr2u0", PCR2U0 },
{ "pcr2l0", PCR2L0 },
{ "pcr3u0", PCR3U0 },
{ "pcr3l0", PCR3L0 },
{ "pcr1u1", PCR1U1 },
{ "pcr1l1", PCR1L1 },
{ "pcr2u1", PCR2U1 },
{ "pcr2l1", PCR2L1 },
{ "pcr3u1", PCR3U1 },
{ "pcr3l1", PCR3L1 },
{ "flashbar", FLASHBAR },
{ "rambar", RAMBAR },
{ "mbar2", MBAR2 },
{ "ac", AC },
{ "bc", BC },
{ "cal", CAL },
{ "crp", CRP },
{ "drp", DRP },
{ "pcsr", PCSR },
{ "psr", PSR },
{ "scc", SCC },
{ "val", VAL },
{ "bad0", BAD0 },
{ "bad1", BAD1 },
{ "bad2", BAD2 },
{ "bad3", BAD3 },
{ "bad4", BAD4 },
{ "bad5", BAD5 },
{ "bad6", BAD6 },
{ "bad7", BAD7 },
{ "bac0", BAC0 },
{ "bac1", BAC1 },
{ "bac2", BAC2 },
{ "bac3", BAC3 },
{ "bac4", BAC4 },
{ "bac5", BAC5 },
{ "bac6", BAC6 },
{ "bac7", BAC7 },
{ "ic", IC },
{ "dc", DC },
{ "nc", NC },
{ "tt0", TT0 },
{ "tt1", TT1 },
{ "ac0", TT0 },
{ "ac1", TT1 },
{ "acusr", PSR },
{ "zd0", ZDATA0 },
{ "zd1", ZDATA1 },
{ "zd2", ZDATA2 },
{ "zd3", ZDATA3 },
{ "zd4", ZDATA4 },
{ "zd5", ZDATA5 },
{ "zd6", ZDATA6 },
{ "zd7", ZDATA7 },
{ "za0", ZADDR0 },
{ "za1", ZADDR1 },
{ "za2", ZADDR2 },
{ "za3", ZADDR3 },
{ "za4", ZADDR4 },
{ "za5", ZADDR5 },
{ "za6", ZADDR6 },
{ "za7", ZADDR7 },
{ "d0l", DATA0L },
{ "d1l", DATA1L },
{ "d2l", DATA2L },
{ "d3l", DATA3L },
{ "d4l", DATA4L },
{ "d5l", DATA5L },
{ "d6l", DATA6L },
{ "d7l", DATA7L },
{ "a0l", ADDR0L },
{ "a1l", ADDR1L },
{ "a2l", ADDR2L },
{ "a3l", ADDR3L },
{ "a4l", ADDR4L },
{ "a5l", ADDR5L },
{ "a6l", ADDR6L },
{ "a7l", ADDR7L },
{ "d0u", DATA0U },
{ "d1u", DATA1U },
{ "d2u", DATA2U },
{ "d3u", DATA3U },
{ "d4u", DATA4U },
{ "d5u", DATA5U },
{ "d6u", DATA6U },
{ "d7u", DATA7U },
{ "a0u", ADDR0U },
{ "a1u", ADDR1U },
{ "a2u", ADDR2U },
{ "a3u", ADDR3U },
{ "a4u", ADDR4U },
{ "a5u", ADDR5U },
{ "a6u", ADDR6U },
{ "a7u", ADDR7U },
{ 0, 0 }
};
static void
init_regtable (void)
{
int i;
for (i = 0; init_table[i].name; i++)
insert_reg (init_table[i].name, init_table[i].number);
}
static int no_68851, no_68881;
#ifdef OBJ_AOUT
int m68k_aout_machtype = 2;
#endif
void
md_assemble (char *str)
{
const char *er;
short *fromP;
char *toP = NULL;
int m, n = 0;
char *to_beg_P;
int shorts_this_frag;
fixS *fixP;
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 (&the_ins, '\0', sizeof (the_ins));
m68k_ip (str);
er = the_ins.error;
if (!er)
{
for (n = 0; n < the_ins.numargs; n++)
if (the_ins.operands[n].error)
{
er = the_ins.operands[n].error;
break;
}
}
if (er)
{
as_bad (_("%s -- statement `%s' ignored"), er, str);
return;
}
if (current_label != NULL)
{
current_label->text = 1;
current_label = NULL;
}
#ifdef OBJ_ELF
dwarf2_emit_insn (0);
#endif
if (the_ins.nfrag == 0)
{
toP = frag_more (2 * the_ins.numo);
fromP = &the_ins.opcode[0];
for (m = the_ins.numo; m; --m)
{
md_number_to_chars (toP, (long) (*fromP), 2);
toP += 2;
fromP++;
}
for (m = 0; m < the_ins.nrel; m++)
{
switch (the_ins.reloc[m].wid)
{
case 'B':
n = 1;
break;
case 'b':
n = 1;
break;
case '3':
n = 1;
break;
case 'w':
case 'W':
n = 2;
break;
case 'l':
n = 4;
break;
default:
as_fatal (_("Don't know how to figure width of %c in md_assemble()"),
the_ins.reloc[m].wid);
}
fixP = fix_new_exp (frag_now,
((toP - frag_now->fr_literal)
- the_ins.numo * 2 + the_ins.reloc[m].n),
n,
&the_ins.reloc[m].exp,
the_ins.reloc[m].pcrel,
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;
}
{
int wid;
wid = 2 * the_ins.fragb[0].fragoff;
for (n = 1; n < the_ins.nfrag; n++)
wid += 2 * (the_ins.numo - the_ins.fragb[n - 1].fragoff);
wid += 10;
frag_grow (wid);
}
for (n = 0, fromP = &the_ins.opcode[0]; n < the_ins.nfrag; n++)
{
int wid;
if (n == 0)
wid = 2 * the_ins.fragb[n].fragoff;
else
wid = 2 * (the_ins.numo - the_ins.fragb[n - 1].fragoff);
toP = frag_more (wid);
to_beg_P = toP;
shorts_this_frag = 0;
for (m = wid / 2; m; --m)
{
md_number_to_chars (toP, (long) (*fromP), 2);
toP += 2;
fromP++;
shorts_this_frag++;
}
for (m = 0; m < the_ins.nrel; m++)
{
if ((the_ins.reloc[m].n) >= 2 * shorts_this_frag)
{
the_ins.reloc[m].n -= 2 * shorts_this_frag;
break;
}
wid = the_ins.reloc[m].wid;
if (wid == 0)
continue;
the_ins.reloc[m].wid = 0;
wid = (wid == 'b') ? 1 : (wid == 'w') ? 2 : (wid == 'l') ? 4 : 4000;
fixP = fix_new_exp (frag_now,
((toP - frag_now->fr_literal)
- the_ins.numo * 2 + the_ins.reloc[m].n),
wid,
&the_ins.reloc[m].exp,
the_ins.reloc[m].pcrel,
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,
(relax_substateT) (the_ins.fragb[n].fragty),
the_ins.fragb[n].fadd, the_ins.fragb[n].foff, to_beg_P);
}
n = (the_ins.numo - the_ins.fragb[n - 1].fragoff);
shorts_this_frag = 0;
if (n)
{
toP = frag_more (n * 2);
while (n--)
{
md_number_to_chars (toP, (long) (*fromP), 2);
toP += 2;
fromP++;
shorts_this_frag++;
}
}
for (m = 0; m < the_ins.nrel; m++)
{
int wid;
wid = the_ins.reloc[m].wid;
if (wid == 0)
continue;
the_ins.reloc[m].wid = 0;
wid = (wid == 'b') ? 1 : (wid == 'w') ? 2 : (wid == 'l') ? 4 : 4000;
fixP = fix_new_exp (frag_now,
((the_ins.reloc[m].n + toP - frag_now->fr_literal)
- shorts_this_frag * 2),
wid,
&the_ins.reloc[m].exp,
the_ins.reloc[m].pcrel,
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;
}
}
static int
m68k_compare_opcode (const void * v1, const void * v2)
{
struct m68k_opcode * op1, * op2;
int ret;
op1 = *(struct m68k_opcode **) v1;
op2 = *(struct m68k_opcode **) v2;
ret = strcmp (op1->name, op2->name);
if (ret)
return ret;
if (op1 < op2)
return -1;
return 0;
}
void
md_begin (void)
{
const struct m68k_opcode *ins;
struct m68k_incant *hack, *slak;
const char *retval = 0;
int i;
if (flag_mri)
{
flag_reg_prefix_optional = 1;
m68k_abspcadd = 1;
if (! m68k_rel32_from_cmdline)
m68k_rel32 = 0;
}
m68k_sorted_opcodes = xmalloc (m68k_numopcodes * sizeof (* m68k_sorted_opcodes));
if (!m68k_sorted_opcodes)
as_fatal (_("Internal Error: Can't allocate m68k_sorted_opcodes of size %d"),
m68k_numopcodes * sizeof (* m68k_sorted_opcodes));
for (i = m68k_numopcodes; i--;)
m68k_sorted_opcodes[i] = m68k_opcodes + i;
qsort (m68k_sorted_opcodes, m68k_numopcodes,
sizeof (m68k_sorted_opcodes[0]), m68k_compare_opcode);
op_hash = hash_new ();
obstack_begin (&robyn, 4000);
for (i = 0; i < m68k_numopcodes; i++)
{
hack = slak = (struct m68k_incant *) obstack_alloc (&robyn, sizeof (struct m68k_incant));
do
{
ins = m68k_sorted_opcodes[i];
slak->m_operands = ins->args;
slak->m_opnum = strlen (slak->m_operands) / 2;
slak->m_arch = ins->arch;
slak->m_opcode = ins->opcode;
slak->m_codenum = ((ins->match) & 0xffffL) ? 2 : 1;
if (i + 1 != m68k_numopcodes
&& !strcmp (ins->name, m68k_sorted_opcodes[i + 1]->name))
{
slak->m_next = obstack_alloc (&robyn, sizeof (struct m68k_incant));
i++;
}
else
slak->m_next = 0;
slak = slak->m_next;
}
while (slak);
retval = hash_insert (op_hash, ins->name, (char *) hack);
if (retval)
as_fatal (_("Internal Error: Can't hash %s: %s"), ins->name, retval);
}
for (i = 0; i < m68k_numaliases; i++)
{
const char *name = m68k_opcode_aliases[i].primary;
const char *alias = m68k_opcode_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_insert (op_hash, alias, val);
if (retval)
as_fatal (_("Internal Error: Can't hash %s: %s"), alias, retval);
}
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 < (int) (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 < (int) sizeof (notend_table); i++)
{
notend_table[i] = 0;
alt_notend_table[i] = 0;
}
notend_table[','] = 1;
notend_table['{'] = 1;
notend_table['}'] = 1;
alt_notend_table['a'] = 1;
alt_notend_table['A'] = 1;
alt_notend_table['d'] = 1;
alt_notend_table['D'] = 1;
alt_notend_table['#'] = 1;
alt_notend_table['&'] = 1;
alt_notend_table['f'] = 1;
alt_notend_table['F'] = 1;
#ifdef REGISTER_PREFIX
alt_notend_table[REGISTER_PREFIX] = 1;
#endif
alt_notend_table['('] = 1;
alt_notend_table['@'] = 1;
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
{
int n = 0;
while (mote_pseudo_table[n].poc_name)
{
hack = obstack_alloc (&robyn, sizeof (struct m68k_incant));
hash_insert (op_hash,
mote_pseudo_table[n].poc_name, (char *) hack);
hack->m_operands = 0;
hack->m_opnum = n;
n++;
}
}
#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 (void)
{
switch (current_chip)
{
case 0:
if (verbose)
as_warn (_("architecture not yet selected: defaulting to 68020"));
control_regs = m68020_control_regs;
break;
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:
case mcf5206e:
case mcf5307:
case mcf5407:
control_regs = mcf_control_regs;
break;
case mcf5249:
control_regs = mcf5249_control_regs;
break;
case mcf528x:
case mcf521x:
control_regs = mcf528x_control_regs;
break;
case mcf5470:
case mcf5480:
control_regs = mcfv4e_control_regs;
break;
default:
abort ();
}
}
void
m68k_init_after_args (void)
{
if (cpu_of_arch (current_architecture) == 0)
{
int i;
const char *default_cpu = TARGET_CPU;
if (*default_cpu == 'm')
default_cpu++;
for (i = 0; i < n_archs; i++)
if (strcasecmp (default_cpu, archs[i].name) == 0)
break;
if (i == n_archs)
{
as_bad (_("unrecognized default cpu `%s' ???"), TARGET_CPU);
current_architecture |= m68020;
}
else
current_architecture |= archs[i].arch;
}
if (current_architecture & m68851)
{
if (current_architecture & m68040)
as_warn (_("68040 and 68851 specified; mmu instructions may assemble incorrectly"));
}
if (!no_68881
&& (cpu_of_arch (current_architecture)
& (m68020 | m68030 | cpu32)))
current_architecture |= m68881;
if (!no_68851
&& (cpu_of_arch (current_architecture) & m68020up) != 0
&& (cpu_of_arch (current_architecture) & m68040up) == 0)
current_architecture |= m68851;
if (no_68881 && (current_architecture & m68881))
as_bad (_("options for 68881 and no-68881 both given"));
if (no_68851 && (current_architecture & m68851))
as_bad (_("options for 68851 and no-68851 both given"));
#ifdef OBJ_AOUT
if (current_architecture & m68000)
m68k_aout_machtype = 0;
else if (current_architecture & m68010)
m68k_aout_machtype = 1;
else if (current_architecture & m68020)
m68k_aout_machtype = 2;
else
m68k_aout_machtype = 2;
#endif
select_control_regs ();
if (cpu_of_arch (current_architecture) < m68020
|| arch_coldfire_p (current_architecture))
md_relax_table[TAB (PCINDEX, BYTE)].rlx_more = 0;
}
void
m68k_frob_label (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);
n->text = 0;
labels = n;
current_label = n;
}
void
m68k_flush_pending_output (void)
{
current_label = NULL;
}
void
m68k_frob_symbol (symbolS *sym)
{
if (S_GET_SEGMENT (sym) == reg_section
&& (int) S_GET_VALUE (sym) < 0)
{
S_SET_SEGMENT (sym, absolute_section);
S_SET_VALUE (sym, ~(int)S_GET_VALUE (sym));
}
else 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;
}
}
}
}
void
m68k_mri_mode_change (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;
}
}
#define MAX_LITTLENUMS 6
char *
md_atof (int type, char *litP, int *sizeP)
{
int prec;
LITTLENUM_TYPE words[MAX_LITTLENUMS];
LITTLENUM_TYPE *wordP;
char *t;
switch (type)
{
case 'f':
case 'F':
case 's':
case 'S':
prec = 2;
break;
case 'd':
case 'D':
case 'r':
case 'R':
prec = 4;
break;
case 'x':
case 'X':
prec = 6;
break;
case 'p':
case 'P':
prec = 6;
break;
default:
*sizeP = 0;
return _("Bad call to MD_ATOF()");
}
t = atof_ieee (input_line_pointer, type, words);
if (t)
input_line_pointer = t;
*sizeP = prec * sizeof (LITTLENUM_TYPE);
for (wordP = words; prec--;)
{
md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE));
litP += sizeof (LITTLENUM_TYPE);
}
return 0;
}
void
md_number_to_chars (char *buf, valueT val, int n)
{
number_to_chars_bigendian (buf, val, n);
}
void
md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
{
offsetT val = *valP;
addressT upper_limit;
offsetT lower_limit;
char *buf = fixP->fx_frag->fr_literal;
buf += fixP->fx_where;
val = SEXT (val);
if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
fixP->fx_done = 1;
#ifdef OBJ_ELF
if (fixP->fx_addsy)
{
memset (buf, 0, fixP->fx_size);
fixP->fx_addnumber = val;
if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
&& !S_IS_DEFINED (fixP->fx_addsy)
&& !S_IS_WEAK (fixP->fx_addsy))
S_SET_WEAK (fixP->fx_addsy);
return;
}
#endif
#ifdef BFD_ASSEMBLER
if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
return;
#endif
switch (fixP->fx_size)
{
case 1:
*buf++ = val;
upper_limit = 0x7f;
lower_limit = - (offsetT) 0x80;
break;
case 2:
*buf++ = (val >> 8);
*buf++ = val;
upper_limit = 0x7fff;
lower_limit = - (offsetT) 0x8000;
break;
case 4:
*buf++ = (val >> 24);
*buf++ = (val >> 16);
*buf++ = (val >> 8);
*buf++ = val;
upper_limit = 0x7fffffff;
lower_limit = - (offsetT) 0x7fffffff - 1;
break;
default:
BAD_CASE (fixP->fx_size);
}
if (fixP->fx_addsy == NULL && fixP->fx_subsy != NULL)
{
fixP->fx_addsy = fixP->fx_subsy;
fixP->fx_subsy = NULL;
fixP->fx_tcbit = 1;
}
if (! fixP->fx_pcrel && ! fixP->fx_signed)
upper_limit = upper_limit * 2 + 1;
if ((addressT) val > upper_limit
&& (val > 0 || val < lower_limit))
as_bad_where (fixP->fx_file, fixP->fx_line, _("value out of range"));
if ((fixP->fx_pcrel
#ifdef BFD_ASSEMBLER
|| fixP->fx_r_type == BFD_RELOC_8_PCREL
#endif
)
&& fixP->fx_size == 1
&& (fixP->fx_addsy == NULL
|| S_IS_DEFINED (fixP->fx_addsy))
&& (val == 0 || val == -1))
as_bad_where (fixP->fx_file, fixP->fx_line, _("invalid byte branch offset"));
}
static void
md_convert_frag_1 (fragS *fragP)
{
long disp;
fixS *fixP;
register int object_address = fragP->fr_fix + fragP->fr_address;
register char *buffer_address = fragP->fr_literal;
buffer_address += fragP->fr_fix;
disp = fragP->fr_symbol ? S_GET_VALUE (fragP->fr_symbol) : 0;
disp = (disp + fragP->fr_offset) - object_address;
switch (fragP->fr_subtype)
{
case TAB (BRANCHBWL, BYTE):
case TAB (BRABSJUNC, BYTE):
case TAB (BRABSJCOND, BYTE):
case TAB (BRANCHBW, BYTE):
know (issbyte (disp));
if (disp == 0)
as_bad_where (fragP->fr_file, fragP->fr_line,
_("short branch with zero offset: use :w"));
fixP = fix_new (fragP, fragP->fr_fix - 1, 1, fragP->fr_symbol,
fragP->fr_offset, 1, RELAX_RELOC_PC8);
fixP->fx_pcrel_adjust = -1;
break;
case TAB (BRANCHBWL, SHORT):
case TAB (BRABSJUNC, SHORT):
case TAB (BRABSJCOND, SHORT):
case TAB (BRANCHBW, SHORT):
fragP->fr_opcode[1] = 0x00;
fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
1, RELAX_RELOC_PC16);
fragP->fr_fix += 2;
break;
case TAB (BRANCHBWL, LONG):
fragP->fr_opcode[1] = (char) 0xFF;
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
1, RELAX_RELOC_PC32);
fragP->fr_fix += 4;
break;
case TAB (BRABSJUNC, LONG):
if (fragP->fr_opcode[0] == 0x61)
{
if (flag_keep_pcrel)
as_fatal (_("Tried to convert PC relative BSR to absolute JSR"));
fragP->fr_opcode[0] = 0x4E;
fragP->fr_opcode[1] = (char) 0xB9;
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
0, RELAX_RELOC_ABS32);
fragP->fr_fix += 4;
}
else if (fragP->fr_opcode[0] == 0x60)
{
if (flag_keep_pcrel)
as_fatal (_("Tried to convert PC relative branch to absolute jump"));
fragP->fr_opcode[0] = 0x4E;
fragP->fr_opcode[1] = (char) 0xF9;
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
0, RELAX_RELOC_ABS32);
fragP->fr_fix += 4;
}
else
{
abort ();
}
break;
case TAB (BRABSJCOND, LONG):
if (flag_keep_pcrel)
as_fatal (_("Tried to convert PC relative conditional branch to absolute jump"));
fragP->fr_opcode[0] ^= 0x01;
fragP->fr_opcode[1] = 0x06;
*buffer_address++ = 0x4e;
*buffer_address++ = (char) 0xf9;
fragP->fr_fix += 2;
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
fragP->fr_offset, 0, RELAX_RELOC_ABS32);
fragP->fr_fix += 4;
break;
case TAB (FBRANCH, SHORT):
know ((fragP->fr_opcode[1] & 0x40) == 0);
fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
1, RELAX_RELOC_PC16);
fragP->fr_fix += 2;
break;
case TAB (FBRANCH, LONG):
fragP->fr_opcode[1] |= 0x40;
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
1, RELAX_RELOC_PC32);
fragP->fr_fix += 4;
break;
case TAB (DBCCLBR, SHORT):
case TAB (DBCCABSJ, SHORT):
fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
1, RELAX_RELOC_PC16);
fragP->fr_fix += 2;
break;
case TAB (DBCCLBR, LONG):
if (flag_keep_pcrel)
as_fatal (_("Tried to convert DBcc to absolute jump"));
*buffer_address++ = 0x00;
*buffer_address++ = 0x04;
*buffer_address++ = 0x60;
*buffer_address++ = 0x06;
*buffer_address++ = 0x60;
*buffer_address++ = (char) 0xff;
fragP->fr_fix += 6;
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset, 1,
RELAX_RELOC_PC32);
fragP->fr_fix += 4;
break;
case TAB (DBCCABSJ, LONG):
if (flag_keep_pcrel)
as_fatal (_("Tried to convert PC relative conditional branch to absolute jump"));
*buffer_address++ = 0x00;
*buffer_address++ = 0x04;
*buffer_address++ = 0x60;
*buffer_address++ = 0x06;
*buffer_address++ = 0x4e;
*buffer_address++ = (char) 0xf9;
fragP->fr_fix += 6;
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset, 0,
RELAX_RELOC_ABS32);
fragP->fr_fix += 4;
break;
case TAB (PCREL1632, SHORT):
fragP->fr_opcode[1] &= ~0x3F;
fragP->fr_opcode[1] |= 0x3A;
fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol,
fragP->fr_offset, 1, RELAX_RELOC_PC16);
fragP->fr_fix += 2;
break;
case TAB (PCREL1632, LONG):
*buffer_address++ = 0x01;
*buffer_address++ = 0x70;
fragP->fr_fix += 2;
fixP = fix_new (fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol,
fragP->fr_offset, 1, RELAX_RELOC_PC32);
fixP->fx_pcrel_adjust = 2;
fragP->fr_fix += 4;
break;
case TAB (PCINDEX, BYTE):
assert (fragP->fr_fix >= 2);
buffer_address[-2] &= ~1;
fixP = fix_new (fragP, fragP->fr_fix - 1, 1, fragP->fr_symbol,
fragP->fr_offset, 1, RELAX_RELOC_PC8);
fixP->fx_pcrel_adjust = 1;
break;
case TAB (PCINDEX, SHORT):
assert (fragP->fr_fix >= 2);
buffer_address[-2] |= 0x1;
buffer_address[-1] = 0x20;
fixP = fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol,
fragP->fr_offset, 1, RELAX_RELOC_PC16);
fixP->fx_pcrel_adjust = 2;
fragP->fr_fix += 2;
break;
case TAB (PCINDEX, LONG):
assert (fragP->fr_fix >= 2);
buffer_address[-2] |= 0x1;
buffer_address[-1] = 0x30;
fixP = fix_new (fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol,
fragP->fr_offset, 1, RELAX_RELOC_PC32);
fixP->fx_pcrel_adjust = 2;
fragP->fr_fix += 4;
break;
case TAB (ABSTOPCREL, SHORT):
fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
1, RELAX_RELOC_PC16);
fragP->fr_fix += 2;
break;
case TAB (ABSTOPCREL, LONG):
if (flag_keep_pcrel)
as_fatal (_("Tried to convert PC relative conditional branch to absolute jump"));
if ((fragP->fr_opcode[1] & 0x3F) != 0x3A)
abort ();
fragP->fr_opcode[1] &= ~0x3F;
fragP->fr_opcode[1] |= 0x39;
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
0, RELAX_RELOC_ABS32);
fragP->fr_fix += 4;
break;
}
}
#ifndef BFD_ASSEMBLER
void
md_convert_frag (object_headers *headers ATTRIBUTE_UNUSED,
segT sec ATTRIBUTE_UNUSED,
fragS *fragP)
{
md_convert_frag_1 (fragP);
}
#else
void
md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
segT sec ATTRIBUTE_UNUSED,
fragS *fragP)
{
md_convert_frag_1 (fragP);
}
#endif
int
md_estimate_size_before_relax (fragS *fragP, segT segment)
{
switch (fragP->fr_subtype)
{
case TAB (BRANCHBWL, SZ_UNDEF):
case TAB (BRABSJUNC, SZ_UNDEF):
case TAB (BRABSJCOND, SZ_UNDEF):
{
if (S_GET_SEGMENT (fragP->fr_symbol) == segment
&& relaxable_symbol (fragP->fr_symbol))
{
fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), BYTE);
}
else if (flag_short_refs)
{
fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
}
else
{
fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), LONG);
}
break;
}
case TAB (BRANCHBW, SZ_UNDEF):
{
if (S_GET_SEGMENT (fragP->fr_symbol) == segment
&& relaxable_symbol (fragP->fr_symbol))
{
fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), BYTE);
}
else
{
fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
}
break;
}
case TAB (FBRANCH, SZ_UNDEF):
case TAB (DBCCLBR, SZ_UNDEF):
case TAB (DBCCABSJ, SZ_UNDEF):
case TAB (PCREL1632, SZ_UNDEF):
{
if ((S_GET_SEGMENT (fragP->fr_symbol) == segment
&& relaxable_symbol (fragP->fr_symbol))
|| flag_short_refs)
{
fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
}
else
{
fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), LONG);
}
break;
}
case TAB (PCINDEX, SZ_UNDEF):
if ((S_GET_SEGMENT (fragP->fr_symbol) == segment
&& relaxable_symbol (fragP->fr_symbol)))
{
fragP->fr_subtype = TAB (PCINDEX, BYTE);
}
else
{
fragP->fr_subtype = TAB (PCINDEX, LONG);
}
break;
case TAB (ABSTOPCREL, SZ_UNDEF):
{
if ((S_GET_SEGMENT (fragP->fr_symbol) == segment
&& relaxable_symbol (fragP->fr_symbol)))
{
fragP->fr_subtype = TAB (ABSTOPCREL, SHORT);
}
else
{
fragP->fr_subtype = TAB (ABSTOPCREL, LONG);
}
break;
}
default:
break;
}
switch (fragP->fr_subtype)
{
case TAB (BRANCHBWL, BYTE):
case TAB (BRABSJUNC, BYTE):
case TAB (BRABSJCOND, BYTE):
case TAB (BRANCHBW, BYTE):
if (fragP->fr_symbol)
{
fragS *sym_frag;
sym_frag = symbol_get_frag (fragP->fr_symbol);
if (S_GET_VALUE (fragP->fr_symbol) == sym_frag->fr_address)
{
fragS *l;
for (l = fragP->fr_next; l && l != sym_frag; l = l->fr_next)
if (l->fr_fix != 0)
break;
if (l == sym_frag)
fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
}
}
break;
default:
break;
}
return md_relax_table[fragP->fr_subtype].rlx_length;
}
#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
#ifdef comment
void
md_ri_to_chars (char *the_bytes, struct reloc_info_generic *ri)
{
md_number_to_chars (the_bytes, ri->r_address, 4);
the_bytes[4] = (ri->r_symbolnum >> 16) & 0x0ff;
the_bytes[5] = (ri->r_symbolnum >> 8) & 0x0ff;
the_bytes[6] = ri->r_symbolnum & 0x0ff;
the_bytes[7] = (((ri->r_pcrel << 7) & 0x80)
| ((ri->r_length << 5) & 0x60)
| ((ri->r_extern << 4) & 0x10));
}
#endif
#ifndef BFD_ASSEMBLER
void
tc_aout_fix_to_chars (char *where, fixS *fixP,
relax_addressT segment_address_in_file)
{
static const unsigned char nbytes_r_length[] = {42, 0, 1, 42, 2};
long r_symbolnum;
know (fixP->fx_addsy != NULL);
md_number_to_chars (where,
(fixP->fx_frag->fr_address
+ fixP->fx_where - segment_address_in_file), 4);
r_symbolnum = (S_IS_DEFINED (fixP->fx_addsy)
? S_GET_TYPE (fixP->fx_addsy)
: fixP->fx_addsy->sy_number);
where[4] = (r_symbolnum >> 16) & 0x0ff;
where[5] = (r_symbolnum >> 8) & 0x0ff;
where[6] = r_symbolnum & 0x0ff;
where[7] = (((fixP->fx_pcrel << 7) & 0x80)
| ((nbytes_r_length[fixP->fx_size] << 5) & 0x60)
| ((!S_IS_DEFINED (fixP->fx_addsy) << 4) & 0x10));
}
#endif
#endif
#ifndef WORKING_DOT_WORD
int md_short_jump_size = 4;
int md_long_jump_size = 6;
void
md_create_short_jump (char *ptr, addressT from_addr, addressT to_addr,
fragS *frag ATTRIBUTE_UNUSED,
symbolS *to_symbol ATTRIBUTE_UNUSED)
{
valueT offset;
offset = to_addr - (from_addr + 2);
md_number_to_chars (ptr, (valueT) 0x6000, 2);
md_number_to_chars (ptr + 2, (valueT) offset, 2);
}
void
md_create_long_jump (char *ptr, addressT from_addr, addressT to_addr,
fragS *frag, symbolS *to_symbol)
{
valueT offset;
if (!HAVE_LONG_BRANCH (current_architecture))
{
if (flag_keep_pcrel)
as_fatal (_("Tried to convert PC relative branch to absolute jump"));
offset = to_addr - S_GET_VALUE (to_symbol);
md_number_to_chars (ptr, (valueT) 0x4EF9, 2);
md_number_to_chars (ptr + 2, (valueT) offset, 4);
fix_new (frag, (ptr + 2) - frag->fr_literal, 4, to_symbol, (offsetT) 0,
0, NO_RELOC);
}
else
{
offset = to_addr - (from_addr + 2);
md_number_to_chars (ptr, (valueT) 0x60ff, 2);
md_number_to_chars (ptr + 2, (valueT) offset, 4);
}
}
#endif
static int
get_num (struct m68k_exp *exp, int ok)
{
if (exp->exp.X_op == O_absent)
{
op (exp) = O_constant;
adds (exp) = 0;
subs (exp) = 0;
offs (exp) = 0;
if (ok == 10)
{
as_warn (_("expression out of range: defaulting to 1"));
offs (exp) = 1;
}
}
else if (exp->exp.X_op == O_constant)
{
switch (ok)
{
case 10:
if ((valueT) TRUNC (offs (exp)) - 1 > 7)
{
as_warn (_("expression out of range: defaulting to 1"));
offs (exp) = 1;
}
break;
case 20:
if ((valueT) TRUNC (offs (exp)) > 7)
goto outrange;
break;
case 30:
if ((valueT) TRUNC (offs (exp)) > 15)
goto outrange;
break;
case 40:
if ((valueT) TRUNC (offs (exp)) > 32)
goto outrange;
break;
case 50:
if ((valueT) TRUNC (offs (exp)) > 127)
goto outrange;
break;
case 55:
if ((valueT) SEXT (offs (exp)) + 64 > 127)
goto outrange;
break;
case 60:
if ((valueT) SEXT (offs (exp)) + 128 > 255)
goto outrange;
break;
case 70:
if ((valueT) TRUNC (offs (exp)) > 4095)
{
outrange:
as_warn (_("expression out of range: defaulting to 0"));
offs (exp) = 0;
}
break;
case 80:
if ((valueT) TRUNC (offs (exp)) != 0xffffffff
&& (valueT) TRUNC (offs (exp)) - 1 > 6)
{
as_warn (_("expression out of range: defaulting to 1"));
offs (exp) = 1;
}
break;
default:
break;
}
}
else if (exp->exp.X_op == O_big)
{
if (offs (exp) <= 0
&& (ok == 90
|| (ok > 10
&& generic_floating_point_number.exponent == 0
&& generic_floating_point_number.low[0] == 0)))
{
LITTLENUM_TYPE words[6];
gen_to_words (words, 2, 8L);
op (exp) = O_constant;
adds (exp) = 0;
subs (exp) = 0;
offs (exp) = words[1] | (words[0] << 16);
}
else if (ok != 0)
{
op (exp) = O_constant;
adds (exp) = 0;
subs (exp) = 0;
offs (exp) = (ok == 10) ? 1 : 0;
as_warn (_("Can't deal with expression; defaulting to %ld"),
offs (exp));
}
}
else
{
if (ok >= 10 && ok <= 80)
{
op (exp) = O_constant;
adds (exp) = 0;
subs (exp) = 0;
offs (exp) = (ok == 10) ? 1 : 0;
as_warn (_("Can't deal with expression; defaulting to %ld"),
offs (exp));
}
}
if (exp->size != SIZE_UNSPEC)
{
switch (exp->size)
{
case SIZE_UNSPEC:
case SIZE_LONG:
break;
case SIZE_BYTE:
if (!isbyte (offs (exp)))
as_warn (_("expression doesn't fit in BYTE"));
break;
case SIZE_WORD:
if (!isword (offs (exp)))
as_warn (_("expression doesn't fit in WORD"));
break;
}
}
return offs (exp);
}
static void
s_data1 (int ignore ATTRIBUTE_UNUSED)
{
subseg_set (data_section, 1);
demand_empty_rest_of_line ();
}
static void
s_data2 (int ignore ATTRIBUTE_UNUSED)
{
subseg_set (data_section, 2);
demand_empty_rest_of_line ();
}
static void
s_bss (int ignore ATTRIBUTE_UNUSED)
{
subseg_set (bss_section, 0);
demand_empty_rest_of_line ();
}
static void
s_even (int ignore ATTRIBUTE_UNUSED)
{
register int temp;
register long temp_fill;
temp = 1;
temp_fill = get_absolute_expression ();
if (!need_pass_2)
frag_align (temp, (int) temp_fill, 0);
demand_empty_rest_of_line ();
record_alignment (now_seg, temp);
}
static void
s_proc (int ignore ATTRIBUTE_UNUSED)
{
demand_empty_rest_of_line ();
}
int
m68k_conditional_pseudoop (pseudo_typeS *pop)
{
return (pop->poc_handler == s_mri_if
|| pop->poc_handler == s_mri_else);
}
static void
mri_chip (void)
{
char *s;
char c;
int i;
s = input_line_pointer;
while (is_part_of_name (c = *input_line_pointer++))
;
*--input_line_pointer = 0;
for (i = 0; i < n_archs; i++)
if (strcasecmp (s, archs[i].name) == 0)
break;
if (i >= n_archs)
{
as_bad (_("%s: unrecognized processor name"), s);
*input_line_pointer = c;
ignore_rest_of_line ();
return;
}
*input_line_pointer = c;
if (*input_line_pointer == '/')
current_architecture = 0;
else
current_architecture &= m68881 | m68851;
current_architecture |= archs[i].arch;
current_chip = archs[i].chip;
while (*input_line_pointer == '/')
{
++input_line_pointer;
s = input_line_pointer;
while (is_part_of_name (c = *input_line_pointer++))
;
*--input_line_pointer = 0;
if (strcmp (s, "68881") == 0)
current_architecture |= m68881;
else if (strcmp (s, "68851") == 0)
current_architecture |= m68851;
*input_line_pointer = c;
}
select_control_regs ();
}
static void
s_chip (int ignore ATTRIBUTE_UNUSED)
{
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 ();
}
static void
s_fopt (int ignore ATTRIBUTE_UNUSED)
{
SKIP_WHITESPACE ();
if (strncasecmp (input_line_pointer, "ID=", 3) == 0)
{
int temp;
input_line_pointer += 3;
temp = get_absolute_expression ();
if (temp < 0 || temp > 7)
as_bad (_("bad coprocessor id"));
else
m68k_float_copnum = COP0 + temp;
}
else
{
as_bad (_("unrecognized fopt option"));
ignore_rest_of_line ();
return;
}
demand_empty_rest_of_line ();
}
struct opt_action
{
const char *name;
void (*pfn) (int arg, int on);
int *pvar;
int arg;
int notarg;
};
static void skip_to_comma (int, int);
static void opt_nest (int, int);
static void opt_chip (int, int);
static void opt_list (int, int);
static void opt_list_symbols (int, int);
static const struct opt_action opt_table[] =
{
{ "abspcadd", 0, &m68k_abspcadd, 1, 0 },
{ "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 }
};
#define OPTCOUNT ((int) (sizeof opt_table / sizeof opt_table[0]))
static void
s_opt (int ignore ATTRIBUTE_UNUSED)
{
do
{
int t;
char *s;
char c;
int i;
const struct opt_action *o;
SKIP_WHITESPACE ();
t = 1;
if (*input_line_pointer == '-')
{
++input_line_pointer;
t = 0;
}
else if (strncasecmp (input_line_pointer, "NO", 2) == 0)
{
input_line_pointer += 2;
t = 0;
}
s = input_line_pointer;
c = get_symbol_end ();
for (i = 0, o = opt_table; i < OPTCOUNT; i++, o++)
{
if (strcasecmp (s, o->name) == 0)
{
if (o->pfn)
{
*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 >= OPTCOUNT)
{
as_bad (_("option `%s' not recognized"), s);
*input_line_pointer = c;
}
}
while (*input_line_pointer++ == ',');
--input_line_pointer;
demand_empty_rest_of_line ();
}
static void
skip_to_comma (int arg ATTRIBUTE_UNUSED, int on ATTRIBUTE_UNUSED)
{
while (*input_line_pointer != ','
&& ! is_end_of_line[(unsigned char) *input_line_pointer])
++input_line_pointer;
}
static void
opt_nest (int arg ATTRIBUTE_UNUSED, int on ATTRIBUTE_UNUSED)
{
if (*input_line_pointer != '=')
{
as_bad (_("bad format of OPT NEST=depth"));
return;
}
++input_line_pointer;
max_macro_nest = get_absolute_expression ();
}
static void
opt_chip (int arg ATTRIBUTE_UNUSED, int on ATTRIBUTE_UNUSED)
{
if (*input_line_pointer != '=')
{
return;
}
++input_line_pointer;
mri_chip ();
}
static void
opt_list (int arg ATTRIBUTE_UNUSED, int on)
{
listing_list (on);
}
static void
opt_list_symbols (int arg ATTRIBUTE_UNUSED, int on)
{
if (on)
listing |= LISTING_SYMBOLS;
else
listing &= ~LISTING_SYMBOLS;
}
static void
s_reg (int ignore ATTRIBUTE_UNUSED)
{
char *s;
int c;
struct m68k_op rop;
int 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 (*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, reg_section);
S_SET_VALUE (line_label, ~mask);
symbol_set_frag (line_label, &zero_address_frag);
if (flag_mri)
mri_comment_end (stop, stopc);
demand_empty_rest_of_line ();
}
struct save_opts
{
struct save_opts *next;
int abspcadd;
int symbols_case_sensitive;
int keep_locals;
int short_refs;
int architecture;
int chip;
int quick;
int rel32;
int listing;
int no_warnings;
};
static struct save_opts *save_stack;
static void
s_save (int ignore ATTRIBUTE_UNUSED)
{
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->chip = current_chip;
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 ();
}
static void
s_restore (int ignore ATTRIBUTE_UNUSED)
{
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;
current_chip = s->chip;
m68k_quick = s->quick;
m68k_rel32 = s->rel32;
listing = s->listing;
flag_no_warnings = s->no_warnings;
free (s);
demand_empty_rest_of_line ();
}
enum mri_control_type
{
mri_for,
mri_if,
mri_repeat,
mri_while
};
struct mri_control_info
{
struct mri_control_info *outer;
enum mri_control_type type;
int else_seen;
char *incr;
char *top;
char *next;
char *bottom;
};
static struct mri_control_info *mri_control_stack;
static int mri_control_index;
static void
mri_assemble (char *str)
{
char *s;
for (s = str; *s != ' ' && *s != '\0'; s++)
*s = TOLOWER (*s);
md_assemble (str);
}
static char *
mri_control_label (void)
{
char *n;
n = (char *) xmalloc (20);
sprintf (n, "%smc%d", FAKE_LABEL_NAME, mri_control_index);
++mri_control_index;
return n;
}
static struct mri_control_info *
push_mri_control (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;
}
static void
pop_mri_control (void)
{
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);
}
static int
parse_mri_condition (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 ();
c1 = TOLOWER (c1);
c2 = TOLOWER (c2);
*pcc = (c1 << 8) | c2;
return 1;
}
static int
parse_mri_control_operand (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 == '<')
{
return parse_mri_condition (pcc);
}
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;
for (s = input_line_pointer; *s != '\0'; ++s)
{
if ((s == input_line_pointer
|| *(s-1) == ' '
|| *(s-1) == '\t')
&& ((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))
static int
swap_mri_condition (int cc)
{
switch (cc)
{
case MCC ('h', 'i'): return MCC ('c', 's');
case MCC ('l', 's'): return MCC ('c', 'c');
case MCC ('h', 's'):
case MCC ('c', 'c'): return MCC ('l', 's');
case MCC ('l', 'o'):
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');
case MCC ('n', 'e'): return MCC ('n', 'e'); case MCC ('e', 'q'): return MCC ('e', 'q'); case MCC ('v', 'c'):
case MCC ('v', 's'):
default :
as_warn (_("Condition <%c%c> in structured control directive can not be encoded correctly"),
(char) (cc >> 8), (char) (cc));
break;
}
return cc;
}
static int
reverse_mri_condition (int cc)
{
switch (cc)
{
case MCC ('h', 'i'): return MCC ('l', 's');
case MCC ('l', 's'): return MCC ('h', 'i');
case MCC ('h', 's'): return MCC ('l', 'o');
case MCC ('c', 'c'): return MCC ('c', 's');
case MCC ('l', 'o'): return MCC ('h', '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;
}
static void
build_mri_control_operand (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;
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;
temp = leftstart;
leftstart = rightstart;
rightstart = temp;
temp = leftstop;
leftstop = rightstop;
rightstop = temp;
}
else
{
cc = swap_mri_condition (cc);
}
}
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++ = TOLOWER (qual);
*s++ = ' ';
memcpy (s, leftstart, leftstop - leftstart);
s += leftstop - leftstart;
*s++ = ',';
memcpy (s, rightstart, rightstop - rightstart);
s += rightstop - rightstart;
*s = '\0';
mri_assemble (buf);
free (buf);
}
buf = (char *) xmalloc (20 + strlen (truelab));
s = buf;
*s++ = 'b';
*s++ = cc >> 8;
*s++ = cc & 0xff;
if (extent != '\0')
*s++ = TOLOWER (extent);
*s++ = ' ';
strcpy (s, truelab);
mri_assemble (buf);
free (buf);
}
static void
parse_mri_control_expression (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"));
}
static void
s_mri_if (int qual)
{
char *s;
int c;
struct mri_control_info *n;
s = input_line_pointer;
while (! (is_end_of_line[(unsigned char) *s]
|| (flag_mri
&& *s == '*'
&& (s == input_line_pointer
|| *(s-1) == ' '
|| *(s-1) == '\t'))))
++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;
}
s_if (O_ne);
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;
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 ();
}
static void
s_mri_else (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] = TOLOWER (qual);
q[1] = '\0';
sprintf (buf, "bra%s %s", q, mri_control_stack->bottom);
mri_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 ();
}
static void
s_mri_endi (int ignore ATTRIBUTE_UNUSED)
{
if (mri_control_stack == NULL
|| mri_control_stack->type != mri_if)
{
as_bad (_("endi without matching if"));
ignore_rest_of_line ();
return;
}
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 ();
}
static void
s_mri_break (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] = TOLOWER (extent);
ex[1] = '\0';
sprintf (buf, "bra%s %s", ex, n->bottom);
mri_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 ();
}
static void
s_mri_next (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] = TOLOWER (extent);
ex[1] = '\0';
sprintf (buf, "bra%s %s", ex, n->next);
mri_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 ();
}
static void
s_mri_for (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];
SKIP_WHITESPACE ();
varstart = input_line_pointer;
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;
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;
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;
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;
}
n = push_mri_control (mri_for);
buf = (char *) xmalloc (50 + (input_line_pointer - varstart));
s = buf;
*s++ = 'm';
*s++ = 'o';
*s++ = 'v';
*s++ = 'e';
if (qual != '\0')
*s++ = TOLOWER (qual);
*s++ = ' ';
memcpy (s, initstart, initstop - initstart);
s += initstop - initstart;
*s++ = ',';
memcpy (s, varstart, varstop - varstart);
s += varstop - varstart;
*s = '\0';
mri_assemble (buf);
colon (n->top);
s = buf;
*s++ = 'c';
*s++ = 'm';
*s++ = 'p';
if (qual != '\0')
*s++ = TOLOWER (qual);
*s++ = ' ';
memcpy (s, endstart, endstop - endstart);
s += endstop - endstart;
*s++ = ',';
memcpy (s, varstart, varstop - varstart);
s += varstop - varstart;
*s = '\0';
mri_assemble (buf);
ex[0] = TOLOWER (extent);
ex[1] = '\0';
if (up)
sprintf (buf, "blt%s %s", ex, n->bottom);
else
sprintf (buf, "bgt%s %s", ex, n->bottom);
mri_assemble (buf);
s = buf;
if (up)
strcpy (s, "add");
else
strcpy (s, "sub");
s += 3;
if (qual != '\0')
*s++ = TOLOWER (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 ();
}
static void
s_mri_endf (int ignore ATTRIBUTE_UNUSED)
{
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);
mri_assemble (mri_control_stack->incr);
sprintf (mri_control_stack->incr, "bra %s", mri_control_stack->top);
mri_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 ();
}
static void
s_mri_repeat (int ignore ATTRIBUTE_UNUSED)
{
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 ();
}
static void
s_mri_until (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 ();
}
static void
s_mri_while (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 == input_line_pointer
|| *(s-1) == ' '
|| *(s-1) == '\t'))))
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 ();
}
static void
s_mri_endw (int ignore ATTRIBUTE_UNUSED)
{
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);
mri_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 ();
}
#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},
#define OPTION_PCREL (OPTION_MD_BASE + 7)
{"pcrel", no_argument, NULL, OPTION_PCREL},
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
int
md_parse_option (int c, char *arg)
{
switch (c)
{
case 'l':
flag_short_refs = 1;
break;
case 'S':
flag_long_jumps = 1;
break;
case OPTION_PCREL:
flag_keep_pcrel = 1;
break;
case 'A':
if (*arg == 'm')
arg++;
case 'm':
if (arg[0] == 'n' && arg[1] == 'o' && arg[2] == '-')
{
int i;
unsigned long arch;
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)
return 0;
arch = archs[i].arch;
if (arch == m68881)
no_68881 = 1;
else if (arch == m68851)
no_68851 = 1;
else
return 0;
}
else
{
int i;
if (arg[0] == 'c' && arg[1] == '6')
arg++;
for (i = 0; i < n_archs; i++)
if (!strcmp (arg, archs[i].name))
{
unsigned long arch = archs[i].arch;
if (cpu_of_arch (arch))
{
current_architecture &= ~m68000up;
current_architecture |= arch;
current_chip = archs[i].chip;
}
else if (arch == m68881)
{
current_architecture |= m68881;
no_68881 = 0;
}
else if (arch == m68851)
{
current_architecture |= m68851;
no_68851 = 0;
}
else
abort ();
break;
}
if (i == n_archs)
{
as_bad (_("unrecognized architecture specification `%s'"), arg);
return 0;
}
}
break;
case OPTION_PIC:
case 'k':
flag_want_pic = 1;
break;
case OPTION_REGISTER_PREFIX_OPTIONAL:
flag_reg_prefix_optional = 1;
reg_prefix_optional_seen = 1;
break;
case 'V':
print_version_id ();
break;
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:
return 0;
}
return 1;
}
void
md_show_usage (FILE *stream)
{
const char *default_cpu = TARGET_CPU;
int i;
unsigned int default_arch;
if (*default_cpu == 'm')
default_cpu++;
for (i = 0; i < n_archs; i++)
{
if (strcasecmp (default_cpu, archs[i].name) == 0)
{
default_arch = archs[i].arch;
for (i = 0; i < n_archs; i++)
{
if (archs[i].arch == default_arch
&& !archs[i].alias)
{
default_cpu = archs[i].name;
break;
}
}
}
}
fprintf (stream, _("\
680X0 options:\n\
-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 | -mcpu32 |\n\
-m5200 | -m5202 | -m5204 | -m5206 | -m5206e | -m521x | -m5249 |\n\
-m528x | -m5307 | -m5407 | -m547x | -m548x | -mcfv4 | -mcfv4e\n\
specify variant of 680X0 architecture [default %s]\n\
-m68881 | -m68882 | -mno-68881 | -mno-68882\n\
target has/lacks floating-point coprocessor\n\
[default yes for 68020, 68030, and cpu32]\n"),
default_cpu);
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\
--pcrel never turn PC-relative branches into absolute jumps\n\
--register-prefix-optional\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"));
}
#ifdef TEST2
int
main (void)
{
struct m68k_it the_ins;
char buf[120];
char *cp;
int n;
m68k_ip_begin ();
for (;;)
{
if (!gets (buf) || !*buf)
break;
if (buf[0] == '|' || buf[1] == '.')
continue;
for (cp = buf; *cp; cp++)
if (*cp == '\t')
*cp = ' ';
if (is_label (buf))
continue;
memset (&the_ins, '\0', sizeof (the_ins));
m68k_ip (&the_ins, buf);
if (the_ins.error)
{
printf (_("Error %s in %s\n"), the_ins.error, buf);
}
else
{
printf (_("Opcode(%d.%s): "), the_ins.numo, the_ins.args);
for (n = 0; n < the_ins.numo; n++)
printf (" 0x%x", the_ins.opcode[n] & 0xffff);
printf (" ");
print_the_insn (&the_ins.opcode[0], stdout);
(void) putchar ('\n');
}
for (n = 0; n < strlen (the_ins.args) / 2; n++)
{
if (the_ins.operands[n].error)
{
printf ("op%d Error %s in %s\n", n, the_ins.operands[n].error, buf);
continue;
}
printf ("mode %d, reg %d, ", the_ins.operands[n].mode,
the_ins.operands[n].reg);
if (the_ins.operands[n].b_const)
printf ("Constant: '%.*s', ",
1 + the_ins.operands[n].e_const - the_ins.operands[n].b_const,
the_ins.operands[n].b_const);
printf ("ireg %d, isiz %d, imul %d, ", the_ins.operands[n].ireg,
the_ins.operands[n].isiz, the_ins.operands[n].imul);
if (the_ins.operands[n].b_iadd)
printf ("Iadd: '%.*s',",
1 + the_ins.operands[n].e_iadd - the_ins.operands[n].b_iadd,
the_ins.operands[n].b_iadd);
putchar ('\n');
}
}
m68k_ip_end ();
return 0;
}
int
is_label (char *str)
{
while (*str == ' ')
str++;
while (*str && *str != ' ')
str++;
if (str[-1] == ':' || str[1] == '=')
return 1;
return 0;
}
#endif
symbolS *
md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
{
return 0;
}
valueT
md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size)
{
#ifdef OBJ_AOUT
#ifdef BFD_ASSEMBLER
int align;
align = bfd_get_section_alignment (stdoutput, segment);
size = ((size + (1 << align) - 1) & ((valueT) -1 << align));
#endif
#endif
return size;
}
long
md_pcrel_from (fixS *fixP)
{
int adjust;
adjust = ((fixP->fx_pcrel_adjust & 0xff) ^ 0x80) - 0x80;
if (adjust == 64)
adjust = -1;
return fixP->fx_where + fixP->fx_frag->fr_address - adjust;
}
#ifndef BFD_ASSEMBLER
#ifdef OBJ_COFF
void
tc_coff_symbol_emit_hook (symbolS *ignore ATTRIBUTE_UNUSED)
{
}
int
tc_coff_sizemachdep (fragS *frag)
{
switch (frag->fr_subtype & 0x3)
{
case BYTE:
return 1;
case SHORT:
return 2;
case LONG:
return 4;
default:
abort ();
return 0;
}
}
#endif
#endif
#ifdef OBJ_ELF
void
m68k_elf_final_processing (void)
{
if (cpu_of_arch (current_architecture) & cpu32)
elf_elfheader (stdoutput)->e_flags |= EF_CPU32;
else if ((cpu_of_arch (current_architecture) & m68000up)
&& !(cpu_of_arch (current_architecture) & m68020up))
elf_elfheader (stdoutput)->e_flags |= EF_M68000;
}
#endif
int
tc_m68k_regname_to_dw2regnum (const char *regname)
{
unsigned int regnum;
static const char *const regnames[] =
{
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
"a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp",
"fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7",
"pc"
};
for (regnum = 0; regnum < ARRAY_SIZE (regnames); regnum++)
if (strcmp (regname, regnames[regnum]) == 0)
return regnum;
return -1;
}
void
tc_m68k_frame_initial_instructions (void)
{
static int sp_regno = -1;
if (sp_regno < 0)
sp_regno = tc_m68k_regname_to_dw2regnum ("sp");
cfi_add_CFA_def_cfa (sp_regno, -DWARF2_CIE_DATA_ALIGNMENT);
cfi_add_CFA_offset (DWARF2_DEFAULT_RETURN_COLUMN, DWARF2_CIE_DATA_ALIGNMENT);
}