+ default:
+ abort ();
+ }
+
+ /* bits is never too big. */
+ return val & ((1 << bits) - 1);
+}
+
+/* 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.
+ A similar case exists for the movem instructions where the register
+ mask is interpreted differently for different EAs. */
+
+static bfd_boolean
+m68k_valid_ea (char code, int val)
+{
+ int mode, mask;
+#define M(n0,n1,n2,n3,n4,n5,n6,n70,n71,n72,n73,n74) \
+ (n0 | n1 << 1 | n2 << 2 | n3 << 3 | n4 << 4 | n5 << 5 | n6 << 6 \
+ | n70 << 7 | n71 << 8 | n72 << 9 | n73 << 10 | n74 << 11)
+
+ switch (code)
+ {
+ case '*':
+ mask = M (1,1,1,1,1,1,1,1,1,1,1,1);
+ break;
+ case '~':
+ mask = M (0,0,1,1,1,1,1,1,1,0,0,0);
+ break;
+ case '%':
+ mask = M (1,1,1,1,1,1,1,1,1,0,0,0);
+ break;
+ case ';':
+ mask = M (1,0,1,1,1,1,1,1,1,1,1,1);
+ break;
+ case '@':
+ mask = M (1,0,1,1,1,1,1,1,1,1,1,0);
+ break;
+ case '!':
+ mask = M (0,0,1,0,0,1,1,1,1,1,1,0);
+ break;
+ case '&':
+ mask = M (0,0,1,0,0,1,1,1,1,0,0,0);
+ break;
+ case '$':
+ mask = M (1,0,1,1,1,1,1,1,1,0,0,0);
+ break;
+ case '?':
+ mask = M (1,0,1,0,0,1,1,1,1,0,0,0);
+ break;
+ case '/':
+ mask = M (1,0,1,0,0,1,1,1,1,1,1,0);
+ break;
+ case '|':
+ mask = M (0,0,1,0,0,1,1,1,1,1,1,0);
+ break;
+ case '>':
+ mask = M (0,0,1,0,1,1,1,1,1,0,0,0);
+ break;
+ case '<':
+ mask = M (0,0,1,1,0,1,1,1,1,1,1,0);
+ break;
+ case 'm':
+ mask = M (1,1,1,1,1,0,0,0,0,0,0,0);
+ break;
+ case 'n':
+ mask = M (0,0,0,0,0,1,0,0,0,1,0,0);
+ break;
+ case 'o':
+ mask = M (0,0,0,0,0,0,1,1,1,0,1,1);
+ break;
+ case 'p':
+ mask = M (1,1,1,1,1,1,0,0,0,0,0,0);
+ break;
+ case 'q':
+ mask = M (1,0,1,1,1,1,0,0,0,0,0,0);
+ break;
+ case 'v':
+ mask = M (1,0,1,1,1,1,0,1,1,0,0,0);
+ break;
+ case 'b':
+ mask = M (1,0,1,1,1,1,0,0,0,1,0,0);
+ break;
+ case 'w':
+ mask = M (0,0,1,1,1,1,0,0,0,1,0,0);
+ break;
+ case 'y':
+ mask = M (0,0,1,0,0,1,0,0,0,0,0,0);
+ break;
+ case 'z':
+ mask = M (0,0,1,0,0,1,0,0,0,1,0,0);
+ break;
+ case '4':
+ mask = M (0,0,1,1,1,1,0,0,0,0,0,0);
+ break;
+ default:
+ abort ();
+ }
+#undef M
+
+ mode = (val >> 3) & 7;
+ if (mode == 7)
+ mode += val & 7;
+ return (mask & (1 << mode)) != 0;
+}
+
+/* Print a base register REGNO and displacement DISP, on INFO->STREAM.
+ REGNO = -1 for pc, -2 for none (suppressed). */
+
+static void
+print_base (int regno, bfd_vma disp, disassemble_info *info)
+{
+ if (regno == -1)
+ {
+ (*info->fprintf_func) (info->stream, "%%pc@(");
+ (*info->print_address_func) (disp, info);
+ }
+ else
+ {
+ char buf[50];
+
+ if (regno == -2)
+ (*info->fprintf_func) (info->stream, "@(");
+ else if (regno == -3)
+ (*info->fprintf_func) (info->stream, "%%zpc@(");
+ else
+ (*info->fprintf_func) (info->stream, "%s@(", reg_names[regno]);
+
+ sprintf_vma (buf, disp);
+ (*info->fprintf_func) (info->stream, "%s", buf);
+ }
+}
+
+/* Print an indexed argument. The base register is BASEREG (-1 for pc).
+ P points to extension word, in buffer.
+ ADDR is the nominal core address of that extension word.
+ Returns NULL upon error. */
+
+static unsigned char *
+print_indexed (int basereg,
+ unsigned char *p,
+ bfd_vma addr,
+ disassemble_info *info)
+{
+ int word;
+ static char *const scales[] = { "", ":2", ":4", ":8" };
+ bfd_vma base_disp;
+ bfd_vma outer_disp;
+ char buf[40];
+ char vmabuf[50];
+
+ NEXTWORD (p, word, NULL);
+
+ /* Generate the text for the index register.
+ Where this will be output is not yet determined. */
+ sprintf (buf, "%s:%c%s",
+ reg_names[(word >> 12) & 0xf],
+ (word & 0x800) ? 'l' : 'w',
+ scales[(word >> 9) & 3]);
+
+ /* Handle the 68000 style of indexing. */
+
+ if ((word & 0x100) == 0)
+ {
+ base_disp = word & 0xff;
+ if ((base_disp & 0x80) != 0)
+ base_disp -= 0x100;
+ if (basereg == -1)
+ base_disp += addr;
+ print_base (basereg, base_disp, info);
+ (*info->fprintf_func) (info->stream, ",%s)", buf);
+ return p;
+ }
+
+ /* Handle the generalized kind. */
+ /* First, compute the displacement to add to the base register. */
+ if (word & 0200)
+ {
+ if (basereg == -1)
+ basereg = -3;
+ else
+ basereg = -2;
+ }
+ if (word & 0100)
+ buf[0] = '\0';
+ base_disp = 0;
+ switch ((word >> 4) & 3)
+ {
+ case 2:
+ NEXTWORD (p, base_disp, NULL);
+ break;
+ case 3:
+ NEXTLONG (p, base_disp, NULL);
+ }
+ if (basereg == -1)
+ base_disp += addr;
+
+ /* Handle single-level case (not indirect). */
+ if ((word & 7) == 0)
+ {
+ print_base (basereg, base_disp, info);
+ if (buf[0] != '\0')
+ (*info->fprintf_func) (info->stream, ",%s", buf);
+ (*info->fprintf_func) (info->stream, ")");
+ return p;
+ }
+
+ /* Two level. Compute displacement to add after indirection. */
+ outer_disp = 0;
+ switch (word & 3)
+ {
+ case 2:
+ NEXTWORD (p, outer_disp, NULL);
+ break;
+ case 3:
+ NEXTLONG (p, outer_disp, NULL);
+ }
+
+ print_base (basereg, base_disp, info);
+ if ((word & 4) == 0 && buf[0] != '\0')
+ {
+ (*info->fprintf_func) (info->stream, ",%s", buf);
+ buf[0] = '\0';
+ }
+ sprintf_vma (vmabuf, outer_disp);
+ (*info->fprintf_func) (info->stream, ")@(%s", vmabuf);
+ if (buf[0] != '\0')
+ (*info->fprintf_func) (info->stream, ",%s", buf);
+ (*info->fprintf_func) (info->stream, ")");
+
+ return p;
+}
+
+#define FETCH_ARG(size, val) \
+ do \
+ { \
+ val = fetch_arg (buffer, place, size, info); \
+ if (val < 0) \
+ return -3; \
+ } \
+ while (0)
+
+/* 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 or -3 to simply abort.
+ ADDR is the pc for this arg to be relative to. */
+
+static int
+print_insn_arg (const char *d,
+ unsigned char *buffer,
+ unsigned char *p0,
+ bfd_vma addr,
+ disassemble_info *info)
+{
+ int val = 0;
+ int place = d[1];
+ unsigned char *p = p0;
+ int regno;
+ const char *regname;
+ unsigned char *p1;
+ double flval;
+ int flt_p;
+ bfd_signed_vma disp;
+ unsigned int uval;
+
+ switch (*d)
+ {
+ case 'c': /* Cache identifier. */
+ {
+ static char *const cacheFieldName[] = { "nc", "dc", "ic", "bc" };
+ FETCH_ARG (2, val);
+ (*info->fprintf_func) (info->stream, cacheFieldName[val]);
+ break;
+ }
+
+ case 'a': /* Address register indirect only. Cf. case '+'. */
+ {
+ FETCH_ARG (3, val);
+ (*info->fprintf_func) (info->stream, "%s@", reg_names[val + 8]);
+ break;
+ }
+
+ case '_': /* 32-bit absolute address for move16. */
+ {
+ NEXTULONG (p, uval);
+ (*info->print_address_func) (uval, info);
+ break;
+ }
+
+ case 'C':
+ (*info->fprintf_func) (info->stream, "%%ccr");
+ break;
+
+ case 'S':
+ (*info->fprintf_func) (info->stream, "%%sr");
+ break;
+
+ case 'U':
+ (*info->fprintf_func) (info->stream, "%%usp");
+ break;
+
+ case 'E':
+ (*info->fprintf_func) (info->stream, "%%acc");
+ break;
+
+ case 'G':
+ (*info->fprintf_func) (info->stream, "%%macsr");
+ break;
+
+ case 'H':
+ (*info->fprintf_func) (info->stream, "%%mask");
+ break;
+
+ case 'J':
+ {
+ /* FIXME: There's a problem here, different m68k processors call the
+ same address different names. The tables below try to get it right
+ using info->mach, but only for v4e. */
+ struct regname { char * name; int value; };
+ static const struct regname names[] =
+ {
+ {"%sfc", 0x000}, {"%dfc", 0x001}, {"%cacr", 0x002},
+ {"%tc", 0x003}, {"%itt0",0x004}, {"%itt1", 0x005},
+ {"%dtt0",0x006}, {"%dtt1",0x007}, {"%buscr",0x008},
+ {"%rgpiobar", 0x009}, {"%acr4",0x00c},
+ {"%acr5",0x00d}, {"%acr6",0x00e}, {"%acr7", 0x00f},
+ {"%usp", 0x800}, {"%vbr", 0x801}, {"%caar", 0x802},
+ {"%msp", 0x803}, {"%isp", 0x804},
+ {"%pc", 0x80f},
+ /* Reg c04 is sometimes called flashbar or rambar.
+ Reg c05 is also sometimes called rambar. */
+ {"%rambar0", 0xc04}, {"%rambar1", 0xc05},
+
+ /* reg c0e is sometimes called mbar2 or secmbar.
+ reg c0f is sometimes called mbar. */
+ {"%mbar0", 0xc0e}, {"%mbar1", 0xc0f},
+
+ /* Should we be calling this psr like we do in case 'Y'? */
+ {"%mmusr",0x805},
+
+ {"%urp", 0x806}, {"%srp", 0x807}, {"%pcr", 0x808},
+
+ /* Fido added these. */
+ {"%cac", 0xffe}, {"%mbo", 0xfff}
+ };
+ /* Alternate names for v4e (MCF5407/5445x/MCF547x/MCF548x), at least. */
+ static const struct regname names_v4e[] =
+ {
+ {"%asid",0x003}, {"%acr0",0x004}, {"%acr1",0x005},
+ {"%acr2",0x006}, {"%acr3",0x007}, {"%mmubar",0x008},
+ };
+ unsigned int arch_mask;
+
+ arch_mask = bfd_m68k_mach_to_features (info->mach);
+ FETCH_ARG (12, val);
+ if (arch_mask & (mcfisa_b | mcfisa_c))
+ {
+ for (regno = ARRAY_SIZE (names_v4e); --regno >= 0;)
+ if (names_v4e[regno].value == val)
+ {
+ (*info->fprintf_func) (info->stream, "%s", names_v4e[regno].name);
+ break;
+ }
+ if (regno >= 0)
+ break;
+ }
+ for (regno = ARRAY_SIZE (names) - 1; regno >= 0; regno--)
+ if (names[regno].value == val)
+ {
+ (*info->fprintf_func) (info->stream, "%s", names[regno].name);
+ break;
+ }
+ if (regno < 0)
+ (*info->fprintf_func) (info->stream, "0x%x", val);
+ }
+ break;
+
+ case 'Q':
+ FETCH_ARG (3, val);
+ /* 0 means 8, except for the bkpt instruction... */
+ if (val == 0 && d[1] != 's')
+ val = 8;
+ (*info->fprintf_func) (info->stream, "#%d", val);
+ break;
+
+ case 'x':
+ FETCH_ARG (3, val);
+ /* 0 means -1. */
+ if (val == 0)
+ val = -1;
+ (*info->fprintf_func) (info->stream, "#%d", val);
+ break;
+
+ case 'j':
+ FETCH_ARG (3, val);
+ (*info->fprintf_func) (info->stream, "#%d", val+1);
+ break;
+
+ case 'K':
+ FETCH_ARG (9, val);
+ (*info->fprintf_func) (info->stream, "#%d", val);
+ break;
+
+ case 'M':
+ if (place == 'h')
+ {
+ static char *const scalefactor_name[] = { "<<", ">>" };
+
+ FETCH_ARG (1, val);
+ (*info->fprintf_func) (info->stream, scalefactor_name[val]);
+ }
+ else
+ {
+ FETCH_ARG (8, val);
+ if (val & 0x80)
+ val = val - 0x100;
+ (*info->fprintf_func) (info->stream, "#%d", val);
+ }
+ break;
+
+ case 'T':
+ FETCH_ARG (4, val);
+ (*info->fprintf_func) (info->stream, "#%d", val);
+ break;
+
+ case 'D':
+ FETCH_ARG (3, val);
+ (*info->fprintf_func) (info->stream, "%s", reg_names[val]);
+ break;
+
+ case 'A':
+ FETCH_ARG (3, val);
+ (*info->fprintf_func) (info->stream, "%s", reg_names[val + 010]);
+ break;
+
+ case 'R':
+ FETCH_ARG (4, val);
+ (*info->fprintf_func) (info->stream, "%s", reg_names[val]);
+ break;
+
+ case 'r':
+ FETCH_ARG (4, regno);
+ if (regno > 7)
+ (*info->fprintf_func) (info->stream, "%s@", reg_names[regno]);
+ else
+ (*info->fprintf_func) (info->stream, "@(%s)", reg_names[regno]);
+ break;
+
+ case 'F':
+ FETCH_ARG (3, val);
+ (*info->fprintf_func) (info->stream, "%%fp%d", val);
+ break;
+
+ case 'O':
+ FETCH_ARG (6, val);
+ if (val & 0x20)
+ (*info->fprintf_func) (info->stream, "%s", reg_names[val & 7]);
+ else
+ (*info->fprintf_func) (info->stream, "%d", val);
+ break;
+
+ case '+':
+ FETCH_ARG (3, val);
+ (*info->fprintf_func) (info->stream, "%s@+", reg_names[val + 8]);
+ break;
+
+ case '-':
+ FETCH_ARG (3, val);
+ (*info->fprintf_func) (info->stream, "%s@-", reg_names[val + 8]);
+ break;
+
+ case 'k':
+ if (place == 'k')
+ {
+ FETCH_ARG (3, val);
+ (*info->fprintf_func) (info->stream, "{%s}", reg_names[val]);
+ }