Reorganise m68k instruction decoding and improve handling of MAC/EMAC
This commit is contained in:
parent
dfdffa2c3c
commit
be8c092bb0
@ -1,3 +1,12 @@
|
||||
2004-05-24 Peter Barada <peter@the-baradas.com>
|
||||
|
||||
* config/m68k-parse.y(operand): Allow for MAC/EMAC mask
|
||||
addressing on MIT style operands.
|
||||
* config/m68k-parse.y(yylex): Allow '-&' for predecrement
|
||||
w/mask addressing.
|
||||
* config/tc-m68k.c(install_operand): Comment 'G' and 'H' type
|
||||
operands.
|
||||
|
||||
2004-05-23 Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
* expr.c (operand, operator): Don't reject '++' and '--'.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* m68k.y -- bison grammar for m68k operand parsing
|
||||
Copyright 1995, 1996, 1997, 1998, 2001 Free Software Foundation, Inc.
|
||||
Copyright 1995, 1996, 1997, 1998, 2001, 2004 Free Software Foundation, Inc.
|
||||
Written by Ken Raeburn and Ian Lance Taylor, Cygnus Support
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
@ -35,7 +35,7 @@
|
||||
etc), as well as gratuitously global symbol names If other parser
|
||||
generators (bison, byacc, etc) produce additional global names that
|
||||
conflict at link time, then those parser generators need to be
|
||||
fixed instead of adding those names to this list. */
|
||||
fixed instead of adding those names to this list. */
|
||||
|
||||
#define yymaxdepth m68k_maxdepth
|
||||
#define yyparse m68k_parse
|
||||
@ -122,7 +122,10 @@ operand:
|
||||
{
|
||||
op->trailing_ampersand = $2;
|
||||
}
|
||||
| mit_operand
|
||||
| mit_operand optional_ampersand
|
||||
{
|
||||
op->trailing_ampersand = $2;
|
||||
}
|
||||
;
|
||||
|
||||
/* A trailing ampersand(for MAC/EMAC mask addressing). */
|
||||
@ -793,8 +796,8 @@ yylex ()
|
||||
case '-':
|
||||
/* A '-' can only appear in -(ar), rn-rn, or ar@-. If it
|
||||
appears anywhere else, it must be a unary minus on an
|
||||
expression. */
|
||||
if (str[1] == '\0')
|
||||
expression, unless it it trailed by a '&'(see mac load insn). */
|
||||
if (str[1] == '\0' || (str[1] == '&' && str[2] == '\0'))
|
||||
return *str++;
|
||||
s = str + 1;
|
||||
if (*s == '(')
|
||||
|
@ -3476,11 +3476,11 @@ install_operand (mode, val)
|
||||
case 'f':
|
||||
the_ins.opcode[0] |= ((val & 0x3) << 0);
|
||||
break;
|
||||
case 'G':
|
||||
case 'G': /* EMAC accumulator in a EMAC load instruction. */
|
||||
the_ins.opcode[0] |= ((~val & 0x1) << 7);
|
||||
the_ins.opcode[1] |= ((val & 0x2) << (4 - 1));
|
||||
break;
|
||||
case 'H':
|
||||
case 'H': /* EMAC accumulator in a EMAC non-load instruction. */
|
||||
the_ins.opcode[0] |= ((val & 0x1) << 7);
|
||||
the_ins.opcode[1] |= ((val & 0x2) << (4 - 1));
|
||||
break;
|
||||
|
@ -1,3 +1,8 @@
|
||||
2004-05-24 Peter Barada <peter@the-baradas.com>
|
||||
|
||||
* gas/m68k/mcf-emac.d: Provide correct disassembler results.
|
||||
* gas/m68k/mcf-mac.d: Provide correct disassembler results.
|
||||
|
||||
2004-05-20 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
* gas/ia64/dv-srlz.d: Fix a typo.
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,7 @@
|
||||
2004-05-24 Peter Barada <peter@the-baradas.com>
|
||||
|
||||
* m68k.h: Add 'size' to m68k_opcode.
|
||||
|
||||
2004-05-05 Peter Barada <peter@the-baradas.com>
|
||||
|
||||
* m68k.h: Switch from ColdFire chip name to core variant.
|
||||
|
@ -73,6 +73,9 @@ struct m68k_opcode
|
||||
{
|
||||
/* The opcode name. */
|
||||
const char *name;
|
||||
/* The pseudo-size of the instruction(in bytes). Used to determine
|
||||
number of bytes necessary to disassemble the instruction. */
|
||||
unsigned int size;
|
||||
/* The opcode itself. */
|
||||
unsigned long opcode;
|
||||
/* The mask used by the disassembler. */
|
||||
|
@ -1,3 +1,20 @@
|
||||
2004-05-24 Peter Barada <peter@the-baradas.com>
|
||||
|
||||
* m68k-dis.c(print_insn_m68k): Strip body of diassembly out
|
||||
into new match_insn_m68k function. Loop over canidate
|
||||
matches and select first that completely matches.
|
||||
* m68k-dis.c(print_insn_arg): Fix 'g' case to only extract 1 bit.
|
||||
* m68k-dis.c(print_insn_arg): Call new function m68k_valid_ea
|
||||
to verify addressing for MAC/EMAC.
|
||||
* m68k-dis.c(print_insn_arg): Use reg_half_names for MAC/EMAC
|
||||
reigster halves since 'fpu' and 'spl' look misleading.
|
||||
* m68k-dis.c(fetch_arg): Fix 'G', 'H', 'I', 'f', 'M', 'N' cases.
|
||||
* m68k-opc.c: Rearragne mac/emac cases to use longest for
|
||||
first, tighten up match masks.
|
||||
* m68k-opc.c: Add 'size' field to struct m68k_opcode. Produce
|
||||
'size' from special case code in print_insn_m68k to
|
||||
determine decode size of insns.
|
||||
|
||||
2004-05-19 Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
* ppc-opc.c (insert_fxm): Enable two operand mfcr when -many as
|
||||
|
@ -46,18 +46,31 @@ static int
|
||||
print_insn_arg PARAMS ((const char *, unsigned char *, unsigned char *,
|
||||
bfd_vma, disassemble_info *));
|
||||
|
||||
const char * const fpcr_names[] = {
|
||||
static bfd_boolean m68k_valid_ea (char code, int val);
|
||||
|
||||
const char * const fpcr_names[] =
|
||||
{
|
||||
"", "%fpiar", "%fpsr", "%fpiar/%fpsr", "%fpcr",
|
||||
"%fpiar/%fpcr", "%fpsr/%fpcr", "%fpiar/%fpsr/%fpcr"
|
||||
};
|
||||
|
||||
static char *const reg_names[] = {
|
||||
static char *const reg_names[] =
|
||||
{
|
||||
"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
|
||||
"%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp",
|
||||
"%ps", "%pc"
|
||||
};
|
||||
|
||||
/* Sign-extend an (unsigned char). */
|
||||
/* Name of register halves for MAC/EMAC.
|
||||
Seperate from reg_names since 'spu', 'fpl' look weird. */
|
||||
static char *const reg_half_names[] =
|
||||
{
|
||||
"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
|
||||
"%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7",
|
||||
"%ps", "%pc"
|
||||
};
|
||||
|
||||
/* Sign-extend an (unsigned char). */
|
||||
#if __STDC__ == 1
|
||||
#define COERCE_SIGNED_CHAR(ch) ((signed char) (ch))
|
||||
#else
|
||||
@ -169,6 +182,147 @@ dummy_print_address (vma, info)
|
||||
{
|
||||
}
|
||||
|
||||
/* Try to match the current instruction to best and if so, return the
|
||||
number of bytes consumed from the instruction stream, else zero. */
|
||||
|
||||
static int
|
||||
match_insn_m68k (bfd_vma memaddr, disassemble_info * info,
|
||||
const struct m68k_opcode * best, struct private * priv)
|
||||
{
|
||||
unsigned char *save_p;
|
||||
unsigned char *p;
|
||||
const char *d;
|
||||
|
||||
bfd_byte *buffer = priv->the_buffer;
|
||||
fprintf_ftype save_printer = info->fprintf_func;
|
||||
void (* save_print_address) (bfd_vma, struct disassemble_info *)
|
||||
= info->print_address_func;
|
||||
|
||||
/* Point at first word of argument data,
|
||||
and at descriptor for first argument. */
|
||||
p = buffer + 2;
|
||||
|
||||
/* Figure out how long the fixed-size portion of the instruction is.
|
||||
The only place this is stored in the opcode table is
|
||||
in the arguments--look for arguments which specify fields in the 2nd
|
||||
or 3rd words of the instruction. */
|
||||
for (d = best->args; *d; d += 2)
|
||||
{
|
||||
/* I don't think it is necessary to be checking d[0] here;
|
||||
I suspect all this could be moved to the case statement below. */
|
||||
if (d[0] == '#')
|
||||
{
|
||||
if (d[1] == 'l' && p - buffer < 6)
|
||||
p = buffer + 6;
|
||||
else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8')
|
||||
p = buffer + 4;
|
||||
}
|
||||
|
||||
if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4)
|
||||
p = buffer + 4;
|
||||
|
||||
switch (d[1])
|
||||
{
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case 'i':
|
||||
if (p - buffer < 4)
|
||||
p = buffer + 4;
|
||||
break;
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
if (p - buffer < 6)
|
||||
p = buffer + 6;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* pflusha is an exceptions. It takes no arguments but is two words
|
||||
long. Recognize it by looking at the lower 16 bits of the mask. */
|
||||
if (p - buffer < 4 && (best->match & 0xFFFF) != 0)
|
||||
p = buffer + 4;
|
||||
|
||||
/* lpstop is another exception. It takes a one word argument but is
|
||||
three words long. */
|
||||
if (p - buffer < 6
|
||||
&& (best->match & 0xffff) == 0xffff
|
||||
&& best->args[0] == '#'
|
||||
&& best->args[1] == 'w')
|
||||
{
|
||||
/* Copy the one word argument into the usual location for a one
|
||||
word argument, to simplify printing it. We can get away with
|
||||
this because we know exactly what the second word is, and we
|
||||
aren't going to print anything based on it. */
|
||||
p = buffer + 6;
|
||||
FETCH_DATA (info, p);
|
||||
buffer[2] = buffer[4];
|
||||
buffer[3] = buffer[5];
|
||||
}
|
||||
|
||||
FETCH_DATA (info, p);
|
||||
|
||||
d = best->args;
|
||||
|
||||
save_p = p;
|
||||
info->print_address_func = dummy_print_address;
|
||||
info->fprintf_func = (fprintf_ftype) dummy_printer;
|
||||
|
||||
/* We scan the operands twice. The first time we don't print anything,
|
||||
but look for errors. */
|
||||
for (; *d; d += 2)
|
||||
{
|
||||
int eaten = print_insn_arg (d, buffer, p, memaddr + (p - buffer), info);
|
||||
|
||||
if (eaten >= 0)
|
||||
p += eaten;
|
||||
else if (eaten == -1)
|
||||
{
|
||||
info->fprintf_func = save_printer;
|
||||
info->print_address_func = save_print_address;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->fprintf_func (info->stream,
|
||||
/* xgettext:c-format */
|
||||
_("<internal error in opcode table: %s %s>\n"),
|
||||
best->name, best->args);
|
||||
info->fprintf_func = save_printer;
|
||||
info->print_address_func = save_print_address;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
p = save_p;
|
||||
info->fprintf_func = save_printer;
|
||||
info->print_address_func = save_print_address;
|
||||
|
||||
d = best->args;
|
||||
|
||||
info->fprintf_func (info->stream, "%s", best->name);
|
||||
|
||||
if (*d)
|
||||
info->fprintf_func (info->stream, " ");
|
||||
|
||||
while (*d)
|
||||
{
|
||||
p += print_insn_arg (d, buffer, p, memaddr + (p - buffer), info);
|
||||
d += 2;
|
||||
|
||||
if (*d && *(d - 2) != 'I' && *d != 'k')
|
||||
info->fprintf_func (info->stream, ",");
|
||||
}
|
||||
|
||||
return p - buffer;
|
||||
}
|
||||
|
||||
/* Print the m68k instruction at address MEMADDR in debugged memory,
|
||||
on INFO->STREAM. Returns length of the instruction, in bytes. */
|
||||
|
||||
@ -177,38 +331,32 @@ print_insn_m68k (memaddr, info)
|
||||
bfd_vma memaddr;
|
||||
disassemble_info *info;
|
||||
{
|
||||
register int i;
|
||||
register unsigned char *p;
|
||||
unsigned char *save_p;
|
||||
register const char *d;
|
||||
register unsigned long bestmask;
|
||||
const struct m68k_opcode *best;
|
||||
int i;
|
||||
const char *d;
|
||||
unsigned int arch_mask;
|
||||
struct private priv;
|
||||
bfd_byte *buffer = priv.the_buffer;
|
||||
fprintf_ftype save_printer = info->fprintf_func;
|
||||
void (*save_print_address) PARAMS ((bfd_vma, struct disassemble_info *))
|
||||
= info->print_address_func;
|
||||
int major_opcode;
|
||||
static int numopcodes[16];
|
||||
static const struct m68k_opcode **opcodes[16];
|
||||
int val;
|
||||
|
||||
if (!opcodes[0])
|
||||
{
|
||||
/* Speed up the matching by sorting the opcode table on the upper
|
||||
four bits of the opcode. */
|
||||
/* Speed up the matching by sorting the opcode
|
||||
table on the upper four bits of the opcode. */
|
||||
const struct m68k_opcode **opc_pointer[16];
|
||||
|
||||
/* First count how many opcodes are in each of the sixteen buckets. */
|
||||
for (i = 0; i < m68k_numopcodes; i++)
|
||||
numopcodes[(m68k_opcodes[i].opcode >> 28) & 15]++;
|
||||
|
||||
/* Then create a sorted table of pointers that point into the
|
||||
unsorted table. */
|
||||
opc_pointer[0] = ((const struct m68k_opcode **)
|
||||
xmalloc (sizeof (struct m68k_opcode *)
|
||||
* m68k_numopcodes));
|
||||
/* Then create a sorted table of pointers
|
||||
that point into the unsorted table. */
|
||||
opc_pointer[0] = xmalloc (sizeof (struct m68k_opcode *)
|
||||
* m68k_numopcodes);
|
||||
opcodes[0] = opc_pointer[0];
|
||||
|
||||
for (i = 1; i < 16; i++)
|
||||
{
|
||||
opc_pointer[i] = opc_pointer[i - 1] + numopcodes[i - 1];
|
||||
@ -217,22 +365,21 @@ print_insn_m68k (memaddr, info)
|
||||
|
||||
for (i = 0; i < m68k_numopcodes; i++)
|
||||
*opc_pointer[(m68k_opcodes[i].opcode >> 28) & 15]++ = &m68k_opcodes[i];
|
||||
|
||||
}
|
||||
|
||||
info->private_data = (PTR) &priv;
|
||||
/* Tell objdump to use two bytes per chunk and six bytes per line for
|
||||
displaying raw data. */
|
||||
/* Tell objdump to use two bytes per chunk
|
||||
and six bytes per line for displaying raw data. */
|
||||
info->bytes_per_chunk = 2;
|
||||
info->bytes_per_line = 6;
|
||||
info->display_endian = BFD_ENDIAN_BIG;
|
||||
priv.max_fetched = priv.the_buffer;
|
||||
priv.insn_start = memaddr;
|
||||
|
||||
if (setjmp (priv.bailout) != 0)
|
||||
/* Error return. */
|
||||
return -1;
|
||||
|
||||
best = NULL;
|
||||
switch (info->mach)
|
||||
{
|
||||
default:
|
||||
@ -286,9 +433,9 @@ print_insn_m68k (memaddr, info)
|
||||
break;
|
||||
}
|
||||
|
||||
bestmask = 0;
|
||||
FETCH_DATA (info, buffer + 2);
|
||||
major_opcode = (buffer[0] >> 4) & 15;
|
||||
|
||||
for (i = 0; i < numopcodes[major_opcode]; i++)
|
||||
{
|
||||
const struct m68k_opcode *opc = opcodes[major_opcode][i];
|
||||
@ -315,22 +462,20 @@ print_insn_m68k (memaddr, info)
|
||||
|
||||
/* Don't use for printout the variants of most floating
|
||||
point coprocessor instructions which use the same
|
||||
register number in two places, as above. */
|
||||
register number in two places, as above. */
|
||||
if (*d == '\0')
|
||||
for (d = opc->args; *d; d += 2)
|
||||
if (d[1] == 't')
|
||||
break;
|
||||
|
||||
/* Don't match fmovel with more than one register; wait for
|
||||
fmoveml. */
|
||||
/* Don't match fmovel with more than one register;
|
||||
wait for fmoveml. */
|
||||
if (*d == '\0')
|
||||
{
|
||||
for (d = opc->args; *d; d += 2)
|
||||
{
|
||||
if (d[0] == 's' && d[1] == '8')
|
||||
{
|
||||
int val;
|
||||
|
||||
val = fetch_arg (buffer, d[1], 3, info);
|
||||
if ((val & (val - 1)) != 0)
|
||||
break;
|
||||
@ -338,158 +483,35 @@ print_insn_m68k (memaddr, info)
|
||||
}
|
||||
}
|
||||
|
||||
if (*d == '\0' && match > bestmask)
|
||||
{
|
||||
best = opc;
|
||||
bestmask = match;
|
||||
}
|
||||
if (*d == '\0')
|
||||
if ((val = match_insn_m68k (memaddr, info, opc, & priv)))
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
if (best == NULL)
|
||||
goto invalid;
|
||||
|
||||
/* Point at first word of argument data,
|
||||
and at descriptor for first argument. */
|
||||
p = buffer + 2;
|
||||
|
||||
/* Figure out how long the fixed-size portion of the instruction is.
|
||||
The only place this is stored in the opcode table is
|
||||
in the arguments--look for arguments which specify fields in the 2nd
|
||||
or 3rd words of the instruction. */
|
||||
for (d = best->args; *d; d += 2)
|
||||
{
|
||||
/* I don't think it is necessary to be checking d[0] here; I suspect
|
||||
all this could be moved to the case statement below. */
|
||||
if (d[0] == '#')
|
||||
{
|
||||
if (d[1] == 'l' && p - buffer < 6)
|
||||
p = buffer + 6;
|
||||
else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8')
|
||||
p = buffer + 4;
|
||||
}
|
||||
if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4)
|
||||
p = buffer + 4;
|
||||
switch (d[1])
|
||||
{
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case 'i':
|
||||
if (p - buffer < 4)
|
||||
p = buffer + 4;
|
||||
break;
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
if (p - buffer < 6)
|
||||
p = buffer + 6;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* pflusha is an exceptions. It takes no arguments but is two words
|
||||
long. Recognize it by looking at the lower 16 bits of the mask. */
|
||||
if (p - buffer < 4 && (best->match & 0xFFFF) != 0)
|
||||
p = buffer + 4;
|
||||
|
||||
/* lpstop is another exception. It takes a one word argument but is
|
||||
three words long. */
|
||||
if (p - buffer < 6
|
||||
&& (best->match & 0xffff) == 0xffff
|
||||
&& best->args[0] == '#'
|
||||
&& best->args[1] == 'w')
|
||||
{
|
||||
/* Copy the one word argument into the usual location for a one
|
||||
word argument, to simplify printing it. We can get away with
|
||||
this because we know exactly what the second word is, and we
|
||||
aren't going to print anything based on it. */
|
||||
p = buffer + 6;
|
||||
FETCH_DATA (info, p);
|
||||
buffer[2] = buffer[4];
|
||||
buffer[3] = buffer[5];
|
||||
}
|
||||
|
||||
FETCH_DATA (info, p);
|
||||
|
||||
d = best->args;
|
||||
|
||||
/* We scan the operands twice. The first time we don't print anything,
|
||||
but look for errors. */
|
||||
|
||||
save_p = p;
|
||||
info->print_address_func = dummy_print_address;
|
||||
info->fprintf_func = (fprintf_ftype) dummy_printer;
|
||||
for (; *d; d += 2)
|
||||
{
|
||||
int eaten = print_insn_arg (d, buffer, p, memaddr + (p - buffer), info);
|
||||
if (eaten >= 0)
|
||||
p += eaten;
|
||||
else if (eaten == -1)
|
||||
goto invalid;
|
||||
else
|
||||
{
|
||||
(*info->fprintf_func) (info->stream,
|
||||
/* xgettext:c-format */
|
||||
_("<internal error in opcode table: %s %s>\n"),
|
||||
best->name,
|
||||
best->args);
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
}
|
||||
p = save_p;
|
||||
info->fprintf_func = save_printer;
|
||||
info->print_address_func = save_print_address;
|
||||
|
||||
d = best->args;
|
||||
|
||||
(*info->fprintf_func) (info->stream, "%s", best->name);
|
||||
|
||||
if (*d)
|
||||
(*info->fprintf_func) (info->stream, " ");
|
||||
|
||||
while (*d)
|
||||
{
|
||||
p += print_insn_arg (d, buffer, p, memaddr + (p - buffer), info);
|
||||
d += 2;
|
||||
if (*d && *(d - 2) != 'I' && *d != 'k')
|
||||
(*info->fprintf_func) (info->stream, ",");
|
||||
}
|
||||
return p - buffer;
|
||||
|
||||
invalid:
|
||||
/* Handle undefined instructions. */
|
||||
info->fprintf_func = save_printer;
|
||||
info->print_address_func = save_print_address;
|
||||
(*info->fprintf_func) (info->stream, "0%o",
|
||||
(buffer[0] << 8) + buffer[1]);
|
||||
info->fprintf_func (info->stream, "0%o", (buffer[0] << 8) + buffer[1]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* Returns number of bytes "eaten" by the operand, or
|
||||
return -1 if an invalid operand was found, or -2 if
|
||||
an opcode tabe error was found. */
|
||||
an opcode tabe error was found. */
|
||||
|
||||
static int
|
||||
print_insn_arg (d, buffer, p0, addr, info)
|
||||
const char *d;
|
||||
unsigned char *buffer;
|
||||
unsigned char *p0;
|
||||
bfd_vma addr; /* PC for this arg to be relative to */
|
||||
bfd_vma addr; /* PC for this arg to be relative to. */
|
||||
disassemble_info *info;
|
||||
{
|
||||
register int val = 0;
|
||||
register int place = d[1];
|
||||
register unsigned char *p = p0;
|
||||
int val = 0;
|
||||
int place = d[1];
|
||||
unsigned char *p = p0;
|
||||
int regno;
|
||||
register const char *regname;
|
||||
register unsigned char *p1;
|
||||
const char *regname;
|
||||
unsigned char *p1;
|
||||
double flval;
|
||||
int flt_p;
|
||||
bfd_signed_vma disp;
|
||||
@ -497,7 +519,7 @@ print_insn_arg (d, buffer, p0, addr, info)
|
||||
|
||||
switch (*d)
|
||||
{
|
||||
case 'c': /* cache identifier */
|
||||
case 'c': /* Cache identifier. */
|
||||
{
|
||||
static char *const cacheFieldName[] = { "nc", "dc", "ic", "bc" };
|
||||
val = fetch_arg (buffer, place, 2, info);
|
||||
@ -505,7 +527,7 @@ print_insn_arg (d, buffer, p0, addr, info)
|
||||
break;
|
||||
}
|
||||
|
||||
case 'a': /* address register indirect only. Cf. case '+'. */
|
||||
case 'a': /* Address register indirect only. Cf. case '+'. */
|
||||
{
|
||||
(*info->fprintf_func)
|
||||
(info->stream,
|
||||
@ -514,7 +536,7 @@ print_insn_arg (d, buffer, p0, addr, info)
|
||||
break;
|
||||
}
|
||||
|
||||
case '_': /* 32-bit absolute address for move16. */
|
||||
case '_': /* 32-bit absolute address for move16. */
|
||||
{
|
||||
uval = NEXTULONG (p);
|
||||
(*info->print_address_func) (uval, info);
|
||||
@ -749,7 +771,7 @@ print_insn_arg (d, buffer, p0, addr, info)
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
val = fetch_arg(buffer, place, 2, info);
|
||||
val = fetch_arg(buffer, place, 1, info);
|
||||
(*info->fprintf_func) (info->stream, "%%accext%s", val==0 ? "01" : "23");
|
||||
break;
|
||||
|
||||
@ -759,6 +781,8 @@ print_insn_arg (d, buffer, p0, addr, info)
|
||||
(*info->fprintf_func) (info->stream, "<<");
|
||||
else if (val == 3)
|
||||
(*info->fprintf_func) (info->stream, ">>");
|
||||
else
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
@ -801,6 +825,10 @@ print_insn_arg (d, buffer, p0, addr, info)
|
||||
else
|
||||
val = fetch_arg (buffer, 's', 6, info);
|
||||
|
||||
/* If the <ea> is invalid for *d, then reject this match. */
|
||||
if (m68k_valid_ea (*d, val) == FALSE)
|
||||
return -1;
|
||||
|
||||
/* Get register number assuming address register. */
|
||||
regno = (val & 7) + 8;
|
||||
regname = reg_names[regno];
|
||||
@ -915,7 +943,7 @@ print_insn_arg (d, buffer, p0, addr, info)
|
||||
{
|
||||
val = fetch_arg (buffer, place, 1, info);
|
||||
if (val)
|
||||
(*info->fprintf_func) (info->stream, "&");
|
||||
info->fprintf_func (info->stream, "&");
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1084,7 +1112,7 @@ print_insn_arg (d, buffer, p0, addr, info)
|
||||
reg &= 0xf;
|
||||
}
|
||||
(*info->fprintf_func) (info->stream, "%s%s",
|
||||
reg_names[reg],
|
||||
reg_half_names[reg],
|
||||
is_upper ? "u" : "l");
|
||||
}
|
||||
break;
|
||||
@ -1096,6 +1124,24 @@ print_insn_arg (d, buffer, p0, addr, info)
|
||||
return p - p0;
|
||||
}
|
||||
|
||||
/* Check if an EA is valid for a particular code. This is required
|
||||
for the EMAC instructions since the type of source address determines
|
||||
if it is a EMAC-load instruciton if the EA is mode 2-5, otherwise it
|
||||
is a non-load EMAC instruction and the bits mean register Ry. */
|
||||
|
||||
static bfd_boolean
|
||||
m68k_valid_ea (char code, int val)
|
||||
{
|
||||
int mode;
|
||||
|
||||
mode = (val >> 3) & 7;
|
||||
if (code == '4')
|
||||
if (!(mode >= 2 && mode <= 5))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Fetch BITS bits from a position in the instruction specified by CODE.
|
||||
CODE is a "place to put an argument", or 'x' for a destination
|
||||
that is a general address (mode and register).
|
||||
@ -1108,7 +1154,8 @@ fetch_arg (buffer, code, bits, info)
|
||||
int bits;
|
||||
disassemble_info *info;
|
||||
{
|
||||
register int val = 0;
|
||||
int val = 0;
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case '/': /* MAC/EMAC mask bit. */
|
||||
@ -1116,11 +1163,11 @@ fetch_arg (buffer, code, bits, info)
|
||||
break;
|
||||
|
||||
case 'G': /* EMAC ACC load. */
|
||||
val = ((buffer[3] >> 3) & 0x2) | ((~buffer[2] >> 7) & 0x1);
|
||||
val = ((buffer[3] >> 3) & 0x2) | ((~buffer[1] >> 7) & 0x1);
|
||||
break;
|
||||
|
||||
case 'H': /* EMAC ACC !load. */
|
||||
val = ((buffer[3] >> 3) & 0x2) | ((buffer[2] >> 7) & 0x1);
|
||||
val = ((buffer[3] >> 3) & 0x2) | ((buffer[1] >> 7) & 0x1);
|
||||
break;
|
||||
|
||||
case ']': /* EMAC ACCEXT bit. */
|
||||
@ -1128,7 +1175,7 @@ fetch_arg (buffer, code, bits, info)
|
||||
break;
|
||||
|
||||
case 'I': /* MAC/EMAC scale factor. */
|
||||
val = buffer[0] >> 1;
|
||||
val = buffer[2] >> 1;
|
||||
break;
|
||||
|
||||
case 'F': /* EMAC ACCx. */
|
||||
@ -1136,7 +1183,7 @@ fetch_arg (buffer, code, bits, info)
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
val = buffer[0];
|
||||
val = buffer[1];
|
||||
break;
|
||||
|
||||
case 's':
|
||||
@ -1235,11 +1282,11 @@ fetch_arg (buffer, code, bits, info)
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
val = buffer[1] | (buffer[3] & 0x40 ? 0x10 : 0);
|
||||
val = (buffer[1] & 0xf) | (buffer[3] & 0x40 ? 0x10 : 0);
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
val = buffer[3] | (buffer[3] & 0x40 ? 0x10 : 0);
|
||||
val = (buffer[3] & 0xf) | (buffer[3] & 0x40 ? 0x10 : 0);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
@ -1286,7 +1333,7 @@ print_indexed (basereg, p, addr, info)
|
||||
bfd_vma addr;
|
||||
disassemble_info *info;
|
||||
{
|
||||
register int word;
|
||||
int word;
|
||||
static char *const scales[] = { "", ":2", ":4", ":8" };
|
||||
bfd_vma base_disp;
|
||||
bfd_vma outer_disp;
|
||||
|
3721
opcodes/m68k-opc.c
3721
opcodes/m68k-opc.c
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user